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.

There are lots of questions on here about iptables DNAT/SNAT setups but I haven't found one that solves my current problem.
I have services bound to the IP address of eth0 (e.g. 192.168.0.20) and I also have a IP address on eth0:0 (192.168.0.40) which is shared with another server. Only one server is active, so this alias interface comes and goes depending on which server is active. In order to get traffic accepted by the service a DNAT rule is used to change the destination IP.

iptables -t nat -A PREROUTING -d 192.168.0.40 -p udp --dport 7100 -j DNAT --to-destination 192.168.0.20

I also wish all outbound traffic from this service to appear to come from the shared IP, so that return responses will work in the event of a active-standby failover.

iptables -t nat -A POSTROUTING -p udp --sport 7100 -j SNAT --to-source 192.168.0.40

My problem is that the SNAT rule is not always run. Inbound traffic causes a connection tracking entry like this.

[root]# conntrack -L -p udp
udp      17 170 src=192.168.0.185 dst=192.168.0.40 sport=7100 dport=7100 src=192.168.0.20 dst=192.168.0.185 sport=7100 dport=7100 [ASSURED] mark=0 secmark=0 use=2

which means the POSTROUTING chain is not run and outbound traffic leaves with the real IP address as the source.

I am thinking I can set up a NOTRACK rule in the raw table to prevent conntracking for this port number, but is there a better or more efficient way to make this work?

Edit - Alternative question: Is there a way (in CentOS/Linux) to have an interface that can be bound to but not used, such that it can be attached to the network or detached when a shared IP address is swapped between servers?

share|improve this question
    
What you are attempting doesn't make any sense. If someone connects to a particular IP address, they won't know what do with a reply that comes from another IP address. They certainly won't return responses to it. (They wouldn't even recognize it as a reply but just as something totally unrelated from a different source.) –  David Schwartz Oct 16 '12 at 13:52
    
What you're suggesting breaks TCP/IP. A 3-way handshake sets up a connection between a source and destination IP address. If I try to connect (SYN) to 192.168.0.20 and I get a SYN/ACK from 192.168.0.40 there will never be a successful connection. –  Sean C. Oct 16 '12 at 14:00
    
I don't want to change the IP address that is visible externally. If someone connects to this service on the shared IP address all IP packets should be sent to and recieved from the shared IP address. I have had the DNAT rule in place for months and it works for TCP and UDP. My problem is that outbound packets are not SNAT-ed to change the source IP, which causes them to appear to come from a different IP address. If there is no connection tracking entry, the SNAT rule works for both UDP and TCP. –  Que_273 Oct 16 '12 at 14:10

2 Answers 2

I can suggest two alternatives, you get to pick one of them or your own.

You can set up your service to listen on the wildcard address and thus avoid the DNAT rule altogether. The SNAT rule will then get applied on the outgoing packets.

Or, depending on what HA solution you are using, you could configure it to start your service listening on the floating IP (192.168.0.40) as it gets migrated.

Not so related note, but this kind of nuisance does not exist in OpenBSD CARP. With CARP you have the virtual IP configured on all nodes, but it is active on only one. This of course means that you can have your service listening on the virtual IP on all nodes.

This is not so pretty, but you could configure the virtual IP on all nodes (and even bring it up) and use arptables to disable ARP replies or announcements for that IP. You can then have ucarp enable or disable the ARP rule as a node becomes a master or slave.

share|improve this answer
    
I am using ucarp to manage the floating IP. The shared interface (eth0:0) is configured on all servers but is not 'up' on the standby. I did not think it was possible to bind to an interface that is not running, but I can test it again. Due to the time it takes to start up (DB loading etc.) we wanted a solution where the application can take over immediately on the ucarp swap and so far, having it running on the real IP and using the DNAT from shared to real IP has mainly worked. –  Que_273 Oct 16 '12 at 14:21
    
Please don't misunderstand me. CARP in OpenBSD configures the IP so you can bind to it, but does not activate it (we actually used such a setup at work). Unfortunately as far as I know this is not the case on Linux. –  chutz Oct 16 '12 at 15:11
    
Thanks for the suggestions @chutz, but I've found another solution. –  Que_273 Oct 17 '12 at 17:09

I've found a solution to my problem.
By using the kernel parameter net.ipv4.ip_nonlocal_bind=1, I can get my service to bind to addresses that do not yet exist.
When the eth0:0 interface is brought up traffic is accepted by the service. ARP etc. is handled by ucarp/networking. With this in place no DNAT/SNAT rules are needed at all.

share|improve this answer
    
I agree, this removes the need for a DNAT, but don't you still need an SNAT for the outgoing packets? –  chutz Oct 18 '12 at 4:11

Your Answer

 
discard

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.