Sample tunnel implementations using quic-go, kcp-go with smux, and pion/sctp
Part of an evaluation of candidate tunnels for the Turbo Tunnel design
https://github.com/net4people/bbs/issues/14
David Fifield <david@bamsoftware.com>
2019-10-02
Public domain


Here are three implementations of a TCP forwarding proxy, made using
different userspace reliability and multiplexing protocols. These
implementations served to help evaluate the protocols' suitability as an
intermediate layer in censorship circumvention transports. For more
information, see the link above.

All three implementations work the same way. The tunnel client accepts
TCP connections. Each incoming connection it breaks into packets (using
one of the three protocols under evaluation), then transmits the packets
to the tunnel server in the form of HTTP requests. The server receives
the packets, reassembles them into a stream, and forwards them to some
other TCP listener. Downstream packets are sent back as HTTP responses.

Besides aiding in protocol evaluation, these sample implementations are
meant to serve as a demonstration of using a sequencing/reliability
layer in the middle of a network stack, where you do not have things
like IP addresses and port numbers to serve as identifiers. All
client-initiated HTTP requests are tagged with a "clientID", which is a
randomly generated string that takes the place of a source address for
the encapsulated, tunnelled packets. (A clientID satisfies the net.Addr
interface and is returned when the server calls ReadFrom.) When the
sequencing/reliability protocol library on the server calls WriteTo to
send downstream data to a particular client (addressed by clientID), the
server stores it in a buffer until a future HTTP request comes in tagged
with that clientID -- then the server pulls data off the buffer and
includes it in the HTTP response. The clientID is fully decoupled from
the client's actual IP address, and the client -- or even the client
tunnel program -- could move to a different IP address and things would
still work.

Not every implementation of a tunnel of this type will need the
complexity of buffering downstream packets. The tunnel protocol was
chosen to test each protocol in a somewhat challenging deployment model.

To build any of the implementations, go into the client/ directory and
run "go build", then go into the server/ directory and run "go build".
In the case of quichttp, you will need Go version 1.13 or later.

One easy way to test the programs is with the Ncat --chat mode. This has
multiple clients communicating with each other on a chat room located on
the other side of the tunnel. The clients can connect to the tunnel
client and chat as if they were connecting to the chat server directly.
All the multiple clients are multiplexed over one virtual connection
carried over HTTP. Note that in the case of quichttp and sctphttp, the
client has to send some data (you have to type something) before the
server will notice the new connection. This restriction does not apply
to kcphttp.

```
run server:
        ncat -l -v --chat 127.0.0.1 31337
        server 127.0.0.1:8000 127.0.0.1:31337

run client:
        client 127.0.0.1:2000 http://127.0.0.1:8000
        ncat -v 127.0.0.1 2000 # as many times as desired

.-------.
:0 ncat |-TCP-.
'-------'     |
              | .------------.        .------------.       .------------------.
.-------.     '-:2000        |        |            |--TCP--:31337             |
:0 ncat |-TCP-+-:2000 client |--HTTP--:8000 server |--TCP--:31337 ncat --chat |
'-------'     .-:2000        |        |            |--TCP--:31337             |
              | '------------'        '------------'       '------------------'
.-------.     |
:0 ncat |-TCP-'
'-------'
```

As a demonstration of general-purpose proxying, replace the Ncat --chat
server with a SOCKS proxy, and replace the Ncat clients with any
SOCKS-supporting application. The SOCKS requests will be tunneled and
delivered to the SOCKS proxy.

The implementations use plaintext HTTP and are not intended to be
covert. But it would not be difficult to add HTTPS support and domain
fronting to create a meek-like covert proxy. Some other ideas for
enhancement:
 - AMP cache proxying (https://github.com/net4people/bbs/issues/5)
 - pluggable transports integration
 - bundling multiple packets per HTTP body
 - padding
