千家信息网

Linux Tcp内核协议栈Packet Drill基本原理是什么

发表于:2025-02-11 作者:千家信息网编辑
千家信息网最后更新 2025年02月11日,本篇内容介绍了"Linux Tcp内核协议栈Packet Drill基本原理是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望
千家信息网最后更新 2025年02月11日Linux Tcp内核协议栈Packet Drill基本原理是什么

本篇内容介绍了"Linux Tcp内核协议栈Packet Drill基本原理是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

Linux TCP 内核协议栈是一个非常复杂的实现, 不但沉淀了过去20多年的设计与实现,同时还在不停的更新。相关的RFC与优化工作一直还在进行中。如何研究和学习Linux TCP内核协议栈这样一块硬骨头就成了一大难题。

当然最重要也是最基本的还是要阅读相关的RFC和内核中的代码实现。这个是最最基本的要求。想要驯服TCP 内核协议栈这样的monster 仅仅浏览和静态分析代码是完全不够的。因为整个实现中充斥着各种边界条件和异常的处理(这里有部分原因是因为TCP协议本身设计造成的),尤其是TCP是有状态的协议, 很多边界条件的触发需要一系列的报文来构成,同时还需要满足时延等其它条件。

幸运的是Google在2013年替大家解决了这个难题。Google 在2013 年发布了TCP 内核协议栈 测试工具 Packet Drill。这个工具是名副其实,大大的简化了学习和测试TCP 内核协议栈的难度。基本可以随心所欲的触摸TCP 内核协议栈的每个细节。Google的这件工具真是造福了人类。

使用Packet Drill, 用户可以随心所欲的构造报文序列,可以指定所有的报文格式(类似tcpdump语法)然后通过TUN接口和目标系统的TCP 内核协议栈来通信, 并对接收到的来自目标系统TCP 内核协议栈 的报文进行校验,来确定是否通过测试。再进一步结合wireshark+Packet Drill 用户可以获得最直观而且具体的体验。每个报文的每个细节都在掌控之中,溜得飞起,人生瞬间到达了巅峰。

Packet Drill 基本原理

TUN 网络设备

TUN 是Linux 下的虚拟网络设备, 可以直通到网络层。使得应用程序可以直接收发IP报文。

Packet Drill 脚本解析/执行引擎

  • 首先 Packet Drill 脚本必须要被解析和分解为 通过传统socket 接口收发报文的部分和通过TUN接口收发报文的部分

  • 在传统socket 接口执行对应的动作。

  • 在TUN接口执行对应的动作,并对收到的数据进行比对。

  • 在本文中 socket 接口主要扮演的是 server side的角色。TUN接口扮演的是client的角色。因而我们可以通过TUN接口完全掌控我们将要发送出去的IP报文,并受到TCP协议栈的反馈。并和预设数据进行比对。

Packet Drill 语法简介

相对时间顺序

Packet Drill 每一个事件(发送/接收/发起系统调用)都有相对前后事件的时间便宜。一般使用+number 来表达。例如+0 就是在之前的事件结束之后立即发起。+.1 表示为在之前时间结束0.1秒之后发起。以此类推

系统调用

Packet Drill 中集成了系统调用, 可以通过脚本来完成例如 socket,bind, read,write,getsocketoption 等等系统调用。熟悉socket 编程的同学很容易理解并使用。

报文的发送与接受

  • 通过内核栈侧。可以通过调用系统调用 read/write 来完成报文的发送与接受。但是因为tcp是有状态的协议栈,所以内核栈本身也会根据协议栈所处状态发送报文(例如ACK/SACK).

  • TUN 设备侧. Packet Drill 使用 < 表示发送报文, 使用 > 表示接收报文。

报文的格式描述

报文格式的表达比较类似tcpdump。例如 S 0:0(0) win 1000表示syn包 win大小为1000, 同时tcp的选项 mss (max segment size)为1000.

下面我们通过2个例子来进一步学习

Handshake and Teardown

我们通过packet drill的脚本 复习一下这个经典的流程。

首选来回顾一下 TCP协议标准的 handshake 和 treardown 流程

接下来我们结合packet drill 的脚本来重现 整个过程

//创建server侧socket, server侧socket 将通过内核协议栈来通信  // 注意这里使用的是传统的系统调用  0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3     //设置对应的socket options  // 注意这里使用的是传统的系统调用  +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0     //bind socket  // 注意这里使用的是传统的系统调用  +0 bind(3, ..., ...) = 0     //listen on the socket  // 注意这里使用的是传统的系统调用  +0 listen(3, 1) = 0     // client侧(TUN)发送 syn 握手的第一个报文  // 注意这里的语法 syn seq都是相对的,从0开始。  +0 < S 0:0(0) win 1000      // client侧(TUN)期望收到的报文格式 syn+ack 且 ack.no=ISN(c)+1  // 参考标准流程图 最后的<...> 表示任何tcp option都可以  // 这里是握手的第二步  +0 > S. 0:0(0) ack 1 <...>     // client侧(TUN)发送 ack 报文 seq = ISN(c)+1, ack = ISN(c) +1  // 这里是握手的第三步  +.1 < . 1:1(0) ack 1 win 1000     //握手成功,server侧 socket 返回 established socket  //这时通过accept 系统调用拿到这个stream 的socket  +0 accept(3, ..., ...) = 4     //server侧向stream 写入 10 bytes  //通过系统调用来完成写操作  +0 write(4, ..., 10)=10     //client侧期望收到receive 10 bytes  +0 > P. 1:11(10) ack 1     //client侧应答 ack 表示接收到 10 bytes  +.0 < . 1:1(0) ack 11 win 1000     // client 关闭连接 发送fin包  +0 < F. 1:1(0) ack 11 win 4000     // client侧期望接收到server端的对于fin的ack报文  // 这里由内核协议栈发回。ack = server seq +1, seq = server ack  // 参考标准流程图  +.005 > . 11:11(0) ack 2     // server 关闭连接 通过系统调用完成  +0 close(4) = 0     // client期望接收到的fin包格式  +0 > F. 11:11(0) ack 2     // client 发送server端fin包的应答ack包  +0 < . 2:2(0) ack 12 win 4000

至此, 我们纯手动的完成了全部的发起和关闭连接的过程。然后我们用wireshark 来验证一下

通过结合packetdrill与wireshark 使得每一步都在我们的掌控之中,

SACK

我们将使用packet drill 来探索一些更为复杂的案例。例如内核协议栈对于 SACK中各种排列组合的响应。

SACK 是TCP协议中优化重传机制的一个重要选项(该选项一般都在报头的options部分)。

最原始的情况下如果发送方对于 每一个报文接受到ACK之后再发送下一个报文, 效率将是极为低下的。引入滑动窗口之后允许发送方一次发送多个报文 但是如果中间某个报文丢失(没有收到其对应的ACK)那么从那个报文开始,其后所有发送过的报文都要被重新发送一次。造成了极大的浪费。

SACK 是一种优化措施, 用来避免不必要的重发, 告知发送方那些报文已经收到,不用再重发。tcp 的选项中允许带有最多3个SACK的options。也就是三个已经收到了得报文区间信息。说了这么多, 还是有一些抽象, 我们来看一个具体的示例。

示例说明

在下面的这个例子中, 我们需要发送报文的顺序是 1,3,5,6,8,4,7,2 也就是测试一下内核tcp协议栈的SACK逻辑是否如同RFC中所描述的一样。

// 初始化部分建立服务器端socket, 不再赘述  +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3  +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0  +0 bind(3, ..., ...) = 0  +0 listen(3, 1) = 0     // Client 端发送 握手报文以及接受服务器响应,不再赘述。这里注意激活了SACK  +.1 < S 0:0(0) win 50000   +0 > S. 0:0(0) ack 1 win 32000   +0 < . 1:1(0) ack 1 win 50000     // Server 端就绪  +.1 accept(3, ..., ...) = 4     //发送报文1  +0 < . 1:1001(1000) ack 1 win 50000  //发送报文3, 报文2 被调整到最后发送  +0 < . 2001:3001(1000) ack 1 win 50000  //发送报文5 报文4 被调整乱序  +0 < . 4001:5001(1000) ack 1 win 50000  //发送报文6  +0 < . 5001:6001(1000) ack 1 win 50000   //发送报文8 报文7 被调整乱序  +0 < P. 7001:8001(1000) ack 1 win 50000  //发送报文4  +0 < . 3001:4001(1000) ack 1 win 50000  //发送报文7  +0 < . 6001:7001(1000) ack 1 win 50000  // 接收到第一个报文的ACK  +0 > . 1:1(0) ack 1001     // 接收到SACK, 报告收到了乱序的报文3,但是没报文2。  +0 > . 1:1(0) ack 1001 win 31000   // 接收到SACK, 报告收到了乱序的报文3,报文5,但是没报文2。没报文4  +0 > . 1:1(0) ack 1001 win 31000   // 接收到SACK, 报告收到了乱序的报文3,报文5,但是没报文2。没报文4  +0 > . 1:1(0) ack 1001 win 31000   // 接收到SACK, 报告收到了乱序的报文3,报文5,6, 报文8,但是没报文2。没报文4,没报文7  +0 > . 1:1(0) ack 1001 win 31000   // 接收到SACK, 报告收到了乱序的报文3,4,5,6, 报文8,但是没报文2。没报文7  +0 > . 1:1(0) ack 1001 win 31000   // 接收到SACK, 报告收到了乱序的报文3,4,5,6,7,8,但是没报文2  +0 > . 1:1(0) ack 1001 win 31000      //发送报文2 至此所有报文完结  +0 < . 1001:2001(1000) ack 1 win 50000     +0 > . 1:1(0) ack 8001`

随后我们再来用wireshark 验证一下。

果然完全匹配。

Packet Drill 其实还有非常复杂而且更精巧的玩法, 可以充分测试各种边界条件。以后有机会再和大家进一步分享

"Linux Tcp内核协议栈Packet Drill基本原理是什么"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

报文 内核 系统 接口 传统 报告 格式 脚本 部分 测试 条件 学习 原理 复杂 事件 可以通过 同时 工具 流程 状态 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 分布式数据库事务中间件 福建网络安全培训免费试学 数据库中正确的逻辑运算 剑与家园只有一个服务器吗 美国加州数据库 java链接数据库怎么看 ted软件开发者 个人信用信息数据库的数据来源字 软件开发过程中人员行为准则 控制网络技术的特征 企业如何提升软件开发能力 pdu服务器专用电源厂家 数据库如何查看存储过程 dns服务器搭建 物联网在网络安全方面的应用 手机如何远程管理电脑服务器 刀片服务器和pc服务器 sql数据库应用技术答案 东莞上位机软件开发培训 netc怎么加入数据库 水务行业网络安全防护方案 网络安全示范学校申报材料 宛若晨星互联网科技 专科女生计算机网络技术好就业吗 新浪体育数据库怎么找 计算机软件开发管辖 滨州hr人力资源软件开发服务 服务器安全模式杀毒 一站式网络技术推广系统 湖北瀚宇汇通网络技术有限公司
0