Прывязаць адну праграму да VPN у Linux — гэта пераважна задача маршрутызацыі, а правіла файрвола вырашае толькі тое, што адбываецца пасля выбару маршруту. Калі супаставіць UID праграмы ў OUTPUT раней, чым тунэль атрымае маршрут па змаўчанні, правіла скіне менавіта той трафік, які вы хацелі абараніць. Тое ж правіла не бачыць і працэс рэзалвера, які адказвае на DNS-запыты праграмы. Выбудуйце парадак правільна, і адзін уліковы запіс без прывілеяў стане надзейным сродкам выбару для раздзеленага тунэлю.

Дайце ўліковаму запісу маршрут раней за вердыкт

Супастаўленне ўласніка адказвае на адно пытанне: ці пабудаваў пакет лакальны сокет, што належыць гэтаму UID? Яно не выбірае інтэрфейс і не можа перамясціць трафік, які галоўная табліца ўжо адпраўляе праз фізічны NIC. Таму правіла UID без адпаведнага маршруту блакуе праграму замест таго, каб перанакіраваць яе.

Прапусціце ўліковы запіс праз яго ўласную табліцу, а потым дайце файрволу пацвердзіць вынік. Гэта працуе на хасту, чый iproute2 разумее uidrange, што ip rule help паведамляе ў адным радку. Табліца 100 трымае маршрут па змаўчанні праз тунэль, і правіла накіроўвае толькі UID 1000 у гэтую табліцу. Усё астатняе застаецца ў галоўнай табліцы і далей выкарыстоўвае фізічнае злучэнне.

ip rule add uidrange 1000-1000 table 100
ip route add default dev tun0 table 100

Другі ўліковы запіс, якому патрэбны іншы тунэль, атрымлівае табліцу 101 і сваё правіла, бо два профілі не могуць адначасова валодаць маршрутам па змаўчанні ў адной табліцы. Профілі NetworkManager сістэмныя, таму гэтая частка застаецца ручной, і правілы знікаюць пасля перазагрузкі, калі нешта іх не аднавіць. Запішыце табліцы ў скрыпт загрузкі побач з вызначэннем тунэлю, каб перападключэнне не пакінула адзін уліковы запіс на няправільным шляху.

Чаму вынятак для loopback забівае тунэль

Большасць скапіяваных версій правіла скідвае кожны пакет, які не выходзіць праз loopback. Тунэль не loopback, таму такая форма скідвае і трафік тунэлю, і вынік выглядае як мёртвы VPN, а не як памылка файрвола.

Калі OUTPUT ужо працуе, ядро ўжо выбрала зыходны інтэрфейс, таму -o параўноўваецца з адказам маршруту, а не з загалоўкам пакета. Супастаўленне ўласніка ужываецца толькі ў OUTPUT і POSTROUTING, а перанакіраваныя пакеты не маюць сокета, які яно магло б прачытаць. Такая камбінацыя азначае, што вынятак мусіць назваць інтэрфейс тунэлю і адмаўляць гэтае супастаўленне, а не адмаўляць loopback.

Loopback усё яшчэ заслугоўвае ўласны ACCEPT над DROP, бо першы DNS-пакет ад праграмы ідзе да лакальнага стуба праз lo. Размясціце два правілы ў гэтым парадку, і ўліковы запіс дасягае стуба, потым тунэлю, і нічога іншага.

iptables -I OUTPUT 1 -o lo -m owner --uid-owner vpnapp -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner vpnapp ! -o tun0 -j DROP

IPv6 — асобны набор правілаў, і пара толькі для v4 пакідае ip6tables некранутым. Праграма, якая аддае перавагу запісам AAAA, тады выйшла б праз фізічнае злучэнне, так і не дасягнуўшы DROP. Люструйце абодва правілы ў ip6tables, або адключыце IPv6 на хасту, калі тунэль не нясе адраса v6. Правілы, дададзеныя ўручную, таксама знікаюць пасля перазагрузкі, таму захавайце іх праз netfilter-persistent save або перабудуйце тую ж логіку як табліцу nftables, якую загружае блок загрузкі.

DNS-адказы прыходзяць з іншага працэсу

Запыт праграмы да 127.0.0.53 праходзіць ACCEPT для loopback, і менавіта там супастаўленне UID спыняецца. Рэзалвер-стуб перасылае запыт уверх са свайго службовага ўліковага запісу, таму правіла, прывязанае да vpnapp ніколі не бачыць другі запыт. Калі рэзалвер выбірае LAN-сервер для злучэння, адказы вяртаюцца праз фізічны NIC, пакуль уласныя пакеты праграмы застаюцца ў тунэлі. Бачны вынік — працоўны тунэль са зламанымі імёнамі або імёны, на якія адказвае сервер, які вы не выбіралі.

Выпраўце развязанне імёнаў на злучэнні тунэлю, а не ў праграме. Дайце профілю тунэлю DNS-сервер і дамен маршрутызацыі, потым пацвердзіце праз resolvectl query і resolvectl status tun0 што рэзалвер выкарыстоўвае яго для імёнаў, якія маюць значэнне. Унутры сеткавага прасторы імёнаў праблема знікае, бо рэзалвер прасторы ведае толькі тунэль.

Праверце правіла з самога ўліковага запісу

Спытайце ядро, які маршрут атрымае UID, потым зрабіце запыт ад гэтага ўліковага запісу і параўнайце адрас выхаду з адрасам вашага ўласнага. Калі абодва паведамляюць той самы адрас, правіла супастаўляе нешта іншае, чым трафік, які вы праверылі. Першая каманда ніжэй паказвае пошук маршруту без адпраўкі пакета, што аддзяляе памылку маршрутызацыі ад памылкі файрвола.

ip route get 1.1.1.1 uid 1000
sudo -u vpnapp curl -s https://ifconfig.co

Лічыльнікі паказваюць, ці правіла калі-небудзь спрацавала. Выканайце iptables -vnL OUTPUT, прачытайце колькасць пакетаў каля кожнага правіла і лічыце нуль каля DROP пасля рэальнага трафіку памылкай супастаўлення.

Перанакіраваны трафік знаходзіцца па-за гэтым дызайнам. Кантэйнер або VM за мостам не мае лакальнага сокета, які належыць vpnapp, таму супастаўленне ўласніка ніколі не спрацоўвае, і гэтыя пакеты ідуць па палітыцы FORWARD. Калі такую нагрузку трэба пакрыць, праверце яе асобна і напішыце палітыку, прывязаную да моста або адраса кантэйнера. Дызайн трымаецца, калі табліца, вынятак інтэрфейсу, рэзалвер і правілы v6 усе паказваюць у адзін бок; пакіньце хоць адно з іх, і ўліковы запіс або працячэ, або страціць сувязь.

Падобныя артыкулы