iptables – Why does the Netfile conntrack TFTP helper only wait for a response from the server from port 69, in violation of RFC?

The problem

I have a TFTP server (Machine & # 39; S & # 39;) and a TFTP client (Machine & # 39; C & # 39; C & # 39; C) in different subnets. They are connected through a router (Machine & # 39; R & # 39;). The 3 machines are Debian 9 / Stretch. The router is running iptables and is configured to mask connections from the client's network to the server's network. I have configured iptables to use the TFTP helper from Netfilter for the tftp connections that go to the TFTP server.

The problem I have is that the TFTP helper sets an expectation for the return tftp connection (as expected) but specifies sport = 69 from the server. This is not how the TFTP communication is supposed to work in accordance with RFC1350. The server must choose a port of random origin for its communication and direct it to the port that the client originally used as a source port (although …).

The result is that the NAT router connects from the client to the server, establishes a translation rule for the return connection, and happily waits for a return packet from the server with the source port = 69 that never arrives.

Startup

The directions are made for clarity:

Iptables in the router have the following rules. All tables have a default ACCEPT policy:

======== RAW Table ========
PREROUTING of the chain (policy ACCEPT 464K packets, 432M bytes)
pkts bytes target prot choose in the destination of origin
59 2504 CT udp - * * 0.0.0.0/0 0.0.0.0/0 udp dpt: 69 CT helper tftp

DEPART chain (policy ACCEPTS 280K packs, 36M bytes)
pkts bytes target prot choose in the destination of origin

======== NAT table ========
POSTROUTING string (ACCEPT policy 398 packets, 40794 bytes)
pkts bytes target prot choose in the destination of origin
5678 349K MASQUERADE all - * enp1s0 0.0.0.0/0 0.0.0.0/0

Once the TFTP client is trying to connect, conntrack -L shows the following:

udp 17 28 src = 2.2.2.1 dst = 1.1.1.1 sport = 45084 dport = 69 [UNREPLIED] src = 1.1.1.1 dst = 1.1.1.2 sport = 69 dport = 45084 mark = 0 helper = tftp use = 1

conntrack -L WAIT:

298 proto = 17 src = 1.1.1.1 dst = 1.1.1.2 sport = 0 dport = 45084 mask-src = 255.255.255.255 mask-dst = 255.255.255.255 sport = 0 dport = 65535 master-src = 2.2.2.1 master-dst = 1.1.1.1 sport = 45084 dport = 69 class = 0 helper = tftp

As you can see, the TFTP help rule works correctly and is activated once the client tries to connect. As you can also see, the expectation created in the EXPECT table has the port of origin 0, which I suppose means "any port". But, as you will see, the connection is only routed back to the client if the port of origin of the server is port 69! Why is this? This is not the correct behavior for what I can say.

I will not mess up this publication if I can avoid it, but what is shown in tcpdump udp and host 1.1.1.1 confirm exactly what iptables and conntrack are showing me.

It works

I run a netcat listener on the TFTP server on port 69 with nc -l -u -p 69 and then I connect to it from the TFTP client with nc -u 1.1.1.1 69. Once I send some data from the client to the server, the TFTP assistant configures an expectation, just as before. However, when I send some data from the server, that's it! the [UNREPLIED] It disappears from the entry of the connection table and the client receives the data I sent. The connection is working correctly. I am sure that if I go a little further, I can even imitate the full TFTP transaction using netcat Y dd.

The traffic looks like:

08: 19: 28.285749 IP 1.1.1.2.60704> 1.1.1.1.tftp: 10 tftp- # 25967
08: 19: 31.676846 IP 1.1.1.1.tftp> 1.1.1.2.60704: 2 tftp- # 25610

I made this same configuration in various Debian 8 / Jessie configurations about a year ago and the TFTP helper worked as expected and I never had any problems. Can someone help me find out if I'm doing something wrong? Is it the problem with the TFTP helper? Why would he have changed his Debian 8 / Jessie behavior?