如何禁用 QEMU 来宾访问主机端口

如何禁用 QEMU 来宾访问主机端口

我使用以下命令来运行 QEMU VM:

qemu-system-x86_64 -enable-kvm -m 1024 -smp 2 -hda disk.qcow2

默认情况下,来宾操作系统可以访问互联网,但也可以访问主机操作系统上的开放端口。如何防止来宾操作系统访问主机端口(但不限制其互联网访问)?

答案1

如果您没有高级 iptables 操作经验以及 Linux 如何过滤本地进程流量的概述,这看起来有些问题。

在您的模式下,qemu 运行模拟 NAT:来自 guest 虚拟机的所有对 NIC 的调用都将被 qemu 进程本身转换为套接字/连接/发送/接收调用。这意味着连接是由机器本身从 127.0.0.1 建立的。此时,您可以作为另一个用户运行 qemu,并通过添加匹配来过滤该用户owner

iptables -I OUTPUT -o lo -m owner --uid-owner username -m multiport --dports ports -j DROP

其中username是要过滤的用户名,ports是要为该计算机禁用的端口的逗号分隔列表。要以其他用户身份运行 qemu,您需要通过sudo或 以用户身份登录su或 之类的工具来运行它login

如果没有这个,您最终会过滤自己,因此如果您添加通用规则来过滤端口,您也将被阻止访问这些端口。

另一种方法是改变 qemu 的网络方式。过滤流量的一个好方法是将 qemu 绑定到虚拟以太网设备:

  • 启用数据包转发。

  • 安装tunctl,添加虚拟网络接口,所有者是你:

tunctl -u yourname -t qemu

(记得将此命令添加到诸如rc.local使其永久化的命令中)

  • 配置 qemu 接口(使用ip/ifconfig或其他操作系统提供的工具)为其分配一个空闲的 /24 子网。该子网也需要在您的来宾操作系统中设置。然后使用 运行 qemu -net tap,ifname=qemu,script=off。再次配置来宾操作系统网络。

qemu然后您可以轻松过滤由虚拟接口表示的来宾操作系统流量:

iptables -I FORWARD -i qemu -m multiport --dports ports -j DROP

应该管用。

但 NAT 停止工作了。如果您需要使 NAT 再次工作,您应该添加一条规则来修补从您的计算机发出的 IP 地址。如果您有eth0所有流量都经过的接口,则为其启用 NAT:

iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE

答案2

-netdev user我想补充一点,如果您使用默认 ( ) 网络,则有一些更简单的防火墙规则。

iptables -I OUTPUT -o lo -m owner --uid-owner qemu-user -d 127.0.0.1 -j DROP

请注意,您必须在用户下运行 qemu qemu-user,您可以使用sudo -u qemu-user qemu-system-x86_64 -enable-kvm ......

这会阻止主机的所有端口在来宾上可见,而无需指定它们(如第一个答案中所示)。请注意,目标地址是127.0.0.1而不是10.0.2.2(访客默认看到主机的地址)的原因是因为 qemu 执行 NAT 的方式。

如果您有兴趣,这里有一些有关 qemu 如何处理默认网络的详细信息:

Qemu 拦截从虚拟化网卡飞出的原始链路层数据包完成的 TCP 和 UDP 连接,并将它们转换为 qemu 进程本身执行的相应连接,通过调用socket(), connect(), sendto(), recvfrom()... 在这样做的同时,它还执行一些地址转换,因此到10.0.2.2和 的连接分别10.0.2.3转换为到127.0.0.1和 的连接127.0.0.53。这就是为什么OUTPUT链式规则会删除 qemu 与 的连接127.0.0.1,使主机对访客不可见,除了主机中的 DNS 服务器(以及 qemu 内部模拟的 DHCP 服务器,但这都是在 qemu 内部完成的)。

在这里,您可以看到当来宾使用10.0.2.3( nslookup google.com 10.0.2.3) 解析 dns 域时,q​​emu 执行的网络相关系统调用:

$ sudo strace -f -e trace=network -p <qemu_pid>
strace: Process 14529 attached with 10 threads
[pid 14529] socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP) = 99
[pid 14529] sendto(99, "\236\353\1\0\0\1\0\0\0\0\0\0\6google\3com\0\0\1\0\1", 28, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, 16) = 28
[pid 14529] recvfrom(99, "\236\353\201\200\0\1\0\1\0\0\0\0\6google\3com\0\0\1\0\1\300\f\0\1"..., 1500, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, [128->16]) = 44
[pid 14529] socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP) = 100
[pid 14529] sendto(100, "@R\1\0\0\1\0\0\0\0\0\0\6google\3com\0\0\34\0\1", 28, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, 16) = 28
[pid 14529] recvfrom(100, "@R\201\200\0\1\0\1\0\0\0\0\6google\3com\0\0\34\0\1\300\f\0\34"..., 1500, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, [128->16]) = 56

如您所见,10.0.2.3被翻译为127.0.0.53.当来宾与此地址通信时,Qemu 仅允许 UDP 流量到达端口 53,因此主机不会进一步暴露,除了其 dns 服务器守护程序之外。

相关内容