Winpcap打开适配器并捕获数据包:解析所捕获的数据包的协议首部

来源:互联网 发布:国内互联网网络股票 编辑:程序博客网 时间:2024/06/08 10:24

本程序的主要目标是展示如何解析所捕获的数据包的协议首部。这个程序可以称为UDPdump,打印一些网络上传输的UDP数据的信息。

我们选择分析和现实UDP协议而不是TCP等其它协议,是因为它比其它的协议更简单

#include "pcap.h"/* 4字节的IP地址 */typedef struct ip_address{    u_char byte1;    u_char byte2;    u_char byte3;    u_char byte4;}ip_address;/* IPv4 首部 */typedef struct ip_header{    u_char  ver_ihl;        // 版本 (4 bits) + 首部长度 (4 bits)    u_char  tos;            // 服务类型(Type of service)     u_short tlen;           // 总长(Total length)     u_short identification; // 标识(Identification)    u_short flags_fo;       // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits)    u_char  ttl;            // 存活时间(Time to live)    u_char  proto;          // 协议(Protocol)    u_short crc;            // 首部校验和(Header checksum)    ip_address  saddr;      // 源地址(Source address)    ip_address  daddr;      // 目的地址(Destination address)    u_int   op_pad;         // 选项与填充(Option + Padding)}ip_header;/* UDP 首部*/typedef struct udp_header{    u_short sport;          // 源端口(Source port)    u_short dport;          // 目的端口(Destination port)    u_short len;            // UDP数据包长度(Datagram length)    u_short crc;            // 校验和(Checksum)}udp_header;/* 回调函数原型 */void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);main(){pcap_if_t *alldevs;pcap_if_t *d;int inum;int i=0;pcap_t *adhandle;char errbuf[PCAP_ERRBUF_SIZE];u_int netmask;char packet_filter[] = "ip and udp";struct bpf_program fcode;    /* 获得设备列表 */    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");        /* 释放设备列表 */        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);        /* 开始捕捉 */    pcap_loop(adhandle, 0, packet_handler, NULL);        return 0;}/* 回调函数,当收到每一个数据包时会被libpcap所调用 */void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data){    struct tm *ltime;    char timestr[16];    ip_header *ih;    udp_header *uh;    u_int ip_len;    u_short sport,dport;    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.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);    /* 获得IP数据包头部的位置 */    ih = (ip_header *) (pkt_data +        14); //以太网头部长度    /* 获得UDP首部的位置 */    ip_len = (ih->ver_ihl & 0xf) * 4;    uh = (udp_header *) ((u_char*)ih + ip_len);    /* 将网络字节序列转换成主机字节序列 */    sport = ntohs( uh->sport );    dport = ntohs( uh->dport );    /* 打印IP地址和UDP端口 */    printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n",        ih->saddr.byte1,        ih->saddr.byte2,        ih->saddr.byte3,        ih->saddr.byte4,        sport,        ih->daddr.byte1,        ih->daddr.byte2,        ih->daddr.byte3,        ih->daddr.byte4,        dport);}


 

首先,我们将过滤器设置成"ip and udp"。在这种方式下,我们确信packet_handler()只会收到基于IPv4UDP数据包;这将简化解析过程,提高程序的效率。

我们还分别创建了用于描述IP首部和UDP首部的结构体。这些结构体中的各种数据会被packet_handler()合理地定位。

packet_handler(), 尽管只受限于单个协议的解析(比如基于IPv4UDP),不过它展示了捕捉器(sniffers)是多么的复杂,就像TcpDumpWinDump对网络数据流进行解码那样。因为我们对MAC首部不感兴趣,所以我们跳过它。为了简洁,我们在开始捕捉前,使用了pcap_datalink()MAC层进行了检测,以确保我们是在处理一个以太网络。这样,我们就能确保MAC首部是14位的。

IP数据包的首部就位于MAC首部的后面。我们将从IP数据包的首部解析到源IP地址和目的IP地址。

处理UDP的首部有一些复杂,因为IP数据包的首部的长度并不是固定的。然而,我们可以通过IP数据包的length域来得到它的长度。一旦我们知道了UDP首部的位置,我们就能解析到源端口和目的端口。

被解析出来的值被打印在屏幕上,形式如下所示:

1. \Device\Packet_{A7FD048A-5D4B-478E-B3C1-34401AC3B72F} (Xircom t 10/100 Adapter)
Enter the interface number (1-2):1

listening on Xircom CardBus Ethernet 10/100 Adapter...
16:13:15.312784 len:87 130.192.31.67.2682 -> 130.192.3.21.53

16:13:15.314796 len:137 130.192.3.21.53 -> 130.192.31.67.2682
16:13:15.322101 len:78 130.192.31.67.2683 -> 130.192.3.21.53

最后3行中的每一行,分别代表了一个数据包

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 三星手机外屏碎了怎么办 苹果手机外屏碎了怎么办 iphone6s听筒坏了怎么办 苹果x外屏碎了怎么办 苹果手机屏摔坏了怎么办 苹果8外屏摔碎了怎么办 苹果7内屏坏了怎么办 苹果手机屏幕里面有水痕怎么办 iphone6屏幕摔裂怎么办 苹果手机电池坏了怎么办 苹果手机充电器坏了怎么办 苹果充电器老是坏怎么办 苹果手机屏幕失控了怎么办 手机自己乱点怎么办 手机点屏幕没用怎么办 手机界面不动了怎么办 手机关不了机怎么办 小米5花屏怎么办 小米手机死机怎么办呢 手机触屏失灵怎么办? 手机触屏不行怎么办 苹果手机屏幕触摸失灵怎么办 苹果7按键失灵怎么办 苹果中间键失灵怎么办 苹果屏触摸不灵怎么办 ipad屏幕乱跳怎么办 屏幕自己乱点怎么办 手机触屏漂移怎么办 玩不好飘频怎么办 苹果手机城乱码了怎么办 苹果手机屏幕乱跳怎么办 苹果笔记本键盘乱码怎么办 苹果电脑打开word乱码怎么办 iphone5s屏幕竖纹怎么办 电脑显示跳屏怎么办 电脑显示器跳屏怎么办 ipad老是跳屏怎么办 lol一直跳ping怎么办 电脑图标一直闪怎么办 vivo手机跳屏怎么办 手机跳屏怎么办oppo