Server Fault is a question and answer site for system and network administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top


  • host = is a public IP (changed it using sed to be consistent).
  • guest = is the IP of a virtual machine running on the physical machine whose IP is


I have the following rules (dumped with iptables-save and filtered) for the two hosts in question (plus all required to understand the context):

-A INPUT -d -p tcp -m multiport --dports 25,465 -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A FORWARD -p icmp -j ACCEPT
-A FORWARD -i _+ -o _+ -j ACCEPT
-A FORWARD -i _+ -o eth0 -j ACCEPT
-A FORWARD -d -p tcp -m multiport --dports 25,465 -j ACCEPT
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable
-A PREROUTING -d -p tcp -m multiport --dports 25,465 -j DNAT --to-destination

The rules ensure that any request from the outside world to the public IP of host will actually end up in guest. All of that works fine and as intended. There are many more rules, but they affect only the other guests or have unrelated purposes. All interfaces for the guests start with an underscore so I can conveniently use _+ to match the interface names in the above rules.

The virtual machines are all KVM guests. The name of the bridge interface is virbr0. Each virtual machine with an external IP address has an interface named after it but prepended with an underscore (so guest foo would have the interface _foo).

Additionally KVM creates a vnetX (X being a number) interface per guest.

The following routes are set w.r.t. the host and guest in question:    *      UH    0      0        0 eth0   *        U     0      0        0 virbr0
default         UG    100    0        0 eth0


If I create a SOCKS proxy by SSH-ing into host (ssh -D) I cannot connect to guest via that proxy. First I thought that the reason was that the SOCKS proxy would probably use the lo interface (tcpdump -i lo confirms that) on the host side, so I added the following rule iptables -I FORWARD -i lo -p tcp -m multiport --dports 25,465 -j ACCEPT (keep in mind that -A INPUT -i lo -j ACCEPT accepts the input already), but that should already be covered by -A FORWARD -d -p tcp -m multiport --dports 25,465 -j ACCEPT. So I removed the rule again and tried the following NAT rule: iptables -t nat -I PREROUTING -d -p tcp -m multiport --dports 25,465 -j DNAT --to-destination and subsequently its equivalent (for all practical purposes) iptables -t nat -I PREROUTING -i lo -p tcp -m multiport --dports 25,465 -j DNAT --to-destination Neither gave me the result I wanted.

How can I bridge the gap in this scenario? And moreover, is my assumption valid that I can test whether the SOCKS proxy works by using telnet 25?

So I was adding the rule iptables -t nat -D OUTPUT -d -p tcp -m multiport --dports 25,465 -j DNAT --to-destination as suggested by mgorven. There is clearly a change in behavior here, but it's not yet entirely what I'm looking for.

Without that rule I get:

$ telnet localhost 25
telnet: Unable to connect to remote host: Connection refused

with that rule I get:

$ telnet localhost 25
telnet: Unable to connect to remote host: Connection timed out
share|improve this question
up vote 1 down vote accepted

The PREROUTING chain is not traversed for packets originating from the host (this diagram is useful for figuring out which chains a packet will traverse). You want to put those rules into the OUTPUT chain of the nat table.

share|improve this answer
thanks for the answer. Sounds logical, let me try it and then I'll accept or ask back. +1 for now. – 0xC0000022L Jul 13 '12 at 12:27
I may have misunderstood your suggestion. Added what I tried to my question. Any ideas? I'm still puzzled. Clearly this is a step in the right direction but something is still missing. – 0xC0000022L Jul 13 '12 at 13:36
@0xC0000022L Um, I wouldn't try to DNAT to the VM. The loopback interface is kinda special so I doubt that that can work. DNAT the host's public IP to the VM and connect to the public IP through the SOCKS server. – mgorven Jul 13 '12 at 17:14
i.e. move the rule from PREROUTING to OUTPUT? – 0xC0000022L Jul 13 '12 at 17:29
@0xC0000022L No, you need the DNAT rule in both the PREROUTING chain (for packets from outside) and the OUTPUT chain (for packets from the host itself). – mgorven Jul 13 '12 at 17:32

Your Answer


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.