Skip to content

Commit 2503d99

Browse files
authored
Merge pull request #47 from multiformats/feat/use-mulitaddr-parsers
use multiaddr parsers
2 parents 1cb9a0e + d2517ac commit 2503d99

File tree

5 files changed

+109
-50
lines changed

5 files changed

+109
-50
lines changed

convert.go

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package manet
33
import (
44
"fmt"
55
"net"
6-
"strings"
76

87
ma "github.com/multiformats/go-multiaddr"
98
)
@@ -68,43 +67,82 @@ func parseBasicNetMaddr(maddr ma.Multiaddr) (net.Addr, error) {
6867

6968
// FromIP converts a net.IP type to a Multiaddr.
7069
func FromIP(ip net.IP) (ma.Multiaddr, error) {
70+
var proto string
7171
switch {
7272
case ip.To4() != nil:
73-
return ma.NewMultiaddr("/ip4/" + ip.String())
73+
proto = "ip4"
7474
case ip.To16() != nil:
75-
return ma.NewMultiaddr("/ip6/" + ip.String())
75+
proto = "ip6"
7676
default:
7777
return nil, errIncorrectNetAddr
7878
}
79+
return ma.NewComponent(proto, ip.String())
7980
}
8081

8182
// DialArgs is a convenience function returning arguments for use in net.Dial
8283
func DialArgs(m ma.Multiaddr) (string, string, error) {
83-
// TODO: find a 'good' way to eliminate the function.
84-
// My preference is with a multiaddr.Format(...) function
85-
if !IsThinWaist(m) {
86-
return "", "", fmt.Errorf("%s is not a 'thin waist' address", m)
87-
}
88-
89-
str := m.String()
90-
parts := strings.Split(str, "/")[1:]
91-
92-
if len(parts) == 2 { // only IP
93-
return parts[0], parts[1], nil
94-
}
95-
96-
network := parts[2]
97-
98-
var host string
99-
switch parts[0] {
100-
case "ip4":
101-
network = network + "4"
102-
host = strings.Join([]string{parts[1], parts[3]}, ":")
84+
var (
85+
zone, network, ip, port string
86+
)
87+
88+
ma.ForEach(m, func(c ma.Component) bool {
89+
switch network {
90+
case "":
91+
switch c.Protocol().Code {
92+
case ma.P_IP6ZONE:
93+
zone = c.Value()
94+
return true
95+
case ma.P_IP6:
96+
network = "ip6"
97+
ip = c.Value()
98+
return true
99+
case ma.P_IP4:
100+
network = "ip4"
101+
ip = c.Value()
102+
return true
103+
}
104+
case "ip4":
105+
switch c.Protocol().Code {
106+
case ma.P_UDP:
107+
network = "udp4"
108+
case ma.P_TCP:
109+
network = "tcp4"
110+
default:
111+
return false
112+
}
113+
port = c.Value()
114+
case "ip6":
115+
switch c.Protocol().Code {
116+
case ma.P_UDP:
117+
network = "udp6"
118+
case ma.P_TCP:
119+
network = "tcp6"
120+
default:
121+
return false
122+
}
123+
port = c.Value()
124+
}
125+
// Done.
126+
return false
127+
})
128+
switch network {
103129
case "ip6":
104-
network = network + "6"
105-
host = fmt.Sprintf("[%s]:%s", parts[1], parts[3])
130+
if zone != "" {
131+
ip += "%" + zone
132+
}
133+
fallthrough
134+
case "ip4":
135+
return network, ip, nil
136+
case "tcp4", "udp4":
137+
return network, ip + ":" + port, nil
138+
case "tcp6", "udp6":
139+
if zone != "" {
140+
ip += "%" + zone
141+
}
142+
return network, "[" + ip + "]" + ":" + port, nil
143+
default:
144+
return "", "", fmt.Errorf("%s is not a 'thin waist' address", m)
106145
}
107-
return network, host, nil
108146
}
109147

110148
func parseTCPNetAddr(a net.Addr) (ma.Multiaddr, error) {

convert_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,10 @@ func TestDialArgs(t *testing.T) {
141141
test("/ip4/127.0.0.1/tcp/4321", "tcp4", "127.0.0.1:4321")
142142
test("/ip6/::1/udp/1234", "udp6", "[::1]:1234")
143143
test("/ip6/::1/tcp/4321", "tcp6", "[::1]:4321")
144+
test("/ip6/::1", "ip6", "::1") // Just an IP
145+
test("/ip4/1.2.3.4", "ip4", "1.2.3.4") // Just an IP
146+
test("/ip6zone/foo/ip6/::1/tcp/4321", "tcp6", "[::1%foo]:4321") // zone
147+
test("/ip6zone/foo/ip6/::1", "ip6", "::1%foo") // no TCP
148+
test("/ip6zone/foo/ip6/::1/ip6zone/bar", "ip6", "::1%foo") // IP over IP
149+
test("/ip6zone/foo/ip4/127.0.0.1/ip6zone/bar", "ip4", "127.0.0.1") // Skip zones in IP
144150
}

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: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ func TestIPLoopback(t *testing.T) {
306306
t.Error("IP6Loopback incorrect:", IP6Loopback)
307307
}
308308

309-
if IP4MappedIP6Loopback.String() != "/ip6/127.0.0.1" {
309+
if IP4MappedIP6Loopback.String() != "/ip6/::ffff:127.0.0.1" {
310310
t.Error("IP4MappedIP6Loopback incorrect:", IP4MappedIP6Loopback)
311311
}
312312

@@ -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)

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
"gxDependencies": [
1010
{
1111
"author": "multiformats",
12-
"hash": "QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7",
12+
"hash": "QmT4U94DnD8FRfqr21obWY32HLM5VExccPKMjQHofeYqr9",
1313
"name": "go-multiaddr",
14-
"version": "1.3.0"
14+
"version": "1.3.5"
1515
}
1616
],
1717
"gxVersion": "0.6.0",

0 commit comments

Comments
 (0)