Note that the original libpcap library at the moment doesn't provide any way to send packets: all the functions showed here are WinPcap externsions and will not work under Unix.
Sending a single packet with pcap_sendpacket
the simplest way to send a packet is shown in the next 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 usage(); void main(int argc, char **argv) { pcap_t *fp; char error[PCAP_ERRBUF_SIZE]; u_char packet[100]; int i; /* Check the validity of the command line */ if (argc != 2) { printf("usage: %s inerface", argv[0]); return; } /* Open the output adapter */ if((fp = pcap_open_live(argv[1], 100, 1, 1000, error) ) == NULL) { fprintf(stderr,"\nError opening adapter: %s\n", error); 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 */ pcap_sendpacket(fp, packet, 100); 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 - 2003 * NetGroup, Politecnico di Torino (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include <stdlib.h> #include <stdio.h> #include <pcap.h> void usage(); void main(int argc, char **argv) { pcap_t *indesc,*outdesc; char error[PCAP_ERRBUF_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 */ if((indesc = pcap_open_offline(argv[1], error)) == NULL){ fprintf(stderr,"\nError opening the input file: %s\n", error); return; } /* Open the output adapter */ if((outdesc = pcap_open_live(argv[2], 100, 1, 1000, error) ) == NULL) { fprintf(stderr,"\nError opening adapter: %s\n", error); 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", error, 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); }
documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.