* dnsfilter: change DNS answer for host rules

When matched by a host rule, return only the IP address specified in rule.
Respond with an empty IP list to another request type.

:: host -- return nothing to A, return :: to AAAA request
0.0.0.0 host -- return 0.0.0.0 to A, return nothing to AAAA request
This commit is contained in:
Simon Zolin 2020-01-09 19:31:14 +03:00
parent 94d86eee10
commit 8d2a9ce923
3 changed files with 19 additions and 21 deletions

View File

@ -1,7 +1,6 @@
package dnsfilter package dnsfilter
import ( import (
"bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net" "net"
@ -538,24 +537,15 @@ func (d *Dnsfilter) matchHost(host string, qtype uint16) (Result, error) {
} else if hostRule, ok := rule.(*rules.HostRule); ok { } else if hostRule, ok := rule.(*rules.HostRule); ok {
res.IP = net.IP{}
if qtype == dns.TypeA && hostRule.IP.To4() != nil { if qtype == dns.TypeA && hostRule.IP.To4() != nil {
// either IPv4 or IPv4-mapped IPv6 address // either IPv4 or IPv4-mapped IPv6 address
res.IP = hostRule.IP.To4() res.IP = hostRule.IP.To4()
return res, nil
} else if qtype == dns.TypeAAAA { } else if qtype == dns.TypeAAAA && hostRule.IP.To4() == nil {
ip4 := hostRule.IP.To4()
if ip4 == nil {
res.IP = hostRule.IP res.IP = hostRule.IP
}
return res, nil return res, nil
}
if bytes.Equal(ip4, []byte{0, 0, 0, 0}) {
// send IP="::" response for a rule "0.0.0.0 blockdomain"
res.IP = net.IPv6zero
return res, nil
}
}
continue
} else { } else {
log.Tracef("Rule type is unsupported: '%s' list_id: %d", log.Tracef("Rule type is unsupported: '%s' list_id: %d",

View File

@ -98,7 +98,7 @@ func (d *Dnsfilter) checkMatchEmpty(t *testing.T, hostname string) {
func TestEtcHostsMatching(t *testing.T) { func TestEtcHostsMatching(t *testing.T) {
addr := "216.239.38.120" addr := "216.239.38.120"
addr6 := "::1" addr6 := "::1"
text := fmt.Sprintf(" %s google.com www.google.com # enforce google's safesearch \n%s google.com\n0.0.0.0 block.com\n", text := fmt.Sprintf(" %s google.com www.google.com # enforce google's safesearch \n%s ipv6.com\n0.0.0.0 block.com\n",
addr, addr6) addr, addr6)
filters := make(map[int]string) filters := make(map[int]string)
filters[0] = text filters[0] = text
@ -110,12 +110,19 @@ func TestEtcHostsMatching(t *testing.T) {
d.checkMatchEmpty(t, "subdomain.google.com") d.checkMatchEmpty(t, "subdomain.google.com")
d.checkMatchEmpty(t, "example.org") d.checkMatchEmpty(t, "example.org")
// IPv6 address // IPv4
d.checkMatchIP(t, "google.com", addr6, dns.TypeAAAA)
// block both IPv4 and IPv6
d.checkMatchIP(t, "block.com", "0.0.0.0", dns.TypeA) d.checkMatchIP(t, "block.com", "0.0.0.0", dns.TypeA)
d.checkMatchIP(t, "block.com", "::", dns.TypeAAAA)
// ...but empty IPv6
ret, err := d.CheckHost("block.com", dns.TypeAAAA, &setts)
assert.True(t, err == nil && ret.IsFiltered && ret.IP != nil && len(ret.IP) == 0)
// IPv6
d.checkMatchIP(t, "ipv6.com", addr6, dns.TypeAAAA)
// ...but empty IPv4
ret, err = d.CheckHost("ipv6.com", dns.TypeA, &setts)
assert.True(t, err == nil && ret.IsFiltered && ret.IP != nil && len(ret.IP) == 0)
} }
// SAFE BROWSING // SAFE BROWSING

View File

@ -788,7 +788,8 @@ func (s *Server) genAAAAAnswer(req *dns.Msg, ip net.IP) *dns.AAAA {
func (s *Server) genResponseWithIP(req *dns.Msg, ip net.IP) *dns.Msg { func (s *Server) genResponseWithIP(req *dns.Msg, ip net.IP) *dns.Msg {
if req.Question[0].Qtype == dns.TypeA && ip.To4() != nil { if req.Question[0].Qtype == dns.TypeA && ip.To4() != nil {
return s.genARecord(req, ip.To4()) return s.genARecord(req, ip.To4())
} else if req.Question[0].Qtype == dns.TypeAAAA && ip.To4() == nil { } else if req.Question[0].Qtype == dns.TypeAAAA &&
len(ip) == net.IPv6len && ip.To4() == nil {
return s.genAAAARecord(req, ip) return s.genAAAARecord(req, ip)
} }