一文教你如何用C代码解析一段网络数据包?【含代码】

2023-11-10

本文的目的是通过随机截取的一段网络数据包,然后根据协议类型来解析出这段内存。

学习本文需要掌握的基础知识:

  1. 网络协议
  2. C语言
  3. Linux操作
  4. 抓包工具的使用

其中抓包工具的安装和使用见下文:

一文包你学会网络数据抓包

视频教学链接如下:

教你如何抓取网络中的数据包!黑客必备技能

一、截取一个网络数据包

通过抓包工具,随机抓取一个tcp数据包


科莱抓包工具解析出的数据包信息如下:

数据包的内存信息:

数据信息可以直接拷贝出来:

二、用到的结构体

下面,一口君就手把手教大家如何解析出这些数据包的信息。

我们可以从Linux内核中找到协议头的定义

  • 以太头:
drivers\staging\rtl8188eu\include\if_ether.h	
struct ethhdr {
	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
	unsigned short	h_proto;		/* packet type ID field	*/
};
  • IP头
	include\uapi\linux\ip.h	
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)  //小端模式
	__u8	ihl:4,
		version:4;
#elif defined(__BIG_ENDIAN_BITFIELD)    //大端模式
	__u8	version:4,
		ihl:4;
#endif
	__u8	tos;
	__u16	tot_len;
	__u16	id;
	__u16	frag_off;
	__u8	ttl;
	__u8	protocol;
	__u16	check;
	__u32	saddr;
	__u32	daddr;
	/*The options start here. */
};

tcp头

include\uapi\linux\tcp.h
struct tcphdr {
	__be16	source;
	__be16	dest;
	__be32	seq;
	__be32	ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u16	res1:4,
		doff:4,
		fin:1,
		syn:1,
		rst:1,
		psh:1,
		ack:1,
		urg:1,
		ece:1,
		cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
	__u16	doff:4,
		res1:4,
		cwr:1,
		ece:1,
		urg:1,
		ack:1,
		psh:1,
		rst:1,
		syn:1,
		fin:1;
#else
#error	"Adjust your <asm/byteorder.h> defines"
#endif	
	__be16	window;
	__sum16	check;
	__be16	urg_ptr;
};

因为协议头长度都是按照标准协议来定义的,

所以以太长度是14,
IP头长度是20,
tcp头长度是20,

各个协议头对应的内存空间如下:

三、解析以太头

#define MAC_ARG(p) p[0],p[1],p[2],p[3],p[4],p[5]
	struct ethhdr *ethh;
	unsigned char *p = pkt;
	
	ethh = (struct ethhdr *)p;

	printf("h_dest:%02x:%02x:%02x:%02x:%02x:%02x \n", MAC_ARG(ethh->h_dest));
	printf("h_source:%02x:%02x:%02x:%02x:%02x:%02x \n", MAC_ARG(ethh->h_source));
	printf("h_proto:%04x\n",ntohs(ethh->h_proto));

注意,数据包中的数据是网络字节序,如果要提取数据一定要注意字节序问题
ethh->h_proto 是short类型,占2个字节,所以存储到本地需要使用函数ntohs
其中:
n:network 网络字节序
h:host 主机字节序
s:short 2个字节
l:long 4个字节
ntohl() :4字节网络字节序数据转换成主机字节序
htons() :2字节主机字节序数据转换成网络字节序
ntohs() :2字节网络字节序数据转换成主机字节序
htonl() :4字节主机字节序数据转换成网络字节序

当执行下面这条语句时,

ethh = (struct ethhdr *)p;

结构体指针变量eth的成员对应关系如下:

以太头
最终打印结果如下:

四、解析ip头

解析ip头思路很简单,

就是从pkt头开始偏移过以太头长度(14字节)就可以找到IP头,

解析代码如下:

#define IP_ARG(p)  p[0],p[1],p[2],p[3]
	/*
		解析IP头
	*/
	if(ntohs(ethh->h_proto) == 0x0800)
	{
	
		iph = (struct iphdr *)(p + sizeof(struct ethhdr));

		q = (unsigned char *)&(iph->saddr);
		printf("src ip:%d.%d.%d.%d\n",IP_ARG(q));

		q = (unsigned char *)&(iph->daddr);
		printf("dest ip:%d.%d.%d.%d\n",IP_ARG(q));
	}

Iiph

最终解析结果如下:

 可以看到我们正确解析出了IP地址,
结果与抓包工具分析出的数据保持了一致。

其中protocol字段表示了ip协议后面的额协议类型,常见的值如下:

数值 描述
0 保留字段,用于IPv6(跳跃点到跳跃点选项)
1 Internet控制消息 (ICMP)
2 Internet组管理 (IGMP)
3 网关到网关 (GGP)
4 1P中的IP(封装)
6 传输控制 (TCP)
7 CBT
8 外部网关协议 (EGP)
9 任何私有内部网关(Cisco在它的IGRP实现中使用) (IGP)
10 BBNRCC监视
11 网络语音协议
12 PUP
13 ARGUS
14 EMCON
15 网络诊断工具
16 混乱(Chaos)
17 用户数据报文 (UDP)
41 1Pv6
58 1Pv6的ICMP
59 1Pv6的无下一个报头
60 IPv6的信宿选项
89 OSPF IGP
92 多播传输协议
94 IP内部的IP封装协议
95 可移动网络互连控制协议
96 旗语通讯安全协议
97 IP中的以太封装
98 封装报头
100 GMTP
101 Ipsilon流量管理协议
133~254 未分配
255 保留

五、解析tcp头

查找tcp头思路很,

就是从pkt头开始偏移过以太头长度(14字节)、和IP头长度(20字节)就可以找到tcp头,

	switch(iph->protocol)
		{
			case 0x1:
				//icmp
				break;
			case 0x6:
				//tcp				
				tcph = (struct tcphdr *)(p + sizeof(struct ethhdr) + sizeof(struct iphdr));
				printf("source:%d dest:%d \n",ntohs(tcph->source),ntohs(tcph->dest);	

				break;
			case 0x11:
				//udp
				
				break;
		}

结构体与内存对应关系

打印结果如下:

六、学会用不同格式打印这块内存

在实际项目中,可能我们解析的并不是标准的TCP/IP协议数据包,

可能是我们自己的定义的协议数据包,

只要掌握了上述方法,

所有的协议分析都能够手到擒来!

有时候我们还需要打印对方发送过来的数据帧内容,

往往我们会以16进制形式将所有数据打印出来,

这样是最有利于我们分析数据内容的。

1. 按字节打印

代码如下:

	for(i=0;i<400;i++)
	{
		printf("%02x ",pkt[i]);
		if(i%20 == 19)
		{
			printf("\n");
		}
	}

2. 按short类型分析一段内存

我们接收数据时,虽然使用一个unsigned char型数组,

但是有时候对方发送过来的数据可能是2个字节的数组,

那我们只需要用short类型的指针,指向内存的头,

然后就可以通过该指针访问到对方发送的数据,

这个时候一定要注意字节序问题,

不同场景可能不一样,所以一定要具体问题具体分析,

本例因为是网络字节序数据转换成主机字节序,

所以需要转换字节序。

//转变short型字节序
void indian_reverse(unsigned short arr[],int num)
{
	int i;
	unsigned short temp;

	for(i=0;i<num;i++)
	{
		temp = 0;

		temp = (arr[i]&0xff00)>>8;
		temp |= (arr[i]&0xff)<<8;
		arr[i] = temp;
	}
}
main()
{
	unsigned short spkt[200];
	
	………………
	memcpy(spkt,pkt,sizeof(pkt));

	indian_reverse(spkt,ARRAY_SIZE(spkt));
	
	for(i=0;i<200;i++)
	{
		printf("%04x ",spkt[i]);
		if(i%10 == 9)
		{
			printf("\n");
		}
	}
	………………
}

结果如下:

完整代码请关注公众号:一口Linux,回复:数据包解析

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一文教你如何用C代码解析一段网络数据包?【含代码】 的相关文章

  • C++ std::thread多线程详解

    c 多线程详解 一 std thread线程创建 1 函数指针 2 Lambda函数 3 functor Funciton Object 4 非静态成员函数 5 静态成员函数 二 std thread线程停止 1 join函数 2 deta
  • 编译报错:error: no matching function for call to

    No matching function for call 表示当我们调用某些函数时 该函数的参数与函数定义的参数不匹配 因此 我们得到一个错误 No matching function for call 所以当我们继续向函数传递不正确类型
  • 小程序微信支付流程(商城余额支付,优惠券支付,积分抵消,微信支付)

    小程序微信支付的流程图 1 登录微信公众平台 开通微信支付功能 这是准备工作的第一步 确保小程序对应的支付功能已经开启 2 登录微信商户平台 该步骤需要获取两个参数 一个是商户号 一个是支付秘钥 如下图所示 注意秘钥自己要保护好 相当于支付
  • idea 2022.1 全新ui 配置

    idea 2022 1 全新ui 配置 版本 IntelliJ IDEA 2022 1 221 5080 210 build 其他的没有测过 以后再也不说大话了 丑陋 具体步骤 打开IDEA 双击shift 在弹出的搜索框中输入Regist

随机推荐

  • 程序部署到服务器服务无法启动问题

    问题描述 原先有一个程序在服务器正常运行 但是客户突然把重装了服务器系统 改为了 无限的未知 win2003 完整克隆版 V8 32位 虽然不太理解客户的心理 但是谁让人家是客户呢 老老实实重装环境部署程序 万幸一切正常 但是我想的太简单了
  • 关于2022年软件测试的5大趋势探讨

    随着数字化技术应用的广泛普及 业界对于软件测试的要求也在持续迭代与增加 当前 越来越多的企业和组织都相继采用了Agile 敏捷 和DevOps之类的软件开发方法 以鼓励和促进测试团队和开发团队之间的紧密协作 根据Gartner的预测 到20
  • deepin v20安装mysql

    deepin v20 换源和安装mysql 由于deepin v20不能直接安装mysql所以先进行换源 更换成阿里源 这样以后速度可以更快 修改文件 sudo vim etc apt sources list 删除内容 并添加以下内容 G
  • DDlog语言特征

    原文地址 这里写链接内容 DDlog是一种语法为datalog式 用来编写DeepDive应用的语言 一个ddlog程序会被编译成deepdive格式下的配置文件 我们通常用这个文件来运行我们的应用 一个ddlog程序由一组声明组成 这些声
  • 【Doxygen】Vscode 插件 DoxyGen Documentation Generator C语言详细设置

    DoxyGen Documentation Generatorc 这个VsCode插件可以设置C C 的doxygen格式自动填充 本文只介绍C语言的json文件配置 触发方式 doxdocgen c triggerSequence 输入
  • Eclipse查看JDK源码

    1 找到jdk 2 配置rt的源码
  • 关于Connection aborted等问题的解决

    错误类型 在爬虫中报如下的错误 requests exceptions ConnectionError Connection aborted RemoteDisconnected Remote end closed connection w
  • Win10远程桌面连接怎么用?(远程桌面连接教程)

    怎么开启远程桌面连接 电脑远程桌面连接怎么用 要使用远程桌面控制电脑 您需先在电脑上开启远程桌面连接并且两台电脑还需在同一个局域网中 否则您的设置端口转发才能使用远程桌面连 那么怎么开启远程桌面连接呢 具体操作步骤如下 步骤1 在Win10
  • Redis的String常用命令

    Redis 基础知识 不想key被更改 再key的后面加上nx eg 127 0 0 1 6379 gt set s 11 OK 127 0 0 1 6379 gt set ss 111 OK 127 0 0 1 6379 gt renam
  • Jest 单元测试术语解析:describe、it、expect、test

    jest测试代码片段 describe number test gt it 1 is true gt expect 1 toBeTruthy test 2 is true gt expect 2 toBeTruthy describe 描述
  • Vue研习录(08)——Vue引入Swiper知识详解及示例分析

    Vue研习录 08 Vue引入Swiper知识详解及示例分析 版权声明 一 Swiper 版权声明 本文原创作者 清风不渡 博客地址 https blog csdn net WXKKang 重拾前端记忆 记录学习笔记 现在进入Vue引入Sw
  • uniapp的webview实现左滑返回上一个页面

    uniapp默认左滑是关闭整个webview 而不是关闭当前页 实现思路 拦截webview的url跳转操作 将新url用webview组件重新打开 当左滑的时候 默认关闭的就是当前webview 继而跳转到上一次的页面中
  • 100 道 Linux 常见面试题,慢慢读~

    1 Linux 概述 1 1 什么是 Linux Linux 是一套免费使用和自由传播的类 Unix 操作系统 是一个基于 POSIX 和 Unix 的多用户 多任务 支持多线程和多 CPU 的操作系统 它能运行主要的 Unix 工具软件
  • 关于对话机器人,你需要了解这些技术

    对话系统 对话机器人 本质上是通过机器学习和人工智能等技术让机器理解人的语言 它包含了诸多学科方法的融合使用 是人工智能领域的一个技术集中演练营 图1给出了对话系统开发中涉及到的主要技术 对话系统技能进阶之路 图1给出的诸多对话系统相关技术
  • Linux SELinux

    Security Enhanced Linux SELinux 是一种Linux系统的安全体系结构 允许管理员对系统访问权限进行更精细的控制 它最初由美国国家安全局 NSA 开发 使用Linux安全模块 LSM 对Linux内核打了一系列补
  • emd分解MATLAB自带函数

    matlab 2018开始自带了emd和hht函数 现将emd函数用法总结如下 imf residual info emd x Interpolation pchip 或者 emd x Interpolation pchip 输入参数 x
  • DataWhale Linux——Task01 Linux简介

    目录 什么是Linux Linux的优点 常用发行版 什么是Linux Linux 全称为GNU Linux 是一种免费使用和自由传播的类UNIX操作系统 我们常说的Linux 是指Linux内核 Linux的优点 开源免费 多用户 多任务
  • 预备1-window常用快捷键

    window常用快捷键 快捷键有很多很多 开发程序 刚入门只需要掌握简单的 菜单键 和书本一样的按键 鼠标的右键 1 查看 菜单 v gt gt gt gt 常用于 隐藏桌面图标 gt gt gt 菜单 v d 2 刷新 菜单键 E 3 新
  • 多功能透明屏,在智能家居领域中,有哪些功能特点?显示、连接

    多功能透明屏是一种新型的显示技术 它能够在透明的表面上显示图像和视频 并且具有多种功能 这种屏幕可以应用于各种领域 如商业广告 智能家居 教育等 为用户提供更加便捷和多样化的体验 首先 多功能透明屏可以用于商业广告 传统的广告牌通常是单一的
  • 一文教你如何用C代码解析一段网络数据包?【含代码】

    本文的目的是通过随机截取的一段网络数据包 然后根据协议类型来解析出这段内存 学习本文需要掌握的基础知识 网络协议 C语言 Linux操作 抓包工具的使用 其中抓包工具的安装和使用见下文 一文包你学会网络数据抓包 视频教学链接如下 教你如何抓