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

news2024/11/14 15:05:30

内核-用户空间鸿沟

构建自己的 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.coloradmin.cn/o/1480285.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一念生花,Coze 结合VisActor 文生图实战总结

前言 词云魔方 逢年过节发送祝福语是中国人特有的礼节&#xff0c;然而准备拜年祝福语也是让人伤透脑筋&#xff0c;大多数人都是拷贝网络上流行的“段子”&#xff0c;改一下名字就发出来了。更有甚者连名字都不改&#xff0c;略显尴尬。 但是如果可以让 AI 总结你想对特定…

18个惊艳的可视化大屏(第十辑):物流运输快递方向

可视化大屏在物流运输行业中具有很大的应用价值&#xff0c;可以帮助企业实现实时监控、路线规划、数据分析、风险预警、服务质量监控和决策支持等目标&#xff0c;提高物流运输效率和安全性&#xff0c;降低成本&#xff0c;提升企业竞争力&#xff0c;贝格前端工场带来的和这…

跨国企业如何选择合格的国际数据业务传输方案

在全球化的商业环境中&#xff0c;跨国企业面临着数据跨境传输的挑战。随着业务的扩展&#xff0c;企业需要在不同国家和地区之间高效、安全地传输大量数据。选择合适的国际数据业务传输方案对于保障数据安全、提高业务效率、遵守法律法规至关重要。 为什么跨国企业需要一个合适…

CentOS 定时调度

文章目录 一、场景说明二、脚本职责三、参数说明四、操作示例五、注意事项 一、场景说明 本自动化脚本旨在为提高研发、测试、运维快速部署应用环境而编写。 脚本遵循拿来即用的原则快速完成 CentOS 系统各应用环境部署工作。 统一研发、测试、生产环境的部署模式、部署结构、…

蓝桥杯练习系统(算法训练)ALGO-994 最大分解

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 给出一个正整数n&#xff0c;求一个和最大的序列a0&#xff0c;a1&#xff0c;a2&#xff0c;……&#xff0c;ap&#xff…

案例研究|DataEase助力众陶联应对产业链数据可视化挑战

佛山众陶联供应链服务有限公司&#xff08;以下简称为“众陶联”&#xff09;成立于2016年&#xff0c;是由34家陶瓷企业共同创办的建陶行业工业互联网平台&#xff0c;股东产值占整个行业的22.5%。众陶联以数据赋能为核心&#xff0c;积极探索新的交易和服务模式&#xff0c;构…

安达发|APS自动排程软件的三种模式

APS自动排程软件是一种用于生产计划和调度的工具&#xff0c;它可以帮助制造企业实现生产过程的优化和效率提升。根据不同的需求和应用场景&#xff0c;APS自动排程软件通常有三种模式&#xff1a;基于模拟仿真模式、基于TOC的模式和扩展以及基于数学建模。下面我将详细介绍这三…

小程序开发:app.vue检测更新时判断是否是朋友圈进入

因为如果从朋友圈点进小程序来的&#xff0c;有些功能就用不了&#xff0c;所以需要判断下是否从朋友圈点进来的。 检查代码如下&#xff1a; checkScene() { // 判断场景值 如果是从分享到朋友圈再打开 就会有一些功能无法使用 // 详见 https://developers.weixin.qq.com/…

Nodejs 第四十三章(redis)

Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的内存数据结构存储系统&#xff0c;它提供了一个高效的键值存储解决方案&#xff0c;并支持多种数据结构&#xff0c;如字符串&#xff08;Strings&#xff09;、哈希&#xff08;Hashes&#xff09;、列表&a…

【机器学习实战1】泰坦尼克号:灾难中的机器学习(一)数据预处理

&#x1f338;博主主页&#xff1a;釉色清风&#x1f338;文章专栏&#xff1a;机器学习实战&#x1f338;今日语录&#xff1a;不要一直责怪过去的自己&#xff0c;她曾经站在雾里也很迷茫。 &#x1f33c;实战项目简介 本次项目是kaggle上的一个入门比赛 &#xff1a;Titani…

QML中动态表格修改数据

1.qml文件中的实现代码 import QtQuick 2.15 import QtQuick.Window 2.15import QtQuick.Controls 2.0 import Qt.labs.qmlmodels 1.0 import QtQuick.Layouts 1.15Window {width: 640height: 480visible: truetitle: qsTr("Hello World")TableModel{id:table_model…

Freesia项目目录结构

目录结构 前端目录&#xff1a; &#xff08;目录结构来自layui-vue-admin&#xff09; src文件下 api&#xff08;前端请求后端服务的路由&#xff09;assert&#xff08;一些内置或必要的资源文件&#xff09;layouts&#xff08;全局框架样式组件&#xff09;router&…

Facebook的数字治理挑战:社交平台的未来模式

在当今数字化时代&#xff0c;社交媒体平台已经成为人们日常生活的重要组成部分&#xff0c;而Facebook作为其中最具代表性的平台之一&#xff0c;其承载的社交功能和影响力已经不可小觑。然而&#xff0c;随着社交媒体的普及和发展&#xff0c;一系列数字治理挑战也随之而来&a…

git项目推荐 maku-boot低代码开发项目推荐

介绍项目 项目仓库地址 官方gitee,这是他的官网 用于做二次开发的脚手架在合适不过 后端框架采用 springboot3,security6,Mybatisplus2,jdk,各种oss的集合,判断ip地址等监控,用来作为源码学习和二次开发都是很好的教材 代码基本都是mvc的二次封装,便于理解 代码模块 启…

初学JavaWeb开发总结

0 什么是Web开发 Web: 全球广域网&#xff0c;又称万维网(www World Wide Web)&#xff0c;能够通过浏览器访问的网站。 Web开发&#xff0c;就是开发网站的&#xff0c;如&#xff1a;淘宝、京东等等。 1 网站的工作流程 流程&#xff1a; 浏览器先向前端服务器请求前端资…

李修思将出席工业循环水节水减排提标降碳新技术推广及应用

演讲嘉宾&#xff1a;李修思 技术总监 山东海能环境技术有限公司 演讲题目&#xff1a;工业循环水节水减排提标降碳新技术推广及应用 会议简介 “十四五”规划中提出&#xff0c;提高工业、能源领城智能化与信息化融合&#xff0c;明确“低碳经济”新的战略目标&#xff0c;…

Axure导入使用ElementUI组件库

在使用Axure进行UI设计时&#xff0c;我们可能导入ElementUI组件库或者一些其他的元件库&#xff0c;其实非常简单&#xff0c;如果你还没有装好Axure可以先安装好AxureRP9汉化版&#xff0c;接下来&#xff0c;我们以AxureRP9汉化版来演示如何导入ElementUI组件库。 第一步&a…

搭建LNMP环境并搭建论坛和博客

目录 一、LNMP架构原理 二、编译安装Nginx 三、编译安装MySQL 四、编译安装PHP 五、配置Nginx支持PHP解析 六、安装论坛 七、安装博客 一、LNMP架构原理 LNMP架构&#xff0c;是指在Linux平台下&#xff0c;由运行Nginx的web服务器&#xff0c;运行PHP的动态页面解析程序…

光伏储能MPPT控制系统如何进行浪涌静电保护?

MPPT&#xff08;Maximum Power Point Tracking&#xff09;是太阳能电池板光伏发电系统中重要的一种控制技术。MPPT控制器能够实时侦测太阳能板的发电电压&#xff0c;并追踪最高电压电流值&#xff08;VI&#xff09;&#xff0c;使系统以最大功率输出对蓄电池充电&#xff0…

Sophon AutoCV推动AI应用从模型生产到高效落地

随着技术市场和应用方向的逐渐成熟&#xff0c;人工智能与各行各业的结合和落地逐渐进入了深水区。 虽然由于行业规模化和应用普及度的限制&#xff0c;人工智能在“传统”行业的落地不如消费互联网行业&#xff0c;但是借助人工智能为“传统”行业的发展注入新能量一直是相关…