Skip to content
This repository was archived by the owner on Apr 3, 2025. It is now read-only.

Commit 602c435

Browse files
committed
NM: Make DNS settings the maximum to avoid DNS leak fallback
NM has atrocious defaults. In the current situation, if you're connected to OpenVPN/WireGuard (full tunnel, default gateway), DNS may go outside of the VPN if the hostname only resolves in e.g. a DHCP provided dns server. This is determined with the ipv4/ipv6 dns-priority setting and the dns-search setting. We have to ensure that the dns-priority gets a negative value, from nm-settings: DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles We thus make the following change if full tunnel/default gateway: - Set the DNS priority: nmcli con modify eduVPN ipv4.dns-priority -2147483648 (int32 min) nmcli con modify eduVPN ipv6.dns-priority -2147483648 (int32 min) - Include the ~. DNS search domain: nmcli con modify eduVPN ipv4.dns-search "~." nmcli con modify eduVPN ipv6.dns-search "~." Modifying the DNS search domain to ~. is needed according to https://systemd.io/RESOLVED-VPNS/. This doc also states it's good to set never-default to no (even if it doesn't do much), which we already did for OpenVPN. Let's do the same for WireGuard. Note that this only seems to happen with systemd-resolved which is the default on Fedora. E.g. Openresolv resolvconf is not affected
1 parent 52b7d08 commit 602c435

File tree

1 file changed

+35
-30
lines changed

1 file changed

+35
-30
lines changed

eduvpn/nm.py

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from shutil import rmtree
1212
from socket import AF_INET, AF_INET6
1313
from tempfile import mkdtemp
14-
from typing import Any, Callable, List, Optional, TextIO, Tuple
14+
from typing import Any, Callable, Optional, TextIO, Tuple
1515

1616
from eduvpn.ovpn import Ovpn
1717
from eduvpn.storage import get_uuid, set_uuid, write_ovpn
@@ -394,12 +394,7 @@ def set_connection(
394394
self,
395395
new_connection: "NM.SimpleConnection",
396396
callback: Callable,
397-
default_gateway: Optional[bool],
398-
dns_search_domains: List[str] = [],
399397
):
400-
new_connection = self.set_setting_ip_config(
401-
new_connection, default_gateway, dns_search_domains
402-
)
403398
new_connection = self.set_setting_ensure_permissions(new_connection)
404399
if self.uuid:
405400
old_con = self.client.get_connection_by_uuid(self.uuid)
@@ -408,28 +403,6 @@ def set_connection(
408403
return
409404
self.add_connection(new_connection, callback)
410405

411-
def set_setting_ip_config(
412-
self,
413-
con: "NM.SimpleConnection",
414-
default_gateway: Optional[bool],
415-
dns_search_domains: List[str] = [],
416-
) -> "NM.SimpleConnection":
417-
"Set IP config settings like default gateway and search domains."
418-
_logger.debug(
419-
f"setting ip config, default gateway: {default_gateway}, dns_search_domains: {dns_search_domains}"
420-
)
421-
ipv4_setting = con.get_setting_ip4_config()
422-
ipv6_setting = con.get_setting_ip6_config()
423-
if default_gateway is not None:
424-
ipv4_setting.set_property("never-default", not default_gateway)
425-
ipv6_setting.set_property("never-default", not default_gateway)
426-
if dns_search_domains:
427-
ipv4_setting.set_property("dns-search", dns_search_domains)
428-
ipv6_setting.set_property("dns-search", dns_search_domains)
429-
con.add_setting(ipv4_setting)
430-
con.add_setting(ipv6_setting)
431-
return con
432-
433406
def set_setting_ensure_permissions(
434407
self, con: "NM.SimpleConnection"
435408
) -> "NM.SimpleConnection":
@@ -443,11 +416,31 @@ def start_openvpn_connection(
443416
) -> None:
444417
_logger.debug("writing ovpn configuration to Network Manager")
445418
new_con = self.import_ovpn(ovpn)
446-
self.set_connection(new_con, callback, default_gateway, dns_search_domains) # type: ignore
419+
s_ip4 = new_con.get_setting_ip4_config()
420+
s_ip6 = new_con.get_setting_ip6_config()
421+
422+
# avoid DNS leaks in default gateway
423+
# see man nm-settings for dns-priority
424+
# and https://systemd.io/RESOLVED-VPNS/
425+
if default_gateway:
426+
s_ip4.set_property(NM.SETTING_IP_CONFIG_DNS_PRIORITY, -2147483648)
427+
s_ip6.set_property(NM.SETTING_IP_CONFIG_DNS_PRIORITY, -2147483648)
428+
s_ip4.add_dns_search("~.")
429+
s_ip6.add_dns_search("~.")
430+
for i in dns_search_domains:
431+
s_ip4.add_dns_search(i)
432+
s_ip6.add_dns_search(i)
433+
s_ip4.set_property("never-default", not default_gateway)
434+
s_ip6.set_property("never-default", not default_gateway)
435+
new_con.add_setting(s_ip4)
436+
new_con.add_setting(s_ip6)
437+
438+
self.set_connection(new_con, callback) # type: ignore
447439

448440
def start_wireguard_connection( # noqa: C901
449441
self,
450442
config: ConfigParser,
443+
default_gateway,
451444
*,
452445
allow_wg_lan=False,
453446
callback=None,
@@ -517,10 +510,22 @@ def start_wireguard_connection( # noqa: C901
517510
s_ip4.add_dns(i)
518511
for i in dns6:
519512
s_ip6.add_dns(i)
513+
514+
# avoid DNS leaks in default gateway
515+
# see man nm-settings for dns-priority
516+
# and https://systemd.io/RESOLVED-VPNS/
517+
if default_gateway:
518+
s_ip4.set_property(NM.SETTING_IP_CONFIG_DNS_PRIORITY, -2147483648)
519+
s_ip6.set_property(NM.SETTING_IP_CONFIG_DNS_PRIORITY, -2147483648)
520+
s_ip4.add_dns_search("~.")
521+
s_ip6.add_dns_search("~.")
520522
for i in dns_hostnames:
521523
s_ip4.add_dns_search(i)
522524
s_ip6.add_dns_search(i)
523525

526+
s_ip4.set_property("never-default", not default_gateway)
527+
s_ip6.set_property("never-default", not default_gateway)
528+
524529
s_ip4.set_property(NM.SETTING_IP_CONFIG_METHOD, "manual")
525530
s_ip6.set_property(NM.SETTING_IP_CONFIG_METHOD, "manual")
526531

@@ -586,7 +591,7 @@ def start_wireguard_connection( # noqa: C901
586591
profile.add_setting(s_con)
587592
profile.add_setting(w_con)
588593

589-
self.set_connection(profile, callback, None) # type: ignore
594+
self.set_connection(profile, callback) # type: ignore
590595

591596
@run_in_glib_thread
592597
def activate_connection(self, callback: Optional[Callable] = None) -> None:

0 commit comments

Comments
 (0)