From 141f79ce0b50f913f39241a8f6f64224a77a098a Mon Sep 17 00:00:00 2001 From: Leon Rinkel Date: Wed, 1 May 2024 10:36:14 +0200 Subject: [PATCH] Add support for SCION addresses --- multiaddr_test.go | 20 ++++++++++++++++++++ protocols.go | 10 ++++++++++ transcoders.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/multiaddr_test.go b/multiaddr_test.go index b33e94d..8f0752c 100644 --- a/multiaddr_test.go +++ b/multiaddr_test.go @@ -88,6 +88,10 @@ func TestConstructFails(t *testing.T) { "/", "", "/p2p/QmxoHT6iViN5xAjoz1VZ553cL31U9F94ht3QvWR1FrEbZY", // sha256 multihash with digest len > 32 + "/scion", + "/scion//udp/1234", + "/scion/0-", + "/scion/1234", } for _, a := range cases { @@ -192,6 +196,10 @@ var good = []string{ "/ip4/127.0.0.1/tcp/127/wss", "/ip4/127.0.0.1/tcp/127/webrtc-direct", "/ip4/127.0.0.1/tcp/127/webrtc", + "/scion/0-0", + "/scion/1-ff00:0:110", + "/scion/1-ff00:0:110/ip4/1.2.3.4", + "/scion/1-ff00:0:110/ip6/::ffff:127.0.0.1/udp/111", } func TestConstructSucceeds(t *testing.T) { @@ -433,6 +441,12 @@ func TestEncapsulate(t *testing.T) { if d != nil { t.Error("decapsulate /ip4 failed: ", d) } + + m5, _ := NewMultiaddr("/scion/1-ff00:0:110") + e := m5.Encapsulate(m) + if s := e.String(); s != "/scion/1-ff00:0:110/ip4/127.0.0.1/udp/1234" { + t.Error("encapsulate /scion/1-ff00:0:110/ip4/127.0.0.1/udp/1234 failed.", s) + } } func TestDecapsulateComment(t *testing.T) { @@ -541,6 +555,11 @@ func TestGetValue(t *testing.T) { 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") + + a = newMultiaddr(t, "/scion/1-ff00:0:110/ip4/127.0.0.1/udp/1234") + assertValueForProto(t, a, P_SCION, "1-ff00:0:110") + assertValueForProto(t, a, P_IP4, "127.0.0.1") + assertValueForProto(t, a, P_UDP, "1234") } func FuzzNewMultiaddrBytes(f *testing.F) { @@ -627,6 +646,7 @@ func TestRoundTrip(t *testing.T) { "/ip4/127.0.0.1/udp/1234/quic-v1/webtransport/certhash/uEiDDq4_xNyDorZBH3TlGazyJdOWSwvo4PUo5YHFMrvDE8g", "/p2p/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP", "/p2p/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP/unix/a/b/c", + "/scion/1-ff00:0:110/ip6/::ffff:127.0.0.1/tcp/111", } { ma, err := NewMultiaddr(s) if err != nil { diff --git a/protocols.go b/protocols.go index b01e6cb..7eb6e21 100644 --- a/protocols.go +++ b/protocols.go @@ -40,6 +40,7 @@ const ( P_PLAINTEXTV2 = 7367777 P_WEBRTC_DIRECT = 280 P_WEBRTC = 281 + P_SCION = 13639680 ) var ( @@ -273,6 +274,14 @@ var ( Code: P_WEBRTC, VCode: CodeToVarint(P_WEBRTC), } + protoSCION = Protocol{ + Name: "scion", + Code: P_SCION, + VCode: CodeToVarint(P_SCION), + Size: LengthPrefixedVarSize, + Path: false, + Transcoder: TranscoderSCION, + } ) func init() { @@ -313,6 +322,7 @@ func init() { protoPlaintextV2, protoWebRTCDirect, protoWebRTC, + protoSCION, } { if err := AddProtocol(p); err != nil { panic(err) diff --git a/transcoders.go b/transcoders.go index 5387740..2d84cce 100644 --- a/transcoders.go +++ b/transcoders.go @@ -454,3 +454,33 @@ func validateCertHash(b []byte) error { _, err := mh.Decode(b) return err } + +var TranscoderSCION = NewTranscoderFromFunctions(scionStB, scionBtS, scionVal) + +func scionVal(b []byte) error { + // SCION IA is 16 bit ISD and 48 bit AS numbers separated by "-" + // ISD numbers formatted as decimal, AS numbering similar to IPv6 + // E.g.: "0-0" or "1234-ff00:0:110" + if len(b) < 3 { + return fmt.Errorf("byte slice too short: %d", len(b)) + } + if minus := bytes.IndexByte(b, '-'); minus < 0 { + return errors.New("scion addresses must contain '-'") + } + return nil +} + +func scionStB(s string) ([]byte, error) { + b := []byte(s) + if err := scionVal(b); err != nil { + return nil, err + } + return b, nil +} + +func scionBtS(b []byte) (string, error) { + if err := scionVal(b); err != nil { + return "", err + } + return string(b), nil +}