diff options
author | 2016-10-22 10:52:10 -0400 | |
---|---|---|
committer | 2016-10-22 15:52:10 +0100 | |
commit | 6d9d60081d7a9eef14ad90d62533de89f88ea434 (patch) | |
tree | a9f8bb7b5d164dad21150ab9778395ae3fe421eb | |
parent | a2bd9ad3f548550bed6b3f8c5d21c30373454da9 (diff) | |
download | coredns-6d9d60081d7a9eef14ad90d62533de89f88ea434.tar.gz coredns-6d9d60081d7a9eef14ad90d62533de89f88ea434.tar.zst coredns-6d9d60081d7a9eef14ad90d62533de89f88ea434.zip |
Add option to parse resolv.conf for proxy upstreams (#353)
* Add option to parse resolv.conf for proxy upstreams
* Add test and README update for resolv.conf proxy
* Run gofmt
-rw-r--r-- | middleware/proxy/README.md | 10 | ||||
-rw-r--r-- | middleware/proxy/upstream.go | 21 | ||||
-rw-r--r-- | middleware/proxy/upstream_test.go | 98 |
3 files changed, 125 insertions, 4 deletions
diff --git a/middleware/proxy/README.md b/middleware/proxy/README.md index f621781d1..ab530a0a9 100644 --- a/middleware/proxy/README.md +++ b/middleware/proxy/README.md @@ -30,7 +30,7 @@ proxy FROM TO... { ~~~ * **FROM** is the name to match for the request to be proxied. -* **TO** is the destination endpoint to proxy to. At least one is required, but multiple may be specified. +* **TO** is the destination endpoint to proxy to. At least one is required, but multiple may be specified. To may be an IP:Port pair, or may reference a file in resolv.conf format * `policy` is the load balancing policy to use; applies only with multiple backends. May be one of random, least_conn, or round_robin. Default is random. * `fail_timeout` specifies how long to consider a backend as down after it has failed. While it is down, requests will not be routed to that backend. A backend is "down" if CoreDNS fails to communicate with it. The default value is 10 seconds ("10s"). * `max_fails` is the number of failures within fail_timeout that are needed before considering a backend to be down. If 0, the backend will never be marked as down. Default is 1. @@ -86,3 +86,11 @@ proxy . backend:1234 { except miek.nl example.org } ~~~ + +Proxy everything except example.org using the host resolv.conf nameservers: + +~~~ +proxy . /etc/resolv.conf { + except miek.nl example.org +} +~~~ diff --git a/middleware/proxy/upstream.go b/middleware/proxy/upstream.go index 1571486e5..02575d1a9 100644 --- a/middleware/proxy/upstream.go +++ b/middleware/proxy/upstream.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "net" "net/http" + "os" "strconv" "strings" "sync/atomic" @@ -65,13 +66,27 @@ func NewStaticUpstreams(c *caddyfile.Dispenser) ([]Upstream, error) { if len(to) == 0 { return upstreams, c.ArgErr() } + + // process the host list, substituting in any nameservers in files + var toHosts []string for _, host := range to { h, _, err := net.SplitHostPort(host) if err != nil { h = host } if x := net.ParseIP(h); x == nil { - return upstreams, fmt.Errorf("not an IP address: `%s'", h) + // it's a file, parse as resolv.conf + c, err := dns.ClientConfigFromFile(host) + if err == os.ErrNotExist { + return upstreams, fmt.Errorf("not an IP address or file: `%s'", h) + } else if err != nil { + return upstreams, err + } + for _, s := range c.Servers { + toHosts = append(toHosts, net.JoinHostPort(s, c.Port)) + } + } else { + toHosts = append(toHosts, host) } } @@ -81,8 +96,8 @@ func NewStaticUpstreams(c *caddyfile.Dispenser) ([]Upstream, error) { } } - upstream.Hosts = make([]*UpstreamHost, len(to)) - for i, host := range to { + upstream.Hosts = make([]*UpstreamHost, len(toHosts)) + for i, host := range toHosts { uh := &UpstreamHost{ Name: defaultHostPort(host), Conns: 0, diff --git a/middleware/proxy/upstream_test.go b/middleware/proxy/upstream_test.go index c48b4446b..bbc51f59a 100644 --- a/middleware/proxy/upstream_test.go +++ b/middleware/proxy/upstream_test.go @@ -1,6 +1,10 @@ package proxy import ( + "io/ioutil" + "os" + "path/filepath" + "strings" "testing" "time" @@ -78,6 +82,19 @@ func TestAllowedPaths(t *testing.T) { } } +func writeTmpFile(t *testing.T, data string) (string, string) { + tempDir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("tempDir: %v", err) + } + + path := filepath.Join(tempDir, "resolv.conf") + if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil { + t.Fatalf("writeFile: %v", err) + } + return tempDir, path +} + func TestProxyParse(t *testing.T) { tests := []struct { inputUpstreams string @@ -143,6 +160,11 @@ proxy . 8.8.8.8:53 { }`, true, }, + { + ` +proxy . some_bogus_filename`, + true, + }, } for i, test := range tests { c := caddy.NewTestController("dns", test.inputUpstreams) @@ -152,3 +174,79 @@ proxy . 8.8.8.8:53 { } } } + +func TestResolvParse(t *testing.T) { + tests := []struct { + inputUpstreams string + filedata string + shouldErr bool + expected []string + }{ + { + ` +proxy . FILE +`, + ` +nameserver 1.2.3.4 +nameserver 4.3.2.1 +`, + false, + []string{"1.2.3.4:53", "4.3.2.1:53"}, + }, + { + ` +proxy example.com 1.1.1.1:5000 +proxy . FILE +proxy example.org 2.2.2.2:1234 +`, + ` +nameserver 1.2.3.4 +`, + false, + []string{"1.1.1.1:5000", "1.2.3.4:53", "2.2.2.2:1234"}, + }, + { + ` +proxy example.com 1.1.1.1:5000 +proxy . FILE +proxy example.org 2.2.2.2:1234 +`, + ` +junky resolve.conf +`, + false, + []string{"1.1.1.1:5000", "2.2.2.2:1234"}, + }, + } + for i, test := range tests { + tempDir, path := writeTmpFile(t, test.filedata) + defer os.RemoveAll(tempDir) + config := strings.Replace(test.inputUpstreams, "FILE", path, -1) + c := caddy.NewTestController("dns", config) + upstreams, err := NewStaticUpstreams(&c.Dispenser) + if (err != nil) != test.shouldErr { + t.Errorf("Test %d expected no error, got %v", i+1, err) + } + var hosts []string + for _, u := range upstreams { + for _, h := range u.(*staticUpstream).Hosts { + hosts = append(hosts, h.Name) + } + } + if !test.shouldErr { + if len(hosts) != len(test.expected) { + t.Errorf("Test %d expected %d hosts got %d", i+1, len(test.expected), len(upstreams)) + } else { + ok := true + for i, v := range test.expected { + if v != hosts[i] { + ok = false + } + } + if !ok { + t.Errorf("Test %d expected %v got %v", i+1, test.expected, upstreams) + } + } + } + } +} |