Unverified Commit a1249543 authored by Sukun's avatar Sukun Committed by GitHub

net: consider dns addresses as public (#220)

* consider dns addresses as public

* fix private domains list

* early return

* add reference to original list
parent dfafc592
......@@ -2,6 +2,7 @@ package manet
import (
"net"
"strings"
ma "github.com/multiformats/go-multiaddr"
)
......@@ -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)
......@@ -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 {
......@@ -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
})
......
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)
}
})
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment