Bug - Module not working for iptables version 1.8.11-2
If iptables version 1.8.11-2 is installed and python 3.12 or python 3.13 is used in Ubuntu or Arch Linux and and the python-iptables module of pip version 1.0.1. is installed, the following code creates the following issue:
import iptc
rule = iptc.Rule()
rule.protocol = "udp"
match = iptc.Match(rule, "udp")
match.dport = "22"
XTablesError Traceback (most recent call last)
Cell In[1], line 5
3 rule.protocol = "udp"
4 match = iptc.Match(rule, "udp")
----> 5 match.sport = "22"
File /usr/local/lib/python3.12/dist-packages/iptc/ip4tc.py:460, in IPTCModule.__setattr__(self, name, value)
458 def __setattr__(self, name, value):
459 if not name.startswith('_') and name not in dir(self):
--> 460 self.parse(name.replace("_", "-"), value)
461 else:
462 object.__setattr__(self, name, value)
File /usr/local/lib/python3.12/dist-packages/iptc/ip4tc.py:332, in IPTCModule.parse(self, parameter, value)
328 argv[i + 1] = args[i]
330 entry = self._rule.entry and ct.pointer(self._rule.entry) or None
--> 332 self._parse(argv, inv, entry)
File /usr/local/lib/python3.12/dist-packages/iptc/ip4tc.py:601, in Match._parse(self, argv, inv, entry)
600 def _parse(self, argv, inv, entry):
--> 601 self._xt.parse_match(argv, inv, self._module, entry,
602 ct.cast(self._ptrptr, ct.POINTER(ct.c_void_p)),
603 self._orig_parse, self._orig_options)
File /usr/local/lib/python3.12/dist-packages/iptc/xtables.py:869, in set_nfproto.<locals>.new(*args)
867 xtobj = args[0]
868 xtables._xtables_set_nfproto(xtobj.proto)
--> 869 return fn(*args)
File /usr/local/lib/python3.12/dist-packages/iptc/xtables.py:1144, in xtables.parse_match(self, argv, invert, m, fw, ptr, x6_parse, x6_options)
1142 entry = self._option_lookup(x6_options, argv[0])
1143 if not entry:
-> 1144 raise XTablesError("%s: no such parameter %s" % (m.name,
1145 argv[0]))
1147 cb = xt_option_call()
1148 cb.entry = ct.pointer(entry)
XTablesError: b'udp': no such parameter b'sport'
There are other things that do not work, such as sport for match udp. I don't know why iptc doesn't work with iptables in version 1.8.11-2 anymore.
I was able to reproduce this with python-iptables 1.2.0 as well.
This is due to ("base", ct.c_uint) field missing from xt_option_entry structure
I've tried to make a patch but I have no idea how to conditionally include this change. Major xtables version haven't been bumped (still v12), actual iptables version is not exported anywhere in iptables libs (xtables, ip4tc) as far as I can tell. Versioning this change is necessary since it obviously segfaults with new field added on iptables<=1.8.10.
Diff for struct itself if anyone needs it:
diff --git a/iptc/xtables.py b/iptc/xtables.py
index 024779c..abdd6f2 100644
--- a/iptc/xtables.py
+++ b/iptc/xtables.py
@@ -108,7 +108,8 @@ class xt_option_entry(ct.Structure):
("ptroff", ct.c_uint),
("size", ct.c_size_t),
("min", ct.c_uint),
- ("max", ct.c_uint)]
+ ("max", ct.c_uint),
+ ("base", ct.c_uint)]
class _U1(ct.Union):
My solution for the moment is to vendor this lib as two submodules (current master and patched) and conditionally build one or the other depending on current iptables version in bash wrapper script:
verlte() {
local sorted
sorted=$(echo -e "$1\n$2" | sort -V)
[[ $1 = "$(head -n1 <<<"$sorted")" ]]
}
iptables_version=$(iptables --version | perl -pe 's/iptables v(\S+).*/$1/')
if verlte "$iptables_version" 1.8.10; then
iptc_path=python-iptables-master
else
iptc_path=python-iptables-bf
fi
iptc_dst=libs/python-iptables
rm "$iptc_dst" >/dev/null || true
ln -sf "$iptc_path" "$iptc_dst"
# then include `libs/python-iptables` in your favorite pkg manager as editable package