I'd like to add that there's a bit of a simpler firewall rule if you are using default (-netdev user
) networking.
iptables -I OUTPUT -o lo -m owner --uid-owner qemu-user -d 127.0.0.1 -j DROP
Note that you must run qemu under the user qemu-user
, which you can do with sudo -u qemu-user qemu-system-x86_64 -enable-kvm ......
This blocks all ports of the host from being visible on the guest without having
to specify them (like in the first answer). Note that the reason the destination address is 127.0.0.1
and not 10.0.2.2
(the address at which the guest sees the host by default) is because of the way qemu performs NAT.
If you're interested here's some detail on how qemu deals with default networking:
Qemu intercepts the TCP and UDP connections done by the raw link-layer packets flying out of the virtualized network card and translates them to corresponding connections performed by the qemu process itself, via calls to socket()
, connect()
, sendto()
, recvfrom()
... While doing this it also performs some address translation, so connections to 10.0.2.2
and 10.0.2.3
get translated to connections to 127.0.0.1
and 127.0.0.53
respectively. This is why the OUTPUT
chain rule drops qemu's connections to 127.0.0.1
, making the host invisible to the guest except for the DNS server in the host (and the emulated DHCP server inside qemu, but this is all done internally in qemu).
Here you can see the networking related syscalls performed by qemu when the guest resolves a dns domain with 10.0.2.3
(nslookup google.com 10.0.2.3
):
$ sudo strace -f -e trace=network -p <qemu_pid>
strace: Process 14529 attached with 10 threads
[pid 14529] socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP) = 99
[pid 14529] sendto(99, "\236\353\1\0\0\1\0\0\0\0\0\0\6google\3com\0\0\1\0\1", 28, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, 16) = 28
[pid 14529] recvfrom(99, "\236\353\201\200\0\1\0\1\0\0\0\0\6google\3com\0\0\1\0\1\300\f\0\1"..., 1500, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, [128->16]) = 44
[pid 14529] socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP) = 100
[pid 14529] sendto(100, "@R\1\0\0\1\0\0\0\0\0\0\6google\3com\0\0\34\0\1", 28, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, 16) = 28
[pid 14529] recvfrom(100, "@R\201\200\0\1\0\1\0\0\0\0\6google\3com\0\0\34\0\1\300\f\0\34"..., 1500, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.53")}, [128->16]) = 56
As you can see, 10.0.2.3
gets translated to 127.0.0.53
. Qemu only allows UDP traffic to port 53 when the guest talks to this address, so the host is not further exposed, except for its dns server daemon.