Pipy 實現 SOCKS 代理

上篇我們介紹了服務網格 osm-edge 出口網關使用的 HTTP 隧道,其處理方式與另一種代理有點類似,就是今天要介紹的 SOCKS 代理。二者的主要差別簡單來說就是前者使用 HTTP CONNECT 告知代理目的地址,而後者則是通過 SOCKS 協議。值得一提的是,SOCKS 也是出口網關的可選協議之一。

SOCKS 是一種網絡傳輸協議,是 Socket Secure 的縮寫,主要用於客戶端與外網服務器之間通訊的中間傳遞。根據 OSI 模型,SOCKS 是會話層的協議,位於表示層與傳輸層之間。

SOCKS 協議的最新版本是 SOCKS5,在 SOCKS4 的基礎上增加了 UDP、認證 和 IPv6 的支持。因此,後面提到的 SOCKS 都是使用最廣泛的 SOCKS5。

先看一下 SOCKS 代理的工作流程。

socks-proxy-process

  1. 協商階段:客戶端與代理建立連接,並進行協商,包括協議版本、認證的方式等等。

  2. 連接階段:客戶端告知代理要連接的目的地址和端口(SOCKS 報文),代理使用報文中的地址和端口與服務端創建連接,並將結果作爲狀態返回給客戶端。

  3. 數據傳輸階段:客戶端向代理發送數據,代理將數據發送到服務端;然後將服務端返回的數據返回給客戶端。

Demo

socks-proxy-demo

還是使用上篇中的例子,在防火牆後有個 TCP 服務端,由於監聽在 127.0.0.1:8081 還能在本地訪問。同樣,使用 Pipy 來模擬這個服務。

pipy()

  .listen('127.0.0.1:8081')
  .replaceData(
    () => new Data('Hi, TCP!\n')
  )

接下來,在服務端一側建立一個 SOCKS 代理。

socks-proxy

PipyJS 編碼

我們的代理監聽在 8000 端口,使用 acceptSOCKS 過濾器 [1] 來處理 SOCKS 協議報文,從報文中獲取目的地址和端口,然後使用該地址和端口創建到服務端的連接。

pipy({
  _host: null,
  _port: null,
})
  //socks
  .listen(8000)
  .acceptSOCKS(
    (host, port) =(
      _host = host,
      _port = port,
      true // return true to accept the session
    )
  ).to(
    $ => $.connect(
      () =`${_host}:${_port}`
    )
  )

測試

在主機 192.168.1.110 上運行我們的代理以及服務端,客戶端 curl 運行在主機 192.168.1.11 上。使用下面的命令進行測試:

curl -x socks5://192.168.1.110:8000 telnet://127.0.0.1:8081

test-socks-proxy

引用鏈接

[1] acceptSOCKS 過濾器: https://flomesh.io/pipy/docs/zh/reference/api/Configuration/acceptSOCKS

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/2_ctaOig2OJf__A-PpAqSw