scapy编写自定义协议
编写自定义格式的步骤如下
- 首先先定义一个类,把所有的字段标注下来,每个字段占用几个字节或者几个bit
例子:我们这里需要构造一个trill协议的数据包,但是scapy没有对这个的支持,查看官方的协议手册 https://www.rfc-editor.org/rfc/rfc6325.html#section-3.8
class TRILL(Packet):
name = "TRILL"
fields_desc = [
# TRILL 版本号(2位)
BitField("version", 0, 2),
# 保留字段(2位)
BitField("reserved", 0, 2),
# 多播标志(1位)
BitField("multicast", 0, 1),
# 操作长度(Op-Length,5位)
BitField("op_length", 0, 5),
# 跳数限制(6位)
BitField("hop_count", 0, 6),
# 入口 RBridge 昵称(16位)
ShortField("ingress_nick", None),
# 出口 RBridge 昵称(16位)
ShortField("egress_nick", None),
# TRILL 头部选项(可变长度)
# 这里仅作为示例,实际中可能需要根据 TRILL 规范定义具体的选项字段
# ByteField("options", 0),
]
然后上面缺少一个可变字段option,接下来需要自定义field成帧函数,实现可变字段的功能,
上面的BitField,ShortField,ByteField都是成帧函数
class OptionField(Field):
def __init__(self, name, default):
Field.__init__(self,name, default)
def addfield(self,pkt,s,val):
if pkt.op_length:
if type(val)==bytes:
return s+val+bytes(pkt.op_length*4-len(val))
else:
return s+val.encode()+bytes(pkt.op_length*4-len(val))
else:
return s
我们一般只要写add就可以组包,getField是解析的时候用的,如果你不要解析就不用
其中关于参数pkt,s,val的说明
- pkt是指当前的数据包是一个对象,
- s 是数据包的bytes真实数据,
- val是传进来的参数的值,传进来是什么类型就是什么 类型,
然后修改trill协议类,增加一个option字段,option字段受op_length控制
class TRILL(Packet):
name = "TRILL"
fields_desc = [
# TRILL 版本号(2位)
BitField("version", 0, 2),
# 保留字段(2位)
BitField("reserved", 0, 2),
# 多播标志(1位)
BitField("multicast", 0, 1),
# 操作长度(Op-Length,5位)
BitField("op_length", 0, 5),
# 跳数限制(6位)
BitField("hop_count", 0, 6),
# 入口 RBridge 昵称(16位)
ShortField("ingress_nick", None),
# 出口 RBridge 昵称(16位)
ShortField("egress_nick", None),
# TRILL 头部选项(可变长度)
# 这里仅作为示例,实际中可能需要根据 TRILL 规范定义具体的选项字段
OptionField("options", None)
]