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

news/发布时间2024/9/20 8:01:52

内核-用户空间鸿沟

构建自己的 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 对应代码

原文地址

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

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

相关文章

SpringBoot底层原理

SpringBoot底层原理 一 配置优先级 1.配置方式 Springboot中支持三种配置方式&#xff0c;分别为&#xff1a; application.propertiesapplication.ymlapplication.yaml 2.配置优先级 当存在多份配置文件时&#xff0c;配置文件会按照它们的优先级生效。 优先级从高到底…

uniapp 编译微信小程序的离谱报错

上图&#xff1a; 如图所示&#xff1a;在同一个元素上同时出现了 wx&#xff1a;if 和 wx&#xff1a;else 就很离谱

LeetCode215.数组中的第K个最大元素

题目 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 输入: [3,2,1,5,6,4], …

RISC-V特权架构 - 机器模式下的异常处理

RISC-V特权架构 - 机器模式下的异常处理 1 进入异常1.1 从mtvec 定义的PC 地址开始执行1.2 更新CSR 寄存器mcause1.3 更新CSR 寄存器mepc1.4 更新CSR 寄存器mtval1.5 更新CSR 寄存器mstatus 2 退出异常2.1 从mepc 定义的PC 地址开始执行2.2 更新CSR 寄存器mstatus 3 异常服务程…

使用 Haproxy 搭建Web群集

Haproxy是目前比较流行的一种群集调度工具&#xff0c;同类群集调度工具有很多&#xff0c;如LVS 和Nginx。相比较而言&#xff0c;LVS.牲能最好&#xff0e;但是搭建相对复杂:Nginx的upstream模块支持群集功能&#xff0e;但是对群集节点健康检查功能不强&#xff0c;性能没有…

进程操作(Win32, C++)

CProcessUtils.h #pragma once#include <wtypesbase.h> #include <tchar.h> #include <vector> #include <map> #include <string>#ifdef _UNICODE using _tstring std::wstring; #else using _tstring std::string; #endif// 进程信息 typed…

Java JDBC JDBC事务管理 JDBC连接池(阿里巴巴Druid连接池、C3P0连接池) JDBC工具类

Java数据库连接 Java DataBase Connectivity。JDBC 规范定义接口&#xff0c;具体的实现由各大数据库厂商来实现。 JDBC可让Java通过程序操作关系型数据库&#xff0c;JDBC基于驱动程序实现与数据库的连接与操作。 JDBC 是 Java 访问数据库的标准规范&#xff0c;真正怎么操作…

gRPC知识归档

文章目录 gRPC知识归档gRPC原理什么是gRPCgRPC的特性gRPC支持语言gRPC使用场景gRPC设计的动机和原则 数据封装和数据传输问题网络传输中的内容封装和数据体积问题JSONProtobuf&#xff08;微服务之间的服务器调用&#xff0c;一般采用二进制序列化&#xff0c;比如protobuf&…

基于springboot实现图书馆管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现图书馆管理系统演示 摘要 电脑的出现是一个时代的进步&#xff0c;不仅仅帮助人们解决了一些数学上的难题&#xff0c;如今电脑的出现&#xff0c;更加方便了人们在工作和生活中对于一些事物的处理。应用的越来越广泛&#xff0c;通过互联网我们可以更方便地…

浅谈 Linux 网络编程 - Server 端模型、sockaddr、sockaddr_in 结构体

文章目录 前言前置知识Server 端核心模型 【重点】相关函数 【重点】socket 函数bind 函数listen 函数accept 函数close 函数 sockaddr 数据结构 【重点】 前言 本文主要是对 Linux 网络编程中&#xff0c;Server 端的模型、相关函数 以及 sockaddr、sockaddr_in 结构体做介绍…

Apache Echarts介绍与入门

介绍 Apache ECharts 是一款基于 Javascript 的数据可视化图表库&#xff0c;提供直观&#xff0c;生动&#xff0c;可交互&#xff0c;可个性化定制的数据可视化图表。 官网地址&#xff1a;https://echarts.apache.org/zh/index.html 入门案例 Apache Echarts官方提供的快…

物联网技术助力智慧城市安全建设:构建全方位、智能化的安全防护体系

一、引言 随着城市化进程的加速和信息技术的迅猛发展&#xff0c;智慧城市已成为现代城市发展的重要方向。在智慧城市建设中&#xff0c;安全是不可或缺的一环。物联网技术的快速发展为智慧城市安全建设提供了有力支持&#xff0c;通过构建全方位、智能化的安全防护体系&#…

HCIA-HarmonyOS设备开发V2.0证书

目录 一、不墨迹&#xff0c;上证书二、考试总结三、习题四、知识点五、坚持就有收获 HCIA-HarmonyOS Device Developer V2.0 开发者能力认证考试已通过。 一、不墨迹&#xff0c;上证书 一个多月的努力&#xff0c;验证了自己的学习成果&#xff0c;也认识到自己有待提升之处…

CleanMyMac X2024测评深度分析与功能全面介绍

一、软件概述 CleanMyMac X 是一款强大的Mac清理和优化工具&#xff0c;它可以帮助用户轻松管理和释放Mac上的空间&#xff0c;优化系统性能&#xff0c;提高运行速度。这款软件以其直观的用户界面和丰富的功能受到了广大Mac用户的欢迎。 CleanMyMac X4.14.6全新版下载如下: …

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(一)

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验&#xff08;前导&#xff09; 四、AXI转FIFO接口模块设计 1.AXI接口知识 AXI协议是基于 burst的传输&#xff0c;并且定义了以下 5 个独立的传输通道&#xff1a; 读地址通道&#xff08;Read Address Channel&#xff0c; …

练习 3 Web [ACTF2020 新生赛]Upload

[ACTF2020 新生赛]Upload1 中间有上传文件的地方&#xff0c;试一下一句话木马 txt 不让传txt 另存为tlyjpg&#xff0c;木马文件上传成功 给出了存放目录&#xff1a; Upload Success! Look here~ ./uplo4d/06a9d80f64fded1e542a95e6d530c70a.jpg 下一步尝试改木马文件后缀…

小程序实现定位城市切换且城市根据首字母A-Z排序后端数据实现逻辑

场景&#xff1a; 话不多说后端提供数据实现步骤&#xff1a; 1.controller层 Api(tags {"[地区]-城市相关接口"}) RestController RequestMapping("region") Slf4j public class RegionController extends BaseController {Resourceprivate RegionServ…

【JavaEE】_Spring Web MVC简介

目录 1. Spring Web MVC简介 2. MVC简介 3. Spring MVC 1. Spring Web MVC简介 官网对于Spring Web MVC的介绍如下&#xff1a; 链接如下&#xff1a; https://docs.spring.io/spring-framework/reference/web/webmvc.html#https://docs.spring.io/spring-framework/refer…

小程序一键链接WIFI

1.小程序一键链接WIFI connectWifi: function() {var that this;//检测手机型号wx.getSystemInfo({success: function(res) {var system ;if (res.platform android) system parseInt(res.system.substr(8));if (res.platform ios) system parseInt(res.system.substr(4…

【LLM RAG】GritLM:统一嵌入和生成的大语言模型浅谈

前言 目前&#xff0c;所有基于文本的语言问题都可以归结为生成问题&#xff0c;并通过单一的LLM来处理。然而&#xff0c;使用嵌入的任务&#xff08;如聚类或检索&#xff09;在这种视角下往往被忽视了。文本嵌入在许多关键的实际应用中扮演着重要角色。如RAG&#xff0c;在…
推荐文章