设置
在主持人使用 Debian Bookworm 服务器我创建了两个 VM-s (服务端192.168.122.227 和pagent-1通过 cockpit (kvm) 连接到 192.168.122.126。它们都运行 Debian Bullseye。我使用的是默认网络。
此时一切正常,我可以从其中任意一个访问网络。
由于我只有一个 IPv4 地址,所以无法使用网桥,所以我想从主持人到服务端。所以我创建/etc/libvirt/hooks/qemu
了主持人:
#!/bin/bash
# Source: https://wiki.libvirt.org/Networking.html#Forwarding_Incoming_Connections
if [ "${1}" = "pserver" ]; then
GUEST_IP=192.168.122.227
if [ "${2}" = "stopped" ] || [ "${2}" = "reconnect" ]; then
/sbin/iptables -D FORWARD -o virbr0 -p tcp -d $GUEST_IP --dport 80 -j ACCEPT
/sbin/iptables -t nat -D PREROUTING -p tcp --dport 80 -j DNAT --to $GUEST_IP:80
/sbin/iptables -D FORWARD -o virbr0 -p tcp -d $GUEST_IP --dport 443 -j ACCEPT
/sbin/iptables -t nat -D PREROUTING -p tcp --dport 443 -j DNAT --to $GUEST_IP:443
fi
if [ "${2}" = "start" ] || [ "${2}" = "reconnect" ]; then
/sbin/iptables -I FORWARD -o virbr0 -p tcp -d $GUEST_IP --dport 80 -j ACCEPT
/sbin/iptables -t nat -I PREROUTING -p tcp --dport 80 -j DNAT --to $GUEST_IP:80
/sbin/iptables -I FORWARD -o virbr0 -p tcp -d $GUEST_IP --dport 443 -j ACCEPT
/sbin/iptables -t nat -I PREROUTING -p tcp --dport 443 -j DNAT --to $GUEST_IP:443
fi
fi
我的问题
完成此操作后,将 SSH 更改为主持人有效,但sudo apt update
两者服务端和pagent-1失败,因为它无法到达deb.debian.org
。在主持人一切正常。
在服务端:
sudo apt update
Err:1 http://deb.debian.org/debian bullseye InRelease
Cannot initiate the connection to debian.map.fastlydns.net:80 (2a04:4e42:8e::644). - connect (101: Network is unreachable) Could not connect to debian.map.fastlydns.net:80 (146.75.122.132), connection timed out Cannot initiate the connection to deb.debian.org:80 (2a04:4e42:8e::644). - connect (101: Network is unreachable)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.
W: Failed to fetch http://deb.debian.org/debian/dists/bullseye/InRelease Cannot initiate the connection to debian.map.fastlydns.net:80 (2a04:4e42:8e::644). - connect (101: Network is unreachable) Could not connect to debian.map.fastlydns.net:80 (146.75.122.132), connection timed out Cannot initiate the connection to deb.debian.org:80 (2a04:4e42:8e::644). - connect (101: Network is unreachable)
W: Some index files failed to download. They have been ignored, or old ones used instead.
我可以 ping 它,但是无法 wget 它:
ping deb.debian.org
PING debian.map.fastlydns.net (146.75.122.132) 56(84) bytes of data.
64 bytes from 146.75.122.132 (146.75.122.132): icmp_seq=1 ttl=59 time=5.33 ms
64 bytes from 146.75.122.132 (146.75.122.132): icmp_seq=2 ttl=59 time=5.37 ms
wget http://deb.debian.org/debian/
--2023-11-24 10:52:59-- http://deb.debian.org/debian/
Resolving deb.debian.org (deb.debian.org)... 146.75.122.132, 2a04:4e42:8e::644
Connecting to deb.debian.org (deb.debian.org)|146.75.122.132|:80...
它就卡在那里了。
我是否意外地将 iptables 规则制定得太宽泛或者可能覆盖了一些 iptables 规则?
答案1
DNAT 规则不会过滤它们将应用到的内容:因此它们适用于所有内容:Internet 发起的流量以及 VM 发起的流量。使用端口 80 或 443 的任何内容始终会重定向到 VM 192.168.122.227,包括来自该 VM 本身或其他 VM 的流量(主机本身不受影响,这需要 nat/OUTPUT 规则)。当从 VM 使用 HTTP 或 HTTPS 时,这会创建一个循环(但允许 ICMP ping 工作,使诊断更加困难)。
应该修改 qemu 钩子脚本中的四个 DNAT 规则,使它们不会影响虚拟机(还引入了 libvirt 桥接名称的参数):
...
GUEST_BRIDGE=virbr0
...
/sbin/iptables -t nat -D PREROUTING ! -i "$GUEST_BRIDGE" -p tcp --dport 80 -j DNAT --to $GUEST_IP:80
...
/sbin/iptables -t nat -D PREROUTING ! -i "$GUEST_BRIDGE" -p tcp --dport 443 -j DNAT --to $GUEST_IP:443
...
/sbin/iptables -t nat -I PREROUTING ! -i "$GUEST_BRIDGE" -p tcp --dport 80 -j DNAT --to $GUEST_IP:80
...
/sbin/iptables -t nat -I PREROUTING ! -i "$GUEST_BRIDGE" -p tcp --dport 443 -j DNAT --to $GUEST_IP:443
...
当流量从桥接器(即虚拟机)发起时,该规则将不适用:虚拟机发起的流量不会改变,也不会循环回到虚拟机。规则集的其余部分可能也应该更改以重复使用"$GUEST_BRIDGE"
。
如果桥接接口不是预先知道的或者不是默认的virbr0
(但为了简单起见仍然是一个桥接),则可以从virsh xmldump
提供给脚本的隐式虚拟机的属性中检索它标准输入通过(安装和)使用xmlstarlet
. 将该GUEST_BRIDGE
行替换为:
GUEST_BRIDGE="$(xmlstarlet select -t -m 'domain/devices/interface' -v 'source/@bridge')"
xmlstartlet
的用法有点复杂,但甚至用在这个libvirt 钩子脚本示例重要的是提供虚拟机的属性(XML 格式)只有一次到标准输入。如果需要检索其他参数,则必须在同一次拍摄中完成。