linux 内核数据包处理中的一些坑和建议
1、获取IP头部
iph = ip_hdr(skb);
struct sk_buff {
......
sk_buff_data_t transport_header; /* Transport layer header */
sk_buff_data_t network_header; /* Network layer header */
sk_buff_data_t mac_header; /* Link layer header */
......
}
1)__netif_receive_skb()在进入三层处理前就对network_header进行了设置。
2)ip_rcv()中详细的检查保证了IP头部到netfilter后是完整的。
3)netfilter可以尽情使用ip头部。
2、获取tcp头部
错误1:
tcph = tcp_hdr(skb);
陷阱:
netfilter的钩子点是属于TCP/IP协议栈的三层流程中,而四层的TCP头部此时还没有正确获取,只是初始化为IP头部的值,无法直接使用。
错误2:
tcph = (char *)iph + (iph->ihl << 2);
陷阱:
数据包可能是非线性的


改进:
tcpoff = skb_network_offset(skb) + (iph->ihl << 2);
tcph = skb_header_pointer(skb, tcpoff, sizeof(_tcph), &_tcph);
if (tcph == NULL)
return;
skb_network_offset(struct skb_buff *skb)
计算三层头部相对于skb->data的偏移
void * skb_header_pointer(struct sk_buff *skb, int offset, int len, void *buffer)
从skb的指定偏移取制定长度的数据,如果要取的数据位于线性区,直接返回其开始指 针,否则,则拷贝到buffer中,并将buffer指针返回。
3、打印IP信息
printk("%pI4 %d -----> %pI4 %d len: %d ID: %d\n",
&iph->saddr,
ntohs(tcph->source),
&iph->daddr,
ntohs(tcph->dest),
ntohs(iph->tot_len),
ntohs(iph->id));
注意要点:
1) IP地址输出
Ipv4:%pI4 %pi4
IPv6:%pI6 %pi6
2) MAC地址
%pM %pm
3)字节序的转换
ntohs() ntohl() htons() htonl()
__const_ntohl() __const_ntohs() __const_htonl() __const_htons()
区别:__const_*()是编译时处理的。
4、获取TCP负载
风险:
payload = (char *)tcph + tcph->doff * 4;
陷阱1:
数据包可能是非线性的,同TCP头部。
陷阱2:
TCP头部数据有可能是被篡改过的,tcph->doff如果很大怎么办?
改进1:
tcplen = skb->len - tcpoff;
if (tcph->doff*4 < sizeof(struct tcphdr) || tcplen < tcph->doff*4)
{
printk("Bad tcp.\n");
return NF_ACCEPT;
}
if (skb_is_nonlinear(skb))
{
printk("Nonlinear skb.\n");
return NF_ACCEPT;
}
payload = (char *)tcph + tcph->doff * 4;
payload_len = tcplen - tcph->doff * 4;
if (payload_len == 0)
return NF_ACCEPT;
接口介绍:
int skb_is_nonlinear(struct sk_buff *skb)
判断skb的数据是否是非线性的
改进2:
char payload_buf[1500];
tcplen = skb->len - tcpoff;
if (tcph->doff*4 < sizeof(struct tcphdr) || tcplen < tcph->doff*4)
{
printk("Bad tcp.\n");
return NF_ACCEPT;
}
payload_len = tcplen - tcph->doff * 4;
if (payload_len == 0)
return NF_ACCEPT;
if (payload_len > sizeof(payload_buf))
return NF_ACCEPT;
payload = skb_header_pointer(skb, tcpoff + tcph->doff*4, payload_len, payload_buf);
if (payload == NULL)
return NF_ACCEPT;
改进3:
tcplen = skb->len - tcpoff;
if (tcph->doff*4 < sizeof(struct tcphdr) || tcplen < tcph->doff*4)
{
printk("Bad tcp.\n");
return NF_ACCEPT;
}
if (skb_ linearize(skb))
{
printk("Can not linearize skb.\n");
return NF_ACCEPT;
}
payload = (char *)tcph + tcph->doff * 4;
payload_len = tcplen - tcph->doff * 4;
if (payload_len == 0)
return NF_ACCEPT;
接口介绍:
int skb_ linearize (struct sk_buff *skb)
将skb线性化
5、解析数据
1)判断数据包内容
风险1:
if (payload[0] != 'G' || payload[1] != 'E' || payload[2] != 'T')
风险2:
if ((payload[0] == 'G' && payload[1] == 'E' && payload[2] == 'T') && payload_len == 3)
陷阱:
如果payload的长度只有1个字节怎么办?
改进:
if (payload_len < 3 || payload[0] != 'G' || payload[1] != 'E' || payload[2] != 'T')
2) 查找数据包中的某个字符串
风险:
host = strstr(payload, "Host: ");
陷阱:
可能会越界,数据包不一定是以'\0'结束。

改进:
host = strnstr(payload, "Host: ", payload_len);
if (host == NULL)
return ;
一定要使用这一系列的函数:
strnchr
strncpy
strncat
strncmp
strnicmp
strnlen
memcpy
3)移动指向数据包的指针
风险:

host = strnstr(payload, "Host: ", payload_len);
if (host == NULL)
return ;
host = host + sizeof("Host: ") - 1;
/*
* deal with host
*/
陷阱:
查找的字符串有可能是数据包的最后一部分。

改进:
host = strnstr(payload, "Host: ", payload_len);
if (host == NULL)
return ;
host = host + sizeof("Host: ") - 1;
if (host >= (payload + payload_len))
return;
/*
* deal with host
*/
4)数据包操作
错误:
u32 len;
len = payload_len - 512;
if (len <= 0)
return;
memcpy(buf, payload, len);
陷阱:
无符号数的强制类型转换,u32类型永远都是大于等于0的,当payload_len小于512 时,判断就会不生效。
改进:
u32 len;
if (payload_len <= 512)
return;
len = payload_len - 512;
memcpy(buf, payload, len);
或者
int len;
len = payload_len - 512;
if (len <= 0)
return;
memcpy(buf, payload, len);
5)
风险:![]()
int len = payload[1];
memcpy(buf, &payload[2], len);
陷阱:
可能是异常数据包,offset不是你想要的
正确做法:
nt len = payload[1];
if (len >= payload_len - 2)
return;
memcpy(buf, &payload[2], len);
综述:数据包处理要时刻保持警醒,它可能不是你想象的样子!
相关文章:
linux 内核数据包处理中的一些坑和建议
1、获取IP头部 iph ip_hdr(skb); struct sk_buff { ...... sk_buff_data_t transport_header; /* Transport layer header */ sk_buff_data_t network_header; /* Network layer header */ sk_buff_data_t mac_header; /* Link layer header */ ...... } 1࿰…...
C++ 的衰退复制(decay-copy)
目录 1.什么是衰退复制(decay-copy) 1.1.推导规则 1.2.LWG issue 929 1.3.想象中的 decay_copy 2.decay-copy 与 auto 2.1.为什么引入衰退复制 2.2. 成为 C 23 的语言特性 3.应用场景 4.总结 1.什么是衰退复制(decay-copy࿰…...
vue-cli 5接入模块联邦 module federation
vue-cli 5接入模块联邦 module federation 模块联邦概念实现思路配置遇到的问题: 模块联邦概念 模块联邦由webpack 5最先推出的,让应用加载远程的代码模块来实现不同的Web应用共享代码片段.模块联邦分为两个角色,一个是生产者,一个是消费者.生产者暴露代码供消费者消费 (用一个…...
【Rust自学】3.6. 控制流:循环
3.6.0. 写在正文之前 欢迎来到Rust自学的第三章,一共有6个小节,分别是: 变量与可变性数据类型:标量类型数据类型:复合类型函数和注释控制流:if else控制流:循环(本文) 通过第二章…...
【第八节】git与github
目录 前言 一、 远程仓库概述 二、 创建、配置、连接推送远程仓库 2.1 在 GitHub 上创建仓库 2.2 生成 SSH Key 2.3 验证 SSH 连接 2.4 本地初始化仓库 2.5 推送本地仓库到远程 三、 管理远程仓库 3.1 查看远程仓库 3.2 提取远程仓库更新 3.3 推送更新到远程仓库 …...
win如何访问Linux数据库(本地)
对于数据库的学习,我们都是在localhost主机上进行操作,当我们在Linux系统上安装数据库时,我们就有了尝试在win上去访问Linux上的数据库的想法。 数据库中的用户: 我们都知道数据库中顶级的用户为root,在做创建用户的联…...
Windows设置所有软件默认以管理员身份运行
方法一、修改注册表 winr打开运行,输入“regedit”打开注册表; 打开此路径“计算机HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem”; 在右侧找到“EnableLUA”,将其值改为0,重启电脑。 …...
前端 计算发布时间(如“1小时前”、“3天前”等)
这样效果,在c端比较常见,通过前端也可以处理 代码如下: // 计算 小时timeAgo(createTime) {// 将 createTime 字符串转换为 Date 对象 const createDate new Date(createTime);const now new Date();const diffInSeconds Math.floor((now…...
shardingjdbc 4.0.0 seata分布式事务Failed to fetch schema问题
报错 12-18 15:18:35.931 [ERROR] [i.s.r.d.s.s.cache.AbstractTableMetaCache:63 ] [traceId:][spanId:] - get table meta of the table wh_stock_log error: Failed to fetch schema of xxx java.sql.SQLException: Failed to fetch schema of wh_stock_logat io.seata.r…...
罗德与施瓦茨NRT2功率反射仪,NRT2通过式功率计
罗德与施瓦茨NRT2功率反射仪NRT2 通过式功率计 描述 定向/通过式功率传感器在线测量正向和反向功率。在安装、维修和监控发射机、天线和射频发生器时,需要进行这些测量。R&SNRT系列由R&SNRT2功率反射计及各种R&SNRT Zxx定向功率传感器。 由于其测量功…...
QLineEdit限制输入固定字节数(UTF-8编码)
setMaxLength(int)只能用来限制输入的字符个数 QLineEdit *editor new QLineEdit(parent); editor->setMaxLength(32); 1、如果是单字节字符,如数字,字母等,字符数正好等于字节数 2、如果是多字节字符,UTF8编码时࿰…...
基于ubuntu的mysql 8.0安装教程
文章目录 1.查看版本2.切换到root账户3.下载安装包4.问题的解决5.查看是否解压成功6.安装我们的发布包7.更新包的内容8.下载mysql9.查看mysql的状态10.设置开机自启动11.登录mysql 公司里面的mysql根本不会出现在windows操作系统上面,下面我们演示的就是如何在ubunt…...
K8s ConfigMap的基础功能介绍
在 Kubernetes 中,ConfigMap 是一种用于管理配置信息的资源对象,它允许你将 配置信息与代码解耦,方便管理和更新应用配置,而无需重新构建镜像或重启服务。 ConfigMap 的功能 存储配置信息: 可以以 键值对 的形式存储配…...
Linux——Shell
if 语句 格式:if list; then list; [ elif list; then list; ] ... [ else list; ] fi 单分支 if 条件表达式; then 命令 fi 示例: #!/bin/bash N10 if [ $N -gt 5 ]; then echo yes fi # bash test.sh yes 双分支 if 条件表达式; then 命令 else 命令…...
armsom产品编译烧录Linux固件
1、开发环境及工具准备 Rockchip Linux 软件包:linux-5.10-gen-rkr4 主机: 安装VMware搭建虚拟机,版本为Ubuntu 20.04 (硬盘容量大于100G) 安装远程连接工具MobaXterm(可连接虚拟机方便文件传输) 2、S…...
VSCode:Markdown插件安装使用 -- 最简洁的VSCode中Markdown插件安装使用
VSCode:Markdown插件安装使用 1.安装Marktext2.使用Marktext 本文,将在Visual Studio Code中,安装和使用Markdown插件,以Marktext插件为例。 1.安装Marktext 打开VSCode,侧边栏中找到扩展模块(或CtrlShiftX快捷键)&am…...
AI 行业发展趋势:科技创新引领未来变革
在当今数字化时代,人工智能(AI)行业正以前所未有的速度蓬勃发展,深刻地改变着我们的生活、工作和社会格局。从基础技术的突破到广泛的应用场景拓展,AI 展现出了一系列令人瞩目的发展趋势,预示着一个充满无限可能的未来。 一、技术创新持续突破 模型规模与性能提升 AI 模…...
FB爆款打法实操经验总结
在进行Facebook广告投放时,有效的预算控制、素材测试、广告效果评估和lookalike受众的管理是至关重要的。通过科学的方法和策略,您可以在竞争激烈的市场中实现更好的业绩。 01 预算控制 测试阶段的广告不稳定性:在投放广告的初期,…...
微信小程序TTS解决方案
微信小程序原生语音合成 API(基础且简单) 介绍:微信小程序提供了基础的语音合成能力。通过wx.createInnerAudioContext()等相关API,可以实现简单的语音播放功能。不过它主要是用于音频播放,对于完整的文本到语音&#…...
centos stream 8下载安装遇到的坑
早在2020年12月。CentOS 官方发文宣称:“CentOS项目的未来是 CentOS Stream 明年我们会将重点从CentOS Linux 转移到CentOS Stream 它紧随当前 RHEL 版本之前。CentOS Linux 8 作为 RHEL 8 的重建,将于 2021 年底结束。CentOS Stream 在该日期之后继续&a…...
【OpenClaw全面解析:从零到精通】第032篇:OpenClaw v2026.4.1 深度解析:聊天原生任务板、SearXNG 搜索与安全护栏如何重塑 AI Agent 工作流
上一篇:[第031篇] OpenClaw 会话管理与上下文持久化深度解析:从“失忆”到长期记忆的完整解决方案 下一篇:未完待续 OpenClaw v2026.4.1 不是一个“加几个小功能”的普通补丁版,而是对 v2026.3.31 安全收紧与后台任务重构的一次前…...
gciWidget:面向车载嵌入式系统的轻量级GUI组件库
1. 项目概述gciWidget是面向大众汽车集团(Volkswagen Group)CARIAD 车载软件平台定制开发的轻量级图形用户界面(GUI)组件库,专为嵌入式车载显示系统设计。其核心定位并非通用型 GUI 框架(如 LVGL 或 TouchG…...
从ORB到SIFT:视觉SLAM中特征点算法实战对比(附OpenCV代码示例)
从ORB到SIFT:视觉SLAM中特征点算法实战对比与工程选型指南 1. 视觉SLAM中的特征点算法核心价值 在机器人自主导航和增强现实领域,视觉SLAM系统的前端处理如同人类视觉皮层,而特征点算法则是这个系统的视网膜神经节细胞。这些算法不仅决定了系…...
【GitLab npm Registry 非标准端口安装问题解决方案】
GitLab npm Registry 非标准端口安装问题解决方案 问题类型: npm/pnpm 客户端与 GitLab npm Registry 集成 影响范围: 使用非标准端口的 GitLab npm Registry 解决时间: 2026-04-03 文档版本: v1.0 一、问题背景 1.1 业务场景 团队需要将内部组件库发布到私有 npm registry,选…...
OpenClaw学习助手:Qwen3.5-9B-AWQ-4bit自动整理网课截图笔记
OpenClaw学习助手:Qwen3.5-9B-AWQ-4bit自动整理网课截图笔记 1. 为什么需要自动化学习助手 作为一名经常通过网课充电的技术从业者,我长期被一个痛点困扰:每次听完两小时的课程,手机相册里会堆满几十张截图,里面有老…...
千问3.5-9B模型蒸馏:轻量化OpenClaw移动端部署
千问3.5-9B模型蒸馏:轻量化OpenClaw移动端部署 1. 为什么需要端侧轻量化 去年夏天,我在树莓派上尝试部署OpenClaw时遇到了一个尴尬的问题——原版Qwen-14B模型需要至少32GB内存才能流畅运行,而我的树莓派4B仅有8GB。每次启动不到5分钟就会因…...
BD663474车载LCD驱动芯片技术解析与CARIAD集成实践
1. BD663474驱动芯片技术解析:面向CARIAD车载显示系统的TFT-LCD底层控制实现BD663474是ROHM半导体推出的一款专为汽车级TFT-LCD面板设计的源极驱动(Source Driver)与栅极驱动(Gate Driver)集成控制器,广泛应…...
单片机驱动MOS管的原理与实战技巧
1. 单片机直接驱动MOS管的原理与风险MOS管作为现代电子设计中最常用的功率开关器件,其控制方式看似简单却暗藏玄机。作为一名经历过多次"炸管"教训的硬件工程师,我想分享一些关于单片机直接驱动MOS管的实战经验。MOS管分为NMOS和PMOS两种类型&…...
新手必看:虚拟机安装SQL Server全攻略
对于初学者来说 我们并不能使用现实的物理环境来进行练手sql服务 那么就需要使用虚拟环境安装sql sever服务 这样的好处是 不仅可以得到真实物理环境的练手 还可以发现任何问题得到还原和解决 那么就看看如何在虚拟环境下安装sql 服务吧一、准备工作1、虚拟机准备本次使用的是v…...
AnimateDiff与Three.js结合:Web端3D文生视频实践
AnimateDiff与Three.js结合:Web端3D文生视频实践 最近在折腾AI视频生成,发现一个挺有意思的事儿:AnimateDiff这类文生视频模型效果越来越好,但生成的东西大多还是“平面”的,想把它放到网页里,特别是做成有…...
