fix: DNS coupée après arrêt du tunnel, gel UI, dialogues sudo à répétition
- wg-quick down échoue silencieusement si l'interface a déjà disparu (crash, kill, veille) et ne retire donc jamais l'entrée DNS posée par wg-quick up : la résolution reste pointée sur un résolveur mort. Ajout d'un nettoyage DNS inconditionnel (app/core/dns.py) déclenché à la connexion, la déconnexion, la fermeture et au démarrage suivant. - is_connected() se basait sur `wg show`, qui rend un code 0 même en cas d'échec de permission pour un utilisateur non-root : l'app se croyait déconnectée en permanence et ne démontait donc jamais le tunnel à la fermeture. Détection réécrite via sysfs (sans privilèges). - Connexion/déconnexion et ping tournaient sur le thread Qt : gel de l'UI pendant les élévations de privilèges. Déportés dans des QThread (app/ui/worker.py). - Restauration réseau garantie sur toutes les sorties (croix, tray, SIGINT/SIGTERM, atexit, exception) via app/core/shutdown.py. - run_privileged() : la détection "sudo veut un mot de passe" ratait en session non-anglophone et sur les comptes ALL=(ALL) ALL ; réécrite pour se fier au message d'erreur réel plutôt qu'à `sudo -l`. - Écriture de la config WireGuard dans /etc/wireguard (root:root 0700) passe maintenant par install -D via la chaîne de privilèges complète au lieu d'un tee non autorisé par les sudoers. - Ajout d'un diagnostic des droits (make check-privileges, bouton Admin) et mise à jour de setup-sudoers pour couvrir toutes les commandes désormais utilisées.
This commit is contained in:
@@ -10,6 +10,9 @@ from PyQt6.QtWidgets import QApplication, QMessageBox, QInputDialog, QLineEdit,
|
||||
from PyQt6.QtCore import Qt
|
||||
|
||||
from app.core.config import Config
|
||||
from app.core import dns as dns_util
|
||||
from app.core import log as conn_log
|
||||
from app.core import shutdown as shutdown_guard
|
||||
from app.ui.main_window import MainWindow
|
||||
from app.ui.systray import SystemTray
|
||||
from app.ui import icons
|
||||
@@ -27,6 +30,23 @@ def _install_taskbar_icon(app_icon) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def recover_dns_state(config: Config) -> None:
|
||||
"""Répare la résolution DNS laissée détournée par une session précédente.
|
||||
|
||||
Si l'application (ou la machine) s'est arrêtée sans exécuter
|
||||
`wg-quick down`, la configuration DNS du tunnel reste active alors que le
|
||||
résolveur correspondant est injoignable : plus aucun nom ne se résout.
|
||||
Le nettoyage n'a lieu que si un résidu est effectivement constaté.
|
||||
"""
|
||||
iface = config.wg.get("interface_name", "wgs0")
|
||||
try:
|
||||
repaired, msg = dns_util.repair_if_broken(iface, config.wg.get("dns", ""))
|
||||
except Exception as e: # noqa: BLE001
|
||||
repaired, msg = False, f"Vérification DNS impossible : {e}"
|
||||
if msg:
|
||||
conn_log.log_event(msg, "warning" if repaired else "error")
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="wgsecure",
|
||||
@@ -85,6 +105,15 @@ def main():
|
||||
|
||||
config = Config()
|
||||
|
||||
# Reste d'une session précédente mal terminée : DNS détourné vers un
|
||||
# résolveur mort. À faire avant d'ouvrir la fenêtre pour rendre l'accès
|
||||
# au réseau tout de suite.
|
||||
recover_dns_state(config)
|
||||
|
||||
# Restauration de l'état réseau garantie sur toutes les sorties :
|
||||
# Quitter, croix, SIGINT/SIGTERM, atexit, exception non rattrapée.
|
||||
shutdown_guard.install(config, report=conn_log.log_event, app=app)
|
||||
|
||||
# Mode Admin direct (--admin)
|
||||
if args.admin:
|
||||
if not require_admin_auth(config, app):
|
||||
|
||||
Reference in New Issue
Block a user