我在 Arch Linux 5.1.2 上的 QEMU 中使用虚拟 tap 网络运行 OpenWrt。tap0 设备(放置在默认 br-lan 子网中)无法访问其自身子网之外的其他(来宾)子网(例如通过 ping)。这很可疑,仅发生在 QEMU 中(部署在真实硬件上的客户端能访问其他子网)。Arch Linux 作为客户机可以正常工作(在 QEMU 中)。
这可能不是 OpenWrt 中的错误,而是一个安全功能,但我无法弄清楚具体是什么。我主要需要它用于每个都有自己子网的 LXC 容器。为了演示目的(如下),我将使用虚拟以太网适配器作为“目标”接口/子网。
为了了解我所看到的情况,我认为最好的方法是建立一个会受到问题影响的最小系统:
- 下载OpenWrt镜像:https://downloads.openwrt.org/releases/18.06.2/targets/x86/64/openwrt-18.06.2-x86-64-combined-ext4.img.gz并将其解压到 /tmp
- 创建主机网络环境:
#!/bin/bash
if [[ ! $(cat /proc/net/dev |grep br0) ]]; then
echo "Creating bridge"
#Make sure nothing interferes with bridges
#systemctl stop NetworkManager.service
sysctl net.ipv4.ip_forward=1 >/dev/null 2>&1
ip tuntap add tap0 mode tap user 1000
ip tuntap add tap1 mode tap user 1000
ip link set tap0 up
ip link set tap1 up
ip link add dev br0 type bridge
ip link add dev br1 type bridge
ip link set tap0 master br0
ip link set tap1 master br1
ip addr add 192.168.99.99/24 broadcast 192.168.99.255 dev br0
ip addr add 192.168.10.1/24 broadcast 192.168.10.255 dev br1
ip link set dev br0 up
ip link set dev br1 up
ip route add 192.168.2.0/24 dev br0
iptables -t nat -A POSTROUTING -s 192.168.10.0/24 ! -d 192.168.10.0/24 -j MASQUERADE
else
echo "Removing bridge"
ip tuntap del tap0 mode tap
ip tuntap del tap1 mode tap
ip link del dev br0 type bridge
ip link del dev br1 type bridge
sysctl net.ipv4.ip_forward=0 >/dev/null 2>&1
iptables -t nat -D POSTROUTING -s 192.168.10.0/24 ! -d 192.168.10.0/24 -j MASQUERADE
#systemctl start NetworkManager.service
fi
- 启动 QEMU:
#!/bin/bash
image=/tmp/openwrt-18.06.2-x86-64-combined-ext4.img
qemu="qemu-system-x86_64 \
-enable-kvm \
-cpu max \
-smp 4 \
-m 1G \
-boot c \
-drive id=disk0,if=none,format=raw,file=${image} \
-device virtio-blk-pci,drive=disk0 \
-device virtio-net,netdev=tap0 \
-device virtio-net,netdev=tap1 \
-netdev tap,id=tap0,ifname=tap0,script=no,downscript=no \
-netdev tap,id=tap1,ifname=tap1,script=no,downscript=no \
-serial mon:stdio \
-device qxl-vga \
-device piix3-usb-uhci \
-device usb-tablet \
"
${qemu}
echo -e "\n\033[1;35mBack at host!\033[0m\n"
- 在 OpenWrt 文本(不是 gfx)控制台上按(Enter)并复制粘贴:
uci set network.lan.ipaddr='192.168.99.1'
uci set network.lan.broadcast='192.168.99.255'
uci set network.wan.proto='static'
uci set network.wan.ipaddr='192.168.10.100'
uci set network.wan.netmask='255.255.255.0'
uci set network.wan.broadcast='192.168.10.255'
uci set network.wan.gateway='192.168.10.1'
uci set network.wan.dns='208.67.222.222'
uci commit
service network restart
opkg update
opkg install ip-full nano less-wide grep xz strace tar wget kmod-dummy ca-certificates
opkg find coreutils* |awk {'print $1}'| xargs opkg install --force-overwrite
opkg find procps-ng* |awk {'print $1}'| xargs opkg install --force-overwrite
ip addr add 192.168.2.1/24 broadcast 192.168.2.255 dev dummy0
ip link set dev dummy0 up
- 做一些测试:
- 客人方面:
ping -I 192.168.99.1 192.168.99.99 (ok)
ping -I 192.168.99.1 192.168.2.1 (ok)
ping -I 192.168.2.1 192.168.99.1 (ok)
ping -I 192.168.2.1 192.168.99.99 (failed)
- Do these when pinging from host:
tcpdump -n -i any -v (who-has 192.168.2.1 tell 192.168.99.99)
tcpdump -n -i br-lan -v (who-has 192.168.2.1 tell 192.168.99.99)
tcpdump -n -i dummy0 -v (nothing...)
- 在主机端:
ping -I 192.168.99.99 192.168.99.1 (ok)
ping -I 192.168.99.99 192.168.2.1 (failed)
接口/子网 (192.168.2.1) 无法访问(从 tap 设备),也无法连接到主机桥 (192.168.99.99)。我检查/更改了几个值,例如“arp_ignore”和“rp_filter”,但无济于事:
for i in /proc/sys/net/ipv4/conf/dummy0/*; do echo "${i} "$(cat ${i}); done
如上所述,这只发生在带有 OpenWrt 的 QEMU 中,我不知道为什么。我已经刷新/清理了所有 iptables/chains/rules,将所有策略设置为 ACCEPT,删除了所有接口并手动创建它们(eth0、dummy0、bridges、eth1),检查了路由和 ARP 条目并启用了混杂模式。一切看起来都很好,但它不起作用。不知何故,OpenWrt 不喜欢那个虚拟适配器。没有“martian”数据包(如果您启用该日志记录模式)。
知道这里是什么问题吗?
答案1
ip 路由添加 192.168.2.0/24 dev br0
这不对。必须将其发送给客户端在后面桥接器而不仅仅是桥接器 (br0)。这有点令人困惑,因为 ARP 数据包在桥接器后面的整个子网上都是可见的。
正确的命令是:
ip route 通过 192.168.99.1 添加 192.168.2.0/24 dev br0