pyTCP
用 Python 寫的 TCP/IP 堆疊
PyTCP 是一個用 Python 寫的功能齊全的 TCP/IP 堆疊。它支援基於 TCP 流的傳輸,以及基於滑動視窗機制和基本擁塞控制的可靠資料包傳送。它還支援具有 SLAAC 位址配置的 IPv6/ICMPv6 協定。它作為附加到 Linux TAP 介面的用戶空間程式運行。它實現了簡單的路由,可以透過本地網路和互聯網發送和接收流量。
與先前的版本不同,2.7 版本包含庫形式的 PyTCP 堆疊程式碼,以便外部程式碼可以輕鬆匯入和使用它。這將使用戶體驗更加流暢,並最終提供在任何第 3 方應用程式中用 PyTCP 呼叫替換標準 Linux 堆疊呼叫(例如套接字庫)的完整能力。
這個專案最初是純粹的教育工作,旨在提高我的 Python 技能並刷新我的網路知識,作為 Facebook 網路工程師角色準備的一部分。從那時起,它變得更像是一個“寵物項目”,我不定期地投入了一些時間。然而,通常每隔一兩個月就會添加一些更新。
我歡迎任何對網路程式設計感興趣的人的貢獻和幫助。任何意見都會受到讚賞。另外,請記住,某些堆疊功能可能僅部分實現(根據堆疊操作的需要)。它們可能以次優方式實現,或者不是 100% 符合 RFC 的方式(由於缺乏時間),或者它們可能包含我仍需要修復的錯誤。
請隨時檢查我的其他兩個相關項目:
- RusTCP - 嘗試用 Rust 重寫一些 PyTCP 功能並使用它來建立 IPv6/SRv6 實驗室路由器。
- SeaTCP - 嘗試使用 C 和彙編語言建立低延遲堆疊。
工作原理和測試設置
PyTCP 堆疊依賴 Linux TAP 介面。 TAP 介面是一個虛擬接口,在網路端,可以透過 Linux 橋接器或 Open vSwitch「插入」現有虛擬網路基礎架構。在內部端,TAP 介面可以像任何其他 NIC 一樣使用,透過程式設計方式傳送和接收封包給其。
如果您想在本地網路中測試 PyTCP 堆疊,我建議創建以下網路設置,該設定允許您同時將 Linux 核心(本質上是您的 Linux 作業系統)和 PyTCP 堆疊連接到本地網路。
<INTERNET> <---> [ROUTER] <---> (eth0)-[Linux bridge]-(br0) <---> [Linux TCP/IP stack]
|
|--(tap7) <---> [PyTCP TCP/IP stack]
範例程式(客戶端或服務)啟動堆疊後,可以透過簡化的 BSD 套接字(如 API 介面)與其進行通訊。也可以透過呼叫PacketHandler
類別中的_*_phtx()
方法之一直接傳送封包。
從 GitHub 儲存庫克隆 PyTCP
在大多數情況下,PyTCP 應直接從 GitHub 儲存庫克隆,因為這種類型的安裝提供了完整的開發和測試環境。
git clone http://github.com/ccie18643/PyTCP
克隆後,我們可以運行其中的範例之一:
- 前往堆疊根目錄(稱為“PyTCP”)。
- 如果需要,請執行
sudo make bridge
命令來建立「br0」橋。 - 執行
sudo make tap
指令建立 tap7 介面並將其指派給「br0」網橋。 - 執行
make
指令來建立適合開發和測試的虛擬環境。 - 跑步
. venv/bin/activate
指令啟動虛擬環境。 - 執行任何範例,例如
example/run_stack.py
。 - 按 Ctrl-C 停止它。
若要微調各種堆疊操作參數,請相應地編輯pytcp/config.py
檔案。
從 PyPi 儲存庫安裝 PyTCP
PyTCP 也可以作為 PyPi 儲存庫中的常規模組安裝。
python -m pip install PyTCP
安裝後,請確保 TAP 介面可運作並新增至橋接器。
sudo ip tuntap add name tap7 mode tap
sudo ip link set dev tap7 up
sudo brctl addbr br0
sudo brctl addif br0 tap7
可以使用以下程式碼匯入並啟動 PyTCP 堆疊。它啟動堆疊子系統並分別使用 DHCPv4 和 IPv6 SLAAC 自動設定 IPv4 和 IPv6 協定位址。
from pytcp import TcpIpStack
stack = TcpIpStack ( interface = "tap7" )
stack . start ()
堆疊子系統在自己的執行緒中運作。啟動後,堆疊將控制權交還給使用者程式碼,並且可以使用以下呼叫停止。
特徵
已經實施:
- Stack -使用「零複製」方法的快速封包解析器。
- Stack -使用「零複製」方法的快速資料包組裝器。
- 堆疊 - MAC 位址操作庫 - 與緩衝區協定 (Memoryview) 相容。
- Stack - IPv4 位址操作庫 - 與緩衝區協定 (Memoryview) 相容,不依賴 Python 標準函式庫。
- Stack - IPv6 位址操作庫 - 與緩衝區協定 (Memoryview) 相容,不依賴 Python 標準函式庫。
- 程式碼 -一些庫和模組的單元測試(基於 Facebook 的 Testslide 框架)
- 乙太網路協定 -支援乙太網路 II 標準幀。
- 乙太網路協定 -單播、IPv4 多播、IPv6 多播和廣播尋址。
- ARP 協定 -回覆、查詢、ARP 快取機制。
- ARP 協定 - ARP 偵測/通告 IP 衝突偵測 (ACD) 機制。
- IPv4 協定 -預設路由,堆疊可以使用 IPv4 協定透過 Internet 與主機通訊。
- IPv4 協定 -使用 DHCPv4 協定自動設定 IPv4 位址。
- IPv4 協定 -入站資料包碎片整理,強大的機制能夠處理無序且重疊的資料片段。
- IPv4 協定 -出站資料包分段。
- IPv4 協定 -接受但不支援 IPv4 選項。
- IPv4 協定 -支援多個堆疊的 IPv4 位址,每個位址的作用就像分配給單獨的 VRF 一樣
- ICMPv4 協定 -回顯請求、回顯應答和連接埠不可達訊息。
- IPv6 協定 -預設路由,堆疊可以使用 IPv6 協定透過 Internet 與主機通訊。
- IPv6 協定 -使用 EUI64 和重複位址偵測自動連結本機位址設定。
- IPv6 協定 -使用路由器通告/EUI64 自動 GUA 位址設定。
- IPv6 協定 -自動分配請求節點多播位址。
- IPv6 協定 -自動分配 IPv6 多播 MAC 位址。
- IPv6 協定 -入站資料包碎片整理,強大的機制能夠處理無序且重疊的資料片段。
- IPv6 協定 -出站資料包分段。
- ICMPv6 協定 -回顯請求、回顯應答和連接埠不可達訊息。
- ICMPv6 協定 -鄰居發現、重複位址偵測。
- ICMPv6 協定 -鄰居發現快取機制。
- ICMPv6 協定 -多重播送偵聽器發現 v2 (MLDv2) 協定實作(僅堆疊需要的訊息)。
- UDP 協定 -完全支援。堆疊可以使用UDP協定與其他主機交換資料。
- UDP 套接字 -完全支持,堆疊的「最終用戶」API 類似於 Berkeley 套接字。
- UDP 服務 -出於測試目的而實現的 Echo、Discard 和 Daytime 服務(在「範例」中)。
- TCP 協定 - TCP 有限狀態機的完整實作。此時,堆疊可以透過 TCP 協定與其他主機交換批次資料。
- TCP 協定 - TCP 選項支援:MSS、WSCALE、SACKPERM、TIMESTAMP。
- TCP 協定 - TCP 滑動視窗機制和資料重傳(快速重傳和基於時間的場景)。
- TCP 協定 - TCP 退避機制/基本擁塞控制。
- TCP 協定 - TCP SYN/FIN 封包重傳。
- TCP 套接字 -完全支持,堆疊的「最終用戶」API 類似於 Berkeley 套接字
待實施:
範例
幾個 ping 封包和兩隻猴子是透過 IPv6 協定上的 TCP 傳送的。
IPv6 鄰居發現/重複位址偵測/位址自動配置。
- 堆疊嘗試自動配置其鏈路本地地址。它將其產生為 EUI64 位址。作為 DAD 過程的一部分,它會加入適當的請求節點多播群組並為其產生的位址發送鄰居請求。
- 堆疊不會收到其產生的位址的任何鄰居通告,因此會將其指派給其介面。
- 堆疊嘗試分配預先配置的靜態位址。作為 DAD 過程的一部分,它會加入適當的請求節點多播群組並發送靜態位址的鄰居請求。
- 已指派相同位址的另一台主機會回覆鄰居通告訊息。這告訴堆疊另一台主機已經分配了它嘗試分配的位址,因此堆疊無法使用它。
- 堆疊發送路由器請求訊息來檢查是否有應使用的全域前綴。
- 路由器以包含附加前綴的路由器通告進行回應。
- 堆疊嘗試分配根據接收到的前綴和 EUI64 主機部分產生的位址。作為 DAD 過程的一部分,它會加入適當的請求節點多播群組並發送靜態位址的鄰居請求。
- 堆疊不會收到其產生的位址的任何鄰居通告,因此會將其指派給其介面。
- 分配所有位址後,堆疊會再發出一份多重播送偵聽器報告,列出它想要偵聽的所有多重播送位址。
TCP 快速重傳在遺失 TX 封包後生效。
- 由於模擬資料包遺失機制,傳出資料包「遺失」。
- 對等方注意到資料包 SEQ 號不一致並發出「快速重傳請求」。
- 堆疊接收請求並重傳遺失的資料包。
RX 封包遺失事件期間執行的無序佇列
- 由於模擬資料包遺失機制,傳入資料包「遺失」。
- 堆疊注意到入站資料包的 SEQ 號碼不一致,並發送「快速重傳」請求。
- 在對等方收到請求之前,它會發送多個 SEQ 高於堆疊預期的資料包。堆疊對所有這些資料包進行排隊。
- 對等方重新傳輸遺失的資料包。
- 堆疊接收到遺失的資料包,拉出儲存在亂序佇列中的所有資料包並進行處理。
- 堆疊發送 ACK 封包以確認從佇列中拉出的最新封包。
TCP 有限狀態機 - 堆疊正在運行 TCP Echo 服務。
- 對等點開啟連線。
- 對等方發送資料。
- 堆疊回顯資料。
- 對等方關閉連線。
TCP 有限狀態機 - 堆疊正在運行 TCP Echo 用戶端。
- 堆疊打開連接。
- 堆疊發送資料。
- Peer 回顯數據。
- 堆疊關閉連線。
預解析資料包健全性檢查正在進行中。
- 第一個螢幕截圖顯示了健全性檢查已關閉的堆疊。格式錯誤的 ICMPv6 封包可能會導致其崩潰。
- 第二個螢幕截圖顯示了開啟健全性檢查的堆疊。格式錯誤的 ICMPv6 封包在傳遞到 ICMPv6 協定解析器之前會被丟棄。
- 第三個螢幕截圖顯示了格式錯誤的資料包。即使封包僅包含一筆記錄,MA 記錄欄位的數量已設定為 777。
ARP 探測/通告機制。
- 堆疊使用 ARP 探針來尋找配置的每個 IP 位址可能存在的衝突。
- 其中一個 IP 位址 (192.168.9.102) 已被佔用,因此堆疊會收到有關該位址的通知並跳過它。
- 其餘的 IP 位址是免費的,因此堆疊透過為每個位址發送 ARP 公告來聲明它們。
ARP 解析和處理 ping 封包。
- 主機 192.168.9.20 嘗試 ping 堆疊。為此,它首先發送 ARP 請求封包以找出堆疊的 MAC 位址。
- 堆疊透過發送 ARP 應答封包進行回應(堆疊不需要發送其請求,因為它已經從主機的請求中記錄了主機的 MAC)。
- 主機發送 ping 封包,堆疊回應它們。
IP 碎片。
- 主機使用三個分段的 IP 封包(三個片段)發送 4Kb UDP 資料封包。
- 堆疊接收資料包並將它們組裝成一個整體,然後將其(透過 UDP 協定處理程序和 UDP 套接字)傳遞給 UDO Echo 服務。
- UDP Echo 服務會擷取資料並將其放回 UDP 套接字。
- UDP 資料封包傳送到 IP 協定處理程序,該處理程序會建立一個 IP 封包,並在檢查它是否超出連結後,MTU 將其分段為三個單獨的 IP 封包。
- IP 封包被封裝在乙太網路封包中並放置在 TX 環上。