BPF ji bo piçûkan, beşa sifir: BPF klasîk

Parzûnên Berkeley Packet (BPF) teknolojiyek kernel Linux-ê ye ku ev çend sal in li ser rûpelên pêşîn ên weşanên teknolojiya bi zimanê Englishngilîzî ye. Konferans bi raporên li ser karanîn û pêşkeftina BPF dagirtî ne. David Miller, parêzgerê binepergala torê Linux, axaftina xwe li Linux Plumbers 2018 bang dike "Ev axaftin ne li ser XDP ye" (XDP ji bo BPF yek dozek karanîna ye). Brendan Gregg axaftinên bi sernavê dide Linux BPF Superpowers. Toke Høiland-Jørgensen dikeneku kernel niha mîkrokernel e. Thomas Graf vê fikrê bi pêş dixe BPF ji bo kernelê javascript e.

Hîn jî li ser Habré danasîna sîstematîkî ya BPF-ê tune, û ji ber vê yekê di rêze gotaran de ez ê hewl bidim ku li ser dîroka teknolojiyê biaxivim, mîmarî û amûrên pêşkeftinê diyar bikim, û qadên serîlêdan û pratîka karanîna BPF-ê destnîşan bikim. Ev gotara, sifir, di rêzê de, dîrok û mîmariya BPF ya klasîk vedibêje, û di heman demê de nehêniyên prensîbên xebitandina wê jî eşkere dike. tcpdump, seccomp, strace, û hê bêtir.

Pêşveçûna BPF ji hêla civaka torê ya Linux ve tê kontrol kirin, serîlêdanên sereke yên heyî yên BPF bi torê ve girêdayî ne û ji ber vê yekê, bi destûr @eucariot, Min navê rêzefîlmê "BPF ji bo biçûkan" kir, ji bo rêzefîlma mezin "Torên ji bo biçûkan".

Kursek kurt di dîroka BPF de (c)

Teknolojiya nûjen a BPF guhertoyek pêşkeftî û berfireh a teknolojiya kevn a bi heman navî ye, ku naha jê re BPF klasîk tê gotin da ku ji tevliheviyê dûr nekevin. Karûbarek naskirî li ser bingeha BPF-ya klasîk hate afirandin tcpdump, mekanîzma seccomp, û her weha modulên kêmtir naskirî xt_bpf bo iptables û dabeşker cls_bpf. Di Linux-a nûjen de, bernameyên BPF yên klasîk bixweber di forma nû de têne wergerandin, lêbelê, ji hêla bikarhêner ve, API li cîhê xwe maye û karanîna nû ji bo BPF-ya klasîk, wekî ku em ê di vê gotarê de bibînin, hîn jî têne dîtin. Ji ber vê yekê, û her weha ji ber ku li dû dîroka pêşkeftina BPF-ya klasîk a li Linux-ê, dê zelaltir bibe ka ew çawa û çima di forma xweya nûjen de derketiye, min biryar da ku bi gotarek li ser BPF-ya klasîk dest pê bikim.

Di dawiya salên heştêyî yên sedsala borî de, endezyarên ji Laboratoriya navdar Lawrence Berkeley eleqedar bûn bi pirsa ka meriv çawa pakêtên torê bi rêkûpêk li ser hardware ku di dawiya salên heştêyî yên sedsala borî de nûjen bû fîltre dike. Fikra bingehîn a fîlterkirinê, ku bi eslê xwe di teknolojiya CSPF (CMU / Parzûna Pakêtê ya Stanford) de hatî bicîh kirin, ew bû ku pakêtên nepêwist bi zûtirîn dem fîltre bike, yanî. di cîhê kernelê de, ji ber ku ev ji kopîkirina daneyên nepêwist di cîhê bikarhêner de dûr dikeve. Ji bo peydakirina ewlehiya dema xebitandinê ji bo xebitandina koda bikarhêner li cîhê kernelê, makîneyek virtual sandboxed hate bikar anîn.

Lêbelê, makîneyên virtual yên ji bo fîlterên heyî hatine sêwirandin ku li ser makîneyên bingeha stack-ê bixebitin û li ser makîneyên nû yên RISC bi qasî ku bi bandor nemeşiyan. Wekî encamek, bi hewildanên endezyarên Berkeley Labs, teknolojiyek nû ya BPF (Parzeyên Packet Berkeley) hate pêşve xistin, mîmariya makîneya virtual ya ku li ser bingeha pêvajoya Motorola 6502 hatî sêwirandin - kargêriya hilberên weha navdar ên wekî Apple II an NES. Makîneya virtual ya nû li gorî çareseriyên heyî bi dehan carî performansa fîlterê zêde kir.

mîmariya makîneya BPF

Em ê bi şêweyekî xebatkar, bi analîzkirina mînakan bi mîmariyê re bên naskirin. Lêbelê, ji bo destpêkê, em bibêjin ku makîneyê du qeydên 32-bit hebûn ku ji bikarhêner re bigihîjin, komkerek. A û qeyda index X, 64 byte bîra (16 peyv), ji bo nivîsandinê û xwendina paşîn, û pergalek piçûk a fermanan ji bo xebata bi van tiştan re heye. Di bernameyan de rêwerzên bazdanê yên ji bo bicihanîna îfadeyên şertî jî hebûn, lê ji bo garantîkirina qedandina bernameyê di wextê xwe de, bazdan tenê dikaribû pêş de were çêkirin, ango, bi taybetî, çêkirina lûleyan qedexe bû.

Plana giştî ya ji bo destpêkirina makîneyê wiha ye. Bikarhêner bernameyek ji bo mîmariya BPF diafirîne û bikar tîne hin mekanîzmaya kernelê (wekî gazîkirina pergalê), bernameyê bar dike û pê ve girêdide ji hinekan re ji jeneratorê bûyerê re di kernelê de (mînak, bûyerek hatina pakêta din a li ser qerta torê ye). Dema ku bûyerek diqewime, kernel bernameyê dimeşîne (mînak, di wergerekê de), û bîra makîneyê bi ji hinekan re herêma bîra kernel (mînak, daneyên pakêtek hatî).

Tiştên li jor dê bes be ku em dest bi lênihêrîna mînakan bikin: li gorî hewcedariyê em ê bi pergal û formata fermanê re bibin nas. Ger hûn dixwazin tavilê pergala fermanê ya makîneyek virtual bixwînin û li ser hemî kapasîteyên wê fêr bibin, wê hingê hûn dikarin gotara orjînal bixwînin. Parzûna pakêtê ya BSD û / an nîvê pêşîn ê pelê Belgekirin/networking/filter.txt ji belgeya kernel. Wekî din, hûn dikarin pêşkêşiyê bixwînin libpcap: Rêbazek Mîmarî û Optimîzasyonê ji bo Girtina Pakêtan, ku tê de McCanne, yek ji nivîskarên BPF, behsa dîroka afirandinê dike libpcap.

Em naha diçin ku hemî mînakên girîng ên karanîna BPF-ya klasîk li ser Linux-ê bifikirin: tcpdump (libpcap), seccomp, xt_bpf, cls_bpf.

tcpdump

Pêşveçûna BPF bi pêşkeftina pêşiyê ji bo parzûnkirina pakêtê - karûbarek naskirî re paralel hate kirin. tcpdump. Û, ji ber ku ev mînaka herî kevn û navdar a karanîna BPF-ya klasîk e, ku li ser gelek pergalên xebitandinê peyda dibe, em ê bi wê re dest bi lêkolîna xwe ya teknolojiyê bikin.

(Min di vê gotarê de hemî nimûneyên li ser Linux-ê bi rê ve kir 5.6.0-rc6. Derketina hin fermanan ji bo xwendina çêtir hate guherandin.)

Mînak: çavdêriya pakêtên IPv6

Ka em bifikirin ku em dixwazin li hemî pakêtên IPv6-ê li ser navgînekê binihêrin eth0. Ji bo vê yekê em dikarin bernameyê bimeşînin tcpdump bi parzûneke sade ip6:

$ sudo tcpdump -i eth0 ip6

Bi vî awayî tcpdump parzûnê berhev dike ip6 nav bytecode mîmariya BPF-ê de bişînin û wê ji kernelê re bişînin (hûragahiyan di beşê de bibînin Tcpdump: barkirin). Parzûna barkirî dê ji bo her pakêtek ku di navberê re derbas dibe were xebitandin eth0. Ger parzûn nirxek ne-sifir vedigerîne n, paşê heta n bytes pakêtê dê li cîhê bikarhêner were kopî kirin û em ê wê di encam de bibînin tcpdump.

BPF ji bo piçûkan, beşa sifir: BPF klasîk

Derket holê ku em dikarin bi hêsanî fêr bibin ka kîjan bytecode ji kernelê re hatiye şandin tcpdump bi alîkariya tcpdump, heke em bi vebijarkê dimeşînin -d:

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

Li ser xeta sifir em fermanê dimeşînin ldh [12], ku tê wateya "barkirina nav qeydê A nîv peyv (16 bit) ku li navnîşana 12" ye û tenê pirs ev e ku em behsa kîjan bîranînê dikin? Bersiv ew e ku li x dest pê dike (x+1)th byte ya pakêta torê ya analîzkirî. Em pakêtan ji navrûya Ethernet dixwînin eth0, û ev wateyaku pakêt bi vî rengî xuya dike (ji bo sadebûnê, em texmîn dikin ku di pakêtê de etîketên VLAN tune):

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

Ji ber vê yekê piştî pêkanîna fermanê ldh [12] di qeydê de A dê meydanek hebe Ether Type - celebê pakêtê ku di vê çarçoweya Ethernetê de hatî şandin. Di rêza 1-ê de em naveroka qeydê didin ber hev A (cureyê pakêtê) c 0x86dd, û ev û heye Tîpa ku em jê re eleqedar dibin IPv6 e. Li ser xeta 1, ji bilî fermana berhevdanê, du stûnên din jî hene - jt 2 и jf 3 - nîşaneyên ku hûn hewce ne ku biçin heke berhevok serketî be (A == 0x86dd) û neserkeftî. Ji ber vê yekê, di rewşek serketî de (IPv6) em diçin rêza 2, û di rewşek neserkeftî de - di rêza 3 de. Di rêza 3 de bername bi koda 0 diqede (pakêtê kopî neke), di xeta 2 de bername bi kodê diqede. 262144 (pakêta herî zêde 256 kilobytes ji min re kopî bike).

Nimûneyek tevlihevtir: em li pakêtên TCP-ê li gorî porta mebestê dinêrin

Ka em bibînin ka parzûnek çawa xuya dike ku hemî pakêtên TCP-ê bi porta mebest 666 kopî dike. Em ê doza IPv4-ê binirxînin, ji ber ku doza IPv6 hêsantir e. Piştî xwendina vê nimûneyê, hûn dikarin parzûna IPv6 bi xwe wekî werzîşê bikolin (ip6 and tcp dst port 666) û parzûnek ji bo doza giştî (tcp dst port 666). Ji ber vê yekê, parzûna ku em jê re eleqedar dibin bi vî rengî xuya dike:

$ 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

Em jixwe dizanin ku xetên 0 û 1 çi dikin. Li ser xeta 2 me berê kontrol kiriye ku ev pakêtek IPv4 e (Tîpa Ether = 0x800) û wê di qeydê de bar bikin A 24. byte ya pakêtê. Pakêta me dişibe

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

ku tê vê wateyê ku em di qeydê de bar dikin A qada Protokolê ya sernavê IP-ê, ku mentiqî ye, ji ber ku em dixwazin tenê pakêtên TCP-ê kopî bikin. Em bi Protokolê re berhev dikin 0x6 (IPPROTO_TCP) li ser xeta 3.

Li ser rêzikên 4 û 5 em nîvpeyvên ku li navnîşana 20-an têne barkirin û fermanê bikar tînin jset kontrol bikin ka yek ji sêyan hatiye danîn flags - girtina maskê derketiye jset sê bitên herî girîng têne paqij kirin. Du ji sê bit ji me re vedibêjin ka pakêt beşek pakêtek IP-ya perçebûyî ye, û heke wusa be, gelo ew perçeya paşîn e. Bitka sêyemîn parastî ye û divê sifir be. Em naxwazin pakêtên ne temam an jî şikestî kontrol bikin, ji ber vê yekê em her sê bit kontrol dikin.

Rêza 6 di vê navnîşê de ya herî balkêş e. Îfade ldxb 4*([14]&0xf) tê vê wateyê ku em di qeydê de bar dikin X çar bitên herî kêm girîng ên pazdehan baytê pakêtê bi 4-ê zêde kirin. Dirêjahiya Sernivîsa Înternetê Sernavê IPv4, ku dirêjahiya sernavê di peyvan de hilîne, ji ber vê yekê hûn hewce ne ku bi 4-an zêde bikin. Balkêş e, vegotin 4*([14]&0xf) ji bo nexşeyek navnîşanek taybetî ye ku tenê di vê formê de û tenê ji bo qeydkirinê tête bikar anîn X, yanî em jî nikarin bibêjin ldb 4*([14]&0xf) ne ldxb 5*([14]&0xf) (em tenê dikarin jihevdengek cûda diyar bikin, wek nimûne, ldxb 4*([16]&0xf)). Eşkere ye ku ev pilana navnîşan bi tam ji bo wergirtinê li BPF hate zêdekirin X (qeyda index) Dirêjahiya serê IPv4.

Ji ber vê yekê li ser xeta 7 em hewl didin ku nîv peyvê li ser bar bikin (X+16). Bînin bîra xwe ku 14 bytes ji hêla sernavê Ethernet ve têne dagir kirin, û X dirêjahiya sernavê IPv4 dihewîne, em wê yekê fam dikin A Porta mebesta TCP-ê tê barkirin:

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

Di dawiyê de, li ser rêza 8-ê em porta mebestê bi nirxa xwestinê re didin ber hev û li ser rêzên 9 an 10-an em encamê vedigerînin - ka pakêtê kopî bikin an na.

Tcpdump: barkirin

Di mînakên berê de, me bi taybetî bi hûrgulî li ser ka meriv çawa bytekoda BPF-ê ji bo fîlterkirina pakêtê bar dike di kernelê de nesekinî. Bi gelemperî, tcpdump ji gelek pergalan re û ji bo xebata bi parzûnan ve hatî şandin tcpdump pirtûkxaneyê bi kar tîne libpcap. Bi kurtasî, ji bo ku parzûnek li ser navgînek bikar bînin cîh bikin libpcap, hûn hewce ne ku jêrîn bikin:

Ji bo dîtina fonksiyonê çawa ye pcap_setfilter li Linux-ê hatî bicîh kirin, em bikar tînin strace (hin rêz hatin rakirin):

$ 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
...

Li ser du xetên pêşîn ên hilberînê em diafirînin soketa xav da ku hemî çarçoveyên Ethernet bixwînin û wê bi navbeynê ve girêdin eth0. Ji mînaka me ya yekem em dizanin ku parzûn ip dê ji çar rêwerzên BPF pêk were, û li ser xeta sêyemîn em dibînin ka vebijarkê çawa bikar tînin SO_ATTACH_FILTER banga sîstema setsockopt em parzûnek dirêjahiya 4 bar dikin û girêdidin. Ev parzûna me ye.

Hêjayî gotinê ye ku di BPF-ya klasîk de, barkirin û girêdana parzûnek her gav wekî operasyonek atomî pêk tê, û di guhertoya nû ya BPF de, barkirina bernameyê û girêdana wê bi jeneratorê bûyerê re di wextê de têne veqetandin.

Rastiya Veşartî

Guhertoyek hinekî bêkêmasî ya derketinê wiha xuya dike:

$ 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
...

Wekî ku li jor hatî behs kirin, em parzûna xwe bi soketa li ser xeta 5 bar dikin û girêdidin, lê di xetên 3 û 4 de çi diqewime? Derket holê ku ev libpcap li me miqate dibe - da ku di derana parzûna me de pakêtên ku wê têr nakin, pirtûkxane negire girêdide Parzûna dummy ret #0 (hemî pakêtan davêjin), soketê vediguhezîne moda ne-astengkirinê û hewl dide ku hemî pakêtên ku dikarin ji parzûnên berê bimînin dakêşîne.

Bi tevahî, ji bo fîlterkirina pakêtên li ser Linux-ê bi karanîna BPF-ya klasîk, hûn hewce ne ku parzûnek di forma avahiyek mîna struct sock_fprog û soketek vekirî, piştî ku parzûn dikare bi karanîna bangek pergalê bi soketê ve were girêdan setsockopt.

Balkêş e, parzûn dikare bi her soketê ve were girêdan, ne tenê xav. Vir nimûne bernameyek ku hemî lê du baytên pêşîn ji hemî datagramên UDP yên hatinî qut dike. (Min şîrove di kodê de zêde kir da ku gotarê tevlihev nekim.)

Zêdetir hûrgulî li ser karanîna setsockopt ji bo girêdana parzûnan, binêre soket (7), lê di derbarê nivîsandina fîlterên xwe yên mîna struct sock_fprog bê alîkarî tcpdump em ê di beşê de biaxivin Bernamekirina BPF bi destên xwe.

Klasîk BPF û sedsala 21-an

BPF di sala 1997-an de di Linux-ê de bû û ji bo demek dirêj ve wekî kargêrek ma libpcap bêyî ti guhertinên taybetî (Guhertinên taybetî yên Linux, bê guman, Ev bû, lê wan wêneya gerdûnî neguherand). Yekem nîşanên ciddî yên ku BPF dê pêşve bibe di sala 2011 de hat, dema ku Eric Dumazet pêşniyar kir. pîvaz, ku Just In Time Compiler li kernelê zêde dike - wergerek ji bo veguherandina BPF bytecode bo xwemalî x86_64 kod.

Berhevkarê JIT di zincîra guhertinan de yekem bû: di 2012 de xuya kirin şiyana nivîsandina fîlteran ji bo seccomp, bikaranîna BPF, di Çile 2013 de hebû zêde kirin module xt_bpf, ku destûrê dide te ku hûn ji bo qaîdeyan binivîsin iptables bi alîkariya BPF, û di Cotmeha 2013 de bû zêde kirin jî modulek cls_bpf, ku dihêle hûn bi karanîna BPF-ê dabeşkerên trafîkê binivîsin.

Em ê di demek nêzîk de bi hûrgulî li van hemî mînakan binêrin, lê pêşî ew ê ji me re kêrhatî be ku em fêr bibin ka meriv çawa ji bo BPF bernameyên keyfî dinivîse û berhev dike, ji ber ku kapasîteyên ku ji hêla pirtûkxaneyê ve têne peyda kirin. libpcap sînorkirî (mînakek hêsan: Parzûnek hatî çêkirin libpcap dikare tenê du nirxan vegerîne - 0 an 0x40000) an bi gelemperî, wekî di doza seccomp de, ne pêkan in.

Bernamekirina BPF bi destên xwe

Werin em bi formata binary ya rêwerzên BPF-ê nas bikin, ew pir hêsan e:

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

Her fermanek 64 bit digire, ku tê de 16 bitên yekem koda rêwerzê ne, dûv re du heşt-bit hene, jt и jf, û 32 bit ji bo argumana K, mebesta wê ji fermanê heta fermanê diguhere. Ji bo nimûne, ferman ret, ku bernameyê biqedîne kod heye 6, û nirxa vegerê ji domdar tê girtin K. Di C de, yek fermanek BPF wekî avahiyek tê destnîşan kirin

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

û hemû bername di forma avahiyekê de ye

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

Bi vî rengî, em dikarin berê bernameyan binivîsin (mînak, em kodên rêwerzan ji wan dizanin [1]). Parzûn dê bi vî rengî xuya bike ip6 ji mînaka me ya yekem:

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,
};

Bername prog em dikarin bi qanûnî di bangekê de bikar bînin

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

Nivîsandina bernameyên di forma kodên makîneyê de ne pir rehet e, lê carinan ew hewce ye (mînakî, ji bo xeletkirinê, çêkirina ceribandinên yekîneyê, nivîsandina gotaran li ser Habré, hwd.). Ji bo rehetiyê, di pelê de <linux/filter.h> makroyên alîkar têne diyar kirin - heman mînaka li jor dikare wekî ji nû ve were nivîsandin

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),
}

Lêbelê, ev vebijark ne pir hêsan e. Ya ku bernameçêkerên kernel Linux-ê sedem kirin ev e, û ji ber vê yekê di pelrêçê de ye tools/bpf kernelên ku hûn dikarin ji bo xebata bi BPF-ya klasîk re sazker û debuggerek bibînin.

Zimanê meclîsê pir dişibe derketina debugê tcpdump, lê ji bilî vê em dikarin etîketên sembolîk diyar bikin. Mînakî, li vir bernameyek heye ku ji bilî TCP/IPv4 hemî pakêtan davêje:

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

Bi xwerû, komker kodê di formatê de çêdike <количество инструкций>,<code1> <jt1> <jf1> <k1>,..., ji bo nimûneya me bi TCP re ew ê bibe

$ 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,

Ji bo rehetiya bernameçêkerên C, formatek derketinê ya cûda dikare were bikar anîn:

$ 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 },

Ev metn dikare di nav pênaseya strukturên celebê de were kopî kirin struct sock_filter, wekî me di destpêka vê beşê de kir.

Linux û pêvekên netsniff-ng

Ji bilî BPF standard, Linux û tools/bpf/bpf_asm piştgirî û set non-standard. Di bingeh de, rêwerzan ji bo gihîştina zeviyên avahiyek têne bikar anîn struct sk_buff, ku di kernelê de pakêtek torê diyar dike. Lêbelê, celebên din ên rêwerzên alîkar jî hene, mînakî ldw cpu dê di qeydê de bar bike A encama xebitandina fonksiyonek kernelê raw_smp_processor_id(). (Di guhertoya nû ya BPF de, ev dirêjkirinên ne-standard hatine dirêj kirin da ku bernameyan bi komek alîkarên kernelê peyda bikin ji bo gihîştina bîranîn, avahî, û çêkirina bûyeran.) Li vir mînakek balkêş a parzûnek heye ku em tê de tenê fîlterê kopî dikin. sernavên pakêtê bi karanîna pêvekê ve di cîhê bikarhêner de bişînin poff, guheztina bargiraniyê:

ld poff
ret a

Berfirehkirinên BPF nayên bikar anîn tcpdump, lê ev sedemek baş e ku hûn bi pakêta karûbar re nas bikin netsniff-ng, ku di nav tiştên din de, bernameyek pêşkeftî heye netsniff-ng, ku ji bilî fîlterkirina bi karanîna BPF-ê, di heman demê de jeneratorek trafîkê ya bi bandor jî heye, û ji pêşkeftîtir e. tools/bpf/bpf_asm, a assembler BPF gazî bpfc. Di pakêtê de belgeyên pir berfireh hene, di dawiya gotarê de lînkên jî bibînin.

seccomp

Ji ber vê yekê, em jixwe dizanin ku meriv bernameyên BPF yên tevliheviya kêfî çawa dinivîse û amade ne ku li mînakên nû binihêrin, ya yekem teknolojiya seccomp e, ku dihêle, bi karanîna fîlterên BPF, komek û komek argumanên bangewaziya pergalê ku li berdest in birêve bibin. pêvajoyek diyarkirî û dûndana wê.

Guhertoya yekem a seccomp di sala 2005-an de li kernelê hate zêdekirin û ne pir populer bû, ji ber ku ew tenê vebijarkek yekta peyda kir - ku komek bangên pergalê yên ku ji pêvajoyek re peyda dibin bi van jêrîn sînordar bike: read, write, exit и sigreturn, û pêvajoya ku qaîdeyên binpêkirin bi kar hat kuştin SIGKILL. Lêbelê, di sala 2012-an de, seccomp şiyana karanîna fîlterên BPF zêde kir, ku dihêle hûn komek bangên pergalê yên destûr diyar bikin û tewra li ser argumanên wan jî kontrol bikin. (Balkêş e, Chrome yek ji bikarhênerên yekem ê vê fonksiyonê bû, û mirovên Chrome niha mekanîzmayek KRSI-yê li ser bingeha guhertoyek nû ya BPF-yê pêşdixin û destûr didin ku modulên Ewlekariya Linux-ê xweş bikin.) Girêdanên belgeyên din dikarin li dawiyê werin dîtin. ya gotara.

Bala xwe bidinê ku berê gotarên li ser hubê di derbarê karanîna seccomp de hebûn, dibe ku kesek bixwaze wan berî (an li şûna) xwendina beşên jêrîn bixwîne. Di gotara Konteynirên û ewlekarî: seccomp Nimûneyên karanîna seccomp, hem guhertoya 2007-an û hem jî guhertoya ku BPF bikar tîne (fîlter bi karanîna libseccomp têne hilberandin) peyda dike, li ser pêwendiya seccomp bi Docker re diaxive, û di heman demê de gelek girêdanên kêrhatî jî peyda dike. Di gotara Veqetandina şeytan bi pergalê an "ji bo vê yekê hûn ne hewceyî Docker in!" Bi taybetî, ew vedihewîne ka meriv çawa lîsteyên reş an lîsteyên spî yên bangên pergalê ji bo şeytanên ku systemd dixebitin zêde dike.

Piştre em ê bibînin ka meriv çawa fîlteran dinivîse û bar dike seccomp di C tazî de û pirtûkxaneyê bikar tîne libseccomp û pro û nebaşiyên her vebijarkê çi ne, û di dawiyê de, em bibînin ka seccomp çawa ji hêla bernameyê ve tê bikar anîn strace.

Nivîsandin û barkirina fîlteran ji bo seccomp

Em jixwe dizanin ku meriv bernameyên BPF-ê çawa dinivîse, ji ber vê yekê em pêşî li navrûya bernamesaziya seccomp binêrin. Hûn dikarin di asta pêvajoyê de parzûnek saz bikin, û hemî pêvajoyên zarokan dê sînoran mîras bigirin. Ev bi karanîna bangek pergalê tête kirin seccomp(2):

seccomp(SECCOMP_SET_MODE_FILTER, flags, &filter)

ko &filter - ev nîşanek e ku avahiyek jixwe ji me re naskirî ye struct sock_fprog, yanî bernameya BPF.

Bernameyên seccomp ji bernameyên ji bo soketan çawa cûda dibin? Têkiliya veguhestin. Di mijara soketan de, ji me re herêmek bîranînê ku pakêt tê de ye, û di doza seccomp de ji me re avahiyek mîna

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

Ev e nr hejmara banga pergalê ye ku were destpêkirin, arch - mîmariya heyî (li ser vê yekê li jêr bêtir), args - heta şeş argumanên banga sîstema, û instruction_pointer nîşanek e ku rêwerza cîhê bikarhênerê ku banga pergalê kiriye. Bi vî rengî, ji bo nimûne, ji bo barkirina hejmara telefona pergalê di qeydê de A divê em bibêjin

ldw [0]

Taybetmendiyên din ji bo bernameyên seccomp hene, mînakî, konteks tenê bi hevrêziya 32-bit dikare were gihîştin û hûn nikanin nîv peyv an bitekê bar bikin - dema ku hûn hewl bidin ku parzûnek bar bikin. ldh [0] banga sîstema seccomp dê vegere EINVAL. Fonksiyon fîlterên barkirî kontrol dike seccomp_check_filter() kernels. (Tiştê xweş ev e, di commita orîjînal de ku fonksiyona seccomp lê zêde kir, wan ji bîr kir ku destûr zêde bikin ku talîmatê li vê fonksiyonê bikar bînin. mod (bermayiya dabeşkirinê) û ji ber zêdekirina wê naha ji bo bernameyên seccomp BPF ne berdest e dê bişkênin ABI.)

Di bingeh de, em jixwe her tiştî dizanin ku bernameyên seccomp binivîsin û bixwînin. Bi gelemperî mantiqa bernameyê wekî navnîşek spî an reş a bangên pergalê, mînakî bernameyê, tê rêz kirin

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

navnîşek reş a çar bangên pergalê yên bi hejmarên 304, 176, 239, 279 kontrol dike. Ev bangên pergalê çi ne? Em nikarin teqez bibêjin, ji ber ku em nizanin bername ji bo kîjan mîmarî hatiye nivîsandin. Ji ber vê yekê, nivîskarên seccomp pêşniyar dikin hemî bernameyan bi kontrolek mîmariyê dest pê bikin (mîmariya heyî di çarçovê de wekî zeviyek tê destnîşan kirin arch avahî struct seccomp_data). Digel ku mîmariya hatî kontrol kirin, destpêka nimûneyê dê weha xuya bike:

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

û dûv re hejmarên banga pergala me dê hin nirxan bistînin.

Em ji bo karanîna seccomp fîlteran dinivîsin û bar dikin libseccomp

Nivîsandina fîlteran di koda xwemalî de an di civîna BPF de dihêle hûn li ser encamê kontrolek tam hebe, lê di heman demê de, carinan çêtir e ku kodek portable û/an xwendin hebe. Pirtûkxane dê di vê yekê de alîkariya me bike libseccomp, ku ji bo nivîsandina parzûnên reş an spî navgînek standard peyda dike.

Werin, wek nimûne, bernameyek binivîsin ku pelek binary ya ku bikarhêner hilbijartî dimeşîne, ku berê navnîşek reş a bangên pergalê ji saz kiriye. gotara jorîn (Bername ji bo xwendina mezintir hêsan bûye, guhertoya tevahî dikare were dîtin vir):

#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]);
}

Pêşî em rêzek diyar dikin sys_numbers ji 40+ hejmarên banga pergalê ji bo astengkirinê. Dûv re, çarçoveyê dest pê bikin ctx û ji pirtûkxaneyê re bêje ka em çi dixwazin destûrê bidin (SCMP_ACT_ALLOW) hemî bangên pergalê ji hêla xwerû ve (avakirina navnîşên reş hêsantir e). Dûv re, yek bi yek, em hemî bangên pergalê ji navnîşa reş lê zêde dikin. Di bersiva bangek pergalê ya ji navnîşê de, em daxwaz dikin SCMP_ACT_TRAP, di vê rewşê de seccomp dê ji pêvajoyê re sînyalek bişîne SIGSYS bi danasîna kîjan bangê sîstemê rêgez binpê kirin. Di dawiyê de, em bi karanîna bernameyê di kernelê de bar dikin seccomp_load, ku dê bernameyê berhev bike û bi karanîna bangek pergalê ve bi pêvajoyê ve girêbide seccomp(2).

Ji bo berhevkirina serketî, divê bername bi pirtûkxaneyê ve were girêdan libseccomp, wek nimûne:

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

Mînaka destpêkek serketî:

$ ./seccomp_lib echo ok
ok

Mînak bangek pergala astengkirî:

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

Em bikar tînin straceji bo hûragahiyan:

$ 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

em çawa dikarin zanibin ku bername ji ber karanîna bangek pergalê ya neqanûnî hate qedandin mount(2).

Ji ber vê yekê, me bi karanîna pirtûkxaneyê parzûnek nivîsand libseccomp, koda ne-tawan di çar rêzan de bicîh dike. Di mînaka li jor de, heke hejmareke mezin ji bangên pergalê hebin, dema darvekirinê dikare bi baldarî were kêm kirin, ji ber ku kontrol tenê navnîşek berhevokê ye. Ji bo optimîzasyonê, libseccomp vê dawiyê hebû patch tê de, ku piştgirî ji bo taybetmendiya parzûnê zêde dike SCMP_FLTATR_CTL_OPTIMIZE. Danîna vê taybetmendiyê li ser 2-ê dê parzûnê veguherîne bernameyek lêgerîna binaryê.

Heke hûn dixwazin bibînin ka fîlterên lêgerînê yên binary çawa dixebitin, lê binêrin script sade, ku bernameyên weha di berhevoka BPF-ê de bi jimartina hejmarên banga pergalê diafirîne, mînakî:

$ 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

Ne mimkun e ku meriv tiştek bi girîngî zûtir binivîsîne, ji ber ku bernameyên BPF nikaribin şûştinên dakêşanê pêk bînin (em nikarin bikin, mînakî, jmp A an jmp [label+X]) û ji ber vê yekê hemî veguherîn statîk in.

seccomp û strace

Her kes bikêrhatî dizane strace ji bo lêkolîna tevgera pêvajoyên li Linux-ê amûrek domdar e. Lêbelê, pir kesan jî li ser bihîstiye pirsgirêkên performansê dema ku vê amûreyê bikar tînin. Rastî ev e strace bi kar anîne ptrace(2), û di vê mekanîzmayê de em nekarin diyar bikin ku em di kîjan komê bangên pergalê de hewce ne ku pêvajoyê rawestînin, ango, mînakî, fermanan

$ 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

hema hema di heman demê de têne pêvajoyê kirin, her çend di rewşa duyemîn de em dixwazin tenê yek bangek pergalê bişopînin.

Vebijêrkek nû --seccomp-bpf, lê zêde kirin strace guhertoya 5.3, dihêle hûn pêvajoyê gelek caran bilezînin û dema destpêkirinê di bin şopa yek bangek pergalê de jixwe bi dema destpêkek birêkûpêk re tê berhev kirin:

$ 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

(Li vir, bê guman, xapandinek hûrgelek heye ku em banga pergala sereke ya vê fermanê naşopînin. Ger me şopanda, wek nimûne, newfsstat, paşê strace dê bi qasî bêhêz fren bike --seccomp-bpf.)

Ev vebijêrk çawa dixebite? Bêyî wê strace bi pêvajoyê ve girêdayî ye û dest bi karanîna wê dike PTRACE_SYSCALL. Dema ku pêvajoyek birêvebirî bangek (her) pergalê derdixe, kontrol tê veguheztin strace, ku li argumanên gazîkirina pergalê dinêre û pê re dimeşîne PTRACE_SYSCALL. Piştî demekê, pêvajo banga pergalê temam dike û dema ku jê derdikeve, kontrol dîsa tê veguheztin strace, ku li nirxên vegerê dinêre û pêvajoyê bi kar tîne dest pê dike PTRACE_SYSCALL, wate ya vê çîye.

BPF ji bo piçûkan, beşa sifir: BPF klasîk

Lêbelê, bi seccomp re, ev pêvajo tam wekî ku em dixwazin were xweşbîn kirin. Ango, heke em bixwazin tenê li banga pergalê binêrin X, wê hingê em dikarin parzûnek BPF ku ji bo wê binivîsin X nirxek vedigerîne SECCOMP_RET_TRACE, û ji bo bangên ku ji me re ne eleqedar in - SECCOMP_RET_ALLOW:

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

Di vê rewşê de strace di destpêkê de pêvajoyê wekî dest pê dike PTRACE_CONT, Parzûna me ji bo her bangek pergalê tête pêvajo kirin, heke banga pergalê nebe X, wê demê pêvajo berdewam dike, lê heke ev X, paşê seccomp dê kontrolê veguherîne straceku dê li argumanan binêre û pêvajoyek mîna dest pê bike PTRACE_SYSCALL (ji ber ku seccomp di derketina ji bangek pergalê de xwedan şiyana xebitandina bernameyekê nîne). Dema ku banga pergalê vedigere, strace dê pêvajoyê ji nû ve bi kar bîne PTRACE_CONT û dê li benda peyamên nû ji seccomp bimîne.

BPF ji bo piçûkan, beşa sifir: BPF klasîk

Dema ku vebijarkê bikar tînin --seccomp-bpf du sînor hene. Pêşîn, ne gengaz e ku meriv beşdarî pêvajoyek berê ya heyî bibe (vebijark -p bernameyên strace), ji ber ku ev ji hêla seccomp ve nayê piştgirî kirin. Ya duyemîn jî, îmkan tune ne li pêvajoyên zarokan binihêrin, ji ber ku fîlterên seccomp ji hêla hemî pêvajoyên zarokan ve têne mîras kirin bêyî ku viya neçalak bikin.

A hûrgulî hinekî din li ser çawa tam strace bi hev re dixebite seccomp dikare ji rapora dawî. Ji bo me, rastiya herî balkêş ev e ku BPF-ya klasîk a ku ji hêla seccomp ve hatî temsîl kirin îro jî tê bikar anîn.

xt_bpf

Naha em vegerin ser cîhana torê.

Paşgotin: Demek dirêj berê, di sala 2007 de, bingehîn bû zêde kirin module xt_u32 ji bo netfilter. Ew ji hêla analogî ve bi dabeşkerek trafîkê ya hê kevntir ve hatî nivîsandin cls_u32 û destûr da we ku hûn ji bo iptables qaîdeyên binaryê yên keyfî bi karanîna van operasyonên hêsan ên jêrîn binivîsin: 32 bit ji pakêtê bar bikin û komek operasyonên jimareyî li ser wan bikin. Bo nimûne,

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

32 bit sernavê IP-yê, ji pelika 6-ê dest pê dike, bar dike û maskek li wan dixe. 0xFF (baytê kêm bistînin). Ev qada protocol Sernavê IP-ê û em wê bi 1 (ICMP) re berhev dikin. Hûn dikarin di yek qaîdeyek de gelek kontrolan bihev bikin, û hûn dikarin operatorê jî bicîh bikin @ - X bytes ber bi rastê ve biçin. Ji bo nimûne, rêbaz

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

kontrol dike ka Hejmara Rêzeya TCP ne wekhev e 0x29. Ez ê bêtir neçim hûrguliyan, ji ber ku jixwe diyar e ku nivîsandina qaîdeyên weha bi destan ne pir hêsan e. Di gotara BPF - bytecode jibîrkirî, gelek girêdan bi mînakên bikar anîn û hilberîna qaîdeyan re hene xt_u32. Her weha girêdanên li dawiya vê gotarê jî bibînin.

Ji sala 2013-an ve modul li şûna modulê xt_u32 hûn dikarin modulek bingehîn a BPF bikar bînin xt_bpf. Kesê ku heya nuha xwendiye divê jixwe prensîba xebata wê zelal be: BPF bytecode wekî qaîdeyên iptables bimeşînin. Hûn dikarin qaîdeyek nû biafirînin, mînakî, bi vî rengî:

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

vir <байткод> - ev koda di formata derana assembler de ye bpf_asm bi xwerû, bo nimûne,

$ 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

Di vê nimûneyê de em hemî pakêtên UDP fîlter dikin. Ji bo bernameyek BPF-ê di modulekê de çarçoveyek xt_bpf, bê guman, daneyên pakêtê, di mijara iptables de, destpêka sernavê IPv4 destnîşan dike. Nirxa vegerê ji bernameya BPF booleanko false tê wateya ku pakêt li hev nekir.

Ew eşkere ye ku modul xt_bpf ji mînaka li jor fîlterên tevlihevtir piştgirî dike. Ka em li mînakên rastîn ên Cloudfare binêrin. Heya vê dawiyê wan modul bikar anîn xt_bpf ji bo parastina li dijî êrîşên DDoS. Di gotara Danasîna Amûrên BPF ew rave dikin ka ew çawa (û çima) parzûnên BPF diafirînin û ji bo afirandina fîlterên weha lînkên komek karûbaran diweşînin. Mînakî, karanîna karûbar bpfgen hûn dikarin bernameyek BPF-ê ku ji bo navekî pirsek DNS-ê li hev dike biafirînin 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

Di bernameyê de em pêşî li qeydê bar dikin X destpêka navnîşana rêzê x04habrx03comx00 di hundurê datagramek UDP de û dûv re daxwazê ​​kontrol bikin: 0x04686162 <-> "x04hab" û vî awayî.

Piçek paşê, Cloudfare koda berhevkarê p0f -> BPF weşand. Di gotara Danasîna berhevkarê p0f BPF ew dipeyivin ka p0f çi ye û meriv çawa îmzeyên p0f veguherîne BPF:

$ ./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,
...

Niha êdî Cloudfare bikar naynin xt_bpf, ji ber ku ew çûn XDP - yek ji vebijarkên ji bo karanîna guhertoya nû ya BPF, binêre. L4Drop: Kêmasiyên XDP DDoS.

cls_bpf

Mînaka paşîn a karanîna BPF ya klasîk di kernelê de dabeşker e cls_bpf ji bo bine-pergala kontrolkirina trafîkê ya li Linux-ê, di dawiya sala 2013-an de li Linux-ê hate zêdekirin û bi têgînî şûna ya kevnar girt. cls_u32.

Lê belê, em ê niha karê şirove nekin cls_bpf, ji ber ku ji hêla zanyariyê ve di derbarê BPF-ya klasîk de ev ê tiştek nede me - em berê bi hemî fonksiyonan re nas bûne. Digel vê yekê, di gotarên paşîn de ku li ser BPF-ya Berfireh diaxivin, em ê ji carekê zêdetir bi vê dabeşkerê re hevdîtin bikin.

Sedemek din ku meriv qala karanîna BPF c ya klasîk neke cls_bpf Pirsgirêk ev e ku, li gorî Extended BPF, qada sepanê di vê rewşê de bi tundî teng dibe: bernameyên klasîk nikarin naveroka pakêtan biguhezînin û nekarin dewletê di navbera bangan de xilas bikin.

Ji ber vê yekê ew dem e ku meriv ji BPF-ya klasîk xatir bixwaze û li pêşerojê binêre.

Bi xatirê te ji BPF klasîk

Me nihêrî ka teknolojiya BPF, ku di destpêka salên nodî de pêş ket, çaryek sedsalê bi serfirazî jiya û heya dawiyê serlêdanên nû dît. Lêbelê, mîna derbasbûna ji makîneyên stackê berbi RISC, ku ji bo pêşkeftina BPF-ya klasîk wekî teşwîqek xizmet kir, di salên 32-an de ji makîneyên 64-bit berbi XNUMX-bit veguheztinek çêbû û BPF-ya klasîk dest bi kevinbûnê kir. Digel vê yekê, kapasîteyên BPF-ya klasîk pir tixûbdar in, û ji bilî mîmariya kevnar - ne xwediyê şiyana me ye ku em di navbera bangên bernameyên BPF-ê de dewletê xilas bikin, îmkana danûstendina rasterast a bikarhêner tune, îhtîmala danûstendinê tune. bi kernelê re, ji bilî xwendina hejmarek sînorkirî ya zeviyên strukturê sk_buff û destpêkirina fonksiyonên arîkar ên herî hêsan, hûn nekarin naveroka pakêtan biguhezînin û wan beralî bikin.

Di rastiyê de, niha her tiştê ku ji BPF-ya klasîk di Linux-ê de dimîne, pêwendiya API-yê ye, û di hundurê kernelê de hemî bernameyên klasîk, çi fîlterên soketê be an jî parzûnên seccomp, bixweber di formatek nû de, BPF-ya Berfireh, têne wergerandin. (Em ê di gotara pêş de tam li ser vê yekê bipeyivin ka ev çawa diqewime.)

Veguherîna mîmariya nû di 2013 de dest pê kir, dema ku Alexey Starovoitov nexşeyek nûvekirina BPF pêşniyar kir. Di sala 2014-an de pêlên têkildar dest pê kir di bingeh de. Bi qasî ku ez fêm dikim, plana destpêkê tenê xweşbînkirina mîmarî û berhevkarê JIT bû ku li ser makîneyên 64-bit bi bandortir bixebite, lê li şûna van xweşbîniyan destpêka beşek nû di pêşkeftina Linux de destnîşan kir.

Gotarên din ên di vê rêzê de dê mîmarî û serîlêdanên teknolojiya nû, ku di destpêkê de wekî BPF-ya navxweyî tê zanîn, dûv re BPF-ya dirêjkirî, û naha bi tenê BPF-ê vedihewîne.

references

  1. Steven McCanne û Van Jacobson, "Parzîna Pakêta BSD: Mîmarek Nû ji bo Girtina Pakêt-Asta Bikarhêner", https://www.tcpdump.org/papers/bpf-usenix93.pdf
  2. Steven McCanne, "libpcap: Mîmarek û Rêbazek Optimîzasyonê ji bo Girtina Pakêtan", https://sharkfestus.wireshark.org/sharkfest.11/presentations/McCanne-Sharkfest'11_Keynote_Address.pdf
  3. tcpdump, libpcap: https://www.tcpdump.org/
  4. Tutorial Match IPtable U32.
  5. BPF - bytecode jibîrkirî: https://blog.cloudflare.com/bpf-the-forgotten-bytecode/
  6. Danasîna Amûra BPF: https://blog.cloudflare.com/introducing-the-bpf-tools/
  7. bpf_cls: http://man7.org/linux/man-pages/man8/tc-bpf.8.html
  8. Pêşniyarek seccomp: https://lwn.net/Articles/656307/
  9. https://github.com/torvalds/linux/blob/master/Documentation/userspace-api/seccomp_filter.rst
  10. habr: Konteynir û ewlekarî: seccomp
  11. habr: Veqetandina şeytan bi systemd an "ji bo vê yekê hûn ne hewceyî Docker in!"
  12. Paul Chaignon, "strace --seccomp-bpf: awirek li binê kapê", https://fosdem.org/2020/schedule/event/debugging_strace_bpf/
  13. netsniff-ng: http://netsniff-ng.org/

Source: www.habr.com

Add a comment