HSC
Network Security Consulting Agency Since 1989 - Specialized in Unix, Windows, TCP/IP and Internet
Text mode: access to the page content
Hervé Schauer Consultants
You are here: Home > Resources > Tips > Introduction à la libpcap
Go to: HSC Trainings
Télécharger le catalogue des formations
Search:  
Version française
   Services   
o Skills & Expertise
o Consulting
o ISO 27001 services
o Audit & Assessment
o Penetration tests
o Vunerability assessment (TSAR)
o Forensics
o ARJEL
o Training courses
o E-learning
   Conferences   
o Agenda
o Past events
o Tutorials
   Resources   
o Thematic index
o Tips
o Lectures
o Courses
o Articles
o Tools (download)
o Vulnerability watch
   Company   
o Hervé Schauer
o Team
o Job opportunities
o Credentials
o History
o Partnerships
o Associations
   Press and
 communication
 
 
o HSC Newsletter
o Bulletin juridique HSC
o Press review
o Press releases
o Publications
   Contacts   
o How to reach us
o Specific inquiries
o Directions to our office
o Hotels near our office
|>|Introduction à la libpcap  

by Frédéric Lavécot (04/12/2000)




--[ Introduction ]---------------------------------------------------------

La libpcap est une bibliothéque de fonctions qui, d'après le README qui 
accompagne l'archive, sert d'interface à la capture de paquets et est 
indépendante du système.

En clair la libpcap permet d'écouter le réseau aves ses propres filtres
puisqu'elle inclus un mécanisme de filtrage basé sur le Berkeley packet filter
(BPF).

Ce tip se propose de donner un aperçu rapide des fonctions offertes par la 
libpcap et d'expliquer les étapes nécessaires à la réalisation d'un sniffer.

Les informations qui suivent ont été obtenues en regardant les sources de 
programmes utilisant la libpcap comme tcpdump et hping2 et en consultant le 
manuel (man pcap).

--[ libpcap ]--------------------------------------------------------------

Pour récupérer l'archive deux choix : 

- version stable : ftp://ftp.ee.lbl.gov/

- version maintenue : http://www.tcpdump.org/

--[ Installation ]---------------------------------------------------------

Sous *BSD : il y a de fortes chances pour que la libpcap soit déjà installée

Sinon :

tar zxvf libpcap-*.tgz

$ ./configure
$ make
# make install
# make install-incl
(pour installer les entêtes nécessaires au développement )
# make install-man
(pour installer le man)


--[ Comment dévelloper un sniffer ? ]--------------------------------------

Les fonctions présentées ici le sont dans l'ordre où elles apparaissent 
généralement dans un sniffer.

Les en-têtes à inclure pour accéder aux fonctions et aux #define


#include <pcap.h>
#include <net/if.h>
#include <netinet/in.h> 


Conseil : si le programme que vous développez doit être porté sur plusieurs
plate-formes, redéfinissez vous mêmes les structure de paquets ip et tcp.
Les champs de ces structures sont différents d'une plate-forme à une autre.
(Rien ne vous empêche de reprendre celles de votre système, de les recopier
dans le même repertoire que votre programme et de faire #include "fichier")
(Le plus souvent les structures des paquets ip et tcp sont définies dans 
/usr/include/netinet/ip.h et /usr/include/netinet/tcp.h)


Première étape : choisir l'interface que l'on veut "sniffer".

deux options : 
 - soit on la choisit : dans ce cas on stocke le nom de l'interface dans un 
   char *.
 - soit on essaye de la détecter grâce à la fonction pcap_lookupdev()
   cette fonction retourne un pointeur sur la première interface réseau 
   utilisable ou NULL si une erreur se produit.


char err_buff[PCAP_ERRBUF_SIZE];
char device[512];

device=NULL;
  
  if(device==NULL)  
  /* If device not specified -> autodetect */
    if ((device = pcap_lookupdev (err_buff)) == NULL)
      {
	printf ("pcap_lookupdev : %s\n", err_buff);
	return (-1);
      }
  printf("device %s detected\n",device);



Deuxième étape : obtenir un descripteur de capture de paquets.

Cela se fait en utilisant la fonction pcap_open_live(). 
pcap_open_live() renvoie un pointeur de type pcap_t. Les paramètres sont :
 - char *device : le nom de l'interface à sniffer
 - int snaplen  : taille maximale de bytes à capturer (sur Ethernet 1514)
 - int promisc  : faut-il placer l'interface en mode promiscuous(1) ? 
 - int to_ms    : timeout de lecture en millisecondes
 - char *ebuf   : utilisé pour récuperer le message d'erreur

IFF_PROMISC est définie dans /usr/include/net/if.h


#define SNAP_LEN 1514
pcap_t *pdes;
char err_buff[PCAP_ERRBUF_SIZE];

 if ((pdes=pcap_open_live(device,SNAP_LEN,IFF_PROMISC,1000,err_buff)) == NULL) 
    /* obtain a packet descriptor to sniff the network */
    {
      printf("\npcap_open_live error : %s\n",err_buff);
      return(-1);
    }
  printf("listening on device %s\n",device); 


Note sur le paramètre de timeout : 1000 semble être une bonne valeur 
(c'est celle adoptée par hping2 et tcpdump). Attention en mettant 0 certains
systèmes ne traiteront plus aucun paquet.


(1) promiscuous : Sur un réseau Ethernet, les trames sont envoyées à toutes 
les stations du réseau. Une interface normale ne remonte que les trames qui 
lui sont destinées. Une interface en mode promiscuous remonte toutes les 
trames qu'elle voit passer.

Si l'on souhaite placer un filtre sur les paquets à remonter :

Troisième étape : obtenir le numéro et le masque associé au réseau de 
                      l'interface.
La fonction pcap_lookupnet() permet de les obtenir. 
pcap_lookupnet renvoie -1 en cas d'erreur. Les paramètres sont :
 - char * device : interface dont on souhaite obtenir les descripteurs
 - bpf_u_int32 * netp : variable dans laquelle l'adresse de réseau sera stockée
 - bpf_u_int32 * maskp : variable dans laquelle le masque de réseau sera stocké
 - char * errbuff : buffer dans lequel une éventuelle erreur sera écrite


char err_buff[PCAP_ERRBUF_SIZE];
bpf_u_int32 netp,maskp;

  if ( pcap_lookupnet(device,&netp,&maskp,err_buff) == -1)
   {
     printf("\n\npcap_lookupnet error : %s",err_buff);
     return(-1);
   }


Quatrième étape : transformer le filtre écrit en texte en un vrai filtre.

Pour cela on utilise la fonction pcap_compile() :
Comme d'habitude la fonction renvoie -1 si une erreur survient.
Les paramètres sont :
pcap_t *pdes : descripteur de paquets capturés
struct bpf_program *bp : structure remplie par pcap_compile()
char *str : filtre écrit sous forme de texte 
exemple : "src port 80 or dst port 80" pour capturer tous les paquets issus ou
à destination du port 80.
int optimize : contrôle l'optimisation du résultat.
(traduction directe de la page man, je n'en sais pas plus)
bpf_u_int32 maskp : masque de réseau (précédemment obtenu)


#define FILTER				"src port 80 or dst port 80"
struct bpf_program  bp;


  if (pcap_compile(*pdes, &bp, FILTER, 0x100, maskp) < 0)
    /* set a filter to capture the packets that match FILTER */ 
    {
      printf("\n\n pcap_compile error : %s\n",pcap_geterr(*pdes));
      return(-1);
    }


Cinquième étape : Appliquer le filtre.

C'est la fonction pcap_setfilter() qui va s'en charger :
Paramètres :


pcap_t *pdes : le descripteur de paquets capturés
struct bpf_program bp : la structure contenant la description du filtre 
                        (entre autres)

 if (pcap_setfilter(*pdes, &bp) < 0)
   {
     printf("\n\n pcap_setfilter error : %s\n",pcap_geterr(*pdes));
     return(-1);
   }
 
 printf("pcap_setfilter OK\n\n");


Voila, vous avez maintenant un descripteur de paquets capturés qui 
correspond parfaitement à vos attentes. Il ne reste plus qu'a lire dedans :

Pour cela on utilise la fonction pcap_loop() dont les paramètres sont :
pcap_t *pdes : le descripteur de paquets capturés 
int cnt : nombre de paquets à traiter (-1 : boucle infinie)
pcap_handler callback : fonction de traitement à exécuter pour chaque paquet 
                        capturé
u_char *user : voir fonction callback()

  char * buff = NULL;
    
  if( pcap_loop(pdes,-1,callback,buff) <0 )
    {
      (void)fprintf(stderr, "pcap_loop: %s\n",pcap_geterr(pdes));
      exit(1);
    }


La fonction callback 
les paramètres de cette fonction sont :
u_char *user : le pointeur passé en paramètre de pcap_loop()
const struct pcap_pkthdr *h : pointeur sur le descripteur du paquet capturé
const u_char *buff : données effectivement capturées 
                     (si vous êtes sur un réseau Ethernet ces données 
                      commencent avec l'en-tête Ethernet du paquet)
void callback(u_char *user, const struct pcap_pkthdr *h, const u_char *buff)
{
  struct iphdr *ip_hdr;   
  unsigned short int len;
  
      
  ip_hdr=(struct iphdr *)(buff+14);

  len=htons(ip_hdr->tot_len);

...
}


La dernière étape : compiler votre programme. Pour pouvoir accéder aux 
fonctions de la libpcap ne pas oublier le paramètre -lpcap dans la commande 
permettant de compiler votre programme.

Quelques information supplémentaires : 

* Il est possible de capturer tous les paquets d'un seul coup avec tcpdump 
et de les sauvegarder dans un fichier pour faire le traitement après coup. 
Pour cela il suffit d'utiliser la fonction pcap_open_offline() à la place de
la fonction pcap_open_live().

 
* Attention sous linux il n'est par défaut pas possible de savoir si le noyau
a perdu des paquets pendant la capture. Si vous utilisez linux et que vous avez
besoin de cette information il existe un patch pour les noyaux 2.2 disponible.

* Si vous avez encore des questions : "man 3 pcap"  sinon : 
Frederic.Lavecot@hsc.fr




Last modified on 30 Mars 2006 at 19:27:01 CET - webmaster@hsc.fr
Mentions légales - Information on this server - © 1989-2013 Hervé Schauer Consultants