From d7b2d63e4cc0d347e6ea272d6225c9b1dbb4f77f Mon Sep 17 00:00:00 2001
From: Eugene Burkov <e.burkov@adguard.com>
Date: Tue, 13 Apr 2021 16:23:36 +0300
Subject: [PATCH] Pull request: 1868 fix rdns

Merge in DNS/adguard-home from 1868-rdns-ipv6 to master

Updates #2943.
Updates #2704.

Squashed commit of the following:

commit 53d67ecf17ed4f9c544344288b58f3596c7246e2
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Apr 13 16:18:33 2021 +0300

    all: imp code, docs

commit 2bc15941b87f92b6fa0a7568538e02700a4385a3
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Apr 13 16:09:08 2021 +0300

    all: imp code
---
 internal/aghnet/subnetdetector.go      |  1 +
 internal/aghnet/subnetdetector_test.go |  8 ++++
 internal/dnsforward/clientid_test.go   |  2 +-
 internal/dnsforward/stats_test.go      |  4 +-
 internal/dnsforward/util_test.go       | 60 ++++++++++++++++++++++++++
 internal/home/rdns.go                  | 10 +++--
 internal/home/rdns_test.go             |  8 +++-
 7 files changed, 85 insertions(+), 8 deletions(-)
 create mode 100644 internal/dnsforward/util_test.go

diff --git a/internal/aghnet/subnetdetector.go b/internal/aghnet/subnetdetector.go
index e610929c..e353903b 100644
--- a/internal/aghnet/subnetdetector.go
+++ b/internal/aghnet/subnetdetector.go
@@ -100,6 +100,7 @@ func NewSubnetDetector() (snd *SubnetDetector, err error) {
 		"::1/128",
 		"fe80::/10",
 		"2001:db8::/32",
+		"fd00::/8",
 	}
 
 	snd = &SubnetDetector{
diff --git a/internal/aghnet/subnetdetector_test.go b/internal/aghnet/subnetdetector_test.go
index 8f2fa4b9..f4b7678c 100644
--- a/internal/aghnet/subnetdetector_test.go
+++ b/internal/aghnet/subnetdetector_test.go
@@ -205,6 +205,14 @@ func TestSubnetDetector_DetectLocallyServedNetwork(t *testing.T) {
 		name: "linked-scoped_unicast",
 		ip:   net.ParseIP("fe80::"),
 		want: true,
+	}, {
+		name: "locally_assigned",
+		ip:   net.ParseIP("fd00::1"),
+		want: true,
+	}, {
+		name: "not_locally_assigned",
+		ip:   net.ParseIP("fc00::1"),
+		want: false,
 	}}
 
 	for _, tc := range testCases {
diff --git a/internal/dnsforward/clientid_test.go b/internal/dnsforward/clientid_test.go
index 0d07bcf7..ef1d5648 100644
--- a/internal/dnsforward/clientid_test.go
+++ b/internal/dnsforward/clientid_test.go
@@ -16,7 +16,7 @@ import (
 // testTLSConn is a tlsConn for tests.
 type testTLSConn struct {
 	// Conn is embedded here simply to make testTLSConn a net.Conn without
-	// acctually implementing all methods.
+	// actually implementing all methods.
 	net.Conn
 
 	serverName string
diff --git a/internal/dnsforward/stats_test.go b/internal/dnsforward/stats_test.go
index 4eb2d3e5..fa9d422c 100644
--- a/internal/dnsforward/stats_test.go
+++ b/internal/dnsforward/stats_test.go
@@ -18,7 +18,7 @@ import (
 // testQueryLog is a simple querylog.QueryLog implementation for tests.
 type testQueryLog struct {
 	// QueryLog is embedded here simply to make testQueryLog
-	// a querylog.QueryLog without acctually implementing all methods.
+	// a querylog.QueryLog without actually implementing all methods.
 	querylog.QueryLog
 
 	lastParams querylog.AddParams
@@ -32,7 +32,7 @@ func (l *testQueryLog) Add(p querylog.AddParams) {
 // testStats is a simple stats.Stats implementation for tests.
 type testStats struct {
 	// Stats is embedded here simply to make testStats a stats.Stats without
-	// acctually implementing all methods.
+	// actually implementing all methods.
 	stats.Stats
 
 	lastEntry stats.Entry
diff --git a/internal/dnsforward/util_test.go b/internal/dnsforward/util_test.go
new file mode 100644
index 00000000..09cdf714
--- /dev/null
+++ b/internal/dnsforward/util_test.go
@@ -0,0 +1,60 @@
+package dnsforward
+
+import (
+	"net"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+// fakeAddr is a mock implementation of net.Addr interface to simplify testing.
+type fakeAddr struct {
+	// Addr is embedded here simply to make fakeAddr a net.Addr without
+	// actually implementing all methods.
+	net.Addr
+}
+
+func TestIPFromAddr(t *testing.T) {
+	supIPv4 := net.IP{1, 2, 3, 4}
+	supIPv6 := net.ParseIP("2a00:1450:400c:c06::93")
+
+	testCases := []struct {
+		name string
+		addr net.Addr
+		want net.IP
+	}{{
+		name: "ipv4_tcp",
+		addr: &net.TCPAddr{
+			IP: supIPv4,
+		},
+		want: supIPv4,
+	}, {
+		name: "ipv6_tcp",
+		addr: &net.TCPAddr{
+			IP: supIPv6,
+		},
+		want: supIPv6,
+	}, {
+		name: "ipv4_udp",
+		addr: &net.UDPAddr{
+			IP: supIPv4,
+		},
+		want: supIPv4,
+	}, {
+		name: "ipv6_udp",
+		addr: &net.UDPAddr{
+			IP: supIPv6,
+		},
+		want: supIPv6,
+	}, {
+		name: "non-ip_addr",
+		addr: &fakeAddr{},
+		want: nil,
+	}}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			assert.Equal(t, tc.want, IPFromAddr(tc.addr))
+		})
+	}
+}
diff --git a/internal/home/rdns.go b/internal/home/rdns.go
index a36b0f63..ea63eb83 100644
--- a/internal/home/rdns.go
+++ b/internal/home/rdns.go
@@ -95,10 +95,12 @@ func (r *RDNS) workerLoop() {
 			continue
 		}
 
-		if host != "" {
-			// Don't handle any errors since AddHost doesn't return non-nil
-			// errors for now.
-			_, _ = r.clients.AddHost(ip.String(), host, ClientSourceRDNS)
+		if host == "" {
+			continue
 		}
+
+		// Don't handle any errors since AddHost doesn't return non-nil
+		// errors for now.
+		_, _ = r.clients.AddHost(ip.String(), host, ClientSourceRDNS)
 	}
 }
diff --git a/internal/home/rdns_test.go b/internal/home/rdns_test.go
index 2779f173..ecc1a2bc 100644
--- a/internal/home/rdns_test.go
+++ b/internal/home/rdns_test.go
@@ -135,7 +135,8 @@ func TestRDNS_WorkerLoop(t *testing.T) {
 
 	locUpstream := &aghtest.TestUpstream{
 		Reverse: map[string][]string{
-			"192.168.1.1": {"local.domain"},
+			"192.168.1.1":            {"local.domain"},
+			"2a00:1450:400c:c06::93": {"ipv6.domain"},
 		},
 	}
 	errUpstream := &aghtest.TestErrUpstream{
@@ -157,6 +158,11 @@ func TestRDNS_WorkerLoop(t *testing.T) {
 		wantLog: `rdns: resolving "192.168.1.2": errupstream: 1234`,
 		name:    "resolve_error",
 		cliIP:   net.IP{192, 168, 1, 2},
+	}, {
+		ups:     locUpstream,
+		wantLog: "",
+		name:    "ipv6_good",
+		cliIP:   net.ParseIP("2a00:1450:400c:c06::93"),
 	}}
 
 	for _, tc := range testCases {