Release Argo Tunnel Client 2018.4.7

This commit is contained in:
cloudflare-warp-bot 2018-04-26 14:57:32 +00:00
parent ff6a14283d
commit 77e7c240c0
18 changed files with 460 additions and 293 deletions

View File

@ -103,7 +103,7 @@ func hello(c *cli.Context) error {
} }
func startHelloWorldServer(listener net.Listener, shutdownC <-chan struct{}) error { func startHelloWorldServer(listener net.Listener, shutdownC <-chan struct{}) error {
Log.Infof("Starting Hello World server at %s", listener.Addr()) logger.Infof("Starting Hello World server at %s", listener.Addr())
serverName := defaultServerName serverName := defaultServerName
if hostname, err := os.Hostname(); err == nil { if hostname, err := os.Hostname(); err == nil {
serverName = hostname serverName = hostname

View File

@ -90,8 +90,8 @@ var sysvTemplate = ServiceTemplate{
# Short-Description: Argo Tunnel # Short-Description: Argo Tunnel
# Description: Argo Tunnel agent # Description: Argo Tunnel agent
### END INIT INFO ### END INIT INFO
cmd="{{.Path}} --config /etc/cloudflared/config.yml --origincert /etc/cloudflared/cert.pem --pidfile /var/run/$name.pid --autoupdate-freq 24h0m0s"
name=$(basename $(readlink -f $0)) name=$(basename $(readlink -f $0))
cmd="{{.Path}} --config /etc/cloudflared/config.yml --origincert /etc/cloudflared/cert.pem --pidfile /var/run/$name.pid --autoupdate-freq 24h0m0s"
pid_file="/var/run/$name.pid" pid_file="/var/run/$name.pid"
stdout_log="/var/log/$name.log" stdout_log="/var/log/$name.log"
stderr_log="/var/log/$name.err" stderr_log="/var/log/$name.err"
@ -184,17 +184,17 @@ func installLinuxService(c *cli.Context) error {
defaultConfigDir := filepath.Dir(c.String("config")) defaultConfigDir := filepath.Dir(c.String("config"))
defaultConfigFile := filepath.Base(c.String("config")) defaultConfigFile := filepath.Base(c.String("config"))
if err = copyCredentials(serviceConfigDir, defaultConfigDir, defaultConfigFile); err != nil { if err = copyCredentials(serviceConfigDir, defaultConfigDir, defaultConfigFile); err != nil {
Log.WithError(err).Infof("Failed to copy user configuration. Before running the service, ensure that %s contains two files, %s and %s", logger.WithError(err).Infof("Failed to copy user configuration. Before running the service, ensure that %s contains two files, %s and %s",
serviceConfigDir, credentialFile, defaultConfigFiles[0]) serviceConfigDir, credentialFile, defaultConfigFiles[0])
return err return err
} }
switch { switch {
case isSystemd(): case isSystemd():
Log.Infof("Using Systemd") logger.Infof("Using Systemd")
return installSystemd(&templateArgs) return installSystemd(&templateArgs)
default: default:
Log.Infof("Using Sysv") logger.Infof("Using Sysv")
return installSysv(&templateArgs) return installSysv(&templateArgs)
} }
} }
@ -203,30 +203,30 @@ func installSystemd(templateArgs *ServiceTemplateArgs) error {
for _, serviceTemplate := range systemdTemplates { for _, serviceTemplate := range systemdTemplates {
err := serviceTemplate.Generate(templateArgs) err := serviceTemplate.Generate(templateArgs)
if err != nil { if err != nil {
Log.WithError(err).Infof("error generating service template") logger.WithError(err).Infof("error generating service template")
return err return err
} }
} }
if err := runCommand("systemctl", "enable", "cloudflared.service"); err != nil { if err := runCommand("systemctl", "enable", "cloudflared.service"); err != nil {
Log.WithError(err).Infof("systemctl enable cloudflared.service error") logger.WithError(err).Infof("systemctl enable cloudflared.service error")
return err return err
} }
if err := runCommand("systemctl", "start", "cloudflared-update.timer"); err != nil { if err := runCommand("systemctl", "start", "cloudflared-update.timer"); err != nil {
Log.WithError(err).Infof("systemctl start cloudflared-update.timer error") logger.WithError(err).Infof("systemctl start cloudflared-update.timer error")
return err return err
} }
Log.Infof("systemctl daemon-reload") logger.Infof("systemctl daemon-reload")
return runCommand("systemctl", "daemon-reload") return runCommand("systemctl", "daemon-reload")
} }
func installSysv(templateArgs *ServiceTemplateArgs) error { func installSysv(templateArgs *ServiceTemplateArgs) error {
confPath, err := sysvTemplate.ResolvePath() confPath, err := sysvTemplate.ResolvePath()
if err != nil { if err != nil {
Log.WithError(err).Infof("error resolving system path") logger.WithError(err).Infof("error resolving system path")
return err return err
} }
if err := sysvTemplate.Generate(templateArgs); err != nil { if err := sysvTemplate.Generate(templateArgs); err != nil {
Log.WithError(err).Infof("error generating system template") logger.WithError(err).Infof("error generating system template")
return err return err
} }
for _, i := range [...]string{"2", "3", "4", "5"} { for _, i := range [...]string{"2", "3", "4", "5"} {
@ -245,36 +245,36 @@ func installSysv(templateArgs *ServiceTemplateArgs) error {
func uninstallLinuxService(c *cli.Context) error { func uninstallLinuxService(c *cli.Context) error {
switch { switch {
case isSystemd(): case isSystemd():
Log.Infof("Using Systemd") logger.Infof("Using Systemd")
return uninstallSystemd() return uninstallSystemd()
default: default:
Log.Infof("Using Sysv") logger.Infof("Using Sysv")
return uninstallSysv() return uninstallSysv()
} }
} }
func uninstallSystemd() error { func uninstallSystemd() error {
if err := runCommand("systemctl", "disable", "cloudflared.service"); err != nil { if err := runCommand("systemctl", "disable", "cloudflared.service"); err != nil {
Log.WithError(err).Infof("systemctl disable cloudflared.service error") logger.WithError(err).Infof("systemctl disable cloudflared.service error")
return err return err
} }
if err := runCommand("systemctl", "stop", "cloudflared-update.timer"); err != nil { if err := runCommand("systemctl", "stop", "cloudflared-update.timer"); err != nil {
Log.WithError(err).Infof("systemctl stop cloudflared-update.timer error") logger.WithError(err).Infof("systemctl stop cloudflared-update.timer error")
return err return err
} }
for _, serviceTemplate := range systemdTemplates { for _, serviceTemplate := range systemdTemplates {
if err := serviceTemplate.Remove(); err != nil { if err := serviceTemplate.Remove(); err != nil {
Log.WithError(err).Infof("error removing service template") logger.WithError(err).Infof("error removing service template")
return err return err
} }
} }
Log.Infof("Successfully uninstall cloudflared service") logger.Infof("Successfully uninstall cloudflared service")
return nil return nil
} }
func uninstallSysv() error { func uninstallSysv() error {
if err := sysvTemplate.Remove(); err != nil { if err := sysvTemplate.Remove(); err != nil {
Log.WithError(err).Infof("error removing service template") logger.WithError(err).Infof("error removing service template")
return err return err
} }
for _, i := range [...]string{"2", "3", "4", "5"} { for _, i := range [...]string{"2", "3", "4", "5"} {
@ -287,6 +287,6 @@ func uninstallSysv() error {
continue continue
} }
} }
Log.Infof("Successfully uninstall cloudflared service") logger.Infof("Successfully uninstall cloudflared service")
return nil return nil
} }

View File

@ -136,7 +136,7 @@ func download(certURL, filePath string) bool {
return true return true
} }
if err != nil { if err != nil {
Log.WithError(err).Error("Error fetching certificate") logger.WithError(err).Error("Error fetching certificate")
return false return false
} }
} }
@ -179,16 +179,16 @@ func putSuccess(client *http.Client, certURL string) {
// indicate success to the relay server // indicate success to the relay server
req, err := http.NewRequest("PUT", certURL+"/ok", nil) req, err := http.NewRequest("PUT", certURL+"/ok", nil)
if err != nil { if err != nil {
Log.WithError(err).Error("HTTP request error") logger.WithError(err).Error("HTTP request error")
return return
} }
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
Log.WithError(err).Error("HTTP error") logger.WithError(err).Error("HTTP error")
return return
} }
resp.Body.Close() resp.Body.Close()
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
Log.Errorf("Unexpected HTTP error code %d", resp.StatusCode) logger.Errorf("Unexpected HTTP error code %d", resp.StatusCode)
} }
} }

View File

@ -9,7 +9,9 @@ import (
"gopkg.in/urfave/cli.v2" "gopkg.in/urfave/cli.v2"
) )
const launchAgentIdentifier = "com.cloudflare.cloudflared" const (
launchdIdentifier = "com.cloudflare.cloudflared"
)
func runApp(app *cli.App) { func runApp(app *cli.App) {
app.Commands = append(app.Commands, &cli.Command{ app.Commands = append(app.Commands, &cli.Command{
@ -32,7 +34,7 @@ func runApp(app *cli.App) {
} }
var launchdTemplate = ServiceTemplate{ var launchdTemplate = ServiceTemplate{
Path: installPath(launchAgentIdentifier), Path: installPath(),
Content: fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?> Content: fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
@ -46,9 +48,9 @@ var launchdTemplate = ServiceTemplate{
<key>RunAtLoad</key> <key>RunAtLoad</key>
<true/> <true/>
<key>StandardOutPath</key> <key>StandardOutPath</key>
<string>/tmp/%s.out.log</string> <string>%s</string>
<key>StandardErrorPath</key> <key>StandardErrorPath</key>
<string>/tmp/%s.err.log</string> <string>%s</string>
<key>KeepAlive</key> <key>KeepAlive</key>
<dict> <dict>
<key>SuccessfulExit</key> <key>SuccessfulExit</key>
@ -57,54 +59,84 @@ var launchdTemplate = ServiceTemplate{
<key>ThrottleInterval</key> <key>ThrottleInterval</key>
<integer>20</integer> <integer>20</integer>
</dict> </dict>
</plist>`, launchAgentIdentifier, launchAgentIdentifier, launchAgentIdentifier), </plist>`, launchdIdentifier, stdoutPath(), stderrPath()),
} }
func installPath(launchAgentIdentifier string) string { func isRootUser() bool {
pathPattern := "~/Library/LaunchAgents/%s.plist" return os.Geteuid() == 0
}
func installPath() string {
// User is root, use /Library/LaunchDaemons instead of home directory // User is root, use /Library/LaunchDaemons instead of home directory
if os.Geteuid() == 0 { if isRootUser() {
pathPattern = "/Library/LaunchDaemons/%s.plist" return fmt.Sprintf("/Library/LaunchDaemons/%s.plist", launchdIdentifier)
} }
return fmt.Sprintf("%s/Library/LaunchAgents/%s.plist", userHomeDir(), launchdIdentifier)
}
return fmt.Sprintf(pathPattern, launchAgentIdentifier) func stdoutPath() string {
if isRootUser() {
return fmt.Sprintf("/Library/Logs/%s.out.log", launchdIdentifier)
}
return fmt.Sprintf("%s/Library/Logs/%s.out.log", userHomeDir(), launchdIdentifier)
}
func stderrPath() string {
if isRootUser() {
return fmt.Sprintf("/Library/Logs/%s.err.log", launchdIdentifier)
}
return fmt.Sprintf("%s/Library/Logs/%s.err.log", userHomeDir(), launchdIdentifier)
} }
func installLaunchd(c *cli.Context) error { func installLaunchd(c *cli.Context) error {
Log.Infof("Installing Argo Tunnel as an user launch agent") if isRootUser() {
logger.Infof("Installing Argo Tunnel client as a system launch daemon. " +
"Argo Tunnel client will run at boot")
} else {
logger.Infof("Installing Argo Tunnel client as an user launch agent. " +
"Note that Argo Tunnel client will only run when the user is logged in. " +
"If you want to run Argo Tunnel client at boot, install with root permission. " +
"For more information, visit https://developers.cloudflare.com/argo-tunnel/reference/service/")
}
etPath, err := os.Executable() etPath, err := os.Executable()
if err != nil { if err != nil {
Log.WithError(err).Infof("error determining executable path") logger.WithError(err).Infof("error determining executable path")
return fmt.Errorf("error determining executable path: %v", err) return fmt.Errorf("error determining executable path: %v", err)
} }
templateArgs := ServiceTemplateArgs{Path: etPath} templateArgs := ServiceTemplateArgs{Path: etPath}
err = launchdTemplate.Generate(&templateArgs) err = launchdTemplate.Generate(&templateArgs)
if err != nil { if err != nil {
Log.WithError(err).Infof("error generating launchd template") logger.WithError(err).Infof("error generating launchd template")
return err return err
} }
plistPath, err := launchdTemplate.ResolvePath() plistPath, err := launchdTemplate.ResolvePath()
if err != nil { if err != nil {
Log.WithError(err).Infof("error resolving launchd template path") logger.WithError(err).Infof("error resolving launchd template path")
return err return err
} }
Log.Infof("Outputs are logged in %s and %s", fmt.Sprintf("/tmp/%s.out.log", launchAgentIdentifier), fmt.Sprintf("/tmp/%s.err.log", launchAgentIdentifier))
logger.Infof("Outputs are logged to %s and %s", stderrPath(), stdoutPath())
return runCommand("launchctl", "load", plistPath) return runCommand("launchctl", "load", plistPath)
} }
func uninstallLaunchd(c *cli.Context) error { func uninstallLaunchd(c *cli.Context) error {
Log.Infof("Uninstalling Argo Tunnel as an user launch agent")
if isRootUser() {
logger.Infof("Uninstalling Argo Tunnel as a system launch daemon")
} else {
logger.Infof("Uninstalling Argo Tunnel as an user launch agent")
}
plistPath, err := launchdTemplate.ResolvePath() plistPath, err := launchdTemplate.ResolvePath()
if err != nil { if err != nil {
Log.WithError(err).Infof("error resolving launchd template path") logger.WithError(err).Infof("error resolving launchd template path")
return err return err
} }
err = runCommand("launchctl", "unload", plistPath) err = runCommand("launchctl", "unload", plistPath)
if err != nil { if err != nil {
Log.WithError(err).Infof("error unloading") logger.WithError(err).Infof("error unloading")
return err return err
} }
Log.Infof("Outputs are logged in %s and %s", fmt.Sprintf("/tmp/%s.out.log", launchAgentIdentifier), fmt.Sprintf("/tmp/%s.err.log", launchAgentIdentifier))
logger.Infof("Outputs are logged to %s and %s", stderrPath(), stdoutPath())
return launchdTemplate.Remove() return launchdTemplate.Remove()
} }

View File

@ -11,12 +11,12 @@ import (
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"sync" "sync"
"syscall" "syscall"
"time" "time"
"github.com/cloudflare/cloudflared/log"
"github.com/cloudflare/cloudflared/metrics" "github.com/cloudflare/cloudflared/metrics"
"github.com/cloudflare/cloudflared/origin" "github.com/cloudflare/cloudflared/origin"
"github.com/cloudflare/cloudflared/tlsconfig" "github.com/cloudflare/cloudflared/tlsconfig"
@ -48,7 +48,7 @@ const (
var listeners = gracenet.Net{} var listeners = gracenet.Net{}
var Version = "DEV" var Version = "DEV"
var BuildTime = "unknown" var BuildTime = "unknown"
var Log *logrus.Logger var logger = log.CreateLogger()
var defaultConfigFiles = []string{"config.yml", "config.yaml"} var defaultConfigFiles = []string{"config.yml", "config.yaml"}
// Launchd doesn't set root env variables, so there is default // Launchd doesn't set root env variables, so there is default
@ -59,15 +59,6 @@ var defaultConfigDirs = []string{"~/.cloudflared", "~/.cloudflare-warp", "~/clou
// May be closed by the Windows service runner. // May be closed by the Windows service runner.
var shutdownC chan struct{} var shutdownC chan struct{}
type BuildAndRuntimeInfo struct {
GoOS string `json:"go_os"`
GoVersion string `json:"go_version"`
GoArch string `json:"go_arch"`
WarpVersion string `json:"warp_version"`
WarpFlags map[string]interface{} `json:"warp_flags"`
WarpEnvs map[string]string `json:"warp_envs"`
}
func main() { func main() {
metrics.RegisterBuildInfo(BuildTime, Version) metrics.RegisterBuildInfo(BuildTime, Version)
raven.SetDSN(sentryDSN) raven.SetDSN(sentryDSN)
@ -306,18 +297,17 @@ func main() {
return nil return nil
} }
app.Before = func(context *cli.Context) error { app.Before = func(context *cli.Context) error {
Log = logrus.New()
inputSource, err := findInputSourceContext(context) inputSource, err := findInputSourceContext(context)
if err != nil { if err != nil {
Log.WithError(err).Infof("Cannot load configuration from %s", context.String("config")) logger.WithError(err).Infof("Cannot load configuration from %s", context.String("config"))
return err return err
} else if inputSource != nil { } else if inputSource != nil {
err := altsrc.ApplyInputSourceValues(context, inputSource, app.Flags) err := altsrc.ApplyInputSourceValues(context, inputSource, app.Flags)
if err != nil { if err != nil {
Log.WithError(err).Infof("Cannot apply configuration from %s", context.String("config")) logger.WithError(err).Infof("Cannot apply configuration from %s", context.String("config"))
return err return err
} }
Log.Infof("Applied configuration from %s", context.String("config")) logger.Infof("Applied configuration from %s", context.String("config"))
} }
return nil return nil
} }
@ -404,45 +394,50 @@ func startServer(c *cli.Context) {
// c.NumFlags() == 0 && c.NArg() == 0. For cloudflared to work, the user needs to at // c.NumFlags() == 0 && c.NArg() == 0. For cloudflared to work, the user needs to at
// least provide a hostname. // least provide a hostname.
if c.NumFlags() == 0 && c.NArg() == 0 && os.Getenv("TUNNEL_HOSTNAME") == "" { if c.NumFlags() == 0 && c.NArg() == 0 && os.Getenv("TUNNEL_HOSTNAME") == "" {
Log.Infof("No arguments were provided. You need to at least specify the hostname for this tunnel. See %s", quickStartUrl) logger.Infof("No arguments were provided. You need to at least specify the hostname for this tunnel. See %s", quickStartUrl)
cli.ShowAppHelp(c) cli.ShowAppHelp(c)
return return
} }
logLevel, err := logrus.ParseLevel(c.String("loglevel")) logLevel, err := logrus.ParseLevel(c.String("loglevel"))
if err != nil { if err != nil {
Log.WithError(err).Fatal("Unknown logging level specified") logger.WithError(err).Fatal("Unknown logging level specified")
} }
Log.SetLevel(logLevel) logger.SetLevel(logLevel)
protoLogLevel, err := logrus.ParseLevel(c.String("proto-loglevel")) protoLogLevel, err := logrus.ParseLevel(c.String("proto-loglevel"))
if err != nil { if err != nil {
Log.WithError(err).Fatal("Unknown protocol logging level specified") logger.WithError(err).Fatal("Unknown protocol logging level specified")
} }
protoLogger := logrus.New() protoLogger := logrus.New()
protoLogger.Level = protoLogLevel protoLogger.Level = protoLogLevel
if c.String("logfile") != "" { if c.String("logfile") != "" {
if err := initLogFile(c, protoLogger); err != nil { if err := initLogFile(c, protoLogger); err != nil {
Log.Error(err) logger.Error(err)
} }
} }
buildInfo := origin.GetBuildInfo()
logger.Infof("Build info: %+v", *buildInfo)
logger.Infof("Version %s", Version)
logClientOptions(c)
if c.IsSet("proxy-dns") { if c.IsSet("proxy-dns") {
port := c.Int("proxy-dns-port") port := c.Int("proxy-dns-port")
if port <= 0 || port > 65535 { if port <= 0 || port > 65535 {
Log.Fatal("The 'proxy-dns-port' must be a valid port number in <1, 65535> range.") logger.Fatal("The 'proxy-dns-port' must be a valid port number in <1, 65535> range.")
} }
wg.Add(1) wg.Add(1)
listener, err := tunneldns.CreateListener(c.String("proxy-dns-address"), uint16(port), c.StringSlice("proxy-dns-upstream")) listener, err := tunneldns.CreateListener(c.String("proxy-dns-address"), uint16(port), c.StringSlice("proxy-dns-upstream"))
if err != nil { if err != nil {
close(dnsReadySignal) close(dnsReadySignal)
listener.Stop() listener.Stop()
Log.WithError(err).Fatal("Cannot create the DNS over HTTPS proxy server") logger.WithError(err).Fatal("Cannot create the DNS over HTTPS proxy server")
} }
go func() { go func() {
err := listener.Start(dnsReadySignal) err := listener.Start(dnsReadySignal)
if err != nil { if err != nil {
Log.WithError(err).Fatal("Cannot start the DNS over HTTPS proxy server") logger.WithError(err).Fatal("Cannot start the DNS over HTTPS proxy server")
} else { } else {
<-shutdownC <-shutdownC
} }
@ -453,13 +448,14 @@ func startServer(c *cli.Context) {
close(dnsReadySignal) close(dnsReadySignal)
} }
if isAutoupdateEnabled(c) { isRunningFromTerminal := isRunningFromTerminal()
if isAutoupdateEnabled(c, isRunningFromTerminal) {
// Wait for proxy-dns to come up (if used) // Wait for proxy-dns to come up (if used)
<-dnsReadySignal <-dnsReadySignal
if initUpdate() { if initUpdate() {
return return
} }
Log.Infof("Autoupdate frequency is set to %v", c.Duration("autoupdate-freq")) logger.Infof("Autoupdate frequency is set to %v", c.Duration("autoupdate-freq"))
go autoupdate(c.Duration("autoupdate-freq"), shutdownC) go autoupdate(c.Duration("autoupdate-freq"), shutdownC)
} }
@ -473,7 +469,7 @@ func startServer(c *cli.Context) {
hostname, err := validation.ValidateHostname(c.String("hostname")) hostname, err := validation.ValidateHostname(c.String("hostname"))
if err != nil { if err != nil {
Log.WithError(err).Fatal("Invalid hostname") logger.WithError(err).Fatal("Invalid hostname")
} }
clientID := c.String("id") clientID := c.String("id")
if !c.IsSet("id") { if !c.IsSet("id") {
@ -482,7 +478,7 @@ func startServer(c *cli.Context) {
tags, err := NewTagSliceFromCLI(c.StringSlice("tag")) tags, err := NewTagSliceFromCLI(c.StringSlice("tag"))
if err != nil { if err != nil {
Log.WithError(err).Fatal("Tag parse failure") logger.WithError(err).Fatal("Tag parse failure")
} }
tags = append(tags, tunnelpogs.Tag{Name: "ID", Value: clientID}) tags = append(tags, tunnelpogs.Tag{Name: "ID", Value: clientID})
@ -491,7 +487,7 @@ func startServer(c *cli.Context) {
listener, err := createListener("127.0.0.1:") listener, err := createListener("127.0.0.1:")
if err != nil { if err != nil {
listener.Close() listener.Close()
Log.WithError(err).Fatal("Cannot start Hello World Server") logger.WithError(err).Fatal("Cannot start Hello World Server")
} }
go func() { go func() {
startHelloWorldServer(listener, shutdownC) startHelloWorldServer(listener, shutdownC)
@ -503,26 +499,26 @@ func startServer(c *cli.Context) {
url, err := validateUrl(c) url, err := validateUrl(c)
if err != nil { if err != nil {
Log.WithError(err).Fatal("Error validating url") logger.WithError(err).Fatal("Error validating url")
} }
Log.Infof("Proxying tunnel requests to %s", url) logger.Infof("Proxying tunnel requests to %s", url)
// Fail if the user provided an old authentication method // Fail if the user provided an old authentication method
if c.IsSet("api-key") || c.IsSet("api-email") || c.IsSet("api-ca-key") { if c.IsSet("api-key") || c.IsSet("api-email") || c.IsSet("api-ca-key") {
Log.Fatal("You don't need to give us your api-key anymore. Please use the new log in method. Just run cloudflared login") logger.Fatal("You don't need to give us your api-key anymore. Please use the new log in method. Just run cloudflared login")
} }
// Check that the user has acquired a certificate using the log in command // Check that the user has acquired a certificate using the log in command
originCertPath, err := homedir.Expand(c.String("origincert")) originCertPath, err := homedir.Expand(c.String("origincert"))
if err != nil { if err != nil {
Log.WithError(err).Fatalf("Cannot resolve path %s", c.String("origincert")) logger.WithError(err).Fatalf("Cannot resolve path %s", c.String("origincert"))
} }
ok, err := fileExists(originCertPath) ok, err := fileExists(originCertPath)
if err != nil { if err != nil {
Log.Fatalf("Cannot check if origin cert exists at path %s", c.String("origincert")) logger.Fatalf("Cannot check if origin cert exists at path %s", c.String("origincert"))
} }
if !ok { if !ok {
Log.Fatalf(`Cannot find a valid certificate for your origin at the path: logger.Fatalf(`Cannot find a valid certificate for your origin at the path:
%s %s
@ -535,7 +531,7 @@ If you don't have a certificate signed by Cloudflare, run the command:
// Easier to send the certificate as []byte via RPC than decoding it at this point // Easier to send the certificate as []byte via RPC than decoding it at this point
originCert, err := ioutil.ReadFile(originCertPath) originCert, err := ioutil.ReadFile(originCertPath)
if err != nil { if err != nil {
Log.WithError(err).Fatalf("Cannot read %s to load origin certificate", originCertPath) logger.WithError(err).Fatalf("Cannot read %s to load origin certificate", originCertPath)
} }
tunnelMetrics := origin.NewTunnelMetrics() tunnelMetrics := origin.NewTunnelMetrics()
@ -558,27 +554,29 @@ If you don't have a certificate signed by Cloudflare, run the command:
} }
tunnelConfig := &origin.TunnelConfig{ tunnelConfig := &origin.TunnelConfig{
EdgeAddrs: c.StringSlice("edge"), EdgeAddrs: c.StringSlice("edge"),
OriginUrl: url, OriginUrl: url,
Hostname: hostname, Hostname: hostname,
OriginCert: originCert, OriginCert: originCert,
TlsConfig: tlsconfig.CreateTunnelConfig(c, c.StringSlice("edge")), TlsConfig: tlsconfig.CreateTunnelConfig(c, c.StringSlice("edge")),
ClientTlsConfig: httpTransport.TLSClientConfig, ClientTlsConfig: httpTransport.TLSClientConfig,
Retries: c.Uint("retries"), Retries: c.Uint("retries"),
HeartbeatInterval: c.Duration("heartbeat-interval"), HeartbeatInterval: c.Duration("heartbeat-interval"),
MaxHeartbeats: c.Uint64("heartbeat-count"), MaxHeartbeats: c.Uint64("heartbeat-count"),
ClientID: clientID, ClientID: clientID,
ReportedVersion: Version, BuildInfo: buildInfo,
LBPool: c.String("lb-pool"), ReportedVersion: Version,
Tags: tags, LBPool: c.String("lb-pool"),
HAConnections: c.Int("ha-connections"), Tags: tags,
HTTPTransport: httpTransport, HAConnections: c.Int("ha-connections"),
Metrics: tunnelMetrics, HTTPTransport: httpTransport,
MetricsUpdateFreq: c.Duration("metrics-update-freq"), Metrics: tunnelMetrics,
ProtocolLogger: protoLogger, MetricsUpdateFreq: c.Duration("metrics-update-freq"),
Logger: Log, ProtocolLogger: protoLogger,
IsAutoupdated: c.Bool("is-autoupdated"), Logger: logger,
GracePeriod: c.Duration("grace-period"), IsAutoupdated: c.Bool("is-autoupdated"),
GracePeriod: c.Duration("grace-period"),
RunFromTerminal: isRunningFromTerminal,
} }
go writePidFile(connectedSignal, c.String("pidfile")) go writePidFile(connectedSignal, c.String("pidfile"))
@ -595,21 +593,21 @@ func runServer(c *cli.Context, wg *sync.WaitGroup, errC chan error, shutdownC ch
wg.Add(1) wg.Add(1)
metricsListener, err := listeners.Listen("tcp", c.String("metrics")) metricsListener, err := listeners.Listen("tcp", c.String("metrics"))
if err != nil { if err != nil {
Log.WithError(err).Fatal("Error opening metrics server listener") logger.WithError(err).Fatal("Error opening metrics server listener")
} }
go func() { go func() {
errC <- metrics.ServeMetrics(metricsListener, shutdownC) errC <- metrics.ServeMetrics(metricsListener, shutdownC, logger)
wg.Done() wg.Done()
}() }()
var errCode int var errCode int
err = WaitForSignal(errC, shutdownC) err = WaitForSignal(errC, shutdownC)
if err != nil { if err != nil {
Log.WithError(err).Fatal("Quitting due to error") logger.WithError(err).Fatal("Quitting due to error")
raven.CaptureErrorAndWait(err, nil) raven.CaptureErrorAndWait(err, nil)
errCode = 1 errCode = 1
} else { } else {
Log.Info("Graceful shutdown...") logger.Info("Graceful shutdown...")
} }
// Wait for clean exit, discarding all errors // Wait for clean exit, discarding all errors
go func() { go func() {
@ -648,7 +646,7 @@ func initUpdate() bool {
if updateApplied() { if updateApplied() {
os.Args = append(os.Args, "--is-autoupdated=true") os.Args = append(os.Args, "--is-autoupdated=true")
if _, err := listeners.StartProcess(); err != nil { if _, err := listeners.StartProcess(); err != nil {
Log.WithError(err).Error("Unable to restart server automatically") logger.WithError(err).Error("Unable to restart server automatically")
return false return false
} }
return true return true
@ -661,7 +659,7 @@ func autoupdate(freq time.Duration, shutdownC chan struct{}) {
if updateApplied() { if updateApplied() {
os.Args = append(os.Args, "--is-autoupdated=true") os.Args = append(os.Args, "--is-autoupdated=true")
if _, err := listeners.StartProcess(); err != nil { if _, err := listeners.StartProcess(); err != nil {
Log.WithError(err).Error("Unable to restart server automatically") logger.WithError(err).Error("Unable to restart server automatically")
} }
close(shutdownC) close(shutdownC)
return return
@ -673,11 +671,11 @@ func autoupdate(freq time.Duration, shutdownC chan struct{}) {
func updateApplied() bool { func updateApplied() bool {
releaseInfo := checkForUpdates() releaseInfo := checkForUpdates()
if releaseInfo.Updated { if releaseInfo.Updated {
Log.Infof("Updated to version %s", releaseInfo.Version) logger.Infof("Updated to version %s", releaseInfo.Version)
return true return true
} }
if releaseInfo.Error != nil { if releaseInfo.Error != nil {
Log.WithError(releaseInfo.Error).Error("Update check failed") logger.WithError(releaseInfo.Error).Error("Update check failed")
} }
return false return false
} }
@ -748,7 +746,7 @@ func writePidFile(waitForSignal chan struct{}, pidFile string) {
} }
file, err := os.Create(pidFile) file, err := os.Create(pidFile)
if err != nil { if err != nil {
Log.WithError(err).Errorf("Unable to write pid to %s", pidFile) logger.WithError(err).Errorf("Unable to write pid to %s", pidFile)
} }
defer file.Close() defer file.Close()
fmt.Fprintf(file, "%d", os.Getpid()) fmt.Fprintf(file, "%d", os.Getpid())
@ -790,16 +788,22 @@ func initLogFile(c *cli.Context, protoLogger *logrus.Logger) error {
logrus.PanicLevel: filePath, logrus.PanicLevel: filePath,
} }
Log.Hooks.Add(lfshook.NewHook(pathMap, &logrus.JSONFormatter{})) logger.Hooks.Add(lfshook.NewHook(pathMap, &logrus.JSONFormatter{}))
protoLogger.Hooks.Add(lfshook.NewHook(pathMap, &logrus.JSONFormatter{})) protoLogger.Hooks.Add(lfshook.NewHook(pathMap, &logrus.JSONFormatter{}))
flags := make(map[string]interface{}) return nil
envs := make(map[string]string) }
func logClientOptions(c *cli.Context) {
flags := make(map[string]interface{})
for _, flag := range c.LocalFlagNames() { for _, flag := range c.LocalFlagNames() {
flags[flag] = c.Generic(flag) flags[flag] = c.Generic(flag)
} }
if len(flags) > 0 {
logger.Infof("Flags %v", flags)
}
envs := make(map[string]string)
// Find env variables for Argo Tunnel // Find env variables for Argo Tunnel
for _, env := range os.Environ() { for _, env := range os.Environ() {
// All Argo Tunnel env variables start with TUNNEL_ // All Argo Tunnel env variables start with TUNNEL_
@ -810,24 +814,33 @@ func initLogFile(c *cli.Context, protoLogger *logrus.Logger) error {
} }
} }
} }
if len(envs) > 0 {
Log.Infof("Argo Tunnel build and runtime configuration: %+v", BuildAndRuntimeInfo{ logger.Infof("Environmental variables %v", envs)
GoOS: runtime.GOOS, }
GoVersion: runtime.Version(),
GoArch: runtime.GOARCH,
WarpVersion: Version,
WarpFlags: flags,
WarpEnvs: envs,
})
return nil
} }
func isAutoupdateEnabled(c *cli.Context) bool { func isAutoupdateEnabled(c *cli.Context, isRunningFromTerminal bool) bool {
if terminal.IsTerminal(int(os.Stdout.Fd())) { if isRunningFromTerminal {
Log.Info(noAutoupdateMessage) logger.Info(noAutoupdateMessage)
return false return false
} }
return !c.Bool("no-autoupdate") && c.Duration("autoupdate-freq") != 0 return !c.Bool("no-autoupdate") && c.Duration("autoupdate-freq") != 0
} }
func isRunningFromTerminal() bool {
return terminal.IsTerminal(int(os.Stdout.Fd()))
}
func userHomeDir() string {
// This returns the home dir of the executing user using OS-specific method
// for discovering the home dir. It's not recommended to call this function
// when the user has root permission as $HOME depends on what options the user
// use with sudo.
homeDir, err := homedir.Dir()
if err != nil {
logger.WithError(err).Fatal("Cannot determine home directory for the user.")
}
return homeDir
}

View File

@ -73,21 +73,21 @@ func runCommand(command string, args ...string) error {
cmd := exec.Command(command, args...) cmd := exec.Command(command, args...)
stderr, err := cmd.StderrPipe() stderr, err := cmd.StderrPipe()
if err != nil { if err != nil {
Log.WithError(err).Infof("error getting stderr pipe") logger.WithError(err).Infof("error getting stderr pipe")
return fmt.Errorf("error getting stderr pipe: %v", err) return fmt.Errorf("error getting stderr pipe: %v", err)
} }
err = cmd.Start() err = cmd.Start()
if err != nil { if err != nil {
Log.WithError(err).Infof("error starting %s", command) logger.WithError(err).Infof("error starting %s", command)
return fmt.Errorf("error starting %s: %v", command, err) return fmt.Errorf("error starting %s: %v", command, err)
} }
commandErr, _ := ioutil.ReadAll(stderr) commandErr, _ := ioutil.ReadAll(stderr)
if len(commandErr) > 0 { if len(commandErr) > 0 {
Log.Errorf("%s: %s", command, commandErr) logger.Errorf("%s: %s", command, commandErr)
} }
err = cmd.Wait() err = cmd.Wait()
if err != nil { if err != nil {
Log.WithError(err).Infof("%s returned error", command) logger.WithError(err).Infof("%s returned error", command)
return fmt.Errorf("%s returned with error: %v", command, err) return fmt.Errorf("%s returned with error: %v", command, err)
} }
return nil return nil
@ -159,7 +159,7 @@ func copyCredentials(serviceConfigDir, defaultConfigDir, defaultConfigFile strin
destConfigPath := filepath.Join(serviceConfigDir, defaultConfigFile) destConfigPath := filepath.Join(serviceConfigDir, defaultConfigFile)
destFile, exists, err := openFile(destConfigPath, true) destFile, exists, err := openFile(destConfigPath, true)
if err != nil { if err != nil {
Log.WithError(err).Infof("cannot open %s", destConfigPath) logger.WithError(err).Infof("cannot open %s", destConfigPath)
return err return err
} else if exists { } else if exists {
// config already exists, do nothing // config already exists, do nothing
@ -185,7 +185,7 @@ func copyCredentials(serviceConfigDir, defaultConfigDir, defaultConfigFile strin
if err != nil { if err != nil {
return fmt.Errorf("unable to copy %s to %s: %v", srcConfigPath, destConfigPath, err) return fmt.Errorf("unable to copy %s to %s: %v", srcConfigPath, destConfigPath, err)
} }
Log.Infof("Copied %s to %s", srcConfigPath, destConfigPath) logger.Infof("Copied %s to %s", srcConfigPath, destConfigPath)
} }
return nil return nil

View File

@ -41,7 +41,7 @@ func runApp(app *cli.App) {
isIntSess, err := svc.IsAnInteractiveSession() isIntSess, err := svc.IsAnInteractiveSession()
if err != nil { if err != nil {
Log.Fatalf("failed to determine if we are running in an interactive session: %v", err) logger.Fatalf("failed to determine if we are running in an interactive session: %v", err)
} }
if isIntSess { if isIntSess {
@ -51,7 +51,7 @@ func runApp(app *cli.App) {
elog, err := eventlog.Open(windowsServiceName) elog, err := eventlog.Open(windowsServiceName)
if err != nil { if err != nil {
Log.WithError(err).Infof("Cannot open event log for %s", windowsServiceName) logger.WithError(err).Infof("Cannot open event log for %s", windowsServiceName)
return return
} }
defer elog.Close() defer elog.Close()
@ -104,62 +104,62 @@ loop:
} }
func installWindowsService(c *cli.Context) error { func installWindowsService(c *cli.Context) error {
Log.Infof("Installing Argo Tunnel Windows service") logger.Infof("Installing Argo Tunnel Windows service")
exepath, err := os.Executable() exepath, err := os.Executable()
if err != nil { if err != nil {
Log.Infof("Cannot find path name that start the process") logger.Infof("Cannot find path name that start the process")
return err return err
} }
m, err := mgr.Connect() m, err := mgr.Connect()
if err != nil { if err != nil {
Log.WithError(err).Infof("Cannot establish a connection to the service control manager") logger.WithError(err).Infof("Cannot establish a connection to the service control manager")
return err return err
} }
defer m.Disconnect() defer m.Disconnect()
s, err := m.OpenService(windowsServiceName) s, err := m.OpenService(windowsServiceName)
if err == nil { if err == nil {
s.Close() s.Close()
Log.Errorf("service %s already exists", windowsServiceName) logger.Errorf("service %s already exists", windowsServiceName)
return fmt.Errorf("service %s already exists", windowsServiceName) return fmt.Errorf("service %s already exists", windowsServiceName)
} }
config := mgr.Config{StartType: mgr.StartAutomatic, DisplayName: windowsServiceDescription} config := mgr.Config{StartType: mgr.StartAutomatic, DisplayName: windowsServiceDescription}
s, err = m.CreateService(windowsServiceName, exepath, config) s, err = m.CreateService(windowsServiceName, exepath, config)
if err != nil { if err != nil {
Log.Infof("Cannot install service %s", windowsServiceName) logger.Infof("Cannot install service %s", windowsServiceName)
return err return err
} }
defer s.Close() defer s.Close()
err = eventlog.InstallAsEventCreate(windowsServiceName, eventlog.Error|eventlog.Warning|eventlog.Info) err = eventlog.InstallAsEventCreate(windowsServiceName, eventlog.Error|eventlog.Warning|eventlog.Info)
if err != nil { if err != nil {
s.Delete() s.Delete()
Log.WithError(err).Infof("Cannot install event logger") logger.WithError(err).Infof("Cannot install event logger")
return fmt.Errorf("SetupEventLogSource() failed: %s", err) return fmt.Errorf("SetupEventLogSource() failed: %s", err)
} }
return nil return nil
} }
func uninstallWindowsService(c *cli.Context) error { func uninstallWindowsService(c *cli.Context) error {
Log.Infof("Uninstalling Argo Tunnel Windows Service") logger.Infof("Uninstalling Argo Tunnel Windows Service")
m, err := mgr.Connect() m, err := mgr.Connect()
if err != nil { if err != nil {
Log.Infof("Cannot establish a connection to the service control manager") logger.Infof("Cannot establish a connection to the service control manager")
return err return err
} }
defer m.Disconnect() defer m.Disconnect()
s, err := m.OpenService(windowsServiceName) s, err := m.OpenService(windowsServiceName)
if err != nil { if err != nil {
Log.Infof("service %s is not installed", windowsServiceName) logger.Infof("service %s is not installed", windowsServiceName)
return fmt.Errorf("service %s is not installed", windowsServiceName) return fmt.Errorf("service %s is not installed", windowsServiceName)
} }
defer s.Close() defer s.Close()
err = s.Delete() err = s.Delete()
if err != nil { if err != nil {
Log.Errorf("Cannot delete service %s", windowsServiceName) logger.Errorf("Cannot delete service %s", windowsServiceName)
return err return err
} }
err = eventlog.Remove(windowsServiceName) err = eventlog.Remove(windowsServiceName)
if err != nil { if err != nil {
Log.Infof("Cannot remove event logger") logger.Infof("Cannot remove event logger")
return fmt.Errorf("RemoveEventLogSource() failed: %s", err) return fmt.Errorf("RemoveEventLogSource() failed: %s", err)
} }
return nil return nil

85
log/log.go Normal file
View File

@ -0,0 +1,85 @@
// this forks the logrus json formatter to rename msg -> message as that's the
// expected field. Ideally the logger should make it easier for us.
package log
import (
"encoding/json"
"fmt"
"time"
"github.com/mattn/go-colorable"
"github.com/sirupsen/logrus"
)
var (
DefaultTimestampFormat = time.RFC3339
)
type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string
}
func CreateLogger() *logrus.Logger {
logger := logrus.New()
logger.Out = colorable.NewColorableStderr()
logger.Formatter = &logrus.TextFormatter{ForceColors: true}
return logger
}
func (f *JSONFormatter) Format(entry *logrus.Entry) ([]byte, error) {
data := make(logrus.Fields, len(entry.Data)+3)
for k, v := range entry.Data {
switch v := v.(type) {
case error:
// Otherwise errors are ignored by `encoding/json`
// https://github.com/sirupsen/logrus/issues/137
data[k] = v.Error()
default:
data[k] = v
}
}
prefixFieldClashes(data)
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat
}
data["time"] = entry.Time.Format(timestampFormat)
data["message"] = entry.Message
data["level"] = entry.Level.String()
serialized, err := json.Marshal(data)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
return append(serialized, '\n'), nil
}
// This is to not silently overwrite `time`, `msg` and `level` fields when
// dumping it. If this code wasn't there doing:
//
// logrus.WithField("level", 1).Info("hello")
//
// Would just silently drop the user provided level. Instead with this code
// it'll logged as:
//
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
//
// It's not exported because it's still using Data in an opinionated way. It's to
// avoid code duplication between the two default formatters.
func prefixFieldClashes(data logrus.Fields) {
if t, ok := data["time"]; ok {
data["fields.time"] = t
}
if m, ok := data["msg"]; ok {
data["fields.msg"] = m
}
if l, ok := data["level"]; ok {
data["fields.level"] = l
}
}

View File

@ -13,7 +13,7 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
log "github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
const ( const (
@ -21,7 +21,7 @@ const (
startupTime = time.Millisecond * 500 startupTime = time.Millisecond * 500
) )
func ServeMetrics(l net.Listener, shutdownC <-chan struct{}) (err error) { func ServeMetrics(l net.Listener, shutdownC <-chan struct{}, logger *logrus.Logger) (err error) {
var wg sync.WaitGroup var wg sync.WaitGroup
// Metrics port is privileged, so no need for further access control // Metrics port is privileged, so no need for further access control
trace.AuthRequest = func(*http.Request) (bool, bool) { return true, true } trace.AuthRequest = func(*http.Request) (bool, bool) { return true, true }
@ -39,7 +39,7 @@ func ServeMetrics(l net.Listener, shutdownC <-chan struct{}) (err error) {
defer wg.Done() defer wg.Done()
err = server.Serve(l) err = server.Serve(l)
}() }()
log.WithField("addr", l.Addr()).Info("Starting metrics server") logger.WithField("addr", l.Addr()).Info("Starting metrics server")
// server.Serve will hang if server.Shutdown is called before the server is // server.Serve will hang if server.Shutdown is called before the server is
// fully started up. So add artificial delay. // fully started up. So add artificial delay.
time.Sleep(startupTime) time.Sleep(startupTime)
@ -51,10 +51,10 @@ func ServeMetrics(l net.Listener, shutdownC <-chan struct{}) (err error) {
wg.Wait() wg.Wait()
if err == http.ErrServerClosed { if err == http.ErrServerClosed {
log.Info("Metrics server stopped") logger.Info("Metrics server stopped")
return nil return nil
} }
log.WithError(err).Error("Metrics server quit with error") logger.WithError(err).Error("Metrics server quit with error")
return err return err
} }

19
origin/build_info.go Normal file
View File

@ -0,0 +1,19 @@
package origin
import (
"runtime"
)
type BuildInfo struct {
GoOS string `json:"go_os"`
GoVersion string `json:"go_version"`
GoArch string `json:"go_arch"`
}
func GetBuildInfo() *BuildInfo {
return &BuildInfo{
GoOS: runtime.GOOS,
GoVersion: runtime.Version(),
GoArch: runtime.GOARCH,
}
}

View File

@ -27,7 +27,7 @@ type muxerMetrics struct {
outBoundRateMax *prometheus.GaugeVec outBoundRateMax *prometheus.GaugeVec
} }
type tunnelMetrics struct { type TunnelMetrics struct {
haConnections prometheus.Gauge haConnections prometheus.Gauge
totalRequests prometheus.Counter totalRequests prometheus.Counter
requestsPerTunnel *prometheus.CounterVec requestsPerTunnel *prometheus.CounterVec
@ -229,7 +229,7 @@ func convertRTTMilliSec(t time.Duration) float64 {
} }
// Metrics that can be collected without asking the edge // Metrics that can be collected without asking the edge
func NewTunnelMetrics() *tunnelMetrics { func NewTunnelMetrics() *TunnelMetrics {
haConnections := prometheus.NewGauge( haConnections := prometheus.NewGauge(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
Name: "ha_connections", Name: "ha_connections",
@ -305,7 +305,7 @@ func NewTunnelMetrics() *tunnelMetrics {
) )
prometheus.MustRegister(serverLocations) prometheus.MustRegister(serverLocations)
return &tunnelMetrics{ return &TunnelMetrics{
haConnections: haConnections, haConnections: haConnections,
totalRequests: totalRequests, totalRequests: totalRequests,
requestsPerTunnel: requestsPerTunnel, requestsPerTunnel: requestsPerTunnel,
@ -322,19 +322,19 @@ func NewTunnelMetrics() *tunnelMetrics {
} }
} }
func (t *tunnelMetrics) incrementHaConnections() { func (t *TunnelMetrics) incrementHaConnections() {
t.haConnections.Inc() t.haConnections.Inc()
} }
func (t *tunnelMetrics) decrementHaConnections() { func (t *TunnelMetrics) decrementHaConnections() {
t.haConnections.Dec() t.haConnections.Dec()
} }
func (t *tunnelMetrics) updateMuxerMetrics(connectionID string, metrics *h2mux.MuxerMetrics) { func (t *TunnelMetrics) updateMuxerMetrics(connectionID string, metrics *h2mux.MuxerMetrics) {
t.muxerMetrics.update(connectionID, metrics) t.muxerMetrics.update(connectionID, metrics)
} }
func (t *tunnelMetrics) incrementRequests(connectionID string) { func (t *TunnelMetrics) incrementRequests(connectionID string) {
t.concurrentRequestsLock.Lock() t.concurrentRequestsLock.Lock()
var concurrentRequests uint64 var concurrentRequests uint64
var ok bool var ok bool
@ -356,25 +356,25 @@ func (t *tunnelMetrics) incrementRequests(connectionID string) {
t.concurrentRequestsPerTunnel.WithLabelValues(connectionID).Inc() t.concurrentRequestsPerTunnel.WithLabelValues(connectionID).Inc()
} }
func (t *tunnelMetrics) decrementConcurrentRequests(connectionID string) { func (t *TunnelMetrics) decrementConcurrentRequests(connectionID string) {
t.concurrentRequestsLock.Lock() t.concurrentRequestsLock.Lock()
if _, ok := t.concurrentRequests[connectionID]; ok { if _, ok := t.concurrentRequests[connectionID]; ok {
t.concurrentRequests[connectionID] -= 1 t.concurrentRequests[connectionID] -= 1
} else { } else {
Log.Error("Concurrent requests per tunnel metrics went wrong; you can't decrement concurrent requests count without increment it first.") logger.Error("Concurrent requests per tunnel metrics went wrong; you can't decrement concurrent requests count without increment it first.")
} }
t.concurrentRequestsLock.Unlock() t.concurrentRequestsLock.Unlock()
t.concurrentRequestsPerTunnel.WithLabelValues(connectionID).Dec() t.concurrentRequestsPerTunnel.WithLabelValues(connectionID).Dec()
} }
func (t *tunnelMetrics) incrementResponses(connectionID, code string) { func (t *TunnelMetrics) incrementResponses(connectionID, code string) {
t.responseByCode.WithLabelValues(code).Inc() t.responseByCode.WithLabelValues(code).Inc()
t.responseCodePerTunnel.WithLabelValues(connectionID, code).Inc() t.responseCodePerTunnel.WithLabelValues(connectionID, code).Inc()
} }
func (t *tunnelMetrics) registerServerLocation(connectionID, loc string) { func (t *TunnelMetrics) registerServerLocation(connectionID, loc string) {
t.locationLock.Lock() t.locationLock.Lock()
defer t.locationLock.Unlock() defer t.locationLock.Unlock()
if oldLoc, ok := t.oldServerLocations[connectionID]; ok && oldLoc == loc { if oldLoc, ok := t.oldServerLocations[connectionID]; ok && oldLoc == loc {

View File

@ -73,7 +73,7 @@ func (s *Supervisor) Run(ctx context.Context, connectedSignal chan struct{}) err
case tunnelError := <-s.tunnelErrors: case tunnelError := <-s.tunnelErrors:
tunnelsActive-- tunnelsActive--
if tunnelError.err != nil { if tunnelError.err != nil {
Log.WithError(tunnelError.err).Warn("Tunnel disconnected due to error") logger.WithError(tunnelError.err).Warn("Tunnel disconnected due to error")
tunnelsWaiting = append(tunnelsWaiting, tunnelError.index) tunnelsWaiting = append(tunnelsWaiting, tunnelError.index)
s.waitForNextTunnel(tunnelError.index) s.waitForNextTunnel(tunnelError.index)
@ -109,10 +109,10 @@ func (s *Supervisor) Run(ctx context.Context, connectedSignal chan struct{}) err
s.lastResolve = time.Now() s.lastResolve = time.Now()
s.resolverC = nil s.resolverC = nil
if result.err == nil { if result.err == nil {
Log.Debug("Service discovery refresh complete") logger.Debug("Service discovery refresh complete")
s.edgeIPs = result.edgeIPs s.edgeIPs = result.edgeIPs
} else { } else {
Log.WithError(result.err).Error("Service discovery error") logger.WithError(result.err).Error("Service discovery error")
} }
} }
} }
@ -121,12 +121,12 @@ func (s *Supervisor) Run(ctx context.Context, connectedSignal chan struct{}) err
func (s *Supervisor) initialize(ctx context.Context, connectedSignal chan struct{}) error { func (s *Supervisor) initialize(ctx context.Context, connectedSignal chan struct{}) error {
edgeIPs, err := ResolveEdgeIPs(s.config.EdgeAddrs) edgeIPs, err := ResolveEdgeIPs(s.config.EdgeAddrs)
if err != nil { if err != nil {
Log.Infof("ResolveEdgeIPs err") logger.Infof("ResolveEdgeIPs err")
return err return err
} }
s.edgeIPs = edgeIPs s.edgeIPs = edgeIPs
if s.config.HAConnections > len(edgeIPs) { if s.config.HAConnections > len(edgeIPs) {
Log.Warnf("You requested %d HA connections but I can give you at most %d.", s.config.HAConnections, len(edgeIPs)) logger.Warnf("You requested %d HA connections but I can give you at most %d.", s.config.HAConnections, len(edgeIPs))
s.config.HAConnections = len(edgeIPs) s.config.HAConnections = len(edgeIPs)
} }
s.lastResolve = time.Now() s.lastResolve = time.Now()

View File

@ -7,7 +7,6 @@ import (
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"runtime"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@ -28,7 +27,7 @@ import (
rpc "zombiezen.com/go/capnproto2/rpc" rpc "zombiezen.com/go/capnproto2/rpc"
) )
var Log *logrus.Logger var logger *logrus.Logger
const ( const (
dialTimeout = 15 * time.Second dialTimeout = 15 * time.Second
@ -48,17 +47,19 @@ type TunnelConfig struct {
HeartbeatInterval time.Duration HeartbeatInterval time.Duration
MaxHeartbeats uint64 MaxHeartbeats uint64
ClientID string ClientID string
BuildInfo *BuildInfo
ReportedVersion string ReportedVersion string
LBPool string LBPool string
Tags []tunnelpogs.Tag Tags []tunnelpogs.Tag
HAConnections int HAConnections int
HTTPTransport http.RoundTripper HTTPTransport http.RoundTripper
Metrics *tunnelMetrics Metrics *TunnelMetrics
MetricsUpdateFreq time.Duration MetricsUpdateFreq time.Duration
ProtocolLogger *logrus.Logger ProtocolLogger *logrus.Logger
Logger *logrus.Logger Logger *logrus.Logger
IsAutoupdated bool IsAutoupdated bool
GracePeriod time.Duration GracePeriod time.Duration
RunFromTerminal bool
} }
type dialError struct { type dialError struct {
@ -92,18 +93,19 @@ func (c *TunnelConfig) RegistrationOptions(connectionID uint8, OriginLocalIP str
return &tunnelpogs.RegistrationOptions{ return &tunnelpogs.RegistrationOptions{
ClientID: c.ClientID, ClientID: c.ClientID,
Version: c.ReportedVersion, Version: c.ReportedVersion,
OS: fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH), OS: fmt.Sprintf("%s_%s", c.BuildInfo.GoOS, c.BuildInfo.GoArch),
ExistingTunnelPolicy: policy, ExistingTunnelPolicy: policy,
PoolName: c.LBPool, PoolName: c.LBPool,
Tags: c.Tags, Tags: c.Tags,
ConnectionID: connectionID, ConnectionID: connectionID,
OriginLocalIP: OriginLocalIP, OriginLocalIP: OriginLocalIP,
IsAutoupdated: c.IsAutoupdated, IsAutoupdated: c.IsAutoupdated,
RunFromTerminal: c.RunFromTerminal,
} }
} }
func StartTunnelDaemon(config *TunnelConfig, shutdownC <-chan struct{}, connectedSignal chan struct{}) error { func StartTunnelDaemon(config *TunnelConfig, shutdownC <-chan struct{}, connectedSignal chan struct{}) error {
Log = config.Logger logger = config.Logger
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
go func() { go func() {
<-shutdownC <-shutdownC
@ -138,7 +140,7 @@ func ServeTunnelLoop(ctx context.Context, config *TunnelConfig, addr *net.TCPAdd
err, recoverable := ServeTunnel(ctx, config, addr, connectionID, connectedFuse, &backoff) err, recoverable := ServeTunnel(ctx, config, addr, connectionID, connectedFuse, &backoff)
if recoverable { if recoverable {
if duration, ok := backoff.GetBackoffDuration(ctx); ok { if duration, ok := backoff.GetBackoffDuration(ctx); ok {
Log.Infof("Retrying in %s seconds", duration) logger.Infof("Retrying in %s seconds", duration)
backoff.Backoff(ctx) backoff.Backoff(ctx)
continue continue
} }
@ -171,7 +173,7 @@ func ServeTunnel(
// Returns error from parsing the origin URL or handshake errors // Returns error from parsing the origin URL or handshake errors
handler, originLocalIP, err := NewTunnelHandler(ctx, config, addr.String(), connectionID) handler, originLocalIP, err := NewTunnelHandler(ctx, config, addr.String(), connectionID)
if err != nil { if err != nil {
errLog := Log.WithError(err) errLog := logger.WithError(err)
switch err.(type) { switch err.(type) {
case dialError: case dialError:
errLog.Error("Unable to dial edge") errLog.Error("Unable to dial edge")
@ -218,21 +220,21 @@ func ServeTunnel(
registerErr := <-registerErrC registerErr := <-registerErrC
wg.Wait() wg.Wait()
if err != nil { if err != nil {
Log.WithError(err).Error("Tunnel error") logger.WithError(err).Error("Tunnel error")
return err, true return err, true
} }
if registerErr != nil { if registerErr != nil {
// Don't retry on errors like entitlement failure or version too old // Don't retry on errors like entitlement failure or version too old
if e, ok := registerErr.(printableRegisterTunnelError); ok { if e, ok := registerErr.(printableRegisterTunnelError); ok {
Log.Error(e) logger.Error(e)
return e.cause, !e.permanent return e.cause, !e.permanent
} else if e, ok := registerErr.(dupConnRegisterTunnelError); ok { } else if e, ok := registerErr.(dupConnRegisterTunnelError); ok {
Log.Info("Already connected to this server, selecting a different one") logger.Info("Already connected to this server, selecting a different one")
return e, true return e, true
} }
// Only log errors to Sentry that may have been caused by the client side, to reduce dupes // Only log errors to Sentry that may have been caused by the client side, to reduce dupes
raven.CaptureError(registerErr, nil) raven.CaptureError(registerErr, nil)
Log.Error("Cannot register") logger.Error("Cannot register")
return err, true return err, true
} }
return nil, false return nil, false
@ -249,7 +251,7 @@ func IsRPCStreamResponse(headers []h2mux.Header) bool {
} }
func RegisterTunnel(ctx context.Context, muxer *h2mux.Muxer, config *TunnelConfig, connectionID uint8, originLocalIP string) error { func RegisterTunnel(ctx context.Context, muxer *h2mux.Muxer, config *TunnelConfig, connectionID uint8, originLocalIP string) error {
logger := Log.WithField("subsystem", "rpc") logger := logger.WithField("subsystem", "rpc")
logger.Debug("initiating RPC stream to register") logger.Debug("initiating RPC stream to register")
stream, err := muxer.OpenStream([]h2mux.Header{ stream, err := muxer.OpenStream([]h2mux.Header{
{Name: ":method", Value: "RPC"}, {Name: ":method", Value: "RPC"},
@ -304,7 +306,7 @@ func RegisterTunnel(ctx context.Context, muxer *h2mux.Muxer, config *TunnelConfi
} }
func UnregisterTunnel(muxer *h2mux.Muxer, gracePeriod time.Duration) error { func UnregisterTunnel(muxer *h2mux.Muxer, gracePeriod time.Duration) error {
logger := Log.WithField("subsystem", "rpc") logger := logger.WithField("subsystem", "rpc")
logger.Debug("initiating RPC stream to unregister") logger.Debug("initiating RPC stream to unregister")
stream, err := muxer.OpenStream([]h2mux.Header{ stream, err := muxer.OpenStream([]h2mux.Header{
{Name: ":method", Value: "RPC"}, {Name: ":method", Value: "RPC"},
@ -335,7 +337,7 @@ func UnregisterTunnel(muxer *h2mux.Muxer, gracePeriod time.Duration) error {
func LogServerInfo(logger *logrus.Entry, func LogServerInfo(logger *logrus.Entry,
promise tunnelrpc.ServerInfo_Promise, promise tunnelrpc.ServerInfo_Promise,
connectionID uint8, connectionID uint8,
metrics *tunnelMetrics, metrics *TunnelMetrics,
) { ) {
serverInfoMessage, err := promise.Struct() serverInfoMessage, err := promise.Struct()
if err != nil { if err != nil {
@ -347,7 +349,7 @@ func LogServerInfo(logger *logrus.Entry,
logger.WithError(err).Warn("Failed to retrieve server information") logger.WithError(err).Warn("Failed to retrieve server information")
return return
} }
Log.Infof("Connected to %s", serverInfo.LocationName) logger.Infof("Connected to %s", serverInfo.LocationName)
metrics.registerServerLocation(uint8ToString(connectionID), serverInfo.LocationName) metrics.registerServerLocation(uint8ToString(connectionID), serverInfo.LocationName)
} }
@ -398,7 +400,7 @@ type TunnelHandler struct {
httpClient http.RoundTripper httpClient http.RoundTripper
tlsConfig *tls.Config tlsConfig *tls.Config
tags []tunnelpogs.Tag tags []tunnelpogs.Tag
metrics *tunnelMetrics metrics *TunnelMetrics
// connectionID is only used by metrics, and prometheus requires labels to be string // connectionID is only used by metrics, and prometheus requires labels to be string
connectionID string connectionID string
} }
@ -407,12 +409,12 @@ var dialer = net.Dialer{DualStack: true}
// NewTunnelHandler returns a TunnelHandler, origin LAN IP and error // NewTunnelHandler returns a TunnelHandler, origin LAN IP and error
func NewTunnelHandler(ctx context.Context, config *TunnelConfig, addr string, connectionID uint8) (*TunnelHandler, string, error) { func NewTunnelHandler(ctx context.Context, config *TunnelConfig, addr string, connectionID uint8) (*TunnelHandler, string, error) {
url, err := validation.ValidateUrl(config.OriginUrl) originURL, err := validation.ValidateUrl(config.OriginUrl)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("Unable to parse origin url %#v", url) return nil, "", fmt.Errorf("Unable to parse origin url %#v", originURL)
} }
h := &TunnelHandler{ h := &TunnelHandler{
originUrl: url, originUrl: originURL,
httpClient: config.HTTPTransport, httpClient: config.HTTPTransport,
tlsConfig: config.ClientTlsConfig, tlsConfig: config.ClientTlsConfig,
tags: config.Tags, tags: config.Tags,
@ -464,11 +466,11 @@ func (h *TunnelHandler) ServeStream(stream *h2mux.MuxedStream) error {
h.metrics.incrementRequests(h.connectionID) h.metrics.incrementRequests(h.connectionID)
req, err := http.NewRequest("GET", h.originUrl, h2mux.MuxedStreamReader{MuxedStream: stream}) req, err := http.NewRequest("GET", h.originUrl, h2mux.MuxedStreamReader{MuxedStream: stream})
if err != nil { if err != nil {
Log.WithError(err).Panic("Unexpected error from http.NewRequest") logger.WithError(err).Panic("Unexpected error from http.NewRequest")
} }
err = H2RequestHeadersToH1Request(stream.Headers, req) err = H2RequestHeadersToH1Request(stream.Headers, req)
if err != nil { if err != nil {
Log.WithError(err).Error("invalid request received") logger.WithError(err).Error("invalid request received")
} }
h.AppendTagHeaders(req) h.AppendTagHeaders(req)
cfRay := FindCfRayHeader(req) cfRay := FindCfRayHeader(req)
@ -501,7 +503,7 @@ func (h *TunnelHandler) ServeStream(stream *h2mux.MuxedStream) error {
} }
func (h *TunnelHandler) logError(stream *h2mux.MuxedStream, err error) { func (h *TunnelHandler) logError(stream *h2mux.MuxedStream, err error) {
Log.WithError(err).Error("HTTP request error") logger.WithError(err).Error("HTTP request error")
stream.WriteHeaders([]h2mux.Header{{Name: ":status", Value: "502"}}) stream.WriteHeaders([]h2mux.Header{{Name: ":status", Value: "502"}})
stream.Write([]byte("502 Bad Gateway")) stream.Write([]byte("502 Bad Gateway"))
h.metrics.incrementResponses(h.connectionID, "502") h.metrics.incrementResponses(h.connectionID, "502")
@ -509,20 +511,20 @@ func (h *TunnelHandler) logError(stream *h2mux.MuxedStream, err error) {
func (h *TunnelHandler) logRequest(req *http.Request, cfRay string) { func (h *TunnelHandler) logRequest(req *http.Request, cfRay string) {
if cfRay != "" { if cfRay != "" {
Log.WithField("CF-RAY", cfRay).Infof("%s %s %s", req.Method, req.URL, req.Proto) logger.WithField("CF-RAY", cfRay).Infof("%s %s %s", req.Method, req.URL, req.Proto)
} else { } else {
Log.Warnf("All requests should have a CF-RAY header. Please open a support ticket with Cloudflare. %s %s %s ", req.Method, req.URL, req.Proto) logger.Warnf("All requests should have a CF-RAY header. Please open a support ticket with Cloudflare. %s %s %s ", req.Method, req.URL, req.Proto)
} }
Log.Debugf("Request Headers %+v", req.Header) logger.Debugf("Request Headers %+v", req.Header)
} }
func (h *TunnelHandler) logResponse(r *http.Response, cfRay string) { func (h *TunnelHandler) logResponse(r *http.Response, cfRay string) {
if cfRay != "" { if cfRay != "" {
Log.WithField("CF-RAY", cfRay).Infof("%s", r.Status) logger.WithField("CF-RAY", cfRay).Infof("%s", r.Status)
} else { } else {
Log.Infof("%s", r.Status) logger.Infof("%s", r.Status)
} }
Log.Debugf("Response Headers %+v", r.Header) logger.Debugf("Response Headers %+v", r.Header)
} }
func (h *TunnelHandler) UpdateMetrics(connectionID string) { func (h *TunnelHandler) UpdateMetrics(connectionID string) {

View File

@ -8,10 +8,12 @@ import (
"io/ioutil" "io/ioutil"
"net" "net"
log "github.com/sirupsen/logrus" "github.com/cloudflare/cloudflared/log"
cli "gopkg.in/urfave/cli.v2" "gopkg.in/urfave/cli.v2"
) )
var logger = log.CreateLogger()
// CLIFlags names the flags used to configure TLS for a command or subsystem. // CLIFlags names the flags used to configure TLS for a command or subsystem.
// The nil value for a field means the flag is ignored. // The nil value for a field means the flag is ignored.
type CLIFlags struct { type CLIFlags struct {
@ -29,7 +31,7 @@ func (f CLIFlags) GetConfig(c *cli.Context) *tls.Config {
if c.IsSet(f.Cert) && c.IsSet(f.Key) { if c.IsSet(f.Cert) && c.IsSet(f.Key) {
cert, err := tls.LoadX509KeyPair(c.String(f.Cert), c.String(f.Key)) cert, err := tls.LoadX509KeyPair(c.String(f.Cert), c.String(f.Key))
if err != nil { if err != nil {
log.WithError(err).Fatal("Error parsing X509 key pair") logger.WithError(err).Fatal("Error parsing X509 key pair")
} }
config.Certificates = []tls.Certificate{cert} config.Certificates = []tls.Certificate{cert}
config.BuildNameToCertificate() config.BuildNameToCertificate()
@ -53,11 +55,11 @@ func (f CLIFlags) GetConfig(c *cli.Context) *tls.Config {
func LoadCert(certPath string) *x509.CertPool { func LoadCert(certPath string) *x509.CertPool {
caCert, err := ioutil.ReadFile(certPath) caCert, err := ioutil.ReadFile(certPath)
if err != nil { if err != nil {
log.WithError(err).Fatalf("Error reading certificate %s", certPath) logger.WithError(err).Fatalf("Error reading certificate %s", certPath)
} }
ca := x509.NewCertPool() ca := x509.NewCertPool()
if !ca.AppendCertsFromPEM(caCert) { if !ca.AppendCertsFromPEM(caCert) {
log.WithError(err).Fatalf("Error parsing certificate %s", certPath) logger.WithError(err).Fatalf("Error parsing certificate %s", certPath)
} }
return ca return ca
} }
@ -66,23 +68,23 @@ func LoadOriginCertsPool() *x509.CertPool {
// First, obtain the system certificate pool // First, obtain the system certificate pool
certPool, systemCertPoolErr := x509.SystemCertPool() certPool, systemCertPoolErr := x509.SystemCertPool()
if systemCertPoolErr != nil { if systemCertPoolErr != nil {
log.Warn("error obtaining the system certificates: %s", systemCertPoolErr) logger.Warnf("error obtaining the system certificates: %s", systemCertPoolErr)
certPool = x509.NewCertPool() certPool = x509.NewCertPool()
} }
// Next, append the Cloudflare CA pool into the system pool // Next, append the Cloudflare CA pool into the system pool
if !certPool.AppendCertsFromPEM([]byte(cloudflareRootCA)) { if !certPool.AppendCertsFromPEM([]byte(cloudflareRootCA)) {
log.Warn("could not append the CF certificate to the system certificate pool") logger.Warn("could not append the CF certificate to the system certificate pool")
if systemCertPoolErr != nil { // Obtaining both certificates failed; this is a fatal error if systemCertPoolErr != nil { // Obtaining both certificates failed; this is a fatal error
log.WithError(systemCertPoolErr).Fatalf("Error loading the certificate pool") logger.WithError(systemCertPoolErr).Fatalf("Error loading the certificate pool")
} }
} }
// Finally, add the Hello certificate into the pool (since it's self-signed) // Finally, add the Hello certificate into the pool (since it's self-signed)
helloCertificate, err := GetHelloCertificateX509() helloCertificate, err := GetHelloCertificateX509()
if err != nil { if err != nil {
log.Warn("error obtaining the Hello server certificate") logger.Warn("error obtaining the Hello server certificate")
} }
certPool.AddCert(helloCertificate) certPool.AddCert(helloCertificate)

View File

@ -8,16 +8,18 @@ import (
"sync" "sync"
"syscall" "syscall"
"gopkg.in/urfave/cli.v2" "github.com/cloudflare/cloudflared/log"
"github.com/cloudflare/cloudflared/metrics" "github.com/cloudflare/cloudflared/metrics"
"github.com/coredns/coredns/core/dnsserver" "github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin" "github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/cache" "github.com/coredns/coredns/plugin/cache"
"github.com/pkg/errors" "github.com/pkg/errors"
log "github.com/sirupsen/logrus" "gopkg.in/urfave/cli.v2"
) )
var logger = log.CreateLogger()
// Listener is an adapter between CoreDNS server and Warp runnable // Listener is an adapter between CoreDNS server and Warp runnable
type Listener struct { type Listener struct {
server *dnsserver.Server server *dnsserver.Server
@ -28,14 +30,14 @@ type Listener struct {
func Run(c *cli.Context) error { func Run(c *cli.Context) error {
metricsListener, err := net.Listen("tcp", c.String("metrics")) metricsListener, err := net.Listen("tcp", c.String("metrics"))
if err != nil { if err != nil {
log.WithError(err).Fatal("Failed to open the metrics listener") logger.WithError(err).Fatal("Failed to open the metrics listener")
} }
go metrics.ServeMetrics(metricsListener, nil) go metrics.ServeMetrics(metricsListener, nil, logger)
listener, err := CreateListener(c.String("address"), uint16(c.Uint("port")), c.StringSlice("upstream")) listener, err := CreateListener(c.String("address"), uint16(c.Uint("port")), c.StringSlice("upstream"))
if err != nil { if err != nil {
log.WithError(err).Errorf("Failed to create the listeners") logger.WithError(err).Errorf("Failed to create the listeners")
return err return err
} }
@ -43,7 +45,7 @@ func Run(c *cli.Context) error {
readySignal := make(chan struct{}) readySignal := make(chan struct{})
err = listener.Start(readySignal) err = listener.Start(readySignal)
if err != nil { if err != nil {
log.WithError(err).Errorf("Failed to start the listeners") logger.WithError(err).Errorf("Failed to start the listeners")
return listener.Stop() return listener.Stop()
} }
<-readySignal <-readySignal
@ -57,7 +59,7 @@ func Run(c *cli.Context) error {
// Shut down server // Shut down server
err = listener.Stop() err = listener.Stop()
if err != nil { if err != nil {
log.WithError(err).Errorf("failed to stop") logger.WithError(err).Errorf("failed to stop")
} }
return err return err
} }
@ -78,7 +80,7 @@ func createConfig(address string, port uint16, p plugin.Handler) *dnsserver.Conf
// Start blocks for serving requests // Start blocks for serving requests
func (l *Listener) Start(readySignal chan struct{}) error { func (l *Listener) Start(readySignal chan struct{}) error {
defer close(readySignal) defer close(readySignal)
log.WithField("addr", l.server.Address()).Infof("Starting DNS over HTTPS proxy server") logger.WithField("addr", l.server.Address()).Infof("Starting DNS over HTTPS proxy server")
// Start UDP listener // Start UDP listener
if udp, err := l.server.ListenPacket(); err == nil { if udp, err := l.server.ListenPacket(); err == nil {
@ -119,7 +121,7 @@ func CreateListener(address string, port uint16, upstreams []string) (*Listener,
// Build the list of upstreams // Build the list of upstreams
upstreamList := make([]Upstream, 0) upstreamList := make([]Upstream, 0)
for _, url := range upstreams { for _, url := range upstreams {
log.WithField("url", url).Infof("Adding DNS upstream") logger.WithField("url", url).Infof("Adding DNS upstream")
upstream, err := NewUpstreamHTTPS(url) upstream, err := NewUpstreamHTTPS(url)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to create HTTPS upstream") return nil, errors.Wrap(err, "failed to create HTTPS upstream")

View File

@ -52,7 +52,7 @@ type RegistrationOptions struct {
ConnectionID uint8 `capnp:"connectionId"` ConnectionID uint8 `capnp:"connectionId"`
OriginLocalIP string `capnp:"originLocalIp"` OriginLocalIP string `capnp:"originLocalIp"`
IsAutoupdated bool `capnp:"isAutoupdated"` IsAutoupdated bool `capnp:"isAutoupdated"`
gracePeriodNanoSec int64 `capnp:"gracePeriodNanoSec"` RunFromTerminal bool `capnp:"runFromTerminal"`
} }
func MarshalRegistrationOptions(s tunnelrpc.RegistrationOptions, p *RegistrationOptions) error { func MarshalRegistrationOptions(s tunnelrpc.RegistrationOptions, p *RegistrationOptions) error {

View File

@ -37,6 +37,8 @@ struct RegistrationOptions {
originLocalIp @7 :Text; originLocalIp @7 :Text;
# whether Argo Tunnel client has been autoupdated # whether Argo Tunnel client has been autoupdated
isAutoupdated @8 :Bool; isAutoupdated @8 :Bool;
# whether Argo Tunnel client is run from a terminal
runFromTerminal @9 :Bool;
} }
struct Tag { struct Tag {

View File

@ -403,6 +403,14 @@ func (s RegistrationOptions) SetIsAutoupdated(v bool) {
s.Struct.SetBit(24, v) s.Struct.SetBit(24, v)
} }
func (s RegistrationOptions) RunFromTerminal() bool {
return s.Struct.Bit(25)
}
func (s RegistrationOptions) SetRunFromTerminal(v bool) {
s.Struct.SetBit(25, v)
}
// RegistrationOptions_List is a list of RegistrationOptions. // RegistrationOptions_List is a list of RegistrationOptions.
type RegistrationOptions_List struct{ capnp.List } type RegistrationOptions_List struct{ capnp.List }
@ -1218,86 +1226,88 @@ func (p TunnelServer_unregisterTunnel_Results_Promise) Struct() (TunnelServer_un
return TunnelServer_unregisterTunnel_Results{s}, err return TunnelServer_unregisterTunnel_Results{s}, err
} }
const schema_db8274f9144abc7e = "x\xda\x9cU_\x88Te\x1b\x7f~\xef;3g\x84" + const schema_db8274f9144abc7e = "x\xda\x9cU_l\x14U\x17\xff\x9d{w;\xdb\xa4" +
"]g\x0fg\x04\xbf\xe1\x93\xe5\x93\x15\xff\xe0\xfa\xe9\xa7" + "e;\x99m\x02\x1bH\x13\xd2\x86B\xbe\xf2\xc1\xc7\x87" +
"\xfb\xa1\xdb\x9f\xd9\xdd\xd4\x98m]\xe7\xdd\xd1\x10\xf5\xc2" + "B\xfd\xd3?\x02\xba\xb5\x94\xbdl1\x08}`\xd8\xbd" +
"\xe3\xcc\xeb\xec\xd9f\xce\x19\xce9c)\xa4%B " + "l\xa7\xce\xcelffQH\x04%\x18#\x89\x04E" +
"$\x96uc\x14\xe4e\x17\x15t\x11\x84\x81\xdd$\xe1" + "^0\x9a@\xe2\x8b\x0fj\xe2\x83\x89\xc1\x04_\xe4\x81" +
"\x85\x08\x19EB\x94l\xa1(\xd6\xa2\x90\x91\x9cx\xcf" + "\x07^\xd4h$1J\x88\x91h\x88\x8d\x9ahb\xc6" +
"\xec\x999\xae\xa5\xd6\xdd9\xcf\xfb>\xcf\xf3{\xfe\xfc" + "\xdc\xd9\xce\xecR\x14\xd0\xb7\x99\xdf=\xf7\x9c\xdf9\xf7" +
"~\xef\xea\x1f\xd9\x10[\x93\xfc.I$6&S\xc1" + "\x9c\xdfY\xf7+\x1be\xeb\xd3_\xa7\x01\xb1%\xdd\x11" +
"\xe3\xf5\x0b\xa7\xff\xff\xe6\xf9\xa3\xa4\xe7Xp\xe8\xcch" + ">X\xbbr\xfe\xbe3\x97\x8fC\xcf\xb3\xf0\xc8\x85\x89" +
"\xf6\x8e\x7f\xe4[\"\xac\xbd\xc4\x0e\xc2\xb8\xca4\"c" + "\xdco\xc1\xb1\xaf\x00\xda\xf0\x19;L\xc6\xf7L\x03\x8c" +
"\x9am%\x04\x17V\x9e\xf9\xe4\xc4G\xaf\xbcEb)" + "\xebl\x07(\xbc\xf2\x9f\x0b\x1f\x9ez\xff\xc5\xd7!V" +
"@\x94\xd0\x88\xd6\xdee\xbf\x81`\xe8<O\x08\xde\xf8" + "\x11\x01)\x0d\xd8\xf0\x07\xfb\x9d@\x86\xceG@\xe1k" +
"\xfa\xd3\xf1\xfak\xa7N\x93\xbe4:\xdf\xc0\x19\xa3D" + "_|4U{\xe5\xecy\xe8\xab\xe2\xf3\xcd\x9c1\xa4" +
"\xb0\xa0\x80\xcbg\xd7$>n\x9d$\xb9:\xea\xe7\xd7" + "\xc2\xde\x02]\xbd\xb8>\xf5A\xf3$\xcd\xd5\xd1\x10\xbf" +
"\x94\xeb0\xff\x80\x10,\xba1\xd2m\xdf<r\x96\xf4" + "\xa1\xae\x8e\xf1wA\xe1\x8a\x1f\xc7\xbb\x9d\x9b\xc7.B" +
"\x1c:(Z\x17\xbf\xe7\xa30n\xabO\xe3\x97\xf0\xf2" + "\xcfS\x8bE\xd3\xf0\x1b>A\xc6/\xea\xd3\xf8)2" +
"\xe8\xae\x93\xaf'\xa7O\x9e#\x91C\xfcvJ\xdd~" + "\x9e\xd8{\xfa\xd5\xf4\xf5\xd3\x97 \xf2\xd4n\xdd\xa1\xac" +
"5\xe1\xc2x7L\xfev\"\x00!\xc8}\xf8\xd8\xfb" + "_Nyd\x9c\x8b\x82\xbf\x91\xba\x9f\x81\xc2\xfc{\x0f" +
"#\x95o\xce\xcf\x89\x1dV\xf6Ej\xc6\xb8\xa4\xfc\x8c" + "\xbc3^\xf9\xf2\xf2\"\xdfQf\x9d\xda\xbc\xd1\xab\xa9" +
"\x8b\xa9\xe7\x09\x01\x9b6\xff\xf5\xd2WO^\x8e\x95\xd0" + "/]{\x1a\x14\xb2\xeb\xe6\xb2\xe7>\x7f\xf8j[\x0a" +
"\xaf\xfd\x00J\x04\xe3\xcf\xee\x9a\x9a\xf7\xe2\x95+\xb3%" + "5\xed[B*\x9czb\xef\\\xe7\xb3\xd7\xae-\xa4" +
"@\x1d\xfdG\x0bK\x18\xd0T\xf5\x03{\x86\xe5\xee\xf5" + "@\xea\xc8\xd4\xa2\x14\x1a\x9a\xca~\xe3\xbe19\xb3i" +
";\xae\x91\x9e\xe3\xf74r\xbb6\x08Cj*\x89\xa9" + "\xf7\x0d\xe8y~K!\xcfh\xc3d\xbc\x15\x059\xa7" +
"\x9d3\xae\xaa\xaf\xe0\xf8\xa1\x8d[7,\xfel&\x1e" + "]2Vg4 <yd\xcb\x8e\xcd+?\x9eo" +
"\xee\xa26\xa3\xc2M\x87\xe1\xf6\xad\xbf\xfe\xf4\x92\xe3\x9f" + "w\xa7g\xe6\x95\xbb\x81\x8crw`\xd3\x0f\x8f\x0e\x9c" +
"\xcf\xccA\x1d^L\xa6W\xc0X\x90V\x11\xf5t\x9e" + "\xfcd~\x11\xeb\xc8pkf\x0d\x19\xbb\x94\x1fC(" +
"ps\xf3;_\xe62\xb9[s\xfa\x11vo =" + "\xe3\x9b\xdb\xde\xfc4\x9f\xcd\xff\xbc\xa8\x1eQ\xf5\x1a\x99" +
"\x05\xa3\x10\xde\xdd\x94\xfe\x89\xfa\x03\xbfi\xdb\xb2\xe66" + "92^\x8al_\xc8|\x87\xa10h8\x8e\xb4\xbd" +
"\x12\xe5\xffF\x9f\xe5Ue\xb3a7\x067\xbd`y" + "z\xaa\xfc\xdf\xf8\xb3\xbc\xb6l\xd6\x9d\xfa\xf0\xd6g," +
"\xbeeW\xb7\x85\xf6|\xd1\xa9Y\xe5\x03E@t\x81" + "?\xb0\x9c\xeat\x84\x8f\x14]\xdb*\x1f*\x12\x89." +
"\x11\xe9\x8b\x06\x89\x00}\xc1N\"0]\x1f!\xca[" + "b\x80\xbeb\x18 \xd2{\xf7\x00\xc4t}\x1c\x18\xb1" +
"U\xdbqeP\xb1\xbc\xb2c\xdb\x92x\xd9?\xbc\xd7" + "\xaa\x8e\xeb\xc9\xb0b\xf9e\xd7q$x98\xba\xdf" +
"\xac\x99vY\xb6\x13\xa5\xeeO\xd4JP\x92\xee~\xe9" + "\xb4M\xa7,\x93@\x1d\xb7\x07j\x06(I\xef\xa0\xf4" +
"\xaej\xda\xae\xacZ\x9e/\xdd\x96\xb9/_4]\xb3" + "\xd66\x1cOV-?\x90^\x13\xee\x1f)\x9a\x9eY" +
"\xee\x89\x04O\x10%@\xa4w\x9f\"\x12=\x1c\xe2\xdf" + "\xf3E\x8a\xa7\x80\x14\x01z\xf7Y@\xf4p\x12\xcb\x19" +
"\x0cA\xd55\xcb\xb2(]XNe\xdc\xb4\x9d\x12\x97" + "\x85U\xcf,\xcb\xa2\xf4\xc8r+S\xa6\xe3\x96\xb8," +
"e$\x89!Ih'\x9d\xffw\x93NH\xafY\xf3" + "S\x1a\x8c\xd2\xa0$\xe8\x92\x7f\x1at\xa7\xf4\x1bv\xe0" +
"=j{=\xd8\x7f\x8ew\xd1\xcc\x84\x90\xbb\xda\x907" + "#\xb9u\xe7\xfb\x8bn\x17\xcdlD\xb9+\xa1\xbcu" +
"\xedT\x04\xe3\x10E\x06\x1d\xc8*\xca\xe8[F\x89\xc4" + "\x8f\x1a0N\xa2\xc8H'\xca\xa9\x91\xd1\xb7O\x00b" +
"\x18\x87\xd8\xc1\xa03\x96\x0d\xdb\xba}\x84H\x149\xc4" + "\x92\x93\xd8\xcdHg,\x17\x95u\xd78 \x8a\x9c\xc4" +
"n\x86\xc0q\xad\xaae?%\x89\xbb>\xba\x89\xa1\x9b" + "\x0c\xa3\xd0\xf5\xac\xaa\xe5<\"\xc1\xbd\x80\xba\xc1\xa8\x1b" +
"\x10L:\x9eo\x9buID\xe8\"\x86.\xc2a\xa7" + "\x14\xce\xba~\xe0\x985\x09\x80\xba\xc0\xa8\x0bt\xd4\xad" +
"\xe1[\x8e\xed\xa1\xa7C\x07\x02zb-\xf8\x93\x01\x0f" + "\x07\x96\xeb\xf8\xd4\xd3\x1a\x07\x10\xf5\xb4\x95\xe0/\x1ex" +
"7\xfdIi\xfbV\xd9T\xceD\xe1l;\x90\x17\x13" + "\xac\x11\xccJ'\xb0\xca\xa6\xba\x0cDo\xdb\xa2\xbc\x12" +
"\x89!\x0e1\x16\x83\\\xf8_\xac\x8e\x08\xf2\x96\xbd\x9d" + "\x10\xa3\x9c\xc4d\x1b\xe5\xc2\xff\xda\xf2\x88)o\xdf\xdf" +
":\xb4\xe7\xe4\x81\x08U\xaf\xac\x9bV-\xfa\x8b\x8a\x19" + "\xcaC{J\x1e\x8aY\xf5\xc9\x9ai\xd9\xf1_\x9c\xcc" +
"&\xed\x99\xce\x9d\x07\xe1\x9b\x08\xbb\xea\x86\xe8\xb66z" + "\x18\xb4\xc7[6w\xe2\xb73\xaa\xaa\x17\xb1\xdbQ\xef" +
"\xc3\x0a\x15\xc6\xbe6\xc6\x1b\xaa\x83\xd79\xc4\xaf1\x8c" + "\x8b2T\x1c\x07c\x8eF'M\x00\xa5\x0cq*\xe5" +
"\xb7U\x07\x7f\xe6\x10\xbf\xc70\xde\xc9\x11\x89[\x1c\x13" + "\xa8E\xd3\xd0i\x1c(u)|)\xb5\x98\x1a\xbd\x94" +
"`\x00\xcf\x82\x13\xe9w\xdf#\x9a\x00G\xa9\x0b\x0cz" + "\x07J=\x0a_N\x8c\x88\xe7\x88\x03\xc62z\x1b(" +
"\x82g\x91 2\xe6a\x94\xa8\x94V\xf6\xac\xb2'\x13" + "-W\xf0\xa02O\xf1\x1c\xa5\x00c r\xdf\xaf\xf0" +
"Y$\x15\xb7\xb0\x82\xa8\xd4\xa5\xec\xcb\x94=\xc5\xb2H" + "u\x0aO\xa7r\x94\x06\x8c!Z\x03\x94\x06\x15\xbeE" +
"\x11\x19K0ET\xeaS\xf6\xd5\xca\xae%\xb3\x8a\x96" + "\xe1\x1d,G\x1d\x801Fs@iT\xe1\x93\x0a\xd7" +
"F?\\\xa2\xd2Je_\xaf\xec\xe9\x85Y\xa4\x89\x8c" + "\xd295\xa1F\x81<\xa0\xf4\x98\xc2\xa7\x15\x9eY\x9a" +
"\x81\xd0\xbeN\xd9\x87\xc0\x10\x94k\x96\xb4\xfdB%>" + "\xa3\x8c\x1a\xd7\x08/*|F\xe1\x9d\xcbr\xd4\x09\x18" +
"\xce\xfd\xd2\xf5,\xc7\x8e\xfe\xb9\xe3\xb5\xfb%gY\x89" + "O\xd21\xa0\xb4[\xe1\x15b\x14\x96mK:A\xa1" +
"\xd6\xae\x15\x9d\x8c\xa2%2\x1d\xe9& C\x08\x1a\x8e" + "\xd2\xfe\xe2\x07\xa5\xe7[\xae\x13\xffs\xd7OJ*\x17" +
"S\x1b\xbfwM2\xbeY\xf50\x9fP\xe4@OG" + "\x06\x97\x9a\xedXt\xb3jr)\xdbRw\x10eA" +
"\x0a\x09\xca\x18\x84\xa4-\xfb\x16e\x1c\xbbPA\x8a\x18" + "a\xddu\xed\xa9[;)\x1b\x98U\x9f\x96\x80\x8a\x9c" +
"R\xed\xb9\x8d9\xd4[6k\x85F\x1b\x89\xe5\x0d7" + "\xa8\xa7\xa5\x96 \x05\x86\xd1\\\x97\x03\x0bY\xd7)T" +
"}\xa7\xd9\xa0\xde\x8a\xe9\xcb\x0a@\x0c\x88M\x94\xcd\x9d" + "\xa8\x03\x8c:\x92\xa7\x9dt\xd1W6\xedB=ab" +
"hocp\x9bYU\x13L\xb7'\xb8|\x05\x91\xe8" + "\xf9c\x8d\xc0m\xd4\xd1W1\x03Y!\x02#\x02\x85" +
"\xe3\x10\xabc\x13\xecW[\xb6\x8cC\xacc\xc8\xa8U" + "^\xc3\xd9\xe6\xb9\xb5i\x92^\xcdrL\x1b\xc9I\xdc" +
"oo\xd4~\xb3\xd6\x94\xf7\xed\xce\xc34\xa5*\xfd\xd6" + "\x03lq;\xf4\xd5\x87\xa7\xcd\xaaz\xfeL\xd2\xa2\xab" +
"W\xc1\xde\xe7\xf4\x15MW3\xeb\xde?\xf4\x9e\x90^" + "\xd7\x00\xa2\x9f\x93X\xd7\xd6\xa2C\xaaE\x079\x89\xff" +
"FIC\\\x8f\x06\x89D\x9aCd\x19\xf2n\xa8\x1c" + "3\xca\xaa9I\xda\xf1\xa0i7\xe4m\x8dw7A" +
"\xe8\xe9H\xf6\x1c\"\xf2\xbfJ\x97oei\xb10I" + "\xaa\xca\xa0\xf9Up\x0e\xb8\xfdE\xd3\xd3\xcc\x9a\xff/" +
"\xd4~'\x11=\x0f\xba8HL/h\xe8<M\x88" + "o\xef\x94~V\xe9J\xbb\x98\x0d\x03\"\xc3I\xe4\x18" +
"^\"\xfd\x09\x97\x98>\xa0\x81\xb5\x9ffDO\xb0\xbe" + "\x8dx\x91\xecPOK\xef\x17M1\xff\xbbp#\xcd" +
"\xfc\x181}\x89\x16D:E\xf9V\xca!\x04Qu" + "(\xcd\x11N\x03\xc9\x92\xa5x\xb7\xe8\xe20\x98^\xd0" +
"\xd4\x1b\xd67\x84 \x12CDzF4\x84\"\x1e\xbd" + "\xa8\xb5\xd7(^c\xfaC\x1e\x98\xbeQ#\x96\xecu" +
"\xdd\xf7ii\xaf\xf7(\x1d\x8b\xde\xad\x87\xf7\xab\x95'" + "\x8a\xf7\xb7\xbe\xfa\x04\x98>\xa0\x85\xb1\xc8a\xa4\x19r" +
"\xa3\xf0\xaan\xc5\xe2N\x11\x89.\x0e\xb1\x90!\xa89" + "\x94\xc28;\xf4E\xf9\x8dR\x18+)\xc5b\x08\x8c" +
"\xb3\xc2\x96\x19\x8f\xad\xd0\x83\x04\xa7\x058\x92\x9d\x8cr" + "R\x91\xee\xbd\xdc\xb7\x09q\x9f\x7f/\x15\x8b\x97\xde\xdd" +
"V\xf1{\xda\xf1M\xa5\x89\xbb9\xc4dl[\xa52" + "\xeb\xd5\x8c\x93U|U\xb5\xda\xfc\xce\x01\xa2\x8b\x93X" +
"\xee\xe1\x10\xb5\x98\xdeXJ\x99&9\xc4\xd1\x8e\xde\xbc" + "\xca(\xb4\xdd\x05U\xccN\xb5\xb5\xd0\x9d\xd4\xaaI8" +
"|\x8cH\x1c\xe5\x10'\x184\xe9\xba\x11$\xad\xe9v" + "\xd6\xac\xac\xba\xac\xfc\xf7$\xfeM%\xa83\x9c\xc4l" +
"T\xb2\xe6T\xc7,[z\x8a\xb6\xb3LUG\x8a\x9f" + "[\xb7J\x05\xee\xe3$\xec6A\xb5\xd4b\x98\xe5$" +
"\x0d\xe9\xd6M[\xda\xf07\x9bV\xad\xe9J\xb5Z-" + "\x8e'\x1a\xa5?\x7f\x02\x10\xc79\x89S\x8c4\xe9y" +
"\xd2\xfd\x11\x00\x00\xff\xffy%\x9bh" "1%\xad\xe1\xb5$\xd6v\xab\x93\x96#}5\xd0\x0b" +
"3\xac\x8e\xd4\xe4\xd6\xa5W3\x1d\xe9P\xb0\xcd\xb4\xec" +
"\x86'\x91\x0c\xdd\x9f\x01\x00\x00\xff\xffR3\x9d#"
func init() { func init() {
schemas.Register(schema_db8274f9144abc7e, schemas.Register(schema_db8274f9144abc7e,