github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/net/hosts.go (about) 1 // Copyright 2009 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 "sync" 9 "time" 10 ) 11 12 const cacheMaxAge = 5 * time.Minute 13 14 func parseLiteralIP(addr string) string { 15 var ip IP 16 var zone string 17 ip = parseIPv4(addr) 18 if ip == nil { 19 ip, zone = parseIPv6(addr, true) 20 } 21 if ip == nil { 22 return "" 23 } 24 if zone == "" { 25 return ip.String() 26 } 27 return ip.String() + "%" + zone 28 } 29 30 // hosts contains known host entries. 31 var hosts struct { 32 sync.Mutex 33 34 // Key for the list of literal IP addresses must be a host 35 // name. It would be part of DNS labels, a FQDN or an absolute 36 // FQDN. 37 // For now the key is converted to lower case for convenience. 38 byName map[string][]string 39 40 // Key for the list of host names must be a literal IP address 41 // including IPv6 address with zone identifier. 42 // We don't support old-classful IP address notation. 43 byAddr map[string][]string 44 45 expire time.Time 46 path string 47 } 48 49 func readHosts() { 50 now := time.Now() 51 hp := testHookHostsPath 52 if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp { 53 hs := make(map[string][]string) 54 is := make(map[string][]string) 55 var file *file 56 if file, _ = open(hp); file == nil { 57 return 58 } 59 for line, ok := file.readLine(); ok; line, ok = file.readLine() { 60 if i := byteIndex(line, '#'); i >= 0 { 61 // Discard comments. 62 line = line[0:i] 63 } 64 f := getFields(line) 65 if len(f) < 2 { 66 continue 67 } 68 addr := parseLiteralIP(f[0]) 69 if addr == "" { 70 continue 71 } 72 for i := 1; i < len(f); i++ { 73 name := absDomainName([]byte(f[i])) 74 h := []byte(f[i]) 75 lowerASCIIBytes(h) 76 key := absDomainName(h) 77 hs[key] = append(hs[key], addr) 78 is[addr] = append(is[addr], name) 79 } 80 } 81 // Update the data cache. 82 hosts.expire = now.Add(cacheMaxAge) 83 hosts.path = hp 84 hosts.byName = hs 85 hosts.byAddr = is 86 file.close() 87 } 88 } 89 90 // lookupStaticHost looks up the addresses for the given host from /etc/hosts. 91 func lookupStaticHost(host string) []string { 92 hosts.Lock() 93 defer hosts.Unlock() 94 readHosts() 95 if len(hosts.byName) != 0 { 96 // TODO(jbd,bradfitz): avoid this alloc if host is already all lowercase? 97 // or linear scan the byName map if it's small enough? 98 lowerHost := []byte(host) 99 lowerASCIIBytes(lowerHost) 100 if ips, ok := hosts.byName[absDomainName(lowerHost)]; ok { 101 return ips 102 } 103 } 104 return nil 105 } 106 107 // lookupStaticAddr looks up the hosts for the given address from /etc/hosts. 108 func lookupStaticAddr(addr string) []string { 109 hosts.Lock() 110 defer hosts.Unlock() 111 readHosts() 112 addr = parseLiteralIP(addr) 113 if addr == "" { 114 return nil 115 } 116 if len(hosts.byAddr) != 0 { 117 if hosts, ok := hosts.byAddr[addr]; ok { 118 return hosts 119 } 120 } 121 return nil 122 }