使用 Scapy 解析 PPPoE 标签
我正在尝试使用 Scapy 正确解析 PPPoE Discovery 数据包。以下是 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'
我想解析该原始有效负载。该有效负载只是一个 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)
不太确定这是否是正确和最好的方式。有什么改进建议吗?
I am trying to correctly dissect PPPoE Discovery packets with Scapy. Here's how Scapy displays example PADI packet:
>>> 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'
I want to parse that Raw payload. This payload is just a list PPPoE tags. Each tags consists of two byte code field, two byte length field and a value (it's length given by previous field, of course).
This is my attempt at representing all this:
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)
Not quite sure if it's the right and best way. Any advice on improving?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我会这样做,就像 Scapy 的 Dot11Elt 实现一样(加上它正确地将
End-Of-List
标记后的字节理解为 Padding):I would do this instead, just like with Scapy's Dot11Elt implementation (plus it correctly understands bytes after
End-Of-List
tag as Padding):在我自己的代码中,针对类似的低级问题(使用基于 ASCII 控制代码的信息分隔符(例如 SOT、EOT、NULL、BELL 等)解析串行端口协议的原始流),我使用了一组正则表达式和标准比较器。它很容易在代码中构建以便其他人理解,并且使用预编译的正则表达式也非常快。
无需坐下来为其编码出确切的Python,如果我想在不添加任何非系统依赖项的情况下获取字段,我会使用大致类似于此伪代码的东西。
In my own code for a similarly low level problem (parsing the raw stream of serial port protocol using ASCII control code based information delimiters such as SOT, EOT, NULL, BELL, etc) I used a set of regexs and standard comparators. It was easy to structure in the code for comprehension by others, and also quite quick using the precompiled regexs.
Without sitting down & coding out the exact python for it, If i wanted to get the fields out without adding any non system dependencies, Id use something roughly like this pseudocode.