ერთი პროგრამის VPN-ზე მიბმა Linux-ზე ძირითადად მარშრუტიზაციის პრობლემაა, და 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 მუშაობს, ბირთვმა უკვე აირჩია გასასვლელი ინტერფეისი, ამიტომ -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, შემდეგ გააკეთეთ მოთხოვნა ამ ანგარიშით და შეადარეთ გასვლის მისამართი საკუთარი ანგარიშისას. თუ ორივე ერთსა და იმავე მისამართს იუწყება, წესი თქვენ მიერ შემოწმებული ტრაფიკის გარდა სხვა რამეს ემთხვევა. ქვემოთ პირველი ბრძანება მარშრუტის ძიებას აჩვენებს პაკეტის გაგზავნის გარეშე, რაც მარშრუტიზაციის შეცდომას 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 წესები ყველა ერთი მიმართულებით მიუთითებს; ერთ-ერთი მათგანი გამოტოვეთ და ანგარიში ან გაჟონავს, ან კავშირს დაკარგავს.

დაკავშირებული სტატიები