| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | package bind
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2021-03-25 20:08:17 +04:30
										 |  |  | 	"errors"
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	"fmt"
 | 
					
						
							|  |  |  | 	"net"
 | 
					
						
							| 
									
										
										
										
											2024-10-24 16:24:08 +02:00
										 |  |  | 	"slices"
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07: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"
 | 
					
						
							| 
									
										
										
										
											2022-03-18 10:11:53 -04:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/log"
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-28 19:56:14 -08:00
										 |  |  | func setup(c *caddy.Controller) error {
 | 
					
						
							| 
									
										
										
										
											2021-03-25 20:08:17 +04:30
										 |  |  | 	config := dnsserver.GetConfig(c)
 | 
					
						
							| 
									
										
										
										
											2018-02-14 14:19:32 -05:00
										 |  |  | 	// addresses will be consolidated over all BIND directives available in that BlocServer
 | 
					
						
							|  |  |  | 	all := []string{}
 | 
					
						
							| 
									
										
										
										
											2021-03-25 20:08:17 +04:30
										 |  |  | 	ifaces, err := net.Interfaces()
 | 
					
						
							|  |  |  | 	if err != nil {
 | 
					
						
							| 
									
										
										
										
											2022-03-18 10:11:53 -04:00
										 |  |  | 		log.Warning(plugin.Error("bind", fmt.Errorf("failed to get interfaces list, cannot bind by interface name: %s", err)))
 | 
					
						
							| 
									
										
										
										
											2021-03-25 20:08:17 +04:30
										 |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	for c.Next() {
 | 
					
						
							| 
									
										
										
										
											2021-03-25 20:08:17 +04:30
										 |  |  | 		b, err := parse(c)
 | 
					
						
							|  |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			return plugin.Error("bind", err)
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2021-03-18 10:08:48 +03:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-25 20:08:17 +04:30
										 |  |  | 		ips, err := listIP(b.addrs, ifaces)
 | 
					
						
							| 
									
										
										
										
											2021-03-18 10:08:48 +03:30
										 |  |  | 		if err != nil {
 | 
					
						
							| 
									
										
										
										
											2021-03-25 20:08:17 +04:30
										 |  |  | 			return plugin.Error("bind", err)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		except, err := listIP(b.except, ifaces)
 | 
					
						
							|  |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			return plugin.Error("bind", err)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for _, ip := range ips {
 | 
					
						
							| 
									
										
										
										
											2023-05-29 15:53:55 +08:00
										 |  |  | 			if !slices.Contains(except, ip) {
 | 
					
						
							| 
									
										
										
										
											2021-03-25 20:08:17 +04:30
										 |  |  | 				all = append(all, ip)
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	config.ListenHosts = all
 | 
					
						
							|  |  |  | 	return nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func parse(c *caddy.Controller) (*bind, error) {
 | 
					
						
							|  |  |  | 	b := &bind{}
 | 
					
						
							|  |  |  | 	b.addrs = c.RemainingArgs()
 | 
					
						
							|  |  |  | 	if len(b.addrs) == 0 {
 | 
					
						
							|  |  |  | 		return nil, errors.New("at least one address or interface name is expected")
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	for c.NextBlock() {
 | 
					
						
							|  |  |  | 		switch c.Val() {
 | 
					
						
							|  |  |  | 		case "except":
 | 
					
						
							|  |  |  | 			b.except = c.RemainingArgs()
 | 
					
						
							|  |  |  | 			if len(b.except) == 0 {
 | 
					
						
							|  |  |  | 				return nil, errors.New("at least one address or interface must be given to except subdirective")
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		default:
 | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("invalid option %q", c.Val())
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return b, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // listIP returns a list of IP addresses from a list of arguments which can be either IP-Address or Interface-Name.
 | 
					
						
							|  |  |  | func listIP(args []string, ifaces []net.Interface) ([]string, error) {
 | 
					
						
							|  |  |  | 	all := []string{}
 | 
					
						
							|  |  |  | 	var isIface bool
 | 
					
						
							|  |  |  | 	for _, a := range args {
 | 
					
						
							|  |  |  | 		isIface = false
 | 
					
						
							|  |  |  | 		for _, iface := range ifaces {
 | 
					
						
							|  |  |  | 			if a == iface.Name {
 | 
					
						
							|  |  |  | 				isIface = true
 | 
					
						
							|  |  |  | 				addrs, err := iface.Addrs()
 | 
					
						
							|  |  |  | 				if err != nil {
 | 
					
						
							|  |  |  | 					return nil, fmt.Errorf("failed to get the IP addresses of the interface: %q", a)
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 				for _, addr := range addrs {
 | 
					
						
							|  |  |  | 					if ipnet, ok := addr.(*net.IPNet); ok {
 | 
					
						
							| 
									
										
										
										
											2024-10-01 15:47:56 +00:00
										 |  |  | 						ipa, err := net.ResolveIPAddr("ip", ipnet.IP.String())
 | 
					
						
							|  |  |  | 						if err == nil {
 | 
					
						
							|  |  |  | 							if len(ipnet.IP) == net.IPv6len &&
 | 
					
						
							|  |  |  | 								(ipnet.IP.IsLinkLocalMulticast() || ipnet.IP.IsLinkLocalUnicast()) {
 | 
					
						
							|  |  |  | 								if ipa.Zone == "" {
 | 
					
						
							|  |  |  | 									ipa.Zone = iface.Name
 | 
					
						
							|  |  |  | 								}
 | 
					
						
							|  |  |  | 							}
 | 
					
						
							|  |  |  | 							all = append(all, ipa.String())
 | 
					
						
							| 
									
										
										
										
											2021-03-18 10:08:48 +03:30
										 |  |  | 						}
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2021-03-25 20:08:17 +04:30
										 |  |  | 		}
 | 
					
						
							|  |  |  | 		if !isIface {
 | 
					
						
							|  |  |  | 			if net.ParseIP(a) == nil {
 | 
					
						
							|  |  |  | 				return nil, fmt.Errorf("not a valid IP address or interface name: %q", a)
 | 
					
						
							| 
									
										
										
										
											2018-02-14 14:19:32 -05:00
										 |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2021-03-25 20:08:17 +04:30
										 |  |  | 			all = append(all, a)
 | 
					
						
							| 
									
										
										
										
											2018-02-14 14:19:32 -05:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2021-03-25 20:08:17 +04:30
										 |  |  | 	return all, nil
 | 
					
						
							|  |  |  | }
 |