-
Notifications
You must be signed in to change notification settings - Fork 101
Expand file tree
/
Copy pathmsg.go
More file actions
447 lines (383 loc) · 13.3 KB
/
msg.go
File metadata and controls
447 lines (383 loc) · 13.3 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
package proto
import (
"errors"
"regexp"
"strings"
"time"
"golang.ngrok.com/muxado/v2"
"golang.ngrok.com/ngrok/v2/internal/pb"
)
type ReqType muxado.StreamType
// NOTE(alan)
// never change the number of a message type that has already been assigned,
// you will break the protocol
const (
// sent from the client to the server
AuthReq ReqType = 0
BindReq ReqType = 1
UnbindReq ReqType = 2
StartTunnelWithLabelReq ReqType = 7
// sent from the server to the client
ProxyReq ReqType = 3
RestartReq ReqType = 4
StopReq ReqType = 5
UpdateReq ReqType = 6
StopTunnelReq ReqType = 9
// sent from client to the server
SrvInfoReq ReqType = 8
)
var Version = []string{"3", "2"} // integers in priority order
// Match the error code in the format (ERR_NGROK_\d+).
var ngrokErrorCodeRegex = regexp.MustCompile(`(ERR_NGROK_\d+)`)
type ngrokError struct {
Inner error
}
func WrapError(err error) error {
return ngrokError{Inner: err}
}
func StringError(msg string) error {
return ngrokError{Inner: errors.New(msg)}
}
func (ne ngrokError) Error() string {
return ne.Inner.Error()
}
func (ne ngrokError) Unwrap() error {
return ne.Inner
}
func (ne ngrokError) Msg() string {
errMsg := ne.Inner.Error()
out := []string{}
lines := strings.SplitSeq(errMsg, "\n")
for line := range lines {
line = strings.Trim(line, " \t\n\r")
if line == "" || ngrokErrorCodeRegex.MatchString(line) {
continue
}
out = append(out, line)
}
return strings.Join(out, "\n")
}
func (ne ngrokError) ErrorCode() string {
errMsg := ne.Inner.Error()
matches := ngrokErrorCodeRegex.FindStringSubmatch(errMsg)
if len(matches) == 2 {
return matches[1]
}
return ""
}
// When a client opens a new control channel to the server it must start by
// sending an Auth message.
type Auth struct {
Version []string // protocol versions supported, ordered by preference
ClientID string `json:"ClientId"` // empty for new sessions
Extra AuthExtra // clients may add whatever data the like to auth messages
}
type ObfuscatedString string
func (t ObfuscatedString) String() string {
return "HIDDEN"
}
func (t ObfuscatedString) PlainText() string {
return string(t)
}
type AuthExtra struct {
OS string
Arch string
Authtoken ObfuscatedString
Version string
Hostname string
UserAgent string
Metadata string
Cookie string
HeartbeatInterval int64
HeartbeatTolerance int64
Fingerprint *Fingerprint
// for each remote operation, these variables define whether the ngrok
// client is capable of executing that operation. each capability
// is transmitted as a pointer to string, with the following meanings:
//
// null -> operation disallow because the ngrok agent version is too old.
// this is true because older clients will never set this value
//
// "" (empty string) -> the operation is supported
//
// non-empty string -> the operation is not supported and this value is the user-facing
// error message describing why it is not supported
UpdateUnsupportedError *string
StopUnsupportedError *string
RestartUnsupportedError *string
ProxyType string
MutualTLS bool
ServiceRun bool
ConfigVersion string
CustomInterface bool
CustomCAs bool
ClientType ClientType // The type of client this is. Currently agent and library clients are supported
// The leg number of the client connection associated with this session.
// Defaults to zero, will be 1 or more for the additional connected
// leg(s) when multi-leg is engaged.
LegNumber uint32
}
type ClientType string
const (
LibraryOfficialGo ClientType = "ngrok-go"
)
// Note: entirely unused
type Fingerprint struct {
M []string
D []string
}
// A server responds to an Auth message with an
// AuthResp message over the control channel.Mutual
//
// If Error is not the empty string
// the server has indicated it will not accept
// the new session and will close the connection.
//
// The server response includes a unique ClientId
// that is used to associate and authenticate future
// proxy connections via the same field in RegProxy messages.
type AuthResp struct {
Version string // protocol version chosen
ClientID string `json:"ClientId"`
Error string
Extra AuthRespExtra
}
type AgentVersionDeprecated struct {
NextMin string
NextDate time.Time
Msg string
}
func (avd *AgentVersionDeprecated) Error() string {
when := "at your earliest convenience."
to := ""
if !avd.NextDate.IsZero() {
when = "by " + avd.NextDate.Format(time.DateOnly) + "."
}
if avd.NextMin != "" {
to = "to " + avd.NextMin + " or later "
}
return "Your agent is deprecated. Please update " + to + when
}
type ConnectAddress struct {
Region string
ServerAddr string
}
type AuthRespExtra struct {
Version string // server version
Region string // server region
// Encrypted server.PersistentSession object.
Cookie string
AccountName string
// Duration in seconds
SessionDuration int64
PlanName string
Banner string
DeprecationWarning *AgentVersionDeprecated
ConnectAddresses []ConnectAddress
AgentSessionID string
}
// A client sends this message to the server over a new stream
// to request the server bind a remote port/hostname on the client's behalf.
type Bind struct {
ID string `json:"-"`
ClientID string `json:"Id"` // a session-unique bind ID generated by the client, if empty, one is generated
Proto string // the protocol to bind (one of 'http', 'https', 'tcp', 'tls', 'ssh')
ForwardsTo string // the address of the upstream service the ngrok agent will forward to
ForwardsProto string // the L7 protocol the upstream service is expecting (one of '', 'http1', 'http2')
Opts any // options for the bind - protocol dependent
Extra BindExtra // anything extra the application wants to send
}
type BindExtra struct {
Name string
Token string
IPPolicyRef string
Metadata string
Description string
Bindings []string
PoolingEnabled bool
}
// The server responds with a BindResp message to notify the client of the
// success or failure of a bind.
type BindResp struct {
ClientID string `json:"Id"` // a session-unique bind ID generated by the client, if empty, one is generated
URL string // public URL of the bind (a human friendly combination of Hostname/Port/Proto/Opts)
Proto string // protocol bound on
Opts any // protocol-specific options that were chosen
Error string // error message is the server failed to bind
Extra BindRespExtra // application-defined extra values
}
type BindRespExtra struct {
Token string
Region string
CreatedAt int64 // unix timestamp in seconds when the tunnel was created
UpdatedAt int64 // unix timestamp in seconds when the tunnel was last updated
TunnelSessionID string // ID of the session that created this tunnel
TunnelID string // ID of the tunnel resource
}
// A client sends this message to the server over a new stream
// to request the server start a new tunnel with the given labels on the client's behalf.
type StartTunnelWithLabel struct {
// ID string `json:"-"` // a session-unique bind ID generated by the client, if empty, one is generated
Labels map[string]string // labels for tunnel group membership
ForwardsTo string // the address of the upstream service the ngrok agent will forward to
ForwardsProto string // the L7 protocol the upstream service is expecting (one of '', 'http1', 'http2')
Metadata string
}
// The server responds with a StartTunnelWithLabelResp message to notify the client of the
// success or failure of the tunnel and label creation.
type StartTunnelWithLabelResp struct {
ID string `json:"Id"`
Error string // error message is the server failed to bind
}
type ProxyProto int32
// in sync with rpx.Tunnel_ProxyProto
const (
ProxyProtoNone = 0
ProxyProtoV1 = 1
ProxyProtoV2 = 2
)
func ParseProxyProto(proxyProto string) (ProxyProto, bool) {
switch proxyProto {
case "":
return ProxyProtoNone, true
case "1":
return ProxyProtoV1, true
case "2":
return ProxyProtoV2, true
default:
return ProxyProtoNone, false
}
}
type HTTPEndpoint struct {
URL string
Domain string
Hostname string // public hostname of the bind
Subdomain string
Auth string
HostHeaderRewrite bool // true if the request's host header is being rewritten
LocalURLScheme string // scheme of the local forward
ProxyProto
// middleware
Compression *pb.MiddlewareConfiguration_Compression
CircuitBreaker *pb.MiddlewareConfiguration_CircuitBreaker
IPRestriction *pb.MiddlewareConfiguration_IPRestriction
BasicAuth *pb.MiddlewareConfiguration_BasicAuth
OAuth *pb.MiddlewareConfiguration_OAuth
OIDC *pb.MiddlewareConfiguration_OIDC
WebhookVerification *pb.MiddlewareConfiguration_WebhookVerification
MutualTLSCA *pb.MiddlewareConfiguration_MutualTLS
RequestHeaders *pb.MiddlewareConfiguration_Headers
ResponseHeaders *pb.MiddlewareConfiguration_Headers
WebsocketTCPConverter *pb.MiddlewareConfiguration_WebsocketTCPConverter
UserAgentFilter *pb.MiddlewareConfiguration_UserAgentFilter
Policy *pb.MiddlewareConfiguration_Policy
TrafficPolicy string
}
type TCPEndpoint struct {
URL string
Addr string
ProxyProto
// middleware
IPRestriction *pb.MiddlewareConfiguration_IPRestriction
Policy *pb.MiddlewareConfiguration_Policy
TrafficPolicy string
}
type TLSEndpoint struct {
URL string
Domain string
Hostname string // public hostname of the bind
Subdomain string
ProxyProto
MutualTLSAtAgent bool
// edge termination options
MutualTLSAtEdge *pb.MiddlewareConfiguration_MutualTLS
TLSTermination *pb.MiddlewareConfiguration_TLSTermination
IPRestriction *pb.MiddlewareConfiguration_IPRestriction
Policy *pb.MiddlewareConfiguration_Policy
TrafficPolicy string
}
type SSHOptions struct {
Hostname string // public hostname of the bind
Username string
Password string
ProxyProto
}
type LabelOptions struct {
Labels map[string]string
}
// A client sends this message to the server over a new stream to request the
// server close a bind
type Unbind struct {
ID string `json:"-"`
ClientID string `json:"Id"` // Id of the bind to close
Extra any // application-defined
}
// The server responds with an UnbindResp message to notify the client of the
// success or failure of the unbind.
type UnbindResp struct {
Error string // an error, if the unbind failed
Extra any // application-defined
}
type EdgeType int32
// in sync with rpx.EdgesTypes_Edge
const (
EdgeTypeUndefined EdgeType = 0
EdgeTypeTCP = 1
EdgeTypeTLS = 2
EdgeTypeHTTPS = 3
)
func ParseEdgeType(et string) (EdgeType, bool) {
switch et {
case "", "0":
return EdgeTypeUndefined, true
case "1":
return EdgeTypeTCP, true
case "2":
return EdgeTypeTLS, true
case "3":
return EdgeTypeHTTPS, true
default:
return EdgeTypeUndefined, false
}
}
// This message is sent first over a new stream from the server to the client to
// provide it with metadata about the connection it will tunnel over the stream.
type ProxyHeader struct {
ID string `json:"Id"` // Bind ID this connection is being proxied for
ClientAddr string // Network address of the client initiating the connection to the tunnel
Proto string // Protocol of the stream
EdgeType string // Type of edge
PassthroughTLS bool // true if the session is passing tls encrypted traffic to the agent
}
// This request is sent from the server to the ngrok agent asking it to immediately terminate itself
type Stop struct{}
// This client responds with StopResponse to the ngrok server to acknowledge it will shutdown
type StopResp struct {
Error string // an error, if one occurred, while requesting a Stop
}
// This request is sent from the server to the ngrok agent asking it to restart itself
type Restart struct{}
// The client responds with RestartResponse to the ngrok server to acknowledge it will restart
type RestartResp struct {
Error string // an error, if one occurred, while trying to restart. empty on OK
}
// This request is sent from the server to the ngrok agent asking it to update itself to
// a new version.
type Update struct {
Version string // the version to update to. if empty, the ngrok agent will update itself to the latest version
PermitMajorVersion bool // whether the caller has permitted a major version update
}
// The client responds with UpdateResponse to the ngrok server to acknowledge it will update
type UpdateResp struct {
Error string // an error, if one
}
// This request is sent from the server to the ngrok agent to request a tunnel to close, with a notice to display to the user
type StopTunnel struct {
ClientID string `json:"Id"` // a session-unique bind ID generated by the client
Message string // an message to display to the user
ErrorCode string // an error code to display to the user. empty on OK
}
type SrvInfo struct{}
type SrvInfoResp struct {
Region string
}