Evian
Evian

Reputation: 1197

Manually implement NAT networks for QEMU VMs in Linux host

Environment

Host: Ubuntu 22.04, kernel 5.19.0, physical interface name enp5s0

QEMU: 6.2.0

Aim

Manually implement a NAT network for VMs spawned by QEMU.

Subnet for VMs is 10.8.20.0/24, VMs can ping host via 10.8.20.2, host can ping each VM. VM can access internet. All VMs interfaces are in a bridge nat-bridge in namespace nat-ns.

My Settings

# Create namespace which is used by all VMs
ip netns add nat-ns

# Create bridge which is used by all VMs
ip netns exec nat-ns ip link add nat-bridge type bridge
ip netns exec nat-ns ip link set dev nat-bridge up

# This veth pair is used for control internet connection.
# `wwwa` side for internet, `wwwb` side for inner subnet
ip link add nat-wwwa type veth peer nat-wwwb
ip addr add 10.8.20.1/24 dev nat-wwwa
ip link set dev nat-wwwa up
ip link set nat-wwwb netns nat-ns
ip netns exec nat-ns ip link set dev nat-wwwb up
ip netns exec nat-ns ip link set nat-wwwb master nat-bridge

# This veth pair is used for host-guest communications
# `hosta` side for communicate, `hostb` side is plugged into bridge
ip netns exec nat-ns ip link add nat-hosta type veth peer nat-hostb
ip netns exec nat-ns ip link set nat-hostb master nat-bridge
ip netns exec nat-ns ip addr add 10.8.20.2/24 broadcast 10.8.20.255 dev nat-hosta
ip netns exec nat-ns ip link set dev nat-hosta up
ip netns exec nat-ns ip link set dev nat-hostb up

# Add default route to go through nat-wwwa
ip netns exec nat-ns ip route add default via 10.8.20.1

# Setup NAT for subnet 10.8.20.0/24
iptables -t nat -A POSTROUTING -s 10.8.20.0/24 -o enp5s0 -j MASQUERADE
iptables -A FORWARD -i enp5s0 -o nat-wwwa -j ACCEPT
iptables -A FORWARD -o enp5s0 -i nat-wwwa -j ACCEPT

# Create TAP interface for VM to use
ip netns exec nat-ns ip tun tap add nat-vm-tap mode tap
ip netns exec nat-ns ip link set nat-vm-tap master nat-bridge
ip netns exec nat-ns ip link set dev nat-vm-tap up

When using QEMU, I passed the following options to use tap:

-netdev tap,id=tap0,ifname=nat-vm-tap,script=no,downscript=no -device virtio-net,netdev=tap0

Inside guest, I claim the interface's ip with 10.8.20.5

After above settings, now I have:

Problem

Host can ping guest, guest can ping host, host can ping internet with nat-hosta interface, guest cannot ping internet. This is the problem.

Notes

First, I don't want to change any settings for my physical network interface, i.e. enp5s0, so I don't make it belong to my newly created bridge.

I don't use Libvirt for some other reasons, so I just manually implement such things for basic QEMU/KVM.

I want to control whether my VM can access Internet or not, by just attaching/detaching the veth pair nat-wwwa/nat-wwwb to nat-bridge.

Upvotes: 0

Views: 868

Answers (1)

Clevin
Clevin

Reputation: 1

My recommendation would be to check the DNS settings /etc/resolv.conf on the guest VM to make sure it has a valid DNS server IP address. Another way would be to temporarily disable firewall rules blocking outgoing internet traffic from the guest VM or allow outgoing connections

Upvotes: 0

Related Questions