Разбор тегов PPPoE с помощью Scapy

Я пытаюсь правильно рассечь пакеты обнаружения PPPoE с помощью Scapy. Вот как Scapy отображает пример пакета PADI:

>>> p = Ether("xffxffxffxffxffxffx08x00'xf3<5x88cx11tx00x00x00x0cx01x01x00x00x01x03x00x04xe0x07x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00")
>>> p.show()
 ###[ Ethernet ]###
  dst= ff:ff:ff:ff:ff:ff
  src= 08:00:27:f3:3c:35
  type= 0x8863
###[ PPP over Ethernet Discovery ]###
     version= 1L
     type= 1L
     code= PADI
     sessionid= 0x0
     len= 12
###[ Raw ]###
        load= 'x01x01x00x00x01x03x00x04xe0x07x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00'

Я хочу проанализировать эту необработанную полезную нагрузку. Эта полезная нагрузка - это просто список тегов PPPoE. Каждый тег состоит из двух байтовых полей кода, двух байтовых полей длины и значения (это длина, заданная предыдущим полем, конечно).

Это моя попытка представить все это:

from scapy.all import *

class PPPoETag(Packet):
    name = "PPPoE Tag"
    fields_desc = [ ShortEnumField('tag_type', None,
                                   {0x0000: 'End-Of-List',
                                    0x0101: 'Service-Name',
                                    0x0102: 'AC-Name',
                                    0x0103: 'Host-Uniq',
                                    0x0104: 'AC-Cookie',
                                    0x0105: 'Vendor-Specific',
                                    0x0110: 'Relay-Session-Id',
                                    0x0201: 'Service-Name-Error',
                                    0x0202: 'AC-System-Error',
                                    0x0203: 'Generic-Error'}),
                    FieldLenField('tag_len', None, length_of='tag_value', fmt='H'),
                    StrLenField('tag_value', '', length_from=lambda pkt:pkt.tag_len)]
    def extract_padding(self, s):
        return '', s

class PPPoED_Tags(Packet):
    name = "PPPoE Tag List"
    fields_desc = [ PacketListField('tag_list', None, PPPoETag) ]

bind_layers(PPPoED, PPPoED_Tags, type=1)

не совсем уверен, что это правильный и лучший способ. Любой советы по улучшению?

2 ответов


в моем собственном коде для аналогичной проблемы низкого уровня (разбор необработанного потока протокола последовательного порта с использованием разделителей информации на основе кода ASCII, таких как SOT, EOT, NULL, BELL и т. д.) Я использовал набор регулярных выражений и стандартных компараторов. Было легко структурировать код для понимания другими, а также довольно быстро использовать предварительно скомпилированные регулярные выражения.

не садясь и кодируя точный python для него, если бы я хотел получить поля без добавления каких-либо не системные зависимости, Id используют что-то вроде этого псевдокода.

    Start Loop over packet content.
        Match any Tag
            Match specific tag type
                set array index based on tag type
            extract length of value
            extract tag value
            store value in array at the index set above
            slice off all the entire now matched & extracted tag.
        Loop until end no more tags match.
    End of loop

Я бы сделал это вместо этого, как и с реализацией Dot11Elt Scapy (плюс он правильно понимает байты после End-Of-List тег отступа):

class PPPoE_Tag(Packet):
    name = "PPPoE Tag"
    fields_desc = [ ShortEnumField('tag_type', None,
                                   {0x0000: 'End-Of-List',
                                    0x0101: 'Service-Name',
                                    0x0102: 'AC-Name',
                                    0x0103: 'Host-Uniq',
                                    0x0104: 'AC-Cookie',
                                    0x0105: 'Vendor-Specific',
                                    0x0110: 'Relay-Session-Id',
                                    0x0201: 'Service-Name-Error',
                                    0x0202: 'AC-System-Error',
                                    0x0203: 'Generic-Error'}),
                    FieldLenField('tag_len', None, length_of='tag_value', fmt='H'),
                    StrLenField('tag_value', '', length_from=lambda pkt:pkt.tag_len)]

bind_layers(PPPoED, PPPoE_Tag, type=1)
bind_layers(PPPoE_Tag, Padding, tag_type=0)
bind_layers(PPPoE_Tag, PPPoE_Tag)