TUN-6380: Enforce connect and keep-alive timeouts for TCP connections in both WARP routing and websocket based TCP proxy.

For WARP routing the defaults for these new settings are 5 seconds for connect timeout and 30 seconds for keep-alive timeout. These values can be configured either remotely or locally. Local config lives under "warp-routing" section in config.yaml.

For websocket-based proxy, the defaults come from originConfig settings (either global or per-service) and use the same defaults as HTTP proxying.
This commit is contained in:
Igor Postelnik
2022-06-13 11:44:27 -05:00
parent 978e01f77e
commit f2339a7244
15 changed files with 144 additions and 88 deletions

View File

@@ -19,8 +19,8 @@ type newLocalConfig struct {
// Config is the original config as read and parsed by cloudflared.
type Config struct {
Ingress *ingress.Ingress
WarpRoutingEnabled bool
Ingress *ingress.Ingress
WarpRouting ingress.WarpRoutingConfig
// Extra settings used to configure this instance but that are not eligible for remotely management
// ie. (--protocol, --loglevel, ...)
@@ -37,7 +37,7 @@ func (rc *newLocalConfig) MarshalJSON() ([]byte, error) {
// UI doesn't support top level configs, so we reconcile to individual ingress configs.
GlobalOriginRequest: nil,
IngressRules: convertToUnvalidatedIngressRules(rc.RemoteConfig.Ingress),
WarpRouting: rc.RemoteConfig.WarpRouting,
WarpRouting: rc.RemoteConfig.WarpRouting.RawConfig(),
},
}

View File

@@ -3,16 +3,17 @@ package orchestration
import (
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/cloudflare/cloudflared/config"
"github.com/cloudflare/cloudflared/ingress"
)
// TestNewLocalConfig_MarshalJSON tests that we are able to converte a compiled and validated config back
// into an "unvalidated" format which is compatible with Remote Managed configurations.
func TestNewLocalConfig_MarshalJSON(t *testing.T) {
rawConfig := []byte(`
{
"originRequest": {
@@ -57,7 +58,11 @@ func TestNewLocalConfig_MarshalJSON(t *testing.T) {
]
}
}
]
],
"warp-routing": {
"enabled": true,
"connectTimeout": 1
}
}
`)
@@ -73,10 +78,18 @@ func TestNewLocalConfig_MarshalJSON(t *testing.T) {
jsonSerde, err := json.Marshal(c)
require.NoError(t, err)
var config ingress.RemoteConfig
err = json.Unmarshal(jsonSerde, &config)
var remoteConfig ingress.RemoteConfig
err = json.Unmarshal(jsonSerde, &remoteConfig)
require.NoError(t, err)
require.Equal(t, config.WarpRouting.Enabled, false)
require.Equal(t, config.Ingress.Rules, expectedConfig.Ingress.Rules)
require.Equal(t, remoteConfig.WarpRouting, ingress.WarpRoutingConfig{
Enabled: true,
ConnectTimeout: config.CustomDuration{
Duration: time.Second,
},
TCPKeepAlive: config.CustomDuration{
Duration: 30 * time.Second, // default value is 30 seconds
},
})
require.Equal(t, remoteConfig.Ingress.Rules, expectedConfig.Ingress.Rules)
}

View File

@@ -47,7 +47,7 @@ func NewOrchestrator(ctx context.Context, config *Config, tags []tunnelpogs.Tag,
log: log,
shutdownC: ctx.Done(),
}
if err := o.updateIngress(*config.Ingress, config.WarpRoutingEnabled); err != nil {
if err := o.updateIngress(*config.Ingress, config.WarpRouting); err != nil {
return nil, err
}
go o.waitToCloseLastProxy()
@@ -80,7 +80,7 @@ func (o *Orchestrator) UpdateConfig(version int32, config []byte) *tunnelpogs.Up
}
}
if err := o.updateIngress(newConf.Ingress, newConf.WarpRouting.Enabled); err != nil {
if err := o.updateIngress(newConf.Ingress, newConf.WarpRouting); err != nil {
o.log.Err(err).
Int32("version", version).
Str("config", string(config)).
@@ -103,7 +103,7 @@ func (o *Orchestrator) UpdateConfig(version int32, config []byte) *tunnelpogs.Up
}
// The caller is responsible to make sure there is no concurrent access
func (o *Orchestrator) updateIngress(ingressRules ingress.Ingress, warpRoutingEnabled bool) error {
func (o *Orchestrator) updateIngress(ingressRules ingress.Ingress, warpRouting ingress.WarpRoutingConfig) error {
select {
case <-o.shutdownC:
return fmt.Errorf("cloudflared already shutdown")
@@ -118,10 +118,10 @@ func (o *Orchestrator) updateIngress(ingressRules ingress.Ingress, warpRoutingEn
if err := ingressRules.StartOrigins(o.log, proxyShutdownC); err != nil {
return errors.Wrap(err, "failed to start origin")
}
newProxy := proxy.NewOriginProxy(ingressRules, warpRoutingEnabled, o.tags, o.log)
newProxy := proxy.NewOriginProxy(ingressRules, warpRouting, o.tags, o.log)
o.proxy.Store(newProxy)
o.config.Ingress = &ingressRules
o.config.WarpRoutingEnabled = warpRoutingEnabled
o.config.WarpRouting = warpRouting
// If proxyShutdownC is nil, there is no previous running proxy
if o.proxyShutdownC != nil {
@@ -139,7 +139,7 @@ func (o *Orchestrator) GetConfigJSON() ([]byte, error) {
c := &newLocalConfig{
RemoteConfig: ingress.RemoteConfig{
Ingress: *o.config.Ingress,
WarpRouting: config.WarpRoutingConfig{Enabled: o.config.WarpRoutingEnabled},
WarpRouting: o.config.WarpRouting,
},
ConfigurationFlags: o.config.ConfigurationFlags,
}
@@ -166,7 +166,7 @@ func (o *Orchestrator) GetVersionedConfigJSON() ([]byte, error) {
OriginRequest ingress.OriginRequestConfig `json:"originRequest"`
}{
Ingress: o.config.Ingress.Rules,
WarpRouting: config.WarpRoutingConfig{Enabled: o.config.WarpRoutingEnabled},
WarpRouting: o.config.WarpRouting.RawConfig(),
OriginRequest: o.config.Ingress.Defaults,
},
}

View File

@@ -48,8 +48,7 @@ var (
// - receiving an old version is noop
func TestUpdateConfiguration(t *testing.T) {
initConfig := &Config{
Ingress: &ingress.Ingress{},
WarpRoutingEnabled: false,
Ingress: &ingress.Ingress{},
}
orchestrator, err := NewOrchestrator(context.Background(), initConfig, testTags, &testLogger)
require.NoError(t, err)
@@ -87,7 +86,8 @@ func TestUpdateConfiguration(t *testing.T) {
}
],
"warp-routing": {
"enabled": true
"enabled": true,
"connectTimeout": 10
}
}
`)
@@ -121,7 +121,8 @@ func TestUpdateConfiguration(t *testing.T) {
require.Equal(t, config.CustomDuration{Duration: time.Second * 90}, configV2.Ingress.Rules[2].Config.ConnectTimeout)
require.Equal(t, false, configV2.Ingress.Rules[2].Config.NoTLSVerify)
require.Equal(t, true, configV2.Ingress.Rules[2].Config.NoHappyEyeballs)
require.True(t, configV2.WarpRoutingEnabled)
require.True(t, configV2.WarpRouting.Enabled)
require.Equal(t, configV2.WarpRouting.ConnectTimeout.Duration, 10*time.Second)
originProxyV2, err := orchestrator.GetOriginProxy()
require.NoError(t, err)
@@ -164,7 +165,7 @@ func TestUpdateConfiguration(t *testing.T) {
require.Len(t, configV10.Ingress.Rules, 1)
require.True(t, configV10.Ingress.Rules[0].Matches("blogs.tunnel.io", "/2022/02/10"))
require.Equal(t, ingress.HelloWorldService, configV10.Ingress.Rules[0].Service.String())
require.False(t, configV10.WarpRoutingEnabled)
require.False(t, configV10.WarpRouting.Enabled)
originProxyV10, err := orchestrator.GetOriginProxy()
require.NoError(t, err)
@@ -246,8 +247,7 @@ func TestConcurrentUpdateAndRead(t *testing.T) {
appliedV2 = make(chan struct{})
initConfig = &Config{
Ingress: &ingress.Ingress{},
WarpRoutingEnabled: false,
Ingress: &ingress.Ingress{},
}
)
@@ -476,8 +476,7 @@ func TestClosePreviousProxies(t *testing.T) {
}
`)
initConfig = &Config{
Ingress: &ingress.Ingress{},
WarpRoutingEnabled: false,
Ingress: &ingress.Ingress{},
}
)
@@ -534,8 +533,7 @@ func TestPersistentConnection(t *testing.T) {
)
msg := t.Name()
initConfig := &Config{
Ingress: &ingress.Ingress{},
WarpRoutingEnabled: false,
Ingress: &ingress.Ingress{},
}
orchestrator, err := NewOrchestrator(context.Background(), initConfig, testTags, &testLogger)
require.NoError(t, err)
@@ -645,8 +643,7 @@ func TestPersistentConnection(t *testing.T) {
func TestSerializeLocalConfig(t *testing.T) {
c := &newLocalConfig{
RemoteConfig: ingress.RemoteConfig{
Ingress: ingress.Ingress{},
WarpRouting: config.WarpRoutingConfig{},
Ingress: ingress.Ingress{},
},
ConfigurationFlags: map[string]string{"a": "b"},
}