Skip to content

Commit

Permalink
feat: update for Qubes OS 4.2
Browse files Browse the repository at this point in the history
BREAKING CHANGE: not backwards compatible with Qubes OS 4.1. Use v1.0.0
if you use 4.1.
  • Loading branch information
hkbakke committed Jan 9, 2024
1 parent 7109df4 commit 7a84b08
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 20 deletions.
21 changes: 15 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Description
Wireguard configuration script for Fedora 38 template in Qubes OS
Wireguard configuration script for Fedora 38 template in Qubes OS 4.2 and
later. For Qubes OS 4.1 use qubes-wireguard version 1.

After setup you will have the following:

Expand All @@ -12,8 +13,17 @@ After setup you will have the following:
* Wireguard DNS handled via Qubes' DNS DNAT rules

# Reusable wireguard template
First clone the fedora 38 template to e.g. `fedora-38-wireguard`. Then run the
template configuration script.
First create a template based on the fedora 38 template. Name the template
`fedora-38-wireguard` or some other useful name. Ensure the template has
internet access unless you have some other way to get the repository code to
the template (e.g. download via another AppVM).

mkdir -p ~/src
cd ~/src
git clone https://github.com/hkbakke/qubes-wireguard.git
cd qubes-wireguard

Then run the template configuration script.

sudo ./bin/wg-template-conf

Expand All @@ -25,15 +35,14 @@ Stop the template VM before continuing.
* You probably also want to enable `Start qube automatically on boot`

## Configuration
* Clone this repo
* Copy `config.example` to `config` and change permissions to protect it
* Create a file named `config` and change permissions to protect it. See `config.example` for syntax.

cp config.example config
chmod 600 config

* Edit the configuration file
* Run the configuration script

sudo ./bin/wg-appvm-conf
sudo /opt/qubes-wireguard/wg-appvm-conf

* Reboot the VPN qube to activate the changes
22 changes: 22 additions & 0 deletions bin/firewall
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env sh

nft -f - << EOF
flush chain ip qubes custom-forward
flush chain ip6 qubes custom-forward
table ip qubes {
chain custom-forward {
ct state related,established counter accept
oifname "wg*" tcp flags syn tcp option maxseg size set rt mtu counter
iifname "vif*" oifname "wg*" counter accept
counter reject
}
}
table ip6 qubes {
chain custom-forward {
ct state related,established counter accept
oifname "wg*" tcp flags syn tcp option maxseg size set rt mtu counter
iifname "vif*" oifname "wg*" counter accept
counter reject
}
}
EOF
69 changes: 69 additions & 0 deletions bin/qubes-setup-wg-dns
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env python3

import os
from ipaddress import IPv4Address

import dbus
import qubesdb


def get_dns_resolved() -> list[IPv4Address]:
"""
Get all DNS servers via dbus
"""
bus = dbus.SystemBus()
resolve1 = bus.get_object("org.freedesktop.resolve1", "/org/freedesktop/resolve1")
dns = resolve1.Get(
"org.freedesktop.resolve1.Manager",
"DNS",
dbus_interface="org.freedesktop.DBus.Properties",
)
return [IPv4Address(bytes(addr)) for _, family, addr in dns if family == 2]


def install_firewall_rules(dns: list[IPv4Address]) -> None:
"""
Configures nftables dnat rules with any non-default DNS servers
"""
qdb = qubesdb.QubesDB()
qubesdb_dns = []

for i in ("/qubes-netvm-primary-dns", "/qubes-netvm-secondary-dns"):
ns_maybe = qdb.read(i)
if ns_maybe is None:
continue
try:
qubesdb_dns.append(IPv4Address(ns_maybe.decode("ascii", "strict")))
except (UnicodeDecodeError, ValueError):
pass

res = [
"add table ip qubes",
# Add the chain so that the subsequent delete will work. If the chain already
# exists this is a harmless no-op.
"add chain ip qubes dnat-dns",
# Delete the chain so that if the chain already exists, it will be removed.
# The removal of the old chain and addition of the new one happen as a single
# atomic operation, so there is no period where neither chain is present or
# where both are present.
"delete chain ip qubes dnat-dns",
"table ip qubes {",
"chain dnat-dns {",
"type nat hook prerouting priority dstnat; policy accept;",
]

extra_dns = [i for i in dns if i not in qubesdb_dns]

for vm_nameserver in qubesdb_dns:
for dest_nameserver in extra_dns:
res += [
f"ip daddr {vm_nameserver} udp dport 53 dnat to {dest_nameserver}",
f"ip daddr {vm_nameserver} tcp dport 53 dnat to {dest_nameserver}",
]

res += ["}\n}\n"]
os.execvp("nft", ("nft", "--", "\n".join(res)))


if __name__ == "__main__":
install_firewall_rules(get_dns_resolved())
4 changes: 1 addition & 3 deletions bin/wg-appvm-conf
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ cat << EOF > "$WG_CONF"
Address = $WG_ADDRESS
DNS = $WG_DNS
PrivateKey = $WG_PRIVATE_KEY
PostUp = for ns in \$(resolvectl dns $WG_CONF_NAME | sed 's/.*: //'); do echo "nameserver \$ns"; done > /etc/resolv.conf
PostUp = /usr/lib/qubes/qubes-setup-dnat-to-ns
PostDown = for ns in \$(resolvectl dns | grep -F 'Link 2 (eth0)' | sed 's/.*: //'); do echo "nameserver \$ns"; done > /etc/resolv.conf
PostUp = /opt/qubes-wireguard/qubes-setup-wg-dns
PostDown = /usr/lib/qubes/qubes-setup-dnat-to-ns
[Peer]
Expand Down
27 changes: 16 additions & 11 deletions bin/wg-template-conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,28 @@ WG_DIR="/rw/config/wireguard"
WG_CONF="$WG_DIR/$WG_CONF_NAME.conf"
FW_DIR="/etc/qubes/qubes-firewall.d"
FW_FILE="wireguard"
INSTALL_DIR="/opt/qubes-wireguard"
DNS_CONFIG_SCRIPT="$INSTALL_DIR/qubes-setup-wg-dns"
APPVM_CONFIG_SCRIPT="$INSTALL_DIR/wg-appvm-conf"


# Install wireguard in template
dnf install -y wireguard-tools
mkdir -p "$WG_DIR"
ln -sf "$WG_CONF" "/etc/wireguard/$WG_CONF_NAME.conf"


# Ensure only traffic destined for the wireguard interface is forwarded
# Add wireguard firewall config script to template
mkdir -p "$FW_DIR"
cp -v "./bin/firewall" "$FW_DIR/$FW_FILE"
chmod +x "$FW_DIR/$FW_FILE"

cat << EOF > "$FW_DIR/$FW_FILE"
#!/bin/sh
iptables -F QBS-FORWARD
iptables -A QBS-FORWARD -o wg+ -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -A QBS-FORWARD -i vif+ -o wg+ -j ACCEPT
iptables -A QBS-FORWARD -j DROP
EOF
# Add wireguard DNS config script to template
mkdir -p "$INSTALL_DIR"
cp -v "./bin/qubes-setup-wg-dns" "$DNS_CONFIG_SCRIPT"
chown root:root "$DNS_CONFIG_SCRIPT"
chmod 755 "$DNS_CONFIG_SCRIPT"

chmod +x "$FW_DIR/$FW_FILE"
# Add AppVM config script to template
cp -v "./bin/wg-appvm-conf" "$APPVM_CONFIG_SCRIPT"
chown root:root "$APPVM_CONFIG_SCRIPT"
chmod 755 "$APPVM_CONFIG_SCRIPT"
3 changes: 3 additions & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
black
mypy
pylint

0 comments on commit 7a84b08

Please sign in to comment.