ერთი cgroup-იდან ტრაფიკის მონიშვნა მარტივი ნაწილია. სამი ცალკე გადაწყვეტილება უნდა დაემთხვეს, სანამ ერთი აპლიკაცია ფიზიკური ინტერფეისიდან გავა, დანარჩენი კი გვირაბში დარჩება: რომელი სოკეტი ეკუთვნის გამონაკლისს, რომელი მარშრუტის ძებნას იწვევს ნიშანი და რომელი წყაროს მისამართი ატარებს პაკეტი გასვლისას. წარუმატებელი ცდების უმეტესობა პირველს სწორად აკეთებს, მეორეს ნახევრად და მესამეს საერთოდ არ უყურებს.

სამი გადაწყვეტილება და არა ერთი

კლასიფიკაცია პასუხობს, ვინ არის გათავისუფლებული. მარშრუტიზაცია პასუხობს, სად მიდის მონიშნული პაკეტი. წყაროს შერჩევა პასუხობს, რას დაინახავს მოშორებული მხარე და სად უნდა დაბრუნდეს პასუხი.

ეს ერთმანეთისგან დამოუკიდებლად მარცხდება. პაკეტი შეიძლება დაიკლასიფიცირდეს, გადამისამართდეს ფიზიკურ ინტერფეისზე და მაინც ატაროს კერძო მისამართი, რომელსაც ზედა დინების ვერც ერთი მარშრუტიზატორი ვერ დააბრუნებს — ეს ქმნის დროის ამოწურვას, რომელიც ზუსტად ფაირვოლის ბლოკს ჰგავს. კლასიფიკაციის ნაბიჯში არაფერი გაფრთხილებთ ამაზე. მარშრუტიზაციის ნაბიჯშიც არაფერი.

რიგსაც აქვს მნიშვნელობა. კლასიფიკაცია ხდება პაკეტის შექმნისას, მარშრუტიზაცია ამის შემდეგ, ხოლო ტრანსლაცია გასასვლელ წერტილში.

თუ ვერ ასახელებ, რომელი სამი საფეხურიდან გატეხილია, დებაგს არ აკეთებ — წესებს გადაალაგებ და იმედოვნებ.

შეესაბამე cgroup-ს, რომელიც ხვალაც იარსებებს

nftables-ს შეუძლია სოკეტის cgroup v2-წევრობის შემოწმება, რაც ნამდვილად სასარგებლოა, რადგან ის პროცესს მიჰყვება და არა დანიშნულებას. ხაფანგი იდენტიფიკატორია. მენიუდან გაშვებული დესკტოპ-აპლიკაცია ხშირად გარდამავალ scope-ში ცხოვრობს, რომლის სახელი შემდეგ გაშვებაზე იცვლება.

nft list ruleset
systemctl status session.slice 2>/dev/null
cat /proc/self/cgroup

scope-ის სახელის ერთი სესიიდან კოპირება და ხისტად ჩაწერა წესს ქმნის, რომელიც დღეს მუშაობს და ხვალ ჩუმად წყვეტს შესაბამისობას. სამაგიეროდ მოათავსე აპლიკაცია განზრახ, სტაბილურ გაშვების კონტექსტში — მაგალითად, შენ მიერ კონტროლირებულ გამოყოფილ scope-ში ან unit-ში — და მას დაემთხვიე. მაშინ წესი გადაურჩება გადატვირთვებსა და პაკეტების განახლებებს. ის ასევე გახდება რამ, რაზეც კოლეგა შენი სესიის ისტორიის გარეშე იმსჯელებს.

ასევე ზუსტად განსაზღვრე, რომელ მექანიზმს იყენებ. cgroup v1-ის net_cls კლასიფიკაცია და cgroup v2-ის სოკეტის შესაბამისობა სხვადასხვა რამ არის და დოკუმენტაციაში მსგავსი სახელის ველი მათ ურთიერთშემცვლელს არ ხდის.

მეორე ძებნას სწორედ route-ჯაჭვი იწვევს

ლოკალურად გენერირებული ტრაფიკისთვის ჯაჭვის ტიპი განსაზღვრავს, მოხდება თუ არა რამე ნიშნის დაყენების შემდეგ. filter ტიპის output-ჯაჭვს შეუძლია პაკეტის მონიშვნა და ბირთვი გააგრძელებს უკვე არჩეული მარშრუტის გამოყენებას. route ტიპის ჯაჭვია ის მექანიზმი, რომელიც ახალ ძებნას ითხოვს.

table inet bypass {
  chain mark {
    type route hook output priority mangle; policy accept;
    socket cgroupv2 level 2 "app.slice" meta mark set 0x1 comment "app bypass"
  }
}
ip rule add fwmark 0x1 lookup 200
ip route add default via 203.0.113.1 dev wlan0 table 200

შემდეგ ნიშანს სჭირდება პოლისიის წესი, რომელიც მას ცხრილში აგზავნის, და ეს ცხრილი სრული უნდა იყოს: ნაგულისხმევი მარშრუტი, ლოკალური დანიშნულებები, რომლებიც აპლიკაციას ჯერ კიდევ სჭირდება, და ზედა დინების გეიტვეი, რომელიც ნამდვილად პასუხობს.

ნიშნის მნიშვნელობა განზრახ შეარჩიე. WireGuard გარე სატრანსპორტო ტრაფიკისთვის საკუთარ fwmark-ს იყენებს და შემთხვევით იმავე რიცხვზე მოხვედრამ შეიძლება ხელი შეუშალოს გვირაბის საკუთარ მარშრუტულ გამონაკლისს ისე, რომ დიაგნოსტიკა მტკივნეული იყოს.

წყაროს მისამართი მარშრუტს არ მიჰყვება

სოკეტი, რომელმაც უკვე შეარჩია წყაროს მისამართი გვირაბის გზისთვის, ინარჩუნებს მას გადამისამართების შემდეგ. მარშრუტის ცვლილებაში არაფერი გადაწერს მას, ამიტომ პაკეტი ფიზიკურ ინტერფეისიდან კერძო წყაროთი გადის, რომელსაც ზედა დინების ქსელი ვერ დააბრუნებს.

ხილვადი სიმპტომია აპლიკაცია, რომელიც თითქოს მონაცემებს აგზავნის და პასუხს არასდროს იღებს, და ფაირვოლის ჟურნალი, რომელიც არაფერს აჩვენებს, რადგან პაკეტი არასდროს დაბრუნდა.

ვიწრო გამოსავალია წყაროს ტრანსლაციის წესი, შემოფარგლული იმ აპლიკაციის ნიშნით და მისი რეალური გამომავალი ინტერფეისით, ინტეგრირებული უკვე არსებულ NAT-თან და არა მის შემცვლელად:

table inet bypass {
  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
    meta mark 0x1 oifname "wlan0" masquerade
  }
}

თარგმნე მხოლოდ გამონაკლისი და მეტი არაფერი. საერთო masquerade წესი სიმპტომს ასწორებს და ანადგურებს შენს უნარს, გაარკვიო რომელი ტრაფიკი რომელი გზით წავიდა. შეესაბამე ნიშანს, რეალურ გამომავალ ინტერფეისს და, თუ შესაძლებელია, თავად აპლიკაციის მისამართს. ფართო წესები ადვილად იწერება და მოგვიანებით აუდიტი თითქმის შეუძლებელია.

რა რჩება გამონაკლისის მიღმა

სახელების გარჩევა შეიძლება სხვა cgroup-ის ცალკე resolver-პროცესიდან მოვიდეს, ამიტომ ბრაუზერის სოკეტის კლასიფიკაცია მის ძებნებს არ კლასიფიცირებს. თუ resolver-ის მოთხოვნები გვირაბში რჩება, ხოლო კავშირი მის გარეთ გადის, split-horizon პასუხები გზას შეიძლება არ დაემთხვეს. ეს შეუსაბამობა წარმოქმნის ხარვეზებს, რომლებიც DNS-ის შეცდომას ჰგავს, მაგრამ არ არის.

შვილობილი პროცესები უმეტეს კონფიგურაციაში cgroup-ს მემკვიდრეობით იღებენ, მაგრამ დამხმარე, რომელიც თავს საკუთარ scope-ში გადაიტანს, არ იღებს. შეამოწმე და ნუ ივარაუდებ, განსაკუთრებით ყველაფერზე, რაც თავს ხელახლა უშვებს.

დაბოლოს, გადაწყვიტე, რა უნდა მოხდეს, როცა გვირაბი გამორთულია. გამონაკლისი, რომელიც ჩუმად სრულ გვერდის ავლად იქცევა, სხვა უსაფრთხოების პოზიციაა, ვიდრე ის, რომელიც დახურვით ვარდება, და მხოლოდ ერთი მათგანია ის, რაც გინდოდა.

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