secdev / secdev/scapy

Enhancement: efficient round-tripping through machine representation

Open
#4,068 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
12.6k
Forks
2.2k
Avg merge
1d 4h
Merged PRs (30d)
56

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the scapy_roundtrip method in the issue and the decode_payload_as API it uses. Reproduce the behavior with packets whose layer bindings do not match the intended stack, then investigate how to extract one layer with a guaranteed Raw payload or otherwise bypass bindings. Done means round-tripping preserves the input layer classes and order with linear behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
networking
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.