I am going through the Scapy example of Adding new protocols and I'm stuck. The aged code as presented on their page throws an error in Python 3 because of string->bytes
conversion, but that's a minor thing. I have written my own implementations of their vlenq2str()
and str2vlenq()
. I call them vlenq2m()
and m2vlenq()
respectively. vlenq2m
converts integer values to bytes (to be used in the packet's raw data), and m2vlenq
converts these bytes from the packet's raw data back to integer (as scapy-internal representation).
My actual problem is that at some point after calling the packet's show2
method, scapy throws a TypeError and I have no clue why.
Here is my minimal example (modernized version of the code from scapy's documentation):
#!/usr/bin/env python
from scapy.fields import Field, StrLenField
from scapy.packet import Packet, ls
from scapy.compat import raw
def vlenq2m(val: int) -> bytes:
s = list()
s.append(val & 0x7F)
val = val >> 7
while val:
s.append(0x80 | (val & 0x7F))
val = val >> 7
s.reverse()
return bytes(s)
def m2vlenq(m: bytes=b"") -> tuple[bytes, int]:
i = l = 0
for n in m:
l = l << 7
l = l + (n & 0x7F)
i = i + 1
if not n & 0x80:
break
return m[i + 1:], l
class VarLenQField(Field):
"""variable length quantities"""
__slots__ = ["fld"]
def __init__(self, name, default, fld):
Field.__init__(self, name, default)
self.fld = fld
def i2m(self, pkt, x):
if x is None:
f = pkt.get_field(self.fld)
x = f.i2len(pkt, pkt.getfieldval(self.fld))
x = vlenq2m(x)
return raw(x)
def m2i(self, pkt, x):
if s is None:
return None, 0
return m2vlenq(x)[1]
def addfield(self, pkt, s, val):
return s + self.i2m(pkt, val)
def getfield(self, pkt, s):
return m2vlenq(s)
class Foo(Packet):
name = "Foo"
fields_desc = [
VarLenQField("len", None, "data"),
StrLenField("data", "", "len"),
]
if __name__ == "__main__":
f = Foo(data="test data")
breakpoint()
f.show2()
Here is the error stack:
$ python -i sominimal.py
Traceback (most recent call last):
File "D:Pythonmlp-monitorsrcmlptcsominimal.py", line 64, in <module>
f.show2()
File "C:ProgramDataAnaconda3envsmmonlibsite-packagesscapypacket.py", line 1289, in show2
return self.__class__(raw(self)).show(dump, indent, lvl, label_lvl)
File "C:ProgramDataAnaconda3envsmmonlibsite-packagesscapyase_classes.py", line 266, in __call__
i.__init__(*args, **kargs)
File "C:ProgramDataAnaconda3envsmmonlibsite-packagesscapypacket.py", line 158, in __init__
self.dissect(_pkt)
File "C:ProgramDataAnaconda3envsmmonlibsite-packagesscapypacket.py", line 875, in dissect
s = self.do_dissect(s)
File "C:ProgramDataAnaconda3envsmmonlibsite-packagesscapypacket.py", line 839, in do_dissect
s, fval = f.getfield(self, s)
File "C:ProgramDataAnaconda3envsmmonlibsite-packagesscapyfields.py", line 1380, in getfield
len_pkt = self.length_from(pkt)
TypeError: 'NoneType' object is not callable
Here is my careful stepping through the debugger up to the point where the error occurs.
$ python -i sominimal.py
> d:pythonmlp-monitorsrcmlptcsominimal.py(65)<module>()
-> f.show2()
(Pdb) s
--Call--
> c:programdataanaconda3envsmmonlibsite-packagesscapypacket.py(1277)show2()
-> def show2(self, dump=False, indent=3, lvl="", label_lvl=""):
(Pdb) n
> c:programdataanaconda3envsmmonlibsite-packagesscapypacket.py(1289)show2()
-> return self.__class__(raw(self)).show(dump, indent, lvl, label_lvl)
(Pdb) s
--Call--
> c:programdataanaconda3envsmmonlibsite-packagesscapycompat.py(50)raw()
-> def raw(x):
(Pdb) n
> c:programdataanaconda3envsmmonlibsite-packagesscapycompat.py(53)raw()
-> return bytes(x)
(Pdb) n
--Return--
> c:programdataanaconda3envsmmonlibsite-packagesscapycompat.py(53)raw()->b'test data'
-> return bytes(x)
(Pdb) n
--Call--
> c:programdataanaconda3envsmmonlibsite-packagesscapyase_classes.py(256)__call__()
-> def __call__(cls, *args, **kargs):
(Pdb) n
> c:programdataanaconda3envsmmonlibsite-packagesscapyase_classes.py(257)__call__()
-> if "dispatch_hook" in cls.__dict__:
(Pdb) n
> c:programdataanaconda3envsmmonlibsite-packagesscapyase_classes.py(265)__call__()
-> i = cls.__new__(cls, cls.__name__, cls.__bases__, cls.__dict__)
(Pdb) s
> c:programdataanaconda3envsmmonlibsite-packagesscapyase_classes.py(266)__call__()
-> i.__init__(*args, **kargs)
(Pdb) type(i)
<class '__main__.Foo'>
(Pdb) type(i.__init__)
<class 'method'>
(Pdb) n
TypeError: 'NoneType' object is not callable
> c:programdataanaconda3envsmmonlibsite-packagesscapyase_classes.py(266)__call__()
-> i.__init__(*args, **kargs)
question from:
https://stackoverflow.com/questions/65846070/stuck-with-varlenqfield-example-from-scapys-documentation