System Administration & Network Administration
ssh iptables virtualization nat virtualbox
Updated Mon, 12 Sep 2022 10:15:00 GMT

Why SSH still works after applying SNAT and DNAT rules to forward ip (on the SSH server)?


I have the following situation:

  • I have a Ubuntu Server VM with a bridged network adapter (let's say its ip is 192.168.100.3) that exposes an ssh server on port 22,
  • the VM is hosted on a Ubuntu Desktop,
  • when I connect over ssh with my VM (from the host) and append some rules in the NAT table of the VM like below:
sudo iptables \
--table nat \
--append PREROUTING \
--protocol ALL \
--destination 192.168.100.3 \
--jump DNAT \
--to-destination 192.168.100.4 # some other machine in my local network
sudo iptables \
--table nat \
--append POSTROUTING \
--protocol ALL \
--destination 192.168.100.4 \
--jump SNAT \
--to-source 192.168.100.3

The ongoing ssh connection remains and I don't get disconnected. However if I open a new terminal on the host and try going ssh user@192.168.100.3 I actually connect with the other machine in my network, to which I forwarded using iptables (192.168.100.4). Why does my first connection remain and not get disconnected? From my understanding the rules I specified should forward ALL packets to the ip 192.168.100.4 and yet it is not the case.




Solution

The nat table is traversed only by the first packet of the connection. It defines all the translations and these are recorded in the connection tracking table. Subsequent packets don't traverse the nat table at all, instead the connection tracker just takes the recorded translation parameters from its table and applies them.

Therefore, nat rules that appeared after the connection was established never apply to the already running connections. The previous connection in your case knows there were no translation rules defined, so it does no translation. If you now connect to another computer and remove nat rules, the connection will be kept, but new connections will be created again without translation.