Black Lives Matter. Support the Equal Justice Initiative.

Source file src/net/hosts.go

Documentation: net

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

View as plain text