د کوچنيانو لپاره BPF، برخه صفر: کلاسیک BPF

د برکلي پاکټ فلټرونه (BPF) د لینکس کرنل ټیکنالوژي ده چې د څو کلونو راهیسې د انګلیسي ژبې تخنیکي خپرونو په لومړي مخ کې ده. کنفرانسونه د BPF کارولو او پراختیا په اړه د راپورونو سره ډک شوي. ډیویډ میلر، د لینکس شبکې سب سیسټم ساتونکی، په لینکس پلمبرز 2018 کې خپلې خبرې کوي "دا خبرې د XDP په اړه ندي" (XDP د BPF لپاره د کارونې یوه قضیه ده). برینډن ګریګ حقدار خبرې ورکوي د لینکس BPF سوپر پاورونه. Toke Høiland-Jørgensen خندادا چې دانې اوس یو مایکروکرنل دی. توماس ګراف دا مفکوره هڅوي BPF د کرنل لپاره جاوا سکرپٹ دی.

په هابري کې د BPF سیسټماتیک توضیحات لاهم شتون نلري ، او له همدې امله د مقالو په لړۍ کې به زه هڅه وکړم د ټیکنالوژۍ تاریخ په اړه وغږیږم ، د جوړښت او پراختیا وسیلې تشریح کړم ، او د BPF کارولو غوښتنلیک او تمرین ساحې په ګوته کړم. دا مقاله، صفر، په لړۍ کې، د کلاسیک BPF تاریخ او جوړښت بیانوي، او د دې عملیاتي اصولو رازونه هم څرګندوي. tcpdump, seccomp, strace، او نور زیات.

د BPF پراختیا د لینکس شبکې ټولنې لخوا کنټرول کیږي ، د BPF اصلي موجوده غوښتنلیکونه د شبکې پورې اړه لري او له همدې امله د اجازې سره @eucariot، ما لړۍ ته "د کوچنيانو لپاره BPF" نوم ورکړ ، د لوی لړۍ په ویاړ "د کوچنیانو لپاره شبکې".

د BPF په تاریخ کې لنډ کورس (c)

عصري BPF ټیکنالوژي د ورته نوم سره د زاړه ټیکنالوژۍ یوه پرمختللې او پراخه شوې نسخه ده چې اوس د ګډوډۍ مخنیوي لپاره کلاسیک BPF نومیږي. یو پیژندل شوی افادیت د کلاسیک BPF پراساس رامینځته شوی tcpdump، میکانیزم seccompاو همدارنګه لږ پیژندل شوي ماډلونه xt_bpf لپاره iptables او طبقه بندي کوونکی cls_bpf. په عصري لینکس کې، د کلاسیک BPF پروګرامونه په اوتومات ډول نوي بڼه ته ژباړل کیږي، په هرصورت، د کاروونکي له نظره، API په خپل ځای کې پاتې دي او د کلاسیک BPF لپاره نوي استعمالونه، لکه څنګه چې موږ به پدې مقاله کې وګورو، لاهم موندل کیږي. د دې دلیل لپاره، او همدارنګه ځکه چې په لینکس کې د کلاسیک BPF پراختیا تاریخ تعقیب، دا به روښانه شي چې څنګه او ولې دا خپل عصري بڼه ته وده ورکړه، ما پریکړه وکړه چې د کلاسیک BPF په اړه د یوې مقالې سره پیل کړم.

د تیرې پیړۍ د اتیایمې لسیزې په پای کې، د لارنس برکلي د مشهور لابراتوار انجنیرانو د دې پوښتنې سره علاقه پیدا کړه چې څنګه په هارډویر کې د شبکې کڅوړې په سمه توګه فلټر کړي چې د تیرې پیړۍ د اتیایمې لسیزې په وروستیو کې عصري وه. د فلټر کولو اساسي نظر، په اصل کې په CSPF (CMU/Stanford Packet Filter) ټیکنالوژۍ کې پلي شوی، د امکان تر حده ژر تر ژره غیر ضروري کڅوړې فلټر کول وو، د بیلګې په توګه. د کرنل په ځای کې، ځکه چې دا د کارونکي ځای ته د غیر ضروري معلوماتو کاپي کولو څخه مخنیوی کوي. د کرنل ځای کې د کارونکي کوډ چلولو لپاره د چلولو وخت امنیت چمتو کولو لپاره ، د شګو بکس شوی مجازی ماشین کارول شوی و.

په هرصورت، د موجوده فلټرونو لپاره مجازی ماشینونه د سټیک پر بنسټ ماشینونو چلولو لپاره ډیزاین شوي او په نوي RISC ماشینونو کې په اغیزمنه توګه نه چلیدل. د پایلې په توګه ، د برکلي لابراتوار انجینرانو د هڅو له لارې ، د BPF (برکلي پاکټ فلټر) نوې ټیکنالوژي رامینځته شوه ، د مجازی ماشین جوړښت چې د موټرولا 6502 پروسیسر پراساس ډیزاین شوی و - د داسې مشهور محصولاتو کاري هارس. اپل II او یا NES. نوي مجازی ماشین د موجوده حلونو په پرتله د فلټر فعالیت لسګونه ځله زیات کړی.

د BPF ماشین جوړښت

موږ به په کاري طریقه د معمارۍ سره آشنا شو، د مثالونو تحلیل. په هرصورت ، د پیل کولو لپاره ، راځئ چې ووایو چې ماشین دوه 32-bit راجسترونه درلودل چې کارونکي ته د لاسرسي وړ دي ، یو جمع کونکی A او د شاخص ثبت X، د حافظې 64 بایټ (16 ټکي) ، د لیکلو او وروسته لوستلو لپاره شتون لري ، او د دې شیانو سره کار کولو لپاره د کمانډونو یو کوچنی سیسټم. په برنامو کې د شرطي څرګندونو پلي کولو لپاره د کود لارښوونې هم شتون درلود ، مګر د برنامه په وخت بشپړیدو تضمین کولو لپاره ، کودونه یوازې مخکې کیدی شي ، د بیلګې په توګه ، په ځانګړي توګه د لوپونو رامینځته کول منع وو.

د ماشین پیل کولو عمومي سکیم په لاندې ډول دی. کارونکي د BPF جوړښت لپاره یو برنامه رامینځته کوي او کارول کیږي ځینې د کرنل میکانیزم (لکه د سیسټم زنګ)، برنامه باروي او نښلوي ځینو ته په کرنل کې د پیښې جنراتور ته (د مثال په توګه ، پیښه د شبکې کارت کې د راتلونکي کڅوړې رارسیدل دي). کله چې یوه پیښه رامنځ ته شي، کرنل برنامه پرمخ وړي (د مثال په توګه، په ژباړونکي کې)، او د ماشین حافظه ورسره مطابقت لري. ځینو ته د کرنل حافظې سیمه (د بیلګې په توګه، د راتلونکی کڅوړې ډاټا).

پورته به زموږ لپاره کافي وي چې د مثالونو په لټه کې شو: موږ به د اړتیا سره سم د سیسټم او کمانډ فارمیټ سره آشنا شو. که تاسو غواړئ سمدلاسه د مجازی ماشین کمانډ سیسټم مطالعه کړئ او د دې ټولو وړتیاو په اړه زده کړئ ، نو تاسو کولی شئ اصلي مقاله ولولئ د BSD پاکټ فلټر او/یا د دوتنې لومړۍ نیمایي Documentation/networking/filter.txt د کرنل اسنادو څخه. سربیره پردې، تاسو کولی شئ پریزنټشن مطالعه کړئ libpcap: د بسته بندي کولو لپاره د جوړښت او اصلاح کولو میتودولوژيپه کوم کې چې مک کین، د BPF یو لیکوال، د تخلیق تاریخ په اړه خبرې کوي libpcap.

موږ اوس په لینکس کې د کلاسیک BPF کارولو ټولې مهمې بیلګې په پام کې نیسو: tcpdump (libpcap, seccomp, xt_bpf, cls_bpf.

tcpdump

د BPF پراختیا د پاکټ فلټر کولو لپاره د فرنټ اینډ پراختیا سره موازي ترسره شوې - یو مشهور کار tcpdump. او، ځکه چې دا د کلاسیک BPF کارولو ترټولو پخوانی او خورا مشهور مثال دی، په ډیری عملیاتي سیسټمونو کې شتون لري، موږ به د دې سره د ټیکنالوژۍ مطالعه پیل کړو.

(ما په دې مقاله کې ټول مثالونه په لینکس کې واخیستل 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)د تحلیل شوي شبکې پیکټ دریم بایټ. موږ د ایترنیټ انٹرفیس څخه پاکټونه لوستل eth0، او دا مطلبدا چې پاکټ داسې ښکاري (د سادګۍ لپاره، موږ فرض کوو چې په کڅوړه کې د VLAN ټاګونه شتون نلري):

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

نو د امر د اجرا کولو وروسته ldh [12] په راجستر کې A یو میدان به وي Ether Type - د دې ایترنیټ چوکاټ کې د لیږد شوي کڅوړې ډول. په 1 کرښه کې موږ د راجستر مینځپانګې پرتله کوو A (د بسته بندۍ ډول) ج 0x86dd، او دا او شته هغه ډول چې موږ یې لیوالتیا لرو IPv6 دی. په 1 کرښه کې، د پرتله کولو کمانډ سربیره، دوه نور کالمونه شتون لري - jt 2 и jf 3 - هغه نښه چې تاسو اړتیا لرئ لاړ شئ که چیرې پرتله کول بریالي وي (A == 0x86dd) او ناکامه. نو، په یوه بریالۍ قضیه (IPv6) کې موږ 2 کرښې ته ځو، او په ناکامه قضیه کې - 3 کرښې ته. په 3 کرښه کې برنامه د کوډ 0 سره پای ته رسیږي (پاکټ کاپي مه کوئ)، په 2 کرښه کې برنامه د کوډ سره پای ته رسیږي. 262144 (ما د اعظمي 256 کیلوبایټ کڅوړه کاپي کړئ).

یو ډیر پیچلی مثال: موږ د منزل بندر لخوا د TCP پاکټونو ته ګورو

راځئ وګورو چې یو فلټر څه ډول ښکاري چې د منزل پورټ 666 سره د TCP ټولې کڅوړې کاپي کوي. موږ به د 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 پاکټ دی (د ایتر ډول = 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, i.e. موږ هم نشو ویلای ldb 4*([14]&0xf) نه ldxb 5*([14]&0xf) (موږ کولی شو یوازې یو مختلف آفسیټ مشخص کړو، د بیلګې په توګه، ldxb 4*([16]&0xf)). دا څرګنده ده چې دا د پته لګولو سکیم د ترلاسه کولو لپاره په دقیقه توګه BPF ته اضافه شوی و X (د شاخص راجستر) IPv4 سرلیک اوږدوالی.

نو په 7 کرښه کې موږ هڅه کوو چې نیمه کلمه پورته کړو (X+16). په یاد ولرئ چې 14 بایټونه د ایترنیټ سرلیک لخوا نیول شوي ، او 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_setfilter په لینوکس کې تطبیق شوی، موږ کاروو 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
...

د محصول په لومړیو دوو کرښو کې موږ جوړوو خام ساکټ د ټولو ایترنیټ چوکاټونو لوستلو لپاره او د انٹرفیس سره وتړئ 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 (ټول پاکټونه پریږدئ)، ساکټ غیر بلاک کولو حالت ته واړوي او هڅه کوي ټول پاکټونه کم کړي چې د پخوانیو فلټرونو څخه پاتې کیدی شي.

په مجموع کې ، د کلاسیک BPF په کارولو سره په لینکس کې کڅوړې فلټر کولو لپاره ، تاسو اړتیا لرئ د جوړښت په بڼه فلټر ولرئ لکه struct sock_fprog او یو خلاص ساکټ، وروسته له هغه چې فلټر د سیسټم کال په کارولو سره ساکټ سره وصل کیدی شي setsockopt.

په زړه پورې ، فلټر په هر ساکټ سره وصل کیدی شي ، نه یوازې خام. دلته مثال یو برنامه چې د ټولو راتلونکو UDP ډیټاګرامونو څخه لومړی دوه بایټس پرته ټول پرې کوي. (ما په کوډ کې تبصرې اضافه کړې ترڅو مقاله ګډوډ نه کړي.)

د کارولو په اړه نور معلومات setsockopt د فلټرونو نښلولو لپاره، وګورئ ساکټ(7)، مګر د خپل فلټر لیکلو په اړه لکه struct sock_fprog پرته له مرستې tcpdump موږ به په برخه کې خبرې وکړو زموږ د خپلو لاسونو سره د BPF پروګرام کول.

کلاسیک BPF او 21 پیړۍ

BPF په 1997 کې په لینکس کې شامل شو او د اوږدې مودې لپاره د کار هارس پاتې شو libpcap پرته له کوم ځانګړي بدلون (د لینکس ځانګړي بدلونونه، البته، دا وه، مګر دوی نړیوال انځور بدل نه کړ). لومړنۍ جدي نښې چې 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))

د ماشین کوډونو په بڼه د پروګرامونو لیکل خورا اسانه ندي، مګر ځینې وختونه اړین دي (د بیلګې په توګه، د ډیبګ کولو لپاره، د واحد ازموینې رامینځته کول، په هابري کې مقالې لیکل، او داسې نور). د اسانتیا لپاره، په فایل کې <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),
}

په هرصورت، دا اختیار خورا اسانه نه دی. دا هغه څه دي چې د لینکس کرنل برنامه کونکي استدلال کوي ، او له همدې امله په لارښود کې 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لکه څنګه چې موږ د دې برخې په پیل کې وکړل.

لینکس او netsniff-ng توسیعونه

د معیاري BPF سربیره، لینکس او 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 فلټرونو کارولو وړتیا اضافه کړه، تاسو ته اجازه درکوي چې د اجازه ورکړل شوي سیسټم زنګونو سیټ تعریف کړئ او حتی د دوی دلیلونو چک ترسره کړئ. (په زړه پورې خبره دا ده چې کروم د دې فعالیت یو له لومړیو کاروونکو څخه و، او د کروم خلک اوس مهال د BPF نوې نسخه پراساس د KRSI میکانیزم رامینځته کوي او د لینکس امنیت ماډلونو دودیز کولو ته اجازه ورکوي.) اضافي اسنادو ته لینکونه په پای کې موندل کیدی شي د مقالې څخه.

په یاد ولرئ چې دمخه د سیکومپ کارولو په اړه په مرکز کې مقالې شتون لري ، شاید یو څوک وغواړي د لاندې فرعي برخو لوستلو دمخه (یا پرځای) یې ولولي. په مقاله کې کانټینرونه او امنیت: seccomp د Seccomp کارولو مثالونه وړاندې کوي، دواړه د 2007 نسخه او نسخه د BPF په کارولو سره (فلټرونه د libseccomp په کارولو سره تولید شوي)، د Docker سره د seccomp د ارتباط په اړه خبرې کوي، او ډیری ګټورې اړیکې هم چمتو کوي. په مقاله کې د سیسټمډ سره ډیمون جلا کول یا "تاسو د دې لپاره ډاکر ته اړتیا نلرئ!" دا په ځانګړي توګه پوښي چې څنګه د سیسټم چلولو ډیمونونو لپاره د سیسټم غوښتنې تور لیستونه یا سپین لیستونه اضافه کړي.

بیا به موږ وګورو چې څنګه د فلټرونو لیکلو او بارولو څرنګوالی seccomp په خلاص C کې او د کتابتون په کارولو سره libseccomp او د هر انتخاب ګټې او زیانونه څه دي، او په نهایت کې، راځئ چې وګورو چې seccomp څنګه د برنامه لخوا کارول کیږي strace.

د seccomp لپاره د فلټرونو لیکل او پورته کول

موږ دمخه پوهیږو چې څنګه د BPF برنامې لیکلو لپاره ، نو راځئ لومړی د seccomp برنامې انٹرفیس ته وګورو. تاسو کولی شئ د پروسې په کچه یو فلټر ترتیب کړئ، او د ماشوم ټولې پروسې به محدودیتونه په میراث کې وي. دا د سیسټم کال په کارولو سره ترسره کیږي seccomp(2):

seccomp(SECCOMP_SET_MODE_FILTER, flags, &filter)

چې &filter - دا یو داسې جوړښت ته اشاره ده چې دمخه موږ ته پیژندل شوی struct sock_fprog, i.e. د BPF پروګرام.

د سیکومپ پروګرامونه څنګه د ساکټ لپاره پروګرامونو څخه توپیر لري؟ لیږدول شوي شرایط. د ساکټونو په حالت کې، موږ ته د حافظې ساحه راکړل شوې وه چې پاکټ پکې شامل وو، او د سیکومپ په قضیه کې موږ ته یو جوړښت راکړل شو لکه

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

دا nr د سیسټم تلیفون شمیره ده چې پیل کیږي، arch - اوسنی جوړښت (لاندې په دې اړه نور) args - تر شپږو پورې سیسټم کال دلیلونه، او instruction_pointer د کارونکي ځای لارښوونې ته اشاره کوي چې سیسټم یې غږ کړی. په دې توګه، د بیلګې په توګه، په راجستر کې د سیسټم تلیفون شمیره پورته کول A موږ باید ووایو

ldw [0]

د seccomp پروګرامونو لپاره نورې ځانګړتیاوې شتون لري، د بیلګې په توګه، شرایط یوازې د 32-bit سیده کولو له لارې لاسرسی کیدی شي او تاسو نشئ کولی نیمه کلمه یا یو بایټ پورته کړئ - کله چې د فلټر پورته کولو هڅه کوئ ldh [0] سیسټم زنګ seccomp بیرته به راشي EINVAL. فنکشن بار شوي فلټرونه ګوري seccomp_check_filter() دانه (په زړه پورې خبره دا ده چې په اصلي ژمنې کې چې د seccomp فعالیت یې اضافه کړ ، دوی دې فنکشن ته د لارښوونې کارولو اجازه اضافه کول هیر کړل mod (د ویش پاتې برخه) او اوس د دې اضافه کولو راهیسې د seccomp BPF برنامو لپاره شتون نلري مات به شي ABI.)

اساسا ، موږ دمخه د 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 شمیرې د څلورو سیسټم تلیفونونو تور لیست چک کوي. دا سیسټم زنګونه څه دي؟ موږ په ډاډ سره نشو ویلای، ځکه چې موږ نه پوهیږو چې برنامه د کوم جوړښت لپاره لیکل شوې وه. له همدې امله، د seccomp لیکوالان وړاندیز ټول پروګرامونه د معمارۍ چک سره پیل کړئ (اوسنی جوړښت د ساحې په توګه په شرایطو کې ښودل شوی 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 په لینکس کې د پروسو چلند مطالعې لپاره یوه لازمي وسیله ده. په هرصورت، ډیری یې په اړه اوریدلي دي د فعالیت مسلې کله چې د دې اسانتیا کارول. حقیقت دا دی 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 لخوا نه ملاتړ کیږي. دوهم، هیڅ امکان نشته نه د ماشوم پروسو ته وګورئ، ځکه چې د سیکومپ فلټرونه د ماشومانو د ټولو پروسو لخوا په میراث پاتې دي پرته له دې چې دا غیر فعال کړي.

په دقیق ډول په اړه یو څه نور تفصیل 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"

د IP سرلیک 32 بټونه پورته کوي، د پیډینګ 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 بایټ کوډ د 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 د 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 په لینکس کې د ترافیک کنټرول فرعي سیسټم لپاره ، د 2013 په پای کې لینکس ته اضافه شوی او په تصور کې د پخوانیو ځای په ځای کول cls_u32.

په هرصورت، موږ به اوس کار تشریح نه کړو cls_bpf، ځکه چې د کلاسیک BPF په اړه د پوهې له نظره دا به موږ ته هیڅ ونه راکوي - موږ دمخه د ټولو فعالیت سره آشنا شوي یو. برسېره پردې، په راتلونکو مقالو کې چې د تمدید شوي BPF په اړه خبرې کوي، موږ به دا کټګوري له یو ځل څخه ډیر وګورو.

بل دلیل چې د کلاسیک BPF کارولو په اړه خبرې نه کول c cls_bpf ستونزه دا ده چې د تمدید شوي BPF په پرتله ، پدې قضیه کې د پلي کیدو ساحه په کلکه محدوده ده: کلاسیک برنامې نشي کولی د کڅوړو مینځپانګې بدل کړي او نشي کولی د تلیفونونو ترمینځ حالت خوندي کړي.

نو دا وخت دی چې کلاسیک BPF ته الوداع ووایاست او راتلونکي ته ګورو.

کلاسیک BPF ته الوداع

موږ وګورو چې څنګه د BPF ټیکنالوژي، چې د نولسمې پیړۍ په لومړیو کې رامینځته شوې، په بریالیتوب سره د څلورمې پیړۍ لپاره ژوند وکړ او تر پایه یې نوي غوښتنلیکونه وموندل. په هرصورت، د سټیک ماشینونو څخه RISC ته د لیږد په څیر، کوم چې د کلاسیک BPF پراختیا لپاره د هڅونې په توګه کار کاوه، په 32 کې د 64-bit څخه XNUMX-bit ماشینونو ته لیږد شتون درلود او کلاسیک BPF ناپاک شو. سربیره پردې ، د کلاسیک BPF وړتیاوې خورا محدود دي ، او د زاړه جوړښت سربیره - موږ د BPF برنامو ته د تلیفونونو ترمینځ د حالت خوندي کولو وړتیا نلرو ، د مستقیم کارونکي متقابل عمل امکان شتون نلري ، د متقابل عمل امکان شتون نلري. د کرنل سره، پرته له دې چې د جوړښت ساحې محدود شمیر لوستل شي sk_buff او د ساده مرستندویه کارونو په لاره اچولو سره، تاسو نشئ کولی د پاکټونو مینځپانګې بدل کړئ او دوی ته یې لارښود کړئ.

په حقیقت کې ، اوس مهال ټول هغه څه چې په لینکس کې د کلاسیک BPF پاتې کیږي د API انٹرفیس دی ، او د کرنل دننه ټول کلاسیک برنامې ، که دا ساکټ فلټرونه وي یا د سیکامپ فلټرونه ، په اوتومات ډول نوي ب formatه کې ژباړل شوي ، پراخ شوي BPF. (موږ به په دې اړه وغږیږو چې دا څنګه په راتلونکې مقاله کې پیښیږي.)

نوي جوړښت ته لیږد په 2013 کې پیل شو، کله چې الیکسي سټاروویتوف د BPF تازه سکیم وړاندیز وکړ. په 2014 کې ورته پیچ څرګندیدل پیل کړل په اصلي. تر هغه ځایه چې زه پوهیږم ، لومړنی پلان یوازې د 64-bit ماشینونو کې د ډیر اغیزمن چلولو لپاره د جوړښت او JIT کمپیلر اصلاح کول و ، مګر پرځای یې دا اصلاح کول د لینکس پراختیا کې د نوي فصل پیل په نښه کړ.

په دې لړۍ کې نورې مقالې به د نوې ټیکنالوژۍ جوړښت او غوښتنلیکونه پوښي، چې په پیل کې د داخلي 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. هوبر: د سیسټمډ سره ډیمون جلا کول یا "تاسو د دې لپاره ډاکر ته اړتیا نلرئ!"
  12. پاول چایګنن، "سټریس - سیکمپ-بی پی ایف: د هود لاندې یو نظر" https://fosdem.org/2020/schedule/event/debugging_strace_bpf/
  13. netsniff-ng: http://netsniff-ng.org/

سرچینه: www.habr.com

Add a comment