| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | package loadbalance
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 	"errors"
 | 
					
						
							| 
									
										
										
										
											2018-07-06 22:49:21 +01:00
										 |  |  | 	"fmt"
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 	"net"
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 	"path/filepath"
 | 
					
						
							|  |  |  | 	"time"
 | 
					
						
							| 
									
										
										
										
											2018-07-06 22:49:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-24 18:14:41 +02:00
										 |  |  | 	"github.com/coredns/caddy"
 | 
					
						
							| 
									
										
										
										
											2017-02-21 22:51:47 -08:00
										 |  |  | 	"github.com/coredns/coredns/core/dnsserver"
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin"
 | 
					
						
							| 
									
										
										
										
											2018-04-22 21:40:33 +01:00
										 |  |  | 	clog "github.com/coredns/coredns/plugin/pkg/log"
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/miekg/dns"
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-22 21:40:33 +01:00
										 |  |  | var log = clog.NewWithPlugin("loadbalance")
 | 
					
						
							| 
									
										
										
										
											2025-04-04 20:27:39 +02:00
										 |  |  | var errOpen = errors.New("weight file open error")
 | 
					
						
							| 
									
										
										
										
											2018-04-22 21:40:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-20 08:02:30 +01:00
										 |  |  | func init() { plugin.Register("loadbalance", setup) }
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | type lbFuncs struct {
 | 
					
						
							|  |  |  | 	shuffleFunc    func(*dns.Msg) *dns.Msg
 | 
					
						
							|  |  |  | 	onStartUpFunc  func() error
 | 
					
						
							|  |  |  | 	onShutdownFunc func() error
 | 
					
						
							|  |  |  | 	weighted       *weightedRR // used in unit tests only
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 	preferSubnets  []*net.IPNet
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | func setup(c *caddy.Controller) error {
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 	//shuffleFunc, startUpFunc, shutdownFunc, err := parse(c)
 | 
					
						
							|  |  |  | 	lb, err := parse(c)
 | 
					
						
							| 
									
										
										
										
											2018-07-06 22:49:21 +01:00
										 |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		return plugin.Error("loadbalance", err)
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 	if lb.onStartUpFunc != nil {
 | 
					
						
							|  |  |  | 		c.OnStartup(lb.onStartUpFunc)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	if lb.onShutdownFunc != nil {
 | 
					
						
							|  |  |  | 		c.OnShutdown(lb.onShutdownFunc)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 	shuffle := lb.shuffleFunc
 | 
					
						
							|  |  |  | 	if len(lb.preferSubnets) > 0 {
 | 
					
						
							|  |  |  | 		original := shuffle
 | 
					
						
							|  |  |  | 		shuffle = func(res *dns.Msg) *dns.Msg {
 | 
					
						
							|  |  |  | 			return reorderPreferredSubnets(original(res), lb.preferSubnets)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 	dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 		return LoadBalance{Next: next, shuffle: shuffle}
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	})
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2018-07-06 22:49:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | func parse(c *caddy.Controller) (*lbFuncs, error) {
 | 
					
						
							|  |  |  | 	config := dnsserver.GetConfig(c)
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 	lb := &lbFuncs{}
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-06 22:49:21 +01:00
										 |  |  | 	for c.Next() {
 | 
					
						
							|  |  |  | 		args := c.RemainingArgs()
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 		if len(args) == 0 {
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 			lb.shuffleFunc = randomShuffle
 | 
					
						
							|  |  |  | 		} else {
 | 
					
						
							|  |  |  | 			switch args[0] {
 | 
					
						
							|  |  |  | 			case ramdomShufflePolicy:
 | 
					
						
							|  |  |  | 				if len(args) > 1 {
 | 
					
						
							|  |  |  | 					return nil, c.Errf("unknown property for %s", args[0])
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 				lb.shuffleFunc = randomShuffle
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 			case weightedRoundRobinPolicy:
 | 
					
						
							|  |  |  | 				if len(args) < 2 {
 | 
					
						
							|  |  |  | 					return nil, c.Err("missing weight file argument")
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 				if len(args) > 2 {
 | 
					
						
							|  |  |  | 					return nil, c.Err("unexpected argument(s)")
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 				weightFileName := args[1]
 | 
					
						
							|  |  |  | 				if !filepath.IsAbs(weightFileName) && config.Root != "" {
 | 
					
						
							|  |  |  | 					weightFileName = filepath.Join(config.Root, weightFileName)
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 				reload := 30 * time.Second
 | 
					
						
							|  |  |  | 				for c.NextBlock() {
 | 
					
						
							|  |  |  | 					switch c.Val() {
 | 
					
						
							|  |  |  | 					case "reload":
 | 
					
						
							|  |  |  | 						t := c.RemainingArgs()
 | 
					
						
							|  |  |  | 						if len(t) < 1 {
 | 
					
						
							|  |  |  | 							return nil, c.Err("reload duration value is missing")
 | 
					
						
							|  |  |  | 						}
 | 
					
						
							|  |  |  | 						if len(t) > 1 {
 | 
					
						
							|  |  |  | 							return nil, c.Err("unexpected argument")
 | 
					
						
							|  |  |  | 						}
 | 
					
						
							|  |  |  | 						var err error
 | 
					
						
							|  |  |  | 						reload, err = time.ParseDuration(t[0])
 | 
					
						
							|  |  |  | 						if err != nil {
 | 
					
						
							|  |  |  | 							return nil, c.Errf("invalid reload duration '%s'", t[0])
 | 
					
						
							|  |  |  | 						}
 | 
					
						
							|  |  |  | 					default:
 | 
					
						
							|  |  |  | 						return nil, c.Errf("unknown property '%s'", c.Val())
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 				*lb = *createWeightedFuncs(weightFileName, reload)
 | 
					
						
							|  |  |  | 			default:
 | 
					
						
							|  |  |  | 				return nil, fmt.Errorf("unknown policy: %s", args[0])
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 		for c.NextBlock() {
 | 
					
						
							|  |  |  | 			switch c.Val() {
 | 
					
						
							|  |  |  | 			case "prefer":
 | 
					
						
							|  |  |  | 				cidrs := c.RemainingArgs()
 | 
					
						
							|  |  |  | 				for _, cidr := range cidrs {
 | 
					
						
							|  |  |  | 					_, subnet, err := net.ParseCIDR(cidr)
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 					if err != nil {
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 						return nil, c.Errf("invalid CIDR %q: %v", cidr, err)
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 					}
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 					lb.preferSubnets = append(lb.preferSubnets, subnet)
 | 
					
						
							| 
									
										
										
										
											2023-01-27 17:36:56 +01:00
										 |  |  | 				}
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 			default:
 | 
					
						
							|  |  |  | 				return nil, c.Errf("unknown property '%s'", c.Val())
 | 
					
						
							| 
									
										
										
										
											2018-07-06 22:49:21 +01:00
										 |  |  | 			}
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2025-08-05 20:34:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return lb, nil
 | 
					
						
							| 
									
										
										
										
											2018-07-06 22:49:21 +01:00
										 |  |  | }
 |