WireGuard in un namespace di rete: perché il socket è rimasto indietro
Spostare l’interfaccia non sposta il socket UDP cifrato, che resta nel namespace in cui è stato creato il dispositivo. Createlo nella destinazione.
L’interfaccia è elencata nel namespace che volevate, l’applicazione vi è associata, eppure non compare mai traffico del tunnel. È la firma di un dispositivo WireGuard del kernel Linux creato in un namespace e spostato in un altro: l’interfaccia si è spostata e il suo socket UDP cifrato no. Entrambi devono trovarsi nel posto giusto prima che il traffico interno conti. Il controllo è rapido quando si sa di dover guardare due contesti invece di uno.
Il sintomo: namespace corretto, nessun pacchetto
Dentro il namespace il tunnel sembra sano. Il dispositivo esiste, gli indirizzi sono assegnati e la configurazione del peer è presente. Fuori, lo scambio UDP atteso non compare mai sull’interfaccia che stavate osservando, e il lato opposto segnala che non c’è stata alcuna stretta di mano.
Il motivo è che i pacchetti interni dell’applicazione raggiungono il dispositivo spostato, e il dispositivo tenta di inviarli tramite un socket che appartiene a un altro contesto di rete. La rotta sottostante che usa, e ogni regola del firewall che vi si applica, sono quelle del namespace in cui il dispositivo è stato creato.
Non è un difetto dello spostamento né una configurazione errata del peer. È ciò che fa l’implementazione del kernel, e la documentazione sui namespace di WireGuard descrive direttamente la regola di creazione.
Perché il socket ha un luogo di nascita
Un dispositivo WireGuard possiede un socket UDP per il suo trasporto cifrato, e quel socket viene aperto nel namespace in cui il dispositivo è creato. Spostare l’interfaccia con un comando di collegamento sposta il dispositivo visibile ma lascia il trasporto dove è iniziato. I due oggetti hanno quindi proprietari diversi.
La conseguenza è facile da trascurare perché le due metà si esaminano in luoghi diversi. La rotta interna si decide nel namespace in cui gira l’applicazione, e la rotta esterna si decide dove vive il socket. Controllarne solo una produce una conclusione sicura ma sbagliata. Controllarle entrambe di solito chiude l’indagine in un solo passaggio.
Createlo dove volete il socket
La soluzione è creare il dispositivo dentro il namespace di destinazione invece di crearlo fuori e spostarlo. Supponendo che esista già un namespace approvato e che il nome sia libero:
ip netns exec vpn-apps ip link add wg-demo type wireguard
ip netns exec vpn-apps wg show
Ora sia l’interfaccia sia il suo socket appartengono a quel contesto, quindi la rotta sottostante e le regole di filtraggio applicabili sono quelle configurate lì. Se il progetto richiede il lato in chiaro altrove, mettete prima l’interfaccia sottostante nel namespace e poi create il tunnel. L’ordine fa parte del progetto, non è un dettaglio implementativo.
Trattateli come comandi di amministrazione di rete, non come una ricetta. Creano un dispositivo e mostrano lo stato; chiavi, peer, indirizzi e rotte devono comunque provenire da una configurazione approvata, e un’interfaccia di produzione esistente non dovrebbe mai essere sostituita in un esempio.
Leggete entrambi i lati del percorso
Quando il dispositivo è nel posto giusto, verificate le due decisioni separatamente. Iniziate dalla ricerca interna dal contesto dell’applicazione, poi controllate il percorso esterno dal contesto che possiede il socket:
ip netns exec vpn-apps ip route get 10.30.0.9
ip netns exec vpn-apps wg show
tcpdump -ni any udp port 51820
Se la ricerca interna si risolve attraverso il tunnel e la cattura esterna mostra lo scambio cifrato, le due metà concordano. Se la cattura è vuota, il socket è ancora altrove, oppure la rotta sottostante nel suo namespace non raggiunge l’endpoint.
Un altro controllo appartiene al verbale: come viene creato il dispositivo dopo un riavvio. Un gestore che ricrea l’interfaccia con un contesto di creazione diverso cambia il luogo di nascita del socket. Uno spostamento manuale che ha funzionato una volta non è prova sul percorso gestito.