Hello,
we're using nftables on debian as a firewall and for NAT for ~300
students. I recently found an issue which might or might not be a bug
and I hope this is the right place for sharing it. Any comments would be
greatly appreciated.
We have a public IP-Address & interface, $nat_ip and $dev_ext; all
packets from the local networks ($user, $man) undergo SNAT.
Also, tcp or udp packets with certain destination ports addressed to
$nat_ip should be forwarded to some clients on the local network
('portforwarding'). This is implemented using packet metainformation:
table ip nat {
set forwarded_ports_tcp { type inet_service; }
set forwarded_ports_udp { type inet_service; }
chain portforwards {
meta mark set mark or $mark_portforward
}
chain prerouting {
type nat hook prerouting priority 0;
meta iif $dev_ext tcp dport @forwarded_ports_tcp goto portforwards
meta iif $dev_ext udp dport @forwarded_ports_udp goto portforwards
}
chain outgoing_post {
snat ip saddr map {
$user : $nat_ip,
$man : $nat_ip
}
}
chain postrouting {
type nat hook postrouting priority 0;
meta oif $dev_ext goto outgoing_post
}
}
add rule ip nat portforwards udp dport 7777 dnat 10.10.3.101 : 7777
add element ip nat forwarded_ports_udp { 7777 }
add rule ip nat portforwards tcp dport 7777 dnat 10.10.3.101 : 7777
add element ip nat forwarded_ports_tcp { 7777 }
Furthermore, in the filter table, we have the following chain, which
contains among others the following rules and is traversed by all
packets being forwarded to the local network:
chain in_ext {
# ...
# accept port forward
meta mark and $mark_portforward != 0 return
reject
}
Now, this works fine for tcp, i.e. I can establish a tcp connection to
$nat_ip:7777 and talk to my laptop (10.10.3.101) from the outside.
For udp, only the first packet arrives at the destination. Adding "ip
daddr 10.10.3.101 return" to the chain in_ext solves this problem.
This brings me to the following conclusion:
UDP portforwarding in our setup, using packet marks, fails because only
the first packet of a 'connection' is marked ( 0x0008 = portforward ) as
it hits the NAT prerouting chain.
All following packets don't traverse the NAT chain because they belong
to the same connection (this is expected), but they do not carry the
mark (0x0008), which is surprising (to me), and different from the
behaviour with TCP packets.
Now, my question is: Is this behaviour intended? If so, why is it
different for TCP & UDP?
Best,
Philip