Enhancement: efficient round-tripping through machine representation
Brief description
I am using scapy as an EDSL for describing packets to be fed through my own custom "dissector" of sorts. Said dissector needs access to computed fields, as well as specified ones, and computed fields are computed only when going to machine representation (AFAICT?). To make this fly, I am specifying packets using Python classes (Ether()/IP()/TCP()/...), converting them to machine representation, and then converting back to the class-ful representation for subsequent processing.
Unfortunately, some of my packets are, shall we say, "weird", by design, in a way that scapy's internal logic for layer binding does not (and probably should not be asked to) understand, and so this round-trip results in a very confused output. I have figured out a way around this -- a way to ensure that the input and output layer stacks have the same classes in the same order -- but it's not particularly pleasant and, worse, it's quadratic in the length of the packet, which is not ideal. A better way to round-trip like this would be most welcome.
Scapy version
2.5.0
Python version
3.11.2
Operating system
5.15.90
Additional environment information
No response
How to reproduce
The round-trip method I've written is as follows:
def scapy_roundtrip(pkt):
out = pkt.__class__(bytes(pkt))
layers_left = pkt.layers()[1:]
cursor = out
while layers_left != []:
if not isinstance(cursor.payload, layers_left[0]):
cursor.decode_payload_as(layers_left[0])
layers_left = layers_left[1:]
cursor = cursor.payload
return out
In the best case, this is just a linear zip down the layers of both the input and output packets. In the worst case, though, every layer of the output needs to be revisited, and decode_payload_as will decode not just that layer but all internal ones as well, leading to quadratic behavior. Ideally, it would be possible to extract just one layer with a guaranteed Raw payload, or something like that, so that decoding was once again linear. Perhaps a flag to decode_payload_as to ignore all layer bindings?
Actual result
No response
Expected result
No response
Related resources
No response