Каб вывесці адзін порт з VPN, патрэбна маршрутызацыя па палітыках
Правіла NAT перапісвае адрасы, але не выбірае інтэрфейс выхаду. Вось правіла, табліца і метка, якія сапраўды трымаюць адзін порт TCP па-за тунелем.
Запыт заўсёды ёсць варыянтам аднаго і таго ж сказа: пакінуць 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, і нават адна праграма можа адкрыць некалькі патокаў рознага выгляду. Калі сапраўднае патрабаванне — каб гэтая праграма ішла праз звычайнае звяно, узровень маршрутызацыі не тое месца; сеткавая прастора імёнаў або проксі для асобнай праграмы падыходзяць лепш.
Калі патрабаванне — каб гэтая падсетка ішла праз звычайнае звяно, цалкам прапусціце меткі і дадайце больш канкрэтны маршрут. Гэта прасцей, гэта бачна ў адной табліцы, і наступны чалавек можа прааўдытаваць гэта, не чытаючы набор правілаў.
Запішыце, якое менавіта з трох патрабаванняў у вас ёсць, перш чым кранаць фільтр. Механізм вышэй дакладны, а дакладнасць, прымянёная не да таго ўзроўню, — гэта проста даўжэйшы збой.