Skip to content

Commit

Permalink
net: consider dns addresses as public (#220)
Browse files Browse the repository at this point in the history
* consider dns addresses as public

* fix private domains list

* early return

* add reference to original list
  • Loading branch information
sukunrt authored Sep 14, 2023
1 parent dfafc59 commit a124954
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 38 deletions.
48 changes: 47 additions & 1 deletion net/private.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package manet

import (
"net"
"strings"

ma "github.com/multiformats/go-multiaddr"
)
Expand Down Expand Up @@ -46,6 +47,35 @@ var unroutableCIDR6 = []string{
"ff00::/8",
}

// 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",
".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
// Ref: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names
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() {
Private4 = parseCIDR(privateCIDR4)
Private6 = parseCIDR(privateCIDR6)
Expand All @@ -65,7 +95,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 {
Expand All @@ -78,6 +109,21 @@ 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 _, ud := range unResolvableDomains {
if strings.HasSuffix(dnsAddr, ud) {
isPublic = false
return false
}
}
for _, pd := range privateUseDomains {
if strings.HasSuffix(dnsAddr, pd) {
isPublic = false
break
}
}
}
return false
})
Expand Down
85 changes: 48 additions & 37 deletions net/private_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
})
}
}

0 comments on commit a124954

Please sign in to comment.