织女的身份:WinPcap基础知识(第八课:发送数据包)

来源:百度文库 编辑:中财网 时间:2024/04/28 13:36:20
 尽管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()的参数如下:一个包含将要发送的数据缓冲区;缓冲区的长度;将要在它上面发送数据的适配器。注意到缓冲区的数据是不经过处理就被发送到网络上的,这就意味着应用程序必须要创建正确的协议头以保证发送一些有用的信息。 view plaincopy to clipboardprint?
#include  
#include  
 
#define HAVE_REMOTE 
#include  
 
#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;  

#include
#include #define HAVE_REMOTE
#include #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结构在Winpcap和libcap里面都是用来存放包,因此发送一个捕获文件时直接发送的。“原始包”意味着发送应用程序将必须包含协议头。 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.  
#include   
#include   
 
#define WPCAP  
#define HAVE_REMOTE  
#include   
 
#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);  
}   本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qsycn/archive/2009/08/18/4459058.aspx