...

Source file src/net/lookup_unix.go

Documentation: net

		 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 || linux || netbsd || openbsd || solaris
		 6  // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
		 7  
		 8  package net
		 9  
		10  import (
		11  	"context"
		12  	"internal/bytealg"
		13  	"sync"
		14  	"syscall"
		15  
		16  	"golang.org/x/net/dns/dnsmessage"
		17  )
		18  
		19  var onceReadProtocols sync.Once
		20  
		21  // readProtocols loads contents of /etc/protocols into protocols map
		22  // for quick access.
		23  func 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.
		54  func lookupProtocol(_ context.Context, name string) (int, error) {
		55  	onceReadProtocols.Do(readProtocols)
		56  	return lookupProtocolMap(name)
		57  }
		58  
		59  func (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  
		79  func (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  
		91  func (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  
	 107  func (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  
	 123  func (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  
	 132  func (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  
	 184  func (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  
	 227  func (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  
	 268  func (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  
	 323  func (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.
	 342  func 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  

View as plain text