go-tunnel icon indicating copy to clipboard operation
go-tunnel copied to clipboard

Is Socks AND TLS supported for outbound from a local client?

Open johnwigley opened this issue 3 years ago • 3 comments

This isn't the obvious usage where you would have the remote or server end of the connection running the socks server with TLS decryption ahead of the socks server. This is a different configuration where the local/client end of the tunnel runs a socks server to determine the outbound connection request BUT that outbound request is then wrapped in a TLS tunnel.

The application is having 1 or more local/clients running a socks server with OUTBOUND TLS wrapping, the inbound socks request identifies which outbound to connect to, is then wrapped in TLS, and then there are multiple remote/server go-tunnel instances which on the remote end just perform TLS decryption with a final port forward to the receiving application.

This has the effect of allowing the client to select which remote application/server to connect to via socks but the connection between local and remote go-tunnel instances is TLS wrapped.

Thanks

johnwigley avatar Nov 24 '20 20:11 johnwigley

If I understood you correctly:

Clients --> Local SOCKS server --> TLS/QUIC --> Remote go-tunnel with specific outbound ports.

In this scenario - the difficulty is mapping the SOCKS resolved outbound destination to the correct go-tunnel instance (I assume multiple instances of remote go-tunnel). SOCKS have no method to "filter" requests - the server has to be custom for your use case..

If the list of outbound destinations is fixed - then it begs the question: why do you need a local SOCKS server at all?

Perhaps I am a bit unclear ..

opencoff avatar Nov 25 '20 19:11 opencoff

Thanks for replying, sorry it wasn't clear. I'll try and clarify...

The particular application I have in mind is where you have a network of approximately 150 nodes that use a proprietary protocol to locate and communicate with each other. They have a mechanism for node discovery and will initiate peer to peer connections over tcp between themselves.

What we want to do is to wrap each of their tcp connections in a TLS tunnel.

The normal way to do a client server TLS tunnel with Stunnel or similar TLS proxy is you set one of them up as the client proxy->TLS->Server proxy, similarly with go-tunnel you set the client to listen on a local port, and then you forward that port to a fixed destination. If you tried that approach in this case, you'd have to configure 150 static local port forwardings to the remote/server TLS termination proxies, and everytime a node changed IP etc then you'd have to reconfigure all the other 149 to update their TLS tunnel definitions - which is clearly impractical.

Much nicer solution would be to capture each nodes outgoing TCP connections via a SOCKS redirector such as Redsocks/Transocks/V2ray etc which will capture the outbound TCP connection and wrap that in a socks connection, so as far as the node is concerned it is making a normal outbound TCP connection but it is captured and delivered to a Socks server transparently. Because the Socks redirector has captured the node's intended TCP destination, the socks server can then make an outbound connection to the remote destination which would normally be the other node's listening socket HOWEVER, we will replace that with a normal stunnel/go-tunnel TLS termination proxy that port forwards the TLS decrypted connection to the receiving node.

Attempted diagram:

  1. Node A makes outbound TCP connection to 1.2.3.4:5555
  2. Redsocks/Transocks captures connection to 1.2.3.4:5555, and delivers it to local Socks server running in Go-Tunnel
  3. A) Local socks server in Go-Tunnel makes outbound connection to 1.2.3.4:5555 where the remote node should be listening. B) This is the unusual part - we need the outbound request that the local socks server makes to 1.2.3.4:5555 to be TLS wrapped.
  4. BUT we have in fact got a stunnel/go-tunnel TLS->cleartext proxy listening on the remote node on 1.2.3.4:5555 which decrypts the incoming TLS connection and delivers it to the remote node which is actually listening on a local ip and port, but has been told to advertise 1.2.3.4:5555 as it's external connection address.

This is all perfectly configurable out of the box with both Stunnel and Go-Tunnel EXCEPT 3B) which is the unusual part, normally you would TLS encrypt the incoming socks connection, NOT the outbound cleartext connection that the socks server makes to the destination.

Ultimately this in effect creates a poor man's TLS VPN where you have dynamically selected port forwards via the socks server that are TLS wrapped, without having to try and manage 150 individual TCP->TLS port forwards on each node, and update them every time an IP address changes.

It looks to me from the go-tunnel configuration file that this configuration is at least supported by the config file syntax if you used something along the lines of, although I guess it was never intended to be used this way:

//Listen on socks proxy but TLS encrypt all outbound connections??? listen: - address: 127.0.0.1:1080

    connect:
        address: SOCKS
        tls:
            cert: /path/to/crt
            key: /path/to/key
            ca: /path/to/ca.crt

Thanks!

johnwigley avatar Nov 25 '20 20:11 johnwigley

Ah I understand now; Thank you for clarifying.

I think the example I provided would work for 3B? In fact that is how I use gotunnel today - I have:

  • client go-tunnel instance listening on 127.0.0.1:1080 (socks ports) on plain TCP
  • client go-tunnel configured to deliver the socks proto wrapped inside a QUIC/TLS tunnel to a remote node
  • my browser on client is configured to use SOCKS proxy on localhost:1080 (i.e, local go-tunnel instance)
  • Remote node is listening on external-ip:port using QUIC/TLS
  • remote node receives TLS (QUIC) streams containing the socks proto
  • remote node parses socks proto and connects to the destination port

The main point here is that the local (client) go-tunnel does NOT terminate socks - it merely wraps it inside a TLS-QUIC stream and hands it off to the remote node. The remote go-tunnel actually unwraps the socks proto.

To accomplish this in your scenario - you could do the following:

  1. Use socks redirector (redsocks/transock etc.) to send the socks wrapped TCP to a LOCAL go-tunnel instance.
  2. This local go-tunnel instance will listen on TCP localhost:1080; And use QUIC/TLS to connect to your "real" socks server. for purposes of the redirector above, this localhost is the "real" socks server.
  3. Configure go-tunnel remote instance to listen on QUIC/TLS and connect as "SOCKS" exacty as the example:
listen:
      - address: :4430
      - quic: true
      - tls:
           .... # quic tls server config

      - connect:
           address: SOCKS

Now, the software you have on any given node will use local socks redirector to divert TCP connections to a local instance of go-tunnel --> configured to use TLS/QUIC to talk to a "real" socks server on the remote server.

opencoff avatar Nov 25 '20 22:11 opencoff