Compare commits
13 Commits
Author | SHA1 | Date |
---|---|---|
|
d8a066628b | |
|
553e77e061 | |
|
8f94f54ec7 | |
|
2827b2fe8f | |
|
6dc8ed710e | |
|
e0b1ac0d05 | |
|
e7c5eb54af | |
|
cfec602fa7 | |
|
6fceb94998 | |
|
cf817f7036 | |
|
c8724a290a | |
|
e7586153be | |
|
11777db304 |
2
Makefile
2
Makefile
|
@ -24,7 +24,7 @@ else
|
||||||
DEB_PACKAGE_NAME := $(BINARY_NAME)
|
DEB_PACKAGE_NAME := $(BINARY_NAME)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
DATE := $(shell date -u '+%Y-%m-%d-%H%M UTC')
|
DATE := $(shell date -u -r RELEASE_NOTES '+%Y-%m-%d-%H%M UTC')
|
||||||
VERSION_FLAGS := -X "main.Version=$(VERSION)" -X "main.BuildTime=$(DATE)"
|
VERSION_FLAGS := -X "main.Version=$(VERSION)" -X "main.BuildTime=$(DATE)"
|
||||||
ifdef PACKAGE_MANAGER
|
ifdef PACKAGE_MANAGER
|
||||||
VERSION_FLAGS := $(VERSION_FLAGS) -X "github.com/cloudflare/cloudflared/cmd/cloudflared/updater.BuiltForPackageManager=$(PACKAGE_MANAGER)"
|
VERSION_FLAGS := $(VERSION_FLAGS) -X "github.com/cloudflare/cloudflared/cmd/cloudflared/updater.BuiltForPackageManager=$(PACKAGE_MANAGER)"
|
||||||
|
|
|
@ -40,7 +40,7 @@ User documentation for Cloudflare Tunnel can be found at https://developers.clou
|
||||||
|
|
||||||
Once installed, you can authenticate `cloudflared` into your Cloudflare account and begin creating Tunnels to serve traffic to your origins.
|
Once installed, you can authenticate `cloudflared` into your Cloudflare account and begin creating Tunnels to serve traffic to your origins.
|
||||||
|
|
||||||
* Create a Tunnel with [these instructions](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/create-tunnel)
|
* Create a Tunnel with [these instructions](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/)
|
||||||
* Route traffic to that Tunnel:
|
* Route traffic to that Tunnel:
|
||||||
* Via public [DNS records in Cloudflare](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/routing-to-tunnel/dns)
|
* Via public [DNS records in Cloudflare](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/routing-to-tunnel/dns)
|
||||||
* Or via a public hostname guided by a [Cloudflare Load Balancer](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/routing-to-tunnel/lb)
|
* Or via a public hostname guided by a [Cloudflare Load Balancer](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/routing-to-tunnel/lb)
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
2025.4.0
|
||||||
|
- 2025-04-02 Fix broken links in `cmd/cloudflared/*.go` related to running tunnel as a service
|
||||||
|
- 2025-04-02 chore: remove repetitive words
|
||||||
|
- 2025-04-01 Fix messages to point to one.dash.cloudflare.com
|
||||||
|
- 2025-04-01 feat: emit explicit errors for the `service` command on unsupported OSes
|
||||||
|
- 2025-04-01 Use RELEASE_NOTES date instead of build date
|
||||||
|
- 2025-04-01 chore: Update tunnel configuration link in the readme
|
||||||
|
- 2025-04-01 fix: expand home directory for credentials file
|
||||||
|
- 2025-04-01 fix: Use path and filepath operation appropriately
|
||||||
|
- 2025-04-01 feat: Adds a new command line for tunnel run for token file
|
||||||
|
- 2025-04-01 chore: fix linter rules
|
||||||
|
- 2025-03-17 TUN-9101: Don't ignore errors on `cloudflared access ssh`
|
||||||
|
- 2025-03-06 TUN-9089: Pin go import to v0.30.0, v0.31.0 requires go 1.23
|
||||||
|
|
||||||
2025.2.1
|
2025.2.1
|
||||||
- 2025-02-26 TUN-9016: update base-debian to v12
|
- 2025-02-26 TUN-9016: update base-debian to v12
|
||||||
- 2025-02-25 TUN-8960: Connect to FED API GW based on the OriginCert's endpoint
|
- 2025-02-25 TUN-8960: Connect to FED API GW based on the OriginCert's endpoint
|
||||||
|
|
|
@ -16,7 +16,7 @@ bullseye: &bullseye
|
||||||
- golangci-lint
|
- golangci-lint
|
||||||
pre-cache: &build_pre_cache
|
pre-cache: &build_pre_cache
|
||||||
- export GOCACHE=/cfsetup_build/.cache/go-build
|
- export GOCACHE=/cfsetup_build/.cache/go-build
|
||||||
- go install golang.org/x/tools/cmd/goimports@latest
|
- go install golang.org/x/tools/cmd/goimports@v0.30.0
|
||||||
post-cache:
|
post-cache:
|
||||||
# Linting
|
# Linting
|
||||||
- make lint
|
- make lint
|
||||||
|
|
|
@ -104,7 +104,7 @@ func ssh(c *cli.Context) error {
|
||||||
case 3:
|
case 3:
|
||||||
options.OriginURL = fmt.Sprintf("https://%s:%s", parts[2], parts[1])
|
options.OriginURL = fmt.Sprintf("https://%s:%s", parts[2], parts[1])
|
||||||
options.TLSClientConfig = &tls.Config{
|
options.TLSClientConfig = &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true, // #nosec G402
|
||||||
ServerName: parts[0],
|
ServerName: parts[0],
|
||||||
}
|
}
|
||||||
log.Warn().Msgf("Using insecure SSL connection because SNI overridden to %s", parts[0])
|
log.Warn().Msgf("Using insecure SSL connection because SNI overridden to %s", parts[0])
|
||||||
|
@ -141,6 +141,5 @@ func ssh(c *cli.Context) error {
|
||||||
logger := log.With().Str("host", url.Host).Logger()
|
logger := log.With().Str("host", url.Host).Logger()
|
||||||
s = stream.NewDebugStream(s, &logger, maxMessages)
|
s = stream.NewDebugStream(s, &logger, maxMessages)
|
||||||
}
|
}
|
||||||
carrier.StartClient(wsConn, s, options)
|
return carrier.StartClient(wsConn, s, options)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,38 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
cli "github.com/urfave/cli/v2"
|
cli "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runApp(app *cli.App, graceShutdownC chan struct{}) {
|
func runApp(app *cli.App, graceShutdownC chan struct{}) {
|
||||||
|
app.Commands = append(app.Commands, &cli.Command{
|
||||||
|
Name: "service",
|
||||||
|
Usage: "Manages the cloudflared system service (not supported on this operating system)",
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "install",
|
||||||
|
Usage: "Install cloudflared as a system service (not supported on this operating system)",
|
||||||
|
Action: cliutil.ConfiguredAction(installGenericService),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "uninstall",
|
||||||
|
Usage: "Uninstall the cloudflared service (not supported on this operating system)",
|
||||||
|
Action: cliutil.ConfiguredAction(uninstallGenericService),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
app.Run(os.Args)
|
app.Run(os.Args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func installGenericService(c *cli.Context) error {
|
||||||
|
return fmt.Errorf("service installation is not supported on this operating system")
|
||||||
|
}
|
||||||
|
|
||||||
|
func uninstallGenericService(c *cli.Context) error {
|
||||||
|
return fmt.Errorf("service uninstallation is not supported on this operating system")
|
||||||
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ func installLaunchd(c *cli.Context) error {
|
||||||
log.Info().Msg("Installing cloudflared client as an user launch agent. " +
|
log.Info().Msg("Installing cloudflared client as an user launch agent. " +
|
||||||
"Note that cloudflared client will only run when the user is logged in. " +
|
"Note that cloudflared client will only run when the user is logged in. " +
|
||||||
"If you want to run cloudflared client at boot, install with root permission. " +
|
"If you want to run cloudflared client at boot, install with root permission. " +
|
||||||
"For more information, visit https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/run-as-service")
|
"For more information, visit https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/configure-tunnels/local-management/as-a-service/macos/")
|
||||||
}
|
}
|
||||||
etPath, err := os.Executable()
|
etPath, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path/filepath"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
homedir "github.com/mitchellh/go-homedir"
|
homedir "github.com/mitchellh/go-homedir"
|
||||||
|
@ -44,7 +44,7 @@ func (st *ServiceTemplate) Generate(args *ServiceTemplateArgs) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err = os.Stat(resolvedPath); err == nil {
|
if _, err = os.Stat(resolvedPath); err == nil {
|
||||||
return fmt.Errorf(serviceAlreadyExistsWarn(resolvedPath))
|
return errors.New(serviceAlreadyExistsWarn(resolvedPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
|
@ -57,7 +57,7 @@ func (st *ServiceTemplate) Generate(args *ServiceTemplateArgs) error {
|
||||||
fileMode = st.FileMode
|
fileMode = st.FileMode
|
||||||
}
|
}
|
||||||
|
|
||||||
plistFolder := path.Dir(resolvedPath)
|
plistFolder := filepath.Dir(resolvedPath)
|
||||||
err = os.MkdirAll(plistFolder, 0o755)
|
err = os.MkdirAll(plistFolder, 0o755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating %s: %v", plistFolder, err)
|
return fmt.Errorf("error creating %s: %v", plistFolder, err)
|
||||||
|
@ -118,49 +118,6 @@ func ensureConfigDirExists(configDir string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// openFile opens the file at path. If create is set and the file exists, returns nil, true, nil
|
|
||||||
func openFile(path string, create bool) (file *os.File, exists bool, err error) {
|
|
||||||
expandedPath, err := homedir.Expand(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
if create {
|
|
||||||
fileInfo, err := os.Stat(expandedPath)
|
|
||||||
if err == nil && fileInfo.Size() > 0 {
|
|
||||||
return nil, true, nil
|
|
||||||
}
|
|
||||||
file, err = os.OpenFile(expandedPath, os.O_RDWR|os.O_CREATE, 0600)
|
|
||||||
} else {
|
|
||||||
file, err = os.Open(expandedPath)
|
|
||||||
}
|
|
||||||
return file, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyCredential(srcCredentialPath, destCredentialPath string) error {
|
|
||||||
destFile, exists, err := openFile(destCredentialPath, true)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if exists {
|
|
||||||
// credentials already exist, do nothing
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
defer destFile.Close()
|
|
||||||
|
|
||||||
srcFile, _, err := openFile(srcCredentialPath, false)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer srcFile.Close()
|
|
||||||
|
|
||||||
// Copy certificate
|
|
||||||
_, err = io.Copy(destFile, srcFile)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to copy %s to %s: %v", srcCredentialPath, destCredentialPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyFile(src, dest string) error {
|
func copyFile(src, dest string) error {
|
||||||
srcFile, err := os.Open(src)
|
srcFile, err := os.Open(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -187,36 +144,3 @@ func copyFile(src, dest string) error {
|
||||||
ok = true
|
ok = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyConfig(srcConfigPath, destConfigPath string) error {
|
|
||||||
// Copy or create config
|
|
||||||
destFile, exists, err := openFile(destConfigPath, true)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot open %s with error: %s", destConfigPath, err)
|
|
||||||
} else if exists {
|
|
||||||
// config already exists, do nothing
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
defer destFile.Close()
|
|
||||||
|
|
||||||
srcFile, _, err := openFile(srcConfigPath, false)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Your service needs a config file that at least specifies the hostname option.")
|
|
||||||
fmt.Println("Type in a hostname now, or leave it blank and create the config file later.")
|
|
||||||
fmt.Print("Hostname: ")
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
|
||||||
input, _ := reader.ReadString('\n')
|
|
||||||
if input == "" {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(destFile, "hostname: %s\n", input)
|
|
||||||
} else {
|
|
||||||
defer srcFile.Close()
|
|
||||||
_, err = io.Copy(destFile, srcFile)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to copy %s to %s: %v", srcConfigPath, destConfigPath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -208,7 +208,7 @@ then protect with Cloudflare Access).
|
||||||
B) Locally reachable TCP/UDP-based private services to Cloudflare connected private users in the same account, e.g.,
|
B) Locally reachable TCP/UDP-based private services to Cloudflare connected private users in the same account, e.g.,
|
||||||
those enrolled to a Zero Trust WARP Client.
|
those enrolled to a Zero Trust WARP Client.
|
||||||
|
|
||||||
You can manage your Tunnels via dash.teams.cloudflare.com. This approach will only require you to run a single command
|
You can manage your Tunnels via one.dash.cloudflare.com. This approach will only require you to run a single command
|
||||||
later in each machine where you wish to run a Tunnel.
|
later in each machine where you wish to run a Tunnel.
|
||||||
|
|
||||||
Alternatively, you can manage your Tunnels via the command line. Begin by obtaining a certificate to be able to do so:
|
Alternatively, you can manage your Tunnels via the command line. Begin by obtaining a certificate to be able to do so:
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
@ -54,7 +55,12 @@ func newSubcommandContext(c *cli.Context) (*subcommandContext, error) {
|
||||||
// Returns something that can find the given tunnel's credentials file.
|
// Returns something that can find the given tunnel's credentials file.
|
||||||
func (sc *subcommandContext) credentialFinder(tunnelID uuid.UUID) CredFinder {
|
func (sc *subcommandContext) credentialFinder(tunnelID uuid.UUID) CredFinder {
|
||||||
if path := sc.c.String(CredFileFlag); path != "" {
|
if path := sc.c.String(CredFileFlag); path != "" {
|
||||||
return newStaticPath(path, sc.fs)
|
// Expand path if CredFileFlag contains `~`
|
||||||
|
absPath, err := homedir.Expand(path)
|
||||||
|
if err != nil {
|
||||||
|
return newStaticPath(path, sc.fs)
|
||||||
|
}
|
||||||
|
return newStaticPath(absPath, sc.fs)
|
||||||
}
|
}
|
||||||
return newSearchByID(tunnelID, sc.c, sc.log, sc.fs)
|
return newSearchByID(tunnelID, sc.c, sc.log, sc.fs)
|
||||||
}
|
}
|
||||||
|
@ -106,7 +112,7 @@ func (sc *subcommandContext) readTunnelCredentials(credFinder CredFinder) (conne
|
||||||
|
|
||||||
var credentials connection.Credentials
|
var credentials connection.Credentials
|
||||||
if err = json.Unmarshal(body, &credentials); err != nil {
|
if err = json.Unmarshal(body, &credentials); err != nil {
|
||||||
if strings.HasSuffix(filePath, ".pem") {
|
if filepath.Ext(filePath) == ".pem" {
|
||||||
return connection.Credentials{}, fmt.Errorf("The tunnel credentials file should be .json but you gave a .pem. " +
|
return connection.Credentials{}, fmt.Errorf("The tunnel credentials file should be .json but you gave a .pem. " +
|
||||||
"The tunnel credentials file was originally created by `cloudflared tunnel create`. " +
|
"The tunnel credentials file was originally created by `cloudflared tunnel create`. " +
|
||||||
"You may have accidentally used the filepath to cert.pem, which is generated by `cloudflared tunnel " +
|
"You may have accidentally used the filepath to cert.pem, which is generated by `cloudflared tunnel " +
|
||||||
|
|
|
@ -41,6 +41,7 @@ const (
|
||||||
CredFileFlag = "credentials-file"
|
CredFileFlag = "credentials-file"
|
||||||
CredContentsFlag = "credentials-contents"
|
CredContentsFlag = "credentials-contents"
|
||||||
TunnelTokenFlag = "token"
|
TunnelTokenFlag = "token"
|
||||||
|
TunnelTokenFileFlag = "token-file"
|
||||||
overwriteDNSFlagName = "overwrite-dns"
|
overwriteDNSFlagName = "overwrite-dns"
|
||||||
noDiagLogsFlagName = "no-diag-logs"
|
noDiagLogsFlagName = "no-diag-logs"
|
||||||
noDiagMetricsFlagName = "no-diag-metrics"
|
noDiagMetricsFlagName = "no-diag-metrics"
|
||||||
|
@ -126,9 +127,14 @@ var (
|
||||||
})
|
})
|
||||||
tunnelTokenFlag = altsrc.NewStringFlag(&cli.StringFlag{
|
tunnelTokenFlag = altsrc.NewStringFlag(&cli.StringFlag{
|
||||||
Name: TunnelTokenFlag,
|
Name: TunnelTokenFlag,
|
||||||
Usage: "The Tunnel token. When provided along with credentials, this will take precedence.",
|
Usage: "The Tunnel token. When provided along with credentials, this will take precedence. Also takes precedence over token-file",
|
||||||
EnvVars: []string{"TUNNEL_TOKEN"},
|
EnvVars: []string{"TUNNEL_TOKEN"},
|
||||||
})
|
})
|
||||||
|
tunnelTokenFileFlag = altsrc.NewStringFlag(&cli.StringFlag{
|
||||||
|
Name: TunnelTokenFileFlag,
|
||||||
|
Usage: "Filepath at which to read the tunnel token. When provided along with credentials, this will take precedence.",
|
||||||
|
EnvVars: []string{"TUNNEL_TOKEN_FILE"},
|
||||||
|
})
|
||||||
forceDeleteFlag = &cli.BoolFlag{
|
forceDeleteFlag = &cli.BoolFlag{
|
||||||
Name: flags.Force,
|
Name: flags.Force,
|
||||||
Aliases: []string{"f"},
|
Aliases: []string{"f"},
|
||||||
|
@ -708,6 +714,7 @@ func buildRunCommand() *cli.Command {
|
||||||
selectProtocolFlag,
|
selectProtocolFlag,
|
||||||
featuresFlag,
|
featuresFlag,
|
||||||
tunnelTokenFlag,
|
tunnelTokenFlag,
|
||||||
|
tunnelTokenFileFlag,
|
||||||
icmpv4SrcFlag,
|
icmpv4SrcFlag,
|
||||||
icmpv6SrcFlag,
|
icmpv6SrcFlag,
|
||||||
maxActiveFlowsFlag,
|
maxActiveFlowsFlag,
|
||||||
|
@ -748,12 +755,22 @@ func runCommand(c *cli.Context) error {
|
||||||
"your origin will not be reachable. You should remove the `hostname` property to avoid this warning.")
|
"your origin will not be reachable. You should remove the `hostname` property to avoid this warning.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tokenStr := c.String(TunnelTokenFlag)
|
||||||
|
// Check if tokenStr is blank before checking for tokenFile
|
||||||
|
if tokenStr == "" {
|
||||||
|
if tokenFile := c.String(TunnelTokenFileFlag); tokenFile != "" {
|
||||||
|
data, err := os.ReadFile(tokenFile)
|
||||||
|
if err != nil {
|
||||||
|
return cliutil.UsageError("Failed to read token file: " + err.Error())
|
||||||
|
}
|
||||||
|
tokenStr = strings.TrimSpace(string(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
// Check if token is provided and if not use default tunnelID flag method
|
// Check if token is provided and if not use default tunnelID flag method
|
||||||
if tokenStr := c.String(TunnelTokenFlag); tokenStr != "" {
|
if tokenStr != "" {
|
||||||
if token, err := ParseToken(tokenStr); err == nil {
|
if token, err := ParseToken(tokenStr); err == nil {
|
||||||
return sc.runWithCredentials(token.Credentials())
|
return sc.runWithCredentials(token.Credentials())
|
||||||
}
|
}
|
||||||
|
|
||||||
return cliutil.UsageError("Provided Tunnel token is not valid.")
|
return cliutil.UsageError("Provided Tunnel token is not valid.")
|
||||||
} else {
|
} else {
|
||||||
tunnelRef := c.Args().First()
|
tunnelRef := c.Args().First()
|
||||||
|
|
|
@ -22,7 +22,7 @@ var (
|
||||||
Usage: "The ID or name of the virtual network to which the route is associated to.",
|
Usage: "The ID or name of the virtual network to which the route is associated to.",
|
||||||
}
|
}
|
||||||
|
|
||||||
routeAddError = errors.New("You must supply exactly one argument, the ID or CIDR of the route you want to delete")
|
errAddRoute = errors.New("You must supply exactly one argument, the ID or CIDR of the route you want to delete")
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildRouteIPSubcommand() *cli.Command {
|
func buildRouteIPSubcommand() *cli.Command {
|
||||||
|
@ -32,7 +32,7 @@ func buildRouteIPSubcommand() *cli.Command {
|
||||||
UsageText: "cloudflared tunnel [--config FILEPATH] route COMMAND [arguments...]",
|
UsageText: "cloudflared tunnel [--config FILEPATH] route COMMAND [arguments...]",
|
||||||
Description: `cloudflared can provision routes for any IP space in your corporate network. Users enrolled in
|
Description: `cloudflared can provision routes for any IP space in your corporate network. Users enrolled in
|
||||||
your Cloudflare for Teams organization can reach those IPs through the Cloudflare WARP
|
your Cloudflare for Teams organization can reach those IPs through the Cloudflare WARP
|
||||||
client. You can then configure L7/L4 filtering on https://dash.teams.cloudflare.com to
|
client. You can then configure L7/L4 filtering on https://one.dash.cloudflare.com to
|
||||||
determine who can reach certain routes.
|
determine who can reach certain routes.
|
||||||
By default IP routes all exist within a single virtual network. If you use the same IP
|
By default IP routes all exist within a single virtual network. If you use the same IP
|
||||||
space(s) in different physical private networks, all meant to be reachable via IP routes,
|
space(s) in different physical private networks, all meant to be reachable via IP routes,
|
||||||
|
@ -187,7 +187,7 @@ func deleteRouteCommand(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.NArg() != 1 {
|
if c.NArg() != 1 {
|
||||||
return routeAddError
|
return errAddRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
var routeId uuid.UUID
|
var routeId uuid.UUID
|
||||||
|
@ -195,7 +195,7 @@ func deleteRouteCommand(c *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, network, err := net.ParseCIDR(c.Args().First())
|
_, network, err := net.ParseCIDR(c.Args().First())
|
||||||
if err != nil || network == nil {
|
if err != nil || network == nil {
|
||||||
return routeAddError
|
return errAddRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
var vnetId *uuid.UUID
|
var vnetId *uuid.UUID
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultCheckUpdateFreq = time.Hour * 24
|
DefaultCheckUpdateFreq = time.Hour * 24
|
||||||
noUpdateInShellMessage = "cloudflared will not automatically update when run from the shell. To enable auto-updates, run cloudflared as a service: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/as-a-service/"
|
noUpdateInShellMessage = "cloudflared will not automatically update when run from the shell. To enable auto-updates, run cloudflared as a service: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configure-tunnels/local-management/as-a-service/"
|
||||||
noUpdateOnWindowsMessage = "cloudflared will not automatically update on Windows systems."
|
noUpdateOnWindowsMessage = "cloudflared will not automatically update on Windows systems."
|
||||||
noUpdateManagedPackageMessage = "cloudflared will not automatically update if installed by a package manager."
|
noUpdateManagedPackageMessage = "cloudflared will not automatically update if installed by a package manager."
|
||||||
isManagedInstallFile = ".installedFromPackageManager"
|
isManagedInstallFile = ".installedFromPackageManager"
|
||||||
|
|
|
@ -10,9 +10,9 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ func (v *WorkersVersion) Apply() error {
|
||||||
|
|
||||||
if err := os.Rename(newFilePath, v.targetPath); err != nil {
|
if err := os.Rename(newFilePath, v.targetPath); err != nil {
|
||||||
//attempt rollback
|
//attempt rollback
|
||||||
os.Rename(oldFilePath, v.targetPath)
|
_ = os.Rename(oldFilePath, v.targetPath)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
os.Remove(oldFilePath)
|
os.Remove(oldFilePath)
|
||||||
|
@ -181,7 +181,7 @@ func download(url, filepath string, isCompressed bool) error {
|
||||||
tr := tar.NewReader(gr)
|
tr := tar.NewReader(gr)
|
||||||
|
|
||||||
// advance the reader pass the header, which will be the single binary file
|
// advance the reader pass the header, which will be the single binary file
|
||||||
tr.Next()
|
_, _ = tr.Next()
|
||||||
|
|
||||||
r = tr
|
r = tr
|
||||||
}
|
}
|
||||||
|
@ -198,7 +198,7 @@ func download(url, filepath string, isCompressed bool) error {
|
||||||
|
|
||||||
// isCompressedFile is a really simple file extension check to see if this is a macos tar and gzipped
|
// isCompressedFile is a really simple file extension check to see if this is a macos tar and gzipped
|
||||||
func isCompressedFile(urlstring string) bool {
|
func isCompressedFile(urlstring string) bool {
|
||||||
if strings.HasSuffix(urlstring, ".tgz") {
|
if path.Ext(urlstring) == ".tgz" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ func isCompressedFile(urlstring string) bool {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return strings.HasSuffix(u.Path, ".tgz")
|
return path.Ext(u.Path) == ".tgz"
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeBatchFile writes a batch file out to disk
|
// writeBatchFile writes a batch file out to disk
|
||||||
|
@ -249,7 +249,6 @@ func runWindowsBatch(batchFile string) error {
|
||||||
if exitError, ok := err.(*exec.ExitError); ok {
|
if exitError, ok := err.(*exec.ExitError); ok {
|
||||||
return fmt.Errorf("Error during update : %s;", string(exitError.Stderr))
|
return fmt.Errorf("Error during update : %s;", string(exitError.Stderr))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
const (
|
const (
|
||||||
windowsServiceName = "Cloudflared"
|
windowsServiceName = "Cloudflared"
|
||||||
windowsServiceDescription = "Cloudflared agent"
|
windowsServiceDescription = "Cloudflared agent"
|
||||||
windowsServiceUrl = "https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/as-a-service/windows/"
|
windowsServiceUrl = "https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configure-tunnels/local-management/as-a-service/windows/"
|
||||||
|
|
||||||
recoverActionDelay = time.Second * 20
|
recoverActionDelay = time.Second * 20
|
||||||
failureCountResetPeriod = time.Hour * 24
|
failureCountResetPeriod = time.Hour * 24
|
||||||
|
|
|
@ -3,7 +3,7 @@ package credentials
|
||||||
import (
|
import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -13,8 +13,8 @@ func TestCredentialsRead(t *testing.T) {
|
||||||
file, err := os.ReadFile("test-cloudflare-tunnel-cert-json.pem")
|
file, err := os.ReadFile("test-cloudflare-tunnel-cert-json.pem")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
certPath := path.Join(dir, originCertFile)
|
certPath := filepath.Join(dir, originCertFile)
|
||||||
os.WriteFile(certPath, file, fs.ModePerm)
|
_ = os.WriteFile(certPath, file, fs.ModePerm)
|
||||||
user, err := Read(certPath, &nopLog)
|
user, err := Read(certPath, &nopLog)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, certPath, user.CertPath())
|
require.Equal(t, certPath, user.CertPath())
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
@ -63,7 +63,7 @@ func TestFindOriginCert_Valid(t *testing.T) {
|
||||||
file, err := os.ReadFile("test-cloudflare-tunnel-cert-json.pem")
|
file, err := os.ReadFile("test-cloudflare-tunnel-cert-json.pem")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
certPath := path.Join(dir, originCertFile)
|
certPath := filepath.Join(dir, originCertFile)
|
||||||
_ = os.WriteFile(certPath, file, fs.ModePerm)
|
_ = os.WriteFile(certPath, file, fs.ModePerm)
|
||||||
path, err := FindOriginCert(certPath, &nopLog)
|
path, err := FindOriginCert(certPath, &nopLog)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -72,7 +72,7 @@ func TestFindOriginCert_Valid(t *testing.T) {
|
||||||
|
|
||||||
func TestFindOriginCert_Missing(t *testing.T) {
|
func TestFindOriginCert_Missing(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
certPath := path.Join(dir, originCertFile)
|
certPath := filepath.Join(dir, originCertFile)
|
||||||
_, err := FindOriginCert(certPath, &nopLog)
|
_, err := FindOriginCert(certPath, &nopLog)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -249,7 +248,7 @@ func createRollingLogger(config RollingConfig) (io.Writer, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
rotatingFileInit.writer = &lumberjack.Logger{
|
rotatingFileInit.writer = &lumberjack.Logger{
|
||||||
Filename: path.Join(config.Dirname, config.Filename),
|
Filename: filepath.Join(config.Dirname, config.Filename),
|
||||||
MaxBackups: config.maxBackups,
|
MaxBackups: config.maxBackups,
|
||||||
MaxSize: config.maxSize,
|
MaxSize: config.maxSize,
|
||||||
MaxAge: config.maxAge,
|
MaxAge: config.maxAge,
|
||||||
|
|
|
@ -74,7 +74,7 @@ type EventLog struct {
|
||||||
type LogEventType int8
|
type LogEventType int8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Cloudflared events are signficant to cloudflared operations like connection state changes.
|
// Cloudflared events are significant to cloudflared operations like connection state changes.
|
||||||
// Cloudflared is also the default event type for any events that haven't been separated into a proper event type.
|
// Cloudflared is also the default event type for any events that haven't been separated into a proper event type.
|
||||||
Cloudflared LogEventType = iota
|
Cloudflared LogEventType = iota
|
||||||
HTTP
|
HTTP
|
||||||
|
@ -129,7 +129,7 @@ func (e *LogEventType) UnmarshalJSON(data []byte) error {
|
||||||
|
|
||||||
// LogLevel corresponds to the zerolog logging levels
|
// LogLevel corresponds to the zerolog logging levels
|
||||||
// "panic", "fatal", and "trace" are exempt from this list as they are rarely used and, at least
|
// "panic", "fatal", and "trace" are exempt from this list as they are rarely used and, at least
|
||||||
// the the first two are limited to failure conditions that lead to cloudflared shutting down.
|
// the first two are limited to failure conditions that lead to cloudflared shutting down.
|
||||||
type LogLevel int8
|
type LogLevel int8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -79,8 +79,8 @@ func (b *BackoffHandler) BackoffTimer() <-chan time.Time {
|
||||||
} else {
|
} else {
|
||||||
b.retries++
|
b.retries++
|
||||||
}
|
}
|
||||||
maxTimeToWait := time.Duration(b.GetBaseTime() * 1 << (b.retries))
|
maxTimeToWait := b.GetBaseTime() * (1 << b.retries)
|
||||||
timeToWait := time.Duration(rand.Int63n(maxTimeToWait.Nanoseconds()))
|
timeToWait := time.Duration(rand.Int63n(maxTimeToWait.Nanoseconds())) // #nosec G404
|
||||||
return b.Clock.After(timeToWait)
|
return b.Clock.After(timeToWait)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,11 +99,11 @@ func (b *BackoffHandler) Backoff(ctx context.Context) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets a grace period within which the the backoff timer is maintained. After the grace
|
// Sets a grace period within which the backoff timer is maintained. After the grace
|
||||||
// period expires, the number of retries & backoff duration is reset.
|
// period expires, the number of retries & backoff duration is reset.
|
||||||
func (b *BackoffHandler) SetGracePeriod() time.Duration {
|
func (b *BackoffHandler) SetGracePeriod() time.Duration {
|
||||||
maxTimeToWait := b.GetBaseTime() * 2 << (b.retries + 1)
|
maxTimeToWait := b.GetBaseTime() * 2 << (b.retries + 1)
|
||||||
timeToWait := time.Duration(rand.Int63n(maxTimeToWait.Nanoseconds()))
|
timeToWait := time.Duration(rand.Int63n(maxTimeToWait.Nanoseconds())) // #nosec G404
|
||||||
b.resetDeadline = b.Clock.Now().Add(timeToWait)
|
b.resetDeadline = b.Clock.Now().Add(timeToWait)
|
||||||
|
|
||||||
return timeToWait
|
return timeToWait
|
||||||
|
@ -118,7 +118,7 @@ func (b BackoffHandler) GetBaseTime() time.Duration {
|
||||||
|
|
||||||
// Retries returns the number of retries consumed so far.
|
// Retries returns the number of retries consumed so far.
|
||||||
func (b *BackoffHandler) Retries() int {
|
func (b *BackoffHandler) Retries() int {
|
||||||
return int(b.retries)
|
return int(b.retries) // #nosec G115
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BackoffHandler) ReachedMaxRetries() bool {
|
func (b *BackoffHandler) ReachedMaxRetries() bool {
|
||||||
|
|
Loading…
Reference in New Issue