Marcar el trànsit d'un cgroup és la part fàcil. Tres decisions separades s'han d'alinear abans que una sola aplicació surti per la interfície física mentre tota la resta es queda al túnel: quin socket pertany a l'excepció, quina consulta d'encaminament desencadena la marca i quina adreça d'origen porta el paquet quan surt. La majoria d'intents fallits encerten la primera, mig encerten la segona i no miren mai la tercera.

Tres decisions, no una

La classificació respon qui està exempt. L'encaminament respon on va en canvi el paquet marcat. La selecció d'origen respon què veurà l'extrem remot i on ha de tornar la resposta.

Aquestes fallen de manera independent. Un paquet pot estar classificat, reencaminat cap a la interfície física i encara portar una adreça privada que cap router amunt pot retornar, cosa que produeix un temps d'espera que sembla exactament un bloqueig de tallafoc. Res al pas de classificació no us n'avisa. Res al pas d'encaminament tampoc.

L'ordre també importa. La classificació passa quan es genera el paquet, l'encaminament passa després i la traducció passa al punt de sortida.

Si no podeu anomenar quina de les tres etapes està trencada, no esteu depurant, esteu reordenant regles i esperant.

Feu coincidir un cgroup que encara existeixi demà

nftables pot comprovar la pertinença d'un socket a cgroup v2, cosa realment útil perquè segueix el procés i no la destinació. La trampa és l'identificador. Una aplicació d'escriptori engegada des d'un menú sovint viu en un scope transitori el nom del qual canvia a la propera execució.

nft list ruleset
systemctl status session.slice 2>/dev/null
cat /proc/self/cgroup

Copiar el nom d'un scope d'una sessió i codificar-lo de manera fixa produeix una regla que funciona avui i demà deixa de coincidir en silenci. Poseu l'aplicació, en canvi, en un context d'execució deliberat i estable, com un scope o una unit que controleu, i feu-la coincidir amb això. Així la regla sobreviu a reinicis i actualitzacions de paquets. També es converteix en una cosa sobre la qual un company pot raonar sense el vostre historial de sessions.

Sigueu també precisos sobre quin mecanisme feu servir. La classificació net_cls de cgroup v1 i la coincidència de socket de cgroup v2 són coses diferents, i un camp amb un nom semblant a la documentació no els fa intercanviables.

És una cadena de tipus route la que desencadena la segona consulta

Per al trànsit generat localment, el tipus de cadena decideix si passa alguna cosa després de posar la marca. Una cadena output de tipus filter pot marcar un paquet i el nucli continuarà fent servir la ruta que ja havia triat. Una cadena de tipus route és el mecanisme que demana una consulta nova.

table inet bypass {
  chain mark {
    type route hook output priority mangle; policy accept;
    socket cgroupv2 level 2 "app.slice" meta mark set 0x1 comment "app bypass"
  }
}
ip rule add fwmark 0x1 lookup 200
ip route add default via 203.0.113.1 dev wlan0 table 200

La marca necessita després una regla de política que l'enviï a una taula, i aquesta taula ha d'estar completa: una ruta per defecte, qualsevol destinació local que l'aplicació encara requereixi i una passarel·la amunt que realment respongui.

Trieu el valor de la marca amb intenció. WireGuard fa servir el seu propi fwmark per al trànsit de transport exterior, i aterrar per accident en el mateix número pot interferir amb l'excepció d'encaminament del propi túnel de maneres que són doloroses de diagnosticar.

L'adreça d'origen no segueix la ruta

Un socket que ja ha triat una adreça d'origen per al camí del túnel conserva aquesta adreça després del reencaminament. Res al canvi d'encaminament no la reescriu, i per això el paquet surt per la interfície física amb un origen privat que la xarxa amunt no pot retornar.

El símptoma visible és una aplicació que sembla enviar dades i no rep mai resposta, i un registre de tallafoc que no mostra res perquè el paquet no va tornar mai.

La correcció estreta és una regla de traducció d'origen limitada a la marca d'aquesta aplicació i a la seva interfície de sortida real, integrada amb el NAT que ja existeixi en lloc de substituir-lo:

table inet bypass {
  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
    meta mark 0x1 oifname "wlan0" masquerade
  }
}

Traduïu l'excepció i res més. Una regla masquerade general arregla el símptoma i destrueix la vostra capacitat de dir quin trànsit va prendre quin camí. Feu coincidir la marca, la interfície de sortida real i, si podeu, l'adreça pròpia de l'aplicació. Les regles àmplies són fàcils d'escriure i gairebé impossibles d'auditar després.

Què continua escapant-se de l'excepció

La resolució de noms pot venir d'un procés resolver separat en un cgroup diferent, així que classificar el socket del navegador no classifica les seves consultes. Si les consultes del resolver es queden al túnel mentre la connexió en surt, les respostes split-horizon poden no coincidir amb el camí. Aquesta discrepància produeix fallades que semblen errors de DNS i no ho són.

Els processos fills hereten el cgroup en la majoria de configuracions, però un helper que es mou al seu propi scope no ho fa. Comproveu en lloc de suposar, sobretot per a qualsevol cosa que es reexecuti.

Finalment, decidiu què ha de passar quan el túnel està caigut. Una excepció que es converteix en silenci en un bypass complet és una postura de seguretat diferent de la que falla tancada, i només una de les dues és la que volíeu.

Articles relacionats