1

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?

2 Answers 2

1

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
3
  • 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) Feb 5, 2013 at 14:17
  • @AndreyKouznetsov Then start using tcpdump to see where the packets go and what they look like.
    – mgorven
    Feb 5, 2013 at 17:08
  • yes, I am already learning it. Feb 6, 2013 at 0:06
0

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
3
  • Same problem :( I still can't connect to 1.2.3.4:7999 from 10.0.3.21 Feb 4, 2013 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 Feb 4, 2013 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, 2013 at 9:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .