From ed310561bd8ffcc3768eee596e1fd956f32eb8f0 Mon Sep 17 00:00:00 2001 From: David Stainton Date: Sat, 29 Aug 2015 19:48:07 +0200 Subject: [PATCH 1/6] Add Tor .onion address support and unit test cases --- codec.go | 11 +++++++++++ multiaddr_test.go | 5 +++++ protocols.csv | 1 + protocols.go | 2 ++ 4 files changed, 19 insertions(+) diff --git a/codec.go b/codec.go index 9fef2da..5db2989 100644 --- a/codec.go +++ b/codec.go @@ -1,6 +1,7 @@ package multiaddr import ( + "encoding/base32" "encoding/binary" "errors" "fmt" @@ -165,6 +166,16 @@ func addressStringToBytes(p Protocol, s string) ([]byte, error) { binary.BigEndian.PutUint16(b, uint16(i)) return b, nil + case P_TOR: + fields := strings.Split(s, ".onion") + if len(fields) != 2 { + return nil, fmt.Errorf("failed to parse ipfs addr: %s not a Tor .onion address.", s) + } + b, err := base32.StdEncoding.DecodeString(strings.ToUpper(fields[0])) + if err != nil { + return nil, fmt.Errorf("failed to parse ipfs addr: %s %s", s, err) + } + return b, nil case P_IPFS: // ipfs // the address is a varint prefixed multihash string representation m, err := mh.FromB58String(s) diff --git a/multiaddr_test.go b/multiaddr_test.go index f0e9c36..6e980cb 100644 --- a/multiaddr_test.go +++ b/multiaddr_test.go @@ -25,6 +25,8 @@ func TestConstructFails(t *testing.T) { "/sctp", "/udp/65536", "/tcp/65536", + "/tor/9imaq4ygg2iegci7.onion", + "/tor/aaimaq4ygg2iegci7.onion", "/udp/1234/sctp", "/udp/1234/udt/1234", "/udp/1234/utp/1234", @@ -49,6 +51,9 @@ func TestConstructSucceeds(t *testing.T) { "/ip4/0.0.0.0", "/ip6/::1", "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21", + "/tor/timaq4ygg2iegci7.onion", + "/tor/timaq4ygg2iegci7.onion/tcp/1234", + "/tor/timaq4ygg2iegci7.onion/tcp/80/http", "/udp/0", "/tcp/0", "/sctp/0", diff --git a/protocols.csv b/protocols.csv index 213e9b5..912b557 100644 --- a/protocols.csv +++ b/protocols.csv @@ -5,6 +5,7 @@ code size name 33 16 dccp 41 128 ip6 132 16 sctp +133 10 tor 301 0 udt 302 0 utp 421 V ipfs diff --git a/protocols.go b/protocols.go index c4ee5df..8cf4414 100644 --- a/protocols.go +++ b/protocols.go @@ -25,6 +25,7 @@ const ( P_DCCP = 33 P_IP6 = 41 P_SCTP = 132 + P_TOR = 133 P_UTP = 301 P_UDT = 302 P_IPFS = 421 @@ -46,6 +47,7 @@ var Protocols = []Protocol{ Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6)}, // these require varint: Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP)}, + Protocol{P_TOR, 10, "tor", CodeToVarint(P_TOR)}, Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP)}, Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT)}, Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP)}, From 75a10eef9b4a8b13f116ee3d946c0adee3212a4d Mon Sep 17 00:00:00 2001 From: Leif Ryge Date: Sat, 29 Aug 2015 20:22:48 +0000 Subject: [PATCH 2/6] more strict validation of .onion addresses --- codec.go | 9 ++++++--- multiaddr_test.go | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/codec.go b/codec.go index 5db2989..b698c23 100644 --- a/codec.go +++ b/codec.go @@ -168,12 +168,15 @@ func addressStringToBytes(p Protocol, s string) ([]byte, error) { case P_TOR: fields := strings.Split(s, ".onion") - if len(fields) != 2 { - return nil, fmt.Errorf("failed to parse ipfs addr: %s not a Tor .onion address.", s) + if len(fields) != 2 || len(fields[1]) != 0 { + return nil, fmt.Errorf("failed to parse tor addr: %s does not end with .onion", s) } b, err := base32.StdEncoding.DecodeString(strings.ToUpper(fields[0])) if err != nil { - return nil, fmt.Errorf("failed to parse ipfs addr: %s %s", s, err) + return nil, fmt.Errorf("failed to parse tor addr: %s %s", s, err) + } + if len(b) != 10 { + return nil, fmt.Errorf("failed to parse tor addr: %s decoded to %s bytes, expected 10", s, len(b)) } return b, nil case P_IPFS: // ipfs diff --git a/multiaddr_test.go b/multiaddr_test.go index 6e980cb..aa45dd6 100644 --- a/multiaddr_test.go +++ b/multiaddr_test.go @@ -27,6 +27,8 @@ func TestConstructFails(t *testing.T) { "/tcp/65536", "/tor/9imaq4ygg2iegci7.onion", "/tor/aaimaq4ygg2iegci7.onion", + "/tor/timaq4ygg2iegci7.onionxxx", + "/tor/timaq4yg.onion", "/udp/1234/sctp", "/udp/1234/udt/1234", "/udp/1234/utp/1234", From 0e7ae0d2eecd239463e6ba13aecb57cb430f7a14 Mon Sep 17 00:00:00 2001 From: David Stainton Date: Mon, 31 Aug 2015 03:19:47 +0200 Subject: [PATCH 3/6] Renamed tor to onion and added embedded port field --- codec.go | 34 +++++++++++++++++++++++++++------- multiaddr_test.go | 10 +++++----- protocols.csv | 2 +- protocols.go | 4 ++-- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/codec.go b/codec.go index 5db2989..12db280 100644 --- a/codec.go +++ b/codec.go @@ -166,16 +166,36 @@ func addressStringToBytes(p Protocol, s string) ([]byte, error) { binary.BigEndian.PutUint16(b, uint16(i)) return b, nil - case P_TOR: - fields := strings.Split(s, ".onion") - if len(fields) != 2 { - return nil, fmt.Errorf("failed to parse ipfs addr: %s not a Tor .onion address.", s) + case P_ONION: + addr := strings.Split(s, ":") + if len(addr) != 2 { + return nil, fmt.Errorf("failed to parse %s addr: %s does not contain a port number.", p.Name, s) } - b, err := base32.StdEncoding.DecodeString(strings.ToUpper(fields[0])) + + // onion address without the ".onion" substring + if len(addr[0]) != 16 { + return nil, fmt.Errorf("failed to parse %s addr: %s not a Tor onion address.", p.Name, s) + } + onionHostBytes, err := base32.StdEncoding.DecodeString(strings.ToUpper(addr[0])) if err != nil { - return nil, fmt.Errorf("failed to parse ipfs addr: %s %s", s, err) + return nil, fmt.Errorf("failed to decode base32 %s addr: %s %s", p.Name, s, err) } - return b, nil + + // onion port number + i, err := strconv.Atoi(addr[1]) + if err != nil { + return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, err) + } + if i >= 65536 { + return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "greater than 65536") + } + onionPortBytes := make([]byte, 2) + binary.BigEndian.PutUint16(onionPortBytes, uint16(i)) + bytes := []byte{} + bytes = append(bytes, onionHostBytes...) + bytes = append(bytes, onionPortBytes...) + return bytes, nil + case P_IPFS: // ipfs // the address is a varint prefixed multihash string representation m, err := mh.FromB58String(s) diff --git a/multiaddr_test.go b/multiaddr_test.go index 6e980cb..cc0676a 100644 --- a/multiaddr_test.go +++ b/multiaddr_test.go @@ -25,8 +25,9 @@ func TestConstructFails(t *testing.T) { "/sctp", "/udp/65536", "/tcp/65536", - "/tor/9imaq4ygg2iegci7.onion", - "/tor/aaimaq4ygg2iegci7.onion", + "/onion/9imaq4ygg2iegci7:80", + "/onion/aaimaq4ygg2iegci7:80", + "/onion/timaq4ygg2iegci7", "/udp/1234/sctp", "/udp/1234/udt/1234", "/udp/1234/utp/1234", @@ -51,9 +52,8 @@ func TestConstructSucceeds(t *testing.T) { "/ip4/0.0.0.0", "/ip6/::1", "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21", - "/tor/timaq4ygg2iegci7.onion", - "/tor/timaq4ygg2iegci7.onion/tcp/1234", - "/tor/timaq4ygg2iegci7.onion/tcp/80/http", + "/onion/timaq4ygg2iegci7:1234", + "/onion/timaq4ygg2iegci7:80/http", "/udp/0", "/tcp/0", "/sctp/0", diff --git a/protocols.csv b/protocols.csv index 912b557..fa27ba3 100644 --- a/protocols.csv +++ b/protocols.csv @@ -5,9 +5,9 @@ code size name 33 16 dccp 41 128 ip6 132 16 sctp -133 10 tor 301 0 udt 302 0 utp 421 V ipfs 480 0 http 443 0 https +444 10 onion \ No newline at end of file diff --git a/protocols.go b/protocols.go index 8cf4414..96846c7 100644 --- a/protocols.go +++ b/protocols.go @@ -25,12 +25,12 @@ const ( P_DCCP = 33 P_IP6 = 41 P_SCTP = 132 - P_TOR = 133 P_UTP = 301 P_UDT = 302 P_IPFS = 421 P_HTTP = 480 P_HTTPS = 443 + P_ONION = 444 ) // These are special sizes @@ -47,7 +47,7 @@ var Protocols = []Protocol{ Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6)}, // these require varint: Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP)}, - Protocol{P_TOR, 10, "tor", CodeToVarint(P_TOR)}, + Protocol{P_ONION, 10, "onion", CodeToVarint(P_ONION)}, Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP)}, Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT)}, Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP)}, From fca4278010af6850c530ff84f5e2582872b069ee Mon Sep 17 00:00:00 2001 From: David Stainton Date: Sat, 26 Sep 2015 01:35:58 +0200 Subject: [PATCH 4/6] Ensure port is above minimum port number for onions --- codec.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/codec.go b/codec.go index 12db280..64e7d04 100644 --- a/codec.go +++ b/codec.go @@ -187,8 +187,12 @@ func addressStringToBytes(p Protocol, s string) ([]byte, error) { return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, err) } if i >= 65536 { - return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "greater than 65536") + return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "port greater than 65536") } + if i < 1 { + return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "port less than 1") + } + onionPortBytes := make([]byte, 2) binary.BigEndian.PutUint16(onionPortBytes, uint16(i)) bytes := []byte{} From 3bc1e2e8c3593d4ebdaaf9c1c386365ad0b8b4d8 Mon Sep 17 00:00:00 2001 From: David Stainton Date: Sat, 26 Sep 2015 01:36:31 +0200 Subject: [PATCH 5/6] Onions are 80 bits --- protocols.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols.go b/protocols.go index 96846c7..c233cef 100644 --- a/protocols.go +++ b/protocols.go @@ -47,7 +47,7 @@ var Protocols = []Protocol{ Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6)}, // these require varint: Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP)}, - Protocol{P_ONION, 10, "onion", CodeToVarint(P_ONION)}, + Protocol{P_ONION, 80, "onion", CodeToVarint(P_ONION)}, Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP)}, Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT)}, Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP)}, From 24ecf94c7004fb26be35d0c4b60c27655746bd1d Mon Sep 17 00:00:00 2001 From: David Stainton Date: Sat, 26 Sep 2015 01:40:26 +0200 Subject: [PATCH 6/6] Add more multiaddr tests for onions --- multiaddr_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/multiaddr_test.go b/multiaddr_test.go index cc0676a..3a60751 100644 --- a/multiaddr_test.go +++ b/multiaddr_test.go @@ -27,7 +27,10 @@ func TestConstructFails(t *testing.T) { "/tcp/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",