计算UDP报文CRC校验的总结

概述

因公司项目需求,遇到需要发送带UDP/IP头数据包的功能,经过多次尝试顺利完成,博文记录以备忘。

环境信息

操作系统

ARM64平台的中标麒麟Kylin V10

工具

tcpdump、wireshark、vscode

原理

请查看大佬的博文

UDP伪包头定义(图片来源于参考链接)
在这里插入图片描述

调试过程

对着大佬的博文说明,用上白嫖党专业技能C++【Copy++】,欠缺的结构体和头文件运用专业技能补全。

//头文件
#include <netinet/udp.h>
#include <netinet/ip.h>
#include <string.h>//结构体
struct ipovly {caddr_t	ih_next, ih_prev;	/* for protocol sequence q's */u_char	ih_x1;			/* (unused) */u_char	ih_pr;			        //协议域short	ih_len;			        //这个相当于IP头部,len = data Len + udp HeaderLen + ip headerstruct	in_addr ih_src;		//源地址struct	in_addr ih_dst;		//目标地址
};

补全后的代码,经过测试,发现死活不对,后面通过打印结构体大小,发现了端倪,罪魁祸首就是 caddr_t 这个数据类型,IP报文头只有20个字节,但是这个结构体直接32个字节,将UDP的数据都覆盖了部分。这就导致生成的CRC总是不对。

经过层层头文件穿透,caddr_t 定义如下

//sys/types.h
......省略部分typedef char *__caddr_t;......省略部分#ifdef	__USE_MISC
# ifndef __daddr_t_defined
typedef __daddr_t daddr_t;
typedef __caddr_t caddr_t;
#  define __daddr_t_defined
# endif
#endif

发现char * 数据类型在64位操作系统下是占用8个字节;在32位操作系统下是占用4个字节,故而导致数据被覆盖。因为struct ipovly这个结构不是同一个博文定义的,不排除是复制有差异。

后面将结构体调整如下

struct ipovly {unsigned int ih_next, ih_prev;	/* for protocol sequence q's */u_char	ih_x1;			/* (unused) */u_char	ih_pr;			        //协议域short	ih_len;			        //这个相当于IP头部,len = data Len + udp HeaderLen + ip headerstruct	in_addr ih_src;		//源地址struct	in_addr ih_dst;		//目标地址
};

因为ih_next、ih_prev这两个字段并没有使用,所以只要保证每个字段大小是4个字节,并且值为0即可。

经过一番测试,对比成功。

完整代码

为了方便项目使用,做了部分调整,请自行针对性修改

#include <netinet/udp.h>
#include <netinet/ip.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>#ifndef IPHL
#define IPHL sizeof(struct ip)
#endif#ifndef UDPHL
#define UDPHL sizeof(struct udphdr)
#endifstruct ipovly
{unsigned int ih_next, ih_prev; /* for protocol sequence q's */u_char ih_x1;                  /* (unused) */u_char ih_pr;                  // 协议域short ih_len;                  // 这个相当于IP头部,len = data Len + udp HeaderLen + ip headerstruct in_addr ih_src, ih_dst; /* source and dest address */
};unsigned short my_cksum(unsigned short *addr, int len)
{register int sum = 0;register unsigned short *w = addr;register int nleft = len;int c = 0;while (nleft > 1){sum += *w++;nleft -= 2;}if (nleft == 1){unsigned char a = 0;memcpy(&a, w, 1);sum += a;}sum = (sum >> 16) + (sum & 0xffff);sum += (sum >> 16);return ~sum;
}short udpipgen(unsigned char *frame,const char *saddr,const char *daddr,unsigned short sport,unsigned short dport,unsigned short msglen)
{struct ip *ip = (struct ip *)(frame);struct udphdr *udp = (struct udphdr *)(frame + IPHL);struct ipovly *io = (struct ipovly *)frame; /*Only for UDP crc*/struct in_addr s_addr, d_addr;memset(&s_addr, 0, sizeof(struct in_addr));memset(&d_addr, 0, sizeof(struct in_addr));inet_aton(saddr, &s_addr);inet_aton(daddr, &d_addr);if (ip == NULL || udp == NULL || io == NULL || saddr == NULL || daddr == NULL ||s_addr.s_addr == 0 || d_addr.s_addr == 0){return 0;}io->ih_next = io->ih_prev = 0;io->ih_dst.s_addr = d_addr.s_addr;io->ih_src.s_addr = s_addr.s_addr;io->ih_x1 = 0;io->ih_pr = IPPROTO_UDP;io->ih_len = htons(UDPHL + msglen);udp->uh_sport = htons(sport);udp->uh_dport = htons(dport);udp->uh_ulen = io->ih_len;udp->uh_sum = my_cksum((unsigned short *)ip, UDPHL + IPHL + msglen);memset(io, 0x00, sizeof(struct ipovly));ip->ip_v = IPVERSION;ip->ip_hl = IPHL >> 2;ip->ip_tos = 0;ip->ip_len = htons(UDPHL + IPHL + msglen);ip->ip_id = htons(0x78D6); //反向验证的时候,注意该字段是否和Wireshark的数据包一致ip->ip_off = 0; //反向验证的时候,注意该字段是否和Wireshark的数据包一致ip->ip_ttl = 1; //反向验证的时候,注意该字段是否和Wireshark的数据包一致ip->ip_p = IPPROTO_UDP;ip->ip_src.s_addr = s_addr.s_addr;ip->ip_dst.s_addr = d_addr.s_addr;ip->ip_sum = my_cksum((unsigned short *)ip, IPHL);return 1;
}/**
* 正向使用程序(通过数据生成对应的IP/UDP包数据)样例
* int main(...)
* {
*    //需要发送的内层数据
* 	char data[100] = {...};
* 	//包含IP头、UDP头、内层数据的数组(以下称帧缓冲区)
* 	char frame[20+8+sizeof(data)] = {0};
* 	memset(frame,0,sizeof(frame));
* 	//内层数据复制到帧缓冲区,因为UDP计算CRC的时候,需要带上数据。IP包头计算CRC只需要包头数据
* 	memcpy(frame+28,data,sizeof(data)); //28 = IP包头20个字节 + UDP包头8个字节
* 	//udpipgen函数会自动填充对应的结构体字段
* 	short ret = udpipgen(frame, "192.168.10.1", "192.168.10.119", 10254, 10252, sizeof(data));
* 	if (ret == 1) { //TODO 生成成功的后续操作 }
* }
*
*//**
* 因为是反向验证程序(从Wireshark捕捉的UDP数据验证CRC),所以该程度的具体功能如下
* 1. 读取一包Wireshark/tcpdump捕捉到的UDP数据包
* 2. 根据IP/UDP解释对应的数据包
* 3. 然后清除对应结构的CRC校验字段
* 4. 调用udpipgen函数,生成CRC
* 5. 控制台打印然后比对原来的CRC和新生成CRC,是否一致
*/
int main(int argc, char *argv[])
{FILE *fp;//注意这个缓冲区大小,如果解释大于1024字节的数据会出问题,请自行修改unsigned char buff[1024] = {0};if (argc < 2){printf("Usage: %s package\n", argv[0]);exit(0);}//argv[1]: 表示Wireshark抓的数据包,只解释一包,批量请自行修改fp = fopen(argv[1], "rb");if (fp == NULL){perror("open file failure!!!");exit(-1);}else{// fseek(fp,18,SEEK_SET);size_t nbytes = fread(buff, 1, 1024, fp);if (nbytes < 0){perror("read file error!!");fclose(fp);fp = NULL;exit(-1);}else{unsigned char dup[nbytes] = {0};//复制数据帧memcpy(dup, buff, nbytes);struct ip *ip = (struct ip *)(buff);struct udphdr *udp = (struct udphdr *)(buff + IPHL);unsigned short ip_sum = ip->ip_sum;unsigned short udp_sum = udp->uh_sum;printf("ip sum: %x, udp sum: %x\n", ip_sum, udp_sum);struct ip *ip2 = (struct ip *)(dup);struct udphdr *udp2 = (struct udphdr *)(dup + IPHL);printf("ip2 sum: %x, udp2 sum: %x\n", ip2->ip_sum, udp2->uh_sum);//重置复制帧的CRC字段ip2->ip_sum = 0;udp2->uh_sum = 0;char saddr[256] = {0};char daddr[256] = {0};inet_ntop(AF_INET, (void *)&ip->ip_src.s_addr, saddr, 256);printf("ip_src.s_addr : %s ,%d ", saddr, ntohs(udp->uh_sport));memset(daddr, 0, 256);inet_ntop(AF_INET, (void *)&ip->ip_dst.s_addr, daddr, 256);printf("ip_dst.s_addr : %s ,%d\n", daddr, ntohs(udp->uh_dport));// udp->len = UDP Header长度(8个字节) + 数据长度,因为Wireshark捕捉的数据包都是网络字节序的,所以需要转换一下printf("data length : %d\n", ntohs(udp->len) - 8);memset((void *)ip2, 0, sizeof(struct ip));// 调用函数,计算IP结构、UDP结构的CRC字段udpipgen(dup, saddr, daddr, ntohs(udp->uh_sport), ntohs(udp->uh_dport), ntohs(udp->uh_ulen) - 8);printf("Calc ip sum: %x, udp sum: %x\n", ip2->ip_sum, udp2->uh_sum);fclose(fp);fp = NULL;}}
}

验证方法

将生成的数据通过UDP发送出去,利用Wireshark/tcpdump抓包,然后通过Wireshark打开
右键呼出菜单,设置自动校验,通过Wireshark的自动校验来验证CRC生成是否正确
在这里插入图片描述

参考链接

手动组UDP/TCP包时计算 CRC 校验碰到的问题。
C语言数据类型在不同位数平台下的字节长度
TCP/IP详解V2(三)之TCP协议
UDP的伪首部是什么?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/211858.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023年第十六届山东省职业院校技能大赛中职组“网络安全”赛项竞赛正式试题

第十六届山东省职业院校技能大赛中职组 “网络安全”赛项竞赛试题 目录 一、竞赛时间 二、竞赛阶段 三、竞赛任务书内容 &#xff08;一&#xff09;拓扑图 &#xff08;二&#xff09;A模块基础设施设置/安全加固&#xff08;200分&#xff09; &#xff08;三&#xf…

Docker安装Elasticsearch以及ik分词器

Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎&#xff0c;能够解决不断涌现出的各种用例。作为 Elastic Stack 的核心&#xff0c;Elasticsearch 会集中存储您的数据&#xff0c;让您飞快完成搜索&#xff0c;微调相关性&#xff0c;进行强大的分析&#xff…

C#图像处理OpenCV开发指南(CVStar,07)——通用滤波(Filter2D)的实例代码

1 函数定义 void Filter2D (Mat src, Mat dst, int ddepth, InputArray kernel, Point anchor Point(-1,-1), double delta 0, int borderType BORDER_DEFAULT ) 1.1 原型 #include <opencv2/imgproc.hpp> Convolves an image wit…

【msg_msg】corCTF2021-msgmsg 套题

前言 该套题共两题&#xff0c;一道简单模式 fire_of_salvation&#xff0c;一道困难模式 wall_of_perdition&#xff0c;都是关于 msg_msg 的利用的。这题跟之前的 TPCTF2023 core 的很像&#xff08;应该是 TPCTF2023 core 跟他很像&#xff0c;bushi&#xff09;。 其中 f…

Elasticsearch:什么是大语言模型(LLM)?

大语言模型定义 大语言模型 (LLM) 是一种深度学习算法&#xff0c;可以执行各种自然语言处理 (natural language processing - NLP) 任务。 大型语言模型使用 Transformer 模型&#xff0c;并使用大量数据集进行训练 —— 因此规模很大。 这使他们能够识别、翻译、预测或生成文…

Linux 存储管理

内容概述 磁盘结构分区类型管理分区管理文件系统挂载设备管理swap空间&#xff08;用来缓解内存空间不足情况&#xff09;RAID 管理LVM管理LVM快照 1 磁盘结构 1.1 设备文件 块设备文件&#xff1a;数据的访问单位是块Block&#xff0c;一个块的IO 字符设备文件&#xff1a…

springboot 整合security并且配置swagger 时,无法访问/doc.html

参考文档&#xff1a; https://blog.csdn.net/qq_43340419/article/details/120312937解决方案&#xff1a;需要在WebSecurityConfig 中 配置允许匿名访问的路径 .antMatchers("/v2/api-docs","/swagger-resources/configuration/ui","/swagger-res…

备忘录模式 rust和java的实现

文章目录 备忘录模式介绍实现javarustrust仓库 备忘录模式 备忘录&#xff08;Memento&#xff09;模式的定义&#xff1a;在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff0c;以便以后当需要时能将该对象恢复到原先…

设计模式——七大设计原则

设计模式——七大设计原则 1、单一职责原则&#xff08;SRP&#xff09;2、开放封闭原则&#xff08;OCP&#xff09;3、依赖倒转原则&#xff08;DIP&#xff09;4、里氏替换原则 (LSP)5、接口隔离原则 (ISP)6、合成/聚合复用原则 (CARP)7、迪米特法则 (LoD) 了解 设计模式 的…

Qt/C++音视频开发57-切换音视频轨道/切换节目流/分别切换音频视频轨道

一、前言 对各种音视频文件格式的支持&#xff0c;是一个播放器的基础功能。一般的音视频文件只有1路流&#xff0c;比如音频文件只有1路音频流&#xff0c;视频文件只有1路音频1路视频流&#xff0c;实践过程中发现&#xff0c;还有一种ts格式的文件&#xff0c;可能有多路流…

Python包管理器PIP用法大全

pip是Python的包管理器&#xff0c;用于安装和管理Python包。以下是一些常用的基本的pip命令&#xff0c;分享给大家&#xff0c;希望对大家使用pip有所帮助。 文章目录 pip installpip uninstallpip listpip searchpip downloadpip configpip freezepip checkpip wheelpip ha…

网络安全攻击预警/态势预测算法汇总

总结&#xff1a; 网络安全攻击预警/态势预测算法众多&#xff0c;主要包括&#xff1a; 基于统计学的算法&#xff1a;协方差矩阵、马尔可夫模型等&#xff1b; 基于机器学习的算法&#xff1a;贝叶斯网络、聚类算法、支持向量机SVM、遗传算法、层次分析法AHP、决策树等&am…

Matlab 曲线动态绘制

axes(handles.axes1); % 选定所画坐标轴 figure也可 h1 animatedline; h1.Color b; h1.LineWidth 2; h1.LineStyle -; % 线属性设置 for i 1 : length(x)addpoints(h1,x(i),y(i)); % x/y为待绘制曲线数据drawnow;pause(0.01); % 画点间停顿 end 示例&#xff1a; figure…

观海微电子---线路腐蚀的起因与对策

线路腐蚀的原理&#xff1a; 在线路表面的污染物中含有金属元素的离子或金属化合物&#xff0c; 在潮湿的空气中这些污染物与线路之间的冷凝水连成微电池&#xff0c;引发电化学反应&#xff0c;产品通电的情况下反应进行得更快&#xff0c;耗损线路导致线路腐蚀形成断线。 腐…

WordPress外贸站优化工具,WordPress外贸SEO优化方法

WordPress外贸站是跨国企业拓展市场、提升品牌知名度的理想选择。然而&#xff0c;如何通过SEO优化、原创文章生成以及留心站点优化的事项&#xff0c;成为众多站长关注的焦点。 SEO&#xff0c;即搜索引擎优化&#xff0c;是提高网站在搜索引擎结果中排名的关键。首先&#x…

linux的权限741

741权限 在 Linux 中&#xff0c;文件和目录的权限由三组权限来定义&#xff0c;分别是所有者&#xff08;Owner&#xff09;、所属组&#xff08;Group&#xff09;和其他用户&#xff08;Others&#xff09;。每一组权限又分为读&#xff08;Read&#xff09;、写&#xff0…

前端大文件上传webuploader(react + umi)

使用WebUploader还可以批量上传文件、支持缩略图等等众多参数选项可设置&#xff0c;以及多个事件方法可调用&#xff0c;你可以随心所欲的定制你要的上传组件。 分片上传 1.什么是分片上传 分片上传&#xff0c;就是将所要上传的文件&#xff0c;按照一定的大小&#xff0c;将…

python实现pdf转word、word转pdf

我的博客 文章首发于公众号&#xff1a;小肖学数据分析 Python自动化办公通常对常用的办公软件文档格式进行操作&#xff0c;比如Word和PDF。 很多软件都需要付费&#xff0c;作为程序员&#xff0c;怎么可能付费。 下面是一个简单示例&#xff0c;如何在Python中将Word文档…

Java抽象类(abstract class)和接口(interface)的区别——面试

1.抽象类&#xff08;abstract class&#xff09;和接口&#xff08;interface&#xff09;的区别&#xff1a; 抽象类可以有构造方法&#xff0c;接口中不能有构造方法。 抽象类中可以有普通成员变量&#xff0c;接口中没有普通成员变量。抽象类中可以包含非抽象的普通方法&am…

总结|哪些平台有大模型知识库的Web API服务

截止2023/12/6 笔者个人的调研&#xff0c;有三家有大模型知识库的web api服务&#xff1a; 平台类型文档数量文档上传并解析的结构api情况返回页码文心一言插件版多文档有问答api&#xff0c;文档上传是通过网页进行上传有&#xff0c;而且是具体的chunk id&#xff0c;需要设…