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. 4 5//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris 6// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris 7 8package net 9 10import ( 11 "context" 12 "internal/bytealg" 13 "sync" 14 "syscall" 15 16 "golang.org/x/net/dns/dnsmessage" 17) 18 19var onceReadProtocols sync.Once 20 21// readProtocols loads contents of /etc/protocols into protocols map 22// for quick access. 23func readProtocols() { 24 file, err := open("/etc/protocols") 25 if err != nil { 26 return 27 } 28 defer file.close() 29 30 for line, ok := file.readLine(); ok; line, ok = file.readLine() { 31 // tcp 6 TCP # transmission control protocol 32 if i := bytealg.IndexByteString(line, '#'); i >= 0 { 33 line = line[0:i] 34 } 35 f := getFields(line) 36 if len(f) < 2 { 37 continue 38 } 39 if proto, _, ok := dtoi(f[1]); ok { 40 if _, ok := protocols[f[0]]; !ok { 41 protocols[f[0]] = proto 42 } 43 for _, alias := range f[2:] { 44 if _, ok := protocols[alias]; !ok { 45 protocols[alias] = proto 46 } 47 } 48 } 49 } 50} 51 52// lookupProtocol looks up IP protocol name in /etc/protocols and 53// returns correspondent protocol number. 54func lookupProtocol(_ context.Context, name string) (int, error) { 55 onceReadProtocols.Do(readProtocols) 56 return lookupProtocolMap(name) 57} 58 59func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) { 60 // Calling Dial here is scary -- we have to be sure not to 61 // dial a name that will require a DNS lookup, or Dial will 62 // call back here to translate it. The DNS config parser has 63 // already checked that all the cfg.servers are IP 64 // addresses, which Dial will use without a DNS lookup. 65 var c Conn 66 var err error 67 if r != nil && r.Dial != nil { 68 c, err = r.Dial(ctx, network, server) 69 } else { 70 var d Dialer 71 c, err = d.DialContext(ctx, network, server) 72 } 73 if err != nil { 74 return nil, mapErr(err) 75 } 76 return c, nil 77} 78 79func (r *Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) { 80 order := systemConf().hostLookupOrder(r, host) 81 if !r.preferGo() && order == hostLookupCgo { 82 if addrs, err, ok := cgoLookupHost(ctx, host); ok { 83 return addrs, err 84 } 85 // cgo not available (or netgo); fall back to Go's DNS resolver 86 order = hostLookupFilesDNS 87 } 88 return r.goLookupHostOrder(ctx, host, order) 89} 90 91func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []IPAddr, err error) { 92 if r.preferGo() { 93 return r.goLookupIP(ctx, network, host) 94 } 95 order := systemConf().hostLookupOrder(r, host) 96 if order == hostLookupCgo { 97 if addrs, err, ok := cgoLookupIP(ctx, network, host); ok { 98 return addrs, err 99 } 100 // cgo not available (or netgo); fall back to Go's DNS resolver 101 order = hostLookupFilesDNS 102 } 103 ips, _, err := r.goLookupIPCNAMEOrder(ctx, network, host, order) 104 return ips, err 105} 106 107func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) { 108 if !r.preferGo() && systemConf().canUseCgo() { 109 if port, err, ok := cgoLookupPort(ctx, network, service); ok { 110 if err != nil { 111 // Issue 18213: if cgo fails, first check to see whether we 112 // have the answer baked-in to the net package. 113 if port, err := goLookupPort(network, service); err == nil { 114 return port, nil 115 } 116 } 117 return port, err 118 } 119 } 120 return goLookupPort(network, service) 121} 122 123func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) { 124 if !r.preferGo() && systemConf().canUseCgo() { 125 if cname, err, ok := cgoLookupCNAME(ctx, name); ok { 126 return cname, err 127 } 128 } 129 return r.goLookupCNAME(ctx, name) 130} 131 132func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { 133 var target string 134 if service == "" && proto == "" { 135 target = name 136 } else { 137 target = "_" + service + "._" + proto + "." + name 138 } 139 p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV) 140 if err != nil { 141 return "", nil, err 142 } 143 var srvs []*SRV 144 var cname dnsmessage.Name 145 for { 146 h, err := p.AnswerHeader() 147 if err == dnsmessage.ErrSectionDone { 148 break 149 } 150 if err != nil { 151 return "", nil, &DNSError{ 152 Err: "cannot unmarshal DNS message", 153 Name: name, 154 Server: server, 155 } 156 } 157 if h.Type != dnsmessage.TypeSRV { 158 if err := p.SkipAnswer(); err != nil { 159 return "", nil, &DNSError{ 160 Err: "cannot unmarshal DNS message", 161 Name: name, 162 Server: server, 163 } 164 } 165 continue 166 } 167 if cname.Length == 0 && h.Name.Length != 0 { 168 cname = h.Name 169 } 170 srv, err := p.SRVResource() 171 if err != nil { 172 return "", nil, &DNSError{ 173 Err: "cannot unmarshal DNS message", 174 Name: name, 175 Server: server, 176 } 177 } 178 srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight}) 179 } 180 byPriorityWeight(srvs).sort() 181 return cname.String(), srvs, nil 182} 183 184func (r *Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) { 185 p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX) 186 if err != nil { 187 return nil, err 188 } 189 var mxs []*MX 190 for { 191 h, err := p.AnswerHeader() 192 if err == dnsmessage.ErrSectionDone { 193 break 194 } 195 if err != nil { 196 return nil, &DNSError{ 197 Err: "cannot unmarshal DNS message", 198 Name: name, 199 Server: server, 200 } 201 } 202 if h.Type != dnsmessage.TypeMX { 203 if err := p.SkipAnswer(); err != nil { 204 return nil, &DNSError{ 205 Err: "cannot unmarshal DNS message", 206 Name: name, 207 Server: server, 208 } 209 } 210 continue 211 } 212 mx, err := p.MXResource() 213 if err != nil { 214 return nil, &DNSError{ 215 Err: "cannot unmarshal DNS message", 216 Name: name, 217 Server: server, 218 } 219 } 220 mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref}) 221 222 } 223 byPref(mxs).sort() 224 return mxs, nil 225} 226 227func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) { 228 p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS) 229 if err != nil { 230 return nil, err 231 } 232 var nss []*NS 233 for { 234 h, err := p.AnswerHeader() 235 if err == dnsmessage.ErrSectionDone { 236 break 237 } 238 if err != nil { 239 return nil, &DNSError{ 240 Err: "cannot unmarshal DNS message", 241 Name: name, 242 Server: server, 243 } 244 } 245 if h.Type != dnsmessage.TypeNS { 246 if err := p.SkipAnswer(); err != nil { 247 return nil, &DNSError{ 248 Err: "cannot unmarshal DNS message", 249 Name: name, 250 Server: server, 251 } 252 } 253 continue 254 } 255 ns, err := p.NSResource() 256 if err != nil { 257 return nil, &DNSError{ 258 Err: "cannot unmarshal DNS message", 259 Name: name, 260 Server: server, 261 } 262 } 263 nss = append(nss, &NS{Host: ns.NS.String()}) 264 } 265 return nss, nil 266} 267 268func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) { 269 p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT) 270 if err != nil { 271 return nil, err 272 } 273 var txts []string 274 for { 275 h, err := p.AnswerHeader() 276 if err == dnsmessage.ErrSectionDone { 277 break 278 } 279 if err != nil { 280 return nil, &DNSError{ 281 Err: "cannot unmarshal DNS message", 282 Name: name, 283 Server: server, 284 } 285 } 286 if h.Type != dnsmessage.TypeTXT { 287 if err := p.SkipAnswer(); err != nil { 288 return nil, &DNSError{ 289 Err: "cannot unmarshal DNS message", 290 Name: name, 291 Server: server, 292 } 293 } 294 continue 295 } 296 txt, err := p.TXTResource() 297 if err != nil { 298 return nil, &DNSError{ 299 Err: "cannot unmarshal DNS message", 300 Name: name, 301 Server: server, 302 } 303 } 304 // Multiple strings in one TXT record need to be 305 // concatenated without separator to be consistent 306 // with previous Go resolver. 307 n := 0 308 for _, s := range txt.TXT { 309 n += len(s) 310 } 311 txtJoin := make([]byte, 0, n) 312 for _, s := range txt.TXT { 313 txtJoin = append(txtJoin, s...) 314 } 315 if len(txts) == 0 { 316 txts = make([]string, 0, 1) 317 } 318 txts = append(txts, string(txtJoin)) 319 } 320 return txts, nil 321} 322 323func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) { 324 if !r.preferGo() && systemConf().canUseCgo() { 325 if ptrs, err, ok := cgoLookupPTR(ctx, addr); ok { 326 return ptrs, err 327 } 328 } 329 return r.goLookupPTR(ctx, addr) 330} 331 332// concurrentThreadsLimit returns the number of threads we permit to 333// run concurrently doing DNS lookups via cgo. A DNS lookup may use a 334// file descriptor so we limit this to less than the number of 335// permitted open files. On some systems, notably Darwin, if 336// getaddrinfo is unable to open a file descriptor it simply returns 337// EAI_NONAME rather than a useful error. Limiting the number of 338// concurrent getaddrinfo calls to less than the permitted number of 339// file descriptors makes that error less likely. We don't bother to 340// apply the same limit to DNS lookups run directly from Go, because 341// there we will return a meaningful "too many open files" error. 342func concurrentThreadsLimit() int { 343 var rlim syscall.Rlimit 344 if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil { 345 return 500 346 } 347 r := int(rlim.Cur) 348 if r > 500 { 349 r = 500 350 } else if r > 30 { 351 r -= 30 352 } 353 return r 354} 355