cloudflare/cloudflared

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2021.12.4

Branches

Tags

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

Clone

HTTPS

Download ZIP

cmd/cloudflared/access/carrier.go

136lines · modecode

1package access
2
3import (
4 "crypto/tls"
5 "fmt"
6 "net/http"
7 "strings"
8
9 "github.com/pkg/errors"
10 "github.com/rs/zerolog"
11 "github.com/urfave/cli/v2"
12
13 "github.com/cloudflare/cloudflared/carrier"
14 "github.com/cloudflare/cloudflared/config"
15 "github.com/cloudflare/cloudflared/logger"
16 "github.com/cloudflare/cloudflared/validation"
17)
18
19const (
20 LogFieldHost = "host"
21 cfAccessClientIDHeader = "Cf-Access-Client-Id"
22 cfAccessClientSecretHeader = "Cf-Access-Client-Secret"
23)
24
25// StartForwarder starts a client side websocket forward
26func StartForwarder(forwarder config.Forwarder, shutdown <-chan struct{}, log *zerolog.Logger) error {
27 validURL, err := validation.ValidateUrl(forwarder.Listener)
28 if err != nil {
29 return errors.Wrap(err, "error validating origin URL")
30 }
31
32 // get the headers from the config file and add to the request
33 headers := make(http.Header)
34 if forwarder.TokenClientID != "" {
35 headers.Set(cfAccessClientIDHeader, forwarder.TokenClientID)
36 }
37
38 if forwarder.TokenSecret != "" {
39 headers.Set(cfAccessClientSecretHeader, forwarder.TokenSecret)
40 }
41
42 carrier.SetBastionDest(headers, forwarder.Destination)
43
44 options := &carrier.StartOptions{
45 OriginURL: forwarder.URL,
46 Headers: headers, //TODO: TUN-2688 support custom headers from config file
47 }
48
49 // we could add a cmd line variable for this bool if we want the SOCK5 server to be on the client side
50 wsConn := carrier.NewWSConnection(log)
51
52 log.Info().Str(LogFieldHost, validURL.Host).Msg("Start Websocket listener")
53 return carrier.StartForwarder(wsConn, validURL.Host, shutdown, options)
54}
55
56// ssh will start a WS proxy server for server mode
57// or copy from stdin/stdout for client mode
58// useful for proxying other protocols (like ssh) over websockets
59// (which you can put Access in front of)
60func ssh(c *cli.Context) error {
61 log := logger.CreateSSHLoggerFromContext(c, logger.EnableTerminalLog)
62
63 // get the hostname from the cmdline and error out if its not provided
64 rawHostName := c.String(sshHostnameFlag)
65 hostname, err := validation.ValidateHostname(rawHostName)
66 if err != nil || rawHostName == "" {
67 return cli.ShowCommandHelp(c, "ssh")
68 }
69 originURL := ensureURLScheme(hostname)
70
71 // get the headers from the cmdline and add them
72 headers := buildRequestHeaders(c.StringSlice(sshHeaderFlag))
73 if c.IsSet(sshTokenIDFlag) {
74 headers.Set(cfAccessClientIDHeader, c.String(sshTokenIDFlag))
75 }
76 if c.IsSet(sshTokenSecretFlag) {
77 headers.Set(cfAccessClientSecretHeader, c.String(sshTokenSecretFlag))
78 }
79
80 carrier.SetBastionDest(headers, c.String(sshDestinationFlag))
81
82 options := &carrier.StartOptions{
83 OriginURL: originURL,
84 Headers: headers,
85 Host: hostname,
86 }
87
88 if connectTo := c.String(sshConnectTo); connectTo != "" {
89 parts := strings.Split(connectTo, ":")
90 switch len(parts) {
91 case 1:
92 options.OriginURL = fmt.Sprintf("https://%s", parts[0])
93 case 2:
94 options.OriginURL = fmt.Sprintf("https://%s:%s", parts[0], parts[1])
95 case 3:
96 options.OriginURL = fmt.Sprintf("https://%s:%s", parts[2], parts[1])
97 options.TLSClientConfig = &tls.Config{
98 InsecureSkipVerify: true,
99 ServerName: parts[0],
100 }
101 log.Warn().Msgf("Using insecure SSL connection because SNI overridden to %s", parts[0])
102 default:
103 return fmt.Errorf("invalid connection override: %s", connectTo)
104 }
105 }
106
107 // we could add a cmd line variable for this bool if we want the SOCK5 server to be on the client side
108 wsConn := carrier.NewWSConnection(log)
109
110 if c.NArg() > 0 || c.IsSet(sshURLFlag) {
111 forwarder, err := config.ValidateUrl(c, true)
112 if err != nil {
113 log.Err(err).Msg("Error validating origin URL")
114 return errors.Wrap(err, "error validating origin URL")
115 }
116 log.Info().Str(LogFieldHost, forwarder.Host).Msg("Start Websocket listener")
117 err = carrier.StartForwarder(wsConn, forwarder.Host, shutdownC, options)
118 if err != nil {
119 log.Err(err).Msg("Error on Websocket listener")
120 }
121 return err
122 }
123
124 return carrier.StartClient(wsConn, &carrier.StdinoutStream{}, options)
125}
126
127func buildRequestHeaders(values []string) http.Header {
128 headers := make(http.Header)
129 for _, valuePair := range values {
130 split := strings.Split(valuePair, ":")
131 if len(split) > 1 {
132 headers.Add(strings.TrimSpace(split[0]), strings.TrimSpace(split[1]))
133 }
134 }
135 return headers
136}
137