I am trying to dissect packets, which encapsulate another packet-like structure, called "tags". The structure looks like this
+---------+
|Ether |
+---------+
|IP | a tag
+---------+
|UDP | +------------+
+---------+ |tagNumber |
|BVLC | +------------+
+---------+ |tagClass |
|NPDU | +------------+
+---------+ +-+ |LVT field |
|APDU | | +------------+
| +------+--+ | | |
| |Tag 1 | <------+ | data |
| +---------+ | |
| |Tag 2 | +------------+
| +---------+
| |Tag n |
+------------+
For this I created a class derived from the existing PacketListField
, which looks like this:
class TagListField(PacketListField):
def __init__(self):
PacketListField.__init__(
self,
"tags",
[],
guessBACNetTagClass,
The referenced guessBACNetTagClass
is a function which returns the correct class needed to dissect the tag.
BACNetTagClasses = {
0x2: "BACNetTag_U_int",
0xC: "BACNetTag_Object_Identifier"
}
def guessBACNetTagClass(packet, **kargs):
""" Returns the correct BACNetTag Class needed to dissect
the current tag
@type packet: binary string
@param packet: the current packet
@type cls: class
@param cls: the correct class for dissection
"""
tagByteBinary = "{0:b}".format(int(struct.unpack("!B", packet[0])[0]))
tagNumber = int(tagByteBinary[0:4],2)
clsName = BACNetTagClasses.get(tagNumber)
cls = globals()[clsName]
return cls(packet, **kargs)
Currently there are, as you can see from the BACNetTagClasses
dictionary from above, two of these classes.
class BACNetTag_Object_Identifier(Packet):
name = "BACNetTag_Object_Identifier"
fields_desc =[
# fields
]
class BACNetTag_U_int(Packet):
name = "BACNetTag_U_int"
fields_desc = [
# fields
]
In the encapsulating layer, called APDU
I added the TagListField
just like another field.
class APDU(Packet):
name = "APDU"
fields_desc = [
# Some other fields
TagListField()
]
A packet, which I am currently trying to dissect, contains multiple tags. The first one (of the type BACNetTag_Object_Identifier
) can be correctly dissected, but the remaining tags are just listed as raw payload.
[<Ether |<UDP |<BVLC |<NPDU |<APDU
pduType=UNCONFIRMED_SERVICE_REQUEST reserved=None serviceChoice=I_AM
tags=[<BACNetTag_Object_Identifier tagNumber=BACNET_OBJECT_IDENTIFIER
tagClass=APPLICATION lengthValueType=4L objectType=DEVICE
instanceNumber=640899L |<Raw load='"\x01\xe0\x91\x00!\xde'
|>>] |>>>>>>]
Is there something wrong with my implementation of PacketListField
? As I understand, the field should try to dissect the remaining tags until no more Bytes are left.
UPDATE:
Using .show()
reveals a bit more about the packets structure
###[ APDU ]###
pduType = UNCONFIRMED_SERVICE_REQUEST
reserved = None
serviceChoice= I_AM
\tags \
|###[ BACNetTag_Object_Identifier ]###
| tagNumber = BACNET_OBJECT_IDENTIFIER
| tagClass = APPLICATION
| lengthValueType= 4L
| objectType= DEVICE
| instanceNumber= 640899L
|###[ Raw ]###
| load = '"\x01\xe0\x91\x00!\xde'
Scapy just appends the remaining Bytes as a Raw
layer to the existing tags
field. That's interesting, but I still don't know why it is doing so.