சிறியவர்களுக்கான BPF, பகுதி பூஜ்யம்: கிளாசிக் BPF

Berkeley Packet Filters (BPF) என்பது லினக்ஸ் கர்னல் தொழில்நுட்பமாகும், இது பல ஆண்டுகளாக ஆங்கில மொழி தொழில்நுட்ப வெளியீடுகளின் முதல் பக்கங்களில் உள்ளது. BPF இன் பயன்பாடு மற்றும் மேம்பாடு குறித்த அறிக்கைகளால் மாநாடுகள் நிரப்பப்பட்டுள்ளன. டேவிட் மில்லர், லினக்ஸ் நெட்வொர்க் துணை அமைப்பு பராமரிப்பாளர், லினக்ஸ் பிளம்பர்ஸ் 2018 இல் தனது பேச்சை அழைக்கிறார் "இந்த பேச்சு XDP பற்றியது அல்ல" (எக்ஸ்டிபி என்பது பிபிஎஃப்க்கான ஒரு பயன்பாட்டு வழக்கு). பிரெண்டன் கிரெக் என்ற தலைப்பில் பேச்சு கொடுக்கிறார் லினக்ஸ் BPF சூப்பர் பவர்ஸ். டோக் ஹொய்லண்ட்-ஜோர்கென்சன் சிரிக்கிறார்அந்த கர்னல் இப்போது மைக்ரோகர்னல். தாமஸ் கிராஃப் என்ற கருத்தை ஊக்குவிக்கிறார் BPF என்பது கர்னலுக்கான ஜாவாஸ்கிரிப்ட் ஆகும்.

ஹப்ரேயில் BPF பற்றி இன்னும் முறையான விளக்கம் இல்லை, எனவே தொடர் கட்டுரைகளில் தொழில்நுட்பத்தின் வரலாற்றைப் பற்றி பேச முயற்சிப்பேன், கட்டிடக்கலை மற்றும் மேம்பாட்டு கருவிகளை விவரிக்கிறேன், மேலும் BPF ஐப் பயன்படுத்துவதற்கான பயன்பாடு மற்றும் நடைமுறையின் பகுதிகளை கோடிட்டுக் காட்டுவேன். இந்த கட்டுரை, பூஜ்யம், தொடரில், கிளாசிக் BPF இன் வரலாறு மற்றும் கட்டிடக்கலையைச் சொல்கிறது, மேலும் அதன் செயல்பாட்டுக் கொள்கைகளின் ரகசியங்களையும் வெளிப்படுத்துகிறது. tcpdump, seccomp, strace, இன்னும் பற்பல.

BPF இன் வளர்ச்சி லினக்ஸ் நெட்வொர்க்கிங் சமூகத்தால் கட்டுப்படுத்தப்படுகிறது, BPF இன் முக்கிய பயன்பாடுகள் நெட்வொர்க்குகளுடன் தொடர்புடையவை, எனவே அனுமதியுடன் @யூகாரியட், நான் தொடரை "சிறியவர்களுக்கான BPF" என்று அழைத்தேன், சிறந்த தொடரின் நினைவாக "சிறியவர்களுக்கான நெட்வொர்க்குகள்".

BPF வரலாற்றில் ஒரு குறுகிய படிப்பு(c)

நவீன பிபிஎஃப் தொழில்நுட்பம் என்பது பழைய தொழில்நுட்பத்தின் மேம்படுத்தப்பட்ட மற்றும் விரிவாக்கப்பட்ட பதிப்பாகும், இது குழப்பத்தைத் தவிர்க்க இப்போது கிளாசிக் பிபிஎஃப் என்று அழைக்கப்படுகிறது. கிளாசிக் BPF அடிப்படையில் நன்கு அறியப்பட்ட பயன்பாடு உருவாக்கப்பட்டது tcpdump, பொறிமுறை seccomp, அத்துடன் குறைவாக அறியப்பட்ட தொகுதிகள் xt_bpf செய்ய iptables மற்றும் வகைப்படுத்தி cls_bpf. நவீன லினக்ஸில், கிளாசிக் பிபிஎஃப் நிரல்கள் தானாகவே புதிய வடிவத்திற்கு மொழிபெயர்க்கப்படுகின்றன, இருப்பினும், ஒரு பயனர் பார்வையில், ஏபிஐ இடத்தில் உள்ளது மற்றும் கிளாசிக் பிபிஎஃப்க்கான புதிய பயன்பாடுகள், இந்த கட்டுரையில் நாம் பார்ப்பது போல், இன்னும் கண்டறியப்படுகின்றன. இந்த காரணத்திற்காகவும், லினக்ஸில் கிளாசிக்கல் பிபிஎஃப் வளர்ச்சியின் வரலாற்றைத் தொடர்ந்து, அது எப்படி, ஏன் அதன் நவீன வடிவமாக உருவானது என்பது தெளிவாகிவிடும் என்பதால், கிளாசிக்கல் பிபிஎஃப் பற்றிய கட்டுரையுடன் தொடங்க முடிவு செய்தேன்.

கடந்த நூற்றாண்டின் எண்பதுகளின் இறுதியில், புகழ்பெற்ற லாரன்ஸ் பெர்க்லி ஆய்வகத்தின் பொறியியலாளர்கள் கடந்த நூற்றாண்டின் எண்பதுகளின் பிற்பகுதியில் நவீனமான வன்பொருளில் நெட்வொர்க் பாக்கெட்டுகளை எவ்வாறு சரியாக வடிகட்டுவது என்ற கேள்வியில் ஆர்வமாக இருந்தனர். முதலில் CSPF (CMU/Stanford Packet Filter) தொழில்நுட்பத்தில் செயல்படுத்தப்பட்ட வடிகட்டலின் அடிப்படை யோசனை, தேவையற்ற பாக்கெட்டுகளை கூடிய விரைவில் வடிகட்ட வேண்டும், அதாவது. கர்னல் இடத்தில், இது தேவையற்ற தரவை பயனர் இடத்தில் நகலெடுப்பதைத் தவிர்க்கிறது. கர்னல் இடத்தில் பயனர் குறியீட்டை இயக்குவதற்கான இயக்க நேர பாதுகாப்பை வழங்க, சாண்ட்பாக்ஸ் செய்யப்பட்ட மெய்நிகர் இயந்திரம் பயன்படுத்தப்பட்டது.

இருப்பினும், ஏற்கனவே உள்ள வடிப்பான்களுக்கான மெய்நிகர் இயந்திரங்கள் ஸ்டாக் அடிப்படையிலான இயந்திரங்களில் இயங்கும் வகையில் வடிவமைக்கப்பட்டுள்ளன, மேலும் புதிய RISC இயந்திரங்களில் திறமையாக இயங்கவில்லை. இதன் விளைவாக, பெர்க்லி லேப்ஸின் பொறியாளர்களின் முயற்சியால், ஒரு புதிய BPF (Berkeley Packet Filters) தொழில்நுட்பம் உருவாக்கப்பட்டது, இதன் மெய்நிகர் இயந்திரக் கட்டமைப்பானது Motorola 6502 செயலியை அடிப்படையாகக் கொண்டு வடிவமைக்கப்பட்டது - இது போன்ற நன்கு அறியப்பட்ட தயாரிப்புகளின் வேலை. ஆப்பிள் II அல்லது எஸ். புதிய மெய்நிகர் இயந்திரம் ஏற்கனவே உள்ள தீர்வுகளுடன் ஒப்பிடும்போது வடிகட்டி செயல்திறனைப் பல மடங்கு அதிகரித்தது.

BPF இயந்திர கட்டமைப்பு

எடுத்துக்காட்டுகளை பகுப்பாய்வு செய்வதன் மூலம் கட்டிடக்கலையை வேலை செய்யும் விதத்தில் அறிந்து கொள்வோம். இருப்பினும், தொடங்குவதற்கு, இயந்திரத்தில் இரண்டு 32-பிட் பதிவேடுகள் பயனருக்கு அணுகக்கூடிய ஒரு குவிப்பான் என்று சொல்லலாம். A மற்றும் குறியீட்டு பதிவு X, 64 பைட்டுகள் நினைவகம் (16 வார்த்தைகள்), எழுதுவதற்கும் அதைத் தொடர்ந்து படிக்கவும் கிடைக்கும், மேலும் இந்த பொருட்களுடன் பணிபுரியும் கட்டளைகளின் சிறிய அமைப்பு. நிபந்தனை வெளிப்பாடுகளை செயல்படுத்துவதற்கான தாவல் வழிமுறைகளும் நிரல்களில் கிடைத்தன, ஆனால் நிரலை சரியான நேரத்தில் முடிப்பதற்கு உத்தரவாதம் அளிக்க, தாவல்களை முன்னோக்கி மட்டுமே செய்ய முடியும், அதாவது, குறிப்பாக, சுழல்களை உருவாக்குவது தடைசெய்யப்பட்டது.

இயந்திரத்தைத் தொடங்குவதற்கான பொதுவான திட்டம் பின்வருமாறு. பயனர் BPF கட்டமைப்பிற்கான ஒரு நிரலை உருவாக்கி, பயன்படுத்துகிறார் சில கர்னல் மெக்கானிசம் (கணினி அழைப்பு போன்றவை), நிரலை ஏற்றி இணைக்கிறது சிலவற்றிற்கு கர்னலில் உள்ள நிகழ்வு ஜெனரேட்டருக்கு (உதாரணமாக, ஒரு நிகழ்வு என்பது பிணைய அட்டையில் அடுத்த பாக்கெட்டின் வருகை). ஒரு நிகழ்வு நிகழும்போது, ​​கர்னல் நிரலை இயக்குகிறது (எடுத்துக்காட்டாக, ஒரு மொழிபெயர்ப்பாளரில்), மற்றும் இயந்திர நினைவகம் சிலவற்றிற்கு கர்னல் நினைவகப் பகுதி (உதாரணமாக, உள்வரும் பாக்கெட்டின் தரவு).

எடுத்துக்காட்டுகளைப் பார்க்கத் தொடங்க மேலே உள்ளவை போதுமானதாக இருக்கும்: தேவையான அமைப்பு மற்றும் கட்டளை வடிவமைப்பைப் பற்றி அறிந்து கொள்வோம். நீங்கள் உடனடியாக ஒரு மெய்நிகர் இயந்திரத்தின் கட்டளை அமைப்பைப் படித்து அதன் அனைத்து திறன்களையும் பற்றி அறிய விரும்பினால், அசல் கட்டுரையைப் படிக்கலாம். BSD பாக்கெட் வடிகட்டி மற்றும்/அல்லது கோப்பின் முதல் பாதி ஆவணப்படுத்தல்/நெட்வொர்க்கிங்/filter.txt கர்னல் ஆவணத்திலிருந்து. கூடுதலாக, நீங்கள் விளக்கக்காட்சியைப் படிக்கலாம் libpcapபாக்கெட் கேப்சருக்கான கட்டிடக்கலை மற்றும் மேம்படுத்தல் முறை, இதில் BPF இன் ஆசிரியர்களில் ஒருவரான McCanne, படைப்பின் வரலாற்றைப் பற்றி பேசுகிறார் 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 (தொகுப்பு வகை) c 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 மூன்று மிக முக்கியமான பிட்கள் அழிக்கப்பட்டன. மூன்று பிட்களில் இரண்டு, பாக்கெட் ஒரு துண்டு துண்டான ஐபி பாக்கெட்டின் ஒரு பகுதியா, அப்படியானால், அது கடைசி துண்டமா என்பதை நமக்குத் தெரிவிக்கிறது. மூன்றாவது பிட் ஒதுக்கப்பட்டுள்ளது மற்றும் பூஜ்ஜியமாக இருக்க வேண்டும். முழுமையடையாத அல்லது உடைந்த பாக்கெட்டுகளை நாங்கள் சரிபார்க்க விரும்பவில்லை, எனவே மூன்று பிட்களையும் சரிபார்க்கிறோம்.

இந்த பட்டியலில் வரி 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 பைட்டுகள் ஈதர்நெட் தலைப்பால் ஆக்கிரமிக்கப்பட்டுள்ளன என்பதை நினைவில் கொள்க, மற்றும் 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 லினக்ஸில் செயல்படுத்தப்பட்டது, நாங்கள் பயன்படுத்துகிறோம் 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 வடிகட்டியை ஏற்றி இணைக்கிறோம். இது எங்களின் வடிகட்டி.

கிளாசிக் பிபிஎஃப் இல், வடிகட்டியை ஏற்றுவதும் இணைப்பதும் எப்போதும் அணுச் செயல்பாடாக நிகழ்கிறது, மேலும் பிபிஎஃப் இன் புதிய பதிப்பில், நிரலை ஏற்றுவது மற்றும் நிகழ்வு ஜெனரேட்டருடன் பிணைப்பது ஆகியவை சரியான நேரத்தில் பிரிக்கப்படுகின்றன என்பது கவனிக்கத்தக்கது.

மறைக்கப்பட்ட உண்மை

வெளியீட்டின் சற்று முழுமையான பதிப்பு இதுபோல் தெரிகிறது:

$ 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 ஐப் பயன்படுத்தி Linux இல் தொகுப்புகளை வடிகட்ட, நீங்கள் ஒரு கட்டமைப்பின் வடிவத்தில் ஒரு வடிகட்டியை வைத்திருக்க வேண்டும் struct sock_fprog மற்றும் ஒரு திறந்த சாக்கெட், அதன் பிறகு வடிகட்டியை கணினி அழைப்பைப் பயன்படுத்தி சாக்கெட்டுடன் இணைக்க முடியும் setsockopt.

சுவாரஸ்யமாக, வடிகட்டியை பச்சையாக இல்லாமல் எந்த சாக்கெட்டிலும் இணைக்க முடியும். இங்கே உதாரணமாக உள்வரும் அனைத்து UDP டேட்டாகிராம்களிலிருந்தும் முதல் இரண்டு பைட்டுகளைத் தவிர மற்ற அனைத்தையும் துண்டிக்கும் நிரல். (கட்டுரையை ஒழுங்கீனம் செய்யக்கூடாது என்பதற்காக குறியீட்டில் கருத்துகளைச் சேர்த்துள்ளேன்.)

பயன்பாடு பற்றிய கூடுதல் விவரங்கள் setsockopt வடிப்பான்களை இணைக்க, பார்க்கவும் சாக்கெட்(7), ஆனால் உங்கள் சொந்த வடிப்பான்களை எழுதுவது பற்றி struct sock_fprog உதவி இல்லாமல் tcpdump பிரிவில் பேசுவோம் எங்கள் சொந்த கைகளால் BPF நிரலாக்கம்.

கிளாசிக் BPF மற்றும் XNUMX ஆம் நூற்றாண்டு

பிபிஎஃப் 1997 இல் லினக்ஸில் சேர்க்கப்பட்டது மற்றும் நீண்ட காலமாக ஒரு பணியாளராக உள்ளது libpcap சிறப்பு மாற்றங்கள் இல்லாமல் (லினக்ஸ்-குறிப்பிட்ட மாற்றங்கள், நிச்சயமாக, அது இருந்தது, ஆனால் அவை உலகளாவிய படத்தை மாற்றவில்லை). 2011 இல் எரிக் டுமாசெட் முன்மொழிந்தபோது BPF உருவாகும் என்பதற்கான முதல் தீவிர அறிகுறிகள் தோன்றின. இணைப்பு, இது ஜஸ்ட் இன் டைம் கம்பைலரை கர்னலில் சேர்க்கிறது - பிபிஎஃப் பைட்கோடை நேட்டிவ் ஆக மாற்றுவதற்கான மொழிபெயர்ப்பாளர் x86_64 குறியீடு.

மாற்றங்களின் சங்கிலியில் JIT கம்பைலர் முதன்மையானது: 2012 இல் தோன்றினார் வடிப்பான்களை எழுதும் திறன் seccomp, 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,

சி புரோகிராமர்களின் வசதிக்காக, வேறுபட்ட வெளியீட்டு வடிவத்தைப் பயன்படுத்தலாம்:

$ 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, லினக்ஸ் மற்றும் 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. தொகுப்பில் விரிவான ஆவணங்கள் உள்ளன, கட்டுரையின் முடிவில் உள்ள இணைப்புகளையும் பார்க்கவும்.

seccomp

எனவே, தன்னிச்சையான சிக்கலான BPF நிரல்களை எவ்வாறு எழுதுவது என்பதை நாங்கள் ஏற்கனவே அறிந்துள்ளோம், மேலும் புதிய எடுத்துக்காட்டுகளைப் பார்க்கத் தயாராக உள்ளோம், இதில் முதலாவது seccomp தொழில்நுட்பம், இது BPF வடிப்பான்களைப் பயன்படுத்தி, கணினி அழைப்பு வாதங்களின் தொகுப்பு மற்றும் தொகுப்பை நிர்வகிக்க அனுமதிக்கிறது. கொடுக்கப்பட்ட செயல்முறை மற்றும் அதன் சந்ததியினர்.

seccomp இன் முதல் பதிப்பு 2005 இல் கர்னலில் சேர்க்கப்பட்டது மற்றும் அது மிகவும் பிரபலமாகவில்லை, ஏனெனில் இது ஒரே ஒரு விருப்பத்தை மட்டுமே வழங்கியது - ஒரு செயல்முறைக்கு கிடைக்கக்கூடிய கணினி அழைப்புகளின் தொகுப்பை பின்வருவனவற்றிற்கு மட்டுப்படுத்த: read, write, exit и sigreturn, மற்றும் விதிகளை மீறும் செயல்முறை பயன்படுத்தி கொல்லப்பட்டது SIGKILL. இருப்பினும், 2012 இல், seccomp BPF வடிப்பான்களைப் பயன்படுத்தும் திறனைச் சேர்த்தது, இது அனுமதிக்கப்பட்ட கணினி அழைப்புகளின் தொகுப்பை வரையறுக்கவும், அவற்றின் வாதங்களைச் சரிபார்க்கவும் உங்களை அனுமதிக்கிறது. (சுவாரஸ்யமாக, இந்த செயல்பாட்டின் முதல் பயனர்களில் Chrome ஆனது, மேலும் Chrome மக்கள் தற்போது BPF இன் புதிய பதிப்பின் அடிப்படையில் KRSI பொறிமுறையை உருவாக்கி லினக்ஸ் பாதுகாப்பு தொகுதிகளை தனிப்பயனாக்க அனுமதிக்கின்றனர்.) கூடுதல் ஆவணங்களுக்கான இணைப்புகளை இறுதியில் காணலாம். கட்டுரையின்.

seccomp ஐப் பயன்படுத்துவது பற்றி ஹப்பில் ஏற்கனவே கட்டுரைகள் உள்ளன என்பதை நினைவில் கொள்ளவும், பின்வரும் துணைப்பிரிவுகளைப் படிக்கும் முன் (அல்லது அதற்குப் பதிலாக) யாராவது அவற்றைப் படிக்க விரும்பலாம். கட்டுரையில் கொள்கலன்கள் மற்றும் பாதுகாப்பு: seccomp 2007 பதிப்பு மற்றும் BPF ஐப் பயன்படுத்தி seccomp ஐப் பயன்படுத்துவதற்கான எடுத்துக்காட்டுகளை வழங்குகிறது (வடிப்பான்கள் libseccomp ஐப் பயன்படுத்தி உருவாக்கப்படுகின்றன), டோக்கருடன் seccomp இன் இணைப்பைப் பற்றி பேசுகிறது, மேலும் பல பயனுள்ள இணைப்புகளையும் வழங்குகிறது. கட்டுரையில் systemd அல்லது "இதற்கு டோக்கர் தேவையில்லை!" என டீமான்களை தனிமைப்படுத்துதல் இது குறிப்பாக, systemd இயங்கும் டீமான்களுக்கான கணினி அழைப்புகளின் தடுப்புப்பட்டியல்கள் அல்லது அனுமதிப்பட்டியல்களை எவ்வாறு சேர்ப்பது என்பதை உள்ளடக்கியது.

அடுத்து எப்படி ஃபில்டர்களை எழுதுவது மற்றும் ஏற்றுவது என்று பார்ப்போம் 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 ஆகிய நான்கு சிஸ்டம் அழைப்புகளின் தடுப்புப்பட்டியலைச் சரிபார்க்கிறது. இந்த சிஸ்டம் அழைப்புகள் என்ன? நிரல் எந்த கட்டிடக்கலைக்காக எழுதப்பட்டது என்பது எங்களுக்குத் தெரியாததால், உறுதியாகச் சொல்ல முடியாது. எனவே, seccomp இன் ஆசிரியர்கள் சலுகை அனைத்து நிரல்களையும் ஒரு கட்டிடக்கலை சரிபார்ப்புடன் தொடங்கவும் (தற்போதைய கட்டிடக்கலை சூழலில் ஒரு புலமாக குறிக்கப்படுகிறது arch அமைப்பு struct seccomp_data) கட்டிடக்கலை சரிபார்க்கப்பட்டால், உதாரணத்தின் ஆரம்பம் இப்படி இருக்கும்:

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

பின்னர் எங்கள் கணினி அழைப்பு எண்கள் குறிப்பிட்ட மதிப்புகளைப் பெறும்.

seccomp பயன்பாட்டிற்காக வடிகட்டிகளை எழுதி ஏற்றுகிறோம் libseccomp

வடிப்பான்களை நேட்டிவ் கோட் அல்லது பிபிஎஃப் அசெம்பிளியில் எழுதுவது, முடிவின் மீது முழுக் கட்டுப்பாட்டைப் பெற உங்களை அனுமதிக்கிறது, ஆனால் அதே நேரத்தில், போர்ட்டபிள் மற்றும்/அல்லது படிக்கக்கூடிய குறியீட்டைக் கொண்டிருப்பது சில சமயங்களில் விரும்பத்தக்கது. இதற்கு நூலகம் நமக்கு உதவும் 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 பயன்படுத்தி செயல்படுத்தப்பட்டது 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 இருந்து காணலாம் சமீபத்திய அறிக்கை. எங்களைப் பொறுத்தவரை, மிகவும் சுவாரஸ்யமான உண்மை என்னவென்றால், seccomp ஆல் குறிப்பிடப்படும் கிளாசிக் BPF இன்றும் பயன்படுத்தப்படுகிறது.

xt_bpf

இப்போது நெட்வொர்க்குகளின் உலகத்திற்கு திரும்புவோம்.

பின்னணி: நீண்ட காலத்திற்கு முன்பு, 2007 இல், மையமானது சேர்க்கப்பட்டது தொகுதி xt_u32 நெட்ஃபில்டருக்கு. இது இன்னும் பழமையான போக்குவரத்து வகைப்படுத்தியுடன் ஒப்புமை மூலம் எழுதப்பட்டது 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 ஒரு பெயருக்கான DNS வினவலுடன் பொருந்தக்கூடிய BPF நிரலை நீங்கள் உருவாக்கலாம் 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-பிட்டிலிருந்து XNUMX-பிட் இயந்திரங்களுக்கு மாற்றம் ஏற்பட்டது மற்றும் கிளாசிக் BPF வழக்கற்றுப் போகத் தொடங்கியது. கூடுதலாக, கிளாசிக் BPF இன் திறன்கள் மிகவும் குறைவாகவே உள்ளன, மேலும் காலாவதியான கட்டிடக்கலைக்கு கூடுதலாக - BPF நிரல்களுக்கான அழைப்புகளுக்கு இடையில் நிலையைச் சேமிக்கும் திறன் எங்களிடம் இல்லை, நேரடி பயனர் தொடர்புக்கான சாத்தியம் இல்லை, தொடர்புகொள்வதற்கான சாத்தியக்கூறுகள் இல்லை. கர்னலுடன், குறிப்பிட்ட எண்ணிக்கையிலான கட்டமைப்பு புலங்களைப் படிப்பதைத் தவிர sk_buff மற்றும் எளிமையான உதவி செயல்பாடுகளைத் தொடங்கினால், நீங்கள் பாக்கெட்டுகளின் உள்ளடக்கங்களை மாற்ற முடியாது மற்றும் அவற்றை திருப்பிவிட முடியாது.

உண்மையில், தற்போது லினக்ஸில் கிளாசிக் பிபிஎஃப் எஞ்சியிருப்பது ஏபிஐ இடைமுகம் ஆகும், மேலும் கெர்னலில் உள்ள அனைத்து கிளாசிக் புரோகிராம்களும், சாக்கெட் வடிப்பான்கள் அல்லது செக்காம்ப் வடிப்பான்களாக இருந்தாலும், தானாக நீட்டிக்கப்பட்ட பிபிஎஃப் வடிவத்தில் புதிய வடிவத்தில் மொழிபெயர்க்கப்படுகின்றன. (இது எப்படி நடக்கிறது என்பதைப் பற்றி அடுத்த கட்டுரையில் பேசுவோம்.)

ஒரு புதிய கட்டிடக்கலைக்கான மாற்றம் 2013 இல் தொடங்கியது, அலெக்ஸி ஸ்டாரோவோய்டோவ் BPF புதுப்பிப்பு திட்டத்தை முன்மொழிந்தார். 2014 இல் தொடர்புடைய இணைப்புகள் தோன்ற ஆரம்பித்தது மையத்தில். நான் புரிந்து கொண்ட வரையில், ஆரம்பத் திட்டமானது 64-பிட் கணினிகளில் மிகவும் திறமையாக இயங்கும் வகையில் கட்டிடக்கலை மற்றும் JIT கம்பைலரை மேம்படுத்துவது மட்டுமே ஆகும், ஆனால் அதற்கு பதிலாக இந்த மேம்படுத்தல்கள் லினக்ஸ் வளர்ச்சியில் ஒரு புதிய அத்தியாயத்தின் தொடக்கத்தைக் குறித்தது.

இந்தத் தொடரின் மேலும் கட்டுரைகள் புதிய தொழில்நுட்பத்தின் கட்டமைப்பு மற்றும் பயன்பாடுகளை உள்ளடக்கும், ஆரம்பத்தில் உள் BPF, பின்னர் நீட்டிக்கப்பட்ட BPF, இப்போது வெறுமனே BPF என அறியப்படுகிறது.

குறிப்புகள்

  1. ஸ்டீவன் மெக்கேன் மற்றும் வான் ஜேக்கப்சன், "தி பிஎஸ்டி பாக்கெட் ஃபில்டர்: எ நியூ ஆர்கிடெக்சர் ஃபார் யூசர்-லெவல் பாக்கெட் கேப்சர்", 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. ஒரு seccomp கண்ணோட்டம்: 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 மூலம் தனிமைப்படுத்துதல் அல்லது "இதற்கு உங்களுக்கு டோக்கர் தேவையில்லை!"
  12. பால் சைக்னான், "ஸ்ட்ரேஸ் --செக்காம்ப்-பிபிஎஃப்: ஹூட் கீழ் ஒரு பார்வை", https://fosdem.org/2020/schedule/event/debugging_strace_bpf/
  13. netsniff-ng: http://netsniff-ng.org/

ஆதாரம்: www.habr.com

கருத்தைச் சேர்