Skip to content

Commit 03e871b

Browse files
committed
fix loopback/link-local checks
1. Ensure we check the entire addr, not just a prefix. 2. Make the LinkLocal test skip zones. 3. Consider link-local multicast to be link-local. 4. Defer to *go* to determine if something is, in fact, a loopback/link-local address.
1 parent 3895ff1 commit 03e871b

File tree

2 files changed

+36
-21
lines changed

2 files changed

+36
-21
lines changed

ip.go

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package manet
22

33
import (
4-
"bytes"
4+
"net"
55

66
ma "github.com/multiformats/go-multiaddr"
77
)
@@ -24,14 +24,6 @@ var (
2424
IP6Unspecified = ma.StringCast("/ip6/::")
2525
)
2626

27-
// Loopback multiaddr prefixes. Any multiaddr beginning with one of the
28-
// following byte sequences is considered a loopback multiaddr.
29-
var loopbackPrefixes = [][]byte{
30-
{ma.P_IP4, 127}, // 127.*
31-
{ma.P_IP6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127}, // ::ffff:127.*
32-
IP6Loopback.Bytes(), // ::1
33-
}
34-
3527
// IsThinWaist returns whether a Multiaddr starts with "Thin Waist" Protocols.
3628
// This means: /{IP4, IP6}[/{TCP, UDP}]
3729
func IsThinWaist(m ma.Multiaddr) bool {
@@ -62,22 +54,41 @@ func IsThinWaist(m ma.Multiaddr) bool {
6254
// IsIPLoopback returns whether a Multiaddr is a "Loopback" IP address
6355
// This means either /ip4/127.*.*.*, /ip6/::1, or /ip6/::ffff:127.*.*.*.*
6456
func IsIPLoopback(m ma.Multiaddr) bool {
65-
b := m.Bytes()
66-
for _, prefix := range loopbackPrefixes {
67-
if bytes.HasPrefix(b, prefix) {
68-
return true
69-
}
57+
c, rest := ma.SplitFirst(m)
58+
if rest != nil {
59+
// Not *just* an IPv4 addr
60+
return false
61+
}
62+
switch c.Protocol().Code {
63+
case ma.P_IP4, ma.P_IP6:
64+
return net.IP(c.RawValue()).IsLoopback()
7065
}
7166
return false
7267
}
7368

74-
// IsIP6LinkLocal returns if a multiaddress is an IPv6 local link. These
75-
// addresses are non routable. The prefix is technically
76-
// fe80::/10, but we test fe80::/16 for simplicity (no need to mask).
77-
// So far, no hardware interfaces exist long enough to use those 2 bits.
78-
// Send a PR if there is.
69+
// IsIP6LinkLocal returns if a an IPv6 link-local multiaddress (with zero or
70+
// more leading zones). These addresses are non routable.
7971
func IsIP6LinkLocal(m ma.Multiaddr) bool {
80-
return bytes.HasPrefix(m.Bytes(), []byte{ma.P_IP6, 0xfe, 0x80})
72+
matched := false
73+
ma.ForEach(m, func(c ma.Component) bool {
74+
// Too much.
75+
if matched {
76+
matched = false
77+
return false
78+
}
79+
80+
switch c.Protocol().Code {
81+
case ma.P_IP6ZONE:
82+
return true
83+
case ma.P_IP6:
84+
ip := net.IP(c.RawValue())
85+
matched = ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast()
86+
return true
87+
default:
88+
return false
89+
}
90+
})
91+
return matched
8192
}
8293

8394
// IsIPUnspecified returns whether a Multiaddr is am Unspecified IP address

net_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,10 @@ func TestIPLoopback(t *testing.T) {
322322
t.Error("IsIPLoopback false positive (/ip4/112.123.11.1)")
323323
}
324324

325+
if IsIPLoopback(newMultiaddr(t, "/ip4/127.0.0.1/ip4/127.0.0.1")) {
326+
t.Error("IsIPLoopback false positive (/ip4/127.0.0.1/127.0.0.1)")
327+
}
328+
325329
if IsIPLoopback(newMultiaddr(t, "/ip4/192.168.0.1/ip6/::1")) {
326330
t.Error("IsIPLoopback false positive (/ip4/192.168.0.1/ip6/::1)")
327331
}
@@ -363,7 +367,7 @@ func TestIPUnspecified(t *testing.T) {
363367

364368
func TestIP6LinkLocal(t *testing.T) {
365369
for a := 0; a < 65536; a++ {
366-
isLinkLocal := (a == 0xfe80)
370+
isLinkLocal := (a&0xffc0 == 0xfe80 || a&0xff0f == 0xff02)
367371
m := newMultiaddr(t, fmt.Sprintf("/ip6/%x::1", a))
368372
if IsIP6LinkLocal(m) != isLinkLocal {
369373
t.Errorf("IsIP6LinkLocal failed (%s != %v)", m, isLinkLocal)

0 commit comments

Comments
 (0)