Scapy Variable Length Fields

*爱你&永不变心* 提交于 2019-12-11 07:47:03

问题


I am trying to understand the difference between PacketListField and FieldListField. Can someone let me know how to use them when adding new protocols.

I am also not clear about the StrLenField, FieldLenField and PacketLenField. I am trying to craft a BGP Update message so that I can understand how it works. I see this is how the BGPUpdate message has been defined. When I try to craft the BGP packet I am not sure how to pass the values for Withdrawn Routes field and also nlri field. I am also not sure how to pass values for Path Attributes.

>>> pkt=BGPUpdate()
>>> pkt.show()
###[ BGP Update fields ]###
  withdrawn_len= None
  withdrawn= []
  tp_len= None
  \total_path\
  nlri= []
>>>                        

class BGPPathAttribute(Packet):
"the attribute of total path"
    name = "BGP Attribute fields"
    fields_desc = [
    FlagsField("flags", 0x40, 8, ["NA0","NA1","NA2","NA3","Extended-Length","Partial","Transitive","Optional"]), #Extened leght may not work
    ByteEnumField("type", 1, {1:"ORIGIN", 2:"AS_PATH", 3:"NEXT_HOP", 4:"MULTI_EXIT_DISC", 5:"LOCAL_PREF", 6:"ATOMIC_AGGREGATE", 7:"AGGREGATOR"}),
    ByteField("attr_len", None),
    StrLenField("value", "", length_from = lambda p: p.attr_len),
   ]
   def post_build(self, p, pay):
        if self.attr_len is None:
            l = len(p) - 3 # 3 is regular length with no additional options
            p = p[:2] + struct.pack("!B",l)  +p[3:]
        return p+pay
    def extract_padding(self, p):
        """any thing after this packet is extracted is padding"""
        return "",p

class BGPUpdate(Packet):
    """Update the routes WithdrawnRoutes = UnfeasiableRoutes"""
    name = "BGP Update fields"
    fields_desc = [
        ShortField("withdrawn_len", None),
        FieldListField("withdrawn",[], BGPIPField("","0.0.0.0/0"), length_from=lambda p:p.withdrawn_len),
        ShortField("tp_len", None),
        PacketListField("total_path", [], BGPPathAttribute, length_from = lambda p: p.tp_len),
        FieldListField("nlri",[], BGPIPField("","0.0.0.0/0"), length_from=lambda p:p.underlayer.len - 23 - p.tp_len - p.withdrawn_len), # len should be BGPHeader.len
        ]
    def post_build(self,p,pay):
        wl = self.withdrawn_len
        subpacklen = lambda p: len ( str( p ))
        subfieldlen = lambda p: BGPIPField("", "0.0.0.0/0").i2len(self,  p )
        if wl is None:
            wl = sum ( map ( subfieldlen , self.withdrawn))
            p = p[:0]+struct.pack("!H", wl)+p[2:]
        if self.tp_len is None:
            l = sum ( map ( subpacklen , self.total_path))
            p = p[:2+wl]+struct.pack("!H", l)+p[4+wl:]
        return p+pay

回答1:


They just operate on different kinds of objects. see scapy build dissect

PacketListField

describes a list of PacketFields of the same type whereas one PacketField represents a Packet type object put into another packets field. It takes a Packet prototype as the third parameter cls __init__(self, name, default, cls, count_from=None, length_from=None). The constructor of the PacketListField either requires the count_from (number of objects) or lengt_from (bytes) arguments being set in order to know how many bytes to pass to the packetlist or how many object to dissect.(e.g. you can have BGPUpdate as the prototype of a PacketField or PacketListField).

For example:

PacketListField("total_path", [], BGPPathAttribute, length_from = lambda p: p.tp_len),

creats a Field called "total_path", with a default value of an empty list [], and tries to dissect up to length_from bytes of the raw_bytestream as BGPPathAttribute(Packet).

FieldListField

In contrast the FieldListField takes a Field as the prototype and tries to dissect the raw_bytestream as a list of prototype fields __init__(self, name, default, field, length_from=None, count_from=None):

FieldListField("withdrawn",[], BGPIPField("","0.0.0.0/0"), length_from=lambda p:p.withdrawn_len),

StrLenField

DataField that typically holds up to length_from bytes __init__(self, name, default, fld=None, length_from=None):.

FieldLenField

Numeric field that holds the length of another field in the same packet __init__(self, name, default, length_of=None, fmt = "H", count_of=None, adjust=lambda pkt,x:x, fld=None):

class SomePacket(Packet):
    name = "SomePacket"
    fields_desc = [ByteEnumField("type", 0x00, {0x00:"SomeType"}),  
                  FieldLenField("length", None, length_of="data"),          # hold length of data
                  StrLenField("data", "", length_from=lambda x:x.length),   # holds data
                  ]

On dissect, scapy will put the first byte into 'type', the next 2 bytes (default fmt="H" for short into the short integer "length", and up to 'length' bytes into 'data'

On build, scapy will automatically fill 'length' with len(data).

PacketLenField

Is a field that dissects length_from bytes as one prototype Packet __init__(self, name, default, cls, length_from=None):

class AnotherPacket(Packet):
    name = "AnotherPacket"
    fields_desc = [
                  BLenField("length", None, length_of="data"),
                  PacketLenField("data", None, SomePacket, length_from=lambda x:x.length),]
                  ]

On dissect, scapy will put the first Byte into the ByteLengthField 'length' and up to 'length' bytes dissected as 'SomePacket' into 'data'

On build, scapy will automatically fill 'length' with the size of the serialized SomePacket.



来源:https://stackoverflow.com/questions/27163340/scapy-variable-length-fields

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!