在libvirt / KVM中将端口转发给来宾


33

使用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。


1
为什么要使用ifconfig?ip是ifconfig的后继者。;)
Manuel Faux

5
问题233760在libvirt从不版本中解决了此问题。 serverfault.com/questions/233760
akaihola 2011年

Answers:


36

Ubuntu的libvirt的最新稳定版本是0.7.5版,该版本没有一些较新的功能(例如,脚本挂钩和网络过滤器),这些功能使自动网络配置更加容易。就是说,以下是在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 NAT配置提供的规则类似于我上面给出的第3条规则,但是它忽略了NEW状态,该状态对于接受传入连接至关重要。

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

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

(
# 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。


3
您能否解释一下如何使用当前的libvirt做到这一点?
Manuel Faux 2010年

1
如果其中一个钩子脚本在libvirt初始化其网络之后运行,则您不需要hacked while循环和睡眠命令。我不确定/ etc / libvirt / hooks / daemon脚本是在网络初始化之前还是之后运行,但是如果您使用/ etc / libvirt / hooks / qemu,则可以在适当的虚拟机启动和运行时创建和销毁规则。停。我不确定您将如何使用网络过滤器(如果有的话),但是libvirt.org/firewall.html上的某些示例闻起来好像可以修改它们以自动创建iptables规则。
艾萨克·萨瑟兰

太好了,我可以确认它是否有效,但是我还没有尝试重新启动服务器时会发生什么...
Aron Lorincz

18

当来宾使用用户模式网络时,有一种动态设置端口重定向的方法,我在这里写过博客:

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

您可以在此处看到详细信息,但是为了方便起见,这是我想出的解决方案:

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

这种单行代码比其他答案容易得多,但仅在某些情况下有效(用户模式网络堆栈)。


3
您的解决方案非常有趣-您可以在答案中包含一些重要的细节(或至少是“操作方法”的部分),以便在博客需要维护时仍然有用吗?:)
voretaq7 2012年

做完了,请随时帮助我的科幻小说声誉升至1以上;-)
Adam Spiers,2012年

这种方法需要在用户模式下使用网络,这可能给我们带来一些无趣的限制。请参阅:linux-kvm.org/page/Networking#User_Networking。另参考:topic.alibabacloud.com/a/...snippets.webaware.com.au/howto/... ]
爱德华多卢西奥

5

一种更“官方的” [1]方法是按照libvirt网站上的描述创建一个钩子脚本:

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

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

[1]尽管libvirt文档本身说这是一种破解,



-1
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

1
谢谢你,但是特别是对于KVM,它也需要NEW状态标志
steveh7
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.