github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/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  // Simple cache.
    31  var hosts struct {
    32  	sync.Mutex
    33  	byName map[string][]string
    34  	byAddr map[string][]string
    35  	expire time.Time
    36  	path   string
    37  }
    38  
    39  func readHosts() {
    40  	now := time.Now()
    41  	hp := testHookHostsPath
    42  	if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp {
    43  		hs := make(map[string][]string)
    44  		is := make(map[string][]string)
    45  		var file *file
    46  		if file, _ = open(hp); file == nil {
    47  			return
    48  		}
    49  		for line, ok := file.readLine(); ok; line, ok = file.readLine() {
    50  			if i := byteIndex(line, '#'); i >= 0 {
    51  				// Discard comments.
    52  				line = line[0:i]
    53  			}
    54  			f := getFields(line)
    55  			if len(f) < 2 {
    56  				continue
    57  			}
    58  			addr := parseLiteralIP(f[0])
    59  			if addr == "" {
    60  				continue
    61  			}
    62  			for i := 1; i < len(f); i++ {
    63  				h := []byte(f[i])
    64  				lowerASCIIBytes(h)
    65  				lh := string(h)
    66  				hs[lh] = append(hs[lh], addr)
    67  				is[addr] = append(is[addr], lh)
    68  			}
    69  		}
    70  		// Update the data cache.
    71  		hosts.expire = now.Add(cacheMaxAge)
    72  		hosts.path = hp
    73  		hosts.byName = hs
    74  		hosts.byAddr = is
    75  		file.close()
    76  	}
    77  }
    78  
    79  // lookupStaticHost looks up the addresses for the given host from /etc/hosts.
    80  func lookupStaticHost(host string) []string {
    81  	hosts.Lock()
    82  	defer hosts.Unlock()
    83  	readHosts()
    84  	if len(hosts.byName) != 0 {
    85  		// TODO(jbd,bradfitz): avoid this alloc if host is already all lowercase?
    86  		// or linear scan the byName map if it's small enough?
    87  		lowerHost := []byte(host)
    88  		lowerASCIIBytes(lowerHost)
    89  		if ips, ok := hosts.byName[string(lowerHost)]; ok {
    90  			return ips
    91  		}
    92  	}
    93  	return nil
    94  }
    95  
    96  // lookupStaticAddr looks up the hosts for the given address from /etc/hosts.
    97  func lookupStaticAddr(addr string) []string {
    98  	hosts.Lock()
    99  	defer hosts.Unlock()
   100  	readHosts()
   101  	addr = parseLiteralIP(addr)
   102  	if addr == "" {
   103  		return nil
   104  	}
   105  	if len(hosts.byAddr) != 0 {
   106  		if hosts, ok := hosts.byAddr[addr]; ok {
   107  			return hosts
   108  		}
   109  	}
   110  	return nil
   111  }