wire: correctly handle undefined IPv4 / IPv6 preferred address values (#4985)

* wire: correctly handle undefined IPv4 / IPv6 preferred address values

* make use of the netip.AddrPort zero value
This commit is contained in:
Marten Seemann
2025-03-15 11:27:28 +07:00
committed by GitHub
parent 24acc54ef1
commit 9ca74c7049
2 changed files with 63 additions and 17 deletions

View File

@@ -436,13 +436,38 @@ func TestTransportParameterRejectsDuplicateParameters(t *testing.T) {
require.Equal(t, fmt.Sprintf("received duplicate transport parameter %#x", initialMaxStreamDataBidiLocalParameterID), transportErr.ErrorMessage)
}
func TestPreferredAddressMarshalAndUnmarshal(t *testing.T) {
func TestTransportParameterPreferredAddress(t *testing.T) {
testCases := []struct {
name string
hasIPv4 bool
hasIPv6 bool
}{
{"IPv4 and IPv6", true, true},
{"IPv4 only", true, false},
{"IPv6 only", false, true},
{"neither IPv4 nor IPv6", false, false},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
testTransportParameterPreferredAddress(t, tc.hasIPv4, tc.hasIPv6)
})
}
}
func testTransportParameterPreferredAddress(t *testing.T, hasIPv4, hasIPv6 bool) {
addr4 := netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), 42)
addr6 := netip.AddrPortFrom(netip.AddrFrom16([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}), 13)
pa := &PreferredAddress{
IPv4: netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), 42),
IPv6: netip.AddrPortFrom(netip.AddrFrom16([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}), 13),
ConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}),
StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
}
if hasIPv4 {
pa.IPv4 = addr4
}
if hasIPv6 {
pa.IPv6 = addr6
}
data := (&TransportParameters{
PreferredAddress: pa,
@@ -450,15 +475,24 @@ func TestPreferredAddressMarshalAndUnmarshal(t *testing.T) {
ActiveConnectionIDLimit: 2,
}).Marshal(protocol.PerspectiveServer)
p := &TransportParameters{}
err := p.Unmarshal(data, protocol.PerspectiveServer)
require.NoError(t, err)
require.Equal(t, pa.IPv4, p.PreferredAddress.IPv4)
require.Equal(t, pa.IPv6, p.PreferredAddress.IPv6)
require.NoError(t, p.Unmarshal(data, protocol.PerspectiveServer))
if hasIPv4 {
require.True(t, p.PreferredAddress.IPv4.IsValid())
require.Equal(t, addr4, p.PreferredAddress.IPv4)
} else {
require.False(t, p.PreferredAddress.IPv4.IsValid())
}
if hasIPv6 {
require.True(t, p.PreferredAddress.IPv6.IsValid())
require.Equal(t, addr6, p.PreferredAddress.IPv6)
} else {
require.False(t, p.PreferredAddress.IPv6.IsValid())
}
require.Equal(t, pa.ConnectionID, p.PreferredAddress.ConnectionID)
require.Equal(t, pa.StatelessResetToken, p.PreferredAddress.StatelessResetToken)
}
func TestPreferredAddressFromClient(t *testing.T) {
func TestTransportParameterPreferredAddressFromClient(t *testing.T) {
b := quicvarint.Append(nil, uint64(preferredAddressParameterID))
b = quicvarint.Append(b, 6)
b = append(b, []byte("foobar")...)
@@ -471,7 +505,7 @@ func TestPreferredAddressFromClient(t *testing.T) {
require.Equal(t, "client sent a preferred_address", transportErr.ErrorMessage)
}
func TestPreferredAddressZeroLengthConnectionID(t *testing.T) {
func TestTransportParameterPreferredAddressZeroLengthConnectionID(t *testing.T) {
pa := &PreferredAddress{
IPv4: netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), 42),
IPv6: netip.AddrPortFrom(netip.AddrFrom16([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}), 13),

View File

@@ -245,11 +245,15 @@ func (p *TransportParameters) readPreferredAddress(b []byte, expectedLen int) er
copy(ipv4[:], b[:4])
port4 := binary.BigEndian.Uint16(b[4:])
b = b[4+2:]
pa.IPv4 = netip.AddrPortFrom(netip.AddrFrom4(ipv4), port4)
if port4 != 0 && ipv4 != [4]byte{} {
pa.IPv4 = netip.AddrPortFrom(netip.AddrFrom4(ipv4), port4)
}
var ipv6 [16]byte
copy(ipv6[:], b[:16])
port6 := binary.BigEndian.Uint16(b[16:])
pa.IPv6 = netip.AddrPortFrom(netip.AddrFrom16(ipv6), port6)
if port6 != 0 && ipv6 != [16]byte{} {
pa.IPv6 = netip.AddrPortFrom(netip.AddrFrom16(ipv6), port6)
}
b = b[16+2:]
connIDLen := int(b[0])
b = b[1:]
@@ -391,12 +395,20 @@ func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte {
if p.PreferredAddress != nil {
b = quicvarint.Append(b, uint64(preferredAddressParameterID))
b = quicvarint.Append(b, 4+2+16+2+1+uint64(p.PreferredAddress.ConnectionID.Len())+16)
ip4 := p.PreferredAddress.IPv4.Addr().As4()
b = append(b, ip4[:]...)
b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv4.Port())
ip6 := p.PreferredAddress.IPv6.Addr().As16()
b = append(b, ip6[:]...)
b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv6.Port())
if p.PreferredAddress.IPv4.IsValid() {
ipv4 := p.PreferredAddress.IPv4.Addr().As4()
b = append(b, ipv4[:]...)
b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv4.Port())
} else {
b = append(b, make([]byte, 6)...)
}
if p.PreferredAddress.IPv6.IsValid() {
ipv6 := p.PreferredAddress.IPv6.Addr().As16()
b = append(b, ipv6[:]...)
b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv6.Port())
} else {
b = append(b, make([]byte, 18)...)
}
b = append(b, uint8(p.PreferredAddress.ConnectionID.Len()))
b = append(b, p.PreferredAddress.ConnectionID.Bytes()...)
b = append(b, p.PreferredAddress.StatelessResetToken[:]...)