现在,我们可以捕获并过滤网络流量了,那就简单协议个程序分析网络数据包。

这里我们只是解析所捕获数据包的首部,打印一些数据包首部的信息。我们以UDP为例,因为UDP比较简单。

首先,应该介绍下网络数据包的格式。网络中的数据包每经过一个层次都会加上那个层的报头来标注一些重要的信息。捕获到的数据包首先有个mac报头,14字节,包含6字节目的mac地址、6字节源mac地址,和2字节上一层协议。这里我们不关注mac报头,所以省略。

接下来是IP数据包,包的格式如下图:

IP数据包有20字节的报头,报头格式如下图:

WinPcap没有给出一个保存IP报头信息的结构体,所以需要我们自己定义。下面是IP报头的定义:

/* 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数据包的位置。下面的代码计算首部长度:

ip_len = (ih->ver_ihl & 0xf) * 4;
得到首部长度后就可以得到UDP的位置了。下图是UDP报头的格式:
同样,UDP结构也需要我们自己定义:
/* 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;

这里涉及到小端法和大端法。下面简单介绍一下。
《UNXI网络编程》定义:术语“小端”和“大端”表示多字节值的哪一端(小端或大端)存储在该值的起始地址。小端存在起始地址,即是小端字节序;大端存在起始地址,即是大端字节序。
也就是说,小端法(Little-Endian)将低位字节存储在内存的低地址即起始地址处,高字节存储在高地址;而大端法(Big-Endian)将低位字节存储在高地址,将高位字节存储在低地址处。
举个例子,对于整形0x12345678。它在大端法和小端法的系统内中,分别如下图所示的方式存放:
还有一个概念叫网络字节序,我们知道网络上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它是将这个字节作为高位还是低位来处理呢?
网络字节序定义:收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端法存放。
网络字节序说是大端字节序。
比如我们经过网络发送0x12345678这个整形,在80X86平台中,它是以小端法存放的,在发送前需要使用系统提供的htonl将其转换成大端法存放,如下图:
因此,对于多字节属性,需要使用函数在网络字节序和主机字节序中转换。
下面是程序的主要代码,将UDP的源IP地址、源端口、目的IP地址、目的端口打印出来:
#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);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("%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);
}

运行结果如下:

WinPcap笔记(7):分析数据包(1)相关推荐

  1. Wireshark数据抓包教程之认识捕获分析数据包

    Wireshark数据抓包教程之认识捕获分析数据包 认识Wireshark捕获数据包 当我们对Wireshark主窗口各部分作用了解了,学会捕获数据了,接下来就该去认识这些捕获的数据包了.Wiresh ...

  2. [渗透攻防] 四.详解MySQL数据库攻防及Fiddler神器分析数据包

    这是最近学习渗透和网站攻防的基础性文章,前面文章从数据库原理解读了防止SQL注入.SQLMAP的基础用法.数据库差异备份.Caidao神器.这篇文章将详细讲解MySQL数据库攻防知识,有点类似第一篇文 ...

  3. Linux中如何使用Wireshark来分析数据包?

    学习分析网络数据包是一项强大的技能. 当连接到网络后,大多数情况下我们不会去考虑实现这一切的底层网络协议.现在,当你阅读本文时,计算机正在交换大量数据包并通过Internet进行传输. 要了解这些协议 ...

  4. ARP原理概述——基于WinPcap发送ARP请求数据包获取远程MAC地址

    ARP原理概述--基于WinPcap发送ARP请求数据包获取远程MAC地址 ARP协议 ARP概述 ARP工作原理 ARP数据包格式 编写程序发送ARP请求获取本机和远程IP的MAC 注意: ARP协 ...

  5. WinPcap笔记(8):分析数据包(2)

    上一讲里分析了UDP数据包,这里简单分析一下TCP数据包. TCP是面向有连接的传输协议,因此相对来说比较复杂.下面是TCP报头的格式: 同样,需要我们自己定义TCP报头: /* tcp 首部 */ ...

  6. Winpcap进行抓包,分析数据包结构并统计IP流量

    2020年华科计算机网络实验 文末有完整代码,仅限参考 一.实验目的 随着计算机网络技术的飞速发展,网络为社会经济做出越来越多的贡献,可以说计算机网络的发展已经成为现代社会进步的一个重要标志.但同时, ...

  7. WinPcap分析数据包

    一.前言 通过前面的学习,我们已经知道了如何打开设备捕获数据了,接下来就可以捕获并过滤网络流量了. 本教程主要的目标是展示如何解析数据包的协议首部,选中分析和实现UDP协议,因为UDP协议相对于其它协 ...

  8. VC++分析数据包实现Telnet协议分析

    Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式.它为用户提供了在本地计算机上完成远程主机工作的能力.在终端使用者的电脑上使用telnet程序,用它连接 ...

  9. python分析数据包_Python解析pcap数据包

    Post Views: 29,789 零.前言 历时数月,终于结束了考研初试,Blog也很长时间没有更新了,期间还是有些小伙伴来Blog看文章很是感动.以后一定会坚持更新,尽量给大家推送一些干货.这次 ...

最新文章

  1. 异步获取邮件推送结果
  2. IP与DSCP优先级
  3. linux 查看文件夹大小 du命令
  4. java流上传文档把磁盘撑满_BOOT目录磁盘占用满处理
  5. css3 flex属性flex-grow、flex-shrink、flex-basis学习笔记
  6. 通过实例看懂diff命令输出
  7. win7系统下VS2015中CUDA8.0调试程序问题
  8. 问题十三:怎么用ray tracing画个球
  9. 计算机故障升温降温法,电脑故障排除1000例
  10. 1000瓶水10只小白鼠问题-面试题目
  11. php表单提交的时候验证失败,解决有时首页表单提交“安全验证失败,请刷新页面后重新提交!”问题...
  12. 连云港师范专科学校计算机老师,喜报:我校学生在2021年中国大学生计算机设计比赛江苏省赛中获一等奖...
  13. 互联网乡镇综治云平台解决方案
  14. 华三防火墙远程telnet登录设置
  15. ps -aux排序--按内存使用排序或按cpu使用排序
  16. 微信小程序--优购商城项目(8)
  17. python列表操作计算列表长度并输出,python列表 (list)
  18. 腾讯云物联网MQTT对接
  19. 网盘搜索神器php源码,127网盘搜索源码|网盘资源搜索神器|thinkphp3.1.3框架开发的...
  20. ALSA声卡驱动中的DAPM详解之一:kcontrol

热门文章

  1. 数据结构与算法2——数组
  2. linux 给文件添加用户名和密码是什么格式,linux成批添加用户的命令
  3. mysql strtok,strtok()和strtok_r()
  4. mysql 3种报错_MySQL读取Binlog日志常见的3种错误-阿里云开发者社区
  5. ddr5内存上市时间_DDR5内存明年才能上市,SK Hynix已预研DDR6:12Gbps
  6. python输入代码界面通常_vscode写python时的代码错误提醒和自动格式化的方法
  7. 热启动必须联网吗_供暖结束,地暖是关闭供水阀门还是关闭回水阀门?你做对了吗?...
  8. java 传递bean_如何将bean作为参数传递给JSP标记?
  9. 嵌套矩形——DAG上的动态规划
  10. 414. 第三大的数