Абыход cgroup у nftables таксама патрабуе выпраўлення адраса крыніцы
Маркіроўка аднаго cgroup накіроўвае яго ў іншую табліцу, а socket захоўвае адрас, які ўжо меў. Класіфікацыя, маршрутызацыя і трансляцыя — тры асобныя крокі.
Маркіроўка трафіку з аднаго cgroup — гэта простая частка. Тры асобныя рашэнні павінны супасці, перш чым адзін дадатак выйдзе праз фізічны інтэрфейс, пакуль усё астатняе застанецца ў тунелі: які socket належыць выключэнню, які пошук маршруту запускае маркер і які адрас крыніцы нясе пакет пры выхадзе. Большасць няўдалых спроб робіць першае правільна, другое — напалову, а на трэцяе наогул не глядзіць.
Тры рашэнні, а не адно
Класіфікацыя адказвае, хто вызвалены. Маршрутызацыя адказвае, куды замест гэтага ідзе пазначаны пакет. Выбар крыніцы адказвае, што ўбачыць далёкі бок і куды павінен вярнуцца адказ.
Гэта адмаўляе незалежна. Пакет можа быць класіфікаваны, перанакіраваны на фізічны інтэрфейс і ўсё яшчэ несці прыватны адрас, які ніводны вышэйшы маршрутызатар не зможа вярнуць; гэта стварае таймаўт, які выглядае дакладна як блакіроўка файрвола. Нішто на этапе класіфікацыі не папярэджвае пра гэта. Нішто і на этапе маршрутызацыі.
Парадак таксама важны. Класіфікацыя адбываецца пры стварэнні пакета, маршрутызацыя — пасля гэтага, а трансляцыя — у пункце выхаду.
Калі вы не можаце назваць, які з трох этапаў зламаны, вы не адладжваеце, а перастройваеце правілы і спадзяецеся.
Супстаўляйце cgroup, які будзе існаваць і заўтра
nftables можа праверыць прыналежнасць socket да cgroup v2, і гэта сапраўды карысна, бо вядзе за працэсам, а не за прызначэннем. Падвох — гэта ідэнтыфікатар. Праграма для працоўнага стала, запушчаная з меню, часта жыве ў часовым scope, імя якога змяняецца пры наступным запуску.
nft list ruleset
systemctl status session.slice 2>/dev/null
cat /proc/self/cgroupКалі скапіяваць імя scope з аднаго сеанса і жорстка закадаваць яго, атрымаецца правіла, якое працуе сёння і моўчкі перастае супадаць заўтра. Замест гэтага змясціце праграму ў наўмысна стабільны кантэкст выканання, напрыклад у выдзелены scope або unit, які вы кантралюеце, і супастаўляйце з ім. Тады правіла перажыве перазагрузкі і абнаўленні пакетаў. Яно таксама стане тым, пра што калега можа разважаць без вашай гісторыі сеансаў.
Таксама будзьце дакладнымі ў тым, які механізм вы выкарыстоўваеце. Класіфікацыя net_cls у cgroup v1 і супастаўленне socket у cgroup v2 — розныя рэчы, і поле з падобнай назвай у дакументацыі не робіць іх узаемазаменнымі.
Менавіта ланцуг тыпу route запускае другі пошук
Для лакальна створанага трафіку тып ланцуга вызначае, ці нешта адбудзецца пасля ўстаноўкі маркера. Ланцуг output тыпу filter можа пазначыць пакет, і ядро працягне выкарыстоўваць ужо выбраны маршрут. Ланцуг тыпу route — гэта механізм, які запытвае новы пошук.
table inet bypass {
chain mark {
type route hook output priority mangle; policy accept;
socket cgroupv2 level 2 "app.slice" meta mark set 0x1 comment "app bypass"
}
}
ip rule add fwmark 0x1 lookup 200
ip route add default via 203.0.113.1 dev wlan0 table 200Затым маркеру патрэбна правіла палітыкі, якое накіроўвае яго ў табліцу, і гэтая табліца павінна быць поўнай: маршрут па змаўчанні, любыя лакальныя прызначэнні, якія праграме яшчэ патрэбны, і вышэйшы шлюз, які сапраўды адказвае.
Выбірайце значэнне маркера свядома. WireGuard выкарыстоўвае ўласны fwmark для знешняга транспартнага трафіку, і выпадковае трапленне на той самы нумар можа перашкодзіць уласнаму маршрутнаму выключэнню тунеля так, што дыягнаставаць будзе балюча.
Адрас крыніцы не ідзе за маршрутам
Socket, які ўжо выбраў адрас крыніцы для шляху праз тунель, захоўвае гэты адрас пасля перанакіравання. Нішто ў змяненні маршруту не перапісвае яго, таму пакет пакідае фізічны інтэрфейс з прыватнай крыніцай, якую вышэйшая сетка не можа вярнуць.
Бачны сімптом — праграма, якая нібыта адпраўляе даныя і ніколі не атрымлівае адказу, і журнал файрвола, які нічога не паказвае, бо пакет так і не вярнуўся.
Вузкае выпраўленне — гэта правіла трансляцыі крыніцы, абмежаванае маркерам гэтай праграмы і яе рэальным знешнім інтэрфейсам, убудаванае ў існуючы NAT, а не замяняльнае яго:
table inet bypass {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
meta mark 0x1 oifname "wlan0" masquerade
}
}Транслюйце выключэнне і больш нічога. Агульнае правіла masquerade выпраўляе сімптом і знішчае вашу здольнасць сказаць, які трафік пайшоў якім шляхам. Супастаўляйце па маркеры, рэальным знешнім інтэрфейсе і, калі можаце, уласным адрасе праграмы. Шырокія правілы лёгка пісаць і амаль немагчыма аўдытаваць потым.
Што ўсё яшчэ ўцякае ад выключэння
Развязанне імёнаў можа прыходзіць ад асобнага працэсу resolver у іншым cgroup, таму класіфікацыя socket браўзера не класіфікуе яго запыты. Калі запыты resolver застаюцца ў тунелі, а злучэнне выходзіць па-за яго, адказы split-horizon могуць не адпавядаць шляху. Гэтая няўзгодненасць стварае збоі, якія выглядаюць як памылкі DNS, але імі не з'яўляюцца.
Даччыныя працэсы ў большасці налад наследавацьмуць cgroup, але дапаможнік, які пераносіць сябе ў свой scope, — не. Правярайце, а не мяркуйце, асабліва для ўсяго, што перазапускае сябе.
Нарэшце, вырашыце, што павінна адбывацца, калі тунель не працуе. Выключэнне, якое моўчкі становіцца поўным абыходам, — гэта іншая пазіцыя бяспекі, чым тое, якое адмаўляе закрыта, і толькі адна з іх — тое, што вы мелі на ўвазе.