【问题标题】:Use a client behind NAT as proxy through public server通过公共服务器使用 NAT 后面的客户端作为代理
【发布时间】:2016-12-23 14:43:22
【问题描述】:

我在理解通过公共服务器将客户端暴露在 NAT 后面的理论方面存在一些问题,例如将客户端用作代理(最好是 SOCKS5)。 我想使用 Go 来解决这个问题,并且有一些很棒的 SOCKS5 Go 库,所以这没问题。

如果 NAT 后面的客户端连接到公共服务器,其他用户如何连接(可能在不同的端口上)以及我应该如何转发请求?

  • “C”是 NAT 后面的(单个)客户端
  • “A”是我想用来公开客户端的公共服务器
  • “U”是一个用户(或多个用户)想通过A连接到C

例如如果 A(公共服务器)侦听端口 5544 和 C(NAT 后面的客户端连接到它,而 C 也有一个本地 SOCKS5 服务器,请求被转发到)(U)用户或什至多个用户如何转发对 C 的请求(在 A:5544 上建立的第一个连接)

[ U --> A:5544 C C 本地 socks5 服务器]

用户连接到 A,C 连接到 A,流量被转发到 C(请注意,C 不监听传入连接,因为 C 连接到 A 而不是反向,因为 C 在 NAT 后面)

希望你明白我的意思。

提前谢谢你!

编辑:

指出我的意思。 C - NAT 后面的客户端不直接监听 TCP,它只是打开一个 TCP 连接(net.Dial() ...)到公共服务器,这会暴露客户端 - C 上的 socks5 代理没有直接暴露所以拨号的 TCP 连接在某种程度上表现得像一个 TCP 侦听器。

我认为基本上它与 teamviewer 使用的技术相同。 但具体如何?此外,多个用户可以通过“A”连接到客户端“C”,这一点也很重要。

补充:baloo 的回答让我更进一步,但现在的问题是,如果来自客户端的回答/流量 远程服务器连接通过

复制(在公共服务器端代码上)
_, err := io.Copy(usrConn, s.ProxyClient)

数据被流式传输/隧道传输,但如果我通过代理请求站点,则该站点正在加载并且加载这也会导致其他“用户”连接被阻止的问题。 (到目前为止,我收到了第一个请求的站点响应,但整个站点的请求仍在等待中……我可能对 SOCKS5 协议有错误的理解?)

这是我的公共服务器凌乱的原型代码:http://pastebin.com/7Y2JBVE0

这是客户端的代码(反向代理):http://pastebin.com/w3i9cap4

【问题讨论】:

    标签: go proxy reverse nat forwarding


    【解决方案1】:

    连接必须配对以使两个“客户端”相互通信,其中一个充当 SOCKS5 服务器,一个充当 SOCKS5 客户端。您在公共服务器上接受来自“NAT 后面的服务器”和“连接到 NAT 后面的服务器的客户端”的 TCP 连接。

    一旦两个连接都建立起来,您可以使用io.Copy 代理两个连接之间的输入和输出。

    您必须保留一个连接池,以便有一个 SOCKS5 服务器连接可用于任何新的 SOCKS5 客户端连接请求。

    NAT 后面的服务器必须拨打一个新连接到公共服务器,然后在该连接上处理 SOCKS5 请求using a generic SOCKS5 server that accepts io.ReadWriteCloser

    一个简化且未经测试的示例:

    package main
    
    import (
        "io"
        "log"
        "net"
    )
    
    func main() {
        lnServer, err := net.Listen("tcp", "1234")
        if err != nil {
            log.Fatalln(err)
        }
        lnClients, err := net.Listen("tcp", "1235")
        if err != nil {
            log.Fatalln(err)
        }   
    
        serverCh := make(chan net.Conn)
        go func() {
            for {
                conn, err := lnServer.Accept()
                if err != nil {
                    // handle errors
                }
                serverCh <- conn
            }
        }()
        for {
            conn, err := ln.Accept()
            if err != nil {
                // handle errors
            }
            sc <- serverCh
            go io.Copy(sc, conn)
            io.Copy(conn, sc)
        }
    }
    

    避免创建自己的连接池和配对的更简单方法可能是在两台服务器之间创建 VPN。公共服务器将所有连接转发到经过 NAT 的客户端。它将能够接受通过 VPN 分配的虚拟 IP 上的连接。进行此设置的一种流行解决方案是OpenVPN

    【讨论】:

    • 好的我想我明白了,但是应该如何进行配对呢?能给我举个小例子吗?
    【解决方案2】:

    您可以使用httputil.ReverseProxy 将用户重定向到本地服务器:
    另见:http://blog.charmes.net/2015/07/reverse-proxy-in-go.html

    测试示例代码:

    package main
    
    import (
        "net/http"
        "net/http/httputil"
        "net/url"
    )
    
    func handler(handler http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            r.Host = r.URL.Host
            handler.ServeHTTP(w, r)
        })
    }
    
    func main() {
        u, _ := url.Parse("https://translate.google.com")
        reverseProxy := httputil.NewSingleHostReverseProxy(u)
        http.ListenAndServe(":3000", handler(reverseProxy))
    }
    

    【讨论】:

    • 实际上我想使用 SOCKS5 协议并以某种方式通过公共服务器将原始请求/流量转发到客户端代理。所以只有客户端担心 socks 协议。然而,这是一个有趣的链接。但我仍然不明白这将如何与该公开客户端代理的多个用户一起使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多