If you’ve configured firewall settings in QubesOS, you’ve probably bumped into its limitations. Many sites aren’t usable with the firewall because they pull resources from too many domains, or the domains don’t resolve to the same IPs reliably (they might use round-robin DNS, or resolve differently depending on what region your VPN is connecting from, or who-knows-what-else). Sometimes we’re forced to turn off the firewall to keep the network usable.
But is there a way to compromise between firewall-on (unreliable usability, high security) and firewall-off (full usability, no security)? A firewall that dynamically updates its rules (ex. by fetching rules from the internet) provides a “better than nothing” approach in cases where a strict firewall is unviable.
Installation
Create a new App qube. Set its network connection to sys-net, and check “Provides network access”. These instructions assume the qube is named “dynamic-firewall” and assume using a Debian 12 template. Fedora should be fine too but has not been tested as much.
Before starting up the new qube, open up the template and make sure required packages are installed:
sudo apt update
sudo apt install qubes-core-admin-client git
sudo shutdown now
Then in the dynamic-firewall qube
sudo su -l
cd /rw
git clone https://github.com/likeafox/dynamic-firewall.git
echo "/rw/dynamic-firewall/install.sh" >> /rw/config/rc.local
./dynamic-firewall/install.sh
Pay attention to the output of the final ./dynamic-firewall/install.sh
, as it should print out something like “installed OK” at the end. If not, you might have a problem.
Finally, dynamic-firewall will need RPC permissions to query clients, so in dom0 make the file /etc/qubes/policy.d/50-dynamic-firewall.policy
with these contents:
admin.vm.CurrentState * dynamic-firewall @tag:dynamic-firewall-user allow target=@adminvm
admin.vm.property.List * dynamic-firewall @tag:dynamic-firewall-user allow target=@adminvm
admin.vm.property.Get * dynamic-firewall @tag:dynamic-firewall-user allow target=@adminvm
admin.vm.firewall.Get * dynamic-firewall @tag:dynamic-firewall-user allow target=@adminvm
(If you named the qube something other than “dynamic-firewall” then modify this file accordingly)
Adding clients
Say you want to attach your qube named “programming” to dynamic-firewall.
- In dom0, add the tag that will allow dynamic-firewall to query it
qvm-tags programming add dynamic-firewall-user
- Change programming’s netvm
qvm-prefs programming netvm dynamic-firewall
- In, dynamic-firewall, modify
/rw/dynamic-firewall/clients
file, adding the line:
programming github
Your programming qube will now be able to connect to all github servers.
Clients also retain all firewall rules you configured in the Qube Manager’s firewall tab. So you can mix allowing site profiles (in the clients file) with allowing specific IPs/domains (in Qubes firewall settings).
Full documentation of the clients file
- Lines are ignored if they are empty, contain only whitespace, or begin with
#
. - The first word of a line is the qube name.
- Subsequent words specify site profiles that are enabled for that qube.
- Words can be separated by an arbitrary amount of space
Example:
# qube-name profiles
programming github pypi
studying wikipedia
This configures dynamic-firewall for two client qubes. programming has access to github and pypi, while studying has access to wikipedia.
Site profiles
A site profile is the entire dynamic ruleset that comprises full access to a particular website/service.
At time of writing there are only 4 site profiles (and 2 aliases) that are able to be specified:
fastly
github
google
pypi
wikipedia
youtube
You can add more by editing sites.py
. The file is meant to be easy to modify if you have the requisite programming knowledge.
programming note: refresh functions return a list
of addresses in either plain or cidr format (ex. ["10.12.0.2", "192.168.0.0/24"]
), or False
if the address list should not be updated.
Questions for improvements
For now it only supports IPv4. What do you think, is there a compelling reason to add IPv6 support right now?
Is there a way to make RPC policy management easier? Afaik, there is no way to specify something like @netvm-client
as a class in a policy file (that would be very nice), and so we need to use tags instead.