From 7d4afd4ae02dcc6f8f190258d2beed0a2d361886 Mon Sep 17 00:00:00 2001 From: Niklas Rehfeld Date: Wed, 1 Jun 2022 12:51:59 +1200 Subject: [PATCH 1/3] Add Http2Origin option to force HTTP/2 origin connections If `http2Origin` is set, it will set `ForceAttemptHTTP2` in the transport config of the `OriginService`. --- cmd/cloudflared/tunnel/cmd.go | 7 +++++++ config/configuration.go | 2 ++ config/configuration_test.go | 4 +++- ingress/config.go | 9 +++++++++ ingress/origin_service.go | 1 + 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cmd/cloudflared/tunnel/cmd.go b/cmd/cloudflared/tunnel/cmd.go index e9038403..0cae34a2 100644 --- a/cmd/cloudflared/tunnel/cmd.go +++ b/cmd/cloudflared/tunnel/cmd.go @@ -821,6 +821,13 @@ func configureProxyFlags(shouldHide bool) []cli.Flag { EnvVars: []string{"TUNNEL_NO_CHUNKED_ENCODING"}, Hidden: shouldHide, }), + altsrc.NewBoolFlag(&cli.BoolFlag{ + Name: ingress.Http2OriginFlag, + Usage: "Enables HTTP/2 origin servers.", + EnvVars: []string{"TUNNEL_ORIGIN_ENABLE_HTTP2"}, + Hidden: shouldHide, + Value: false, + }), } return append(flags, sshFlags(shouldHide)...) } diff --git a/config/configuration.go b/config/configuration.go index 49395404..82491477 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -227,6 +227,8 @@ type OriginRequestConfig struct { ProxyType *string `yaml:"proxyType" json:"proxyType,omitempty"` // IP rules for the proxy service IPRules []IngressIPRule `yaml:"ipRules" json:"ipRules,omitempty"` + // Attempt to connect to origin with HTTP/2 + Http2Origin *bool `yaml:"http2Origin" json:"http2Origin,omitempty"` } type IngressIPRule struct { diff --git a/config/configuration_test.go b/config/configuration_test.go index d870913d..2822b80b 100644 --- a/config/configuration_test.go +++ b/config/configuration_test.go @@ -139,7 +139,8 @@ var rawConfig = []byte(` "ports": [443, 4443], "allow": true } - ] + ], + "http2Origin": true } `) @@ -188,6 +189,7 @@ func assertConfig( assert.Equal(t, true, *config.NoTLSVerify) assert.Equal(t, uint(9000), *config.ProxyPort) assert.Equal(t, "socks", *config.ProxyType) + assert.Equal(t, true, *config.Http2Origin) privateV4 := "10.0.0.0/8" privateV6 := "fc00::/7" diff --git a/ingress/config.go b/ingress/config.go index bc2a9f6b..0d692fe9 100644 --- a/ingress/config.go +++ b/ingress/config.go @@ -35,6 +35,7 @@ const ( NoChunkedEncodingFlag = "no-chunked-encoding" ProxyAddressFlag = "proxy-address" ProxyPortFlag = "proxy-port" + Http2OriginFlag = "http2-origin" ) const ( @@ -93,6 +94,7 @@ func originRequestFromSingeRule(c *cli.Context) OriginRequestConfig { var proxyAddress = defaultProxyAddress var proxyPort uint var proxyType string + var http2Origin bool if flag := ProxyConnectTimeoutFlag; c.IsSet(flag) { connectTimeout = config.CustomDuration{Duration: c.Duration(flag)} } @@ -136,9 +138,13 @@ func originRequestFromSingeRule(c *cli.Context) OriginRequestConfig { // Note TUN-3758 , we use Int because UInt is not supported with altsrc proxyPort = uint(c.Int(flag)) } + if flag := Http2OriginFlag; c.IsSet(flag) { + http2Origin = c.Bool(flag) + } if c.IsSet(Socks5Flag) { proxyType = socksProxy } + return OriginRequestConfig{ ConnectTimeout: connectTimeout, TLSTimeout: tlsTimeout, @@ -155,6 +161,7 @@ func originRequestFromSingeRule(c *cli.Context) OriginRequestConfig { ProxyAddress: proxyAddress, ProxyPort: proxyPort, ProxyType: proxyType, + Http2Origin: http2Origin, } } @@ -263,6 +270,8 @@ type OriginRequestConfig struct { ProxyType string `yaml:"proxyType" json:"proxyType"` // IP rules for the proxy service IPRules []ipaccess.Rule `yaml:"ipRules" json:"ipRules"` + // Attempt to connect to origin with HTTP/2 + Http2Origin bool `yaml:"http2Origin" json:"http2Origin"` } func (defaults *OriginRequestConfig) setConnectTimeout(overrides config.OriginRequestConfig) { diff --git a/ingress/origin_service.go b/ingress/origin_service.go index c96e4608..8877fdc7 100644 --- a/ingress/origin_service.go +++ b/ingress/origin_service.go @@ -291,6 +291,7 @@ func newHTTPTransport(service OriginService, cfg OriginRequestConfig, log *zerol TLSHandshakeTimeout: cfg.TLSTimeout.Duration, ExpectContinueTimeout: 1 * time.Second, TLSClientConfig: &tls.Config{RootCAs: originCertPool, InsecureSkipVerify: cfg.NoTLSVerify}, + ForceAttemptHTTP2: cfg.Http2Origin, } if _, isHelloWorld := service.(*helloWorld); !isHelloWorld && cfg.OriginServerName != "" { httpTransport.TLSClientConfig.ServerName = cfg.OriginServerName From 2345720b2b5a51a0e36fd519783708aa7900c429 Mon Sep 17 00:00:00 2001 From: Niklas Rehfeld Date: Thu, 2 Jun 2022 09:49:06 +1200 Subject: [PATCH 2/3] fix ingress rules unit test --- ingress/rule_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ingress/rule_test.go b/ingress/rule_test.go index 7561709a..279d7911 100644 --- a/ingress/rule_test.go +++ b/ingress/rule_test.go @@ -182,25 +182,25 @@ func TestMarshalJSON(t *testing.T) { { name: "Nil", path: nil, - expected: `{"hostname":"example.com","path":null,"service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null}}`, + expected: `{"hostname":"example.com","path":null,"service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null,"http2Origin":false}}`, want: true, }, { name: "Nil regex", path: &Regexp{Regexp: nil}, - expected: `{"hostname":"example.com","path":null,"service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null}}`, + expected: `{"hostname":"example.com","path":null,"service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null,"http2Origin":false}}`, want: true, }, { name: "Empty", path: &Regexp{Regexp: regexp.MustCompile("")}, - expected: `{"hostname":"example.com","path":"","service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null}}`, + expected: `{"hostname":"example.com","path":"","service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null,"http2Origin":false}}`, want: true, }, { name: "Basic", path: &Regexp{Regexp: regexp.MustCompile("/echo")}, - expected: `{"hostname":"example.com","path":"/echo","service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null}}`, + expected: `{"hostname":"example.com","path":"/echo","service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null,"http2Origin":false}}`, want: true, }, } From 5ed3d4e29a7f04c8b7abc3dcff45a55b90aefa2f Mon Sep 17 00:00:00 2001 From: Niklas Rehfeld Date: Thu, 9 Jun 2022 16:44:40 +1200 Subject: [PATCH 3/3] Update remaining OriginRequestConfig functions for Http2Origins --- ingress/config.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ingress/config.go b/ingress/config.go index 0d692fe9..8b0804b1 100644 --- a/ingress/config.go +++ b/ingress/config.go @@ -227,6 +227,9 @@ func originRequestFromConfig(c config.OriginRequestConfig) OriginRequestConfig { } } } + if c.Http2Origin != nil { + out.Http2Origin = *c.Http2Origin + } return out } @@ -377,6 +380,12 @@ func (defaults *OriginRequestConfig) setIPRules(overrides config.OriginRequestCo } } +func (defaults *OriginRequestConfig) setHttp2Origin(overrides config.OriginRequestConfig) { + if val := overrides.Http2Origin; val != nil { + defaults.Http2Origin = *val + } +} + // SetConfig gets config for the requests that cloudflared sends to origins. // Each field has a setter method which sets a value for the field by trying to find: // 1. The user config for this rule @@ -402,6 +411,7 @@ func setConfig(defaults OriginRequestConfig, overrides config.OriginRequestConfi cfg.setProxyAddress(overrides) cfg.setProxyType(overrides) cfg.setIPRules(overrides) + cfg.setHttp2Origin(overrides) return cfg } @@ -449,6 +459,7 @@ func ConvertToRawOriginConfig(c OriginRequestConfig) config.OriginRequestConfig ProxyPort: zeroUIntToNil(c.ProxyPort), ProxyType: emptyStringToNil(c.ProxyType), IPRules: convertToRawIPRules(c.IPRules), + Http2Origin: defaultBoolToNil(c.Http2Origin), } }