Заявката винаги е вариант на едно и също изречение: запази VPN за сърфиране, но остави SSH или задача за архивиране да използва нормалната връзка. Съветът, който се разпространява за това, а именно да се прехвърли портът с правила на iptables NAT, не го прави. Правилото NAT пренаписва адреси и портове в рамките на поток; то никога не избира през кой интерфейс пакетът излиза. Това решение принадлежи на търсенето в маршрутната таблица, а то се нуждае от помощ, за да види порт.

Защо обикновен маршрут не може да съвпадне с порт

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

Съвременните iproute2 и ядра разширяват селектора на правилото: ipproto, sport и dport се приемат, така че ip rule add ipproto tcp dport 22 table 100 изразява намерението в един ред. Изпълнете ip rule add help на реалния хост, за да видите дали вашата сборка показва dport. Ако показва, готови сте с една команда; ако не, пътят с марка по-долу е еквивалентът.

Както и да е, правилото е само указател. Таблица 100 все още се нуждае от маршрут и точно тази част хората забравят.

Три части или една

Съвременната форма е единственото правило по-горе плюс маршрут в алтернативната таблица. Класическата форма добавя netfilter по средата: маркирайте пакета, после съпоставете марката в правило. И двете завършват в едно и също търсене; различават се по това къде се чете портът.

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

Трите части по ред

Първо, маркирайте потоците, които искате да отклоните, във верига, която се изпълнява достатъчно рано, за да съществува марката преди решението за маршрут:

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

Второ, изпратете маркираните пакети в отделна таблица:

ip rule add fwmark 0x1/0x1 table 100

Трето, дайте на тази таблица маршрут по подразбиране през физическата връзка. Адресите са примерни; заменете ги със свои:

ip route add default via 192.168.1.1 dev wlan0 table 100

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

Какво го държи работещо след първия пакет

Марките важат за изходящи пакети. Отговорът пристига на физическия интерфейс с адреса, който тази връзка е задала, и основната таблица може все още да предпочита тунела за това местоназначение. Два механизма поддържат пътя на отговора последователен: правило на база източник за адреса на връзката и проследяване на връзки, което запазва решението за целия живот на потока. Запазването на марката в conntrack и възстановяването ѝ при отговор е обичайният начин да се направи състояниево изключение стабилно.

Филтрирането по обратен път е другият тих убиец. Ако ядрото проверява строго обратния път и отговорът пристигне на интерфейс, който основната таблица не би избрала, пакетът се отхвърля без съобщение. rp_filter стойностите по подразбиране се различават според дистрибуцията и според това дали интерфейсът се препраща, затова четете ефективната стойност, вместо да предполагате, че е изключена.

Не маркирайте собствения транспорт на тунела. Тунел WireGuard или UDP OpenVPN не е TCP 22, затова рецептата по-горе е безопасна, но изключение, написано като всичко освен местоназначението на тунела, може да прихване криптираните пакети и да счупи тунела по начин, който изглежда като маршрутна примка.

Проверете го, вместо да предполагате

Попитайте ядрото кой път би избрало, за местоназначението и за порта, после изпълнете реалния трансфер:

ip route get 203.0.113.10
ip rule show
nft list ruleset

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

Кога това е грешният инструмент

Изключенията на база порт са крехки по природа. Услугите местят портове, HTTP/3 идва като UDP 443, а едно приложение може да отвори няколко потока от различен вид. Ако истинското изискване е тази програма да използва нормалната връзка, слоят за маршрутизация е грешното място; мрежово пространство от имена или прокси за отделно приложение пасват по-добре.

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

Запишете кое от трите изисквания всъщност имате, преди да пипате защитната стена. Механизмът по-горе е точен, а точност, приложена към грешния слой, е просто по-дълго прекъсване.

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