| 
									
										
										
										
											2018-09-19 08:16:04 +01:00
										 |  |  | package parse
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2021-12-23 18:02:28 +01:00
										 |  |  | 	"errors"
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 	"fmt"
 | 
					
						
							|  |  |  | 	"net"
 | 
					
						
							|  |  |  | 	"os"
 | 
					
						
							| 
									
										
										
										
											2020-01-16 14:47:39 -05:00
										 |  |  | 	"strings"
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 07:29:37 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/transport"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 	"github.com/miekg/dns"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-23 18:02:28 +01:00
										 |  |  | // ErrNoNameservers is returned by HostPortOrFile if no servers can be parsed.
 | 
					
						
							|  |  |  | var ErrNoNameservers = errors.New("no nameservers found")
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 14:47:39 -05:00
										 |  |  | // Strips the zone, but preserves any port that comes after the zone
 | 
					
						
							|  |  |  | func stripZone(host string) string {
 | 
					
						
							|  |  |  | 	if strings.Contains(host, "%") {
 | 
					
						
							|  |  |  | 		lastPercent := strings.LastIndex(host, "%")
 | 
					
						
							|  |  |  | 		newHost := host[:lastPercent]
 | 
					
						
							|  |  |  | 		return newHost
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return host
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:16:04 +01:00
										 |  |  | // HostPortOrFile parses the strings in s, each string can either be a
 | 
					
						
							| 
									
										
										
										
											2018-09-19 07:29:37 +01:00
										 |  |  | // address, [scheme://]address:port or a filename. The address part is checked
 | 
					
						
							|  |  |  | // and in case of filename a resolv.conf like file is (assumed) and parsed and
 | 
					
						
							|  |  |  | // the nameservers found are returned.
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:16:04 +01:00
										 |  |  | func HostPortOrFile(s ...string) ([]string, error) {
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 	var servers []string
 | 
					
						
							| 
									
										
										
										
											2018-09-19 07:29:37 +01:00
										 |  |  | 	for _, h := range s {
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:16:04 +01:00
										 |  |  | 		trans, host := Transport(h)
 | 
					
						
							| 
									
										
										
										
											2018-09-19 07:29:37 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 		addr, _, err := net.SplitHostPort(host)
 | 
					
						
							| 
									
										
										
										
											2020-01-16 14:47:39 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			// Parse didn't work, it is not a addr:port combo
 | 
					
						
							| 
									
										
										
										
											2020-01-16 14:47:39 -05:00
										 |  |  | 			hostNoZone := stripZone(host)
 | 
					
						
							|  |  |  | 			if net.ParseIP(hostNoZone) == nil {
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 				ss, err := tryFile(host)
 | 
					
						
							|  |  |  | 				if err == nil {
 | 
					
						
							|  |  |  | 					servers = append(servers, ss...)
 | 
					
						
							|  |  |  | 					continue
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 				return servers, fmt.Errorf("not an IP address or file: %q", host)
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2018-09-19 07:29:37 +01:00
										 |  |  | 			var ss string
 | 
					
						
							|  |  |  | 			switch trans {
 | 
					
						
							|  |  |  | 			case transport.DNS:
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:16:04 +01:00
										 |  |  | 				ss = net.JoinHostPort(host, transport.Port)
 | 
					
						
							| 
									
										
										
										
											2018-09-19 07:29:37 +01:00
										 |  |  | 			case transport.TLS:
 | 
					
						
							|  |  |  | 				ss = transport.TLS + "://" + net.JoinHostPort(host, transport.TLSPort)
 | 
					
						
							|  |  |  | 			case transport.GRPC:
 | 
					
						
							|  |  |  | 				ss = transport.GRPC + "://" + net.JoinHostPort(host, transport.GRPCPort)
 | 
					
						
							|  |  |  | 			case transport.HTTPS:
 | 
					
						
							|  |  |  | 				ss = transport.HTTPS + "://" + net.JoinHostPort(host, transport.HTTPSPort)
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 			servers = append(servers, ss)
 | 
					
						
							|  |  |  | 			continue
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 14:47:39 -05:00
										 |  |  | 		if net.ParseIP(stripZone(addr)) == nil {
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 			ss, err := tryFile(host)
 | 
					
						
							|  |  |  | 			if err == nil {
 | 
					
						
							|  |  |  | 				servers = append(servers, ss...)
 | 
					
						
							|  |  |  | 				continue
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 			return servers, fmt.Errorf("not an IP address or file: %q", host)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2018-09-19 07:29:37 +01:00
										 |  |  | 		servers = append(servers, h)
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2020-03-13 14:23:10 +01:00
										 |  |  | 	if len(servers) == 0 {
 | 
					
						
							| 
									
										
										
										
											2021-12-23 18:02:28 +01:00
										 |  |  | 		return servers, ErrNoNameservers
 | 
					
						
							| 
									
										
										
										
											2020-03-13 14:23:10 +01:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 	return servers, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Try to open this is a file first.
 | 
					
						
							|  |  |  | func tryFile(s string) ([]string, error) {
 | 
					
						
							|  |  |  | 	c, err := dns.ClientConfigFromFile(s)
 | 
					
						
							|  |  |  | 	if err == os.ErrNotExist {
 | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("failed to open file %q: %q", s, err)
 | 
					
						
							|  |  |  | 	} else if err != nil {
 | 
					
						
							|  |  |  | 		return nil, err
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	servers := []string{}
 | 
					
						
							|  |  |  | 	for _, s := range c.Servers {
 | 
					
						
							|  |  |  | 		servers = append(servers, net.JoinHostPort(s, c.Port))
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return servers, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:16:04 +01:00
										 |  |  | // HostPort will check if the host part is a valid IP address, if the
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | // IP address is valid, but no port is found, defaultPort is added.
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:16:04 +01:00
										 |  |  | func HostPort(s, defaultPort string) (string, error) {
 | 
					
						
							| 
									
										
										
										
											2016-11-24 16:57:20 +01:00
										 |  |  | 	addr, port, err := net.SplitHostPort(s)
 | 
					
						
							|  |  |  | 	if port == "" {
 | 
					
						
							|  |  |  | 		port = defaultPort
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		if net.ParseIP(s) == nil {
 | 
					
						
							|  |  |  | 			return "", fmt.Errorf("must specify an IP address: `%s'", s)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		return net.JoinHostPort(s, port), nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if net.ParseIP(addr) == nil {
 | 
					
						
							|  |  |  | 		return "", fmt.Errorf("must specify an IP address: `%s'", addr)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return net.JoinHostPort(addr, port), nil
 | 
					
						
							|  |  |  | }
 |