使反向 TCP 连接接受任意数量的连接(就像普通的 TCP 服务器)

Make reverse TCP connection accept any amount of connections (like a normal TCP server)

我正在尝试为基于 CONNECT 的 HTTP 代理创建反向代理。想要使用代理的用户只需将 machine A 视为 HTTP 代理即可。它的工作方式如下:

  1. machine B 打开到 machine A 的 TCP 套接字。
  2. machine A 上,TCP 套接字在端口上公开,所有传入数据都通过隧道传输到 machine B (io.Copy)。
  3. machine B 上,所有数据都通过隧道传输到本地 HTTP 服务器,并将套接字传输到 machine A

本质上这是一个 HTTP 代理背后的反向代理。之所以如此复杂,是因为 HTTP 代理位于 NAT 之后(在 machine B 上),因此无法直接访问。用例是能够在 NAT 后面托管 HTTP 代理。

机器A隧道(Go):

package main

import (
    "log"
    "net"
)

func Conn(c *net.TCPConn) string {
    return c.RemoteAddr().String() + " (" + c.LocalAddr().String() + ")"
}

func ProxifyConns(recipientConn, donorConn *net.TCPConn) {
    log.Println("Proxying", ConnrecipientConn), "and", Conn(donorConn))
    go func() {
        _, err := io.Copy(recipientConn, donorConn)
        if err != nil {
            utils.StacktraceError(err)
        }
        recipientConn.Close()
    }()
    go func() {
        _, err := io.Copy(donorConn, recipientConn)
        if err != nil {
            utils.StacktraceError(err)
        }
        recipientConn.Close()
    }()
}


func main() {
    // Open the donor listener
    donorsAddr, err := net.ResolveTCPAddr("tcp4", ":11000")
    if err != nil {
        utils.StacktraceErrorAndExit(err)
    }
    listenerDonors, err := net.ListenTCP("tcp", donorsAddr)
    if err != nil {
        utils.StacktraceErrorAndExit(err)
    }
    defer listenerDonors.Close()
    log.Println("Listening for donors on", listenerDonors.Addr())

    // Open the recipient listener
    recipientsAddr, err := net.ResolveTCPAddr("tcp4", ":10000")
    if err != nil {
        utils.StacktraceErrorAndExit(err)
    }
    listenerRecipients, err := net.ListenTCP("tcp", recipientsAddr)
    if err != nil {
        utils.StacktraceErrorAndExit(err)
    }
    defer listenerRecipients.Close()
    log.Println("Listening for recipients on", listenerRecipients.Addr())

    //  Handle donor connections
    donorConns := make(chan *net.TCPConn)
    go func() {
        for {
            donorConn, err := listenerDonors.AcceptTCP()
            donorConn.SetKeepAlive(true)
            if err != nil {
                utils.StacktraceErrorAndExit(err)
                return
            }
            log.Println("New donor connection from", Conn(donorConn))
            donorConns <- donorConn
        }
    }()

    // Handle recipient connections
    for {
        recipientConn, err := listenerRecipients.AcceptTCP()
        recipientConn.SetKeepAlive(true)
        if err != nil {
            utils.StacktraceErrorAndExit(err)
            return
        }
        log.Println("New recipient connection from", Conn(recipientConn))
        donorConn := <-donorConns
        proxy.ProxifyConns(recipientConn, donorConn)
    }
}

机器B隧道(Node.js):

import net, { AddressInfo } from 'net';
import http from 'http';
import golgi from 'golgi';

export const startHttpProxy = () => {
  const server = http.createServer();
  let proxyServer: http.Server = golgi(server);
  // Listening to 0 assigns a random OS-assigned port
  proxyServer = proxyServer.listen(0);
  return proxyServer;
};

export const startDonorSocket = () => {
  const proxyServer = startHttpProxy();
  const proxyServerSocket = new net.Socket();
  proxyServerSocket.connect(
    (proxyServer.address() as AddressInfo).port,
    '127.0.0.1'
  );

  const donorSocket = new net.Socket();
  donorSocket.setKeepAlive(true);
  donorSocket.connect(11000, '2.226.102.14', () => {
    proxyServerSocket.pipe(donorSocket);
    donorSocket.pipe(proxyServerSocket);
  });
};

不幸的是,这在通过隧道连接到一个 TCP 地址时有效,但在通过隧道连接到更多地址时不起作用。如果我打开许多机器 B 隧道(Node.js 代码),它就可以工作。我的意思是,捐赠者连接 (Node.js) 每次被接收者(HTTP 代理用户)占用时都会被“消耗”,因为在其上建立了持久的 TCP 隧道。

我想知道是否有一种方法可以使它适用于任何数量的 TCP 连接,而不仅仅是一个。我现在唯一的想法是在每次消耗连接时创建更多的 TCP 捐赠者连接,但我想知道是否有更简单的解决方案。

当你这样做时

go func() {
    for {
        donorConn, err := listenerDonors.AcceptTCP()
        donorConn.SetKeepAlive(true)
        if err != nil {
            utils.StacktraceErrorAndExit(err)
            return
        }
        log.Println("New donor connection from", Conn(donorConn))
        donorConns <- donorConn
    }
}()

您开始处理第一个 TCP 连接。此代码在 donorConns <- donorConn 上阻塞。在发送到通道完成之前,循环不会进入第二次迭代(并且不会接受下一个 TCP 连接)。

你做了一个非常相似的第二个循环

// Handle recipient connections
for {
    recipientConn, err := listenerRecipients.AcceptTCP()
    recipientConn.SetKeepAlive(true)
    if err != nil {
        utils.StacktraceErrorAndExit(err)
        return
    }
    log.Println("New recipient connection from", Conn(recipientConn))
    donorConn := <-donorConns
    proxy.ProxifyConns(recipientConn, donorConn)
}

需要 donorConn := <-donorConns 才能完成(从第一个循环开始)并且需要 proxy.ProxifyConns(recipientConn, donorConn) 才能完成。

我不确定你打算如何让整个事情发挥作用,但很可能,你需要一个非常小的改变:
go proxy.ProxifyConns(recipientConn, donorConn)