Regler för port 80 och 443 skickar inte webbläsaren genom en VPN
En portträff väljer TCP-strömmar, inte en webbläsare. HTTP/3 körs över UDP, DNS kan ta en annan väg, och en uppdaterare träffar samma regel som du skrev.
Någon ber att webbläsaren ska använda tunneln, och svaret kommer tillbaka som en brandväggsregel som matchar målportarna 80 och 443. Den ser exakt ut och är det inte. En portträff väljer paket efter deras transportrubrik, inte efter vilket program som öppnade socketen, och modernt surfande begränsar sig inte till de två portarna på TCP. Regeln kommer att missa en del av trafiken du ville inkludera och fånga trafik du aldrig tänkt röra. Bestäm innan du skriver den vilken av tre olika gränser du egentligen vill ha.
Regeln beskriver en transportklass, inte en applikation
På Linux undersöker en målportträff TCP-rubriken och ingenting ovanför den. Att märka de paketen och styra dem med en policyrutt fungerar exakt som dokumenterat, och ingen av dessa maskinerier vet vad nyttolasten betyder eller vilken process som skickade den. Märket är ett nummer fäst vid ett paket, inte en identitet fäst vid en applikation.
nft add rule inet mangle output tcp dport { 80, 443 } meta mark set 0x1
ip rule add fwmark 0x1 table 100
ip route add default dev wg0 table 100
Två konsekvenser följer omedelbart. En programuppdatering som kontaktar TCP 443 får samma behandling som webbläsaren, vilket kan vara bra eller kan vara ett avbrott som väntar på nästa uppdateringscykel. Och en webbtjänst som medvetet publiceras på en annan port, säg 8443, faller helt utanför regeln trots att det fortfarande är den webbtrafik som användaren brydde sig om.
Talen är legitima selektorer när kravet verkligen handlar om de portarna. De blir fiktion när det står «webbläsare» i ärendet och ett portintervall implementeras i regeluppsättningen. Den luckan är ingen dokumentationsdetalj. Det är skillnaden mellan en regel du kan försvara i en granskning och en som ingen kan testa.
HTTP/3 lämnar tyst din TCP-regel
HTTP/3 körs över QUIC, och QUIC bärs i UDP. En regel som bara matchar TCP kan inte se det, så samma webbläsare som klarar din testsida kan skicka en senare begäran över UDP och kringgå tunneln utan att någon ändrar en inställning. RFC 9114 beskriver HTTP/3 som ett QUIC-baserat protokoll, och QUIC använder UDP med standardport 443 i den vanliga driftsättningen.
Om en viss webbläsare försöker med HTTP/3 beror på dess konfiguration, på webbplatsen och på om ett tidigare försök lyckades. Det gör det olämpligt att resonera om ur minnet. Fråga verktyget i stället:
curl --http3 -sS -o /dev/null -w '%{http_version} %{time_total}\n' https://example.com
ss -tunp | grep -E ':443\b'
curl-raden skriver ut den förhandlade versionen, så en 3 bekräftar att UDP-vägen användes. Socketlistan visar sedan om den anslutningen är bunden till tunnelns gränssnitt eller till det fysiska. Om HTTP/3 inte finns i din curl-bygge misslyckas flaggan högljutt i stället för att tyst falla tillbaka, vilket är dess egen lilla nåd.
DNS är ett eget beslut som du måste fatta
En portregel för webbtrafik säger ingenting om namnmatchning. Webbläsaren kan använda systemets resolver, en resolver som konfigurerats inuti webbläsaren eller en som den senaste anslutningen sköt in. Var och en av dem kan skicka frågor via en annan väg än den som din regel väljer, vilket ger den klassiska klyvningen: sidan laddas, namnet löses upp någonstans där du inte förväntade dig, och den interna webbplatsen löses upp till en offentlig adress eller inte alls.
Bestäm det uttryckligen. Om interna namn måste lösas upp genom tunneln måste resolvern ligga inuti den, och regeluppsättningen måste tillåta DNS till den resolvern medan andra frågor hålls utanför. Om webbläsaren använder DNS over HTTPS till en offentlig leverantör kringgår frågan din resolver helt och portregeln kan inte hjälpa. Skriv valet i samma ändringspost som routingregeln, eftersom de två läses tillsammans av den som felsöker nästa fel.
Verifiera sedan med resolvern i stället för med sidan:
resolvectl query intranet.example.internal
resolvectl status | grep -A3 'Current DNS Server'
Ett saknat svar är ett upplösningsproblem även när webbläsarens felmeddelande skyller på nätverket. De två felen ser identiska ut för en användare och är helt olika ärenden.
Tre gränser, tre olika mekanismer
Det mesta av förvirringen försvinner så snart du namnger den gräns du vill ha. De är inte utbytbara, och var och en har ett annat felläge vid ett tunnelavbrott.
| What you actually want | Mechanism that fits | What it does not cover |
|---|---|---|
| These transport ports use this exit | Firewall mark plus policy route | Applications, HTTP/3 over UDP, DNS |
| This browsing session stays separate | Application-aware VPN, or a separate network namespace plus a proxy | Other applications in the same session |
| Only these private sites are reachable | Destination-based routes with private DNS | Public sites on the same address family |
En separat webbläsarprofil är fällan i mittraden. Den skiljer kakor och historik och ändrar ingenting i värdens routingtabell, så båda profilerna tar samma väg. Isolering kräver något som kärnan tvingar fram, det vill säga ett namnutrymme, en container eller ett program som äger sitt eget tunnelgränssnitt.
Vilken rad som än gäller, skriv ned vad som ska hända när tunneln faller. En märkesbaserad rutt som försvinner med gränssnittet faller vanligtvis tillbaka på den fysiska standardrutten, vilket är fail-open-beteende. Det kan vara acceptabelt för surfande och oacceptabelt för allt annat, och det är ett beslut, inte en implementeringsdetalj.
Testa de strömmar du påstår att du täcker
Acceptanstestet måste följa den gräns du skrev ned, inte de portnummer som var bekväma. Välj en ström som måste gå genom tunneln, en som inte får, och en som använder en transport du inte tänkte på:
ip route get 203.0.113.40
curl -sS -o /dev/null -w 'v4 %{http_version} %{remote_ip}\n' https://example.com
nft list ruleset | grep -A2 'dport'
Ruttuppslaget talar om vilket gränssnitt ett mål verkligen använder, och det är det faktum som de flesta rapporter har fel om. curl-raden bekräftar den förhandlade versionen och adressfamiljen. Regeluppsättningens utskrift fångar den regel du lade till under testningen och glömde avgränsa, och så blir ett tillfälligt märke permanent fail-open-routing.
Logga alla tre utdata med tidsstämpel och förvara dem med ändringen. När någon senare rapporterar att «VPN:en förstörde intranätet» kommer skillnaden mellan den avsedda och den implementerade gränsen att synas i den loggen, och rättelsen blir en regeländring i stället för en diskussion.