A server has 3 ifaces, 2 internal (eth1/2) in different public networks, one external (eth0).
There is a service (openvpn) that can't bind to some IPs/ifaces, only to all or one, but I need it to accept connections (UDP) on internal ifaces only. The default gw is via the external one.
I have a working setup with 2 instances of the service, bound to the IPs of each internal iface and routing set with iproute2 (ip route add xxx table x
, ip rule add from <IP> table x
).
Is it possible to DNAT the incoming connection on the second internal iface (eth2) to the IP of the first internal iface (eth1) and make it respond via the same interface (eth2)? In this case it wouldn't be necessary to run the second instance of the service and maintain 2 identical configs with the only difference of the IP to listen on.
The problem is that if I change (with DNAT) the destination IP of the incoming connection on eth2 to the IP of the eth1, then the ip rule based on from <IP>
won't work. Or, better to say, it will make the service reply via eth1, not eth2, using the default gw of the eth1.
Is it possible to efficiently set-mark for all outgoing packets of the DNATed "session" (UDP), so I could use fwmark in ip rule? Any other solution for the main problem?
Best Answer
Found a solution. This solution should work for any linux service that can't listen on specific interfaces, but only on all (0.0.0.0) or one particular, like MySQL, OpenVPN and many others. So we make the service listen on one iface and add netfilter/iproute2 rules to redirect all requests for the same protocol and port on another iface to our service on the first iface.
The "session" (despite being UDP in the OpenVPN case) is actually maintained by netfilter, and there is a module conntrack that permits to reference packets from a specific session. In this case I added a rule for OUTPUT in mangle table to mark all packets from the DNATed sessions with a mark. And then I use this mark to route the packets.
So, the commands are:
Define the variables
This command instructs netfilter to overwrite the destination IP of the incoming connections on our second iface.
This command instructs netfilter to set-mark for the outgoing packets (the reply of the service) of the overwritten (DNATed) incoming connection.
--ctorigdst
is the original (pre-DNATed) destination IP of the incoming connectionThis command instructs iproute2 to route set-marked packets via the route definitions of the table 100. Prio is necessary to set the highest priority for this rule, as it's very specific and won't interfere with other rules. If prio is not specified, the routing rules for the first internal iface may get higher priority.
This command adds a default gateway to the table 100
For all this to work, it's necessary to lessen the grip of the return path filter on the second internal iface.