[Avanti]  [Indietro]  [Su]  

14.3.6 La struttura degli indirizzi dei packet socket

I packet socket, identificati dal dominio PF_PACKET, sono un'interfaccia specifica di Linux per inviare e ricevere pacchetti direttamente su un'interfaccia di rete, senza passare per le routine di gestione dei protocolli di livello superiore. In questo modo è possibile implementare dei protocolli in user space, agendo direttamente sul livello fisico. In genere comunque si preferisce usare la libreria pcap, che assicura la portabilità su altre piattaforme, anche se con funzionalità ridotte.

Questi socket possono essere di tipo SOCK_RAW o SOCK_DGRAM. Con socket di tipo SOCK_RAW si può operare sul livello di collegamento, ed i pacchetti vengono passati direttamente dal socket al driver del dispositivo e viceversa. In questo modo, in fase di trasmissione, il contenuto completo dei pacchetti, comprese le varie intestazioni, deve essere fornito dall'utente. In fase di ricezione invece tutto il contenuto del pacchetto viene passato inalterato sul socket, anche se il kernel analizza comunque il pacchetto, riempiendo gli opportuni campi della struttura sockaddr_ll ad esso associata.

Si usano invece socket di tipo SOCK_DGRAM quando si vuole operare a livello di rete. In questo caso in fase di ricezione l'intestazione del protocollo di collegamento viene rimossa prima di passare il resto del pacchetto all'utente, mentre in fase di trasmissione viene creata una opportuna intestazione per il protocollo a livello di collegamento utilizzato, usando le informazioni necessarie che devono essere specificate sempre con una struttura sockaddr_ll.

Nella creazione di un packet socket il valore dell'argomento protocol di socket serve a specificare, in network order, il numero identificativo del protocollo di collegamento si vuole utilizzare. I valori possibili sono definiti secondo lo standard IEEE 802.3, e quelli disponibili in Linux sono accessibili attraverso opportune costanti simboliche definite nel file linux/if_ether.h. Se si usa il valore speciale ETH_P_ALL passeranno sul packet socket tutti i pacchetti, qualunque sia il loro protocollo di collegamento. Ovviamente l'uso di questi socket è una operazione privilegiata e può essere effettuati solo da un processo con i privilegi di amministratore (user-ID effettivo nullo) o con la capability CAP_NET_RAW.

Una volta aperto un packet socket, tutti i pacchetti del protocollo specificato passeranno attraverso di esso, qualunque sia l'interfaccia da cui provengono; se si vuole limitare il passaggio ad una interfaccia specifica occorre usare la funzione bind per agganciare il socket a quest'ultima.


1: struct sockaddr_ll { 
2:     unsigned short  sll_family;    /* Always AF_PACKET */ 
3:     unsigned short  sll_protocol;  /* Physical layer protocol */ 
4:     int             sll_ifindex;   /* Interface number */ 
5:     unsigned short  sll_hatype;    /* Header type */ 
6:     unsigned char   sll_pkttype;   /* Packet type */ 
7:     unsigned char   sll_halen;     /* Length of address */ 
8:     unsigned char   sll_addr[8];   /* Physical layer address */ 
9: }; 
Figura 14.6: La struttura sockaddr_ll degli indirizzi dei packet socket.

Nel caso dei packet socket la struttura degli indirizzi è di tipo sockaddr_ll, e la sua definizione è riportata in fig. 14.6; essa però viene ad assumere un ruolo leggermente diverso rispetto a quanto visto finora per gli altri tipi di socket. Infatti se il socket è di tipo SOCK_RAW si deve comunque scrivere tutto direttamente nel pacchetto, quindi la struttura non serve più a specificare gli indirizzi. Essa mantiene questo ruolo solo per i socket di tipo SOCK_DGRAM, per i quali permette di specificare i dati necessari al protocollo di collegamento, mentre viene sempre utilizzata in lettura (per entrambi i tipi di socket), per la ricezione dei i dati relativi a ciascun pacchetto.

Al solito il campo sll_family deve essere sempre impostato al valore AF_PACKET. Il campo sll_protocol indica il protocollo scelto, e deve essere indicato in network order, facendo uso delle costanti simboliche definite in linux/if_ether.h. Il campo sll_ifindex è l'indice dell'interfaccia, che, in caso di presenza di più interfacce dello stesso tipo (se ad esempio si hanno più schede ethernet), permette di selezionare quella con cui si vuole operare (un valore nullo indica qualunque interfaccia). Questi sono i due soli campi che devono essere specificati quando si vuole selezionare una interfaccia specifica, usando questa struttura con la funzione bind.

I campi sll_halen e sll_addr indicano rispettivamente l'indirizzo associato all'interfaccia sul protocollo di collegamento e la relativa lunghezza; ovviamente questi valori cambiano a seconda del tipo di collegamento che si usa, ad esempio, nel caso di ethernet, questi saranno il MAC address della scheda e la relativa lunghezza. Essi vengono usati, insieme ai campi sll_family e sll_ifindex quando si inviano dei pacchetti, in questo caso tutti gli altri campi devono essere nulli.

Il campo sll_hatype indica il tipo ARP, come definito in linux/if_arp.h, mentre il campo sll_pkttype indica il tipo di pacchetto; entrambi vengono impostati alla ricezione di un pacchetto ed han senso solo in questo caso. In particolare sll_pkttype può assumere i seguenti valori: PACKET_HOST per un pacchetto indirizzato alla macchina ricevente, PACKET_BROADCAST per un pacchetto di broadcast, PACKET_MULTICAST per un pacchetto inviato ad un indirizzo fisico di multicast, PACKET_OTHERHOST per un pacchetto inviato ad un'altra stazione (e ricevuto su un'interfaccia in modo promiscuo), PACKET_OUTGOING per un pacchetto originato dalla propria macchina che torna indietro sul socket.

Si tenga presente infine che in fase di ricezione, anche se si richiede il troncamento del pacchetto, le funzioni recvmsg, recv e recvfrom restituiranno comunque la lunghezza effettiva del pacchetto così come arrivato sulla linea.


[Avanti]  [Indietro]  [Su]  
© 2000-2003 Simone Piccardi
Pubblicazione web curata da Mirko Maischberger