From c3ff8182affd6598b7cab15fed4ee8feeda4229a Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 5 Dec 2023 01:29:31 +0700 Subject: [PATCH] all: ignoring local interfaces RFC1918 IP for private resolver Otherwises, the discovery may make a looping with new PTR query flow. --- cmd/cli/dns_proxy.go | 17 +---------------- cmd/cli/prog.go | 2 +- resolver.go | 28 +++++++++++++++++++++++++++- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/cmd/cli/dns_proxy.go b/cmd/cli/dns_proxy.go index 3c63782..e2477f2 100644 --- a/cmd/cli/dns_proxy.go +++ b/cmd/cli/dns_proxy.go @@ -114,7 +114,7 @@ func (p *prog) serveDNS(listenerNum string) error { // addresses of the machine. So ctrld could receive queries from LAN clients. if needRFC1918Listeners(listenerConfig) { g.Go(func() error { - for _, addr := range rfc1918Addresses() { + for _, addr := range ctrld.Rfc1918Addresses() { func() { listenAddr := net.JoinHostPort(addr, strconv.Itoa(listenerConfig.Port)) s, errCh := runDNSServer(listenAddr, proto, handler) @@ -737,21 +737,6 @@ func needRFC1918Listeners(lc *ctrld.ListenerConfig) bool { return lc.IP == "127.0.0.1" && lc.Port == 53 } -func rfc1918Addresses() []string { - var res []string - interfaces.ForeachInterface(func(i interfaces.Interface, prefixes []netip.Prefix) { - addrs, _ := i.Addrs() - for _, addr := range addrs { - ipNet, ok := addr.(*net.IPNet) - if !ok || !ipNet.IP.IsPrivate() { - continue - } - res = append(res, ipNet.IP.String()) - } - }) - return res -} - // ipFromARPA parses a FQDN arpa domain and return the IP address if valid. func ipFromARPA(arpa string) net.IP { if arpa, ok := strings.CutSuffix(arpa, ".in-addr.arpa."); ok { diff --git a/cmd/cli/prog.go b/cmd/cli/prog.go index f828426..9fcb42f 100644 --- a/cmd/cli/prog.go +++ b/cmd/cli/prog.go @@ -438,7 +438,7 @@ func (p *prog) setDNS() { nameservers := []string{ns} if needRFC1918Listeners(lc) { - nameservers = append(nameservers, rfc1918Addresses()...) + nameservers = append(nameservers, ctrld.Rfc1918Addresses()...) } if err := setDNS(netIface, nameservers); err != nil { logger.Error().Err(err).Msgf("could not set DNS for interface") diff --git a/resolver.go b/resolver.go index 8fd26cf..750679c 100644 --- a/resolver.go +++ b/resolver.go @@ -5,10 +5,12 @@ import ( "errors" "fmt" "net" + "net/netip" "sync" "time" "github.com/miekg/dns" + "tailscale.com/net/interfaces" ) const ( @@ -245,12 +247,16 @@ func NewBootstrapResolver(servers ...string) Resolver { } // NewPrivateResolver returns an OS resolver, which includes only private DNS servers, -// excluding nameservers from /etc/resolv.conf file. +// excluding: +// +// - Nameservers from /etc/resolv.conf file. +// - Nameservers which is local RFC1918 addresses. // // This is useful for doing PTR lookup in LAN network. func NewPrivateResolver() Resolver { nss := nameservers() resolveConfNss := nameserversFromResolvconf() + localRfc1918Addrs := Rfc1918Addresses() n := 0 for _, ns := range nss { host, _, _ := net.SplitHostPort(ns) @@ -263,6 +269,10 @@ func NewPrivateResolver() Resolver { if sliceContains(resolveConfNss, host) { continue } + // Ignoring local RFC 1918 addresses. + if sliceContains(localRfc1918Addrs, host) { + continue + } ip := net.ParseIP(host) if ip != nil && ip.IsPrivate() && !ip.IsLoopback() { nss[n] = ns @@ -285,6 +295,22 @@ func NewResolverWithNameserver(nameservers []string) Resolver { return &osResolver{nameservers: nameservers} } +// Rfc1918Addresses returns the list of local interfaces private IP addresses +func Rfc1918Addresses() []string { + var res []string + interfaces.ForeachInterface(func(i interfaces.Interface, prefixes []netip.Prefix) { + addrs, _ := i.Addrs() + for _, addr := range addrs { + ipNet, ok := addr.(*net.IPNet) + if !ok || !ipNet.IP.IsPrivate() { + continue + } + res = append(res, ipNet.IP.String()) + } + }) + return res +} + func newDialer(dnsAddress string) *net.Dialer { return &net.Dialer{ Resolver: &net.Resolver{