B Keenan
B Keenan

Reputation: 121

Using scapy packetfields

I'm putting together a new protocol layer in scapy. I'm using a packetfield to represent a len-value pair within the protocal. I can get the layer to build a packet. .show() and hexdump() show the packet fields as expected. .show2() however is a different story.

I have something similar too:

class bar(Packet):
    name="Bar Packet"
    fields_desc = [
                    FieldLenField("len", None, length_of="val", fmt="!H"),
                    StrLenField("val", "", length_from=lambda p:p.len)
                  ]

class foo(Packet):
    name="Foo Packet"
    fields_desc = [
                    XByteField("fld1", 0x00),
                    XByteField("fld2", 0x00),
                    PacketField("fld3", '', bar),
                    PacketField("fld4", '', bar),
                    PacketField("fld5", '', bar),
                    XByteField("fld6", 0x00),
                    XByteField("fld7", 0x00)
                  ]

If I construct a packet as such:

p = foo()
p.fld3 = bar(val="one")
p.fld4 = bar(val="two")
p.fld5 = bar(val="three")

p.show() and hexdump(p) work as expected.

However, p.show2() builds the packet just fine but fails to dissect the packet string. Fields 1 - 3 dissect as expected (fld3.len even gets properly calculated). Dissection stop here. The remaining bytes become Raw payload to fld3, and fields 4 - 7 get nothing.

I've attempted to bind_layers(foo, bar) and get the same results. Based on reading here, in the scapy documentation, and in various scapy protocol files, I think something needs to be done in bar.post_dissect(), but I'm not sure what.

How do I get bar to relinquish its remaining raw payload back to foo for further dissection?

Upvotes: 4

Views: 2969

Answers (1)

Pedro
Pedro

Reputation: 46

I have solved it, I've just added an extract_padding function to the Bar class, the Code is like:

class Bar(Packet):
    name = "Bar Packet"
    fields_desc = [
                    FieldLenField("len", None, length_of="val", fmt="!H"),
                    StrLenField("val", 0, length_from=lambda pkt:pkt.len)
                  ]

    def extract_padding(self, p):
        return "", p

class Foo(Packet):
    name = "Foo Packet"
    fields_desc = [
                    XByteField("fld1", 0x00),
                    XByteField("fld2", 0x00),
                    PacketField("fld3", "", Bar),
                    PacketField("fld4", "", Bar),
                    PacketField("fld5", "", Bar),
                    XByteField("fld6", 0x00),
                    XByteField("fld7", 0x00)
                  ]

If you review the Scapy documentation, it tells:

  • extract_padding() is an important function which should be called by every layer containing its own size, so that it can tell apart in the payload what is really related to this layer and what will be considered as additional padding bytes.

I run this code and this is the result:

###[ Foo Packet ]###
  fld1      = 0x0
  fld2      = 0x0
  \fld3      \
   |###[ Bar Packet ]###
   |  len       = 3
   |  val       = 'one'
  \fld4      \
   |###[ Bar Packet ]###
   |  len       = 3
   |  val       = 'two'
  \fld5      \
   |###[ Bar Packet ]###
   |  len       = 5
   |  val       = 'three'
  fld6      = 0x0
  fld7      = 0x0

Process finished with exit code 0

Upvotes: 3

Related Questions