Closed KusakabeShi closed 2 years ago
我不知道你在说什么,而且这种奇怪的需求不应该就是自己去解决吗⋯
就是可以在tun端運行服務,比如http之類 讓外面的人連近來,類似路由器的port forwarding功能
8080->192.168.22.3:80/tcp
這樣設定就會使tun2socks在主機監聽tcp 8080,有連線建立就向tun端的192.168.22.3:80 發送 TCP SYN開始建立連線。 一樣要維護tcp狀態機,有點像是tun2sock原本在做的事情反過來
直接用iptables就可以做了吧,这种需求比较奇怪而且并不是tun2socks 的行为,所以没必要加吧
恩... 應該說,我的使用情境比較不一樣。博主設想的情境應該是這樣:
+--------------------------------------------------------+
| +-----+ +----------+ |
| user space | app | |tun2socks |-------+ |
| +--|--+ +----^-----+ | |
|-------------------|--------------|-------------|--------
| +--v---+ | | |
| kernel | tun |----------+ +------v--+ |
| +------+ | eth0 | |
+-----------------------------------------+---------+----+
然後用iptables呼叫netfilter把eth0上面的端口導向tun
+--------------------------------------------------------+
| +-----+ +----------+ |
| user space | app | |tun2socks |------+ |
| +--|--+ +-^--------+ | |
|-------------------|-----------|---------------|---------
| +--v---+ | | |
| kernel space | tun |-------+ | |
| +---^--+ +---v-----+ |
| | +----------+ | | |
| +-----port forw <------- eth0 | |
| +----------+ | | |
+-------------------------------------------+---------+--+
但我這邊,是想把這個tun2socks作為這個系統 https://www.kskb.eu.org/2021/06/dn42.html 的一個組件,作為layer3和layer4的轉換工具(下圖右上角的tun2socks) 使VPP網路能連接外網(現有tun2socks已能做到),並且暴露VPP裡面的服務給外網(feature request!!!)
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| +--------------------------|-----------------------------------+ |
| | VPP | userspace imeplmentation | |
| +-----------------------+ | +----------------->| Layer 4 of bind() socket() | |
| | exabgp | | | | function | |
| | | | | |-----------------------------------| |
| | +-------------| | | | +--------------+ | |
| | +--- |BGP sessions | | | +--------------> | Route table | layer3 | |
| |+---v----+----------^--| +--------------+ | | | | +--------------+ | +---------------+ +----------+ |
| ||python3-vpp-api| | | | nginx | | | | |------------------------------------ |wireguard-go*2 |--+ |tun2socks |--+ |
| +----|------------------+ ---------------- | +--------+ +--------+ | +-----+ +-----+ +------+ | ----------------- | ------------ | |
| | |ldpreload.so | | ldpreload.so | | |api.sock| |cli.sock| | layer2 |memif| |memif| |memif | | | tap2tun*2 | | | tap2tun | | |
| | +------|------+ +-------|------+ +--+------|-+-+----^---+---|----------+--|--+-+--|--+-+---|--+-+ +-------^-------+ | +--^-------+ | |
| | | | | | | | | | | | | |
|------|-----------|-----------------|---------------------|--------|----------------------------------------------------------------------------------------------------------|
| | | | | | | | | | | | | |
| | +----------------------unix socket------+ | -------------------unix soxket--------------|---------------------- | |
| +------unix socket-------------------------------------------| | v |
| udp direct |
+-------------+ +------------------------------------------+ |
|kernel space | | | eth0 | |
+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |
| |
+----------------+ +--------v--+
| | | |
| DN42 Network | | Clearnet |
| | | |
+----------------+ +-----------+
在這個場景中,我沒有kernel的任何權限,tun0之類的虛擬網卡也沒有註冊在kernel裡面。 唯一用的kernel功能只有unix socket和普通的tcp/udp socket。幾乎所有東西都在userspace完成
tun2socks的tun端被我用libmemif經由tap2tun註冊在VPP裡面,所以也不可能用iptables直接把封包轉送到tun端。而且要捕獲網卡的tcp封包也是要root權限。所以還是只能在tun2socks這端用 bind() 去listen然後送進tun端
qemu在沒有root的情況下,是用SLIRP這個工具來做layer2-layer4的轉換的。layer2端對應VM的虛擬網卡,layer4端則是tun2socks的direct模式,以在沒有root的情況下和使VM上網(vm的kernel跑在主系統的user space,vm裡的網卡也沒註冊進主系統)。slirp也有提供port forward的功能,讓外界可以連線到vm裡面的服務
為甚麼我不用SLIRP而是在這邊提交feature request呢... 是希望有一個go版本的SLIRP可以用,各種編譯問題比C++好處理多了。 還有一個因素是我對layer4-layer3轉換的知識比較不足,一個linux tcp socket的狀態和tcp狀態機的對應和轉換,還有gvisor裡面的處裡邏輯。我可能要重頭開始看。想說博主比我還要更熟悉這塊
如果博主暫時不打算加入此功能,想問問博主有沒有知道go語言實現的其他類似的工具,要搞C++(SLIRP)太痛苦了...
啊我好像明白你的意思了,有点意思🤨
所以如果我没有理解错的话,你FR是不是想增加一个类似-device udp://1270.0.0.1:1234
的UDP套接字来模拟tun
设备,作为L3-L4的入口?
不太一樣, 是L4->L3的入口 -p 9000:192.168.0.1:9000/tcp
L3->L4的部分比較好弄,我去改 https://github.com/xjasonlyu/tun2socks/blob/main/core/device/tun/tun.go ,弄一個tun_vpp之類的就行了,改寫他的Read() Write() function
我目前的理解是這樣(來源網路),L3->L4的原理是中继程式运行一个独立TCP/IP协议栈,並建立一个侦听 “TCP_SYN” 任何地址与端口的虚拟TCP服务器。每當建立一個虛擬服務器,就開一個對外的tcp連接,與之互相通信。也就是博主已經完成的部分
但是L4->L3就觸及我的知識盲區了。我想到可能的工作原理大概是這樣,一樣有userspace的TCP/IP协议栈,並且 listen port 8080。當外部連建立,則運行一個虛擬TCP客戶端,和L3內部這邊的服務器交互
你是想绕过kernel,自己在userspace网络栈上实现tcp状态机?即tcp2raw这样?
假设有这么个东西,那你的SYN包要以什么形式出来,直接发到tun接口上还是以UDP形式封装发给其他端口?
你是想绕过kernel,自己在userspace网络栈上实现tcp状态机?即tcp2raw这样?
是阿,博主的這個專案不是已經用gVisor的TCP/IP协议栈實現了L3->L4的部分了嗎?
假设有这么个东西,那你的SYN包要以什么形式出来,直接发到tun接口上还是以UDP形式封装发给其他端口?
直接发到tun接口。 這個專案的tun接口看上去有在 core/device/tun 作抽象。之後要轉發到UDP還是轉去其他地方,只要改寫 core/device/tun/io_unix.go 裡面的Read和Write就行了對吧?
直接发到tun接口。 這個專案的tun接口看上去有在 core/device/tun 作抽象。之後要轉發到UDP還是轉去其他地方,只要改寫 core/device/tun/io_unix.go 裡面的Read和Write就行了對吧?
不是哦,device抽象的是入口,默认出口是tunnel,即将所有的包重组成至L4然后通过proxy转发。
那你需要的应该是tcp2tun吧🌚,实现不复杂,只是似乎和这个项目没有太大关系了。这样的话就是要么iptables,要么自己造轮子了。
sorry之後忙別的忘記回復
我想說這個專案已經實現了L3->L4的部分,再多實現一個L4->L3,變成一個全功能的L3<->L4轉換器,我就可以直接拿來用
自己實現也可以,我再看看相關資料好了
我說的功能在這邊找到了! https://github.com/KusakabeSi/slirpnetstack
有兩個端,一邊是L2/L3 raw packet,另一邊則是linux tcp/udp session。這隻程式可以做轉換
當Layer 3端收到TCP SYN的時候,就在Layer 4呼叫connect() 系統呼叫 當Layer 4端監聽端口的 accept() 被觸發,就對Layer 3那邊發出TCP SYN 觸發遠端系統的accept()
剛好對應這個的 "local forward" 和 "remote forward" 模式!
可以設置一系列類似這樣的規則,
就會在主機listen udp 1314 等等port,forwarding到tun端對應ip:port
udp無狀態比較好弄些,tcp感覺上比較麻煩。
只有udp也好,加上這個功能也是挺實用的