Regels voor poort 80 en 443 sturen de browser niet door een VPN
Een poortmatch selecteert TCP-stromen, geen browser. HTTP/3 draait op UDP, DNS kan een andere route nemen, en een updater valt onder dezelfde regel die u schreef.
Iemand vraagt of de browser de tunnel kan gebruiken, en het antwoord komt terug als een firewallregel die overeenkomt met de bestemmingspoorten 80 en 443. Het ziet precies uit en dat is het niet. Een poortmatch selecteert pakketten op hun transportheader, niet op welk programma de socket opende, en modern browsen beperkt zich niet tot die twee poorten op TCP. De regel zal verkeer missen dat u wilde meenemen en verkeer vangen dat u nooit wilde aanraken. Bepaal voordat u hem schrijft welke van drie verschillende grenzen u eigenlijk wilt.
De regel beschrijft een transportklasse, geen toepassing
Op Linux onderzoekt een bestemmingspoortmatch de TCP-header en niets daarboven. Die pakketten markeren en met een beleidsroute sturen werkt precies zoals gedocumenteerd, en geen van die machines weet wat de payload betekent of welk proces hem stuurde. De markering is een nummer dat aan een pakket hangt, geen identiteit die aan een toepassing hangt.
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
Twee gevolgen volgen onmiddellijk. Een software-updater die TCP 443 contacteert, krijgt dezelfde behandeling als de browser, wat prima kan zijn of een storing die op de volgende updateronde wacht. En een webservice die bewust op een andere poort is gepubliceerd, zeg 8443, valt volledig buiten de regel terwijl het nog steeds het webverkeer is dat de gebruiker aanging.
De nummers zijn legitieme selectors wanneer de eis echt over die poorten gaat. Ze worden fictie wanneer er „browser” in de ticket staat en er een poortbereik in de regelset wordt geïmplementeerd. Dat gat is geen documentatiedetail. Het is het verschil tussen een regel die u in een review kunt verdedigen en een die niemand kan testen.
HTTP/3 verlaat stilletjes uw TCP-regel
HTTP/3 draait op QUIC, en QUIC wordt in UDP vervoerd. Een regel die alleen TCP matcht, kan het niet zien, dus dezelfde browser die uw testpagina haalt, kan een later verzoek via UDP sturen en de tunnel omzeilen zonder dat iemand een instelling wijzigt. RFC 9114 beschrijft HTTP/3 als een op QUIC gebaseerd protocol, en QUIC gebruikt UDP met een standaardpoort 443 in de gangbare uitrol.
Of een bepaalde browser HTTP/3 probeert, hangt af van de configuratie, van de site en van of een eerdere poging slaagde. Daardoor is het slecht om er uit het geheugen over te redeneren. Vraag het gereedschap:
curl --http3 -sS -o /dev/null -w '%{http_version} %{time_total}\n' https://example.com
ss -tunp | grep -E ':443\b'
De curl-regel drukt de onderhandelde versie af, dus een 3 bevestigt dat het UDP-pad is gebruikt. De socketlijst laat vervolgens zien of die verbinding aan de tunnelinterface of aan de fysieke is gebonden. Als HTTP/3 niet in uw curl-build zit, faalt de vlag luid in plaats van stil terug te vallen, wat zijn eigen kleine genade is.
DNS is een aparte beslissing die u moet nemen
Een poortregel voor webverkeer zegt niets over naamresolutie. De browser kan de systeemresolver gebruiken, een resolver die in de browser is geconfigureerd, of een die de laatste verbinding naar binnen duwde. Elk daarvan kan query's over een andere route sturen dan die uw regel kiest, wat de klassieke splitsing oplevert: de pagina laadt, de naam wordt ergens opgelost waar u het niet verwachtte, en de interne site lost op naar een openbaar adres of helemaal niet.
Bepaal dat expliciet. Als interne namen via de tunnel moeten worden opgelost, moet de resolver erin zitten, en de regelset moet DNS naar die resolver toestaan terwijl andere query's buiten blijven. Als de browser DNS over HTTPS naar een openbare provider gebruikt, omzeilt de query uw resolver volledig en kan de poortregel niet helpen. Schrijf de keuze in hetzelfde wijzigingsrecord als de routeringsregel, want beide worden samen gelezen door wie de volgende fout debugt.
Controleer het daarna met de resolver in plaats van met de pagina:
resolvectl query intranet.example.internal
resolvectl status | grep -A3 'Current DNS Server'
Een ontbrekend antwoord is een resolutieprobleem, zelfs wanneer de foutmelding van de browser het netwerk de schuld geeft. Die twee storingen zien er voor een gebruiker identiek uit en zijn volledig verschillende tickets.
Drie grenzen, drie verschillende mechanismen
Het meeste van de verwarring verdwijnt zodra u de grens noemt die u wilt. Ze zijn niet uitwisselbaar, en elk heeft een andere faalmodus tijdens een tunnelstoring.
| 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 |
Een apart browserprofiel is de valkuil in de middelste rij. Het scheidt cookies en geschiedenis, en het verandert niets aan de routeringstabel van de host, dus beide profielen nemen dezelfde route. Isolatie vereist iets wat de kernel afdwingt, dat wil zeggen een namespace, een container of een toepassing met een eigen tunnelinterface.
Welke rij ook geldt, schrijf op wat er moet gebeuren als de tunnel wegvalt. Een markeringsroute die met de interface verdwijnt, valt meestal terug op de fysieke standaardroute, wat fail-open-gedrag is. Dat kan acceptabel zijn voor browsen en onacceptabel voor al het andere, en het is een beslissing, geen implementatiedetail.
Test de stromen die u zegt te dekken
De acceptatietest moet de grens volgen die u hebt opgeschreven, niet de poortnummers die handig waren. Kies één stroom die door de tunnel moet, één die dat niet mag, en één die een transport gebruikt waar u niet aan had gedacht:
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'
De route-opvraag vertelt welke interface een bestemming werkelijk gebruikt, en dat is het feit dat de meeste rapporten verkeerd hebben. De curl-regel bevestigt de onderhandelde versie en de adresfamilie. De dump van de regelset vangt de regel die u tijdens het testen toevoegde en vergat af te bakenen, en zo wordt een tijdelijke markering permanente fail-open-routering.
Leg alle drie de uitvoer vast met een tijdstempel en bewaar ze bij de wijziging. Wanneer iemand later meldt dat „de VPN het intranet heeft gesloopt”, is het verschil tussen de beoogde en de geïmplementeerde grens zichtbaar in dat record, en de oplossing wordt een regelwijziging in plaats van een discussie.