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