diff --git a/multiaddr_test.go b/multiaddr_test.go index 6d160b4..4d2d5de 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", "/http-path/tmp%2Fbar", "/http-path/tmp%2Fbar%2Fbaz", "/http-path/foo", @@ -438,6 +446,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) { @@ -546,6 +560,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) { @@ -632,6 +651,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", "/http-path/tmp%2Fbar", } { ma, err := NewMultiaddr(s) diff --git a/protocols.go b/protocols.go index d3117b2..024da53 100644 --- a/protocols.go +++ b/protocols.go @@ -41,6 +41,7 @@ const ( P_PLAINTEXTV2 = 7367777 P_WEBRTC_DIRECT = 280 P_WEBRTC = 281 + P_SCION = 13639680 ) var ( @@ -281,6 +282,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() { @@ -322,6 +331,7 @@ func init() { protoPlaintextV2, protoWebRTCDirect, protoWebRTC, + protoSCION, } { if err := AddProtocol(p); err != nil { panic(err) diff --git a/transcoders.go b/transcoders.go index 0d0327e..ab2ebf2 100644 --- a/transcoders.go +++ b/transcoders.go @@ -456,6 +456,36 @@ func validateCertHash(b []byte) error { 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 +} + var TranscoderHTTPPath = NewTranscoderFromFunctions(httpPathStB, httpPathBtS, validateHTTPPath) func httpPathStB(s string) ([]byte, error) {