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 have a host machine(A) with lxc-container(B). A's local ip address is 10.0.3.1 and public ip, let's say 1.2.3.4. B's local ip address is 10.0.3.21.

I need 1.2.3.4:7999 to be forwarded to 10.0.3.1:7999 and I created the following rules for that:

iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 7999 -j DNAT --to 10.0.3.21:7999
iptables -A FORWARD -p tcp -d 10.0.3.21 --dport 7999 -j ACCEPT

When I connect to the A (1.2.3.4:7999) from the outside world I am connecting successfully. But I am falling when I try to connect to B from A (connection timed out).

What rules should I create to be able to connect to 1.2.3.4:7999 from 10.0.3.1?

share|improve this question

2 Answers 2

You have a NAT hairpin situation here, which your current iptables rules don't support. When the container sends the request out the packet looks like this:

10.0.3.21:12345 -> 1.2.3.4:7999

The gateway then DNATs the packet to this, and sends it back to the container:

10.0.3.21:12345 -> 10.0.3.21:7999

The container receives the packets and sends a response which looks like this:

10.0.3.21:7999 -> 10.0.3.21:12345

i.e. it's directly addresses to the container itself. But port 12345 doesn't know about a connection with 10.0.3.21:7999, because the connection was with 1.2.3.4:7999, and so the response is ignored.

The solution is to also SNAT the packet on the gateway so that the response goes back to the gateway, which then undoes both NATs. Try adding something like this:

iptables -t NAT -A POSTROUTING -o lxcbr0 -d 10.0.3.21 -s 10.0.3.21 -j SNAT --to 10.0.3.1
share|improve this answer
    
after adding this rule I am getting same problem. I tried to connect to 10.0.3.1:7999 (connection refused) from B and to 1.2.3.4:7999 (connection timed out) –  Andrey Kouznetsov Feb 5 '13 at 14:17
    
@AndreyKouznetsov Then start using tcpdump to see where the packets go and what they look like. –  mgorven Feb 5 '13 at 17:08
    
yes, I am already learning it. –  Andrey Kouznetsov Feb 6 '13 at 0:06

I think the problem you're experiencing is that the answer is coming back on a different interface.

Initial Request

S: 1.2.3.4
D: 1.2.3.4

DNAT

S: 1.2.3.4
D: 10.0.3.21

At this point, host A makes the decision to route to 10.0.3.21 using the private network interface.

REPLY

S: (IP of default GW interface on B)
D: 1.2.3.4

The reply packet from B will traverse the default gateway and more than likely come back to A on its public interface, at which point the packet is discarded because there is no matching entry in the connection tracking table.


Solution

Add the following rule to ensure the reply traverses the same path as the request.

iptables -t nat -I POSTROUTING -s 1.2.3.4 -d 10.0.3.21 -o (interface of 10.0.3.1) -j SNAT --to 10.0.3.1
share|improve this answer
    
Same problem :( I still can't connect to 1.2.3.4:7999 from 10.0.3.21 –  Andrey Kouznetsov Feb 4 '13 at 9:23
    
The command I used was iptables -t nat -I POSTROUTING -s 1.2.3.4 -d 10.0.3.21 -o lxcbr0 -j SNAT --to 10.0.3.1 –  Andrey Kouznetsov Feb 4 '13 at 9:24
    
There's probably something I'm overlooking then. The best advice I can offer is to use tcpdump on server B to examine what the packet headers look like on the way in, and what the reply looks like. Remember that a server talking to itself will often prefer the lo interface (regardless of IP), and to check other interfaces for the reply if it is missing. You should also delete that POSTROUTING rule until you are sure you know what is going on. –  Andrew B Feb 4 '13 at 9:27

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.