
代碼在Github上的鏈接:edgetunnel/src/worker-vless.js at main · zizifn/edgetunnel (github.com)
丟給ChatGPT他的解釋這段代碼的用途:
這段代碼是一個 Cloudflare Worker,它是用於處理 WebSocket 請求的。讓我們來逐一解釋代碼中的不同部分:
- 開頭註解:
- 這些是用來描述版本和時間戳的註解,並未對程式碼功能有直接影響。
import
與@ts-ignore
:import { connect } from 'cloudflare:sockets';
:導入 Cloudflare Worker 中提供的connect
方法,用於建立 WebSocket 連接。@ts-ignore
:TypeScript 的忽略註解,忽略以下代碼中可能出現的型別檢查錯誤。
- UUID 驗證與設定:
- 定義了一個 UUID (Universally Unique Identifier),並檢查它是否為有效的 UUID。
- 如果 UUID 無效,會拋出一個錯誤。
export default
:- 定義一個 Cloudflare Worker 的主要函式
fetch
,用於處理傳入的 HTTP 請求。 - 該函式接收三個參數:
request
(請求物件)、env
(環境變數)、ctx
(執行上下文)。 - 根據不同的條件,函式會回傳不同的
Response
物件。
- 定義一個 Cloudflare Worker 的主要函式
fetch
函式:- 這個函式是用於處理 HTTP 請求的主要邏輯。
- 首先會檢查請求是否為 WebSocket 升級請求,如果不是則根據路徑回傳不同的回應。
- 如果是 WebSocket 升級請求,則調用
vlessOverWSHandler
函式處理 WebSocket 的數據交換。
vlessOverWSHandler
函式:- 這個函式處理 WebSocket 升級後的數據交換。
- 依據數據包的內容,可能會建立一個 TCP 或 UDP 的連接,然後進行數據的轉發。
- 如果是 DNS 的 UDP 請求,會轉發到 1.1.1.1 服務進行解析。
- 其他輔助函式:
handleTCPOutBound
、makeReadableWebSocketStream
、processVlessHeader
等都是用於處理 WebSocket 和 Socket 的數據傳輸。base64ToArrayBuffer
、isValidUUID
等是輔助函式,用於處理 UUID 字串和 Base64 轉換。
總體來說,這個代碼看起來是一個 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 連接後,
vlessOverWSHandler
函式開始運行。 - 這個函式接收一個 WebSocket 物件 (
webSocket
) 作為參數,這是客戶端與伺服器之間建立的 WebSocket 連接。 - 一開始,會建立一個用於 UDP 數據處理的
TransformStream
並設置相應的回調函式。
接收 WebSocket 資料:
vlessOverWSHandler
函式監聽客戶端發送的消息,並處理收到的數據。- 當從客戶端接收到 WebSocket 消息時,它會通過
message
事件來觸發,然後讀取消息的數據。
數據處理:
vlessOverWSHandler
函式會檢查收到的 WebSocket 消息是否為 DNS 的 UDP 請求,如果是,則進行 DNS 解析。- 如果不是 DNS 的 UDP 請求,則根據消息內容的不同進行相應的處理。具體處理方式取決於傳送的 VLESS 協議內容。
UDP 數據處理:
- 當收到的數據是 DNS 的 UDP 請求時,
vlessOverWSHandler
函式會將數據傳遞給TransformStream
,進行數據轉換。 - 轉換流程是將 UDP 資料包拆分為多個單獨的 UDP 消息,並分別進行處理。
- 每個 UDP 消息都會發送到
fetch
函式,該函式會將該消息發送到 1.1.1.1 DNS 服務器進行解析。
回應數據:
- 當 DNS 解析完成後,
vlessOverWSHandler
函式會獲得 DNS 解析結果的 UDP 回應數據。 - 將回應數據封裝為 UDP 資料包,然後將其返回給 WebSocket 客戶端。
WebSocket 關閉處理:
- 在整個處理過程中,
vlessOverWSHandler
函式會監聽 WebSocket 的狀態變化,特別是關閉事件。 - 如果 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连接并转发数据。
函数的工作原理如下:
函数参数:
handleTCPOutBound
函数接受多个参数,包括remoteSocket
表示已连接到目标服务器的远程 TCP Socket 对象,addressRemote
表示目标服务器的地址,portRemote
表示目标服务器的端口号,rawClientData
表示客户端发送的原始数据,webSocket
表示 WebSocket 对象,vlessResponseHeader
表示 VLESS 协议的响应头部信息,以及log
表示用于输出日志的函数。
建立远程连接:
- 首先,函数通过
connectAndWrite
函数建立到目标服务器的远程 TCP 连接。该函数会返回一个新的tcpSocket
对象,代表已建立的连接。
转发数据:
- 一旦远程连接建立完成,函数将客户端发送的原始数据
rawClientData
转发到该连接中,从而将数据发送到目标服务器。
监听远程 Socket 数据:
- 接着,函数会监听远程 Socket 的数据流,并将收到的数据转发到 WebSocket 连接中,从而将目标服务器的响应数据返回给客户端。
WebSocket 关闭处理:
- 在整个处理过程中,函数还会监听 WebSocket 的状态变化,特别是关闭事件。如果 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