当前位置: 网站首页>>协议分析>>Winpcap>>

WinpCap学习笔记(6)

时间:2006-10-16 来源:binaryluo的博客 作者:binaryluo 点击:
尽管Winpcap清楚地指出了它的目的是数据包的截获,但是它还提供了一些对于原始网络(rawnetworking)的有用特性。用户可以找到一组完整的发包(sendpackets)函数。需要注意的是,libpcap目前并没有提供任何的发包的方法。 用pcap_sendpacket()发送单个数据包 下面的代
  

   尽管Winpcap清楚地指出了它的目的是数据包的截获,但是它还提供了一些对于原始网络(raw networking)的有用特性。用户可以找到一组完整的发包(send packets)函数。需要注意的是,libpcap目前并没有提供任何的发包的方法。

 

用pcap_sendpacket()发送单个数据包

    下面的代码片断表现了最简单的发送一个数据包的过程。打开适配器后,pcap_sendpacket()被用来发送一个手工的(hand

-crafted)数据包。

 

    试验代码:

#include <stdlib.h>
#include <stdio.h>
#include <pcap.h>
#include <remote-ext.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("\tusage: %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 destinat 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;
}

函数1:

int pcap_sendpacket(pcap_t*   p,

u_char*   buf,

int       size)

    发送一个原始数据包(raw packet)到网络上。p是用来发送数据包的那个接口,buf包含着要发送的数据包的数据(包括各种各样的协议头),size是buf所指的缓冲区的尺寸,也就是要发送的数据包的大小。MAC循环冗余码校验不必被包含,因为它很容易被计算出来并被网络接口驱动添加。如果数据包被成功发送,返回0;否则,返回-1。

 

发送队列(Send queues)

      pcap_sendpacket()提供了一个简单快捷的发送单个数据包的方法,发送队列(send queues)提供了一个高级的,强大的,优化的发送一组数据包的机制。发送队列是一个用来保存将要发送到网络上的的众多数据包的容器。它有一个大小,描述了它所能容纳的最大字节数。

    通过指定发送队列的大小,pcap_sendqueue_alloc()函数创建一个发送队列。一旦发送队列被创建好,pcap_sendqueue_queue()可以把一个数据包添加到发送队列里。函数pcap_sendqueue_alloc()的参数必须与pcap_next_ex()和pcap_handler()的相同,因此,从一个文件捕获或读取数据包的时候,如何进行pcap_sendqueue_alloc()的参数传递是一个问题。

 

试验代码:

 

#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);
             [Page]
    /* 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); [Page]
    }
    
    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);
}

函数1:

pcap_send_queue* pcap_sendqueue_alloc(u_int memsize)

    为一个发送队列分配空间,即创建一个用来存储一组原始数据包(raw packet)的缓冲区,这些数据包将用pcap_sendqueue_transmit()提交到网络上。memsize是队列容纳的字节数,因此它决定了队列所能容纳的最大数据量。使用pcap_sendqueue_queue()可以在发送队列中插入数据包。

 

函数2:

int pcap_sendqueue_queue(pcap_send_queue*            queue,

const struct pcap_pkthdr* pkt_header,

const u_char*             pkt_data)

    添加一个数据包到发送队列中。queue指向发送队列的尾部;pkt_header指向一个pcap_pkthdr结构体,该结构体包含时间戳和数据包的长度;pkt_data指向存放数据包数据部分的缓冲区。

    为了提交一个发送队列,Winpcap提供了pcap_sendqueue_transmit()函数。

 

函数3:

u_int pcap_sendqueue_transmit(pcap_t*                 p,

pcap_send_queue*      queue,

int                   sync)

    该函数将队列里的内容提交到线路上。p是一个指向适配器的指针,数据包将在这个适配器上被发送;queue指向pcap_send_queue结构体,它包含着要发送的所有数据包;sync决定了发送操作是否被同步:如果它是非0(non-zero),发送数据包关系到时间戳,否则,他们将以最快的速度发送(即不考虑时间戳)。

    返回值是发送的字节数。如果它小于size参数,将发生一个错误。该错误可能是由于驱动/适配器(driver/adapter)问题或发送队列的不一致/伪造(inconsistent/bogus)引起。

注意:

l         使用该函数的效率比使用pcap_sendpacket()发送一系列数据包的效率高,因为数据包在核心态(kernel-level)被缓冲,所以降低了上下文的交换次数。因此,使用pcap_sendqueue_transmit()更好。

l         当sync被设置为TRUE时,随着一个高精度的时间戳,数据包将在内核伴被同步。这就要求CPU的数量是不可忽略的,通常允许以一个微秒级的精度发送数据包(这依赖于机器性能计数器的准确度)。然而,用pcap_sendpacket()发送数据包不能达到这样一个精确度。

    如果第三个参数非0,发送将被同步(synchronized),即相关的时间戳将被注意。这个操作要求注意CPU的数量,因为使用“繁忙 等待(busy wait)”循环,同步发生在内核驱动。

    当不再需要一个队列时,可以用pcap_sendqueue_destroy()来删除之,这将释放与该发送队列相关的所有缓冲区。
 

------分隔线----------------------------
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
最新评论 查看所有评论
发表评论 查看所有评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 密码: 验证码:
推荐内容
  • 如何编译WinPcap

    编译驱动 编译NPF时,有两个主要的路径:Windows NTx和Windows 9x。注意,因为NPF驱动...

  • winpcap 驱动简介

    winpcap(windowspacketcapture)是windows平台下一个免费,公共的网络访问系统。开发wi...

  • 命令行下装WinPcap

    WinPcap是个很常用的工具,但必须在窗口界面下安装。在网上也可以找到不用GUI的版本(...

  • WinPcap 教程

    原文出处:http://winpcap.polito.it/docs/man/html/index.html 作者: LorisDegioanni...