2018-10-08 19:20:28 +00:00
package tunnel
import (
2020-03-27 14:39:59 +00:00
"bufio"
2019-06-17 21:18:47 +00:00
"context"
2018-10-08 19:20:28 +00:00
"fmt"
"io/ioutil"
2018-09-21 15:18:23 +00:00
"net"
2020-05-04 20:15:17 +00:00
"net/http"
2018-10-19 20:44:35 +00:00
"net/url"
2018-10-08 19:20:28 +00:00
"os"
2019-11-12 18:50:41 +00:00
"reflect"
2019-07-18 21:29:16 +00:00
"runtime"
2018-10-08 19:20:28 +00:00
"runtime/trace"
2020-09-25 02:33:12 +00:00
"strconv"
2020-04-30 05:02:08 +00:00
"strings"
2018-10-08 19:20:28 +00:00
"sync"
"time"
2019-08-26 20:56:17 +00:00
"github.com/cloudflare/cloudflared/awsuploader"
2019-06-17 21:18:47 +00:00
"github.com/cloudflare/cloudflared/cmd/cloudflared/buildinfo"
2020-05-18 18:24:17 +00:00
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
2018-10-08 19:20:28 +00:00
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
2020-07-29 22:48:27 +00:00
"github.com/cloudflare/cloudflared/cmd/cloudflared/ui"
2018-10-08 19:20:28 +00:00
"github.com/cloudflare/cloudflared/cmd/cloudflared/updater"
2019-11-12 18:50:41 +00:00
"github.com/cloudflare/cloudflared/dbconnect"
2020-05-04 20:15:17 +00:00
"github.com/cloudflare/cloudflared/h2mux"
2018-10-08 19:20:28 +00:00
"github.com/cloudflare/cloudflared/hello"
2020-04-29 20:51:32 +00:00
"github.com/cloudflare/cloudflared/logger"
2018-10-08 19:20:28 +00:00
"github.com/cloudflare/cloudflared/metrics"
"github.com/cloudflare/cloudflared/origin"
2019-03-04 19:48:56 +00:00
"github.com/cloudflare/cloudflared/signal"
2020-03-31 14:56:22 +00:00
"github.com/cloudflare/cloudflared/socks"
2019-08-26 20:25:24 +00:00
"github.com/cloudflare/cloudflared/sshlog"
2019-07-18 21:29:16 +00:00
"github.com/cloudflare/cloudflared/sshserver"
2019-05-28 20:53:35 +00:00
"github.com/cloudflare/cloudflared/tlsconfig"
2018-10-08 19:20:28 +00:00
"github.com/cloudflare/cloudflared/tunneldns"
2020-07-30 17:00:57 +00:00
"github.com/cloudflare/cloudflared/tunnelstore"
2018-09-21 15:18:23 +00:00
"github.com/cloudflare/cloudflared/websocket"
2019-07-18 21:29:16 +00:00
2018-10-08 19:20:28 +00:00
"github.com/coreos/go-systemd/daemon"
"github.com/facebookgo/grace/gracenet"
2019-07-18 21:29:16 +00:00
"github.com/getsentry/raven-go"
"github.com/gliderlabs/ssh"
"github.com/google/uuid"
2020-04-28 00:55:27 +00:00
"github.com/mitchellh/go-homedir"
2018-10-08 19:20:28 +00:00
"github.com/pkg/errors"
2020-08-05 10:49:53 +00:00
"github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc"
2018-10-08 19:20:28 +00:00
)
2019-08-28 15:48:30 +00:00
const (
2019-08-26 20:56:17 +00:00
sentryDSN = "https://56a9c9fa5c364ab28f34b14f35ea0f1b:3e8827f6f9f740738eb11138f7bebb68@sentry.io/189878"
2019-10-02 20:56:28 +00:00
sshLogFileDirectory = "/usr/local/var/log/cloudflared/"
2019-08-28 15:48:30 +00:00
// sshPortFlag is the port on localhost the cloudflared ssh server will run on
2019-08-26 20:56:17 +00:00
sshPortFlag = "local-ssh-port"
2019-08-28 15:48:30 +00:00
// sshIdleTimeoutFlag defines the duration a SSH session can remain idle before being closed
sshIdleTimeoutFlag = "ssh-idle-timeout"
// sshMaxTimeoutFlag defines the max duration a SSH session can remain open for
2019-08-26 20:56:17 +00:00
sshMaxTimeoutFlag = "ssh-max-timeout"
// bucketNameFlag is the bucket name to use for the SSH log uploader
bucketNameFlag = "bucket-name"
// regionNameFlag is the AWS region name to use for the SSH log uploader
regionNameFlag = "region-name"
// secretIDFlag is the Secret id of SSH log uploader
secretIDFlag = "secret-id"
// accessKeyIDFlag is the Access key id of SSH log uploader
accessKeyIDFlag = "access-key-id"
// sessionTokenIDFlag is the Session token of SSH log uploader
sessionTokenIDFlag = "session-token"
// s3URLFlag is the S3 URL of SSH log uploader (e.g. don't use AWS s3 and use google storage bucket instead)
s3URLFlag = "s3-url-host"
2019-09-04 16:14:27 +00:00
2019-10-17 21:23:06 +00:00
// hostKeyPath is the path of the dir to save SSH host keys too
hostKeyPath = "host-key-path"
2020-05-04 20:15:17 +00:00
//sshServerFlag enables cloudflared ssh proxy server
sshServerFlag = "ssh-server"
2020-03-31 14:56:22 +00:00
// socks5Flag is to enable the socks server to deframe
socks5Flag = "socks5"
2020-05-04 20:15:17 +00:00
// bastionFlag is to enable bastion, or jump host, operation
bastionFlag = "bastion"
2020-09-01 16:06:00 +00:00
// uiFlag is to enable launching cloudflared in interactive UI mode
uiFlag = "ui"
2020-06-05 15:18:40 +00:00
logDirectoryFlag = "log-directory"
2020-04-29 20:51:32 +00:00
debugLevelWarning = "At debug level, request URL, method, protocol, content legnth and header will be logged. " +
"Response status, content length and header will also be logged in debug level."
2019-08-28 15:48:30 +00:00
)
2018-10-08 19:20:28 +00:00
var (
shutdownC chan struct { }
graceShutdownC chan struct { }
version string
)
func Flags ( ) [ ] cli . Flag {
return tunnelFlags ( true )
}
func Commands ( ) [ ] * cli . Command {
cmds := [ ] * cli . Command {
{
Name : "login" ,
2020-05-18 18:24:17 +00:00
Action : cliutil . ErrorHandler ( login ) ,
2018-10-08 19:20:28 +00:00
Usage : "Generate a configuration file with your login details" ,
ArgsUsage : " " ,
Flags : [ ] cli . Flag {
& cli . StringFlag {
Name : "url" ,
Hidden : true ,
} ,
} ,
Hidden : true ,
} ,
{
Name : "proxy-dns" ,
2020-05-18 18:24:17 +00:00
Action : cliutil . ErrorHandler ( tunneldns . Run ) ,
2018-10-08 19:20:28 +00:00
Usage : "Run a DNS over HTTPS proxy server." ,
Flags : [ ] cli . Flag {
& cli . StringFlag {
Name : "metrics" ,
Value : "localhost:" ,
Usage : "Listen address for metrics reporting." ,
EnvVars : [ ] string { "TUNNEL_METRICS" } ,
} ,
& cli . StringFlag {
Name : "address" ,
Usage : "Listen address for the DNS over HTTPS proxy server." ,
Value : "localhost" ,
EnvVars : [ ] string { "TUNNEL_DNS_ADDRESS" } ,
} ,
& cli . IntFlag {
Name : "port" ,
Usage : "Listen on given port for the DNS over HTTPS proxy server." ,
Value : 53 ,
EnvVars : [ ] string { "TUNNEL_DNS_PORT" } ,
} ,
& cli . StringSliceFlag {
Name : "upstream" ,
Usage : "Upstream endpoint URL, you can specify multiple endpoints for redundancy." ,
Value : cli . NewStringSlice ( "https://1.1.1.1/dns-query" , "https://1.0.0.1/dns-query" ) ,
EnvVars : [ ] string { "TUNNEL_DNS_UPSTREAM" } ,
} ,
2020-04-04 20:49:36 +00:00
& cli . StringSliceFlag {
Name : "bootstrap" ,
Usage : "bootstrap endpoint URL, you can specify multiple endpoints for redundancy." ,
Value : cli . NewStringSlice ( "https://162.159.36.1/dns-query" , "https://162.159.46.1/dns-query" , "https://[2606:4700:4700::1111]/dns-query" , "https://[2606:4700:4700::1001]/dns-query" ) ,
EnvVars : [ ] string { "TUNNEL_DNS_BOOTSTRAP" } ,
} ,
2018-10-08 19:20:28 +00:00
} ,
ArgsUsage : " " , // can't be the empty string or we get the default output
Hidden : false ,
} ,
2019-11-12 18:50:41 +00:00
dbConnectCmd ( ) ,
2018-10-08 19:20:28 +00:00
}
var subcommands [ ] * cli . Command
for _ , cmd := range cmds {
c := * cmd
c . Hidden = false
subcommands = append ( subcommands , & c )
}
2020-07-30 17:00:57 +00:00
2020-05-21 20:36:49 +00:00
subcommands = append ( subcommands , buildCreateCommand ( ) )
subcommands = append ( subcommands , buildListCommand ( ) )
subcommands = append ( subcommands , buildDeleteCommand ( ) )
2020-06-16 22:43:22 +00:00
subcommands = append ( subcommands , buildRunCommand ( ) )
2020-07-03 08:55:11 +00:00
subcommands = append ( subcommands , buildCleanupCommand ( ) )
2020-07-06 08:01:48 +00:00
subcommands = append ( subcommands , buildRouteCommand ( ) )
2018-10-08 19:20:28 +00:00
2020-09-16 12:15:49 +00:00
cmds = append ( cmds , buildTunnelCommand ( subcommands ) )
return cmds
}
func buildTunnelCommand ( subcommands [ ] * cli . Command ) * cli . Command {
return & cli . Command {
2018-10-08 19:20:28 +00:00
Name : "tunnel" ,
2020-07-30 17:00:57 +00:00
Action : cliutil . ErrorHandler ( TunnelCommand ) ,
2018-10-08 19:20:28 +00:00
Before : Before ,
Category : "Tunnel" ,
Usage : "Make a locally-running web service accessible over the internet using Argo Tunnel." ,
2020-05-21 20:36:49 +00:00
ArgsUsage : " " ,
2018-10-08 19:20:28 +00:00
Description : ` Argo Tunnel asks you to specify a hostname on a Cloudflare - powered
domain you control and a local address . Traffic from that hostname is routed
( optionally via a Cloudflare Load Balancer ) to this machine and appears on the
specified port where it can be served .
This feature requires your Cloudflare account be subscribed to the Argo Smart Routing feature .
To use , begin by calling login to download a certificate :
2020-09-16 12:15:49 +00:00
$ cloudflared tunnel login
2018-10-08 19:20:28 +00:00
With your certificate installed you can then launch your first tunnel ,
replacing my . site . com with a subdomain of your site :
2020-09-16 12:15:49 +00:00
$ cloudflared tunnel -- hostname my . site . com -- url http : //localhost:8080
2018-10-08 19:20:28 +00:00
If you have a web server running on port 8080 ( in this example ) , it will be available on
the internet ! ` ,
Subcommands : subcommands ,
Flags : tunnelFlags ( false ) ,
2020-09-16 12:15:49 +00:00
}
2018-10-08 19:20:28 +00:00
}
2020-07-30 17:00:57 +00:00
func TunnelCommand ( c * cli . Context ) error {
2020-09-01 16:06:00 +00:00
if name := c . String ( "name" ) ; name != "" { // Start a named tunnel
2020-07-30 17:00:57 +00:00
return adhocNamedTunnel ( c , name )
2020-09-01 16:06:00 +00:00
} else { // Start a classic tunnel
return classicTunnel ( c )
2020-07-30 17:00:57 +00:00
}
2018-10-08 19:20:28 +00:00
}
func Init ( v string , s , g chan struct { } ) {
version , shutdownC , graceShutdownC = v , s , g
}
2020-07-30 17:00:57 +00:00
// adhocNamedTunnel create, route and run a named tunnel in one command
func adhocNamedTunnel ( c * cli . Context , name string ) error {
sc , err := newSubcommandContext ( c )
if err != nil {
return err
}
tunnel , ok , err := sc . tunnelActive ( name )
if err != nil || ! ok {
tunnel , err = sc . create ( name )
if err != nil {
return errors . Wrap ( err , "failed to create tunnel" )
}
} else {
sc . logger . Infof ( "Tunnel already created with ID %s" , tunnel . ID )
}
2020-09-01 16:06:00 +00:00
if r , ok := routeFromFlag ( c ) ; ok {
2020-09-17 20:19:47 +00:00
if res , err := sc . route ( tunnel . ID , r ) ; err != nil {
2020-07-30 17:00:57 +00:00
sc . logger . Errorf ( "failed to create route, please create it manually. err: %v." , err )
} else {
2020-09-17 20:19:47 +00:00
sc . logger . Infof ( res . SuccessSummary ( ) )
2020-07-30 17:00:57 +00:00
}
}
if err := sc . run ( tunnel . ID ) ; err != nil {
return errors . Wrap ( err , "error running tunnel" )
}
return nil
}
2020-09-01 16:06:00 +00:00
// classicTunnel creates a "classic" non-named tunnel
func classicTunnel ( c * cli . Context ) error {
sc , err := newSubcommandContext ( c )
if err != nil {
return err
}
return StartServer ( c , version , shutdownC , graceShutdownC , nil , sc . logger , sc . isUIEnabled )
}
func routeFromFlag ( c * cli . Context ) ( tunnelstore . Route , bool ) {
2020-07-30 17:00:57 +00:00
if hostname := c . String ( "hostname" ) ; hostname != "" {
if lbPool := c . String ( "lb-pool" ) ; lbPool != "" {
return tunnelstore . NewLBRoute ( hostname , lbPool ) , true
}
return tunnelstore . NewDNSRoute ( hostname ) , true
}
return nil , false
}
2020-09-01 16:06:00 +00:00
func createLogger ( c * cli . Context , isTransport bool , disableTerminal bool ) ( * logger . OutputWriter , error ) {
var loggerOpts [ ] logger . Option
2020-06-16 15:33:03 +00:00
logPath := c . String ( "logfile" )
2020-06-16 21:18:24 +00:00
if logPath == "" {
2020-06-16 15:33:03 +00:00
logPath = c . String ( logDirectoryFlag )
}
2020-04-29 20:51:32 +00:00
if logPath != "" {
loggerOpts = append ( loggerOpts , logger . DefaultFile ( logPath ) )
}
logLevel := c . String ( "loglevel" )
if isTransport {
logLevel = c . String ( "transport-loglevel" )
2020-06-11 16:08:05 +00:00
if logLevel == "" {
logLevel = "fatal"
}
2020-04-29 20:51:32 +00:00
}
loggerOpts = append ( loggerOpts , logger . LogLevelString ( logLevel ) )
2020-09-01 16:06:00 +00:00
if disableTerminal {
2020-07-24 22:17:17 +00:00
disableOption := logger . DisableTerminal ( true )
loggerOpts = append ( loggerOpts , disableOption )
}
2020-09-01 16:06:00 +00:00
l , err := logger . New ( loggerOpts ... )
2020-07-29 22:48:27 +00:00
if err != nil {
2020-09-01 16:06:00 +00:00
return nil , err
2020-07-29 22:48:27 +00:00
}
return l , nil
}
2020-09-01 16:06:00 +00:00
func StartServer (
c * cli . Context ,
version string ,
shutdownC ,
graceShutdownC chan struct { } ,
namedTunnel * origin . NamedTunnelConfig ,
log logger . Service ,
isUIEnabled bool ,
) error {
2019-01-07 20:30:22 +00:00
_ = raven . SetDSN ( sentryDSN )
2018-10-08 19:20:28 +00:00
var wg sync . WaitGroup
listeners := gracenet . Net { }
errC := make ( chan error )
2019-03-04 19:48:56 +00:00
connectedSignal := signal . New ( make ( chan struct { } ) )
2018-10-08 19:20:28 +00:00
dnsReadySignal := make ( chan struct { } )
if c . String ( "config" ) == "" {
2020-09-01 16:06:00 +00:00
log . Infof (
"Cannot determine default configuration path. No file %v in %v" ,
config . DefaultConfigFiles ,
config . DefaultConfigSearchDirectories ( ) ,
)
2018-10-08 19:20:28 +00:00
}
if c . IsSet ( "trace-output" ) {
tmpTraceFile , err := ioutil . TempFile ( "" , "trace" )
if err != nil {
2020-09-01 16:06:00 +00:00
log . Errorf ( "Failed to create new temporary file to save trace output: %s" , err )
2018-10-08 19:20:28 +00:00
}
defer func ( ) {
if err := tmpTraceFile . Close ( ) ; err != nil {
2020-09-01 16:06:00 +00:00
log . Errorf ( "Failed to close trace output file %s with error: %s" , tmpTraceFile . Name ( ) , err )
2018-10-08 19:20:28 +00:00
}
if err := os . Rename ( tmpTraceFile . Name ( ) , c . String ( "trace-output" ) ) ; err != nil {
2020-09-01 16:06:00 +00:00
log . Errorf ( "Failed to rename temporary trace output file %s to %s with error: %s" , tmpTraceFile . Name ( ) , c . String ( "trace-output" ) , err )
2018-10-08 19:20:28 +00:00
} else {
2019-01-07 20:30:22 +00:00
err := os . Remove ( tmpTraceFile . Name ( ) )
if err != nil {
2020-09-01 16:06:00 +00:00
log . Errorf ( "Failed to remove the temporary trace file %s with error: %s" , tmpTraceFile . Name ( ) , err )
2019-01-07 20:30:22 +00:00
}
2018-10-08 19:20:28 +00:00
}
} ( )
if err := trace . Start ( tmpTraceFile ) ; err != nil {
2020-09-01 16:06:00 +00:00
log . Errorf ( "Failed to start trace: %s" , err )
2018-10-08 19:20:28 +00:00
return errors . Wrap ( err , "Error starting tracing" )
}
defer trace . Stop ( )
}
2019-06-17 21:18:47 +00:00
buildInfo := buildinfo . GetBuildInfo ( version )
2020-09-01 16:06:00 +00:00
buildInfo . Log ( log )
logClientOptions ( c , log )
2018-10-08 19:20:28 +00:00
if c . IsSet ( "proxy-dns" ) {
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
2020-09-01 16:06:00 +00:00
errC <- runDNSProxyServer ( c , dnsReadySignal , shutdownC , log )
2018-10-08 19:20:28 +00:00
} ( )
} else {
close ( dnsReadySignal )
}
// Wait for proxy-dns to come up (if used)
<- dnsReadySignal
metricsListener , err := listeners . Listen ( "tcp" , c . String ( "metrics" ) )
if err != nil {
2020-09-01 16:06:00 +00:00
log . Errorf ( "Error opening metrics server listener: %s" , err )
2018-10-08 19:20:28 +00:00
return errors . Wrap ( err , "Error opening metrics server listener" )
}
defer metricsListener . Close ( )
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
2020-09-01 16:06:00 +00:00
errC <- metrics . ServeMetrics ( metricsListener , shutdownC , log )
2018-10-08 19:20:28 +00:00
} ( )
go notifySystemd ( connectedSignal )
if c . IsSet ( "pidfile" ) {
2020-09-01 16:06:00 +00:00
go writePidFile ( connectedSignal , c . String ( "pidfile" ) , log )
2018-10-08 19:20:28 +00:00
}
2019-06-17 21:18:47 +00:00
cloudflaredID , err := uuid . NewRandom ( )
if err != nil {
2020-09-01 16:06:00 +00:00
log . Errorf ( "Cannot generate cloudflared ID: %s" , err )
2019-06-17 21:18:47 +00:00
return err
}
ctx , cancel := context . WithCancel ( context . Background ( ) )
go func ( ) {
<- shutdownC
cancel ( )
} ( )
2019-06-18 16:47:29 +00:00
// update needs to be after DNS proxy is up to resolve equinox server address
2020-09-01 16:06:00 +00:00
if updater . IsAutoupdateEnabled ( c , log ) {
log . Infof ( "Autoupdate frequency is set to %v" , c . Duration ( "autoupdate-freq" ) )
2019-06-18 16:47:29 +00:00
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
2020-09-01 16:06:00 +00:00
autoupdater := updater . NewAutoUpdater ( c . Duration ( "autoupdate-freq" ) , & listeners , log )
2019-06-18 16:47:29 +00:00
errC <- autoupdater . Run ( ctx )
} ( )
}
2018-10-08 19:20:28 +00:00
// Serve DNS proxy stand-alone if no hostname or tag or app is going to run
if dnsProxyStandAlone ( c ) {
2019-03-04 19:48:56 +00:00
connectedSignal . Notify ( )
2018-10-08 19:20:28 +00:00
// no grace period, handle SIGINT/SIGTERM immediately
2020-09-01 16:06:00 +00:00
return waitToShutdown ( & wg , errC , shutdownC , graceShutdownC , 0 , log )
2018-10-08 19:20:28 +00:00
}
if c . IsSet ( "hello-world" ) {
2020-09-01 16:06:00 +00:00
log . Infof ( "hello-world set" )
2018-10-08 19:20:28 +00:00
helloListener , err := hello . CreateTLSListener ( "127.0.0.1:" )
if err != nil {
2020-09-01 16:06:00 +00:00
log . Errorf ( "Cannot start Hello World Server: %s" , err )
2018-10-08 19:20:28 +00:00
return errors . Wrap ( err , "Cannot start Hello World Server" )
}
defer helloListener . Close ( )
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
2020-09-01 16:06:00 +00:00
_ = hello . StartHelloWorldServer ( log , helloListener , shutdownC )
2018-10-08 19:20:28 +00:00
} ( )
2020-06-25 18:25:39 +00:00
forceSetFlag ( c , "url" , "https://" + helloListener . Addr ( ) . String ( ) )
2018-10-08 19:20:28 +00:00
}
2020-05-04 20:15:17 +00:00
if c . IsSet ( sshServerFlag ) {
2019-07-18 21:29:16 +00:00
if runtime . GOOS != "darwin" && runtime . GOOS != "linux" {
2019-09-10 23:50:04 +00:00
msg := fmt . Sprintf ( "--ssh-server is not supported on %s" , runtime . GOOS )
2020-09-01 16:06:00 +00:00
log . Error ( msg )
2019-09-10 23:50:04 +00:00
return errors . New ( msg )
2019-07-18 21:29:16 +00:00
}
2020-09-01 16:06:00 +00:00
log . Infof ( "ssh-server set" )
2019-07-18 21:29:16 +00:00
2019-09-03 21:28:06 +00:00
logManager := sshlog . NewEmptyManager ( )
2019-08-26 20:56:17 +00:00
if c . IsSet ( bucketNameFlag ) && c . IsSet ( regionNameFlag ) && c . IsSet ( accessKeyIDFlag ) && c . IsSet ( secretIDFlag ) {
uploader , err := awsuploader . NewFileUploader ( c . String ( bucketNameFlag ) , c . String ( regionNameFlag ) ,
c . String ( accessKeyIDFlag ) , c . String ( secretIDFlag ) , c . String ( sessionTokenIDFlag ) , c . String ( s3URLFlag ) )
if err != nil {
2019-09-10 23:50:04 +00:00
msg := "Cannot create uploader for SSH Server"
2020-09-01 16:06:00 +00:00
log . Errorf ( "%s: %s" , msg , err )
2019-09-10 23:50:04 +00:00
return errors . Wrap ( err , msg )
}
2019-10-02 20:56:28 +00:00
if err := os . MkdirAll ( sshLogFileDirectory , 0700 ) ; err != nil {
2019-09-10 23:50:04 +00:00
msg := fmt . Sprintf ( "Cannot create SSH log file directory %s" , sshLogFileDirectory )
2020-09-01 16:06:00 +00:00
log . Errorf ( "%s: %s" , msg , err )
2019-09-10 23:50:04 +00:00
return errors . Wrap ( err , msg )
2019-08-26 20:56:17 +00:00
}
2019-09-03 21:28:06 +00:00
logManager = sshlog . New ( sshLogFileDirectory )
2019-08-26 20:56:17 +00:00
2020-09-01 16:06:00 +00:00
uploadManager := awsuploader . NewDirectoryUploadManager ( log , uploader , sshLogFileDirectory , 30 * time . Minute , shutdownC )
2019-08-26 20:56:17 +00:00
uploadManager . Start ( )
}
2019-10-09 21:56:47 +00:00
localServerAddress := "127.0.0.1:" + c . String ( sshPortFlag )
2020-09-01 16:06:00 +00:00
server , err := sshserver . New ( logManager , log , version , localServerAddress , c . String ( "hostname" ) , c . Path ( hostKeyPath ) , shutdownC , c . Duration ( sshIdleTimeoutFlag ) , c . Duration ( sshMaxTimeoutFlag ) )
2019-07-18 21:29:16 +00:00
if err != nil {
2019-09-10 23:50:04 +00:00
msg := "Cannot create new SSH Server"
2020-09-01 16:06:00 +00:00
log . Errorf ( "%s: %s" , msg , err )
2019-09-10 23:50:04 +00:00
return errors . Wrap ( err , msg )
2019-07-18 21:29:16 +00:00
}
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
if err = server . Start ( ) ; err != nil && err != ssh . ErrServerClosed {
2020-09-01 16:06:00 +00:00
log . Errorf ( "SSH server error: %s" , err )
2019-10-16 15:53:46 +00:00
// TODO: remove when declarative tunnels are implemented.
close ( shutdownC )
2019-07-18 21:29:16 +00:00
}
} ( )
2020-06-25 18:25:39 +00:00
forceSetFlag ( c , "url" , "ssh://" + localServerAddress )
2019-07-18 21:29:16 +00:00
}
2020-06-05 20:10:09 +00:00
url := c . String ( "url" )
hostname := c . String ( "hostname" )
if url == hostname && url != "" && hostname != "" {
errText := "hostname and url shouldn't match. See --help for more information"
2020-09-01 16:06:00 +00:00
log . Error ( errText )
2020-06-05 20:10:09 +00:00
return fmt . Errorf ( errText )
}
2020-05-04 20:15:17 +00:00
if staticHost := hostnameFromURI ( c . String ( "url" ) ) ; isProxyDestinationConfigured ( staticHost , c ) {
2020-09-25 02:33:12 +00:00
listener , err := net . Listen ( "tcp" , net . JoinHostPort ( c . String ( "proxy-address" ) , strconv . Itoa ( c . Int ( "proxy-port" ) ) ) )
2018-09-21 15:18:23 +00:00
if err != nil {
2020-09-01 16:06:00 +00:00
log . Errorf ( "Cannot start Websocket Proxy Server: %s" , err )
2018-09-21 15:18:23 +00:00
return errors . Wrap ( err , "Cannot start Websocket Proxy Server" )
}
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
2020-03-31 14:56:22 +00:00
streamHandler := websocket . DefaultStreamHandler
if c . IsSet ( socks5Flag ) {
2020-09-01 16:06:00 +00:00
log . Info ( "SOCKS5 server started" )
2020-05-04 20:15:17 +00:00
streamHandler = func ( wsConn * websocket . Conn , remoteConn net . Conn , _ http . Header ) {
2020-03-31 14:56:22 +00:00
dialer := socks . NewConnDialer ( remoteConn )
requestHandler := socks . NewRequestHandler ( dialer )
socksServer := socks . NewConnectionHandler ( requestHandler )
socksServer . Serve ( wsConn )
}
2020-05-04 20:15:17 +00:00
} else if c . IsSet ( sshServerFlag ) {
streamHandler = func ( wsConn * websocket . Conn , remoteConn net . Conn , requestHeaders http . Header ) {
if finalDestination := requestHeaders . Get ( h2mux . CFJumpDestinationHeader ) ; finalDestination != "" {
token := requestHeaders . Get ( h2mux . CFAccessTokenHeader )
if err := websocket . SendSSHPreamble ( remoteConn , finalDestination , token ) ; err != nil {
2020-09-01 16:06:00 +00:00
log . Errorf ( "Failed to send SSH preamble: %s" , err )
2020-05-04 20:15:17 +00:00
return
}
}
websocket . DefaultStreamHandler ( wsConn , remoteConn , requestHeaders )
}
2020-03-31 14:56:22 +00:00
}
2020-09-01 16:06:00 +00:00
errC <- websocket . StartProxyServer ( log , listener , staticHost , shutdownC , streamHandler )
2018-09-21 15:18:23 +00:00
} ( )
2020-06-25 18:25:39 +00:00
forceSetFlag ( c , "url" , "http://" + listener . Addr ( ) . String ( ) )
2018-09-21 15:18:23 +00:00
}
2020-09-01 16:06:00 +00:00
transportLogger , err := createLogger ( c , true , false )
2020-04-29 20:51:32 +00:00
if err != nil {
return errors . Wrap ( err , "error setting up transport logger" )
}
2020-09-01 16:06:00 +00:00
tunnelConfig , err := prepareTunnelConfig ( c , buildInfo , version , log , transportLogger , namedTunnel )
2018-10-08 19:20:28 +00:00
if err != nil {
return err
}
2020-04-30 05:02:08 +00:00
reconnectCh := make ( chan origin . ReconnectSignal , 1 )
2020-03-27 14:39:59 +00:00
if c . IsSet ( "stdin-control" ) {
2020-09-01 16:06:00 +00:00
log . Info ( "Enabling control through stdin" )
go stdinControl ( reconnectCh , log )
2020-03-27 14:39:59 +00:00
}
2020-03-19 15:38:28 +00:00
2018-10-08 19:20:28 +00:00
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
2020-06-25 18:25:39 +00:00
errC <- origin . StartTunnelDaemon ( ctx , tunnelConfig , connectedSignal , cloudflaredID , reconnectCh )
2018-10-08 19:20:28 +00:00
} ( )
2020-04-29 20:51:32 +00:00
2020-09-01 16:06:00 +00:00
if isUIEnabled {
const tunnelEventChanBufferSize = 16
tunnelEventChan := make ( chan ui . TunnelEvent , tunnelEventChanBufferSize )
2020-07-24 22:17:17 +00:00
tunnelConfig . TunnelEventChan = tunnelEventChan
2020-07-29 22:48:27 +00:00
2020-09-01 16:06:00 +00:00
tunnelInfo := ui . NewUIModel (
version ,
hostname ,
metricsListener . Addr ( ) . String ( ) ,
tunnelConfig . OriginUrl ,
tunnelConfig . HAConnections ,
)
logLevels , err := logger . ParseLevelString ( c . String ( "loglevel" ) )
if err != nil {
return err
}
tunnelInfo . LaunchUI ( ctx , log , logLevels , tunnelEventChan )
2020-07-24 22:17:17 +00:00
}
2020-09-01 16:06:00 +00:00
return waitToShutdown ( & wg , errC , shutdownC , graceShutdownC , c . Duration ( "grace-period" ) , log )
2018-10-08 19:20:28 +00:00
}
2020-06-25 18:25:39 +00:00
// forceSetFlag attempts to set the given flag value in the closest context that has it defined
func forceSetFlag ( c * cli . Context , name , value string ) {
for _ , ctx := range c . Lineage ( ) {
if err := ctx . Set ( name , value ) ; err == nil {
break
}
}
}
2018-10-08 19:20:28 +00:00
func Before ( c * cli . Context ) error {
2020-09-01 16:06:00 +00:00
logger , err := createLogger ( c , false , false )
2020-04-29 20:51:32 +00:00
if err != nil {
2020-06-12 16:20:36 +00:00
return cliutil . PrintLoggerSetupError ( "error setting up logger" , err )
2020-04-29 20:51:32 +00:00
}
2018-10-08 19:20:28 +00:00
if c . String ( "config" ) == "" {
2020-08-14 20:52:47 +00:00
logger . Debugf ( "Cannot determine default configuration path. No file %v in %v" , config . DefaultConfigFiles , config . DefaultConfigSearchDirectories ( ) )
2018-10-08 19:20:28 +00:00
}
inputSource , err := config . FindInputSourceContext ( c )
if err != nil {
2020-04-29 20:51:32 +00:00
logger . Errorf ( "Cannot load configuration from %s: %s" , c . String ( "config" ) , err )
2018-10-08 19:20:28 +00:00
return err
} else if inputSource != nil {
err := altsrc . ApplyInputSourceValues ( c , inputSource , c . App . Flags )
if err != nil {
2020-04-29 20:51:32 +00:00
logger . Errorf ( "Cannot apply configuration from %s: %s" , c . String ( "config" ) , err )
2018-10-08 19:20:28 +00:00
return err
}
2018-10-19 20:44:35 +00:00
logger . Debugf ( "Applied configuration from %s" , c . String ( "config" ) )
2018-10-08 19:20:28 +00:00
}
return nil
}
2020-05-04 20:15:17 +00:00
// isProxyDestinationConfigured returns true if there is a static host set or if bastion mode is set.
func isProxyDestinationConfigured ( staticHost string , c * cli . Context ) bool {
return staticHost != "" || c . IsSet ( bastionFlag )
}
2018-10-08 19:20:28 +00:00
func waitToShutdown ( wg * sync . WaitGroup ,
errC chan error ,
shutdownC , graceShutdownC chan struct { } ,
gracePeriod time . Duration ,
2020-04-29 20:51:32 +00:00
logger logger . Service ,
2018-10-08 19:20:28 +00:00
) error {
var err error
if gracePeriod > 0 {
2020-04-29 20:51:32 +00:00
err = waitForSignalWithGraceShutdown ( errC , shutdownC , graceShutdownC , gracePeriod , logger )
2018-10-08 19:20:28 +00:00
} else {
2020-04-29 20:51:32 +00:00
err = waitForSignal ( errC , shutdownC , logger )
2018-10-08 19:20:28 +00:00
close ( graceShutdownC )
}
if err != nil {
2020-04-29 20:51:32 +00:00
logger . Errorf ( "Quitting due to error: %s" , err )
2018-10-08 19:20:28 +00:00
} else {
logger . Info ( "Quitting..." )
}
// Wait for clean exit, discarding all errors
go func ( ) {
for range errC {
}
} ( )
wg . Wait ( )
return err
}
2019-03-04 19:48:56 +00:00
func notifySystemd ( waitForSignal * signal . Signal ) {
<- waitForSignal . Wait ( )
2018-10-08 19:20:28 +00:00
daemon . SdNotify ( false , "READY=1" )
}
2020-04-29 20:51:32 +00:00
func writePidFile ( waitForSignal * signal . Signal , pidFile string , logger logger . Service ) {
2019-03-04 19:48:56 +00:00
<- waitForSignal . Wait ( )
2020-04-28 00:55:27 +00:00
expandedPath , err := homedir . Expand ( pidFile )
if err != nil {
2020-04-29 20:51:32 +00:00
logger . Errorf ( "Unable to expand %s, try to use absolute path in --pidfile: %s" , pidFile , err )
2020-04-28 00:55:27 +00:00
return
}
file , err := os . Create ( expandedPath )
2018-10-08 19:20:28 +00:00
if err != nil {
2020-04-29 20:51:32 +00:00
logger . Errorf ( "Unable to write pid to %s: %s" , expandedPath , err )
2020-04-28 00:55:27 +00:00
return
2018-10-08 19:20:28 +00:00
}
defer file . Close ( )
fmt . Fprintf ( file , "%d" , os . Getpid ( ) )
}
2019-02-01 22:43:59 +00:00
func hostnameFromURI ( uri string ) string {
u , err := url . Parse ( uri )
if err != nil {
return ""
}
switch u . Scheme {
case "ssh" :
return addPortIfMissing ( u , 22 )
case "rdp" :
return addPortIfMissing ( u , 3389 )
2020-05-13 18:53:31 +00:00
case "smb" :
return addPortIfMissing ( u , 445 )
2020-03-23 15:22:58 +00:00
case "tcp" :
return addPortIfMissing ( u , 7864 ) // just a random port since there isn't a default in this case
2019-02-01 22:43:59 +00:00
}
return ""
}
func addPortIfMissing ( uri * url . URL , port int ) string {
if uri . Port ( ) != "" {
return uri . Host
}
return fmt . Sprintf ( "%s:%d" , uri . Hostname ( ) , port )
}
2019-11-12 18:50:41 +00:00
func dbConnectCmd ( ) * cli . Command {
cmd := dbconnect . Cmd ( )
// Append the tunnel commands so users can customize the daemon settings.
cmd . Flags = appendFlags ( Flags ( ) , cmd . Flags ... )
// Override before to run tunnel validation before dbconnect validation.
cmd . Before = func ( c * cli . Context ) error {
err := Before ( c )
if err == nil {
err = dbconnect . CmdBefore ( c )
}
return err
}
// Override action to setup the Proxy, then if successful, start the tunnel daemon.
2020-05-18 18:24:17 +00:00
cmd . Action = cliutil . ErrorHandler ( func ( c * cli . Context ) error {
2019-11-12 18:50:41 +00:00
err := dbconnect . CmdAction ( c )
if err == nil {
2020-07-30 17:00:57 +00:00
err = TunnelCommand ( c )
2019-11-12 18:50:41 +00:00
}
return err
2020-05-18 18:24:17 +00:00
} )
2019-11-12 18:50:41 +00:00
return cmd
}
// appendFlags will append extra flags to a slice of flags.
//
// The cli package will panic if two flags exist with the same name,
// so if extraFlags contains a flag that was already defined, modify the
// original flags to use the extra version.
func appendFlags ( flags [ ] cli . Flag , extraFlags ... cli . Flag ) [ ] cli . Flag {
for _ , extra := range extraFlags {
var found bool
// Check if an extra flag overrides an existing flag.
for i , flag := range flags {
if reflect . DeepEqual ( extra . Names ( ) , flag . Names ( ) ) {
flags [ i ] = extra
found = true
break
}
}
// Append the extra flag if it has nothing to override.
if ! found {
flags = append ( flags , extra )
}
}
return flags
}
2018-10-08 19:20:28 +00:00
func tunnelFlags ( shouldHide bool ) [ ] cli . Flag {
2020-09-16 12:15:49 +00:00
flags := [ ] cli . Flag {
2018-10-08 19:20:28 +00:00
& cli . StringFlag {
Name : "config" ,
Usage : "Specifies a config file in YAML format." ,
Value : config . FindDefaultConfigPath ( ) ,
Hidden : shouldHide ,
} ,
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : "autoupdate-freq" ,
2019-06-18 16:47:29 +00:00
Usage : fmt . Sprintf ( "Autoupdate frequency. Default is %v." , updater . DefaultCheckUpdateFreq ) ,
Value : updater . DefaultCheckUpdateFreq ,
2018-10-08 19:20:28 +00:00
Hidden : shouldHide ,
} ) ,
altsrc . NewBoolFlag ( & cli . BoolFlag {
2019-08-27 20:53:28 +00:00
Name : "no-autoupdate" ,
Usage : "Disable periodic check for updates, restarting the server with the new version." ,
EnvVars : [ ] string { "NO_AUTOUPDATE" } ,
Value : false ,
Hidden : shouldHide ,
2018-10-08 19:20:28 +00:00
} ) ,
altsrc . NewBoolFlag ( & cli . BoolFlag {
Name : "is-autoupdated" ,
Usage : "Signal the new process that Argo Tunnel client has been autoupdated" ,
Value : false ,
Hidden : true ,
} ) ,
altsrc . NewStringSliceFlag ( & cli . StringSliceFlag {
Name : "edge" ,
2020-02-19 22:16:13 +00:00
Usage : "Address of the Cloudflare tunnel server. Only works in Cloudflare's internal testing environment." ,
2018-10-08 19:20:28 +00:00
EnvVars : [ ] string { "TUNNEL_EDGE" } ,
Hidden : true ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
2019-05-28 20:53:35 +00:00
Name : tlsconfig . CaCertFlag ,
2018-11-15 15:43:50 +00:00
Usage : "Certificate Authority authenticating connections with Cloudflare's edge network." ,
2018-10-08 19:20:28 +00:00
EnvVars : [ ] string { "TUNNEL_CACERT" } ,
Hidden : true ,
} ) ,
altsrc . NewBoolFlag ( & cli . BoolFlag {
Name : "no-tls-verify" ,
Usage : "Disables TLS verification of the certificate presented by your origin. Will allow any certificate from the origin to be accepted. Note: The connection from your machine to Cloudflare's Edge is still encrypted." ,
EnvVars : [ ] string { "NO_TLS_VERIFY" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "origincert" ,
Usage : "Path to the certificate generated for your origin when you run cloudflared login." ,
EnvVars : [ ] string { "TUNNEL_ORIGIN_CERT" } ,
Value : findDefaultOriginCertPath ( ) ,
Hidden : shouldHide ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
2019-05-28 20:53:35 +00:00
Name : tlsconfig . OriginCAPoolFlag ,
2018-10-08 19:20:28 +00:00
Usage : "Path to the CA for the certificate of your origin. This option should be used only if your certificate is not signed by Cloudflare." ,
EnvVars : [ ] string { "TUNNEL_ORIGIN_CA_POOL" } ,
Hidden : shouldHide ,
} ) ,
2019-02-14 10:40:54 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "unix-socket" ,
Usage : "Path to unix socket to use instead of --url" ,
EnvVars : [ ] string { "TUNNEL_UNIX_SOCKET" } ,
Hidden : shouldHide ,
} ) ,
2018-10-08 19:20:28 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "hostname" ,
Usage : "Set a hostname on a Cloudflare zone to route traffic through this tunnel." ,
EnvVars : [ ] string { "TUNNEL_HOSTNAME" } ,
Hidden : shouldHide ,
} ) ,
2019-08-30 03:55:54 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "http-host-header" ,
Usage : "Sets the HTTP Host header for the local webserver." ,
EnvVars : [ ] string { "TUNNEL_HTTP_HOST_HEADER" } ,
Hidden : shouldHide ,
} ) ,
2018-10-08 19:20:28 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "origin-server-name" ,
Usage : "Hostname on the origin server certificate." ,
EnvVars : [ ] string { "TUNNEL_ORIGIN_SERVER_NAME" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "id" ,
Usage : "A unique identifier used to tie connections to this tunnel instance." ,
EnvVars : [ ] string { "TUNNEL_ID" } ,
Hidden : true ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "lb-pool" ,
Usage : "The name of a (new/existing) load balancing pool to add this origin to." ,
EnvVars : [ ] string { "TUNNEL_LB_POOL" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "api-key" ,
Usage : "This parameter has been deprecated since version 2017.10.1." ,
EnvVars : [ ] string { "TUNNEL_API_KEY" } ,
Hidden : true ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "api-email" ,
Usage : "This parameter has been deprecated since version 2017.10.1." ,
EnvVars : [ ] string { "TUNNEL_API_EMAIL" } ,
Hidden : true ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "api-ca-key" ,
Usage : "This parameter has been deprecated since version 2017.10.1." ,
EnvVars : [ ] string { "TUNNEL_API_CA_KEY" } ,
Hidden : true ,
} ) ,
2020-05-21 20:36:49 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "api-url" ,
Usage : "Base URL for Cloudflare API v4" ,
EnvVars : [ ] string { "TUNNEL_API_URL" } ,
Value : "https://api.cloudflare.com/client/v4" ,
Hidden : true ,
} ) ,
2018-10-08 19:20:28 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "metrics" ,
Value : "localhost:" ,
Usage : "Listen address for metrics reporting." ,
EnvVars : [ ] string { "TUNNEL_METRICS" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : "metrics-update-freq" ,
Usage : "Frequency to update tunnel metrics" ,
Value : time . Second * 5 ,
EnvVars : [ ] string { "TUNNEL_METRICS_UPDATE_FREQ" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewStringSliceFlag ( & cli . StringSliceFlag {
Name : "tag" ,
Usage : "Custom tags used to identify this tunnel, in format `KEY=VALUE`. Multiple tags may be specified" ,
EnvVars : [ ] string { "TUNNEL_TAG" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : "heartbeat-interval" ,
Usage : "Minimum idle time before sending a heartbeat." ,
Value : time . Second * 5 ,
Hidden : true ,
} ) ,
altsrc . NewUint64Flag ( & cli . Uint64Flag {
Name : "heartbeat-count" ,
Usage : "Minimum number of unacked heartbeats to send before closing the connection." ,
Value : 5 ,
Hidden : true ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "loglevel" ,
Value : "info" ,
2020-04-29 20:51:32 +00:00
Usage : "Application logging level {fatal, error, info, debug}. " + debugLevelWarning ,
2018-10-08 19:20:28 +00:00
EnvVars : [ ] string { "TUNNEL_LOGLEVEL" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
2019-01-28 20:11:56 +00:00
Name : "transport-loglevel" ,
Aliases : [ ] string { "proto-loglevel" } , // This flag used to be called proto-loglevel
2020-04-29 20:51:32 +00:00
Value : "fatal" ,
Usage : "Transport logging level(previously called protocol logging level) {fatal, error, info, debug}" ,
2019-01-28 20:11:56 +00:00
EnvVars : [ ] string { "TUNNEL_PROTO_LOGLEVEL" , "TUNNEL_TRANSPORT_LOGLEVEL" } ,
2018-10-08 19:20:28 +00:00
Hidden : shouldHide ,
} ) ,
altsrc . NewUintFlag ( & cli . UintFlag {
Name : "retries" ,
Value : 5 ,
Usage : "Maximum number of retries for connection/protocol errors." ,
EnvVars : [ ] string { "TUNNEL_RETRIES" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "pidfile" ,
Usage : "Write the application's PID to this file after first successful connection." ,
EnvVars : [ ] string { "TUNNEL_PIDFILE" } ,
Hidden : shouldHide ,
} ) ,
2020-06-16 15:33:03 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "logfile" ,
Usage : "Save application log to this file for reporting issues." ,
EnvVars : [ ] string { "TUNNEL_LOGFILE" } ,
Hidden : shouldHide ,
} ) ,
2018-10-08 19:20:28 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
2020-06-05 15:18:40 +00:00
Name : logDirectoryFlag ,
Usage : "Save application log to this directory for reporting issues." ,
2020-06-16 15:33:03 +00:00
EnvVars : [ ] string { "TUNNEL_LOGDIRECTORY" } ,
2018-10-08 19:20:28 +00:00
Hidden : shouldHide ,
} ) ,
altsrc . NewIntFlag ( & cli . IntFlag {
Name : "ha-connections" ,
Value : 4 ,
Hidden : true ,
} ) ,
2020-09-25 02:33:12 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "proxy-address" ,
Usage : "Listen address for the proxy." ,
Value : "127.0.0.1" ,
EnvVars : [ ] string { "TUNNEL_PROXY_ADDRESS" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewIntFlag ( & cli . IntFlag {
Name : "proxy-port" ,
Usage : "Listen port for the proxy." ,
Value : 0 ,
EnvVars : [ ] string { "TUNNEL_PROXY_PORT" } ,
Hidden : shouldHide ,
} ) ,
2018-10-08 19:20:28 +00:00
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : "proxy-connect-timeout" ,
Usage : "HTTP proxy timeout for establishing a new connection" ,
Value : time . Second * 30 ,
Hidden : shouldHide ,
} ) ,
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : "proxy-tls-timeout" ,
Usage : "HTTP proxy timeout for completing a TLS handshake" ,
Value : time . Second * 10 ,
Hidden : shouldHide ,
} ) ,
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : "proxy-tcp-keepalive" ,
Usage : "HTTP proxy TCP keepalive duration" ,
Value : time . Second * 30 ,
Hidden : shouldHide ,
} ) ,
altsrc . NewBoolFlag ( & cli . BoolFlag {
Name : "proxy-no-happy-eyeballs" ,
Usage : "HTTP proxy should disable \"happy eyeballs\" for IPv4/v6 fallback" ,
Hidden : shouldHide ,
} ) ,
altsrc . NewIntFlag ( & cli . IntFlag {
Name : "proxy-keepalive-connections" ,
Usage : "HTTP proxy maximum keepalive connection pool size" ,
Value : 100 ,
Hidden : shouldHide ,
} ) ,
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : "proxy-keepalive-timeout" ,
Usage : "HTTP proxy timeout for closing an idle connection" ,
Value : time . Second * 90 ,
Hidden : shouldHide ,
} ) ,
2019-06-18 16:47:29 +00:00
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : "proxy-connection-timeout" ,
Usage : "HTTP proxy timeout for closing an idle connection" ,
Value : time . Second * 90 ,
Hidden : shouldHide ,
} ) ,
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : "proxy-expect-continue-timeout" ,
Usage : "HTTP proxy timeout for closing an idle connection" ,
Value : time . Second * 90 ,
Hidden : shouldHide ,
} ) ,
2018-10-08 19:20:28 +00:00
altsrc . NewBoolFlag ( & cli . BoolFlag {
Name : "proxy-dns" ,
Usage : "Run a DNS over HTTPS proxy server." ,
EnvVars : [ ] string { "TUNNEL_DNS" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewIntFlag ( & cli . IntFlag {
Name : "proxy-dns-port" ,
Value : 53 ,
Usage : "Listen on given port for the DNS over HTTPS proxy server." ,
EnvVars : [ ] string { "TUNNEL_DNS_PORT" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "proxy-dns-address" ,
Usage : "Listen address for the DNS over HTTPS proxy server." ,
Value : "localhost" ,
EnvVars : [ ] string { "TUNNEL_DNS_ADDRESS" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewStringSliceFlag ( & cli . StringSliceFlag {
Name : "proxy-dns-upstream" ,
Usage : "Upstream endpoint URL, you can specify multiple endpoints for redundancy." ,
Value : cli . NewStringSlice ( "https://1.1.1.1/dns-query" , "https://1.0.0.1/dns-query" ) ,
EnvVars : [ ] string { "TUNNEL_DNS_UPSTREAM" } ,
Hidden : shouldHide ,
} ) ,
2020-04-04 20:49:36 +00:00
altsrc . NewStringSliceFlag ( & cli . StringSliceFlag {
Name : "proxy-dns-bootstrap" ,
Usage : "bootstrap endpoint URL, you can specify multiple endpoints for redundancy." ,
Value : cli . NewStringSlice ( "https://162.159.36.1/dns-query" , "https://162.159.46.1/dns-query" , "https://[2606:4700:4700::1111]/dns-query" , "https://[2606:4700:4700::1001]/dns-query" ) ,
EnvVars : [ ] string { "TUNNEL_DNS_BOOTSTRAP" } ,
Hidden : shouldHide ,
} ) ,
2018-10-08 19:20:28 +00:00
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : "grace-period" ,
Usage : "Duration to accept new requests after cloudflared receives first SIGINT/SIGTERM. A second SIGINT/SIGTERM will force cloudflared to shutdown immediately." ,
Value : time . Second * 30 ,
EnvVars : [ ] string { "TUNNEL_GRACE_PERIOD" } ,
Hidden : true ,
} ) ,
altsrc . NewUintFlag ( & cli . UintFlag {
Name : "compression-quality" ,
Value : 0 ,
Usage : "(beta) Use cross-stream compression instead HTTP compression. 0-off, 1-low, 2-medium, >=3-high." ,
EnvVars : [ ] string { "TUNNEL_COMPRESSION_LEVEL" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewBoolFlag ( & cli . BoolFlag {
Name : "no-chunked-encoding" ,
Usage : "Disables chunked transfer encoding; useful if you are running a WSGI server." ,
EnvVars : [ ] string { "TUNNEL_NO_CHUNKED_ENCODING" } ,
Hidden : shouldHide ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "trace-output" ,
Usage : "Name of trace output file, generated when cloudflared stops." ,
EnvVars : [ ] string { "TUNNEL_TRACE_OUTPUT" } ,
Hidden : shouldHide ,
} ) ,
2019-04-04 22:04:55 +00:00
altsrc . NewBoolFlag ( & cli . BoolFlag {
2019-12-04 17:22:08 +00:00
Name : "use-reconnect-token" ,
Usage : "Test reestablishing connections with the new 'reconnect token' flow." ,
2020-03-04 20:15:17 +00:00
Value : true ,
2019-12-04 17:22:08 +00:00
EnvVars : [ ] string { "TUNNEL_USE_RECONNECT_TOKEN" } ,
Hidden : true ,
} ) ,
2019-06-18 16:47:29 +00:00
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : "dial-edge-timeout" ,
Usage : "Maximum wait time to set up a connection with the edge" ,
Value : time . Second * 15 ,
EnvVars : [ ] string { "DIAL_EDGE_TIMEOUT" } ,
Hidden : true ,
} ) ,
2020-09-16 12:15:49 +00:00
altsrc . NewBoolFlag ( & cli . BoolFlag {
Name : "stdin-control" ,
Usage : "Control the process using commands sent through stdin" ,
EnvVars : [ ] string { "STDIN-CONTROL" } ,
Hidden : true ,
Value : false ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : "name" ,
Aliases : [ ] string { "n" } ,
EnvVars : [ ] string { "TUNNEL_NAME" } ,
Usage : "Stable name to identify the tunnel. Using this flag will create, route and run a tunnel. For production usage, execute each command separately" ,
} ) ,
altsrc . NewBoolFlag ( & cli . BoolFlag {
Name : uiFlag ,
Usage : "Launch tunnel UI. Tunnel logs are scrollable via 'j', 'k', or arrow keys." ,
Value : false ,
Hidden : shouldHide ,
} ) ,
urlFlag ( shouldHide ) ,
helloWorldFlag ( shouldHide ) ,
createSocks5Flag ( shouldHide ) ,
}
return append ( flags , sshFlags ( shouldHide ) ... )
}
func urlFlag ( shouldHide bool ) cli . Flag {
return altsrc . NewStringFlag ( & cli . StringFlag {
Name : "url" ,
Value : "http://localhost:8080" ,
Usage : "Connect to the local webserver at `URL`." ,
EnvVars : [ ] string { "TUNNEL_URL" } ,
Hidden : shouldHide ,
} )
}
func helloWorldFlag ( shouldHide bool ) cli . Flag {
return altsrc . NewBoolFlag ( & cli . BoolFlag {
Name : "hello-world" ,
Value : false ,
Usage : "Run Hello World Server" ,
EnvVars : [ ] string { "TUNNEL_HELLO_WORLD" } ,
Hidden : shouldHide ,
} )
}
func sshFlags ( shouldHide bool ) [ ] cli . Flag {
return [ ] cli . Flag {
2019-07-18 21:29:16 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
2019-08-28 15:48:30 +00:00
Name : sshPortFlag ,
2019-07-18 21:29:16 +00:00
Usage : "Localhost port that cloudflared SSH server will run on" ,
2019-09-04 15:37:53 +00:00
Value : "2222" ,
2019-07-18 21:29:16 +00:00
EnvVars : [ ] string { "LOCAL_SSH_PORT" } ,
Hidden : true ,
} ) ,
2019-08-28 15:48:30 +00:00
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : sshIdleTimeoutFlag ,
Usage : "Connection timeout after no activity" ,
EnvVars : [ ] string { "SSH_IDLE_TIMEOUT" } ,
Hidden : true ,
} ) ,
altsrc . NewDurationFlag ( & cli . DurationFlag {
Name : sshMaxTimeoutFlag ,
Usage : "Absolute connection timeout" ,
EnvVars : [ ] string { "SSH_MAX_TIMEOUT" } ,
Hidden : true ,
} ) ,
2019-08-26 20:56:17 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
Name : bucketNameFlag ,
Usage : "Bucket name of where to upload SSH logs" ,
EnvVars : [ ] string { "BUCKET_ID" } ,
Hidden : true ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : regionNameFlag ,
Usage : "Region name of where to upload SSH logs" ,
EnvVars : [ ] string { "REGION_ID" } ,
Hidden : true ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : secretIDFlag ,
Usage : "Secret ID of where to upload SSH logs" ,
EnvVars : [ ] string { "SECRET_ID" } ,
Hidden : true ,
} ) ,
2020-09-16 12:15:49 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
Name : accessKeyIDFlag ,
Usage : "Access Key ID of where to upload SSH logs" ,
EnvVars : [ ] string { "ACCESS_CLIENT_ID" } ,
Hidden : true ,
} ) ,
2019-08-26 20:56:17 +00:00
altsrc . NewStringFlag ( & cli . StringFlag {
Name : sessionTokenIDFlag ,
Usage : "Session Token to use in the configuration of SSH logs uploading" ,
EnvVars : [ ] string { "SESSION_TOKEN_ID" } ,
Hidden : true ,
} ) ,
altsrc . NewStringFlag ( & cli . StringFlag {
Name : s3URLFlag ,
Usage : "S3 url of where to upload SSH logs" ,
EnvVars : [ ] string { "S3_URL" } ,
Hidden : true ,
} ) ,
2019-10-17 21:23:06 +00:00
altsrc . NewPathFlag ( & cli . PathFlag {
Name : hostKeyPath ,
Usage : "Absolute path of directory to save SSH host keys in" ,
EnvVars : [ ] string { "HOST_KEY_PATH" } ,
Hidden : true ,
} ) ,
2020-03-27 14:39:59 +00:00
altsrc . NewBoolFlag ( & cli . BoolFlag {
2020-09-16 12:15:49 +00:00
Name : sshServerFlag ,
2020-03-31 14:56:22 +00:00
Value : false ,
2020-09-16 12:15:49 +00:00
Usage : "Run an SSH Server" ,
EnvVars : [ ] string { "TUNNEL_SSH_SERVER" } ,
Hidden : true , // TODO: remove when feature is complete
2020-05-04 20:15:17 +00:00
} ) ,
altsrc . NewBoolFlag ( & cli . BoolFlag {
Name : bastionFlag ,
Value : false ,
Usage : "Runs as jump host" ,
EnvVars : [ ] string { "TUNNEL_BASTION" } ,
Hidden : shouldHide ,
2020-03-31 14:56:22 +00:00
} ) ,
2020-03-27 14:39:59 +00:00
}
}
2020-09-16 12:15:49 +00:00
func createSocks5Flag ( shouldHide bool ) cli . Flag {
return altsrc . NewBoolFlag ( & cli . BoolFlag {
Name : socks5Flag ,
Usage : "specify if this tunnel is running as a SOCK5 Server" ,
EnvVars : [ ] string { "TUNNEL_SOCKS" } ,
Value : false ,
Hidden : shouldHide ,
} )
}
2020-04-29 20:51:32 +00:00
func stdinControl ( reconnectCh chan origin . ReconnectSignal , logger logger . Service ) {
2020-03-27 14:39:59 +00:00
for {
scanner := bufio . NewScanner ( os . Stdin )
for scanner . Scan ( ) {
command := scanner . Text ( )
2020-04-30 05:02:08 +00:00
parts := strings . SplitN ( command , " " , 2 )
2020-03-27 14:39:59 +00:00
2020-04-30 05:02:08 +00:00
switch parts [ 0 ] {
case "" :
break
2020-03-27 14:39:59 +00:00
case "reconnect" :
2020-04-30 05:02:08 +00:00
var reconnect origin . ReconnectSignal
if len ( parts ) > 1 {
var err error
if reconnect . Delay , err = time . ParseDuration ( parts [ 1 ] ) ; err != nil {
logger . Error ( err . Error ( ) )
continue
}
}
logger . Infof ( "Sending reconnect signal %+v" , reconnect )
reconnectCh <- reconnect
2020-03-27 14:39:59 +00:00
default :
2020-04-29 20:51:32 +00:00
logger . Infof ( "Unknown command: %s" , command )
2020-04-30 05:02:08 +00:00
fallthrough
case "help" :
2020-06-16 22:43:22 +00:00
logger . Info ( ` Supported command :
reconnect [ delay ]
2020-04-30 05:02:08 +00:00
- restarts one randomly chosen connection with optional delay before reconnect ` )
2020-03-27 14:39:59 +00:00
}
}
2018-10-08 19:20:28 +00:00
}
2019-12-04 17:22:08 +00:00
}