Förfrågan är alltid en variant av samma mening: behåll VPN:en för surfning, men låt SSH eller ett säkerhetskopieringsjobb använda den vanliga anslutningen. Rådet som cirkulerar om detta, att vidarebefordra porten med NAT-regler i iptables, gör inte det. En NAT-regel skriver om adresser och portar inuti ett flöde; den väljer aldrig vilket gränssnitt paketet lämnar via. Det beslutet hör till ruttuppslagningen, och ruttuppslagningen behöver hjälp för att se en port.

Varför en vanlig rutt inte kan matcha en port

Linux väljer en rutt genom att slå upp destinationsadressen i en tabell, efter att kandidattabeller filtrerats genom policyregler. Dessa regler kan matcha ett brandväggsmärke, en källadress, ett inkommande gränssnitt eller ett UID. Själva ruttposten har inget portfält, eftersom rutten väljs innan transportrubriken spelar roll.

Nuvarande iproute2 och kärnor vidgar regelväljaren: ipproto, sport och dport accepteras, så ip rule add ipproto tcp dport 22 table 100 uttrycker avsikten på en rad. Kör ip rule add help på den faktiska värden för att se om din byggnad listar dport. Om den gör det är du klar med ett kommando; om inte är märkesvägen nedan motsvarigheten.

Hur som helst är regeln bara en pekare. Tabell 100 behöver fortfarande en rutt, och det är delen folk glömmer.

Tre delar, eller en

Den moderna formen är den enda regeln ovan plus en rutt i den alternativa tabellen. Den klassiska formen lägger netfilter i mitten: märk paketet och matcha sedan märket i en regel. Båda slutar i samma uppslagning; de skiljer sig i var porten läses.

Märkesmetoden finns eftersom netfilter ser transportrubriken och ruttkoden historiskt inte gjorde det. Det är hela mekanismen, och den förklarar varför reservvägen är tre samverkande delar i stället för ett smart kommando.

De tre delarna i ordning

Märk först de flöden du vill avleda, i en kedja som körs tidigt nog för att märket ska finnas före ruttbeslutet:

nft add table inet vpnexempt
nft 'add chain inet vpnexempt out { type route hook output priority mangle; }'
nft add rule inet vpnexempt out tcp dport 22 meta mark set 0x1

Skicka sedan de märkta paketen till en separat tabell:

ip rule add fwmark 0x1/0x1 table 100

Ge till sist den tabellen en standardrutt via den fysiska länken. Adresserna är illustrativa; ersätt dem med dina egna:

ip route add default via 192.168.1.1 dev wlan0 table 100

Hoppa över det tredje steget och det märkta paketet hittar ingen rutt i tabell 100, så det misslyckas. Symtomet ser ut som om regeln förstörde nätverket, när den i själva verket tog bort den enda väg paketet hade kvar.

Vad som håller det igång efter det första paketet

Märken gäller utgående paket. Svaret kommer in på det fysiska gränssnittet med adressen som länken tilldelat, och huvudtabellen kan fortfarande föredra tunneln för den destinationen. Två mekanismer håller returvägen konsekvent: en källbaserad regel för länkadressen och connection tracking som bevarar beslutet under flödets hela livstid. Att spara märket i conntrack och återställa det på svaret är det vanliga sättet att göra ett tillståndsfullt undantag stabilt.

Filtrering av omvänd väg är den andra tysta mördaren. Om kärnan validerar returvägen strikt och svaret kommer in på ett gränssnitt som huvudtabellen inte skulle välja, släpps paketet utan meddelande. rp_filter standardvärden skiljer sig mellan distributioner och beroende på om gränssnittet vidarebefordras, så läs det effektiva värdet i stället för att anta att det är av.

Märk inte tunnelns egen transport. En WireGuard- eller UDP OpenVPN-tunnel är inte TCP 22, så receptet ovan är säkert, men ett undantag skrivet som allt utom tunneldestinationen kan fånga de krypterade paketen och bryta tunneln på ett sätt som ser ut som en ruttloop.

Kontrollera i stället för att anta

Fråga kärnan vilken väg den skulle ta, för destinationen och för porten, och kör sedan den verkliga överföringen:

ip route get 203.0.113.10
ip rule show
nft list ruleset

Om märket finns men räknarna aldrig rör sig matchar regeln inte. Räknare är skillnaden mellan en konfiguration du skrev och en policy som kärnan tillämpar.

När detta är fel verktyg

Portbaserade undantag är bräckliga till sin natur. Tjänster flyttar portar, HTTP/3 kommer som UDP 443, och en applikation kan öppna flera flöden av olika slag. Om det verkliga kravet är att detta program använder den vanliga länken är routinglagret fel plats; ett nätverksnamnrymd eller en proxy per applikation passar bättre.

Om kravet är att detta subnät använder den vanliga länken, hoppa över märkena helt och lägg till en mer specifik rutt. Det är enklare, det syns i en tabell, och nästa person kan granska det utan att läsa en regeluppsättning.

Skriv ned vilket av de tre kraven du faktiskt har innan du rör brandväggen. Mekanismen ovan är precis, och precision tillämpad på fel lager är bara ett längre avbrott.

Relaterade artiklar