Skip to content
74 changes: 64 additions & 10 deletions network/qubes-setup-dnat-to-ns
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ from __future__ import annotations
import dbus
import qubesdb
from typing import List
from ipaddress import IPv4Address
from itertools import zip_longest
from ipaddress import ip_address, IPv4Address, IPv6Address
import os

def get_dns_resolv_conf():
Expand All @@ -38,7 +39,7 @@ def get_dns_resolv_conf():
if len(tokens) < 2 or tokens[0] != "nameserver":
continue
try:
nameservers.append(IPv4Address(tokens[1]))
nameservers.append(ip_address(tokens[1]))
except ValueError:
pass
return nameservers
Expand Down Expand Up @@ -69,13 +70,13 @@ def get_dns_resolved():
raise
# Use global entries first
dns.sort(key=lambda x: x[0] != 0)
# Only keep IPv4 entries. systemd-resolved is trusted to return valid
# addresses.
return [IPv4Address(bytes(addr)) for _g, family, addr in dns if family == 2]
# systemd-resolved is trusted to return valid addresses.
return [ip_address(bytes(addr)) for _g, family, addr in dns]

def install_firewall_rules(dns):
qdb = qubesdb.QubesDB()
qubesdb_dns = []
qubesdb_dns6 = []
for i in ('/qubes-netvm-primary-dns', '/qubes-netvm-secondary-dns'):
ns_maybe = qdb.read(i)
if ns_maybe is None:
Expand All @@ -84,6 +85,14 @@ def install_firewall_rules(dns):
qubesdb_dns.append(IPv4Address(ns_maybe.decode("ascii", "strict")))
except (UnicodeDecodeError, ValueError):
pass
for i in ('/qubes-netvm-primary-dns6', '/qubes-netvm-secondary-dns6'):
ns_maybe = qdb.read(i)
if ns_maybe is None:
continue
try:
qubesdb_dns6.append(IPv6Address(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
Expand All @@ -95,15 +104,60 @@ def install_firewall_rules(dns):
# where both are present.
'delete chain ip qubes dnat-dns',
'table ip qubes {',
'chain custom-dnat-dns {}',
'chain dnat-dns {',
'type nat hook prerouting priority dstnat; policy accept;',
'jump custom-dnat-dns',
]
for i, (vm_nameserver, dest) in enumerate(zip_longest(qubesdb_dns,
[dns_ip for dns_ip in dns if type(dns_ip) is IPv4Address])):
if i >= len(qubesdb_dns):
break
dns_ = str(dest)
if dest is None or (vm_nameserver == dest and
qdb.read('/qubes-ip') is None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
qdb.read('/qubes-ip') is None):
qdb.read('/qubes-primary-dns') is None):

for consistency?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

res += [
f"ip daddr {vm_nameserver} tcp dport 53 reject with icmp type host-unreachable",
f"ip daddr {vm_nameserver} udp dport 53 reject with icmp type host-unreachable",
]
else:
res += [
f"ip daddr {vm_nameserver} udp dport 53 dnat to {dns_}",
f"ip daddr {vm_nameserver} tcp dport 53 dnat to {dns_}",
]
res += ["}\n}\n"]
res += [
'add table ip6 qubes',
# Add the chain so that the subsequent delete will work. If the chain already
# exists this is a harmless no-op.
'add chain ip6 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 ip6 qubes dnat-dns',
'table ip6 qubes {',
'chain custom-dnat-dns {}',
'chain dnat-dns {',
'type nat hook prerouting priority dstnat; policy accept;',
'jump custom-dnat-dns',
]
for vm_nameserver, dest in zip(qubesdb_dns, get_dns_resolved()):
for i, (vm_nameserver, dest) in enumerate(zip_longest(qubesdb_dns6,
[dns_ip for dns_ip in dns if type(dns_ip) is IPv6Address])):
if i >= len(qubesdb_dns6):
break
dns_ = str(dest)
res += [
f"ip daddr {vm_nameserver} udp dport 53 dnat to {dns_}",
f"ip daddr {vm_nameserver} tcp dport 53 dnat to {dns_}",
]
if dest is None or (vm_nameserver == dest and
qdb.read('/qubes-primary-dns6') is None):
res += [
f"ip6 daddr {vm_nameserver} tcp dport 53 reject with icmpv6 type addr-unreachable",
f"ip6 daddr {vm_nameserver} udp dport 53 reject with icmpv6 type addr-unreachable",
]
else:
res += [
f"ip6 daddr {vm_nameserver} udp dport 53 dnat to {dns_}",
f"ip6 daddr {vm_nameserver} tcp dport 53 dnat to {dns_}",
]
res += ["}\n}\n"]
os.execvp("nft", ("nft", "--", "\n".join(res)))

Expand Down
46 changes: 37 additions & 9 deletions network/setup-ip
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ configure_network () {
local gateway6="$8"
local primary_dns="$9"
local secondary_dns="${10}"
local custom="${11}"
local primary_dns6="${11}"
local secondary_dns6="${12}"
local custom="${13}"

/sbin/ip -- address replace "$ip/$netmask" dev "$INTERFACE"
if [[ "$custom" = false ]]; then
Expand Down Expand Up @@ -64,16 +66,21 @@ configure_network () {
if [ -h /etc/resolv.conf ]; then
rm -f /etc/resolv.conf
fi
echo > /etc/resolv.conf
echo -n > /etc/resolv.conf
if ! qsvc disable-dns-server ; then
echo "nameserver $primary_dns" > /etc/resolv.conf
if [ -n "$primary_dns6" ]; then
echo "nameserver $primary_dns6" >> /etc/resolv.conf
echo "nameserver $secondary_dns6" >> /etc/resolv.conf
fi
echo "nameserver $primary_dns" >> /etc/resolv.conf
echo "nameserver $secondary_dns" >> /etc/resolv.conf
fi
fi
if [ -x /usr/bin/resolvectl ] && \
systemctl is-enabled -q systemd-resolved.service && \
! qsvc disable-dns-server ; then
resolvectl dns "$INTERFACE" "$primary_dns" "$secondary_dns"
resolvectl dns "$INTERFACE" "$primary_dns6" "$secondary_dns6" \
"$primary_dns" "$secondary_dns"
fi
}

Expand All @@ -88,7 +95,9 @@ configure_network_nm () {
local gateway6="$8"
local primary_dns="$9"
local secondary_dns="${10}"
local custom="${11}"
local primary_dns6="${11}"
local secondary_dns6="${12}"
local custom="${13}"

local prefix
local prefix6
Expand Down Expand Up @@ -119,6 +128,10 @@ __EOF__
if ! qsvc disable-dns-server ; then
ip4_nm_config="${ip4_nm_config}
dns=${primary_dns};${secondary_dns}"
if [ -n "$primary_dns6" ]; then
ip6_nm_config="${ip6_nm_config}
dns=${primary_dns6};${secondary_dns6}"
fi
fi
if ! qsvc disable-default-route ; then
ip4_nm_config="${ip4_nm_config}
Expand Down Expand Up @@ -183,8 +196,21 @@ configure_qubes_ns() {
#netmask=$(qubesdb-read /qubes-netvm-netmask)
primary_dns=$(qubesdb-read /qubes-netvm-primary-dns 2>/dev/null || echo "$gateway")
secondary_dns=$(qubesdb-read /qubes-netvm-secondary-dns)
echo "NS1=$primary_dns" > /var/run/qubes/qubes-ns
echo "NS2=$secondary_dns" >> /var/run/qubes/qubes-ns
primary_dns6=$(qubesdb-read /qubes-netvm-primary-dns6 ||:)
secondary_dns6=$(qubesdb-read /qubes-netvm-secondary-dns6 ||:)
if [ -n "$primary_dns6" ]; then
cat > /var/run/qubes/qubes-ns<< EOF
NS1=$primary_dns6
NS1=$secondary_dns6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
NS1=$secondary_dns6
NS2=$secondary_dns6

NS3=$primary_dns
NS4=$secondary_dns
EOF
else
cat > /var/run/qubes/qubes-ns<< EOF
NS1=$primary_dns
NS1=$secondary_dns
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
NS1=$secondary_dns
NS2=$secondary_dns

EOF
fi
/usr/lib/qubes/qubes-setup-dnat-to-ns
}

Expand Down Expand Up @@ -244,6 +270,8 @@ if [ "$ACTION" == "add" ]; then

primary_dns=$(/usr/bin/qubesdb-read /qubes-primary-dns 2>/dev/null) || primary_dns=
secondary_dns=$(/usr/bin/qubesdb-read /qubes-secondary-dns 2>/dev/null) || secondary_dns=
primary_dns6=$(/usr/bin/qubesdb-read /qubes-primary-dns6 2>/dev/null ||:) || primary_dns6=
secondary_dns6=$(/usr/bin/qubesdb-read /qubes-secondary-dns6 2>/dev/null ||:) || secondary_dns6=
/usr/lib/systemd/systemd-sysctl \
"--prefix=/net/ipv4/conf/all" \
"--prefix=/net/ipv4/neigh/all" \
Expand All @@ -257,9 +285,9 @@ if [ "$ACTION" == "add" ]; then
if [ -n "$ip4" ]; then
# If NetworkManager is enabled, let it configure the network
if qsvc network-manager && [ -e /usr/bin/nmcli ]; then
configure_network_nm "$MAC" "$INTERFACE" "$ip4" "$ip6" "$netmask" "$netmask6" "$gateway" "$gateway6" "$primary_dns" "$secondary_dns" "$custom"
configure_network_nm "$MAC" "$INTERFACE" "$ip4" "$ip6" "$netmask" "$netmask6" "$gateway" "$gateway6" "$primary_dns" "$secondary_dns" "$primary_dns6" "$secondary_dns6" "$custom"
else
configure_network "$MAC" "$INTERFACE" "$ip4" "$ip6" "$netmask" "$netmask6" "$gateway" "$gateway6" "$primary_dns" "$secondary_dns" "$custom"
configure_network "$MAC" "$INTERFACE" "$ip4" "$ip6" "$netmask" "$netmask6" "$gateway" "$gateway6" "$primary_dns" "$secondary_dns" "$primary_dns6" "$secondary_dns6" "$custom"
fi

network=$(qubesdb-read /qubes-netvm-network 2>/dev/null) || network=
Expand Down
2 changes: 2 additions & 0 deletions qubes-rpc/post-install.d/10-qubes-core-agent-features.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ advertise_systemd_service() {
done
}

qvm-features-request supported-feature.ipv6dns=1

advertise_systemd_service network-manager NetworkManager.service \
network-manager.service
advertise_systemd_service modem-manager ModemManager.service
Expand Down
17 changes: 15 additions & 2 deletions vm-systemd/network-proxy-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,22 @@ if [ "x$network" != "x" ]; then
#netmask=$(qubesdb-read /qubes-netvm-netmask)
primary_dns=$(qubesdb-read /qubes-netvm-primary-dns 2>/dev/null || echo "$gateway")
secondary_dns=$(qubesdb-read /qubes-netvm-secondary-dns)
primary_dns6=$(qubesdb-read /qubes-netvm-primary-dns6 ||:)
secondary_dns6=$(qubesdb-read /qubes-netvm-secondary-dns6 ||:)
modprobe netbk 2> /dev/null || modprobe xen-netback || "${modprobe_fail_cmd}"
echo "NS1=$primary_dns" > /var/run/qubes/qubes-ns
echo "NS2=$secondary_dns" >> /var/run/qubes/qubes-ns
if [ -n "$primary_dns6" ]; then
cat > /var/run/qubes/qubes-ns<< EOF
NS1=$primary_dns6
NS1=$secondary_dns6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
NS1=$secondary_dns6
NS2=$secondary_dns6

NS3=$primary_dns
NS4=$secondary_dns
EOF
else
cat > /var/run/qubes/qubes-ns<< EOF
NS1=$primary_dns
NS1=$secondary_dns
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
NS1=$secondary_dns
NS2=$secondary_dns

EOF
fi
/usr/lib/qubes/qubes-setup-dnat-to-ns
echo "1" > /proc/sys/net/ipv4/ip_forward
# enable also IPv6 forwarding, if IPv6 is enabled
Expand Down