Skip to content

Commit 3ce601c

Browse files
authored
Merge pull request #46 from multiformats/feat/private-net
private networks and utility functions
2 parents 2503d99 + 115f321 commit 3ce601c

File tree

2 files changed

+164
-0
lines changed

2 files changed

+164
-0
lines changed

private.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package manet
2+
3+
import (
4+
"net"
5+
6+
ma "github.com/multiformats/go-multiaddr"
7+
)
8+
9+
// Private4 and Private6 are well-known private networks
10+
var Private4, Private6 []*net.IPNet
11+
var privateCIDR4 = []string{
12+
// localhost
13+
"127.0.0.0/8",
14+
// private networks
15+
"10.0.0.0/8",
16+
"100.64.0.0/10",
17+
"172.16.0.0/12",
18+
"192.168.0.0/16",
19+
// link local
20+
"169.254.0.0/16",
21+
}
22+
var privateCIDR6 = []string{
23+
// localhost
24+
"::1/128",
25+
// ULA reserved
26+
"fc00::/7",
27+
// link local
28+
"fe80::/10",
29+
}
30+
31+
// Unroutable4 and Unroutable6 are well known unroutable address ranges
32+
var Unroutable4, Unroutable6 []*net.IPNet
33+
var unroutableCIDR4 = []string{
34+
"0.0.0.0/8",
35+
"192.0.0.0/26",
36+
"192.0.2.0/24",
37+
"192.88.99.0/24",
38+
"198.18.0.0/15",
39+
"198.51.100.0/24",
40+
"203.0.113.0/24",
41+
"224.0.0.0/4",
42+
"240.0.0.0/4",
43+
"255.255.255.255/32",
44+
}
45+
var unroutableCIDR6 = []string{
46+
"ff00::/8",
47+
}
48+
49+
func init() {
50+
Private4 = parseCIDR(privateCIDR4)
51+
Private6 = parseCIDR(privateCIDR6)
52+
Unroutable4 = parseCIDR(unroutableCIDR4)
53+
Unroutable6 = parseCIDR(unroutableCIDR6)
54+
}
55+
56+
func parseCIDR(cidrs []string) []*net.IPNet {
57+
ipnets := make([]*net.IPNet, len(cidrs))
58+
for i, cidr := range cidrs {
59+
_, ipnet, err := net.ParseCIDR(cidr)
60+
if err != nil {
61+
panic(err)
62+
}
63+
ipnets[i] = ipnet
64+
}
65+
return ipnets
66+
}
67+
68+
// IsPublicAddr retruns true if the IP part of the multiaddr is a publicly routable address
69+
func IsPublicAddr(a ma.Multiaddr) bool {
70+
isPublic := false
71+
ma.ForEach(a, func(c ma.Component) bool {
72+
switch c.Protocol().Code {
73+
case ma.P_IP6ZONE:
74+
return true
75+
default:
76+
return false
77+
case ma.P_IP4:
78+
ip := net.IP(c.RawValue())
79+
isPublic = !inAddrRange(ip, Private4) && !inAddrRange(ip, Unroutable4)
80+
case ma.P_IP6:
81+
ip := net.IP(c.RawValue())
82+
isPublic = !inAddrRange(ip, Private6) && !inAddrRange(ip, Unroutable6)
83+
}
84+
return false
85+
})
86+
return isPublic
87+
}
88+
89+
// IsPrivateAddr returns true if the IP part of the mutiaddr is in a private network
90+
func IsPrivateAddr(a ma.Multiaddr) bool {
91+
isPrivate := false
92+
ma.ForEach(a, func(c ma.Component) bool {
93+
switch c.Protocol().Code {
94+
case ma.P_IP6ZONE:
95+
return true
96+
default:
97+
return false
98+
case ma.P_IP4:
99+
isPrivate = inAddrRange(net.IP(c.RawValue()), Private4)
100+
case ma.P_IP6:
101+
isPrivate = inAddrRange(net.IP(c.RawValue()), Private6)
102+
}
103+
return false
104+
})
105+
return isPrivate
106+
}
107+
108+
func inAddrRange(ip net.IP, ipnets []*net.IPNet) bool {
109+
for _, ipnet := range ipnets {
110+
if ipnet.Contains(ip) {
111+
return true
112+
}
113+
}
114+
115+
return false
116+
}

private_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package manet
2+
3+
import (
4+
"testing"
5+
6+
ma "github.com/multiformats/go-multiaddr"
7+
)
8+
9+
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*")
47+
}
48+
}

0 commit comments

Comments
 (0)