WinPcap实战(二)——接收ARP包

来源:互联网 发布:哪里有招聘网络写手 编辑:程序博客网 时间:2024/05/16 05:07

ARP帧结构

ARP帧结构(28B):硬件类型(2B,Ethernet:0x1)——上层协议类型(2B,IP:0x0800)——硬件地址长度(1B,0x6)——IP地址长度(1B,0x4)——操作(2B,请求: 0x1; 应答: 0x2)——源MAC地址(6B)——源IP地址(6B)——目的MAC地址(6B)——目的IP地址(6B)

依据ARP帧结构定义结构体

struct ArpHeader{    unsigned short hdtyp;   //硬件类型    unsigned short protyp;   //协议类型    unsigned char hdsize;   //硬件地址长度    unsigned char prosize;   //协议地址长度    unsigned short op;   //操作类型,ARP请求(1),ARP应答(2),RARP请求(3),RARP应答(4)。    u_char smac[6];   //源MAC地址    u_char sip[4];   //源IP地址    u_char dmac[6];   //目的MAC地址    u_char dip[4];   //目的IP地址};

源代码

#include "stdafx.h"#include "pcap.h"struct ArpHeader{    unsigned short hdtyp;   //硬件类型    unsigned short protyp;   //协议类型    unsigned char hdsize;   //硬件地址长度    unsigned char prosize;   //协议地址长度    unsigned short op;   //操作类型,ARP请求(1),ARP应答(2),RARP请求(3),RARP应答(4)。    u_char smac[6];   //源MAC地址    u_char sip[4];   //源IP地址    u_char dmac[6];   //目的MAC地址    u_char dip[4];   //目的IP地址};int main(){    pcap_if_t *alldevs;   //所有网络适配器      pcap_if_t *d;   //选中的网络适配器     int inum;   //选择网络适配器    int i = 0;   //for循环变量    pcap_t *adhandle;   //打开网络适配器,捕捉实例,是pcap_open返回的对象    char errbuf[PCAP_ERRBUF_SIZE];   //错误缓冲区,大小为256    int res;   //抓包函数pcap_next_ex返回值,1-成功、0:获取报文超时、-1:发生错误、-2: 获取到离线记录文件的最后一个报文    u_int netmask;    //子网掩码    //ether proto protocol:如果数据包属于某些以太协议(protocol)类型, 则与此对应的条件表达式为真,协议字段可以是ARP    char packet_filter[] = "ether proto \\arp";   //要抓取的包的类型,这里是抓取ARP包;    struct bpf_program fcode;   //pcap_compile所调用的结构体    struct tm *ltime;   //和时间处理有关的变量     char timestr[16];   //和时间处理有关的变量    time_t local_tv_sec;    //和时间处理有关的变量    struct pcap_pkthdr *header;   //接收到的数据包的头部    const u_char *pkt_data;    //接收到的数据包的内容    /* 获取本机设备列表 */    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,          // 设备名        65536,            // 要捕捉的数据包的部分                           // 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;    }    /* 检查数据链路层,为了简单,我们只考虑以太网 */    if (pcap_datalink(adhandle) != DLT_EN10MB)    {        fprintf(stderr, "\nThis program works only on Ethernet networks.\n");        /* 释放设备列表 */        pcap_freealldevs(alldevs);        return -1;    }    if (d->addresses != NULL)        /* 获得接口第一个地址的掩码 */        netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;    else        /* 如果接口没有地址,那么我们假设一个C类的掩码 */        netmask = 0xffffff;    //编译过滤器    if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0)    {        fprintf(stderr, "\nUnable to compile the packet filter. Check the syntax.\n");        /* 释放设备列表 */        pcap_freealldevs(alldevs);        return -1;    }    //设置过滤器    if (pcap_setfilter(adhandle, &fcode) < 0)    {        fprintf(stderr, "\nError setting the filter.\n");        /* 释放设备列表 */        pcap_freealldevs(alldevs);        return -1;    }    printf("\nlistening on %s...\n", d->description);    /* 释放设备列表 */    pcap_freealldevs(alldevs);    /*以上代码在WinPcap开发文档中都可以找到,解析ARP包的代码则要自己编写*/    /* 获取数据包 */    while ((res = pcap_next_ex(adhandle, &header, &pkt_data)) >= 0) {        if (res == 0)            /* 超时时间到 */            continue;        //解析ARP包        ArpHeader* arph = (ArpHeader *)(pkt_data + 14);        //类型         printf("报文类型:");        if (arph->op == 256)            printf("请求报文\t");        else            printf("应答报文\t");        //长度        printf("长度(B):%d\t", header->len);        //时间        /* 将时间戳转换成可识别的格式 */        local_tv_sec = header->ts.tv_sec;        ltime = localtime(&local_tv_sec);        strftime(timestr, sizeof timestr, "%H:%M:%S", ltime);        printf("时间:%s\n", timestr);        //输出源IP        printf("源IP:");        for (i = 0; i < 3; i++)        {            printf("%d.", arph->sip[i]);        }        printf("%d\t", arph->sip[3]);        //输出目的IP        printf("目的IP:");        for (i = 0; i < 3; i++)        {            printf("%d.", arph->dip[i]);        }        printf("%d\n", arph->dip[3]);        //输出源MAC        printf("源MAC:");        for (i = 0; i < 5; i++)        {            printf("%02x-", arph->smac[i]);        }        printf("%02x\t", arph->smac[5]);        //输出目的MAC        printf("目的MAC:");        for (i = 0; i < 5; i++)        {            printf("%02x-", *(pkt_data + i));        }        printf("%02x\n", *(pkt_data + 5));        printf("----------------------------我是一只分隔线-----------------------------\n");    }    if (res == -1) {   //接收ARP包出错        printf("Error reading the packets: %s\n", pcap_geterr(adhandle));        return -1;    }    return 0;}

运行结果

程序在VS2015企业版里面运行无误,需要提前配置好WinPcap的编程环境

选择第三个网卡,开始监听网络
这里写图片描述

等待几分钟后,抓取到ARP包
这里写图片描述

传送门

发送ARP包:
http://blog.csdn.net/u013539342/article/details/48523933#t4
参考网址:http://blog.csdn.net/cqcre/article/details/40213911
WinPcap编程配置:http://www.findspace.name/easycoding/871
VS下This function or variable may be unsafe解决办法:
http://jingyan.baidu.com/article/49711c616b8a1ffa441b7cdc.html

1 0
原创粉丝点击