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)
{
u_char packet[100];
int i;
if (argc != 2)
{
printf("usage: %s interface (e.g. 'rpcap://eth0')", argv[0]);
return;
}
100,
1000,
NULL,
errbuf
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", argv[1]);
return;
}
packet[0]=1;
packet[1]=1;
packet[2]=1;
packet[3]=1;
packet[4]=1;
packet[5]=1;
packet[6]=2;
packet[7]=2;
packet[8]=2;
packet[9]=2;
packet[10]=2;
packet[11]=2;
for(i=12;i<100;i++)
{
packet[i]=(u_char)i;
}
{
fprintf(stderr,
"\nError sending the packet: %s\n",
pcap_geterr(fp));
return;
}
return;
}
#define PCAP_OPENFLAG_PROMISCUOUS
Defines if the adapter has to go in promiscuous mode.
struct pcap pcap_t
Descriptor of an open capture instance. This structure is opaque to the user, that handles its conten...
#define PCAP_ERRBUF_SIZE
Size to use when allocating the buffer that contains the libpcap errors.
pcap_t * pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf)
Open a generic source in order to capture / send (WinPcap only) traffic.
int pcap_sendpacket(pcap_t *p, u_char *buf, int size)
Send a raw packet.
char * pcap_geterr(pcap_t *p)
return the error text pertaining to the last pcap library error.
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.
#include <stdlib.h>
#include <stdio.h>
#include <pcap.h>
void usage();
void main(int argc, char **argv)
{
FILE *capfile;
int caplen, sync;
u_int res;
u_char *pktdata;
float cpu_time;
u_int npacks = 0;
errno_t fopen_error;
if (argc <= 2 || argc >= 5)
{
usage();
return;
}
fopen_error = fopen_s(&capfile, argv[1],"rb");
if(fopen_error != 0){
printf("Error opening the file, errno %d.\n", fopen_error);
return;
}
fseek(capfile , 0, SEEK_END);
fclose(capfile);
if(argc == 4 && argv[3][0] == 's')
sync = TRUE;
else
sync = FALSE;
NULL,
NULL,
argv[1],
errbuf
) != 0)
{
fprintf(stderr,"\nError creating a source string\n");
return;
}
{
fprintf(stderr,"\nUnable to open the file %s.\n", source);
return;
}
{
fprintf(stderr,"\nUnable to open adapter %s.\n", source);
return;
}
{
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();
}
while ((res =
pcap_next_ex( indesc, &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");
return;
}
cpu_time = (float)clock ();
{
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");
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);
}
#define PCAP_SRC_FILE
Internal representation of the type of source in use (file, remote/local interface).
#define PCAP_BUF_SIZE
Defines the maximum buffer size in which address, port, interface names are kept.
int pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, const u_char **pkt_data)
Read a packet from an interface or from an offline capture.
int pcap_sendqueue_queue(pcap_send_queue *queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data)
Add a packet to a send queue.
int pcap_datalink(pcap_t *p)
Return the link layer of an adapter.
void pcap_sendqueue_destroy(pcap_send_queue *queue)
Destroy a send queue.
pcap_send_queue * pcap_sendqueue_alloc(u_int memsize)
Allocate a send queue.
int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf)
Accept a set of strings (host name, port, ...), and it returns the complete source string according t...
void pcap_close(pcap_t *p)
close the files associated with p and deallocates resources.
u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync)
Send a queue of raw packets to the network.
Header of a packet in the dump file.
bpf_u_int32 caplen
length of portion present
A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit().
u_int len
Current size of the queue, in bytes.
<<< Previous Next >>>