简体   繁体   中英

Scapy: How to access a Custom Layer

I am trying to understand how to add a custom dissector in Scapy. I am using Python 3.4 and Scapy3 if that has any bearing on the result.

I have a stupid class, and the packet.show2() command correctly renders the nested packet. But I can not access the new Layers field values.

Scary Class and bind_layer follows...

from scapy.all import *
#Create simple Class
class DUMBO(Packet):
    fields_desc = [
        ShortField('ears',0),
        ShortField('legs',0),
        ShortField('trunk',0)
    ]
#Inform TCP that ports 9898 are this protocol
bind_layers(TCP, DUMBO, sport=9898, dport=9898)

I make a packet like this

#Make a Packet
pack=IP()/TCP(sport=9898, dport=9898)/Raw(load=b'\x00\x02\x00\x04\x00\x01')

Looking at the Packet I have created using ls yields

version    : BitField             = 4               (4)
ihl        : BitField             = None            (None)
tos        : XByteField           = 0               (0)
len        : ShortField           = None            (None)
id         : ShortField           = 1               (1)
flags      : FlagsField           = 0               (0)
frag       : BitField             = 0               (0)
ttl        : ByteField            = 64              (64)
proto      : ByteEnumField        = 6               (0)
chksum     : XShortField          = None            (None)
src        : Emph                 = '127.0.0.1'     (None)
dst        : Emph                 = '127.0.0.1'     ('127.0.0.1')
options    : PacketListField      = []              ([])
--
sport      : ShortEnumField       = 9898            (20)
dport      : ShortEnumField       = 9898            (80)
seq        : IntField             = 0               (0)
ack        : IntField             = 0               (0)
dataofs    : BitField             = None            (None)
reserved   : BitField             = 0               (0)
flags      : FlagsField           = 2               (2)
window     : ShortField           = 8192            (8192)
chksum     : XShortField          = None            (None)
urgptr     : ShortField           = 0               (0)
options    : TCPOptionsField      = {}              ({})
--
load       : StrField             = b'\x00\x02\x00\x04\x00\x01' (b'')

And display it using Show2 it all looks good

pack.show2()


###[ IP ]###
  version   = 4
  ihl       = 5
  tos       = 0x0
  len       = 46
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = tcp
  chksum    = 0x7cc7
  src       = 127.0.0.1
  dst       = 127.0.0.1
  \options   \
###[ TCP ]###
     sport     = monkeycom
     dport     = monkeycom
     seq       = 0
     ack       = 0
     dataofs   = 5
     reserved  = 0
     flags     = S
     window    = 8192
     chksum    = 0x447f
     urgptr    = 0
     options   = []
###[ DUMBO ]###
        ears      = 2
        legs      = 4
        trunk     = 1

I now want to access the DUMBO Layer fields

But PACK[DUMBO].ears

Is not correct - as the packet when displayed as pack.show() still has the Payload as Raw....

What am I missing??

Ok - This is my solution....

    pack=IP()/TCP(sport=19898, dport=19898)/Raw(load=b'\x00\x02\x00\x04\x00\x01')

    #Cast this packet back
    pack=IP(bytes(pack))
    pack.show2()
    pack.show()
    if DUMBO in pack:
        print('Elephant in the house')
        print('Ears -> {}'.format(pack[DUMBO].ears))

If anyone else can improve on this I would be happy on seeing the solution.

Note: I'm just getting started with Scapy, so I can't promise this is the correct/only way to go.

As per Documentation: Add new protocols to Scapy , put the code with the protocol definition in a seperate python file. Make sure you also set the required headers. Then place that file either in scapy/layers or scapy/contrib .

After that, the protocol can be loaded with load_layer(...) or load_contrib(...) where you plan on using it.

For DUMBO we'll go with contrib .

dumbo.py :

# scapy.contrib.description = Dumbo the elephant
# scapy.contrib.status = loads

from scapy.packet import Packet, bind_layers
from scapy.fields import ShortField
from scapy.layers.inet import TCP

#Create simple Class
class DUMBO(Packet):
    fields_desc = [
        ShortField('ears',0),
        ShortField('legs',0),
        ShortField('trunk',0)
    ]
#Inform TCP that ports 9898 are this protocol
bind_layers(TCP, DUMBO, sport=9898, dport=9898)

Now let's use it:

$ scapy
>>> load_contrib("dumbo")
>>> pack1=IP()/TCP(sport=9898, dport=9898)/DUMBO(b'\x00\x02\x00\x04\x00\x01')
>>> pack2=IP()/TCP(sport=9898, dport=9898)/DUMBO(ears=2, legs=4, trunk=1)
>>> pack1
<IP  frag=0 proto=tcp |<TCP  sport=9898 dport=9898 |<DUMBO  ears=2 legs=4 trunk=1 |>>>
>>> pack2
<IP  frag=0 proto=tcp |<TCP  sport=9898 dport=9898 |<DUMBO  ears=2 legs=4 trunk=1 |>>>
>>> pack1[DUMBO].ears
2
>>> pack2[DUMBO].ears
2

Hope this helps somebody who stumbles upon this question.


Versions used: Python v3.8.5; Scapy v2.4.5

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM