-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DialerProxy: Fix SplitHTTP H3 dialerProxy #3570
Conversation
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
if err != nil {
return nil, err
}
var packetConn net.PacketConn
switch c := conn.(type) {
......
default:
packetConn = &connWrapper{Conn: conn}
}
return quic.DialEarly(ctx, packetConn, conn.RemoteAddr(), tlsCfg, cfg) type connWrapper struct {
net.Conn
}
func (c *connWrapper) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
n, err = c.Read(p)
return n, c.RemoteAddr(), err
}
func (c *connWrapper) WriteTo(p []byte, _ net.Addr) (n int, err error) {
return c.Write(p)
}
func (c *connWrapper) LocalAddr() net.Addr {
// return some random and unique things
} For the warning in https://github.com/quic-go/quic-go/blob/c40d4ccb7fe00974095f06a7eb5ac00dd62b7f5b/sys_conn_buffers_write.go#L19, just ignore it (or implement a dummy |
Thanks, this does seem cleaner. Howvever, when using the config files from #3560, I still get the same error as before even for a single connection:
removing dialerProxy fixes it |
SplitHTTP H3 不支持 dialerProxy 只是我不小心发现的,实际上似乎没有这样的使用场景,有时间可以先实现 #3560 (comment) |
For Xray-core/transport/internet/dialer.go Line 129 in 2becdd6
Wrong context used? Maybe using the ctx from getHTTPClient is correct.
For a connection issue: I tried with minimal config |
It is true that the dialer doesn't work with splithttp h3, but there is another way to send splithttp h3 outbound to another outbound. {
"dns": {
"hosts": {
"domain:googleapis.cn": "googleapis.com"
},
"servers": [
"8.8.8.8"
]
},
"inbounds": [
{
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true,
"userLevel": 8
},
"sniffing": {
"destOverride": [
"quic",
"http",
"tls"
],
"enabled": true
},
"tag": "socks"
},
{
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {
"userLevel": 8
},
"tag": "http"
},
{
"listen": "127.0.0.1",
"port": 23451,
"protocol": "dokodemo-door",
"settings": {
"address": "ip or domain", // config domain or ip
"port": 443, // config port
"network": "tcp,udp", // udp is required
"timeout": 0,
"userLevel": 8,
"followRedirect": false
},
"tag": "proxytodirect"
}
],
"log": {
"loglevel": "none"
},
"outbounds": [
{
"mux": {
"concurrency": 8,
"enabled": false,
"xudpConcurrency": 8,
"xudpProxyUDP443": "allow"
},
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "127.0.0.1",
"port": 23451,
"users": [
{
"encryption": "none",
"flow": "",
"id": "your-id", // config id
"level": 8,
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "splithttp",
"security": "tls",
"splithttpSettings": {
"host": "your.host", // config host
"path": "/yourpath" // config path
},
"tlsSettings": {
"allowInsecure": false,
"alpn": [
"h3" // quic
],
"fingerprint": "chrome",
"serverName": "your.sni" // config sni
}
},
"tag": "proxy"
},
{
"protocol": "freedom",
"settings": {},
"tag": "direct"
},
{
"protocol": "blackhole",
"settings": {
"response": {
"type": "http"
}
},
"tag": "block"
}
],
"policy": {
"levels": {
"8": {
"connIdle": 300,
"downlinkOnly": 1,
"handshake": 4,
"uplinkOnly": 1
}
},
"system": {
"statsOutboundUplink": true,
"statsOutboundDownlink": true
}
},
"routing": {
"domainStrategy": "AsIs",
"rules": [
// rule to send dokodemo-door to direct.
{
"inboundTag": [
"proxytodirect"
],
"outboundTag": "direct",
"type": "field"
},
// It is important to set DNS and send it to the right outbound (i.e. the second outbound) if you put the domain in the address section of dokodemo-door.
{
"outboundTag": "direct",
"port": "53",
"type": "field"
}
]
},
"stats": {}
}
1- If the second outbound has Mux, it must be xudpProxyUDP443 allow or skip. 2- Pay attention to dns, I explained it in the form of a comment in the code.
|
The discussion is about how to fix it rather than using another way to workaround it. The dialer does work, and dialerProxy will work after applying the changes I mentioned. It is dialer reuse(?) that causes a very basic configuration (without dialerProxy) having connection issues. |
Pay attention to the first paragraph of my comment. I didn't say don't improve dialerproxy! Pay attention to what is written on the xray github page. |
I had to delete another comment of mine. Thanks to @dyhkwong's comments I got it working. But I have a different conclusion:
To reproduce this issue with dialerproxy, do this:
this explains why some workarounds worked:
Anyway, this PR now fixes dialerProxy without affecting QUIC connection reuse. I'm not 100% sure if any other uses of dialerProxy are affected though, and maybe it leaks connections in some other scenario now due to I found that changing to |
GRPC and HTTP use ctx like this, is that your case? Xray-core/transport/internet/grpc/dial.go Lines 122 to 124 in 96e8b8b
Xray-core/transport/internet/http/dialer.go Lines 72 to 74 in 96e8b8b
And can you reproduce the connectivity issue? It even happens without |
@dyhkwong it's pretty interesting. I tried this code snippet now, it seems that it does not fix http3 client reuse (but patching in I was not able to reproduce the general connectivity issue you described earlier. I am inclined to believe it only happens on some systems because there's also tests for this 😅 |
Looks good to me, thanks all! |
* wip * wip * formatting * cnc connection no longer needs to be a Packetconn * dialerProxy: do not cancel connection when Dial context is cancelled
Summary for users: If you have Fragment turned on in v2rayNG and other clients, splithttp+h3 configs may not connect. With this PR, this bug is fixed.
I implemented the suggestions in #3560, but I ran into some difficulties: