Skip to content

Commit a124954

Browse files
authored
net: consider dns addresses as public (#220)
* consider dns addresses as public * fix private domains list * early return * add reference to original list
1 parent dfafc59 commit a124954

File tree

2 files changed

+95
-38
lines changed

2 files changed

+95
-38
lines changed

net/private.go

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package manet
22

33
import (
44
"net"
5+
"strings"
56

67
ma "github.com/multiformats/go-multiaddr"
78
)
@@ -46,6 +47,35 @@ var unroutableCIDR6 = []string{
4647
"ff00::/8",
4748
}
4849

50+
// unResolvableDomains do not resolve to an IP address.
51+
// Ref: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names
52+
var unResolvableDomains = []string{
53+
// Reverse DNS Lookup
54+
".in-addr.arpa",
55+
".ip6.arpa",
56+
57+
// RFC 6761: Users MAY assume that queries for "invalid" names will always return NXDOMAIN
58+
// responses
59+
".invalid",
60+
}
61+
62+
// privateUseDomains are reserved for private use and have no central authority for consistent
63+
// address resolution
64+
// Ref: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names
65+
var privateUseDomains = []string{
66+
// RFC 8375: Reserved for home networks
67+
".home.arpa",
68+
69+
// MDNS
70+
".local",
71+
72+
// RFC 6761: Users may assume that IPv4 and IPv6 address queries for localhost names will
73+
// always resolve to the respective IP loopback address
74+
".localhost",
75+
// RFC 6761: No central authority for .test names
76+
".test",
77+
}
78+
4979
func init() {
5080
Private4 = parseCIDR(privateCIDR4)
5181
Private6 = parseCIDR(privateCIDR6)
@@ -65,7 +95,8 @@ func parseCIDR(cidrs []string) []*net.IPNet {
6595
return ipnets
6696
}
6797

68-
// IsPublicAddr retruns true if the IP part of the multiaddr is a publicly routable address
98+
// IsPublicAddr returns true if the IP part of the multiaddr is a publicly routable address
99+
// or if it's a dns address without a special use domain e.g. .local.
69100
func IsPublicAddr(a ma.Multiaddr) bool {
70101
isPublic := false
71102
ma.ForEach(a, func(c ma.Component) bool {
@@ -78,6 +109,21 @@ func IsPublicAddr(a ma.Multiaddr) bool {
78109
case ma.P_IP6:
79110
ip := net.IP(c.RawValue())
80111
isPublic = !inAddrRange(ip, Private6) && !inAddrRange(ip, Unroutable6)
112+
case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR:
113+
dnsAddr := c.Value()
114+
isPublic = true
115+
for _, ud := range unResolvableDomains {
116+
if strings.HasSuffix(dnsAddr, ud) {
117+
isPublic = false
118+
return false
119+
}
120+
}
121+
for _, pd := range privateUseDomains {
122+
if strings.HasSuffix(dnsAddr, pd) {
123+
isPublic = false
124+
break
125+
}
126+
}
81127
}
82128
return false
83129
})

net/private_test.go

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,59 @@
11
package manet
22

33
import (
4+
"fmt"
45
"testing"
56

67
ma "github.com/multiformats/go-multiaddr"
78
)
89

910
func TestIsPublicAddr(t *testing.T) {
10-
a, err := ma.NewMultiaddr("/ip4/192.168.1.1/tcp/80")
11-
if err != nil {
12-
t.Fatal(err)
13-
}
14-
15-
if IsPublicAddr(a) {
16-
t.Fatal("192.168.1.1 is not a public address!")
17-
}
18-
19-
if !IsPrivateAddr(a) {
20-
t.Fatal("192.168.1.1 is a private address!")
21-
}
22-
23-
a, err = ma.NewMultiaddr("/ip4/1.1.1.1/tcp/80")
24-
if err != nil {
25-
t.Fatal(err)
26-
}
27-
28-
if !IsPublicAddr(a) {
29-
t.Fatal("1.1.1.1 is a public address!")
30-
}
31-
32-
if IsPrivateAddr(a) {
33-
t.Fatal("1.1.1.1 is not a private address!")
34-
}
35-
36-
a, err = ma.NewMultiaddr("/tcp/80/ip4/1.1.1.1")
37-
if err != nil {
38-
t.Fatal(err)
39-
}
40-
41-
if IsPublicAddr(a) {
42-
t.Fatal("shouldn't consider an address that starts with /tcp/ as *public*")
43-
}
44-
45-
if IsPrivateAddr(a) {
46-
t.Fatal("shouldn't consider an address that starts with /tcp/ as *private*")
11+
tests := []struct {
12+
addr ma.Multiaddr
13+
isPublic bool
14+
isPrivate bool
15+
}{
16+
{
17+
addr: ma.StringCast("/ip4/192.168.1.1/tcp/80"),
18+
isPublic: false,
19+
isPrivate: true,
20+
},
21+
{
22+
addr: ma.StringCast("/ip4/1.1.1.1/tcp/80"),
23+
isPublic: true,
24+
isPrivate: false,
25+
},
26+
{
27+
addr: ma.StringCast("/tcp/80/ip4/1.1.1.1"),
28+
isPublic: false,
29+
isPrivate: false,
30+
},
31+
{
32+
addr: ma.StringCast("/dns/node.libp2p.io/udp/1/quic-v1"),
33+
isPublic: true,
34+
isPrivate: false,
35+
},
36+
{
37+
addr: ma.StringCast("/dnsaddr/node.libp2p.io/udp/1/quic-v1"),
38+
isPublic: true,
39+
isPrivate: false,
40+
},
41+
{
42+
addr: ma.StringCast("/dns/node.libp2p.local/udp/1/quic-v1"),
43+
isPublic: false,
44+
isPrivate: false, // You can configure .local domains in local networks to return public addrs
45+
},
46+
}
47+
for i, tt := range tests {
48+
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
49+
isPublic := IsPublicAddr(tt.addr)
50+
isPrivate := IsPrivateAddr(tt.addr)
51+
if isPublic != tt.isPublic {
52+
t.Errorf("IsPublicAddr check failed for %s: expected %t, got %t", tt.addr, tt.isPublic, isPublic)
53+
}
54+
if isPrivate != tt.isPrivate {
55+
t.Errorf("IsPrivateAddr check failed for %s: expected %t, got %t", tt.addr, tt.isPrivate, isPrivate)
56+
}
57+
})
4758
}
4859
}

0 commit comments

Comments
 (0)