2
votes

I'm trying to create a new protocol. The problem is, more fields need to be added to the fields_desc dynamically, but I'm not sure how to achieve this. In the Scapy documentation I read that a layer in Scapy is actually just a list of fields, which one can manipulate, but Scapy does not seem to like the following:

>>> class SomePacket(Packet):
...         
...     name = "SomePacket"
...     fields_desc = [ IntField("Number",0) ]
...             
...     def add_IntField(self, name, value):
...         self.fields_desc.append(IntField(name, value))
... 
>>> packet = SomePacket()
>>> ls(packet)
Number     : IntField             = 0               (0)
>>> packet.add_IntField("X",1)
>>> ls(packet)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/scapy/packet.py", line 1212, in ls
    print "%-10s : %-20s = %-15s (%s)" % (f.name, f.__class__.__name__, repr(getattr(obj,f.name)), repr(f.default))
  File "/usr/lib/python2.7/dist-packages/scapy/packet.py", line 176, in __getattr__
    fld,v = self.getfield_and_val(attr)
  File "/usr/lib/python2.7/dist-packages/scapy/packet.py", line 172, in getfield_and_val
    return self.payload.getfield_and_val(attr)
  File "/usr/lib/python2.7/dist-packages/scapy/packet.py", line 1057, in getfield_and_val
    raise AttributeError(attr)
AttributeError: X
>>> packet = SomePacket()
>>> ls(packet)
Number     : IntField             = 0               (0)
X          : IntField             = 1               (1)

So when I first try to show the packet contents after I added the field it does not work. But if I create the packet again the attribute is suddenly there. What am I doing wrong?

1

1 Answers

2
votes

You shouldn't do it that way. When you create a new SomePacket object, the __init__() function of Packet takes the fields_desc list to initialize a lot of other stuff. Dynamically adding new values to the fields_desc leads to inconsistency, which produces the given error.

One solution would be changing the add_IntField function to a classmethod and add needed fields before creating a new object, like this:

>>> class SomePacket(Packet):
...         
...     name = "SomePacket"
...     fields_desc = [ IntField("Number",0) ]
...     
...     @classmethod
...     def add_IntField(cls, name, value):
...         cls.fields_desc.append(IntField(name, value))

>>> SomePacket.add_IntField('X', 1)
>>> packet = SomePacket()
>>> ls(packet)
Number     : IntField             = 0               (0)
X          : IntField             = 1               (1)