It seems it is indeed possible to use nftables for a stateless NAT limited to NTP packets.
I did some tests with iptables and nftables to get a better idea of the NAT and connection tracking impact. I used an older consumer-grade router TP-LINK WDR4900 v1 running OpenWrt 19.07, which was connected between an NTP server and a host running ntpperf to simulate a large number of clients sending requests at a specified rate.
First, I optimized the router configuration a bit:
- Increased
nf_conntrack_buckets
to be closer tonf_conntrack_max
, which made the hashtable chains shorter and improved the performance with connection tracking by about 10% - Disabled the ethernet+WLAN bridge, which made a 12% improvement
- Switched to a manual firewall configuration and moved the NTP-specific firewall rules to the chain beginnings, which made a 20% improvement
Then I compared the performance in several different iptables and nftables configurations:
- iptables with stateful forwarding (no NAT) - 16 kpps
- iptables with stateless forwarding (no NAT) - 36 kpps
- iptables with stateful NAT - 15.5 kpps
- nftables with stateful NAT - 16 kpps
- nftables with stateless NAT - 30 kpps
- no firewall - 47 kpps
So, it seems switching to nftables can improve the performance by a factor of two and avoid wasting conntrack memory at the same time. It might be worth the hassle if you want to increase your pool speed, but donât want to switch to a more powerful router. At least on OpenWrt it wasnât too bad. It provides nft kernel modules in the repository.
Here is the raw table I used if anyone is looking for an example:
table ip raw {
chain prerouting {
type filter hook prerouting priority -300;
iif eth0.2 udp dport 123 ip daddr 192.168.123.1 ip daddr set 192.168.123.99 notrack
iif eth0.1 udp sport 123 ip saddr 192.168.123.99 notrack
}
chain postrouting {
type filter hook postrouting priority -300;
oif eth0.2 udp sport 123 ip saddr 192.168.123.99 ip saddr set 192.168.123.1
}
}