I have a scapy
protocol and a packet.
Like "First steps" say, it's easy to print a packet with its fields, and the packet's binary dump:
>>> a=Ether()/IP(dst="www.slashdot.org")/TCP()/"GET /index.html HTTP/1.0 \n\n"
>>> a
<Ether type=IPv4 |<IP frag=0 proto=6 dst=Net("www.slashdot.org/32") |<TCP
|<Raw load='GET /index.html HTTP/1.0 \n\n' |>
>>>
>>> hexdump(a)
0000 FF FF FF FF FF FF 02 42 AC 1F 80 3C 08 00 45 00 .......B...<..E.
0010 00 43 00 01 00 00 40 06 C9 F0 AC 1F 80 3C 68 12 .C....@......<h.
0020 1C 56 00 14 00 50 00 00 00 00 00 00 00 00 50 02 .V...P........P.
0030 20 00 0C EE 00 00 47 45 54 20 2F 69 6E 64 65 78 .....GET /index
0040 2E 68 74 6D 6C 20 48 54 54 50 2F 31 2E 30 20 0A .html HTTP/1.0 .
0050 0A .
>>>
Now, I want to know, for example, what offset does dport
field in TCP
have. Or all of the fields in all the layers.
Can I print them with scapy
? Is there a single way to do it for all protocols, including custom ones?
interesting question. I don't believe that there's currently any builtin way of doing that, and I can't really think of a use case.
The things that gets the closest, for purely informative purpose, are probably either:
pdfdump()
(and alike) functions: https://scapy.readthedocs.io/en/latest/usage.html#graphical-dumps-pdf-psrfc()
function>>> rfc(TCP)
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SPORT | DPORT |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SEQ |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ACK |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|DATAOFS|RESER| FLAGS | WINDOW |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| CHKSUM | URGPTR |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| OPTIONS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fig. TCP
But if you want really is a numerical value, matching the offset of a field from the first byte, It's not super hard to do it yourself, with something like:
def calc_offset(packet, layer, field):
"""Calculate the offset of a field, in a packet"""
offset = 0
while packet: # for each payload
for fld in packet.fields_desc: # for each field
if fld.name == field and isinstance(packet, layer):
return int(offset)
offset += fld.i2len(packet, packet.getfieldval(fld.name)) # add length
packet = packet.payload
return -1
In your example:
>>> a=Ether()/IP(dst="www.slashdot.org")/TCP()/"GET /index.html HTTP/1.0 \n\n"
>>> calc_offset(a, TCP, "dport")
36
>>> struct.unpack("!H", bytes(a)[36:36+2])[0]
80
>>> a.dport
80
Hope this helped