计算机网络课程设计--基于winpcap实现简单的抓包

这篇博客主要记录如何通过winpcap实现网络抓包。首先我们简单介绍一下这次主要用到的函数:

pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf);
该方法打开一个网络适配器,三个参数的解释如下:

第一个参数:适配器名称,是数据的来源

第二个参数:制定要捕获数据包中的哪些部分。技术文档中介绍说,在一些操作系统中,驱动可以被配置成只捕获数据包的初始化部分,它的好处就是可以减少应用程序间

复制数量的量,从而提高捕获效率。下面将要给出的实例程序中设为65535。我们知道对于使用以太网的局域网来说,最大传输单元为1500字节,那么设为65535则能保证

收到完整的数据包。

第三个参数是最重要的一个值,它用来指示适配器是否需要设置成混杂模式,简单的说,就是所有流经这个网卡的数据都会被捕获,无论是不是发给这个网卡的,大多数捕获程序都会选择混杂模式,当然你也可以选择单一模式。

混杂模式:PCAP_OPENFLAG_PROMISCUOUS

第四个参数表示的是读取数据的超时时间,单位是毫秒。意思就是说会在read_timeout时间内对适配器的读取操作进行响应,不管有没有读到数据。这里有两个特殊的值需

要说明一下,如果将时间设置为0意味着没有超时,那么如果没有数据到达的话,读操作就永远不会返回;如果设置为-1则恰恰相反,不论有没有读到数据都会立即返回。

第五个参数之前提到过,它表示的是连接远程用户的验证信息,由于我们不需要连接到远程用户,这里置为NULL。

第六个参数是错误信息缓冲,如果该函数在调用过程中出错则会将出错信息保存在缓冲中。

函数的返回值是一个pcap_t的指针类型,查看声明处我们可以发现pcap_t实际上是pcap结构体,而文档上说明它是一个已打开的捕捉实例的描述符。

代码:

#define HAVE_REMOTE
#include 

/* packet handler 函数原型 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);

int main()
{
    pcap_if_t *alldevs;
    pcap_if_t *d;
    int inum;
    int i=0;
    pcap_t *adhandle;
    char errbuf[PCAP_ERRBUF_SIZE];

    /* 获取本机设备列表 */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    {
        fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }

    /* 打印列表 */
    for(d=alldevs; d; d=d->next)
    {
        printf("%d. %s", ++i, d->name);
        if (d->description)
            printf(" (%s)\n", d->description);
        else
            printf(" (No description available)\n");
    }

    if(i==0)
    {
        printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
        return -1;
    }

    printf("Enter the interface number (1-%d):",i);
    scanf("%d", &inum);

    if(inum < 1 || inum > i)
    {
        printf("\nInterface number out of range.\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

    /* 跳转到选中的适配器 */
    for(d=alldevs, i=0; i< inum-1 ; d=d->next, i++);

    /* 打开设备 */
    if ( (adhandle= pcap_open(d->name,          // 设备名
                              65535,            // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
                              PCAP_OPENFLAG_PROMISCUOUS,    // 混杂模式
                              1000,             // 读取超时时间
                              NULL,             // 远程机器验证
                              errbuf            // 错误缓冲池
                             ) ) == NULL)
    {
        fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

    printf("\nlistening on %s...\n", d->description);

    /* 释放设备列表 */
    pcap_freealldevs(alldevs);

    /* 开始捕获 */
    pcap_loop(adhandle, 0, packet_handler, NULL);

    return 0;
}

pcap_loop函数API:

int pcap_loop  ( pcap_t *  p,  
  int  cnt,  
  pcap_handler  callback,  
  u_char *  user   
 ) 
这个函数就是用来捕获数据包的,而且是通过回调函数的方法进行捕获,第三个参数就是回调函数。

packet_handler:

/* 每次捕获到数据包时,libpcap都会自动调用这个回调函数 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
    struct tm *ltime;
    char timestr[16];
    time_t local_tv_sec;

    /* 将时间戳转换成可识别的格式 */
    local_tv_sec = header->ts.tv_sec;
    ltime=localtime(&local_tv_sec);
    strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);

    printf("%s,%.6ld len:%d\n", timestr, header->ts.tv_usec, header->len);

}
相当于把数据包里面的时间戳,长度显示出来。





你可能感兴趣的:(计算机网络课程设计)