Kiçiklər üçün BPF, sıfır hissə: klassik BPF

Berkeley Paket Filtrləri (BPF) artıq bir neçə ildir ki, ingilisdilli texniki nəşrlərin ön səhifələrində yer alan Linux nüvəsi texnologiyasıdır. Konfranslar BPF-nin istifadəsi və inkişafı haqqında söhbətlərlə doludur. Devid Miller, Linux Şəbəkə Alt Sistemi Meneceri, Linux Plumbers 2018-də çıxışını elan edir "Bu söhbət XDP ilə bağlı deyil" (XDP BPF üçün bir istifadə halıdır). Brendan Gregg adlı danışıqlar aparır Linux BPF Super Gücləri. Toke Høiland-Jørgensen gülürnüvənin indi mikrokernel olduğunu. Tomas Qraf bu fikri irəli sürür BPF əsas üçün javascriptdir.

Habré-də BPF-nin sistemli təsviri hələ də yoxdur və buna görə də bir sıra məqalələrdə texnologiyanın tarixi haqqında danışmağa, arxitektura və inkişaf vasitələrini təsvir etməyə, BPF-dən istifadənin tətbiqi və praktika sahələrini təsvir etməyə çalışacağam. Dövrün bu, sıfır məqaləsi klassik BPF-nin tarixini və memarlığını izah edir, həm də iş prinsiplərinin sirlərini açır. tcpdump, seccomp, strace, və daha çox.

BPF-nin inkişafı Linux şəbəkə icması tərəfindən idarə olunur, BPF-nin əsas mövcud tətbiqləri şəbəkələrlə bağlıdır və buna görə də icazə ilə @eucariot, Serialı böyük seriyanın şərəfinə "Kiçiklər üçün BPF" adlandırdım "Kiçiklər üçün şəbəkələr".

BPF-nin qısa tarixi(c)

Müasir BPF texnologiyası qarışıqlığın qarşısını almaq üçün klassik BPF adlandırılan eyni adlı köhnə texnologiyanın təkmilləşdirilmiş və genişləndirilmiş versiyasıdır. Klassik BPF əsasında tanınmış bir yardım proqramı yaradıldı tcpdump, mexanizm seccomp, eləcə də az tanınan modul xt_bpf uğrunda iptables və təsnifatçı cls_bpf. Müasir Linux-da klassik BPF proqramları avtomatik olaraq yeni formaya çevrilir, lakin istifadəçinin nöqteyi-nəzərindən API öz yerində qalıb və bu məqalədə görəcəyimiz kimi klassik BPF-nin yeni istifadələri hələ də tapılır. Bu səbəbdən, həm də Linux-da klassik BPF-nin inkişaf tarixini izləyərək onun necə və nə üçün müasir bir formaya çevrildiyi daha aydın olacaq, mən klassik BPF haqqında məqalə ilə başlamaq qərarına gəldim.

Ötən əsrin səksəninci illərinin sonlarında məşhur Lawrence Berkeley Laboratoriyasının mühəndisləri ötən əsrin səksəninci illərinin sonları üçün müasir aparatlarda şəbəkə paketlərini düzgün süzgəcdən keçirmə sualı ilə maraqlandılar. Əvvəlcə CSPF (CMU/Stanford Packet Filter) texnologiyasında tətbiq edilən filtrləmənin əsas ideyası lazımsız paketləri mümkün qədər tez süzmək idi, yəni. nüvə məkanında, çünki bu, lazımsız məlumatların istifadəçi sahəsinə kopyalanmasının qarşısını alır. Kernel məkanında istifadəçi kodunun işlədilməsi üçün iş vaxtı təhlükəsizliyini təmin etmək üçün sandboxed virtual maşından istifadə edilmişdir.

Bununla belə, mövcud filtrlər üçün virtual maşınlar yığın əsaslı maşınlarda işləmək üçün nəzərdə tutulmuşdu və yeni RISC maşınlarında o qədər də səmərəli işləmədi. Nəticədə, Berkeley Labs mühəndislərinin səyləri ilə virtual maşın arxitekturası Motorola 6502 prosessoru əsasında hazırlanmış, yeni BPF texnologiyası (Berkeley Paket Filtrləri) işləyib hazırladı. Apple II və ya NES. Yeni virtual maşın mövcud həllərlə müqayisədə filtrlərin işini onlarla dəfə artırıb.

BPF Maşın Memarlığı

Biz nümunələri təhlil edərək arxitektura ilə işlək şəkildə tanış olacağıq. Bununla belə, başlamaq üçün deyək ki, maşında istifadəçi üçün iki 32 bitlik registr, akkumulyator var idi. A və indeks reyestri X, yazmaq və sonrakı oxumaq üçün 64 bayt yaddaş (16 söz) və bu obyektlərlə işləmək üçün kiçik təlimatlar dəsti var. Şərti ifadələri yerinə yetirmək üçün proqramlarda atlama təlimatları da mövcud idi, lakin proqramın vaxtında tamamlanmasını təmin etmək üçün yalnız irəli tullanmaq mümkün idi, yəni. xüsusilə, döngələr yaratmaq qadağan edildi.

Maşını işə salmağın ümumi sxemi aşağıdakı kimidir. İstifadəçi BPF arxitekturası üçün proqram yaradır və istifadə edir bəziləri nüvə mexanizmi (məsələn, sistem çağırışı), proqramı yükləyir və birləşdirir bəzilərinə nüvədəki hadisə generatoru (məsələn, hadisə növbəti paketin şəbəkə kartına gəlməsidir). Hadisə baş verdikdə, nüvə proqramı işlədir (məsələn, tərcüməçidə), maşın yaddaşı isə bəzilərinə nüvənin yaddaş bölgəsi (məsələn, gələn paketin məlumatları).

Nümunələrin təhlilinə başlamaq üçün yuxarıda deyilənlər kifayət edəcək: lazım gəldikdə sistem və əmr formatı ilə tanış olacağıq. Bir virtual maşının komanda sistemini dərhal öyrənmək və onun bütün imkanlarını öyrənmək istəyirsinizsə, orijinal məqaləni oxuya bilərsiniz. BSD paket filtri və/və ya faylın birinci yarısı Documentation/şəbəkə/filter.txt kernel sənədlərindən. Bundan əlavə, təqdimata baxa bilərsiniz libpcap: Paket Tutma üçün Memarlıq və Optimallaşdırma Metodologiyası, BPF-nin müəlliflərindən biri olan Makkann yaradılış tarixindən bəhs edir libpcap.

Linux-da klassik BPF-nin istifadəsinə dair bütün əhəmiyyətli nümunələrin nəzərdən keçirilməsinə müraciət edirik: tcpdump (libpcap), seccomp, xt_bpf, cls_bpf.

tcpdump

BPF-nin inkişafı paket filtrasiyası üçün ön ucun inkişafı ilə paralel olaraq həyata keçirildi - tanınmış bir yardım proqramı tcpdump. Və bu, bir çox əməliyyat sistemlərində mövcud olan klassik BPF-dən istifadənin ən qədim və ən məşhur nümunəsi olduğundan, texnologiyanı onunla öyrənəcəyik və başlayacağıq.

(Mən bu məqalədəki bütün nümunələri Linux-da işlətdim 5.6.0-rc6. Bəzi əmrlərin çıxışı oxunaqlılıq üçün redaktə edilmişdir.)

Misal: IPv6 Paketlərinə baxmaq

Təsəvvür edin ki, biz interfeysdə bütün IPv6 paketlərinə baxmaq istəyirik eth0. Bunun üçün proqramı işlədə bilərik tcpdump sadə filtrlə ip6:

$ sudo tcpdump -i eth0 ip6

Bu halda, tcpdump filtri tərtib edəcək ip6 BPF arxitekturasının bayt koduna daxil edin və nüvəyə göndərin (bölmədə təfərrüatlara baxın tcpdump: yükləyin). Yüklənmiş filtr interfeysdən keçən hər bir paket üçün işlədiləcək eth0. Filtr qeyri-null dəyəri qaytarırsa n, sonra qədər n paketin baytları istifadəçi sahəsinə kopyalanacaq və biz onu çıxışda görəcəyik tcpdump.

Kiçiklər üçün BPF, sıfır hissə: klassik BPF

Belə çıxır ki, biz ləpəyə hansı bayt kodunun göndərildiyini asanlıqla öyrənə bilərik tcpdump köməyi ilə tcpdump, seçimi ilə işlədirsək -d:

$ sudo tcpdump -i eth0 -d ip6
(000) ldh      [12]
(001) jeq      #0x86dd          jt 2    jf 3
(002) ret      #262144
(003) ret      #0

Sıfır sətirdə əmri yerinə yetiririk ldh [12], bu "reyestrə yükləyin" deməkdir A 16" ünvanında yerləşən yarım söz (12 bit) və yeganə sual budur ki, biz hansı yaddaşa müraciət edirik? Cavab budur ki x başlayır (x+1)-təhlil olunan şəbəkə paketinin baytı. Paketləri Ethernet interfeysindən oxuyuruq eth0və bu vasitəpaketin belə görünməsi (sadəlik üçün paketdə VLAN teqlərinin olmadığını güman edirik):

       6              6          2
|Destination MAC|Source MAC|Ether Type|...|

Beləliklə, əmri yerinə yetirdikdən sonra ldh [12] reyestrdə A sahə olacaq Ether Type — bu Ethernet çərçivəsində ötürülən paket növü. 1-ci sətirdə reyestrin məzmununu müqayisə edirik A (paket növü) c 0x86ddvə bu və var bizi maraqlandıran IPv6 növü. 1-ci sətirdə müqayisə əmrinə əlavə olaraq daha iki sütun var - jt 2 и jf 3 - uğurlu müqayisə zamanı keçiləcək etiketlər (A == 0x86dd) və uğursuz oldu. Beləliklə, uğurlu halda (IPv6) 2-ci sətirə, uğursuz halda isə 3-cü sətirə keçirik. 3-cü sətirdə proqram 0 kodu ilə (paketi kopyalamayın), 2-ci sətirdə proqramdan çıxır. 262144 kodu ilə çıxır (mənə maksimum 256 kilobaytlıq paketi kopyalayın).

Daha mürəkkəb nümunə: təyinat portuna görə TCP paketlərinə baxın

Gəlin görək filtr bütün TCP paketlərini təyinat portu 666 ilə kopyalayır. IPv4 işi daha sadə olduğundan biz IPv6 məsələsini nəzərdən keçirəcəyik. Bu nümunəni öyrəndikdən sonra IPv6 filtrini məşq kimi özünüz öyrənə bilərsiniz (ip6 and tcp dst port 666) və ümumi hal üçün filtr (tcp dst port 666). Beləliklə, bizi maraqlandıran filtr belə görünür:

$ sudo tcpdump -i eth0 -d ip and tcp dst port 666
(000) ldh      [12]
(001) jeq      #0x800           jt 2    jf 10
(002) ldb      [23]
(003) jeq      #0x6             jt 4    jf 10
(004) ldh      [20]
(005) jset     #0x1fff          jt 10   jf 6
(006) ldxb     4*([14]&0xf)
(007) ldh      [x + 16]
(008) jeq      #0x29a           jt 9    jf 10
(009) ret      #262144
(010) ret      #0

0 və 1 sətirlərinin nə etdiyini artıq bilirik. 2-ci sətirdə biz artıq bunun IPv4 paketi olduğunu təsdiqləmişik (Eter Növü = 0x800) və reyestrə yükləyin A Paketin 24-cü baytı. Paketimiz belə görünür

       14            8      1     1
|ethernet header|ip fields|ttl|protocol|...|

bu o deməkdir ki, biz reyestrə yükləyirik A IP başlığının Protokol sahəsi, məntiqlidir, çünki biz yalnız TCP paketlərini kopyalamaq istəyirik. Protokolu ilə müqayisə edirik 0x6 (IPPROTO_TCP) 3-cü sətirdə.

4-cü və 5-ci sətirlərdə 20-ci ünvanda və komanda ilə yarım sözləri yükləyirik jset üçdən birinin təyin edilib-edilmədiyini yoxlayın bayraqlar - buraxılmış maskada jset üst üç bit təmizləndi. Üç bitdən ikisi paketin parçalanmış IP paketinin bir hissəsi olub-olmadığını, əgər belədirsə, sonuncu fraqment olub olmadığını bildirir. Üçüncü bit qorunur və sıfır olmalıdır. Biz tam olmayan və ya qırıq paketləri yoxlamaq istəmirik, ona görə də hər üç biti yoxlayırıq.

6-cı sətir bu siyahıda ən maraqlıdır. İfadə ldxb 4*([14]&0xf) reyestrə yüklədiyimizi bildirir X paketin on beşinci baytının dörd ən az əhəmiyyətli biti 4-ə vurulur. On beşinci baytın dörd ən az əhəmiyyətli biti sahədir. İnternet Başlıq Uzunluğu Başlığın uzunluğunu sözlərlə saxlayan IPv4 başlığı, ona görə də sonra 4-ə vurmaq lazımdır.Maraqlıdır ki, ifadə 4*([14]&0xf) yalnız bu formada və yalnız qeydiyyat üçün istifadə edilə bilən xüsusi ünvanlama sxemi üçün təyinatdır X, yəni. biz də deyə bilmərik ldb 4*([14]&0xf) nə də ldxb 5*([14]&0xf) (biz yalnız fərqli ofset təyin edə bilərik, məsələn, ldxb 4*([16]&0xf)). Aydındır ki, bu ünvanlama sxemi BPF-ə məhz qəbul etmək üçün əlavə edilib X (indeks halda) IPv4 başlıq uzunluğu.

Beləliklə, 7-ci sətirdə biz yarım sözü, ünvana yükləməyə çalışırıq (X+16). 14 baytın Ethernet başlığı tərəfindən tutulduğunu xatırlayaraq və X IPv4 başlığının uzunluğunu ehtiva edir, biz bunu başa düşürük A TCP təyinat portu yüklənir:

       14           X           2             2
|ethernet header|ip header|source port|destination port|

Nəhayət, 8-ci sətirdə təyinat portunu axtardığımız dəyərlə müqayisə edirik və 9 və ya 10-cu sətirlərdə nəticəni qaytarırıq - paketi kopyalamaq və ya etməmək.

tcpdump: yükləyin

Əvvəlki nümunələrdə, paket filtrasiyası üçün BPF bayt kodunu kernelə necə yükləməyimiz barədə ətraflı məlumat vermədik. Ümumiyyətlə, tcpdump bir çox sistemlərə və filtrlərlə işləmək üçün daşınmışdır tcpdump kitabxanadan istifadə edir libpcap. Bir sözlə, bir interfeysə bir filtr qoymaq üçün libpcap, aşağıdakıları etməlisiniz:

Funksiyanın necə olduğunu görmək üçün pcap_setfilter Linux-da tətbiq olunur, istifadə edirik strace (bəzi sətirlər silinib):

$ sudo strace -f -e trace=%network tcpdump -p -i eth0 ip
socket(AF_PACKET, SOCK_RAW, 768)        = 3
bind(3, {sa_family=AF_PACKET, sll_protocol=htons(ETH_P_ALL), sll_ifindex=if_nametoindex("eth0"), sll_hatype=ARPHRD_NETROM, sll_pkttype=PACKET_HOST, sll_halen=0}, 20) = 0
setsockopt(3, SOL_SOCKET, SO_ATTACH_FILTER, {len=4, filter=0xb00bb00bb00b}, 16) = 0
...

İlk iki çıxış sətirində biz yaradırıq xam rozetka bütün Ethernet çərçivələrini oxumaq və onu interfeysə bağlamaq üçün eth0. etibarən ilk nümunəmiz filtr olduğunu bilirik ip dörd BPF təlimatından ibarət olacaq və üçüncü sətirdə seçimdən istifadə edərək necə olduğunu görürük SO_ATTACH_FILTER sistem çağırışı setsockopt biz 4 uzunluqlu filtri yükləyirik və əlavə edirik. Bu bizim filtrimizdir.

Qeyd etmək lazımdır ki, klassik BPF-də filtrin yüklənməsi və qoşulması həmişə atom əməliyyatı kimi baş verir, BPF-nin yeni versiyasında isə proqramın yüklənməsi və hadisə generatoruna bağlanması vaxtında ayrılır.

gizli həqiqət

Çıxışın bir az daha tam versiyası belə görünür:

$ sudo strace -f -e trace=%network tcpdump -p -i eth0 ip
socket(AF_PACKET, SOCK_RAW, 768)        = 3
bind(3, {sa_family=AF_PACKET, sll_protocol=htons(ETH_P_ALL), sll_ifindex=if_nametoindex("eth0"), sll_hatype=ARPHRD_NETROM, sll_pkttype=PACKET_HOST, sll_halen=0}, 20) = 0
setsockopt(3, SOL_SOCKET, SO_ATTACH_FILTER, {len=1, filter=0xbeefbeefbeef}, 16) = 0
recvfrom(3, 0x7ffcad394257, 1, MSG_TRUNC, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
setsockopt(3, SOL_SOCKET, SO_ATTACH_FILTER, {len=4, filter=0xb00bb00bb00b}, 16) = 0
...

Yuxarıda qeyd edildiyi kimi, filtrimizi 5-ci sətirdəki rozetkaya yükləyirik və birləşdiririk, bəs 3 və 4-cü sətirlərdə nə baş verir? Belə çıxır ki, bu libpcap bizə qayğı göstərir - filtrimizin çıxışına onu qane etməyən paketlər daxil olmasın, kitabxana bağlayır dummy filter ret #0 (bütün paketləri buraxın), rozetkanı bloklanmayan rejimə qoyur və keçmiş filtrlərdən qalan paketləri çıxarmağa çalışır.

Ümumilikdə, klassik BPF-dən istifadə edərək Linux-da paketləri süzgəcdən keçirmək üçün belə bir struktur şəklində filtrə sahib olmalısınız. struct sock_fprog və açıq rozetka, bundan sonra filtr sistem çağırışından istifadə edərək yuvaya qoşula bilər setsockopt.

Maraqlıdır ki, filtri yalnız xam deyil, istənilən rozetkaya taxmaq olar. Burada misal bütün daxil olan UDP dataqramlarının ilk iki baytından başqa hamısını silən proqram. (Məqaləni qarışdırmamaq üçün koda şərhlər əlavə etdim.)

İstifadə haqqında ətraflı setsockopt filtrləri birləşdirmək üçün baxın rozetka (7), lakin öz forma filtrlərinizi yazmaq haqqında struct sock_fprog köməyi olmadan tcpdump bölməsində danışacağıq BPF-ni öz əllərimizlə proqramlaşdırırıq.

Klassik BPF və XXI əsr

BPF 1997-ci ildə Linux-a daxil edilmişdir və uzun müddətdir ki, iş başında olmuşdur. libpcap çox dəyişiklik olmadan (Linux-a xas dəyişikliklər, əlbəttə ki, idi, lakin qlobal mənzərəni dəyişmədilər). BPF-nin inkişaf edəcəyinə dair ilk ciddi əlamətlər 2011-ci ildə Erik Dumazetin təklif etdiyi zaman ortaya çıxdı. yamaq, BPF bayt kodunu yerli dilə çevirmək üçün tərcüməçi - Just In Time Compiler-i nüvəyə əlavə edən x86_64 kod.

JIT kompilyatoru dəyişikliklər zəncirində birinci oldu: 2012-ci ildə ortaya çıxdı üçün filtrlər yazmaq bacarığı seccomp, BPF istifadə edərək, 2013-cü ilin yanvar ayında oldu əlavə etdi modul xt_bpfüçün qaydaları yazmağa imkan verir iptables BPF istifadə edərək, 2013-cü ilin oktyabr ayında oldu əlavə etdi həm də moduldur cls_bpf, BPF-dən istifadə edərək trafik təsnifatını yazmağa imkan verir.

Bütün bu misallara tezliklə daha ətraflı baxacağıq, lakin əvvəlcə BPF üçün ixtiyari proqramları necə yazmağı və tərtib etməyi öyrənmək bizim üçün faydalı olacaq, çünki kitabxananın təqdim etdiyi imkanlar. libpcap məhdud (sadə misal: filtr tərəfindən yaradılmışdır libpcap yalnız iki dəyər qaytara bilər - 0 və ya 0x40000) və ya ümumiyyətlə, seccomp vəziyyətində olduğu kimi, tətbiq edilmir.

BPF-ni öz əllərimizlə proqramlaşdırırıq

BPF təlimatlarının ikili formatı ilə tanış olaq, çox sadədir:

   16    8    8     32
| code | jt | jf |  k  |

Hər bir təlimat 64 bit tutur, burada ilk 16 bit təlimat kodudur, sonra iki səkkiz bitlik abzas var, jt и jf, və arqument üçün 32 bit K, məqsədi komandadan komandaya dəyişir. Məsələn, əmr ret, proqramı sonlandıran kod var 6, və qaytarılan dəyər sabitdən götürülür K. C-də tək BPF təlimatı struktur kimi təmsil olunur

struct sock_filter {
        __u16   code;
        __u8    jt;
        __u8    jf;
        __u32   k;
}

və bütün proqram - struktur şəklində

struct sock_fprog {
        unsigned short len;
        struct sock_filter *filter;
}

Beləliklə, biz artıq proqramlar yaza bilərik (məsələn, biz təlimat kodlarını bilirik [1]). Filtr belə görünəcək ip6 haqqında ilk nümunəmiz:

struct sock_filter code[] = {
        { 0x28, 0, 0, 0x0000000c },
        { 0x15, 0, 1, 0x000086dd },
        { 0x06, 0, 0, 0x00040000 },
        { 0x06, 0, 0, 0x00000000 },
};
struct sock_fprog prog = {
        .len = ARRAY_SIZE(code),
        .filter = code,
};

proqram prog biz qanuni olaraq zəngdə istifadə edə bilərik

setsockopt(sk, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog))

Proqramları maşın kodları şəklində yazmaq çox rahat deyil, lakin bəzən buna ehtiyac yaranır (məsələn, sazlama, vahid testləri yaratmaq, Habré-də məqalələr yazmaq və s.). Rahatlıq üçün fayl <linux/filter.h> köməkçi makrolar müəyyən edilmişdir - yuxarıdakı kimi eyni nümunə kimi yenidən yazıla bilər

struct sock_filter code[] = {
        BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 12),
        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ETH_P_IPV6, 0, 1),
        BPF_STMT(BPF_RET|BPF_K, 0x00040000),
        BPF_STMT(BPF_RET|BPF_K, 0),
}

Ancaq bu seçim də çox əlverişli deyil. Beləliklə, Linux nüvəsi proqramçıları da əsaslandırdılar və buna görə də kataloqda tools/bpf kernels, klassik BPF ilə işləmək üçün assembler və sazlayıcı tapa bilərsiniz.

Assembly dili debug çıxışına çox oxşardır tcpdump, lakin əlavə olaraq simvolik etiketləri təyin edə bilərik. Məsələn, burada TCP/IPv4 istisna olmaqla bütün paketləri buraxan bir proqram var:

$ cat /tmp/tcp-over-ipv4.bpf
ldh [12]
jne #0x800, drop
ldb [23]
jneq #6, drop
ret #-1
drop: ret #0

Varsayılan olaraq, assembler formatda kod yaradır <количество инструкций>,<code1> <jt1> <jf1> <k1>,..., TCP ilə nümunəmiz üçün belə olacaq

$ tools/bpf/bpf_asm /tmp/tcp-over-ipv4.bpf
6,40 0 0 12,21 0 3 2048,48 0 0 23,21 0 1 6,6 0 0 4294967295,6 0 0 0,

C proqramçılarının rahatlığı üçün başqa çıxış formatından istifadə etmək olar:

$ tools/bpf/bpf_asm -c /tmp/tcp-over-ipv4.bpf
{ 0x28,  0,  0, 0x0000000c },
{ 0x15,  0,  3, 0x00000800 },
{ 0x30,  0,  0, 0x00000017 },
{ 0x15,  0,  1, 0x00000006 },
{ 0x06,  0,  0, 0xffffffff },
{ 0x06,  0,  0, 0000000000 },

Bu mətn tip strukturu tərifinə kopyalana bilər struct sock_filter, bu bölmənin əvvəlində etdiyimiz kimi.

Linux uzantıları və netsniff-ng

Standart BPF təlimatlarına əlavə olaraq, Linux və tools/bpf/bpf_asm dəstək və xüsusi dəst. Əsasən, ifadələr strukturun sahələrinə daxil olmaq üçün istifadə olunur. struct sk_buff, nüvədəki şəbəkə paketini təsvir edən. Bununla belə, köməkçi təlimatların başqa növləri var, məsələn ldw cpu reyestrinə yükləyin A kernel funksiyasının icrasının nəticəsi raw_smp_processor_id(). (BPF-nin yeni versiyasında bu qeyri-standart genişləndirmələr proqramlar üçün yaddaşa, strukturlara daxil olmaq və hadisələr yaratmaq üçün nüvə köməkçiləri dəstini təmin etmək üçün genişləndirilib.) Burada yalnız paket başlıqlarını kopyaladığımız filtrin maraqlı nümunəsi var. genişləndirmədən istifadə edərək istifadəçi sahəsinə poff, faydalı yük ofset:

ld poff
ret a

BPF uzantıları istifadə edilə bilməz tcpdump, lakin bu, kommunal paketlə tanış olmaq üçün yaxşı bir səbəbdir netsniff-ng, digər şeylərlə yanaşı, inkişaf etmiş bir proqramı ehtiva edir netsniff-ng, BPF-dən istifadə edərək filtrləmə ilə yanaşı, həm də səmərəli trafik generatorunu ehtiva edir və daha təkmildir tools/bpf/bpf_asm, bir BPF montajçısı çağırdı bpfc. Paketdə kifayət qədər ətraflı sənədlər var, məqalənin sonundakı bağlantılara da baxın.

seccomp

Beləliklə, biz artıq ixtiyari mürəkkəbliyin BPF proqramlarını necə yazacağımızı bilirik və yeni nümunələrə baxmağa hazırıq, bunlardan birincisi BPF filtrlərindən istifadə edərək verilmiş bir sistem üçün mövcud olan sistem çağırış arqumentləri dəstini və dəstini idarə etməyə imkan verən seccomp texnologiyasıdır. proses və onun törəmələri.

Seccomp-un ilk versiyası 2005-ci ildə nüvəyə əlavə edildi və o qədər də populyar deyildi, çünki o, yalnız bir variant təmin etdi - proses üçün mövcud olan sistem zəngləri dəstini aşağıdakılarla məhdudlaşdırmaq: read, write, exit и sigreturn, və qaydaları pozan proses ilə öldürüldü SIGKILL. Bununla belə, 2012-ci ildə BPF filtrlərindən istifadə etmək imkanı seccomp-a əlavə edildi ki, bu da icazə verilən sistem zənglərinin dəstini müəyyən etməyə və hətta onların arqumentlərini yoxlamağa imkan verir. (Maraqlıdır ki, Chrome bu funksiyanın ilk istifadəçilərindən biri olub və KRSI mexanizmi hazırda BPF-nin yeni versiyası əsasında və Linux Təhlükəsizlik Modullarının fərdiləşdirilməsinə imkan verən Chrome-da insanlar tərəfindən hazırlanır.) Əlavə sənədlərə keçidlər ola bilər. məqalənin sonunda tapıldı.

Qeyd edək ki, Habré-də artıq seccomp-dan istifadə haqqında məqalələr var, bəlkə kimsə aşağıdakı alt bölmələri oxumadan əvvəl (və ya əvəzinə) onları oxumaq istəyəcək. Məqalədə Konteynerlər və təhlükəsizlik: seccomp seccomp-dan istifadə nümunələri, həm 2007-ci il versiyası, həm də BPF-dən istifadə edən versiya (filtrlər libseccomp istifadə edərək yaradılır), seccomp-un Docker ilə əlaqəsi haqqında danışır və həmçinin bir çox faydalı bağlantılar təqdim edir. Məqalədə Demonları systemd ilə təcrid edin və ya "bunun üçün sizə Docker lazım deyil!" sistemli demonlar üçün sistem zənglərinin qara və ya ağ siyahıya alınması haqqında xüsusi olaraq danışır.

Sonra filtrləri necə yazmaq və yükləmək lazım olduğunu görəcəyik seccomp çılpaq C-də və kitabxananın köməyi ilə libseccomp və hər bir variantın müsbət və mənfi tərəfləri nələrdir və nəhayət, seccomp-un proqram tərəfindən necə istifadə edildiyinə baxaq. strace.

Seccomp üçün filtrlərin yazılması və yüklənməsi

Biz artıq BPF proqramlarını necə yazacağımızı bilirik, ona görə də əvvəlcə seccomp API-yə baxaq. Siz filtri proses səviyyəsində təyin edə bilərsiniz, halbuki bütün uşaq proseslər məhdudiyyətləri miras alacaq. Bu, sistem çağırışı ilə edilir. seccomp(2):

seccomp(SECCOMP_SET_MODE_FILTER, flags, &filter)

hara &filter artıq bizə tanış olan strukturun göstəricisidir struct sock_fprog, yəni. BPF proqramı.

Seccomp proqramları ilə soket proqramları arasında fərq nədir? Kontekst ötürülür. Sockets vəziyyətində bizə paketi ehtiva edən yaddaş sahəsi verildi və seccomp vəziyyətində bizə belə bir quruluş verilir.

struct seccomp_data {
    int   nr;
    __u32 arch;
    __u64 instruction_pointer;
    __u64 args[6];
};

Burada nr başlanacaq sistem çağırışının nömrəsidir, arch - cari memarlıq (aşağıda daha ətraflı), args - altıya qədər sistem çağırışı arqumentləri və instruction_pointer bu sistem çağırışını edən istifadəçi sahəsi təlimatının göstəricisidir. Beləliklə, məsələn, sistemin zəng nömrəsini reyestrə yükləmək A deməliyik

ldw [0]

Seccomp proqramları üçün başqa xüsusiyyətlər də var, məsələn, kontekstə giriş yalnız 32-bit uyğunlaşdırma ilə mümkündür və siz yarım söz və ya bayt yükləyə bilməzsiniz - filtri yükləməyə çalışarkən ldh [0] sistem çağırışı seccomp geri dönəcək EINVAL. Yüklənmiş filtrlər funksiya tərəfindən yoxlanılır seccomp_check_filter() ləpələr. (Maraqlıdır ki, seccomp funksiyasını əlavə edən orijinal öhdəlik bu funksiyaya təlimatdan istifadə etmək icazəsini əlavə etməyi unutdu. mod (bölmənin qalan hissəsi) və indi onu əlavə etdikdən sonra seccomp BPF proqramları üçün mövcud deyil qırılacaq ABI.)

Əsasən, biz artıq seccomp proqramlarını yazmaq və oxumaq üçün hər şeyi bilirik. Adətən proqramın məntiqi sistem zənglərinin ağ və ya qara siyahısı kimi təşkil edilir, məsələn, proqram

ld [0]
jeq #304, bad
jeq #176, bad
jeq #239, bad
jeq #279, bad
good: ret #0x7fff0000 /* SECCOMP_RET_ALLOW */
bad: ret #0

304, 176, 239, 279 nömrəli dörd sistem çağırışının qara siyahısını yoxlayır. Bu sistem zəngləri hansılardır? Proqramın hansı arxitektura üçün yazıldığını bilmədiyimiz üçün dəqiq deyə bilmərik. Buna görə də, seccomp müəllifləri təklif bütün proqramları arxitektura yoxlaması ilə başlayın (cari arxitektura kontekstdə sahə kimi göstərilir arch quruluşu struct seccomp_data). Arxitektura yoxlanıldıqda, nümunənin başlanğıcı belə görünür:

ld [4]
jne #0xc000003e, bad_arch ; SCMP_ARCH_X86_64

və sonra sistem zəng nömrələrimiz müəyyən dəyərlər alacaqdı.

Seccomp üçün filtrlərin yazılması və yüklənməsi libseccomp

Filtrlərin yerli kodda və ya BPF assemblerində yazılması nəticəyə tam nəzarət etməyə imkan verir, lakin eyni zamanda, bəzən portativ və/və ya oxuna bilən kodun olması üstünlük təşkil edir. Kitabxana bu işdə bizə kömək edəcək. libseccomp, qara və ya ağ filtrlərin yazılması üçün standart interfeys təmin edir.

Məsələn, istifadəçinin seçdiyi ikili faylı işlədən proqram yazaq, əvvəllər sistem zənglərinin qara siyahısını yaradaraq. yuxarıdakı məqalə (proqram daha çox oxunaqlı olmaq üçün sadələşdirilmişdir, tam versiyanı tapmaq olar burada):

#include <seccomp.h>
#include <unistd.h>
#include <err.h>

static int sys_numbers[] = {
        __NR_mount,
        __NR_umount2,
       // ... еще 40 системных вызовов ...
        __NR_vmsplice,
        __NR_perf_event_open,
};

int main(int argc, char **argv)
{
        scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);

        for (size_t i = 0; i < sizeof(sys_numbers)/sizeof(sys_numbers[0]); i++)
                seccomp_rule_add(ctx, SCMP_ACT_TRAP, sys_numbers[i], 0);

        seccomp_load(ctx);

        execvp(argv[1], &argv[1]);
        err(1, "execlp: %s", argv[1]);
}

Əvvəlcə bir massiv təyin edirik sys_numbers bloklanacaq 40+ sistem zəng nömrəsi. Sonra konteksti işə salırıq ctx və kitabxanaya nəyə icazə vermək istədiyimizi deyin (SCMP_ACT_ALLOW) defolt olaraq bütün sistem zəngləri (qara siyahıların yaradılması daha asandır). Sonra, bir-bir qara siyahıya alınmış bütün sistem zənglərini əlavə edirik. Siyahıdan sistem çağırışına cavab olaraq biz xahiş edirik SCMP_ACT_TRAP, bu halda seccomp prosesə siqnal göndərəcək SIGSYS hansı xüsusi sistem çağırışının qaydaları pozduğunun təsviri ilə. Nəhayət, proqramı ilə nüvəyə yükləyirik seccomp_load, proqramı tərtib edəcək və sistem çağırışından istifadə edərək prosesə əlavə edəcək seccomp(2).

Uğurlu tərtib etmək üçün proqram kitabxana ilə əlaqələndirilməlidir libseccomp, məsələn:

cc -std=c17 -Wall -Wextra -c -o seccomp_lib.o seccomp_lib.c
cc -o seccomp_lib seccomp_lib.o -lseccomp

Uğurlu işə salınma nümunəsi:

$ ./seccomp_lib echo ok
ok

Bloklanmış sistem çağırışına misal:

$ sudo ./seccomp_lib mount -t bpf bpf /tmp
Bad system call

Biz istifadə edirik straceətraflı məlumat üçün:

$ sudo strace -e seccomp ./seccomp_lib mount -t bpf bpf /tmp
seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=50, filter=0x55d8e78428e0}) = 0
--- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0xboobdeadbeef, si_syscall=__NR_mount, si_arch=AUDIT_ARCH_X86_64} ---
+++ killed by SIGSYS (core dumped) +++
Bad system call

hardan bilə bilərik ki, proqram qadağan edilmiş sistem çağırışının istifadəsi səbəbindən dayandırılıb mount(2).

Ümumilikdə kitabxanadan istifadə edərək filtr yazdıq libseccomp, qeyri-trivial kodu dörd sətirə yerləşdirmək. Yuxarıdakı misalda, çox sayda sistem çağırışı varsa, icra müddəti nəzərəçarpacaq dərəcədə azala bilər, çünki yoxlama yalnız müqayisələrin siyahısıdır. Optimallaşdırma üçün bu yaxınlarda libseccomp var idi yamaq daxildir, filtr atribut dəstəyini əlavə edir SCMP_FLTATR_CTL_OPTIMIZE. Bu atributu 2-yə təyin etsəniz, filtr ikili axtarış proqramına çevriləcəkdir.

İkili axtarış filtrlərinin necə işlədiyini görmək istəyirsinizsə, nəzər yetirin sadə skript, sistem zəng nömrələrini yığmaqla BPF assemblerində belə proqramlar yaradır, məsələn:

$ echo 1 3 6 8 13 | ./generate_bin_search_bpf.py
ld [0]
jeq #6, bad
jgt #6, check8
jeq #1, bad
jeq #3, bad
ret #0x7fff0000
check8:
jeq #8, bad
jeq #13, bad
ret #0x7fff0000
bad: ret #0

Daha sürətli bir şey yazıla bilməz, çünki BPF proqramları girinti keçidlərini həyata keçirə bilməz (məsələn, biz edə bilmərik jmp A və ya jmp [label+X]) və buna görə də bütün keçidlər statikdir.

seccomp və strace

Faydalılığı hamı bilir strace - Linux-da proseslərin davranışının öyrənilməsində əvəzsiz vasitədir. Bununla belə, çoxları haqqında eşitmişdir performans problemləri bu yardım proqramından istifadə edərkən. Fakt budur ki strace köməyi ilə həyata keçirilir ptrace(2), və bu mexanizmdə biz hansı sistem çağırışları toplusunda prosesi dayandırmağımız lazım olduğunu müəyyən edə bilmirik, məsələn, əmrlər.

$ time strace du /usr/share/ >/dev/null 2>&1

real    0m3.081s
user    0m0.531s
sys     0m2.073s

и

$ time strace -e open du /usr/share/ >/dev/null 2>&1

real    0m2.404s
user    0m0.193s
sys     0m1.800s

təxminən eyni vaxtda işləyirik, baxmayaraq ki, ikinci halda biz yalnız bir sistem çağırışını izləmək istəyirik.

Yeni seçim --seccomp-bpf-a əlavə edildi strace 5.3 versiyası, prosesi dəfələrlə sürətləndirməyə imkan verir və bir sistem çağırışının izi altında işə salınma vaxtı artıq normal işə salınma vaxtı ilə müqayisə edilə bilər:

$ time strace --seccomp-bpf -e open du /usr/share/ >/dev/null 2>&1

real    0m0.148s
user    0m0.017s
sys     0m0.131s

$ time du /usr/share/ >/dev/null 2>&1

real    0m0.140s
user    0m0.024s
sys     0m0.116s

(Əlbəttə, burada kiçik bir aldatma var ki, biz bu əmrin əsas olmayan sistem çağırışını izləyirik. Əgər izləyirdiksə, məsələn, newfsstat, Sonra strace olmadığı qədər yavaşlayardı --seccomp-bpf.)

Bu seçim necə işləyir? Onsuz strace bir prosesə qoşulur və onunla başlayır PTRACE_SYSCALL. Nəzarət olunan proses (hər hansı) sistem çağırışını işə saldıqda, idarəetmə ötürülür strace, sistem çağırışının arqumentlərinə baxır və onu çağırır PTRACE_SYSCALL. Müəyyən müddətdən sonra proses sistem çağırışını tamamlayır və o, çıxdıqda idarəetmə yenidən ötürülür. straceqayıdış dəyərlərinə baxır və prosesə başlayır PTRACE_SYSCALL, və s.

Kiçiklər üçün BPF, sıfır hissə: klassik BPF

Lakin seccomp ilə bu proses bizim istədiyimiz kimi sadələşdirilə bilər. Yəni, yalnız sistem çağırışına baxmaq istəsək X, onda biz bunun üçün bir BPF filtri yaza bilərik X dəyər qaytarır SECCOMP_RET_TRACE, və bizim üçün maraqlı olmayan zənglər üçün - SECCOMP_RET_ALLOW:

ld [0]
jneq #X, ignore
trace: ret #0x7ff00000
ignore: ret #0x7fff0000

Bu vəziyyətdə strace kimi prosesə ilkin olaraq başlayır PTRACE_CONT, sistem çağırışı deyilsə, hər bir sistem çağırışı üçün filtrimiz işlənir X, sonra proses davam edir, lakin əgər X, sonra seccomp nəzarəti ötürəcək stracekimi arqumentlərə baxacaq və prosesi başlayacaq PTRACE_SYSCALL (çünki seccomp-un sistem çağırışından çıxdıqda proqramı işə salmaq imkanı yoxdur). Sistem zəngi qayıtdıqda, strace ilə prosesi yenidən başladın PTRACE_CONT və seccomp-dan yeni mesajlar gözləyəcək.

Kiçiklər üçün BPF, sıfır hissə: klassik BPF

Seçimdən istifadə edərkən --seccomp-bpf iki məhdudiyyət var. Birincisi, artıq mövcud prosesə əlavə etmək mümkün olmayacaq (seçim -p proqramları strace) çünki seccomp tərəfindən dəstəklənmir. İkincisi, heç bir imkan yoxdur heç bir uşaq proseslərə baxın, çünki seccomp filtrləri bütün uşaq proseslər tərəfindən miras alınır, bunu aradan qaldırmaq üçün heç bir yol yoxdur.

Necə bir az daha ətraflı strace ilə işləmək seccomp -dən öyrənmək olar son hesabat. Bizim üçün ən maraqlı fakt odur ki, seccomp ilə təmsil olunan klassik BPF hələ də tətbiqlər tapır.

xt_bpf

Şəbəkələr dünyasına qayıdaq.

Ümumi məlumat: uzun müddət əvvəl, 2007-ci ildə əsas idi əlavə etdi modul xt_u32 netfiltr üçün. Daha qədim trafik təsnifatı ilə bənzətmə ilə yazılmışdır cls_u32 və aşağıdakı sadə əməliyyatlardan istifadə edərək iptables üçün ixtiyari ikili qaydaları yazmağa imkan verdi: paketdən 32 bit yükləyin və onlarla hesab əməliyyatları toplusunu yerinə yetirin. Misal üçün,

sudo iptables -A INPUT -m u32 --u32 "6&0xFF=1" -j LOG --log-prefix "seen-by-xt_u32"

32-cı abzasdan başlayaraq IP başlığının 6 bitini yükləyir və onlara maska ​​tətbiq edir 0xFF (aşağı baytı götürün). Bu sahə protocol IP başlığı və biz onu 1 (ICMP) ilə müqayisə edirik. Siz bir qaydada bir çox çeki birləşdirə bilərsiniz və siz bəyanatı da icra edə bilərsiniz @ — X baytı sağa köçürün. Məsələn, qayda

iptables -m u32 --u32 "6&0xFF=0x6 && 0>>22&0x3C@4=0x29"

TCP Sıra nömrəsinin bərabər olmadığını yoxlayır 0x29. Bu cür qaydaları əl ilə yazmağın o qədər də rahat olmadığı artıq aydın olduğu üçün daha ətraflı məlumat verməyəcəyəm. Məqalədə BPF - unudulmuş bayt kodu, üçün qaydaların istifadəsi və yaradılması nümunələri ilə bir neçə bağlantı var xt_u32. Bu məqalənin sonundakı bağlantılara da baxın.

2013-cü ildən modul əvəzinə modul xt_u32 BPF əsaslı moduldan istifadə edə bilərsiniz xt_bpf. Buraya qədər oxuyan hər kəs bunun necə işlədiyini artıq aydınlaşdırmalıdır: BPF bayt kodunu iptables qaydaları kimi işlədin. Yeni bir qayda yarada bilərsiniz, məsələn, bu kimi:

iptables -A INPUT -m bpf --bytecode <байткод> -j LOG

burada <байткод> assembler çıxış formatında koddur bpf_asm standart olaraq, məsələn,

$ cat /tmp/test.bpf
ldb [9]
jneq #17, ignore
ret #1
ignore: ret #0

$ bpf_asm /tmp/test.bpf
4,48 0 0 9,21 0 1 17,6 0 0 1,6 0 0 0,

# iptables -A INPUT -m bpf --bytecode "$(bpf_asm /tmp/test.bpf)" -j LOG

Bu nümunədə biz bütün UDP paketlərini filtrləyirik. Modulda BPF proqramı üçün kontekst xt_bpf, əlbəttə ki, paketin məlumatlarına, iptables vəziyyətində, IPv4 başlığının başlanğıcına işarə edir. BPF proqramından dəyəri qaytarın booleanHara false paketin uyğun gəlmədiyini bildirir.

Modul olduğu aydındır xt_bpf yuxarıdakı nümunədən daha mürəkkəb filtrləri dəstəkləyir. Cloudfare-dən real nümunələrə baxaq. Son vaxtlara qədər onlar moduldan istifadə edirdilər xt_bpf DDoS hücumlarından qorunmaq üçün. Məqalədə BPF Alətləri ilə tanış olun onlar BPF filtrlərini necə (və nə üçün) yaratdıqlarını və belə filtrləri yaratmaq üçün bir sıra kommunal xidmətlərə keçidləri dərc etdiklərini izah edirlər. Məsələn, yardım proqramından istifadə etməklə bpfgen bir ad üçün DNS sorğusuna uyğun gələn BPF proqramı yarada bilərsiniz habr.com:

$ ./bpfgen --assembly dns -- habr.com
ldx 4*([0]&0xf)
ld #20
add x
tax

lb_0:
    ld [x + 0]
    jneq #0x04686162, lb_1
    ld [x + 4]
    jneq #0x7203636f, lb_1
    ldh [x + 8]
    jneq #0x6d00, lb_1
    ret #65535

lb_1:
    ret #0

Proqramda ilk öncə registrə yükləyirik X xəttin əvvəlinin ünvanı x04habrx03comx00 UDP datagram daxilində və sonra sorğunu yoxlayın: 0x04686162 <-> "x04hab" və s.

Bir az sonra Cloudfare p0f -> BPF kompilyator kodunu nəşr etdi. Məqalədə p0f BPF kompilyatorunu təqdim edirik p0f-nin nə olduğu və p0f imzalarını BPF-ə necə çevirmək barədə danışırlar:

$ ./bpfgen p0f -- 4:64:0:0:*,0::ack+:0
39,0 0 0 0,48 0 0 8,37 35 0 64,37 0 34 29,48 0 0 0,
84 0 0 15,21 0 31 5,48 0 0 9,21 0 29 6,40 0 0 6,
...

Hazırda Cloudfare artıq istifadə etmir xt_bpf, onlar XDP-yə keçdikləri üçün - BPF-nin yeni versiyasından istifadə seçimlərindən biri, aşağıya baxın. L4Drop: XDP DDoS azaldılması.

cls_bpf

Klassik BPF-nin nüvədə istifadəsinin son nümunəsi təsnifatçıdır cls_bpf Linux-da trafikə nəzarət alt sistemi üçün, 2013-cü ilin sonunda Linux-a əlavə edildi və konseptual olaraq qədimi əvəz etdi. cls_u32.

Ancaq indi işi təsvir etməyəcəyik cls_bpf, klassik BPF haqqında bilik nöqteyi-nəzərindən bu bizə heç nə verməyəcək - biz artıq bütün funksionallıqla tanış olmuşuq. Bundan əlavə, Genişləndirilmiş BPF haqqında danışan sonrakı məqalələrdə bu təsnifatçı ilə bir dəfədən çox görüşəcəyik.

Klassik BPF-dən istifadə haqqında danışmamağın başqa bir səbəbi c cls_bpf Genişləndirilmiş BPF ilə müqayisədə bu halda tətbiq dairəsi kəskin şəkildə daralır: klassik proqramlar paketlərin məzmununu dəyişə bilməz və zənglər arasında vəziyyəti saxlaya bilməz.

Beləliklə, klassik BPF ilə vidalaşmaq və gələcəyə baxmaq vaxtıdır.

Klassik BPF ilə vida

32-cı illərin əvvəllərində inkişaf etdirilən BPF texnologiyasının əsrin dörddə birini necə uğurla yaşadığına və sona qədər yeni tətbiqlər tapmasına baxdıq. Bununla belə, klassik BPF-nin inkişafı üçün təkan rolunu oynayan stack maşınlarından RISC-ə keçid kimi, 64-ci illərdə XNUMX bitlik maşınlardan XNUMX bitlik maşınlara keçid baş verdi və klassik BPF köhnəldi. Bundan əlavə, klassik BPF-nin imkanları çox məhduddur və köhnəlmiş arxitekturaya əlavə olaraq - BPF proqramlarına edilən zənglər arasında vəziyyəti saxlamaq imkanımız yoxdur, istifadəçi ilə birbaşa qarşılıqlı əlaqə imkanı yoxdur, yoxdur. məhdud sayda struktur sahələrini oxumaq istisna olmaqla, nüvə ilə qarşılıqlı əlaqə imkanı sk_buff və ən sadə köməkçi funksiyaları işə salmaqla siz paketlərin məzmununu dəyişdirə və onları yönləndirə bilməzsiniz.

Əslində, hazırda Linux-da klassik BPF-dən yalnız API interfeysi qalır və nüvənin daxilində bütün klassik proqramlar, istər soket filtrləri, istərsə də seccomp filtrləri avtomatik olaraq yeni formata, Genişləndirilmiş BPF-ə tərcümə olunur. (Bunun necə baş verdiyini növbəti məqalədə dəqiq izah edəcəyik.)

Yeni arxitekturaya keçid 2013-cü ildə, Aleksey Starovoitovun BPF-nin təkmilləşdirilməsi sxemini təklif etdiyi zaman başladı. 2014-cü ildə müvafiq yamalar görünməyə başladı əsasda. Başa düşdüyümə görə, əvvəlcə 64 bitlik maşınlarda daha səmərəli işləmək üçün arxitektura və JIT-kompilyatoru optimallaşdırmaq planlaşdırılırdı, lakin bunun əvəzinə bu optimallaşdırmalar Linux inkişafında yeni bir fəslin başlanğıcını qeyd etdi.

Bu seriyanın sonrakı məqalələri əvvəlcə daxili BPF, sonra genişləndirilmiş BPF və indi sadəcə BPF kimi tanınan yeni texnologiyanın arxitekturasını və tətbiqlərini əhatə edəcəkdir.

References

  1. Steven McCanne və Van Jacobson, "BSD Paket Filtri: İstifadəçi səviyyəsində Paket Tutması üçün Yeni Arxitektura", https://www.tcpdump.org/papers/bpf-usenix93.pdf
  2. Steven McCanne, "libpcap: Paket Tutma üçün Memarlıq və Optimallaşdırma Metodologiyası", https://sharkfestus.wireshark.org/sharkfest.11/presentations/McCanne-Sharkfest'11_Keynote_Address.pdf
  3. tcpdump, libpcap: https://www.tcpdump.org/
  4. IPtable U32 Maç Təlimatı.
  5. BPF - unudulmuş bayt kodu: https://blog.cloudflare.com/bpf-the-forgotten-bytecode/
  6. BPF Alətini təqdim edirik: https://blog.cloudflare.com/introducing-the-bpf-tools/
  7. bpf_cls: http://man7.org/linux/man-pages/man8/tc-bpf.8.html
  8. İkinci baxış: https://lwn.net/Articles/656307/
  9. https://github.com/torvalds/linux/blob/master/Documentation/userspace-api/seccomp_filter.rst
  10. habr: Konteynerlər və təhlükəsizlik: seccomp
  11. habr: Demonları systemd ilə təcrid edin və ya "bunun üçün Dockerə ehtiyacınız yoxdur!"
  12. Paul Chaignon, "strace --seccomp-bpf: kapotun altına baxış", https://fosdem.org/2020/schedule/event/debugging_strace_bpf/
  13. netsniff-ng: http://netsniff-ng.org/

Mənbə: www.habr.com

Добавить комментарий