在 KVM 虚拟机和主机之间设置 NAT 网络的正确方法是什么?
KVM虚拟机:
未安装防火墙
$ sudo arp-scan -r 5 -t 1000 --interface=eth0 --localnet
10.0.2.2 52:55:0a:00:02:02 locally administered
10.0.2.3 52:55:0a:00:02:03 locally administered
$ ip r
default via 10.0.2.2 dev eth0 proto dhcp metric 100
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100
是否配置
eth0: inet 10.0.2.15 netmask 255.255.255.0 broacast 10.0.2.255
ether 52:54:00:12:34:56
lo: inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1
主持人:
:~$ ip r
0.0.0.0/1 via 10.211.1.10 dev tun0
default via 192.168.1.1 dev wlan0 proto dhcp metric 600
10.21xxxxxxxx dev tun0 proto kernel scope link src 10.21xxxxx
xxxxxxxxxxxx dev wlan0
128.0.0.0/1 via 10.211.1.10 dev tun0
192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.172 metric 600
192.168.4.0/22 dev eth0 proto kernel scope link src 192.168.4.8 metric 100
:~$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.2.3 netmask 255.0.0.0 broadcast 10.255.255.255
inet6 fe80::76c8:79b4:88d4:7f5c prefixlen 64 scopeid 0x20<link>
ether ec:8e:b5:71:33:6e txqueuelen 1000 (Ethernet)
RX packets 1700 bytes 194730 (190.1 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2862 bytes 246108 (240.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 16 memory 0xe1000000-e1020000
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 13251 bytes 7933624 (7.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 13251 bytes 7933624 (7.5 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500
inet 10.211.1.69 netmask 255.255.255.255 destination 10.211.1.70
inet6 fe80::a920:941c:ffa8:5579 prefixlen 64 scopeid 0x20<link>
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 100 (UNSPEC)
RX packets 4348 bytes 2242726 (2.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3823 bytes 404190 (394.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.172 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::651b:5014:7929:9ba3 prefixlen 64 scopeid 0x20<link>
ether d8:55:a3:d5:d1:30 txqueuelen 1000 (Ethernet)
RX packets 114455 bytes 117950099 (112.4 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 67169 bytes 14855011 (14.1 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
~$ sudo arp-scan -r 5 -t 1000 --localnet
just hangs......
主机无法 ping 10.0.2.2
未启用防火墙
尝试过
$ sudo ip route add default via 10.0.2.0
$ sudo ip route add default via 10.0.2.2
$ sudo ip route add default via 10.0.2.0/24
没有 virsh NAT 还能工作吗?
可以仅从命令行修复 NAT 吗?
更新:
$ sudo ip link add natbr0 type bridge
$ sudo ip link set dev natbr0 up
$ sudo ip link set dev eth0 up
$ sudo ip link set dev eth0 master natbr0
可以将 eth0 从属设备桥接到 kvm - vm 可以 ping 网络上的其他计算机。但不能 ping 主机@Tom Yan 的答案结合archlinux-Network_bridge上面创建的命令可以 ping 其他网络 ip
因此我尝试改变工作桥接连接以允许主机和 kvm 进行通信。
Goal: host$ ping kvm
$ sudo ip link add natbr0 type bridge
$ sudo ip link set dev natbr0 up
$ sudo ip a add 10.0.2.1/24 dev natbr0
$ sudo kvm -m 3G -hdb /dev/sde -nic bridge,br=natbr0
kvm$ sudo ip link add natbr0 type bridge
kvm$ sudo ip a add 10.0.2.2
kvm$ sudo ip link set dev natbr0 up
kvm can ping it self
$ ping 10.0.2.2
PING 10.0.2.2 (10.0.2.2) 56(84) bytes of data
64 bytes from 10.0.2.2: icmp_seq=1 ttl=64 time=0.027 ms
但 kvm$ping 10.0.2.1
Destination Host Unreachable
主机$ ping 10.0.2.2
(just hangs)
更喜欢使用命令行来测试流程/系统基本框架的弹性,而不是使用大量可能更容易出现故障的脚本。- 命令行是否有效,错误更容易被追踪、隔离和重现。根据 Linux 版本,某些脚本/脚本部分(如包含在提供的 xml 替代解决方案中的脚本)可能有效或无效。如果可以通过执行上述命令在任何 Linux 版本上重现与 kvm 的桥接……那么似乎也可以使用 cli 命令实现 kvm NAT - 只是为了澄清这篇文章的要点,NAT kvm 的 cli 步骤将更加标准化,因此更可取。
通常@NikitaKipriyanov 的答案是正确的,这是答案,但需要对命令进行调整
$ sudo kvm -m 3G -hdb /dev/sde -net nic -net 用户,hostfwd=tcp::1810-:22
使用命令 tweak vm 可以像默认一样与互联网通信,也可以通过 ssh 与主机通信。感谢@NikitaKipriyanov 和@cnst 对 tweak 的贡献https://stackoverflow.com/a/54120040
用户需要使用本地主机地址通过端口 1810 进行 ssh
$ ssh p@localhost -p 1810
答案1
NAT 的常见想法是看不到已翻译的地址。您没有通往这些地址的路线。它们对您来说并不存在。您只能看到这些地址被翻译成的地址。
QEMU 的情况也没什么不同。在这种情况下,您的主机在“外部”,您的虚拟机在“内部”,因此虚拟机永远无法通过其分配的地址进行访问。您有虚拟机的 10.0.2.2/24 地址,但当它到达互联网时,其数据包会被转换为 192.168.1.172通过 QEMU 进程,因此主机将这些数据包视为由 QEMU 进程创建的,并将它们视为任何其他数据包(例如,来自本地运行的 Web 浏览器或类似的东西)。
如何从主机访问虚拟机?当我们有 NAT 时,为了访问隐藏在其后面的主机,我们安装基因转移酶规则。同样,QEMU 的情况也没有什么不同,你必须在其中设置一些规则,然后你就可以从主机(或者如果你想的话,从其他主机)与虚拟机进行通信,方法是将数据包发送到虚拟机的选定端口。主持人地址。
根据QEMU 文档,要将 DNAT 规则设置到其用户模式 NAT 中,请使用子句hostfwd
。让我们将以下内容引入其命令行:
-netdev user,id=usernet0,hostfwd=tcp::11111-:22 \
-device virtio-net-pci,netdev=usernet0,mac=08:00:27:92:B0:51
然后,tcp 端口 11111 将被我机器上的进程占用qemu-system-x86_64
,如果你连接到本地主机端口 11111,将连接到虚拟机的端口 22。
一般形式为hostfwd=hostip:hostport-guestip:guestport
,若省略hostip
,则为localhost,若省略guestip
,则为访客网络内的第一个“非网关”地址。
我注意到有人提到了你virsh
。你在跑步吗libvirt
?那么这个问题是重复的;请参阅评论。
答案2
您可以使用网桥,而无需将 VM 主机上的任何物理以太网接口束缚于它。
假设我们坚持选择子网10.0.2.0/24
(这不是必要的):
# ip l add natbr0 type bridge
# ip a add 10.0.2.1/24 dev natbr0
然后创建以下文件:
$ echo 'allow natbr0' | sudo tee /etc/qemu/bridge.conf
allow natbr0
然后使用例如-nic bridge,br=natbr0
或启动 qemu -netdev bridge,br=natbr0,id=nb0 -device virtio-net,netdev=nb0
,它将tap
以动态方式将您的虚拟机连接到桥接器(即,tap
一旦虚拟机关闭,接口将被删除)。
您还需要在虚拟机上配置静态 IP:
# ip a add 10.0.2.2/24 dev ens3
# ip r add default via 10.0.2.1
除非您还在主机上设置了 DHCP 服务器(例如使用 dnsmasq)。不要忘记配置在 VM 内部使用的 DNS 服务器。
请注意,使用相同网桥的虚拟机可以相互通信,除非您通过某种方式(例如 ebtables)阻止这种通信。
default
仅当您希望 VM 能够访问“外部”时,路由(和要使用的 DNS 服务器)才是必需的。如果您只需要它能够与 VM 主机通信,则应跳过第二条命令并停止阅读。(好吧,阅读P.S.
)
如果您不想在虚拟机中使用特定的“公共”DNS 服务器,那么最好将主机上的 dnsmasq 配置为 DNS 转发器,尽管使用 DNAT 将 DNS 请求转发到 eg 应该192.168.1.1
适用于基本 DNS 请求。
然后您需要启用 IP 转发:
# sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
如果你想避免从/到某个网络接口进行 IP 转发(例如 tun0
)出于安全原因,您需要设置防火墙。例如:
# iptables -A FORWARD -i tun0 -j DROP
# iptables -A FORWARD -o tun0 -j DROP
由于您有 (VPN) 隧道路由,该default
路由实际上会覆盖路由,因此从虚拟机到 Internet 的流量也将进入隧道(除非您添加了上述示例规则)。如果您希望流量通过路由器,则需要策略路由。例如:
# ip ru add iif natbr0 lookup table 123
# ip r add 192.168.1.1 dev wlan0 table 123 # probably optional
# ip r add default via 192.168.1.1 table 123
您还可以阻止虚拟机访问 LAN 主机:
# iptables -A FORWARD -i natbr0 -d 192.168.1.0/24 -j DROP
-I
如果您要将 DNS 请求重定向到路由器,请做出例外(请注意):
# iptables -I FORWARD -i natbr0 -d 192.168.1.1 -p tcp --dport 53 -j ACCEPT
# iptables -I FORWARD -i natbr0 -d 192.168.1.1 -p udp --dport 53 -j ACCEPT
最后,配置 iptables 以便为您的 VM 子网动态执行 SNAT(根据出站接口):
# iptables -t nat -A POSTROUTING -s 10.0.2.0/24 -j MASQUERADE
请注意,这并非旨在阻止某些来自“外部”(您的物理 LAN 主机或 Internet;VM 主机不计算在内)的流量到达您的 VM。当来自 VM 的响应流量的源地址在转发出去之前发生更改时,它只会中断通信。为了正确隔离,您需要在链中设置(额外的)适当规则FORWARD
。如果您有这样的需要,请考虑在那里进行“有状态”设置。
此外,您可以将 DNS 请求从虚拟机重定向到主机到您的路由器:
iptables -t nat -A PREROUTING -d 10.0.2.1 -p udp --dport 53 -j DNAT --to-destination 192.168.1.1
iptables -t nat -A PREROUTING -d 10.0.2.1 -p tcp --dport 53 -j DNAT --to-destination 192.168.1.1
这或多或少允许您将其用作10.0.2.1
VM 中的 DNS 服务器。
PS 上述所有操作(除了创建 / 写入/etc/qemu/bridge.conf
)都是易失性的,也就是说,一旦您重新启动,它们就会消失(除非您的发行版做了一些愚蠢的事情)。我不会深入研究如何使它们持久化,因为有不同的方法/方法,并且它可能特定于发行版。