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; }
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 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; 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-2003 Politecnico di Torino. All rights reserved.