// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package net import ( "sync" "time" ) const cacheMaxAge = 5 * time.Minute func parseLiteralIP(addr string) string { var ip IP var zone string ip = parseIPv4(addr) if ip == nil { ip, zone = parseIPv6(addr, true) } if ip == nil { return "" } if zone == "" { return ip.String() } return ip.String() + "%" + zone } // Simple cache. var hosts struct { sync.Mutex byName map[string][]string byAddr map[string][]string expire time.Time path string } func readHosts() { now := time.Now() hp := testHookHostsPath if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp { hs := make(map[string][]string) is := make(map[string][]string) var file *file if file, _ = open(hp); file == nil { return } for line, ok := file.readLine(); ok; line, ok = file.readLine() { if i := byteIndex(line, '#'); i >= 0 { // Discard comments. line = line[0:i] } f := getFields(line) if len(f) < 2 { continue } addr := parseLiteralIP(f[0]) if addr == "" { continue } for i := 1; i < len(f); i++ { h := f[i] hs[h] = append(hs[h], addr) is[addr] = append(is[addr], h) } } // Update the data cache. hosts.expire = now.Add(cacheMaxAge) hosts.path = hp hosts.byName = hs hosts.byAddr = is file.close() } } // lookupStaticHost looks up the addresses for the given host from /etc/hosts. func lookupStaticHost(host string) []string { hosts.Lock() defer hosts.Unlock() readHosts() if len(hosts.byName) != 0 { if ips, ok := hosts.byName[host]; ok { return ips } } return nil } // lookupStaticAddr looks up the hosts for the given address from /etc/hosts. func lookupStaticAddr(addr string) []string { hosts.Lock() defer hosts.Unlock() readHosts() addr = parseLiteralIP(addr) if addr == "" { return nil } if len(hosts.byAddr) != 0 { if hosts, ok := hosts.byAddr[addr]; ok { return hosts } } return nil }