cloudflare/cloudflared

Public

mirrored from https://github.com/cloudflare/cloudflaredAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2024.1.2

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

connection/control.go

128lines · modecode

1package connection
2
3import (
4 "context"
5 "io"
6 "net"
7 "time"
8
9 "github.com/rs/zerolog"
10
11 "github.com/cloudflare/cloudflared/management"
12 tunnelpogs "github.com/cloudflare/cloudflared/tunnelrpc/pogs"
13)
14
15// RPCClientFunc derives a named tunnel rpc client that can then be used to register and unregister connections.
16type RPCClientFunc func(context.Context, io.ReadWriteCloser, *zerolog.Logger) NamedTunnelRPCClient
17
18type controlStream struct {
19 observer *Observer
20
21 connectedFuse ConnectedFuse
22 namedTunnelProperties *NamedTunnelProperties
23 connIndex uint8
24 edgeAddress net.IP
25 protocol Protocol
26
27 newRPCClientFunc RPCClientFunc
28
29 gracefulShutdownC <-chan struct{}
30 gracePeriod time.Duration
31 stoppedGracefully bool
32}
33
34// ControlStreamHandler registers connections with origintunneld and initiates graceful shutdown.
35type ControlStreamHandler interface {
36 // ServeControlStream handles the control plane of the transport in the current goroutine calling this
37 ServeControlStream(ctx context.Context, rw io.ReadWriteCloser, connOptions *tunnelpogs.ConnectionOptions, tunnelConfigGetter TunnelConfigJSONGetter) error
38 // IsStopped tells whether the method above has finished
39 IsStopped() bool
40}
41
42type TunnelConfigJSONGetter interface {
43 GetConfigJSON() ([]byte, error)
44}
45
46// NewControlStream returns a new instance of ControlStreamHandler
47func NewControlStream(
48 observer *Observer,
49 connectedFuse ConnectedFuse,
50 namedTunnelConfig *NamedTunnelProperties,
51 connIndex uint8,
52 edgeAddress net.IP,
53 newRPCClientFunc RPCClientFunc,
54 gracefulShutdownC <-chan struct{},
55 gracePeriod time.Duration,
56 protocol Protocol,
57) ControlStreamHandler {
58 if newRPCClientFunc == nil {
59 newRPCClientFunc = newRegistrationRPCClient
60 }
61 return &controlStream{
62 observer: observer,
63 connectedFuse: connectedFuse,
64 namedTunnelProperties: namedTunnelConfig,
65 newRPCClientFunc: newRPCClientFunc,
66 connIndex: connIndex,
67 edgeAddress: edgeAddress,
68 gracefulShutdownC: gracefulShutdownC,
69 gracePeriod: gracePeriod,
70 protocol: protocol,
71 }
72}
73
74func (c *controlStream) ServeControlStream(
75 ctx context.Context,
76 rw io.ReadWriteCloser,
77 connOptions *tunnelpogs.ConnectionOptions,
78 tunnelConfigGetter TunnelConfigJSONGetter,
79) error {
80 rpcClient := c.newRPCClientFunc(ctx, rw, c.observer.log)
81
82 registrationDetails, err := rpcClient.RegisterConnection(ctx, c.namedTunnelProperties, connOptions, c.connIndex, c.edgeAddress, c.observer)
83 if err != nil {
84 rpcClient.Close()
85 return err
86 }
87
88 c.observer.logConnected(registrationDetails.UUID, c.connIndex, registrationDetails.Location, c.edgeAddress, c.protocol)
89 c.observer.sendConnectedEvent(c.connIndex, c.protocol, registrationDetails.Location)
90 c.connectedFuse.Connected()
91
92 // if conn index is 0 and tunnel is not remotely managed, then send local ingress rules configuration
93 if c.connIndex == 0 && !registrationDetails.TunnelIsRemotelyManaged {
94 if tunnelConfig, err := tunnelConfigGetter.GetConfigJSON(); err == nil {
95 if err := rpcClient.SendLocalConfiguration(ctx, tunnelConfig, c.observer); err != nil {
96 c.observer.log.Err(err).Msg("unable to send local configuration")
97 }
98 } else {
99 c.observer.log.Err(err).Msg("failed to obtain current configuration")
100 }
101 }
102
103 c.waitForUnregister(ctx, rpcClient)
104 return nil
105}
106
107func (c *controlStream) waitForUnregister(ctx context.Context, rpcClient NamedTunnelRPCClient) {
108 // wait for connection termination or start of graceful shutdown
109 defer rpcClient.Close()
110 select {
111 case <-ctx.Done():
112 break
113 case <-c.gracefulShutdownC:
114 c.stoppedGracefully = true
115 }
116
117 c.observer.sendUnregisteringEvent(c.connIndex)
118 rpcClient.GracefulShutdown(ctx, c.gracePeriod)
119 c.observer.log.Info().
120 Int(management.EventTypeKey, int(management.Cloudflared)).
121 Uint8(LogFieldConnIndex, c.connIndex).
122 IPAddr(LogFieldIPAddress, c.edgeAddress).
123 Msg("Unregistered tunnel connection")
124}
125
126func (c *controlStream) IsStopped() bool {
127 return c.stoppedGracefully
128}
129