XTLS / Xray-core

Xray, Penetrates Everything. Also the best v2ray-core, with XTLS support. Fully compatible configuration.
https://t.me/projectXray
Mozilla Public License 2.0
24.57k stars 3.84k forks source link

[Feature suggestion & draft] Redesigned browser dialer #3840

Open PoneyClairDeLune opened 1 week ago

PoneyClairDeLune commented 1 week ago

A continuation of #3832. Aimed at maximizing throughput and minimizing resource consumption on the browser side, and also potentially allowing arbitrary headers with the browser dialer.

Prerequisites

This draft is designed with the following assumptions.

Design

Still not fleshed out. Critiques are welcomed!

Web routes

WS /control

The control plane. This is the only place where any form of processing can happen with all possible latest web features. Xray can command the browser dialer on what and how to connect through it. If request bodies from Meek-like transports are not streamed, this should also carry the body of the request.

Message structure
Byte length Required? Use
4 (uint32) Y Length of payload. MSB to eliminate uncertainty of endianness with a somewhat fast implementation, or LSB to maximize speed. Should always be 0 for WebSocket connections and streamed web requests.
variable Y JSON-encoded command.
variable N Raw payload. Currently only used by non-streamed requests to post to remote.
Commands
{
    "m": "WS", // Method, can be "WS", "GET" or "POST"
    "p": "", // A string or an array of strings for expected **WebSocket** protocols
    "r": "", // Remote URL
    "i": 65535, // A numerical (positive integer) or a web-safe random string ID to distinguish connections
    "h": {} // A map of non-restricted custom headers to send to the server, cannot be used for WebSocket
}

WS /data?id=<socketId>

For Chrome 124 and later. Where contents of WebSocket connections are passed through without any processing.

WebSocketStream - MDN

GET/POST /data?id=<socketId>

For Chrome 105 and later. Where contents of all web-compliant connections are passed through without any processing. Has the exact same use as above, only that for each duplex connection, a get-post pair is created due to browsers refusing to support HTTP/2 cleartext.

Send ReadableStream in request body - caniuse.com

Browser-side behaviour

Criteria WebSocket behaviour
WebSocketStream WebSocketStream pass-through 1
Anything else Iterated WebSocket
Criteria Meek-like behaviour
Chrome 105+ Request stream pass-through
Anything else Iterated bodies (memory leak)
RPRX commented 6 days ago

https://github.com/XTLS/Xray-core/pull/3832

And somehow the browser dialer of SplitHTTP is implemented via WebSocket instead of fetch request in either direction.

关于这个我想起来了,因为初版 browser dialer 写于 2021 年,而 chromium 在 2022 年才支持 streaming requests with fetch

并且 websocket 没有任何同源限制,不过问题不大,https://github.com/XTLS/Xray-core/pull/3830 加了跨域 header 就没问题了,话说加跨域 header 前竟然也能用

RPRX commented 6 days ago

刚又仔细看了一眼发现自己已读乱回了

PoneyClairDeLune commented 2 days ago

https://github.com/XTLS/Xray-core/blob/main/transport/internet/browser_dialer/dialer.go#L35

Went through the Go code for the browser dialer today. Not sure what purpose does the CSRF token serve, but if they're utilized to reject local scanning initiated from websites, an origin filter should suffice. Suppose a random website initiates a WebSocket connection to the browser dialer, but no matter how they try, the Origin header will always be set, thus the same effect could be achieved by simply rejecting WebSocket connections with a mismatched Origin header.


Another thought: Maybe the browser dialer page could benefit from some visual overhaul...