diff --git a/carrier/carrier.go b/carrier/carrier.go index a3787c4d..771dab9e 100644 --- a/carrier/carrier.go +++ b/carrier/carrier.go @@ -4,6 +4,7 @@ package carrier import ( + "crypto/tls" "io" "net" "net/http" @@ -20,8 +21,10 @@ import ( const LogFieldOriginURL = "originURL" type StartOptions struct { - OriginURL string - Headers http.Header + OriginURL string + Headers http.Header + Host string + TLSClientConfig *tls.Config } // Connection wraps up all the needed functions to forward over the tunnel diff --git a/carrier/websocket.go b/carrier/websocket.go index 704d3d5c..7a5976fa 100644 --- a/carrier/websocket.go +++ b/carrier/websocket.go @@ -82,11 +82,17 @@ func createWebsocketStream(options *StartOptions, log *zerolog.Logger) (*cfwebso return nil, err } req.Header = options.Headers + if options.Host != "" { + req.Host = options.Host + } dump, err := httputil.DumpRequest(req, false) log.Debug().Msgf("Websocket request: %s", string(dump)) - wsConn, resp, err := cfwebsocket.ClientConnect(req, nil) + dialer := &websocket.Dialer{ + TLSClientConfig: options.TLSClientConfig, + } + wsConn, resp, err := cfwebsocket.ClientConnect(req, dialer) defer closeRespBody(resp) if err != nil && IsAccessResponse(resp) { diff --git a/cmd/cloudflared/access/carrier.go b/cmd/cloudflared/access/carrier.go index b775ca92..c0fdaf71 100644 --- a/cmd/cloudflared/access/carrier.go +++ b/cmd/cloudflared/access/carrier.go @@ -1,6 +1,8 @@ package access import ( + "crypto/tls" + "fmt" "net/http" "strings" @@ -84,6 +86,26 @@ func ssh(c *cli.Context) error { options := &carrier.StartOptions{ OriginURL: originURL, Headers: headers, + Host: hostname, + } + + if connectTo := c.String(sshConnectTo); connectTo != "" { + parts := strings.Split(connectTo, ":") + switch len(parts) { + case 1: + options.OriginURL = fmt.Sprintf("https://%s", parts[0]) + case 2: + options.OriginURL = fmt.Sprintf("https://%s:%s", parts[0], parts[1]) + case 3: + options.OriginURL = fmt.Sprintf("https://%s:%s", parts[2], parts[1]) + options.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, + ServerName: parts[0], + } + log.Warn().Msgf("Using insecure SSL connection because SNI overridden to %s", parts[0]) + default: + return fmt.Errorf("invalid connection override: %s", connectTo) + } } // we could add a cmd line variable for this bool if we want the SOCK5 server to be on the client side diff --git a/cmd/cloudflared/access/cmd.go b/cmd/cloudflared/access/cmd.go index f9049c69..e622aad8 100644 --- a/cmd/cloudflared/access/cmd.go +++ b/cmd/cloudflared/access/cmd.go @@ -33,6 +33,7 @@ const ( sshTokenIDFlag = "service-token-id" sshTokenSecretFlag = "service-token-secret" sshGenCertFlag = "short-lived-cert" + sshConnectTo = "connect-to" sshConfigTemplate = ` Add to your {{.Home}}/.ssh/config: @@ -54,7 +55,7 @@ Host cfpipe-{{.Hostname}} const sentryDSN = "https://56a9c9fa5c364ab28f34b14f35ea0f1b@sentry.io/189878" var ( - shutdownC chan struct{} + shutdownC chan struct{} ) // Init will initialize and store vars from the main program @@ -164,6 +165,11 @@ func Commands() []*cli.Command { Aliases: []string{"loglevel"}, //added to match the tunnel side Usage: "Application logging level {fatal, error, info, debug}. ", }, + &cli.StringFlag{ + Name: sshConnectTo, + Hidden: true, + Usage: "Connect to alternate location for testing, value is host, host:port, or sni:port:host", + }, }, }, {