| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | package forward
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 	"crypto/tls"
 | 
					
						
							|  |  |  | 	"errors"
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	"fmt"
 | 
					
						
							|  |  |  | 	"strconv"
 | 
					
						
							|  |  |  | 	"time"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-24 18:14:41 +02:00
										 |  |  | 	"github.com/coredns/caddy"
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	"github.com/coredns/coredns/core/dnsserver"
 | 
					
						
							|  |  |  | 	"github.com/coredns/coredns/plugin"
 | 
					
						
							| 
									
										
										
										
											2020-10-12 19:10:35 +02:00
										 |  |  | 	"github.com/coredns/coredns/plugin/dnstap"
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/parse"
 | 
					
						
							| 
									
										
										
										
											2023-03-24 12:55:51 +00:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/proxy"
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	pkgtls "github.com/coredns/coredns/plugin/pkg/tls"
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/transport"
 | 
					
						
							| 
									
										
										
										
											2022-08-15 22:16:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/miekg/dns"
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-04 15:35:55 +01:00
										 |  |  | func init() {
 | 
					
						
							|  |  |  | 	plugin.Register("forward", setup)
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | func setup(c *caddy.Controller) error {
 | 
					
						
							| 
									
										
										
										
											2022-07-20 10:35:04 -04:00
										 |  |  | 	fs, err := parseForward(c)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	if err != nil {
 | 
					
						
							| 
									
										
										
										
											2018-02-23 15:02:05 +00:00
										 |  |  | 		return plugin.Error("forward", err)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2022-07-20 10:35:04 -04:00
										 |  |  | 	for i := range fs {
 | 
					
						
							|  |  |  | 		f := fs[i]
 | 
					
						
							|  |  |  | 		if f.Len() > max {
 | 
					
						
							|  |  |  | 			return plugin.Error("forward", fmt.Errorf("more than %d TOs configured: %d", max, f.Len()))
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 10:35:04 -04:00
										 |  |  | 		if i == len(fs)-1 {
 | 
					
						
							|  |  |  | 			// last forward: point next to next plugin
 | 
					
						
							|  |  |  | 			dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
 | 
					
						
							|  |  |  | 				f.Next = next
 | 
					
						
							|  |  |  | 				return f
 | 
					
						
							|  |  |  | 			})
 | 
					
						
							|  |  |  | 		} else {
 | 
					
						
							|  |  |  | 			// middle forward: point next to next forward
 | 
					
						
							|  |  |  | 			nextForward := fs[i+1]
 | 
					
						
							|  |  |  | 			dnsserver.GetConfig(c).AddPlugin(func(plugin.Handler) plugin.Handler {
 | 
					
						
							|  |  |  | 				f.Next = nextForward
 | 
					
						
							|  |  |  | 				return f
 | 
					
						
							|  |  |  | 			})
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 10:35:04 -04:00
										 |  |  | 		c.OnStartup(func() error {
 | 
					
						
							|  |  |  | 			return f.OnStartup()
 | 
					
						
							|  |  |  | 		})
 | 
					
						
							|  |  |  | 		c.OnStartup(func() error {
 | 
					
						
							|  |  |  | 			if taph := dnsserver.GetConfig(c).Handler("dnstap"); taph != nil {
 | 
					
						
							| 
									
										
										
										
											2023-01-31 03:38:15 +08:00
										 |  |  | 				f.SetTapPlugin(taph.(*dnstap.Dnstap))
 | 
					
						
							| 
									
										
										
										
											2020-10-12 19:10:35 +02:00
										 |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2022-07-20 10:35:04 -04:00
										 |  |  | 			return nil
 | 
					
						
							|  |  |  | 		})
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 10:35:04 -04:00
										 |  |  | 		c.OnShutdown(func() error {
 | 
					
						
							|  |  |  | 			return f.OnShutdown()
 | 
					
						
							|  |  |  | 		})
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // OnStartup starts a goroutines for all proxies.
 | 
					
						
							|  |  |  | func (f *Forward) OnStartup() (err error) {
 | 
					
						
							|  |  |  | 	for _, p := range f.proxies {
 | 
					
						
							| 
									
										
										
										
											2023-03-24 12:55:51 +00:00
										 |  |  | 		p.Start(f.hcInterval)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	return nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // OnShutdown stops all configured proxies.
 | 
					
						
							|  |  |  | func (f *Forward) OnShutdown() error {
 | 
					
						
							|  |  |  | 	for _, p := range f.proxies {
 | 
					
						
							| 
									
										
										
										
											2023-03-24 12:55:51 +00:00
										 |  |  | 		p.Stop()
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	return nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 10:35:04 -04:00
										 |  |  | func parseForward(c *caddy.Controller) ([]*Forward, error) {
 | 
					
						
							|  |  |  | 	var fs = []*Forward{}
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	for c.Next() {
 | 
					
						
							| 
									
										
										
										
											2022-07-20 10:35:04 -04:00
										 |  |  | 		f, err := parseStanza(c)
 | 
					
						
							| 
									
										
										
										
											2018-08-16 00:24:47 +03:00
										 |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			return nil, err
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2022-07-20 10:35:04 -04:00
										 |  |  | 		fs = append(fs, f)
 | 
					
						
							| 
									
										
										
										
											2018-08-16 00:24:47 +03:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2022-07-20 10:35:04 -04:00
										 |  |  | 	return fs, nil
 | 
					
						
							| 
									
										
										
										
											2018-08-16 00:24:47 +03:00
										 |  |  | }
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-28 10:41:12 +01:00
										 |  |  | func parseStanza(c *caddy.Controller) (*Forward, error) {
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 	f := New()
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 	if !c.Args(&f.from) {
 | 
					
						
							|  |  |  | 		return f, c.ArgErr()
 | 
					
						
							| 
									
										
										
										
											2018-08-16 00:24:47 +03:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 	origFrom := f.from
 | 
					
						
							|  |  |  | 	zones := plugin.Host(f.from).NormalizeExact()
 | 
					
						
							| 
									
										
										
										
											2022-02-17 15:13:18 -05:00
										 |  |  | 	if len(zones) == 0 {
 | 
					
						
							|  |  |  | 		return f, fmt.Errorf("unable to normalize '%s'", f.from)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 	f.from = zones[0] // there can only be one here, won't work with non-octet reverse
 | 
					
						
							| 
									
										
										
										
											2018-08-16 00:24:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 	if len(zones) > 1 {
 | 
					
						
							|  |  |  | 		log.Warningf("Unsupported CIDR notation: '%s' expands to multiple zones. Using only '%s'.", origFrom, f.from)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2023-07-04 15:35:55 +01:00
										 |  |  | 		p := proxy.NewProxy("forward", h, trans)
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		f.proxies = append(f.proxies, p)
 | 
					
						
							|  |  |  | 		transports[i] = trans
 | 
					
						
							| 
									
										
										
										
											2018-08-16 00:24:47 +03:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for c.NextBlock() {
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		if err := parseBlock(c, f); err != nil {
 | 
					
						
							|  |  |  | 			return f, 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)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		f.proxies[i].SetExpire(f.expire)
 | 
					
						
							| 
									
										
										
										
											2023-03-24 12:55:51 +00:00
										 |  |  | 		f.proxies[i].GetHealthchecker().SetRecursionDesired(f.opts.HCRecursionDesired)
 | 
					
						
							| 
									
										
										
										
											2022-02-09 15:45:52 +01:00
										 |  |  | 		// when TLS is used, checks are set to tcp-tls
 | 
					
						
							| 
									
										
										
										
											2023-03-24 12:55:51 +00:00
										 |  |  | 		if f.opts.ForceTCP && transports[i] != transport.TLS {
 | 
					
						
							|  |  |  | 			f.proxies[i].GetHealthchecker().SetTCPTransport()
 | 
					
						
							| 
									
										
										
										
											2022-02-09 15:45:52 +01:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2023-03-24 12:55:51 +00:00
										 |  |  | 		f.proxies[i].GetHealthchecker().SetDomain(f.opts.HCDomain)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2020-02-04 07:59:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 	return f, nil
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | func parseBlock(c *caddy.Controller, f *Forward) error {
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	switch c.Val() {
 | 
					
						
							|  |  |  | 	case "except":
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		ignore := c.RemainingArgs()
 | 
					
						
							|  |  |  | 		if len(ignore) == 0 {
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 			return c.ArgErr()
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		for i := 0; i < len(ignore); i++ {
 | 
					
						
							|  |  |  | 			f.ignored = append(f.ignored, plugin.Host(ignore[i]).NormalizeExact()...)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	case "max_fails":
 | 
					
						
							|  |  |  | 		if !c.NextArg() {
 | 
					
						
							|  |  |  | 			return c.ArgErr()
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2022-02-07 06:09:12 -08:00
										 |  |  | 		n, err := strconv.ParseUint(c.Val(), 10, 32)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			return err
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		f.maxfails = uint32(n)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	case "health_check":
 | 
					
						
							|  |  |  | 		if !c.NextArg() {
 | 
					
						
							|  |  |  | 			return c.ArgErr()
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		dur, err := time.ParseDuration(c.Val())
 | 
					
						
							|  |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			return err
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		if dur < 0 {
 | 
					
						
							|  |  |  | 			return fmt.Errorf("health_check can't be negative: %d", dur)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		f.hcInterval = dur
 | 
					
						
							| 
									
										
										
										
											2023-03-24 12:55:51 +00:00
										 |  |  | 		f.opts.HCDomain = "."
 | 
					
						
							| 
									
										
										
										
											2020-03-06 11:52:43 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		for c.NextArg() {
 | 
					
						
							|  |  |  | 			switch hcOpts := c.Val(); hcOpts {
 | 
					
						
							|  |  |  | 			case "no_rec":
 | 
					
						
							| 
									
										
										
										
											2023-03-24 12:55:51 +00:00
										 |  |  | 				f.opts.HCRecursionDesired = false
 | 
					
						
							| 
									
										
										
										
											2022-04-13 00:39:48 +08:00
										 |  |  | 			case "domain":
 | 
					
						
							|  |  |  | 				if !c.NextArg() {
 | 
					
						
							|  |  |  | 					return c.ArgErr()
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							| 
									
										
										
										
											2022-08-15 22:16:15 +08:00
										 |  |  | 				hcDomain := c.Val()
 | 
					
						
							|  |  |  | 				if _, ok := dns.IsDomainName(hcDomain); !ok {
 | 
					
						
							|  |  |  | 					return fmt.Errorf("health_check: invalid domain name %s", hcDomain)
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							| 
									
										
										
										
											2023-03-24 12:55:51 +00:00
										 |  |  | 				f.opts.HCDomain = plugin.Name(hcDomain).Normalize()
 | 
					
						
							| 
									
										
										
										
											2020-03-06 11:52:43 +01:00
										 |  |  | 			default:
 | 
					
						
							|  |  |  | 				return fmt.Errorf("health_check: unknown option %s", hcOpts)
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	case "force_tcp":
 | 
					
						
							|  |  |  | 		if c.NextArg() {
 | 
					
						
							|  |  |  | 			return c.ArgErr()
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2023-03-24 12:55:51 +00:00
										 |  |  | 		f.opts.ForceTCP = true
 | 
					
						
							| 
									
										
										
										
											2018-07-07 10:14:21 +03:00
										 |  |  | 	case "prefer_udp":
 | 
					
						
							|  |  |  | 		if c.NextArg() {
 | 
					
						
							|  |  |  | 			return c.ArgErr()
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2023-03-24 12:55:51 +00:00
										 |  |  | 		f.opts.PreferUDP = true
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	case "tls":
 | 
					
						
							|  |  |  | 		args := c.RemainingArgs()
 | 
					
						
							| 
									
										
										
										
											2018-03-30 16:35:09 +03:00
										 |  |  | 		if len(args) > 3 {
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 			return c.ArgErr()
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2023-06-01 14:07:58 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-30 16:35:09 +03:00
										 |  |  | 		tlsConfig, err := pkgtls.NewTLSConfigFromArgs(args...)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			return err
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		f.tlsConfig = tlsConfig
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	case "tls_servername":
 | 
					
						
							|  |  |  | 		if !c.NextArg() {
 | 
					
						
							|  |  |  | 			return c.ArgErr()
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		f.tlsServerName = c.Val()
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	case "expire":
 | 
					
						
							|  |  |  | 		if !c.NextArg() {
 | 
					
						
							|  |  |  | 			return c.ArgErr()
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		dur, err := time.ParseDuration(c.Val())
 | 
					
						
							|  |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			return err
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		if dur < 0 {
 | 
					
						
							|  |  |  | 			return fmt.Errorf("expire can't be negative: %s", dur)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		f.expire = dur
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 	case "policy":
 | 
					
						
							|  |  |  | 		if !c.NextArg() {
 | 
					
						
							|  |  |  | 			return c.ArgErr()
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		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)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2020-02-04 07:59:08 -05:00
										 |  |  | 	case "max_concurrent":
 | 
					
						
							|  |  |  | 		if !c.NextArg() {
 | 
					
						
							|  |  |  | 			return c.ArgErr()
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		n, err := strconv.Atoi(c.Val())
 | 
					
						
							|  |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			return err
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2021-11-12 13:19:16 -05:00
										 |  |  | 		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)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 22:00:47 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	default:
 | 
					
						
							|  |  |  | 		return c.Errf("unknown property '%s'", c.Val())
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const max = 15 // Maximum number of upstreams.
 |