tcpdump mailing list archives

Re: Portable way to "block" on pcap_next_ex()


From: Fernando Gont <fernando () gont com ar>
Date: Mon, 16 Jan 2012 19:20:40 -0300

Hi, Guy,

On 01/16/2012 05:25 PM, Guy Harris wrote:
If you have a system where select() works as it should, i.e.:
[....]
select() will block until either

1) a bufferful of packets arrives

or

2) the timer, started when the select() is done, expires,
regardless of whether any packets are available to read.

This doesn't seem to agree with my tests.

I've just checked this on FreeBSD-8.2-release and on a current
Ubuntu system,

Sorry, I didn't make it clear enough that, when I said that, I was
speaking only of systems using BPF, so it wouldn't apply to Ubuntu
(or any other Linux distribution), for example.

But it does work in the same way on FreeBSD and OpenBSD, too. -- just
tested this...


and in both cases select() returns "readable" only for each packet
that is received.

What do you mean by "only for each packet that is received"?  Do you
mean that it doesn't return "readable" if there are no packets to
read?

Both on Linux and on BSDs, each time a packet is received, select()
returns readable (without waiting for the entire buffer to fill up). --
my understanding is that you were expecting select() to block till the
buffer filled up, or when the timer expired. But everytime select()
returns, there's a packet to read, and it seems it never returns when
there are no packets to read.

FWIW, this is my test program:

/*
 * Testing select() and pcap_next_ex()
 *
 * Please send any bug reports to Fernando Gont <fgont () si6networks com>
 */

#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <getopt.h>
#include <unistd.h>
#include <string.h>
#include <pcap.h>
#include <sys/types.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <sys/socket.h>
#include <sys/select.h>

/* Constants used with the libpcap functions */
#define PCAP_ICMPV6_FILTER      "icmp6 and ip6[40]==128"
#define PCAP_SNAP_LEN           65535
#define PCAP_TIMEOUT            1
#define PCAP_PROMISC            1
#define PCAP_OPT                1
#ifndef PCAP_NETMASK_UNKNOWN
        #define PCAP_NETMASK_UNKNOWN    0xffffffff
#endif
#define IFACE_LENGTH    255

pcap_t                  *pfd;
bpf_u_int32             my_netmask;
bpf_u_int32             my_ip;
struct bpf_program      pcap_filter;
char                    dev[64], errbuf[PCAP_ERRBUF_SIZE];
char                    iface[IFACE_LENGTH];
char                    *lasts, *rpref, *endptr;
char                    *charptr;


int main(int argc, char **argv){
        extern char             *optarg;        
        extern int              optind;
        int                     r, sel, fd;
        fd_set                  sset, rset;
        struct pcap_pkthdr      *pkthdr;
        const u_char            *pktdata;
        unsigned char           iface_f=0;

        static struct option longopts[] = {
                {"interface", required_argument, 0, 'i'},
        };

        char shortopts[]= "i:";
        char option;

        if(argc<=1){
                puts("Missing parameters");
                exit(1);
        }


        while((option=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
                switch(option) {

                        case 'i':  /* Interface */
                                strncpy(iface, optarg, IFACE_LENGTH-1);
                                iface_f=1;
                                break;

                        default:
                                puts("Unsuported option");
                                exit(1);
                                break;
                        } /* switch */
        } /* while(getopt) */

        if(geteuid()) {
                puts("tool needs root privileges to run.");
                exit(1);
        }

        if(!iface_f){
                puts("Must specify the network interface with the -i option");
                exit(1);
        }

        if( (pfd= pcap_open_live(iface, PCAP_SNAP_LEN, PCAP_PROMISC,
PCAP_TIMEOUT, errbuf)) == NULL){
                printf("pcap_open_live(): %s\n", errbuf);
                exit(1);
        }

        if( pcap_datalink(pfd) != DLT_EN10MB){
                printf("Error: Interface %s is not an Ethernet interface", iface);
                exit(1);
        }

        if(pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_FILTER, PCAP_OPT,
PCAP_NETMASK_UNKNOWN) == -1){
                printf("pcap_compile(): %s", pcap_geterr(pfd));
                exit(1);
        }

        if(pcap_setfilter(pfd, &pcap_filter) == -1){
                printf("pcap_setfilter(): %s", pcap_geterr(pfd));
                exit(1);
        }

        pcap_freecode(&pcap_filter);


        if( (fd= pcap_fileno(pfd)) == -1){
                puts("Error obtaining descriptor number for pcap_t");
                exit(1);
        }

        FD_ZERO(&sset);
        FD_SET(fd, &sset);

        while(1){
                rset= sset;

                if((sel=select(fd+1, &rset, NULL, NULL, NULL)) == -1){
                        if(errno == EINTR){
                                puts("select() was interrupted");
                                continue;
                        }
                        else{
                                puts("Error in select()");
                                exit(1);
                        }
                }

                puts("Descriptor was readable");

                if((r=pcap_next_ex(pfd, &pkthdr, &pktdata)) == -1){
                        printf("pcap_next_ex(): %s", pcap_geterr(pfd));
                        exit(1);
                }
                else if(r == 0){
                        puts("pcap_next_ex() returned 0");
                        continue;
                }

                puts("pcap_next_ex() returned a packet");
        }

        exit(0);
}


P.S.: The filter above expects ICMPv6 echo requests, so you can test the
program with "ping6 IPV6ADDRESS".

Thanks!

Best regards,
-- 
Fernando Gont
e-mail: fernando () gont com ar || fgont () si6networks com
PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1



-
This is the tcpdump-workers list.
Visit https://cod.sandelman.ca/ to unsubscribe.


Current thread: