使用dispatch_hook()

时间:2015-01-19 04:38:19

标签: python scapy

如何使用dispatch_hook()链接不同的图层。我有这样的包。我只是想知道是否有更好的方法使用dispatch_hook()。

这是我制作包的方式:

>>>> pkt=PCEPCommonHeader(Type=6)/PCEPErrorMsg(error_objects=[PCEPErrorObject()])

>>> pkt.show()
###[ PCEP common header ]###
  Version= 1
  Flags= 0
  Type= PCEPErrorMsg
  Length= None
###[ PCEPErrorMsg ]###
     \error_objects\
      |###[ PCEP-ERROR OBJECT ]###
      |  \common_object_header\
      |   |###[ PCEP Common Object Header ]###
      |   |  oclass= PCEP-ERROR
      |   |  oType= 1
      |   |  resflags=
      |   |  pflag=
      |   |  iflag=
      |   |  obLength= 4
      |  Reserved= 0
      |  flags= 0
      |  ET= 0
      |  EV= 0
>>>  

Code Snip:

connection, pcc_address = pce.accept()
pcc_client=StreamSocket(connection,basecls=PCEPCommonHeader)

_PCEP_types      = {6:"PCEPErrorMsg"}
_object_class    = {13: "PCEP-ERROR"}
_PCEP_ERR_types  = {3: "Unknown Object"}
_PCEP_ERR_values = {3: {1: "Unrecognized object class",
                        2: "Unrecognized object Type"}}
class PCEPCommonHeader(Packet):
  """This is the common header for all PCEP packets"""
  name = "PCEP common header"
  #Common Header Length is 4 bytes
  fields_desc = [BitField("Version",1,3),
                   BitField("Flags",0,5),
                   ByteEnumField("Type", 2, _PCEP_types),
                   ShortField("Length", None)]

class PCEPCommonObjectHeader(Packet):
    """Common Header for the PCEP Objects"""
    #Common ObjectHeader Length is 4 Bytes
    name = "PCEP Common Object Header"


    fields_desc = [ByteEnumField("oclass",0, _object_class),
                       BitField("oType",0,4),
                       FlagsField("resflags", 0x0, 2, "Res"),
                       FlagsField("pflag", 0x0, 1, "P"),
                       FlagsField("iflag", 0x0, 1, "I"),
                       ShortField("obLength", 4)]

class PCEPErrorObject(Packet):

  '''PCEP-ERROR Object to notify error conditions in a PCEP session'''

  name = 'PCEP-ERROR OBJECT'

  common_object = PCEPCommonObjectHeader(oclass=13,oType=1)
  fields_desc = [PacketField("common_object_header",common_object,PCEPCommonObjectHeader),
                  ByteField("Reserved",0),
                  ByteField("flags",0),
                  ByteEnumField("ET", 0, _PCEP_ERR_types),
                  MultiEnumField("EV", 0, _PCEP_ERR_values,depends_on=lambda pkt: pkt.ET,fmt="B")]

class PCEPErrorMsg(Packet):

  fields_desc = [PacketListField("error_objects",None,PCEPErrorObject)]


bind_layers( PCEPCommonHeader, PCEPErrorMsg, Type=6)

1 个答案:

答案 0 :(得分:1)

.dispatch_hook()背后的想法是拥有一个主类,让我们称之为Protocol继承(直接或不是)来自Packet,并拥有派生类(直接继承)或不,来自ProtocolPacket);假设我们有Protocol1Protocol2

当您(或Scapy)通过调用.dispatch_hook()实例化该类时,将调用Protocol()方法。它使用与传递给Protocol()完全相同的参数调用,并返回将要(真正)使用的类。

让我们从Scapy代码中得到一个真实的例子。 Ether()(以太网v2)和Dot3()()是非常相似的第二层协议:两者都以六字节目标地址开头,后跟六字节源地址。 Ether()接下来的两个字节是有效载荷的类型,而Dot3()接下来的两个字节是数据包大小。由于数据包不能超过1500字节,并且以太网类型不能小于1500(1536是最小的精确值)。​​

来自Scapy代码(文件scapy/layers/l2.py):

class Ether(Packet):
    [...]
    @classmethod
    def dispatch_hook(cls, _pkt=None, *args, **kargs):
        if _pkt and len(_pkt) >= 14:
            if struct.unpack("!H", _pkt[12:14])[0] <= 1500:
                return Dot3
        return cls

class Dot3(Packet):
    [...]
    @classmethod
    def dispatch_hook(cls, _pkt=None, *args, **kargs):
        if _pkt and len(_pkt) >= 14:
            if struct.unpack("!H", _pkt[12:14])[0] > 1500:
                return Ether
        return cls

如果需要,可以找到一个更复杂,更完整的示例in TorPylle,即Scapy中TOR协议的实现。