nftables cgroup-bypass behöver också en korrigering av källadressen
Att markera en cgroup skickar den till en annan tabell, och socketen behåller adressen den redan hade. Klassificera, routa och översätt som tre separata steg.
Att markera trafik från en cgroup är den enkla delen. Tre separata beslut måste stämma innan en enda applikation går ut genom det fysiska gränssnittet medan allt annat stannar i tunneln: vilken socket som hör till undantaget, vilken routeuppslagning markeringen utlöser och vilken källadress paketet bär när det lämnar. De flesta misslyckade försök får den första rätt, den andra halvt och tittar aldrig på den tredje.
Tre beslut, inte ett
Klassificeringen svarar på vem som är undantagen. Routningen svarar på vart det markerade paketet går i stället. Källvalet svarar på vad andra änden ser och vart svaret ska tillbaka.
Dessa misslyckas oberoende av varandra. Ett paket kan klassificeras, routas om till det fysiska gränssnittet och ändå bära en privat adress som ingen uppströms router kan returnera, vilket ger en timeout som ser precis ut som en brandväggsblockering. Inget i klassificeringssteget varnar dig om det. Inget i routningssteget heller.
Ordningen spelar också roll. Klassificering sker när paketet genereras, routning sker efteråt och översättning sker vid utgångspunkten.
Om du inte kan namnge vilket av de tre stegen som är trasigt felsöker du inte, du arrangerar om regler och hoppas.
Matcha en cgroup som finns kvar i morgon
nftables kan testa en sockets cgroup v2-medlemskap, vilket verkligen är användbart eftersom det följer processen och inte destinationen. Haken är identifieraren. En skrivbordsapplikation som startas från en meny lever ofta i en tillfällig scope vars namn ändras vid nästa start.
nft list ruleset
systemctl status session.slice 2>/dev/null
cat /proc/self/cgroupAtt kopiera ett scopenamn från en session och hårdkoda det ger en regel som fungerar idag och tyst slutar matcha i morgon. Sätt i stället applikationen i en medveten, stabil exekveringskontext, till exempel en egen scope eller unit som du kontrollerar, och matcha den. Regeln överlever då omstarter och paketuppdateringar. Den blir också något en kollega kan resonera kring utan din sessionshistorik.
Var också precis om vilken mekanism du använder. net_cls-klassificering i cgroup v1 och socketmatchning i cgroup v2 är olika saker, och ett liknande namngivet fält i dokumentationen gör dem inte utbytbara.
Det är route-kedjan som utlöser den andra uppslagningen
För lokalt genererad trafik avgör kedjetypen om något händer efter att markeringen satts. En output-kedja av typen filter kan markera ett paket och kärnan fortsätter att använda den route den redan valt. En kedja av typen route är mekanismen som begär en ny uppslagning.
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 200Markeringen behöver då en policyregel som skickar den till en tabell, och den tabellen måste vara komplett: en standardroute, lokala destinationer som applikationen fortfarande behöver och en uppströms gateway som faktiskt svarar.
Välj markeringsvärdet medvetet. WireGuard använder sin egen fwmark för yttre transporttrafik, och att av misstag landa på samma nummer kan störa tunnelns egen routeundantag på sätt som är svåra att diagnostisera.
Källadressen följer inte routen
En socket som redan valt en källadress för tunnelvägen behåller den adressen efter omroutningen. Inget i routeändringen skriver om den, och därför lämnar paketet det fysiska gränssnittet med en privat källa som uppströmsnätet inte kan returnera.
Det synliga symptomet är en applikation som verkar skicka data och aldrig får svar, och en brandväggslogg som inte visar något eftersom paketet aldrig kom tillbaka.
Den snäva åtgärden är en källöversättningsregel begränsad till den applikationens markering och dess faktiska utgångsgränssnitt, integrerad med den NAT som redan finns i stället för att ersätta den:
table inet bypass {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
meta mark 0x1 oifname "wlan0" masquerade
}
}Översätt undantaget och inget annat. En allmän masquerade-regel åtgärdar symptomet och förstör din förmåga att säga vilken trafik som tog vilken väg. Matcha markeringen, det faktiska utgångsgränssnittet och, om du kan, applikationens egen adress. Breda regler är lätta att skriva och nästan omöjliga att granska senare.
Vad som fortfarande slipper undan undantaget
Namnuppslagning kan komma från en separat resolverprocess i en annan cgroup, så att klassificera webbläsarens socket klassificerar inte dess uppslagningar. Om resolverens frågor stannar i tunneln medan anslutningen går utanför den kan split-horizon-svar inte stämma med vägen. Den missanpassningen ger fel som ser ut som DNS-buggar och inte är det.
Barnprocesser ärver cgroup i de flesta uppsättningar, men en hjälpare som flyttar sig in i sin egen scope gör det inte. Kontrollera i stället för att anta, särskilt för allt som kör om sig själv.
Bestäm till sist vad som ska hända när tunneln är nere. Ett undantag som tyst blir en fullständig bypass är en annan säkerhetshållning än ett som misslyckas stängt, och bara en av dem är det du menade.