Source file src/net/lookup_unix.go

     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 unix
     6  
     7  package net
     8  
     9  import (
    10  	"context"
    11  	"internal/bytealg"
    12  	"sync"
    13  	"syscall"
    14  )
    15  
    16  var onceReadProtocols sync.Once
    17  
    18  // readProtocols loads contents of /etc/protocols into protocols map
    19  // for quick access.
    20  func readProtocols() {
    21  	file, err := open("/etc/protocols")
    22  	if err != nil {
    23  		return
    24  	}
    25  	defer file.close()
    26  
    27  	for line, ok := file.readLine(); ok; line, ok = file.readLine() {
    28  		// tcp    6   TCP    # transmission control protocol
    29  		if i := bytealg.IndexByteString(line, '#'); i >= 0 {
    30  			line = line[0:i]
    31  		}
    32  		f := getFields(line)
    33  		if len(f) < 2 {
    34  			continue
    35  		}
    36  		if proto, _, ok := dtoi(f[1]); ok {
    37  			if _, ok := protocols[f[0]]; !ok {
    38  				protocols[f[0]] = proto
    39  			}
    40  			for _, alias := range f[2:] {
    41  				if _, ok := protocols[alias]; !ok {
    42  					protocols[alias] = proto
    43  				}
    44  			}
    45  		}
    46  	}
    47  }
    48  
    49  // lookupProtocol looks up IP protocol name in /etc/protocols and
    50  // returns correspondent protocol number.
    51  func lookupProtocol(_ context.Context, name string) (int, error) {
    52  	onceReadProtocols.Do(readProtocols)
    53  	return lookupProtocolMap(name)
    54  }
    55  
    56  func (r *Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
    57  	order := systemConf().hostLookupOrder(r, host)
    58  	if !r.preferGo() && order == hostLookupCgo {
    59  		if addrs, err, ok := cgoLookupHost(ctx, host); ok {
    60  			return addrs, err
    61  		}
    62  		// cgo not available (or netgo); fall back to Go's DNS resolver
    63  		order = hostLookupFilesDNS
    64  	}
    65  	return r.goLookupHostOrder(ctx, host, order)
    66  }
    67  
    68  func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []IPAddr, err error) {
    69  	if r.preferGo() {
    70  		return r.goLookupIP(ctx, network, host)
    71  	}
    72  	order := systemConf().hostLookupOrder(r, host)
    73  	if order == hostLookupCgo {
    74  		if addrs, err, ok := cgoLookupIP(ctx, network, host); ok {
    75  			return addrs, err
    76  		}
    77  		// cgo not available (or netgo); fall back to Go's DNS resolver
    78  		order = hostLookupFilesDNS
    79  	}
    80  	ips, _, err := r.goLookupIPCNAMEOrder(ctx, network, host, order)
    81  	return ips, err
    82  }
    83  
    84  func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
    85  	if !r.preferGo() && systemConf().canUseCgo() {
    86  		if port, err, ok := cgoLookupPort(ctx, network, service); ok {
    87  			if err != nil {
    88  				// Issue 18213: if cgo fails, first check to see whether we
    89  				// have the answer baked-in to the net package.
    90  				if port, err := goLookupPort(network, service); err == nil {
    91  					return port, nil
    92  				}
    93  			}
    94  			return port, err
    95  		}
    96  	}
    97  	return goLookupPort(network, service)
    98  }
    99  
   100  func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
   101  	if !r.preferGo() && systemConf().canUseCgo() {
   102  		if cname, err, ok := cgoLookupCNAME(ctx, name); ok {
   103  			return cname, err
   104  		}
   105  	}
   106  	return r.goLookupCNAME(ctx, name)
   107  }
   108  
   109  func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
   110  	return r.goLookupSRV(ctx, service, proto, name)
   111  }
   112  
   113  func (r *Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
   114  	return r.goLookupMX(ctx, name)
   115  }
   116  
   117  func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
   118  	return r.goLookupNS(ctx, name)
   119  }
   120  
   121  func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
   122  	return r.goLookupTXT(ctx, name)
   123  }
   124  
   125  func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) {
   126  	if !r.preferGo() && systemConf().canUseCgo() {
   127  		if ptrs, err, ok := cgoLookupPTR(ctx, addr); ok {
   128  			return ptrs, err
   129  		}
   130  	}
   131  	return r.goLookupPTR(ctx, addr)
   132  }
   133  
   134  // concurrentThreadsLimit returns the number of threads we permit to
   135  // run concurrently doing DNS lookups via cgo. A DNS lookup may use a
   136  // file descriptor so we limit this to less than the number of
   137  // permitted open files. On some systems, notably Darwin, if
   138  // getaddrinfo is unable to open a file descriptor it simply returns
   139  // EAI_NONAME rather than a useful error. Limiting the number of
   140  // concurrent getaddrinfo calls to less than the permitted number of
   141  // file descriptors makes that error less likely. We don't bother to
   142  // apply the same limit to DNS lookups run directly from Go, because
   143  // there we will return a meaningful "too many open files" error.
   144  func concurrentThreadsLimit() int {
   145  	var rlim syscall.Rlimit
   146  	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil {
   147  		return 500
   148  	}
   149  	r := int(rlim.Cur)
   150  	if r > 500 {
   151  		r = 500
   152  	} else if r > 30 {
   153  		r -= 30
   154  	}
   155  	return r
   156  }
   157  

View as plain text