From c0880b5cf5a32c74457129e6df1fb267ef0708fb Mon Sep 17 00:00:00 2001 From: sukun Date: Thu, 7 Sep 2023 15:04:48 +0530 Subject: [PATCH] consider dns addresses as public --- net/private.go | 62 ++++++++++++++++++++++++++++++++- net/private_test.go | 85 +++++++++++++++++++++++++-------------------- 2 files changed, 109 insertions(+), 38 deletions(-) diff --git a/net/private.go b/net/private.go index ba57f00..a5f2727 100644 --- a/net/private.go +++ b/net/private.go @@ -2,6 +2,7 @@ package manet import ( "net" + "strings" ma "github.com/multiformats/go-multiaddr" ) @@ -46,6 +47,55 @@ var unroutableCIDR6 = []string{ "ff00::/8", } +// specialUseDomains are reserved for various purposes and do not have a central authority +// for consistent resolution in different networks. +// see: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names +// This list doesn't contain `.onion` addresses as they are consistently resolved everywhere. +var specialUseDomains = []string{ + "6tisch.arpa", + "10.in-addr.arpa", + "16.172.in-addr.arpa", + "17.172.in-addr.arpa", + "18.172.in-addr.arpa", + "19.172.in-addr.arpa", + "20.172.in-addr.arpa", + "21.172.in-addr.arpa", + "22.172.in-addr.arpa", + "23.172.in-addr.arpa", + "24.172.in-addr.arpa", + "25.172.in-addr.arpa", + "26.172.in-addr.arpa", + "27.172.in-addr.arpa", + "28.172.in-addr.arpa", + "29.172.in-addr.arpa", + "30.172.in-addr.arpa", + "31.172.in-addr.arpa", + "168.192.in-addr.arpa", + "170.0.0.192.in-addr.arpa", + "171.0.0.192.in-addr.arpa", + "ipv4only.arpa", + "254.169.in-addr.arpa", + "8.e.f.ip6.arpa", + "9.e.f.ip6.arpa", + "a.e.f.ip6.arpa", + "b.e.f.ip6.arpa", + "home.arpa", + "example", + "example.com", + "example.net", + "example.org", + "invalid", + "intranet", + "internal", + "private", + "corp", + "home", + "lan", + "local", + "localhost", + "test", +} + func init() { Private4 = parseCIDR(privateCIDR4) Private6 = parseCIDR(privateCIDR6) @@ -65,7 +115,8 @@ func parseCIDR(cidrs []string) []*net.IPNet { return ipnets } -// IsPublicAddr retruns true if the IP part of the multiaddr is a publicly routable address +// IsPublicAddr returns true if the IP part of the multiaddr is a publicly routable address +// or if it's a dns address without a special use domain e.g. .local. func IsPublicAddr(a ma.Multiaddr) bool { isPublic := false ma.ForEach(a, func(c ma.Component) bool { @@ -78,6 +129,15 @@ func IsPublicAddr(a ma.Multiaddr) bool { case ma.P_IP6: ip := net.IP(c.RawValue()) isPublic = !inAddrRange(ip, Private6) && !inAddrRange(ip, Unroutable6) + case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR: + dnsAddr := c.Value() + isPublic = true + for _, sd := range specialUseDomains { + if strings.HasSuffix(dnsAddr, sd) { + isPublic = false + break + } + } } return false }) diff --git a/net/private_test.go b/net/private_test.go index a4380a5..04e1ddb 100644 --- a/net/private_test.go +++ b/net/private_test.go @@ -1,48 +1,59 @@ package manet import ( + "fmt" "testing" ma "github.com/multiformats/go-multiaddr" ) func TestIsPublicAddr(t *testing.T) { - a, err := ma.NewMultiaddr("/ip4/192.168.1.1/tcp/80") - if err != nil { - t.Fatal(err) - } - - if IsPublicAddr(a) { - t.Fatal("192.168.1.1 is not a public address!") - } - - if !IsPrivateAddr(a) { - t.Fatal("192.168.1.1 is a private address!") - } - - a, err = ma.NewMultiaddr("/ip4/1.1.1.1/tcp/80") - if err != nil { - t.Fatal(err) - } - - if !IsPublicAddr(a) { - t.Fatal("1.1.1.1 is a public address!") - } - - if IsPrivateAddr(a) { - t.Fatal("1.1.1.1 is not a private address!") - } - - a, err = ma.NewMultiaddr("/tcp/80/ip4/1.1.1.1") - if err != nil { - t.Fatal(err) - } - - if IsPublicAddr(a) { - t.Fatal("shouldn't consider an address that starts with /tcp/ as *public*") - } - - if IsPrivateAddr(a) { - t.Fatal("shouldn't consider an address that starts with /tcp/ as *private*") + tests := []struct { + addr ma.Multiaddr + isPublic bool + isPrivate bool + }{ + { + addr: ma.StringCast("/ip4/192.168.1.1/tcp/80"), + isPublic: false, + isPrivate: true, + }, + { + addr: ma.StringCast("/ip4/1.1.1.1/tcp/80"), + isPublic: true, + isPrivate: false, + }, + { + addr: ma.StringCast("/tcp/80/ip4/1.1.1.1"), + isPublic: false, + isPrivate: false, + }, + { + addr: ma.StringCast("/dns/node.libp2p.io/udp/1/quic-v1"), + isPublic: true, + isPrivate: false, + }, + { + addr: ma.StringCast("/dnsaddr/node.libp2p.io/udp/1/quic-v1"), + isPublic: true, + isPrivate: false, + }, + { + addr: ma.StringCast("/dns/node.libp2p.local/udp/1/quic-v1"), + isPublic: false, + isPrivate: false, // You can configure .local domains in local networks to return public addrs + }, + } + for i, tt := range tests { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + isPublic := IsPublicAddr(tt.addr) + isPrivate := IsPrivateAddr(tt.addr) + if isPublic != tt.isPublic { + t.Errorf("IsPublicAddr check failed for %s: expected %t, got %t", tt.addr, tt.isPublic, isPublic) + } + if isPrivate != tt.isPrivate { + t.Errorf("IsPrivateAddr check failed for %s: expected %t, got %t", tt.addr, tt.isPrivate, isPrivate) + } + }) } }