@xunuo
2017-07-12T12:26:13.000000Z
字数 3739
阅读 1597
网络数据包分析
#include <cstdlib>#include <pcap.h>/*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地址};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]; //错误缓冲区,大小为256int res; //抓包函数pcap_next_ex返回值,1-成功、0:获取报文超时、-1:发生错误、-2: 获取到离线记录文件的最后一个报文u_int netmask; //子网掩码//ether proto protocol:如果数据包属于某些以太协议(protocol)类型, 则与此对应的条件表达式为真,协议字段可以是ARPchar 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);elseprintf(" (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_s("%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;elsenetmask = 0xffffff; /* 如果接口没有地址,那么我们假设一个C类的掩码 */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 (ntohs(arph->op)==1)printf("请求报文\n");elseprintf("应答报文\n");printf("数据包具体内容:\n");for (int i = 1; i < header->len; i++){printf("%02x ", pkt_data[i - 1]);if (i % 8 == 0)printf(" ");if (i % 16 == 0)printf("\n");}printf("\n长度(B):%d\n", header->len);//长度printf("源IP:");for (i = 0; i <=3; i++){if(i==3)printf("%d\n", arph->sip[3]);elseprintf("%d.", arph->sip[i]);}printf("目的IP:");for (i = 0; i <=3; i++){if(i==3)printf("%d\n", arph->dip[3]);elseprintf("%d.", arph->dip[i]);}printf("源MAC:");for (i = 0; i <=5; i++){if(i==5)printf("%02x\n", arph->smac[5]);elseprintf("%02x-", arph->smac[i]);}printf("目的MAC:");for (i = 0; i <=5; i++){if(i==5)printf("%02x\n", *(pkt_data + 5));elseprintf("%02x-", *(pkt_data + i));}if (ntohs(arph->hdtyp) == 1)printf("硬件类型:Ethernet\n");printf("协议类型:%04x\n", ntohs(arph->protyp));printf("硬件长度:%d\n", arph->hdsize);printf("协议长度%d\n", arph->prosize);printf("操作类型:%d\n", ntohs(arph->op));printf("\n\n");}if (res == -1) //接收ARP包出错{printf("Error reading the packets: %s\n", pcap_geterr(adhandle));return -1;}return 0;}