I have a machine with two interfaces that have different routeable IPv4 addresses. To return traffic on the right interface, I used this answer and comment, and it works: I can ssh into the machine using either IP address. (I don't know if this has any impact, but it might have.)
Now I added the following iptables rules for reverse proxying / DNAT using this answer. My boot script now looks like:
# eth0 is automatically brought up and gets 192.168.1.2 as IP
sudo ip link set eth1 up
sudo ip addr add 192.168.2.2/24 dev eth1
sudo ip rule add from 192.168.2.2 table frometh1
sudo ip route add default via 192.168.2.1 dev eth1 table frometh1
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.0.0.1:443
sudo iptables -t nat -A PREROUTING -i eth1 -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.0.0.1:443
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
echo 1 > /proc/sys/net/ipv4/ip_forward
Initially, the -i eth*
was omitted and the DNAT rule was just one command. The MASQUERADE rules were also one command by exchanging -o eth*
for -d 10.0.0.1
. I split them in an attempt to make the interfaces explicit, in case iptables implicitly takes one of the interfaces.
When I try to reach 192.168.1.2:443
, the traffic is forwarded and masqueraded as expected. The hit counter for the correct DNAT rule in the PREROUTING table is incremented and the right MASQUERADE rule is incremented. I can successfully build a TCP connection.
When trying to reach 192.168.2.2:443
, I can see the traffic incoming on the interface, and the hit counter for correct DNAT rule in the PREROUTING table is incremented. But there is no outgoing packet and neither of the two MASQUERADE rules in POSTROUTING is incremented. The TCP SYN never reaches the remote system (10.0.0.1
).
Note that it does not matter if the forwarding happens through eth0 or eth1, it's fine to forward the traffic to the target (10.0.0.1
) over either eth0 or eth1.
Why do the iptables rules work only for eth0 and not for eth1?
Edit: It might be relevant to know that proxying in userspace works fine:
mkfifo /tmp/fifo
sudo nc -kvlp 443 </tmp/fifo | nc 10.0.0.1 443 >/tmp/fifo
Allows traffic to flow both ways, as described in this blog. The problem with this solution is that the remote end sees only one, persistent TCP connection. It should see one connection per client and handle multiple clients simultaneously.
192.168.2.X
) or somewhere further?nc -v $external_ip_for_eth1 443
.