Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I'm trying to accomplish the following: I have a box with a service listening on a dummy interface (say 172.16.0.1), udp port 5555. Now what I'd like to do is to take packets that arrive on interfaces eth0 (1.1.1.1:5555) and eth1 (2.2.2.2:5555) and forward them to the service on the dummy interface, and have replies go back to clients out the same physical interface they came in. Clients must think they're talking to 1.1.1.1:5555 or 2.2.2.2:5555. I think I need a mix of iptables rules and packet marking, plus some iproute rules (if it's possible at all). What I tried is to catch packets coming in from eth0 and eth1, udp port 5555, and mark them with 1 and 2 respectively, and --save-mark in the connmark. Then I used a DNAT to 172.16.0.1. The service seems to be getting the packets. Now I'm not sure how to do the reverse. It seems that for packets originating from the box, you can't do anything before the routing decision, but that would be the place to restore the marks, and thus make a routing decision based on those. Here's what I have so far:

iptables -t mangle -A PREROUTING -d 1.1.1.1 -p udp --port 5555 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -d 2.2.2.2 -p udp --port 5555 -j MARK --set-mark 2

iptables -t mangle -A PREROUTING -d 1.1.1.1 -p udp --port 5555 -j CONNMARK --save-mark
iptables -t mangle -A PREROUTING -d 2.2.2.2 -p udp --port 5555 -j CONNMARK --save-mark

iptables -t nat -A PREROUTING -m mark --mark 1 -j DNAT --to-destination 172.16.0.1
iptables -t nat -A PREROUTING -m mark --mark 2 -j DNAT --to-destination 172.16.0.1

# What next?

As I said, I'm not even sure it can be done. To give a bit of background, it's an old OpenVPN installation that cannot be upgraded (otherwise I'd install a recent version that supports multihoming natively).

Thanks for any help.

share|improve this question

3 Answers 3

Have you tried just using straight NAT (via the REDIRECT target) to do this? Conntrack should take care of the return packets, no need for manual marking.

share|improve this answer

I think I kind of got it working, here's what I did in case it might be useful to somebody else in the future:

iptables -t mangle -A PREROUTING -i eth0 -d 1.1.1.1 -p udp --dport 5555 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -i eth1 -d 2.2.2.2 -p udp --dport 5555 -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -i eth0 -p udp --dport 5555 -j CONNMARK --save-mark
iptables -t mangle -A PREROUTING -i eth1 -p udp --dport 5555 -j CONNMARK --save-mark

# nat PREROUTING comes after mangle PREROUTING
iptables -t nat -A PREROUTING -m mark --mark 1 -j DNAT --to-destination 172.16.0.1
iptables -t nat -A PREROUTING -m mark --mark 2 -j DNAT --to-destination 172.16.0.1

# restore mark from packets originating from 172.16.0.1, as it triggers a new routing decision
iptables -t mangle -A OUTPUT -s 172.16.0.1 -p udp --sport 5555 -j CONNMARK --restore-mark

ip rule add prio 20 fwmark 1 lookup upstream0
ip rule add prio 21 fwmark 2 lookup upstream1

OpenVPN is bound to 172.16.0.1 only (assigned to interface dummy0), and gets all traffic that clients send to 1.1.1.1:5555 or 2.2.2.2:5555.

share|improve this answer

I don't see how that could help:

It redirects the packet to the machine itself by changing the destination IP to the primary address of the incoming interface

Incoming packets are already addressed to the address of the incoming interface (ie 1.1.1.1 or 2.2.2.2). Or maybe I didn't understand what you mean, apologies in that case.

I forgot to add, if that solution seems overkill, it's because I tried the simpler one first, ie having the service listen on 0.0.0.0:5555 and using packet marking, but again I don't see where to restore the marking for locally-generated UDP packets.

If I switch to TCP everything works correctly even without the need of marking (not sure why exactly); I still need source-base routing rules of course, but then it "just works". I'll probably switch to TCP if I'm not able to make it work using UDP (although TCP has worst performance). My guess about why TCP works and UDP doesn't is because UDP/IP packets do not have a source address set when hitting the routing decision, so the address is "filled in" after the routing, which will select either the default route, or a random route in a multipath group, and that won't match the original incoming interface (or it will, but only by accident). On the other hand, TCP/IP packets already have a source address (and it is the right one) when they reach the routing phase, so source-based routing rules can be used. This is just a guess, if somebody spots some mistake I'm more than happy to stand corrected.

Thank you.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.