cloudflared-mirror/ingress/config_test.go

423 lines
11 KiB
Go

package ingress
import (
"encoding/json"
"flag"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
yaml "gopkg.in/yaml.v3"
"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: config.CustomDuration{Duration: 1 * time.Minute},
TLSTimeout: config.CustomDuration{Duration: 1 * time.Second},
TCPKeepAlive: config.CustomDuration{Duration: 1 * time.Second},
NoHappyEyeballs: true,
KeepAliveTimeout: config.CustomDuration{Duration: 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: config.CustomDuration{Duration: 2 * time.Minute},
TLSTimeout: config.CustomDuration{Duration: 2 * time.Second},
TCPKeepAlive: config.CustomDuration{Duration: 2 * time.Second},
NoHappyEyeballs: false,
KeepAliveTimeout: config.CustomDuration{Duration: 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": 60,
"tlsTimeout": 1,
"noHappyEyeballs": true,
"tcpKeepAlive": 1,
"keepAliveConnections": 1,
"keepAliveTimeout": 1,
"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": 120,
"tlsTimeout": 2,
"noHappyEyeballs": false,
"tcpKeepAlive": 2,
"keepAliveConnections": 2,
"keepAliveTimeout": 2,
"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: config.CustomDuration{Duration: 2 * time.Minute},
TLSTimeout: config.CustomDuration{Duration: 2 * time.Second},
TCPKeepAlive: config.CustomDuration{Duration: 2 * time.Second},
NoHappyEyeballs: false,
KeepAliveTimeout: config.CustomDuration{Duration: 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": 120,
"tlsTimeout": 2,
"noHappyEyeballs": false,
"tcpKeepAlive": 2,
"keepAliveConnections": 2,
"keepAliveTimeout": 2,
"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
}