Skip to content

Comments

Proxy: Add TUN inbound for Windows & Linux, including Android#5464

Merged
RPRX merged 6 commits intoXTLS:mainfrom
Owersun:tun
Jan 7, 2026
Merged

Proxy: Add TUN inbound for Windows & Linux, including Android#5464
RPRX merged 6 commits intoXTLS:mainfrom
Owersun:tun

Conversation

@Owersun
Copy link
Collaborator

@Owersun Owersun commented Dec 22, 2025

This is implementation of tun network L3 interface as input to the app.

There is README.md in the folder, explaining how the feature works.

Worth to mention on the implementation itself:
This is extremely oversimplified (not in functionality, rather intentionally without excessive complexity) implementation.
There is Linux support only (but the implementation allow to add support for other OS later, if needed). Most probable use case of this feature are router boxes, which mostly are linux based devices.
There are no internal app configuration ways to manage the interface, as network interface is OS level entity. The complication of double routing table or ip rules, or other ways this should be enhanced to work properly, should be managed by OS, to ensure proper integrity with network state of the system. This is explicit decision based on how many different things there are you could do with a network interface in Linux, and adding all of that to be configurable through the app is excessive.
No external additional libraries used, the whole ip stack is gvisor lib, already existing in the app. Tun interface itself is just a file in the system.
OS Level optimisations like GRO/GSO are intentionally disabled, as passing through traffic (forwarded through the interface) anyway is not subject for it. Implementing and always checking and accounting for possible GRO/GSO tables affect performance, not enhance it, in the configuration as a router device. There is very-very-very slim possible advantage for traffic originating from the router itself, which will gain like 0.1% real life performance, but will need like 80% more code to support it.

There were several tests done with different scenarios, all of them used VRAY-XTLS-Reality as uplink.
Normal browsing works just fine, TLS sniffing also works, no issues with that.
Ssh through the interface also worked without any issues, no delays, not lag.
Torrents work just fine.
In one case, test subject managed to run another IPSec (UDP) based VPN on top of that, connecting through Xray, through IPSec commercial VPN to different locations, and then using VoIP and video conferencing apps on top of that, joining several meetings. All that from the country where IPSec VPN is under restricted ban.
I honestly didn't come up with more cases I wanna try after that worked.

With my router based on mediatek mt7986a (banana-pi-r3) I was not able to find traffic top with my 100Mb uplink connection, services like speedtest always load it up to the top.
Although I expect the numbers will not be so extreme when many connections open and close. The cpu profile shows that cpu spikes on connection establishing (routing through the app, forward to uplink and so on), and then it has no problem for traffic flow through same running connection.

All in all, this is very similar implementation to any standalone tun-socks proxy there is, just without excessive complexity, and without necessary app-to-app connection in between, passing packets, converted to connection streams, from the network directly to the app core.

@Fangliding
Copy link
Member

明明有文档站为什么要单独写个README.md

@Owersun
Copy link
Collaborator Author

Owersun commented Dec 22, 2025

Current README explains how the feature is intended to be used.
Sure best place for it would be part of wiki page for Xray-core, it’s just not the part of this repo. It felt a little wrong to open a pull request without explanation of how this intended to be used.

@Fangliding
Copy link
Member

它那么长似乎有的地方不是面向开发而是像文档面向最终用户的?

@Owersun
Copy link
Collaborator Author

Owersun commented Dec 22, 2025

Yes, README included is more an explanation for a user how to utilise the feature.
Although it should be helpful for anyone testing it.
If there is a better place to add user targeted description, tell me where should I move it.
I felt like this README is required to explain why there are no options that any tun-socks proxy is full of

@Fangliding
Copy link
Member

可以解释一下 ConnectionHandler 是做什么的吗 我好像没有看到有关它的逻辑

@Owersun
Copy link
Collaborator Author

Owersun commented Dec 22, 2025

"ConnectionHandler" is an interface with only one function "HandleConnection".
The function is passed as callback to stack implementation, and intended to be called every time stack receive new connection.
In current implementation (gvisor) this function is wrapped in a small function that is passed to gvisor as callback.

gvisor call stack function every time there is new connection (TCP SYN packet or UDP packet that doesn't belong to any stream), stack function map gvisor connection to simple golang net.Conn and pass it to the HandlerConnection. HandleConnection receive net.Conn and destination as input, and simply pass it to the app dispatcher as new connection with the destination. At this stage the net.Conn stream is no different to stream received by any other proxy implementation as result of connect to the proxy. Gvisor is the connection that bridges network packets and net.Conn streams

the usage of this function is on stack_gvisor.go#89

@Fangliding
Copy link
Member

我的意思是 没有其他抽象逻辑 为什么要声明一个接口

@Owersun
Copy link
Collaborator Author

Owersun commented Dec 22, 2025

In case there could be other implementations of the stack, than gvisor.
Yes, there is barely one now, but if there is going to be, it is just going to be stack_whatever.go, that consume same interface "ConnectionHandler" as callback, and bridge it to the different ip stack implementation.
For sure this can be squashed to not exist, but it will save like 10 lines of code?.. In exchange of requiring to put it all back, if there is other implementation than gvisor.
Besides that I tried as I could to replicate how things are done in other parts of the app, I think this approach was taken in how it happens in wireguard. Or maybe how it was in sing-tun, which I researched.

@Fangliding
Copy link
Member

tun.LinuxTun 最后可以被正确调用Close()吗

@Owersun
Copy link
Collaborator Author

Owersun commented Dec 22, 2025

That's a legit thought. Thank you for that.
It will take some time from me to find place to put it, currently all construct functions actually complete, leaving only stack threads running.

@Owersun
Copy link
Collaborator Author

Owersun commented Dec 22, 2025

I reviewed the flow, and it matches other input implementations: there is no "close" that signal proxy input/output handler to finish, so after it is initialised it is never going to shutdown. There is no closing of tun device in wireguard implementation, or any socket cleanup in other implementations.
I've added .Close() calls to cleanup the interface/stack in case of errors returned.
In general the device is properly deregistered from the system by OS when app binary finishes, there is not going to be a dangling tun interface in the system, Linux knows its job related to that.
If there would be any way to hook to core shutting down and register a callback of that event, I can insert cleanup there, but as I wrote, I didn't find any input/output implementation doing that.

@RPRX
Copy link
Member

RPRX commented Dec 23, 2025

This is extremely oversimplified (not in functionality, rather intentionally without excessive complexity) implementation.

这就是 Xray-core 需要的 TUN

Linux 上其实 TPROXY 性能比 TUN 更好,所以如果能把 Windows TUN 一起实现就更好了,今年的 Project X NFT 大奖就是你的了

其实为啥我迟迟不动工 Windows TUN,一是因为麻烦二是因为我不太想让 core 处理 tcp/ip,总是在调研类似于 TRPOXY 的方案,不过 WPF 没有 wintun.dll 这种现成的免费驱动,而如果搞 API HOOK 或 DLL 注入则更麻烦,权限不一定够还可能被判定为外挂

最有希望的是 eBPF on Windows 不过还在测试版又要钱去实名签名,所以我决定两个都要,先整个 wintun.dll 吧 @Owersun

@Owersun
Copy link
Collaborator Author

Owersun commented Dec 23, 2025

Thank you for kind words.

I did omit windows implementation for the same reason you have mentioned. It's complicated, it will require external wuntun.dll, and with all that complexity it barely is going to be used. tun really shines for forwarded traffic, which most of the time is router setup, 99% of which is a linux box. Windows tun implementation will be used by like 1% of enthusiasts and will add 80% of the code to implement. Really bad trade off. Although I made the code extendable enough that it can be added later if there are really going to be people asking. Just don't think initial version must have it.
I did investigate TPROXY before starting with the implementation. It is nice, it is performant, but it doesn't cover everything. e.g. will require quirks to do things like ICMP or multicast. Or encapsulate other protocols like GRE. All in all TPROXY is tcp/udp layer on the level of ip/nf tables where kernel is trying to stitch packets into streams. tun is raw network input that directly pass packets into the app, where gvisor tries to stitch them into streams. Same things, different application levels.
I would say tun is not "next TPROXY", it is additional input type that can be used when needed. Same way e.g. VLESS and xHTTP exist together in the core. They both are for the same thing - to masque the traffic. And one can be used in one case, the other in the other. Same idea here. TPROXY with dokodemo can be great choice on a router with sub 300Hz cpu. Tun can be chosen when a user requires really strange setups.
Once more, the simplification of this implementation (no ways to configure the interface, no support for anything except linux) is not because that's as good as I can do, it's because this should cover 80% of use cases with really clean feature. And then always can be further enhanced to support android/macos/windows(maybe)/... and so on.

@Fangliding
Copy link
Member

Windows TUN是无和有的区别 而Linux TUN vs Linux tproxy 是性能和配置是否麻烦的事(

@Owersun
Copy link
Collaborator Author

Owersun commented Dec 23, 2025

Sure, I'll have a look how other apps does that for Windows.
In my initial research it was all looking as "no thank you".
It will take some time, since I really have not a single windows machine, I'll need to roll a virtual machine and take a look how windows look in 2025. It's been a long time.
by the way, the wireguard implementation doesn't have windows tun, probably for the same reason.

@Zerogoki00
Copy link

Zerogoki00 commented Dec 23, 2025

@Owersun

Windows tun implementation will be used by like 1% of enthusiasts and will add 80% of the code to implement

not really, for example sing-box also has a tun interface and it's actively used on Windows in many GUI proxy clients. Having a cross-platform tun interface would be very nice for xray, because there will be no need for double setup of xray <--> sing-box or tun2proxy for system-wide tunneling on windows

@Owersun
Copy link
Collaborator Author

Owersun commented Dec 23, 2025

Sure thing. As I said - this is initial implementation I made as MVP (minimal viable product). I tried to do it as clean as possible, so that the idea is clear. And extendable at the same time.
The plan was that windows support can be added later if needed.
I already see in this topic that windows tun support is demanded feature, so I did agree I'll add it in. I'm already looking at it (although it will take some time from me because of holiday season).
I just want to warn everyone that windows support will add like three times more code that there is now in the pull request. It will be really more complicated to review.

@yuhan6665
Copy link
Member

Thanks @Owersun for your great work!
I have a question for Android, I see you define a tun interface and currently Android is excluded. I'm one of the author of Android app v2rayNG, I wonder if the tun inbound can work with the Android VPN service and what work would be needed to support it.

Currently, we need to spin off a separate tun2socks process like the following https://github.com/2dust/v2rayNG/blob/master/V2rayNG/app/src/main/java/com/v2ray/ang/service/Tun2SocksService.kt#L35

@Owersun
Copy link
Collaborator Author

Owersun commented Dec 27, 2025

To make it work on Android it require literally 1 line change.
Android is Linux, only the device to clone to make new interface is at /dev/tun instead of /dev/net/tun.
As I was saying, my goal was to introduce base, most useful system, and then start adding more support.
Android is the easiest to add, I can take a look at it (what happens when it is enabled, how the interface behave), after I'm done with Windows.

@yuhan6665
Copy link
Member

Guys, I have some good news. I try to pass the Android VPN service fd to the core and it is working with initial testing on v2rayNG!
That means we will be able to use Core's Tun soon, instead of badvpn-tun2socks or hev-socks5. cc @2dust

This is an important step towards one-core-fits-all and it will simplify many use cases. My suggestion is that we accept the PR now and work on Windows and other improvements later. @RPRX @Fangliding

@Fangliding
Copy link
Member

它的效率能比hev高吗(
我之前没有在意Android平台 因为觉得Android平台上还是专门去弄可能好点
以及可能的udp问题(

@Owersun
Copy link
Collaborator Author

Owersun commented Dec 28, 2025

I'm glad that it turned out to be easily usable, that was the whole idea.

With Windows I honestly done with the implementation, but it just look horrible... With external wintun.dll required (all other apps wireguard-go/sing-tun/etc. do that the same way), with problems with ipv6, and with a lot internal memory allocation (although this doesn't affect speed much).
I am at the process of making it not horrible as minimal version, but windows is really sad OS for network handling.

@yuhan6665
Copy link
Member

它的效率能比hev高吗( 我之前没有在意Android平台 因为觉得Android平台上还是专门去弄可能好点 以及可能的udp问题(

效率是一码事 全 go stack 是另一码事 所以 v2rayNG 搞了可选的 tun (现在是俩选项 我准备加第三个)
将来甚至可能搞 process 分流啥的

@Fangliding
Copy link
Member

Fangliding commented Dec 28, 2025

Android编译是后来加的 其他安卓客户端用的是 Linux arm64编译吧 不知道这样会不会有问题
还有那个Android编译还有小问题 #4772

@2dust
Copy link

2dust commented Dec 29, 2025

Guys, I have some good news. I try to pass the Android VPN service fd to the core and it is working with initial testing on v2rayNG! That means we will be able to use Core's Tun soon, instead of badvpn-tun2socks or hev-socks5. cc @2dust

This is an important step towards one-core-fits-all and it will simplify many use cases. My suggestion is that we accept the PR now and work on Windows and other improvements later. @RPRX @Fangliding

如果能实现,v2rayNG 将移除 badvpn-tun2socks ,只保留 xray tun 和 hev tun 即可

@RPRX RPRX merged commit 39ba1f7 into XTLS:main Jan 7, 2026
38 of 39 checks passed
@RPRX
Copy link
Member

RPRX commented Jan 7, 2026

那就先合了,感谢 PR,我去研究一下 TUN inbound 的 FullCone

@RPRX
Copy link
Member

RPRX commented Jan 7, 2026

@Fangliding 可以开始更新下个版本的文档了

@RPRX
Copy link
Member

RPRX commented Jan 7, 2026

@RPRX
Copy link
Member

RPRX commented Jan 7, 2026

提前发表一下感想吧,我几乎不会说什么利于团结的话,不过这次真的是有感而发:通过本次对 TUN 的支持我看到了 Xray 生态的生机勃勃万物竞发和 Xray 团队的通力合作,first-time-contributor @Owersun 实现了 TUN,@yuhan6665 完善了 Android 支持,@Fangliding 添加了进程名/绝对路径/文件夹路由,@KobeArthurScofield 更新了 CI 为 Windows 添加了 wintun.dll,每个人都及时贡献了自己最擅长的部分,共同完成了本次对 TUN 的支持,至于我干了什么,我一直在 vibe,啊不是晚点还有 FullCone

我不觉得这不如“一个人完成所有方面”,恰恰相反我觉得这才是最健康、长久的模式,有人说 Xray 是靠 PR 来活着的,以前是这样,以后还会是,Xray 最宝贵的资源或许不在于那些原创协议,而是在于各个方面的贡献者以及对新 contributor 的吸引力

说回 TUN,如今 Xray 加了它,对 end-user 来说可能没太大区别,毕竟各个客户端早就有了自己的 tun->socks 方案(这就是为什么 TUN 在我计划中的优先级很低),但是自有 TUN 对于接下来的 Xray-only 官方客户端来说至关重要,提前扫除了一大障碍

@CN-CODEGOD
Copy link

感谢

@CN-CODEGOD
Copy link

wintun - Windows 里用户的?

@arror
Copy link

arror commented Jan 8, 2026

sniffing配置不顺带支持下嘛

@mehdifirefox
Copy link

提前发表一下感想吧,我几乎不会说什么利于团结的话,不过这次真的是有感而发:通过本次对 TUN 的支持我看到了 Xray 生态的生机勃勃万物竞发和 Xray 团队的通力合作,first-time-contributor @Owersun 实现了 TUN,@yuhan6665 完善了 Android 支持,@Fangliding 添加了进程名/绝对路径/文件夹路由,@KobeArthurScofield 更新了 CI 为 Windows 添加了 wintun.dll,每个人都及时贡献了自己最擅长的部分,共同完成了本次对 TUN 的支持,至于我干了什么,我一直在 vibe,啊不是晚点还有 FullCone

我不觉得这不如“一个人完成所有方面”,恰恰相反我觉得这才是最健康、长久的模式,有人说 Xray 是靠 PR 来活着的,以前是这样,以后还会是,Xray 最宝贵的资源或许不在于那些原创协议,而是在于各个方面的贡献者以及对新 contributor 的吸引力

说回 TUN,如今 Xray 加了它,对 end-user 来说可能没太大区别,毕竟各个客户端早就有了自己的 tun->socks 方案(这就是为什么 TUN 在我计划中的优先级很低),但是自有 TUN 对于接下来的 Xray-only 官方客户端来说至关重要,提前扫除了一大障碍

Our Iranian international internet will be cut off today. And we, the people, do not have any suitable solution. Think about us

@RPRX
Copy link
Member

RPRX commented Jan 8, 2026

@mehdifirefox 不知道你是英语不好还是,你这说的意思像是我干了啥导致了 cut off 一样,不是你们最近在街头搞革命导致的吗

CDN 企业还有国际联网的话可以用 XHTTP

@RPRX
Copy link
Member

RPRX commented Jan 9, 2026

@copilot 根据这个 PR 内的讨论,并参考其它 inbound 的代码为 TUN 实现 FullCone,针对 main 分支发起 PR

@RPRX
Copy link
Member

RPRX commented Jan 9, 2026

无反应,我在 #4292 发试试

@RPRX RPRX mentioned this pull request Jan 9, 2026
4 tasks
@MoRanYue
Copy link

MoRanYue commented Jan 9, 2026

@mehdifirefox your country's gov is shameless, doing the thing similar to CCP.

@RPRX
Copy link
Member

RPRX commented Jan 10, 2026

@Owersun #5509 (comment)

@RPRX
Copy link
Member

RPRX commented Jan 10, 2026

sniffing配置不顺带支持下嘛

这个是 dispatcher 内自动调用的,应该本来就支持吧,@Fangliding 你看下

@RPRX
Copy link
Member

RPRX commented Jan 10, 2026

wintun - Windows 里用户的?

不知道你问的是什么,但 TUN 是要管理员权限才能用的

@RPRX
Copy link
Member

RPRX commented Jan 10, 2026

@Fangliding 看一下是否支持 sniffing,它和 mux 好像是 worker 那边注入 ctx 的但是 TUN inbound 似乎不基于 worker

@Fangliding
Copy link
Member

@Fangliding 看一下是否支持 sniffing,它和 mux 好像是 worker 那边注入 ctx 的但是 TUN inbound 似乎不基于 worker

对 它没有注入嗅探请求 但是不应该影响其他路由

@yuhan6665
Copy link
Member

With remote connections (when Xray is on a router, serving/forwarding connections arriving from the network behind the router) - there is never going to be a process name, because there is no originating process

关于这一点,我的意思是以后可以做个高级功能来实现,两个 Xray 通信来传递进程名等信息

instead of passing process info for every new connection, why not pass the routing config, once, and the Xray running on the device would perform the routing

@EbrahimTahernejad
Copy link

EbrahimTahernejad commented Jan 30, 2026

is there a reason you marked the android tun for android only? doesn't the ios tun work the same assuming we have the tun fd?

@Owersun
Copy link
Collaborator Author

Owersun commented Jan 30, 2026

is there a reason you marked the android tun for android only? doesn't the ios tun work the same assuming we have the tun fd?

tun is OS network interface, Android is Linux based OS, iOS is heavily modified Darwin OS, they require completely different approach for creating/working with network interfaces. They are not the same at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.