Differences

This shows you the differences between two versions of the page.

Link to this comparison view

so2:laboratoare:lab11 [2013/05/08 10:43]
razvan.deaconescu [Linux]
so2:laboratoare:lab11 [2017/05/07 19:19] (current)
octavian.purdila update lxr links to use 4.9
Line 1: Line 1:
-====== Laborator 11 - Networking ​======+====== Laborator 11 - Maparea memoriei ​======
  
 ===== Obiectivele laboratorului ===== ===== Obiectivele laboratorului =====
  
-  * Înțelegerea arhitecturii subsistemului ​de networking la nivelul nucleelor Linux și Windows +  *familiarizarea cu mecanismele de mapare a spațiilor de adresă 
-  * Deprinderea unor abilități practice ​de gestiune a pachetelor IP în cadrul unui filtru de pachete/​firewall +  *prezentarea structurilor cele mai importante din Linux, legate ​de memory management 
-  * Familiarizarea cu modul de utilizare al sockeților la nivelul nucleului Linux+
 ===== Cuvinte cheie ===== ===== Cuvinte cheie =====
  
-  *stiva TCP/IP +  *spațiu de adresă 
-  *protocol +  *mmap 
-  *adresă ​IP +  *''​struct page''​ 
-  *port +  *''​struct vm_area_struct''​ 
-  *socket, BSD socket, INET socket +  *''​struct ​vm_struct''​ 
-  *PF_INET, AF_INET +  *''​remap_pfn_range''​ 
-  *SOCK_STREAM,​ SOCK_DGRAM +  *SetPageReserved/ClearPageReserved 
-  *IPPROTO_TCP,​ IPPROTO_UDP +  ​
-  *interfața loopback +
-  *bind, connect, listen, accept +
-  *send, sendto, recv, recvfrom +
-  *struct socket, struct sock, struct ​sk_buff +
-  *htons, htonl, ntohs, ntohl +
-  *NPI, TDI, NDIS, WSK +
-  *NDIS Miniport/Protocol/​Intermediate Drivers +
-  ​*Filter-Hook/​Firewall-Hook Drivers +
-  *RtlUshortByteSwap,​ RtlUlongByteSwap+
 ===== Materiale ajutătoare ===== ===== Materiale ajutătoare =====
  
Line 30: Line 21:
   *[[http://​elf.cs.pub.ro/​so2/​res/​extra/​so2_reference.pdf|SO2 Reference Card]]   *[[http://​elf.cs.pub.ro/​so2/​res/​extra/​so2_reference.pdf|SO2 Reference Card]]
  
-===== Noțiuni teoretice ​=====+===== Maparea memoriei în Linux =====
  
-Dezvoltarea Internet-ului a dus la creșterea exponențială a aplicațiilor de rețea și, drept  consecință, la creșterea cerințelor de viteza și productivitate a subsistemului de rețea (networking) al unui sistem ​de operare. Subsistemul de networking nu este o componentă esențială a nucleului unui sistem de operare (kernel-ul de Linux poate fi compilat fără suport de rețea)Este, însă, destul de puțin probabil pentru un sistem de calcul ​(sau chiar un dispozitiv embeddedsă conțină un sistem de operare fără suport de rețea, datorită nevoii de conectivitateAtât sistemele Linux (Unix), cât și Windows folosesc [[http://​en.wikipedia.org/​wiki/​TCP/​IP_model|stiva TCP/IP]]. Nucleul acestora va conține implementate protocoalele pâna la nivelul transport inclusiv, urmând ca protocoalele de nivel aplicație să fie implementate ​în user-space ​(HTTP, FTP, SSH, etc.).+În kernel-ul Linux există posibilitatea mapării unui spaţiu ​de adresă kernel ​într-un spaţiu ​de adresă utilizatorÎn acest fel se elimină overhead-ul datorat copierii informaţiei din user-space în kernel-space ​(şi invers). Acest lucru poate fi realizat prin intermediul unui device driver şi a interfeţei dispozitiv ​(''/​dev''​a acestuia ​în user-space.
  
-==== Networking în user-space ​====+Această facilitate poate fi folosită prin completarea operaţiei [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​fs.h#​L1708|mmap]] din structura [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​fs.h#​L1696|struct file_operations]] asociată dispozitivului şi utilizând apelul ''​mmap''​ din user-space.
  
-În user-space abstracția comunicației în rețea este socket-ul. Socket-ul abstractizează un canal de comunicație și este interfața de interacțiune ​cu stiva TCP/IP implementată în kernel. Unui socket IP i se asociază o adresă IP, protocolul de nivel transport utilizat (TCP, UDP etc) și un port. Apelurile uzuale pe un socket sunt apelul de creare (''​socket''​),​ de inițializare (''​bind''​),​ de conectare (''​connect''​),​ de așteptare de conexiuni (''​listen'',​ ''​accept''​) și de închidere (''​close''​).+==== Structuri ​de lucru cu memoria ====
  
-Comunicația în rețea se realizează prin intermediul apelurilor ''​read/​write''​ sau ''​recv/​send''​ pentru socket-i TCPrespectiv ''​recvfrom/​sendto''​ pentru socket-i UDP. Operațiile ​de transmitere și recepție sunt transparente aplicației,​ lăsând la latitudinea nucleului încapsularea și transmiterea acestora în rețea. Este, însă, posibilă implementarea stivei TCP/IP în user-space folosind socket-i raw (opțiunea ''​PF_PACKET''​ la crearea unui socket), sau implementarea unui protocol ​de nivel aplicație ​în kernel ​([[http://​en.wikipedia.org/​wiki/​TUX_web_server|TUX web server]]).+Înainte de a discuta despre mecanismul de memory-mapping peste un dispozitivvom prezenta câteva din structurile ​de bază legate ​de subsistemul de management al memoriei ​în kernel-ul Linux.
  
-Pentru mai multe detalii despre programarea în user-space folosind socket-iconsultați ​[[http://www.beej.us/guide/bgnet/output/html/multipage/|Beej's Guide to Network Programming Using Internet Sockets]] pentru Linux și [[http://www.sockets.com/winsock.htm|Windows Sockets]] pentru Windows.+Cateva din structurile importante sunt: [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​mm_types.h#​L45|struct page]], [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#​L300|struct vm_area_struct]] şi [[http://elixir.free-electrons.com/linux/​v4.9/​source/​include/​linux/​mm_types.h#L396|struct mm_struct]].
  
-===== Linux networking =====+==== Structura ''​page'' ​====
  
-Kernel-ul Linux oferă trei structuri fundamentale pentru lucrul cu pachetele de rețea: ​[[http://lxr.linux.no/#linux+v2.6.35/include/​linux/​net.h#​L136|struct socket]], [[http://lxr.linux.no/#linux+v2.6.35/​include/​net/sock.h#L155|struct ​sock]] și [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​skbuff.h#​L257|struct ​sk_buff]].+Structura ​[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L45|struct ​page]] este utilizată pentru a încorpora informaţii despre toate paginile fizice din sistemKernel-ul deţine o structură ''​struct ​page''​ pentru toate paginile din sistem.
  
-Primele două reprezintă abstracții ale unui socket+Există numeroase funcţii care interacţionează cu această structură
-  *[[http://lxr.linux.no/#linux+v2.6.35/include/linux/net.h#L136|struct socket]] este o abstracție foarte aproape de user-space, adică de [[http://en.wikipedia.org/wiki/Berkeley_sockets|socket-ii BSD]] folosiți ​pentru ​programarea aplicațiilor ​de rețea. +  *[[http://elixir.free-electrons.com/linux/v4.9/​source/​arch/​x86/include/asm/page.h#L68|virt_to_page]] întoarce pagina asociată unei adrese virtuale; 
-  *[[http://lxr.linux.no/#linux+v2.6.35/include/net/sock.h#L155|struct sock]] sau //INET socket// în terminologia Linux este reprezentarea la nivel rețea ​unui socket. +  *[[http://elixir.free-electrons.com/linux/v4.9/​source/​include/​asm-generic/​memory_model.h#​L81|pfn_to_page]] întoarce pagina asociată ​pentru ​un număr ​de pagină (''​page frame number''​);​ 
-Cele doua structuri sunt corelate: ''​struct socket''​ conține un câmp de INET socket, iar ''​struct sock''​ are un BSD socket care îl deține.+  *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm.h#L1013|page_address]] întoarce adresa virtuală ​paginii transmise ca parametru.
  
-Structura [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​skbuff.h#​L257|struct sk_buff]] este reprezentarea unui pachet de rețea și a stării acestuia. O astfel de structură este creată la sosirea unui pachet în kernel, fie din user-space, fie de la placa de rețea. +==== Structura ​''​vm_area_struct'' ​====
-==== Structura ​socket ​====+
  
-Structura [[http://lxr.linux.no/#linux+v2.6.35/​include/​linux/​net.h#L136|struct ​socket]] este reprezentarea în kernel a unui socket BSD, operațiile care pot fi executate asupra acestuia fiind similare cu cele expuse ​de kernel aplicațiilor (prin apeluri de sistem). Operațiile comune de lucru cu socket-ii (creare, inițializare/​bind,​ închidere, etc.), rezultă în apeluri ​de sistem specifice; acestea operează asupra unei structuri ​de tipul ''​struct socket''​.+Structura [[http://elixir.free-electrons.com/linux/v4.9/source/​include/​linux/​mm_types.h#L300|struct ​vm_area_struct]] deţine informaţii despre o zonă de memorie virtuală contiguă. Zonele ​de memorie ale unui proces pot fi vizualizate inspectând ​''​procfs''​:
  
-Operațiile asupra [[http://lxr.linux.no/#​linux+v2.6.35/​include/​linux/​net.h#​L136|struct socket]] sunt descrise în [[http://lxr.linux.no/​linux+v2.6.35/​net/​socket.c|net/​socket.c]] și sunt independente de tipul de protocoale de mai jos. Structura ''​struct socket''​ este, astfel, o interfață generică peste implementări particulare de operații de rețea. De obicei, numele acestor operații încep cu șirul ''​sock_''​. +<code bash> 
- +$ cat /proc/1/maps 
-=== Operații asupra structurii socket === +08048000-0804f000 r-xp 00000000 03:01 401624 ​    /sbin/init 
- +0804f000-08050000 rw-p 00007000 03:01 401624 ​    /sbin/init 
-Operații asupra unui socket sunt: +08050000-08071000 rw-p 08050000 00:00 0 
- +40000000-40016000 r-xp 00000000 03:01 369654 ​    /lib/ld-2.3.2.so 
-== Crearea == +40016000-40017000 rw-p 00015000 03:01 369654 ​    /lib/ld-2.3.2.so 
- +40017000-40018000 rw-p 40017000 00:00 0 
-Crearea este asemănătoare apelului ''​socket''​ din user-space, dar socket-ul creat [[http://lxr.linux.no/#​linux+v2.6.35/​include/​linux/​net.h#​L136|struct socket]], va fi întors în parametrul ''​res'':​ +4001d000-40147000 r-xp 00000000 03:01 371432 ​    /lib/tls/libc-2.3.2.so 
-  ​*''​int ''​[[http://​lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L1264|sock_create]]''​(int family, int type, int protocol, struct socket %%**%%res)''​ +40147000-40150000 rw-p 00129000 03:01 371432 ​    /lib/tls/libc-2.3.2.so 
-    * funcție apelată pentru crearea unui socket în urma unui apel de sistem ''​socket'';​ +40150000-40153000 rw-p 40150000 00:00 0 
-  *''​int ''​[[http://lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L1269|sock_create_kern]]''​(int family, int type, int protocol, struct socket %%**%%res)''​ +bffff000-c0000000 rw-p bffff000 00:00 0 
-    * funcție apelată pentru crearea unui socket în kernel; +ffffe000-fffff000 ---p 00000000 00:00 0
-  *''​int ''​[[http://lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L1022|sock_create_lite]]''​(int family, int type, int protocol, struct socket %%**%%res)''​ +
-    * funcție '​lite'​ cu eliminarea verificării parametrilor. +
- +
-Parametrii acestor apeluri sunt următorii+
-  ​*''​family''​ reprezintă familia protocoalelor utilizate în transferul informației;​ de obicei, acestea încep cu șirul ''​PF_''​ (//Protocol Family//); constantele care reprezintă familia de protocoale utilizate se găsesc în [[http://lxr.linux.no/linux+v2.6.35/​include/​linux/​socket.h|linux/​socket.h]],​ dintre care cea mai utilizată este ''​PF_INET'',​ pentru protocoalele TCP/IP+
-  ​*''​type''​ reprezintă tipul de socket; constantele utilizate pentru acest parametru se găsesc în [[http://lxr.linux.no/linux+v2.6.35/​include/​linux/​net.h|linux/​net.h]],​ dintre care cele mai utilizate sunt ''​SOCK_STREAM''​ pentru o comunicație bazată pe conexiune între sursă și destinație și ''​SOCK_DGRAM''​ pentru o comunicație fără conexiune+
-  ​*''​protocol''​ reprezintă protocolul utilizat și este în strânsă legătură cu parametrul type; constatele utilizate pentru acest parametru se găsesc în [[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​in.h|linux/​in.h]],​ dintre care cele mai folosite sunt ''​IPPROTO_TCP''​ pentru TCP și ''​IPPROTO_UDP''​ pentru UDP. +
- +
-Pentru crearea unui socket TCP în kernel se va apela: +
-<code c> +
-struct socket *sock; +
-int err; +
-err = sock_create_kern(PF_INET,​ SOCK_STREAM,​ IPPROTO_TCP,​ &​sock);​ +
-if(err < 0) { +
-    /* handle error */ +
-}+
 </​code>​ </​code>​
  
-iar pentru crearea unui socket UDP: +O zonă de memorie este caracterizată printr-o adresă de startadresă de stoplungimepermisiuni. ​
-<code c> +
-struct socket *sock; +
-int err; +
-err = sock_create_kern(PF_INETSOCK_DGRAMIPPROTO_UDP&​sock);​ +
-if(err < 0) { +
-    /* error */ +
-+
-</​code>​+
  
-Un exemplu de utilizare poate fi urmărit în codul handler-ului pentru ​apelul ​de sistem ​[[http://lxr.linux.no/#linux+v2.6.35/net/socket.c#L1274|sys_socket]]+O structură ''​vm_area_struct''​ este creată la fiecare apel ''​mmap''​ din user-space. Un driver care are suport ​pentru ​operaţia ​de ''​mmap''​ trebuie să completeze şi să iniţializeze structura ''​vm_area_struct''​ asociată. Cele mai importante câmpuri ale acestei structuri sunt: 
-<code c> +  *[[http://elixir.free-electrons.com/​linux/v4.9/​source/​include/linux/mm_types.h#​L303|vm_start]],​ [[http://​elixir.free-electrons.com/linux/v4.9/​source/​include/​linux/​mm_types.h#L304|vm_end]], reprezintă începutulrespectivsfârşitul zonei de memorie (aceste câmpuri apar şi in ''/​proc/​*/​maps''​); 
-SYSCALL_DEFINE3(socketintfamilyint, type, int, protocol+  ​*[[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​mm_types.h#​L351|vm_file]],​ pointer-ul la structura de fişier asociată (dacă există)
-+  *[[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​mm_types.h#​L349|vm_pgoff]],​ offset-ul zonei în cadrul fişierului
- int retval+  ​*[[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​mm_types.h#​L324|vm_flags]],​ un set de indicatori; 
- struct socket ​*sock+  *[[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​mm_types.h#​L346|vm_ops]],​ un set de funcţii de lucru asupra acestei zone. 
- int flags;+  *[[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​mm_types.h#​L308|vm_next]],​ [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​mm_types.h#​L308|vm_prev]],​ ''​vm_area''​-urile aferente unui proces sunt înlănțuite printr-o listă
  
- /* Check the SOCK_* constants for consistency. ​ */ +==== Structura ''​mm_struct''​ ====
- BUILD_BUG_ON(SOCK_CLOEXEC !O_CLOEXEC);​ +
- BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) !SOCK_TYPE_MASK);​ +
- BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK);​ +
- BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK);​+
  
- flags = type & ~SOCK_TYPE_MASK;​ +Structura [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​mm_types.h#​L396|struct mm_struct]] înglobează toate zonele de memorie asociate unui procesfolosind câmpul ''​mm''​ al structurii [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​sched.h#​L1475|task_struct]] se poate obţine structura ''​mm_struct''​ asociată procesului curent.
- if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) +
- return ​-EINVAL; +
- type &= SOCK_TYPE_MASK;+
  
- if (SOCK_NONBLOCK !O_NONBLOCK && (flags & SOCK_NONBLOCK)) +==== Maparea memoriei ====
- flags ​(flags & ~SOCK_NONBLOCK) | O_NONBLOCK;+
  
- retval = sock_create(familytype, protocol, &​sock);​ +Maparea memoriei ​(''​memory mapping''​) este una dintre cele mai interesante caracteristici ale unui sistem Unix. Din punct de vedere al unui driverfacilitatea de ''​memory-mapping''​ permite accesul direct al memoriei unui dispozitiv din user-space.
- if (retval < 0) +
- goto out;+
  
- retval = sock_map_fd(sockflags & (O_CLOEXEC ​O_NONBLOCK));​ +Pentru a asocia unui driver o operaţie ''​mmap''​trebuie utilizat câmpul [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​fs.h#​L1708|mmap]] din structura [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​fs.h#​L1696|struct file_operations]] asociată dispozitivului. Metoda astfel asociată este utilizată în cazul unui apel ''​mmap''​ din user-space.
- if (retval < 0) +
- goto out_release;​+
  
-out: +==== User-space ====
- /* It may be already another descriptor 8) Not kernel problem. */ +
- return retval;+
  
-out_release: +Apelul ''​mmap''​ din user-space realizează o mapare între spaţiul de adresă al unui proces şi un fişier şi are signatura:
- sock_release(sock);​ +
- return retval; +
-+
-</​code>​+
  
-== Închiderea == +<​code ​C
- +void *mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset);
-Închiderea conexiunii (pentru socket cu conexiune) și eliberarea resurselor asociate: +
-  *''​void ''​[[http://​lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L514|sock_release]]''​(struct socket *sock)''​ - această funcție va apela funcția ''​release''​ din câmpul ''​ops''​ al structurii socket-ului:​ +
-<​code ​c+
-void sock_release(struct socket ​*sock) +
-+
- if (sock->​ops+
- struct module *owner = sock->​ops->​owner; +
- +
- sock->​ops->​release(sock);​ +
- sock->​ops = NULL; +
- module_put(owner);​ +
-+
- //... +
-}+
 </​code>​ </​code>​
  
-== Transmiterea/​recepția unui mesaj ==+Pentru a mapa memorie între un dispozitiv şi user-space, se va deschide dispozitivul cu un apel ''​open''​ şi se va pasa apelului ''​mmap''​ descriptorul acestuia.
  
-Transmiterea/​recepția mesajelor se face cu ajutorul funcțiilor:​ +==== Kernel-space ====
-  *''​int ''​[[http://​lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L709|sock_recvmsg]]''​(struct socket *sock, struct msghdr *msg, size_t size, int flags);''​ +
-  *''​int ''​[[http://​lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L739|kernel_recvmsg]]''​(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size, int flags);''​ +
-  *''​int ''​[[http://​lxr.linux.no/​linux+v2.6.35/​net/​socket.c#​L576|sock_sendmsg]]''​(struct socket *sock, struct msghdr *msg, size_t size);''​ +
-  *''​int ''​[[http://​lxr.linux.no/​linux+v2.6.35/​net/​socket.c#​L590|kernel_sendmsg]]''​(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size);''​+
  
-Funcțiile de transmitere/​recepție de mesaj vor apela ulterior funcția ''​sendmsg/​recvmsg''​ din câmpul ''​ops''​ al socket-ului. Funcțiile ce conțin ''​kernel_''​ ca prefix sunt folosite în cazul în care socket-ul este utilizat în cadrul ​kernel-ului. +Operaţia ''​mmap''​ din kernel-space se declară ca un membru al structurii ​''​struct file_operations''​ de forma
- +<​code ​C
-Parametrii acestor funcții sunt următorii:​ +int (*mmap) (struct ​file *filp, struct ​vm_area_struct ​*vma)
-  *''​msg'',​ o structura [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​socket.h#​L55|struct msghdr]], ce conține mesajul de transmis/​recepționat. Dintre componentele importante ale acestei structuri avem: +
-    *''​msg_name'',​ ''​msg_namelen'',​ care pentru socket-i ''​UDP''​ trebuie completați cu adresa la care se transmite mesajul ([[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​in.h#​L181|struct sockaddr_in]]) +
-    *''​msg_iov'',​ ''​msg_iovlen'',​ datele de transmis, într-un vector de structuri [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​uio.h#​L7|struct iovec]]. O structură ''​iovec''​ conține ​un pointer către buffer-ul ce conține datele și dimensiunea acestuia. +
-  *''​vec''​, o structură [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​uio.h#​L31|kvec]],​ ce conține un pointer către buffer-ul ce conține datele și dimensiunea acestuia; după cum se poate observa, are o structură similară cu structura [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​uio.h#​L7|struct iovec]] +
- +
-Modul de lucru cu funcțiile de transmitere poate fi urmărit în cadrul handler-ului pentru apelul de sistem [[http://​lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L1644|sys_sendto]]+
-<​code ​c+
-SYSCALL_DEFINE6(sendto, int, fd, void __user ​*, buff, size_t, len, +
-                unsigned, flags, ​struct ​sockaddr __user ​*, addr, +
-                int, addr_len) +
-+
-         struct ​socket ​*sock; +
-         char address[MAX_SOCK_ADDR];​ +
-         int err; +
-         ​struct msghdr msg; +
-         ​struct iovec iov; +
-         int fput_needed;​ +
-         ​struct file *sock_file;​ +
- +
-         ​sock_file = fget_light(fd,​ &​fput_needed)+
-         err = -EBADF; +
-         if (!sock_file) +
-                 goto out; +
- +
-         sock = sock_from_file(sock_file,​ &​err);​ +
-         if (!sock) +
-                 goto out_put; +
-         ​iov.iov_base = buff; +
-         ​iov.iov_len = len; +
-         ​msg.msg_name = NULL; +
-         ​msg.msg_iov = &iov; +
-         ​msg.msg_iovlen = 1; +
-         ​msg.msg_control = NULL; +
-         ​msg.msg_controllen = 0; +
-         ​msg.msg_namelen = 0; +
-         if (addr) { +
-                 err = move_addr_to_kernel(addr,​ addr_len, address); +
-                 if (err < 0) +
-                         goto out_put; +
-                 ​msg.msg_name = address; +
-                 ​msg.msg_namelen = addr_len; +
-         } +
-         if (sock->​file->​f_flags & O_NONBLOCK) +
-                 flags |= MSG_DONTWAIT;​ +
-         ​msg.msg_flags = flags; +
-         err = sock_sendmsg(sock,​ &msg, len); +
- +
-out_put: +
-         ​fput_light(sock_file,​ fput_needed);​ +
-out: +
-         ​return err; +
-}+
 </​code>​ </​code>​
  
-=== Câmpuri ale structurii socket ===+Câmpul ''​filp''​ reprezintă pointer-ul la structura [[http://​lxr.free-electrons.com/​source/​include/​linux/​fs.h#​L866|struct file]] creată o dată cu deschiderea dispozitivului din user-space. Câmpul ''​vma''​ este utilizat pentru a indica spaţiul de adresă virtual folosit pentru maparea memoriei dispozitivului. Un driver va putea aloca memorie (folosind ''​kmalloc''​ sau ''​vmalloc''​),​ urmând ca un set de procese să poată mapa în spaţiul propriu de adresă adresa alocată în driver.
  
-Structura [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​net.h#​L136|struct socket]]: +===== ''​remap_pfn_range''​ =====
-<code c> +
-/** +
-  *  struct socket - general BSD socket +
-  *  @state: socket state (%SS_CONNECTED,​ etc) +
-  *  @type: socket type (%SOCK_STREAM,​ etc) +
-  *  @flags: socket flags (%SOCK_ASYNC_NOSPACE,​ etc) +
-  *  @ops: protocol specific socket operations +
-  *  @fasync_list:​ Asynchronous wake up list +
-  *  @file: File back pointer for gc +
-  *  @sk: internal networking protocol agnostic socket representation +
-  *  @wait: wait queue for several uses +
-  */ +
-struct socket { +
-        socket_state ​           state; +
-        short                   ​type;​ +
-        unsigned long           ​flags;​ +
-        /* +
-         * Please keep fasync_list & wait fields in the same cache line +
-         */ +
-        struct fasync_struct ​   *fasync_list;​ +
-        wait_queue_head_t ​      wait;+
  
-        ​struct ​file             ​*file;​ +Pentru maparea unui spaţiu de memorie fizică în spaţiul virtual utilizator, reprezentat de structura ''​struct ​vm_area_struct'',​ se folosește apelul [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​mm.h#​L2193|remap_pfn_range]]. Acesta va mapa un spaţiu de adresă fizic contiguu în spaţiul virtual reprezentat de ''​struct vm_area_struct'':​ 
-        ​struct sock             *sk; +<code C> 
-        ​const ​struct ​proto_ops  ​*ops; +int remap_pfn_range(struct ​vm_area_struct ​*vma, unsigned long addr, 
-};+                        ​unsigned long pfn, unsigned long size, pgprot_t prot);
 </​code>​ </​code>​
  
-Câmpuri importante ​sunt: +Parametrii funcţiei ​sunt: 
-  *''​ops'' ​- structura ce conține pointeri la funcțiile specifice protocolului implementat+  *''​vma''​, spaţiul de memorie virtuală în cadrul căruia se face maparea
-  *''​sk'' ​- //INET socket//-ul asociat. +  *''​addr''​, spaţiul virtual de adresă de unde se începe remaparea; se vor construi tabele de pagini pentru spaţiul virtual de adresă cuprins intre ''​addr'' ​şi ''​addr + size'';​ 
- +  ​*''​pfn''​numărul paginii fizice ​(''​page frame number''​) în care se mapează adresa virtuală; de obicei acesta se obţine prin shifting-ul adresei fizice ​[[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/page_types.h#L8|PAGE_SHIFT]] biţi la dreapta 
-=== Structura proto_ops === +  ​*''​size'',​ dimensiunea ​(în octeţi) a spaţiului ​de memorie care va fi remapat; 
- +  *''​prot'', ​caracteristicile de protecţie pentru noul spaţiu de adresă.
-Structura [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​net.h#​L159|struct proto_ops]] conține implementările operațiilor specifice protocolului implementat (''​TCP''​''​UDP''​, etc.)funcțiile de aici vor fi apelate din funcțiile generice de lucru cu [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​net.h#​L136|struct socket]] ([[http://​lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L514|sock_release]],​ [[http://​lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L576|sock_sendmsg]],​ etc.) +
- +
-Structura [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​net.h#​L159|struct proto_ops]] conțineașadar, o serie de pointeri de funcții pentru implementări specifice de protocol: +
-<code c> +
-struct proto_ops { +
- int family;​ +
- struct module *owner;​ +
- int (*release) ​  ​(struct socket *sock); +
- int (*bind)  ​    ​(struct socket *sock, +
-       struct sockaddr *myaddr, +
-       int sockaddr_len);​ +
- int (*connect) ​  ​(struct socket *sock, +
-       struct sockaddr *vaddr, +
-       int sockaddr_len,​ int flags); +
- int (*socketpair)(struct socket *sock1, +
-       struct socket *sock2); +
- int (*accept) ​   (struct socket *sock, +
-       struct socket *newsock, int flags); +
- //... +
-</​code>​ +
- +
-Inițializarea câmpului ​''​ops'' ​din [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​net.h#​L136|struct socket]] ​se realizează în funcția [[http://​lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L1151|__sock_create]],​ prin apelul funcției [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​net.h#​L214|create]] specifică protocoluluiun apel echivalent este următorul:​ +
-<code c> +
-//... +
-        if ((err = net_families[family]->​create(net,​ sock, protocol)) < 0) { +
-                sock->​ops = NULL; +
-                goto out_module_put;​ +
-        } +
-//... +
-</​code>​ +
- +
-Se va realiza astfel instanțierea pointerilor ​de funcții cu apeluri specifice tipului de protocol asociat socket-ului. Apelurile ​[[http://lxr.linux.no/#linux+v2.6.35/net/socket.c#​L2312|sock_register]] și [[http://lxr.linux.no/#​linux+v2.6.35/net/​socket.c#​L2344|sock_unregister]] sunt folosite pentru completarea vectorului [[http://lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#L154|net_families]]. +
- +
-Pentru restul operațiilor cu socketi ​(în afară de creare, închidere ștransmitere/​recepție mesaj, prezentate mai sus, în secțiunea [[#​Operații asupra structurii socket|Operații asupra structurii socket]]), se vor apela funcțiile date de pointerii din această structură. Spre exemplu, pentru operația ​''​bind'', ​care asociază unui socket un port pe mașina locală, vom avea următoarea secvență de cod: +
-<code c> +
-#define MY_PORT 60000 +
- +
-struct sockaddr_in addr = { +
-    ​.sin_family = AF_INET, +
-    .sin_port = htons (MY_PORT),​ +
-    .sin_addr = { htonl (INADDR_LOOPBACK) } +
-};+
  
-//...+Un exemplu de utilizare a acestei funcţii este: 
 +<code C> 
 +struct vm_area_struct *vma; 
 +unsigned long phys_pgoff;​ 
 +int ret;
  
-err sock->ops->bind (sock(struct sockaddr *) &addr, sizeof(addr)); +ret remap_pfn_range (vma, vma->vm_start, phys_pgoff,​ 
-if (err < 0) { +                   vma->vm_end - vma->​vm_startvma->​vm_page_prot); 
-    /* handle error */+if (ret < 0) { 
 +        ​printk(KERN_ERR"​could not map address area\n"​);​ 
 +        return -EIO;
 } }
-//... 
 </​code>​ </​code>​
  
-După cum se poate observa, pentru transmiterea informațiilor legate ​de adresa și portul care se vor asocia socket-ului, ​se completează o structură [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​in.h#​L181|struct sockaddr_in]]. ((hton* -- despre funcțiile ​''​htons''​''​htonl'' ​vom discuta la secțiunea [[#​Conversii|Conversii]].))+În exemplul ​de mai sus se realizează o mapare a zonei fizice începând de la numărul de pagină ''​phys_pgoff'' ​în întreg spaţiul virtual de adresă reprezentat de ''​vma''​.
  
-==== Structura sock ====+Două funcţii care sunt utile sunt cele de translatare a unei adrese virtuale din spaţiul kernel în adrese fizice. Acestea sunt [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​arch/​x86/​include/​asm/​io.h#​L118| virt_to_phys]] pentru adrese alocate folosind ''​kmalloc''​ şi [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​mm.h#​L473|vmalloc_to_pfn]] pentru adrese alocate folosind ''​vmalloc''​.
  
-Structura [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​net/​sock.h#​L155|struct sock]] descrie un //INET socket//. O astfel ​de structură este asociată unui socket creat în user-space și, implicit, ​unei structuri [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​net.h#​L136|struct socket]]. Structura este folosită pentru a menține informații despre starea unei conexiuni. Câmpurile structurii și operațiile asociate încep, de obicei, cu șirul ​''​sk_''​. Câteva câmpuri sunt prezentate mai jos+Astfel, numărul ​de pagină ''​phys_pgoff''​ din exemplul de mai sus se va obţine ​în cazul unei adrese ​''​kmalloc_area'' ​alocate folosind ''​kmalloc''​ astfel
-<​code ​c+<​code ​C
-struct sock { +static ​char* kmalloc_area;
- //... +
- unsigned ​char sk_protocol;​ +
- unsigned short sk_type;​ +
- //... +
- struct socket *sk_socket; +
- //... +
- struct sk_buff *sk_send_head;​ +
- //... +
- void (*sk_state_change)(struct sock *sk); +
- void (*sk_data_ready)(struct sock *sk, int bytes); +
- void (*sk_write_space)(struct sock *sk); +
- void (*sk_error_report)(struct sock *sk); +
-  int (*sk_backlog_rcv)(struct sock *sk, +
-  ​ struct sk_buff *skb); +
- void                    (*sk_destruct)(struct sock *sk); +
-}; +
-</​code>​+
  
-  *''​sk_protocol''​ este tipul de protocol utilizat de socket; +unsigned long phys_pgoff = virt_to_phys((void *)kmalloc_area) >> ​PAGE_SHIFT;
-  *''​sk_type''​ este tipul de socket ​(''​SOCK_STREAM'',​ ''​SOCK_DGRAM'',​ etc.) +
-  *''​sk_socket''​ este socket-ul BSD care îl deține; +
-  *''​sk_send_head''​ este lista de structuri ''​sk_buff''​ pentru transmitere;​ +
-  *pointerii de funcții de la sfârșit sunt callback-uri pentru diverse situații. +
- +
-Inițializarea ''​struct sock''​ și atașarea acesteia la un socket BSD se face cu ajutorul callback-ului [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​net.h#​L214|create]] din [[http://​lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L154|net_families]] ​(apelat in [[http://​lxr.linux.no/#​linux+v2.6.35/​net/​socket.c#​L1151|__sock_create]]). Mai jos este prezentat modul de +
-inițializare a structurii ''​struct sock''​ pentru protocolul IP, în cadrul funcției [[http://​lxr.linux.no/#​linux+v2.6.35/​net/​ipv4/​af_inet.c#​L262|inet_create]]:​ +
-<code c> +
-/* +
-  * Create an inet socket. +
-  */ +
- +
-static int inet_create(struct net *net, struct socket *sock, int protocol) +
-+
- struct sock *sk; +
- +
- //... +
- err = -ENOBUFS; +
- sk = sk_alloc(net,​ PF_INET, GFP_KERNEL, answer_prot)+
- if (sk == NULL) +
- goto out; +
- +
- err = 0; +
- sk->​sk_no_check = answer_no_check;​ +
- if (INET_PROTOSW_REUSE & answer_flags) +
- sk->​sk_reuse = 1; +
- +
- //... +
- sock_init_data(sock,​ sk); +
- +
- sk->​sk_destruct  ​  = inet_sock_destruct;​ +
- sk->​sk_family  ​  = PF_INET; +
- sk->​sk_protocol  ​  = protocol; +
- sk->​sk_backlog_rcv = sk->sk_prot->backlog_rcv; +
- //... +
-}+
 </​code>​ </​code>​
 +iar în cazul unei adrese alocate folosind ''​vmalloc'':​
 +<code C>
 +static char *vmalloc_area;​
  
-==== Structura sk_buff ==== +unsigned long  phys_pgoff ​ = vmalloc_to_pfn ​(vmalloc_area);
- +
-Structura [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​skbuff.h#​L257|struct sk_buff]] (//socket buffer//) descrie un pachet de rețea. Câmpurile structurii conțin informații atât despre antetele și conținutul pachetelor cât și protocoalele utilizate, dispozitivul de rețea utilizat, pointeri către celelalte structuri ''​struct sk_buff''​. O descriere sumară a conținutului structurii este prezentată mai jos: +
-<code c> +
- ​struct sk_buff { +
-         /* These two members must be first. */ +
-         ​struct sk_buff ​         *next; +
-         ​struct sk_buff ​         *prev; +
- +
-         ​struct sock             ​*sk;​ +
-         ​ktime_t ​                ​tstamp;​ +
-         ​struct net_device ​      ​*dev;​ +
- +
-         ​struct ​ dst_entry ​      ​*dst;​ +
-         ​struct ​ sec_path ​       *sp; +
- +
-         /* +
-          * This is the control buffer. It is free to use for every +
-          * layer. Please put your private variables there. If you +
-          * want to keep them across layers you have to do a skb_clone() +
-          * first. This is owned by whoever has the skb queued ATM. +
-          */ +
-         ​char ​                   cb[48]; +
- +
-         ​unsigned int            len, +
-                                 ​data_len;​ +
-         ​__u16 ​                  ​mac_len,​ +
-                                 ​hdr_len;​ +
- +
-         /* ... */ +
- +
-         ​void ​                   (*destructor)(struct sk_buff *skb); +
- +
-         /* ... */ +
- +
-         ​sk_buff_data_t ​         transport_header;​ +
-         ​sk_buff_data_t ​         network_header;​ +
-         ​sk_buff_data_t ​         mac_header;​ +
- +
-         /* These elements must be at the end, see alloc_skb() for details. ​ */ +
-         ​sk_buff_data_t ​         tail; +
-         ​sk_buff_data_t ​         end; +
-         ​unsigned char           ​*head,​ +
-                                 ​*data;​ +
-         ​unsigned int            truesize; +
-         ​atomic_t ​               users; +
- };+
 </​code>​ </​code>​
  
-unde: +De cele mai multe ori, implementarea funcţiei ​''​mmap'' ​descrisă mai sus se reduce la un apel al funcţiei ​''​remap_pfn_range''​. Paginile alocate folosind ​''​vmalloc'' ​nu sunt fizic contigueastfel încât va trebui mapată fiecare ​pagină în parte (în cazul în care zona de memorie are mai multe pagini)apelând ​''​remap_pfn_range'' ​pentru fiecare pagină virtuală.
-  *''​next'' ​și ''​prev''​ sunt pointeri către următorul, respectiv precedentul element din lista de buffer-e; +
-  *''​dev'' ​este device-ul care transmite sau primește buffer-ul;​ +
-  *''​sk''​ este socket-ul asociat buffer-ului;​ +
-  *''​destructor''​ este apelul callback de dealocare a buffer-ului;​ +
-  *''​transport_header'',​ ''​network header''​ și ''​mac_header''​ sunt offset-uri între începutul pachetului si începutul diverselor headere din pachet. Ele sunt menținute intern de diversele niveluri de procesare prin care trece pachetul. Pentru a obține pointeri către headerefolosiți una din următoarele funcții: [[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​tcp.h#​L213|tcp_hdr]],​ [[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​udp.h#​L43|udp_hdr]],​ [[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​ip.h#​L110|ip_hdr]],​ etc. În principiu, ​fiecare ​protocol oferă o funcție ​de a obține o referință la header-ul respectivului protocol din cadrul unui pachet primit. De reținut: câmpul ''​network_header''​ nu este setat decât după ce pachetul ajunge la nivelul rețeaiar câmpul ​''​transport_header'' ​nu este setat decât după ce pachetul ajunge la nivelul transport.+
  
-Structura unui [[http://​www.networksorcery.com/​enp/​protocol/​ip.htm|antet IP]] ([[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​ip.h#​L85|struct iphdr]]) are următoarele câmpuri: +===== ''​SetPageReserved''​/''​ClearPageReserved''​ =====
-<code c> +
-struct iphdr { +
-#if defined(__LITTLE_ENDIAN_BITFIELD) +
-         ​__u8 ​   ihl:4, +
-                 ​version:​4;​ +
-#elif defined (__BIG_ENDIAN_BITFIELD) +
-         ​__u8 ​   version:​4,​ +
-                 ​ihl:​4;​ +
-#else +
-#​error ​ "​Please fix <​asm/​byteorder.h>"​ +
-#endif +
-         ​__u8 ​   tos; +
-         ​__be16 ​ tot_len; +
-         ​__be16 ​ id; +
-         ​__be16 ​ frag_off; +
-         ​__u8 ​   ttl; +
-         ​__u8 ​   protocol; +
-         ​__sum16 check; +
-         ​__be32 ​ saddr; +
-         ​__be32 ​ daddr; +
-         /*The options start here. */ +
-}; +
-</​code>​+
  
-unde: +Înainte ​de a fi utilizată, unei pagini îi va trebui activat bitul [[http://elixir.free-electrons.com/linux/v4.9/source/​include/​linux/​page-flags.h#L85|PG_reserved]]. Acest bit înseamnă că pagina nu poate fi evacuată pe disk (''​swap''​)Activarea se realizează cu ajutorul macroului ​[[http://elixir.free-electrons.com/linux/v4.9/source/​include/​linux/​page-flags.h#L194|SetPageReserved]]. Macrodefiniţia primeşte ca parametru un pointer către structura de pagină''​struct page''​, care se obţine din adresa virtuală din kernel cu ajutorul funcţiei ​''​virt_to_page''​, pentru adrese alocate folosind ''​kmalloc'':​ 
-  *''​protocol''​ reprezintă protocolul ​de nivel transport ​utilizat+<code C> 
-  *''​saddr''​ reprezintă adresa IP a nodului sursă; +#define NPAGES 16
-  *''​daddr''​ reprezintă adresa IP a nodului destinație. +
- +
-Structura unui [[http://www.networksorcery.com/enp/protocol/​tcp.htm|antet TCP]] ([[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​tcp.h#L24|struct tcphdr]]) are următoarele câmpuri: +
-<​code ​c+
-struct tcphdr { +
-         ​__be16 ​ source; +
-         ​__be16 ​ dest; +
-         ​__be32 ​ seq; +
-         ​__be32 ​ ack_seq; +
-#if defined(__LITTLE_ENDIAN_BITFIELD) +
-         ​__u16 ​  ​res1:​4,​ +
-                 ​doff:​4,​ +
-                 ​fin:​1,​ +
-                 ​syn:​1,​ +
-                 ​rst:​1,​ +
-                 ​psh:​1,​ +
-                 ​ack:​1,​ +
-                 ​urg:​1,​ +
-                 ​ece:​1,​ +
-                 ​cwr:​1;​ +
-#elif defined(__BIG_ENDIAN_BITFIELD) +
-         ​__u16 ​  ​doff:​4,​ +
-                 ​res1:​4,​ +
-                 ​cwr:​1,​ +
-                 ​ece:​1,​ +
-                 ​urg:​1,​ +
-                 ​ack:​1,​ +
-                 ​psh:​1,​ +
-                 ​rst:​1,​ +
-                 ​syn:​1,​ +
-                 ​fin:​1;​ +
-#else +
-#​error ​ "​Adjust your <​asm/​byteorder.h>​ defines"​ +
-#endif +
-         ​__be16 ​ window; +
-         ​__sum16 check; +
-         ​__be16 ​ urg_ptr; +
-}; +
-</​code>​ +
-  *''​source''​ reprezintă portul sursă +
-  *''​dest'' ​reprezintă portul destinație +
-  *''​syn'',​ ''​ack'',​ ''​fin''​ sunt flag-uri folosite în protocolul TCP; pentru detalii studiați această [[http://​www.eventhelix.com/​Realtimemantra/​Networking/​Tcp.pdf|diagramă]]. +
- +
-Structura unui [[http://www.networksorcery.com/enp/protocol/​udp.htm|antet UDP]] ([[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​udp.h#L22|struct udphdr]]) are următoarele câmpuri: +
-<code c> +
-struct udphdr { +
-         ​__be16 ​ source; +
-         ​__be16 ​ dest; +
-         ​__be16 ​ len; +
-         ​__sum16 check; +
-}; +
-</​code>​ +
-  *''​source'' ​reprezintă portul sursă +
-  *''​dest'' ​reprezintă portul destinație+
  
-Un exemplu de accesare a informațiilor prezente în antetele unui pachet de rețea este următorul: +static char* kmalloc_area;​ 
-<code c> +int i;
-struct sk_buff *skb;+
  
-struct iphdr *iph ip_hdr(skb)                /IP header */ +for (i 0i < NPAGES ​PAGE_SIZE; i +PAGE_SIZE) { 
-/* iph->​saddr ​ - source IP address */ +        ​SetPageReserved(virt_to_page(((unsigned long)kmalloc_area) + i));
-/* iph->​daddr ​ - destination IP address */ +
-if (iph->​protocol =IPPROTO_TCP) {              /* TCP protocol */ +
-    ​struct tcphdr *tcph = tcp_hdr(skb);          /* TCP header */ +
-    /* tcph->​source ​ - source TCP port */ +
-    /* tcph->​dest ​   - destination TCP port */ +
-} else if (iph->​protocol == IPPROTO_UDP) {       /* UDP protocol */ +
-    struct udphdr *udph = udp_hdr(skb);          /* UDP header */ +
-    /* udph->​source ​ - source UDP port */ +
-    /* udph->​dest ​   - destination UDP port */+
 } }
 </​code>​ </​code>​
 +şi cu ajutorul funcţiei [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​mm/​vmalloc.c#​L235|vmalloc_to_page]] pentru adrese alocate folosind ''​vmalloc'':​
 +<code C>
 +#define NPAGES 16
  
-==== Conversii ====+static char* vmalloc_area;​ 
 +int i;
  
-În sisteme diferite, există mai multe variante pentru ordonarea octeților într-un cuvânt ​([[http://​en.wikipedia.org/​wiki/​Endianness|Endianness]]),​ printre care: [[http://​en.wikipedia.org/​wiki/​Endianness#​Big-endian|Big Endian]] (cel mai semnificativ octet primul) ș[[http://​en.wikipedia.org/​wiki/​Endianness#​Little-endian|Little Endian]] (cel mai puțin semnificativ octet primul). Având în vedere că o rețea interconectează sisteme cu platforme diferite, Internet-ul a impus o secvență standard pentru stocarea datelor numerice, numită [[http://​en.wikipedia.org/​wiki/​Endianness#​Endianness_in_networking|network byte-order]]. Spre deosebire, secvența octeților pentru reprezentarea datelor numerice pe calculatorul gazdă se numește host byte-order. Datele primite/​trimise din/în rețea sunt în formatul network byte-order și trebuie facută conversia între acest format și host byte-order. +for (i = 0; NPAGES ​PAGE_SIZE; i += PAGE_SIZE{ 
- +        ​SetPageReserved(vmalloc_to_page((void *)(((unsigned long)vmalloc_area) + i)));
-Pentru conversie există urmatoarele macrodefiniții:​ +
-  *''​u16 ''​[[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​byteorder/​generic.h#​L140|htons]]''​(u16 x)''​ +
-    *convertește un întreg pe 16 biți din host byte-order în network byte-order (//host to network short//) +
-  *''​u32 ''​[[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​byteorder/​generic.h#​L138|htonl]]''​(u32 x)''​ +
-    *convertește un întreg pe 32 de biți din host byte-order în network byte-order (//host to network long//) +
-  *''​u16 ''​[[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​byteorder/​generic.h#​L141|ntohs]]''​(u16 x)''​ +
-    *convertește un întreg pe 16 biți din network byte-order în host byte-order (//network to host short//) +
-  *''​u32 ''​[[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​byteorder/​generic.h#​L139|ntohl]]''​(u32 x)''​ +
-    *convertește un întreg pe 32 de biți din network byte-order în host byte-order (//network to host long//) +
-==== netfilter ==== +
- +
-[[http://​www.netfilter.org/​|Netfilter]] este denumirea interfeței de kernel pentru captura pachetelor de rețea cu scopul de modificare/​analiză a acestora (pentru filtrare, NAT, etc.). Interfața //​netfilter//​ este utilizată în user-space de [[http://​www.frozentux.net/​documents/​iptables-tutorial/​|iptables]]. +
- +
-În kernel-ul Linux, captura de pachete folosind netfilter se realizează prin atașarea unor hook-uri. Hook-urile pot fi precizate în diferite locații din traseul urmat de un pachet de rețea în kernel, în funcție de necesitate. O organigramă cu traseul urmat de un pachet și zonele posibile de plasare a unui hook găsiți [[http://​linux-ip.net/​nf/​nfk-traversal.png|aici]]. +
- +
-Header-ul inclus atunci când se folosește netfilter este [[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​netfilter.h|linux/​netfilter.h]]. +
- +
-Un hook se definește prin intermediul structurii [[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​netfilter.h#​L96|struct nf_hook_ops]]:​ <code c> +
-struct nf_hook_ops { +
- struct list_head list; +
- +
- /* User fills in from here down. */ +
- nf_hookfn *hook; +
- struct module *owner; +
- int pf; +
- int hooknum; +
- /* Hooks are ordered in ascending priority. */ +
- int priority; +
-}; +
-</​code>​ +
- +
-unde: +
-  *''​pf''​ este tipul pachetului ([[http://​lxr.linux.no/#​linux+v2.6.35/​include/​linux/​socket.h#​L199|PF_INET]],​ etc.); +
-  *''​hooknum''​ este tipul de hook utilizat; pentru IP, acestea sunt definite în [[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​netfilter_ipv4.h|linux/​netfilter_ipv4.h]]:​ <code c> +
-/* IP Hooks */ +
-/* After promisc drops, checksum checks. */ +
-#define NF_INET_PRE_ROUTING 0 +
-/* If the packet is destined for this box. */ +
-#define NF_INET_LOCAL_IN 1 +
-/* If the packet is destined for another interface. */ +
-#define NF_INET_FORWARD 2 +
-/* Packets coming from a local process. */ +
-#define NF_INET_LOCAL_OUT 3 +
-/* Packets about to hit the wire. */ +
-#define NF_INET_POST_ROUTING 4 +
-#define NF_INET_NUMHOOKS 5 +
-</​code>​ +
-  *''​priority''​ este prioritateaprioritățile sunt definite în [[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​netfilter_ipv4.h|linux/​netfilter_ipv4.h]]: ​<code c> +
- enum nf_ip_hook_priorities { +
-         ​NF_IP_PRI_FIRST = INT_MIN, +
-         ​NF_IP_PRI_CONNTRACK_DEFRAG = -400, +
-         ​NF_IP_PRI_RAW = -300, +
-         ​NF_IP_PRI_SELINUX_FIRST = -225, +
-         ​NF_IP_PRI_CONNTRACK = -200, +
-         ​NF_IP_PRI_MANGLE = -150, +
-         ​NF_IP_PRI_NAT_DST = -100, +
-         ​NF_IP_PRI_FILTER = 0, +
-         ​NF_IP_PRI_NAT_SRC = 100, +
-         ​NF_IP_PRI_SELINUX_LAST = 225, +
-         ​NF_IP_PRI_CONNTRACK_HELPER = INT_MAX - 2, +
-         ​NF_IP_PRI_NAT_SEQ_ADJUST = INT_MAX - 1, +
-         ​NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX, +
-         ​NF_IP_PRI_LAST = INT_MAX, +
- }; +
-</​code>​ +
-  ​*''​nhook_fn''​ este handler-ul apelat in momentul capturării unui pachet de rețea (în forma unei structuri ''​struct sk_buff''​)prototipul este definit în [[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​netfilter.h|linux/​netfilter.h]]:​ <code c> +
-typedef unsigned int nf_hookfn(unsigned int hooknum, +
-        ​struct sk_buff *skb, +
-        const struct net_device *in, +
-        const struct net_device *out, +
-        int (*okfn)(struct sk_buff *)); +
-</​code>​ +
-    *''​skb''​ este pointer la pachet-ul de rețea capturat. +
-    *Se observă că se poate folosi acelașhandler pentru mai multe hook-uri, deosebirea între acestea realizându-se cu ajutorul parametrului ''​hooknum''​. +
-    *Un handler de captură poate întoarce una din [[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​netfilter.h#​L17|constantele NF_*]]: <code c> +
-/* Responses from hook functions. */ +
-#define NF_DROP 0 +
-#define NF_ACCEPT 1 +
-#define NF_STOLEN 2 +
-#define NF_QUEUE 3 +
-#define NF_REPEAT 4 +
-#define NF_STOP 5 +
-</​code>​ +
-    *''​NF_DROP''​ este folosit pentru a filtra (ignoraun pachet, iar ''​NF_ACCEPT''​ este folosit pentru a accepta un pachet și a-l transmite mai departe. +
- +
-Înregistrarea/​deînregistrarea unui hook se realizează cu ajutorul funcțiilor definite în [[http://​lxr.linux.no/​linux+v2.6.35/​include/​linux/​netfilter.h|linux/​netfilter.h]]:​ <code c> +
-/* Function to register/​unregister hook points. */ +
-int nf_register_hook(struct nf_hook_ops *reg); +
-void nf_unregister_hook(struct nf_hook_ops *reg); +
-int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n); +
-void nf_unregister_hooks(struct nf_hook_ops ​*reg, unsigned int n)+
-</​code>​ +
- +
-  * **Atenție!** Există anumite restricții legate de utilizarea funcțiilor de extragere a antetelor dintr-un ''​struct sk_buff''​ dat ca parametru într-un hook netfilter. În timp ce antetul IP poate fi obținut de fiecare dată folosind ''​ip_hdr()'',​ antetele TCP și UDP pot fi obținute cu ''​tcp_hdr()'',​ respectiv ''​udp_hdr()''​ numai pentru pachete care pornesc dinspre sistem, și nu pentru cele care intră. În cazul din urmă, trebuie calculat manual offset-ul antetelor în pachet: <code c> +
-// Pentru pachete TCP (iph->​protocol == IPPROTO_TCP) +
-tcph = (struct tcphdr*)((__u32*)iph iph->​ihl);​ +
-// Pentru pachete UDP (iph->​protocol == IPPROTO_UDP) +
-udph = (struct udphdr*)((__u32*)iph + iph->​ihl);​ +
-</​code>​ +
- +
-Acest cod funcționează în toate situațiile de filtrare, șastfel este recomandată folosirea lui în locul funcțiilor de acces la antete. +
- +
-Un exemplu de utilizare a unui hook netfilter este prezentat mai jos: +
-<code c> +
-#include <​linux/​netfilter.h>​ +
-#include <​linux/​netfilter_ipv4.h>​ +
- +
-static unsigned int my_nf_hookfn(unsigned int hooknum, +
- struct sk_buff *skb, +
- const struct net_device *in, +
- const struct net_device *out, +
- int (*okfn)(struct sk_buff *)) +
-+
- /* process packet */ +
- //... +
- +
- return NF_ACCEPT;+
 } }
- 
-static struct nf_hook_ops my_nfho = { 
- .owner ​      = THIS_MODULE,​ 
- .hook ​       = my_nf_hookfn,​ 
- .hooknum ​    = NF_INET_LOCAL_IN,​ 
- .pf          = PF_INET, 
- .priority ​   = NF_IP_PRI_FIRST 
-}; 
- 
-int __init my_hook_init(void) 
-{ 
- return nf_register_hook(&​my_nfho);​ 
-} 
- 
-void __exit my_hook_exit(void) 
-{ 
- nf_unregister_hook(&​my_nfho);​ 
-} 
- 
-module_init(my_hook_init);​ 
-module_exit(my_hook_exit);​ 
 </​code>​ </​code>​
-===== Windows networking ===== 
  
-În kernel-ul Windows lucrul cu rețeaua se realizează prin intermediul NPI ([[http://msdn.microsoft.com/en-us/library/ff568373.aspx|Network Programming Interface]])NPI definește interfața între module ​de networking care doresc să comunice între ele (clienți și provideri).+Înainte de eliberarea paginii ​(''​kfree''/''​vfree''​),​ bitul de pagină rezervată trebuie dezactivat cu ajutorul macroului ​[[http://lxr.free-electrons.com/source/include/linux/​page-flags.h?​v=4.9#L185|ClearPageReserved]]. Acesta primeşte ca parametru acelaşi pointer către o structura ​de pagină care a fost dat la ''​SetPageReserved''​.
  
-==== TDI ==== 
- 
-În Windows 2000/​XP/​2003,​ NPI este reprezentată de TDI ([[http://​msdn.microsoft.com/​en-us/​library/​ff565685.aspx|Transport Driver Interface]]). TDI expune o interfață peste care rulează așa numiții //clienți TDI// care implementează operațiile specifice. Socket-ii Windows (winsockets) sunt implementați peste clienți TDI. 
- 
-TDI folosește obiecte fișier pentru comunicație și pentru controlul acesteia. Astfel, TDI folosește obiecte fișier pentru a descrie adrese de transport deschise, conexiuni asociate unei adrese de transport și canale de control cu scopul de stabilire și consultare a parametrilor de comunicație. 
- 
-=== NDIS === 
- 
-Arhitectura de rețea pentru Windows este una modulară. TDI este construit peste NDIS ([[http://​msdn.microsoft.com/​en-us/​library/​ff556938.aspx|Network Driver Interface Specification]]). NDIS este o bibliotecă de funcții kernel care abstractizează diferitele niveluri ale rețelei; fiecărui astfel de nivel i se pot asocia drivere specifice. Folosind interfețele NDIS se pot construi: 
-  *[[http://​msdn.microsoft.com/​en-us/​library/​ff557065.aspx|NDIS Miniport Drivers]], drivere pentru NIC (Network Interface Card); 
-  *[[http://​msdn.microsoft.com/​en-us/​library/​ff557149.aspx|NDIS Protocol Drivers]], drivere utilizate pentru implementarea unui protocol; acestea transmit și primesc pachete de rețea prin intermediul unui driver tip miniport; 
-  *[[http://​msdn.microsoft.com/​en-us/​library/​ff557012.aspx|NDIS Intermediate Drivers]], drivere utilizate în filtrarea de pachete, load balancing, colectarea de statistici de rețea. 
- 
-=== Winsock Kernel === 
- 
-Începând cu Windows Vista, se recomandă utilizarea WSK ([[http://​msdn.microsoft.com/​en-us/​library/​ff556958.aspx|Winsock Kernel]]) în locul TDI. WSK vine cu un API nou pentru o performanță mai bună și programarea mai ușoara a driver-elor. WSK NPI suportă operații pe socket-i asemănătoare cu cele din user-space. 
- 
-=== Operații TDI === 
- 
-[[http://​msdn.microsoft.com/​en-us/​library/​ff565119.aspx|Operațiile TDI]] sunt apropiate operațiilor disponibile în user-space pentru lucrul cu socket-i: 
-  *deschiderea unei adrese de transport (echivalent cu un socket local și un apel bind asociat); 
-  *deschiderea unui punct de conexiune; 
-  *cererea unei conexiuni; 
-  *acceptarea unei conexiuni; 
-  *transmiterea unui segment de date pe o conexiune; 
-  *primirea unui segment de date pe o conexiune; 
-  *deconectarea;​ 
-  *închiderea unui punct de conexiune; 
-  *transmiterea unei datagrame; 
-  *primirea unei datagrame; 
-  *diverse operații de control. 
- 
-[[http://​msdn.microsoft.com/​en-us/​library/​ff565091.aspx|API-ul]] furnizat de TDI pentru implementarea acestor operații este unul destul de stufos iar [[http://​msdn.microsoft.com/​en-us/​library/​ff565119.aspx|documentația asociată]] poate fi pe alocuri confuză și greu de urmărit; drept urmare, nu vom insista. 
- 
-O descriere foarte bună a modului de utilizare a API-ului TDI (împreună cu un exemplu cod sursa) găsiți la [[http://​www.codeproject.com/​kb/​system/​driverdev5asp.aspx|The Code Project]]. 
-==== Captura de pachete în kernel-ul Windows ==== 
- 
-Captura de pachete în kernel-ul Windows se realizează prin intermediul [[http://​msdn.microsoft.com/​en-us/​library/​ff565094.aspx|TDI Drivers]], [[http://​msdn.microsoft.com/​en-us/​library/​ff557012.aspx|NDIS Intermediate Drivers]], sau așa numitelor [[http://​msdn.microsoft.com/​en-us/​library/​ff546594.aspx|Hook Drivers]]. Deși primele doua tipuri oferă mai multă flexibilitate și sunt recomandate în locul hook drivers, nu vom insista pe acestea deoarece au un API complex. 
- 
-Kernel-ul de Windows 2000/​XP/​2003 oferă API pentru două tipuri de hook drivers: 
-  *[[http://​msdn.microsoft.com/​en-us/​library/​ff546489.aspx|Filter-Hook Drivers]], adăugă ​ funcționalitate driver-ului de filtrare IP (IP filter driver) existent în sistem; dezavantajul este că nu poate exista decât un singur filter-hook driver în sistem pentru a fi folosit de IP filter driver. 
-  *[[http://​msdn.microsoft.com/​en-us/​library/​ff546499.aspx|Firewall-Hook Drivers]], este folosit pentru a filtra pachete primite/​transmise de-a lungul unui firewall în contextul protocolului TCP/IP. 
- 
-=== Filter-Hook Driver === 
- 
-Un [[http://​msdn.microsoft.com/​en-us/​library/​ff546489.aspx|filter-hook driver]] înregistrează un callback (denumit filter hook) în cadrul IP filter driver. Funcția de callback este apoi utilizată pentru a prelucra pachetul. 
- 
-== Callback == 
- 
-La fel cum în Linux, tipul funcției de filtrare era ''​nf_hook_fn'',​ în cazul filter-hook,​ funcția de callback trebuie să fie [[http://​msdn.microsoft.com/​en-us/​library/​ff562312.aspx|PacketFilterExtensionPtr]]:​ 
-<code c> 
-typedef ​ PF_FORWARD_ACTION 
-  (*PacketFilterExtensionPtr)( 
-    IN unsigned char  *PacketHeader,​ 
-    IN unsigned char  *Packet, 
-    IN unsigned int  PacketLength,​ 
-    IN unsigned int  RecvInterfaceIndex,​ 
-    IN unsigned int  SendInterfaceIndex,​ 
-    IN IPAddr ​ RecvLinkNextHop,​ 
-    IN IPAddr ​ SendLinkNextHop 
-    ); 
-</​code>​ 
- 
-unde: 
-  *''​PacketHeader''​ este pointer la antetul IP al pachetului; de obicei se va face cast la un pointer de tip [[http://​msdn.microsoft.com/​en-us/​library/​ff562312.aspx#​ddk_ipheader_nr|IPHeader]]:​ <code c> 
-typedef struct IPHeader { 
-  UCHAR   ​iph_verlen;​ 
-  UCHAR   ​iph_tos;​ 
-  USHORT ​ iph_length; 
-  USHORT ​ iph_id; 
-  USHORT ​ iph_offset; 
-  UCHAR   ​iph_ttl;​ 
-  UCHAR   ​iph_protocol;​ 
-  USHORT ​ iph_xsum; 
-  ULONG   ​iph_src;​ 
-  ULONG   ​iph_dest;​ 
-} IPHeader; 
-</​code>​ 
-  *''​Packet''​ este un pointer la informația conținută de pachetul IP fără antetul acestuia; de obicei, se vor crea structuri ''​UDPHeader''​ și ''​TCPHeader''​ și se va face un cast corespunzător;​ 
-  *''​PacketLength''​ este lungimea, în octeți, a conținutului pachetului (fără antet). 
- 
-Funcția de callback (hook-ul) poate întoarce trei valori: 
-  *''​PF_FORWARD'':​ IP filter driver va transmite imediat pachetul următorului nivel din stiva de rețea; 
-  *''​PF_DROP'':​ IP filter driver va filtra (ignora) pachetul; 
-  *''​PF_PASS'':​ IP filter driver va procesa pachetul și apoi îl va transmite următorului nivel din stiva de rețea. 
- 
-Un exemplu de astfel de funcție: 
-<code c> 
-static PF_FORWARD_ACTION cbFilterFunction ( 
- unsigned char *PacketHeader,​ 
- unsigned char *Packet,​ 
- unsigned int PacketLength,​ 
- unsigned int RecvInterfaceIndex,​ 
- unsigned int SendInterfaceIndex,​ 
- unsigned long RecvLinkNextHop,​ 
- unsigned long SendLinkNextHop) { 
- 
-    IPHeader *iph = (IPHeader *) PacketHeader;​ 
- 
-    if (iph->​iph_protocol == IPPROTO_TCP) { 
-        TCPHeader *tcph = (TCPHeader*) Packet; 
-        /* process tcp packet from IP address iph->​iph_src */ 
-    } else  if (iph->​protocol == IPPROTO_UDP) { 
-        UDPHeader *udph = (UDPHeader*) Packet; 
-        /* process tcp packet from IP address iph->​iph_src */ 
-    } 
- 
-    return PF_FORWARD; 
-} 
-</​code>​ 
- 
-== Înregistrare/​deînregistrare == 
- 
-Hook-ul se înregistrează în cadrul IP filter driver prin intermediul rutinei ioctl [[http://​msdn.microsoft.com/​en-us/​library/​ff548976.aspx|IOCTL_PF_SET_EXTENSION_POINTER]];​ se creează un IRP care apoi este transmis către IP filter driver. Pașii urmați sunt: 
- 
-  * Obținerea obiectului dispozitiv (device object) asociat IP filter driver folosind [[http://​msdn.microsoft.com/​en-us/​library/​ff549198.aspx|IoGetDeviceObjectPointer]]:​ <code c> 
-NTSTATUS status = STATUS_SUCCESS;​ 
-UNICODE_STRING filterName; 
-PDEVICE_OBJECT ipDeviceObject = NULL; 
-PFILE_OBJECT ipFileObject = NULL; 
- 
-RtlInitUnicodeString(&​filterName,​ DD_IPFLTRDRVR_DEVICE_NAME);​ 
-status = IoGetDeviceObjectPointer(&​filterName,​ STANDARD_RIGHTS_ALL,​ 
-                                  &​ipFileObject,​ &​ipDeviceObject);​ 
-</​code>​ 
-  * Funcția primește ca argumente numele IP filter driver și pointeri la buffer-ele care rețin obiectul dispozitiv și obiectul fișier asociat. 
-  * Construirea IRP-ului de înregistrare folosind [[http://​msdn.microsoft.com/​en-us/​library/​ff548318.aspx|IoBuildDeviceIoControlRequest]]:​ <code c> 
-PDEVICE_OBJECT ipDeviceObject = NULL; 
-PF_SET_EXTENSION_HOOK_INFO filterData; 
-KEVENT event; 
-IO_STATUS_BLOCK ioStatus; 
-PIRP irp; 
- 
-/* get pointer to IP filter driver device object */ 
-//... 
- 
-/* specify the callback filter function */ 
-filterData.ExtensionPointer = cbFilterFunction;​ 
- 
-/* init event that will notify us of the completion of the request */ 
-KeInitializeEvent(&​event,​ NotificationEvent,​ FALSE); 
-irp = IoBuildDeviceIoControlRequest( 
- IOCTL_PF_SET_EXTENSION_POINTER,​ 
- ipDeviceObject,​ 
- (PVOID) &​filterData,​ 
- sizeof (PF_SET_EXTENSION_HOOK_INFO),​ 
- NULL, 
- 0, 
- FALSE, 
- &​event,​ 
- &​ioStatus);​ 
-</​code>​ 
-  * Printre parametrii transmiși se număra: 
-    * valoarea [[http://​msdn.microsoft.com/​en-us/​library/​ff548976(VS.85).aspx|IOCTL_PF_SET_EXTENSION_POINTER]] prin care se specifică hook-ul; 
-    * pointerul la obiectul dispozitiv asociat IP filter driver; 
-    * buffer ce conține o structură [[http://​msdn.microsoft.com/​en-us/​library/​ff562370(VS.85).aspx|PF_SET_EXTENSION_HOOK_INFO]];​ câmpul ''​ExtensionPointer''​ al acestei structuri specifică callback-ul;​ pentru a elibera hook-ul din sistem, aici se poate transmite ''​NULL''​). 
-  * Apelul întoarce IRP-ul de înregistare a hook-ului. 
-  * Transmiterea IRP-ului către IP filter driver folosind [[http://​msdn.microsoft.com/​en-us/​library/​ff548336.aspx|IoCallDriver]]:​ <code c> 
-status = IoCallDriver (ipDeviceObject,​ irp); 
-</​code>​ 
- 
-== Deînregistrare == 
- 
-Pentru deînregistare trebuie construit un IRP pentru care pointerul la structura ''​PF_SET_EXTENSION_HOOK_INFO''​ să fie ''​NULL''​. 
- 
-== IpFilterDriver == 
- 
-Înainte de încărcarea în kernel a unui filter-hook driver trebuie pornit serviciul ''​IpFilterDriver'':​ 
-<​code>​ 
-net start IpFilterDriver 
-</​code>​ 
- 
-O implementare de Filter-Hook driver găsiți la The Code Project: [[http://​www.codeproject.com/​KB/​IP/​drvfltip.aspx|Developing Firewalls for Windows 2000/XP]]. 
- 
-=== Firewall-Hook Driver === 
- 
-Avantajul utilizării [[http://​msdn.microsoft.com/​en-us/​library/​ff546499.aspx|Firewall-Hook driver]] este posibilitatea de inserare a mai multor funcții de filtrare. Fiecare funcție are asociată o anumită prioritate. Sistemul va apela funcțiile în ordinea priorității pâna în momentul în care una din ele întoarce ''​DROP_PACKET''​. 
- 
-== Callback == 
- 
-La fel ca la filter-hook,​ filtrarea se realizează prin intermediul unui callback. Tipul acestuia este ''​IPPacketFirewallPtr'':​ 
-<code c> 
-FORWARD_ACTION cbFilterFunction(VOID **pData, 
-                                UINT RecvInterfaceIndex,​ 
-                                UINT *pSendInterfaceIndex,​ 
-                                UCHAR *pDestinationType,​ 
-                                VOID *pContext, 
-                                UINT ContextLength,​ 
-                                struct IPRcvBuf **pRcvBuf); 
-</​code>​ 
- 
-unde: 
-  *''​pData''​ este un pointer la un buffer de pachet de tipul [[http://​msdn.microsoft.com/​en-us/​library/​aa915349.aspx|struct IPRcvBuf]]; 
-  *''​pContext''​ este un pointer la o structură ''​FIREWALL_CONTEXT_T''​ de unde se pot afla informații despre pachet. 
- 
-Funcția poate întoarce trei valori: 
-  *''​FORWARD'':​ pachetul este admis și este transmis următorului callback; 
-  *''​DROP'':​ pachetul este filtrat (ignorat); 
-  *''​ICMP_ON_DROP'':​ pachetul este filtrat și se transmite un pachet ''​ICMP''​ sistemului de la distanță. 
- 
-Structura [[http://​msdn.microsoft.com/​en-us/​library/​aa915349.aspx|struct IPRcvBuf]] are următorul conținut: 
-<code c> 
-struct IPRcvBuf { 
- /* point to the next buffer in the chain */ 
- struct IPRcvBuf *ipr_next; 
- 
- /* always 0 */ 
- UINT ipr_owner; 
- 
- /* buffer data */ 
- UCHAR *ipr_buffer;​ 
- 
- /* buffer data size */ 
- UINT ipr_size; 
- 
- //... 
-}; 
-</​code>​ 
- 
-Spre deosebire de filter-hook,​ pachetul nu mai este complet asamblat. El va trebui reasamblat urmând pointerul ''​ipr_next''​ la următorul buffer: 
-<code c> 
-FORWARD_ACTION cbFilterFunction(VOID **pData, 
-                                UINT RecvInterfaceIndex,​ 
-                                UINT *pSendInterfaceIndex,​ 
-                                UCHAR *pDestinationType,​ 
-                                VOID *pContext, 
-                                UINT ContextLength,​ 
-                                struct IPRcvBuf **pRcvBuf) 
-{ 
-        char *pPacket = NULL; 
-        int iBufferSize;​ 
-        struct IPRcvBuf *pBuffer = (struct IPRcvBuf *) *pData; 
- 
-        /* total packet size */ 
-        iBufferSize = buffer->​ipr_size;​ 
-        while (pBuffer->​ipr_next != NULL) { 
-                pBuffer = pBuffer->​ipr_next;​ 
-                iBufferSize += pBuffer->​ipr_size;​ 
-        } 
- 
-        /* allocate memory for entire packet */ 
-        pPacket = (char *) ExAllocatePool(NonPagedPool,​ iBufferSize);​ 
-        if (pPacket != NULL) { 
-                unsigned int iOffset = 0; 
-                pBuffer = (struct IPRcvBuf *) *pData; 
- 
-                /* copy all the buffers in the entire packet buffer */ 
-                memcpy(pPacket,​ pBuffer->​ipr_buffer,​ pBuffer->​ipr_size);​ 
-                while(pBuffer->​ipr_next != NULL) { 
-                iOffset += pBuffer->​ipr_size;​ 
-                pBuffer = pBbuffer->​ipr_next;​ 
-                memcpy(pPacket + iOffset, pBuffer->​ipr_buffer,​ 
- pBbuffer->​ipr_size);​ 
-                } 
-        } 
-        //... 
-} 
-</​code>​ 
- 
-== Înregistrare/​deînregistrare == 
- 
-Înregistrarea/​deînregistrarea unui callback se realizează la fel ca la filter-driver. Acum, însa, codul ioctl folosit la crearea IRP-ului este ''​IOCTL_IP_SET_FIREWALL_HOOK'',​ iar structura utilizată este de tip ''​IP_SET_FIREWALL_HOOK_INFO'':​ 
-<code c> 
-typedef struct _IP_SET_FIREWALL_HOOK_INFO { 
- /*  filter callback */ 
- IPPacketFirewallPtr FirewallPtr;​ 
- 
- /* priority of the hook */ 
- UINT Priority; 
- 
- /* if TRUE then ADD else DELETE */ 
- BOOLEAN Add; 
-} IP_SET_FIREWALL_HOOK_INFO,​ *PIP_SET_FIREWALL_HOOK_INFO;​ 
-</​code>​ 
- 
-Pentru înregistarea unui callback câmpul ''​Add''​ al structurii va fi inițializat la ''​TRUE'',​ iar pentru deînregistrare la ''​FALSE'':​ 
-<code c> 
-PDEVICE_OBJECT ipDeviceObject = NULL; 
-IP_SET_FIREWALL_HOOK_INFO filterData; 
-KEVENT event; 
-IO_STATUS_BLOCK ioStatus; 
-PIRP irp; 
- 
-/* get pointer to IP filter driver device object */ 
-//... 
- 
-/* specify the callback filter function */ 
-filterData.FirewallPtr = filterFunction;​ 
-filterData.Priority = 1; 
-filterData.Add = load; 
- 
-KeInitializeEvent(&​event,​ NotificationEvent,​ FALSE); 
- 
-/* build IRP */ 
-irp = IoBuildDeviceIoControlRequest( 
- IOCTL_IP_SET_FIREWALL_HOOK,​ 
- ipDeviceObject,​ 
- (PVOID) &​filterData,​ 
- sizeof (IP_SET_FIREWALL_HOOK_INFO),​ 
- NULL, 
- 0, 
- FALSE, 
- &​event,​ 
- &​ioStatus);​ 
-</​code>​ 
- 
-O implementare de Firewall-Hook driver găsiți la The Code Project: [[http://​www.codeproject.com/​KB/​IP/​FwHookDrv.aspx|An Adventure: How to implement a Firewall-Hook Driver?]] 
- 
-=== Windows Filtering Platform Callout Drivers === 
- 
-Începând cu Windows Vista, implementarea de drivere de filtrare de pachete se va realiza utilizând [[http://​msdn.microsoft.com/​en-us/​library/​ff571068.aspx|Windows Filtering Platform Callout Drivers]]. Aceste drivere sunt construite în cadrul WFP ([[http://​msdn.microsoft.com/​en-us/​library/​ff571066.aspx|Windows Filtering Platform]]) pentru a prelucra pachetele de rețea. 
- 
-==== Conversii ==== 
- 
-La fel ca și pentru Linux, pentru datele primite/​transmise din/în rețea trebuie facută conversia între network byte-order și host byte-order. 
- 
-Pentru conversie există urmatoarele funcții: 
-  *''​USHORT ''​[[http://​msdn.microsoft.com/​en-us/​library/​ff563016.aspx|RtlUshortByteSwap]]''​(USHORT Source)''​ – convertește un întreg pe 16 biți între formatul host byte-order și network byte-order (echivalent pentru ''​ntohs''​ și ''​htons''​) 
-  *''​ULONG ''​[[http://​msdn.microsoft.com/​en-us/​library/​ff562886.aspx|RtlUlongByteSwap]]''​(ULONG ​ Source)''​ – convertește un întreg pe 32 de biți între formatul host byte-order și network byte-order order (echivalent pentru ''​ntohl''​ și ''​htonl''​) 
-===== netcat ===== 
- 
-Cand se dezvolta aplicații care includ o parte de networking, una din cele mai folosite unelte este netcat. Supranumit și "​Swiss-army knife for TCP/​IP",​ netcat permite printre altele: 
-  *Inițierea de conexiuni TCP; 
-  *Așteptarea unei conexiuni TCP; 
-  *Trimiterea și primirea de pachete UDP; 
-  *Afișarea traficului sub forma de hexdump; 
-  *Execuția unui program la stabilirea conexiunii (de exemplu, un shell); 
-  *Setarea unor opțiuni speciale în pachetele trimise. 
- 
-Pentru a iniția o conexiune TCP: 
-<​code>​ 
-nc hostname port 
-</​code>​ 
- 
-Pentru a asculta pe un port TCP: 
-<​code>​ 
-nc -l -p port 
-</​code>​ 
- 
-Primirea și trimiterea pachetelor UDP se realizează adăugând opțiunea ''​-u''​ în linia de comandă. 
- 
-**Observație:​** numele comenzii este ''​nc'';​ de multe ori ''​netcat''​ este un alias pentru această comandă. Există și alte implementări ale comenzii netcat, unele având parametrii puțin diferiți față de implementarea clasică. Consultați ''​man nc''​ sau rulați ''​nc -h''​ pentru a vedea modul de utilizare. 
- 
-Pentru mai multe informații despre netcat, citiți acest [[http://​team5150.com/​~random/​apps/​netcat/​Netcat_Tutorial.pdf|tutorial]]. 
- 
-===== Exerciții ===== 
- 
-<note important>​ 
-  * Toate exercițiile de Linux vor fi realizate în cadrul **mașinii virtuale** de Linux (dacă nu este specificat altfel), iar cele de Windows în cadrul **mașinii virtuale** de Windows. 
-  * Recomandăm să porniți VMware într-un workspace separat. 
-  * Excepție face folosirea LXR, puteți folosi mașina fizică pentru căutări. ​ În cazul folosirii cscope, folosiți mașina virtuală, mai precis directorul ''/​usr/​src/​linux''​. 
-</​note>​ 
- 
-  * Mașinile virtuale pot fi accesate, respectiv, prin Multicast DNS, folosind numele ''​spook.local''​ (Linux) și ''​chooch.local''​ Windows. 
-    * Pentru accesarea mașinilor virtuale puteți folosi SSH. Conturile mașinilor virtuale sunt: 
-      * Linux: root/​student (adică utilizatorul ''​root''​ cu parola ''​student'';​ conectare folosind comanda ''​ssh root@spook.local''​),​ student/​student (''​ssh student@spook.local''​) 
-      * Windows: Administrator/​student (''​ssh Administrator@spook.local''​),​ student/​student (''​ssh student@chooch.local''​) 
-    * Fiind vorba de kernel programming/​driver development veți folosi preponderent conturile privilegiate (''​root''​ respectiv ''​Administrator''​). 
-    * Există create două alias-uri SSH pentru conectare rapidă la mașinile virtuale: 
-      * Linux (root): ''​ssh linux''​ 
-      * Windows (Administrator):​ ''​ssh windows''​ 
-  * Pentru accesarea locală a sistemului de fișiere de pe mașinile virtuale puteți folosi Samba/CIFS, prin intermediul a două scripturi: 
-    * Montarea ''/​root/​share/''​ de pe mașina virtuală Linux în ''/​home/​student/​linux-share/''​ pe sistemul local se face folosind comanda ''​~/​bin/​mount-linux''​. 
-    * Montarea ''/​home/​Administrator/​share/''​ (Cygwin) de pe mașina virtuală Windows în ''/​home/​student/​windows-share/''​ pe sistemul local se face folosind comanda ''​~/​bin/​mount-windows''​. 
- 
-<note warning> 
-Înainte de a rezolva un exercițiu, citiți cu **atenție** toate bullet-urile acestuia. 
-</​note>​ 
- 
-<​note>​ 
-Punctajul maxim obținut este de **10 puncte**. Bonusul poate recupera lipsa de activitate de la alte laboratoare. 
-</​note>​ 
-==== Linux ==== 
- 
-  * Folosiți directorul ''​lin/''​ din [[http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab11-tasks.zip|arhiva de sarcini]] a laboratorului. 
-  * Punctaj total: **6 puncte** 
- 
-<note important>​ 
-  * Pe mașina virtuală de Linux recomandăm:​ 
-    * Conectarea prin SSH de pe sistemul fizic folosind comanda ''​ssh linux''​. 
-    * Folosirea ''​wget''​ pentru descărcarea [[http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab11-tasks.zip | arhivei de sarcini]] a laboratorului. 
-  * În cazul apariției unui oops, reporniți mașina virtuală (sau faceți revert la un snapshot realizat anterior de voi). 
-</​note>​ 
- 
-  - (**2 puncte**) Afișare pachete în kernel space 
-    * Creați un modul de kernel care afișează adresa și portul sursă pentru pachetele TCP care inițiază o conexiune spre exterior. 
-    * Porniți de la scheletul din ''​lin/​1-2-netfilter/''​. 
-      * Completați zonele marcate cu ''​TODO 1''​. 
-    * Înregistrați hook-ul netfilter. 
-      * Parcurgeți secțiunea [[#​netfilter|netfilter]]. 
-      * Va trebui sa folosiți un hook ''​NF_INET_LOCAL_OUT''​. 
-    * Obțineți antetul IP folosind macro-ul [[http://​lxr.free-electrons.com/​source/​include/​uapi/​linux/​ip.h?​v=3.7#​L85|iphdr]],​ iar antetul TCP folosind macro-ul [[http://​lxr.free-electrons.com/​source/​include/​uapi/​linux/​tcp.h?​v=3.7#​L24|tcphdr]]. 
-      * Parcurgeți secțiunea [[#​structura_sk_buff|Structura sk_buff]]. 
-    * Pentru a identifica pachetul de inițiere a unei conexiuni TCP studiați această [[http://​www.eventhelix.com/​Realtimemantra/​Networking/​Tcp.pdf|diagramă]]. 
-      * Pachetul are flagul SYN din antetul TCP activ, iar flagul ACK inactiv. 
-    * Pentru afișarea adresei IP sursă folosiți formatul ''​%pI4''​ al funcției [[https://​www.kernel.org/​doc/​Documentation/​printk-formats.txt|printk]]. 
-    * Portul TCP sursă este, în antentul TCP, în formatul [[http://​en.wikipedia.org/​wiki/​Byte_order#​Endianness_in_networking|network byte-order]]. 
-      * Folosiți [[http://​lxr.free-electrons.com/​source/​include/​linux/​byteorder/​generic.h?​v=3.7#​L141|ntohs]] pentru conversie. 
-      * Parcurgeți secțiunea [[#​conversii|Conversii]]. 
-    * Pentru testare folosiți ''​lin/​1-2-netfilter/​test-1.sh''​. 
-  - (**1 punct**) Precizare adresă destinație. 
-    * Extindeți modulul de la exercițiul 1 astfel încât să permită precizarea unei adrese destinație dorite prin intermediul unei rutine ioctl ''​MY_IOCTL_FILTER_ADDRESS''​. 
-      * Afișați numai acele pachete care conțin adresa destinație precizată. 
-    * Completați zonele marcate cu ''​TODO 2''​. 
-    * Completați funcția ''​my_ioctl''​. 
-      * Revedeți [[:​so2:​laboratoare:​lab04#​ioctl|Laboratorul 4]]. 
-      * Adresa transmisă din user-space este în [[http://​en.wikipedia.org/​wiki/​Endianness#​Endianness_in_networking|network byte-order]]. 
-        * Adresa IP estre trimisă prin adresă, nu prin valoare. 
-      * Stocați adresa IP în variabila ''​ioctl_set_addr''​. 
-    * Completați funcția ''​test_daddr''​ 
-      * Pentru comparație,​ folosiți adresele în network byte-order. 
-    * Apelați funcția ''​test_addr''​ în handler-ul netfilter. 
-      * Afișați doar pachetele de inițiere de conexiune pentru care adresa destinație este cea transmisă prin rutina ioctl. 
-    * Pentru testare folosiți [[http://​www.securitydocs.com/​library/​3376|netcat]] sau scriptul ''​lin/​1-2-netfilter/​test-2.sh''​. 
-      * Scriptul face toți pașii necesari, inclusiv compilarea utilitarului de testare, inserarea și scoaterea modulului. 
-        * (opțional) Pentru setarea adresei din user-space folosiți utilitarul ''​lin/​1-2-netfilter/​test.c''​. 
-        * (opțional) Îl puteți compila cu comanda: ''​make -f Makefile.test''​. 
-    * După rularea testului, în outputul dmesg trebuie să apară **o singură linie** de forma<​code>​ 
-Connection from: 127.0.0.1:​60001 
-</​code>​ 
-      * **Nu** trebuie să apară o linie de forma<​code>​ 
-Connection from: 127.0.0.2:​60001 
-</​code>​ 
-  - (**2 puncte**) Socket TCP în starea listening 
-    * Creați un modul de kernel care creează un socket TCP ce ascultă conexiuni pe portul ''​60000''​ pe interfața de loopback (în ''​init_module''​). 
-    * Folosiți scheletul din ''​lin/​3-4-tcp-sock/''​ din [[http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab11-tasks.zip|arhiva de sarcini]] a laboratorului. 
-      * Completați zonele marcate cu ''​TODO 1''​. 
-    * Creați socketul de tip server și adăugați-l în starea listening. 
-      * Parcurgeți secțiunile [[#​operatii_asupra_structurii_socket|Operații asupra structurii socket]] și [[#​structura_proto_ops|Structura proto_ops]] din laborator. 
-      * Pentru echivalentul ''​bind'',​ ''​listen''​ în kernel-space,​ consultați handler-ele de apel de sistem [[http://​lxr.free-electrons.com/​source/​net/​socket.c#​L1519|sys_bind]] și [[http://​lxr.free-electrons.com/​source/​net/​socket.c#​L1548|sys_listen]]. 
-      * Este vorba de apeluri de forma ''​sock->​ops->​...''​. 
-    * Eliberați socket-ul în funcția de tip exit a modulului. 
-    * Pentru testare, rulați scriptul ''​lin/​3-4-tcp_sock/​test-3.sh''​. 
-      * În urma rulării testului, se va afișa un socket TCP ascultând conexiuni pe portul 60000. 
-  - (**1 punct**) Acceptarea unei conexiuni în kernel space 
-    * Extindeți modulul de la exercițiul anterior pentru a permite acceptarea unei conexiuni din exterior (nu trebuie transmis mesaj, doar acceptată o nouă conexiune). 
-    * Completați zonele marcate cu ''​TODO 2''​. 
-    * Parcurgeți secțiunile [[#​operatii_asupra_structurii_socket|Operații asupra structurii socket]] și [[#​structura_proto_ops|Structura proto_ops]] din laborator. 
-    * Pentru echivalentul ''​accept''​ în kernel-space,​ consultați handler-ul de apel de sistem [[http://​lxr.free-electrons.com/​source/​net/​socket.c#​L1662|sys_accept]] (care este implementat folosind [[http://​lxr.free-electrons.com/​source/​net/​socket.c#​L1581|sys_accept4]]). 
-      * Folosiți ''​0''​ ca valoarea pentru ultimul argument (''​flags''​). 
-    * Afișați adresa și portul socket-ului destinație. 
-    * Pentru a afla numele peer-ului unui socket (adresa sa), consultați handler-ul de apel de sistem [[http://​lxr.free-electrons.com/​source/​net/​socket.c#​L1738|sys_getpeername]]. 
-    * După adăugarea codului care face ''​accept''​ în funcția de inițializare a modulului, operația de ''​insmod''​ se va bloca până se va realiza o conexiune. 
-      * Puteți debloca folosind netcat pe portul respectiv. 
-      * În consecință,​ scriptul de testare de la exercițiul precedent nu va ma funcționa. 
-    * Pentru testarea, adică inițierea unei conexiuni din exterior, folosiți scriptul ''​lin/​3-4-tcp_sock/​test-4.sh''​. 
-      * Nu se va afișa ceva special (în buffer-ul kernel-ului). 
-      * Reușita testului va fi dată de realizarea conexiunii, deblocarea modulului și extragerea modulului din kernel. 
-==== Bonus ==== 
- 
-  - Socket UDP sender 
-    * Creați un modul de kernel care creează un socket UDP și transmite mesajul "​kernelsocket"​ pe socket către adresa loopback pe portul ''​60001''​. 
-    * Porniți de la scheletul ''​lin/​5-udp-sock/''​ din [[http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab11-tasks.zip|arhiva de sarcini]] a laboratorului.. 
-    * Pentru a vedea cum se face transmiterea de mesaje în kernel-space,​ consultați handler-ul de apel de sistem [[http://​lxr.free-electrons.com/​source/​net/​socket.c#​L1818|sys_send]] sau secțiunea [[#​transmitereareceptia_unui_mesaj|Transmiterea/​recepția unui mesaj]]. 
-    * Pentru transmiterea efectiva folosiți [[http://​lxr.free-electrons.com/​source/​net/​socket.c#​L666|kernel_sendmsg]]. 
-    * Parametrii de transmitere a mesajului sunt preluați din kernel-space. 
-    * Pentru deschiderea unui socket UDP pe portul 60001 folosiți [[http://​www.securitydocs.com/​library/​3376|netcat]];​ 
-    * Citiți secțiunile [[#​operatii_asupra_structurii_socket|Operații asupra structurii socket]] și [[#​structura_proto_ops|Structura proto_ops]] din laborator. 
-==== Windows ==== 
- 
-  * Folosiți directorul ''​win/''​ din [[http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab11-tasks.zip|arhiva de sarcini]] a laboratorului. 
-  * Punctaj total: **5 puncte** 
- 
-<note warning> 
-Nu lucrați în directoare care conțin spații (blank). 
-</​note>​ 
-  ​ 
-<note tip> 
-  * Pe mașina virtuală de Windows recomandăm:​ 
-    * Folosirea mașinii virtuale în modul full screen. 
-    * Accesarea tuturor resurselor (browser, LXR) din cadrul mașinii virtuale, fără interacțiune cu sistemul fizic. 
-  * Lucrul cu module de kernel în Windows se realizează din consola DDK (''​Windows Server 2003 Checked x86 Build Environment''​). 
-    * Folosiți icon-ul ''​x86 Checked Build Environment''​ din partea dreaptă a Desktop-ului pentru a deschide consola DDK. 
-  * Recomandăm să lucrați în ''​C:​\Cygwin\home\Administrator\so2''​ sau ''​C:​\Cygwin\home\Administrator\share''​. 
-  * Pentru a folosi Vim în consolele din Windows, folosiți comanda ''​vim-nox''​. 
-  * În cazul apariției unui //Blue Screen of Death// (BSOD), așteptați repornirea mașinii virtuale și apoi porniți ''​WinDbg''​ și din acesta dump-ul de memorie ''​C:​\Windows\MEMORY.DMP''​. 
-    * Folosiți comanda ''​!analyze -v''​ pentru depanare. 
-    * Parcurgeți indicațiile din [[:​so2:​laboratoare:​lab02#​analiza_folosind_memory_dump|laboratorul 2]]. 
-</​note>​ 
- 
-  - (**3 puncte**) Afișare adreselor de pachet în kernel space 
-    * Creați un modul de kernel care afișează adresa și portul sursă pentru pachetele TCP de inițiere de conexiune. 
-      * Puteți folosi [[http://​msdn.microsoft.com/​en-us/​library/​ff546489.aspx|Filter-Hook Driver]] sau [[http://​msdn.microsoft.com/​en-us/​library/​ff546499.aspx|Firewall-Hook Driver]]. 
-        * În cazul Filter-Hook Driver, nu uitați să porniți serviciul ''​IpFilterDriver''​ (''​net start IpFilterDriver''​). 
-    * Folosiți scheletul din ''​win/​1-2-filter/'',​ respectiv ''​win/​1-2-firewall/''​ din [[http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab11-tasks.zip|arhiva de sarcini]] a laboratorului. 
-    * Parcurgeți secțiunile [[#​captura_de_pachete_in_kernel-ul_windows|Captura de pachete în kernel-ul Windows]] și [[#​conversii1|Conversii]] din laborator. 
-    * Completați funcțiile ''​cbFilterFunction'',​ respectiv ''​FilterPacket''​. 
-      * Cele două funcții vor afișa adresa și portul sursă pentru pachetele de inițiere de conexiune. 
-    * Pachetele de inițiere de conexiune sunt cele care au activat flag-ul ''​SYN''​ în antetul TCP și au dezactivat flag-ul ''​ACK''​. 
-    * **Structurile folosite se găsesc în fișierul** ''​win/​include/​NetHeaders.h''​. 
-    * Folosiți pointer-ul ''​iph''​ pentru a referi antetul IP. 
-    * Antetul TCP este dat de argumentul ''​Packet''​. Antetul TCP este reprezentat de tipul de date ''​TCPHeader''​ descris în ''​include/​NetHeaders.h''​. 
-    * Folosiți ''​DbgPrint''​ pentru afișarea adresei sursă și a portului sursă. 
-      * Folosiți macro-urile ''​NIPQUAD''​ și ''​NIPQUAD_FMT''​ pentru afișarea adresei IP/ 
-      * Folosiți o construcție de forma ''"​..."​ NIPQUAD_FMT "​...",​ NIPQUAD(address)''​ unde ''​address''​ este în [[http://​en.wikipedia.org/​wiki/​Endianness#​Endianness_in_networking|network byte-order]]. 
-        * ''​NIPQUAD_FMT''​ este un șir de caractere, nu se pun virgule la concatenarea cu alte siruri de caractere. 
-    * Pentru testare folosiți ''​nc''​. 
-      * Pentru crearea unui port (partea de server) folosiți comanda ''​nc -l -p 5000''​. 
-      * Pentru deschiderea unei conexiuni folosiți (partea de client) comanda ''​nc localhost 5000''​. 
-      * În momentul realizării conexiunii modulul vostru va trebui să afișeze adresa sursă și portul aferent. 
-  - (**2 puncte**) Afișarea unor anumite adrese de pachet în kernel space 
-    * Extindeți modulul de la exercițiul anterior astfel încât să permită precizarea unei adrese destinație dorite prin intermediul unei rutine ioctl ''​MY_IOCTL_FILTER_ADDRESS''​. 
-      * Se afișează numai acele pachete care conțin adresa destinație precizată. 
-    * Parcurgeți secțiunile [[#​captura_de_pachete_in_kernel-ul_windows|Captura de pachete în kernel-ul Windows]] și [[#​conversii1|Conversii]] din laborator. 
-    * Completați funcția ''​testDestinationAddress''​ și apelați-o în cadrul funcțiilor ''​cbFilterFunction'',​ respectiv ''​FilterPacket''​ pentru testarea adresei destinație a unui pachet. 
-    * Completați funcția ''​DeviceIoControl''​ pentru a permite stocarea adresei destinație de test (în cadrul variabilei ''​ioctlSetAddresss''​. 
-    * Pentru testarea modulului folosiți testul din ''​win/​test/''​ din [[http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab11-tasks.zip|arhiva de sarcini]] a laboratorului. 
-      * Fișierul de test permite specificarea adresei care să fie filtrate. Recomandăm specificarea adresei IP aferentă mașinii virtuale. 
-      * Adresa transmisă din user-space este în [[http://​en.wikipedia.org/​wiki/​Endianness#​Endianness_in_networking|network byte-order]]. 
-    * Pentru crearea unui port (partea de server) folosiți comanda ''​nc -l -p 5000''​. 
-    * Pentru deschiderea unei conexiuni care să rezulte în afișarea unui mesaj din cadrul modulului de kernel rulați comanda ''​nc $IP_ADDRESS 5000''​ (unde ''​$IP_ADDRESS''​ este adresa IP a mașinii virtuale). 
-    * Pentru deschiderea unei conexiuni care să **nu** rezulte în afișarea unui mesaj din cadrul modulului de kernel rulați comanda ''​nc ​ localhost 5000''​. 
-==== Soluții ==== 
- 
-  *[[http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab11-sol.zip | Soluții exerciții laborator 11]] 
  
 ===== Resurse utile ===== ===== Resurse utile =====
Line 1198: Line 180:
 ==== Linux ==== ==== Linux ====
  
-  ​* Understanding ​Linux Network Internals +  ​Linux Device Drivers 3rd Edition – [[http://lwn.net/images/pdf/LDD3/​ch15.pdf|Chapter 15. Memory Mapping and DMA]] 
-  * [[http://www.cs.unh.edu/cnrg/gherrin/|Linux IP networking]] +  ​[[http://​www.scs.ch/~frey/linux/memorymap.html|Linux ​- mapping driver memory in user-space]] 
-  ​[[http://​www.ecsl.cs.sunysb.edu/elibrary/linux/network/​LinuxKernel.pdf|Linux ​Networking Kernel]] +  ​[[http://​www.xml.com/ldd/chapter/book/ch13.html|Linux Device Driver mmap Skeleton]] 
-  ​[[http://​www.stllinux.org/meeting_notes/2001/0719/myTUX/|The TUX Web Server]] +  ​[[http://​www.linuxhq.com/guides/TLK/mm/memory.html|The Linux Kernel ​- Memory Management]] 
-  * [[http://​www.beej.us/​guide/​bgnet/​output/​html/multipage/|Beej's Guide to Network Programming Using Internet Sockets]] +  ​[[http://lwn.net/Articles/28746/|Driver portingsupporting mmap()]] 
-  ​[[http://​www.linuxjournal.com/article/7660|Kernel Korner - Network Programming in the Kernel]] +  - [[http://​www.linuxjournal.com/article/1287|Device ​Drivers Concluded]] 
-  * [[http://www.phrack.org/​issues.html?​issue=61&​id=13&​mode=txt|Hacking the Linux Kernel ​Network Stack]] +  ​[[http://​www.ecst.csuchico.edu/~beej/guide/ipc/mmap.html|Memory Mapped Files]] 
-  ​[[http://www.netfilter.org/​|The netfilter.org project]] +  - [[http://en.wikipedia.org/wiki/Mmap|mmap]]
-  * [[http://​www.topsight.net/article.php?​story=2003050621055083|Using Netfilter hooks]] +
-  * [[http://www.6test.edu.cn/​~lujx/​linux_networking/​0131777203_ch19lev1sec3.html|The Netfilter Architecture of Linux 2.4]] +
-  * [[http://​www.linuxfoundation.org/​en/​Net:​Main_Page|Linux Foundation Networking Page]] +
- +
-==== Windows ==== +
- +
-  ​* [[http://​msdn2.microsoft.com/​en-us/​library/​aa973518.aspx|Windows and Windows 2000 Networking]] +
-  * [[http://​www.codeproject.com/kb/system/​driverdev5asp.aspx|Transport ​Device ​Interface]] +
-  ​[[http://​www.codeproject.com/​KB/​IP/​drvfltip.aspx|Developing Firewalls for Windows 2000/XP]] (Filter-Hook Driver example) +
-  * [[http://www.codeproject.com/KB/​IP/​FwHookDrv.aspx|An Adventure: How to implement a Firewall-Hook Driver?]] +
-  ​* [[http://​download.microsoft.com/​download/​9/​8/​f/​98f3fe47-dfc3-4e74-92a3-088782200fe7/​TWNE05008_WinHEC05.ppt|Windows Filtering Platform and Winsock Kernel]] +
-  * [[http://www.acc.umu.se/~bosse/High%20performance%20kernel%20mode%20web%20server%20for%20Windows.pdf| High performance kernel mode web server for Windows]] +
-  * [[http://​www.sockets.com/​winsock.htm|Windows Sockets]]+
so2/laboratoare/lab11.1367999020.txt.gz · Last modified: 2013/05/08 10:43 by razvan.deaconescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0