Како да закачите една Linux апликација на VPN со UID правила
UID правило гледа само локални сокети, а вообичаениот loopback исклучок го убива тунелот. Прво насочете ја сметката, потоа филтрирајте и проверете го секој чекор.
Закачувањето на една програма на VPN во Linux е главно проблем со рутирањето, а правилото на огнениот ѕид одлучува само што се случува откако ќе се избере рутата. Ако го совпаднете UID-от на програмата во OUTPUT пред тунелот да ја поседува стандардната рута, правилото го отфрла токму сообраќајот што сакавте да го заштитите. Истото правило не го гледа ниту процесот на resolver што одговара на 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 пакет од програмата оди до локалниот stub низ lo. Ставете ги двете правила во овој редослед и сметката стигнува до stub, потоа до тунелот, и никаде друго.
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 поминува низ loopback ACCEPT, и токму таму совпаѓањето на UID запира. Stub resolver препраќа нагоре од својата сервисна сметка, затоа правило сврзано со vpnapp никогаш не го гледа второто барање. Ако resolver избере LAN сервер за врската, одговорите се враќаат низ физичката NIC, додека сопствените пакети на програмата остануваат во тунелот. Видливиот резултат е работен тунел со скршени имиња, или имиња на кои одговара сервер што не сте го избрале.
Поправете го разрешувањето имиња на врската на тунелот, не во апликацијата. Дајте му на профилот на тунелот DNS сервер и домен за рутирање, потоа потврдете со resolvectl query и resolvectl status tun0 дека resolver го користи за имињата што се важни. Внатре во мрежен именски простор проблемот исчезнува, бидејќи resolver на просторот го знае само тунелот.
Проверете го правилото од самата сметка
Прашајте го јадрото која рута ја добива 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. Ако тој товар треба да се покрие, тестирајте го одделно и напишете политика врзана за мостот или адресата на контејнерот. Дизајнот држи кога табелата, исклучокот за интерфејс, resolver и v6 правилата сите покажуваат во иста насока; испуштете кое било од нив и сметката или истекува или ја губи врската.