Încorporați într-o stivă TCP / IP în sistemul de operare GNU / Linux
Studiul protocoalelor este o activitate destul de interesantă. Totuși, mulți cercetători sunt implicați în evaluarea și verificarea lor în diferite situații. Personal, m-am confruntat cu necesitatea de a studia protocolul în primul an de lucru la IMM UrB RAS [1]. Indiferent de cum ar părea banal, a fost un protocol TCP. Motivul pentru care am început să fac acest lucru a fost următorul - era necesar să înțelegem rețeaua într-unul din clustele de calcul. Când transmiteți date prin TCP peste 2 100 Mbps. plăci de rețea în același timp (așa-numitul canal de legătură sau engleză. lipire) observată rata de creștere sa dublat, iar în același timp, de la carduri de viteză gigabit nu numai că nu a crescut, dar chiar a scăzut la 600 Mbps. în câteva secunde. Sniffer nu a arătat nimic special. Și, în general, snifferul nu poate oferi întotdeauna informații exhaustive despre ceea ce se întâmplă în rețea. Folosindu-l, puteți afla ce sa întâmplat în rețea și pe această bază încercați să înțelegeți ce sa întâmplat cu protocolul. Dar pentru aceasta, cel puțin este necesar să ne imaginăm cu exactitate implementarea acestui protocol în acest sistem de operare. Sunt de acord, acest lucru nu este ușor. Și este într-adevăr absolut necesar, când OS în sine și toate protocoalele sunt chiar în fața noastră? În plus, când este un sistem open source, unde nu există nimic care să fie ascuns de ochii noștri.
Datorită faptului că schimbările în Linux kernel-ul sistemului de operare se fac destul de des, este dificil de a scrie un cod care ar lucra pe mai multe nuclee dintr-o dată. Din acest motiv, acest articol descrie un exemplu de încorporare a unui teanc în kernelul TCP în versiunea 2.6.12 a kernel-ului Linux. De asemenea, în aplicație, puteți găsi codul pentru versiunea kernel 2.6.18 (datorită lui VenROCK, forțat!).
Subsistemul de rețea al OS GNU / Linux
Odată ce sistemul de operare trebuie să funcționeze cu un pachet de rețea, acesta este sk_buff. Acesta este creat în momentul în care sistemul a primit pachetul din rețea sau când trebuie să creeze un pachet nou pentru trimitere. Din acest motiv, în stivă de rețea, aproape fiecare funcție primește această structură ca parametru. Scopul său principal este de a oferi o modalitate simplă și eficientă de a lucra cu pachetul pe toate straturile de rețea ale stivei de rețea (a se vedea Figura 1). Structura sk_buff este o structură de control cu un bloc de memorie atașat în care pachetul este localizat [2]. Astfel, schimbând variabilele din structură, schimbăm conținutul pachetului sau informațiile despre serviciu.
Fig. 1. structura sk_buff
Partea principală a acestei structuri este prezentată mai jos.
O descriere mai detaliată poate fi găsită în codul sursă al kernel-ului Linux: include / linux / skbuff.h.
Descrierea sa completă poate fi găsită în include / net / sock.h.
Având aceste două structuri (struct sk_buff și struct sock) la dispoziția dvs., puteți să primiți și să trimiteți pachete, să furnizați informații din interfața de rețea aplicației de utilizator și invers. Dar structura ciorapi descrie doar lucruri comune. De exemplu, nu conține numărul secvenței așteptate a segmentului TCP și multe alte lucruri utile. În acest scop, alte structuri servesc.
Fiecare protocol are o structură proprie pentru stocarea informațiilor de care are nevoie. De exemplu, pentru TCP, această structură se numește tcp_sock. pentru UDP - udp_sock. continuați singuri :). Toate acestea moștenesc structura șosetei. deși nu întotdeauna direct, ca în cazul tcp_sock (a se vedea figura 2). Toate distracțiile legate de protocolul pot fi găsite în aceste structuri - starea, timpul de expirare, numărul de ordine al pachetului așteptat și multe alte informații specifice. Astfel, cel mai bun mod de a afla ce se întâmplă cu o mașină de protocol TCP este de a citi datele din structura tcp_sock.
Fig. 2. Moșteniți structura ciorapi
Accesați structura tcp_sock
Și apoi se extrage soclul în sine:
Funcția care calculează hash-ul se numește tcp_hashfn. din moment ce nucleu versiunea 2.6.18 a devenit cunoscut inet_ehashfn (), și a fost mutat la fișierul antet, astfel că acum nu este nevoie să-l descrie în propriul cod. Dar scriem codul sub 2.6.12, deci va trebui să ne uităm unde și cum este descrisă această funcție. Codul sursă al acestuia poate fi privit și în net / ipv4 / tcp_ipv4.c.
Aici este necesar pentru a face un punct important - portul local este transferat la forma normală (LittleEndian), și portul de destinație pentru octet de rețea (BigEndian), adică htons (dest) trebuie să fie executat. După extragerea soclului, accesul la structura tcp_sock este foarte simplu:
Ei bine, atunci ce dorește inima ta.
remarcă
Pe lângă diferențele din ramura însăși 2.6. există mai multe diferențe la conectarea la stackul TCP în 2.4. Dar întreaga diferență se află într-un alt nume pentru structuri și o modalitate ușor diferită de extragere a soclului. Principiul rămâne același.