diff --git a/.gitignore b/.gitignore
index 41cb9f1..7b641af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,8 @@
+# This comment is used to simplify checking local copies of the file. Bump
+# this number every time a significant change is made to this file.
+#
+# AdGuard-Project-Version: 3
+
# Please, DO NOT put your text editors' temporary files here. The more are
# added, the harder it gets to maintain and manage projects' gitignores. Put
# them into your global gitignore file instead.
@@ -6,12 +11,15 @@
#
# Only build, run, and test outputs here. Sorted. With negations at the
# bottom to make sure they take effect.
+*.exe
*.out
*.test
/bin/
/filters/
/github-mirror/
+/test-reports/
/test/
+/tmp/
AdGuardDNS
agdns
asn.mmdb
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9d01da9..74897e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ The format is **not** based on [Keep a Changelog][kec], since the project **does
[kec]: https://keepachangelog.com/en/1.0.0/
[sem]: https://semver.org/spec/v2.0.0.html
+## AGDNS-2998 / Build 1042
+
+- Profiles’ file cache version has been incremented. The new field `StandardEnabled` has been added to access’ object.
+
## AGDNS-3018 / Build 1033
- The environment variables `DNSCHECK_KV_TTL`, `DNSCHECK_KV_TYPE` have been added.
diff --git a/Makefile b/Makefile
index cd01e3f..0dd7888 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ BRANCH = $${BRANCH:-$$(git rev-parse --abbrev-ref HEAD)}
GOAMD64 = v1
GOPROXY = https://proxy.golang.org|direct
GOTELEMETRY = off
-GOTOOLCHAIN = go1.24.5
+GOTOOLCHAIN = go1.24.6
RACE = 0
REVISION = $${REVISION:-$$(git rev-parse --short HEAD)}
VERSION = 0
diff --git a/README.md b/README.md
index e4d20a5..25ebbe4 100644
--- a/README.md
+++ b/README.md
@@ -71,6 +71,6 @@ You can sign up for a personal AdGuard DNS account and get access to the followi
## Software license
-Copyright (C) 2022-2024 AdGuard Software Ltd.
+Copyright (C) 2022-2025 AdGuard Software Ltd.
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
diff --git a/doc/debughttp.md b/doc/debughttp.md
index c84640a..e23caab 100644
--- a/doc/debughttp.md
+++ b/doc/debughttp.md
@@ -112,6 +112,7 @@ Supported IDs:
- `profiledb_full`
- `profiledb`
- `rulestat`
+- `standard_profile_access`
- `ticket_rotator`
- `tlsconfig`
- `websvc`
diff --git a/doc/environment.md b/doc/environment.md
index a12d0c2..c778541 100644
--- a/doc/environment.md
+++ b/doc/environment.md
@@ -65,6 +65,11 @@ AdGuard DNS uses [environment variables][wiki-env] to store some of the more sen
- [`SESSION_TICKET_REFRESH_INTERVAL`](#SESSION_TICKET_REFRESH_INTERVAL)
- [`SESSION_TICKET_TYPE`](#SESSION_TICKET_TYPE)
- [`SESSION_TICKET_URL`](#SESSION_TICKET_URL)
+- [`STANDARD_ACCESS_API_KEY`](#STANDARD_ACCESS_API_KEY)
+- [`STANDARD_ACCESS_REFRESH_INTERVAL`](#STANDARD_ACCESS_REFRESH_INTERVAL)
+- [`STANDARD_ACCESS_TIMEOUT`](#STANDARD_ACCESS_TIMEOUT)
+- [`STANDARD_ACCESS_TYPE`](#STANDARD_ACCESS_TYPE)
+- [`STANDARD_ACCESS_URL`](#STANDARD_ACCESS_URL)
- [`SSL_KEY_LOG_FILE`](#SSL_KEY_LOG_FILE)
- [`VERBOSE`](#VERBOSE)
- [`WEB_STATIC_DIR_ENABLED`](#WEB_STATIC_DIR_ENABLED)
@@ -535,6 +540,36 @@ The base backend URL used as a TLS session ticket storage, when [`SESSION_TICKET
**Default:** **Unset.**
+## `STANDARD_ACCESS_API_KEY`
+
+The API key to use when authenticating requests to the standard access settings storage API, if [`STANDARD_ACCESS_TYPE`](#STANDARD_ACCESS_TYPE) is set to `backend`. The API key should be valid as defined by [RFC 6750].
+
+**Default:** **Unset.**
+
+## `STANDARD_ACCESS_REFRESH_INTERVAL`
+
+The interval between standard access settings updates, when [`STANDARD_ACCESS_TYPE`](#STANDARD_ACCESS_TYPE) is set to `backend`, as a human-readable duration.
+
+**Default:** **Unset.**
+
+## `STANDARD_ACCESS_TIMEOUT`
+
+The timeout for standard access settings updates, when [`STANDARD_ACCESS_TYPE`](#STANDARD_ACCESS_TYPE) is set to `backend`, as a human-readable duration.
+
+**Default:** **Unset.**
+
+## `STANDARD_ACCESS_TYPE`
+
+The type of standard access settings storage. Its possible values are: `off` and `backend`. When set to `backend`, the [`STANDARD_ACCESS_API_KEY`](#STANDARD_ACCESS_API_KEY), [`STANDARD_ACCESS_REFRESH_INTERVAL`](#STANDARD_ACCESS_REFRESH_INTERVAL), [`STANDARD_ACCESS_TIMEOUT`](#STANDARD_ACCESS_TIMEOUT), and [`STANDARD_ACCESS_URL`](#STANDARD_ACCESS_URL) variables are required.
+
+**Default:** **Unset.**
+
+## `STANDARD_ACCESS_URL`
+
+The base backend URL used as a standard access settings storage, when [`STANDARD_ACCESS_TYPE`](#STANDARD_ACCESS_TYPE) is set to `backend`. Supports gRPC(S) (`grpc://` and`grpcs://`) URLs. See the [external API requirements section][ext-backend-dnscheck].
+
+**Default:** **Unset.**
+
## `SSL_KEY_LOG_FILE`
If set, TLS key logs are written to this file to allow other programs (i.e. Wireshark) to decrypt packets. **Must only be used for debug purposes**.
diff --git a/go.mod b/go.mod
index 3bb4a5f..4e4af79 100644
--- a/go.mod
+++ b/go.mod
@@ -1,79 +1,80 @@
module github.com/AdguardTeam/AdGuardDNS
-go 1.24.5
+go 1.24.6
require (
// NOTE: Do not change the pseudoversion.
github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-00010101000000-000000000000
- github.com/AdguardTeam/golibs v0.32.15
- github.com/AdguardTeam/urlfilter v0.20.0
+ github.com/AdguardTeam/golibs v0.34.0
+ github.com/AdguardTeam/urlfilter v0.21.0
github.com/ameshkov/dnscrypt/v2 v2.4.0
github.com/axiomhq/hyperloglog v0.2.5
github.com/bluele/gcache v0.0.2
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500
github.com/caarlos0/env/v7 v7.1.0
- github.com/getsentry/sentry-go v0.34.0
+ github.com/getsentry/sentry-go v0.35.1
github.com/gomodule/redigo v1.9.2
+ github.com/google/go-cmp v0.7.0
github.com/google/renameio/v2 v2.0.0
- github.com/miekg/dns v1.1.66
+ github.com/miekg/dns v1.1.68
github.com/oschwald/maxminddb-golang v1.13.1
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
- github.com/prometheus/client_golang v1.22.0
+ github.com/prometheus/client_golang v1.23.0
github.com/prometheus/client_model v0.6.2
- github.com/prometheus/common v0.64.0
- github.com/quic-go/quic-go v0.52.0
- github.com/stretchr/testify v1.10.0
- golang.org/x/crypto v0.39.0
- golang.org/x/net v0.41.0
- golang.org/x/sys v0.34.0
+ github.com/prometheus/common v0.65.0
+ github.com/quic-go/quic-go v0.54.0
+ github.com/stretchr/testify v1.11.1
+ github.com/viktordanov/golang-lru v0.5.6
+ golang.org/x/crypto v0.41.0
+ golang.org/x/net v0.43.0
+ golang.org/x/sys v0.35.0
golang.org/x/time v0.12.0
- google.golang.org/grpc v1.73.0
- google.golang.org/protobuf v1.36.6
+ google.golang.org/grpc v1.75.0
+ google.golang.org/protobuf v1.36.8
gopkg.in/yaml.v2 v2.4.0
)
require (
- cloud.google.com/go v0.121.3 // indirect
+ cloud.google.com/go v0.121.6 // indirect
cloud.google.com/go/ai v0.12.1 // indirect
- cloud.google.com/go/auth v0.16.2 // indirect
+ cloud.google.com/go/auth v0.16.5 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
- cloud.google.com/go/compute/metadata v0.7.0 // indirect
+ cloud.google.com/go/compute/metadata v0.8.0 // indirect
cloud.google.com/go/longrunning v0.6.7 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/ameshkov/dnsstamps v1.0.3 // indirect
+ github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/caarlos0/env/v11 v11.3.1 // indirect
github.com/ccojocar/zxcvbn-go v1.0.4 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/golangci/misspell v0.7.0 // indirect
github.com/google/generative-ai-go v0.20.1 // indirect
- github.com/google/go-cmp v0.7.0 // indirect
- github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a // indirect
+ github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
- github.com/googleapis/gax-go/v2 v2.14.2 // indirect
+ github.com/googleapis/gax-go/v2 v2.15.0 // indirect
github.com/gookit/color v1.5.4 // indirect
- github.com/gordonklaus/ineffassign v0.1.0 // indirect
+ github.com/gordonklaus/ineffassign v0.2.0 // indirect
github.com/jstemmer/go-junit-report/v2 v2.1.0 // indirect
github.com/kamstrup/intmap v0.5.1 // indirect
github.com/kisielk/errcheck v1.9.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
- github.com/onsi/ginkgo/v2 v2.23.4 // indirect
+ github.com/onsi/ginkgo/v2 v2.25.1 // indirect
github.com/panjf2000/ants/v2 v2.11.3 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/procfs v0.16.1 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+ github.com/prometheus/procfs v0.17.0 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
- github.com/securego/gosec/v2 v2.22.5 // indirect
+ github.com/securego/gosec/v2 v2.22.8 // indirect
github.com/uudashr/gocognit v1.2.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
@@ -82,21 +83,20 @@ require (
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
- go.uber.org/automaxprocs v1.6.0 // indirect
- go.uber.org/mock v0.5.2 // indirect
- golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
- golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b // indirect
- golang.org/x/mod v0.26.0 // indirect
+ go.uber.org/mock v0.6.0 // indirect
+ golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
+ golang.org/x/exp/typeparams v0.0.0-20250819193227-8b4c13bb791b // indirect
+ golang.org/x/mod v0.27.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.16.0 // indirect
- golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b // indirect
- golang.org/x/term v0.33.0 // indirect
- golang.org/x/text v0.27.0 // indirect
- golang.org/x/tools v0.34.0 // indirect
+ golang.org/x/telemetry v0.0.0-20250822161441-f407b8c191ff // indirect
+ golang.org/x/term v0.34.0 // indirect
+ golang.org/x/text v0.28.0 // indirect
+ golang.org/x/tools v0.36.0 // indirect
golang.org/x/vuln v1.1.4 // indirect
- google.golang.org/api v0.241.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
+ google.golang.org/api v0.248.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/tools v0.6.1 // indirect
diff --git a/go.sum b/go.sum
index ab675e3..ad8f376 100644
--- a/go.sum
+++ b/go.sum
@@ -1,27 +1,31 @@
-cloud.google.com/go v0.121.3 h1:84RD+hQXNdY5Sw/MWVAx5O9Aui/rd5VQ9HEcdN19afo=
-cloud.google.com/go v0.121.3/go.mod h1:6vWF3nJWRrEUv26mMB3FEIU/o1MQNVPG1iHdisa2SJc=
+cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
+cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
cloud.google.com/go/ai v0.12.1 h1:m1n/VjUuHS+pEO/2R4/VbuuEIkgk0w67fDQvFaMngM0=
cloud.google.com/go/ai v0.12.1/go.mod h1:5vIPNe1ZQsVZqCliXIPL4QnhObQQY4d9hAGHdVc4iw4=
-cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
-cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
+cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI=
+cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
-cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
-cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
+cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA=
+cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
-github.com/AdguardTeam/golibs v0.32.15 h1:arDRDWiZCH3g5Onr8AqMnOHhaOppNoBpgC3DNhmeDeA=
-github.com/AdguardTeam/golibs v0.32.15/go.mod h1:G9CzUOzx87J+2u+eClJrrwWD7lMbROvuUnT8uvDUzIA=
-github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs=
-github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk=
+github.com/AdguardTeam/golibs v0.34.0 h1:JQK024DkTYxE7vsPVsYsoyDHW/53Nun7OYb9qscniK8=
+github.com/AdguardTeam/golibs v0.34.0/go.mod h1:K4C2EbfSEM1zY5YXoti9SfbTAHN/kIX97LpDtCwORrM=
+github.com/AdguardTeam/urlfilter v0.21.0 h1:ThIxiP7yoaXt8JTEroGQeU5ftQSoFpUq+t1L+TIx2pA=
+github.com/AdguardTeam/urlfilter v0.21.0/go.mod h1:xoZ3AF5qpE9ngbbeSShY9hgVeyHtm9MdH5xH1u714Wg=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
+github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
+github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/ameshkov/dnscrypt/v2 v2.4.0 h1:if6ZG2cuQmcP2TwSY+D0+8+xbPfoatufGlOQTMNkI9o=
github.com/ameshkov/dnscrypt/v2 v2.4.0/go.mod h1:WpEFV2uhebXb8Jhes/5/fSdpmhGV8TL22RDaeWwV6hI=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
github.com/axiomhq/hyperloglog v0.2.5 h1:Hefy3i8nAs8zAI/tDp+wE7N+Ltr8JnwiW3875pvl0N8=
github.com/axiomhq/hyperloglog v0.2.5/go.mod h1:DLUK9yIzpU5B6YFLjxTIcbHu1g4Y1WQb1m5RH3radaM=
+github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
+github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
@@ -36,16 +40,16 @@ github.com/ccojocar/zxcvbn-go v1.0.4 h1:FWnCIRMXPj43ukfX000kvBZvV6raSxakYr1nzyNr
github.com/ccojocar/zxcvbn-go v1.0.4/go.mod h1:3GxGX+rHmueTUMvm5ium7irpyjmm7ikxYFOSJB21Das=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33 h1:ucRHb6/lvW/+mTEIGbvhcYU3S8+uSNkuMjx/qZFfhtM=
github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
-github.com/getsentry/sentry-go v0.34.0 h1:1FCHBVp8TfSc8L10zqSwXUZNiOSF+10qw4czjarTiY4=
-github.com/getsentry/sentry-go v0.34.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
+github.com/getsentry/sentry-go v0.35.1 h1:iopow6UVLE2aXu46xKVIs8Z9D/YZkJrHkgozrxa+tOQ=
+github.com/getsentry/sentry-go v0.35.1/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -72,8 +76,8 @@ github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18=
-github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
+github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY=
+github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
@@ -84,12 +88,12 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
-github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
-github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
+github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
+github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
-github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s=
-github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
+github.com/gordonklaus/ineffassign v0.2.0 h1:Uths4KnmwxNJNzq87fwQQDDnbNb7De00VOk9Nu0TySs=
+github.com/gordonklaus/ineffassign v0.2.0/go.mod h1:TIpymnagPSexySzs7F9FnO1XFTy8IT3a59vmZp5Y9Lw=
github.com/jstemmer/go-junit-report/v2 v2.1.0 h1:X3+hPYlSczH9IMIpSC9CQSZA0L+BipYafciZUWHEmsc=
github.com/jstemmer/go-junit-report/v2 v2.1.0/go.mod h1:mgHVr7VUo5Tn8OLVr1cKnLuEy0M92wdRntM99h7RkgQ=
github.com/kamstrup/intmap v0.5.1 h1:ENGAowczZA+PJPYYlreoqJvWgQVtAmX1l899WfYFVK0=
@@ -106,14 +110,14 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
-github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
-github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
+github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
+github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
-github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
-github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
-github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
+github.com/onsi/ginkgo/v2 v2.25.1 h1:Fwp6crTREKM+oA6Cz4MsO8RhKQzs2/gOIVOUscMAfZY=
+github.com/onsi/ginkgo/v2 v2.25.1/go.mod h1:ppTWQ1dh9KM/F1XgpeRqelR+zHVwV81DGRSDnFxK7Sk=
+github.com/onsi/gomega v1.38.0 h1:c/WX+w8SLAinvuKKQFh77WEucCnPk4j2OTUr7lt7BeY=
+github.com/onsi/gomega v1.38.0/go.mod h1:OcXcwId0b9QsE7Y49u+BTrL4IdKOBOKnD6VQNTJEB6o=
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg=
@@ -124,47 +128,46 @@ github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
-github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
-github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
-github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
-github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
+github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
+github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
-github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4=
-github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
-github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
-github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
+github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
+github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
+github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
+github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
-github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
-github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
+github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
+github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
-github.com/securego/gosec/v2 v2.22.5 h1:ySws9uwOeE42DsG54v2moaJfh7r08Ev7SAYJuoMDfRA=
-github.com/securego/gosec/v2 v2.22.5/go.mod h1:AWfgrFsVewk5LKobsPWlygCHt8K91boVPyL6GUZG5NY=
+github.com/securego/gosec/v2 v2.22.8 h1:3NMpmfXO8wAVFZPNsd3EscOTa32Jyo6FLLlW53bexMI=
+github.com/securego/gosec/v2 v2.22.8/go.mod h1:ZAw8K2ikuH9qDlfdV87JmNghnVfKB1XC7+TVzk6Utto=
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYRA=
github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU=
+github.com/viktordanov/golang-lru v0.5.6 h1:wEyMgglEo5IZ7Maxeh8E2jCPskpQnt6FJAYl1/TJ6ac=
+github.com/viktordanov/golang-lru v0.5.6/go.mod h1:R91CBCcMhp6TYUy8NHP/PJ09sk5BTDwb8KMO21CELes=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
-github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
@@ -187,72 +190,56 @@ go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
-go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
-go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
-golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
-golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
-golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
-golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b h1:KdrhdYPDUvJTvrDK9gdjfFd6JTk8vA1WJoldYSi0kHo=
-golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ=
-golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
-golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
-golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
+go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
+go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
+golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
+golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
+golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
+golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
+golang.org/x/exp/typeparams v0.0.0-20250819193227-8b4c13bb791b h1:GU1ttDuJS89SePnuEsEuLj7dMMFP2JkGsDV1Z51iDXo=
+golang.org/x/exp/typeparams v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms=
+golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
+golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
+golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
+golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
-golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ=
-golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
-golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
-golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/telemetry v0.0.0-20250822161441-f407b8c191ff h1:ey0rzo8V0Po6WkHMbhGVL6zNkuYDBe9iP5toIRchj9Q=
+golang.org/x/telemetry v0.0.0-20250822161441-f407b8c191ff/go.mod h1:JIJwPkb04vX0KeIBbQ7epGtgIjA8ihHbsAtW4A/lIQ4=
+golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
+golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
+golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
+golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
-golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
+golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
+golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
+golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
+golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
+golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
+golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8=
golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.241.0 h1:QKwqWQlkc6O895LchPEDUSYr22Xp3NCxpQRiWTB6avE=
-google.golang.org/api v0.241.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
-google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
-google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
-google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU=
-google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
-google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
-google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
+gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
+gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
+google.golang.org/api v0.248.0 h1:hUotakSkcwGdYUqzCRc5yGYsg4wXxpkKlW5ryVqvC1Y=
+google.golang.org/api v0.248.0/go.mod h1:yAFUAF56Li7IuIQbTFoLwXTCI6XCFKueOlS7S9e4F9k=
+google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
+google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
+google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 h1:APHvLLYBhtZvsbnpkfknDZ7NyH4z5+ub/I0u8L3Oz6g=
+google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1/go.mod h1:xUjFWUnWDpZ/C0Gu0qloASKFb6f8/QXiiXhSPFsD668=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 h1:pmJpJEvT846VzausCQ5d7KreSROcDqmO388w5YbnltA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
+google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
+google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
-google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
-google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
+google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/go.work b/go.work
index 804fc4e..03ae774 100644
--- a/go.work
+++ b/go.work
@@ -1,4 +1,4 @@
-go 1.24.5
+go 1.24.6
use (
.
diff --git a/go.work.sum b/go.work.sum
index 5be767c..f0e2372 100644
--- a/go.work.sum
+++ b/go.work.sum
@@ -11,6 +11,7 @@ cel.dev/expr v0.20.0 h1:OunBvVCfvpWlt4dN7zg3FM6TDkzOePe1+foGJ9AXeeI=
cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
cel.dev/expr v0.23.0 h1:wUb94w6OYQS4uXraxo9U+wUAs9jT47Xvl4iPgAwM2ss=
cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
+cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
@@ -183,6 +184,7 @@ cloud.google.com/go/storage v1.51.0/go.mod h1:YEJfu/Ki3i5oHC/7jyTgsGZwdQ8P9hqMqv
cloud.google.com/go/storage v1.53.0 h1:gg0ERZwL17pJ+Cz3cD2qS60w1WMDnwcm5YPAIQBHUAw=
cloud.google.com/go/storage v1.53.0/go.mod h1:7/eO2a/srr9ImZW9k5uufcNahT2+fPb8w5it1i5boaA=
cloud.google.com/go/storage v1.55.0/go.mod h1:ztSmTTwzsdXe5syLVS0YsbFxXuvEmEyZj7v7zChEmuY=
+cloud.google.com/go/storage v1.56.0/go.mod h1:Tpuj6t4NweCLzlNbw9Z9iwxEkrSem20AetIeH/shgVU=
cloud.google.com/go/storagetransfer v1.10.4/go.mod h1:vef30rZKu5HSEf/x1tK3WfWrL0XVoUQN/EPDRGPzjZs=
cloud.google.com/go/talent v1.6.6/go.mod h1:y/WQDKrhVz12WagoarpAIyKKMeKGKHWPoReZ0g8tseQ=
cloud.google.com/go/texttospeech v1.7.5/go.mod h1:tzpCuNWPwrNJnEa4Pu5taALuZL4QRRLcb+K9pbhXT6M=
@@ -232,6 +234,8 @@ github.com/AdguardTeam/golibs v0.32.11/go.mod h1:LXr0gqqZuVpt+L+bP3Nnr0/CecLmm3r
github.com/AdguardTeam/gomitmproxy v0.2.0 h1:rvCOf17pd1/CnMyMQW891zrEiIQBpQ8cIGjKN9pinUU=
github.com/AdguardTeam/gomitmproxy v0.2.1 h1:p9gr8Er1TYvf+7ic81Ax1sZ62UNCsMTZNbm7tC59S9o=
github.com/AdguardTeam/gomitmproxy v0.2.1/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
+github.com/AdguardTeam/urlfilter v0.21.0 h1:ThIxiP7yoaXt8JTEroGQeU5ftQSoFpUq+t1L+TIx2pA=
+github.com/AdguardTeam/urlfilter v0.21.0/go.mod h1:xoZ3AF5qpE9ngbbeSShY9hgVeyHtm9MdH5xH1u714Wg=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
@@ -251,12 +255,15 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0/go.mod h1:2bIszWvQRlJVmJLiuLhukLImRjKPcYdzzsx6darK02A=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0/go.mod h1:ZV4VOm0/eHR06JLrXWe09068dHpr3TRpY9Uo7T+anuA=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo=
github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk=
github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
@@ -312,6 +319,7 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
+github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
@@ -362,6 +370,7 @@ github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k=
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
+github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
@@ -380,7 +389,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -453,6 +461,7 @@ github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
+github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -514,6 +523,7 @@ github.com/golang/glog v1.2.3 h1:oDTdz9f5VGVVNGu/Q7UXKWYsD0873HXLHdJUNBsSEKM=
github.com/golang/glog v1.2.3/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc=
github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
+github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -1150,7 +1160,6 @@ go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxt
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
-go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
@@ -1161,6 +1170,7 @@ go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9f
go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc=
go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
+go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -1704,6 +1714,7 @@ google.golang.org/genproto/googleapis/bytestream v0.0.0-20250512202823-5a2f75b73
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250528174236-200df99c418a/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822 h1:zWFRixYR5QlotL+Uv3YfsPRENIrQFXiGs+iwqel6fOQ=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y=
+google.golang.org/genproto/googleapis/bytestream v0.0.0-20250818200422-3122310a409c/go.mod h1:1kGGe25NDrNJYgta9Rp2QLLXWS1FLVMMXNvihbhK0iE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
diff --git a/internal/access/access.go b/internal/access/access.go
index 7e0dbce..3a716d2 100644
--- a/internal/access/access.go
+++ b/internal/access/access.go
@@ -4,10 +4,10 @@ package access
import (
"fmt"
"net/netip"
- "strings"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdurlflt"
"github.com/AdguardTeam/golibs/netutil"
- "github.com/AdguardTeam/golibs/stringutil"
+ "github.com/AdguardTeam/golibs/syncutil"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist"
)
@@ -32,25 +32,28 @@ type Interface interface {
type Global struct {
blockedHostsEng *urlfilter.DNSEngine
blockedNets netutil.SubnetSet
+ reqPool *syncutil.Pool[urlfilter.DNSRequest]
+ resPool *syncutil.Pool[urlfilter.DNSResult]
}
-// NewGlobal create a new Global from provided parameters.
+// NewGlobal creates a new *Global from provided parameters.
func NewGlobal(blockedDomains []string, blockedSubnets []netip.Prefix) (g *Global, err error) {
g = &Global{
blockedNets: netutil.SliceSubnetSet(blockedSubnets),
+ reqPool: syncutil.NewPool(func() (req *urlfilter.DNSRequest) {
+ return &urlfilter.DNSRequest{}
+ }),
+ resPool: syncutil.NewPool(func() (v *urlfilter.DNSResult) {
+ return &urlfilter.DNSResult{}
+ }),
}
- b := &strings.Builder{}
- for _, h := range blockedDomains {
- stringutil.WriteToBuilder(b, strings.ToLower(h), "\n")
- }
-
- lists := []filterlist.RuleList{
- &filterlist.StringRuleList{
+ lists := []filterlist.Interface{
+ filterlist.NewBytes(&filterlist.BytesConfig{
ID: blocklistFilterID,
- RulesText: b.String(),
+ RulesText: agdurlflt.RulesToBytesLower(blockedDomains),
IgnoreCosmetic: true,
- },
+ }),
}
rulesStrg, err := filterlist.NewRuleStorage(lists)
@@ -68,16 +71,37 @@ var _ Interface = (*Global)(nil)
// IsBlockedHost implements the [Interface] interface for *Global.
func (g *Global) IsBlockedHost(host string, qt uint16) (blocked bool) {
- res, matched := g.blockedHostsEng.MatchRequest(&urlfilter.DNSRequest{
- Hostname: host,
- DNSType: qt,
- })
+ return matchBlocked(host, qt, g.blockedHostsEng, g.reqPool, g.resPool)
+}
- if matched && res.NetworkRule != nil {
+// matchBlocked is a helper function that handles matching of request using DNS
+// engines and pools of requests and results. engine, reqPool, and resPool must
+// not be nil.
+func matchBlocked(
+ host string,
+ qt uint16,
+ engine *urlfilter.DNSEngine,
+ reqPool *syncutil.Pool[urlfilter.DNSRequest],
+ resPool *syncutil.Pool[urlfilter.DNSResult],
+) (blocked bool) {
+ req := reqPool.Get()
+ defer reqPool.Put(req)
+
+ req.Reset()
+ req.Hostname = host
+ req.DNSType = qt
+
+ res := resPool.Get()
+ defer resPool.Put(res)
+
+ res.Reset()
+
+ blocked = engine.MatchRequestInto(req, res)
+ if blocked && res.NetworkRule != nil {
return !res.NetworkRule.Whitelist
}
- return matched
+ return blocked
}
// IsBlockedIP implements the [Interface] interface for *Global.
diff --git a/internal/access/access_test.go b/internal/access/access_test.go
index 23cb4f2..55b9a47 100644
--- a/internal/access/access_test.go
+++ b/internal/access/access_test.go
@@ -17,7 +17,59 @@ const testTimeout = 1 * time.Second
// testAccessMtrc is the common profile access engine metrics for tests.
var testAccessMtrc = access.EmptyProfileMetrics{}
-func TestGlobal_IsBlockedHost(t *testing.T) {
+// testCases is the list of test cases for the [IsBlocked] function.
+var testCases = []struct {
+ want assert.BoolAssertionFunc
+ name string
+ host string
+ qt uint16
+}{{
+ want: assert.False,
+ name: "pass",
+ host: "pass.test",
+ qt: dns.TypeA,
+}, {
+ want: assert.True,
+ name: "blocked_domain_a",
+ host: "block.test",
+ qt: dns.TypeA,
+}, {
+ want: assert.True,
+ name: "blocked_domain_https",
+ host: "block.test",
+ qt: dns.TypeHTTPS,
+}, {
+ want: assert.True,
+ name: "uppercase_domain",
+ host: "uppercase.test",
+ qt: dns.TypeHTTPS,
+}, {
+ want: assert.False,
+ name: "pass_qt",
+ host: "block_aaaa.test",
+ qt: dns.TypeA,
+}, {
+ want: assert.True,
+ name: "block_qt",
+ host: "block_aaaa.test",
+ qt: dns.TypeAAAA,
+}, {
+ want: assert.True,
+ name: "allowlist_block",
+ host: "block.allowlist.test",
+ qt: dns.TypeA,
+}, {
+ want: assert.False,
+ name: "allowlist_test",
+ host: "allow.allowlist.test",
+ qt: dns.TypeA,
+}}
+
+// newTestGlobal is a test helper that returns a new [access.Global] with test
+// rules.
+func newTestGlobal(t testing.TB) (global *access.Global) {
+ t.Helper()
+
global, err := access.NewGlobal([]string{
"block.test",
"UPPERCASE.test",
@@ -27,52 +79,13 @@ func TestGlobal_IsBlockedHost(t *testing.T) {
}, nil)
require.NoError(t, err)
- testCases := []struct {
- want assert.BoolAssertionFunc
- name string
- host string
- qt uint16
- }{{
- want: assert.False,
- name: "pass",
- host: "pass.test",
- qt: dns.TypeA,
- }, {
- want: assert.True,
- name: "blocked_domain_A",
- host: "block.test",
- qt: dns.TypeA,
- }, {
- want: assert.True,
- name: "blocked_domain_HTTPS",
- host: "block.test",
- qt: dns.TypeHTTPS,
- }, {
- want: assert.True,
- name: "uppercase_domain",
- host: "uppercase.test",
- qt: dns.TypeHTTPS,
- }, {
- want: assert.False,
- name: "pass_qt",
- host: "block_aaaa.test",
- qt: dns.TypeA,
- }, {
- want: assert.True,
- name: "block_qt",
- host: "block_aaaa.test",
- qt: dns.TypeAAAA,
- }, {
- want: assert.True,
- name: "allowlist_block",
- host: "block.allowlist.test",
- qt: dns.TypeA,
- }, {
- want: assert.False,
- name: "allowlist_test",
- host: "allow.allowlist.test",
- qt: dns.TypeA,
- }}
+ return global
+}
+
+func TestGlobal_IsBlockedHost(t *testing.T) {
+ t.Parallel()
+
+ global := newTestGlobal(t)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@@ -83,9 +96,11 @@ func TestGlobal_IsBlockedHost(t *testing.T) {
}
func TestGlobal_IsBlockedIP(t *testing.T) {
+ t.Parallel()
+
global, err := access.NewGlobal([]string{}, []netip.Prefix{
- netip.MustParsePrefix("1.1.1.1/32"),
- netip.MustParsePrefix("2.2.2.0/8"),
+ netip.MustParsePrefix("192.0.2.1/32"),
+ netip.MustParsePrefix("198.51.100.0/24"),
})
require.NoError(t, err)
@@ -96,19 +111,19 @@ func TestGlobal_IsBlockedIP(t *testing.T) {
}{{
want: assert.False,
name: "pass",
- ip: netip.MustParseAddr("1.1.1.0"),
+ ip: netip.MustParseAddr("192.0.2.0"),
}, {
want: assert.True,
name: "block_ip",
- ip: netip.MustParseAddr("1.1.1.1"),
+ ip: netip.MustParseAddr("192.0.2.1"),
}, {
want: assert.False,
name: "pass_subnet",
- ip: netip.MustParseAddr("1.2.2.2"),
+ ip: netip.MustParseAddr("198.51.101.1"),
}, {
want: assert.True,
name: "block_subnet",
- ip: netip.MustParseAddr("2.2.2.2"),
+ ip: netip.MustParseAddr("198.51.100.1"),
}}
for _, tc := range testCases {
@@ -118,3 +133,77 @@ func TestGlobal_IsBlockedIP(t *testing.T) {
})
}
}
+
+func BenchmarkGlobal_IsBlockedHost(b *testing.B) {
+ global := newTestGlobal(b)
+
+ for _, tc := range testCases {
+ b.Run(tc.name, func(b *testing.B) {
+ var blocked bool
+
+ b.ReportAllocs()
+ for b.Loop() {
+ blocked = global.IsBlockedHost(tc.host, tc.qt)
+ }
+
+ tc.want(b, blocked)
+ })
+ }
+
+ // Most recent results:
+ //
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/access
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkGlobal_IsBlockedHost/pass-16 2313513 515.0 ns/op 16 B/op 1 allocs/op
+ // BenchmarkGlobal_IsBlockedHost/blocked_domain_a-16 1604049 683.4 ns/op 24 B/op 1 allocs/op
+ // BenchmarkGlobal_IsBlockedHost/blocked_domain_https-16 1981204 597.7 ns/op 24 B/op 1 allocs/op
+ // BenchmarkGlobal_IsBlockedHost/uppercase_domain-16 2093197 590.5 ns/op 24 B/op 1 allocs/op
+ // BenchmarkGlobal_IsBlockedHost/pass_qt-16 1961065 653.3 ns/op 24 B/op 1 allocs/op
+ // BenchmarkGlobal_IsBlockedHost/block_qt-16 768783 1567 ns/op 24 B/op 1 allocs/op
+ // BenchmarkGlobal_IsBlockedHost/allowlist_block-16 759159 1890 ns/op 32 B/op 1 allocs/op
+ // BenchmarkGlobal_IsBlockedHost/allowlist_test-16 371722 3170 ns/op 32 B/op 1 allocs/op
+}
+
+func BenchmarkGlobal_IsBlockedIP(b *testing.B) {
+ global, err := access.NewGlobal([]string{}, []netip.Prefix{
+ netip.MustParsePrefix("192.0.2.0/24"),
+ })
+ require.NoError(b, err)
+
+ b.Run("pass", func(b *testing.B) {
+ ip := netip.MustParseAddr("192.0.3.0")
+
+ var blocked bool
+
+ b.ReportAllocs()
+ for b.Loop() {
+ blocked = global.IsBlockedIP(ip)
+ }
+
+ assert.False(b, blocked)
+ })
+
+ b.Run("block", func(b *testing.B) {
+ ip := netip.MustParseAddr("192.0.2.0")
+
+ var blocked bool
+
+ b.ReportAllocs()
+ for b.Loop() {
+ blocked = global.IsBlockedIP(ip)
+ }
+
+ assert.True(b, blocked)
+ })
+
+ // Most recent results:
+ //
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/access
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkGlobal_IsBlockedIP/pass-16 100000000 10.18 ns/op 0 B/op 0 allocs/op
+ // BenchmarkGlobal_IsBlockedIP/block-16 141876058 8.545 ns/op 0 B/op 0 allocs/op
+}
diff --git a/internal/access/blocker.go b/internal/access/blocker.go
new file mode 100644
index 0000000..8d0c63b
--- /dev/null
+++ b/internal/access/blocker.go
@@ -0,0 +1,38 @@
+package access
+
+import (
+ "context"
+ "net/netip"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/miekg/dns"
+)
+
+// Blocker is the interface to control DNS resolution access.
+type Blocker interface {
+ // IsBlocked returns true if the req should be blocked. req must not be
+ // nil, and req.Question must have one item.
+ IsBlocked(
+ ctx context.Context,
+ req *dns.Msg,
+ rAddr netip.AddrPort,
+ l *geoip.Location,
+ ) (isBlocked bool)
+}
+
+// EmptyBlocker is an empty [Blocker] implementation that does nothing.
+type EmptyBlocker struct{}
+
+// type check
+var _ Blocker = EmptyBlocker{}
+
+// IsBlocked implements the [Blocker] interface for EmptyBlocker. It always
+// returns false.
+func (EmptyBlocker) IsBlocked(
+ _ context.Context,
+ _ *dns.Msg,
+ _ netip.AddrPort,
+ _ *geoip.Location,
+) (isBlocked bool) {
+ return false
+}
diff --git a/internal/access/engine.go b/internal/access/engine.go
index 2ca8db0..5a6bd35 100644
--- a/internal/access/engine.go
+++ b/internal/access/engine.go
@@ -3,12 +3,12 @@ package access
import (
"context"
"fmt"
- "strings"
"sync"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
- "github.com/AdguardTeam/golibs/stringutil"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdurlflt"
+ "github.com/AdguardTeam/golibs/syncutil"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist"
"github.com/miekg/dns"
@@ -18,18 +18,26 @@ import (
//
// TODO(a.garipov): Replace/merge with [custom.Filter].
type blockedHostEngine struct {
- metrics ProfileMetrics
- lazyEngine *urlfilter.DNSEngine
initOnce *sync.Once
+ lazyEngine *urlfilter.DNSEngine
+ reqPool *syncutil.Pool[urlfilter.DNSRequest]
+ resPool *syncutil.Pool[urlfilter.DNSResult]
+ metrics ProfileMetrics
rules []string
}
// newBlockedHostEngine creates a new blockedHostEngine. mtrc must not be nil.
func newBlockedHostEngine(mtrc ProfileMetrics, rules []string) (e *blockedHostEngine) {
return &blockedHostEngine{
- metrics: mtrc,
- rules: rules,
initOnce: &sync.Once{},
+ reqPool: syncutil.NewPool(func() (req *urlfilter.DNSRequest) {
+ return &urlfilter.DNSRequest{}
+ }),
+ resPool: syncutil.NewPool(func() (v *urlfilter.DNSResult) {
+ return &urlfilter.DNSResult{}
+ }),
+ metrics: mtrc,
+ rules: rules,
}
}
@@ -48,31 +56,20 @@ func (e *blockedHostEngine) isBlocked(ctx context.Context, req *dns.Msg) (blocke
})
q := req.Question[0]
- res, matched := e.lazyEngine.MatchRequest(&urlfilter.DNSRequest{
- Hostname: agdnet.NormalizeQueryDomain(q.Name),
- DNSType: q.Qtype,
- })
- if matched && res.NetworkRule != nil {
- return !res.NetworkRule.Whitelist
- }
+ host := agdnet.NormalizeQueryDomain(q.Name)
- return matched
+ return matchBlocked(host, q.Qtype, e.lazyEngine, e.reqPool, e.resPool)
}
// init returns new properly initialized dns engine.
func (e *blockedHostEngine) init() (eng *urlfilter.DNSEngine) {
- b := &strings.Builder{}
- for _, h := range e.rules {
- stringutil.WriteToBuilder(b, strings.ToLower(h), "\n")
- }
-
- lists := []filterlist.RuleList{
- &filterlist.StringRuleList{
+ lists := []filterlist.Interface{
+ filterlist.NewBytes(&filterlist.BytesConfig{
ID: blocklistFilterID,
- RulesText: b.String(),
+ RulesText: agdurlflt.RulesToBytesLower(e.rules),
IgnoreCosmetic: true,
- },
+ }),
}
rulesStrg, err := filterlist.NewRuleStorage(lists)
diff --git a/internal/access/engine_internal_test.go b/internal/access/engine_internal_test.go
index 40d8472..0165777 100644
--- a/internal/access/engine_internal_test.go
+++ b/internal/access/engine_internal_test.go
@@ -109,3 +109,46 @@ func TestBlockedHostEngine_IsBlocked_concurrent(t *testing.T) {
wg.Wait()
}
+
+func BenchmarkBlockedHostEngine_IsBlocked(b *testing.B) {
+ engine := newBlockedHostEngine(EmptyProfileMetrics{}, []string{
+ "block.test",
+ })
+
+ ctx := testutil.ContextWithTimeout(b, testTimeout)
+
+ b.Run("pass", func(b *testing.B) {
+ req := dnsservertest.NewReq("pass.test", dns.TypeA, dns.ClassINET)
+
+ var blocked bool
+
+ b.ReportAllocs()
+ for b.Loop() {
+ blocked = engine.isBlocked(ctx, req)
+ }
+
+ assert.False(b, blocked)
+ })
+
+ b.Run("block", func(b *testing.B) {
+ req := dnsservertest.NewReq("block.test", dns.TypeA, dns.ClassINET)
+
+ var blocked bool
+
+ b.ReportAllocs()
+ for b.Loop() {
+ blocked = engine.isBlocked(ctx, req)
+ }
+
+ assert.True(b, blocked)
+ })
+
+ // Most recent results:
+ //
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/access
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkBlockedHostEngine_IsBlocked/pass-16 3362199 369.1 ns/op 16 B/op 1 allocs/op
+ // BenchmarkBlockedHostEngine_IsBlocked/block-16 2299890 510.6 ns/op 24 B/op 1 allocs/op
+}
diff --git a/internal/access/profile.go b/internal/access/profile.go
index 620b31d..10e72cf 100644
--- a/internal/access/profile.go
+++ b/internal/access/profile.go
@@ -6,6 +6,8 @@ import (
"slices"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/golibs/syncutil"
+ "github.com/AdguardTeam/urlfilter"
"github.com/miekg/dns"
)
@@ -14,18 +16,13 @@ type Profile interface {
// Config returns the profile access configuration.
Config() (conf *ProfileConfig)
- // IsBlocked returns true if the req should be blocked. req must not be
- // nil, and req.Question must have one item.
- IsBlocked(
- ctx context.Context,
- req *dns.Msg,
- rAddr netip.AddrPort,
- l *geoip.Location,
- ) (blocked bool)
+ Blocker
}
-// EmptyProfile is an empty profile implementation that does nothing.
-type EmptyProfile struct{}
+// EmptyProfile is an empty [Profile] implementation that does nothing.
+type EmptyProfile struct {
+ EmptyBlocker
+}
// type check
var _ Profile = EmptyProfile{}
@@ -34,17 +31,6 @@ var _ Profile = EmptyProfile{}
// returns nil.
func (EmptyProfile) Config() (conf *ProfileConfig) { return nil }
-// IsBlocked implements the [Profile] interface for EmptyProfile. It always
-// returns false.
-func (EmptyProfile) IsBlocked(
- _ context.Context,
- _ *dns.Msg,
- _ netip.AddrPort,
- _ *geoip.Location,
-) (blocked bool) {
- return false
-}
-
// ProfileConfig is a profile specific access configuration.
//
// NOTE: Do not change fields of this structure without incrementing
@@ -64,14 +50,23 @@ type ProfileConfig struct {
// BlocklistDomainRules is slice of rules to match requests.
BlocklistDomainRules []string
+
+ // StandardEnabled controls whether the profile should also apply standard
+ // access settings.
+ StandardEnabled bool
}
// DefaultProfile controls profile specific IP and client blocking that take
// place before all other processing. DefaultProfile is safe for concurrent
// use.
type DefaultProfile struct {
+ standard Blocker
+
blockedHostsEng *blockedHostEngine
+ reqPool *syncutil.Pool[urlfilter.DNSRequest]
+ resPool *syncutil.Pool[urlfilter.DNSResult]
+
allowedNets []netip.Prefix
blockedNets []netip.Prefix
@@ -80,6 +75,8 @@ type DefaultProfile struct {
blockedASN []geoip.ASN
blocklistDomainRules []string
+
+ standardEnabled bool
}
// defaultProfileConfig is the configuration for the default access for
@@ -89,21 +86,42 @@ type defaultProfileConfig struct {
// nil and must be valid.
conf *ProfileConfig
+ // reqPool is the pool of URLFilter request data to use and reuse during
+ // filtering. It must not be nil.
+ reqPool *syncutil.Pool[urlfilter.DNSRequest]
+
+ // resPool is the pool of URLFilter result data to use and reuse during
+ // filtering. It must not be nil.
+ resPool *syncutil.Pool[urlfilter.DNSResult]
+
// metrics is used for the collection of the profile access engine
// statistics. It must not be nil.
metrics ProfileMetrics
+
+ // standard is the standard access blocker to use.
+ standard Blocker
}
// newDefaultProfile creates a new *DefaultProfile. conf is assumed to be
// valid. mtrc must not be nil.
func newDefaultProfile(c *defaultProfileConfig) (p *DefaultProfile) {
return &DefaultProfile{
- allowedNets: c.conf.AllowedNets,
- blockedNets: c.conf.BlockedNets,
- allowedASN: c.conf.AllowedASN,
- blockedASN: c.conf.BlockedASN,
+ standard: c.standard,
+
+ blockedHostsEng: newBlockedHostEngine(c.metrics, c.conf.BlocklistDomainRules),
+
+ reqPool: c.reqPool,
+ resPool: c.resPool,
+
+ allowedNets: c.conf.AllowedNets,
+ blockedNets: c.conf.BlockedNets,
+
+ allowedASN: c.conf.AllowedASN,
+ blockedASN: c.conf.BlockedASN,
+
blocklistDomainRules: c.conf.BlocklistDomainRules,
- blockedHostsEng: newBlockedHostEngine(c.metrics, c.conf.BlocklistDomainRules),
+
+ standardEnabled: c.conf.StandardEnabled,
}
}
@@ -118,10 +136,14 @@ func (p *DefaultProfile) Config() (conf *ProfileConfig) {
AllowedASN: slices.Clone(p.allowedASN),
BlockedASN: slices.Clone(p.blockedASN),
BlocklistDomainRules: slices.Clone(p.blocklistDomainRules),
+ StandardEnabled: p.standardEnabled,
}
}
-// IsBlocked implements the [Profile] interface for *DefaultProfile.
+// type check
+var _ Blocker = (*DefaultProfile)(nil)
+
+// IsBlocked implements the [Blocker] interface for *DefaultProfile.
func (p *DefaultProfile) IsBlocked(
ctx context.Context,
req *dns.Msg,
@@ -130,7 +152,9 @@ func (p *DefaultProfile) IsBlocked(
) (blocked bool) {
ip := rAddr.Addr()
- return p.isBlockedByNets(ip, l) || p.isBlockedByHostsEng(ctx, req)
+ return p.isBlockedByNets(ip, l) ||
+ p.isBlockedByHostsEng(ctx, req) ||
+ p.standard.IsBlocked(ctx, req, rAddr, l)
}
// isBlockedByNets returns true if ip or l is blocked by current profile.
@@ -163,28 +187,3 @@ func matchASNs(asns []geoip.ASN, l *geoip.Location) (ok bool) {
func (p *DefaultProfile) isBlockedByHostsEng(ctx context.Context, req *dns.Msg) (blocked bool) {
return p.blockedHostsEng.isBlocked(ctx, req)
}
-
-// ProfileConstructor creates default access managers for profiles.
-//
-// TODO(a.garipov): Add global standard rules for profile access managers here
-// as well.
-type ProfileConstructor struct {
- metrics ProfileMetrics
-}
-
-// NewProfileConstructor returns a properly initialized *ProfileConstructor.
-// mtrc must not be nil.
-func NewProfileConstructor(mtrc ProfileMetrics) (c *ProfileConstructor) {
- return &ProfileConstructor{
- metrics: mtrc,
- }
-}
-
-// New creates a new access manager for a profile based on the configuration.
-// conf must not be nil and must be valid.
-func (c *ProfileConstructor) New(conf *ProfileConfig) (p *DefaultProfile) {
- return newDefaultProfile(&defaultProfileConfig{
- conf: conf,
- metrics: c.metrics,
- })
-}
diff --git a/internal/access/profile_test.go b/internal/access/profile_test.go
index 831bd7a..f692509 100644
--- a/internal/access/profile_test.go
+++ b/internal/access/profile_test.go
@@ -13,30 +13,49 @@ import (
)
func TestDefaultProfile_Config(t *testing.T) {
+ t.Parallel()
+
conf := &access.ProfileConfig{
- AllowedNets: []netip.Prefix{netip.MustParsePrefix("1.1.1.0/24")},
- BlockedNets: []netip.Prefix{netip.MustParsePrefix("2.2.2.0/24")},
+ AllowedNets: []netip.Prefix{netip.MustParsePrefix("192.0.2.1/32")},
+ BlockedNets: []netip.Prefix{netip.MustParsePrefix("192.0.2.2/32")},
AllowedASN: []geoip.ASN{1},
BlockedASN: []geoip.ASN{1, 2},
BlocklistDomainRules: []string{"block.test"},
+ StandardEnabled: true,
}
- cons := access.NewProfileConstructor(testAccessMtrc)
+ cons := access.NewProfileConstructor(&access.ProfileConstructorConfig{
+ Metrics: testAccessMtrc,
+ Standard: access.EmptyBlocker{},
+ })
+
a := cons.New(conf)
got := a.Config()
- assert.Equal(t, conf.AllowedNets, got.AllowedNets)
- assert.Equal(t, conf.BlockedNets, got.BlockedNets)
- assert.Equal(t, conf.AllowedASN, got.AllowedASN)
- assert.Equal(t, conf.BlockedASN, got.BlockedASN)
- assert.Equal(t, conf.BlocklistDomainRules, got.BlocklistDomainRules)
+ assert.Equal(t, conf, got)
}
func TestDefaultProfile_IsBlocked(t *testing.T) {
- passAddrPort := netip.MustParseAddrPort("3.3.3.3:3333")
+ t.Parallel()
+
+ passAddrPort := netip.MustParseAddrPort("192.0.2.3:3333")
+
+ std := access.NewStandardBlocker(&access.StandardBlockerConfig{
+ AllowedNets: []netip.Prefix{netip.MustParsePrefix("192.0.2.10/32")},
+ BlockedNets: []netip.Prefix{netip.MustParsePrefix("192.0.2.20/32")},
+ AllowedASN: []geoip.ASN{10},
+ BlockedASN: []geoip.ASN{10, 20},
+ BlocklistDomainRules: []string{
+ "block.std.test",
+ "UPPERCASE.STD.test",
+ "||block_aaaa.std.test^$dnstype=AAAA",
+ "||allowlist.std.test^",
+ "@@||allow.allowlist.std.test^",
+ },
+ })
conf := &access.ProfileConfig{
- AllowedNets: []netip.Prefix{netip.MustParsePrefix("1.1.1.1/32")},
- BlockedNets: []netip.Prefix{netip.MustParsePrefix("1.1.1.0/24")},
+ AllowedNets: []netip.Prefix{netip.MustParsePrefix("192.0.2.1/32")},
+ BlockedNets: []netip.Prefix{netip.MustParsePrefix("192.0.2.2/32")},
AllowedASN: []geoip.ASN{1},
BlockedASN: []geoip.ASN{1, 2},
BlocklistDomainRules: []string{
@@ -46,9 +65,13 @@ func TestDefaultProfile_IsBlocked(t *testing.T) {
"||allowlist.test^",
"@@||allow.allowlist.test^",
},
+ StandardEnabled: true,
}
- cons := access.NewProfileConstructor(testAccessMtrc)
+ cons := access.NewProfileConstructor(&access.ProfileConstructorConfig{
+ Metrics: testAccessMtrc,
+ Standard: std,
+ })
a := cons.New(conf)
testCases := []struct {
@@ -117,21 +140,21 @@ func TestDefaultProfile_IsBlocked(t *testing.T) {
}, {
want: assert.False,
name: "pass_ip",
- rAddr: netip.MustParseAddrPort("1.1.1.1:57"),
+ rAddr: netip.MustParseAddrPort("192.0.2.1:57"),
host: "pass.test",
qt: dns.TypeA,
loc: nil,
}, {
want: assert.True,
name: "block_subnet",
- rAddr: netip.MustParseAddrPort("1.1.1.2:57"),
+ rAddr: netip.MustParseAddrPort("192.0.2.2:57"),
host: "pass.test",
qt: dns.TypeA,
loc: nil,
}, {
want: assert.False,
name: "pass_subnet",
- rAddr: netip.MustParseAddrPort("1.2.2.2:57"),
+ rAddr: netip.MustParseAddrPort("192.0.2.1:57"),
host: "pass.test",
qt: dns.TypeA,
loc: nil,
@@ -156,10 +179,103 @@ func TestDefaultProfile_IsBlocked(t *testing.T) {
host: "pass.test",
qt: dns.TypeA,
loc: &geoip.Location{ASN: 2},
+ }, {
+ want: assert.True,
+ name: "standard_blocked_domain_A",
+ host: "block.std.test",
+ qt: dns.TypeA,
+ rAddr: passAddrPort,
+ loc: nil,
+ }, {
+ want: assert.True,
+ name: "standard_blocked_domain_HTTPS",
+ host: "block.std.test",
+ qt: dns.TypeHTTPS,
+ rAddr: passAddrPort,
+ loc: nil,
+ }, {
+ want: assert.True,
+ name: "standard_uppercase_domain",
+ host: "uppercase.std.test",
+ qt: dns.TypeHTTPS,
+ rAddr: passAddrPort,
+ loc: nil,
+ }, {
+ want: assert.False,
+ name: "standard_pass_qt",
+ host: "block_aaaa.std.test",
+ qt: dns.TypeA,
+ rAddr: passAddrPort,
+ loc: nil,
+ }, {
+ want: assert.True,
+ name: "standard_block_qt",
+ host: "block_aaaa.std.test",
+ qt: dns.TypeAAAA,
+ rAddr: passAddrPort,
+ loc: nil,
+ }, {
+ want: assert.True,
+ name: "standard_allowlist_block",
+ host: "block.allowlist.std.test",
+ qt: dns.TypeA,
+ rAddr: passAddrPort,
+ loc: nil,
+ }, {
+ want: assert.False,
+ name: "standard_allowlist_test",
+ host: "allow.allowlist.std.test",
+ qt: dns.TypeA,
+ rAddr: passAddrPort,
+ loc: nil,
+ }, {
+ want: assert.False,
+ name: "standard_pass_ip",
+ rAddr: netip.MustParseAddrPort("192.0.2.21:57"),
+ host: "pass.std.test",
+ qt: dns.TypeA,
+ loc: nil,
+ }, {
+ want: assert.True,
+ name: "standard_block_subnet",
+ rAddr: netip.MustParseAddrPort("192.0.2.20:57"),
+ host: "pass.std.test",
+ qt: dns.TypeA,
+ loc: nil,
+ }, {
+ want: assert.False,
+ name: "standard_pass_subnet",
+ rAddr: netip.MustParseAddrPort("192.0.2.11:57"),
+ host: "pass.std.test",
+ qt: dns.TypeA,
+ loc: nil,
+ }, {
+ want: assert.True,
+ name: "standard_block_host_pass_asn",
+ rAddr: passAddrPort,
+ host: "block.std.test",
+ qt: dns.TypeA,
+ loc: &geoip.Location{ASN: 10},
+ }, {
+ want: assert.False,
+ name: "standard_pass_asn",
+ rAddr: passAddrPort,
+ host: "pass.std.test",
+ qt: dns.TypeA,
+ loc: &geoip.Location{ASN: 10},
+ }, {
+ want: assert.True,
+ name: "standard_block_asn",
+ rAddr: passAddrPort,
+ host: "pass.std.test",
+ qt: dns.TypeA,
+ loc: &geoip.Location{ASN: 20},
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
req := dnsservertest.NewReq(tc.host, tc.qt, dns.ClassINET)
ctx := testutil.ContextWithTimeout(t, testTimeout)
@@ -170,6 +286,8 @@ func TestDefaultProfile_IsBlocked(t *testing.T) {
}
func TestDefaultProfile_IsBlocked_prefixAllowlist(t *testing.T) {
+ t.Parallel()
+
conf := &access.ProfileConfig{
AllowedNets: []netip.Prefix{
netip.MustParsePrefix("2.2.2.0/24"),
@@ -181,7 +299,10 @@ func TestDefaultProfile_IsBlocked_prefixAllowlist(t *testing.T) {
BlocklistDomainRules: nil,
}
- cons := access.NewProfileConstructor(testAccessMtrc)
+ cons := access.NewProfileConstructor(&access.ProfileConstructorConfig{
+ Metrics: testAccessMtrc,
+ Standard: access.EmptyBlocker{},
+ })
a := cons.New(conf)
testCases := []struct {
@@ -212,6 +333,8 @@ func TestDefaultProfile_IsBlocked_prefixAllowlist(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
req := dnsservertest.NewReq("pass.test", dns.TypeA, dns.ClassINET)
ctx := testutil.ContextWithTimeout(t, testTimeout)
@@ -238,7 +361,10 @@ func BenchmarkDefaultProfile_IsBlocked(b *testing.B) {
},
}
- cons := access.NewProfileConstructor(testAccessMtrc)
+ cons := access.NewProfileConstructor(&access.ProfileConstructorConfig{
+ Metrics: testAccessMtrc,
+ Standard: access.EmptyBlocker{},
+ })
a := cons.New(conf)
ctx := testutil.ContextWithTimeout(b, testTimeout)
@@ -271,10 +397,10 @@ func BenchmarkDefaultProfile_IsBlocked(b *testing.B) {
// Most recent results:
//
- // goos: darwin
- // goarch: amd64
- // pkg: github.com/AdguardTeam/AdGuardDNS/internal/access
- // cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
- // BenchmarkDefaultProfile_IsBlocked/pass-12 2761741 421.9 ns/op 96 B/op 2 allocs/op
- // BenchmarkDefaultProfile_IsBlocked/block-12 2143516 556.1 ns/op 128 B/op 4 allocs/op
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/access
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkDefaultProfile_IsBlocked/pass-16 2679700 468.8 ns/op 16 B/op 1 allocs/op
+ // BenchmarkDefaultProfile_IsBlocked/block-16 2081113 576.4 ns/op 24 B/op 1 allocs/op
}
diff --git a/internal/access/profileconstructor.go b/internal/access/profileconstructor.go
new file mode 100644
index 0000000..240abd8
--- /dev/null
+++ b/internal/access/profileconstructor.go
@@ -0,0 +1,57 @@
+package access
+
+import (
+ "github.com/AdguardTeam/golibs/syncutil"
+ "github.com/AdguardTeam/urlfilter"
+)
+
+// ProfileConstructorConfig is the configuration for the [ProfileConstructor].
+type ProfileConstructorConfig struct {
+ // Metrics is used for the collection of the statistics of profile access
+ // managers. It must not be nil.
+ Metrics ProfileMetrics
+
+ // Standard is the standard blocker for all profiles which have enabled this
+ // feature. It must not be nil.
+ Standard Blocker
+}
+
+// ProfileConstructor creates default access managers for profiles.
+type ProfileConstructor struct {
+ reqPool *syncutil.Pool[urlfilter.DNSRequest]
+ resPool *syncutil.Pool[urlfilter.DNSResult]
+ metrics ProfileMetrics
+ standard Blocker
+}
+
+// NewProfileConstructor returns a properly initialized *ProfileConstructor.
+// conf must not be nil.
+func NewProfileConstructor(conf *ProfileConstructorConfig) (c *ProfileConstructor) {
+ return &ProfileConstructor{
+ reqPool: syncutil.NewPool(func() (req *urlfilter.DNSRequest) {
+ return &urlfilter.DNSRequest{}
+ }),
+ resPool: syncutil.NewPool(func() (v *urlfilter.DNSResult) {
+ return &urlfilter.DNSResult{}
+ }),
+ metrics: conf.Metrics,
+ standard: conf.Standard,
+ }
+}
+
+// New creates a new access manager for a profile based on the configuration.
+// conf must not be nil and must be valid.
+func (c *ProfileConstructor) New(conf *ProfileConfig) (p *DefaultProfile) {
+ var standard Blocker = EmptyBlocker{}
+ if conf.StandardEnabled {
+ standard = c.standard
+ }
+
+ return newDefaultProfile(&defaultProfileConfig{
+ conf: conf,
+ reqPool: c.reqPool,
+ resPool: c.resPool,
+ metrics: c.metrics,
+ standard: standard,
+ })
+}
diff --git a/internal/access/standardaccess.go b/internal/access/standardaccess.go
new file mode 100644
index 0000000..bcad9b2
--- /dev/null
+++ b/internal/access/standardaccess.go
@@ -0,0 +1,183 @@
+package access
+
+import (
+ "context"
+ "net/netip"
+ "slices"
+ "sync"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdurlflt"
+ "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/syncutil"
+ "github.com/AdguardTeam/urlfilter"
+ "github.com/AdguardTeam/urlfilter/filterlist"
+ "github.com/miekg/dns"
+)
+
+// StandardSetter is the interface for setting the standard access blocker
+// configuration.
+type StandardSetter interface {
+ // SetConfig sets the configuration for the standard access blocker. conf
+ // must not be nil. Fields of conf must not be modified after calling this
+ // method. It must be safe for concurrent use.
+ SetConfig(conf *StandardBlockerConfig)
+}
+
+// EmptyStandard is an empty [StandardSetter] implementation that does nothing.
+type EmptyStandard struct{}
+
+// type check
+var _ StandardSetter = EmptyStandard{}
+
+// SetConfig implements the [StandardSetter] interface for EmptyStandard. It
+// always returns false.
+func (EmptyStandard) SetConfig(_ *StandardBlockerConfig) {}
+
+// StandardBlockerConfig is the configuration structure for the standard access
+// blocker.
+type StandardBlockerConfig struct {
+ // AllowedNets are the networks allowed for DNS resolution. If empty or
+ // nil, all networks are allowed, except those blocked by BlockedNets.
+ AllowedNets []netip.Prefix
+
+ // BlockedNets are the networks blocked for DNS resolution. If empty or
+ // nil, all networks are allowed, except those allowed by AllowedNets.
+ BlockedNets []netip.Prefix
+
+ // AllowedASN are the ASNs allowed for DNS resolution. If empty or nil, all
+ // ASNs are allowed, except those blocked by BlockedASN.
+ AllowedASN []geoip.ASN
+
+ // BlockedASN are the ASNs blocked for DNS resolution. If empty or nil, all
+ // ASNs are allowed, except those allowed by AllowedASN.
+ BlockedASN []geoip.ASN
+
+ // BlocklistDomainRules are the rules blocking the domains. If empty or
+ // nil, no domains are blocked.
+ BlocklistDomainRules []string
+}
+
+// StandardBlocker is the dynamic [Blocker] implementation with standard
+// access settings.
+type StandardBlocker struct {
+ reqPool *syncutil.Pool[urlfilter.DNSRequest]
+ resPool *syncutil.Pool[urlfilter.DNSResult]
+
+ // mu protects all fields below.
+ mu *sync.RWMutex
+
+ blockedHostsEng *urlfilter.DNSEngine
+
+ allowedNets []netip.Prefix
+ blockedNets []netip.Prefix
+
+ // TODO(d.kolyshev): Change to map[geoip.ASN]unit to improve performance.
+ allowedASN []geoip.ASN
+ blockedASN []geoip.ASN
+}
+
+// NewStandardBlocker creates a new StandardBlocker instance. conf must not be
+// nil.
+func NewStandardBlocker(conf *StandardBlockerConfig) (s *StandardBlocker) {
+ s = &StandardBlocker{
+ reqPool: syncutil.NewPool(func() (req *urlfilter.DNSRequest) {
+ return &urlfilter.DNSRequest{}
+ }),
+ resPool: syncutil.NewPool(func() (v *urlfilter.DNSResult) {
+ return &urlfilter.DNSResult{}
+ }),
+
+ mu: &sync.RWMutex{},
+ }
+
+ s.SetConfig(conf)
+
+ return s
+}
+
+// type check
+var _ StandardSetter = (*StandardBlocker)(nil)
+
+// SetConfig implements the [StandardSetter] interface for *StandardBlocker.
+func (b *StandardBlocker) SetConfig(c *StandardBlockerConfig) {
+ lists := []filterlist.Interface{
+ filterlist.NewBytes(&filterlist.BytesConfig{
+ ID: blocklistFilterID,
+ RulesText: agdurlflt.RulesToBytesLower(c.BlocklistDomainRules),
+ IgnoreCosmetic: true,
+ }),
+ }
+
+ // Should never panic, since the storage has only one list.
+ rulesStrg := errors.Must(filterlist.NewRuleStorage(lists))
+ eng := urlfilter.NewDNSEngine(rulesStrg)
+
+ b.mu.Lock()
+ defer b.mu.Unlock()
+
+ b.blockedHostsEng = eng
+ b.allowedNets = c.AllowedNets
+ b.blockedNets = c.BlockedNets
+ b.allowedASN = c.AllowedASN
+ b.blockedASN = c.BlockedASN
+}
+
+// type check
+var _ Blocker = (*StandardBlocker)(nil)
+
+// IsBlocked implements the [Blocker] interface for *StandardBlocker.
+func (b *StandardBlocker) IsBlocked(
+ _ context.Context,
+ req *dns.Msg,
+ rAddr netip.AddrPort,
+ l *geoip.Location,
+) (blocked bool) {
+ b.mu.RLock()
+ defer b.mu.RUnlock()
+
+ ip := rAddr.Addr()
+
+ return b.isBlockedByNets(ip, l) || b.isBlockedByHostsEng(req)
+}
+
+// isBlockedByNets returns true if ip or l is blocked by current configuration.
+func (b *StandardBlocker) isBlockedByNets(ip netip.Addr, l *geoip.Location) (blocked bool) {
+ if matchASNs(b.allowedASN, l) || matchNets(b.allowedNets, ip) {
+ return false
+ }
+
+ return matchASNs(b.blockedASN, l) || matchNets(b.blockedNets, ip)
+}
+
+// isBlockedByHostsEng returns true if the req is blocked by blocklist domain
+// rules. req must have exactly one question.
+func (b *StandardBlocker) isBlockedByHostsEng(req *dns.Msg) (blocked bool) {
+ q := req.Question[0]
+
+ host := agdnet.NormalizeQueryDomain(q.Name)
+
+ return matchBlocked(host, q.Qtype, b.blockedHostsEng, b.reqPool, b.resPool)
+}
+
+// Equal returns true if c and other are equal. nil is only equal to other nil.
+func (c *StandardBlockerConfig) Equal(other *StandardBlockerConfig) (ok bool) {
+ if c == nil {
+ return other == nil
+ } else if other == nil {
+ return false
+ }
+
+ switch {
+ case
+ !slices.Equal(c.AllowedNets, other.AllowedNets),
+ !slices.Equal(c.BlockedNets, other.BlockedNets),
+ !slices.Equal(c.AllowedASN, other.AllowedASN),
+ !slices.Equal(c.BlockedASN, other.BlockedASN),
+ !slices.Equal(c.BlocklistDomainRules, other.BlocklistDomainRules):
+ return false
+ default:
+ return true
+ }
+}
diff --git a/internal/access/standardaccess_test.go b/internal/access/standardaccess_test.go
new file mode 100644
index 0000000..9e6df63
--- /dev/null
+++ b/internal/access/standardaccess_test.go
@@ -0,0 +1,58 @@
+package access_test
+
+import (
+ "net/netip"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/access"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/miekg/dns"
+ "github.com/stretchr/testify/assert"
+)
+
+func BenchmarkStandardBlocker_IsBlocked(b *testing.B) {
+ blocker := access.NewStandardBlocker(&access.StandardBlockerConfig{
+ BlocklistDomainRules: []string{
+ "block.test",
+ },
+ })
+
+ ctx := testutil.ContextWithTimeout(b, testTimeout)
+ remoteAddr := netip.AddrPort{}
+
+ b.Run("pass", func(b *testing.B) {
+ req := dnsservertest.NewReq("pass.test", dns.TypeA, dns.ClassINET)
+
+ var blocked bool
+
+ b.ReportAllocs()
+ for b.Loop() {
+ blocked = blocker.IsBlocked(ctx, req, remoteAddr, nil)
+ }
+
+ assert.False(b, blocked)
+ })
+
+ b.Run("block", func(b *testing.B) {
+ req := dnsservertest.NewReq("block.test", dns.TypeA, dns.ClassINET)
+
+ var blocked bool
+
+ b.ReportAllocs()
+ for b.Loop() {
+ blocked = blocker.IsBlocked(ctx, req, remoteAddr, nil)
+ }
+
+ assert.True(b, blocked)
+ })
+
+ // Most recent results:
+ //
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/access
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkStandardBlocker_IsBlocked/pass-16 3009312 378.2 ns/op 16 B/op 1 allocs/op
+ // BenchmarkStandardBlocker_IsBlocked/block-16 2518006 421.9 ns/op 24 B/op 1 allocs/op
+}
diff --git a/internal/agdcache/agdcache_test.go b/internal/agdcache/agdcache_test.go
new file mode 100644
index 0000000..0b093ba
--- /dev/null
+++ b/internal/agdcache/agdcache_test.go
@@ -0,0 +1,13 @@
+package agdcache_test
+
+import "time"
+
+// Constants used in tests.
+const (
+ key = "key"
+ val = 123
+
+ nonExistingKey = "nonExistingKey"
+
+ expDuration = 100 * time.Millisecond
+)
diff --git a/internal/agdcache/default.go b/internal/agdcache/default.go
new file mode 100644
index 0000000..122ea28
--- /dev/null
+++ b/internal/agdcache/default.go
@@ -0,0 +1,126 @@
+package agdcache
+
+import (
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/AdguardTeam/golibs/timeutil"
+ "github.com/viktordanov/golang-lru/simplelru"
+)
+
+// Config is a configuration structure of a cache.
+type Config struct {
+ // Clock is used to get current time for expiration. It must not be nil.
+ Clock timeutil.Clock
+
+ // Count is the maximum number of elements to keep in the cache. It must be
+ // positive.
+ //
+ // TODO(a.garipov): Make uint64.
+ Count int
+}
+
+// entry is an entry of the cache with expiration.
+type entry[T any] struct {
+ // val is the value of the entry.
+ val T
+
+ // expiration is the expiration unix time in nanoseconds. Zero means no
+ // expiration. It's an int64 in optimization purposes.
+ expiration int64
+}
+
+// Default is an implementation of a thread safe, fixed size LRU cache with
+// expiration.
+type Default[K comparable, T any] struct {
+ // cacheMu protects cache.
+ cacheMu *sync.RWMutex
+
+ cache *simplelru.LRU[K, entry[T]]
+ clock timeutil.Clock
+}
+
+// New returns a new initialized *Default cache and error, if any.
+func New[K comparable, T any](conf *Config) (c *Default[K, T], err error) {
+ lru, err := simplelru.NewLRU[K, entry[T]](conf.Count, nil)
+ if err != nil {
+ return nil, fmt.Errorf("agdcache: creating lru: %w", err)
+ }
+
+ return &Default[K, T]{
+ cache: lru,
+ clock: conf.Clock,
+ cacheMu: &sync.RWMutex{},
+ }, nil
+}
+
+// type check
+var _ Interface[any, any] = (*Default[any, any])(nil)
+
+// Set implements the [Interface] interface for *Default.
+func (c *Default[K, T]) Set(key K, val T) {
+ c.cacheMu.Lock()
+ defer c.cacheMu.Unlock()
+
+ // Not a pointer, but the value is used in optimization purposes.
+ e := entry[T]{
+ val: val,
+ }
+
+ c.cache.Add(key, e)
+}
+
+// SetWithExpire implements the [Interface] interface for *Default.
+func (c *Default[K, T]) SetWithExpire(key K, val T, duration time.Duration) {
+ c.cacheMu.Lock()
+ defer c.cacheMu.Unlock()
+
+ e := entry[T]{
+ val: val,
+ expiration: c.clock.Now().Add(duration).UnixNano(),
+ }
+
+ c.cache.Add(key, e)
+}
+
+// Get implements the [Interface] interface for *Default. It returns the value
+// and whether the key was found. Removes the key from the cache if it has
+// expired.
+func (c *Default[K, T]) Get(key K) (val T, ok bool) {
+ // TODO(a.garipov): Optimize, use RLock.
+ c.cacheMu.Lock()
+ defer c.cacheMu.Unlock()
+
+ e, ok := c.cache.Get(key)
+ if !ok {
+ return val, false
+ }
+
+ if e.expiration > 0 && c.clock.Now().UnixNano() > e.expiration {
+ c.cache.Remove(key)
+
+ return val, false
+ }
+
+ return e.val, true
+}
+
+// type check
+var _ Clearer = (*Default[any, any])(nil)
+
+// Clear implements the [Interface] interface for *Default.
+func (c *Default[K, T]) Clear() {
+ c.cacheMu.Lock()
+ defer c.cacheMu.Unlock()
+
+ c.cache.Purge()
+}
+
+// Len implements the [Interface] interface for *Default.
+func (c *Default[K, T]) Len() (n int) {
+ c.cacheMu.RLock()
+ defer c.cacheMu.RUnlock()
+
+ return c.cache.Len()
+}
diff --git a/internal/agdcache/default_test.go b/internal/agdcache/default_test.go
new file mode 100644
index 0000000..bfbcae6
--- /dev/null
+++ b/internal/agdcache/default_test.go
@@ -0,0 +1,182 @@
+package agdcache_test
+
+import (
+ "testing"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
+ "github.com/AdguardTeam/golibs/testutil/faketime"
+ "github.com/AdguardTeam/golibs/timeutil"
+ "github.com/bluele/gcache"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestDefault(t *testing.T) {
+ var (
+ testTimeNow = time.Now()
+ nowLater = testTimeNow.Add(2 * expDuration)
+ )
+
+ clock := &faketime.Clock{
+ OnNow: func() (now time.Time) { return testTimeNow },
+ }
+
+ cache, err := agdcache.New[string, int](&agdcache.Config{
+ Clock: clock,
+ Count: 10,
+ })
+ require.NoError(t, err)
+
+ cache.Set(key, val)
+ assert.Equal(t, 1, cache.Len())
+
+ v, ok := cache.Get(key)
+ assert.Equal(t, val, v)
+ assert.True(t, ok)
+
+ v, ok = cache.Get(nonExistingKey)
+ assert.Equal(t, 0, v)
+ assert.False(t, ok)
+
+ cache.Clear()
+ assert.Equal(t, 0, cache.Len())
+
+ cache.SetWithExpire(key, val, expDuration)
+ assert.Equal(t, 1, cache.Len())
+
+ v, ok = cache.Get(key)
+ assert.Equal(t, val, v)
+ assert.True(t, ok)
+
+ clock.OnNow = func() (now time.Time) { return nowLater }
+
+ v, ok = cache.Get(key)
+ assert.Equal(t, 0, v)
+ assert.False(t, ok)
+
+ assert.Equal(t, 0, cache.Len())
+}
+
+func BenchmarkDefault(b *testing.B) {
+ var ok bool
+
+ b.Run("set", func(b *testing.B) {
+ cache := newDefault(b)
+
+ b.ReportAllocs()
+ for i := 0; b.Loop(); i++ {
+ cache.Set(i, i)
+ _, ok = cache.Get(i)
+ }
+
+ assert.True(b, ok)
+ })
+
+ b.Run("set_expire", func(b *testing.B) {
+ cache := newDefault(b)
+
+ b.ReportAllocs()
+ for i := 0; b.Loop(); i++ {
+ cache.SetWithExpire(i, i, 2000)
+ _, ok = cache.Get(i)
+ }
+
+ assert.True(b, ok)
+ })
+
+ // Most recent results:
+ //
+ // goos: darwin
+ // goarch: arm64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/agdcache
+ // cpu: Apple M1 Pro
+ // BenchmarkDefault/set-8 7764472 138.6 ns/op 56 B/op 2 allocs/op
+ // BenchmarkDefault/set_expire-8 4727664 246.5 ns/op 56 B/op 2 allocs/op
+}
+
+func FuzzDefault(f *testing.F) {
+ const (
+ size = 1_000
+ secondsSeed = uint(1)
+ )
+
+ f.Add("key", 1, secondsSeed, 1)
+ f.Add("key", 1, secondsSeed, 2)
+ f.Add("key", 1, secondsSeed, 3)
+
+ now := time.Now()
+
+ f.Fuzz(func(t *testing.T, key string, val int, seconds uint, op int) {
+ clock := &faketime.Clock{
+ OnNow: func() (n time.Time) {
+ return now
+ },
+ }
+
+ cache, err := agdcache.New[string, int](&agdcache.Config{
+ Clock: clock,
+ Count: size,
+ })
+ require.NoError(t, err)
+
+ gCache := gcache.New(size).LRU().Clock(clock).Build()
+
+ switch {
+ case op%2 == 0:
+ cache.Set(key, val)
+ err = gCache.Set(key, val)
+ require.NoError(t, err)
+ case op%3 == 0:
+ dur := time.Duration(seconds) * time.Second
+
+ cache.SetWithExpire(key, val, dur)
+ err = gCache.SetWithExpire(key, val, dur)
+ require.NoError(t, err)
+ case op%5 == 0:
+ cache.Clear()
+ gCache.Purge()
+ }
+
+ clock.OnNow = func() (n time.Time) {
+ return now.Add(1 * time.Second)
+ }
+
+ got, ok := cache.Get(key)
+ gGot, err := gCache.Get(key)
+ gVal, gValOk := gGot.(int)
+ if !gValOk {
+ gVal = 0
+ }
+
+ require.Equalf(
+ t,
+ err == nil,
+ ok,
+ "key %q, val %d, dur %d, op %d: incorrect ok",
+ key, val, seconds, op,
+ )
+ require.Equalf(
+ t,
+ gVal,
+ got,
+ "key %q, val %d, dur %d, op %d: incorrect val",
+ key, val, seconds, op,
+ )
+
+ l := cache.Len()
+ goL := gCache.Len(false)
+ require.Equal(t, l, goL)
+ })
+}
+
+// newDefault returns a new cache for testing.
+func newDefault(tb testing.TB) (cache *agdcache.Default[int, int]) {
+ cache, err := agdcache.New[int, int](&agdcache.Config{
+ Clock: timeutil.SystemClock{},
+ Count: 10_000,
+ })
+ require.NoError(tb, err)
+
+ return cache
+}
diff --git a/internal/agdcache/lru_test.go b/internal/agdcache/lru_test.go
index bdd9a90..b2b91f3 100644
--- a/internal/agdcache/lru_test.go
+++ b/internal/agdcache/lru_test.go
@@ -8,13 +8,6 @@ import (
)
func TestLRU(t *testing.T) {
- const (
- key = "key"
- val = 123
-
- nonExistingKey = "nonExistingKey"
- )
-
cache := agdcache.NewLRU[string, int](&agdcache.LRUConfig{
Count: 10,
})
@@ -35,3 +28,71 @@ func TestLRU(t *testing.T) {
assert.Equal(t, 0, cache.Len())
}
+
+func BenchmarkLRU(b *testing.B) {
+ cache := agdcache.NewLRU[int, int](&agdcache.LRUConfig{
+ Count: 10_000,
+ })
+
+ var ok bool
+
+ b.ReportAllocs()
+ for i := 0; b.Loop(); i++ {
+ cache.Set(i, i)
+ _, ok = cache.Get(i)
+ }
+
+ assert.True(b, ok)
+
+ // Most recent results:
+ //
+ // goos: darwin
+ // goarch: arm64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/agdcache
+ // cpu: Apple M1 Pro
+ // BenchmarkLRU-8 5104281 207.2 ns/op 136 B/op 5 allocs/op
+}
+
+func BenchmarkLRU_expire(b *testing.B) {
+ cache := agdcache.NewLRU[int, int](&agdcache.LRUConfig{
+ Count: 10_000,
+ })
+
+ var ok bool
+
+ b.Run("default_expire", func(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; b.Loop(); i++ {
+ cache.Set(i, i)
+ _, ok = cache.Get(i)
+ }
+
+ assert.True(b, ok)
+
+ // Most recent results:
+ //
+ // goos: darwin
+ // goarch: arm64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/agdcache
+ // cpu: Apple M1 Pro
+ // BenchmarkLRU_expire/default_expire-8 4883622 208.6 ns/op 136 B/op 5 allocs/op
+ })
+
+ b.Run("set_expire", func(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; b.Loop(); i++ {
+ cache.SetWithExpire(i, i, 2000)
+ _, ok = cache.Get(i)
+ }
+
+ assert.True(b, ok)
+
+ // Most recent results:
+ //
+ // goos: darwin
+ // goarch: arm64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/agdcache
+ // cpu: Apple M1 Pro
+ // BenchmarkLRU_expire/set_expire-8 3620727 328.7 ns/op 160 B/op 5 allocs/op
+ })
+}
diff --git a/internal/agdtest/interface.go b/internal/agdtest/interface.go
index 1220572..43d7bd6 100644
--- a/internal/agdtest/interface.go
+++ b/internal/agdtest/interface.go
@@ -2,7 +2,6 @@ package agdtest
import (
"context"
- "fmt"
"net"
"net/netip"
"time"
@@ -23,6 +22,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/remotekv"
"github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
"github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/prometheus/client_golang/prometheus"
)
@@ -191,8 +191,8 @@ func (c *ErrorCollector) Collect(ctx context.Context, err error) {
// NewErrorCollector returns a new *ErrorCollector all methods of which panic.
func NewErrorCollector() (c *ErrorCollector) {
return &ErrorCollector{
- OnCollect: func(_ context.Context, err error) {
- panic(fmt.Errorf("unexpected call to ErrorCollector.Collect(%v)", err))
+ OnCollect: func(ctx context.Context, err error) {
+ panic(testutil.UnexpectedCall(ctx, err))
},
}
}
@@ -291,13 +291,13 @@ func (g *GeoIP) SubnetByLocation(
func NewGeoIP() (c *GeoIP) {
return &GeoIP{
OnData: func(host string, ip netip.Addr) (l *geoip.Location, err error) {
- panic(fmt.Errorf("unexpected call to GeoIP.Data(%v, %v)", host, ip))
+ panic(testutil.UnexpectedCall(host, ip))
},
OnSubnetByLocation: func(
l *geoip.Location,
fam netutil.AddrFamily,
) (n netip.Prefix, err error) {
- panic(fmt.Errorf("unexpected call to GeoIP.SubnetByLocation(%v, %v)", l, fam))
+ panic(testutil.UnexpectedCall(l, fam))
},
}
}
@@ -390,50 +390,41 @@ func (db *ProfileDB) ProfileByLinkedIP(
func NewProfileDB() (db *ProfileDB) {
return &ProfileDB{
OnCreateAutoDevice: func(
- _ context.Context,
+ ctx context.Context,
id agd.ProfileID,
humanID agd.HumanID,
devType agd.DeviceType,
) (p *agd.Profile, d *agd.Device, err error) {
- panic(fmt.Errorf(
- "unexpected call to ProfileDB.CreateAutoDevice(%v, %v, %v)",
- id,
- humanID,
- devType,
- ))
+ panic(testutil.UnexpectedCall(ctx, id, humanID, devType))
},
OnProfileByDedicatedIP: func(
- _ context.Context,
+ ctx context.Context,
ip netip.Addr,
) (p *agd.Profile, d *agd.Device, err error) {
- panic(fmt.Errorf("unexpected call to ProfileDB.ProfileByDedicatedIP(%v)", ip))
+ panic(testutil.UnexpectedCall(ctx, ip))
},
OnProfileByDeviceID: func(
- _ context.Context,
+ ctx context.Context,
id agd.DeviceID,
) (p *agd.Profile, d *agd.Device, err error) {
- panic(fmt.Errorf("unexpected call to ProfileDB.ProfileByDeviceID(%v)", id))
+ panic(testutil.UnexpectedCall(ctx, id))
},
OnProfileByHumanID: func(
- _ context.Context,
+ ctx context.Context,
profID agd.ProfileID,
humanID agd.HumanIDLower,
) (p *agd.Profile, d *agd.Device, err error) {
- panic(fmt.Errorf(
- "unexpected call to ProfileDB.ProfileByHumanID(%v, %v)",
- profID,
- humanID,
- ))
+ panic(testutil.UnexpectedCall(ctx, profID, humanID))
},
OnProfileByLinkedIP: func(
- _ context.Context,
+ ctx context.Context,
ip netip.Addr,
) (p *agd.Profile, d *agd.Device, err error) {
- panic(fmt.Errorf("unexpected call to ProfileDB.ProfileByLinkedIP(%v)", ip))
+ panic(testutil.UnexpectedCall(ctx, ip))
},
}
}
@@ -475,16 +466,16 @@ func (s *ProfileStorage) Profiles(
func NewProfileStorage() (s *ProfileStorage) {
return &ProfileStorage{
OnCreateAutoDevice: func(
- _ context.Context,
+ ctx context.Context,
req *profiledb.StorageCreateAutoDeviceRequest,
) (resp *profiledb.StorageCreateAutoDeviceResponse, err error) {
- panic(fmt.Errorf("unexpected call to ProfileStorage.CreateAutoDevice(%v)", req))
+ panic(testutil.UnexpectedCall(ctx, req))
},
OnProfiles: func(
- _ context.Context,
+ ctx context.Context,
req *profiledb.StorageProfilesRequest,
) (resp *profiledb.StorageProfilesResponse, err error) {
- panic(fmt.Errorf("unexpected call to ProfileStorage.Profiles(%v)", req))
+ panic(testutil.UnexpectedCall(ctx, req))
},
}
}
@@ -587,14 +578,14 @@ func (l *RateLimit) CountResponses(ctx context.Context, req *dns.Msg, ip netip.A
func NewRateLimit() (c *RateLimit) {
return &RateLimit{
OnIsRateLimited: func(
- _ context.Context,
+ ctx context.Context,
req *dns.Msg,
addr netip.Addr,
) (shouldDrop, isAllowlisted bool, err error) {
- panic(fmt.Errorf("unexpected call to RateLimit.IsRateLimited(%v, %v)", req, addr))
+ panic(testutil.UnexpectedCall(ctx, req, addr))
},
- OnCountResponses: func(_ context.Context, resp *dns.Msg, addr netip.Addr) {
- panic(fmt.Errorf("unexpected call to RateLimit.CountResponses(%v, %v)", resp, addr))
+ OnCountResponses: func(ctx context.Context, resp *dns.Msg, addr netip.Addr) {
+ panic(testutil.UnexpectedCall(ctx, resp, addr))
},
}
}
diff --git a/internal/agdtest/profile.go b/internal/agdtest/profile.go
new file mode 100644
index 0000000..d62073f
--- /dev/null
+++ b/internal/agdtest/profile.go
@@ -0,0 +1,31 @@
+package agdtest
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/access"
+ gocmp "github.com/google/go-cmp/cmp"
+ "github.com/stretchr/testify/assert"
+)
+
+// AssertEqualProfile compares two values while ignoring internal details of
+// some fields of profiles, such as pools.
+func AssertEqualProfile(tb testing.TB, want, got any) (ok bool) {
+ tb.Helper()
+
+ exportAll := gocmp.Exporter(func(_ reflect.Type) (ok bool) { return true })
+
+ defAccCmp := gocmp.Comparer(func(want, got *access.DefaultProfile) (ok bool) {
+ return gocmp.Equal(want.Config(), got.Config(), exportAll)
+ })
+
+ diff := gocmp.Diff(want, got, defAccCmp, exportAll)
+ if diff == "" {
+ return true
+ }
+
+ // Use assert.Failf instead of tb.Errorf to get a more consistent error
+ // message.
+ return assert.Failf(tb, "not equal", "got: %+v\nwant: %+v\ndiff: %s", got, want, diff)
+}
diff --git a/internal/agdurlflt/agdurlflt.go b/internal/agdurlflt/agdurlflt.go
new file mode 100644
index 0000000..3c567eb
--- /dev/null
+++ b/internal/agdurlflt/agdurlflt.go
@@ -0,0 +1,68 @@
+// Package agdurlflt contains utilities for the urlfilter module.
+package agdurlflt
+
+import (
+ "bytes"
+ "unicode"
+)
+
+// RulesLen returns the length of the byte buffer necessary to write ruleStrs,
+// separated by a newline, to it.
+func RulesLen[S ~string](ruleStrs []S) (l int) {
+ if len(ruleStrs) == 0 {
+ return 0
+ }
+
+ for _, s := range ruleStrs {
+ l += len(s) + len("\n")
+ }
+
+ return l
+}
+
+// RulesToBytes writes ruleStrs to a byte slice and returns it.
+//
+// TODO(a.garipov): Consider moving to golibs or urlfilter.
+func RulesToBytes[S ~string](ruleStrs []S) (b []byte) {
+ l := RulesLen(ruleStrs)
+ if l == 0 {
+ return nil
+ }
+
+ buf := bytes.NewBuffer(make([]byte, 0, l))
+ for _, s := range ruleStrs {
+ _, _ = buf.WriteString(string(s))
+ _ = buf.WriteByte('\n')
+ }
+
+ return buf.Bytes()
+}
+
+// RulesToBytesLower writes lowercase versions of ruleStrs to a byte slice and
+// returns it.
+//
+// NOTE: Do not use this for rules that can include dnsrewrite modifiers, since
+// their DNS types are case-sensitive.
+//
+// TODO(a.garipov): Consider moving to golibs or urlfilter.
+func RulesToBytesLower(ruleStrs []string) (b []byte) {
+ l := RulesLen(ruleStrs)
+ if l == 0 {
+ return nil
+ }
+
+ buf := bytes.NewBuffer(make([]byte, 0, l))
+ for _, s := range ruleStrs {
+ for _, c := range s {
+ // NOTE: Theoretically there might be cases where a lowercase
+ // version of a rune takes up more space or less space than an
+ // uppercase one, but that doesn't matter since we're using a
+ // bytes.Buffer and rules generally are ASCII-only.
+ _, _ = buf.WriteRune(unicode.ToLower(c))
+ }
+
+ _ = buf.WriteByte('\n')
+ }
+
+ return buf.Bytes()
+}
diff --git a/internal/agdurlflt/agdurlflt_test.go b/internal/agdurlflt/agdurlflt_test.go
new file mode 100644
index 0000000..0ca02d6
--- /dev/null
+++ b/internal/agdurlflt/agdurlflt_test.go
@@ -0,0 +1,57 @@
+package agdurlflt_test
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdurlflt"
+ "github.com/stretchr/testify/require"
+)
+
+// testRulesStrs are the common filtering rules for tests.
+var testRulesStrs = []string{
+ `||blocked.example^`,
+ `@@||allowed.example^`,
+ `||dnsrewrite.example^$dnsrewrite=192.0.2.1`,
+}
+
+// testRulesData is the data of [testRulesStrs] as bytes.
+var testRulesData = []byte(strings.Join(testRulesStrs, "\n") + "\n")
+
+func BenchmarkRulesToBytes(b *testing.B) {
+ var got []byte
+
+ b.ReportAllocs()
+ for b.Loop() {
+ got = agdurlflt.RulesToBytes(testRulesStrs)
+ }
+
+ require.Equal(b, testRulesData, got)
+
+ // Most recent results:
+ //
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/agdurlflt
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkRulesToBytes-16 7925872 145.3 ns/op 96 B/op 1 allocs/op
+}
+
+func BenchmarkRulesToBytesLower(b *testing.B) {
+ var got []byte
+
+ b.ReportAllocs()
+ for b.Loop() {
+ got = agdurlflt.RulesToBytesLower(testRulesStrs)
+ }
+
+ require.Equal(b, testRulesData, got)
+
+ // Most recent results:
+ //
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/agdurlflt
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkRulesToBytesLower-16 1000000 1188 ns/op 96 B/op 1 allocs/op
+}
diff --git a/internal/backendpb/backendpb_internal_test.go b/internal/backendpb/backendpb_internal_test.go
index c77af5c..6a6c862 100644
--- a/internal/backendpb/backendpb_internal_test.go
+++ b/internal/backendpb/backendpb_internal_test.go
@@ -58,4 +58,7 @@ var TestLogger = slogutil.NewDiscardLogger()
// TestProfileAccessConstructor is the common constructor of profile access
// managers for tests
-var TestProfileAccessConstructor = access.NewProfileConstructor(access.EmptyProfileMetrics{})
+var TestProfileAccessConstructor = access.NewProfileConstructor(&access.ProfileConstructorConfig{
+ Metrics: access.EmptyProfileMetrics{},
+ Standard: access.EmptyBlocker{},
+})
diff --git a/internal/backendpb/billstat_test.go b/internal/backendpb/billstat_test.go
index 5ebefa0..d8f4681 100644
--- a/internal/backendpb/billstat_test.go
+++ b/internal/backendpb/billstat_test.go
@@ -47,14 +47,14 @@ func TestBillStat_Upload(t *testing.T) {
ctx context.Context,
req *backendpb.CreateDeviceRequest,
) (resp *backendpb.CreateDeviceResponse, err error) {
- panic("not implemented")
+ panic(testutil.UnexpectedCall(ctx, req))
},
OnGetDNSProfiles: func(
req *backendpb.DNSProfilesRequest,
srv grpc.ServerStreamingServer[backendpb.DNSProfile],
) (err error) {
- panic("not implemented")
+ panic(testutil.UnexpectedCall(req, srv))
},
OnSaveDevicesBillingStat: func(
diff --git a/internal/backendpb/dns.pb.go b/internal/backendpb/dns.pb.go
index 0b3069d..d51192c 100644
--- a/internal/backendpb/dns.pb.go
+++ b/internal/backendpb/dns.pb.go
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.36.6
-// protoc v6.31.0
+// protoc-gen-go v1.36.8
+// protoc v6.32.0
// source: dns.proto
package backendpb
@@ -1056,7 +1056,7 @@ func (x *ParentalSettings) GetSchedule() *ScheduleSettings {
type ScheduleSettings struct {
state protoimpl.MessageState `protogen:"open.v1"`
Tmz string `protobuf:"bytes,1,opt,name=tmz,proto3" json:"tmz,omitempty"`
- WeeklyRange *WeeklyRange `protobuf:"bytes,2,opt,name=weeklyRange,proto3" json:"weeklyRange,omitempty"`
+ WeeklyRange *WeeklyRange `protobuf:"bytes,2,opt,name=weekly_range,json=weeklyRange,proto3" json:"weekly_range,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -2810,7 +2810,7 @@ var File_dns_proto protoreflect.FileDescriptor
const file_dns_proto_rawDesc = "" +
"\n" +
- "\tdns.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1bgoogle/protobuf/empty.proto\"\x1a\n" +
+ "\tdns.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x1a\n" +
"\x18RateLimitSettingsRequest\"P\n" +
"\x19RateLimitSettingsResponse\x123\n" +
"\x0fallowed_subnets\x18\x01 \x03(\v2\n" +
@@ -2897,10 +2897,10 @@ const file_dns_proto_rawDesc = "" +
"\x13general_safe_search\x18\x03 \x01(\bR\x11generalSafeSearch\x12.\n" +
"\x13youtube_safe_search\x18\x04 \x01(\bR\x11youtubeSafeSearch\x12)\n" +
"\x10blocked_services\x18\x05 \x03(\tR\x0fblockedServices\x12-\n" +
- "\bschedule\x18\x06 \x01(\v2\x11.ScheduleSettingsR\bschedule\"T\n" +
+ "\bschedule\x18\x06 \x01(\v2\x11.ScheduleSettingsR\bschedule\"U\n" +
"\x10ScheduleSettings\x12\x10\n" +
- "\x03tmz\x18\x01 \x01(\tR\x03tmz\x12.\n" +
- "\vweeklyRange\x18\x02 \x01(\v2\f.WeeklyRangeR\vweeklyRange\"\xd8\x01\n" +
+ "\x03tmz\x18\x01 \x01(\tR\x03tmz\x12/\n" +
+ "\fweekly_range\x18\x02 \x01(\v2\f.WeeklyRangeR\vweeklyRange\"\xd8\x01\n" +
"\vWeeklyRange\x12\x1b\n" +
"\x03mon\x18\x01 \x01(\v2\t.DayRangeR\x03mon\x12\x1b\n" +
"\x03tue\x18\x02 \x01(\v2\t.DayRangeR\x03tue\x12\x1b\n" +
@@ -3019,8 +3019,7 @@ const file_dns_proto_rawDesc = "" +
"\x13CustomDomainService\x12_\n" +
"\x1agetCustomDomainCertificate\x12\x1f.CustomDomainCertificateRequest\x1a .CustomDomainCertificateResponse2Z\n" +
"\x14SessionTicketService\x12B\n" +
- "\x11getSessionTickets\x12\x15.SessionTicketRequest\x1a\x16.SessionTicketResponseB=\n" +
- "!com.adguard.backend.dns.generatedB\x10DNSProfilesProtoP\x01\xa2\x02\x03DNSb\x06proto3"
+ "\x11getSessionTickets\x12\x15.SessionTicketRequest\x1a\x16.SessionTicketResponseb\x06proto3"
var (
file_dns_proto_rawDescOnce sync.Once
@@ -3111,7 +3110,7 @@ var file_dns_proto_depIdxs = []int32{
45, // 20: CustomDomain.current:type_name -> CustomDomain.Current
24, // 21: DeviceSettings.authentication:type_name -> AuthenticationSettings
13, // 22: ParentalSettings.schedule:type_name -> ScheduleSettings
- 14, // 23: ScheduleSettings.weeklyRange:type_name -> WeeklyRange
+ 14, // 23: ScheduleSettings.weekly_range:type_name -> WeeklyRange
15, // 24: WeeklyRange.mon:type_name -> DayRange
15, // 25: WeeklyRange.tue:type_name -> DayRange
15, // 26: WeeklyRange.wed:type_name -> DayRange
diff --git a/internal/backendpb/dns.proto b/internal/backendpb/dns.proto
index 867effc..a17d761 100644
--- a/internal/backendpb/dns.proto
+++ b/internal/backendpb/dns.proto
@@ -1,118 +1,107 @@
syntax = "proto3";
import "google/protobuf/duration.proto";
-import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";
+import "google/protobuf/timestamp.proto";
-option java_multiple_files = true;
-option java_package = "com.adguard.backend.dns.generated";
-option java_outer_classname = "DNSProfilesProto";
-option objc_class_prefix = "DNS";
+// TODO(a.garipov): Expand the documentation and make it consistent.
service DNSService {
-
/*
- Gets DNS profiles.
+ Gets DNS profiles.
- Field "sync_time" in DNSProfilesRequest - pass to return the latest updates after this time moment.
+ Field "sync_time" in DNSProfilesRequest - pass to return the latest updates after this time moment.
- The trailers headers will include a "sync_time", given in milliseconds,
- that should be used for subsequent incremental DNS profile synchronization requests.
+ The trailers headers will include a "sync_time", given in milliseconds,
+ that should be used for subsequent incremental DNS profile synchronization requests.
- This method may return the following errors:
- - RateLimitedError: If too many "full sync" concurrent requests are made.
- - AuthenticationFailedError: If the authentication failed.
+ This method may return the following errors:
+ - RateLimitedError: If too many "full sync" concurrent requests are made.
+ - AuthenticationFailedError: If the authentication failed.
*/
rpc getDNSProfiles(DNSProfilesRequest) returns (stream DNSProfile);
/*
- Stores devices activity.
+ Stores devices activity.
- This method may return the following errors:
- - AuthenticationFailedError: If the authentication failed.
+ This method may return the following errors:
+ - AuthenticationFailedError: If the authentication failed.
*/
rpc saveDevicesBillingStat(stream DeviceBillingStat) returns (google.protobuf.Empty);
/*
- Create device by "human_id".
+ Create device by "human_id".
- This method may return the following errors:
- - RateLimitedError: If the request was made too frequently and the client must wait before retrying.
- - DeviceQuotaExceededError: If the client has exceeded its quota for creating devices.
- - BadRequestError: If the request is invalid: DNS server does not exist, creation of auto-devices is disabled or human_id validation failed.
- - AuthenticationFailedError: If the authentication failed.
+ This method may return the following errors:
+ - RateLimitedError: If the request was made too frequently and the client must wait before retrying.
+ - DeviceQuotaExceededError: If the client has exceeded its quota for creating devices.
+ - BadRequestError: If the request is invalid: DNS server does not exist, creation of auto-devices is disabled or human_id validation failed.
+ - AuthenticationFailedError: If the authentication failed.
*/
rpc createDeviceByHumanId(CreateDeviceRequest) returns (CreateDeviceResponse);
}
service RateLimitService {
-
/*
- Gets rate limit settings.
+ Gets rate limit settings.
*/
rpc getRateLimitSettings(RateLimitSettingsRequest) returns (RateLimitSettingsResponse);
/*
- Gets global access settings.
+ Gets global access settings.
*/
rpc getGlobalAccessSettings(GlobalAccessSettingsRequest) returns (GlobalAccessSettingsResponse);
}
service RemoteKVService {
-
/**
- Get the value for the specified key.
+ Get the value for the specified key.
- This method may return the following errors:
- - AuthenticationFailedError: If the authentication failed.
- */
+ This method may return the following errors:
+ - AuthenticationFailedError: If the authentication failed.
+ */
rpc get(RemoteKVGetRequest) returns (RemoteKVGetResponse);
/**
- Set the value for the specified key.
+ Set the value for the specified key.
- This method may return the following errors:
- - AuthenticationFailedError: If the authentication failed.
- - BadRequestError: If the request is invalid: value size exceeds the 512kb.
- */
+ This method may return the following errors:
+ - AuthenticationFailedError: If the authentication failed.
+ - BadRequestError: If the request is invalid: value size exceeds the 512kb.
+ */
rpc set(RemoteKVSetRequest) returns (RemoteKVSetResponse);
}
service CustomDomainService {
-
/*
- Get certificate for custom domain.
+ Get certificate for custom domain.
- This method may return the following errors:
- - AuthenticationFailedError: If the authentication failed.
- - BadRequestError: If the request is invalid: cert_name is empty.
- - NotFoundError: If the certificate could not be found.
+ This method may return the following errors:
+ - AuthenticationFailedError: If the authentication failed.
+ - BadRequestError: If the request is invalid: cert_name is empty or no certificate found.
+ - NotFoundError: If the certificate was not found.
+ - RateLimitedError: If the request was made too frequently and the client must wait before retrying.
*/
rpc getCustomDomainCertificate(CustomDomainCertificateRequest) returns (CustomDomainCertificateResponse);
}
service SessionTicketService {
+ /*
+ Gets session ticket for the current date
- /*
- Gets session ticket for the current date
-
- This method may return the following errors:
- - AuthenticationFailedError: If the authentication failed.
- */
- rpc getSessionTickets(SessionTicketRequest) returns (SessionTicketResponse);
+ This method may return the following errors:
+ - AuthenticationFailedError: If the authentication failed.
+ */
+ rpc getSessionTickets(SessionTicketRequest) returns (SessionTicketResponse);
}
-message RateLimitSettingsRequest {
-
-}
+message RateLimitSettingsRequest {}
message RateLimitSettingsResponse {
repeated CidrRange allowed_subnets = 1;
}
-message GlobalAccessSettingsRequest {
-
-}
+message GlobalAccessSettingsRequest {}
message GlobalAccessSettingsResponse {
AccessSettings standard = 1;
@@ -164,18 +153,17 @@ message DNSProfile {
}
message DeviceSettingsChange {
-
message Deleted {
- string device_id = 1;
+ string device_id = 1;
}
message Upserted {
- DeviceSettings device = 1;
+ DeviceSettings device = 1;
}
oneof change {
- Deleted deleted = 1;
- Upserted upserted = 2;
+ Deleted deleted = 1;
+ Upserted upserted = 2;
}
}
@@ -237,7 +225,7 @@ message ParentalSettings {
message ScheduleSettings {
string tmz = 1;
- WeeklyRange weeklyRange = 2;
+ WeeklyRange weekly_range = 2;
}
message WeeklyRange {
@@ -369,9 +357,7 @@ message RemoteKVSetRequest {
google.protobuf.Duration ttl = 3;
}
-message RemoteKVSetResponse {
-
-}
+message RemoteKVSetResponse {}
message CustomDomainCertificateRequest {
string cert_name = 1;
@@ -385,10 +371,10 @@ message CustomDomainCertificateResponse {
message SessionTicketRequest {}
message SessionTicketResponse {
- repeated SessionTicket tickets = 1;
+ repeated SessionTicket tickets = 1;
}
message SessionTicket {
- string name = 1;
- bytes data = 2;
+ string name = 1;
+ bytes data = 2;
}
diff --git a/internal/backendpb/dns_grpc.pb.go b/internal/backendpb/dns_grpc.pb.go
index f1d8738..33694c9 100644
--- a/internal/backendpb/dns_grpc.pb.go
+++ b/internal/backendpb/dns_grpc.pb.go
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
-// - protoc v6.31.0
+// - protoc v6.32.0
// source: dns.proto
package backendpb
@@ -554,8 +554,9 @@ type CustomDomainServiceClient interface {
//
// This method may return the following errors:
// - AuthenticationFailedError: If the authentication failed.
- // - BadRequestError: If the request is invalid: cert_name is empty.
- // - NotFoundError: If the certificate could not be found.
+ // - BadRequestError: If the request is invalid: cert_name is empty or no certificate found.
+ // - NotFoundError: If the certificate was not found.
+ // - RateLimitedError: If the request was made too frequently and the client must wait before retrying.
GetCustomDomainCertificate(ctx context.Context, in *CustomDomainCertificateRequest, opts ...grpc.CallOption) (*CustomDomainCertificateResponse, error)
}
@@ -585,8 +586,9 @@ type CustomDomainServiceServer interface {
//
// This method may return the following errors:
// - AuthenticationFailedError: If the authentication failed.
- // - BadRequestError: If the request is invalid: cert_name is empty.
- // - NotFoundError: If the certificate could not be found.
+ // - BadRequestError: If the request is invalid: cert_name is empty or no certificate found.
+ // - NotFoundError: If the certificate was not found.
+ // - RateLimitedError: If the request was made too frequently and the client must wait before retrying.
GetCustomDomainCertificate(context.Context, *CustomDomainCertificateRequest) (*CustomDomainCertificateResponse, error)
mustEmbedUnimplementedCustomDomainServiceServer()
}
diff --git a/internal/backendpb/metrics.go b/internal/backendpb/metrics.go
index 9b84ce0..b2953f0 100644
--- a/internal/backendpb/metrics.go
+++ b/internal/backendpb/metrics.go
@@ -182,3 +182,22 @@ func (EmptyTicketStorageMetrics) SetTicketsState(_ context.Context, _ float64) {
// ObserveUpdate implements the [TicketStorageMetrics] interface for
// EmptyTicketStorageMetrics.
func (EmptyTicketStorageMetrics) ObserveUpdate(_ context.Context, _ time.Duration, _ error) {}
+
+// StandardAccessMetrics is an interface that is used for the collection of
+// standard access statistics.
+type StandardAccessMetrics interface {
+ // ObserveUpdate sets the duration of the standard access settings update
+ // operation.
+ ObserveUpdate(ctx context.Context, dur time.Duration, err error)
+}
+
+// EmptyStandardAccessMetrics is the implementation of the
+// [StandardAccessMetrics] interface that does nothing.
+type EmptyStandardAccessMetrics struct{}
+
+// type check
+var _ StandardAccessMetrics = EmptyStandardAccessMetrics{}
+
+// ObserveUpdate implements the [StandardAccessMetrics] interface for
+// EmptyStandardAccessMetrics.
+func (EmptyStandardAccessMetrics) ObserveUpdate(_ context.Context, _ time.Duration, _ error) {}
diff --git a/internal/backendpb/profile.go b/internal/backendpb/profile.go
index 857b47f..ff000cf 100644
--- a/internal/backendpb/profile.go
+++ b/internal/backendpb/profile.go
@@ -88,6 +88,7 @@ func (x *AccessSettings) toInternal(
logger *slog.Logger,
errColl errcoll.Interface,
cons *access.ProfileConstructor,
+ standardEnabled bool,
) (a access.Profile) {
if x == nil || !x.Enabled {
return access.EmptyProfile{}
@@ -99,9 +100,32 @@ func (x *AccessSettings) toInternal(
AllowedASN: asnToInternal(x.AllowlistAsn),
BlockedASN: asnToInternal(x.BlocklistAsn),
BlocklistDomainRules: x.BlocklistDomainRules,
+ StandardEnabled: standardEnabled,
})
}
+// toStandardConfig converts protobuf access settings to an internal structure.
+// If x is nil, toStandardConfig returns nil.
+func (x *AccessSettings) toStandardConfig(
+ ctx context.Context,
+ logger *slog.Logger,
+ errColl errcoll.Interface,
+) (a *access.StandardBlockerConfig) {
+ if x == nil || !x.Enabled {
+ logger.WarnContext(ctx, "received disabled standard access settings")
+
+ return nil
+ }
+
+ return &access.StandardBlockerConfig{
+ AllowedNets: cidrRangeToInternal(ctx, errColl, logger, x.AllowlistCidr),
+ BlockedNets: cidrRangeToInternal(ctx, errColl, logger, x.BlocklistCidr),
+ AllowedASN: asnToInternal(x.AllowlistAsn),
+ BlockedASN: asnToInternal(x.BlocklistAsn),
+ BlocklistDomainRules: x.BlocklistDomainRules,
+ }
+}
+
// cidrRangeToInternal is a helper that converts a slice of CidrRange to the
// slice of [netip.Prefix].
func cidrRangeToInternal(
diff --git a/internal/backendpb/profilestorage.go b/internal/backendpb/profilestorage.go
index baa735c..a885f7a 100644
--- a/internal/backendpb/profilestorage.go
+++ b/internal/backendpb/profilestorage.go
@@ -304,6 +304,14 @@ func (s *ProfileStorage) newProfile(
Enabled: customEnabled,
}
+ accessProf := p.Access.toInternal(
+ ctx,
+ s.logger,
+ s.errColl,
+ s.profAccessCons,
+ p.StandardAccessSettingsEnabled,
+ )
+
return &agd.Profile{
CustomDomains: p.CustomDomain.toInternal(ctx, s.errColl, s.logger),
DeviceIDs: container.NewMapSet(deviceIDs...),
@@ -313,7 +321,7 @@ func (s *ProfileStorage) newProfile(
RuleList: p.RuleLists.toInternal(ctx, s.errColl, s.logger),
SafeBrowsing: p.SafeBrowsing.toInternal(),
},
- Access: p.Access.toInternal(ctx, s.logger, s.errColl, s.profAccessCons),
+ Access: accessProf,
BlockingMode: m,
Ratelimiter: p.RateLimit.toInternal(ctx, s.errColl, s.logger, s.respSzEst),
AccountID: accID,
diff --git a/internal/backendpb/profilestorage_internal_test.go b/internal/backendpb/profilestorage_internal_test.go
index eb83834..9bb6910 100644
--- a/internal/backendpb/profilestorage_internal_test.go
+++ b/internal/backendpb/profilestorage_internal_test.go
@@ -56,7 +56,7 @@ func TestProfileStorage_NewProfile(t *testing.T) {
)
require.NoError(t, err)
- assert.Equal(t, newProfile(t), got)
+ agdtest.AssertEqualProfile(t, newProfile(t), got)
assert.Equal(t, newDevices(t), gotDevices)
assert.Equal(t, wantDevChg, gotDevChg)
})
@@ -95,7 +95,7 @@ func TestProfileStorage_NewProfile(t *testing.T) {
errCollErr,
)
- assert.Equal(t, newProfile(t), got)
+ agdtest.AssertEqualProfile(t, newProfile(t), got)
assert.Equal(t, newDevices(t), gotDevices)
assert.Equal(t, wantDevChg, gotDevChg)
})
@@ -135,7 +135,10 @@ func TestProfileStorage_NewProfile(t *testing.T) {
errCollErr,
)
- assert.NotEqual(t, newProfile(t), got)
+ wantProf := newProfile(t)
+ wantProf.DeviceIDs.Delete(TestDeviceID)
+
+ agdtest.AssertEqualProfile(t, wantProf, got)
assert.NotEqual(t, newDevices(t), gotDevices)
assert.Len(t, gotDevices, 3)
assert.Equal(t, wantDevChg, gotDevChg)
@@ -250,7 +253,7 @@ func TestProfileStorage_NewProfile(t *testing.T) {
wantProf := newProfile(t)
wantProf.BlockingMode = &dnsmsg.BlockingModeNullIP{}
- assert.Equal(t, wantProf, got)
+ agdtest.AssertEqualProfile(t, wantProf, got)
assert.Equal(t, newDevices(t), gotDevices)
assert.Equal(t, wantDevChg, gotDevChg)
})
diff --git a/internal/backendpb/profilestorage_test.go b/internal/backendpb/profilestorage_test.go
index 4f7a34e..d37c6bc 100644
--- a/internal/backendpb/profilestorage_test.go
+++ b/internal/backendpb/profilestorage_test.go
@@ -52,13 +52,13 @@ func TestProfileStorage_CreateAutoDevice(t *testing.T) {
req *backendpb.DNSProfilesRequest,
srv grpc.ServerStreamingServer[backendpb.DNSProfile],
) (err error) {
- panic("not implemented")
+ panic(testutil.UnexpectedCall(req, srv))
},
OnSaveDevicesBillingStat: func(
srv grpc.ClientStreamingServer[backendpb.DeviceBillingStat, emptypb.Empty],
) (err error) {
- panic("not implemented")
+ panic(testutil.UnexpectedCall(srv))
},
}
@@ -114,10 +114,10 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
srv := &testDNSServiceServer{
OnCreateDeviceByHumanId: func(
- _ context.Context,
- _ *backendpb.CreateDeviceRequest,
- ) (_ *backendpb.CreateDeviceResponse, _ error) {
- panic("not implemented")
+ ctx context.Context,
+ req *backendpb.CreateDeviceRequest,
+ ) (resp *backendpb.CreateDeviceResponse, err error) {
+ panic(testutil.UnexpectedCall(ctx, req))
},
OnGetDNSProfiles: func(
@@ -131,9 +131,9 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
},
OnSaveDevicesBillingStat: func(
- _ grpc.ClientStreamingServer[backendpb.DeviceBillingStat, emptypb.Empty],
- ) (_ error) {
- panic("not implemented")
+ srv grpc.ClientStreamingServer[backendpb.DeviceBillingStat, emptypb.Empty],
+ ) (err error) {
+ panic(testutil.UnexpectedCall(srv))
},
}
diff --git a/internal/backendpb/ratelimiter_test.go b/internal/backendpb/ratelimiter_test.go
index 488f359..51bbd40 100644
--- a/internal/backendpb/ratelimiter_test.go
+++ b/internal/backendpb/ratelimiter_test.go
@@ -2,7 +2,6 @@ package backendpb_test
import (
"context"
- "fmt"
"net/netip"
"testing"
@@ -38,10 +37,10 @@ func TestRateLimiter_Refresh(t *testing.T) {
},
// TODO(e.burkov): Use and test.
OnGetGlobalAccessSettings: func(
- _ context.Context,
- _ *backendpb.GlobalAccessSettingsRequest,
- ) (_ *backendpb.GlobalAccessSettingsResponse, _ error) {
- panic(fmt.Errorf("unexpected call to GetGlobalAccessSettings"))
+ ctx context.Context,
+ req *backendpb.GlobalAccessSettingsRequest,
+ ) (resp *backendpb.GlobalAccessSettingsResponse, err error) {
+ panic(testutil.UnexpectedCall(ctx, req))
},
}
diff --git a/internal/backendpb/standardaccess.go b/internal/backendpb/standardaccess.go
new file mode 100644
index 0000000..162b7a4
--- /dev/null
+++ b/internal/backendpb/standardaccess.go
@@ -0,0 +1,96 @@
+package backendpb
+
+import (
+ "context"
+ "fmt"
+ "log/slog"
+ "net/url"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/access"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter/filterstorage"
+)
+
+// StandardAccessConfig is the configuration structure for the business logic
+// backend standard profile access service.
+type StandardAccessConfig struct {
+ // Logger is used for logging the operation of the standard access service.
+ // It must not be nil.
+ Logger *slog.Logger
+
+ // GRPCMetrics is used for the collection of the protobuf communication
+ // statistics.
+ GRPCMetrics GRPCMetrics
+
+ // Metrics is used to collect standard access service statistics.
+ Metrics StandardAccessMetrics
+
+ // ErrColl is used to collect errors during procedure calls.
+ ErrColl errcoll.Interface
+
+ // Endpoint is the backend API URL. The scheme should be either "grpc" or
+ // "grpcs". It must not be nil.
+ Endpoint *url.URL
+
+ // APIKey is the API key used for authentication, if any. If empty, no
+ // authentication is performed.
+ APIKey string
+}
+
+// StandardAccess is the implementation of the [service.Refresher] interface
+// that retrieves the standard access settings from the business logic backend.
+type StandardAccess struct {
+ logger *slog.Logger
+ grpcMetrics GRPCMetrics
+ metrics StandardAccessMetrics
+ errColl errcoll.Interface
+ client RateLimitServiceClient
+ apiKey string
+}
+
+// NewStandardAccess creates a new properly initialized standard access service.
+// c must not be nil.
+func NewStandardAccess(c *StandardAccessConfig) (a *StandardAccess, err error) {
+ client, err := newClient(c.Endpoint)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return nil, err
+ }
+
+ return &StandardAccess{
+ logger: c.Logger,
+ grpcMetrics: c.GRPCMetrics,
+ metrics: c.Metrics,
+ errColl: c.ErrColl,
+ client: NewRateLimitServiceClient(client),
+ apiKey: c.APIKey,
+ }, nil
+}
+
+// type check
+var _ filterstorage.StandardAccessStorage = (*StandardAccess)(nil)
+
+// Config retrieves the standard access settings from the business logic
+// backend.
+func (a *StandardAccess) Config(ctx context.Context) (c *access.StandardBlockerConfig, err error) {
+ ctx = ctxWithAuthentication(ctx, a.apiKey)
+ req := &GlobalAccessSettingsRequest{}
+
+ start := time.Now()
+ defer func() {
+ // TODO(e.burkov): Consider separating metrics for networking and
+ // decoding.
+ a.metrics.ObserveUpdate(ctx, time.Since(start), err)
+ }()
+
+ resp, err := a.client.GetGlobalAccessSettings(ctx, req)
+ if err != nil {
+ return nil, fmt.Errorf(
+ "loading global access settings: %w",
+ fixGRPCError(ctx, a.grpcMetrics, err),
+ )
+ }
+
+ return resp.GetStandard().toStandardConfig(ctx, a.logger, a.errColl), nil
+}
diff --git a/internal/bindtodevice/manager_linux.go b/internal/bindtodevice/manager_linux.go
index 91badea..823c189 100644
--- a/internal/bindtodevice/manager_linux.go
+++ b/internal/bindtodevice/manager_linux.go
@@ -225,7 +225,7 @@ var _ service.Interface = (*Manager)(nil)
//
// TODO(a.garipov): Consider an interface solution instead of the nil exception.
//
-// TODO(a.garipov): Use the context for cancelation.
+// TODO(a.garipov): Use the context for cancellation.
func (m *Manager) Start(ctx context.Context) (err error) {
if m == nil {
return nil
@@ -262,7 +262,7 @@ func (m *Manager) Start(ctx context.Context) (err error) {
//
// TODO(a.garipov): Consider waiting for all sockets to close.
//
-// TODO(a.garipov): Use the context for cancelation.
+// TODO(a.garipov): Use the context for cancellation.
//
// TODO(a.garipov): Consider an interface solution instead of the nil exception.
func (m *Manager) Shutdown(_ context.Context) (err error) {
diff --git a/internal/bindtodevice/socket_linux_internal_test.go b/internal/bindtodevice/socket_linux_internal_test.go
index 02a7349..731d18d 100644
--- a/internal/bindtodevice/socket_linux_internal_test.go
+++ b/internal/bindtodevice/socket_linux_internal_test.go
@@ -406,6 +406,7 @@ func TestListenControlWithSO(t *testing.T) {
)
require.NotNil(t, lc)
+ // TODO(a.garipov): Move to golibs.
type syscallConner interface {
SyscallConn() (c syscall.RawConn, err error)
}
@@ -414,9 +415,10 @@ func TestListenControlWithSO(t *testing.T) {
c, err := lc.ListenPacket(context.Background(), "udp", "0.0.0.0:0")
require.NoError(t, err)
require.NotNil(t, c)
- require.Implements(t, (*syscallConner)(nil), c)
- sc, err := c.(syscallConner).SyscallConn()
+ scConner := testutil.RequireTypeAssert[syscallConner](t, c)
+
+ sc, err := scConner.SyscallConn()
require.NoError(t, err)
err = sc.Control(func(fd uintptr) {
@@ -440,9 +442,10 @@ func TestListenControlWithSO(t *testing.T) {
c, err := lc.Listen(context.Background(), "tcp", "0.0.0.0:0")
require.NoError(t, err)
require.NotNil(t, c)
- require.Implements(t, (*syscallConner)(nil), c)
- sc, err := c.(syscallConner).SyscallConn()
+ scConner := testutil.RequireTypeAssert[syscallConner](t, c)
+
+ sc, err := scConner.SyscallConn()
require.NoError(t, err)
err = sc.Control(func(fd uintptr) {
diff --git a/internal/cmd/access.go b/internal/cmd/access.go
index 486efad..5e9699a 100644
--- a/internal/cmd/access.go
+++ b/internal/cmd/access.go
@@ -6,6 +6,12 @@ import (
"github.com/AdguardTeam/golibs/validate"
)
+// Possible values of the STANDARD_ACCESS_TYPE environment variable.
+const (
+ standardAccessOff = "off"
+ standardAccessBackend = "backend"
+)
+
// accessConfig is the configuration that controls IP and hosts blocking.
type accessConfig struct {
// BlockedQuestionDomains is a list of AdBlock rules used to block access.
diff --git a/internal/cmd/builder.go b/internal/cmd/builder.go
index 8401d8c..f0aeafe 100644
--- a/internal/cmd/builder.go
+++ b/internal/cmd/builder.go
@@ -57,16 +57,17 @@ import (
// Constants that define debug identifiers for the debug HTTP service.
const (
- debugIDAllowlist = "allowlist"
- debugIDBillStat = "billstat"
- debugIDCustomDomainDB = "custom_domain_db"
- debugIDGeoIP = "geoip"
- debugIDProfileDB = "profiledb"
- debugIDProfileDBFull = "profiledb_full"
- debugIDRuleStat = "rulestat"
- debugIDTLSConfig = "tlsconfig"
- debugIDTicketRotator = "ticket_rotator"
- debugIDWebSvc = "websvc"
+ debugIDAllowlist = "allowlist"
+ debugIDBillStat = "billstat"
+ debugIDCustomDomainDB = "custom_domain_db"
+ debugIDGeoIP = "geoip"
+ debugIDProfileDB = "profiledb"
+ debugIDProfileDBFull = "profiledb_full"
+ debugIDRuleStat = "rulestat"
+ debugIDStandardProfileAccess = "standard_profile_access"
+ debugIDTLSConfig = "tlsconfig"
+ debugIDTicketRotator = "ticket_rotator"
+ debugIDWebSvc = "websvc"
// debugIDPrefixPlugin is the prefix for plugin debug identifiers.
debugIDPrefixPlugin = "plugin/"
@@ -97,6 +98,7 @@ type builder struct {
promRegisterer prometheus.Registerer
rand *rand.Rand
sigHdlr *service.SignalHandler
+ standardAccess access.Blocker
// The fields below are initialized later by calling the builder's methods.
// Keep them sorted.
@@ -318,9 +320,9 @@ func (b *builder) initAdultBlocking(
return nil
}
- b.adultBlockingHashes, err = hashprefix.NewStorage("")
+ b.adultBlockingHashes, err = hashprefix.NewStorage(nil)
if err != nil {
- // Don't expect errors here because we pass an empty string.
+ // Expect no errors here because we pass a nil.
panic(err)
}
@@ -420,7 +422,7 @@ func (b *builder) initNewRegDomains(
return nil
}
- b.newRegDomainsHashes, err = hashprefix.NewStorage("")
+ b.newRegDomainsHashes, err = hashprefix.NewStorage(nil)
if err != nil {
// Don't expect errors here because we pass an empty string.
panic(err)
@@ -508,7 +510,7 @@ func (b *builder) initSafeBrowsing(
return nil
}
- b.safeBrowsingHashes, err = hashprefix.NewStorage("")
+ b.safeBrowsingHashes, err = hashprefix.NewStorage(nil)
if err != nil {
// Don't expect errors here because we pass an empty string.
panic(err)
@@ -581,6 +583,83 @@ func (b *builder) initSafeBrowsing(
return nil
}
+// initStandardAccess initializes the standard access settings.
+//
+// The following methods must be called before this one:
+// - [builder.initGRPCMetrics]
+func (b *builder) initStandardAccess(ctx context.Context) (err error) {
+ switch typ := b.env.StandardAccessType; typ {
+ case standardAccessOff:
+ b.standardAccess = access.EmptyBlocker{}
+
+ return nil
+ case standardAccessBackend:
+ // Go on.
+ //
+ // TODO(e.burkov): Extract the initialization logic to a separate
+ // function.
+ default:
+ panic(fmt.Errorf("env STANDARD_ACCESS_TYPE: %w: %q", errors.ErrBadEnumValue, typ))
+ }
+
+ stdAcc := access.NewStandardBlocker(&access.StandardBlockerConfig{})
+ b.standardAccess = stdAcc
+
+ mtrc, err := metrics.NewBackendStandardAccess(b.mtrcNamespace, b.promRegisterer)
+ if err != nil {
+ return fmt.Errorf("initializing standard access metrics: %w", err)
+ }
+
+ strg, err := backendpb.NewStandardAccess(&backendpb.StandardAccessConfig{
+ Endpoint: &b.env.StandardAccessURL.URL,
+ GRPCMetrics: b.backendGRPCMtrc,
+ Metrics: mtrc,
+ Logger: b.baseLogger.With(slogutil.KeyPrefix, "standard_access_storage"),
+ ErrColl: b.errColl,
+ APIKey: b.env.StandardAccessAPIKey,
+ })
+ if err != nil {
+ return fmt.Errorf("initializing standard access storage: %w", err)
+ }
+
+ updater, err := filterstorage.NewStandardAccess(ctx, &filterstorage.StandardAccessConfig{
+ BaseLogger: b.baseLogger,
+ Logger: b.baseLogger.With(slogutil.KeyPrefix, "standard_access_updater"),
+ Getter: strg,
+ Setter: stdAcc,
+ CacheDir: b.env.FilterCachePath,
+ })
+ if err != nil {
+ return fmt.Errorf("initializing standard access updater: %w", err)
+ }
+
+ err = updater.Refresh(ctx)
+ if err != nil {
+ return fmt.Errorf("initializing standard access updater: %w", err)
+ }
+
+ refrWorker := service.NewRefreshWorker(&service.RefreshWorkerConfig{
+ Clock: timeutil.SystemClock{},
+ ContextConstructor: contextutil.NewTimeoutConstructor(
+ time.Duration(b.env.StandardAccessTimeout),
+ ),
+ ErrorHandler: newSlogErrorHandler(b.baseLogger, "standard_access_refresh"),
+ Refresher: updater,
+ Schedule: timeutil.NewConstSchedule(time.Duration(b.env.StandardAccessRefreshIvl)),
+ RefreshOnShutdown: false,
+ })
+ err = refrWorker.Start(context.WithoutCancel(ctx))
+ if err != nil {
+ return fmt.Errorf("starting standard access refresher: %w", err)
+ }
+
+ b.sigHdlr.AddService(refrWorker)
+
+ b.debugRefrs[debugIDStandardProfileAccess] = updater
+
+ return nil
+}
+
// initFilterStorage initializes and refreshes the filter storage. It also adds
// the refresher with ID [filter.StoragePrefix] to the debug refreshers.
//
@@ -598,7 +677,7 @@ func (b *builder) initFilterStorage(ctx context.Context) (err error) {
b.filterStorage, err = filterstorage.New(&filterstorage.Config{
BaseLogger: b.baseLogger,
Logger: b.baseLogger.With(slogutil.KeyPrefix, filter.StoragePrefix),
- BlockedServices: &filterstorage.ConfigBlockedServices{
+ BlockedServices: &filterstorage.BlockedServicesConfig{
IndexURL: blockedSvcIdxURL,
// TODO(a.garipov): Consider adding a separate parameter here.
IndexMaxSize: c.MaxSize,
@@ -612,15 +691,15 @@ func (b *builder) initFilterStorage(ctx context.Context) (err error) {
ResultCacheEnabled: c.RuleListCache.Enabled,
Enabled: bool(b.env.BlockedServiceEnabled),
},
- Custom: &filterstorage.ConfigCustom{
+ Custom: &filterstorage.CustomConfig{
CacheCount: c.CustomFilterCacheSize,
},
- HashPrefix: &filterstorage.ConfigHashPrefix{
+ HashPrefix: &filterstorage.HashPrefixConfig{
Adult: b.adultBlocking,
Dangerous: b.safeBrowsing,
NewlyRegistered: b.newRegDomains,
},
- RuleLists: &filterstorage.ConfigRuleLists{
+ RuleLists: &filterstorage.RuleListsConfig{
IndexURL: &b.env.FilterIndexURL.URL,
// TODO(a.garipov): Consider adding a separate parameter here.
IndexMaxSize: c.MaxSize,
@@ -686,14 +765,14 @@ func (b *builder) newSafeSearchConfig(
u *urlutil.URL,
id filter.ID,
enabled bool,
-) (c *filterstorage.ConfigSafeSearch) {
+) (c *filterstorage.SafeSearchConfig) {
if !enabled {
- return &filterstorage.ConfigSafeSearch{}
+ return &filterstorage.SafeSearchConfig{}
}
fltConf := b.conf.Filters
- return &filterstorage.ConfigSafeSearch{
+ return &filterstorage.SafeSearchConfig{
URL: &u.URL,
ID: id,
// TODO(a.garipov): Consider adding a separate parameter here.
@@ -1148,6 +1227,7 @@ func (b *builder) initGRPCMetrics(ctx context.Context) (err error) {
case
b.profilesEnabled,
b.env.SessionTicketType == sessionTicketRemote,
+ b.env.StandardAccessType == standardAccessBackend,
b.env.DNSCheckKVType == kvModeBackend,
b.env.RateLimitAllowlistType == rlAllowlistTypeBackend:
// Go on.
@@ -1262,7 +1342,10 @@ func (b *builder) initProfileDB(ctx context.Context) (err error) {
return fmt.Errorf("registering profile access engine metrics: %w", err)
}
- profAccessCons := access.NewProfileConstructor(profileMtrc)
+ profAccessCons := access.NewProfileConstructor(&access.ProfileConstructorConfig{
+ Metrics: profileMtrc,
+ Standard: b.standardAccess,
+ })
backendProfileDBMtrc, err := metrics.NewBackendProfileDB(b.mtrcNamespace, b.promRegisterer)
if err != nil {
diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go
index 7146c22..e3bb189 100644
--- a/internal/cmd/cmd.go
+++ b/internal/cmd/cmd.go
@@ -112,6 +112,8 @@ func Main(plugins *plugin.Registry) {
errors.Check(b.initGRPCMetrics(ctx))
+ errors.Check(b.initStandardAccess(ctx))
+
errors.Check(b.initTLSManager(ctx))
errors.Check(b.initCustomDomainDB(ctx))
diff --git a/internal/cmd/env.go b/internal/cmd/env.go
index 574f2a6..a7681c2 100644
--- a/internal/cmd/env.go
+++ b/internal/cmd/env.go
@@ -49,6 +49,7 @@ type environment struct {
RuleStatURL *urlutil.URL `env:"RULESTAT_URL"`
SafeBrowsingURL *urlutil.URL `env:"SAFE_BROWSING_URL"`
SessionTicketURL *urlutil.URL `env:"SESSION_TICKET_URL"`
+ StandardAccessURL *urlutil.URL `env:"STANDARD_ACCESS_URL"`
YoutubeSafeSearchURL *urlutil.URL `env:"YOUTUBE_SAFE_SEARCH_URL"`
BackendRateLimitAPIKey string `env:"BACKEND_RATELIMIT_API_KEY"`
@@ -74,6 +75,8 @@ type environment struct {
SessionTicketCachePath string `env:"SESSION_TICKET_CACHE_PATH"`
SessionTicketIndexName string `env:"SESSION_TICKET_INDEX_NAME"`
SessionTicketType string `env:"SESSION_TICKET_TYPE"`
+ StandardAccessAPIKey string `env:"STANDARD_ACCESS_API_KEY"`
+ StandardAccessType string `env:"STANDARD_ACCESS_TYPE"`
// TODO(a.garipov): Consider renaming to "WEB_STATIC_PATH" or something
// similar.
@@ -83,9 +86,11 @@ type environment struct {
ProfilesMaxRespSize datasize.ByteSize `env:"PROFILES_MAX_RESP_SIZE" envDefault:"64MB"`
- CustomDomainsRefreshIvl timeutil.Duration `env:"CUSTOM_DOMAINS_REFRESH_INTERVAL"`
- DNSCheckKVTTL timeutil.Duration `env:"DNSCHECK_KV_TTL"`
- SessionTicketRefreshIvl timeutil.Duration `env:"SESSION_TICKET_REFRESH_INTERVAL"`
+ CustomDomainsRefreshIvl timeutil.Duration `env:"CUSTOM_DOMAINS_REFRESH_INTERVAL"`
+ DNSCheckKVTTL timeutil.Duration `env:"DNSCHECK_KV_TTL"`
+ SessionTicketRefreshIvl timeutil.Duration `env:"SESSION_TICKET_REFRESH_INTERVAL"`
+ StandardAccessRefreshIvl timeutil.Duration `env:"STANDARD_ACCESS_REFRESH_INTERVAL"`
+ StandardAccessTimeout timeutil.Duration `env:"STANDARD_ACCESS_TIMEOUT"`
// TODO(a.garipov): Rename to DNSCHECK_CACHE_KV_COUNT?
DNSCheckCacheKVSize int `env:"DNSCHECK_CACHE_KV_SIZE"`
@@ -152,6 +157,7 @@ func (envs *environment) Validate() (err error) {
errs = envs.validateDNSCheck(errs)
errs = envs.validateRateLimit(errs)
errs = envs.validateSessionTickets(errs)
+ errs = envs.validateStandardAccess(errs)
errs = envs.validateRateLimitURLs(errs)
return errors.Join(errs...)
@@ -328,12 +334,12 @@ func (envs *environment) validateRateLimit(errs []error) (res []error) {
func (envs *environment) validateSessionTickets(errs []error) (res []error) {
res = errs
- err := validate.Positive("env SESSION_TICKET_REFRESH_INTERVAL", envs.SessionTicketRefreshIvl)
+ err := validate.NotEmpty("env SESSION_TICKET_TYPE", envs.SessionTicketType)
if err != nil {
- res = append(res, err)
+ return append(res, err)
}
- err = validate.NotEmpty("env SESSION_TICKET_TYPE", envs.SessionTicketType)
+ err = validate.Positive("env SESSION_TICKET_REFRESH_INTERVAL", envs.SessionTicketRefreshIvl)
if err != nil {
return append(res, err)
}
@@ -342,24 +348,52 @@ func (envs *environment) validateSessionTickets(errs []error) (res []error) {
case sessionTicketLocal:
return res
case sessionTicketRemote:
- // Go on.
+ res = append(
+ res,
+ validate.NotEmpty("env SESSION_TICKET_API_KEY", envs.SessionTicketAPIKey),
+ validate.NotEmpty("env SESSION_TICKET_CACHE_PATH", envs.SessionTicketCachePath),
+ validate.NotEmpty("env SESSION_TICKET_INDEX_NAME", envs.SessionTicketIndexName),
+ )
+
+ if err = validate.NotNil("env SESSION_TICKET_URL", envs.SessionTicketURL); err != nil {
+ res = append(res, err)
+ } else if err = urlutil.ValidateGRPCURL(&envs.SessionTicketURL.URL); err != nil {
+ res = append(res, fmt.Errorf("env SESSION_TICKET_URL: %w", err))
+ }
default:
err = fmt.Errorf("env SESSION_TICKET_TYPE: %w: %q", errors.ErrBadEnumValue, typ)
return append(res, err)
}
- res = append(
- res,
- validate.NotEmpty("env SESSION_TICKET_API_KEY", envs.SessionTicketAPIKey),
- validate.NotEmpty("env SESSION_TICKET_CACHE_PATH", envs.SessionTicketCachePath),
- validate.NotEmpty("env SESSION_TICKET_INDEX_NAME", envs.SessionTicketIndexName),
- )
+ return res
+}
- if err = validate.NotNil("env SESSION_TICKET_URL", envs.SessionTicketURL); err != nil {
- res = append(res, err)
- } else if err = urlutil.ValidateGRPCURL(&envs.SessionTicketURL.URL); err != nil {
- res = append(res, fmt.Errorf("env SESSION_TICKET_URL: %w", err))
+// validateStandardAccess appends validation errors to the given errs if
+// environment variables for standard access contain errors.
+func (envs *environment) validateStandardAccess(errs []error) (res []error) {
+ res = errs
+
+ switch typ := envs.StandardAccessType; typ {
+ case standardAccessOff:
+ return res
+ case standardAccessBackend:
+ res = append(
+ res,
+ validate.NotEmpty("env STANDARD_ACCESS_API_KEY", envs.StandardAccessAPIKey),
+ validate.Positive("env STANDARD_ACCESS_REFRESH_INTERVAL", envs.StandardAccessRefreshIvl),
+ validate.Positive("env STANDARD_ACCESS_TIMEOUT", envs.StandardAccessTimeout),
+ )
+
+ if err := validate.NotNil("env STANDARD_ACCESS_URL", envs.StandardAccessURL); err != nil {
+ res = append(res, err)
+ } else if err = urlutil.ValidateGRPCURL(&envs.StandardAccessURL.URL); err != nil {
+ res = append(res, fmt.Errorf("env STANDARD_ACCESS_URL: %w", err))
+ }
+ default:
+ err := fmt.Errorf("env STANDARD_ACCESS_TYPE: %w: %q", errors.ErrBadEnumValue, typ)
+
+ return append(res, err)
}
return res
diff --git a/internal/connlimiter/limiter_test.go b/internal/connlimiter/limiter_test.go
index 8d6ba2f..2b8b089 100644
--- a/internal/connlimiter/limiter_test.go
+++ b/internal/connlimiter/limiter_test.go
@@ -34,20 +34,21 @@ func TestLimiter(t *testing.T) {
Resume: 1,
})
+ // TODO(a.garipov): Add fakenet.NewConn to golibs.
conn := &fakenet.Conn{
OnClose: func() (err error) { return nil },
- OnLocalAddr: func() (laddr net.Addr) { panic("not implemented") },
- OnRead: func(b []byte) (n int, err error) { panic("not implemented") },
+ OnLocalAddr: func() (laddr net.Addr) { panic(testutil.UnexpectedCall()) },
+ OnRead: func(b []byte) (n int, err error) { panic(testutil.UnexpectedCall(b)) },
OnRemoteAddr: func() (addr net.Addr) {
return &net.TCPAddr{
IP: netutil.IPv4Localhost().AsSlice(),
Port: 1234,
}
},
- OnSetDeadline: func(t time.Time) (err error) { panic("not implemented") },
- OnSetReadDeadline: func(t time.Time) (err error) { panic("not implemented") },
- OnSetWriteDeadline: func(t time.Time) (err error) { panic("not implemented") },
- OnWrite: func(b []byte) (n int, err error) { panic("not implemented") },
+ OnSetDeadline: func(t time.Time) (err error) { panic(testutil.UnexpectedCall(t)) },
+ OnSetReadDeadline: func(t time.Time) (err error) { panic(testutil.UnexpectedCall(t)) },
+ OnSetWriteDeadline: func(t time.Time) (err error) { panic(testutil.UnexpectedCall(t)) },
+ OnWrite: func(b []byte) (n int, err error) { panic(testutil.UnexpectedCall(b)) },
}
lsnr := &fakenet.Listener{
diff --git a/internal/connlimiter/listenconfig_test.go b/internal/connlimiter/listenconfig_test.go
index 32f775b..9834b62 100644
--- a/internal/connlimiter/listenconfig_test.go
+++ b/internal/connlimiter/listenconfig_test.go
@@ -10,30 +10,32 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/connlimiter"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/AdguardTeam/golibs/testutil/fakenet"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestListenConfig(t *testing.T) {
+ // TODO(a.garipov): Add fakenet.NewPacketConn to golibs.
pc := &fakenet.PacketConn{
- OnClose: func() (_ error) { panic("not implemented") },
- OnLocalAddr: func() (_ net.Addr) { panic("not implemented") },
- OnReadFrom: func(_ []byte) (_ int, _ net.Addr, _ error) {
- panic("not implemented")
+ OnClose: func() (err error) { panic(testutil.UnexpectedCall()) },
+ OnLocalAddr: func() (laddr net.Addr) { panic(testutil.UnexpectedCall()) },
+ OnReadFrom: func(b []byte) (n int, addr net.Addr, err error) {
+ panic(testutil.UnexpectedCall(b))
},
- OnSetDeadline: func(_ time.Time) (_ error) { panic("not implemented") },
- OnSetReadDeadline: func(_ time.Time) (_ error) { panic("not implemented") },
- OnSetWriteDeadline: func(_ time.Time) (_ error) { panic("not implemented") },
- OnWriteTo: func(_ []byte, _ net.Addr) (_ int, _ error) {
- panic("not implemented")
+ OnSetDeadline: func(t time.Time) (err error) { panic(testutil.UnexpectedCall(t)) },
+ OnSetReadDeadline: func(t time.Time) (err error) { panic(testutil.UnexpectedCall(t)) },
+ OnSetWriteDeadline: func(t time.Time) (err error) { panic(testutil.UnexpectedCall(t)) },
+ OnWriteTo: func(b []byte, addr net.Addr) (n int, err error) {
+ panic(testutil.UnexpectedCall(b, addr))
},
}
lsnr := &fakenet.Listener{
- OnAccept: func() (_ net.Conn, _ error) { panic("not implemented") },
- OnAddr: func() (_ net.Addr) { panic("not implemented") },
- OnClose: func() (_ error) { return nil },
+ OnAccept: func() (c net.Conn, err error) { panic(testutil.UnexpectedCall()) },
+ OnAddr: func() (addr net.Addr) { panic(testutil.UnexpectedCall()) },
+ OnClose: func() (err error) { return nil },
}
c := &agdtest.ListenConfig{
diff --git a/internal/debugsvc/debugsvc.go b/internal/debugsvc/debugsvc.go
index 61d6c24..a593ef6 100644
--- a/internal/debugsvc/debugsvc.go
+++ b/internal/debugsvc/debugsvc.go
@@ -1,4 +1,6 @@
// Package debugsvc contains the debug HTTP API of AdGuard DNS.
+//
+// TODO(a.garipov): Add standard or custom metrics.
package debugsvc
import (
@@ -130,7 +132,7 @@ var _ service.Interface = (*Service)(nil)
//
// TODO(a.garipov): Wait for the services to go online.
//
-// TODO(a.garipov): Use the context for cancelation.
+// TODO(a.garipov): Use the context for cancellation.
func (svc *Service) Start(ctx context.Context) (err error) {
for _, srv := range svc.servers {
go runServer(ctx, svc.logger, srv)
diff --git a/internal/debugsvc/debugsvc_test.go b/internal/debugsvc/debugsvc_test.go
index 1f55e9a..8099753 100644
--- a/internal/debugsvc/debugsvc_test.go
+++ b/internal/debugsvc/debugsvc_test.go
@@ -99,10 +99,10 @@ func TestService_Start(t *testing.T) {
// yet, check for it in periodically.
var resp *http.Response
healthCheckURL := srvURL.JoinPath(debugsvc.PathPatternHealthCheck)
- require.EventuallyWithT(t, func(ct *assert.CollectT) {
+ require.EventuallyWithT(t, func(c *assert.CollectT) {
var getErr error
resp, getErr = client.Get(ctx, healthCheckURL)
- assert.NoError(t, getErr)
+ assert.NoError(c, getErr)
}, testTimeout, testTimeout/10)
body := readRespBody(t, resp)
diff --git a/internal/dnsserver/cache/cache.go b/internal/dnsserver/cache/cache.go
index 9738e17..aa01778 100644
--- a/internal/dnsserver/cache/cache.go
+++ b/internal/dnsserver/cache/cache.go
@@ -24,8 +24,9 @@ import (
//
// TODO(a.garipov): Extract cache logic to golibs.
type Middleware struct {
- logger *slog.Logger
- metrics MetricsListener
+ logger *slog.Logger
+ metrics MetricsListener
+ // TODO(d.kolyshev): Use [agdcache.Default].
cache gcache.Cache
cacheMinTTL time.Duration
overrideTTL bool
diff --git a/internal/dnsserver/dnsserver.go b/internal/dnsserver/dnsserver.go
index 6b301ef..b95520e 100644
--- a/internal/dnsserver/dnsserver.go
+++ b/internal/dnsserver/dnsserver.go
@@ -1,4 +1,4 @@
-// Copyright (C) 2022-2024 AdGuard Software Ltd.
+// Copyright (C) 2022-2025 AdGuard Software Ltd.
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
diff --git a/internal/dnsserver/dnsservertest/handler.go b/internal/dnsserver/dnsservertest/handler.go
index 940afe0..0eedd51 100644
--- a/internal/dnsserver/dnsservertest/handler.go
+++ b/internal/dnsserver/dnsservertest/handler.go
@@ -2,12 +2,12 @@ package dnsservertest
import (
"context"
- "fmt"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
)
@@ -59,8 +59,7 @@ func NewDefaultHandlerWithCount(recordsCount int) (h dnsserver.Handler) {
// NewPanicHandler returns a DNS handler that panics with an error.
func NewPanicHandler() (handler dnsserver.Handler) {
f := func(ctx context.Context, rw dnsserver.ResponseWriter, req *dns.Msg) (err error) {
- // TODO(a.garipov): Add a helper for these kinds of errors to golibs.
- panic(fmt.Errorf("unexpected call to ServeDNS(%v, %v)", rw, req))
+ panic(testutil.UnexpectedCall(ctx, rw, req))
}
return dnsserver.HandlerFunc(f)
diff --git a/internal/dnsserver/doc.go b/internal/dnsserver/doc.go
index 9c39802..cf44e39 100644
--- a/internal/dnsserver/doc.go
+++ b/internal/dnsserver/doc.go
@@ -1,4 +1,4 @@
-// Copyright (C) 2022-2024 AdGuard Software Ltd.
+// Copyright (C) 2022-2025 AdGuard Software Ltd.
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
diff --git a/internal/dnsserver/go.mod b/internal/dnsserver/go.mod
index f53dfe2..1354ec4 100644
--- a/internal/dnsserver/go.mod
+++ b/internal/dnsserver/go.mod
@@ -1,46 +1,42 @@
module github.com/AdguardTeam/AdGuardDNS/internal/dnsserver
-go 1.24.5
+go 1.24.6
require (
- github.com/AdguardTeam/golibs v0.32.15
+ github.com/AdguardTeam/golibs v0.34.0
github.com/ameshkov/dnscrypt/v2 v2.4.0
github.com/ameshkov/dnsstamps v1.0.3
github.com/bluele/gcache v0.0.2
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500
- github.com/miekg/dns v1.1.66
+ github.com/miekg/dns v1.1.68
github.com/panjf2000/ants/v2 v2.11.3
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
- github.com/prometheus/client_golang v1.22.0
- github.com/quic-go/quic-go v0.52.0
- github.com/stretchr/testify v1.10.0
- golang.org/x/net v0.41.0
- golang.org/x/sys v0.33.0
+ github.com/prometheus/client_golang v1.23.0
+ github.com/quic-go/quic-go v0.54.0
+ github.com/stretchr/testify v1.11.1
+ golang.org/x/net v0.43.0
+ golang.org/x/sys v0.35.0
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
- github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+ github.com/kr/text v0.2.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
- github.com/onsi/ginkgo/v2 v2.23.4 // indirect
- github.com/onsi/gomega v1.37.0 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
- github.com/prometheus/common v0.64.0 // indirect
- github.com/prometheus/procfs v0.16.1 // indirect
+ github.com/prometheus/common v0.65.0 // indirect
+ github.com/prometheus/procfs v0.17.0 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
- go.uber.org/automaxprocs v1.6.0 // indirect
- go.uber.org/mock v0.5.2 // indirect
- golang.org/x/crypto v0.39.0 // indirect
- golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
- golang.org/x/mod v0.25.0 // indirect
- golang.org/x/sync v0.15.0 // indirect
- golang.org/x/text v0.26.0 // indirect
- golang.org/x/tools v0.34.0 // indirect
- google.golang.org/protobuf v1.36.6 // indirect
+ go.uber.org/mock v0.6.0 // indirect
+ golang.org/x/crypto v0.41.0 // indirect
+ golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
+ golang.org/x/mod v0.27.0 // indirect
+ golang.org/x/sync v0.16.0 // indirect
+ golang.org/x/text v0.28.0 // indirect
+ golang.org/x/tools v0.36.0 // indirect
+ google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/internal/dnsserver/go.sum b/internal/dnsserver/go.sum
index caae2e1..b2b555d 100644
--- a/internal/dnsserver/go.sum
+++ b/internal/dnsserver/go.sum
@@ -1,5 +1,5 @@
-github.com/AdguardTeam/golibs v0.32.15 h1:arDRDWiZCH3g5Onr8AqMnOHhaOppNoBpgC3DNhmeDeA=
-github.com/AdguardTeam/golibs v0.32.15/go.mod h1:G9CzUOzx87J+2u+eClJrrwWD7lMbROvuUnT8uvDUzIA=
+github.com/AdguardTeam/golibs v0.34.0 h1:JQK024DkTYxE7vsPVsYsoyDHW/53Nun7OYb9qscniK8=
+github.com/AdguardTeam/golibs v0.34.0/go.mod h1:K4C2EbfSEM1zY5YXoti9SfbTAHN/kIX97LpDtCwORrM=
github.com/ameshkov/dnscrypt/v2 v2.4.0 h1:if6ZG2cuQmcP2TwSY+D0+8+xbPfoatufGlOQTMNkI9o=
github.com/ameshkov/dnscrypt/v2 v2.4.0/go.mod h1:WpEFV2uhebXb8Jhes/5/fSdpmhGV8TL22RDaeWwV6hI=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
@@ -12,76 +12,65 @@ github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 h1:6lhrsTEnloDPXye
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
-github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
-github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
-github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18=
-github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
-github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
+github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
+github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
-github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
-github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
-github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg=
github.com/panjf2000/ants/v2 v2.11.3/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible h1:IWzUvJ72xMjmrjR9q3H1PF+jwdN0uNQiR2t1BLNalyo=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
-github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
-github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
-github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
+github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
-github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4=
-github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
-github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
-github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
+github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
+github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
+github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
+github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
-github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
-github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
+github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
+github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
-go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
-go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
-go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
-golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
-golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
-golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
-golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
-golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
-golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
-golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
-golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
-golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
-golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
-golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
-golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
-golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
-google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
-google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
+go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
+golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
+golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
+golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
+golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
+golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
+golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
+golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
+golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
+golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
+golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
+golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
+golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
+golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
+google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
+google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/internal/dnsserver/netext/listenconfig_unix_test.go b/internal/dnsserver/netext/listenconfig_unix_test.go
index d9e3155..3e8cc16 100644
--- a/internal/dnsserver/netext/listenconfig_unix_test.go
+++ b/internal/dnsserver/netext/listenconfig_unix_test.go
@@ -9,6 +9,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/netext"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/sys/unix"
@@ -18,6 +19,7 @@ func TestDefaultListenConfigWithOOB(t *testing.T) {
lc := netext.DefaultListenConfigWithOOB(nil)
require.NotNil(t, lc)
+ // TODO(a.garipov): Move to golibs.
type syscallConner interface {
SyscallConn() (c syscall.RawConn, err error)
}
@@ -26,9 +28,10 @@ func TestDefaultListenConfigWithOOB(t *testing.T) {
c, err := lc.ListenPacket(context.Background(), "udp4", "127.0.0.1:0")
require.NoError(t, err)
require.NotNil(t, c)
- require.Implements(t, (*syscallConner)(nil), c)
- sc, err := c.(syscallConner).SyscallConn()
+ scConner := testutil.RequireTypeAssert[syscallConner](t, c)
+
+ sc, err := scConner.SyscallConn()
require.NoError(t, err)
err = sc.Control(func(fd uintptr) {
@@ -51,9 +54,10 @@ func TestDefaultListenConfigWithOOB(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, c)
- require.Implements(t, (*syscallConner)(nil), c)
- sc, err := c.(syscallConner).SyscallConn()
+ scConner := testutil.RequireTypeAssert[syscallConner](t, c)
+
+ sc, err := scConner.SyscallConn()
require.NoError(t, err)
err = sc.Control(func(fd uintptr) {
@@ -86,9 +90,10 @@ func TestDefaultListenConfigWithSO(t *testing.T) {
c, err := lc.ListenPacket(context.Background(), "udp4", "127.0.0.1:0")
require.NoError(t, err)
require.NotNil(t, c)
- require.Implements(t, (*syscallConner)(nil), c)
- sc, err := c.(syscallConner).SyscallConn()
+ scConner := testutil.RequireTypeAssert[syscallConner](t, c)
+
+ sc, err := scConner.SyscallConn()
require.NoError(t, err)
err = sc.Control(func(fd uintptr) {
@@ -119,9 +124,10 @@ func TestDefaultListenConfigWithSO(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, c)
- require.Implements(t, (*syscallConner)(nil), c)
- sc, err := c.(syscallConner).SyscallConn()
+ scConner := testutil.RequireTypeAssert[syscallConner](t, c)
+
+ sc, err := scConner.SyscallConn()
require.NoError(t, err)
err = sc.Control(func(fd uintptr) {
diff --git a/internal/dnsserver/serverhttps_test.go b/internal/dnsserver/serverhttps_test.go
index bf7f766..4911937 100644
--- a/internal/dnsserver/serverhttps_test.go
+++ b/internal/dnsserver/serverhttps_test.go
@@ -527,7 +527,7 @@ func createDoH3Client(
_ string,
tlsCfg *tls.Config,
cfg *quic.Config,
- ) (c quic.EarlyConnection, e error) {
+ ) (c *quic.Conn, e error) {
return quic.DialAddrEarly(ctx, httpsAddr.String(), tlsCfg, cfg)
},
QUICConfig: quicConfig,
diff --git a/internal/dnsserver/serverquic.go b/internal/dnsserver/serverquic.go
index 3f7d4ef..c814ef1 100644
--- a/internal/dnsserver/serverquic.go
+++ b/internal/dnsserver/serverquic.go
@@ -316,7 +316,7 @@ func (s *ServerQUIC) acceptQUICConn(
// decremented.
func (s *ServerQUIC) serveQUICConnAsync(
ctx context.Context,
- conn quic.Connection,
+ conn *quic.Conn,
connWg *sync.WaitGroup,
) {
defer connWg.Done()
@@ -331,7 +331,7 @@ func (s *ServerQUIC) serveQUICConnAsync(
// serveQUICConn handles a new QUIC connection. It waits for new streams and
// passes them to serveQUICStream.
-func (s *ServerQUIC) serveQUICConn(ctx context.Context, conn quic.Connection) (err error) {
+func (s *ServerQUIC) serveQUICConn(ctx context.Context, conn *quic.Conn) (err error) {
streamWg := &sync.WaitGroup{}
defer func() {
// Wait until all streams are processed.
@@ -347,7 +347,7 @@ func (s *ServerQUIC) serveQUICConn(ctx context.Context, conn quic.Connection) (e
// design specifies that for each subsequent query on a QUIC connection
// the client MUST select the next available client-initiated
// bidirectional stream.
- var stream quic.Stream
+ var stream *quic.Stream
acceptCtx, cancel := context.WithDeadline(ctx, time.Now().Add(maxQUICIdleTimeout))
// For some reason AcceptStream below seems to get stuck even when
@@ -403,8 +403,8 @@ func (s *ServerQUIC) serveQUICConn(ctx context.Context, conn quic.Connection) (e
// be decremented.
func (s *ServerQUIC) serveQUICStreamAsync(
ctx context.Context,
- stream quic.Stream,
- conn quic.Connection,
+ stream *quic.Stream,
+ conn *quic.Conn,
wg *sync.WaitGroup,
) {
defer wg.Done()
@@ -421,8 +421,8 @@ func (s *ServerQUIC) serveQUICStreamAsync(
// and writes back the responses.
func (s *ServerQUIC) serveQUICStream(
ctx context.Context,
- stream quic.Stream,
- conn quic.Connection,
+ stream *quic.Stream,
+ conn *quic.Conn,
) (err error) {
// The server MUST send the response on the same stream, and MUST indicate
// through the STREAM FIN mechanism that no further data will be sent on
@@ -486,7 +486,7 @@ func (s *ServerQUIC) serveQUICStream(
// if anything went wrong.
func (s *ServerQUIC) readQUICMsg(
ctx context.Context,
- stream quic.Stream,
+ stream *quic.Stream,
) (m *dns.Msg, err error) {
bufPtr := s.reqPool.Get()
defer s.reqPool.Put(bufPtr)
@@ -607,7 +607,7 @@ func isExpectedQUICErr(err error) (ok bool) {
}
// Catch quic-go's IdleTimeoutError. This error is returned from
- // quic.Connection.AcceptStream calls and this is an expected outcome,
+ // *quic.Conn.AcceptStream calls and this is an expected outcome,
// happens all the time with different QUIC clients.
var qErr *quic.IdleTimeoutError
if errors.As(err, &qErr) {
@@ -690,7 +690,7 @@ func validQUICMsg(req *dns.Msg) (ok bool) {
// code and logs if it fails to close the connection.
func (s *ServerQUIC) closeQUICConn(
ctx context.Context,
- conn quic.Connection,
+ conn *quic.Conn,
code quic.ApplicationErrorCode,
) {
err := conn.CloseWithError(code, "")
@@ -725,6 +725,7 @@ func newServerQUICConfig(
// quicAddrValidator is a helper struct that holds a small LRU cache of
// addresses for which we do not require address validation.
type quicAddrValidator struct {
+ // TODO(d.kolyshev): Use [agdcache.Default].
cache gcache.Cache
metrics MetricsListener
ttl time.Duration
diff --git a/internal/dnsserver/serverquic_test.go b/internal/dnsserver/serverquic_test.go
index e04e4ce..49c6ca2 100644
--- a/internal/dnsserver/serverquic_test.go
+++ b/internal/dnsserver/serverquic_test.go
@@ -86,7 +86,7 @@ func TestServerQUIC_integration_ENDS0Padding(t *testing.T) {
conn, err := quic.DialAddr(context.Background(), addr.String(), tlsConfig, nil)
require.NoError(t, err)
- defer func(conn quic.Connection, code quic.ApplicationErrorCode, s string) {
+ defer func(conn *quic.Conn, code quic.ApplicationErrorCode, s string) {
_ = conn.CloseWithError(code, s)
}(conn, 0, "")
@@ -196,7 +196,7 @@ func testQUICExchange(
return conn.CloseWithError(0, "")
})
- defer func(conn quic.Connection, code quic.ApplicationErrorCode, s string) {
+ defer func(conn *quic.Conn, code quic.ApplicationErrorCode, s string) {
_ = conn.CloseWithError(code, s)
}(conn, 0, "")
@@ -210,7 +210,7 @@ func testQUICExchange(
// sendQUICMessage is a test helper that sends a test QUIC message.
func sendQUICMessage(
- conn quic.Connection,
+ conn *quic.Conn,
req *dns.Msg,
) (resp *dns.Msg, err error) {
stream, err := conn.OpenStreamSync(context.Background())
@@ -266,7 +266,7 @@ func sendQUICMessage(
// test's t.
func requireSendQUICMessage(
t testing.TB,
- conn quic.Connection,
+ conn *quic.Conn,
req *dns.Msg,
) (resp *dns.Msg) {
t.Helper()
@@ -279,7 +279,7 @@ func requireSendQUICMessage(
// writeQUICStream writes buf to the specified QUIC stream in chunks. This way
// it is possible to test how the server deals with chunked DNS messages.
-func writeQUICStream(buf []byte, stream quic.Stream) (err error) {
+func writeQUICStream(buf []byte, stream *quic.Stream) (err error) {
// Send the DNS query to the stream and split it into chunks of up
// to 400 bytes. 400 is an arbitrary chosen value.
chunkSize := 400
diff --git a/internal/dnssvc/context.go b/internal/dnssvc/context.go
index 05f9171..a8ca6f8 100644
--- a/internal/dnssvc/context.go
+++ b/internal/dnssvc/context.go
@@ -26,7 +26,7 @@ var _ contextutil.Constructor = (*contextConstructor)(nil)
// New implements the [contextutil.Constructor] interface for
// *contextConstructor. It returns a context with a new [agd.RequestID] as well
-// as its timeout and the corresponding cancelation function.
+// as its timeout and the corresponding cancellation function.
func (c *contextConstructor) New(
parent context.Context,
) (ctx context.Context, cancel context.CancelFunc) {
diff --git a/internal/dnssvc/dnssvc_test.go b/internal/dnssvc/dnssvc_test.go
index 687b34b..41ea323 100644
--- a/internal/dnssvc/dnssvc_test.go
+++ b/internal/dnssvc/dnssvc_test.go
@@ -80,17 +80,21 @@ func (l *testListener) LocalUDPAddr() (addr net.Addr) {
}
// newTestListener returns a *testListener all of methods of which panic with
-// a "not implemented" message.
+// an unexpected call message.
func newTestListener() (tl *testListener) {
return &testListener{
- onName: func() (_ string) { panic("not implemented") },
- onProto: func() (_ dnsserver.Protocol) { panic("not implemented") },
- onNetwork: func() (_ dnsserver.Network) { panic("not implemented") },
- onAddr: func() (_ string) { panic("not implemented") },
- onStart: func(_ context.Context) (err error) { panic("not implemented") },
- onShutdown: func(_ context.Context) (err error) { panic("not implemented") },
- onLocalUDPAddr: func() (_ net.Addr) { panic("not implemented") },
- onLocalTCPAddr: func() (_ net.Addr) { panic("not implemented") },
+ onName: func() (name string) { panic(testutil.UnexpectedCall()) },
+ onProto: func() (proto dnsserver.Protocol) { panic(testutil.UnexpectedCall()) },
+ onNetwork: func() (n dnsserver.Network) { panic(testutil.UnexpectedCall()) },
+ onAddr: func() (addr string) { panic(testutil.UnexpectedCall()) },
+ onStart: func(ctx context.Context) (err error) {
+ panic(testutil.UnexpectedCall(ctx))
+ },
+ onShutdown: func(ctx context.Context) (err error) {
+ panic(testutil.UnexpectedCall(ctx))
+ },
+ onLocalUDPAddr: func() (addr net.Addr) { panic(testutil.UnexpectedCall()) },
+ onLocalTCPAddr: func() (addr net.Addr) { panic(testutil.UnexpectedCall()) },
}
}
diff --git a/internal/dnssvc/handler.go b/internal/dnssvc/handler.go
index 8c45634..d52ad98 100644
--- a/internal/dnssvc/handler.go
+++ b/internal/dnssvc/handler.go
@@ -17,6 +17,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/ecscache"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/golibs/timeutil"
// TODO(e.burkov): Move registering of the metrics to another package to
// avoid dependency on the metrics package.
@@ -123,6 +124,7 @@ func wrapPreUpstreamMw(
cacheMw := ecscache.NewMiddleware(&ecscache.MiddlewareConfig{
Metrics: mtrc,
+ Clock: timeutil.SystemClock{},
Cloner: c.Cloner,
Logger: c.BaseLogger.With(slogutil.KeyPrefix, "ecscache"),
CacheManager: c.CacheManager,
diff --git a/internal/dnssvc/handler_test.go b/internal/dnssvc/handler_test.go
index 2594ab8..0f024a0 100644
--- a/internal/dnssvc/handler_test.go
+++ b/internal/dnssvc/handler_test.go
@@ -26,36 +26,38 @@ func TestNewHandlers(t *testing.T) {
t.Parallel()
accessMgr := &agdtest.AccessManager{
- OnIsBlockedHost: func(host string, qt uint16) (blocked bool) { panic("not implemented") },
- OnIsBlockedIP: func(ip netip.Addr) (blocked bool) { panic("not implemented") },
+ OnIsBlockedHost: func(host string, qt uint16) (blocked bool) {
+ panic(testutil.UnexpectedCall(host, qt))
+ },
+ OnIsBlockedIP: func(ip netip.Addr) (blocked bool) { panic(testutil.UnexpectedCall(ip)) },
}
billStat := &agdtest.BillStatRecorder{
OnRecord: func(
- _ context.Context,
- _ agd.DeviceID,
- _ geoip.Country,
- _ geoip.ASN,
- _ time.Time,
- _ agd.Protocol,
+ ctx context.Context,
+ id agd.DeviceID,
+ ctry geoip.Country,
+ asn geoip.ASN,
+ start time.Time,
+ proto agd.Protocol,
) {
- panic("not implemented")
+ panic(testutil.UnexpectedCall(ctx, id, ctry, asn, start, proto))
},
}
dnsCk := &agdtest.DNSCheck{
OnCheck: func(
- _ context.Context,
- _ *dns.Msg,
- _ *agd.RequestInfo,
+ ctx context.Context,
+ req *dns.Msg,
+ ri *agd.RequestInfo,
) (resp *dns.Msg, err error) {
- panic("not implemented")
+ panic(testutil.UnexpectedCall(ctx, req, ri))
},
}
dnsDB := &agdtest.DNSDB{
- OnRecord: func(_ context.Context, _ *dns.Msg, _ *agd.RequestInfo) {
- panic("not implemented")
+ OnRecord: func(ctx context.Context, resp *dns.Msg, ri *agd.RequestInfo) {
+ panic(testutil.UnexpectedCall(ctx, resp, ri))
},
}
@@ -76,30 +78,30 @@ func TestNewHandlers(t *testing.T) {
}
fltStrg := &agdtest.FilterStorage{
- OnForConfig: func(_ context.Context, _ filter.Config) (f filter.Interface) {
- panic("not implemented")
+ OnForConfig: func(ctx context.Context, c filter.Config) (f filter.Interface) {
+ panic(testutil.UnexpectedCall(ctx, c))
},
- OnHasListID: func(_ filter.ID) (ok bool) { panic("not implemented") },
+ OnHasListID: func(id filter.ID) (ok bool) { panic(testutil.UnexpectedCall(id)) },
}
hashMatcher := &agdtest.HashMatcher{
OnMatchByPrefix: func(
- _ context.Context,
- _ string,
+ ctx context.Context,
+ host string,
) (hashes []string, matched bool, err error) {
- panic("not implemented")
+ panic(testutil.UnexpectedCall(ctx, host))
},
}
queryLog := &agdtest.QueryLog{
- OnWrite: func(_ context.Context, _ *querylog.Entry) (err error) {
- panic("not implemented")
+ OnWrite: func(ctx context.Context, e *querylog.Entry) (err error) {
+ panic(testutil.UnexpectedCall(ctx, e))
},
}
ruleStat := &agdtest.RuleStat{
- OnCollect: func(_ context.Context, _ filter.ID, _ filter.RuleText) {
- panic("not implemented")
+ OnCollect: func(ctx context.Context, id filter.ID, text filter.RuleText) {
+ panic(testutil.UnexpectedCall(ctx, id, text))
},
}
diff --git a/internal/dnssvc/integration_test.go b/internal/dnssvc/integration_test.go
index 9e6b2bd..91f8e43 100644
--- a/internal/dnssvc/integration_test.go
+++ b/internal/dnssvc/integration_test.go
@@ -136,7 +136,7 @@ func newTestService(
OnForConfig: func(_ context.Context, _ filter.Config) (f filter.Interface) {
return flt
},
- OnHasListID: func(_ filter.ID) (ok bool) { panic("not implemented") },
+ OnHasListID: func(id filter.ID) (ok bool) { panic(testutil.UnexpectedCall(id)) },
}
var ql querylog.Interface = &agdtest.QueryLog{
@@ -397,8 +397,8 @@ func TestService_Wrap(t *testing.T) {
Rule: cnameRule,
}, nil
},
- OnFilterResponse: func(_ context.Context, _ *filter.Response) (filter.Result, error) {
- panic("not implemented")
+ OnFilterResponse: func(ctx context.Context, resp *filter.Response) (filter.Result, error) {
+ panic(testutil.UnexpectedCall(ctx, resp))
},
}
diff --git a/internal/dnssvc/internal/devicefinder/devicefinder_test.go b/internal/dnssvc/internal/devicefinder/devicefinder_test.go
index 365fe00..54716ba 100644
--- a/internal/dnssvc/internal/devicefinder/devicefinder_test.go
+++ b/internal/dnssvc/internal/devicefinder/devicefinder_test.go
@@ -265,9 +265,9 @@ func assertEqualResult(tb testing.TB, want, got agd.DeviceResult) {
}
}
-// newDefault is is a helper for creating the device finders for tests. c may
-// be nil, and all zero-value fields in c are replaced with defaults for tests.
-// The default server is [srvDoH].
+// newDefault is a helper for creating device finders for tests. c may be nil,
+// and all zero-value fields in c are replaced with defaults for tests. The
+// default server is [srvDoH].
func newDefault(tb testing.TB, c *devicefinder.Config) (f *devicefinder.Default) {
tb.Helper()
@@ -303,12 +303,12 @@ func TestDefault_Find_dnscrypt(t *testing.T) {
func BenchmarkDefault(b *testing.B) {
profDB := &agdtest.ProfileDB{
OnCreateAutoDevice: func(
- _ context.Context,
- _ agd.ProfileID,
- _ agd.HumanID,
- _ agd.DeviceType,
+ ctx context.Context,
+ profID agd.ProfileID,
+ humanID agd.HumanID,
+ typ agd.DeviceType,
) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
+ panic(testutil.UnexpectedCall(ctx, profID, humanID, typ))
},
OnProfileByDedicatedIP: func(
diff --git a/internal/dnssvc/internal/mainmw/mainmw_test.go b/internal/dnssvc/internal/mainmw/mainmw_test.go
index 878cfa7..362a0d7 100644
--- a/internal/dnssvc/internal/mainmw/mainmw_test.go
+++ b/internal/dnssvc/internal/mainmw/mainmw_test.go
@@ -69,14 +69,14 @@ func TestMiddleware_Wrap(t *testing.T) {
var (
billStatNotImp = &agdtest.BillStatRecorder{
OnRecord: func(
- _ context.Context,
- _ agd.DeviceID,
- _ geoip.Country,
- _ geoip.ASN,
- _ time.Time,
- _ agd.Protocol,
+ ctx context.Context,
+ id agd.DeviceID,
+ ctry geoip.Country,
+ asn geoip.ASN,
+ start time.Time,
+ proto agd.Protocol,
) {
- panic("not implemented")
+ panic(testutil.UnexpectedCall(ctx, id, ctry, asn, start, proto))
},
}
@@ -114,7 +114,7 @@ func TestMiddleware_Wrap(t *testing.T) {
OnForConfig: func(_ context.Context, _ filter.Config) (f filter.Interface) {
return flt
},
- OnHasListID: func(_ filter.ID) (ok bool) { panic("not implemented") },
+ OnHasListID: func(id filter.ID) (ok bool) { panic(testutil.UnexpectedCall(id)) },
}
geoIP := agdtest.NewGeoIP()
@@ -392,14 +392,14 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
var (
billStatNotImp = &agdtest.BillStatRecorder{
OnRecord: func(
- _ context.Context,
- _ agd.DeviceID,
- _ geoip.Country,
- _ geoip.ASN,
- _ time.Time,
- _ agd.Protocol,
+ ctx context.Context,
+ id agd.DeviceID,
+ ctry geoip.Country,
+ asn geoip.ASN,
+ start time.Time,
+ proto agd.Protocol,
) {
- panic("not implemented")
+ panic(testutil.UnexpectedCall(ctx, id, ctry, asn, start, proto))
},
}
@@ -672,7 +672,7 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
OnForConfig: func(_ context.Context, _ filter.Config) (f filter.Interface) {
return flt
},
- OnHasListID: func(_ filter.ID) (ok bool) { panic("not implemented") },
+ OnHasListID: func(id filter.ID) (ok bool) { panic(testutil.UnexpectedCall(id)) },
}
q := tc.req.Question[0]
diff --git a/internal/ecscache/cache.go b/internal/ecscache/cache.go
index ec2a44f..022527f 100644
--- a/internal/ecscache/cache.go
+++ b/internal/ecscache/cache.go
@@ -2,14 +2,10 @@ package ecscache
import (
"context"
- "encoding/binary"
- "hash/maphash"
"net/netip"
"time"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
- "github.com/AdguardTeam/golibs/mathutil"
"github.com/miekg/dns"
)
@@ -44,12 +40,12 @@ type cacheRequest struct {
// support ECS, isECSDependent is true. cr, cr.req, and cr.subnet must not be
// nil.
func (mw *Middleware) get(
- ctx context.Context,
+ _ context.Context,
req *dns.Msg,
cr *cacheRequest,
) (resp *dns.Msg, isECSDependent bool) {
- key := mw.toCacheKey(cr, false)
- item, ok := mw.itemFromCache(ctx, mw.cache, key, cr)
+ key := newCacheKey(cr, false)
+ item, ok := mw.cache.Get(key)
if ok {
return fromCacheItem(item, mw.cloner, req, cr.reqDO), false
} else if cr.isECSDeclined {
@@ -57,8 +53,8 @@ func (mw *Middleware) get(
}
// Try ECS-aware cache.
- key = mw.toCacheKey(cr, true)
- item, ok = mw.itemFromCache(ctx, mw.ecsCache, key, cr)
+ key = newCacheKey(cr, true)
+ item, ok = mw.ecsCache.Get(key)
if ok {
return fromCacheItem(item, mw.cloner, req, cr.reqDO), true
}
@@ -66,67 +62,6 @@ func (mw *Middleware) get(
return nil, false
}
-// itemFromCache retrieves a DNS message for the given key. cr.host is used to
-// detect key collisions. If there is a key collision, it returns nil and
-// false.
-func (mw *Middleware) itemFromCache(
- ctx context.Context,
- cache agdcache.Interface[uint64, *cacheItem],
- key uint64,
- cr *cacheRequest,
-) (item *cacheItem, ok bool) {
- item, ok = cache.Get(key)
- if !ok {
- return nil, false
- }
-
- // Check for cache key collisions.
- if item.host != cr.host {
- mw.logger.WarnContext(ctx, "cache collision", "item", item, "host", cr.host)
-
- return nil, false
- }
-
- return item, true
-}
-
-// hashSeed is the seed used by all hashes to create hash keys.
-var hashSeed = maphash.MakeSeed()
-
-// toCacheKey returns the appropriate cache key for msg. msg must have one
-// question record. subnet must not be nil.
-func (mw *Middleware) toCacheKey(cr *cacheRequest, respIsECSDependent bool) (key uint64) {
- // Use maphash explicitly instead of using a key structure to reduce
- // allocations and optimize interface conversion up the stack.
- //
- // TODO(a.garipov, e.burkov): Consider just using struct as a key.
- h := &maphash.Hash{}
- h.SetSeed(hashSeed)
-
- _, _ = h.WriteString(cr.host)
-
- // Save on allocations by reusing a buffer.
- var buf [6]byte
- binary.LittleEndian.PutUint16(buf[:2], cr.qType)
- binary.LittleEndian.PutUint16(buf[2:4], cr.qClass)
-
- buf[4] = mathutil.BoolToNumber[byte](cr.reqDO)
-
- addr := cr.subnet.Addr()
- buf[5] = mathutil.BoolToNumber[byte](addr.Is6())
-
- _, _ = h.Write(buf[:])
-
- if respIsECSDependent {
- _, _ = h.Write(addr.AsSlice())
- _ = h.WriteByte(byte(cr.subnet.Bits()))
- } else {
- _ = h.WriteByte(mathutil.BoolToNumber[byte](cr.isECSDeclined))
- }
-
- return h.Sum64()
-}
-
// set saves resp to the cache if it's cacheable. If msg cannot be cached, it
// is ignored.
func (mw *Middleware) set(resp *dns.Msg, cr *cacheRequest, respIsECSDependent bool) {
@@ -146,11 +81,55 @@ func (mw *Middleware) set(resp *dns.Msg, cr *cacheRequest, respIsECSDependent bo
dnsmsg.SetMinTTL(resp, uint32(exp.Seconds()))
}
- key := mw.toCacheKey(cr, respIsECSDependent)
+ key := newCacheKey(cr, respIsECSDependent)
+ cache.SetWithExpire(key, &cacheItem{
+ msg: mw.cloner.Clone(resp),
+ when: mw.clock.Now(),
+ }, exp)
+}
- cachedResp := mw.cloner.Clone(resp)
+// cacheKey represents a key used in the cache.
+type cacheKey struct {
+ // host is a non-FQDN version of a cached hostname.
+ host string
- cache.SetWithExpire(key, toCacheItem(cachedResp, cr.host), exp)
+ // subnet is the network of the country the DNS request came from determined
+ // with GeoIP.
+ subnet netip.Prefix
+
+ // qType is the question type of the DNS request.
+ qType uint16
+
+ // qClass is the class of the DNS request.
+ qClass uint16
+
+ // reqDO is the state of DNSSEC OK bit from the DNS request.
+ reqDO bool
+
+ // isECSDeclined reflects if the client explicitly restricts using its
+ // information in EDNS client subnet option as per RFC 7871.
+ //
+ // See https://datatracker.ietf.org/doc/html/rfc7871#section-7.1.2.
+ isECSDeclined bool
+}
+
+// newCacheKey returns the appropriate cache key for msg. msg must have one
+// question record. cr must not be nil.
+func newCacheKey(cr *cacheRequest, respIsECSDependent bool) (key cacheKey) {
+ key = cacheKey{
+ host: cr.host,
+ qType: cr.qType,
+ qClass: cr.qClass,
+ reqDO: cr.reqDO,
+ }
+
+ if respIsECSDependent {
+ key.subnet = cr.subnet
+ } else {
+ key.isECSDeclined = cr.isECSDeclined
+ }
+
+ return key
}
// cacheItem represents an item that we will store in the cache.
@@ -160,19 +139,6 @@ type cacheItem struct {
// msg is the cached DNS message.
msg *dns.Msg
-
- // host is the cached normalized hostname for later cache key collision
- // checks.
- host string
-}
-
-// toCacheItem creates a *cacheItem from a DNS message.
-func toCacheItem(resp *dns.Msg, host string) (item *cacheItem) {
- return &cacheItem{
- msg: resp,
- when: time.Now(),
- host: host,
- }
}
// fromCacheItem creates a response from the cached item. item, cloner, and req
diff --git a/internal/ecscache/cache_internal_test.go b/internal/ecscache/cache_internal_test.go
index 0fac69b..8e8e048 100644
--- a/internal/ecscache/cache_internal_test.go
+++ b/internal/ecscache/cache_internal_test.go
@@ -6,26 +6,35 @@ import (
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/golibs/timeutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
)
-func BenchmarkMiddleware_Get(b *testing.B) {
- mw := &Middleware{
- cache: agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
- Count: 10,
- }),
- ecsCache: agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
- Count: 10,
- }),
- }
+func BenchmarkMiddleware(b *testing.B) {
+ mw := NewMiddleware(&MiddlewareConfig{
+ Metrics: EmptyMetrics{},
+ Clock: timeutil.SystemClock{},
+ Cloner: agdtest.NewCloner(),
+ Logger: slogutil.NewDiscardLogger(),
+ CacheManager: agdcache.EmptyManager{},
+ GeoIP: agdtest.NewGeoIP(),
+ NoECSCount: 100,
+ ECSCount: 100,
+ })
const (
host = "benchmark.example"
fqdn = host + "."
+
+ defaultTTL uint32 = 3600
)
+ reqAddr := netip.MustParseAddr("1.2.3.4")
+
req := dnsservertest.NewReq(fqdn, dns.TypeA, dns.ClassINET)
cr := &cacheRequest{
host: host,
@@ -34,6 +43,9 @@ func BenchmarkMiddleware_Get(b *testing.B) {
qClass: dns.ClassINET,
reqDO: true,
}
+ resp := dnsservertest.NewResp(dns.RcodeSuccess, req, dnsservertest.SectionAnswer{
+ dnsservertest.NewA(host, defaultTTL, reqAddr),
+ })
ctx := context.Background()
@@ -41,16 +53,18 @@ func BenchmarkMiddleware_Get(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
+ mw.set(resp, cr, true)
+
msg, _ = mw.get(ctx, req, cr)
}
- assert.Nil(b, msg)
+ assert.NotNil(b, msg)
// Most recent results:
//
// goos: darwin
- // goarch: amd64
+ // goarch: arm64
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/ecscache
- // cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
- // BenchmarkMiddleware_Get-12 5855624 195.1 ns/op 16 B/op 2 allocs/op
+ // cpu: Apple M1 Pro
+ // BenchmarkMiddleware_Get-8 1647064 726.8 ns/op 568 B/op 12 allocs/op
}
diff --git a/internal/ecscache/ecsblocklist.go b/internal/ecscache/ecsblocklist.go
index ea6595f..4ebc3b8 100644
--- a/internal/ecscache/ecsblocklist.go
+++ b/internal/ecscache/ecsblocklist.go
@@ -7,103 +7,367 @@ import "github.com/AdguardTeam/golibs/container"
// FakeECSFQDNs contains all domains that indicate ECS support, but in fact
// don't have one.
var FakeECSFQDNs = container.NewMapSet(
- "01-cdn.videodb.cloud.",
"0272ac85-5199-4024-a555-397c3d825d95.prmutv.co.",
"0cf.io.",
"0cf17917-395b-4f25-91cc-db3bdd6044b0.prmutv.co.",
"1.eu.ntp.huan.tv.",
+ "1024sj.com.",
"103.chtsite.com.",
- "11-alarm-mop.meshare.com.",
- "11222.cn.",
- "11ipip.com.",
"12-alarm-mop.meshare.com.",
- "123ipip.icu.",
"126.com.",
"126.net.",
"127.net.",
"13-alarm-mop.meshare.com.",
- "1337.abcvg.info.",
- "14-alarm-mop.meshare.com.",
+ "15969-ipv4v6e.clump.dprodmgd104.aa-rt.sharepoint.com.",
"163.com.",
"163jiasu.com.",
"163yun.com.",
+ "166.net.",
"1688.com.",
- "178448.com.",
- "189cube.com.",
"18ea70d2d9a945cfb97d818ba71817dc.pacloudflare.com.",
"1adr.com.",
"1ato.com.",
"1osb.com.",
"2.401402081.west-gcloud.codm.activision.com.",
- "2.497948935.codmsg.gcloudcs.com.",
"2.realtime.services.box.net.",
- "2345.cc.",
- "289d106c-df24-4cd9-a9fa-753e928c23ad.prmutv.co.",
+ "21cn.com.",
+ "2591j46p8g-3.algolianet.com.",
"2acdb9b66bb242618283aadb21ede6c1.pacloudflare.com.",
+ "2e4b93d1-a8ae-4a89-8885-6109135ac0de.prmutv.co.",
"2gis.ru.",
"2owo1y.n0qq3z.com.",
- "31gamestudio.com.",
- "33ipip.top.",
+ "340.ncsis.gov.",
"345ddz.com.",
"360safe.com.",
"3a6b0682-f3e1-4576-a706-5eb4101b9cc3.prmutv.co.",
"3d2fb0bd-52fc-4b75-aaf5-2d436c172540.prmutv.co.",
- "3gcj.com.",
+ "3dmxku.com.",
"4.401402081.west-gcloud.codm.activision.com.",
- "4.497948935.codmsg.gcloudcs.com.",
"4.adsco.re.",
"401402081.west-gcloud.codm.activision.com.",
- "497948935.codmsg.gcloudcs.com.",
- "500audio.com.",
- "51jiaoxi.com.",
+ "4513764478418944-content.customer.pendo.io.",
+ "4b32bb64ce554875ae3f8836479c89d4.pacloudflare.com.",
+ "4dmax.space.",
+ "507b28fb-2ef1-4c34-8bda-ba32030bb199.prmutv.co.",
"520.jp.",
- "5f876161-9740-4cc8-9b64-4585990b2690.prmutv.co.",
- "5k6ph8.qz94.com.",
- "5lgx5w5cgs9pyyu8u.ay.delivery.",
+ "5d79bce7-5d2b-427e-a6c4-b89b6c7bf048.prmutv.co.",
"6.401402081.west-gcloud.codm.activision.com.",
"6093eccf-6734-4877-ac8b-83d6d0e27b46.prmutv.co.",
- "64.adsco.re.",
- "64ypd.6w9hps.com.",
- "65-66.com.",
"66yahoo.com.",
+ "68547f8f-2fd8-4ff3-9b63-51e86e2edee8.prmutv.co.",
"7c7b02d4bc3d48dd81a7c7738d4de1ab.pacloudflare.com.",
- "88a66e5c-8fe8-48af-9c6c-3ec3f4983aad.prmutv.co.",
"8x8.com.cdn.cloudflare.net.",
+ "920.ncsis.gov.",
"998law.com.",
- "9game.cn.",
- "a-ap.1rx.io.",
+ "9pumbooc7hqedhjmeavbpmp5ik9u0ngr-data.customer.pendo.io.",
"a-api.anthropic.com.",
"a-cdn.anthropic.com.",
"a-m-p.xyz.",
+ "a-yz.com.",
"a.appbaqend.com.",
"a.audrte.com.",
+ "a.bringads.ru.",
+ "a.getepic.com.",
+ "a.myisolved.com.",
"a.nel.cloudflare.com.",
"a.nitropay.com.",
- "a.quora.com.",
"a.simplemdm.com.",
- "a.utraff.com.",
- "a.yximgs.com.cdn.dnsv1.com.",
- "a40.usablenet.com.",
+ "a048.casalemedia.com.",
+ "a087.casalemedia.com.",
+ "a1477.casalemedia.com.",
+ "a1478.casalemedia.com.",
+ "a1479.casalemedia.com.",
+ "a1518.casalemedia.com.",
+ "a1523.casalemedia.com.",
+ "a1527.casalemedia.com.",
+ "a1537.casalemedia.com.",
+ "a1544.casalemedia.com.",
+ "a1549.casalemedia.com.",
+ "a1556.casalemedia.com.",
+ "a1577.casalemedia.com.",
+ "a1623.casalemedia.com.",
+ "a1635.casalemedia.com.",
+ "a1637.casalemedia.com.",
+ "a1667.casalemedia.com.",
+ "a1678.casalemedia.com.",
+ "a1681.casalemedia.com.",
+ "a1684.casalemedia.com.",
+ "a1687.casalemedia.com.",
+ "a1688.casalemedia.com.",
+ "a1689.casalemedia.com.",
+ "a1690.casalemedia.com.",
+ "a1691.casalemedia.com.",
+ "a1692.casalemedia.com.",
+ "a22711502979.cdn.optimizely.com.",
+ "a252.casalemedia.com.",
+ "a25758810713.cdn.optimizely.com.",
+ "a2806.casalemedia.com.",
+ "a2811.casalemedia.com.",
+ "a2828.casalemedia.com.",
+ "a2836.casalemedia.com.",
+ "a2839.casalemedia.com.",
+ "a2849.casalemedia.com.",
+ "a2850.casalemedia.com.",
+ "a2854.casalemedia.com.",
+ "a2859.casalemedia.com.",
+ "a2869.casalemedia.com.",
+ "a2884.casalemedia.com.",
+ "a2898.casalemedia.com.",
+ "a2900.casalemedia.com.",
+ "a2901.casalemedia.com.",
+ "a2916.casalemedia.com.",
+ "a2928.casalemedia.com.",
+ "a2935.casalemedia.com.",
+ "a2941.casalemedia.com.",
+ "a2944.casalemedia.com.",
+ "a2a5c7f9-3fa0-4182-889a-15aa61acf59b.prmutv.co.",
+ "a364.casalemedia.com.",
+ "a366.casalemedia.com.",
+ "a375.casalemedia.com.",
+ "a389.casalemedia.com.",
+ "a392.casalemedia.com.",
+ "a410.casalemedia.com.",
+ "a416.casalemedia.com.",
+ "a4621041136.cdn.optimizely.com.",
+ "a5551.casalemedia.com.",
+ "a5557.casalemedia.com.",
+ "a5558.casalemedia.com.",
+ "a5560.casalemedia.com.",
+ "a5561.casalemedia.com.",
+ "a5562.casalemedia.com.",
+ "a5563.casalemedia.com.",
+ "a5564.casalemedia.com.",
+ "a5565.casalemedia.com.",
+ "a5567.casalemedia.com.",
+ "a5568.casalemedia.com.",
+ "a5569.casalemedia.com.",
+ "a5570.casalemedia.com.",
+ "a5572.casalemedia.com.",
+ "a5573.casalemedia.com.",
+ "a5574.casalemedia.com.",
+ "a5575.casalemedia.com.",
+ "a5576.casalemedia.com.",
+ "a5578.casalemedia.com.",
+ "a5579.casalemedia.com.",
+ "a5581.casalemedia.com.",
+ "a5582.casalemedia.com.",
+ "a5584.casalemedia.com.",
+ "a5585.casalemedia.com.",
+ "a5586.casalemedia.com.",
+ "a5587.casalemedia.com.",
+ "a5588.casalemedia.com.",
+ "a5589.casalemedia.com.",
+ "a5590.casalemedia.com.",
+ "a5591.casalemedia.com.",
+ "a5593.casalemedia.com.",
+ "a5594.casalemedia.com.",
+ "a5595.casalemedia.com.",
+ "a5596.casalemedia.com.",
+ "a5599.casalemedia.com.",
+ "a55a84b3-9632-4869-b625-3d8ef43ed18d.prmutv.co.",
+ "a5600.casalemedia.com.",
+ "a5601.casalemedia.com.",
+ "a5602.casalemedia.com.",
+ "a5603.casalemedia.com.",
+ "a5604.casalemedia.com.",
+ "a5605.casalemedia.com.",
+ "a5606.casalemedia.com.",
+ "a5607.casalemedia.com.",
+ "a5608.casalemedia.com.",
+ "a5609.casalemedia.com.",
+ "a5610.casalemedia.com.",
+ "a5611.casalemedia.com.",
+ "a5612.casalemedia.com.",
+ "a5613.casalemedia.com.",
+ "a5614.casalemedia.com.",
+ "a5615.casalemedia.com.",
+ "a5616.casalemedia.com.",
+ "a5617.casalemedia.com.",
+ "a5618.casalemedia.com.",
+ "a5619.casalemedia.com.",
+ "a5620.casalemedia.com.",
+ "a5621.casalemedia.com.",
+ "a5622.casalemedia.com.",
+ "a5623.casalemedia.com.",
+ "a5624.casalemedia.com.",
+ "a5626.casalemedia.com.",
+ "a5627.casalemedia.com.",
+ "a5628.casalemedia.com.",
+ "a5630.casalemedia.com.",
+ "a5631.casalemedia.com.",
+ "a5632.casalemedia.com.",
+ "a5633.casalemedia.com.",
+ "a5634.casalemedia.com.",
+ "a5635.casalemedia.com.",
+ "a5636.casalemedia.com.",
+ "a5637.casalemedia.com.",
+ "a5638.casalemedia.com.",
+ "a5639.casalemedia.com.",
+ "a5640.casalemedia.com.",
+ "a5671.casalemedia.com.",
+ "a5672.casalemedia.com.",
+ "a5673.casalemedia.com.",
+ "a5675.casalemedia.com.",
+ "a5676.casalemedia.com.",
+ "a5677.casalemedia.com.",
+ "a5679.casalemedia.com.",
+ "a568.casalemedia.com.",
+ "a5680.casalemedia.com.",
+ "a5681.casalemedia.com.",
+ "a5682.casalemedia.com.",
+ "a5683.casalemedia.com.",
+ "a5684.casalemedia.com.",
+ "a5685.casalemedia.com.",
+ "a5688.casalemedia.com.",
+ "a5689.casalemedia.com.",
+ "a5690.casalemedia.com.",
+ "a5692.casalemedia.com.",
+ "a5693.casalemedia.com.",
+ "a5694.casalemedia.com.",
+ "a5695.casalemedia.com.",
+ "a5696.casalemedia.com.",
+ "a5697.casalemedia.com.",
+ "a5698.casalemedia.com.",
+ "a5699.casalemedia.com.",
+ "a5700.casalemedia.com.",
+ "a5701.casalemedia.com.",
+ "a5702.casalemedia.com.",
+ "a5704.casalemedia.com.",
+ "a5705.casalemedia.com.",
+ "a5706.casalemedia.com.",
+ "a5707.casalemedia.com.",
+ "a5708.casalemedia.com.",
+ "a5709.casalemedia.com.",
+ "a5710.casalemedia.com.",
+ "a572.casalemedia.com.",
+ "a5731.casalemedia.com.",
+ "a5732.casalemedia.com.",
+ "a5733.casalemedia.com.",
+ "a5735.casalemedia.com.",
+ "a5736.casalemedia.com.",
+ "a5737.casalemedia.com.",
+ "a5738.casalemedia.com.",
+ "a5739.casalemedia.com.",
+ "a5740.casalemedia.com.",
+ "a5741.casalemedia.com.",
+ "a5742.casalemedia.com.",
+ "a5743.casalemedia.com.",
+ "a5744.casalemedia.com.",
+ "a5745.casalemedia.com.",
+ "a5746.casalemedia.com.",
+ "a5747.casalemedia.com.",
+ "a5748.casalemedia.com.",
+ "a5749.casalemedia.com.",
+ "a5750.casalemedia.com.",
+ "a5751.casalemedia.com.",
+ "a5752.casalemedia.com.",
+ "a5753.casalemedia.com.",
+ "a5754.casalemedia.com.",
+ "a5755.casalemedia.com.",
+ "a5756.casalemedia.com.",
+ "a5758.casalemedia.com.",
+ "a5759.casalemedia.com.",
+ "a576.casalemedia.com.",
+ "a5763.casalemedia.com.",
+ "a5764.casalemedia.com.",
+ "a5765.casalemedia.com.",
+ "a5766.casalemedia.com.",
+ "a5767.casalemedia.com.",
+ "a5768.casalemedia.com.",
+ "a5769.casalemedia.com.",
+ "a577.casalemedia.com.",
+ "a5770.casalemedia.com.",
+ "a5771.casalemedia.com.",
+ "a5772.casalemedia.com.",
+ "a5773.casalemedia.com.",
+ "a5774.casalemedia.com.",
+ "a5775.casalemedia.com.",
+ "a5776.casalemedia.com.",
+ "a5777.casalemedia.com.",
+ "a5778.casalemedia.com.",
+ "a5779.casalemedia.com.",
+ "a578.casalemedia.com.",
+ "a5780.casalemedia.com.",
+ "a5781.casalemedia.com.",
+ "a5782.casalemedia.com.",
+ "a5783.casalemedia.com.",
+ "a5785.casalemedia.com.",
+ "a5786.casalemedia.com.",
+ "a5787.casalemedia.com.",
+ "a5788.casalemedia.com.",
+ "a5789.casalemedia.com.",
+ "a5790.casalemedia.com.",
+ "a5791.casalemedia.com.",
+ "a5792.casalemedia.com.",
+ "a5793.casalemedia.com.",
+ "a5794.casalemedia.com.",
+ "a5795.casalemedia.com.",
+ "a5796.casalemedia.com.",
+ "a5797.casalemedia.com.",
+ "a5798.casalemedia.com.",
+ "a5799.casalemedia.com.",
+ "a5800.casalemedia.com.",
+ "a5801.casalemedia.com.",
+ "a5802.casalemedia.com.",
+ "a5803.casalemedia.com.",
+ "a5804.casalemedia.com.",
+ "a5805.casalemedia.com.",
+ "a5806.casalemedia.com.",
+ "a5809.casalemedia.com.",
+ "a5810.casalemedia.com.",
+ "a5811.casalemedia.com.",
+ "a5813.casalemedia.com.",
+ "a5814.casalemedia.com.",
+ "a5815.casalemedia.com.",
+ "a5856.casalemedia.com.",
+ "a5857.casalemedia.com.",
+ "a5858.casalemedia.com.",
+ "a5859.casalemedia.com.",
+ "a5860.casalemedia.com.",
+ "a5861.casalemedia.com.",
+ "a5862.casalemedia.com.",
+ "a5863.casalemedia.com.",
+ "a5864.casalemedia.com.",
+ "a5865.casalemedia.com.",
+ "a5866.casalemedia.com.",
+ "a5867.casalemedia.com.",
+ "a5868.casalemedia.com.",
+ "a5869.casalemedia.com.",
+ "a5870.casalemedia.com.",
+ "a5871.casalemedia.com.",
+ "a5872.casalemedia.com.",
+ "a5873.casalemedia.com.",
+ "a5874.casalemedia.com.",
+ "a5875.casalemedia.com.",
+ "a5876.casalemedia.com.",
+ "a5877.casalemedia.com.",
+ "a5878.casalemedia.com.",
+ "a5880.casalemedia.com.",
+ "a5881.casalemedia.com.",
+ "a5882.casalemedia.com.",
+ "a5883.casalemedia.com.",
+ "a5884.casalemedia.com.",
+ "a5885.casalemedia.com.",
+ "a5tfzk.doordash.com.",
"aa.online-metrix.net.",
"aa.quantummetric.com.",
- "aaa.a-mo.net.",
"ab.qq.com.",
"aba2c424-419a-4d03-9aed-2dca8a7139e4.prmutv.co.",
- "abcvg.info.",
- "abeacdataonrt-stsdk.vivo.com.cn.",
"abroad.apilocate.amap.com.",
"abtest-aws-us-east-01.saas.sensorsdata.com.",
"accela.com.",
"accentuate.io.",
- "accenture.com.",
"access.mp.lura.live.",
- "account-devices-gdo.myq-cloud.com.",
"account.box.com.",
+ "account.cpanel.net.",
+ "account.meraki.com.",
+ "account.premierleague.com.",
"accountapi.agoda.com.",
"accounts.pointclickcare.com.",
"accounts.shopify.com.",
+ "accounts.superhuman.com.",
+ "accurint.com.",
"acdn.tinkoff.ru.",
- "acehardware.groupbycloud.com.",
"acfun.cn.",
"acgvideo.com.",
"acme-v02.api.letsencrypt.org.",
@@ -121,118 +385,121 @@ var FakeECSFQDNs = container.NewMapSet(
"acr13.prd.dc13.adaptiva.cloud.",
"acr14.prd.dc14.adaptiva.cloud.",
"acrobits.cz.",
- "actualized.org.",
+ "activitymonitor-westus.classroom.cloud.",
"ad-host-backup-america.oss-us-west-1.aliyuncs.com.",
"ad-host-backup-asia.oss-ap-southeast-1.aliyuncs.com.",
"ad-host-backup-europe.oss-eu-central-1.aliyuncs.com.",
- "ad.nvdvr.cn.",
"adapex.io.",
"adaptiva.cloud.",
"adash.man.aliyuncs.com.",
"adblock.telemetry.getadblock.com.",
"adder.feeder.co.",
+ "additionfi.com.",
+ "adexchangeclear.com.",
+ "adguard.com.",
"adiam.tech.",
"aditude.io.",
- "adlog.vivo.com.cn.",
"adm.wsms.haplat.net.",
"admbk.wsms.haplat.net.",
- "admin.cloud.microsoft.",
"admin.shopify.com.",
"admixer.com.",
+ "adopt.jaggaer.com.",
"ads.playstream.media.",
+ "ads.themoneytizer.com.",
"adsco.re.",
"adsinteractive.com.",
- "adstag0102.xyz.",
"adstatistics.av380.net.",
- "adsukses.online.",
"adtarget.market.",
+ "adtech.ink.",
+ "adtidy.org.",
"advantage.purpleguys.com.",
"advantage2.purpleguys.com.",
"advertise.cloudlinks.cn.",
"adview.com.",
- "adx-event-service.trackeradx.com.",
- "adx-in.ads.heytapmobile.com.",
- "adx-sg-req.mosspf.net.",
"adxpremium.services.",
- "aerocomminc.com.",
+ "aeries.com.",
"afd-lnkd.www.linkedin.com.",
- "affpa.top.",
"afss.zhiqinyun.cn.",
"ag.dns-finder.com.",
+ "agelesslivingny.com.",
"agent-healthcheck.defensx.com.",
"agent-logos.storage.googleapis.com.",
+ "agent.marketingcloudfx.com.",
"agentio.com.",
"agents.fxpasu01.manage.microsoft.us.",
+ "ai-assistant.foxit.com.",
"ai-voice.cloudbirds.cn.",
+ "ai.finalsite.com.",
"aicdn.com.",
"aid.send.microad.jp.",
"aidata.io.",
+ "aidcgroup.net.",
+ "air-quality-api.open-meteo.com.",
"airasia.com.",
- "aisee.tv.",
+ "airtory.com.",
"ajcloud.net.",
+ "akrdinfo.cn.",
"akulaku.com.",
"alarm.wsms.haplat.net.",
"alarmbk.wsms.haplat.net.",
+ "alb.mobile.devnet.helium.wtf.",
"albany.remotepc.com.",
"album-sg01a.ocloud.heytapmobi.com.",
- "alburychurches.org.",
"alfasense.com.",
- "ali-alarm-us.oss-us-east-1.aliyuncs.com.",
"alibaba-inc.com.",
"alibabachengdun.com.",
"alibabacorp.com.",
"alibabausercontent.com.",
- "alicloudapi.com.",
"alikunlun.com.",
"alikunlun.net.",
"alive1.cloudbirds.cn.",
"alive2.cloudbirds.cn.",
"alive3.cloudbirds.cn.",
"aliyuncs.com.",
- "allelcoelec.jp.",
- "allkarupspc.com.",
+ "aloyoga.com.",
"alpha1-ap-public.val.qq.com.",
+ "alpha1-nj-gp4-mix2.val.qq.com.",
"ambari.dvr163.com.",
"amdcopen.m.taobao.com.",
- "amdcopen.m.taobao.com.gds.alibabadns.com.",
- "aminer.cn.",
+ "americanchemicalsociety-my.sharepoint.com.",
+ "ameritas-my.sharepoint.com.",
+ "amp-static.cbsnews.com.",
"amp.permutive.com.",
"amplitudelab.usemotion.com.",
"ams-api.video.intl.xiaomi.com.",
- "ams-l7-apm.slb.xiaomi.com.",
+ "ams-howl.api.intl.miui.com.",
"ams2-cdn.2gis.com.",
"amsterdam.remotepc.com.",
- "amuseddie.com.",
"an3762.ci.managedwhitelisting.com.",
+ "analytics-2.athome.com.",
"analytics-debugger.com.",
"analytics-ingress-global.bitmovin.com.",
"analytics.languagetoolplus.com.",
"analytics.pdf24.org.",
"analytics.qumucloud.com.",
+ "analytics.talbots.com.",
"android.crashsight.wetest.net.",
- "anfensi.com.",
"ankara.remotepc.com.",
"anlian.co.",
"announce.torrentsmd.com.",
- "announcekit.co.",
+ "announcekit.app.",
"anthropic.com.",
"antstream.com.",
"aocde.com.",
- "aon.com.",
- "api-analytics-us3.zepp.com.",
- "api-app-slow.bitkeep.fun.",
+ "ap.sd-rtn.com.",
"api-asyncgw-gcc-teams.usgovtrafficmanager.net.",
"api-auth.flysleep.cn.",
+ "api-auth.zztfly.com.",
"api-decider.vsco.co.",
"api-eu1.hubspot.com.",
"api-glb-aapne1a.smoot.apple.com.",
"api-glb-aapne1c.smoot.apple.com.",
"api-glb-aaps1b.smoot.apple.com.",
"api-glb-aapse1c.smoot.apple.com.",
- "api-glb-aeun1a.smoot.apple.com.",
+ "api-glb-aeun1b.smoot.apple.com.",
"api-glb-aeus2a.smoot.apple.com.",
"api-glb-aeus2b.smoot.apple.com.",
- "api-glb-asae1b.smoot.apple.com.",
+ "api-glb-aeuw1b.smoot.apple.com.",
"api-glb-ause1a.smoot.apple.com.",
"api-glb-ause1b.smoot.apple.com.",
"api-glb-ause1c.smoot.apple.com.",
@@ -242,16 +509,13 @@ var FakeECSFQDNs = container.NewMapSet(
"api-glb-ausw2b.smoot.apple.com.",
"api-glb-ausw2c.smoot.apple.com.",
"api-mayi.django.t.taobao.com.",
- "api-mifit-cn3.zepp.com.",
"api-mifit-us3.zepp.com.",
- "api-php2-ovh.keepsolid.com.",
- "api-php4-ovh.keepsolid.com.",
- "api-php9-ovh.keepsolid.com.",
"api-player.musicstylingonline.com.",
"api-preview.luckyorange.com.",
"api-private.atlassian.com.",
+ "api-prod-2.optisigns.com.",
+ "api-proxy.conveythis.com.",
"api-safari-aapse1c.smoot.apple.com.",
- "api-safari-aeun1a.smoot.apple.com.",
"api-safari-aeun1b.smoot.apple.com.",
"api-safari-aeus2a.smoot.apple.com.",
"api-safari-aeus2b.smoot.apple.com.",
@@ -264,130 +528,134 @@ var FakeECSFQDNs = container.NewMapSet(
"api-safari-ause2c.smoot.apple.com.",
"api-safari-ausw2b.smoot.apple.com.",
"api-safari-ausw2c.smoot.apple.com.",
+ "api-service.shein.com.cdn.cloudflare.net.",
"api-sh.django.t.taobao.com.gds.alibabadns.com.",
- "api-stream.twitter.com.",
+ "api-spotlight-ause1a.smoot.apple.com.",
+ "api-spotlight-ause1b.smoot.apple.com.",
+ "api-spotlight-ause1c.smoot.apple.com.",
+ "api-spotlight-ause2a.smoot.apple.com.",
+ "api-spotlight-ause2b.smoot.apple.com.",
+ "api-spotlight-ause2c.smoot.apple.com.",
+ "api-us.aosulife.com.",
+ "api-us.mida.so.",
"api-user.dalyfeds.com.",
- "api.2gis.ru.",
+ "api-westus.classroom.cloud.",
"api.56myu5u3v.com.",
+ "api.adguard.org.",
+ "api.agent.dcca.dell.com.",
"api.al-array.com.",
"api.ams.gcc.teams.microsoft.com.",
+ "api.anthropic.com.",
"api.atlassian.com.",
"api.auth.2gis.com.",
"api.bobble.ai.",
"api.box.com.",
"api.btloader.com.",
"api.bugreport.huorong.cn.",
- "api.c1al9.com.",
"api.cdo.oppomobile.com.",
"api.cloud.tenda.com.cn.",
"api.config-security.com.",
+ "api.crazygames.com.",
"api.crobox.com.",
"api.crush.163.com.",
- "api.dashboard.3dos.io.",
+ "api.cyberghostvpn.com.",
"api.dealersocket.com.",
- "api.dewmobile.net.",
+ "api.f6kyf.com.",
"api.facemojikeyboard.com.",
- "api.fouanalytics.com.",
+ "api.funneljourney.io.",
"api.gelighting.com.",
"api.glanceapis.com.",
"api.gleap.io.",
"api.gravitec.media.",
- "api.hcaptcha.com.",
- "api.hive.blog.",
"api.internal.temp-mail.io.",
"api.ipgeolocation.io.",
- "api.k.163.com.",
- "api.kinogram.best.",
+ "api.kingdata.ksyun.com.",
"api.letsplaywell.com.",
"api.lightboxcdn.com.",
- "api.mida.so.",
- "api.mintkeyboard.com.",
+ "api.linkr.com.",
+ "api.mavenoid.com.",
"api.moyoung.com.",
"api.nkryu17dc.com.",
"api.onedrive.com.",
"api.open-meteo.com.",
+ "api.owhealth.com.cdn.cloudflare.net.",
"api.permutive.app.",
"api.permutive.com.",
- "api.pgf-thek63.com.",
+ "api.pixelpioneerss.com.",
+ "api.poki.com.",
"api.polaris.al-array.com.",
"api.popin.cc.",
"api.production.gstcpx.site.",
+ "api.queryly.com.",
"api.ringcentral.biz.",
"api.rollbar.com.",
- "api.sbz.vn.",
"api.sdk.cqsjd.xyz.",
- "api.smartdeploy.com.",
"api.snapchat.com.",
- "api.sound-machine.com.",
- "api.stiven-king.com.",
+ "api.tamosplayer.com.",
"api.tracking.al-array.com.",
"api.transitapp.com.",
- "api.ttwifi.net.",
+ "api.transmitsecurity.io.cdn.cloudflare.net.",
"api.unity.com.",
"api.us.xiaoyi.com.",
- "api.userlike.com.",
+ "api.usercentrics.eu.",
"api.vieon.vn.",
"api.vsco.co.",
"api.x1skf.com.",
- "api.xiaoyi.com.",
- "api.yosmart.com.",
"api.zmcyu9ypy.com.",
"api000.backblazeb2.com.",
"api001.backblazeb2.com.",
- "api002.backblazeb2.com.",
"apiblink.ru.",
"apiisgp.ezvizlife.com.",
"apiisgp.hik-connect.com.",
"apis.live.net.",
- "apk.v-mate.mobi.",
- "apm-api.mihoyo.com.",
- "apollo.archive.org.",
+ "apixeu.b2c.com.",
"app-atl.five9.com.",
"app-scl.five9.com.",
- "app.anaplan.com.",
"app.box.com.",
"app.cybba.solutions.",
"app.ee-share.com.",
+ "app.eu.securiti.ai.",
"app.firmguard.com.",
- "app.iherb.com.",
"app.pdq.com.",
"app.pendo.qgenda.com.",
"app.pendo.uptodate.com.",
"app.sealsubscriptions.com.",
- "app.snapchat.com.",
+ "app.talkingpts.org.",
+ "app.usercentrics.eu.",
"app.zoom.us.",
"appdump.nie.easebar.com.",
- "appleimap.163.com.",
+ "appliedcloudservices.com.",
"applog.matrix.easebar.com.",
"appocean.media.",
- "appprd.american-time.com.",
+ "apps-ds.shopifynetwork.com.",
"apps.samsung.com.",
+ "apps.shopify.com.",
"apps.wix.com.",
"appstoreonrt-stsdk.vivo.com.cn.",
+ "appstoreort-stsdk.vivo.com.cn.",
"aralego.net.",
"arbitrum.io.",
"arenabg.com.",
- "arenahll-h5.uatext66ap.com.",
+ "aristotleinsight.com.",
+ "arkdhs-my.sharepoint.com.",
+ "arm-frontdoor-edge-geo.trafficmanager.net.",
"arm1.maxhost.io.",
- "armexdef.uk.",
+ "armexfort.uk.",
"arms-retcode-sg.aliyuncs.com.",
- "articles.ipt.pw.",
- "artsy.net.",
+ "article.writeswonder.com.",
"as-api.asm.skype.com.",
"as-prod.asyncgw.teams.microsoft.com.",
"asanalytics.booking.com.",
- "asgnotice.bidmatrixdsp.com.",
- "asheville.remotepc.com.",
+ "asc-a.hbwrapper.com.",
"asia-browser.vivoglobal.com.",
"asia-ex-adlog.vivoglobal.com.",
- "asia-rommc-api.vivoglobal.com.",
+ "asia-minor-appstore.vivoglobal.com.",
"asia-timer-appstore.vivoglobal.com.",
"asia-timesync.vivoglobal.com.",
"asia-upload-appstore.vivoglobal.com.",
"asia-usrsys-api.vivoglobal.com.",
"asia-wifi.vivoglobal.com.",
"asia.remotepc.com.",
- "asklib.com.",
"asm-api-golocal-geo-am-teams.trafficmanager.net.",
"asm-api-golocal-geo-as-teams.trafficmanager.net.",
"asm-api-golocal-geo-eu-teams.trafficmanager.net.",
@@ -400,106 +668,102 @@ var FakeECSFQDNs = container.NewMapSet(
"asset.fwpub1.com.",
"asset.fwscripts.com.",
"assets.api.stairwell.com.",
- "assets.api.useinsider.com.",
- "assets.windscribe.com.",
- "astemo-am.spectrum.colortokens.com.",
+ "assets.id.me.",
+ "assets.ovid.com.",
+ "assets.secure.checkout.visa.com.",
"async-motiondetection-us-1d.oss-us-west-1.aliyuncs.com.",
"asyncim.zoom.us.",
- "ati.com.",
- "atianqi.com.",
+ "atka.aibansg.com.",
"atlanta.remotepc.com.",
"atlanta3.remotepc.com.",
"atlanta4.remotepc.com.",
"atlas.shopifysvc.com.",
"atlassian.net.",
+ "atlassianblog.wpengine.com.",
+ "atm-broker-ws-1314297-sg.vasdgame.com.",
+ "atom-tag-acc-real-hwp.gamedistribution.com.",
"au-prod.asyncgw.teams.microsoft.com.",
"au.ff.avast.sec.miui.com.",
"auckland.remotepc.com.",
- "audienceye.com.",
+ "audio.vivintsky.com.",
"audiostatlog.cc.easebar.com.",
- "audiouser.cc.easebar.com.",
"audrte.com.",
"australiaeast.api.cognitive.microsoft.com.",
"auth-l7.bereal.com.",
"auth.atlassian.com.",
+ "auth.prod.ims.adobejanus.com.",
"auto-load-balancer.likr.com.tw.",
- "autocounter.idealmedia.io.",
- "autohome.com.cn.",
- "automate.heart.net.",
"automate.itsasap.com.",
- "avatar.us.kwcdn.com.",
+ "avigilon.com.",
"aws-aus-e-rdvz.g.nssvc.net.",
"aws-bz-s-rdvz.g.nssvc.net.",
- "aws-in-w-rdvz.g.nssvc.net.",
"aws-us-e-rdvz.g.nssvc.net.",
"aws-us-nc-rdvz.g.nssvc.net.",
+ "ayads.co.",
"az-us-e-rdvz.g.nssvc.net.",
"az-us-sc-features.netscalergateway.net.",
- "az-us-sc-rdvz.g.nssvc.net.",
"azchicago.remotepc.com.",
"azchicago2.remotepc.com.",
+ "azure-reg.c.nssvc.net.",
"azurgames.com.",
- "b1-data.ads.heytapmobi.com.",
- "b1-nldc1.zemanta.com.",
"b2b.filesyscrm.com.",
- "b2b168.com.",
"bablosoft.com.",
"backend.deepl.com.",
"badambiz.com.",
"badoo.app.",
+ "baganintel.com.",
"bahrain.remotepc.com.",
- "baike.so.com.",
"baishan-cloud.net.",
- "baixing.com.",
"balancer.api.net2fast.com.",
+ "ballstate-my.sharepoint.com.",
"baltimore.remotepc.com.",
"bam.nr-data.net.cdn.cloudflare.net.",
- "bancomermovil.com.",
"bangalore2.remotepc.com.",
"bangalore3.remotepc.com.",
"bangalore4.remotepc.com.",
- "baron.cgee.net.",
+ "bankozarks.sharepoint.com.",
+ "bankwithunited-my.sharepoint.com.",
"barstoolsports.com.",
+ "batesvilletechnology.com.",
"bbvaexperience.com.",
- "bcit.ca.",
"bd1cec50-00d1-4ce9-9572-785857419a1e.prmutv.co.",
+ "bdreporting.com.",
"be.nortic.ogtic.gob.do.",
"be1213.am.managedwhitelisting.com.",
"beacon.qq.com.",
"beacons4.gvt2.com.",
"beacons5.gvt2.com.",
+ "becn.sharepoint.com.",
"bee.tc.easebar.com.",
"beizi.biz.",
"belgium.remotepc.com.",
"belgrad.remotepc.com.",
"bend.remotepc.com.",
- "betlive.com.",
"bgtfs.transitapp.com.",
"bi-tracker-global.rivergame.net.",
- "biddr.brealtime.com.",
- "bidmatrixdsp.com.",
"bidster.net.",
"bifrost.vivaldi.com.",
"bigdata.talkie-ai.com.",
- "biggaboo.com.",
"bik.gov.tr.",
- "bike100.tw.",
"bildanat.com.",
- "birdeye.so.",
- "birdsshopping.com.",
- "biz.everychina.com.",
- "bizcommunity.com.",
+ "bistro-la-nature.com.",
+ "bitdefender.com.cdn.cloudflare.net.",
+ "bithumb.com.",
+ "bitmovin.com.",
"bj-td-menta-01-callback.advlion.com.",
+ "bl.listrakbi.com.",
"black-cat.crypto.com.",
"blackboard.com.",
"blackbox.dropbox-dns.com.",
- "bluetracktor.com.",
+ "blacknut.net.",
+ "bloomerang.co.",
+ "bluebuffalo.com.",
"bluffdale.remotepc.com.",
"bmaus.bumble.com.",
"boardgamearena.com.",
+ "boardgamearena.net.",
"bobble.ai.",
- "bokep.work.",
- "bookmarking.site.",
+ "bobid-ip.hybrid.ai.",
"books-analytics-events.apple.com.",
"books-personalization-server.apple.com.",
"booksy.com.",
@@ -510,30 +774,28 @@ var FakeECSFQDNs = container.NewMapSet(
"box.com.",
"box.net.",
"br.chat.si.riotgames.com.",
- "brands-prod.cdn-tinkoff.ru.",
"bratislava.remotepc.com.",
"brazilsouth.api.cognitive.microsoft.com.",
- "breaktime.com.tw.",
"breitbart.com.",
+ "bringads.ru.",
"broadstreetads.com.",
+ "broker-projectd.vasdgame.com.",
"broker-ws-prod-cag-sg.vasdgame.com.",
- "broker.jagat.io.",
- "bt.ktrackers.com.",
+ "bsclink.cn.",
+ "bsgslb.cn.",
+ "bsgslb.com.",
"bt.moack.co.kr.",
- "bt1.archive.org.",
- "btc-europe.com.",
"btinstall-artifacts.bittorrent.com.",
"btrace.qq.com.",
- "bts-la.ucweb.com.",
"bucharest.remotepc.com.",
"budapest.remotepc.com.",
"buenosaires.remotepc.com.",
"bugly.qcloud.com.",
+ "bugly.weplayer.cc.",
"bugreport.huorong.cn.",
- "builds.crazygames.com.",
+ "bx01.optimix.cn.",
"bytecdn.cn.",
"bytedance.net.",
- "bzroofn.com.",
"c.4dex.io.",
"c.4dex.tech.",
"c.51y5.net.",
@@ -541,30 +803,28 @@ var FakeECSFQDNs = container.NewMapSet(
"c.appbaqend.com.",
"c.pub.network.",
"c1.ttcache.com.",
+ "c10.patreonusercontent.com.",
"c2.ttcache.com.",
"c2c.wechat.com.",
"c3.ttcache.com.",
"c4.ttcache.com.",
- "ca-mon-gcp-r001.router.teamviewer.com.",
"ca-prod.asyncgw.teams.microsoft.com.",
- "ca-tor-anx-r004.router.teamviewer.com.",
- "ca-tor-anx-r007.router.teamviewer.com.",
- "ca-van-anx-r005.router.teamviewer.com.",
+ "ca.4dmax.space.",
"ca.rogers.rcs.telephony.goog.",
"ca000.backblaze.com.",
"ca001.backblaze.com.",
- "ca002.backblaze.com.",
"ca80a1adb12a4fbdac5ffcbc944e9a61.pacloudflare.com.",
"cachenetworks.com.",
+ "caixa.gov.br.",
"caldav.163.com.",
"california.remotepc.com.",
"caltech.edu.",
+ "campuslabsengage.com.",
"camstore.vsco.co.",
"canada.remotepc.com.",
"canadacentral.api.cognitive.microsoft.com.",
"canadaeast.api.cognitive.microsoft.com.",
"canberra.remotepc.com.",
- "cangura.com.",
"cantor-lite-api.vsco.co.",
"capetown.remotepc.com.",
"capig.stape.id.",
@@ -573,33 +833,43 @@ var FakeECSFQDNs = container.NewMapSet(
"cardiff.remotepc.com.",
"care.novaicare.com.",
"cartx.cloud.",
+ "cas-us8.wfs.cloud.",
+ "cask.qg2.apps.qualys.com.",
+ "cask.qg3.apps.qualys.com.",
+ "cask.qg4.apps.qualys.com.",
"cat1.hbwrapper.com.",
"cat2.hbwrapper.com.",
"cat3.hbwrapper.com.",
- "catholichealth.net.",
- "cbox.im.",
"cbox.ws.",
- "cbsipv4.shuzilm.cn.",
"cc.easebar.com.",
- "cd.elements.video.",
+ "ccare2.ccr1.com.",
+ "ccf.ivalua.com.",
+ "ccs.c.nssvc.net.",
+ "cdn-audio-gcp-media.getepic.com.",
+ "cdn-c.skcrtxr.com.",
"cdn-cname.pendo.io.",
- "cdn-profiles.tunein.com.",
- "cdn-st.rutubelist.ru.",
+ "cdn-gcp-media-drm.getepic.com.",
+ "cdn-gcp-media.getepic.com.",
+ "cdn-gop.garenanow.com.",
+ "cdn-probe-jobs.mrgcdn.ru.",
"cdn-us.algoliaradar.com.",
- "cdn.adfinity.pro.",
+ "cdn-video-gcp-media.getepic.com.",
"cdn.adjust.com.",
"cdn.adtarget.market.",
- "cdn.adx.ws.",
+ "cdn.aimtell.com.cdn.cloudflare.net.",
"cdn.ap.bittorrent.com.",
"cdn.chargeafter.com.",
+ "cdn.conveythis.com.",
"cdn.deepintent.com.",
+ "cdn.flightradar24.com.",
"cdn.ftd.agency.",
- "cdn.fuseplatform.net.cdn.cloudflare.net.",
"cdn.groupbycloud.com.",
"cdn.hw.gcloudcs.com.",
"cdn.inappstory.ru.",
"cdn.instapagemetrics.com.",
+ "cdn.justuno.com.",
"cdn.lgrckt-in.com.",
+ "cdn.minga.io.",
"cdn.nmcorp.video.",
"cdn.pandora.xiaomi.com.",
"cdn.pendo.uptodate.com.",
@@ -609,22 +879,20 @@ var FakeECSFQDNs = container.NewMapSet(
"cdn.sierrapacificgroup.com.",
"cdn.skcrtxr.com.",
"cdn.static.linkr.com.",
- "cdn.storageimagedisplay.com.",
"cdn.t-bank-app.ru.",
"cdn.t-bank-app.su.",
"cdn.tapdb-dev.com.",
- "cdn.tbank.ru.",
- "cdn.upcbroadband.com.",
+ "cdn.us.minga.io.",
"cdn.uxfeedback.ru.",
- "cdn.viqeo.tv.",
- "cdn01.humeysha.com.",
+ "cdn.viously.com.",
"cdn02.humeysha.com.",
- "cdn03.humeysha.com.",
- "cdn04.humeysha.com.",
+ "cdn05.humeysha.com.",
"cdn1.wixdns.net.",
- "cdn3.uxfeedback.ru.",
+ "cdn11.bigcommerce.com.cdn.cloudflare.net.",
+ "cdn3.fireworktv.com.",
"cdn4.fireworktv.com.",
"cdnapps.avada.io.",
+ "cdnfp.accurint.com.",
"cdngslb.com.",
"cdntm.hsbc.co.uk.",
"cdnwidget.com.",
@@ -633,114 +901,124 @@ var FakeECSFQDNs = container.NewMapSet(
"cedexis-test.com.",
"cedock.com.",
"cef.com.br.",
- "census.shodan.io.",
+ "center00.deltaork.com.",
+ "center01.deltaork.com.",
+ "center02.deltaork.com.",
+ "center03.deltaork.com.",
+ "center04.deltaork.com.",
+ "center05.deltaork.com.",
+ "center06.deltaork.com.",
+ "center07.deltaork.com.",
+ "center08.deltaork.com.",
+ "center09.deltaork.com.",
+ "center10.deltaork.com.",
+ "center11.deltaork.com.",
+ "center12.deltaork.com.",
+ "center13.deltaork.com.",
+ "center14.deltaork.com.",
+ "center15.deltaork.com.",
+ "center16.deltaork.com.",
+ "center17.deltaork.com.",
+ "center18.deltaork.com.",
+ "center19.deltaork.com.",
"centralindia.api.cognitive.microsoft.com.",
"centralus.api.cognitive.microsoft.com.",
"centrexit.com.",
+ "cf-3ip.web.us-east-1.prod.diagnostic.networking.aws.dev.",
"cfa.fidelity.com.",
- "cgee.net.",
- "cgi.twns.qq.com.",
+ "challenges.app.",
"chanjet.com.",
"chargeafter.com.",
"charlotte.remotepc.com.",
+ "chaseprod.quantummetric.com.",
+ "chat.openai.com.",
"check2.lloydsbank.co.uk.",
"check2.zennolab.com.",
- "checkout-sdk.bigcommerce.com.",
"checkout.shopify.com.",
- "chek.zennolab.com.",
+ "checkout.www.deepl.com.",
"chekfast.zennolab.com.",
- "chem17.com.",
- "chemsrc.com.",
"chennai.remotepc.com.",
"chicago2.remotepc.com.",
+ "china-dcr-ccl-zj-b.haplat.net.",
"chinaccl-a.haplat.net.",
"chinaccl-b.haplat.net.",
"chinaccl-c.haplat.net.",
- "chinatimes.com.",
- "choperella.com.",
"chrome.com.",
"chtsite.com.",
+ "chub1.imp.uk.contentkeeper.net.",
+ "chub1.imp.us.contentkeeper.net.",
+ "chub2.imp.uk.contentkeeper.net.",
+ "chub2.imp.us.contentkeeper.net.",
"cicd-release-api.dalyfeds.com.",
- "cis.citrix.com.",
- "citizenmaths.com.",
+ "cimcsouth.com.",
+ "cisa.gov.",
"citrix-cloud-content.customer.pendo.io.",
"citrix-cloud-data.customer.pendo.io.",
+ "citrix-sharefile-content.customer.pendo.io.",
"citrix-sharefile-data.customer.pendo.io.",
"citrix.com.",
"cl-data.ads.heytapmobi.com.",
+ "claphands20.com.",
"claude.ai.",
"cleveland.remotepc.com.",
- "click-v4.cldirplarimo.com.",
- "click-v4.ecxclk.com.",
+ "click-v4.clkoplardir.com.",
+ "click-v4.exmainclckback.com.",
"click-v4.junclikrmedi.com.",
- "click-v4.preclksize.com.",
+ "click-v4.mainexclkdir.com.",
"clickiocmp.com.",
"client-log.box.com.",
"client-tracking.omiapp.me.",
"client-updates.lumu.io.",
- "client.brightvpn.com.",
- "client.mail.163.com.",
"client.otcollector.com.",
"clientlogsf.music.163.com.",
+ "clipchamp.com.",
"cloud-agent.policypak.com.",
"cloud-config-service.rtc.aliyuncs.com.",
"cloud-links.net.",
- "cloud-x-21-srb.rufowupe.xyz.",
- "cloud-x-21-srb.tedumari.xyz.",
- "cloud-x-21-srb.wutirase.xyz.",
- "cloud-x-21-srb.zewaduko.xyz.",
- "cloud.huawei.asia.",
- "cloud.ibm.com.",
+ "cloud-x-21-srb.pugiwora.xyz.",
+ "cloud.huawei.ru.",
"cloud.v-key.com.",
"cloud.vmp.onezapp.com.",
"cloudbirds.cn.",
"cloudlinks.cn.",
- "clzymbeai00003p6q8pmnae1v.d.jitsu.com.",
"cm-x.mgid.com.",
- "cm7mjur1o00003p6r7lio27sb.d.jitsu.com.",
- "cmgate.vip.qq.com.",
"cmpassport.com.",
- "cms.ejoyspace.com.",
+ "cn-hangzhou.oss-cdn.aliyun-inc.com.",
"cn-mib2high-mbbservices.audi-connect.cn.",
"cn-mib2plus.mbbservices-1a.audi-connect.cn.",
"cn.cdn.dnsv1.com.",
- "cn.cdn.dnsv1.com.cn.",
- "cn.gcloudcs.com.",
"cname.pendo.io.",
"cname.shopify.com.",
- "cnplug.ttlock.com.",
+ "cnhtcsales.com.",
"cnt.woxh.world.",
"cnzz.com.",
- "co-vcode-od.vivoglobal.com.",
- "coastalbreed.com.",
"codacloud.net.",
"code42.com.",
- "codelibrary.amlegal.com.",
- "codmsg.gcloudcs.com.",
- "coindesk.com.",
- "collect.trendyol.com.",
- "collector-direct.xhamster.com.",
+ "codepush.akulaku.net.",
"collector.agentio.com.",
+ "collector.prn.fyi.",
"collector.quillbot.com.",
"collector.vhx.tv.",
"collector.wdp.brave.com.",
"collector.woxh.world.",
"collector.xhamster.com.",
"collector.xhamster.desi.",
- "colortokens.com.",
"columbus.remotepc.com.",
+ "columbusoh.infinitecampus.org.",
"com.cdn.dnsv1.com.",
"com.cdn.dnsv1.com.cn.",
"com.yangyi19.com.",
"cometglobal.cf.t3cloud.pb.com.",
+ "cometservd1.pb.com.",
+ "comfrt-us.attn.tv.",
"comicbook.com.",
- "commimg.kwcdn.com.cdn.cloudflare.net.",
+ "commercial.ocsp.identrust.com.",
"common-afd.fe.1drv.com.",
"common-afdrk.fe.1drv.com.",
+ "common-geo.wac.trafficmanager.net.",
"company.rt.ru.",
- "compellent.com.",
"compiles.overleafusercontent.com.",
- "comserver.us1.mspa.n-able.com.",
+ "concursolutions.report-uri.com.",
"config-alps.y5en.com.",
"config-security.com.",
"config.a-m-p.xyz.",
@@ -749,86 +1027,104 @@ var FakeECSFQDNs = container.NewMapSet(
"config.content-settings.com.",
"config.office.net.",
"config.silk.al-array.com.",
- "config.smooch.io.",
"config.y5en.com.",
"config2.cmpassport.com.",
"configdl.teamviewer.com.",
- "configv2.unityads.unitychina.cn.",
- "connect.thescore.com.",
"connectad.io.",
"connectivitycheck.unisoc.com.",
"connectivitycheck.unisoc.com.c.yundunwaf5.com.",
+ "connector.msappproxy.net.",
+ "contact-ldap.8x8.com.",
"contacts.zoho.com.",
+ "content.adopt.jaggaer.com.",
+ "content.assist.chromeriver.com.",
+ "content.bhrpendo.bamboohr.com.",
+ "content.dap.paylocity.com.",
+ "content.data.aleks.com.",
+ "content.data.mheducation.com.",
"content.discover.com.",
"content.discovercard.com.",
+ "content.ebanking-services.com.",
+ "content.engage.starrez.com.",
+ "content.fisglobal.com.",
"content.gap.com.",
+ "content.help.explorelearning.com.",
+ "content.maxconnector.com.",
+ "content.pendo.brightlysoftware.com.",
"content.pendo.careporthealth.com.",
+ "content.pendo.follettdestiny.com.",
"content.pendo.saashr.com.",
"content.productinsights.blackline.com.",
+ "content.tracking.billtrust.com.",
+ "content22.bmo.com.",
"content22.citicards.com.",
"content22.online.citi.com.",
"contentexchange.me.",
"control-out.mna.qq.com.",
"conversion-assistant.apps.seabroadnet.com.",
- "conversionbear.com.",
+ "cookiereports.com.",
"coolccloud.com.",
"coolkit.cc.",
- "coopcowboys.com.",
"copenhagen.remotepc.com.",
"cordial.com.",
"core.iprom.net.",
"core.omiapp.me.",
- "cortacreativo.com.",
"cosmos.azure.com.",
"countly.mail.163.com.",
+ "courts.ca.gov.",
"cpisolutions.com.",
"cpm.appocean.media.",
"cpm.aserve1.net.",
"cpm.qortex.ai.",
"cpm.vuukle.net.",
+ "cpr-pusa01.app.blackbaud.net.",
"cpx-research.com.",
"crash.xiaohongshu.com.",
"crashlytics.com.",
"crashsight.qq.com.",
"crashsight.wetest.net.",
- "crc-engines.api.ksztone.com.",
"crealitycloud.com.",
- "creative.bbrdbr.com.",
- "creative.rmhfrtnd.com.",
"creator.pdf24.org.",
+ "creditmaven.com.",
+ "credova.com.",
"crlocsp.cn.",
"croatia.remotepc.com.",
"crobox.com.",
"crobox.io.",
+ "crossborder-integration.global-e.com.",
"crossforward.com.",
"crowd.transitapp.com.",
"cs.globalsun.io.",
"cs.nex8.net.",
"cs.playdigo.com.",
- "cs13.pikabu.ru.",
- "cs44.pikabu.ru.",
"csdn.net.",
"cstb.adsinteractive.com.",
+ "cstse02.ultipro.com.",
+ "cstsew02.ultipro.com.",
"cstsn02.ultipro.com.",
- "csyzf.com.cn.",
"cta-eu1.hubspot.com.",
"ctmail.com.",
"ctripins.com.",
+ "ctrk.klclick.com.",
"cts.appmeta.store.",
"ctt-er.hnzkclouds.com.",
- "cucloud.cn.",
+ "ctx-akadns-features.netscalergateway.net.",
+ "cummins365-my.sharepoint.com.",
+ "custom-cf.video.twimg.com.cdn.cloudflare.net.",
"customer.gopayapi.com.",
"customer.homedepot.com.",
+ "cvs.quantummetric.com.",
+ "cwa-ma01.ntiva.com.",
+ "cwa-mw01.ntiva.com.",
"cwmpb-as.ruijienetworks.com.",
- "cws.conviva.com.",
- "cz88.net.",
+ "cybersource.com.",
+ "cza.crazygames.com.",
"czechrepublic.remotepc.com.",
- "czyyhgd.com.",
+ "czhuaqiang.com.",
"d.docs.live.net.",
"d.pub.network.",
"d2fb08da-1c03-4c8a-978f-ad8a96b4c31f.partner.permutive.app.",
"d2fb08da-1c03-4c8a-978f-ad8a96b4c31f.prmutv.co.",
- "d3-pr-cu-tm-secapi.trafficmanager.net.",
"d5p.de17a.com.",
"d6691a17-6fdb-4d26-85d6-b3dd27f55f08.prmutv.co.",
"d837da8d.cloudsrv.minerva-labs.com.",
@@ -837,51 +1133,62 @@ var FakeECSFQDNs = container.NewMapSet(
"da.mossru.com.",
"dacdn.visualwebsiteoptimizer.com.",
"daemon.nanoleaf.me.",
- "dailynewshungary.com.",
"dal-cdsltm-2b.dataremote.com.",
"dallas.remotepc.com.",
"dallas2.remotepc.com.",
"dallas3.remotepc.com.",
"dallas4.remotepc.com.",
"dallas5.remotepc.com.",
- "dangkexuexi.com.",
"daraz.com.",
- "darkness.services.",
"dashi.163.com.",
"data-detect.nie.easebar.com.",
+ "data-feed.flightradar24.com.",
"data-tr.rethinkad.com.",
"data.analytics.clockwisemd.com.",
- "data.armexdef.uk.",
+ "data.analytics.thomsonreuters.com.",
+ "data.analytics.ux.quickbase.com.",
+ "data.armexfort.uk.",
"data.assist.chromeriver.com.",
"data.bhrpendo.bamboohr.com.",
"data.cw.edgenuity.com.",
"data.dap.paylocity.com.",
+ "data.data.aleks.com.",
"data.data.mheducation.com.",
+ "data.guide-app.zoominfo.co.",
"data.hockeystack.com.",
+ "data.info.costar.com.",
+ "data.ipd.goto.com.",
"data.kuiniuca.com.",
"data.meitu.com.",
+ "data.p-a.egnyte.com.",
+ "data.p3nd0.sproutsocial.com.",
+ "data.pathfinder.gohighlevel.com.",
+ "data.pendo-cobalt.westlaw.com.",
+ "data.pendo-tracking.seismic.com.",
"data.pendo.brightlysoftware.com.",
"data.pendo.careporthealth.com.",
+ "data.pendo.follettdestiny.com.",
+ "data.pendo.gomotive.com.",
+ "data.pendo.looker.app.",
+ "data.pendo.progresslearning.com.",
"data.pendo.saashr.com.",
"data.pendo.udemy.com.",
"data.pendoanalytics.dayforcehcm.com.",
+ "data.productanalytics.coconutcalendar.com.",
"data.productinsights.blackline.com.",
+ "data.riotgames.com.cdn.cloudflare.net.",
+ "data.tracking.billtrust.com.",
"data00.adlooxtracking.com.",
- "dataannotation.tech.",
"datacollection.uve.weibo.com.",
"datahub.ultimate-guitar.com.",
"datasec-kmsex-cn.heytapmobi.com.",
"datasink.cloudlinks.cn.",
"datasite.com.",
"datatheorem.com.",
- "daydreamingland.com.",
"dayunlinks.cn.",
- "dayviews.com.",
"dbankcdn.ru.cdn.dnsv1.com.",
- "dc-device-service.apple.com.",
"dc-device-service.v.aaplimg.com.",
"dc-dragate-cn.heytapmobi.com.",
- "dc-o.api.leiniao.com.",
"dc.ads.linkedin.com.",
"dc.di.atlas.samsung.com.",
"dc.dqa.samsung.com.",
@@ -901,115 +1208,109 @@ var FakeECSFQDNs = container.NewMapSet(
"dc13.adaptiva.cloud.",
"dc14.adaptiva.cloud.",
"dca-cdsltm-2b.dataremote.com.",
- "dcmdaa.51y5.net.",
+ "dcs-live-uc1.mp.lura.live.",
+ "dcs-live-ue1.mp.lura.live.",
+ "dcs-live-ue4.mp.lura.live.",
+ "dcs-live-uw1.mp.lura.live.",
+ "dcs-live.mp.lura.live.",
+ "dcs-mcdn.mp.lura.live.",
+ "dcs-png.mp.lura.live.",
"dcs-vod.mp.lura.live.",
+ "dcs.mp.lura.live.",
"dcs4-vod.mp.lura.live.",
- "ddimg.cn.",
+ "ddata.huntingtonbank.com.",
"ddnsclient.ivview.net.",
- "de-muc-anx-c023.carouter.teamviewer.com.",
"de-prod.asyncgw.teams.microsoft.com.",
- "de.api.io.mi.com.",
"de.dt.rcs.telephony.goog.",
"dealmoon.com.",
"debugbear.com.",
"decagon.ai.",
- "deepseek.com.cdn.cloudflare.net.",
"delivery.upremium.asia.",
- "deliveryhero.io.",
"dellsupportcenter.com.",
"delta.quantummetric.com.",
- "demeter-int-ecom-collect.trendyol.com.",
- "demeter-tr-core-collect.trendyol.com.",
"denver.remotepc.com.",
+ "desktop.gonitro.com.",
"desync.com.",
"dev-silent-upgrade.cloudbirds.cn.",
"dev.av380.net.",
- "dev.sgp.hik-connect.com.",
"dev.visualwebsiteoptimizer.com.",
- "dev5.keepsolid.com.",
"devc.flysleep.cn.",
- "develop.muxintu.com.",
+ "devc.zztfly.com.",
+ "deviceapi.ca1.absolute.com.",
"deviceops.hstgps.com.",
- "deviceservices-external.apple.com.",
"devicetrust.com.",
- "dewasyscrm.com.",
- "dewmobile.net.",
- "dewu.com.",
- "dhs.gov.",
- "dht.transmissionbt.com.",
+ "devs-api.poki.com.",
+ "diagnostics.api.speechify.com.",
"dialpad.com.",
+ "dicontent.ckapis.com.",
"dict.deepl.com.",
"dict.ntes53.netease.com.",
"dictvip-business.youdao.com.",
"digiboy.ir.",
"digitalcardservice.com.",
"dir.4.401402081.west-gcloud.codm.activision.com.",
- "dir.4.497948935.codmsg.gcloudcs.com.",
+ "directadvert.ru.",
"discovery.ringcentral.biz.",
- "discoverygc.com.",
"dispatcher.omiapp.me.",
- "dispatchosglobal.yuanshen.com.",
- "dissertationtopic.net.",
+ "distservp1.pb.com.",
"divide.dalyfeds.com.",
"dl2.discordapp.net.",
- "dlg.3yjt.com.",
- "dlg.kelikeliq.com.",
- "dlink.com.",
+ "dler.com.",
"dls-udc.dqa.samsung.com.",
"dls.di.atlas.samsung.com.",
"dm-us.hybrid.ai.",
- "dm.slim02.jp.",
+ "dm.hybrid.ai.",
+ "dm.wo.com.cn.",
+ "dmv.ca.gov.",
"dns-e.ns4v.icu.",
"dns-finder.com.",
"dns-tunnel-check.googlezip.net.",
- "dns.anlian.co.",
"dns.rubyfish.cn.",
"dns1.nettica.com.",
- "doccafe.com.",
- "docs.getxray.app.",
+ "doceditor.wrike.com.",
"docs.live.net.",
"docs.zoom.us.",
"doctrack.fda.gov.ph.",
"document360.io.",
- "donate.ssl.xmrig.com.",
"donewyork1.remotepc.com.",
"donewyork2.remotepc.com.",
"donewyork3.remotepc.com.",
- "donnermann-und-partner.de.",
+ "dorpat-use.geo.iponweb.net.",
+ "dorpat-usw.geo.iponweb.net.",
"dosfo1.remotepc.com.",
"dosfo2.remotepc.com.",
"doublenix.com.",
- "doubtnut.com.",
"douyin.starrydyn.com.",
- "down.taodocs.com.",
"download.2.401402081.west-gcloud.codm.activision.com.",
- "download.2.497948935.codmsg.gcloudcs.com.",
"download.gep.mtss.gov.pt.",
"downloadcenter.genetec.com.",
+ "dp.barclaysus.com.",
+ "dpf.authorize.net.",
"dpool.sina.com.cn.",
"dreame.tech.",
"drfdisvc.walmart.com.",
+ "drown.org.",
"ds.gsma.com.",
"dsa-eu.hybrid.ai.",
- "dsa-us.hybrid.ai.",
"dsp-ap.eskimi.com.",
"dsp-trk.eskimi.com.",
"dsp-trvm.eskimi.com.",
"dstillery.com.",
- "dts.euume.com.",
"dtscout.com.",
- "dualspaceapi.com.",
"dubai.remotepc.com.",
"dublin.remotepc.com.",
"dun.163yun.com.",
"duolingo.cn.",
"dz.cyberhaven.io.",
"dzfread.cn.",
- "e-hentai.org.",
+ "e-signlive.com.",
"e.189.cn.",
"e.cdnwidget.com.",
+ "e.postpilot.com.",
"e.userflow.com.",
"e.viously.com.",
+ "e1cef1f0-495f-4973-ba1c-880786e73a66.prmutv.co.",
+ "e1prodappsapimgmtgw.azure-api.net.",
"e2c1.gcp.gvt2.com.",
"e2c10.gcp.gvt2.com.",
"e2c11.gcp.gvt2.com.",
@@ -1092,35 +1393,26 @@ var FakeECSFQDNs = container.NewMapSet(
"e2c82.gcp.gvt2.com.",
"e2c83.gcp.gvt2.com.",
"e2c9.gcp.gvt2.com.",
+ "e43.ultipro.com.",
"e488cdb0-e7cb-4d91-9648-60d437d8e491.prmutv.co.",
"e5de3d23065c4748b155c28e6fa36f3e.pacloudflare.com.",
"eafddirect.msedge.net.",
+ "easel.teacherspayteachers.com.",
"easeus.com.",
"eastasia.api.cognitive.microsoft.com.",
"eastmoney.com.",
"eastus.api.cognitive.microsoft.com.",
"eastus2.api.cognitive.microsoft.com.",
"easycounter.com.",
+ "ecatholic.com.",
+ "eccdnx.com.",
"echo.websocket.org.",
"ecouser.net.",
- "ecs-gallatin-c2s.trafficmanager.net.",
- "ecs.tagtoo.co.",
- "ectransistors.com.",
+ "ed.link.",
"edevice.toshiba-solutions.com.",
- "edge-msk-1.kinescopecdn.net.",
- "edge-msk-2.kinescopecdn.net.",
- "edge-msk-3.kinescopecdn.net.",
- "edge-msk-4.kinescopecdn.net.",
- "edge-msk-5.kinescopecdn.net.",
- "edge-msk-6.kinescopecdn.net.",
- "edge-msk-7.kinescopecdn.net.",
- "edge-msk-8.kinescopecdn.net.",
- "edge-msk-9.kinescopecdn.net.",
"edge-term4-atl1.roblox.com.",
- "edge-term4-cdg2.roblox.com.",
"edge-term4-dfw2.roblox.com.",
"edge-term4-fra2.roblox.com.",
- "edge-term4-fra4.roblox.com.",
"edge-term4-iad4.roblox.com.",
"edge-term4-lax2.roblox.com.",
"edge-term4-lax4.roblox.com.",
@@ -1131,77 +1423,76 @@ var FakeECSFQDNs = container.NewMapSet(
"edge-term4-ord2.roblox.com.",
"edge-term4-sea1.roblox.com.",
"edge-term4-sin2.roblox.com.",
+ "edge-term4-sin4.roblox.com.",
"edge-term4-sin6.roblox.com.",
- "edge.rgi.pmc.pay.riotgames.com.",
"edgecdn.ru.",
"edgedl.me.gvt1.com.",
"edgelocation.ivanticloud.com.",
"editor.wix.com.",
"edna.id.",
"edrawsoft.com.",
- "edreams.es.",
+ "edubit.vn.",
"education-certification.youdao.com.",
"ee-share.com.",
"efercro.com.",
- "egs-platform-service.store.epicgames.com.",
- "ei.dyn-rev.app.",
- "ejoyspace.com.",
- "elcompanies.com.",
+ "efs.ultipro.com.",
+ "egateway.ultipro.com.",
+ "ei.5gtb.com.",
"elemecdn.com.",
- "elite-hunterz.com.",
- "email-tu.998law.com.",
+ "elitebidder.com.",
"emails.zappos.com.",
+ "embed.ly.cdn.cloudflare.net.",
+ "en.linguee.com.",
"en.woxh.world.",
"endpointprotector.com.",
"engage.wixapps.net.",
"enplug.com.",
"ent.box.com.",
- "entitlements.auth.riotgames.com.cdn.cloudflare.net.",
- "entrance-exam.net.",
+ "envoy-ios-prod.getepic.com.",
+ "epdg.vowifi.cspire.com.",
+ "epic.us.production.appliedcloudplatform.com.",
+ "eponesh.com.",
"eportal.fda.gov.ph.",
"epubgame.com.",
"eqoe.cn.",
+ "erpapimanagementservice.azure-api.net.",
"error-analytics-production.shopifysvc.com.",
"error-analytics-sessions-production.shopifysvc.com.",
"errortracking-lb.deepl.com.",
"errortracking.deepl.com.",
"esignlive.com.",
"essence.com.",
- "etracker.com.",
+ "ethicagarden.com.",
"etsv2.datalake.gameloft.com.",
"eu-aa.online-metrix.net.",
"eu-api.asm.skype.com.",
"eu-prod.asyncgw.teams.microsoft.com.",
- "eu-us.consentmanager.net.",
"eu.global.market.xiaomi.com.",
- "eu.iot.dreame.tech.",
+ "eu.inspi-dsp.com.",
"eu.statusapi.micloud.xiaomi.net.",
"eu.whatfix.com.",
"eu1.badoo.com.",
"eu1.bumble.com.",
"euler-saas-cn.heytapmobi.com.",
- "europe-west1-itv-ds-prd.cloudfunctions.net.",
"europe-west1-skyuk-uk-pa-tds-prod.cloudfunctions.net.",
"europe.remotepc.com.",
"euw1.chat.si.riotgames.com.",
"euw1.s.seedtag.com.",
"eve.gameloft.com.",
- "event.meloshort.com.",
- "event.sdk.cqsjd.xyz.",
- "event.togothermany.com.",
- "events.attentivemobile.com.",
+ "event.evtm.53.com.",
"events.glanceapis.com.",
"events.jotform.com.",
+ "events.usermaven.com.",
"everestsystemsco.com.",
- "everychina.com.",
"evtrust.com.",
"exappupgrade.vivoglobal.com.",
"exceptions-eu1.hubspot.com.",
"exodus.desync.com.",
- "exoticindiaart.com.",
"exp.host.",
"expedia.quantummetric.com.",
"experimentation-grpc.deepl.com.",
+ "expf.ru.",
+ "explicit-explicit.bing.net.trafficmanager.net.",
"expo.olo.com.",
"extension.savvy.security.",
"extensions.shopifycdn.com.",
@@ -1210,12 +1501,12 @@ var FakeECSFQDNs = container.NewMapSet(
"external-atl3-1.xx.fbcdn.net.",
"external-atl3-2.xx.fbcdn.net.",
"external-atl3-3.xx.fbcdn.net.",
+ "external-bos5-1.xx.fbcdn.net.",
"external-den2-1.xx.fbcdn.net.",
"external-det1-1.xx.fbcdn.net.",
"external-dfw5-1.xx.fbcdn.net.",
"external-dfw5-2.xx.fbcdn.net.",
"external-dfw5-3.xx.fbcdn.net.",
- "external-fra3-1.xx.fbcdn.net.",
"external-hou1-1.xx.fbcdn.net.",
"external-iad3-1.xx.fbcdn.net.",
"external-iad3-2.xx.fbcdn.net.",
@@ -1233,6 +1524,7 @@ var FakeECSFQDNs = container.NewMapSet(
"external-mia3-2.xx.fbcdn.net.",
"external-mia3-3.xx.fbcdn.net.",
"external-mia5-1.xx.fbcdn.net.",
+ "external-mia5-2.xx.fbcdn.net.",
"external-msp1-1.xx.fbcdn.net.",
"external-ord5-1.xx.fbcdn.net.",
"external-ord5-2.xx.fbcdn.net.",
@@ -1241,48 +1533,43 @@ var FakeECSFQDNs = container.NewMapSet(
"external-sea1-1.xx.fbcdn.net.",
"external-sea5-1.xx.fbcdn.net.",
"external-sjc3-1.xx.fbcdn.net.",
- "external-vie1-1.xx.fbcdn.net.",
+ "external-sjc6-1.xx.fbcdn.net.",
"f002.backblazeb2.com.",
- "f150forum.com.",
- "f389d50a-32e0-478b-9d4b-2d4592528bea.prmutv.co.",
- "f95zone.to.",
"fa3fca7ce79f4b81a39f216e916397d5.pacloudflare.com.",
- "faas.marktplaats.nl.",
"factset.com.",
+ "fanatics.ent.box.com.",
"fanyiegg.youdao.com.",
- "fast.genomics.lbl.gov.",
- "fastball-gateway.mlb.com.",
+ "fastenal-my.sharepoint.com.",
+ "fdccpaadaptor.forddirectservices.com.",
"fdl.flysleep.cn.",
- "feed.mp.lura.live.",
+ "fdl.zztfly.com.",
+ "features.netscalergateway.net.",
"feeder.co.",
- "feelinsonice.l.google.com.",
- "feishu.cn.",
- "fema.gov.",
"fengkongcloud.com.",
- "fenxi.com.",
"fgwn01.ultipro.com.",
"fi.telephony.goog.",
"field59.com.",
- "file.3gcj.com.",
- "file.myqcloud.com.cdn.dnsv1.com.",
- "file.sgpjbg.com.",
+ "fil-pusa01.app.blackbaud.net.",
"filemail.com.",
+ "files.ivaws.com.",
"files.jotform.com.",
"filesyscrm.com.",
- "filters.adavoid.org.",
+ "finalforms.com.",
"finalsite.com.",
"finalsite.net.",
"fireeye.com.",
+ "fireflies.ai.",
+ "fit-pay.com.",
"five9.com.",
- "flashjoin.net.",
"flip.to.",
"flixcdn.com.",
"floors.nitropay.com.",
- "flr-eu3.cbox.ws.",
"flypgs.com.",
"fm.printaudit.com.",
"fmsi-lts.com.",
"foisonad.com.",
+ "followlyrics.com.",
+ "fonts.cdnfonts.com.",
"fonts.shopify.com.",
"fonts.shopifycdn.com.",
"forcesafesearch.google.com.",
@@ -1290,7 +1577,6 @@ var FakeECSFQDNs = container.NewMapSet(
"forms-eu1.hscollectedforms.net.",
"forms-eu1.hsforms.com.",
"forms.shopifyapps.com.",
- "forthepeople.zoom.us.",
"fortisimperious.com.",
"fortworth.remotepc.com.",
"foundation-ipv4.youdao.com.",
@@ -1312,66 +1598,59 @@ var FakeECSFQDNs = container.NewMapSet(
"fp-us-xfinity.rcs.telephony.goog.",
"fp.ca.rogers.rcs.telephony.goog.",
"fp.de.dt.rcs.telephony.goog.",
+ "fp.marketingcloudfx.com.",
"fp.ps.easebar.com.",
+ "fp.ups.com.",
"fp.us.tracfone.rcs.telephony.goog.",
"fpdlp.applxweb.com.",
- "fr-par-anx-c031.carouter.teamviewer.com.",
+ "fpf.hybrid.ai.",
"fr-prod.asyncgw.teams.microsoft.com.",
"fr.resolver.msg.global.xiaomi.net.",
- "fragpunk.com.",
"fran.frvr.com.",
"francecentral.api.cognitive.microsoft.com.",
"franecki.net.",
"frankfurt.remotepc.com.",
- "free.publictracker.xyz.",
+ "free-sg.cyrohost.in.",
"fremont.remotepc.com.",
+ "friends.crazygames.com.",
+ "frontend-event-collector.shopifysvc.com.",
+ "fs.ultiproworkplace.com.",
+ "ftke02.ultipro.com.",
+ "ftkew02.ultipro.com.",
"ftkn01.ultipro.com.",
"ftkn02.ultipro.com.",
- "ftpm.amd.com.",
- "fuyexuetang.com.",
"fxltsbl.com.",
"g-galleryapi.micloud.xiaomi.net.",
"g.galleryapi.micloud.xiaomi.net.",
+ "g10102301085.co.",
"g10498469755.co.",
- "g4.algbid.app.",
"g4.bidbrain.app.",
"g4.mongobrain.app.",
"g4.rtbrain.app.",
- "g83naxx1ena.appdump.nie.easebar.com.",
"ga.badambiz.com.",
- "galaxyappstore.com.",
"gallery.vcmdiawe.com.",
"galleryn0.vcmdiawe.com.",
"galleryn1.vcmdiawe.com.",
- "galleryn10.vcmdiawe.com.",
- "galleryn11.vcmdiawe.com.",
- "galleryn12.vcmdiawe.com.",
- "galleryn13.vcmdiawe.com.",
"galleryn2.vcmdiawe.com.",
"galleryn3.vcmdiawe.com.",
+ "game-api-acc-real-hwp.gamedistribution.com.",
"game.zuiqiangyingyu.net.",
- "gameconfig.ivymobile.com.",
+ "gamechanger.quantummetric.com.",
"gameloft.com.",
"gamemonkey.org.",
- "gamersdream.shop.",
- "games.crazygames.com.",
- "gateway-2.eu-west-1.production.jet-external.com.",
- "gateway.apphud.com.",
+ "gamepigeon.net.",
+ "gateway.ultiproworkplace.com.",
"gateway.zscalerone.net.",
- "gatochino.com.",
- "gb-vodafone.rcs.telephony.goog.",
- "gb.ee.rcs.telephony.goog.",
"gb.o2.rcs.telephony.goog.",
- "gccmod.ecs.office.com.",
"gcdn.co.",
"gcloud.qq.com.",
"gcloudcs.com.",
"gcloudsdk.com.",
- "gcs.sc-cdn.net.",
"gdid.datalake.gameloft.com.",
"geappl.io.",
"geniex.com.",
"geniusmonkey.com.",
+ "gentil.info.",
"geo-dra.platform.hicloud.com.",
"geoip.apps.getjoy.ai.",
"geoplugin.net.",
@@ -1379,31 +1658,33 @@ var FakeECSFQDNs = container.NewMapSet(
"germanywestcentral.api.cognitive.microsoft.com.",
"getadmiral.com.",
"getbutton.io.",
+ "getepic.com.",
"getjoy.ai.",
"getnodejs.com.",
"getshop.tv.",
"gettopple.com.",
"gifshow.com.",
"gigabyte.com.",
- "gingerscraps.net.",
"giraff.io.",
- "gismeteo.net.",
"gitlab.com.",
"gjapplog.ucweb.com.",
- "gkzhan.com.",
"gla.gameloft.com.",
- "glife.arenaplus.net.",
+ "gleap.io.",
+ "glennedia.com.",
+ "glic-my.sharepoint.com.",
+ "global-all.g.nssvc.net.",
+ "global.datasite.com.",
"global.gme.qcloud.com.",
+ "global.jns.swiftserve.com.",
"globalsigncdn.com.cdn.cloudflare.net.",
"globalsun.io.",
"gme.qcloud.com.",
- "go.accessacloud.com.",
- "go.bluetracktor.com.",
- "go.hpyjmp.com.",
+ "gmfinancial.com.",
+ "go.myavlive.com.",
"go2yd.com.",
"goadserver.com.",
"goaffpro.com.",
- "goods-vod.kwcdn.com.",
+ "gohighlevel.com.",
"google.org.",
"googledomains.com.",
"googlesync.permutive.com.",
@@ -1412,59 +1693,63 @@ var FakeECSFQDNs = container.NewMapSet(
"gov-bam.nr-data.net.cdn.cloudflare.net.",
"gr-api.gotii.com.",
"graph-us.avepointonlineservices.com.",
- "gravite.net.",
+ "graphql.usercentrics.eu.",
"gravitec.net.",
+ "greatwolf-my.sharepoint.com.",
"greenville.remotepc.com.",
- "grin.com.",
"grist.org.",
- "gromelink-link-sg.sgameglobal.com.cdn.cloudflare.net.",
+ "gropulse.com.",
"group-ib.com.",
+ "grouponeauto-my.sharepoint.com.",
+ "grouponeauto.sharepoint.com.",
"grow.me.",
"growone.sg.",
- "growthbook-proxy.lenta.tech.",
"grpc.vivintsky.com.",
- "gs-dra.game.dbankcloud.com.",
"gslb.finzfin.com.",
"gslb.sgw.shopeemobile.com.",
- "gtimg.cn.",
+ "gss.gaijin.net.",
"gtm.deepl.com.",
"gtm.quillbot.com.",
"gtm.shopify.com.",
"gtm3.shopify.com.",
- "gtp.gr.",
- "guid.tpns.sgp.tencent.com.",
- "gulamerah.online.",
"gwadar.cn.",
"gyazo.com.",
"gz0.googleusercontent.com.",
"h-5h8i3ud8.online-metrix.net.",
+ "h-adp.online-metrix.net.",
"h-discover.online-metrix.net.",
"h-ebay.online-metrix.net.",
"h-homedepot.online-metrix.net.",
- "h-hsbcmx.online-metrix.net.",
"h-online.citi.online-metrix.net.",
- "h-rbs-bank.online-metrix.net.",
"h-sdk.online-metrix.net.",
"h-signifyd.online-metrix.net.",
+ "h-ups.online-metrix.net.",
+ "h-v60nf4oj-qfp.online-metrix.net.",
"h-walmart.online-metrix.net.",
"h.online-metrix.net.",
"h104216-dcdn.mp.lura.live.",
"h104216-fcdn.mp.lura.live.",
+ "h104216-hcdn.mp.lura.live.",
"h107833-ecdn.mp.lura.live.",
"h64.online-metrix.net.",
"hamina.remotepc.com.",
+ "handshake-production-cdn.joinhandshake.com.",
+ "hapi.teamviewer.com.",
+ "hapsee.cn.",
"hapseemate.cn.",
"harry.lu.",
- "haskell.org.",
"hawaii.remotepc.com.",
"hbopenbid-apac-v2.pubmnet.com.",
"hbwrapper.com.",
- "hbzhan.com.",
- "healthlincchc.org.",
+ "health.avid.com.",
"hecheck.bitmyanmar.info.",
"hetangsmart.com.",
"heytapdownload.com.",
"heytapmobi.com.",
+ "hft-prod.actioniq.mr-in.com.",
+ "hidanoriko.net.",
+ "highwire.org.",
+ "hiido.com.",
"hisearch-dra.dt.dbankcloud.com.",
"hismarttv.com.",
"hits.getelevar.com.",
@@ -1474,14 +1759,14 @@ var FakeECSFQDNs = container.NewMapSet(
"hls.xingyouc.com.",
"hnzkclouds.com.",
"holykjvbible.com.",
+ "home.imgsmail.ru.",
"homedepot-app.quantummetric.com.",
"homedepot.quantummetric.com.",
"honeywell.com.",
"hongkong.remotepc.com.",
"hornetsecurity.com.",
- "hosted.weblate.org.",
"hpplay.cn.",
- "hsg.tdm.qq.com.",
+ "hprofits.com.",
"hstgps.com.",
"html5.qq.com.",
"htms.heytapmobi.com.",
@@ -1489,91 +1774,85 @@ var FakeECSFQDNs = container.NewMapSet(
"huan.tv.",
"huaweicloud.com.",
"huaweicloudwaf.com.",
+ "hub.gibraltarsoftware.com.",
"hubcloud.com.cn.",
"hubspotemail.net.",
"huion.cn.",
- "humiliationstudies.org.",
"humix.com.cdn.cloudflare.net.",
"huorong.cn.",
- "hw.118114.net.",
+ "husunward.com.",
"hw.gcloudcs.com.",
- "hwa.youlesp.com.",
"hwapps-o.api.leiniao.com.",
"hwmsg-as1-usa-o.api.leiniao.com.",
- "hwmsg-as2-asia-o.api.leiniao.com.",
- "hwmsg-as2-usa-o.api.leiniao.com.",
"hwmsg-as3-usa-o.api.leiniao.com.",
"hwmsg-as4-usa-o.api.leiniao.com.",
- "hwmsg-as5-asia-o.api.leiniao.com.",
- "hwr.youlesp.com.",
- "hwtpc-o.api.leiniao.com.",
- "hwzz-01.com.",
"hybrid.ai.",
"i-sg01a.ocloud.heytapmobi.com.",
+ "i.gstatvb.com.",
"i.inspi-dsp.com.",
- "i.magazine.heytapmobi.com.",
+ "i.omiapp.me.",
"i.one-bid.com.",
"i.qchannel03.cn.",
"i.search.heytapmobi.com.",
"i.vsco.co.",
- "i6-vn.weather.oppomobile.com.",
+ "i1.nhentai.net.",
+ "i2.nhentai.net.",
+ "i4.nhentai.net.",
"i8yz83pn.com.",
"ialicdn.com.",
+ "iam-v2.appliedcloudservices.com.",
+ "iberiaparishsdla.aristotleinsight.com.",
"ibit.ly.",
"ibm.account.box.com.",
"ibm.box.com.",
"ibsrv.net.",
- "ic-components.com.",
+ "ic.wps.cn.",
"icare.infranetgroup.com.",
- "icdn.dantri.com.vn.",
"iceudpstat.xdrtc.com.",
"ichano.cn.",
- "id-ooredoo.rcs.telephony.goog.",
+ "icon.cdn.prod.atlassian-dev.net.",
+ "iconmonstr.com.",
+ "id-minor-appstore.vivoglobal.com.",
"id-telkom.rcs.telephony.goog.",
"id-timer-appstore.vivoglobal.com.",
"id.atlassian.com.",
- "id.tuoitre.vn.",
+ "id.pinterest.com.",
"id.woxh.world.",
"iddallas1.remotepc.com.",
"iddenver.remotepc.com.",
- "idealapi.nl.",
- "ideasevenmedia.com.",
"ident.me.",
"ident.mygaru.com.",
"idlondon.remotepc.com.",
"idnewyork1.remotepc.com.",
"idoocloud.com.",
- "idqqimg.com.",
"idr.cdnwidget.com.",
"ids.cdnwidget.com.",
"iemiq.com.",
"igame.gcloudcs.com.",
+ "iili.io.",
"ijoysoftconnect.com.",
- "ikki.youdao.com.",
- "ilcats.ru.",
"ilog-sea-aliyun.alipayplus.com.",
"im.vsco.co.",
"im360.sentry.cloudlinux.com.",
"image.myqcloud.com.",
"image.online.adp.com.",
+ "image.providesupport.com.",
"images.fptplay53.net.",
"images.getadmiral.com.",
"imap.earthlink.net.",
- "img-preview.51jiaoxi.com.",
- "img.jigao616.com.",
- "img.xjishu.com.",
- "img.zhuanlichaxun.net.",
- "img0.didiglobal.com.",
+ "ime-reporter.badambiz.com.",
+ "img.11467.com.",
+ "img.3dmxku.com.",
"img2021.navyfederal.org.",
+ "img9.target.com.",
"imgs.signifyd.com.",
+ "imgs2.imgsmail.ru.",
+ "imgs3.hcaptcha.com.",
"immomo.com.",
"imou-sg-ali-online-paas-iot-private-picture.oss-ap-southeast-1.aliyuncs.com.",
- "imou-sg3-ali-online-paas-private-picture.oss-ap-southeast-1.aliyuncs.com.",
"imoulife.com.",
"imp.adx.roockmobile.com.",
- "imp.hifunadx.site.",
"impactify.media.",
- "impression-forwarder.vibe.co.",
"imptrk.siteplug.com.",
"in-api.asm.skype.com.",
"in-prod.asyncgw.teams.microsoft.com.",
@@ -1581,31 +1860,29 @@ var FakeECSFQDNs = container.NewMapSet(
"in.gov.",
"in.visitors.live.",
"inaccuracy.net.",
- "includes.ccdc02.com.",
+ "inc-collabrtc.officeapps.live.com.",
"incoming.thunderbird.net.",
"indiamart.com.",
"indianapolis.remotepc.com.",
- "indigitall-cdn.com.",
+ "indodax.com.",
"inf.miui.com.",
- "infoldgames.com.",
- "infrastructure-command-api.newrelic.com.",
+ "infinitecampus.com.",
+ "infinitecampus.org.",
+ "ingest.quantummetric.com.",
"ingest.webeyez.com.",
+ "ingesteu.quantummetric.com.",
+ "ingestion.zetta.so.",
+ "ingress.us2.rum-ingress-coralogix.com.",
"inneraudioms.cc.easebar.com.",
- "innersloth.com.",
"innity.com.",
"innity.net.",
- "ino.qq.com.",
- "ins.connatix.com.",
- "insearchofdesign.com.",
- "insight.ucweb.com.",
- "insightful-updates.io.",
- "inskinad.com.",
"inspi-dsp.com.",
+ "inspirebrands.quantummetric.com.",
"instantmessaging-pa-jms-ap.googleapis.com.",
"instantmessaging-pa-jms-eu.googleapis.com.",
"instantmessaging-pa-jms-preprod-us.googleapis.com.",
"instantmessaging-pa-jms-us.googleapis.com.",
- "internetdownloadmanager.com.",
+ "instatus.com.",
"intl-im-conn.iq.com.",
"intuit.zoom.us.",
"ios-api-2.duolingo.cn.",
@@ -1619,26 +1896,32 @@ var FakeECSFQDNs = container.NewMapSet(
"ip-tools.tanjingpaas.com.",
"ip0.zenno.services.",
"ip1.zenno.services.",
- "ipfs.io.",
"ipm.atm.youku.com.",
+ "iprep1.t.ctmail.com.",
+ "iprep2.t.ctmail.com.",
"iprep3.t.ctmail.com.",
"iprep4.t.ctmail.com.",
+ "iprep5.t.ctmail.com.",
+ "ipres.1.geo.ctmail.com.",
+ "ipres.2.geo.ctmail.com.",
"ipres.3.geo.ctmail.com.",
"ipres.4.geo.ctmail.com.",
+ "ipres.5.geo.ctmail.com.",
"iprofiles.apple.com.",
+ "iprofiles.v.aaplimg.com.",
"iprom.net.",
"ipt.pw.",
+ "ipv4.cadc.absolute.com.",
+ "ipv4.games.",
"ipv4.geojs.io.",
"ipv4.sdiptest.com.",
"ipv4.tracker.harry.lu.",
- "ipv6-3.sdiptest.com.",
"ipv6-4.sdiptest.com.",
"ipv6.shuzilm.cn.",
"iq.com.",
"ironmountain.cyberhaven.io.",
- "isciii.es.",
+ "iscorp.com.",
"isgp.ezvizlife.com.",
- "isonaspureaccesscloud.com.",
"istanbul.remotepc.com.",
"istatmenus.app.",
"ita-free-lb.deepl.com.",
@@ -1647,40 +1930,34 @@ var FakeECSFQDNs = container.NewMapSet(
"itc.cn.",
"itch.io.",
"itch.zone.",
+ "itemorder.com.",
"itm.cloud.com.",
- "itmop.com.",
- "itsfreeporn.com.",
+ "ittpx-asia.eskimi.com.",
+ "ittpx-us-e.eskimi.com.",
"ittpx.eskimi.com.",
"itzmx.com.",
+ "ivalua.com.",
"ivview.com.",
"ivview.net.",
- "ivymobile.com.",
- "iybrb.net.",
- "izap24.ru.",
+ "ivytechccofindiana-my.sharepoint.com.",
"izatcloud.net.",
+ "jabfm.org.",
"japanwest.api.cognitive.microsoft.com.",
"jazzpharmaceuticals.cyberhaven.io.",
"jdadelivers.com.",
- "jefferycotton.com.",
- "jfcdns.com.",
- "jfmtechnology.com.",
- "jiaochengzhijia.com.",
- "jigao616.com.",
+ "jhahosted.com.",
"jilliandescribecompany.com.",
- "jinliwujin.com.",
"jira.com.",
- "jishiyuchat.com.",
"jitsu.com.",
- "jjsm789.com.",
+ "jocombssd.aristotleinsight.com.",
"johannesburg.remotepc.com.",
"johnmuirhealth.com.",
+ "johnmuirhealth.sharepoint.com.",
"joinhandshake.com.",
"jp-prod.asyncgw.teams.microsoft.com.",
"jp.cinarra.com.",
"jp1.chat.si.riotgames.com.",
- "jpost.com.",
"jpush.cn.",
- "jpush.html5.qq.com.",
"jpush.io.",
"jrustonapps.net.",
"js-eu1.hs-analytics.net.",
@@ -1690,56 +1967,51 @@ var FakeECSFQDNs = container.NewMapSet(
"js-eu1.hscollectedforms.net.",
"js-eu1.hsforms.net.",
"js-eu1.hubspot.com.",
- "jsnflowmeter.com.",
- "jtexpress.com.cn.",
+ "js.eruptr.io.",
+ "jspm.io.",
+ "jtt.rsmjournals.com.",
"junglefrog.com.",
"justice.gov.",
- "justwipe.co.uk.",
+ "jxappgtw.jhahosted.com.",
"k-aeu1.contentsquare.net.",
"k-aus1.contentsquare.net.",
- "k.163.com.",
- "k01.mbwbm.org.",
- "k8s1-creatives-la.lb.indexww.com.",
- "k8s1-creatives-va.lb.indexww.com.",
+ "k8s1-event-tracker-la.lb.indexww.com.",
"k8s1-event-tracker-ny.lb.indexww.com.",
"k8s1-event-tracker-sg.lb.indexww.com.",
"k8s1-event-tracker-sj.lb.indexww.com.",
+ "k8s1-event-tracker-ty.lb.indexww.com.",
+ "k8s1-event-tracker-va.lb.indexww.com.",
"k8s1-la-ext-haproxy.lb.indexww.com.",
+ "k8s1-sj-ext-haproxy.lb.indexww.com.",
"ka-aus1.contentsquare.net.",
- "kaixinkan.com.cn.",
"kajicam.com.",
- "kalay.net.cn.",
- "kapola.gr.",
- "karaoke-lyrics.net.",
- "kemnaker.go.id.",
+ "kaziya-ryokan.com.",
+ "khabarban.com.",
"khronos.org.",
- "kidzparel.com.",
"kiev.remotepc.com.",
+ "kilat.io.",
"kinogram.best.",
+ "kiprotect.com.",
"kiwisizing.com.",
"klagenfurt.remotepc.com.",
- "klinci.ru.",
- "knoxconnect.net.",
"knoxville.remotepc.com.",
+ "kntxy.com.",
"komect.com.",
- "komikindo.rip.",
"komiku.org.",
"koreacentral.api.cognitive.microsoft.com.",
- "kotaksecurities.com.",
"kstatic.googleusercontent.com.",
"ktlt.cdn-vk.ru.",
"kunlunaq.com.",
"kunlunar.com.",
- "kunlunca.com.",
"kunluncan.com.",
"kunlungr.com.",
"kunlunhuf.com.",
"kunlunsl.com.",
"kunlunso.com.",
- "kurogame.com.",
+ "kunvertads.com.",
"kurogame.xyz.",
+ "kuwo.cn.",
"kwimgs.com.",
- "l.deepintent.com.",
"la.remotepc.com.",
"la1.chat.si.riotgames.com.",
"la10.remotepc.com.",
@@ -1756,55 +2028,50 @@ var FakeECSFQDNs = container.NewMapSet(
"lahuashanbx.com.",
"lan.sdk.linkedin.com.",
"lansing.remotepc.com.",
+ "larkoffice.com.",
"larksuite.com.",
"lastwar-game-us-cf-ali.lastwarapp.com.",
- "laureatelatammx.sharepoint.com.",
"lax.remotepc.com.",
"layerxsecurity.com.",
- "lazpay-fe-kyc-module-file.oss-ap-southeast-1.aliyuncs.com.",
"lb-tencent-sv-3.ubianet.com.",
"lb-tencent-sv-4.ubianet.com.",
"lbv1.com.",
+ "ld.aurelius.host.",
+ "ldap.google.com.",
"ldmnq.com.",
+ "leadmanagerfx.com.",
"leihuo.netease.com.",
"leiniao.com.",
- "lemmy.ca.",
"lens.l.google.com.",
- "lenta.tech.",
"levect.com.",
"leveldata.poki.io.",
"lexicon.33across.com.",
- "lh199607.com.",
- "lianmeng.360.cn.",
"library.pdq.com.",
- "libsyn.com.",
"license.gonative.io.",
"license.litespeedtech.com.",
"licensing.bitmovin.com.",
+ "licensing.sbullet.com.",
"lichess.org.",
+ "lifestancecom.sharepoint.com.",
+ "liftdsp.com.",
"lightwidget.com.",
- "likeevideo.ru.",
- "likr.com.tw.",
+ "lima-tpgateway3.factset.com.",
"lima.remotepc.com.",
"linguee-lb.linguee.com.",
"linguee.com.",
- "linguee.fr.",
"link-vision-picture-sg-v2.oss-ap-southeast-1.aliyuncs.com.",
"linkr.bio.",
- "links.officedepot.com.mx.",
- "liquipedia.net.",
+ "linvk.com.",
"lisbon.remotepc.com.",
"lissabon.remotepc.com.",
- "list.tronlink.org.",
- "list.winehq.org.",
- "listal.com.",
"litedev.sgp.ezvizlife.com.",
"litedev.sgp.hik-connect.com.",
+ "litedev.us.hik-connect.com.",
"litespeedtech.com.",
+ "littler-my.sharepoint.com.",
+ "live-smshopv2.v.trpcdn.net.",
"live.126.net.",
"live.ngb.haplat.net.",
- "live.omiapp.me.",
- "live.qcloud.com.",
"live2.ngb.haplat.net.",
"live3.ngb.haplat.net.",
"live4.ngb.haplat.net.",
@@ -1823,32 +2090,25 @@ var FakeECSFQDNs = container.NewMapSet(
"liveoversea7.ngb.haplat.net.",
"liveoversea8.ngb.haplat.net.",
"liveoversea9.ngb.haplat.net.",
- "livepositively.com.",
- "liverpool.groupbycloud.com.",
"ljubljana.remotepc.com.",
- "loaduk.betfred.com.",
+ "loandepot.zoom.us.",
"local.adguard.org.",
- "log-abroad-ups.submitdata.top.",
"log-api.newrelic.com.cdn.cloudflare.net.",
"log-auth.flysleep.cn.",
"log-auth.zztfly.com.",
"log.mile.so.",
"log.webmaxlogger.net.",
- "log.xiaoyi.com.",
"log.zoom.us.",
- "logctrl.av380.net.",
- "logger.moviead55.ru.",
+ "logging-service-prod.getepic.com.",
"logging.mp.lura.live.",
"loggly.com.",
- "login.loudtalks.com.",
+ "login.shift.com.",
"login.teamviewer.com.",
"login.vivaldi.net.",
- "logs2.sportslocalmedia.com.",
- "logsdata.cxkfwn.com.",
+ "logo.dev.",
"logu.hpplay.cn.",
"logus.xiaoyi.com.",
"logx.optimizely.com.",
- "lokalise.co.",
"london.remotepc.com.",
"london2.remotepc.com.",
"london3.remotepc.com.",
@@ -1856,23 +2116,21 @@ var FakeECSFQDNs = container.NewMapSet(
"london5.remotepc.com.",
"london6.remotepc.com.",
"london8.remotepc.com.",
- "long.tv.",
"look.360.cn.",
- "lookchem.com.",
"lotus-dsp.ru.",
"lpa.ds.gsma.com.",
+ "lplfinancial.app.box.com.",
+ "lplfinancial.atlassian.net.",
"lsagentrelay.lansweeper.com.",
- "ludashi.com.",
+ "ltfl.librarything.com.",
+ "lumberjack.vitalsource.com.",
"luxembourg.remotepc.com.",
- "lx.netease.com.",
"lycraservice-pa-cam-prod.googleapis.com.",
"lyric.alarmnet.com.",
"m-aus1.contentsquare.net.",
- "m.betlive.com.",
+ "m-shindo.com.",
"m.csqtrk.net.",
- "m.csyzf.com.cn.",
"m1.ubianet.com.",
- "m110601-fcdn.mp.lura.live.",
"m2.ubianet.com.",
"m3.ubianet.com.",
"m4.ubianet.com.",
@@ -1880,24 +2138,26 @@ var FakeECSFQDNs = container.NewMapSet(
"m6.ubianet.com.",
"macclog-as.rj.link.",
"macclog002-as.rj.link.",
- "madrapvideos.com.",
"madrid.remotepc.com.",
- "magic.link.",
- "magicacid.cn.",
"magichue.net.",
"maidenhead.remotepc.com.",
+ "mail.beehiiv.com.",
"mail.superhuman.com.",
+ "mailinblue.com.",
"mailings.lmcdn.ru.",
+ "maintenanceconnection.com.",
"malware-filter.gitlab.io.",
- "manage.kmail-lists.com.",
+ "mam.manage.microsoft.us.",
"manage.wix.com.",
+ "manage1.esna.com.",
"management-2.dataremote.com.",
+ "management.azure.com.",
+ "management.privatelink.azure.com.",
"manassas.remotepc.com.",
"manchester.remotepc.com.",
- "marketplace.atlassian.com.",
+ "mapixl.com.",
"marmot-cloud.com.",
"marseille.remotepc.com.",
- "marvelrivals.com.",
"master1.teamviewer.com.",
"master10.teamviewer.com.",
"master11.teamviewer.com.",
@@ -1915,31 +2175,18 @@ var FakeECSFQDNs = container.NewMapSet(
"master8.teamviewer.com.",
"master9.teamviewer.com.",
"match.contentexchange.me.",
- "material.qq.com.",
"matrix.netease.com.",
"max-l.mediav.com.",
"maxhost.io.",
- "mayihu.com.",
"mbboauth-1c.prd.cn.vwg-connect.cn.",
"mcallen.remotepc.com.",
+ "mcdermottwillemery.sharepoint.com.",
+ "mcdn.podbean.com.",
+ "mcds.dalyfeds.com.",
+ "mclife.xtools.info.",
"mcount.easebar.com.",
- "mdap.tngdigital.com.my.",
- "mdlg.nc66kljo.com.",
- "mdlg.oc1nvtla.com.",
- "mdlg.pc2toyuca.com.",
- "mdlg.qc3okokla.com.",
- "mdlg.rc4kickin.com.",
- "mdlg.sc5mnster.com.",
- "mdlg.tc6hunda.com.",
- "mdlg.uc7oicee.com.",
- "mdvdns.com.",
"meari-oss-us.oss-us-west-1.aliyuncs.com.",
"meari-us.oss-us-west-1.aliyuncs.com.",
- "mecha-aus-ping.seasungamescdn.com.",
- "mecha-gz-ping.seasungamescdn.com.",
- "mecha-ind-ping.seasungamescdn.com.",
- "mecha-kr-ping.seasungamescdn.com.",
- "medal.tv.",
"medellin.remotepc.com.",
"media-ams2-1.cdn.whatsapp.net.",
"media-ams4-1.cdn.whatsapp.net.",
@@ -1947,14 +2194,11 @@ var FakeECSFQDNs = container.NewMapSet(
"media-atl3-1.cdn.whatsapp.net.",
"media-atl3-2.cdn.whatsapp.net.",
"media-atl3-3.cdn.whatsapp.net.",
- "media-ber1-1.cdn.whatsapp.net.",
"media-bog2-1.cdn.whatsapp.net.",
"media-bog2-2.cdn.whatsapp.net.",
"media-bos5-1.cdn.whatsapp.net.",
"media-bru2-1.cdn.whatsapp.net.",
"media-cdg4-1.cdn.whatsapp.net.",
- "media-cdg4-2.cdn.whatsapp.net.",
- "media-cdg4-3.cdn.whatsapp.net.",
"media-cdn.atlassian.com.",
"media-cgk1-1.cdn.whatsapp.net.",
"media-cgk1-2.cdn.whatsapp.net.",
@@ -1974,7 +2218,6 @@ var FakeECSFQDNs = container.NewMapSet(
"media-fra5-2.cdn.whatsapp.net.",
"media-gru1-1.cdn.whatsapp.net.",
"media-gru1-2.cdn.whatsapp.net.",
- "media-gru2-1.cdn.whatsapp.net.",
"media-gru2-2.cdn.whatsapp.net.",
"media-gua1-1.cdn.whatsapp.net.",
"media-ham3-1.cdn.whatsapp.net.",
@@ -1987,7 +2230,6 @@ var FakeECSFQDNs = container.NewMapSet(
"media-iad3-1.cdn.whatsapp.net.",
"media-iad3-2.cdn.whatsapp.net.",
"media-ist1-1.cdn.whatsapp.net.",
- "media-ist1-2.cdn.whatsapp.net.",
"media-kul2-1.cdn.whatsapp.net.",
"media-kul2-2.cdn.whatsapp.net.",
"media-kul3-1.cdn.whatsapp.net.",
@@ -2033,42 +2275,29 @@ var FakeECSFQDNs = container.NewMapSet(
"media-sin6-2.cdn.whatsapp.net.",
"media-sin6-3.cdn.whatsapp.net.",
"media-sjc3-1.cdn.whatsapp.net.",
+ "media-sjc6-1.cdn.whatsapp.net.",
"media-sof1-1.cdn.whatsapp.net.",
"media-sof1-2.cdn.whatsapp.net.",
"media-vie1-1.cdn.whatsapp.net.",
"media-waw2-1.cdn.whatsapp.net.",
- "media-waw2-2.cdn.whatsapp.net.",
"media-yyz1-1.cdn.whatsapp.net.",
- "media-zrh1-1.cdn.whatsapp.net.",
- "media.canva.com.",
+ "media.ringcentral.com.",
+ "media.superhuman.com.",
"media.tinkoff.ru.",
"mediav.com.",
"medproad.com.",
- "medspanewsletter.com.",
- "meinali.com.",
"melbourne.remotepc.com.",
+ "memphis.remotepc.com.",
"mentamob.com.",
- "mercadolibre.com.ar.",
"merchant-analytics-api.shopifyapps.com.",
+ "messaging-api.shopifyapps.com.",
"metadata.decagon.ai.",
- "metafilter.com.",
- "meteocast.in.",
- "meteocast.net.",
- "meteotrend.com.",
- "metric-api.newrelic.com.cdn.cloudflare.net.",
"metrics-dre.dt.dbankcloud.cn.",
"metrics-dre.dt.dbankcloud.com.",
"metrics-dre.dt.hihonorcloud.com.",
- "metrics.aimetric.net.",
"metrics5.data.hicloud.com.",
"mexicocity.remotepc.com.",
- "mftransparency.org.",
- "mgspabst.prismray.io.",
- "mgsphdr1.prismray.io.",
- "mgsppros1.prismray.io.",
- "mgsptele.prismray.io.",
"mgtv.com.",
- "mhtcotton.com.",
"miami.remotepc.com.",
"miami2.remotepc.com.",
"mib2clu8.car-cloud-cn.net.",
@@ -2076,21 +2305,21 @@ var FakeECSFQDNs = container.NewMapSet(
"microvirt.com.",
"mid4.linkedin.com.",
"mida.so.",
- "migu.cn.",
+ "middleburycsin.aristotleinsight.com.",
"milan.remotepc.com.",
+ "milestoneinternet.com.cdn.cloudflare.net.",
"mimir2.vivaldi.com.",
"min-api.cryptocompare.com.",
"mini.browser.360.cn.",
"minigame.vip.",
"mintkeyboard.com.",
- "miro.medium.com.",
- "mirrors.iu13.net.",
- "misacdn.net.",
+ "miqe.sdxpkgyaq.com.",
"mixi.media.",
- "mkey.163.com.",
"mm.fcix.net.",
+ "mn365.sharepoint.com.",
"mobile-bank.cdn-tinkoff.ru.",
"mobile-collector.newrelic.com.cdn.cloudflare.net.",
+ "mobile-gw-plas.ultipro.com.",
"mobile-l7.bereal.com.",
"mobile-protect-api.securetheorem.com.",
"mobiledataplan-pa.googleapis.com.",
@@ -2101,97 +2330,87 @@ var FakeECSFQDNs = container.NewMapSet(
"modoro360.com.",
"moni-onrt-stsdk.vivo.com.cn.",
"monitor.fraudblocker.com.",
- "monitoring.qg3.apps.qualys.com.",
- "monticello.remotepc.com.",
+ "monorail-edge.shopifysvc.com.",
+ "monorail-edge.tm.shopifysvc.com.",
+ "montage-discovery.displaynote.com.",
+ "montage-updates.displaynote.com.",
"montreal.remotepc.com.",
+ "monumetric.com.",
"motiondetection-us-1d.oss-us-west-1.aliyuncs.com.",
"motiondetection-us-7d.oss-us-west-1.aliyuncs.com.",
- "motorolasolutions.com.",
- "mountainside-medical.com.",
"mouser.com.",
"mp.360.cn.",
- "mpwb.bidlink.top.",
- "mq-yl-gw.yosmart.com.",
- "mrpahs.com.",
"mrswd.wo87sf.com.",
"ms-static-images.t-static.ru.",
+ "ms1app.pb.com.",
"msdl.microsoft.com.",
"msf.3g.qq.com.",
"msg-img-hk.oss-cn-hongkong.aliyuncs.com.",
+ "msgrt-hwp.gamedistribution.com.",
+ "msp.meituan.com.",
"mu.ariba.com.",
"mumbai.remotepc.com.",
"mumu.nie.netease.com.",
"munich.remotepc.com.",
"munimob.com.",
- "music.163.com.163jiasu.com.",
"musical.ly.",
- "musicandmoreinc.com.",
"musicstylingonline.com.",
- "mx-mex-anx-r009.router.teamviewer.com.",
- "mx-p.vivoglobal.com.",
- "mx-vcode-api.vivoglobal.com.",
- "mx-vcode-od.vivoglobal.com.",
- "mx.amx.rcs.telephony.goog.",
+ "mxp-pusa01.app.blackbaud.net.",
"mxptint.net.",
"my.apps.factset.com.",
"my.getadmiral.com.",
"my.nalpeiron.com.",
- "my.olo.com.",
- "mycharismashop.com.",
- "mydrive.connect.aig.",
+ "myapi.arlo.com.cdn.cloudflare.net.",
"myisolved.com.",
- "myporn.club.",
"myqcloud.com.",
"myqcloud.com.cdn.dnsv1.com.",
+ "mystery-game-tile.poki.io.",
"myvscloud.com.",
- "n03.mbmyj.org.",
- "n04.mbeaj.org.",
- "n04.mbmyj.org.",
- "n04.mbqgu.org.",
- "n04.mbrtz.org.",
- "n05.mbzcp.org.",
- "n06.mbdny.org.",
- "n06.mbznp.org.",
- "n07.mbxma.org.",
- "n08.mbqgu.org.",
- "n09.mbeaj.org.",
- "n10.mbwnp.org.",
- "n11.mbcej.org.",
- "n11.mbwnp.org.",
- "n12.mbwww.org.",
- "n15.mbdny.org.",
- "n20.mbdny.org.",
- "n20.mbrtz.org.",
- "n27.mbcej.org.",
- "n27.mbwww.org.",
- "n28.mbwbm.org.",
- "n30.mbtmv.org.",
- "na-filter-upgrade.huan.tv.",
- "na159.epm.cyberark.com.",
+ "myworkdaycdn.com.cn.",
+ "n10.xyz.",
+ "n1022-spare.network-auth.com.",
+ "n1022.network-auth.com.",
+ "n1036.network-auth.com.",
+ "n21.ultipro.com.",
+ "n219.network-auth.com.",
+ "n259-spare.network-auth.com.",
+ "n259.network-auth.com.",
+ "n32.ultipro.com.",
+ "n35.ultipro.com.",
+ "n43foto.com.",
+ "n44.network-auth.com.",
+ "n509.network-auth.com.",
+ "n677.network-auth.com.",
+ "n686-spare.network-auth.com.",
+ "n686.network-auth.com.",
+ "n715-spare.network-auth.com.",
+ "n715.network-auth.com.",
+ "n866-spare.network-auth.com.",
+ "n866.network-auth.com.",
+ "na171.epm.cyberark.com.",
"na2.chat.si.riotgames.com.",
"nab.com.au.",
+ "nagumosan.com.",
"namequery.com.",
"naperville.remotepc.com.",
"napps.zoom.us.",
"nashville.remotepc.com.",
- "nati.adbase.top.",
+ "nationalmap.gov.",
"native.qq.com.",
"nawzryhwatm.broker.amsoveasea.com.",
"nc.com.",
"ncentral.centrexit.com.",
"nearme.com.cn.",
"nechicago.remotepc.com.",
+ "neonataltherapists.com.",
"net.cdn.dnsv1.com.",
"netapm.music.163.com.",
- "netapp.com.",
"netease.com.",
"netease.im.",
- "netops.ecimon.com.",
"netpop.app.",
"netpresenter.com.",
"netsolssl.com.",
"network-check.sybo.net.",
- "networkofcare.org.",
"neworleans.remotepc.com.",
"news-client.apple.com.",
"news-events.apple.com.",
@@ -2199,34 +2418,29 @@ var FakeECSFQDNs = container.NewMapSet(
"news-sports-events.apple.com.",
"newsletter-edge.apple.com.",
"newsroom.bi.",
- "newstral.com.",
"newtvcdn.com.",
"newyork.remotepc.com.",
"newyork2.remotepc.com.",
"newyork3.remotepc.com.",
- "nexedi.cn.",
"nexstar.amp.permutive.com.",
"nexx360.io.",
- "ng.colortokens.com.",
+ "ng1.angus.mrisoftware.com.",
"ngb.haplat.net.",
"nginxcloudfileproxy-vtm-online.imoulife.com.",
"nice-team.net.",
"nie.netease.com.",
- "nieapps.com.",
- "niplife.com.",
+ "nitroapps.co.",
"nitropay.com.",
- "nitropdf.com.",
- "nlb-al8f8ly066beiyjhsv.eu-central-1.nlb.aliyuncs.com.",
"nmcorp.video.",
+ "noah.n43foto.com.",
"noc.computerhelpnj.com.",
"node.setupad.com.",
"nogigiddy.com.",
"nokia.com.",
+ "nolagov-my.sharepoint.com.",
"noodlemagazine.com.",
- "noon.com.",
- "nordcurrent.com.",
+ "nordvpn.com.",
"northcentralus.api.cognitive.microsoft.com.",
- "northeastshooters.com.",
"northeurope.api.cognitive.microsoft.com.",
"nortic.ogtic.gob.do.",
"norwayeast.api.cognitive.microsoft.com.",
@@ -2234,6 +2448,7 @@ var FakeECSFQDNs = container.NewMapSet(
"notice.sg.bidder.paddlewaver.com.",
"notification889.com.",
"notify.music.163.com.",
+ "novabeyond.com.",
"novaicare.com.",
"nps.gov.",
"ns-cloud-a1.googledomains.com.",
@@ -2258,22 +2473,26 @@ var FakeECSFQDNs = container.NewMapSet(
"ns-cloud-e4.googledomains.com.",
"ns.aliyuncs.com.",
"ns.identrust.com.",
+ "ns1.digitalocean.com.",
"ns1.g.aaplimg.com.",
"ns1.google.com.",
"ns1.identrust.com.",
"ns2.cloudflare.net.",
+ "ns2.digitalocean.com.",
"ns2.g.aaplimg.com.",
"ns2.google.com.",
"ns3.cloudflare.net.",
+ "ns3.digitalocean.com.",
"ns3.g.aaplimg.com.",
"ns3.google.com.",
"ns4.cloudflare.net.",
"ns4.g.aaplimg.com.",
"ns4.google.com.",
+ "ns4v.icu.",
"ns5.cloudflare.net.",
"nsa.nalpeiron.com.",
"ntes53.netease.com.",
- "ntp-vcp.21cn.com.",
+ "ntiva.com.",
"ntp.aliyun.com.",
"ntp.arlo.com.",
"ntp.arlo.com.cdn.cloudflare.net.",
@@ -2284,9 +2503,11 @@ var FakeECSFQDNs = container.NewMapSet(
"ntp3.aliyun.com.",
"ntp4.aliyun.com.",
"ntp5.aliyun.com.",
+ "ntp6.aliyun.com.",
"ntp7.aliyun.com.",
"nts.xtracloud.net.",
"nuremberg.remotepc.com.",
+ "nv.gov.",
"nvdvr.cn.",
"nvu-prd.mqtt.ivanticloud.com.",
"nwr.mmcdn.com.",
@@ -2295,88 +2516,91 @@ var FakeECSFQDNs = container.NewMapSet(
"nws.zoom.us.",
"nxs.mp.lura.live.",
"nycrt.marphezis.com.",
- "nyhyarc.com.",
+ "oauth-login-drcn.platform.dbankcloud.com.",
"obihai.telephony.goog.",
"obs.ap-southeast-1.myhuaweicloud.com.",
"obs.ap-southeast-3.myhuaweicloud.com.",
- "obs.eu-west-101.myhuaweicloud.eu.",
+ "obs.line-apps.com.",
"observability-l7.bereal.com.",
"obsproject.com.",
+ "obus-dc136101-cn.heytapmobi.com.",
"obus-dc20058-cn.heytapmobi.com.",
- "obus-dc2007-cn.heytapmobi.com.",
"obus-dc20123-cn.heytapmobi.com.",
"obus-dc20157-cn.heytapmobi.com.",
- "obus-dc2020-cn.heytapmobi.com.",
"obus-dctech-cn.heytapmobi.com.",
+ "oce.ovid.com.",
+ "ocean-components.com.",
"ocloud.oppomobile.com.",
+ "ocps-xfer.kronos.net.",
"ocsp.identrust.com.",
"odrs.fda.gov.ph.",
"oec22-normal-alisg.tokopediax.com.",
"ogma-l7.bereal.com.",
- "okii.com.",
"okko.tv.",
"ollama.com.",
"omaha.formlabs.com.",
"omiapp.me.",
"on-hwapps-o.api.leiniao.com.",
+ "onboard.triptease.io.",
+ "one.newrelic.com.",
"onekey1.cmpassport.com.",
"oneplus.net.",
"onethingpcs.com.",
"onezapp.com.",
- "onlinemace.com.",
+ "online-store-web.shopifyapps.com.",
"onlinewebfonts.com.",
- "onsite-api.listrak.com.",
"oozf.9vuyy.xyz.",
"op.mykonf.com.",
"opamarketplace.com.",
- "open.acgtracker.com.",
+ "open-closed.net.",
"open.dstud.io.",
"open.oppomobile.com.",
- "opencmp.net.",
"opendsp.ru.",
- "openrice.com.",
"opex-service-cn.allawntech.com.",
- "oppo.com.",
+ "opml.radiotime.com.",
"oppomobile.com.",
"opposhop.cn.",
+ "opps-api.getwarmly.com.",
"optimize.ulinq.asia.",
"optimize.urekamedia.com.",
"optimizely.com.",
"orangehire.com.au.",
- "orderonline.id.",
+ "orchidworld.jp.",
"oregon.remotepc.com.",
"origin.fe-image-cache-ttp.useast8.byteglb.com.",
"orlando.remotepc.com.",
- "ort.stsdk.vivo.com.cn.",
+ "orthoclinical.sharepoint.com.",
"os.ydmob.com.",
"osaka.remotepc.com.",
- "oscar666.com.",
- "oss-ap-northeast-1.aliyuncs.com.",
"oss-ap-southeast-1.aliyuncs.com.",
"oss-ap-southeast-5.aliyuncs.com.",
+ "oss-cn-beijing.aliyuncs.com.",
+ "oss-cn-hangzhou.aliyuncs.com.",
"oss-cn-hongkong.aliyuncs.com.",
+ "oss-cn-shanghai.aliyuncs.com.",
"oss-cn-shenzhen.aliyuncs.com.",
+ "oss-cn-zhangjiakou.aliyuncs.com.",
"oss-eu-central-1.aliyuncs.com.",
"oss-us-east-1.aliyuncs.com.",
"oss-us-west-1.aliyuncs.com.",
- "oss.aliyuncs.com.",
- "otc.t-systems.com.",
"otlp-http-production.shopifysvc.com.",
+ "otsu-jva.com.",
"ott-lb.deepl.com.",
"ott.deepl.com.",
"ovative.com.",
- "overflow.biz.",
"overleaf.com.",
"overleafusercontent.com.",
"overseasccl-a.haplat.net.",
"overseasccl-b.haplat.net.",
- "overseasccl-c.haplat.net.",
- "overseasccl-d.haplat.net.",
"overseasccl-e.haplat.net.",
"ovh.maxhost.io.",
+ "ownadx-xml.tri.media.",
+ "oxsquare.net.",
"p.adlooxtracking.com.",
+ "p.myisolved.com.",
"p.vsco.co.",
"p0-pu-private-useast8.tiktokv.us.",
+ "p0-tiktok-dm-ttp2-private.tiktokv.us.",
"p107609.cedexis-test.com.",
"p109522.cedexis-test.com.",
"p118600.itm.cloud.com.",
@@ -2395,12 +2619,6 @@ var FakeECSFQDNs = container.NewMapSet(
"p2p-cal.anker-in.com.",
"p2p-ohi-2.anker-in.com.",
"p2p-ohi-4.anker-in.com.",
- "p2p-par-2.anker-in.com.",
- "p2p-par-3.anker-in.com.",
- "p2p-par.anker-in.com.",
- "p2p-sgp-2.anker-in.com.",
- "p2p-sgp.anker-in.com.",
- "p2p-sto-3.anker-in.com.",
"p2p-vir.anker-in.com.",
"p2p.qq.com.",
"p2p2-usa.aqara.com.",
@@ -2426,15 +2644,19 @@ var FakeECSFQDNs = container.NewMapSet(
"p34856.cedexis-test.com.",
"p34858.cedexis-test.com.",
"p35883.cedexis-test.com.",
+ "p39266.cedexis-test.com.",
"p39604.cedexis-test.com.",
"p40255.cedexis-test.com.",
+ "p40256.cedexis-test.com.",
"p40259.cedexis-test.com.",
"p40264.cedexis-test.com.",
+ "p40265.cedexis-test.com.",
"p40266.cedexis-test.com.",
"p40267.cedexis-test.com.",
"p40480.cedexis-test.com.",
"p40488.cedexis-test.com.",
"p40491.cedexis-test.com.",
+ "p40952.cedexis-test.com.",
"p41237.cedexis-test.com.",
"p41238.cedexis-test.com.",
"p41905.cedexis-test.com.",
@@ -2454,83 +2676,86 @@ var FakeECSFQDNs = container.NewMapSet(
"p95708.cedexis-test.com.",
"p95711.cedexis-test.com.",
"p95722.cedexis-test.com.",
+ "pa.authenticator.beyondidentity.com.",
"paddlewaver.com.",
"pai.googlezip.net.",
"palermo.remotepc.com.",
"palm.tech.",
- "panaryglassware.com.",
"panorama.wixapps.net.",
- "pansousuo.com.",
- "papegames.com.",
"paris.remotepc.com.",
"parlovoz.com.",
+ "partner-identity.myq-cloud.com.",
"pasadena.remotepc.com.",
"passportalmsp.com.",
- "patentcenter.uspto.gov.",
"pay.shopify.com.",
+ "payment.api.speechify.com.",
"payment.omiapp.me.",
"pbdlsp1.pb.com.",
- "pbe1.chat.si.riotgames.com.",
+ "pbjs.rbstsystems.live.",
"pbs.atmtd.com.",
"pbs.btloader.com.",
"pbs.nitropay.com.",
- "pbs.receptivity.io.",
+ "pbsj.bricks-co.com.",
"pc-store.lenovomm.cn.",
"pc.crashsight.wetest.net.",
"pc.perfsight.wetest.net.",
"pcdn.brave.com.",
+ "pcworld.com.",
"pd.cdnwidget.com.",
"pdf24.org.",
"pdfforge.org.",
- "pe0733.ci.managedwhitelisting.com.",
- "peplink.com.",
+ "pearcommerce.com.",
+ "people.com.cdn.cloudflare.net.",
+ "peopleadmin.com.",
"perf-eu1.hsforms.com.",
"perfsight.qq.com.",
"perfsight.wetest.net.",
- "permutive.arstechnica.com.",
+ "perkspot-api.perkspot.com.",
"permutive.businessinsider.com.",
"perr.brightvpn.com.",
"pf.intuit.com.",
"pharos.studyquicks.com.",
"phonebridge.zoho.com.",
- "phonehome.hazelcast.com.",
"photoroom.com.",
- "pic.rutubelist.ru.",
+ "piicmgvmss.polaris.com.",
"pikabu.ru.",
"pin.apiblink.ru.",
"pingler.com.",
"pingma.qq.com.",
"pioneer.ghtinc.com.",
+ "pirateparty.gr.",
"pitk.unioneeu.com.",
"pittsburgh.remotepc.com.",
"pix.cdnwidget.com.",
"pixel.adlooxtracking.ru.",
"pixel.dashfi.dev.",
"pixel.gliacloud.com.",
- "pixivzhan.com.",
- "pk-live.cn.",
"planner.cloud.microsoft.",
"platform-alib.linkedin.cn.",
- "playfamily.ru.",
+ "play-bs-las.livetech.shopee.co.id.",
+ "playdigo.com.",
"playstream.media.",
"pllatdpr.cn.",
"plrm.zone.",
"plt-api-us.xiaoyi.com.",
+ "pluralsight.com.",
"pm.geniusmonkey.com.",
- "pod-19-sunco-ws.zendesk.com.",
"poizon.com.",
"polandcentral.api.cognitive.microsoft.com.",
+ "policy.cookiereports.com.",
+ "polling.zoom.us.",
"polymarket.com.",
+ "pool-bid-gce-us.dorpat.iponweb.net.",
+ "pool-usw.dorpat.iponweb.net.",
"pop-convert.com.",
- "pop-release.itop.qq.com.",
"popt.in.",
- "porsche-parts-store.myshopify.com.",
"portal.us.ubianet.com.",
"portals.mobi.",
"portland.remotepc.com.",
"posthog.com.",
+ "postpilot.com.",
+ "pov.spectrum.net.",
"pp.cadc.absolute.com.",
- "pp.ringcentral.biz.",
"pp.usdc.absolute.com.",
"ppgames.net.",
"pragmaticplay.net.",
@@ -2548,15 +2773,17 @@ var FakeECSFQDNs = container.NewMapSet(
"prd.dc13.adaptiva.cloud.",
"prd.dc14.adaptiva.cloud.",
"prd.pck.netskrt.net.",
+ "prebid.adipolo.live.",
"prebid.anyclip.com.",
"prebid.trustedstack.com.",
+ "premium.xvpn.io.",
"presentation-hkg1.turn.com.",
- "primevox.net.",
"printaudit.com.",
+ "privacy-proxy.usercentrics.eu.",
+ "privy.com.",
"privy.io.",
+ "privymktg.com.",
"pro-glswish-aks-tm.trafficmanager.net.",
- "proballers.com.",
- "probe.twitter.com.cdn.cloudflare.net.",
"procore.com.",
"prod-client-api.v.aaplimg.com.",
"prod-default.lb.logrocket.network.",
@@ -2565,50 +2792,41 @@ var FakeECSFQDNs = container.NewMapSet(
"prod-event-relay-sports-api.v.aaplimg.com.",
"prod-event-relay-stocks-api.v.aaplimg.com.",
"prod-event-relay-weather-api.v.aaplimg.com.",
+ "prod-naus-track.popmart.com.",
"prod-newsletter-edge.v.aaplimg.com.",
- "prod-ssg-launcher-api.amazingseasun.com.",
+ "prod-tasks.trafficmanager.net.",
"prod.api.letsencrypt.org.",
+ "production.appliedcloudplatform.com.",
"productreviews.shopifycdn.com.",
+ "profile.zoho.com.",
"profiler-collector.dalyfeds.com.",
- "profiles.zello.com.",
- "project-limelight.com.",
- "promotionad.nvcam.net.",
+ "prominder360.com.",
+ "propertyview.net.",
"proquest.com.",
"protonvpn.com.",
"provaltech.com.",
"proxy-safebrowsing.googleapis.com.",
"proxy.mob.maps.yandex.net.",
"proxy.shopifycdn.com.",
- "ps.namequery.com.",
- "psychologs.com.",
- "psychpulse.com.",
+ "psav-my.sharepoint.com.",
"pub.affilimateapis.com.",
+ "pub.dev.",
"pub.network.",
- "pubg1.battleye.com.",
"public-api.uxfeedback.ru.",
- "public-cdn-s3-us-west-2.oss-us-east-1.aliyuncs.com.",
- "publiclog.zhiyan.tencent-cloud.net.",
- "publictracker.xyz.",
- "pubsub.checkvideo.net.",
"puffer.6.401402081.west-gcloud.codm.activision.com.",
- "pull-cmaf-l77-va01.tiktokcdn.com.",
- "pulse.app-wizard.io.",
"punch.p2p.qq.com.",
"purpleguys.com.",
"push-ads-cn.heytapmobi.com.",
"push-row.zui.com.",
"push.omiapp.me.",
"pushmac.flexibits.com.",
- "pushtrs9.push.hicloud.com.",
- "puswdsprmtprs.dealersocket.com.",
"pvvstream.pro.",
"pw.mediav.com.",
- "pwnt.bidflex.top.",
+ "pwa.zoom.us.",
"px-intl.ucweb.com.",
"px.ads.linkedin.com.",
"px4.ads.linkedin.com.",
"pxl.stripchat.com.",
- "qagpublic.qg1.apps.qualys.ae.",
"qagpublic.qg1.apps.qualys.ca.",
"qagpublic.qg1.apps.qualys.co.uk.",
"qagpublic.qg1.apps.qualys.com.",
@@ -2620,23 +2838,25 @@ var FakeECSFQDNs = container.NewMapSet(
"qagpublic.qg4.apps.qualys.com.",
"qatarcentral.api.cognitive.microsoft.com.",
"qc-static.coccoc.com.",
- "qcloud-sg-datareceiver.kurogame.xyz.",
- "qcloud.com.",
"qfp.intuit.com.",
"qiezibenpao.com.",
"qikify.com.",
- "qldzkj.com.",
+ "qiyeku.cn.",
+ "qm2.progressive.com.",
+ "qmi.cdw.com.",
+ "qntv.io.",
"qookkagames.com.",
"qpic.cn.cdn.dnsv1.com.",
- "qq.com.cn.",
"qualcomm.cn.",
"qualcomm.com.",
- "qualys.ae.",
- "quangcao.tuoitre.vn.",
+ "quantamagazine.org.",
"quantummetric.com.",
"quicinc.com.",
"quickcep.com.",
+ "quyou8.com.",
"qxwz.com.",
+ "r.3gl.net.",
+ "r.akulaku.net.",
"r.ingest-lr.com.",
"r.intake-lr.com.",
"r.lgrckt-in.com.",
@@ -2648,126 +2868,336 @@ var FakeECSFQDNs = container.NewMapSet(
"r.lr-ingest.io.",
"r.lr-intake.com.",
"r.lrkt-in.com.",
- "r.visitstats.com.",
- "r1---sn-ab5l6nrs.c.2mdn.net.",
+ "r.superhuman.com.",
+ "r1---sn-ab5sznz6.c.2mdn.net.",
+ "r1---sn-ab5sznzy.c.2mdn.net.",
+ "r1---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r1---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r1---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r1---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
"r1---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
"r1---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
+ "r1---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r1---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r1---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r1---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r1---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r1---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r1---sn-n2uxaxjvh-j5xl.gvt1.com.",
+ "r1---sn-nh5gujvh-h4xe.googlevideo.com.",
+ "r1---sn-nh5gujvh-h4xl.googlevideo.com.",
+ "r1---sn-nh5gujvh-h4xl.gvt1.com.",
+ "r1---sn-q4fl6nd7.c.2mdn.net.",
+ "r1---sn-q4fl6nz7.c.2mdn.net.",
+ "r1---sn-q4flrne6.c.2mdn.net.",
"r1---sn-tn.googlevideo.com.",
- "r1---sn-vgqsknlk.c.2mdn.net.",
+ "r1---sn-vgqskne6.c.2mdn.net.",
+ "r1---sn-vgqsknlr.c.2mdn.net.",
+ "r1---sn-vgqsknz6.c.2mdn.net.",
+ "r1---sn-vgqsknz7.c.2mdn.net.",
+ "r1---sn-vgqsknzl.c.2mdn.net.",
+ "r1---sn-vgqsrne6.c.2mdn.net.",
+ "r1---sn-vgqsrnzr.c.2mdn.net.",
+ "r1---sn-vgqsrnzz.c.2mdn.net.",
"r1.sn-tn.googlevideo.com.",
+ "r1.visualwebsiteoptimizer.com.",
+ "r10---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r10---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r10---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r10---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "r10---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r10---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r10---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r10---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r10---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r10---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r11---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r11---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r11---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r11---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "r11---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r11---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r11---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r11---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r11---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r11---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r12---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r12---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r12---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r12---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "r12---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r12---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r12---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r12---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r12---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r12---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r13---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r13---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r13---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r13---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "r13---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r13---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r13---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r13---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r13---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r13---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r2---sn-ab5l6nrd.c.2mdn.net.",
+ "r2---sn-ab5l6nrz.c.2mdn.net.",
+ "r2---sn-ab5sznz6.c.2mdn.net.",
+ "r2---sn-ab5sznzd.c.2mdn.net.",
+ "r2---sn-ab5sznze.c.2mdn.net.",
+ "r2---sn-ab5sznzr.c.2mdn.net.",
+ "r2---sn-ab5sznzy.c.2mdn.net.",
+ "r2---sn-ab5sznzz.c.2mdn.net.",
+ "r2---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r2---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r2---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r2---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
"r2---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
"r2---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
+ "r2---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r2---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r2---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r2---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r2---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r2---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r2---sn-n2uxaxjvh-j5xs.gvt1.com.",
+ "r2---sn-nh5gujvh-h4xe.googlevideo.com.",
+ "r2---sn-nh5gujvh-h4xe.gvt1.com.",
+ "r2---sn-nh5gujvh-h4xl.googlevideo.com.",
+ "r2---sn-nh5gujvh-h4xl.gvt1.com.",
+ "r2---sn-nx57ynsk.c.2mdn.net.",
+ "r2---sn-q4fzen7l.c.2mdn.net.",
+ "r2---sn-q4fzen7s.c.2mdn.net.",
"r2---sn-tn.googlevideo.com.",
- "r2.cloudflarestorage.com.",
+ "r2---sn-vgqskn6s.c.2mdn.net.",
+ "r2---sn-vgqsknld.c.2mdn.net.",
+ "r2---sn-vgqsknlr.c.2mdn.net.",
+ "r2---sn-vgqsknse.c.2mdn.net.",
+ "r2---sn-vgqsknzd.c.2mdn.net.",
+ "r2---sn-vgqsrn67.c.2mdn.net.",
+ "r2---sn-vgqsrn6z.c.2mdn.net.",
+ "r2---sn-vgqsrnll.c.2mdn.net.",
+ "r2---sn-vgqsrnls.c.2mdn.net.",
+ "r2---sn-vgqsrnsd.c.2mdn.net.",
+ "r2---sn-vgqsrnsr.c.2mdn.net.",
+ "r2---sn-vgqsrnsy.c.2mdn.net.",
+ "r2---sn-vgqsrnzz.c.2mdn.net.",
"r2.sn-tn.googlevideo.com.",
+ "r2.visualwebsiteoptimizer.com.",
+ "r3---sn-ab5l6nr6.c.2mdn.net.",
+ "r3---sn-ab5sznzr.c.2mdn.net.",
+ "r3---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r3---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r3---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r3---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
"r3---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
"r3---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
+ "r3---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r3---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r3---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r3---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r3---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r3---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r3---sn-jxopj-nh4e.gvt1.com.",
+ "r3---sn-q4fl6nsd.c.2mdn.net.",
+ "r3---sn-q4flrnlz.c.2mdn.net.",
+ "r3---sn-q4flrnss.c.2mdn.net.",
+ "r3---sn-q4fzene7.c.2mdn.net.",
+ "r3---sn-q4fzenee.c.2mdn.net.",
"r3---sn-tn.googlevideo.com.",
+ "r3---sn-vgqskn67.c.2mdn.net.",
+ "r3---sn-vgqskne6.c.2mdn.net.",
+ "r3---sn-vgqskns7.c.2mdn.net.",
+ "r3---sn-vgqsknz7.c.2mdn.net.",
+ "r3---sn-vgqsrn6e.c.2mdn.net.",
+ "r3---sn-vgqsrnll.c.2mdn.net.",
+ "r3---sn-vgqsrnzs.c.2mdn.net.",
"r3.sn-tn.googlevideo.com.",
+ "r3.visualwebsiteoptimizer.com.",
+ "r4---sn-ab5l6nrz.c.2mdn.net.",
+ "r4---sn-ab5sznzr.c.2mdn.net.",
+ "r4---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r4---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r4---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r4---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
"r4---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
"r4---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
- "r4---sn-vgqsknlk.c.2mdn.net.",
- "r4.visualwebsiteoptimizer.com.",
+ "r4---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r4---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r4---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r4---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r4---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r4---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r4---sn-q4fl6n6d.c.2mdn.net.",
+ "r4---sn-q4flrn7k.c.2mdn.net.",
+ "r4---sn-q4flrnlz.c.2mdn.net.",
+ "r4---sn-q4fzen7s.c.2mdn.net.",
+ "r4---sn-q4fzenee.c.2mdn.net.",
+ "r4---sn-vgqsknz6.c.2mdn.net.",
+ "r4---sn-vgqsknz7.c.2mdn.net.",
+ "r4---sn-vgqsrnll.c.2mdn.net.",
+ "r4---sn-vgqsrnlz.c.2mdn.net.",
+ "r4---sn-vgqsrnsy.c.2mdn.net.",
+ "r4---sn-vgqsrnz6.c.2mdn.net.",
+ "r4---sn-vgqsrnzr.c.2mdn.net.",
+ "r5---sn-ab5l6nr6.c.2mdn.net.",
+ "r5---sn-ab5l6nrl.c.2mdn.net.",
+ "r5---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r5---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r5---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r5---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
"r5---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
"r5---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
- "r5---sn-vgqsrnzs.c.2mdn.net.",
- "r5.visualwebsiteoptimizer.com.",
+ "r5---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r5---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r5---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r5---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r5---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r5---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r5---sn-q4fzen7l.c.2mdn.net.",
+ "r5---sn-vgqskn6d.c.2mdn.net.",
+ "r5---sn-vgqskne6.c.2mdn.net.",
+ "r5---sn-vgqsknlk.c.2mdn.net.",
+ "r5---sn-vgqsknlr.c.2mdn.net.",
+ "r5---sn-vgqsknls.c.2mdn.net.",
+ "r5---sn-vgqsknsk.c.2mdn.net.",
+ "r5---sn-vgqsrn6e.c.2mdn.net.",
+ "r5---sn-vgqsrnlz.c.2mdn.net.",
+ "r5---sn-vgqsrnz6.c.2mdn.net.",
+ "r5---sn-vgqsrnzz.c.2mdn.net.",
+ "r6---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r6---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r6---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r6---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
"r6---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
"r6---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
- "r6.visualwebsiteoptimizer.com.",
- "rack.avads.live.",
+ "r6---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r6---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r6---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r6---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r6---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r6---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r7---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r7---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r7---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r7---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "r7---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r7---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r7---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r7---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r7---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r7---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r8---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r8---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r8---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r8---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "r8---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r8---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r8---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r8---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r8---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r8---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "r9---sn-bvvbaxivnuxq5uu-p5ie.googlevideo.com.",
+ "r9---sn-bvvbaxivnuxq5uu-p5il.googlevideo.com.",
+ "r9---sn-bvvbaxivnuxq5uu-p5is.googlevideo.com.",
+ "r9---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "r9---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "r9---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "r9---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "r9---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "r9---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "r9---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
"radar.cedexis.com.",
- "radio-browser.info.",
- "raiderlogbook.com.",
"raleigh.remotepc.com.",
- "raspbian.raspberrypi.org.",
+ "rba-screen.healthsafe-id.com.",
+ "rba.onehealthcareid.com.",
"rbm-ap.storage.googleapis.com.",
"rbm-us.storage.googleapis.com.",
"rcs-acs-att-us.jibe.google.com.",
"rcs-acs-mcc311.jibe.google.com.",
"rcs-acs-mcc510.jibe.google.com.",
- "rcs-acs-mcc515.jibe.google.com.",
"rcs-acs-tmo-us.jibe.google.com.",
"rcs-copper-optimized-us.googleapis.com.",
"rcs-copper-us.googleapis.com.",
"rcs.telephony.goog.",
- "rctiplus.id.",
- "readlink.com.",
+ "rdtxd.mediav.com.",
+ "readingplus.com.",
"readwise.io.",
"realtime-data-api.transitapp.com.",
- "realtime.dewasyscrm.com.",
+ "realtime.kabutoservices.com.",
"realtime.luckyorange.com.",
"realtime.services.box.net.",
- "realtotal.de.",
"rec-cgi.evgcdn.net.",
+ "recognizedpotential.com.",
"recombee.com.",
+ "recruiting.ultipro.com.",
+ "recruiting2.ultipro.com.",
+ "reg.c.nssvc.net.",
"regions.com.",
- "registration.prna01.cmdagent.trafficmanager.net.",
+ "register.com.",
"reichelcormier.bid.",
"relatoriounico.pt.",
- "relay-f0493aa4.net.anydesk.com.",
"remote-config.gslb.sgw.shopeemobile.com.",
"remote.control4.com.",
- "renfei.net.",
"repo.zabbix.com.",
"report.apkpure.net.",
- "req.adx.ws.",
- "request-global.czilladx.com.",
"resideo.com.",
+ "resolver.1.geo.ctmail.com.",
+ "resolver.2.geo.ctmail.com.",
"resolver.3.geo.ctmail.com.",
"resolver.4.geo.ctmail.com.",
"resolver.5.geo.ctmail.com.",
+ "resolver1.ast.ctmail.com.",
+ "resolver2.ast.ctmail.com.",
"resolver3.ast.ctmail.com.",
"resolver4.ast.ctmail.com.",
"resolver5.ast.ctmail.com.",
- "resources-minvest-prod.cdn-tinkoff.ru.",
"restaurantguru.com.",
+ "restproxy-analytics.ascendlearning.com.",
"restrict.youtube.com.",
"restrictmoderate.youtube.com.",
"retcode-us-west-1.arms.aliyuncs.com.",
- "retention.dewasyscrm.com.",
- "retirementpartner.com.",
- "retool.com.",
"revize.com.",
+ "rhmail.sharepoint.com.",
"ri9864.ci.managedwhitelisting.com.",
"richrelevance.com.",
"rivergame.net.",
"riverside.remotepc.com.",
+ "rl.progressive.com.",
"rl.quantummetric.com.",
"rlm.haokan.mobi.",
"rmm.trustapex.com.",
"rmm2.jmark.com.",
"rms-dra.platform.dbankcloud.com.",
"rn-resource-app.xiaohongshu.com.",
+ "ro.zoominfo.com.",
"roborock.com.",
+ "rocketsoftwareinc-my.sharepoint.com.",
+ "rockhillssch.aristotleinsight.com.",
"rockylinux.org.",
"roistat.com.",
"roockmobile.com.",
- "roseperl.com.",
+ "router-01.edge.scw.cloud.",
+ "router-02.edge.scw.cloud.",
"router.teamviewer.com.",
"roxy.azurefd.net.",
"rpt.cedexis.com.",
- "rq.upgrade.cmpc.cmcm.com.",
"rq.wh.cmcm.com.",
"rr1---sn-0nnpbo5a-bggl.googlevideo.com.",
- "rr1---sn-2aqu-hoal6.googlevideo.com.",
- "rr1---sn-2aqu-hoalk.googlevideo.com.",
"rr1---sn-2aqu-hoaly.googlevideo.com.",
"rr1---sn-2aqu-hoas7.googlevideo.com.",
- "rr1---sn-2aqu-hoasd.googlevideo.com.",
"rr1---sn-2aqu-hoasz.googlevideo.com.",
- "rr1---sn-2aqu-jbt6.googlevideo.com.",
- "rr1---sn-2aqu-jbtd.googlevideo.com.",
- "rr1---sn-2aqu-jxcr.googlevideo.com.",
- "rr1---sn-2aqu-jxcy.googlevideo.com.",
"rr1---sn-2imern76.googlevideo.com.",
"rr1---sn-2imern7d.googlevideo.com.",
+ "rr1---sn-2imern7d.gvt1.com.",
+ "rr1---sn-2imern7r.googlevideo.com.",
"rr1---sn-2imeyn7k.googlevideo.com.",
"rr1---sn-2o5ua5-53.googlevideo.com.",
"rr1---sn-2oaig5-55.googlevideo.com.",
"rr1---sn-2oq4f5-c4.googlevideo.com.",
+ "rr1---sn-2oq4f5-c4.gvt1.com.",
"rr1---sn-2ovgq5-cw.googlevideo.com.",
- "rr1---sn-30a7rne6.googlevideo.com.",
"rr1---sn-30a7rned.googlevideo.com.",
"rr1---sn-30a7rnek.googlevideo.com.",
"rr1---sn-30a7rner.googlevideo.com.",
@@ -2775,18 +3205,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-30a7yner.googlevideo.com.",
"rr1---sn-30a7yney.googlevideo.com.",
"rr1---sn-30a7ynl7.googlevideo.com.",
- "rr1---sn-3n4pcxg-pju6.googlevideo.com.",
- "rr1---sn-3n4pcxg-pjuz.googlevideo.com.",
"rr1---sn-42u-nboze.googlevideo.com.",
- "rr1---sn-42u-nbozl.googlevideo.com.",
- "rr1---sn-42u-nbozs.googlevideo.com.",
"rr1---sn-42u-nbozz.googlevideo.com.",
"rr1---sn-4g5e6ns6.googlevideo.com.",
"rr1---sn-4g5e6ns7.googlevideo.com.",
"rr1---sn-4g5e6nsd.googlevideo.com.",
"rr1---sn-4g5e6nsk.googlevideo.com.",
- "rr1---sn-4g5e6nsr.googlevideo.com.",
- "rr1---sn-4g5e6nss.googlevideo.com.",
"rr1---sn-4g5e6nsy.googlevideo.com.",
"rr1---sn-4g5e6nsz.googlevideo.com.",
"rr1---sn-4g5e6nz7.googlevideo.com.",
@@ -2803,7 +3227,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-4g5edndk.googlevideo.com.",
"rr1---sn-4g5edndl.googlevideo.com.",
"rr1---sn-4g5edndr.googlevideo.com.",
- "rr1---sn-4g5ednds.googlevideo.com.",
"rr1---sn-4g5edndy.googlevideo.com.",
"rr1---sn-4g5edndz.googlevideo.com.",
"rr1---sn-4g5ednkl.googlevideo.com.",
@@ -2815,6 +3238,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-4g5ednse.googlevideo.com.",
"rr1---sn-4g5ednsk.googlevideo.com.",
"rr1---sn-4g5ednsl.googlevideo.com.",
+ "rr1---sn-4g5ednsr.googlevideo.com.",
"rr1---sn-4g5ednss.googlevideo.com.",
"rr1---sn-4g5ednsy.googlevideo.com.",
"rr1---sn-4g5ednsz.googlevideo.com.",
@@ -2826,29 +3250,19 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-4g5lznes.googlevideo.com.",
"rr1---sn-4g5lzney.googlevideo.com.",
"rr1---sn-4g5lznez.googlevideo.com.",
+ "rr1---sn-4g5lznl6.googlevideo.com.",
"rr1---sn-4g5lznl7.googlevideo.com.",
"rr1---sn-4g5lznle.googlevideo.com.",
"rr1---sn-4g5lznls.googlevideo.com.",
"rr1---sn-4g5lznlz.googlevideo.com.",
- "rr1---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
"rr1---sn-5abxgpxuxaxjvh-9n4s.googlevideo.com.",
"rr1---sn-5abxgpxuxaxjvh-9n4z.googlevideo.com.",
- "rr1---sn-5abxgpxuxaxjvh-cawl.googlevideo.com.",
- "rr1---sn-5abxgpxuxaxjvh-caws.googlevideo.com.",
- "rr1---sn-5abxgpxuxaxjvh-j1ae.googlevideo.com.",
- "rr1---sn-5abxgpxuxaxjvh-j1as.googlevideo.com.",
- "rr1---sn-5abxgpxuxaxjvh-j1az.googlevideo.com.",
- "rr1---sn-5axnug5-hxm6.googlevideo.com.",
- "rr1---sn-5go7yner.googlevideo.com.",
- "rr1---sn-5go7ynl6.googlevideo.com.",
- "rr1---sn-5go7ynld.googlevideo.com.",
"rr1---sn-5goeenes.googlevideo.com.",
- "rr1---sn-5goeenez.googlevideo.com.",
+ "rr1---sn-5gxo-in8l.googlevideo.com.",
+ "rr1---sn-5gxo-in8s.googlevideo.com.",
"rr1---sn-5hne6n6e.googlevideo.com.",
"rr1---sn-5hne6ns6.googlevideo.com.",
"rr1---sn-5hne6nsd.googlevideo.com.",
- "rr1---sn-5hne6nsk.googlevideo.com.",
- "rr1---sn-5hne6nsr.googlevideo.com.",
"rr1---sn-5hne6nsy.googlevideo.com.",
"rr1---sn-5hne6nsz.googlevideo.com.",
"rr1---sn-5hne6nz6.googlevideo.com.",
@@ -2856,7 +3270,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-5hne6nzs.googlevideo.com.",
"rr1---sn-5hne6nzy.googlevideo.com.",
"rr1---sn-5hnednss.googlevideo.com.",
- "rr1---sn-5hnednsz.googlevideo.com.",
"rr1---sn-5hnekn76.googlevideo.com.",
"rr1---sn-5hnekn7d.googlevideo.com.",
"rr1---sn-5hnekn7l.googlevideo.com.",
@@ -2865,7 +3278,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-5hneknee.googlevideo.com.",
"rr1---sn-5hneknek.googlevideo.com.",
"rr1---sn-5hneknes.googlevideo.com.",
- "rr1---sn-5uaezndd.googlevideo.com.",
+ "rr1---sn-5pgnugx5h-hn26.googlevideo.com.",
+ "rr1---sn-5pgnugx5h-hn2d.googlevideo.com.",
+ "rr1---sn-5pgnugx5h-hn2k.googlevideo.com.",
"rr1---sn-5uaezne6.googlevideo.com.",
"rr1---sn-5uaezned.googlevideo.com.",
"rr1---sn-5uaeznel.googlevideo.com.",
@@ -2876,6 +3291,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-5uaeznls.googlevideo.com.",
"rr1---sn-5uaeznly.googlevideo.com.",
"rr1---sn-5uaeznlz.googlevideo.com.",
+ "rr1---sn-5uaeznse.googlevideo.com.",
"rr1---sn-5uaeznsl.googlevideo.com.",
"rr1---sn-5uaeznss.googlevideo.com.",
"rr1---sn-5uaezny6.googlevideo.com.",
@@ -2896,39 +3312,29 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-5ualdnsz.googlevideo.com.",
"rr1---sn-5ualdnz7.googlevideo.com.",
"rr1---sn-5ualdnze.googlevideo.com.",
- "rr1---sn-8pxuuxa-nbo6s.googlevideo.com.",
- "rr1---sn-8pxuuxa-nboz6.googlevideo.com.",
- "rr1---sn-8qj-i2ies.googlevideo.com.",
- "rr1---sn-8qj-i5o6k.googlevideo.com.",
- "rr1---sn-8qj-i5ody.googlevideo.com.",
"rr1---sn-8qj-i5okl.googlevideo.com.",
- "rr1---sn-8qj-i5oks.googlevideo.com.",
"rr1---sn-8qj-i5ozd.googlevideo.com.",
- "rr1---sn-8qj-i5ozr.googlevideo.com.",
- "rr1---sn-8qj-i5ozz.googlevideo.com.",
"rr1---sn-8qj-nbo66.googlevideo.com.",
- "rr1---sn-8qj-nbo67.googlevideo.com.",
"rr1---sn-8qj-nbo6y.googlevideo.com.",
"rr1---sn-8qj-nbod6.googlevideo.com.",
- "rr1---sn-8qj-nbod7.googlevideo.com.",
"rr1---sn-8xgp1vo-ab56.googlevideo.com.",
"rr1---sn-8xgp1vo-ab5d.googlevideo.com.",
+ "rr1---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr1---sn-8xgp1vo-ab5l.googlevideo.com.",
"rr1---sn-8xgp1vo-ab5s.googlevideo.com.",
- "rr1---sn-8xgp1vo-ab5z.googlevideo.com.",
- "rr1---sn-8xgp1vo-nh4e.googlevideo.com.",
- "rr1---sn-8xgp1vo-nh4l.googlevideo.com.",
+ "rr1---sn-8xgp1vo-p5il.googlevideo.com.",
+ "rr1---sn-8xgp1vo-p5qee.googlevideo.com.",
+ "rr1---sn-8xgp1vo-p5qel.googlevideo.com.",
+ "rr1---sn-8xgp1vo-p5qes.googlevideo.com.",
"rr1---sn-8xgp1vo-poql.googlevideo.com.",
+ "rr1---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr1---sn-8xgp1vo-xfge.googlevideo.com.",
+ "rr1---sn-8xgp1vo-xfgl.googlevideo.com.",
"rr1---sn-8xgp1vo-xfgs.googlevideo.com.",
- "rr1---sn-9gv76n7e.googlevideo.com.",
- "rr1---sn-9gv76n7l.googlevideo.com.",
"rr1---sn-9gv76n7s.googlevideo.com.",
"rr1---sn-9gv76n7z.googlevideo.com.",
- "rr1---sn-9gv7ene6.googlevideo.com.",
"rr1---sn-9gv7zn76.googlevideo.com.",
"rr1---sn-9gv7zn7e.googlevideo.com.",
- "rr1---sn-9gv7zn7r.googlevideo.com.",
"rr1---sn-9gv7zn7y.googlevideo.com.",
"rr1---sn-a5m7lnl6.googlevideo.com.",
"rr1---sn-a5m7lnld.googlevideo.com.",
@@ -2965,7 +3371,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-a5msenle.googlevideo.com.",
"rr1---sn-ab5l6ndr.googlevideo.com.",
"rr1---sn-ab5l6ndy.googlevideo.com.",
- "rr1---sn-ab5l6nk6.googlevideo.com.",
"rr1---sn-ab5l6nkd.googlevideo.com.",
"rr1---sn-ab5l6nr6.googlevideo.com.",
"rr1---sn-ab5l6nrd.googlevideo.com.",
@@ -3016,23 +3421,34 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-aigzrnsz.googlevideo.com.",
"rr1---sn-aigzrnz7.googlevideo.com.",
"rr1---sn-aigzrnze.googlevideo.com.",
+ "rr1---sn-aj4g55-5v.googlevideo.com.",
"rr1---sn-ajab55-55.googlevideo.com.",
"rr1---sn-avbpj-cq5e.googlevideo.com.",
- "rr1---sn-b5hh503-h5oe.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
"rr1---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxqjvhj5nu-vgqz.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxqjvm-2ime.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
+ "rr1---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
"rr1---sn-cvb7lne7.googlevideo.com.",
"rr1---sn-cvb7lnee.googlevideo.com.",
"rr1---sn-cvb7lnlz.googlevideo.com.",
"rr1---sn-cvb7sn7k.googlevideo.com.",
"rr1---sn-cvb7sn7r.googlevideo.com.",
- "rr1---sn-gxuo03g-ig3e.googlevideo.com.",
"rr1---sn-gxuo03g-ig3l.googlevideo.com.",
- "rr1---sn-h0jeenl6.googlevideo.com.",
- "rr1---sn-h0jeenle.googlevideo.com.",
- "rr1---sn-h0jelne6.googlevideo.com.",
- "rr1---sn-h0jelnes.googlevideo.com.",
- "rr1---sn-h0jelnez.googlevideo.com.",
- "rr1---sn-hgn7rn7y.googlevideo.com.",
+ "rr1---sn-hjoj-poul.googlevideo.com.",
+ "rr1---sn-hjoj-pous.googlevideo.com.",
"rr1---sn-hoa7kn76.googlevideo.com.",
"rr1---sn-hoa7kn76.gvt1.com.",
"rr1---sn-hoa7kn7z.googlevideo.com.",
@@ -3042,33 +3458,34 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-hoa7rn7z.googlevideo.com.",
"rr1---sn-hoa7rn7z.gvt1.com.",
"rr1---sn-hp57kn6r.googlevideo.com.",
+ "rr1---sn-hp57kn6r.gvt1.com.",
"rr1---sn-hp57kn6y.googlevideo.com.",
"rr1---sn-hp57knd6.googlevideo.com.",
"rr1---sn-hp57kndd.googlevideo.com.",
- "rr1---sn-hp57kndd.gvt1.com.",
"rr1---sn-hp57kndk.googlevideo.com.",
- "rr1---sn-hp57kndk.gvt1.com.",
"rr1---sn-hp57kndr.googlevideo.com.",
- "rr1---sn-hp57kndr.gvt1.com.",
"rr1---sn-hp57knds.googlevideo.com.",
"rr1---sn-hp57kndy.googlevideo.com.",
+ "rr1---sn-hp57kndy.gvt1.com.",
"rr1---sn-hp57kndz.googlevideo.com.",
"rr1---sn-hp57knk7.googlevideo.com.",
"rr1---sn-hp57yn7r.googlevideo.com.",
"rr1---sn-hp57yn7y.googlevideo.com.",
"rr1---sn-hp57yne7.googlevideo.com.",
"rr1---sn-hp57ynee.googlevideo.com.",
+ "rr1---sn-hp57ynl6.googlevideo.com.",
"rr1---sn-hp57ynlr.googlevideo.com.",
"rr1---sn-hp57ynly.googlevideo.com.",
"rr1---sn-hp57yns7.googlevideo.com.",
+ "rr1---sn-hp57yns7.gvt1.com.",
"rr1---sn-hp57ynse.googlevideo.com.",
"rr1---sn-hp57ynsl.googlevideo.com.",
+ "rr1---sn-hp57ynsl.gvt1.com.",
"rr1---sn-hp57ynss.googlevideo.com.",
- "rr1---sn-hp57ynss.gvt1.com.",
"rr1---sn-hpqfxnu-oaxe.googlevideo.com.",
"rr1---sn-hpqfxnu-oaxl.googlevideo.com.",
- "rr1---sn-huxaqvv-ubqe.googlevideo.com.",
- "rr1---sn-huxaqvv-ubql.googlevideo.com.",
+ "rr1---sn-hvgxoxu-jv0l.googlevideo.com.",
+ "rr1---sn-hvgxoxu-jv0s.googlevideo.com.",
"rr1---sn-i3b7kn6s.googlevideo.com.",
"rr1---sn-i3b7knld.googlevideo.com.",
"rr1---sn-i3b7knlk.googlevideo.com.",
@@ -3081,15 +3498,20 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-i3belney.googlevideo.com.",
"rr1---sn-i3belnl6.googlevideo.com.",
"rr1---sn-i3belnl7.googlevideo.com.",
- "rr1---sn-i3belnll.googlevideo.com.",
"rr1---sn-i3belnls.googlevideo.com.",
"rr1---sn-i3bssn7e.googlevideo.com.",
+ "rr1---sn-jn2pgx4pcxg-w5o6.googlevideo.com.",
+ "rr1---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr1---sn-jn2pgx4pcxg-w5oz.googlevideo.com.",
"rr1---sn-jvhh4pcgx-ajte.googlevideo.com.",
"rr1---sn-jvhh4pcgx-ajtl.googlevideo.com.",
- "rr1---sn-jvhj5nu-nh4e.googlevideo.com.",
- "rr1---sn-jvhj5nu-nh4l.googlevideo.com.",
- "rr1---sn-jvhj5nu-nh4s.googlevideo.com.",
- "rr1---sn-jvhj5nu-nh4z.googlevideo.com.",
+ "rr1---sn-jxopj-n5oe.googlevideo.com.",
+ "rr1---sn-jxopj-nh4e.googlevideo.com.",
+ "rr1---sn-jxopj-nh4e.gvt1.com.",
+ "rr1---sn-n2uxaxjvh-j5xl.googlevideo.com.",
+ "rr1---sn-n2uxaxjvh-j5xl.gvt1.com.",
+ "rr1---sn-n2uxaxjvh-j5xs.googlevideo.com.",
+ "rr1---sn-n2uxaxjvh-j5xs.gvt1.com.",
"rr1---sn-n4v7snee.googlevideo.com.",
"rr1---sn-n4v7sney.googlevideo.com.",
"rr1---sn-n4v7snl7.googlevideo.com.",
@@ -3099,20 +3521,21 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-n4v7snly.googlevideo.com.",
"rr1---sn-n4v7sns7.googlevideo.com.",
"rr1---sn-n4v7snse.googlevideo.com.",
+ "rr1---sn-nh5gujvh-h4xe.googlevideo.com.",
+ "rr1---sn-nh5gujvh-h4xe.gvt1.com.",
+ "rr1---sn-nh5gujvh-h4xl.googlevideo.com.",
+ "rr1---sn-nh5gujvh-h4xl.gvt1.com.",
"rr1---sn-npoe7ndl.googlevideo.com.",
- "rr1---sn-npoe7ndl.gvt1.com.",
"rr1---sn-npoe7ne6.googlevideo.com.",
"rr1---sn-npoe7ne7.googlevideo.com.",
"rr1---sn-npoe7ned.googlevideo.com.",
"rr1---sn-npoe7nek.googlevideo.com.",
- "rr1---sn-npoe7ner.googlevideo.com.",
"rr1---sn-npoe7nes.googlevideo.com.",
"rr1---sn-npoe7ney.googlevideo.com.",
"rr1---sn-npoe7nez.googlevideo.com.",
"rr1---sn-npoe7nl6.googlevideo.com.",
"rr1---sn-npoe7nlz.googlevideo.com.",
"rr1---sn-npoe7ns6.googlevideo.com.",
- "rr1---sn-npoe7ns6.gvt1.com.",
"rr1---sn-npoe7ns7.googlevideo.com.",
"rr1---sn-npoe7ns7.gvt1.com.",
"rr1---sn-npoe7nsd.googlevideo.com.",
@@ -3121,11 +3544,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-npoe7nsl.googlevideo.com.",
"rr1---sn-npoe7nsr.googlevideo.com.",
"rr1---sn-npoe7nsr.gvt1.com.",
- "rr1---sn-npoe7nss.googlevideo.com.",
- "rr1---sn-npoe7nss.gvt1.com.",
"rr1---sn-npoe7nsy.googlevideo.com.",
"rr1---sn-npoe7nz7.googlevideo.com.",
- "rr1---sn-npoe7nz7.gvt1.com.",
"rr1---sn-npoeene6.googlevideo.com.",
"rr1---sn-npoeened.googlevideo.com.",
"rr1---sn-npoeenee.googlevideo.com.",
@@ -3133,42 +3553,33 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-npoeener.googlevideo.com.",
"rr1---sn-npoeeney.googlevideo.com.",
"rr1---sn-npoeenez.googlevideo.com.",
- "rr1---sn-npoeenl7.googlevideo.com.",
"rr1---sn-npoeenle.googlevideo.com.",
"rr1---sn-npoeenlk.googlevideo.com.",
- "rr1---sn-npoeenlk.gvt1.com.",
"rr1---sn-npoeenll.googlevideo.com.",
"rr1---sn-npoeenly.googlevideo.com.",
- "rr1---sn-npoeenly.gvt1.com.",
"rr1---sn-npoeens7.googlevideo.com.",
- "rr1---sn-npoeens7.gvt1.com.",
"rr1---sn-npoldn76.googlevideo.com.",
- "rr1---sn-npoldn76.gvt1.com.",
"rr1---sn-npoldn7d.googlevideo.com.",
"rr1---sn-npoldn7d.gvt1.com.",
"rr1---sn-npoldn7e.googlevideo.com.",
- "rr1---sn-npoldn7e.gvt1.com.",
"rr1---sn-npoldn7l.googlevideo.com.",
"rr1---sn-npoldn7l.gvt1.com.",
- "rr1---sn-npoldn7s.googlevideo.com.",
"rr1---sn-npoldn7y.googlevideo.com.",
"rr1---sn-npoldn7y.gvt1.com.",
"rr1---sn-npoldn7z.googlevideo.com.",
- "rr1---sn-npoldn7z.gvt1.com.",
"rr1---sn-npoldne7.googlevideo.com.",
- "rr1---sn-npoldne7.gvt1.com.",
- "rr1---sn-ntqe6nee.googlevideo.com.",
- "rr1---sn-nv47ln6e.googlevideo.com.",
- "rr1---sn-nv47zn7y.googlevideo.com.",
- "rr1---sn-nv47zne7.googlevideo.com.",
- "rr1---sn-nv47znee.googlevideo.com.",
- "rr1---sn-nv47znel.googlevideo.com.",
+ "rr1---sn-nv0uixgo-5ual.googlevideo.com.",
+ "rr1---sn-nx57ynlk.googlevideo.com.",
"rr1---sn-nx57ynsd.googlevideo.com.",
"rr1---sn-nx57ynse.googlevideo.com.",
"rr1---sn-nx57ynsk.googlevideo.com.",
"rr1---sn-nx57ynsl.googlevideo.com.",
+ "rr1---sn-nx57ynsr.googlevideo.com.",
"rr1---sn-nx57ynss.googlevideo.com.",
+ "rr1---sn-nx57ynsy.googlevideo.com.",
"rr1---sn-nx57ynsz.googlevideo.com.",
+ "rr1---sn-nx57ynz7.googlevideo.com.",
+ "rr1---sn-nx57ynze.googlevideo.com.",
"rr1---sn-o097znsd.googlevideo.com.",
"rr1---sn-o097znse.googlevideo.com.",
"rr1---sn-o097znsk.googlevideo.com.",
@@ -3183,12 +3594,15 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-o097znzr.googlevideo.com.",
"rr1---sn-oj5hn5-55.googlevideo.com.",
"rr1---sn-oji3bc-5j.googlevideo.com.",
+ "rr1---sn-ojnpo5-58.googlevideo.com.",
"rr1---sn-p5qddn76.googlevideo.com.",
"rr1---sn-p5qddn7d.googlevideo.com.",
"rr1---sn-p5qddn7k.googlevideo.com.",
"rr1---sn-p5qddn7r.googlevideo.com.",
"rr1---sn-p5qddn7z.googlevideo.com.",
"rr1---sn-p5qlsn6l.googlevideo.com.",
+ "rr1---sn-p5qlsn6s.googlevideo.com.",
+ "rr1---sn-p5qlsn6z.googlevideo.com.",
"rr1---sn-p5qlsn76.googlevideo.com.",
"rr1---sn-p5qlsn7d.googlevideo.com.",
"rr1---sn-p5qlsn7l.googlevideo.com.",
@@ -3201,25 +3615,40 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-p5qlsnrr.googlevideo.com.",
"rr1---sn-p5qlsny6.googlevideo.com.",
"rr1---sn-p5qs7n6d.googlevideo.com.",
+ "rr1---sn-p5qs7n6y.googlevideo.com.",
+ "rr1---sn-p5qs7nd7.googlevideo.com.",
"rr1---sn-p5qs7nsk.googlevideo.com.",
- "rr1---sn-p5qs7nsr.googlevideo.com.",
"rr1---sn-p5qs7nzk.googlevideo.com.",
"rr1---sn-p5qs7nzr.googlevideo.com.",
"rr1---sn-p5qs7nzy.googlevideo.com.",
+ "rr1---sn-paapovpnjxou0gt-nual.googlevideo.com.",
+ "rr1---sn-paapovpnjxou0gt-nuas.googlevideo.com.",
+ "rr1---sn-paapovpnjxou0gt-nuaz.googlevideo.com.",
"rr1---sn-pjnpu-5hfe.googlevideo.com.",
"rr1---sn-pjnpu-5hfl.googlevideo.com.",
- "rr1---sn-pouxgoxm5-cvbe.googlevideo.com.",
+ "rr1---sn-pobpb-poql.googlevideo.com.",
"rr1---sn-q4fl6n66.googlevideo.com.",
+ "rr1---sn-q4fl6n66.gvt1.com.",
"rr1---sn-q4fl6n6d.googlevideo.com.",
"rr1---sn-q4fl6n6r.googlevideo.com.",
+ "rr1---sn-q4fl6n6r.gvt1.com.",
"rr1---sn-q4fl6n6s.googlevideo.com.",
+ "rr1---sn-q4fl6n6s.gvt1.com.",
"rr1---sn-q4fl6n6y.googlevideo.com.",
+ "rr1---sn-q4fl6n6y.gvt1.com.",
"rr1---sn-q4fl6n6z.googlevideo.com.",
+ "rr1---sn-q4fl6n6z.gvt1.com.",
+ "rr1---sn-q4fl6nd6.googlevideo.com.",
"rr1---sn-q4fl6nd7.googlevideo.com.",
+ "rr1---sn-q4fl6nd7.gvt1.com.",
"rr1---sn-q4fl6nde.googlevideo.com.",
+ "rr1---sn-q4fl6nde.gvt1.com.",
"rr1---sn-q4fl6ndl.googlevideo.com.",
+ "rr1---sn-q4fl6ndl.gvt1.com.",
"rr1---sn-q4fl6nds.googlevideo.com.",
+ "rr1---sn-q4fl6nds.gvt1.com.",
"rr1---sn-q4fl6ndz.googlevideo.com.",
+ "rr1---sn-q4fl6ndz.gvt1.com.",
"rr1---sn-q4fl6nlz.googlevideo.com.",
"rr1---sn-q4fl6ns6.googlevideo.com.",
"rr1---sn-q4fl6ns7.googlevideo.com.",
@@ -3228,45 +3657,67 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-q4fl6nsl.googlevideo.com.",
"rr1---sn-q4fl6nsr.googlevideo.com.",
"rr1---sn-q4fl6nss.googlevideo.com.",
+ "rr1---sn-q4fl6nss.gvt1.com.",
"rr1---sn-q4fl6nsy.googlevideo.com.",
+ "rr1---sn-q4fl6nsy.gvt1.com.",
"rr1---sn-q4fl6nz6.googlevideo.com.",
+ "rr1---sn-q4fl6nz6.gvt1.com.",
"rr1---sn-q4fl6nz7.googlevideo.com.",
"rr1---sn-q4fl6nzy.googlevideo.com.",
+ "rr1---sn-q4fl6nzy.gvt1.com.",
+ "rr1---sn-q4flrn7k.googlevideo.com.",
"rr1---sn-q4flrn7r.googlevideo.com.",
"rr1---sn-q4flrn7y.googlevideo.com.",
"rr1---sn-q4flrne6.googlevideo.com.",
"rr1---sn-q4flrne7.googlevideo.com.",
+ "rr1---sn-q4flrne7.gvt1.com.",
"rr1---sn-q4flrnee.googlevideo.com.",
+ "rr1---sn-q4flrnee.gvt1.com.",
"rr1---sn-q4flrnek.googlevideo.com.",
"rr1---sn-q4flrnel.googlevideo.com.",
"rr1---sn-q4flrner.googlevideo.com.",
+ "rr1---sn-q4flrner.gvt1.com.",
"rr1---sn-q4flrnes.googlevideo.com.",
"rr1---sn-q4flrney.googlevideo.com.",
"rr1---sn-q4flrnez.googlevideo.com.",
"rr1---sn-q4flrnl6.googlevideo.com.",
"rr1---sn-q4flrnl7.googlevideo.com.",
"rr1---sn-q4flrnld.googlevideo.com.",
+ "rr1---sn-q4flrnld.gvt1.com.",
"rr1---sn-q4flrnle.googlevideo.com.",
"rr1---sn-q4flrnlz.googlevideo.com.",
"rr1---sn-q4flrnsd.googlevideo.com.",
+ "rr1---sn-q4flrnsd.gvt1.com.",
"rr1---sn-q4flrnsk.googlevideo.com.",
- "rr1---sn-q4flrnsl.googlevideo.com.",
"rr1---sn-q4flrnss.googlevideo.com.",
+ "rr1---sn-q4fzen7e.googlevideo.com.",
+ "rr1---sn-q4fzen7e.gvt1.com.",
"rr1---sn-q4fzen7l.googlevideo.com.",
+ "rr1---sn-q4fzen7l.gvt1.com.",
"rr1---sn-q4fzen7s.googlevideo.com.",
+ "rr1---sn-q4fzen7s.gvt1.com.",
"rr1---sn-q4fzen7y.googlevideo.com.",
"rr1---sn-q4fzene7.googlevideo.com.",
+ "rr1---sn-q4fzene7.gvt1.com.",
"rr1---sn-q4fzenee.googlevideo.com.",
+ "rr1---sn-q4fzenee.gvt1.com.",
"rr1---sn-qja5mc-5h.googlevideo.com.",
"rr1---sn-qjp5q5-55.googlevideo.com.",
"rr1---sn-qxo7rn7k.googlevideo.com.",
- "rr1---sn-qxo7rn7r.googlevideo.com.",
- "rr1---sn-qxo7rn7y.googlevideo.com.",
+ "rr1---sn-qxo7rne7.googlevideo.com.",
+ "rr1---sn-qxo7rnee.googlevideo.com.",
"rr1---sn-qxoedn7k.googlevideo.com.",
"rr1---sn-qxoedne7.googlevideo.com.",
"rr1---sn-qxoednee.googlevideo.com.",
- "rr1---sn-t0aedn7l.googlevideo.com.",
+ "rr1---sn-qxoednel.googlevideo.com.",
+ "rr1---sn-qxoednes.googlevideo.com.",
+ "rr1---sn-qxuxa-5xme.googlevideo.com.",
"rr1---sn-u1hp55-5c.googlevideo.com.",
+ "rr1---sn-u1hp55-5c.gvt1.com.",
+ "rr1---sn-v5goxu-jhi6.googlevideo.com.",
+ "rr1---sn-v5goxu-jhid.googlevideo.com.",
+ "rr1---sn-v5goxu-jhil.googlevideo.com.",
+ "rr1---sn-v5goxu-jhiz.googlevideo.com.",
"rr1---sn-vgqskn66.googlevideo.com.",
"rr1---sn-vgqskn67.googlevideo.com.",
"rr1---sn-vgqskn6d.googlevideo.com.",
@@ -3280,6 +3731,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-vgqsknld.googlevideo.com.",
"rr1---sn-vgqsknlk.googlevideo.com.",
"rr1---sn-vgqsknll.googlevideo.com.",
+ "rr1---sn-vgqsknlr.googlevideo.com.",
"rr1---sn-vgqsknls.googlevideo.com.",
"rr1---sn-vgqsknlz.googlevideo.com.",
"rr1---sn-vgqskns7.googlevideo.com.",
@@ -3300,6 +3752,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-vgqsrn6e.googlevideo.com.",
"rr1---sn-vgqsrn6l.googlevideo.com.",
"rr1---sn-vgqsrn6z.googlevideo.com.",
+ "rr1---sn-vgqsrn6z.gvt1.com.",
"rr1---sn-vgqsrne6.googlevideo.com.",
"rr1---sn-vgqsrned.googlevideo.com.",
"rr1---sn-vgqsrnek.googlevideo.com.",
@@ -3315,7 +3768,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-vgqsrnsd.googlevideo.com.",
"rr1---sn-vgqsrnsr.googlevideo.com.",
"rr1---sn-vgqsrnsy.googlevideo.com.",
- "rr1---sn-vgqsrnz6.googlevideo.com.",
"rr1---sn-vgqsrnz7.googlevideo.com.",
"rr1---sn-vgqsrnzd.googlevideo.com.",
"rr1---sn-vgqsrnzk.googlevideo.com.",
@@ -3325,39 +3777,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-vgqsrnzz.googlevideo.com.",
"rr1---sn-voxoxu-v3jl.googlevideo.com.",
"rr1---sn-voxoxu-v3js.googlevideo.com.",
- "rr1.sn-2oq4f5-c4.googlevideo.com.",
- "rr1.sn-2ovgq5-cw.googlevideo.com.",
- "rr1.sn-4g5e6nze.googlevideo.com.",
- "rr1.sn-a5m7lnl6.googlevideo.com.",
- "rr1.sn-a5m7lnld.googlevideo.com.",
- "rr1.sn-a5mekn6d.googlevideo.com.",
- "rr1.sn-a5mekn6k.googlevideo.com.",
- "rr1.sn-a5mekn6l.googlevideo.com.",
- "rr1.sn-a5mekn6r.googlevideo.com.",
- "rr1.sn-a5mekn6s.googlevideo.com.",
- "rr1.sn-a5mekn6z.googlevideo.com.",
- "rr1.sn-a5meknd6.googlevideo.com.",
- "rr1.sn-a5meknde.googlevideo.com.",
- "rr1.sn-a5mekndl.googlevideo.com.",
- "rr1.sn-a5meknds.googlevideo.com.",
- "rr1.sn-a5mekndz.googlevideo.com.",
- "rr1.sn-a5meknsd.googlevideo.com.",
- "rr1.sn-a5meknsy.googlevideo.com.",
- "rr1.sn-a5meknzk.googlevideo.com.",
- "rr1.sn-a5meknzr.googlevideo.com.",
- "rr1.sn-a5mlrnek.googlevideo.com.",
- "rr1.sn-a5mlrnl6.googlevideo.com.",
- "rr1.sn-a5mlrnll.googlevideo.com.",
- "rr1.sn-a5mlrnls.googlevideo.com.",
- "rr1.sn-a5mlrnlz.googlevideo.com.",
- "rr1.sn-a5msen76.googlevideo.com.",
- "rr1.sn-a5msen7l.googlevideo.com.",
- "rr1.sn-a5msenek.googlevideo.com.",
- "rr1.sn-a5msener.googlevideo.com.",
- "rr1.sn-a5msenes.googlevideo.com.",
- "rr1.sn-a5msenl7.googlevideo.com.",
- "rr1.sn-a5msenle.googlevideo.com.",
- "rr1.sn-hgn7rn7y.googlevideo.com.",
+ "rr1.sn-5hne6nsz.googlevideo.com.",
+ "rr1.sn-5hneknek.googlevideo.com.",
"rr1.sn-hp57kn6r.googlevideo.com.",
"rr1.sn-hp57kn6y.googlevideo.com.",
"rr1.sn-hp57knd6.googlevideo.com.",
@@ -3368,151 +3789,140 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1.sn-hp57kndy.googlevideo.com.",
"rr1.sn-hp57kndz.googlevideo.com.",
"rr1.sn-hp57knk7.googlevideo.com.",
- "rr1.sn-hp57yn7r.googlevideo.com.",
- "rr1.sn-hp57yn7y.googlevideo.com.",
+ "rr1.sn-hp57ynl6.googlevideo.com.",
"rr1.sn-hp57ynlr.googlevideo.com.",
"rr1.sn-hp57ynly.googlevideo.com.",
"rr1.sn-hp57yns7.googlevideo.com.",
"rr1.sn-hp57ynse.googlevideo.com.",
"rr1.sn-hp57ynsl.googlevideo.com.",
"rr1.sn-hp57ynss.googlevideo.com.",
- "rr1.sn-ntqe6nee.googlevideo.com.",
"rr1.sn-nx57ynsk.googlevideo.com.",
"rr1.sn-q4fl6n6d.googlevideo.com.",
"rr1.sn-q4fl6n6r.googlevideo.com.",
- "rr1.sn-q4fl6n6z.googlevideo.com.",
- "rr1.sn-q4fl6ndz.googlevideo.com.",
- "rr1.sn-q4fl6ns6.googlevideo.com.",
- "rr1.sn-q4flrn7r.googlevideo.com.",
- "rr1.sn-q4flrnl6.googlevideo.com.",
- "rr1.sn-q4flrnld.googlevideo.com.",
- "rr1.sn-q4flrnle.googlevideo.com.",
- "rr1.sn-q4flrnlz.googlevideo.com.",
- "rr1.sn-q4flrnsd.googlevideo.com.",
- "rr1.sn-q4flrnsk.googlevideo.com.",
- "rr1.sn-q4flrnsl.googlevideo.com.",
- "rr1.sn-q4flrnss.googlevideo.com.",
+ "rr1.sn-q4fl6nd6.googlevideo.com.",
+ "rr1.sn-q4fl6nsl.googlevideo.com.",
+ "rr1.sn-q4flrn7k.googlevideo.com.",
+ "rr1.sn-q4flrnes.googlevideo.com.",
"rr1.sn-q4fzen7l.googlevideo.com.",
- "rr1.sn-q4fzen7s.googlevideo.com.",
- "rr1.sn-q4fzen7y.googlevideo.com.",
- "rr1.sn-q4fzene7.googlevideo.com.",
- "rr1.sn-q4fzenee.googlevideo.com.",
- "rr1.sn-qja5mc-5h.googlevideo.com.",
"rr1.sn-u1hp55-5c.googlevideo.com.",
- "rr1.sn-vgqskn66.googlevideo.com.",
- "rr1.sn-vgqskn67.googlevideo.com.",
- "rr1.sn-vgqskn6s.googlevideo.com.",
- "rr1.sn-vgqskn6z.googlevideo.com.",
- "rr1.sn-vgqsknld.googlevideo.com.",
- "rr1.sn-vgqsknlk.googlevideo.com.",
- "rr1.sn-vgqskns7.googlevideo.com.",
- "rr1.sn-vgqsknse.googlevideo.com.",
- "rr1.sn-vgqsknsk.googlevideo.com.",
- "rr1.sn-vgqsknz6.googlevideo.com.",
- "rr1.sn-vgqsknz7.googlevideo.com.",
- "rr1.sn-vgqsknzd.googlevideo.com.",
- "rr1.sn-vgqsknze.googlevideo.com.",
- "rr1.sn-vgqsknzk.googlevideo.com.",
- "rr1.sn-vgqsknzl.googlevideo.com.",
- "rr1.sn-vgqsknzr.googlevideo.com.",
- "rr1.sn-vgqsknzs.googlevideo.com.",
- "rr1.sn-vgqsknzy.googlevideo.com.",
- "rr1.sn-vgqsknzz.googlevideo.com.",
- "rr1.sn-vgqsrn67.googlevideo.com.",
- "rr1.sn-vgqsrn6e.googlevideo.com.",
- "rr1.sn-vgqsrn6l.googlevideo.com.",
- "rr1.sn-vgqsrn6z.googlevideo.com.",
- "rr1.sn-vgqsrnl6.googlevideo.com.",
- "rr1.sn-vgqsrnld.googlevideo.com.",
- "rr1.sn-vgqsrnlk.googlevideo.com.",
- "rr1.sn-vgqsrnls.googlevideo.com.",
- "rr1.sn-vgqsrnlz.googlevideo.com.",
- "rr1.sn-vgqsrns6.googlevideo.com.",
- "rr1.sn-vgqsrnsd.googlevideo.com.",
- "rr1.sn-vgqsrnsr.googlevideo.com.",
- "rr1.sn-vgqsrnsy.googlevideo.com.",
- "rr1.sn-vgqsrnz6.googlevideo.com.",
- "rr1.sn-vgqsrnz7.googlevideo.com.",
- "rr1.sn-vgqsrnzd.googlevideo.com.",
- "rr1.sn-vgqsrnzk.googlevideo.com.",
- "rr1.sn-vgqsrnzr.googlevideo.com.",
- "rr1.sn-vgqsrnzs.googlevideo.com.",
- "rr1.sn-vgqsrnzy.googlevideo.com.",
"rr1.sn-vgqsrnzz.googlevideo.com.",
- "rr10---sn-42u-nboze.googlevideo.com.",
- "rr10---sn-42u-nbozl.googlevideo.com.",
- "rr10---sn-42u-nbozs.googlevideo.com.",
- "rr10---sn-8pxuuxa-nbosd.googlevideo.com.",
"rr10---sn-8qj-i5ozd.googlevideo.com.",
"rr10---sn-8xgp1vo-ab56.googlevideo.com.",
"rr10---sn-8xgp1vo-ab5d.googlevideo.com.",
- "rr10---sn-jvhj5nu-nh4e.googlevideo.com.",
- "rr10---sn-jvhj5nu-nh4l.googlevideo.com.",
- "rr10---sn-jvhj5nu-nh4s.googlevideo.com.",
- "rr10---sn-jvhj5nu-nh4z.googlevideo.com.",
- "rr11---sn-42u-nboze.googlevideo.com.",
- "rr11---sn-42u-nbozl.googlevideo.com.",
- "rr11---sn-42u-nbozs.googlevideo.com.",
- "rr11---sn-8qj-i5ozd.googlevideo.com.",
+ "rr10---sn-8xgp1vo-p5qee.googlevideo.com.",
+ "rr10---sn-8xgp1vo-p5qel.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxqjvhj5nu-vgqz.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxqjvm-2ime.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxqjvm-2ims.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
+ "rr10---sn-bvvbaxivnuxqjvm-q4fl.gvt1.com.",
"rr11---sn-8xgp1vo-ab56.googlevideo.com.",
"rr11---sn-8xgp1vo-ab5d.googlevideo.com.",
- "rr12---sn-42u-nboze.googlevideo.com.",
- "rr12---sn-42u-nbozl.googlevideo.com.",
+ "rr11---sn-8xgp1vo-p5qee.googlevideo.com.",
+ "rr11---sn-8xgp1vo-p5qel.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvhj5nu-n4vl.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvhj5nu-vgqz.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvm-2ime.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvm-2ims.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvm-q4fe.gvt1.com.",
+ "rr11---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
+ "rr11---sn-bvvbaxivnuxqjvm-q4fl.gvt1.com.",
"rr12---sn-42u-nbozs.googlevideo.com.",
- "rr12---sn-8qj-i5ozd.googlevideo.com.",
- "rr13---sn-42u-nboze.googlevideo.com.",
- "rr13---sn-42u-nbozl.googlevideo.com.",
+ "rr12---sn-8xgp1vo-p5qel.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxqjvm-2ime.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxqjvm-2ims.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
+ "rr12---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
"rr13---sn-42u-nbozs.googlevideo.com.",
- "rr14---sn-42u-nboze.googlevideo.com.",
- "rr14---sn-42u-nbozl.googlevideo.com.",
- "rr14---sn-42u-nbozs.googlevideo.com.",
- "rr15---sn-42u-nboze.googlevideo.com.",
- "rr15---sn-42u-nbozl.googlevideo.com.",
- "rr16---sn-42u-nbozl.googlevideo.com.",
+ "rr13---sn-8xgp1vo-p5qel.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxqjvhj5nu-vgqz.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
+ "rr13---sn-bvvbaxivnuxqjvm-q4fe.gvt1.com.",
+ "rr13---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
+ "rr14---sn-bvvbaxivnuxqjvhj5nu-n4vl.googlevideo.com.",
+ "rr15---sn-bvvbaxivnuxqjvhj5nu-n4v6.googlevideo.com.",
"rr2---sn-0nnpbo5a-bggl.googlevideo.com.",
- "rr2---sn-2aqu-hoal6.googlevideo.com.",
- "rr2---sn-2aqu-hoalk.googlevideo.com.",
"rr2---sn-2aqu-hoaly.googlevideo.com.",
"rr2---sn-2aqu-hoas7.googlevideo.com.",
- "rr2---sn-2aqu-hoasd.googlevideo.com.",
- "rr2---sn-2aqu-hoasz.googlevideo.com.",
- "rr2---sn-2aqu-jbt6.googlevideo.com.",
- "rr2---sn-2aqu-jbtd.googlevideo.com.",
- "rr2---sn-2aqu-jxcr.googlevideo.com.",
- "rr2---sn-2aqu-jxcy.googlevideo.com.",
"rr2---sn-2imern76.googlevideo.com.",
"rr2---sn-2imern7d.googlevideo.com.",
+ "rr2---sn-2imern7d.gvt1.com.",
+ "rr2---sn-2imern7r.googlevideo.com.",
+ "rr2---sn-2imern7r.gvt1.com.",
"rr2---sn-2imeyn7k.googlevideo.com.",
"rr2---sn-2o5ua5-53.googlevideo.com.",
"rr2---sn-2oaig5-55.googlevideo.com.",
+ "rr2---sn-2op5q5-58.googlevideo.com.",
"rr2---sn-2oq4f5-c4.googlevideo.com.",
+ "rr2---sn-2oq4f5-c4.gvt1.com.",
"rr2---sn-2ovgq5-cw.googlevideo.com.",
- "rr2---sn-30a7rne6.googlevideo.com.",
"rr2---sn-30a7rned.googlevideo.com.",
"rr2---sn-30a7rnek.googlevideo.com.",
"rr2---sn-30a7ynek.googlevideo.com.",
"rr2---sn-30a7yner.googlevideo.com.",
"rr2---sn-30a7yney.googlevideo.com.",
"rr2---sn-30a7ynl7.googlevideo.com.",
- "rr2---sn-3n4pcxg-pju6.googlevideo.com.",
- "rr2---sn-3n4pcxg-pjuz.googlevideo.com.",
- "rr2---sn-42u-nbosk.googlevideo.com.",
- "rr2---sn-42u-nboze.googlevideo.com.",
- "rr2---sn-42u-nbozl.googlevideo.com.",
- "rr2---sn-42u-nbozs.googlevideo.com.",
"rr2---sn-42u-nbozz.googlevideo.com.",
"rr2---sn-4g5e6ns6.googlevideo.com.",
"rr2---sn-4g5e6ns7.googlevideo.com.",
"rr2---sn-4g5e6nsd.googlevideo.com.",
"rr2---sn-4g5e6nsk.googlevideo.com.",
- "rr2---sn-4g5e6nsr.googlevideo.com.",
"rr2---sn-4g5e6nss.googlevideo.com.",
"rr2---sn-4g5e6nsy.googlevideo.com.",
"rr2---sn-4g5e6nsz.googlevideo.com.",
"rr2---sn-4g5e6nz7.googlevideo.com.",
"rr2---sn-4g5e6nze.googlevideo.com.",
"rr2---sn-4g5e6nzl.googlevideo.com.",
- "rr2---sn-4g5e6nzs.googlevideo.com.",
"rr2---sn-4g5e6nzz.googlevideo.com.",
"rr2---sn-4g5edn6k.googlevideo.com.",
"rr2---sn-4g5edn6r.googlevideo.com.",
@@ -3523,7 +3933,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-4g5edndk.googlevideo.com.",
"rr2---sn-4g5edndl.googlevideo.com.",
"rr2---sn-4g5edndr.googlevideo.com.",
- "rr2---sn-4g5ednds.googlevideo.com.",
"rr2---sn-4g5edndy.googlevideo.com.",
"rr2---sn-4g5edndz.googlevideo.com.",
"rr2---sn-4g5ednkl.googlevideo.com.",
@@ -3539,6 +3948,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-4g5ednss.googlevideo.com.",
"rr2---sn-4g5ednsy.googlevideo.com.",
"rr2---sn-4g5ednsz.googlevideo.com.",
+ "rr2---sn-4g5ednz7.googlevideo.com.",
"rr2---sn-4g5lzne6.googlevideo.com.",
"rr2---sn-4g5lzned.googlevideo.com.",
"rr2---sn-4g5lznek.googlevideo.com.",
@@ -3550,22 +3960,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-4g5lznle.googlevideo.com.",
"rr2---sn-4g5lznls.googlevideo.com.",
"rr2---sn-4g5lznlz.googlevideo.com.",
- "rr2---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
"rr2---sn-5abxgpxuxaxjvh-9n4s.googlevideo.com.",
"rr2---sn-5abxgpxuxaxjvh-9n4z.googlevideo.com.",
- "rr2---sn-5abxgpxuxaxjvh-cawe.googlevideo.com.",
- "rr2---sn-5abxgpxuxaxjvh-cawl.googlevideo.com.",
- "rr2---sn-5abxgpxuxaxjvh-caws.googlevideo.com.",
- "rr2---sn-5abxgpxuxaxjvh-j1ae.googlevideo.com.",
- "rr2---sn-5abxgpxuxaxjvh-j1as.googlevideo.com.",
- "rr2---sn-5abxgpxuxaxjvh-j1az.googlevideo.com.",
- "rr2---sn-5axnug5-hxm6.googlevideo.com.",
- "rr2---sn-5go7yner.googlevideo.com.",
"rr2---sn-5go7ynl6.googlevideo.com.",
- "rr2---sn-5go7ynld.googlevideo.com.",
- "rr2---sn-5go7ynlk.googlevideo.com.",
"rr2---sn-5goeenes.googlevideo.com.",
- "rr2---sn-5goeenez.googlevideo.com.",
+ "rr2---sn-5gxo-in8l.googlevideo.com.",
+ "rr2---sn-5gxo-in8s.googlevideo.com.",
"rr2---sn-5hne6n6e.googlevideo.com.",
"rr2---sn-5hne6n6l.googlevideo.com.",
"rr2---sn-5hne6ns6.googlevideo.com.",
@@ -3576,10 +3976,13 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-5hne6nsz.googlevideo.com.",
"rr2---sn-5hne6nz6.googlevideo.com.",
"rr2---sn-5hne6nzd.googlevideo.com.",
+ "rr2---sn-5hne6nzd.gvt1.com.",
"rr2---sn-5hne6nzk.googlevideo.com.",
- "rr2---sn-5hne6nzs.googlevideo.com.",
+ "rr2---sn-5hne6nzk.gvt1.com.",
+ "rr2---sn-5hne6nzy.googlevideo.com.",
"rr2---sn-5hnednss.googlevideo.com.",
"rr2---sn-5hnednsz.googlevideo.com.",
+ "rr2---sn-5hnednsz.gvt1.com.",
"rr2---sn-5hnekn76.googlevideo.com.",
"rr2---sn-5hnekn7d.googlevideo.com.",
"rr2---sn-5hnekn7l.googlevideo.com.",
@@ -3588,20 +3991,29 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-5hneknee.googlevideo.com.",
"rr2---sn-5hneknek.googlevideo.com.",
"rr2---sn-5hneknes.googlevideo.com.",
+ "rr2---sn-5hneknes.gvt1.com.",
+ "rr2---sn-5pgnugx5h-hn26.googlevideo.com.",
+ "rr2---sn-5pgnugx5h-hn2d.googlevideo.com.",
+ "rr2---sn-5pgnugx5h-hn2k.googlevideo.com.",
"rr2---sn-5uaezndd.googlevideo.com.",
"rr2---sn-5uaezne6.googlevideo.com.",
"rr2---sn-5uaezned.googlevideo.com.",
"rr2---sn-5uaeznel.googlevideo.com.",
+ "rr2---sn-5uaezner.googlevideo.com.",
+ "rr2---sn-5uaezner.gvt1.com.",
"rr2---sn-5uaeznes.googlevideo.com.",
"rr2---sn-5uaeznez.googlevideo.com.",
"rr2---sn-5uaeznl6.googlevideo.com.",
+ "rr2---sn-5uaeznld.googlevideo.com.",
"rr2---sn-5uaeznls.googlevideo.com.",
"rr2---sn-5uaeznly.googlevideo.com.",
"rr2---sn-5uaeznlz.googlevideo.com.",
+ "rr2---sn-5uaeznlz.gvt1.com.",
"rr2---sn-5uaeznse.googlevideo.com.",
"rr2---sn-5uaeznsl.googlevideo.com.",
"rr2---sn-5uaeznss.googlevideo.com.",
"rr2---sn-5uaezny6.googlevideo.com.",
+ "rr2---sn-5uaeznyz.googlevideo.com.",
"rr2---sn-5uaeznze.googlevideo.com.",
"rr2---sn-5ualdnle.googlevideo.com.",
"rr2---sn-5ualdnll.googlevideo.com.",
@@ -3609,6 +4021,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-5ualdnls.googlevideo.com.",
"rr2---sn-5ualdns6.googlevideo.com.",
"rr2---sn-5ualdns7.googlevideo.com.",
+ "rr2---sn-5ualdns7.gvt1.com.",
"rr2---sn-5ualdnsd.googlevideo.com.",
"rr2---sn-5ualdnse.googlevideo.com.",
"rr2---sn-5ualdnsk.googlevideo.com.",
@@ -3619,39 +4032,31 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-5ualdnsz.googlevideo.com.",
"rr2---sn-5ualdnz7.googlevideo.com.",
"rr2---sn-5ualdnze.googlevideo.com.",
- "rr2---sn-8pxuuxa-nbo6l.googlevideo.com.",
- "rr2---sn-8pxuuxa-nbo6s.googlevideo.com.",
"rr2---sn-8qj-i5o6k.googlevideo.com.",
- "rr2---sn-8qj-i5ody.googlevideo.com.",
"rr2---sn-8qj-i5okl.googlevideo.com.",
- "rr2---sn-8qj-i5oks.googlevideo.com.",
- "rr2---sn-8qj-i5ozd.googlevideo.com.",
- "rr2---sn-8qj-i5ozr.googlevideo.com.",
- "rr2---sn-8qj-i5ozz.googlevideo.com.",
"rr2---sn-8qj-nbo66.googlevideo.com.",
- "rr2---sn-8qj-nbo67.googlevideo.com.",
- "rr2---sn-8qj-nbo6r.googlevideo.com.",
"rr2---sn-8qj-nbo6y.googlevideo.com.",
"rr2---sn-8qj-nbod6.googlevideo.com.",
+ "rr2---sn-8qj-nbosd.googlevideo.com.",
"rr2---sn-8xgp1vo-ab56.googlevideo.com.",
"rr2---sn-8xgp1vo-ab5d.googlevideo.com.",
+ "rr2---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr2---sn-8xgp1vo-ab5l.googlevideo.com.",
"rr2---sn-8xgp1vo-ab5s.googlevideo.com.",
"rr2---sn-8xgp1vo-ab5z.googlevideo.com.",
- "rr2---sn-8xgp1vo-nh4l.googlevideo.com.",
- "rr2---sn-8xgp1vo-poql.googlevideo.com.",
+ "rr2---sn-8xgp1vo-p5il.googlevideo.com.",
+ "rr2---sn-8xgp1vo-p5qee.googlevideo.com.",
+ "rr2---sn-8xgp1vo-p5qel.googlevideo.com.",
+ "rr2---sn-8xgp1vo-p5qes.googlevideo.com.",
+ "rr2---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr2---sn-8xgp1vo-xfge.googlevideo.com.",
"rr2---sn-8xgp1vo-xfgl.googlevideo.com.",
"rr2---sn-8xgp1vo-xfgs.googlevideo.com.",
- "rr2---sn-9gv76n7e.googlevideo.com.",
- "rr2---sn-9gv76n7l.googlevideo.com.",
"rr2---sn-9gv76n7s.googlevideo.com.",
"rr2---sn-9gv76n7z.googlevideo.com.",
- "rr2---sn-9gv7ene6.googlevideo.com.",
"rr2---sn-9gv7ened.googlevideo.com.",
"rr2---sn-9gv7zn76.googlevideo.com.",
"rr2---sn-9gv7zn7e.googlevideo.com.",
- "rr2---sn-9gv7zn7r.googlevideo.com.",
"rr2---sn-9gv7zn7y.googlevideo.com.",
"rr2---sn-a5m7lnl6.googlevideo.com.",
"rr2---sn-a5m7lnld.googlevideo.com.",
@@ -3690,7 +4095,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-ab5l6ndy.googlevideo.com.",
"rr2---sn-ab5l6nk6.googlevideo.com.",
"rr2---sn-ab5l6nkd.googlevideo.com.",
- "rr2---sn-ab5l6nr6.googlevideo.com.",
"rr2---sn-ab5l6nrd.googlevideo.com.",
"rr2---sn-ab5l6nrk.googlevideo.com.",
"rr2---sn-ab5l6nrl.googlevideo.com.",
@@ -3721,6 +4125,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-aigl6nz7.googlevideo.com.",
"rr2---sn-aigl6nze.googlevideo.com.",
"rr2---sn-aigl6nzk.googlevideo.com.",
+ "rr2---sn-aigl6nzl.googlevideo.com.",
"rr2---sn-aigl6nzr.googlevideo.com.",
"rr2---sn-aigl6nzs.googlevideo.com.",
"rr2---sn-aigzrn76.googlevideo.com.",
@@ -3738,24 +4143,36 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-aigzrnsz.googlevideo.com.",
"rr2---sn-aigzrnz7.googlevideo.com.",
"rr2---sn-aigzrnze.googlevideo.com.",
+ "rr2---sn-aj4g55-5v.googlevideo.com.",
"rr2---sn-aj5ua5-5c.googlevideo.com.",
"rr2---sn-ajab55-55.googlevideo.com.",
"rr2---sn-avbpj-cq5e.googlevideo.com.",
- "rr2---sn-b5hh503-h5oe.googlevideo.com.",
"rr2---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
- "rr2---sn-c0q7lnz7.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxqjvhj5nu-vgqz.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxqjvm-2ime.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxqjvm-2ims.googlevideo.com.",
+ "rr2---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
"rr2---sn-cvb7lne7.googlevideo.com.",
"rr2---sn-cvb7lnee.googlevideo.com.",
+ "rr2---sn-cvb7lnlz.googlevideo.com.",
"rr2---sn-cvb7sn7k.googlevideo.com.",
"rr2---sn-cvb7sn7r.googlevideo.com.",
- "rr2---sn-gxuo03g-3c2l.googlevideo.com.",
"rr2---sn-gxuo03g-ig3l.googlevideo.com.",
- "rr2---sn-h0jeenl6.googlevideo.com.",
- "rr2---sn-h0jeenld.googlevideo.com.",
- "rr2---sn-h0jeenle.googlevideo.com.",
- "rr2---sn-h0jelnes.googlevideo.com.",
- "rr2---sn-h0jelnez.googlevideo.com.",
- "rr2---sn-hgn7rnll.googlevideo.com.",
+ "rr2---sn-hjoj-gq0l.googlevideo.com.",
+ "rr2---sn-hjoj-poul.googlevideo.com.",
+ "rr2---sn-hjoj-pous.googlevideo.com.",
"rr2---sn-hoa7kn76.googlevideo.com.",
"rr2---sn-hoa7kn76.gvt1.com.",
"rr2---sn-hoa7rn76.googlevideo.com.",
@@ -3763,10 +4180,11 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-hoa7rn7z.googlevideo.com.",
"rr2---sn-hoa7rn7z.gvt1.com.",
"rr2---sn-hp57kn6r.googlevideo.com.",
+ "rr2---sn-hp57kn6r.gvt1.com.",
"rr2---sn-hp57kn6y.googlevideo.com.",
"rr2---sn-hp57knd6.googlevideo.com.",
+ "rr2---sn-hp57knd6.gvt1.com.",
"rr2---sn-hp57kndd.googlevideo.com.",
- "rr2---sn-hp57kndd.gvt1.com.",
"rr2---sn-hp57kndk.googlevideo.com.",
"rr2---sn-hp57kndr.googlevideo.com.",
"rr2---sn-hp57kndr.gvt1.com.",
@@ -3775,20 +4193,22 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-hp57kndz.googlevideo.com.",
"rr2---sn-hp57kndz.gvt1.com.",
"rr2---sn-hp57knk7.googlevideo.com.",
+ "rr2---sn-hp57knk7.gvt1.com.",
"rr2---sn-hp57yn7r.googlevideo.com.",
"rr2---sn-hp57yn7y.googlevideo.com.",
"rr2---sn-hp57yne7.googlevideo.com.",
"rr2---sn-hp57ynee.googlevideo.com.",
- "rr2---sn-hp57ynl6.googlevideo.com.",
"rr2---sn-hp57ynlr.googlevideo.com.",
"rr2---sn-hp57ynly.googlevideo.com.",
"rr2---sn-hp57yns7.googlevideo.com.",
+ "rr2---sn-hp57yns7.gvt1.com.",
"rr2---sn-hp57ynse.googlevideo.com.",
"rr2---sn-hp57ynsl.googlevideo.com.",
+ "rr2---sn-hp57ynsl.gvt1.com.",
"rr2---sn-hpqfxnu-oaxe.googlevideo.com.",
"rr2---sn-hpqfxnu-oaxl.googlevideo.com.",
- "rr2---sn-huxaqvv-ubqe.googlevideo.com.",
- "rr2---sn-huxaqvv-ubql.googlevideo.com.",
+ "rr2---sn-hvgxoxu-jv0l.googlevideo.com.",
+ "rr2---sn-hvgxoxu-jv0s.googlevideo.com.",
"rr2---sn-i3b7kn6s.googlevideo.com.",
"rr2---sn-i3b7knld.googlevideo.com.",
"rr2---sn-i3b7knlk.googlevideo.com.",
@@ -3798,25 +4218,37 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-i3b7knsl.googlevideo.com.",
"rr2---sn-i3b7knzl.googlevideo.com.",
"rr2---sn-i3b7knzs.googlevideo.com.",
- "rr2---sn-i3belne6.googlevideo.com.",
+ "rr2---sn-i3belney.googlevideo.com.",
"rr2---sn-i3belnl6.googlevideo.com.",
"rr2---sn-i3belnl7.googlevideo.com.",
"rr2---sn-i3belnll.googlevideo.com.",
+ "rr2---sn-i3belnls.googlevideo.com.",
"rr2---sn-i3bssn7e.googlevideo.com.",
+ "rr2---sn-jn2pgx4pcxg-w5o6.googlevideo.com.",
+ "rr2---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr2---sn-jn2pgx4pcxg-w5oz.googlevideo.com.",
"rr2---sn-jvhh4pcgx-ajte.googlevideo.com.",
"rr2---sn-jvhh4pcgx-ajtl.googlevideo.com.",
- "rr2---sn-jvhj5nu-nh4e.googlevideo.com.",
- "rr2---sn-jvhj5nu-nh4l.googlevideo.com.",
- "rr2---sn-jvhj5nu-nh4s.googlevideo.com.",
- "rr2---sn-jvhj5nu-nh4z.googlevideo.com.",
+ "rr2---sn-jxopj-n5oe.googlevideo.com.",
+ "rr2---sn-jxopj-nh4e.googlevideo.com.",
+ "rr2---sn-jxopj-nh4e.gvt1.com.",
+ "rr2---sn-n2uxaxjvh-j5xl.googlevideo.com.",
+ "rr2---sn-n2uxaxjvh-j5xl.gvt1.com.",
+ "rr2---sn-n2uxaxjvh-j5xs.googlevideo.com.",
+ "rr2---sn-n2uxaxjvh-j5xs.gvt1.com.",
"rr2---sn-n4v7snee.googlevideo.com.",
"rr2---sn-n4v7sney.googlevideo.com.",
"rr2---sn-n4v7snl7.googlevideo.com.",
"rr2---sn-n4v7snll.googlevideo.com.",
"rr2---sn-n4v7snlr.googlevideo.com.",
"rr2---sn-n4v7snls.googlevideo.com.",
+ "rr2---sn-n4v7snly.googlevideo.com.",
"rr2---sn-n4v7sns7.googlevideo.com.",
"rr2---sn-n4v7snse.googlevideo.com.",
+ "rr2---sn-nh5gujvh-h4xe.googlevideo.com.",
+ "rr2---sn-nh5gujvh-h4xe.gvt1.com.",
+ "rr2---sn-nh5gujvh-h4xl.googlevideo.com.",
+ "rr2---sn-nh5gujvh-h4xl.gvt1.com.",
"rr2---sn-npoe7ndl.googlevideo.com.",
"rr2---sn-npoe7ndl.gvt1.com.",
"rr2---sn-npoe7ne6.googlevideo.com.",
@@ -3834,18 +4266,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-npoe7ns7.googlevideo.com.",
"rr2---sn-npoe7ns7.gvt1.com.",
"rr2---sn-npoe7nsd.googlevideo.com.",
- "rr2---sn-npoe7nsd.gvt1.com.",
"rr2---sn-npoe7nsk.googlevideo.com.",
- "rr2---sn-npoe7nsk.gvt1.com.",
"rr2---sn-npoe7nsr.googlevideo.com.",
- "rr2---sn-npoe7nss.googlevideo.com.",
- "rr2---sn-npoe7nss.gvt1.com.",
+ "rr2---sn-npoe7nsr.gvt1.com.",
"rr2---sn-npoe7nsy.googlevideo.com.",
- "rr2---sn-npoe7nsy.gvt1.com.",
"rr2---sn-npoe7nz7.googlevideo.com.",
- "rr2---sn-npoe7nz7.gvt1.com.",
"rr2---sn-npoeene6.googlevideo.com.",
- "rr2---sn-npoeene6.gvt1.com.",
"rr2---sn-npoeened.googlevideo.com.",
"rr2---sn-npoeenee.googlevideo.com.",
"rr2---sn-npoeenek.googlevideo.com.",
@@ -3855,38 +4281,30 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-npoeenl7.googlevideo.com.",
"rr2---sn-npoeenle.googlevideo.com.",
"rr2---sn-npoeenlk.googlevideo.com.",
- "rr2---sn-npoeenlk.gvt1.com.",
"rr2---sn-npoeenll.googlevideo.com.",
"rr2---sn-npoeenly.googlevideo.com.",
- "rr2---sn-npoeenly.gvt1.com.",
"rr2---sn-npoeens7.googlevideo.com.",
"rr2---sn-npoeens7.gvt1.com.",
"rr2---sn-npoldn76.googlevideo.com.",
- "rr2---sn-npoldn76.gvt1.com.",
"rr2---sn-npoldn7d.googlevideo.com.",
"rr2---sn-npoldn7d.gvt1.com.",
"rr2---sn-npoldn7e.googlevideo.com.",
- "rr2---sn-npoldn7e.gvt1.com.",
"rr2---sn-npoldn7l.googlevideo.com.",
- "rr2---sn-npoldn7l.gvt1.com.",
- "rr2---sn-npoldn7s.googlevideo.com.",
"rr2---sn-npoldn7y.googlevideo.com.",
- "rr2---sn-npoldn7y.gvt1.com.",
"rr2---sn-npoldn7z.googlevideo.com.",
- "rr2---sn-npoldn7z.gvt1.com.",
"rr2---sn-npoldne7.googlevideo.com.",
- "rr2---sn-npoldne7.gvt1.com.",
- "rr2---sn-nv47ln6e.googlevideo.com.",
- "rr2---sn-nv47zn7r.googlevideo.com.",
- "rr2---sn-nv47znee.googlevideo.com.",
- "rr2---sn-nv47znel.googlevideo.com.",
+ "rr2---sn-ntq7yned.googlevideo.com.",
+ "rr2---sn-nv0uixgo-5ual.googlevideo.com.",
"rr2---sn-nx57ynlk.googlevideo.com.",
"rr2---sn-nx57ynsd.googlevideo.com.",
"rr2---sn-nx57ynse.googlevideo.com.",
"rr2---sn-nx57ynsk.googlevideo.com.",
"rr2---sn-nx57ynsl.googlevideo.com.",
- "rr2---sn-nx57ynss.googlevideo.com.",
+ "rr2---sn-nx57ynsr.googlevideo.com.",
+ "rr2---sn-nx57ynsy.googlevideo.com.",
"rr2---sn-nx57ynsz.googlevideo.com.",
+ "rr2---sn-nx57ynz7.googlevideo.com.",
+ "rr2---sn-nx57ynze.googlevideo.com.",
"rr2---sn-o097znsd.googlevideo.com.",
"rr2---sn-o097znse.googlevideo.com.",
"rr2---sn-o097znsk.googlevideo.com.",
@@ -3895,18 +4313,20 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-o097znss.googlevideo.com.",
"rr2---sn-o097znsz.googlevideo.com.",
"rr2---sn-o097znz7.googlevideo.com.",
- "rr2---sn-o097znzd.googlevideo.com.",
"rr2---sn-o097znze.googlevideo.com.",
"rr2---sn-o097znzk.googlevideo.com.",
"rr2---sn-o097znzr.googlevideo.com.",
"rr2---sn-oj5hn5-55.googlevideo.com.",
"rr2---sn-oji3bc-5j.googlevideo.com.",
+ "rr2---sn-ojnpo5-58.googlevideo.com.",
"rr2---sn-p5qddn76.googlevideo.com.",
"rr2---sn-p5qddn7d.googlevideo.com.",
"rr2---sn-p5qddn7k.googlevideo.com.",
"rr2---sn-p5qddn7r.googlevideo.com.",
"rr2---sn-p5qddn7z.googlevideo.com.",
"rr2---sn-p5qlsn6l.googlevideo.com.",
+ "rr2---sn-p5qlsn6s.googlevideo.com.",
+ "rr2---sn-p5qlsn6z.googlevideo.com.",
"rr2---sn-p5qlsn76.googlevideo.com.",
"rr2---sn-p5qlsn7d.googlevideo.com.",
"rr2---sn-p5qlsn7l.googlevideo.com.",
@@ -3919,29 +4339,36 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-p5qlsnrr.googlevideo.com.",
"rr2---sn-p5qlsny6.googlevideo.com.",
"rr2---sn-p5qs7n6d.googlevideo.com.",
+ "rr2---sn-p5qs7n6y.googlevideo.com.",
+ "rr2---sn-p5qs7nd7.googlevideo.com.",
"rr2---sn-p5qs7nsk.googlevideo.com.",
- "rr2---sn-p5qs7nsr.googlevideo.com.",
"rr2---sn-p5qs7nzk.googlevideo.com.",
"rr2---sn-p5qs7nzr.googlevideo.com.",
"rr2---sn-p5qs7nzy.googlevideo.com.",
+ "rr2---sn-paapovpnjxou0gt-nual.googlevideo.com.",
+ "rr2---sn-paapovpnjxou0gt-nuas.googlevideo.com.",
+ "rr2---sn-paapovpnjxou0gt-nuaz.googlevideo.com.",
"rr2---sn-pjnpu-5hfe.googlevideo.com.",
"rr2---sn-pjnpu-5hfl.googlevideo.com.",
- "rr2---sn-pjx-nwv6.googlevideo.com.",
- "rr2---sn-pouxgoxm5-cvbe.googlevideo.com.",
+ "rr2---sn-pobpb-poql.googlevideo.com.",
"rr2---sn-q4fl6n66.googlevideo.com.",
+ "rr2---sn-q4fl6n66.gvt1.com.",
"rr2---sn-q4fl6n6d.googlevideo.com.",
"rr2---sn-q4fl6n6r.googlevideo.com.",
"rr2---sn-q4fl6n6s.googlevideo.com.",
+ "rr2---sn-q4fl6n6s.gvt1.com.",
"rr2---sn-q4fl6n6y.googlevideo.com.",
+ "rr2---sn-q4fl6n6y.gvt1.com.",
"rr2---sn-q4fl6n6z.googlevideo.com.",
- "rr2---sn-q4fl6nd6.googlevideo.com.",
+ "rr2---sn-q4fl6n6z.gvt1.com.",
"rr2---sn-q4fl6nd7.googlevideo.com.",
"rr2---sn-q4fl6nde.googlevideo.com.",
"rr2---sn-q4fl6ndl.googlevideo.com.",
"rr2---sn-q4fl6nds.googlevideo.com.",
"rr2---sn-q4fl6ndz.googlevideo.com.",
- "rr2---sn-q4fl6nlz.googlevideo.com.",
+ "rr2---sn-q4fl6ndz.gvt1.com.",
"rr2---sn-q4fl6ns6.googlevideo.com.",
+ "rr2---sn-q4fl6ns6.gvt1.com.",
"rr2---sn-q4fl6ns7.googlevideo.com.",
"rr2---sn-q4fl6nsd.googlevideo.com.",
"rr2---sn-q4fl6nsk.googlevideo.com.",
@@ -3951,40 +4378,59 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-q4fl6nsy.googlevideo.com.",
"rr2---sn-q4fl6nz6.googlevideo.com.",
"rr2---sn-q4fl6nz7.googlevideo.com.",
+ "rr2---sn-q4fl6nz7.gvt1.com.",
"rr2---sn-q4fl6nzy.googlevideo.com.",
"rr2---sn-q4flrn7k.googlevideo.com.",
"rr2---sn-q4flrn7r.googlevideo.com.",
+ "rr2---sn-q4flrn7r.gvt1.com.",
"rr2---sn-q4flrn7y.googlevideo.com.",
"rr2---sn-q4flrne6.googlevideo.com.",
"rr2---sn-q4flrne7.googlevideo.com.",
+ "rr2---sn-q4flrne7.gvt1.com.",
"rr2---sn-q4flrnee.googlevideo.com.",
+ "rr2---sn-q4flrnee.gvt1.com.",
"rr2---sn-q4flrnek.googlevideo.com.",
"rr2---sn-q4flrnel.googlevideo.com.",
+ "rr2---sn-q4flrnel.gvt1.com.",
"rr2---sn-q4flrner.googlevideo.com.",
"rr2---sn-q4flrnes.googlevideo.com.",
+ "rr2---sn-q4flrnes.gvt1.com.",
"rr2---sn-q4flrney.googlevideo.com.",
+ "rr2---sn-q4flrney.gvt1.com.",
"rr2---sn-q4flrnez.googlevideo.com.",
"rr2---sn-q4flrnl6.googlevideo.com.",
+ "rr2---sn-q4flrnl6.gvt1.com.",
"rr2---sn-q4flrnl7.googlevideo.com.",
- "rr2---sn-q4flrnld.googlevideo.com.",
+ "rr2---sn-q4flrnl7.gvt1.com.",
"rr2---sn-q4flrnle.googlevideo.com.",
+ "rr2---sn-q4flrnle.gvt1.com.",
"rr2---sn-q4flrnlz.googlevideo.com.",
- "rr2---sn-q4flrnsd.googlevideo.com.",
- "rr2---sn-q4flrnsk.googlevideo.com.",
"rr2---sn-q4flrnsl.googlevideo.com.",
+ "rr2---sn-q4flrnsl.gvt1.com.",
"rr2---sn-q4flrnss.googlevideo.com.",
+ "rr2---sn-q4flrnss.gvt1.com.",
"rr2---sn-q4fzen7e.googlevideo.com.",
"rr2---sn-q4fzen7l.googlevideo.com.",
+ "rr2---sn-q4fzen7l.gvt1.com.",
"rr2---sn-q4fzen7s.googlevideo.com.",
+ "rr2---sn-q4fzen7s.gvt1.com.",
"rr2---sn-q4fzen7y.googlevideo.com.",
"rr2---sn-q4fzene7.googlevideo.com.",
+ "rr2---sn-q4fzene7.gvt1.com.",
"rr2---sn-q4fzenee.googlevideo.com.",
"rr2---sn-qjp5q5-55.googlevideo.com.",
"rr2---sn-qxo7rn7k.googlevideo.com.",
- "rr2---sn-qxo7rn7r.googlevideo.com.",
+ "rr2---sn-qxo7rne7.googlevideo.com.",
+ "rr2---sn-qxo7rnee.googlevideo.com.",
"rr2---sn-qxoedn7k.googlevideo.com.",
"rr2---sn-qxoednee.googlevideo.com.",
- "rr2---sn-t0aedn7l.googlevideo.com.",
+ "rr2---sn-qxoednel.googlevideo.com.",
+ "rr2---sn-qxoednes.googlevideo.com.",
+ "rr2---sn-qxuxa-5xme.googlevideo.com.",
+ "rr2---sn-v5goxu-jhi6.googlevideo.com.",
+ "rr2---sn-v5goxu-jhid.googlevideo.com.",
+ "rr2---sn-v5goxu-jhil.googlevideo.com.",
+ "rr2---sn-v5goxu-jhiz.googlevideo.com.",
"rr2---sn-vgqskn66.googlevideo.com.",
"rr2---sn-vgqskn67.googlevideo.com.",
"rr2---sn-vgqskn6d.googlevideo.com.",
@@ -4017,6 +4463,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-vgqsrn66.googlevideo.com.",
"rr2---sn-vgqsrn67.googlevideo.com.",
"rr2---sn-vgqsrn6e.googlevideo.com.",
+ "rr2---sn-vgqsrn6l.googlevideo.com.",
"rr2---sn-vgqsrn6z.googlevideo.com.",
"rr2---sn-vgqsrne6.googlevideo.com.",
"rr2---sn-vgqsrned.googlevideo.com.",
@@ -4028,52 +4475,20 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-vgqsrnlk.googlevideo.com.",
"rr2---sn-vgqsrnll.googlevideo.com.",
"rr2---sn-vgqsrnls.googlevideo.com.",
- "rr2---sn-vgqsrnlz.googlevideo.com.",
"rr2---sn-vgqsrns6.googlevideo.com.",
"rr2---sn-vgqsrnsd.googlevideo.com.",
+ "rr2---sn-vgqsrnsr.googlevideo.com.",
"rr2---sn-vgqsrnsy.googlevideo.com.",
"rr2---sn-vgqsrnz6.googlevideo.com.",
"rr2---sn-vgqsrnz7.googlevideo.com.",
- "rr2---sn-vgqsrnzd.googlevideo.com.",
"rr2---sn-vgqsrnzk.googlevideo.com.",
+ "rr2---sn-vgqsrnzr.googlevideo.com.",
"rr2---sn-vgqsrnzs.googlevideo.com.",
"rr2---sn-vgqsrnzy.googlevideo.com.",
"rr2---sn-vgqsrnzz.googlevideo.com.",
"rr2---sn-voxoxu-v3jl.googlevideo.com.",
"rr2---sn-voxoxu-v3js.googlevideo.com.",
- "rr2.sn-2oq4f5-c4.googlevideo.com.",
- "rr2.sn-a5m7lnl6.googlevideo.com.",
- "rr2.sn-a5m7lnld.googlevideo.com.",
- "rr2.sn-a5mekn6d.googlevideo.com.",
- "rr2.sn-a5mekn6k.googlevideo.com.",
- "rr2.sn-a5mekn6l.googlevideo.com.",
- "rr2.sn-a5mekn6r.googlevideo.com.",
- "rr2.sn-a5mekn6s.googlevideo.com.",
- "rr2.sn-a5mekn6z.googlevideo.com.",
- "rr2.sn-a5meknd6.googlevideo.com.",
- "rr2.sn-a5meknde.googlevideo.com.",
- "rr2.sn-a5mekndl.googlevideo.com.",
- "rr2.sn-a5meknds.googlevideo.com.",
- "rr2.sn-a5mekndz.googlevideo.com.",
- "rr2.sn-a5meknsd.googlevideo.com.",
- "rr2.sn-a5meknsy.googlevideo.com.",
- "rr2.sn-a5meknzk.googlevideo.com.",
- "rr2.sn-a5meknzr.googlevideo.com.",
- "rr2.sn-a5meknzs.googlevideo.com.",
- "rr2.sn-a5mlrnek.googlevideo.com.",
- "rr2.sn-a5mlrnl6.googlevideo.com.",
- "rr2.sn-a5mlrnll.googlevideo.com.",
- "rr2.sn-a5mlrnls.googlevideo.com.",
- "rr2.sn-a5mlrnlz.googlevideo.com.",
- "rr2.sn-a5msen76.googlevideo.com.",
- "rr2.sn-a5msen7l.googlevideo.com.",
- "rr2.sn-a5msen7s.googlevideo.com.",
- "rr2.sn-a5msen7z.googlevideo.com.",
- "rr2.sn-a5msenek.googlevideo.com.",
- "rr2.sn-a5msener.googlevideo.com.",
- "rr2.sn-a5msenes.googlevideo.com.",
- "rr2.sn-a5msenl7.googlevideo.com.",
- "rr2.sn-a5msenle.googlevideo.com.",
+ "rr2.sn-5hnekn76.googlevideo.com.",
"rr2.sn-hp57kn6r.googlevideo.com.",
"rr2.sn-hp57kn6y.googlevideo.com.",
"rr2.sn-hp57knd6.googlevideo.com.",
@@ -4085,109 +4500,48 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2.sn-hp57kndz.googlevideo.com.",
"rr2.sn-hp57knk7.googlevideo.com.",
"rr2.sn-hp57yn7y.googlevideo.com.",
- "rr2.sn-hp57ynl6.googlevideo.com.",
"rr2.sn-hp57ynlr.googlevideo.com.",
"rr2.sn-hp57ynly.googlevideo.com.",
"rr2.sn-hp57yns7.googlevideo.com.",
"rr2.sn-hp57ynse.googlevideo.com.",
"rr2.sn-hp57ynsl.googlevideo.com.",
- "rr2.sn-hpqfxnu-oaxl.googlevideo.com.",
"rr2.sn-nx57ynsk.googlevideo.com.",
- "rr2.sn-q4fl6n6r.googlevideo.com.",
- "rr2.sn-q4fl6n6s.googlevideo.com.",
- "rr2.sn-q4fl6nd6.googlevideo.com.",
- "rr2.sn-q4fl6nsy.googlevideo.com.",
- "rr2.sn-q4flrnl6.googlevideo.com.",
- "rr2.sn-q4flrnld.googlevideo.com.",
- "rr2.sn-q4flrnle.googlevideo.com.",
- "rr2.sn-q4flrnlz.googlevideo.com.",
- "rr2.sn-q4flrnsd.googlevideo.com.",
- "rr2.sn-q4flrnsk.googlevideo.com.",
- "rr2.sn-q4flrnsl.googlevideo.com.",
- "rr2.sn-q4flrnss.googlevideo.com.",
- "rr2.sn-q4fzen7e.googlevideo.com.",
+ "rr2.sn-q4fl6n6y.googlevideo.com.",
+ "rr2.sn-q4fl6ns7.googlevideo.com.",
+ "rr2.sn-q4flrnee.googlevideo.com.",
+ "rr2.sn-q4flrnez.googlevideo.com.",
"rr2.sn-q4fzen7l.googlevideo.com.",
- "rr2.sn-q4fzen7s.googlevideo.com.",
- "rr2.sn-q4fzen7y.googlevideo.com.",
- "rr2.sn-q4fzene7.googlevideo.com.",
- "rr2.sn-q4fzenee.googlevideo.com.",
- "rr2.sn-vgqskn66.googlevideo.com.",
- "rr2.sn-vgqskn67.googlevideo.com.",
- "rr2.sn-vgqskn6d.googlevideo.com.",
- "rr2.sn-vgqskn6s.googlevideo.com.",
- "rr2.sn-vgqskn6z.googlevideo.com.",
- "rr2.sn-vgqsknld.googlevideo.com.",
- "rr2.sn-vgqsknlk.googlevideo.com.",
- "rr2.sn-vgqsknlr.googlevideo.com.",
- "rr2.sn-vgqskns7.googlevideo.com.",
- "rr2.sn-vgqsknse.googlevideo.com.",
- "rr2.sn-vgqsknsk.googlevideo.com.",
- "rr2.sn-vgqsknz6.googlevideo.com.",
- "rr2.sn-vgqsknz7.googlevideo.com.",
- "rr2.sn-vgqsknzd.googlevideo.com.",
- "rr2.sn-vgqsknze.googlevideo.com.",
- "rr2.sn-vgqsknzk.googlevideo.com.",
- "rr2.sn-vgqsknzl.googlevideo.com.",
- "rr2.sn-vgqsknzr.googlevideo.com.",
- "rr2.sn-vgqsknzs.googlevideo.com.",
- "rr2.sn-vgqsknzy.googlevideo.com.",
- "rr2.sn-vgqsknzz.googlevideo.com.",
- "rr2.sn-vgqsrn66.googlevideo.com.",
- "rr2.sn-vgqsrn67.googlevideo.com.",
- "rr2.sn-vgqsrn6e.googlevideo.com.",
- "rr2.sn-vgqsrn6z.googlevideo.com.",
- "rr2.sn-vgqsrnes.googlevideo.com.",
- "rr2.sn-vgqsrnl6.googlevideo.com.",
- "rr2.sn-vgqsrnld.googlevideo.com.",
- "rr2.sn-vgqsrnlk.googlevideo.com.",
- "rr2.sn-vgqsrnls.googlevideo.com.",
- "rr2.sn-vgqsrnlz.googlevideo.com.",
- "rr2.sn-vgqsrns6.googlevideo.com.",
- "rr2.sn-vgqsrnsd.googlevideo.com.",
- "rr2.sn-vgqsrnsy.googlevideo.com.",
- "rr2.sn-vgqsrnz6.googlevideo.com.",
- "rr2.sn-vgqsrnz7.googlevideo.com.",
- "rr2.sn-vgqsrnzd.googlevideo.com.",
- "rr2.sn-vgqsrnzk.googlevideo.com.",
- "rr2.sn-vgqsrnzs.googlevideo.com.",
- "rr2.sn-vgqsrnzy.googlevideo.com.",
"rr2.sn-vgqsrnzz.googlevideo.com.",
"rr3---sn-0nnpbo5a-bggl.googlevideo.com.",
- "rr3---sn-2aqu-hoal6.googlevideo.com.",
"rr3---sn-2aqu-hoas7.googlevideo.com.",
- "rr3---sn-2aqu-hoasd.googlevideo.com.",
"rr3---sn-2aqu-hoasz.googlevideo.com.",
- "rr3---sn-2aqu-jbt6.googlevideo.com.",
- "rr3---sn-2aqu-jbtd.googlevideo.com.",
- "rr3---sn-2aqu-jxcr.googlevideo.com.",
- "rr3---sn-2aqu-jxcy.googlevideo.com.",
"rr3---sn-2imern76.googlevideo.com.",
"rr3---sn-2imern7d.googlevideo.com.",
+ "rr3---sn-2imern7d.gvt1.com.",
+ "rr3---sn-2imern7r.googlevideo.com.",
+ "rr3---sn-2imern7r.gvt1.com.",
"rr3---sn-2imeyn7k.googlevideo.com.",
"rr3---sn-2o5ua5-53.googlevideo.com.",
"rr3---sn-2oaig5-55.googlevideo.com.",
+ "rr3---sn-2op5q5-58.googlevideo.com.",
"rr3---sn-2oq4f5-c4.googlevideo.com.",
- "rr3---sn-2ovgq5-cw.googlevideo.com.",
+ "rr3---sn-2oq4f5-c4.gvt1.com.",
"rr3---sn-30a7rned.googlevideo.com.",
"rr3---sn-30a7rnek.googlevideo.com.",
"rr3---sn-30a7ynek.googlevideo.com.",
"rr3---sn-30a7yner.googlevideo.com.",
"rr3---sn-30a7yney.googlevideo.com.",
"rr3---sn-30a7ynl7.googlevideo.com.",
- "rr3---sn-42u-nboze.googlevideo.com.",
- "rr3---sn-42u-nbozl.googlevideo.com.",
- "rr3---sn-42u-nbozs.googlevideo.com.",
- "rr3---sn-42u-nbozz.googlevideo.com.",
"rr3---sn-4g5e6ns6.googlevideo.com.",
"rr3---sn-4g5e6ns7.googlevideo.com.",
"rr3---sn-4g5e6nsd.googlevideo.com.",
"rr3---sn-4g5e6nsk.googlevideo.com.",
- "rr3---sn-4g5e6nsr.googlevideo.com.",
"rr3---sn-4g5e6nss.googlevideo.com.",
"rr3---sn-4g5e6nsy.googlevideo.com.",
"rr3---sn-4g5e6nsz.googlevideo.com.",
"rr3---sn-4g5e6nz7.googlevideo.com.",
"rr3---sn-4g5e6nze.googlevideo.com.",
+ "rr3---sn-4g5e6nzl.googlevideo.com.",
"rr3---sn-4g5e6nzs.googlevideo.com.",
"rr3---sn-4g5e6nzz.googlevideo.com.",
"rr3---sn-4g5edn6k.googlevideo.com.",
@@ -4199,13 +4553,11 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-4g5edndk.googlevideo.com.",
"rr3---sn-4g5edndl.googlevideo.com.",
"rr3---sn-4g5edndr.googlevideo.com.",
- "rr3---sn-4g5ednds.googlevideo.com.",
"rr3---sn-4g5edndy.googlevideo.com.",
"rr3---sn-4g5edndz.googlevideo.com.",
"rr3---sn-4g5ednkl.googlevideo.com.",
"rr3---sn-4g5ednld.googlevideo.com.",
"rr3---sn-4g5ednly.googlevideo.com.",
- "rr3---sn-4g5edns6.googlevideo.com.",
"rr3---sn-4g5edns7.googlevideo.com.",
"rr3---sn-4g5ednsd.googlevideo.com.",
"rr3---sn-4g5ednse.googlevideo.com.",
@@ -4228,17 +4580,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-4g5lznle.googlevideo.com.",
"rr3---sn-4g5lznls.googlevideo.com.",
"rr3---sn-4g5lznlz.googlevideo.com.",
- "rr3---sn-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
- "rr3---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
"rr3---sn-5abxgpxuxaxjvh-9n4z.googlevideo.com.",
- "rr3---sn-5abxgpxuxaxjvh-cawe.googlevideo.com.",
- "rr3---sn-5abxgpxuxaxjvh-caws.googlevideo.com.",
- "rr3---sn-5abxgpxuxaxjvh-j1ae.googlevideo.com.",
- "rr3---sn-5abxgpxuxaxjvh-j1as.googlevideo.com.",
- "rr3---sn-5abxgpxuxaxjvh-j1az.googlevideo.com.",
- "rr3---sn-5go7yner.googlevideo.com.",
"rr3---sn-5go7ynl6.googlevideo.com.",
- "rr3---sn-5go7ynld.googlevideo.com.",
"rr3---sn-5goeenes.googlevideo.com.",
"rr3---sn-5goeenez.googlevideo.com.",
"rr3---sn-5hne6n6e.googlevideo.com.",
@@ -4262,10 +4605,10 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-5hnekn7s.googlevideo.com.",
"rr3---sn-5hnekn7z.googlevideo.com.",
"rr3---sn-5hneknee.googlevideo.com.",
- "rr3---sn-5hneknee.gvt1.com.",
"rr3---sn-5hneknek.googlevideo.com.",
"rr3---sn-5hneknes.googlevideo.com.",
"rr3---sn-5uaezndd.googlevideo.com.",
+ "rr3---sn-5uaezndd.gvt1.com.",
"rr3---sn-5uaezne6.googlevideo.com.",
"rr3---sn-5uaezned.googlevideo.com.",
"rr3---sn-5uaeznel.googlevideo.com.",
@@ -4274,7 +4617,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-5uaeznl6.googlevideo.com.",
"rr3---sn-5uaeznls.googlevideo.com.",
"rr3---sn-5uaeznly.googlevideo.com.",
- "rr3---sn-5uaeznlz.googlevideo.com.",
"rr3---sn-5uaeznse.googlevideo.com.",
"rr3---sn-5uaeznsl.googlevideo.com.",
"rr3---sn-5uaeznss.googlevideo.com.",
@@ -4292,58 +4634,45 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-5ualdnsk.googlevideo.com.",
"rr3---sn-5ualdnsl.googlevideo.com.",
"rr3---sn-5ualdnsr.googlevideo.com.",
- "rr3---sn-5ualdnss.googlevideo.com.",
"rr3---sn-5ualdnsy.googlevideo.com.",
+ "rr3---sn-5ualdnsy.gvt1.com.",
"rr3---sn-5ualdnsz.googlevideo.com.",
"rr3---sn-5ualdnz7.googlevideo.com.",
"rr3---sn-5ualdnze.googlevideo.com.",
- "rr3---sn-8pxuuxa-nbo6l.googlevideo.com.",
- "rr3---sn-8pxuuxa-nbo6s.googlevideo.com.",
- "rr3---sn-8pxuuxa-nboz6.googlevideo.com.",
- "rr3---sn-8qj-i2iez.googlevideo.com.",
- "rr3---sn-8qj-i5o66.googlevideo.com.",
- "rr3---sn-8qj-i5o6k.googlevideo.com.",
- "rr3---sn-8qj-i5ody.googlevideo.com.",
- "rr3---sn-8qj-i5oks.googlevideo.com.",
- "rr3---sn-8qj-i5ozd.googlevideo.com.",
- "rr3---sn-8qj-i5ozr.googlevideo.com.",
- "rr3---sn-8qj-i5ozz.googlevideo.com.",
"rr3---sn-8qj-nbo66.googlevideo.com.",
- "rr3---sn-8qj-nbo67.googlevideo.com.",
"rr3---sn-8qj-nbod6.googlevideo.com.",
+ "rr3---sn-8qj-nbosd.googlevideo.com.",
+ "rr3---sn-8xgp1vo-a5ml.googlevideo.com.",
"rr3---sn-8xgp1vo-ab56.googlevideo.com.",
"rr3---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr3---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr3---sn-8xgp1vo-ab5l.googlevideo.com.",
"rr3---sn-8xgp1vo-ab5s.googlevideo.com.",
"rr3---sn-8xgp1vo-ab5z.googlevideo.com.",
- "rr3---sn-8xgp1vo-nh4e.googlevideo.com.",
- "rr3---sn-8xgp1vo-poql.googlevideo.com.",
+ "rr3---sn-8xgp1vo-p5qee.googlevideo.com.",
+ "rr3---sn-8xgp1vo-p5qel.googlevideo.com.",
+ "rr3---sn-8xgp1vo-p5qes.googlevideo.com.",
"rr3---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr3---sn-8xgp1vo-xfge.googlevideo.com.",
"rr3---sn-8xgp1vo-xfgl.googlevideo.com.",
"rr3---sn-8xgp1vo-xfgs.googlevideo.com.",
- "rr3---sn-9gv76n7e.googlevideo.com.",
- "rr3---sn-9gv76n7l.googlevideo.com.",
"rr3---sn-9gv76n7s.googlevideo.com.",
"rr3---sn-9gv76n7z.googlevideo.com.",
- "rr3---sn-9gv7ene6.googlevideo.com.",
- "rr3---sn-9gv7ened.googlevideo.com.",
"rr3---sn-9gv7zn76.googlevideo.com.",
"rr3---sn-9gv7zn7e.googlevideo.com.",
- "rr3---sn-9gv7zn7r.googlevideo.com.",
"rr3---sn-9gv7zn7y.googlevideo.com.",
"rr3---sn-a5m7lnl6.googlevideo.com.",
"rr3---sn-a5m7lnld.googlevideo.com.",
"rr3---sn-a5mekn6d.googlevideo.com.",
"rr3---sn-a5mekn6k.googlevideo.com.",
+ "rr3---sn-a5mekn6k.gvt1.com.",
"rr3---sn-a5mekn6l.googlevideo.com.",
"rr3---sn-a5mekn6r.googlevideo.com.",
"rr3---sn-a5mekn6s.googlevideo.com.",
"rr3---sn-a5mekn6z.googlevideo.com.",
"rr3---sn-a5meknd6.googlevideo.com.",
- "rr3---sn-a5meknde.googlevideo.com.",
"rr3---sn-a5mekndl.googlevideo.com.",
+ "rr3---sn-a5mekndl.gvt1.com.",
"rr3---sn-a5meknds.googlevideo.com.",
"rr3---sn-a5mekndz.googlevideo.com.",
"rr3---sn-a5meknsd.googlevideo.com.",
@@ -4376,11 +4705,14 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-ab5l6nrl.googlevideo.com.",
"rr3---sn-ab5l6nrr.googlevideo.com.",
"rr3---sn-ab5l6nrs.googlevideo.com.",
+ "rr3---sn-ab5l6nrz.googlevideo.com.",
+ "rr3---sn-ab5sznld.googlevideo.com.",
"rr3---sn-ab5sznly.googlevideo.com.",
"rr3---sn-ab5sznz6.googlevideo.com.",
"rr3---sn-ab5sznzd.googlevideo.com.",
"rr3---sn-ab5sznze.googlevideo.com.",
"rr3---sn-ab5sznzk.googlevideo.com.",
+ "rr3---sn-ab5sznzl.googlevideo.com.",
"rr3---sn-ab5sznzr.googlevideo.com.",
"rr3---sn-ab5sznzs.googlevideo.com.",
"rr3---sn-ab5sznzy.googlevideo.com.",
@@ -4397,6 +4729,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-aigl6nsr.googlevideo.com.",
"rr3---sn-aigl6nz7.googlevideo.com.",
"rr3---sn-aigl6nze.googlevideo.com.",
+ "rr3---sn-aigl6nzk.googlevideo.com.",
"rr3---sn-aigl6nzl.googlevideo.com.",
"rr3---sn-aigl6nzr.googlevideo.com.",
"rr3---sn-aigl6nzs.googlevideo.com.",
@@ -4411,29 +4744,40 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-aigzrnse.googlevideo.com.",
"rr3---sn-aigzrnsl.googlevideo.com.",
"rr3---sn-aigzrnsr.googlevideo.com.",
- "rr3---sn-aigzrnss.googlevideo.com.",
"rr3---sn-aigzrnsz.googlevideo.com.",
"rr3---sn-aigzrnz7.googlevideo.com.",
"rr3---sn-aigzrnze.googlevideo.com.",
+ "rr3---sn-aj4g55-5v.googlevideo.com.",
+ "rr3---sn-aj5ua5-5c.googlevideo.com.",
"rr3---sn-ajab55-55.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
"rr3---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
"rr3---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
- "rr3---sn-c0q7lnz7.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxqjvhj5nu-n4vl.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxqjvhj5nu-vgqz.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxqjvm-2ims.googlevideo.com.",
+ "rr3---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
"rr3---sn-cvb7lne7.googlevideo.com.",
"rr3---sn-cvb7lnee.googlevideo.com.",
"rr3---sn-cvb7lnlz.googlevideo.com.",
"rr3---sn-cvb7sn7k.googlevideo.com.",
"rr3---sn-cvb7sn7r.googlevideo.com.",
- "rr3---sn-gxuo03g-3c2l.googlevideo.com.",
- "rr3---sn-gxuo03g-ig3e.googlevideo.com.",
"rr3---sn-gxuo03g-ig3l.googlevideo.com.",
- "rr3---sn-h0jeenl6.googlevideo.com.",
- "rr3---sn-h0jeenld.googlevideo.com.",
- "rr3---sn-h0jeenle.googlevideo.com.",
- "rr3---sn-h0jelne6.googlevideo.com.",
- "rr3---sn-h0jelnes.googlevideo.com.",
- "rr3---sn-h0jelnez.googlevideo.com.",
+ "rr3---sn-hgn7rn7k.googlevideo.com.",
"rr3---sn-hgn7rnls.googlevideo.com.",
+ "rr3---sn-hjoj-gq0l.googlevideo.com.",
+ "rr3---sn-hjoj-poul.googlevideo.com.",
"rr3---sn-hoa7kn76.googlevideo.com.",
"rr3---sn-hoa7kn76.gvt1.com.",
"rr3---sn-hoa7kn7z.googlevideo.com.",
@@ -4443,31 +4787,35 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-hoa7rn7z.googlevideo.com.",
"rr3---sn-hoa7rn7z.gvt1.com.",
"rr3---sn-hp57kn6r.googlevideo.com.",
+ "rr3---sn-hp57kn6r.gvt1.com.",
"rr3---sn-hp57kn6y.googlevideo.com.",
"rr3---sn-hp57kn6y.gvt1.com.",
"rr3---sn-hp57knd6.googlevideo.com.",
+ "rr3---sn-hp57knd6.gvt1.com.",
"rr3---sn-hp57kndd.googlevideo.com.",
+ "rr3---sn-hp57kndd.gvt1.com.",
"rr3---sn-hp57kndk.googlevideo.com.",
"rr3---sn-hp57kndr.googlevideo.com.",
+ "rr3---sn-hp57kndr.gvt1.com.",
"rr3---sn-hp57knds.googlevideo.com.",
"rr3---sn-hp57kndy.googlevideo.com.",
+ "rr3---sn-hp57kndy.gvt1.com.",
"rr3---sn-hp57kndz.googlevideo.com.",
"rr3---sn-hp57knk7.googlevideo.com.",
- "rr3---sn-hp57yn7r.googlevideo.com.",
"rr3---sn-hp57yn7y.googlevideo.com.",
"rr3---sn-hp57yne7.googlevideo.com.",
"rr3---sn-hp57ynee.googlevideo.com.",
"rr3---sn-hp57ynl6.googlevideo.com.",
"rr3---sn-hp57ynlr.googlevideo.com.",
+ "rr3---sn-hp57ynlr.gvt1.com.",
"rr3---sn-hp57ynly.googlevideo.com.",
"rr3---sn-hp57yns7.googlevideo.com.",
- "rr3---sn-hp57yns7.gvt1.com.",
"rr3---sn-hp57ynse.googlevideo.com.",
+ "rr3---sn-hp57ynse.gvt1.com.",
"rr3---sn-hp57ynsl.googlevideo.com.",
"rr3---sn-hp57ynss.googlevideo.com.",
- "rr3---sn-huxaqvv-ubqe.googlevideo.com.",
+ "rr3---sn-hp57ynss.gvt1.com.",
"rr3---sn-i3b7kn6s.googlevideo.com.",
- "rr3---sn-i3b7knld.googlevideo.com.",
"rr3---sn-i3b7knlk.googlevideo.com.",
"rr3---sn-i3b7kns6.googlevideo.com.",
"rr3---sn-i3b7knsd.googlevideo.com.",
@@ -4476,15 +4824,16 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-i3b7knzl.googlevideo.com.",
"rr3---sn-i3b7knzs.googlevideo.com.",
"rr3---sn-i3belne6.googlevideo.com.",
- "rr3---sn-i3belney.googlevideo.com.",
- "rr3---sn-i3belnl6.googlevideo.com.",
"rr3---sn-i3belnl7.googlevideo.com.",
"rr3---sn-i3belnll.googlevideo.com.",
+ "rr3---sn-i3belnls.googlevideo.com.",
"rr3---sn-i3bssn7e.googlevideo.com.",
- "rr3---sn-jvhj5nu-nh4e.googlevideo.com.",
- "rr3---sn-jvhj5nu-nh4l.googlevideo.com.",
- "rr3---sn-jvhj5nu-nh4s.googlevideo.com.",
- "rr3---sn-jvhj5nu-nh4z.googlevideo.com.",
+ "rr3---sn-jn2pgx4pcxg-w5o6.googlevideo.com.",
+ "rr3---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr3---sn-jn2pgx4pcxg-w5oz.googlevideo.com.",
+ "rr3---sn-jxopj-n5oe.googlevideo.com.",
+ "rr3---sn-jxopj-nh4e.googlevideo.com.",
+ "rr3---sn-jxopj-nh4e.gvt1.com.",
"rr3---sn-n4v7snee.googlevideo.com.",
"rr3---sn-n4v7sney.googlevideo.com.",
"rr3---sn-n4v7snl7.googlevideo.com.",
@@ -4495,7 +4844,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-n4v7sns7.googlevideo.com.",
"rr3---sn-n4v7snse.googlevideo.com.",
"rr3---sn-npoe7ndl.googlevideo.com.",
- "rr3---sn-npoe7ndl.gvt1.com.",
"rr3---sn-npoe7ne6.googlevideo.com.",
"rr3---sn-npoe7ne7.googlevideo.com.",
"rr3---sn-npoe7ned.googlevideo.com.",
@@ -4514,14 +4862,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-npoe7nsk.googlevideo.com.",
"rr3---sn-npoe7nsk.gvt1.com.",
"rr3---sn-npoe7nsl.googlevideo.com.",
- "rr3---sn-npoe7nsl.gvt1.com.",
"rr3---sn-npoe7nsr.googlevideo.com.",
- "rr3---sn-npoe7nss.googlevideo.com.",
- "rr3---sn-npoe7nss.gvt1.com.",
"rr3---sn-npoe7nsy.googlevideo.com.",
- "rr3---sn-npoe7nsy.gvt1.com.",
"rr3---sn-npoe7nz7.googlevideo.com.",
- "rr3---sn-npoe7nz7.gvt1.com.",
"rr3---sn-npoeene6.googlevideo.com.",
"rr3---sn-npoeened.googlevideo.com.",
"rr3---sn-npoeenee.googlevideo.com.",
@@ -4530,16 +4873,11 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-npoeeney.googlevideo.com.",
"rr3---sn-npoeenez.googlevideo.com.",
"rr3---sn-npoeenl7.googlevideo.com.",
- "rr3---sn-npoeenl7.gvt1.com.",
"rr3---sn-npoeenle.googlevideo.com.",
"rr3---sn-npoeenlk.googlevideo.com.",
- "rr3---sn-npoeenlk.gvt1.com.",
"rr3---sn-npoeenll.googlevideo.com.",
- "rr3---sn-npoeenll.gvt1.com.",
"rr3---sn-npoeenly.googlevideo.com.",
- "rr3---sn-npoeenly.gvt1.com.",
"rr3---sn-npoeens7.googlevideo.com.",
- "rr3---sn-npoeens7.gvt1.com.",
"rr3---sn-npoldn76.googlevideo.com.",
"rr3---sn-npoldn76.gvt1.com.",
"rr3---sn-npoldn7d.googlevideo.com.",
@@ -4547,25 +4885,20 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-npoldn7e.googlevideo.com.",
"rr3---sn-npoldn7e.gvt1.com.",
"rr3---sn-npoldn7l.googlevideo.com.",
- "rr3---sn-npoldn7l.gvt1.com.",
- "rr3---sn-npoldn7s.googlevideo.com.",
"rr3---sn-npoldn7y.googlevideo.com.",
- "rr3---sn-npoldn7y.gvt1.com.",
"rr3---sn-npoldn7z.googlevideo.com.",
- "rr3---sn-npoldn7z.gvt1.com.",
"rr3---sn-npoldne7.googlevideo.com.",
"rr3---sn-npoldne7.gvt1.com.",
- "rr3---sn-nv47ln6e.googlevideo.com.",
- "rr3---sn-nv47zn7r.googlevideo.com.",
- "rr3---sn-nv47zn7y.googlevideo.com.",
- "rr3---sn-nv47zne7.googlevideo.com.",
- "rr3---sn-nv47znee.googlevideo.com.",
+ "rr3---sn-nx57ynlk.googlevideo.com.",
"rr3---sn-nx57ynsd.googlevideo.com.",
"rr3---sn-nx57ynse.googlevideo.com.",
"rr3---sn-nx57ynsk.googlevideo.com.",
- "rr3---sn-nx57ynsl.googlevideo.com.",
+ "rr3---sn-nx57ynsr.googlevideo.com.",
"rr3---sn-nx57ynss.googlevideo.com.",
+ "rr3---sn-nx57ynsy.googlevideo.com.",
"rr3---sn-nx57ynsz.googlevideo.com.",
+ "rr3---sn-nx57ynz7.googlevideo.com.",
+ "rr3---sn-nx57ynze.googlevideo.com.",
"rr3---sn-o097znsd.googlevideo.com.",
"rr3---sn-o097znse.googlevideo.com.",
"rr3---sn-o097znsk.googlevideo.com.",
@@ -4574,18 +4907,18 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-o097znss.googlevideo.com.",
"rr3---sn-o097znsz.googlevideo.com.",
"rr3---sn-o097znz7.googlevideo.com.",
- "rr3---sn-o097znzd.googlevideo.com.",
"rr3---sn-o097znze.googlevideo.com.",
- "rr3---sn-o097znzk.googlevideo.com.",
"rr3---sn-o097znzr.googlevideo.com.",
"rr3---sn-oj5hn5-55.googlevideo.com.",
- "rr3---sn-oji3bc-5j.googlevideo.com.",
+ "rr3---sn-ojnpo5-58.googlevideo.com.",
"rr3---sn-p5qddn76.googlevideo.com.",
"rr3---sn-p5qddn7d.googlevideo.com.",
"rr3---sn-p5qddn7k.googlevideo.com.",
"rr3---sn-p5qddn7r.googlevideo.com.",
"rr3---sn-p5qddn7z.googlevideo.com.",
"rr3---sn-p5qlsn6l.googlevideo.com.",
+ "rr3---sn-p5qlsn6s.googlevideo.com.",
+ "rr3---sn-p5qlsn6z.googlevideo.com.",
"rr3---sn-p5qlsn76.googlevideo.com.",
"rr3---sn-p5qlsn7d.googlevideo.com.",
"rr3---sn-p5qlsn7l.googlevideo.com.",
@@ -4595,19 +4928,24 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-p5qlsndr.googlevideo.com.",
"rr3---sn-p5qlsndz.googlevideo.com.",
"rr3---sn-p5qlsnrl.googlevideo.com.",
- "rr3---sn-p5qlsny6.googlevideo.com.",
+ "rr3---sn-p5qlsnrr.googlevideo.com.",
"rr3---sn-p5qs7n6d.googlevideo.com.",
+ "rr3---sn-p5qs7n6y.googlevideo.com.",
+ "rr3---sn-p5qs7nd7.googlevideo.com.",
"rr3---sn-p5qs7nsk.googlevideo.com.",
- "rr3---sn-p5qs7nsr.googlevideo.com.",
"rr3---sn-p5qs7nzk.googlevideo.com.",
"rr3---sn-p5qs7nzr.googlevideo.com.",
"rr3---sn-p5qs7nzy.googlevideo.com.",
+ "rr3---sn-pobpb-poql.googlevideo.com.",
"rr3---sn-q4fl6n66.googlevideo.com.",
"rr3---sn-q4fl6n6d.googlevideo.com.",
"rr3---sn-q4fl6n6r.googlevideo.com.",
"rr3---sn-q4fl6n6s.googlevideo.com.",
+ "rr3---sn-q4fl6n6s.gvt1.com.",
"rr3---sn-q4fl6n6y.googlevideo.com.",
+ "rr3---sn-q4fl6n6y.gvt1.com.",
"rr3---sn-q4fl6n6z.googlevideo.com.",
+ "rr3---sn-q4fl6n6z.gvt1.com.",
"rr3---sn-q4fl6nd7.googlevideo.com.",
"rr3---sn-q4fl6nde.googlevideo.com.",
"rr3---sn-q4fl6ndl.googlevideo.com.",
@@ -4618,55 +4956,71 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-q4fl6ns7.googlevideo.com.",
"rr3---sn-q4fl6nsd.googlevideo.com.",
"rr3---sn-q4fl6nsk.googlevideo.com.",
+ "rr3---sn-q4fl6nsk.gvt1.com.",
"rr3---sn-q4fl6nsl.googlevideo.com.",
+ "rr3---sn-q4fl6nsl.gvt1.com.",
"rr3---sn-q4fl6nsr.googlevideo.com.",
"rr3---sn-q4fl6nss.googlevideo.com.",
"rr3---sn-q4fl6nsy.googlevideo.com.",
"rr3---sn-q4fl6nz6.googlevideo.com.",
+ "rr3---sn-q4fl6nz6.gvt1.com.",
"rr3---sn-q4fl6nz7.googlevideo.com.",
+ "rr3---sn-q4fl6nz7.gvt1.com.",
"rr3---sn-q4fl6nzy.googlevideo.com.",
"rr3---sn-q4flrn7k.googlevideo.com.",
"rr3---sn-q4flrn7r.googlevideo.com.",
"rr3---sn-q4flrn7y.googlevideo.com.",
"rr3---sn-q4flrne6.googlevideo.com.",
+ "rr3---sn-q4flrne6.gvt1.com.",
"rr3---sn-q4flrne7.googlevideo.com.",
+ "rr3---sn-q4flrne7.gvt1.com.",
"rr3---sn-q4flrnee.googlevideo.com.",
+ "rr3---sn-q4flrnee.gvt1.com.",
"rr3---sn-q4flrnek.googlevideo.com.",
+ "rr3---sn-q4flrnek.gvt1.com.",
"rr3---sn-q4flrnel.googlevideo.com.",
"rr3---sn-q4flrner.googlevideo.com.",
"rr3---sn-q4flrnes.googlevideo.com.",
"rr3---sn-q4flrney.googlevideo.com.",
"rr3---sn-q4flrnez.googlevideo.com.",
"rr3---sn-q4flrnl6.googlevideo.com.",
+ "rr3---sn-q4flrnl6.gvt1.com.",
"rr3---sn-q4flrnl7.googlevideo.com.",
"rr3---sn-q4flrnld.googlevideo.com.",
"rr3---sn-q4flrnle.googlevideo.com.",
"rr3---sn-q4flrnlz.googlevideo.com.",
- "rr3---sn-q4flrnsd.googlevideo.com.",
+ "rr3---sn-q4flrnlz.gvt1.com.",
"rr3---sn-q4flrnsk.googlevideo.com.",
+ "rr3---sn-q4flrnsk.gvt1.com.",
"rr3---sn-q4flrnss.googlevideo.com.",
"rr3---sn-q4fzen7e.googlevideo.com.",
+ "rr3---sn-q4fzen7e.gvt1.com.",
"rr3---sn-q4fzen7l.googlevideo.com.",
+ "rr3---sn-q4fzen7l.gvt1.com.",
"rr3---sn-q4fzen7s.googlevideo.com.",
"rr3---sn-q4fzen7y.googlevideo.com.",
"rr3---sn-q4fzene7.googlevideo.com.",
"rr3---sn-q4fzenee.googlevideo.com.",
+ "rr3---sn-q4fzenee.gvt1.com.",
"rr3---sn-qja5mc-5h.googlevideo.com.",
"rr3---sn-qjp5q5-55.googlevideo.com.",
"rr3---sn-qxo7rn7k.googlevideo.com.",
- "rr3---sn-qxo7rn7r.googlevideo.com.",
- "rr3---sn-qxo7rn7y.googlevideo.com.",
+ "rr3---sn-qxo7rne7.googlevideo.com.",
+ "rr3---sn-qxo7rnee.googlevideo.com.",
"rr3---sn-qxoedn7k.googlevideo.com.",
"rr3---sn-qxoedne7.googlevideo.com.",
"rr3---sn-qxoednee.googlevideo.com.",
- "rr3---sn-t0aedn7l.googlevideo.com.",
+ "rr3---sn-qxoednel.googlevideo.com.",
+ "rr3---sn-qxoednes.googlevideo.com.",
+ "rr3---sn-u1hp55-5c.googlevideo.com.",
+ "rr3---sn-u1hp55-5c.gvt1.com.",
+ "rr3---sn-v5goxu-jhil.googlevideo.com.",
"rr3---sn-vgqskn66.googlevideo.com.",
"rr3---sn-vgqskn67.googlevideo.com.",
"rr3---sn-vgqskn6d.googlevideo.com.",
"rr3---sn-vgqskn6s.googlevideo.com.",
"rr3---sn-vgqskn6z.googlevideo.com.",
"rr3---sn-vgqskne6.googlevideo.com.",
- "rr3---sn-vgqskned.googlevideo.com.",
"rr3---sn-vgqsknek.googlevideo.com.",
"rr3---sn-vgqsknes.googlevideo.com.",
"rr3---sn-vgqsknez.googlevideo.com.",
@@ -4683,7 +5037,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-vgqsknz7.googlevideo.com.",
"rr3---sn-vgqsknzd.googlevideo.com.",
"rr3---sn-vgqsknze.googlevideo.com.",
- "rr3---sn-vgqsknzk.googlevideo.com.",
"rr3---sn-vgqsknzl.googlevideo.com.",
"rr3---sn-vgqsknzr.googlevideo.com.",
"rr3---sn-vgqsknzs.googlevideo.com.",
@@ -4703,12 +5056,10 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-vgqsrnld.googlevideo.com.",
"rr3---sn-vgqsrnlk.googlevideo.com.",
"rr3---sn-vgqsrnll.googlevideo.com.",
- "rr3---sn-vgqsrnls.googlevideo.com.",
"rr3---sn-vgqsrnlz.googlevideo.com.",
"rr3---sn-vgqsrns6.googlevideo.com.",
"rr3---sn-vgqsrnsd.googlevideo.com.",
"rr3---sn-vgqsrnsr.googlevideo.com.",
- "rr3---sn-vgqsrnsy.googlevideo.com.",
"rr3---sn-vgqsrnz6.googlevideo.com.",
"rr3---sn-vgqsrnz7.googlevideo.com.",
"rr3---sn-vgqsrnzd.googlevideo.com.",
@@ -4717,40 +5068,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-vgqsrnzs.googlevideo.com.",
"rr3---sn-vgqsrnzy.googlevideo.com.",
"rr3---sn-vgqsrnzz.googlevideo.com.",
- "rr3.sn-2oq4f5-c4.googlevideo.com.",
- "rr3.sn-2ovgq5-cw.googlevideo.com.",
- "rr3.sn-a5m7lnl6.googlevideo.com.",
- "rr3.sn-a5m7lnld.googlevideo.com.",
- "rr3.sn-a5mekn6d.googlevideo.com.",
- "rr3.sn-a5mekn6k.googlevideo.com.",
- "rr3.sn-a5mekn6l.googlevideo.com.",
- "rr3.sn-a5mekn6r.googlevideo.com.",
- "rr3.sn-a5mekn6s.googlevideo.com.",
- "rr3.sn-a5mekn6z.googlevideo.com.",
- "rr3.sn-a5meknd6.googlevideo.com.",
- "rr3.sn-a5meknde.googlevideo.com.",
- "rr3.sn-a5mekndl.googlevideo.com.",
- "rr3.sn-a5meknds.googlevideo.com.",
- "rr3.sn-a5mekndz.googlevideo.com.",
- "rr3.sn-a5meknsd.googlevideo.com.",
- "rr3.sn-a5meknsy.googlevideo.com.",
- "rr3.sn-a5meknzk.googlevideo.com.",
- "rr3.sn-a5meknzl.googlevideo.com.",
- "rr3.sn-a5meknzr.googlevideo.com.",
- "rr3.sn-a5meknzs.googlevideo.com.",
- "rr3.sn-a5mlrnek.googlevideo.com.",
- "rr3.sn-a5mlrnl6.googlevideo.com.",
- "rr3.sn-a5mlrnll.googlevideo.com.",
- "rr3.sn-a5mlrnls.googlevideo.com.",
- "rr3.sn-a5mlrnlz.googlevideo.com.",
- "rr3.sn-a5msen76.googlevideo.com.",
- "rr3.sn-a5msen7s.googlevideo.com.",
- "rr3.sn-a5msen7z.googlevideo.com.",
- "rr3.sn-a5msenek.googlevideo.com.",
- "rr3.sn-a5msener.googlevideo.com.",
- "rr3.sn-a5msenes.googlevideo.com.",
- "rr3.sn-a5msenl7.googlevideo.com.",
- "rr3.sn-a5msenle.googlevideo.com.",
+ "rr3.sn-hgn7rn7k.googlevideo.com.",
"rr3.sn-hp57kn6r.googlevideo.com.",
"rr3.sn-hp57kn6y.googlevideo.com.",
"rr3.sn-hp57knd6.googlevideo.com.",
@@ -4761,7 +5079,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3.sn-hp57kndy.googlevideo.com.",
"rr3.sn-hp57kndz.googlevideo.com.",
"rr3.sn-hp57knk7.googlevideo.com.",
- "rr3.sn-hp57yn7y.googlevideo.com.",
"rr3.sn-hp57ynl6.googlevideo.com.",
"rr3.sn-hp57ynlr.googlevideo.com.",
"rr3.sn-hp57ynly.googlevideo.com.",
@@ -4770,96 +5087,33 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3.sn-hp57ynsl.googlevideo.com.",
"rr3.sn-hp57ynss.googlevideo.com.",
"rr3.sn-nx57ynsk.googlevideo.com.",
- "rr3.sn-q4fl6n66.googlevideo.com.",
- "rr3.sn-q4fl6n6r.googlevideo.com.",
- "rr3.sn-q4fl6nd7.googlevideo.com.",
- "rr3.sn-q4fl6nz7.googlevideo.com.",
- "rr3.sn-q4fl6nzy.googlevideo.com.",
"rr3.sn-q4flrnl6.googlevideo.com.",
- "rr3.sn-q4flrnld.googlevideo.com.",
- "rr3.sn-q4flrnle.googlevideo.com.",
- "rr3.sn-q4flrnlz.googlevideo.com.",
- "rr3.sn-q4flrnsk.googlevideo.com.",
- "rr3.sn-q4flrnss.googlevideo.com.",
- "rr3.sn-q4fzen7e.googlevideo.com.",
"rr3.sn-q4fzen7l.googlevideo.com.",
- "rr3.sn-q4fzen7s.googlevideo.com.",
- "rr3.sn-q4fzen7y.googlevideo.com.",
- "rr3.sn-q4fzene7.googlevideo.com.",
- "rr3.sn-qja5mc-5h.googlevideo.com.",
- "rr3.sn-vgqskn66.googlevideo.com.",
- "rr3.sn-vgqskn67.googlevideo.com.",
- "rr3.sn-vgqskn6d.googlevideo.com.",
- "rr3.sn-vgqskn6s.googlevideo.com.",
- "rr3.sn-vgqskn6z.googlevideo.com.",
- "rr3.sn-vgqsknld.googlevideo.com.",
- "rr3.sn-vgqsknlk.googlevideo.com.",
- "rr3.sn-vgqsknlr.googlevideo.com.",
- "rr3.sn-vgqskns7.googlevideo.com.",
- "rr3.sn-vgqsknse.googlevideo.com.",
- "rr3.sn-vgqsknsk.googlevideo.com.",
- "rr3.sn-vgqsknz6.googlevideo.com.",
- "rr3.sn-vgqsknz7.googlevideo.com.",
- "rr3.sn-vgqsknzd.googlevideo.com.",
- "rr3.sn-vgqsknze.googlevideo.com.",
- "rr3.sn-vgqsknzk.googlevideo.com.",
- "rr3.sn-vgqsknzl.googlevideo.com.",
- "rr3.sn-vgqsknzr.googlevideo.com.",
- "rr3.sn-vgqsknzs.googlevideo.com.",
- "rr3.sn-vgqsknzy.googlevideo.com.",
- "rr3.sn-vgqsknzz.googlevideo.com.",
- "rr3.sn-vgqsrn66.googlevideo.com.",
- "rr3.sn-vgqsrn67.googlevideo.com.",
- "rr3.sn-vgqsrn6e.googlevideo.com.",
- "rr3.sn-vgqsrn6l.googlevideo.com.",
- "rr3.sn-vgqsrn6z.googlevideo.com.",
- "rr3.sn-vgqsrnl6.googlevideo.com.",
- "rr3.sn-vgqsrnld.googlevideo.com.",
- "rr3.sn-vgqsrnlk.googlevideo.com.",
- "rr3.sn-vgqsrnls.googlevideo.com.",
- "rr3.sn-vgqsrnlz.googlevideo.com.",
- "rr3.sn-vgqsrns6.googlevideo.com.",
- "rr3.sn-vgqsrnsd.googlevideo.com.",
- "rr3.sn-vgqsrnsr.googlevideo.com.",
- "rr3.sn-vgqsrnsy.googlevideo.com.",
- "rr3.sn-vgqsrnz6.googlevideo.com.",
- "rr3.sn-vgqsrnz7.googlevideo.com.",
- "rr3.sn-vgqsrnzd.googlevideo.com.",
- "rr3.sn-vgqsrnzk.googlevideo.com.",
- "rr3.sn-vgqsrnzr.googlevideo.com.",
- "rr3.sn-vgqsrnzs.googlevideo.com.",
- "rr3.sn-vgqsrnzy.googlevideo.com.",
+ "rr3.sn-u1hp55-5c.googlevideo.com.",
"rr3.sn-vgqsrnzz.googlevideo.com.",
"rr4---sn-0nnpbo5a-bggl.googlevideo.com.",
"rr4---sn-2aqu-hoas7.googlevideo.com.",
- "rr4---sn-2aqu-hoasd.googlevideo.com.",
- "rr4---sn-2aqu-hoasz.googlevideo.com.",
- "rr4---sn-2aqu-jbt6.googlevideo.com.",
- "rr4---sn-2aqu-jbtd.googlevideo.com.",
- "rr4---sn-2aqu-jxcr.googlevideo.com.",
- "rr4---sn-2aqu-jxcy.googlevideo.com.",
"rr4---sn-2imern76.googlevideo.com.",
+ "rr4---sn-2imern76.gvt1.com.",
"rr4---sn-2imern7d.googlevideo.com.",
+ "rr4---sn-2imern7r.googlevideo.com.",
"rr4---sn-2imeyn7k.googlevideo.com.",
+ "rr4---sn-2imeyn7k.gvt1.com.",
"rr4---sn-2o5ua5-53.googlevideo.com.",
"rr4---sn-2oaig5-55.googlevideo.com.",
+ "rr4---sn-2op5q5-58.googlevideo.com.",
"rr4---sn-2oq4f5-c4.googlevideo.com.",
+ "rr4---sn-2oq4f5-c4.gvt1.com.",
"rr4---sn-2ovgq5-cw.googlevideo.com.",
"rr4---sn-30a7rned.googlevideo.com.",
"rr4---sn-30a7rnek.googlevideo.com.",
"rr4---sn-30a7rner.googlevideo.com.",
"rr4---sn-30a7ynek.googlevideo.com.",
+ "rr4---sn-30a7yney.googlevideo.com.",
"rr4---sn-30a7ynl7.googlevideo.com.",
- "rr4---sn-42u-nbosr.googlevideo.com.",
- "rr4---sn-42u-nboze.googlevideo.com.",
- "rr4---sn-42u-nbozl.googlevideo.com.",
- "rr4---sn-42u-nbozs.googlevideo.com.",
- "rr4---sn-42u-nbozz.googlevideo.com.",
"rr4---sn-4g5e6ns6.googlevideo.com.",
"rr4---sn-4g5e6ns7.googlevideo.com.",
- "rr4---sn-4g5e6nsd.googlevideo.com.",
"rr4---sn-4g5e6nsk.googlevideo.com.",
- "rr4---sn-4g5e6nsr.googlevideo.com.",
"rr4---sn-4g5e6nss.googlevideo.com.",
"rr4---sn-4g5e6nsy.googlevideo.com.",
"rr4---sn-4g5e6nz7.googlevideo.com.",
@@ -4876,7 +5130,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-4g5edndk.googlevideo.com.",
"rr4---sn-4g5edndl.googlevideo.com.",
"rr4---sn-4g5edndr.googlevideo.com.",
- "rr4---sn-4g5ednds.googlevideo.com.",
"rr4---sn-4g5edndy.googlevideo.com.",
"rr4---sn-4g5edndz.googlevideo.com.",
"rr4---sn-4g5ednkl.googlevideo.com.",
@@ -4905,16 +5158,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-4g5lznle.googlevideo.com.",
"rr4---sn-4g5lznls.googlevideo.com.",
"rr4---sn-4g5lznlz.googlevideo.com.",
- "rr4---sn-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
- "rr4---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
"rr4---sn-5abxgpxuxaxjvh-9n4z.googlevideo.com.",
- "rr4---sn-5abxgpxuxaxjvh-cawe.googlevideo.com.",
- "rr4---sn-5abxgpxuxaxjvh-caws.googlevideo.com.",
- "rr4---sn-5abxgpxuxaxjvh-j1ae.googlevideo.com.",
- "rr4---sn-5abxgpxuxaxjvh-j1az.googlevideo.com.",
- "rr4---sn-5go7yner.googlevideo.com.",
"rr4---sn-5go7ynl6.googlevideo.com.",
- "rr4---sn-5go7ynld.googlevideo.com.",
"rr4---sn-5goeenes.googlevideo.com.",
"rr4---sn-5goeenez.googlevideo.com.",
"rr4---sn-5hne6n6e.googlevideo.com.",
@@ -4928,7 +5173,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-5hne6nz6.googlevideo.com.",
"rr4---sn-5hne6nzd.googlevideo.com.",
"rr4---sn-5hne6nzk.googlevideo.com.",
- "rr4---sn-5hne6nzs.googlevideo.com.",
"rr4---sn-5hne6nzy.googlevideo.com.",
"rr4---sn-5hnednss.googlevideo.com.",
"rr4---sn-5hnednsz.googlevideo.com.",
@@ -4936,7 +5180,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-5hnekn7d.googlevideo.com.",
"rr4---sn-5hnekn7l.googlevideo.com.",
"rr4---sn-5hnekn7s.googlevideo.com.",
- "rr4---sn-5hnekn7z.googlevideo.com.",
"rr4---sn-5hneknee.googlevideo.com.",
"rr4---sn-5hneknek.googlevideo.com.",
"rr4---sn-5hneknes.googlevideo.com.",
@@ -4947,10 +5190,10 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-5uaeznes.googlevideo.com.",
"rr4---sn-5uaeznez.googlevideo.com.",
"rr4---sn-5uaeznl6.googlevideo.com.",
+ "rr4---sn-5uaeznl6.gvt1.com.",
"rr4---sn-5uaeznld.googlevideo.com.",
"rr4---sn-5uaeznls.googlevideo.com.",
"rr4---sn-5uaeznly.googlevideo.com.",
- "rr4---sn-5uaeznlz.googlevideo.com.",
"rr4---sn-5uaeznse.googlevideo.com.",
"rr4---sn-5uaeznsl.googlevideo.com.",
"rr4---sn-5uaeznss.googlevideo.com.",
@@ -4961,49 +5204,40 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-5ualdnll.googlevideo.com.",
"rr4---sn-5ualdnlr.googlevideo.com.",
"rr4---sn-5ualdnls.googlevideo.com.",
+ "rr4---sn-5ualdns6.googlevideo.com.",
"rr4---sn-5ualdns7.googlevideo.com.",
"rr4---sn-5ualdnsd.googlevideo.com.",
"rr4---sn-5ualdnse.googlevideo.com.",
"rr4---sn-5ualdnsk.googlevideo.com.",
- "rr4---sn-5ualdnsl.googlevideo.com.",
"rr4---sn-5ualdnsr.googlevideo.com.",
"rr4---sn-5ualdnss.googlevideo.com.",
+ "rr4---sn-5ualdnss.gvt1.com.",
"rr4---sn-5ualdnsy.googlevideo.com.",
"rr4---sn-5ualdnsz.googlevideo.com.",
"rr4---sn-5ualdnz7.googlevideo.com.",
"rr4---sn-5ualdnze.googlevideo.com.",
- "rr4---sn-8pxuuxa-nbo6l.googlevideo.com.",
- "rr4---sn-8pxuuxa-nbo6s.googlevideo.com.",
- "rr4---sn-8pxuuxa-nboz6.googlevideo.com.",
- "rr4---sn-8qj-i2iez.googlevideo.com.",
- "rr4---sn-8qj-i5o6d.googlevideo.com.",
"rr4---sn-8qj-i5o6k.googlevideo.com.",
- "rr4---sn-8qj-i5ody.googlevideo.com.",
- "rr4---sn-8qj-i5oks.googlevideo.com.",
- "rr4---sn-8qj-i5ozd.googlevideo.com.",
- "rr4---sn-8qj-i5ozr.googlevideo.com.",
- "rr4---sn-8qj-i5ozz.googlevideo.com.",
"rr4---sn-8qj-nbo66.googlevideo.com.",
- "rr4---sn-8qj-nbo67.googlevideo.com.",
+ "rr4---sn-8qj-nbosd.googlevideo.com.",
"rr4---sn-8xgp1vo-ab56.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5l.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5s.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5z.googlevideo.com.",
- "rr4---sn-8xgp1vo-nh4e.googlevideo.com.",
+ "rr4---sn-8xgp1vo-p5qe.googlevideo.com.",
+ "rr4---sn-8xgp1vo-p5qe7.googlevideo.com.",
+ "rr4---sn-8xgp1vo-p5qee.googlevideo.com.",
+ "rr4---sn-8xgp1vo-p5qel.googlevideo.com.",
"rr4---sn-8xgp1vo-poql.googlevideo.com.",
+ "rr4---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr4---sn-8xgp1vo-xfge.googlevideo.com.",
"rr4---sn-8xgp1vo-xfgl.googlevideo.com.",
"rr4---sn-8xgp1vo-xfgs.googlevideo.com.",
- "rr4---sn-9gv76n7e.googlevideo.com.",
"rr4---sn-9gv76n7s.googlevideo.com.",
"rr4---sn-9gv76n7z.googlevideo.com.",
- "rr4---sn-9gv7ene6.googlevideo.com.",
- "rr4---sn-9gv7ened.googlevideo.com.",
"rr4---sn-9gv7zn76.googlevideo.com.",
"rr4---sn-9gv7zn7e.googlevideo.com.",
- "rr4---sn-9gv7zn7r.googlevideo.com.",
"rr4---sn-a5m7lnl6.googlevideo.com.",
"rr4---sn-a5m7lnld.googlevideo.com.",
"rr4---sn-a5mekn6d.googlevideo.com.",
@@ -5089,18 +5323,32 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-aigzrnsz.googlevideo.com.",
"rr4---sn-aigzrnz7.googlevideo.com.",
"rr4---sn-aigzrnze.googlevideo.com.",
+ "rr4---sn-aj4g55-5v.googlevideo.com.",
+ "rr4---sn-aj5ua5-5c.googlevideo.com.",
+ "rr4---sn-ajab55-55.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
"rr4---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
- "rr4---sn-c0q7lnz7.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxqjvhj5nu-vgqz.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxqjvm-2ime.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxqjvm-2ims.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
+ "rr4---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
"rr4---sn-cvb7lne7.googlevideo.com.",
"rr4---sn-cvb7lnee.googlevideo.com.",
"rr4---sn-cvb7lnlz.googlevideo.com.",
"rr4---sn-cvb7sn7k.googlevideo.com.",
"rr4---sn-cvb7sn7r.googlevideo.com.",
- "rr4---sn-gxuo03g-ig3e.googlevideo.com.",
- "rr4---sn-h0jeenl6.googlevideo.com.",
- "rr4---sn-h0jeenld.googlevideo.com.",
- "rr4---sn-h0jelne6.googlevideo.com.",
- "rr4---sn-h0jelnes.googlevideo.com.",
"rr4---sn-hoa7kn7z.googlevideo.com.",
"rr4---sn-hoa7kn7z.gvt1.com.",
"rr4---sn-hoa7rn76.googlevideo.com.",
@@ -5110,12 +5358,11 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-hp57kn6r.googlevideo.com.",
"rr4---sn-hp57kn6r.gvt1.com.",
"rr4---sn-hp57kn6y.googlevideo.com.",
+ "rr4---sn-hp57kn6y.gvt1.com.",
"rr4---sn-hp57knd6.googlevideo.com.",
"rr4---sn-hp57kndd.googlevideo.com.",
- "rr4---sn-hp57kndd.gvt1.com.",
"rr4---sn-hp57kndk.googlevideo.com.",
"rr4---sn-hp57kndr.googlevideo.com.",
- "rr4---sn-hp57kndr.gvt1.com.",
"rr4---sn-hp57knds.googlevideo.com.",
"rr4---sn-hp57kndy.googlevideo.com.",
"rr4---sn-hp57kndz.googlevideo.com.",
@@ -5126,13 +5373,16 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-hp57yne7.googlevideo.com.",
"rr4---sn-hp57ynee.googlevideo.com.",
"rr4---sn-hp57ynl6.googlevideo.com.",
+ "rr4---sn-hp57ynl6.gvt1.com.",
"rr4---sn-hp57ynlr.googlevideo.com.",
"rr4---sn-hp57ynly.googlevideo.com.",
"rr4---sn-hp57yns7.googlevideo.com.",
+ "rr4---sn-hp57yns7.gvt1.com.",
"rr4---sn-hp57ynse.googlevideo.com.",
"rr4---sn-hp57ynsl.googlevideo.com.",
+ "rr4---sn-hp57ynsl.gvt1.com.",
"rr4---sn-hp57ynss.googlevideo.com.",
- "rr4---sn-huxaqvv-ubqe.googlevideo.com.",
+ "rr4---sn-hp57ynss.gvt1.com.",
"rr4---sn-i3b7kn6s.googlevideo.com.",
"rr4---sn-i3b7knld.googlevideo.com.",
"rr4---sn-i3b7knlk.googlevideo.com.",
@@ -5145,12 +5395,14 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-i3belne6.googlevideo.com.",
"rr4---sn-i3belney.googlevideo.com.",
"rr4---sn-i3belnl7.googlevideo.com.",
+ "rr4---sn-i3belnll.googlevideo.com.",
"rr4---sn-i3belnls.googlevideo.com.",
"rr4---sn-i3bssn7e.googlevideo.com.",
- "rr4---sn-jvhj5nu-nh4e.googlevideo.com.",
- "rr4---sn-jvhj5nu-nh4l.googlevideo.com.",
- "rr4---sn-jvhj5nu-nh4s.googlevideo.com.",
- "rr4---sn-jvhj5nu-nh4z.googlevideo.com.",
+ "rr4---sn-jn2pgx4pcxg-w5o6.googlevideo.com.",
+ "rr4---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr4---sn-jxopj-n5oe.googlevideo.com.",
+ "rr4---sn-jxopj-nh4e.googlevideo.com.",
+ "rr4---sn-jxopj-nh4e.gvt1.com.",
"rr4---sn-n4v7snee.googlevideo.com.",
"rr4---sn-n4v7sney.googlevideo.com.",
"rr4---sn-n4v7snl7.googlevideo.com.",
@@ -5160,7 +5412,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-n4v7sns7.googlevideo.com.",
"rr4---sn-n4v7snse.googlevideo.com.",
"rr4---sn-npoe7ndl.googlevideo.com.",
- "rr4---sn-npoe7ndl.gvt1.com.",
+ "rr4---sn-npoe7ne6.googlevideo.com.",
"rr4---sn-npoe7ne7.googlevideo.com.",
"rr4---sn-npoe7ned.googlevideo.com.",
"rr4---sn-npoe7nek.googlevideo.com.",
@@ -5171,64 +5423,46 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-npoe7nl6.googlevideo.com.",
"rr4---sn-npoe7nlz.googlevideo.com.",
"rr4---sn-npoe7ns6.googlevideo.com.",
- "rr4---sn-npoe7ns6.gvt1.com.",
"rr4---sn-npoe7ns7.googlevideo.com.",
"rr4---sn-npoe7ns7.gvt1.com.",
"rr4---sn-npoe7nsd.googlevideo.com.",
"rr4---sn-npoe7nsk.googlevideo.com.",
- "rr4---sn-npoe7nsk.gvt1.com.",
"rr4---sn-npoe7nsl.googlevideo.com.",
"rr4---sn-npoe7nsr.googlevideo.com.",
- "rr4---sn-npoe7nss.googlevideo.com.",
- "rr4---sn-npoe7nss.gvt1.com.",
"rr4---sn-npoe7nsy.googlevideo.com.",
- "rr4---sn-npoe7nsy.gvt1.com.",
"rr4---sn-npoe7nz7.googlevideo.com.",
- "rr4---sn-npoe7nz7.gvt1.com.",
"rr4---sn-npoeene6.googlevideo.com.",
"rr4---sn-npoeened.googlevideo.com.",
"rr4---sn-npoeenee.googlevideo.com.",
"rr4---sn-npoeenek.googlevideo.com.",
"rr4---sn-npoeener.googlevideo.com.",
- "rr4---sn-npoeener.gvt1.com.",
"rr4---sn-npoeeney.googlevideo.com.",
+ "rr4---sn-npoeenez.googlevideo.com.",
"rr4---sn-npoeenl7.googlevideo.com.",
- "rr4---sn-npoeenl7.gvt1.com.",
"rr4---sn-npoeenle.googlevideo.com.",
"rr4---sn-npoeenlk.googlevideo.com.",
"rr4---sn-npoeenlk.gvt1.com.",
"rr4---sn-npoeenll.googlevideo.com.",
+ "rr4---sn-npoeenll.gvt1.com.",
"rr4---sn-npoeenly.googlevideo.com.",
- "rr4---sn-npoeenly.gvt1.com.",
"rr4---sn-npoeens7.googlevideo.com.",
- "rr4---sn-npoeens7.gvt1.com.",
"rr4---sn-npoldn76.googlevideo.com.",
- "rr4---sn-npoldn76.gvt1.com.",
"rr4---sn-npoldn7d.googlevideo.com.",
- "rr4---sn-npoldn7d.gvt1.com.",
"rr4---sn-npoldn7e.googlevideo.com.",
- "rr4---sn-npoldn7e.gvt1.com.",
"rr4---sn-npoldn7l.googlevideo.com.",
"rr4---sn-npoldn7l.gvt1.com.",
- "rr4---sn-npoldn7s.googlevideo.com.",
"rr4---sn-npoldn7y.googlevideo.com.",
- "rr4---sn-npoldn7y.gvt1.com.",
"rr4---sn-npoldn7z.googlevideo.com.",
- "rr4---sn-npoldn7z.gvt1.com.",
- "rr4---sn-npoldne7.googlevideo.com.",
- "rr4---sn-npoldne7.gvt1.com.",
- "rr4---sn-ntqe6n7r.googlevideo.com.",
- "rr4---sn-nv47ln6e.googlevideo.com.",
- "rr4---sn-nv47zn7y.googlevideo.com.",
- "rr4---sn-nv47zne7.googlevideo.com.",
- "rr4---sn-nv47znee.googlevideo.com.",
- "rr4---sn-nv47znel.googlevideo.com.",
- "rr4---sn-nx57ynlk.googlevideo.com.",
+ "rr4---sn-ntq7yned.googlevideo.com.",
"rr4---sn-nx57ynsd.googlevideo.com.",
"rr4---sn-nx57ynse.googlevideo.com.",
"rr4---sn-nx57ynsk.googlevideo.com.",
- "rr4---sn-nx57ynss.googlevideo.com.",
+ "rr4---sn-nx57ynsl.googlevideo.com.",
+ "rr4---sn-nx57ynsr.googlevideo.com.",
+ "rr4---sn-nx57ynsy.googlevideo.com.",
"rr4---sn-nx57ynsz.googlevideo.com.",
+ "rr4---sn-nx57ynz7.googlevideo.com.",
+ "rr4---sn-nx57ynze.googlevideo.com.",
"rr4---sn-o097znsd.googlevideo.com.",
"rr4---sn-o097znse.googlevideo.com.",
"rr4---sn-o097znsk.googlevideo.com.",
@@ -5239,7 +5473,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-o097znz7.googlevideo.com.",
"rr4---sn-o097znzd.googlevideo.com.",
"rr4---sn-o097znze.googlevideo.com.",
- "rr4---sn-o097znzk.googlevideo.com.",
"rr4---sn-o097znzr.googlevideo.com.",
"rr4---sn-oj5hn5-55.googlevideo.com.",
"rr4---sn-oji3bc-5j.googlevideo.com.",
@@ -5249,6 +5482,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-p5qddn7r.googlevideo.com.",
"rr4---sn-p5qddn7z.googlevideo.com.",
"rr4---sn-p5qlsn6l.googlevideo.com.",
+ "rr4---sn-p5qlsn6s.googlevideo.com.",
+ "rr4---sn-p5qlsn6z.googlevideo.com.",
"rr4---sn-p5qlsn76.googlevideo.com.",
"rr4---sn-p5qlsn7d.googlevideo.com.",
"rr4---sn-p5qlsn7l.googlevideo.com.",
@@ -5256,13 +5491,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-p5qlsnd6.googlevideo.com.",
"rr4---sn-p5qlsndk.googlevideo.com.",
"rr4---sn-p5qlsndr.googlevideo.com.",
- "rr4---sn-p5qlsndz.googlevideo.com.",
"rr4---sn-p5qlsnrl.googlevideo.com.",
"rr4---sn-p5qlsnrr.googlevideo.com.",
"rr4---sn-p5qlsny6.googlevideo.com.",
"rr4---sn-p5qs7n6d.googlevideo.com.",
+ "rr4---sn-p5qs7nd7.googlevideo.com.",
"rr4---sn-p5qs7nsk.googlevideo.com.",
- "rr4---sn-p5qs7nsr.googlevideo.com.",
"rr4---sn-p5qs7nzk.googlevideo.com.",
"rr4---sn-p5qs7nzr.googlevideo.com.",
"rr4---sn-p5qs7nzy.googlevideo.com.",
@@ -5270,26 +5504,37 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-q4fl6n6d.googlevideo.com.",
"rr4---sn-q4fl6n6s.googlevideo.com.",
"rr4---sn-q4fl6n6y.googlevideo.com.",
+ "rr4---sn-q4fl6n6y.gvt1.com.",
"rr4---sn-q4fl6n6z.googlevideo.com.",
"rr4---sn-q4fl6nd7.googlevideo.com.",
"rr4---sn-q4fl6nde.googlevideo.com.",
+ "rr4---sn-q4fl6nde.gvt1.com.",
"rr4---sn-q4fl6ndl.googlevideo.com.",
"rr4---sn-q4fl6nds.googlevideo.com.",
"rr4---sn-q4fl6ndz.googlevideo.com.",
"rr4---sn-q4fl6nlz.googlevideo.com.",
"rr4---sn-q4fl6ns6.googlevideo.com.",
+ "rr4---sn-q4fl6ns6.gvt1.com.",
"rr4---sn-q4fl6ns7.googlevideo.com.",
"rr4---sn-q4fl6nsd.googlevideo.com.",
+ "rr4---sn-q4fl6nsd.gvt1.com.",
"rr4---sn-q4fl6nsk.googlevideo.com.",
"rr4---sn-q4fl6nsl.googlevideo.com.",
"rr4---sn-q4fl6nsr.googlevideo.com.",
"rr4---sn-q4fl6nss.googlevideo.com.",
"rr4---sn-q4fl6nsy.googlevideo.com.",
+ "rr4---sn-q4fl6nsy.gvt1.com.",
"rr4---sn-q4fl6nz6.googlevideo.com.",
+ "rr4---sn-q4fl6nz6.gvt1.com.",
"rr4---sn-q4fl6nz7.googlevideo.com.",
+ "rr4---sn-q4fl6nz7.gvt1.com.",
"rr4---sn-q4fl6nzy.googlevideo.com.",
+ "rr4---sn-q4fl6nzy.gvt1.com.",
"rr4---sn-q4flrn7k.googlevideo.com.",
"rr4---sn-q4flrn7r.googlevideo.com.",
+ "rr4---sn-q4flrn7r.gvt1.com.",
+ "rr4---sn-q4flrn7y.googlevideo.com.",
+ "rr4---sn-q4flrn7y.gvt1.com.",
"rr4---sn-q4flrne6.googlevideo.com.",
"rr4---sn-q4flrne7.googlevideo.com.",
"rr4---sn-q4flrnee.googlevideo.com.",
@@ -5301,34 +5546,41 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-q4flrnez.googlevideo.com.",
"rr4---sn-q4flrnl6.googlevideo.com.",
"rr4---sn-q4flrnl7.googlevideo.com.",
+ "rr4---sn-q4flrnl7.gvt1.com.",
"rr4---sn-q4flrnld.googlevideo.com.",
"rr4---sn-q4flrnle.googlevideo.com.",
"rr4---sn-q4flrnlz.googlevideo.com.",
"rr4---sn-q4flrnsd.googlevideo.com.",
- "rr4---sn-q4flrnsk.googlevideo.com.",
+ "rr4---sn-q4flrnsd.gvt1.com.",
"rr4---sn-q4flrnsl.googlevideo.com.",
+ "rr4---sn-q4flrnsl.gvt1.com.",
"rr4---sn-q4flrnss.googlevideo.com.",
"rr4---sn-q4fzen7e.googlevideo.com.",
"rr4---sn-q4fzen7l.googlevideo.com.",
+ "rr4---sn-q4fzen7l.gvt1.com.",
"rr4---sn-q4fzen7s.googlevideo.com.",
+ "rr4---sn-q4fzen7s.gvt1.com.",
"rr4---sn-q4fzen7y.googlevideo.com.",
"rr4---sn-q4fzene7.googlevideo.com.",
+ "rr4---sn-q4fzene7.gvt1.com.",
"rr4---sn-q4fzenee.googlevideo.com.",
"rr4---sn-qja5mc-5h.googlevideo.com.",
"rr4---sn-qjp5q5-55.googlevideo.com.",
"rr4---sn-qxo7rn7k.googlevideo.com.",
- "rr4---sn-qxo7rn7r.googlevideo.com.",
- "rr4---sn-qxo7rn7y.googlevideo.com.",
+ "rr4---sn-qxo7rne7.googlevideo.com.",
+ "rr4---sn-qxo7rnee.googlevideo.com.",
"rr4---sn-qxoedn7k.googlevideo.com.",
"rr4---sn-qxoedne7.googlevideo.com.",
- "rr4---sn-t0aedn7l.googlevideo.com.",
+ "rr4---sn-qxoednee.googlevideo.com.",
+ "rr4---sn-qxoednel.googlevideo.com.",
+ "rr4---sn-qxoednes.googlevideo.com.",
"rr4---sn-u1hp55-5c.googlevideo.com.",
+ "rr4---sn-v5goxu-jhil.googlevideo.com.",
"rr4---sn-vgqskn66.googlevideo.com.",
"rr4---sn-vgqskn67.googlevideo.com.",
"rr4---sn-vgqskn6d.googlevideo.com.",
"rr4---sn-vgqskn6s.googlevideo.com.",
"rr4---sn-vgqskn6z.googlevideo.com.",
- "rr4---sn-vgqskne6.googlevideo.com.",
"rr4---sn-vgqskned.googlevideo.com.",
"rr4---sn-vgqsknek.googlevideo.com.",
"rr4---sn-vgqsknes.googlevideo.com.",
@@ -5336,6 +5588,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-vgqsknld.googlevideo.com.",
"rr4---sn-vgqsknlk.googlevideo.com.",
"rr4---sn-vgqsknll.googlevideo.com.",
+ "rr4---sn-vgqsknlr.googlevideo.com.",
"rr4---sn-vgqsknls.googlevideo.com.",
"rr4---sn-vgqsknlz.googlevideo.com.",
"rr4---sn-vgqskns7.googlevideo.com.",
@@ -5378,40 +5631,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-vgqsrnzr.googlevideo.com.",
"rr4---sn-vgqsrnzs.googlevideo.com.",
"rr4---sn-vgqsrnzy.googlevideo.com.",
+ "rr4---sn-vgqsrnzy.gvt1.com.",
"rr4---sn-vgqsrnzz.googlevideo.com.",
- "rr4.sn-2oq4f5-c4.googlevideo.com.",
- "rr4.sn-2ovgq5-cw.googlevideo.com.",
- "rr4.sn-a5m7lnl6.googlevideo.com.",
- "rr4.sn-a5m7lnld.googlevideo.com.",
- "rr4.sn-a5mekn6d.googlevideo.com.",
- "rr4.sn-a5mekn6k.googlevideo.com.",
- "rr4.sn-a5mekn6l.googlevideo.com.",
- "rr4.sn-a5mekn6r.googlevideo.com.",
- "rr4.sn-a5mekn6s.googlevideo.com.",
- "rr4.sn-a5mekn6z.googlevideo.com.",
- "rr4.sn-a5meknd6.googlevideo.com.",
- "rr4.sn-a5meknde.googlevideo.com.",
- "rr4.sn-a5mekndl.googlevideo.com.",
- "rr4.sn-a5meknds.googlevideo.com.",
- "rr4.sn-a5meknsd.googlevideo.com.",
- "rr4.sn-a5meknsy.googlevideo.com.",
- "rr4.sn-a5meknzk.googlevideo.com.",
- "rr4.sn-a5meknzr.googlevideo.com.",
- "rr4.sn-a5meknzs.googlevideo.com.",
- "rr4.sn-a5mlrnek.googlevideo.com.",
- "rr4.sn-a5mlrnl6.googlevideo.com.",
- "rr4.sn-a5mlrnll.googlevideo.com.",
- "rr4.sn-a5mlrnls.googlevideo.com.",
- "rr4.sn-a5mlrnlz.googlevideo.com.",
- "rr4.sn-a5msen76.googlevideo.com.",
- "rr4.sn-a5msen7l.googlevideo.com.",
- "rr4.sn-a5msen7s.googlevideo.com.",
- "rr4.sn-a5msen7z.googlevideo.com.",
- "rr4.sn-a5msenek.googlevideo.com.",
- "rr4.sn-a5msener.googlevideo.com.",
- "rr4.sn-a5msenes.googlevideo.com.",
- "rr4.sn-a5msenl7.googlevideo.com.",
- "rr4.sn-a5msenle.googlevideo.com.",
+ "rr4---sn-vgqsrnzz.gvt1.com.",
"rr4.sn-hp57kn6r.googlevideo.com.",
"rr4.sn-hp57kn6y.googlevideo.com.",
"rr4.sn-hp57knd6.googlevideo.com.",
@@ -5422,8 +5644,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4.sn-hp57kndy.googlevideo.com.",
"rr4.sn-hp57kndz.googlevideo.com.",
"rr4.sn-hp57knk7.googlevideo.com.",
- "rr4.sn-hp57yn7r.googlevideo.com.",
- "rr4.sn-hp57yn7y.googlevideo.com.",
"rr4.sn-hp57ynl6.googlevideo.com.",
"rr4.sn-hp57ynlr.googlevideo.com.",
"rr4.sn-hp57ynly.googlevideo.com.",
@@ -5431,102 +5651,37 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4.sn-hp57ynse.googlevideo.com.",
"rr4.sn-hp57ynsl.googlevideo.com.",
"rr4.sn-hp57ynss.googlevideo.com.",
- "rr4.sn-ntqe6n7r.googlevideo.com.",
"rr4.sn-nx57ynsk.googlevideo.com.",
- "rr4.sn-q4fl6n6y.googlevideo.com.",
- "rr4.sn-q4fl6ndz.googlevideo.com.",
- "rr4.sn-q4fl6nsd.googlevideo.com.",
- "rr4.sn-q4flrn7k.googlevideo.com.",
- "rr4.sn-q4flrn7r.googlevideo.com.",
- "rr4.sn-q4flrnee.googlevideo.com.",
- "rr4.sn-q4flrnes.googlevideo.com.",
- "rr4.sn-q4flrnl6.googlevideo.com.",
- "rr4.sn-q4flrnld.googlevideo.com.",
- "rr4.sn-q4flrnle.googlevideo.com.",
- "rr4.sn-q4flrnlz.googlevideo.com.",
- "rr4.sn-q4flrnsd.googlevideo.com.",
- "rr4.sn-q4flrnsl.googlevideo.com.",
- "rr4.sn-q4flrnss.googlevideo.com.",
- "rr4.sn-q4fzen7e.googlevideo.com.",
+ "rr4.sn-q4fl6ndl.googlevideo.com.",
+ "rr4.sn-q4flrney.googlevideo.com.",
+ "rr4.sn-q4flrnl7.googlevideo.com.",
"rr4.sn-q4fzen7l.googlevideo.com.",
- "rr4.sn-q4fzen7s.googlevideo.com.",
- "rr4.sn-q4fzen7y.googlevideo.com.",
- "rr4.sn-q4fzene7.googlevideo.com.",
- "rr4.sn-q4fzenee.googlevideo.com.",
- "rr4.sn-qja5mc-5h.googlevideo.com.",
"rr4.sn-u1hp55-5c.googlevideo.com.",
- "rr4.sn-vgqskn66.googlevideo.com.",
- "rr4.sn-vgqskn67.googlevideo.com.",
- "rr4.sn-vgqskn6d.googlevideo.com.",
- "rr4.sn-vgqskn6s.googlevideo.com.",
- "rr4.sn-vgqskn6z.googlevideo.com.",
- "rr4.sn-vgqsknld.googlevideo.com.",
- "rr4.sn-vgqsknlk.googlevideo.com.",
- "rr4.sn-vgqskns7.googlevideo.com.",
- "rr4.sn-vgqsknse.googlevideo.com.",
- "rr4.sn-vgqsknsk.googlevideo.com.",
- "rr4.sn-vgqsknz6.googlevideo.com.",
- "rr4.sn-vgqsknz7.googlevideo.com.",
- "rr4.sn-vgqsknzd.googlevideo.com.",
- "rr4.sn-vgqsknze.googlevideo.com.",
- "rr4.sn-vgqsknzk.googlevideo.com.",
- "rr4.sn-vgqsknzl.googlevideo.com.",
- "rr4.sn-vgqsknzr.googlevideo.com.",
- "rr4.sn-vgqsknzs.googlevideo.com.",
- "rr4.sn-vgqsknzy.googlevideo.com.",
- "rr4.sn-vgqsknzz.googlevideo.com.",
- "rr4.sn-vgqsrn66.googlevideo.com.",
- "rr4.sn-vgqsrn67.googlevideo.com.",
- "rr4.sn-vgqsrn6e.googlevideo.com.",
- "rr4.sn-vgqsrn6l.googlevideo.com.",
- "rr4.sn-vgqsrn6z.googlevideo.com.",
- "rr4.sn-vgqsrnl6.googlevideo.com.",
- "rr4.sn-vgqsrnld.googlevideo.com.",
- "rr4.sn-vgqsrnlk.googlevideo.com.",
- "rr4.sn-vgqsrnls.googlevideo.com.",
- "rr4.sn-vgqsrnlz.googlevideo.com.",
- "rr4.sn-vgqsrns6.googlevideo.com.",
- "rr4.sn-vgqsrnsd.googlevideo.com.",
- "rr4.sn-vgqsrnsr.googlevideo.com.",
- "rr4.sn-vgqsrnsy.googlevideo.com.",
- "rr4.sn-vgqsrnz6.googlevideo.com.",
- "rr4.sn-vgqsrnz7.googlevideo.com.",
- "rr4.sn-vgqsrnzd.googlevideo.com.",
- "rr4.sn-vgqsrnzk.googlevideo.com.",
- "rr4.sn-vgqsrnzr.googlevideo.com.",
- "rr4.sn-vgqsrnzs.googlevideo.com.",
- "rr4.sn-vgqsrnzy.googlevideo.com.",
"rr4.sn-vgqsrnzz.googlevideo.com.",
"rr5---sn-0nnpbo5a-bggl.googlevideo.com.",
"rr5---sn-2aqu-hoas7.googlevideo.com.",
- "rr5---sn-2aqu-hoasd.googlevideo.com.",
- "rr5---sn-2aqu-hoasz.googlevideo.com.",
- "rr5---sn-2aqu-jbt6.googlevideo.com.",
- "rr5---sn-2aqu-jxcy.googlevideo.com.",
"rr5---sn-2imern76.googlevideo.com.",
+ "rr5---sn-2imern76.gvt1.com.",
"rr5---sn-2imern7d.googlevideo.com.",
+ "rr5---sn-2imern7r.googlevideo.com.",
"rr5---sn-2imeyn7k.googlevideo.com.",
+ "rr5---sn-2imeyn7k.gvt1.com.",
"rr5---sn-2o5ua5-53.googlevideo.com.",
"rr5---sn-2oaig5-55.googlevideo.com.",
+ "rr5---sn-2op5q5-58.googlevideo.com.",
"rr5---sn-2oq4f5-c4.googlevideo.com.",
+ "rr5---sn-2oq4f5-c4.gvt1.com.",
"rr5---sn-2ovgq5-cw.googlevideo.com.",
- "rr5---sn-30a7rned.googlevideo.com.",
- "rr5---sn-30a7rnek.googlevideo.com.",
"rr5---sn-30a7rner.googlevideo.com.",
"rr5---sn-30a7ynek.googlevideo.com.",
"rr5---sn-30a7yner.googlevideo.com.",
"rr5---sn-30a7yney.googlevideo.com.",
"rr5---sn-30a7ynl7.googlevideo.com.",
- "rr5---sn-42u-nbosd.googlevideo.com.",
- "rr5---sn-42u-nbosk.googlevideo.com.",
"rr5---sn-42u-nboze.googlevideo.com.",
- "rr5---sn-42u-nbozl.googlevideo.com.",
- "rr5---sn-42u-nbozs.googlevideo.com.",
"rr5---sn-4g5e6ns6.googlevideo.com.",
"rr5---sn-4g5e6ns7.googlevideo.com.",
"rr5---sn-4g5e6nsd.googlevideo.com.",
"rr5---sn-4g5e6nsk.googlevideo.com.",
- "rr5---sn-4g5e6nsr.googlevideo.com.",
"rr5---sn-4g5e6nss.googlevideo.com.",
"rr5---sn-4g5e6nsy.googlevideo.com.",
"rr5---sn-4g5e6nsz.googlevideo.com.",
@@ -5544,7 +5699,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-4g5edndk.googlevideo.com.",
"rr5---sn-4g5edndl.googlevideo.com.",
"rr5---sn-4g5edndr.googlevideo.com.",
- "rr5---sn-4g5ednds.googlevideo.com.",
"rr5---sn-4g5edndy.googlevideo.com.",
"rr5---sn-4g5edndz.googlevideo.com.",
"rr5---sn-4g5ednkl.googlevideo.com.",
@@ -5573,19 +5727,10 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-4g5lznle.googlevideo.com.",
"rr5---sn-4g5lznls.googlevideo.com.",
"rr5---sn-4g5lznlz.googlevideo.com.",
- "rr5---sn-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
- "rr5---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
- "rr5---sn-5abxgpxuxaxjvh-cawe.googlevideo.com.",
- "rr5---sn-5abxgpxuxaxjvh-caws.googlevideo.com.",
- "rr5---sn-5abxgpxuxaxjvh-j1ae.googlevideo.com.",
- "rr5---sn-5abxgpxuxaxjvh-j1az.googlevideo.com.",
- "rr5---sn-5go7yner.googlevideo.com.",
"rr5---sn-5go7ynl6.googlevideo.com.",
- "rr5---sn-5go7ynld.googlevideo.com.",
- "rr5---sn-5go7ynlk.googlevideo.com.",
- "rr5---sn-5goeenez.googlevideo.com.",
"rr5---sn-5hne6n6e.googlevideo.com.",
"rr5---sn-5hne6n6l.googlevideo.com.",
+ "rr5---sn-5hne6n6l.gvt1.com.",
"rr5---sn-5hne6ns6.googlevideo.com.",
"rr5---sn-5hne6nsd.googlevideo.com.",
"rr5---sn-5hne6nsk.googlevideo.com.",
@@ -5595,7 +5740,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-5hne6nz6.googlevideo.com.",
"rr5---sn-5hne6nzd.googlevideo.com.",
"rr5---sn-5hne6nzk.googlevideo.com.",
- "rr5---sn-5hne6nzk.gvt1.com.",
"rr5---sn-5hne6nzs.googlevideo.com.",
"rr5---sn-5hne6nzy.googlevideo.com.",
"rr5---sn-5hnednss.googlevideo.com.",
@@ -5612,6 +5756,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-5uaezne6.googlevideo.com.",
"rr5---sn-5uaezned.googlevideo.com.",
"rr5---sn-5uaeznel.googlevideo.com.",
+ "rr5---sn-5uaezner.googlevideo.com.",
"rr5---sn-5uaeznes.googlevideo.com.",
"rr5---sn-5uaeznez.googlevideo.com.",
"rr5---sn-5uaeznl6.googlevideo.com.",
@@ -5632,7 +5777,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-5ualdns7.googlevideo.com.",
"rr5---sn-5ualdnsd.googlevideo.com.",
"rr5---sn-5ualdnse.googlevideo.com.",
- "rr5---sn-5ualdnsk.googlevideo.com.",
"rr5---sn-5ualdnsl.googlevideo.com.",
"rr5---sn-5ualdnsr.googlevideo.com.",
"rr5---sn-5ualdnss.googlevideo.com.",
@@ -5640,35 +5784,22 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-5ualdnsz.googlevideo.com.",
"rr5---sn-5ualdnz7.googlevideo.com.",
"rr5---sn-5ualdnze.googlevideo.com.",
- "rr5---sn-8pxuuxa-nbo6l.googlevideo.com.",
- "rr5---sn-8pxuuxa-nbosd.googlevideo.com.",
- "rr5---sn-8qj-i5o6d.googlevideo.com.",
- "rr5---sn-8qj-i5o6k.googlevideo.com.",
- "rr5---sn-8qj-i5ody.googlevideo.com.",
- "rr5---sn-8qj-i5ozd.googlevideo.com.",
- "rr5---sn-8qj-i5ozr.googlevideo.com.",
- "rr5---sn-8qj-i5ozz.googlevideo.com.",
"rr5---sn-8qj-nbo66.googlevideo.com.",
- "rr5---sn-8qj-nbo67.googlevideo.com.",
+ "rr5---sn-8xgp1vo-a5ml.googlevideo.com.",
"rr5---sn-8xgp1vo-ab56.googlevideo.com.",
"rr5---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr5---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr5---sn-8xgp1vo-ab5l.googlevideo.com.",
"rr5---sn-8xgp1vo-ab5s.googlevideo.com.",
"rr5---sn-8xgp1vo-ab5z.googlevideo.com.",
- "rr5---sn-8xgp1vo-nh4e.googlevideo.com.",
+ "rr5---sn-8xgp1vo-p5qee.googlevideo.com.",
+ "rr5---sn-8xgp1vo-p5qel.googlevideo.com.",
+ "rr5---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr5---sn-8xgp1vo-xfge.googlevideo.com.",
- "rr5---sn-8xgp1vo-xfgl.googlevideo.com.",
"rr5---sn-8xgp1vo-xfgs.googlevideo.com.",
- "rr5---sn-9gv76n7e.googlevideo.com.",
- "rr5---sn-9gv76n7l.googlevideo.com.",
"rr5---sn-9gv76n7s.googlevideo.com.",
- "rr5---sn-9gv76n7z.googlevideo.com.",
- "rr5---sn-9gv7ene6.googlevideo.com.",
- "rr5---sn-9gv7ened.googlevideo.com.",
"rr5---sn-9gv7zn76.googlevideo.com.",
"rr5---sn-9gv7zn7e.googlevideo.com.",
- "rr5---sn-9gv7zn7r.googlevideo.com.",
"rr5---sn-9gv7zn7y.googlevideo.com.",
"rr5---sn-a5m7lnl6.googlevideo.com.",
"rr5---sn-a5m7lnld.googlevideo.com.",
@@ -5694,6 +5825,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-a5mlrnll.googlevideo.com.",
"rr5---sn-a5mlrnls.googlevideo.com.",
"rr5---sn-a5mlrnlz.googlevideo.com.",
+ "rr5---sn-a5msen76.googlevideo.com.",
"rr5---sn-a5msen7l.googlevideo.com.",
"rr5---sn-a5msen7s.googlevideo.com.",
"rr5---sn-a5msen7z.googlevideo.com.",
@@ -5711,7 +5843,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-ab5l6nrk.googlevideo.com.",
"rr5---sn-ab5l6nrl.googlevideo.com.",
"rr5---sn-ab5l6nrr.googlevideo.com.",
- "rr5---sn-ab5l6nrs.googlevideo.com.",
"rr5---sn-ab5l6nrz.googlevideo.com.",
"rr5---sn-ab5sznld.googlevideo.com.",
"rr5---sn-ab5sznly.googlevideo.com.",
@@ -5731,6 +5862,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-aigl6ney.googlevideo.com.",
"rr5---sn-aigl6nl7.googlevideo.com.",
"rr5---sn-aigl6ns6.googlevideo.com.",
+ "rr5---sn-aigl6nsd.googlevideo.com.",
"rr5---sn-aigl6nsk.googlevideo.com.",
"rr5---sn-aigl6nsr.googlevideo.com.",
"rr5---sn-aigl6nz7.googlevideo.com.",
@@ -5738,7 +5870,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-aigl6nzk.googlevideo.com.",
"rr5---sn-aigl6nzl.googlevideo.com.",
"rr5---sn-aigl6nzr.googlevideo.com.",
- "rr5---sn-aigl6nzr.gvt1.com.",
"rr5---sn-aigl6nzs.googlevideo.com.",
"rr5---sn-aigzrn76.googlevideo.com.",
"rr5---sn-aigzrn7d.googlevideo.com.",
@@ -5755,23 +5886,32 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-aigzrnsz.googlevideo.com.",
"rr5---sn-aigzrnz7.googlevideo.com.",
"rr5---sn-aigzrnze.googlevideo.com.",
+ "rr5---sn-aj4g55-5v.googlevideo.com.",
"rr5---sn-aj5ua5-5c.googlevideo.com.",
- "rr5---sn-ajab55-55.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
"rr5---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
"rr5---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
- "rr5---sn-c0q7lnz7.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxqjvhj5nu-vgqz.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxqjvm-2ime.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxqjvm-2ims.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxqjvm-2ims.gvt1.com.",
+ "rr5---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
+ "rr5---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
"rr5---sn-cvb7lne7.googlevideo.com.",
"rr5---sn-cvb7lnee.googlevideo.com.",
"rr5---sn-cvb7lnlz.googlevideo.com.",
"rr5---sn-cvb7sn7k.googlevideo.com.",
"rr5---sn-cvb7sn7r.googlevideo.com.",
- "rr5---sn-h0jeenl6.googlevideo.com.",
- "rr5---sn-h0jeenld.googlevideo.com.",
- "rr5---sn-h0jeenle.googlevideo.com.",
- "rr5---sn-h0jelne6.googlevideo.com.",
- "rr5---sn-h0jelnes.googlevideo.com.",
- "rr5---sn-h0jelnez.googlevideo.com.",
- "rr5---sn-hgn7rnll.googlevideo.com.",
"rr5---sn-hoa7kn76.googlevideo.com.",
"rr5---sn-hoa7kn76.gvt1.com.",
"rr5---sn-hoa7rn76.googlevideo.com.",
@@ -5779,16 +5919,17 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-hoa7rn7z.googlevideo.com.",
"rr5---sn-hoa7rn7z.gvt1.com.",
"rr5---sn-hp57kn6r.googlevideo.com.",
+ "rr5---sn-hp57kn6r.gvt1.com.",
"rr5---sn-hp57kn6y.googlevideo.com.",
"rr5---sn-hp57knd6.googlevideo.com.",
- "rr5---sn-hp57knd6.gvt1.com.",
"rr5---sn-hp57kndd.googlevideo.com.",
"rr5---sn-hp57kndk.googlevideo.com.",
- "rr5---sn-hp57kndk.gvt1.com.",
"rr5---sn-hp57kndr.googlevideo.com.",
+ "rr5---sn-hp57kndr.gvt1.com.",
"rr5---sn-hp57knds.googlevideo.com.",
"rr5---sn-hp57knds.gvt1.com.",
"rr5---sn-hp57kndy.googlevideo.com.",
+ "rr5---sn-hp57kndy.gvt1.com.",
"rr5---sn-hp57kndz.googlevideo.com.",
"rr5---sn-hp57knk7.googlevideo.com.",
"rr5---sn-hp57yn7r.googlevideo.com.",
@@ -5796,15 +5937,17 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-hp57yne7.googlevideo.com.",
"rr5---sn-hp57ynee.googlevideo.com.",
"rr5---sn-hp57ynl6.googlevideo.com.",
+ "rr5---sn-hp57ynl6.gvt1.com.",
"rr5---sn-hp57ynlr.googlevideo.com.",
- "rr5---sn-hp57ynlr.gvt1.com.",
"rr5---sn-hp57ynly.googlevideo.com.",
"rr5---sn-hp57ynly.gvt1.com.",
"rr5---sn-hp57yns7.googlevideo.com.",
"rr5---sn-hp57yns7.gvt1.com.",
"rr5---sn-hp57ynse.googlevideo.com.",
"rr5---sn-hp57ynsl.googlevideo.com.",
+ "rr5---sn-hp57ynsl.gvt1.com.",
"rr5---sn-hp57ynss.googlevideo.com.",
+ "rr5---sn-hp57ynss.gvt1.com.",
"rr5---sn-i3b7kn6s.googlevideo.com.",
"rr5---sn-i3b7knld.googlevideo.com.",
"rr5---sn-i3b7knlk.googlevideo.com.",
@@ -5820,10 +5963,10 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-i3belnll.googlevideo.com.",
"rr5---sn-i3belnls.googlevideo.com.",
"rr5---sn-i3bssn7e.googlevideo.com.",
- "rr5---sn-jvhj5nu-nh4e.googlevideo.com.",
- "rr5---sn-jvhj5nu-nh4l.googlevideo.com.",
- "rr5---sn-jvhj5nu-nh4s.googlevideo.com.",
- "rr5---sn-jvhj5nu-nh4z.googlevideo.com.",
+ "rr5---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr5---sn-jxopj-n5oe.googlevideo.com.",
+ "rr5---sn-jxopj-nh4e.googlevideo.com.",
+ "rr5---sn-jxopj-nh4e.gvt1.com.",
"rr5---sn-n4v7snee.googlevideo.com.",
"rr5---sn-n4v7sney.googlevideo.com.",
"rr5---sn-n4v7snl7.googlevideo.com.",
@@ -5839,64 +5982,52 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-npoe7ned.googlevideo.com.",
"rr5---sn-npoe7nek.googlevideo.com.",
"rr5---sn-npoe7ner.googlevideo.com.",
- "rr5---sn-npoe7ner.gvt1.com.",
"rr5---sn-npoe7nes.googlevideo.com.",
"rr5---sn-npoe7ney.googlevideo.com.",
"rr5---sn-npoe7nez.googlevideo.com.",
"rr5---sn-npoe7nl6.googlevideo.com.",
"rr5---sn-npoe7nlz.googlevideo.com.",
- "rr5---sn-npoe7ns6.googlevideo.com.",
- "rr5---sn-npoe7ns6.gvt1.com.",
"rr5---sn-npoe7ns7.googlevideo.com.",
"rr5---sn-npoe7ns7.gvt1.com.",
"rr5---sn-npoe7nsd.googlevideo.com.",
"rr5---sn-npoe7nsk.googlevideo.com.",
- "rr5---sn-npoe7nsk.gvt1.com.",
"rr5---sn-npoe7nsl.googlevideo.com.",
"rr5---sn-npoe7nsr.googlevideo.com.",
- "rr5---sn-npoe7nss.googlevideo.com.",
- "rr5---sn-npoe7nss.gvt1.com.",
"rr5---sn-npoe7nsy.googlevideo.com.",
"rr5---sn-npoe7nz7.googlevideo.com.",
- "rr5---sn-npoe7nz7.gvt1.com.",
"rr5---sn-npoeene6.googlevideo.com.",
"rr5---sn-npoeened.googlevideo.com.",
"rr5---sn-npoeenee.googlevideo.com.",
"rr5---sn-npoeenek.googlevideo.com.",
+ "rr5---sn-npoeener.googlevideo.com.",
"rr5---sn-npoeeney.googlevideo.com.",
"rr5---sn-npoeenez.googlevideo.com.",
"rr5---sn-npoeenl7.googlevideo.com.",
"rr5---sn-npoeenle.googlevideo.com.",
"rr5---sn-npoeenlk.googlevideo.com.",
- "rr5---sn-npoeenlk.gvt1.com.",
- "rr5---sn-npoeenly.googlevideo.com.",
+ "rr5---sn-npoeenll.googlevideo.com.",
"rr5---sn-npoeens7.googlevideo.com.",
- "rr5---sn-npoeens7.gvt1.com.",
"rr5---sn-npoldn76.googlevideo.com.",
"rr5---sn-npoldn7d.googlevideo.com.",
- "rr5---sn-npoldn7d.gvt1.com.",
"rr5---sn-npoldn7e.googlevideo.com.",
- "rr5---sn-npoldn7e.gvt1.com.",
"rr5---sn-npoldn7l.googlevideo.com.",
"rr5---sn-npoldn7l.gvt1.com.",
- "rr5---sn-npoldn7s.googlevideo.com.",
"rr5---sn-npoldn7y.googlevideo.com.",
- "rr5---sn-npoldn7y.gvt1.com.",
"rr5---sn-npoldn7z.googlevideo.com.",
"rr5---sn-npoldn7z.gvt1.com.",
"rr5---sn-npoldne7.googlevideo.com.",
"rr5---sn-npoldne7.gvt1.com.",
- "rr5---sn-nv47ln6e.googlevideo.com.",
- "rr5---sn-nv47zn7y.googlevideo.com.",
- "rr5---sn-nv47znee.googlevideo.com.",
- "rr5---sn-nv47znel.googlevideo.com.",
+ "rr5---sn-ntq7yns7.googlevideo.com.",
"rr5---sn-nx57ynlk.googlevideo.com.",
"rr5---sn-nx57ynsd.googlevideo.com.",
- "rr5---sn-nx57ynse.googlevideo.com.",
"rr5---sn-nx57ynsk.googlevideo.com.",
"rr5---sn-nx57ynsl.googlevideo.com.",
+ "rr5---sn-nx57ynsr.googlevideo.com.",
"rr5---sn-nx57ynss.googlevideo.com.",
+ "rr5---sn-nx57ynsy.googlevideo.com.",
"rr5---sn-nx57ynsz.googlevideo.com.",
+ "rr5---sn-nx57ynz7.googlevideo.com.",
+ "rr5---sn-nx57ynze.googlevideo.com.",
"rr5---sn-o097znsd.googlevideo.com.",
"rr5---sn-o097znse.googlevideo.com.",
"rr5---sn-o097znsk.googlevideo.com.",
@@ -5910,13 +6041,16 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-o097znzr.googlevideo.com.",
"rr5---sn-oj5hn5-55.googlevideo.com.",
"rr5---sn-oji3bc-5j.googlevideo.com.",
+ "rr5---sn-ojnpo5-58.googlevideo.com.",
+ "rr5---sn-ojnpo5-58.gvt1.com.",
"rr5---sn-p5qddn76.googlevideo.com.",
"rr5---sn-p5qddn7d.googlevideo.com.",
"rr5---sn-p5qddn7k.googlevideo.com.",
"rr5---sn-p5qddn7r.googlevideo.com.",
"rr5---sn-p5qddn7z.googlevideo.com.",
"rr5---sn-p5qlsn6l.googlevideo.com.",
- "rr5---sn-p5qlsn76.googlevideo.com.",
+ "rr5---sn-p5qlsn6s.googlevideo.com.",
+ "rr5---sn-p5qlsn6z.googlevideo.com.",
"rr5---sn-p5qlsn7d.googlevideo.com.",
"rr5---sn-p5qlsn7l.googlevideo.com.",
"rr5---sn-p5qlsn7s.googlevideo.com.",
@@ -5928,69 +6062,94 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-p5qlsnrr.googlevideo.com.",
"rr5---sn-p5qlsny6.googlevideo.com.",
"rr5---sn-p5qs7n6d.googlevideo.com.",
+ "rr5---sn-p5qs7n6y.googlevideo.com.",
+ "rr5---sn-p5qs7nd7.googlevideo.com.",
"rr5---sn-p5qs7nsk.googlevideo.com.",
- "rr5---sn-p5qs7nsr.googlevideo.com.",
"rr5---sn-p5qs7nzk.googlevideo.com.",
"rr5---sn-p5qs7nzr.googlevideo.com.",
"rr5---sn-p5qs7nzy.googlevideo.com.",
"rr5---sn-q4fl6n66.googlevideo.com.",
"rr5---sn-q4fl6n6d.googlevideo.com.",
+ "rr5---sn-q4fl6n6d.gvt1.com.",
"rr5---sn-q4fl6n6r.googlevideo.com.",
+ "rr5---sn-q4fl6n6r.gvt1.com.",
"rr5---sn-q4fl6n6s.googlevideo.com.",
+ "rr5---sn-q4fl6n6s.gvt1.com.",
"rr5---sn-q4fl6n6y.googlevideo.com.",
+ "rr5---sn-q4fl6n6y.gvt1.com.",
"rr5---sn-q4fl6n6z.googlevideo.com.",
+ "rr5---sn-q4fl6n6z.gvt1.com.",
"rr5---sn-q4fl6nd7.googlevideo.com.",
"rr5---sn-q4fl6nde.googlevideo.com.",
"rr5---sn-q4fl6ndl.googlevideo.com.",
"rr5---sn-q4fl6nds.googlevideo.com.",
+ "rr5---sn-q4fl6nds.gvt1.com.",
"rr5---sn-q4fl6ndz.googlevideo.com.",
+ "rr5---sn-q4fl6ndz.gvt1.com.",
"rr5---sn-q4fl6nlz.googlevideo.com.",
"rr5---sn-q4fl6ns6.googlevideo.com.",
"rr5---sn-q4fl6ns7.googlevideo.com.",
"rr5---sn-q4fl6nsd.googlevideo.com.",
+ "rr5---sn-q4fl6nsd.gvt1.com.",
"rr5---sn-q4fl6nsk.googlevideo.com.",
"rr5---sn-q4fl6nsl.googlevideo.com.",
"rr5---sn-q4fl6nsr.googlevideo.com.",
+ "rr5---sn-q4fl6nsr.gvt1.com.",
"rr5---sn-q4fl6nss.googlevideo.com.",
+ "rr5---sn-q4fl6nss.gvt1.com.",
"rr5---sn-q4fl6nsy.googlevideo.com.",
+ "rr5---sn-q4fl6nsy.gvt1.com.",
"rr5---sn-q4fl6nz6.googlevideo.com.",
"rr5---sn-q4fl6nz7.googlevideo.com.",
+ "rr5---sn-q4fl6nz7.gvt1.com.",
"rr5---sn-q4fl6nzy.googlevideo.com.",
+ "rr5---sn-q4fl6nzy.gvt1.com.",
"rr5---sn-q4flrn7k.googlevideo.com.",
"rr5---sn-q4flrn7r.googlevideo.com.",
"rr5---sn-q4flrn7y.googlevideo.com.",
"rr5---sn-q4flrne6.googlevideo.com.",
"rr5---sn-q4flrne7.googlevideo.com.",
+ "rr5---sn-q4flrne7.gvt1.com.",
"rr5---sn-q4flrnee.googlevideo.com.",
"rr5---sn-q4flrnek.googlevideo.com.",
"rr5---sn-q4flrnel.googlevideo.com.",
"rr5---sn-q4flrner.googlevideo.com.",
"rr5---sn-q4flrnes.googlevideo.com.",
+ "rr5---sn-q4flrnes.gvt1.com.",
"rr5---sn-q4flrney.googlevideo.com.",
"rr5---sn-q4flrnez.googlevideo.com.",
"rr5---sn-q4flrnl6.googlevideo.com.",
"rr5---sn-q4flrnl7.googlevideo.com.",
"rr5---sn-q4flrnld.googlevideo.com.",
"rr5---sn-q4flrnle.googlevideo.com.",
+ "rr5---sn-q4flrnle.gvt1.com.",
"rr5---sn-q4flrnlz.googlevideo.com.",
+ "rr5---sn-q4flrnlz.gvt1.com.",
"rr5---sn-q4flrnsd.googlevideo.com.",
+ "rr5---sn-q4flrnsd.gvt1.com.",
"rr5---sn-q4flrnsk.googlevideo.com.",
"rr5---sn-q4flrnsl.googlevideo.com.",
+ "rr5---sn-q4flrnsl.gvt1.com.",
"rr5---sn-q4flrnss.googlevideo.com.",
"rr5---sn-q4fzen7e.googlevideo.com.",
+ "rr5---sn-q4fzen7e.gvt1.com.",
"rr5---sn-q4fzen7l.googlevideo.com.",
+ "rr5---sn-q4fzen7l.gvt1.com.",
"rr5---sn-q4fzen7s.googlevideo.com.",
"rr5---sn-q4fzen7y.googlevideo.com.",
+ "rr5---sn-q4fzen7y.gvt1.com.",
"rr5---sn-q4fzene7.googlevideo.com.",
"rr5---sn-q4fzenee.googlevideo.com.",
"rr5---sn-qja5mc-5h.googlevideo.com.",
"rr5---sn-qjp5q5-55.googlevideo.com.",
"rr5---sn-qxo7rn7k.googlevideo.com.",
- "rr5---sn-qxo7rn7r.googlevideo.com.",
- "rr5---sn-qxo7rn7y.googlevideo.com.",
+ "rr5---sn-qxo7rne7.googlevideo.com.",
+ "rr5---sn-qxo7rnee.googlevideo.com.",
"rr5---sn-qxoedn7k.googlevideo.com.",
"rr5---sn-qxoedne7.googlevideo.com.",
- "rr5---sn-t0aedn7l.googlevideo.com.",
+ "rr5---sn-qxoednee.googlevideo.com.",
+ "rr5---sn-qxoednel.googlevideo.com.",
+ "rr5---sn-qxoednes.googlevideo.com.",
"rr5---sn-vgqskn66.googlevideo.com.",
"rr5---sn-vgqskn67.googlevideo.com.",
"rr5---sn-vgqskn6d.googlevideo.com.",
@@ -6011,7 +6170,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-vgqsknse.googlevideo.com.",
"rr5---sn-vgqsknsk.googlevideo.com.",
"rr5---sn-vgqsknz6.googlevideo.com.",
- "rr5---sn-vgqsknz7.googlevideo.com.",
"rr5---sn-vgqsknzd.googlevideo.com.",
"rr5---sn-vgqsknzk.googlevideo.com.",
"rr5---sn-vgqsknzl.googlevideo.com.",
@@ -6035,7 +6193,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-vgqsrnll.googlevideo.com.",
"rr5---sn-vgqsrnls.googlevideo.com.",
"rr5---sn-vgqsrnlz.googlevideo.com.",
- "rr5---sn-vgqsrns6.googlevideo.com.",
"rr5---sn-vgqsrnsd.googlevideo.com.",
"rr5---sn-vgqsrnsy.googlevideo.com.",
"rr5---sn-vgqsrnz6.googlevideo.com.",
@@ -6046,38 +6203,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-vgqsrnzs.googlevideo.com.",
"rr5---sn-vgqsrnzy.googlevideo.com.",
"rr5---sn-vgqsrnzz.googlevideo.com.",
- "rr5.sn-2oq4f5-c4.googlevideo.com.",
- "rr5.sn-2ovgq5-cw.googlevideo.com.",
- "rr5.sn-a5m7lnl6.googlevideo.com.",
- "rr5.sn-a5m7lnld.googlevideo.com.",
- "rr5.sn-a5mekn6d.googlevideo.com.",
- "rr5.sn-a5mekn6k.googlevideo.com.",
- "rr5.sn-a5mekn6l.googlevideo.com.",
- "rr5.sn-a5mekn6r.googlevideo.com.",
- "rr5.sn-a5mekn6s.googlevideo.com.",
- "rr5.sn-a5mekn6z.googlevideo.com.",
- "rr5.sn-a5meknd6.googlevideo.com.",
- "rr5.sn-a5meknde.googlevideo.com.",
- "rr5.sn-a5mekndl.googlevideo.com.",
- "rr5.sn-a5meknds.googlevideo.com.",
- "rr5.sn-a5mekndz.googlevideo.com.",
- "rr5.sn-a5meknsd.googlevideo.com.",
- "rr5.sn-a5meknsy.googlevideo.com.",
- "rr5.sn-a5meknzk.googlevideo.com.",
- "rr5.sn-a5meknzl.googlevideo.com.",
- "rr5.sn-a5meknzr.googlevideo.com.",
- "rr5.sn-a5mlrnek.googlevideo.com.",
- "rr5.sn-a5mlrnl6.googlevideo.com.",
- "rr5.sn-a5mlrnll.googlevideo.com.",
- "rr5.sn-a5mlrnls.googlevideo.com.",
- "rr5.sn-a5mlrnlz.googlevideo.com.",
- "rr5.sn-a5msen7l.googlevideo.com.",
- "rr5.sn-a5msen7z.googlevideo.com.",
- "rr5.sn-a5msenek.googlevideo.com.",
- "rr5.sn-a5msener.googlevideo.com.",
- "rr5.sn-a5msenes.googlevideo.com.",
- "rr5.sn-a5msenl7.googlevideo.com.",
- "rr5.sn-a5msenle.googlevideo.com.",
+ "rr5.sn-aigl6nsd.googlevideo.com.",
"rr5.sn-hp57kn6r.googlevideo.com.",
"rr5.sn-hp57kn6y.googlevideo.com.",
"rr5.sn-hp57knd6.googlevideo.com.",
@@ -6088,8 +6214,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5.sn-hp57kndy.googlevideo.com.",
"rr5.sn-hp57kndz.googlevideo.com.",
"rr5.sn-hp57knk7.googlevideo.com.",
- "rr5.sn-hp57yn7r.googlevideo.com.",
- "rr5.sn-hp57yn7y.googlevideo.com.",
"rr5.sn-hp57ynl6.googlevideo.com.",
"rr5.sn-hp57ynlr.googlevideo.com.",
"rr5.sn-hp57ynly.googlevideo.com.",
@@ -6097,200 +6221,164 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5.sn-hp57ynse.googlevideo.com.",
"rr5.sn-hp57ynsl.googlevideo.com.",
"rr5.sn-hp57ynss.googlevideo.com.",
+ "rr5.sn-ntq7yns7.googlevideo.com.",
"rr5.sn-nx57ynsk.googlevideo.com.",
- "rr5.sn-q4fl6n6r.googlevideo.com.",
+ "rr5.sn-q4fl6n6s.googlevideo.com.",
+ "rr5.sn-q4fl6nd7.googlevideo.com.",
"rr5.sn-q4fl6ndl.googlevideo.com.",
- "rr5.sn-q4fl6ndz.googlevideo.com.",
- "rr5.sn-q4flrn7y.googlevideo.com.",
- "rr5.sn-q4flrner.googlevideo.com.",
- "rr5.sn-q4flrnes.googlevideo.com.",
- "rr5.sn-q4flrnl6.googlevideo.com.",
- "rr5.sn-q4flrnld.googlevideo.com.",
- "rr5.sn-q4flrnlz.googlevideo.com.",
- "rr5.sn-q4flrnsd.googlevideo.com.",
- "rr5.sn-q4flrnsk.googlevideo.com.",
- "rr5.sn-q4flrnsl.googlevideo.com.",
+ "rr5.sn-q4flrnl7.googlevideo.com.",
"rr5.sn-q4flrnss.googlevideo.com.",
- "rr5.sn-q4fzen7e.googlevideo.com.",
"rr5.sn-q4fzen7l.googlevideo.com.",
- "rr5.sn-q4fzen7s.googlevideo.com.",
"rr5.sn-q4fzen7y.googlevideo.com.",
- "rr5.sn-q4fzene7.googlevideo.com.",
- "rr5.sn-q4fzenee.googlevideo.com.",
- "rr5.sn-qja5mc-5h.googlevideo.com.",
- "rr5.sn-vgqskn66.googlevideo.com.",
- "rr5.sn-vgqskn67.googlevideo.com.",
- "rr5.sn-vgqskn6d.googlevideo.com.",
- "rr5.sn-vgqskn6s.googlevideo.com.",
- "rr5.sn-vgqskn6z.googlevideo.com.",
- "rr5.sn-vgqsknez.googlevideo.com.",
- "rr5.sn-vgqsknld.googlevideo.com.",
- "rr5.sn-vgqsknlr.googlevideo.com.",
- "rr5.sn-vgqskns7.googlevideo.com.",
- "rr5.sn-vgqsknse.googlevideo.com.",
- "rr5.sn-vgqsknsk.googlevideo.com.",
- "rr5.sn-vgqsknz6.googlevideo.com.",
- "rr5.sn-vgqsknz7.googlevideo.com.",
- "rr5.sn-vgqsknzd.googlevideo.com.",
- "rr5.sn-vgqsknzk.googlevideo.com.",
- "rr5.sn-vgqsknzl.googlevideo.com.",
- "rr5.sn-vgqsknzr.googlevideo.com.",
- "rr5.sn-vgqsknzs.googlevideo.com.",
- "rr5.sn-vgqsknzy.googlevideo.com.",
- "rr5.sn-vgqsknzz.googlevideo.com.",
- "rr5.sn-vgqsrn66.googlevideo.com.",
- "rr5.sn-vgqsrn67.googlevideo.com.",
- "rr5.sn-vgqsrn6e.googlevideo.com.",
- "rr5.sn-vgqsrn6l.googlevideo.com.",
- "rr5.sn-vgqsrn6z.googlevideo.com.",
- "rr5.sn-vgqsrnl6.googlevideo.com.",
- "rr5.sn-vgqsrnld.googlevideo.com.",
- "rr5.sn-vgqsrnlk.googlevideo.com.",
- "rr5.sn-vgqsrnls.googlevideo.com.",
- "rr5.sn-vgqsrnlz.googlevideo.com.",
- "rr5.sn-vgqsrns6.googlevideo.com.",
- "rr5.sn-vgqsrnsd.googlevideo.com.",
- "rr5.sn-vgqsrnsy.googlevideo.com.",
- "rr5.sn-vgqsrnz6.googlevideo.com.",
- "rr5.sn-vgqsrnz7.googlevideo.com.",
- "rr5.sn-vgqsrnzd.googlevideo.com.",
- "rr5.sn-vgqsrnzk.googlevideo.com.",
- "rr5.sn-vgqsrnzr.googlevideo.com.",
- "rr5.sn-vgqsrnzs.googlevideo.com.",
- "rr5.sn-vgqsrnzy.googlevideo.com.",
"rr5.sn-vgqsrnzz.googlevideo.com.",
"rr6---sn-2aqu-hoas7.googlevideo.com.",
- "rr6---sn-2aqu-hoasd.googlevideo.com.",
- "rr6---sn-2aqu-hoasz.googlevideo.com.",
- "rr6---sn-2aqu-jbt6.googlevideo.com.",
"rr6---sn-42u-nboze.googlevideo.com.",
- "rr6---sn-42u-nbozl.googlevideo.com.",
- "rr6---sn-42u-nbozs.googlevideo.com.",
- "rr6---sn-42u-nbozz.googlevideo.com.",
- "rr6---sn-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
- "rr6---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
- "rr6---sn-5abxgpxuxaxjvh-j1ae.googlevideo.com.",
- "rr6---sn-5abxgpxuxaxjvh-j1az.googlevideo.com.",
- "rr6---sn-8pxuuxa-nbo6l.googlevideo.com.",
- "rr6---sn-8pxuuxa-nbosd.googlevideo.com.",
- "rr6---sn-8qj-i5o66.googlevideo.com.",
- "rr6---sn-8qj-i5o6d.googlevideo.com.",
- "rr6---sn-8qj-i5o6k.googlevideo.com.",
- "rr6---sn-8qj-i5ody.googlevideo.com.",
- "rr6---sn-8qj-i5ozd.googlevideo.com.",
- "rr6---sn-8qj-i5ozr.googlevideo.com.",
"rr6---sn-8qj-nbo66.googlevideo.com.",
- "rr6---sn-8qj-nbo67.googlevideo.com.",
- "rr6---sn-8xgp1vo-a5me.googlevideo.com.",
"rr6---sn-8xgp1vo-ab56.googlevideo.com.",
"rr6---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr6---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr6---sn-8xgp1vo-ab5l.googlevideo.com.",
- "rr6---sn-8xgp1vo-p5ie.googlevideo.com.",
+ "rr6---sn-8xgp1vo-p5qee.googlevideo.com.",
+ "rr6---sn-8xgp1vo-p5qel.googlevideo.com.",
+ "rr6---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr6---sn-8xgp1vo-xfge.googlevideo.com.",
"rr6---sn-8xgp1vo-xfgl.googlevideo.com.",
"rr6---sn-8xgp1vo-xfgs.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
"rr6---sn-bvvbaxivnuxq5uu-q4fe.googlevideo.com.",
- "rr6---sn-jvhj5nu-nh4e.googlevideo.com.",
- "rr6---sn-jvhj5nu-nh4l.googlevideo.com.",
- "rr6---sn-jvhj5nu-nh4s.googlevideo.com.",
- "rr6---sn-jvhj5nu-nh4z.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxq5uu-q4fl.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvhj5nu-n4v6.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvhj5nu-vgqz.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvm-2ime.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvm-2ims.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvm-2ims.gvt1.com.",
+ "rr6---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvm-q4fe.gvt1.com.",
+ "rr6---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
+ "rr6---sn-bvvbaxivnuxqjvm-q4fl.gvt1.com.",
+ "rr6---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr6---sn-jxopj-n5oe.googlevideo.com.",
+ "rr6---sn-jxopj-nh4e.googlevideo.com.",
+ "rr6---sn-jxopj-nh4e.gvt1.com.",
"rr7---sn-2aqu-hoas7.googlevideo.com.",
- "rr7---sn-2aqu-hoasd.googlevideo.com.",
"rr7---sn-2aqu-hoasz.googlevideo.com.",
- "rr7---sn-2aqu-jxcy.googlevideo.com.",
- "rr7---sn-42u-nboze.googlevideo.com.",
- "rr7---sn-42u-nbozl.googlevideo.com.",
- "rr7---sn-42u-nbozs.googlevideo.com.",
- "rr7---sn-42u-nbozz.googlevideo.com.",
- "rr7---sn-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
- "rr7---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
- "rr7---sn-5abxgpxuxaxjvh-cawe.googlevideo.com.",
- "rr7---sn-5abxgpxuxaxjvh-j1ae.googlevideo.com.",
- "rr7---sn-8pxuuxa-nbo6l.googlevideo.com.",
- "rr7---sn-8pxuuxa-nbosd.googlevideo.com.",
- "rr7---sn-8qj-i5o66.googlevideo.com.",
- "rr7---sn-8qj-i5o6d.googlevideo.com.",
- "rr7---sn-8qj-i5o6k.googlevideo.com.",
- "rr7---sn-8qj-i5ody.googlevideo.com.",
"rr7---sn-8qj-i5ozd.googlevideo.com.",
- "rr7---sn-8qj-i5ozr.googlevideo.com.",
"rr7---sn-8qj-nbo66.googlevideo.com.",
"rr7---sn-8xgp1vo-ab56.googlevideo.com.",
"rr7---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr7---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr7---sn-8xgp1vo-ab5l.googlevideo.com.",
+ "rr7---sn-8xgp1vo-p5qee.googlevideo.com.",
+ "rr7---sn-8xgp1vo-p5qel.googlevideo.com.",
+ "rr7---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr7---sn-8xgp1vo-xfge.googlevideo.com.",
- "rr7---sn-jvhj5nu-nh4e.googlevideo.com.",
- "rr7---sn-jvhj5nu-nh4l.googlevideo.com.",
- "rr7---sn-jvhj5nu-nh4s.googlevideo.com.",
- "rr7---sn-jvhj5nu-nh4z.googlevideo.com.",
- "rr8---sn-2aqu-hoale.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxqjvhj5nu-vgqz.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxqjvm-2ime.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxqjvm-2ims.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
+ "rr7---sn-bvvbaxivnuxqjvm-q4fe.gvt1.com.",
+ "rr7---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
+ "rr7---sn-jxopj-n5oe.googlevideo.com.",
"rr8---sn-2aqu-hoas7.googlevideo.com.",
- "rr8---sn-2aqu-hoasd.googlevideo.com.",
- "rr8---sn-2aqu-hoasz.googlevideo.com.",
- "rr8---sn-2aqu-jxcy.googlevideo.com.",
- "rr8---sn-42u-nboze.googlevideo.com.",
"rr8---sn-42u-nbozl.googlevideo.com.",
- "rr8---sn-42u-nbozs.googlevideo.com.",
- "rr8---sn-42u-nbozz.googlevideo.com.",
- "rr8---sn-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
- "rr8---sn-5abxgpxuxaxjvh-j1ae.googlevideo.com.",
- "rr8---sn-8pxuuxa-nbo6l.googlevideo.com.",
- "rr8---sn-8qj-i5o66.googlevideo.com.",
- "rr8---sn-8qj-i5o6d.googlevideo.com.",
- "rr8---sn-8qj-i5o6k.googlevideo.com.",
- "rr8---sn-8qj-i5ody.googlevideo.com.",
"rr8---sn-8qj-i5ozd.googlevideo.com.",
- "rr8---sn-8qj-i5ozr.googlevideo.com.",
"rr8---sn-8xgp1vo-ab56.googlevideo.com.",
"rr8---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr8---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr8---sn-8xgp1vo-ab5l.googlevideo.com.",
"rr8---sn-8xgp1vo-ab5s.googlevideo.com.",
"rr8---sn-8xgp1vo-ab5z.googlevideo.com.",
+ "rr8---sn-8xgp1vo-p5qee.googlevideo.com.",
+ "rr8---sn-8xgp1vo-p5qel.googlevideo.com.",
"rr8---sn-8xgp1vo-xfge.googlevideo.com.",
"rr8---sn-8xgp1vo-xfgl.googlevideo.com.",
- "rr8---sn-jvhj5nu-nh4e.googlevideo.com.",
- "rr8---sn-jvhj5nu-nh4l.googlevideo.com.",
- "rr8---sn-jvhj5nu-nh4s.googlevideo.com.",
- "rr8---sn-jvhj5nu-nh4z.googlevideo.com.",
- "rr9---sn-42u-nboze.googlevideo.com.",
- "rr9---sn-42u-nbozl.googlevideo.com.",
- "rr9---sn-42u-nbozs.googlevideo.com.",
- "rr9---sn-8pxuuxa-nbosd.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxq5uu-vgql.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxqjvhj5nu-vgq6.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxqjvm-2ime.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxqjvm-2ims.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
+ "rr8---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
"rr9---sn-8xgp1vo-ab56.googlevideo.com.",
"rr9---sn-8xgp1vo-ab5d.googlevideo.com.",
- "rr9---sn-jvhj5nu-nh4e.googlevideo.com.",
- "rr9---sn-jvhj5nu-nh4l.googlevideo.com.",
- "rr9---sn-jvhj5nu-nh4s.googlevideo.com.",
- "rr9---sn-jvhj5nu-nh4z.googlevideo.com.",
+ "rr9---sn-8xgp1vo-p5qee.googlevideo.com.",
+ "rr9---sn-8xgp1vo-p5qel.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxq5uu-q4f6.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxq5uu-q4fs.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxq5uu-q4fz.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxq5uu-vgqe.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxq5uu-vgqs.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxq5uu-vgqz.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxqjvhj5nu-vgqd.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxqjvhj5nu-vgqe.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxqjvhj5nu-vgql.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxqjvhj5nu-vgqs.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxqjvhj5nu-vgqz.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxqjvm-2ime.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxqjvm-2ims.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxqjvm-q4fe.googlevideo.com.",
+ "rr9---sn-bvvbaxivnuxqjvm-q4fe.gvt1.com.",
+ "rr9---sn-bvvbaxivnuxqjvm-q4fl.googlevideo.com.",
+ "rs-stripe.alm.com.",
"rsapi.haokan.mobi.",
"rsx.afterpay.com.",
"rt.teramind.co.",
- "rtb-eu-v4.prertbdir.com.",
+ "rtb-use.hellogenie.com.",
+ "rtb-use.mfadsrvr.com.",
"rtb-useast.creativedot.net.",
- "rtb2-useast.applabs.live.",
+ "rtb-usw.mfadsrvr.com.",
+ "rtb-uswest.creativedot.net.",
+ "rtbasia.com.",
"rtbmax.com.",
- "rtbsuperhub.com.",
"rtbwave.com.",
"rttf.citrix.com.",
"ru-comonrt-stsdk.vivoglobal.com.",
"ru-comort-stsdk.vivoglobal.com.",
- "ru-err-up.vivoglobal.com.",
"ru-exappupgrade.vivoglobal.com.",
"ru-fcm.sms.intl.xiaomi.com.",
- "ru-main-appstore.vivoglobal.com.",
"ru-st-exappupgrade.vivoglobal.com.",
"ru-st-sysupgrade.vivoglobal.com.",
- "ru-vcode-api.vivoglobal.com.",
"ru-vcode-od.vivoglobal.com.",
"ru.cdn.dnsv1.com.",
"ru.global.market.xiaomi.com.",
+ "rubiconmd.zoom.us.",
"rubyfish.cn.",
- "rugbyfootballsport.com.",
+ "rudderstack.beeper-tools.com.",
"ruijienetworks.com.",
"rule34video.com.",
+ "rumt-zh.com.",
"rus-account.palm.tech.",
"rus-api.nebulalive.com.",
"rus-configuration.transsion-os.com.",
@@ -6300,64 +6388,52 @@ var FakeECSFQDNs = container.NewMapSet(
"rutubelist.ru.",
"s-cdn.anthropic.com.",
"s-cs.send.microad.jp.",
- "s-light.tiket.photos.",
- "s.alfasrv.com.",
- "s.dblks.net.",
+ "s-pinimg-com.gslb.pinterest.com.",
"s.seedtag.com.",
"s1.kqxs.tube.",
- "s1.welib-premium.org.",
- "s10.histats.com.",
+ "s1002-f107.mp.lura.live.",
"s2-a.time.mci1.us.rozint.net.",
"s2-b.time.mci1.us.rozint.net.",
"s2.kqxs.tube.",
- "s2.welib-premium.org.",
- "s3-advertising.zalopay.vn.",
+ "s3-us01.didiglobal.com.",
"s3.kqxs.tube.",
"s5.kqxs.tube.",
- "s5.tuoitre.vn.",
"s6.kqxs.tube.",
+ "s7.kqxs.tube.",
"sa1.chat.si.riotgames.com.",
"sa2.chat.si.riotgames.com.",
"sa3.chat.si.riotgames.com.",
"saas.sensorsdata.com.",
"saintasaph.remotepc.com.",
+ "sales.ai.dynamics.com.",
+ "salesmanago.com.",
"saltlakecity.remotepc.com.",
- "samhealthanon.genetec.com.",
- "samip.genetec.com.",
- "sampkac.genetec.com.",
- "samsclub.quantummetric.com.",
+ "samsclubglass.quantummetric.com.",
"sanantonio.remotepc.com.",
"sandiego.remotepc.com.",
"sandiegodc.remotepc.com.",
"sanjose.remotepc.com.",
"santiago.remotepc.com.",
- "saoniuhuo.com.",
"saopaulo.remotepc.com.",
"saopaulo1.remotepc.com.",
- "sav.cynet.com.",
- "sblinks.net.",
- "sbm.pw.",
- "sc-sa.dzfread.cn.",
- "sca-vcode-od.vivoglobal.com.",
+ "satellite-cdn.salesloft.com.",
+ "sb.adtidy.org.",
"scanservice1.qg3.apps.qualys.com.",
+ "scapi.vmware.com.",
"schneidercorp.com.",
- "scielo.isciii.es.",
"sciener.cn.",
- "scirp.org.",
"scm.haplat.net.",
"scontent-ams2-1.cdninstagram.com.",
"scontent-ams2-1.xx.fbcdn.net.",
"scontent-ams4-1.cdninstagram.com.",
"scontent-ams4-1.xx.fbcdn.net.",
"scontent-arn2-1.cdninstagram.com.",
- "scontent-arn2-1.xx.fbcdn.net.",
"scontent-atl3-1.cdninstagram.com.",
"scontent-atl3-1.xx.fbcdn.net.",
"scontent-atl3-2.cdninstagram.com.",
"scontent-atl3-2.xx.fbcdn.net.",
"scontent-atl3-3.cdninstagram.com.",
"scontent-atl3-3.xx.fbcdn.net.",
- "scontent-ber1-1.cdninstagram.com.",
"scontent-bkk1-1.xx.fbcdn.net.",
"scontent-bkk1-2.xx.fbcdn.net.",
"scontent-bog2-1.cdninstagram.com.",
@@ -6394,6 +6470,7 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-dfw5-3.xx.fbcdn.net.",
"scontent-dus1-1.cdninstagram.com.",
"scontent-dus1-1.xx.fbcdn.net.",
+ "scontent-fml1-1.cdninstagram.com.",
"scontent-fra3-1.cdninstagram.com.",
"scontent-fra3-1.xx.fbcdn.net.",
"scontent-fra3-2.cdninstagram.com.",
@@ -6402,9 +6479,7 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-fra5-1.xx.fbcdn.net.",
"scontent-fra5-2.cdninstagram.com.",
"scontent-fra5-2.xx.fbcdn.net.",
- "scontent-gua1-1.xx.fbcdn.net.",
"scontent-ham3-1.cdninstagram.com.",
- "scontent-ham3-1.xx.fbcdn.net.",
"scontent-hel3-1.cdninstagram.com.",
"scontent-hkg1-1.cdninstagram.com.",
"scontent-hkg1-1.xx.fbcdn.net.",
@@ -6456,21 +6531,14 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-mnl1-1.xx.fbcdn.net.",
"scontent-mnl1-2.cdninstagram.com.",
"scontent-mnl1-2.xx.fbcdn.net.",
- "scontent-mnl3-1.cdninstagram.com.",
"scontent-mnl3-1.xx.fbcdn.net.",
- "scontent-mnl3-2.cdninstagram.com.",
"scontent-mnl3-2.xx.fbcdn.net.",
- "scontent-mrs2-1.xx.fbcdn.net.",
- "scontent-mrs2-2.xx.fbcdn.net.",
- "scontent-mrs2-3.xx.fbcdn.net.",
"scontent-msp1-1.cdninstagram.com.",
"scontent-msp1-1.xx.fbcdn.net.",
"scontent-mty2-1.cdninstagram.com.",
"scontent-mty2-1.xx.fbcdn.net.",
"scontent-muc2-1.cdninstagram.com.",
"scontent-muc2-1.xx.fbcdn.net.",
- "scontent-nrt1-1.xx.fbcdn.net.",
- "scontent-nrt1-2.xx.fbcdn.net.",
"scontent-ord5-1.cdninstagram.com.",
"scontent-ord5-1.xx.fbcdn.net.",
"scontent-ord5-2.cdninstagram.com.",
@@ -6479,7 +6547,6 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-ord5-3.xx.fbcdn.net.",
"scontent-phx1-1.cdninstagram.com.",
"scontent-phx1-1.xx.fbcdn.net.",
- "scontent-prg1-1.cdninstagram.com.",
"scontent-qro1-1.cdninstagram.com.",
"scontent-qro1-1.xx.fbcdn.net.",
"scontent-qro1-2.cdninstagram.com.",
@@ -6506,54 +6573,44 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-sin6-3.xx.fbcdn.net.",
"scontent-sjc3-1.cdninstagram.com.",
"scontent-sjc3-1.xx.fbcdn.net.",
- "scontent-sof1-1.cdninstagram.com.",
- "scontent-sof1-1.xx.fbcdn.net.",
- "scontent-sof1-2.xx.fbcdn.net.",
+ "scontent-sjc6-1.cdninstagram.com.",
+ "scontent-sjc6-1.xx.fbcdn.net.",
"scontent-vie1-1.cdninstagram.com.",
"scontent-vie1-1.xx.fbcdn.net.",
- "scontent-waw2-1.cdninstagram.com.",
- "scontent-waw2-1.xx.fbcdn.net.",
"scontent-waw2-2.cdninstagram.com.",
- "scontent-waw2-2.xx.fbcdn.net.",
"scontent-yyz1-1.cdninstagram.com.",
"scontent-yyz1-1.xx.fbcdn.net.",
- "scot-api.steem-engine.net.",
"scraper2.onlineradiobox.com.",
- "scripttags.jst.ai.",
"scservices.genetec.com.",
+ "sdaonuo.com.",
"sdk.beizi.biz.",
"sdk.cqsjd.xyz.",
- "sdk.iad-01.braze.com.",
- "sdk.qcloud.com.",
"sdkgate.pushv3.easebar.com.",
"sdks.shopifycdn.com.",
"sdktmp.hubcloud.com.cn.",
- "seaart.ai.",
"seabroadnet.com.",
"seagullscientific.com.",
"seal-blue.bbb.org.",
+ "seal-goldengate.bbb.org.",
"sealsubscriptions.com.",
- "search-proxy-cn.heytapmobi.com.",
"search.dnssearch.org.",
"search.namequery.com.",
"search.us.namequery.com.",
+ "search22-normal-c-alisg.tiktokv.com.",
"searchserverapi.com.",
"searchserverapi1.com.",
- "seasuncdn.com.",
- "seasungamescdn.com.",
"seattle.remotepc.com.",
- "secapi.netshort.com.",
"secure-signals.permutive.app.",
- "secure.checkout.visa.com.",
+ "secure.accurint.com.",
+ "secure.stratanetwork.com.",
"secure.syndetics.com.",
- "secure5.arcot.com.",
+ "secureacceptance.cybersource.com.",
"securetheorem.com.",
+ "security-reports.shopifysvc.com.",
"securityapi.d3-pr-tm.com.",
"seedtag.com.",
- "seguridadinmobiliaria.com.",
"semaphore.cocogain.io.",
"send.microad.jp.",
- "sensei.ruselabs.com.",
"sensorsdata.cn.",
"sensorsdata.com.",
"sensorsgateway.com.",
@@ -6561,78 +6618,78 @@ var FakeECSFQDNs = container.NewMapSet(
"sentry-webapp.quillbot.com.",
"sentry.appodeal.com.",
"sentry.cloudlinux.com.",
+ "sentry.wmt.dev.",
"seoul.remotepc.com.",
- "serv.xapstream.com.",
- "serve-next.olo.com.",
- "server.easycounter.com.",
+ "serraview.com.",
+ "serve.mongobrain.app.",
+ "server-v4.shop.app.",
"server.shop.app.",
- "serverforge.org.",
"service2.ultipro.com.",
- "servicecdn.ru.",
+ "servicebus1041.myconnectsecure.com.",
+ "servicebus1042.myconnectsecure.com.",
+ "servicebus1043.myconnectsecure.com.",
+ "servicebus1044.myconnectsecure.com.",
"services.adaptiva.cloud.",
"services.lego.com.",
- "services2.risevision.com.",
"servicetitan.com.",
"servs.modoro360.com.",
+ "servt.modoro360.com.",
+ "servx.modoro360.com.",
"servx.opamarketplace.com.",
"servx.playstream.media.",
"settings.luckyorange.com.",
"sevenrooms.com.",
+ "sewjn80htn-3.algolianet.com.",
"sfont.zalopay.com.vn.",
"sfu.voip.signal.org.",
"sg-o-s3.smartcloudcon.com.",
- "sg-trk.bidmatrixdsp.com.",
"sg.api.translator.voice.gcloudsdk.com.",
"sg.bidder.paddlewaver.com.",
"sgfp.tongdun.net.",
"sgpcas.ezvizlife.com.",
- "sgpjbg.com.",
- "sgshort.pay.wechat.com.",
- "sgspeed.ino.sgameglobal.com.",
- "sh.jd.com.",
- "share.connect.aig.",
+ "sgtm.stevemadden.com.",
"share.fcgame.net.",
"sharpschool.com.",
- "shavers.sbm.pw.",
- "shiply-cdn.qq.com.",
"shop.app.",
"shopcircle.co.",
- "shopifp.com.",
+ "shopify-assets.shopifycdn.com.",
"shopify-gtm-suite.getelevar.com.",
"shopify.com.",
"shopifynetwork.com.",
"shortpixel.ai.",
+ "show-creative1.com.",
"shp.ee.",
"shrinetheme.com.",
"shuzilm.cn.",
- "sigma-qdata-h72.proxima.nie.netease.com.",
+ "signin.ultipro.com.",
"simplemdm.com.",
- "simpleswap.io.",
- "sina.com.",
+ "simpplr.com.",
"sinaimg.cn.",
+ "sink.archive.org.",
"sip-backup.phonepower.com.",
"sip-primary.phonepower.com.",
"sip.ringcentral.com.",
- "sip10.ringcentral.com.",
- "sip112-1121.ringcentral.com.",
- "sip112-1131.ringcentral.com.",
"sip112-1141.ringcentral.com.",
- "sip113-1121.ringcentral.com.",
- "sip113-1141.ringcentral.com.",
+ "sip121-1111.ringcentral.com.",
"sip121-1121.ringcentral.com.",
"sip121-1131.ringcentral.com.",
"sip121-1141.ringcentral.com.",
+ "sip121-1221.ringcentral.com.",
+ "sip121-1231.ringcentral.com.",
"sip121-1241.ringcentral.com.",
"sip123-1111.ringcentral.com.",
"sip123-1121.ringcentral.com.",
"sip123-1131.ringcentral.com.",
"sip123-1141.ringcentral.com.",
"sip123-1211.ringcentral.com.",
+ "sip123-1221.ringcentral.com.",
"sip123-1231.ringcentral.com.",
"sip123-1241.ringcentral.com.",
+ "sip131-1111.ringcentral.com.",
"sip131-1121.ringcentral.com.",
"sip131-1131.ringcentral.com.",
"sip131-1141.ringcentral.com.",
+ "sip131-1211.ringcentral.com.",
"sip131-1221.ringcentral.com.",
"sip131-1241.ringcentral.com.",
"sip132-1111.ringcentral.com.",
@@ -6640,17 +6697,26 @@ var FakeECSFQDNs = container.NewMapSet(
"sip132-1131.ringcentral.com.",
"sip132-1141.ringcentral.com.",
"sip132-1211.ringcentral.com.",
+ "sip132-1221.ringcentral.com.",
+ "sip132-1231.ringcentral.com.",
+ "sip132-1241.ringcentral.com.",
"sip421-121.ringcentral.biz.",
"sirsi.net.",
+ "site-assets.fontawesome.com.",
"site-config.com.",
+ "sixpence.ai.",
"sjc.zoom.us.",
"skeepers.io.",
+ "skims.com.",
"skyapi.policies.live.net.",
"skydrivesync.policies.live.net.",
- "smartarget-sp-cache.fra1.digitaloceanspaces.com.",
+ "skyward-ocprod.iscorp.com.",
+ "skyward.iscorp.com.",
+ "sm-tc.cn.",
+ "sm.cn.",
"smartcloudcon.com.",
+ "smartcommunications.cloud.",
"smarthome.ctdevice.ott4china.com.",
- "smarthome.iot.heytapmobi.com.",
"smoot-api-safari-aapse1c.v.aaplimg.com.",
"smoot-api-safari-aeun1a.v.aaplimg.com.",
"smoot-api-safari-aeun1b.v.aaplimg.com.",
@@ -6680,15 +6746,17 @@ var FakeECSFQDNs = container.NewMapSet(
"smoot-searchv2-ausw2b.v.aaplimg.com.",
"smoot-searchv2-ausw2c.v.aaplimg.com.",
"sms.ads.heytapmobi.com.",
- "snap-storage-cdn.l.google.com.",
"snippet.affilimatejs.com.",
"snmp-device-na.toshiba-solutions.com.",
+ "so1506.ci.managedwhitelisting.com.",
"sobot.com.",
"socialchain.app.",
"sofia.remotepc.com.",
+ "sogoucdn.com.",
"sohu.com.",
"solid.preyproject.com.",
"sonar-akl1-1.xx.fbcdn.net.",
+ "sonar-amd1-1.xx.fbcdn.net.",
"sonar-ams2-1.xx.fbcdn.net.",
"sonar-ams4-1.xx.fbcdn.net.",
"sonar-arn2-1.xx.fbcdn.net.",
@@ -6703,7 +6771,9 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-blr1-2.xx.fbcdn.net.",
"sonar-bog2-1.xx.fbcdn.net.",
"sonar-bog2-2.xx.fbcdn.net.",
- "sonar-bom2-1.xx.fbcdn.net.",
+ "sonar-bom1-1.xx.fbcdn.net.",
+ "sonar-bom2-2.xx.fbcdn.net.",
+ "sonar-bom2-3.xx.fbcdn.net.",
"sonar-bos5-1.xx.fbcdn.net.",
"sonar-bru2-1.xx.fbcdn.net.",
"sonar-bsb1-1.xx.fbcdn.net.",
@@ -6720,11 +6790,6 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-cgk2-2.xx.fbcdn.net.",
"sonar-cph2-1.xx.fbcdn.net.",
"sonar-cpt1-1.xx.fbcdn.net.",
- "sonar-del1-1.xx.fbcdn.net.",
- "sonar-del1-2.xx.fbcdn.net.",
- "sonar-del2-1.xx.fbcdn.net.",
- "sonar-del2-2.xx.fbcdn.net.",
- "sonar-del2-3.xx.fbcdn.net.",
"sonar-den2-1.xx.fbcdn.net.",
"sonar-det1-1.xx.fbcdn.net.",
"sonar-dfw5-1.xx.fbcdn.net.",
@@ -6785,7 +6850,6 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-lim1-1.xx.fbcdn.net.",
"sonar-lis1-1.xx.fbcdn.net.",
"sonar-los2-1.xx.fbcdn.net.",
- "sonar-maa3-1.xx.fbcdn.net.",
"sonar-mad1-1.xx.fbcdn.net.",
"sonar-mad2-1.xx.fbcdn.net.",
"sonar-man2-1.xx.fbcdn.net.",
@@ -6835,12 +6899,11 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-sin6-2.xx.fbcdn.net.",
"sonar-sin6-3.xx.fbcdn.net.",
"sonar-sjc3-1.xx.fbcdn.net.",
+ "sonar-sjc6-1.xx.fbcdn.net.",
"sonar-sof1-1.xx.fbcdn.net.",
"sonar-sof1-2.xx.fbcdn.net.",
"sonar-ssn1-1.xx.fbcdn.net.",
"sonar-syd2-1.xx.fbcdn.net.",
- "sonar-tir3-2.xx.fbcdn.net.",
- "sonar-tir3-3.xx.fbcdn.net.",
"sonar-tpe1-1.xx.fbcdn.net.",
"sonar-vie1-1.xx.fbcdn.net.",
"sonar-waw2-1.xx.fbcdn.net.",
@@ -6848,52 +6911,45 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-yyz1-1.xx.fbcdn.net.",
"sonar-zrh1-1.xx.fbcdn.net.",
"sonar.viously.com.",
- "songswave.com.",
- "souluojie.com.",
- "sound-machine.com.",
"southafricanorth.api.cognitive.microsoft.com.",
"southcarolina.remotepc.com.",
"southeastasia.api.cognitive.microsoft.com.",
"southindia.api.cognitive.microsoft.com.",
+ "southwest.quantummetric.com.",
"spadsync.com.",
"sparteo.com.",
- "spifc.ssl.fun.",
+ "speedtest.cn.",
+ "spiceworks.com.cdn.cloudflare.net.",
"spiny.ai.",
"spion.savvy.security.",
- "split-tool.com.",
+ "splunk.atlassian.net.",
"src.ebay-us.com.",
"srv.datacygnal.io.",
"srv00.com.",
- "ss.zolnm.com.",
+ "ssctech.com.",
+ "ssl.geoplugin.net.",
"sso.services.box.net.",
"ssp.hbrd.io.",
"ssp.hybrid.ai.",
- "sss.pk-live.cn.",
- "ssxd.mediav.com.",
+ "st-ok-pts.cdn-vk.ru.",
"st-ok.cdn-vk.ru.",
- "st-sysupgrade.vivo.com.cn.",
- "st.p.360.cn.",
+ "st-premium-v3-univ-srs-win-3744-g3.api.splashtop.com.",
"stable.dl2.discordapp.net.",
- "staffbase.com.",
- "stape.nz.",
- "stardust-tv.com.",
+ "stape.ai.",
+ "stappupgrade.vivo.com.cn.",
"stardustgod.com.",
- "starhalo.mobi.",
"starrydyn.com.",
- "startpage.foxitsoftware.com.cdn.cloudflare.net.",
"startssl.com.",
- "stat.360safe.com.",
- "stat.cnbcindonesia.com.",
- "stat.cnnindonesia.com.",
- "stat.playfamily.ru.",
- "stat2.okko.tv.",
+ "stat.lianmeng.360.cn.",
"statad.ru.",
"static-atl3-1.xx.fbcdn.net.",
"static-atl3-2.xx.fbcdn.net.",
+ "static-atl3-3.xx.fbcdn.net.",
"static-det1-1.xx.fbcdn.net.",
"static-dfw5-1.xx.fbcdn.net.",
"static-dfw5-2.xx.fbcdn.net.",
"static-dfw5-3.xx.fbcdn.net.",
+ "static-forms.clink-lists.com.",
"static-hou1-1.xx.fbcdn.net.",
"static-iad3-1.xx.fbcdn.net.",
"static-iad3-2.xx.fbcdn.net.",
@@ -6902,58 +6958,63 @@ var FakeECSFQDNs = container.NewMapSet(
"static-lga3-1.xx.fbcdn.net.",
"static-lga3-2.xx.fbcdn.net.",
"static-lga3-3.xx.fbcdn.net.",
- "static-lhr6-1.xx.fbcdn.net.",
"static-lhr8-1.xx.fbcdn.net.",
"static-lhr8-2.xx.fbcdn.net.",
"static-mia3-3.xx.fbcdn.net.",
+ "static-mia5-1.xx.fbcdn.net.",
"static-msp1-1.xx.fbcdn.net.",
"static-ord5-1.xx.fbcdn.net.",
"static-ord5-2.xx.fbcdn.net.",
"static-ord5-3.xx.fbcdn.net.",
"static-sea1-1.xx.fbcdn.net.",
+ "static-sea5-1.xx.fbcdn.net.",
"static-sjc3-1.xx.fbcdn.net.",
+ "static-sjc6-1.xx.fbcdn.net.",
"static.avito.ru.",
- "static.fd-api.com.",
- "static.hnonline.sk.",
+ "static.galaksion.com.",
"static.linkr.com.",
"static.rustore.ru.",
- "static.rutubelist.ru.",
- "staticontent.com.",
- "statis.ekatox-ru.com.",
+ "stats.norton.com.trafficmanager.net.",
"stats.transitapp.com.",
+ "stats.vidalytics.com.",
"statsig.anthropic.com.",
- "steem-engine.net.",
"stemchristie.rome2rio.com.",
+ "stevemadden.com.",
"stg-data-in.ads.heytapmobile.com.",
"stg-data.ads.heytapmobi.com.",
- "stjohnsblackheath.org.uk.",
"stockholm.remotepc.com.",
"stocks-analytics-events.apple.com.",
"store-cfg-ru.heytapmobile.com.",
"store.vsco.co.",
+ "stp-live.inside-graph.com.",
"str-vcode-tracker-fenghuang-prd-bj.vivo.com.cn.",
"streamhub.tech.",
"streaming.forexpros.com.",
- "streaming.humix.com.",
"streetviewpixels-pa.googleapis.com.",
+ "stripst.com.",
+ "sts.eccmp.com.",
+ "stse02.ultipro.com.",
+ "stsew02.ultipro.com.",
"stsn02.ultipro.com.",
+ "student.atitesting.com.",
"studyquicks.com.",
"stun.acrobits.cz.",
"stun.cloudflare.com.",
"stun.l.google.com.",
"stun1.l.google.com.",
+ "stun1.ringcentral.com.",
"stun2.l.google.com.",
+ "stun2.ringcentral.com.",
"stun3.l.google.com.",
"stun4.l.google.com.",
- "stylitics.com.cdn.cloudflare.net.",
"su6786.ci.managedwhitelisting.com.",
- "sudingtech.com.",
"sumologic.com.",
"sunmi.com.",
"supabase.com.",
+ "superacme.com.",
+ "superantispyware.com.",
"supl.qxwz.com.",
- "sur.ly.",
- "sushi.ruselabs.com.",
+ "support.powerschool.com.",
"sv8.cyberhaven.io.",
"sve.cc.",
"svk-native.ru.",
@@ -6966,40 +7027,43 @@ var FakeECSFQDNs = container.NewMapSet(
"sync.bidence.net.",
"sync.driftpixel.live.",
"sync.omnifytv.live.",
- "sync.oraki.io.",
- "sync.saideao.com.",
- "sync.techdsp.ru.",
+ "sync.rbstsystems.live.",
+ "sync.spoutroserve.com.",
"sync.videowalldirect.com.",
"syndetics.com.",
"systemreportservices.genetec.com.",
- "t-nation.com.",
+ "szmyccm.com.",
"t-odx.geo2.op-mobile.opera.com.",
"t-odx.op-mobile.opera.com.",
"t.marketingcloudfx.com.",
"t.mookie1.com.",
"t.nit.ro.",
"t.poki.io.",
- "t.rentcafe.com.",
+ "t.rtbwave.com.",
"t1.nhentai.net.",
"t1.tacdn.com.",
"t2.nhentai.net.",
- "t3.nhentai.net.",
+ "t22431.adipolo.live.",
"t3.xiaohongshu.com.",
+ "t3125.adipolo.live.",
+ "t315.adipolo.live.",
"t4.nhentai.net.",
"t9.nhentai.net.",
+ "t9674.adipolo.live.",
+ "t99193.adipolo.live.",
+ "tag.winister.app.",
"tags.natwest.com.",
- "talleyn.com.",
- "talosintelligence.com.",
+ "taipei.remotepc.com.",
+ "tako22-normal-useast1a.tiktokv.com.",
+ "talkingpts.org.",
+ "tamosplayer.com.",
"tampa.remotepc.com.",
- "tange365.com.",
"tanjingpaas.com.",
"tantanapp.com.",
- "taodocs.com.",
- "tap.avads.live.",
- "tapecontent.net.",
- "tapestry-app.quantummetric.com.",
+ "tanx.com.",
"tapsell.ir.",
"tasks.office.com.",
+ "tasks.zoom.us.",
"tbgku.wx3vze.com.",
"tccprod01.honeywell.com.",
"tccprod01.resideo.com.",
@@ -7008,43 +7072,32 @@ var FakeECSFQDNs = container.NewMapSet(
"tccprod03.honeywell.com.",
"tccprod03.resideo.com.",
"tcdnlive.com.",
- "tcdnos.com.",
- "tch.quora.com.",
- "tclai.top.",
"tclclouds.com.",
"tdcservices.tandemdiabetes.com.",
"tdm.qq.com.",
- "tdos.vip.",
"teamviewer.com.",
"techcrunch.com.",
"teddymobile.cn.",
"telemetry.savvy.security.",
"teleparty.com.",
"telephony.goog.",
- "teleport.media.",
"tencent-cloud.com.",
"tencent-cloud.net.",
"tencentcos.cn.",
"tencentmusic.com.",
"tenda.com.cn.",
- "tenpay.com.",
- "terms3.hicloud.com.",
+ "test.resolver.perfops.net.",
"tgdms.filewave.net.",
"tgp.qq.com.",
"tgpa.qq.com.",
- "thebabycotshop.com.",
- "theeducationpeople.org.",
- "theliquorshop.com.sg.",
- "themarketer.com.",
+ "themes.shopify.com.",
+ "thenew.money.",
"theoks.net.",
- "thetracker.org.",
- "think-client.wejoysg.com.",
+ "thetvapp.to.",
"thinkific.com.",
- "thirdgen.org.",
"thm.visa.com.",
"thm12.visa.com.",
"tianwenca.com.",
- "tienphong.vn.",
"time-a-b.nist.gov.",
"time-a-g.nist.gov.",
"time-a.nist.gov.",
@@ -7057,11 +7110,8 @@ var FakeECSFQDNs = container.NewMapSet(
"time-c-g.nist.gov.",
"time-c.timefreq.bldrdoc.gov.",
"time-nw.nist.gov.",
- "time.ecansol.net.",
- "time.lmtlabs.com.",
"time.nest.com.",
"time.tritan-bb.net.",
- "time.walb.tech.",
"time1.aliyun.com.",
"time1.google.com.",
"time2.aliyun.com.",
@@ -7074,25 +7124,27 @@ var FakeECSFQDNs = container.NewMapSet(
"timi-esports.qq.com.",
"tk.mosspf.com.",
"tk.mosspf.net.",
- "tkda.mosspf.net.",
"tkx.mp.lura.live.",
"tlivecdn.com.",
"tlivesource.com.",
"tls12.eu01.nr-data.net.cdn.cloudflare.net.",
"tls12.newrelic.com.cdn.cloudflare.net.",
- "tlsext.com.",
"tm.barclays.co.uk.",
+ "tm.bdc-cdn.com.",
"tm.cybersource.com.",
+ "tm.regions.com.",
+ "tmfp.klarna.com.",
"tmfsdktcp.m.qq.com.",
"tmfsdktcpv4.m.qq.com.",
"tmga.qq.com.",
"tmge.alicdn.com.",
+ "tmx.bestbuy.com.",
+ "tmx.esfp.c1.vanguard.com.",
"tmx.tdbank.com.",
"tmx.uptodate.com.",
"tngdigital.com.my.",
"tokyo.remotepc.com.",
"tongdun.net.",
- "tools.vssl.com.",
"toronto.remotepc.com.",
"toshiba-solutions.com.",
"touch-us.xiaoyi.com.",
@@ -7100,155 +7152,87 @@ var FakeECSFQDNs = container.NewMapSet(
"tpns.sgp.tencent.com.",
"tpns.sh.tencent.com.",
"tpns.tencent.com.",
- "tra-ac-ae.apktorrents.com.",
- "tra-ac-ae.best82.com.",
- "tra-ac-ae2.apktorrents.com.",
- "tra-ac-ae2.best82.com.",
- "tra-ac-id.apktorrents.com.",
- "tra-ac-id.best82.com.",
- "tra-ac-id2.apktorrents.com.",
- "tra-ac-id2.best82.com.",
- "tra-ac-ind.apktorrents.com.",
- "tra-ac-ind.best82.com.",
- "tra-ac-mas.apktorrents.com.",
- "tra-ac-mas.best82.com.",
- "tra-ard-id.apktorrents.com.",
- "tra-ard-id.best82.com.",
- "tra-bd-dac.best61.com.",
- "tra-bd-dac.hyper-torrent.com.",
- "tra-co-bog.best61.com.",
- "tra-co-bog.hyper-torrent.com.",
- "tra-eg-cai.best61.com.",
- "tra-eg-cai.hyper-torrent.com.",
- "tra-hd-id.apktorrents.com.",
- "tra-hd-id.best82.com.",
- "tra-ht-id.apktorrents.com.",
- "tra-ht-id.best82.com.",
- "tra-hz-de.hyper-torrent.com.",
- "tra-hz-fl.hyper-torrent.com.",
- "tra-iq-bgd.best61.com.",
- "tra-iq-bgd.hyper-torrent.com.",
- "tra-kh-pnh.best61.com.",
- "tra-kh-pnh.hyper-torrent.com.",
- "tra-lwb-sg.best61.com.",
- "tra-mm-rgn.best61.com.",
- "tra-mm-rgn.hyper-torrent.com.",
- "tra-my-kl.best61.com.",
- "tra-my-kl.hyper-torrent.com.",
- "tra-ph-mnl.best61.com.",
- "tra-ph-mnl.hyper-torrent.com.",
- "tra-pk-khi.best61.com.",
- "tra-pk-khi.hyper-torrent.com.",
- "tra-s4-us.best61.com.",
- "tra-sa-jnb.best61.com.",
- "tra-sa-jnb.hyper-torrent.com.",
- "tra-tc-ind.apktorrents.com.",
- "tra-tc-ind.best82.com.",
- "tra-th-bkk.best61.com.",
- "tra-th-bkk.hyper-torrent.com.",
- "tra-the-br.apktorrents.com.",
- "tra-the-br.best82.com.",
- "tra-the-tr.apktorrents.com.",
- "tra-the-tr.best82.com.",
- "tra-ved-br.apktorrents.com.",
- "tra-ved-br.best82.com.",
- "tra-ved-in.apktorrents.com.",
- "tra-ved-in.best82.com.",
- "tra-ved-ru.apktorrents.com.",
- "tra-ved-ru.best82.com.",
+ "tpsservice-files-inner.cn-hangzhou.oss-cdn.aliyun-inc.com.",
"trace.qq.com.",
- "trace.tgp.qq.com.",
"track-eu1.hubspot.com.",
- "track-gateway.y5kfpt.com.",
- "track.easeus.com.",
"track.mindtos.com.",
"track.sendlane.com.",
"trackedlink.net.",
"tracker-udp.gbitt.info.",
- "tracker.auctor.tv.",
- "tracker.best61.com.",
- "tracker.darkness.services.",
- "tracker.dsp.os.medproad.com.",
"tracker.filemail.com.",
- "tracker.files.fm.",
"tracker.grepler.com.",
"tracker.hownetwork.xyz.",
- "tracker.hyper-torrent.com.",
- "tracker.mywaifu.best.",
+ "tracker.linvk.com.",
"tracker.newtvcdn.com.",
"tracker.srv00.com.",
"tracker.theoks.net.",
- "tracker.therarbg.com.",
"tracker1.bt.moack.co.kr.",
- "tracker1.myporn.club.",
- "tracker3.itzmx.com.",
+ "tracking.brandzero.org.",
"tracking.eu.flamtyr.com.",
+ "tracking.mygaru.com.",
+ "tradovateapi.com.",
"tradplusad.com.",
"transaccional.saludtotal.com.co.",
"translate.brave.com.",
- "transparency.peer-39.com.",
+ "transmitdrs.schwab.com.",
"traversal.syncromsp.com.",
+ "treas.gov.",
"treasury.gov.",
"tri.media.",
"tribalfusion.com.",
+ "trk-keingent.com.",
"trk.bid-algorix.com.",
- "truecable.com.",
- "truney.com.",
+ "trpcdn.net.",
+ "truemed.com.",
"tse1.explicit.bing.net.",
"tsms-dra.security.dbankcloud.com.",
"tsms-dre.security.dbankcloud.com.",
"tt.browser.360.cn.",
"ttcache.com.",
- "ttshp.online.",
+ "ttk2.nbaonlineservice.com.",
"ttuhscep.cyberhaven.io.",
"tubecup.net.",
"tunnel.googlezip.net.",
"turn.cloudflare.com.",
- "tutubh.com.",
- "tvmaze.com.",
+ "tusd1.sharepoint.com.",
"tw.ntp.org.cn.",
"tx-cfg-u1.ubixioe.com.",
- "tx-data-u1.ubixioe.com.",
"tydevice.com.",
"u-ams.4dex.io.",
"u-las.4dex.io.",
"u.4dex.io.",
"uaenorth.api.cognitive.microsoft.com.",
"uapi.mp.360.cn.",
- "uatext66ap.com.",
- "ubiabox-us.oss-us-west-1.aliyuncs.com.",
- "ubs.sf-express.com.",
+ "uc.asusappnw.com.",
"uc.cn.",
"ucloud.com.cn.",
"ucweb.com.",
"udemycdn.com.",
- "udsp.io.",
+ "udms.zoom.us.",
"uhabo.com.",
"uk-api.asm.skype.com.",
"uk-prod.asyncgw.teams.microsoft.com.",
- "ukc-word-view.officeapps.live.com.",
- "ukdevilz.com.",
+ "ukc-excel-collab.officeapps.live.com.",
"ulikecam.com.",
"ulinq.asia.",
"ultipro.com.",
"ultiprotime.com.",
+ "ultiproworkplace.com.",
"umeng.com.",
- "un228.xyz.",
"unipay.qq.com.",
"unisoc.com.",
"united.quantummetric.com.",
"unity.cn.",
- "unityads.unitychina.cn.",
"unls.mep.go.cr.",
- "uodoo.com.",
- "up.railway.app.",
"update.huorong.cn.",
"update.kingsoftstore.com.",
"update.vivaldi.com.",
+ "update.yealink.com.",
"updateapp.av380.net.",
"updatechannel.sharegate.com.",
"updaterservices.genetec.com.",
"updatesnl.macrium.com.",
+ "uphealth.sharepoint.com.",
"upravel.com.",
"upremium.asia.",
"urekamedia.com.",
@@ -7258,104 +7242,67 @@ var FakeECSFQDNs = container.NewMapSet(
"us-04.ws-api.ringcentral.com.",
"us-05.ws-api.ringcentral.com.",
"us-06.ws-api.ringcentral.com.",
+ "us-adx-tracking.tradplusad.com.",
"us-api.asm.skype.com.",
- "us-atl-anx-r001.router.teamviewer.com.",
- "us-atl-anx-r002.router.teamviewer.com.",
- "us-atl-anx-r009.router.teamviewer.com.",
- "us-atl-anx-r010.router.teamviewer.com.",
"us-central1-addshoppers-data-production.cloudfunctions.net.",
- "us-central1-ah-acemarketingteam.cloudfunctions.net.",
"us-central1-amp-error-reporting.cloudfunctions.net.",
"us-central1-bps-oi-production.cloudfunctions.net.",
+ "us-central1-darden-main.cloudfunctions.net.",
+ "us-central1-digitalproducts-gabbo.cloudfunctions.net.",
+ "us-central1-ds-specials-dev.cloudfunctions.net.",
+ "us-central1-faro-cloud-proxy-production.cloudfunctions.net.",
"us-central1-fsgenergy-shared.cloudfunctions.net.",
- "us-central1-gaggle-staging.cloudfunctions.net.",
- "us-central1-locket-4252a.cloudfunctions.net.",
+ "us-central1-genericchatapp-4d046.cloudfunctions.net.",
+ "us-central1-launchpad-169908.cloudfunctions.net.",
+ "us-central1-live-prod-1-1.cloudfunctions.net.",
+ "us-central1-openoracle-de73b.cloudfunctions.net.",
"us-central1-royal-match-prod-cce6d.cloudfunctions.net.",
"us-central1-safelivealert-5.cloudfunctions.net.",
"us-central1-shopify-instrumentat-ff788286.cloudfunctions.net.",
+ "us-central1-speechifymobile.cloudfunctions.net.",
"us-central1-tranquil-petal-272922.cloudfunctions.net.",
"us-central1-wise-arch-107501.cloudfunctions.net.",
- "us-chi-anx-r005.router.teamviewer.com.",
- "us-cmh-gcp-r002.router.teamviewer.com.",
- "us-cmh-gcp-r004.router.teamviewer.com.",
+ "us-chi-anx-r002.router.teamviewer.com.",
+ "us-dal-anx-r001.router.teamviewer.com.",
"us-dal-anx-r002.router.teamviewer.com.",
- "us-dal-anx-r003.router.teamviewer.com.",
- "us-dal-anx-r004.router.teamviewer.com.",
- "us-dal-anx-r006.router.teamviewer.com.",
- "us-dal-anx-r008.router.teamviewer.com.",
- "us-dal-gcp-r003.router.teamviewer.com.",
"us-den-anx-r002.router.teamviewer.com.",
- "us-den-anx-r003.router.teamviewer.com.",
- "us-den-anx-r004.router.teamviewer.com.",
- "us-den-anx-r007.router.teamviewer.com.",
- "us-den-anx-r008.router.teamviewer.com.",
"us-den-anx-r010.router.teamviewer.com.",
"us-device-scheduler.ymcs.yealink.com.",
"us-device.ymcs.yealink.com.",
"us-east4-chkp-gcp-rnd-threat-hunt-box.cloudfunctions.net.",
"us-hnl-anx-r001.router.teamviewer.com.",
- "us-iad-gcp-r001.router.teamviewer.com.",
- "us-lax-anx-r006.router.teamviewer.com.",
- "us-lax-anx-r009.router.teamviewer.com.",
- "us-lax-anx-r011.router.teamviewer.com.",
- "us-lax-anx-r013.router.teamviewer.com.",
- "us-lax-gcp-r001.router.teamviewer.com.",
- "us-lax-gcp-r005.router.teamviewer.com.",
+ "us-hnl-anx-r002.router.teamviewer.com.",
"us-mia-anx-r003.router.teamviewer.com.",
- "us-mia-anx-r006.router.teamviewer.com.",
- "us-mia-anx-r008.router.teamviewer.com.",
- "us-mia-anx-r010.router.teamviewer.com.",
- "us-mia-anx-r011.router.teamviewer.com.",
- "us-mia-anx-r012.router.teamviewer.com.",
- "us-mia-anx-r013.router.teamviewer.com.",
+ "us-mia-anx-r014.router.teamviewer.com.",
"us-njc-anx-r003.router.teamviewer.com.",
"us-njc-anx-r004.router.teamviewer.com.",
- "us-njc-anx-r006.router.teamviewer.com.",
- "us-njc-anx-r009.router.teamviewer.com.",
- "us-njc-anx-r011.router.teamviewer.com.",
- "us-njc-anx-r012.router.teamviewer.com.",
- "us-njc-anx-r013.router.teamviewer.com.",
- "us-njc-anx-r014.router.teamviewer.com.",
+ "us-njc-anx-r007.router.teamviewer.com.",
+ "us-njc-anx-r010.router.teamviewer.com.",
"us-njc-anx-r015.router.teamviewer.com.",
+ "us-njc-anx-r017.router.teamviewer.com.",
"us-njc-anx-r018.router.teamviewer.com.",
"us-njc-anx-r019.router.teamviewer.com.",
- "us-njc-anx-r020.router.teamviewer.com.",
- "us-oma-gcp-r002.router.teamviewer.com.",
- "us-pdx-gcp-r004.router.teamviewer.com.",
- "us-pdx-gcp-r005.router.teamviewer.com.",
+ "us-pdx-gcp-r001.router.teamviewer.com.",
"us-prod.asyncgw.teams.microsoft.com.",
- "us-sea-anx-r001.router.teamviewer.com.",
- "us-sea-anx-r002.router.teamviewer.com.",
- "us-sea-anx-r004.router.teamviewer.com.",
- "us-sea-anx-r006.router.teamviewer.com.",
- "us-slc-gcp-r003.router.teamviewer.com.",
- "us-slc-gcp-r005.router.teamviewer.com.",
"us-spectrum.rcs.telephony.goog.",
- "us-was-anx-r001.router.teamviewer.com.",
- "us-was-anx-r002.router.teamviewer.com.",
- "us-was-anx-r004.router.teamviewer.com.",
- "us-was-anx-r005.router.teamviewer.com.",
- "us-was-anx-r007.router.teamviewer.com.",
- "us-was-anx-r008.router.teamviewer.com.",
- "us-was-anx-r009.router.teamviewer.com.",
- "us-was-anx-r010.router.teamviewer.com.",
- "us-was-anx-r011.router.teamviewer.com.",
- "us-was-anx-r012.router.teamviewer.com.",
- "us-was-anx-r014.router.teamviewer.com.",
- "us-was-anx-r015.router.teamviewer.com.",
- "us-was-anx-r017.router.teamviewer.com.",
- "us-was-anx-r019.router.teamviewer.com.",
- "us.dell.com.",
+ "us-was-anx-r016.router.teamviewer.com.",
+ "us.a.iteleserve.com.",
+ "us.a.qwadro.com.",
"us.galleryapi.micloud.xiaomi.net.",
"us.inspi-dsp.com.",
- "us.iot.dreame.tech.",
+ "us.keyapi.micloud.xiaomi.net.",
+ "us.production.appliedcloudplatform.com.",
"us.tracfone.rcs.telephony.goog.",
"us.ubianet.com.",
"us.uscc.rcs.telephony.goog.",
+ "us.xfinity.rcs.telephony.goog.",
"us01docs.zoom.us.",
"us02log.zoom.us.",
"us02nws-platform.zoom.us.",
"us02nws.zoom.us.",
+ "us02polling.zoom.us.",
+ "us02st1.zoom.us.",
+ "us02tasks.zoom.us.",
"us02web.zoom.us.",
"us02www3.zoom.us.",
"us04asyncim.zoom.us.",
@@ -7375,43 +7322,39 @@ var FakeECSFQDNs = container.NewMapSet(
"us06tasks.zoom.us.",
"us06web.zoom.us.",
"us06www3.zoom.us.",
+ "us3-cdn.inside-graph.com.",
+ "us4-cloud.acronis.com.",
"usbank.quantummetric.com.",
+ "usc-collabrtc-geo.rtc.trafficmanager.net.",
"usc.edu.",
"usc1.s.seedtag.com.",
"use4.s.seedtag.com.",
- "userlike.com.",
+ "user-profile.api.speechify.com.",
+ "usercentrics.eu.",
+ "userstat.net.",
"userx.pro.",
"usgs.gov.",
"ussav.cynet.com.",
- "usserver.serverapi.org.",
"usslb.cynet.com.",
+ "usv.stape.io.",
"usw-aiwit-file-push.oss-us-west-1.aliyuncs.com.",
+ "usw.stape.io.",
"usw2.s.seedtag.com.",
- "uswest-beacon.deepintent.com.",
"ut.hzshudian.com.",
- "uta-net.com.",
"ute-tech.com.cn.",
- "uu3mfpevy.com.",
"uuidksinc.net.",
"uxfeedback.ru.",
"v-key.com.",
"v.shopify.com.",
- "v.streaming.qq.com.",
"v.vivintsky.com.",
- "v1.bundlecdn.com.",
- "v231jfce5hgkxkp9s14upngl7b8fynz3w.probe.tbcache.com.",
"v39-ca.tiktokcdn.com.",
- "v39-row.gts.byteoversea.net.",
- "v39e-us.tiktokcdn.com.",
+ "v4.ai.ingka.ikea.net.",
"v58pq.mpvflv.com.",
"v6-gdvod.kwaicdn.com.",
- "va.justanswer.com.",
- "vak345.com.",
- "vandemoorteleprofessional.com.",
+ "va9265.ci.managedwhitelisting.com.",
"varify.io.",
- "vcdn.cloud.",
"vcmdiawe.com.",
- "veh-dms.na.ultifi.gm.com.",
+ "vdo.ai.",
"velaw.cyberhaven.io.",
"venafi.com.",
"verification.fda.gov.ph.",
@@ -7419,16 +7362,17 @@ var FakeECSFQDNs = container.NewMapSet(
"verticals.wix.com.",
"vfa.hpplay.cn.",
"vg-tcp-gateway.detailroi.com.",
- "vg-tcp-receiver.detailroi.com.",
"vg-tcp-rule.detailroi.com.",
"vgorigin.hakunaymatata.com.",
"vhx.com.",
"vibe.co.",
"vibeaconstr.onezapp.com.",
"vicoo.tech.",
+ "vidctf--assets.ro.co.",
"video-atl3-1.xx.fbcdn.net.",
"video-atl3-2.xx.fbcdn.net.",
"video-atl3-3.xx.fbcdn.net.",
+ "video-bos5-1.xx.fbcdn.net.",
"video-den2-1.xx.fbcdn.net.",
"video-det1-1.xx.fbcdn.net.",
"video-dfw5-1.xx.fbcdn.net.",
@@ -7442,6 +7386,10 @@ var FakeECSFQDNs = container.NewMapSet(
"video-lga3-1.xx.fbcdn.net.",
"video-lga3-2.xx.fbcdn.net.",
"video-lga3-3.xx.fbcdn.net.",
+ "video-lhr6-1.xx.fbcdn.net.",
+ "video-lhr6-2.xx.fbcdn.net.",
+ "video-lhr8-1.xx.fbcdn.net.",
+ "video-lhr8-2.xx.fbcdn.net.",
"video-mia3-1.xx.fbcdn.net.",
"video-mia3-2.xx.fbcdn.net.",
"video-mia3-3.xx.fbcdn.net.",
@@ -7451,18 +7399,23 @@ var FakeECSFQDNs = container.NewMapSet(
"video-ord5-1.xx.fbcdn.net.",
"video-ord5-2.xx.fbcdn.net.",
"video-ord5-3.xx.fbcdn.net.",
+ "video-phx1-1.xx.fbcdn.net.",
"video-sea1-1.xx.fbcdn.net.",
"video-sea5-1.xx.fbcdn.net.",
"video-sjc3-1.xx.fbcdn.net.",
+ "video-sjc6-1.xx.fbcdn.net.",
"video.rainberrytv.com.",
+ "video.turncdn.com.",
+ "video.twimg.com.cdn.cloudflare.net.",
"videocontent-dra.himovie.dbankcloud.com.",
+ "videos.typing.com.",
"vidmate.net.",
"vieon.vn.",
+ "viircypg.com.",
"vik-ca.moonactive.net.",
"viki.com.",
"viously.com.",
"vip.qq.com.",
- "vipads.live.",
"virgul.com.",
"visaforchina.cn.",
"visitor.fiftyt.com.",
@@ -7471,6 +7424,7 @@ var FakeECSFQDNs = container.NewMapSet(
"vivoglobal.com.",
"vlscppe.microsoft.com.",
"vmaas.abacusgroupllc.com.",
+ "vnet-report-7.21cn.com.",
"vnt.a-m-p.xyz.",
"vnt.woxh.world.",
"vod-pro.com.",
@@ -7484,211 +7438,203 @@ var FakeECSFQDNs = container.NewMapSet(
"voe.sx.",
"voice.gcloudcs.com.",
"voice.telephony.goog.",
- "voicetube.com.",
+ "voya.com.",
+ "vpn1.ocso.com.",
+ "vpushort-stsdk.vivo.com.cn.",
"vsco.co.",
- "vssl.com.",
- "vswenku.com.",
"vx9dle.n0qq3z.com.",
- "vyvr9aimsfmecivs.seed.packetsdk.io.",
- "vyvr9aimsfmecivs.seed.packetsdk.net.",
- "vyvr9aimsfmecivs.seed.packetsdk.xyz.",
"vzuu.com.",
"w-lb.deepl.com.",
"w.deepl.com.",
- "w25.cf.2ksports.com.",
"w3.mp.lura.live.",
- "wa9.3cp2h7v3eg.net.",
"wallet-order-service.shopifyapps.com.",
- "wallstreet-online.de.",
- "wanmei.com.",
- "wap.cmpassport.com.",
+ "wangyiyun-js.oss-cn-shanghai.aliyuncs.com.",
+ "waophoto.com.",
"warsaw.remotepc.com.",
+ "washoenv.infinitecampus.org.",
+ "wayfair-us.attn.tv.",
"wayfinding-hub-gateway-atl.ultipro.com.",
"wayfinding-hub-gateway-plas1.ultipro.com.",
"wc.shopify.com.",
"weather-analytics-events.apple.com.",
- "weather-forecasts.ru.",
"weather-server-sg.allawnos.com.",
"weather-server.allawntech.com.",
"weather-widget-events.apple.com.",
"weathercn.com.",
"weatherlive.world.",
"web-static.mindbox.ru.",
- "web.archive.org.",
"web.voice.telephony.goog.",
"web1.remotepc.com.",
"webapi.teamviewer.com.",
- "webcf.waybackmachine.org.",
- "weblate.org.",
+ "webapi.tresorit.com.",
"webmd.com.",
- "websocket-centrifugo-sp-v5.stripchat.com.",
+ "webserver.chatcora.natwest.com.",
+ "websocket-sp-v6.stripchat.com.",
"websocket.app.pdq.com.",
"websocket.org.",
"wechatos.net.",
- "wegame.com.cn.",
"weibocdn.com.",
+ "welcome.ultipro.com.",
"wemuslim.com.",
- "wenkuxiazai.com.",
- "wepartytt.com.",
+ "wendys.com.",
+ "wenke99.com.",
"westcentralus.api.cognitive.microsoft.com.",
"westeurope.api.cognitive.microsoft.com.",
- "westpalm.remotepc.com.",
"westus.api.cognitive.microsoft.com.",
"westus2.api.cognitive.microsoft.com.",
"westus3.api.cognitive.microsoft.com.",
- "wewjyw.qb6ges.com.",
- "whbdyx.com.",
"whirlpool.com.",
- "whisk.mxsec.pro.",
- "whitehouse.gov.",
- "widdimo.com.",
- "widget-api.stylitics.com.",
+ "whitingturner.sharepoint.com.",
+ "whizzco.com.",
+ "whoop-status-worker-prod.whoop.workers.dev.",
"widget-api.uxfeedback.ru.",
- "wiki.clicklaw.bc.ca.",
"windows.policies.live.net.",
+ "windstream.net.",
"winscp.net.",
"wireless-social.com.",
+ "wkhpe.com.",
+ "wl.hpyrdr.com.",
+ "wmt.dev.",
+ "wondershare.com.",
"wordreference.com.",
+ "workable.com.",
+ "workdaycdn.com.cn.",
"worldnic.com.",
"worldtimeserver.com.",
+ "wosign.com.",
"woxh.world.",
"wpk-auth.ucweb.com.",
+ "wpk-sdkv-intl.effirst.com.",
"wr.moyoung.com.",
"wr.pvp.net.",
- "ws.accessacloud.com.",
+ "ws-acc-hwp.gamedistribution.com.",
+ "ws-prod-1.optisigns.com.",
+ "ws-prod-2.optisigns.com.",
+ "ws-prod-3.optisigns.com.",
"ws.gleap.io.",
+ "ws.sixpence.ai.",
+ "ws.smartpass.app.",
+ "ws.thales.monumetric.com.",
"ws.tildacdn.com.",
"wsms.haplat.net.",
+ "wsod.com.",
"wsoversea.com.",
- "wtzw.com.",
- "wuhuyaohua.com.",
- "wujinjian.net.",
- "wujisite.com.",
- "www.3xbz.com.",
- "www.allelcoelec.jp.",
- "www.aminer.cn.",
- "www.art.com.",
+ "ww2.justanswer.com.",
+ "www.1024sj.com.",
+ "www.artfut.com.",
"www.atlassian.com.",
+ "www.audio-digest.org.",
"www.automizely-analytics.com.",
- "www.bb.com.br.",
- "www.bizcommunity.com.",
+ "www.bistro-la-nature.com.",
"www.breitbart.com.",
- "www.btc-europe.com.",
+ "www.canva.com.",
"www.cdn-tinkoff.ru.",
"www.chrome.com.",
"www.claudeusercontent.com.",
"www.cmpassport.com.",
+ "www.cnhtcsales.com.",
"www.ctmail.com.",
- "www.cz88.net.",
- "www.daydreamingland.com.",
- "www.easycounter.com.",
- "www.ecb.europa.eu.",
- "www.ecclesiasticalsewing.com.",
- "www.ecosia.org.cdn.cloudflare.net.",
- "www.exoticindiaart.com.",
- "www.fortnite.com.",
+ "www.czhuaqiang.com.",
+ "www.fourth.com.",
"www.geoplugin.net.",
"www.google.org.",
- "www.ietf.org.",
- "www.insulationsuperstore.co.uk.",
- "www.investopedia.com.",
+ "www.husunward.com.",
+ "www.ibegin.com.",
+ "www.indiamart.com.",
"www.jimmyjohns.com.",
- "www.jpost.com.",
+ "www.johnmuirhealth.com.",
"www.jrustonapps.net.",
- "www.jsnflowmeter.com.",
- "www.knoxconnect.net.",
- "www.linguee.com.",
- "www.mercadolivre.com.br.",
- "www.mycharismashop.com.",
- "www.net.cn.",
- "www.npttech.com.",
+ "www.nagumosan.com.",
+ "www.newegg.com.",
+ "www.nmpa.gov.cn.",
+ "www.notion.so.",
"www.opposhop.cn.",
+ "www.orchidworld.jp.",
+ "www.otsu-jva.com.",
"www.overleaf.com.",
+ "www.oxsquare.net.",
"www.pingler.com.",
+ "www.quyou8.com.",
+ "www.regions.com.",
"www.samsungsds.com.",
- "www.seaart.ai.",
+ "www.sdaonuo.com.",
"www.sevenrooms.com.",
- "www.simonandschuster.net.",
- "www.sobot.com.",
- "www.speedtest.net.cdn.cloudflare.net.",
- "www.thebabycotshop.com.",
- "www.tvmaze.com.",
- "www.users.storage.live.com.",
- "www.vipads.live.",
+ "www.static-src.com.",
+ "www.stdlibrary.com.",
+ "www.stevemadden.com.",
+ "www.thenew.money.",
+ "www.time.gov.",
+ "www.ute-tech.com.cn.",
"www.visaforchina.cn.",
- "www.vswenku.com.",
+ "www.wenke99.com.",
+ "www.whitehouse.gov.",
"www.wix.com.",
"www.worldtimeserver.com.",
- "www.yixuelunwen.com.",
- "www.zixin.com.cn.",
+ "www.yext-pixel.com.",
+ "www.ymtech-sh.com.",
+ "www.zmtzlt.com.",
"www.zoom.com.",
"www.zoom.us.",
+ "www.ztautoparts.com.",
"www1.remotepc.com.",
+ "www19.pointclickcare.com.",
"www2-lb.deepl.com.",
"www2.deepl.com.",
- "www2.hkej.com.",
"www28.pointclickcare.com.",
"www3.zoom.us.",
"www30.pointclickcare.com.",
"www31.pointclickcare.com.",
"www5.cbox.ws.",
+ "wx.huion.cn.",
"wxqcloud.qq.com.",
"wxqcloud.qq.com.cn.",
"wyze.com.",
"x-flow.app.",
- "x-mol.com.",
- "x.cnt.my.",
"x.script.ac.",
- "xbeibeix.com.",
- "xenforo.com.",
+ "xactlycorp.com.",
+ "xai.chronosphere.io.",
"xftg.msgny.xyz.",
"xhpingcdn.com.",
"xhscdn.com.cdn.dnsv1.com.",
- "xiaopang.sto.ipidea.online.",
"xiaoyi.com.",
"xingyouc.com.",
"xinqiucc.com.",
"xintaicz.cn.",
- "xjishu.com.",
"xmcsrv.net.",
"xml.ezmob.com.",
- "xoyo.com.",
- "xpreg.itsupport247.net.",
+ "xml.kunvertads.com.",
+ "xmpp.displaynote.com.",
+ "xmt.paze.com.",
+ "xn--pckh8d8a2c4a3j4c.com.",
+ "xsystewideusync.com.",
+ "xtools.info.",
"yalla.live.",
"ydmob.com.",
"yealink.com.",
- "yhachina.com.",
- "yingyan.com.",
- "yixuelunwen.com.",
"ymmobi.com.",
+ "ymtech-sh.com.",
"yomedia.vn.",
"yomeno.xyz.",
"yosmart.com.",
- "yougreentube.com.",
"youlesp.com.",
- "yp.ringcentral.biz.",
- "yunxindns.com.",
+ "yp.cdnstream1.com.",
"yunxinfw.com.",
- "yximgs.com.cdn.dnsv1.com.",
- "z-m-scontent-mnl1-1.xx.fbcdn.net.",
- "z-m-scontent-mnl1-2.xx.fbcdn.net.",
"z.cdn.adtarget.market.",
"z.cdn.ftd.agency.",
"z.cdn.trafficbass.com.",
- "zemanta.com.",
"zenno.services.",
- "zhaobiao.cn.",
+ "zennolab.com.",
"zhaosw.com.",
- "zhuanlichaxun.net.",
- "zhulong.com.",
- "zixin.com.cn.",
"zjcdn.com.yangyi19.com.",
- "zlisc.com.",
- "zn5.cdn.net.ru.",
+ "zmtzlt.com.",
"zog.link.",
+ "zoho.uk.",
"zoom.us.",
+ "ztautoparts.com.",
"zui.com.",
"zuiqiangyingyu.net.",
"zurich.remotepc.com.",
+ "zvuk.com.",
+ "zxid-m.mobileservice.cn.",
"zztfly.com.",
)
diff --git a/internal/ecscache/ecscache.go b/internal/ecscache/ecscache.go
index 7ecd3b2..3d8cef5 100644
--- a/internal/ecscache/ecscache.go
+++ b/internal/ecscache/ecscache.go
@@ -18,6 +18,7 @@ import (
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/syncutil"
+ "github.com/AdguardTeam/golibs/timeutil"
"github.com/miekg/dns"
)
@@ -27,6 +28,9 @@ type MiddlewareConfig struct {
// statistics. It must not be nil.
Metrics Metrics
+ // Clock is used for getting current time. It must not be nil.
+ Clock timeutil.Clock
+
// Cloner is used to clone messages taken from cache. It must not be nil.
Cloner *dnsmsg.Cloner
@@ -58,6 +62,9 @@ type MiddlewareConfig struct {
// Middleware is a dnsserver.Middleware with ECS-aware caching.
type Middleware struct {
+ // clock is used to get current time for cache expiration.
+ clock timeutil.Clock
+
// metrics is used for the collection of the ECS cache statistics.
metrics Metrics
@@ -71,10 +78,10 @@ type Middleware struct {
logger *slog.Logger
// cache is the LRU cache for results indicating no support for ECS.
- cache agdcache.Interface[uint64, *cacheItem]
+ cache agdcache.Interface[cacheKey, *cacheItem]
// ecsCache is the LRU cache for results indicating ECS support.
- ecsCache agdcache.Interface[uint64, *cacheItem]
+ ecsCache agdcache.Interface[cacheKey, *cacheItem]
// geoIP is used to get subnets for countries.
geoIP geoip.Interface
@@ -97,17 +104,20 @@ const (
// adds the caches with IDs [CacheIDNoECS] and [CacheIDWithECS] to the cache
// manager. c must not be nil.
func NewMiddleware(c *MiddlewareConfig) (m *Middleware) {
- cache := agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
+ cache := errors.Must(agdcache.New[cacheKey, *cacheItem](&agdcache.Config{
+ Clock: c.Clock,
Count: c.NoECSCount,
- })
- ecsCache := agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
+ }))
+ ecsCache := errors.Must(agdcache.New[cacheKey, *cacheItem](&agdcache.Config{
+ Clock: c.Clock,
Count: c.ECSCount,
- })
+ }))
c.CacheManager.Add(cacheIDNoECS, cache)
c.CacheManager.Add(cacheIDWithECS, ecsCache)
return &Middleware{
+ clock: c.Clock,
metrics: c.Metrics,
cloner: c.Cloner,
logger: c.Logger,
@@ -235,7 +245,7 @@ func (mw *Middleware) writeUpstreamResponse(
respIsECS := respIsECSDependent(scope, req.Question[0].Name)
- var cache agdcache.Interface[uint64, *cacheItem]
+ var cache agdcache.Interface[cacheKey, *cacheItem]
if respIsECS {
cache = mw.ecsCache
} else {
diff --git a/internal/ecscache/ecscache_internal_test.go b/internal/ecscache/ecscache_internal_test.go
index b8651fa..a869ea4 100644
--- a/internal/ecscache/ecscache_internal_test.go
+++ b/internal/ecscache/ecscache_internal_test.go
@@ -40,5 +40,3 @@ func TestRoundDiv(t *testing.T) {
MaxCount: 100_000,
}))
}
-
-// TODO(a.garipov): Add benchmarks for the new ECS cache key packing.
diff --git a/internal/ecscache/ecscache_test.go b/internal/ecscache/ecscache_test.go
index 154bc34..d57f019 100644
--- a/internal/ecscache/ecscache_test.go
+++ b/internal/ecscache/ecscache_test.go
@@ -19,6 +19,7 @@ import (
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
+ "github.com/AdguardTeam/golibs/timeutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -680,7 +681,9 @@ func newWithCache(
return dnsserver.WithMiddlewares(
h,
ecscache.NewMiddleware(&ecscache.MiddlewareConfig{
- Metrics: ecscache.EmptyMetrics{},
+ Metrics: ecscache.EmptyMetrics{},
+ // TODO(d.kolyshev): Use fake clock and test expiration.
+ Clock: timeutil.SystemClock{},
Cloner: agdtest.NewCloner(),
Logger: slogutil.NewDiscardLogger(),
CacheManager: agdcache.EmptyManager{},
diff --git a/internal/filter/config.go b/internal/filter/config.go
index f62b2fe..ad19a3a 100644
--- a/internal/filter/config.go
+++ b/internal/filter/config.go
@@ -2,9 +2,7 @@ package filter
import (
"context"
- "net/netip"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/urlfilter"
)
@@ -56,20 +54,18 @@ type ConfigCustom struct {
// Custom is a custom filter for a client.
type Custom interface {
- // DNSResult returns the result of applying the urlfilter DNS filtering
- // engine. If the request is not filtered, DNSResult returns nil.
- DNSResult(
- ctx context.Context,
- clientIP netip.Addr,
- clientName string,
- host string,
- rrType dnsmsg.RRType,
- isAns bool,
- ) (res *urlfilter.DNSResult)
-
// Rules returns the rules used to create the filter. rules must not be
// modified.
Rules() (rules []RuleText)
+
+ // SetURLFilterResult applies the DNS filtering engine and sets the values
+ // in res if any have matched. ok must be true if there is a match. req
+ // and res must not be nil.
+ SetURLFilterResult(
+ ctx context.Context,
+ req *urlfilter.DNSRequest,
+ res *urlfilter.DNSResult,
+ ) (ok bool)
}
// ConfigParental is the configuration for parental-control filtering.
diff --git a/internal/filter/custom/custom.go b/internal/filter/custom/custom.go
index bceaddd..4c0fc9e 100644
--- a/internal/filter/custom/custom.go
+++ b/internal/filter/custom/custom.go
@@ -4,14 +4,11 @@ package custom
import (
"context"
"log/slog"
- "net/netip"
- "strings"
"sync"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdurlflt"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
- "github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/urlfilter"
)
@@ -45,46 +42,33 @@ func New(c *Config) (f *Filter) {
// init initializes f.immutable.
func (f *Filter) init(ctx context.Context) {
- // TODO(a.garipov): Consider making a copy of [strings.Join] for
- // [filter.RuleText].
- textLen := 0
- for _, r := range f.rules {
- textLen += len(r) + len("\n")
- }
-
- b := &strings.Builder{}
- b.Grow(textLen)
-
- for _, r := range f.rules {
- stringutil.WriteToBuilder(b, string(r), "\n")
- }
-
// Don't use cache for users' custom filters, because [rulelist.ResultCache]
// doesn't take $client rules into account.
//
// TODO(a.garipov): Consider adding client names to the result-cache keys.
- cache := rulelist.EmptyResultCache{}
-
- f.immutable = rulelist.NewImmutable(b.String(), filter.IDCustom, "", cache)
+ f.immutable = rulelist.NewImmutable(
+ agdurlflt.RulesToBytes(f.rules),
+ filter.IDCustom,
+ "",
+ rulelist.EmptyResultCache{},
+ )
f.logger.DebugContext(ctx, "engine compiled", "num_rules", f.immutable.RulesCount())
}
-// DNSResult returns the result of applying the custom filter to the query with
-// the given parameters.
-func (f *Filter) DNSResult(
+// SetURLFilterResult applies the DNS filtering engine and sets the values in
+// res if any have matched. ok is true if there is a match. req and res must
+// not be nil.
+func (f *Filter) SetURLFilterResult(
ctx context.Context,
- clientIP netip.Addr,
- clientName string,
- host string,
- rrType dnsmsg.RRType,
- isAns bool,
-) (r *urlfilter.DNSResult) {
+ req *urlfilter.DNSRequest,
+ res *urlfilter.DNSResult,
+) (ok bool) {
f.initOnce.Do(func() {
f.init(ctx)
})
- return f.immutable.DNSResult(clientIP, clientName, host, rrType, isAns)
+ return f.immutable.SetURLFilterResult(ctx, req, res)
}
// Rules implements the [filter.Custom] interface for *Filter.
diff --git a/internal/filter/custom/custom_test.go b/internal/filter/custom/custom_test.go
index 415e33c..4903ce7 100644
--- a/internal/filter/custom/custom_test.go
+++ b/internal/filter/custom/custom_test.go
@@ -8,6 +8,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter/custom"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/filtertest"
"github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/urlfilter"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -29,7 +30,7 @@ func TestFilter(t *testing.T) {
require.NotNil(t, f)
require.Equal(t, rules, f.Rules())
- ip := filtertest.IPv4Client
+ ctx := context.Background()
testCases := []struct {
name string
@@ -57,12 +58,20 @@ func TestFilter(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
- dr := f.DNSResult(context.Background(), ip, tc.cliName, tc.host, dns.TypeA, false)
+ req := &urlfilter.DNSRequest{
+ ClientIP: filtertest.IPv4Client,
+ ClientName: tc.cliName,
+ Hostname: tc.host,
+ DNSType: dns.TypeA,
+ }
+ res := &urlfilter.DNSResult{}
- require.NotNil(t, dr)
- require.NotNil(t, dr.NetworkRule)
+ ok := f.SetURLFilterResult(ctx, req, res)
- assert.Equal(t, tc.wantRuleStr, dr.NetworkRule.RuleText)
+ require.True(t, ok)
+ require.NotNil(t, res.NetworkRule)
+
+ assert.Equal(t, tc.wantRuleStr, res.NetworkRule.RuleText)
})
}
}
diff --git a/internal/filter/filterstorage/config.go b/internal/filter/filterstorage/config.go
index cff4bc1..70e2ed0 100644
--- a/internal/filter/filterstorage/config.go
+++ b/internal/filter/filterstorage/config.go
@@ -25,27 +25,31 @@ type Config struct {
// BlockedServices is the configuration of a blocked-service filter for a
// default filter storage. It must not be nil
- BlockedServices *ConfigBlockedServices
+ BlockedServices *BlockedServicesConfig
// Custom is the configuration of a custom filters storage for a default
// filter storage. It must not be nil
- Custom *ConfigCustom
+ Custom *CustomConfig
// HashPrefix is the hashprefix-filter configuration for a default filter
// storage. It must not be nil
- HashPrefix *ConfigHashPrefix
+ HashPrefix *HashPrefixConfig
// RuleLists is the rule-list configuration for a default filter storage.
// It must not be nil.
- RuleLists *ConfigRuleLists
+ RuleLists *RuleListsConfig
// SafeSearchGeneral is the general safe-search configuration for a default
// filter storage. It must not be nil.
- SafeSearchGeneral *ConfigSafeSearch
+ SafeSearchGeneral *SafeSearchConfig
// SafeSearchYouTube is the YouTube safe-search configuration for a default
// filter storage. It must not be nil.
- SafeSearchYouTube *ConfigSafeSearch
+ SafeSearchYouTube *SafeSearchConfig
+
+ // StandardAccess is the standard access configuration for a default filter
+ // storage. It must not be nil.
+ StandardAccess *StandardAccessConfig
// CacheManager is the global cache manager. It must not be nil.
CacheManager agdcache.Manager
@@ -66,9 +70,9 @@ type Config struct {
CacheDir string
}
-// ConfigBlockedServices is the blocked-service filter configuration for a
+// BlockedServicesConfig is the blocked-service filter configuration for a
// default filter storage.
-type ConfigBlockedServices struct {
+type BlockedServicesConfig struct {
// IndexURL is the URL of the blocked-service filter index. It must not be
// modified after calling [New]. It must not be nil. It is ignored if
// [ConfigBlockedServices.Enabled] is false.
@@ -102,17 +106,17 @@ type ConfigBlockedServices struct {
Enabled bool
}
-// ConfigCustom is the configuration of a custom filters storage for a default
+// CustomConfig is the configuration of a custom filters storage for a default
// filter storage.
-type ConfigCustom struct {
+type CustomConfig struct {
// CacheCount is the count of items to keep in the LRU cache of custom
// filters. It must be greater than zero.
CacheCount int
}
-// ConfigHashPrefix is the hashprefix-filter configuration for a default filter
+// HashPrefixConfig is the hashprefix-filter configuration for a default filter
// storage.
-type ConfigHashPrefix struct {
+type HashPrefixConfig struct {
// Adult is the optional hashprefix filter for adult content. If nil, no
// adult-content filtering is performed.
Adult *hashprefix.Filter
@@ -126,8 +130,8 @@ type ConfigHashPrefix struct {
NewlyRegistered *hashprefix.Filter
}
-// ConfigRuleLists is the rule-list configuration for a default filter storage.
-type ConfigRuleLists struct {
+// RuleListsConfig is the rule-list configuration for a default filter storage.
+type RuleListsConfig struct {
// IndexURL is the URL of the rule-list filter index. It must not be
// modified after calling [New]. It must not be nil.
IndexURL *url.URL
@@ -164,9 +168,9 @@ type ConfigRuleLists struct {
ResultCacheEnabled bool
}
-// ConfigSafeSearch is the single safe-search configuration for a default filter
+// SafeSearchConfig is the single safe-search configuration for a default filter
// storage.
-type ConfigSafeSearch struct {
+type SafeSearchConfig struct {
// URL is the HTTP(S) URL of the safe-search rules list. It must not be
// modified after calling [New]. It must not be nil. It is ignored if
// [ConfigSafeSearch.Enabled] is false.
diff --git a/internal/filter/filterstorage/default.go b/internal/filter/filterstorage/default.go
index 30b4cc8..5c9ded5 100644
--- a/internal/filter/filterstorage/default.go
+++ b/internal/filter/filterstorage/default.go
@@ -21,6 +21,7 @@ import (
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/timeutil"
+ "github.com/AdguardTeam/urlfilter"
"github.com/c2h5oh/datasize"
)
@@ -150,7 +151,7 @@ func (s *Default) init(c *Config) (err error) {
// initBlockedServices initializes the blocked-service filter in s. c must not
// be nil.
-func (s *Default) initBlockedServices(c *ConfigBlockedServices) (err error) {
+func (s *Default) initBlockedServices(c *BlockedServicesConfig) (err error) {
if !c.Enabled {
return nil
}
@@ -181,7 +182,7 @@ func (s *Default) initBlockedServices(c *ConfigBlockedServices) (err error) {
// initSafeSearch initializes the safe-search filters in s. gen and yt must not
// be nil.
-func (s *Default) initSafeSearch(gen, yt *ConfigSafeSearch) (err error) {
+func (s *Default) initSafeSearch(gen, yt *SafeSearchConfig) (err error) {
s.safeSearchGeneral, err = newSafeSearch(s.baseLogger, gen, s.cacheManager, s.cacheDir)
if err != nil {
return fmt.Errorf("general safe search: %w", err)
@@ -199,7 +200,7 @@ func (s *Default) initSafeSearch(gen, yt *ConfigSafeSearch) (err error) {
// arguments must not be empty.
func newSafeSearch(
baseLogger *slog.Logger,
- c *ConfigSafeSearch,
+ c *SafeSearchConfig,
cacheMgr agdcache.Manager,
cacheDir string,
) (f *safesearch.Filter, err error) {
@@ -230,7 +231,7 @@ func newSafeSearch(
// initRuleListRefr initializes the rule-list refresher in s. c must not be
// nil.
-func (s *Default) initRuleListRefr(c *ConfigRuleLists) (err error) {
+func (s *Default) initRuleListRefr(c *RuleListsConfig) (err error) {
s.ruleListIdxRefr, err = refreshable.New(&refreshable.Config{
Logger: s.baseLogger.With(
slogutil.KeyPrefix, path.Join("filters", string(FilterIDRuleListIndex)),
@@ -269,7 +270,12 @@ func (s *Default) ForConfig(ctx context.Context, c filter.Config) (f filter.Inte
// forClient returns a new filter based on a client configuration. c must not
// be nil.
func (s *Default) forClient(ctx context.Context, c *filter.ConfigClient) (f filter.Interface) {
- compConf := &composite.Config{}
+ compConf := &composite.Config{
+ // TODO(a.garipov): Find ways of reusing these. Perhaps add Close to
+ // [filter.Interface]?
+ URLFilterRequest: &urlfilter.DNSRequest{},
+ URLFilterResult: &urlfilter.DNSResult{},
+ }
s.setParental(ctx, compConf, c.Parental)
s.setRuleLists(compConf, c.RuleList)
@@ -364,7 +370,12 @@ func (s *Default) setSafeBrowsing(compConf *composite.Config, c *filter.ConfigSa
// forGroup returns a new filter based on a group configuration. c must not be
// nil.
func (s *Default) forGroup(ctx context.Context, c *filter.ConfigGroup) (f filter.Interface) {
- compConf := &composite.Config{}
+ compConf := &composite.Config{
+ // TODO(a.garipov): Find ways of reusing these. Perhaps add Close to
+ // [filter.Interface]?
+ URLFilterRequest: &urlfilter.DNSRequest{},
+ URLFilterResult: &urlfilter.DNSResult{},
+ }
s.setParental(ctx, compConf, c.Parental)
s.setRuleLists(compConf, c.RuleList)
diff --git a/internal/filter/filterstorage/default_test.go b/internal/filter/filterstorage/default_test.go
index 3cb5216..abb6d3d 100644
--- a/internal/filter/filterstorage/default_test.go
+++ b/internal/filter/filterstorage/default_test.go
@@ -26,24 +26,24 @@ func TestNew(t *testing.T) {
Host: "index.example",
}
- servicesDisabled := &filterstorage.ConfigBlockedServices{
+ servicesDisabled := &filterstorage.BlockedServicesConfig{
Enabled: false,
}
- safeSearchGeneralDisabled := &filterstorage.ConfigSafeSearch{
+ safeSearchGeneralDisabled := &filterstorage.SafeSearchConfig{
ID: filter.IDGeneralSafeSearch,
Enabled: false,
}
- safeSearchYouTubeDisabled := &filterstorage.ConfigSafeSearch{
+ safeSearchYouTubeDisabled := &filterstorage.SafeSearchConfig{
ID: filter.IDYoutubeSafeSearch,
Enabled: false,
}
testCases := []struct {
- services *filterstorage.ConfigBlockedServices
- safeSearchGen *filterstorage.ConfigSafeSearch
- safeSearchYT *filterstorage.ConfigSafeSearch
+ services *filterstorage.BlockedServicesConfig
+ safeSearchGen *filterstorage.SafeSearchConfig
+ safeSearchYT *filterstorage.SafeSearchConfig
name string
}{{
services: servicesDisabled,
diff --git a/internal/filter/filterstorage/filterstorage.go b/internal/filter/filterstorage/filterstorage.go
index 0d057fe..51a414e 100644
--- a/internal/filter/filterstorage/filterstorage.go
+++ b/internal/filter/filterstorage/filterstorage.go
@@ -10,14 +10,16 @@ import (
//
// TODO(a.garipov): Consider using a separate type.
const (
- FilterIDBlockedServiceIndex filter.ID = "blocked_service_index"
- FilterIDRuleListIndex filter.ID = "rule_list_index"
+ FilterIDBlockedServiceIndex filter.ID = "blocked_service_index"
+ FilterIDRuleListIndex filter.ID = "rule_list_index"
+ FilterIDStandardProfileAccess filter.ID = "standard_profile_access"
)
// Filenames for filter indexes.
const (
- indexFileNameBlockedServices = "services.json"
- indexFileNameRuleLists = "filters.json"
+ indexFileNameBlockedServices = "services.json"
+ indexFileNameRuleLists = "filters.json"
+ indexFileNameStandardProfileAccess = "standard_profile_access.json"
)
// Constants that define cache identifiers for the cache manager.
diff --git a/internal/filter/filterstorage/filterstorage_test.go b/internal/filter/filterstorage/filterstorage_test.go
index 3191c54..c5fc433 100644
--- a/internal/filter/filterstorage/filterstorage_test.go
+++ b/internal/filter/filterstorage/filterstorage_test.go
@@ -109,7 +109,7 @@ func newDefault(tb testing.TB) (s *filterstorage.Default) {
c := newDisabledConfig(tb, newConfigRuleLists(ruleListIdxURL))
c.BlockedServices = newConfigBlockedServices(svcIdxURL)
- c.HashPrefix = &filterstorage.ConfigHashPrefix{
+ c.HashPrefix = &filterstorage.HashPrefixConfig{
Adult: filtertest.NewHashprefixFilter(tb, filter.IDAdultBlocking),
Dangerous: filtertest.NewHashprefixFilter(tb, filter.IDSafeBrowsing),
NewlyRegistered: filtertest.NewHashprefixFilter(tb, filter.IDNewRegDomains),
@@ -143,26 +143,26 @@ func newDefault(tb testing.TB) (s *filterstorage.Default) {
// entities.
func newDisabledConfig(
tb testing.TB,
- rlConf *filterstorage.ConfigRuleLists,
+ rlConf *filterstorage.RuleListsConfig,
) (c *filterstorage.Config) {
tb.Helper()
return &filterstorage.Config{
BaseLogger: slogutil.NewDiscardLogger(),
Logger: slogutil.NewDiscardLogger(),
- BlockedServices: &filterstorage.ConfigBlockedServices{
+ BlockedServices: &filterstorage.BlockedServicesConfig{
Enabled: false,
},
- Custom: &filterstorage.ConfigCustom{
+ Custom: &filterstorage.CustomConfig{
CacheCount: filtertest.CacheCount,
},
- HashPrefix: &filterstorage.ConfigHashPrefix{},
+ HashPrefix: &filterstorage.HashPrefixConfig{},
RuleLists: rlConf,
- SafeSearchGeneral: &filterstorage.ConfigSafeSearch{
+ SafeSearchGeneral: &filterstorage.SafeSearchConfig{
ID: filter.IDGeneralSafeSearch,
Enabled: false,
},
- SafeSearchYouTube: &filterstorage.ConfigSafeSearch{
+ SafeSearchYouTube: &filterstorage.SafeSearchConfig{
ID: filter.IDYoutubeSafeSearch,
Enabled: false,
},
@@ -177,8 +177,8 @@ func newDisabledConfig(
// newConfigBlockedServices is a test helper that returns a new enabled
// *ConfigBlockedServices with the given index URL. The rest of the fields are
// set to the corresponding [filtertest] values.
-func newConfigBlockedServices(indexURL *url.URL) (c *filterstorage.ConfigBlockedServices) {
- return &filterstorage.ConfigBlockedServices{
+func newConfigBlockedServices(indexURL *url.URL) (c *filterstorage.BlockedServicesConfig) {
+ return &filterstorage.BlockedServicesConfig{
IndexURL: indexURL,
IndexMaxSize: filtertest.FilterMaxSize,
IndexRefreshTimeout: filtertest.Timeout,
@@ -192,8 +192,8 @@ func newConfigBlockedServices(indexURL *url.URL) (c *filterstorage.ConfigBlocked
// newConfigRuleLists is a test helper that returns a new *ConfigRuleLists with
// the given index URL. The rest of the fields are set to the corresponding
// [filtertest] values.
-func newConfigRuleLists(indexURL *url.URL) (c *filterstorage.ConfigRuleLists) {
- return &filterstorage.ConfigRuleLists{
+func newConfigRuleLists(indexURL *url.URL) (c *filterstorage.RuleListsConfig) {
+ return &filterstorage.RuleListsConfig{
IndexURL: indexURL,
IndexMaxSize: filtertest.FilterMaxSize,
MaxSize: filtertest.FilterMaxSize,
@@ -209,8 +209,8 @@ func newConfigRuleLists(indexURL *url.URL) (c *filterstorage.ConfigRuleLists) {
// newConfigSafeSearch is a test helper that returns a new enabled
// *ConfigSafeSearch with the given filter URL and ID. The rest of the fields
// are set to the corresponding [filtertest] values.
-func newConfigSafeSearch(u *url.URL, id filter.ID) (c *filterstorage.ConfigSafeSearch) {
- return &filterstorage.ConfigSafeSearch{
+func newConfigSafeSearch(u *url.URL, id filter.ID) (c *filterstorage.SafeSearchConfig) {
+ return &filterstorage.SafeSearchConfig{
URL: u,
ID: id,
MaxSize: filtertest.FilterMaxSize,
diff --git a/internal/filter/filterstorage/refresh.go b/internal/filter/filterstorage/refresh.go
index ebc2c18..5fa8fb3 100644
--- a/internal/filter/filterstorage/refresh.go
+++ b/internal/filter/filterstorage/refresh.go
@@ -8,7 +8,6 @@ import (
"path"
"path/filepath"
"slices"
- "strings"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
@@ -81,13 +80,13 @@ func (s *Default) loadIndex(
ctx context.Context,
acceptStale bool,
) (resp *indexResp, err error) {
- text, err := s.ruleListIdxRefr.Refresh(ctx, acceptStale)
+ b, err := s.ruleListIdxRefr.Refresh(ctx, acceptStale)
if err != nil {
return nil, fmt.Errorf("loading index: %w", err)
}
resp = &indexResp{}
- err = json.NewDecoder(strings.NewReader(text)).Decode(resp)
+ err = json.Unmarshal(b, resp)
if err != nil {
return nil, fmt.Errorf("decoding: %w", err)
}
diff --git a/internal/filter/filterstorage/standardaccess.go b/internal/filter/filterstorage/standardaccess.go
new file mode 100644
index 0000000..38e05c0
--- /dev/null
+++ b/internal/filter/filterstorage/standardaccess.go
@@ -0,0 +1,252 @@
+package filterstorage
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "log/slog"
+ "net/url"
+ "path/filepath"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/access"
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/refreshable"
+ "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
+ "github.com/AdguardTeam/golibs/service"
+ "github.com/AdguardTeam/golibs/validate"
+ "github.com/google/renameio/v2"
+)
+
+// StandardAccessStorage is the interface for a storage of standard access
+// settings.
+type StandardAccessStorage interface {
+ // Config returns the standard access settings. conf must not be modified
+ // after calling this method.
+ Config(ctx context.Context) (conf *access.StandardBlockerConfig, err error)
+}
+
+// EmptyStandardAccessStorage is the empty implementation of the
+// [StandardAccessStorage] interface.
+type EmptyStandardAccessStorage struct{}
+
+// type check
+var _ StandardAccessStorage = EmptyStandardAccessStorage{}
+
+// Config implements the [StandardAccessStorage] interface for
+// EmptyStandardAccessStorage. It always returns nil.
+func (EmptyStandardAccessStorage) Config(
+ _ context.Context,
+) (conf *access.StandardBlockerConfig, err error) {
+ return nil, nil
+}
+
+// StandardAccessConfig is the configuration of a standard access storage for a
+// default filter storage.
+//
+// TODO(e.burkov): Move to another package, when internal/refreshable is moved
+// to golibs.
+type StandardAccessConfig struct {
+ // BaseLogger is used to log cache loading.
+ BaseLogger *slog.Logger
+
+ // Logger is used to log refresh operations.
+ Logger *slog.Logger
+
+ // Getter is the storage of standard access settings. It must not be nil.
+ Getter StandardAccessStorage
+
+ // Setter is the standard access to refresh from storage. It must not be
+ // nil.
+ Setter access.StandardSetter
+
+ // CacheDir is the directory where the cache files are stored.
+ CacheDir string
+}
+
+// StandardAccess updates the standard access settings from storage, caching
+// them in the cache directory.
+type StandardAccess struct {
+ getter StandardAccessStorage
+ logger *slog.Logger
+ setter access.StandardSetter
+ latest *access.StandardBlockerConfig
+ cache *refreshable.Refreshable
+ cachePath string
+}
+
+// NewStandardAccess creates a new properly initialized standard access. c must
+// be valid. It uses the latest cached settings if available, use the
+// [StandardAccess.Refresh] method to update them.
+func NewStandardAccess(ctx context.Context, c *StandardAccessConfig) (s *StandardAccess, err error) {
+ cachePath := filepath.Join(c.CacheDir, indexFileNameStandardProfileAccess)
+
+ refr, err := refreshable.New(&refreshable.Config{
+ Logger: c.BaseLogger.With(slogutil.KeyPrefix, "standard_access_cache"),
+ URL: &url.URL{
+ Scheme: urlutil.SchemeFile,
+ Path: cachePath,
+ },
+ ID: FilterIDStandardProfileAccess,
+ // Don't set CachePath, Timeout and MaxSize, since this refreshable is
+ // used in file-only mode. Also don't set Staleness, since it always
+ // accepts stale.
+ })
+ if err != nil {
+ return nil, fmt.Errorf("creating refreshable: %w", err)
+ }
+
+ s = &StandardAccess{
+ getter: c.Getter,
+ logger: c.Logger,
+ setter: c.Setter,
+ cache: refr,
+ cachePath: cachePath,
+ }
+
+ err = s.loadFromCache(ctx)
+ if err != nil {
+ if !errors.Is(err, errors.ErrNoValue) {
+ // Don't wrap the error, since it's informative enough as is.
+ return nil, err
+ }
+
+ s.logger.WarnContext(ctx, "cache is empty")
+ s.latest = &access.StandardBlockerConfig{}
+ }
+
+ s.setter.SetConfig(s.latest)
+
+ return s, nil
+}
+
+// type check
+var _ service.Refresher = (*StandardAccess)(nil)
+
+// Refresh implements the [service.Refresher] interface for *StandardAccess.
+func (s *StandardAccess) Refresh(ctx context.Context) (err error) {
+ s.logger.InfoContext(ctx, "refresh started")
+ defer s.logger.InfoContext(ctx, "refresh finished")
+
+ conf, err := s.getter.Config(ctx)
+ if err != nil {
+ return err
+ }
+
+ if conf == nil {
+ conf = &access.StandardBlockerConfig{}
+ }
+
+ if conf.Equal(s.latest) {
+ s.logger.DebugContext(ctx, "no changes")
+
+ return nil
+ }
+
+ s.latest = conf
+ s.setter.SetConfig(s.latest)
+
+ err = s.writeCache()
+ if err != nil {
+ return fmt.Errorf("writing cache: %w", err)
+ }
+
+ return nil
+}
+
+// StandardAccessVersion is the current schema version of the standard access
+// settings cache.
+//
+// NOTE: Increment this value on every change in [access.StandardBlockerConfig]
+// that requires a change in the JSON representation.
+const StandardAccessVersion uint = 1
+
+// jsonStandardAccessSettings is the JSON representation of
+// [access.StandardBlockerConfig].
+type jsonStandardAccessSettings struct {
+ AllowedNets []netutil.Prefix `json:"allowed_nets"`
+ BlockedNets []netutil.Prefix `json:"blocked_nets"`
+ AllowedASN []geoip.ASN `json:"allowed_asns"`
+ BlockedASN []geoip.ASN `json:"blocked_asns"`
+ BlocklistDomainRules []string `json:"rules"`
+ SchemaVersion uint `json:"schema_version"`
+}
+
+// standardAccessConfigToJSON converts the standard access settings to the JSON
+// representation.
+func standardAccessConfigToJSON(conf *access.StandardBlockerConfig) (s *jsonStandardAccessSettings) {
+ s = &jsonStandardAccessSettings{
+ AllowedNets: make([]netutil.Prefix, 0, len(conf.AllowedNets)),
+ BlockedNets: make([]netutil.Prefix, 0, len(conf.BlockedNets)),
+ AllowedASN: conf.AllowedASN,
+ BlockedASN: conf.BlockedASN,
+ BlocklistDomainRules: conf.BlocklistDomainRules,
+ SchemaVersion: StandardAccessVersion,
+ }
+ for _, p := range conf.AllowedNets {
+ s.AllowedNets = append(s.AllowedNets, netutil.Prefix{Prefix: p})
+ }
+ for _, p := range conf.BlockedNets {
+ s.BlockedNets = append(s.BlockedNets, netutil.Prefix{Prefix: p})
+ }
+
+ return s
+}
+
+// toInternal converts the JSON representation of the standard access settings
+// to the internal one.
+func (s *jsonStandardAccessSettings) toInternal() (conf *access.StandardBlockerConfig) {
+ return &access.StandardBlockerConfig{
+ AllowedNets: netutil.UnembedPrefixes(s.AllowedNets),
+ BlockedNets: netutil.UnembedPrefixes(s.BlockedNets),
+ AllowedASN: s.AllowedASN,
+ BlockedASN: s.BlockedASN,
+ BlocklistDomainRules: s.BlocklistDomainRules,
+ }
+}
+
+// loadFromCache loads the standard access settings from the cache.
+func (s *StandardAccess) loadFromCache(ctx context.Context) (err error) {
+ raw, err := s.cache.Refresh(ctx, true)
+ if err != nil {
+ return fmt.Errorf("loading cache: %w", err)
+ }
+
+ err = validate.NotEmptySlice("cache", raw)
+ if err != nil {
+ // Don't wrap the error, since it's informative enough as is.
+ return err
+ }
+
+ settings := &jsonStandardAccessSettings{}
+ err = json.Unmarshal(raw, settings)
+ if err != nil {
+ return fmt.Errorf("decoding cache: %w", err)
+ }
+
+ v := settings.SchemaVersion
+ err = validate.InRange("schema_version", v, StandardAccessVersion, StandardAccessVersion)
+ if err != nil {
+ return fmt.Errorf("malformed cache: %w", err)
+ }
+
+ s.latest = settings.toInternal()
+
+ return nil
+}
+
+// writeCache writes the latest standard access settings to the cache.
+func (s *StandardAccess) writeCache() (err error) {
+ settings := standardAccessConfigToJSON(s.latest)
+
+ b := &bytes.Buffer{}
+ err = json.NewEncoder(b).Encode(settings)
+ if err != nil {
+ return fmt.Errorf("encoding cache: %w", err)
+ }
+
+ return renameio.WriteFile(s.cachePath, b.Bytes(), 0o600)
+}
diff --git a/internal/filter/filterstorage/standardaccess_test.go b/internal/filter/filterstorage/standardaccess_test.go
new file mode 100644
index 0000000..ef143a9
--- /dev/null
+++ b/internal/filter/filterstorage/standardaccess_test.go
@@ -0,0 +1,210 @@
+package filterstorage_test
+
+import (
+ "context"
+ "net/netip"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/access"
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter/filterstorage"
+ "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// testTimeout is the common timeout for tests and contexts.
+const testTimeout = 1 * time.Second
+
+// testLogger is the common logger for tests.
+var testLogger = slogutil.NewDiscardLogger()
+
+// testStandardAccessStorage is the mock implementation of the
+// [filterstorage.StandardAccessStorage] interface for tests.
+//
+// TODO(e.burkov): Move to agdtest.
+type testStandardAccessStorage struct {
+ OnConfig func(ctx context.Context) (conf *access.StandardBlockerConfig, err error)
+}
+
+// type check
+var _ filterstorage.StandardAccessStorage = (*testStandardAccessStorage)(nil)
+
+// Config implements the [filterstorage.StandardAccessStorage] interface for
+// *testStandardAccessStorage.
+func (s *testStandardAccessStorage) Config(
+ ctx context.Context,
+) (conf *access.StandardBlockerConfig, err error) {
+ return s.OnConfig(ctx)
+}
+
+// testStandardSetter is the mock implementation of the [access.StandardSetter]
+// interface for tests.
+//
+// TODO(e.burkov): Move to agdtest.
+type testStandardSetter struct {
+ OnSetConfig func(conf *access.StandardBlockerConfig)
+}
+
+// type check
+var _ access.StandardSetter = (*testStandardSetter)(nil)
+
+// SetConfig implements the [access.StandardSetter] interface for
+// *testStandardSetter.
+func (s *testStandardSetter) SetConfig(conf *access.StandardBlockerConfig) {
+ s.OnSetConfig(conf)
+}
+
+// panicSetter is the mock implementation of the [access.StandardSetter]
+// interface for tests that panics on any call.
+var panicSetter = &testStandardSetter{
+ OnSetConfig: func(conf *access.StandardBlockerConfig) { panic("should not be called") },
+}
+
+func TestStandardAccess(t *testing.T) {
+ t.Parallel()
+
+ testConf := &access.StandardBlockerConfig{
+ AllowedNets: []netip.Prefix{netip.MustParsePrefix("192.0.2.1/32")},
+ BlockedNets: []netip.Prefix{netip.MustParsePrefix("192.0.2.2/32")},
+ AllowedASN: []geoip.ASN{10},
+ BlockedASN: []geoip.ASN{20},
+ BlocklistDomainRules: []string{
+ "blocked.std.test",
+ "@@allowed.std.test",
+ },
+ }
+
+ errStorage := &testStandardAccessStorage{
+ OnConfig: func(_ context.Context) (conf *access.StandardBlockerConfig, err error) {
+ return nil, assert.AnError
+ },
+ }
+ okStorage := &testStandardAccessStorage{
+ OnConfig: func(_ context.Context) (conf *access.StandardBlockerConfig, err error) {
+ return testConf, nil
+ },
+ }
+
+ pt := testutil.PanicT{}
+ emptySetter := &testStandardSetter{
+ OnSetConfig: func(conf *access.StandardBlockerConfig) { require.Empty(pt, conf) },
+ }
+ testSetter := &testStandardSetter{
+ OnSetConfig: func(conf *access.StandardBlockerConfig) { require.Equal(pt, testConf, conf) },
+ }
+
+ testCases := []struct {
+ storage filterstorage.StandardAccessStorage
+ setter access.StandardSetter
+ wantRefrErr error
+ name string
+ }{{
+ storage: okStorage,
+ setter: testSetter,
+ wantRefrErr: nil,
+ name: "success",
+ }, {
+ storage: filterstorage.EmptyStandardAccessStorage{},
+ setter: emptySetter,
+ wantRefrErr: nil,
+ name: "empty",
+ }, {
+ storage: errStorage,
+ setter: panicSetter,
+ wantRefrErr: assert.AnError,
+ name: "error",
+ }}
+
+ for _, tc := range testCases {
+ setter := &testStandardSetter{
+ // Use empty setter to ensure that nothing stored in cache.
+ OnSetConfig: emptySetter.OnSetConfig,
+ }
+
+ newCtx := testutil.ContextWithTimeout(t, testTimeout)
+ sa, newErr := filterstorage.NewStandardAccess(newCtx, &filterstorage.StandardAccessConfig{
+ Logger: testLogger,
+ BaseLogger: testLogger,
+ Getter: tc.storage,
+ Setter: setter,
+ CacheDir: t.TempDir(),
+ })
+ require.NoError(t, newErr)
+
+ setter.OnSetConfig = tc.setter.SetConfig
+
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ err := sa.Refresh(ctx)
+ require.ErrorIs(t, err, tc.wantRefrErr)
+ })
+ }
+}
+
+func TestStandardAccess_cache(t *testing.T) {
+ t.Parallel()
+
+ testConf := &access.StandardBlockerConfig{
+ AllowedNets: []netip.Prefix{netip.MustParsePrefix("192.0.2.1/32")},
+ BlockedNets: []netip.Prefix{netip.MustParsePrefix("192.0.2.2/32")},
+ AllowedASN: []geoip.ASN{10},
+ BlockedASN: []geoip.ASN{20},
+ BlocklistDomainRules: []string{
+ "blocked.std.test",
+ "@@allowed.std.test",
+ },
+ }
+
+ pt := testutil.PanicT{}
+ testSetter := &testStandardSetter{
+ OnSetConfig: func(conf *access.StandardBlockerConfig) {
+ require.Equal(pt, testConf, conf)
+ },
+ }
+ emptySetter := &testStandardSetter{
+ OnSetConfig: func(conf *access.StandardBlockerConfig) {
+ require.Empty(pt, conf)
+ },
+ }
+
+ testCases := []struct {
+ setter access.StandardSetter
+ wantErrMsg string
+ name string
+ }{{
+ setter: testSetter,
+ wantErrMsg: "",
+ name: "success",
+ }, {
+ setter: panicSetter,
+ wantErrMsg: "malformed cache: schema_version: out of range: " +
+ "must be no less than 1, got 0",
+ name: "bad_version",
+ }, {
+ setter: emptySetter,
+ wantErrMsg: "",
+ name: "non-existent",
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ _, err := filterstorage.NewStandardAccess(ctx, &filterstorage.StandardAccessConfig{
+ Logger: testLogger,
+ BaseLogger: testLogger,
+ Getter: filterstorage.EmptyStandardAccessStorage{},
+ Setter: tc.setter,
+ CacheDir: filepath.Join("./testdata", t.Name()),
+ })
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+ })
+ }
+}
diff --git a/internal/filter/filterstorage/testdata/TestStandardAccess_cache/bad_version/standard_profile_access.json b/internal/filter/filterstorage/testdata/TestStandardAccess_cache/bad_version/standard_profile_access.json
new file mode 100644
index 0000000..06a8918
--- /dev/null
+++ b/internal/filter/filterstorage/testdata/TestStandardAccess_cache/bad_version/standard_profile_access.json
@@ -0,0 +1,4 @@
+{
+ "unknown_field": "value",
+ "schema_version": 0
+}
diff --git a/internal/filter/filterstorage/testdata/TestStandardAccess_cache/success/standard_profile_access.json b/internal/filter/filterstorage/testdata/TestStandardAccess_cache/success/standard_profile_access.json
new file mode 100644
index 0000000..570d42b
--- /dev/null
+++ b/internal/filter/filterstorage/testdata/TestStandardAccess_cache/success/standard_profile_access.json
@@ -0,0 +1,19 @@
+{
+ "allowed_nets": [
+ "192.0.2.1/32"
+ ],
+ "blocked_nets": [
+ "192.0.2.2/32"
+ ],
+ "allowed_asns": [
+ 10
+ ],
+ "blocked_asns": [
+ 20
+ ],
+ "rules": [
+ "blocked.std.test",
+ "@@allowed.std.test"
+ ],
+ "schema_version": 1
+}
diff --git a/internal/filter/hashprefix/filter.go b/internal/filter/hashprefix/filter.go
index 0d41696..b490a6f 100644
--- a/internal/filter/hashprefix/filter.go
+++ b/internal/filter/hashprefix/filter.go
@@ -81,16 +81,6 @@ type FilterConfig struct {
MaxSize datasize.ByteSize
}
-// cacheItem represents an item that we will store in the cache.
-type cacheItem struct {
- // res is the filtering result.
- res filter.Result
-
- // host is the cached normalized hostname for later cache key collision
- // checks.
- host string
-}
-
// Filter is a filter that matches hosts by their hashes based on a hash-prefix
// table. It should be initially refreshed with [Filter.RefreshInitial].
type Filter struct {
@@ -101,7 +91,7 @@ type Filter struct {
errColl errcoll.Interface
hashprefixMtcs Metrics
metrics filter.Metrics
- resCache agdcache.Interface[rulelist.CacheKey, *cacheItem]
+ resCache agdcache.Interface[rulelist.CacheKey, filter.Result]
id filter.ID
repIP netip.Addr
repFQDN string
@@ -119,7 +109,7 @@ const IDPrefix = "filters/hashprefix"
func NewFilter(c *FilterConfig) (f *Filter, err error) {
id := c.ID
- resCache := agdcache.NewLRU[rulelist.CacheKey, *cacheItem](&agdcache.LRUConfig{
+ resCache := agdcache.NewLRU[rulelist.CacheKey, filter.Result](&agdcache.LRUConfig{
Count: c.CacheCount,
})
@@ -174,10 +164,10 @@ func (f *Filter) FilterRequest(
host, qt, cl := req.Host, req.QType, req.QClass
cacheKey := rulelist.NewCacheKey(host, qt, cl, false)
- item, ok := f.itemFromCache(ctx, cacheKey, host)
+ item, ok := f.resCache.Get(cacheKey)
f.hashprefixMtcs.IncrementLookups(ctx, ok)
if ok {
- return f.clonedResult(req.DNS, item.res), nil
+ return f.clonedResult(req.DNS, item), nil
}
fam, ok := isFilterable(qt)
@@ -196,10 +186,7 @@ func (f *Filter) FilterRequest(
}
if matched == "" {
- f.resCache.Set(cacheKey, &cacheItem{
- res: nil,
- host: host,
- })
+ f.resCache.Set(cacheKey, nil)
return nil, nil
}
@@ -210,35 +197,13 @@ func (f *Filter) FilterRequest(
return nil, err
}
- f.setInCache(cacheKey, r, host)
+ f.setInCache(cacheKey, r)
f.hashprefixMtcs.UpdateCacheSize(ctx, f.resCache.Len())
return r, nil
}
-// itemFromCache retrieves a cache item for the given key. host is used to
-// detect key collisions. If there is a key collision, it returns nil and
-// false.
-func (f *Filter) itemFromCache(
- ctx context.Context,
- key rulelist.CacheKey,
- host string,
-) (item *cacheItem, ok bool) {
- item, ok = f.resCache.Get(key)
- if !ok {
- return nil, false
- }
-
- if item.host != host {
- f.logger.WarnContext(ctx, "collision: bad cache item", "item", item, "host", host)
-
- return nil, false
- }
-
- return item, true
-}
-
// isFilterable returns true if the question type is filterable. If the type is
// filterable with a blocked page, fam is the address family for the IP
// addresses of the blocked page; otherwise fam is [netutil.AddrFamilyNone].
@@ -335,18 +300,12 @@ func (f *Filter) respForFamily(
// [*filter.ResultModifiedResponse].
//
// See AGDNS-359.
-func (f *Filter) setInCache(k rulelist.CacheKey, r filter.Result, host string) {
+func (f *Filter) setInCache(k rulelist.CacheKey, r filter.Result) {
switch r := r.(type) {
case *filter.ResultModifiedRequest:
- f.resCache.Set(k, &cacheItem{
- res: r.Clone(f.cloner),
- host: host,
- })
+ f.resCache.Set(k, r.Clone(f.cloner))
case *filter.ResultModifiedResponse:
- f.resCache.Set(k, &cacheItem{
- res: r.Clone(f.cloner),
- host: host,
- })
+ f.resCache.Set(k, r.Clone(f.cloner))
default:
panic(fmt.Errorf("hashprefix: unexpected type for result: %T(%[1]v)", r))
}
@@ -392,13 +351,13 @@ func (f *Filter) refresh(ctx context.Context, acceptStale bool) (err error) {
f.metrics.SetFilterStatus(ctx, string(f.id), time.Now(), count, err)
}()
- text, err := f.refr.Refresh(ctx, acceptStale)
+ b, err := f.refr.Refresh(ctx, acceptStale)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
}
- count, err = f.hashes.Reset(text)
+ count, err = f.hashes.Reset(b)
if err != nil {
return fmt.Errorf("%s: resetting: %w", f.id, err)
}
diff --git a/internal/filter/hashprefix/filter_test.go b/internal/filter/hashprefix/filter_test.go
index 10bb274..3a32267 100644
--- a/internal/filter/hashprefix/filter_test.go
+++ b/internal/filter/hashprefix/filter_test.go
@@ -241,7 +241,7 @@ func TestFilter_Refresh(t *testing.T) {
refrCh := make(chan struct{}, 1)
cachePath, srvURL := filtertest.PrepareRefreshable(t, refrCh, testHashes, http.StatusOK)
- strg, err := hashprefix.NewStorage("")
+ strg, err := hashprefix.NewStorage(nil)
require.NoError(t, err)
f, err := hashprefix.NewFilter(&hashprefix.FilterConfig{
@@ -292,7 +292,7 @@ func TestFilter_FilterRequest_staleCache(t *testing.T) {
// Create the filter.
- strg, err := hashprefix.NewStorage("")
+ strg, err := hashprefix.NewStorage(nil)
require.NoError(t, err)
cloner := agdtest.NewCloner()
diff --git a/internal/filter/hashprefix/hashprefix_test.go b/internal/filter/hashprefix/hashprefix_test.go
index 15c1f01..7db9c11 100644
--- a/internal/filter/hashprefix/hashprefix_test.go
+++ b/internal/filter/hashprefix/hashprefix_test.go
@@ -6,3 +6,6 @@ import (
// testHashes is the host data for tests.
const testHashes = filtertest.HostAdultContent + "\n"
+
+// testHashesData is the host data for tests.
+var testHashesData = []byte(testHashes)
diff --git a/internal/filter/hashprefix/matcher_test.go b/internal/filter/hashprefix/matcher_test.go
index 3eed512..187ba7b 100644
--- a/internal/filter/hashprefix/matcher_test.go
+++ b/internal/filter/hashprefix/matcher_test.go
@@ -4,9 +4,9 @@ import (
"context"
"crypto/sha256"
"encoding/hex"
- "strings"
"testing"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdurlflt"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix"
"github.com/stretchr/testify/assert"
@@ -43,7 +43,7 @@ func TestMatcher(t *testing.T) {
hashStrs[i] = hex.EncodeToString(sum[:])
}
- hashes, err := hashprefix.NewStorage(strings.Join(hosts, "\n"))
+ hashes, err := hashprefix.NewStorage(agdurlflt.RulesToBytes(hosts))
require.NoError(t, err)
ctx := context.Background()
diff --git a/internal/filter/hashprefix/storage.go b/internal/filter/hashprefix/storage.go
index eaba656..e6c03fa 100644
--- a/internal/filter/hashprefix/storage.go
+++ b/internal/filter/hashprefix/storage.go
@@ -2,6 +2,7 @@ package hashprefix
import (
"bufio"
+ "bytes"
"crypto/sha256"
"encoding/hex"
"fmt"
@@ -15,8 +16,7 @@ import (
//
// TODO(a.garipov): See if we could unexport this.
type Storage struct {
- // resetMu makes sure that only one reset is taking place at a time. It
- // also protects prev.
+ // resetMu makes sure that only one reset is taking place at a time.
resetMu *sync.Mutex
// hashSuffixes contains the hashSuffixes map. It is an atomic pointer to
@@ -29,9 +29,11 @@ type Storage struct {
type suffixMap = map[Prefix][]suffix
// NewStorage returns a new hash storage containing hashes of the domain names
-// listed in hostnames, one domain name per line, requirements are described in
-// [Storage.Reset]. Empty string causes no errors.
-func NewStorage(hostnames string) (s *Storage, err error) {
+// listed in hostnameData (see [Storage.Reset]). hostnameData may be nil.
+//
+// TODO(a.garipov): Consider moving the version with the initial data into
+// tests.
+func NewStorage(hostnameData []byte) (s *Storage, err error) {
s = &Storage{
resetMu: &sync.Mutex{},
hashSuffixes: &atomic.Pointer[suffixMap]{},
@@ -39,8 +41,8 @@ func NewStorage(hostnames string) (s *Storage, err error) {
s.hashSuffixes.Store(&suffixMap{})
- if hostnames != "" {
- _, err = s.Reset(hostnames)
+ if hostnameData != nil {
+ _, err = s.Reset(hostnameData)
if err != nil {
return nil, err
}
@@ -130,23 +132,23 @@ func (s *Storage) loadHashSuffixes(pref Prefix) (sufs []suffix, ok bool) {
}
// Reset resets the hosts in the index using the domain names listed in
-// hostnames and returns the total number of processed rules. hostnames should
-// be a list of valid, lowercased domain names, one per line, and may include
+// hostnameData and returns the total number of processed rules. hostnameData
+// should contain valid, lowercased domain names, one per line, and may include
// empty lines and comments ('#' at the first position).
-func (s *Storage) Reset(hostnames string) (n int, err error) {
+func (s *Storage) Reset(hostnameData []byte) (n int, err error) {
s.resetMu.Lock()
defer s.resetMu.Unlock()
next := make(suffixMap, len(*s.hashSuffixes.Load()))
- sc := bufio.NewScanner(strings.NewReader(hostnames))
+ sc := bufio.NewScanner(bytes.NewReader(hostnameData))
for sc.Scan() {
- host := sc.Text()
+ host := sc.Bytes()
if len(host) == 0 || host[0] == '#' {
continue
}
- sum := sha256.Sum256([]byte(host))
+ sum := sha256.Sum256(host)
pref := Prefix(sum[:PrefixLen])
suf := suffix(sum[PrefixLen:])
next[pref] = append(next[pref], suf)
diff --git a/internal/filter/hashprefix/storage_test.go b/internal/filter/hashprefix/storage_test.go
index b87f456..5dfc385 100644
--- a/internal/filter/hashprefix/storage_test.go
+++ b/internal/filter/hashprefix/storage_test.go
@@ -5,9 +5,9 @@ import (
"encoding/hex"
"fmt"
"strconv"
- "strings"
"testing"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdurlflt"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/filtertest"
"github.com/stretchr/testify/assert"
@@ -15,7 +15,7 @@ import (
)
func TestStorage_Hashes(t *testing.T) {
- s, err := hashprefix.NewStorage(testHashes)
+ s, err := hashprefix.NewStorage(testHashesData)
require.NoError(t, err)
h := sha256.Sum256([]byte(filtertest.HostAdultContent))
@@ -30,7 +30,7 @@ func TestStorage_Hashes(t *testing.T) {
}
func TestStorage_Matches(t *testing.T) {
- s, err := hashprefix.NewStorage(testHashes)
+ s, err := hashprefix.NewStorage(testHashesData)
require.NoError(t, err)
got := s.Matches(filtertest.HostAdultContent)
@@ -41,12 +41,12 @@ func TestStorage_Matches(t *testing.T) {
}
func TestStorage_Reset(t *testing.T) {
- s, err := hashprefix.NewStorage(testHashes)
+ s, err := hashprefix.NewStorage(testHashesData)
require.NoError(t, err)
assert.True(t, s.Matches(filtertest.HostAdultContent))
- const newHashes = filtertest.Host + "\n"
+ newHashes := []byte(filtertest.Host + "\n")
n, err := s.Reset(newHashes)
require.NoError(t, err)
@@ -83,7 +83,7 @@ func BenchmarkStorage_Hashes(b *testing.B) {
hosts = append(hosts, fmt.Sprintf("%d."+filtertest.HostAdultContent, i))
}
- s, err := hashprefix.NewStorage(strings.Join(hosts, "\n"))
+ s, err := hashprefix.NewStorage(agdurlflt.RulesToBytes(hosts))
require.NoError(b, err)
var hashPrefixes []hashprefix.Prefix
@@ -105,16 +105,16 @@ func BenchmarkStorage_Hashes(b *testing.B) {
})
}
- // Most recent results, on a ThinkPad X13 with a Ryzen Pro 7 CPU:
+ // Most recent results:
//
- // goos: darwin
- // goarch: amd64
- // pkg: github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix
- // cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
- // BenchmarkStorage_Hashes/1-12 7134991 173.2 ns/op 80 B/op 2 allocs/op
- // BenchmarkStorage_Hashes/2-12 6062851 200.0 ns/op 80 B/op 2 allocs/op
- // BenchmarkStorage_Hashes/3-12 5138690 233.9 ns/op 80 B/op 2 allocs/op
- // BenchmarkStorage_Hashes/4-12 4361190 271.8 ns/op 80 B/op 2 allocs/op
+ // goos: darwin
+ // goarch: arm64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix
+ // cpu: Apple M1 Pro
+ // BenchmarkStorage_Hashes/1-8 10519970 102.7 ns/op 80 B/op 2 allocs/op
+ // BenchmarkStorage_Hashes/2-8 10045784 118.1 ns/op 80 B/op 2 allocs/op
+ // BenchmarkStorage_Hashes/3-8 9088449 129.2 ns/op 80 B/op 2 allocs/op
+ // BenchmarkStorage_Hashes/4-8 8577764 139.4 ns/op 80 B/op 2 allocs/op
}
func BenchmarkStorage_ResetHosts(b *testing.B) {
@@ -125,22 +125,22 @@ func BenchmarkStorage_ResetHosts(b *testing.B) {
hosts = append(hosts, fmt.Sprintf("%d."+filtertest.HostAdultContent, i))
}
- hostnames := strings.Join(hosts, "\n")
- s, err := hashprefix.NewStorage(hostnames)
+ hostnameData := agdurlflt.RulesToBytes(hosts)
+ s, err := hashprefix.NewStorage(hostnameData)
require.NoError(b, err)
b.ReportAllocs()
for b.Loop() {
- _, err = s.Reset(hostnames)
+ _, err = s.Reset(hostnameData)
}
require.NoError(b, err)
// Most recent results:
//
- // goos: darwin
- // goarch: amd64
- // pkg: github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix
- // cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
- // BenchmarkStorage_ResetHosts-12 3814 313231 ns/op 118385 B/op 1009 allocs/op
+ // goos: darwin
+ // goarch: arm64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix
+ // cpu: Apple M1 Pro
+ // BenchmarkStorage_ResetHosts-8 8610 128756 ns/op 118380 B/op 1009 allocs/op
}
diff --git a/internal/filter/internal/composite/composite.go b/internal/filter/internal/composite/composite.go
index 0b5be03..91191a3 100644
--- a/internal/filter/internal/composite/composite.go
+++ b/internal/filter/internal/composite/composite.go
@@ -9,12 +9,19 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
+ "github.com/AdguardTeam/urlfilter"
"github.com/miekg/dns"
)
// Filter is a composite filter based on several types of safe-search and
// rule-list filters.
type Filter struct {
+ // ufReq is the URLFilter request data to use and reuse during filtering.
+ ufReq *urlfilter.DNSRequest
+
+ // ufRes is the URLFilter result data to use and reuse during filtering.
+ ufRes *urlfilter.DNSResult
+
// custom is the custom rule-list filter of the profile, if any.
custom filter.Custom
@@ -26,13 +33,20 @@ type Filter struct {
// services, if any.
svcLists []*rulelist.Immutable
- // reqFilters are the safe-browsing and safe-search request filters in the
- // composite filter.
+ // reqFilters are the safe-browsing request filters in the composite filter.
reqFilters []RequestFilter
}
// Config is the configuration structure for the composite filter.
type Config struct {
+ // URLFilterRequest is the request data to use and reuse during filtering.
+ // It must not be nil.
+ URLFilterRequest *urlfilter.DNSRequest
+
+ // URLFilterResult is the result data to use and reuse during filtering. It
+ // must not be nil.
+ URLFilterResult *urlfilter.DNSResult
+
// SafeBrowsing is the safe-browsing filter to apply, if any.
SafeBrowsing RequestFilter
@@ -44,10 +58,10 @@ type Config struct {
NewRegisteredDomains RequestFilter
// GeneralSafeSearch is the general safe-search filter to apply, if any.
- GeneralSafeSearch RequestFilter
+ GeneralSafeSearch RequestFilterUF
// YouTubeSafeSearch is the youtube safe-search filter to apply, if any.
- YouTubeSafeSearch RequestFilter
+ YouTubeSafeSearch RequestFilterUF
// Custom is the custom rule-list filter of the profile, if any.
Custom filter.Custom
@@ -61,16 +75,14 @@ type Config struct {
ServiceLists []*rulelist.Immutable
}
-// RequestFilter can filter a request based on the request info.
-type RequestFilter interface {
- // FilterRequest filters a DNS request based on the information provided
- // about the request. req must be valid.
- FilterRequest(ctx context.Context, req *filter.Request) (r filter.Result, err error)
-}
-
// New returns a new composite filter. c must not be nil.
+//
+// TODO(a.garipov): Consider reusing composite filters and adding function Set
+// and method Reset.
func New(c *Config) (f *Filter) {
f = &Filter{
+ ufReq: c.URLFilterRequest,
+ ufRes: c.URLFilterResult,
custom: c.Custom,
ruleLists: c.RuleLists,
svcLists: c.ServiceLists,
@@ -79,15 +91,17 @@ func New(c *Config) (f *Filter) {
// DO NOT change the order of request filters without necessity.
f.reqFilters = appendIfNotNil(f.reqFilters, c.SafeBrowsing)
f.reqFilters = appendIfNotNil(f.reqFilters, c.AdultBlocking)
- f.reqFilters = appendIfNotNil(f.reqFilters, c.GeneralSafeSearch)
- f.reqFilters = appendIfNotNil(f.reqFilters, c.YouTubeSafeSearch)
+ f.reqFilters = appendIfNotNilUF(f.reqFilters, c.GeneralSafeSearch, f.ufReq, f.ufRes)
+ f.reqFilters = appendIfNotNilUF(f.reqFilters, c.YouTubeSafeSearch, f.ufReq, f.ufRes)
f.reqFilters = appendIfNotNil(f.reqFilters, c.NewRegisteredDomains)
return f
}
-// appendIfNotNil appends flt to flts if flt is not nil.
-func appendIfNotNil(flts []RequestFilter, flt RequestFilter) (res []RequestFilter) {
+// appendIfNotNil appends flt to orig if flt is not nil.
+func appendIfNotNil(orig []RequestFilter, flt RequestFilter) (flts []RequestFilter) {
+ flts = orig
+
if flt != nil {
flts = append(flts, flt)
}
@@ -95,6 +109,27 @@ func appendIfNotNil(flts []RequestFilter, flt RequestFilter) (res []RequestFilte
return flts
}
+// appendIfNotNilUF wraps flt and appends it to orig if flt is not nil.
+func appendIfNotNilUF(
+ orig []RequestFilter,
+ flt RequestFilterUF,
+ req *urlfilter.DNSRequest,
+ res *urlfilter.DNSResult,
+) (flts []RequestFilter) {
+ flts = orig
+
+ if flt != nil {
+ // TODO(a.garipov): Consider reusing wrapper structures.
+ flts = append(flts, &ufRequestFilter{
+ flt: flt,
+ req: req,
+ res: res,
+ })
+ }
+
+ return flts
+}
+
// type check
var _ filter.Interface = (*Filter)(nil)
@@ -137,6 +172,7 @@ func (f *Filter) FilterRequest(
// Go on.
}
+ // Secondly, check the safe-browsing and safe-search filters.
for _, rf := range f.reqFilters {
r, err = rf.FilterRequest(ctx, req)
if err != nil {
@@ -156,45 +192,87 @@ func (f *Filter) filterReqWithRuleLists(
ctx context.Context,
req *filter.Request,
) (r filter.Result) {
- ip, host, qt := req.RemoteIP, req.Host, req.QType
+ f.ufReq.Reset()
- // TODO(a.garipov): Consider adding a pool of results to the default
- // storage and use it here.
- ufRes := newURLFilterResult()
- if f.custom != nil {
- id := filter.IDCustom
+ f.ufReq.ClientIP = req.RemoteIP
+ f.ufReq.ClientName = req.ClientName
+ f.ufReq.DNSType = req.QType
+ f.ufReq.Hostname = req.Host
- // Only use the device name for custom filters of profiles with devices.
- dr := f.custom.DNSResult(ctx, ip, req.ClientName, host, qt, false)
- mod := rulelist.ProcessDNSRewrites(req, dr.DNSRewrites(), id)
- if mod != nil {
- // Process the DNS rewrites of the custom list and return them
- // first, because custom rules have priority over other rules.
- return mod
- }
-
- ufRes.add(id, "", dr)
+ c := newURLFilterResultCollector()
+ mod := f.filterReqWithCustom(ctx, req, c, f.ufReq, f.ufRes)
+ if mod != nil {
+ // Custom DNS rewrites have priority over other rules.
+ return mod
}
- for _, rl := range f.ruleLists {
- id, _ := rl.ID()
- dr := rl.DNSResult(ip, "", host, qt, false)
- mod := rulelist.ProcessDNSRewrites(req, dr.DNSRewrites(), id)
- if mod != nil {
- // DNS rewrites have higher priority, so a modified request must be
- // returned immediately.
- return mod
- }
+ // Don't use the device name for non-custom filters.
+ f.ufReq.ClientName = ""
- ufRes.add(id, "", dr)
+ for _, rl := range f.ruleLists {
+ f.ufRes.Reset()
+ ok := rl.SetURLFilterResult(ctx, f.ufReq, f.ufRes)
+ if ok {
+ id, _ := rl.ID()
+
+ mod = rulelist.ProcessDNSRewrites(req, f.ufRes.DNSRewrites(), id)
+ if mod != nil {
+ // DNS rewrites have higher priority, so a modified request must
+ // be returned immediately.
+ return mod
+ }
+
+ c.add(id, "", f.ufRes)
+ }
}
for _, rl := range f.svcLists {
id, svcID := rl.ID()
- ufRes.add(id, svcID, rl.DNSResult(ip, "", host, qt, false))
+
+ f.ufRes.Reset()
+ ok := rl.SetURLFilterResult(ctx, f.ufReq, f.ufRes)
+ if ok {
+ c.add(id, svcID, f.ufRes)
+ }
}
- return ufRes.toInternal(qt)
+ return c.toInternal(req.QType)
+}
+
+// filterReqWithCustom filters one question's information through the custom
+// rule-list filter of the composite filter, if there is one. All arguments
+// must not be nil.
+func (f *Filter) filterReqWithCustom(
+ ctx context.Context,
+ req *filter.Request,
+ c *urlFilterResultCollector,
+ ufReq *urlfilter.DNSRequest,
+ ufRes *urlfilter.DNSResult,
+) (res filter.Result) {
+ if f.custom == nil {
+ return nil
+ }
+
+ // Only use the device name for custom filters of profiles with devices.
+ ufReq.ClientName = req.ClientName
+
+ ufRes.Reset()
+
+ ok := f.custom.SetURLFilterResult(ctx, ufReq, ufRes)
+ if !ok {
+ return nil
+ }
+
+ id := filter.IDCustom
+
+ mod := rulelist.ProcessDNSRewrites(req, ufRes.DNSRewrites(), id)
+ if mod != nil {
+ return mod
+ }
+
+ c.add(id, "", ufRes)
+
+ return nil
}
// FilterResponse implements the [filter.Interface] interface for *Filter. It
@@ -242,23 +320,49 @@ func (f *Filter) filterRespWithRuleLists(
host string,
rrType dnsmsg.RRType,
) (r filter.Result) {
- ufRes := newURLFilterResult()
+ f.ufReq.Reset()
+
+ f.ufReq.Answer = true
+ f.ufReq.ClientIP = resp.RemoteIP
+ f.ufReq.DNSType = rrType
+ f.ufReq.Hostname = host
+
+ c := newURLFilterResultCollector()
for _, rl := range f.ruleLists {
id, _ := rl.ID()
- ufRes.add(id, "", rl.DNSResult(resp.RemoteIP, "", host, rrType, true))
+
+ f.ufRes.Reset()
+
+ ok := rl.SetURLFilterResult(ctx, f.ufReq, f.ufRes)
+ if ok {
+ c.add(id, "", f.ufRes)
+ }
}
if f.custom != nil {
- dr := f.custom.DNSResult(ctx, resp.RemoteIP, resp.ClientName, host, rrType, true)
- ufRes.add(filter.IDCustom, "", dr)
+ f.ufReq.ClientName = resp.ClientName
+
+ f.ufRes.Reset()
+
+ ok := f.custom.SetURLFilterResult(ctx, f.ufReq, f.ufRes)
+ if ok {
+ c.add(filter.IDCustom, "", f.ufRes)
+ }
}
+ f.ufReq.ClientName = ""
+
for _, rl := range f.svcLists {
id, svcID := rl.ID()
- ufRes.add(id, svcID, rl.DNSResult(resp.RemoteIP, "", host, rrType, true))
+
+ f.ufRes.Reset()
+ ok := rl.SetURLFilterResult(ctx, f.ufReq, f.ufRes)
+ if ok {
+ c.add(id, svcID, f.ufRes)
+ }
}
- return ufRes.toInternal(rrType)
+ return c.toInternal(rrType)
}
// filterHTTPSAnswer filters HTTPS answers information through all rule list
@@ -290,7 +394,7 @@ func (f *Filter) filterSVCBHint(
hint string,
resp *filter.Response,
) (r filter.Result) {
- for _, s := range strings.Split(hint, ",") {
+ for s := range strings.SplitSeq(hint, ",") {
r = f.filterRespWithRuleLists(ctx, resp, s, dns.TypeHTTPS)
if r != nil {
return r
diff --git a/internal/filter/internal/composite/composite_internal_test.go b/internal/filter/internal/composite/composite_internal_test.go
index ae060bb..b17068d 100644
--- a/internal/filter/internal/composite/composite_internal_test.go
+++ b/internal/filter/internal/composite/composite_internal_test.go
@@ -7,6 +7,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/filtertest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
+ "github.com/AdguardTeam/urlfilter"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
)
@@ -20,7 +21,9 @@ func BenchmarkFilter_FilterReqWithRuleLists(b *testing.B) {
)
f := New(&Config{
- RuleLists: []*rulelist.Refreshable{blockingRL},
+ URLFilterRequest: &urlfilter.DNSRequest{},
+ URLFilterResult: &urlfilter.DNSResult{},
+ RuleLists: []*rulelist.Refreshable{blockingRL},
})
ctx := context.Background()
@@ -37,9 +40,9 @@ func BenchmarkFilter_FilterReqWithRuleLists(b *testing.B) {
// Most recent results:
//
- // goos: darwin
- // goarch: amd64
- // pkg: github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/composite
- // cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
- // BenchmarkFilter_FilterReqWithRuleLists-12 760046 1336 ns/op 592 B/op 12 allocs/op
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/composite
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkFilter_FilterReqWithRuleLists-16 807964 1904 ns/op 469 B/op 8 allocs/op
}
diff --git a/internal/filter/internal/composite/composite_test.go b/internal/filter/internal/composite/composite_test.go
index da57a31..cd709f1 100644
--- a/internal/filter/internal/composite/composite_test.go
+++ b/internal/filter/internal/composite/composite_test.go
@@ -1,6 +1,7 @@
package composite_test
import (
+ "cmp"
"context"
"net/http"
"net/netip"
@@ -20,13 +21,14 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/safesearch"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
+ "github.com/AdguardTeam/urlfilter"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// newReqData returns data for calling FilterRequest. The context uses
-// [filtertest.Timeout] and [tb.Cleanup] is used for its cancelation. req uses
+// [filtertest.Timeout] and [tb.Cleanup] is used for its cancellation. req uses
// [filtertest.FQDNBlocked], [dns.TypeA], and [dns.ClassINET] for the request
// data.
func newReqData(tb testing.TB) (ctx context.Context, req *filter.Request) {
@@ -52,8 +54,20 @@ func newReqDataWithFQDN(tb testing.TB, fqdn string) (ctx context.Context, req *f
return ctx, req
}
+// newComposite is a helper for creating composite filters tests. c may be nil,
+// and all zero-value fields in c are replaced with defaults for tests.
+func newComposite(tb testing.TB, c *composite.Config) (f *composite.Filter) {
+ tb.Helper()
+
+ c = cmp.Or(c, &composite.Config{})
+ c.URLFilterRequest = cmp.Or(c.URLFilterRequest, &urlfilter.DNSRequest{})
+ c.URLFilterResult = cmp.Or(c.URLFilterResult, &urlfilter.DNSResult{})
+
+ return composite.New(c)
+}
+
func TestFilter_FilterRequest_customWithClientName(t *testing.T) {
- f := composite.New(&composite.Config{
+ f := newComposite(t, &composite.Config{
Custom: custom.New(&custom.Config{
Logger: slogutil.NewDiscardLogger(),
Rules: []filter.RuleText{
@@ -113,7 +127,7 @@ func TestFilter_FilterRequest_badfilter(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- f := composite.New(&composite.Config{
+ f := newComposite(t, &composite.Config{
RuleLists: tc.ruleLists,
})
@@ -143,7 +157,7 @@ func TestFilter_FilterRequest_customAllow(t *testing.T) {
Rules: []filter.RuleText{allowRule},
})
- f := composite.New(&composite.Config{
+ f := newComposite(t, &composite.Config{
Custom: customRL,
RuleLists: []*rulelist.Refreshable{blockingRL},
})
@@ -287,12 +301,10 @@ func TestFilter_FilterRequest_dnsrewrite(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- c := &composite.Config{
+ f := newComposite(t, &composite.Config{
Custom: tc.custom,
RuleLists: tc.ruleLists,
- }
-
- f := composite.New(c)
+ })
ctx := context.Background()
res, fltErr := f.FilterRequest(ctx, &filter.Request{
@@ -309,7 +321,7 @@ func TestFilter_FilterRequest_dnsrewrite(t *testing.T) {
}
}
-// newCustom is a helper to create a cusotm filter from a rule text.
+// newCustom is a helper to create a custom filter from a rule text.
func newCustom(tb testing.TB, text string) (f *custom.Filter) {
tb.Helper()
@@ -334,7 +346,7 @@ func TestFilter_FilterRequest_hostsRules(t *testing.T) {
)
rl := newFromStr(t, rules, filtertest.RuleListID1)
- f := composite.New(&composite.Config{
+ f := newComposite(t, &composite.Config{
RuleLists: []*rulelist.Refreshable{rl},
})
@@ -433,7 +445,7 @@ func TestFilter_FilterRequest_safeSearch(t *testing.T) {
err = gen.Refresh(testutil.ContextWithTimeout(t, filtertest.Timeout), false)
require.NoError(t, err)
- f := composite.New(&composite.Config{
+ f := newComposite(t, &composite.Config{
GeneralSafeSearch: gen,
})
@@ -458,13 +470,13 @@ func TestFilter_FilterRequest_safeSearch(t *testing.T) {
func TestFilter_FilterRequest_services(t *testing.T) {
svcRL := rulelist.NewImmutable(
- filtertest.RuleBlockStr,
+ []byte(filtertest.RuleBlockStr),
filter.IDBlockedService,
filtertest.BlockedServiceID1,
rulelist.EmptyResultCache{},
)
- f := composite.New(&composite.Config{
+ f := newComposite(t, &composite.Config{
ServiceLists: []*rulelist.Immutable{svcRL},
})
@@ -498,7 +510,7 @@ func TestFilter_FilterResponse(t *testing.T) {
)
blockingRL := newFromStr(t, blockRules, filtertest.RuleListID1)
- f := composite.New(&composite.Config{
+ f := newComposite(t, &composite.Config{
RuleLists: []*rulelist.Refreshable{blockingRL},
})
diff --git a/internal/filter/internal/composite/request.go b/internal/filter/internal/composite/request.go
new file mode 100644
index 0000000..b9f80ef
--- /dev/null
+++ b/internal/filter/internal/composite/request.go
@@ -0,0 +1,51 @@
+package composite
+
+import (
+ "context"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter"
+ "github.com/AdguardTeam/urlfilter"
+)
+
+// RequestFilter can filter a request based on the request info.
+type RequestFilter interface {
+ // FilterRequest filters a DNS request based on the information provided
+ // about the request. req must be valid.
+ FilterRequest(ctx context.Context, req *filter.Request) (r filter.Result, err error)
+}
+
+// RequestFilterUF can filter a request based on the request info and using
+// URLFilter data to optimize allocations.
+type RequestFilterUF interface {
+ // FilterRequestUF filters a DNS request based on the information provided
+ // about the request and using URLFilter data to optimize allocations. req
+ // must be valid. ufReq and ufRes must not be nil and must be reset.
+ FilterRequestUF(
+ ctx context.Context,
+ req *filter.Request,
+ ufReq *urlfilter.DNSRequest,
+ ufRes *urlfilter.DNSResult,
+ ) (r filter.Result, err error)
+}
+
+// ufRequestFilter is a wrapper around a [RequestFilterUF] that uses the
+// provided URLFilter data.
+type ufRequestFilter struct {
+ flt RequestFilterUF
+ req *urlfilter.DNSRequest
+ res *urlfilter.DNSResult
+}
+
+// type check
+var _ RequestFilter = (*ufRequestFilter)(nil)
+
+// FilterRequest implements the [RequestFilter] interface for *ufRequestFilter.
+func (f *ufRequestFilter) FilterRequest(
+ ctx context.Context,
+ req *filter.Request,
+) (r filter.Result, err error) {
+ f.req.Reset()
+ f.res.Reset()
+
+ return f.flt.FilterRequestUF(ctx, req, f.req, f.res)
+}
diff --git a/internal/filter/internal/composite/result.go b/internal/filter/internal/composite/result.go
index 72e185f..85bc697 100644
--- a/internal/filter/internal/composite/result.go
+++ b/internal/filter/internal/composite/result.go
@@ -10,10 +10,10 @@ import (
"github.com/miekg/dns"
)
-// urlFilterResult is an entity simplifying the collection and compilation of
-// urlfilter results. It contains per-pointer indexes of the IDs of filters
-// producing network and host rules.
-type urlFilterResult struct {
+// urlFilterResultCollector is an entity simplifying the collection and
+// compilation of urlfilter results. It contains per-pointer indexes of the IDs
+// of filters producing network and host rules.
+type urlFilterResultCollector struct {
netRuleIDs map[*rules.NetworkRule]filter.ID
hostRuleIDs map[*rules.HostRule]filter.ID
@@ -25,9 +25,9 @@ type urlFilterResult struct {
hostRules6 []*rules.HostRule
}
-// newURLFilterResult returns a properly initialized *urlFilterResult.
-func newURLFilterResult() (r *urlFilterResult) {
- return &urlFilterResult{
+// newURLFilterResultCollector returns a properly initialized *urlFilterResult.
+func newURLFilterResultCollector() (r *urlFilterResultCollector) {
+ return &urlFilterResultCollector{
netRuleIDs: map[*rules.NetworkRule]filter.ID{},
hostRuleIDs: map[*rules.HostRule]filter.ID{},
@@ -36,66 +36,61 @@ func newURLFilterResult() (r *urlFilterResult) {
}
}
-// add appends the rules from dr to the slices within r. If dr is nil, add does
-// nothing.
-func (r *urlFilterResult) add(
+// add appends the rules from dr to the slices within c. dr must not be nil.
+func (c *urlFilterResultCollector) add(
id filter.ID,
svcID filter.BlockedServiceID,
dr *urlfilter.DNSResult,
) {
- if dr == nil {
- return
- }
-
for _, nr := range dr.NetworkRules {
- r.networkRules = append(r.networkRules, nr)
- r.netRuleIDs[nr] = id
+ c.networkRules = append(c.networkRules, nr)
+ c.netRuleIDs[nr] = id
if svcID != "" {
- r.netRuleSvcIDs[nr] = svcID
+ c.netRuleSvcIDs[nr] = svcID
}
}
- r.addHostRules(id, svcID, dr.HostRulesV4, dr.HostRulesV6)
+ c.addHostRules(id, svcID, dr.HostRulesV4, dr.HostRulesV6)
}
// addHostRules adds the host rules to the result.
-func (r *urlFilterResult) addHostRules(
+func (c *urlFilterResultCollector) addHostRules(
id filter.ID,
svcID filter.BlockedServiceID,
hostRules4 []*rules.HostRule,
hostRules6 []*rules.HostRule,
) {
for _, hr4 := range hostRules4 {
- r.hostRules4 = append(r.hostRules4, hr4)
- r.hostRuleIDs[hr4] = id
+ c.hostRules4 = append(c.hostRules4, hr4)
+ c.hostRuleIDs[hr4] = id
if svcID != "" {
- r.hostRuleSvcIDs[hr4] = svcID
+ c.hostRuleSvcIDs[hr4] = svcID
}
}
for _, hr6 := range hostRules6 {
- r.hostRules6 = append(r.hostRules6, hr6)
- r.hostRuleIDs[hr6] = id
+ c.hostRules6 = append(c.hostRules6, hr6)
+ c.hostRuleIDs[hr6] = id
if svcID != "" {
- r.hostRuleSvcIDs[hr6] = svcID
+ c.hostRuleSvcIDs[hr6] = svcID
}
}
}
// toInternal converts a result of using several urlfilter rulelists into a
// filter.Result.
-func (r *urlFilterResult) toInternal(rrType dnsmsg.RRType) (res filter.Result) {
- if nr := rules.GetDNSBasicRule(r.networkRules); nr != nil {
- return r.netRuleDataToResult(nr)
+func (c *urlFilterResultCollector) toInternal(rrType dnsmsg.RRType) (res filter.Result) {
+ if nr := rules.GetDNSBasicRule(c.networkRules); nr != nil {
+ return c.netRuleDataToResult(nr)
}
- return r.hostsRulesToResult(rrType)
+ return c.hostsRulesToResult(rrType)
}
// netRuleDataToResult converts a urlfilter network rule into a filtering
// result.
-func (r *urlFilterResult) netRuleDataToResult(nr *rules.NetworkRule) (res filter.Result) {
- fltID, ok := r.netRuleIDs[nr]
+func (c *urlFilterResultCollector) netRuleDataToResult(nr *rules.NetworkRule) (res filter.Result) {
+ fltID, ok := c.netRuleIDs[nr]
if !ok {
// Shouldn't happen, since fltID is supposed to be among the filters
// added to the result.
@@ -105,7 +100,7 @@ func (r *urlFilterResult) netRuleDataToResult(nr *rules.NetworkRule) (res filter
var rule filter.RuleText
if fltID == filter.IDBlockedService {
var svcID filter.BlockedServiceID
- svcID, ok = r.netRuleSvcIDs[nr]
+ svcID, ok = c.netRuleSvcIDs[nr]
if !ok {
// Shouldn't happen, since svcID is supposed to be among the filters
// added to the result.
@@ -131,8 +126,8 @@ func (r *urlFilterResult) netRuleDataToResult(nr *rules.NetworkRule) (res filter
}
// hostsRulesToResult converts /etc/hosts-style rules into a filtering result.
-func (r *urlFilterResult) hostsRulesToResult(rrType dnsmsg.RRType) (res filter.Result) {
- if len(r.hostRules4) == 0 && len(r.hostRules6) == 0 {
+func (c *urlFilterResultCollector) hostsRulesToResult(rrType dnsmsg.RRType) (res filter.Result) {
+ if len(c.hostRules4) == 0 && len(c.hostRules6) == 0 {
return nil
}
@@ -143,24 +138,24 @@ func (r *urlFilterResult) hostsRulesToResult(rrType dnsmsg.RRType) (res filter.R
//
// See also AGDNS-591.
var resHostRule *rules.HostRule
- if rrType == dns.TypeA && len(r.hostRules4) > 0 {
- resHostRule = r.hostRules4[0]
- } else if rrType == dns.TypeAAAA && len(r.hostRules6) > 0 {
- resHostRule = r.hostRules6[0]
+ if rrType == dns.TypeA && len(c.hostRules4) > 0 {
+ resHostRule = c.hostRules4[0]
+ } else if rrType == dns.TypeAAAA && len(c.hostRules6) > 0 {
+ resHostRule = c.hostRules6[0]
} else {
- if len(r.hostRules4) > 0 {
- resHostRule = r.hostRules4[0]
+ if len(c.hostRules4) > 0 {
+ resHostRule = c.hostRules4[0]
} else {
- resHostRule = r.hostRules6[0]
+ resHostRule = c.hostRules6[0]
}
}
- return r.hostRuleDataToResult(resHostRule)
+ return c.hostRuleDataToResult(resHostRule)
}
// hostRuleDataToResult converts a urlfilter host rule into a filtering result.
-func (r *urlFilterResult) hostRuleDataToResult(hr *rules.HostRule) (res filter.Result) {
- fltID, ok := r.hostRuleIDs[hr]
+func (c *urlFilterResultCollector) hostRuleDataToResult(hr *rules.HostRule) (res filter.Result) {
+ fltID, ok := c.hostRuleIDs[hr]
if !ok {
// Shouldn't happen, since fltID is supposed to be among the filters
// added to the result.
@@ -170,7 +165,7 @@ func (r *urlFilterResult) hostRuleDataToResult(hr *rules.HostRule) (res filter.R
var rule filter.RuleText
if fltID == filter.IDBlockedService {
var svcID filter.BlockedServiceID
- svcID, ok = r.hostRuleSvcIDs[hr]
+ svcID, ok = c.hostRuleSvcIDs[hr]
if !ok {
// Shouldn't happen, since svcID is supposed to be among the filters
// added to the result.
diff --git a/internal/filter/internal/filtertest/hashprefix.go b/internal/filter/internal/filtertest/hashprefix.go
index 0ee1052..242e523 100644
--- a/internal/filter/internal/filtertest/hashprefix.go
+++ b/internal/filter/internal/filtertest/hashprefix.go
@@ -58,7 +58,7 @@ func NewHashprefixFilterWithRepl(
cachePath, srvURL := PrepareRefreshable(tb, nil, data, http.StatusOK)
- strg, err := hashprefix.NewStorage("")
+ strg, err := hashprefix.NewStorage(nil)
require.NoError(tb, err)
f, err = hashprefix.NewFilter(&hashprefix.FilterConfig{
diff --git a/internal/filter/internal/filtertest/refresh.go b/internal/filter/internal/filtertest/refresh.go
index ddc9eb1..b76e3d0 100644
--- a/internal/filter/internal/filtertest/refresh.go
+++ b/internal/filter/internal/filtertest/refresh.go
@@ -19,6 +19,8 @@ import (
// as well as creates a cache file. If reqCh not nil, a signal is sent every
// time the server is called. The server uses [ServerName] as the value of the
// Server header.
+//
+// TODO(a.garipov): Rewrite to use []byte for text.
func PrepareRefreshable(
tb testing.TB,
reqCh chan<- struct{},
diff --git a/internal/filter/internal/refreshable/refreshable.go b/internal/filter/internal/refreshable/refreshable.go
index a728630..3be9f57 100644
--- a/internal/filter/internal/refreshable/refreshable.go
+++ b/internal/filter/internal/refreshable/refreshable.go
@@ -2,6 +2,7 @@
package refreshable
import (
+ "bytes"
"context"
"fmt"
"io"
@@ -26,6 +27,8 @@ import (
// Refreshable contains the logic common to filters and indexes that can refresh
// themselves from a file and a URL.
+//
+// TODO(a.garipov, e.burkov): Move to golibs.
type Refreshable struct {
logger *slog.Logger
http *agdhttp.Client
@@ -48,20 +51,26 @@ type Config struct {
// ID is the filter list ID for this filter.
ID filter.ID
- // CachePath is the path to the file containing the cached data.
+ // CachePath is the path to the file containing the cached data. It only
+ // used for non-file URLs.
CachePath string
- // Staleness is the time after which a file is considered stale.
+ // Staleness is the time after which a file is considered stale. It should
+ // be positive, otherwise any cache will be discarded.
Staleness time.Duration
- // Timeout is the timeout for the HTTP client used by this refreshable.
+ // Timeout is the timeout for the HTTP client used by this refreshable. It
+ // must be positive, if the non-file URL is used.
Timeout time.Duration
- // MaxSize is the maximum size of the downloadable data.
+ // MaxSize is the maximum size of the downloadable data. It must be
+ // positive, if the non-file URL is used.
MaxSize datasize.ByteSize
}
// New returns a new refreshable. c must not be nil.
+//
+// TODO(e.burkov): Consider validating c more thoroughly.
func New(c *Config) (f *Refreshable, err error) {
if c.URL == nil {
return nil, fmt.Errorf("refreshable.New: nil url for refreshable with ID %q", c.ID)
@@ -87,31 +96,31 @@ func New(c *Config) (f *Refreshable, err error) {
// load the data from its URL when there is already a file in the cache
// directory, regardless of its staleness.
//
-// TODO(a.garipov): Consider making refresh return a reader instead of a string.
-func (f *Refreshable) Refresh(ctx context.Context, acceptStale bool) (text string, err error) {
+// TODO(a.garipov): Consider making refresh return a reader instead of bytes.
+func (f *Refreshable) Refresh(ctx context.Context, acceptStale bool) (b []byte, err error) {
defer func() { err = errors.Annotate(err, "%s: %w", f.id) }()
if strings.EqualFold(f.url.Scheme, urlutil.SchemeFile) {
- text, err = f.refreshFromFileOnly(ctx)
+ b, err = f.refreshFromFileOnly(ctx)
} else {
- text, err = f.useCachedOrRefreshFromURL(ctx, acceptStale)
+ b, err = f.useCachedOrRefreshFromURL(ctx, acceptStale)
}
- return text, err
+ return b, err
}
// refreshFromFileOnly refreshes from the file in the URL. It must only be
// called when the URL of this refreshable is a file URI.
-func (f *Refreshable) refreshFromFileOnly(ctx context.Context) (text string, err error) {
+func (f *Refreshable) refreshFromFileOnly(ctx context.Context) (b []byte, err error) {
filePath := f.url.Path
f.logger.InfoContext(ctx, "using data from file", "path", filePath)
- text, err = f.refreshFromFile(true, filePath, time.Time{})
+ b, err = f.refreshFromFile(true, filePath, time.Time{})
if err != nil {
- return "", fmt.Errorf("refreshing from file %q: %w", filePath, err)
+ return nil, fmt.Errorf("refreshing from file %q: %w", filePath, err)
}
- return text, nil
+ return b, nil
}
// useCachedOrRefreshFromURL reloads the data from the cache file or the http
@@ -122,46 +131,47 @@ func (f *Refreshable) refreshFromFileOnly(ctx context.Context) (text string, err
func (f *Refreshable) useCachedOrRefreshFromURL(
ctx context.Context,
acceptStale bool,
-) (text string, err error) {
+) (b []byte, err error) {
+ // TODO(e.burkov): Add [timeutil.Clock].
now := time.Now()
- text, err = f.refreshFromFile(acceptStale, f.cachePath, now)
+ b, err = f.refreshFromFile(acceptStale, f.cachePath, now)
if err != nil {
- return "", fmt.Errorf("refreshing from cache file %q: %w", f.cachePath, err)
+ return nil, fmt.Errorf("refreshing from cache file %q: %w", f.cachePath, err)
}
- if text == "" {
+ if len(b) == 0 {
ru := urlutil.RedactUserinfo(f.url)
f.logger.InfoContext(ctx, "refreshing from url", "url", ru)
- text, err = f.refreshFromURL(ctx, now)
+ b, err = f.refreshFromURL(ctx, now)
if err != nil {
- return "", fmt.Errorf("refreshing from url %q: %w", ru, err)
+ return nil, fmt.Errorf("refreshing from url %q: %w", ru, err)
}
} else {
f.logger.InfoContext(ctx, "using cached data from file", "path", f.cachePath)
}
- return text, nil
+ return b, nil
}
// refreshFromFile loads data from filePath if the file's mtime shows that it's
// still fresh relative to updTime. If acceptStale is true, and the file
-// exists, the data is read from there regardless of its staleness. If err is
-// nil and text is empty, a refresh from a URL is required.
+// exists, the data is read from there regardless of its staleness. If both b
+// and err are nil, a refresh from a URL is required.
func (f *Refreshable) refreshFromFile(
acceptStale bool,
filePath string,
updTime time.Time,
-) (text string, err error) {
+) (b []byte, err error) {
// #nosec G304 -- Assume that filePath is always either cacheDir + a valid,
// no-slash ID or a path from the index env.
file, err := os.Open(filePath)
if errors.Is(err, os.ErrNotExist) {
// File does not exist. Refresh from the URL.
- return "", nil
+ return nil, nil
} else if err != nil {
- return "", fmt.Errorf("opening refreshable file: %w", err)
+ return nil, fmt.Errorf("opening refreshable file: %w", err)
}
defer func() { err = errors.WithDeferred(err, file.Close()) }()
@@ -169,21 +179,21 @@ func (f *Refreshable) refreshFromFile(
var fi fs.FileInfo
fi, err = file.Stat()
if err != nil {
- return "", fmt.Errorf("reading refreshable file stat: %w", err)
+ return nil, fmt.Errorf("reading refreshable file stat: %w", err)
}
if mtime := fi.ModTime(); !mtime.Add(f.staleness).After(updTime) {
- return "", nil
+ return nil, nil
}
}
- b := &strings.Builder{}
- _, err = io.Copy(b, file)
+ // Consider cache files to be of a prevalidated size.
+ b, err = io.ReadAll(file)
if err != nil {
- return "", fmt.Errorf("reading refreshable file: %w", err)
+ return nil, fmt.Errorf("reading refreshable file: %w", err)
}
- return b.String(), nil
+ return b, nil
}
// refreshFromURL loads the data from u, puts it into the file specified by
@@ -191,18 +201,18 @@ func (f *Refreshable) refreshFromFile(
func (f *Refreshable) refreshFromURL(
ctx context.Context,
updTime time.Time,
-) (text string, err error) {
+) (b []byte, err error) {
// TODO(a.garipov): Cache these like renameio recommends.
tmpDir := renameio.TempDir(filepath.Dir(f.cachePath))
tmpFile, err := renameio.TempFile(tmpDir, f.cachePath)
if err != nil {
- return "", fmt.Errorf("creating temporary refreshable file: %w", err)
+ return nil, fmt.Errorf("creating temporary refreshable file: %w", err)
}
defer func() { err = f.withDeferredTmpCleanup(err, tmpFile, updTime) }()
resp, err := f.http.Get(ctx, f.url)
if err != nil {
- return "", fmt.Errorf("requesting: %w", err)
+ return nil, fmt.Errorf("requesting: %w", err)
}
defer func() { err = errors.WithDeferred(err, resp.Body.Close()) }()
@@ -218,24 +228,24 @@ func (f *Refreshable) refreshFromURL(
err = agdhttp.CheckStatus(resp, http.StatusOK)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
- return "", err
+ return nil, err
}
- b := &strings.Builder{}
- mw := io.MultiWriter(b, tmpFile)
+ buf := &bytes.Buffer{}
+ mw := io.MultiWriter(buf, tmpFile)
_, err = io.Copy(mw, ioutil.LimitReader(resp.Body, f.maxSize.Bytes()))
if err != nil {
- return "", agdhttp.WrapServerError(fmt.Errorf("reading into file: %w", err), resp)
+ return nil, agdhttp.WrapServerError(fmt.Errorf("reading into file: %w", err), resp)
}
// TODO(a.garipov): Make a more sophisticated data size ratio check.
//
// See AGDNS-598.
- if b.Len() == 0 {
- return "", agdhttp.WrapServerError(errors.Error("empty text, not resetting"), resp)
+ if buf.Len() == 0 {
+ return nil, agdhttp.WrapServerError(errors.Error("empty text, not resetting"), resp)
}
- return b.String(), nil
+ return buf.Bytes(), nil
}
// withDeferredTmpCleanup is a helper that performs the necessary cleanups and
diff --git a/internal/filter/internal/refreshable/refreshable_test.go b/internal/filter/internal/refreshable/refreshable_test.go
index 0717912..fb8e8d1 100644
--- a/internal/filter/internal/refreshable/refreshable_test.go
+++ b/internal/filter/internal/refreshable/refreshable_test.go
@@ -23,16 +23,22 @@ const refrID = "test_id"
// Default texts for tests.
const (
- testFileText = "||filefilter.example\n"
- testURLText = "||urlfilter.example\n"
+ testTextFile = "||filefilter.example\n"
+ testTextURL = "||urlfilter.example\n"
+)
+
+// Byte versions of default texts for tests.
+var (
+ testTextFileData = []byte(testTextFile)
+ testTextURLData = []byte(testTextURL)
)
func TestRefreshable_Refresh(t *testing.T) {
testCases := []struct {
name string
- wantText string
wantErrMsg string
srvText string
+ wantData []byte
staleness time.Duration
srvCode int
acceptStale bool
@@ -40,32 +46,32 @@ func TestRefreshable_Refresh(t *testing.T) {
useCacheFile bool
}{{
name: "no_file",
- wantText: testURLText,
wantErrMsg: "",
- srvText: testURLText,
+ srvText: testTextURL,
+ wantData: testTextURLData,
staleness: 0,
srvCode: http.StatusOK,
acceptStale: true,
expectReq: true,
useCacheFile: false,
}, {
- name: "no_file_http_empty",
- wantText: "",
+ name: "no_file_http_empty",
wantErrMsg: refrID + `: refreshing from url "URL": ` +
`server "` + filtertest.ServerName + `": empty text, not resetting`,
srvText: "",
+ wantData: nil,
staleness: 0,
srvCode: http.StatusOK,
acceptStale: true,
expectReq: true,
useCacheFile: false,
}, {
- name: "no_file_http_error",
- wantText: "",
+ name: "no_file_http_error",
wantErrMsg: refrID + `: refreshing from url "URL": ` +
`server "` + filtertest.ServerName + `": ` +
`status code error: expected 200, got 500`,
srvText: "internal server error",
+ wantData: nil,
staleness: 0,
srvCode: http.StatusInternalServerError,
acceptStale: true,
@@ -73,9 +79,9 @@ func TestRefreshable_Refresh(t *testing.T) {
useCacheFile: false,
}, {
name: "file",
- wantText: testFileText,
wantErrMsg: "",
srvText: "",
+ wantData: testTextFileData,
staleness: filtertest.Staleness,
srvCode: http.StatusOK,
acceptStale: true,
@@ -83,9 +89,9 @@ func TestRefreshable_Refresh(t *testing.T) {
useCacheFile: true,
}, {
name: "file_stale",
- wantText: testURLText,
wantErrMsg: "",
- srvText: testURLText,
+ srvText: testTextURL,
+ wantData: testTextURLData,
staleness: -1 * time.Hour,
srvCode: http.StatusOK,
acceptStale: false,
@@ -93,9 +99,9 @@ func TestRefreshable_Refresh(t *testing.T) {
useCacheFile: true,
}, {
name: "file_stale_accept",
- wantText: testFileText,
wantErrMsg: "",
srvText: "",
+ wantData: testTextFileData,
staleness: -1 * time.Hour,
srvCode: http.StatusOK,
acceptStale: true,
@@ -123,7 +129,7 @@ func TestRefreshable_Refresh(t *testing.T) {
require.NoError(t, err)
ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
- gotText, err := f.Refresh(ctx, tc.acceptStale)
+ gotData, err := f.Refresh(ctx, tc.acceptStale)
if tc.expectReq {
testutil.RequireReceive(t, reqCh, filtertest.Timeout)
}
@@ -135,7 +141,7 @@ func TestRefreshable_Refresh(t *testing.T) {
}
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
- assert.Equal(t, tc.wantText, gotText)
+ assert.Equal(t, tc.wantData, gotData)
})
}
}
@@ -150,7 +156,7 @@ func prepareCachePath(t *testing.T, realCachePath string, useCacheFile bool) (ca
return filepath.Join(t.TempDir(), "does_not_exist")
}
- err := os.WriteFile(realCachePath, []byte(testFileText), 0o600)
+ err := os.WriteFile(realCachePath, testTextFileData, 0o600)
require.NoError(t, err)
return realCachePath
@@ -218,7 +224,7 @@ func TestRefreshable_Refresh_fileURL(t *testing.T) {
fltFile, err := os.CreateTemp(dir, filepath.Base(t.Name()))
require.NoError(t, err)
- _, err = fltFile.WriteString(testFileText)
+ _, err = fltFile.Write(testTextFileData)
require.NoError(t, err)
require.NoError(t, fltFile.Close())
@@ -240,8 +246,8 @@ func TestRefreshable_Refresh_fileURL(t *testing.T) {
require.NoError(t, err)
ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
- text, err := f.Refresh(ctx, true)
+ b, err := f.Refresh(ctx, true)
require.NoError(t, err)
- assert.Equal(t, testFileText, text)
+ assert.Equal(t, testTextFileData, b)
}
diff --git a/internal/filter/internal/rulelist/cache.go b/internal/filter/internal/rulelist/cache.go
index 55acc4c..d45fb8c 100644
--- a/internal/filter/internal/rulelist/cache.go
+++ b/internal/filter/internal/rulelist/cache.go
@@ -1,65 +1,38 @@
package rulelist
import (
- "encoding/binary"
- "hash/maphash"
-
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
- "github.com/AdguardTeam/golibs/mathutil"
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/timeutil"
"github.com/AdguardTeam/urlfilter"
)
-// CacheKey is the cache key type for [NewCacheKey].
-type CacheKey uint64
-
-// hashSeed is the seed used by all hashes to create hash keys.
-var hashSeed = maphash.MakeSeed()
-
-// NewCacheKey produces a cache key based on the arguments using default
-// algorithm.
-func NewCacheKey(host string, qt dnsmsg.RRType, cl dnsmsg.Class, isAns bool) (k CacheKey) {
- // Use maphash explicitly instead of using a key structure to reduce
- // allocations and optimize interface conversion up the stack.
- h := &maphash.Hash{}
- h.SetSeed(hashSeed)
-
- _, _ = h.WriteString(host)
-
- // Save on allocations by reusing a buffer.
- var buf [5]byte
- binary.LittleEndian.PutUint16(buf[:2], qt)
- binary.LittleEndian.PutUint16(buf[2:4], cl)
- buf[4] = mathutil.BoolToNumber[byte](isAns)
-
- _, _ = h.Write(buf[:])
-
- return CacheKey(h.Sum64())
-}
-
type (
// ResultCache is a convenient alias for cache to keep types in check.
- ResultCache = agdcache.Interface[CacheKey, *CacheItem]
+ ResultCache = agdcache.Interface[CacheKey, *urlfilter.DNSResult]
// EmptyResultCache is a convenient alias for empty cache to keep types in
// check. See [filter.DNSResult].
- EmptyResultCache = agdcache.Empty[CacheKey, *CacheItem]
+ EmptyResultCache = agdcache.Empty[CacheKey, *urlfilter.DNSResult]
)
// NewResultCache returns a new initialized cache with the given element count.
-// If useCache is false, it returns a cache implementation that does nothing.
+// If useCache is true, count must be positive. If useCache is false, it
+// returns a cache implementation that does nothing.
func NewResultCache(count int, useCache bool) (cache ResultCache) {
if !useCache {
return EmptyResultCache{}
}
- return agdcache.NewLRU[CacheKey, *CacheItem](&agdcache.LRUConfig{
+ return errors.Must(agdcache.New[CacheKey, *urlfilter.DNSResult](&agdcache.Config{
+ Clock: timeutil.SystemClock{},
Count: count,
- })
+ }))
}
// NewManagedResultCache is like [NewResultCache] but it also adds a newly
-// created cache to the cache manager by id.
+// created cache to the cache manager by id. count must be positive.
func NewManagedResultCache(
m agdcache.Manager,
id string,
@@ -72,29 +45,29 @@ func NewManagedResultCache(
return cache
}
-// CacheItem is an item stored in a [ResultCache].
-type CacheItem struct {
- // res is the DNS filtering result.
- res *urlfilter.DNSResult
-
- // host is the cached normalized hostname for later cache key collision
- // checks.
+// CacheKey represents a key used in the cache.
+type CacheKey struct {
+ // host is a non-FQDN version of a cached hostname.
host string
+
+ // qType is the question type of the DNS request.
+ qType uint16
+
+ // qClass is the class of the DNS request.
+ qClass uint16
+
+ // isAns is true if the request is an answer.
+ isAns bool
}
-// itemFromCache retrieves a cache item for the given key. host is used to
-// detect key collisions. If there is a key collision, it returns nil and
-// false.
-func itemFromCache(cache ResultCache, key CacheKey, host string) (item *CacheItem, ok bool) {
- item, ok = cache.Get(key)
- if !ok {
- return nil, false
+// NewCacheKey creates a new cache key for the given parameters.
+func NewCacheKey(host string, qt dnsmsg.RRType, cl dnsmsg.Class, isAns bool) (key CacheKey) {
+ key = CacheKey{
+ host: host,
+ qType: qt,
+ qClass: cl,
+ isAns: isAns,
}
- if item.host != host {
- // Cache collision.
- return nil, false
- }
-
- return item, true
+ return key
}
diff --git a/internal/filter/internal/rulelist/dnsrewrite.go b/internal/filter/internal/rulelist/dnsrewrite.go
index 6b5acfe..bfc6bec 100644
--- a/internal/filter/internal/rulelist/dnsrewrite.go
+++ b/internal/filter/internal/rulelist/dnsrewrite.go
@@ -81,6 +81,8 @@ type dnsRewriteResultResponse map[rules.RRType][]rules.RRValue
// processDNSRewriteRules processes DNS rewrite rules in dnsr. The result will
// have either CanonName or RCode or Response set.
+//
+// TODO(a.garipov): Reuse dnsRewriteResult structures.
func processDNSRewriteRules(dnsr []*rules.NetworkRule) (res *dnsRewriteResult) {
dnsrr := &dnsRewriteResult{
Response: dnsRewriteResultResponse{},
diff --git a/internal/filter/internal/rulelist/immutable.go b/internal/filter/internal/rulelist/immutable.go
index f8c3f1b..052135a 100644
--- a/internal/filter/internal/rulelist/immutable.go
+++ b/internal/filter/internal/rulelist/immutable.go
@@ -21,12 +21,12 @@ type Immutable struct {
// NewImmutable returns a new immutable DNS request and response filter using
// the provided rule text and IDs.
func NewImmutable(
- text string,
+ rulesData []byte,
id filter.ID,
svcID filter.BlockedServiceID,
cache ResultCache,
) (f *Immutable) {
return &Immutable{
- baseFilter: newBaseFilter(text, id, svcID, cache),
+ baseFilter: newBaseFilter(rulesData, id, svcID, cache),
}
}
diff --git a/internal/filter/internal/rulelist/refreshable.go b/internal/filter/internal/rulelist/refreshable.go
index c7768d6..0b152f5 100644
--- a/internal/filter/internal/rulelist/refreshable.go
+++ b/internal/filter/internal/rulelist/refreshable.go
@@ -4,11 +4,9 @@ import (
"context"
"fmt"
"log/slog"
- "net/netip"
"strings"
"sync"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/refreshable"
"github.com/AdguardTeam/golibs/netutil/urlutil"
@@ -42,7 +40,7 @@ type Refreshable struct {
// HTTP(S) URL. The initial refresh should be called explicitly if necessary.
func NewRefreshable(c *refreshable.Config, cache ResultCache) (f *Refreshable, err error) {
f = &Refreshable{
- baseFilter: newBaseFilter("", c.ID, "", cache),
+ baseFilter: newBaseFilter(nil, c.ID, "", cache),
logger: c.Logger,
mu: &sync.RWMutex{},
}
@@ -72,49 +70,49 @@ func NewRefreshable(c *refreshable.Config, cache ResultCache) (f *Refreshable, e
//
// TODO(a.garipov): Only used in tests. Consider removing later.
func NewFromString(
- text string,
+ rulesData string,
id filter.ID,
svcID filter.BlockedServiceID,
cache ResultCache,
) (f *Refreshable) {
return &Refreshable{
mu: &sync.RWMutex{},
- baseFilter: newBaseFilter(text, id, svcID, cache),
+ baseFilter: newBaseFilter([]byte(rulesData), id, svcID, cache),
}
}
-// DNSResult returns the result of applying the urlfilter DNS filtering engine.
-// If the request is not filtered, DNSResult returns nil.
-func (f *Refreshable) DNSResult(
- clientIP netip.Addr,
- clientName string,
- host string,
- rrType dnsmsg.RRType,
- isAns bool,
-) (res *urlfilter.DNSResult) {
+// SetURLFilterResult applies the DNS filtering engine and sets the values in
+// res if any have matched. ok is true if there is a match. req and res must
+// not be nil.
+func (f *Refreshable) SetURLFilterResult(
+ ctx context.Context,
+ req *urlfilter.DNSRequest,
+ res *urlfilter.DNSResult,
+) (ok bool) {
f.mu.RLock()
defer f.mu.RUnlock()
- return f.baseFilter.DNSResult(clientIP, clientName, host, rrType, isAns)
+ return f.baseFilter.SetURLFilterResult(ctx, req, res)
}
// Refresh reloads the rule list data. If acceptStale is true, do not try to
// load the list from its URL when there is already a file in the cache
// directory, regardless of its staleness.
func (f *Refreshable) Refresh(ctx context.Context, acceptStale bool) (err error) {
- text, err := f.refr.Refresh(ctx, acceptStale)
+ rulesData, err := f.refr.Refresh(ctx, acceptStale)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
}
- // TODO(a.garipov): Add filterlist.BytesRuleList.
- strList := &filterlist.StringRuleList{
- RulesText: text,
- IgnoreCosmetic: true,
+ lists := []filterlist.Interface{
+ filterlist.NewBytes(&filterlist.BytesConfig{
+ RulesText: rulesData,
+ IgnoreCosmetic: true,
+ }),
}
- s, err := filterlist.NewRuleStorage([]filterlist.RuleList{strList})
+ s, err := filterlist.NewRuleStorage(lists)
if err != nil {
return fmt.Errorf("%s: creating rule storage: %w", f.id, err)
}
diff --git a/internal/filter/internal/rulelist/refreshable_test.go b/internal/filter/internal/rulelist/refreshable_test.go
index 4f80c83..219c772 100644
--- a/internal/filter/internal/rulelist/refreshable_test.go
+++ b/internal/filter/internal/rulelist/refreshable_test.go
@@ -2,83 +2,99 @@ package rulelist_test
import (
"net/http"
- "net/netip"
"testing"
- "github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/filtertest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/refreshable"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
+ "github.com/AdguardTeam/urlfilter"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-// testReqHost is the request host for tests.
-const testReqHost = "blocked.example"
-
-// testRemoteIP is the client IP for tests
-var testRemoteIP = netip.MustParseAddr("1.2.3.4")
-
-// testFltListID is the common filter list IDs for tests.
-const testFltListID filter.ID = "fl1"
-
-// testBlockRule is the common blocking rule for tests.
-const testBlockRule = "||" + testReqHost + "\n"
-
func TestRefreshable_RulesCount(t *testing.T) {
- rl := rulelist.NewFromString(testBlockRule, testFltListID, "", rulelist.EmptyResultCache{})
+ rl := rulelist.NewFromString(
+ filtertest.RuleBlockStr,
+ filtertest.RuleListID1,
+ "",
+ rulelist.EmptyResultCache{},
+ )
assert.Equal(t, 1, rl.RulesCount())
}
-func TestRefreshable_DNSResult_cache(t *testing.T) {
+func TestRefreshable_SetURLFilterResult_cache(t *testing.T) {
cache := rulelist.NewResultCache(filtertest.CacheCount, true)
- rl := rulelist.NewFromString(testBlockRule, testFltListID, "", cache)
+ rl := rulelist.NewFromString(filtertest.RuleBlockStr, filtertest.RuleListID1, "", cache)
- const qt = dns.TypeA
+ require.True(t, t.Run("blocked", func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+ req := &urlfilter.DNSRequest{
+ ClientIP: filtertest.IPv4Client,
+ Hostname: filtertest.HostBlocked,
+ DNSType: dns.TypeA,
+ }
+ res := &urlfilter.DNSResult{}
- t.Run("blocked", func(t *testing.T) {
- dr := rl.DNSResult(testRemoteIP, "", testReqHost, qt, false)
- require.NotNil(t, dr)
+ ok := rl.SetURLFilterResult(ctx, req, res)
+ require.True(t, ok)
- assert.Len(t, dr.NetworkRules, 1)
+ assert.Len(t, res.NetworkRules, 1)
+ r := res.NetworkRules[0]
- cachedDR := rl.DNSResult(testRemoteIP, "", testReqHost, qt, false)
- require.NotNil(t, cachedDR)
+ res.Reset()
+ ok = rl.SetURLFilterResult(ctx, req, res)
+ require.True(t, ok)
- assert.Same(t, dr, cachedDR)
- })
+ assert.Same(t, r, res.NetworkRules[0])
+ }))
- t.Run("none", func(t *testing.T) {
- const otherHost = "other.example"
+ require.True(t, t.Run("none", func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+ req := &urlfilter.DNSRequest{
+ ClientIP: filtertest.IPv4Client,
+ Hostname: filtertest.Host,
+ DNSType: dns.TypeA,
+ }
+ res := &urlfilter.DNSResult{}
- dr := rl.DNSResult(testRemoteIP, "", otherHost, qt, false)
- assert.Nil(t, dr)
+ ok := rl.SetURLFilterResult(ctx, req, res)
+ assert.False(t, ok)
- cachedDR := rl.DNSResult(testRemoteIP, "", otherHost, dns.TypeA, false)
- assert.Nil(t, cachedDR)
- })
+ res.Reset()
+ ok = rl.SetURLFilterResult(ctx, req, res)
+ assert.False(t, ok)
+ }))
}
func TestRefreshable_ID(t *testing.T) {
- const svcID = filter.BlockedServiceID("test_service")
- rl := rulelist.NewFromString(testBlockRule, testFltListID, svcID, rulelist.EmptyResultCache{})
+ rl := rulelist.NewFromString(
+ filtertest.RuleBlockStr,
+ filtertest.RuleListID1,
+ filtertest.BlockedServiceID1Str,
+ rulelist.EmptyResultCache{},
+ )
gotID, gotSvcID := rl.ID()
- assert.Equal(t, testFltListID, gotID)
- assert.Equal(t, svcID, gotSvcID)
+ assert.Equal(t, filtertest.RuleListID1, gotID)
+ assert.Equal(t, filtertest.BlockedServiceID1, gotSvcID)
}
func TestRefreshable_Refresh(t *testing.T) {
- cachePath, srvURL := filtertest.PrepareRefreshable(t, nil, testBlockRule, http.StatusOK)
+ cachePath, srvURL := filtertest.PrepareRefreshable(
+ t,
+ nil,
+ filtertest.RuleBlockStr,
+ http.StatusOK,
+ )
rl, err := rulelist.NewRefreshable(
&refreshable.Config{
Logger: slogutil.NewDiscardLogger(),
URL: srvURL,
- ID: testFltListID,
+ ID: filtertest.RuleListID1,
CachePath: cachePath,
Staleness: filtertest.Staleness,
MaxSize: filtertest.FilterMaxSize,
@@ -93,8 +109,71 @@ func TestRefreshable_Refresh(t *testing.T) {
assert.Equal(t, 1, rl.RulesCount())
- dr := rl.DNSResult(testRemoteIP, "", testReqHost, dns.TypeA, false)
- require.NotNil(t, dr)
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
+ req := &urlfilter.DNSRequest{
+ ClientIP: filtertest.IPv4Client,
+ Hostname: filtertest.HostBlocked,
+ DNSType: dns.TypeA,
+ }
+ res := &urlfilter.DNSResult{}
- assert.Len(t, dr.NetworkRules, 1)
+ ok := rl.SetURLFilterResult(ctx, req, res)
+ require.True(t, ok)
+
+ assert.Len(t, res.NetworkRules, 1)
+}
+
+func BenchmarkRefreshable_SetURLFilterResult(b *testing.B) {
+ rl := rulelist.NewFromString(
+ filtertest.RuleBlockStr,
+ filtertest.RuleListID1,
+ "",
+ rulelist.EmptyResultCache{},
+ )
+
+ ctx := testutil.ContextWithTimeout(b, filtertest.Timeout)
+ res := &urlfilter.DNSResult{}
+
+ b.Run("blocked", func(b *testing.B) {
+ req := &urlfilter.DNSRequest{
+ ClientIP: filtertest.IPv4Client,
+ Hostname: filtertest.HostBlocked,
+ DNSType: dns.TypeA,
+ }
+
+ var ok bool
+ b.ReportAllocs()
+ for b.Loop() {
+ res.Reset()
+ ok = rl.SetURLFilterResult(ctx, req, res)
+ }
+
+ require.True(b, ok)
+ })
+
+ b.Run("other", func(b *testing.B) {
+ req := &urlfilter.DNSRequest{
+ ClientIP: filtertest.IPv4Client,
+ Hostname: filtertest.Host,
+ DNSType: dns.TypeA,
+ }
+
+ var ok bool
+ b.ReportAllocs()
+ for b.Loop() {
+ res.Reset()
+ ok = rl.SetURLFilterResult(ctx, req, res)
+ }
+
+ require.False(b, ok)
+ })
+
+ // Most recent results:
+ //
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkRefreshable_SetURLFilterResult/blocked-16 1340384 918.6 ns/op 24 B/op 1 allocs/op
+ // BenchmarkRefreshable_SetURLFilterResult/other-16 2127038 589.3 ns/op 24 B/op 1 allocs/op
}
diff --git a/internal/filter/internal/rulelist/rulelist.go b/internal/filter/internal/rulelist/rulelist.go
index 009fa97..d4740d3 100644
--- a/internal/filter/internal/rulelist/rulelist.go
+++ b/internal/filter/internal/rulelist/rulelist.go
@@ -3,10 +3,9 @@
package rulelist
import (
+ "context"
"fmt"
- "net/netip"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist"
@@ -18,8 +17,8 @@ import (
type baseFilter struct {
// engine is the DNS filtering engine.
//
- // NOTE: Do not save the [filterlist.RuleList] used to create the engine to
- // close it, because filter exclusively uses [filterlist.StringRuleList],
+ // NOTE: Do not save the [filterlist.Interface] used to create the engine
+ // to close it, because filter exclusively uses [filterlist.StringRuleList],
// which doesn't require closing.
engine *urlfilter.DNSEngine
@@ -38,7 +37,7 @@ type baseFilter struct {
// newBaseFilter returns a new base DNS request and response filter using the
// provided rule text and IDs.
func newBaseFilter(
- text string,
+ rulesData []byte,
id filter.ID,
svcID filter.BlockedServiceID,
cache ResultCache,
@@ -49,13 +48,14 @@ func newBaseFilter(
svcID: svcID,
}
- // TODO(a.garipov): Add filterlist.BytesRuleList.
- strList := &filterlist.StringRuleList{
- RulesText: text,
- IgnoreCosmetic: true,
+ lists := []filterlist.Interface{
+ filterlist.NewBytes(&filterlist.BytesConfig{
+ RulesText: rulesData,
+ IgnoreCosmetic: true,
+ }),
}
- s, err := filterlist.NewRuleStorage([]filterlist.RuleList{strList})
+ s, err := filterlist.NewRuleStorage(lists)
if err != nil {
// Should never happen, there is only one filter list, and the only
// error that is currently returned from [filterlist.NewRuleStorage] is
@@ -73,50 +73,61 @@ func newBaseFilter(
return f
}
-// DNSResult returns the result of applying the urlfilter DNS filtering engine.
-// If the request is not filtered, DNSResult returns nil.
-func (f *baseFilter) DNSResult(
- clientIP netip.Addr,
- clientName string,
- host string,
- rrType dnsmsg.RRType,
- isAns bool,
-) (res *urlfilter.DNSResult) {
- var ok bool
+// SetURLFilterResult applies the DNS filtering engine and sets the values in
+// res if any have matched. ok is true if there is a match. req and res must
+// not be nil.
+func (f *baseFilter) SetURLFilterResult(
+ _ context.Context,
+ req *urlfilter.DNSRequest,
+ res *urlfilter.DNSResult,
+) (ok bool) {
var cacheKey CacheKey
- var item *CacheItem
+ var cachedRes *urlfilter.DNSResult
// Don't waste resources on computing the cache key if the cache is not
// enabled.
- _, emptyCache := f.cache.(EmptyResultCache)
- if !emptyCache {
+ _, noCache := f.cache.(EmptyResultCache)
+ if !noCache {
// TODO(a.garipov): Add real class here.
- cacheKey = NewCacheKey(host, rrType, dns.ClassINET, isAns)
- item, ok = itemFromCache(f.cache, cacheKey, host)
+ cacheKey = NewCacheKey(req.Hostname, req.DNSType, dns.ClassINET, req.Answer)
+ cachedRes, ok = f.cache.Get(cacheKey)
if ok {
- return item.res
+ if cachedRes == nil {
+ return false
+ }
+
+ shallowCloneInto(res, cachedRes)
+
+ return true
}
}
- dnsReq := &urlfilter.DNSRequest{
- Hostname: host,
- ClientIP: clientIP,
- ClientName: clientName,
- DNSType: rrType,
- Answer: isAns,
+ ok = f.engine.MatchRequestInto(req, res)
+ ok = ok || len(res.NetworkRules) > 0
+
+ if noCache {
+ return ok
}
- res, ok = f.engine.MatchRequest(dnsReq)
- if !ok && len(res.NetworkRules) == 0 {
- res = nil
+ if ok {
+ cachedRes = &urlfilter.DNSResult{}
+ shallowCloneInto(cachedRes, res)
}
- f.cache.Set(cacheKey, &CacheItem{
- res: res,
- host: host,
- })
+ f.cache.Set(cacheKey, cachedRes)
- return res
+ return ok
+}
+
+// shallowCloneInto sets properties in other, as if making a shallow clone.
+// other must not be nil and should be empty or reset using [DNSResult.Reset].
+//
+// TODO(a.garipov): Add to urlfilter.
+func shallowCloneInto(other, res *urlfilter.DNSResult) {
+ other.NetworkRule = res.NetworkRule
+ other.HostRulesV4 = append(other.HostRulesV4, res.HostRulesV4...)
+ other.HostRulesV6 = append(other.HostRulesV6, res.HostRulesV6...)
+ other.NetworkRules = append(other.NetworkRules, res.NetworkRules...)
}
// ID returns the filter list ID of this rule list filter, as well as the ID of
diff --git a/internal/filter/internal/rulelist/rulelist_internal_test.go b/internal/filter/internal/rulelist/rulelist_internal_test.go
new file mode 100644
index 0000000..df5460b
--- /dev/null
+++ b/internal/filter/internal/rulelist/rulelist_internal_test.go
@@ -0,0 +1,88 @@
+package rulelist
+
+import (
+ "context"
+ "net/netip"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter"
+ "github.com/AdguardTeam/urlfilter"
+ "github.com/miekg/dns"
+ "github.com/stretchr/testify/require"
+)
+
+// TODO(d.kolyshev): Use constants from filtertest package.
+const (
+ // testHostBlocked is the blocked request host for tests.
+ testHostBlocked = "blocked.example"
+
+ // testHostOther is the other request host for tests.
+ testHostOther = "other.example"
+)
+
+// testRemoteIP is the client IP for tests
+var testRemoteIP = netip.MustParseAddr("1.2.3.4")
+
+// testFltListID is the common filter list IDs for tests.
+const testFltListID filter.ID = "fl1"
+
+// testBlockRule is the common blocking rule for tests.
+const testBlockRule = "||" + testHostBlocked + "\n"
+
+// TODO(a.garipov): Add benchmarks with a cache.
+func BenchmarkBaseFilter_SetURLFilterResult(b *testing.B) {
+ f := newBaseFilter(
+ []byte(testBlockRule),
+ testFltListID,
+ "",
+ EmptyResultCache{},
+ )
+
+ const qt = dns.TypeA
+
+ ctx := context.Background()
+ res := &urlfilter.DNSResult{}
+
+ b.Run("blocked", func(b *testing.B) {
+ req := &urlfilter.DNSRequest{
+ ClientIP: testRemoteIP,
+ Hostname: testHostBlocked,
+ DNSType: qt,
+ }
+
+ var ok bool
+ b.ReportAllocs()
+ for b.Loop() {
+ res.Reset()
+ ok = f.SetURLFilterResult(ctx, req, res)
+ }
+
+ require.True(b, ok)
+ })
+
+ b.Run("other", func(b *testing.B) {
+ req := &urlfilter.DNSRequest{
+ ClientIP: testRemoteIP,
+ Hostname: testHostOther,
+ DNSType: qt,
+ }
+
+ var ok bool
+ b.ReportAllocs()
+ for b.Loop() {
+ res.Reset()
+ ok = f.SetURLFilterResult(ctx, req, res)
+ }
+
+ require.False(b, ok)
+ })
+
+ // Most recent results:
+ //
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkBaseFilter_SetURLFilterResult/blocked-16 906486 1372 ns/op 24 B/op 1 allocs/op
+ // BenchmarkBaseFilter_SetURLFilterResult/other-16 2203561 609.1 ns/op 24 B/op 1 allocs/op
+}
diff --git a/internal/filter/internal/safesearch/safesearch.go b/internal/filter/internal/safesearch/safesearch.go
index 7d211be..0b0bcfc 100644
--- a/internal/filter/internal/safesearch/safesearch.go
+++ b/internal/filter/internal/safesearch/safesearch.go
@@ -11,6 +11,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/composite"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/refreshable"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
+ "github.com/AdguardTeam/urlfilter"
"github.com/miekg/dns"
)
@@ -46,13 +47,15 @@ func New(c *Config, cache rulelist.ResultCache) (f *Filter, err error) {
}
// type check
-var _ composite.RequestFilter = (*Filter)(nil)
+var _ composite.RequestFilterUF = (*Filter)(nil)
-// FilterRequest implements the [composite.RequestFilter] interface for *Filter.
-// It modifies the response if host matches f.
-func (f *Filter) FilterRequest(
+// FilterRequestUF implements the [composite.RequestFilterUF] interface for
+// *Filter. It modifies the response if host matches f.
+func (f *Filter) FilterRequestUF(
ctx context.Context,
req *filter.Request,
+ ufReq *urlfilter.DNSRequest,
+ ufRes *urlfilter.DNSResult,
) (r filter.Result, err error) {
qt := req.QType
switch qt {
@@ -62,13 +65,19 @@ func (f *Filter) FilterRequest(
return nil, nil
}
- host := req.Host
- dr := f.flt.DNSResult(req.RemoteIP, "", host, qt, false)
+ ufReq.Hostname = req.Host
+ ufReq.DNSType = req.QType
+
+ ok := f.flt.SetURLFilterResult(ctx, ufReq, ufRes)
+ if !ok {
+ return nil, nil
+ }
+
id, _ := f.flt.ID()
- r = rulelist.ProcessDNSRewrites(req, dr.DNSRewrites(), id)
+ r = rulelist.ProcessDNSRewrites(req, ufRes.DNSRewrites(), id)
- replaceRule(r, host)
+ replaceRule(r, req.Host)
return r, nil
}
diff --git a/internal/filter/internal/safesearch/safesearch_test.go b/internal/filter/internal/safesearch/safesearch_test.go
index a341a1c..bcdb7bf 100644
--- a/internal/filter/internal/safesearch/safesearch_test.go
+++ b/internal/filter/internal/safesearch/safesearch_test.go
@@ -17,6 +17,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/safesearch"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
+ "github.com/AdguardTeam/urlfilter"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -43,42 +44,16 @@ const testFilterRules = `|` + testEngineWithIP + `^$dnsrewrite=NOERROR;A;` + tes
`|` + testEngineWithDomain + `^$dnsrewrite=NOERROR;CNAME;` + testSafeDomain
func TestFilter(t *testing.T) {
- reqCh := make(chan struct{}, 1)
- cachePath, srvURL := filtertest.PrepareRefreshable(t, reqCh, testFilterRules, http.StatusOK)
-
- f, newErr := safesearch.New(
- &safesearch.Config{
- Refreshable: &refreshable.Config{
- Logger: slogutil.NewDiscardLogger(),
- ID: filter.IDGeneralSafeSearch,
- URL: srvURL,
- CachePath: cachePath,
- Staleness: filtertest.Staleness,
- Timeout: filtertest.Timeout,
- MaxSize: filtertest.FilterMaxSize,
- },
- CacheTTL: 1 * time.Minute,
- },
- rulelist.NewResultCache(filtertest.CacheCount, true),
- )
- require.NoError(t, newErr)
-
- refrErr := f.Refresh(testutil.ContextWithTimeout(t, filtertest.Timeout), true)
- require.NoError(t, refrErr)
-
- testutil.RequireReceive(t, reqCh, filtertest.Timeout)
+ f := newTestFilter(t)
require.True(t, t.Run("no_match", func(t *testing.T) {
- ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
- req := newReq(t, testOther, dns.TypeA)
- res, err := f.FilterRequest(ctx, req)
- require.NoError(t, err)
+ req := newRequest(t, testOther, dns.TypeA)
+ res := filterRequest(t, f, req)
assert.Nil(t, res)
require.True(t, t.Run("cached", func(t *testing.T) {
- res, err = f.FilterRequest(ctx, req)
- require.NoError(t, err)
+ res = filterRequest(t, f, req)
// TODO(a.garipov): Find a way to make caches more inspectable.
assert.Nil(t, res)
@@ -86,19 +61,15 @@ func TestFilter(t *testing.T) {
}))
require.True(t, t.Run("txt", func(t *testing.T) {
- ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
- req := newReq(t, testEngineWithIP, dns.TypeTXT)
- res, err := f.FilterRequest(ctx, req)
- require.NoError(t, err)
+ req := newRequest(t, testEngineWithIP, dns.TypeTXT)
+ res := filterRequest(t, f, req)
assert.Nil(t, res)
}))
require.True(t, t.Run("ip", func(t *testing.T) {
- ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
- req := newReq(t, testEngineWithIP, dns.TypeA)
- res, err := f.FilterRequest(ctx, req)
- require.NoError(t, err)
+ req := newRequest(t, testEngineWithIP, dns.TypeA)
+ res := filterRequest(t, f, req)
rm := testutil.RequireTypeAssert[*filter.ResultModifiedResponse](t, res)
require.Len(t, rm.Msg.Answer, 1)
@@ -109,11 +80,9 @@ func TestFilter(t *testing.T) {
assert.Equal(t, net.IP(testIPOfEngineWithIP.AsSlice()), a.A)
t.Run("cached", func(t *testing.T) {
- newReq := newReq(t, testEngineWithIP, dns.TypeA)
+ newReq := newRequest(t, testEngineWithIP, dns.TypeA)
- var cachedRes filter.Result
- cachedRes, err = f.FilterRequest(ctx, newReq)
- require.NoError(t, err)
+ cachedRes := filterRequest(t, f, newReq)
// Do not assert that the results are the same, since a modified
// result of a safe search is always cloned. But assert that the
@@ -128,10 +97,8 @@ func TestFilter(t *testing.T) {
}))
require.True(t, t.Run("domain", func(t *testing.T) {
- ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
- req := newReq(t, testEngineWithDomain, dns.TypeA)
- res, err := f.FilterRequest(ctx, req)
- require.NoError(t, err)
+ req := newRequest(t, testEngineWithDomain, dns.TypeA)
+ res := filterRequest(t, f, req)
rm := testutil.RequireTypeAssert[*filter.ResultModifiedRequest](t, res)
require.NotNil(t, rm.Msg)
@@ -146,10 +113,8 @@ func TestFilter(t *testing.T) {
}))
require.True(t, t.Run("https", func(t *testing.T) {
- ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
- req := newReq(t, testEngineWithDomain, dns.TypeHTTPS)
- res, err := f.FilterRequest(ctx, req)
- require.NoError(t, err)
+ req := newRequest(t, testEngineWithDomain, dns.TypeHTTPS)
+ res := filterRequest(t, f, req)
rm := testutil.RequireTypeAssert[*filter.ResultModifiedRequest](t, res)
require.NotNil(t, rm.Msg)
@@ -164,9 +129,141 @@ func TestFilter(t *testing.T) {
}))
}
-// newReq is a test helper that returns the filtering request with the given
+// filterRequest is a helper that calls [safesearch.Filter.FilterRequestUF].
+func filterRequest(tb testing.TB, f *safesearch.Filter, req *filter.Request) (res filter.Result) {
+ tb.Helper()
+
+ ctx := testutil.ContextWithTimeout(tb, filtertest.Timeout)
+ res, err := f.FilterRequestUF(ctx, req, &urlfilter.DNSRequest{}, &urlfilter.DNSResult{})
+ require.NoError(tb, err)
+
+ return res
+}
+
+func BenchmarkFilter_FilterRequestUF(b *testing.B) {
+ const qt = dns.TypeA
+
+ f := newTestFilter(b)
+
+ b.Run("no_match", func(b *testing.B) {
+ var res filter.Result
+ var err error
+
+ ctx := testutil.ContextWithTimeout(b, filtertest.Timeout)
+ req := newRequest(b, testOther, qt)
+
+ ufReq := &urlfilter.DNSRequest{
+ Hostname: req.Host,
+ DNSType: qt,
+ }
+
+ ufRes := &urlfilter.DNSResult{}
+
+ b.ReportAllocs()
+ for b.Loop() {
+ ufRes.Reset()
+ res, err = f.FilterRequestUF(ctx, req, ufReq, ufRes)
+ }
+
+ assert.NoError(b, err)
+ assert.Nil(b, res)
+ })
+
+ b.Run("ip", func(b *testing.B) {
+ var res filter.Result
+ var err error
+
+ ctx := testutil.ContextWithTimeout(b, filtertest.Timeout)
+ req := newRequest(b, testEngineWithIP, qt)
+
+ ufReq := &urlfilter.DNSRequest{
+ Hostname: req.Host,
+ DNSType: qt,
+ }
+
+ ufRes := &urlfilter.DNSResult{}
+
+ b.ReportAllocs()
+ for b.Loop() {
+ ufRes.Reset()
+ res, err = f.FilterRequestUF(ctx, req, ufReq, ufRes)
+ }
+
+ assert.NoError(b, err)
+ assert.NotNil(b, res)
+ })
+
+ b.Run("domain", func(b *testing.B) {
+ var res filter.Result
+ var err error
+
+ ctx := testutil.ContextWithTimeout(b, filtertest.Timeout)
+ req := newRequest(b, testEngineWithDomain, qt)
+
+ ufReq := &urlfilter.DNSRequest{
+ Hostname: req.Host,
+ DNSType: qt,
+ }
+
+ ufRes := &urlfilter.DNSResult{}
+
+ b.ReportAllocs()
+ for b.Loop() {
+ ufRes.Reset()
+ res, err = f.FilterRequestUF(ctx, req, ufReq, ufRes)
+ }
+
+ assert.NoError(b, err)
+ assert.NotNil(b, res)
+ })
+
+ // Most recent results:
+ //
+ // goos: darwin
+ // goarch: arm64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/safesearch
+ // cpu: Apple M1 Pro
+ // BenchmarkFilter_FilterRequestUF/no_match-8 27804783 43.23 ns/op 0 B/op 0 allocs/op
+ // BenchmarkFilter_FilterRequestUF/ip-8 3136018 382.3 ns/op 672 B/op 11 allocs/op
+ // BenchmarkFilter_FilterRequestUF/domain-8 4929343 237.8 ns/op 400 B/op 7 allocs/op
+}
+
+// newTestFilter creates a new [*safesearch.Filter] for testing, and refreshes
+// it immediately.
+func newTestFilter(tb testing.TB) (f *safesearch.Filter) {
+ tb.Helper()
+
+ reqCh := make(chan struct{}, 1)
+ cachePath, srvURL := filtertest.PrepareRefreshable(tb, reqCh, testFilterRules, http.StatusOK)
+
+ f, err := safesearch.New(
+ &safesearch.Config{
+ Refreshable: &refreshable.Config{
+ Logger: slogutil.NewDiscardLogger(),
+ ID: filter.IDGeneralSafeSearch,
+ URL: srvURL,
+ CachePath: cachePath,
+ Staleness: filtertest.Staleness,
+ Timeout: filtertest.Timeout,
+ MaxSize: filtertest.FilterMaxSize,
+ },
+ CacheTTL: 1 * time.Minute,
+ },
+ rulelist.NewResultCache(filtertest.CacheCount, true),
+ )
+ require.NoError(tb, err)
+
+ err = f.Refresh(testutil.ContextWithTimeout(tb, filtertest.Timeout), true)
+ require.NoError(tb, err)
+
+ testutil.RequireReceive(tb, reqCh, filtertest.Timeout)
+
+ return f
+}
+
+// newRequest is a test helper that returns the filtering request with the given
// data.
-func newReq(tb testing.TB, host string, qt dnsmsg.RRType) (req *filter.Request) {
+func newRequest(tb testing.TB, host string, qt dnsmsg.RRType) (req *filter.Request) {
tb.Helper()
return &filter.Request{
diff --git a/internal/filter/internal/serviceblock/index.go b/internal/filter/internal/serviceblock/index.go
index 040964a..91c964a 100644
--- a/internal/filter/internal/serviceblock/index.go
+++ b/internal/filter/internal/serviceblock/index.go
@@ -5,9 +5,9 @@ import (
"fmt"
"log/slog"
"path"
- "strings"
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdurlflt"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
@@ -93,7 +93,8 @@ func (svc *indexRespService) toInternal(
fltIDStr := path.Join(cachePrefix, string(filter.IDBlockedService), string(svcID))
cache := rulelist.NewManagedResultCache(cacheManager, fltIDStr, cacheCount, useCache)
- rl = rulelist.NewImmutable(strings.Join(svc.Rules, "\n"), filter.IDBlockedService, svcID, cache)
+ rulesData := agdurlflt.RulesToBytes(svc.Rules)
+ rl = rulelist.NewImmutable(rulesData, filter.IDBlockedService, svcID, cache)
logger.InfoContext(ctx, "converted service", "svc_id", svcID, "num_rules", rl.RulesCount())
diff --git a/internal/filter/internal/serviceblock/serviceblock.go b/internal/filter/internal/serviceblock/serviceblock.go
index c99b760..ddb3a9b 100644
--- a/internal/filter/internal/serviceblock/serviceblock.go
+++ b/internal/filter/internal/serviceblock/serviceblock.go
@@ -8,7 +8,6 @@ import (
"encoding/json"
"fmt"
"log/slog"
- "strings"
"sync"
"time"
@@ -134,13 +133,13 @@ func (f *Filter) Refresh(
// loadIndex fetches, decodes, and returns the blocked service index data.
func (f *Filter) loadIndex(ctx context.Context, acceptStale bool) (resp *indexResp, err error) {
- text, err := f.refr.Refresh(ctx, acceptStale)
+ b, err := f.refr.Refresh(ctx, acceptStale)
if err != nil {
return nil, fmt.Errorf("loading index: %w", err)
}
resp = &indexResp{}
- err = json.NewDecoder(strings.NewReader(text)).Decode(resp)
+ err = json.Unmarshal(b, resp)
if err != nil {
return nil, fmt.Errorf("decoding index: %w", err)
}
diff --git a/internal/filter/internal/serviceblock/serviceblock_test.go b/internal/filter/internal/serviceblock/serviceblock_test.go
index e174b99..1a20c68 100644
--- a/internal/filter/internal/serviceblock/serviceblock_test.go
+++ b/internal/filter/internal/serviceblock/serviceblock_test.go
@@ -1,7 +1,6 @@
package serviceblock_test
import (
- "context"
"net/http"
"testing"
@@ -42,7 +41,7 @@ func TestFilter(t *testing.T) {
require.NoError(t, err)
- ctx := context.Background()
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
err = f.Refresh(ctx, agdcache.EmptyManager{}, 0, false, false)
require.NoError(t, err)
diff --git a/internal/metrics/standardaccess.go b/internal/metrics/standardaccess.go
new file mode 100644
index 0000000..31ffac1
--- /dev/null
+++ b/internal/metrics/standardaccess.go
@@ -0,0 +1,81 @@
+package metrics
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/AdguardTeam/golibs/container"
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+// BackendStandardAccess is a metrics collector for standard access updates.
+type BackendStandardAccess struct {
+ // updateDuration is the histogram with the duration of the last TLS session
+ // tickets update.
+ updateDuration prometheus.Histogram
+
+ // errorsTotal is the counter with the total number of errors occurred
+ // during TLS session ticket updates.
+ errorsTotal prometheus.Counter
+}
+
+// NewBackendStandardAccess returns a new StandardAccessStorage that collects
+// metrics about standard access updates.
+func NewBackendStandardAccess(
+ namespace string,
+ reg prometheus.Registerer,
+) (m *BackendStandardAccess, err error) {
+ const (
+ updateDuration = "standard_access_update_duration"
+ errorsTotal = "standard_access_update_errors_total"
+ )
+
+ m = &BackendStandardAccess{
+ updateDuration: prometheus.NewHistogram(prometheus.HistogramOpts{
+ Name: updateDuration,
+ Subsystem: subsystemBackend,
+ Namespace: namespace,
+ Help: "Duration of the last standard access update in seconds.",
+ Buckets: []float64{0.001, 0.01, 0.1, 1},
+ }),
+ errorsTotal: prometheus.NewCounter(prometheus.CounterOpts{
+ Name: errorsTotal,
+ Subsystem: subsystemBackend,
+ Namespace: namespace,
+ Help: "The total number of errors occurred during standard access updates.",
+ }),
+ }
+
+ var errs []error
+ collectors := container.KeyValues[string, prometheus.Collector]{{
+ Key: updateDuration,
+ Value: m.updateDuration,
+ }, {
+ Key: errorsTotal,
+ Value: m.errorsTotal,
+ }}
+
+ for _, c := range collectors {
+ err = reg.Register(c.Value)
+ if err != nil {
+ errs = append(errs, fmt.Errorf("registering metrics %q: %w", c.Key, err))
+ }
+ }
+
+ if err = errors.Join(errs...); err != nil {
+ return nil, err
+ }
+
+ return m, nil
+}
+
+// ObserveUpdate implements the [backendpb.StandardAccessMetrics] interface for
+// *BackendStandardAccess.
+func (m *BackendStandardAccess) ObserveUpdate(_ context.Context, d time.Duration, err error) {
+ m.updateDuration.Observe(d.Seconds())
+ if err != nil {
+ m.errorsTotal.Inc()
+ }
+}
diff --git a/internal/metrics/tlstickets.go b/internal/metrics/tlstickets.go
index e71bc89..19bdf17 100644
--- a/internal/metrics/tlstickets.go
+++ b/internal/metrics/tlstickets.go
@@ -40,11 +40,11 @@ func NewBackendTicketStorage(
reg prometheus.Registerer,
) (m *BackendTicketStorage, err error) {
const (
- ticketsState = "tickets_state"
- updateStatus = "update_status"
- updatedTime = "update_time"
- updateDuration = "update_duration"
- errorsTotal = "update_errors_total"
+ ticketsState = "tickets_state"
+ ticketsUpdateStatus = "tickets_update_status"
+ ticketsUpdatedTime = "tickets_update_time"
+ ticketsUpdateDuration = "tickets_update_duration"
+ ticketsErrorsTotal = "tickets_update_errors_total"
)
m = &BackendTicketStorage{
@@ -55,26 +55,26 @@ func NewBackendTicketStorage(
Help: "State number code of the last updated TLS session tickets.",
}),
updateStatus: prometheus.NewGaugeVec(prometheus.GaugeOpts{
- Name: updateStatus,
+ Name: ticketsUpdateStatus,
Subsystem: subsystemTLS,
Namespace: namespace,
Help: "Status of the TLS session ticket update. 1 means success.",
}, []string{"name"}),
updatedTime: prometheus.NewGaugeVec(prometheus.GaugeOpts{
- Name: updatedTime,
+ Name: ticketsUpdatedTime,
Subsystem: subsystemTLS,
Namespace: namespace,
Help: "Time when the TLS session ticket was last time updated.",
}, []string{"name"}),
updateDuration: prometheus.NewHistogram(prometheus.HistogramOpts{
- Name: "update_duration_seconds",
+ Name: ticketsUpdateDuration,
Subsystem: subsystemTLS,
Namespace: namespace,
Help: "Duration of the last TLS session ticket update in seconds.",
Buckets: []float64{0.001, 0.01, 0.1, 1},
}),
errorsTotal: prometheus.NewCounter(prometheus.CounterOpts{
- Name: "update_errors_total",
+ Name: ticketsErrorsTotal,
Subsystem: subsystemTLS,
Namespace: namespace,
Help: "The total number of errors occurred during TLS session ticket updates.",
@@ -86,16 +86,16 @@ func NewBackendTicketStorage(
Key: ticketsState,
Value: m.ticketsState,
}, {
- Key: updateStatus,
+ Key: ticketsUpdateStatus,
Value: m.updateStatus,
}, {
- Key: updatedTime,
+ Key: ticketsUpdatedTime,
Value: m.updatedTime,
}, {
- Key: updateDuration,
+ Key: ticketsUpdateDuration,
Value: m.updateDuration,
}, {
- Key: errorsTotal,
+ Key: ticketsErrorsTotal,
Value: m.errorsTotal,
}}
diff --git a/internal/profiledb/default_test.go b/internal/profiledb/default_test.go
index 73708fd..6ef1683 100644
--- a/internal/profiledb/default_test.go
+++ b/internal/profiledb/default_test.go
@@ -375,8 +375,9 @@ func TestDefault_fileCache_success(t *testing.T) {
p, d, err := db.ProfileByDeviceID(context.Background(), dev.ID)
require.NoError(t, err)
+
assert.Equal(t, dev, d)
- assert.Equal(t, prof, p)
+ agdtest.AssertEqualProfile(t, prof, p)
}
func TestDefault_fileCache_badVersion(t *testing.T) {
diff --git a/internal/profiledb/internal/filecachepb/filecache.pb.go b/internal/profiledb/internal/filecachepb/filecache.pb.go
index 21989be..441e84e 100644
--- a/internal/profiledb/internal/filecachepb/filecache.pb.go
+++ b/internal/profiledb/internal/filecachepb/filecache.pb.go
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.36.6
-// protoc v6.31.0
+// protoc-gen-go v1.36.8
+// protoc v6.32.0
// source: filecache.proto
package filecachepb
@@ -854,6 +854,7 @@ type Access struct {
BlocklistAsn []uint32 `protobuf:"varint,5,rep,packed,name=blocklist_asn,json=blocklistAsn,proto3" json:"blocklist_asn,omitempty"`
BlocklistCidr []*CidrRange `protobuf:"bytes,2,rep,name=blocklist_cidr,json=blocklistCidr,proto3" json:"blocklist_cidr,omitempty"`
BlocklistDomainRules []string `protobuf:"bytes,3,rep,name=blocklist_domain_rules,json=blocklistDomainRules,proto3" json:"blocklist_domain_rules,omitempty"`
+ StandardEnabled bool `protobuf:"varint,6,opt,name=standard_enabled,json=standardEnabled,proto3" json:"standard_enabled,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -923,6 +924,13 @@ func (x *Access) GetBlocklistDomainRules() []string {
return nil
}
+func (x *Access) GetStandardEnabled() bool {
+ if x != nil {
+ return x.StandardEnabled
+ }
+ return false
+}
+
type CidrRange struct {
state protoimpl.MessageState `protogen:"open.v1"`
Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
@@ -1725,13 +1733,14 @@ const file_filecache_proto_rawDesc = "" +
"\x0ehuman_id_lower\x18\a \x01(\tR\fhumanIdLower\x12\x1b\n" +
"\tlinked_ip\x18\x02 \x01(\fR\blinkedIp\x12#\n" +
"\rdedicated_ips\x18\x04 \x03(\fR\fdedicatedIps\x12+\n" +
- "\x11filtering_enabled\x18\x05 \x01(\bR\x10filteringEnabled\"\x82\x02\n" +
+ "\x11filtering_enabled\x18\x05 \x01(\bR\x10filteringEnabled\"\xad\x02\n" +
"\x06Access\x12#\n" +
"\rallowlist_asn\x18\x04 \x03(\rR\fallowlistAsn\x12;\n" +
"\x0eallowlist_cidr\x18\x01 \x03(\v2\x14.profiledb.CidrRangeR\rallowlistCidr\x12#\n" +
"\rblocklist_asn\x18\x05 \x03(\rR\fblocklistAsn\x12;\n" +
"\x0eblocklist_cidr\x18\x02 \x03(\v2\x14.profiledb.CidrRangeR\rblocklistCidr\x124\n" +
- "\x16blocklist_domain_rules\x18\x03 \x03(\tR\x14blocklistDomainRules\"=\n" +
+ "\x16blocklist_domain_rules\x18\x03 \x03(\tR\x14blocklistDomainRules\x12)\n" +
+ "\x10standard_enabled\x18\x06 \x01(\bR\x0fstandardEnabled\"=\n" +
"\tCidrRange\x12\x18\n" +
"\aaddress\x18\x01 \x01(\fR\aaddress\x12\x16\n" +
"\x06prefix\x18\x02 \x01(\rR\x06prefix\"\x85\x01\n" +
diff --git a/internal/profiledb/internal/filecachepb/filecache.proto b/internal/profiledb/internal/filecachepb/filecache.proto
index 564e77d..cb95e97 100644
--- a/internal/profiledb/internal/filecachepb/filecache.proto
+++ b/internal/profiledb/internal/filecachepb/filecache.proto
@@ -152,6 +152,7 @@ message Access {
repeated uint32 blocklist_asn = 5;
repeated CidrRange blocklist_cidr = 2;
repeated string blocklist_domain_rules = 3;
+ bool standard_enabled = 6;
}
message CidrRange {
diff --git a/internal/profiledb/internal/filecachepb/filecachepb.go b/internal/profiledb/internal/filecachepb/filecachepb.go
index 2fdfdc8..189d8fa 100644
--- a/internal/profiledb/internal/filecachepb/filecachepb.go
+++ b/internal/profiledb/internal/filecachepb/filecachepb.go
@@ -420,6 +420,7 @@ func (x *Access) toInternal(cons *access.ProfileConstructor) (a access.Profile)
AllowedASN: asnToInternal(x.AllowlistAsn),
BlockedASN: asnToInternal(x.BlocklistAsn),
BlocklistDomainRules: x.BlocklistDomainRules,
+ StandardEnabled: x.StandardEnabled,
})
}
@@ -474,14 +475,16 @@ func profileToProtobuf(p *agd.Profile) (pbProf *Profile) {
}()
return &Profile{
- CustomDomains: customDomainsToProtobuf(p.CustomDomains),
- FilterConfig: filterConfigToProtobuf(p.FilterConfig),
- Access: accessToProtobuf(p.Access.Config()),
- BlockingMode: blockingModeToProtobuf(p.BlockingMode),
- Ratelimiter: ratelimiterToProtobuf(p.Ratelimiter.Config()),
- AccountId: string(p.AccountID),
- ProfileId: string(p.ID),
- DeviceIds: unsafelyConvertStrSlice[agd.DeviceID, string](p.DeviceIDs.Values()),
+ CustomDomains: customDomainsToProtobuf(p.CustomDomains),
+ FilterConfig: filterConfigToProtobuf(p.FilterConfig),
+ Access: accessToProtobuf(p.Access.Config()),
+ BlockingMode: blockingModeToProtobuf(p.BlockingMode),
+ Ratelimiter: ratelimiterToProtobuf(p.Ratelimiter.Config()),
+ AccountId: string(p.AccountID),
+ ProfileId: string(p.ID),
+ DeviceIds: unsafelyConvertStrSlice[agd.DeviceID, string](
+ p.DeviceIDs.Values(),
+ ),
FilteredResponseTtl: durationpb.New(p.FilteredResponseTTL),
AutoDevicesEnabled: p.AutoDevicesEnabled,
BlockChromePrefetch: p.BlockChromePrefetch,
@@ -645,6 +648,7 @@ func accessToProtobuf(c *access.ProfileConfig) (ac *Access) {
BlocklistAsn: blockedASNs,
BlocklistCidr: prefixesToProtobuf(c.BlockedNets),
BlocklistDomainRules: c.BlocklistDomainRules,
+ StandardEnabled: c.StandardEnabled,
}
}
diff --git a/internal/profiledb/internal/filecachepb/storage_test.go b/internal/profiledb/internal/filecachepb/storage_test.go
index 5189d20..11c6ba7 100644
--- a/internal/profiledb/internal/filecachepb/storage_test.go
+++ b/internal/profiledb/internal/filecachepb/storage_test.go
@@ -6,6 +6,7 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb/internal"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb/internal/filecachepb"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb/internal/profiledbtest"
@@ -41,7 +42,7 @@ func TestStorage(t *testing.T) {
require.NotNil(t, gotFC)
require.NotEmpty(t, *gotFC)
- assert.Equal(t, fc, gotFC)
+ agdtest.AssertEqualProfile(t, fc, gotFC)
}
func TestStorage_Load_noFile(t *testing.T) {
diff --git a/internal/profiledb/internal/internal.go b/internal/profiledb/internal/internal.go
index 8308e77..c6efc16 100644
--- a/internal/profiledb/internal/internal.go
+++ b/internal/profiledb/internal/internal.go
@@ -13,7 +13,7 @@ import (
// FileCacheVersion is the version of cached data structure. It must be
// manually incremented on every change in [agd.Device], [agd.Profile], and any
// file-cache structures.
-const FileCacheVersion = 17
+const FileCacheVersion = 18
// CacheVersionError is returned from [FileCacheStorage.Load] method if the
// stored cache version doesn't match current [FileCacheVersion].
diff --git a/internal/profiledb/internal/profiledbtest/profiledbtest.go b/internal/profiledb/internal/profiledbtest/profiledbtest.go
index 9f63f69..6f8404f 100644
--- a/internal/profiledb/internal/profiledbtest/profiledbtest.go
+++ b/internal/profiledb/internal/profiledbtest/profiledbtest.go
@@ -54,7 +54,10 @@ var Logger = slogutil.NewDiscardLogger()
// ProfileAccessConstructor is the common constructor of profile access managers
// for tests.
-var ProfileAccessConstructor = access.NewProfileConstructor(access.EmptyProfileMetrics{})
+var ProfileAccessConstructor = access.NewProfileConstructor(&access.ProfileConstructorConfig{
+ Metrics: access.EmptyProfileMetrics{},
+ Standard: access.EmptyProfile{},
+})
// ContextWithTimeout is a helper that returns a context with [Timeout].
func ContextWithTimeout(tb testing.TB) (ctx context.Context) {
@@ -157,6 +160,7 @@ func NewProfile(tb testing.TB) (p *agd.Profile, d *agd.Device) {
AllowedASN: []geoip.ASN{1},
BlockedASN: []geoip.ASN{2},
BlocklistDomainRules: []string{"block.test"},
+ StandardEnabled: true,
}),
BlockingMode: &dnsmsg.BlockingModeNullIP{},
Ratelimiter: agd.NewDefaultRatelimiter(&agd.RatelimitConfig{
diff --git a/internal/tlsconfig/customdomaindb_test.go b/internal/tlsconfig/customdomaindb_test.go
index 8248f6c..70c623b 100644
--- a/internal/tlsconfig/customdomaindb_test.go
+++ b/internal/tlsconfig/customdomaindb_test.go
@@ -6,7 +6,6 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
- "fmt"
"net/http"
"net/http/httptest"
"os"
@@ -524,21 +523,16 @@ func (m *testManager) Remove(ctx context.Context, certPath, keyPath string, isCu
func newTestManager() (m *testManager) {
return &testManager{
onAdd: func(ctx context.Context, certPath, keyPath string, isCustom bool) (err error) {
- panic(fmt.Errorf("unexpected call to testManager.Add(%v, %v, %v)", certPath, keyPath, isCustom))
+ panic(testutil.UnexpectedCall(ctx, certPath, keyPath, isCustom))
},
onClone: func() (c *tls.Config) {
- panic(fmt.Errorf("unexpected call to testManager.Clone()"))
+ panic(testutil.UnexpectedCall())
},
onCloneWithMetrics: func(proto, srvName string, deviceDomains []string) (c *tls.Config) {
- panic(fmt.Errorf(
- "unexpected call to testManager.CloneWithMetrics(%v, %v, %v)",
- proto,
- srvName,
- deviceDomains,
- ))
+ panic(testutil.UnexpectedCall(proto, srvName, deviceDomains))
},
onRemove: func(ctx context.Context, certPath, keyPath string, isCustom bool) (err error) {
- panic(fmt.Errorf("unexpected call to testManager.Remove(%v, %v, %v)", certPath, keyPath, isCustom))
+ panic(testutil.UnexpectedCall(ctx, certPath, keyPath, isCustom))
},
}
}
@@ -702,7 +696,7 @@ func TestCustomDomainDB_Refresh_retry(t *testing.T) {
certName string,
) (cert, key []byte, err error) {
if !shouldCall {
- panic(fmt.Errorf("unexpected call to strg.OnCertificateData(%s)", certName))
+ panic(testutil.UnexpectedCall(ctx, certName))
}
if strgErr != nil {
diff --git a/main.go b/main.go
index 3f7c7c4..5e634df 100644
--- a/main.go
+++ b/main.go
@@ -1,4 +1,4 @@
-// Copyright (C) 2022-2024 AdGuard Software Ltd.
+// Copyright (C) 2022-2025 AdGuard Software Ltd.
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
diff --git a/scripts/backend/dns.go b/scripts/backend/dns.go
index cf56cd8..866c2e4 100644
--- a/scripts/backend/dns.go
+++ b/scripts/backend/dns.go
@@ -271,8 +271,9 @@ func (s *mockDNSServiceServer) newDNSProfile(isFullSync bool) (dp *backendpb.DNS
Rps: 100,
Enabled: true,
},
- CustomDomain: customDomain,
- AccountId: "acc1234",
- DeviceChanges: deviceChanges,
+ CustomDomain: customDomain,
+ AccountId: "acc1234",
+ DeviceChanges: deviceChanges,
+ StandardAccessSettingsEnabled: true,
}
}
diff --git a/scripts/backend/ratelimiter.go b/scripts/backend/ratelimit.go
similarity index 68%
rename from scripts/backend/ratelimiter.go
rename to scripts/backend/ratelimit.go
index 9eef5bd..a8d5e8d 100644
--- a/scripts/backend/ratelimiter.go
+++ b/scripts/backend/ratelimit.go
@@ -2,8 +2,8 @@ package main
import (
"context"
- "fmt"
"log/slog"
+ "net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
"github.com/AdguardTeam/golibs/httphdr"
@@ -56,8 +56,32 @@ func (s *mockRateLimitServiceServer) GetRateLimitSettings(
//
// TODO(a.garipov): Implement this method.
func (s *mockRateLimitServiceServer) GetGlobalAccessSettings(
- _ context.Context,
- _ *backendpb.GlobalAccessSettingsRequest,
+ ctx context.Context,
+ req *backendpb.GlobalAccessSettingsRequest,
) (_ *backendpb.GlobalAccessSettingsResponse, _ error) {
- panic(fmt.Errorf("unexpected call to GetGlobalAccessSettings"))
+ md, _ := metadata.FromIncomingContext(ctx)
+
+ s.log.InfoContext(
+ ctx,
+ "getting",
+ "auth", md.Get(httphdr.Authorization),
+ "req", req,
+ )
+
+ return &backendpb.GlobalAccessSettingsResponse{
+ Standard: &backendpb.AccessSettings{
+ AllowlistCidr: []*backendpb.CidrRange{{
+ Address: netip.MustParseAddr("10.10.10.0").AsSlice(),
+ Prefix: 24,
+ }},
+ BlocklistCidr: []*backendpb.CidrRange{{
+ Address: netip.MustParseAddr("20.20.20.0").AsSlice(),
+ Prefix: 24,
+ }},
+ AllowlistAsn: []uint32{10},
+ BlocklistAsn: []uint32{20},
+ BlocklistDomainRules: []string{"block.std.test"},
+ Enabled: true,
+ },
+ }, nil
}
diff --git a/scripts/make/go-fuzz.sh b/scripts/make/go-fuzz.sh
index 35cfb6d..bc94fc9 100644
--- a/scripts/make/go-fuzz.sh
+++ b/scripts/make/go-fuzz.sh
@@ -64,3 +64,15 @@ readonly go count_flags shuffle_flags timeout_flags fuzztime_flags
--fuzz='FuzzHumanIDParser_ParseNormalized' \
./internal/agd/ \
;
+
+"$go" test \
+ "$count_flags" \
+ "$shuffle_flags" \
+ "$race_flags" \
+ "$timeout_flags" \
+ "$x_flags" \
+ "$v_flags" \
+ "$fuzztime_flags" \
+ --fuzz='FuzzDefault' \
+ ./internal/agdcache/ \
+ ;
diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh
index 5324f0f..811e29d 100644
--- a/scripts/make/go-lint.sh
+++ b/scripts/make/go-lint.sh
@@ -64,17 +64,20 @@ set -f -u
#
# NOTE: For AdGuard DNS, there are the following exceptions:
#
+# * internal/agdtest/profile.go: a test helper requiring the use of
+# reflect.Type.
# * internal/profiledb/internal/filecachepb/unsafe.go: a “safe” unsafe helper
# to prevent excessive allocations.
blocklist_imports() {
import_or_tab="$(printf '^\\(import \\|\t\\)')"
readonly import_or_tab
- find . \
+ find_with_ignore \
-type 'f' \
'(' \
-name '*.go' \
'!' -name '*.pb.go' \
+ '!' -path './internal/agdtest/profile.go' \
'!' -path './internal/profiledb/internal/filecachepb/unsafe.go' \
')' \
-exec \
@@ -104,7 +107,7 @@ blocklist_imports() {
method_const() {
# NOTE: File ./internal/remotekv/rediskv/rediskv.go is excluded, since it
# uses "GET" as a Redis command.
- find . \
+ find_with_ignore \
-type 'f' \
'(' -name '*.go' '!' -path './internal/remotekv/rediskv/rediskv.go' ')' \
-exec \
@@ -125,10 +128,11 @@ method_const() {
# use of filenames like client_manager.go.
underscores() {
underscore_files="$(
- find . \
+ find_with_ignore \
-type 'f' \
-name '*_*.go' \
- '!' '(' -name '*_darwin.go' \
+ '!' '(' \
+ -name '*_darwin.go' \
-o -name '*_generate.go' \
-o -name '*_grpc.pb.go' \
-o -name '*_linux.go' \
@@ -180,7 +184,7 @@ run_linter ineffassign ./... "$dnssrvmod"
run_linter unparam ./... "$dnssrvmod"
-find . \
+find_with_ignore \
-type 'f' \
'(' \
-name 'Makefile' \
diff --git a/scripts/make/go-test.sh b/scripts/make/go-test.sh
index 3441416..a4e24c6 100644
--- a/scripts/make/go-test.sh
+++ b/scripts/make/go-test.sh
@@ -3,7 +3,7 @@
# This comment is used to simplify checking local copies of the script. Bump
# this number every time a significant change is made to this script.
#
-# AdGuard-Project-Version: 5
+# AdGuard-Project-Version: 6
verbose="${VERBOSE:-0}"
readonly verbose
@@ -36,7 +36,7 @@ else
fi
readonly race_flags
-count_flags='--count=1'
+count_flags='--count=2'
cover_flags='--coverprofile=./cover.out'
go="${GO:-go}"
shuffle_flags='--shuffle=on'
diff --git a/scripts/make/helper.sh b/scripts/make/helper.sh
index 8caa047..6c8a457 100644
--- a/scripts/make/helper.sh
+++ b/scripts/make/helper.sh
@@ -6,15 +6,15 @@
# right after the initial environment processing.
# This comment is used to simplify checking local copies of the script. Bump
-# this number every time a remarkable change is made to this script.
+# this number every time a significant change is made to this script.
#
-# AdGuard-Project-Version: 4
+# AdGuard-Project-Version: 5
# Deferred helpers
not_found_msg='
looks like a binary not found error.
-make sure you have installed the linter binaries using:
+make sure you have installed the linter binaries, including using:
$ make go-tools
'
@@ -73,3 +73,33 @@ run_linter() (
return "$exitcode"
)
+
+# find_with_ignore is a wrapper around find that does not descend into ignored
+# directories, such as ./tmp/.
+#
+# NOTE: The arguments must contain on of -exec, -ok, or -print; see
+# https://pubs.opengroup.org/onlinepubs/9799919799/utilities/find.html.
+#
+# TODO(a.garipov): Find a way to integrate the entire gitignore, including the
+# global one, without using git, as .git is not copied into the build container.
+#
+# Keep in sync with .gitignore.
+find_with_ignore() {
+ find . \
+ '(' \
+ -type 'd' \
+ '(' \
+ -name '.git' \
+ -o -name 'bin' \
+ -o -name 'filters' \
+ -o -name 'github-mirror' \
+ -o -name 'test' \
+ -o -name 'test-reports' \
+ -o -name 'tmp' \
+ ')' \
+ -prune \
+ ')' \
+ -o \
+ "$@" \
+ ;
+}
diff --git a/scripts/make/md-lint.sh b/scripts/make/md-lint.sh
index e9ee7a5..9b50e2c 100644
--- a/scripts/make/md-lint.sh
+++ b/scripts/make/md-lint.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# This comment is used to simplify checking local copies of the script. Bump
-# this number every time a remarkable change is made to this script.
+# this number every time a significant change is made to this script.
#
# AdGuard-Project-Version: 3
diff --git a/scripts/make/sh-lint.sh b/scripts/make/sh-lint.sh
index ca748c5..39196ef 100644
--- a/scripts/make/sh-lint.sh
+++ b/scripts/make/sh-lint.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# This comment is used to simplify checking local copies of the script. Bump
-# this number every time a remarkable change is made to this script.
+# this number every time a significant change is made to this script.
#
# AdGuard-Project-Version: 3
diff --git a/scripts/make/txt-lint.sh b/scripts/make/txt-lint.sh
index 2479a95..6f9129e 100644
--- a/scripts/make/txt-lint.sh
+++ b/scripts/make/txt-lint.sh
@@ -1,9 +1,9 @@
#!/bin/sh
# This comment is used to simplify checking local copies of the script. Bump
-# this number every time a remarkable change is made to this script.
+# this number every time a significant change is made to this script.
#
-# AdGuard-Project-Version: 7
+# AdGuard-Project-Version: 9
verbose="${VERBOSE:-0}"
readonly verbose
@@ -33,19 +33,18 @@ trailing_newlines() (
nl="$(printf '\n')"
readonly nl
- find . \
+ find_with_ignore \
-type 'f' \
'!' '(' \
- -name '*.mmdb' \
+ -name '*.exe' \
+ -o -name '*.mmdb' \
-o -name '*.out' \
-o -name '*.pb' \
+ -o -name '*.test' \
-o -name 'AdGuardDNS' \
-o -name 'agdns' \
- -o -path './.git/*' \
- -o -path './bin/*' \
- -o -path './filters/*' \
- -o -path './test/*' \
')' \
+ -print \
| while read -r f; do
final_byte="$(tail -c -1 "$f")"
if [ "$final_byte" != "$nl" ]; then
@@ -57,19 +56,18 @@ trailing_newlines() (
# trailing_whitespace is a simple check that makes sure that there are no
# trailing whitespace in plain-text files.
trailing_whitespace() {
- find . \
+ find_with_ignore \
-type 'f' \
'!' '(' \
- -name '*.mmdb' \
+ -name '*.exe' \
+ -o -name '*.mmdb' \
-o -name '*.out' \
-o -name '*.pb' \
+ -o -name '*.test' \
-o -name 'AdGuardDNS' \
-o -name 'agdns' \
- -o -path './.git/*' \
- -o -path './bin/*' \
- -o -path './filters/*' \
- -o -path './test/*' \
')' \
+ -print \
| while read -r f; do
grep -e '[[:space:]]$' -n -- "$f" \
| sed -e "s:^:${f}\::" -e 's/ \+$/>>>&<<'
@@ -80,7 +78,7 @@ run_linter -e trailing_newlines
run_linter -e trailing_whitespace
-find . \
+find_with_ignore \
-type 'f' \
'(' \
-name 'Makefile' \
@@ -90,8 +88,4 @@ find . \
-o -name '*.yaml' \
-o -name '*.yml' \
')' \
- '!' '(' \
- -path './filters/*' \
- -o -path './test/*' \
- ')' \
-exec 'misspell' '--error' '{}' '+'