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.