rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/net/lookup.go (about)

     1  // Copyright 2012 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  package net
     6  
     7  import (
     8  	"internal/singleflight"
     9  	"time"
    10  )
    11  
    12  // protocols contains minimal mappings between internet protocol
    13  // names and numbers for platforms that don't have a complete list of
    14  // protocol numbers.
    15  //
    16  // See http://www.iana.org/assignments/protocol-numbers
    17  var protocols = map[string]int{
    18  	"icmp": 1, "ICMP": 1,
    19  	"igmp": 2, "IGMP": 2,
    20  	"tcp": 6, "TCP": 6,
    21  	"udp": 17, "UDP": 17,
    22  	"ipv6-icmp": 58, "IPV6-ICMP": 58, "IPv6-ICMP": 58,
    23  }
    24  
    25  // LookupHost looks up the given host using the local resolver.
    26  // It returns an array of that host's addresses.
    27  func LookupHost(host string) (addrs []string, err error) {
    28  	return lookupHost(host)
    29  }
    30  
    31  // LookupIP looks up host using the local resolver.
    32  // It returns an array of that host's IPv4 and IPv6 addresses.
    33  func LookupIP(host string) (ips []IP, err error) {
    34  	addrs, err := lookupIPMerge(host)
    35  	if err != nil {
    36  		return
    37  	}
    38  	ips = make([]IP, len(addrs))
    39  	for i, addr := range addrs {
    40  		ips[i] = addr.IP
    41  	}
    42  	return
    43  }
    44  
    45  var lookupGroup singleflight.Group
    46  
    47  // lookupIPMerge wraps lookupIP, but makes sure that for any given
    48  // host, only one lookup is in-flight at a time. The returned memory
    49  // is always owned by the caller.
    50  func lookupIPMerge(host string) (addrs []IPAddr, err error) {
    51  	addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
    52  		return testHookLookupIP(lookupIP, host)
    53  	})
    54  	return lookupIPReturn(addrsi, err, shared)
    55  }
    56  
    57  // lookupIPReturn turns the return values from singleflight.Do into
    58  // the return values from LookupIP.
    59  func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	addrs := addrsi.([]IPAddr)
    64  	if shared {
    65  		clone := make([]IPAddr, len(addrs))
    66  		copy(clone, addrs)
    67  		addrs = clone
    68  	}
    69  	return addrs, nil
    70  }
    71  
    72  // lookupIPDeadline looks up a hostname with a deadline.
    73  func lookupIPDeadline(host string, deadline time.Time) (addrs []IPAddr, err error) {
    74  	if deadline.IsZero() {
    75  		return lookupIPMerge(host)
    76  	}
    77  
    78  	// We could push the deadline down into the name resolution
    79  	// functions.  However, the most commonly used implementation
    80  	// calls getaddrinfo, which has no timeout.
    81  
    82  	timeout := deadline.Sub(time.Now())
    83  	if timeout <= 0 {
    84  		return nil, errTimeout
    85  	}
    86  	t := time.NewTimer(timeout)
    87  	defer t.Stop()
    88  
    89  	ch := lookupGroup.DoChan(host, func() (interface{}, error) {
    90  		return testHookLookupIP(lookupIP, host)
    91  	})
    92  
    93  	select {
    94  	case <-t.C:
    95  		// The DNS lookup timed out for some reason.  Force
    96  		// future requests to start the DNS lookup again
    97  		// rather than waiting for the current lookup to
    98  		// complete.  See issue 8602.
    99  		lookupGroup.Forget(host)
   100  
   101  		return nil, errTimeout
   102  
   103  	case r := <-ch:
   104  		return lookupIPReturn(r.Val, r.Err, r.Shared)
   105  	}
   106  }
   107  
   108  // LookupPort looks up the port for the given network and service.
   109  func LookupPort(network, service string) (port int, err error) {
   110  	return lookupPort(network, service)
   111  }
   112  
   113  // LookupCNAME returns the canonical DNS host for the given name.
   114  // Callers that do not care about the canonical name can call
   115  // LookupHost or LookupIP directly; both take care of resolving
   116  // the canonical name as part of the lookup.
   117  func LookupCNAME(name string) (cname string, err error) {
   118  	return lookupCNAME(name)
   119  }
   120  
   121  // LookupSRV tries to resolve an SRV query of the given service,
   122  // protocol, and domain name.  The proto is "tcp" or "udp".
   123  // The returned records are sorted by priority and randomized
   124  // by weight within a priority.
   125  //
   126  // LookupSRV constructs the DNS name to look up following RFC 2782.
   127  // That is, it looks up _service._proto.name.  To accommodate services
   128  // publishing SRV records under non-standard names, if both service
   129  // and proto are empty strings, LookupSRV looks up name directly.
   130  func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
   131  	return lookupSRV(service, proto, name)
   132  }
   133  
   134  // LookupMX returns the DNS MX records for the given domain name sorted by preference.
   135  func LookupMX(name string) (mx []*MX, err error) {
   136  	return lookupMX(name)
   137  }
   138  
   139  // LookupNS returns the DNS NS records for the given domain name.
   140  func LookupNS(name string) (ns []*NS, err error) {
   141  	return lookupNS(name)
   142  }
   143  
   144  // LookupTXT returns the DNS TXT records for the given domain name.
   145  func LookupTXT(name string) (txt []string, err error) {
   146  	return lookupTXT(name)
   147  }
   148  
   149  // LookupAddr performs a reverse lookup for the given address, returning a list
   150  // of names mapping to that address.
   151  func LookupAddr(addr string) (name []string, err error) {
   152  	return lookupAddr(addr)
   153  }