使用 /etc/libvirt/hooks/qemu 进行端口转发后,无法从 VM 访问 deb.debian.org

使用 /etc/libvirt/hooks/qemu 进行端口转发后,无法从 VM 访问 deb.debian.org

设置

主持人使用 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 格式)只有一次标准输入。如果需要检索其他参数,则必须在同一次拍摄中完成。

相关内容