The four toolkit adapters disagree about whether the 8-octet Fragment header
belongs to the IPv6 reassembly packet's ihl and header. Measured on
examples/captures/ipv6.pcap, frame 13:
| adapter |
ihl |
len(header) |
tl |
Fragment header inside header? |
toolkit/pcap.py (default) |
48 |
48 |
1496 |
yes |
toolkit/pcapng.py |
48 |
48 |
1496 |
yes |
toolkit/dpkt.py |
40 |
40 |
1488 |
no |
toolkit/scapy.py |
40 |
40 |
1496 |
no |
Note tl is a three-way disagreement: scapy and the default agree at 1496
while dpkt reports 1488.
Why the default path includes it
pcapkit/protocols/internet/ipv6.py:341 adds each extension header's length to
hdr_len before the Fragment-header check breaks the loop at line 354:
hdr_len += next_.length # line 341
...
if ex_proto == Enum_ExtensionHeader.IPv6_Frag: # line 354
ipv6.__update__({'fragment': self._read_packet(header=hdr_len, payload=raw_len)})
break
So by the time _read_packet(header=hdr_len, ...) cuts the header, hdr_len
already counts the Fragment header — and ipv6_info.fragment.header, which
toolkit/pcap.py:119 passes as header, therefore contains it. The data
model's own comment agrees that this is hdr_len's meaning: "Header length
(including extension headers)".
dpkt and scapy compute the boundary independently and land on the other
side: hdr_len + ipv6_frag.__hdr_len__ is where dpkt starts the payload, and
scapy uses bytes(ipv6)[:-len(ipv6_frag)].
The user-visible consequence
The reassembled datagram presents a Fragment header on a datagram that is by
definition no longer a fragment:
reassembled datagram, default engine:
len(header)=48 next-header byte=44 (44 = IPv6-Frag)
payload len=4778
:rfc:8200#section-4.5 — "The Fragment header is not present in the
reassembled packet." So the default and pcapng adapters are the wrong ones
here, and dpkt/scapy are right.
Suggested fix
Have toolkit/pcap.py and toolkit/pcapng.py report the header up to but not
including the Fragment header, matching the other two adapters and the RFC.
ipv6_info.hdr_len itself should keep its documented meaning (it is correct as
a header length; it is just not the right value for this field), so the
adapters need the pre-Fragment length rather than a change to the data model.
tl wants settling in the same pass, since no two adapters currently agree on
it either.
Worth a test asserting all four adapters produce the same ihl, header and
tl for the same capture — the inconsistency survived because each adapter is
only ever tested against itself.
Found while fixing the documentation for these fields in #413, where the
docstring's "only headers before IPv6-Frag" comment turned out to be wrong for
the adapter it describes. That comment is repeated verbatim in all four
adapters and should be corrected alongside the behaviour.
The four toolkit adapters disagree about whether the 8-octet Fragment header
belongs to the IPv6 reassembly packet's
ihlandheader. Measured onexamples/captures/ipv6.pcap, frame 13:ihllen(header)tlheader?toolkit/pcap.py(default)toolkit/pcapng.pytoolkit/dpkt.pytoolkit/scapy.pyNote
tlis a three-way disagreement:scapyand the default agree at 1496while
dpktreports 1488.Why the default path includes it
pcapkit/protocols/internet/ipv6.py:341adds each extension header's length tohdr_lenbefore the Fragment-header check breaks the loop at line 354:So by the time
_read_packet(header=hdr_len, ...)cuts the header,hdr_lenalready counts the Fragment header — and
ipv6_info.fragment.header, whichtoolkit/pcap.py:119passes asheader, therefore contains it. The datamodel's own comment agrees that this is
hdr_len's meaning: "Header length(including extension headers)".
dpktandscapycompute the boundary independently and land on the otherside:
hdr_len + ipv6_frag.__hdr_len__is wheredpktstarts the payload, andscapyusesbytes(ipv6)[:-len(ipv6_frag)].The user-visible consequence
The reassembled datagram presents a Fragment header on a datagram that is by
definition no longer a fragment:
:rfc:
8200#section-4.5— "The Fragment header is not present in thereassembled packet." So the default and pcapng adapters are the wrong ones
here, and
dpkt/scapyare right.Suggested fix
Have
toolkit/pcap.pyandtoolkit/pcapng.pyreport the header up to but notincluding the Fragment header, matching the other two adapters and the RFC.
ipv6_info.hdr_lenitself should keep its documented meaning (it is correct asa header length; it is just not the right value for this field), so the
adapters need the pre-Fragment length rather than a change to the data model.
tlwants settling in the same pass, since no two adapters currently agree onit either.
Worth a test asserting all four adapters produce the same
ihl,headerandtlfor the same capture — the inconsistency survived because each adapter isonly ever tested against itself.
Found while fixing the documentation for these fields in #413, where the
docstring's "only headers before IPv6-Frag" comment turned out to be wrong for
the adapter it describes. That comment is repeated verbatim in all four
adapters and should be corrected alongside the behaviour.