Differences

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

Link to this comparison view

so2:laboratoare:lab10 [2017/04/23 16:42]
razvan.deaconescu [Cuvinte cheie]
so2:laboratoare:lab10 [2019/05/06 10:20] (current)
liza_elena.babu [Structura socket]
Line 30: Line 30:
 ===== Noțiuni teoretice ===== ===== Noțiuni teoretice =====
  
-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 embedded) să conțină un sistem de operare fără suport de rețea, datorită nevoii de conectivitate. Atâ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ână la nivelul transport inclusiv, urmând ca protocoalele de nivel aplicație să fie implementate în user-space (HTTP, FTP, SSH, etc.).+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 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 embedded) să conțină un sistem de operare fără suport de rețea, datorită nevoii de conectivitate. Atâ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ână la nivelul transport inclusiv, urmând ca protocoalele de nivel aplicație să fie implementate în user-space (HTTP, FTP, SSH, etc.).
  
 ==== Networking în user-space ==== ==== Networking în user-space ====
Line 42: Line 42:
 ===== Linux networking ===== ===== Linux networking =====
  
-Kernel-ul Linux oferă trei structuri fundamentale pentru lucrul cu pachetele de rețea: [[http://lxr.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L101|struct socket]], [[http://lxr.free-electrons.com/​source/​include/​net/​sock.h?v=4.9#L232|struct sock]] și [[http://lxr.free-electrons.com/​source/​include/​linux/​skbuff.h?v=4.9#L565|struct sk_buff]].+Kernel-ul Linux oferă trei structuri fundamentale pentru lucrul cu pachetele de rețea: [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L100|struct socket]], [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​net/​sock.h#​L234|struct sock]] și [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​skbuff.h#​L585|struct sk_buff]].
  
 Primele două reprezintă abstractizări ale unui socket: Primele două reprezintă abstractizări ale unui socket:
-  * [[http://lxr.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L101|struct socket]] este o abstractizare foarte aproape de user-space, adică de [[http://​en.wikipedia.org/​wiki/​Berkeley_sockets|sockeții BSD]] folosiți pentru programarea aplicațiilor de rețea. +  * [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L100|struct socket]] este o abstractizare foarte aproape de user-space, adică de [[http://​en.wikipedia.org/​wiki/​Berkeley_sockets|sockeții BSD]] folosiți pentru programarea aplicațiilor de rețea. 
-  * [[http://lxr.free-electrons.com/​source/​include/​net/​sock.h?v=4.9#L232|struct sock]] sau //INET socket// în terminologia Linux este reprezentarea la nivel rețea a unui socket.+  * [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​net/​sock.h#​L234|struct sock]] sau //INET socket// în terminologia Linux este reprezentarea la nivel rețea a unui socket.
 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. 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.
  
-Structura [[http://lxr.free-electrons.com/​source/​include/​linux/​skbuff.h?v=4.9#L565|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 [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​skbuff.h#​L585|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 socket ==== ==== Structura socket ====
  
-Structura [[http://lxr.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L101|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 sockeții (creare, inițializare/​bind,​ închidere, etc.), rezultă în apeluri de sistem specifice; acestea operează asupra unei structuri de tipul ''​struct socket''​.+Structura [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L100|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 sockeții (creare, inițializare/​bind,​ închidere, etc.), rezultă în apeluri de sistem specifice; acestea operează asupra unei structuri de tipul ''​struct socket''​.
  
-Operațiile asupra [[http://lxr.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L101|struct socket]] sunt descrise în [[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9|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_''​.+Operațiile asupra [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L100|struct socket]] sunt descrise în [[https://elixir.bootlin.com/​linux/​v4.15/​source/​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_''​.
  
 === Operații asupra structurii socket === === Operații asupra structurii socket ===
Line 62: Line 62:
 == Crearea == == Crearea ==
  
-Crearea este asemănătoare apelului ''​socket''​ din user-space, dar socket-ul creat [[http://lxr.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L101|struct socket]], va fi întors în parametrul ''​res'':​ +Crearea este asemănătoare apelului ''​socket''​ din user-space, dar socket-ul creat [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L100|struct socket]], va fi întors în parametrul ''​res'':​ 
-  * ''​int ''​[[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L1206|sock_create]]''​(int family, int type, int protocol, struct socket %%**%%res)''​+  * ''​int ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L1305|sock_create]]''​(int family, int type, int protocol, struct socket %%**%%res)''​
     * funcție apelată pentru crearea unui socket în urma unui apel de sistem ''​socket'';​     * funcție apelată pentru crearea unui socket în urma unui apel de sistem ''​socket'';​
-  * ''​int ''​[[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L1212|sock_create_kern]]''​(int family, int type, int protocol, struct socket %%**%%res)''​+  * ''​int ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L1311|sock_create_kern]]''​(struct net *net, int family, int type, int protocol, struct socket %%**%%res)''​
     * funcție apelată pentru crearea unui socket în kernel;     * funcție apelată pentru crearea unui socket în kernel;
-  * ''​int ''​[[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L970|sock_create_lite]]''​(int family, int type, int protocol, struct socket %%**%%res)''​+  * ''​int ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L1069|sock_create_lite]]''​(int family, int type, int protocol, struct socket %%**%%res)''​
     * funcție '​lite'​ cu eliminarea verificării parametrilor.     * funcție '​lite'​ cu eliminarea verificării parametrilor.
  
 Parametrii acestor apeluri sunt următorii: 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.free-electrons.com/​source/​include/​linux/​socket.h?v=4.9|linux/​socket.h]],​ dintre care cea mai utilizată este ''​PF_INET'',​ pentru protocoalele TCP/IP. +  ​* ''​net'',​ acolo unde este prezent este o referință la namespace-ul de rețea folosit; uzual îl vom inițializa la [[https://​elixir.bootlin.com/​linux/​v4.15/​source/​net/​core/​net_namespace.c#​L37|init_net]];​ 
-  * ''​type''​ reprezintă tipul de socket; constantele utilizate pentru acest parametru se găsesc în [[http://lxr.free-electrons.com/​source/​include/​linux/​net.h?v=4.9|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. +  ​* ''​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 [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​socket.h|linux/​socket.h]],​ dintre care cea mai utilizată este ''​PF_INET'',​ pentru protocoalele TCP/IP. 
-  * ''​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.free-electrons.com/​source/​include/​linux/​in.h?v=4.9|linux/​in.h]],​ dintre care cele mai folosite sunt ''​IPPROTO_TCP''​ pentru TCP și ''​IPPROTO_UDP''​ pentru UDP.+  * ''​type''​ reprezintă tipul de socket; constantele utilizate pentru acest parametru se găsesc în [[https://elixir.bootlin.com/​linux/​v4.15/​source/​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 [[https://elixir.bootlin.com/​linux/​v4.15/​source/​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: Pentru crearea unui socket TCP în kernel se va apela:
 <code c> <code c>
-struct socket *sock; + struct socket *sock; 
-int err; + int err; 
-err = sock_create_kern(PF_INET,​ SOCK_STREAM,​ IPPROTO_TCP,​ &​sock);​ + 
-if(err < 0) { + err = sock_create_kern(&​init_net, ​PF_INET, SOCK_STREAM,​ IPPROTO_TCP,​ &​sock);​ 
-    /* handle error */ + if (err < 0) { 
-}+ /* handle error */ 
 + }
 </​code>​ </​code>​
  
 iar pentru crearea unui socket UDP: iar pentru crearea unui socket UDP:
 <code c> <code c>
-struct socket *sock; + struct socket *sock; 
-int err; + int err; 
-err = sock_create_kern(PF_INET,​ SOCK_DGRAM, IPPROTO_UDP,​ &​sock);​ + 
-if(err < 0) { + err = sock_create_kern(&​init_net, ​PF_INET, SOCK_DGRAM, IPPROTO_UDP,​ &​sock);​ 
-    /* error */ + if (err < 0) { 
-}+ /* handle ​error */ 
 + }
 </​code>​ </​code>​
  
-Un exemplu de utilizare poate fi urmărit în codul handler-ului pentru apelul de sistem [[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L1218|sys_socket]]:​+Un exemplu de utilizare poate fi urmărit în codul handler-ului pentru apelul de sistem [[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L1317|sys_socket]]:​
 <code c> <code c>
 SYSCALL_DEFINE3(socket,​ int, family, int, type, int, protocol) SYSCALL_DEFINE3(socket,​ int, family, int, type, int, protocol)
Line 121: Line 124:
  goto out;  goto out;
  
- retval = sock_map_fd(sock,​ flags & (O_CLOEXEC | O_NONBLOCK))+ return ​sock_map_fd(sock,​ flags & (O_CLOEXEC | O_NONBLOCK));​
- if (retval < 0) +
- goto out_release;​ +
- +
-out: +
- /* It may be already another descriptor 8) Not kernel problem. */ +
- return retval; +
- +
-out_release:​ +
- sock_release(sock);​ +
- return retval;+
 } }
 </​code>​ </​code>​
Line 138: Line 131:
  
 Închiderea conexiunii (pentru socket cu conexiune) și eliberarea resurselor asociate: Închiderea conexiunii (pentru socket cu conexiune) și eliberarea resurselor asociate:
-  * ''​void ''​[[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L571|sock_release]]''​(struct socket *sock)''​ - această funcție va apela funcția ''​release''​ din câmpul ''​ops''​ al structurii socket-ului:​+  * ''​void ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L588|sock_release]]''​(struct socket *sock)''​ - această funcție va apela funcția ''​release''​ din câmpul ''​ops''​ al structurii socket-ului:​
 <code c> <code c>
 void sock_release(struct socket *sock) void sock_release(struct socket *sock)
Line 156: Line 149:
  
 Transmiterea/​recepția mesajelor se face cu ajutorul funcțiilor:​ Transmiterea/​recepția mesajelor se face cu ajutorul funcțiilor:​
-  * ''​int ''​[[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L726|sock_recvmsg]]''​(struct socket *sock, struct msghdr *msg, size_t size, int flags);''​ +  * ''​int ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L814|sock_recvmsg]]''​(struct socket *sock, struct msghdr *msg, int flags);''​ 
-  * ''​int ''​[[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L734|kernel_recvmsg]]''​(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size, int flags);''​ +  * ''​int ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L822|kernel_recvmsg]]''​(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size, int flags);''​ 
-  * ''​int ''​[[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L626|sock_sendmsg]]''​(struct socket *sock, struct msghdr *msg, size_t size);''​ +  * ''​int ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L643|sock_sendmsg]]''​(struct socket *sock, struct msghdr *msg);''​ 
-  * ''​int ''​[[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L635|kernel_sendmsg]]''​(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size);''​+  * ''​int ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L652|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. 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.
  
 Parametrii acestor funcții sunt următorii: Parametrii acestor funcții sunt următorii:
-  * ''​msg'',​ o structura [[http://lxr.free-electrons.com/​source/​include/​linux/​socket.h?v=4.9#L47|struct msghdr]], ce conține mesajul de transmis/​recepționat. Dintre componentele importante ale acestei structuri avem+  * ''​msg'',​ o structura [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​socket.h#​L48|struct msghdr]], ce conține mesajul de transmis/​recepționat. Dintre componentele importante ale acestei structuri avem ''​msg_name'' ​și ''​msg_namelen'',​ carepentru ​sockeți ''​UDP''​trebuie ​completate ​cu adresa la care se transmite mesajul ([[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​uapi/​linux/​in.h#​L229|struct sockaddr_in]]) 
-    * ''​msg_name''​''​msg_namelen'',​ care pentru ​socket-i ''​UDP''​ trebuie ​completați ​cu adresa la care se transmite mesajul ([[http://lxr.free-electrons.com/​source/​include/​uapi/​linux/​in.h?v=4.9#L227|struct sockaddr_in]]) +  * ''​vec'', ​o structură ​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​uio.h#​L19|struct ​kvec]], ce conține un pointer către buffer-ul ce conține datele și dimensiunea acestuia; după cum se poate observaare o structură ​similară cu structura ​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/uapi/​linux/​uio.h#​L17|struct iovec]] (structura [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​uapi/​linux/​uio.h#​L17|struct iovec]] corespunde datelor user space, iar structura ​[[https://​elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​uio.h#​L19|struct ​kvec]] corespunde datelor kernel space)
-    * ''​msg_iov'', ​''​msg_iovlen'',​ datele de transmis, într-un vector de structuri ​[[http://lxr.free-electrons.com/​source/​include/uapi/​linux/​uio.h?v=4.9#L16|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.free-electrons.com/​source/​include/​linux/​uio.h?v=4.9#L18|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.free-electrons.com/​source/​include/​uapi/​linux/​uio.h?v=4.9#L16|struct iovec]] ​(structura ''​iovec'' ​corespunde datelor user space, iar structura ​''​kvec'' ​corespunde datelor kernel space)+
  
-Modul de lucru cu funcțiile de transmitere poate fi urmărit în cadrul handler-ului pentru apelul de sistem [[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L1618|sys_sendto]]:​+Modul de lucru cu funcțiile de transmitere poate fi urmărit în cadrul handler-ului pentru apelul de sistem [[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L1691|sys_sendto]]:​
 <code c> <code c>
 SYSCALL_DEFINE6(sendto,​ int, fd, void __user *, buff, size_t, len, SYSCALL_DEFINE6(sendto,​ int, fd, void __user *, buff, size_t, len,
-                ​unsigned, flags, struct sockaddr __user *, addr, + unsigned ​int, flags, struct sockaddr __user *, addr, 
-                int, addr_len)+ int, addr_len)
 { {
-         struct socket *sock; + struct socket *sock; 
-         char address[MAX_SOCK_ADDR]+ struct sockaddr_storage ​address; 
-         ​int err; + int err; 
-         ​struct msghdr msg; + struct msghdr msg; 
-         ​struct iovec iov; + struct iovec iov; 
-         ​int fput_needed+ int fput_needed;​
-         ​struct file *sock_file;+
  
-         ​sock_file ​fget_light(fd, &fput_needed); + err import_single_range(WRITE, buff, len, &iov, &​msg.msg_iter); 
-         ​err = -EBADF+ if (unlikely(err)) 
-         ​if (!sock_file+ return err; 
-                 ​goto out;+ sock sockfd_lookup_light(fd,​ &err, &​fput_needed)
 + if (!sock
 + goto out;
  
-         sock = sock_from_file(sock_file,​ &​err);​ + msg.msg_name = NULL; 
-         if (!sock) + msg.msg_control = NULL; 
-                 goto out_put; + msg.msg_controllen = 0; 
-         ​iov.iov_base = buff; + msg.msg_namelen = 0; 
-         ​iov.iov_len = len; + if (addr) { 
-         msg.msg_name = NULL; + err = move_addr_to_kernel(addr,​ addr_len, ​&address); 
-         msg.msg_iov = &iov; + if (err < 0) 
-         ​msg.msg_iovlen = 1; + goto out_put; 
-         msg.msg_control = NULL; + msg.msg_name = (struct sockaddr *)&address; 
-         ​msg.msg_controllen = 0; + msg.msg_namelen = addr_len; 
-         ​msg.msg_namelen = 0; +
-         ​if (addr) { + if (sock->​file->​f_flags & O_NONBLOCK) 
-                 ​err = move_addr_to_kernel(addr,​ addr_len, address); + flags |= MSG_DONTWAIT;​ 
-                 ​if (err < 0) + msg.msg_flags = flags; 
-                         ​goto out_put; + err = sock_sendmsg(sock,​ &msg);
-                 ​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: out_put:
-         fput_light(sock_file, fput_needed);​+ fput_light(sock->​file, fput_needed);​
 out: out:
-         return err;+ return err;
 } }
 </​code>​ </​code>​
Line 220: Line 205:
 === Câmpuri ale structurii socket === === Câmpuri ale structurii socket ===
  
-Structura [[http://lxr.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L101|struct socket]]:+Structura [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L100|struct socket]]:
 <code c> <code c>
 /** /**
-  ​*  struct socket - general BSD socket + *  struct socket - general BSD socket 
-  *  @state: socket state (%SS_CONNECTED,​ etc) + ​* ​ @state: socket state (%SS_CONNECTED,​ etc) 
-  *  @type: socket type (%SOCK_STREAM,​ etc) + ​* ​ @type: socket type (%SOCK_STREAM,​ etc) 
-  *  @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc) + ​* ​ @flags: socket flags (%SOCK_NOSPACE, etc) 
-  *  @ops: protocol specific socket operations + ​* ​ @ops: protocol specific socket operations 
-  ​* ​ @fasync_list:​ Asynchronous wake up list + ​* ​ @file: File back pointer for gc 
-  ​*  @file: File back pointer for gc + ​* ​ @sk: internal networking protocol agnostic socket representation 
-  *  @sk: internal networking protocol agnostic socket representation + ​* ​ @wq: wait queue for several uses 
-  *  @wait: wait queue for several uses + */
-  */+
 struct socket { struct socket {
-        ​socket_state ​           state; + socket_state state; 
-        short                   ​type; + 
-        unsigned long           ​flags; + short type; 
-        /* + 
-         * Please keep fasync_list & wait fields in the same cache line + unsigned long flags; 
-         */ + 
-        struct ​fasync_struct ​   ​*fasync_list;​ + struct ​socket_wq __rcu *wq;
-        wait_queue_head_t ​      wait;+
  
-        ​struct file             ​*file; + struct file *file; 
-        struct sock             ​*sk; + struct sock *sk; 
-        const struct proto_ops ​ *ops;+ const struct proto_ops *ops;​
 }; };
 </​code>​ </​code>​
Line 255: Line 238:
 === Structura proto_ops === === Structura proto_ops ===
  
-Structura [[http://lxr.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L136|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.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L101|struct socket]] ([[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L571|sock_release]],​ [[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L626|sock_sendmsg]],​ etc.)+Structura [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L133|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 [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L100|struct socket]] ([[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L588|sock_release]],​ [[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L643|sock_sendmsg]],​ etc.)
  
-Structura [[http://lxr.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L136|struct proto_ops]] conține, așadar, o serie de pointeri de funcții pentru implementări specifice de protocol:+Structura [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L133|struct proto_ops]] conține, așadar, o serie de pointeri de funcții pentru implementări specifice de protocol:
 <code c> <code c>
 struct proto_ops { struct proto_ops {
Line 273: Line 256:
  int (*accept) ​   (struct socket *sock,  int (*accept) ​   (struct socket *sock,
        struct socket *newsock, int flags);        struct socket *newsock, int flags);
 + int (*getname) ​  ​(struct socket *sock,
 +       struct sockaddr *addr,
 +       int peer);
  //...  //...
 </​code>​ </​code>​
  
-Inițializarea câmpului ''​ops''​ din [[http://lxr.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L101|struct socket]] se realizează în funcția [[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L1097|__sock_create]],​ prin apelul funcției [[http://lxr.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L202|create]] specifică protocolului;​ un apel echivalent este următorul:+Inițializarea câmpului ''​ops''​ din [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L100|struct socket]] se realizează în funcția [[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L1196|__sock_create]],​ prin apelul funcției [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L207|create]] specifică protocolului;​ un apel echivalent este cel din [[https://​elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L1267|implementarea funcției __sock_create]]:
 <code c> <code c>
 //... //...
-        if ((err = net_families[family]->​create(net,​ sock, protocol)< 0) { + err = pf->​create(net,​ sock, protocol, kern)
-                ​sock->​ops = NULL; + if (err < 0) 
-                ​goto out_module_put;​ + goto out_module_put;​
-        }+
 //... //...
 </​code>​ </​code>​
  
-Se va realiza astfel instanțierea pointerilor de funcții cu apeluri specifice tipului de protocol asociat socket-ului. Apelurile [[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L2436|sock_register]] și [[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L2469|sock_unregister]] sunt folosite pentru completarea vectorului [[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#​L158|net_families]].+Se va realiza astfel instanțierea pointerilor de funcții cu apeluri specifice tipului de protocol asociat socket-ului. Apelurile [[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L2512|sock_register]] și [[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L2545|sock_unregister]] sunt folosite pentru completarea vectorului [[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L158|net_families]].
  
 Pentru restul operațiilor cu socketi (în afară de creare, închidere și 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: Pentru restul operațiilor cu socketi (în afară de creare, închidere și 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:
Line 293: Line 278:
  
 struct sockaddr_in addr = { struct sockaddr_in addr = {
-    ​.sin_family = AF_INET, + .sin_family = AF_INET, 
-    .sin_port = htons (MY_PORT),​ + .sin_port = htons (MY_PORT),​ 
-    .sin_addr = { htonl (INADDR_LOOPBACK) }+ .sin_addr = { htonl (INADDR_LOOPBACK) }
 }; };
  
 //... //...
- + err = sock->​ops->​bind (sock, (struct sockaddr *) &addr, sizeof(addr));​ 
-err = sock->​ops->​bind (sock, (struct sockaddr *) &addr, sizeof(addr));​ + if (err < 0) { 
-if (err < 0) { + /* handle error */ 
-    /* handle error */ + }
-}+
 //... //...
 </​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.free-electrons.com/​source/​include/​uapi/​linux/​in.h?v=4.9#L227|struct sockaddr_in]]. ((hton* -- despre funcțiile ''​htons'',​ ''​htonl''​ vom discuta la secțiunea [[#​Conversii|Conversii]].))+După cum se poate observa, pentru transmiterea informațiilor legate de adresa și portul care se vor asocia socket-ului,​ se completează o structură [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​uapi/​linux/​in.h#​L229|struct sockaddr_in]]. ((hton* -- despre funcțiile ''​htons'',​ ''​htonl''​ vom discuta la secțiunea [[#​Conversii|Conversii]].))
  
 ==== Structura sock ==== ==== Structura sock ====
  
-Structura [[http://lxr.free-electrons.com/​source/​include/​net/​sock.h?v=4.9#L232|struct sock]] descrie un //INET socket//. O astfel de structură este asociată unui socket creat în user-space și, implicit, unei structuri [[http://​lxr.free-electrons.com/​source/​include/​linux/​net.h?​v=4.9#​L101|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:+Structura [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​net/​sock.h#​L234|struct sock]] descrie un //INET socket//. O astfel de structură este asociată unui socket creat în user-space și, implicit, unei structuri [[http://​lxr.free-electrons.com/​source/​include/​linux/​net.h?​v=4.9#​L101|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:
 <code c> <code c>
 struct sock { struct sock {
  //...  //...
- unsigned ​char sk_protocol; + unsigned ​int sk_padding : 1, 
- unsigned short sk_type;+ sk_no_check_tx : 1, 
 + sk_no_check_rx : 1, 
 + sk_userlocks : 4, 
 + sk_protocol ​ : 8, 
 + sk_type ​     : 16;
  //...  //...
  struct socket *sk_socket;​  struct socket *sk_socket;​
Line 323: Line 311:
  //...  //...
  void (*sk_state_change)(struct sock *sk);  void (*sk_state_change)(struct sock *sk);
- void (*sk_data_ready)(struct sock *sk, int bytes);+ void (*sk_data_ready)(struct sock *sk);
  void (*sk_write_space)(struct sock *sk);  void (*sk_write_space)(struct sock *sk);
  void (*sk_error_report)(struct sock *sk);  void (*sk_error_report)(struct sock *sk);
-  int (*sk_backlog_rcv)(struct sock *sk,+ int (*sk_backlog_rcv)(struct sock *sk,
   ​ struct sk_buff *skb);   ​ struct sk_buff *skb);
  void                    (*sk_destruct)(struct sock *sk);  void                    (*sk_destruct)(struct sock *sk);
Line 338: Line 326:
   * pointerii de funcții de la sfârșit sunt callback-uri pentru diverse situații.   * 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.free-electrons.com/​source/​include/​linux/​net.h?v=4.9#L202|create]] din [[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#​L158|net_families]] (apelat in [[http://lxr.free-electrons.com/​source/​net/​socket.c?v=4.9#L1097|__sock_create]]). Mai jos este prezentat modul de +Inițializarea ''​struct sock''​ și atașarea acesteia la un socket BSD se face cu ajutorul callback-ului [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​net.h#​L207|create]] din [[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L158|net_families]] (apelat in [[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​socket.c#​L1196|__sock_create]]). Mai jos este prezentat modul de 
-inițializare a structurii ''​struct sock''​ pentru protocolul IP, în cadrul funcției [[http://lxr.free-electrons.com/​source/​net/​ipv4/​af_inet.c?v=4.9#L240|inet_create]]:​+inițializare a structurii ''​struct sock''​ pentru protocolul IP, în cadrul funcției [[https://elixir.bootlin.com/​linux/​v4.15/​source/​net/​ipv4/​af_inet.c#​L241|inet_create]]:​
 <code c> <code c>
 /* /*
-  ​* Create an inet socket. + * Create an inet socket. 
-  */+ */
  
-static int inet_create(struct net *net, struct socket *sock, int protocol)+static int inet_create(struct net *net, struct socket *sock, int protocol
 +        int kern)
 { {
 +
  struct sock *sk;  struct sock *sk;
  
  //...  //...
  err = -ENOBUFS;  err = -ENOBUFS;
- sk = sk_alloc(net,​ PF_INET, GFP_KERNEL, answer_prot);​ + sk = sk_alloc(net,​ PF_INET, GFP_KERNEL, answer_prot, kern); 
- if (sk == NULL)+ if (!sk)
  goto out;  goto out;
  
  err = 0;  err = 0;
- sk->​sk_no_check = answer_no_check;​ 
  if (INET_PROTOSW_REUSE & answer_flags)  if (INET_PROTOSW_REUSE & answer_flags)
- sk->​sk_reuse = 1;+ sk->​sk_reuse = SK_CAN_REUSE; 
  
  //...  //...
Line 364: Line 354:
  
  sk->​sk_destruct  ​  = inet_sock_destruct;​  sk->​sk_destruct  ​  = inet_sock_destruct;​
- sk->​sk_family  ​  = PF_INET; 
  sk->​sk_protocol  ​  = protocol;  sk->​sk_protocol  ​  = protocol;
  sk->​sk_backlog_rcv = sk->​sk_prot->​backlog_rcv;​  sk->​sk_backlog_rcv = sk->​sk_prot->​backlog_rcv;​
Line 373: Line 362:
 ==== Structura sk_buff ==== ==== Structura sk_buff ====
  
-Structura [[http://lxr.free-electrons.com/​source/​include/​linux/​skbuff.h?v=4.9#L565|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:+Structura [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​skbuff.h#​L585|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> <code c>
- struct sk_buff { +struct sk_buff { 
-         ​/* These two members must be first. */ + union { 
-         ​struct sk_buff ​         *next; + struct { 
-         ​struct sk_buff ​         *prev;+ /* These two members must be first. */ 
 + struct sk_buff *next; 
 + struct sk_buff *prev;
  
-         struct ​sock             *sk+ union { 
-         ktime_t ​                ​tstamp;​ + struct ​net_device *dev
-         struct net_device ​      *dev;+ /* Some protocols might use this space to store information,​ 
 +  while device pointer would be NULL. 
 + * UDP receive path is one user. 
 + */ 
 + unsigned long dev_scratch;​ 
 + }; 
 + };
  
-         struct ​ ​dst_entry ​      *dst+ struct ​rb_node rbnode;​ /used in netem & tcp stack */ 
-         ​struct ​ ​sec_path ​       ​*sp;+ }
 + struct ​sock *sk;
  
-         /* +        union { 
-          * This is the control buffer. It is free to use for every +  ​ ktime_t tstamp;​ 
-          * layer. Please put your private variables there. If you + u64 skb_mstamp;​ 
-          * 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; +  * This is the control buffer. It is free to use for every 
-         __u16                   ​mac_len,​ +  * layer. Please put your private variables there. If you 
-                                 hdr_len;+  * 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] __aligned(8);
  
-         /* ... */+ unsigned long _skb_refdst;​ 
 + void (*destructor)(struct sk_buff *skb); 
 +        union { 
 +         ​ struct { 
 +  unsigned long _skb_refdst;​ 
 + void (*destructor)(struct sk_buff *skb); 
 + }; 
 + struct list_head tcp_tsorted_anchor;​ 
 + }; 
 + /* ... */
  
-         ​void ​                   (*destructor)(struct sk_buff *skb);+ unsigned int len, 
 + data_len;​ 
 + __u16 mac_len,​ 
 + hdr_len;
  
          /* ... */          /* ... */
  
-         ​sk_buff_data_t ​         ​transport_header;​ + __be16 protocol;​ 
-         sk_buff_data_t ​         ​network_header;​ + __u16 transport_header;​ 
-         sk_buff_data_t ​         ​mac_header;+ __u16 network_header;​ 
 + __u16 mac_header;
  
-         /* These elements must be at the end, see alloc_skb() for details. ​ */ + /* private: */ 
-         ​sk_buff_data_t ​         tail; + __u32 headers_end[0];​ 
-         ​sk_buff_data_t ​         end; + /* public: */ 
-         ​unsigned char           ​*head, + 
-                                 ​*data; + /* These elements must be at the end, see alloc_skb() for details. ​ */ 
-         ​unsigned int            truesize; + sk_buff_data_t tail; 
-         atomic_t ​               ​users; + sk_buff_data_t end; 
- };+ unsigned char *head, 
 + *data; 
 + unsigned int truesize; 
 + refcount_t users; 
 +};
 </​code>​ </​code>​
  
Line 425: Line 440:
   * ''​sk''​ este socket-ul asociat buffer-ului;​   * ''​sk''​ este socket-ul asociat buffer-ului;​
   * ''​destructor''​ este apelul callback de dealocare a 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 headere, folosiți una din următoarele funcții: [[http://lxr.free-electrons.com/​source/​include/​linux/​tcp.h?v=4.9#​L28|tcp_hdr]],​ [[http://lxr.free-electrons.com/​source/​include/​linux/​udp.h?v=4.9#​L25|udp_hdr]],​ [[http://lxr.free-electrons.com/​source/​include/​linux/​ip.h?v=4.9#​L23|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țea, iar câmpul ''​transport_header''​ nu este setat decât după ce pachetul ajunge la nivelul transport.+  * ''​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 headere, folosiți una din următoarele funcții: [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​tcp.h#​L28|tcp_hdr]],​ [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​udp.h#​L25|udp_hdr]],​ [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​ip.h#​L23|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țea, iar câmpul ''​transport_header''​ nu este setat decât după ce pachetul ajunge la nivelul transport.
  
-Structura unui [[https://​en.wikipedia.org/​wiki/​IPv4#​Header|antet IP]] ([[http://lxr.free-electrons.com/​source/​include/​uapi/​linux/​ip.h?v=4.9#L85|struct iphdr]]) are următoarele câmpuri:+Structura unui [[https://​en.wikipedia.org/​wiki/​IPv4#​Header|antet IP]] ([[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​uapi/​linux/​ip.h#​L86|struct iphdr]]) are următoarele câmpuri:
 <code c> <code c>
 struct iphdr { struct iphdr {
 #if defined(__LITTLE_ENDIAN_BITFIELD) #if defined(__LITTLE_ENDIAN_BITFIELD)
-         __u8    ihl:4, + __u8 ihl:​4,​ 
-                 ​version:4;+ version:4;
 #elif defined (__BIG_ENDIAN_BITFIELD) #elif defined (__BIG_ENDIAN_BITFIELD)
-         __u8    version:​4,​ + __u8 version:​4,​ 
-                 ​ihl:4;+   ihl:4;
 #else #else
-#​error ​ "​Please fix <​asm/​byteorder.h>"​+#​error "​Please fix <​asm/​byteorder.h>"​
 #endif #endif
-         __u8    tos; + __u8 tos; 
-         ​__be16 ​ tot_len; + __be16 tot_len;​ 
-         ​__be16 ​ id; + __be16 id;​ 
-         ​__be16 ​ frag_off; + __be16 frag_off;​ 
-         ​__u8    ttl; + __u8 ttl;​ 
-         ​__u8    protocol; + __u8 protocol;​ 
-         ​__sum16 check; + __sum16 check;​ 
-         ​__be32 ​ saddr; + __be32 saddr;​ 
-         ​__be32 ​ daddr; + __be32 daddr;​ 
-         ​/*The options start here. */+ /*The options start here. */
 }; };
 </​code>​ </​code>​
Line 457: Line 472:
   * ''​daddr''​ reprezintă adresa IP a nodului destinație.   * ''​daddr''​ reprezintă adresa IP a nodului destinație.
  
-Structura unui [[https://​en.wikipedia.org/​wiki/​Transmission_Control_Protocol#​TCP_segment_structure|antet TCP]] ([[http://lxr.free-electrons.com/​source/​include/​uapi/​linux/​tcp.h?v=4.9#L24|struct tcphdr]]) are următoarele câmpuri:+Structura unui [[https://​en.wikipedia.org/​wiki/​Transmission_Control_Protocol#​TCP_segment_structure|antet TCP]] ([[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​uapi/​linux/​tcp.h#​L25|struct tcphdr]]) are următoarele câmpuri:
 <code c> <code c>
 struct tcphdr { struct tcphdr {
-         __be16 ​ source; + __be16 source;​ 
-         ​__be16 ​ dest; + __be16 dest;​ 
-         ​__be32 ​ seq; + __be32 seq;​ 
-         ​__be32 ​ ack_seq;+ __be32 ack_seq;​
 #if defined(__LITTLE_ENDIAN_BITFIELD) #if defined(__LITTLE_ENDIAN_BITFIELD)
-         __u16   ​res1:4, + __u16 res1:​4,​ 
-                 ​doff:4, + doff:4, 
-                 ​fin:1, + fin:1, 
-                 ​syn:1, + syn:1, 
-                 ​rst:1, + rst:1, 
-                 ​psh:1, + psh:1, 
-                 ​ack:1, + ack:1, 
-                 ​urg:1, + urg:1, 
-                 ​ece:1, + ece:1, 
-                 ​cwr:1;+ cwr:1;
 #elif defined(__BIG_ENDIAN_BITFIELD) #elif defined(__BIG_ENDIAN_BITFIELD)
-         __u16   ​doff:4, + __u16 doff:​4,​ 
-                 ​res1:4, + res1:4, 
-                 ​cwr:1, + cwr:1, 
-                 ​ece:1, + ece:1, 
-                 ​urg:1, + urg:1, 
-                 ​ack:1, + ack:1, 
-                 ​psh:1, + psh:1, 
-                 ​rst:1, + rst:1, 
-                 ​syn:1, + syn:1, 
-                 ​fin:1;+ fin:1;
 #else #else
-#​error ​ "​Adjust your <​asm/​byteorder.h>​ defines"​ +#​error "​Adjust your <​asm/​byteorder.h>​ defines"​ 
-#endif +#endif  
-         ​__be16 ​ window; + __be16 window;​ 
-         ​__sum16 check; + __sum16 check;​ 
-         ​__be16 ​ urg_ptr;+ __be16 urg_ptr;​
 }; };
 </​code>​ </​code>​
Line 498: Line 513:
   * ''​syn'',​ ''​ack'',​ ''​fin''​ sunt flag-uri folosite în protocolul TCP; pentru detalii studiați această [[http://​www.eventhelix.com/​Realtimemantra/​Networking/​Tcp.pdf|diagramă]].   * ''​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 [[https://​en.wikipedia.org/​wiki/​User_Datagram_Protocol#​Packet_structure|antet UDP]] ([[http://lxr.free-electrons.com/​source/​include/​uapi/​linux/​udp.h?v=4.9#L22|struct udphdr]]) are următoarele câmpuri:+Structura unui [[https://​en.wikipedia.org/​wiki/​User_Datagram_Protocol#​Packet_structure|antet UDP]] ([[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​uapi/​linux/​udp.h#​L23|struct udphdr]]) are următoarele câmpuri:
 <code c> <code c>
 struct udphdr { struct udphdr {
-         __be16 ​ source; + __be16 source;​ 
-         ​__be16 ​ dest; + __be16 dest;​ 
-         ​__be16 ​ len; + __be16 len;​ 
-         ​__sum16 check;+ __sum16 check;​
 }; };
 </​code>​ </​code>​
Line 512: Line 527:
 Un exemplu de accesare a informațiilor prezente în antetele unui pachet de rețea este următorul: Un exemplu de accesare a informațiilor prezente în antetele unui pachet de rețea este următorul:
 <code c> <code c>
-struct sk_buff *skb;+ struct sk_buff *skb;
  
-struct iphdr *iph = ip_hdr(skb); ​                /* IP header */ + struct iphdr *iph = ip_hdr(skb); ​                /* IP header */ 
-/* iph->​saddr ​ - source IP address */ + /* iph->​saddr ​ - source IP address */ 
-/* iph->​daddr ​ - destination IP address */ + /* iph->​daddr ​ - destination IP address */ 
-if (iph->​protocol == IPPROTO_TCP) {              /* TCP protocol */ + if (iph->​protocol == IPPROTO_TCP) {              /* TCP protocol */ 
-    struct tcphdr *tcph = tcp_hdr(skb); ​         /* TCP header */ + struct tcphdr *tcph = tcp_hdr(skb); ​         /* TCP header */ 
-    /* tcph->​source ​ - source TCP port */ + /* tcph->​source ​ - source TCP port */ 
-    /* tcph->​dest ​   - destination TCP port */ + /* tcph->​dest ​   - destination TCP port */ 
-} else if (iph->​protocol == IPPROTO_UDP) {       /* UDP protocol */ + } else if (iph->​protocol == IPPROTO_UDP) {       /* UDP protocol */ 
-    struct udphdr *udph = udp_hdr(skb); ​         /* UDP header */ + struct udphdr *udph = udp_hdr(skb); ​         /* UDP header */ 
-    /* udph->​source ​ - source UDP port */ + /* udph->​source ​ - source UDP port */ 
-    /* udph->​dest ​   - destination UDP port */ + /* udph->​dest ​   - destination UDP port */ 
-}+ }
 </​code>​ </​code>​
  
Line 533: Line 548:
  
 Pentru conversie există urmatoarele macrodefiniții:​ Pentru conversie există urmatoarele macrodefiniții:​
-  * ''​u16 ''​[[http://lxr.free-electrons.com/​source/​include/​linux/​byteorder/​generic.h?v=4.9#L140|htons]]''​(u16 x)''​+  * ''​u16 ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​byteorder/​generic.h#​L141|htons]]''​(u16 x)''​
     * convertește un întreg pe 16 biți din host byte-order în network byte-order (//host to network short//)     * convertește un întreg pe 16 biți din host byte-order în network byte-order (//host to network short//)
-  * ''​u32 ''​[[http://lxr.free-electrons.com/​source/​include/​linux/​byteorder/​generic.h?v=4.9#L138|htonl]]''​(u32 x)''​+  * ''​u32 ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​byteorder/​generic.h#​L139|htonl]]''​(u32 x)''​
     * convertește un întreg pe 32 de biți din host byte-order în network byte-order (//host to network long//)     * convertește un întreg pe 32 de biți din host byte-order în network byte-order (//host to network long//)
-  * ''​u16 ''​[[http://lxr.free-electrons.com/​source/​include/​linux/​byteorder/​generic.h?v=4.9#​L141|ntohs]]''​(u16 x)''​+  * ''​u16 ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​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//)     * convertește un întreg pe 16 biți din network byte-order în host byte-order (//network to host short//)
-  * ''​u32 ''​[[http://lxr.free-electrons.com/​source/​include/​linux/​byteorder/​generic.h?v=4.9#​L139|ntohl]]''​(u32 x)''​+  * ''​u32 ''​[[https://elixir.bootlin.com/​linux/​v4.15/​source/​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//)     * convertește un întreg pe 32 de biți din network byte-order în host byte-order (//network to host long//)
  
Line 548: Line 563:
 Î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]]. Î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.free-electrons.com/​source/​include/​linux/​netfilter.h?v=4.9|linux/​netfilter.h]].+Header-ul inclus atunci când se folosește netfilter este [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​netfilter.h|linux/​netfilter.h]].
  
-Un hook se definește prin intermediul structurii [[http://lxr.free-electrons.com/​source/​include/​linux/​netfilter.h?v=4.9#L65|struct nf_hook_ops]]:​ <code c>+Un hook se definește prin intermediul structurii [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​netfilter.h#​L64|struct nf_hook_ops]]:​ <code c>
 struct nf_hook_ops { struct nf_hook_ops {
- struct list_head ​       list; 
- 
  /* User fills in from here down. */  /* User fills in from here down. */
  nf_hookfn ​              ​*hook;​  nf_hookfn ​              ​*hook;​
Line 565: Line 578:
 </​code>​ </​code>​
  
-În cadrul structurii [[http://lxr.free-electrons.com/​source/​include/​linux/​netfilter.h?v=4.9#L65|struct nf_hook_ops]],​ ''​pf''​ este tipul pachetului ([[http://lxr.free-electrons.com/​source/​include/​linux/​socket.h?v=4.9#L212|PF_INET]], etc.). ''​priority''​ este prioritatea;​ prioritățile sunt definite în [[http://lxr.free-electrons.com/​source/​include/​uapi/​linux/​netfilter_ipv4.h?v=4.9|uapi/​linux/​netfilter_ipv4.h]]:<​code c>+În cadrul structurii [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​netfilter.h#​L64|struct nf_hook_ops]],​ ''​pf''​ este tipul pachetului ([[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​socket.h#​L217|PF_INET]], etc.). ''​priority''​ este prioritatea;​ prioritățile sunt definite în [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​uapi/​linux/​netfilter_ipv4.h|uapi/​linux/​netfilter_ipv4.h]]:<​code c>
 enum nf_ip_hook_priorities { enum nf_ip_hook_priorities {
  NF_IP_PRI_FIRST = INT_MIN,  NF_IP_PRI_FIRST = INT_MIN,
Line 586: Line 599:
 ''​net_device''​ reprezintă dispozitivul (interfața de rețea) pe care se dorește realizată captura. ''​net_device''​ reprezintă dispozitivul (interfața de rețea) pe care se dorește realizată captura.
  
-În momentul în care un pachet este capturat, modul de prelucrare este definit de câmpurile ''​hooknum''​ și ''​hook''​. ''​hooknum''​ este tipul de hook utilizat; pentru IP, tipurile de hook-uri sunt definite în [[http://lxr.free-electrons.com/​source/​include/​uapi/​linux/​netfilter.h?v=4.9|linux/​netfilter.h]]:<​code c>+În momentul în care un pachet este capturat, modul de prelucrare este definit de câmpurile ''​hooknum''​ și ''​hook''​. ''​hooknum''​ este tipul de hook utilizat; pentru IP, tipurile de hook-uri sunt definite în [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​uapi/​linux/​netfilter.h|linux/​netfilter.h]]:<​code c>
 enum nf_inet_hooks { enum nf_inet_hooks {
  NF_INET_PRE_ROUTING,​  NF_INET_PRE_ROUTING,​
Line 597: Line 610:
 </​code>​ </​code>​
  
-''​hook''​ este handler-ul apelat in momentul capturării unui pachet de rețea (pachet transmis în forma unei structuri ''​struct sk_buff''​). Câmpul ''​priv''​ reprezintă o informație privată transmisă handler-ului. Prototipul handler-ului de captură este definit de tipul [[http://lxr.free-electrons.com/​source/​include/​linux/​netfilter.h?v=4.9#L62|nf_hookfn]]:​ <code c>+''​hook''​ este handler-ul apelat in momentul capturării unui pachet de rețea (pachet transmis în forma unei structuri ''​struct sk_buff''​). Câmpul ''​priv''​ reprezintă o informație privată transmisă handler-ului. Prototipul handler-ului de captură este definit de tipul [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​netfilter.h#​L61|nf_hookfn]]:​ <code c>
 struct nf_hook_state { struct nf_hook_state {
  unsigned int hook;  unsigned int hook;
- int thresh; 
  u_int8_t pf;  u_int8_t pf;
  struct net_device *in;  struct net_device *in;
Line 606: Line 618:
  struct sock *sk;  struct sock *sk;
  struct net *net;  struct net *net;
- struct nf_hook_entry __rcu *hook_entries;​ 
  int (*okfn)(struct net *, struct sock *, struct sk_buff *);  int (*okfn)(struct net *, struct sock *, struct sk_buff *);
 }; };
Line 616: Line 627:
 </​code>​ </​code>​
  
-În cazul funcției de captură de tipul [[http://lxr.free-electrons.com/​source/​include/​linux/​netfilter.h?v=4.9#L62|nf_hookfn]],​ câmpul ''​priv''​ reprezintă informația privată cu care a fost inițializată structura de tipul [[http://lxr.free-electrons.com/​source/​include/​linux/​netfilter.h?v=4.9#L65|struct nf_hook_ops]]. ''​skb''​ este pointer la pachet-ul de rețea capturat; pe baza informațiilor din ''​skb''​ se iau deciziile de filtrare a pachetului. Parametrul ''​state''​ al funcției reprezintă informațiile de stare legate de captura pachetului, incluzând interfața de intrare, interfața de ieșire, prioritatea,​ numărul hook-ului. Prioritatea și numărul hook-ului sunt utile pentru a permite ca aceeași funcție să fie apelată de mai multe hook-uri.+În cazul funcției de captură de tipul [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​netfilter.h#​L61|nf_hookfn]],​ câmpul ''​priv''​ reprezintă informația privată cu care a fost inițializată structura de tipul [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​netfilter.h#​L64|struct nf_hook_ops]]. ''​skb''​ este pointer la pachet-ul de rețea capturat; pe baza informațiilor din ''​skb''​ se iau deciziile de filtrare a pachetului. Parametrul ''​state''​ al funcției reprezintă informațiile de stare legate de captura pachetului, incluzând interfața de intrare, interfața de ieșire, prioritatea,​ numărul hook-ului. Prioritatea și numărul hook-ului sunt utile pentru a permite ca aceeași funcție să fie apelată de mai multe hook-uri.
  
-Un handler de captură poate întoarce una din [[http://lxr.free-electrons.com/​source/​include/​uapi/​linux/​netfilter.h?v=4.9#​L10|constantele NF_*]]: <code c>+Un handler de captură poate întoarce una din [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​uapi/​linux/​netfilter.h#​L10|constantele NF_*]]: <code c>
 /* Responses from hook functions. */ /* Responses from hook functions. */
 #define NF_DROP 0 #define NF_DROP 0
Line 631: Line 642:
 ''​NF_DROP''​ este folosit pentru a filtra (ignora) un pachet, iar ''​NF_ACCEPT''​ este folosit pentru a accepta un pachet și a-l transmite mai departe. ''​NF_DROP''​ este folosit pentru a filtra (ignora) un 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.free-electrons.com/​source/​include/​linux/​netfilter.h?v=4.9|linux/​netfilter.h]]:​ <code c>+Înregistrarea/​deînregistrarea unui hook se realizează cu ajutorul funcțiilor definite în [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​netfilter.h|linux/​netfilter.h]]:​ <code c>
 /* Function to register/​unregister hook points. */ /* Function to register/​unregister hook points. */
-int nf_register_hook(struct nf_hook_ops *reg); +int nf_register_net_hook(struct net *net, const struct nf_hook_ops *ops); 
-void nf_unregister_hook(struct nf_hook_ops *reg); +void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *ops); 
-int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n); +int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg, 
-void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);+   ​unsigned int n); 
 +void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg, 
 +      unsigned int n);
 </​code>​ </​code>​
  
Line 679: Line 692:
 int __init my_hook_init(void) int __init my_hook_init(void)
 { {
- return ​nf_register_hook(&​my_nfho);​+ return ​nf_register_net_hook(&​init_net, ​&​my_nfho);​
 } }
  
 void __exit my_hook_exit(void) void __exit my_hook_exit(void)
 { {
- nf_unregister_hook(&​my_nfho);​+ nf_unregister_net_hook(&​init_net, ​&​my_nfho); ​
 } }
  
Line 715: Line 728:
 **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. **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]].+Pentru mai multe informații despre netcat, citiți acest [[https://www.win.tue.nl/~aeb/linux/hh/netcat_tutorial.pdf|tutorial]].
  
 ===== Resurse utile ===== ===== Resurse utile =====
Line 721: Line 734:
   * Understanding Linux Network Internals   * Understanding Linux Network Internals
   * [[http://​www.cs.unh.edu/​cnrg/​gherrin/​|Linux IP networking]]   * [[http://​www.cs.unh.edu/​cnrg/​gherrin/​|Linux IP networking]]
-  * [[http://​www.ecsl.cs.sunysb.edu/​elibrary/​linux/​network/​LinuxKernel.pdf|Linux Networking Kernel]] 
   * [[http://​www.stllinux.org/​meeting_notes/​2001/​0719/​myTUX/​|The TUX Web Server]]   * [[http://​www.stllinux.org/​meeting_notes/​2001/​0719/​myTUX/​|The TUX Web Server]]
-  * [[http://www.beej.us/guide/bgnet/output/html/multipage/|Beej'​s Guide to Network Programming Using Internet Sockets]]+  * [[http://​beej.us/​net2/bgnet.html|Beej'​s Guide to Network Programming Using Internet Sockets]]
   * [[http://​www.linuxjournal.com/​article/​7660|Kernel Korner - Network Programming in the Kernel]]   * [[http://​www.linuxjournal.com/​article/​7660|Kernel Korner - Network Programming in the Kernel]]
-  * [[http://www.phrack.org/​issues.html?​issue=61&id=13&​mode=txt|Hacking the Linux Kernel Network Stack]]+  * [[http://​phrack.org/​issues/61/13.html|Hacking the Linux Kernel Network Stack]]
   * [[http://​www.netfilter.org/​|The netfilter.org project]]   * [[http://​www.netfilter.org/​|The netfilter.org project]]
-  * [[http://www.topsight.net/article.php?​story=2003050621055083|Using Netfilter hooks]] +  * [[https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture|A Deep Dive Into Iptables and Netfilter Architecture]]
-  * [[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]]   * [[http://​www.linuxfoundation.org/​en/​Net:​Main_Page|Linux Foundation Networking Page]]
  
so2/laboratoare/lab10.1492954978.txt.gz · Last modified: 2017/04/23 16:42 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