plugin/dns64 : add support for DNS requests over IPv4 network (#4809)
This commit is contained in:
parent
39a99a5bbe
commit
b546031f9b
5 changed files with 106 additions and 9 deletions
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue