BPF барои хурдсолон, қисми сифр: BPF классикӣ

Berkeley Packet Filters (BPF) як технологияи ядрои Linux мебошад, ки чанд сол боз дар саҳифаҳои аввали нашрияҳои технологӣ бо забони англисӣ қарор дорад. Конфронсҳо бо гузоришҳо дар бораи истифода ва рушди BPF пур карда мешаванд. Дэвид Миллер, нигоҳдории зерсистемаи шабакаи Linux, суханронии худро дар Linux Plumbers 2018 даъват мекунад "Ин сӯҳбат дар бораи XDP нест" (XDP як ҳолати истифода барои BPF аст). Брендан Грегг бо сарлавҳа гуфтугӯ мекунад Superpowers Linux BPF. Токе Ҳойланд-Йоргенсен хандидки ядро ​​акнун як микроядро мебошад. Томас Граф ин идеяро пешбарӣ мекунад BPF JavaScript барои ядро ​​​​аст.

То ҳол тавсифи систематикии BPF дар Habré вуҷуд надорад ва аз ин рӯ дар як қатор мақолаҳо ман кӯшиш мекунам дар бораи таърихи технология сӯҳбат кунам, асбобҳои меъморӣ ва рушдро тавсиф кунам ва самтҳои татбиқ ва амалияи истифодаи BPF-ро шарҳ диҳам. Ин мақола, сифр, дар силсила, таърих ва меъмории классикии BPF нақл мекунад ва инчунин асрори принсипҳои кори онро ошкор мекунад. tcpdump, seccomp, strace, ва бисёр чизҳои дигар.

Рушди BPF аз ҷониби ҷомеаи шабакавии Linux назорат карда мешавад, барномаҳои асосии мавҷудаи BPF бо шабакаҳо алоқаманданд ва аз ин рӯ, бо иҷозат @eucario, Ман силсилаи «BPF барои хурдтаракон», ба ифтихори силсилаи бузург номида "Шабакаҳо барои хурдсолон".

Курси кӯтоҳ дар таърихи BPF(c)

Технологияи муосири BPF як версияи такмилёфта ва васеъшудаи технологияи кӯҳна бо ҳамон ном мебошад, ки ҳоло BPF классикӣ номида мешавад, то нофаҳмиҳо пешгирӣ карда шавад. Як утилитаи маъруф дар асоси BPF классикӣ сохта шудааст tcpdump, механизм seccomp, инчунин модулҳои камтар маълум xt_bpf барои iptables ва классификатор cls_bpf. Дар Linux муосир, барномаҳои классикии BPF ба таври худкор ба шакли нав тарҷума карда мешаванд, аммо аз нуқтаи назари корбар API дар ҷои худ боқӣ мондааст ва истифодаҳои нави BPF классикӣ, тавре ки мо дар ин мақола мебинем, ҳоло ҳам пайдо мешаванд. Аз ин сабаб ва инчунин азбаски пас аз таърихи рушди классикии BPF дар Linux, маълум мешавад, ки чӣ гуна ва чаро он ба шакли муосири худ табдил ёфтааст, ман тасмим гирифтам, ки бо мақолае дар бораи BPF классикӣ оғоз кунам.

Дар охири солҳои ҳаштодуми асри гузашта муҳандисони лабораторияи машҳури Лоуренс Беркли ба саволи дуруст филтр кардани бастаҳои шабакавӣ дар сахтафзор, ки дар охири солҳои ҳаштодуми асри гузашта муосир буданд, таваҷҷӯҳ зоҳир карданд. Идеяи асосии филтр, ки аслан дар технологияи CSPF (CMU/Stanford Packet Filter) амалӣ шуда буд, ҳарчи зудтар филтр кардани бастаҳои нолозим буд, яъне. дар фазои ядро, зеро ин аз нусхабардории маълумоти нолозим ба фазои корбар пешгирӣ мекунад. Барои таъмини амнияти вақти корӣ барои иҷро кардани коди корбар дар фазои ядро, як мошини виртуалии қуттии қум истифода шуд.

Аммо, мошинҳои маҷозӣ барои филтрҳои мавҷуда барои кор дар мошинҳои ба стек асосёфта тарҳрезӣ шуда буданд ва дар мошинҳои нави RISC чандон самаранок кор намекарданд. Дар натиҷа, бо кӯшишҳои муҳандисони Berkeley Labs технологияи нави BPF (Berkeley Packet Filters) таҳия карда шуд, ки меъмории мошини маҷозии он дар асоси протсессори Motorola 6502 тарҳрезӣ шудааст - қувваи кории чунин маҳсулоти маъруф. Apple II ё НЕ. Мошини нави виртуалӣ иҷрои филтрро дар муқоиса бо қарорҳои мавҷуда даҳҳо маротиба афзоиш дод.

Меъмории мошини BPF

Мо бо меъморй ба тарзи кор, тахлили мисолхо шинос мешавем. Аммо, барои оғоз, биёед бигӯем, ки мошин дорои ду регистри 32-бит барои корбар дастрас буд, як аккумулятор. A ва феҳристи индекс X, 64 байт хотира (16 калима), барои навиштан ва хондани минбаъда дастрас ва системаи хурди фармонҳо барои кор бо ин объектҳо. Дастурҳои ҷаҳиш оид ба татбиқи ифодаҳои шартӣ низ дар барномаҳо мавҷуданд, аммо барои кафолат додани анҷоми саривақтии барнома, ҷаҳишҳоро танҳо ба пеш кардан мумкин буд, яъне, аз ҷумла, сохтани ҳалқаҳо манъ буд.

Схемаи умумии ба кор андохтани машина чунин аст. Истифодабаранда барои меъмории BPF барнома эҷод мекунад ва бо истифода аз баъзе механизми ядро ​​(ба монанди занги система), барномаро бор мекунад ва ба он пайваст мекунад ба баъзехо ба генератори ҳодиса дар ядро ​​(масалан, ҳодиса омадани бастаи навбатӣ дар корти шабака мебошад). Ҳангоми рух додани ҳодиса, ядро ​​​​программаро иҷро мекунад (масалан, дар тарҷума) ва хотираи мошин ба ба баъзехо минтақаи хотираи ядро ​​(масалан, маълумоти бастаи воридотӣ).

Барои мо ба дидани мисолҳо чизҳои дар боло зикршуда кофӣ хоҳанд буд: мо ҳангоми зарурат бо система ва формати фармон шинос мешавем. Агар шумо хоҳед, ки фавран системаи фармондиҳии мошини виртуалиро омӯзед ва дар бораи тамоми қобилиятҳои он маълумот гиред, пас шумо метавонед мақолаи аслиро хонед. Филтри бастаи BSD ва/ё нисфи аввали файл Documentation/networking/filter.txt аз ҳуҷҷатҳои ядро ​​​​. Илова бар ин, шумо метавонед презентатсияро омӯзед libpcap: Методологияи меъморӣ ва оптимизатсия барои гирифтани пакет, ки дар он Маккен, яке аз муаллифони BPF, дар бораи таърихи офариниш сухан меронад libpcap.

Ҳоло мо ба баррасии ҳама намунаҳои муҳими истифодаи классикии BPF дар Linux меравем: tcpdump (libpcap), seccomp, xt_bpf, cls_bpf.

tcpdump

Таҳияи BPF дар баробари таҳияи фронт барои филтри бастаҳо - як утилитаи маъруф анҷом дода шуд. tcpdump. Ва азбаски ин қадимтарин ва машҳуртарин намунаи истифодаи классикии BPF мебошад, ки дар бисёр системаҳои оператсионӣ мавҷуд аст, мо омӯзиши технологияи худро бо он оғоз мекунем.

(Ман ҳама мисолҳоро дар ин мақола дар Linux иҷро кардам 5.6.0-rc6. Натиҷаи баъзе фармонҳо барои хондан беҳтар таҳрир карда шудааст.)

Мисол: риояи бастаҳои IPv6

Биёед тасаввур кунем, ки мо мехоҳем ҳамаи пакетҳои IPv6-ро дар интерфейс бубинем eth0. Барои ин мо метавонем барномаро иҷро кунем tcpdump бо филтри оддӣ ip6:

$ sudo tcpdump -i eth0 ip6

ҳамин тавр tcpdump филтрро тартиб медиҳад ip6 ба байткоди меъмории BPF ворид кунед ва онро ба ядро ​​фиристед (ба тафсилот дар қисмати Tcpdump: боркунӣ). Филтри боршуда барои ҳар як бастае, ки аз интерфейс мегузарад, иҷро мешавад eth0. Агар филтр арзиши ғайрисифрро баргардонад n, баъд то n байтҳои баста ба фазои корбар нусхабардорӣ карда мешавад ва мо онро дар баромад мебинем tcpdump.

BPF барои хурдсолон, қисми сифр: BPF классикӣ

Маълум мешавад, ки мо ба осонӣ фаҳмем, ки кадом байткод ба ядро ​​фиристода шудааст tcpdump бо ёрии tcpdump, агар мо онро бо вариант иҷро кунем -d:

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

Дар сатри сифр мо фармонро иҷро мекунем ldh [12], ки маънои "бор кардан ба реестрро дорад A ним калима (16 бит) дар суроғаи 12 ҷойгир аст ва саволи ягона ин аст, ки мо ба кадом намуди хотира муроҷиат мекунем? Ҷавоб ин аст, ки дар x сар мешавад (x+1)Байти бастаи шабакаи таҳлилшуда. Мо пакетҳоро аз интерфейси Ethernet мехонем eth0ва ин маънои онро дорадки баста чунин менамояд (барои соддагӣ, мо тахмин мезанем, ки дар баста тегҳои VLAN вуҷуд надоранд):

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

Пас, пас аз иҷрои фармон ldh [12] дар феҳрист A майдон пайдо мешавад Ether Type — навъи бастае, ки дар ин чаҳорчӯбаи Ethernet интиқол дода мешавад. Дар сатри 1 мо мундариҷаи реестрро муқоиса мекунем A (навъи баста) в 0x86ddва ин ва вуҷуд дорад Намуде, ки мо ба он таваҷҷӯҳ дорем, IPv6 аст. Дар сатри 1, ба ғайр аз фармони муқоиса, боз ду сутун мавҷуд аст - jt 2 и jf 3 — аломатҳое, ки агар муқоиса муваффақ бошад (A == 0x86dd) ва нобарор. Ҳамин тавр, дар ҳолати муваффақ (IPv6) мо ба сатри 2 меравем ва дар ҳолати номуваффақ - ба сатри 3. Дар сатри 3 барнома бо рамзи 0 хотима меёбад (пакетро нусхабардорӣ накунед), дар сатри 2 барнома бо код хотима меёбад. 262144 (ба ман ҳадди аксар 256 килобайтро нусхабардорӣ кунед).

Мисоли мураккабтар: мо ба бастаҳои TCP аз рӯи бандари таъинот назар мекунем

Биёед бубинем, ки филтр чӣ гуна аст, ки ҳамаи бастаҳои TCP-ро бо порти таъиноти 666 нусхабардорӣ мекунад. Мо парвандаи IPv4-ро баррасӣ хоҳем кард, зеро парвандаи IPv6 соддатар аст. Пас аз омӯзиши ин мисол, шумо метавонед филтри IPv6-ро худатон ҳамчун машқ (ip6 and tcp dst port 666) ва филтр барои ҳолати умумӣ (tcp dst port 666). Ҳамин тавр, филтри ба мо таваҷҷӯҳ зоҳир кардани он чунин аст:

$ 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 ва 1 чӣ кор мекунанд. Дар сатри 2 мо аллакай санҷидаем, ки ин бастаи IPv4 аст (Ether Type = 0x800) ва онро ба реестр бор кунед A Байти 24-уми баста. Бастаи мо чунин менамояд

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

ки ин маънои онро дорад, ки мо ба реестр бор мекунем A майдони Протоколи сарлавҳаи IP, ки мантиқист, зеро мо мехоҳем танҳо бастаҳои TCP-ро нусхабардорӣ кунем. Мо Протоколро бо 0x6 (IPPROTO_TCP) дар сатри 3.

Дар сатрҳои 4 ва 5 мо нимкалимаҳои дар суроғаи 20 ҷойгиршударо бор мекунем ва фармонро истифода мебарем jset санҷед, ки яке аз се муқаррар карда шудааст байракхо - пӯшидани ниқоби додашуда jset се битҳои муҳимтарин тоза карда мешаванд. Ду бит аз се бит ба мо мегӯянд, ки оё баста як қисми пакети пора-пораи IP аст ва агар ин тавр бошад, оё он порчаи охирин аст. Бити сеюм маҳфуз аст ва бояд сифр бошад. Мо намехоҳем бастаҳои нопурра ё шикастаро тафтиш кунем, аз ин рӯ ҳар се битро тафтиш мекунем.

Сатри 6 ҷолибтарин дар ин рӯйхат аст. Ифода ldxb 4*([14]&0xf) маънои онро дорад, ки мо ба реестр бор мекунем X камтарин чор бит аз байт понздаҳуми баста ба 4 зарб. Дарозии сарлавҳаи интернет Сарлавҳаи IPv4, ки дарозии сарлавҳаро бо калимаҳо нигоҳ медорад, бинобар ин шумо бояд ба 4 зарб кунед. Ҷолиб он аст, ки ифода 4*([14]&0xf) нишона барои схемаи махсуси адресатсия мебошад, ки онро танҳо дар ин шакл ва танҳо барои реестр истифода бурдан мумкин аст X, яъне. мо хам гуфта наметавонем ldb 4*([14]&0xf) на ldxb 5*([14]&0xf) (мо метавонем танҳо ҷуброни дигарро муайян кунем, масалан, ldxb 4*([16]&0xf)). Маълум аст, ки ин схемаи адресатсия ба BPF маҳз барои гирифтани он илова карда шудааст X (Феҳристи индекс) Дарозии сарлавҳаи IPv4.

Ҳамин тавр, дар сатри 7 мо кӯшиш мекунем, ки ним калимаро дар (X+16). Дар хотир доред, ки 14 байтро сарлавҳаи Ethernet ишғол мекунад ва X дорои дарозии сарлавҳаи IPv4, мо мефаҳмем, ки дар A Порти таъиноти TCP бор карда шудааст:

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

Ниҳоят, дар сатри 8 мо порти таъинотро бо арзиши дилхоҳ муқоиса мекунем ва дар сатрҳои 9 ё 10 натиҷаро бармегардонем - оё бастаро нусхабардорӣ мекунем ё не.

Tcpdump: боркунӣ

Дар мисолҳои қаблӣ, мо ба таври муфассал дар бораи он ки чӣ гуна мо байткоди BPF-ро ба ядро ​​барои филтркунии пакет бор мекунем, нагуфтем. Умуман, tcpdump ба бисёр системаҳо интиқол дода мешавад ва барои кор бо филтрҳо tcpdump китобхонаро истифода мебарад libpcap. Ба таври мухтасар, барои ҷойгир кардани филтр дар интерфейс бо истифода аз libpcap, шумо бояд инҳоро иҷро кунед:

  • тавсифкунандаи тип эҷод кунед pcap_t аз номи интерфейс: pcap_create,
  • интерфейси фаъол: pcap_activate,
  • филтр тартиб додан: pcap_compile,
  • филтрро пайваст кунед: pcap_setfilter.

Барои дидани он, ки функсия чӣ гуна аст pcap_setfilter дар Linux амалӣ карда мешавад, мо истифода мебарем strace (баъзе сатрҳо хориҷ карда шудаанд):

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

Дар ду сатри аввали баромад мо эҷод мекунем розеткаи хом барои хондани ҳамаи чаҳорчӯбаҳои Ethernet ва пайваст кардани он ба интерфейс eth0. Аз мисоли аввалини мо мо медонем, ки филтр ip аз чор дастури BPF иборат хоҳад буд ва дар хати сеюм мо мебинем, ки чӣ тавр истифода бурдани опсия SO_ATTACH_FILTER занги система setsockopt мо филтри дарозии 4-ро бор мекунем ва пайваст мекунем. Ин филтри мост.

Қобили зикр аст, ки дар BPF-и классикӣ боркунӣ ва пайваст кардани филтр ҳамеша ҳамчун амалиёти атомӣ сурат мегирад ва дар версияи нави BPF боркунии барнома ва пайваст кардани он ба генератори ҳодиса бо вақт ҷудо карда мешавад.

Ҳақиқати Пинҳон

Варианти каме мукаммалтари натиҷа чунин аст:

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

Тавре ки дар боло зикр гардид, мо филтри худро ба васлаки сатри 5 бор мекунем ва пайваст мекунем, аммо дар сатрҳои 3 ва 4 чӣ мешавад? Маълум мешавад, ки ин libpcap ба мо ғамхорӣ мекунад - ба тавре ки баромади филтри мо бастаҳоеро дар бар нагирад, ки онро қонеъ намекунанд, китобхона мепайвандад филтри муҷаррад ret #0 (ҳамаи бастаҳоро партоед), розеткаро ба ҳолати ғайрибандӣ мегузарад ва кӯшиш мекунад, ки ҳамаи бастаҳоеро, ки аз филтрҳои қаблӣ боқӣ монда метавонанд, хориҷ кунед.

Дар маҷмӯъ, барои филтр кардани бастаҳо дар Linux бо истифода аз BPF классикӣ, шумо бояд филтр дар шакли сохтор дошта бошед struct sock_fprog ва розеткаи кушода, ки пас аз он филтрро бо истифода аз занги система ба васл кардан мумкин аст setsockopt.

Ҷолиб он аст, ки филтрро на танҳо хом, балки ба ҳама гуна розетка васл кардан мумкин аст. Ин ҷо намуна барномае, ки ҳама ба ҷуз ду байтҳои аввалро аз ҳама датаграммаҳои воридотии UDP қатъ мекунад. (Ман дар код шарҳҳо илова кардам, то мақоларо халалдор накунам.)

Тафсилоти бештар дар бораи истифода setsockopt барои пайваст кардани филтрҳо нигаред розетка (7), балки дар бораи навиштани филтрҳои худ мисли struct sock_fprog бе кумак tcpdump дар бахш сухбат мекунем Барномасозии BPF бо дастони худ.

BPF классикӣ ва асри XNUMX

BPF дар соли 1997 ба Linux дохил карда шуда буд ва барои муддати тӯлонӣ як аспи корӣ боқӣ монд libpcap бе ягон тағйироти махсус (Тағйироти мушаххаси Linux, албатта, Ин буд,, аммо онҳо манзараи ҷаҳониро тағир надоданд). Аввалин аломатҳои ҷиддии рушди BPF дар соли 2011 пайдо шуданд, вақте ки Эрик Думазет пешниҳод кард часпондан, ки Just In Time Compiler -ро ба ядро ​​илова мекунад - тарҷумон барои табдил додани байткоди BPF ба аслӣ x86_64 рамзи.

Компилятори JIT дар силсилаи тағйирот аввалин шуда буд: дар соли 2012 пайдо шуд қобилияти навиштани филтрҳо барои секкомп, бо истифода аз BPF, дар моҳи январи соли 2013 вуҷуд дошт илова намуд модул xt_bpf, ки ба шумо имкон медиҳад, ки қоидаҳои нависед iptables бо кӯмаки BPF, ва дар моҳи октябри соли 2013 буд илова намуд инчунин модул cls_bpf, ки ба шумо имкон медиҳад, ки таснифоти трафикро бо истифода аз BPF нависед.

Мо ба зудӣ ҳамаи ин мисолҳоро муфассалтар дида мебароем, аммо аввал барои мо омӯхтани тарзи навиштан ва тартиб додани барномаҳои худсарона барои BPF муфид хоҳад буд, зеро имкониятҳои аз ҷониби китобхона пешниҳодшуда libpcap маҳдуд (мисоли оддӣ: филтр тавлидшуда libpcap метавонад танҳо ду арзишро баргардонад - 0 ё 0x40000) ё умуман, ба монанди ҳолати seccomp, татбиқ намешаванд.

Барномасозии BPF бо дастони худ

Биёед бо формати бинарии дастурҳои BPF шинос шавем, ин хеле содда аст:

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

Ҳар як дастур 64 битро ишғол мекунад, ки дар он 16 битҳои аввал коди дастур мебошанд, баъд ду хати ҳашт-битӣ мавҷуданд, jt и jf, ва 32 бит барои далел K, ки максад аз он аз фармон ба фармон фарк мекунад. Масалан, фармон ret, ки барномаро қатъ мекунад, код дорад 6, ва арзиши бозгашт аз доимӣ гирифта мешавад K. Дар C, як дастури BPF ҳамчун сохтор муаррифӣ карда мешавад

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

ва тамоми барнома дар шакли сохтор аст

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

Ҳамин тариқ, мо аллакай метавонем барномаҳо нависем (масалан, мо кодҳои дастурро аз [1]). Ин аст, ки филтр чунин хоҳад буд ip6 аз он мисоли аввалини мо:

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

барнома prog мо метавонем ба таври қонунӣ дар занг истифода барем

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

Навиштани барномаҳо дар шакли рамзҳои мошинӣ чандон қулай нест, вале баъзан зарур аст (масалан, барои ислоҳи хатогиҳо, эҷоди тестҳои воҳидҳо, навиштани мақолаҳо дар Habré ва ғайра). Барои роҳат, дар файл <linux/filter.h> макросҳои ёрирасон муайян карда шудаанд - ҳамон мисоли дар боло зикршударо метавон дубора навишт

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

Аммо, ин вариант хеле қулай нест. Ин аст он чизе ки барномасозони ядрои Linux асоснок карданд ва аз ин рӯ дар феҳрист tools/bpf ядроҳо шумо метавонед ассемблер ва ислоҳкунандаро барои кор бо классикии BPF пайдо кунед.

Забони ассамблея ба баромади дебаг хеле монанд аст tcpdump, вале илова бар ин мо метавонем тамғакоғазҳои рамзиро муайян кунем. Масалан, ин ҷо як барномаест, ки ҳамаи бастаҳоро ба ҷуз TCP/IPv4 мепартояд:

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

Бо нобаёнӣ, ассемблер кодро дар формат тавлид мекунад <количество инструкций>,<code1> <jt1> <jf1> <k1>,..., барои мисоли мо бо TCP он хоҳад буд

$ 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, формати дигари баромадро истифода бурдан мумкин аст:

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

Ин матнро метавон ба таърифи сохтори намуд нусхабардорӣ кард struct sock_filter, чунон ки мо дар аввали ин бахш кардем.

Linux ва васеъшавии netsniff-ng

Илова ба стандарти BPF, Linux ва tools/bpf/bpf_asm дастгирй ва маҷмӯи ғайристандартӣ. Асосан, дастурҳо барои дастрасӣ ба майдонҳои сохтор истифода мешаванд struct sk_buff, ки бастаи шабакавиро дар ядро ​​тавсиф мекунад. Аммо, инчунин намудҳои дигари дастурҳои ёрирасон мавҷуданд, масалан ldw cpu ба реестр бор карда мешавад A натиҷаи иҷро кардани функсияи ядро ​​​​ raw_smp_processor_id(). (Дар версияи нави BPF, ин васеъкуниҳои ғайристандартӣ барои таъмини барномаҳо бо маҷмӯи ёрирасонҳои ядро ​​барои дастрасӣ ба хотира, сохторҳо ва тавлиди рӯйдодҳо васеъ карда шудаанд.) Ин аст мисоли ҷолиби филтр, ки дар он мо танҳо сарлавҳаҳои бастаҳо ба фазои корбар бо истифода аз васеъкунӣ poff, ҷуброни боркашонӣ:

ld poff
ret a

Дар васеъкунии BPF наметавонанд истифода шаванд tcpdump, аммо ин як сабаби хуб барои шинос шудан бо бастаи коммуналӣ аст netsniff-ng, ки дар байни дигар чизҳо, дорои барномаи пешрафта мебошад netsniff-ng, ки ба ғайр аз филтр бо истифода аз BPF, инчунин дорои генератори самараноки трафик, ва пешрафтатар аз tools/bpf/bpf_asm, як монтажчии BPF даъват карда шуд bpfc. Маҷмӯа дорои ҳуҷҷатҳои хеле муфассал аст, инчунин ба истинодҳо дар охири мақола нигаред.

секкомп

Ҳамин тавр, мо аллакай медонем, ки чӣ тавр навиштани барномаҳои BPF-и мураккабии худсарона ва омодаем, ки мисолҳои навро бубинем, ки аввалини онҳо технологияи seccomp мебошад, ки имкон медиҳад бо истифода аз филтрҳои BPF маҷмӯа ва маҷмӯи аргументҳои зангҳои системавиро идора кунад. раванди додашуда ва наслҳои он.

Нахустин версияи seccomp ба ядро ​​соли 2005 илова карда шуд ва он қадар маъмул набуд, зеро он танҳо як вариантро фароҳам овард - маҳдуд кардани маҷмӯи зангҳои системавӣ барои раванд ба таври зерин: read, write, exit и sigreturn, ва процессе, ки коидахоро вайрон мекард, истифода бурда кушта шуд SIGKILL. Аммо, дар соли 2012, seccomp қобилияти истифодаи филтрҳои BPF-ро илова кард, ки ба шумо имкон медиҳад, ки маҷмӯи зангҳои системавии иҷозатдодашударо муайян кунед ва ҳатто далелҳои онҳоро тафтиш кунед. (Ҷолиб он аст, ки Chrome яке аз аввалин корбарони ин функсия буд ва мардуми Chrome дар айни замон механизми KRSI-ро дар асоси версияи нави BPF таҳия мекунанд ва ба мутобиқсозии Модулҳои Амнияти Linux иҷозат медиҳанд.) Истинодҳо ба ҳуҷҷатҳои иловагиро дар охир пайдо кардан мумкин аст. аз мақола.

Аҳамият диҳед, ки дар марказ аллакай мақолаҳо дар бораи истифодаи seccomp мавҷуданд, шояд касе мехоҳад онҳоро пеш аз хондани зерфаслҳои зерин (ё ба ҷои) хонад. Дар макола Контейнерҳо ва амният: seccomp намунаҳои истифодаи seccomp, ҳам версияи 2007 ва ҳам версияи истифодаи BPF (филтрҳо бо истифода аз libseccomp тавлид мешаванд), дар бораи пайвасти seccomp бо Docker сӯҳбат мекунанд ва инчунин истинодҳои муфидро пешкаш мекунанд. Дар макола Ҷудо кардани демонҳо бо systemd ё "барои ин ба шумо Docker лозим нест!" Он, аз ҷумла, чӣ гуна илова кардани рӯйхати сиёҳ ё рӯйхати сафеди зангҳои системаро барои демонҳои системавӣ дар бар мегирад.

Минбаъд мо мебинем, ки чӣ гуна филтрҳоро навиштан ва бор кардан лозим аст seccomp дар C луч ва бо истифода аз китобхона libseccomp ва тарафҳои мусбӣ ва манфии ҳар як вариант чист ва дар ниҳоят биёед бубинем, ки seccomp аз ҷониби барнома чӣ гуна истифода мешавад strace.

Навиштан ва боркунии филтрҳо барои seccomp

Мо аллакай медонем, ки чӣ гуна барномаҳои BPF нависед, аз ин рӯ биёед аввал интерфейси барномасозии seccomp-ро бубинем. Шумо метавонед филтрро дар сатҳи раванд насб кунед ва ҳамаи равандҳои кӯдак маҳдудиятҳоро мерос мегиранд. Ин бо истифода аз занги система анҷом дода мешавад seccomp(2):

seccomp(SECCOMP_SET_MODE_FILTER, flags, &filter)

ки &filter - ин нишондодест ба сохторе, ки барои мо аллакай шинос аст struct sock_fprog, яъне. Барномаи BPF.

Барномаҳои seccomp аз барномаҳои розеткаҳо чӣ фарқият доранд? Контексти интиқолшуда. Дар мавриди розеткаҳо ба мо як минтақаи хотирае дода шуд, ки пакетро дар бар мегирад ва дар мавриди seccomp ба мо сохторе дода шуд

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

Ин аст, nr рақами занги системаест, ки бояд оғоз шавад, arch - меъмории ҷорӣ (бештар дар ин бора дар зер), args - то шаш далелҳои занги система, ва instruction_pointer ишора ба дастури фазои корбар аст, ки занги системаро кардааст. Ҳамин тариқ, масалан, барои бор кардани рақами занги система ба реестр A мо бояд гуфт

ldw [0]

Барои барномаҳои seccomp дигар хусусиятҳо мавҷуданд, масалан, ба контекст танҳо тавассути ҳамоҳангсозии 32-бит дастрас шудан мумкин аст ва шумо наметавонед ним калима ё байтро бор кунед - ҳангоми кӯшиши бор кардани филтр ldh [0] занги система seccomp бармегардад EINVAL. Функсия филтрҳои боршударо тафтиш мекунад seccomp_check_filter() ядроҳо. (Хандовар ин аст, ки дар ӯҳдадории аслӣ, ки функсияи seccomp-ро илова кардааст, онҳо фаромӯш карданд, ки иҷозати истифодаи дастурро ба ин функсия илова кунанд. mod (боқимондаи тақсимот) ва ҳоло барои барномаҳои seccomp BPF, аз замони илова шуданаш дастнорас аст мешиканад АБИ.)

Асосан, мо аллакай ҳама чизро барои навиштан ва хондани барномаҳои seccomp медонем. Одатан мантиқи барнома ҳамчун рӯйхати сафед ё сиёҳи зангҳои система тартиб дода мешавад, масалан, барнома

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 месанҷад. Ин зангҳои система чист? Мо аниқ гуфта наметавонем, зеро намедонем, ки барнома барои кадом меъморӣ навишта шудааст. Бинобар ин, муаллифони секкомп резерв ҳамаи барномаҳоро бо санҷиши меъморӣ оғоз кунед (меъмории ҷорӣ дар контекст ҳамчун майдон нишон дода мешавад arch сохторҳо struct seccomp_data). Бо тафтиши меъморӣ, оғози мисол чунин хоҳад буд:

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

ва он гоҳ рақамҳои занги системаи мо арзишҳои муайянро мегиранд.

Мо филтрҳоро барои seccomp истифода менависем ва бор мекунем libseccomp

Навиштани филтрҳо дар коди аслӣ ё дар маҷлиси BPF ба шумо имкон медиҳад, ки аз болои натиҷа пурра назорат кунед, аммо дар айни замон, баъзан доштани рамзи сайёр ва/ё хондашаванда афзалтар аст. Дар ин бобат ба мо китобхона ёрй мерасонад libseccomp, ки интерфейси стандартиро барои навиштани филтрҳои сиёҳ ё сафед таъмин мекунад.

Масалан, биёед барномаеро нависем, ки файли бинарии интихобкардаи корбарро иҷро мекунад ва қаблан рӯйхати сиёҳи зангҳои системаро аз мақолаи боло (барнома барои хониши бештар содда карда шудааст, версияи пурраи онро метавон пайдо кард дар ин ҷо):

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

Аввал мо массивро муайян мекунем sys_numbers аз 40+ рақамҳои занги система барои бастани. Сипас, контекстро оғоз кунед ctx ва ба китобхона бигӯед, ки мо чӣ мехоҳем иҷозат диҳем (SCMP_ACT_ALLOW) ҳама зангҳои системавӣ ба таври нобаёнӣ (сохтани рӯйхати сиёҳ осонтар аст). Сипас, мо як ба як ҳамаи зангҳои системаро аз рӯйхати сиёҳ илова мекунем. Дар посух ба занги система аз рӯйхат, мо дархост мекунем SCMP_ACT_TRAP, дар ин ҳолат seccomp ба раванд сигнал мефиристад SIGSYS бо тавсифи он, ки кадом занги система қоидаҳоро вайрон кардааст. Ниҳоят, мо бо истифода аз барнома барномаро ба ядро ​​бор мекунем seccomp_load, ки барномаро тартиб медиҳад ва онро бо истифода аз занги система ба раванд замима мекунад seccomp(2).

Барои бомуваффақият тартиб додани барнома, бояд бо китобхона пайваст карда шавад libseccomp, масалан:

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

Намунаи оғози бомуваффақият:

$ ./seccomp_lib echo ok
ok

Намунаи занги басташудаи система:

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

Мо истифода мебарем straceбарои тафсилот:

$ 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

аз куҷо мо метавонем донем, ки барнома бо сабаби истифодаи занги ғайриқонунии система қатъ шудааст mount(2).

Ҳамин тавр, мо бо истифода аз китобхона филтр навиштем libseccomp, мувофиқ кардани рамзи ғайримуқаррарӣ ба чор сатр. Дар мисоли дар боло овардашуда, агар шумораи зиёди зангҳои система вуҷуд дошта бошанд, вақти иҷроро ба таври назаррас коҳиш додан мумкин аст, зеро чек танҳо рӯйхати муқоисаҳост. Барои оптимизатсия, libseccomp ба наздикӣ дошт пачка дохил карда шудааст, ки дастгирии атрибути филтрро илова мекунад SCMP_FLTATR_CTL_OPTIMIZE. Танзими ин атрибут ба 2 филтрро ба барномаи ҷустуҷӯии дуӣ табдил медиҳад.

Агар шумо хоҳед бинед, ки филтрҳои ҷустуҷӯии дуӣ чӣ гуна кор мекунанд, ба он назар андозед скрипти оддӣ, ки чунин барномаҳоро дар ассемблер BPF тавассути зангзании рақамҳои занги система тавлид мекунад, масалан:

$ 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

Ба таври назаррас зудтар навиштани чизе ғайриимкон аст, зеро барномаҳои BPF ҷаҳишҳоро иҷро карда наметавонанд (масалан, мо наметавонем, jmp A ё jmp [label+X]) ва аз ин рӯ, ҳамаи гузаришҳо статикӣ мебошанд.

seccomp ва strace

Фоидаро ҳама медонад strace воситаи муҳим барои омӯзиши рафтори равандҳо дар Linux мебошад. Бо вуҷуди ин, бисёриҳо дар бораи он шунидаанд масъалаҳои иҷроиш ҳангоми истифодаи ин утилита. Гап дар сари он аст strace истифода бурда мешавад ptrace(2), ва дар ин механизм мо наметавонем муайян кунем, ки дар кадом маҷмӯи зангҳои система ба мо лозим аст, ки равандро қатъ кунем, масалан, фармонҳо.

$ 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

тақрибан дар як вақт коркард мешаванд, гарчанде ки дар ҳолати дуюм мо мехоҳем танҳо як занги системаро пайгирӣ кунем.

Варианти нав --seccomp-bpf, илова ба strace версияи 5.3, ба шумо имкон медиҳад, ки равандро чанд маротиба суръат бахшед ва вақти оғозёбӣ дар зери як занги система аллакай бо вақти оғози муқаррарӣ муқоиса карда мешавад:

$ 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

(Дар ин ҷо, албатта, як фиреби каме вуҷуд дорад, ки мо занги асосии ин фармонро пайгирӣ намекунем. Агар мо пайгирӣ мекардем, масалан, newfsstat, он гоҳ strace тормоз мекард, мисли он ки бидуни он --seccomp-bpf.)

Ин вариант чӣ гуна кор мекунад? Бе вай strace ба раванд пайваст мешавад ва онро ба истифода оғоз мекунад PTRACE_SYSCALL. Вақте ки раванди идорашаванда (ҳар гуна) занги системаро медиҳад, назорат ба он интиқол дода мешавад strace, ки ба далелҳои занги система назар мекунад ва онро бо истифода аз он иҷро мекунад PTRACE_SYSCALL. Пас аз чанд вақт, раванд занги системаро анҷом медиҳад ва ҳангоми баромадан аз он, назорат дубора интиқол дода мешавад strace, ки ба арзишҳои бозгашт назар мекунад ва равандро бо истифода оғоз мекунад PTRACE_SYSCALL, ва ғайра.

BPF барои хурдсолон, қисми сифр: BPF классикӣ

Бо seccomp, ин равандро метавон маҳз ҳамон тавре ки мо мехоҳем оптимизатсия кард. Маҳз, агар мо хоҳем, ки танҳо занги системаро бубинем X, он гоҳ мо метавонем филтри BPF нависем, ки барои X арзиш бармегардонад SECCOMP_RET_TRACE, ва барои зангҳое, ки барои мо манфиатдор нестанд - SECCOMP_RET_ALLOW:

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

Дар ин ҳолат strace дар аввал процессро чун PTRACE_CONT, филтри мо барои ҳар як занги система коркард мешавад, агар занги система набошад X, пас процесс давом дорад, аммо агар ин X, пас seccomp назоратро интиқол медиҳад straceки ба далелхо назар карда, процесси монанди PTRACE_SYSCALL (зеро seccomp қобилияти иҷро кардани барномаро ҳангоми баромадан аз занги система надорад). Вақте ки занги система бармегардад, strace бо истифода аз раванди аз нав оғоз хоҳад кард PTRACE_CONT ва паёмҳои навро аз seccomp интизор мешаванд.

BPF барои хурдсолон, қисми сифр: BPF классикӣ

Ҳангоми истифодаи опсия --seccomp-bpf ду маҳдудият вуҷуд дорад. Аввалан, ҳамроҳ шудан ба раванди мавҷуда имконнопазир хоҳад буд (варианти -p барномаҳои strace), зеро ин аз ҷониби seccomp дастгирӣ намешавад. Дуюм, имкон надорад не ба равандҳои кӯдакон нигаред, зеро филтрҳои seccomp аз ҷониби ҳамаи равандҳои кӯдакона мерос гирифта мешаванд, ки қобилияти хомӯш кардани ин.

Тафсилоти каме дар бораи он ки чӣ тавр дақиқ strace бо seccomp аз пайдо кардан мумкин аст гузориши охирин. Барои мо далели ҷолибтарин ин аст, ки BPF-и классикӣ, ки аз ҷониби seccomp муаррифӣ шудааст, ҳоло ҳам истифода мешавад.

xt_bpf

Акнун биёед ба ҷаҳони шабакаҳо баргардем.

Маълумот: хеле пеш, дар соли 2007, аслӣ буд илова намуд модул xt_u32 барои netfilter. Он аз рӯи қиёс бо таснифи боз ҳам қадимии трафик навишта шудааст cls_u32 ва ба шумо имкон дод, ки бо истифода аз амалҳои оддии зерин қоидаҳои бинариро барои iptables нависед: аз баста 32 бит бор кунед ва маҷмӯи амалҳои арифметикиро дар онҳо иҷро кунед. Барои намуна,

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

32 бит сарлавҳаи IP-ро аз пуркунии 6 сар карда, ба онҳо ниқоб татбиқ мекунад 0xFF (байти пастро гиред). Ин майдон protocol Сарлавҳаи IP ва мо онро бо 1 (ICMP) муқоиса мекунем. Шумо метавонед бисёр чекҳоро дар як қоида муттаҳид кунед ва шумо инчунин метавонед операторро иҷро кунед @ — X байтро ба тарафи рост гузаронед. Масалан, қоида

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

тафтиш мекунад, ки оё рақами пайдарпайии TCP баробар нест 0x29. Ман минбаъд ба тафсилот намеравам, зеро аллакай маълум аст, ки навиштани чунин қоидаҳо бо дастӣ чандон қулай нест. Дар макола BPF - байткоди фаромӯшшуда, якчанд пайвандҳо бо мисолҳои истифода ва тавлиди қоида барои нест xt_u32. Ҳамчунин ба истинодҳо дар охири ин мақола нигаред.

Аз соли 2013 модул ба ҷои модул xt_u32 шумо метавонед модули асоси BPF истифода баред xt_bpf. Ҳар касе, ки ин ҷо хондааст, бояд аллакай дар бораи принсипи кори он равшан бошад: BPF bytecode -ро ҳамчун қоидаҳои iptables иҷро кунед. Шумо метавонед як қоидаи нав эҷод кунед, масалан, ин тавр:

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

дар ин ҷо <байткод> - ин рамз дар формати баромади ассемблер аст bpf_asm ба таври нобаёнӣ, масалан,

$ 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

Дар ин мисол мо ҳама бастаҳои UDP-ро филтр мекунем. Контекст барои барномаи BPF дар модул xt_bpf, албатта, ба маълумоти маҷмӯӣ, дар мавриди iptables, ба оғози сарлавҳаи IPv4 ишора мекунад. Баргардонидани арзиш аз барномаи BPF булӣки дар false маънои онро дорад, ки баста мувофиқат намекунад.

Маълум аст, ки модул xt_bpf нисбат ба мисоли дар боло овардашуда филтрҳои мураккабтарро дастгирӣ мекунад. Биёед мисолҳои воқеиро аз Cloudfare дида бароем. То ба наздикӣ онҳо модулро истифода мебурданд xt_bpf барои муҳофизат аз ҳамлаҳои DDoS. Дар макола Муаррифии асбобҳои BPF онҳо мефаҳмонанд, ки чӣ тавр (ва чаро) онҳо филтрҳои BPF-ро тавлид мекунанд ва истинодҳоро ба маҷмӯи утилитаҳо барои сохтани чунин филтрҳо нашр мекунанд. Масалан, бо истифода аз утилита bpfgen шумо метавонед барномаи BPF эҷод кунед, ки ба дархости DNS барои ном мувофиқат кунад 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

Дар барнома мо аввал ба реестр бор мекунем X оғози суроғаи сатр x04habrx03comx00 дар дохили datagram UDP ва сипас дархостро тафтиш кунед: 0x04686162 <-> "x04hab" ва ғайра.

Каме дертар, Cloudfare рамзи компилятори p0f -> BPF-ро нашр кард. Дар макола Муаррифии компилятори p0f BPF онҳо дар бораи чӣ будани p0f ва чӣ гуна табдил додани имзоҳои p0f ба 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,
...

Ҳоло дигар Cloudfare-ро истифода намебарад xt_bpf, зеро онҳо ба XDP кӯчиданд - яке аз имконоти истифодаи версияи нави BPF, нигаред. L4Drop: Митигатсияҳои XDP DDoS.

cls_bpf

Намунаи охирини истифодаи классикии BPF дар ядро ​​​​классификатор аст cls_bpf барои зерсистемаи назорати трафик дар Linux, ки дар охири соли 2013 ба Linux илова карда шуд ва консептуалӣ ивазкунандаи қадимаи cls_u32.

Аммо, мо акнун корро тавсиф намекунем cls_bpf, зеро аз нуқтаи назари дониш дар бораи BPF классикӣ ин ба мо чизе намедиҳад - мо аллакай бо тамоми функсияҳо шинос шудаем. Илова бар ин, дар мақолаҳои минбаъда, ки дар бораи Extended BPF сухан меронанд, мо бо ин таснифот зиёда аз як маротиба вомехӯрем.

Сабаби дигаре, ки дар бораи истифодаи классикии BPF гап назанед в cls_bpf Мушкилот дар он аст, ки дар муқоиса бо Extended BPF, доираи татбиқ дар ин ҳолат ба таври куллӣ танг шудааст: барномаҳои классикӣ наметавонанд мундариҷаи бастаҳоро тағир диҳанд ва ҳолати байни зангҳоро захира карда наметавонанд.

Пас, вақти он расидааст, ки бо BPF классикӣ видоъ кунем ва ба оянда назар кунем.

Дуруд бо BPF классикӣ

Мо ба он назар кардем, ки технологияи BPF, ки дар ибтидои навадум таҳия шудааст, дар тӯли чоряк аср бомуваффақият зиндагӣ мекард ва то охир барномаҳои нав пайдо кард. Аммо, ба монанди гузариш аз мошинҳои стекӣ ба RISC, ки ҳамчун такони рушди классикии BPF хизмат мекард, дар солҳои 32-ум гузариш аз мошинҳои 64-бит ба XNUMX-бит ба амал омад ва BPF классикӣ кӯҳна шудан гирифт. Илова бар ин, имкониятҳои классикии BPF хеле маҳдуданд ва ба ғайр аз меъмории кӯҳна - мо имкони захира кардани ҳолати байни зангҳо ба барномаҳои BPF надорем, имкони ҳамкории мустақими корбарон вуҷуд надорад, имкони ҳамкорӣ вуҷуд надорад. бо ядро, ба истиснои хондани шумораи маҳдуди майдонҳои сохтор sk_buff ва ба кор андохтани соддатарин вазифаҳои ёрирасон, шумо наметавонед мундариҷаи пакетҳоро тағир диҳед ва ба онҳо равона кунед.

Дарвоқеъ, дар айни замон ҳама чизе, ки аз BPF-и классикӣ дар Linux боқӣ мемонад, интерфейси API мебошад ва дар дохили ядро ​​ҳама барномаҳои классикӣ, хоҳ он филтрҳои розетка ё филтрҳои seccomp, ба таври худкор ба формати нав, Extended BPF тарҷума карда мешаванд. (Мо дар бораи он ки чӣ тавр ин воқеа рӯй медиҳад, дар мақолаи навбатӣ сӯҳбат хоҳем кард.)

Гузариш ба меъмории нав дар соли 2013 оғоз ёфт, вақте ки Алексей Старовойтов нақшаи навсозии BPF-ро пешниҳод кард. Дар соли 2014 часбҳои мувофиқ пайдо шудан гирифт дар асл. То ҷое ки ман мефаҳмам, нақшаи аслӣ танҳо оптимизатсияи меъморӣ ва компилятори JIT буд, то дар мошинҳои 64-бит самараноктар кор кунад, аммо ба ҷои ин оптимизатсияҳо оғози боби нав дар рушди Linux буданд.

Мақолаҳои минбаъда дар ин силсила меъморӣ ва татбиқи технологияи навро дар бар мегиранд, ки дар аввал бо номи BPF дохилӣ маълуманд, баъд BPF васеъ ва ҳоло танҳо BPF.

мурожиат

  1. Стивен МакКен ва Ван Ҷейкобсон, "Филтри бастаи BSD: меъмории нав барои гирифтани пакети сатҳи корбар", https://www.tcpdump.org/papers/bpf-usenix93.pdf
  2. Стивен МакКэнн, "libpcap: Методологияи меъморӣ ва оптимизатсия барои гирифтани пакет", https://sharkfestus.wireshark.org/sharkfest.11/presentations/McCanne-Sharkfest'11_Keynote_Address.pdf
  3. tcpdump, libpcap: https://www.tcpdump.org/
  4. Омӯзиши бозии IPtable U32.
  5. BPF - байткоди фаромӯшшуда: https://blog.cloudflare.com/bpf-the-forgotten-bytecode/
  6. Муаррифии воситаи BPF: https://blog.cloudflare.com/introducing-the-bpf-tools/
  7. bpf_cls: http://man7.org/linux/man-pages/man8/tc-bpf.8.html
  8. Шарҳи мухтасар: https://lwn.net/Articles/656307/
  9. https://github.com/torvalds/linux/blob/master/Documentation/userspace-api/seccomp_filter.rst
  10. habr: Контейнерҳо ва амният: seccomp
  11. habr: Ҷудо кардани демонҳо бо systemd ё "барои ин ба шумо Docker лозим нест!"
  12. Пол Чайнон, "strace --seccomp-bpf: назар дар зери кулоҳ", https://fosdem.org/2020/schedule/event/debugging_strace_bpf/
  13. netsniff-ng: http://netsniff-ng.org/

Манбаъ: will.com

Илова Эзоҳ