Rootless Router(Extra):Userspace 網路棧
- Rootless Router(Part: 0): 用戶態DN42節點
- Rootless Router(Part: 1): wggo-vpp
- Rootless Router(Re: 0): VPP Host stack
- Rootless Router(Part: 2): BIRD-vpp
- Rootless Router(Part: 3): EtherGuard
- Rootless Router(Extra):蒐集的Userspace 網路棧
- Rootless Router(Part: 4): 被VPP Host Stack衝康
- Rootless Router(Part: 5): 完結
- Rootless Router(Fin): UML版本上線啦!
- Rootless Router(Afterword): Azure App Service真的很靈
之前在這篇提到我蒐集到的Userspace network stack,想說獨立一篇出來好了。之後有查到新東西直接加進來
用戶態的網路堆疊方案
這些是目前我找到的用戶態的網路堆疊方案,以及他們kernel bypass所用的技術
- 基於LD_PRELOAD
- VPP (我用起來相容性不好。後來發現BIRD能用)
- NUSE (聽說bug很多)
- The shadow simulator (很新的專案,資料蠻少的)
- 基於ptrace
- gVisor
- UML(User Mode Linux) (就是linux的網路棧)
- The shadow simulator (好像兩個一起用,增加穩定度)
- 重新編譯原始碼
- LKL(Linux Kernel Library) (C/C++版本,也是linux的網路棧)
- LKL.js (javascript版本的LKL,可以在瀏覽器上執行!)
- F-Stack
- 基於network namespace (只是用了linux的ns隔離,本質上還是跑在kernel)
- mininet
- 沒有kernel bypass功能,依賴tun/tap
- RARE/freertr
- ns3
什麼是kernel bypass? 和網路隔離有什麼關係?
首先我們要知道,unix底下,程式如何連上網路的
首先,linux可執行檔使用 socket(domain,type,protocol) 系統呼叫
OS就會在背景創建一個socket,同時返回一個file descriptor,是一個整數。以下簡稱fd
如果我們想監聽port,我們使用 bind(fd, &addr, addrlen) 這個系統呼叫
如果我們想連線,就會使用 connect(fd, &addr, addrlen) 這個系統呼叫
我們想接收/發送資料,只要呼叫 read(fd, &buf, len) 或是 write(fd, &buf, len)即可
剩下的一切,linux都會在背後幫我們處理
linux如何處裡的呢? 預設情況下,linux會維護一個網路堆疊
據我們的需求,這些API都會和那個堆疊互動。修改堆疊內tcp狀態機的狀態
或是從網路堆疊複製/寫入資料到我們提供的buffer內
或是呼叫網卡驅動,驅動網卡的電路晶片,發送網路封包
當我們想要隔離網路的時候,有一個要點: 不要和主系統的網路堆疊互動。我們跑去和別的網路堆疊作互動
常見的網路隔離的技術:
- network namespace: linux kernel 維護多個網路堆疊
- 當應用程式呼叫socket()時,kernel會根據你所處的namespace,決定要和哪個堆疊作互動
- LD_PRELOAD: 劫持現有程式內部的系統呼叫。
- 以VPP為例,首先
- DPDK架構下,封包不經過kernel
- 所以VPP要自己維護一個網路堆疊,獨立於kernel的網路堆疊
- VCL負責劫持程式的 socket()/bind()/connect()/read()/write() 等等系統呼叫
- 並且把呼叫參數轉交給VPP,和VPP維護的網路堆疊作互動
- 被VPP劫持了的系統呼叫列表
- 基於環境變數,環境變數被改變,劫持就失效了
- ptrace: 和LD_PRELOAD一樣,但是改成透過ptrace()這個系呼叫
- 流程類似,劫持網路相關系統呼叫
- hook由kernel管理,更難逃逸
- 為一些容器技術利用,在用戶態實現kernel API
- 做出比docker更安全的容器,不受kernel漏洞影響
- 重新編譯原始碼: 這個很容易理解
- 編譯的時候直接把 bind() socket()之類的改成 custom_bind() custom_socket()
- 裡面則是和自己維護的堆疊互動
改動系統路由表/創建network space/veth/tun tap等等操作都是Operation Not Permitted
所以只能仰賴這種方式,不再依賴kernel提供的網路堆疊,使用自己實作的網路堆疊。再用kernel bypass的方式把第三方程式拉入使用自己的堆疊
能用的kernel bypass技術
Docker unprivileged container 裡面,只有方案1/3是可以用的,ptrace/ns都沒權限
更新: 有個好消息,kernel 4.8以後,ptrace就可以用了。因為linux kernel的ptrace security issues修好了!
所以docker 19.03以及kernel 4.8以後,方案2也可用了!
現在方案2也納入我的考慮之中了!
不過我目前VPP已經搞一堆東西了,現在要我換跑道,改走gvisor路線,之前的努力就又白費了
還不想現在切換跑道,遇到問題能patch先考慮patch看看。這就是沉沒成本效應嗎?
留言
張貼留言