At markere trafik fra én cgroup er den nemme del. Tre separate beslutninger skal passe sammen, før en enkelt applikation forlader den fysiske grænseflade, mens alt andet bliver i tunnelen: hvilken socket hører til undtagelsen, hvilket routing-opslag udløser markeringen, og hvilken kildeadresse pakken bærer, når den forlader. De fleste mislykkede forsøg får den første rigtig, den anden halvt og ser aldrig på den tredje.

Tre beslutninger, ikke én

Klassificering svarer på, hvem der er undtaget. Routing svarer på, hvor den markerede pakke i stedet går hen. Kildevalg svarer på, hvad den fjerne ende vil se, og hvor svaret skal vende tilbage.

Disse fejler uafhængigt. En pakke kan være klassificeret, rutet om til den fysiske grænseflade og stadig bære en privat adresse, som ingen upstream-router kan returnere, hvilket giver en timeout, der ser præcis ud som en firewall-blokering. Intet i klassificeringstrinnet advarer om det. Intet i routingtrinnet heller.

Rækkefølgen betyder også noget. Klassificering sker, når pakken genereres, routing sker bagefter, og oversættelse sker ved udgangspunktet.

Hvis du ikke kan navngive, hvilket af de tre trin der er i stykker, fejlsøger du ikke, du omarrangerer regler og håber.

Match en cgroup, der stadig findes i morgen

nftables kan teste en sockets cgroup v2-medlemskab, hvilket er virkelig nyttigt, fordi det følger processen og ikke destinationen. Haken er identifikatoren. En desktopapplikation startet fra en menu lever ofte i et forbigående scope, hvis navn ændres ved næste start.

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

At kopiere et scope-navn fra én session og hardcode det giver en regel, der virker i dag og i morgen stille holder op med at matche. Sæt i stedet applikationen i en bevidst stabil eksekveringskontekst, for eksempel et dedikeret scope eller unit, du kontrollerer, og match det. Så overlever reglen genstarter og pakkeopdateringer. Den bliver også noget, en kollega kan ræsonnere om uden din sessionshistorik.

Vær også præcis om, hvilken mekanisme du bruger. net_cls-klassificering i cgroup v1 og socket-matching i cgroup v2 er forskellige ting, og et felt med et lignende navn i dokumentationen gør dem ikke udskiftelige.

Det er en kæde af typen route, der udløser det andet opslag

For lokalt genereret trafik afgør kædetypen, om der sker noget, efter markeringen er sat. En output-kæde af typen filter kan markere en pakke, og kernen vil fortsætte med at bruge den rute, den allerede har valgt. En kæde af typen route er mekanismen, der beder om et nyt opslag.

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

Markeringen har derefter brug for en politikregel, der sender den til en tabel, og den tabel skal være komplet: en standardrute, eventuelle lokale destinationer, som applikationen stadig kræver, og en upstream-gateway, der faktisk svarer.

Vælg markeringsværdien bevidst. WireGuard bruger sit eget fwmark til den ydre transporttrafik, og at lande på det samme nummer ved et uheld kan forstyrre tunnelens egen routing-undtagelse på måder, der er smertefulde at diagnosticere.

Kildeadressen følger ikke ruten

En socket, der allerede har valgt en kildeadresse til tunnelstien, beholder den adresse efter omrutningen. Intet i routingændringen skriver den om, og derfor forlader pakken den fysiske grænseflade med en privat kilde, som upstream-nettet ikke kan returnere.

Det synlige symptom er en applikation, der ser ud til at sende data og aldrig får svar, og en firewall-log, der intet viser, fordi pakken aldrig kom tilbage.

Den snævre rettelse er en kildeoversættelsesregel afgrænset til den applikations markering og dens reelle udgangsgrænseflade, integreret med den NAT, der allerede findes, i stedet for at erstatte den:

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

Oversæt undtagelsen og intet andet. En blanket masquerade-regel retter symptomet og ødelægger din evne til at se, hvilken trafik der tog hvilken vej. Match på markeringen, den reelle udgangsgrænseflade og, hvis du kan, applikationens egen adresse. Brede regler er nemme at skrive og næsten umulige at revidere senere.

Hvad der stadig undslipper undtagelsen

Navneopløsning kan komme fra en separat resolverproces i en anden cgroup, så klassificering af browserens socket klassificerer ikke dens opslag. Hvis resolverens forespørgsler bliver i tunnelen, mens forbindelsen forlader den udenom, kan split-horizon-svar ikke passe med stien. Den uoverensstemmelse giver fejl, der ligner DNS-bugs og ikke er det.

Barneprocesser arver cgroup i de fleste opsætninger, men en helper, der flytter sig selv til sit eget scope, gør ikke. Kontrollér i stedet for at antage, især for alt, der genstarter sig selv.

Beslut endelig, hvad der skal ske, når tunnelen er nede. En undtagelse, der stille bliver en fuld bypass, er en anden sikkerhedsholdning end en, der fejler lukket, og kun én af dem er det, du mente.

Relaterede artikler