// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Read static host/IP entries from /etc/hosts.
-
package net
import (
const cacheMaxAge = 5 * time.Minute
-// hostsPath points to the file with static IP/address entries.
-var hostsPath = "/etc/hosts"
+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 {
func readHosts() {
now := time.Now()
- hp := hostsPath
+ hp := testHookHostsPath
if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp {
hs := make(map[string][]string)
is := make(map[string][]string)
line = line[0:i]
}
f := getFields(line)
- if len(f) < 2 || ParseIP(f[0]) == nil {
+ 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], f[0])
- is[f[0]] = append(is[f[0]], h)
+ hs[h] = append(hs[h], addr)
+ is[addr] = append(is[addr], h)
}
}
// Update the data cache.
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
package net
import (
+ "reflect"
"sort"
"testing"
)
-type hostTest struct {
- host string
- ips []IP
+type staticHostEntry struct {
+ in string
+ out []string
}
-var hosttests = []hostTest{
- {"odin", []IP{
- IPv4(127, 0, 0, 2),
- IPv4(127, 0, 0, 3),
- ParseIP("::2"),
- }},
- {"thor", []IP{
- IPv4(127, 1, 1, 1),
- }},
- {"loki", []IP{}},
- {"ullr", []IP{
- IPv4(127, 1, 1, 2),
- }},
- {"ullrhost", []IP{
- IPv4(127, 1, 1, 2),
- }},
+var lookupStaticHostTests = []struct {
+ name string
+ ents []staticHostEntry
+}{
+ {
+ "testdata/hosts",
+ []staticHostEntry{
+ {"odin", []string{"127.0.0.2", "127.0.0.3", "::2"}},
+ {"thor", []string{"127.1.1.1"}},
+ {"ullr", []string{"127.1.1.2"}},
+ {"ullrhost", []string{"127.1.1.2"}},
+ {"localhost", []string{"fe80::1%lo0"}},
+ },
+ },
+ {
+ "testdata/singleline-hosts", // see golang.org/issue/6646
+ []staticHostEntry{
+ {"odin", []string{"127.0.0.2"}},
+ },
+ },
+ {
+ "testdata/ipv4-hosts", // see golang.org/issue/8996
+ []staticHostEntry{
+ {"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}},
+ {"localhost.localdomain", []string{"127.0.0.3"}},
+ },
+ },
+ {
+ "testdata/ipv6-hosts", // see golang.org/issue/8996
+ []staticHostEntry{
+ {"localhost", []string{"::1", "fe80::1", "fe80::2%lo0", "fe80::3%lo0"}},
+ {"localhost.localdomain", []string{"fe80::3%lo0"}},
+ },
+ },
}
func TestLookupStaticHost(t *testing.T) {
- p := hostsPath
- hostsPath = "testdata/hosts"
- for i := 0; i < len(hosttests); i++ {
- tt := hosttests[i]
- ips := lookupStaticHost(tt.host)
- if len(ips) != len(tt.ips) {
- t.Errorf("# of hosts = %v; want %v", len(ips), len(tt.ips))
- continue
- }
- for k, v := range ips {
- if tt.ips[k].String() != v {
- t.Errorf("lookupStaticHost(%q) = %v; want %v", tt.host, v, tt.ips[k])
+ defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+
+ for _, tt := range lookupStaticHostTests {
+ testHookHostsPath = tt.name
+ for _, ent := range tt.ents {
+ addrs := lookupStaticHost(ent.in)
+ if !reflect.DeepEqual(addrs, ent.out) {
+ t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", tt.name, ent.in, addrs, ent.out)
}
}
}
- hostsPath = p
}
-// https://golang.org/issue/6646
-func TestSingleLineHostsFile(t *testing.T) {
- p := hostsPath
- hostsPath = "testdata/hosts_singleline"
+var lookupStaticAddrTests = []struct {
+ name string
+ ents []staticHostEntry
+}{
+ {
+ "testdata/hosts",
+ []staticHostEntry{
+ {"255.255.255.255", []string{"broadcasthost"}},
+ {"127.0.0.2", []string{"odin"}},
+ {"127.0.0.3", []string{"odin"}},
+ {"::2", []string{"odin"}},
+ {"127.1.1.1", []string{"thor"}},
+ {"127.1.1.2", []string{"ullr", "ullrhost"}},
+ {"fe80::1%lo0", []string{"localhost"}},
+ },
+ },
+ {
+ "testdata/singleline-hosts", // see golang.org/issue/6646
+ []staticHostEntry{
+ {"127.0.0.2", []string{"odin"}},
+ },
+ },
+ {
+ "testdata/ipv4-hosts", // see golang.org/issue/8996
+ []staticHostEntry{
+ {"127.0.0.1", []string{"localhost"}},
+ {"127.0.0.2", []string{"localhost"}},
+ {"127.0.0.3", []string{"localhost", "localhost.localdomain"}},
+ },
+ },
+ {
+ "testdata/ipv6-hosts", // see golang.org/issue/8996
+ []staticHostEntry{
+ {"::1", []string{"localhost"}},
+ {"fe80::1", []string{"localhost"}},
+ {"fe80::2%lo0", []string{"localhost"}},
+ {"fe80::3%lo0", []string{"localhost", "localhost.localdomain"}},
+ },
+ },
+}
- ips := lookupStaticHost("odin")
- if len(ips) != 1 || ips[0] != "127.0.0.2" {
- t.Errorf("lookupStaticHost = %v, want %v", ips, []string{"127.0.0.2"})
- }
+func TestLookupStaticAddr(t *testing.T) {
+ defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
- hostsPath = p
+ for _, tt := range lookupStaticAddrTests {
+ testHookHostsPath = tt.name
+ for _, ent := range tt.ents {
+ hosts := lookupStaticAddr(ent.in)
+ if !reflect.DeepEqual(hosts, ent.out) {
+ t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", tt.name, ent.in, hosts, ent.out)
+ }
+ }
+ }
}
func TestLookupHost(t *testing.T) {