Разбор тегов 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)