Firewall blocks internet on bridge in KVM virtual machine

I was using the internet on my KVM virtual machines without issue some time earlier in the year (probably around July). I went several months without using them, and now when I boot a virtual machine it doesn’t have internet unless I disable the firewall on my machine. The bridge network still appears to be fine, and I haven’t changed any network settings.

It appears as though some update has made it so that the default firewall settings block internet access for the virtual machines. So far, I’ve just been disabling the firewall to get the internet working, but surely there’s a better way to go about it. Does anyone happen to know what rules need to be added in order to allow KVM virtual machines to have internet access via br0 without simply disabling the firewall?

Some more details would be useful. I can only assume that you have firewalld active on the host? If so,

sudo firewall-cmd --list-all

Just in case this is relevant…

firewalld and the virtual network driver If firewalld is active on the host, libvirt will attempt to place the bridge interface of a libvirt virtual network into the firewalld zone named “libvirt” (thus making all guest->host traffic on that network subject to the rules of the “libvirt” zone). This is done because, if firewalld is using its nftables backend (available since firewalld 0.6.0) the default firewalld zone (which would be used if libvirt didn’t explicitly set the zone) prevents forwarding traffic from guests through the bridge, as well as preventing DHCP, DNS, and most other traffic from guests to host. The zone named “libvirt” is installed into the firewalld configuration by libvirt (not by firewalld), and allows forwarded traffic through the bridge as well as DHCP, DNS, TFTP, and SSH traffic to the host - depending on firewalld’s backend this will be implemented via either iptables or nftables rules. libvirt’s own rules outlined above will always be iptables rules regardless of which backend is in use by firewalld.
NB: It is possible to manually set the firewalld zone for a network’s interface with the “zone” attribute of the network’s “bridge” element.
NB: Prior to libvirt 5.1.0, the firewalld “libvirt” zone did not exist, and prior to firewalld 0.7.0 a feature crucial to making the “libvirt” zone operate properly (rich rule priority settings) was not implemented in firewalld. In cases where one or the other of the two packages is missing the necessary functionality, it’s still possible to have functional guest networking by setting the firewalld backend to “iptables” (in firewalld prior to 0.6.0, this was the only backend available).

More info:

Hi
I don’t use a firewall, but this seemed to work…


firewall-cmd --permanent --direct --passthrough ipv4 -I FORWARD -i br0 -j ACCEPT
firewall-cmd --permanent --direct --passthrough ipv4 -I FORWARD -o br0 -j ACCEPT
systemctl restart firewalld

Yes, sorry. My post wasn’t clear. I’ve, even since back when the internet did work on the virtual machines, had a firewall active on the host. I’ve also not modified any firewall settings what-so-ever (no custom rules, nothing extra enabled, nothing disabled). I’m assuming that something has either modified the default firewall rules or otherwise modified the behavior of the firewall with respect to the bridge network since around July (since I’ve not changed any settings and it worked then). I’m wondering if maybe there are some rules that were supposed to be automatically added / altered as part of an update, but maybe for some reason that’s not happened on my machine. Or maybe this is the expected behavior and the VM isn’t supposed to have network access when the firewall is active with the default settings?

firewall-cmd --list-all     
public
  target: default
  icmp-block-inversion: no
  interfaces:  
  sources:  
  services: dhcpv6-client
  ports:  
  protocols:  
  masquerade: no
  forward-ports:  
  source-ports:  
  icmp-blocks:  
  rich rules: 

I’ll give this a shot later. I wonder these rules used to be automatically present?

I can only share the link to the libvirt firewalld info I gave already, and that refers to the existence of the ‘libvirt’ zone (created automatically). Perhaps check

firewall-cmd --list-all --zone libvirt

Your existing configuration doesn’t have any interface explicitly listed as part of the public zone

I’ll give this a shot later. I wonder these rules used to be automatically present?

Yes, worth a shot (as a means to an end), although from what I can gather libvirt should work with firewalld automatically for recent versions of both.

More info about available zones and what is active currently…

firewall-cmd --get-zones
firewall-cmd --get-active-zone

Hi
I see the following;


firewall-cmd --list-all --zone libvirt

Error: INVALID_ZONE: libvirt

firewall-cmd --get-zones

block dmz drop external home internal public trusted work

firewall-cmd --get-active-zone

public
  interfaces: eth0 br0 tap0

Mine also does not have a libvirt zone.

After digging further, it appears as though such zone should not be necessary as my firewalld.conf sets the backend to iptables.

The default zone was also set to public, so both br0 and the ethernet device were actually in public. I went ahead and placed them explicitly in the public zone to see if it made a difference. It did not.

For now I’ll just stick with the iptables rules to get things going.

No, that won’t help. I didn’t see any interfaces listed in the public zone output you shared earlier in any case.

For now I’ll just stick with the iptables rules to get things going.

Yes, that’s probably the easiest thing to do for now.

Am wondering if your HostOS has more than one network interface (defined as excluding localhost).
Also,

Is your guest configured with a static address or as a DHCP client (whether you have a reserved lease or not)?

And,
What do you mean by you can’t access the Internet?
Particularly if your Guest is configured as DHCP client, what is its network configuration, has it been acquired an IP address and network configuration from your DHCP server?
Regardless whether your Guest is configured as a DHCP client or not, is it able to ping or otherwise access resources in your LAN (unless you connect directly to the Internet with PPOE or something similar), so for instance did you ping your Internet Gateway router by IP address and possibly by name?

The reason why I’m proposing the above questions is that for the most basic configuration, your Guest will be accessing the network (and Internet) using the exact same ports at the HostOS, and assuming that your br0 is configured as a plain bridging device and bound to the only network interface on the HostOS, then your HostOS firewall should not be blocking your Guest…In other words, for anything that your HostOS can access, your GuestOS should have same access assume the GuestOS firewall isn’t blocking.

Note that I’m assuming that your virtualization was set up by running the YaST “install virtualization” module.
If you instead did things on your own like installing and configuring your own br0 and especially if you installed and are running through a virtual switch, those kinds of things can greatly alter the overall picture.

So,
Am exploring whether you really understand what is working or not, hopefully if you discover something new like a name resolution or network configuration issue, we can pin down exactly what needs to be addressed.

TSU

I have exactly the same problem.
And I cannot understand why DHCP traffic is blocked. I don’t have the libvirt zone.

In my case, I have configured everything via ansible.
So, I have them:


sudo firewall-cmd --list-all 
public (active) 
  target: default 
  icmp-block-inversion: no 
  interfaces: eth0 desktop_virt 
  sources:  
  services: ssh kdeconnect-kde libvirt-tls dhcp 
  ports:  
  protocols:  
  masquerade: no 
  forward-ports:  
  source-ports:  
  icmp-blocks:  
  rich rules:

And the following:



nmcli connection  
NAME              UUID                                  TYPE      DEVICE      
desktop_virt        45bc9ba8-8120-4bc5-93f4-168f28687f88  bridge    [FONT=monospace]desktop_virt  
desktop_virt-slave  baad34ea-f9a9-4f4b-aeed-9ff4601baa98  ethernet  eth0        
vnet0             2bcc1100-95e9-4f7f-97fc-99d895aa6228  tun       vnet0 


I added the vnet0 in the public zone. No change.
The only way to get the DHCP working (and thus I am suspecting any network traffic) is to disable firewalld.

My package versions are:
[/FONT]
[FONT=monospace]libvirt-6.0.0-lp152.9.6.2.x86_64[/FONT]
[FONT=monospace][FONT=monospace]firewalld-0.5.5-lp152.6.3.noarch

So, any solution?

[/FONT][/FONT]

If you are using docker on your computer (not on the VM) try the following either before launching the VM:

sudo iptables -I FORWARD -i br0 -o br0 -j ACCEPT

I came across this after hours of googling and what I remember is that docker adds a rule to reject this.

With my windows VM, if I forget to do this before launch, I can do it after launch and after a short time the VM gets accessed.

The answer to this is hidden in the libvirt documentation.
Actually, it’s quite straight forward and it is documented but in the wrong place.

In the https://wiki.libvirt.org/page/Networking#Forwarding_Incoming_Connections we see that we have to modify the sysctl entries:

# cat >> /etc/sysctl.conf <<EOF  net.bridge.bridge-nf-call-ip6tables = 0
 net.bridge.bridge-nf-call-iptables = 0
 net.bridge.bridge-nf-call-arptables = 0
 EOF
 # sysctl -p /etc/sysctl.conf

The web page implies that you have to do it when you use the network service (since it’s under this section and not as a general comment).
But you have to do it always.

After that, you don’t need any tricky forwarding rules.

Great info. It works for me.