On 06/08/2015 03:24 PM, BJ wrote:
Hello all,
I was told on IRC that I should come here to discuss a recommended
change on the networking page in the wiki.
If you take a look at the "Basic Script" shown
here:
http://wiki.libvirt.org/page/Networking#Forwarding_Incoming_Connections
It does two things:
1) Create a DNAT rule in the NAT table of IPTABLES
2) Create a FORWARD rule in the FILTER table of IPTABLES
The FORWARD rule is set up as it ought to be, however, the DNAT rule
has some unintended consequences. I set up a DNAT on port 80, and
suddenly, I couldn't access out on port 80 anymore from my guest machine.
I'm not seeing the same results here. outbound port 80 is still allowed
from my host once the rule is in place. Of course incoming port 80 isn't
being redirected to the guest either, so I think I have bigger problems.
(this is likely due to the fact that I haven't tried the script again
since 2013 or so, and a lot has likely changed with the iptables rules
added to a Fedora system since then)
However, if I changed the destination address from
"anywhere" to the
IP of the host machine, the problem resolved. So I change the script
to as follows. (Changes are highlighted. For some reason the original
script didn't work using /bin/sh, but it did with /bin/bash, so I
changed that too).
I don't know for sure, but my guess is that this line:
length=$(( ${#Host_port[@]} - 1 ))
which was added by vgerris in order to support forwarding of multiple
ports, could be what's causing the incompatibility (that wasn't in the
original, simpler version of the script, written by me.)
*#!/bin/bash*
# used some from advanced script to have multiple ports: use an equal
number of guest and host ports
Guest_name=xxxxxxx
Guest_ipaddr=xxx.xxx.xxx.xx
*Host_ipaddr=xxx.xxx.xxx.xx*
Host_port=( '80' '443' )
Guest_port=( '80' '443' )
length=$(( ${#Host_port[@]} - 1 ))
if [ "${1}" = "${Guest_name}" ]; then
if [ "${2}" = "stopped" -o "${2}" =
"reconnect" ]; then
for i in `seq 0 $length`; do
iptables -t nat -D PREROUTING *-d ${Host_ipaddr}* -p
tcp --dport ${Host_port[$i]} -j DNAT --to
${Guest_ipaddr}:${Guest_port[$i]}
iptables -D FORWARD -d ${Guest_ipaddr}/32 -p tcp -m
state --state NEW -m tcp --dport ${Guest_port[$i]} -j ACCEPT
done
fi
if [ "${2}" = "start" -o "${2}" = "reconnect"
]; then
for i in `seq 0 $length`; do
iptables -t nat -A PREROUTING *-d ${Host_ipaddr}* -p
tcp --dport ${Host_port[$i]} -j DNAT --to
${Guest_ipaddr}:${Guest_port[$i]}
iptables -I FORWARD 4 -d ${Guest_ipaddr}/32 -p tcp -m
state --state NEW -m tcp --dport ${Guest_port[$i]} -j ACCEPT
done
fi
fi
Lastly, I should note that I am using Ubuntu 14.04, both for the host
and guest.
I'm also curious as to why this is considered a hack method. It states
in the wiki that "This method is a hack", but it doesn't express why.
I consider it a hack because:
1) It requires the IP address of the guest to be known before the guest
is started, so either you need to guess the guest's IP (if the guest is
getting its IP address via dhcp) or configured the guest IP address in
multiple places.
2) It requires using a hook script, which "taints" *all* guests on this
machine, rendering them "unsupported" in the eyes of some (in practice,
once you see what is causing the tainting it's not such a big deal, but
it does mean that an external script gets control with elevated privileges).
3) The "configuration" is just the contents of the shell script, so it
can't be supported by any higher level management application - you will
always need to directly modify this single shell script file.
4) If you change the configuration for a guest while that guest is
running, any forwarding rules that were a part of the old config but not
in the new config will be orphaned in your iptables nat table until
*all* rules are flushed.
5) If anything else messes with the iptables rules, these port
forwarding rules are broken. Especially on older versions of libvirt
(0.9.12 and older, which is around the time that entry was written),
just restarting libvirtd would break the port forwarding.
6) As both of us have experienced here, interaction with the iptables
rules of the underlying system can easily result in it not working at all.
The proper way to support this would be XML added to the domain
configuration, something like:
<interface type='network'>
<source network='default'/>
<model type='virtio'/
<mac address='52:54:00:11:22:33'/>
<redirect protocol='tcp'>
<public address='1.2.3.4' port='2200'/>
<private port='22'/>
</redirect>
...
</interface>
(or something like that). libvirt would then auto-determine the IP
address of the interface and add the necessary iptables rules (or
perhaps an rinetd config line item, which may be less prone to sabotage
by distro-specific default iptables setups). The inverse would be
automatically done when the domain was shutdown.
Many VM Servers have similar features. I know Virtual Box does, I
use
the same feature there. It may not be how I would set up a production
server, but doesn't make it a hack.
It's not the port forwarding itself that I consider to be a hack, it's
the method that's used by that script to accomplish it. (And since I was
the original author of the script and the entry in the wiki, I think I
am allowed to criticize it :-)