Skip to content

inet: choose the payload class from reassembled fragments - #5143

Open
KernelClint wants to merge 1 commit into
secdev:masterfrom
KernelClint:inet-payload-class-from-reassembled
Open

inet: choose the payload class from reassembled fragments#5143
KernelClint wants to merge 1 commit into
secdev:masterfrom
KernelClint:inet-payload-class-from-reassembled

Conversation

@KernelClint

Copy link
Copy Markdown
Contributor

_defrag_ip_pkt() puts a fragmented IPv4 datagram back together and then has to decide what the
reassembled bytes are. At
scapy/layers/inet.py:1467-1505
it reuses the class Scapy guessed for the first fragment's payload:

pay_class = p[IP].payload.__class__

The first fragment is often too short to classify correctly — with a small enough first fragment
Scapy has not seen a complete TCP header, so the guess is whatever it managed from those bytes. The
complete datagram is then forced into that class regardless of what the assembled bytes actually
are. Through TCPSession, an HTTP response that arrived in valid ordered fragments comes back
without its application layer, while the byte-identical unfragmented response comes back correctly.

The change asks the reassembled IP layer to classify the complete bytes, the same way ordinary
dissection does:

-            pay_class = p[IP].payload.__class__
+            pay_class = p[IP].guess_payload_class(data)
...
-            p /= pay_class(data)
+            p[IP].add_payload(pay_class(data))

Every valid fragment layout is still reassembled; what changes is that the result is classified from
what was actually received.

The added regression reassembles the same HTTP response at two fragment sizes, including one whose
first fragment is too small to classify, and asserts the response body is delivered in both. Without
the source change it fails.

Performance was measured on one computer, before and after the fix: reassembling a valid ordered
datagram took 232.0 µs before and 176.3 µs after — 24% faster. Repeat runs moved by less than
that, so it is a real difference. Dispatching normally avoids the work the old path spent forcing
bytes into a class that could not parse them.

@codecov

codecov Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.64%. Comparing base (b3bbcc8) to head (4bc5e3f).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #5143   +/-   ##
=======================================
  Coverage   80.63%   80.64%           
=======================================
  Files         390      390           
  Lines       96936    96936           
=======================================
+ Hits        78168    78174    +6     
+ Misses      18768    18762    -6     
Files with missing lines Coverage Δ
scapy/layers/inet.py 71.94% <100.00%> (ø)

... and 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant