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

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

Although the name WinPcap indicates clearly that the 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.

Note that the original libpcap library at the moment doesn't provide any way to send packets, therefore all the functions shown 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, the length of the buffer 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 provides an advanced, powerful and optimized mechanism to send a collection 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 of the new send queue.

Once the send queue is created, pcap_sendqueue_queue() can be used to add a packet to the send queue. This function takes a pcap_pkthdr with the timestamp and the length and a buffer with the data of the packet. These parameters are the same as those 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 these parameters to pcap_sendqueue_queue().

To transmit a send 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 operation requires a remarkable amount of CPU, because the synchronization takes place in the kernel driver using "busy wait" loops. Although this operation is quite CPU intensive, it often results in very high precision packet transmissions (often around few microseconds or less).

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

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

The next program 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 send 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 -- it is important that the capture-file link-layer be the same as the adapter's link layer for otherwise the tranmission is 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-2005 Politecnico di Torino. Copyright (c) 2005 CACE technologies. All rights reserved.