From 2d328ea840df18ba1891b36db7592baaab991d71 Mon Sep 17 00:00:00 2001
From: Eugene Burkov <e.burkov@adguard.com>
Date: Tue, 7 Dec 2021 14:12:59 +0300
Subject: [PATCH] Pull request: improve anonymizer performance

Merge in DNS/adguard-home from imp-anonymizer to master

Squashed commit of the following:

commit 340237d747ede620756e8d213c9da825d038d691
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Dec 7 12:43:27 2021 +0300

    querylog: mv slow version

commit 96daf498200d0de86f62a3a1c1502f928fba2b0a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Dec 6 21:21:13 2021 +0300

    querylog: imp anonymizer
---
 internal/querylog/decode_test.go | 10 ++++++++++
 internal/querylog/http.go        | 31 +++++++------------------------
 2 files changed, 17 insertions(+), 24 deletions(-)

diff --git a/internal/querylog/decode_test.go b/internal/querylog/decode_test.go
index 0a1b41fe..d57b24f0 100644
--- a/internal/querylog/decode_test.go
+++ b/internal/querylog/decode_test.go
@@ -245,6 +245,16 @@ func TestDecodeLogEntry_backwardCompatability(t *testing.T) {
 	}
 }
 
+// anonymizeIPSlow masks ip to anonymize the client if the ip is a valid one.
+// It only exists in purposes of benchmark comparison, see BenchmarkAnonymizeIP.
+func anonymizeIPSlow(ip net.IP) {
+	if ip4 := ip.To4(); ip4 != nil {
+		copy(ip4[net.IPv4len-2:net.IPv4len], []byte{0, 0})
+	} else if len(ip) == net.IPv6len {
+		copy(ip[net.IPv6len-10:net.IPv6len], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
+	}
+}
+
 func BenchmarkAnonymizeIP(b *testing.B) {
 	benchCases := []struct {
 		name string
diff --git a/internal/querylog/http.go b/internal/querylog/http.go
index 73bdbe56..f5ddf7c0 100644
--- a/internal/querylog/http.go
+++ b/internal/querylog/http.go
@@ -90,34 +90,17 @@ func (l *queryLog) handleQueryLogInfo(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
-// anonymizeIPSlow masks ip to anonymize the client if the ip is a valid one.
-// It only exists in purposes of benchmark demonstration.
-func anonymizeIPSlow(ip net.IP) {
-	if ip4 := ip.To4(); ip4 != nil {
-		copy(ip4[net.IPv4len-2:], []byte{0, 0})
-	} else if len(ip) == net.IPv6len {
-		copy(ip[net.IPv6len-10:], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
-	}
-}
-
 // AnonymizeIP masks ip to anonymize the client if the ip is a valid one.
 func AnonymizeIP(ip net.IP) {
-	// We use an assignment operator here since it compiles into more efficient
-	// code than copy().  See BenchmarkAnonymizeIP.
+	// zeroes is a slice of zero bytes from which the IP address tail is copied.
+	// Using constant string as source of copying is more efficient than byte
+	// slice, see https://github.com/golang/go/issues/49997.
+	const zeroes = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+
 	if ip4 := ip.To4(); ip4 != nil {
-		ip4[net.IPv4len-2], ip4[net.IPv4len-1] = 0, 0
+		copy(ip4[net.IPv4len-2:net.IPv4len], zeroes)
 	} else if len(ip) == net.IPv6len {
-		ip[net.IPv6len-10],
-			ip[net.IPv6len-9],
-			ip[net.IPv6len-8],
-			ip[net.IPv6len-7],
-			ip[net.IPv6len-6],
-			ip[net.IPv6len-5],
-			ip[net.IPv6len-4],
-			ip[net.IPv6len-3],
-			ip[net.IPv6len-2],
-			ip[net.IPv6len-1] =
-			0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+		copy(ip[net.IPv6len-10:net.IPv6len], zeroes)
 	}
 }