I have a cable connection with a Linux-based router. The router has two physical interfaces:
enp1s0 (dhcp from cable provider)
enp2s0 (192.168.1.1)
with masquerading on enp1s0. then, I have an OpenVPN client connection:
tun0 (10.0.0.4)
Again, with masquerading on this device. The regular routing table has no entries pointing to this device, but I have an additional routing table:
vpn-clients
so that I can add a default route using this device:
ip route add default via 10.0.0.1 dev tun0 table vpn-clients
and then specify per-client which table to use:
ip rule add from 192.168.1.200 lookup vpn-clients
ip rule add from 192.168.1.201 lookup vpn-clients
...
and port forwarding on tun0:
/sbin/iptables -t nat -A PREROUTING -i tun0 -p udp --dport 5555 -j DNAT --to-destination 192.168.1.200:5555
This looks like it is working (at least for outgoing connections). All traffic from the clients that are source-routed appears to be routed through the vpn.
Now, incoming connections are an entirely different story. I used to have loads and loads of martians logged.
I realized that it might be caused by the combination of source routing, port forwarding and masquerading, i.e. the kernel might not be aware that the destination of an incoming package will be modified, and instead assume that the 10.0.0.4 is the final destination, which would be impossible, because there aren't any routes set that would explain things coming in for this destination from anything but it's own subnet.
So, I added a somewhat dummy-ish route:
ip rule lookup from 10.0.0.4 lookup vpn-clients
so that the "routing table" for this interface becomes "vpn-clients" which DOES have a default route pointing in that direction.
This stopped the martians being logged & dropped. Incoming connections are working fine now. Is this the "correct" way, though? Would it be possible to make this better?