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