2

我在 scapy 中实现 GTPv2。当前定义如下:

class _GTPv2IE_HDR(Packet):
    fields_desc = [ ByteEnumField("type", None, gtpv2_ie_types),
                    ShortField("length", None),
                    BitField("spare", 0, 4),
                    BitField("instance", 0, 4) ]

class GTPv2IE(Packet):
    name = "GTPv2 Information Element"
    fields_desc = [ _GTPv2IE_HDR ]

    def extract_padding(self, p):
        return "", p

    def post_build(self, p, pay):
        if self.length is None:
            l = len(p) - 4
            p = p[:1] + struct.pack("!H", l) + p[3:]
        return p + pay

正如你所见,GTPv2IE 是信息元素的基类(类似于 ipv6 中的 ext 标头)。

这是我定义 IE 的方式:

class GTPv2IE_Recovery(GTPv2IE):
    name = "GTPv2 Recovery IE"
    type = 3
    fields_desc = [ _GTPv2IE_HDR,
                    ByteField("recovery", None) ]
    def post_build(self, p, pay):
        if self.recovery is None:
            rec = random.getrandbits(8)
            p = p[:4] + struct.pack("B", rec)
        return GTPv2IE.post_build(self, p, pay)

现在 GTPv2 数据包本身在 fields_desc 列表的末尾具有以下字段:

PacketListField("info_elements", [], GTPv2IE, length_from=lambda p:p.length-4-(4 if p.flags & 0x8 != 0 else 0)))

问题是当我创建 GTPv2 数据包时:

pkt = IP(dst='2.2.2.2') / UDP() / GTPv2(info_elements=[GTPv2IE_Recovery()])

并调用 show2() 我得到:

###[ IP ]###
  version= 4L
  ihl= 5L
  tos= 0x0
  len= 41
  id= 1
  flags= 
  frag= 0L
  ttl= 64
  proto= udp
  chksum= 0x7465
  src= 1.1.1.90
  dst= 2.2.2.2
  \options\
###[ UDP ]###
     sport= 2123
     dport= 2123
     len= 21
     chksum= 0xc380
###[ GTPv2 ]###
        version= 2L
        flags= 
        type= echo_request
        length= 9
        sequence= 0x3a444d
        spare2= 0
        \info_elements\
         |###[ GTPv2 Information Element ]###
         |  type= recovery
         |  length= 1
         |  spare= 0L
         |  instance= 0L
         |###[ GTPv2 Information Element ]###
         |  type= 90
         |  length= None
         |  spare= 0
         |  instance= 0

show() 方法按预期工作:

###[ IP ]###
  version= 4
  ihl= None
  tos= 0x0
  len= None
  id= 1
  flags= 
  frag= 0
  ttl= 64
  proto= udp
  chksum= None
  src= 1.1.1.90
  dst= 2.2.2.2
  \options\
###[ UDP ]###
     sport= 2123
     dport= 2123
     len= None
     chksum= None
###[ GTPv2 ]###
        version= 2
        flags= 
        type= echo_request
        length= None
        sequence= None
        spare2= 0
        \info_elements\
         |###[ GTPv2 Recovery IE ]###
         |  type= recovery
         |  length= None
         |  spare= 0
         |  instance= 0
         |  recovery= None

谢谢你们的帮助。

亚历克斯。

4

1 回答 1

2

我已经完成了这个工作(以 IPOption 为例):

我向 GTPv2IE 基类添加了 2 个类方法,如下所示:

registered_info_elements = {}
@classmethod
def register_variant(cls):
    cls.registered_info_elements[cls.type.default] = cls
@classmethod
def dispatch_hook(cls, pkt=None, *args, **kargs):
    if pkt:
        t = ord(pkt[0])
        return cls.registered_info_elements.get(t, cls)
    return cls

现在 show2() 按预期工作:

>>> pkt.show2()
###[ IP ]###
  version= 4L
  ihl= 5L
  tos= 0x0
  len= 46
  id= 1
  flags= 
  frag= 0L
  ttl= 64
  proto= udp
  chksum= 0x7607
  src= 1.1.1.90
  dst= 1.1.1.92
  \options\
###[ UDP ]###
     sport= 2123
     dport= 2123
     len= 26
     chksum= 0x52da
###[ GTPv2 ]###
        version= 2L
        flags= 
        type= echo_request
        length= 14
        sequence= 0x8ce2a1
        spare2= 0
        \info_elements\
         |###[ GTPv2 Recovery IE ]###
         |  type= recovery
         |  length= 1
         |  spare= 0L
         |  instance= 0L
         |  recovery= 37
         |###[ GTPv2 Sending Node Features IE ]###
         |  type= node_features
         |  length= 1
         |  spare= 0L
         |  instance= 0L
         |  node_features= PRN+MABR+NTSR
于 2012-12-02T16:50:30.607 回答