diff --git a/network/qubes-nmhook b/network/qubes-nmhook index a2065110..322b8fde 100755 --- a/network/qubes-nmhook +++ b/network/qubes-nmhook @@ -7,10 +7,14 @@ if [ "$2" = "up" ] || [ "$2" = "vpn-up" ] || [ "$2" = "vpn-down" ] || [ "$2" = "dhcp4-change" ]; then /usr/lib/qubes/qubes-setup-dnat-to-ns - # FIXME: Tinyproxy does not reload DNS servers. - if under_systemd ; then - systemctl --no-block try-restart qubes-updates-proxy.service - else - service qubes-updates-proxy try-restart + # Do not restart updates proxy if DNS hasn't changed + # (qubes-setup-dnat-to-ns exits with 100 in such a case) + if [ $? -ne 100 ]; then + # FIXME: Tinyproxy does not reload DNS servers. + if under_systemd ; then + systemctl --no-block try-restart qubes-updates-proxy.service + else + service qubes-updates-proxy try-restart + fi fi fi diff --git a/network/qubes-setup-dnat-to-ns b/network/qubes-setup-dnat-to-ns index 70d2926e..3dcbe904 100755 --- a/network/qubes-setup-dnat-to-ns +++ b/network/qubes-setup-dnat-to-ns @@ -20,6 +20,10 @@ # from __future__ import annotations + +import subprocess +import sys + import dbus import qubesdb from typing import List @@ -85,7 +89,7 @@ def install_firewall_rules(dns): qubesdb_dns.append(IPv4Address(ns_maybe.decode("ascii", "strict"))) except (UnicodeDecodeError, ValueError): pass - res = [ + preamble = [ '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. @@ -95,6 +99,8 @@ def install_firewall_rules(dns): # atomic operation, so there is no period where neither chain is present or # where both are present. 'delete chain ip qubes dnat-dns', + ] + rules = [ 'table ip qubes {', 'chain dnat-dns {', 'type nat hook prerouting priority dstnat; policy accept;', @@ -105,7 +111,7 @@ def install_firewall_rules(dns): # Or maybe user wants to enforce DNS-Over-HTTPS. # Drop IPv4 DNS requests to qubesdb_dns addresses. for vm_nameserver in qubesdb_dns: - res += [ + rules += [ f"ip daddr {vm_nameserver} udp dport 53 drop", f"ip daddr {vm_nameserver} tcp dport 53 drop", ] @@ -115,12 +121,25 @@ def install_firewall_rules(dns): dns_resolved = dns_resolved + dns_resolved for vm_nameserver, dest in zip(qubesdb_dns, dns_resolved): dns_ = str(dest) - res += [ + rules += [ 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"] - os.execvp("nft", ("nft", "--", "\n".join(res))) + rules += ["}", "}"] + + # check if new rules are the same as the old ones - if so, don't reload + # and return that info via exit code + try: + old_rules = subprocess.check_output( + ["nft", "list", "chain", "ip", "qubes", "dnat-dns"]).decode().splitlines() + except subprocess.CalledProcessError: + old_rules = [] + old_rules = [line.strip() for line in old_rules] + + if old_rules == rules: + sys.exit(100) + + os.execvp("nft", ("nft", "--", "\n".join(preamble + rules))) if __name__ == '__main__': install_firewall_rules(get_dns_resolved()) diff --git a/network/setup-ip b/network/setup-ip index 11144a50..0c3aff35 100755 --- a/network/setup-ip +++ b/network/setup-ip @@ -185,7 +185,9 @@ configure_qubes_ns() { 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 - /usr/lib/qubes/qubes-setup-dnat-to-ns + ret=0 + /usr/lib/qubes/qubes-setup-dnat-to-ns || ret=$? + [ "$ret" -eq 0 ] || [ "$ret" -eq 100 ] || exit "$ret" } qubes_ip_change_hook() {