Skip to content

Commit 02b88d4

Browse files
committed
Fix systemd-resolved issue with dns leak protection
1 parent 3ac008e commit 02b88d4

File tree

1 file changed

+71
-62
lines changed

1 file changed

+71
-62
lines changed

protonvpn_cli/connection.py

Lines changed: 71 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -554,75 +554,84 @@ def manage_dns(mode, dns_server=False):
554554

555555
if mode == "leak_protection":
556556
logger.debug("Leak Protection initiated")
557-
# Restore original resolv.conf if it exists
558-
if os.path.isfile(backupfile):
559-
logger.debug("resolv.conf.backup exists")
560-
manage_dns("restore")
561-
# Check for custom DNS Server
562-
if not int(get_config_value("USER", "dns_leak_protection")):
563-
if get_config_value("USER", "custom_dns") == "None":
564-
logger.debug("DNS Leak Protection is disabled")
565-
return
566-
else:
567-
dns_server = get_config_value("USER", "custom_dns")
568-
logger.debug("Using custom DNS")
557+
if shutil.which("resolvectl") and os.path.islink("/etc/resolv.conf"):
558+
logger.debug("Running resolvectl command for leak_protection")
559+
cmd_args = ["sudo", "resolvectl", "dns", "proton0", dns_server]
560+
pipes = subprocess.Popen(cmd_args, stderr=subprocess.PIPE)
561+
_, std_err = pipes.communicate()
562+
if pipes.returncode != 0:
563+
raise Exception(f"{' '.join(cmd_args)} failed with code {pipes.returncode} -> {std_err.strip()}")
569564
else:
570-
logger.debug("DNS Leak Protection is enabled")
571-
# Make sure DNS Server has been provided
572-
if not dns_server:
573-
raise Exception("No DNS Server has been provided.")
574-
575-
shutil.copy2(resolvconf_path, backupfile)
576-
logger.debug("{0} (resolv.conf) backed up".format(resolvconf_path))
577-
578-
# Remove previous nameservers
579-
dns_regex = re.compile(r"^nameserver .*$")
580-
581-
with open(backupfile, 'r') as backup_handle:
582-
with open(resolvconf_path, 'w') as resolvconf_handle:
583-
for line in backup_handle:
584-
if not dns_regex.search(line):
585-
resolvconf_handle.write(line)
586-
587-
logger.debug("Removed existing DNS Servers")
588-
589-
# Add ProtonVPN managed DNS Server to resolv.conf
590-
dns_server = dns_server.split()
591-
with open(resolvconf_path, "a") as f:
592-
f.write("# ProtonVPN DNS Servers. Managed by ProtonVPN-CLI.\n")
593-
for dns in dns_server[:3]:
594-
f.write("nameserver {0}\n".format(dns))
595-
logger.debug("Added ProtonVPN or custom DNS")
596-
597-
# Write the hash of the edited file in the configuration
598-
#
599-
# This is so it doesn't restore an old DNS configuration
600-
# if the configuration changes during a VPN session
601-
# (e.g. by switching networks)
602-
603-
with open(resolvconf_path, "rb") as f:
604-
filehash = zlib.crc32(f.read())
605-
set_config_value("metadata", "resolvconf_hash", filehash)
565+
# Restore original resolv.conf if it exists
566+
if os.path.isfile(backupfile):
567+
logger.debug("resolv.conf.backup exists")
568+
manage_dns("restore")
569+
# Check for custom DNS Server
570+
if not int(get_config_value("USER", "dns_leak_protection")):
571+
if get_config_value("USER", "custom_dns") == "None":
572+
logger.debug("DNS Leak Protection is disabled")
573+
return
574+
else:
575+
dns_server = get_config_value("USER", "custom_dns")
576+
logger.debug("Using custom DNS")
577+
else:
578+
logger.debug("DNS Leak Protection is enabled")
579+
# Make sure DNS Server has been provided
580+
if not dns_server:
581+
raise Exception("No DNS Server has been provided.")
582+
583+
shutil.copy2(resolvconf_path, backupfile)
584+
logger.debug("{0} (resolv.conf) backed up".format(resolvconf_path))
585+
586+
# Remove previous nameservers
587+
dns_regex = re.compile(r"^nameserver .*$")
588+
589+
with open(backupfile, 'r') as backup_handle:
590+
with open(resolvconf_path, 'w') as resolvconf_handle:
591+
for line in backup_handle:
592+
if not dns_regex.search(line):
593+
resolvconf_handle.write(line)
594+
595+
logger.debug("Removed existing DNS Servers")
596+
597+
# Add ProtonVPN managed DNS Server to resolv.conf
598+
dns_server = dns_server.split()
599+
with open(resolvconf_path, "a") as f:
600+
f.write("# ProtonVPN DNS Servers. Managed by ProtonVPN-CLI.\n")
601+
for dns in dns_server[:3]:
602+
f.write("nameserver {0}\n".format(dns))
603+
logger.debug("Added ProtonVPN or custom DNS")
604+
605+
# Write the hash of the edited file in the configuration
606+
#
607+
# This is so it doesn't restore an old DNS configuration
608+
# if the configuration changes during a VPN session
609+
# (e.g. by switching networks)
610+
611+
with open(resolvconf_path, "rb") as f:
612+
filehash = zlib.crc32(f.read())
613+
set_config_value("metadata", "resolvconf_hash", filehash)
606614

607615
elif mode == "restore":
608616
logger.debug("Restoring DNS")
609-
if os.path.isfile(backupfile):
617+
if not (shutil.which("resolvectl") and os.path.islink("/etc/resolv.conf")):
618+
if os.path.isfile(backupfile):
610619

611-
# Check if the file changed since connection
612-
oldhash = get_config_value("metadata", "resolvconf_hash")
613-
with open(resolvconf_path, "rb") as f:
614-
filehash = zlib.crc32(f.read())
620+
# Check if the file changed since connection
621+
oldhash = get_config_value("metadata", "resolvconf_hash")
622+
with open(resolvconf_path, "rb") as f:
623+
filehash = zlib.crc32(f.read())
615624

616-
if filehash == int(oldhash):
617-
shutil.copy2(backupfile, resolvconf_path)
618-
logger.debug("resolv.conf restored from backup")
619-
else:
620-
logger.debug("resolv.conf changed. Not restoring.")
625+
if filehash == int(oldhash):
626+
shutil.copy2(backupfile, resolvconf_path)
627+
logger.debug("resolv.conf restored from backup")
628+
else:
629+
logger.debug("resolv.conf changed. Not restoring.")
621630

622-
os.remove(backupfile)
623-
logger.debug("resolv.conf.backup removed")
624-
else:
625-
logger.debug("No Backupfile found")
631+
os.remove(backupfile)
632+
logger.debug("resolv.conf.backup removed")
633+
else:
634+
logger.debug("No Backupfile found")
626635
else:
627636
raise Exception("Invalid argument provided. "
628637
"Mode must be 'restore' or 'leak_protection'")

0 commit comments

Comments
 (0)