Skip to content

Commit 1b9801e

Browse files
author
forest
committed
add usage example and fix readme
1 parent 3e12a9d commit 1b9801e

File tree

9 files changed

+179
-3
lines changed

9 files changed

+179
-3
lines changed

README.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ It is intended to be used to make it easier for non-tech-savvy people to host we
77

88
This repository only includes the application that does the tunneling part. It does not include any other management or automation tools.
99

10+
See the usage example folder for a basic test.
11+
1012
![Diagram](readme/Diagram.png)
1113

1214
### How it is intended to be used:
1315

1416
1. An automated tool creates a cloud instance and installs and configures the tunnel server on it.
15-
1. An automated tool installs the tunnel client on the self-hoster's server computer.
16-
1. The tunnel client connects to the tunnel server on the Tunnel Control Port. This connection will use TLS Client Authentication. This connection will be held open and re-created if dropped.
17+
1. An automated tool installs the tunnel client on the self-hoster's server computer.
1718
1. An automated tool calls the `PUT /tunnels` api on the tunnel server's Management Port, and sends a JSON file describing which ports should be opened on the tunnel server, which client they should be tunneled to, and which ports on the client they should be tunneled to, as well as whether or not the HAProxy "PROXY" protocol should be used. This connection will also use TLS Client Authentication.
19+
1. The tunnel client connects to the tunnel server on the Tunnel Control Port. This connection will use TLS Client Authentication. This connection will be held open and re-created if dropped.
1820
1. An internet user connects to the tunnel server on one of the ports defined in the JSON. The internet user's request is tunneled through the original connection from the tunnel client, and then proxied to the web server software running on the self-hoster's server computer.
1921

2022
### Why did you set it up this way?
@@ -31,4 +33,8 @@ I have a few requirements for this system.
3133
1. Simplicity and Laser-like focus on "opaque" usage of TCP/TLS. Removed HTTP/WebSocket/Virtual Hosts code.
3234
1. Added support for HAProxy "PROXY" protocol.
3335
1. Added support for Port mappings between front end and back end.
34-
1. Fixed various bugs related to connection lifecycle.
36+
1. Fixed various bugs related to connection lifecycle.
37+
38+
### Issues
39+
40+
Unfortunately right now the tunnels config has to put set 1st before the client can connect. I'll probably fix this later.

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module git.sequentialread.com/forest/tunnel
22

33
require (
4+
github.com/armon/go-proxyproto v0.0.0-20180202201750-5b7edb60ff5f
45
github.com/cenkalti/backoff v2.1.0+incompatible
56
github.com/gorilla/websocket v1.4.0
67
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
git.sequentialread.com/forest/tunnel v0.0.0-20170601195443-35a8b95662bf h1:2flo/nnhfe3sSxQ/MHlK7KoY54tQ1pAvMzkh0ZOxyH4=
22
git.sequentialread.com/forest/tunnel v0.0.0-20170601195443-35a8b95662bf/go.mod h1:i+PvDDsWjggoCQOO8bGJJKRB9qfxmHk5yzIEA/h8dzg=
3+
github.com/armon/go-proxyproto v0.0.0-20180202201750-5b7edb60ff5f h1:SaJ6yqg936TshyeFZqQE+N+9hYkIeL9AMr7S4voCl10=
4+
github.com/armon/go-proxyproto v0.0.0-20180202201750-5b7edb60ff5f/go.mod h1:QmP9hvJ91BbJmGVGSbutW19IC0Q9phDCLGaomwTJbgU=
35
github.com/cenkalti/backoff v2.1.0+incompatible h1:FIRvWBZrzS4YC7NT5cOuZjexzFvIr+Dbi6aD1cZaNBk=
46
github.com/cenkalti/backoff v2.1.0+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
57
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=

usage-example/client-config.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"DebugLog": false,
3+
"ClientIdentifier": "TestClient1",
4+
"ServerHost": "localhost",
5+
"ServerTunnelControlPort": 9056,
6+
"ServerManagementPort": 9057
7+
}

usage-example/listener.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"net"
6+
7+
proxyproto "github.com/armon/go-proxyproto"
8+
)
9+
10+
func main() {
11+
// Create a listener
12+
tcpListener, err := net.Listen("tcp", ":9001")
13+
if err != nil {
14+
panic(err)
15+
}
16+
17+
fmt.Print("Listener: I am listening on port 9001\n")
18+
19+
// Wrap listener in a proxyproto listener
20+
proxyListener := &proxyproto.Listener{Listener: tcpListener}
21+
for {
22+
conn, err := proxyListener.Accept()
23+
if err != nil {
24+
panic(err)
25+
}
26+
go acceptConnection(conn)
27+
28+
}
29+
30+
}
31+
32+
func acceptConnection(conn net.Conn) {
33+
fmt.Printf("Listener: Someone connected from: %s\r\n", conn.RemoteAddr().String())
34+
buffer := make([]byte, 4096, 4096)
35+
bytesRead := 0
36+
var err error
37+
for done := false; !done; done = bytesRead > 0 {
38+
bytesRead, err = conn.Read(buffer)
39+
if err != nil {
40+
panic(err)
41+
}
42+
}
43+
44+
fmt.Printf("Listener: read %d bytes\n", bytesRead)
45+
fmt.Printf("Listener: the sender sent: %s\n", string(buffer[:bytesRead]))
46+
fmt.Print("Listener: I am going to respond with \"asd\"\n")
47+
conn.Write([]byte("asd"))
48+
err = conn.Close()
49+
if err != nil {
50+
panic(err)
51+
}
52+
fmt.Println("Listener: conn.Close()")
53+
}

usage-example/run-test.sh

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/bin/bash -e
2+
3+
touch test.log
4+
5+
tail -f test.log &
6+
TAIL_PID=$!
7+
8+
go build -o ./tunnel ../main.go
9+
go build -o ./sender sender.go
10+
go build -o ./listener listener.go
11+
12+
# Start the server
13+
# tunnel mux port: 9056
14+
# management port: 9057
15+
./tunnel -mode server -configFile server-config.json 2>&1 >> test.log &
16+
SERVER_PID=$!
17+
18+
# Start the "listener" test app
19+
# It listens on port 9001. This would be your web application server.
20+
./listener 2>&1 >> test.log &
21+
LISTENER_PID=$!
22+
23+
sleep 1
24+
25+
# Post the tunnels config to the management port of the tunnel server
26+
# this would be done by the automation tool
27+
echo "tunnel configuration:"
28+
curl -s -X PUT -H "Content-Type: application/json" -d @tunnels.json localhost:9057/tunnels 2>&1 >> test.log
29+
echo ""
30+
echo ""
31+
32+
# Start the client
33+
# Client Identifier: TestClient1
34+
./tunnel -mode client -configFile client-config.json 2>&1 >> test.log &
35+
CLIENT_PID=$!
36+
37+
sleep 1
38+
39+
# Start the "sender" test app
40+
# It listens on port 9001. This would be your end user who wants to use the web application.
41+
./sender 2>&1 >> test.log &
42+
SENDER_PID=$!
43+
44+
sleep 1
45+
46+
echo "Wait 3 seconds then exit. " >> test.log
47+
48+
sleep 3
49+
50+
kill -TERM $SERVER_PID
51+
kill -TERM $CLIENT_PID
52+
kill -TERM $LISTENER_PID
53+
kill -TERM $TAIL_PID
54+
55+
rm test.log
56+
rm tunnel
57+
rm sender
58+
rm listener

usage-example/sender.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"net"
6+
)
7+
8+
func main() {
9+
10+
fmt.Println("Sender: I am dialing localhost:9000")
11+
12+
conn, err := net.Dial("tcp", "localhost:9000")
13+
if err != nil {
14+
panic(err)
15+
}
16+
sent, err := conn.Write([]byte("Hello ! Hello! \n"))
17+
if err != nil {
18+
panic(err)
19+
}
20+
fmt.Printf("Sender: sent %d bytes\n", sent)
21+
22+
buffer := make([]byte, 4096, 4096)
23+
bytesRead := 0
24+
for done := false; !done; done = bytesRead > 0 {
25+
bytesRead, err = conn.Read(buffer)
26+
if err != nil {
27+
panic(err)
28+
}
29+
}
30+
31+
fmt.Printf("Sender: read %d bytes\n", bytesRead)
32+
fmt.Printf("Sender: Response from listener was: %s\n", string(buffer[:bytesRead]))
33+
34+
//conn.Close()
35+
}

usage-example/server-config.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
{
3+
"DebugLog": false,
4+
"TunnelControlPort": 9056,
5+
"ManagementPort": 9057
6+
}

usage-example/tunnels.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
{
3+
"ClientIdentifier": "TestClient1",
4+
"FrontEndListenPort": 9000,
5+
"BackEndPort": 9001,
6+
"ProxyProtocol": true
7+
}
8+
]

0 commit comments

Comments
 (0)