Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

# Sending Packets
[WinPcap tutorial: a step by step guide to program WinPcap]

Although the name WinPcap indicates clearly that the main purpose of the library is packet capture, other useful features for raw networking are provided. Among them, the user can find a complete set of functions to send packets, that this lesson will show.

Note that the original libpcap library at the moment doesn't provide any way to send packets: all the functions showed here are WinPcap extensions and will not work under Unix.

Sending a single packet with pcap_sendpacket()

The simplest way to send a packet is shown in the following code snippet. After opening an adapter, pcap_sendpacket() is called to send a hand-crafted packet. pcap_sendpacket() takes as arguments a buffer containing the data to send, its length and the adapter that will send it. Notice that the buffer is sent to the net as is, without any manipulation: this means that the application has to create the correct protocol headers in order to send something meaningful.

    #include <stdlib.h>
    #include <stdio.h>

    #include <pcap.h>

    void main(int argc, char **argv)
    {
    pcap_t *fp;
    char errbuf[PCAP_ERRBUF_SIZE];
    u_char packet[100];
    int i;

        /* Check the validity of the command line */
        if (argc != 2)
        {
            printf("usage: %s interface (e.g. 'rpcap://eth0')", argv[0]);
            return;
        }

        /* Open the output device */
        if ( (fp= pcap_open(argv[1],            // name of the device
                            100,                // portion of the packet to capture (only the first 100 bytes)
                            PCAP_OPENFLAG_PROMISCUOUS,  // promiscuous mode
                            1000,               // read timeout
                            NULL,               // authentication on the remote machine
                            errbuf              // error buffer
                            ) ) == NULL)
        {
            fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", argv[1]);
            return;
        }

        /* Supposing to be on ethernet, set mac destination to 1:1:1:1:1:1 */
        packet[0]=1;
        packet[1]=1;
        packet[2]=1;
        packet[3]=1;
        packet[4]=1;
        packet[5]=1;

        /* set mac source to 2:2:2:2:2:2 */
        packet[6]=2;
        packet[7]=2;
        packet[8]=2;
        packet[9]=2;
        packet[10]=2;
        packet[11]=2;

        /* Fill the rest of the packet */
        for(i=12;i<100;i++)
        {
            packet[i]=i%256;
        }

        /* Send down the packet */
        if (pcap_sendpacket(fp, packet, 100 /* size */) != 0)
        {
            fprintf(stderr,"\nError sending the packet: \n", pcap_geterr(fp));
            return;
        }

        return;
    }

    00001 #include <stdlib.h>
    00002 #include <stdio.h>
    00003
    00004 #include <pcap.h>
    00005
    00006
    00007 void main(int argc, char **argv)
    00008 {
    00009 pcap_t *fp;
    00010 char errbuf[PCAP_ERRBUF_SIZE];
    00011 u_char packet[100];
    00012 int i;
    00013
    00014     /* Check the validity of the command line */
    00015     if (argc != 2)
    00016     {
    00017         printf("usage: %s interface (e.g. 'rpcap://eth0')", argv[0]);
    00018         return;
    00019     }
    00020
    00021     /* Open the output device */
    00022     if ( (fp= pcap_open(argv[1],            // name of the device
    00023                         100,                // portion of the packet to capture (only the first 100 bytes)
    00024                         PCAP_OPENFLAG_PROMISCUOUS,  // promiscuous mode
    00025                         1000,               // read timeout
    00026                         NULL,               // authentication on the remote machine
    00027                         errbuf              // error buffer
    00028                         ) ) == NULL)
    00029     {
    00030         fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", argv[1]);
    00031         return;
    00032     }
    00033
    00034     /* Supposing to be on ethernet, set mac destination to 1:1:1:1:1:1 */
    00035     packet[0]=1;
    00036     packet[1]=1;
    00037     packet[2]=1;
    00038     packet[3]=1;
    00039     packet[4]=1;
    00040     packet[5]=1;
    00041
    00042     /* set mac source to 2:2:2:2:2:2 */
    00043     packet[6]=2;
    00044     packet[7]=2;
    00045     packet[8]=2;
    00046     packet[9]=2;
    00047     packet[10]=2;
    00048     packet[11]=2;
    00049
    00050     /* Fill the rest of the packet */
    00051     for(i=12;i<100;i++)
    00052     {
    00053         packet[i]=i%256;
    00054     }
    00055
    00056     /* Send down the packet */
    00057     if (pcap_sendpacket(fp, packet, 100 /* size */) != 0)
    00058     {
    00059         fprintf(stderr,"\nError sending the packet: \n", pcap_geterr(fp));
    00060         return;
    00061     }
    00062
    00063     return;
    00064 }

Send queues

While pcap_sendpacket() offers a simple and immediate way to send a single packet, send queues provide an advanced, powerful and optimized mechanism to send groups of packets. A send queue is a container for a variable number of packets that will be sent to the network. It has a size, that represents the maximum amount of bytes it can store.

A send queue is created calling the pcap_sendqueue_alloc() function, specifying the size that the new queue will have.

Once the queue is created, pcap_sendqueue_queue() can be used to store a packet in it. This function receives a pcap_pkthdr with the timestamp and the length and a buffer with the data of the packet. These parameters are the same received by pcap_next_ex() and pcap_handler(), therefore queuing a packet that was just captured or read from a file is a matter of passing them to pcap_sendqueue_queue().

To send a queue, WinPcap provides the pcap_sendqueue_transmit() function. Note the third parameter: if nonzero, the send will be synchronized, i.e. the relative timestamps of the packets will be respected. This requires a remarkable amount of CPU, because the synchronization takes place in the kernel driver using "brute force" loops, but normally grants a very high precision (often around few microseconds or less).

Note that sending a queue with pcap_sendqueue_transmit() is much more efficient than performing a series of pcap_sendpacket(), because a send queue is buffered at kernel level decreasing drastically the number of context switches.

When a queue is no more needed, it can be deleted with pcap_sendqueue_destroy() that frees all the buffers associated with it.

The next code shows how to use send queues. It opens a capture file with pcap_open_offline(), then it moves the packets from the file to a properly allocated queue. At his point it transmits the queue, synchronizing it if requested by the user.

Note that the link-layer of the dumpfile is compared with the one of the interface that will send the packets using pcap_datalink(), and a warning is printed if they are different: sending on a link-layer the packets captured from a different one is quite pointless.

    /*
     * Copyright (c) 1999 - 2002
     *  Politecnico di Torino.  All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that: (1) source code distributions
     * retain the above copyright notice and this paragraph in its entirety, (2)
     * distributions including binary code include the above copyright notice and
     * this paragraph in its entirety in the documentation or other materials
     * provided with the distribution, and (3) all advertising materials mentioning
     * features or use of this software display the following acknowledgement:
     * ``This product includes software developed by the Politecnico
     * di Torino, and its contributors.'' Neither the name of
     * the University nor the names of its contributors may be used to endorse
     * or promote products derived from this software without specific prior
     * written permission.
     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     */

    #include <stdlib.h>
    #include <stdio.h>

    #include <pcap.h>
    #include <remote-ext.h>

    void usage();

    void main(int argc, char **argv)
    {
        pcap_t *indesc,*outdesc;
        char errbuf[PCAP_ERRBUF_SIZE];
        char source[PCAP_BUF_SIZE];
        FILE *capfile;
        int caplen, sync;
        u_int res;
        pcap_send_queue *squeue;
        struct pcap_pkthdr *pktheader;
        u_char *pktdata;
        float cpu_time;
        u_int npacks = 0;

        /* Check the validity of the command line */
        if (argc <= 2 || argc >= 5)
        {
            usage();
            return;
        }

        /* Retrieve the length of the capture file */
        capfile=fopen(argv[1],"rb");
        if(!capfile){
            printf("Capture file not found!\n");
            return;
        }

        fseek(capfile , 0, SEEK_END);
        caplen= ftell(capfile)- sizeof(struct pcap_file_header);
        fclose(capfile);

        /* Chek if the timestamps must be respected */
        if(argc == 4 && argv[3][0] == 's')
            sync = TRUE;
        else
            sync = FALSE;

        /* Open the capture */
        /* Create the source string according to the new WinPcap syntax */
        if ( pcap_createsrcstr( source,         // variable that will keep the source string
                                PCAP_SRC_FILE,  // we want to open a file
                                NULL,           // remote host
                                NULL,           // port on the remote host
                                argv[1],        // name of the file we want to open
                                errbuf          // error buffer
                                ) != 0)
        {
            fprintf(stderr,"\nError creating a source string\n");
            return;
        }

        /* Open the capture file */
        if ( (indesc= pcap_open(source, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) ) == NULL)
        {
            fprintf(stderr,"\nUnable to open the file %s.\n", source);
            return;
        }

        /* Open the output adapter */
        if ( (outdesc= pcap_open(argv[2], 100, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) ) == NULL)
        {
            fprintf(stderr,"\nUnable to open adapter %s.\n", source);
            return;
        }

        /* Check the MAC type */
        if (pcap_datalink(indesc) != pcap_datalink(outdesc))
        {
            printf("Warning: the datalink of the capture differs from the one of the selected interface.\n");
            printf("Press a key to continue, or CTRL+C to stop.\n");
            getchar();
        }

        /* Allocate a send queue */
        squeue = pcap_sendqueue_alloc(caplen);

        /* Fill the queue with the packets from the file */
        while ((res = pcap_next_ex( indesc, &pktheader, &pktdata)) == 1)
        {
            if (pcap_sendqueue_queue(squeue, pktheader, pktdata) == -1)
            {
                printf("Warning: packet buffer too small, not all the packets will be sent.\n");
                break;
            }

            npacks++;
        }

        if (res == -1)
        {
            printf("Corrupted input file.\n");
            pcap_sendqueue_destroy(squeue);
            return;
        }

        /* Transmit the queue */

        cpu_time = (float)clock ();

        if ((res = pcap_sendqueue_transmit(outdesc, squeue, sync)) < squeue->len)
        {
            printf("An error occurred sending the packets: %s. Only %d bytes were sent\n", pcap_geterr(outdesc), res);
        }

        cpu_time = (clock() - cpu_time)/CLK_TCK;

        printf ("\n\nElapsed time: %5.3f\n", cpu_time);
        printf ("\nTotal packets generated = %d", npacks);
        printf ("\nAverage packets per second = %d", (int)((double)npacks/cpu_time));
        printf ("\n");

        /* free the send queue */
        pcap_sendqueue_destroy(squeue);

        /* Close the input file */
        pcap_close(indesc);

        /*
         * lose the output adapter
         * IMPORTANT: remember to close the adapter, otherwise there will be no guarantee that all the
         * packets will be sent!
         */
        pcap_close(outdesc);

        return;
    }

    void usage()
    {

        printf("\nSendcap, sends a libpcap/tcpdump capture file to the net. Copyright (C) 2002 Loris Degioanni.\n");
        printf("\nUsage:\n");
        printf("\t sendcap file_name adapter [s]\n");
        printf("\nParameters:\n");
        printf("\nfile_name: the name of the dump file that will be sent to the network\n");
        printf("\nadapter: the device to use. Use \"WinDump -D\" for a list of valid devices\n");
        printf("\ns: if present, forces the packets to be sent synchronously, i.e. respecting the timestamps in the dump file. This option will work only under Windows NTx.\n\n");

        exit(0);
    }

    00001 /*
    00002  * Copyright (c) 1999 - 2002
    00003  *  Politecnico di Torino.  All rights reserved.
    00004  *
    00005  * Redistribution and use in source and binary forms, with or without
    00006  * modification, are permitted provided that: (1) source code distributions
    00007  * retain the above copyright notice and this paragraph in its entirety, (2)
    00008  * distributions including binary code include the above copyright notice and
    00009  * this paragraph in its entirety in the documentation or other materials
    00010  * provided with the distribution, and (3) all advertising materials mentioning
    00011  * features or use of this software display the following acknowledgement:
    00012  * ``This product includes software developed by the Politecnico
    00013  * di Torino, and its contributors.'' Neither the name of
    00014  * the University nor the names of its contributors may be used to endorse
    00015  * or promote products derived from this software without specific prior
    00016  * written permission.
    00017  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
    00018  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
    00019  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    00020  */
    00021
    00022 #include <stdlib.h>
    00023 #include <stdio.h>
    00024
    00025 #include <pcap.h>
    00026 #include <remote-ext.h>
    00027
    00028 void usage();
    00029
    00030 void main(int argc, char **argv)
    00031 {
    00032     pcap_t *indesc,*outdesc;
    00033     char errbuf[PCAP_ERRBUF_SIZE];
    00034     char source[PCAP_BUF_SIZE];
    00035     FILE *capfile;
    00036     int caplen, sync;
    00037     u_int res;
    00038     pcap_send_queue *squeue;
    00039     struct pcap_pkthdr *pktheader;
    00040     u_char *pktdata;
    00041     float cpu_time;
    00042     u_int npacks = 0;
    00043
    00044     /* Check the validity of the command line */
    00045     if (argc <= 2 || argc >= 5)
    00046     {
    00047         usage();
    00048         return;
    00049     }
    00050
    00051     /* Retrieve the length of the capture file */
    00052     capfile=fopen(argv[1],"rb");
    00053     if(!capfile){
    00054         printf("Capture file not found!\n");
    00055         return;
    00056     }
    00057
    00058     fseek(capfile , 0, SEEK_END);
    00059     caplen= ftell(capfile)- sizeof(struct pcap_file_header);
    00060     fclose(capfile);
    00061
    00062     /* Chek if the timestamps must be respected */
    00063     if(argc == 4 && argv[3][0] == 's')
    00064         sync = TRUE;
    00065     else
    00066         sync = FALSE;
    00067
    00068     /* Open the capture */
    00069     /* Create the source string according to the new WinPcap syntax */
    00070     if ( pcap_createsrcstr( source,         // variable that will keep the source string
    00071                             PCAP_SRC_FILE,  // we want to open a file
    00072                             NULL,           // remote host
    00073                             NULL,           // port on the remote host
    00074                             argv[1],        // name of the file we want to open
    00075                             errbuf          // error buffer
    00076                             ) != 0)
    00077     {
    00078         fprintf(stderr,"\nError creating a source string\n");
    00079         return;
    00080     }
    00081
    00082     /* Open the capture file */
    00083     if ( (indesc= pcap_open(source, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) ) == NULL)
    00084     {
    00085         fprintf(stderr,"\nUnable to open the file %s.\n", source);
    00086         return;
    00087     }
    00088
    00089     /* Open the output adapter */
    00090     if ( (outdesc= pcap_open(argv[2], 100, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) ) == NULL)
    00091     {
    00092         fprintf(stderr,"\nUnable to open adapter %s.\n", source);
    00093         return;
    00094     }
    00095
    00096     /* Check the MAC type */
    00097     if (pcap_datalink(indesc) != pcap_datalink(outdesc))
    00098     {
    00099         printf("Warning: the datalink of the capture differs from the one of the selected interface.\n");
    00100         printf("Press a key to continue, or CTRL+C to stop.\n");
    00101         getchar();
    00102     }
    00103
    00104     /* Allocate a send queue */
    00105     squeue = pcap_sendqueue_alloc(caplen);
    00106
    00107     /* Fill the queue with the packets from the file */
    00108     while ((res = pcap_next_ex( indesc, &pktheader, &pktdata)) == 1)
    00109     {
    00110         if (pcap_sendqueue_queue(squeue, pktheader, pktdata) == -1)
    00111         {
    00112             printf("Warning: packet buffer too small, not all the packets will be sent.\n");
    00113             break;
    00114         }
    00115
    00116         npacks++;
    00117     }
    00118
    00119     if (res == -1)
    00120     {
    00121         printf("Corrupted input file.\n");
    00122         pcap_sendqueue_destroy(squeue);
    00123         return;
    00124     }
    00125
    00126     /* Transmit the queue */
    00127
    00128     cpu_time = (float)clock ();
    00129
    00130     if ((res = pcap_sendqueue_transmit(outdesc, squeue, sync)) < squeue->len)
    00131     {
    00132         printf("An error occurred sending the packets: %s. Only %d bytes were sent\n", pcap_geterr(outdesc), res);
    00133     }
    00134
    00135     cpu_time = (clock() - cpu_time)/CLK_TCK;
    00136
    00137     printf ("\n\nElapsed time: %5.3f\n", cpu_time);
    00138     printf ("\nTotal packets generated = %d", npacks);
    00139     printf ("\nAverage packets per second = %d", (int)((double)npacks/cpu_time));
    00140     printf ("\n");
    00141
    00142     /* free the send queue */
    00143     pcap_sendqueue_destroy(squeue);
    00144
    00145     /* Close the input file */
    00146     pcap_close(indesc);
    00147
    00148     /*
    00149      * lose the output adapter
    00150      * IMPORTANT: remember to close the adapter, otherwise there will be no guarantee that all the
    00151      * packets will be sent!
    00152      */
    00153     pcap_close(outdesc);
    00154
    00155
    00156     return;
    00157 }
    00158
    00159
    00160 void usage()
    00161 {
    00162
    00163     printf("\nSendcap, sends a libpcap/tcpdump capture file to the net. Copyright (C) 2002 Loris Degioanni.\n");
    00164     printf("\nUsage:\n");
    00165     printf("\t sendcap file_name adapter [s]\n");
    00166     printf("\nParameters:\n");
    00167     printf("\nfile_name: the name of the dump file that will be sent to the network\n");
    00168     printf("\nadapter: the device to use. Use \"WinDump -D\" for a list of valid devices\n");
    00169     printf("\ns: if present, forces the packets to be sent synchronously, i.e. respecting the timestamps in the dump file. This option will work only under Windows NTx.\n\n");
    00170
    00171     exit(0);
    00172 }

<<< Previous Next >>>

documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.