Definitions
host
= 172.16.1.155 is a public IP (changed it usingsed
to be consistent).guest
= 192.168.122.10 is the IP of a virtual machine running on the physical machine whose IP is 172.16.1.155.
Situation
I have the following rules (dumped with iptables-save
and filtered) for the two hosts in question (plus all required to understand the context):
*filter
-A INPUT -d 172.16.1.155/32 -p tcp -m multiport --dports 25,465 -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j DROP
-A FORWARD -p icmp -j ACCEPT
-A FORWARD -i _+ -o _+ -j ACCEPT
-A FORWARD -i _+ -o eth0 -j ACCEPT
-A FORWARD -d 192.168.122.10/32 -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 FORWARD -j LOG
-A FORWARD -j DROP
COMMIT
*nat
-A PREROUTING -d 172.16.1.155/32 -p tcp -m multiport --dports 25,465 -j DNAT --to-destination 192.168.122.10
COMMIT
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:
172.16.1.155 * 255.255.255.255 UH 0 0 0 eth0
192.168.122.0 * 255.255.255.0 U 0 0 0 virbr0
default 172.16.1.155 0.0.0.0 UG 100 0 0 eth0
Question
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 192.168.122.10/32 -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 127.0.0.1/24 -p tcp -m multiport --dports 25,465 -j DNAT --to-destination 192.168.122.10
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 192.168.122.10
. 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 127.0.0.1 25
?
So I was adding the rule iptables -t nat -D OUTPUT -d 127.0.0.1/24 -p tcp -m multiport --dports 25,465 -j DNAT --to-destination 192.168.122.10
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
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
with that rule I get:
$ telnet localhost 25
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection timed out
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.