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

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

>>> p = Ether("\xff\xff\xff\xff\xff\xff\x08\x00'\xf3<5\x88c\x11\t\x00\x00\x00\x0c\x01\x01\x00\x00\x01\x03\x00\x04\xe0\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
>>> 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= '\x01\x01\x00\x00\x01\x03\x00\x04\xe0\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

Я хочу разобрать эту полезную нагрузку Raw. Эта полезная нагрузка представляет собой список тегов 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 и т. Д.), Я использовал набор регулярных выражений и стандартных компараторов. Это было легко структурировать в коде для понимания другими, а также довольно быстро с помощью скомпилированных регулярных выражений.

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

    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

Я бы сделал это вместо этого, как и в реализации Scoty Dot11Elt (плюс он правильно понимает байты после 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)
Другие вопросы по тегам