Skip to content

Commit 1891521

Browse files
committed
Simplify privateIP detection
1 parent 6e08854 commit 1891521

File tree

2 files changed

+266
-36
lines changed

2 files changed

+266
-36
lines changed

client.go

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -966,42 +966,11 @@ func filterPrivateAddrs(addrs []multiaddr.Multiaddr) []multiaddr.Multiaddr {
966966
return filtered
967967
}
968968

969-
// isPrivateIP checks if an IP address is private or local.
969+
// isPrivateIP checks if an IP address is private or local using Go's standard library.
970970
// Returns true for:
971-
// - RFC1918 private networks (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
972-
// - Link-local addresses (169.254.0.0/16)
973-
// - Loopback addresses (127.0.0.0/8)
974-
// - IPv6 unique local addresses (fc00::/7)
975-
// - IPv6 link-local addresses (fe80::/10)
971+
// - RFC1918 private networks (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) via IP.IsPrivate()
972+
// - Link-local, loopback, and multicast addresses via built-in methods
973+
// - IPv6 unique local addresses (fc00::/7) via IP.IsPrivate()
976974
func isPrivateIP(ip net.IP) bool {
977-
if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
978-
return true
979-
}
980-
981-
// Check for private IPv4 ranges
982-
if ip4 := ip.To4(); ip4 != nil {
983-
// 10.0.0.0/8
984-
if ip4[0] == 10 {
985-
return true
986-
}
987-
// 172.16.0.0/12
988-
if ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31 {
989-
return true
990-
}
991-
// 192.168.0.0/16
992-
if ip4[0] == 192 && ip4[1] == 168 {
993-
return true
994-
}
995-
// 169.254.0.0/16 (link-local)
996-
if ip4[0] == 169 && ip4[1] == 254 {
997-
return true
998-
}
999-
}
1000-
1001-
// Check for IPv6 unique local addresses (fc00::/7)
1002-
if len(ip) == net.IPv6len && ip[0]&0xfe == 0xfc {
1003-
return true
1004-
}
1005-
1006-
return false
975+
return ip.IsPrivate() || ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast()
1007976
}
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
package p2p
2+
3+
import (
4+
"net"
5+
"testing"
6+
7+
"github.com/multiformats/go-multiaddr"
8+
)
9+
10+
func TestFilterPrivateAddrs(t *testing.T) {
11+
tests := []struct {
12+
name string
13+
input []string
14+
expected []string
15+
}{
16+
{
17+
name: "filter_out_private_ipv4",
18+
input: []string{
19+
"/ip4/10.0.0.1/tcp/4001",
20+
"/ip4/8.8.8.8/tcp/4001",
21+
"/ip4/172.16.0.1/tcp/4001",
22+
"/ip4/1.1.1.1/tcp/4001",
23+
},
24+
expected: []string{
25+
"/ip4/8.8.8.8/tcp/4001",
26+
"/ip4/1.1.1.1/tcp/4001",
27+
},
28+
},
29+
{
30+
name: "filter_out_localhost",
31+
input: []string{
32+
"/ip4/127.0.0.1/tcp/4001",
33+
"/ip4/8.8.8.8/tcp/4001",
34+
},
35+
expected: []string{
36+
"/ip4/8.8.8.8/tcp/4001",
37+
},
38+
},
39+
{
40+
name: "filter_out_link_local",
41+
input: []string{
42+
"/ip4/169.254.1.1/tcp/4001",
43+
"/ip4/8.8.8.8/tcp/4001",
44+
},
45+
expected: []string{
46+
"/ip4/8.8.8.8/tcp/4001",
47+
},
48+
},
49+
{
50+
name: "filter_out_192_168",
51+
input: []string{
52+
"/ip4/192.168.1.1/tcp/4001",
53+
"/ip4/8.8.8.8/tcp/4001",
54+
},
55+
expected: []string{
56+
"/ip4/8.8.8.8/tcp/4001",
57+
},
58+
},
59+
{
60+
name: "filter_out_ipv6_private",
61+
input: []string{
62+
"/ip6/fc00::1/tcp/4001",
63+
"/ip6/2001:4860:4860::8888/tcp/4001",
64+
},
65+
expected: []string{
66+
"/ip6/2001:4860:4860::8888/tcp/4001",
67+
},
68+
},
69+
{
70+
name: "filter_out_ipv6_link_local",
71+
input: []string{
72+
"/ip6/fe80::1/tcp/4001",
73+
"/ip6/2001:4860:4860::8888/tcp/4001",
74+
},
75+
expected: []string{
76+
"/ip6/2001:4860:4860::8888/tcp/4001",
77+
},
78+
},
79+
{
80+
name: "all_private_returns_empty",
81+
input: []string{
82+
"/ip4/10.0.0.1/tcp/4001",
83+
"/ip4/192.168.1.1/tcp/4001",
84+
"/ip4/127.0.0.1/tcp/4001",
85+
},
86+
expected: []string{},
87+
},
88+
{
89+
name: "all_public_returns_all",
90+
input: []string{
91+
"/ip4/8.8.8.8/tcp/4001",
92+
"/ip4/1.1.1.1/tcp/4001",
93+
"/ip6/2001:4860:4860::8888/tcp/4001",
94+
},
95+
expected: []string{
96+
"/ip4/8.8.8.8/tcp/4001",
97+
"/ip4/1.1.1.1/tcp/4001",
98+
"/ip6/2001:4860:4860::8888/tcp/4001",
99+
},
100+
},
101+
{
102+
name: "empty_input_returns_empty",
103+
input: []string{},
104+
expected: []string{},
105+
},
106+
{
107+
name: "mixed_valid_and_invalid",
108+
input: []string{
109+
"/ip4/8.8.8.8/tcp/4001",
110+
"invalid-addr",
111+
"/ip4/10.0.0.1/tcp/4001",
112+
},
113+
expected: []string{
114+
"/ip4/8.8.8.8/tcp/4001",
115+
},
116+
},
117+
{
118+
name: "edge_case_172_15_not_filtered",
119+
input: []string{
120+
"/ip4/172.15.0.1/tcp/4001", // Not in 172.16-31 range
121+
"/ip4/8.8.8.8/tcp/4001",
122+
},
123+
expected: []string{
124+
"/ip4/172.15.0.1/tcp/4001",
125+
"/ip4/8.8.8.8/tcp/4001",
126+
},
127+
},
128+
{
129+
name: "edge_case_172_32_not_filtered",
130+
input: []string{
131+
"/ip4/172.32.0.1/tcp/4001", // Not in 172.16-31 range
132+
"/ip4/8.8.8.8/tcp/4001",
133+
},
134+
expected: []string{
135+
"/ip4/172.32.0.1/tcp/4001",
136+
"/ip4/8.8.8.8/tcp/4001",
137+
},
138+
},
139+
{
140+
name: "edge_case_172_16_filtered",
141+
input: []string{
142+
"/ip4/172.16.0.1/tcp/4001",
143+
"/ip4/8.8.8.8/tcp/4001",
144+
},
145+
expected: []string{
146+
"/ip4/8.8.8.8/tcp/4001",
147+
},
148+
},
149+
{
150+
name: "edge_case_172_31_filtered",
151+
input: []string{
152+
"/ip4/172.31.255.255/tcp/4001",
153+
"/ip4/8.8.8.8/tcp/4001",
154+
},
155+
expected: []string{
156+
"/ip4/8.8.8.8/tcp/4001",
157+
},
158+
},
159+
}
160+
161+
for _, tt := range tests {
162+
t.Run(tt.name, func(t *testing.T) {
163+
// Convert string multiaddrs to multiaddr.Multiaddr
164+
inputAddrs := make([]multiaddr.Multiaddr, 0, len(tt.input))
165+
for _, addrStr := range tt.input {
166+
addr, err := multiaddr.NewMultiaddr(addrStr)
167+
if err != nil {
168+
// Skip invalid addresses in input
169+
continue
170+
}
171+
inputAddrs = append(inputAddrs, addr)
172+
}
173+
174+
// Call filterPrivateAddrs
175+
result := filterPrivateAddrs(inputAddrs)
176+
177+
// Convert result back to strings for comparison
178+
resultStrs := make([]string, 0, len(result))
179+
for _, addr := range result {
180+
resultStrs = append(resultStrs, addr.String())
181+
}
182+
183+
// Check length
184+
if len(resultStrs) != len(tt.expected) {
185+
t.Errorf("Expected %d addresses, got %d.\nExpected: %v\nGot: %v",
186+
len(tt.expected), len(resultStrs), tt.expected, resultStrs)
187+
return
188+
}
189+
190+
// Check each address
191+
for i, expectedAddr := range tt.expected {
192+
if resultStrs[i] != expectedAddr {
193+
t.Errorf("Address %d: expected %s, got %s", i, expectedAddr, resultStrs[i])
194+
}
195+
}
196+
})
197+
}
198+
}
199+
200+
func TestIsPrivateIP(t *testing.T) {
201+
tests := []struct {
202+
name string
203+
ip string
204+
expected bool
205+
}{
206+
// RFC1918 private networks
207+
{"10.0.0.1", "10.0.0.1", true},
208+
{"10.255.255.255", "10.255.255.255", true},
209+
{"172.16.0.1", "172.16.0.1", true},
210+
{"172.31.255.255", "172.31.255.255", true},
211+
{"192.168.1.1", "192.168.1.1", true},
212+
{"192.168.255.255", "192.168.255.255", true},
213+
214+
// Edge cases for 172.x range
215+
{"172.15.0.1_not_private", "172.15.0.1", false},
216+
{"172.32.0.1_not_private", "172.32.0.1", false},
217+
218+
// Link-local
219+
{"169.254.1.1", "169.254.1.1", true},
220+
221+
// Loopback
222+
{"127.0.0.1", "127.0.0.1", true},
223+
{"127.255.255.255", "127.255.255.255", true},
224+
225+
// Public IPs
226+
{"8.8.8.8", "8.8.8.8", false},
227+
{"1.1.1.1", "1.1.1.1", false},
228+
{"208.67.222.222", "208.67.222.222", false},
229+
230+
// IPv6 unique local (fc00::/7)
231+
{"fc00::1", "fc00::1", true},
232+
{"fd00::1", "fd00::1", true},
233+
234+
// IPv6 link-local (fe80::/10)
235+
{"fe80::1", "fe80::1", true},
236+
237+
// IPv6 loopback
238+
{"::1", "::1", true},
239+
240+
// IPv6 public
241+
{"2001:4860:4860::8888", "2001:4860:4860::8888", false},
242+
{"2606:4700:4700::1111", "2606:4700:4700::1111", false},
243+
}
244+
245+
for _, tt := range tests {
246+
t.Run(tt.name, func(t *testing.T) {
247+
ip := parseIP(tt.ip)
248+
if ip == nil {
249+
t.Fatalf("Failed to parse IP: %s", tt.ip)
250+
}
251+
result := isPrivateIP(ip)
252+
if result != tt.expected {
253+
t.Errorf("isPrivateIP(%s) = %v, want %v", tt.ip, result, tt.expected)
254+
}
255+
})
256+
}
257+
}
258+
259+
func parseIP(s string) net.IP {
260+
return net.ParseIP(s)
261+
}

0 commit comments

Comments
 (0)