将端口转发给libvirt / KVM中的guest虚拟机

在使用NAT时,如何将运行libvirt / KVM的服务器上的端口转发到VM上的指定端口?

例如,主机的公有IP为1.2.3.4。 我想转发端口80到10.0.0.1和端口22到10.0.0.2。

我想我需要添加iptables规则,但我不知道哪里是适当的,什么应该指定。

iptables -L的输出

Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT udp -- anywhere anywhere udp dpt:domain ACCEPT tcp -- anywhere anywhere tcp dpt:domain ACCEPT udp -- anywhere anywhere udp dpt:bootps ACCEPT tcp -- anywhere anywhere tcp dpt:bootps Chain FORWARD (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere 10.0.0.0/24 state RELATED,ESTABLISHED ACCEPT all -- 10.0.0.0/24 anywhere ACCEPT all -- anywhere anywhere REJECT all -- anywhere anywhere reject-with icmp-port-unreachable REJECT all -- anywhere anywhere reject-with icmp-port-unreachable Chain OUTPUT (policy ACCEPT) target prot opt source destination 

输出ifconfig

 eth0 Link encap:Ethernet HWaddr 00:1b:fc:46:73:b9 inet addr:192.168.1.14 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: fe80::21b:fcff:fe46:73b9/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:201 errors:0 dropped:0 overruns:0 frame:0 TX packets:85 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:31161 (31.1 KB) TX bytes:12090 (12.0 KB) Interrupt:17 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) virbr1 Link encap:Ethernet HWaddr ca:70:d1:77:b2:48 inet addr:10.0.0.1 Bcast:10.0.0.255 Mask:255.255.255.0 inet6 addr: fe80::c870:d1ff:fe77:b248/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:6 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:468 (468.0 B) 

我使用Ubuntu 10.04。

    libvirt for Ubuntu的最新稳定版本是0.7.5版本,它没有一些更新的function(例如脚本钩子和networkingfilter),使自动networkingconfiguration更容易。 这就是说,以下是如何在Ubuntu 10.04 Lucid Lynx上为libvirt 0.7.5启用端口转发。

    这些iptables规则应该做的伎俩:

     iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 80 -j DNAT --to-destination 10.0.0.1:80 iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 22 -j DNAT --to-destination 10.0.0.2:22 iptables -I FORWARD -m state -d 10.0.0.0/24 --state NEW,RELATED,ESTABLISHED -j ACCEPT 

    默认的KVM NATconfiguration提供了一个类似于上面给出的第三条的规则,但省略了NEW状态,这对于接受传入连接是必不可less的。

    如果你编写一个启动脚本来添加这些规则,而你不小心,libvirt 0.7.5会通过插入它自己来覆盖它们。 因此,为了确保这些规则在启动时正确应用, 插入规则之前 ,需要确保libvirt已经初始化。

    在行exit 0之前将以下行添加到/etc/rc.local中:

     ( # Make sure the libvirt has started and has initialized its network. while [ `ps -e | grep -c libvirtd` -lt 1 ]; do sleep 1 done sleep 10 # Set up custom iptables rules. iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 80 -j DNAT --to-destination 10.0.0.1:80 iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 22 -j DNAT --to-destination 10.0.0.2:22 iptables -I FORWARD -m state -d 10.0.0.0/24 --state NEW,RELATED,ESTABLISHED -j ACCEPT ) & 

    上面的sleep 10是一个黑客,以确保libvirt守护进程已经有机会初始化其iptables规则,然后我们添加我们自己的。 我不能等到他们发布Ubuntu的libvirt版本0.8.3。

    当客户使用用户模式的networking时 ,有一种方法可以设置端口redirect,我在这里发表了博客:

    http://blog.adamspiers.org/2012/01/23/port-redirection-from-kvm-host-to-guest/

    你可以看到那里的细节,但为了方便,这里是我想出的解决scheme:

     virsh qemu-monitor-command --hmp sles11 'hostfwd_add ::2222-:22' 

    这个单线程比其他答案容易得多,但是只在某些情况下(用户模式networking堆栈)有效。

    更为“官方”的方式是创build一个钩子脚本,如libvirt网站所述:

    http://wiki.libvirt.org/page/Networking#Forwarding_Incoming_Connections

    …基本上这个脚本将在KVM guest虚拟机启动时被调用。 脚本本身将添加正确添加的“NEW”连接状态的适当的iptable规则(类似于上面的Isaac Sutherland的回答)。 请注意,您必须使用正确的主机和端口值修改脚本。

    [1]虽然libvirt文档本身说这是一种黑客,去图

     iptables -t nat -I PREROUTING -d 1.2.3.4 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1 iptables -t nat -I PREROUTING -d 1.2.3.4 -p tcp --dport 22 -j DNAT --to-destination 10.0.0.1