mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-12-17 05:01:35 +03:00
705a9d909d
* use hash prefix as the cache key Squashed commit of the following: commit d719a84ee9b9cf43aaab4f53d07451645ea836db Merge: d9d6d44397df1989
Author: Simon Zolin <s.zolin@adguard.com> Date: Thu Aug 13 11:41:28 2020 +0300 Merge remote-tracking branch 'origin/master' into sbpc commit d9d6d44376c44959f2216b08e577d8e5c5f65bff Merge: 0a8b2483de92c852
Author: Simon Zolin <s.zolin@adguard.com> Date: Thu Aug 13 11:23:14 2020 +0300 Merge remote-tracking branch 'origin/master' into sbpc commit 0a8b24839683683a9d327ecf57a7d182b3996b1d Merge: 0255a24a9b9902f0
Author: Simon Zolin <s.zolin@adguard.com> Date: Wed Aug 12 20:21:22 2020 +0300 Merge remote-tracking branch 'origin/master' into sbpc commit 0255a24a191efd2e4ef23d6a00a7a9fed8831730 Author: Simon Zolin <s.zolin@adguard.com> Date: Wed Aug 12 17:16:57 2020 +0300 - TestServerCustomClientUpstream(): fix commit d2311902f887be9621a9d9312c73f899dd269440 Author: Simon Zolin <s.zolin@adguard.com> Date: Wed Aug 12 17:07:12 2020 +0300 * SB/PC: hard-code Family server IP addresses to prevent from requesting them at runtime commit ee340108f11f98d49a7af2a7e8a228c25ab1537a Author: Simon Zolin <s.zolin@adguard.com> Date: Wed Aug 12 17:05:57 2020 +0300 * dnsproxy v0.30.1 commit f5f53ba7116ad525204d00b80352202eee88b78c Author: Simon Zolin <s.zolin@adguard.com> Date: Wed Aug 12 14:53:23 2020 +0300 minor commit fb4631e2cd570b0fd5ae26ec2b1890361275a5a8 Author: Simon Zolin <s.zolin@adguard.com> Date: Mon Aug 10 20:07:27 2020 +0300 * SB/PC: implement new cache commit f9f58461a6efbcfacd798f7640a4645cf1971cb2 Author: Simon Zolin <s.zolin@adguard.com> Date: Fri Aug 7 19:31:05 2020 +0300 doc commit ed69626a6c119ab1a3b187f5afbd4cef708c3159 Author: Simon Zolin <s.zolin@adguard.com> Date: Fri Aug 7 18:25:57 2020 +0300 * SB/PC: use hostname prefix for cache commit afa8040c8c0836c7e59e6fb9aaf1caccd132ea8f Author: Simon Zolin <s.zolin@adguard.com> Date: Fri Jul 31 11:19:49 2020 +0300 * SB/PC: use 4-character hash in request
150 lines
3.6 KiB
Go
150 lines
3.6 KiB
Go
package dnsfilter
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/gob"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/AdguardTeam/golibs/cache"
|
|
"github.com/AdguardTeam/golibs/log"
|
|
)
|
|
|
|
/*
|
|
expire byte[4]
|
|
res Result
|
|
*/
|
|
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
|
|
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 0
|
|
}
|
|
val := buf.Bytes()
|
|
_ = cache.Set([]byte(host), val)
|
|
return len(val)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// SafeSearchDomain returns replacement address for search engine
|
|
func (d *Dnsfilter) SafeSearchDomain(host string) (string, bool) {
|
|
val, ok := safeSearchDomains[host]
|
|
return val, ok
|
|
}
|
|
|
|
func (d *Dnsfilter) checkSafeSearch(host string) (Result, error) {
|
|
if log.GetLevel() >= log.DEBUG {
|
|
timer := log.StartTimer()
|
|
defer timer.LogElapsed("SafeSearch: 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("SafeSearch: found in cache: %s", 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
|
|
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)
|
|
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
|
|
valLen := d.setCacheResult(gctx.safeSearchCache, host, res)
|
|
log.Debug("SafeSearch: stored in cache: %s (%d bytes)", host, valLen)
|
|
return res, nil
|
|
}
|
|
|
|
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) {
|
|
d.Config.SafeSearchEnabled = false
|
|
d.Config.ConfigModified()
|
|
}
|
|
|
|
func (d *Dnsfilter) handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) {
|
|
data := map[string]interface{}{
|
|
"enabled": d.Config.SafeSearchEnabled,
|
|
}
|
|
jsonVal, err := json.Marshal(data)
|
|
if err != nil {
|
|
httpError(r, w, http.StatusInternalServerError, "Unable to marshal status json: %s", err)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, err = w.Write(jsonVal)
|
|
if err != nil {
|
|
httpError(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err)
|
|
return
|
|
}
|
|
}
|