1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
6 // +build darwin dragonfly freebsd linux netbsd openbsd solaris
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
26 func libc_getaddrinfo(node
*byte, service
*byte, hints
*syscall
.Addrinfo
, res
**syscall
.Addrinfo
) int
29 func libc_freeaddrinfo(res
*syscall
.Addrinfo
)
32 func libc_gai_strerror(errcode
int) *byte
34 // bytePtrToString takes a NUL-terminated array of bytes and convert
36 func bytePtrToString(p
*byte) string {
37 a
:= (*[10000]byte)(unsafe
.Pointer(p
))
45 // An addrinfoErrno represents a getaddrinfo, getnameinfo-specific
46 // error number. It's a signed number and a zero value is a non-error
48 type addrinfoErrno
int
50 func (eai addrinfoErrno
) Error() string { return bytePtrToString(libc_gai_strerror(int(eai
))) }
51 func (eai addrinfoErrno
) Temporary() bool { return eai
== syscall
.EAI_AGAIN
}
52 func (eai addrinfoErrno
) Timeout() bool { return false }
54 func cgoLookupHost(name
string) (hosts
[]string, err error
, completed
bool) {
55 addrs
, err
, completed
:= cgoLookupIP(name
)
56 for _
, addr
:= range addrs
{
57 hosts
= append(hosts
, addr
.String())
62 func cgoLookupPort(network
, service
string) (port
int, err error
, completed
bool) {
66 var hints syscall
.Addrinfo
69 case "tcp", "tcp4", "tcp6":
70 hints
.Ai_socktype
= syscall
.SOCK_STREAM
71 hints
.Ai_protocol
= syscall
.IPPROTO_TCP
72 case "udp", "udp4", "udp6":
73 hints
.Ai_socktype
= syscall
.SOCK_DGRAM
74 hints
.Ai_protocol
= syscall
.IPPROTO_UDP
76 return 0, &DNSError
{Err
: "unknown network", Name
: network
+ "/" + service
}, true
78 if len(network
) >= 4 {
81 hints
.Ai_family
= syscall
.AF_INET
83 hints
.Ai_family
= syscall
.AF_INET6
87 s
:= syscall
.StringBytePtr(service
)
88 var res
*syscall
.Addrinfo
89 syscall
.Entersyscall()
90 gerrno
:= libc_getaddrinfo(nil, s
, &hints
, &res
)
94 case syscall
.EAI_SYSTEM
:
95 errno
:= syscall
.GetErrno()
96 if errno
== 0 { // see golang.org/issue/6232
97 errno
= syscall
.EMFILE
101 err
= addrinfoErrno(gerrno
)
103 return 0, &DNSError
{Err
: err
.Error(), Name
: network
+ "/" + service
}, true
105 defer libc_freeaddrinfo(res
)
107 for r
:= res
; r
!= nil; r
= r
.Ai_next
{
109 case syscall
.AF_INET
:
110 sa
:= (*syscall
.RawSockaddrInet4
)(unsafe
.Pointer(r
.Ai_addr
))
111 p
:= (*[2]byte)(unsafe
.Pointer(&sa
.Port
))
112 return int(p
[0])<<8 |
int(p
[1]), nil, true
113 case syscall
.AF_INET6
:
114 sa
:= (*syscall
.RawSockaddrInet6
)(unsafe
.Pointer(r
.Ai_addr
))
115 p
:= (*[2]byte)(unsafe
.Pointer(&sa
.Port
))
116 return int(p
[0])<<8 |
int(p
[1]), nil, true
119 return 0, &DNSError
{Err
: "unknown port", Name
: network
+ "/" + service
}, true
122 func cgoLookupIPCNAME(name
string) (addrs
[]IPAddr
, cname
string, err error
, completed
bool) {
124 defer releaseThread()
126 var hints syscall
.Addrinfo
127 hints
.Ai_flags
= int32(cgoAddrInfoFlags
)
128 hints
.Ai_socktype
= syscall
.SOCK_STREAM
130 h
:= syscall
.StringBytePtr(name
)
131 var res
*syscall
.Addrinfo
132 syscall
.Entersyscall()
133 gerrno
:= libc_getaddrinfo(h
, nil, &hints
, &res
)
134 syscall
.Exitsyscall()
137 case syscall
.EAI_SYSTEM
:
138 errno
:= syscall
.GetErrno()
140 // err should not be nil, but sometimes getaddrinfo returns
141 // gerrno == C.EAI_SYSTEM with err == nil on Linux.
142 // The report claims that it happens when we have too many
143 // open files, so use syscall.EMFILE (too many open files in system).
144 // Most system calls would return ENFILE (too many open files),
145 // so at the least EMFILE should be easy to recognize if this
146 // comes up again. golang.org/issue/6232.
147 errno
= syscall
.EMFILE
150 case syscall
.EAI_NONAME
:
153 err
= addrinfoErrno(gerrno
)
155 return nil, "", &DNSError
{Err
: err
.Error(), Name
: name
}, true
157 defer libc_freeaddrinfo(res
)
160 cname
= bytePtrToString((*byte)(unsafe
.Pointer(res
.Ai_canonname
)))
164 if len(cname
) > 0 && cname
[len(cname
)-1] != '.' {
168 for r
:= res
; r
!= nil; r
= r
.Ai_next
{
169 // We only asked for SOCK_STREAM, but check anyhow.
170 if r
.Ai_socktype
!= syscall
.SOCK_STREAM
{
174 case syscall
.AF_INET
:
175 sa
:= (*syscall
.RawSockaddrInet4
)(unsafe
.Pointer(r
.Ai_addr
))
176 addr
:= IPAddr
{IP
: copyIP(sa
.Addr
[:])}
177 addrs
= append(addrs
, addr
)
178 case syscall
.AF_INET6
:
179 sa
:= (*syscall
.RawSockaddrInet6
)(unsafe
.Pointer(r
.Ai_addr
))
180 addr
:= IPAddr
{IP
: copyIP(sa
.Addr
[:]), Zone
: zoneToString(int(sa
.Scope_id
))}
181 addrs
= append(addrs
, addr
)
184 return addrs
, cname
, nil, true
187 func cgoLookupIP(name
string) (addrs
[]IPAddr
, err error
, completed
bool) {
188 addrs
, _
, err
, completed
= cgoLookupIPCNAME(name
)
192 func cgoLookupCNAME(name
string) (cname
string, err error
, completed
bool) {
193 _
, cname
, err
, completed
= cgoLookupIPCNAME(name
)
197 // These are roughly enough for the following:
199 // Source Encoding Maximum length of single name entry
200 // Unicast DNS ASCII or <=253 + a NUL terminator
201 // Unicode in RFC 5892 252 * total number of labels + delimiters + a NUL terminator
202 // Multicast DNS UTF-8 in RFC 5198 or <=253 + a NUL terminator
203 // the same as unicast DNS ASCII <=253 + a NUL terminator
204 // Local database various depends on implementation
207 maxNameinfoLen
= 4096
210 func cgoLookupPTR(addr
string) ([]string, error
, bool) {
212 defer releaseThread()
215 ip
:= parseIPv4(addr
)
217 ip
, zone
= parseIPv6(addr
, true)
220 return nil, &DNSError
{Err
: "invalid address", Name
: addr
}, true
222 sa
, salen
:= cgoSockaddr(ip
, zone
)
224 return nil, &DNSError
{Err
: "invalid address " + ip
.String(), Name
: addr
}, true
229 for l
:= nameinfoLen
; l
<= maxNameinfoLen
; l
*= 2 {
231 gerrno
, err
= cgoNameinfoPTR(b
, sa
, salen
)
232 if gerrno
== 0 || gerrno
!= syscall
.EAI_OVERFLOW
{
238 case syscall
.EAI_SYSTEM
:
239 if err
== nil { // see golang.org/issue/6232
243 err
= addrinfoErrno(gerrno
)
245 return nil, &DNSError
{Err
: err
.Error(), Name
: addr
}, true
248 for i
:= 0; i
< len(b
); i
++ {
254 return []string{absDomainName(b
)}, nil, true
257 func cgoSockaddr(ip IP
, zone
string) (*syscall
.RawSockaddr
, syscall
.Socklen_t
) {
258 if ip4
:= ip
.To4(); ip4
!= nil {
259 return cgoSockaddrInet4(ip4
), syscall
.Socklen_t(syscall
.SizeofSockaddrInet4
)
261 if ip6
:= ip
.To16(); ip6
!= nil {
262 return cgoSockaddrInet6(ip6
, zoneToInt(zone
)), syscall
.Socklen_t(syscall
.SizeofSockaddrInet6
)
267 func copyIP(x IP
) IP
{
271 y
:= make(IP
, len(x
))