Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
145 views
in Technique[技术] by (71.8m points)

python - Stuck with VarLenQField example from Scapy's documentation

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You're super close. You only missed a small, weird quirk: use a function instead of a string in StrLenField

class Foo(Packet):
    name = "Foo"
    fields_desc = [
        VarLenQField("len", None, "data"),
        StrLenField("data", "", length_from=lambda pkt: pkt.len)
    ]

also wow there's a wrong example on the page that uses a string. I'll have that fixed


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...