Skip to content

Commit bfe2f28

Browse files
committed
Major feature update:
* Added socks server capability * Fully tested Quic client/server * E2E test cases * Updated diagram for using the socks feature * updated readme
1 parent 3e92834 commit bfe2f28

16 files changed

Lines changed: 976 additions & 204 deletions

README.md

Lines changed: 116 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
# go-tunnel - Robust Quic/TLS Tunnel (Stunnel replacement)
22

33
## What is it?
4-
A supercharged [Stunnel](https://www.stunnel.org) replacement written in golang. It is
4+
A supercharged [Stunnel](https://www.stunnel.org) replacement written in golang.
55
is in a sense a proxy enabling addition of network-encryption to existing
66
clients without any source code changes.
77

8-
go-tunnel uses golang's TLS stack and built-in certification verification.
9-
108
## Features
119

1210
- TLS 1.3 for client and server mode (TLS Connect or TLS Listen)
1311
- Quic client and server mode (Quic listen or Quic connect)
12+
- Optional SOCKS for connecting endpoint (SOCKS server)
1413
- Optional TLS client certificate (for Quic/TLS Connect)
1514
- SNI on the listening Quic/TLS server
1615
- Ratelimits - global and per-IP
@@ -19,50 +18,66 @@ go-tunnel uses golang's TLS stack and built-in certification verification.
1918
- YAML Configuration file
2019
- Access Control on per IP or subnet basis (allow/deny combination)
2120
- Strong ciphers and curves preferred on both client & server
21+
- Comes with end-to-end tests covering variety of scenarios
2222

2323
Note that TLS private keys need to be *unencrypted*; we don't support password protected
2424
private keys yet. The main reason for this is that when `gotun` is daemonized, it may not be
2525
possible to obtain the password in an interactive manner. Additionally, for SNI support, it may be
2626
impossible to ask for interactive password in the middle of a client connection setup.
2727

28-
### Motivating Example
29-
Let us suppose that you have a SOCKS5 server on host `192.168.55.3` and this
30-
is accessible via a "gateway" node `172.16.55.3`. Furthermore, let us say that
31-
clients/browsers wishing to use the SOCKS5 proxy are in the `10.0.0.0/24` subnet.
32-
And to keep things simple, let us assume that one host in the `10.0.0.0` network
33-
can access the gateway node: `10.0.0.5`.
28+
## Motivating Example
29+
Lets assume you have a public server on `proxy.example.com`
30+
listening on Quic/UDP supporting SOCKS protocol for connecting to
31+
outbound destinations. For security reasons, you want to limit
32+
access to only clients that are TLS authenticated (TLS client
33+
certs).
34+
35+
Lets also assume that you have a laptop that wants to connect to the
36+
SOCKS server efficiently.
37+
38+
Using two instances of `gotun`, you can accomplish this:
39+
40+
1. Local gotun instance on your laptop configured to accept TCP and
41+
connect using Quic to the external server `proxy.example.com`
3442

35-
Ordinarily, we'd create a IP routing rule on `10.0.0.5` to make the hosts on its network
36-
access the `192.168.55.0/24` via `172.16.55.3`. But, we desire the communication
37-
between `10.0.0.0/24` and `172.16.55.0/24` to be encrypted.
43+
2. Server gotun instance on the external host configured to accept
44+
authenticated Quic connections and proxy via SOCKS.
3845

39-
Thus, with go-tunnel, one can setup a "bridge" between the two networks - and the bridge
40-
is encrypted with TLS. The picture below explains the connectivity:
46+
3. Configure your laptop browser to use the "local" SOCKS server.
4147

42-
![example diagram](/docs/example-diagram.png)
48+
Using Quic to connect the two `gotun` instances reduces the TCP/TLS
49+
overhead of every socks connection. And, TLS client certs enables
50+
strong authentication on the external server.
4351

44-
In the setup above, hosts will treat `10.0.0.5:1080` as their "real" SOCKS server. Behind the
45-
scenes, go-tunnel is relaying the packets from `10.0.0.5` to `172.16.55.3` via TLS. And, in turn
46-
`172.16.55.3` relays the decrypted packets to the actual SOCKS server on `192.168.55.3`.
52+
The picture below explains the connectivity:
4753

48-
The config file shown above actually demonstrates a really secure tunnel - where the server and
49-
client both use certificates to authenticate each other.
54+
![example diagram](/docs/socks-example.png)
5055

51-
Assuming the config on "Gotunnel-A" is in file `a.conf`, and the config on "Gotunnel-B" is in
52-
`b.conf`, to run the above example, on host "Gotunnel-A":
56+
In the setup above, the laptop browser clients will treat
57+
`127.0.0.1:1080` as their "real" SOCKS server. Behind the scenes,
58+
`gotun` will tunnel the packets via Quic to a remote endpoint where
59+
a second `gotun` instance will unbundle the SOCKS protocol and
60+
connect to the final destination.
5361

54-
gotun -d a.conf
62+
The config file shown above actually demonstrates a really secure tunnel
63+
- where the server and client both use certificates to authenticate each other.
5564

56-
And, on host "Gotunnel-B":
65+
Assuming the config on "Gotunnel Laptop" is in file `client.conf`, and the
66+
config on "Gotunnel Server" is in `server.conf`, to run the above example,
67+
on host "Gotunnel-A":
5768

58-
gotun -d b.conf
69+
gotun client.conf
5970

71+
And, on the public server:
6072

61-
The `-d` flag runs `gotun` in debug mode - where the logs are sent
62-
to STDOUT.
73+
gotun server.conf
6374

64-
### Building go-tunnel
65-
You need a reasonably new Golang toolchain (1.8+). And the `go`
75+
The `-d` flag for `gotun` runs it in debug mode - where the logs are sent
76+
to STDOUT. It's not recommended to run a production server in debug
77+
mode (too many log messages).
78+
79+
## Building go-tunnel
80+
You need a reasonably new Golang toolchain (1.14+). And the `go`
6681
executable needs to be in your path. Then run:
6782

6883
make
@@ -105,8 +120,8 @@ In debug mode, the logs are sent to STDOUT and the debug level is set to DEBUG
105120
In the absence of the `-d` flag, the default log level is INFO or
106121
whatever is set in the config file.
107122

108-
### Config File
109-
The config file is a YAML v2 document. A self-explanatory example is below:
123+
## Config File
124+
The config file is a YAML v2 document. A complete, self-explanatory example is below:
110125

111126
```yaml
112127

@@ -121,6 +136,10 @@ log: STDOUT
121136
# Logging level - "DEBUG", "INFO", "WARN", "ERROR"
122137
loglevel: DEBUG
123138

139+
# config dir - where all non-absolute file references below will
140+
# apply.
141+
config-dir: /etc/gotun
142+
124143
# Listeners
125144
listen:
126145
# Listen plain text
@@ -129,25 +148,26 @@ listen:
129148
deny: []
130149

131150
timeout:
132-
connect: 10
133-
read: 10
134-
write: 30
151+
connect: 5
152+
read: 2
153+
write: 2
135154

136155
# limit to N reqs/sec globally
137156
ratelimit:
138157
global: 2000
139-
perhost: 30
158+
per-host: 30
159+
cache-size: 10000
140160

141161
# Connect via TLS
142162
connect:
143163
address: host.name:443
144164
bind: my.ip.address
145165
tls:
146-
cert: /path/to/crt
147-
key: /path/to/key
148-
# path to CA bundle that can verify the server certificate.
149-
# This can be a file or a directory.
150-
ca: /path/to/ca.crt
166+
cert: /path/to/crt
167+
key: /path/to/key
168+
# path to CA bundle that can verify the server certificate.
169+
# This can be a file or a directory.
170+
ca: /path/to/ca.crt
151171

152172
# if address is a name, then servername is populated from it.
153173
# else, if it is an IP address, it must be set below.
@@ -159,29 +179,48 @@ listen:
159179
allow: [127.0.0.1/8, 11.0.1.0/24, 11.0.2.0/24]
160180
deny: []
161181
timeout:
162-
connect: 8
163-
read: 9
164-
write: 27
182+
connect: 5
183+
read: 2
184+
write: 2
165185

166186
tls:
167-
sni: true
168-
certdir: /path/to/cert/dir
187+
sni: /path/to/cert/dir
169188

170189
# clientcert can be "required" or "optional" or "blank" or absent.
171190
# if it is required/optional, then clientca must be set to the list of
172191
# CAs that can verify a presented client cert.
173-
clientcert: required
174-
clientca: /path/to/clientca.crt
192+
client-cert: required
193+
client-ca: /path/to/clientca.crt
175194

176195
# plain connect but use proxy-protocol v1 when speaking
177196
# downstream
178197
connect:
179198
address: 55.66.77.88:80
180199
proxyprotocol: v1
181200

201+
202+
# Listen on Quic + client auth and connect to SOCKS
203+
- address: 127.0.0.1:8443
204+
tls:
205+
quic: true
206+
cert: /path/to/crt
207+
key: /path/to/key
208+
# path to CA bundle that can verify the server certificate.
209+
# This can be a file or a directory.
210+
ca: /path/to/ca.crt
211+
212+
client-cert: required
213+
client-ca: /path/to/clientca.crt
214+
215+
connect:
216+
address: SOCKS
217+
182218
```
183219

184-
### Using SNI
220+
The `etc/` directory has example configurations for running
221+
Quic+SOCKS on a public server and a local laptop.
222+
223+
## Using SNI
185224
SNI is exposed via domain specific certs & keys in the `tls.certdir` config block. SNI is
186225
enabled by setting `tls.sni` config element to `true`; and each hostname that is requested via
187226
SNI needs a cert and key file with the file prefix of hostname. e.g., if the client is looking
@@ -190,7 +229,15 @@ for hostname "blog.mydomain.com" via SNI, then `gotun` will look for `blog.mydom
190229
an example for SNI configured on listen address `127.0.0.1:9443`.
191230

192231

193-
### Performance Test
232+
## Security
233+
`gotun` tries to be safe by default:
234+
235+
- Opinionated TLS 1.3 configuration
236+
- All config file references are checked for safety: e.g., any TLS
237+
certs/keys are verified to have sane permissions (NOT group/world
238+
writable)
239+
240+
## Performance Test
194241
Using iperf3 on two debian-linux (amd64) hosts connected via Gigabit Ethernet and `gotun` running on either end,
195242
the performance looks like so:
196243

@@ -224,7 +271,7 @@ CPU Utilization: local/sender 1.8% (0.0%u/1.7%s), remote/receiver 9.0% (0.6%u/8.
224271

225272
```
226273

227-
### Access Control Rules
274+
## Access Control Rules
228275
Go-tunnel implements a flexible ACL by combination of
229276
allow/deny rules. The rules are evaluated in the following order:
230277

@@ -234,7 +281,7 @@ allow/deny rules. The rules are evaluated in the following order:
234281
- Explicit denial takes precedence over explicit allow
235282
- Default (fall through) policy is to deny
236283

237-
#### Example of allow/deny combinations
284+
### Example of allow/deny combinations
238285

239286
1. Allow all:
240287

@@ -273,7 +320,24 @@ If you are a developer, the notes here will be useful for you:
273320
274321
- The code uses go modules; so, you'll need a reasonably new go toolchain (1.10+)
275322
276-
- The go-tunnel code is in `./gotun`.
323+
- The go-tunnel code is in `./gotun`:
324+
325+
* main.go: `main()` for `gotun`
326+
* server.go: Implements TCP/TLS and Quic servers; also
327+
implements the SOCKS server protocol
328+
* conf.go: YAML configuration file parser
329+
* quicdial.go: Dial outbound connections via Quic + streams
330+
* tcpdial.go: Dial outbound connections via TCP
331+
* safety.go: Safely open files/dirs referenced in config file
332+
333+
- Tests: running tests: `go test -v ./gotun`
334+
Some of the tests/helpers:
335+
* mocked_test.go: Mock servers and clients
336+
* tcp_test.go: Tests for TCP/TLS to TCP/TLS
337+
* quic_test.go: Tests for TCP/TLS to Quic and vice versa
338+
* socks_test.go: Tests for socks (includes a test for the
339+
example configuration above)
340+
* utils_test.go: test helpers (e.g., `assert()`)
277341

278342
- We build `build` - a a master shell script to build the daemons;
279343
it does two very important things:

docs/README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Example Configurations for various scenarios
2+
3+
## TLS to TCP proxy with client authentication
4+
If you want to have strong authentication of clients to access a
5+
service behind the proxy, then the following configuration is a good
6+
starting point:
7+
8+
```yaml
9+
10+
log: SYSLOG
11+
loglevel: INFO
12+
13+
listen:
14+
- address: ip.address:lport
15+
ratelimit:
16+
global: 20000
17+
per-host: 50
18+
# LRU cache size for per-host rate limit
19+
cache-size: 50000
20+
21+
tls:
22+
cert: /path/to/server.crt
23+
key: /path/to/server.key
24+
# ca can be a file containing multiple certs or a
25+
# directory containing ca certs
26+
ca: /path/to/ca.bundle
27+
28+
client-cert: required
29+
client-ca: /path/to/clientca.crt
30+
31+
32+
connect:
33+
address: host.name:port
34+
proxy-protocol: v1
35+
36+
```
37+
38+
Now, clients that have a valid cert/key pair can connect to to
39+
`ip.address:lport` above. And if the cert/key pair is valid and
40+
accepted by the proxy, the client will be connected to the backend
41+
on `host.name:port`.
42+
43+
## Quic to TCP with client authentication
44+
If you have a modern quic client (e.g., most chrome browsers) but
45+
your service is still serving legacy TCP/TLS, `gotunnel` can help
46+
bridge this protocol gap: configure it to listen on a quic port and
47+
relay connections from client to the backend TCP/TLS service:
48+
49+
```yaml
50+
51+
log: SYSLOG
52+
loglevel: INFO
53+
54+
listen:
55+
- address: ip.address:lport
56+
ratelimit:
57+
global: 20000
58+
per-host: 50
59+
60+
tls:
61+
quic: true
62+
cert: /path/to/server.crt
63+
key: /path/to/server.key
64+
# ca can be a file containing multiple certs or a
65+
# directory containing ca certs
66+
ca: /path/to/ca.bundle
67+
68+
clientcert: required
69+
clientca: /path/to/clientca.crt
70+
71+
72+
connect:
73+
address: host.name:port
74+
proxy-protocol: v1
75+
```
76+
77+
The configuration is essentially the same as the previous one - with
78+
the addition of the **`quic: true`** setting. This setting forces
79+
`gotunnel` to listen on a UDP port.

docs/socks-example.dia

1.81 KB
Binary file not shown.

docs/socks-example.png

28.8 KB
Loading

0 commit comments

Comments
 (0)