TUN-5702: Allow to deserialize config from JSON
This commit is contained in:
parent
d07d24e5a2
commit
b1edf5b96d
|
@ -175,60 +175,62 @@ func ValidateUrl(c *cli.Context, allowURLFromArgs bool) (*url.URL, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type UnvalidatedIngressRule struct {
|
type UnvalidatedIngressRule struct {
|
||||||
Hostname string
|
Hostname string `json:"hostname"`
|
||||||
Path string
|
Path string `json:"path"`
|
||||||
Service string
|
Service string `json:"service"`
|
||||||
OriginRequest OriginRequestConfig `yaml:"originRequest"`
|
OriginRequest OriginRequestConfig `yaml:"originRequest" json:"originRequest"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// OriginRequestConfig is a set of optional fields that users may set to
|
// OriginRequestConfig is a set of optional fields that users may set to
|
||||||
// customize how cloudflared sends requests to origin services. It is used to set
|
// customize how cloudflared sends requests to origin services. It is used to set
|
||||||
// up general config that apply to all rules, and also, specific per-rule
|
// up general config that apply to all rules, and also, specific per-rule
|
||||||
// config.
|
// config.
|
||||||
// Note: To specify a time.Duration in go-yaml, use e.g. "3s" or "24h".
|
// Note:
|
||||||
|
// - To specify a time.Duration in go-yaml, use e.g. "3s" or "24h".
|
||||||
|
// - To specify a time.Duration in json, use int64 of the nanoseconds
|
||||||
type OriginRequestConfig struct {
|
type OriginRequestConfig struct {
|
||||||
// HTTP proxy timeout for establishing a new connection
|
// HTTP proxy timeout for establishing a new connection
|
||||||
ConnectTimeout *time.Duration `yaml:"connectTimeout"`
|
ConnectTimeout *time.Duration `yaml:"connectTimeout" json:"connectTimeout"`
|
||||||
// HTTP proxy timeout for completing a TLS handshake
|
// HTTP proxy timeout for completing a TLS handshake
|
||||||
TLSTimeout *time.Duration `yaml:"tlsTimeout"`
|
TLSTimeout *time.Duration `yaml:"tlsTimeout" json:"tlsTimeout"`
|
||||||
// HTTP proxy TCP keepalive duration
|
// HTTP proxy TCP keepalive duration
|
||||||
TCPKeepAlive *time.Duration `yaml:"tcpKeepAlive"`
|
TCPKeepAlive *time.Duration `yaml:"tcpKeepAlive" json:"tcpKeepAlive"`
|
||||||
// HTTP proxy should disable "happy eyeballs" for IPv4/v6 fallback
|
// HTTP proxy should disable "happy eyeballs" for IPv4/v6 fallback
|
||||||
NoHappyEyeballs *bool `yaml:"noHappyEyeballs"`
|
NoHappyEyeballs *bool `yaml:"noHappyEyeballs" json:"noHappyEyeballs"`
|
||||||
// HTTP proxy maximum keepalive connection pool size
|
// HTTP proxy maximum keepalive connection pool size
|
||||||
KeepAliveConnections *int `yaml:"keepAliveConnections"`
|
KeepAliveConnections *int `yaml:"keepAliveConnections" json:"keepAliveConnections"`
|
||||||
// HTTP proxy timeout for closing an idle connection
|
// HTTP proxy timeout for closing an idle connection
|
||||||
KeepAliveTimeout *time.Duration `yaml:"keepAliveTimeout"`
|
KeepAliveTimeout *time.Duration `yaml:"keepAliveTimeout" json:"keepAliveTimeout"`
|
||||||
// Sets the HTTP Host header for the local webserver.
|
// Sets the HTTP Host header for the local webserver.
|
||||||
HTTPHostHeader *string `yaml:"httpHostHeader"`
|
HTTPHostHeader *string `yaml:"httpHostHeader" json:"httpHostHeader"`
|
||||||
// Hostname on the origin server certificate.
|
// Hostname on the origin server certificate.
|
||||||
OriginServerName *string `yaml:"originServerName"`
|
OriginServerName *string `yaml:"originServerName" json:"originServerName"`
|
||||||
// Path to the CA for the certificate of your origin.
|
// Path to the CA for the certificate of your origin.
|
||||||
// This option should be used only if your certificate is not signed by Cloudflare.
|
// This option should be used only if your certificate is not signed by Cloudflare.
|
||||||
CAPool *string `yaml:"caPool"`
|
CAPool *string `yaml:"caPool" json:"caPool"`
|
||||||
// Disables TLS verification of the certificate presented by your origin.
|
// Disables TLS verification of the certificate presented by your origin.
|
||||||
// Will allow any certificate from the origin to be accepted.
|
// Will allow any certificate from the origin to be accepted.
|
||||||
// Note: The connection from your machine to Cloudflare's Edge is still encrypted.
|
// Note: The connection from your machine to Cloudflare's Edge is still encrypted.
|
||||||
NoTLSVerify *bool `yaml:"noTLSVerify"`
|
NoTLSVerify *bool `yaml:"noTLSVerify" json:"noTLSVerify"`
|
||||||
// Disables chunked transfer encoding.
|
// Disables chunked transfer encoding.
|
||||||
// Useful if you are running a WSGI server.
|
// Useful if you are running a WSGI server.
|
||||||
DisableChunkedEncoding *bool `yaml:"disableChunkedEncoding"`
|
DisableChunkedEncoding *bool `yaml:"disableChunkedEncoding" json:"disableChunkedEncoding"`
|
||||||
// Runs as jump host
|
// Runs as jump host
|
||||||
BastionMode *bool `yaml:"bastionMode"`
|
BastionMode *bool `yaml:"bastionMode" json:"bastionMode"`
|
||||||
// Listen address for the proxy.
|
// Listen address for the proxy.
|
||||||
ProxyAddress *string `yaml:"proxyAddress"`
|
ProxyAddress *string `yaml:"proxyAddress" json:"proxyAddress"`
|
||||||
// Listen port for the proxy.
|
// Listen port for the proxy.
|
||||||
ProxyPort *uint `yaml:"proxyPort"`
|
ProxyPort *uint `yaml:"proxyPort" json:"proxyPort"`
|
||||||
// Valid options are 'socks' or empty.
|
// Valid options are 'socks' or empty.
|
||||||
ProxyType *string `yaml:"proxyType"`
|
ProxyType *string `yaml:"proxyType" json:"proxyType"`
|
||||||
// IP rules for the proxy service
|
// IP rules for the proxy service
|
||||||
IPRules []IngressIPRule `yaml:"ipRules"`
|
IPRules []IngressIPRule `yaml:"ipRules" json:"ipRules"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IngressIPRule struct {
|
type IngressIPRule struct {
|
||||||
Prefix *string `yaml:"prefix"`
|
Prefix *string `yaml:"prefix" json:"prefix"`
|
||||||
Ports []int `yaml:"ports"`
|
Ports []int `yaml:"ports" json:"ports"`
|
||||||
Allow bool `yaml:"allow"`
|
Allow bool `yaml:"allow" json:"allow"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
|
@ -240,7 +242,7 @@ type Configuration struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type WarpRoutingConfig struct {
|
type WarpRoutingConfig struct {
|
||||||
Enabled bool `yaml:"enabled"`
|
Enabled bool `yaml:"enabled" json:"enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type configFileSettings struct {
|
type configFileSettings struct {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -26,6 +27,18 @@ func TestConfigFileSettings(t *testing.T) {
|
||||||
)
|
)
|
||||||
rawYAML := `
|
rawYAML := `
|
||||||
tunnel: config-file-test
|
tunnel: config-file-test
|
||||||
|
originRequest:
|
||||||
|
ipRules:
|
||||||
|
- prefix: "10.0.0.0/8"
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
- 8080
|
||||||
|
allow: false
|
||||||
|
- prefix: "fc00::/7"
|
||||||
|
ports:
|
||||||
|
- 443
|
||||||
|
- 4443
|
||||||
|
allow: true
|
||||||
ingress:
|
ingress:
|
||||||
- hostname: tunnel1.example.com
|
- hostname: tunnel1.example.com
|
||||||
path: /id
|
path: /id
|
||||||
|
@ -53,6 +66,21 @@ counters:
|
||||||
assert.Equal(t, firstIngress, config.Ingress[0])
|
assert.Equal(t, firstIngress, config.Ingress[0])
|
||||||
assert.Equal(t, secondIngress, config.Ingress[1])
|
assert.Equal(t, secondIngress, config.Ingress[1])
|
||||||
assert.Equal(t, warpRouting, config.WarpRouting)
|
assert.Equal(t, warpRouting, config.WarpRouting)
|
||||||
|
privateV4 := "10.0.0.0/8"
|
||||||
|
privateV6 := "fc00::/7"
|
||||||
|
ipRules := []IngressIPRule{
|
||||||
|
{
|
||||||
|
Prefix: &privateV4,
|
||||||
|
Ports: []int{80, 8080},
|
||||||
|
Allow: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Prefix: &privateV6,
|
||||||
|
Ports: []int{443, 4443},
|
||||||
|
Allow: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, ipRules, config.OriginRequest.IPRules)
|
||||||
|
|
||||||
retries, err := config.Int("retries")
|
retries, err := config.Int("retries")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -81,3 +109,71 @@ counters:
|
||||||
assert.Equal(t, 456, counters[1])
|
assert.Equal(t, 456, counters[1])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalOriginRequestConfig(t *testing.T) {
|
||||||
|
raw := []byte(`
|
||||||
|
{
|
||||||
|
"connectTimeout": 10000000000,
|
||||||
|
"tlsTimeout": 30000000000,
|
||||||
|
"tcpKeepAlive": 30000000000,
|
||||||
|
"noHappyEyeballs": true,
|
||||||
|
"keepAliveTimeout": 60000000000,
|
||||||
|
"keepAliveConnections": 10,
|
||||||
|
"httpHostHeader": "app.tunnel.com",
|
||||||
|
"originServerName": "app.tunnel.com",
|
||||||
|
"caPool": "/etc/capool",
|
||||||
|
"noTLSVerify": true,
|
||||||
|
"disableChunkedEncoding": true,
|
||||||
|
"bastionMode": true,
|
||||||
|
"proxyAddress": "127.0.0.3",
|
||||||
|
"proxyPort": 9000,
|
||||||
|
"proxyType": "socks",
|
||||||
|
"ipRules": [
|
||||||
|
{
|
||||||
|
"prefix": "10.0.0.0/8",
|
||||||
|
"ports": [80, 8080],
|
||||||
|
"allow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"prefix": "fc00::/7",
|
||||||
|
"ports": [443, 4443],
|
||||||
|
"allow": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
var config OriginRequestConfig
|
||||||
|
assert.NoError(t, json.Unmarshal(raw, &config))
|
||||||
|
assert.Equal(t, time.Second*10, *config.ConnectTimeout)
|
||||||
|
assert.Equal(t, time.Second*30, *config.TLSTimeout)
|
||||||
|
assert.Equal(t, time.Second*30, *config.TCPKeepAlive)
|
||||||
|
assert.Equal(t, true, *config.NoHappyEyeballs)
|
||||||
|
assert.Equal(t, time.Second*60, *config.KeepAliveTimeout)
|
||||||
|
assert.Equal(t, 10, *config.KeepAliveConnections)
|
||||||
|
assert.Equal(t, "app.tunnel.com", *config.HTTPHostHeader)
|
||||||
|
assert.Equal(t, "app.tunnel.com", *config.OriginServerName)
|
||||||
|
assert.Equal(t, "/etc/capool", *config.CAPool)
|
||||||
|
assert.Equal(t, true, *config.NoTLSVerify)
|
||||||
|
assert.Equal(t, true, *config.DisableChunkedEncoding)
|
||||||
|
assert.Equal(t, true, *config.BastionMode)
|
||||||
|
assert.Equal(t, "127.0.0.3", *config.ProxyAddress)
|
||||||
|
assert.Equal(t, true, *config.NoTLSVerify)
|
||||||
|
assert.Equal(t, uint(9000), *config.ProxyPort)
|
||||||
|
assert.Equal(t, "socks", *config.ProxyType)
|
||||||
|
|
||||||
|
privateV4 := "10.0.0.0/8"
|
||||||
|
privateV6 := "fc00::/7"
|
||||||
|
ipRules := []IngressIPRule{
|
||||||
|
{
|
||||||
|
Prefix: &privateV4,
|
||||||
|
Ports: []int{80, 8080},
|
||||||
|
Allow: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Prefix: &privateV6,
|
||||||
|
Ports: []int{443, 4443},
|
||||||
|
Allow: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, ipRules, config.IPRules)
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ingress
|
package ingress
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
@ -38,6 +39,34 @@ const (
|
||||||
socksProxy = "socks"
|
socksProxy = "socks"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RemoteConfig models ingress settings that can be managed remotely, for example through the dashboard.
|
||||||
|
type RemoteConfig struct {
|
||||||
|
Ingress Ingress
|
||||||
|
WarpRouting config.WarpRoutingConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type remoteConfigJSON struct {
|
||||||
|
GlobalOriginRequest config.OriginRequestConfig `json:"originRequest"`
|
||||||
|
IngressRules []config.UnvalidatedIngressRule `json:"ingress"`
|
||||||
|
WarpRouting config.WarpRoutingConfig `json:"warp-routing"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *RemoteConfig) UnmarshalJSON(b []byte) error {
|
||||||
|
var rawConfig remoteConfigJSON
|
||||||
|
if err := json.Unmarshal(b, &rawConfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ingress, err := validateIngress(rawConfig.IngressRules, originRequestFromConfig(rawConfig.GlobalOriginRequest))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.Ingress = ingress
|
||||||
|
rc.WarpRouting = rawConfig.WarpRouting
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func originRequestFromSingeRule(c *cli.Context) OriginRequestConfig {
|
func originRequestFromSingeRule(c *cli.Context) OriginRequestConfig {
|
||||||
var connectTimeout time.Duration = defaultConnectTimeout
|
var connectTimeout time.Duration = defaultConnectTimeout
|
||||||
var tlsTimeout time.Duration = defaultTLSTimeout
|
var tlsTimeout time.Duration = defaultTLSTimeout
|
||||||
|
@ -119,7 +148,7 @@ func originRequestFromSingeRule(c *cli.Context) OriginRequestConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func originRequestFromYAML(y config.OriginRequestConfig) OriginRequestConfig {
|
func originRequestFromConfig(c config.OriginRequestConfig) OriginRequestConfig {
|
||||||
out := OriginRequestConfig{
|
out := OriginRequestConfig{
|
||||||
ConnectTimeout: defaultConnectTimeout,
|
ConnectTimeout: defaultConnectTimeout,
|
||||||
TLSTimeout: defaultTLSTimeout,
|
TLSTimeout: defaultTLSTimeout,
|
||||||
|
@ -128,50 +157,58 @@ func originRequestFromYAML(y config.OriginRequestConfig) OriginRequestConfig {
|
||||||
KeepAliveTimeout: defaultKeepAliveTimeout,
|
KeepAliveTimeout: defaultKeepAliveTimeout,
|
||||||
ProxyAddress: defaultProxyAddress,
|
ProxyAddress: defaultProxyAddress,
|
||||||
}
|
}
|
||||||
if y.ConnectTimeout != nil {
|
if c.ConnectTimeout != nil {
|
||||||
out.ConnectTimeout = *y.ConnectTimeout
|
out.ConnectTimeout = *c.ConnectTimeout
|
||||||
}
|
}
|
||||||
if y.TLSTimeout != nil {
|
if c.TLSTimeout != nil {
|
||||||
out.TLSTimeout = *y.TLSTimeout
|
out.TLSTimeout = *c.TLSTimeout
|
||||||
}
|
}
|
||||||
if y.TCPKeepAlive != nil {
|
if c.TCPKeepAlive != nil {
|
||||||
out.TCPKeepAlive = *y.TCPKeepAlive
|
out.TCPKeepAlive = *c.TCPKeepAlive
|
||||||
}
|
}
|
||||||
if y.NoHappyEyeballs != nil {
|
if c.NoHappyEyeballs != nil {
|
||||||
out.NoHappyEyeballs = *y.NoHappyEyeballs
|
out.NoHappyEyeballs = *c.NoHappyEyeballs
|
||||||
}
|
}
|
||||||
if y.KeepAliveConnections != nil {
|
if c.KeepAliveConnections != nil {
|
||||||
out.KeepAliveConnections = *y.KeepAliveConnections
|
out.KeepAliveConnections = *c.KeepAliveConnections
|
||||||
}
|
}
|
||||||
if y.KeepAliveTimeout != nil {
|
if c.KeepAliveTimeout != nil {
|
||||||
out.KeepAliveTimeout = *y.KeepAliveTimeout
|
out.KeepAliveTimeout = *c.KeepAliveTimeout
|
||||||
}
|
}
|
||||||
if y.HTTPHostHeader != nil {
|
if c.HTTPHostHeader != nil {
|
||||||
out.HTTPHostHeader = *y.HTTPHostHeader
|
out.HTTPHostHeader = *c.HTTPHostHeader
|
||||||
}
|
}
|
||||||
if y.OriginServerName != nil {
|
if c.OriginServerName != nil {
|
||||||
out.OriginServerName = *y.OriginServerName
|
out.OriginServerName = *c.OriginServerName
|
||||||
}
|
}
|
||||||
if y.CAPool != nil {
|
if c.CAPool != nil {
|
||||||
out.CAPool = *y.CAPool
|
out.CAPool = *c.CAPool
|
||||||
}
|
}
|
||||||
if y.NoTLSVerify != nil {
|
if c.NoTLSVerify != nil {
|
||||||
out.NoTLSVerify = *y.NoTLSVerify
|
out.NoTLSVerify = *c.NoTLSVerify
|
||||||
}
|
}
|
||||||
if y.DisableChunkedEncoding != nil {
|
if c.DisableChunkedEncoding != nil {
|
||||||
out.DisableChunkedEncoding = *y.DisableChunkedEncoding
|
out.DisableChunkedEncoding = *c.DisableChunkedEncoding
|
||||||
}
|
}
|
||||||
if y.BastionMode != nil {
|
if c.BastionMode != nil {
|
||||||
out.BastionMode = *y.BastionMode
|
out.BastionMode = *c.BastionMode
|
||||||
}
|
}
|
||||||
if y.ProxyAddress != nil {
|
if c.ProxyAddress != nil {
|
||||||
out.ProxyAddress = *y.ProxyAddress
|
out.ProxyAddress = *c.ProxyAddress
|
||||||
|
}
|
||||||
|
if c.ProxyPort != nil {
|
||||||
|
out.ProxyPort = *c.ProxyPort
|
||||||
|
}
|
||||||
|
if c.ProxyType != nil {
|
||||||
|
out.ProxyType = *c.ProxyType
|
||||||
|
}
|
||||||
|
if len(c.IPRules) > 0 {
|
||||||
|
for _, r := range c.IPRules {
|
||||||
|
rule, err := ipaccess.NewRuleByCIDR(r.Prefix, r.Ports, r.Allow)
|
||||||
|
if err == nil {
|
||||||
|
out.IPRules = append(out.IPRules, rule)
|
||||||
}
|
}
|
||||||
if y.ProxyPort != nil {
|
|
||||||
out.ProxyPort = *y.ProxyPort
|
|
||||||
}
|
}
|
||||||
if y.ProxyType != nil {
|
|
||||||
out.ProxyType = *y.ProxyType
|
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -188,10 +225,10 @@ type OriginRequestConfig struct {
|
||||||
TCPKeepAlive time.Duration `yaml:"tcpKeepAlive"`
|
TCPKeepAlive time.Duration `yaml:"tcpKeepAlive"`
|
||||||
// HTTP proxy should disable "happy eyeballs" for IPv4/v6 fallback
|
// HTTP proxy should disable "happy eyeballs" for IPv4/v6 fallback
|
||||||
NoHappyEyeballs bool `yaml:"noHappyEyeballs"`
|
NoHappyEyeballs bool `yaml:"noHappyEyeballs"`
|
||||||
// HTTP proxy maximum keepalive connection pool size
|
|
||||||
KeepAliveConnections int `yaml:"keepAliveConnections"`
|
|
||||||
// HTTP proxy timeout for closing an idle connection
|
// HTTP proxy timeout for closing an idle connection
|
||||||
KeepAliveTimeout time.Duration `yaml:"keepAliveTimeout"`
|
KeepAliveTimeout time.Duration `yaml:"keepAliveTimeout"`
|
||||||
|
// HTTP proxy maximum keepalive connection pool size
|
||||||
|
KeepAliveConnections int `yaml:"keepAliveConnections"`
|
||||||
// Sets the HTTP Host header for the local webserver.
|
// Sets the HTTP Host header for the local webserver.
|
||||||
HTTPHostHeader string `yaml:"httpHostHeader"`
|
HTTPHostHeader string `yaml:"httpHostHeader"`
|
||||||
// Hostname on the origin server certificate.
|
// Hostname on the origin server certificate.
|
||||||
|
@ -308,6 +345,19 @@ func (defaults *OriginRequestConfig) setProxyType(overrides config.OriginRequest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (defaults *OriginRequestConfig) setIPRules(overrides config.OriginRequestConfig) {
|
||||||
|
if val := overrides.IPRules; len(val) > 0 {
|
||||||
|
ipAccessRule := make([]ipaccess.Rule, len(overrides.IPRules))
|
||||||
|
for i, r := range overrides.IPRules {
|
||||||
|
rule, err := ipaccess.NewRuleByCIDR(r.Prefix, r.Ports, r.Allow)
|
||||||
|
if err == nil {
|
||||||
|
ipAccessRule[i] = rule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defaults.IPRules = ipAccessRule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetConfig gets config for the requests that cloudflared sends to origins.
|
// 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:
|
// Each field has a setter method which sets a value for the field by trying to find:
|
||||||
// 1. The user config for this rule
|
// 1. The user config for this rule
|
||||||
|
@ -332,5 +382,6 @@ func setConfig(defaults OriginRequestConfig, overrides config.OriginRequestConfi
|
||||||
cfg.setProxyPort(overrides)
|
cfg.setProxyPort(overrides)
|
||||||
cfg.setProxyAddress(overrides)
|
cfg.setProxyAddress(overrides)
|
||||||
cfg.setProxyType(overrides)
|
cfg.setProxyType(overrides)
|
||||||
|
cfg.setIPRules(overrides)
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
|
@ -0,0 +1,422 @@
|
||||||
|
package ingress
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
yaml "gopkg.in/yaml.v2"
|
||||||
|
|
||||||
|
"github.com/cloudflare/cloudflared/config"
|
||||||
|
"github.com/cloudflare/cloudflared/ipaccess"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ensure that the nullable config from `config` package and the
|
||||||
|
// non-nullable config from `ingress` package have the same number of
|
||||||
|
// fields.
|
||||||
|
// This test ensures that programmers didn't add a new field to
|
||||||
|
// one struct and forget to add it to the other ;)
|
||||||
|
func TestCorrespondingFields(t *testing.T) {
|
||||||
|
require.Equal(
|
||||||
|
t,
|
||||||
|
CountFields(t, config.OriginRequestConfig{}),
|
||||||
|
CountFields(t, OriginRequestConfig{}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CountFields(t *testing.T, val interface{}) int {
|
||||||
|
b, err := yaml.Marshal(val)
|
||||||
|
require.NoError(t, err)
|
||||||
|
m := make(map[string]interface{}, 0)
|
||||||
|
err = yaml.Unmarshal(b, &m)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return len(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalRemoteConfigOverridesGlobal(t *testing.T) {
|
||||||
|
rawConfig := []byte(`
|
||||||
|
{
|
||||||
|
"originRequest": {
|
||||||
|
"connectTimeout": 90,
|
||||||
|
"noHappyEyeballs": true
|
||||||
|
},
|
||||||
|
"ingress": [
|
||||||
|
{
|
||||||
|
"hostname": "jira.cfops.com",
|
||||||
|
"service": "http://192.16.19.1:80",
|
||||||
|
"originRequest": {
|
||||||
|
"noTLSVerify": true,
|
||||||
|
"connectTimeout": 10
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"service": "http_status:404"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"warp-routing": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
var remoteConfig RemoteConfig
|
||||||
|
err := json.Unmarshal(rawConfig, &remoteConfig)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, remoteConfig.Ingress.Rules[0].Config.NoTLSVerify)
|
||||||
|
require.True(t, remoteConfig.Ingress.defaults.NoHappyEyeballs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOriginRequestConfigOverrides(t *testing.T) {
|
||||||
|
validate := func(ing Ingress) {
|
||||||
|
// Rule 0 didn't override anything, so it inherits the user-specified
|
||||||
|
// root-level configuration.
|
||||||
|
actual0 := ing.Rules[0].Config
|
||||||
|
expected0 := OriginRequestConfig{
|
||||||
|
ConnectTimeout: 1 * time.Minute,
|
||||||
|
TLSTimeout: 1 * time.Second,
|
||||||
|
TCPKeepAlive: 1 * time.Second,
|
||||||
|
NoHappyEyeballs: true,
|
||||||
|
KeepAliveTimeout: 1 * time.Second,
|
||||||
|
KeepAliveConnections: 1,
|
||||||
|
HTTPHostHeader: "abc",
|
||||||
|
OriginServerName: "a1",
|
||||||
|
CAPool: "/tmp/path0",
|
||||||
|
NoTLSVerify: true,
|
||||||
|
DisableChunkedEncoding: true,
|
||||||
|
BastionMode: true,
|
||||||
|
ProxyAddress: "127.1.2.3",
|
||||||
|
ProxyPort: uint(100),
|
||||||
|
ProxyType: "socks5",
|
||||||
|
IPRules: []ipaccess.Rule{
|
||||||
|
newIPRule(t, "10.0.0.0/8", []int{80, 8080}, false),
|
||||||
|
newIPRule(t, "fc00::/7", []int{443, 4443}, true),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.Equal(t, expected0, actual0)
|
||||||
|
|
||||||
|
// Rule 1 overrode all the root-level config.
|
||||||
|
actual1 := ing.Rules[1].Config
|
||||||
|
expected1 := OriginRequestConfig{
|
||||||
|
ConnectTimeout: 2 * time.Minute,
|
||||||
|
TLSTimeout: 2 * time.Second,
|
||||||
|
TCPKeepAlive: 2 * time.Second,
|
||||||
|
NoHappyEyeballs: false,
|
||||||
|
KeepAliveTimeout: 2 * time.Second,
|
||||||
|
KeepAliveConnections: 2,
|
||||||
|
HTTPHostHeader: "def",
|
||||||
|
OriginServerName: "b2",
|
||||||
|
CAPool: "/tmp/path1",
|
||||||
|
NoTLSVerify: false,
|
||||||
|
DisableChunkedEncoding: false,
|
||||||
|
BastionMode: false,
|
||||||
|
ProxyAddress: "interface",
|
||||||
|
ProxyPort: uint(200),
|
||||||
|
ProxyType: "",
|
||||||
|
IPRules: []ipaccess.Rule{
|
||||||
|
newIPRule(t, "10.0.0.0/16", []int{3000, 3030}, false),
|
||||||
|
newIPRule(t, "192.16.0.0/24", []int{5000, 5050}, true),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.Equal(t, expected1, actual1)
|
||||||
|
}
|
||||||
|
|
||||||
|
rulesYAML := `
|
||||||
|
originRequest:
|
||||||
|
connectTimeout: 1m
|
||||||
|
tlsTimeout: 1s
|
||||||
|
noHappyEyeballs: true
|
||||||
|
tcpKeepAlive: 1s
|
||||||
|
keepAliveConnections: 1
|
||||||
|
keepAliveTimeout: 1s
|
||||||
|
httpHostHeader: abc
|
||||||
|
originServerName: a1
|
||||||
|
caPool: /tmp/path0
|
||||||
|
noTLSVerify: true
|
||||||
|
disableChunkedEncoding: true
|
||||||
|
bastionMode: True
|
||||||
|
proxyAddress: 127.1.2.3
|
||||||
|
proxyPort: 100
|
||||||
|
proxyType: socks5
|
||||||
|
ipRules:
|
||||||
|
- prefix: "10.0.0.0/8"
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
- 8080
|
||||||
|
allow: false
|
||||||
|
- prefix: "fc00::/7"
|
||||||
|
ports:
|
||||||
|
- 443
|
||||||
|
- 4443
|
||||||
|
allow: true
|
||||||
|
ingress:
|
||||||
|
- hostname: tun.example.com
|
||||||
|
service: https://localhost:8000
|
||||||
|
- hostname: "*"
|
||||||
|
service: https://localhost:8001
|
||||||
|
originRequest:
|
||||||
|
connectTimeout: 2m
|
||||||
|
tlsTimeout: 2s
|
||||||
|
noHappyEyeballs: false
|
||||||
|
tcpKeepAlive: 2s
|
||||||
|
keepAliveConnections: 2
|
||||||
|
keepAliveTimeout: 2s
|
||||||
|
httpHostHeader: def
|
||||||
|
originServerName: b2
|
||||||
|
caPool: /tmp/path1
|
||||||
|
noTLSVerify: false
|
||||||
|
disableChunkedEncoding: false
|
||||||
|
bastionMode: false
|
||||||
|
proxyAddress: interface
|
||||||
|
proxyPort: 200
|
||||||
|
proxyType: ""
|
||||||
|
ipRules:
|
||||||
|
- prefix: "10.0.0.0/16"
|
||||||
|
ports:
|
||||||
|
- 3000
|
||||||
|
- 3030
|
||||||
|
allow: false
|
||||||
|
- prefix: "192.16.0.0/24"
|
||||||
|
ports:
|
||||||
|
- 5000
|
||||||
|
- 5050
|
||||||
|
allow: true
|
||||||
|
`
|
||||||
|
|
||||||
|
ing, err := ParseIngress(MustReadIngress(rulesYAML))
|
||||||
|
require.NoError(t, err)
|
||||||
|
validate(ing)
|
||||||
|
|
||||||
|
rawConfig := []byte(`
|
||||||
|
{
|
||||||
|
"originRequest": {
|
||||||
|
"connectTimeout": 60000000000,
|
||||||
|
"tlsTimeout": 1000000000,
|
||||||
|
"noHappyEyeballs": true,
|
||||||
|
"tcpKeepAlive": 1000000000,
|
||||||
|
"keepAliveConnections": 1,
|
||||||
|
"keepAliveTimeout": 1000000000,
|
||||||
|
"httpHostHeader": "abc",
|
||||||
|
"originServerName": "a1",
|
||||||
|
"caPool": "/tmp/path0",
|
||||||
|
"noTLSVerify": true,
|
||||||
|
"disableChunkedEncoding": true,
|
||||||
|
"bastionMode": true,
|
||||||
|
"proxyAddress": "127.1.2.3",
|
||||||
|
"proxyPort": 100,
|
||||||
|
"proxyType": "socks5",
|
||||||
|
"ipRules": [
|
||||||
|
{
|
||||||
|
"prefix": "10.0.0.0/8",
|
||||||
|
"ports": [80, 8080],
|
||||||
|
"allow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"prefix": "fc00::/7",
|
||||||
|
"ports": [443, 4443],
|
||||||
|
"allow": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ingress": [
|
||||||
|
{
|
||||||
|
"hostname": "tun.example.com",
|
||||||
|
"service": "https://localhost:8000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hostname": "*",
|
||||||
|
"service": "https://localhost:8001",
|
||||||
|
"originRequest": {
|
||||||
|
"connectTimeout": 120000000000,
|
||||||
|
"tlsTimeout": 2000000000,
|
||||||
|
"noHappyEyeballs": false,
|
||||||
|
"tcpKeepAlive": 2000000000,
|
||||||
|
"keepAliveConnections": 2,
|
||||||
|
"keepAliveTimeout": 2000000000,
|
||||||
|
"httpHostHeader": "def",
|
||||||
|
"originServerName": "b2",
|
||||||
|
"caPool": "/tmp/path1",
|
||||||
|
"noTLSVerify": false,
|
||||||
|
"disableChunkedEncoding": false,
|
||||||
|
"bastionMode": false,
|
||||||
|
"proxyAddress": "interface",
|
||||||
|
"proxyPort": 200,
|
||||||
|
"proxyType": "",
|
||||||
|
"ipRules": [
|
||||||
|
{
|
||||||
|
"prefix": "10.0.0.0/16",
|
||||||
|
"ports": [3000, 3030],
|
||||||
|
"allow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"prefix": "192.16.0.0/24",
|
||||||
|
"ports": [5000, 5050],
|
||||||
|
"allow": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"warp-routing": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
var remoteConfig RemoteConfig
|
||||||
|
err = json.Unmarshal(rawConfig, &remoteConfig)
|
||||||
|
require.NoError(t, err)
|
||||||
|
validate(remoteConfig.Ingress)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOriginRequestConfigDefaults(t *testing.T) {
|
||||||
|
validate := func(ing Ingress) {
|
||||||
|
// Rule 0 didn't override anything, so it inherits the cloudflared defaults
|
||||||
|
actual0 := ing.Rules[0].Config
|
||||||
|
expected0 := OriginRequestConfig{
|
||||||
|
ConnectTimeout: defaultConnectTimeout,
|
||||||
|
TLSTimeout: defaultTLSTimeout,
|
||||||
|
TCPKeepAlive: defaultTCPKeepAlive,
|
||||||
|
KeepAliveConnections: defaultKeepAliveConnections,
|
||||||
|
KeepAliveTimeout: defaultKeepAliveTimeout,
|
||||||
|
ProxyAddress: defaultProxyAddress,
|
||||||
|
}
|
||||||
|
require.Equal(t, expected0, actual0)
|
||||||
|
|
||||||
|
// Rule 1 overrode all defaults.
|
||||||
|
actual1 := ing.Rules[1].Config
|
||||||
|
expected1 := OriginRequestConfig{
|
||||||
|
ConnectTimeout: 2 * time.Minute,
|
||||||
|
TLSTimeout: 2 * time.Second,
|
||||||
|
TCPKeepAlive: 2 * time.Second,
|
||||||
|
NoHappyEyeballs: false,
|
||||||
|
KeepAliveTimeout: 2 * time.Second,
|
||||||
|
KeepAliveConnections: 2,
|
||||||
|
HTTPHostHeader: "def",
|
||||||
|
OriginServerName: "b2",
|
||||||
|
CAPool: "/tmp/path1",
|
||||||
|
NoTLSVerify: false,
|
||||||
|
DisableChunkedEncoding: false,
|
||||||
|
BastionMode: false,
|
||||||
|
ProxyAddress: "interface",
|
||||||
|
ProxyPort: uint(200),
|
||||||
|
ProxyType: "",
|
||||||
|
IPRules: []ipaccess.Rule{
|
||||||
|
newIPRule(t, "10.0.0.0/16", []int{3000, 3030}, false),
|
||||||
|
newIPRule(t, "192.16.0.0/24", []int{5000, 5050}, true),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.Equal(t, expected1, actual1)
|
||||||
|
}
|
||||||
|
|
||||||
|
rulesYAML := `
|
||||||
|
ingress:
|
||||||
|
- hostname: tun.example.com
|
||||||
|
service: https://localhost:8000
|
||||||
|
- hostname: "*"
|
||||||
|
service: https://localhost:8001
|
||||||
|
originRequest:
|
||||||
|
connectTimeout: 2m
|
||||||
|
tlsTimeout: 2s
|
||||||
|
noHappyEyeballs: false
|
||||||
|
tcpKeepAlive: 2s
|
||||||
|
keepAliveConnections: 2
|
||||||
|
keepAliveTimeout: 2s
|
||||||
|
httpHostHeader: def
|
||||||
|
originServerName: b2
|
||||||
|
caPool: /tmp/path1
|
||||||
|
noTLSVerify: false
|
||||||
|
disableChunkedEncoding: false
|
||||||
|
bastionMode: false
|
||||||
|
proxyAddress: interface
|
||||||
|
proxyPort: 200
|
||||||
|
proxyType: ""
|
||||||
|
ipRules:
|
||||||
|
- prefix: "10.0.0.0/16"
|
||||||
|
ports:
|
||||||
|
- 3000
|
||||||
|
- 3030
|
||||||
|
allow: false
|
||||||
|
- prefix: "192.16.0.0/24"
|
||||||
|
ports:
|
||||||
|
- 5000
|
||||||
|
- 5050
|
||||||
|
allow: true
|
||||||
|
`
|
||||||
|
ing, err := ParseIngress(MustReadIngress(rulesYAML))
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
validate(ing)
|
||||||
|
|
||||||
|
rawConfig := []byte(`
|
||||||
|
{
|
||||||
|
"ingress": [
|
||||||
|
{
|
||||||
|
"hostname": "tun.example.com",
|
||||||
|
"service": "https://localhost:8000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hostname": "*",
|
||||||
|
"service": "https://localhost:8001",
|
||||||
|
"originRequest": {
|
||||||
|
"connectTimeout": 120000000000,
|
||||||
|
"tlsTimeout": 2000000000,
|
||||||
|
"noHappyEyeballs": false,
|
||||||
|
"tcpKeepAlive": 2000000000,
|
||||||
|
"keepAliveConnections": 2,
|
||||||
|
"keepAliveTimeout": 2000000000,
|
||||||
|
"httpHostHeader": "def",
|
||||||
|
"originServerName": "b2",
|
||||||
|
"caPool": "/tmp/path1",
|
||||||
|
"noTLSVerify": false,
|
||||||
|
"disableChunkedEncoding": false,
|
||||||
|
"bastionMode": false,
|
||||||
|
"proxyAddress": "interface",
|
||||||
|
"proxyPort": 200,
|
||||||
|
"proxyType": "",
|
||||||
|
"ipRules": [
|
||||||
|
{
|
||||||
|
"prefix": "10.0.0.0/16",
|
||||||
|
"ports": [3000, 3030],
|
||||||
|
"allow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"prefix": "192.16.0.0/24",
|
||||||
|
"ports": [5000, 5050],
|
||||||
|
"allow": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
var remoteConfig RemoteConfig
|
||||||
|
err = json.Unmarshal(rawConfig, &remoteConfig)
|
||||||
|
require.NoError(t, err)
|
||||||
|
validate(remoteConfig.Ingress)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDefaultConfigFromCLI(t *testing.T) {
|
||||||
|
set := flag.NewFlagSet("contrive", 0)
|
||||||
|
c := cli.NewContext(nil, set, nil)
|
||||||
|
|
||||||
|
expected := OriginRequestConfig{
|
||||||
|
ConnectTimeout: defaultConnectTimeout,
|
||||||
|
TLSTimeout: defaultTLSTimeout,
|
||||||
|
TCPKeepAlive: defaultTCPKeepAlive,
|
||||||
|
KeepAliveConnections: defaultKeepAliveConnections,
|
||||||
|
KeepAliveTimeout: defaultKeepAliveTimeout,
|
||||||
|
ProxyAddress: defaultProxyAddress,
|
||||||
|
}
|
||||||
|
actual := originRequestFromSingeRule(c)
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newIPRule(t *testing.T, prefix string, ports []int, allow bool) ipaccess.Rule {
|
||||||
|
rule, err := ipaccess.NewRuleByCIDR(&prefix, ports, allow)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return rule
|
||||||
|
}
|
|
@ -163,7 +163,7 @@ func (ing Ingress) CatchAll() *Rule {
|
||||||
return &ing.Rules[len(ing.Rules)-1]
|
return &ing.Rules[len(ing.Rules)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func validate(ingress []config.UnvalidatedIngressRule, defaults OriginRequestConfig) (Ingress, error) {
|
func validateIngress(ingress []config.UnvalidatedIngressRule, defaults OriginRequestConfig) (Ingress, error) {
|
||||||
rules := make([]Rule, len(ingress))
|
rules := make([]Rule, len(ingress))
|
||||||
for i, r := range ingress {
|
for i, r := range ingress {
|
||||||
cfg := setConfig(defaults, r.OriginRequest)
|
cfg := setConfig(defaults, r.OriginRequest)
|
||||||
|
@ -290,7 +290,7 @@ func ParseIngress(conf *config.Configuration) (Ingress, error) {
|
||||||
if len(conf.Ingress) == 0 {
|
if len(conf.Ingress) == 0 {
|
||||||
return Ingress{}, ErrNoIngressRules
|
return Ingress{}, ErrNoIngressRules
|
||||||
}
|
}
|
||||||
return validate(conf.Ingress, originRequestFromYAML(conf.OriginRequest))
|
return validateIngress(conf.Ingress, originRequestFromConfig(conf.OriginRequest))
|
||||||
}
|
}
|
||||||
|
|
||||||
func isHTTPService(url *url.URL) bool {
|
func isHTTPService(url *url.URL) bool {
|
||||||
|
|
|
@ -34,7 +34,7 @@ func Test_parseIngress(t *testing.T) {
|
||||||
localhost8000 := MustParseURL(t, "https://localhost:8000")
|
localhost8000 := MustParseURL(t, "https://localhost:8000")
|
||||||
localhost8001 := MustParseURL(t, "https://localhost:8001")
|
localhost8001 := MustParseURL(t, "https://localhost:8001")
|
||||||
fourOhFour := newStatusCode(404)
|
fourOhFour := newStatusCode(404)
|
||||||
defaultConfig := setConfig(originRequestFromYAML(config.OriginRequestConfig{}), config.OriginRequestConfig{})
|
defaultConfig := setConfig(originRequestFromConfig(config.OriginRequestConfig{}), config.OriginRequestConfig{})
|
||||||
require.Equal(t, defaultKeepAliveConnections, defaultConfig.KeepAliveConnections)
|
require.Equal(t, defaultKeepAliveConnections, defaultConfig.KeepAliveConnections)
|
||||||
tr := true
|
tr := true
|
||||||
type args struct {
|
type args struct {
|
||||||
|
@ -324,7 +324,17 @@ ingress:
|
||||||
{
|
{
|
||||||
Hostname: "socks.foo.com",
|
Hostname: "socks.foo.com",
|
||||||
Service: newSocksProxyOverWSService(accessPolicy()),
|
Service: newSocksProxyOverWSService(accessPolicy()),
|
||||||
Config: defaultConfig,
|
Config: setConfig(originRequestFromConfig(config.OriginRequestConfig{}), config.OriginRequestConfig{IPRules: []config.IngressIPRule{
|
||||||
|
{
|
||||||
|
Prefix: ipRulePrefix("1.1.1.0/24"),
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
Allow: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Prefix: ipRulePrefix("0.0.0.0/0"),
|
||||||
|
Allow: false,
|
||||||
|
},
|
||||||
|
}}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Service: &fourOhFour,
|
Service: &fourOhFour,
|
||||||
|
@ -345,7 +355,7 @@ ingress:
|
||||||
{
|
{
|
||||||
Hostname: "bastion.foo.com",
|
Hostname: "bastion.foo.com",
|
||||||
Service: newBastionService(),
|
Service: newBastionService(),
|
||||||
Config: setConfig(originRequestFromYAML(config.OriginRequestConfig{}), config.OriginRequestConfig{BastionMode: &tr}),
|
Config: setConfig(originRequestFromConfig(config.OriginRequestConfig{}), config.OriginRequestConfig{BastionMode: &tr}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Service: &fourOhFour,
|
Service: &fourOhFour,
|
||||||
|
@ -365,7 +375,7 @@ ingress:
|
||||||
{
|
{
|
||||||
Hostname: "bastion.foo.com",
|
Hostname: "bastion.foo.com",
|
||||||
Service: newBastionService(),
|
Service: newBastionService(),
|
||||||
Config: setConfig(originRequestFromYAML(config.OriginRequestConfig{}), config.OriginRequestConfig{BastionMode: &tr}),
|
Config: setConfig(originRequestFromConfig(config.OriginRequestConfig{}), config.OriginRequestConfig{BastionMode: &tr}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Service: &fourOhFour,
|
Service: &fourOhFour,
|
||||||
|
@ -397,6 +407,10 @@ ingress:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ipRulePrefix(s string) *string {
|
||||||
|
return &s
|
||||||
|
}
|
||||||
|
|
||||||
func TestSingleOriginSetsConfig(t *testing.T) {
|
func TestSingleOriginSetsConfig(t *testing.T) {
|
||||||
flagSet := flag.NewFlagSet(t.Name(), flag.PanicOnError)
|
flagSet := flag.NewFlagSet(t.Name(), flag.PanicOnError)
|
||||||
flagSet.Bool("hello-world", true, "")
|
flagSet.Bool("hello-world", true, "")
|
||||||
|
|
|
@ -1,203 +0,0 @@
|
||||||
package ingress
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
yaml "gopkg.in/yaml.v2"
|
|
||||||
|
|
||||||
"github.com/cloudflare/cloudflared/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Ensure that the nullable config from `config` package and the
|
|
||||||
// non-nullable config from `ingress` package have the same number of
|
|
||||||
// fields.
|
|
||||||
// This test ensures that programmers didn't add a new field to
|
|
||||||
// one struct and forget to add it to the other ;)
|
|
||||||
func TestCorrespondingFields(t *testing.T) {
|
|
||||||
require.Equal(
|
|
||||||
t,
|
|
||||||
CountFields(t, config.OriginRequestConfig{}),
|
|
||||||
CountFields(t, OriginRequestConfig{}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CountFields(t *testing.T, val interface{}) int {
|
|
||||||
b, err := yaml.Marshal(val)
|
|
||||||
require.NoError(t, err)
|
|
||||||
m := make(map[string]interface{}, 0)
|
|
||||||
err = yaml.Unmarshal(b, &m)
|
|
||||||
require.NoError(t, err)
|
|
||||||
return len(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOriginRequestConfigOverrides(t *testing.T) {
|
|
||||||
rulesYAML := `
|
|
||||||
originRequest:
|
|
||||||
connectTimeout: 1m
|
|
||||||
tlsTimeout: 1s
|
|
||||||
noHappyEyeballs: true
|
|
||||||
tcpKeepAlive: 1s
|
|
||||||
keepAliveConnections: 1
|
|
||||||
keepAliveTimeout: 1s
|
|
||||||
httpHostHeader: abc
|
|
||||||
originServerName: a1
|
|
||||||
caPool: /tmp/path0
|
|
||||||
noTLSVerify: true
|
|
||||||
disableChunkedEncoding: true
|
|
||||||
bastionMode: True
|
|
||||||
proxyAddress: 127.1.2.3
|
|
||||||
proxyPort: 100
|
|
||||||
proxyType: socks5
|
|
||||||
ingress:
|
|
||||||
- hostname: tun.example.com
|
|
||||||
service: https://localhost:8000
|
|
||||||
- hostname: "*"
|
|
||||||
service: https://localhost:8001
|
|
||||||
originRequest:
|
|
||||||
connectTimeout: 2m
|
|
||||||
tlsTimeout: 2s
|
|
||||||
noHappyEyeballs: false
|
|
||||||
tcpKeepAlive: 2s
|
|
||||||
keepAliveConnections: 2
|
|
||||||
keepAliveTimeout: 2s
|
|
||||||
httpHostHeader: def
|
|
||||||
originServerName: b2
|
|
||||||
caPool: /tmp/path1
|
|
||||||
noTLSVerify: false
|
|
||||||
disableChunkedEncoding: false
|
|
||||||
bastionMode: false
|
|
||||||
proxyAddress: interface
|
|
||||||
proxyPort: 200
|
|
||||||
proxyType: ""
|
|
||||||
`
|
|
||||||
ing, err := ParseIngress(MustReadIngress(rulesYAML))
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rule 0 didn't override anything, so it inherits the user-specified
|
|
||||||
// root-level configuration.
|
|
||||||
actual0 := ing.Rules[0].Config
|
|
||||||
expected0 := OriginRequestConfig{
|
|
||||||
ConnectTimeout: 1 * time.Minute,
|
|
||||||
TLSTimeout: 1 * time.Second,
|
|
||||||
NoHappyEyeballs: true,
|
|
||||||
TCPKeepAlive: 1 * time.Second,
|
|
||||||
KeepAliveConnections: 1,
|
|
||||||
KeepAliveTimeout: 1 * time.Second,
|
|
||||||
HTTPHostHeader: "abc",
|
|
||||||
OriginServerName: "a1",
|
|
||||||
CAPool: "/tmp/path0",
|
|
||||||
NoTLSVerify: true,
|
|
||||||
DisableChunkedEncoding: true,
|
|
||||||
BastionMode: true,
|
|
||||||
ProxyAddress: "127.1.2.3",
|
|
||||||
ProxyPort: uint(100),
|
|
||||||
ProxyType: "socks5",
|
|
||||||
}
|
|
||||||
require.Equal(t, expected0, actual0)
|
|
||||||
|
|
||||||
// Rule 1 overrode all the root-level config.
|
|
||||||
actual1 := ing.Rules[1].Config
|
|
||||||
expected1 := OriginRequestConfig{
|
|
||||||
ConnectTimeout: 2 * time.Minute,
|
|
||||||
TLSTimeout: 2 * time.Second,
|
|
||||||
NoHappyEyeballs: false,
|
|
||||||
TCPKeepAlive: 2 * time.Second,
|
|
||||||
KeepAliveConnections: 2,
|
|
||||||
KeepAliveTimeout: 2 * time.Second,
|
|
||||||
HTTPHostHeader: "def",
|
|
||||||
OriginServerName: "b2",
|
|
||||||
CAPool: "/tmp/path1",
|
|
||||||
NoTLSVerify: false,
|
|
||||||
DisableChunkedEncoding: false,
|
|
||||||
BastionMode: false,
|
|
||||||
ProxyAddress: "interface",
|
|
||||||
ProxyPort: uint(200),
|
|
||||||
ProxyType: "",
|
|
||||||
}
|
|
||||||
require.Equal(t, expected1, actual1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOriginRequestConfigDefaults(t *testing.T) {
|
|
||||||
rulesYAML := `
|
|
||||||
ingress:
|
|
||||||
- hostname: tun.example.com
|
|
||||||
service: https://localhost:8000
|
|
||||||
- hostname: "*"
|
|
||||||
service: https://localhost:8001
|
|
||||||
originRequest:
|
|
||||||
connectTimeout: 2m
|
|
||||||
tlsTimeout: 2s
|
|
||||||
noHappyEyeballs: false
|
|
||||||
tcpKeepAlive: 2s
|
|
||||||
keepAliveConnections: 2
|
|
||||||
keepAliveTimeout: 2s
|
|
||||||
httpHostHeader: def
|
|
||||||
originServerName: b2
|
|
||||||
caPool: /tmp/path1
|
|
||||||
noTLSVerify: false
|
|
||||||
disableChunkedEncoding: false
|
|
||||||
bastionMode: false
|
|
||||||
proxyAddress: interface
|
|
||||||
proxyPort: 200
|
|
||||||
proxyType: ""
|
|
||||||
`
|
|
||||||
ing, err := ParseIngress(MustReadIngress(rulesYAML))
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rule 0 didn't override anything, so it inherits the cloudflared defaults
|
|
||||||
actual0 := ing.Rules[0].Config
|
|
||||||
expected0 := OriginRequestConfig{
|
|
||||||
ConnectTimeout: defaultConnectTimeout,
|
|
||||||
TLSTimeout: defaultTLSTimeout,
|
|
||||||
TCPKeepAlive: defaultTCPKeepAlive,
|
|
||||||
KeepAliveConnections: defaultKeepAliveConnections,
|
|
||||||
KeepAliveTimeout: defaultKeepAliveTimeout,
|
|
||||||
ProxyAddress: defaultProxyAddress,
|
|
||||||
}
|
|
||||||
require.Equal(t, expected0, actual0)
|
|
||||||
|
|
||||||
// Rule 1 overrode all defaults.
|
|
||||||
actual1 := ing.Rules[1].Config
|
|
||||||
expected1 := OriginRequestConfig{
|
|
||||||
ConnectTimeout: 2 * time.Minute,
|
|
||||||
TLSTimeout: 2 * time.Second,
|
|
||||||
NoHappyEyeballs: false,
|
|
||||||
TCPKeepAlive: 2 * time.Second,
|
|
||||||
KeepAliveConnections: 2,
|
|
||||||
KeepAliveTimeout: 2 * time.Second,
|
|
||||||
HTTPHostHeader: "def",
|
|
||||||
OriginServerName: "b2",
|
|
||||||
CAPool: "/tmp/path1",
|
|
||||||
NoTLSVerify: false,
|
|
||||||
DisableChunkedEncoding: false,
|
|
||||||
BastionMode: false,
|
|
||||||
ProxyAddress: "interface",
|
|
||||||
ProxyPort: uint(200),
|
|
||||||
ProxyType: "",
|
|
||||||
}
|
|
||||||
require.Equal(t, expected1, actual1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDefaultConfigFromCLI(t *testing.T) {
|
|
||||||
set := flag.NewFlagSet("contrive", 0)
|
|
||||||
c := cli.NewContext(nil, set, nil)
|
|
||||||
|
|
||||||
expected := OriginRequestConfig{
|
|
||||||
ConnectTimeout: defaultConnectTimeout,
|
|
||||||
TLSTimeout: defaultTLSTimeout,
|
|
||||||
TCPKeepAlive: defaultTCPKeepAlive,
|
|
||||||
KeepAliveConnections: defaultKeepAliveConnections,
|
|
||||||
KeepAliveTimeout: defaultKeepAliveTimeout,
|
|
||||||
ProxyAddress: defaultProxyAddress,
|
|
||||||
}
|
|
||||||
actual := originRequestFromSingeRule(c)
|
|
||||||
require.Equal(t, expected, actual)
|
|
||||||
}
|
|
Loading…
Reference in New Issue