From 9ad4bba9aba286c88cbf26e0f57e72f6975713cf Mon Sep 17 00:00:00 2001
From: Simon Zolin <s.zolin@adguard.com>
Date: Wed, 22 May 2019 12:38:17 +0300
Subject: [PATCH] * dnsfilter: return the correct IP address (host rules)

---
 dnsfilter/dnsfilter.go | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/dnsfilter/dnsfilter.go b/dnsfilter/dnsfilter.go
index b9292f5f..40ca57f0 100644
--- a/dnsfilter/dnsfilter.go
+++ b/dnsfilter/dnsfilter.go
@@ -19,6 +19,7 @@ import (
 	"github.com/AdguardTeam/golibs/log"
 	"github.com/AdguardTeam/urlfilter"
 	"github.com/bluele/gcache"
+	"github.com/miekg/dns"
 	"golang.org/x/net/publicsuffix"
 )
 
@@ -147,7 +148,7 @@ func (r Reason) Matched() bool {
 }
 
 // CheckHost tries to match host against rules, then safebrowsing and parental if they are enabled
-func (d *Dnsfilter) CheckHost(host string) (Result, error) {
+func (d *Dnsfilter) CheckHost(host string, qtype uint16) (Result, error) {
 	// sometimes DNS clients will try to resolve ".", which is a request to get root servers
 	if host == "" {
 		return Result{Reason: NotFilteredNotFound}, nil
@@ -159,7 +160,7 @@ func (d *Dnsfilter) CheckHost(host string) (Result, error) {
 	}
 
 	// try filter lists first
-	result, err := d.matchHost(host)
+	result, err := d.matchHost(host, qtype)
 	if err != nil {
 		return result, err
 	}
@@ -517,7 +518,7 @@ func (d *Dnsfilter) initFiltering(filters map[int]string) error {
 }
 
 // matchHost is a low-level way to check only if hostname is filtered by rules, skipping expensive safebrowsing and parental lookups
-func (d *Dnsfilter) matchHost(host string) (Result, error) {
+func (d *Dnsfilter) matchHost(host string, qtype uint16) (Result, error) {
 	if d.filteringEngine == nil {
 		return Result{}, nil
 	}
@@ -527,6 +528,8 @@ func (d *Dnsfilter) matchHost(host string) (Result, error) {
 		return Result{}, nil
 	}
 
+	log.Tracef("%d rules matched for host '%s'", len(rules), host)
+
 	for _, rule := range rules {
 
 		log.Tracef("Found rule for host '%s': '%s'  list_id: %d",
@@ -548,8 +551,15 @@ func (d *Dnsfilter) matchHost(host string) (Result, error) {
 
 		} else if hostRule, ok := rule.(*urlfilter.HostRule); ok {
 
-			res.IP = hostRule.IP
-			return res, nil
+			if qtype == dns.TypeA && hostRule.IP.To4() != nil {
+				// either IPv4 or IPv4-mapped IPv6 address
+				res.IP = hostRule.IP.To4()
+				return res, nil
+			} else if qtype == dns.TypeAAAA && hostRule.IP.To4() == nil {
+				res.IP = hostRule.IP
+				return res, nil
+			}
+			continue
 
 		} else {
 			log.Tracef("Rule type is unsupported: '%s'  list_id: %d",