If my guess is right, then TL;DR, on router do this:
modprobe nf_nat_tftp
Either the previous jessie kernel (3.16) auto-loaded nf_nat_tftp, either a script did it, but it appears it's not the case anymore.
Anyway, if that didn't help, here's how to easily reproduce the setup in OP's question, allowing to do any kind of test easily on any Linux system (but remember it's only virtualizing network here, nothing else). I hope this can help if it didn't solve.
Needed: root user, ip netns
, atftpd
and atftp
(or equivalent server and client software).
From scratch there's no reason to have a TFTP helper loaded on the router (so here on the testing host).
lsmod | grep _tftp
should return nothing. Let's suppose it returned nothing or returned only nf_conntrack_tftp
from previous rules usage, but not nf_nat_tftp
(just rmmod nf_nat_tftp
if present, to follow the line of thoughts below).
Using these commands to initialize the namespaces:
ip netns del tftp || :
ip netns del router || :
ip netns del client || :
ip netns add client
ip netns add router
ip netns add tftp
ip -n tftp link add eth0 type veth peer netns router name tftp0
ip -n client link add eth0 type veth peer netns router name client0
ip -n router link set client0 up
ip -n router link set tftp0 up
ip -n tftp link set eth0 up
ip -n client link set eth0 up
ip -n tftp addr add dev eth0 1.1.1.1/24
ip -n router addr add dev tftp0 1.1.1.2/24
ip -n router addr add dev client0 2.2.2.2/24
ip -n client addr add dev eth0 2.2.2.1/24
ip -n client route add default via 2.2.2.2
ip netns exec router sh -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
ip netns exec router sh -c 'echo 0 > /proc/sys/net/netfilter/nf_conntrack_helper' # this one might be global on former kernels and might need to be executed without "ip netns exec router"
ip netns exec router iptables -t nat -A POSTROUTING -o tftp0 -j MASQUERADE
ip netns exec router iptables -t raw -A PREROUTING -p udp --dport 69 -j CT --helper tftp
That last command should automatically trigger the loading of nf_conntrack_tftp
:
# uname -r
4.19.7
# lsmod | grep _tftp
nf_conntrack_tftp 16384 1
nf_conntrack 163840 20 xt_conntrack,[...],nf_nat,nf_conntrack_tftp,[...],nf_nat_ipv4,[...]
(Depending on kernel, there might be nf_conntrack_ipv4
instead of nf_conntrack
appearing)
Prepare files:
mkdir -p /tmp/tftp
echo test > /tmp/tftp/test.txt
mkdir -p /tmp/client
Term1:
ip netns exec router tcpdump -e -n -s0 -i any ip
Term2:
ip netns exec tftp atftpd --daemon --no-fork /tmp/tftp
Term3:
ip netns exec client atftp -g -l /tmp/client/test.txt -r test.txt 1.1.1.1
Will display:
timeout: retrying...
^Ctftp: unknown error.
tftp: aborting
Term 1 will show something like:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
17:46:52.958631 In 46:b9:b2:13:ec:51 ethertype IPv4 (0x0800), length 61: 2.2.2.1.36231 > 1.1.1.1.69: 17 RRQ "test.txt" octet
17:46:52.958719 Out 1a:0c:61:3d:f9:00 ethertype IPv4 (0x0800), length 61: 1.1.1.2.36231 > 1.1.1.1.69: 17 RRQ "test.txt" octet
17:46:52.959324 In d6:49:0e:de:b7:27 ethertype IPv4 (0x0800), length 53: 1.1.1.1.38635 > 1.1.1.2.36231: UDP, length 9
17:46:52.959397 Out 1a:0c:61:3d:f9:00 ethertype IPv4 (0x0800), length 81: 1.1.1.2 > 1.1.1.1: ICMP 1.1.1.2 udp port 36231 unreachable, length 45
17:46:57.960151 In 46:b9:b2:13:ec:51 ethertype IPv4 (0x0800), length 61: 2.2.2.1.36231 > 1.1.1.1.69: 17 RRQ "test.txt" octet
17:46:57.960213 Out 1a:0c:61:3d:f9:00 ethertype IPv4 (0x0800), length 61: 1.1.1.2.36231 > 1.1.1.1.69: 17 RRQ "test.txt" octet
17:46:57.960834 In d6:49:0e:de:b7:27 ethertype IPv4 (0x0800), length 53: 1.1.1.1.44001 > 1.1.1.2.36231: UDP, length 9
17:46:57.960932 Out 1a:0c:61:3d:f9:00 ethertype IPv4 (0x0800), length 81: 1.1.1.2 > 1.1.1.1: ICMP 1.1.1.2 udp port 36231 unreachable, length 45
Now after doing (on the router, so here on the testing host) modprobe nf_nat_tftp
, the client command in Term3 will succeed and Term1 will show:
17:54:11.142487 In 46:b9:b2:13:ec:51 ethertype IPv4 (0x0800), length 61: 2.2.2.1.49514 > 1.1.1.1.69: 17 RRQ "test.txt" octet
17:54:11.142556 Out 1a:0c:61:3d:f9:00 ethertype IPv4 (0x0800), length 61: 1.1.1.2.49514 > 1.1.1.1.69: 17 RRQ "test.txt" octet
17:54:11.143090 In d6:49:0e:de:b7:27 ethertype IPv4 (0x0800), length 53: 1.1.1.1.36339 > 1.1.1.2.49514: UDP, length 9
17:54:11.143146 Out 96:c2:ee:fb:cc:07 ethertype IPv4 (0x0800), length 53: 1.1.1.1.36339 > 2.2.2.1.49514: UDP, length 9
17:54:11.143226 In 46:b9:b2:13:ec:51 ethertype IPv4 (0x0800), length 48: 2.2.2.1.49514 > 1.1.1.1.36339: UDP, length 4
17:54:11.143262 Out 1a:0c:61:3d:f9:00 ethertype IPv4 (0x0800), length 48: 1.1.1.2.49514 > 1.1.1.1.36339: UDP, length 4
Looking at conntrack expectations and flows (examples not matching above examples):
without nf_nat_tftp
:
# ip netns exec router sh -c 'conntrack -E & conntrack -E expect'
[NEW] 300 proto=17 src=1.1.1.1 dst=1.1.1.2 sport=0 dport=56876 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=2.2.2.1 master-dst=1.1.1.1 sport=56876 dport=69 class=0 helper=tftp
[NEW] udp 17 30 src=2.2.2.1 dst=1.1.1.1 sport=56876 dport=69 [UNREPLIED] src=1.1.1.1 dst=1.1.1.2 sport=69 dport=56876 helper=tftp
[DESTROY] 299 proto=17 src=1.1.1.1 dst=1.1.1.2 sport=0 dport=56876 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=2.2.2.1 master-dst=1.1.1.1 sport=56876 dport=69 class=0 helper=tftp
[NEW] udp 17 30 src=1.1.1.1 dst=1.1.1.2 sport=58241 dport=56876 [UNREPLIED] src=1.1.1.2 dst=1.1.1.1 sport=56876 dport=58241
^Cconntrack v1.4.4 (conntrack-tools): conntrack v1.4.4 (conntrack-tools): 2 flow events have been shown.
2 expectation events have been shown.
Above, the 2nd flow (last line) doesn't refer to 2.2.2.1
.
With nf_nat_tftp
:
# ip netns exec router sh -c 'conntrack -E & conntrack -E expect'
[NEW] 300 proto=17 src=1.1.1.1 dst=1.1.1.2 sport=0 dport=38115 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=2.2.2.1 master-dst=1.1.1.1 sport=38115 dport=69 class=0 helper=tftp
[NEW] udp 17 30 src=2.2.2.1 dst=1.1.1.1 sport=38115 dport=69 [UNREPLIED] src=1.1.1.1 dst=1.1.1.2 sport=69 dport=38115 helper=tftp
[DESTROY] 299 proto=17 src=1.1.1.1 dst=1.1.1.2 sport=0 dport=38115 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=2.2.2.1 master-dst=1.1.1.1 sport=38115 dport=69 class=0 helper=tftp
[NEW] udp 17 30 src=1.1.1.1 dst=1.1.1.2 sport=35725 dport=38115 [UNREPLIED] src=2.2.2.1 dst=1.1.1.1 sport=38115 dport=35725
[UPDATE] udp 17 30 src=1.1.1.1 dst=1.1.1.2 sport=35725 dport=38115 src=2.2.2.1 dst=1.1.1.1 sport=38115 dport=35725
^Cconntrack v1.4.4 (conntrack-tools): 2 expectation events have been shown.
conntrack v1.4.4 (conntrack-tools): 3 flow events have been shown.
The 2nd flow does refer to 2.2.2.1
.
So it appears that while nf_conntrack_tftp
is good enough to allow the 2nd flow usage for example with -m ctstate --ctstate RELATED
in a firewall, nf_nat_tftp
is still required to also actually alter in the 2nd flow the destination IP (and perhaps sometimes port) when NAT is in use.
AFAIK, at least in recent kernels, nothing will trigger the loading of the companion NAT TFTP helper in addition to the conntrack TFTP helper: it has to be loaded manually.