libgo: update to Go 1.11
[official-gcc.git] / libgo / go / net / lookup_unix.go
blob76d6ae30f78b33af7440c45ab6dbe35829fd4624
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
7 package net
9 import (
10 "context"
11 "sync"
12 "syscall"
14 "golang_org/x/net/dns/dnsmessage"
17 var onceReadProtocols sync.Once
19 // readProtocols loads contents of /etc/protocols into protocols map
20 // for quick access.
21 func readProtocols() {
22 file, err := open("/etc/protocols")
23 if err != nil {
24 return
26 defer file.close()
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 {
31 line = line[0:i]
33 f := getFields(line)
34 if len(f) < 2 {
35 continue
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.
63 var c Conn
64 var err error
65 if r != nil && r.Dial != nil {
66 c, err = r.Dial(ctx, network, server)
67 } else {
68 var d Dialer
69 c, err = d.DialContext(ctx, network, server)
71 if err != nil {
72 return nil, mapErr(err)
74 return c, nil
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 {
81 return addrs, err
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) {
90 if r.preferGo() {
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 {
96 return addrs, err
98 // cgo not available (or netgo); fall back to Go's DNS resolver
99 order = hostLookupFilesDNS
101 ips, _, err := r.goLookupIPCNAMEOrder(ctx, host, order)
102 return ips, err
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 {
108 if err != nil {
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 {
112 return port, nil
115 return port, err
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 {
124 return cname, err
127 return r.goLookupCNAME(ctx, name)
130 func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
131 var target string
132 if service == "" && proto == "" {
133 target = name
134 } else {
135 target = "_" + service + "._" + proto + "." + name
137 p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV)
138 if err != nil {
139 return "", nil, err
141 var srvs []*SRV
142 var cname dnsmessage.Name
143 for {
144 h, err := p.AnswerHeader()
145 if err == dnsmessage.ErrSectionDone {
146 break
148 if err != nil {
149 return "", nil, &DNSError{
150 Err: "cannot unmarshal DNS message",
151 Name: name,
152 Server: server,
155 if h.Type != dnsmessage.TypeSRV {
156 if err := p.SkipAnswer(); err != nil {
157 return "", nil, &DNSError{
158 Err: "cannot unmarshal DNS message",
159 Name: name,
160 Server: server,
163 continue
165 if cname.Length == 0 && h.Name.Length != 0 {
166 cname = h.Name
168 srv, err := p.SRVResource()
169 if err != nil {
170 return "", nil, &DNSError{
171 Err: "cannot unmarshal DNS message",
172 Name: name,
173 Server: server,
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)
184 if err != nil {
185 return nil, err
187 var mxs []*MX
188 for {
189 h, err := p.AnswerHeader()
190 if err == dnsmessage.ErrSectionDone {
191 break
193 if err != nil {
194 return nil, &DNSError{
195 Err: "cannot unmarshal DNS message",
196 Name: name,
197 Server: server,
200 if h.Type != dnsmessage.TypeMX {
201 if err := p.SkipAnswer(); err != nil {
202 return nil, &DNSError{
203 Err: "cannot unmarshal DNS message",
204 Name: name,
205 Server: server,
208 continue
210 mx, err := p.MXResource()
211 if err != nil {
212 return nil, &DNSError{
213 Err: "cannot unmarshal DNS message",
214 Name: name,
215 Server: server,
218 mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref})
221 byPref(mxs).sort()
222 return mxs, nil
225 func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
226 p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS)
227 if err != nil {
228 return nil, err
230 var nss []*NS
231 for {
232 h, err := p.AnswerHeader()
233 if err == dnsmessage.ErrSectionDone {
234 break
236 if err != nil {
237 return nil, &DNSError{
238 Err: "cannot unmarshal DNS message",
239 Name: name,
240 Server: server,
243 if h.Type != dnsmessage.TypeNS {
244 if err := p.SkipAnswer(); err != nil {
245 return nil, &DNSError{
246 Err: "cannot unmarshal DNS message",
247 Name: name,
248 Server: server,
251 continue
253 ns, err := p.NSResource()
254 if err != nil {
255 return nil, &DNSError{
256 Err: "cannot unmarshal DNS message",
257 Name: name,
258 Server: server,
261 nss = append(nss, &NS{Host: ns.NS.String()})
263 return nss, nil
266 func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
267 p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT)
268 if err != nil {
269 return nil, err
271 var txts []string
272 for {
273 h, err := p.AnswerHeader()
274 if err == dnsmessage.ErrSectionDone {
275 break
277 if err != nil {
278 return nil, &DNSError{
279 Err: "cannot unmarshal DNS message",
280 Name: name,
281 Server: server,
284 if h.Type != dnsmessage.TypeTXT {
285 if err := p.SkipAnswer(); err != nil {
286 return nil, &DNSError{
287 Err: "cannot unmarshal DNS message",
288 Name: name,
289 Server: server,
292 continue
294 txt, err := p.TXTResource()
295 if err != nil {
296 return nil, &DNSError{
297 Err: "cannot unmarshal DNS message",
298 Name: name,
299 Server: server,
302 if len(txts) == 0 {
303 txts = txt.TXT
304 } else {
305 txts = append(txts, txt.TXT...)
308 return txts, nil
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 {
314 return ptrs, err
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 {
333 return 500
335 r := int(rlim.Cur)
336 if r > 500 {
337 r = 500
338 } else if r > 30 {
339 r -= 30
341 return r