Skip to content

Commit fb56eae

Browse files
committed
docs(changelog): fold #2755, #2758 and #2759 (#2449)
- Fixed: a cut header's rebuild keeps the next layer its parse had, where 1.5.x rebuilt a cut Ethernet header's Raw as NoPayload, and that Raw carries no error (#2759), a new entry; old values measured against v1.5.1. - Amended unreleased entries (#2758): a cut list of schema items ends with the data, the item the cut lands inside zero-filled and none past it, in the ListField, IGMP and HTTP/2 SETTINGS entries, the last also rebuilding at its declared Length or a recomputed one once edited. - Folded (#2755): a counted item the data ends inside reads as a quiet short read, into the ListField and IGMP entries. - CHANGELOG.md regenerated; util/changelog_md.py --check passes.
1 parent b853afe commit fb56eae

2 files changed

Lines changed: 49 additions & 26 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Wave 2 of the roadmap, per the contributing docs' enhancement-proposal page: the
1616

1717
- **Added** -- `ICMPv4` ([RFC 792](https://datatracker.ietf.org/doc/html/rfc792)) and `ICMPv6` ([RFC 4443](https://datatracker.ietf.org/doc/html/rfc4443)), on an abstract `ICMP` base, for IP protocols 1 and 58, which were kept as `Raw` ([#2436](https://github.com/JarryShaw/PyPCAPKit/issues/2436), [#2446](https://github.com/JarryShaw/PyPCAPKit/pull/2446)); a protochain names `ICMPv6` where it named `IPv6_ICMP`. Echo, Destination Unreachable, Time Exceeded and Parameter Problem bodies are decoded, and ICMPv6's Packet Too Big; every other type, Neighbor Discovery and MLD included, keeps its body raw. ICMPv4 takes the plain `ICMP` of [RFC 792](https://datatracker.ietf.org/doc/html/rfc792) as its `id()` and alias. `register_icmp_type()` registers a message-body parser. The type and code registries are `pcapkit.const.icmp` and `pcapkit.const.icmpv6`, crawled from IANA.
1818

19-
- **Added** -- IGMPv1 ([RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112)), IGMPv2 ([RFC 2236](https://datatracker.ietf.org/doc/html/rfc2236)) and IGMPv3 ([RFC 3376](https://datatracker.ietf.org/doc/html/rfc3376)), as `IGMPv1`, `IGMPv2` and `IGMPv3`, each named after its module ([#2529](https://github.com/JarryShaw/PyPCAPKit/issues/2529), [#2542](https://github.com/JarryShaw/PyPCAPKit/pull/2542)), on an abstract `IGMP` base bound at IP protocol 2, which picks the version from the message type alone except for a Membership Query: one of 8 octets is IGMPv1 if its Max Resp Time is zero and IGMPv2 otherwise, one of 12 or more IGMPv3 ([#2439](https://github.com/JarryShaw/PyPCAPKit/issues/2439), [#2448](https://github.com/JarryShaw/PyPCAPKit/issues/2448), [#2444](https://github.com/JarryShaw/PyPCAPKit/pull/2444), [#2465](https://github.com/JarryShaw/PyPCAPKit/pull/2465)). An IGMPv3 Query carries its source list and a Membership Report its group records, and an IGMPv3 Query's Max Resp Code and QQIC are decoded from their floating-point form. An IGMPv3 message the capture cut short, a Report cut inside its group records included, parses and rebuilds as captured, whether parsed on its own or carried by IPv4, and IGMPv3's `make()` takes `num_group_records`, from the record count to `0xFFFF` ([#2650](https://github.com/JarryShaw/PyPCAPKit/issues/2650), [#2660](https://github.com/JarryShaw/PyPCAPKit/issues/2660), [#2662](https://github.com/JarryShaw/PyPCAPKit/pull/2662), [#2672](https://github.com/JarryShaw/PyPCAPKit/pull/2672)). The octets it lacks read as zeros, the group records included, and a Report's header schema cut inside the Additional Data past its records packs back as captured ([#2686](https://github.com/JarryShaw/PyPCAPKit/issues/2686), [#2687](https://github.com/JarryShaw/PyPCAPKit/issues/2687), [#2701](https://github.com/JarryShaw/PyPCAPKit/pull/2701)). A Report parsed on its own sizes its group records by its record count, so one cut before the records it counts reads `TRUNCATED`, as it does behind IPv4, holding the records captured and none made up, and a count no IP payload could carry raises `ProtocolError` ([#2711](https://github.com/JarryShaw/PyPCAPKit/issues/2711), [#2738](https://github.com/JarryShaw/PyPCAPKit/pull/2738)). Any other message, a 9- to 11-octet Query included, is kept as `Raw`. IGMPv1 takes the plain `IGMP` of [RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112) as its `id()` and alias, and IGMPv2's and IGMPv3's `id()` are their own names alone, `('IGMPv2',)` and `('IGMPv3',)`; the base's is `('IGMP', 'IGMPv2', 'IGMPv3')`, each member's canonical name ([#2512](https://github.com/JarryShaw/PyPCAPKit/issues/2512), [#2506](https://github.com/JarryShaw/PyPCAPKit/pull/2506), [#2518](https://github.com/JarryShaw/PyPCAPKit/pull/2518)). IGMPv2's and IGMPv3's `name` carries the version, `'Internet Group Management Protocol version 2'` say, while IGMPv1's, as in [RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112), does not ([#2558](https://github.com/JarryShaw/PyPCAPKit/issues/2558), [#2590](https://github.com/JarryShaw/PyPCAPKit/pull/2590)). The registries are `pcapkit.const.igmp`: the types crawled from IANA, the group record types from a hand-maintained table.
19+
- **Added** -- IGMPv1 ([RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112)), IGMPv2 ([RFC 2236](https://datatracker.ietf.org/doc/html/rfc2236)) and IGMPv3 ([RFC 3376](https://datatracker.ietf.org/doc/html/rfc3376)), as `IGMPv1`, `IGMPv2` and `IGMPv3`, each named after its module ([#2529](https://github.com/JarryShaw/PyPCAPKit/issues/2529), [#2542](https://github.com/JarryShaw/PyPCAPKit/pull/2542)), on an abstract `IGMP` base bound at IP protocol 2, which picks the version from the message type alone except for a Membership Query: one of 8 octets is IGMPv1 if its Max Resp Time is zero and IGMPv2 otherwise, one of 12 or more IGMPv3 ([#2439](https://github.com/JarryShaw/PyPCAPKit/issues/2439), [#2448](https://github.com/JarryShaw/PyPCAPKit/issues/2448), [#2444](https://github.com/JarryShaw/PyPCAPKit/pull/2444), [#2465](https://github.com/JarryShaw/PyPCAPKit/pull/2465)). An IGMPv3 Query carries its source list and a Membership Report its group records, and an IGMPv3 Query's Max Resp Code and QQIC are decoded from their floating-point form. An IGMPv3 message the capture cut short, a Report cut inside its group records included, parses and rebuilds as captured, whether parsed on its own or carried by IPv4, and IGMPv3's `make()` takes `num_group_records`, from the record count to `0xFFFF` ([#2650](https://github.com/JarryShaw/PyPCAPKit/issues/2650), [#2660](https://github.com/JarryShaw/PyPCAPKit/issues/2660), [#2662](https://github.com/JarryShaw/PyPCAPKit/pull/2662), [#2672](https://github.com/JarryShaw/PyPCAPKit/pull/2672)). The octets it lacks read as zeros, in the group record the cut lands inside included, and a Report's header schema cut inside the Additional Data past its records packs back as captured ([#2686](https://github.com/JarryShaw/PyPCAPKit/issues/2686), [#2687](https://github.com/JarryShaw/PyPCAPKit/issues/2687), [#2701](https://github.com/JarryShaw/PyPCAPKit/pull/2701)); no group record past the cut is read, however the Report is framed ([#2756](https://github.com/JarryShaw/PyPCAPKit/issues/2756), [#2758](https://github.com/JarryShaw/PyPCAPKit/pull/2758)). A Report parsed on its own sizes its group records by its record count, so one cut before the records it counts reads `TRUNCATED`, as it does behind IPv4, holding the records captured and none made up, and a count no IP payload could carry raises `ProtocolError` ([#2711](https://github.com/JarryShaw/PyPCAPKit/issues/2711), [#2738](https://github.com/JarryShaw/PyPCAPKit/pull/2738)); one cut inside a counted record reads quietly ([#2749](https://github.com/JarryShaw/PyPCAPKit/issues/2749), [#2755](https://github.com/JarryShaw/PyPCAPKit/pull/2755)). Any other message, a 9- to 11-octet Query included, is kept as `Raw`. IGMPv1 takes the plain `IGMP` of [RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112) as its `id()` and alias, and IGMPv2's and IGMPv3's `id()` are their own names alone, `('IGMPv2',)` and `('IGMPv3',)`; the base's is `('IGMP', 'IGMPv2', 'IGMPv3')`, each member's canonical name ([#2512](https://github.com/JarryShaw/PyPCAPKit/issues/2512), [#2506](https://github.com/JarryShaw/PyPCAPKit/pull/2506), [#2518](https://github.com/JarryShaw/PyPCAPKit/pull/2518)). IGMPv2's and IGMPv3's `name` carries the version, `'Internet Group Management Protocol version 2'` say, while IGMPv1's, as in [RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112), does not ([#2558](https://github.com/JarryShaw/PyPCAPKit/issues/2558), [#2590](https://github.com/JarryShaw/PyPCAPKit/pull/2590)). The registries are `pcapkit.const.igmp`: the types crawled from IANA, the group record types from a hand-maintained table.
2020

2121
- **Added** -- construction through a versioned family's base: `IP` and `L2TP`, which raised `TypeError` in 1.5.x, and the `ICMP`, `IGMP` and `LinuxSLL` bases above give a member, never an instance of the base, on parsing octets, building from fields and `from_data` ([#2574](https://github.com/JarryShaw/PyPCAPKit/issues/2574), [#2639](https://github.com/JarryShaw/PyPCAPKit/pull/2639)). The `version` keyword names the member. Without it, IP's, IGMP's and L2TP's octets give the member they describe, and `from_data` the one its data names, IGMP's data models carrying a `version` for it. Building from fields without it raises `ProtocolError`, whose message asks for `version`, and so do ICMP and Linux cooked-capture octets, which carry no version; their `from_data` on a `dict` raises it too, as does a version a family has no member for, such as L2TP's `3`. A member built directly takes `version` as well, which must be its own. HTTP's base follows the same rules, a breaking change given below ([#2628](https://github.com/JarryShaw/PyPCAPKit/issues/2628), [#2651](https://github.com/JarryShaw/PyPCAPKit/pull/2651)). IPv4 and IPv6 check the Version field before the rest of the header, so octets of the other version raise `[IPv4] invalid version: 6` say, where IPv4's error named whichever field they broke first.
2222

@@ -120,9 +120,9 @@ Wave 2 of the roadmap, per the contributing docs' enhancement-proposal page: the
120120

121121
- **Fixed** -- a membership test such as `'ESP' in layer` on an extension header parsed by the IPv6 header's walk -- AH, HOPOPT, IPv6_Route, IPv6_Frag, IPv6_Opts, MH, HIP or the generic IPv6_Ext -- raised `AttributeError`. The layer now holds `NoPayload`, the upper layer belonging to the enclosing IPv6 header ([#2484](https://github.com/JarryShaw/PyPCAPKit/issues/2484), [#2487](https://github.com/JarryShaw/PyPCAPKit/issues/2487), [#2486](https://github.com/JarryShaw/PyPCAPKit/pull/2486), [#2488](https://github.com/JarryShaw/PyPCAPKit/pull/2488)).
122122

123-
- **Fixed** -- `ListField.unpack` reads a list of schema items the data ends inside zero-filled to its length, as `FieldBase.unpack` reads any other field, so a schema cut inside one packs back as captured, where the first item past the data raised `FieldValueError` for consuming nothing ([#2686](https://github.com/JarryShaw/PyPCAPKit/issues/2686), [#2701](https://github.com/JarryShaw/PyPCAPKit/pull/2701)). Each item filled is a schema object rather than a zero octet, so `ZERO_PAD_BUDGET_RATIO` bounds the fill from its first octet, with neither the free band of `MAX_ZERO_PAD_SHORTFALL` nor a one-off allowance, and a cut list declaring more than `MAX_ZERO_PAD_LENGTH` is refused. If the items then fail, the fill stays charged, as a field's does, and the octets it counted as read are given back ([#2705](https://github.com/JarryShaw/PyPCAPKit/issues/2705), [#2706](https://github.com/JarryShaw/PyPCAPKit/pull/2706)). A `ListField` given a `count` reports a list whose octets hold fewer items than it counts as a short read, the absent items never made up ([#2711](https://github.com/JarryShaw/PyPCAPKit/issues/2711), [#2738](https://github.com/JarryShaw/PyPCAPKit/pull/2738)). A TCP `SACK` option running past the data raises `ProtocolError`, `Field options has an option that runs past the end of the data: <Option.SACK: 5> ...`, where it raised that `FieldValueError`, `Field sack has an item that consumed no data: ...`.
123+
- **Fixed** -- `ListField.unpack` reads a list of schema items the data ends inside up to the end of the data, the item the cut lands inside read with its missing octets as zeros, as `FieldBase.unpack` reads any other field, so a schema cut inside one packs back as captured, where the first item past the data raised `FieldValueError` for consuming nothing ([#2686](https://github.com/JarryShaw/PyPCAPKit/issues/2686), [#2701](https://github.com/JarryShaw/PyPCAPKit/pull/2701)). No item that would start past the captured octets is read, so a cut list holds no zero item the capture never held ([#2756](https://github.com/JarryShaw/PyPCAPKit/issues/2756), [#2758](https://github.com/JarryShaw/PyPCAPKit/pull/2758)). The fill is of schema objects rather than zero octets, so `ZERO_PAD_BUDGET_RATIO` bounds it from its first octet, with neither the free band of `MAX_ZERO_PAD_SHORTFALL` nor a one-off allowance, the zeros left unread going back to the budget, and a cut list declaring more than `MAX_ZERO_PAD_LENGTH` is refused. If the items then fail, the fill stays charged, as a field's does, and the octets it counted as read are given back ([#2705](https://github.com/JarryShaw/PyPCAPKit/issues/2705), [#2706](https://github.com/JarryShaw/PyPCAPKit/pull/2706)). A `ListField` given a `count` reports a list whose octets hold fewer items than it counts as a short read, the absent items never made up ([#2711](https://github.com/JarryShaw/PyPCAPKit/issues/2711), [#2738](https://github.com/JarryShaw/PyPCAPKit/pull/2738)), and reads an item it counts that the data ends inside as a quiet short read ([#2749](https://github.com/JarryShaw/PyPCAPKit/issues/2749), [#2755](https://github.com/JarryShaw/PyPCAPKit/pull/2755)). A TCP `SACK` option running past the data raises `ProtocolError`, `Field options has an option that runs past the end of the data: <Option.SACK: 5> ...`, where it raised that `FieldValueError`, `Field sack has an item that consumed no data: ...`.
124124

125-
- **Fixed** -- an HTTP/2 `SETTINGS` frame the capture cut short inside its settings raised `FieldValueError` from the list of settings, so a segment carrying one was kept as `Raw`. It parses, with the octets its settings lack read as zeros, as a cut `DATA` frame's data is, and rebuilds as captured ([#2659](https://github.com/JarryShaw/PyPCAPKit/issues/2659), [#2686](https://github.com/JarryShaw/PyPCAPKit/issues/2686), [#2666](https://github.com/JarryShaw/PyPCAPKit/pull/2666), [#2701](https://github.com/JarryShaw/PyPCAPKit/pull/2701)). A frame of any type the capture cut short after the connection preface rebuilds as captured too, where `from_data` gave the preface's first octets, as many as were captured of the frame ([#2665](https://github.com/JarryShaw/PyPCAPKit/issues/2665), [#2675](https://github.com/JarryShaw/PyPCAPKit/pull/2675)).
125+
- **Fixed** -- an HTTP/2 `SETTINGS` frame the capture cut short inside its settings raised `FieldValueError` from the list of settings, so a segment carrying one was kept as `Raw`. It parses, the setting the cut lands inside read with its missing octets as zeros, as a cut `DATA` frame's data is, and no setting past it, and rebuilds as captured ([#2659](https://github.com/JarryShaw/PyPCAPKit/issues/2659), [#2686](https://github.com/JarryShaw/PyPCAPKit/issues/2686), [#2666](https://github.com/JarryShaw/PyPCAPKit/pull/2666), [#2701](https://github.com/JarryShaw/PyPCAPKit/pull/2701)), at its declared Length, or at one recomputed from its settings once they are edited ([#2756](https://github.com/JarryShaw/PyPCAPKit/issues/2756), [#2758](https://github.com/JarryShaw/PyPCAPKit/pull/2758)). A frame of any type the capture cut short after the connection preface rebuilds as captured too, where `from_data` gave the preface's first octets, as many as were captured of the frame ([#2665](https://github.com/JarryShaw/PyPCAPKit/issues/2665), [#2675](https://github.com/JarryShaw/PyPCAPKit/pull/2675)).
126126

127127
- **Fixed** -- an `SCTP` packet the capture cut short of the length declared for it, by an IPv4 Total Length, an IPv6 Payload Length or a caller's `length`, rebuilt through `from_data` without the octets after its last whole chunk, which its header schema's `bytes()` counted twice. It rebuilds as captured, as one parsed with no length declared did ([#2673](https://github.com/JarryShaw/PyPCAPKit/issues/2673), [#2679](https://github.com/JarryShaw/PyPCAPKit/pull/2679)). Its header schema cut inside the padding of its last chunk, parameter or cause, or such an item's own schema cut inside its padding, packs back as captured, where 1.5.x packed it at full width, 34 octets in and 36 out; and a header schema cut inside an option area packs back the octets read, where a TCP header schema of data offset 8 cut 25 octets in gave 32 octets from `bytes()` and 23 from `pack()` ([#2680](https://github.com/JarryShaw/PyPCAPKit/issues/2680), [#2685](https://github.com/JarryShaw/PyPCAPKit/issues/2685), [#2682](https://github.com/JarryShaw/PyPCAPKit/pull/2682)).
128128

@@ -134,6 +134,8 @@ Wave 2 of the roadmap, per the contributing docs' enhancement-proposal page: the
134134

135135
- **Fixed** -- rebuilding a layer through `from_data` reported its payload's messages twice, once from the payload's own rebuild and again from the layer's parse of it: in 1.5.x, `Ethernet.from_data` of a frame cut inside its TCP header logged the refusal twice, where the parse logged it once. Each is reported once ([#2711](https://github.com/JarryShaw/PyPCAPKit/issues/2711), [#2738](https://github.com/JarryShaw/PyPCAPKit/pull/2738)). IPv4 records a cut inside the payload length it declares as its `__short_read__`, where 1.5.x recorded none, and so do Ethernet, GRE, ICMP, IGMP and a TSO IPv4 layer for a cut at the end of their frame.
136136

137+
- **Fixed** -- a header the capture cut short parsed with a `Raw` next layer but rebuilt through `from_data` with a `NoPayload` one, from the same octets: in 1.5.x an `Ethernet` header cut inside its type field parsed as `Ethernet:Raw` and rebuilt as `Ethernet:NoPayload`, as did ARP's family, AH, HIP, the IPv6 extension headers, MH, VLAN, L2TPv2 and Loopback. The rebuild keeps the next layer the parse had, GRE's, FRAD's and the Linux cooked-capture headers' included ([#2717](https://github.com/JarryShaw/PyPCAPKit/issues/2717), [#2759](https://github.com/JarryShaw/PyPCAPKit/pull/2759)). A next layer a cut header leaves no octets is `Raw` without a dispatch on the code the cut left as zeros, and carries no `error`, where 1.5.x's carried the failed dispatch's, as `Field padding resolved to a negative length; template='-20s'`.
138+
137139
- **Fixed** -- the `json`, `plist` and `tree` dumps of an `Info`, and of its `to_dict()` export, left out a field named like one of its builtin names, such as `items`, `keys` or a reassembled datagram's `packet`. Each is dumped under its own name, and a reassembled datagram's `packet` as its parsed layer's `info` ([#2733](https://github.com/JarryShaw/PyPCAPKit/issues/2733), [#2736](https://github.com/JarryShaw/PyPCAPKit/pull/2736)).
138140

139141
- **Fixed** -- importing `pcapkit.vendor.ipx`, or running its packet or socket crawler, without `requests` installed lost an entry of `sys.path` on each failed attempt, so a `pkgutil.walk_packages()` retrying it drained `sys.path` until it raised `IndexError`. The entry is now restored however the import ends ([#2589](https://github.com/JarryShaw/PyPCAPKit/issues/2589), [#2601](https://github.com/JarryShaw/PyPCAPKit/pull/2601)).

0 commit comments

Comments
 (0)