Libpcap asynchrone: perdre des paquets?

J’ai un programme qui envoie un ensemble de paquets TCP SYN à un hôte (à l’aide de sockets bruts) et utilise libpcap (avec un filtre) pour obtenir les réponses. J’essaie d’implémenter cela dans une infrastructure d’E / S asynchrone, mais il semble que certaines réponses ne soient pas disponibles dans libpcap (notamment les premiers paquets d’une série lorsqu’il faut moins de 100 microseconds entre le TCP SYN et la réponse). Le descripteur pcap est configuré comme ceci:

 pcap_t* pcap = pcap_open_live(NULL, -1, false, -1, errorBuffer); pcap_setnonblock(pcap, true, errorBuffer); 

Ensuite, j’ajoute un filtre (contenu dans la chaîne filterExpression):

 struct bpf_program filter; pcap_comstack(pcap, &filter, filterExpression.c_str(), false, 0); pcap_setfilter(pcap, &filter); pcap_freecode(&filter); 

Et sur une boucle, après avoir envoyé chaque paquet, j’utilise select pour savoir si je peux lire dans libpcap:

 int pcapFd = pcap_get_selectable_fd(pcap); fd_set fdRead; FD_ZERO(&fdRead); FD_SET(pcapFd, &fdRead); select(pcapFd + 1, &fdRead, NULL, NULL, &selectTimeout); 

Et lisez le:

 if (FD_ISSET(pcapFd, &fdRead)) { struct pcap_pkthdr* pktHeader; const u_char* pktData; if (pcap_next_ex(pcap, &pktHeader, &pktData) > 0) { // Process received response. } else { // Nothing to receive (or error). } } 

Comme je l’ai dit précédemment, certains des paquets sont manqués (tombant dans le “rien à recevoir” sinon). Je sais que ces paquets sont là, car je peux les capturer de manière synchrone (en utilisant tcpdump ou un thread exécutant pcap_loop ). Me manque-t-il des détails ici? Ou est-ce un problème avec libpcap ?

Si la FD de pcap_t est signalée comme lisible par select() (ou poll() ou quel que soit l’appel / le mécanisme que vous utilisez), rien ne garantit que cela signifie qu’un seul paquet peut être lu sans blocage.

Si vous utilisez pcap_next_ex() , vous ne lirez qu’un seul paquet; si plus d’un paquet est disponible pour être lu, si vous faites un autre select() , il devrait immédiatement le retourner, indiquant que le FD est lisible à nouveau, auquel cas vous devrez probablement appeler pcap_next_ex() nouveau, etc. . Cela signifie au moins un appel système par paquet (le select() ), et éventuellement plus d’appels, en fonction de la version de votre système d’exploitation et de la version de libpcap que vous possédez.

Si, au lieu de cela, vous appelez pcap_dispatch() avec un argument de nombre de paquets pcap_dispatch() -1, cet appel renverra tous les paquets pouvant être obtenus en une seule opération de lecture et les traitera tous. Par conséquent, sur la plupart des plates-formes, vous pouvez obtenir plusieurs paquets avec un ou deux appels système si plusieurs paquets sont disponibles (ce qui risque de se produire avec un trafic réseau élevé, comme si vous testiez votre programme avec un stream SYN).

En outre, sur les systèmes Linux prenant en charge la capture de paquets mappés sur la mémoire (je pense que tous les kernelx 2.6 et ultérieurs le font, et la plupart sinon tous les kernelx 2.4), et avec les versions plus récentes de libpcap, pcap_next_ex() doit faire une copie du pcap_next_ex() paquet pour éviter que le kernel ne modifie le paquet en dessous du code traitant le paquet et pour éviter de “verrouiller” un emplacement dans la mémoire tampon en anneau pendant une période indéfinie, de sorte qu’une copie supplémentaire est impliquée.

Cela semble poser un problème avec libpcap qui utilise la cartographie de la mémoire sous Linux. S’il vous plaît voir mon autre question pour plus de détails.