在 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 對應代碼

原文地址

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/711646.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/711646.shtml
英文地址,請注明出處:http://en.pswp.cn/news/711646.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【教3妹學編程-算法題】標記所有下標的最早秒數 II

3妹&#xff1a;2哥2哥&#xff0c;你有沒有看到上海女老師出軌男學生的瓜啊。 2哥 : 看到 了&#xff0c;真的是太毀三觀了&#xff01; 3妹&#xff1a;是啊&#xff0c; 老師本是教書育人的職業&#xff0c;明確規定不能和學生談戀愛啊&#xff0c;更何況是出軌。 2哥 : 是啊…

shell 免交互ecxept樣例

語法 expect [選項] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ] 選項 -c&#xff1a;從命令行執行expect腳本&#xff0c;默認expect是交互地執行的 示例&#xff1a;expect -c expect "\n" {send "pressed enter\n"} -d&#xff1a;輸出調試信息 …

【Qt學習】QTextEdit 與 QComboBox 的 屬性與實例(槽函數的使用、讀取本機內容到控件)

文章目錄 1. QTextEdit2.1 介紹2.2 實例使用 - 槽函數的使用 2. QComboBox2.1 介紹2.2 實例使用案例1&#xff1a;設置下拉框項目組件的方式案例2&#xff1a;讀取本機文件內容 到QComboBox 1. QTextEdit 2.1 介紹 我們可以查閱官方文檔&#xff0c;對QTextEdit 有更深的了解&…

源碼安裝nginx保姆級教程

一.目錄存放 1./usr/lib/syste,md/system/:每個服務最主要的啟動腳本設定 2. /run/systemd/system/&#xff1a;系統執行過程中所產生的服務腳本&#xff0c;這些腳本的優先序要比 /usr/lib/systemd/system/ 高&#xff01; 3./etc/systemd/system/&#xff1a;管…

【java 基礎】閑話 ClassLoader 和 SPI (一)

文章目錄 引子雙親委派模型你真的明白了嗎&#xff1f; 雙親委派“不夠用了”SPI機制 其他瑣碎 引子 有別于 java 提供的 IO 模塊&#xff0c;java 中的classloader主要是用來加載類的&#xff0c;當然除了加載類&#xff0c;也可以加載資源文件。 那么首先我們會問一個問題&…

java基礎 - 14 Java的Deque之Deque、BlockingDeque、LinkedBlockingDeque、ArrayDeque

Java 中的 Deque&#xff08;雙端隊列&#xff09;是一種具有隊列和棧特性的數據結構&#xff0c;它允許在兩端進行插入和刪除操作。Deque 接口是 Java 集合框架中的一部分&#xff0c;它定義了雙端隊列的基本操作。 BlockingDeque 接口&#xff1a; BlockingDeque 接口是 Deq…

docker搭建git服務器

1、docker搭建git服務器 總體思路&#xff1a;服務端通過docker搭建git服務器&#xff0c;客戶端創建git的賬戶及公鑰密鑰&#xff1b; 1&#xff09;服務端# 創建容器 # --privileged 獲得完整的root權限 # /usr/sbin/init 啟動容器執行的第一個命令 以便可以使用systemctl命…

2024年FPGA可以進嗎

2024年&#xff0c;IC設計FPGA行業仍有可能是一個極具吸引力和活力的行業&#xff0c;主要原因包括&#xff1a; 1. 技術發展趨勢&#xff1a;隨著5G、人工智能、物聯網、自動駕駛、云計算等高新技術的快速發展和廣泛應用&#xff0c;對集成電路尤其是高性能、低功耗、定制化芯…

【UE 材質】制作加載圖案(2)

在上一篇&#xff08;【UE 材質】制作加載圖案&#xff09;基礎上繼續實現如下效果的加載圖案 效果 步驟 1. 復制一份上一篇制作的材質并打開 2. 添加“Floor”節點向下取整 除相同的平鋪數 此時的效果如下 刪除如下節點 通過“Ceil”向上取整&#xff0c;參數“Tiling”默認…

教師招聘和事業編d類有什么區別嗎

每年都有大批懷揣教育夢想的年輕人&#xff0c;站在職業的十字路口&#xff0c;對未來充滿期許與疑惑。他們中的許多人都會面臨這樣一個問題&#xff1a;教師招聘和事業編D類&#xff0c;到底有什么區別&#xff1f;今天&#xff0c;就讓我來為你揭開這兩者的神秘面紗。 別被這…

【大數據】Flink SQL 語法篇(五):Regular Join、Interval Join

《Flink SQL 語法篇》系列&#xff0c;共包含以下 10 篇文章&#xff1a; Flink SQL 語法篇&#xff08;一&#xff09;&#xff1a;CREATEFlink SQL 語法篇&#xff08;二&#xff09;&#xff1a;WITH、SELECT & WHERE、SELECT DISTINCTFlink SQL 語法篇&#xff08;三&…

ubuntu系統下大數據服務器磁盤調優測試記錄

一、背景 在kvm虛擬機ubuntu操作系統大數據平臺測試的過程中&#xff0c;遭遇了磁盤I/O性能的瓶頸&#xff0c;因有cpu綁核操作&#xff0c;故有做隔核操作驗證是否是綁核影響的磁盤I/O&#xff0c;后又對磁盤進行透傳以及掛內存盤等操作&#xff1b; 二、磁盤介紹 2.1 磁盤…

『NLP學習筆記』圖解 BERT、ELMo和GPT(NLP如何破解遷移學習)

圖解 BERT、ELMo和GPT(NLP如何破解遷移學習) 文章目錄 一. 前言二. 示例-句子分類三. 模型架構3.1. 模型輸入3.2. 模型輸出四. BERT VS卷積神經網絡五. 詞嵌入新時代5.1. 簡要回顧詞嵌入Word Embedding5.2. ELMo: 上下文語境很重要5.2.1. ELMo的秘密是什么?5.3. ULM-FiT:將遷…

藍橋杯Python B組練習——斐波那契數列

一、題目 定義 斐波那契數列&#xff08;Fibonacci sequence&#xff09;&#xff0c;又稱黃金分割數列&#xff0c;因數學家萊昂納多斐波那契&#xff08;Leonardo Fibonacci&#xff09;以兔子繁殖為例子而引入&#xff0c;故又稱為“兔子數列”&#xff0c;指的是這樣一個數…

Linux x86平臺獲取sys_call_table

文章目錄 前言一、根據call *sys_call_table來獲取二、使用dump_stack三、根據MSR_LSTAR寄存器四、使用sys_close參考資料 前言 Linux 3.10.0 – x86_64 最簡單獲取sys_call_table符號的方法&#xff1a; # cat /proc/kallsyms | grep sys_call_table ffffffff816beee0 R sy…

隨想錄算法訓練營第四十七天|198.打家劫舍、213.打家劫舍II、337.打家劫舍III

198.打家劫舍 public class Solution {public int Rob(int[] nums) {if(nums.Length0){return 0;}if(nums.Length1){return nums[0];}int[] dpnew int[nums.Length1];dp[0]nums[0];dp[1]Math.Max(nums[0],nums[1]);for(int i2;i<nums.Length;i){dp[i]Math.Max(dp[i-2]nums[…

什么是 HTTPS 證書?作用是什么?

HTTPS 證書&#xff0c;即超文本傳輸安全協議證書&#xff08;Hypertext Transfer Protocol Secure&#xff09;&#xff0c;是網站安全的關鍵組成部分。它通過 SSL/TLS 加密協議&#xff0c;確保用戶與網站之間的數據傳輸是加密和安全的。 什么是 HTTPS 證書&#xff1f; HT…

使用Docker -compose啟動自定義jar包

步驟1&#xff1a;編寫docker-compose.yml文件 首先我們需要編寫一個docker-compose.yml文件來定義我們的服務傳到我們的云服務器上 以下是一個示例&#xff1a; version: 3 services:app:build:context: .dockerfile: Dockerfileports:- 8080:8080volumes:- ./app.jar:/app…

可視化圖表:水球圖,展示百分比的神器。

Hi&#xff0c;我是貝格前端工場的老司機&#xff0c;本文分享可視化圖表設計的水球圖設計&#xff0c;歡迎老鐵持續關注我們。 一、水球圖及其作用 水球圖是一種特殊的可視化圖表&#xff0c;它主要用于展示百分比或比例的數據&#xff0c;并以水球的形式進行呈現。水球圖的作…

2023面試題

目錄 題目 1:JVM 整體結構是什么樣的? 8 題目 3:Object 類有哪些方法? 11 題目 4:靜態變量與實例變量區別? 11 題目 5:String 類的常用方法有哪些? 11 題目 6:數組有沒有 length()方法?String 有沒有 length() 12 題目 7:String、StringBuffer、StringBuilder 的區別…