Причвршћивање једног програма на VPN у Linux-у је пре свега проблем рутирања, а правило заштитног зида одлучује само шта се дешава након што се рута изабере. Ако у OUTPUT упарите UID програма пре него што тунел добије подразумевану руту, правило одбацује управо тај саобраћај који сте хтели да заштитите. Исто правило не види ни процес 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 пролази кроз ACCEPT за loopback, и управо ту подударање 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 правила сви показују у истом смеру; изоставите било које од њих и налог или цури, или губи везу.

Повезани чланци