2021-05-21 14:15:47 +01:00
|
|
|
package filtering
|
2018-08-30 15:25:33 +01:00
|
|
|
|
|
|
|
import (
|
2020-11-16 16:45:31 +00:00
|
|
|
"bytes"
|
2019-05-16 12:03:25 +01:00
|
|
|
"fmt"
|
2023-09-07 15:13:48 +01:00
|
|
|
"net/netip"
|
2018-08-30 15:25:33 +01:00
|
|
|
"testing"
|
2019-05-22 16:30:27 +01:00
|
|
|
|
2021-02-04 17:35:13 +00:00
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
|
2023-06-07 18:04:01 +01:00
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering/hashprefix"
|
2020-11-16 16:45:31 +00:00
|
|
|
"github.com/AdguardTeam/golibs/log"
|
2023-09-07 15:13:48 +01:00
|
|
|
"github.com/AdguardTeam/golibs/netutil"
|
2022-11-02 13:18:02 +00:00
|
|
|
"github.com/AdguardTeam/golibs/testutil"
|
2019-11-27 12:11:46 +00:00
|
|
|
"github.com/AdguardTeam/urlfilter/rules"
|
2019-05-22 16:30:27 +01:00
|
|
|
"github.com/miekg/dns"
|
2019-07-23 10:21:37 +01:00
|
|
|
"github.com/stretchr/testify/assert"
|
2021-03-11 14:32:58 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2018-08-30 15:25:33 +01:00
|
|
|
)
|
|
|
|
|
2020-11-16 12:52:05 +00:00
|
|
|
func TestMain(m *testing.M) {
|
2022-11-02 13:18:02 +00:00
|
|
|
testutil.DiscardLogOutput(m)
|
2020-11-16 12:52:05 +00:00
|
|
|
}
|
|
|
|
|
2022-08-17 16:23:30 +01:00
|
|
|
const (
|
|
|
|
sbBlocked = "wmconvirus.narod.ru"
|
|
|
|
pcBlocked = "pornhub.com"
|
|
|
|
)
|
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Helpers.
|
2018-10-03 22:20:53 +01:00
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
func newForTest(t testing.TB, c *Config, filters []Filter) (f *DNSFilter, setts *Settings) {
|
|
|
|
setts = &Settings{
|
2021-10-20 17:52:13 +01:00
|
|
|
ProtectionEnabled: true,
|
|
|
|
FilteringEnabled: true,
|
2021-02-04 17:35:13 +00:00
|
|
|
}
|
2019-07-23 18:01:50 +01:00
|
|
|
if c != nil {
|
2020-08-13 09:49:42 +01:00
|
|
|
c.SafeBrowsingCacheSize = 10000
|
|
|
|
c.ParentalCacheSize = 10000
|
2019-08-22 13:09:43 +01:00
|
|
|
c.SafeSearchCacheSize = 1000
|
|
|
|
c.CacheTime = 30
|
2023-04-12 12:48:42 +01:00
|
|
|
setts.SafeSearchEnabled = c.SafeSearchConf.Enabled
|
2019-07-25 14:37:06 +01:00
|
|
|
setts.SafeBrowsingEnabled = c.SafeBrowsingEnabled
|
|
|
|
setts.ParentalEnabled = c.ParentalEnabled
|
2022-09-29 15:36:01 +01:00
|
|
|
} else {
|
|
|
|
// It must not be nil.
|
|
|
|
c = &Config{}
|
2019-07-23 18:01:50 +01:00
|
|
|
}
|
2022-09-29 15:36:01 +01:00
|
|
|
f, err := New(c, filters)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return f, setts
|
2018-08-30 15:25:33 +01:00
|
|
|
}
|
|
|
|
|
2023-06-07 18:04:01 +01:00
|
|
|
func newChecker(host string) Checker {
|
|
|
|
return hashprefix.New(&hashprefix.Config{
|
|
|
|
CacheTime: 10,
|
|
|
|
CacheSize: 100000,
|
|
|
|
Upstream: aghtest.NewBlockUpstream(host, true),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
func (d *DNSFilter) checkMatch(t *testing.T, hostname string, setts *Settings) {
|
2018-08-30 15:25:33 +01:00
|
|
|
t.Helper()
|
2021-01-29 13:09:31 +00:00
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err := d.CheckHost(hostname, dns.TypeA, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoErrorf(t, err, "host %q", hostname)
|
|
|
|
|
|
|
|
assert.Truef(t, res.IsFiltered, "host %q", hostname)
|
2018-08-30 15:25:33 +01:00
|
|
|
}
|
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
func (d *DNSFilter) checkMatchIP(t *testing.T, hostname, ip string, qtype uint16, setts *Settings) {
|
2018-10-29 12:46:58 +00:00
|
|
|
t.Helper()
|
2020-12-17 10:32:46 +00:00
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err := d.CheckHost(hostname, qtype, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoErrorf(t, err, "host %q", hostname, err)
|
|
|
|
require.NotEmpty(t, res.Rules, "host %q", hostname)
|
|
|
|
|
|
|
|
assert.Truef(t, res.IsFiltered, "host %q", hostname)
|
2021-03-11 14:32:58 +00:00
|
|
|
|
|
|
|
r := res.Rules[0]
|
|
|
|
require.NotNilf(t, r.IP, "Expected ip %s to match, actual: %v", ip, r.IP)
|
2021-06-17 12:09:16 +01:00
|
|
|
|
|
|
|
assert.Equalf(t, ip, r.IP.String(), "host %q", hostname)
|
2018-10-29 12:46:58 +00:00
|
|
|
}
|
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
func (d *DNSFilter) checkMatchEmpty(t *testing.T, hostname string, setts *Settings) {
|
2018-08-30 15:25:33 +01:00
|
|
|
t.Helper()
|
2021-01-29 13:09:31 +00:00
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err := d.CheckHost(hostname, dns.TypeA, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoErrorf(t, err, "host %q", hostname)
|
|
|
|
|
|
|
|
assert.Falsef(t, res.IsFiltered, "host %q", hostname)
|
2018-08-30 15:25:33 +01:00
|
|
|
}
|
|
|
|
|
2023-09-07 15:13:48 +01:00
|
|
|
func TestDNSFilter_CheckHost_hostRules(t *testing.T) {
|
2018-10-29 12:46:58 +00:00
|
|
|
addr := "216.239.38.120"
|
2019-05-22 16:30:27 +01:00
|
|
|
addr6 := "::1"
|
2020-01-30 16:06:09 +00:00
|
|
|
text := fmt.Sprintf(` %s google.com www.google.com # enforce google's safesearch
|
|
|
|
%s ipv6.com
|
|
|
|
0.0.0.0 block.com
|
|
|
|
0.0.0.1 host2
|
|
|
|
0.0.0.2 host2
|
|
|
|
::1 host2
|
|
|
|
`,
|
2019-05-22 16:30:27 +01:00
|
|
|
addr, addr6)
|
2020-11-06 09:15:08 +00:00
|
|
|
filters := []Filter{{
|
2020-02-26 16:58:25 +00:00
|
|
|
ID: 0, Data: []byte(text),
|
|
|
|
}}
|
2022-09-29 15:36:01 +01:00
|
|
|
d, setts := newForTest(t, nil, filters)
|
2021-01-29 13:09:31 +00:00
|
|
|
t.Cleanup(d.Close)
|
2018-10-29 12:46:58 +00:00
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
d.checkMatchIP(t, "google.com", addr, dns.TypeA, setts)
|
|
|
|
d.checkMatchIP(t, "www.google.com", addr, dns.TypeA, setts)
|
|
|
|
d.checkMatchEmpty(t, "subdomain.google.com", setts)
|
|
|
|
d.checkMatchEmpty(t, "example.org", setts)
|
2019-05-22 16:30:27 +01:00
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// IPv4 match.
|
2022-09-29 15:36:01 +01:00
|
|
|
d.checkMatchIP(t, "block.com", "0.0.0.0", dns.TypeA, setts)
|
2020-01-09 16:31:14 +00:00
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Empty IPv6.
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err := d.CheckHost("block.com", dns.TypeAAAA, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-12-17 10:32:46 +00:00
|
|
|
assert.True(t, res.IsFiltered)
|
2021-03-11 14:32:58 +00:00
|
|
|
|
|
|
|
require.Len(t, res.Rules, 1)
|
2021-06-17 12:09:16 +01:00
|
|
|
|
2021-03-11 14:32:58 +00:00
|
|
|
assert.Equal(t, "0.0.0.0 block.com", res.Rules[0].Text)
|
|
|
|
assert.Empty(t, res.Rules[0].IP)
|
2020-01-09 16:31:14 +00:00
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// IPv6 match.
|
2022-09-29 15:36:01 +01:00
|
|
|
d.checkMatchIP(t, "ipv6.com", addr6, dns.TypeAAAA, setts)
|
2020-01-09 16:31:14 +00:00
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Empty IPv4.
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err = d.CheckHost("ipv6.com", dns.TypeA, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-12-17 10:32:46 +00:00
|
|
|
assert.True(t, res.IsFiltered)
|
2021-03-11 14:32:58 +00:00
|
|
|
|
|
|
|
require.Len(t, res.Rules, 1)
|
2021-06-17 12:09:16 +01:00
|
|
|
|
2021-03-11 14:32:58 +00:00
|
|
|
assert.Equal(t, "::1 ipv6.com", res.Rules[0].Text)
|
|
|
|
assert.Empty(t, res.Rules[0].IP)
|
2020-01-30 16:06:09 +00:00
|
|
|
|
2021-06-17 12:09:16 +01:00
|
|
|
// Two IPv4, both must be returned.
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err = d.CheckHost("host2", dns.TypeA, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-12-17 10:32:46 +00:00
|
|
|
assert.True(t, res.IsFiltered)
|
2021-03-11 14:32:58 +00:00
|
|
|
|
2021-06-17 12:09:16 +01:00
|
|
|
require.Len(t, res.Rules, 2)
|
|
|
|
|
2023-09-07 15:13:48 +01:00
|
|
|
assert.Equal(t, res.Rules[0].IP, netip.AddrFrom4([4]byte{0, 0, 0, 1}))
|
|
|
|
assert.Equal(t, res.Rules[1].IP, netip.AddrFrom4([4]byte{0, 0, 0, 2}))
|
2020-01-30 16:06:09 +00:00
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// One IPv6 address.
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err = d.CheckHost("host2", dns.TypeAAAA, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-12-17 10:32:46 +00:00
|
|
|
assert.True(t, res.IsFiltered)
|
2021-03-11 14:32:58 +00:00
|
|
|
|
|
|
|
require.Len(t, res.Rules, 1)
|
2021-06-17 12:09:16 +01:00
|
|
|
|
2023-09-07 15:13:48 +01:00
|
|
|
assert.Equal(t, res.Rules[0].IP, netutil.IPv6Localhost())
|
2018-10-29 12:46:58 +00:00
|
|
|
}
|
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Safe Browsing.
|
2018-08-30 15:25:33 +01:00
|
|
|
|
|
|
|
func TestSafeBrowsing(t *testing.T) {
|
2020-11-16 16:45:31 +00:00
|
|
|
logOutput := &bytes.Buffer{}
|
2021-02-04 17:35:13 +00:00
|
|
|
aghtest.ReplaceLogWriter(t, logOutput)
|
|
|
|
aghtest.ReplaceLogLevel(t, log.DEBUG)
|
2020-11-16 16:45:31 +00:00
|
|
|
|
2023-06-07 18:04:01 +01:00
|
|
|
sbChecker := newChecker(sbBlocked)
|
|
|
|
|
|
|
|
d, setts := newForTest(t, &Config{
|
|
|
|
SafeBrowsingEnabled: true,
|
|
|
|
SafeBrowsingChecker: sbChecker,
|
|
|
|
}, nil)
|
2021-01-29 13:09:31 +00:00
|
|
|
t.Cleanup(d.Close)
|
2020-11-16 16:45:31 +00:00
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
d.checkMatch(t, sbBlocked, setts)
|
2022-08-17 16:23:30 +01:00
|
|
|
|
|
|
|
require.Contains(t, logOutput.String(), fmt.Sprintf("safebrowsing lookup for %q", sbBlocked))
|
2020-11-16 16:45:31 +00:00
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
d.checkMatch(t, "test."+sbBlocked, setts)
|
|
|
|
d.checkMatchEmpty(t, "yandex.ru", setts)
|
|
|
|
d.checkMatchEmpty(t, pcBlocked, setts)
|
2019-10-16 10:57:49 +01:00
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Cached result.
|
2022-09-29 15:36:01 +01:00
|
|
|
d.checkMatch(t, sbBlocked, setts)
|
|
|
|
d.checkMatchEmpty(t, pcBlocked, setts)
|
2018-08-30 15:25:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestParallelSB(t *testing.T) {
|
2023-06-07 18:04:01 +01:00
|
|
|
d, setts := newForTest(t, &Config{
|
|
|
|
SafeBrowsingEnabled: true,
|
|
|
|
SafeBrowsingChecker: newChecker(sbBlocked),
|
|
|
|
}, nil)
|
2021-01-29 13:09:31 +00:00
|
|
|
t.Cleanup(d.Close)
|
2022-08-17 16:23:30 +01:00
|
|
|
|
2018-08-30 15:25:33 +01:00
|
|
|
t.Run("group", func(t *testing.T) {
|
2024-05-15 11:34:12 +01:00
|
|
|
for i := range 100 {
|
2018-08-30 15:25:33 +01:00
|
|
|
t.Run(fmt.Sprintf("aaa%d", i), func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2022-09-29 15:36:01 +01:00
|
|
|
d.checkMatch(t, sbBlocked, setts)
|
|
|
|
d.checkMatch(t, "test."+sbBlocked, setts)
|
|
|
|
d.checkMatchEmpty(t, "yandex.ru", setts)
|
|
|
|
d.checkMatchEmpty(t, pcBlocked, setts)
|
2018-08-30 15:25:33 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Parental.
|
2019-05-16 12:03:25 +01:00
|
|
|
|
2018-08-30 15:25:33 +01:00
|
|
|
func TestParentalControl(t *testing.T) {
|
2020-11-16 16:45:31 +00:00
|
|
|
logOutput := &bytes.Buffer{}
|
2021-02-04 17:35:13 +00:00
|
|
|
aghtest.ReplaceLogWriter(t, logOutput)
|
|
|
|
aghtest.ReplaceLogLevel(t, log.DEBUG)
|
2020-11-16 16:45:31 +00:00
|
|
|
|
2023-06-07 18:04:01 +01:00
|
|
|
d, setts := newForTest(t, &Config{
|
|
|
|
ParentalEnabled: true,
|
|
|
|
ParentalControlChecker: newChecker(pcBlocked),
|
|
|
|
}, nil)
|
2021-01-29 13:09:31 +00:00
|
|
|
t.Cleanup(d.Close)
|
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
d.checkMatch(t, pcBlocked, setts)
|
2022-08-17 16:23:30 +01:00
|
|
|
require.Contains(t, logOutput.String(), fmt.Sprintf("parental lookup for %q", pcBlocked))
|
2021-06-17 12:09:16 +01:00
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
d.checkMatch(t, "www."+pcBlocked, setts)
|
|
|
|
d.checkMatchEmpty(t, "www.yandex.ru", setts)
|
|
|
|
d.checkMatchEmpty(t, "yandex.ru", setts)
|
|
|
|
d.checkMatchEmpty(t, "api.jquery.com", setts)
|
2019-10-16 10:57:49 +01:00
|
|
|
|
2021-03-11 14:32:58 +00:00
|
|
|
// Test cached result.
|
2022-09-29 15:36:01 +01:00
|
|
|
d.checkMatch(t, pcBlocked, setts)
|
|
|
|
d.checkMatchEmpty(t, "yandex.ru", setts)
|
2018-08-30 15:25:33 +01:00
|
|
|
}
|
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Filtering.
|
2018-08-30 15:25:33 +01:00
|
|
|
|
|
|
|
func TestMatching(t *testing.T) {
|
2021-01-29 13:09:31 +00:00
|
|
|
const nl = "\n"
|
|
|
|
const (
|
|
|
|
blockingRules = `||example.org^` + nl
|
|
|
|
allowlistRules = `||example.org^` + nl + `@@||test.example.org` + nl
|
|
|
|
importantRules = `@@||example.org^` + nl + `||test.example.org^$important` + nl
|
|
|
|
regexRules = `/example\.org/` + nl + `@@||test.example.org^` + nl
|
|
|
|
maskRules = `test*.example.org^` + nl + `exam*.com` + nl
|
|
|
|
dnstypeRules = `||example.org^$dnstype=AAAA` + nl + `@@||test.example.org^` + nl
|
|
|
|
)
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
rules string
|
|
|
|
host string
|
|
|
|
wantReason Reason
|
2021-03-11 09:17:54 +00:00
|
|
|
wantIsFiltered bool
|
2021-01-29 13:09:31 +00:00
|
|
|
wantDNSType uint16
|
|
|
|
}{{
|
|
|
|
name: "sanity",
|
|
|
|
rules: "||doubleclick.net^",
|
|
|
|
host: "www.doubleclick.net",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "sanity",
|
|
|
|
rules: "||doubleclick.net^",
|
|
|
|
host: "nodoubleclick.net",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "sanity",
|
|
|
|
rules: "||doubleclick.net^",
|
|
|
|
host: "doubleclick.net.ru",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "sanity",
|
|
|
|
rules: "||doubleclick.net^",
|
2022-08-17 16:23:30 +01:00
|
|
|
host: sbBlocked,
|
2021-01-29 13:09:31 +00:00
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "blocking",
|
|
|
|
rules: blockingRules,
|
|
|
|
host: "example.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "blocking",
|
|
|
|
rules: blockingRules,
|
|
|
|
host: "test.example.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "blocking",
|
|
|
|
rules: blockingRules,
|
|
|
|
host: "test.test.example.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "blocking",
|
|
|
|
rules: blockingRules,
|
|
|
|
host: "testexample.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "blocking",
|
|
|
|
rules: blockingRules,
|
|
|
|
host: "onemoreexample.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "allowlist",
|
|
|
|
rules: allowlistRules,
|
|
|
|
host: "example.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "allowlist",
|
|
|
|
rules: allowlistRules,
|
|
|
|
host: "test.example.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredAllowList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "allowlist",
|
|
|
|
rules: allowlistRules,
|
|
|
|
host: "test.test.example.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredAllowList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "allowlist",
|
|
|
|
rules: allowlistRules,
|
|
|
|
host: "testexample.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "allowlist",
|
|
|
|
rules: allowlistRules,
|
|
|
|
host: "onemoreexample.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "important",
|
|
|
|
rules: importantRules,
|
|
|
|
host: "example.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredAllowList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "important",
|
|
|
|
rules: importantRules,
|
|
|
|
host: "test.example.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "important",
|
|
|
|
rules: importantRules,
|
|
|
|
host: "test.test.example.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "important",
|
|
|
|
rules: importantRules,
|
|
|
|
host: "testexample.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "important",
|
|
|
|
rules: importantRules,
|
|
|
|
host: "onemoreexample.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "regex",
|
|
|
|
rules: regexRules,
|
|
|
|
host: "example.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "regex",
|
|
|
|
rules: regexRules,
|
|
|
|
host: "test.example.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredAllowList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "regex",
|
|
|
|
rules: regexRules,
|
|
|
|
host: "test.test.example.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredAllowList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "regex",
|
|
|
|
rules: regexRules,
|
|
|
|
host: "testexample.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "regex",
|
|
|
|
rules: regexRules,
|
|
|
|
host: "onemoreexample.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "mask",
|
|
|
|
rules: maskRules,
|
|
|
|
host: "test.example.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "mask",
|
|
|
|
rules: maskRules,
|
|
|
|
host: "test2.example.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "mask",
|
|
|
|
rules: maskRules,
|
|
|
|
host: "example.com",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "mask",
|
|
|
|
rules: maskRules,
|
|
|
|
host: "exampleeee.com",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "mask",
|
|
|
|
rules: maskRules,
|
|
|
|
host: "onemoreexamsite.com",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "mask",
|
|
|
|
rules: maskRules,
|
|
|
|
host: "example.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "mask",
|
|
|
|
rules: maskRules,
|
|
|
|
host: "testexample.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "mask",
|
|
|
|
rules: maskRules,
|
|
|
|
host: "example.co.uk",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "dnstype",
|
|
|
|
rules: dnstypeRules,
|
|
|
|
host: "onemoreexample.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "dnstype",
|
|
|
|
rules: dnstypeRules,
|
|
|
|
host: "example.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredNotFound,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "dnstype",
|
|
|
|
rules: dnstypeRules,
|
|
|
|
host: "example.org",
|
|
|
|
wantIsFiltered: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
wantDNSType: dns.TypeAAAA,
|
|
|
|
}, {
|
|
|
|
name: "dnstype",
|
|
|
|
rules: dnstypeRules,
|
|
|
|
host: "test.example.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredAllowList,
|
|
|
|
wantDNSType: dns.TypeA,
|
|
|
|
}, {
|
|
|
|
name: "dnstype",
|
|
|
|
rules: dnstypeRules,
|
|
|
|
host: "test.example.org",
|
|
|
|
wantIsFiltered: false,
|
|
|
|
wantReason: NotFilteredAllowList,
|
|
|
|
wantDNSType: dns.TypeAAAA,
|
|
|
|
}}
|
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(fmt.Sprintf("%s-%s", tc.name, tc.host), func(t *testing.T) {
|
|
|
|
filters := []Filter{{ID: 0, Data: []byte(tc.rules)}}
|
2022-09-29 15:36:01 +01:00
|
|
|
d, setts := newForTest(t, nil, filters)
|
2021-01-29 13:09:31 +00:00
|
|
|
t.Cleanup(d.Close)
|
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err := d.CheckHost(tc.host, tc.wantDNSType, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
assert.Equalf(t, tc.wantIsFiltered, res.IsFiltered, "Hostname %s has wrong result (%v must be %v)", tc.host, res.IsFiltered, tc.wantIsFiltered)
|
|
|
|
assert.Equalf(t, tc.wantReason, res.Reason, "Hostname %s has wrong reason (%v must be %v)", tc.host, res.Reason, tc.wantReason)
|
2018-08-30 15:25:33 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-26 16:58:25 +00:00
|
|
|
func TestWhitelist(t *testing.T) {
|
|
|
|
rules := `||host1^
|
|
|
|
||host2^
|
|
|
|
`
|
2020-11-06 09:15:08 +00:00
|
|
|
filters := []Filter{{
|
2020-02-26 16:58:25 +00:00
|
|
|
ID: 0, Data: []byte(rules),
|
|
|
|
}}
|
|
|
|
|
|
|
|
whiteRules := `||host1^
|
|
|
|
||host3^
|
|
|
|
`
|
2020-11-06 09:15:08 +00:00
|
|
|
whiteFilters := []Filter{{
|
2020-02-26 16:58:25 +00:00
|
|
|
ID: 0, Data: []byte(whiteRules),
|
|
|
|
}}
|
2022-09-29 15:36:01 +01:00
|
|
|
d, setts := newForTest(t, nil, filters)
|
2021-02-04 12:12:34 +00:00
|
|
|
|
2023-07-12 13:13:31 +01:00
|
|
|
err := d.setFilters(filters, whiteFilters, false)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
t.Cleanup(d.Close)
|
2020-02-26 16:58:25 +00:00
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Matched by white filter.
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err := d.CheckHost("host1", dns.TypeA, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2021-01-13 13:56:05 +00:00
|
|
|
assert.False(t, res.IsFiltered)
|
|
|
|
assert.Equal(t, res.Reason, NotFilteredAllowList)
|
2021-06-17 12:09:16 +01:00
|
|
|
|
2021-03-11 14:32:58 +00:00
|
|
|
require.Len(t, res.Rules, 1)
|
2021-06-17 12:09:16 +01:00
|
|
|
|
2021-03-11 14:32:58 +00:00
|
|
|
assert.Equal(t, "||host1^", res.Rules[0].Text)
|
2020-02-26 16:58:25 +00:00
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Not matched by white filter, but matched by block filter.
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err = d.CheckHost("host2", dns.TypeA, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2021-01-13 13:56:05 +00:00
|
|
|
assert.True(t, res.IsFiltered)
|
|
|
|
assert.Equal(t, res.Reason, FilteredBlockList)
|
2021-06-17 12:09:16 +01:00
|
|
|
|
2021-03-11 14:32:58 +00:00
|
|
|
require.Len(t, res.Rules, 1)
|
2021-06-17 12:09:16 +01:00
|
|
|
|
2021-03-11 14:32:58 +00:00
|
|
|
assert.Equal(t, "||host2^", res.Rules[0].Text)
|
2020-02-26 16:58:25 +00:00
|
|
|
}
|
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Client Settings.
|
2019-05-28 12:14:12 +01:00
|
|
|
|
2021-05-21 14:15:47 +01:00
|
|
|
func applyClientSettings(setts *Settings) {
|
2019-05-28 12:14:12 +01:00
|
|
|
setts.FilteringEnabled = false
|
|
|
|
setts.ParentalEnabled = false
|
2019-07-15 12:03:22 +01:00
|
|
|
setts.SafeBrowsingEnabled = true
|
2019-07-23 10:21:37 +01:00
|
|
|
|
2019-11-27 12:11:46 +00:00
|
|
|
rule, _ := rules.NewNetworkRule("||facebook.com^", 0)
|
2019-07-23 10:21:37 +01:00
|
|
|
s := ServiceEntry{}
|
|
|
|
s.Name = "facebook"
|
2019-11-27 12:11:46 +00:00
|
|
|
s.Rules = []*rules.NetworkRule{rule}
|
2019-07-23 10:21:37 +01:00
|
|
|
setts.ServicesRules = append(setts.ServicesRules, s)
|
2019-05-28 12:14:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestClientSettings(t *testing.T) {
|
2022-09-29 15:36:01 +01:00
|
|
|
d, setts := newForTest(t,
|
2021-01-29 13:09:31 +00:00
|
|
|
&Config{
|
2023-06-07 18:04:01 +01:00
|
|
|
ParentalEnabled: true,
|
|
|
|
SafeBrowsingEnabled: false,
|
|
|
|
SafeBrowsingChecker: newChecker(sbBlocked),
|
|
|
|
ParentalControlChecker: newChecker(pcBlocked),
|
2021-01-29 13:09:31 +00:00
|
|
|
},
|
|
|
|
[]Filter{{
|
|
|
|
ID: 0, Data: []byte("||example.org^\n"),
|
|
|
|
}},
|
|
|
|
)
|
|
|
|
t.Cleanup(d.Close)
|
2022-08-17 16:23:30 +01:00
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
type testCase struct {
|
|
|
|
name string
|
|
|
|
host string
|
|
|
|
before bool
|
|
|
|
wantReason Reason
|
|
|
|
}
|
|
|
|
testCases := []testCase{{
|
|
|
|
name: "filters",
|
|
|
|
host: "example.org",
|
|
|
|
before: true,
|
|
|
|
wantReason: FilteredBlockList,
|
|
|
|
}, {
|
|
|
|
name: "parental",
|
2022-08-17 16:23:30 +01:00
|
|
|
host: pcBlocked,
|
2021-01-29 13:09:31 +00:00
|
|
|
before: true,
|
|
|
|
wantReason: FilteredParental,
|
|
|
|
}, {
|
|
|
|
name: "safebrowsing",
|
2022-08-17 16:23:30 +01:00
|
|
|
host: sbBlocked,
|
2021-01-29 13:09:31 +00:00
|
|
|
before: false,
|
|
|
|
wantReason: FilteredSafeBrowsing,
|
|
|
|
}, {
|
|
|
|
name: "additional_rules",
|
|
|
|
host: "facebook.com",
|
|
|
|
before: false,
|
|
|
|
wantReason: FilteredBlockedService,
|
2020-02-26 16:58:25 +00:00
|
|
|
}}
|
2019-05-28 12:14:12 +01:00
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
makeTester := func(tc testCase, before bool) func(t *testing.T) {
|
|
|
|
return func(t *testing.T) {
|
2021-10-20 17:52:13 +01:00
|
|
|
t.Helper()
|
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
r, err := d.CheckHost(tc.host, dns.TypeA, setts)
|
2021-10-20 17:52:13 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
if before {
|
|
|
|
assert.True(t, r.IsFiltered)
|
|
|
|
assert.Equal(t, tc.wantReason, r.Reason)
|
|
|
|
} else {
|
|
|
|
assert.False(t, r.IsFiltered)
|
|
|
|
}
|
|
|
|
}
|
2019-05-28 12:14:12 +01:00
|
|
|
}
|
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Check behaviour without any per-client settings, then apply per-client
|
2021-10-20 17:52:13 +01:00
|
|
|
// settings and check behavior once again.
|
2021-01-29 13:09:31 +00:00
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(tc.name, makeTester(tc, tc.before))
|
2019-07-15 12:03:22 +01:00
|
|
|
}
|
|
|
|
|
2022-09-29 15:36:01 +01:00
|
|
|
applyClientSettings(setts)
|
2019-05-28 12:14:12 +01:00
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(tc.name, makeTester(tc, !tc.before))
|
2019-07-15 12:03:22 +01:00
|
|
|
}
|
2019-05-28 12:14:12 +01:00
|
|
|
}
|
|
|
|
|
2021-01-29 13:09:31 +00:00
|
|
|
// Benchmarks.
|
2018-10-03 22:20:53 +01:00
|
|
|
|
2018-08-30 15:25:33 +01:00
|
|
|
func BenchmarkSafeBrowsing(b *testing.B) {
|
2023-06-07 18:04:01 +01:00
|
|
|
d, setts := newForTest(b, &Config{
|
|
|
|
SafeBrowsingEnabled: true,
|
|
|
|
SafeBrowsingChecker: newChecker(sbBlocked),
|
|
|
|
}, nil)
|
2021-01-29 13:09:31 +00:00
|
|
|
b.Cleanup(d.Close)
|
2022-08-17 16:23:30 +01:00
|
|
|
|
2024-05-15 11:34:12 +01:00
|
|
|
for range b.N {
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err := d.CheckHost(sbBlocked, dns.TypeA, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoError(b, err)
|
|
|
|
|
2022-08-17 16:23:30 +01:00
|
|
|
assert.Truef(b, res.IsFiltered, "expected hostname %q to match", sbBlocked)
|
2018-08-30 15:25:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkSafeBrowsingParallel(b *testing.B) {
|
2023-06-07 18:04:01 +01:00
|
|
|
d, setts := newForTest(b, &Config{
|
|
|
|
SafeBrowsingEnabled: true,
|
|
|
|
SafeBrowsingChecker: newChecker(sbBlocked),
|
|
|
|
}, nil)
|
2021-01-29 13:09:31 +00:00
|
|
|
b.Cleanup(d.Close)
|
2022-08-17 16:23:30 +01:00
|
|
|
|
2018-08-30 15:25:33 +01:00
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
2022-09-29 15:36:01 +01:00
|
|
|
res, err := d.CheckHost(sbBlocked, dns.TypeA, setts)
|
2021-06-17 12:09:16 +01:00
|
|
|
require.NoError(b, err)
|
|
|
|
|
2022-08-17 16:23:30 +01:00
|
|
|
assert.Truef(b, res.IsFiltered, "expected hostname %q to match", sbBlocked)
|
2018-08-30 15:25:33 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|