使反向 TCP 连接接受任意数量的连接(就像普通的 TCP 服务器)
Make reverse TCP connection accept any amount of connections (like a normal TCP server)
我正在尝试为基于 CONNECT 的 HTTP 代理创建反向代理。想要使用代理的用户只需将 machine A
视为 HTTP 代理即可。它的工作方式如下:
machine B
打开到 machine A
的 TCP 套接字。
- 在
machine A
上,TCP 套接字在端口上公开,所有传入数据都通过隧道传输到 machine B
(io.Copy)。
- 在
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)
我正在尝试为基于 CONNECT 的 HTTP 代理创建反向代理。想要使用代理的用户只需将 machine A
视为 HTTP 代理即可。它的工作方式如下:
machine B
打开到machine A
的 TCP 套接字。- 在
machine A
上,TCP 套接字在端口上公开,所有传入数据都通过隧道传输到machine B
(io.Copy)。 - 在
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)