Scapy 可变长度字段 [英] Scapy Variable Length Fields

查看:76
本文介绍了Scapy 可变长度字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解 PacketListField 和 FieldListField 之间的区别.有人可以告诉我在添加新协议时如何使用它们.

我也不清楚 StrLenField、FieldLenField 和 PacketLenField.我正在尝试制作 BGP 更新消息,以便了解它是如何工作的.我看到这是如何定义 BGPUpdate 消息的.当我尝试制作 BGP 数据包时,我不确定如何传递 Withdrawn Routes 字段和 nlri 字段的值.我也不知道如何传递路径属性的值.

<预><代码>>>>pkt=BGPUpdate()>>>pkt.show()###[ BGP 更新字段]###撤回_len=无撤回= []tp_len= 无\总路径\nlri= []>>>类 BGPPathAttribute(Packet):总路径属性"name = "BGP 属性字段"fields_desc = [FlagsField("flags", 0x40, 8, ["NA0","NA1","NA2","NA3","Extended-Length","Partial","Transitive","Optional"]), #Extened leght可能不起作用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", 无),StrLenField("value", "", length_from = lambda p: p.attr_len),]def post_build(self, p, pay):如果 self.attr_len 是 None:l = len(p) - 3 # 3 是没有附加选项的常规长度p = p[:2] + struct.pack("!B",l) +p[3:]回报 p+paydef extract_padding(self, p):"""这个包被解压后的任何东西都是填充"""返回 "",p类 BGPUpdate(数据包):"""更新路由 WithdrawnRoutes = UnfeasableRoutes"""name = "BGP 更新字段"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 应该是BGPHeader.len]def post_build(self,p,pay):wl = self.withdrawn_lensubpacklen = lambda p: len ( str( p ))subfieldlen = lambda p: BGPIPField("", "0.0.0.0/0").i2len(self, p)如果 wl 为 None:wl = sum ( map ( subfieldlen , self.withdrawn))p = p[:0]+struct.pack("!H", wl)+p[2:]如果 self.tp_len 是 None:l = sum ( map ( subpacklen , self.total_path))p = p[:2+wl]+struct.pack("!H", l)+p[4+wl:]回报 p+pay

解决方案

它们只是对不同种类的对象进行操作.参见 scapy 构建剖析

数据包列表字段

描述了相同类型的 PacketFields 列表,而一个 PacketField 表示放入另一个数据包字段的 Packet 类型对象.它接受一个数据包原型作为第三个参数 cls __init__(self, name, default, cls, count_from=None, length_from=None).PacketListField 的构造函数需要设置 count_from(对象数量)或 lengt_from(字节)参数,以便知道要传递给数据包列表的字节数或要剖析的对象数.(例如,您可以拥有 BGPUpdate 作为 PacketField 或 PacketListField 的原型).

例如:

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

创建一个名为total_path"的字段,默认值为空列表[],并尝试将raw_bytestream的length_from字节解析为BGPPathAttribute(Packet).

FieldListField

相比之下,FieldListField 以 Field 作为原型,并尝试将 raw_bytestream 剖析为原型字段列表 __init__(self, name, default, field, length_from=None, count_from=无):

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

StrLenField

通常最多容纳 length_from 字节的数据字段 __init__(self, name, default, fld=None, length_from=None):.

FieldLenField

保存同一数据包中另一个字段长度的数值字段 __init__(self, name, default, length_of=None, fmt = "H", count_of=None, adjust=lambda pkt,x:x,fld=无):

class SomePacket(Packet):name = "SomePacket"fields_desc = [ByteEnumField("type", 0x00, {0x00:"SomeType"}),FieldLenField("length", None, length_of="data"), # 保存数据长度StrLenField("data", "", length_from=lambda x:x.length), # 保存数据]

在解析时,scapy 会将第一个字节放入 'type',接下来的 2 个字节(默认 fmt="H" 为短整数length",最多为 'length'字节到'数据'

在构建时,scapy 会自动用 len(data) 填充 'length'.

PacketLenField

是一个将 length_from 字节解析为一个原型 Packet __init__(self, name, default, cls, length_from=None) 的字段:

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

在剖析时,scapy 会将第一个字节放入 ByteLengthField 'length' 并将最多 'length' 个字节作为 'SomePacket' 剖析为 'data'

在构建时,scapy 会自动用序列化 SomePacket 的大小填充 'length'.

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

解决方案

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.

这篇关于Scapy 可变长度字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆