Compare commits

...

4 Commits

Author SHA1 Message Date
Sudarsan Reddy 43f1c6ba82 Release 2021.11.0 2021-11-04 14:15:42 +00:00
Sudarsan Reddy 0146a8d8ed TUN-5285: Fallback to HTTP2 immediately if connection times out with no network activity 2021-11-04 10:42:53 +00:00
Silver 36479ef11f Merge pull request #478 from echtish/secret-flag
Add flag to 'tunnel create' subcommand to specify a base64-encoded secret
2021-11-02 16:21:01 -05:00
Jeremy Teale 1239006e96 Add flag to 'tunnel create' subcommand to specify a base64-encoded secret 2021-09-29 18:56:38 -05:00
7 changed files with 54 additions and 16 deletions
+4
View File
@@ -1,3 +1,7 @@
2021.11.0
- 2021-11-03 TUN-5285: Fallback to HTTP2 immediately if connection times out with no network activity
- 2021-09-29 Add flag to 'tunnel create' subcommand to specify a base64-encoded secret
2021.10.5
- 2021-10-25 Update change log for release 2021.10.4
- 2021-10-25 Revert "TUN-5184: Make sure outstanding websocket write is finished, and no more writes after shutdown"
+2 -1
View File
@@ -181,7 +181,8 @@ func Init(ver string, gracefulShutdown chan struct{}) {
func runAdhocNamedTunnel(sc *subcommandContext, name, credentialsOutputPath string) error {
tunnel, ok, err := sc.tunnelActive(name)
if err != nil || !ok {
tunnel, err = sc.create(name, credentialsOutputPath)
// pass empty string as secret to generate one
tunnel, err = sc.create(name, credentialsOutputPath, "")
if err != nil {
return errors.Wrap(err, "failed to create tunnel")
}
+17 -4
View File
@@ -1,6 +1,7 @@
package tunnel
import (
"encoding/base64"
"encoding/json"
"fmt"
"os"
@@ -148,15 +149,27 @@ func (sc *subcommandContext) readTunnelCredentials(credFinder CredFinder) (conne
return credentials, nil
}
func (sc *subcommandContext) create(name string, credentialsFilePath string) (*tunnelstore.Tunnel, error) {
func (sc *subcommandContext) create(name string, credentialsFilePath string, secret string) (*tunnelstore.Tunnel, error) {
client, err := sc.client()
if err != nil {
return nil, errors.Wrap(err, "couldn't create client to talk to Cloudflare Tunnel backend")
}
tunnelSecret, err := generateTunnelSecret()
if err != nil {
return nil, errors.Wrap(err, "couldn't generate the secret for your new tunnel")
var tunnelSecret []byte
if secret == "" {
tunnelSecret, err = generateTunnelSecret()
if err != nil {
return nil, errors.Wrap(err, "couldn't generate the secret for your new tunnel")
}
} else {
decodedSecret, err := base64.StdEncoding.DecodeString(secret)
if err != nil {
return nil, errors.Wrap(err, "Couldn't decode tunnel secret from base64")
}
tunnelSecret = []byte(decodedSecret)
if len(tunnelSecret) < 32 {
return nil, errors.New("Decoded tunnel secret must be at least 32 bytes long")
}
}
tunnel, err := client.CreateTunnel(name, tunnelSecret)
+8 -2
View File
@@ -156,6 +156,12 @@ var (
Usage: `Overwrites existing DNS records with this hostname`,
EnvVars: []string{"TUNNEL_FORCE_PROVISIONING_DNS"},
}
createSecretFlag = &cli.StringFlag{
Name: "secret",
Aliases: []string{"s"},
Usage: "Base64 encoded secret to set for the tunnel. The decoded secret must be at least 32 bytes long. If not specified, a random 32-byte secret will be generated.",
EnvVars: []string{"TUNNEL_CREATE_SECRET"},
}
)
func buildCreateCommand() *cli.Command {
@@ -170,7 +176,7 @@ func buildCreateCommand() *cli.Command {
For example, to create a tunnel named 'my-tunnel' run:
$ cloudflared tunnel create my-tunnel`,
Flags: []cli.Flag{outputFormatFlag, credentialsFileFlagCLIOnly},
Flags: []cli.Flag{outputFormatFlag, credentialsFileFlagCLIOnly, createSecretFlag},
CustomHelpTemplate: commandHelpTemplate(),
}
}
@@ -196,7 +202,7 @@ func createCommand(c *cli.Context) error {
warningChecker := updater.StartWarningCheck(c)
defer warningChecker.LogWarningIfAny(sc.log)
_, err = sc.create(name, c.String(CredFileFlag))
_, err = sc.create(name, c.String(CredFileFlag), c.String(createSecretFlag.Name))
return errors.Wrap(err, "failed to create tunnel")
}
+3 -3
View File
@@ -49,12 +49,12 @@ func NewQUICConnection(
) (*QUICConnection, error) {
session, err := quic.DialAddr(edgeAddr.String(), tlsConfig, quicConfig)
if err != nil {
return nil, errors.Wrap(err, "failed to dial to edge")
return nil, fmt.Errorf("failed to dial to edge: %w", err)
}
registrationStream, err := session.OpenStream()
if err != nil {
return nil, errors.Wrap(err, "failed to open a registration stream")
return nil, fmt.Errorf("failed to open a registration stream: %w", err)
}
err = controlStreamHandler.ServeControlStream(ctx, registrationStream, connOptions, false)
@@ -82,7 +82,7 @@ func (q *QUICConnection) Serve(ctx context.Context) error {
if errors.Is(err, context.Canceled) {
return nil
}
return errors.Wrap(err, "failed to accept QUIC stream")
return fmt.Errorf("failed to accept QUIC stream: %w", err)
}
go func() {
defer stream.Close()
+9 -2
View File
@@ -190,7 +190,13 @@ func ServeTunnelLoop(
case <-gracefulShutdownC:
return nil
case <-protocolFallback.BackoffTimer():
if !selectNextProtocol(&connLog, protocolFallback, config.ProtocolSelector) {
var idleTimeoutError *quic.IdleTimeoutError
if !selectNextProtocol(
&connLog,
protocolFallback,
config.ProtocolSelector,
errors.As(err, &idleTimeoutError),
) {
return err
}
}
@@ -222,8 +228,9 @@ func selectNextProtocol(
connLog *zerolog.Logger,
protocolBackoff *protocolFallback,
selector connection.ProtocolSelector,
isNetworkActivityTimeout bool,
) bool {
if protocolBackoff.ReachedMaxRetries() {
if protocolBackoff.ReachedMaxRetries() || isNetworkActivityTimeout {
fallback, hasFallback := selector.Fallback()
if !hasFallback {
return false
+11 -4
View File
@@ -62,7 +62,7 @@ func TestWaitForBackoffFallback(t *testing.T) {
// Retry #0 and #1. At retry #2, we switch protocol, so the fallback loop has one more retry than this
for i := 0; i < int(maxRetries-1); i++ {
protocolFallback.BackoffTimer() // simulate retry
ok := selectNextProtocol(&log, protocolFallback, protocolSelector)
ok := selectNextProtocol(&log, protocolFallback, protocolSelector, false)
assert.True(t, ok)
assert.Equal(t, initProtocol, protocolFallback.protocol)
}
@@ -70,7 +70,7 @@ func TestWaitForBackoffFallback(t *testing.T) {
// Retry fallback protocol
for i := 0; i < int(maxRetries); i++ {
protocolFallback.BackoffTimer() // simulate retry
ok := selectNextProtocol(&log, protocolFallback, protocolSelector)
ok := selectNextProtocol(&log, protocolFallback, protocolSelector, false)
assert.True(t, ok)
fallback, ok := protocolSelector.Fallback()
assert.True(t, ok)
@@ -82,12 +82,19 @@ func TestWaitForBackoffFallback(t *testing.T) {
// No protocol to fallback, return error
protocolFallback.BackoffTimer() // simulate retry
ok := selectNextProtocol(&log, protocolFallback, protocolSelector)
ok := selectNextProtocol(&log, protocolFallback, protocolSelector, false)
assert.False(t, ok)
protocolFallback.reset()
protocolFallback.BackoffTimer() // simulate retry
ok = selectNextProtocol(&log, protocolFallback, protocolSelector)
ok = selectNextProtocol(&log, protocolFallback, protocolSelector, false)
assert.True(t, ok)
assert.Equal(t, initProtocol, protocolFallback.protocol)
protocolFallback.reset()
protocolFallback.BackoffTimer() // simulate retry
ok = selectNextProtocol(&log, protocolFallback, protocolSelector, true)
// Check that we get a true after the first try itself when this flag is true. This allows us to immediately
// switch protocols.
assert.True(t, ok)
}