net/packet: clarify minFragBlks reuse for IPv6 and test chained ext header
Follow-up cleanups to the IPv6 fragment extension header support added in the previous commit: - Document that minFragBlks is sized for IPv4 but intentionally reused by decode6 for IPv6 fragments, where it is conservative (IPv6 fragments carry no per-fragment IP header) and only ever rejects more later fragments as Unknown, never fewer. - Add a TestDecode case for a first fragment reachable only through a chained extension header (base Next Header = Hop-by-Hop Options, which chains to Fragment). decode6 only parses the Fragment header when it is the base header's immediate Next Header, so this must classify as Unknown. The test locks in that scoping decision. Updates #20083 Updates #20140 Change-Id: Ibece03c6baf2385b0cc399f179819b08cbe921cc Signed-off-by: James Tucker <james@tailscale.com>
This commit is contained in:
committed by
James Tucker
parent
ca20611d11
commit
26b2ed0a6a
@@ -17,6 +17,11 @@ import (
|
||||
const unknown = ipproto.Unknown
|
||||
|
||||
// RFC1858: prevent overlapping fragment attacks.
|
||||
//
|
||||
// The bound is sized for IPv4 (max IPv4 header + basic TCP header) but is
|
||||
// intentionally reused by decode6 for IPv6 fragments. It is conservative for
|
||||
// IPv6, whose fragments carry no per-fragment IP header, so it only ever
|
||||
// rejects more later fragments as Unknown, never fewer.
|
||||
const minFragBlks = (60 + 20) / 8 // max IPv4 header + basic TCP header in fragment blocks (8 bytes each)
|
||||
|
||||
// ip6FragHeader is the IANA protocol number for the IPv6 Fragment extension
|
||||
|
||||
@@ -357,6 +357,40 @@ var udp6SmallOffsetFragmentDecode = Parsed{
|
||||
Dst: mustIPPort("[2607:f8b0:400a:809::200e]:0"),
|
||||
}
|
||||
|
||||
// A first fragment reachable only through a chained extension header: the base
|
||||
// header's Next Header is Hop-by-Hop Options (0), which then chains to the
|
||||
// Fragment header. decode6 only parses the Fragment header when it is the
|
||||
// base header's immediate Next Header, so it must classify this as Unknown
|
||||
// rather than walking the chain. This locks in that scoping decision so a
|
||||
// future change can't silently start (mis)parsing chained headers.
|
||||
var udp6ChainedFragmentBuffer = []byte{
|
||||
// IPv6 header. Next header = 0 (Hop-by-Hop Options), payload len = 24.
|
||||
0x60, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x40,
|
||||
// Src addr
|
||||
0x20, 0x01, 0x05, 0x59, 0xbc, 0x13, 0x54, 0x00, 0x17, 0x49, 0x46, 0x28, 0x39, 0x34, 0x0e, 0x1b,
|
||||
// Dst addr
|
||||
0x26, 0x07, 0xf8, 0xb0, 0x40, 0x0a, 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0e,
|
||||
// Hop-by-Hop Options header (8 bytes): NextHeader=44 (Fragment),
|
||||
// HdrExtLen=0, followed by PadN option padding.
|
||||
0x2c, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00,
|
||||
// Fragment extension header: NextHeader=UDP, Reserved, Offset=0 + M=1, Identification.
|
||||
0x11, 0x00, 0x00, 0x01, 0xde, 0xad, 0xbe, 0xef,
|
||||
// UDP header (unreachable: decoder stops at the unhandled Hop-by-Hop header).
|
||||
0xd4, 0x04, 0x01, 0xbb, 0x00, 0x18, 0x00, 0x00,
|
||||
}
|
||||
|
||||
var udp6ChainedFragmentDecode = Parsed{
|
||||
b: udp6ChainedFragmentBuffer,
|
||||
subofs: 40, // base header only; the Hop-by-Hop header is not parsed
|
||||
dataofs: 0,
|
||||
length: len(udp6ChainedFragmentBuffer),
|
||||
|
||||
IPVersion: 6,
|
||||
IPProto: Unknown,
|
||||
Src: mustIPPort("[2001:559:bc13:5400:1749:4628:3934:e1b]:0"),
|
||||
Dst: mustIPPort("[2607:f8b0:400a:809::200e]:0"),
|
||||
}
|
||||
|
||||
var udp4ReplyBuffer = []byte{
|
||||
// IP header up to checksum
|
||||
0x45, 0x00, 0x00, 0x29, 0x21, 0x52, 0x00, 0x00, 0x40, 0x11, 0x49, 0x5f,
|
||||
@@ -696,6 +730,7 @@ func TestDecode(t *testing.T) {
|
||||
{"ipv6_frag_nonfirst", udp6NonFirstFragmentBuffer, udp6NonFirstFragmentDecode},
|
||||
{"ipv6_frag_short_first", udp6ShortFirstFragmentBuffer, udp6ShortFirstFragmentDecode},
|
||||
{"ipv6_frag_small_offset", udp6SmallOffsetFragmentBuffer, udp6SmallOffsetFragmentDecode},
|
||||
{"ipv6_frag_chained", udp6ChainedFragmentBuffer, udp6ChainedFragmentDecode},
|
||||
{"ipv4_fragtooshort", tcp4ShortFragmentBuffer, tcp4ShortFragmentDecode},
|
||||
{"ipv4_short_first_fragment", ipv4ShortFirstFragmentBuffer, ipv4ShortFirstFragmentDecode},
|
||||
{"ipv4_small_offset_fragment", ipv4SmallOffsetFragmentBuffer, ipv4SmallOffsetFragmentDecode},
|
||||
|
||||
Reference in New Issue
Block a user