Port Forwarding in Different Network Scenarios

Port forwarding is useful for rerouting traffic to another port or machine. This is still my iptables version of that setup. The two private networks are 192.168.0.0/24 and 192.168.1.0/24.

Network Configuration

  • ClientIP 192.168.0.240
  • Machine1 192.168.0.2 port 2020
  • Machine2 192.168.1.2 port 1010

Enabling IP Forwarding

The kernel needs to allow forwarding. To do this temporarily, use the sysctl command:

sysctl -w net.ipv4.ip_forward=1

To make it permanent, add /etc/sysctl.d/90-port-forward.conf:

net.ipv4.ip_forward = 1

You can check if IP forwarding is enabled by viewing the content of the /proc/sys/net/ipv4/ip_forward file:

cat /proc/sys/net/ipv4/ip_forward

Setting Up IPTables Rules

Now we need to set up iptables rules to redirect the source port to Machine2’s IP and port. We also need to masquerade the traffic so Machine2 answers to Machine1, which in turn answers to the client.

iptables -t nat -A PREROUTING -i ens18 -p tcp -d 192.168.0.2 --dport 2020 \
  -j DNAT --to-destination 192.168.1.2:1010
iptables -t nat -A POSTROUTING -p tcp -s 192.168.0.240 -d 192.168.1.2 --dport 1010 \
  -j MASQUERADE

Since traffic is moving from PREROUTING to FORWARD to POSTROUTING, we need to make the FORWARD chain aware and accept the traffic from the client and not drop it before it reaches POSTROUTING.

iptables -A FORWARD -i ens18 -p tcp -s 192.168.0.240 -d 192.168.1.2 --dport 1010 \
  -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables -A FORWARD -o ens18 -p tcp -s 192.168.1.2 --sport 1010 -d 192.168.0.240 \
  -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

To monitor the iptables rules, use these commands:

watch iptables -t nat -L -n -v
watch iptables -L -n -v

Forwarding to Internal Localhost

To forward to localhost, enable route_localnet only on that interface. This weakens the normal martian-address check, so I retain source and port restrictions in the DNAT rule:

sysctl -w net.ipv4.conf.ens18.route_localnet=1

You can set up the forwarding from one host, from one subnet, or even from one MAC address:

iptables -t nat -A PREROUTING -i ens18 -p tcp -s 192.168.0.123 --dport 8001 -j DNAT --to-destination 127.0.0.1:8001
iptables -t nat -A PREROUTING -i ens18 -p tcp -s 192.168.0.0/24 --dport 8001 -j DNAT --to-destination 127.0.0.1:8001
iptables -t nat -A PREROUTING -i ens18 -p tcp -m mac --mac-source 00:0F:EA:91:04:07 --dport 8001 -j DNAT --to-destination 127.0.0.1:8001

You can even block all traffic except for a specific MAC address:

/sbin/iptables -A INPUT -p tcp --dport 22 -m mac ! --mac-source YOUR-MAC-ADDRESS-HERE -j DROP

Persistence is distribution-specific. On Debian/Ubuntu with iptables-persistent:

sudo netfilter-persistent save

Optional nftables Translation

I keep iptables primary because it is what this setup used. For comparison, its main NAT rules translate to:

table ip port_forward {
  chain prerouting {
    type nat hook prerouting priority dstnat;
    iifname "ens18" ip daddr 192.168.0.2 tcp dport 2020 dnat to 192.168.1.2:1010
  }
  chain postrouting {
    type nat hook postrouting priority srcnat;
    ip saddr 192.168.0.240 ip daddr 192.168.1.2 tcp dport 1010 masquerade
  }
}

This is an optional translation, not a replacement for my tested workflow. nftables NAT documentation

By using these steps, you should be able to successfully forward traffic from one machine to another, or from one network to another, with iptables.



Buy Me a Coffee