dnsmsg.go\
fd.go\
fd_$(GOOS).go\
+ hosts.go\
ip.go\
ipsock.go\
net.go\
return ok
}
-// LookupHost looks up the host name using the local DNS resolver.
+// LookupHost looks for name using the local hosts file and DNS resolver.
// It returns the canonical name for the host and an array of that
// host's addresses.
func LookupHost(name string) (cname string, addrs []string, err os.Error) {
err = dnserr
return
}
-
+ // Use entries from /etc/hosts if they match.
+ addrs = lookupStaticHost(name)
+ if len(addrs) > 0 {
+ cname = name
+ return
+ }
// If name is rooted (trailing dot) or has enough dots,
// try it by itself first.
rooted := len(name) > 0 && name[len(name)-1] == '.'
--- /dev/null
+// 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.
+
+// Read static host/IP entries from /etc/hosts.
+
+package net
+
+import (
+ "os"
+ "sync"
+)
+
+const cacheMaxAge = int64(300) // 5 minutes.
+
+// hostsPath points to the file with static IP/address entries.
+var hostsPath = "/etc/hosts"
+
+// Simple cache.
+var hosts struct {
+ sync.Mutex
+ data map[string][]string
+ time int64
+ path string
+}
+
+func readHosts() {
+ now, _, _ := os.Time()
+ hp := hostsPath
+ if len(hosts.data) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp {
+ hs := make(map[string][]string)
+ var file *file
+ file, _ = open(hp)
+ 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 || ParseIP(f[0]) == nil {
+ continue
+ }
+ h := f[1]
+ old, _ := hs[h]
+ hs[h] = appendHost(old, f[0])
+ }
+ // Update the data cache.
+ hosts.time, _, _ = os.Time()
+ hosts.path = hp
+ hosts.data = hs
+ file.close()
+ }
+}
+
+func appendHost(hosts []string, address string) []string {
+ n := len(hosts)
+ if n+1 > cap(hosts) { // reallocate
+ a := make([]string, n, 2*n+1)
+ copy(a, hosts)
+ hosts = a
+ }
+ hosts = hosts[0 : n+1]
+ hosts[n] = address
+ return hosts
+}
+
+// lookupStaticHosts 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.data) != 0 {
+ if ips, ok := hosts.data[host]; ok {
+ return ips
+ }
+ }
+ return nil
+}
--- /dev/null
+// 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 (
+ "testing"
+)
+
+type hostTest struct {
+ host string
+ ips []IP
+}
+
+
+var hosttests = []hostTest{
+ hostTest{"odin", []IP{
+ IPv4(127, 0, 0, 2),
+ IPv4(127, 0, 0, 3),
+ ParseIP("::2"),
+ }},
+ hostTest{"thor", []IP{
+ IPv4(127, 1, 1, 1),
+ }},
+ hostTest{"loki", []IP{}},
+}
+
+func TestLookupStaticHost(t *testing.T) {
+ p := hostsPath
+ hostsPath = "hosts_testdata"
+ 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))
+ return
+ }
+ for k, v := range ips {
+ if tt.ips[k].String() != v {
+ t.Errorf("lookupStaticHost(%q) = %v; want %v",
+ tt.host, v, tt.ips[k])
+ }
+ }
+ }
+ hostsPath = p
+}
--- /dev/null
+255.255.255.255 broadcasthost
+127.0.0.2 odin
+127.0.0.3 odin # inline comment
+::2 odin
+127.1.1.1 thor
+# Bogus entries that must be ignored.
+123.123.123 loki
+321.321.321.321
+# TODO(yvesj): Should we be able to parse this? From a Darwin system.
+fe80::1%lo0 localhost
var p [IPv4len]byte
i := 0
for j := 0; j < IPv4len; j++ {
+ if i >= len(s) {
+ // Missing octets.
+ return nil
+ }
if j > 0 {
if s[i] != '.' {
return nil