I recently installed KVM on my laptop and all was going reasonably well until I tried to connect to the internet from one of the guests. For some reason that I couldn’t fathom at first the guest couldn’t talk to the internet and the local network couldn’t talk to the guest. This surprised me because I’d already checked that the host could reach the internet and the local network could reach the virtual bridge and the host. I was also fairly sure that I had checked my first guest could access the internet but I couldn’t be sure.
UPDATE: What do you know the interface name was wrong in the default network configuration. I hadn’t realized that libvirt was installing the rules into the firewall each time it started but once I’d changed the name of the interface in the network definition it changed automatically in the firewall.
After checking all the obvious things I started looking at the firewall on the host machine. I didn’t immediately pick the firewall as the problem because KVM adds some very lax rules and I couldn’t believe they were causing the problem. When I checked though this is what I saw:
$ sudo iptables -vL Chain INPUT (policy ACCEPT 47157 packets, 9794K bytes) pkts bytes target prot opt in out source destination 8 486 ACCEPT udp -- virbr0 any anywhere anywhere udp dpt:domain 0 0 ACCEPT tcp -- virbr0 any anywhere anywhere tcp dpt:domain 2 656 ACCEPT udp -- virbr0 any anywhere anywhere udp dpt:bootps 0 0 ACCEPT tcp -- virbr0 any anywhere anywhere tcp dpt:bootps Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- eth00 virbr0 anywhere 10.0.0.0/24 0 0 ACCEPT all -- virbr0 eth00 10.0.0.0/24 anywhere 0 0 ACCEPT all -- virbr0 virbr0 anywhere anywhere 144 8640 REJECT all -- any virbr0 anywhere anywhere reject-with icmp-port-unreachable 34 2728 REJECT all -- virbr0 any anywhere anywhere reject-with icmp-port-unreachable Chain OUTPUT (policy ACCEPT 46508 packets, 7354K bytes) pkts bytes target prot opt in out source destination 2 656 ACCEPT udp -- any virbr0 anywhere anywhere udp dpt:bootpc
At first glance everything looks correct. My VM network is 10.0.0.0/24 and there are entries in the FORWARD table. I’d already checked and turned on forwarding in sysctl as well. But wait, why is that network interface called eth00 rather than eth0 as it actually is on the machine?
To very quickly test my suspicion that these odd rules were causing the problem I added these two rules to the FORWARD table:
sudo iptables -I FORWARD -d 10.0.0.0/24 -j ACCEPT sudo iptables -I FORWARD -s 10.0.0.0/24 -j ACCEPT
These are broader than I would like but they provided the point that it was the firewall that was causing the problem. To put in a better fix first run this command to list the firewall rules with numbers:
sudo iptables -vL --line-numbers
Now use this command to delete the offending rules:
sudo iptables -D FORWARD 1
Where you replace 1 with the line number you want to delete. Note that if you start at the highest number and work backwards the line numbers don’t change as you delete items. Once you are done add two new rules like this:
sudo iptables -I FORWARD -i eth0 -o virbr0 -d 10.0.0.0/24 -j ACCPET sudo iptables -I FORWARD -i virbr0 -o eth0 -s 10.0.0.0/24 -j ACCEPT
The first rule allows connections in from the LAN (or Internet depending on how you’ve configured the rest of the system) to the guests on the virtual subnet. The second rule allows connections out from the guests to the LAN / Internet. I’m less concerned about connections outbound than I am inbound.
If you want you can tighten the first rule up by only allowing connections when the source is within the subnet of your LAN:
sudo iptables -I FORWARD -i eth0 -o virbr0 -s 192.168.1.0/24 -d 10.0.0.0/24 -j ACCEPT
I think it is reasonable to assume that connections will only be coming from within the LAN. If connections were to be coming from the wider Internet then it’s likely they would be port forwarded from a public facing machine that is on the LAN.