From cf7ed7c1ad2986e869f7ea5e835a581c559361ac Mon Sep 17 00:00:00 2001 From: idk Date: Thu, 8 Nov 2018 03:36:21 -0500 Subject: [PATCH] created onionv3 and garlic multiaddrs --- multiaddr_test.go | 37 ++++++++++++++++++-- protocols.go | 38 +++++++++++++++++--- transcoders.go | 88 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 8 deletions(-) diff --git a/multiaddr_test.go b/multiaddr_test.go index 261cba3..1a979de 100644 --- a/multiaddr_test.go +++ b/multiaddr_test.go @@ -38,6 +38,24 @@ func TestConstructFails(t *testing.T) { "/onion/timaq4ygg2iegci7:-1", "/onion/timaq4ygg2iegci7", "/onion/timaq4ygg2iegci@:666", + "/onion3/9ww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:80", + "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd7:80", + "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:0", + "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:-1", + "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd", + "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyy@:666", + "/garlict/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq", + "/garlict/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq7:80", + "/garlict/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:0", + "/garlict/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:0", + "/garlict/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:-1", + "/garlict/566niximlxdzpanmn4qouucvua3k7neniss47li5r6ugoertzuq@:666", + "/garlicu/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq", + "/garlicu/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq7:80", + "/garlicu/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:0", + "/garlicu/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:0", + "/garlicu/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:-1", + "/garlicu/566niximlxdzpanmn4qouucvua3k7neniss47li5r6ugoertzuq@:666", "/udp/1234/sctp", "/udp/1234/udt/1234", "/udp/1234/utp/1234", @@ -74,6 +92,12 @@ func TestConstructSucceeds(t *testing.T) { "/ip6zone/x/ip6/fe80::1/udp/1234/quic", "/onion/timaq4ygg2iegci7:1234", "/onion/timaq4ygg2iegci7:80/http", + "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234", + "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:80/http", + "/garlict/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:1234", + "/garlict/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:80/http", + "/garlicu/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:1234", + "/garlicu/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:80/http", "/udp/0", "/tcp/0", "/sctp/0", @@ -159,21 +183,25 @@ func TestStringToBytes(t *testing.T) { b2, err := stringToBytes(s) if err != nil { - t.Error("failed to convert", s) + t.Error("failed to convert", s, err) } - if !bytes.Equal(b1, b2) { t.Error("failed to convert", s, "to", b1, "got", b2) } if err := validateBytes(b2); err != nil { - t.Error(err) + t.Error(err, "len:", len(b2)) } } 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") + testString("/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234", "bd03adadec040be047f9658668b11a504f3155001f231a37f54c4476c07fb4cc139ed7e30304d2") + testString("/garlict/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:1234", "ca03efbcd45d0c5dc79781ac6f20ea5055a036afb48d45a52e7d68ec7d4338919e6904d2") + testString("/garlicu/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:1234", "cb03efbcd45d0c5dc79781ac6f20ea5055a036afb48d45a52e7d68ec7d4338919e6904d2") + } func TestBytesToString(t *testing.T) { @@ -203,6 +231,9 @@ func TestBytesToString(t *testing.T) { 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") + testString("/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234", "bd03adadec040be047f9658668b11a504f3155001f231a37f54c4476c07fb4cc139ed7e30304d2") + testString("/garlict/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:1234", "ca03efbcd45d0c5dc79781ac6f20ea5055a036afb48d45a52e7d68ec7d4338919e6904d2") + testString("/garlicu/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:1234", "cb03efbcd45d0c5dc79781ac6f20ea5055a036afb48d45a52e7d68ec7d4338919e6904d2") } func TestBytesSplitAndJoin(t *testing.T) { diff --git a/protocols.go b/protocols.go index d466598..407b9c4 100644 --- a/protocols.go +++ b/protocols.go @@ -21,7 +21,11 @@ const ( P_IPFS = 0x01A5 // alias for backwards compatability P_HTTP = 0x01E0 P_HTTPS = 0x01BB - P_ONION = 0x01BC + P_ONION = 0x01BC // also for backwards compatibility + P_ONION2 = 0x01BC + P_ONION3 = 0x01BD + P_GARLICT = 0x01CA + P_GARLICU = 0x01CB ) var ( @@ -80,13 +84,34 @@ var ( Size: 16, Transcoder: TranscoderPort, } - protoONION = Protocol{ + protoONION2 = Protocol{ Name: "onion", - Code: P_ONION, - VCode: CodeToVarint(P_ONION), + Code: P_ONION2, + VCode: CodeToVarint(P_ONION2), Size: 96, Transcoder: TranscoderOnion, } + protoONION3 = Protocol{ + Name: "onion3", + Code: P_ONION3, + VCode: CodeToVarint(P_ONION3), + Size: 296, + Transcoder: TranscoderOnion3, + } + protoGARLICT = Protocol{ + Name: "garlict", + Code: P_GARLICT, + VCode: CodeToVarint(P_GARLICT), + Size: 272, + Transcoder: TranscoderGarlic, + } + protoGARLICU = Protocol{ + Name: "garlicu", + Code: P_GARLICU, + VCode: CodeToVarint(P_GARLICU), + Size: 272, + Transcoder: TranscoderGarlic, + } protoUTP = Protocol{ Name: "utp", Code: P_UTP, @@ -138,7 +163,10 @@ func init() { protoIP6, protoIP6ZONE, protoSCTP, - protoONION, + protoONION2, + protoONION3, + protoGARLICT, + protoGARLICU, protoUTP, protoUDT, protoQUIC, diff --git a/transcoders.go b/transcoders.go index b5408f0..4ced267 100644 --- a/transcoders.go +++ b/transcoders.go @@ -167,6 +167,94 @@ func onionBtS(b []byte) (string, error) { return addr + ":" + strconv.Itoa(int(port)), nil } +var TranscoderOnion3 = NewTranscoderFromFunctions(onion3StB, onion3BtS, nil) + +func onion3StB(s string) ([]byte, error) { + addr := strings.Split(s, ":") + if len(addr) != 2 { + return nil, fmt.Errorf("failed to parse onion addr: %s does not contain a port number.", s) + } + + // onion address without the ".onion" substring + if len(addr[0]) != 56 { + return nil, fmt.Errorf("failed to parse onion addr: %s not a Tor onionv3 address. len == %d", s, len(addr[0])) + } + onionHostBytes, err := base32.StdEncoding.DecodeString(strings.ToUpper(addr[0])) + if err != nil { + return nil, fmt.Errorf("failed to decode base32 onion addr: %s %s", s, err) + } + + // onion port number + i, err := strconv.Atoi(addr[1]) + if err != nil { + return nil, fmt.Errorf("failed to parse onion addr: %s", err) + } + if i >= 65536 { + return nil, fmt.Errorf("failed to parse onion addr: %s", "port greater than 65536") + } + if i < 1 { + return nil, fmt.Errorf("failed to parse onion addr: %s", "port less than 1") + } + + onionPortBytes := make([]byte, 2) + binary.BigEndian.PutUint16(onionPortBytes, uint16(i)) + bytes := []byte{} + bytes = append(bytes, onionHostBytes[0:35]...) + bytes = append(bytes, onionPortBytes...) + return bytes, nil +} + +func onion3BtS(b []byte) (string, error) { + addr := strings.ToLower(base32.StdEncoding.EncodeToString(b[0:35])) + port := binary.BigEndian.Uint16(b[35:37]) + str := addr + ":" + strconv.Itoa(int(port)) + return str, nil +} + +var TranscoderGarlic = NewTranscoderFromFunctions(garlicStB, garlicBtS, nil) + +func garlicStB(s string) ([]byte, error) { + addr := strings.Split(s, ":") + if len(addr) != 2 { + return nil, fmt.Errorf("failed to parse garlic addr: %s does not contain a port number.", s) + } + // garlic address without the ".b32.i2p" substring, with padding + if len(addr[0]) != 52 { + return nil, fmt.Errorf("failed to parse garlic addr: %s not a i2p base32 address. len: %d", s, len(addr[0])) + } + garlicHostBytes := make([]byte, 32) + _, err := base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567").Decode(garlicHostBytes, []byte(addr[0]+"====")) + if err != nil { + return nil, fmt.Errorf("failed to decode base32 garlic addr: %s %s %s", s, err, string(s[48])) + } + + // garlic port number + i, err := strconv.Atoi(addr[1]) + if err != nil { + return nil, fmt.Errorf("failed to parse garlic addr: %s", err) + } + if i >= 65536 { + return nil, fmt.Errorf("failed to parse garlic addr: %s", "port greater than 65536") + } + if i < 1 { + return nil, fmt.Errorf("failed to parse garlic addr: %s", "port less than 1") + } + + garlicPortBytes := make([]byte, 2) + binary.BigEndian.PutUint16(garlicPortBytes, uint16(i)) + bytes := []byte{} + bytes = append(bytes, garlicHostBytes[0:32]...) + bytes = append(bytes, garlicPortBytes...) + return bytes, nil +} + +func garlicBtS(b []byte) (string, error) { + addr := strings.Replace(strings.ToLower(base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567").EncodeToString(b[0:32])), "=", "", -1) + port := binary.BigEndian.Uint16(b[32:34]) + str := addr + ":" + strconv.Itoa(int(port)) + return str, nil +} + var TranscoderP2P = NewTranscoderFromFunctions(p2pStB, p2pBtS, p2pVal) func p2pStB(s string) ([]byte, error) {