Reputation: 324
I am trying to add a field to a packet with a type that is dependant on another field value. One of these "types" is a var length string, with an additional "len" attribute if applicable.
Consider the following example:
from scapy.all import *
class TestPacket(Packet):
fields_desc=[
ShortField("index", 0),
ByteEnumField("type", 0 , { 1: "String", 2: "Integer" }),
ConditionalField(FieldLenField("len", None, length_of="data"), lambda x: x.type==1),
ConditionalField(StrLenField("data", "", length_from=lambda pkt:pkt.len), lambda x: x.type==7 or x.type==11),
ConditionalField(IntField("data", 1), lambda pkt: pkt.type==2)]
p = TestPacket(index=12, type=1, data="My Sample String")
p.show2()
p = TestPacket(index=13, type=2, data=5)
p.show2()
The problem is that the "len" is always set to 4 (the length of the IntField, as it is the last "data" conditional field).
What is the best way to achieve this functionality? Conditional fields with different names? Storing the raw bytes as a var length string, no matter the type?
Upvotes: 0
Views: 1455
Reputation: 5431
You can use MultipleTypeField. See https://scapy.readthedocs.io/en/latest/api/scapy.fields.html#scapy.fields.MultipleTypeField
For instance:
class DebugPacket(Packet):
fields_desc = [
ByteEnumField("atyp", 0x1, {0x1: "IPv4", 0x3: "DNS", 0x4: "IPv6"}),
MultipleTypeField(
[
# IPv4
(IPField("addr", "0.0.0.0"), lambda pkt: pkt.atyp == 0x1),
# DNS
(DNSStrField("addr", ""), lambda pkt: pkt.atyp == 0x3),
# IPv6
(IP6Field("addr", "::"), lambda pkt: pkt.atyp == 0x4),
],
StrField("addr", "") # By default
),
]
It allows you to have the same field having multiple types depending on a condition
Upvotes: 1