WinPcap基础知识(第八课:发送数据包)

尽管WinPcap这个名字已经很清晰的表明这个库是用来捕获数据包的,但是另外一个非常有用的功能是提供了原始网络操作。这里,用户可以找到一系列函数来发送数据包,这节课我们就会向大家一一展示。注意到原始的libcap库不提供任何方法来发送数据库:这里讲的所有的函数是WinPcap扩展,它们不能在Unix系统下面工作。 用pcap_sendpacket()发送单个数据包函数原型: int pcap_sendpacket ( pcap_t * p, u_char * buf, int size ) 说明:该函数可以发送一个原始数据包到网络上。Buf包含要发送到网络上的数据包的数据(包括协议头)。注意,MAC CRC不用包含,因为它是网卡驱动计算然后添加的。返回值为0说明数据包已经成功的发送了,否则返回-1。

 

pcap_sendpacket()发送单个包

 

最简单发送一个数据包的方法如下面代码所示。打开一个适配器后,调用pcap_sendpacket()来发送一个手工数据包。Pcap_sendpacket()的参数如下:一个包含将要发送的数据缓冲区;缓冲区的长度;将要在它上面发送数据的适配器。注意到缓冲区的数据是不经过处理就被发送到网络上的,这就意味着应用程序必须要创建正确的协议头以保证发送一些有用的信息。

 

#include <stdlib.h> #include <stdio.h> #define HAVE_REMOTE #include <pcap.h> #pragma comment(lib,"wpcap") 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]=(u_char)i; } /* Send down the packet */ if (pcap_sendpacket(fp, packet, 100 /* size */) != 0) { fprintf(stderr,"/nError sending the packet: %s/n", pcap_geterr(fp)); return; } return; }

 

发送队列

Pcap_sendpacket()提供了一个简单而又直接的方法来发送一个数据包,发送队列提供了一个高级的有效的最优化机制来发送一组数据包。一个发送队列是一个用来存放即将要发送到网络上的多个数据包的容器。它有大小,大小表明了它能够存放的数据包的最大数量。发送队列是通过调用pcap_sendqueue_alloc()函数来创建的,创建时要指定所需创建的队列的大小。一旦队列创建完毕,就可以使用pcap_sendqueue_queue()来存放一个数据包在队列里面。此函数获得一个带有时间戳,长度,数据包缓冲区的pcap_pkthdr。这些参数同样被pcap_next_ex()和函数pcap_handler()接收。因此,把一个刚捕获的或者从文件中读取出来的数据包放到队列中去就是把数据包作为参数传递给pcap_sendqueue_queue()

  

看看几个函数

 

int pcap_sendqueue_queue  (  pcap_send_queue *  queue, 

 

  const struct pcap_pkthdr *  pkt_header, 

 

  const u_char *  pkt_data  ) 

 

能:向发送队列中添加一个数据包。Pcap_sendqueue_queue()方法向队列得末尾添加一个数据包。Pkt_header参数指向一个pcap_pkthdr结构体(结构体含有数据包得时间戳,长度,以及一个pkt_data指针,它指向包数据的指针)。Pcap_ptkhdr结构在Winpcaplibcap里面都是用来存放包,因此发送一个捕获文件时直接发送的。“原始包”意味着发送应用程序将必须包含协议头。

 

CRC头就不用了,那是网卡驱动程序进行计算然后加上的。

 

u_int pcap_sendqueue_transmit  (  pcap_t *  p,   

  pcap_send_queue *  queue, 

 

  int  sync  )  

 

功能:把一个装有原始包的队列发送到网络上。注意一下参数sync,它决定发送操作是否必须同步。如果是非0,数据包发送要注意时间戳(the packets are sent respecting the timestamps);否则,数据包尽可能快的发送出去。

 

为了发送一个队列,WinPcap提供了pcap_sendqueue_transmit()函数。注意一下第三个参数:如果是非空,发送就是同步的。例如:数据包的相关的时间戳也会被重视。这就需要占用大量cpu资源,因为同步方式代替在内核。。。。。(翻译不出来)

 

 注意到用pcap_sendqueue_transmit()来发送一个队列比执行一序列的pcap_sendpacket()每次发送一个数据包来说效率高的多。因为一个发送队列是一个缓冲区,在内核级大量减少了上下文切换的次数。

 

当不再需要一个队列,就可以用pcap_sendqueue_destroy()函数来释放,它会释放与之关联的所有的缓冲区。

  

下面的代码显示了怎么样使用发送队列。首先它用pcap_open_offline()函数打开一个捕获文件,然后把数据包从文件中拷贝到合适分配的队列里面。这时,开始传送队列。  

 

注意到dump文件的链路层是与使用pcap_datalink()方法来发送数据包所在的其中一个接口一致的。如果他们不同的话就会打印出一个警告:sending on a link-layer the packets captured from a different one is quite 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> #define WPCAP #define HAVE_REMOTE #include <pcap.h> #pragma comment(lib,"wpcap") 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; errno_t fopen_error; /* Check the validity of the command line */ if (argc <= 2 || argc >= 5) { usage(); return; } /* Retrieve the length of the capture file */ 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); 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, (const unsigned char **)&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); }

 

 

 

你可能感兴趣的:(struct,File,header,null,Authentication,documentation)