使用 dispatch_hook()

Using dispatch_hook()

如何使用 dispatch_hook() link 不同的图层。我有这样的包裹。我只是想知道是否有更好的方法使用 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
>>>  

代码片段:

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)

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

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

让我们举一个真实的例子,来自Scapy代码。 Ether() (Ethernet 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 协议的实现。