Skip to content

Conversation

@Owersun
Copy link

@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
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
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
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
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
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
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
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
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
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
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
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 即可

@Fangliding
Copy link
Member

在json写Windows的反斜杠会喜提 C:\\Windows\\System32\\curl.exe 这样的类似物 还有重新引入我想抽象掉的 .exe 后缀

@Owersun
Copy link
Author

Owersun commented Jan 5, 2026

Yeah, about that...
I specifically added TUN only supporting Input, to not make it a security hole (when someone can reach internal network, connecting externally to the place of traffic egress, and making the traffic spill out of TUN).
And as you can guess this contradicts what FullCone is...
I understand that this is perceived as needed for gaming, but in reality there are many network configurations that work the same already, routers prevent returning traffic and so on. So many-many-many games actually have ways to work with restrictive NAT without FullCone.
Before actually implementing anything like that, I would prefer to wait for actual "this specific game is not working, can you have a look?" cases. That will as give real test subject to dissect, as will show how much actually this is needed. As I said, it could turn out that most of games work just fine in the current implementation, because real life internet is already full with similar deployments.
Although I can also try to give it a shot in advance, just need some test cases maybe... I personally don't have anything that didn't work, so I would need some application name to have a subject to fix.

PS. It will take a day or two from me to understand what needs to be added to support ProcessName for routing. I already understand the idea, just need to find out now how to tie it to TUN.

@RPRX
Copy link
Member

RPRX commented Jan 5, 2026

@Fangliding 你测一下 json 5 支持的单引号会不会特殊对待反斜杠吧,总之匹配绝对路径是有用的,需要实现一下

@RPRX
Copy link
Member

RPRX commented Jan 5, 2026

@Owersun FullCone 就是 #237 而已,Xray-core 的其它部分都支持,你可以参考一下 UDP worker 和 Tunnel inbound 的代码

至于测试,用 NatTypeTester 就行

@Fangliding
Copy link
Member

Fangliding commented Jan 5, 2026

没有 还是需要双写
让它支持很简单 现在这个样子还是我把前面剪掉的结果
我想让它有一个 path:/xxx/xxx 或者 path:C:\\xx\\xxx.exe 但是它可能无法识别放在Linux的叫 path: 的可执行文件(虽然99.99%遇不到)/self 糖仍然有效

@RPRX
Copy link
Member

RPRX commented Jan 5, 2026

但是它可能无法识别一个放在Linux根路径的叫 path: 的可执行文件

那不应该是 /path: 吗

@Fangliding
Copy link
Member

脑子有点乱 反正可能有小问题 主要是Linux的可执行文件名字太自由了

可以在文档里强制交代需要写 C:/system/xxx 这样的正斜杠路径 这样就没问题了 但是就不能从文件管理器复制来了 好吧双斜杠版本也不能复制

@RPRX
Copy link
Member

RPRX commented Jan 5, 2026

我的意思就是检测到有斜杠就当绝对路径来匹配,否则就是文件名,如果支持 regex 了可以再参考下 routing 其它部分的语法

@Fangliding
Copy link
Member

找不到比 斜杠+名字 更合适的糖了 Linux只禁止可执行文件使用斜杠或者 \0 我觉得用path: 开头是比较好的 改成只识别斜杠就没法用这个糖了

@RPRX
Copy link
Member

RPRX commented Jan 5, 2026

我查了下 : 这个字符在 Linux 上也是合法的,那就 self/ 吧,反正 Linux & Win 上没文件能叫这名,绝对路径也不会是这个

@RPRX
Copy link
Member

RPRX commented Jan 5, 2026

相对路径没必要支持所以也不冲突

对了还有个文件夹匹配的问题,你看以斜杠结尾的当作文件夹比较方便还是 regex?

@RPRX
Copy link
Member

RPRX commented Jan 5, 2026

总之支持文件夹比支持 regex 有用些,先实现个支持绝对路径和支持文件夹吧,以斜杠结尾的就看作是文件夹

至于 regex,有人需要的话再说吧

@Fangliding
Copy link
Member

那processName得改名process了

@RPRX
Copy link
Member

RPRX commented Jan 5, 2026

那就改名吧,你重开一个 PR,早上喝了酒脑子不清醒没考虑那么多直接给合了

@RPRX
Copy link
Member

RPRX commented Jan 5, 2026

开个脑洞,哎你说我们是不是该做个功能让路由器上的 Xray 也能匹配到电脑上的 process 和手机上的包名

@RPRX
Copy link
Member

RPRX commented Jan 5, 2026

还有对于 TUN 应该有个直接放行 IP packet 的机制而无需走 Xray 的 outbound(当然对于 UDP 也不需要每次都查,就像路由),这样非 TCP/UDP/ICMP 包就不受影响,我感觉隔壁的实现应该是这样,以后的版本再做吧

@Owersun
Copy link
Author

Owersun commented Jan 6, 2026

I tried the local processName based routing with TUN and it is working as intended:
with the config:

  "routing": {
    "rules": [
      {
        "processName": ["curl"],
        "outboundTag": "peer01"
      },
      {
        "processName": ["wget"],
        "outboundTag": "peer02"
      },
      {
        "inboundTag": ["tun"],
        "outboundTag": "peer01"
      }
    ]
  }

the result is

Xray 25.12.8 (Xray, Penetrates Everything.) Custom (go1.25.0 linux/arm64)
A unified platform for anti-censorship.
2026/01/06 11:29:54.391632 [Info] infra/conf/serial: Reading config: &{Name:debug.config.json Format:json}
2026/01/06 11:29:54.399947 [Debug] app/log: Logger started
2026/01/06 11:29:54.403609 [Info] proxy/tun: xray0 created
2026/01/06 11:29:54.406451 [Info] proxy/tun: xray0 up
2026/01/06 11:29:54.407180 [Warning] core: Xray 25.12.8 started
2026/01/06 11:30:48.551287 [Info] [1658994057] proxy/tun: processing connection from: 10.1.9.1:55690
2026/01/06 11:30:48.562884 [Info] [1658994057] app/dispatcher: taking detour [peer01] for [tcp:172.67.168.106:443]
2026/01/06 11:30:48.565257 [Info] [1658994057] transport/internet/tcp: dialing TCP to tcp:<redacted peer01>:443
2026/01/06 11:30:48.566157 [Debug] [1658994057] transport/internet: dialing to tcp:<redacted peer01>:443
2026/01/06 11:30:48.641376 [Info] [1658994057] proxy/vless/outbound: tunneling request to tcp:172.67.168.106:443 via <redacted peer01>:443
2026/01/06 11:30:48.643950 [Debug] [1658994057] proxy: XtlsFilterTls found tls client hello! 1571
2026/01/06 11:30:48.644030 [Debug] [1658994057] proxy: XtlsPadding 1571 166 0
2026/01/06 11:30:48.663350 [Debug] [1658994057] proxy: Xtls Unpadding new block, content 1424 padding 147 command 0
2026/01/06 11:30:48.663408 [Debug] [1658994057] proxy: XtlsFilterTls inconclusive server hello 1163 52
2026/01/06 11:30:48.663932 [Debug] [1658994057] proxy: XtlsFilterTls found tls 1.3! 261 TLS_AES_256_GCM_SHA384
2026/01/06 11:30:48.664976 [Debug] [1658994057] proxy: Xtls Unpadding new block, content 2498 padding 133 command 0
2026/01/06 11:30:48.675754 [Debug] [1658994057] proxy: XtlsPadding 80 1075 0
2026/01/06 11:30:48.676591 [Debug] [1658994057] proxy: XtlsPadding 123 1154 2
2026/01/06 11:30:48.690887 [Debug] [1658994057] proxy: Xtls Unpadding new block, content 544 padding 463 command 2
2026/01/06 11:30:48.691086 [Debug] [1658994057] proxy: CopyRawConn (maybe) readv
2026/01/06 11:30:48.722545 [Info] [1658994057] proxy/tun: connection completed
2026/01/06 11:31:10.418000 [Info] [625660992] proxy/tun: processing connection from: 10.1.9.1:46870
2026/01/06 11:31:10.435449 [Info] [625660992] app/dispatcher: taking detour [peer02] for [tcp:172.67.168.106:443]
2026/01/06 11:31:10.438057 [Info] [625660992] transport/internet/tcp: dialing TCP to tcp:<redacted peer02>:443
2026/01/06 11:31:10.438930 [Debug] [625660992] transport/internet: dialing to tcp:<redacted peer02>:443
2026/01/06 11:31:10.553196 [Info] [625660992] proxy/vless/outbound: tunneling request to tcp:172.67.168.106:443 via <redacted peer02>:443
2026/01/06 11:31:10.555180 [Debug] [625660992] proxy: XtlsFilterTls found tls client hello! 517
2026/01/06 11:31:10.555259 [Debug] [625660992] proxy: XtlsPadding 517 549 0
2026/01/06 11:31:10.614810 [Debug] [625660992] proxy: Xtls Unpadding new block, content 3112 padding 64 command 0
2026/01/06 11:31:10.614905 [Debug] [625660992] proxy: XtlsFilterTls found tls 1.3! 1163 TLS_AES_256_GCM_SHA384
2026/01/06 11:31:10.617878 [Debug] [625660992] proxy: XtlsPadding 6 912 0
2026/01/06 11:31:10.620195 [Debug] [625660992] proxy: XtlsPadding 74 1061 2
2026/01/06 11:31:10.768128 [Debug] [625660992] proxy: Xtls Unpadding new block, content 1020 padding 225 command 2
2026/01/06 11:31:10.768442 [Debug] [625660992] proxy: CopyRawConn (maybe) readv
2026/01/06 11:31:11.776443 [Info] [625660992] proxy/tun: connection completed

So with local processes at least the linux stuff is working as intended (which I suspected it will be, you were saying there is no source information, but actually there is, the TUN connection pass proper source info to the dispatcher).
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, it's just network traffic flowing through the network interfaces (basically the process is linux kernel, but it is not going to be reflected in any way in connection states in /proc/net/tcp).

@Owersun
Copy link
Author

Owersun commented Jan 6, 2026

还有对于 TUN 应该有个直接放行 IP packet 的机制而无需走 Xray 的 outbound(当然对于 UDP 也不需要每次都查,就像路由),这样非 TCP/UDP/ICMP 包就不受影响,我感觉隔壁的实现应该是这样,以后的版本再做吧

I think this needs to be managed on the OS level. Tun is OS network level interface, if anyone want traffic around it (flowing through and out some other network interface), he can configure it on the network level to avoid entering the tun device.
If network traffic enters tun, it's an input to Xray, end of story. If Xray have no routing rule for it, it is dropped, as easy as that.
I think it's fair explanation to provide to users - tun is network level device, people should be able to understand what they are doing, and if they do, they should have no problem to pass traffic they want to go around Xray, around tun of Xray.
Although I think it should be working already just fine with connecting the traffic to "freedom" output, I see no reasons it wouldn't, but it will be an extremely inefficient way of routing network traffic from one interface to the other...

@RPRX
Copy link
Member

RPRX commented Jan 6, 2026

@Owersun IP packet 肯定包含 source 的,我的意思是之前没有在代码中取到它,给你说个方向

非目标流量走 Xray outbound direct 的话有两个问题,一是解包并重新封装 IP packet 以及 inbound->outbound 的开销,二是 direct 出站目前只支持 TCP 和 UDP,我的意思是或许可以用 raw socket 把 IP packet 原样发出,不过这个不急

目前离发版只剩 FullCone 的问题了,实现“按来源二元组路由且五分钟不活跃超时”和“把返回包的源地址写入 UDP”即可

毕竟 TUN 的一大作用就是打游戏

@RPRX
Copy link
Member

RPRX commented Jan 6, 2026

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 通信来传递进程名等信息

@Owersun
Copy link
Author

Owersun commented Jan 6, 2026

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 通信来传递进程名等信息

Yeah, I totally had the same idea yesterday, that to work on the ingress and egress, two Xray peers should be able to exchange the contexts, the client should pass the context to the server. But that sounds like a whole feature to add.

@Owersun
Copy link
Author

Owersun commented Jan 6, 2026

@Owersun IP packet 肯定包含 source 的,我的意思是之前没有在代码中取到它,给你说个方向

非目标流量走 Xray outbound direct 的话有两个问题,一是解包并重新封装 IP packet 以及 inbound->outbound 的开销,二是 direct 出站目前只支持 TCP 和 UDP,我的意思是或许可以用 raw socket 把 IP packet 原样发出,不过这个不急

目前离发版只剩 FullCone 的问题了,实现“按来源二元组路由且五分钟不活跃超时”和“把返回包的源地址写入 UDP”即可

毕竟 TUN 的一大作用就是打游戏

I will have a look at what's needed, what you mentioned, next few days.

@RPRX
Copy link
Member

RPRX commented Jan 6, 2026

话说 Xray outbound 的流量应该会回到 TUN inbound?目前是怎么处理的

@Fangliding
Copy link
Member

很明显似乎并没有人注意到outbound可以手动绑定接口的功能

@RPRX
Copy link
Member

RPRX commented Jan 6, 2026

知道有这个功能,我是问这个 PR 目前是怎么处理的

@RPRX
Copy link
Member

RPRX commented Jan 6, 2026

@Owersun Rebase 446df14

@Owersun
Copy link
Author

Owersun commented Jan 6, 2026

I did merge it to my /tun branch (not rebased).
I can rebase, but I'm afraid then the pull request can get lost, and also there is one external commit for Android not from me that also can get damaged.
So the processName is part of the tun branch, just not as rebase, rather later merge.

Do you want me to do the rebase? Or current state is good enough?

@Owersun
Copy link
Author

Owersun commented Jan 6, 2026

话说 Xray outbound 的流量应该会回到 TUN inbound?目前是怎么处理的

Gvisor replicate ip network stack in both directions, it as convert raw packets into data stream (that then is passed into core for routing), as chop back the returning data to packets that are then sent from the tun device. It's kind of meant to work like this, otherwise it wouldn't work.
But there is no Outbound implementation for tun, I explicitly implemented it as only Inbound, to be used only on client side, and never on server side. There is no reason to use tun device on server side, Xray binary can egress traffic into the OS as a process itself, no special network interface is required for that. Also that prevents from introducing weird loop holes when people can misconfigure it the way, that their egress point allows connecting back to their home network because tun acts as Outbound.
Although nothing prevents from making tun support Outbound mode. It's just not really useful/needed and easily misconfigured...

@Owersun
Copy link
Author

Owersun commented Jan 7, 2026

Ok, I've investigated all the options around NAT and what you call FullCone (which I was calling One-To-One from my network times).
I have few things to say, probably it's going to be long, but please hear me out.

The idea of this tun implementation was targeted to replace workarounds people already are using with Xray - apps like tun2socks and sing-tun. To pass network traffic directly into Xray other ways, than TPROXY. Not "surpass" TPROXY, just give the other way to do that, that people already are using, just with external apps. With similar result, just a little more native, robust and performant. The implementation does exactly that, it serves as Inbound on client side and eliminates several steps happening before, when external app is used. No app in front, no network app-to-app, no input that doesn't know about source of the traffic. Nothing of that, just pure direct traffic->connection into Xray routing. Efficient, performant, informative. This implementation does that very well.
And so, firstly: with this design it places the client, both local or in clients local network, to the same place on network diagram as a home client behind a router is, under Symmetric NAT. 99% of domestic internet/homeowners are working like this, it's one of the widest connection schemes existing. Yes, it's not FullCone/One-To-One NAT, but 99% of applications which need peering found a way to work with that type of NAT, there are several ways to do that. Especially most of the games, where data security is not a big deal. I barely can imagine or remember a game that will fail to establish a group match with Symmetric NAT, there are numerous ways to do that. All of them will work with this TUN implementation just fine.
Secondly, people perceive NAT as some kind of "stateful network firewall" for their local network, protecting them from external connections. This is exactly what symmetric NAT does. And FullCone is going to expose clients behind Xray to the outside world, which can be surprising for some users, and I'm definitely sure will trigger issues...
And finally, the FullCone NAT support is not part of Inbound, it needs to be done at the traffic egress, so it should be a mechanism that Outbounds implement, allowing traffic passing through, by the context, to clients behind. I really don't think you would like to see this pull request becoming huge change/addition to core mechanisms of the Xray, it will be extremely excessive and huge. And most probably if I do that you will have different idea how it should be done ;). Just the way it always is in a collective of developers. It can be done, it should be done at many different places in the app core, it also totally can be done later. Does it really needed to be part of this pull request?..

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.