+ dnsfilter: use AG DNS server for SB/PC services
* move SS/SB/PC services to security.go * remove old useless code (HTTP client)
This commit is contained in:
@@ -1,13 +1,7 @@
|
||||
package dnsfilter
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
@@ -16,30 +10,14 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/joomcode/errorx"
|
||||
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/cache"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/urlfilter"
|
||||
"github.com/bluele/gcache"
|
||||
"github.com/miekg/dns"
|
||||
"golang.org/x/net/publicsuffix"
|
||||
)
|
||||
|
||||
const defaultHTTPTimeout = 5 * time.Minute
|
||||
const defaultHTTPMaxIdleConnections = 100
|
||||
|
||||
const defaultSafebrowsingServer = "sb.adtidy.org"
|
||||
const defaultSafebrowsingURL = "%s://%s/safebrowsing-lookup-hash.html?prefixes=%s"
|
||||
const defaultParentalServer = "pctrl.adguard.com"
|
||||
const defaultParentalURL = "%s://%s/check-parental-control-hash?prefixes=%s&sensitivity=%d"
|
||||
const defaultParentalSensitivity = 13 // use "TEEN" by default
|
||||
const maxDialCacheSize = 2 // the number of host names for safebrowsing and parental control
|
||||
|
||||
// ServiceEntry - blocked service array element
|
||||
type ServiceEntry struct {
|
||||
Name string
|
||||
@@ -65,7 +43,6 @@ type RewriteEntry struct {
|
||||
type Config struct {
|
||||
ParentalSensitivity int `yaml:"parental_sensitivity"` // must be either 3, 10, 13 or 17
|
||||
ParentalEnabled bool `yaml:"parental_enabled"`
|
||||
UsePlainHTTP bool `yaml:"-"` // use plain HTTP for requests to parental and safe browsing servers
|
||||
SafeSearchEnabled bool `yaml:"safesearch_enabled"`
|
||||
SafeBrowsingEnabled bool `yaml:"safebrowsing_enabled"`
|
||||
ResolverAddress string `yaml:"-"` // DNS server address
|
||||
@@ -110,12 +87,10 @@ type Dnsfilter struct {
|
||||
filteringEngine *urlfilter.DNSEngine
|
||||
engineLock sync.RWMutex
|
||||
|
||||
// HTTP lookups for safebrowsing and parental
|
||||
client http.Client // handle for http client -- single instance as recommended by docs
|
||||
transport *http.Transport // handle for http transport used by http client
|
||||
|
||||
parentalServer string // access via methods
|
||||
safeBrowsingServer string // access via methods
|
||||
parentalServer string // access via methods
|
||||
safeBrowsingServer string // access via methods
|
||||
parentalUpstream upstream.Upstream
|
||||
safeBrowsingUpstream upstream.Upstream
|
||||
|
||||
Config // for direct access by library users, even a = assignment
|
||||
confLock sync.RWMutex
|
||||
@@ -251,9 +226,6 @@ func (d *Dnsfilter) filtersInitializer() {
|
||||
|
||||
// Close - close the object
|
||||
func (d *Dnsfilter) Close() {
|
||||
if d != nil && d.transport != nil {
|
||||
d.transport.CloseIdleConnections()
|
||||
}
|
||||
if d.rulesStorage != nil {
|
||||
d.rulesStorage.Close()
|
||||
}
|
||||
@@ -261,7 +233,6 @@ func (d *Dnsfilter) Close() {
|
||||
|
||||
type dnsFilterContext struct {
|
||||
stats Stats
|
||||
dialCache gcache.Cache // "host" -> "IP" cache for safebrowsing and parental control servers
|
||||
safebrowsingCache cache.Cache
|
||||
parentalCache cache.Cache
|
||||
safeSearchCache cache.Cache
|
||||
@@ -328,11 +299,10 @@ func (d *Dnsfilter) CheckHost(host string, qtype uint16, setts *RequestFiltering
|
||||
}
|
||||
}
|
||||
|
||||
// check safeSearch if no match
|
||||
if setts.SafeSearchEnabled {
|
||||
result, err = d.checkSafeSearch(host)
|
||||
if err != nil {
|
||||
log.Printf("Failed to safesearch HTTP lookup, ignoring check: %v", err)
|
||||
log.Info("SafeSearch: failed: %v", err)
|
||||
return Result{}, nil
|
||||
}
|
||||
|
||||
@@ -341,12 +311,10 @@ func (d *Dnsfilter) CheckHost(host string, qtype uint16, setts *RequestFiltering
|
||||
}
|
||||
}
|
||||
|
||||
// check safebrowsing if no match
|
||||
if setts.SafeBrowsingEnabled {
|
||||
result, err = d.checkSafeBrowsing(host)
|
||||
if err != nil {
|
||||
// failed to do HTTP lookup -- treat it as if we got empty response, but don't save cache
|
||||
log.Printf("Failed to do safebrowsing HTTP lookup, ignoring check: %v", err)
|
||||
log.Info("SafeBrowsing: failed: %v", err)
|
||||
return Result{}, nil
|
||||
}
|
||||
if result.Reason.Matched() {
|
||||
@@ -354,12 +322,10 @@ func (d *Dnsfilter) CheckHost(host string, qtype uint16, setts *RequestFiltering
|
||||
}
|
||||
}
|
||||
|
||||
// check parental if no match
|
||||
if setts.ParentalEnabled {
|
||||
result, err = d.checkParental(host)
|
||||
if err != nil {
|
||||
// failed to do HTTP lookup -- treat it as if we got empty response, but don't save cache
|
||||
log.Printf("Failed to do parental HTTP lookup, ignoring check: %v", err)
|
||||
log.Printf("Parental: failed: %v", err)
|
||||
return Result{}, nil
|
||||
}
|
||||
if result.Reason.Matched() {
|
||||
@@ -367,7 +333,6 @@ func (d *Dnsfilter) CheckHost(host string, qtype uint16, setts *RequestFiltering
|
||||
}
|
||||
}
|
||||
|
||||
// nothing matched, return nothing
|
||||
return Result{}, nil
|
||||
}
|
||||
|
||||
@@ -445,311 +410,6 @@ func matchBlockedServicesRules(host string, svcs []ServiceEntry) Result {
|
||||
return res
|
||||
}
|
||||
|
||||
/*
|
||||
expire byte[4]
|
||||
res Result
|
||||
*/
|
||||
func (d *Dnsfilter) setCacheResult(cache cache.Cache, host string, res Result) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
expire := uint(time.Now().Unix()) + d.Config.CacheTime*60
|
||||
var exp []byte
|
||||
exp = make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(exp, uint32(expire))
|
||||
_, _ = buf.Write(exp)
|
||||
|
||||
enc := gob.NewEncoder(&buf)
|
||||
err := enc.Encode(res)
|
||||
if err != nil {
|
||||
log.Error("gob.Encode(): %s", err)
|
||||
return
|
||||
}
|
||||
_ = cache.Set([]byte(host), buf.Bytes())
|
||||
log.Debug("Stored in cache %p: %s", cache, host)
|
||||
}
|
||||
|
||||
func getCachedResult(cache cache.Cache, host string) (Result, bool) {
|
||||
data := cache.Get([]byte(host))
|
||||
if data == nil {
|
||||
return Result{}, false
|
||||
}
|
||||
|
||||
exp := int(binary.BigEndian.Uint32(data[:4]))
|
||||
if exp <= int(time.Now().Unix()) {
|
||||
cache.Del([]byte(host))
|
||||
return Result{}, false
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.Write(data[4:])
|
||||
dec := gob.NewDecoder(&buf)
|
||||
r := Result{}
|
||||
err := dec.Decode(&r)
|
||||
if err != nil {
|
||||
log.Debug("gob.Decode(): %s", err)
|
||||
return Result{}, false
|
||||
}
|
||||
|
||||
return r, true
|
||||
}
|
||||
|
||||
// for each dot, hash it and add it to string
|
||||
func hostnameToHashParam(host string, addslash bool) (string, map[string]bool) {
|
||||
var hashparam bytes.Buffer
|
||||
hashes := map[string]bool{}
|
||||
tld, icann := publicsuffix.PublicSuffix(host)
|
||||
if !icann {
|
||||
// private suffixes like cloudfront.net
|
||||
tld = ""
|
||||
}
|
||||
curhost := host
|
||||
for {
|
||||
if curhost == "" {
|
||||
// we've reached end of string
|
||||
break
|
||||
}
|
||||
if tld != "" && curhost == tld {
|
||||
// we've reached the TLD, don't hash it
|
||||
break
|
||||
}
|
||||
tohash := []byte(curhost)
|
||||
if addslash {
|
||||
tohash = append(tohash, '/')
|
||||
}
|
||||
sum := sha256.Sum256(tohash)
|
||||
hexhash := fmt.Sprintf("%X", sum)
|
||||
hashes[hexhash] = true
|
||||
hashparam.WriteString(fmt.Sprintf("%02X%02X%02X%02X/", sum[0], sum[1], sum[2], sum[3]))
|
||||
pos := strings.IndexByte(curhost, byte('.'))
|
||||
if pos < 0 {
|
||||
break
|
||||
}
|
||||
curhost = curhost[pos+1:]
|
||||
}
|
||||
return hashparam.String(), hashes
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) checkSafeSearch(host string) (Result, error) {
|
||||
if log.GetLevel() >= log.DEBUG {
|
||||
timer := log.StartTimer()
|
||||
defer timer.LogElapsed("SafeSearch HTTP lookup for %s", host)
|
||||
}
|
||||
|
||||
// Check cache. Return cached result if it was found
|
||||
cachedValue, isFound := getCachedResult(gctx.safeSearchCache, host)
|
||||
if isFound {
|
||||
atomic.AddUint64(&gctx.stats.Safesearch.CacheHits, 1)
|
||||
log.Tracef("%s: found in SafeSearch cache", host)
|
||||
return cachedValue, nil
|
||||
}
|
||||
|
||||
safeHost, ok := d.SafeSearchDomain(host)
|
||||
if !ok {
|
||||
return Result{}, nil
|
||||
}
|
||||
|
||||
res := Result{IsFiltered: true, Reason: FilteredSafeSearch}
|
||||
if ip := net.ParseIP(safeHost); ip != nil {
|
||||
res.IP = ip
|
||||
d.setCacheResult(gctx.safeSearchCache, host, res)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// TODO this address should be resolved with upstream that was configured in dnsforward
|
||||
addrs, 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
|
||||
}
|
||||
}
|
||||
|
||||
if len(res.IP) == 0 {
|
||||
return Result{}, fmt.Errorf("no ipv4 addresses in safe search response for %s", safeHost)
|
||||
}
|
||||
|
||||
// Cache result
|
||||
d.setCacheResult(gctx.safeSearchCache, host, res)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) checkSafeBrowsing(host string) (Result, error) {
|
||||
if log.GetLevel() >= log.DEBUG {
|
||||
timer := log.StartTimer()
|
||||
defer timer.LogElapsed("SafeBrowsing HTTP lookup for %s", host)
|
||||
}
|
||||
|
||||
format := func(hashparam string) string {
|
||||
schema := "https"
|
||||
if d.UsePlainHTTP {
|
||||
schema = "http"
|
||||
}
|
||||
url := fmt.Sprintf(defaultSafebrowsingURL, schema, d.safeBrowsingServer, hashparam)
|
||||
return url
|
||||
}
|
||||
handleBody := func(body []byte, hashes map[string]bool) (Result, error) {
|
||||
result := Result{}
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(body)))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
splitted := strings.Split(line, ":")
|
||||
if len(splitted) < 3 {
|
||||
continue
|
||||
}
|
||||
hash := splitted[2]
|
||||
if _, ok := hashes[hash]; ok {
|
||||
// it's in the hash
|
||||
result.IsFiltered = true
|
||||
result.Reason = FilteredSafeBrowsing
|
||||
result.Rule = splitted[0]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
// error, don't save cache
|
||||
return Result{}, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// check cache
|
||||
cachedValue, isFound := getCachedResult(gctx.safebrowsingCache, host)
|
||||
if isFound {
|
||||
atomic.AddUint64(&gctx.stats.Safebrowsing.CacheHits, 1)
|
||||
log.Tracef("%s: found in the lookup cache %p", host, gctx.safebrowsingCache)
|
||||
return cachedValue, nil
|
||||
}
|
||||
|
||||
result, err := d.lookupCommon(host, &gctx.stats.Safebrowsing, true, format, handleBody)
|
||||
|
||||
if err == nil {
|
||||
d.setCacheResult(gctx.safebrowsingCache, host, result)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (d *Dnsfilter) checkParental(host string) (Result, error) {
|
||||
if log.GetLevel() >= log.DEBUG {
|
||||
timer := log.StartTimer()
|
||||
defer timer.LogElapsed("Parental HTTP lookup for %s", host)
|
||||
}
|
||||
|
||||
format := func(hashparam string) string {
|
||||
schema := "https"
|
||||
if d.UsePlainHTTP {
|
||||
schema = "http"
|
||||
}
|
||||
sensitivity := d.ParentalSensitivity
|
||||
if sensitivity == 0 {
|
||||
sensitivity = defaultParentalSensitivity
|
||||
}
|
||||
url := fmt.Sprintf(defaultParentalURL, schema, d.parentalServer, hashparam, sensitivity)
|
||||
return url
|
||||
}
|
||||
handleBody := func(body []byte, hashes map[string]bool) (Result, error) {
|
||||
// parse json
|
||||
var m []struct {
|
||||
Blocked bool `json:"blocked"`
|
||||
ClientTTL int `json:"clientTtl"`
|
||||
Reason string `json:"reason"`
|
||||
Hash string `json:"hash"`
|
||||
}
|
||||
err := json.Unmarshal(body, &m)
|
||||
if err != nil {
|
||||
// error, don't save cache
|
||||
log.Printf("Couldn't parse json '%s': %s", body, err)
|
||||
return Result{}, err
|
||||
}
|
||||
|
||||
result := Result{}
|
||||
|
||||
for i := range m {
|
||||
if !hashes[m[i].Hash] {
|
||||
continue
|
||||
}
|
||||
if m[i].Blocked {
|
||||
result.IsFiltered = true
|
||||
result.Reason = FilteredParental
|
||||
result.Rule = fmt.Sprintf("parental %s", m[i].Reason)
|
||||
break
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// check cache
|
||||
cachedValue, isFound := getCachedResult(gctx.parentalCache, host)
|
||||
if isFound {
|
||||
atomic.AddUint64(&gctx.stats.Parental.CacheHits, 1)
|
||||
log.Tracef("%s: found in the lookup cache %p", host, gctx.parentalCache)
|
||||
return cachedValue, nil
|
||||
}
|
||||
|
||||
result, err := d.lookupCommon(host, &gctx.stats.Parental, false, format, handleBody)
|
||||
|
||||
if err == nil {
|
||||
d.setCacheResult(gctx.parentalCache, host, result)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
type formatHandler func(hashparam string) string
|
||||
type bodyHandler func(body []byte, hashes map[string]bool) (Result, error)
|
||||
|
||||
// real implementation of lookup/check
|
||||
func (d *Dnsfilter) lookupCommon(host string, lookupstats *LookupStats, hashparamNeedSlash bool, format formatHandler, handleBody bodyHandler) (Result, error) {
|
||||
// convert hostname to hash parameters
|
||||
hashparam, hashes := hostnameToHashParam(host, hashparamNeedSlash)
|
||||
|
||||
// format URL with our hashes
|
||||
url := format(hashparam)
|
||||
|
||||
// do HTTP request
|
||||
atomic.AddUint64(&lookupstats.Requests, 1)
|
||||
atomic.AddInt64(&lookupstats.Pending, 1)
|
||||
updateMax(&lookupstats.Pending, &lookupstats.PendingMax)
|
||||
resp, err := d.client.Get(url)
|
||||
atomic.AddInt64(&lookupstats.Pending, -1)
|
||||
if resp != nil && resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
// error, don't save cache
|
||||
return Result{}, err
|
||||
}
|
||||
|
||||
// get body text
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
// error, don't save cache
|
||||
return Result{}, err
|
||||
}
|
||||
|
||||
// handle status code
|
||||
switch {
|
||||
case resp.StatusCode == 204:
|
||||
// empty result, save cache
|
||||
return Result{}, nil
|
||||
case resp.StatusCode != 200:
|
||||
return Result{}, fmt.Errorf("HTTP status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
result, err := handleBody(body, hashes)
|
||||
if err != nil {
|
||||
return Result{}, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
//
|
||||
// Adding rule and matching against the rules
|
||||
//
|
||||
@@ -887,97 +547,6 @@ func (d *Dnsfilter) matchHost(host string, qtype uint16) (Result, error) {
|
||||
return Result{}, nil
|
||||
}
|
||||
|
||||
//
|
||||
// lifecycle helper functions
|
||||
//
|
||||
|
||||
// Return TRUE if this host's IP should be cached
|
||||
func (d *Dnsfilter) shouldBeInDialCache(host string) bool {
|
||||
return host == d.safeBrowsingServer ||
|
||||
host == d.parentalServer
|
||||
}
|
||||
|
||||
// Search for an IP address by host name
|
||||
func searchInDialCache(host string) string {
|
||||
rawValue, err := gctx.dialCache.Get(host)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
ip, _ := rawValue.(string)
|
||||
log.Debug("Found in cache: %s -> %s", host, ip)
|
||||
return ip
|
||||
}
|
||||
|
||||
// Add "hostname" -> "IP address" entry to cache
|
||||
func addToDialCache(host, ip string) {
|
||||
err := gctx.dialCache.Set(host, ip)
|
||||
if err != nil {
|
||||
log.Debug("dialCache.Set: %s", err)
|
||||
}
|
||||
log.Debug("Added to cache: %s -> %s", host, ip)
|
||||
}
|
||||
|
||||
type dialFunctionType func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||
|
||||
// Connect to a remote server resolving hostname using our own DNS server
|
||||
func (d *Dnsfilter) createCustomDialContext(resolverAddr string) dialFunctionType {
|
||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
log.Tracef("network:%v addr:%v", network, addr)
|
||||
|
||||
host, port, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dialer := &net.Dialer{
|
||||
Timeout: time.Minute * 5,
|
||||
}
|
||||
|
||||
if net.ParseIP(host) != nil {
|
||||
con, err := dialer.DialContext(ctx, network, addr)
|
||||
return con, err
|
||||
}
|
||||
|
||||
cache := d.shouldBeInDialCache(host)
|
||||
if cache {
|
||||
ip := searchInDialCache(host)
|
||||
if len(ip) != 0 {
|
||||
addr = fmt.Sprintf("%s:%s", ip, port)
|
||||
return dialer.DialContext(ctx, network, addr)
|
||||
}
|
||||
}
|
||||
|
||||
r := upstream.NewResolver(resolverAddr, 30*time.Second)
|
||||
addrs, e := r.LookupIPAddr(ctx, host)
|
||||
log.Tracef("LookupIPAddr: %s: %v", host, addrs)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
if len(addrs) == 0 {
|
||||
return nil, fmt.Errorf("couldn't lookup host: %s", host)
|
||||
}
|
||||
|
||||
var dialErrs []error
|
||||
for _, a := range addrs {
|
||||
addr = fmt.Sprintf("%s:%s", a.String(), port)
|
||||
con, err := dialer.DialContext(ctx, network, addr)
|
||||
if err != nil {
|
||||
dialErrs = append(dialErrs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if cache {
|
||||
addToDialCache(host, a.String())
|
||||
}
|
||||
|
||||
return con, err
|
||||
}
|
||||
return nil, errorx.DecorateMany(fmt.Sprintf("couldn't dial to %s", addr), dialErrs...)
|
||||
}
|
||||
}
|
||||
|
||||
// New creates properly initialized DNS Filter that is ready to be used
|
||||
func New(c *Config, filters map[int]string) *Dnsfilter {
|
||||
|
||||
@@ -1002,34 +571,16 @@ func New(c *Config, filters map[int]string) *Dnsfilter {
|
||||
cacheConf.MaxSize = c.ParentalCacheSize
|
||||
gctx.parentalCache = cache.New(cacheConf)
|
||||
}
|
||||
|
||||
if len(c.ResolverAddress) != 0 && gctx.dialCache == nil {
|
||||
dur := time.Duration(c.CacheTime) * time.Minute
|
||||
gctx.dialCache = gcache.New(maxDialCacheSize).LRU().Expiration(dur).Build()
|
||||
}
|
||||
}
|
||||
|
||||
d := new(Dnsfilter)
|
||||
|
||||
// Customize the Transport to have larger connection pool,
|
||||
// We are not (re)using http.DefaultTransport because of race conditions found by tests
|
||||
d.transport = &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
MaxIdleConns: defaultHTTPMaxIdleConnections, // default 100
|
||||
MaxIdleConnsPerHost: defaultHTTPMaxIdleConnections, // default 2
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
err := d.initSecurityServices()
|
||||
if err != nil {
|
||||
log.Error("dnsfilter: initialize services: %s", err)
|
||||
return nil
|
||||
}
|
||||
if c != nil && len(c.ResolverAddress) != 0 {
|
||||
d.transport.DialContext = d.createCustomDialContext(c.ResolverAddress)
|
||||
}
|
||||
d.client = http.Client{
|
||||
Transport: d.transport,
|
||||
Timeout: defaultHTTPTimeout,
|
||||
}
|
||||
d.safeBrowsingServer = defaultSafebrowsingServer
|
||||
d.parentalServer = defaultParentalServer
|
||||
|
||||
if c != nil {
|
||||
d.Config = *c
|
||||
}
|
||||
@@ -1053,38 +604,6 @@ func New(c *Config, filters map[int]string) *Dnsfilter {
|
||||
return d
|
||||
}
|
||||
|
||||
//
|
||||
// config manipulation helpers
|
||||
//
|
||||
|
||||
// SetSafeBrowsingServer lets you optionally change hostname of safesearch lookup
|
||||
func (d *Dnsfilter) SetSafeBrowsingServer(host string) {
|
||||
if len(host) == 0 {
|
||||
d.safeBrowsingServer = defaultSafebrowsingServer
|
||||
} else {
|
||||
d.safeBrowsingServer = host
|
||||
}
|
||||
}
|
||||
|
||||
// SetHTTPTimeout lets you optionally change timeout during lookups
|
||||
func (d *Dnsfilter) SetHTTPTimeout(t time.Duration) {
|
||||
d.client.Timeout = t
|
||||
}
|
||||
|
||||
// ResetHTTPTimeout resets lookup timeouts
|
||||
func (d *Dnsfilter) ResetHTTPTimeout() {
|
||||
d.client.Timeout = defaultHTTPTimeout
|
||||
}
|
||||
|
||||
// SafeSearchDomain returns replacement address for search engine
|
||||
func (d *Dnsfilter) SafeSearchDomain(host string) (string, bool) {
|
||||
if d.SafeSearchEnabled {
|
||||
val, ok := safeSearchDomains[host]
|
||||
return val, ok
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
//
|
||||
// stats
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user