mirror of
https://github.com/coredns/coredns.git
synced 2025-10-27 08:14:18 -04:00
Initial implementation of ForwardCRD plugin (#4512)
* Add forwardcrd plugin README.md Co-authored-by: Aidan Obley <aobley@vmware.com> Signed-off-by: Christian Ang <angc@vmware.com> * Create forwardcrd plugin - Place forwardcrd before forward plugin in plugin list. This will avoid forward from preventing the forwardcrd plugin from handling any queries in the case of having a default upstream forwarder in a server block (as is the case in the default kubernetes Corefile). Co-authored-by: Aidan Obley <aobley@vmware.com> Signed-off-by: Christian Ang <angc@vmware.com> * Add Forward CRD Signed-off-by: Christian Ang <angc@vmware.com> * Add NewWithConfig to forward plugin - allows external packages to instanciate forward plugins Co-authored-by: Aidan Obley <aobley@vmware.com> Signed-off-by: Christian Ang <angc@vmware.com> * ForwardCRD plugin handles requests for Forward CRs - add a Kubernetes controller that can read Forward CRs - instances of the forward plugin are created based on Forward CRs from the Kubernetes controller - DNS requests are handled by calling matching Forward plugin instances based on zone name - Defaults to the kube-system namespace to align with Corefile RBAC Signed-off-by: Christian Ang <angc@vmware.com> Use klog v2 in forwardcrd plugin * Refactor forward setup to use NewWithConfig Co-authored-by: Christian Ang <angc@vmware.com> Signed-off-by: Edwin Xie <exie@vmware.com> * Use ParseInt instead of Atoi - to ensure that the bitsize is 32 for later casting to uint32 Signed-off-by: Christian Ang <angc@vmware.com> * Add @christianang to CODEOWNERS for forwardcrd Signed-off-by: Christian Ang <angc@vmware.com> Co-authored-by: Edwin Xie <exie@vmware.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@@ -16,6 +17,8 @@ import (
|
||||
"github.com/coredns/coredns/plugin/dnstap"
|
||||
"github.com/coredns/coredns/plugin/metadata"
|
||||
clog "github.com/coredns/coredns/plugin/pkg/log"
|
||||
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
"github.com/coredns/coredns/request"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
@@ -54,12 +57,127 @@ type Forward struct {
|
||||
Next plugin.Handler
|
||||
}
|
||||
|
||||
// ForwardConfig represents the configuration of the Forward Plugin. This can
|
||||
// be used with NewWithConfig to create a new configured instance of the
|
||||
// Forward Plugin.
|
||||
type ForwardConfig struct {
|
||||
From string
|
||||
To []string
|
||||
Except []string
|
||||
MaxFails *uint32
|
||||
HealthCheck *time.Duration
|
||||
HealthCheckNoRec bool
|
||||
ForceTCP bool
|
||||
PreferUDP bool
|
||||
TLSConfig *tls.Config
|
||||
TLSServerName string
|
||||
Expire *time.Duration
|
||||
MaxConcurrent *int64
|
||||
Policy string
|
||||
TapPlugin *dnstap.Dnstap
|
||||
}
|
||||
|
||||
// New returns a new Forward.
|
||||
func New() *Forward {
|
||||
f := &Forward{maxfails: 2, tlsConfig: new(tls.Config), expire: defaultExpire, p: new(random), from: ".", hcInterval: hcInterval, opts: options{forceTCP: false, preferUDP: false, hcRecursionDesired: true}}
|
||||
return f
|
||||
}
|
||||
|
||||
// NewWithConfig returns a new Forward configured by the provided
|
||||
// ForwardConfig.
|
||||
func NewWithConfig(config ForwardConfig) (*Forward, error) {
|
||||
f := New()
|
||||
if config.From != "" {
|
||||
zones := plugin.Host(config.From).NormalizeExact()
|
||||
f.from = zones[0] // there can only be one here, won't work with non-octet reverse
|
||||
|
||||
if len(zones) > 1 {
|
||||
log.Warningf("Unsupported CIDR notation: '%s' expands to multiple zones. Using only '%s'.", config.From, f.from)
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(config.Except); i++ {
|
||||
f.ignored = append(f.ignored, plugin.Host(config.Except[i]).NormalizeExact()...)
|
||||
}
|
||||
if config.MaxFails != nil {
|
||||
f.maxfails = *config.MaxFails
|
||||
}
|
||||
if config.HealthCheck != nil {
|
||||
if *config.HealthCheck < 0 {
|
||||
return nil, fmt.Errorf("health_check can't be negative: %s", *config.HealthCheck)
|
||||
}
|
||||
f.hcInterval = *config.HealthCheck
|
||||
}
|
||||
f.opts.hcRecursionDesired = !config.HealthCheckNoRec
|
||||
f.opts.forceTCP = config.ForceTCP
|
||||
f.opts.preferUDP = config.PreferUDP
|
||||
if config.TLSConfig != nil {
|
||||
f.tlsConfig = config.TLSConfig
|
||||
}
|
||||
f.tlsServerName = config.TLSServerName
|
||||
if f.tlsServerName != "" {
|
||||
f.tlsConfig.ServerName = f.tlsServerName
|
||||
}
|
||||
if config.Expire != nil {
|
||||
f.expire = *config.Expire
|
||||
if *config.Expire < 0 {
|
||||
return nil, fmt.Errorf("expire can't be negative: %s", *config.Expire)
|
||||
}
|
||||
}
|
||||
if config.MaxConcurrent != nil {
|
||||
if *config.MaxConcurrent < 0 {
|
||||
return f, fmt.Errorf("max_concurrent can't be negative: %d", *config.MaxConcurrent)
|
||||
}
|
||||
f.ErrLimitExceeded = fmt.Errorf("concurrent queries exceeded maximum %d", *config.MaxConcurrent)
|
||||
f.maxConcurrent = *config.MaxConcurrent
|
||||
}
|
||||
if config.Policy != "" {
|
||||
switch config.Policy {
|
||||
case "random":
|
||||
f.p = &random{}
|
||||
case "round_robin":
|
||||
f.p = &roundRobin{}
|
||||
case "sequential":
|
||||
f.p = &sequential{}
|
||||
default:
|
||||
return f, fmt.Errorf("unknown policy '%s'", config.Policy)
|
||||
}
|
||||
}
|
||||
f.tapPlugin = config.TapPlugin
|
||||
|
||||
toHosts, err := parse.HostPortOrFile(config.To...)
|
||||
if err != nil {
|
||||
return f, err
|
||||
}
|
||||
|
||||
transports := make([]string, len(toHosts))
|
||||
allowedTrans := map[string]bool{"dns": true, "tls": true}
|
||||
for i, host := range toHosts {
|
||||
trans, h := parse.Transport(host)
|
||||
|
||||
if !allowedTrans[trans] {
|
||||
return f, fmt.Errorf("'%s' is not supported as a destination protocol in forward: %s", trans, host)
|
||||
}
|
||||
p := NewProxy(h, trans)
|
||||
f.proxies = append(f.proxies, p)
|
||||
transports[i] = trans
|
||||
}
|
||||
|
||||
// Initialize ClientSessionCache in tls.Config. This may speed up a TLS handshake
|
||||
// in upcoming connections to the same TLS server.
|
||||
f.tlsConfig.ClientSessionCache = tls.NewLRUClientSessionCache(len(f.proxies))
|
||||
|
||||
for i := range f.proxies {
|
||||
// Only set this for proxies that need it.
|
||||
if transports[i] == transport.TLS {
|
||||
f.proxies[i].SetTLSConfig(f.tlsConfig)
|
||||
}
|
||||
f.proxies[i].SetExpire(f.expire)
|
||||
f.proxies[i].health.SetRecursionDesired(f.opts.hcRecursionDesired)
|
||||
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// SetProxy appends p to the proxy list and starts healthchecking.
|
||||
func (f *Forward) SetProxy(p *Proxy) {
|
||||
f.proxies = append(f.proxies, p)
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
package forward
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/plugin/dnstap"
|
||||
)
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
@@ -22,3 +28,281 @@ func TestList(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewWithConfig(t *testing.T) {
|
||||
expectedExcept := []string{"foo.com.", "example.com."}
|
||||
expectedMaxFails := uint32(5)
|
||||
expectedHealthCheck := 5 * time.Second
|
||||
expectedServerName := "test"
|
||||
expectedExpire := 20 * time.Second
|
||||
expectedMaxConcurrent := int64(5)
|
||||
expectedDnstap := dnstap.Dnstap{}
|
||||
|
||||
f, err := NewWithConfig(ForwardConfig{
|
||||
From: "test",
|
||||
To: []string{"1.2.3.4:3053", "tls://4.5.6.7"},
|
||||
Except: []string{"FOO.com", "example.com"},
|
||||
MaxFails: &expectedMaxFails,
|
||||
HealthCheck: &expectedHealthCheck,
|
||||
HealthCheckNoRec: true,
|
||||
ForceTCP: true,
|
||||
PreferUDP: true,
|
||||
TLSConfig: &tls.Config{NextProtos: []string{"some-proto"}},
|
||||
TLSServerName: expectedServerName,
|
||||
Expire: &expectedExpire,
|
||||
MaxConcurrent: &expectedMaxConcurrent,
|
||||
TapPlugin: &expectedDnstap,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Expected not to error: %s", err)
|
||||
}
|
||||
|
||||
if f.from != "test." {
|
||||
t.Fatalf("Expected from to be %s, got: %s", "test.", f.from)
|
||||
}
|
||||
|
||||
if len(f.proxies) != 2 {
|
||||
t.Fatalf("Expected proxies to have len of %d, got: %d", 2, len(f.proxies))
|
||||
}
|
||||
|
||||
if f.proxies[0].addr != "1.2.3.4:3053" {
|
||||
t.Fatalf("Expected proxy to have addr of %s, got: %s", "1.2.3.4:3053", f.proxies[0].addr)
|
||||
}
|
||||
|
||||
if f.proxies[1].addr != "4.5.6.7:853" {
|
||||
t.Fatalf("Expected proxy to have addr of %s, got: %s", "4.5.6.7:853", f.proxies[1].addr)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(f.ignored, expectedExcept) {
|
||||
t.Fatalf("Expected ignored to consist of %#v, got: %#v", expectedExcept, f.ignored)
|
||||
}
|
||||
|
||||
if f.maxfails != 5 {
|
||||
t.Fatalf("Expected maxfails to be %d, got: %d", expectedMaxFails, f.maxfails)
|
||||
}
|
||||
|
||||
if f.hcInterval != 5*time.Second {
|
||||
t.Fatalf("Expected hcInterval to be %s, got: %s", expectedHealthCheck, f.hcInterval)
|
||||
}
|
||||
|
||||
if f.opts.hcRecursionDesired {
|
||||
t.Fatalf("Expected hcRecursionDesired to be false")
|
||||
}
|
||||
|
||||
if !f.opts.forceTCP {
|
||||
t.Fatalf("Expected forceTCP to be true")
|
||||
}
|
||||
|
||||
if !f.opts.preferUDP {
|
||||
t.Fatalf("Expected preferUDP to be true")
|
||||
}
|
||||
|
||||
if len(f.tlsConfig.NextProtos) != 1 || f.tlsConfig.NextProtos[0] != "some-proto" {
|
||||
t.Fatalf("Expected tlsConfig to have NextProtos to consist of %s, got: %s", "some-proto", f.tlsConfig.NextProtos)
|
||||
}
|
||||
|
||||
if f.tlsConfig.ServerName != expectedServerName {
|
||||
t.Fatalf("Expected tlsConfig to have ServerName to be %s, got: %s", expectedServerName, f.tlsConfig.ServerName)
|
||||
}
|
||||
|
||||
if f.tlsServerName != "test" {
|
||||
t.Fatalf("Expected tlsSeverName to be %s, got: %s", expectedServerName, f.tlsServerName)
|
||||
}
|
||||
|
||||
if f.expire != 20*time.Second {
|
||||
t.Fatalf("Expected expire to be %s, got: %s", expectedExpire, f.expire)
|
||||
}
|
||||
|
||||
if f.ErrLimitExceeded == nil || f.ErrLimitExceeded.Error() != "concurrent queries exceeded maximum 5" {
|
||||
t.Fatalf("Expected ErrLimitExceeded to be %s, got: %s", "concurrent queries exceeded maximum 5", f.ErrLimitExceeded)
|
||||
}
|
||||
|
||||
if f.maxConcurrent != 5 {
|
||||
t.Fatalf("Expected maxConcurrent to be %d, got: %d", 5, f.maxConcurrent)
|
||||
}
|
||||
|
||||
if fmt.Sprintf("%T", f.tlsConfig.ClientSessionCache) != "*tls.lruSessionCache" {
|
||||
t.Fatalf("Expected tlsConfig.ClientSessionCache to be type %s, got: %T", "*tls.lruSessionCache", f.tlsConfig.ClientSessionCache)
|
||||
}
|
||||
|
||||
if f.proxies[0].transport.expire != f.expire {
|
||||
t.Fatalf("Expected proxy.transport.expire to be %s, got: %s", f.expire, f.proxies[0].transport.expire)
|
||||
}
|
||||
|
||||
if f.proxies[1].transport.expire != f.expire {
|
||||
t.Fatalf("Expected proxy.transport.expire to be %s, got: %s", f.expire, f.proxies[1].transport.expire)
|
||||
}
|
||||
|
||||
if f.proxies[0].health.GetRecursionDesired() != f.opts.hcRecursionDesired {
|
||||
t.Fatalf("Expected proxy.health.GetRecursionDesired to be %t, got: %t", f.opts.hcRecursionDesired, f.proxies[0].health.GetRecursionDesired())
|
||||
}
|
||||
|
||||
if f.proxies[1].health.GetRecursionDesired() != f.opts.hcRecursionDesired {
|
||||
t.Fatalf("Expected proxy.health.GetRecursionDesired to be %t, got: %t", f.opts.hcRecursionDesired, f.proxies[1].health.GetRecursionDesired())
|
||||
}
|
||||
|
||||
if f.proxies[0].transport.tlsConfig == f.tlsConfig {
|
||||
t.Fatalf("Expected proxy.transport.tlsConfig to be nil, got: %#v", f.proxies[0].transport.tlsConfig)
|
||||
}
|
||||
|
||||
if f.proxies[1].transport.tlsConfig != f.tlsConfig {
|
||||
t.Fatalf("Expected proxy.transport.tlsConfig to be %#v, got: %#v", f.tlsConfig, f.proxies[1].transport.tlsConfig)
|
||||
}
|
||||
|
||||
if f.tapPlugin != &expectedDnstap {
|
||||
t.Fatalf("Expcted tapPlugin to be %p, got: %p", &expectedDnstap, f.tapPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewWithConfigNegativeHealthCheck(t *testing.T) {
|
||||
healthCheck, _ := time.ParseDuration("-5s")
|
||||
|
||||
_, err := NewWithConfig(ForwardConfig{
|
||||
To: []string{"1.2.3.4:3053", "4.5.6.7"},
|
||||
HealthCheck: &healthCheck,
|
||||
})
|
||||
if err == nil || err.Error() != "health_check can't be negative: -5s" {
|
||||
t.Fatalf("Expected error to be %s, got: %s", "health_check can't be negative: -5s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewWithConfigNegativeExpire(t *testing.T) {
|
||||
expire, _ := time.ParseDuration("-5s")
|
||||
|
||||
_, err := NewWithConfig(ForwardConfig{
|
||||
To: []string{"1.2.3.4:3053", "4.5.6.7"},
|
||||
Expire: &expire,
|
||||
})
|
||||
if err == nil || err.Error() != "expire can't be negative: -5s" {
|
||||
t.Fatalf("Expected error to be %s, got: %s", "expire can't be negative: -5s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewWithConfigNegativeMaxConcurrent(t *testing.T) {
|
||||
maxConcurrent := int64(-5)
|
||||
|
||||
_, err := NewWithConfig(ForwardConfig{
|
||||
To: []string{"1.2.3.4:3053", "4.5.6.7"},
|
||||
MaxConcurrent: &maxConcurrent,
|
||||
})
|
||||
if err == nil || err.Error() != "max_concurrent can't be negative: -5" {
|
||||
t.Fatalf("Expected error to be %s, got: %s", "max_concurrent can't be negative: -5", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewWithConfigPolicy(t *testing.T) {
|
||||
config := ForwardConfig{
|
||||
To: []string{"1.2.3.4:3053", "4.5.6.7"},
|
||||
}
|
||||
|
||||
config.Policy = "random"
|
||||
f, err := NewWithConfig(config)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected not to error: %s", err)
|
||||
}
|
||||
|
||||
if _, ok := f.p.(*random); !ok {
|
||||
t.Fatalf("Expect p to be of type %s, got: %T", "random", f.p)
|
||||
}
|
||||
|
||||
config.Policy = "round_robin"
|
||||
f, err = NewWithConfig(config)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected not to error: %s", err)
|
||||
}
|
||||
|
||||
if _, ok := f.p.(*roundRobin); !ok {
|
||||
t.Fatalf("Expect p to be of type %s, got: %T", "roundRobin", f.p)
|
||||
}
|
||||
|
||||
config.Policy = "sequential"
|
||||
f, err = NewWithConfig(config)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected not to error: %s", err)
|
||||
}
|
||||
|
||||
if _, ok := f.p.(*sequential); !ok {
|
||||
t.Fatalf("Expect p to be of type %s, got: %T", "sequential", f.p)
|
||||
}
|
||||
|
||||
config.Policy = "invalid_policy"
|
||||
_, err = NewWithConfig(config)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error %s, got: %s", "unknown policy 'invalid_policy'", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewWithConfigServerNameDefault(t *testing.T) {
|
||||
f, err := NewWithConfig(ForwardConfig{
|
||||
To: []string{"1.2.3.4"},
|
||||
TLSConfig: &tls.Config{ServerName: "some-server-name"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Expected not to error: %s", err)
|
||||
}
|
||||
|
||||
if f.tlsConfig.ServerName != "some-server-name" {
|
||||
t.Fatalf("Expect tlsConfig.ServerName to be %s, got: %s", "some-server-name", f.tlsConfig.ServerName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewWithConfigWithDefaults(t *testing.T) {
|
||||
f, err := NewWithConfig(ForwardConfig{
|
||||
To: []string{"1.2.3.4"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Expected not to error: %s", err)
|
||||
}
|
||||
|
||||
if f.from != "." {
|
||||
t.Fatalf("Expected from to be %s, got: %s", ".", f.from)
|
||||
}
|
||||
|
||||
if f.ignored != nil {
|
||||
t.Fatalf("Expected ignored to be nil but was %#v", f.ignored)
|
||||
}
|
||||
|
||||
if f.maxfails != 2 {
|
||||
t.Fatalf("Expected maxfails to be %d, got: %d", 2, f.maxfails)
|
||||
}
|
||||
|
||||
if f.hcInterval != 500*time.Millisecond {
|
||||
t.Fatalf("Expected hcInterval to be %s, got: %s", 500*time.Millisecond, f.hcInterval)
|
||||
}
|
||||
|
||||
if !f.opts.hcRecursionDesired {
|
||||
t.Fatalf("Expected hcRecursionDesired to be true")
|
||||
}
|
||||
|
||||
if f.opts.forceTCP {
|
||||
t.Fatalf("Expected forceTCP to be false")
|
||||
}
|
||||
|
||||
if f.opts.preferUDP {
|
||||
t.Fatalf("Expected preferUDP to be false")
|
||||
}
|
||||
|
||||
if f.tlsConfig == nil {
|
||||
t.Fatalf("Expected tlsConfig to be non nil")
|
||||
}
|
||||
|
||||
if f.tlsServerName != "" {
|
||||
t.Fatalf("Expected tlsServerName to be empty")
|
||||
}
|
||||
|
||||
if f.expire != defaultExpire {
|
||||
t.Fatalf("Expected expire to be %s, got: %s", defaultExpire, f.expire)
|
||||
}
|
||||
|
||||
if f.ErrLimitExceeded != nil {
|
||||
t.Fatalf("Expected ErrLimitExceeded to be nil")
|
||||
}
|
||||
|
||||
if f.maxConcurrent != 0 {
|
||||
t.Fatalf("Expected maxConcurrent to be %d, got: %d", 0, f.maxConcurrent)
|
||||
}
|
||||
|
||||
if _, ok := f.p.(*random); !ok {
|
||||
t.Fatalf("Expect p to be of type %s, got: %T", "random", f.p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package forward
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -11,9 +9,7 @@ import (
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/dnstap"
|
||||
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||
pkgtls "github.com/coredns/coredns/plugin/pkg/tls"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
)
|
||||
|
||||
func init() { plugin.Register("forward", setup) }
|
||||
@@ -87,90 +83,46 @@ func parseForward(c *caddy.Controller) (*Forward, error) {
|
||||
}
|
||||
|
||||
func parseStanza(c *caddy.Controller) (*Forward, error) {
|
||||
f := New()
|
||||
cfg := ForwardConfig{}
|
||||
|
||||
if !c.Args(&f.from) {
|
||||
return f, c.ArgErr()
|
||||
}
|
||||
origFrom := f.from
|
||||
zones := plugin.Host(f.from).NormalizeExact()
|
||||
f.from = zones[0] // there can only be one here, won't work with non-octet reverse
|
||||
|
||||
if len(zones) > 1 {
|
||||
log.Warningf("Unsupported CIDR notation: '%s' expands to multiple zones. Using only '%s'.", origFrom, f.from)
|
||||
if !c.Args(&cfg.From) {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
|
||||
to := c.RemainingArgs()
|
||||
if len(to) == 0 {
|
||||
return f, c.ArgErr()
|
||||
}
|
||||
|
||||
toHosts, err := parse.HostPortOrFile(to...)
|
||||
if err != nil {
|
||||
return f, err
|
||||
}
|
||||
|
||||
transports := make([]string, len(toHosts))
|
||||
allowedTrans := map[string]bool{"dns": true, "tls": true}
|
||||
for i, host := range toHosts {
|
||||
trans, h := parse.Transport(host)
|
||||
|
||||
if !allowedTrans[trans] {
|
||||
return f, fmt.Errorf("'%s' is not supported as a destination protocol in forward: %s", trans, host)
|
||||
}
|
||||
p := NewProxy(h, trans)
|
||||
f.proxies = append(f.proxies, p)
|
||||
transports[i] = trans
|
||||
cfg.To = c.RemainingArgs()
|
||||
if len(cfg.To) == 0 {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
|
||||
for c.NextBlock() {
|
||||
if err := parseBlock(c, f); err != nil {
|
||||
return f, err
|
||||
if err := parseBlock(c, &cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if f.tlsServerName != "" {
|
||||
f.tlsConfig.ServerName = f.tlsServerName
|
||||
}
|
||||
|
||||
// Initialize ClientSessionCache in tls.Config. This may speed up a TLS handshake
|
||||
// in upcoming connections to the same TLS server.
|
||||
f.tlsConfig.ClientSessionCache = tls.NewLRUClientSessionCache(len(f.proxies))
|
||||
|
||||
for i := range f.proxies {
|
||||
// Only set this for proxies that need it.
|
||||
if transports[i] == transport.TLS {
|
||||
f.proxies[i].SetTLSConfig(f.tlsConfig)
|
||||
}
|
||||
f.proxies[i].SetExpire(f.expire)
|
||||
f.proxies[i].health.SetRecursionDesired(f.opts.hcRecursionDesired)
|
||||
}
|
||||
|
||||
return f, nil
|
||||
return NewWithConfig(cfg)
|
||||
}
|
||||
|
||||
func parseBlock(c *caddy.Controller, f *Forward) error {
|
||||
func parseBlock(c *caddy.Controller, cfg *ForwardConfig) error {
|
||||
switch c.Val() {
|
||||
case "except":
|
||||
ignore := c.RemainingArgs()
|
||||
if len(ignore) == 0 {
|
||||
cfg.Except = c.RemainingArgs()
|
||||
if len(cfg.Except) == 0 {
|
||||
return c.ArgErr()
|
||||
}
|
||||
for i := 0; i < len(ignore); i++ {
|
||||
f.ignored = append(f.ignored, plugin.Host(ignore[i]).NormalizeExact()...)
|
||||
}
|
||||
case "max_fails":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
n, err := strconv.Atoi(c.Val())
|
||||
n, err := strconv.ParseInt(c.Val(), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n < 0 {
|
||||
return fmt.Errorf("max_fails can't be negative: %d", n)
|
||||
}
|
||||
f.maxfails = uint32(n)
|
||||
maxFails := uint32(n)
|
||||
cfg.MaxFails = &maxFails
|
||||
case "health_check":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
@@ -179,15 +131,12 @@ func parseBlock(c *caddy.Controller, f *Forward) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dur < 0 {
|
||||
return fmt.Errorf("health_check can't be negative: %d", dur)
|
||||
}
|
||||
f.hcInterval = dur
|
||||
cfg.HealthCheck = &dur
|
||||
|
||||
for c.NextArg() {
|
||||
switch hcOpts := c.Val(); hcOpts {
|
||||
case "no_rec":
|
||||
f.opts.hcRecursionDesired = false
|
||||
cfg.HealthCheckNoRec = true
|
||||
default:
|
||||
return fmt.Errorf("health_check: unknown option %s", hcOpts)
|
||||
}
|
||||
@@ -197,12 +146,12 @@ func parseBlock(c *caddy.Controller, f *Forward) error {
|
||||
if c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
f.opts.forceTCP = true
|
||||
cfg.ForceTCP = true
|
||||
case "prefer_udp":
|
||||
if c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
f.opts.preferUDP = true
|
||||
cfg.PreferUDP = true
|
||||
case "tls":
|
||||
args := c.RemainingArgs()
|
||||
if len(args) > 3 {
|
||||
@@ -213,12 +162,12 @@ func parseBlock(c *caddy.Controller, f *Forward) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.tlsConfig = tlsConfig
|
||||
cfg.TLSConfig = tlsConfig
|
||||
case "tls_servername":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
f.tlsServerName = c.Val()
|
||||
cfg.TLSServerName = c.Val()
|
||||
case "expire":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
@@ -227,24 +176,12 @@ func parseBlock(c *caddy.Controller, f *Forward) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dur < 0 {
|
||||
return fmt.Errorf("expire can't be negative: %s", dur)
|
||||
}
|
||||
f.expire = dur
|
||||
cfg.Expire = &dur
|
||||
case "policy":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
switch x := c.Val(); x {
|
||||
case "random":
|
||||
f.p = &random{}
|
||||
case "round_robin":
|
||||
f.p = &roundRobin{}
|
||||
case "sequential":
|
||||
f.p = &sequential{}
|
||||
default:
|
||||
return c.Errf("unknown policy '%s'", x)
|
||||
}
|
||||
cfg.Policy = c.Val()
|
||||
case "max_concurrent":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
@@ -253,11 +190,8 @@ func parseBlock(c *caddy.Controller, f *Forward) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n < 0 {
|
||||
return fmt.Errorf("max_concurrent can't be negative: %d", n)
|
||||
}
|
||||
f.ErrLimitExceeded = errors.New("concurrent queries exceeded maximum " + c.Val())
|
||||
f.maxConcurrent = int64(n)
|
||||
maxConcurrent := int64(n)
|
||||
cfg.MaxConcurrent = &maxConcurrent
|
||||
|
||||
default:
|
||||
return c.Errf("unknown property '%s'", c.Val())
|
||||
|
||||
Reference in New Issue
Block a user