github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/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 "context" 9 "internal/nettrace" 10 "internal/singleflight" 11 ) 12 13 // protocols contains minimal mappings between internet protocol 14 // names and numbers for platforms that don't have a complete list of 15 // protocol numbers. 16 // 17 // See http://www.iana.org/assignments/protocol-numbers 18 // 19 // On Unix, this map is augmented by readProtocols via lookupProtocol. 20 var protocols = map[string]int{ 21 "icmp": 1, 22 "igmp": 2, 23 "tcp": 6, 24 "udp": 17, 25 "ipv6-icmp": 58, 26 } 27 28 // services contains minimal mappings between services names and port 29 // numbers for platforms that don't have a complete list of port numbers 30 // (some Solaris distros, nacl, etc). 31 // 32 // See https://www.iana.org/assignments/service-names-port-numbers 33 // 34 // On Unix, this map is augmented by readServices via goLookupPort. 35 var services = map[string]map[string]int{ 36 "udp": { 37 "domain": 53, 38 }, 39 "tcp": { 40 "ftp": 21, 41 "ftps": 990, 42 "gopher": 70, // ʕ◔ϖ◔ʔ 43 "http": 80, 44 "https": 443, 45 "imap2": 143, 46 "imap3": 220, 47 "imaps": 993, 48 "pop3": 110, 49 "pop3s": 995, 50 "smtp": 25, 51 "ssh": 22, 52 "telnet": 23, 53 }, 54 } 55 56 const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow 57 58 func lookupProtocolMap(name string) (int, error) { 59 var lowerProtocol [maxProtoLength]byte 60 n := copy(lowerProtocol[:], name) 61 lowerASCIIBytes(lowerProtocol[:n]) 62 proto, found := protocols[string(lowerProtocol[:n])] 63 if !found || n != len(name) { 64 return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name} 65 } 66 return proto, nil 67 } 68 69 // maxPortBufSize is the longest reasonable name of a service 70 // (non-numeric port). 71 // Currently the longest known IANA-unregistered name is 72 // "mobility-header", so we use that length, plus some slop in case 73 // something longer is added in the future. 74 const maxPortBufSize = len("mobility-header") + 10 75 76 func lookupPortMap(network, service string) (port int, error error) { 77 switch network { 78 case "tcp4", "tcp6": 79 network = "tcp" 80 case "udp4", "udp6": 81 network = "udp" 82 } 83 84 if m, ok := services[network]; ok { 85 var lowerService [maxPortBufSize]byte 86 n := copy(lowerService[:], service) 87 lowerASCIIBytes(lowerService[:n]) 88 if port, ok := m[string(lowerService[:n])]; ok && n == len(service) { 89 return port, nil 90 } 91 } 92 return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service} 93 } 94 95 // DefaultResolver is the resolver used by the package-level Lookup 96 // functions and by Dialers without a specified Resolver. 97 var DefaultResolver = &Resolver{} 98 99 // A Resolver looks up names and numbers. 100 // 101 // A nil *Resolver is equivalent to a zero Resolver. 102 type Resolver struct { 103 // PreferGo controls whether Go's built-in DNS resolver is preferred 104 // on platforms where it's available. It is equivalent to setting 105 // GODEBUG=netdns=go, but scoped to just this resolver. 106 PreferGo bool 107 108 // StrictErrors controls the behavior of temporary errors 109 // (including timeout, socket errors, and SERVFAIL) when using 110 // Go's built-in resolver. For a query composed of multiple 111 // sub-queries (such as an A+AAAA address lookup, or walking the 112 // DNS search list), this option causes such errors to abort the 113 // whole query instead of returning a partial result. This is 114 // not enabled by default because it may affect compatibility 115 // with resolvers that process AAAA queries incorrectly. 116 StrictErrors bool 117 118 // Dial optionally specifies an alternate dialer for use by 119 // Go's built-in DNS resolver to make TCP and UDP connections 120 // to DNS services. The host in the address parameter will 121 // always be a literal IP address and not a host name, and the 122 // port in the address parameter will be a literal port number 123 // and not a service name. 124 // If the Conn returned is also a PacketConn, sent and received DNS 125 // messages must adhere to RFC 1035 section 4.2.1, "UDP usage". 126 // Otherwise, DNS messages transmitted over Conn must adhere 127 // to RFC 7766 section 5, "Transport Protocol Selection". 128 // If nil, the default dialer is used. 129 Dial func(ctx context.Context, network, address string) (Conn, error) 130 131 // TODO(bradfitz): optional interface impl override hook 132 // TODO(bradfitz): Timeout time.Duration? 133 } 134 135 // LookupHost looks up the given host using the local resolver. 136 // It returns a slice of that host's addresses. 137 func LookupHost(host string) (addrs []string, err error) { 138 return DefaultResolver.LookupHost(context.Background(), host) 139 } 140 141 // LookupHost looks up the given host using the local resolver. 142 // It returns a slice of that host's addresses. 143 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) { 144 // Make sure that no matter what we do later, host=="" is rejected. 145 // ParseIP, for example, does accept empty strings. 146 if host == "" { 147 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host} 148 } 149 if ip := ParseIP(host); ip != nil { 150 return []string{host}, nil 151 } 152 return r.lookupHost(ctx, host) 153 } 154 155 // LookupIP looks up host using the local resolver. 156 // It returns a slice of that host's IPv4 and IPv6 addresses. 157 func LookupIP(host string) ([]IP, error) { 158 addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host) 159 if err != nil { 160 return nil, err 161 } 162 ips := make([]IP, len(addrs)) 163 for i, ia := range addrs { 164 ips[i] = ia.IP 165 } 166 return ips, nil 167 } 168 169 // LookupIPAddr looks up host using the local resolver. 170 // It returns a slice of that host's IPv4 and IPv6 addresses. 171 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) { 172 // Make sure that no matter what we do later, host=="" is rejected. 173 // ParseIP, for example, does accept empty strings. 174 if host == "" { 175 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host} 176 } 177 if ip := ParseIP(host); ip != nil { 178 return []IPAddr{{IP: ip}}, nil 179 } 180 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace) 181 if trace != nil && trace.DNSStart != nil { 182 trace.DNSStart(host) 183 } 184 // The underlying resolver func is lookupIP by default but it 185 // can be overridden by tests. This is needed by net/http, so it 186 // uses a context key instead of unexported variables. 187 resolverFunc := r.lookupIP 188 if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string) ([]IPAddr, error)); alt != nil { 189 resolverFunc = alt 190 } 191 192 ch := lookupGroup.DoChan(host, func() (interface{}, error) { 193 return testHookLookupIP(ctx, resolverFunc, host) 194 }) 195 196 select { 197 case <-ctx.Done(): 198 // If the DNS lookup timed out for some reason, force 199 // future requests to start the DNS lookup again 200 // rather than waiting for the current lookup to 201 // complete. See issue 8602. 202 ctxErr := ctx.Err() 203 if ctxErr == context.DeadlineExceeded { 204 lookupGroup.Forget(host) 205 } 206 err := mapErr(ctxErr) 207 if trace != nil && trace.DNSDone != nil { 208 trace.DNSDone(nil, false, err) 209 } 210 return nil, err 211 case r := <-ch: 212 if trace != nil && trace.DNSDone != nil { 213 addrs, _ := r.Val.([]IPAddr) 214 trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err) 215 } 216 return lookupIPReturn(r.Val, r.Err, r.Shared) 217 } 218 } 219 220 // lookupGroup merges LookupIPAddr calls together for lookups 221 // for the same host. The lookupGroup key is is the LookupIPAddr.host 222 // argument. 223 // The return values are ([]IPAddr, error). 224 var lookupGroup singleflight.Group 225 226 // lookupIPReturn turns the return values from singleflight.Do into 227 // the return values from LookupIP. 228 func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) { 229 if err != nil { 230 return nil, err 231 } 232 addrs := addrsi.([]IPAddr) 233 if shared { 234 clone := make([]IPAddr, len(addrs)) 235 copy(clone, addrs) 236 addrs = clone 237 } 238 return addrs, nil 239 } 240 241 // ipAddrsEface returns an empty interface slice of addrs. 242 func ipAddrsEface(addrs []IPAddr) []interface{} { 243 s := make([]interface{}, len(addrs)) 244 for i, v := range addrs { 245 s[i] = v 246 } 247 return s 248 } 249 250 // LookupPort looks up the port for the given network and service. 251 func LookupPort(network, service string) (port int, err error) { 252 return DefaultResolver.LookupPort(context.Background(), network, service) 253 } 254 255 // LookupPort looks up the port for the given network and service. 256 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) { 257 port, needsLookup := parsePort(service) 258 if needsLookup { 259 port, err = r.lookupPort(ctx, network, service) 260 if err != nil { 261 return 0, err 262 } 263 } 264 if 0 > port || port > 65535 { 265 return 0, &AddrError{Err: "invalid port", Addr: service} 266 } 267 return port, nil 268 } 269 270 // LookupCNAME returns the canonical name for the given host. 271 // Callers that do not care about the canonical name can call 272 // LookupHost or LookupIP directly; both take care of resolving 273 // the canonical name as part of the lookup. 274 // 275 // A canonical name is the final name after following zero 276 // or more CNAME records. 277 // LookupCNAME does not return an error if host does not 278 // contain DNS "CNAME" records, as long as host resolves to 279 // address records. 280 func LookupCNAME(host string) (cname string, err error) { 281 return DefaultResolver.lookupCNAME(context.Background(), host) 282 } 283 284 // LookupCNAME returns the canonical name for the given host. 285 // Callers that do not care about the canonical name can call 286 // LookupHost or LookupIP directly; both take care of resolving 287 // the canonical name as part of the lookup. 288 // 289 // A canonical name is the final name after following zero 290 // or more CNAME records. 291 // LookupCNAME does not return an error if host does not 292 // contain DNS "CNAME" records, as long as host resolves to 293 // address records. 294 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) { 295 return r.lookupCNAME(ctx, host) 296 } 297 298 // LookupSRV tries to resolve an SRV query of the given service, 299 // protocol, and domain name. The proto is "tcp" or "udp". 300 // The returned records are sorted by priority and randomized 301 // by weight within a priority. 302 // 303 // LookupSRV constructs the DNS name to look up following RFC 2782. 304 // That is, it looks up _service._proto.name. To accommodate services 305 // publishing SRV records under non-standard names, if both service 306 // and proto are empty strings, LookupSRV looks up name directly. 307 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { 308 return DefaultResolver.lookupSRV(context.Background(), service, proto, name) 309 } 310 311 // LookupSRV tries to resolve an SRV query of the given service, 312 // protocol, and domain name. The proto is "tcp" or "udp". 313 // The returned records are sorted by priority and randomized 314 // by weight within a priority. 315 // 316 // LookupSRV constructs the DNS name to look up following RFC 2782. 317 // That is, it looks up _service._proto.name. To accommodate services 318 // publishing SRV records under non-standard names, if both service 319 // and proto are empty strings, LookupSRV looks up name directly. 320 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) { 321 return r.lookupSRV(ctx, service, proto, name) 322 } 323 324 // LookupMX returns the DNS MX records for the given domain name sorted by preference. 325 func LookupMX(name string) ([]*MX, error) { 326 return DefaultResolver.lookupMX(context.Background(), name) 327 } 328 329 // LookupMX returns the DNS MX records for the given domain name sorted by preference. 330 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { 331 return r.lookupMX(ctx, name) 332 } 333 334 // LookupNS returns the DNS NS records for the given domain name. 335 func LookupNS(name string) ([]*NS, error) { 336 return DefaultResolver.lookupNS(context.Background(), name) 337 } 338 339 // LookupNS returns the DNS NS records for the given domain name. 340 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { 341 return r.lookupNS(ctx, name) 342 } 343 344 // LookupTXT returns the DNS TXT records for the given domain name. 345 func LookupTXT(name string) ([]string, error) { 346 return DefaultResolver.lookupTXT(context.Background(), name) 347 } 348 349 // LookupTXT returns the DNS TXT records for the given domain name. 350 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) { 351 return r.lookupTXT(ctx, name) 352 } 353 354 // LookupAddr performs a reverse lookup for the given address, returning a list 355 // of names mapping to that address. 356 // 357 // When using the host C library resolver, at most one result will be 358 // returned. To bypass the host resolver, use a custom Resolver. 359 func LookupAddr(addr string) (names []string, err error) { 360 return DefaultResolver.lookupAddr(context.Background(), addr) 361 } 362 363 // LookupAddr performs a reverse lookup for the given address, returning a list 364 // of names mapping to that address. 365 func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) { 366 return r.lookupAddr(ctx, addr) 367 }