I have a server with Debian GNU/Linux as host system.
The host runs several guest virtual machines, but it has only one public
IP address.
Each virtual machine is a QEMU/KVM Debian GNU/Linux system that runs
some specific service (so I have one for websites, one for mail, one for
database, one for ssh connections, and so on).
One of the virtual machines is the router: the host system forwards any
incoming connection to it and the router forwards the connection to the
correct VM based on the TCP destination port.
The host system forwards connections to the router with these iptables
rules (1.2.3.4 stands for the public IP address):
# Generated by iptables-save v1.4.21 on Sun Jun 25 22:33:39 2017
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [86517:5472157]
:OUTPUT ACCEPT [32635:3750271]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp -m tcp --dport 31222 --tcp-flags FIN,SYN,RST,ACK SYN -m
conntrack --ctstate NEW -j ACCEPT
-A INPUT -i virbr10 -p udp -m udp -m multiport --dports 53,67 -j ACCEPT
-A INPUT -i virbr10 -p tcp -m tcp -m multiport --dports 53,67 -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p tcp -m tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -d 10.7.33.0/24 -o virbr10 -m conntrack --ctstate
RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s 10.7.33.0/24 -i virbr10 -j ACCEPT
-A FORWARD -i virbr10 -o virbr10 -j ACCEPT
-A FORWARD -d 10.7.33.100/32 -o virbr10 -p tcp -m tcp --dport 1:31221
--tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j ACCEPT
-A FORWARD -i virbr10 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -o virbr10 -j REJECT --reject-with icmp-port-unreachable
COMMIT
# Completed on Sun Jun 25 22:33:39 2017
# Generated by iptables-save v1.4.21 on Sun Jun 25 22:33:39 2017
*nat
:PREROUTING ACCEPT [265547:18746839]
:INPUT ACCEPT [7946:621443]
:OUTPUT ACCEPT [44:3768]
:POSTROUTING ACCEPT [737574:41994020]
-A PREROUTING -d 1.2.3.4/32 -p tcp -m tcp --dport 1:31221 --tcp-flags
FIN,SYN,RST,ACK SYN -j DNAT --to-destination 10.7.33.100
-A POSTROUTING -s 10.7.33.0/24 -d 224.0.0.0/24 -j RETURN
-A POSTROUTING -s 10.7.33.0/24 -d 255.255.255.255/32 -j RETURN
-A POSTROUTING -s 10.7.33.0/24 ! -d 10.7.33.0/24 -p tcp -j MASQUERADE
--to-ports 1024-65535
-A POSTROUTING -s 10.7.33.0/24 ! -d 10.7.33.0/24 -p udp -j MASQUERADE
--to-ports 1024-65535
-A POSTROUTING -s 10.7.33.0/24 ! -d 10.7.33.0/24 -j MASQUERADE
COMMIT
# Completed on Sun Jun 25 22:33:39 2017
# Generated by iptables-save v1.4.21 on Sun Jun 25 22:33:39 2017
*mangle
:PREROUTING ACCEPT [32568589:28152102128]
:INPUT ACCEPT [65809:5372699]
:FORWARD ACCEPT [32502779:28146729377]
:OUTPUT ACCEPT [56541:5855271]
:POSTROUTING ACCEPT [32535420:28150481592]
-A POSTROUTING -o virbr10 -p udp -m udp --dport 68 -j CHECKSUM
--checksum-fill
COMMIT
# Completed on Sun Jun 25 22:33:39 2017
Then the router has its own set of iptables rules (I report only a few
here):
# Generated by iptables-save v1.4.21 on Sun Jun 25 22:41:19 2017
*filter
:INPUT ACCEPT [114664:5730467]
:FORWARD ACCEPT [20388771:18133798388]
:OUTPUT ACCEPT [112664:4594474]
-A INPUT -s 10.7.33.101/32 -p tcp -m tcp --sport 29101 -j LOG
COMMIT
# Completed on Sun Jun 25 22:41:19 2017
# Generated by iptables-save v1.4.21 on Sun Jun 25 22:41:19 2017
*nat
:PREROUTING ACCEPT [108899:5217224]
:INPUT ACCEPT [108899:5217224]
:OUTPUT ACCEPT [2734:162786]
:POSTROUTING ACCEPT [2734:162786]
-A PREROUTING -p tcp -m tcp --dport 29101 -j DNAT --to-destination
10.7.33.101
-A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.7.33.101
-A PREROUTING -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.7.33.101
-A PREROUTING -p tcp -m tcp --dport 25 -j DNAT --to-destination 10.7.33.109
-A POSTROUTING -d 10.7.33.101/32 -p tcp -m tcp --dport 29101 -j SNAT
--to-source 10.7.33.100
-A POSTROUTING -d 10.7.33.101/32 -p tcp -m tcp --dport 80 -j SNAT
--to-source 10.7.33.100
-A POSTROUTING -d 10.7.33.101/32 -p tcp -m tcp --dport 443 -j SNAT
--to-source 10.7.33.100
-A POSTROUTING -d 10.7.33.109/32 -p tcp -m tcp --dport 25 -j SNAT
--to-source 10.7.33.100
COMMIT
# Completed on Sun Jun 25 22:41:19 2017
It works like a charm, but there is one problem: my mail server receives
all the connections from the router, which has its own private IP
address (10.7.33.100), so the mail server can't enforce SPF policies nor
DNS RBL rules on incoming mail connections.
Is there a way to forward packets from the host to the router and from
the router to the correct virtual server keeping the original source IP
address?