main.go
3.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package server
import (
"crypto/tls"
"math/rand"
"ngrok/conn"
log "ngrok/log"
"ngrok/msg"
"ngrok/util"
"os"
"runtime/debug"
"time"
)
const (
registryCacheSize uint64 = 1024 * 1024 // 1 MB
connReadTimeout time.Duration = 10 * time.Second
)
// GLOBALS
var (
tunnelRegistry *TunnelRegistry
controlRegistry *ControlRegistry
// XXX: kill these global variables - they're only used in tunnel.go for constructing forwarding URLs
opts *Options
listeners map[string]*conn.Listener
)
func NewProxy(pxyConn conn.Conn, regPxy *msg.RegProxy) {
// fail gracefully if the proxy connection fails to register
defer func() {
if r := recover(); r != nil {
pxyConn.Warn("Failed with error: %v", r)
pxyConn.Close()
}
}()
// set logging prefix
pxyConn.SetType("pxy")
// look up the control connection for this proxy
pxyConn.Info("Registering new proxy for %s", regPxy.ClientId)
ctl := controlRegistry.Get(regPxy.ClientId)
if ctl == nil {
panic("No client found for identifier: " + regPxy.ClientId)
}
ctl.RegisterProxy(pxyConn)
}
// Listen for incoming control and proxy connections
// We listen for incoming control and proxy connections on the same port
// for ease of deployment. The hope is that by running on port 443, using
// TLS and running all connections over the same port, we can bust through
// restrictive firewalls.
func tunnelListener(addr string, tlsConfig *tls.Config) {
// listen for incoming connections
listener, err := conn.Listen(addr, "tun", tlsConfig)
if err != nil {
panic(err)
}
log.Info("Listening for control and proxy connections on %s", listener.Addr.String())
for c := range listener.Conns {
go func(tunnelConn conn.Conn) {
// don't crash on panics
defer func() {
if r := recover(); r != nil {
tunnelConn.Info("tunnelListener failed with error %v: %s", r, debug.Stack())
}
}()
tunnelConn.SetReadDeadline(time.Now().Add(connReadTimeout))
var rawMsg msg.Message
if rawMsg, err = msg.ReadMsg(tunnelConn); err != nil {
tunnelConn.Warn("Failed to read message: %v", err)
tunnelConn.Close()
return
}
// don't timeout after the initial read, tunnel heartbeating will kill
// dead connections
tunnelConn.SetReadDeadline(time.Time{})
switch m := rawMsg.(type) {
case *msg.Auth:
NewControl(tunnelConn, m)
case *msg.RegProxy:
NewProxy(tunnelConn, m)
default:
tunnelConn.Close()
}
}(c)
}
}
func Main() {
// parse options
opts = parseArgs()
// init logging
log.LogTo(opts.logto, opts.loglevel)
// seed random number generator
seed, err := util.RandomSeed()
if err != nil {
panic(err)
}
rand.Seed(seed)
// init tunnel/control registry
registryCacheFile := os.Getenv("REGISTRY_CACHE_FILE")
tunnelRegistry = NewTunnelRegistry(registryCacheSize, registryCacheFile)
controlRegistry = NewControlRegistry()
// start listeners
listeners = make(map[string]*conn.Listener)
// load tls configuration
tlsConfig, err := LoadTLSConfig(opts.tlsCrt, opts.tlsKey)
if err != nil {
panic(err)
}
//log.Info("start config main")
//Add by jannson, start config http server
go ConfigMain()
// listen for http
if opts.httpAddr != "" {
listeners["http"] = startHttpListener(opts.httpAddr, nil)
}
// listen for https
if opts.httpsAddr != "" {
listeners["https"] = startHttpListener(opts.httpsAddr, tlsConfig)
}
// ngrok clients
tunnelListener(opts.tunnelAddr, tlsConfig)
}