nftables-ում cgroup-ի շրջանցումը նաև աղբյուրի հասցեի ուղղում է պահանջում
Մեկ cgroup նշելը ուղարկում է այն այլ աղյուսակ, իսկ socket-ը պահպանում է այն հասցեն, որ արդեն ուներ։ Դասակարգում, երթուղավորում և թարգմանություն՝ որպես երեք առանձին քայլ։
Մեկ cgroup-ից եկող թրաֆիկը նշելը հեշտ մասն է։ Երեք առանձին որոշումներ պետք է համաձայնեցվեն նախքան մեկ ծրագիր դուրս կգա ֆիզիկական ինտերֆեյսով, մինչ մնացած ամեն ինչ մնում է թունելում՝ որ socket-ն է պատկանում բացառությանը, որ երթուղային որոնումն է գործարկում նշանը, և որ աղբյուրի հասցեն է կրում փաթեթը դուրս գալիս։ Անհաջող փորձերի մեծ մասը ճիշտ է անում առաջինը, կիսով չափ՝ երկրորդը, և երբեք չի նայում երրորդին։
Երեք որոշում, ոչ թե մեկ
Դասակարգումը պատասխանում է ով է ազատված։ Երթուղավորումը պատասխանում է ուր է գնում նշված փաթեթը փոխարենը։ Աղբյուրի ընտրությունը պատասխանում է ինչ կտեսնի հեռավոր կողմը և ուր պետք է վերադառնա պատասխանը։
Սրանք ձախողվում են անկախ։ Փաթեթը կարող է դասակարգվել, վերաերթուղավորվել ֆիզիկական ինտերֆեյս, և այնուամենայնիվ կրել մասնավոր հասցե, որը ոչ մի վերին երթուղիչ չի կարող վերադարձնել, ինչը ստեղծում է ժամկետի սպառում, որը նույնական է firewall-ի արգելափակմանը։ Ոչինչ դասակարգման քայլում չի զգուշացնում դրա մասին։ Ոչինչ նաև երթուղավորման քայլում։
Հերթականությունը նույնպես կարևոր է։ Դասակարգումը տեղի է ունենում փաթեթի ստեղծման պահին, երթուղավորումը՝ դրանից հետո, իսկ թարգմանությունը՝ ելքի կետում։
Եթե չես կարող անվանել, թե երեք փուլերից որն է կոտրված, դու չես վրիպազերծում, այլ վերադասավորում ես կանոնները և հույս դնում։
Համապատասխանեցրու այնպիսի cgroup-ի, որը կմնա նաև վաղը
nftables-ը կարող է ստուգել socket-ի cgroup v2 անդամակցությունը, ինչը իսկապես օգտակար է, որովհետև հետևում է գործընթացին, ոչ թե նպատակակետին։ Խոչընդոտը նույնացուցիչն է։ Ընտրացանկից գործարկված աշխատասեղանի ծրագիրը հաճախ ապրում է անցողիկ scope-ում, որի անունը փոխվում է հաջորդ գործարկման ժամանակ։
nft list ruleset
systemctl status session.slice 2>/dev/null
cat /proc/self/cgroupScope-ի անունը մեկ նստաշրջանից պատճենելը և կոշտ կոդավորելը ստեղծում է կանոն, որն այսօր աշխատում է, իսկ վաղը լուռ դադարում է համապատասխանել։ Փոխարենը տեղադրիր ծրագիրը դիտավորյալ կայուն կատարման համատեքստում, օրինակ՝ քո կառավարած առանձին scope կամ unit, և համապատասխանեցրու դրան։ Այն ժամանակ կանոնը վերապրում է վերագործարկումները և փաթեթների թարմացումները։ Այն նաև դառնում է մի բան, որի մասին գործընկերը կարող է մտածել առանց քո նստաշրջանների պատմության։
Եղիր նաև ճշգրիտ այն մեխանիզմի հարցում, որն օգտագործում ես։ cgroup v1-ի net_cls դասակարգումը և cgroup v2-ի socket համապատասխանեցումը տարբեր բաներ են, և փաստաթղթերում նման անունով դաշտը դրանք փոխարինելի չի դարձնում։
route տիպի շղթան է, որ գործարկում է երկրորդ որոնումը
Տեղում ստեղծված թրաֆիկի համար շղթայի տիպը որոշում է՝ ինչ-որ բան տեղի կունենա արդյոք նշանը դնելուց հետո։ filter տիպի ելքային շղթան կարող է նշել փաթեթը, և միջուկը կշարունակի օգտագործել արդեն ընտրված երթուղին։ 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-ը արտաքին տրանսպորտային թրաֆիկի համար, և պատահաբար նույն թվին հանդիպելը կարող է խանգարել թունելի սեփական երթուղային բացառությանը այնպիսի ձևերով, որ ախտորոշելը ցավոտ է։
Աղբյուրի հասցեն չի հետևում երթուղուն
Այն socket-ը, որն արդեն ընտրել է աղբյուրի հասցե թունելի ուղու համար, պահպանում է այդ հասցեն վերաերթուղավորումից հետո։ Ոչինչ երթուղու փոփոխության մեջ չի վերագրում այն, դրա համար էլ փաթեթը լքում է ֆիզիկական ինտերֆեյսը մասնավոր աղբյուրով, որը վերին ցանցը չի կարող վերադարձնել։
Տեսանելի ախտանիշը ծրագիր է, որը կարծես տվյալներ է ուղարկում և երբեք պատասխան չի ստանում, և firewall-ի մատյան, որը ոչինչ չի ցույց տալիս, որովհետև փաթեթը երբեք չվերադարձավ։
Նեղ ուղղումը աղբյուրի թարգմանության կանոն է՝ սահմանափակված այդ ծրագրի նշանով և նրա իրական ելքային ինտերֆեյսով, ինտեգրված գոյություն ունեցող NAT-ին՝ այն փոխարինելու փոխարեն։
table inet bypass {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
meta mark 0x1 oifname "wlan0" masquerade
}
}Թարգմանիր բացառությունը և ուրիշ ոչինչ։ Ընդհանուր masquerade կանոնը շտկում է ախտանիշը և ոչնչացնում է քո կարողությունը ասելու, թե որ թրաֆիկն որ ուղին գնաց։ Համապատասխանեցրու նշանին, իրական ելքային ինտերֆեյսին և, եթե կարող ես, ծրագրի սեփական հասցեին։ Լայն կանոնները հեշտ են գրվում և գրեթե անհնար է ավելի ուշ աուդիտ անել։
Ինչ դեռ դուրս է սահում բացառությունից
Անունների լուծումը կարող է գալ առանձին resolver գործընթացից այլ cgroup-ում, ուստի զննարկիչի socket-ի դասակարգումը չի դասակարգում նրա հարցումները։ Եթե resolver-ի հարցումները մնում են թունելում, մինչ կապը դուրս է գալիս դրանից, split-horizon պատասխանները կարող են չհամապատասխանել ուղուն։ Այդ անհամապատասխանությունը ստեղծում է խափանումներ, որոնք նման են DNS սխալների և այդպիսին չեն։
Երեխա գործընթացները ժառանգում են cgroup-ը շատ կարգավորումներում, բայց օգնականը, որն ինքն իրեն տեղափոխում է իր scope, չի ժառանգում։ Ստուգիր, ոչ թե ենթադրիր, հատկապես այն ամենի համար, ինչ նորից գործարկում է ինքն իրեն։
Վերջում որոշիր, թե ինչ պետք է լինի, երբ թունելն անջատված է։ Բացառությունը, որը լուռ դառնում է ամբողջական շրջանցում, այլ անվտանգության դիրքորոշում է, քան փակ վիճակում ձախողվողը, և դրանցից միայն մեկն է այն, ինչ նկատի ունեիր։