当前位置: 首页 > news >正文

在 Rust 中实现 TCP : 1. 联通内核与用户空间的桥梁

内核-用户空间鸿沟

构建自己的 TCP栈是一项极具挑战的任务。通常,当用户空间应用程序需要互联网连接时,它们会调用操作系统内核提供的高级 API。这些 API 帮助应用程序 连接网络创建、发送和接收数据,从而消除了直接处理原始数据包的复杂性。这是开发标准应用程序的绝佳选择。

然而,当您打算构建自定义 TCP 栈时,事情就会变得棘手。为了实现自定义TCP 栈,您不仅仅是网络服务的消费者,还必须是管理者、处理者和调度者。这意味着需要直接与原始网络数据包交互,并处理它们,然后将它们发送到各自的目的地。本质上,您必须绕过操作系统的内置 TCP 栈,才能在用户空间 TCP 栈中直接接收和处理来自网络的原始数据包。

为了能够实现[在用户空间]处理原始网络数据包,需要设置一个虚拟网络接口。虚拟网络接口将“欺骗”内核将传入数据包直接传递给它,就像物理 NIC(网络接口卡)一样,但内核不会干预原始数据包处理。对于这个小技巧,我们将使用 Linux TUN/TAP 设备驱动程序,专注于 TUN(网络)来启动我们的虚拟网络接口。

从本质上讲,TUN 设备是一个存在于操作系统内核中的基于软件的[虚拟]网络接口。该虚拟网络接口的行为与物理网络接口非常相似,但它不依赖于物理硬件。 TUN 设备在 OSI 模型的第 3 层运行,并向任何需要发送或接收数据包的应用程序公开文件描述符。

一旦启动并运行了 TUN 设备,任何针对其 关联 IP 地址的数据包都将被内核重定向(内核不过问任何问题,不处理任何数据包),直接进入已将自身绑定到的用户空间应用程序的怀抱中的TUN 设备。这种设置为我们提供了全权委托,我们可以随心所欲地处理原始数据包。

在这里插入图片描述
linux Tun/Tap 原理 ,注意tun0 直接把数据包转发给了 User Application B,这样User Application B 就会接收到原始数据

数据包处理工作流程:TUN 设备与标准网络堆栈

StepWith TUN Device TUNWithout TUN Device
1Packet arrives at physical NIC.
数据包到达物理网卡。
Packet arrives at physical NIC.
数据包到达物理网卡。
2Kernel’s routing sends packet to TUN.
内核的路由将数据包发送到TUN。
Kernel’s network stack processes packet.
内核的网络堆栈处理数据包。
3Packet forwarded to TUN device.
数据包转发到 TUN 设备。
Packet may be filtered, NAT’d, etc.
数据包可能会被过滤、NAT 等。
4User-space app reads packet from TUN.
用户空间应用程序从 TUN 读取数据包。
OS passes packet to appropriate socket
操作系统将数据包传递到适当的套接字
5User-space stack processes packet.
用户空间堆栈处理数据包。
Application reads packet from socket.
应用程序从套接字读取数据包。
6Optional: User-space modifies packet.
可选:用户空间修改数据包。
N/A 不适用
7Optional: Packet sent out via TUN.
可选:通过 TUN 发送的数据包。
N/A 不适用
8Kernel routes the outgoing packet.
内核路由传出数据包。
Kernel routes the outgoing packet.
内核路由传出数据包。
  • With a TUN Device:
    TUN 设备:内核执行的工作最少。它将数据包转发到 TUN 设备,允许用户空间应用程序(我们的 TCP 应用程序)处理大部分数据包处理,包括可选的修改和潜在的重传。

  • Without a TUN Device:
    非TUN 设备:内核自己的网络堆栈完全处理数据包,包括任何路由、过滤和 NAT 操作。应用程序只是从套接字读取数据包,从底层细节中抽象出来。

现在理解了为什么需要使用 TUN 设备,可以开始编写一些代码了。可以通过运行创建一个全新的 Rust 项目。

cargo new blah blaj

我们将使用 TunTap crate ,它是 Tun/Tap 驱动程序的 Rust 包装。要将其添加到项目中,只需将以下行添加到 Cargo.Toml 文件中。

tun-tap = "0.1.4"
use std::io;fn main() -> io::Result<()> {// Create a new TUN interface named "tun0" in TUN mode.let nic = tun_tap::Iface::new("tune", tun_tap::Mode::Tun)?;// Define a buffer of size 1504 bytes (maximum Ethernet frame size without CRC) to store received data.let mut buf = [0u8; 1504];// Main loop to continuously receive data from the interface.loop {// Receive data from the TUN interface and store the number of bytes received in `nbytes`.let nbytes = nic.recv(&mut buf[..])?;eprintln!("read {} bytes: {:x?}", nbytes, &buf[..nbytes]);}Ok(())
}

使用 cargo b --release 构建二进制文件后,需要提升编译后的二进制文件的权限。通过运行 sudo setcap cap_net_admin=eip ./target/release/tcp 来实现这一点。这授予二进制文件操作网络接口和路由表所需的权限。

一旦执行了二进制文件,就会创建一个名为“tun0”的新虚拟网络接口。为了验证它的存在,可以运行 ip addr ,它应该显示所在机器上所有网络接口的列表,包括新创建的“tun0”,它通常位于列表的底部,如下所示。

4: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500                               qdisc noop state DOWN group default qlen 500
link/none 

但要注意,此时它没有 IP 地址。所以不能向它发送任何数据包。为了解决这个问题,可以执行 sudo ip addr add 192.168.0.1/24 dev tun0 ,给 创建的名为 tun0 的网络接口 分配 IP 地址 192.168.0.1 和子网掩码 255.255.255.0 (由 /24 表示) )。然后可以再次运行 ip addr 命令进行确认,将看到如下所示的输出,确认虚拟网络接口现在已附加一个 IP 地址,现在可以 ping 并向其发送数据包。

4: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 
qdisc noop state DOWN group default qlen 500
link/none    
inet 192.168.0.1/24 scope global tun0
valid_lft forever preferred_lft forever

接下来,通过执行 sudo ip link set up dev tun0 激活网络接口。

现在我们已经准备好进行测试了。如果您还记得,之前我们说过将在内核发送给用户空间程序中处理原始网络数据包,那么现在看看它的实际情况。继续运行以下命令来 ping 虚拟网络接口或其中的任何子网。 [同时二进制文件仍在执行]

ping - I tun0 192.168.0.2 

您会注意到应用程序收到了一些原始字节。像下面这样的东西。这挺令人兴奋。

[0, 0, 86, dd, 60, 0, 0, 0, 0, 8, 3a, ff, fe, 80, 0, 0, 0, 0, 0, 0, 15, 62, d0, a2, 5c, 4e, c2, 45, ff, 2, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 2, 85, 0, 78, 9e, 0, 0, 0, 0]]

辅助脚本

为了方便操作,可以编写整个过程的脚本:

#!/bin/bash
cargo b --release
sudo setcap cap_net_admin=eip ./target/release/tcp
./target/release/tcp & 
pid=$1
sudo ip addr add 192.168.0.1/24 dev tun0
trap "kill $pid" INT TERM
wait $pid

参考

  • Virtual networking 101: Bridging the gap to understanding TAP
    虚拟网络 101:弥合理解 TAP 的差距
  • Corresponding Code 对应代码

原文地址

相关文章:

在 Rust 中实现 TCP : 1. 联通内核与用户空间的桥梁

内核-用户空间鸿沟 构建自己的 TCP栈是一项极具挑战的任务。通常&#xff0c;当用户空间应用程序需要互联网连接时&#xff0c;它们会调用操作系统内核提供的高级 API。这些 API 帮助应用程序 连接网络创建、发送和接收数据&#xff0c;从而消除了直接处理原始数据包的复杂性。…...

STM32-ADC一步到位学习手册

1.按部就班陈述概念 ADC 是 Analog-to-Digital Converter 的缩写&#xff0c;指的是模拟/数字转换器。它将连续变量的模拟信号转换为离散的数字信号。在 STM32 中&#xff0c;ADC 具有高达 12 位的转换精度&#xff0c;有多达 18 个测量通道&#xff0c;其中 16 个为外部通道&…...

【文件管理】关于上传下载文件的设计

这里主要谈论的是产品设计里面的文件管理&#xff0c;比如文件的上传交互及背后影响到的前后端设计。 上传文件 场景&#xff1a;一条记录&#xff0c;比如个人信息&#xff0c;有姓名&#xff0c;出生年月&#xff0c;性别等一般的字段&#xff0c;还可以允许用户上传附件作为…...

微服务架构 SpringCloud

didi单体应用架构 将项目所有模块(功能)打成jar或者war&#xff0c;然后部署一个进程--医院挂号系统&#xff1b; > 优点: > 1:部署简单:由于是完整的结构体&#xff0c;可以直接部署在一个服务器上即可。 > 2:技术单一:项目不需要复杂的技术栈&#xff0c;往往一套熟…...

前端 css 实现标签的效果

效果如下图 直接上代码&#xff1a; <div class"label-child">NEW</div> // css样式 // 父元素 class .border-radius { position: relative; overflow: hidden; } .label-child { position: absolute; width: 150rpx; height: 27rpx; text-align: cente…...

SLAM基础知识-卡尔曼滤波

前言&#xff1a; 在SLAM系统中&#xff0c;后端优化部分有两大流派。一派是基于马尔科夫性假设的滤波器方法&#xff0c;认为当前时刻的状态只与上一时刻的状态有关。另一派是非线性优化方法&#xff0c;认为当前时刻状态应该结合之前所有时刻的状态一起考虑。 卡尔曼滤波是…...

云时代【6】—— 镜像 与 容器

云时代【6】—— 镜像 与 容器 四、Docker&#xff08;三&#xff09;镜像 与 容器1. 镜像&#xff08;1&#xff09;定义&#xff08;2&#xff09;相关指令&#xff08;3&#xff09;实战演习镜像容器基本操作离线迁移镜像镜像的压缩与共享 2. 容器&#xff08;1&#xff09;…...

【QT+QGIS跨平台编译】之五十三:【QGIS_CORE跨平台编译】—【qgssqlstatementparser.cpp生成】

文章目录 一、Bison二、生成来源三、构建过程一、Bison GNU Bison 是一个通用的解析器生成器,它可以将注释的无上下文语法转换为使用 LALR (1) 解析表的确定性 LR 或广义 LR (GLR) 解析器。Bison 还可以生成 IELR (1) 或规范 LR (1) 解析表。一旦您熟练使用 Bison,您可以使用…...

JMeter性能测试基本过程及示例

jmeter 为性能测试提供了一下特色&#xff1a; jmeter 可以对测试静态资源&#xff08;例如 js、html 等&#xff09;以及动态资源&#xff08;例如 php、jsp、ajax 等等&#xff09;进行性能测试 jmeter 可以挖掘出系统最大能处理的并发用户数 jmeter 提供了一系列各种形式的…...

你知道什么是回调函数吗?

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…...

mac苹果电脑c盘满了如何清理内存?2024最新操作教程分享

苹果电脑用户经常会遇到麻烦:内置存储器(即C盘)空间不断缩小&#xff0c;电脑运行缓慢。在这种情况下&#xff0c;苹果电脑c盘满了怎么清理&#xff1f;如何有效清理和优化存储空间&#xff0c;提高计算机性能&#xff1f;成了一个重要的问题。今天&#xff0c;我想给大家详细介…...

k8s-kubeapps图形化管理 21

结合harbor仓库 由于kubeapps不读取hosts解析&#xff0c;因此需要添加本地仓库域名解析&#xff08;dns解析&#xff09; 更改context为全局模式 添加repo仓库 复制ca证书 添加成功 图形化部署 更新部署应用版本 再次进行部署 上传nginx 每隔十分钟会自动进行刷新 在本地仓库…...

1_Springboot(一)入门

Springboot&#xff08;一&#xff09;——入门 本章重点&#xff1a; 1.什么是Springboot; 2.使用Springboot搭建web项目&#xff1b; 一、Springboot 1.Springboot产生的背景 Servlet->Struts2->Spring->SpringMVC&#xff0c;技术发展过程中&#xff0c;对使…...

Docker Machine简介

Docker Machine 是一种可以让您在虚拟主机上安装 Docker 的工具&#xff0c;并可以使用 docker-machine 命令来管理主机。 Docker Machine 也可以集中管理所有的 docker 主机&#xff0c;比如快速的给 100 台服务器安装上 docker。 Docker Machine 管理的虚拟主机可以是机上的…...

GWO优化高斯回归预测(matlab代码)

GWO-高斯回归预测matlab代码 GWO&#xff08;Grey Wolf Optimizer&#xff0c;灰狼优化算法&#xff09;是一种群智能优化算法&#xff0c;由澳大利亚格里菲斯大学的Mirjalili等人于2014年提出。这种算法的设计灵感来源于灰狼群体的捕食行为&#xff0c;其核心思想在于模仿灰狼…...

LaTeX-设置图像与表格位置

文章目录 LaTeX-设置图像与表格位置1.图像位置定位1.1 基本定位1.2 figure环境实现图像的位置定位&#xff08;常用&#xff09;1.3 一个图形中包含多个图像1.4在图形周围换行文本 2.表格位置定位2.1基本定位2.1 table环境实现表格的位置定位&#xff08;常用&#xff09;2.3在…...

STM32 DMA入门指导

什么是DMA DMA&#xff0c;全称直接存储器访问&#xff08;Direct Memory Access&#xff09;&#xff0c;是一种允许硬件子系统直接读写系统内存的技术&#xff0c;无需中央处理单元&#xff08;CPU&#xff09;的介入。下面是DMA的工作原理概述&#xff1a; 数据传输触发&am…...

mysql根据指定顺序返回数据--order by field

在查询数据的时候&#xff0c;在in查询的时候&#xff0c;想返回的数据根据 in里的数据顺序返回&#xff0c;可以直接在orderby中通过 FIELD(字段名称逗号分隔的值的顺序) 进行指定&#xff1b;示例没有加 order by field添加 order by field效果...

IEEE SGL与NVMe SGL的区别?

在HBA&#xff08;Host Bus Adapter&#xff09;驱动程序中&#xff0c;IEEE SGL&#xff08;Institute of Electrical and Electronics Engineers Scatter-Gather List&#xff09;和NVMe SGL&#xff08;Non-Volatile Memory Express Scatter-Gather List&#xff09;是两种不…...

struct内存对齐

5.1.3 struct内存对齐 结构体的对齐规则&#xff1a; (1)第一个成员在与结构体偏移量为0的地址处。 (2)其他成员变量要对齐到对齐数的整数倍的地址处 对齐数 编译器默认的对齐数与该成员大小的较小值。&#xff08;vs中默认值为8&#xff09; (3)结构体总大小为最大对齐数…...

如何审计一个智能合约?

如何审计一个智能合约&#xff1f; 智能合约作为区块链技术的核心应用之一&#xff0c;凭借其去中心化、不可篡改的特性&#xff0c;被广泛应用于金融、供应链、游戏等领域。智能合约一旦部署便难以修改&#xff0c;任何漏洞都可能引发严重的安全问题&#xff0c;甚至导致巨额…...

RadioHead嵌入式无线协议栈原理与STM32实战

1. RadioHead库概述&#xff1a;面向嵌入式系统的面向对象无线数据链路协议栈RadioHead 是一个专为资源受限嵌入式微处理器设计的、高度可移植的面向对象无线数据链路协议栈。它并非简单的射频驱动封装&#xff0c;而是一套完整的、分层抽象的通信框架&#xff0c;覆盖从物理层…...

使用 Nginx 实现负载均衡与反向代理

Nginx作为一款高性能的Web服务器和反向代理工具&#xff0c;凭借其轻量级、高并发的特性&#xff0c;成为现代架构中负载均衡与反向代理的首选方案。无论是应对突发流量&#xff0c;还是提升服务可用性&#xff0c;Nginx都能通过简洁的配置实现高效分发请求。本文将深入探讨其核…...

再次革新 .NET 的构建和发布方式(一)氨

本文能帮你解决什么&#xff1f; 1. 搞懂FastAPI异步&#xff08;async/await&#xff09;到底在什么场景下能真正提升性能。 2. 掌握在FastAPI中正确使用多线程处理CPU密集型任务的方法。 3. 避开常见的坑&#xff08;比如阻塞操作、数据库连接池耗尽、GIL限制&#xff09;。 …...

穿戴式设备:生理信号采集与健康状态分析

**穿戴式设备&#xff1a;生理信号采集与健康状态分析** 在科技飞速发展的今天&#xff0c;穿戴式设备已成为健康管理的重要工具。它们通过实时采集心率、血氧、体温等生理信号&#xff0c;结合智能算法分析用户的健康状态&#xff0c;为疾病预防和健康干预提供科学依据。无论…...

NeurIPS 2024新作SOFTS实战:用PyTorch复现这个高效的多元时间序列预测模型

NeurIPS 2024新作SOFTS实战&#xff1a;用PyTorch复现高效的多元时间序列预测模型 多元时间序列预测在能源管理、交通流量分析和金融市场预测等领域具有广泛应用。2024年NeurIPS会议上提出的SOFTS模型&#xff0c;通过创新的Series-cOre Fusion机制&#xff0c;在预测精度和计算…...

可变形卷积实战:从原理到PyTorch实现

1. 可变形卷积的核心原理 第一次接触可变形卷积这个概念时&#xff0c;我正被一个目标检测项目困扰着。传统卷积神经网络在处理形变物体时表现不佳&#xff0c;比如检测不同姿态的行人或者被部分遮挡的车辆。直到发现了可变形卷积这个"黑科技"&#xff0c;问题才迎刃…...

Windows平台下的高效BLE设备调试指南

1. Windows平台BLE调试入门指南 第一次接触BLE设备调试的开发者&#xff0c;往往会被一堆专业术语吓到——GATT、特征值、广播包、RSSI...其实在Windows平台上调试BLE设备&#xff0c;完全可以像玩积木一样简单。我刚开始做智能手环开发时&#xff0c;花了三天才搞明白怎么读取…...

Python字典进阶:从‘学生成绩统计’到‘自动选课分析’,教你写出更地道的代码

Python字典进阶&#xff1a;从‘学生成绩统计’到‘自动选课分析’&#xff0c;教你写出更地道的代码 在Python的世界里&#xff0c;字典&#xff08;dict&#xff09;就像是一个神奇的魔法口袋&#xff0c;它能以键值对的形式存储各种数据&#xff0c;让信息的存取变得异常高效…...

Ubuntu下配置Samba服务实现跨平台文件共享

1. 为什么需要Samba服务&#xff1f; 如果你同时使用Windows和Linux电脑&#xff0c;肯定遇到过文件互传的麻烦。用U盘拷来拷去太原始&#xff0c;微信传文件又受大小限制&#xff0c;这时候Samba就是你的救星。它就像在两个系统之间架了一座桥&#xff0c;让文件传输变得像在本…...