I'm facing a strange problem when I try to load a big iptables set of rules on a LXC container (it's working fine on a virtual machine).
The container is running Linux Debian 12 bookworm.
I'm able to configure the rules and save them with:
/usr/sbin/netfilter-persistent save
However, if I try to load them, I get this error message ( the file is 694 chars length)
$ sudo iptables-restore < /etc/iptables/rules.v4
sendmsg() failed: Message too long
iptables-restore: line 692 failed: Message too long.
What's weird is that if I add the verbose mode it is working fine
$ sudo iptables-restore -v < /etc/iptables/rules.v4 && echo ok
(...)
# Completed on Fri Sep 15 08:57:48 2023
ok
However, if I try to load a big file (33750 lines), I'm always getting the "Message too long" error, in verbose mode or not.
All the loading tests are working fine on a virtual machine (same os).
So I'm wondering if there is a line limit or memory limit somewhere in LXC ? I have tried to play with limits.conf
but it didn't change anything yet.
Any idea ?
EDIT Here are more information to reproduce this behavior:
Kernel version:
Linux xxxxxx 6.2.16-10-pve #1 SMP PREEMPT_DYNAMIC PMX 6.2.16-10 (2023-08-18T11:42Z) x86_64 GNU/Linux
Some packages version (guest container):
ii iptables 1.8.9-2 amd64 administration tools for packet filtering and NAT
ii iptables-persistent 1.0.20 all boot-time loader for netfilter rules, iptables plugin
ii libip4tc2:amd64 1.8.9-2 amd64 netfilter libip4tc library
ii libip6tc2:amd64 1.8.9-2 amd64 netfilter libip6tc library
ii libnetfilter-conntrack3:amd64 1.0.9-3 amd64 Netfilter netlink-conntrack library
ii libxtables12:amd64 1.8.9-2 amd64 netfilter xtables library
ii netfilter-persistent 1.0.20 all boot-time loader for netfilter configuration
host packages:
ii lxc-pve 5.0.2-4 amd64 Linux containers userspace tools
ii lxcfs 5.0.3-pve3 amd64 LXC userspace filesystem
ii pve-lxc-syscalld 1.3.0 amd64 PVE LXC syscall daemon
The little ruleset is :
# Generated by iptables-save v1.8.9 (nf_tables) on Fri Sep 15 08:57:48 2023
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:block_spam2 - [0:0]
:block_spam1 - [0:0]
:block_spam3 - [0:0]
:incoming_net - [0:0]
:sensitive_daemons - [0:0]
-A INPUT -j block_spam1
-A INPUT -j block_spam2
-A INPUT -j block_spam3
-A INPUT -j sensitive_daemons
-A INPUT -j incoming_net
-A INPUT -j sensitive_daemons
-A block_spam2 -s 1.0.1.0/24 -j DROP
-A block_spam2 -s 84.22.192.0/19 -j DROP
-A block_spam1 -s 103.39.156.0/22 -j DROP
-A block_spam1 -s 5.255.220.0/22 -j DROP
-A block_spam3 -s 87.245.234.136/32 -j DROP
-A block_spam3 -s 217.199.224.0/19 -j DROP
[...] 675 lines here : block_spam[1-3] with a uniq ip address [...]
-A incoming_net -d 192.168.1.248/29 -p tcp -m tcp --dport 80 -j ACCEPT
-A incoming_net -d 192.168.1.248/29 -p tcp -m tcp --dport 443 -j ACCEPT
-A incoming_net -d 192.168.1.248/29 -p tcp -j DROP
-A sensitive_daemons -s 192.168.1.248/29 -p tcp -m tcp --dport 22 -j DROP
-A sensitive_daemons -s 192.168.1.0/24 -d 192.168.1.24/32 -p tcp -m tcp --dport 22 -j ACCEPT
-A sensitive_daemons -p tcp -m tcp --dport 22 -j DROP
COMMIT
# Completed on Fri Sep 15 08:57:48 2023
You should consider using ipset to keep host/network addresses for block_spam* rules (and likely merge them into just one set), this would be faster. Or just move to nftables and use built in sets.
If you look up the sendmsg() man page you'll see that it does not actually have a response indicating that a message was too large. It does however return ENOBUFS if there is not enough space in the message buffer - similar, but not the same thing. I suspect that is what is happenning here. And is caused when nothing is emptying the message buffer - socket communications have failed in some way. Why is iptables-restore writing to a socket? Most likly its trying to write log entries (or one large one) but that's mostly guesswork. On most modern Linux 'iptables-restore' is a symlink pointing to one of several implementions of packet filtering tools.
If
iptables-restore -v
works, then you have a workaround, however the most LIKELY reason for having lots of firewall rules is because you are adding rules about individual client addresses directly. This is fine for small numbers of addresses but DOES NOT SCALE. As @Tomek says, usingipset
is a much better solution (this does scale).