代码在Github上的链接:edgetunnel/src/worker-vless.js at main · zizifn/edgetunnel (github.com)
丢给ChatGPT他的解释这段代码的用途:
这段代码是一个 Cloudflare Worker,它是用於处理 WebSocket 请求的。让我们来逐一解释代码中的不同部分:
- 开头注解:
import
与@ts-ignore
:- UUID 验证与设定:
export default
:fetch
函式:vlessOverWSHandler
函式:- 其他辅助函式:
总体来说,这个代码看起来是一个 WebSocket 的代理伺服器,可以在 Cloudflare Worker 环境中运行。它处理进来的 HTTP 请求,并在需要时建立 WebSocket 连接,将数据转发到後端伺服器或其他服务器上。根据需要,它还支援对 DNS 的 UDP 请求进行转发。
摘要节点
ProxyIP的作用?
当我们查看代码时,可以发现 proxyIP
是一个空字串,它被定义在代码的开头:
let proxyIP = '';
在後续代码中,proxyIP
的值会被设定为 env.PROXYIP
或保持不变,取决於是否存在 env.PROXYIP
:
proxyIP = env.PROXYIP || proxyIP;
这里,env
是一个代表环境变数的物件。根据代码中的注释,它是在 fetch
函式的参数中传入的:
async fetch(request, env, ctx) { ... }
因此,env
应该是一个包含了一些环境设定的物件。env.PROXYIP
似乎是这个物件中的一个属性,用於指定代理 IP。
总的来说,proxyIP
这个变数的作用是用来存储代理伺服器的 IP 地址。如果在 env
中提供了 PROXYIP
,则会将该值赋给 proxyIP
,否则 proxyIP
的值保持不变。使用 proxyIP
变数可以方便地在後续代码中引用代理 IP,以便在需要时使用。
vlessOverWSHandler 这个function是的运作原理
vlessOverWSHandler
函式是用於处理 WebSocket 升级後的数据交换。它处理了从客户端传递过来的 WebSocket 资料,并根据数据的不同进行相应的处理。
让我们逐步解释 vlessOverWSHandler
函式的运作:
开始处理:接收 WebSocket 资料:数据处理:UDP 数据处理:
回应数据:
WebSocket 关闭处理:
总体来说,vlessOverWSHandler
函式在 WebSocket 升级後负责处理数据传输。根据数据内容,它可能建立 TCP 或 UDP 连接,然後进行数据的转发。如果收到 DNS 的 UDP 请求,它会将该请求发送到 1.1.1.1 DNS 服务器进行解析,然後将解析结果返回给 WebSocket 客户端。
如果 vlessOverWSHandler
接收到的是 TCP 数据,它会进行以下处理:
- 解析 VLESS 协议头部:
首先,它会解析收到的 TCP 数据中的 VLESS 协议头部,以了解目标地址和端口等信息。 - 创建 TCP 连接:
接下来,vlessOverWSHandler
会根据 VLESS 协议头部中的目标地址和端口信息,建立一个新的 TCP 连接。它会向目标地址和端口发送数据,将接收到的 TCP 数据转发到该 TCP 连接。 - 转发数据:
一旦新的 TCP 连接建立完成,vlessOverWSHandler
会将接收到的 TCP 数据转发到该连接中,这样数据就能够正确地发送到目标服务器。 - WebSocket 关闭处理:
在整个处理过程中,vlessOverWSHandler
函式会监听 WebSocket 的状态变化,特别是关闭事件。如果 WebSocket 关闭,则相应地处理数据流程,确保正确地关闭数据传输。
总的来说,如果 vlessOverWSHandler
接收到的是 TCP 数据,它会根据 VLESS 协议头部中的目标地址和端口信息,建立一个新的 TCP 连接,然後将接收到的 TCP 数据转发到该连接中,最终将数据正确地发送到目标服务器。这样,它能够处理 WebSocket 传输中的 TCP 数据流量。
handleTCPOutBound 的运作原理
handleTCPOutBound
函数的作用是处理出站(Outbound)TCP连接,即建立到目标服务器的TCP连接并转发数据。
函数的工作原理如下:
函数参数:
建立远程连接:
转发数据:
监听远程 Socket 数据:
WebSocket 关闭处理:
总体而言,handleTCPOutBound
函数的工作原理是建立到目标服务器的远程 TCP 连接,然后将客户端发送的原始数据转发到目标服务器,再将目标服务器的响应数据转发回客户端。这样,它能够处理 WebSocket 传输中的 TCP 数据流量。
在 handleTCPOutBound
函数中,转发数据和监听远程 Socket 数据是通过以下几个部分的代码实现的:
- 转发数据:
在handleTCPOutBound
函数的write
方法中,将客户端发送的原始数据rawClientData
转发到已建立的远程 TCP 连接tcpSocket
中。具体实现代码如下:
async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log) { // ... 其他代码 ... // 转发数据到远程 Socket const writer = tcpSocket.writable.getWriter(); await writer.write(rawClientData); writer.releaseLock(); // ... 其他代码 ... }
- 监听远程 Socket 数据:
在handleTCPOutBound
函数中,通过tcpSocket.readable
的pipeTo
方法来监听远程 Socket 的数据流,并将收到的数据转发到 WebSocket 连接中,从而将目标服务器的响应数据返回给客户端。具体实现代码如下:
async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log) { // ... 其他代码 ... // 监听远程 Socket 数据,并将数据转发到 WebSocket 连接中 remoteSocket.readable.pipeTo(new WritableStream({ async write(chunk, controller) { if (webSocket.readyState !== WS_READY_STATE_OPEN) { controller.error('webSocket.readyState is not open, maybe close'); } webSocket.send(chunk); }, close() { log(`remoteConnection!.readable is close with hasIncomingData is ${hasIncomingData}`); // safeCloseWebSocket(webSocket); // no need server close websocket first for some case will cause HTTP ERR_CONTENT_LENGTH_MISMATCH issue, client will send close event anyway. }, abort(reason) { console.error(`remoteConnection!.readable abort`, reason); }, })).catch((error) => { console.error(`remoteSocketToWS has exception`, error.stack || error); safeCloseWebSocket(webSocket); }); // ... 其他代码 ... }
在这两个部分中,handleTCPOutBound
函数分别将数据从客户端转发到远程 Socket(目标服务器)以及从远程 Socket 转发到 WebSocket 连接,实现了数据的转发和监听功能。这样,数据能够在客户端、目标服务器和 WebSocket 之间传递,实现了 TCP 数据的传输和响应。
makeReadableWebSocketStream 是干什麽的?
makeReadableWebSocketStream
是一个函数,它的作用是创建一个可读的 WebSocket 流(ReadableStream)。
在 WebSocket 中,可以通过 addEventListener
监听 message
事件来接收来自客户端的数据。然而,message
事件在接收到数据后只会触发一次,无法实现数据流的持续传输。makeReadableWebSocketStream
函数的目的是将 WebSocket 的数据流封装为一个可读流,以便能够通过流式数据传输的方式处理客户端的数据,并且在客户端发送更多数据时,能够持续触发数据传输。
函数的实现原理如下:
- 创建可读流:
函数首先通过new ReadableStream()
创建一个可读流对象stream
。 - 注册事件监听器:
在可读流的start
回调函数中,函数会通过addEventListener
监听 WebSocket 的message
事件。一旦接收到客户端发送的数据,该事件会触发并将数据添加到可读流中。 - 数据传输:
在可读流的transform
回调函数中,函数会将接收到的 WebSocket 数据转换为可读流的数据,并通过controller.enqueue
方法将数据添加到可读流中。这样,在 WebSocket 有新数据到来时,transform
回调函数会被调用,从而触发数据传输。 - WebSocket 关闭处理:
函数还会监听 WebSocket 的状态变化,特别是关闭事件。一旦 WebSocket 关闭,cancel
回调函数会被调用,函数会相应地关闭数据传输。
通过这种方式,makeReadableWebSocketStream
函数实现了将 WebSocket 的数据流封装为可读流的功能,使得可以通过流式传输的方式处理客户端的数据,从而能够持续地接收客户端的数据并作出相应的处理。
processVlessHeader 是干什麽的?
processVlessHeader
是一个函数,它的作用是解析 VLESS 协议的头部信息。
在 VLESS 协议中,数据流的开头包含了一些特定的字段,用于标识数据的类型和其他相关信息。processVlessHeader
函数接收一个 ArrayBuffer 参数 vlessBuffer
,该参数是从客户端发送的数据流中提取的 VLESS 协议头部信息。函数会解析该头部信息,提取出其中的字段,以便后续对数据进行处理。
具体来说,processVlessHeader
函数的工作原理如下:
- 解析数据类型和用户验证:
函数首先从vlessBuffer
中解析出数据类型(TCP 或 UDP)以及用户验证信息(UUID)。这里需要注意的是,VLESS 头部信息的前 17 个字节包含了 UUID,用于验证用户身份。如果解析出的 UUID 与预设的userID
不匹配,说明该用户不合法。 - 解析其他信息:
接下来,函数会解析其他的 VLESS 头部信息,包括可选字段的长度和字段值。目前,函数只关心数据类型为 UDP 时的处理,因为数据类型为 TCP 或 MUX 时不需要做特殊处理。 - 提取目标服务器地址和端口:
当数据类型为 UDP 时,函数会提取出目标服务器的地址(IPv4 或 IPv6)和端口号,以便后续转发 UDP 数据包。 - 返回解析结果:
最后,函数会返回一个包含解析结果的对象。如果解析过程中出现错误或数据格式不合法,函数会在返回的对象中标记出错信息。如果解析成功,返回的对象包含了目标服务器的地址、端口号以及其他相关信息,用于后续的数据转发和处理。
总体而言,processVlessHeader
函数在 VLESS 协议的数据流中提取出相关的信息,以便后续根据这些信息来进行数据的处理和转发。这个函数在整个 VLESS 协议的实现中起到了关键的作用。
remoteSocketToWS 是干什麽的?
remoteSocketToWS
是一个函数,它的作用是将来自远程服务器的数据流转发到 WebSocket 客户端。
在 VLESS 协议中,数据流是从远程服务器返回给本地客户端的。而本地客户端与服务器之间是通过 WebSocket 连接通信的。remoteSocketToWS
函数负责将远程服务器返回的数据流转发到 WebSocket 客户端,以便客户端能够接收到实时的数据并做相应的处理。
函数的实现原理如下:
- 数据转发:
函数通过remoteSocket
的readable
属性来获取可读流,这个可读流是从远程服务器读取数据的。然后,通过pipeTo
方法将远程服务器的数据流与 WebSocket 的数据流相连接,实现数据的转发。 - WebSocket 传输:
在转发数据的过程中,函数会检查 WebSocket 的状态,只有在 WebSocket 连接处于打开状态(WS_READY_STATE_OPEN
)时,才会将数据发送给客户端。 - 关闭处理:
函数会监听remoteSocket
的关闭事件,当远程服务器的连接关闭时,会执行相应的关闭处理,并调用safeCloseWebSocket
函数关闭 WebSocket 连接,避免出现异常。
总体来说,remoteSocketToWS
函数是 VLESS 协议中数据转发的关键部分,它负责将远程服务器返回的数据转发给 WebSocket 客户端,实现了客户端与服务器之间的实时数据传输。
remoteSocketToWS
函数并没有在转发数据时添加 VLESS 协议的头部信息。实际上,该函数是用于处理 UDP 数据的转发,而 VLESS 协议的头部信息是在客户端发起 WebSocket 请求时添加的。
在 VLESS 协议中,客户端在发起 WebSocket 连接时会携带特定的查询参数或者在 WebSocket 握手时发送特定的数据来表明使用 VLESS 协议。服务器在收到客户端的请求后,会根据请求中携带的信息来识别并处理 VLESS 协议的数据。
因此,在 remoteSocketToWS
函数中并没有添加 VLESS 协议的头部信息,而是在 WebSocket 握手阶段或客户端发起请求时添加的。该函数只负责将远程服务器返回的数据转发给 WebSocket 客户端,并不处理具体的协议头部信息。
https://chat.openai.com/share/75559006-a870-4d1f-9516-51c1f9487cf5