V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
humbass
V2EX  ›  Node.js

如何给代理加一层 socks5 代理方式

  •  
  •   humbass · 2022-07-23 14:14:07 +08:00 · 5826 次点击
    这是一个创建于 857 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用 electron 写的客户端 , 需要用到一个代理的功能,目前是直接使用 http 代理,设置远程的 proxy-server 地址即可。 走的是 http 、https 代理,代码在最下面。

    #########         ############
    本地客户端 -proxy-> proxy server -> 指定网站
    #########         ############
    

    希望在本地增加一个 socks5 的代理层,数据转换后通过 http\websockets 到 proxy server, 类似这样

    #########           ###########          ############
    本地客户端 -socks5-> local proxy  -proxy-> proxy server -> 指定网站
    #########           ###########          ############
    

    求赐教!!




    服务器端代理的源码

    const http = require('http')
    const net = require('net')
    const port = 1080
    function buildHeaders(headers) {
      const arr = []
      for (const [k, v] of Object.entries(headers)) {
        arr.push(`${k}:${v}\r\n`)
      }
      return arr.join('')
    }
    
    function getHostAndPort(req) {
      let host
      let port
      try {
        ;[host, port] = new URL(req.url)
      } catch (e) {
        ;[host, port] = req.headers.host.split(':')
      } finally {
        if (!port) {
          port = 80
        }
      }
      console.log(host, port)
      return [host, port]
    }
    const server = http.createServer((req, res) => {
      const [host, port] = getHostAndPort(req)
      http.get(
        {
          port,
          host,
          path: req.url
        },
        response => {
          response.pipe(res)
        }
      )
    })
    
    server.on('upgrade', (req, res, head) => {
      const [host, port] = getHostAndPort(req)
      const client = net.connect({
        port,
        host
      })
      client.on('connect', () => {
        client.write(`GET ${req.url}\r\n` + buildHeaders(req.headers) + '\r\n')
        res.pipe(client)
        client.pipe(res)
      })
      client.on('error', () => {
        res.destroy()
      })
    })
    server.on('connect', (req, client, head) => {
      const [host, port] = getHostAndPort(req)
      const socket = net.connect(port, host, () => {
        console.log('connect', port, host, head)
        client.write('HTTP/1.1 200 Connection Established\r\n' + 'Proxy-agent: Node.js-Proxy\r\n' + '\r\n')
        socket.write(head)
        socket.pipe(client)
        client.pipe(socket)
      })
    })
    server.listen(port, () => console.log(port))
    
    
    第 1 条附言  ·  2022-07-23 17:06:25 +08:00

    补充:

    • 本地需要 socks5
    • socks5 转换数据后通过 http\https\websocks 与远程的设备通信
    • 只能使用 nodejs 实现,因为要运行在 electron 中

    本地访问->本地socks->本地websocks->远程websocks->目标网站

    试验过直接用socks,容易被GFW截断,部分指定的站点在海外

    13 条回复    2022-07-26 14:04:31 +08:00
    binux
        1
    binux  
       2022-07-23 14:44:25 +08:00
    实现一下 socks5 握手协议呗。
    v23x
        2
    v23x  
       2022-07-23 15:15:02 +08:00
    没有什么比 socks5 更简单的了...

    不会超过 10 行代码
    humbass
        3
    humbass  
    OP
       2022-07-23 16:23:42 +08:00
    @v23x 有些特定的资源需要 科学, 所以不能直接 SOCKS5 到国外
    sujin190
        4
    sujin190  
       2022-07-23 16:38:31 +08:00
    python3 -m sevent.helpers.proxy2proxy -p 8088 -T socks5 -P 10.10.10.10:8088

    -p 8088 为本地 socks5 代理端口
    -P 10.10.10.10:8088 远程 socks5 服务器

    一行命令行解决,但是不支持 socks5 需要用户名密码校验的啊
    sujin190
        5
    sujin190  
       2022-07-23 16:41:05 +08:00
    python3 -m sevent.helpers.proxy2proxy -p 8088 -T http -P 10.10.10.10:8088

    远端时 http 代理也行,只是也不支持添加用户名密码。。
    humbass
        6
    humbass  
    OP
       2022-07-23 17:07:36 +08:00
    @sujin190 运行在 electron ,客户的机器上不一定有 python3 ,只能是 nodejs, 另外代理的方式也不对,我是希望通过 http/https/websocket 来做本地与远程的数据通信
    shynome
        7
    shynome  
       2022-07-23 19:09:29 +08:00 via Android
    反正 electron 这么大,再加一个二进制 v2ray 也没啥事
    humbass
        8
    humbass  
    OP
       2022-07-23 19:12:31 +08:00   ❤️ 1
    @shynome 有试过加 v2ray ,用 child_process 线程启动,很容易闪退。
    ThirdFlame
        9
    ThirdFlame  
       2022-07-23 20:35:16 +08:00
    v2ray 、xray 不就支持多层。
    linuxyz
        10
    linuxyz  
       2022-07-24 21:47:40 +08:00
    也许可以在 https://gist.github.com/longbill/d321fc371e6dda9acf40decdb923c048 基础上改改。 你要么需要把整个 socks5 交互的报文头传过去,要么自己设计一个小的协议。socks5 本身还是挺简单的,实现一个不支持验证的 Socks5 Server 看上面的 gist 就差不多了。

    但是估计你无论如何也需要一个远程的 ProxyServer:

    本地访问->本地 socks->本地 websocks->远程 websocks->远程的 ProxyServer->目标网站

    否则是无法连目标网站的。
    humbass
        11
    humbass  
    OP
       2022-07-24 21:57:53 +08:00
    @linuxyz 感谢回复

    以前用过 socks5 ,也是直接连到远程的 socks5 server ,但是某些站点在海外,容易触发防火墙拦截
    所以现在改成 http/https 的方式直接

    难点是 socks5 如何 跟本地 交互,把 socks5 的包改成 http 的包。没有网络编程经验,难度有点大 。
    3825995121
        12
    3825995121  
       2022-07-26 13:49:58 +08:00
    https://github.com/oyyd/http-proxy-to-socks#readme
    http-proxy-to-socks 这个 node 包的作用就是监听 http 然后转到 socket5
    可以参考一下
    humbass
        13
    humbass  
    OP
       2022-07-26 14:04:31 +08:00
    @3825995121 socks5 的代码也容易实现,难的是 如果 socks5 to websocket 并且可以 websocket to socks5
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5819 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 03:19 · PVG 11:19 · LAX 19:19 · JFK 22:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.