aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Ondřej Benkovský <ondrej.benkovsky@jamf.com> 2022-01-07 17:16:23 +0100
committerGravatar GitHub <noreply@github.com> 2022-01-07 11:16:23 -0500
commitb546031f9b9507d01bf7d91889011f10e67c0bba (patch)
treed9944b7cdcff0bceb2c7ee8f450038d4b3483b7d
parent39a99a5bbe363a921dc3307c8b49876d12d538f7 (diff)
downloadcoredns-b546031f9b9507d01bf7d91889011f10e67c0bba.tar.gz
coredns-b546031f9b9507d01bf7d91889011f10e67c0bba.tar.zst
coredns-b546031f9b9507d01bf7d91889011f10e67c0bba.zip
plugin/dns64 : add support for DNS requests over IPv4 network (#4809)
-rw-r--r--plugin/dns64/README.md15
-rw-r--r--plugin/dns64/dns64.go13
-rw-r--r--plugin/dns64/dns64_test.go52
-rw-r--r--plugin/dns64/setup.go2
-rw-r--r--plugin/dns64/setup_test.go33
5 files changed, 106 insertions, 9 deletions
diff --git a/plugin/dns64/README.md b/plugin/dns64/README.md
index 65a338b63..c3f4d9680 100644
--- a/plugin/dns64/README.md
+++ b/plugin/dns64/README.md
@@ -27,11 +27,13 @@ Or use this slightly longer form with more options:
dns64 [PREFIX] {
[translate_all]
prefix PREFIX
+ [allow_ipv4]
}
~~~
* `prefix` specifies any local IPv6 prefix to use, instead of the well known prefix (64:ff9b::/96)
* `translate_all` translates all queries, including responses that have AAAA results.
+* `allow_ipv4` Allow translating queries if they come in over IPv4, default is IPv6 only translation.
## Examples
@@ -70,6 +72,19 @@ Enable translation even if an existing AAAA record is present.
}
~~~
+Apply translation even to the requests which arrived over IPv4 network. Warning, the `allow_ipv4` feature will apply
+translations to requests coming from dual-stack clients. This means that a request for a client that sends an `AAAA`
+that would normal result in an `NXDOMAIN` would get a translated result.
+This may cause unwanted IPv6 dns64 traffic when a dualstack client would normally use the result of an `A` record request.
+
+~~~ corefile
+. {
+ dns64 {
+ allow_ipv4
+ }
+}
+~~~
+
## Metrics
If monitoring is enabled (via the _prometheus_ plugin) then the following metrics are exported:
diff --git a/plugin/dns64/dns64.go b/plugin/dns64/dns64.go
index b06b0bdb9..110bfeadd 100644
--- a/plugin/dns64/dns64.go
+++ b/plugin/dns64/dns64.go
@@ -28,13 +28,14 @@ type DNS64 struct {
Next plugin.Handler
Prefix *net.IPNet
TranslateAll bool // Not comply with 5.1.1
+ AllowIPv4 bool
Upstream UpstreamInt
}
// ServeDNS implements the plugin.Handler interface.
func (d *DNS64) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
// Don't proxy if we don't need to.
- if !requestShouldIntercept(&request.Request{W: w, Req: r}) {
+ if !d.requestShouldIntercept(&request.Request{W: w, Req: r}) {
return d.Next.ServeDNS(ctx, w, r)
}
@@ -69,13 +70,13 @@ func (d *DNS64) Name() string { return "dns64" }
// requestShouldIntercept returns true if the request represents one that is eligible
// for DNS64 rewriting:
-// 1. The request came in over IPv6 (not in RFC)
+// 1. The request came in over IPv6 or the 'allow_ipv4' option is set
// 2. The request is of type AAAA
// 3. The request is of class INET
-func requestShouldIntercept(req *request.Request) bool {
- // Only intercept with this when the request came in over IPv6. This is not mentioned in the RFC.
- // File an issue if you think we should translate even requests made using IPv4, or have a configuration flag
- if req.Family() == 1 { // If it came in over v4, don't do anything.
+func (d *DNS64) requestShouldIntercept(req *request.Request) bool {
+ // Make sure that request came in over IPv4 unless AllowIPv4 option is enabled.
+ // Translating requests without taking into consideration client (source) IP might be problematic in dual-stack networks.
+ if !d.AllowIPv4 && req.Family() == 1 {
return false
}
diff --git a/plugin/dns64/dns64_test.go b/plugin/dns64/dns64_test.go
index d7f9fdade..de7ab65a8 100644
--- a/plugin/dns64/dns64_test.go
+++ b/plugin/dns64/dns64_test.go
@@ -21,6 +21,58 @@ func To6(prefix, address string) (net.IP, error) {
return to6(pref, addr)
}
+func TestRequestShouldIntercept(t *testing.T) {
+ tests := []struct {
+ name string
+ allowIpv4 bool
+ remoteIP string
+ msg *dns.Msg
+ want bool
+ }{
+ {
+ name: "should intercept request from IPv6 network - AAAA - IN",
+ allowIpv4: true,
+ remoteIP: "::1",
+ msg: new(dns.Msg).SetQuestion("example.com", dns.TypeAAAA),
+ want: true,
+ },
+ {
+ name: "should intercept request from IPv4 network - AAAA - IN",
+ allowIpv4: true,
+ remoteIP: "127.0.0.1",
+ msg: new(dns.Msg).SetQuestion("example.com", dns.TypeAAAA),
+ want: true,
+ },
+ {
+ name: "should not intercept request from IPv4 network - AAAA - IN",
+ allowIpv4: false,
+ remoteIP: "127.0.0.1",
+ msg: new(dns.Msg).SetQuestion("example.com", dns.TypeAAAA),
+ want: false,
+ },
+ {
+ name: "should not intercept request from IPv6 network - A - IN",
+ allowIpv4: false,
+ remoteIP: "::1",
+ msg: new(dns.Msg).SetQuestion("example.com", dns.TypeA),
+ want: false,
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ h := DNS64{AllowIPv4: tc.allowIpv4}
+ rec := dnstest.NewRecorder(&test.ResponseWriter{RemoteIP: tc.remoteIP})
+ r := request.Request{W: rec, Req: tc.msg}
+
+ actual := h.requestShouldIntercept(&r)
+
+ if actual != tc.want {
+ t.Fatalf("Expected %v, but got %v", tc.want, actual)
+ }
+ })
+ }
+}
+
func TestTo6(t *testing.T) {
v6, err := To6("64:ff9b::/96", "64.64.64.64")
diff --git a/plugin/dns64/setup.go b/plugin/dns64/setup.go
index 0c53fab4b..134a12a65 100644
--- a/plugin/dns64/setup.go
+++ b/plugin/dns64/setup.go
@@ -66,6 +66,8 @@ func dns64Parse(c *caddy.Controller) (*DNS64, error) {
dns64.Prefix = pref
case "translate_all":
dns64.TranslateAll = true
+ case "allow_ipv4":
+ dns64.AllowIPv4 = true
default:
return nil, c.Errf("unknown property '%s'", c.Val())
}
diff --git a/plugin/dns64/setup_test.go b/plugin/dns64/setup_test.go
index 3b4a4fe0e..e7d13f418 100644
--- a/plugin/dns64/setup_test.go
+++ b/plugin/dns64/setup_test.go
@@ -10,17 +10,20 @@ func TestSetupDns64(t *testing.T) {
tests := []struct {
inputUpstreams string
shouldErr bool
- prefix string
+ wantPrefix string
+ wantAllowIpv4 bool
}{
{
`dns64`,
false,
"64:ff9b::/96",
+ false,
},
{
`dns64 64:dead::/96`,
false,
"64:dead::/96",
+ false,
},
{
`dns64 {
@@ -28,11 +31,13 @@ func TestSetupDns64(t *testing.T) {
}`,
false,
"64:ff9b::/96",
+ false,
},
{
`dns64`,
false,
"64:ff9b::/96",
+ false,
},
{
`dns64 {
@@ -40,6 +45,7 @@ func TestSetupDns64(t *testing.T) {
}`,
false,
"64:ff9b::/96",
+ false,
},
{
`dns64 {
@@ -47,6 +53,7 @@ func TestSetupDns64(t *testing.T) {
}`,
false,
"64:ff9b::/32",
+ false,
},
{
`dns64 {
@@ -54,6 +61,7 @@ func TestSetupDns64(t *testing.T) {
}`,
true,
"64:ff9b::/52",
+ false,
},
{
`dns64 {
@@ -61,6 +69,7 @@ func TestSetupDns64(t *testing.T) {
}`,
true,
"64:ff9b::/104",
+ false,
},
{
`dns64 {
@@ -68,6 +77,7 @@ func TestSetupDns64(t *testing.T) {
}`,
true,
"8.8.9.9/24",
+ false,
},
{
`dns64 {
@@ -75,6 +85,7 @@ func TestSetupDns64(t *testing.T) {
}`,
false,
"64:ff9b::/96",
+ false,
},
{
`dns64 {
@@ -82,6 +93,7 @@ func TestSetupDns64(t *testing.T) {
}`,
false,
"2002:ac12:b083::/96",
+ false,
},
{
`dns64 {
@@ -89,6 +101,7 @@ func TestSetupDns64(t *testing.T) {
}`,
false,
"2002:c0a8:a88a::/48",
+ false,
},
{
`dns64 foobar {
@@ -96,11 +109,13 @@ func TestSetupDns64(t *testing.T) {
}`,
true,
"64:ff9b::/96",
+ false,
},
{
`dns64 foobar`,
true,
"64:ff9b::/96",
+ false,
},
{
`dns64 {
@@ -108,6 +123,15 @@ func TestSetupDns64(t *testing.T) {
}`,
true,
"64:ff9b::/96",
+ false,
+ },
+ {
+ `dns64 {
+ allow_ipv4
+ }`,
+ false,
+ "64:ff9b::/96",
+ true,
},
}
@@ -118,8 +142,11 @@ func TestSetupDns64(t *testing.T) {
t.Errorf("Test %d expected %v error, got %v for %s", i+1, test.shouldErr, err, test.inputUpstreams)
}
if err == nil {
- if dns64.Prefix.String() != test.prefix {
- t.Errorf("Test %d expected prefix %s, got %v", i+1, test.prefix, dns64.Prefix.String())
+ if dns64.Prefix.String() != test.wantPrefix {
+ t.Errorf("Test %d expected prefix %s, got %v", i+1, test.wantPrefix, dns64.Prefix.String())
+ }
+ if dns64.AllowIPv4 != test.wantAllowIpv4 {
+ t.Errorf("Test %d expected prefix %v, got %v", i+1, test.wantAllowIpv4, dns64.AllowIPv4)
}
}
}