From c0880b5cf5a32c74457129e6df1fb267ef0708fb Mon Sep 17 00:00:00 2001 From: sukun Date: Thu, 7 Sep 2023 15:04:48 +0530 Subject: [PATCH 1/4] 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) + } + }) } } From 26ad11d297fbed2b72bb6bb4e4af282b97b91433 Mon Sep 17 00:00:00 2001 From: sukun Date: Wed, 13 Sep 2023 21:48:37 +0530 Subject: [PATCH 2/4] fix private domains list --- net/private.go | 82 ++++++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 49 deletions(-) diff --git a/net/private.go b/net/private.go index a5f2727..36b1fc2 100644 --- a/net/private.go +++ b/net/private.go @@ -47,53 +47,31 @@ 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", +// unResolvableDomains do not resolve to an IP address. +var unResolvableDomains = []string{ + // Reverse DNS Lookup + ".in-addr.arpa", + ".ip6.arpa", + + // RFC 6761: Users MAY assume that queries for "invalid" names will always return NXDOMAIN + // responses + ".invalid", +} + +// privateUseDomains are reserved for private use and have no central authority for consistent +// address resolution +var privateUseDomains = []string{ + // RFC 8375: Reserved for home networks + ".home.arpa", + + // MDNS + ".local", + + // RFC 6761: Users may assume that IPv4 and IPv6 address queries for localhost names will + // always resolve to the respective IP loopback address + ".localhost", + // RFC 6761: No central authority for .test names + ".test", } func init() { @@ -132,8 +110,14 @@ func IsPublicAddr(a ma.Multiaddr) bool { 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) { + for _, ud := range unResolvableDomains { + if strings.HasSuffix(dnsAddr, ud) { + isPublic = false + break + } + } + for _, pd := range privateUseDomains { + if strings.HasSuffix(dnsAddr, pd) { isPublic = false break } From 353cc18e492186168f85c2e4e488270d02f92eb9 Mon Sep 17 00:00:00 2001 From: sukun Date: Thu, 14 Sep 2023 10:13:45 +0530 Subject: [PATCH 3/4] early return --- net/private.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/private.go b/net/private.go index 36b1fc2..06b4784 100644 --- a/net/private.go +++ b/net/private.go @@ -113,7 +113,7 @@ func IsPublicAddr(a ma.Multiaddr) bool { for _, ud := range unResolvableDomains { if strings.HasSuffix(dnsAddr, ud) { isPublic = false - break + return false } } for _, pd := range privateUseDomains { From 9d1559c05311c0f9ce478bbfdc4cb6e18523bcd4 Mon Sep 17 00:00:00 2001 From: sukun Date: Thu, 14 Sep 2023 10:31:35 +0530 Subject: [PATCH 4/4] add reference to original list --- net/private.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/private.go b/net/private.go index 06b4784..c0b6acb 100644 --- a/net/private.go +++ b/net/private.go @@ -48,6 +48,7 @@ var unroutableCIDR6 = []string{ } // unResolvableDomains do not resolve to an IP address. +// Ref: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names var unResolvableDomains = []string{ // Reverse DNS Lookup ".in-addr.arpa", @@ -60,6 +61,7 @@ var unResolvableDomains = []string{ // privateUseDomains are reserved for private use and have no central authority for consistent // address resolution +// Ref: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names var privateUseDomains = []string{ // RFC 8375: Reserved for home networks ".home.arpa",