Files
Loki/internal/loki/sys_firewall_windows.go
Loki de6551a153 Rebaptise AJEAN en Loki (fork, lignée conservée)
- module github.com/R0m1k3/Loki, cmd/loki, internal/loki (package loki)
- LOKI_HOME, LOKI_MODEL_DIRS, LOKI_SERVICE, LOKI_DL_CONNS ; /etc/loki ;
  units loki-engine / loki-ui ; binaire et aide CLI
- updateRepo pointe sur R0m1k3/Loki (l'auto-update ne tirera plus les
  binaires AJEAN amont)

Conservé à l'identique : le domaine ajean.link (service de tunnel amont),
les littéraux de migration 0.7.x (migrate_07.go), RELEASE_NOTES.md et
LICENSE (historique et licence de l'amont).

go build/vet/test : verts.
2026-08-14 21:33:15 +00:00

80 lines
3.1 KiB
Go

//go:build windows
package loki
import (
"fmt"
"os/exec"
"strconv"
"strings"
)
// sys_firewall_windows.go — règles de pare-feu entrantes pour le moteur.
//
// Sur une installation Windows fraîche, même avec HOST=0.0.0.0, le pare-feu
// bloque tout ce qui arrive du réseau : l'utilisateur voyait « ça écoute
// partout » et se prenait quand même un délai d'attente depuis son autre
// machine. Loki pose donc la règle lui-même, quand il en a le droit.
//
// `loki install` ne réclame PAS les droits administrateur (voir
// sys_install_windows.go) : netsh échouera donc souvent. On ne fait pas semblant
// que ça a marché — firewallState relit la règle, et firewallManualHint donne la
// commande exacte à coller dans un terminal administrateur.
// firewallRuleName identifie nos règles. Une par port : changer PORT dans la
// configuration ne doit pas laisser une règle ouverte sur l'ancien.
func firewallRuleName(port int) string {
return "Loki moteur (port " + strconv.Itoa(port) + ")"
}
// netsh exécute netsh sans faire clignoter de console (hideCmd) et renvoie sa
// sortie combinée.
func netsh(args ...string) (string, error) {
if firewallInert {
return "", fmt.Errorf("pare-feu non piloté")
}
out, err := hideCmd(exec.Command("netsh", args...)).CombinedOutput()
return strings.TrimSpace(string(out)), err
}
// firewallOpen autorise le port en entrée (TCP), pour les profils privé et
// domaine seulement : ouvrir un modèle non authentifié sur un réseau public
// (café, hôtel) n'est pas un défaut qu'on pose au nom de l'utilisateur.
func firewallOpen(port int) error {
_ = firewallClose(port) // idempotence : pas d'empilement de règles homonymes
out, err := netsh("advfirewall", "firewall", "add", "rule",
"name="+firewallRuleName(port), "dir=in", "action=allow",
"protocol=TCP", "localport="+strconv.Itoa(port), "profile=private,domain")
if err != nil {
return fmt.Errorf("règle de pare-feu refusée (droits administrateur requis) : %s", out)
}
return nil
}
// firewallClose retire la règle. Absente = rien à faire, et surtout pas une
// erreur.
func firewallClose(port int) error {
_, _ = netsh("advfirewall", "firewall", "delete", "rule", "name="+firewallRuleName(port))
return nil
}
// firewallState relit l'état RÉEL de la règle plutôt que de croire au succès
// supposé d'une commande passée.
func firewallState(port int) string {
out, err := netsh("advfirewall", "firewall", "show", "rule", "name="+firewallRuleName(port))
if err != nil || strings.TrimSpace(out) == "" {
return "ferme"
}
// netsh répond « Aucune règle ne correspond aux critères » (localisé) avec un
// code de sortie non nul : le err ci-dessus suffit. Ici la règle existe.
return "ouvert"
}
// firewallManualHint : la commande à coller dans un terminal ADMINISTRATEUR
// quand Loki n'a pas pu poser la règle lui-même.
func firewallManualHint(port int) string {
return fmt.Sprintf("le pare-feu Windows bloque encore le port %d. Ouvre un terminal ADMINISTRATEUR et lance :\n"+
` netsh advfirewall firewall add rule name="%s" dir=in action=allow protocol=TCP localport=%d profile=private,domain`,
port, firewallRuleName(port), port)
}