func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []string, err error) {
if order == hostLookupFilesDNS || order == hostLookupFiles {
// Use entries from /etc/hosts if they match.
- addrs = lookupStaticHost(name)
+ addrs, _ = lookupStaticHost(name)
if len(addrs) > 0 || order == hostLookupFiles {
return
}
}
// lookup entries from /etc/hosts
-func goLookupIPFiles(name string) (addrs []IPAddr) {
- for _, haddr := range lookupStaticHost(name) {
+func goLookupIPFiles(name string) (addrs []IPAddr, canonical string) {
+ addr, canonical := lookupStaticHost(name)
+ for _, haddr := range addr {
haddr, zone := splitHostZone(haddr)
if ip := ParseIP(haddr); ip != nil {
addr := IPAddr{IP: ip, Zone: zone}
}
}
sortByRFC6724(addrs)
- return
+ return addrs, canonical
}
// goLookupIP is the native Go implementation of LookupIP.
func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name string, order hostLookupOrder) (addrs []IPAddr, cname dnsmessage.Name, err error) {
if order == hostLookupFilesDNS || order == hostLookupFiles {
- addrs = goLookupIPFiles(name)
- if len(addrs) > 0 || order == hostLookupFiles {
- return addrs, dnsmessage.Name{}, nil
+ var canonical string
+ addrs, canonical = goLookupIPFiles(name)
+
+ if len(addrs) > 0 {
+ var err error
+ cname, err = dnsmessage.NewName(canonical)
+ if err != nil {
+ return nil, dnsmessage.Name{}, err
+ }
+ return addrs, cname, nil
+ }
+
+ if order == hostLookupFiles {
+ return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
}
}
+
if !isDomainName(name) {
// See comment in func lookup above about use of errNoSuchHost.
return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
sortByRFC6724(addrs)
if len(addrs) == 0 && !(network == "CNAME" && cname.Length > 0) {
if order == hostLookupDNSFiles {
- addrs = goLookupIPFiles(name)
+ var canonical string
+ addrs, canonical = goLookupIPFiles(name)
+ if len(addrs) > 0 {
+ var err error
+ cname, err = dnsmessage.NewName(canonical)
+ if err != nil {
+ return nil, dnsmessage.Name{}, err
+ }
+ return addrs, cname, nil
+ }
}
- if len(addrs) == 0 && lastErr != nil {
+ if lastErr != nil {
return nil, dnsmessage.Name{}, lastErr
}
}
}
}
+func TestGoLookupIPCNAMEOrderHostsAliasesFilesOnlyMode(t *testing.T) {
+ defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+ testHookHostsPath = "testdata/aliases"
+ mode := hostLookupFiles
+
+ for _, v := range lookupStaticHostAliasesTest {
+ testGoLookupIPCNAMEOrderHostsAliases(t, mode, v.lookup, absDomainName(v.res))
+ }
+}
+
+func TestGoLookupIPCNAMEOrderHostsAliasesFilesDNSMode(t *testing.T) {
+ defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+ testHookHostsPath = "testdata/aliases"
+ mode := hostLookupFilesDNS
+
+ for _, v := range lookupStaticHostAliasesTest {
+ testGoLookupIPCNAMEOrderHostsAliases(t, mode, v.lookup, absDomainName(v.res))
+ }
+}
+
+var goLookupIPCNAMEOrderDNSFilesModeTests = []struct {
+ lookup, res string
+}{
+ // 127.0.1.1
+ {"invalid.invalid", "invalid.test"},
+}
+
+func TestGoLookupIPCNAMEOrderHostsAliasesDNSFilesMode(t *testing.T) {
+ defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+ testHookHostsPath = "testdata/aliases"
+ mode := hostLookupDNSFiles
+
+ for _, v := range goLookupIPCNAMEOrderDNSFilesModeTests {
+ testGoLookupIPCNAMEOrderHostsAliases(t, mode, v.lookup, absDomainName(v.res))
+ }
+}
+
+func testGoLookupIPCNAMEOrderHostsAliases(t *testing.T, mode hostLookupOrder, lookup, lookupRes string) {
+ ins := []string{lookup, absDomainName(lookup), strings.ToLower(lookup), strings.ToUpper(lookup)}
+ for _, in := range ins {
+ _, res, err := goResolver.goLookupIPCNAMEOrder(context.Background(), "ip", in, mode)
+ if err != nil {
+ t.Errorf("expected err == nil, but got error: %v", err)
+ }
+ if res.String() != lookupRes {
+ t.Errorf("goLookupIPCNAMEOrder(%v): got %v, want %v", in, res, lookupRes)
+ }
+ }
+}
+
// Test that we advertise support for a larger DNS packet size.
// This isn't a great test as it just tests the dnsmessage package
// against itself.
return ip.String() + "%" + zone
}
+type byName struct {
+ addrs []string
+ canonicalName string
+}
+
// hosts contains known host entries.
var hosts struct {
sync.Mutex
// name. It would be part of DNS labels, a FQDN or an absolute
// FQDN.
// For now the key is converted to lower case for convenience.
- byName map[string][]string
+ byName map[string]byName
// Key for the list of host names must be a literal IP address
// including IPv6 address with zone identifier.
return
}
- hs := make(map[string][]string)
+ hs := make(map[string]byName)
is := make(map[string][]string)
+
var file *file
if file, _ = open(hp); file == nil {
return
if addr == "" {
continue
}
+
+ var canonical string
for i := 1; i < len(f); i++ {
name := absDomainName(f[i])
h := []byte(f[i])
lowerASCIIBytes(h)
key := absDomainName(string(h))
- hs[key] = append(hs[key], addr)
+
+ if i == 1 {
+ canonical = key
+ }
+
is[addr] = append(is[addr], name)
+
+ if v,ok := hs[key]; ok {
+ hs[key] = byName{
+ addrs: append(v.addrs, addr),
+ canonicalName: v.canonicalName,
+ }
+ continue
+ }
+
+ hs[key] = byName{
+ addrs: []string{addr},
+ canonicalName: canonical,
+ }
}
}
// Update the data cache.
file.close()
}
-// lookupStaticHost looks up the addresses for the given host from /etc/hosts.
-func lookupStaticHost(host string) []string {
+// lookupStaticHost looks up the addresses and the cannonical name for the given host from /etc/hosts.
+func lookupStaticHost(host string) ([]string, string) {
hosts.Lock()
defer hosts.Unlock()
readHosts()
lowerASCIIBytes(lowerHost)
host = string(lowerHost)
}
- if ips, ok := hosts.byName[absDomainName(host)]; ok {
- ipsCp := make([]string, len(ips))
- copy(ipsCp, ips)
- return ipsCp
+ if byName, ok := hosts.byName[absDomainName(host)]; ok {
+ ipsCp := make([]string, len(byName.addrs))
+ copy(ipsCp, byName.addrs)
+ return ipsCp, byName.canonicalName
}
}
- return nil
+ return nil, ""
}
// lookupStaticAddr looks up the hosts for the given address from /etc/hosts.
func testStaticHost(t *testing.T, hostsPath string, ent staticHostEntry) {
ins := []string{ent.in, absDomainName(ent.in), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
for _, in := range ins {
- addrs := lookupStaticHost(in)
+ addrs, _ := lookupStaticHost(in)
if !reflect.DeepEqual(addrs, ent.out) {
t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", hostsPath, in, addrs, ent.out)
}
ent := staticHostEntry{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}}
testStaticHost(t, testHookHostsPath, ent)
// Modify the addresses return by lookupStaticHost.
- addrs := lookupStaticHost(ent.in)
+ addrs, _ := lookupStaticHost(ent.in)
for i := range addrs {
addrs[i] += "junk"
}
}
testStaticAddr(t, testHookHostsPath, ent)
}
+
+var lookupStaticHostAliasesTest = []struct {
+ lookup, res string
+}{
+ // 127.0.0.1
+ {"test", "test"},
+ // 127.0.0.2
+ {"test2.example.com", "test2.example.com"},
+ {"2.test", "test2.example.com"},
+ // 127.0.0.3
+ {"test3.example.com", "3.test"},
+ {"3.test", "3.test"},
+ // 127.0.0.4
+ {"example.com", "example.com"},
+ // 127.0.0.5
+ {"test5.example.com", "test4.example.com"},
+ {"5.test", "test4.example.com"},
+ {"4.test", "test4.example.com"},
+ {"test4.example.com", "test4.example.com"},
+}
+
+func TestLookupStaticHostAliases(t *testing.T) {
+ defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+
+ testHookHostsPath = "testdata/aliases"
+ for _, ent := range lookupStaticHostAliasesTest {
+ testLookupStaticHostAliases(t, ent.lookup, absDomainName(ent.res))
+ }
+}
+
+func testLookupStaticHostAliases(t *testing.T, lookup, lookupRes string) {
+ ins := []string{lookup, absDomainName(lookup), strings.ToLower(lookup), strings.ToUpper(lookup)}
+ for _, in := range ins {
+ _, res := lookupStaticHost(in)
+ if res != lookupRes {
+ t.Errorf("lookupStaticHost(%v): got %v, want %v", in, res, lookupRes)
+ }
+ }
+}
--- /dev/null
+127.0.0.1 test
+127.0.0.2 test2.example.com 2.test
+127.0.0.3 3.test test3.example.com
+127.0.0.4 example.com
+127.0.0.5 test4.example.com 4.test 5.test test5.example.com
+
+# must be a non resolvable domain on the internet
+127.0.1.1 invalid.test invalid.invalid