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.
5 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
14 "golang_org/x/net/dns/dnsmessage"
17 var onceReadProtocols sync
.Once
19 // readProtocols loads contents of /etc/protocols into protocols map
21 func readProtocols() {
22 file
, err
:= open("/etc/protocols")
28 for line
, ok
:= file
.readLine(); ok
; line
, ok
= file
.readLine() {
29 // tcp 6 TCP # transmission control protocol
30 if i
:= byteIndex(line
, '#'); i
>= 0 {
37 if proto
, _
, ok
:= dtoi(f
[1]); ok
{
38 if _
, ok
:= protocols
[f
[0]]; !ok
{
39 protocols
[f
[0]] = proto
41 for _
, alias
:= range f
[2:] {
42 if _
, ok
:= protocols
[alias
]; !ok
{
43 protocols
[alias
] = proto
50 // lookupProtocol looks up IP protocol name in /etc/protocols and
51 // returns correspondent protocol number.
52 func lookupProtocol(_ context
.Context
, name
string) (int, error
) {
53 onceReadProtocols
.Do(readProtocols
)
54 return lookupProtocolMap(name
)
57 func (r
*Resolver
) dial(ctx context
.Context
, network
, server
string) (Conn
, error
) {
58 // Calling Dial here is scary -- we have to be sure not to
59 // dial a name that will require a DNS lookup, or Dial will
60 // call back here to translate it. The DNS config parser has
61 // already checked that all the cfg.servers are IP
62 // addresses, which Dial will use without a DNS lookup.
65 if r
!= nil && r
.Dial
!= nil {
66 c
, err
= r
.Dial(ctx
, network
, server
)
69 c
, err
= d
.DialContext(ctx
, network
, server
)
72 return nil, mapErr(err
)
77 func (r
*Resolver
) lookupHost(ctx context
.Context
, host
string) (addrs
[]string, err error
) {
78 order
:= systemConf().hostLookupOrder(r
, host
)
79 if !r
.preferGo() && order
== hostLookupCgo
{
80 if addrs
, err
, ok
:= cgoLookupHost(ctx
, host
); ok
{
83 // cgo not available (or netgo); fall back to Go's DNS resolver
84 order
= hostLookupFilesDNS
86 return r
.goLookupHostOrder(ctx
, host
, order
)
89 func (r
*Resolver
) lookupIP(ctx context
.Context
, host
string) (addrs
[]IPAddr
, err error
) {
91 return r
.goLookupIP(ctx
, host
)
93 order
:= systemConf().hostLookupOrder(r
, host
)
94 if order
== hostLookupCgo
{
95 if addrs
, err
, ok
:= cgoLookupIP(ctx
, host
); ok
{
98 // cgo not available (or netgo); fall back to Go's DNS resolver
99 order
= hostLookupFilesDNS
101 ips
, _
, err
:= r
.goLookupIPCNAMEOrder(ctx
, host
, order
)
105 func (r
*Resolver
) lookupPort(ctx context
.Context
, network
, service
string) (int, error
) {
106 if !r
.preferGo() && systemConf().canUseCgo() {
107 if port
, err
, ok
:= cgoLookupPort(ctx
, network
, service
); ok
{
109 // Issue 18213: if cgo fails, first check to see whether we
110 // have the answer baked-in to the net package.
111 if port
, err
:= goLookupPort(network
, service
); err
== nil {
118 return goLookupPort(network
, service
)
121 func (r
*Resolver
) lookupCNAME(ctx context
.Context
, name
string) (string, error
) {
122 if !r
.preferGo() && systemConf().canUseCgo() {
123 if cname
, err
, ok
:= cgoLookupCNAME(ctx
, name
); ok
{
127 return r
.goLookupCNAME(ctx
, name
)
130 func (r
*Resolver
) lookupSRV(ctx context
.Context
, service
, proto
, name
string) (string, []*SRV
, error
) {
132 if service
== "" && proto
== "" {
135 target
= "_" + service
+ "._" + proto
+ "." + name
137 p
, server
, err
:= r
.lookup(ctx
, target
, dnsmessage
.TypeSRV
)
142 var cname dnsmessage
.Name
144 h
, err
:= p
.AnswerHeader()
145 if err
== dnsmessage
.ErrSectionDone
{
149 return "", nil, &DNSError
{
150 Err
: "cannot unmarshal DNS message",
155 if h
.Type
!= dnsmessage
.TypeSRV
{
156 if err
:= p
.SkipAnswer(); err
!= nil {
157 return "", nil, &DNSError
{
158 Err
: "cannot unmarshal DNS message",
165 if cname
.Length
== 0 && h
.Name
.Length
!= 0 {
168 srv
, err
:= p
.SRVResource()
170 return "", nil, &DNSError
{
171 Err
: "cannot unmarshal DNS message",
176 srvs
= append(srvs
, &SRV
{Target
: srv
.Target
.String(), Port
: srv
.Port
, Priority
: srv
.Priority
, Weight
: srv
.Weight
})
178 byPriorityWeight(srvs
).sort()
179 return cname
.String(), srvs
, nil
182 func (r
*Resolver
) lookupMX(ctx context
.Context
, name
string) ([]*MX
, error
) {
183 p
, server
, err
:= r
.lookup(ctx
, name
, dnsmessage
.TypeMX
)
189 h
, err
:= p
.AnswerHeader()
190 if err
== dnsmessage
.ErrSectionDone
{
194 return nil, &DNSError
{
195 Err
: "cannot unmarshal DNS message",
200 if h
.Type
!= dnsmessage
.TypeMX
{
201 if err
:= p
.SkipAnswer(); err
!= nil {
202 return nil, &DNSError
{
203 Err
: "cannot unmarshal DNS message",
210 mx
, err
:= p
.MXResource()
212 return nil, &DNSError
{
213 Err
: "cannot unmarshal DNS message",
218 mxs
= append(mxs
, &MX
{Host
: mx
.MX
.String(), Pref
: mx
.Pref
})
225 func (r
*Resolver
) lookupNS(ctx context
.Context
, name
string) ([]*NS
, error
) {
226 p
, server
, err
:= r
.lookup(ctx
, name
, dnsmessage
.TypeNS
)
232 h
, err
:= p
.AnswerHeader()
233 if err
== dnsmessage
.ErrSectionDone
{
237 return nil, &DNSError
{
238 Err
: "cannot unmarshal DNS message",
243 if h
.Type
!= dnsmessage
.TypeNS
{
244 if err
:= p
.SkipAnswer(); err
!= nil {
245 return nil, &DNSError
{
246 Err
: "cannot unmarshal DNS message",
253 ns
, err
:= p
.NSResource()
255 return nil, &DNSError
{
256 Err
: "cannot unmarshal DNS message",
261 nss
= append(nss
, &NS
{Host
: ns
.NS
.String()})
266 func (r
*Resolver
) lookupTXT(ctx context
.Context
, name
string) ([]string, error
) {
267 p
, server
, err
:= r
.lookup(ctx
, name
, dnsmessage
.TypeTXT
)
273 h
, err
:= p
.AnswerHeader()
274 if err
== dnsmessage
.ErrSectionDone
{
278 return nil, &DNSError
{
279 Err
: "cannot unmarshal DNS message",
284 if h
.Type
!= dnsmessage
.TypeTXT
{
285 if err
:= p
.SkipAnswer(); err
!= nil {
286 return nil, &DNSError
{
287 Err
: "cannot unmarshal DNS message",
294 txt
, err
:= p
.TXTResource()
296 return nil, &DNSError
{
297 Err
: "cannot unmarshal DNS message",
305 txts
= append(txts
, txt
.TXT
...)
311 func (r
*Resolver
) lookupAddr(ctx context
.Context
, addr
string) ([]string, error
) {
312 if !r
.preferGo() && systemConf().canUseCgo() {
313 if ptrs
, err
, ok
:= cgoLookupPTR(ctx
, addr
); ok
{
317 return r
.goLookupPTR(ctx
, addr
)
320 // concurrentThreadsLimit returns the number of threads we permit to
321 // run concurrently doing DNS lookups via cgo. A DNS lookup may use a
322 // file descriptor so we limit this to less than the number of
323 // permitted open files. On some systems, notably Darwin, if
324 // getaddrinfo is unable to open a file descriptor it simply returns
325 // EAI_NONAME rather than a useful error. Limiting the number of
326 // concurrent getaddrinfo calls to less than the permitted number of
327 // file descriptors makes that error less likely. We don't bother to
328 // apply the same limit to DNS lookups run directly from Go, because
329 // there we will return a meaningful "too many open files" error.
330 func concurrentThreadsLimit() int {
331 var rlim syscall
.Rlimit
332 if err
:= syscall
.Getrlimit(syscall
.RLIMIT_NOFILE
, &rlim
); err
!= nil {