JeroenvIS / pynetfilter_conntrack

Python binding of libnetfilter_conntrack
GNU General Public License v2.0
0 stars 0 forks source link

expect.py example gives RunTimeError in conntrack_entry.py #1

Open JeroenvIS opened 1 year ago

JeroenvIS commented 1 year ago

The expect.py example code gives a RunTimeError in conntrack_entry.py:

(venv) root@sflow:/home/jeroen/code/pynetfilter_conntrack# ./expect.py
Traceback (most recent call last):
  File "/home/jeroen/code/pynetfilter_conntrack/./expect.py", line 97, in <module>
    main()
  File "/home/jeroen/code/pynetfilter_conntrack/./expect.py", line 92, in main
    create_conntrack()
  File "/home/jeroen/code/pynetfilter_conntrack/./expect.py", line 31, in create_conntrack
    master.orig_l3proto = AF_INET
  File "/home/jeroen/code/pynetfilter_conntrack/pynetfilter_conntrack/conntrack_entry.py", line 93, in __setattr__
    self._setAttr(name, value)
  File "/home/jeroen/code/pynetfilter_conntrack/pynetfilter_conntrack/conntrack_entry.py", line 81, in _setAttr
    setter(self._handle, attrid, value)
RuntimeError: ffi_prep_cif_var failed

Environment:

(venv) root@sflow:/home/jeroen/code/pynetfilter_conntrack# uname -a
Linux sflow 5.15.0-70-generic #77-Ubuntu SMP Tue Mar 21 14:02:37 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

(venv) root@sflow:/home/jeroen/code/pynetfilter_conntrack# python -V
Python 3.10.6

(venv) root@sflow:/home/jeroen/code/pynetfilter_conntrack# pip list
Package               Version Editable project location
--------------------- ------- ---------------------------------------
IPy                   1.1
pip                   22.0.2
pynetfilter-conntrack 0.7     /home/jeroen/code/pynetfilter_conntrack
setuptools            59.6.0
JeroenvIS commented 1 year ago

The ffi_prep_cif_var probably originates somewhere within ctypes. Exact error unclear, not sure how to proceed in debugging. Added some print statements in #6b22a36 and tried to use more strict ctype casts on arguments, but that doesn't help.

Output with extra print statements from #6b22a36:

(venv) root@sflow:/home/jeroen/code/pynetfilter_conntrack# ./expect.py
__setattr__: orig_l3proto, 2, 2, (15, 8)
_setAttr: name orig_l3proto, attrid 15, value 2, handle <pynetfilter_conntrack.func.LP_nf_conntrack object at 0x7f6663d97d40>
Traceback (most recent call last):
  File "/home/jeroen/code/pynetfilter_conntrack/./expect.py", line 97, in <module>
    main()
  File "/home/jeroen/code/pynetfilter_conntrack/./expect.py", line 92, in main
    create_conntrack()
  File "/home/jeroen/code/pynetfilter_conntrack/./expect.py", line 31, in create_conntrack
    master.orig_l3proto = AF_INET
  File "/home/jeroen/code/pynetfilter_conntrack/pynetfilter_conntrack/conntrack_entry.py", line 95, in __setattr__
    self._setAttr(name, value)
  File "/home/jeroen/code/pynetfilter_conntrack/pynetfilter_conntrack/conntrack_entry.py", line 82, in _setAttr
    setter(self._handle, attrid, value)
RuntimeError: ffi_prep_cif_var failed
JeroenvIS commented 1 year ago

The issue occurs when setting the address family. If that is skipped by commenting out https://github.com/JeroenvIS/pynetfilter_conntrack/blob/6b22a36959f78d9b49b6a5b738f0257db23ecb68/expect.py#L31 , setting the IP addresses succeeds and the RuntimeError happens when we try to set the L4 protocol:

(venv) root@sflow:/home/jeroen/code/pynetfilter_conntrack# ./expect.py
__setattr__: orig_ipv4_src, 172.16.127.201, 172.16.127.201, (0, 32)
_setAttr: name orig_ipv4_src, attrid 0, value 3380547756, handle <pynetfilter_conntrack.func.LP_nf_conntrack object at 0x7f0837673d40>
__setattr__: orig_ipv4_dst, 204.152.191.36, 204.152.191.36, (1, 32)
_setAttr: name orig_ipv4_dst, attrid 1, value 616536268, handle <pynetfilter_conntrack.func.LP_nf_conntrack object at 0x7f0837673d40>
__setattr__: orig_l4proto, 6, 6, (17, 8)
_setAttr: name orig_l4proto, attrid 17, value 6, handle <pynetfilter_conntrack.func.LP_nf_conntrack object at 0x7f0837673d40>
Traceback (most recent call last):
  File "/home/jeroen/code/pynetfilter_conntrack/./expect.py", line 97, in <module>
    main()
  File "/home/jeroen/code/pynetfilter_conntrack/./expect.py", line 92, in main
    create_conntrack()
  File "/home/jeroen/code/pynetfilter_conntrack/./expect.py", line 34, in create_conntrack
    master.orig_l4proto = IPPROTO_TCP
  File "/home/jeroen/code/pynetfilter_conntrack/pynetfilter_conntrack/conntrack_entry.py", line 95, in __setattr__
    self._setAttr(name, value)
  File "/home/jeroen/code/pynetfilter_conntrack/pynetfilter_conntrack/conntrack_entry.py", line 82, in _setAttr
    setter(self._handle, attrid, value)
RuntimeError: ffi_prep_cif_var failed

That tells us:

Perhaps this change in libffi-3.4.2 (https://github.com/libffi/libffi/releases/tag/v3.4.2) is relevant:

Reject float and small integer argument in ffi_prep_cif_var(). Callers must promote these types themselves.

ylebre commented 1 year ago

I did a bit of digging around to see what is going on, and found this page: https://netfilter.org/projects/libnetfilter_conntrack/doxygen/html/group__ct.html

From what I can see, there is a function: nfct_set_attr_u8 (struct nf_conntrack *ct, const enum nf_conntrack_attr type, uint8_t value)

Checking the python code, it looks like the setter only has two arguments (instead of the three I've found here).

JeroenvIS commented 1 year ago

As discussed offline with @ylebre : setting IP protocol and L4 protocol succeeds when using nfct_set_attr_u32 for 8-bit attributes. Then the 16-bit items fail, and there the same fix helps. With the two simple changes in #a6022a5, all the _setAttr calls resulting from creating the "master" conntrack entry succeed,

Now the expect.py fails at the last step of creating the Expect entry, but that's a different issue.