Pull request #886: all: allow multiple rules in dns filter results
Merge in DNS/adguard-home from 2102-rules-result to master Updates #2102. Squashed commit of the following: commit 47b2aa94c56b37be492c3c01e8111054612d9722 Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Thu Dec 17 13:12:27 2020 +0300 querylog: remove pre-v0.99.3 compatibility code commit 2af0ee43c2444a7d842fcff057f2ba02f300244b Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Thu Dec 17 13:00:27 2020 +0300 all: improve documentation commit 3add300a42f0aa67bb315a448e294636c85d0b3b Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Wed Dec 16 18:30:01 2020 +0300 all: improve changelog commit e04ef701fc2de7f4453729e617641c47e0883679 Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Wed Dec 16 17:56:53 2020 +0300 all: improve code and documentation commit 4f04845ae275ae4291869e00c62e4ff81b01eaa3 Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Wed Dec 16 17:01:08 2020 +0300 all: document changes, improve api commit bc59b7656a402d0c65f13bd74a71d8dda6a8a65d Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Tue Dec 15 18:22:01 2020 +0300 all: allow multiple rules in dns filter results
This commit is contained in:
@@ -188,7 +188,7 @@ func BlockedSvcKnown(s string) bool {
|
||||
}
|
||||
|
||||
// ApplyBlockedServices - set blocked services settings for this DNS request
|
||||
func (d *Dnsfilter) ApplyBlockedServices(setts *RequestFilteringSettings, list []string, global bool) {
|
||||
func (d *DNSFilter) ApplyBlockedServices(setts *RequestFilteringSettings, list []string, global bool) {
|
||||
setts.ServicesRules = []ServiceEntry{}
|
||||
if global {
|
||||
d.confLock.RLock()
|
||||
@@ -210,7 +210,7 @@ func (d *Dnsfilter) ApplyBlockedServices(setts *RequestFilteringSettings, list [
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleBlockedServicesList(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleBlockedServicesList(w http.ResponseWriter, r *http.Request) {
|
||||
d.confLock.RLock()
|
||||
list := d.Config.BlockedServices
|
||||
d.confLock.RUnlock()
|
||||
@@ -223,7 +223,7 @@ func (d *Dnsfilter) handleBlockedServicesList(w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleBlockedServicesSet(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleBlockedServicesSet(w http.ResponseWriter, r *http.Request) {
|
||||
list := []string{}
|
||||
err := json.NewDecoder(r.Body).Decode(&list)
|
||||
if err != nil {
|
||||
@@ -241,7 +241,7 @@ func (d *Dnsfilter) handleBlockedServicesSet(w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
|
||||
// registerBlockedServicesHandlers - register HTTP handlers
|
||||
func (d *Dnsfilter) registerBlockedServicesHandlers() {
|
||||
func (d *DNSFilter) registerBlockedServicesHandlers() {
|
||||
d.Config.HTTPRegister("GET", "/control/blocked_services/list", d.handleBlockedServicesList)
|
||||
d.Config.HTTPRegister("POST", "/control/blocked_services/set", d.handleBlockedServicesSet)
|
||||
}
|
||||
|
||||
@@ -91,8 +91,8 @@ type filtersInitializerParams struct {
|
||||
blockFilters []Filter
|
||||
}
|
||||
|
||||
// Dnsfilter holds added rules and performs hostname matches against the rules
|
||||
type Dnsfilter struct {
|
||||
// DNSFilter matches hostnames and DNS requests against filtering rules.
|
||||
type DNSFilter struct {
|
||||
rulesStorage *filterlist.RuleStorage
|
||||
filteringEngine *urlfilter.DNSEngine
|
||||
rulesStorageWhite *filterlist.RuleStorage
|
||||
@@ -129,7 +129,7 @@ const (
|
||||
NotFilteredNotFound Reason = iota
|
||||
// NotFilteredWhiteList - the host is explicitly whitelisted
|
||||
NotFilteredWhiteList
|
||||
// NotFilteredError is return where there was an error during
|
||||
// NotFilteredError is returned when there was an error during
|
||||
// checking. Reserved, currently unused.
|
||||
NotFilteredError
|
||||
|
||||
@@ -148,27 +148,32 @@ const (
|
||||
// FilteredBlockedService - the host is blocked by "blocked services" settings
|
||||
FilteredBlockedService
|
||||
|
||||
// ReasonRewrite - rewrite rule was applied
|
||||
// ReasonRewrite is returned when there was a rewrite by
|
||||
// a legacy DNS Rewrite rule.
|
||||
ReasonRewrite
|
||||
|
||||
// RewriteEtcHosts - rewrite by /etc/hosts rule
|
||||
RewriteEtcHosts
|
||||
// RewriteAutoHosts is returned when there was a rewrite by
|
||||
// autohosts rules (/etc/hosts and so on).
|
||||
RewriteAutoHosts
|
||||
)
|
||||
|
||||
// TODO(a.garipov): Resync with actual code names or replace completely
|
||||
// in HTTP API v1.
|
||||
var reasonNames = []string{
|
||||
"NotFilteredNotFound",
|
||||
"NotFilteredWhiteList",
|
||||
"NotFilteredError",
|
||||
NotFilteredNotFound: "NotFilteredNotFound",
|
||||
NotFilteredWhiteList: "NotFilteredWhiteList",
|
||||
NotFilteredError: "NotFilteredError",
|
||||
|
||||
"FilteredBlackList",
|
||||
"FilteredSafeBrowsing",
|
||||
"FilteredParental",
|
||||
"FilteredInvalid",
|
||||
"FilteredSafeSearch",
|
||||
"FilteredBlockedService",
|
||||
FilteredBlackList: "FilteredBlackList",
|
||||
FilteredSafeBrowsing: "FilteredSafeBrowsing",
|
||||
FilteredParental: "FilteredParental",
|
||||
FilteredInvalid: "FilteredInvalid",
|
||||
FilteredSafeSearch: "FilteredSafeSearch",
|
||||
FilteredBlockedService: "FilteredBlockedService",
|
||||
|
||||
"Rewrite",
|
||||
"RewriteEtcHosts",
|
||||
ReasonRewrite: "Rewrite",
|
||||
|
||||
RewriteAutoHosts: "RewriteEtcHosts",
|
||||
}
|
||||
|
||||
func (r Reason) String() string {
|
||||
@@ -189,7 +194,7 @@ func (r Reason) In(reasons ...Reason) bool {
|
||||
}
|
||||
|
||||
// GetConfig - get configuration
|
||||
func (d *Dnsfilter) GetConfig() RequestFilteringSettings {
|
||||
func (d *DNSFilter) GetConfig() RequestFilteringSettings {
|
||||
c := RequestFilteringSettings{}
|
||||
// d.confLock.RLock()
|
||||
c.SafeSearchEnabled = d.Config.SafeSearchEnabled
|
||||
@@ -200,7 +205,7 @@ func (d *Dnsfilter) GetConfig() RequestFilteringSettings {
|
||||
}
|
||||
|
||||
// WriteDiskConfig - write configuration
|
||||
func (d *Dnsfilter) WriteDiskConfig(c *Config) {
|
||||
func (d *DNSFilter) WriteDiskConfig(c *Config) {
|
||||
d.confLock.Lock()
|
||||
*c = d.Config
|
||||
c.Rewrites = rewriteArrayDup(d.Config.Rewrites)
|
||||
@@ -211,7 +216,7 @@ func (d *Dnsfilter) WriteDiskConfig(c *Config) {
|
||||
// SetFilters - set new filters (synchronously or asynchronously)
|
||||
// When filters are set asynchronously, the old filters continue working until the new filters are ready.
|
||||
// In this case the caller must ensure that the old filter files are intact.
|
||||
func (d *Dnsfilter) SetFilters(blockFilters, allowFilters []Filter, async bool) error {
|
||||
func (d *DNSFilter) SetFilters(blockFilters, allowFilters []Filter, async bool) error {
|
||||
if async {
|
||||
params := filtersInitializerParams{
|
||||
allowFilters: allowFilters,
|
||||
@@ -245,7 +250,7 @@ func (d *Dnsfilter) SetFilters(blockFilters, allowFilters []Filter, async bool)
|
||||
}
|
||||
|
||||
// Starts initializing new filters by signal from channel
|
||||
func (d *Dnsfilter) filtersInitializer() {
|
||||
func (d *DNSFilter) filtersInitializer() {
|
||||
for {
|
||||
params := <-d.filtersInitializerChan
|
||||
err := d.initFiltering(params.allowFilters, params.blockFilters)
|
||||
@@ -257,13 +262,13 @@ func (d *Dnsfilter) filtersInitializer() {
|
||||
}
|
||||
|
||||
// Close - close the object
|
||||
func (d *Dnsfilter) Close() {
|
||||
func (d *DNSFilter) Close() {
|
||||
d.engineLock.Lock()
|
||||
defer d.engineLock.Unlock()
|
||||
d.reset()
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) reset() {
|
||||
func (d *DNSFilter) reset() {
|
||||
var err error
|
||||
|
||||
if d.rulesStorage != nil {
|
||||
@@ -290,34 +295,60 @@ type dnsFilterContext struct {
|
||||
|
||||
var gctx dnsFilterContext // global dnsfilter context
|
||||
|
||||
// Result holds state of hostname check
|
||||
type Result struct {
|
||||
IsFiltered bool `json:",omitempty"` // True if the host name is filtered
|
||||
Reason Reason `json:",omitempty"` // Reason for blocking / unblocking
|
||||
Rule string `json:",omitempty"` // Original rule text
|
||||
IP net.IP `json:",omitempty"` // Not nil only in the case of a hosts file syntax
|
||||
FilterID int64 `json:",omitempty"` // Filter ID the rule belongs to
|
||||
|
||||
// for ReasonRewrite:
|
||||
CanonName string `json:",omitempty"` // CNAME value
|
||||
|
||||
// for RewriteEtcHosts:
|
||||
ReverseHosts []string `json:",omitempty"`
|
||||
|
||||
// for ReasonRewrite & RewriteEtcHosts:
|
||||
IPList []net.IP `json:",omitempty"` // list of IP addresses
|
||||
|
||||
// for FilteredBlockedService:
|
||||
ServiceName string `json:",omitempty"` // Name of the blocked service
|
||||
// ResultRule contains information about applied rules.
|
||||
type ResultRule struct {
|
||||
// FilterListID is the ID of the rule's filter list.
|
||||
FilterListID int64 `json:",omitempty"`
|
||||
// Text is the text of the rule.
|
||||
Text string `json:",omitempty"`
|
||||
// IP is the host IP. It is nil unless the rule uses the
|
||||
// /etc/hosts syntax or the reason is FilteredSafeSearch.
|
||||
IP net.IP `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Matched can be used to see if any match at all was found, no matter filtered or not
|
||||
// Result contains the result of a request check.
|
||||
//
|
||||
// All fields transitively have omitempty tags so that the query log
|
||||
// doesn't become too large.
|
||||
//
|
||||
// TODO(a.garipov): Clarify relationships between fields. Perhaps
|
||||
// replace with a sum type or an interface?
|
||||
type Result struct {
|
||||
// IsFiltered is true if the request is filtered.
|
||||
IsFiltered bool `json:",omitempty"`
|
||||
|
||||
// Reason is the reason for blocking or unblocking the request.
|
||||
Reason Reason `json:",omitempty"`
|
||||
|
||||
// Rules are applied rules. If Rules are not empty, each rule
|
||||
// is not nil.
|
||||
Rules []*ResultRule `json:",omitempty"`
|
||||
|
||||
// ReverseHosts is the reverse lookup rewrite result. It is
|
||||
// empty unless Reason is set to RewriteAutoHosts.
|
||||
ReverseHosts []string `json:",omitempty"`
|
||||
|
||||
// IPList is the lookup rewrite result. It is empty unless
|
||||
// Reason is set to RewriteAutoHosts or ReasonRewrite.
|
||||
IPList []net.IP `json:",omitempty"`
|
||||
|
||||
// CanonName is the CNAME value from the lookup rewrite result.
|
||||
// It is empty unless Reason is set to ReasonRewrite.
|
||||
CanonName string `json:",omitempty"`
|
||||
|
||||
// ServiceName is the name of the blocked service. It is empty
|
||||
// unless Reason is set to FilteredBlockedService.
|
||||
ServiceName string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Matched returns true if any match at all was found regardless of
|
||||
// whether it was filtered or not.
|
||||
func (r Reason) Matched() bool {
|
||||
return r != NotFilteredNotFound
|
||||
}
|
||||
|
||||
// CheckHostRules tries to match the host against filtering rules only
|
||||
func (d *Dnsfilter) CheckHostRules(host string, qtype uint16, setts *RequestFilteringSettings) (Result, error) {
|
||||
// CheckHostRules tries to match the host against filtering rules only.
|
||||
func (d *DNSFilter) CheckHostRules(host string, qtype uint16, setts *RequestFilteringSettings) (Result, error) {
|
||||
if !setts.FilteringEnabled {
|
||||
return Result{}, nil
|
||||
}
|
||||
@@ -325,9 +356,9 @@ func (d *Dnsfilter) CheckHostRules(host string, qtype uint16, setts *RequestFilt
|
||||
return d.matchHost(host, qtype, *setts)
|
||||
}
|
||||
|
||||
// CheckHost tries to match the host against filtering rules,
|
||||
// then safebrowsing and parental if they are enabled
|
||||
func (d *Dnsfilter) CheckHost(host string, qtype uint16, setts *RequestFilteringSettings) (Result, error) {
|
||||
// CheckHost tries to match the host against filtering rules, then
|
||||
// safebrowsing and parental control rules, if they are enabled.
|
||||
func (d *DNSFilter) CheckHost(host string, qtype uint16, setts *RequestFilteringSettings) (Result, error) {
|
||||
// sometimes DNS clients will try to resolve ".", which is a request to get root servers
|
||||
if host == "" {
|
||||
return Result{Reason: NotFilteredNotFound}, nil
|
||||
@@ -413,10 +444,10 @@ func (d *Dnsfilter) CheckHost(host string, qtype uint16, setts *RequestFiltering
|
||||
return Result{}, nil
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) checkAutoHosts(host string, qtype uint16, result *Result) (matched bool) {
|
||||
func (d *DNSFilter) checkAutoHosts(host string, qtype uint16, result *Result) (matched bool) {
|
||||
ips := d.Config.AutoHosts.Process(host, qtype)
|
||||
if ips != nil {
|
||||
result.Reason = RewriteEtcHosts
|
||||
result.Reason = RewriteAutoHosts
|
||||
result.IPList = ips
|
||||
|
||||
return true
|
||||
@@ -424,7 +455,7 @@ func (d *Dnsfilter) checkAutoHosts(host string, qtype uint16, result *Result) (m
|
||||
|
||||
revHosts := d.Config.AutoHosts.ProcessReverse(host, qtype)
|
||||
if len(revHosts) != 0 {
|
||||
result.Reason = RewriteEtcHosts
|
||||
result.Reason = RewriteAutoHosts
|
||||
|
||||
// TODO(a.garipov): Optimize this with a buffer.
|
||||
result.ReverseHosts = make([]string, len(revHosts))
|
||||
@@ -445,7 +476,7 @@ func (d *Dnsfilter) checkAutoHosts(host string, qtype uint16, result *Result) (m
|
||||
// . repeat for the new domain name (Note: we return only the last CNAME)
|
||||
// . Find A or AAAA record for a domain name (exact match or by wildcard)
|
||||
// . if found, set IP addresses (IPv4 or IPv6 depending on qtype) in Result.IPList array
|
||||
func (d *Dnsfilter) processRewrites(host string, qtype uint16) Result {
|
||||
func (d *DNSFilter) processRewrites(host string, qtype uint16) Result {
|
||||
var res Result
|
||||
|
||||
d.confLock.RLock()
|
||||
@@ -504,9 +535,16 @@ func matchBlockedServicesRules(host string, svcs []ServiceEntry) Result {
|
||||
res.Reason = FilteredBlockedService
|
||||
res.IsFiltered = true
|
||||
res.ServiceName = s.Name
|
||||
res.Rule = rule.Text()
|
||||
log.Debug("Blocked Services: matched rule: %s host: %s service: %s",
|
||||
res.Rule, host, s.Name)
|
||||
|
||||
ruleText := rule.Text()
|
||||
res.Rules = []*ResultRule{{
|
||||
FilterListID: int64(rule.GetFilterListID()),
|
||||
Text: ruleText,
|
||||
}}
|
||||
|
||||
log.Debug("blocked services: matched rule: %s host: %s service: %s",
|
||||
ruleText, host, s.Name)
|
||||
|
||||
return res
|
||||
}
|
||||
}
|
||||
@@ -573,7 +611,7 @@ func createFilteringEngine(filters []Filter) (*filterlist.RuleStorage, *urlfilte
|
||||
}
|
||||
|
||||
// Initialize urlfilter objects.
|
||||
func (d *Dnsfilter) initFiltering(allowFilters, blockFilters []Filter) error {
|
||||
func (d *DNSFilter) initFiltering(allowFilters, blockFilters []Filter) error {
|
||||
rulesStorage, filteringEngine, err := createFilteringEngine(blockFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -600,7 +638,7 @@ func (d *Dnsfilter) initFiltering(allowFilters, blockFilters []Filter) 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, qtype uint16, setts RequestFilteringSettings) (Result, error) {
|
||||
func (d *DNSFilter) matchHost(host string, qtype uint16, setts RequestFilteringSettings) (Result, error) {
|
||||
d.engineLock.RLock()
|
||||
// Keep in mind that this lock must be held no just when calling Match()
|
||||
// but also while using the rules returned by it.
|
||||
@@ -658,7 +696,8 @@ func (d *Dnsfilter) matchHost(host string, qtype uint16, setts RequestFilteringS
|
||||
log.Debug("Filtering: found rule for host %q: %q list_id: %d",
|
||||
host, rule.Text(), rule.GetFilterListID())
|
||||
res := makeResult(rule, FilteredBlackList)
|
||||
res.IP = rule.IP.To4()
|
||||
res.Rules[0].IP = rule.IP.To4()
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -667,7 +706,8 @@ func (d *Dnsfilter) matchHost(host string, qtype uint16, setts RequestFilteringS
|
||||
log.Debug("Filtering: found rule for host %q: %q list_id: %d",
|
||||
host, rule.Text(), rule.GetFilterListID())
|
||||
res := makeResult(rule, FilteredBlackList)
|
||||
res.IP = rule.IP
|
||||
res.Rules[0].IP = rule.IP
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -683,22 +723,28 @@ func (d *Dnsfilter) matchHost(host string, qtype uint16, setts RequestFilteringS
|
||||
log.Debug("Filtering: found rule for host %q: %q list_id: %d",
|
||||
host, rule.Text(), rule.GetFilterListID())
|
||||
res := makeResult(rule, FilteredBlackList)
|
||||
res.IP = net.IP{}
|
||||
res.Rules[0].IP = net.IP{}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
return Result{}, nil
|
||||
}
|
||||
|
||||
// Construct Result object
|
||||
// makeResult returns a properly constructed Result.
|
||||
func makeResult(rule rules.Rule, reason Reason) Result {
|
||||
res := Result{}
|
||||
res.FilterID = int64(rule.GetFilterListID())
|
||||
res.Rule = rule.Text()
|
||||
res.Reason = reason
|
||||
res := Result{
|
||||
Reason: reason,
|
||||
Rules: []*ResultRule{{
|
||||
FilterListID: int64(rule.GetFilterListID()),
|
||||
Text: rule.Text(),
|
||||
}},
|
||||
}
|
||||
|
||||
if reason == FilteredBlackList {
|
||||
res.IsFiltered = true
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -708,7 +754,7 @@ func InitModule() {
|
||||
}
|
||||
|
||||
// New creates properly initialized DNS Filter that is ready to be used.
|
||||
func New(c *Config, blockFilters []Filter) *Dnsfilter {
|
||||
func New(c *Config, blockFilters []Filter) *DNSFilter {
|
||||
if c != nil {
|
||||
cacheConf := cache.Config{
|
||||
EnableLRU: true,
|
||||
@@ -730,7 +776,7 @@ func New(c *Config, blockFilters []Filter) *Dnsfilter {
|
||||
}
|
||||
}
|
||||
|
||||
d := new(Dnsfilter)
|
||||
d := new(DNSFilter)
|
||||
|
||||
err := d.initSecurityServices()
|
||||
if err != nil {
|
||||
@@ -768,7 +814,7 @@ func New(c *Config, blockFilters []Filter) *Dnsfilter {
|
||||
// Start - start the module:
|
||||
// . start async filtering initializer goroutine
|
||||
// . register web handlers
|
||||
func (d *Dnsfilter) Start() {
|
||||
func (d *DNSFilter) Start() {
|
||||
d.filtersInitializerChan = make(chan filtersInitializerParams, 1)
|
||||
go d.filtersInitializer()
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ func purgeCaches() {
|
||||
}
|
||||
}
|
||||
|
||||
func NewForTest(c *Config, filters []Filter) *Dnsfilter {
|
||||
func NewForTest(c *Config, filters []Filter) *DNSFilter {
|
||||
setts = RequestFilteringSettings{}
|
||||
setts.FilteringEnabled = true
|
||||
if c != nil {
|
||||
@@ -58,38 +58,48 @@ func NewForTest(c *Config, filters []Filter) *Dnsfilter {
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) checkMatch(t *testing.T, hostname string) {
|
||||
func (d *DNSFilter) checkMatch(t *testing.T, hostname string) {
|
||||
t.Helper()
|
||||
ret, err := d.CheckHost(hostname, dns.TypeA, &setts)
|
||||
res, err := d.CheckHost(hostname, dns.TypeA, &setts)
|
||||
if err != nil {
|
||||
t.Errorf("Error while matching host %s: %s", hostname, err)
|
||||
}
|
||||
if !ret.IsFiltered {
|
||||
if !res.IsFiltered {
|
||||
t.Errorf("Expected hostname %s to match", hostname)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) checkMatchIP(t *testing.T, hostname, ip string, qtype uint16) {
|
||||
func (d *DNSFilter) checkMatchIP(t *testing.T, hostname, ip string, qtype uint16) {
|
||||
t.Helper()
|
||||
ret, err := d.CheckHost(hostname, qtype, &setts)
|
||||
|
||||
res, err := d.CheckHost(hostname, qtype, &setts)
|
||||
if err != nil {
|
||||
t.Errorf("Error while matching host %s: %s", hostname, err)
|
||||
}
|
||||
if !ret.IsFiltered {
|
||||
|
||||
if !res.IsFiltered {
|
||||
t.Errorf("Expected hostname %s to match", hostname)
|
||||
}
|
||||
if ret.IP == nil || ret.IP.String() != ip {
|
||||
t.Errorf("Expected ip %s to match, actual: %v", ip, ret.IP)
|
||||
|
||||
if len(res.Rules) == 0 {
|
||||
t.Errorf("Expected result to have rules")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r := res.Rules[0]
|
||||
if r.IP == nil || r.IP.String() != ip {
|
||||
t.Errorf("Expected ip %s to match, actual: %v", ip, r.IP)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) checkMatchEmpty(t *testing.T, hostname string) {
|
||||
func (d *DNSFilter) checkMatchEmpty(t *testing.T, hostname string) {
|
||||
t.Helper()
|
||||
ret, err := d.CheckHost(hostname, dns.TypeA, &setts)
|
||||
res, err := d.CheckHost(hostname, dns.TypeA, &setts)
|
||||
if err != nil {
|
||||
t.Errorf("Error while matching host %s: %s", hostname, err)
|
||||
}
|
||||
if ret.IsFiltered {
|
||||
if res.IsFiltered {
|
||||
t.Errorf("Expected hostname %s to not match", hostname)
|
||||
}
|
||||
}
|
||||
@@ -120,26 +130,43 @@ func TestEtcHostsMatching(t *testing.T) {
|
||||
d.checkMatchIP(t, "block.com", "0.0.0.0", dns.TypeA)
|
||||
|
||||
// ...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)
|
||||
assert.True(t, ret.Rule == "0.0.0.0 block.com")
|
||||
res, err := d.CheckHost("block.com", dns.TypeAAAA, &setts)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, res.IsFiltered)
|
||||
if assert.Len(t, res.Rules, 1) {
|
||||
assert.Equal(t, "0.0.0.0 block.com", res.Rules[0].Text)
|
||||
assert.Len(t, res.Rules[0].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)
|
||||
res, err = d.CheckHost("ipv6.com", dns.TypeA, &setts)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, res.IsFiltered)
|
||||
if assert.Len(t, res.Rules, 1) {
|
||||
assert.Equal(t, "::1 ipv6.com", res.Rules[0].Text)
|
||||
assert.Len(t, res.Rules[0].IP, 0)
|
||||
}
|
||||
|
||||
// 2 IPv4 (return only the first one)
|
||||
ret, err = d.CheckHost("host2", dns.TypeA, &setts)
|
||||
assert.True(t, err == nil && ret.IsFiltered)
|
||||
assert.True(t, ret.IP != nil && ret.IP.Equal(net.ParseIP("0.0.0.1")))
|
||||
res, err = d.CheckHost("host2", dns.TypeA, &setts)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, res.IsFiltered)
|
||||
if assert.Len(t, res.Rules, 1) {
|
||||
loopback4 := net.IP{0, 0, 0, 1}
|
||||
assert.Equal(t, res.Rules[0].IP, loopback4)
|
||||
}
|
||||
|
||||
// ...and 1 IPv6 address
|
||||
ret, err = d.CheckHost("host2", dns.TypeAAAA, &setts)
|
||||
assert.True(t, err == nil && ret.IsFiltered)
|
||||
assert.True(t, ret.IP != nil && ret.IP.Equal(net.ParseIP("::1")))
|
||||
res, err = d.CheckHost("host2", dns.TypeAAAA, &setts)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, res.IsFiltered)
|
||||
if assert.Len(t, res.Rules, 1) {
|
||||
loopback6 := net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
|
||||
assert.Equal(t, res.Rules[0].IP, loopback6)
|
||||
}
|
||||
}
|
||||
|
||||
// SAFE BROWSING
|
||||
@@ -206,13 +233,11 @@ func TestCheckHostSafeSearchYandex(t *testing.T) {
|
||||
|
||||
// Check host for each domain
|
||||
for _, host := range yandex {
|
||||
result, err := d.CheckHost(host, dns.TypeA, &setts)
|
||||
if err != nil {
|
||||
t.Errorf("SafeSearch doesn't work for yandex domain `%s` cause %s", host, err)
|
||||
}
|
||||
|
||||
if result.IP.String() != "213.180.193.56" {
|
||||
t.Errorf("SafeSearch doesn't work for yandex domain `%s`", host)
|
||||
res, err := d.CheckHost(host, dns.TypeA, &setts)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, res.IsFiltered)
|
||||
if assert.Len(t, res.Rules, 1) {
|
||||
assert.Equal(t, res.Rules[0].IP.String(), "213.180.193.56")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,13 +251,11 @@ func TestCheckHostSafeSearchGoogle(t *testing.T) {
|
||||
|
||||
// Check host for each domain
|
||||
for _, host := range googleDomains {
|
||||
result, err := d.CheckHost(host, dns.TypeA, &setts)
|
||||
if err != nil {
|
||||
t.Errorf("SafeSearch doesn't work for %s cause %s", host, err)
|
||||
}
|
||||
|
||||
if result.IP == nil {
|
||||
t.Errorf("SafeSearch doesn't work for %s", host)
|
||||
res, err := d.CheckHost(host, dns.TypeA, &setts)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, res.IsFiltered)
|
||||
if assert.Len(t, res.Rules, 1) {
|
||||
assert.NotEqual(t, res.Rules[0].IP.String(), "0.0.0.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,40 +265,30 @@ func TestSafeSearchCacheYandex(t *testing.T) {
|
||||
defer d.Close()
|
||||
domain := "yandex.ru"
|
||||
|
||||
var result Result
|
||||
var err error
|
||||
|
||||
// Check host with disabled safesearch
|
||||
result, err = d.CheckHost(domain, dns.TypeA, &setts)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot check host due to %s", err)
|
||||
}
|
||||
if result.IP != nil {
|
||||
t.Fatalf("SafeSearch is not enabled but there is an answer for `%s` !", domain)
|
||||
}
|
||||
// Check host with disabled safesearch.
|
||||
res, err := d.CheckHost(domain, dns.TypeA, &setts)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, res.IsFiltered)
|
||||
assert.Len(t, res.Rules, 0)
|
||||
|
||||
d = NewForTest(&Config{SafeSearchEnabled: true}, nil)
|
||||
defer d.Close()
|
||||
|
||||
result, err = d.CheckHost(domain, dns.TypeA, &setts)
|
||||
res, err = d.CheckHost(domain, dns.TypeA, &setts)
|
||||
if err != nil {
|
||||
t.Fatalf("CheckHost for safesearh domain %s failed cause %s", domain, err)
|
||||
}
|
||||
|
||||
// Fir yandex we already know valid ip
|
||||
if result.IP.String() != "213.180.193.56" {
|
||||
t.Fatalf("Wrong IP for %s safesearch: %s", domain, result.IP.String())
|
||||
// For yandex we already know valid ip.
|
||||
if assert.Len(t, res.Rules, 1) {
|
||||
assert.Equal(t, res.Rules[0].IP.String(), "213.180.193.56")
|
||||
}
|
||||
|
||||
// Check cache
|
||||
// Check cache.
|
||||
cachedValue, isFound := getCachedResult(gctx.safeSearchCache, domain)
|
||||
|
||||
if !isFound {
|
||||
t.Fatalf("Safesearch cache doesn't work for %s!", domain)
|
||||
}
|
||||
|
||||
if cachedValue.IP.String() != "213.180.193.56" {
|
||||
t.Fatalf("Wrong IP in cache for %s safesearch: %s", domain, cachedValue.IP.String())
|
||||
assert.True(t, isFound)
|
||||
if assert.Len(t, cachedValue.Rules, 1) {
|
||||
assert.Equal(t, cachedValue.Rules[0].IP.String(), "213.180.193.56")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,13 +296,10 @@ func TestSafeSearchCacheGoogle(t *testing.T) {
|
||||
d := NewForTest(nil, nil)
|
||||
defer d.Close()
|
||||
domain := "www.google.ru"
|
||||
result, err := d.CheckHost(domain, dns.TypeA, &setts)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot check host due to %s", err)
|
||||
}
|
||||
if result.IP != nil {
|
||||
t.Fatalf("SafeSearch is not enabled but there is an answer!")
|
||||
}
|
||||
res, err := d.CheckHost(domain, dns.TypeA, &setts)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, res.IsFiltered)
|
||||
assert.Len(t, res.Rules, 0)
|
||||
|
||||
d = NewForTest(&Config{SafeSearchEnabled: true}, nil)
|
||||
defer d.Close()
|
||||
@@ -313,25 +323,17 @@ func TestSafeSearchCacheGoogle(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
result, err = d.CheckHost(domain, dns.TypeA, &setts)
|
||||
if err != nil {
|
||||
t.Fatalf("CheckHost for safesearh domain %s failed cause %s", domain, err)
|
||||
res, err = d.CheckHost(domain, dns.TypeA, &setts)
|
||||
assert.Nil(t, err)
|
||||
if assert.Len(t, res.Rules, 1) {
|
||||
assert.True(t, res.Rules[0].IP.Equal(ip))
|
||||
}
|
||||
|
||||
if result.IP.String() != ip.String() {
|
||||
t.Fatalf("Wrong IP for %s safesearch: %s. Should be: %s",
|
||||
domain, result.IP.String(), ip)
|
||||
}
|
||||
|
||||
// Check cache
|
||||
// Check cache.
|
||||
cachedValue, isFound := getCachedResult(gctx.safeSearchCache, domain)
|
||||
|
||||
if !isFound {
|
||||
t.Fatalf("Safesearch cache doesn't work for %s!", domain)
|
||||
}
|
||||
|
||||
if cachedValue.IP.String() != ip.String() {
|
||||
t.Fatalf("Wrong IP in cache for %s safesearch: %s", domain, cachedValue.IP.String())
|
||||
assert.True(t, isFound)
|
||||
if assert.Len(t, cachedValue.Rules, 1) {
|
||||
assert.True(t, cachedValue.Rules[0].IP.Equal(ip))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,15 +435,15 @@ func TestMatching(t *testing.T) {
|
||||
d := NewForTest(nil, filters)
|
||||
defer d.Close()
|
||||
|
||||
ret, err := d.CheckHost(test.hostname, test.dnsType, &setts)
|
||||
res, err := d.CheckHost(test.hostname, test.dnsType, &setts)
|
||||
if err != nil {
|
||||
t.Errorf("Error while matching host %s: %s", test.hostname, err)
|
||||
}
|
||||
if ret.IsFiltered != test.isFiltered {
|
||||
t.Errorf("Hostname %s has wrong result (%v must be %v)", test.hostname, ret.IsFiltered, test.isFiltered)
|
||||
if res.IsFiltered != test.isFiltered {
|
||||
t.Errorf("Hostname %s has wrong result (%v must be %v)", test.hostname, res.IsFiltered, test.isFiltered)
|
||||
}
|
||||
if ret.Reason != test.reason {
|
||||
t.Errorf("Hostname %s has wrong reason (%v must be %v)", test.hostname, ret.Reason.String(), test.reason.String())
|
||||
if res.Reason != test.reason {
|
||||
t.Errorf("Hostname %s has wrong reason (%v must be %v)", test.hostname, res.Reason.String(), test.reason.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -466,16 +468,20 @@ func TestWhitelist(t *testing.T) {
|
||||
defer d.Close()
|
||||
|
||||
// matched by white filter
|
||||
ret, err := d.CheckHost("host1", dns.TypeA, &setts)
|
||||
res, err := d.CheckHost("host1", dns.TypeA, &setts)
|
||||
assert.True(t, err == nil)
|
||||
assert.True(t, !ret.IsFiltered && ret.Reason == NotFilteredWhiteList)
|
||||
assert.True(t, ret.Rule == "||host1^")
|
||||
assert.True(t, !res.IsFiltered && res.Reason == NotFilteredWhiteList)
|
||||
if assert.Len(t, res.Rules, 1) {
|
||||
assert.True(t, res.Rules[0].Text == "||host1^")
|
||||
}
|
||||
|
||||
// not matched by white filter, but matched by block filter
|
||||
ret, err = d.CheckHost("host2", dns.TypeA, &setts)
|
||||
res, err = d.CheckHost("host2", dns.TypeA, &setts)
|
||||
assert.True(t, err == nil)
|
||||
assert.True(t, ret.IsFiltered && ret.Reason == FilteredBlackList)
|
||||
assert.True(t, ret.Rule == "||host2^")
|
||||
assert.True(t, res.IsFiltered && res.Reason == FilteredBlackList)
|
||||
if assert.Len(t, res.Rules, 1) {
|
||||
assert.True(t, res.Rules[0].Text == "||host2^")
|
||||
}
|
||||
}
|
||||
|
||||
// CLIENT SETTINGS
|
||||
@@ -559,11 +565,11 @@ func BenchmarkSafeBrowsing(b *testing.B) {
|
||||
defer d.Close()
|
||||
for n := 0; n < b.N; n++ {
|
||||
hostname := "wmconvirus.narod.ru"
|
||||
ret, err := d.CheckHost(hostname, dns.TypeA, &setts)
|
||||
res, err := d.CheckHost(hostname, dns.TypeA, &setts)
|
||||
if err != nil {
|
||||
b.Errorf("Error while matching host %s: %s", hostname, err)
|
||||
}
|
||||
if !ret.IsFiltered {
|
||||
if !res.IsFiltered {
|
||||
b.Errorf("Expected hostname %s to match", hostname)
|
||||
}
|
||||
}
|
||||
@@ -575,11 +581,11 @@ func BenchmarkSafeBrowsingParallel(b *testing.B) {
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
hostname := "wmconvirus.narod.ru"
|
||||
ret, err := d.CheckHost(hostname, dns.TypeA, &setts)
|
||||
res, err := d.CheckHost(hostname, dns.TypeA, &setts)
|
||||
if err != nil {
|
||||
b.Errorf("Error while matching host %s: %s", hostname, err)
|
||||
}
|
||||
if !ret.IsFiltered {
|
||||
if !res.IsFiltered {
|
||||
b.Errorf("Expected hostname %s to match", hostname)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ func (r *RewriteEntry) prepare() {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) prepareRewrites() {
|
||||
func (d *DNSFilter) prepareRewrites() {
|
||||
for i := range d.Rewrites {
|
||||
d.Rewrites[i].prepare()
|
||||
}
|
||||
@@ -148,7 +148,7 @@ type rewriteEntryJSON struct {
|
||||
Answer string `json:"answer"`
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleRewriteList(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleRewriteList(w http.ResponseWriter, r *http.Request) {
|
||||
arr := []*rewriteEntryJSON{}
|
||||
|
||||
d.confLock.Lock()
|
||||
@@ -169,7 +169,7 @@ func (d *Dnsfilter) handleRewriteList(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleRewriteAdd(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleRewriteAdd(w http.ResponseWriter, r *http.Request) {
|
||||
jsent := rewriteEntryJSON{}
|
||||
err := json.NewDecoder(r.Body).Decode(&jsent)
|
||||
if err != nil {
|
||||
@@ -191,7 +191,7 @@ func (d *Dnsfilter) handleRewriteAdd(w http.ResponseWriter, r *http.Request) {
|
||||
d.Config.ConfigModified()
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleRewriteDelete(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleRewriteDelete(w http.ResponseWriter, r *http.Request) {
|
||||
jsent := rewriteEntryJSON{}
|
||||
err := json.NewDecoder(r.Body).Decode(&jsent)
|
||||
if err != nil {
|
||||
@@ -218,7 +218,7 @@ func (d *Dnsfilter) handleRewriteDelete(w http.ResponseWriter, r *http.Request)
|
||||
d.Config.ConfigModified()
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) registerRewritesHandlers() {
|
||||
func (d *DNSFilter) registerRewritesHandlers() {
|
||||
d.Config.HTTPRegister("GET", "/control/rewrite/list", d.handleRewriteList)
|
||||
d.Config.HTTPRegister("POST", "/control/rewrite/add", d.handleRewriteAdd)
|
||||
d.Config.HTTPRegister("POST", "/control/rewrite/delete", d.handleRewriteDelete)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func TestRewrites(t *testing.T) {
|
||||
d := Dnsfilter{}
|
||||
d := DNSFilter{}
|
||||
// CNAME, A, AAAA
|
||||
d.Rewrites = []RewriteEntry{
|
||||
{"somecname", "somehost.com", 0, nil},
|
||||
@@ -104,7 +104,7 @@ func TestRewrites(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRewritesLevels(t *testing.T) {
|
||||
d := Dnsfilter{}
|
||||
d := DNSFilter{}
|
||||
// exact host, wildcard L2, wildcard L3
|
||||
d.Rewrites = []RewriteEntry{
|
||||
{"host.com", "1.1.1.1", 0, nil},
|
||||
@@ -133,7 +133,7 @@ func TestRewritesLevels(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRewritesExceptionCNAME(t *testing.T) {
|
||||
d := Dnsfilter{}
|
||||
d := DNSFilter{}
|
||||
// wildcard; exception for a sub-domain
|
||||
d.Rewrites = []RewriteEntry{
|
||||
{"*.host.com", "2.2.2.2", 0, nil},
|
||||
@@ -153,7 +153,7 @@ func TestRewritesExceptionCNAME(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRewritesExceptionWC(t *testing.T) {
|
||||
d := Dnsfilter{}
|
||||
d := DNSFilter{}
|
||||
// wildcard; exception for a sub-wildcard
|
||||
d.Rewrites = []RewriteEntry{
|
||||
{"*.host.com", "2.2.2.2", 0, nil},
|
||||
@@ -173,7 +173,7 @@ func TestRewritesExceptionWC(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRewritesExceptionIP(t *testing.T) {
|
||||
d := Dnsfilter{}
|
||||
d := DNSFilter{}
|
||||
// exception for AAAA record
|
||||
d.Rewrites = []RewriteEntry{
|
||||
{"host.com", "1.2.3.4", 0, nil},
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// Safe Browsing, Parental Control
|
||||
|
||||
package dnsfilter
|
||||
|
||||
import (
|
||||
@@ -22,6 +20,8 @@ import (
|
||||
"golang.org/x/net/publicsuffix"
|
||||
)
|
||||
|
||||
// Safe browsing and parental control methods.
|
||||
|
||||
const (
|
||||
dnsTimeout = 3 * time.Second
|
||||
defaultSafebrowsingServer = `https://dns-family.adguard.com/dns-query`
|
||||
@@ -30,7 +30,7 @@ const (
|
||||
pcTXTSuffix = `pc.dns.adguard.com.`
|
||||
)
|
||||
|
||||
func (d *Dnsfilter) initSecurityServices() error {
|
||||
func (d *DNSFilter) initSecurityServices() error {
|
||||
var err error
|
||||
d.safeBrowsingServer = defaultSafebrowsingServer
|
||||
d.parentalServer = defaultParentalServer
|
||||
@@ -287,7 +287,7 @@ func check(c *sbCtx, r Result, u upstream.Upstream) (Result, error) {
|
||||
return Result{}, nil
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) checkSafeBrowsing(host string) (Result, error) {
|
||||
func (d *DNSFilter) checkSafeBrowsing(host string) (Result, error) {
|
||||
if log.GetLevel() >= log.DEBUG {
|
||||
timer := log.StartTimer()
|
||||
defer timer.LogElapsed("SafeBrowsing lookup for %s", host)
|
||||
@@ -301,12 +301,14 @@ func (d *Dnsfilter) checkSafeBrowsing(host string) (Result, error) {
|
||||
res := Result{
|
||||
IsFiltered: true,
|
||||
Reason: FilteredSafeBrowsing,
|
||||
Rule: "adguard-malware-shavar",
|
||||
Rules: []*ResultRule{{
|
||||
Text: "adguard-malware-shavar",
|
||||
}},
|
||||
}
|
||||
return check(ctx, res, d.safeBrowsingUpstream)
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) checkParental(host string) (Result, error) {
|
||||
func (d *DNSFilter) checkParental(host string) (Result, error) {
|
||||
if log.GetLevel() >= log.DEBUG {
|
||||
timer := log.StartTimer()
|
||||
defer timer.LogElapsed("Parental lookup for %s", host)
|
||||
@@ -320,7 +322,9 @@ func (d *Dnsfilter) checkParental(host string) (Result, error) {
|
||||
res := Result{
|
||||
IsFiltered: true,
|
||||
Reason: FilteredParental,
|
||||
Rule: "parental CATEGORY_BLACKLISTED",
|
||||
Rules: []*ResultRule{{
|
||||
Text: "parental CATEGORY_BLACKLISTED",
|
||||
}},
|
||||
}
|
||||
return check(ctx, res, d.parentalUpstream)
|
||||
}
|
||||
@@ -331,17 +335,17 @@ func httpError(r *http.Request, w http.ResponseWriter, code int, format string,
|
||||
http.Error(w, text, code)
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleSafeBrowsingEnable(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleSafeBrowsingEnable(w http.ResponseWriter, r *http.Request) {
|
||||
d.Config.SafeBrowsingEnabled = true
|
||||
d.Config.ConfigModified()
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleSafeBrowsingDisable(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleSafeBrowsingDisable(w http.ResponseWriter, r *http.Request) {
|
||||
d.Config.SafeBrowsingEnabled = false
|
||||
d.Config.ConfigModified()
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) {
|
||||
data := map[string]interface{}{
|
||||
"enabled": d.Config.SafeBrowsingEnabled,
|
||||
}
|
||||
@@ -358,17 +362,17 @@ func (d *Dnsfilter) handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleParentalEnable(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleParentalEnable(w http.ResponseWriter, r *http.Request) {
|
||||
d.Config.ParentalEnabled = true
|
||||
d.Config.ConfigModified()
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleParentalDisable(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleParentalDisable(w http.ResponseWriter, r *http.Request) {
|
||||
d.Config.ParentalEnabled = false
|
||||
d.Config.ConfigModified()
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleParentalStatus(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleParentalStatus(w http.ResponseWriter, r *http.Request) {
|
||||
data := map[string]interface{}{
|
||||
"enabled": d.Config.ParentalEnabled,
|
||||
}
|
||||
@@ -386,7 +390,7 @@ func (d *Dnsfilter) handleParentalStatus(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) registerSecurityHandlers() {
|
||||
func (d *DNSFilter) registerSecurityHandlers() {
|
||||
d.Config.HTTPRegister("POST", "/control/safebrowsing/enable", d.handleSafeBrowsingEnable)
|
||||
d.Config.HTTPRegister("POST", "/control/safebrowsing/disable", d.handleSafeBrowsingDisable)
|
||||
d.Config.HTTPRegister("GET", "/control/safebrowsing/status", d.handleSafeBrowsingStatus)
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
expire byte[4]
|
||||
res Result
|
||||
*/
|
||||
func (d *Dnsfilter) setCacheResult(cache cache.Cache, host string, res Result) int {
|
||||
func (d *DNSFilter) setCacheResult(cache cache.Cache, host string, res Result) int {
|
||||
var buf bytes.Buffer
|
||||
|
||||
expire := uint(time.Now().Unix()) + d.Config.CacheTime*60
|
||||
@@ -63,12 +63,12 @@ func getCachedResult(cache cache.Cache, host string) (Result, bool) {
|
||||
}
|
||||
|
||||
// SafeSearchDomain returns replacement address for search engine
|
||||
func (d *Dnsfilter) SafeSearchDomain(host string) (string, bool) {
|
||||
func (d *DNSFilter) SafeSearchDomain(host string) (string, bool) {
|
||||
val, ok := safeSearchDomains[host]
|
||||
return val, ok
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) checkSafeSearch(host string) (Result, error) {
|
||||
func (d *DNSFilter) checkSafeSearch(host string) (Result, error) {
|
||||
if log.GetLevel() >= log.DEBUG {
|
||||
timer := log.StartTimer()
|
||||
defer timer.LogElapsed("SafeSearch: lookup for %s", host)
|
||||
@@ -87,49 +87,52 @@ func (d *Dnsfilter) checkSafeSearch(host string) (Result, error) {
|
||||
return Result{}, nil
|
||||
}
|
||||
|
||||
res := Result{IsFiltered: true, Reason: FilteredSafeSearch}
|
||||
res := Result{
|
||||
IsFiltered: true,
|
||||
Reason: FilteredSafeSearch,
|
||||
Rules: []*ResultRule{{}},
|
||||
}
|
||||
|
||||
if ip := net.ParseIP(safeHost); ip != nil {
|
||||
res.IP = ip
|
||||
res.Rules[0].IP = ip
|
||||
valLen := d.setCacheResult(gctx.safeSearchCache, host, res)
|
||||
log.Debug("SafeSearch: stored in cache: %s (%d bytes)", host, valLen)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// TODO this address should be resolved with upstream that was configured in dnsforward
|
||||
addrs, err := net.LookupIP(safeHost)
|
||||
ips, err := net.LookupIP(safeHost)
|
||||
if err != nil {
|
||||
log.Tracef("SafeSearchDomain for %s was found but failed to lookup for %s cause %s", host, safeHost, err)
|
||||
return Result{}, err
|
||||
}
|
||||
|
||||
for _, i := range addrs {
|
||||
if ipv4 := i.To4(); ipv4 != nil {
|
||||
res.IP = ipv4
|
||||
break
|
||||
for _, ip := range ips {
|
||||
if ipv4 := ip.To4(); ipv4 != nil {
|
||||
res.Rules[0].IP = ipv4
|
||||
|
||||
l := d.setCacheResult(gctx.safeSearchCache, host, res)
|
||||
log.Debug("SafeSearch: stored in cache: %s (%d bytes)", host, l)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(res.IP) == 0 {
|
||||
return Result{}, fmt.Errorf("no ipv4 addresses in safe search response for %s", safeHost)
|
||||
}
|
||||
|
||||
// Cache result
|
||||
valLen := d.setCacheResult(gctx.safeSearchCache, host, res)
|
||||
log.Debug("SafeSearch: stored in cache: %s (%d bytes)", host, valLen)
|
||||
return res, nil
|
||||
return Result{}, fmt.Errorf("no ipv4 addresses in safe search response for %s", safeHost)
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleSafeSearchEnable(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleSafeSearchEnable(w http.ResponseWriter, r *http.Request) {
|
||||
d.Config.SafeSearchEnabled = true
|
||||
d.Config.ConfigModified()
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleSafeSearchDisable(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleSafeSearchDisable(w http.ResponseWriter, r *http.Request) {
|
||||
d.Config.SafeSearchEnabled = false
|
||||
d.Config.ConfigModified()
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *DNSFilter) handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) {
|
||||
data := map[string]interface{}{
|
||||
"enabled": d.Config.SafeSearchEnabled,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user