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;
}

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;

    /* 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;
        }
    }

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

    /* Transmit the queue */
    
    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);
    }
    
    /* free the send queue */
    pcap_sendqueue_destroy(squeue);

    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);
}

<<< Previous Next >>>


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