527 lines
13 KiB
Go
527 lines
13 KiB
Go
package multiaddr
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"math/rand"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func newMultiaddr(t *testing.T, a string) Multiaddr {
|
|
m, err := NewMultiaddr(a)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
return m
|
|
}
|
|
|
|
func TestConstructFails(t *testing.T) {
|
|
cases := []string{
|
|
"/ip4",
|
|
"/ip4/::1",
|
|
"/ip4/fdpsofodsajfdoisa",
|
|
"/ip6",
|
|
"/ip6zone",
|
|
"/ip6zone/",
|
|
"/ip6zone//ip6/fe80::1",
|
|
"/udp",
|
|
"/tcp",
|
|
"/sctp",
|
|
"/udp/65536",
|
|
"/tcp/65536",
|
|
"/quic/65536",
|
|
"/onion/9imaq4ygg2iegci7:80",
|
|
"/onion/aaimaq4ygg2iegci7:80",
|
|
"/onion/timaq4ygg2iegci7:0",
|
|
"/onion/timaq4ygg2iegci7:-1",
|
|
"/onion/timaq4ygg2iegci7",
|
|
"/onion/timaq4ygg2iegci@:666",
|
|
"/udp/1234/sctp",
|
|
"/udp/1234/udt/1234",
|
|
"/udp/1234/utp/1234",
|
|
"/ip4/127.0.0.1/udp/jfodsajfidosajfoidsa",
|
|
"/ip4/127.0.0.1/udp",
|
|
"/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa",
|
|
"/ip4/127.0.0.1/tcp",
|
|
"/ip4/127.0.0.1/quic/1234",
|
|
"/ip4/127.0.0.1/ipfs",
|
|
"/ip4/127.0.0.1/ipfs/tcp",
|
|
"/ip4/127.0.0.1/p2p",
|
|
"/ip4/127.0.0.1/p2p/tcp",
|
|
"/unix",
|
|
"/ip4/1.2.3.4/tcp/80/unix",
|
|
}
|
|
|
|
for _, a := range cases {
|
|
if _, err := NewMultiaddr(a); err == nil {
|
|
t.Errorf("should have failed: %s - %s", a, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConstructSucceeds(t *testing.T) {
|
|
cases := []string{
|
|
"/ip4/1.2.3.4",
|
|
"/ip4/0.0.0.0",
|
|
"/ip6/::1",
|
|
"/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21",
|
|
"/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21/udp/1234/quic",
|
|
"/ip6zone/x/ip6/fe80::1",
|
|
"/ip6zone/x%y/ip6/fe80::1",
|
|
"/ip6zone/x%y/ip6/::",
|
|
"/ip6zone/x/ip6/fe80::1/udp/1234/quic",
|
|
"/onion/timaq4ygg2iegci7:1234",
|
|
"/onion/timaq4ygg2iegci7:80/http",
|
|
"/udp/0",
|
|
"/tcp/0",
|
|
"/sctp/0",
|
|
"/udp/1234",
|
|
"/tcp/1234",
|
|
"/sctp/1234",
|
|
"/udp/65535",
|
|
"/tcp/65535",
|
|
"/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
|
|
"/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
|
|
"/udp/1234/sctp/1234",
|
|
"/udp/1234/udt",
|
|
"/udp/1234/utp",
|
|
"/tcp/1234/http",
|
|
"/tcp/1234/https",
|
|
"/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
|
|
"/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
|
|
"/ip4/127.0.0.1/udp/1234",
|
|
"/ip4/127.0.0.1/udp/0",
|
|
"/ip4/127.0.0.1/tcp/1234",
|
|
"/ip4/127.0.0.1/tcp/1234/",
|
|
"/ip4/127.0.0.1/udp/1234/quic",
|
|
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
|
|
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
|
|
"/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
|
|
"/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
|
|
"/unix/a/b/c/d/e",
|
|
"/unix/stdio",
|
|
"/ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f",
|
|
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio",
|
|
"/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio",
|
|
}
|
|
|
|
for _, a := range cases {
|
|
if _, err := NewMultiaddr(a); err != nil {
|
|
t.Errorf("should have succeeded: %s -- %s", a, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEqual(t *testing.T) {
|
|
m1 := newMultiaddr(t, "/ip4/127.0.0.1/udp/1234")
|
|
m2 := newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234")
|
|
m3 := newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234")
|
|
m4 := newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234/")
|
|
|
|
if m1.Equal(m2) {
|
|
t.Error("should not be equal")
|
|
}
|
|
|
|
if m2.Equal(m1) {
|
|
t.Error("should not be equal")
|
|
}
|
|
|
|
if !m2.Equal(m3) {
|
|
t.Error("should be equal")
|
|
}
|
|
|
|
if !m3.Equal(m2) {
|
|
t.Error("should be equal")
|
|
}
|
|
|
|
if !m1.Equal(m1) {
|
|
t.Error("should be equal")
|
|
}
|
|
|
|
if !m2.Equal(m4) {
|
|
t.Error("should be equal")
|
|
}
|
|
|
|
if !m4.Equal(m3) {
|
|
t.Error("should be equal")
|
|
}
|
|
}
|
|
|
|
func TestStringToBytes(t *testing.T) {
|
|
|
|
testString := func(s string, h string) {
|
|
b1, err := hex.DecodeString(h)
|
|
if err != nil {
|
|
t.Error("failed to decode hex", h)
|
|
}
|
|
|
|
b2, err := stringToBytes(s)
|
|
if err != nil {
|
|
t.Error("failed to convert", s)
|
|
}
|
|
|
|
if !bytes.Equal(b1, b2) {
|
|
t.Error("failed to convert", s, "to", b1, "got", b2)
|
|
}
|
|
|
|
if err := validateBytes(b2); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
testString("/ip4/127.0.0.1/udp/1234", "047f000001910204d2")
|
|
testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1")
|
|
testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f000001910204d2047f0000010610e1")
|
|
}
|
|
|
|
func TestBytesToString(t *testing.T) {
|
|
|
|
testString := func(s1 string, h string) {
|
|
t.Helper()
|
|
b, err := hex.DecodeString(h)
|
|
if err != nil {
|
|
t.Error("failed to decode hex", h)
|
|
}
|
|
|
|
if err := validateBytes(b); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
s2, err := bytesToString(b)
|
|
if err != nil {
|
|
t.Error("failed to convert", b, err)
|
|
}
|
|
|
|
if s1 != s2 {
|
|
t.Error("failed to convert", b, "to", s1, "got", s2)
|
|
}
|
|
}
|
|
|
|
testString("/ip4/127.0.0.1/udp/1234", "047f000001910204d2")
|
|
testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1")
|
|
testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f000001910204d2047f0000010610e1")
|
|
testString("/onion/aaimaq4ygg2iegci:80", "bc030010c0439831b48218480050")
|
|
}
|
|
|
|
func TestBytesSplitAndJoin(t *testing.T) {
|
|
|
|
testString := func(s string, res []string) {
|
|
m, err := NewMultiaddr(s)
|
|
if err != nil {
|
|
t.Fatal("failed to convert", s, err)
|
|
}
|
|
|
|
split := Split(m)
|
|
if len(split) != len(res) {
|
|
t.Error("not enough split components", split)
|
|
return
|
|
}
|
|
|
|
for i, a := range split {
|
|
if a.String() != res[i] {
|
|
t.Errorf("split component failed: %s != %s", a, res[i])
|
|
}
|
|
}
|
|
|
|
joined := Join(split...)
|
|
if !m.Equal(joined) {
|
|
t.Errorf("joined components failed: %s != %s", m, joined)
|
|
}
|
|
|
|
for i, a := range split {
|
|
if a.String() != res[i] {
|
|
t.Errorf("split component failed: %s != %s", a, res[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
testString("/ip4/1.2.3.4/udp/1234", []string{"/ip4/1.2.3.4", "/udp/1234"})
|
|
testString("/ip4/1.2.3.4/tcp/1/ip4/2.3.4.5/udp/2",
|
|
[]string{"/ip4/1.2.3.4", "/tcp/1", "/ip4/2.3.4.5", "/udp/2"})
|
|
testString("/ip4/1.2.3.4/utp/ip4/2.3.4.5/udp/2/udt",
|
|
[]string{"/ip4/1.2.3.4", "/utp", "/ip4/2.3.4.5", "/udp/2", "/udt"})
|
|
}
|
|
|
|
func TestProtocols(t *testing.T) {
|
|
m, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234")
|
|
if err != nil {
|
|
t.Error("failed to construct", "/ip4/127.0.0.1/udp/1234")
|
|
}
|
|
|
|
ps := m.Protocols()
|
|
if ps[0].Code != ProtocolWithName("ip4").Code {
|
|
t.Error(ps[0], ProtocolWithName("ip4"))
|
|
t.Error("failed to get ip4 protocol")
|
|
}
|
|
|
|
if ps[1].Code != ProtocolWithName("udp").Code {
|
|
t.Error(ps[1], ProtocolWithName("udp"))
|
|
t.Error("failed to get udp protocol")
|
|
}
|
|
|
|
}
|
|
|
|
func TestProtocolsWithString(t *testing.T) {
|
|
pwn := ProtocolWithName
|
|
good := map[string][]Protocol{
|
|
"/ip4": []Protocol{pwn("ip4")},
|
|
"/ip4/tcp": []Protocol{pwn("ip4"), pwn("tcp")},
|
|
"ip4/tcp/udp/ip6": []Protocol{pwn("ip4"), pwn("tcp"), pwn("udp"), pwn("ip6")},
|
|
"////////ip4/tcp": []Protocol{pwn("ip4"), pwn("tcp")},
|
|
"ip4/udp/////////": []Protocol{pwn("ip4"), pwn("udp")},
|
|
"////////ip4/tcp////////": []Protocol{pwn("ip4"), pwn("tcp")},
|
|
}
|
|
|
|
for s, ps1 := range good {
|
|
ps2, err := ProtocolsWithString(s)
|
|
if err != nil {
|
|
t.Errorf("ProtocolsWithString(%s) should have succeeded", s)
|
|
}
|
|
|
|
for i, ps1p := range ps1 {
|
|
ps2p := ps2[i]
|
|
if ps1p.Code != ps2p.Code {
|
|
t.Errorf("mismatch: %s != %s, %s", ps1p.Name, ps2p.Name, s)
|
|
}
|
|
}
|
|
}
|
|
|
|
bad := []string{
|
|
"dsijafd", // bogus proto
|
|
"/ip4/tcp/fidosafoidsa", // bogus proto
|
|
"////////ip4/tcp/21432141/////////", // bogus proto
|
|
"////////ip4///////tcp/////////", // empty protos in between
|
|
}
|
|
|
|
for _, s := range bad {
|
|
if _, err := ProtocolsWithString(s); err == nil {
|
|
t.Errorf("ProtocolsWithString(%s) should have failed", s)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestEncapsulate(t *testing.T) {
|
|
m, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
m2, err := NewMultiaddr("/udp/5678")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
b := m.Encapsulate(m2)
|
|
if s := b.String(); s != "/ip4/127.0.0.1/udp/1234/udp/5678" {
|
|
t.Error("encapsulate /ip4/127.0.0.1/udp/1234/udp/5678 failed.", s)
|
|
}
|
|
|
|
m3, _ := NewMultiaddr("/udp/5678")
|
|
c := b.Decapsulate(m3)
|
|
if s := c.String(); s != "/ip4/127.0.0.1/udp/1234" {
|
|
t.Error("decapsulate /udp failed.", "/ip4/127.0.0.1/udp/1234", s)
|
|
}
|
|
|
|
m4, _ := NewMultiaddr("/ip4/127.0.0.1")
|
|
d := c.Decapsulate(m4)
|
|
if s := d.String(); s != "" {
|
|
t.Error("decapsulate /ip4 failed.", "/", s)
|
|
}
|
|
}
|
|
|
|
func assertValueForProto(t *testing.T, a Multiaddr, p int, exp string) {
|
|
t.Logf("checking for %s in %s", ProtocolWithCode(p).Name, a)
|
|
fv, err := a.ValueForProtocol(p)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if fv != exp {
|
|
t.Fatalf("expected %q for %d in %s, but got %q instead", exp, p, a, fv)
|
|
}
|
|
}
|
|
|
|
func TestGetValue(t *testing.T) {
|
|
a := newMultiaddr(t, "/ip4/127.0.0.1/utp/tcp/5555/udp/1234/utp/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP")
|
|
assertValueForProto(t, a, P_IP4, "127.0.0.1")
|
|
assertValueForProto(t, a, P_UTP, "")
|
|
assertValueForProto(t, a, P_TCP, "5555")
|
|
assertValueForProto(t, a, P_UDP, "1234")
|
|
assertValueForProto(t, a, P_IPFS, "QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP")
|
|
assertValueForProto(t, a, P_P2P, "QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP")
|
|
|
|
_, err := a.ValueForProtocol(P_IP6)
|
|
switch err {
|
|
case ErrProtocolNotFound:
|
|
break
|
|
case nil:
|
|
t.Fatal("expected value lookup to fail")
|
|
default:
|
|
t.Fatalf("expected ErrProtocolNotFound but got: %s", err)
|
|
}
|
|
|
|
a = newMultiaddr(t, "/ip4/0.0.0.0") // only one addr
|
|
assertValueForProto(t, a, P_IP4, "0.0.0.0")
|
|
|
|
a = newMultiaddr(t, "/ip4/0.0.0.0/ip4/0.0.0.0/ip4/0.0.0.0") // same sub-addr
|
|
assertValueForProto(t, a, P_IP4, "0.0.0.0")
|
|
|
|
a = newMultiaddr(t, "/ip4/0.0.0.0/udp/12345/utp") // ending in a no-value one.
|
|
assertValueForProto(t, a, P_IP4, "0.0.0.0")
|
|
assertValueForProto(t, a, P_UDP, "12345")
|
|
assertValueForProto(t, a, P_UTP, "")
|
|
|
|
a = newMultiaddr(t, "/ip4/0.0.0.0/unix/a/b/c/d") // ending in a path one.
|
|
assertValueForProto(t, a, P_IP4, "0.0.0.0")
|
|
assertValueForProto(t, a, P_UNIX, "/a/b/c/d")
|
|
}
|
|
|
|
func TestFuzzBytes(t *testing.T) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
// Bump up these numbers if you want to stress this
|
|
buf := make([]byte, 256)
|
|
for i := 0; i < 2000; i++ {
|
|
l := rand.Intn(len(buf))
|
|
rand.Read(buf[:l])
|
|
|
|
// just checking that it doesnt panic
|
|
ma, err := NewMultiaddrBytes(buf[:l])
|
|
if err == nil {
|
|
// for any valid multiaddrs, make sure these calls don't panic
|
|
_ = ma.String()
|
|
ma.Protocols()
|
|
}
|
|
}
|
|
}
|
|
|
|
func randMaddrString() string {
|
|
good_corpus := []string{"tcp", "ip", "udp", "ipfs", "0.0.0.0", "127.0.0.1", "12345", "QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP"}
|
|
|
|
size := rand.Intn(256)
|
|
parts := make([]string, 0, size)
|
|
for i := 0; i < size; i++ {
|
|
switch rand.Intn(5) {
|
|
case 0, 1, 2:
|
|
parts = append(parts, good_corpus[rand.Intn(len(good_corpus))])
|
|
default:
|
|
badbuf := make([]byte, rand.Intn(256))
|
|
rand.Read(badbuf)
|
|
parts = append(parts, string(badbuf))
|
|
}
|
|
}
|
|
|
|
return "/" + strings.Join(parts, "/")
|
|
}
|
|
|
|
func TestFuzzString(t *testing.T) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
// Bump up these numbers if you want to stress this
|
|
for i := 0; i < 2000; i++ {
|
|
|
|
// just checking that it doesnt panic
|
|
ma, err := NewMultiaddr(randMaddrString())
|
|
if err == nil {
|
|
// for any valid multiaddrs, make sure these calls don't panic
|
|
_ = ma.String()
|
|
ma.Protocols()
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBinaryRepresentation(t *testing.T) {
|
|
expected := []byte{0x4, 0x7f, 0x0, 0x0, 0x1, 0x91, 0x2, 0x4, 0xd2}
|
|
ma, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
if !bytes.Equal(ma.Bytes(), expected) {
|
|
t.Errorf("expected %x, got %x", expected, ma.Bytes())
|
|
}
|
|
}
|
|
|
|
func TestRoundTrip(t *testing.T) {
|
|
for _, s := range []string{
|
|
"/unix/a/b/c/d",
|
|
"/ip6/::ffff:127.0.0.1/tcp/111",
|
|
"/ip4/127.0.0.1/tcp/123",
|
|
"/ip4/127.0.0.1/udp/123",
|
|
"/ip4/127.0.0.1/udp/123/ip6/::",
|
|
"/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP",
|
|
"/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP/unix/a/b/c",
|
|
} {
|
|
ma, err := NewMultiaddr(s)
|
|
if err != nil {
|
|
t.Errorf("error when parsing %q: %s", s, err)
|
|
continue
|
|
}
|
|
if ma.String() != s {
|
|
t.Errorf("failed to round trip %q", s)
|
|
}
|
|
}
|
|
}
|
|
|
|
// XXX: Change this test when we switch to /p2p by default.
|
|
func TestIPFSvP2P(t *testing.T) {
|
|
var (
|
|
p2pAddr = "/p2p/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP"
|
|
ipfsAddr = "/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP"
|
|
)
|
|
|
|
for _, s := range []string{p2pAddr, ipfsAddr} {
|
|
ma, err := NewMultiaddr(s)
|
|
if err != nil {
|
|
t.Errorf("error when parsing %q: %s", s, err)
|
|
}
|
|
if ma.String() != ipfsAddr {
|
|
t.Errorf("expected %q, got %q", ipfsAddr, ma.String())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInvalidP2PAddr(t *testing.T) {
|
|
badAddr := "a503221221c05877cbae039d70a5e600ea02c6f9f2942439285c9e344e26f8d280c850fad6"
|
|
bts, err := hex.DecodeString(badAddr)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ma, err := NewMultiaddrBytes(bts)
|
|
if err == nil {
|
|
t.Error("should have failed")
|
|
// Check for panic
|
|
_ = ma.String()
|
|
}
|
|
}
|
|
|
|
func TestZone(t *testing.T) {
|
|
ip6String := "/ip6zone/eth0/ip6/::1"
|
|
ip6Bytes := []byte{
|
|
0x2a, 4,
|
|
'e', 't', 'h', '0',
|
|
0x29,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 1,
|
|
}
|
|
|
|
ma, err := NewMultiaddr(ip6String)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if !bytes.Equal(ma.Bytes(), ip6Bytes) {
|
|
t.Errorf("expected %x, got %x", ip6Bytes, ma.Bytes())
|
|
}
|
|
|
|
ma2, err2 := NewMultiaddrBytes(ip6Bytes)
|
|
if err2 != nil {
|
|
t.Error(err)
|
|
}
|
|
if ma2.String() != ip6String {
|
|
t.Errorf("expected %s, got %s", ip6String, ma2.String())
|
|
}
|
|
}
|