10

How can I get a list of all the layers in scapy? Eg: Ether/IP/UDP/DNS or Ether/IP/TCP/HTTP. The only thing I can think of is to do a packet.summary() and parse the output, which seems very crude. I think there should be a method built-in, but cannot find any in the documentation. Any suggestions?

What I am trying to do is to iterate over all the fields of a specific protocol given by a user and display its values.

Update: What I am looking for exactly can be seen in wireshark: Open any capture, select a packet, and in the 'Frame' menu, one can see Protocols in frame: eth:ip:udp:data This is exactly what I am looking for in Scapy. I hope I am clearer now.

krish7919
  • 892
  • 2
  • 13
  • 30

4 Answers4

11

Each additional layer is the payload of a packet, so you can iterate

def expand(x):
    yield x
    while x.payload:
        x = x.payload
        yield x

and then

res = list(expand(packet))

I hope that is what you meant.

cronos
  • 2,268
  • 16
  • 17
  • This doesn't give me the layers in the packet. It just prints the packet contents. What I am looking for exactly can be seen in wireshark: Open any capture, select a packet, and in the 'Frame' menu, one can see `Protocols in frame: eth:ip:udp:data`. This is exactly what I am looking for in Scapy. I hope I am clearer now. – krish7919 Nov 25 '12 at 11:15
  • It does, just each packet contains all upper layers by construction. See @eminor who prints the names with my method. – cronos Nov 25 '12 at 12:14
10

Use packet.getLayer(<id>) in a loop. For example:

from scapy.all import Ether

def get_packet_layers(packet):
    counter = 0
    while True:
        layer = packet.getlayer(counter)
        if layer is None:
            break

        yield layer
        counter += 1


packet = 'ffffffffffff00ffd59c64320806000108000604000100ffd59c6432000000000000000000000a000001'.decode('hex')
packet = Ether(_pkt=packet)

for layer in get_packet_layers(packet):
    print (layer.name)

outputs

Ethernet
ARP
Jossef Harush Kadouri
  • 32,361
  • 10
  • 130
  • 129
krish7919
  • 892
  • 2
  • 13
  • 30
5

I looked at the source code and didn't find such a method, so I altered cronos's code a bit and it looks like it does what you want now.

You could write a bug report for scapy and suggest a new method.

>>> ip = Ether()/IP()/TCP()
>>> ip
<Ether  type=0x800 |<IP  frag=0 proto=tcp |<TCP  |>>>
>>> ip.name
'Ethernet'
>>> def expand(x):
...     yield x.name
...     while x.payload:
...         x = x.payload
...         yield x.name
... 
>>> list(expand(ip))
['Ethernet', 'IP', 'TCP']
>>> l=list(expand(ip))
>>> ":".join(l)
'Ethernet:IP:TCP'
>>> 
eminor
  • 923
  • 6
  • 11
  • I was trying something similar when you answered this and logged in to post my answer! Check my code below. – krish7919 Nov 25 '12 at 12:21
2

With packet.payload.layers() i get a list of layer classes for the packet. I can then access the packet layers, for example:


def sniff_callback(packet):
    print(packet.payload.layers())  # display all layers
    first_layer = packet[packet.payload.layers()[0]]  # access first layer of the list

Guillaume Lebreton
  • 2,586
  • 16
  • 25