Някой иска браузърът да използва тунела и заявката се връща като правило на защитна стена, съвпадащо с портовете на местоназначението 80 и 443. Изглежда точно и не е. Съвпадението по порт избира пакети по транспортния им заглавен блок, а не по това коя програма е отворила сокета, и съвременното сърфиране не се ограничава до тези два порта по TCP. Правилото ще пропусне част от трафика, който сте искали да включите, и ще улови трафик, който никога не сте възнамерявали да докосвате. Преди да го напишете, решете коя от трите различни граници всъщност искате.

Правилото описва транспортен клас, не приложение

В Linux съвпадението по порт на местоназначението преглежда TCP заглавката и нищо над нея. Маркирането на тези пакети и насочването им с политически маршрут работи точно както е документирано и никой от тези механизми не знае какво означава полезният товар и кой процес го е изпратил. Марката е число, прикрепено към пакет, а не идентичност, прикрепена към приложение.

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

Веднага следват две последици. Програма за обновяване, която се свързва с TCP 443, получава същото отношение като браузъра, което може да е добре или може да е прекъсване, чакащо следващия цикъл на обновяване. А уеб услуга, публикувана умишлено на друг порт, да речем 8443, изцяло изпада от правилото, макар че все още е уеб трафикът, за който потребителят е бил загрижен.

Числата са законни селектори, когато изискването наистина е за тези портове. Те стават фикция, когато в заявката е написано „браузър“, а в набора от правила е реализиран диапазон от портове. Тази разлика не е документационна дребнавост. Тя е разликата между правило, което можете да защитите при преглед, и такова, което никой не може да тества.

HTTP/3 тихо изоставя вашето TCP правило

HTTP/3 работи върху QUIC, а QUIC се пренася в UDP. Правило, което съвпада само с TCP, не може да го види, така че същият браузър, който удовлетворява тестовата ви страница, може да изпрати следваща заявка по UDP и да заобиколи тунела, без никой да промени настройка. RFC 9114 описва HTTP/3 като протокол, базиран на QUIC, а QUIC използва UDP с порт по подразбиране 443 при обичайното разгръщане.

Дали даден браузър ще опита HTTP/3 зависи от конфигурацията му, от сайта и от това дали предишен опит е успял. Това го прави лош обект за разсъждение по памет. Попитайте инструмента вместо това:

curl --http3 -sS -o /dev/null -w '%{http_version} %{time_total}\n' https://example.com
ss -tunp | grep -E ':443\b'

Редът curl отпечатва договорената версия, така че 3 потвърждава, че е използван пътят през UDP. Списъкът на сокетите после показва дали тази връзка е вързана към интерфейса на тунела, или към физическия. Ако HTTP/3 липсва в компилацията ви на curl, флагът се проваля шумно, вместо тихо да отстъпи, което си е негова малка милост.

DNS е отделно решение, което трябва да вземете

Правило за порт за уеб трафик не казва нищо за разрешаването на имена. Браузърът може да използва системния резолвер, резолвер, конфигуриран вътре в браузъра, или такъв, изпратен от последното свързване. Всеки от тях може да изпраща заявки по различен път от този, който избира вашето правило, което дава класическото разделение: страницата се зарежда, името се разрешава някъде, където не сте очаквали, а вътрешният сайт се разрешава до публичен адрес или изобщо не се разрешава.

Решете го изрично. Ако вътрешните имена трябва да се разрешават през тунела, резолверът трябва да е вътре в него, а наборът от правила трябва да разрешава DNS към този резолвер, като държи другите заявки навън. Ако браузърът използва DNS over HTTPS към публичен доставчик, заявката заобикаля изцяло вашия резолвер и правилото за порт не може да помогне. Запишете избора в същия запис за промяна като правилото за маршрутизиране, защото двете се четат заедно от този, който ще отстранява следващия отказ.

После проверете с резолвера, не със страницата:

resolvectl query intranet.example.internal
resolvectl status | grep -A3 'Current DNS Server'

Липсващият отговор е проблем с разрешаването дори когато съобщението за грешка на браузъра обвинява мрежата. Тези два отказа изглеждат еднакви за потребителя и са напълно различни задачи.

Три граници, три различни механизма

Повечето от объркването изчезва, щом назовете границата, която искате. Те не са взаимозаменяеми и всяка има различен режим на отказ при прекъсване на тунела.

What you actually wantMechanism that fitsWhat it does not cover
These transport ports use this exitFirewall mark plus policy routeApplications, HTTP/3 over UDP, DNS
This browsing session stays separateApplication-aware VPN, or a separate network namespace plus a proxyOther applications in the same session
Only these private sites are reachableDestination-based routes with private DNSPublic sites on the same address family

Отделен профил на браузъра е капанът в средния ред. Той разделя бисквитки и история и не променя нищо в таблицата за маршрутизиране на хоста, така че двата профила поемат един и същ път. Изолацията изисква нещо, което ядрото налага, тоест пространство от имена, контейнер или приложение, което притежава собствен интерфейс за тунел.

Който и ред да важи, запишете какво трябва да се случи, когато тунелът падне. Маршрут на базата на марка, който изчезва с интерфейса, обикновено се връща към физическия маршрут по подразбиране, което е поведение fail-open. Това може да е приемливо за сърфиране и неприемливо за всичко друго и е решение, а не подробност на реализацията.

Тествайте потоците, които твърдите, че покривате

Приемателният тест трябва да следва границата, която сте записали, а не номерата на портове, които са били удобни. Изберете един поток, който трябва да минава през тунела, един, който не трябва, и един, който използва транспорт, за който не сте се сетили:

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'

Търсенето на маршрут ви казва кой интерфейс всъщност използва дадено местоназначение, а това е фактът, който повечето доклади сбъркват. Редът curl потвърждава договорената версия и семейството адреси. Извеждането на набора от правила улавя правилото, което сте добавили по време на тестването и сте забравили да ограничите, и точно така временна марка се превръща в постоянна маршрутизация с fail-open.

Запишете и трите изхода с времева марка и ги пазете с промяната. Когато по-късно някой съобщи, че „VPN счупи вътрешната мрежа“, разликата между предвидената и реализираната граница ще се види в този запис и поправката ще бъде промяна в правило, а не спор.

Подобни статии