Pull request: 1558 enable dnsrewrites on disabled protection
Merge in DNS/adguard-home from 1558-always-rewrite to master Squashed commit of the following: commit b8508b3b5fb688cad273a9259c09ccfc07948b2f Author: Eugene Burkov <E.Burkov@AdGuard.COM> Date: Wed Oct 20 19:17:22 2021 +0300 all: imp log of changes commit 97e3649b670786a2936e368a9505faf52f8e8804 Author: Eugene Burkov <E.Burkov@AdGuard.COM> Date: Mon Oct 18 13:18:15 2021 +0300 all: enable dnsrewrites on disabled protection
This commit is contained in:
parent
d7aafa7dc6
commit
b8c4651dec
|
@ -46,6 +46,8 @@ and this project adheres to
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- `$dnsrewrite` rules and other DNS rewrites will now be applied even when the
|
||||||
|
protection is disabled ([#1558]).
|
||||||
- DHCP gateway address, subnet mask, IP address range, and leases validations
|
- DHCP gateway address, subnet mask, IP address range, and leases validations
|
||||||
([#3529]).
|
([#3529]).
|
||||||
- The `systemd` service script will now create the `/var/log` directory when it
|
- The `systemd` service script will now create the `/var/log` directory when it
|
||||||
|
@ -155,6 +157,7 @@ In this release, the schema version has changed from 10 to 12.
|
||||||
- Go 1.15 support.
|
- Go 1.15 support.
|
||||||
|
|
||||||
[#1381]: https://github.com/AdguardTeam/AdGuardHome/issues/1381
|
[#1381]: https://github.com/AdguardTeam/AdGuardHome/issues/1381
|
||||||
|
[#1558]: https://github.com/AdguardTeam/AdGuardHome/issues/1558
|
||||||
[#1691]: https://github.com/AdguardTeam/AdGuardHome/issues/1691
|
[#1691]: https://github.com/AdguardTeam/AdGuardHome/issues/1691
|
||||||
[#1898]: https://github.com/AdguardTeam/AdGuardHome/issues/1898
|
[#1898]: https://github.com/AdguardTeam/AdGuardHome/issues/1898
|
||||||
[#1992]: https://github.com/AdguardTeam/AdGuardHome/issues/1992
|
[#1992]: https://github.com/AdguardTeam/AdGuardHome/issues/1992
|
||||||
|
|
|
@ -90,7 +90,7 @@ func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error {
|
||||||
s.processRestrictLocal,
|
s.processRestrictLocal,
|
||||||
s.processInternalIPAddrs,
|
s.processInternalIPAddrs,
|
||||||
s.processClientID,
|
s.processClientID,
|
||||||
processFilteringBeforeRequest,
|
s.processFilteringBeforeRequest,
|
||||||
s.processLocalPTR,
|
s.processLocalPTR,
|
||||||
s.processUpstream,
|
s.processUpstream,
|
||||||
processDNSSECAfterResponse,
|
processDNSSECAfterResponse,
|
||||||
|
@ -468,19 +468,18 @@ func (s *Server) processLocalPTR(ctx *dnsContext) (rc resultCode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply filtering logic
|
// Apply filtering logic
|
||||||
func processFilteringBeforeRequest(ctx *dnsContext) (rc resultCode) {
|
func (s *Server) processFilteringBeforeRequest(ctx *dnsContext) (rc resultCode) {
|
||||||
s := ctx.srv
|
if ctx.proxyCtx.Res != nil {
|
||||||
d := ctx.proxyCtx
|
// Go on since the response is already set.
|
||||||
|
return resultCodeSuccess
|
||||||
if d.Res != nil {
|
|
||||||
return resultCodeSuccess // response is already set - nothing to do
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.serverLock.RLock()
|
s.serverLock.RLock()
|
||||||
defer s.serverLock.RUnlock()
|
defer s.serverLock.RUnlock()
|
||||||
|
|
||||||
ctx.protectionEnabled = s.conf.ProtectionEnabled && s.dnsFilter != nil
|
ctx.protectionEnabled = s.conf.ProtectionEnabled
|
||||||
if !ctx.protectionEnabled {
|
|
||||||
|
if s.dnsFilter == nil {
|
||||||
return resultCodeSuccess
|
return resultCodeSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,8 +488,7 @@ func processFilteringBeforeRequest(ctx *dnsContext) (rc resultCode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
ctx.result, err = s.filterDNSRequest(ctx)
|
if ctx.result, err = s.filterDNSRequest(ctx); err != nil {
|
||||||
if err != nil {
|
|
||||||
ctx.err = err
|
ctx.err = err
|
||||||
|
|
||||||
return resultCodeError
|
return resultCodeError
|
||||||
|
@ -608,48 +606,50 @@ func processDNSSECAfterResponse(ctx *dnsContext) (rc resultCode) {
|
||||||
func processFilteringAfterResponse(ctx *dnsContext) (rc resultCode) {
|
func processFilteringAfterResponse(ctx *dnsContext) (rc resultCode) {
|
||||||
s := ctx.srv
|
s := ctx.srv
|
||||||
d := ctx.proxyCtx
|
d := ctx.proxyCtx
|
||||||
res := ctx.result
|
|
||||||
var err error
|
|
||||||
|
|
||||||
switch res.Reason {
|
switch res := ctx.result; res.Reason {
|
||||||
case filtering.Rewritten,
|
case filtering.NotFilteredAllowList:
|
||||||
|
// Go on.
|
||||||
|
case
|
||||||
|
filtering.Rewritten,
|
||||||
filtering.RewrittenRule:
|
filtering.RewrittenRule:
|
||||||
|
|
||||||
if len(ctx.origQuestion.Name) == 0 {
|
if len(ctx.origQuestion.Name) == 0 {
|
||||||
// origQuestion is set in case we get only CNAME without IP from rewrites table
|
// origQuestion is set in case we get only CNAME without IP from
|
||||||
|
// rewrites table.
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Req.Question[0] = ctx.origQuestion
|
d.Req.Question[0], d.Res.Question[0] = ctx.origQuestion, ctx.origQuestion
|
||||||
d.Res.Question[0] = ctx.origQuestion
|
if len(d.Res.Answer) > 0 {
|
||||||
|
answer := append([]dns.RR{s.genAnswerCNAME(d.Req, res.CanonName)}, d.Res.Answer...)
|
||||||
if len(d.Res.Answer) != 0 {
|
|
||||||
answer := []dns.RR{}
|
|
||||||
answer = append(answer, s.genAnswerCNAME(d.Req, res.CanonName))
|
|
||||||
answer = append(answer, d.Res.Answer...)
|
|
||||||
d.Res.Answer = answer
|
d.Res.Answer = answer
|
||||||
}
|
}
|
||||||
|
|
||||||
case filtering.NotFilteredAllowList:
|
|
||||||
// nothing
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if !ctx.protectionEnabled || // filters are disabled: there's nothing to check for
|
// Check the response only if the it's from an upstream. Don't check
|
||||||
!ctx.responseFromUpstream { // only check response if it's from an upstream server
|
// the response if the protection is disabled since dnsrewrite rules
|
||||||
|
// aren't applied to it anyway.
|
||||||
|
if !ctx.protectionEnabled || !ctx.responseFromUpstream || s.dnsFilter == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
origResp2 := d.Res
|
|
||||||
ctx.result, err = s.filterDNSResponse(ctx)
|
origResp := d.Res
|
||||||
|
result, err := s.filterDNSResponse(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.err = err
|
ctx.err = err
|
||||||
|
|
||||||
return resultCodeError
|
return resultCodeError
|
||||||
}
|
}
|
||||||
if ctx.result != nil {
|
|
||||||
ctx.origResp = origResp2 // matched by response
|
if result != nil {
|
||||||
} else {
|
ctx.result = result
|
||||||
ctx.result = &filtering.Result{}
|
ctx.origResp = origResp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ctx.result == nil {
|
||||||
|
ctx.result = &filtering.Result{}
|
||||||
|
}
|
||||||
|
|
||||||
return resultCodeSuccess
|
return resultCodeSuccess
|
||||||
}
|
}
|
||||||
|
|
|
@ -909,6 +909,7 @@ func TestRewrite(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
f := filtering.New(c, nil)
|
f := filtering.New(c, nil)
|
||||||
|
f.SetEnabled(true)
|
||||||
|
|
||||||
snd, err := aghnet.NewSubnetDetector()
|
snd, err := aghnet.NewSubnetDetector()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -945,45 +946,56 @@ func TestRewrite(t *testing.T) {
|
||||||
|
|
||||||
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
||||||
|
|
||||||
req := createTestMessageWithType("test.com.", dns.TypeA)
|
subTestFunc := func(t *testing.T) {
|
||||||
reply, err := dns.Exchange(req, addr.String())
|
req := createTestMessageWithType("test.com.", dns.TypeA)
|
||||||
require.NoError(t, err)
|
reply, eerr := dns.Exchange(req, addr.String())
|
||||||
|
require.NoError(t, eerr)
|
||||||
|
|
||||||
require.Len(t, reply.Answer, 1)
|
require.Len(t, reply.Answer, 1)
|
||||||
|
|
||||||
a, ok := reply.Answer[0].(*dns.A)
|
a, ok := reply.Answer[0].(*dns.A)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
assert.True(t, net.IP{1, 2, 3, 4}.Equal(a.A))
|
assert.True(t, net.IP{1, 2, 3, 4}.Equal(a.A))
|
||||||
|
|
||||||
req = createTestMessageWithType("test.com.", dns.TypeAAAA)
|
req = createTestMessageWithType("test.com.", dns.TypeAAAA)
|
||||||
reply, err = dns.Exchange(req, addr.String())
|
reply, eerr = dns.Exchange(req, addr.String())
|
||||||
require.NoError(t, err)
|
require.NoError(t, eerr)
|
||||||
|
|
||||||
assert.Empty(t, reply.Answer)
|
assert.Empty(t, reply.Answer)
|
||||||
|
|
||||||
req = createTestMessageWithType("alias.test.com.", dns.TypeA)
|
req = createTestMessageWithType("alias.test.com.", dns.TypeA)
|
||||||
reply, err = dns.Exchange(req, addr.String())
|
reply, eerr = dns.Exchange(req, addr.String())
|
||||||
require.NoError(t, err)
|
require.NoError(t, eerr)
|
||||||
|
|
||||||
require.Len(t, reply.Answer, 2)
|
require.Len(t, reply.Answer, 2)
|
||||||
|
|
||||||
assert.Equal(t, "test.com.", reply.Answer[0].(*dns.CNAME).Target)
|
assert.Equal(t, "test.com.", reply.Answer[0].(*dns.CNAME).Target)
|
||||||
assert.True(t, net.IP{1, 2, 3, 4}.Equal(reply.Answer[1].(*dns.A).A))
|
assert.True(t, net.IP{1, 2, 3, 4}.Equal(reply.Answer[1].(*dns.A).A))
|
||||||
|
|
||||||
req = createTestMessageWithType("my.alias.example.org.", dns.TypeA)
|
req = createTestMessageWithType("my.alias.example.org.", dns.TypeA)
|
||||||
reply, err = dns.Exchange(req, addr.String())
|
reply, eerr = dns.Exchange(req, addr.String())
|
||||||
require.NoError(t, err)
|
require.NoError(t, eerr)
|
||||||
|
|
||||||
// The original question is restored.
|
// The original question is restored.
|
||||||
require.Len(t, reply.Question, 1)
|
require.Len(t, reply.Question, 1)
|
||||||
|
|
||||||
assert.Equal(t, "my.alias.example.org.", reply.Question[0].Name)
|
assert.Equal(t, "my.alias.example.org.", reply.Question[0].Name)
|
||||||
|
|
||||||
require.Len(t, reply.Answer, 2)
|
require.Len(t, reply.Answer, 2)
|
||||||
|
|
||||||
assert.Equal(t, "example.org.", reply.Answer[0].(*dns.CNAME).Target)
|
assert.Equal(t, "example.org.", reply.Answer[0].(*dns.CNAME).Target)
|
||||||
assert.Equal(t, dns.TypeA, reply.Answer[1].Header().Rrtype)
|
assert.Equal(t, dns.TypeA, reply.Answer[1].Header().Rrtype)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, protect := range []bool{true, false} {
|
||||||
|
val := protect
|
||||||
|
conf := s.getDNSConfig()
|
||||||
|
conf.ProtectionEnabled = &val
|
||||||
|
s.setConfig(conf)
|
||||||
|
|
||||||
|
t.Run(fmt.Sprintf("protection_is_%t", val), subTestFunc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func publicKey(priv interface{}) interface{} {
|
func publicKey(priv interface{}) interface{} {
|
||||||
|
@ -1092,9 +1104,10 @@ func TestPTRResponseFromHosts(t *testing.T) {
|
||||||
require.ErrorIs(t, hc.Close(), closeCalled)
|
require.ErrorIs(t, hc.Close(), closeCalled)
|
||||||
})
|
})
|
||||||
|
|
||||||
c := filtering.Config{
|
flt := filtering.New(&filtering.Config{
|
||||||
EtcHosts: hc,
|
EtcHosts: hc,
|
||||||
}
|
}, nil)
|
||||||
|
flt.SetEnabled(true)
|
||||||
|
|
||||||
var snd *aghnet.SubnetDetector
|
var snd *aghnet.SubnetDetector
|
||||||
snd, err = aghnet.NewSubnetDetector()
|
snd, err = aghnet.NewSubnetDetector()
|
||||||
|
@ -1104,7 +1117,7 @@ func TestPTRResponseFromHosts(t *testing.T) {
|
||||||
var s *Server
|
var s *Server
|
||||||
s, err = NewServer(DNSCreateParams{
|
s, err = NewServer(DNSCreateParams{
|
||||||
DHCPServer: &testDHCP{},
|
DHCPServer: &testDHCP{},
|
||||||
DNSFilter: filtering.New(&c, nil),
|
DNSFilter: flt,
|
||||||
SubnetDetector: snd,
|
SubnetDetector: snd,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -1112,32 +1125,41 @@ func TestPTRResponseFromHosts(t *testing.T) {
|
||||||
s.conf.UDPListenAddrs = []*net.UDPAddr{{}}
|
s.conf.UDPListenAddrs = []*net.UDPAddr{{}}
|
||||||
s.conf.TCPListenAddrs = []*net.TCPAddr{{}}
|
s.conf.TCPListenAddrs = []*net.TCPAddr{{}}
|
||||||
s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
|
s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
|
||||||
s.conf.FilteringConfig.ProtectionEnabled = true
|
|
||||||
|
|
||||||
err = s.Prepare(nil)
|
err = s.Prepare(nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = s.Start()
|
err = s.Start()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
s.Close()
|
s.Close()
|
||||||
})
|
})
|
||||||
|
|
||||||
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
subTestFunc := func(t *testing.T) {
|
||||||
req := createTestMessageWithType("1.0.0.127.in-addr.arpa.", dns.TypePTR)
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
||||||
|
req := createTestMessageWithType("1.0.0.127.in-addr.arpa.", dns.TypePTR)
|
||||||
|
|
||||||
resp, err := dns.Exchange(req, addr.String())
|
resp, eerr := dns.Exchange(req, addr.String())
|
||||||
require.NoError(t, err)
|
require.NoError(t, eerr)
|
||||||
|
|
||||||
require.Lenf(t, resp.Answer, 1, "%#v", resp)
|
require.Len(t, resp.Answer, 1)
|
||||||
|
|
||||||
assert.Equal(t, dns.TypePTR, resp.Answer[0].Header().Rrtype)
|
assert.Equal(t, dns.TypePTR, resp.Answer[0].Header().Rrtype)
|
||||||
assert.Equal(t, "1.0.0.127.in-addr.arpa.", resp.Answer[0].Header().Name)
|
assert.Equal(t, "1.0.0.127.in-addr.arpa.", resp.Answer[0].Header().Name)
|
||||||
|
|
||||||
ptr, ok := resp.Answer[0].(*dns.PTR)
|
ptr, ok := resp.Answer[0].(*dns.PTR)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.Equal(t, "host.", ptr.Ptr)
|
assert.Equal(t, "host.", ptr.Ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, protect := range []bool{true, false} {
|
||||||
|
val := protect
|
||||||
|
conf := s.getDNSConfig()
|
||||||
|
conf.ProtectionEnabled = &val
|
||||||
|
s.setConfig(conf)
|
||||||
|
|
||||||
|
t.Run(fmt.Sprintf("protection_is_%t", val), subTestFunc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewServer(t *testing.T) {
|
func TestNewServer(t *testing.T) {
|
||||||
|
|
|
@ -52,6 +52,7 @@ func (s *Server) beforeRequestHandler(
|
||||||
// the client's IP address and ID, if any, from ctx.
|
// the client's IP address and ID, if any, from ctx.
|
||||||
func (s *Server) getClientRequestFilteringSettings(ctx *dnsContext) *filtering.Settings {
|
func (s *Server) getClientRequestFilteringSettings(ctx *dnsContext) *filtering.Settings {
|
||||||
setts := s.dnsFilter.GetConfig()
|
setts := s.dnsFilter.GetConfig()
|
||||||
|
setts.ProtectionEnabled = ctx.protectionEnabled
|
||||||
if s.conf.FilterHandler != nil {
|
if s.conf.FilterHandler != nil {
|
||||||
ip, _ := netutil.IPAndPortFromAddr(ctx.proxyCtx.Addr)
|
ip, _ := netutil.IPAndPortFromAddr(ctx.proxyCtx.Addr)
|
||||||
s.conf.FilterHandler(ip, ctx.clientID, &setts)
|
s.conf.FilterHandler(ip, ctx.clientID, &setts)
|
||||||
|
@ -65,32 +66,31 @@ func (s *Server) getClientRequestFilteringSettings(ctx *dnsContext) *filtering.S
|
||||||
func (s *Server) filterDNSRequest(ctx *dnsContext) (*filtering.Result, error) {
|
func (s *Server) filterDNSRequest(ctx *dnsContext) (*filtering.Result, error) {
|
||||||
d := ctx.proxyCtx
|
d := ctx.proxyCtx
|
||||||
req := d.Req
|
req := d.Req
|
||||||
host := strings.TrimSuffix(req.Question[0].Name, ".")
|
q := req.Question[0]
|
||||||
res, err := s.dnsFilter.CheckHost(host, req.Question[0].Qtype, ctx.setts)
|
host := strings.TrimSuffix(q.Name, ".")
|
||||||
if err != nil {
|
res, err := s.dnsFilter.CheckHost(host, q.Qtype, ctx.setts)
|
||||||
// Return immediately if there's an error
|
switch {
|
||||||
return nil, fmt.Errorf("filtering failed to check host %q: %w", host, err)
|
case err != nil:
|
||||||
} else if res.IsFiltered {
|
return nil, fmt.Errorf("failed to check host %q: %w", host, err)
|
||||||
log.Tracef("Host %s is filtered, reason - %q, matched rule: %q", host, res.Reason, res.Rules[0].Text)
|
case res.IsFiltered:
|
||||||
|
log.Tracef("host %q is filtered, reason %q, rule: %q", host, res.Reason, res.Rules[0].Text)
|
||||||
d.Res = s.genDNSFilterMessage(d, &res)
|
d.Res = s.genDNSFilterMessage(d, &res)
|
||||||
} else if res.Reason.In(filtering.Rewritten, filtering.RewrittenRule) &&
|
case res.Reason.In(filtering.Rewritten, filtering.RewrittenRule) &&
|
||||||
res.CanonName != "" &&
|
res.CanonName != "" &&
|
||||||
len(res.IPList) == 0 {
|
len(res.IPList) == 0:
|
||||||
// Resolve the new canonical name, not the original host
|
// Resolve the new canonical name, not the original host name. The
|
||||||
// name. The original question is readded in
|
// original question is readded in processFilteringAfterResponse.
|
||||||
// processFilteringAfterResponse.
|
ctx.origQuestion = q
|
||||||
ctx.origQuestion = req.Question[0]
|
|
||||||
req.Question[0].Name = dns.Fqdn(res.CanonName)
|
req.Question[0].Name = dns.Fqdn(res.CanonName)
|
||||||
} else if res.Reason == filtering.RewrittenAutoHosts && len(res.ReverseHosts) != 0 {
|
case res.Reason == filtering.RewrittenAutoHosts && len(res.ReverseHosts) != 0:
|
||||||
resp := s.makeResponse(req)
|
resp := s.makeResponse(req)
|
||||||
|
hdr := dns.RR_Header{
|
||||||
|
Name: q.Name,
|
||||||
|
Rrtype: dns.TypePTR,
|
||||||
|
Ttl: s.conf.BlockedResponseTTL,
|
||||||
|
Class: dns.ClassINET,
|
||||||
|
}
|
||||||
for _, h := range res.ReverseHosts {
|
for _, h := range res.ReverseHosts {
|
||||||
hdr := dns.RR_Header{
|
|
||||||
Name: req.Question[0].Name,
|
|
||||||
Rrtype: dns.TypePTR,
|
|
||||||
Ttl: s.conf.BlockedResponseTTL,
|
|
||||||
Class: dns.ClassINET,
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr := &dns.PTR{
|
ptr := &dns.PTR{
|
||||||
Hdr: hdr,
|
Hdr: hdr,
|
||||||
Ptr: h,
|
Ptr: h,
|
||||||
|
@ -100,7 +100,7 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*filtering.Result, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Res = resp
|
d.Res = resp
|
||||||
} else if res.Reason.In(filtering.Rewritten, filtering.RewrittenAutoHosts) {
|
case res.Reason.In(filtering.Rewritten, filtering.RewrittenAutoHosts):
|
||||||
resp := s.makeResponse(req)
|
resp := s.makeResponse(req)
|
||||||
|
|
||||||
name := host
|
name := host
|
||||||
|
@ -110,11 +110,12 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*filtering.Result, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ip := range res.IPList {
|
for _, ip := range res.IPList {
|
||||||
if req.Question[0].Qtype == dns.TypeA {
|
switch q.Qtype {
|
||||||
|
case dns.TypeA:
|
||||||
a := s.genAnswerA(req, ip.To4())
|
a := s.genAnswerA(req, ip.To4())
|
||||||
a.Hdr.Name = dns.Fqdn(name)
|
a.Hdr.Name = dns.Fqdn(name)
|
||||||
resp.Answer = append(resp.Answer, a)
|
resp.Answer = append(resp.Answer, a)
|
||||||
} else if req.Question[0].Qtype == dns.TypeAAAA {
|
case dns.TypeAAAA:
|
||||||
a := s.genAnswerAAAA(req, ip)
|
a := s.genAnswerAAAA(req, ip)
|
||||||
a.Hdr.Name = dns.Fqdn(name)
|
a.Hdr.Name = dns.Fqdn(name)
|
||||||
resp.Answer = append(resp.Answer, a)
|
resp.Answer = append(resp.Answer, a)
|
||||||
|
@ -122,9 +123,8 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*filtering.Result, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Res = resp
|
d.Res = resp
|
||||||
} else if res.Reason == filtering.RewrittenRule {
|
case res.Reason == filtering.RewrittenRule:
|
||||||
err = s.filterDNSRewrite(req, res, d)
|
if err = s.filterDNSRewrite(req, res, d); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,6 +179,7 @@ func (s *Server) filterDNSResponse(ctx *dnsContext) (*filtering.Result, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
host = strings.TrimSuffix(host, ".")
|
||||||
res, err := s.checkHostRules(host, d.Req.Question[0].Qtype, ctx.setts)
|
res, err := s.checkHostRules(host, d.Req.Question[0].Qtype, ctx.setts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -38,6 +38,7 @@ type Settings struct {
|
||||||
|
|
||||||
ServicesRules []ServiceEntry
|
ServicesRules []ServiceEntry
|
||||||
|
|
||||||
|
ProtectionEnabled bool
|
||||||
FilteringEnabled bool
|
FilteringEnabled bool
|
||||||
SafeSearchEnabled bool
|
SafeSearchEnabled bool
|
||||||
SafeBrowsingEnabled bool
|
SafeBrowsingEnabled bool
|
||||||
|
@ -221,12 +222,13 @@ func (r Reason) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// In returns true if reasons include r.
|
// In returns true if reasons include r.
|
||||||
func (r Reason) In(reasons ...Reason) bool {
|
func (r Reason) In(reasons ...Reason) (ok bool) {
|
||||||
for _, reason := range reasons {
|
for _, reason := range reasons {
|
||||||
if r == reason {
|
if r == reason {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +247,7 @@ func (d *DNSFilter) GetConfig() (s Settings) {
|
||||||
defer d.confLock.RUnlock()
|
defer d.confLock.RUnlock()
|
||||||
|
|
||||||
return Settings{
|
return Settings{
|
||||||
FilteringEnabled: atomic.LoadUint32(&d.Config.enabled) == 1,
|
FilteringEnabled: atomic.LoadUint32(&d.Config.enabled) != 0,
|
||||||
SafeSearchEnabled: d.Config.SafeSearchEnabled,
|
SafeSearchEnabled: d.Config.SafeSearchEnabled,
|
||||||
SafeBrowsingEnabled: d.Config.SafeBrowsingEnabled,
|
SafeBrowsingEnabled: d.Config.SafeBrowsingEnabled,
|
||||||
ParentalEnabled: d.Config.ParentalEnabled,
|
ParentalEnabled: d.Config.ParentalEnabled,
|
||||||
|
@ -421,14 +423,16 @@ func (d *DNSFilter) CheckHost(
|
||||||
// Sometimes clients try to resolve ".", which is a request to get root
|
// Sometimes clients try to resolve ".", which is a request to get root
|
||||||
// servers.
|
// servers.
|
||||||
if host == "" {
|
if host == "" {
|
||||||
return Result{Reason: NotFilteredNotFound}, nil
|
return Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
host = strings.ToLower(host)
|
host = strings.ToLower(host)
|
||||||
|
|
||||||
res = d.processRewrites(host, qtype)
|
if setts.FilteringEnabled {
|
||||||
if res.Reason == Rewritten {
|
res = d.processRewrites(host, qtype)
|
||||||
return res, nil
|
if res.Reason == Rewritten {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, hc := range d.hostCheckers {
|
for _, hc := range d.hostCheckers {
|
||||||
|
@ -448,7 +452,7 @@ func (d *DNSFilter) CheckHost(
|
||||||
// matchSysHosts tries to match the host against the operating system's hosts
|
// matchSysHosts tries to match the host against the operating system's hosts
|
||||||
// database.
|
// database.
|
||||||
func (d *DNSFilter) matchSysHosts(host string, qtype uint16, setts *Settings) (res Result, err error) {
|
func (d *DNSFilter) matchSysHosts(host string, qtype uint16, setts *Settings) (res Result, err error) {
|
||||||
if d.EtcHosts == nil {
|
if !setts.FilteringEnabled || d.EtcHosts == nil {
|
||||||
return Result{}, nil
|
return Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,10 +472,8 @@ func (d *DNSFilter) matchSysHosts(host string, qtype uint16, setts *Settings) (r
|
||||||
|
|
||||||
var ips []net.IP
|
var ips []net.IP
|
||||||
var revHosts []string
|
var revHosts []string
|
||||||
|
|
||||||
for _, nr := range dnsr {
|
for _, nr := range dnsr {
|
||||||
dr := nr.DNSRewrite
|
if nr.DNSRewrite == nil {
|
||||||
if dr == nil {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -553,6 +555,10 @@ func matchBlockedServicesRules(
|
||||||
_ uint16,
|
_ uint16,
|
||||||
setts *Settings,
|
setts *Settings,
|
||||||
) (res Result, err error) {
|
) (res Result, err error) {
|
||||||
|
if !setts.ProtectionEnabled {
|
||||||
|
return Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
svcs := setts.ServicesRules
|
svcs := setts.ServicesRules
|
||||||
if len(svcs) == 0 {
|
if len(svcs) == 0 {
|
||||||
return Result{}, nil
|
return Result{}, nil
|
||||||
|
@ -784,7 +790,7 @@ func (d *DNSFilter) matchHost(
|
||||||
// TODO(e.burkov): Inspect if the above is true.
|
// TODO(e.burkov): Inspect if the above is true.
|
||||||
defer d.engineLock.RUnlock()
|
defer d.engineLock.RUnlock()
|
||||||
|
|
||||||
if d.filteringEngineAllow != nil {
|
if setts.ProtectionEnabled && d.filteringEngineAllow != nil {
|
||||||
dnsres, ok := d.filteringEngineAllow.MatchRequest(ureq)
|
dnsres, ok := d.filteringEngineAllow.MatchRequest(ureq)
|
||||||
if ok {
|
if ok {
|
||||||
return d.matchHostProcessAllowList(host, dnsres)
|
return d.matchHostProcessAllowList(host, dnsres)
|
||||||
|
@ -810,6 +816,11 @@ func (d *DNSFilter) matchHost(
|
||||||
return Result{}, nil
|
return Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !setts.ProtectionEnabled {
|
||||||
|
// Don't check non-dnsrewrite filtering results.
|
||||||
|
return Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
res = d.matchHostProcessDNSResult(qtype, dnsres)
|
res = d.matchHostProcessDNSResult(qtype, dnsres)
|
||||||
for _, r := range res.Rules {
|
for _, r := range res.Rules {
|
||||||
log.Debug(
|
log.Debug(
|
||||||
|
|
|
@ -21,7 +21,9 @@ func TestMain(m *testing.M) {
|
||||||
aghtest.DiscardLogOutput(m)
|
aghtest.DiscardLogOutput(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
var setts Settings
|
var setts = Settings{
|
||||||
|
ProtectionEnabled: true,
|
||||||
|
}
|
||||||
|
|
||||||
// Helpers.
|
// Helpers.
|
||||||
|
|
||||||
|
@ -39,9 +41,9 @@ func purgeCaches() {
|
||||||
|
|
||||||
func newForTest(c *Config, filters []Filter) *DNSFilter {
|
func newForTest(c *Config, filters []Filter) *DNSFilter {
|
||||||
setts = Settings{
|
setts = Settings{
|
||||||
FilteringEnabled: true,
|
ProtectionEnabled: true,
|
||||||
|
FilteringEnabled: true,
|
||||||
}
|
}
|
||||||
setts.FilteringEnabled = true
|
|
||||||
if c != nil {
|
if c != nil {
|
||||||
c.SafeBrowsingCacheSize = 10000
|
c.SafeBrowsingCacheSize = 10000
|
||||||
c.ParentalCacheSize = 10000
|
c.ParentalCacheSize = 10000
|
||||||
|
@ -797,7 +799,11 @@ func TestClientSettings(t *testing.T) {
|
||||||
|
|
||||||
makeTester := func(tc testCase, before bool) func(t *testing.T) {
|
makeTester := func(tc testCase, before bool) func(t *testing.T) {
|
||||||
return func(t *testing.T) {
|
return func(t *testing.T) {
|
||||||
r, _ := d.CheckHost(tc.host, dns.TypeA, &setts)
|
t.Helper()
|
||||||
|
|
||||||
|
r, err := d.CheckHost(tc.host, dns.TypeA, &setts)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
if before {
|
if before {
|
||||||
assert.True(t, r.IsFiltered)
|
assert.True(t, r.IsFiltered)
|
||||||
assert.Equal(t, tc.wantReason, r.Reason)
|
assert.Equal(t, tc.wantReason, r.Reason)
|
||||||
|
@ -808,7 +814,7 @@ func TestClientSettings(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check behaviour without any per-client settings, then apply per-client
|
// Check behaviour without any per-client settings, then apply per-client
|
||||||
// settings and check behaviour once again.
|
// settings and check behavior once again.
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, makeTester(tc, tc.before))
|
t.Run(tc.name, makeTester(tc, tc.before))
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,7 +306,7 @@ func (d *DNSFilter) checkSafeBrowsing(
|
||||||
_ uint16,
|
_ uint16,
|
||||||
setts *Settings,
|
setts *Settings,
|
||||||
) (res Result, err error) {
|
) (res Result, err error) {
|
||||||
if !setts.SafeBrowsingEnabled {
|
if !setts.ProtectionEnabled || !setts.SafeBrowsingEnabled {
|
||||||
return Result{}, nil
|
return Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +339,7 @@ func (d *DNSFilter) checkParental(
|
||||||
_ uint16,
|
_ uint16,
|
||||||
setts *Settings,
|
setts *Settings,
|
||||||
) (res Result, err error) {
|
) (res Result, err error) {
|
||||||
if !setts.ParentalEnabled {
|
if !setts.ProtectionEnabled || !setts.ParentalEnabled {
|
||||||
return Result{}, nil
|
return Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,7 @@ func TestSBPC_checkErrorUpstream(t *testing.T) {
|
||||||
d.SetParentalUpstream(ups)
|
d.SetParentalUpstream(ups)
|
||||||
|
|
||||||
setts := &Settings{
|
setts := &Settings{
|
||||||
|
ProtectionEnabled: true,
|
||||||
SafeBrowsingEnabled: true,
|
SafeBrowsingEnabled: true,
|
||||||
ParentalEnabled: true,
|
ParentalEnabled: true,
|
||||||
}
|
}
|
||||||
|
@ -135,35 +136,36 @@ func TestSBPC(t *testing.T) {
|
||||||
const hostname = "example.org"
|
const hostname = "example.org"
|
||||||
|
|
||||||
setts := &Settings{
|
setts := &Settings{
|
||||||
|
ProtectionEnabled: true,
|
||||||
SafeBrowsingEnabled: true,
|
SafeBrowsingEnabled: true,
|
||||||
ParentalEnabled: true,
|
ParentalEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
|
testCache cache.Cache
|
||||||
|
testFunc func(host string, _ uint16, _ *Settings) (res Result, err error)
|
||||||
name string
|
name string
|
||||||
block bool
|
block bool
|
||||||
testFunc func(host string, _ uint16, _ *Settings) (res Result, err error)
|
|
||||||
testCache cache.Cache
|
|
||||||
}{{
|
}{{
|
||||||
|
testCache: gctx.safebrowsingCache,
|
||||||
|
testFunc: d.checkSafeBrowsing,
|
||||||
name: "sb_no_block",
|
name: "sb_no_block",
|
||||||
block: false,
|
block: false,
|
||||||
testFunc: d.checkSafeBrowsing,
|
|
||||||
testCache: gctx.safebrowsingCache,
|
|
||||||
}, {
|
}, {
|
||||||
|
testCache: gctx.safebrowsingCache,
|
||||||
|
testFunc: d.checkSafeBrowsing,
|
||||||
name: "sb_block",
|
name: "sb_block",
|
||||||
block: true,
|
block: true,
|
||||||
testFunc: d.checkSafeBrowsing,
|
|
||||||
testCache: gctx.safebrowsingCache,
|
|
||||||
}, {
|
}, {
|
||||||
|
testCache: gctx.parentalCache,
|
||||||
|
testFunc: d.checkParental,
|
||||||
name: "pc_no_block",
|
name: "pc_no_block",
|
||||||
block: false,
|
block: false,
|
||||||
testFunc: d.checkParental,
|
|
||||||
testCache: gctx.parentalCache,
|
|
||||||
}, {
|
}, {
|
||||||
|
testCache: gctx.parentalCache,
|
||||||
|
testFunc: d.checkParental,
|
||||||
name: "pc_block",
|
name: "pc_block",
|
||||||
block: true,
|
block: true,
|
||||||
testFunc: d.checkParental,
|
|
||||||
testCache: gctx.parentalCache,
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|
|
@ -74,7 +74,7 @@ func (d *DNSFilter) checkSafeSearch(
|
||||||
_ uint16,
|
_ uint16,
|
||||||
setts *Settings,
|
setts *Settings,
|
||||||
) (res Result, err error) {
|
) (res Result, err error) {
|
||||||
if !setts.SafeSearchEnabled {
|
if !setts.ProtectionEnabled || !setts.SafeSearchEnabled {
|
||||||
return Result{}, nil
|
return Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -404,6 +404,7 @@ func (f *Filtering) handleCheckHost(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
setts := Context.dnsFilter.GetConfig()
|
setts := Context.dnsFilter.GetConfig()
|
||||||
setts.FilteringEnabled = true
|
setts.FilteringEnabled = true
|
||||||
|
setts.ProtectionEnabled = true
|
||||||
Context.dnsFilter.ApplyBlockedServices(&setts, nil, true)
|
Context.dnsFilter.ApplyBlockedServices(&setts, nil, true)
|
||||||
result, err := Context.dnsFilter.CheckHost(host, dns.TypeA, &setts)
|
result, err := Context.dnsFilter.CheckHost(host, dns.TypeA, &setts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue