Մի ծրագիր Linux-ում VPN-ին կապելը հիմնականում երթուղավորման խնդիր է, և firewall-ի կանոնը որոշում է միայն այն, թե ինչ է լինում երթուղու ընտրությունից հետո։ Եթե ծրագրի UID-ն համընկնեք OUTPUT-ում այն բանից առաջ, երբ թունելը տիրանա լռելյայն երթուղուն, կանոնը կթափի հենց այն երթևեկությունը, որը ցանկանում էիք պաշտպանել։ Նույն կանոնը չի տեսնում նաև resolver-ի պրոցեսը, որը պատասխանում է ծրագրի DNS հարցումներին։ Կարգը դրեք ճիշտ, և մեկ արտոնություն չունեցող հաշիվը դառնում է բաժանված թունելի վստահելի ընտրիչ։

Երթուղի տվեք հաշվին մինչև դատավճիռը

Սեփականատիրոջ համընկնումը պատասխանում է մեկ հարցի՝ արդյոք այս UID-ին պատկանող տեղական սոքեթը կառուցել է փաթեթը։ Այն չի ընտրում ինտերֆեյս և չի կարող տեղափոխել այն երթևեկությունը, որը հիմնական աղյուսակն արդեն ուղարկում է ֆիզիկական NIC-ով։ Դրա համար է, որ համապատասխան երթուղի չունեցող UID կանոնը արգելափակում է ծրագիրը՝ այն վերահասցեավորելու փոխարեն։

Նախ հաշիվն անցկացրեք նրա սեփական աղյուսակով, ապա թույլ տվեք firewall-ին հաստատել արդյունքը։ Սա աշխատում է այն հոսթի վրա, որի 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-ի, ոչ թե firewall-ի սխալի։

Երբ OUTPUT-ը աշխատում է, kernel-ն արդեն ընտրել է ելքային ինտերֆեյս, ուստի -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-ը ճանաչում է միայն թունելը։

Ստուգեք կանոնը հենց հաշվից

Հարցրեք kernel-ին, թե UID-ն ինչ երթուղի է ստանում, ապա հարցում կատարեք որպես այդ հաշիվ և համեմատեք ելքի հասցեն ձեր սեփական հաշվի հասցեի հետ։ Եթե երկուսն էլ նույն հասցեն հաղորդեն, կանոնը համընկնում է ձեր փորձարկած երթևեկությունից բացի այլ բանի հետ։ Ներքևի առաջին հրամանը ցույց է տալիս երթուղու որոնումը առանց փաթեթ ուղարկելու, ինչը տարանջատում է երթուղավորման սխալը firewall-ի սխալից։

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 կանոնները բոլորը նույն ուղղությունն են ցույց տալիս․ բաց թողեք դրանցից որևէ մեկը, և հաշիվը կա՛մ արտահոսում է, կա՛մ կորցնում է կապը։

Առնչվող հոդվածներ