aboutsummaryrefslogtreecommitdiff
path: root/plugin/pkg/parse
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/pkg/parse')
-rw-r--r--plugin/pkg/parse/host.go98
-rw-r--r--plugin/pkg/parse/host_test.go87
-rw-r--r--plugin/pkg/parse/parse.go7
-rw-r--r--plugin/pkg/parse/transport.go33
-rw-r--r--plugin/pkg/parse/transport_test.go25
5 files changed, 247 insertions, 3 deletions
diff --git a/plugin/pkg/parse/host.go b/plugin/pkg/parse/host.go
new file mode 100644
index 000000000..87177125f
--- /dev/null
+++ b/plugin/pkg/parse/host.go
@@ -0,0 +1,98 @@
+package parse
+
+import (
+ "fmt"
+ "net"
+ "os"
+
+ "github.com/coredns/coredns/plugin/pkg/transport"
+
+ "github.com/miekg/dns"
+)
+
+// HostPortOrFile parses the strings in s, each string can either be a
+// 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.
+func HostPortOrFile(s ...string) ([]string, error) {
+ var servers []string
+ for _, h := range s {
+
+ trans, host := Transport(h)
+
+ addr, _, err := net.SplitHostPort(host)
+ if err != nil {
+ // Parse didn't work, it is not a addr:port combo
+ if net.ParseIP(host) == nil {
+ // Not an IP address.
+ ss, err := tryFile(host)
+ if err == nil {
+ servers = append(servers, ss...)
+ continue
+ }
+ return servers, fmt.Errorf("not an IP address or file: %q", host)
+ }
+ var ss string
+ switch trans {
+ case transport.DNS:
+ ss = net.JoinHostPort(host, transport.Port)
+ 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)
+ }
+ servers = append(servers, ss)
+ continue
+ }
+
+ if net.ParseIP(addr) == nil {
+ // Not an IP address.
+ ss, err := tryFile(host)
+ if err == nil {
+ servers = append(servers, ss...)
+ continue
+ }
+ return servers, fmt.Errorf("not an IP address or file: %q", host)
+ }
+ servers = append(servers, h)
+ }
+ 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
+}
+
+// HostPort will check if the host part is a valid IP address, if the
+// IP address is valid, but no port is found, defaultPort is added.
+func HostPort(s, defaultPort string) (string, error) {
+ 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
+}
diff --git a/plugin/pkg/parse/host_test.go b/plugin/pkg/parse/host_test.go
new file mode 100644
index 000000000..f6e771f29
--- /dev/null
+++ b/plugin/pkg/parse/host_test.go
@@ -0,0 +1,87 @@
+package parse
+
+import (
+ "io/ioutil"
+ "os"
+ "testing"
+
+ "github.com/coredns/coredns/plugin/pkg/transport"
+)
+
+func TestHostPortOrFile(t *testing.T) {
+ tests := []struct {
+ in string
+ expected string
+ shouldErr bool
+ }{
+ {
+ "8.8.8.8",
+ "8.8.8.8:53",
+ false,
+ },
+ {
+ "8.8.8.8:153",
+ "8.8.8.8:153",
+ false,
+ },
+ {
+ "/etc/resolv.conf:53",
+ "",
+ true,
+ },
+ {
+ "resolv.conf",
+ "127.0.0.1:53",
+ false,
+ },
+ }
+
+ err := ioutil.WriteFile("resolv.conf", []byte("nameserver 127.0.0.1\n"), 0600)
+ if err != nil {
+ t.Fatalf("Failed to write test resolv.conf")
+ }
+ defer os.Remove("resolv.conf")
+
+ for i, tc := range tests {
+ got, err := HostPortOrFile(tc.in)
+ if err == nil && tc.shouldErr {
+ t.Errorf("Test %d, expected error, got nil", i)
+ continue
+ }
+ if err != nil && tc.shouldErr {
+ continue
+ }
+ if got[0] != tc.expected {
+ t.Errorf("Test %d, expected %q, got %q", i, tc.expected, got[0])
+ }
+ }
+}
+
+func TestParseHostPort(t *testing.T) {
+ tests := []struct {
+ in string
+ expected string
+ shouldErr bool
+ }{
+ {"8.8.8.8:53", "8.8.8.8:53", false},
+ {"a.a.a.a:153", "", true},
+ {"8.8.8.8", "8.8.8.8:53", false},
+ {"8.8.8.8:", "8.8.8.8:53", false},
+ {"8.8.8.8::53", "", true},
+ {"resolv.conf", "", true},
+ }
+
+ for i, tc := range tests {
+ got, err := HostPort(tc.in, transport.Port)
+ if err == nil && tc.shouldErr {
+ t.Errorf("Test %d, expected error, got nil", i)
+ continue
+ }
+ if err != nil && !tc.shouldErr {
+ t.Errorf("Test %d, expected no error, got %q", i, err)
+ }
+ if got != tc.expected {
+ t.Errorf("Test %d, expected %q, got %q", i, tc.expected, got)
+ }
+ }
+}
diff --git a/plugin/pkg/parse/parse.go b/plugin/pkg/parse/parse.go
index 17d2641ef..17fe75fb0 100644
--- a/plugin/pkg/parse/parse.go
+++ b/plugin/pkg/parse/parse.go
@@ -4,7 +4,8 @@ package parse
import (
"fmt"
- "github.com/coredns/coredns/plugin/pkg/dnsutil"
+ "github.com/coredns/coredns/plugin/pkg/transport"
+
"github.com/mholt/caddy"
)
@@ -19,7 +20,7 @@ func Transfer(c *caddy.Controller, secondary bool) (tos, froms []string, err err
tos = c.RemainingArgs()
for i := range tos {
if tos[i] != "*" {
- normalized, err := dnsutil.ParseHostPort(tos[i], "53")
+ normalized, err := HostPort(tos[i], transport.Port)
if err != nil {
return nil, nil, err
}
@@ -34,7 +35,7 @@ func Transfer(c *caddy.Controller, secondary bool) (tos, froms []string, err err
froms = c.RemainingArgs()
for i := range froms {
if froms[i] != "*" {
- normalized, err := dnsutil.ParseHostPort(froms[i], "53")
+ normalized, err := HostPort(froms[i], transport.Port)
if err != nil {
return nil, nil, err
}
diff --git a/plugin/pkg/parse/transport.go b/plugin/pkg/parse/transport.go
new file mode 100644
index 000000000..d632120d7
--- /dev/null
+++ b/plugin/pkg/parse/transport.go
@@ -0,0 +1,33 @@
+package parse
+
+import (
+ "strings"
+
+ "github.com/coredns/coredns/plugin/pkg/transport"
+)
+
+// Transport returns the transport defined in s and a string where the
+// transport prefix is removed (if there was any). If no transport is defined
+// we default to TransportDNS
+func Transport(s string) (trans string, addr string) {
+ switch {
+ case strings.HasPrefix(s, transport.TLS+"://"):
+ s = s[len(transport.TLS+"://"):]
+ return transport.TLS, s
+
+ case strings.HasPrefix(s, transport.DNS+"://"):
+ s = s[len(transport.DNS+"://"):]
+ return transport.DNS, s
+
+ case strings.HasPrefix(s, transport.GRPC+"://"):
+ s = s[len(transport.GRPC+"://"):]
+ return transport.GRPC, s
+
+ case strings.HasPrefix(s, transport.HTTPS+"://"):
+ s = s[len(transport.HTTPS+"://"):]
+
+ return transport.HTTPS, s
+ }
+
+ return transport.DNS, s
+}
diff --git a/plugin/pkg/parse/transport_test.go b/plugin/pkg/parse/transport_test.go
new file mode 100644
index 000000000..d0e0fcddd
--- /dev/null
+++ b/plugin/pkg/parse/transport_test.go
@@ -0,0 +1,25 @@
+package parse
+
+import (
+ "testing"
+
+ "github.com/coredns/coredns/plugin/pkg/transport"
+)
+
+func TestTransport(t *testing.T) {
+ for i, test := range []struct {
+ input string
+ expected string
+ }{
+ {"dns://.:53", transport.DNS},
+ {"2003::1/64.:53", transport.DNS},
+ {"grpc://example.org:1443 ", transport.GRPC},
+ {"tls://example.org ", transport.TLS},
+ {"https://example.org ", transport.HTTPS},
+ } {
+ actual, _ := Transport(test.input)
+ if actual != test.expected {
+ t.Errorf("Test %d: Expected %s but got %s", i, test.expected, actual)
+ }
+ }
+}