From 1774cbfccb4cd3814906034e28c802f4dd17c4e3 Mon Sep 17 00:00:00 2001 From: Dominik Roos Date: Tue, 10 Oct 2023 09:43:08 +0200 Subject: [PATCH] slayers: unmap IPv4-mapped IPv6 addresses (#4377) The Go standard library can produce IPv4-mapped IPv6 addresses when resolving IP addresses. These IP addresses need to be unmapped before putting them on the wire. Before this patch, we could observe the following with tshark: Len=1304 SCION 1-ff00:0:110,[::ffff:172.20.2.2] -> 1-ff00:0:111,[::ffff:172.20.3.2] UDP 32769 -> 32768 1208 The regression was introduced in #4346, which removed the unmapping behavior in slayers.PackAddr. This patch restores the behavior to ensure only unmapped IPv4 addresses make it on the wire. Handling the unmapping in the code that generates the addresses and only checking this in slayers would seem ideal, but these calls are often very far away from the place that would then trigger an error. Thus handling this in slayers seems like a compromise that saves us and the users of the slayers package a lot of trouble. --- pkg/slayers/scion.go | 9 +++++---- pkg/slayers/scion_test.go | 15 +++++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/pkg/slayers/scion.go b/pkg/slayers/scion.go index 7e24772f14..66ff20c755 100644 --- a/pkg/slayers/scion.go +++ b/pkg/slayers/scion.go @@ -394,15 +394,16 @@ func ParseAddr(addrType AddrType, raw []byte) (addr.Host, error) { func PackAddr(host addr.Host) (AddrType, []byte, error) { switch host.Type() { case addr.HostTypeIP: - ip := host.IP() + // The IP is potentially IPv4-in-IPv6. We need to unmap it to ensure + // we only have true IPv4 or IPv6 addresses. + ip := host.IP().Unmap() if !ip.IsValid() { break } - t := T4Ip if ip.Is6() { - t = T16Ip + return T16Ip, ip.AsSlice(), nil } - return t, ip.AsSlice(), nil + return T4Ip, ip.AsSlice(), nil case addr.HostTypeSVC: raw := make([]byte, 4) binary.BigEndian.PutUint16(raw, uint16(host.SVC())) diff --git a/pkg/slayers/scion_test.go b/pkg/slayers/scion_test.go index 06d4967551..a794587614 100644 --- a/pkg/slayers/scion_test.go +++ b/pkg/slayers/scion_test.go @@ -33,10 +33,11 @@ import ( ) var ( - ip6Addr = addr.MustParseHost("2001:db8::68") - ip4Addr = addr.MustParseHost("10.0.0.100") - svcAddr = addr.MustParseHost("Wildcard") - rawPath = func() []byte { + ip6Addr = addr.MustParseHost("2001:db8::68") + ip4Addr = addr.MustParseHost("10.0.0.100") + ip4in6Addr = addr.MustParseHost("::ffff:10.0.0.100") + svcAddr = addr.MustParseHost("Wildcard") + rawPath = func() []byte { return []byte("\x00\x00\x20\x80\x00\x00\x01\x11\x00\x00\x01\x00\x01\x00\x02\x22\x00" + "\x00\x01\x00\x00\x3f\x00\x01\x00\x00\x01\x02\x03\x04\x05\x06\x00\x3f\x00\x03\x00" + "\x02\x01\x02\x03\x04\x05\x06\x00\x3f\x00\x00\x00\x02\x01\x02\x03\x04\x05\x06\x00" + @@ -311,6 +312,12 @@ func TestPackAddr(t *testing.T) { rawAddr: ip4Addr.IP().AsSlice(), errorFunc: assert.NoError, }, + "pack IPv4-mapped IPv6": { + addr: ip4in6Addr, + addrType: slayers.T4Ip, + rawAddr: []byte{0xa, 0x0, 0x0, 0x64}, + errorFunc: assert.NoError, + }, "pack IPv6": { addr: ip6Addr, addrType: slayers.T16Ip,