mirror of
https://github.com/golang/go
synced 2024-11-16 20:04:52 -07:00
net: add support for /etc/hosts aliases using go resolver
It adds support for /etc/hosts aliases and fixes the difference between the glibc cgo and the go DNS resolver.
Examples: https://pastebin.com/Fv6UcAVr
Fixes #44741
Change-Id: I98c484fced900731fbad800278b296028a45f044
GitHub-Last-Rev: 3d47e44f11
GitHub-Pull-Request: golang/go#51004
Reviewed-on: https://go-review.googlesource.com/c/go/+/382996
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
parent
fd0c0db4a4
commit
d931b3b771
@ -559,7 +559,7 @@ func (r *Resolver) goLookupHost(ctx context.Context, name string) (addrs []strin
|
|||||||
func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []string, err error) {
|
func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []string, err error) {
|
||||||
if order == hostLookupFilesDNS || order == hostLookupFiles {
|
if order == hostLookupFilesDNS || order == hostLookupFiles {
|
||||||
// Use entries from /etc/hosts if they match.
|
// Use entries from /etc/hosts if they match.
|
||||||
addrs = lookupStaticHost(name)
|
addrs, _ = lookupStaticHost(name)
|
||||||
if len(addrs) > 0 || order == hostLookupFiles {
|
if len(addrs) > 0 || order == hostLookupFiles {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -576,8 +576,9 @@ func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hos
|
|||||||
}
|
}
|
||||||
|
|
||||||
// lookup entries from /etc/hosts
|
// lookup entries from /etc/hosts
|
||||||
func goLookupIPFiles(name string) (addrs []IPAddr) {
|
func goLookupIPFiles(name string) (addrs []IPAddr, canonical string) {
|
||||||
for _, haddr := range lookupStaticHost(name) {
|
addr, canonical := lookupStaticHost(name)
|
||||||
|
for _, haddr := range addr {
|
||||||
haddr, zone := splitHostZone(haddr)
|
haddr, zone := splitHostZone(haddr)
|
||||||
if ip := ParseIP(haddr); ip != nil {
|
if ip := ParseIP(haddr); ip != nil {
|
||||||
addr := IPAddr{IP: ip, Zone: zone}
|
addr := IPAddr{IP: ip, Zone: zone}
|
||||||
@ -585,7 +586,7 @@ func goLookupIPFiles(name string) (addrs []IPAddr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sortByRFC6724(addrs)
|
sortByRFC6724(addrs)
|
||||||
return
|
return addrs, canonical
|
||||||
}
|
}
|
||||||
|
|
||||||
// goLookupIP is the native Go implementation of LookupIP.
|
// goLookupIP is the native Go implementation of LookupIP.
|
||||||
@ -598,11 +599,23 @@ func (r *Resolver) goLookupIP(ctx context.Context, network, host string) (addrs
|
|||||||
|
|
||||||
func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name string, order hostLookupOrder) (addrs []IPAddr, cname dnsmessage.Name, err error) {
|
func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name string, order hostLookupOrder) (addrs []IPAddr, cname dnsmessage.Name, err error) {
|
||||||
if order == hostLookupFilesDNS || order == hostLookupFiles {
|
if order == hostLookupFilesDNS || order == hostLookupFiles {
|
||||||
addrs = goLookupIPFiles(name)
|
var canonical string
|
||||||
if len(addrs) > 0 || order == hostLookupFiles {
|
addrs, canonical = goLookupIPFiles(name)
|
||||||
return addrs, dnsmessage.Name{}, nil
|
|
||||||
|
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) {
|
if !isDomainName(name) {
|
||||||
// See comment in func lookup above about use of errNoSuchHost.
|
// See comment in func lookup above about use of errNoSuchHost.
|
||||||
return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
|
return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
|
||||||
@ -776,9 +789,18 @@ func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name strin
|
|||||||
sortByRFC6724(addrs)
|
sortByRFC6724(addrs)
|
||||||
if len(addrs) == 0 && !(network == "CNAME" && cname.Length > 0) {
|
if len(addrs) == 0 && !(network == "CNAME" && cname.Length > 0) {
|
||||||
if order == hostLookupDNSFiles {
|
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
|
return nil, dnsmessage.Name{}, lastErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2170,6 +2170,56 @@ func TestRootNS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
// Test that we advertise support for a larger DNS packet size.
|
||||||
// This isn't a great test as it just tests the dnsmessage package
|
// This isn't a great test as it just tests the dnsmessage package
|
||||||
// against itself.
|
// against itself.
|
||||||
|
@ -28,6 +28,11 @@ func parseLiteralIP(addr string) string {
|
|||||||
return ip.String() + "%" + zone
|
return ip.String() + "%" + zone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type byName struct {
|
||||||
|
addrs []string
|
||||||
|
canonicalName string
|
||||||
|
}
|
||||||
|
|
||||||
// hosts contains known host entries.
|
// hosts contains known host entries.
|
||||||
var hosts struct {
|
var hosts struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
@ -36,7 +41,7 @@ var hosts struct {
|
|||||||
// name. It would be part of DNS labels, a FQDN or an absolute
|
// name. It would be part of DNS labels, a FQDN or an absolute
|
||||||
// FQDN.
|
// FQDN.
|
||||||
// For now the key is converted to lower case for convenience.
|
// 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
|
// Key for the list of host names must be a literal IP address
|
||||||
// including IPv6 address with zone identifier.
|
// including IPv6 address with zone identifier.
|
||||||
@ -62,8 +67,9 @@ func readHosts() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hs := make(map[string][]string)
|
hs := make(map[string]byName)
|
||||||
is := make(map[string][]string)
|
is := make(map[string][]string)
|
||||||
|
|
||||||
var file *file
|
var file *file
|
||||||
if file, _ = open(hp); file == nil {
|
if file, _ = open(hp); file == nil {
|
||||||
return
|
return
|
||||||
@ -81,13 +87,32 @@ func readHosts() {
|
|||||||
if addr == "" {
|
if addr == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var canonical string
|
||||||
for i := 1; i < len(f); i++ {
|
for i := 1; i < len(f); i++ {
|
||||||
name := absDomainName(f[i])
|
name := absDomainName(f[i])
|
||||||
h := []byte(f[i])
|
h := []byte(f[i])
|
||||||
lowerASCIIBytes(h)
|
lowerASCIIBytes(h)
|
||||||
key := absDomainName(string(h))
|
key := absDomainName(string(h))
|
||||||
hs[key] = append(hs[key], addr)
|
|
||||||
|
if i == 1 {
|
||||||
|
canonical = key
|
||||||
|
}
|
||||||
|
|
||||||
is[addr] = append(is[addr], name)
|
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.
|
// Update the data cache.
|
||||||
@ -100,8 +125,8 @@ func readHosts() {
|
|||||||
file.close()
|
file.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookupStaticHost looks up the addresses for the given host from /etc/hosts.
|
// lookupStaticHost looks up the addresses and the cannonical name for the given host from /etc/hosts.
|
||||||
func lookupStaticHost(host string) []string {
|
func lookupStaticHost(host string) ([]string, string) {
|
||||||
hosts.Lock()
|
hosts.Lock()
|
||||||
defer hosts.Unlock()
|
defer hosts.Unlock()
|
||||||
readHosts()
|
readHosts()
|
||||||
@ -111,13 +136,13 @@ func lookupStaticHost(host string) []string {
|
|||||||
lowerASCIIBytes(lowerHost)
|
lowerASCIIBytes(lowerHost)
|
||||||
host = string(lowerHost)
|
host = string(lowerHost)
|
||||||
}
|
}
|
||||||
if ips, ok := hosts.byName[absDomainName(host)]; ok {
|
if byName, ok := hosts.byName[absDomainName(host)]; ok {
|
||||||
ipsCp := make([]string, len(ips))
|
ipsCp := make([]string, len(byName.addrs))
|
||||||
copy(ipsCp, ips)
|
copy(ipsCp, byName.addrs)
|
||||||
return ipsCp
|
return ipsCp, byName.canonicalName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookupStaticAddr looks up the hosts for the given address from /etc/hosts.
|
// lookupStaticAddr looks up the hosts for the given address from /etc/hosts.
|
||||||
|
@ -72,7 +72,7 @@ func TestLookupStaticHost(t *testing.T) {
|
|||||||
func testStaticHost(t *testing.T, hostsPath string, ent staticHostEntry) {
|
func testStaticHost(t *testing.T, hostsPath string, ent staticHostEntry) {
|
||||||
ins := []string{ent.in, absDomainName(ent.in), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
|
ins := []string{ent.in, absDomainName(ent.in), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
|
||||||
for _, in := range ins {
|
for _, in := range ins {
|
||||||
addrs := lookupStaticHost(in)
|
addrs, _ := lookupStaticHost(in)
|
||||||
if !reflect.DeepEqual(addrs, ent.out) {
|
if !reflect.DeepEqual(addrs, ent.out) {
|
||||||
t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", hostsPath, in, addrs, ent.out)
|
t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", hostsPath, in, addrs, ent.out)
|
||||||
}
|
}
|
||||||
@ -157,7 +157,7 @@ func TestHostCacheModification(t *testing.T) {
|
|||||||
ent := staticHostEntry{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}}
|
ent := staticHostEntry{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}}
|
||||||
testStaticHost(t, testHookHostsPath, ent)
|
testStaticHost(t, testHookHostsPath, ent)
|
||||||
// Modify the addresses return by lookupStaticHost.
|
// Modify the addresses return by lookupStaticHost.
|
||||||
addrs := lookupStaticHost(ent.in)
|
addrs, _ := lookupStaticHost(ent.in)
|
||||||
for i := range addrs {
|
for i := range addrs {
|
||||||
addrs[i] += "junk"
|
addrs[i] += "junk"
|
||||||
}
|
}
|
||||||
@ -173,3 +173,42 @@ func TestHostCacheModification(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testStaticAddr(t, testHookHostsPath, ent)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
8
src/net/testdata/aliases
vendored
Normal file
8
src/net/testdata/aliases
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
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
|
Loading…
Reference in New Issue
Block a user