利用Cloudflare Worker部署VLESS翻牆代理的代碼學習:Zizifn’s edgetunnel repo

代碼在Github上的鏈接:edgetunnel/src/worker-vless.js at main · zizifn/edgetunnel (github.com)

丟給ChatGPT他的解釋這段代碼的用途:

這段代碼是一個 Cloudflare Worker,它是用於處理 WebSocket 請求的。讓我們來逐一解釋代碼中的不同部分:

  1. 開頭註解:
    • 這些是用來描述版本和時間戳的註解,並未對程式碼功能有直接影響。
  2. import@ts-ignore
    • import { connect } from 'cloudflare:sockets';:導入 Cloudflare Worker 中提供的 connect 方法,用於建立 WebSocket 連接。
    • @ts-ignore:TypeScript 的忽略註解,忽略以下代碼中可能出現的型別檢查錯誤。
  3. UUID 驗證與設定:
    • 定義了一個 UUID (Universally Unique Identifier),並檢查它是否為有效的 UUID。
    • 如果 UUID 無效,會拋出一個錯誤。
  4. export default
    • 定義一個 Cloudflare Worker 的主要函式 fetch,用於處理傳入的 HTTP 請求。
    • 該函式接收三個參數:request (請求物件)、env (環境變數)、ctx (執行上下文)。
    • 根據不同的條件,函式會回傳不同的 Response 物件。
  5. fetch 函式:
    • 這個函式是用於處理 HTTP 請求的主要邏輯。
    • 首先會檢查請求是否為 WebSocket 升級請求,如果不是則根據路徑回傳不同的回應。
    • 如果是 WebSocket 升級請求,則調用 vlessOverWSHandler 函式處理 WebSocket 的數據交換。
  6. vlessOverWSHandler 函式:
    • 這個函式處理 WebSocket 升級後的數據交換。
    • 依據數據包的內容,可能會建立一個 TCP 或 UDP 的連接,然後進行數據的轉發。
    • 如果是 DNS 的 UDP 請求,會轉發到 1.1.1.1 服務進行解析。
  7. 其他輔助函式:
    • handleTCPOutBoundmakeReadableWebSocketStreamprocessVlessHeader 等都是用於處理 WebSocket 和 Socket 的數據傳輸。
    • base64ToArrayBufferisValidUUID 等是輔助函式,用於處理 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 數據,它會進行以下處理:

  1. 解析 VLESS 協議頭部:
    首先,它會解析收到的 TCP 數據中的 VLESS 協議頭部,以了解目標地址和端口等信息。
  2. 創建 TCP 連接:
    接下來,vlessOverWSHandler 會根據 VLESS 協議頭部中的目標地址和端口信息,建立一個新的 TCP 連接。它會向目標地址和端口發送數據,將接收到的 TCP 數據轉發到該 TCP 連接。
  3. 轉發數據:
    一旦新的 TCP 連接建立完成,vlessOverWSHandler 會將接收到的 TCP 數據轉發到該連接中,這樣數據就能夠正確地發送到目標服務器。
  4. 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 数据是通过以下几个部分的代码实现的:

  1. 转发数据:
    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();

      // ... 其他代码 ...
   }
  1. 监听远程 Socket 数据:
    handleTCPOutBound 函数中,通过 tcpSocket.readablepipeTo 方法来监听远程 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 的数据流封装为一个可读流,以便能够通过流式数据传输的方式处理客户端的数据,并且在客户端发送更多数据时,能够持续触发数据传输。

函数的实现原理如下:

  1. 创建可读流:
    函数首先通过 new ReadableStream() 创建一个可读流对象 stream
  2. 注册事件监听器:
    在可读流的 start 回调函数中,函数会通过 addEventListener 监听 WebSocket 的 message 事件。一旦接收到客户端发送的数据,该事件会触发并将数据添加到可读流中。
  3. 数据传输:
    在可读流的 transform 回调函数中,函数会将接收到的 WebSocket 数据转换为可读流的数据,并通过 controller.enqueue 方法将数据添加到可读流中。这样,在 WebSocket 有新数据到来时,transform 回调函数会被调用,从而触发数据传输。
  4. WebSocket 关闭处理:
    函数还会监听 WebSocket 的状态变化,特别是关闭事件。一旦 WebSocket 关闭,cancel 回调函数会被调用,函数会相应地关闭数据传输。

通过这种方式,makeReadableWebSocketStream 函数实现了将 WebSocket 的数据流封装为可读流的功能,使得可以通过流式传输的方式处理客户端的数据,从而能够持续地接收客户端的数据并作出相应的处理。

processVlessHeader 是幹什麼的?

processVlessHeader 是一个函数,它的作用是解析 VLESS 协议的头部信息。

在 VLESS 协议中,数据流的开头包含了一些特定的字段,用于标识数据的类型和其他相关信息。processVlessHeader 函数接收一个 ArrayBuffer 参数 vlessBuffer,该参数是从客户端发送的数据流中提取的 VLESS 协议头部信息。函数会解析该头部信息,提取出其中的字段,以便后续对数据进行处理。

具体来说,processVlessHeader 函数的工作原理如下:

  1. 解析数据类型和用户验证:
    函数首先从 vlessBuffer 中解析出数据类型(TCP 或 UDP)以及用户验证信息(UUID)。这里需要注意的是,VLESS 头部信息的前 17 个字节包含了 UUID,用于验证用户身份。如果解析出的 UUID 与预设的 userID 不匹配,说明该用户不合法。
  2. 解析其他信息:
    接下来,函数会解析其他的 VLESS 头部信息,包括可选字段的长度和字段值。目前,函数只关心数据类型为 UDP 时的处理,因为数据类型为 TCP 或 MUX 时不需要做特殊处理。
  3. 提取目标服务器地址和端口:
    当数据类型为 UDP 时,函数会提取出目标服务器的地址(IPv4 或 IPv6)和端口号,以便后续转发 UDP 数据包。
  4. 返回解析结果:
    最后,函数会返回一个包含解析结果的对象。如果解析过程中出现错误或数据格式不合法,函数会在返回的对象中标记出错信息。如果解析成功,返回的对象包含了目标服务器的地址、端口号以及其他相关信息,用于后续的数据转发和处理。

总体而言,processVlessHeader 函数在 VLESS 协议的数据流中提取出相关的信息,以便后续根据这些信息来进行数据的处理和转发。这个函数在整个 VLESS 协议的实现中起到了关键的作用。

remoteSocketToWS 是幹什麼的?

remoteSocketToWS 是一个函数,它的作用是将来自远程服务器的数据流转发到 WebSocket 客户端。

在 VLESS 协议中,数据流是从远程服务器返回给本地客户端的。而本地客户端与服务器之间是通过 WebSocket 连接通信的。remoteSocketToWS 函数负责将远程服务器返回的数据流转发到 WebSocket 客户端,以便客户端能够接收到实时的数据并做相应的处理。

函数的实现原理如下:

  1. 数据转发:
    函数通过 remoteSocketreadable 属性来获取可读流,这个可读流是从远程服务器读取数据的。然后,通过 pipeTo 方法将远程服务器的数据流与 WebSocket 的数据流相连接,实现数据的转发。
  2. WebSocket 传输:
    在转发数据的过程中,函数会检查 WebSocket 的状态,只有在 WebSocket 连接处于打开状态(WS_READY_STATE_OPEN)时,才会将数据发送给客户端。
  3. 关闭处理:
    函数会监听 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

歡迎你的留言討論:

你可以一針見血

by Upsangel
Logo