all: sync with master; upd chlog

This commit is contained in:
Ainar Garipov
2023-03-09 15:39:35 +03:00
parent 4f928be393
commit a21558f418
98 changed files with 2687 additions and 24734 deletions

View File

@@ -1,38 +0,0 @@
//go:build ignore
// +build ignore
package filtering
import (
"fmt"
"sort"
"testing"
)
// This is a simple tool that takes a list of services and prints them to the output.
// It is supposed to be used to update:
// client/src/helpers/constants.js
// client/src/components/ui/Icons.js
//
// Usage:
// 1. go run ./internal/filtering/blocked_test.go
// 2. Use the output to replace `SERVICES` array in "client/src/helpers/constants.js".
// 3. You'll need to enter services names manually.
// 4. Don't forget to add missing icons to "client/src/components/ui/Icons.js".
//
// TODO(ameshkov): Rework generator: have a JSON file with all the metadata we need
// then use this JSON file to generate JS and Go code
func TestGenServicesArray(t *testing.T) {
services := make([]svc, len(serviceRulesArray))
copy(services, serviceRulesArray)
sort.Slice(services, func(i, j int) bool {
return services[i].name < services[j].name
})
fmt.Println("export const SERVICES = [")
for _, s := range services {
fmt.Printf(" {\n id: '%s',\n name: '%s',\n },\n", s.name, s.name)
}
fmt.Println("];")
}

View File

@@ -420,11 +420,11 @@ type ResultRule struct {
// Result contains the result of a request check.
//
// All fields transitively have omitempty tags so that the query log
// doesn't become too large.
// 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?
// TODO(a.garipov): Clarify relationships between fields. Perhaps replace with
// a sum type or an interface?
type Result struct {
// DNSRewriteResult is the $dnsrewrite filter rule result.
DNSRewriteResult *DNSRewriteResult `json:",omitempty"`
@@ -813,17 +813,18 @@ func (d *DNSFilter) matchHostProcessDNSResult(
return res
}
if dnsres.HostRulesV4 != nil || dnsres.HostRulesV6 != nil {
// Question type doesn't match the host rules. Return the first matched
// host rule, but without an IP address.
var matchedRules []rules.Rule
if dnsres.HostRulesV4 != nil {
matchedRules = []rules.Rule{dnsres.HostRulesV4[0]}
} else if dnsres.HostRulesV6 != nil {
matchedRules = []rules.Rule{dnsres.HostRulesV6[0]}
}
return hostResultForOtherQType(dnsres)
}
return makeResult(matchedRules, FilteredBlockList)
// hostResultForOtherQType returns a result based on the host rules in dnsres,
// if any. dnsres.HostRulesV4 take precedence over dnsres.HostRulesV6.
func hostResultForOtherQType(dnsres *urlfilter.DNSResult) (res Result) {
if len(dnsres.HostRulesV4) != 0 {
return makeResult([]rules.Rule{dnsres.HostRulesV4[0]}, FilteredBlockList)
}
if len(dnsres.HostRulesV6) != 0 {
return makeResult([]rules.Rule{dnsres.HostRulesV6[0]}, FilteredBlockList)
}
return Result{}
@@ -840,7 +841,7 @@ func (d *DNSFilter) matchHost(
return Result{}, nil
}
ureq := &urlfilter.DNSRequest{
ufReq := &urlfilter.DNSRequest{
Hostname: host,
SortedClientTags: setts.ClientTags,
// TODO(e.burkov): Wait for urlfilter update to pass net.IP.
@@ -857,7 +858,7 @@ func (d *DNSFilter) matchHost(
defer d.engineLock.RUnlock()
if setts.ProtectionEnabled && d.filteringEngineAllow != nil {
dnsres, ok := d.filteringEngineAllow.MatchRequest(ureq)
dnsres, ok := d.filteringEngineAllow.MatchRequest(ufReq)
if ok {
return d.matchHostProcessAllowList(host, dnsres)
}
@@ -867,17 +868,13 @@ func (d *DNSFilter) matchHost(
return Result{}, nil
}
dnsres, ok := d.filteringEngine.MatchRequest(ureq)
dnsres, matchedEngine := d.filteringEngine.MatchRequest(ufReq)
// Check DNS rewrites first, because the API there is a bit awkward.
if dnsr := dnsres.DNSRewrites(); len(dnsr) > 0 {
res = d.processDNSRewrites(dnsr)
if res.Reason == RewrittenRule && res.CanonName == host {
// A rewrite of a host to itself. Go on and try matching other
// things.
} else {
return res, nil
}
} else if !ok {
dnsRWRes := d.processDNSResultRewrites(dnsres, host)
if dnsRWRes.Reason != NotFilteredNotFound {
return dnsRWRes, nil
} else if !matchedEngine {
return Result{}, nil
}
@@ -899,6 +896,26 @@ func (d *DNSFilter) matchHost(
return res, nil
}
// processDNSResultRewrites returns an empty Result if there are no dnsrewrite
// rules in dnsres. Otherwise, it returns the processed Result.
func (d *DNSFilter) processDNSResultRewrites(
dnsres *urlfilter.DNSResult,
host string,
) (dnsRWRes Result) {
dnsr := dnsres.DNSRewrites()
if len(dnsr) == 0 {
return Result{}
}
res := d.processDNSRewrites(dnsr)
if res.Reason == RewrittenRule && res.CanonName == host {
// A rewrite of a host to itself. Go on and try matching other things.
return Result{}
}
return res
}
// makeResult returns a properly constructed Result.
func makeResult(matchedRules []rules.Rule, reason Reason) (res Result) {
resRules := make([]*ResultRule, len(matchedRules))

View File

@@ -1,11 +1,8 @@
// DNS Rewrites
package filtering
import (
"fmt"
"net"
"sort"
"strings"
"github.com/AdguardTeam/golibs/errors"
@@ -14,6 +11,8 @@ import (
"golang.org/x/exp/slices"
)
// Legacy DNS rewrites
// LegacyRewrite is a single legacy DNS rewrite record.
//
// Instances of *LegacyRewrite must never be nil.
@@ -123,38 +122,24 @@ func matchDomainWildcard(host, wildcard string) (ok bool) {
return isWildcard(wildcard) && strings.HasSuffix(host, wildcard[1:])
}
// rewritesSorted is a slice of legacy rewrites for sorting.
// legacyRewriteSortsBefore sorts rewirtes according to the following priority:
//
// The sorting priority:
//
// 1. A and AAAA > CNAME
// 2. wildcard > exact
// 3. lower level wildcard > higher level wildcard
//
// TODO(a.garipov): Replace with slices.Sort.
type rewritesSorted []*LegacyRewrite
// Len implements the sort.Interface interface for rewritesSorted.
func (a rewritesSorted) Len() (l int) { return len(a) }
// Swap implements the sort.Interface interface for rewritesSorted.
func (a rewritesSorted) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
// Less implements the sort.Interface interface for rewritesSorted.
func (a rewritesSorted) Less(i, j int) (less bool) {
ith, jth := a[i], a[j]
if ith.Type == dns.TypeCNAME && jth.Type != dns.TypeCNAME {
// 1. A and AAAA > CNAME;
// 2. wildcard > exact;
// 3. lower level wildcard > higher level wildcard;
func legacyRewriteSortsBefore(a, b *LegacyRewrite) (sortsBefore bool) {
if a.Type == dns.TypeCNAME && b.Type != dns.TypeCNAME {
return true
} else if ith.Type != dns.TypeCNAME && jth.Type == dns.TypeCNAME {
} else if a.Type != dns.TypeCNAME && b.Type == dns.TypeCNAME {
return false
}
if iw, jw := isWildcard(ith.Domain), isWildcard(jth.Domain); iw != jw {
return jw
if aIsWld, bIsWld := isWildcard(a.Domain), isWildcard(b.Domain); aIsWld != bIsWld {
return bIsWld
}
// Both are either wildcards or not.
return len(ith.Domain) > len(jth.Domain)
// Both are either wildcards or both aren't.
return len(a.Domain) > len(b.Domain)
}
// prepareRewrites normalizes and validates all legacy DNS rewrites.
@@ -196,7 +181,7 @@ func findRewrites(
return nil, matched
}
sort.Sort(rewritesSorted(rewrites))
slices.SortFunc(rewrites, legacyRewriteSortsBefore)
for i, r := range rewrites {
if isWildcard(r.Domain) {

View File

@@ -8,7 +8,6 @@ import (
"fmt"
"net"
"net/http"
"sort"
"strings"
"sync"
"time"
@@ -19,6 +18,7 @@ import (
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/miekg/dns"
"golang.org/x/exp/slices"
"golang.org/x/net/publicsuffix"
)
@@ -241,8 +241,8 @@ func (c *sbCtx) processTXT(resp *dns.Msg) (bool, [][]byte) {
}
func (c *sbCtx) storeCache(hashes [][]byte) {
sort.Slice(hashes, func(a, b int) bool {
return bytes.Compare(hashes[a], hashes[b]) == -1
slices.SortFunc(hashes, func(a, b []byte) (sortsBefore bool) {
return bytes.Compare(a, b) == -1
})
var curData []byte

View File

@@ -13,8 +13,37 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/urlfilter/rules"
)
// SafeSearch interface describes a service for search engines hosts rewrites.
type SafeSearch interface {
// SearchHost returns a replacement address for the search engine host.
SearchHost(host string, qtype uint16) (res *rules.DNSRewrite)
// CheckHost checks host with safe search engine.
CheckHost(host string, qtype uint16) (res Result, err error)
}
// SafeSearchConfig is a struct with safe search related settings.
type SafeSearchConfig struct {
// CustomResolver is the resolver used by safe search.
CustomResolver Resolver `yaml:"-"`
// Enabled indicates if safe search is enabled entirely.
Enabled bool `yaml:"enabled" json:"enabled"`
// Services flags. Each flag indicates if the corresponding service is
// enabled or disabled.
Bing bool `yaml:"bing" json:"bing"`
DuckDuckGo bool `yaml:"duckduckgo" json:"duckduckgo"`
Google bool `yaml:"google" json:"google"`
Pixabay bool `yaml:"pixabay" json:"pixabay"`
Yandex bool `yaml:"yandex" json:"yandex"`
YouTube bool `yaml:"youtube" json:"youtube"`
}
/*
expire byte[4]
res Result

View File

@@ -0,0 +1,34 @@
package safesearch
import _ "embed"
//go:embed rules/bing.txt
var bing string
//go:embed rules/google.txt
var google string
//go:embed rules/pixabay.txt
var pixabay string
//go:embed rules/duckduckgo.txt
var duckduckgo string
//go:embed rules/yandex.txt
var yandex string
//go:embed rules/youtube.txt
var youtube string
// safeSearchRules is a map with rules texts grouped by search providers.
// Source rules downloaded from:
// https://adguardteam.github.io/HostlistsRegistry/assets/engines_safe_search.txt,
// https://adguardteam.github.io/HostlistsRegistry/assets/youtube_safe_search.txt.
var safeSearchRules = map[Service]string{
Bing: bing,
DuckDuckGo: duckduckgo,
Google: google,
Pixabay: pixabay,
Yandex: yandex,
YouTube: youtube,
}

View File

@@ -0,0 +1 @@
|www.bing.com^$dnsrewrite=NOERROR;CNAME;strict.bing.com

View File

@@ -0,0 +1,3 @@
|duckduckgo.com^$dnsrewrite=NOERROR;CNAME;safe.duckduckgo.com
|start.duckduckgo.com^$dnsrewrite=NOERROR;CNAME;safe.duckduckgo.com
|www.duckduckgo.com^$dnsrewrite=NOERROR;CNAME;safe.duckduckgo.com

View File

@@ -0,0 +1,191 @@
|www.google.ad^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ae^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.al^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.am^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.as^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.at^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.az^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ba^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.be^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.bf^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.bg^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.bi^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.bj^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.bs^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.bt^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.by^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ca^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.cat^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.cd^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.cf^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.cg^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ch^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ci^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.cl^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.cm^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.cn^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.ao^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.bw^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.ck^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.cr^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.id^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.il^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.in^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.jp^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.ke^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.kr^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.ls^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.ma^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.mz^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.nz^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.th^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.tz^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.ug^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.uk^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.uz^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.ve^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.co.vi^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.af^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.ag^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.ai^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.ar^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.au^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.bd^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.bh^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.bn^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.bo^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.br^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.bz^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.co^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.cu^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.cy^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.do^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.ec^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.eg^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.et^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.fj^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.gh^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.gi^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.gt^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.hk^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.jm^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.kh^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.kw^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.lb^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.ly^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.mm^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.mt^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.mx^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.my^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.na^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.nf^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.ng^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.ni^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.np^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.om^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.pa^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.pe^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.pg^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.ph^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.pk^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.pr^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.py^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.qa^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.sa^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.sb^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.sg^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.sl^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.sv^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.tj^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.tr^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.tw^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.ua^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.uy^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.vc^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com.vn^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.com^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.cv^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.cz^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.de^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.dj^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.dk^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.dm^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.dz^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ee^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.es^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.fi^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.fm^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.fr^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ga^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ge^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.gg^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.gl^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.gm^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.gp^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.gr^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.gy^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.hn^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.hr^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ht^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.hu^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ie^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.im^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.iq^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.is^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.it^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.je^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.jo^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.kg^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ki^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.kz^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.la^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.li^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.lk^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.lt^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.lu^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.lv^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.md^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.me^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.mg^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.mk^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ml^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.mn^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ms^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.mu^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.mv^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.mw^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ne^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.nl^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.no^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.nr^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.nu^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.pl^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.pn^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ps^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.pt^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ro^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.rs^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ru^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.rw^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.sc^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.se^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.sh^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.si^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.sk^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.sm^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.sn^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.so^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.sr^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.st^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.td^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.tg^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.tk^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.tl^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.tm^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.tn^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.to^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.tt^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.vg^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.vu^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com
|www.google.ws^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com

View File

@@ -0,0 +1 @@
|pixabay.com^$dnsrewrite=NOERROR;CNAME;safesearch.pixabay.com

View File

@@ -0,0 +1,52 @@
|www.xn--d1acpjx3f.xn--p1ai^$dnsrewrite=NOERROR;A;213.180.193.56
|www.ya.ru^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.az^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.by^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.co.il^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.com.am^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.com.ge^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.com.ru^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.com.tr^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.com^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.de^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.ee^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.eu^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.fi^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.fr^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.kz^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.lt^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.lv^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.md^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.net^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.org^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.pl^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.ru^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.tj^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.tm^$dnsrewrite=NOERROR;A;213.180.193.56
|www.yandex.uz^$dnsrewrite=NOERROR;A;213.180.193.56
|xn--d1acpjx3f.xn--p1ai^$dnsrewrite=NOERROR;A;213.180.193.56
|ya.ru^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.az^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.by^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.co.il^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.com.am^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.com.ge^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.com.ru^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.com.tr^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.com^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.de^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.ee^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.eu^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.fi^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.fr^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.kz^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.lt^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.lv^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.md^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.net^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.org^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.pl^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.ru^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.tj^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.tm^$dnsrewrite=NOERROR;A;213.180.193.56
|yandex.uz^$dnsrewrite=NOERROR;A;213.180.193.56

View File

@@ -0,0 +1,5 @@
|www.youtube.com^$dnsrewrite=NOERROR;CNAME;restrictmoderate.youtube.com
|m.youtube.com^$dnsrewrite=NOERROR;CNAME;restrictmoderate.youtube.com
|youtubei.googleapis.com^$dnsrewrite=NOERROR;CNAME;restrictmoderate.youtube.com
|youtube.googleapis.com^$dnsrewrite=NOERROR;CNAME;restrictmoderate.youtube.com
|www.youtube-nocookie.com^$dnsrewrite=NOERROR;CNAME;restrictmoderate.youtube.com

View File

@@ -0,0 +1,269 @@
// Package safesearch implements safesearch host matching.
package safesearch
import (
"bytes"
"context"
"encoding/binary"
"encoding/gob"
"fmt"
"net"
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist"
"github.com/AdguardTeam/urlfilter/rules"
"github.com/miekg/dns"
)
// Service is a enum with service names used as search providers.
type Service string
// Service enum members.
const (
Bing Service = "bing"
DuckDuckGo Service = "duckduckgo"
Google Service = "google"
Pixabay Service = "pixabay"
Yandex Service = "yandex"
YouTube Service = "youtube"
)
// isServiceProtected returns true if the service safe search is active.
func isServiceProtected(s filtering.SafeSearchConfig, service Service) (ok bool) {
switch service {
case Bing:
return s.Bing
case DuckDuckGo:
return s.DuckDuckGo
case Google:
return s.Google
case Pixabay:
return s.Pixabay
case Yandex:
return s.Yandex
case YouTube:
return s.YouTube
default:
panic(fmt.Errorf("safesearch: invalid sources: not found service %q", service))
}
}
// DefaultSafeSearch is the default safesearch struct.
type DefaultSafeSearch struct {
engine *urlfilter.DNSEngine
safeSearchCache cache.Cache
resolver filtering.Resolver
cacheTime time.Duration
}
// NewDefaultSafeSearch returns new safesearch struct. CacheTime is an element
// TTL (in minutes).
func NewDefaultSafeSearch(
conf filtering.SafeSearchConfig,
cacheSize uint,
cacheTime time.Duration,
) (ss *DefaultSafeSearch, err error) {
engine, err := newEngine(filtering.SafeSearchListID, conf)
if err != nil {
return nil, err
}
var resolver filtering.Resolver = net.DefaultResolver
if conf.CustomResolver != nil {
resolver = conf.CustomResolver
}
return &DefaultSafeSearch{
engine: engine,
safeSearchCache: cache.New(cache.Config{
EnableLRU: true,
MaxSize: cacheSize,
}),
cacheTime: cacheTime,
resolver: resolver,
}, nil
}
// newEngine creates new engine for provided safe search configuration.
func newEngine(listID int, conf filtering.SafeSearchConfig) (engine *urlfilter.DNSEngine, err error) {
var sb strings.Builder
for service, serviceRules := range safeSearchRules {
if isServiceProtected(conf, service) {
sb.WriteString(serviceRules)
}
}
strList := &filterlist.StringRuleList{
ID: listID,
RulesText: sb.String(),
IgnoreCosmetic: true,
}
rs, err := filterlist.NewRuleStorage([]filterlist.RuleList{strList})
if err != nil {
return nil, fmt.Errorf("creating rule storage: %w", err)
}
engine = urlfilter.NewDNSEngine(rs)
log.Info("safesearch: filter %d: reset %d rules", listID, engine.RulesCount)
return engine, nil
}
// type check
var _ filtering.SafeSearch = (*DefaultSafeSearch)(nil)
// SearchHost implements the [filtering.SafeSearch] interface for *DefaultSafeSearch.
func (ss *DefaultSafeSearch) SearchHost(host string, qtype uint16) (res *rules.DNSRewrite) {
r, _ := ss.engine.MatchRequest(&urlfilter.DNSRequest{
Hostname: strings.ToLower(host),
DNSType: qtype,
})
rewritesRules := r.DNSRewrites()
if len(rewritesRules) > 0 {
return rewritesRules[0].DNSRewrite
}
return nil
}
// CheckHost implements the [filtering.SafeSearch] interface for
// *DefaultSafeSearch.
func (ss *DefaultSafeSearch) CheckHost(
host string,
qtype uint16,
) (res filtering.Result, err 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 := ss.getCachedResult(host)
if isFound {
log.Debug("safesearch: found in cache: %s", host)
return cachedValue, nil
}
rewrite := ss.SearchHost(host, qtype)
if rewrite == nil {
return filtering.Result{}, nil
}
dRes, err := ss.newResult(rewrite, qtype)
if err != nil {
log.Debug("safesearch: failed to lookup addresses for %s: %s", host, err)
return filtering.Result{}, err
}
if dRes != nil {
res = *dRes
ss.setCacheResult(host, res)
return res, nil
}
return filtering.Result{}, fmt.Errorf("no ipv4 addresses in safe search response for %s", host)
}
// newResult creates Result object from rewrite rule.
func (ss *DefaultSafeSearch) newResult(
rewrite *rules.DNSRewrite,
qtype uint16,
) (res *filtering.Result, err error) {
res = &filtering.Result{
Rules: []*filtering.ResultRule{{
FilterListID: filtering.SafeSearchListID,
}},
Reason: filtering.FilteredSafeSearch,
IsFiltered: true,
}
if rewrite.RRType == qtype && (qtype == dns.TypeA || qtype == dns.TypeAAAA) {
ip, ok := rewrite.Value.(net.IP)
if !ok || ip == nil {
return nil, nil
}
res.Rules[0].IP = ip
return res, nil
}
if rewrite.NewCNAME == "" {
return nil, nil
}
ips, err := ss.resolver.LookupIP(context.Background(), "ip", rewrite.NewCNAME)
if err != nil {
return nil, err
}
for _, ip := range ips {
if ip = ip.To4(); ip == nil {
continue
}
res.Rules[0].IP = ip
return res, nil
}
return nil, nil
}
// setCacheResult stores data in cache for host.
func (ss *DefaultSafeSearch) setCacheResult(host string, res filtering.Result) {
expire := uint32(time.Now().Add(ss.cacheTime).Unix())
exp := make([]byte, 4)
binary.BigEndian.PutUint32(exp, expire)
buf := bytes.NewBuffer(exp)
err := gob.NewEncoder(buf).Encode(res)
if err != nil {
log.Error("safesearch: cache encoding: %s", err)
return
}
val := buf.Bytes()
_ = ss.safeSearchCache.Set([]byte(host), val)
log.Debug("safesearch: stored in cache: %s (%d bytes)", host, len(val))
}
// getCachedResult returns stored data from cache for host.
func (ss *DefaultSafeSearch) getCachedResult(host string) (res filtering.Result, ok bool) {
res = filtering.Result{}
data := ss.safeSearchCache.Get([]byte(host))
if data == nil {
return res, false
}
exp := binary.BigEndian.Uint32(data[:4])
if exp <= uint32(time.Now().Unix()) {
ss.safeSearchCache.Del([]byte(host))
return res, false
}
buf := bytes.NewBuffer(data[4:])
err := gob.NewDecoder(buf).Decode(&res)
if err != nil {
log.Debug("safesearch: cache decoding: %s", err)
return filtering.Result{}, false
}
return res, true
}

View File

@@ -0,0 +1,202 @@
package safesearch
import (
"context"
"net"
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/urlfilter/rules"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const (
safeSearchCacheSize = 5000
cacheTime = 30 * time.Minute
)
var defaultSafeSearchConf = filtering.SafeSearchConfig{
Enabled: true,
Bing: true,
DuckDuckGo: true,
Google: true,
Pixabay: true,
Yandex: true,
YouTube: true,
}
var yandexIP = net.IPv4(213, 180, 193, 56)
func newForTest(t testing.TB, ssConf filtering.SafeSearchConfig) (ss *DefaultSafeSearch) {
ss, err := NewDefaultSafeSearch(ssConf, safeSearchCacheSize, cacheTime)
require.NoError(t, err)
return ss
}
func TestSafeSearch(t *testing.T) {
ss := newForTest(t, defaultSafeSearchConf)
val := ss.SearchHost("www.google.com", dns.TypeA)
assert.Equal(t, &rules.DNSRewrite{NewCNAME: "forcesafesearch.google.com"}, val)
}
func TestCheckHostSafeSearchYandex(t *testing.T) {
ss := newForTest(t, defaultSafeSearchConf)
// Check host for each domain.
for _, host := range []string{
"yandex.ru",
"yAndeX.ru",
"YANdex.COM",
"yandex.by",
"yandex.kz",
"www.yandex.com",
} {
res, err := ss.CheckHost(host, dns.TypeA)
require.NoError(t, err)
assert.True(t, res.IsFiltered)
require.Len(t, res.Rules, 1)
assert.Equal(t, yandexIP, res.Rules[0].IP)
assert.EqualValues(t, filtering.SafeSearchListID, res.Rules[0].FilterListID)
}
}
func TestCheckHostSafeSearchGoogle(t *testing.T) {
resolver := &aghtest.TestResolver{}
ip, _ := resolver.HostToIPs("forcesafesearch.google.com")
ss := newForTest(t, defaultSafeSearchConf)
ss.resolver = resolver
// Check host for each domain.
for _, host := range []string{
"www.google.com",
"www.google.im",
"www.google.co.in",
"www.google.iq",
"www.google.is",
"www.google.it",
"www.google.je",
} {
t.Run(host, func(t *testing.T) {
res, err := ss.CheckHost(host, dns.TypeA)
require.NoError(t, err)
assert.True(t, res.IsFiltered)
require.Len(t, res.Rules, 1)
assert.Equal(t, ip, res.Rules[0].IP)
assert.EqualValues(t, filtering.SafeSearchListID, res.Rules[0].FilterListID)
})
}
}
func TestSafeSearchCacheYandex(t *testing.T) {
const domain = "yandex.ru"
ss := newForTest(t, filtering.SafeSearchConfig{Enabled: false})
// Check host with disabled safesearch.
res, err := ss.CheckHost(domain, dns.TypeA)
require.NoError(t, err)
assert.False(t, res.IsFiltered)
assert.Empty(t, res.Rules)
ss = newForTest(t, defaultSafeSearchConf)
res, err = ss.CheckHost(domain, dns.TypeA)
require.NoError(t, err)
// For yandex we already know valid IP.
require.Len(t, res.Rules, 1)
assert.Equal(t, res.Rules[0].IP, yandexIP)
// Check cache.
cachedValue, isFound := ss.getCachedResult(domain)
require.True(t, isFound)
require.Len(t, cachedValue.Rules, 1)
assert.Equal(t, cachedValue.Rules[0].IP, yandexIP)
}
func TestSafeSearchCacheGoogle(t *testing.T) {
const domain = "www.google.ru"
ss := newForTest(t, filtering.SafeSearchConfig{Enabled: false})
res, err := ss.CheckHost(domain, dns.TypeA)
require.NoError(t, err)
assert.False(t, res.IsFiltered)
assert.Empty(t, res.Rules)
resolver := &aghtest.TestResolver{}
ss = newForTest(t, defaultSafeSearchConf)
ss.resolver = resolver
// Lookup for safesearch domain.
rewrite := ss.SearchHost(domain, dns.TypeA)
ips, err := resolver.LookupIP(context.Background(), "ip", rewrite.NewCNAME)
require.NoError(t, err)
var foundIP net.IP
for _, ip := range ips {
if ip.To4() != nil {
foundIP = ip
break
}
}
res, err = ss.CheckHost(domain, dns.TypeA)
require.NoError(t, err)
require.Len(t, res.Rules, 1)
assert.True(t, res.Rules[0].IP.Equal(foundIP))
// Check cache.
cachedValue, isFound := ss.getCachedResult(domain)
require.True(t, isFound)
require.Len(t, cachedValue.Rules, 1)
assert.True(t, cachedValue.Rules[0].IP.Equal(foundIP))
}
const googleHost = "www.google.com"
var dnsRewriteSink *rules.DNSRewrite
func BenchmarkSafeSearch(b *testing.B) {
ss := newForTest(b, defaultSafeSearchConf)
for n := 0; n < b.N; n++ {
dnsRewriteSink = ss.SearchHost(googleHost, dns.TypeA)
}
assert.Equal(b, "forcesafesearch.google.com", dnsRewriteSink.NewCNAME)
}
var dnsRewriteParallelSink *rules.DNSRewrite
func BenchmarkSafeSearch_parallel(b *testing.B) {
ss := newForTest(b, defaultSafeSearchConf)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
dnsRewriteParallelSink = ss.SearchHost(googleHost, dns.TypeA)
}
})
assert.Equal(b, "forcesafesearch.google.com", dnsRewriteParallelSink.NewCNAME)
}

View File

@@ -71,6 +71,7 @@ var blockedServices = []blockedService{{
"||amazon.jp^",
"||amazon.nl^",
"||amazon.red^",
"||amazon.se^",
"||amazon.sg^",
"||amazon^",
"||amazonalexavoxcon.com^",
@@ -1171,6 +1172,16 @@ var blockedServices = []blockedService{{
"||zuckerberg.com^",
"||zuckerberg.net^",
},
}, {
ID: "gog",
Name: "GOG",
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 34 34\"><path d=\"M31 31H3a3 3 0 0 1-3-3V3A3 3 0 0 1 3 0H31a3 3 0 0 1 3 3V28A3 3 0 0 1 31 31ZM4 24.5A1.5 1.5 0 0 0 5.5 26H11V24H6.5a.5.5 0 0 1-.5-.5v-3a.5.5 0 0 1 .5-.5H11V18H5.5A1.5 1.5 0 0 0 4 19.5Zm8-18A1.5 1.5 0 0 0 10.5 5h-5A1.5 1.5 0 0 0 4 6.5v5A1.5 1.5 0 0 0 5.5 13H9V11H6.5a.5.5 0 0 1-.5-.5v-3A.5.5 0 0 1 6.5 7h3a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H4v2h6.5A1.5 1.5 0 0 0 12 14.5Zm0 13v5A1.5 1.5 0 0 0 13.5 26h5A1.5 1.5 0 0 0 20 24.5v-5A1.5 1.5 0 0 0 18.5 18h-5A1.5 1.5 0 0 0 12 19.5Zm9-13A1.5 1.5 0 0 0 19.5 5h-5A1.5 1.5 0 0 0 13 6.5v5A1.5 1.5 0 0 0 14.5 13h5A1.5 1.5 0 0 0 21 11.5Zm9 0A1.5 1.5 0 0 0 28.5 5h-5A1.5 1.5 0 0 0 22 6.5v5A1.5 1.5 0 0 0 23.5 13H27V11H24.5a.5.5 0 0 1-.5-.5v-3a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H22v2h6.5A1.5 1.5 0 0 0 30 14.5ZM30 18H22.5A1.5 1.5 0 0 0 21 19.5V26h2V20.5a.5.5 0 0 1 .5-.5h1v6h2V20H28v6h2ZM18.5 11h-3a.5.5 0 0 1-.5-.5v-3a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 .5.5v3A.5.5 0 0 1 18.5 11Zm-4 9h3a.5.5 0 0 1 .5.5v3a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-3A.5.5 0 0 1 14.5 20Z\" /></svg>"),
Rules: []string{
"||gog-cdn-lumen.secure2.footprint.net^",
"||gog-statics.com^",
"||gog.com^",
"||gogalaxy.com^",
},
}, {
ID: "hulu",
Name: "Hulu",
@@ -1280,6 +1291,14 @@ var blockedServices = []blockedService{{
"||iq.com^",
"||iqiyi.com^",
},
}, {
ID: "kakaotalk",
Name: "KakaoTalk",
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 24 24\" ><path d=\"M22.125 0H1.875C.839 0 0 .84 0 1.875v20.25C0 23.161.84 24 1.875 24h20.25C23.161 24 24 23.16 24 22.125V1.875C24 .839 23.16 0 22.125 0zM12 18.75c-.591 0-1.17-.041-1.732-.12-.562.396-3.813 2.679-4.12 2.722 0 0-.125.049-.232-.014s-.088-.229-.088-.229c.032-.22.843-3.018.992-3.533-2.745-1.36-4.57-3.769-4.57-6.513 0-4.246 4.365-7.688 9.75-7.688s9.75 3.442 9.75 7.688c0 4.245-4.365 7.687-9.75 7.687zM8.05 9.867h-.878v3.342c0 .296-.252.537-.563.537s-.562-.24-.562-.537V9.867h-.878a.552.552 0 0 1 0-1.101h2.88a.552.552 0 0 1 0 1.101zm10.987 2.957a.558.558 0 0 1 .109.417.559.559 0 0 1-.219.37.557.557 0 0 1-.338.114.558.558 0 0 1-.45-.224l-1.319-1.747-.195.195v1.227a.564.564 0 0 1-.562.563.563.563 0 0 1-.563-.563V9.328a.563.563 0 0 1 1.125 0v1.21l1.57-1.57a.437.437 0 0 1 .311-.126c.14 0 .282.061.388.167a.555.555 0 0 1 .165.356.438.438 0 0 1-.124.343l-1.282 1.281 1.385 1.835zm-8.35-3.502c-.095-.27-.383-.548-.75-.556-.366.008-.654.286-.749.555l-1.345 3.541c-.171.53-.022.728.133.8a.857.857 0 0 0 .357.077c.235 0 .414-.095.468-.248l.279-.73h1.715l.279.73c.054.153.233.248.468.248a.86.86 0 0 0 .357-.078c.155-.071.304-.268.133-.8l-1.345-3.54zm-1.311 2.443.562-1.596.561 1.596H9.376zm5.905 1.383a.528.528 0 0 1-.539.516h-1.804a.528.528 0 0 1-.54-.516v-3.82c0-.31.258-.562.575-.562s.574.252.574.562v3.305h1.195c.297 0 .54.231.54.515z\"/></svg>"),
Rules: []string{
"||kakao.com^",
"||kgslb.com^",
},
}, {
ID: "leagueoflegends",
Name: "League of Legends",
@@ -1291,6 +1310,24 @@ var blockedServices = []blockedService{{
"||lolstatic.com^",
"||lolusercontent.com^",
},
}, {
ID: "line",
Name: "LINE",
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 50 50\"><path d=\"M 9 4 C 6.24 4 4 6.24 4 9 L 4 41 C 4 43.76 6.24 46 9 46 L 41 46 C 43.76 46 46 43.76 46 41 L 46 9 C 46 6.24 43.76 4 41 4 L 9 4 z M 25 11 C 33.27 11 40 16.359219 40 22.949219 C 40 25.579219 38.959297 27.960781 36.779297 30.300781 C 35.209297 32.080781 32.660547 34.040156 30.310547 35.660156 C 27.960547 37.260156 25.8 38.519609 25 38.849609 C 24.68 38.979609 24.44 39.039062 24.25 39.039062 C 23.59 39.039062 23.649219 38.340781 23.699219 38.050781 C 23.739219 37.830781 23.919922 36.789063 23.919922 36.789062 C 23.969922 36.419063 24.019141 35.830937 23.869141 35.460938 C 23.699141 35.050938 23.029062 34.840234 22.539062 34.740234 C 15.339063 33.800234 10 28.849219 10 22.949219 C 10 16.359219 16.73 11 25 11 z M 23.992188 18.998047 C 23.488379 19.007393 23 19.391875 23 20 L 23 26 C 23 26.552 23.448 27 24 27 C 24.552 27 25 26.552 25 26 L 25 23.121094 L 27.185547 26.580078 C 27.751547 27.372078 29 26.973 29 26 L 29 20 C 29 19.448 28.552 19 28 19 C 27.448 19 27 19.448 27 20 L 27 23 L 24.814453 19.419922 C 24.602203 19.122922 24.294473 18.992439 23.992188 18.998047 z M 15 19 C 14.448 19 14 19.448 14 20 L 14 26 C 14 26.552 14.448 27 15 27 L 18 27 C 18.552 27 19 26.552 19 26 C 19 25.448 18.552 25 18 25 L 16 25 L 16 20 C 16 19.448 15.552 19 15 19 z M 21 19 C 20.448 19 20 19.448 20 20 L 20 26 C 20 26.552 20.448 27 21 27 C 21.552 27 22 26.552 22 26 L 22 20 C 22 19.448 21.552 19 21 19 z M 31 19 C 30.448 19 30 19.448 30 20 L 30 26 C 30 26.552 30.448 27 31 27 L 34 27 C 34.552 27 35 26.552 35 26 C 35 25.448 34.552 25 34 25 L 32 25 L 32 24 L 34 24 C 34.553 24 35 23.552 35 23 C 35 22.448 34.553 22 34 22 L 32 22 L 32 21 L 34 21 C 34.552 21 35 20.552 35 20 C 35 19.448 34.552 19 34 19 L 31 19 z\"/></svg>"),
Rules: []string{
"||gcld-line.com^",
"||lin.ee^",
"||line-apps-beta.com^",
"||line-apps-rc.com^",
"||line-apps.com^",
"||line-cdn.net^",
"||line-scdn.net^",
"||line.me^",
"||line.naver.jp^",
"||linecorp.com^",
"||linemyshop.com^",
"||lineshoppingseller.com^",
},
}, {
ID: "mail_ru",
Name: "Mail.ru",
@@ -1308,13 +1345,13 @@ var blockedServices = []blockedService{{
"||aus.social^",
"||awscommunity.social^",
"||cyberplace.social^",
"||defcon.social^",
"||det.social^",
"||fosstodon.org^",
"||glasgow.social^",
"||h4.io^",
"||hachyderm.io^",
"||hessen.social^",
"||home.social^",
"||hostux.social^",
"||ieji.de^",
"||indieweb.social^",
@@ -1333,6 +1370,7 @@ var blockedServices = []blockedService{{
"||mastodon.au^",
"||mastodon.bida.im^",
"||mastodon.com.tr^",
"||mastodon.eus^",
"||mastodon.green^",
"||mastodon.ie^",
"||mastodon.iriseden.eu^",
@@ -1360,10 +1398,8 @@ var blockedServices = []blockedService{{
"||mindly.social^",
"||mstdn.ca^",
"||mstdn.jp^",
"||mstdn.party^",
"||mstdn.social^",
"||muenchen.social^",
"||nerdculture.de^",
"||newsie.social^",
"||noc.social^",
"||norden.social^",
@@ -1382,6 +1418,7 @@ var blockedServices = []blockedService{{
"||social.anoxinon.de^",
"||social.cologne^",
"||social.dev-wiki.de^",
"||social.linux.pizza^",
"||social.politicaconciencia.org^",
"||social.vivaldi.net^",
"||sself.co^",
@@ -1398,11 +1435,11 @@ var blockedServices = []blockedService{{
"||toot.wales^",
"||troet.cafe^",
"||twingyeo.kr^",
"||uiuxdev.social^",
"||union.place^",
"||universeodon.com^",
"||urbanists.social^",
"||vocalodon.net^",
"||wien.rocks^",
"||wxw.moe^",
},
}, {
@@ -1599,6 +1636,14 @@ var blockedServices = []blockedService{{
"||snapchat.com^",
"||snapkit.co",
},
}, {
ID: "soundcloud",
Name: "SoundCloud",
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 24 24\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"><path d=\"M19 17.75c2.07 0 3.75-1.68 3.75-3.75 0-2.07-1.68-3.75-3.75-3.75-.173 0-.344.012-.511.035-.73-2.337-2.913-4.035-5.489-4.035-.818 0-1.596.171-2.301.48-.273.119-.449.389-.449.687l0 9.583c0 .414.336.75.75.75l8 0zM7.25 8l0 9c0 .414.336.75.75.75.414 0 .75-.336.75-.75l0-9c0-.414-.336-.75-.75-.75-.414 0-.75.336-.75.75zM4.25 10l0 7c0 .414.336.75.75.75.414 0 .75-.336.75-.75l0-7c0-.414-.336-.75-.75-.75-.414 0-.75.336-.75.75zM1.25 12l0 5c0 .414.336.75.75.75.414 0 .75-.336.75-.75l0-5c0-.414-.336-.75-.75-.75-.414 0-.75.336-.75.75z\"/></svg>"),
Rules: []string{
"||sndcdn.com^",
"||soundcloud.com^",
},
}, {
ID: "spotify",
Name: "Spotify",