diff --git a/CHANGELOG.md b/CHANGELOG.md
index 825824c..51a89fa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,98 @@ The format is **not** based on [Keep a Changelog][kec], since the project
+## AGDNS-2048 / Build 750
+
+ * The environment variables `RESEARCH_LOGS` and `RESEARCH_METRICS` have been
+ removed.
+
+
+
+## AGDNS-2022 / Build 746
+
+ * The property `block_page_redirect` of objects within `server_groups` array
+ has been removed.
+
+
+
+## AGDNS-1981 / Build 744
+
+ * The objects within `server_groups` array had a change in their
+ `block_page_redirect` configuration, it now supports arrays of IP addresses
+ in `ipv4` and `ipv6` fields.
+
+ * Profile's file cache version was incremented. In case of
+ `BlockingModeCustomIP` the `profile.blocking_mode` IPv4/IPv6 fields are now
+ arrays of IP addresses.
+
+
+
+## AGDNS-2012 / Build 732
+
+ * The querylog now has a new field, `"rn"`, which is a 16-bit unsigned random
+ number. Field `"u"`, the unique request ID, is deprecated and may be
+ removed in the future.
+
+
+
+## AGDNS-1879 / Build 729
+
+ * Profile's file cache version was incremented. The new field
+ `authentication` has been added to profile's device object.
+
+
+
+## AGDNS-1934 / Build 728
+
+ * The object `filters` has new properties: `index_refresh_timeout`, and
+ `rule_list_refresh_timeout`. So replace this:
+
+ ```yaml
+ filters:
+ # …
+ ```
+
+ with this:
+
+ ```yaml
+ filters:
+ # …
+ index_refresh_timeout: 1m
+ rule_list_refresh_timeout: 1m
+ ```
+
+ * The objects `safe_browsing` and `adult_blocking` have a new property:
+ `refresh_timeout`. So replace this:
+
+ ```yaml
+ safe_browsing:
+ # …
+ # …
+ adult_blocking:
+ # …
+ ```
+
+ with this:
+
+ ```yaml
+ safe_browsing:
+ # …
+ refresh_timeout: 1m
+ # …
+ adult_blocking:
+ # …
+ refresh_timeout: 1m
+ ```
+
+
+
+## AGDNS-1954 / Build 726
+
+ * The object `web` has a new optional property, `general_blocking`. Its
+ format is the same as in `adult_blocking` and `safe_browsing`.
+
+
+
## AGDNS-1954 / Build 719
* The objects within `server_groups` array have a new property
@@ -37,6 +129,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
probability: 0.01
```
+ > [!NOTE]
+ > For `ipv4` and `ipv6` only one address is currently supported.
+
For server groups that do not require a block-page redirect, set:
```yaml
diff --git a/Makefile b/Makefile
index 967628b..4365c85 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@
# Makefile. Bump this number every time a significant change is made to
# this Makefile.
#
-# AdGuard-Project-Version: 4
+# AdGuard-Project-Version: 5
# Don't name these macros "GO" etc., because GNU Make apparently makes
# them exported environment variables with the literal value of
@@ -22,8 +22,8 @@ VERBOSE.MACRO = $${VERBOSE:-0}
BRANCH = $$( git rev-parse --abbrev-ref HEAD )
GOAMD64 = v1
-GOPROXY = https://goproxy.cn|https://proxy.golang.org|direct
-GOTOOLCHAIN = go1.21.8
+GOPROXY = https://proxy.golang.org|direct
+GOTOOLCHAIN = go1.22.4
RACE = 0
REVISION = $$( git rev-parse --short HEAD )
VERSION = 0
diff --git a/config.dist.yaml b/config.dist.yaml
index 29945bd..a7fdcc0 100644
--- a/config.dist.yaml
+++ b/config.dist.yaml
@@ -196,33 +196,44 @@ web:
certificates:
- certificate: './test/cert.crt'
key: './test/cert.key'
- # Optional safe browsing web server configuration. static_content is not
+ # Optional adult blocking web server configuration. static_content is not
# served on these addresses. The addresses should be the same as in the
- # safe_browsing object.
- safe_browsing:
+ # general_blocking and safe_browsing objects.
+ adult_blocking:
bind:
- address: '127.0.0.1:9081'
- address: '127.0.0.1:9444'
certificates:
- certificate: './test/cert.crt'
key: './test/cert.key'
- block_page: './test/block_page_sb.html'
- # Optional adult blocking web server configuration. static_content is not
+ block_page: './test/block_page_adult.html'
+ # Optional general blocking web server configuration. static_content is not
# served on these addresses. The addresses should be the same as in the
- # adult_blocking object.
- adult_blocking:
+ # adult_blocking and safe_browsing objects.
+ general_blocking:
bind:
- address: '127.0.0.1:9082'
- address: '127.0.0.1:9445'
certificates:
- certificate: './test/cert.crt'
key: './test/cert.key'
- block_page: './test/block_page_adult.html'
+ block_page: './test/block_page_general.html'
+ # Optional safe browsing web server configuration. static_content is not
+ # served on these addresses. The addresses should be the same as in the
+ # general_blocking and safe_browsing objects.
+ safe_browsing:
+ bind:
+ - address: '127.0.0.1:9083'
+ - address: '127.0.0.1:9446'
+ certificates:
+ - certificate: './test/cert.crt'
+ key: './test/cert.key'
+ block_page: './test/block_page_sb.html'
# Listen addresses for the web service in addition to the ones in the
# DNS-over-HTTPS handlers.
non_doh_bind:
- - address: '127.0.0.1:9083'
- - address: '127.0.0.1:9446'
+ - address: '127.0.0.1:9084'
+ - address: '127.0.0.1:9447'
certificates:
- certificate: './test/cert.crt'
key: './test/cert.key'
@@ -253,6 +264,7 @@ safe_browsing:
cache_size: 1024
cache_ttl: 1h
refresh_interval: 1h
+ refresh_timeout: 1m
# AdGuard adult content blocking filter configuration.
adult_blocking:
@@ -260,8 +272,12 @@ adult_blocking:
cache_size: 1024
cache_ttl: 1h
refresh_interval: 1h
+ refresh_timeout: 1m
# Settings for rule-list-based filters.
+#
+# TODO(a.garipov): Add the timeout for the blocked-service index refresh. It
+# is currently hardcoded to 3 minutes.
filters:
# The TTL to set for responses to requests for filtered domains.
response_ttl: 5m
@@ -273,9 +289,17 @@ filters:
# How often to update filters from the index. See the documentation for the
# FILTER_INDEX_URL environment variable.
refresh_interval: 1h
- # The timeout for the entire filter update operation. Be aware that each
- # individual refresh operation also has its own hardcoded 3m timeout.
+ # The timeout for the entire filter update operation. Note that filter
+ # rule-list index and each filter rule-list update operations have their own
+ # timeouts, see index_refresh_timeout and rule_list_refresh_timeout.
refresh_timeout: 5m
+ # The timeout for the filter rule-list index update operation. See also
+ # refresh_timeout for the entire filter update operation.
+ index_refresh_timeout: 1m
+ # The timeout for the filter update operation of each rule-list, including
+ # the safe-search ones. See also refresh_timeout for the entire filter
+ # update operation.
+ rule_list_refresh_timeout: 1m
# MaxSize is the maximum size of the downloadable filtering rule-list.
max_size: 256MB
# Rule list cache.
@@ -351,38 +375,6 @@ server_groups:
- name: 'adguard_dns_default'
# This filtering_group is used for all anonymous clients.
filtering_group: 'default'
- # Settings for redirection to a block page.
- block_page_redirect:
- # If enabled is false, other fields can be skipped.
- enabled: true
- # Addresses to use for A queries. If enabled is true, ipv4, ipv6, or
- # both must be filled.
- ipv4:
- - address: '127.0.0.1'
- - address: '127.0.0.2'
- # Addresses to use for AAAA queries. If enabled is true, ipv4, ipv6, or
- # both must be filled.
- ipv6:
- - address: '::1'
- - address: '::2'
- # Request parameters based on which the block page is always shown. For
- # requests matching these parameters, both skip and probability are
- # ignored.
- apply:
- client:
- - address: '192.168.0.0/16'
- - address: '1.2.3.4'
- # Request parameters based on which the block page is never shown. For
- # requests matching these parameters, probability is ignored.
- skip:
- client:
- - address: '1.2.0.0/16'
- - address: '5.6.7.8'
- question:
- - domain: 'do-not-show-block.site.example'
- # The probability of responding with the block page IPs based on remote
- # address. Must be between 0.0 and 1.0.
- probability: 0.01
ddr:
enabled: true
# Device ID domain name suffix to DDR record template mapping. Keep in
diff --git a/doc/configuration.md b/doc/configuration.md
index 0534f87..5231360 100644
--- a/doc/configuration.md
+++ b/doc/configuration.md
@@ -28,7 +28,6 @@ configuration file with comments.
* [Filtering groups](#filtering_groups)
* [Network interface listeners](#interface_listeners)
* [Server groups](#server_groups)
- * [Block-page redirecting](#server_groups-*-block_page_redirect)
* [DDR](#server_groups-*-ddr)
* [TLS](#server_groups-*-tls)
* [Servers](#server_groups-*-servers-*)
@@ -609,9 +608,9 @@ The optional `web` object has the following properties:
```
* `safe_browsing`:
- The optional safe browsing web server configurations. Every request is
- responded with the content from the file to which the `block_page` property
- points.
+ The optional safe browsing block-page web server configurations. Every
+ request is responded with the content from the file to which the
+ `block_page` property points.
See the [full description of this API][http-block-pages] on the HTTP API
page.
@@ -639,10 +638,15 @@ The optional `web` object has the following properties:
```
* `adult_blocking`:
- The optional adult blocking web server configurations. The format of the
+ The optional adult block-page web server configuration. The format of the
values is the same as in the [`safe_browsing`](#web-safe_browsing) object
above.
+ * `general_blocking`:
+ The optional general block-page web server configuration. The format of
+ the values is the same as in the [`safe_browsing`](#web-safe_browsing)
+ object above.
+
* `non_doh_bind`:
The optional listen addresses and optional TLS configuration for the web
service in addition to the ones in the DNS-over-HTTPS handlers. The
@@ -669,6 +673,9 @@ The optional `web` object has the following properties:
Inside of the `headers` map, the header `Content-Type` is required.
+ > [!NOTE]
+ > Paths are case-sensitive.
+
**Property example:**
```yaml
@@ -735,6 +742,11 @@ The `safe_browsing` object has the following properties:
**Example:** `1m`.
+ * `refresh_timeout`:
+ The timeout for the update operation, as a human-readable duration.
+
+ **Example:** `1m`.
+
## Adult-content blocking
@@ -746,6 +758,9 @@ The `adult_blocking` object has the same properties as the
## Filter Lists
+**TODO(a.garipov):** Add the timeout for the blocked-service index refresh. It
+is currently hardcoded to 3 minutes.
+
The `filters` object has the following properties:
* `response_ttl`:
@@ -777,11 +792,29 @@ The `filters` object has the following properties:
* `refresh_timeout`:
The timeout for the *entire* filter update operation, as a human-readable
- duration. Be aware that each individual refresh operation also has its own
- hardcoded 3m timeout.
+ duration. Note that filter rule-list index and each filter rule-list
+ update operations have their own timeouts, see
+ [`index_refresh_timeout`](#filters-index_refresh_timeout) and
+ [`rule_list_refresh_timeout`](#filters-rule_list_refresh_timeout).
**Example:** `5m`.
+ * `index_refresh_timeout`:
+ The timeout for the filter rule-list index update operation, as a
+ human-readable duration. See also
+ [`refresh_timeout`](#filters-refresh_timeout) for the entire filter update
+ operation.
+
+ **Example:** `1m`.
+
+ * `rule_list_refresh_timeout`:
+ The timeout for the filter update operation of each rule-list, including the
+ safe-search ones, as a human-readable duration. See also
+ [`refresh_timeout`](#filters-refresh_timeout) for the entire filter update
+ operation.
+
+ **Example:** `1m`.
+
* `max_size`:
The maximum size of the downloadable content for a rule-list in a
human-readable format.
@@ -939,9 +972,6 @@ The items of the `server_groups` array have the following properties:
**Example:** `default`.
- * `block_page_redirect`: The block-page redirect configuration object. See
- [below](#server_groups-*-block_page_redirect).
-
* `ddr`: The DDR configuration object. See [below](#server_groups-*-ddr).
* `tls`: The TLS configuration object. See [below](#server_groups-*-tls).
@@ -956,69 +986,6 @@ The items of the `server_groups` array have the following properties:
- ### Block-page redirecting
-
-The block-page redirect configuration object. If enabled, AdGuard DNS responds
-with the configured IP addresses to “redirect” users to an informative block
-page.
-
- * `enabled`:
-
- Shows if the block-page redirect is enabled. If `false`, the fields below
- can be skipped.
-
- * `ipv4`:
-
- Arrays of IPv4 addresses with which to respond to blocked `A` queries.
-
- If `enabled` is true, `ipv4`, `ipv6`, or both must be filled.
-
- * `ipv6`:
-
- Arrays of IPv6 addresses with which to respond to blocked `AAAA` queries.
-
- If `enabled` is true, `ipv4`, `ipv6`, or both must be filled.
-
- * `apply`:
-
- Request parameters based on which the block-page redirect is always
- performed. For requests matching these parameters, both `skip` and
- `probability` are
- ignored.
-
- **Property example:**
-
- ```yaml
- apply:
- client:
- - address: '192.168.0.0/16'
- - address: '1.2.3.4'
- ```
-
- * `skip`:
-
- Request parameters based on which the block-page redirect is never
- performed. For requests matching these parameters, `probability` is
- ignored.
-
- **Property example:**
-
- ```yaml
- skip:
- client:
- - address: '1.2.0.0/16'
- - address: '5.6.7.8'
- question:
- - domain: 'do-not-show-block.site.example'
- ```
-
- * `probability`:
-
- The probability of responding with the block page IPs based on remote
- address. Must be between `0.0` and `1.0`.
-
-
-
### DDR
The DDR configuration object. Many of these data duplicate data from objects in
diff --git a/doc/development.md b/doc/development.md
index 0690f3c..0eda125 100644
--- a/doc/development.md
+++ b/doc/development.md
@@ -13,7 +13,7 @@
Development is supported on Linux and macOS (aka Darwin) systems.
-1. Install Go 1.21 or later.
+1. Install Go 1.22 or later.
1. Call `make init` to set up the Git pre-commit hook.
@@ -219,15 +219,15 @@ curl 'https://raw.githubusercontent.com/maxmind/MaxMind-DB/main/test-data/GeoIP2
You'll need to supply the following:
- * [`ADULT_BLOCKING_URL`](#env-ADULT_BLOCKING_URL)
- * [`BILLSTAT_URL`](#env-BILLSTAT_URL)
- * [`CONSUL_ALLOWLIST_URL`](#env-CONSUL_ALLOWLIST_URL)
- * [`GENERAL_SAFE_SEARCH_URL`](#env-GENERAL_SAFE_SEARCH_URL)
- * [`LINKED_IP_TARGET_URL`](#env-LINKED_IP_TARGET_URL)
- * [`NEW_REG_DOMAINS_URL`](#env-NEW_REG_DOMAINS_URL)
- * [`PROFILES_URL`](#env-PROFILES_URL)
- * [`SAFE_BROWSING_URL`](#env-SAFE_BROWSING_URL)
- * [`YOUTUBE_SAFE_SEARCH_URL`](#env-YOUTUBE_SAFE_SEARCH_URL)
+ * [`ADULT_BLOCKING_URL`][env-ADULT_BLOCKING_URL]
+ * [`BILLSTAT_URL`][env-BILLSTAT_URL]
+ * [`CONSUL_ALLOWLIST_URL`][env-CONSUL_ALLOWLIST_URL]
+ * [`GENERAL_SAFE_SEARCH_URL`][env-GENERAL_SAFE_SEARCH_URL]
+ * [`LINKED_IP_TARGET_URL`][env-LINKED_IP_TARGET_URL]
+ * [`NEW_REG_DOMAINS_URL`][env-NEW_REG_DOMAINS_URL]
+ * [`PROFILES_URL`][env-PROFILES_URL]
+ * [`SAFE_BROWSING_URL`][env-SAFE_BROWSING_URL]
+ * [`YOUTUBE_SAFE_SEARCH_URL`][env-YOUTUBE_SAFE_SEARCH_URL]
See the [external HTTP API documentation][externalhttp].
@@ -280,6 +280,16 @@ env \
./AdGuardDNS
```
+[env-ADULT_BLOCKING_URL]: environment.md#ADULT_BLOCKING_URL
+[env-BILLSTAT_URL]: environment.md#BILLSTAT_URL
+[env-CONSUL_ALLOWLIST_URL]: environment.md#CONSUL_ALLOWLIST_URL
+[env-GENERAL_SAFE_SEARCH_URL]: environment.md#GENERAL_SAFE_SEARCH_URL
+[env-LINKED_IP_TARGET_URL]: environment.md#LINKED_IP_TARGET_URL
+[env-NEW_REG_DOMAINS_URL]: environment.md#NEW_REG_DOMAINS_URL
+[env-PROFILES_URL]: environment.md#PROFILES_URL
+[env-SAFE_BROWSING_URL]: environment.md#SAFE_BROWSING_URL
+[env-YOUTUBE_SAFE_SEARCH_URL]: environment.md#YOUTUBE_SAFE_SEARCH_URL
+
[externalhttp]: externalhttp.md
diff --git a/doc/environment.md b/doc/environment.md
index 59427ac..437c469 100644
--- a/doc/environment.md
+++ b/doc/environment.md
@@ -26,8 +26,6 @@ sensitive configuration. All other configuration is stored in the
* [`PROFILES_ENABLED`](#PROFILES_ENABLED)
* [`PROFILES_URL`](#PROFILES_URL)
* [`QUERYLOG_PATH`](#QUERYLOG_PATH)
- * [`RESEARCH_LOGS`](#RESEARCH_LOGS)
- * [`RESEARCH_METRICS`](#RESEARCH_METRICS)
* [`RULESTAT_URL`](#RULESTAT_URL)
* [`SAFE_BROWSING_URL`](#SAFE_BROWSING_URL)
* [`SENTRY_DSN`](#SENTRY_DSN)
@@ -264,25 +262,6 @@ The path to the file into which the query log is going to be written.
-## `RESEARCH_METRICS`
-
-If `1`, enable collection of a set of special prometheus metrics (prefix is
-`dns_research`). If `0`, disable collection of those metrics.
-
-**Default:** `0`.
-
-
-
-## `RESEARCH_LOGS`
-
-If `1`, enable logging of additional info that may be required for research
-purposes (prefix `research:`). The log will only be written when
-`RESEARCH_METRICS` is also set to `1`. If `0`, disable logging of this info.
-
-**Default:** `0`.
-
-
-
## `RULESTAT_URL`
The URL to send filtering rule list statistics to. If empty or unset, the
diff --git a/doc/http.md b/doc/http.md
index 135495e..a8a34e6 100644
--- a/doc/http.md
+++ b/doc/http.md
@@ -17,9 +17,9 @@ appropriately.
## Block Pages
-The safe browsing and adult blocking servers. Every request is responded with
-the content from the configured file, with the exception of `GET /favicon.ico`
-and `GET /robots.txt` requests, which are handled separately:
+The safe-browsing, adult-blocking, and popup-blocking servers. Every request is
+responded with the content from the configured file, with the exception of `GET
+/favicon.ico` and `GET /robots.txt` requests, which are handled separately:
* `GET /favicon.ico` requests are responded with a plain-text `404 Not Found`
response.
diff --git a/doc/querylog.md b/doc/querylog.md
index 1c18b09..2e74b4d 100644
--- a/doc/querylog.md
+++ b/doc/querylog.md
@@ -5,8 +5,8 @@ entries are designed to be concise and easily compressable. An example of the
log output:
```jsonl
-{"u":"ABCD","b":"prof1234","i":"dev1234","c":"RU","d":"US","n":"example.com.","l":"cdef5678","m":"||example.com^","t":1628590394000,"a":1234,"e":5,"q":1,"f":2,"s":0,"p":8,"r":0}
-{"u":"DEFG","b":"prof1234","i":"dev1234","c":"RU","d":"JP","n":"example.org.","l":"hijk9012","m":"||example.org^","t":1628590394100,"a":6789,"e":6,"q":1,"f":2,"s":0,"p":8,"r":0}
+{"u":"ABCD","b":"prof1234","i":"dev1234","c":"RU","d":"US","n":"example.com.","l":"cdef5678","m":"||example.com^","t":1628590394000,"a":1234,"e":5,"q":1,"rn":1234,"f":2,"s":0,"p":8,"r":0}
+{"u":"DEFG","b":"prof1234","i":"dev1234","c":"RU","d":"JP","n":"example.org.","l":"hijk9012","m":"||example.org^","t":1628590394100,"a":6789,"e":6,"q":1,"rn":56789,"f":2,"s":0,"p":8,"r":0}
```
AdGuard DNS opens and closes the log file on each write to prevent issues with
@@ -24,6 +24,9 @@ rules to remember, which property means what. The properties are:
* `u`:
The unique ID of the request. The short name `u` stands for “unique”.
+ > [!NOTE]
+ > This field is deprecated and may be removed in the future.
+
**Example:** `"ABCD1234"`
* `b`:
@@ -141,6 +144,12 @@ rules to remember, which property means what. The properties are:
See [this Wikipedia list][wiki-dnsrr] for numeric values and their meanings.
+ * `rn`:
+ A random 16-bit unsigned integer added to an entry for easier deduplication
+ when `"u"` is not used for that.
+
+ **Example:** `12345`
+
* `f`:
The action taken with this request. The short name `f` stands for
“filtering”. The possible values are:
diff --git a/go.mod b/go.mod
index f15db5c..90a6928 100644
--- a/go.mod
+++ b/go.mod
@@ -1,13 +1,13 @@
module github.com/AdguardTeam/AdGuardDNS
-go 1.21.8
+go 1.22.4
require (
github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-00010101000000-000000000000
- github.com/AdguardTeam/golibs v0.20.1
+ github.com/AdguardTeam/golibs v0.23.2
github.com/AdguardTeam/urlfilter v0.18.0
- github.com/ameshkov/dnscrypt/v2 v2.2.7
- github.com/axiomhq/hyperloglog v0.0.0-20240124082744-24bca3a5b39b
+ github.com/ameshkov/dnscrypt/v2 v2.3.0
+ github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02
github.com/bluele/gcache v0.0.2
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500
github.com/caarlos0/env/v7 v7.1.0
@@ -16,17 +16,18 @@ require (
github.com/miekg/dns v1.1.58
github.com/oschwald/maxminddb-golang v1.12.0
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
- github.com/prometheus/client_golang v1.18.0
- github.com/prometheus/client_model v0.5.0
- github.com/prometheus/common v0.46.0
- github.com/quic-go/quic-go v0.41.0
- github.com/stretchr/testify v1.8.4
- golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
- golang.org/x/net v0.21.0
- golang.org/x/sys v0.17.0
+ github.com/prometheus/client_golang v1.19.0
+ github.com/prometheus/client_model v0.6.1
+ github.com/prometheus/common v0.52.3
+ github.com/quic-go/quic-go v0.42.0
+ github.com/stretchr/testify v1.9.0
+ golang.org/x/crypto v0.22.0
+ golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8
+ golang.org/x/net v0.24.0
+ golang.org/x/sys v0.19.0
golang.org/x/time v0.5.0
- google.golang.org/grpc v1.61.1
- google.golang.org/protobuf v1.32.0
+ google.golang.org/grpc v1.63.2
+ google.golang.org/protobuf v1.33.0
gopkg.in/yaml.v2 v2.4.0
)
@@ -35,23 +36,22 @@ require (
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
github.com/ameshkov/dnsstamps v1.0.3 // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
- github.com/golang/protobuf v1.5.3 // indirect
- github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
- github.com/onsi/ginkgo/v2 v2.15.0 // indirect
- github.com/panjf2000/ants/v2 v2.9.0 // indirect
+ github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
+ github.com/onsi/ginkgo/v2 v2.17.1 // indirect
+ github.com/panjf2000/ants/v2 v2.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/procfs v0.12.0 // indirect
+ github.com/prometheus/procfs v0.13.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
go.uber.org/mock v0.4.0 // indirect
- golang.org/x/crypto v0.19.0 // indirect
- golang.org/x/mod v0.15.0 // indirect
+ golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/sync v0.7.0 // indirect
golang.org/x/text v0.14.0 // indirect
- golang.org/x/tools v0.18.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect
+ golang.org/x/tools v0.20.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240412170617-26222e5d3d56 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 07b3d00..73e4466 100644
--- a/go.sum
+++ b/go.sum
@@ -1,17 +1,17 @@
-github.com/AdguardTeam/golibs v0.20.1 h1:ol8qLjWGZhU9paMMwN+OLWVTUigGsXa29iVTyd62VKY=
-github.com/AdguardTeam/golibs v0.20.1/go.mod h1:bgcMgRviCKyU6mkrX+RtT/OsKPFzyppelfRsksMG3KU=
+github.com/AdguardTeam/golibs v0.23.2 h1:rMjYantwtQ39e8G4zBQ6ZLlm4s3XH30Bc9VxhoOHwao=
+github.com/AdguardTeam/golibs v0.23.2/go.mod h1:o9i55Sx6v7qogRQeqaBfmLbC/pZqeMBWi015U5PTDY0=
github.com/AdguardTeam/urlfilter v0.18.0 h1:ZZzwODC/ADpjJSODxySrrUnt/fvOCfGFaCW6j+wsGfQ=
github.com/AdguardTeam/urlfilter v0.18.0/go.mod h1:IXxBwedLiZA2viyHkaFxY/8mjub0li2PXRg8a3d9Z1s=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us=
-github.com/ameshkov/dnscrypt/v2 v2.2.7 h1:aEitLIR8HcxVodZ79mgRcCiC0A0I5kZPBuWGFwwulAw=
-github.com/ameshkov/dnscrypt/v2 v2.2.7/go.mod h1:qPWhwz6FdSmuK7W4sMyvogrez4MWdtzosdqlr0Rg3ow=
+github.com/ameshkov/dnscrypt/v2 v2.3.0 h1:pDXDF7eFa6Lw+04C0hoMh8kCAQM8NwUdFEllSP2zNLs=
+github.com/ameshkov/dnscrypt/v2 v2.3.0/go.mod h1:N5hDwgx2cNb4Ay7AhvOSKst+eUiOZ/vbKRO9qMpQttE=
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.0.0-20240124082744-24bca3a5b39b h1:F3yMzKumBUQ6Fn0sYI1YQ16vQRucpZOfBQ9HXWl5+XI=
-github.com/axiomhq/hyperloglog v0.0.0-20240124082744-24bca3a5b39b/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c=
+github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02 h1:bXAPYSbdYbS5VTy92NIUbeDI1qyggi+JYh5op9IFlcQ=
+github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c=
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=
@@ -20,8 +20,8 @@ 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/caarlos0/env/v7 v7.1.0 h1:9lzTF5amyQeWHZzuZeKlCb5FWSUxpG1js43mhbY8ozg=
github.com/caarlos0/env/v7 v7.1.0/go.mod h1:LPPWniDUq4JaO6Q41vtlyikhMknqymCLBw0eX4dcH1E=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+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.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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=
@@ -38,14 +38,12 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo=
-github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
+github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
+github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -56,14 +54,14 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
-github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
-github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
+github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
+github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
-github.com/panjf2000/ants/v2 v2.9.0 h1:SztCLkVxBRigbg+vt0S5QvF5vxAbxbKt09/YfAJ0tEo=
-github.com/panjf2000/ants/v2 v2.9.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
+github.com/panjf2000/ants/v2 v2.9.1 h1:Q5vh5xohbsZXGcD6hhszzGqB7jSSc2/CRr3QKIga8Kw=
+github.com/panjf2000/ants/v2 v2.9.1/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
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/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
@@ -74,18 +72,18 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/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/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
-github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
-github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
-github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
-github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y=
-github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ=
-github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
-github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
+github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
+github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.52.3 h1:5f8uj6ZwHSscOGNdIQg6OiZv/ybiK2CO2q2drVZAQSA=
+github.com/prometheus/common v0.52.3/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
+github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
+github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
-github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
-github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
+github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
+github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4=
@@ -99,8 +97,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
@@ -109,34 +107,31 @@ github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFi
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
-golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
-golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
-golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
-golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
-golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
-golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
-golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
+golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc=
+golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
+golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
-golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
-golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
-golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
+golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
-golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
-golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk=
-google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
-google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
-google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
+golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240412170617-26222e5d3d56 h1:zviK8GX4VlMstrK3JkexM5UHjH1VOkRebH9y3jhSBGk=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240412170617-26222e5d3d56/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
+google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
+google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
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 73f6dc4..c7ea491 100644
--- a/go.work
+++ b/go.work
@@ -1,4 +1,4 @@
-go 1.21.8
+go 1.22.4
use (
.
diff --git a/go.work.sum b/go.work.sum
index 41b9568..1d7941d 100644
--- a/go.work.sum
+++ b/go.work.sum
@@ -6,7 +6,10 @@ cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
cloud.google.com/go/bigquery v1.8.0 h1:PQcPefKFdaIzjQFbiyOgAqyx8q5djaE7x9Sqe712DPA=
cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk=
cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
+cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
+cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg=
+cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40=
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
@@ -51,6 +54,7 @@ github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjK
github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE=
github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU=
github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
+github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
@@ -100,7 +104,10 @@ github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nC
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY=
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
+github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
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=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d h1:t5Wuyh53qYyg9eqn4BbnlIT+vmhyww0TatL+zT3uWgI=
@@ -113,9 +120,13 @@ github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZi
github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E=
github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM=
github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
+github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI=
+github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
+github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
+github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
@@ -171,7 +182,10 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekf
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
+github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
+github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
+github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7 h1:2hRPrmiwPrp3fQX967rNJIhQPtiGXdlQWAxKbKw3VHA=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
@@ -200,7 +214,10 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+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/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
@@ -223,6 +240,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20220517205856-0058ec4f073c/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab h1:BA4a7pe6ZTd9F8kXETBoijjFJ/ntaa//1wiH9BZu4zU=
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
+github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465 h1:KwWnWVWCNtNq/ewIX7HIKnELmEx2nDP42yskD/pi7QE=
+github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
github.com/influxdata/influxdb v1.7.6 h1:8mQ7A/V+3noMGCt/P9pD09ISaiz9XvgCk303UYA3gcs=
github.com/iris-contrib/jade v1.1.4 h1:WoYdfyJFfZIUgqNAeOyRfTNQZOksSlZ6+FnXR3AEpX0=
github.com/iris-contrib/jade v1.1.4/go.mod h1:EDqR+ur9piDl6DUgs6qRrlfzmlx/D5UybogqrXvJTBE=
@@ -313,6 +332,7 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/microcosm-cc/bluemonday v1.0.1 h1:SIYunPjnlXcW+gVfvm0IlSeR5U3WZUOLfVmqg85Go44=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
@@ -424,6 +444,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -477,12 +499,15 @@ golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20221019170559-20944726eadf/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230306221820-f0f767cdffd6/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230807204917-050eac23e9de/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
+golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -514,6 +539,9 @@ golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
+golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -524,7 +552,10 @@ golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
+golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
+golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
+golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852 h1:xYq6+9AtI+xP3M4r0N1hCkHrInHDBohhquRgx9Kk6gI=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -553,7 +584,13 @@ golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808 h1:+Kc94D8UVEVxJnLXp/+FMfqQARZtWHfVrcRtcG8aT3g=
golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ=
+golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY=
+golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
@@ -568,7 +605,12 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
+golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
+golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
+golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
+golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
+golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
@@ -591,6 +633,7 @@ golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
@@ -604,6 +647,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -615,11 +659,16 @@ google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWof
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8=
google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0=
google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk=
-google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU=
-google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M=
+google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe h1:USL2DhxfgRchafRvt/wYyyQNzwgL7ZiURcozOE/Pkvo=
+google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
+google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
+google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
+google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
+google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0=
+google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
diff --git a/internal/access/engine_internal_test.go b/internal/access/engine_internal_test.go
index 53960f3..f053a95 100644
--- a/internal/access/engine_internal_test.go
+++ b/internal/access/engine_internal_test.go
@@ -71,7 +71,6 @@ func TestBlockedHostEngine_IsBlocked(t *testing.T) {
}}
for _, tc := range testCases {
- tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
@@ -90,7 +89,7 @@ func TestBlockedHostEngine_IsBlocked_concurrent(t *testing.T) {
engine := newBlockedHostEngine(rules)
wg := &sync.WaitGroup{}
- for i := 0; i < routinesLimit; i++ {
+ for i := range routinesLimit {
wg.Add(1)
host := fmt.Sprintf("%d.%s", i, "block.test")
diff --git a/internal/access/profile_test.go b/internal/access/profile_test.go
index 0d004aa..364d7b8 100644
--- a/internal/access/profile_test.go
+++ b/internal/access/profile_test.go
@@ -236,7 +236,7 @@ func BenchmarkDefaultProfile_IsBlocked(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
_ = a.IsBlocked(passReq, passAddrPort, nil)
}
})
@@ -247,7 +247,7 @@ func BenchmarkDefaultProfile_IsBlocked(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
_ = a.IsBlocked(blockReq, passAddrPort, nil)
}
})
diff --git a/internal/agd/device.go b/internal/agd/device.go
index a2b7c26..55d529c 100644
--- a/internal/agd/device.go
+++ b/internal/agd/device.go
@@ -5,6 +5,7 @@ import (
"net/netip"
"unicode/utf8"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
)
@@ -16,6 +17,9 @@ import (
// NOTE: Do not change fields of this structure without incrementing
// [internal/profiledb/internal.FileCacheVersion].
type Device struct {
+ // Auth defines authentication settings of this device. It's never nil.
+ Auth *AuthSettings
+
// ID is the unique ID of the device.
ID DeviceID
@@ -104,3 +108,20 @@ func NewDeviceName(s string) (n DeviceName, err error) {
return DeviceName(s), nil
}
+
+// AuthSettings are the authentication settings of a device.
+//
+// NOTE: Do not change fields of this structure without incrementing
+// [internal/profiledb/internal.FileCacheVersion].
+type AuthSettings struct {
+ // PasswordHash is the hash of the auth password. It is never nil.
+ PasswordHash agdpasswd.Authenticator
+
+ // Enabled tells whether the authentication should be enabled at all.
+ // This must be true in order for all parameters to work.
+ Enabled bool
+
+ // DoHAuthOnly defines if the device should only be authenticated through
+ // DoH protocol.
+ DoHAuthOnly bool
+}
diff --git a/internal/agd/device_test.go b/internal/agd/device_test.go
index 350ab49..ba46ee7 100644
--- a/internal/agd/device_test.go
+++ b/internal/agd/device_test.go
@@ -42,7 +42,6 @@ func TestNewDeviceName(t *testing.T) {
}}
for _, tc := range testCases {
- tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
diff --git a/internal/agd/filterlist.go b/internal/agd/filterlist.go
index 1c5cba0..cb81dda 100644
--- a/internal/agd/filterlist.go
+++ b/internal/agd/filterlist.go
@@ -17,33 +17,41 @@ const (
// FilterListIDNone means that no filter were applied at all.
FilterListIDNone FilterListID = ""
- // FilterListIDBlockedService is the shared filter list ID used when a
+ // FilterListIDBlockedService is the shared filter-list ID used when a
// request was blocked by the service blocker.
FilterListIDBlockedService FilterListID = "blocked_service"
- // FilterListIDCustom is the special shared filter list ID used when
+ // FilterListIDCustom is the special shared filter-list ID used when
// a request was filtered by a custom profile rule.
FilterListIDCustom FilterListID = "custom"
- // FilterListIDAdultBlocking is the special shared filter list ID used when
+ // FilterListIDAdultBlocking is the special shared filter-list ID used when
// a request was filtered by the adult content blocking filter.
FilterListIDAdultBlocking FilterListID = "adult_blocking"
- // FilterListIDSafeBrowsing is the special shared filter list ID used when
+ // FilterListIDSafeBrowsing is the special shared filter-list ID used when
// a request was filtered by the safe browsing filter.
FilterListIDSafeBrowsing FilterListID = "safe_browsing"
- // FilterListIDNewRegDomains is the special shared filter list ID used when
+ // FilterListIDNewRegDomains is the special shared filter-list ID used when
// a request was filtered by the newly registered domains filter.
FilterListIDNewRegDomains FilterListID = "newly_registered_domains"
- // FilterListIDGeneralSafeSearch is the shared filter list ID used when
+ // FilterListIDGeneralSafeSearch is the shared filter-list ID used when
// a request was modified by the general safe search filter.
FilterListIDGeneralSafeSearch FilterListID = "general_safe_search"
- // FilterListIDYoutubeSafeSearch is the special shared filter list ID used
+ // FilterListIDYoutubeSafeSearch is the special shared filter-list ID used
// when a request was modified by the YouTube safe search filter.
FilterListIDYoutubeSafeSearch FilterListID = "youtube_safe_search"
+
+ // FilterListIDAdGuardDNS is the special filter-list ID of the main AdGuard
+ // DNS filtering-rule list. For this list, rule statistics are collected.
+ FilterListIDAdGuardDNS FilterListID = "adguard_dns_filter"
+
+ // FilterListIDAdGuardPopup is the special filter-list ID of the AdGuard DNS
+ // list of popup domains.
+ FilterListIDAdGuardPopup FilterListID = "adguard_popup_filter"
)
// The maximum and minimum lengths of a filter list ID.
@@ -72,6 +80,21 @@ func NewFilterListID(s string) (id FilterListID, err error) {
return FilterListID(s), nil
}
+// SupportsDNSRewrite returns true if the $dnsrewrite rules in filtering-rule
+// lists with this ID should be processed.
+func (id FilterListID) SupportsDNSRewrite() (ok bool) {
+ switch id {
+ case
+ FilterListIDAdGuardPopup,
+ FilterListIDCustom,
+ FilterListIDGeneralSafeSearch,
+ FilterListIDYoutubeSafeSearch:
+ return true
+ default:
+ return false
+ }
+}
+
// FilterRuleText is the text of a single rule within a filter.
type FilterRuleText string
diff --git a/internal/agd/filterlist_test.go b/internal/agd/filterlist_test.go
index 993c162..4878a51 100644
--- a/internal/agd/filterlist_test.go
+++ b/internal/agd/filterlist_test.go
@@ -37,7 +37,6 @@ func TestNewFilterListID(t *testing.T) {
}}
for _, tc := range testCases {
- tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
@@ -86,7 +85,6 @@ func TestNewFilterRuleText(t *testing.T) {
}}
for _, tc := range testCases {
- tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
diff --git a/internal/agd/requestid_test.go b/internal/agd/requestid_test.go
index 700a4d8..5ef9e90 100644
--- a/internal/agd/requestid_test.go
+++ b/internal/agd/requestid_test.go
@@ -14,7 +14,7 @@ func BenchmarkNewRequestID(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
reqIDSink = agd.NewRequestID()
}
diff --git a/internal/agd/servergroup.go b/internal/agd/servergroup.go
index 51c7ba6..b379cff 100644
--- a/internal/agd/servergroup.go
+++ b/internal/agd/servergroup.go
@@ -2,23 +2,14 @@ package agd
import (
"crypto/tls"
- "fmt"
- "math"
- "net/netip"
- "github.com/AdguardTeam/golibs/stringutil"
+ "github.com/AdguardTeam/golibs/container"
"github.com/miekg/dns"
)
// ServerGroup is a group of DNS servers all of which use the same filtering
// settings.
type ServerGroup struct {
- // BlockPageRedirect is the configuration for the server group's block page.
- // BlockPageRedirect is never nil.
- //
- // TODO(a.garipov): Use.
- BlockPageRedirect *BlockPageRedirect
-
// DDR is the configuration for the server group's Discovery Of Designated
// Resolvers (DDR) handlers. DDR is never nil.
DDR *DDR
@@ -60,11 +51,11 @@ type TLS struct {
type DDR struct {
// DeviceTargets is the set of all domain names, subdomains of which should
// be checked for DDR queries with device IDs.
- DeviceTargets *stringutil.Set
+ DeviceTargets *container.MapSet[string]
// PublicTargets is the set of all public domain names, DDR queries for
// which should be processed.
- PublicTargets *stringutil.Set
+ PublicTargets *container.MapSet[string]
// DeviceRecordTemplates are used to respond to DDR queries from recognized
// devices.
@@ -78,81 +69,3 @@ type DDR struct {
// name queries receive an NXDOMAIN response.
Enabled bool
}
-
-// BlockPageRedirect is the configuration for a [ServerGroup]'s block page.
-type BlockPageRedirect struct {
- // Apply defines request parameters based on which the block page is shown
- // always. If a request matches Apply, both [BlockPageRedirect.Skip] and
- // [BlockPageRedirect.Probability] are ignored.
- //
- // If [BlockPageRedirect.Enabled] is true, Apply must not be nil.
- Apply *BlockPageRedirectApply
-
- // Skip defines request parameters based on which the block page is not
- // shown, regardless of [BlockPageRedirect.Probability].
- //
- // If [BlockPageRedirect.Enabled] is true, Skip must not be nil.
- Skip *BlockPageRedirectSkip
-
- // IPv4 are the IPv4 addresses of the block page, used to respond to A
- // queries.
- //
- // If [BlockPageRedirect.Enabled] is true, IPv4, [BlockPageRedirect.IPv6],
- // or both must be filled.
- IPv4 []netip.Addr
-
- // IPv6 are the IPv6 addresses of the block page, used to respond to AAAA
- // queries.
- //
- // If [BlockPageRedirect.Enabled] is true, [BlockPageRedirect.IPv4], IPv6,
- // or both must be filled.
- IPv6 []netip.Addr
-
- // Probability defines the probability of responding with the block page IPs
- // based on remote address. Probability must be between 0.0 and 1.0.
- Probability Probability
-
- // Enabled defines whether the block-page feature is enabled.
- Enabled bool
-}
-
-// Probability is a type for probabilities ranging from 0.0 to 1.0.
-type Probability float64
-
-// NewProbability returns a properly converted Probability or an error.
-func NewProbability(f float64) (prob Probability, err error) {
- if math.IsNaN(f) || f < 0.0 || f > 1.0 {
- return 0, fmt.Errorf("probability must be between 0.0 and 1.0; got %v", f)
- }
-
- return Probability(f), nil
-}
-
-// MustNewProbability returns a properly converted Probability or panics with an
-// error.
-func MustNewProbability(f float64) (prob Probability) {
- prob, err := NewProbability(f)
- if err != nil {
- panic(err)
- }
-
- return prob
-}
-
-// BlockPageRedirectApply defines the conditions for applying the block-page
-// logic for a particular request.
-type BlockPageRedirectApply struct {
- // ClientSubnets are the subnets for which block page is always enabled.
- ClientSubnets []netip.Prefix
-}
-
-// BlockPageRedirectSkip defines the conditions for skipping the block page
-// logic for a particular request.
-type BlockPageRedirectSkip struct {
- // ClientSubnets are the subnets for which block page is always disabled.
- ClientSubnets []netip.Prefix
-
- // QuestionDomains are the domain names for which block page is always
- // disabled.
- QuestionDomains []string
-}
diff --git a/internal/agdcache/agdcache.go b/internal/agdcache/agdcache.go
new file mode 100644
index 0000000..bf8261f
--- /dev/null
+++ b/internal/agdcache/agdcache.go
@@ -0,0 +1,59 @@
+// Package agdcache contains cache interfaces, helpers, and implementations.
+package agdcache
+
+import (
+ "time"
+)
+
+// Interface is the cache interface.
+type Interface[K, T any] interface {
+ // Set sets key and val as cache pair.
+ Set(key K, val T)
+
+ // SetWithExpire sets key and val as cache pair with expiration time.
+ SetWithExpire(key K, val T, expiration time.Duration)
+
+ // Get gets val from the cache using key.
+ Get(key K) (val T, ok bool)
+
+ // Clearer completely clears cache.
+ Clearer
+
+ // Len returns the number of items in the cache.
+ Len() (n int)
+}
+
+// Clearer is a partial cache interface.
+type Clearer interface {
+ // Clear completely clears cache.
+ Clear()
+}
+
+// Empty is an [Interface] implementation that does nothing.
+type Empty[K, T any] struct{}
+
+// type check
+var _ Interface[any, any] = Empty[any, any]{}
+
+// Set implements the [Interface] interface for Empty.
+func (c Empty[K, T]) Set(key K, val T) {}
+
+// SetWithExpire implements the [Interface] interface for Empty.
+func (c Empty[K, T]) SetWithExpire(key K, val T, expiration time.Duration) {}
+
+// Get implements the [Interface] interface for Empty.
+func (c Empty[K, T]) Get(key K) (val T, ok bool) {
+ return val, false
+}
+
+// type check
+var _ Clearer = Empty[any, any]{}
+
+// Clear implements the [Interface] interface for Empty.
+func (c Empty[K, T]) Clear() {}
+
+// Len implements the [Interface] interface for Empty. n may include items that
+// have expired, but have not yet been cleaned up.
+func (c Empty[K, T]) Len() (n int) {
+ return 0
+}
diff --git a/internal/agdcache/lru.go b/internal/agdcache/lru.go
new file mode 100644
index 0000000..228563a
--- /dev/null
+++ b/internal/agdcache/lru.go
@@ -0,0 +1,106 @@
+package agdcache
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/bluele/gcache"
+)
+
+// LRUConfig is a configuration structure of a cache.
+type LRUConfig struct {
+ Size int
+}
+
+// LRU is an [Interface] implementation.
+type LRU[K, T any] struct {
+ cache gcache.Cache
+}
+
+// NewLRU returns a new initialized LRU cache.
+func NewLRU[K, T any](conf *LRUConfig) (c *LRU[K, T]) {
+ return &LRU[K, T]{
+ cache: gcache.New(conf.Size).LRU().Build(),
+ }
+}
+
+// type check
+var _ Interface[any, any] = (*LRU[any, any])(nil)
+
+// Set implements the [Interface] interface for *LRU.
+func (c *LRU[K, T]) Set(key K, val T) {
+ err := c.cache.Set(key, val)
+ if err != nil {
+ // Shouldn't happen, since we don't set a serialization function.
+ panic(fmt.Errorf("agdcache: setting cache item: %w", err))
+ }
+}
+
+// SetWithExpire implements the [Interface] interface for *LRU.
+func (c *LRU[K, T]) SetWithExpire(key K, val T, expiration time.Duration) {
+ err := c.cache.SetWithExpire(key, val, expiration)
+ if err != nil {
+ // Shouldn't happen, since we don't set a serialization function.
+ panic(fmt.Errorf("agdcache: setting cache item with expiration: %w", err))
+ }
+}
+
+// Get implements the [Interface] interface for *LRU.
+func (c *LRU[K, T]) Get(key K) (val T, ok bool) {
+ v, err := c.cache.Get(key)
+ if err != nil {
+ if !errors.Is(err, gcache.KeyNotFoundError) {
+ // Shouldn't happen, since we don't set a serialization function.
+ panic(fmt.Errorf("agdcache: getting cache item: %w", err))
+ }
+
+ return val, false
+ }
+
+ // T may be an interface type, so check v against nil explicitly to prevent
+ // v.(T) below from panicking.
+ if v == nil {
+ return val, true
+ }
+
+ return v.(T), true
+}
+
+// type check
+var _ Clearer = (*LRU[any, any])(nil)
+
+// Clear implements the [Interface] interface for *LRU.
+func (c *LRU[K, T]) Clear() {
+ c.cache.Purge()
+}
+
+// Len implements the [Interface] interface for *LRU. n may include items
+// that have expired, but have not yet been cleaned up.
+func (c *LRU[K, T]) Len() (n int) {
+ const checkExpired = false
+
+ return c.cache.Len(checkExpired)
+}
+
+// Manager manages caches.
+type Manager struct {
+ caches map[string]Clearer
+}
+
+// NewManager returns a new initialized *Manager.
+func NewManager() (m *Manager) {
+ return &Manager{
+ caches: map[string]Clearer{},
+ }
+}
+
+// Add adds cache by id.
+func (m *Manager) Add(id string, cache Clearer) {
+ m.caches[id] = cache
+}
+
+// ClearByID clears cache by id.
+func (m *Manager) ClearByID(id string) {
+ m.caches[id].Clear()
+}
diff --git a/internal/agdcache/lru_test.go b/internal/agdcache/lru_test.go
new file mode 100644
index 0000000..e9161d4
--- /dev/null
+++ b/internal/agdcache/lru_test.go
@@ -0,0 +1,69 @@
+package agdcache_test
+
+import (
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLRU(t *testing.T) {
+ const (
+ key = "key"
+ val = 123
+
+ nonExistingKey = "nonExistingKey"
+ )
+
+ cache := agdcache.NewLRU[string, int](&agdcache.LRUConfig{
+ Size: 10,
+ })
+
+ 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())
+}
+
+func TestManager(t *testing.T) {
+ const (
+ key = "key"
+ val = 123
+ id = "cacheID"
+
+ nonExistingKey = "nonExistingKey"
+ )
+
+ cache := agdcache.NewLRU[string, int](&agdcache.LRUConfig{
+ Size: 10,
+ })
+
+ 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)
+
+ m := agdcache.NewManager()
+ m.Add(id, cache)
+ m.ClearByID(id)
+
+ assert.Equal(t, 0, cache.Len())
+}
diff --git a/internal/agdhttp/agdhttp.go b/internal/agdhttp/agdhttp.go
index b0a51a8..16ecc8f 100644
--- a/internal/agdhttp/agdhttp.go
+++ b/internal/agdhttp/agdhttp.go
@@ -15,6 +15,7 @@ import (
// HTTP header value constants.
const (
HdrValApplicationJSON = "application/json"
+ HdrValGzip = "gzip"
HdrValTextCSV = "text/csv"
HdrValTextHTML = "text/html"
HdrValTextPlain = "text/plain"
diff --git a/internal/agdhttp/client.go b/internal/agdhttp/client.go
index 75b6263..85a22a6 100644
--- a/internal/agdhttp/client.go
+++ b/internal/agdhttp/client.go
@@ -34,22 +34,18 @@ func NewClient(conf *ClientConfig) (c *Client) {
}
}
-// Get is a wrapper around http.Client.Get.
+// Get is a wrapper around [http.Client.Get].
//
// When err is nil, resp always contains a non-nil resp.Body. Caller should
// close resp.Body when done reading from it.
-//
-// See also go doc http.Client.Get.
func (c *Client) Get(ctx context.Context, u *url.URL) (resp *http.Response, err error) {
return c.do(ctx, http.MethodGet, u, "", nil)
}
-// Post is a wrapper around http.Client.Post.
+// Post is a wrapper around [http.Client.Post].
//
// When err is nil, resp always contains a non-nil resp.Body. Caller should
// close resp.Body when done reading from it.
-//
-// See also go doc http.Client.Post.
func (c *Client) Post(
ctx context.Context,
u *url.URL,
@@ -59,7 +55,7 @@ func (c *Client) Post(
return c.do(ctx, http.MethodPost, u, contentType, body)
}
-// Put is a wrapper around http.Client.Do.
+// Put is a wrapper around [http.Client.Put].
//
// When err is nil, resp always contains a non-nil resp.Body. Caller should
// close resp.Body when done reading from it.
@@ -72,7 +68,7 @@ func (c *Client) Put(
return c.do(ctx, http.MethodPut, u, contentType, body)
}
-// do is a wrapper around http.Client.Do.
+// do is a wrapper around [http.Client.Do].
func (c *Client) do(
ctx context.Context,
method string,
@@ -98,7 +94,8 @@ func (c *Client) do(
resp, err = c.http.Do(req)
if err != nil && resp != nil && resp.Header != nil {
- // A non-nil Response with a non-nil error only occurs when CheckRedirect fails.
+ // A non-nil Response with a non-nil error only occurs when
+ // CheckRedirect fails.
return resp, WrapServerError(err, resp)
}
diff --git a/internal/agdnet/resolver.go b/internal/agdnet/resolver.go
deleted file mode 100644
index 40875e3..0000000
--- a/internal/agdnet/resolver.go
+++ /dev/null
@@ -1,213 +0,0 @@
-package agdnet
-
-import (
- "context"
- "fmt"
- "math"
- "net"
- "net/netip"
- "sync"
- "time"
-
- "github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/log"
- "github.com/AdguardTeam/golibs/netutil"
-)
-
-// Resolver is the DNS resolver interface.
-//
-// See [net.Resolver].
-//
-// TODO(a.garipov): Move to golibs and unite with the one in module dnsproxy.
-type Resolver interface {
- // LookupNetIP returns a slice of host's IP addresses of family specified by
- // fam, which must be either [netutil.AddrFamilyIPv4] or
- // [netutil.AddrFamilyIPv6].
- LookupNetIP(
- ctx context.Context,
- fam netutil.AddrFamily,
- host string,
- ) (ips []netip.Addr, err error)
-}
-
-// DefaultResolver uses [net.DefaultResolver] to resolve addresses.
-type DefaultResolver struct{}
-
-// type check
-var _ Resolver = DefaultResolver{}
-
-// LookupNetIP implements the [Resolver] interface for DefaultResolver.
-func (DefaultResolver) LookupNetIP(
- ctx context.Context,
- fam netutil.AddrFamily,
- host string,
-) (ips []netip.Addr, err error) {
- switch fam {
- case netutil.AddrFamilyIPv4:
- return net.DefaultResolver.LookupNetIP(ctx, "ip4", host)
- case netutil.AddrFamilyIPv6:
- return net.DefaultResolver.LookupNetIP(ctx, "ip6", host)
- default:
- return nil, net.UnknownNetworkError(fam.String())
- }
-}
-
-// resolveCache is a simple address resolving cache.
-type resolveCache map[string]*resolveCacheItem
-
-// resolveCacheItem is an item of [resolveCache].
-type resolveCacheItem struct {
- refrTime time.Time
- ips []netip.Addr
-}
-
-// CachingResolver caches resolved results for hosts for a certain time,
-// regardless of the actual TTLs of the records. It is used for caching the
-// results of lookups of hostnames that don't change their IP addresses often.
-type CachingResolver struct {
- resolver Resolver
-
- // mu protects ip4 and ip6.
- mu *sync.Mutex
- ipv4 resolveCache
- ipv6 resolveCache
-
- ttl time.Duration
-}
-
-// NewCachingResolver returns a new caching resolver.
-func NewCachingResolver(resolver Resolver, ttl time.Duration) (c *CachingResolver) {
- return &CachingResolver{
- resolver: resolver,
-
- mu: &sync.Mutex{},
- ipv4: resolveCache{},
- ipv6: resolveCache{},
-
- ttl: ttl,
- }
-}
-
-// type check
-var _ Resolver = (*CachingResolver)(nil)
-
-// LookupNetIP implements the [Resolver] interface for *CachingResolver. host
-// should be normalized. Slice ips and its elements must not be mutated.
-func (c *CachingResolver) LookupNetIP(
- ctx context.Context,
- fam netutil.AddrFamily,
- host string,
-) (ips []netip.Addr, err error) {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- var item *resolveCacheItem
- switch fam {
- case netutil.AddrFamilyIPv4:
- item = c.ipv4[host]
- case netutil.AddrFamilyIPv6:
- item = c.ipv6[host]
- default:
- return nil, net.UnknownNetworkError(fam.String())
- }
-
- if item == nil || time.Since(item.refrTime) > c.ttl {
- item, err = c.resolve(ctx, fam, host)
- if err != nil {
- return nil, err
- }
- }
-
- return item.ips, nil
-}
-
-// resolve looks up the IP addresses for host and puts them into the cache.
-func (c *CachingResolver) resolve(
- ctx context.Context,
- fam netutil.AddrFamily,
- host string,
-) (item *resolveCacheItem, err error) {
- var ips []netip.Addr
-
- refrTime := time.Now()
-
- // Don't resolve IP addresses.
- ip := ipFromHost(host, fam)
- if ip != (netip.Addr{}) {
- ips = []netip.Addr{ip}
-
- // Set the refresh time to the maximum date that time.Duration allows to
- // prevent this item from refreshing.
- refrTime = time.Unix(0, math.MaxInt64)
- } else {
- ips, err = c.resolver.LookupNetIP(ctx, fam, host)
- if err != nil {
- if !isExpectedLookupError(fam, err) {
- return nil, fmt.Errorf("resolving %s addr for %q: %w", fam, host, err)
- }
-
- log.Debug("caching resolver: warning: %s", err)
- }
- }
-
- var cache resolveCache
- if fam == netutil.AddrFamilyIPv4 {
- cache = c.ipv4
- } else {
- cache = c.ipv6
- }
-
- item = &resolveCacheItem{
- refrTime: refrTime,
- ips: ips,
- }
-
- cache[host] = item
-
- return item, nil
-}
-
-// ipFromHost parses host as if it'd be an IP address of specified fam. It
-// returns an empty netip.
-func ipFromHost(host string, fam netutil.AddrFamily) (ip netip.Addr) {
- var famFunc func(netip.Addr) (ok bool)
- switch fam {
- case netutil.AddrFamilyIPv4:
- famFunc = netip.Addr.Is4
- case netutil.AddrFamilyIPv6:
- famFunc = netip.Addr.Is6
- default:
- return netip.Addr{}
- }
-
- ip, err := netip.ParseAddr(host)
- if err != nil || !famFunc(ip) {
- return netip.Addr{}
- }
-
- return ip
-}
-
-// isExpectedLookupError returns true if the error is an expected lookup error.
-func isExpectedLookupError(fam netutil.AddrFamily, err error) (ok bool) {
- var dnsErr *net.DNSError
- if fam == netutil.AddrFamilyIPv6 && errors.As(err, &dnsErr) {
- // It's expected that Go default DNS resolver returns a DNS error in
- // some cases when it receives an empty response. It's unclear what
- // exactly triggers this error, though.
- //
- // TODO(ameshkov): Consider researching this in detail.
- return true
- }
-
- var addrErr *net.AddrError
- if !errors.As(err, &addrErr) {
- return false
- }
-
- // Expect the error about no suitable addresses. For example, no IPv6
- // addresses for a host that does have IPv4 ones.
- //
- // See function filterAddrList in ${GOROOT}/src/net/ipsock.go.
- return addrErr.Err == "no suitable address found"
-}
diff --git a/internal/agdnet/resolver_test.go b/internal/agdnet/resolver_test.go
deleted file mode 100644
index cb4caf2..0000000
--- a/internal/agdnet/resolver_test.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package agdnet_test
-
-import (
- "context"
- "net/netip"
- "testing"
-
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
- "github.com/AdguardTeam/golibs/netutil"
- "github.com/AdguardTeam/golibs/timeutil"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestCachingResolver_Resolve(t *testing.T) {
- const testHost = "addr.example"
-
- var numLookups uint64
- wantIPv4 := []netip.Addr{netip.MustParseAddr("1.2.3.4")}
- wantIPv6 := []netip.Addr{netip.MustParseAddr("1234::5678")}
- r := &agdtest.Resolver{
- OnLookupNetIP: func(
- ctx context.Context,
- fam netutil.AddrFamily,
- host string,
- ) (ips []netip.Addr, err error) {
- numLookups++
-
- if fam == netutil.AddrFamilyIPv4 {
- return wantIPv4, nil
- }
-
- return nil, nil
- },
- }
-
- cached := agdnet.NewCachingResolver(r, 1*timeutil.Day)
-
- testCases := []struct {
- name string
- host string
- wantIPs []netip.Addr
- wantNum uint64
- fam netutil.AddrFamily
- }{{
- name: "initial",
- host: testHost,
- wantIPs: wantIPv4,
- wantNum: 1,
- fam: netutil.AddrFamilyIPv4,
- }, {
- name: "cached",
- host: testHost,
- wantIPs: wantIPv4,
- wantNum: 1,
- fam: netutil.AddrFamilyIPv4,
- }, {
- name: "other_network",
- host: testHost,
- wantIPs: nil,
- wantNum: 2,
- fam: netutil.AddrFamilyIPv6,
- }, {
- name: "ipv4",
- host: wantIPv4[0].String(),
- wantIPs: wantIPv4,
- wantNum: 2,
- fam: netutil.AddrFamilyIPv4,
- }, {
- name: "ipv6",
- host: wantIPv6[0].String(),
- wantIPs: wantIPv6,
- wantNum: 2,
- fam: netutil.AddrFamilyIPv6,
- }}
-
- ctx := context.Background()
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- got, err := cached.LookupNetIP(ctx, tc.fam, tc.host)
- require.NoError(t, err)
-
- assert.Equal(t, tc.wantNum, numLookups)
- assert.Equal(t, tc.wantIPs, got)
- })
- }
-}
diff --git a/internal/agdpasswd/authenticator.go b/internal/agdpasswd/authenticator.go
new file mode 100644
index 0000000..99ace5c
--- /dev/null
+++ b/internal/agdpasswd/authenticator.go
@@ -0,0 +1,51 @@
+// Package agdpasswd contains authentication utils.
+package agdpasswd
+
+import (
+ "context"
+
+ "golang.org/x/crypto/bcrypt"
+)
+
+// Authenticator represents a password authenticator.
+type Authenticator interface {
+ // Authenticate returns true if the given passwd is allowed.
+ Authenticate(ctx context.Context, passwd []byte) (ok bool)
+}
+
+// AllowAuthenticator is an empty authenticator implementation that always
+// grants access, regardless of any restrictions.
+type AllowAuthenticator struct{}
+
+// type check
+var _ Authenticator = AllowAuthenticator{}
+
+// Authenticate implements the [Authenticator] interface for AllowAuthenticator.
+func (AllowAuthenticator) Authenticate(_ context.Context, _ []byte) (ok bool) {
+ return true
+}
+
+// PasswordHashBcrypt is the Bcrypt implementation of [Authenticator].
+type PasswordHashBcrypt struct {
+ // bytes contains the password hash.
+ bytes []byte
+}
+
+// NewPasswordHashBcrypt returns a new bcrypt hashed password authenticator.
+func NewPasswordHashBcrypt(hashedPassword []byte) (p *PasswordHashBcrypt) {
+ return &PasswordHashBcrypt{bytes: hashedPassword}
+}
+
+// PasswordHash returns password hash bytes slice.
+func (p *PasswordHashBcrypt) PasswordHash() (b []byte) {
+ return p.bytes
+}
+
+// type check
+var _ Authenticator = (*PasswordHashBcrypt)(nil)
+
+// Authenticate implements the [Authenticator] interface for
+// *PasswordHashBcrypt.
+func (p *PasswordHashBcrypt) Authenticate(_ context.Context, passwd []byte) (ok bool) {
+ return bcrypt.CompareHashAndPassword(p.bytes, passwd) == nil
+}
diff --git a/internal/agdpasswd/authenticator_test.go b/internal/agdpasswd/authenticator_test.go
new file mode 100644
index 0000000..f61929c
--- /dev/null
+++ b/internal/agdpasswd/authenticator_test.go
@@ -0,0 +1,49 @@
+package agdpasswd_test
+
+import (
+ "context"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "golang.org/x/crypto/bcrypt"
+)
+
+func TestMain(m *testing.M) {
+ testutil.DiscardLogOutput(m)
+}
+
+func TestPasswordHashBcrypt_Authenticate(t *testing.T) {
+ t.Parallel()
+
+ const passwd = "mypassword"
+
+ hash, err := bcrypt.GenerateFromPassword([]byte(passwd), 0)
+ require.NoError(t, err)
+
+ authenticator := agdpasswd.NewPasswordHashBcrypt(hash)
+
+ testCases := []struct {
+ want assert.BoolAssertionFunc
+ name string
+ pass string
+ }{{
+ want: assert.True,
+ name: "success",
+ pass: passwd,
+ }, {
+ want: assert.False,
+ name: "fail",
+ pass: "an-other-passwd",
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ tc.want(t, authenticator.Authenticate(context.Background(), []byte(tc.pass)))
+ })
+ }
+}
diff --git a/internal/agdservice/refresh.go b/internal/agdservice/refresh.go
index 0ac590c..6456eeb 100644
--- a/internal/agdservice/refresh.go
+++ b/internal/agdservice/refresh.go
@@ -13,6 +13,10 @@ import (
// Refresher is the interface for entities that can update themselves.
type Refresher interface {
+ // Refresh is called by a [RefreshWorker]. The error returned by Refresh is
+ // only returned from [RefreshWorker.Shutdown] and only when
+ // [RefreshWorkerConfig.RefreshOnShutdown] is true. In all other cases, the
+ // error is ignored, and refreshers must handle error reporting themselves.
Refresh(ctx context.Context) (err error)
}
@@ -21,11 +25,9 @@ type Refresher interface {
type RefreshWorker struct {
done chan unit
context func() (ctx context.Context, cancel context.CancelFunc)
- logRoutine func(format string, args ...any)
tick *time.Ticker
rand *rand.Rand
refr Refresher
- errColl errcoll.Interface
name string
maxStartSleep time.Duration
@@ -40,12 +42,6 @@ type RefreshWorkerConfig struct {
// Refresher is the entity being refreshed.
Refresher Refresher
- // ErrColl is used to collect errors during refreshes.
- //
- // TODO(a.garipov): Remove this and make all Refreshers handle their own
- // errors.
- ErrColl errcoll.Interface
-
// Name is the name of this worker. It is used for logging and error
// collecting.
//
@@ -64,12 +60,6 @@ type RefreshWorkerConfig struct {
// that should persist to disk or remote storage before shutting down.
RefreshOnShutdown bool
- // RoutineLogsAreDebug, if true, instructs the worker to write initial and
- // final log messages for each singular refresh on the Debug level rather
- // than on the Info one. This is useful to prevent routine logs from
- // workers with a small interval from overflowing with messages.
- RoutineLogsAreDebug bool
-
// RandomizeStart, if true, instructs the worker to sleep before starting a
// refresh. The duration of the sleep is a random duration of up to 10 % of
// Interval.
@@ -82,14 +72,6 @@ type RefreshWorkerConfig struct {
// NewRefreshWorker returns a new valid *RefreshWorker with the provided
// parameters. c must not be nil.
func NewRefreshWorker(c *RefreshWorkerConfig) (w *RefreshWorker) {
- // TODO(a.garipov): Add log.WithLevel.
- var logRoutine func(format string, args ...any)
- if c.RoutineLogsAreDebug {
- logRoutine = log.Debug
- } else {
- logRoutine = log.Info
- }
-
var maxStartSleep time.Duration
var rng *rand.Rand
if c.RandomizeStart {
@@ -100,11 +82,9 @@ func NewRefreshWorker(c *RefreshWorkerConfig) (w *RefreshWorker) {
return &RefreshWorker{
done: make(chan unit),
context: c.Context,
- logRoutine: logRoutine,
tick: time.NewTicker(c.Interval),
rand: rng,
refr: c.Refresher,
- errColl: c.ErrColl,
name: c.Name,
maxStartSleep: maxStartSleep,
refrOnShutdown: c.RefreshOnShutdown,
@@ -172,7 +152,7 @@ func (w *RefreshWorker) sleepRandom() (shouldRefresh bool) {
}
sleepDur := time.Duration(w.rand.Int63n(int64(w.maxStartSleep)))
- w.logRoutine("worker %q: sleeping for %s before refresh", w.name, sleepDur)
+ log.Debug("worker %q: sleeping for %s before refresh", w.name, sleepDur)
timer := time.NewTimer(sleepDur)
defer func() {
@@ -197,24 +177,51 @@ func (w *RefreshWorker) sleepRandom() (shouldRefresh bool) {
// refresh refreshes the entity and logs the status of the refresh.
func (w *RefreshWorker) refresh() {
- name := w.name
- w.logRoutine("worker %q: refreshing", name)
-
// TODO(a.garipov): Consider adding a helper for enriching errors with
// context deadline data without duplication. See an example in method
// filter.refreshableFilter.refresh.
ctx, cancel := w.context()
defer cancel()
- log.Debug("worker %q: starting refresh", name)
- err := w.refr.Refresh(ctx)
- log.Debug("worker %q: finished refresh", name)
+ _ = w.refr.Refresh(ctx)
+}
+// RefresherWithErrColl reports all refresh errors to errColl and logs them
+// using a provided logging function.
+type RefresherWithErrColl struct {
+ refr Refresher
+ log func(format string, args ...any)
+ errColl errcoll.Interface
+ prefix string
+}
+
+// NewRefresherWithErrColl wraps refr into a refresher that collects errors and
+// logs them.
+func NewRefresherWithErrColl(
+ refr Refresher,
+ logFunc func(format string, args ...any),
+ errColl errcoll.Interface,
+ prefix string,
+) (wrapped *RefresherWithErrColl) {
+ return &RefresherWithErrColl{
+ refr: refr,
+ log: logFunc,
+ errColl: errColl,
+ prefix: prefix,
+ }
+}
+
+// type check
+var _ Refresher = (*RefresherWithErrColl)(nil)
+
+// Refresh implements the [Refresher] interface for *RefresherWithErrColl.
+func (r *RefresherWithErrColl) Refresh(ctx context.Context) (err error) {
+ err = r.refr.Refresh(ctx)
if err != nil {
- errcoll.Collectf(ctx, w.errColl, "%s: %w", name, err)
-
- return
+ err = fmt.Errorf("%s: %w", r.prefix, err)
+ r.log("%s", err)
+ r.errColl.Collect(ctx, err)
}
- w.logRoutine("worker %q: refreshed successfully", name)
+ return err
}
diff --git a/internal/agdservice/refresh_test.go b/internal/agdservice/refresh_test.go
index b1ebba7..0d8f41d 100644
--- a/internal/agdservice/refresh_test.go
+++ b/internal/agdservice/refresh_test.go
@@ -42,52 +42,39 @@ func newTestRefresher(t *testing.T, respErr error) (refr *agdtest.Refresher, syn
return refr, syncCh
}
-// newRefrConf returns worker configuration.
-func newRefrConf(
+// newRefrConfig returns worker configuration.
+func newRefrConfig(
t *testing.T,
refr agdservice.Refresher,
ivl time.Duration,
refrOnShutDown bool,
- errCh chan sig,
) (conf *agdservice.RefreshWorkerConfig) {
t.Helper()
- pt := testutil.PanicT{}
-
- errColl := &agdtest.ErrorCollector{
- OnCollect: func(_ context.Context, _ error) {
- testutil.RequireSend(pt, errCh, sig{}, testTimeout)
- },
- }
-
return &agdservice.RefreshWorkerConfig{
Context: func() (ctx context.Context, cancel context.CancelFunc) {
return context.WithTimeout(context.Background(), testTimeout)
},
- Refresher: refr,
- ErrColl: errColl,
- Name: name,
- Interval: ivl,
- RefreshOnShutdown: refrOnShutDown,
- RoutineLogsAreDebug: false,
- RandomizeStart: false,
+ Refresher: refr,
+ Name: name,
+ Interval: ivl,
+ RefreshOnShutdown: refrOnShutDown,
+ RandomizeStart: false,
}
}
func TestRefreshWorker(t *testing.T) {
t.Run("success", func(t *testing.T) {
refr, syncCh := newTestRefresher(t, nil)
- errCh := make(chan sig, 1)
- w := agdservice.NewRefreshWorker(newRefrConf(t, refr, testIvl, false, errCh))
+ w := agdservice.NewRefreshWorker(newRefrConfig(t, refr, testIvl, false))
- err := w.Start(agdtest.ContextWithTimeout(t, testTimeout))
+ err := w.Start(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
testutil.RequireReceive(t, syncCh, testTimeout)
- require.Empty(t, errCh)
- err = w.Shutdown(agdtest.ContextWithTimeout(t, testTimeout))
+ err = w.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
})
@@ -95,12 +82,12 @@ func TestRefreshWorker(t *testing.T) {
refr, syncCh := newTestRefresher(t, nil)
errCh := make(chan sig, 1)
- w := agdservice.NewRefreshWorker(newRefrConf(t, refr, testIvlLong, true, errCh))
+ w := agdservice.NewRefreshWorker(newRefrConfig(t, refr, testIvlLong, true))
- err := w.Start(agdtest.ContextWithTimeout(t, testTimeout))
+ err := w.Start(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
- err = w.Shutdown(agdtest.ContextWithTimeout(t, testTimeout))
+ err = w.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
testutil.RequireReceive(t, syncCh, testTimeout)
@@ -109,33 +96,29 @@ func TestRefreshWorker(t *testing.T) {
t.Run("error", func(t *testing.T) {
errRefr, syncCh := newTestRefresher(t, testError)
- errCh := make(chan sig, 1)
- w := agdservice.NewRefreshWorker(newRefrConf(t, errRefr, testIvl, false, errCh))
+ w := agdservice.NewRefreshWorker(newRefrConfig(t, errRefr, testIvl, false))
- err := w.Start(agdtest.ContextWithTimeout(t, testTimeout))
+ err := w.Start(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
testutil.RequireReceive(t, syncCh, testTimeout)
- testutil.RequireReceive(t, errCh, testTimeout)
- err = w.Shutdown(agdtest.ContextWithTimeout(t, testTimeout))
+ err = w.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
})
t.Run("error_on_shutdown", func(t *testing.T) {
errRefr, syncCh := newTestRefresher(t, testError)
- errCh := make(chan sig, 1)
- w := agdservice.NewRefreshWorker(newRefrConf(t, errRefr, testIvlLong, true, errCh))
+ w := agdservice.NewRefreshWorker(newRefrConfig(t, errRefr, testIvlLong, true))
- err := w.Start(agdtest.ContextWithTimeout(t, testTimeout))
+ err := w.Start(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
- err = w.Shutdown(agdtest.ContextWithTimeout(t, testTimeout))
+ err = w.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
assert.ErrorIs(t, err, testError)
testutil.RequireReceive(t, syncCh, testTimeout)
- require.Empty(t, errCh)
})
}
diff --git a/internal/agdtest/agdtest.go b/internal/agdtest/agdtest.go
index 60ac18d..2b7c652 100644
--- a/internal/agdtest/agdtest.go
+++ b/internal/agdtest/agdtest.go
@@ -3,8 +3,6 @@
package agdtest
import (
- "context"
- "testing"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
@@ -27,16 +25,3 @@ func NewConstructor() (c *dnsmsg.Constructor) {
func NewCloner() (c *dnsmsg.Cloner) {
return dnsmsg.NewCloner(dnsmsg.EmptyClonerStat{})
}
-
-// ContextWithTimeout is a helper that creates a new context with timeout and
-// registers ctx's cleanup with t.Cleanup.
-//
-// TODO(a.garipov): Move to golibs.
-func ContextWithTimeout(tb testing.TB, timeout time.Duration) (ctx context.Context) {
- tb.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), timeout)
- tb.Cleanup(cancel)
-
- return ctx
-}
diff --git a/internal/agdtest/interface.go b/internal/agdtest/interface.go
index 00b901c..c5cd63b 100644
--- a/internal/agdtest/interface.go
+++ b/internal/agdtest/interface.go
@@ -8,7 +8,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/billstat"
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
@@ -52,27 +52,20 @@ func (a *AccessManager) IsBlockedIP(ip netip.Addr) (blocked bool) {
return a.OnIsBlockedIP(ip)
}
-// Package agdnet
+// Package agdpasswd
// type check
-var _ agdnet.Resolver = (*Resolver)(nil)
+var _ agdpasswd.Authenticator = (*Authenticator)(nil)
-// Resolver is an [agdnet.Resolver] for tests.
-type Resolver struct {
- OnLookupNetIP func(
- ctx context.Context,
- fam netutil.AddrFamily,
- host string,
- ) (ips []netip.Addr, err error)
+// Authenticator is an [agdpasswd.Authenticator] for tests.
+type Authenticator struct {
+ OnAuthenticate func(ctx context.Context, passwd []byte) (ok bool)
}
-// LookupNetIP implements the [agdnet.Resolver] interface for *Resolver.
-func (r *Resolver) LookupNetIP(
- ctx context.Context,
- fam netutil.AddrFamily,
- host string,
-) (ips []netip.Addr, err error) {
- return r.OnLookupNetIP(ctx, fam, host)
+// Authenticate implements the [agdpasswd.Authenticator] interface for
+// *Authenticator.
+func (a *Authenticator) Authenticate(ctx context.Context, passwd []byte) (ok bool) {
+ return a.OnAuthenticate(ctx, passwd)
}
// Package agdservice
diff --git a/internal/backendpb/backend.pb.go b/internal/backendpb/backend.pb.go
index c1cdc32..dbbc954 100644
--- a/internal/backendpb/backend.pb.go
+++ b/internal/backendpb/backend.pb.go
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.31.0
-// protoc v4.25.1
+// protoc-gen-go v1.33.0
+// protoc v4.25.3
// source: backend.proto
package backendpb
@@ -359,11 +359,12 @@ type DeviceSettings struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
- Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
- FilteringEnabled bool `protobuf:"varint,3,opt,name=filtering_enabled,json=filteringEnabled,proto3" json:"filtering_enabled,omitempty"`
- LinkedIp []byte `protobuf:"bytes,4,opt,name=linked_ip,json=linkedIp,proto3" json:"linked_ip,omitempty"`
- DedicatedIps [][]byte `protobuf:"bytes,5,rep,name=dedicated_ips,json=dedicatedIps,proto3" json:"dedicated_ips,omitempty"`
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ FilteringEnabled bool `protobuf:"varint,3,opt,name=filtering_enabled,json=filteringEnabled,proto3" json:"filtering_enabled,omitempty"`
+ LinkedIp []byte `protobuf:"bytes,4,opt,name=linked_ip,json=linkedIp,proto3" json:"linked_ip,omitempty"`
+ DedicatedIps [][]byte `protobuf:"bytes,5,rep,name=dedicated_ips,json=dedicatedIps,proto3" json:"dedicated_ips,omitempty"`
+ Authentication *AuthenticationSettings `protobuf:"bytes,6,opt,name=authentication,proto3" json:"authentication,omitempty"`
}
func (x *DeviceSettings) Reset() {
@@ -433,6 +434,13 @@ func (x *DeviceSettings) GetDedicatedIps() [][]byte {
return nil
}
+func (x *DeviceSettings) GetAuthentication() *AuthenticationSettings {
+ if x != nil {
+ return x.Authentication
+ }
+ return nil
+}
+
type ParentalSettings struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1179,6 +1187,81 @@ func (x *CidrRange) GetPrefix() uint32 {
return 0
}
+type AuthenticationSettings struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ DohAuthOnly bool `protobuf:"varint,1,opt,name=doh_auth_only,json=dohAuthOnly,proto3" json:"doh_auth_only,omitempty"`
+ // Types that are assignable to DohPasswordHash:
+ //
+ // *AuthenticationSettings_PasswordHashBcrypt
+ DohPasswordHash isAuthenticationSettings_DohPasswordHash `protobuf_oneof:"doh_password_hash"`
+}
+
+func (x *AuthenticationSettings) Reset() {
+ *x = AuthenticationSettings{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_backend_proto_msgTypes[16]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *AuthenticationSettings) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AuthenticationSettings) ProtoMessage() {}
+
+func (x *AuthenticationSettings) ProtoReflect() protoreflect.Message {
+ mi := &file_backend_proto_msgTypes[16]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use AuthenticationSettings.ProtoReflect.Descriptor instead.
+func (*AuthenticationSettings) Descriptor() ([]byte, []int) {
+ return file_backend_proto_rawDescGZIP(), []int{16}
+}
+
+func (x *AuthenticationSettings) GetDohAuthOnly() bool {
+ if x != nil {
+ return x.DohAuthOnly
+ }
+ return false
+}
+
+func (m *AuthenticationSettings) GetDohPasswordHash() isAuthenticationSettings_DohPasswordHash {
+ if m != nil {
+ return m.DohPasswordHash
+ }
+ return nil
+}
+
+func (x *AuthenticationSettings) GetPasswordHashBcrypt() []byte {
+ if x, ok := x.GetDohPasswordHash().(*AuthenticationSettings_PasswordHashBcrypt); ok {
+ return x.PasswordHashBcrypt
+ }
+ return nil
+}
+
+type isAuthenticationSettings_DohPasswordHash interface {
+ isAuthenticationSettings_DohPasswordHash()
+}
+
+type AuthenticationSettings_PasswordHashBcrypt struct {
+ PasswordHashBcrypt []byte `protobuf:"bytes,2,opt,name=password_hash_bcrypt,json=passwordHashBcrypt,proto3,oneof"`
+}
+
+func (*AuthenticationSettings_PasswordHashBcrypt) isAuthenticationSettings_DohPasswordHash() {}
+
var File_backend_proto protoreflect.FileDescriptor
var file_backend_proto_rawDesc = []byte{
@@ -1263,7 +1346,7 @@ var file_backend_proto_rawDesc = []byte{
0x63, 0x6b, 0x44, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x6f, 0x75, 0x73, 0x44, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x72, 0x64, 0x18,
0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x72, 0x64, 0x22,
- 0xa3, 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
+ 0xe4, 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
@@ -1273,110 +1356,123 @@ var file_backend_proto_rawDesc = []byte{
0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x49, 0x70,
0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x69, 0x70,
0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74,
- 0x65, 0x64, 0x49, 0x70, 0x73, 0x22, 0x87, 0x02, 0x0a, 0x10, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74,
- 0x61, 0x6c, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e,
- 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61,
- 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x61, 0x64,
- 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
- 0x41, 0x64, 0x75, 0x6c, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
- 0x5f, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01,
- 0x28, 0x08, 0x52, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x53, 0x61, 0x66, 0x65, 0x53,
- 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x2e, 0x0a, 0x13, 0x79, 0x6f, 0x75, 0x74, 0x75, 0x62, 0x65,
- 0x5f, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01,
- 0x28, 0x08, 0x52, 0x11, 0x79, 0x6f, 0x75, 0x74, 0x75, 0x62, 0x65, 0x53, 0x61, 0x66, 0x65, 0x53,
- 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x29, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64,
- 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52,
- 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
- 0x12, 0x2d, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x53, 0x65, 0x74,
- 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x22,
- 0x54, 0x0a, 0x10, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69,
- 0x6e, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x6d, 0x7a, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x03, 0x74, 0x6d, 0x7a, 0x12, 0x2e, 0x0a, 0x0b, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x52,
- 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x57, 0x65, 0x65,
- 0x6b, 0x6c, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0b, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79,
- 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0xd8, 0x01, 0x0a, 0x0b, 0x57, 0x65, 0x65, 0x6b, 0x6c, 0x79,
- 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x03, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x6d,
- 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x03, 0x74, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x74, 0x75, 0x65, 0x12,
- 0x1b, 0x0a, 0x03, 0x77, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44,
- 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x77, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x03,
- 0x74, 0x68, 0x75, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52,
- 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x74, 0x68, 0x75, 0x12, 0x1b, 0x0a, 0x03, 0x66, 0x72, 0x69,
- 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67,
- 0x65, 0x52, 0x03, 0x66, 0x72, 0x69, 0x12, 0x1b, 0x0a, 0x03, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20,
+ 0x65, 0x64, 0x49, 0x70, 0x73, 0x12, 0x3f, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
+ 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65,
+ 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x87, 0x02, 0x0a, 0x10, 0x50, 0x61, 0x72, 0x65, 0x6e,
+ 0x74, 0x61, 0x6c, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65,
+ 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e,
+ 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x61,
+ 0x64, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63,
+ 0x6b, 0x41, 0x64, 0x75, 0x6c, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
+ 0x6c, 0x5f, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x08, 0x52, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x53, 0x61, 0x66, 0x65,
+ 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x2e, 0x0a, 0x13, 0x79, 0x6f, 0x75, 0x74, 0x75, 0x62,
+ 0x65, 0x5f, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x04, 0x20,
+ 0x01, 0x28, 0x08, 0x52, 0x11, 0x79, 0x6f, 0x75, 0x74, 0x75, 0x62, 0x65, 0x53, 0x61, 0x66, 0x65,
+ 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x29, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65,
+ 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09,
+ 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+ 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x06, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x53, 0x65,
+ 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
+ 0x22, 0x54, 0x0a, 0x10, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x53, 0x65, 0x74, 0x74,
+ 0x69, 0x6e, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x6d, 0x7a, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x03, 0x74, 0x6d, 0x7a, 0x12, 0x2e, 0x0a, 0x0b, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79,
+ 0x52, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x57, 0x65,
+ 0x65, 0x6b, 0x6c, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0b, 0x77, 0x65, 0x65, 0x6b, 0x6c,
+ 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0xd8, 0x01, 0x0a, 0x0b, 0x57, 0x65, 0x65, 0x6b, 0x6c,
+ 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x03, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03,
- 0x73, 0x61, 0x74, 0x12, 0x1b, 0x0a, 0x03, 0x73, 0x75, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x73, 0x75, 0x6e,
- 0x22, 0x68, 0x0a, 0x08, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x05,
- 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f,
+ 0x6d, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x03, 0x74, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x74, 0x75, 0x65,
+ 0x12, 0x1b, 0x0a, 0x03, 0x77, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e,
+ 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x77, 0x65, 0x64, 0x12, 0x1b, 0x0a,
+ 0x03, 0x74, 0x68, 0x75, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79,
+ 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x74, 0x68, 0x75, 0x12, 0x1b, 0x0a, 0x03, 0x66, 0x72,
+ 0x69, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e,
+ 0x67, 0x65, 0x52, 0x03, 0x66, 0x72, 0x69, 0x12, 0x1b, 0x0a, 0x03, 0x73, 0x61, 0x74, 0x18, 0x06,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52,
+ 0x03, 0x73, 0x61, 0x74, 0x12, 0x1b, 0x0a, 0x03, 0x73, 0x75, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x73, 0x75,
+ 0x6e, 0x22, 0x68, 0x0a, 0x08, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x2f, 0x0a,
+ 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44,
+ 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2b,
+ 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75,
- 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2b, 0x0a,
- 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f,
- 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x3f, 0x0a, 0x11, 0x52, 0x75,
- 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
- 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
- 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73,
- 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x3e, 0x0a, 0x14, 0x42,
- 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f,
- 0x6d, 0x49, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x36, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x36, 0x22, 0x16, 0x0a, 0x14, 0x42,
- 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x58, 0x44, 0x4f, 0x4d,
- 0x41, 0x49, 0x4e, 0x22, 0x14, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d,
- 0x6f, 0x64, 0x65, 0x4e, 0x75, 0x6c, 0x6c, 0x49, 0x50, 0x22, 0x15, 0x0a, 0x13, 0x42, 0x6c, 0x6f,
- 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x45, 0x46, 0x55, 0x53, 0x45, 0x44,
- 0x22, 0xe3, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x69, 0x6c, 0x6c, 0x69,
- 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x12, 0x48, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x61,
- 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10,
- 0x6c, 0x61, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x54, 0x69, 0x6d, 0x65,
- 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a,
- 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18,
- 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x75,
- 0x6e, 0x74, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x18, 0x04, 0x20,
- 0x01, 0x28, 0x0d, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73,
- 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x61, 0x73, 0x6e, 0x12, 0x18, 0x0a, 0x07,
- 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x71,
- 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0x90, 0x02, 0x0a, 0x0e, 0x41, 0x63, 0x63, 0x65, 0x73,
- 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x31, 0x0a, 0x0e, 0x61, 0x6c, 0x6c,
- 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28,
- 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x61,
- 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x69, 0x64, 0x72, 0x12, 0x31, 0x0a, 0x0e,
- 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02,
- 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65,
- 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x69, 0x64, 0x72, 0x12,
- 0x23, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e,
- 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73,
- 0x74, 0x41, 0x73, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73,
- 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x62, 0x6c, 0x6f,
- 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x62, 0x6c, 0x6f,
- 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x72, 0x75,
- 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
- 0x6c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12,
- 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08,
- 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x3d, 0x0a, 0x09, 0x43, 0x69, 0x64,
- 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
- 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
- 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
- 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x32, 0x8a, 0x01, 0x0a, 0x0a, 0x44, 0x4e, 0x53,
- 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x0e, 0x67, 0x65, 0x74, 0x44, 0x4e,
- 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x13, 0x2e, 0x44, 0x4e, 0x53, 0x50,
- 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b,
- 0x2e, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x30, 0x01, 0x12, 0x46, 0x0a,
- 0x16, 0x73, 0x61, 0x76, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x69, 0x6c, 0x6c,
- 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x12, 0x12, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
- 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
- 0x70, 0x74, 0x79, 0x28, 0x01, 0x42, 0x3d, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x64, 0x67,
- 0x75, 0x61, 0x72, 0x64, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x64, 0x6e, 0x73,
- 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x42, 0x10, 0x44, 0x4e, 0x53, 0x50,
- 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0xa2, 0x02,
- 0x03, 0x44, 0x4e, 0x53, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x3f, 0x0a, 0x11, 0x52,
+ 0x75, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
+ 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64,
+ 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x3e, 0x0a, 0x14,
+ 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x75, 0x73, 0x74,
+ 0x6f, 0x6d, 0x49, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x36,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x36, 0x22, 0x16, 0x0a, 0x14,
+ 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x58, 0x44, 0x4f,
+ 0x4d, 0x41, 0x49, 0x4e, 0x22, 0x14, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67,
+ 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x75, 0x6c, 0x6c, 0x49, 0x50, 0x22, 0x15, 0x0a, 0x13, 0x42, 0x6c,
+ 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x45, 0x46, 0x55, 0x53, 0x45,
+ 0x44, 0x22, 0xe3, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x69, 0x6c, 0x6c,
+ 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x12, 0x48, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x5f,
+ 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
+ 0x10, 0x6c, 0x61, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x54, 0x69, 0x6d,
+ 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25,
+ 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f,
+ 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x18, 0x04,
+ 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x61,
+ 0x73, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x61, 0x73, 0x6e, 0x12, 0x18, 0x0a,
+ 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07,
+ 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0x90, 0x02, 0x0a, 0x0e, 0x41, 0x63, 0x63, 0x65,
+ 0x73, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x31, 0x0a, 0x0e, 0x61, 0x6c,
+ 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x01, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d,
+ 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x69, 0x64, 0x72, 0x12, 0x31, 0x0a,
+ 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18,
+ 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67,
+ 0x65, 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x69, 0x64, 0x72,
+ 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x73,
+ 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69,
+ 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69,
+ 0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x62, 0x6c,
+ 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x62, 0x6c,
+ 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x72,
+ 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x62, 0x6c, 0x6f, 0x63,
+ 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73,
+ 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28,
+ 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x3d, 0x0a, 0x09, 0x43, 0x69,
+ 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
+ 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
+ 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x85, 0x01, 0x0a, 0x16, 0x41, 0x75,
+ 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74,
+ 0x69, 0x6e, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x64, 0x6f, 0x68, 0x5f, 0x61, 0x75, 0x74, 0x68,
+ 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x64, 0x6f, 0x68,
+ 0x41, 0x75, 0x74, 0x68, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x61, 0x73, 0x73,
+ 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x62, 0x63, 0x72, 0x79, 0x70, 0x74,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x12, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
+ 0x72, 0x64, 0x48, 0x61, 0x73, 0x68, 0x42, 0x63, 0x72, 0x79, 0x70, 0x74, 0x42, 0x13, 0x0a, 0x11,
+ 0x64, 0x6f, 0x68, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73,
+ 0x68, 0x32, 0x8a, 0x01, 0x0a, 0x0a, 0x44, 0x4e, 0x53, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+ 0x12, 0x34, 0x0a, 0x0e, 0x67, 0x65, 0x74, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
+ 0x65, 0x73, 0x12, 0x13, 0x2e, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f,
+ 0x66, 0x69, 0x6c, 0x65, 0x30, 0x01, 0x12, 0x46, 0x0a, 0x16, 0x73, 0x61, 0x76, 0x65, 0x44, 0x65,
+ 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74,
+ 0x12, 0x12, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67,
+ 0x53, 0x74, 0x61, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x42, 0x3d,
+ 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x64, 0x67, 0x75, 0x61, 0x72, 0x64, 0x2e, 0x62, 0x61,
+ 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
+ 0x74, 0x65, 0x64, 0x42, 0x10, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73,
+ 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0xa2, 0x02, 0x03, 0x44, 0x4e, 0x53, 0x62, 0x06, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1391,63 +1487,65 @@ func file_backend_proto_rawDescGZIP() []byte {
return file_backend_proto_rawDescData
}
-var file_backend_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
+var file_backend_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
var file_backend_proto_goTypes = []interface{}{
- (*DNSProfilesRequest)(nil), // 0: DNSProfilesRequest
- (*DNSProfile)(nil), // 1: DNSProfile
- (*SafeBrowsingSettings)(nil), // 2: SafeBrowsingSettings
- (*DeviceSettings)(nil), // 3: DeviceSettings
- (*ParentalSettings)(nil), // 4: ParentalSettings
- (*ScheduleSettings)(nil), // 5: ScheduleSettings
- (*WeeklyRange)(nil), // 6: WeeklyRange
- (*DayRange)(nil), // 7: DayRange
- (*RuleListsSettings)(nil), // 8: RuleListsSettings
- (*BlockingModeCustomIP)(nil), // 9: BlockingModeCustomIP
- (*BlockingModeNXDOMAIN)(nil), // 10: BlockingModeNXDOMAIN
- (*BlockingModeNullIP)(nil), // 11: BlockingModeNullIP
- (*BlockingModeREFUSED)(nil), // 12: BlockingModeREFUSED
- (*DeviceBillingStat)(nil), // 13: DeviceBillingStat
- (*AccessSettings)(nil), // 14: AccessSettings
- (*CidrRange)(nil), // 15: CidrRange
- (*timestamppb.Timestamp)(nil), // 16: google.protobuf.Timestamp
- (*durationpb.Duration)(nil), // 17: google.protobuf.Duration
- (*emptypb.Empty)(nil), // 18: google.protobuf.Empty
+ (*DNSProfilesRequest)(nil), // 0: DNSProfilesRequest
+ (*DNSProfile)(nil), // 1: DNSProfile
+ (*SafeBrowsingSettings)(nil), // 2: SafeBrowsingSettings
+ (*DeviceSettings)(nil), // 3: DeviceSettings
+ (*ParentalSettings)(nil), // 4: ParentalSettings
+ (*ScheduleSettings)(nil), // 5: ScheduleSettings
+ (*WeeklyRange)(nil), // 6: WeeklyRange
+ (*DayRange)(nil), // 7: DayRange
+ (*RuleListsSettings)(nil), // 8: RuleListsSettings
+ (*BlockingModeCustomIP)(nil), // 9: BlockingModeCustomIP
+ (*BlockingModeNXDOMAIN)(nil), // 10: BlockingModeNXDOMAIN
+ (*BlockingModeNullIP)(nil), // 11: BlockingModeNullIP
+ (*BlockingModeREFUSED)(nil), // 12: BlockingModeREFUSED
+ (*DeviceBillingStat)(nil), // 13: DeviceBillingStat
+ (*AccessSettings)(nil), // 14: AccessSettings
+ (*CidrRange)(nil), // 15: CidrRange
+ (*AuthenticationSettings)(nil), // 16: AuthenticationSettings
+ (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp
+ (*durationpb.Duration)(nil), // 18: google.protobuf.Duration
+ (*emptypb.Empty)(nil), // 19: google.protobuf.Empty
}
var file_backend_proto_depIdxs = []int32{
- 16, // 0: DNSProfilesRequest.sync_time:type_name -> google.protobuf.Timestamp
+ 17, // 0: DNSProfilesRequest.sync_time:type_name -> google.protobuf.Timestamp
2, // 1: DNSProfile.safe_browsing:type_name -> SafeBrowsingSettings
4, // 2: DNSProfile.parental:type_name -> ParentalSettings
8, // 3: DNSProfile.rule_lists:type_name -> RuleListsSettings
3, // 4: DNSProfile.devices:type_name -> DeviceSettings
- 17, // 5: DNSProfile.filtered_response_ttl:type_name -> google.protobuf.Duration
+ 18, // 5: DNSProfile.filtered_response_ttl:type_name -> google.protobuf.Duration
9, // 6: DNSProfile.blocking_mode_custom_ip:type_name -> BlockingModeCustomIP
10, // 7: DNSProfile.blocking_mode_nxdomain:type_name -> BlockingModeNXDOMAIN
11, // 8: DNSProfile.blocking_mode_null_ip:type_name -> BlockingModeNullIP
12, // 9: DNSProfile.blocking_mode_refused:type_name -> BlockingModeREFUSED
14, // 10: DNSProfile.access:type_name -> AccessSettings
- 5, // 11: ParentalSettings.schedule:type_name -> ScheduleSettings
- 6, // 12: ScheduleSettings.weeklyRange:type_name -> WeeklyRange
- 7, // 13: WeeklyRange.mon:type_name -> DayRange
- 7, // 14: WeeklyRange.tue:type_name -> DayRange
- 7, // 15: WeeklyRange.wed:type_name -> DayRange
- 7, // 16: WeeklyRange.thu:type_name -> DayRange
- 7, // 17: WeeklyRange.fri:type_name -> DayRange
- 7, // 18: WeeklyRange.sat:type_name -> DayRange
- 7, // 19: WeeklyRange.sun:type_name -> DayRange
- 17, // 20: DayRange.start:type_name -> google.protobuf.Duration
- 17, // 21: DayRange.end:type_name -> google.protobuf.Duration
- 16, // 22: DeviceBillingStat.last_activity_time:type_name -> google.protobuf.Timestamp
- 15, // 23: AccessSettings.allowlist_cidr:type_name -> CidrRange
- 15, // 24: AccessSettings.blocklist_cidr:type_name -> CidrRange
- 0, // 25: DNSService.getDNSProfiles:input_type -> DNSProfilesRequest
- 13, // 26: DNSService.saveDevicesBillingStat:input_type -> DeviceBillingStat
- 1, // 27: DNSService.getDNSProfiles:output_type -> DNSProfile
- 18, // 28: DNSService.saveDevicesBillingStat:output_type -> google.protobuf.Empty
- 27, // [27:29] is the sub-list for method output_type
- 25, // [25:27] is the sub-list for method input_type
- 25, // [25:25] is the sub-list for extension type_name
- 25, // [25:25] is the sub-list for extension extendee
- 0, // [0:25] is the sub-list for field type_name
+ 16, // 11: DeviceSettings.authentication:type_name -> AuthenticationSettings
+ 5, // 12: ParentalSettings.schedule:type_name -> ScheduleSettings
+ 6, // 13: ScheduleSettings.weeklyRange:type_name -> WeeklyRange
+ 7, // 14: WeeklyRange.mon:type_name -> DayRange
+ 7, // 15: WeeklyRange.tue:type_name -> DayRange
+ 7, // 16: WeeklyRange.wed:type_name -> DayRange
+ 7, // 17: WeeklyRange.thu:type_name -> DayRange
+ 7, // 18: WeeklyRange.fri:type_name -> DayRange
+ 7, // 19: WeeklyRange.sat:type_name -> DayRange
+ 7, // 20: WeeklyRange.sun:type_name -> DayRange
+ 18, // 21: DayRange.start:type_name -> google.protobuf.Duration
+ 18, // 22: DayRange.end:type_name -> google.protobuf.Duration
+ 17, // 23: DeviceBillingStat.last_activity_time:type_name -> google.protobuf.Timestamp
+ 15, // 24: AccessSettings.allowlist_cidr:type_name -> CidrRange
+ 15, // 25: AccessSettings.blocklist_cidr:type_name -> CidrRange
+ 0, // 26: DNSService.getDNSProfiles:input_type -> DNSProfilesRequest
+ 13, // 27: DNSService.saveDevicesBillingStat:input_type -> DeviceBillingStat
+ 1, // 28: DNSService.getDNSProfiles:output_type -> DNSProfile
+ 19, // 29: DNSService.saveDevicesBillingStat:output_type -> google.protobuf.Empty
+ 28, // [28:30] is the sub-list for method output_type
+ 26, // [26:28] is the sub-list for method input_type
+ 26, // [26:26] is the sub-list for extension type_name
+ 26, // [26:26] is the sub-list for extension extendee
+ 0, // [0:26] is the sub-list for field type_name
}
func init() { file_backend_proto_init() }
@@ -1648,6 +1746,18 @@ func file_backend_proto_init() {
return nil
}
}
+ file_backend_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*AuthenticationSettings); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
}
file_backend_proto_msgTypes[1].OneofWrappers = []interface{}{
(*DNSProfile_BlockingModeCustomIp)(nil),
@@ -1655,13 +1765,16 @@ func file_backend_proto_init() {
(*DNSProfile_BlockingModeNullIp)(nil),
(*DNSProfile_BlockingModeRefused)(nil),
}
+ file_backend_proto_msgTypes[16].OneofWrappers = []interface{}{
+ (*AuthenticationSettings_PasswordHashBcrypt)(nil),
+ }
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_backend_proto_rawDesc,
NumEnums: 0,
- NumMessages: 16,
+ NumMessages: 17,
NumExtensions: 0,
NumServices: 1,
},
diff --git a/internal/backendpb/backend.proto b/internal/backendpb/backend.proto
index c759b06..2dc0bcd 100644
--- a/internal/backendpb/backend.proto
+++ b/internal/backendpb/backend.proto
@@ -66,6 +66,7 @@ message DeviceSettings {
bool filtering_enabled = 3;
bytes linked_ip = 4;
repeated bytes dedicated_ips = 5;
+ AuthenticationSettings authentication = 6;
}
message ParentalSettings {
@@ -136,3 +137,10 @@ message CidrRange {
bytes address = 1;
uint32 prefix = 2;
}
+
+message AuthenticationSettings {
+ bool doh_auth_only = 1;
+ oneof doh_password_hash {
+ bytes password_hash_bcrypt = 2;
+ }
+}
diff --git a/internal/backendpb/backend_grpc.pb.go b/internal/backendpb/backend_grpc.pb.go
index 0a249aa..34874b1 100644
--- a/internal/backendpb/backend_grpc.pb.go
+++ b/internal/backendpb/backend_grpc.pb.go
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
-// - protoc v4.25.1
+// - protoc v4.25.3
// source: backend.proto
package backendpb
diff --git a/internal/backendpb/profiledb.go b/internal/backendpb/profiledb.go
index 1ae0d8f..450619c 100644
--- a/internal/backendpb/profiledb.go
+++ b/internal/backendpb/profiledb.go
@@ -11,6 +11,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdprotobuf"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
@@ -355,6 +356,37 @@ func (x *ScheduleSettings) toInternal() (sch *agd.ParentalProtectionSchedule, er
return sch, nil
}
+// toInternal converts a protobuf custom blocking-mode to an internal one.
+// Assumes that at least one IP address is specified in the result blocking-mode
+// object.
+func (pbm *BlockingModeCustomIP) toInternal() (m dnsmsg.BlockingMode, err error) {
+ custom := &dnsmsg.BlockingModeCustomIP{}
+
+ // TODO(a.garipov): Only one IPv4 address is supported on protobuf side.
+ var ipv4Addr netip.Addr
+ err = ipv4Addr.UnmarshalBinary(pbm.Ipv4)
+ if err != nil {
+ return nil, fmt.Errorf("bad custom ipv4: %w", err)
+ } else if ipv4Addr.IsValid() {
+ custom.IPv4 = []netip.Addr{ipv4Addr}
+ }
+
+ // TODO(a.garipov): Only one IPv6 address is supported on protobuf side.
+ var ipv6Addr netip.Addr
+ err = ipv6Addr.UnmarshalBinary(pbm.Ipv6)
+ if err != nil {
+ return nil, fmt.Errorf("bad custom ipv6: %w", err)
+ } else if ipv6Addr.IsValid() {
+ custom.IPv6 = []netip.Addr{ipv6Addr}
+ }
+
+ if len(custom.IPv4)+len(custom.IPv6) == 0 {
+ return nil, errors.Error("no valid custom ips found")
+ }
+
+ return custom, nil
+}
+
// blockingModeToInternal converts a protobuf blocking-mode sum-type to an
// internal one. If pbm is nil, blockingModeToInternal returns a null-IP
// blocking mode.
@@ -363,18 +395,7 @@ func blockingModeToInternal(pbm isDNSProfile_BlockingMode) (m dnsmsg.BlockingMod
case nil:
return &dnsmsg.BlockingModeNullIP{}, nil
case *DNSProfile_BlockingModeCustomIp:
- custom := &dnsmsg.BlockingModeCustomIP{}
- err = custom.IPv4.UnmarshalBinary(pbm.BlockingModeCustomIp.Ipv4)
- if err != nil {
- return nil, fmt.Errorf("bad custom ipv4: %w", err)
- }
-
- err = custom.IPv6.UnmarshalBinary(pbm.BlockingModeCustomIp.Ipv6)
- if err != nil {
- return nil, fmt.Errorf("bad custom ipv6: %w", err)
- }
-
- return custom, nil
+ return pbm.BlockingModeCustomIp.toInternal()
case *DNSProfile_BlockingModeNxdomain:
return &dnsmsg.BlockingModeNXDOMAIN{}, nil
case *DNSProfile_BlockingModeNullIp:
@@ -443,6 +464,11 @@ func (ds *DeviceSettings) toInternal(bindSet netutil.SubnetSet) (dev *agd.Device
}
}
+ auth, err := ds.Authentication.toInternal()
+ if err != nil {
+ return nil, fmt.Errorf("auth: %s: %w", ds.Id, err)
+ }
+
id, err := agd.NewDeviceID(ds.Id)
if err != nil {
return nil, fmt.Errorf("device id: %s: %w", ds.Id, err)
@@ -454,6 +480,7 @@ func (ds *DeviceSettings) toInternal(bindSet netutil.SubnetSet) (dev *agd.Device
}
return &agd.Device{
+ Auth: auth,
ID: id,
Name: name,
LinkedIP: linkedIP,
@@ -462,6 +489,44 @@ func (ds *DeviceSettings) toInternal(bindSet netutil.SubnetSet) (dev *agd.Device
}, nil
}
+// toInternal converts a protobuf auth settings structure to an internal one.
+// If x is nil, toInternal returns non-nil settings with enabled field set to
+// false.
+func (x *AuthenticationSettings) toInternal() (s *agd.AuthSettings, err error) {
+ if x == nil {
+ return &agd.AuthSettings{
+ Enabled: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ }, nil
+ }
+
+ ph, err := dohPasswordToInternal(x.DohPasswordHash)
+ if err != nil {
+ return nil, fmt.Errorf("password hash: %w", err)
+ }
+
+ return &agd.AuthSettings{
+ PasswordHash: ph,
+ Enabled: true,
+ DoHAuthOnly: x.DohAuthOnly,
+ }, nil
+}
+
+// dohPasswordToInternal converts a protobuf DoH password hash sum-type to an
+// internal one.
+func dohPasswordToInternal(
+ pbp isAuthenticationSettings_DohPasswordHash,
+) (p agdpasswd.Authenticator, err error) {
+ switch pbp := pbp.(type) {
+ case nil:
+ return agdpasswd.AllowAuthenticator{}, nil
+ case *AuthenticationSettings_PasswordHashBcrypt:
+ return agdpasswd.NewPasswordHashBcrypt(pbp.PasswordHashBcrypt), nil
+ default:
+ return nil, fmt.Errorf("bad pb auth doh password hash %T(%[1]v)", pbp)
+ }
+}
+
// rulesToInternal is a helper that converts the filter rules from the backend
// response to AdGuard DNS filtering rules.
func rulesToInternal(
diff --git a/internal/backendpb/profiledb_internal_test.go b/internal/backendpb/profiledb_internal_test.go
index 000197e..055aeb6 100644
--- a/internal/backendpb/profiledb_internal_test.go
+++ b/internal/backendpb/profiledb_internal_test.go
@@ -9,6 +9,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
@@ -92,7 +93,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
assert.NotEqual(t, newProfile(t), got)
assert.NotEqual(t, newDevices(t), gotDevices)
- assert.Len(t, gotDevices, 1)
+ assert.Len(t, gotDevices, 2)
})
t.Run("empty", func(t *testing.T) {
@@ -153,6 +154,16 @@ func TestDNSProfile_ToInternal(t *testing.T) {
testutil.AssertErrorMsg(t, "blocking mode: bad custom ipv6: unexpected slice size", err)
})
+ t.Run("nil_ips_blocking_mode", func(t *testing.T) {
+ dp := NewTestDNSProfile(t)
+ bm := dp.BlockingMode.(*DNSProfile_BlockingModeCustomIp)
+ bm.BlockingModeCustomIp.Ipv4 = nil
+ bm.BlockingModeCustomIp.Ipv6 = nil
+
+ _, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
+ testutil.AssertErrorMsg(t, "blocking mode: no valid custom ips found", err)
+ })
+
t.Run("nil_blocking_mode", func(t *testing.T) {
dp := NewTestDNSProfile(t)
dp.BlockingMode = nil
@@ -244,17 +255,33 @@ func NewTestDNSProfile(tb testing.TB) (dp *DNSProfile) {
}
devices := []*DeviceSettings{{
- Id: "118ffe93",
- Name: "118ffe93-name",
+ Id: "1111aaaa",
+ Name: "1111aaaa-name",
FilteringEnabled: false,
LinkedIp: ipToBytes(tb, netip.MustParseAddr("1.1.1.1")),
DedicatedIps: [][]byte{ipToBytes(tb, netip.MustParseAddr("1.1.1.2"))},
}, {
- Id: "b9e1a762",
- Name: "b9e1a762-name",
+ Id: "2222bbbb",
+ Name: "2222bbbb-name",
FilteringEnabled: true,
LinkedIp: ipToBytes(tb, netip.MustParseAddr("2.2.2.2")),
DedicatedIps: nil,
+ Authentication: &AuthenticationSettings{
+ DohAuthOnly: true,
+ DohPasswordHash: &AuthenticationSettings_PasswordHashBcrypt{
+ PasswordHashBcrypt: []byte("test-hash"),
+ },
+ },
+ }, {
+ Id: "3333cccc",
+ Name: "3333cccc-name",
+ FilteringEnabled: false,
+ LinkedIp: ipToBytes(tb, netip.MustParseAddr("3.3.3.3")),
+ DedicatedIps: nil,
+ Authentication: &AuthenticationSettings{
+ DohAuthOnly: false,
+ DohPasswordHash: nil,
+ },
}}
return &DNSProfile{
@@ -358,8 +385,8 @@ func newProfile(tb testing.TB) (p *agd.Profile) {
}
wantBlockingMode := &dnsmsg.BlockingModeCustomIP{
- IPv4: netip.MustParseAddr("1.2.3.4"),
- IPv6: netip.MustParseAddr("1234::cdef"),
+ IPv4: []netip.Addr{netip.MustParseAddr("1.2.3.4")},
+ IPv6: []netip.Addr{netip.MustParseAddr("1234::cdef")},
}
wantAccess := access.NewDefaultProfile(&access.ProfileConfig{
@@ -376,8 +403,9 @@ func newProfile(tb testing.TB) (p *agd.Profile) {
ID: testProfileID,
UpdateTime: TestUpdTime,
DeviceIDs: []agd.DeviceID{
- "118ffe93",
- "b9e1a762",
+ "1111aaaa",
+ "2222bbbb",
+ "3333cccc",
},
RuleListIDs: []agd.FilterListID{"1"},
CustomRules: []agd.FilterRuleText{"||example.org^"},
@@ -399,17 +427,38 @@ func newDevices(t *testing.T) (d []*agd.Device) {
t.Helper()
return []*agd.Device{{
- ID: "118ffe93",
+ Auth: &agd.AuthSettings{
+ Enabled: false,
+ DoHAuthOnly: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ },
+ ID: "1111aaaa",
LinkedIP: netip.MustParseAddr("1.1.1.1"),
- Name: "118ffe93-name",
+ Name: "1111aaaa-name",
DedicatedIPs: []netip.Addr{netip.MustParseAddr("1.1.1.2")},
FilteringEnabled: false,
}, {
- ID: "b9e1a762",
+ Auth: &agd.AuthSettings{
+ Enabled: true,
+ DoHAuthOnly: true,
+ PasswordHash: agdpasswd.NewPasswordHashBcrypt([]byte("test-hash")),
+ },
+ ID: "2222bbbb",
LinkedIP: netip.MustParseAddr("2.2.2.2"),
- Name: "b9e1a762-name",
+ Name: "2222bbbb-name",
DedicatedIPs: nil,
FilteringEnabled: true,
+ }, {
+ Auth: &agd.AuthSettings{
+ Enabled: true,
+ DoHAuthOnly: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ },
+ ID: "3333cccc",
+ LinkedIP: netip.MustParseAddr("3.3.3.3"),
+ Name: "3333cccc-name",
+ DedicatedIPs: nil,
+ FilteringEnabled: false,
}}
}
@@ -479,7 +528,7 @@ func BenchmarkDNSProfile_ToInternal(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
profSink, _, errSink = dp.toInternal(ctx, TestUpdTime, testBind, errColl)
}
diff --git a/internal/backendpb/profiledb_test.go b/internal/backendpb/profiledb_test.go
index 90cdbf0..dee6ee6 100644
--- a/internal/backendpb/profiledb_test.go
+++ b/internal/backendpb/profiledb_test.go
@@ -81,7 +81,7 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
respSink, errSink = s.Profiles(ctx, req)
}
diff --git a/internal/billstat/runtime.go b/internal/billstat/runtime.go
index 4901a28..bc5a0aa 100644
--- a/internal/billstat/runtime.go
+++ b/internal/billstat/runtime.go
@@ -2,12 +2,12 @@ package billstat
import (
"context"
- "fmt"
"sync"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/log"
@@ -18,6 +18,9 @@ import (
// RuntimeRecorderConfig is the configuration structure for a runtime billing
// statistics recorder. All fields must be non-empty.
type RuntimeRecorderConfig struct {
+ // ErrColl is used to collect errors during refreshes.
+ ErrColl errcoll.Interface
+
// Uploader is used to upload the billing statistics records to.
Uploader Uploader
}
@@ -29,6 +32,7 @@ func NewRuntimeRecorder(c *RuntimeRecorderConfig) (r *RuntimeRecorder) {
mu: &sync.Mutex{},
records: Records{},
uploader: c.Uploader,
+ errColl: c.ErrColl,
}
}
@@ -44,6 +48,9 @@ type RuntimeRecorder struct {
// uploader is the uploader to which the billing statistics records are
// uploaded.
uploader Uploader
+
+ // errColl is used to collect errors during refreshes.
+ errColl errcoll.Interface
}
// type check
@@ -58,6 +65,10 @@ func (r *RuntimeRecorder) Record(
start time.Time,
proto agd.Protocol,
) {
+ // TODO(a.garipov): Use slog.
+ log.Debug("billstat_refresh: started")
+ defer log.Debug("billstat_refresh: finished")
+
r.mu.Lock()
defer r.mu.Unlock()
@@ -96,7 +107,7 @@ func (r *RuntimeRecorder) Refresh(ctx context.Context) (err error) {
if err != nil {
r.remergeRecords(records)
- log.Info("billstat: refresh failed, records remerged")
+ log.Info("billstat_refresh: failed, records remerged")
} else {
metrics.BillStatUploadTimestamp.SetToCurrentTime()
}
@@ -106,10 +117,10 @@ func (r *RuntimeRecorder) Refresh(ctx context.Context) (err error) {
err = r.uploader.Upload(ctx, records)
if err != nil {
- return fmt.Errorf("uploading billstat records: %w", err)
+ errcoll.Collectf(ctx, r.errColl, "billstat_refresh: %w", err)
}
- return nil
+ return err
}
// resetRecords returns the current data and resets the records map to an empty
diff --git a/internal/billstat/runtime_test.go b/internal/billstat/runtime_test.go
index ea8b8d0..8f35073 100644
--- a/internal/billstat/runtime_test.go
+++ b/internal/billstat/runtime_test.go
@@ -30,6 +30,11 @@ const (
func TestRuntimeRecorder_success(t *testing.T) {
var gotRecord *billstat.Record
c := &billstat.RuntimeRecorderConfig{
+ ErrColl: &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, _ error) {
+ panic("not implemented")
+ },
+ },
Uploader: &agdtest.BillStatUploader{
OnUpload: func(_ context.Context, records billstat.Records) (err error) {
gotRecord = records[devID]
@@ -48,7 +53,7 @@ func TestRuntimeRecorder_success(t *testing.T) {
// incremented.
const reqNum = 2
var err error
- for i := 0; i < reqNum; i++ {
+ for range reqNum {
r.Record(ctx, devID, clientCtry, clientASN, start, proto)
}
@@ -89,7 +94,13 @@ func TestRuntimeRecorder_fail(t *testing.T) {
return nil
}
+ var gotCollErr error
c := &billstat.RuntimeRecorderConfig{
+ ErrColl: &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) {
+ gotCollErr = err
+ },
+ },
Uploader: &agdtest.BillStatUploader{
OnUpload: onUpload,
},
@@ -118,6 +129,7 @@ func TestRuntimeRecorder_fail(t *testing.T) {
err := r.Refresh(context.Background())
require.ErrorIs(t, err, testError)
+ require.ErrorIs(t, gotCollErr, testError)
require.Nil(t, gotRecord)
// Request the backend again, expect the correct, merged data.
diff --git a/internal/bindtodevice/chanpacketconn_linux.go b/internal/bindtodevice/chanpacketconn_linux.go
index c799e9e..bca6b10 100644
--- a/internal/bindtodevice/chanpacketconn_linux.go
+++ b/internal/bindtodevice/chanpacketconn_linux.go
@@ -46,6 +46,7 @@ func newChanPacketConn(
sessions chan *packetSession,
subnet netip.Prefix,
writeRequests chan *packetConnWriteReq,
+ writeRequestsGauge prometheus.Gauge,
laddr net.Addr,
) (c *chanPacketConn) {
return &chanPacketConn{
@@ -54,7 +55,7 @@ func newChanPacketConn(
writeRequests: writeRequests,
sessionsGauge: metrics.BindToDeviceUDPSessionsChanSize.WithLabelValues(subnet.String()),
- writeRequestsGauge: metrics.BindToDeviceUDPWriteRequestsChanSize.WithLabelValues(subnet.String()),
+ writeRequestsGauge: writeRequestsGauge,
deadlineMu: &sync.RWMutex{},
@@ -64,9 +65,9 @@ func newChanPacketConn(
}
// packetConnWriteReq is a request to write a piece of data to the original
-// packet connection. resp, body, and either raddr or session must be set.
+// packet connection. respCh, body, and either raddr or session must be set.
type packetConnWriteReq struct {
- resp chan *packetConnWriteResp
+ respCh chan *packetConnWriteResp
session *packetSession
raddr net.Addr
deadline time.Time
@@ -265,7 +266,7 @@ func (c *chanPacketConn) writeToSession(
resp := make(chan *packetConnWriteResp, 1)
req := &packetConnWriteReq{
- resp: resp,
+ respCh: resp,
session: s,
raddr: raddr,
deadline: deadline,
diff --git a/internal/bindtodevice/chanpacketconn_linux_internal_test.go b/internal/bindtodevice/chanpacketconn_linux_internal_test.go
index a917f9a..81cc617 100644
--- a/internal/bindtodevice/chanpacketconn_linux_internal_test.go
+++ b/internal/bindtodevice/chanpacketconn_linux_internal_test.go
@@ -8,13 +8,14 @@ import (
"time"
"github.com/AdguardTeam/golibs/testutil"
+ "github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestChanPacketConn_Close(t *testing.T) {
sessions := make(chan *packetSession)
- c := newChanPacketConn(sessions, testSubnetIPv4, nil, testLAddr)
+ c := newChanPacketConn(sessions, testSubnetIPv4, nil, nil, testLAddr)
err := c.Close()
assert.NoError(t, err)
@@ -23,14 +24,14 @@ func TestChanPacketConn_Close(t *testing.T) {
}
func TestChanPacketConn_LocalAddr(t *testing.T) {
- c := newChanPacketConn(nil, testSubnetIPv4, nil, testLAddr)
+ c := newChanPacketConn(nil, testSubnetIPv4, nil, nil, testLAddr)
got := c.LocalAddr()
assert.Equal(t, testLAddr, got)
}
func TestChanPacketConn_ReadFromSession(t *testing.T) {
sessions := make(chan *packetSession, 1)
- c := newChanPacketConn(sessions, testSubnetIPv4, nil, testLAddr)
+ c := newChanPacketConn(sessions, testSubnetIPv4, nil, nil, testLAddr)
body := []byte("hello")
bodyLen := len(body)
@@ -79,7 +80,9 @@ func TestChanPacketConn_ReadFromSession(t *testing.T) {
func TestChanPacketConn_WriteToSession(t *testing.T) {
sessions := make(chan *packetSession, 1)
writes := make(chan *packetConnWriteReq, 1)
- c := newChanPacketConn(sessions, testSubnetIPv4, writes, testLAddr)
+
+ gauge := prometheus.NewGauge(prometheus.GaugeOpts{})
+ c := newChanPacketConn(sessions, testSubnetIPv4, writes, gauge, testLAddr)
body := []byte("hello")
bodyLen := len(body)
@@ -125,7 +128,7 @@ func checkWriteReqAndRespond(
req, ok := testutil.RequireReceive(pt, writes, testTimeout)
require.NotNil(pt, req)
- require.NotNil(pt, req.resp)
+ require.NotNil(pt, req.respCh)
require.True(pt, ok)
if wantRaddr != nil {
@@ -141,14 +144,14 @@ func checkWriteReqAndRespond(
assert.Equal(pt, wantDeadline, req.deadline)
assert.Equal(pt, wantBody, req.body)
- testutil.RequireSend(pt, req.resp, &packetConnWriteResp{
+ testutil.RequireSend(pt, req.respCh, &packetConnWriteResp{
err: nil,
written: len(wantBody),
}, testTimeout)
}
func TestChanPacketConn_deadlines(t *testing.T) {
- c := newChanPacketConn(nil, testSubnetIPv4, nil, testLAddr)
+ c := newChanPacketConn(nil, testSubnetIPv4, nil, nil, testLAddr)
deadline := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
testCases := []struct {
diff --git a/internal/bindtodevice/interfacelistener_linux.go b/internal/bindtodevice/interfacelistener_linux.go
index ad57993..de29b03 100644
--- a/internal/bindtodevice/interfacelistener_linux.go
+++ b/internal/bindtodevice/interfacelistener_linux.go
@@ -15,19 +15,22 @@ import (
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/syncutil"
+ "github.com/prometheus/client_golang/prometheus"
)
// interfaceListener contains information about a single interface listener.
type interfaceListener struct {
- conns *connIndex
- listenConf *net.ListenConfig
- bodyPool *syncutil.Pool[[]byte]
- oobPool *syncutil.Pool[[]byte]
- writeRequests chan *packetConnWriteReq
- done chan unit
- errColl errcoll.Interface
- ifaceName string
- port uint16
+ conns *connIndex
+ listenConf *net.ListenConfig
+ bodyPool *syncutil.Pool[[]byte]
+ oobPool *syncutil.Pool[[]byte]
+ writeRequests chan *packetConnWriteReq
+ done chan unit
+ errColl errcoll.Interface
+ writeRequestsGauge prometheus.Gauge
+ writeDurationHist prometheus.Observer
+ ifaceName string
+ port uint16
}
// listenTCP runs the TCP listening loop. It is intended to be used as a
@@ -113,7 +116,7 @@ func (l *interfaceListener) listenUDP(errCh chan<- error) {
errCh <- nil
- go l.writeUDP(udpConn)
+ go l.writeUDPResponses(udpConn)
logPrefix := fmt.Sprintf("bindtodevice: listener %s:%d: udp", l.ifaceName, l.port)
@@ -185,46 +188,60 @@ func (l *interfaceListener) readUDP(c *net.UDPConn, logPrefix string) (err error
return nil
}
-// writeUDP runs the UDP write loop. It is intended to be used as a goroutine.
-func (l *interfaceListener) writeUDP(c *net.UDPConn) {
+// writeUDPResponses runs the UDP write loop. It is intended to be used as a
+// goroutine.
+func (l *interfaceListener) writeUDPResponses(c *net.UDPConn) {
defer log.OnPanic("interfaceListener.writeUDP")
- logPrefix := fmt.Sprintf("bindtodevice: listener %s:%d: udp write", l.ifaceName, l.port)
for {
- var req *packetConnWriteReq
select {
case <-l.done:
- optlog.Debug1("%s: done", logPrefix)
+ optlog.Debug2("bindtodevice: listener %s:%d: udp write: done", l.ifaceName, l.port)
return
- case req = <-l.writeRequests:
- // Go on.
+ case req := <-l.writeRequests:
+ l.writeUDP(c, req)
}
-
- resp := &packetConnWriteResp{}
- resp.err = c.SetWriteDeadline(req.deadline)
- if resp.err != nil {
- req.resp <- resp
-
- continue
- }
-
- if s := req.session; s == nil {
- resp.written, resp.err = c.WriteTo(req.body, req.raddr)
- } else {
- resp.written, _, resp.err = c.WriteMsgUDP(
- req.body,
- s.respOOB,
- req.session.raddr,
- )
-
- l.bodyPool.Put(&s.readBody)
- }
-
- resetDeadlineErr := c.SetWriteDeadline(time.Time{})
-
- resp.err = errors.WithDeferred(resp.err, resetDeadlineErr)
-
- req.resp <- resp
}
}
+
+// writeUDP handles a single write operation and writes a response to
+// req.respCh.
+func (l *interfaceListener) writeUDP(c *net.UDPConn, req *packetConnWriteReq) {
+ resp := &packetConnWriteResp{}
+ resp.err = c.SetWriteDeadline(req.deadline)
+ if resp.err != nil {
+ req.respCh <- resp
+
+ return
+ }
+
+ l.writeToUDPConn(c, req, resp)
+
+ resetDeadlineErr := c.SetWriteDeadline(time.Time{})
+ resp.err = errors.WithDeferred(resp.err, resetDeadlineErr)
+
+ req.respCh <- resp
+}
+
+// writeToUDPConn writes to c, depending on what kind of session req contains,
+// and sets resp.written and resp.err accordingly.
+func (l *interfaceListener) writeToUDPConn(
+ c *net.UDPConn,
+ req *packetConnWriteReq,
+ resp *packetConnWriteResp,
+) {
+ start := time.Now()
+ defer func() { l.writeDurationHist.Observe(time.Since(start).Seconds()) }()
+
+ s := req.session
+ if s == nil {
+ resp.written, resp.err = c.WriteTo(req.body, req.raddr)
+
+ return
+ }
+
+ resp.written, _, resp.err = c.WriteMsgUDP(req.body, s.respOOB, req.session.raddr)
+
+ l.bodyPool.Put(&s.readBody)
+}
diff --git a/internal/bindtodevice/listenconfig_linux_internal_test.go b/internal/bindtodevice/listenconfig_linux_internal_test.go
index 5a33bbe..07eada5 100644
--- a/internal/bindtodevice/listenconfig_linux_internal_test.go
+++ b/internal/bindtodevice/listenconfig_linux_internal_test.go
@@ -12,7 +12,7 @@ import (
)
func TestListenConfig(t *testing.T) {
- pc := newChanPacketConn(nil, testSubnetIPv4, nil, testLAddr)
+ pc := newChanPacketConn(nil, testSubnetIPv4, nil, nil, testLAddr)
lsnr := newChanListener(nil, testSubnetIPv4, testLAddr)
addr := &agdnet.PrefixNetAddr{
Prefix: testSubnetIPv4,
diff --git a/internal/bindtodevice/manager_linux.go b/internal/bindtodevice/manager_linux.go
index cdbffef..6e7c107 100644
--- a/internal/bindtodevice/manager_linux.go
+++ b/internal/bindtodevice/manager_linux.go
@@ -12,6 +12,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/netext"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/mapsutil"
@@ -84,7 +85,7 @@ func (m *Manager) Add(id ID, ifaceName string, port uint16, ctrlConf *ControlCon
return nil
}
- err = mapsutil.OrderedRangeError(m.ifaceListeners, validateDup)
+ err = mapsutil.SortedRangeError(m.ifaceListeners, validateDup)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
@@ -109,15 +110,17 @@ func (m *Manager) newInterfaceListener(
port uint16,
) (l *interfaceListener) {
return &interfaceListener{
- conns: &connIndex{},
- listenConf: newListenConfig(ifaceName, ctrlConf),
- bodyPool: syncutil.NewSlicePool[byte](bodySize),
- oobPool: syncutil.NewSlicePool[byte](netext.IPDstOOBSize),
- writeRequests: make(chan *packetConnWriteReq, m.chanBufSize),
- done: m.done,
- errColl: m.errColl,
- ifaceName: ifaceName,
- port: port,
+ conns: &connIndex{},
+ listenConf: newListenConfig(ifaceName, ctrlConf),
+ bodyPool: syncutil.NewSlicePool[byte](bodySize),
+ oobPool: syncutil.NewSlicePool[byte](netext.IPDstOOBSize),
+ writeRequests: make(chan *packetConnWriteReq, m.chanBufSize),
+ done: m.done,
+ errColl: m.errColl,
+ writeRequestsGauge: metrics.BindToDeviceUDPWriteRequestsChanSize.WithLabelValues(ifaceName),
+ writeDurationHist: metrics.BindToDeviceUDPWriteDurationSeconds.WithLabelValues(ifaceName),
+ ifaceName: ifaceName,
+ port: port,
}
}
@@ -159,11 +162,17 @@ func (m *Manager) ListenConfig(id ID, subnet netip.Prefix) (c *ListenConfig, err
}
sessCh := make(chan *packetSession, m.chanBufSize)
- pConn := newChanPacketConn(sessCh, subnet, l.writeRequests, &agdnet.PrefixNetAddr{
- Prefix: subnet,
- Net: "udp",
- Port: l.port,
- })
+ pConn := newChanPacketConn(
+ sessCh,
+ subnet,
+ l.writeRequests,
+ l.writeRequestsGauge,
+ &agdnet.PrefixNetAddr{
+ Prefix: subnet,
+ Net: "udp",
+ Port: l.port,
+ },
+ )
err = l.conns.addPacketConn(pConn)
if err != nil {
diff --git a/internal/bindtodevice/manager_linux_test.go b/internal/bindtodevice/manager_linux_test.go
index 49a24ce..879336c 100644
--- a/internal/bindtodevice/manager_linux_test.go
+++ b/internal/bindtodevice/manager_linux_test.go
@@ -233,10 +233,10 @@ func TestManager(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, lc)
- err = m.Start(agdtest.ContextWithTimeout(t, testTimeout))
+ err = m.Start(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return m.Shutdown(agdtest.ContextWithTimeout(t, testTimeout))
+ return m.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
})
t.Run("tcp", func(t *testing.T) {
diff --git a/internal/bindtodevice/socket_linux_internal_test.go b/internal/bindtodevice/socket_linux_internal_test.go
index 16bcea9..52278f1 100644
--- a/internal/bindtodevice/socket_linux_internal_test.go
+++ b/internal/bindtodevice/socket_linux_internal_test.go
@@ -113,9 +113,7 @@ func SubtestListenControlTCP(
ifaceName string,
ifaceNet *net.IPNet,
) {
- ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
- t.Cleanup(cancel)
-
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
lsnr, err := lc.Listen(ctx, "tcp", "0.0.0.0:0")
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, lsnr.Close)
@@ -194,9 +192,7 @@ func SubtestListenControlUDP(
ifaceName string,
ifaceNet *net.IPNet,
) {
- ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
- t.Cleanup(cancel)
-
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
packetConn, err := lc.ListenPacket(ctx, "udp", "0.0.0.0:0")
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, packetConn.Close)
@@ -528,7 +524,7 @@ func BenchmarkReadPacketSession(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
sessSink, errSink = readPacketSession(c, body, oob)
}
diff --git a/internal/cmd/additional.go b/internal/cmd/additional.go
index cf1b98a..ca25983 100644
--- a/internal/cmd/additional.go
+++ b/internal/cmd/additional.go
@@ -14,7 +14,7 @@ type additionalInfo map[string]string
// validateAdditionalInfo return an error is the section is invalid.
func (c additionalInfo) validate() (err error) {
- return mapsutil.OrderedRangeError(c, func(k, _ string) (keyErr error) {
+ return mapsutil.SortedRangeError(c, func(k, _ string) (keyErr error) {
if model.LabelName(k).IsValid() {
return nil
}
diff --git a/internal/cmd/backend.go b/internal/cmd/backend.go
index d68e5df..15bf237 100644
--- a/internal/cmd/backend.go
+++ b/internal/cmd/backend.go
@@ -110,6 +110,7 @@ func setupBillStat(
}
rec = billstat.NewRuntimeRecorder(&billstat.RuntimeRecorderConfig{
+ ErrColl: errColl,
Uploader: billStatUploader,
})
@@ -120,13 +121,11 @@ func setupBillStat(
Context: func() (ctx context.Context, cancel context.CancelFunc) {
return context.WithTimeout(context.Background(), timeout)
},
- Refresher: rec,
- ErrColl: errColl,
- Name: "billstat",
- Interval: refrIvl,
- RefreshOnShutdown: true,
- RoutineLogsAreDebug: true,
- RandomizeStart: false,
+ Refresher: rec,
+ Name: "billstat",
+ Interval: refrIvl,
+ RefreshOnShutdown: true,
+ RandomizeStart: false,
})
err = billStatRefr.Start(context.Background())
if err != nil {
@@ -157,6 +156,7 @@ func setupProfDB(
timeout := conf.Timeout.Duration
profDB, err = profiledb.New(&profiledb.Config{
Storage: profStrg,
+ ErrColl: errColl,
FullSyncIvl: conf.FullRefreshIvl.Duration,
FullSyncRetryIvl: conf.FullRefreshRetryIvl.Duration,
InitialTimeout: timeout,
@@ -172,13 +172,11 @@ func setupProfDB(
Context: func() (ctx context.Context, cancel context.CancelFunc) {
return context.WithTimeout(context.Background(), timeout)
},
- Refresher: profDB,
- ErrColl: errColl,
- Name: "profiledb",
- Interval: refrIvl,
- RefreshOnShutdown: false,
- RoutineLogsAreDebug: true,
- RandomizeStart: true,
+ Refresher: profDB,
+ Name: "profiledb",
+ Interval: refrIvl,
+ RefreshOnShutdown: false,
+ RandomizeStart: true,
})
err = profDBRefr.Start(context.Background())
if err != nil {
diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go
index 405a533..6ceb317 100644
--- a/internal/cmd/cmd.go
+++ b/internal/cmd/cmd.go
@@ -10,7 +10,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/debugsvc"
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
@@ -27,7 +26,6 @@ import (
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/service"
- "github.com/AdguardTeam/golibs/timeutil"
)
// Main is the entry point of application.
@@ -92,9 +90,6 @@ func Main() {
// Safe-browsing and adult-blocking filters
- // TODO(ameshkov): Consider making configurable.
- filteringResolver := agdnet.NewCachingResolver(agdnet.DefaultResolver{}, 1*timeutil.Day)
-
err = os.MkdirAll(envs.FilterCachePath, agd.DefaultDirPerm)
check(err)
@@ -105,7 +100,6 @@ func Main() {
cloner := dnsmsg.NewCloner(metrics.ClonerStat{})
safeBrowsingHashes, safeBrowsingFilter, err := setupHashPrefixFilter(
c.SafeBrowsing,
- filteringResolver,
cloner,
agd.FilterListIDSafeBrowsing,
envs.SafeBrowsingURL,
@@ -118,7 +112,6 @@ func Main() {
adultBlockingHashes, adultBlockingFilter, err := setupHashPrefixFilter(
c.AdultBlocking,
- filteringResolver,
cloner,
agd.FilterListIDAdultBlocking,
envs.AdultBlockingURL,
@@ -132,7 +125,6 @@ func Main() {
_, newRegDomainsFilter, err := setupHashPrefixFilter(
// Reuse general safe browsing filter configuration.
c.SafeBrowsing,
- filteringResolver,
cloner,
agd.FilterListIDNewRegDomains,
envs.NewRegDomainsURL,
@@ -147,8 +139,6 @@ func Main() {
fltStrgConf := c.Filters.toInternal(
errColl,
- filteringResolver,
- cloner,
envs,
safeBrowsingFilter,
adultBlockingFilter,
@@ -156,7 +146,7 @@ func Main() {
)
fltRefrTimeout := c.Filters.RefreshTimeout.Duration
- fltStrg, err := setupFilterStorage(fltStrgConf, sigHdlr, errColl, fltRefrTimeout)
+ fltStrg, err := setupFilterStorage(fltStrgConf, sigHdlr, fltRefrTimeout)
check(err)
fltGroups, err := c.FilteringGroups.toInternal(fltStrg)
@@ -293,8 +283,6 @@ func Main() {
UseCacheTTLOverride: c.Cache.TTLOverride.Enabled,
UseECSCache: c.Cache.Type == cacheTypeECS,
ProfileDBEnabled: bool(envs.ProfilesEnabled),
- ResearchMetrics: bool(envs.ResearchMetrics),
- ResearchLogs: bool(envs.ResearchLogs),
}
dnsSvc, err := dnssvc.New(dnsConf)
diff --git a/internal/cmd/config.go b/internal/cmd/config.go
index 2121d62..220d7c0 100644
--- a/internal/cmd/config.go
+++ b/internal/cmd/config.go
@@ -100,7 +100,8 @@ func (c *configuration) buildQueryLog(envs *environments) (l querylog.Interface)
}
return querylog.NewFileSystem(&querylog.FileSystemConfig{
- Path: envs.QueryLogPath,
+ Path: envs.QueryLogPath,
+ RandSeed: uint64(time.Now().UnixNano()),
})
}
diff --git a/internal/cmd/ddr.go b/internal/cmd/ddr.go
index f7f825b..dbf049d 100644
--- a/internal/cmd/ddr.go
+++ b/internal/cmd/ddr.go
@@ -9,9 +9,9 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
- "github.com/AdguardTeam/golibs/stringutil"
"github.com/miekg/dns"
)
@@ -50,8 +50,8 @@ func (c *ddrConfig) toInternal(msgs *dnsmsg.Constructor) (conf *agd.DDR) {
func ddrRecsToSVCBTmpls(
msgs *dnsmsg.Constructor,
records map[string]*ddrRecord,
-) (targets *stringutil.Set, tmpls []*dns.SVCB) {
- targets = stringutil.NewSet()
+) (targets *container.MapSet[string], tmpls []*dns.SVCB) {
+ targets = container.NewMapSet[string]()
for target, r := range records {
target = strings.TrimPrefix(target, "*.")
targets.Add(target)
diff --git a/internal/cmd/env.go b/internal/cmd/env.go
index 070e462..f5abc0e 100644
--- a/internal/cmd/env.go
+++ b/internal/cmd/env.go
@@ -60,8 +60,6 @@ type environments struct {
LogTimestamp strictBool `env:"LOG_TIMESTAMP" envDefault:"1"`
LogVerbose strictBool `env:"VERBOSE" envDefault:"0"`
ProfilesEnabled strictBool `env:"PROFILES_ENABLED" envDefault:"1"`
- ResearchMetrics strictBool `env:"RESEARCH_METRICS" envDefault:"0"`
- ResearchLogs strictBool `env:"RESEARCH_LOGS" envDefault:"0"`
}
// readEnvs reads the configuration.
@@ -117,9 +115,7 @@ func (envs *environments) buildErrColl() (errColl errcoll.Interface, err error)
}
// geoIP returns an GeoIP database implementation from environment.
-func (envs *environments) geoIP(
- c *geoIPConfig,
-) (g *geoip.File, err error) {
+func (envs *environments) geoIP(c *geoIPConfig) (g *geoip.File, err error) {
log.Debug("using geoip files %q and %q", envs.GeoIPASNPath, envs.GeoIPCountryPath)
g, err = geoip.NewFile(&geoip.FileConfig{
@@ -180,19 +176,18 @@ func (envs *environments) buildRuleStat(
}
httpRuleStat := rulestat.NewHTTP(&rulestat.HTTPConfig{
- URL: &envs.RuleStatURL.URL,
+ ErrColl: errColl,
+ URL: &envs.RuleStatURL.URL,
})
refr := agdservice.NewRefreshWorker(&agdservice.RefreshWorkerConfig{
Context: ctxWithDefaultTimeout,
Refresher: httpRuleStat,
- ErrColl: errColl,
Name: "rulestat",
// TODO(ameshkov): Consider making configurable.
- Interval: 10 * time.Minute,
- RefreshOnShutdown: true,
- RoutineLogsAreDebug: false,
- RandomizeStart: false,
+ Interval: 10 * time.Minute,
+ RefreshOnShutdown: true,
+ RandomizeStart: false,
})
err = refr.Start(context.Background())
if err != nil {
diff --git a/internal/cmd/error.go b/internal/cmd/error.go
index 92ccfd7..ff6d651 100644
--- a/internal/cmd/error.go
+++ b/internal/cmd/error.go
@@ -16,24 +16,6 @@ func check(err error) {
}
}
-// coalesceError returns the first non-nil error. It is named after function
-// COALESCE in SQL. If all errors are nil, it returns nil.
-//
-// TODO(a.garipov): Consider a similar helper to group errors together to show
-// as many errors as possible.
-//
-// TODO(a.garipov): Think of ways to merge with [aghalg.Coalesce] in AdGuard
-// Home.
-func coalesceError(errors ...error) (res error) {
- for _, err := range errors {
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
// numberOrDuration is the constraint for integer types along with
// timeutil.Duration.
type numberOrDuration interface {
diff --git a/internal/cmd/filter.go b/internal/cmd/filter.go
index 074754f..bff86c4 100644
--- a/internal/cmd/filter.go
+++ b/internal/cmd/filter.go
@@ -5,9 +5,7 @@ import (
"fmt"
"time"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix"
@@ -17,10 +15,11 @@ import (
"github.com/c2h5oh/datasize"
)
-// Filters configuration
-
// filtersConfig contains the configuration for the filter lists and filtering
// storage to be used.
+//
+// TODO(a.garipov): Add the timeout for the blocked-service index refresh. It
+// is currently hardcoded to 3 minutes.
type filtersConfig struct {
// RuleListCache is the cache settings for the filtering rule-list.
RuleListCache *fltRuleListCache `yaml:"rule_list_cache"`
@@ -41,10 +40,21 @@ type filtersConfig struct {
RefreshIvl timeutil.Duration `yaml:"refresh_interval"`
// RefreshTimeout is the timeout for the entire filter update operation.
- // Note that each individual refresh operation also has its own hardcoded
- // 30s timeout.
+ // Note that filter rule-list index and each filter rule-list update
+ // operations have their own timeouts, see IndexRefreshTimeout and
+ // RuleListRefreshTimeout.
RefreshTimeout timeutil.Duration `yaml:"refresh_timeout"`
+ // IndexRefreshTimeout is the timeout for the filter rule-list index update
+ // operation. See also RefreshTimeout for the entire filter update
+ // operation.
+ IndexRefreshTimeout timeutil.Duration `yaml:"index_refresh_timeout"`
+
+ // RuleListRefreshTimeout is the timeout for the filter update operation of
+ // each rule-list, which includes safe-search filters. See also
+ // RefreshTimeout for the entire filter update operation.
+ RuleListRefreshTimeout timeutil.Duration `yaml:"rule_list_refresh_timeout"`
+
// MaxSize is the maximum size of the downloadable filtering rule-list.
MaxSize datasize.ByteSize `yaml:"max_size"`
}
@@ -53,8 +63,6 @@ type filtersConfig struct {
// cacheDir must exist. c is assumed to be valid.
func (c *filtersConfig) toInternal(
errColl errcoll.Interface,
- resolver agdnet.Resolver,
- cloner *dnsmsg.Cloner,
envs *environments,
safeBrowsing *hashprefix.Filter,
adultBlocking *hashprefix.Filter,
@@ -70,17 +78,17 @@ func (c *filtersConfig) toInternal(
NewRegDomains: newRegDomains,
Now: time.Now,
ErrColl: errColl,
- Resolver: resolver,
- Cloner: cloner,
CacheDir: envs.FilterCachePath,
CustomFilterCacheSize: c.CustomFilterCacheSize,
SafeSearchCacheSize: c.SafeSearchCacheSize,
// TODO(a.garipov): Consider making this configurable.
- SafeSearchCacheTTL: 1 * time.Hour,
- RuleListCacheSize: c.RuleListCache.Size,
- RefreshIvl: c.RefreshIvl.Duration,
- UseRuleListCache: c.RuleListCache.Enabled,
- MaxRuleListSize: c.MaxSize.Bytes(),
+ SafeSearchCacheTTL: 1 * time.Hour,
+ RuleListCacheSize: c.RuleListCache.Size,
+ RefreshIvl: c.RefreshIvl.Duration,
+ IndexRefreshTimeout: c.IndexRefreshTimeout.Duration,
+ RuleListRefreshTimeout: c.RuleListRefreshTimeout.Duration,
+ UseRuleListCache: c.RuleListCache.Enabled,
+ MaxRuleListSize: c.MaxSize.Bytes(),
}
}
@@ -97,6 +105,10 @@ func (c *filtersConfig) validate() (err error) {
return newMustBePositiveError("refresh_interval", c.RefreshIvl)
case c.RefreshTimeout.Duration <= 0:
return newMustBePositiveError("refresh_timeout", c.RefreshTimeout)
+ case c.IndexRefreshTimeout.Duration <= 0:
+ return newMustBePositiveError("index_refresh_timeout", c.IndexRefreshTimeout)
+ case c.RuleListRefreshTimeout.Duration <= 0:
+ return newMustBePositiveError("rule_list_refresh_timeout", c.RuleListRefreshTimeout)
case c.MaxSize <= 0:
return newMustBePositiveError("max_size", c.MaxSize)
default:
@@ -138,7 +150,6 @@ func (c *fltRuleListCache) validate() (err error) {
func setupFilterStorage(
conf *filter.DefaultStorageConfig,
sigHdlr *service.SignalHandler,
- errColl errcoll.Interface,
refreshTimeout time.Duration,
) (strg *filter.DefaultStorage, err error) {
strg, err = filter.NewDefaultStorage(conf)
@@ -150,13 +161,11 @@ func setupFilterStorage(
Context: func() (ctx context.Context, cancel context.CancelFunc) {
return context.WithTimeout(context.Background(), refreshTimeout)
},
- Refresher: strg,
- ErrColl: errColl,
- Name: "filters",
- Interval: conf.RefreshIvl,
- RefreshOnShutdown: false,
- RoutineLogsAreDebug: false,
- RandomizeStart: false,
+ Refresher: strg,
+ Name: "filters",
+ Interval: conf.RefreshIvl,
+ RefreshOnShutdown: false,
+ RandomizeStart: false,
})
err = refr.Start(context.Background())
if err != nil {
diff --git a/internal/cmd/filteringgroup.go b/internal/cmd/filteringgroup.go
index 7efbc2e..370d508 100644
--- a/internal/cmd/filteringgroup.go
+++ b/internal/cmd/filteringgroup.go
@@ -5,8 +5,8 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
+ "github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/stringutil"
)
// Filtering Groups Configuration
@@ -94,7 +94,7 @@ func (g *filteringGroup) validate() (err error) {
return errors.Error("no parental")
}
- fltIDs := stringutil.NewSet()
+ fltIDs := container.NewMapSet[string]()
for i, fltID := range g.RuleLists.IDs {
if fltIDs.Has(fltID) {
return fmt.Errorf("rule_lists: at index %d: duplicate id %q", i, fltID)
@@ -160,7 +160,7 @@ func (groups filteringGroups) validate() (err error) {
return errors.Error("no filtering_groups")
}
- ids := stringutil.NewSet()
+ ids := container.NewMapSet[string]()
for i, g := range groups {
err = g.validate()
if err != nil {
diff --git a/internal/cmd/geoip.go b/internal/cmd/geoip.go
index e645928..835151f 100644
--- a/internal/cmd/geoip.go
+++ b/internal/cmd/geoip.go
@@ -7,6 +7,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/timeutil"
)
@@ -63,14 +64,19 @@ func setupGeoIP(
}
refr := agdservice.NewRefreshWorker(&agdservice.RefreshWorkerConfig{
- Context: ctxWithDefaultTimeout,
- Refresher: geoIP,
- ErrColl: errColl,
- Name: "geoip",
- Interval: conf.RefreshIvl.Duration,
- RefreshOnShutdown: false,
- RoutineLogsAreDebug: false,
- RandomizeStart: false,
+ Context: ctxWithDefaultTimeout,
+ // Do not add errColl to geoip's config, as that would create an import
+ // cycle.
+ Refresher: agdservice.NewRefresherWithErrColl(
+ geoIP,
+ log.Info,
+ errColl,
+ "geoip_refresh",
+ ),
+ Name: "geoip",
+ Interval: conf.RefreshIvl.Duration,
+ RefreshOnShutdown: false,
+ RandomizeStart: false,
})
err = refr.Start(context.Background())
if err != nil {
diff --git a/internal/cmd/ifacelistener.go b/internal/cmd/ifacelistener.go
index 8a530ba..d45ee83 100644
--- a/internal/cmd/ifacelistener.go
+++ b/internal/cmd/ifacelistener.go
@@ -35,7 +35,7 @@ func (c *interfaceListenersConfig) toInternal(
ChannelBufferSize: c.ChannelBufferSize,
})
- err = mapsutil.OrderedRangeError(
+ err = mapsutil.SortedRangeError(
c.List,
func(id bindtodevice.ID, l *interfaceListener) (addErr error) {
return errors.Annotate(m.Add(id, l.Interface, l.Port, ctrlConf), "adding listener %q: %w", id)
@@ -66,7 +66,7 @@ func (c *interfaceListenersConfig) validate() (err error) {
// Go on.
}
- err = mapsutil.OrderedRangeError(
+ err = mapsutil.SortedRangeError(
c.List,
func(id bindtodevice.ID, l *interfaceListener) (lsnrErr error) {
return errors.Annotate(l.validate(), "interface %q: %w", id)
diff --git a/internal/cmd/ratelimit.go b/internal/cmd/ratelimit.go
index 5fa8089..715888a 100644
--- a/internal/cmd/ratelimit.go
+++ b/internal/cmd/ratelimit.go
@@ -1,6 +1,7 @@
package cmd
import (
+ "cmp"
"context"
"fmt"
"net/url"
@@ -88,7 +89,7 @@ func (o *rateLimitOptions) validate() (err error) {
return errNilConfig
}
- return coalesceError(
+ return cmp.Or(
validatePositive("rps", o.RPS),
validatePositive("subnet_key_len", o.SubnetKeyLen),
)
@@ -120,7 +121,7 @@ func (c *rateLimitConfig) validate() (err error) {
return fmt.Errorf("allowlist: %w", errNilConfig)
}
- return coalesceError(
+ return cmp.Or(
validateProp("connection_limit", c.ConnectionLimit.validate),
validateProp("ipv4", c.IPv4.validate),
validateProp("ipv6", c.IPv6.validate),
@@ -144,20 +145,18 @@ func setupRateLimiter(
) (rateLimiter *ratelimit.Backoff, connLimiter *connlimiter.Limiter, err error) {
allowSubnets := netutil.UnembedPrefixes(conf.Allowlist.List)
allowlist := ratelimit.NewDynamicAllowlist(allowSubnets, nil)
- refresher, err := consul.NewAllowlistRefresher(allowlist, consulAllowlist)
+ refresher, err := consul.NewAllowlistRefresher(allowlist, consulAllowlist, errColl)
if err != nil {
return nil, nil, fmt.Errorf("creating allowlist refresher: %w", err)
}
refr := agdservice.NewRefreshWorker(&agdservice.RefreshWorkerConfig{
- Context: ctxWithDefaultTimeout,
- Refresher: refresher,
- ErrColl: errColl,
- Name: "allowlist",
- Interval: conf.Allowlist.RefreshIvl.Duration,
- RefreshOnShutdown: false,
- RoutineLogsAreDebug: false,
- RandomizeStart: false,
+ Context: ctxWithDefaultTimeout,
+ Refresher: refresher,
+ Name: "allowlist",
+ Interval: conf.Allowlist.RefreshIvl.Duration,
+ RefreshOnShutdown: false,
+ RandomizeStart: false,
})
err = refr.Start(context.Background())
diff --git a/internal/cmd/safebrowsing.go b/internal/cmd/safebrowsing.go
index 595a79a..acaebda 100644
--- a/internal/cmd/safebrowsing.go
+++ b/internal/cmd/safebrowsing.go
@@ -6,7 +6,6 @@ import (
"path/filepath"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
@@ -37,13 +36,15 @@ type safeBrowsingConfig struct {
// RefreshIvl defines how often AdGuard DNS refreshes the filter.
RefreshIvl timeutil.Duration `yaml:"refresh_interval"`
+
+ // RefreshTimeout is the timeout for the filter update operation.
+ RefreshTimeout timeutil.Duration `yaml:"refresh_timeout"`
}
// toInternal converts c to the safe browsing filter configuration for the
// filter storage of the DNS server. c is assumed to be valid.
func (c *safeBrowsingConfig) toInternal(
errColl errcoll.Interface,
- resolver agdnet.Resolver,
cloner *dnsmsg.Cloner,
id agd.FilterListID,
url *urlutil.URL,
@@ -60,11 +61,11 @@ func (c *safeBrowsingConfig) toInternal(
Hashes: hashes,
URL: netutil.CloneURL(&url.URL),
ErrColl: errColl,
- Resolver: resolver,
ID: id,
CachePath: filepath.Join(cacheDir, string(id)),
ReplacementHost: c.BlockHost,
Staleness: c.RefreshIvl.Duration,
+ RefreshTimeout: c.RefreshTimeout.Duration,
CacheTTL: c.CacheTTL.Duration,
CacheSize: c.CacheSize,
MaxSize: maxSize,
@@ -85,6 +86,8 @@ func (c *safeBrowsingConfig) validate() (err error) {
return newMustBePositiveError("cache_ttl", c.CacheTTL)
case c.RefreshIvl.Duration <= 0:
return newMustBePositiveError("refresh_interval", c.RefreshIvl)
+ case c.RefreshTimeout.Duration <= 0:
+ return newMustBePositiveError("refresh_timeout", c.RefreshTimeout)
default:
return nil
}
@@ -94,7 +97,6 @@ func (c *safeBrowsingConfig) validate() (err error) {
// starts and registers its refresher in the signal handler.
func setupHashPrefixFilter(
conf *safeBrowsingConfig,
- resolver *agdnet.CachingResolver,
cloner *dnsmsg.Cloner,
id agd.FilterListID,
url *urlutil.URL,
@@ -103,7 +105,7 @@ func setupHashPrefixFilter(
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (strg *hashprefix.Storage, flt *hashprefix.Filter, err error) {
- fltConf, err := conf.toInternal(errColl, resolver, cloner, id, url, cachePath, maxSize)
+ fltConf, err := conf.toInternal(errColl, cloner, id, url, cachePath, maxSize)
if err != nil {
return nil, nil, fmt.Errorf("configuring hash prefix filter %s: %w", id, err)
}
@@ -114,14 +116,16 @@ func setupHashPrefixFilter(
}
refr := agdservice.NewRefreshWorker(&agdservice.RefreshWorkerConfig{
- Context: ctxWithDefaultTimeout,
- Refresher: flt,
- ErrColl: errColl,
- Name: string(id),
- Interval: fltConf.Staleness,
- RefreshOnShutdown: false,
- RoutineLogsAreDebug: false,
- RandomizeStart: false,
+ // Note that we also set the same timeout for the http.Client in
+ // [hashprefix.NewFilter].
+ Context: func() (ctx context.Context, cancel context.CancelFunc) {
+ return context.WithTimeout(context.Background(), fltConf.RefreshTimeout)
+ },
+ Refresher: flt,
+ Name: string(id),
+ Interval: fltConf.Staleness,
+ RefreshOnShutdown: false,
+ RandomizeStart: false,
})
err = refr.Start(context.Background())
if err != nil {
diff --git a/internal/cmd/server.go b/internal/cmd/server.go
index c06bcc8..e79035f 100644
--- a/internal/cmd/server.go
+++ b/internal/cmd/server.go
@@ -7,8 +7,8 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/bindtodevice"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/stringutil"
)
// toInternal returns the configuration of DNS servers for a single server
@@ -95,7 +95,7 @@ func (srvs servers) validate() (needsTLS bool, err error) {
return false, errors.Error("no servers")
}
- names := stringutil.NewSet()
+ names := container.NewMapSet[string]()
for i, s := range srvs {
if s == nil {
return false, fmt.Errorf("at index %d: no server", i)
@@ -323,19 +323,17 @@ func (c *serverBindInterface) validate() (err error) {
// Go on.
}
- set := map[netip.Prefix]struct{}{}
-
+ set := container.NewMapSet[netip.Prefix]()
for i, subnet := range c.Subnets {
if !subnet.IsValid() {
return fmt.Errorf("bad subnet at index %d", i)
}
- _, ok := set[subnet]
- if ok {
+ if set.Has(subnet) {
return fmt.Errorf("duplicate subnet %s at index %d", subnet, i)
}
- set[subnet] = struct{}{}
+ set.Add(subnet)
}
return nil
diff --git a/internal/cmd/servergroup.go b/internal/cmd/servergroup.go
index 33b1db1..9de8e1d 100644
--- a/internal/cmd/servergroup.go
+++ b/internal/cmd/servergroup.go
@@ -2,14 +2,12 @@ package cmd
import (
"fmt"
- "net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/bindtodevice"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/netutil"
- "github.com/AdguardTeam/golibs/stringutil"
)
// serverGroups are the DNS server groups. A valid instance of serverGroups has
@@ -41,11 +39,10 @@ func (srvGrps serverGroups) toInternal(
}
svcSrvGrps[i] = &agd.ServerGroup{
- BlockPageRedirect: g.BlockPageRedirect.toInternal(),
- DDR: g.DDR.toInternal(messages),
- TLS: tlsConf,
- Name: agd.ServerGroupName(g.Name),
- FilteringGroup: fltGrpID,
+ DDR: g.DDR.toInternal(messages),
+ TLS: tlsConf,
+ Name: agd.ServerGroupName(g.Name),
+ FilteringGroup: fltGrpID,
}
svcSrvGrps[i].Servers, err = g.Servers.toInternal(tlsConf, btdMgr, ratelimitConf, dnsConf)
@@ -63,7 +60,7 @@ func (srvGrps serverGroups) validate() (err error) {
return errors.Error("no server groups")
}
- names := stringutil.NewSet()
+ names := container.NewMapSet[string]()
for i, g := range srvGrps {
err = g.validate()
if err != nil {
@@ -86,9 +83,6 @@ func (srvGrps serverGroups) validate() (err error) {
// TODO(a.garipov): Think about more consistent naming, since this object is a
// configuration, but it also stores other configurations.
type serverGroup struct {
- // BlockPageRedirect is the configuration for the server group's block page.
- BlockPageRedirect *serverGroupBlockPageConfig `yaml:"block_page_redirect"`
-
// DDR is the Discovery Of Designated Resolvers (DDR) configuration for this
// server group.
DDR *ddrConfig `yaml:"ddr"`
@@ -117,11 +111,6 @@ func (g *serverGroup) validate() (err error) {
return errors.Error("no filtering_group")
}
- err = g.BlockPageRedirect.validate()
- if err != nil {
- return fmt.Errorf("block_page_redirect: %w", err)
- }
-
err = g.DDR.validate()
if err != nil {
return fmt.Errorf("ddr: %w", err)
@@ -139,255 +128,3 @@ func (g *serverGroup) validate() (err error) {
return nil
}
-
-// serverGroupBlockPageConfig is the configuration for a [serverGroup]'s block
-// page. See [agd.BlockPageRedirect] and the related types for more
-// documentation and contracts.
-type serverGroupBlockPageConfig struct {
- // Apply defines request parameters based on which the block page is always
- // shown.
- Apply *serverGroupBlockPageApplyConfig `yaml:"apply"`
-
- // Skip defines request parameters based on which the block page is never
- // shown, regardless of the probability.
- Skip *serverGroupBlockPageSkipConfig `yaml:"skip"`
-
- // IPv4 are the IPv4 records of the block page, used to respond to A
- // queries.
- IPv4 []*serverGroupBlockPageRecord `yaml:"ipv4"`
-
- // IPv6 are the IPv6 records of the block page, used to respond to AAAA
- // queries.
- IPv6 []*serverGroupBlockPageRecord `yaml:"ipv6"`
-
- // Probability defines the probability of responding with the block page IPs
- // based on remote address.
- Probability float64 `yaml:"probability"`
-
- // Enabled defines whether the block-page feature is enabled.
- Enabled bool `yaml:"enabled"`
-}
-
-// toInternal returns the block-page redirect configuration for a server group.
-// c is assumed to be valid.
-func (c *serverGroupBlockPageConfig) toInternal() (conf *agd.BlockPageRedirect) {
- if !c.Enabled {
- return &agd.BlockPageRedirect{}
- }
-
- var ipv4 []netip.Addr
- for _, r := range c.IPv4 {
- ipv4 = append(ipv4, r.Address)
- }
-
- var ipv6 []netip.Addr
- for _, r := range c.IPv6 {
- ipv6 = append(ipv6, r.Address)
- }
-
- return &agd.BlockPageRedirect{
- Apply: c.Apply.toInternal(),
- Skip: c.Skip.toInternal(),
- IPv4: ipv4,
- IPv6: ipv6,
- Probability: agd.MustNewProbability(c.Probability),
- Enabled: c.Enabled,
- }
-}
-
-// validate returns an error if the block-page redirect configuration is
-// invalid.
-func (c *serverGroupBlockPageConfig) validate() (err error) {
- switch {
- case c == nil:
- return errNilConfig
- case !c.Enabled:
- return nil
- case len(c.IPv4) == 0 && len(c.IPv6) == 0:
- return errors.Error("ipv4, ipv6, or both must be set")
- }
-
- _, err = agd.NewProbability(c.Probability)
- if err != nil {
- return fmt.Errorf("probability: %w", err)
- }
-
- err = c.validateAddrs()
- if err != nil {
- // Don't wrap the error, because it's informative enough as is.
- return err
- }
-
- err = c.Apply.validate()
- if err != nil {
- return fmt.Errorf("apply: %w", err)
- }
-
- err = c.Skip.validate()
- if err != nil {
- return fmt.Errorf("skip: %w", err)
- }
-
- return nil
-}
-
-// validateAddrs returns an error if the block-page redirect if the IP addresses
-// in the block-page redirect configuration are invalid.
-func (c *serverGroupBlockPageConfig) validateAddrs() (err error) {
- for i, r := range c.IPv4 {
- err = r.validate()
- if err != nil {
- return fmt.Errorf("ipv4: at index %d: address: %w", i, err)
- } else if !r.Address.Is4() {
- return fmt.Errorf("ipv4: at index %d: address: not ipv4: %v", i, r.Address)
- }
- }
-
- for i, r := range c.IPv6 {
- err = r.validate()
- if err != nil {
- return fmt.Errorf("ipv6: at index %d: %w", i, err)
- } else if !r.Address.Is6() {
- return fmt.Errorf("ipv6: at index %d: address: not ipv6: %v", i, r.Address)
- }
- }
-
- return nil
-}
-
-// serverGroupBlockPageRecord is a structure for defining answer records in
-// [serverGroupBlockPageConfig].
-type serverGroupBlockPageRecord struct {
- Address netip.Addr `yaml:"address"`
-}
-
-// validate returns an error if the record configuration is invalid.
-func (c *serverGroupBlockPageRecord) validate() (err error) {
- switch {
- case c == nil:
- return errNilConfig
- case !c.Address.IsValid():
- return errors.Error("invalid addr")
- default:
- return nil
- }
-}
-
-// serverGroupBlockPageApplyConfig defines the conditions for applying the
-// block-page logic for a particular request.
-type serverGroupBlockPageApplyConfig struct {
- // Client are the parameters for clients for which block page is always
- // enabled.
- Client []*serverGroupBlockPageClientConfig `yaml:"client"`
-}
-
-// toInternal returns the block-page redirect applying configuration for a
-// server group. c is assumed to be valid.
-func (c *serverGroupBlockPageApplyConfig) toInternal() (conf *agd.BlockPageRedirectApply) {
- var subnets []netip.Prefix
- for _, cli := range c.Client {
- subnets = append(subnets, cli.Address.Prefix)
- }
-
- return &agd.BlockPageRedirectApply{
- ClientSubnets: subnets,
- }
-}
-
-// validate returns an error if the block-page redirect applying configuration
-// is invalid.
-func (c *serverGroupBlockPageApplyConfig) validate() (err error) {
- if c == nil {
- return errNilConfig
- }
-
- for i, cli := range c.Client {
- err = cli.validate()
- if err != nil {
- return fmt.Errorf("client: at index %d: %w", i, err)
- }
- }
-
- return nil
-}
-
-// serverGroupBlockPageClientConfig is a common structure for defining clients
-// in [serverGroupBlockPageSkipConfig] and [serverGroupBlockPageApplyConfig].
-type serverGroupBlockPageClientConfig struct {
- Address netutil.Prefix `yaml:"address"`
-}
-
-// validate returns an error if the client configuration is invalid.
-func (c *serverGroupBlockPageClientConfig) validate() (err error) {
- switch {
- case c == nil:
- return errNilConfig
- case !c.Address.IsValid():
- return errors.Error("invalid addr")
- default:
- return nil
- }
-}
-
-// serverGroupBlockPageSkipConfig defines the conditions for skipping the block
-// page logic for a particular request.
-type serverGroupBlockPageSkipConfig struct {
- // Client are the parameters for clients for which block page is always
- // disabled.
- Client []*serverGroupBlockPageClientConfig `yaml:"client"`
-
- // QuestionDomains are the parameters for request questions for which block
- // page is always disabled.
- Question []*serverGroupBlockPageQuestionConfig `yaml:"question"`
-}
-
-// toInternal returns the block-page redirect skipping configuration for a
-// server group. c is assumed to be valid.
-func (c *serverGroupBlockPageSkipConfig) toInternal() (conf *agd.BlockPageRedirectSkip) {
- var subnets []netip.Prefix
- for _, cli := range c.Client {
- subnets = append(subnets, cli.Address.Prefix)
- }
-
- var domains []string
- for _, q := range c.Question {
- domains = append(domains, q.Domain)
- }
-
- return &agd.BlockPageRedirectSkip{
- ClientSubnets: subnets,
- QuestionDomains: domains,
- }
-}
-
-// validate returns an error if the block-page redirect skipping configuration
-// is invalid.
-func (c *serverGroupBlockPageSkipConfig) validate() (err error) {
- if c == nil {
- return errNilConfig
- }
-
- for i, cli := range c.Client {
- err = cli.validate()
- if err != nil {
- return fmt.Errorf("client: at index %d: %w", i, err)
- }
- }
-
- for i, q := range c.Question {
- switch {
- case q == nil:
- return fmt.Errorf("question: at index %d: %w", i, errNilConfig)
- case q.Domain == "":
- return fmt.Errorf("question: at index %d: %w", i, errors.Error("empty domain"))
- }
- }
-
- return nil
-}
-
-// serverGroupBlockPageQuestionConfig is a structure for defining question
-// domains in [serverGroupBlockPageRedirectSkip].
-type serverGroupBlockPageQuestionConfig struct {
- Domain string `yaml:"domain"`
-}
diff --git a/internal/cmd/tls.go b/internal/cmd/tls.go
index dd50b16..abeb1ad 100644
--- a/internal/cmd/tls.go
+++ b/internal/cmd/tls.go
@@ -15,9 +15,10 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/service"
- "github.com/AdguardTeam/golibs/stringutil"
"github.com/prometheus/client_golang/prometheus"
)
@@ -96,7 +97,7 @@ func (c *tlsConfig) validate(needsTLS bool) (err error) {
// validateDeviceIDWildcards returns an error if the device ID domain wildcards
// are invalid.
func validateDeviceIDWildcards(wildcards []string) (err error) {
- s := stringutil.NewSet()
+ s := container.NewMapSet[string]()
for i, w := range wildcards {
// TODO(e.burkov): Consider removing this requirement.
if !strings.HasPrefix(w, "*.") {
@@ -185,14 +186,18 @@ func (certs tlsConfigCerts) validate() (err error) {
// ticketRotator is a refresh worker that rereads and resets TLS session tickets.
type ticketRotator struct {
- confs map[*tls.Config][]string
+ errColl errcoll.Interface
+ confs map[*tls.Config][]string
}
// newTicketRotator creates a new TLS session ticket rotator that rotates
// tickets for the TLS configurations of all servers in grps.
//
// grps is assumed to be valid.
-func newTicketRotator(grps []*agd.ServerGroup) (tr *ticketRotator, err error) {
+func newTicketRotator(
+ errColl errcoll.Interface,
+ grps []*agd.ServerGroup,
+) (tr *ticketRotator, err error) {
confs := map[*tls.Config][]string{}
for _, g := range grps {
@@ -209,7 +214,8 @@ func newTicketRotator(grps []*agd.ServerGroup) (tr *ticketRotator, err error) {
}
tr = &ticketRotator{
- confs: confs,
+ errColl: errColl,
+ confs: confs,
}
err = tr.Refresh(context.Background())
@@ -231,7 +237,17 @@ const sessTickLen = 32
var _ agdservice.Refresher = (*ticketRotator)(nil)
// Refresh implements the [agdservice.Refresher] interface for *ticketRotator.
-func (r *ticketRotator) Refresh(_ context.Context) (err error) {
+func (r *ticketRotator) Refresh(ctx context.Context) (err error) {
+ // TODO(a.garipov): Use slog.
+ log.Debug("tickrot_refresh: started")
+ defer log.Debug("tickrot_refresh: finished")
+
+ defer func() {
+ if err != nil {
+ errcoll.Collectf(ctx, r.errColl, "tickrot_refresh: %w", err)
+ }
+ }()
+
for conf, files := range r.confs {
keys := make([][sessTickLen]byte, 0, len(files))
@@ -304,7 +320,7 @@ func setupTicketRotator(
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (err error) {
- tickRot, err := newTicketRotator(srvGrps)
+ tickRot, err := newTicketRotator(errColl, srvGrps)
if err != nil {
return fmt.Errorf("setting up ticket rotator: %w", err)
}
@@ -312,13 +328,11 @@ func setupTicketRotator(
refr := agdservice.NewRefreshWorker(&agdservice.RefreshWorkerConfig{
Context: ctxWithDefaultTimeout,
Refresher: tickRot,
- ErrColl: errColl,
Name: "tickrot",
// TODO(ameshkov): Consider making configurable.
- Interval: 1 * time.Minute,
- RefreshOnShutdown: false,
- RoutineLogsAreDebug: true,
- RandomizeStart: false,
+ Interval: 1 * time.Minute,
+ RefreshOnShutdown: false,
+ RandomizeStart: false,
})
err = refr.Start(context.Background())
if err != nil {
diff --git a/internal/cmd/upstream.go b/internal/cmd/upstream.go
index 3372e2c..2a1ff0b 100644
--- a/internal/cmd/upstream.go
+++ b/internal/cmd/upstream.go
@@ -1,6 +1,7 @@
package cmd
import (
+ "cmp"
"context"
"fmt"
"net/netip"
@@ -13,6 +14,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/prometheus"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/timeutil"
)
@@ -73,7 +75,7 @@ func (c *upstreamConfig) validate() (err error) {
}
}
- return coalesceError(
+ return cmp.Or(
validateProp("fallback", c.Fallback.validate),
validateProp("healthcheck", c.Healthcheck.validate),
)
@@ -171,13 +173,16 @@ func newUpstreamHealthcheck(
conf.Healthcheck.Timeout.Duration,
)
},
- Refresher: handler,
- ErrColl: errColl,
- Name: "upstream healthcheck",
- Interval: conf.Healthcheck.Interval.Duration,
- RefreshOnShutdown: false,
- RoutineLogsAreDebug: true,
- RandomizeStart: false,
+ Refresher: agdservice.NewRefresherWithErrColl(
+ handler,
+ log.Debug,
+ errColl,
+ "upstream_healthcheck_refresh",
+ ),
+ Name: "upstream healthcheck",
+ Interval: conf.Healthcheck.Interval.Duration,
+ RefreshOnShutdown: false,
+ RandomizeStart: false,
})
}
diff --git a/internal/cmd/websvc.go b/internal/cmd/websvc.go
index a294334..31feb18 100644
--- a/internal/cmd/websvc.go
+++ b/internal/cmd/websvc.go
@@ -25,12 +25,15 @@ type webConfig struct {
// LinkedIP is the optional linked IP web server.
LinkedIP *linkedIPServer `yaml:"linked_ip"`
- // SafeBrowsing is the optional safe browsing block page web server.
- SafeBrowsing *blockPageServer `yaml:"safe_browsing"`
-
// AdultBlocking is the optional adult blocking block page web server.
AdultBlocking *blockPageServer `yaml:"adult_blocking"`
+ // GeneralBlocking is the optional general block-page web server.
+ GeneralBlocking *blockPageServer `yaml:"general_blocking"`
+
+ // SafeBrowsing is the optional safe browsing block page web server.
+ SafeBrowsing *blockPageServer `yaml:"safe_browsing"`
+
// RootRedirectURL is the URL to which non-DNS and non-Debug HTTP requests
// are redirected. If not set, a 404 page is shown.
RootRedirectURL *urlutil.URL `yaml:"root_redirect_url"`
@@ -86,6 +89,11 @@ func (c *webConfig) toInternal(
return nil, fmt.Errorf("converting adult_blocking: %w", err)
}
+ conf.GeneralBlocking, err = c.GeneralBlocking.toInternal()
+ if err != nil {
+ return nil, fmt.Errorf("converting general_blocking: %w", err)
+ }
+
conf.SafeBrowsing, err = c.SafeBrowsing.toInternal()
if err != nil {
return nil, fmt.Errorf("converting safe_browsing: %w", err)
@@ -146,16 +154,21 @@ func (c *webConfig) validate() (err error) {
return fmt.Errorf("linked_ip: %w", err)
}
- err = c.SafeBrowsing.validate()
- if err != nil {
- return fmt.Errorf("safe_browsing: %w", err)
- }
-
err = c.AdultBlocking.validate()
if err != nil {
return fmt.Errorf("adult_blocking: %w", err)
}
+ err = c.GeneralBlocking.validate()
+ if err != nil {
+ return fmt.Errorf("general_blocking: %w", err)
+ }
+
+ err = c.SafeBrowsing.validate()
+ if err != nil {
+ return fmt.Errorf("safe_browsing: %w", err)
+ }
+
err = c.StaticContent.validate()
if err != nil {
return fmt.Errorf("static_content: %w", err)
diff --git a/internal/consul/allowlist.go b/internal/consul/allowlist.go
index 6627099..60ed0e7 100644
--- a/internal/consul/allowlist.go
+++ b/internal/consul/allowlist.go
@@ -13,6 +13,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
@@ -23,12 +24,14 @@ type AllowlistRefresher struct {
allowlist *ratelimit.DynamicAllowlist
http *agdhttp.Client
url *url.URL
+ errColl errcoll.Interface
}
// NewAllowlistRefresher returns a properly initialized *AllowlistRefresher.
func NewAllowlistRefresher(
allowlist *ratelimit.DynamicAllowlist,
consulURL *url.URL,
+ errColl errcoll.Interface,
) (l *AllowlistRefresher, err error) {
l = &AllowlistRefresher{
allowlist: allowlist,
@@ -36,7 +39,8 @@ func NewAllowlistRefresher(
// TODO(a.garipov): Consider making configurable.
Timeout: 15 * time.Second,
}),
- url: consulURL,
+ url: consulURL,
+ errColl: errColl,
}
err = l.Refresh(context.Background())
@@ -53,6 +57,10 @@ var _ agdservice.Refresher = (*AllowlistRefresher)(nil)
// Refresh implements the [agdservice.Refresher] interface for
// *AllowlistRefresher.
func (l *AllowlistRefresher) Refresh(ctx context.Context) (err error) {
+ // TODO(a.garipov): Use slog.
+ log.Info("allowlist_refresh: started")
+ defer log.Info("allowlist_refresh: finished")
+
defer func() {
metrics.ConsulAllowlistUpdateTime.SetToCurrentTime()
metrics.SetStatusGauge(metrics.ConsulAllowlistUpdateStatus, err)
@@ -60,7 +68,10 @@ func (l *AllowlistRefresher) Refresh(ctx context.Context) (err error) {
consulNets, err := l.loadConsul(ctx)
if err != nil {
- return fmt.Errorf("reading consul: %w", err)
+ errcoll.Collectf(ctx, l.errColl, "allowlist_refresh: %w", err)
+
+ // Don't wrap the error, because it's informative enough as is.
+ return err
}
log.Info("allowlist: loaded %d records from %s", len(consulNets), l.url)
diff --git a/internal/consul/allowlist_test.go b/internal/consul/allowlist_test.go
index 6a5e69c..bdae898 100644
--- a/internal/consul/allowlist_test.go
+++ b/internal/consul/allowlist_test.go
@@ -2,6 +2,7 @@ package consul_test
import (
"context"
+ "io"
"net/http"
"net/http/httptest"
"net/netip"
@@ -9,6 +10,7 @@ import (
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/consul"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
"github.com/AdguardTeam/golibs/testutil"
@@ -70,12 +72,18 @@ func TestNewAllowlistRefresher(t *testing.T) {
u := handleWithURL(t, http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
pt := testutil.PanicT{}
- _, err := rw.Write([]byte(testCases[i].resp))
+ _, err := io.WriteString(rw, testCases[i].resp)
require.NoError(pt, err)
}))
t.Run(tc.name, func(t *testing.T) {
- _, err := consul.NewAllowlistRefresher(al, u)
+ errColl := &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) {
+ panic("not implemented")
+ },
+ }
+
+ _, err := consul.NewAllowlistRefresher(al, u, errColl)
require.NoError(t, err)
for _, ip := range tc.wantAllow {
@@ -104,10 +112,18 @@ func TestNewAllowlistRefresher(t *testing.T) {
}))
wantErr := &agdhttp.StatusError{}
- _, err := consul.NewAllowlistRefresher(al, u)
+ var gotCollErr error
+ errColl := &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) {
+ gotCollErr = err
+ },
+ }
+
+ _, err := consul.NewAllowlistRefresher(al, u, errColl)
require.ErrorAs(t, err, &wantErr)
assert.Equal(t, wantErr.Got, status)
+ assert.ErrorAs(t, gotCollErr, &wantErr)
})
}
@@ -116,11 +132,18 @@ func TestAllowlistRefresher_Refresh_deadline(t *testing.T) {
u := handleWithURL(t, http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
pt := testutil.PanicT{}
- _, err := rw.Write([]byte(`[]`))
+ _, err := io.WriteString(rw, `[]`)
require.NoError(pt, err)
}))
- c, err := consul.NewAllowlistRefresher(al, u)
+ var gotCollErr error
+ errColl := &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) {
+ gotCollErr = err
+ },
+ }
+
+ c, err := consul.NewAllowlistRefresher(al, u, errColl)
require.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
@@ -128,4 +151,5 @@ func TestAllowlistRefresher_Refresh_deadline(t *testing.T) {
err = c.Refresh(ctx)
assert.ErrorIs(t, err, context.Canceled)
+ assert.ErrorIs(t, gotCollErr, context.Canceled)
}
diff --git a/internal/debugsvc/debugsvc_test.go b/internal/debugsvc/debugsvc_test.go
index fa339f2..ae6bd4b 100644
--- a/internal/debugsvc/debugsvc_test.go
+++ b/internal/debugsvc/debugsvc_test.go
@@ -7,7 +7,6 @@ import (
"testing"
"time"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/debugsvc"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
@@ -45,11 +44,11 @@ func TestService_Start(t *testing.T) {
var err error
require.NotPanics(t, func() {
- err = svc.Start(agdtest.ContextWithTimeout(t, testTimeout))
+ err = svc.Start(testutil.ContextWithTimeout(t, testTimeout))
})
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return svc.Shutdown(agdtest.ContextWithTimeout(t, testTimeout))
+ return svc.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
})
client := http.Client{
diff --git a/internal/dnsdb/buffer.go b/internal/dnsdb/buffer.go
index 78f4ce5..4e23647 100644
--- a/internal/dnsdb/buffer.go
+++ b/internal/dnsdb/buffer.go
@@ -5,6 +5,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/golibs/container"
"github.com/miekg/dns"
)
@@ -63,7 +64,7 @@ func (b *buffer) all() (records []*record) {
defer b.mu.Unlock()
for key, val := range b.entries {
- if len(val.answers) == 0 {
+ if val.answers.Len() == 0 {
records = append(records, &record{
target: key.target,
hits: val.hits,
@@ -73,7 +74,7 @@ func (b *buffer) all() (records []*record) {
continue
}
- for a := range val.answers {
+ val.answers.Range(func(a recordAnswer) (cont bool) {
records = append(records, &record{
target: key.target,
answer: a.value,
@@ -81,24 +82,26 @@ func (b *buffer) all() (records []*record) {
rrType: a.rrType,
rcode: a.rcode,
})
- }
+
+ return true
+ })
}
return records
}
-// toAnswerSet converts a slice of [dns.RR] to a map that can easier be
+// toAnswerSet converts a slice of [dns.RR] to a set that can easier be
// serialized to a csv.
-func toAnswerSet(answers []dns.RR, rc dnsmsg.RCode) (answerSet map[recordAnswer]unit) {
- answerSet = map[recordAnswer]unit{}
+func toAnswerSet(answers []dns.RR, rc dnsmsg.RCode) (answerSet *container.MapSet[recordAnswer]) {
+ answerSet = container.NewMapSet[recordAnswer]()
for _, a := range answers {
ansStr := answerString(a)
if ansStr != "" {
- answerSet[recordAnswer{
+ answerSet.Add(recordAnswer{
value: ansStr,
rrType: a.Header().Rrtype,
rcode: rc,
- }] = unit{}
+ })
}
}
diff --git a/internal/dnsdb/http.go b/internal/dnsdb/http.go
index ace0110..7e8a7af 100644
--- a/internal/dnsdb/http.go
+++ b/internal/dnsdb/http.go
@@ -38,9 +38,12 @@ func (db *Default) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}()
var rw io.Writer = w
- // TODO(a.garipov): Consider parsing the quality value.
- if strings.Contains(r.Header.Get(httphdr.AcceptEncoding), "gzip") {
- h.Set(httphdr.ContentEncoding, "gzip")
+
+ // TODO(a.garipov): Parse the quality value.
+ //
+ // TODO(a.garipov): Support other compression algorithms.
+ if strings.Contains(r.Header.Get(httphdr.AcceptEncoding), agdhttp.HdrValGzip) {
+ h.Set(httphdr.ContentEncoding, agdhttp.HdrValGzip)
gw := gzip.NewWriter(w)
defer func() { err = errors.WithDeferred(err, gw.Close()) }()
diff --git a/internal/dnsdb/http_test.go b/internal/dnsdb/http_test.go
index c13759b..bbe3c6b 100644
--- a/internal/dnsdb/http_test.go
+++ b/internal/dnsdb/http_test.go
@@ -31,7 +31,7 @@ func TestDefault_ServeHTTP(t *testing.T) {
successHdr := http.Header{
httphdr.ContentType: []string{agdhttp.HdrValTextCSV},
httphdr.Trailer: []string{httphdr.XError},
- httphdr.ContentEncoding: []string{"gzip"},
+ httphdr.ContentEncoding: []string{agdhttp.HdrValGzip},
}
newMsg := func(rcode int, name string, qtype uint16) (m *dns.Msg) {
@@ -112,7 +112,7 @@ func TestDefault_ServeHTTP(t *testing.T) {
(&url.URL{Scheme: "http", Host: "example.com"}).String(),
nil,
)
- r.Header.Add(httphdr.AcceptEncoding, "gzip")
+ r.Header.Add(httphdr.AcceptEncoding, agdhttp.HdrValGzip)
for _, tc := range testCases {
db := dnsdb.New(&dnsdb.DefaultConfig{
diff --git a/internal/dnsdb/record.go b/internal/dnsdb/record.go
index a059812..c6bd38d 100644
--- a/internal/dnsdb/record.go
+++ b/internal/dnsdb/record.go
@@ -5,6 +5,7 @@ import (
"strings"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/golibs/container"
"github.com/miekg/dns"
)
@@ -69,12 +70,9 @@ type recordKey struct {
qt dnsmsg.RRType
}
-// unit is a convenient alias for struct{}.
-type unit = struct{}
-
// recordValue contains the values for a single record key.
type recordValue struct {
- answers map[recordAnswer]unit
+ answers *container.MapSet[recordAnswer]
hits uint64
}
diff --git a/internal/dnsmsg/blockingmode.go b/internal/dnsmsg/blockingmode.go
index a7b68cf..f87e46e 100644
--- a/internal/dnsmsg/blockingmode.go
+++ b/internal/dnsmsg/blockingmode.go
@@ -17,11 +17,15 @@ type BlockingMode interface {
// BlockingModeCustomIP makes the [dnsmsg.Constructor] return responses with
// custom IP addresses to A and AAAA requests. For all other types of requests,
-// as well as if one of the addresses isn't set, it returns a response with no
-// answers (aka NODATA).
+// as well as in case the address corresponding to IP version is not set, it
+// returns a response with no answers (aka NODATA).
type BlockingModeCustomIP struct {
- IPv4 netip.Addr
- IPv6 netip.Addr
+ // IPv4 is a slice of valid IPv4 addresses used in responses to A requests.
+ IPv4 []netip.Addr
+
+ // IPv6 is a slice of valid IPv6 addresses used in responses to AAAA
+ // requests.
+ IPv6 []netip.Addr
}
// isBlockingMode implements the BlockingMode interface for
diff --git a/internal/dnsmsg/cloner.go b/internal/dnsmsg/cloner.go
index 7f82d4a..df8dc24 100644
--- a/internal/dnsmsg/cloner.go
+++ b/internal/dnsmsg/cloner.go
@@ -9,8 +9,8 @@ import (
// Cloner is a pool that can clone common parts of DNS messages with fewer
// allocations.
//
-// TODO(a.garipov): Use in filtering when cloning a [filter.ResultModified]
-// message.
+// TODO(a.garipov): Use in filtering when cloning a
+// [filter.ResultModifiedResponse] message.
//
// TODO(a.garipov): Use in [Constructor].
type Cloner struct {
diff --git a/internal/dnsmsg/cloner_test.go b/internal/dnsmsg/cloner_test.go
index 3da1b14..961ba72 100644
--- a/internal/dnsmsg/cloner_test.go
+++ b/internal/dnsmsg/cloner_test.go
@@ -328,7 +328,7 @@ func BenchmarkClone(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
msgSink = dnsmsg.Clone(tc.msg)
}
@@ -372,7 +372,7 @@ func BenchmarkCloner_Clone(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for i := range b.N {
msgSink = c.Clone(tc.msg)
if i < b.N-1 {
// Don't dispose of the last one to be sure that we can
diff --git a/internal/dnsmsg/constructor.go b/internal/dnsmsg/constructor.go
index 92b9f81..244880d 100644
--- a/internal/dnsmsg/constructor.go
+++ b/internal/dnsmsg/constructor.go
@@ -33,6 +33,17 @@ func NewConstructor(cloner *Cloner, bm BlockingMode, respTTL time.Duration) (c *
}
}
+// Cloner returns the constructor's Cloner.
+func (c *Constructor) Cloner() (cloner *Cloner) {
+ return c.cloner
+}
+
+// FilteredResponseTTL returns the TTL that the constructor uses to build
+// blocked responses.
+func (c *Constructor) FilteredResponseTTL() (ttl time.Duration) {
+ return c.fltRespTTL
+}
+
// NewBlockedRespMsg returns a blocked DNS response message based on the
// constructor's blocking mode.
func (c *Constructor) NewBlockedRespMsg(req *dns.Msg) (msg *dns.Msg, err error) {
@@ -65,12 +76,12 @@ func (c *Constructor) newBlockedCustomIPRespMsg(
) (msg *dns.Msg, err error) {
switch qt := req.Question[0].Qtype; qt {
case dns.TypeA:
- if m.IPv4.IsValid() {
- return c.NewIPRespMsg(req, m.IPv4)
+ if len(m.IPv4) > 0 {
+ return c.NewIPRespMsg(req, m.IPv4...)
}
case dns.TypeAAAA:
- if m.IPv6.IsValid() {
- return c.NewIPRespMsg(req, m.IPv6)
+ if len(m.IPv6) > 0 {
+ return c.NewIPRespMsg(req, m.IPv6...)
}
default:
// Go on.
@@ -202,7 +213,7 @@ func (c *Constructor) AppendDebugExtra(req, resp *dns.Msg, str string) (err erro
// TODO(a.garipov): Use slices.Chunk in Go 1.23.
newStr := make([]string, strNum)
- for i := 0; i < strNum; i++ {
+ for i := range strNum {
start := i * MaxTXTStringLen
var cutStr string
diff --git a/internal/dnsmsg/constructor_test.go b/internal/dnsmsg/constructor_test.go
index 113515f..ccb3bfc 100644
--- a/internal/dnsmsg/constructor_test.go
+++ b/internal/dnsmsg/constructor_test.go
@@ -2,6 +2,7 @@ package dnsmsg_test
import (
"net"
+ "net/netip"
"strings"
"testing"
@@ -81,26 +82,34 @@ func TestConstructor_NewBlockedRespMsg_customIP(t *testing.T) {
wantAAAA bool
}{{
messages: dnsmsg.NewConstructor(nil, &dnsmsg.BlockingModeCustomIP{
- IPv4: testIPv4,
- IPv6: testIPv6,
+ IPv4: []netip.Addr{testIPv4},
+ IPv6: []netip.Addr{testIPv6},
}, testFltRespTTL),
name: "both",
wantA: true,
wantAAAA: true,
}, {
messages: dnsmsg.NewConstructor(nil, &dnsmsg.BlockingModeCustomIP{
- IPv4: testIPv4,
+ IPv4: []netip.Addr{testIPv4},
}, testFltRespTTL),
name: "ipv4_only",
wantA: true,
wantAAAA: false,
}, {
messages: dnsmsg.NewConstructor(nil, &dnsmsg.BlockingModeCustomIP{
- IPv6: testIPv6,
+ IPv6: []netip.Addr{testIPv6},
}, testFltRespTTL),
name: "ipv6_only",
wantA: false,
wantAAAA: true,
+ }, {
+ messages: dnsmsg.NewConstructor(nil, &dnsmsg.BlockingModeCustomIP{
+ IPv4: []netip.Addr{},
+ IPv6: []netip.Addr{},
+ }, testFltRespTTL),
+ name: "empty",
+ wantA: false,
+ wantAAAA: false,
}}
for _, tc := range testCases {
diff --git a/internal/dnsserver/cache/cache_test.go b/internal/dnsserver/cache/cache_test.go
index 1483a71..2083cdd 100644
--- a/internal/dnsserver/cache/cache_test.go
+++ b/internal/dnsserver/cache/cache_test.go
@@ -194,7 +194,7 @@ func TestMiddleware_Wrap(t *testing.T) {
var err error
var nrw *dnsserver.NonWriterResponseWriter
- for i := 0; i < N; i++ {
+ for range N {
addr := &net.UDPAddr{IP: net.IP{1, 2, 3, 4}, Port: 53}
nrw = dnsserver.NewNonWriterResponseWriter(addr, addr)
err = withCache.ServeDNS(context.Background(), nrw, tc.req)
diff --git a/internal/dnsserver/dnsserver.go b/internal/dnsserver/dnsserver.go
index df85084..7a39608 100644
--- a/internal/dnsserver/dnsserver.go
+++ b/internal/dnsserver/dnsserver.go
@@ -14,7 +14,7 @@ import (
)
// Handler is an interface that defines how the DNS server would process DNS
-// queries. Inspired by net/http.Server and it's Handler.
+// queries. Inspired by net/http.Server and it's Handler.
type Handler interface {
// ServeDNS should process the request and write a DNS response to the
// specified ResponseWriter.
@@ -28,7 +28,7 @@ type Handler interface {
}
// The HandlerFunc type is an adapter to allow the use of ordinary functions
-// as DNS handlers. If f is a function with the appropriate signature,
+// as DNS handlers. If f is a function with the appropriate signature,
// HandlerFunc(f) is a Handler that calls f.
type HandlerFunc func(context.Context, ResponseWriter, *dns.Msg) (err error)
diff --git a/internal/dnsserver/dnsserver_test.go b/internal/dnsserver/dnsserver_test.go
index 8fd0d68..038c7d7 100644
--- a/internal/dnsserver/dnsserver_test.go
+++ b/internal/dnsserver/dnsserver_test.go
@@ -1,9 +1,7 @@
package dnsserver_test
import (
- "context"
"testing"
- "time"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/golibs/testutil"
@@ -15,16 +13,3 @@ func TestMain(m *testing.M) {
// testTimeout is a common timeout for tests.
const testTimeout = dnsserver.DefaultReadTimeout
-
-// contextWithTimeout is a helper that creates a new context with timeout and
-// registers ctx's cleanup with t.Cleanup.
-//
-// TODO(a.garipov): Move to golibs and DRY.
-func contextWithTimeout(tb testing.TB, timeout time.Duration) (ctx context.Context) {
- tb.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), timeout)
- tb.Cleanup(cancel)
-
- return ctx
-}
diff --git a/internal/dnsserver/dnsservertest/handler.go b/internal/dnsserver/dnsservertest/handler.go
index 179e8c9..ca0c6b3 100644
--- a/internal/dnsserver/dnsservertest/handler.go
+++ b/internal/dnsserver/dnsservertest/handler.go
@@ -33,7 +33,7 @@ func CreateTestHandler(recordsCount int) (h dnsserver.Handler) {
}
ip := netutil.IPv4Localhost().Prev()
- for i := 0; i < recordsCount; i++ {
+ for range recordsCount {
// Add 1 to make sure that each IP is valid.
ip = ip.Next()
ans = append(ans, &dns.A{Hdr: hdr, A: ip.AsSlice()})
diff --git a/internal/dnsserver/forward/forward.go b/internal/dnsserver/forward/forward.go
index 22b9c93..705b458 100644
--- a/internal/dnsserver/forward/forward.go
+++ b/internal/dnsserver/forward/forward.go
@@ -34,6 +34,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
"golang.org/x/exp/rand"
)
@@ -265,6 +266,10 @@ func (h *Handler) exchange(
// upstreams is detected to be up again, requests are redirected back to the
// main upstreams.
func (h *Handler) Refresh(ctx context.Context) (err error) {
+ // TODO(a.garipov): Use slog.
+ log.Debug("upstream_healthcheck_refresh: started")
+ defer log.Debug("upstream_healthcheck_refresh: finished")
+
return h.refresh(ctx, false)
}
diff --git a/internal/dnsserver/forward/forward_test.go b/internal/dnsserver/forward/forward_test.go
index 352b32e..61f103c 100644
--- a/internal/dnsserver/forward/forward_test.go
+++ b/internal/dnsserver/forward/forward_test.go
@@ -21,18 +21,6 @@ func TestMain(m *testing.M) {
// testTimeout is the timeout for tests.
const testTimeout = 1 * time.Second
-// newTimeoutCtx is a test helper that returns a context with a timeout of
-// [testTimeout] and its cancel function being called in the test cleanup. It
-// should not be used where cancelation is expected sooner.
-func newTimeoutCtx(tb testing.TB, parent context.Context) (ctx context.Context) {
- tb.Helper()
-
- ctx, cancel := context.WithTimeout(parent, testTimeout)
- tb.Cleanup(cancel)
-
- return ctx
-}
-
func TestHandler_ServeDNS(t *testing.T) {
srv, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
@@ -49,7 +37,7 @@ func TestHandler_ServeDNS(t *testing.T) {
rw := dnsserver.NewNonWriterResponseWriter(srv.LocalUDPAddr(), srv.LocalUDPAddr())
// Check the handler's ServeDNS method
- err := handler.ServeDNS(newTimeoutCtx(t, context.Background()), rw, req)
+ err := handler.ServeDNS(testutil.ContextWithTimeout(t, testTimeout), rw, req)
require.NoError(t, err)
res := rw.Msg()
diff --git a/internal/dnsserver/forward/healthcheck_test.go b/internal/dnsserver/forward/healthcheck_test.go
index d0dbab2..6524a81 100644
--- a/internal/dnsserver/forward/healthcheck_test.go
+++ b/internal/dnsserver/forward/healthcheck_test.go
@@ -9,6 +9,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/forward"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -63,32 +64,30 @@ func TestHandler_Refresh(t *testing.T) {
req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
rw := dnsserver.NewNonWriterResponseWriter(fallback.LocalUDPAddr(), fallback.LocalUDPAddr())
- ctx := context.Background()
-
- err := handler.ServeDNS(newTimeoutCtx(t, ctx), rw, req)
+ err := handler.ServeDNS(testutil.ContextWithTimeout(t, testTimeout), rw, req)
require.Error(t, err)
assert.Equal(t, int64(2), upstreamRequestsCount.Load())
- err = handler.Refresh(newTimeoutCtx(t, ctx))
+ err = handler.Refresh(testutil.ContextWithTimeout(t, testTimeout))
require.Error(t, err)
assert.Equal(t, int64(4), upstreamRequestsCount.Load())
- err = handler.ServeDNS(newTimeoutCtx(t, ctx), rw, req)
+ err = handler.ServeDNS(testutil.ContextWithTimeout(t, testTimeout), rw, req)
require.NoError(t, err)
assert.Equal(t, int64(4), upstreamRequestsCount.Load())
// Now, set upstream up.
upstreamIsUp.Store(true)
- err = handler.ServeDNS(newTimeoutCtx(t, ctx), rw, req)
+ err = handler.ServeDNS(testutil.ContextWithTimeout(t, testTimeout), rw, req)
require.NoError(t, err)
assert.Equal(t, int64(4), upstreamRequestsCount.Load())
- err = handler.Refresh(newTimeoutCtx(t, ctx))
+ err = handler.Refresh(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
assert.Equal(t, int64(5), upstreamRequestsCount.Load())
- err = handler.ServeDNS(newTimeoutCtx(t, ctx), rw, req)
+ err = handler.ServeDNS(testutil.ContextWithTimeout(t, testTimeout), rw, req)
require.NoError(t, err)
assert.Equal(t, int64(6), upstreamRequestsCount.Load())
}
diff --git a/internal/dnsserver/forward/upstreamplain_test.go b/internal/dnsserver/forward/upstreamplain_test.go
index ddf4895..89487c2 100644
--- a/internal/dnsserver/forward/upstreamplain_test.go
+++ b/internal/dnsserver/forward/upstreamplain_test.go
@@ -44,7 +44,7 @@ func TestUpstreamPlain_Exchange(t *testing.T) {
defer log.OnCloserError(u, log.DEBUG)
req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
- res, nw, err := u.Exchange(newTimeoutCtx(t, context.Background()), req)
+ res, nw, err := u.Exchange(testutil.ContextWithTimeout(t, testTimeout), req)
require.NoError(t, err)
require.NotNil(t, res)
dnsservertest.RequireResponse(t, req, res, 1, dns.RcodeSuccess, false)
@@ -95,9 +95,7 @@ func TestUpstreamPlain_Exchange_truncated(t *testing.T) {
})
defer log.OnCloserError(uUDP, log.DEBUG)
- ctx := context.Background()
-
- res, nw, err := uUDP.Exchange(newTimeoutCtx(t, ctx), req)
+ res, nw, err := uUDP.Exchange(testutil.ContextWithTimeout(t, testTimeout), req)
require.NoError(t, err)
dnsservertest.RequireResponse(t, req, res, 0, dns.RcodeSuccess, true)
@@ -110,7 +108,7 @@ func TestUpstreamPlain_Exchange_truncated(t *testing.T) {
})
defer log.OnCloserError(uTCP, log.DEBUG)
- res, nw, err = uTCP.Exchange(newTimeoutCtx(t, ctx), req)
+ res, nw, err = uTCP.Exchange(testutil.ContextWithTimeout(t, testTimeout), req)
require.NoError(t, err)
dnsservertest.RequireResponse(t, req, res, 1, dns.RcodeSuccess, false)
@@ -124,7 +122,7 @@ func TestUpstreamPlain_Exchange_truncated(t *testing.T) {
})
defer log.OnCloserError(uAny, log.DEBUG)
- res, nw, err = uAny.Exchange(newTimeoutCtx(t, ctx), req)
+ res, nw, err = uAny.Exchange(testutil.ContextWithTimeout(t, testTimeout), req)
require.NoError(t, err)
dnsservertest.RequireResponse(t, req, res, 1, dns.RcodeSuccess, false)
@@ -165,7 +163,8 @@ func TestUpstreamPlain_Exchange_fallbackFail(t *testing.T) {
var resp *dns.Msg
var err error
go func() {
- resp, _, err = u.Exchange(newTimeoutCtx(t, context.Background()), req)
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ resp, _, err = u.Exchange(ctx, req)
testutil.RequireSend(pt, respCh, struct{}{}, testTimeout)
}()
@@ -266,7 +265,8 @@ func TestUpstreamPlain_Exchange_fallbackSuccess(t *testing.T) {
var actualResp *dns.Msg
var err error
go func() {
- actualResp, _, err = u.Exchange(newTimeoutCtx(t, context.Background()), clonedReq)
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ actualResp, _, err = u.Exchange(ctx, clonedReq)
testutil.RequireSend(pt, respCh, struct{}{}, testTimeout)
}()
diff --git a/internal/dnsserver/go.mod b/internal/dnsserver/go.mod
index 5cbeb78..22f1ff3 100644
--- a/internal/dnsserver/go.mod
+++ b/internal/dnsserver/go.mod
@@ -1,44 +1,45 @@
module github.com/AdguardTeam/AdGuardDNS/internal/dnsserver
-go 1.21.8
+go 1.22.4
require (
- github.com/AdguardTeam/golibs v0.20.1
- github.com/ameshkov/dnscrypt/v2 v2.2.7
+ github.com/AdguardTeam/golibs v0.23.2
+ github.com/ameshkov/dnscrypt/v2 v2.3.0
github.com/ameshkov/dnsstamps v1.0.3
github.com/bluele/gcache v0.0.2
github.com/miekg/dns v1.1.58
- github.com/panjf2000/ants/v2 v2.9.0
+ github.com/panjf2000/ants/v2 v2.9.1
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
- github.com/prometheus/client_golang v1.18.0
- github.com/quic-go/quic-go v0.41.0
- github.com/stretchr/testify v1.8.4
- golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
- golang.org/x/net v0.21.0
- golang.org/x/sys v0.17.0
+ github.com/prometheus/client_golang v1.19.0
+ github.com/quic-go/quic-go v0.42.0
+ github.com/stretchr/testify v1.9.0
+ golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8
+ golang.org/x/net v0.24.0
+ golang.org/x/sys v0.19.0
)
require (
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/go-logr/logr v1.4.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
- github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
+ github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
github.com/kr/text v0.2.0 // indirect
- github.com/onsi/ginkgo/v2 v2.15.0 // indirect
+ github.com/onsi/ginkgo/v2 v2.17.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/client_model v0.5.0 // indirect
- github.com/prometheus/common v0.46.0 // indirect
- github.com/prometheus/procfs v0.12.0 // indirect
+ github.com/prometheus/client_model v0.6.1 // indirect
+ github.com/prometheus/common v0.52.3 // indirect
+ github.com/prometheus/procfs v0.13.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
go.uber.org/mock v0.4.0 // indirect
- golang.org/x/crypto v0.19.0 // indirect
- golang.org/x/mod v0.15.0 // indirect
+ golang.org/x/crypto v0.22.0 // indirect
+ golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/sync v0.7.0 // indirect
golang.org/x/text v0.14.0 // indirect
- golang.org/x/tools v0.18.0 // indirect
- google.golang.org/protobuf v1.32.0 // indirect
+ golang.org/x/tools v0.20.0 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/internal/dnsserver/go.sum b/internal/dnsserver/go.sum
index 6e91b7f..2104d62 100644
--- a/internal/dnsserver/go.sum
+++ b/internal/dnsserver/go.sum
@@ -1,19 +1,19 @@
-github.com/AdguardTeam/golibs v0.20.1 h1:ol8qLjWGZhU9paMMwN+OLWVTUigGsXa29iVTyd62VKY=
-github.com/AdguardTeam/golibs v0.20.1/go.mod h1:bgcMgRviCKyU6mkrX+RtT/OsKPFzyppelfRsksMG3KU=
+github.com/AdguardTeam/golibs v0.23.2 h1:rMjYantwtQ39e8G4zBQ6ZLlm4s3XH30Bc9VxhoOHwao=
+github.com/AdguardTeam/golibs v0.23.2/go.mod h1:o9i55Sx6v7qogRQeqaBfmLbC/pZqeMBWi015U5PTDY0=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us=
-github.com/ameshkov/dnscrypt/v2 v2.2.7 h1:aEitLIR8HcxVodZ79mgRcCiC0A0I5kZPBuWGFwwulAw=
-github.com/ameshkov/dnscrypt/v2 v2.2.7/go.mod h1:qPWhwz6FdSmuK7W4sMyvogrez4MWdtzosdqlr0Rg3ow=
+github.com/ameshkov/dnscrypt/v2 v2.3.0 h1:pDXDF7eFa6Lw+04C0hoMh8kCAQM8NwUdFEllSP2zNLs=
+github.com/ameshkov/dnscrypt/v2 v2.3.0/go.mod h1:N5hDwgx2cNb4Ay7AhvOSKst+eUiOZ/vbKRO9qMpQttE=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
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=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -22,40 +22,40 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo=
-github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
+github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
+github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
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.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
-github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
-github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
+github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
+github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
-github.com/panjf2000/ants/v2 v2.9.0 h1:SztCLkVxBRigbg+vt0S5QvF5vxAbxbKt09/YfAJ0tEo=
-github.com/panjf2000/ants/v2 v2.9.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
+github.com/panjf2000/ants/v2 v2.9.1 h1:Q5vh5xohbsZXGcD6hhszzGqB7jSSc2/CRr3QKIga8Kw=
+github.com/panjf2000/ants/v2 v2.9.1/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
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/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
-github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
-github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
-github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
-github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y=
-github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ=
-github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
-github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
+github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
+github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.52.3 h1:5f8uj6ZwHSscOGNdIQg6OiZv/ybiK2CO2q2drVZAQSA=
+github.com/prometheus/common v0.52.3/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
+github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
+github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
-github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
-github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
+github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
+github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -65,29 +65,31 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
-golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
-golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
-golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
-golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
-golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
-golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
-golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
+golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc=
+golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
+golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
-golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
-golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
-golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
+golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
-golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
-google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
-google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
+golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
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/packetconn_linux_test.go b/internal/dnsserver/netext/packetconn_linux_test.go
index e315457..45a2772 100644
--- a/internal/dnsserver/netext/packetconn_linux_test.go
+++ b/internal/dnsserver/netext/packetconn_linux_test.go
@@ -24,7 +24,7 @@ func TestSessionPacketConn(t *testing.T) {
// Try the test multiple times to reduce flakiness due to UDP failures.
var success4, success6 bool
- for i := 0; i < numTries; i++ {
+ for i := range numTries {
var isTimeout4, isTimeout6 bool
success4 = t.Run(fmt.Sprintf("ipv4_%d", i), func(t *testing.T) {
isTimeout4 = testSessionPacketConn(t, "udp4", "0.0.0.0:0", net.IP{127, 0, 0, 1})
diff --git a/internal/dnsserver/pool/conn.go b/internal/dnsserver/pool/conn.go
index 3864d4a..44443a1 100644
--- a/internal/dnsserver/pool/conn.go
+++ b/internal/dnsserver/pool/conn.go
@@ -6,7 +6,7 @@ import (
)
// Conn wraps a net.Conn and contains additional info that could be required
-// by the Pool instance. It can be used directly instead of a net.Conn or you
+// by the Pool instance. It can be used directly instead of a net.Conn or you
// may choose to use the underlying Conn.Conn instead.
type Conn struct {
net.Conn
diff --git a/internal/dnsserver/pool/pool.go b/internal/dnsserver/pool/pool.go
index 298befe..4d1cc03 100644
--- a/internal/dnsserver/pool/pool.go
+++ b/internal/dnsserver/pool/pool.go
@@ -14,7 +14,7 @@ import (
// ErrClosed indicates that the Pool is closed and cannot be used anymore.
const ErrClosed = errors.Error("the pool is closed")
-// Factory is a type for the Pool's factory method. Factory implementation
+// Factory is a type for the Pool's factory method. Factory implementation
// must use the context's deadline if it's specified.
type Factory func(ctx context.Context) (conn net.Conn, err error)
@@ -35,8 +35,8 @@ type Pool struct {
factory Factory
}
-// NewPool creates a new Pool instance. maxCapacity configures the maximum
-// number of idle connections in the pool. If the pool is full,
+// NewPool creates a new Pool instance. maxCapacity configures the maximum
+// number of idle connections in the pool. If the pool is full,
// Put will close the connection instead of adding it to the pool.
func NewPool(maxCapacity int, factory Factory) (p *Pool) {
return &Pool{
@@ -45,7 +45,7 @@ func NewPool(maxCapacity int, factory Factory) (p *Pool) {
}
}
-// Get returns a free connection from the pool. If there are no connections it
+// Get returns a free connection from the pool. If there are no connections it
// will use the Factory method to create a new one.
func (p *Pool) Get(ctx context.Context) (conn *Conn, err error) {
p.connsChanMu.RLock()
@@ -80,7 +80,7 @@ func (p *Pool) Get(ctx context.Context) (conn *Conn, err error) {
}
}
-// Put puts the connection back to the pool. If the pool is closed,
+// Put puts the connection back to the pool. If the pool is closed,
// the connection will be simply closed instead.
func (p *Pool) Put(conn *Conn) (err error) {
p.connsChanMu.RLock()
@@ -101,7 +101,7 @@ func (p *Pool) Put(conn *Conn) (err error) {
}
}
-// Close closes the Pool. After that it cannot be used anymore, every method
+// Close closes the Pool. After that it cannot be used anymore, every method
// will return ErrClosed.
func (p *Pool) Close() (err error) {
p.connsChanMu.Lock()
@@ -126,7 +126,7 @@ func (p *Pool) Close() (err error) {
return errors.Annotate(errors.Join(errs...), "closing pool: %w")
}
-// closeConn is used when the pool is closed. In this case we attempt to close
+// closeConn is used when the pool is closed. In this case we attempt to close
// the connection immediately.
func (p *Pool) closeConn(conn *Conn) (err error) {
err = conn.Close()
diff --git a/internal/dnsserver/prometheus/cache_test.go b/internal/dnsserver/prometheus/cache_test.go
index 49a5d6a..ead3ce3 100644
--- a/internal/dnsserver/prometheus/cache_test.go
+++ b/internal/dnsserver/prometheus/cache_test.go
@@ -29,7 +29,7 @@ func TestCacheMetricsListener_integration_cache(t *testing.T) {
// Pass 10 requests through the middleware. This way we'll increment and
// set both hits and misses.
- for i := 0; i < 10; i++ {
+ for range 10 {
ctx := dnsserver.ContextWithServerInfo(context.Background(), testServerInfo)
ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{
StartTime: time.Now(),
diff --git a/internal/dnsserver/prometheus/initsyncmap_internal_test.go b/internal/dnsserver/prometheus/initsyncmap_internal_test.go
index c64f0c9..c5c17c4 100644
--- a/internal/dnsserver/prometheus/initsyncmap_internal_test.go
+++ b/internal/dnsserver/prometheus/initsyncmap_internal_test.go
@@ -11,7 +11,7 @@ import (
func TestInitSyncMap(t *testing.T) {
numCalls := atomic.Uint32{}
- m := newInitSyncMap[int, int](func(k int) (v int) {
+ m := newInitSyncMap(func(k int) (v int) {
numCalls.Add(1)
return k + 1
@@ -26,13 +26,13 @@ func TestInitSyncMap(t *testing.T) {
results := make(chan int, n)
- for i := 0; i < n; i++ {
+ for range n {
go func() {
results <- m.get(key)
}()
}
- for i := 0; i < n; i++ {
+ for range n {
got, _ := testutil.RequireReceive(t, results, 1*time.Second)
assert.Equal(t, want, got)
}
diff --git a/internal/dnsserver/prometheus/ratelimit_test.go b/internal/dnsserver/prometheus/ratelimit_test.go
index bc9cdd0..5d0ef14 100644
--- a/internal/dnsserver/prometheus/ratelimit_test.go
+++ b/internal/dnsserver/prometheus/ratelimit_test.go
@@ -40,7 +40,7 @@ func TestRateLimiterMetricsListener_integration_cache(t *testing.T) {
)
// Pass 10 requests through the middleware.
- for i := 0; i < 10; i++ {
+ for i := range 10 {
ctx := dnsserver.ContextWithServerInfo(context.Background(), testServerInfo)
ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{
StartTime: time.Now(),
@@ -73,7 +73,7 @@ func BenchmarkRateLimitMetricsListener(b *testing.B) {
b.Run("OnAllowlisted", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
l.OnAllowlisted(ctx, req, rw)
}
})
@@ -81,7 +81,7 @@ func BenchmarkRateLimitMetricsListener(b *testing.B) {
b.Run("OnRateLimited", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
l.OnRateLimited(ctx, req, rw)
}
})
diff --git a/internal/dnsserver/prometheus/server_test.go b/internal/dnsserver/prometheus/server_test.go
index 72d4715..1428e8c 100644
--- a/internal/dnsserver/prometheus/server_test.go
+++ b/internal/dnsserver/prometheus/server_test.go
@@ -48,7 +48,7 @@ func TestServerMetricsListener_integration_requestLifetime(t *testing.T) {
addr := srv.LocalUDPAddr().String()
// Pass 10 requests to make the test less flaky.
- for i := 0; i < 10; i++ {
+ for range 10 {
res, _, exchErr := c.Exchange(req, addr)
require.NoError(t, exchErr)
require.NotNil(t, res)
@@ -96,7 +96,7 @@ func BenchmarkServerMetricsListener(b *testing.B) {
b.Run("OnRequest", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
l.OnRequest(ctx, info, rw)
}
})
@@ -104,7 +104,7 @@ func BenchmarkServerMetricsListener(b *testing.B) {
b.Run("OnInvalidMsg", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
l.OnInvalidMsg(ctx)
}
})
@@ -112,7 +112,7 @@ func BenchmarkServerMetricsListener(b *testing.B) {
b.Run("OnError", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
l.OnError(ctx, nil)
}
})
@@ -120,7 +120,7 @@ func BenchmarkServerMetricsListener(b *testing.B) {
b.Run("OnPanic", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
l.OnPanic(ctx, nil)
}
})
diff --git a/internal/dnsserver/protocol.go b/internal/dnsserver/protocol.go
index 183c338..71da69b 100644
--- a/internal/dnsserver/protocol.go
+++ b/internal/dnsserver/protocol.go
@@ -85,7 +85,7 @@ func (p Protocol) IsStdEncrypted() (ok bool) {
// Used for a kind of validation.
type Network string
-// Network enum members. Note that we use "tcp" and "udp" strings so that
+// Network enum members. Note that we use "tcp" and "udp" strings so that
// we could use these constants when calling golang net package functions.
const (
NetworkTCP Network = "tcp"
diff --git a/internal/dnsserver/ratelimit/backoff.go b/internal/dnsserver/ratelimit/backoff.go
index 8259fcb..4a16eb0 100644
--- a/internal/dnsserver/ratelimit/backoff.go
+++ b/internal/dnsserver/ratelimit/backoff.go
@@ -12,8 +12,6 @@ import (
cache "github.com/patrickmn/go-cache"
)
-// Backoff Rate Limiter
-
// BackoffConfig is the configuration structure for a backoff rate limiter.
type BackoffConfig struct {
// Allowlist defines which IP networks are excluded from rate limiting.
@@ -158,9 +156,8 @@ func validateAddr(addr netip.Addr) (err error) {
// CountResponses implements the Interface interface for *Backoff.
func (l *Backoff) CountResponses(ctx context.Context, resp *dns.Msg, ip netip.Addr) {
- respLimit := l.respSzEst
- respSize := resp.Len()
- for i := 0; i < respSize/respLimit; i++ {
+ estRespNum := resp.Len() / l.respSzEst
+ for range estRespNum {
_, _, _ = l.IsRateLimited(ctx, resp, ip)
}
}
diff --git a/internal/dnsserver/ratelimit/ratelimit_test.go b/internal/dnsserver/ratelimit/ratelimit_test.go
index 7552ed9..42f6e6b 100644
--- a/internal/dnsserver/ratelimit/ratelimit_test.go
+++ b/internal/dnsserver/ratelimit/ratelimit_test.go
@@ -124,7 +124,7 @@ func TestRatelimitMiddleware(t *testing.T) {
})
n := 0
- for i := 0; i < tc.reqsNum; i++ {
+ for range tc.reqsNum {
nrw := dnsserver.NewNonWriterResponseWriter(
&net.UDPAddr{IP: []byte{1, 2, 3, 4}},
tc.remoteAddr,
diff --git a/internal/dnsserver/serverbase.go b/internal/dnsserver/serverbase.go
index d3678ff..ea9891a 100644
--- a/internal/dnsserver/serverbase.go
+++ b/internal/dnsserver/serverbase.go
@@ -268,7 +268,7 @@ func (s *ServerBase) dispose(rw ResponseWriter, resp *dns.Msg) {
}
// serveDNSMsgInternal serves the DNS request and uses recorder as a
-// ResponseWriter. This method is supposed to be called from serveDNSMsg,
+// ResponseWriter. This method is supposed to be called from serveDNSMsg,
// the recorded response is used for counting metrics.
func (s *ServerBase) serveDNSMsgInternal(
ctx context.Context,
diff --git a/internal/dnsserver/serverbench_test.go b/internal/dnsserver/serverbench_test.go
index aefe091..c1c5bb1 100644
--- a/internal/dnsserver/serverbench_test.go
+++ b/internal/dnsserver/serverbench_test.go
@@ -61,14 +61,13 @@ func BenchmarkServeDNS(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
_, err = conn.Write(msg)
require.NoError(b, err)
err = readMsg(resBuf, tc.network, conn)
require.NoError(b, err)
}
- b.StopTimer()
})
}
}
@@ -130,7 +129,7 @@ func BenchmarkServeTLS(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
_, err = conn.Write(msg)
require.NoError(b, err)
@@ -147,7 +146,6 @@ func BenchmarkServeTLS(b *testing.B) {
require.GreaterOrEqual(b, n, dnsserver.DNSHeaderSize)
}
- b.StopTimer()
}
func BenchmarkServeDoH(b *testing.B) {
@@ -207,7 +205,7 @@ func BenchmarkServeDoH(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
var res *http.Response
res, err = client.Do(req)
require.NoError(b, err)
@@ -271,13 +269,12 @@ func BenchmarkServeDNSCrypt(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
var resp *dns.Msg
resp, err = client.ExchangeConn(conn, req, ri)
require.NoError(b, err)
require.True(b, resp.Response)
}
- b.StopTimer()
})
}
}
@@ -312,10 +309,9 @@ func BenchmarkServeQUIC(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
resp := requireSendQUICMessage(b, sess, req)
require.NotNil(b, resp)
require.True(b, resp.Response)
}
- b.StopTimer()
}
diff --git a/internal/dnsserver/serverdns.go b/internal/dnsserver/serverdns.go
index 066e054..d6ce00a 100644
--- a/internal/dnsserver/serverdns.go
+++ b/internal/dnsserver/serverdns.go
@@ -1,6 +1,7 @@
package dnsserver
import (
+ "cmp"
"context"
"net"
"sync"
@@ -108,26 +109,14 @@ func NewServerDNS(conf ConfigDNS) (s *ServerDNS) {
// server with a TLS layer on top of it.
func newServerDNS(proto Protocol, conf ConfigDNS) (s *ServerDNS) {
// Init default settings first.
- //
- // TODO(a.garipov): Use cmp.Or in Go 1.22.
- if conf.ReadTimeout == 0 {
- conf.ReadTimeout = DefaultReadTimeout
- }
- if conf.WriteTimeout == 0 {
- conf.WriteTimeout = DefaultWriteTimeout
- }
- if conf.TCPIdleTimeout == 0 {
- conf.TCPIdleTimeout = DefaultTCPIdleTimeout
- }
+ conf.ReadTimeout = cmp.Or(conf.ReadTimeout, DefaultReadTimeout)
+ conf.WriteTimeout = cmp.Or(conf.WriteTimeout, DefaultWriteTimeout)
+ conf.TCPIdleTimeout = cmp.Or(conf.TCPIdleTimeout, DefaultTCPIdleTimeout)
- // Use dns.MinMsgSize since 99% of DNS queries fit this size, so this is
- // a sensible default.
- if conf.UDPSize == 0 {
- conf.UDPSize = dns.MinMsgSize
- }
- if conf.TCPSize == 0 {
- conf.TCPSize = dns.MinMsgSize
- }
+ // Use dns.MinMsgSize since 99% of DNS queries fit this size, so this is a
+ // sensible default.
+ conf.UDPSize = cmp.Or(conf.UDPSize, dns.MinMsgSize)
+ conf.TCPSize = cmp.Or(conf.TCPSize, dns.MinMsgSize)
if conf.ListenConfig == nil {
conf.ListenConfig = netext.DefaultListenConfigWithOOB(nil)
diff --git a/internal/dnsserver/serverdns_test.go b/internal/dnsserver/serverdns_test.go
index fd4cd76..2fea08d 100644
--- a/internal/dnsserver/serverdns_test.go
+++ b/internal/dnsserver/serverdns_test.go
@@ -315,7 +315,7 @@ func TestServerDNS_integration_tcpQueriesPipelining(t *testing.T) {
const queriesNum = 100
sentIDs := make(map[uint16]string, queriesNum)
- for i := 0; i < queriesNum; i++ {
+ for i := range queriesNum {
name := fmt.Sprintf("host%d.org", i)
req := dnsservertest.CreateMessage(name, dns.TypeA)
req.Id = uint16(i + 1)
@@ -341,7 +341,7 @@ func TestServerDNS_integration_tcpQueriesPipelining(t *testing.T) {
// Read the responses and check their IDs.
receivedIDs := make(map[uint16]string, queriesNum)
- for i := 0; i < queriesNum; i++ {
+ for range queriesNum {
err = conn.SetReadDeadline(time.Now().Add(time.Second))
require.NoError(t, err)
@@ -466,7 +466,6 @@ func TestServerDNS_integration_tcpMsgIgnore(t *testing.T) {
}
for _, tc := range testCases {
- tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
diff --git a/internal/dnsserver/serverdnsudp.go b/internal/dnsserver/serverdnsudp.go
index a44ff34..e334e91 100644
--- a/internal/dnsserver/serverdnsudp.go
+++ b/internal/dnsserver/serverdnsudp.go
@@ -51,12 +51,22 @@ func (s *ServerDNS) acceptUDPMsg(ctx context.Context, conn net.PacketConn) (err
s.wg.Add(1)
- reqCtx, reqCancel := s.requestContext()
- reqCtx = ContextWithRequestInfo(reqCtx, &RequestInfo{StartTime: time.Now()})
+ // Save the start time here, but create the context inside the goroutine,
+ // since s.reqCtx.New can be slow.
+ //
+ // TODO(a.garipov): The slowness is likely due to constant reallocation of
+ // timers in [context.WithTimeout]. Consider creating an optimized reusable
+ // version.
+ startTime := time.Now()
return s.workerPool.Submit(func() {
+ reqCtx, reqCancel := s.requestContext()
defer reqCancel()
+ reqCtx = ContextWithRequestInfo(reqCtx, &RequestInfo{
+ StartTime: startTime,
+ })
+
s.serveUDPPacket(reqCtx, (*bufPtr)[:n], conn, sess)
s.udpPool.Put(bufPtr)
})
diff --git a/internal/dnsserver/serverhttps.go b/internal/dnsserver/serverhttps.go
index 8ee3ddf..a65f954 100644
--- a/internal/dnsserver/serverhttps.go
+++ b/internal/dnsserver/serverhttps.go
@@ -77,7 +77,7 @@ type ConfigHTTPS struct {
QUICLimitsEnabled bool
}
-// ServerHTTPS is a DoH server implementation. It supports both DNS Wireformat
+// ServerHTTPS is a DoH server implementation. It supports both DNS Wireformat
// and DNS JSON format. Regular DoH (wireformat) will be available at the
// /dns-query location. JSON format will be available at the "/resolve"
// location.
@@ -95,6 +95,9 @@ type ServerHTTPS struct {
// quicListener is a listener that we use to serve DoH3 requests.
quicListener *quic.EarlyListener
+ // quicTransport is saved here to close it later.
+ quicTransport *quic.Transport
+
conf ConfigHTTPS
}
@@ -264,21 +267,33 @@ func (s *ServerHTTPS) shutdown(ctx context.Context) (err error) {
}
// Finally, shutdown the HTTP/3 server.
- if s.h3Server != nil {
- err = s.quicListener.Close()
- if err != nil {
- log.Debug("[%s]: quic listener shutdown: %v", s.Name(), err)
- }
-
- err = s.h3Server.Close()
- if err != nil {
- log.Debug("[%s]: http/3 server shutdown: %v", s.Name(), err)
- }
- }
+ s.shutdownH3()
return nil
}
+// shutdownH3 shuts down the HTTP/3 server, if enabled, and logs all errors.
+func (s *ServerHTTPS) shutdownH3() {
+ if s.h3Server == nil {
+ return
+ }
+
+ err := s.quicListener.Close()
+ if err != nil {
+ log.Debug("[%s]: quic listener shutdown: %s", s.Name(), err)
+ }
+
+ err = s.quicTransport.Close()
+ if err != nil {
+ log.Debug("[%s]: quic transport shutdown: %s", s.Name(), err)
+ }
+
+ err = s.h3Server.Close()
+ if err != nil {
+ log.Debug("[%s]: http/3 server shutdown: %s", s.Name(), err)
+ }
+}
+
// serveHTTPS is launched in a worker goroutine and serves HTTP/1.1 and HTTP/2
// requests.
func (s *ServerHTTPS) serveHTTPS(ctx context.Context, hs *http.Server, l net.Listener) {
@@ -523,16 +538,23 @@ func (s *ServerHTTPS) listenQUIC(ctx context.Context) (err error) {
conn, err := s.listenConfig.ListenPacket(ctx, "udp", s.addr)
if err != nil {
- return err
+ return fmt.Errorf("listening udp for quic: %w", err)
}
- qConf := newServerQUICConfig(s.metrics, s.conf.QUICLimitsEnabled, s.conf.MaxStreamsPerPeer)
- ql, err := quic.ListenEarly(conn, tlsConf, qConf)
+ v := newQUICAddrValidator(quicAddrValidatorCacheSize, s.metrics, quicAddrValidatorCacheTTL)
+ transport := &quic.Transport{
+ Conn: conn,
+ VerifySourceAddress: v.requiresValidation,
+ }
+
+ qConf := newServerQUICConfig(s.conf.QUICLimitsEnabled, s.conf.MaxStreamsPerPeer)
+ ql, err := transport.ListenEarly(tlsConf, qConf)
if err != nil {
- return err
+ return fmt.Errorf("listening quic: %w", err)
}
s.udpListener = conn
+ s.quicTransport = transport
s.quicListener = ql
return nil
diff --git a/internal/dnsserver/serverhttps_test.go b/internal/dnsserver/serverhttps_test.go
index f664420..96b46ce 100644
--- a/internal/dnsserver/serverhttps_test.go
+++ b/internal/dnsserver/serverhttps_test.go
@@ -104,7 +104,6 @@ func TestServerHTTPS_integration_serveRequests(t *testing.T) {
}}
for _, tc := range testCases {
- tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
diff --git a/internal/dnsserver/serverhttpsjson.go b/internal/dnsserver/serverhttpsjson.go
index 4752084..19a3db5 100644
--- a/internal/dnsserver/serverhttpsjson.go
+++ b/internal/dnsserver/serverhttpsjson.go
@@ -12,7 +12,7 @@ import (
// JSONMsg represents a *dns.Msg in the JSON format defined here:
// https://developers.google.com/speed/public-dns/docs/doh/json#dns_response_in_json
-// Note, that we do not implement some parts of it. There is no "Comment" field
+// Note, that we do not implement some parts of it. There is no "Comment" field
// and there's no "edns_client_subnet".
type JSONMsg struct {
Question []JSONQuestion `json:"Question"`
@@ -169,7 +169,7 @@ func httpRequestToMsgJSON(req *http.Request) (b []byte, err error) {
}
// urlQueryParameterToUint16 is a helper function that extracts a uint16 value
-// from a query parameter. See httpRequestToMsgJSON to see how it's used.
+// from a query parameter. See httpRequestToMsgJSON to see how it's used.
func urlQueryParameterToUint16(
q url.Values,
name string,
@@ -199,7 +199,7 @@ func urlQueryParameterToUint16(
}
// urlQueryParameterToBoolean is a helper function that extracts a boolean value
-// from a query parameter. See httpRequestToMsgJSON to see how it's used.
+// from a query parameter. See httpRequestToMsgJSON to see how it's used.
func urlQueryParameterToBoolean(
q url.Values,
name string,
diff --git a/internal/dnsserver/serverquic.go b/internal/dnsserver/serverquic.go
index 2af9816..058b7ec 100644
--- a/internal/dnsserver/serverquic.go
+++ b/internal/dnsserver/serverquic.go
@@ -99,6 +99,9 @@ type ServerQUIC struct {
// quicListener is a listener that we use to accept DoQ connections.
quicListener *quic.Listener
+ // transport is the QUIC transport saved here to close it later.
+ transport *quic.Transport
+
// TODO(a.garipov): Remove this and only save the values a server actually
// uses.
conf ConfigQUIC
@@ -208,11 +211,16 @@ func (s *ServerQUIC) shutdown() (err error) {
// First, mark it as stopped
s.started = false
- // Now close all listeners
+ // Now close all listeners.
err = s.quicListener.Close()
if err != nil {
- // Log this error but do not return it
- log.Debug("[%s]: Failed to close QUIC listener: %v", s.Name(), err)
+ log.Debug("[%s]: closing quic listener: %s", s.Name(), err)
+ }
+
+ // And the transport.
+ err = s.transport.Close()
+ if err != nil {
+ log.Debug("[%s]: closing quic transport: %s", s.Name(), err)
}
return nil
@@ -317,7 +325,7 @@ func (s *ServerQUIC) serveQUICConnAsync(
}
}
-// serveQUICConn handles a new QUIC connection. It waits for new streams and
+// 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) {
streamWg := &sync.WaitGroup{}
@@ -387,7 +395,7 @@ func (s *ServerQUIC) serveQUICConn(ctx context.Context, conn quic.Connection) (e
}
// serveQUICStreamAsync wraps serveQUICStream call and handles all possible
-// errors that might happen there. It also makes sure that the WaitGroup will
+// errors that might happen there. It also makes sure that the WaitGroup will
// be decremented.
func (s *ServerQUIC) serveQUICStreamAsync(
ctx context.Context,
@@ -552,21 +560,25 @@ func readAll(r io.Reader, buf []byte) (n int, err error) {
func (s *ServerQUIC) listenQUIC(ctx context.Context) (err error) {
conn, err := s.listenConfig.ListenPacket(ctx, "udp", s.addr)
if err != nil {
- return err
+ return fmt.Errorf("listening udp for quic: %w", err)
}
- qConf := newServerQUICConfig(s.metrics, s.conf.QUICLimitsEnabled, s.conf.MaxStreamsPerPeer)
+ v := newQUICAddrValidator(quicAddrValidatorCacheSize, s.metrics, quicAddrValidatorCacheTTL)
+ transport := &quic.Transport{
+ Conn: conn,
+ VerifySourceAddress: v.requiresValidation,
+ }
- // Do not change to quic.ListenEarly, see quicNotEarlyListener to know why.
- ql, err := quic.Listen(conn, s.conf.TLSConfig, qConf)
+ qConf := newServerQUICConfig(s.conf.QUICLimitsEnabled, s.conf.MaxStreamsPerPeer)
+ ql, err := transport.Listen(s.conf.TLSConfig, qConf)
if err != nil {
- return err
+ return fmt.Errorf("listening quic: %w", err)
}
// Save this for s.LocalUDPAddr. Do not close it separately as ql closes
// the underlying connection.
s.udpListener = conn
-
+ s.transport = transport
s.quicListener = ql
return nil
@@ -681,12 +693,9 @@ func closeQUICConn(conn quic.Connection, code quic.ApplicationErrorCode) {
// newServerQUICConfig creates *quic.Config populated with the default settings.
// This function is supposed to be used for both DoQ and DoH3 server.
func newServerQUICConfig(
- metrics MetricsListener,
quicLimitsEnabled bool,
maxStreamsPerPeer int,
) (conf *quic.Config) {
- v := newQUICAddrValidator(quicAddrValidatorCacheSize, metrics, quicAddrValidatorCacheTTL)
-
maxIncStreams := quicDefaultMaxStreamsPerPeer
maxIncUniStreams := quicDefaultMaxStreamsPerPeer
if quicLimitsEnabled {
@@ -695,10 +704,9 @@ func newServerQUICConfig(
}
return &quic.Config{
- MaxIdleTimeout: maxQUICIdleTimeout,
- MaxIncomingStreams: int64(maxIncStreams),
- MaxIncomingUniStreams: int64(maxIncUniStreams),
- RequireAddressValidation: v.requiresValidation,
+ MaxIdleTimeout: maxQUICIdleTimeout,
+ MaxIncomingStreams: int64(maxIncStreams),
+ MaxIncomingUniStreams: int64(maxIncUniStreams),
// Enable 0-RTT by default for all addresses, it's beneficial for the
// performance.
Allow0RTT: true,
@@ -727,7 +735,7 @@ func newQUICAddrValidator(
}
// requiresValidation determines if a QUIC Retry packet should be sent by the
-// client. This allows the server to verify the client's address but increases
+// client. This allows the server to verify the client's address but increases
// the latency.
//
// TODO(ameshkov): consider caddy-like implementation here.
diff --git a/internal/dnsserver/serverquic_test.go b/internal/dnsserver/serverquic_test.go
index 834e790..b2e08bc 100644
--- a/internal/dnsserver/serverquic_test.go
+++ b/internal/dnsserver/serverquic_test.go
@@ -31,7 +31,7 @@ func TestServerQUIC_integration_query(t *testing.T) {
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(contextWithTimeout(t, testTimeout))
+ return srv.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
})
// Open a QUIC connection.
@@ -47,7 +47,7 @@ func TestServerQUIC_integration_query(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(queriesNum)
- for i := 0; i < queriesNum; i++ {
+ for range queriesNum {
req := dnsservertest.NewReq("example.org.", dns.TypeA, dns.ClassINET)
req.RecursionDesired = true
@@ -80,7 +80,7 @@ func TestServerQUIC_integration_ENDS0Padding(t *testing.T) {
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(contextWithTimeout(t, testTimeout))
+ return srv.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
})
// Open a QUIC connection.
@@ -114,7 +114,7 @@ func TestServerQUIC_integration_0RTT(t *testing.T) {
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(contextWithTimeout(t, testTimeout))
+ return srv.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
})
quicTracer := dnsservertest.NewQUICTracer()
@@ -152,7 +152,7 @@ func TestServerQUIC_integration_largeQuery(t *testing.T) {
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(contextWithTimeout(t, testTimeout))
+ return srv.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
})
// Open a QUIC connection.
diff --git a/internal/dnsserver/servertls_test.go b/internal/dnsserver/servertls_test.go
index a97688d..1c1d1f5 100644
--- a/internal/dnsserver/servertls_test.go
+++ b/internal/dnsserver/servertls_test.go
@@ -90,7 +90,6 @@ func TestServerTLS_integration_msgIgnore(t *testing.T) {
}
for _, tc := range testCases {
- tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
@@ -168,7 +167,7 @@ func TestServerTLS_integration_queriesPipelining(t *testing.T) {
// those queries IDs
count := 100
ids := map[uint16]bool{}
- for i := 0; i < count; i++ {
+ for i := range count {
req := new(dns.Msg)
req.Id = uint16(i)
req.RecursionDesired = true
@@ -191,7 +190,7 @@ func TestServerTLS_integration_queriesPipelining(t *testing.T) {
}
// Now read the responses and check their IDs
- for i := 0; i < count; i++ {
+ for range count {
_ = conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
l := make([]byte, 2)
_, err = conn.Read(l)
diff --git a/internal/dnsserver/ttl.go b/internal/dnsserver/ttl.go
index 96ed6b3..cefb4c9 100644
--- a/internal/dnsserver/ttl.go
+++ b/internal/dnsserver/ttl.go
@@ -29,7 +29,7 @@ func minimalTTL(m *dns.Msg) (d time.Duration) {
}
// isEmptyRequest returns true if the message has no records at all
-// or if it has just an OPT record. We consider it an "empty" message
+// or if it has just an OPT record. We consider it an "empty" message
// in this case.
func isEmptyMessage(m *dns.Msg) (empty bool) {
return len(m.Answer) == 0 && len(m.Ns) == 0 &&
diff --git a/internal/dnssvc/dnssvc.go b/internal/dnssvc/dnssvc.go
index 427988c..53178ed 100644
--- a/internal/dnssvc/dnssvc.go
+++ b/internal/dnssvc/dnssvc.go
@@ -22,6 +22,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/prometheus"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/accessmw"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicesetter"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/initial"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/mainmw"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/preservice"
@@ -147,17 +148,6 @@ type Config struct {
// ProfileDBEnabled is true, if user devices and profiles recognition is
// enabled.
ProfileDBEnabled bool
-
- // ResearchMetrics controls whether research metrics are enabled or not.
- // This is a set of metrics that we may need temporary, so its collection is
- // controlled by a separate setting.
- ResearchMetrics bool
-
- // ResearchLogs controls whether logging of additional info for research
- // purposes is enabled. These logs may be overly verbose and are only
- // required temporary, that's why it's controlled by a separate setting.
- // This setting will only be used when ResearchMetrics is also set to true.
- ResearchLogs bool
}
// New returns a new DNS service.
@@ -208,16 +198,14 @@ func New(c *Config) (svc *Service, err error) {
Checker: c.DNSCheck,
}),
mainmw.New(&mainmw.Config{
- Messages: c.Messages,
- Cloner: c.Cloner,
- BillStat: c.BillStat,
- ErrColl: c.ErrColl,
- FilterStorage: c.FilterStorage,
- GeoIP: c.GeoIP,
- QueryLog: c.QueryLog,
- RuleStat: c.RuleStat,
- ResearchMetrics: c.ResearchMetrics,
- ResearchLogs: c.ResearchLogs,
+ Messages: c.Messages,
+ Cloner: c.Cloner,
+ BillStat: c.BillStat,
+ ErrColl: c.ErrColl,
+ FilterStorage: c.FilterStorage,
+ GeoIP: c.GeoIP,
+ QueryLog: c.QueryLog,
+ RuleStat: c.RuleStat,
}),
)
@@ -426,8 +414,8 @@ func NewListener(
})
case agd.ProtoDoQ:
l = dnsserver.NewServerQUIC(dnsserver.ConfigQUIC{
- ConfigBase: baseConf,
TLSConfig: s.TLS,
+ ConfigBase: baseConf,
MaxStreamsPerPeer: quicConf.MaxStreamsPerPeer,
QUICLimitsEnabled: quicConf.QUICLimitsEnabled,
})
@@ -516,14 +504,13 @@ func newServers(
})
imw := initial.New(&initial.Config{
- Messages: c.Messages,
- FilteringGroup: fg,
- ServerGroup: srvGrp,
- Server: s,
- ProfileDB: c.ProfileDB,
- GeoIP: c.GeoIP,
- ErrColl: c.ErrColl,
- ProfileDBEnabled: c.ProfileDBEnabled,
+ Messages: c.Messages,
+ FilteringGroup: fg,
+ ServerGroup: srvGrp,
+ Server: s,
+ DeviceSetter: newDeviceSetter(c, srvGrp, s),
+ GeoIP: c.GeoIP,
+ ErrColl: c.ErrColl,
})
h := dnsserver.WithMiddlewares(
@@ -553,6 +540,20 @@ func newServers(
return servers, nil
}
+// newDeviceSetter returns a new [devicesetter.Interface] for a server based on
+// the configuration.
+func newDeviceSetter(c *Config, g *agd.ServerGroup, s *agd.Server) (ds devicesetter.Interface) {
+ if !c.ProfileDBEnabled {
+ return devicesetter.Empty{}
+ }
+
+ return devicesetter.NewDefault(&devicesetter.Config{
+ ProfileDB: c.ProfileDB,
+ Server: s,
+ DeviceIDWildcards: g.TLS.DeviceIDWildcards,
+ })
+}
+
// newServers creates a slice of listeners for a server.
func newListeners(
c *Config,
diff --git a/internal/dnssvc/dnssvc_test.go b/internal/dnssvc/dnssvc_test.go
index 4e651f3..f9e3412 100644
--- a/internal/dnssvc/dnssvc_test.go
+++ b/internal/dnssvc/dnssvc_test.go
@@ -10,7 +10,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/forward"
@@ -174,13 +173,13 @@ func TestService_Start(t *testing.T) {
require.NoError(t, err)
require.NotPanics(t, func() {
- err = svc.Start(agdtest.ContextWithTimeout(t, dnssvctest.Timeout))
+ err = svc.Start(testutil.ContextWithTimeout(t, dnssvctest.Timeout))
assert.NoError(t, err)
assert.Equal(t, uint64(1), numStart.Load())
})
require.NotPanics(t, func() {
- err = svc.Shutdown(agdtest.ContextWithTimeout(t, dnssvctest.Timeout))
+ err = svc.Shutdown(testutil.ContextWithTimeout(t, dnssvctest.Timeout))
assert.NoError(t, err)
assert.Equal(t, uint64(1), numShutdown.Load())
})
diff --git a/internal/dnssvc/integration_test.go b/internal/dnssvc/integration_test.go
index 0254c8b..2d701ec 100644
--- a/internal/dnssvc/integration_test.go
+++ b/internal/dnssvc/integration_test.go
@@ -5,12 +5,12 @@ import (
"net"
"net/http"
"net/netip"
- "strings"
"testing"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
@@ -60,6 +60,10 @@ func newTestService(
pt := testutil.PanicT{}
dev := &agd.Device{
+ Auth: &agd.AuthSettings{
+ Enabled: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ },
ID: dnssvctest.DeviceID,
FilteringEnabled: true,
}
@@ -228,7 +232,6 @@ func newTestService(
},
},
ServerGroups: []*agd.ServerGroup{{
- BlockPageRedirect: &agd.BlockPageRedirect{},
DDR: &agd.DDR{
Enabled: true,
},
@@ -246,10 +249,10 @@ func newTestService(
require.NoError(t, err)
require.NotNil(t, svc)
- err = svc.Start(agdtest.ContextWithTimeout(t, dnssvctest.Timeout))
+ err = svc.Start(testutil.ContextWithTimeout(t, dnssvctest.Timeout))
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return svc.Shutdown(agdtest.ContextWithTimeout(t, dnssvctest.Timeout))
+ return svc.Shutdown(testutil.ContextWithTimeout(t, dnssvctest.Timeout))
})
return svc, srvAddr
@@ -274,12 +277,6 @@ func TestService_Wrap(t *testing.T) {
clientAddr := &net.TCPAddr{IP: net.IP{1, 2, 3, 4}, Port: 12345}
- tlsServerName := strings.ReplaceAll(
- dnssvctest.DeviceIDWildcard,
- "*",
- string(dnssvctest.DeviceID),
- )
-
ctx := context.Background()
ctx = dnsserver.ContextWithServerInfo(ctx, &dnsserver.ServerInfo{
Proto: agd.ProtoDoT,
@@ -321,7 +318,7 @@ func TestService_Wrap(t *testing.T) {
ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{
StartTime: time.Now(),
- TLSServerName: tlsServerName,
+ TLSServerName: dnssvctest.DeviceIDSrvName,
})
err := svc.Handle(ctx, testSrvGrpName, dnssvctest.ServerName, rw, req)
@@ -362,7 +359,7 @@ func TestService_Wrap(t *testing.T) {
mod := dnsmsg.Clone(m)
mod.Question[0].Name = cnameFQDN
- return &filter.ResultModified{
+ return &filter.ResultModifiedRequest{
Msg: mod,
List: dnssvctest.FilterListID1,
Rule: cnameRule,
@@ -395,7 +392,7 @@ func TestService_Wrap(t *testing.T) {
ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{
StartTime: time.Now(),
- TLSServerName: tlsServerName,
+ TLSServerName: dnssvctest.DeviceIDSrvName,
})
err := svc.Handle(ctx, testSrvGrpName, dnssvctest.ServerName, rw, req)
diff --git a/internal/dnssvc/internal/devicesetter/device.go b/internal/dnssvc/internal/devicesetter/device.go
new file mode 100644
index 0000000..49d369e
--- /dev/null
+++ b/internal/dnssvc/internal/devicesetter/device.go
@@ -0,0 +1,187 @@
+package devicesetter
+
+import (
+ "context"
+ "net/netip"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
+ "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
+ "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
+ "github.com/AdguardTeam/golibs/errors"
+)
+
+// findDevice returns a valid, non-deleted profile and device or nils. err is
+// only not nil when it's not [profiledb.ErrDeviceNotFound].
+func (ds *Default) findDevice(
+ ctx context.Context,
+ laddr netip.AddrPort,
+ remoteIP netip.Addr,
+ id agd.DeviceID,
+) (prof *agd.Profile, dev *agd.Device, err error) {
+ // TODO(a.garipov): Add package optslog for optimized slog logging?
+ optlog.Debug3("devicesetter: got dev id %q, raddr %s, and laddr %s", id, remoteIP, laddr)
+
+ prof, dev, byWhat, err := ds.deviceFromDB(ctx, laddr, remoteIP, id)
+ if err != nil {
+ if !errors.Is(err, profiledb.ErrDeviceNotFound) {
+ // Don't wrap the error, because it's likely [errUnknownDedicated].
+ return nil, nil, err
+ }
+
+ optlog.Debug1("devicesetter: profile or device not found: %s", err)
+
+ return nil, nil, nil
+ }
+
+ if prof.Deleted {
+ optlog.Debug1("devicesetter: profile %s is deleted", prof.ID)
+
+ return nil, nil, nil
+ }
+
+ optlog.Debug3("devicesetter: found profile %s and device %s by %s", prof.ID, dev.ID, byWhat)
+
+ return prof, dev, nil
+}
+
+// Constants for the parameter by which a device has been found.
+const (
+ byDeviceID = "device id"
+ byDedicatedIP = "dedicated ip"
+ byLinkedIP = "linked ip"
+)
+
+// deviceFromDB queries the profile DB for the profile and device by the client
+// data. It also returns the description of how it has found them.
+func (ds *Default) deviceFromDB(
+ ctx context.Context,
+ laddr netip.AddrPort,
+ remoteIP netip.Addr,
+ id agd.DeviceID,
+) (prof *agd.Profile, dev *agd.Device, byWhat string, err error) {
+ if id != "" {
+ prof, dev, err = ds.db.ProfileByDeviceID(ctx, id)
+ if err != nil {
+ return nil, nil, "", err
+ }
+
+ return prof, dev, byDeviceID, nil
+ }
+
+ if ds.srv.Protocol == agd.ProtoDNS {
+ return ds.deviceByAddrs(ctx, laddr, remoteIP)
+ }
+
+ return nil, nil, "", profiledb.ErrDeviceNotFound
+}
+
+// deviceByAddrs finds the profile and the device by the remote and local
+// addresses depending on the data and the server settings.
+func (ds *Default) deviceByAddrs(
+ ctx context.Context,
+ laddr netip.AddrPort,
+ remoteIP netip.Addr,
+) (prof *agd.Profile, dev *agd.Device, byWhat string, err error) {
+ if ds.srv.BindsToInterfaces() && !ds.srv.HasAddr(laddr) {
+ prof, dev, err = ds.deviceByLocalAddr(ctx, laddr.Addr())
+ if err != nil {
+ return nil, nil, "", err
+ }
+
+ return prof, dev, byDedicatedIP, nil
+ }
+
+ if !ds.srv.LinkedIPEnabled {
+ return nil, nil, "", profiledb.ErrDeviceNotFound
+ }
+
+ prof, dev, err = ds.db.ProfileByLinkedIP(ctx, remoteIP)
+ if err != nil {
+ return nil, nil, "", err
+ }
+
+ return prof, dev, byLinkedIP, nil
+}
+
+// deviceByLocalAddr finds the profile and the device by the local address.
+func (ds *Default) deviceByLocalAddr(
+ ctx context.Context,
+ localIP netip.Addr,
+) (prof *agd.Profile, dev *agd.Device, err error) {
+ prof, dev, err = ds.db.ProfileByDedicatedIP(ctx, localIP)
+ if err != nil {
+ if errors.Is(err, profiledb.ErrDeviceNotFound) {
+ optlog.Debug1("devicesetter: unknown dedicated ip for server %s; dropping", ds.srv.Name)
+
+ err = ErrUnknownDedicated
+ }
+
+ return nil, nil, err
+ }
+
+ return prof, dev, nil
+}
+
+// setDevice authenticates the device, if necessary, and sets profile and
+// device data in ri using the information from the arguments. It also logs its
+// decisions. All arguments must not be nil.
+func (ds *Default) setDevice(
+ ctx context.Context,
+ ri *agd.RequestInfo,
+ srvReqInfo *dnsserver.RequestInfo,
+ prof *agd.Profile,
+ dev *agd.Device,
+) {
+ if !ds.authDevice(ctx, srvReqInfo, dev) {
+ metrics.DNSSvcDoHAuthFailsTotal.Inc()
+
+ optlog.Debug1("devicesetter: device %s: authentication failed", dev.ID)
+
+ return
+ }
+
+ ri.Profile = prof
+ ri.Device = dev
+
+ // TODO(a.garipov): Consider using the global cloner here once it is tested
+ // and optimized.
+ ri.Messages = dnsmsg.NewConstructor(nil, prof.BlockingMode, prof.FilteredResponseTTL)
+}
+
+// authDevice returns true if ctx passes device authentication configuration.
+// all arguments must not be nil.
+func (ds *Default) authDevice(
+ ctx context.Context,
+ srvReqInfo *dnsserver.RequestInfo,
+ dev *agd.Device,
+) (ok bool) {
+ conf := dev.Auth
+ if !conf.Enabled {
+ return true
+ }
+
+ if ds.srv.Protocol != agd.ProtoDoH {
+ // Pass non-DoH-only devices regardless of the userinfo and block
+ // DoH-only devices in case of non-DoH protocol.
+ return !conf.DoHAuthOnly
+ }
+
+ userinfo := srvReqInfo.Userinfo
+ if userinfo == nil {
+ // Require presence of userinfo if DoHAuthOnly is enabled. Otherwise,
+ // pass.
+ return !conf.DoHAuthOnly
+ }
+
+ // NOTE: It is currently assumed that if the execution got here, the device
+ // ID and thus the device were found using the userinfo.
+ password, set := userinfo.Password()
+ if !set {
+ return false
+ }
+
+ return conf.PasswordHash.Authenticate(ctx, []byte(password))
+}
diff --git a/internal/dnssvc/internal/devicesetter/device_test.go b/internal/dnssvc/internal/devicesetter/device_test.go
new file mode 100644
index 0000000..10ce7ca
--- /dev/null
+++ b/internal/dnssvc/internal/devicesetter/device_test.go
@@ -0,0 +1,251 @@
+package devicesetter_test
+
+import (
+ "context"
+ "net/netip"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicesetter"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/miekg/dns"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestDefault_SetDevice_plainAddrs(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ req *dns.Msg
+ srv *agd.Server
+ wantProf *agd.Profile
+ wantDev *agd.Device
+ wantErrMsg string
+ laddr netip.AddrPort
+ raddr netip.AddrPort
+ name string
+ }{{
+ req: reqNormal,
+ srv: srvPlainWithLinkedIP,
+ wantProf: nil,
+ wantDev: nil,
+ wantErrMsg: "",
+ laddr: dnssvctest.ServerAddrPort,
+ raddr: dnssvctest.ClientAddrPort,
+ name: "no_match",
+ }, {
+ req: reqNormal,
+ srv: srvPlainWithLinkedIP,
+ wantProf: profNormal,
+ wantDev: devNormal,
+ wantErrMsg: "",
+ laddr: dnssvctest.ServerAddrPort,
+ raddr: linkedAddrPort,
+ name: "linked_ip",
+ }, {
+ req: reqNormal,
+ srv: srvPlain,
+ wantProf: nil,
+ wantDev: nil,
+ wantErrMsg: "",
+ laddr: dnssvctest.ServerAddrPort,
+ raddr: linkedAddrPort,
+ name: "linked_ip_not_supported",
+ }, {
+ req: reqNormal,
+ srv: srvPlainWithBindData,
+ wantProf: profNormal,
+ wantDev: devNormal,
+ wantErrMsg: "",
+ laddr: dedicatedAddrPort,
+ raddr: dnssvctest.ClientAddrPort,
+ name: "dedicated",
+ }, {
+ req: reqNormal,
+ srv: srvPlainWithBindData,
+ wantProf: nil,
+ wantDev: nil,
+ wantErrMsg: "setting profile: unknown dedicated ip",
+ laddr: dnssvctest.ServerAddrPort,
+ raddr: dnssvctest.ClientAddrPort,
+ name: "dedicated_not_found",
+ }, {
+ req: reqNormal,
+ srv: srvPlain,
+ wantProf: nil,
+ wantDev: nil,
+ wantErrMsg: "",
+ laddr: dedicatedAddrPort,
+ raddr: dnssvctest.ClientAddrPort,
+ name: "dedicated_not_supported",
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ profDB := &agdtest.ProfileDB{
+ OnProfileByDedicatedIP: newOnProfileByDedicatedIP(dedicatedAddr),
+ OnProfileByDeviceID: func(
+ _ context.Context,
+ _ agd.DeviceID,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ OnProfileByLinkedIP: newOnProfileByLinkedIP(linkedAddr),
+ }
+
+ pf := devicesetter.NewDefault(&devicesetter.Config{
+ ProfileDB: profDB,
+ Server: tc.srv,
+ DeviceIDWildcards: nil,
+ })
+
+ ctx := dnsserver.ContextWithRequestInfo(context.Background(), &dnsserver.RequestInfo{})
+ ri := &agd.RequestInfo{
+ RemoteIP: tc.raddr.Addr(),
+ }
+
+ err := pf.SetDevice(ctx, tc.req, ri, tc.laddr)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+ assert.Equal(t, tc.wantProf, ri.Profile)
+ assert.Equal(t, tc.wantDev, ri.Device)
+ })
+ }
+}
+
+func TestDefault_SetDevice_plainEDNS(t *testing.T) {
+ testCases := []struct {
+ req *dns.Msg
+ srv *agd.Server
+ wantProf *agd.Profile
+ wantDev *agd.Device
+ wantErrMsg string
+ laddr netip.AddrPort
+ raddr netip.AddrPort
+ name string
+ }{{
+ req: reqNormal,
+ srv: srvPlain,
+ wantProf: nil,
+ wantDev: nil,
+ wantErrMsg: "",
+ laddr: dnssvctest.ServerAddrPort,
+ raddr: dnssvctest.ClientAddrPort,
+ name: "no_edns",
+ }, {
+ req: reqEDNS,
+ srv: srvPlain,
+ wantProf: nil,
+ wantDev: nil,
+ wantErrMsg: "",
+ laddr: dnssvctest.ServerAddrPort,
+ raddr: dnssvctest.ClientAddrPort,
+ name: "edns_no_dev_id",
+ }, {
+ req: reqEDNSDevID,
+ srv: srvPlain,
+ wantProf: profNormal,
+ wantDev: devNormal,
+ wantErrMsg: "",
+ laddr: dnssvctest.ServerAddrPort,
+ raddr: dnssvctest.ClientAddrPort,
+ name: "edns_dev_id",
+ }, {
+ req: reqEDNSBadDevID,
+ srv: srvPlain,
+ wantProf: nil,
+ wantDev: nil,
+ wantErrMsg: `edns option device id check: bad device id "!!!": bad hostname label rune '!'`,
+ laddr: dnssvctest.ServerAddrPort,
+ raddr: dnssvctest.ClientAddrPort,
+ name: "edns_bad_dev_id",
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ profDB := &agdtest.ProfileDB{
+ OnProfileByDedicatedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ OnProfileByDeviceID: newOnProfileByDeviceID(dnssvctest.DeviceID),
+ OnProfileByLinkedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ }
+
+ pf := devicesetter.NewDefault(&devicesetter.Config{
+ ProfileDB: profDB,
+ Server: tc.srv,
+ DeviceIDWildcards: nil,
+ })
+
+ ctx := dnsserver.ContextWithRequestInfo(context.Background(), &dnsserver.RequestInfo{})
+ ri := &agd.RequestInfo{
+ RemoteIP: tc.raddr.Addr(),
+ }
+
+ err := pf.SetDevice(ctx, tc.req, ri, tc.laddr)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+ assert.Equal(t, tc.wantProf, ri.Profile)
+ assert.Equal(t, tc.wantDev, ri.Device)
+ })
+ }
+}
+
+func TestDefault_SetDevice_deleted(t *testing.T) {
+ t.Parallel()
+
+ profDB := &agdtest.ProfileDB{
+ OnProfileByDedicatedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ OnProfileByDeviceID: func(
+ _ context.Context,
+ _ agd.DeviceID,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ OnProfileByLinkedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ return profDeleted, devNormal, nil
+ },
+ }
+
+ pf := devicesetter.NewDefault(&devicesetter.Config{
+ ProfileDB: profDB,
+ Server: srvPlainWithLinkedIP,
+ })
+
+ raddr := linkedAddrPort
+ msgCons := agdtest.NewConstructor()
+ ri := &agd.RequestInfo{
+ Messages: msgCons,
+ RemoteIP: raddr.Addr(),
+ }
+
+ ctx := dnsserver.ContextWithRequestInfo(context.Background(), &dnsserver.RequestInfo{})
+ err := pf.SetDevice(ctx, reqNormal, ri, dnssvctest.ServerAddrPort)
+ require.Nil(t, err)
+
+ assert.Nil(t, ri.Profile)
+ assert.Nil(t, ri.Device)
+ assert.Same(t, msgCons, ri.Messages)
+}
diff --git a/internal/dnssvc/internal/devicesetter/deviceid.go b/internal/dnssvc/internal/devicesetter/deviceid.go
new file mode 100644
index 0000000..5092a16
--- /dev/null
+++ b/internal/dnssvc/internal/devicesetter/deviceid.go
@@ -0,0 +1,234 @@
+package devicesetter
+
+import (
+ "fmt"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
+ "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/netutil"
+ "github.com/miekg/dns"
+)
+
+// supportsDeviceID returns true if p supports a way to get a device ID.
+func supportsDeviceID(p agd.Protocol) (ok bool) {
+ switch p {
+ case
+ agd.ProtoDNS,
+ agd.ProtoDoH,
+ agd.ProtoDoQ,
+ agd.ProtoDoT:
+ return true
+ default:
+ return false
+ }
+}
+
+// deviceID extracts the device ID from the given parameters. If the device ID
+// is not found, it returns an empty ID and nil, as the lookup could also be
+// done later by remote and local addresses.
+func (ds *Default) deviceID(
+ req *dns.Msg,
+ srvReqInfo *dnsserver.RequestInfo,
+) (id agd.DeviceID, err error) {
+ if ds.srv.Protocol.IsStdEncrypted() {
+ return ds.deviceIDFromSrvReqInfo(srvReqInfo)
+ }
+
+ return deviceIDFromEDNS(req)
+}
+
+// deviceIDFromSrvReqInfo extracts device ID from the arguments. The ID is
+// extracted in the following manner:
+//
+// 1. If applicable, the ID is firstly extracted from the DoH information, such
+// as the userinfo or URL path.
+//
+// 2. Secondly, the TLS Server Name is inspected using ds's device ID
+// wildcards.
+//
+// Any returned errors will have the underlying type of [*deviceIDError].
+func (ds *Default) deviceIDFromSrvReqInfo(
+ srvReqInfo *dnsserver.RequestInfo,
+) (id agd.DeviceID, err error) {
+ if ds.srv.Protocol == agd.ProtoDoH {
+ id, err = deviceIDForDoH(srvReqInfo)
+ if id != "" || err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return id, err
+ }
+ }
+
+ if len(ds.wildcardDomains) == 0 {
+ return "", nil
+ }
+
+ id, err = ds.deviceIDFromCliSrvName(srvReqInfo.TLSServerName)
+ if err != nil {
+ return "", newDeviceIDError(err, "tls server name")
+ }
+
+ return id, nil
+}
+
+// deviceIDForDoH extracts a device ID from the DoH request information. The ID
+// is extracted firstly from the request's userinfo, if any, and then from the
+// URL path. srvReqInfo must not be nil.
+//
+// Any returned errors will have the underlying type of [*deviceIDError].
+func deviceIDForDoH(srvReqInfo *dnsserver.RequestInfo) (id agd.DeviceID, err error) {
+ if userinfo := srvReqInfo.Userinfo; userinfo != nil {
+ id, err = agd.NewDeviceID(userinfo.Username())
+ if err != nil {
+ return "", newDeviceIDError(err, "basic auth")
+ }
+
+ return id, nil
+ }
+
+ id, err = deviceIDFromDoHURL(srvReqInfo.URL)
+ if err != nil {
+ return "", newDeviceIDError(err, "http url path")
+ }
+
+ // In case of empty device ID, we will continue the lookup process.
+ return id, nil
+}
+
+// deviceIDFromDoHURL extracts the device ID from the path of the DoH request.
+func deviceIDFromDoHURL(u *url.URL) (id agd.DeviceID, err error) {
+ parts, err := pathParts(u.Path)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return "", err
+ }
+
+ if len(parts) == 2 {
+ // Don't wrap the error, because it's informative enough as is.
+ return agd.NewDeviceID(parts[1])
+ }
+
+ // pathParts guarantees that if there aren't two parts, there's only one,
+ // and it is a valid DNS path.
+ return "", nil
+}
+
+// pathParts splits and validates urlPath. If err is nil, parts has either one
+// or two parts.
+func pathParts(urlPath string) (parts []string, err error) {
+ defer func() { err = errors.Annotate(err, "bad path %q: %w", urlPath) }()
+
+ parts = strings.Split(path.Clean(urlPath), "/")
+ if parts[0] == "" {
+ parts = parts[1:]
+ }
+
+ l := len(parts)
+ if l == 0 || parts[0] == "" {
+ return nil, errors.Error("empty elements")
+ } else if l > 2 {
+ return nil, fmt.Errorf("%d extra parts", l-2)
+ }
+
+ if !strings.HasSuffix(dnsserver.PathDoH, parts[0]) &&
+ !strings.HasSuffix(dnsserver.PathJSON, parts[0]) {
+ return nil, errors.Error("not a dns path")
+ }
+
+ return parts, nil
+}
+
+// deviceIDFromCliSrvName extracts and validates a device ID. cliSrvName is the
+// server name as sent by the client.
+func (ds *Default) deviceIDFromCliSrvName(cliSrvName string) (id agd.DeviceID, err error) {
+ if cliSrvName == "" {
+ // No server name in ClientHello, so the request is probably made on the
+ // IP address.
+ return "", nil
+ }
+
+ matchedDomain := matchDomain(cliSrvName, ds.wildcardDomains)
+ if matchedDomain == "" {
+ return "", nil
+ }
+
+ optlog.Debug2("devicesetter: device id: matched %q from %q", matchedDomain, ds.wildcardDomains)
+
+ idStr := cliSrvName[:len(cliSrvName)-len(matchedDomain)-1]
+ id, err = agd.NewDeviceID(idStr)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return "", err
+ }
+
+ return id, nil
+}
+
+// matchDomain searches among domains for one the subdomain of which is sub. If
+// there is no such domain, matchDomain returns an empty string.
+func matchDomain(sub string, domains []string) (matchedDomain string) {
+ for _, domain := range domains {
+ if netutil.IsImmediateSubdomain(sub, domain) {
+ return domain
+ }
+ }
+
+ return ""
+}
+
+// DnsmasqCPEIDOption is the identifier of dnsmasq EDNS0 option
+// EDNS0_OPTION_NOMCPEID.
+//
+// See https://github.com/PowerDNS/dnsmasq/blob/master/src/dns-protocol.h.
+const DnsmasqCPEIDOption uint16 = 65074
+
+// deviceIDFromEDNS extracts the device ID from EDNS0 option of plain DNS
+// request. This method works with dnsmasq option `--add-cpe-id`, which adds
+// an identifying string to DNS queries through [dnsmasqCPEIDOption] option as
+// a non-standard support of Nominum servers. Requests of this kind could also
+// be emulated with `+ednsopt` option of `dig` utility:
+//
+// dig @94.140.14.49 'edns-id.example' IN A\
+// +ednsopt=65074:"$( printf 'abcd1234' | od -A n -t x1 | tr -d ' ' )"
+//
+// Any returned errors will have the underlying type of [*deviceIDError].
+func deviceIDFromEDNS(req *dns.Msg) (id agd.DeviceID, err error) {
+ option := req.IsEdns0()
+ if option == nil {
+ return "", nil
+ }
+
+ for _, opt := range option.Option {
+ id, err = deviceIDFromENDSOPT(opt)
+ if id != "" || err != nil {
+ return id, err
+ }
+ }
+
+ return "", nil
+}
+
+// deviceIDFromENDSOPT inspects opt and, if it's an option that can carry a
+// device ID, returns a validated device ID or the validation error. Any
+// returned errors will have the underlying type of [*deviceIDError].
+func deviceIDFromENDSOPT(opt dns.EDNS0) (id agd.DeviceID, err error) {
+ if opt.Option() != DnsmasqCPEIDOption {
+ return "", nil
+ }
+
+ o, ok := opt.(*dns.EDNS0_LOCAL)
+ if !ok {
+ return "", nil
+ }
+
+ id, err = agd.NewDeviceID(string(o.Data))
+ if err != nil {
+ return "", newDeviceIDError(err, "edns option")
+ }
+
+ return id, nil
+}
diff --git a/internal/dnssvc/internal/devicesetter/deviceid_test.go b/internal/dnssvc/internal/devicesetter/deviceid_test.go
new file mode 100644
index 0000000..2c4ff0f
--- /dev/null
+++ b/internal/dnssvc/internal/devicesetter/deviceid_test.go
@@ -0,0 +1,468 @@
+package devicesetter_test
+
+import (
+ "context"
+ "net/netip"
+ "net/url"
+ "path"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicesetter"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestDefault_SetDevice_DoHAuth(t *testing.T) {
+ t.Parallel()
+
+ var (
+ devAuthSuccess = newDevAuth(false, true)
+ devAuthFail = newDevAuth(false, false)
+ )
+
+ testCases := []struct {
+ wantProf *agd.Profile
+ wantDev *agd.Device
+ profDBDev *agd.Device
+ reqURL *url.URL
+ wantErrMsg string
+ name string
+ }{{
+ wantProf: profNormal,
+ wantDev: devAuthSuccess,
+ profDBDev: devAuthSuccess,
+ reqURL: &url.URL{
+ Path: dnsserver.PathDoH,
+ User: url.UserPassword(dnssvctest.DeviceIDStr, testPassword),
+ },
+ wantErrMsg: "",
+ name: "success",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ profDBDev: devAuthFail,
+ reqURL: &url.URL{
+ Path: dnsserver.PathDoH,
+ User: url.UserPassword(dnssvctest.DeviceIDStr, testPassword),
+ },
+ wantErrMsg: "",
+ name: "passwd_fail",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ profDBDev: devAuthSuccess,
+ reqURL: &url.URL{
+ Path: dnsserver.PathDoH,
+ User: url.User(dnssvctest.DeviceIDStr),
+ },
+ wantErrMsg: "",
+ name: "no_passwd",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ profDBDev: nil,
+ reqURL: &url.URL{
+ Path: dnsserver.PathDoH,
+ User: nil,
+ },
+ wantErrMsg: "",
+ name: "no_userinfo",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ profDBDev: devAuthSuccess,
+ reqURL: &url.URL{
+ Path: dnsserver.PathDoH,
+ User: url.UserPassword("!!!", testPassword),
+ },
+ wantErrMsg: `basic auth device id check: bad device id "!!!": bad hostname label rune '!'`,
+ name: "bad_id",
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ profDB := &agdtest.ProfileDB{
+ OnProfileByDedicatedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ OnProfileByDeviceID: func(
+ _ context.Context,
+ devID agd.DeviceID,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ if tc.profDBDev != nil {
+ return profNormal, tc.profDBDev, nil
+ }
+
+ return nil, nil, profiledb.ErrDeviceNotFound
+ },
+ OnProfileByLinkedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ }
+
+ df := devicesetter.NewDefault(&devicesetter.Config{
+ ProfileDB: profDB,
+ Server: srvDoH,
+ DeviceIDWildcards: []string{},
+ })
+
+ ctx := dnsserver.ContextWithRequestInfo(context.Background(), &dnsserver.RequestInfo{
+ TLSServerName: dnssvctest.DomainForDevices,
+ URL: tc.reqURL,
+ Userinfo: tc.reqURL.User,
+ })
+ ri := &agd.RequestInfo{
+ RemoteIP: dnssvctest.ClientAddr,
+ }
+
+ err := df.SetDevice(ctx, reqNormal, ri, dnssvctest.ServerAddrPort)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+ assert.Equal(t, tc.wantProf, ri.Profile)
+ assert.Equal(t, tc.wantDev, ri.Device)
+ })
+ }
+}
+
+func TestDefault_SetDevice_DoHAuthOnly(t *testing.T) {
+ t.Parallel()
+
+ var (
+ devAuthSuccess = newDevAuth(true, true)
+ devAuthFail = newDevAuth(true, false)
+ )
+
+ testCases := []struct {
+ wantProf *agd.Profile
+ wantDev *agd.Device
+ profDBDev *agd.Device
+ srv *agd.Server
+ reqURL *url.URL
+ wantErrMsg string
+ cliSrvName string
+ name string
+ }{{
+ wantProf: profNormal,
+ wantDev: devAuthSuccess,
+ profDBDev: devAuthSuccess,
+ srv: srvDoH,
+ reqURL: &url.URL{
+ Path: dnsserver.PathDoH,
+ User: url.UserPassword(dnssvctest.DeviceIDStr, testPassword),
+ },
+ wantErrMsg: "",
+ cliSrvName: dnssvctest.DomainForDevices,
+ name: "success",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ profDBDev: devAuthFail,
+ srv: srvDoH,
+ reqURL: &url.URL{
+ Path: dnsserver.PathDoH,
+ User: url.UserPassword(dnssvctest.DeviceIDStr, testPassword),
+ },
+ wantErrMsg: "",
+ cliSrvName: dnssvctest.DomainForDevices,
+ name: "passwd_fail",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ profDBDev: devAuthSuccess,
+ srv: srvDoT,
+ reqURL: nil,
+ wantErrMsg: "",
+ cliSrvName: dnssvctest.DeviceIDSrvName,
+ name: "not_doh",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ profDBDev: devAuthSuccess,
+ srv: srvDoH,
+ reqURL: &url.URL{
+ Path: dnsserver.PathDoH,
+ User: nil,
+ },
+ wantErrMsg: "",
+ cliSrvName: dnssvctest.DeviceIDSrvName,
+ name: "no_userinfo",
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ profDB := &agdtest.ProfileDB{
+ OnProfileByDedicatedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ OnProfileByDeviceID: func(
+ _ context.Context,
+ devID agd.DeviceID,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ return profNormal, tc.profDBDev, nil
+ },
+ OnProfileByLinkedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ }
+
+ df := devicesetter.NewDefault(&devicesetter.Config{
+ ProfileDB: profDB,
+ Server: tc.srv,
+ DeviceIDWildcards: []string{dnssvctest.DeviceIDWildcard},
+ })
+
+ srvReqInfo := &dnsserver.RequestInfo{
+ TLSServerName: tc.cliSrvName,
+ URL: tc.reqURL,
+ }
+ if tc.reqURL != nil {
+ srvReqInfo.Userinfo = tc.reqURL.User
+ }
+
+ ctx := dnsserver.ContextWithRequestInfo(context.Background(), srvReqInfo)
+ ri := &agd.RequestInfo{
+ RemoteIP: dnssvctest.ClientAddr,
+ }
+
+ err := df.SetDevice(ctx, reqNormal, ri, dnssvctest.ServerAddrPort)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+ assert.Equal(t, tc.wantProf, ri.Profile)
+ assert.Equal(t, tc.wantDev, ri.Device)
+ })
+ }
+}
+
+func TestDefault_SetDevice_DoH(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ wantProf *agd.Profile
+ wantDev *agd.Device
+ reqURL *url.URL
+ wantErrMsg string
+ name string
+ }{{
+ wantProf: profNormal,
+ wantDev: devNormal,
+ reqURL: &url.URL{
+ Path: path.Join(dnsserver.PathDoH, dnssvctest.DeviceIDStr),
+ },
+ wantErrMsg: "",
+ name: "id_path_match",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ reqURL: &url.URL{
+ Path: path.Join(dnsserver.PathDoH, dnssvctest.DeviceIDStr, "extra"),
+ },
+ wantErrMsg: `http url path device id check: bad path "/dns-query/` +
+ dnssvctest.DeviceIDStr + `/extra": ` + `1 extra parts`,
+ name: "extra_parts",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ reqURL: &url.URL{
+ Path: path.Join(dnsserver.PathDoH, "!!!"),
+ },
+ wantErrMsg: `http url path device id check: bad device id "!!!": ` +
+ `bad hostname label rune '!'`,
+ name: "bad_id",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ reqURL: &url.URL{
+ Path: dnsserver.PathDoH,
+ },
+ wantErrMsg: "",
+ name: "no_id",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ reqURL: &url.URL{
+ Path: "/",
+ },
+ wantErrMsg: `http url path device id check: bad path "/": empty elements`,
+ name: "empty_path",
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ reqURL: &url.URL{
+ Path: "/other",
+ },
+ wantErrMsg: `http url path device id check: bad path "/other": not a dns path`,
+ name: "not_dns_path",
+ }}
+
+ profDB := &agdtest.ProfileDB{
+ OnProfileByDedicatedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ OnProfileByDeviceID: newOnProfileByDeviceID(dnssvctest.DeviceID),
+ OnProfileByLinkedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ df := devicesetter.NewDefault(&devicesetter.Config{
+ ProfileDB: profDB,
+ Server: srvDoH,
+ DeviceIDWildcards: []string{},
+ })
+
+ ctx := dnsserver.ContextWithRequestInfo(context.Background(), &dnsserver.RequestInfo{
+ TLSServerName: dnssvctest.DomainForDevices,
+ URL: tc.reqURL,
+ })
+ ri := &agd.RequestInfo{
+ RemoteIP: dnssvctest.ClientAddr,
+ }
+
+ err := df.SetDevice(ctx, reqNormal, ri, dnssvctest.ServerAddrPort)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+ assert.Equal(t, tc.wantProf, ri.Profile)
+ assert.Equal(t, tc.wantDev, ri.Device)
+ })
+ }
+}
+
+func TestDefault_SetDevice_stdEncrypted(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ wantProf *agd.Profile
+ wantDev *agd.Device
+ wantErrMsg string
+ cliSrvName string
+ name string
+ wildcards []string
+ }{{
+ wantProf: nil,
+ wantDev: nil,
+ wantErrMsg: "",
+ cliSrvName: "",
+ name: "no_id",
+ wildcards: nil,
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ wantErrMsg: "",
+ cliSrvName: dnssvctest.DeviceIDSrvName,
+ name: "no_wildcards",
+ wildcards: nil,
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ wantErrMsg: "",
+ cliSrvName: "",
+ name: "no_cli_srvname",
+ wildcards: []string{dnssvctest.DeviceIDWildcard},
+ }, {
+ wantProf: profNormal,
+ wantDev: devNormal,
+ wantErrMsg: "",
+ cliSrvName: dnssvctest.DeviceIDSrvName,
+ name: "id_match",
+ wildcards: []string{dnssvctest.DeviceIDWildcard},
+ }, {
+ wantProf: nil,
+ wantDev: nil,
+ wantErrMsg: `tls server name device id check: bad device id "!!!": ` +
+ `bad hostname label rune '!'`,
+ cliSrvName: "!!!.d.dns.example",
+ name: "bad_id",
+ wildcards: []string{dnssvctest.DeviceIDWildcard},
+ }}
+
+ profDB := &agdtest.ProfileDB{
+ OnProfileByDedicatedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ OnProfileByDeviceID: newOnProfileByDeviceID(dnssvctest.DeviceID),
+ OnProfileByLinkedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+ }
+
+ srvData := []struct {
+ srv *agd.Server
+ reqURL *url.URL
+ name string
+ }{{
+ srv: srvDoH,
+ reqURL: &url.URL{
+ Path: dnsserver.PathDoH,
+ },
+ name: "doh",
+ }, {
+ srv: srvDoQ,
+ reqURL: nil,
+ name: "doq",
+ }, {
+ srv: srvDoT,
+ reqURL: nil,
+ name: "dot",
+ }}
+
+ for _, tc := range testCases {
+ for _, sd := range srvData {
+ t.Run(sd.name+"_"+tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ df := devicesetter.NewDefault(&devicesetter.Config{
+ ProfileDB: profDB,
+ Server: sd.srv,
+ DeviceIDWildcards: tc.wildcards,
+ })
+
+ ctx := dnsserver.ContextWithRequestInfo(context.Background(), &dnsserver.RequestInfo{
+ TLSServerName: tc.cliSrvName,
+ URL: sd.reqURL,
+ })
+ ri := &agd.RequestInfo{
+ RemoteIP: dnssvctest.ClientAddr,
+ }
+
+ err := df.SetDevice(ctx, reqNormal, ri, dnssvctest.ServerAddrPort)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+ assert.Equal(t, tc.wantProf, ri.Profile)
+ assert.Equal(t, tc.wantDev, ri.Device)
+ })
+ }
+ }
+}
diff --git a/internal/dnssvc/internal/devicesetter/devicesetter.go b/internal/dnssvc/internal/devicesetter/devicesetter.go
new file mode 100644
index 0000000..455f47c
--- /dev/null
+++ b/internal/dnssvc/internal/devicesetter/devicesetter.go
@@ -0,0 +1,124 @@
+// Package devicesetter contains the logic for looking up and authenticating
+// profiles and devices for a DNS query.
+//
+// TODO(a.garipov): Use.
+package devicesetter
+
+import (
+ "context"
+ "fmt"
+ "net/netip"
+ "strings"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
+ "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
+ "github.com/miekg/dns"
+)
+
+// Interface is the profile-setter interface.
+type Interface interface {
+ // SetDevice sets the device, profile, and message-constructor data in ri if
+ // it can recognize those. All arguments must not be nil. ri.RemoteIP must
+ // be set.
+ //
+ // If the request uses a dedicated server IP address for which there are no
+ // devices, SetDevice returns [ErrUnknownDedicated].
+ //
+ // TODO(a.garipov): Consider returning a struct instead of setting things
+ // directly in ri.
+ SetDevice(
+ ctx context.Context,
+ req *dns.Msg,
+ ri *agd.RequestInfo,
+ laddr netip.AddrPort,
+ ) (err error)
+}
+
+// Empty is an [Interface] implementation that does nothing.
+type Empty struct{}
+
+// type check
+var _ Interface = Empty{}
+
+// SetDevice implements the [Interface] interface for Empty. It does nothing
+// and returns nil.
+func (Empty) SetDevice(
+ ctx context.Context,
+ req *dns.Msg,
+ ri *agd.RequestInfo,
+ laddr netip.AddrPort,
+) (err error) {
+ return nil
+}
+
+// Config is the configuration structure for the default profile setter.
+type Config struct {
+ // ProfileDB is used to find the profiles. It must not be nil.
+ ProfileDB profiledb.Interface
+
+ // Server contains the data of the server for which the profiles are found.
+ // It must not be nil.
+ Server *agd.Server
+
+ // DeviceIDWildcards, if any, provides the wildcards of domain names to use
+ // for looking up device ID from TLS server names.
+ DeviceIDWildcards []string
+}
+
+// Default is the default profile setter.
+type Default struct {
+ db profiledb.Interface
+ srv *agd.Server
+ wildcardDomains []string
+}
+
+// NewDefault returns a new default profile setter. c must be non-nil and
+// valid.
+func NewDefault(c *Config) (ds *Default) {
+ var wildcardDomains []string
+ for _, w := range c.DeviceIDWildcards {
+ wildcardDomains = append(wildcardDomains, strings.TrimPrefix(w, "*."))
+ }
+
+ return &Default{
+ db: c.ProfileDB,
+ srv: c.Server,
+ wildcardDomains: wildcardDomains,
+ }
+}
+
+// type check
+var _ Interface = (*Default)(nil)
+
+// SetDevice sets the profile, device, and message constructor in ri using the
+// information from req and laddr. ctx must contain [*dnsserver.RequestInfo].
+func (ds *Default) SetDevice(
+ ctx context.Context,
+ req *dns.Msg,
+ ri *agd.RequestInfo,
+ laddr netip.AddrPort,
+) (err error) {
+ if !supportsDeviceID(ds.srv.Protocol) {
+ return nil
+ }
+
+ srvReqInfo := dnsserver.MustRequestInfoFromContext(ctx)
+ id, err := ds.deviceID(req, srvReqInfo)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return err
+ }
+
+ prof, dev, err := ds.findDevice(ctx, laddr, ri.RemoteIP, id)
+ if err != nil {
+ // Likely [errUnknownDedicated].
+ return fmt.Errorf("setting profile: %w", err)
+ } else if prof == nil || dev == nil {
+ return nil
+ }
+
+ ds.setDevice(ctx, ri, srvReqInfo, prof, dev)
+
+ return nil
+}
diff --git a/internal/dnssvc/internal/devicesetter/devicesetter_test.go b/internal/dnssvc/internal/devicesetter/devicesetter_test.go
new file mode 100644
index 0000000..4004fd5
--- /dev/null
+++ b/internal/dnssvc/internal/devicesetter/devicesetter_test.go
@@ -0,0 +1,222 @@
+package devicesetter_test
+
+import (
+ "context"
+ "net/netip"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicesetter"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/miekg/dns"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestMain(m *testing.M) {
+ srvPlainWithBindData.SetBindData([]*agd.ServerBindData{{
+ ListenConfig: &agdtest.ListenConfig{},
+ PrefixAddr: &agdnet.PrefixNetAddr{
+ // TODO(a.garipov): Move to dnssvctest?
+ Prefix: netip.MustParsePrefix("192.0.2.0/30"),
+ Net: "udp",
+ Port: 53,
+ },
+ }})
+
+ testutil.DiscardLogOutput(m)
+}
+
+// Common requests for tests.
+var (
+ reqNormal = dnsservertest.NewReq(dnssvctest.DomainFQDN, dns.TypeA, dns.ClassINET)
+ reqEDNS = dnsservertest.NewReq(
+ dnssvctest.DomainFQDN,
+ dns.TypeA,
+ dns.ClassINET,
+ dnsservertest.SectionExtra{
+ newExtraOPT(1234, []byte{5, 6, 7, 8}),
+ },
+ )
+ reqEDNSDevID = dnsservertest.NewReq(
+ dnssvctest.DomainFQDN,
+ dns.TypeA,
+ dns.ClassINET,
+ dnsservertest.SectionExtra{
+ newExtraOPT(devicesetter.DnsmasqCPEIDOption, []byte(dnssvctest.DeviceID)),
+ },
+ )
+ reqEDNSBadDevID = dnsservertest.NewReq(
+ dnssvctest.DomainFQDN,
+ dns.TypeA,
+ dns.ClassINET,
+ dnsservertest.SectionExtra{
+ newExtraOPT(devicesetter.DnsmasqCPEIDOption, []byte("!!!")),
+ },
+ )
+)
+
+// testPassword is the common password for tests.
+//
+// TODO(a.garipov): Move to dnssvctest?
+const testPassword = "123456"
+
+// newExtraOPT returns a new dns.OPT with a local option with the given code and
+// data.
+func newExtraOPT(code uint16, data []byte) (opt *dns.OPT) {
+ return &dns.OPT{
+ Hdr: dns.RR_Header{
+ Rrtype: dns.TypeOPT,
+ },
+ Option: []dns.EDNS0{&dns.EDNS0_LOCAL{
+ Code: code,
+ Data: data,
+ }},
+ }
+}
+
+// Common servers for tests.
+var (
+ srvPlain = &agd.Server{
+ Protocol: agd.ProtoDNS,
+ LinkedIPEnabled: false,
+ }
+ srvPlainWithLinkedIP = &agd.Server{
+ Protocol: agd.ProtoDNS,
+ LinkedIPEnabled: true,
+ }
+ srvDoH = &agd.Server{
+ Protocol: agd.ProtoDoH,
+ }
+ srvDoQ = &agd.Server{
+ Protocol: agd.ProtoDoQ,
+ }
+ srvDoT = &agd.Server{
+ Protocol: agd.ProtoDoT,
+ }
+
+ // NOTE: The bind data are set in [TestMain].
+ srvPlainWithBindData = &agd.Server{
+ Protocol: agd.ProtoDNS,
+ LinkedIPEnabled: false,
+ }
+)
+
+// Common addresses for tests.
+//
+// TODO(a.garipov): Move more common variables and constants to dnssvctest.
+var (
+ linkedAddr = netip.MustParseAddr("192.0.2.1")
+ dedicatedAddr = netip.MustParseAddr("192.0.2.2")
+
+ linkedAddrPort = netip.AddrPortFrom(linkedAddr, 12345)
+ dedicatedAddrPort = netip.AddrPortFrom(dedicatedAddr, 53)
+)
+
+// Common profiles and devices for tests.
+var (
+ profNormal = &agd.Profile{
+ BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ ID: dnssvctest.ProfileID,
+ DeviceIDs: []agd.DeviceID{dnssvctest.DeviceID},
+ Deleted: false,
+ }
+
+ profDeleted = &agd.Profile{
+ BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ ID: dnssvctest.ProfileID,
+ DeviceIDs: []agd.DeviceID{dnssvctest.DeviceID},
+ Deleted: true,
+ }
+
+ devNormal = &agd.Device{
+ Auth: &agd.AuthSettings{
+ Enabled: false,
+ },
+ ID: dnssvctest.DeviceID,
+ LinkedIP: linkedAddr,
+ }
+)
+
+// newDevAuth returns a new device with the given parameters for tests.
+func newDevAuth(dohAuthOnly, passwdMatches bool) (d *agd.Device) {
+ return &agd.Device{
+ Auth: &agd.AuthSettings{
+ PasswordHash: &agdtest.Authenticator{
+ OnAuthenticate: func(_ context.Context, _ []byte) (ok bool) {
+ return passwdMatches
+ },
+ },
+ Enabled: true,
+ DoHAuthOnly: dohAuthOnly,
+ },
+ ID: dnssvctest.DeviceID,
+ }
+}
+
+// newOnProfileByDedicatedIP returns a function with the type of
+// [agdtest.ProfileDB.OnProfileByDedicatedIP] that returns p and d only when
+// localIP is equal to the given one.
+func newOnProfileByDedicatedIP(
+ wantLocalIP netip.Addr,
+) (f func(_ context.Context, localIP netip.Addr) (p *agd.Profile, d *agd.Device, err error)) {
+ return func(_ context.Context, localIP netip.Addr) (p *agd.Profile, d *agd.Device, err error) {
+ if localIP == wantLocalIP {
+ return profNormal, devNormal, nil
+ }
+
+ return nil, nil, profiledb.ErrDeviceNotFound
+ }
+}
+
+// newOnProfileByDeviceID returns a function with the type of
+// [agdtest.ProfileDB.OnProfileByDeviceID] that returns p and d only when devID
+// is equal to the given one.
+func newOnProfileByDeviceID(
+ wantDevID agd.DeviceID,
+) (f func(_ context.Context, devID agd.DeviceID) (p *agd.Profile, d *agd.Device, err error)) {
+ return func(_ context.Context, devID agd.DeviceID) (p *agd.Profile, d *agd.Device, err error) {
+ if devID == wantDevID {
+ return profNormal, devNormal, nil
+ }
+
+ return nil, nil, profiledb.ErrDeviceNotFound
+ }
+}
+
+// newOnProfileByLinkedIP returns a function with the type of
+// [agdtest.ProfileDB.OnProfileByLinkedIP] that returns p and d only when
+// remoteIP is equal to the given one.
+func newOnProfileByLinkedIP(
+ wantRemoteIP netip.Addr,
+) (f func(_ context.Context, remoteIP netip.Addr) (p *agd.Profile, d *agd.Device, err error)) {
+ return func(_ context.Context, remoteIP netip.Addr) (p *agd.Profile, d *agd.Device, err error) {
+ if remoteIP == wantRemoteIP {
+ return profNormal, devNormal, nil
+ }
+
+ return nil, nil, profiledb.ErrDeviceNotFound
+ }
+}
+
+func TestDefault_SetDevice_dnscrypt(t *testing.T) {
+ t.Parallel()
+
+ df := devicesetter.NewDefault(&devicesetter.Config{
+ Server: &agd.Server{
+ Protocol: agd.ProtoDNSCrypt,
+ },
+ })
+
+ ctx := context.Background()
+ ri := &agd.RequestInfo{}
+ err := df.SetDevice(ctx, reqNormal, ri, dnssvctest.ServerAddrPort)
+ assert.Nil(t, err)
+ assert.Nil(t, ri.Profile)
+ assert.Nil(t, ri.Device)
+}
diff --git a/internal/dnssvc/internal/devicesetter/error.go b/internal/dnssvc/internal/devicesetter/error.go
new file mode 100644
index 0000000..3517989
--- /dev/null
+++ b/internal/dnssvc/internal/devicesetter/error.go
@@ -0,0 +1,51 @@
+package devicesetter
+
+import (
+ "fmt"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/golibs/errors"
+)
+
+const (
+ // ErrUnknownDedicated is returned by [Interface.SetDevice] if the request
+ // should be dropped, because it's a request for an unknown dedicated IP
+ // address.
+ ErrUnknownDedicated errors.Error = "unknown dedicated ip"
+)
+
+// deviceIDError is an error about bad device ID or other issues found during
+// device ID checking.
+type deviceIDError struct {
+ err error
+ typ string
+}
+
+// type check
+var _ error = (*deviceIDError)(nil)
+
+// newDeviceIDError is a helper constructor for device-ID errors.
+func newDeviceIDError(orig error, typ string) (err error) {
+ return &deviceIDError{
+ err: orig,
+ typ: typ,
+ }
+}
+
+// Error implements the error interface for *deviceIDError.
+func (err *deviceIDError) Error() (msg string) {
+ return fmt.Sprintf("%s device id check: %s", err.typ, err.err)
+}
+
+// type check
+var _ errors.Wrapper = (*deviceIDError)(nil)
+
+// Unwrap implements the [errors.Wrapper] interface for *deviceIDError.
+func (err *deviceIDError) Unwrap() (unwrapped error) { return err.err }
+
+// type check
+var _ errcoll.SentryReportableError = (*deviceIDError)(nil)
+
+// IsSentryReportable implements the [errcoll.SentryReportableError] interface
+// for *deviceIDError.
+func (*deviceIDError) IsSentryReportable() (ok bool) { return false }
diff --git a/internal/dnssvc/internal/dnssvctest/dnssvctest.go b/internal/dnssvc/internal/dnssvctest/dnssvctest.go
index dcb1f45..dd596d8 100644
--- a/internal/dnssvc/internal/dnssvctest/dnssvctest.go
+++ b/internal/dnssvc/internal/dnssvctest/dnssvctest.go
@@ -56,10 +56,19 @@ const (
// ServerName is the common server name for tests.
const ServerName agd.ServerName = "test_server_dns_tls"
-// DeviceIDWildcard is the common wildcard domain for retrieving [agd.DeviceID]
-// in tests. Use [strings.ReplaceAll] to replace the "*" symbol with the actual
-// [agd.DeviceID].
-const DeviceIDWildcard = "*.dns.example.com"
+const (
+ // DomainForDevices is the upper-level domain name for requests with device
+ // in e.g. HTTP path.
+ DomainForDevices = "d.dns.example"
+
+ // DeviceIDWildcard is the common wildcard domain for retrieving [agd.DeviceID]
+ // in tests. Use [strings.ReplaceAll] to replace the "*" symbol with the actual
+ // [agd.DeviceID] or use [DeviceIDSrvName].
+ DeviceIDWildcard = "*." + DomainForDevices
+
+ // DeviceIDSrvName is the common client server-name for tests.
+ DeviceIDSrvName = DeviceIDStr + "." + DomainForDevices
+)
// Common addresses for tests.
var (
diff --git a/internal/dnssvc/internal/dnssvctest/interface.go b/internal/dnssvc/internal/dnssvctest/interface.go
new file mode 100644
index 0000000..380a185
--- /dev/null
+++ b/internal/dnssvc/internal/dnssvctest/interface.go
@@ -0,0 +1,37 @@
+package dnssvctest
+
+import (
+ "context"
+ "net/netip"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicesetter"
+ "github.com/miekg/dns"
+)
+
+// Package devicesetter
+
+// type check
+var _ devicesetter.Interface = (*DeviceSetter)(nil)
+
+// DeviceSetter is a [devicesetter.Interface] implementation for DNS service
+// tests.
+type DeviceSetter struct {
+ OnSetDevice func(
+ ctx context.Context,
+ req *dns.Msg,
+ ri *agd.RequestInfo,
+ laddr netip.AddrPort,
+ ) (err error)
+}
+
+// SetDevice implements the [devicesetter.Interface] interface for
+// *DeviceSetter.
+func (ds *DeviceSetter) SetDevice(
+ ctx context.Context,
+ req *dns.Msg,
+ ri *agd.RequestInfo,
+ laddr netip.AddrPort,
+) (err error) {
+ return ds.OnSetDevice(ctx, req, ri, laddr)
+}
diff --git a/internal/dnssvc/internal/initial/deviceid.go b/internal/dnssvc/internal/initial/deviceid.go
deleted file mode 100644
index c4e4c0c..0000000
--- a/internal/dnssvc/internal/initial/deviceid.go
+++ /dev/null
@@ -1,208 +0,0 @@
-package initial
-
-import (
- "context"
- "fmt"
- "net/url"
- "path"
- "strings"
-
- "github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
- "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
- "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
- "github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/netutil"
- "github.com/miekg/dns"
-)
-
-// deviceIDFromClientServerName extracts and validates a device ID. cliSrvName
-// is the server name as sent by the client. wildcards are the domain wildcards
-// for device ID detection.
-func deviceIDFromClientServerName(
- cliSrvName string,
- wildcards []string,
-) (id agd.DeviceID, err error) {
- if cliSrvName == "" {
- // No server name in ClientHello, so the request is probably made on the
- // IP address.
- return "", nil
- }
-
- matchedDomain := ""
- for _, wildcard := range wildcards {
- // Assume that wildcards have been validated for this prefix in the
- // configuration parsing.
- domain := wildcard[len("*."):]
- matched := netutil.IsImmediateSubdomain(cliSrvName, domain)
- if matched {
- matchedDomain = domain
-
- break
- }
- }
-
- if matchedDomain == "" {
- return "", nil
- }
-
- optlog.Debug2("device id check: matched %q from %q", matchedDomain, wildcards)
-
- idStr := cliSrvName[:len(cliSrvName)-len(matchedDomain)-1]
- id, err = agd.NewDeviceID(idStr)
- if err != nil {
- // Don't wrap the error, because it's informative enough as is.
- return "", err
- }
-
- return id, nil
-}
-
-// deviceIDFromDoHURL extracts the device ID from the path of the client's
-// DNS-over-HTTPS request.
-func deviceIDFromDoHURL(u *url.URL) (id agd.DeviceID, err error) {
- origPath := u.Path
- parts := strings.Split(path.Clean(origPath), "/")
- if parts[0] == "" {
- parts = parts[1:]
- }
-
- if parts[0] == "" ||
- !strings.HasSuffix(dnsserver.PathDoH, parts[0]) &&
- !strings.HasSuffix(dnsserver.PathJSON, parts[0]) {
- return "", fmt.Errorf("bad path %q", u.Path)
- }
-
- switch len(parts) {
- case 1:
- // Just /dns-query, no device ID.
- return "", nil
- case 2:
- id, err = agd.NewDeviceID(parts[1])
- if err != nil {
- // Don't wrap the error, because it's informative enough as is.
- return "", err
- }
- default:
- return "", fmt.Errorf("bad path %q: extra parts", u.Path)
- }
-
- return id, nil
-}
-
-// deviceIDError is an error about a bad device ID or other issues found during
-// device ID checking.
-type deviceIDError struct {
- err error
- typ string
-}
-
-// type check
-var _ error = (*deviceIDError)(nil)
-
-// Error implements the error interface for *deviceIDError.
-func (err *deviceIDError) Error() (msg string) {
- return fmt.Sprintf("%s device id check: %s", err.typ, err.err)
-}
-
-// type check
-var _ errors.Wrapper = (*deviceIDError)(nil)
-
-// Unwrap implements the errors.Wrapper interface for *deviceIDError.
-func (err *deviceIDError) Unwrap() (unwrapped error) { return err.err }
-
-// type check
-var _ errcoll.SentryReportableError = (*deviceIDError)(nil)
-
-// IsSentryReportable implements the errcoll.SentryReportableError interface for
-// *deviceIDError.
-func (err *deviceIDError) IsSentryReportable() (ok bool) { return false }
-
-// deviceIDFromContext extracts the device from the server name of the TLS
-// client's DoH, DoT, or DoQ request, using the provided domain name wildcards,
-// and also from the DoH request, using the path of the HTTP URL. If the
-// protocol is not one of these, id is an empty string and err is nil.
-//
-// Any returned errors will have the underlying type of *deviceIDError.
-func deviceIDFromContext(
- ctx context.Context,
- proto agd.Protocol,
- wildcards []string,
-) (id agd.DeviceID, err error) {
- ri := dnsserver.MustRequestInfoFromContext(ctx)
-
- if proto == agd.ProtoDoH {
- id, err = deviceIDFromDoHURL(ri.URL)
- if err != nil {
- return "", &deviceIDError{
- err: err,
- typ: "http url",
- }
- } else if id != "" {
- return id, nil
- }
-
- // Go on and check the domain name as well.
- } else if proto != agd.ProtoDoT && proto != agd.ProtoDoQ {
- return "", nil
- }
-
- if len(wildcards) == 0 {
- return "", nil
- }
-
- cliSrvName := ri.TLSServerName
- id, err = deviceIDFromClientServerName(cliSrvName, wildcards)
- if err != nil {
- return "", &deviceIDError{
- err: err,
- typ: "tls server name",
- }
- }
-
- return id, nil
-}
-
-// dnsmasqCPEIDOption is the identifier of dnsmasq EDNS0 option
-// `EDNS0_OPTION_NOMCPEID`.
-//
-// See: https://github.com/PowerDNS/dnsmasq/blob/master/src/dns-protocol.h.
-const dnsmasqCPEIDOption uint16 = 65074
-
-// deviceIDFromEDNS extracts the device ID from EDNS0 option of plain DNS
-// request. This method works with dnsmasq option `--add-cpe-id`, which adds
-// an identifying string to DNS queries through [dnsmasqCPEIDOption] option as
-// a non-standard support of Nominum servers.
-//
-// Requests of this kind could be emulated with `+ednsopt` option of `dig`
-// utility.
-// TODO(a.garipov): Add test documentation.
-func deviceIDFromEDNS(req *dns.Msg) (id agd.DeviceID, err error) {
- option := req.IsEdns0()
- if option == nil {
- return "", nil
- }
-
- for _, opt := range option.Option {
- if opt.Option() != dnsmasqCPEIDOption {
- continue
- }
-
- o, ok := opt.(*dns.EDNS0_LOCAL)
- if !ok {
- continue
- }
-
- id, err = agd.NewDeviceID(string(o.Data))
- if err != nil {
- return "", &deviceIDError{
- err: err,
- typ: "edns option",
- }
- }
-
- return id, nil
- }
-
- return "", nil
-}
diff --git a/internal/dnssvc/internal/initial/deviceid_internal_test.go b/internal/dnssvc/internal/initial/deviceid_internal_test.go
deleted file mode 100644
index c26eb32..0000000
--- a/internal/dnssvc/internal/initial/deviceid_internal_test.go
+++ /dev/null
@@ -1,270 +0,0 @@
-package initial
-
-import (
- "context"
- "net/url"
- "testing"
-
- "github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
- "github.com/AdguardTeam/golibs/testutil"
- "github.com/miekg/dns"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestDeviceIDFromContext(t *testing.T) {
- testCases := []struct {
- name string
- cliSrvName string
- wantDeviceID agd.DeviceID
- wantErrMsg string
- wildcards []string
- proto agd.Protocol
- }{{
- name: "dns",
- cliSrvName: "",
- wantDeviceID: "",
- wantErrMsg: "",
- wildcards: nil,
- proto: agd.ProtoDNS,
- }, {
- name: "tls_no_device_id",
- cliSrvName: "dns.example.com",
- wantDeviceID: "",
- wantErrMsg: "",
- wildcards: []string{"*.dns.example.com"},
- proto: agd.ProtoDoT,
- }, {
- name: "tls_no_client_server_name",
- cliSrvName: "",
- wantDeviceID: "",
- wantErrMsg: "",
- wildcards: []string{"*.dns.example.com"},
- proto: agd.ProtoDoT,
- }, {
- name: "tls_device_id",
- cliSrvName: dnssvctest.DeviceIDStr + ".dns.example.com",
- wantDeviceID: dnssvctest.DeviceID,
- wantErrMsg: "",
- wildcards: []string{"*.dns.example.com"},
- proto: agd.ProtoDoT,
- }, {
- name: "tls_bad_device_id",
- cliSrvName: "!!!.dns.example.com",
- wantDeviceID: "",
- wantErrMsg: `tls server name device id check: bad device id "!!!": ` +
- `bad hostname label rune '!'`,
- wildcards: []string{"*.dns.example.com"},
- proto: agd.ProtoDoT,
- }, {
- name: "tls_deep_subdomain",
- cliSrvName: "abc." + dnssvctest.DeviceIDStr + ".dns.example.com",
- wantDeviceID: "",
- wantErrMsg: "",
- wildcards: []string{"*.dns.example.com"},
- proto: agd.ProtoDoT,
- }, {
- name: "tls_device_id_too_long",
- cliSrvName: `abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmno` +
- `pqrstuvwxyz0123456789.dns.example.com`,
- wantDeviceID: "",
- wantErrMsg: `tls server name device id check: bad device id ` +
- `"abcdefghijklmnopqrstuvwxyz0123456789` +
- `abcdefghijklmnopqrstuvwxyz0123456789": ` +
- `too long: got 72 bytes, max 8`,
- wildcards: []string{"*.dns.example.com"},
- proto: agd.ProtoDoT,
- }, {
- name: "quic_device_id",
- cliSrvName: dnssvctest.DeviceIDStr + ".dns.example.com",
- wantDeviceID: dnssvctest.DeviceID,
- wantErrMsg: "",
- wildcards: []string{"*.dns.example.com"},
- proto: agd.ProtoDoQ,
- }, {
- name: "tls_device_id_suffix",
- cliSrvName: "dev.mydns.example.com",
- wantDeviceID: "",
- wantErrMsg: "",
- wildcards: []string{"*.dns.example.com"},
- proto: agd.ProtoDoT,
- }, {
- name: "tls_device_id_subdomain_wildcard",
- cliSrvName: dnssvctest.DeviceIDStr + ".sub.dns.example.com",
- wantDeviceID: dnssvctest.DeviceID,
- wantErrMsg: "",
- wildcards: []string{
- "*.dns.example.com",
- "*.sub.dns.example.com",
- },
- proto: agd.ProtoDoT,
- }}
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- ctx := context.Background()
- ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{
- TLSServerName: tc.cliSrvName,
- })
-
- deviceID, err := deviceIDFromContext(ctx, tc.proto, tc.wildcards)
- assert.Equal(t, tc.wantDeviceID, deviceID)
- testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
- })
- }
-}
-
-func TestDeviceIDFromContext_https(t *testing.T) {
- testCases := []struct {
- name string
- path string
- wantDeviceID agd.DeviceID
- wantErrMsg string
- }{{
- name: "no_device_id",
- path: "/dns-query",
- wantDeviceID: "",
- wantErrMsg: "",
- }, {
- name: "no_device_id_slash",
- path: "/dns-query/",
- wantDeviceID: "",
- wantErrMsg: "",
- }, {
- name: "device_id",
- path: "/dns-query/" + dnssvctest.DeviceIDStr,
- wantDeviceID: dnssvctest.DeviceID,
- wantErrMsg: "",
- }, {
- name: "device_id_slash",
- path: "/dns-query/" + dnssvctest.DeviceIDStr + "/",
- wantDeviceID: dnssvctest.DeviceID,
- wantErrMsg: "",
- }, {
- name: "bad_url",
- path: "/foo",
- wantDeviceID: "",
- wantErrMsg: `http url device id check: bad path "/foo"`,
- }, {
- name: "extra",
- path: "/dns-query/" + dnssvctest.DeviceIDStr + "/foo",
- wantDeviceID: "",
- wantErrMsg: `http url device id check: bad path "/dns-query/` + dnssvctest.DeviceIDStr +
- `/foo": extra parts`,
- }, {
- name: "bad_device_id",
- path: "/dns-query/!!!",
- wantDeviceID: "",
- wantErrMsg: `http url device id check: bad device id "!!!": ` +
- `bad hostname label rune '!'`,
- }}
-
- const proto = agd.ProtoDoH
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- u := &url.URL{
- Scheme: "https",
- Host: "dns.example.com",
- Path: tc.path,
- }
-
- ctx := context.Background()
- ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{
- URL: u,
- })
-
- deviceID, err := deviceIDFromContext(ctx, proto, nil)
- assert.Equal(t, tc.wantDeviceID, deviceID)
- testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
- })
- }
-
- t.Run("domain_name", func(t *testing.T) {
- u := &url.URL{
- Scheme: "https",
- Host: dnssvctest.DeviceIDStr + ".dns.example.com",
- Path: "/dns-query",
- }
-
- ctx := context.Background()
- ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{
- URL: u,
- TLSServerName: u.Host,
- })
-
- deviceID, err := deviceIDFromContext(ctx, proto, []string{"*.dns.example.com"})
- require.NoError(t, err)
-
- assert.Equal(t, agd.DeviceID(dnssvctest.DeviceID), deviceID)
- })
-}
-
-func TestDeviceIDFromEDNS(t *testing.T) {
- testCases := []struct {
- name string
- opt dns.EDNS0
- wantDeviceID agd.DeviceID
- wantErrMsg string
- }{{
- name: "no_device_id",
- wantDeviceID: "",
- wantErrMsg: "",
- }, {
- name: "wrong_edns",
- opt: &dns.EDNS0_LOCAL{
- Code: dnsmasqCPEIDOption - 1,
- Data: []byte("devid"),
- },
- wantDeviceID: "",
- wantErrMsg: "",
- }, {
- name: "no_device_id",
- opt: &dns.EDNS0_LOCAL{
- Code: dnsmasqCPEIDOption,
- Data: []byte{},
- },
- wantDeviceID: "",
- wantErrMsg: `edns option device id check: bad device id "": ` +
- `too short: got 0 bytes, min 1`,
- }, {
- name: "bad_device_id",
- opt: &dns.EDNS0_LOCAL{
- Code: dnsmasqCPEIDOption,
- Data: []byte("toolongdeviceid"),
- },
- wantDeviceID: "",
- wantErrMsg: `edns option device id check: bad device id "toolongdeviceid": ` +
- `too long: got 15 bytes, max 8`,
- }, {
- name: "device_id",
- opt: &dns.EDNS0_LOCAL{
- Code: dnsmasqCPEIDOption,
- Data: []byte("devid"),
- },
- wantDeviceID: "devid",
- wantErrMsg: "",
- }}
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- msg := dnsservertest.NewReq("example.com.", dns.TypeA, dns.ClassINET)
- if tc.opt != nil {
- msg.SetEdns0(dnsmsg.DefaultEDNSUDPSize, true)
- extra := &dns.OPT{
- Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeOPT},
- Option: []dns.EDNS0{tc.opt},
- }
- msg.Extra = append(msg.Extra, extra)
- }
-
- deviceID, err := deviceIDFromEDNS(msg)
- assert.Equal(t, tc.wantDeviceID, deviceID)
- testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
- })
- }
-}
diff --git a/internal/dnssvc/internal/initial/initial.go b/internal/dnssvc/internal/initial/initial.go
index a77bd28..381bace 100644
--- a/internal/dnssvc/internal/initial/initial.go
+++ b/internal/dnssvc/internal/initial/initial.go
@@ -16,11 +16,11 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicesetter"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/AdGuardDNS/internal/optlog"
- "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/syncutil"
@@ -47,18 +47,14 @@ type Middleware struct {
// pool is the pool of [agd.RequestInfo] values.
pool *syncutil.Pool[agd.RequestInfo]
- // db is the database of user profiles and devices.
- db profiledb.Interface
+ // deviceSetter is used to set the device and profile for a request, if any.
+ deviceSetter devicesetter.Interface
// geoIP detects the location of the request source.
geoIP geoip.Interface
// errColl collects and reports the errors considered non-critical.
errColl errcoll.Interface
-
- // profilesEnabled is true, if user devices and profiles recognition is
- // enabled.
- profilesEnabled bool
}
// Config is the configuration structure for the initial middleware. All fields
@@ -76,21 +72,18 @@ type Config struct {
// Server is the current server which serves the request.
Server *agd.Server
- // DB is the database of user profiles and devices.
- ProfileDB profiledb.Interface
+ // DeviceSetter is used to set the device and profile for a request, if any.
+ DeviceSetter devicesetter.Interface
// GeoIP detects the location of the request source.
GeoIP geoip.Interface
// ErrColl collects and reports the errors considered non-critical.
ErrColl errcoll.Interface
-
- // ProfileDBEnabled is true, if user devices and profiles recognition is
- // enabled.
- ProfileDBEnabled bool
}
-// New returns a new initial middleware. c must not be nil.
+// New returns a new initial middleware. c must not be nil, and all its fields
+// must be valid.
func New(c *Config) (mw *Middleware) {
return &Middleware{
messages: c.Messages,
@@ -100,10 +93,9 @@ func New(c *Config) (mw *Middleware) {
pool: syncutil.NewPool(func() (v *agd.RequestInfo) {
return &agd.RequestInfo{}
}),
- db: c.ProfileDB,
- geoIP: c.GeoIP,
- errColl: c.ErrColl,
- profilesEnabled: c.ProfileDBEnabled,
+ deviceSetter: c.DeviceSetter,
+ geoIP: c.GeoIP,
+ errColl: c.ErrColl,
}
}
@@ -184,8 +176,8 @@ func (mw *Middleware) Wrap(next dnsserver.Handler) (wrapped dnsserver.Handler) {
func (mw *Middleware) newRequestInfo(
ctx context.Context,
req *dns.Msg,
- lAddr net.Addr,
- rAddr netip.AddrPort,
+ laddr net.Addr,
+ raddr netip.AddrPort,
) (ri *agd.RequestInfo, err error) {
ri = mw.pool.Get()
@@ -205,9 +197,10 @@ func (mw *Middleware) newRequestInfo(
// Put the host, server, and client IP data into the request information
// immediately.
+ remoteIP := raddr.Addr()
ri.FilteringGroup = mw.fltGrp
ri.Messages = mw.messages
- ri.RemoteIP = rAddr.Addr()
+ ri.RemoteIP = remoteIP
ri.ServerGroup = mw.srvGrp.Name
ri.Server = mw.srv.Name
ri.Proto = mw.srv.Protocol
@@ -224,69 +217,22 @@ func (mw *Middleware) newRequestInfo(
ri.ID, _ = agd.RequestIDFromContext(ctx)
// Add the GeoIP information, if any.
- err = mw.addLocation(ctx, ri, req)
+ err = mw.addLocation(ctx, req, ri)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return nil, err
}
- if !mw.profilesEnabled {
- return ri, nil
- }
-
// Add the profile information, if any.
- localAddr := netutil.NetAddrToAddrPort(lAddr)
- err = mw.addProfile(ctx, ri, req, localAddr)
+ localAddr := netutil.NetAddrToAddrPort(laddr)
+ err = mw.deviceSetter.SetDevice(ctx, req, ri, localAddr)
if err != nil {
- // Don't wrap the error, because it's informative enough as is.
- return nil, err
+ return nil, fmt.Errorf("getting device from req: %w", err)
}
return ri, nil
}
-// addLocation adds GeoIP location information about the client's remote address
-// as well as the EDNS Client Subnet information, if there is one, to ri. err
-// is not nil only if req contains a malformed EDNS Client Subnet option.
-func (mw *Middleware) addLocation(ctx context.Context, ri *agd.RequestInfo, req *dns.Msg) (err error) {
- ri.Location = mw.locationData(ctx, ri.RemoteIP, "client")
-
- ecs, scope, err := dnsmsg.ECSFromMsg(req)
- if err != nil {
- return fmt.Errorf("adding ecs info: %w", err)
- } else if ecs != (netip.Prefix{}) {
- ri.ECS = &agd.ECS{
- Location: mw.locationData(ctx, ecs.Addr(), "ecs"),
- Subnet: ecs,
- Scope: scope,
- }
- }
-
- return nil
-}
-
-// locationData returns the GeoIP location information about the IP address.
-// typ is the type of data being requested for error reporting and logging.
-func (mw *Middleware) locationData(
- ctx context.Context,
- ip netip.Addr,
- typ string,
-) (l *geoip.Location) {
- l, err := mw.geoIP.Data("", ip)
- if err != nil {
- // Consider GeoIP errors non-critical. Report and go on.
- errcoll.Collectf(ctx, mw.errColl, "init mw: getting geoip for %s ip: %w", typ, err)
- }
-
- if l == nil {
- optlog.Debug2("init mw: no geoip for %s ip %s", typ, ip)
- } else {
- optlog.Debug4("init mw: found country/asn %q/%d for %s ip %s", l.Country, l.ASN, typ, ip)
- }
-
- return l
-}
-
// processReqInfoErr processes the error returned by [Middleware.newRequestInfo]
// and returns the properly handled and/or wrapped error.
func (mw *Middleware) processReqInfoErr(
@@ -295,7 +241,7 @@ func (mw *Middleware) processReqInfoErr(
req *dns.Msg,
origErr error,
) (err error) {
- if errors.Is(origErr, errUnknownDedicated) {
+ if errors.Is(origErr, devicesetter.ErrUnknownDedicated) {
metrics.DNSSvcUnknownDedicatedTotal.Inc()
// The request is dropped by the profile search. Don't write anything
diff --git a/internal/dnssvc/internal/initial/initial_test.go b/internal/dnssvc/internal/initial/initial_test.go
index 64eb731..ff52448 100644
--- a/internal/dnssvc/internal/initial/initial_test.go
+++ b/internal/dnssvc/internal/initial/initial_test.go
@@ -8,16 +8,16 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/initial"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
- "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
+ "github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
- "github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
@@ -41,7 +41,13 @@ const (
)
func TestMiddleware_Wrap(t *testing.T) {
- testDevice := &agd.Device{ID: dnssvctest.DeviceID}
+ testDevice := &agd.Device{
+ Auth: &agd.AuthSettings{
+ Enabled: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ },
+ ID: dnssvctest.DeviceID,
+ }
geoIP := &agdtest.GeoIP{
OnSubnetByLocation: func(
@@ -56,7 +62,7 @@ func TestMiddleware_Wrap(t *testing.T) {
}
srvs := newServers()
- // TODO(a.garipov): Use stdlib's maps in Go 1.22 or later.
+ // TODO(a.garipov): Use stdlib's maps in Go 1.23 or later.
srvGrp := newServerGroup(maps.Values(srvs))
var handler dnsserver.Handler = dnsserver.HandlerFunc(func(
@@ -100,22 +106,6 @@ func TestMiddleware_Wrap(t *testing.T) {
wantTarget: resolverFQDN,
wantNum: len(srvGrp.DDR.PublicRecordTemplates),
qtype: dns.TypeSVCB,
- }, {
- device: testDevice,
- name: "linked_ip",
- srv: srvs["dns"],
- host: ddrFQDN,
- wantTarget: targetWithID,
- wantNum: len(srvGrp.DDR.PublicRecordTemplates),
- qtype: dns.TypeSVCB,
- }, {
- device: testDevice,
- name: "no_linked_ip",
- srv: srvs["dns_nolink"],
- host: ddrFQDN,
- wantTarget: resolverFQDN,
- wantNum: len(srvGrp.DDR.PublicRecordTemplates),
- qtype: dns.TypeSVCB,
}, {
device: testDevice,
name: "public_resolver_name",
@@ -150,24 +140,17 @@ func TestMiddleware_Wrap(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- db := &agdtest.ProfileDB{
- OnProfileByDeviceID: func(
+ ds := &dnssvctest.DeviceSetter{
+ OnSetDevice: func(
_ context.Context,
- _ agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return prof, tc.device, nil
- },
- OnProfileByDedicatedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return nil, nil, profiledb.ErrDeviceNotFound
- },
- OnProfileByLinkedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return prof, tc.device, nil
+ _ *dns.Msg,
+ ri *agd.RequestInfo,
+ _ netip.AddrPort,
+ ) (err error) {
+ ri.Device = tc.device
+ ri.Profile = prof
+
+ return nil
},
}
@@ -176,16 +159,14 @@ func TestMiddleware_Wrap(t *testing.T) {
FilteringGroup: &agd.FilteringGroup{},
ServerGroup: srvGrp,
Server: tc.srv,
- ProfileDB: db,
+ DeviceSetter: ds,
GeoIP: geoIP,
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
- ProfileDBEnabled: true,
})
- ctx := context.Background()
- ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{
+ ctx := dnsserver.ContextWithRequestInfo(context.Background(), &dnsserver.RequestInfo{
TLSServerName: srvNameForProto(tc.device, resolverName, tc.srv.Protocol),
})
@@ -212,11 +193,11 @@ func TestMiddleware_Wrap(t *testing.T) {
}
assert.Len(t, resp.Answer, tc.wantNum)
- for _, rr := range resp.Answer {
+ for i, rr := range resp.Answer {
svcb := testutil.RequireTypeAssert[*dns.SVCB](t, rr)
- assert.Equal(t, tc.wantTarget, svcb.Target)
- assert.Equal(t, tc.host, svcb.Hdr.Name)
+ assert.Equalf(t, tc.wantTarget, svcb.Target, "rr at index %d", i)
+ assert.Equalf(t, tc.host, svcb.Hdr.Name, "rr at index %d", i)
}
})
}
@@ -271,24 +252,14 @@ func TestMiddleware_Wrap_error(t *testing.T) {
const testError errors.Error = errors.Error("test error")
- db := &agdtest.ProfileDB{
- OnProfileByDeviceID: func(
+ ds := &dnssvctest.DeviceSetter{
+ OnSetDevice: func(
_ context.Context,
- _ agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
- OnProfileByDedicatedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
- OnProfileByLinkedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return nil, nil, testError
+ _ *dns.Msg,
+ ri *agd.RequestInfo,
+ _ netip.AddrPort,
+ ) (err error) {
+ return testError
},
}
@@ -297,15 +268,16 @@ func TestMiddleware_Wrap_error(t *testing.T) {
FilteringGroup: &agd.FilteringGroup{},
ServerGroup: srvGrp,
Server: srv,
- ProfileDB: db,
+ DeviceSetter: ds,
GeoIP: geoIP,
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
- ProfileDBEnabled: true,
})
ctx := context.Background()
+ ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{})
+
rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.RemoteAddr)
req := &dns.Msg{
Question: []dns.Question{{
@@ -326,10 +298,16 @@ func TestMiddleware_Wrap_access(t *testing.T) {
passIP := net.IP{3, 3, 3, 3}
srvs := newServers()
- // TODO(a.garipov): Use stdlib's maps in Go 1.22 or later.
+ // TODO(a.garipov): Use stdlib's maps in Go 1.23 or later.
srvGrp := newServerGroup(maps.Values(srvs))
- testDevice := &agd.Device{ID: dnssvctest.DeviceID}
+ testDevice := &agd.Device{
+ Auth: &agd.AuthSettings{
+ Enabled: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ },
+ ID: dnssvctest.DeviceID,
+ }
testProfile := &agd.Profile{
Access: access.NewDefaultProfile(&access.ProfileConfig{
AllowedNets: []netip.Prefix{netip.MustParsePrefix("1.1.1.1/32")},
@@ -346,24 +324,17 @@ func TestMiddleware_Wrap_access(t *testing.T) {
}),
}
- db := &agdtest.ProfileDB{
- OnProfileByDeviceID: func(
+ ds := &dnssvctest.DeviceSetter{
+ OnSetDevice: func(
_ context.Context,
- _ agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return testProfile, testDevice, nil
- },
- OnProfileByDedicatedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return nil, nil, profiledb.ErrDeviceNotFound
- },
- OnProfileByLinkedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return nil, nil, profiledb.ErrDeviceNotFound
+ _ *dns.Msg,
+ ri *agd.RequestInfo,
+ _ netip.AddrPort,
+ ) (err error) {
+ ri.Device = testDevice
+ ri.Profile = testProfile
+
+ return nil
},
}
@@ -514,12 +485,11 @@ func TestMiddleware_Wrap_access(t *testing.T) {
FilteringGroup: &agd.FilteringGroup{},
ServerGroup: srvGrp,
Server: srvs["dot"],
- ProfileDB: db,
+ DeviceSetter: ds,
GeoIP: geoIP,
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
- ProfileDBEnabled: true,
})
ctx := context.Background()
@@ -568,10 +538,9 @@ func newServers() (srvs map[agd.ServerName]*agd.Server) {
func newServerGroup(srvs []*agd.Server) (srvGrp *agd.ServerGroup) {
srvGrp = &agd.ServerGroup{
- BlockPageRedirect: &agd.BlockPageRedirect{},
DDR: &agd.DDR{
- DeviceTargets: stringutil.NewSet(),
- PublicTargets: stringutil.NewSet(),
+ DeviceTargets: container.NewMapSet[string](),
+ PublicTargets: container.NewMapSet[string](),
Enabled: true,
},
TLS: &agd.TLS{
@@ -609,10 +578,9 @@ var errSink error
func BenchmarkMiddleware_Wrap(b *testing.B) {
const devIDTarget = "dns.example.com"
srvGrp := &agd.ServerGroup{
- BlockPageRedirect: &agd.BlockPageRedirect{},
DDR: &agd.DDR{
- DeviceTargets: stringutil.NewSet(),
- PublicTargets: stringutil.NewSet(),
+ DeviceTargets: container.NewMapSet[string](),
+ PublicTargets: container.NewMapSet[string](),
Enabled: true,
},
TLS: &agd.TLS{
@@ -655,7 +623,12 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
prof := &agd.Profile{
Access: access.EmptyProfile{},
}
- dev := &agd.Device{}
+ dev := &agd.Device{
+ Auth: &agd.AuthSettings{
+ Enabled: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ },
+ }
ctx := context.Background()
ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{
@@ -682,24 +655,17 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.RemoteAddr)
b.Run("success", func(b *testing.B) {
- db := &agdtest.ProfileDB{
- OnProfileByDeviceID: func(
+ ds := &dnssvctest.DeviceSetter{
+ OnSetDevice: func(
_ context.Context,
- _ agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return prof, dev, nil
- },
- OnProfileByDedicatedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
- OnProfileByLinkedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
+ _ *dns.Msg,
+ ri *agd.RequestInfo,
+ _ netip.AddrPort,
+ ) (err error) {
+ ri.Device = dev
+ ri.Profile = prof
+
+ return nil
},
}
@@ -708,19 +674,18 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
FilteringGroup: &agd.FilteringGroup{},
ServerGroup: srvGrp,
Server: srvGrp.Servers[0],
- ProfileDB: db,
+ DeviceSetter: ds,
GeoIP: geoIP,
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
- ProfileDBEnabled: true,
})
h := mw.Wrap(handler)
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
errSink = h.ServeDNS(ctx, rw, req)
}
@@ -728,24 +693,14 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
})
b.Run("not_found", func(b *testing.B) {
- db := &agdtest.ProfileDB{
- OnProfileByDeviceID: func(
+ ds := &dnssvctest.DeviceSetter{
+ OnSetDevice: func(
_ context.Context,
- _ agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return nil, nil, profiledb.ErrDeviceNotFound
- },
- OnProfileByDedicatedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
- OnProfileByLinkedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
+ _ *dns.Msg,
+ ri *agd.RequestInfo,
+ _ netip.AddrPort,
+ ) (err error) {
+ return nil
},
}
@@ -754,19 +709,18 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
FilteringGroup: &agd.FilteringGroup{},
ServerGroup: srvGrp,
Server: srvGrp.Servers[0],
- ProfileDB: db,
+ DeviceSetter: ds,
GeoIP: geoIP,
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
- ProfileDBEnabled: true,
})
h := mw.Wrap(handler)
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
errSink = h.ServeDNS(ctx, rw, req)
}
@@ -774,24 +728,17 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
})
b.Run("firefox_canary", func(b *testing.B) {
- db := &agdtest.ProfileDB{
- OnProfileByDeviceID: func(
+ ds := &dnssvctest.DeviceSetter{
+ OnSetDevice: func(
_ context.Context,
- _ agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return prof, dev, nil
- },
- OnProfileByDedicatedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
- OnProfileByLinkedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
+ _ *dns.Msg,
+ ri *agd.RequestInfo,
+ _ netip.AddrPort,
+ ) (err error) {
+ ri.Device = dev
+ ri.Profile = prof
+
+ return nil
},
}
@@ -808,19 +755,18 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
FilteringGroup: &agd.FilteringGroup{},
ServerGroup: srvGrp,
Server: srvGrp.Servers[0],
- ProfileDB: db,
+ DeviceSetter: ds,
GeoIP: geoIP,
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
- ProfileDBEnabled: true,
})
h := mw.Wrap(handler)
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
errSink = h.ServeDNS(ctx, rw, ffReq)
}
@@ -829,27 +775,24 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
b.Run("ddr", func(b *testing.B) {
devWithID := &agd.Device{
+ Auth: &agd.AuthSettings{
+ Enabled: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ },
ID: dnssvctest.DeviceID,
}
- db := &agdtest.ProfileDB{
- OnProfileByDeviceID: func(
+ ds := &dnssvctest.DeviceSetter{
+ OnSetDevice: func(
_ context.Context,
- _ agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return prof, devWithID, nil
- },
- OnProfileByDedicatedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
- OnProfileByLinkedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
+ _ *dns.Msg,
+ ri *agd.RequestInfo,
+ _ netip.AddrPort,
+ ) (err error) {
+ ri.Device = devWithID
+ ri.Profile = prof
+
+ return nil
},
}
@@ -867,19 +810,18 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
FilteringGroup: &agd.FilteringGroup{},
ServerGroup: srvGrp,
Server: srvGrp.Servers[0],
- ProfileDB: db,
+ DeviceSetter: ds,
GeoIP: geoIP,
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
- ProfileDBEnabled: true,
})
h := mw.Wrap(handler)
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
errSink = h.ServeDNS(ctx, rw, ddrReq)
}
@@ -891,8 +833,8 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
// goarch: amd64
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/initial
// cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
- // BenchmarkMiddleware_Wrap/success-16 1929643 659.7 ns/op 72 B/op 2 allocs/op
- // BenchmarkMiddleware_Wrap/not_found-16 2377362 587.3 ns/op 48 B/op 1 allocs/op
- // BenchmarkMiddleware_Wrap/firefox_canary-16 1663753 757.4 ns/op 72 B/op 2 allocs/op
- // BenchmarkMiddleware_Wrap/ddr-16 280981 4431 ns/op 1408 B/op 45 allocs/op
+ // BenchmarkMiddleware_Wrap/success-16 2837168 489.8 ns/op 48 B/op 1 allocs/op
+ // BenchmarkMiddleware_Wrap/not_found-16 2583918 420.7 ns/op 48 B/op 1 allocs/op
+ // BenchmarkMiddleware_Wrap/firefox_canary-16 2658222 505.1 ns/op 48 B/op 1 allocs/op
+ // BenchmarkMiddleware_Wrap/ddr-16 302330 4949 ns/op 1384 B/op 44 allocs/op
}
diff --git a/internal/dnssvc/internal/initial/location.go b/internal/dnssvc/internal/initial/location.go
new file mode 100644
index 0000000..1a00f1e
--- /dev/null
+++ b/internal/dnssvc/internal/initial/location.go
@@ -0,0 +1,60 @@
+package initial
+
+import (
+ "context"
+ "fmt"
+ "net/netip"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
+ "github.com/miekg/dns"
+)
+
+// addLocation adds GeoIP location information about the client's remote address
+// as well as the EDNS Client Subnet information, if there is one, to ri. err
+// is not nil only if req contains a malformed EDNS Client Subnet option.
+func (mw *Middleware) addLocation(
+ ctx context.Context,
+ req *dns.Msg,
+ ri *agd.RequestInfo,
+) (err error) {
+ ri.Location = mw.locationData(ctx, ri.RemoteIP, "client")
+
+ ecs, scope, err := dnsmsg.ECSFromMsg(req)
+ if err != nil {
+ return fmt.Errorf("adding ecs info: %w", err)
+ } else if ecs != (netip.Prefix{}) {
+ ri.ECS = &agd.ECS{
+ Location: mw.locationData(ctx, ecs.Addr(), "ecs"),
+ Subnet: ecs,
+ Scope: scope,
+ }
+ }
+
+ return nil
+}
+
+// locationData returns the GeoIP location information about the IP address.
+// typ is the type of data being requested for error reporting and logging.
+func (mw *Middleware) locationData(
+ ctx context.Context,
+ ip netip.Addr,
+ typ string,
+) (l *geoip.Location) {
+ l, err := mw.geoIP.Data("", ip)
+ if err != nil {
+ // Consider GeoIP errors non-critical. Report and go on.
+ errcoll.Collectf(ctx, mw.errColl, "init mw: getting geoip for %s ip: %w", typ, err)
+ }
+
+ if l == nil {
+ optlog.Debug2("init mw: no geoip for %s ip %s", typ, ip)
+ } else {
+ optlog.Debug4("init mw: found country/asn %q/%d for %s ip %s", l.Country, l.ASN, typ, ip)
+ }
+
+ return l
+}
diff --git a/internal/dnssvc/internal/initial/profile.go b/internal/dnssvc/internal/initial/profile.go
deleted file mode 100644
index 88d02d6..0000000
--- a/internal/dnssvc/internal/initial/profile.go
+++ /dev/null
@@ -1,131 +0,0 @@
-package initial
-
-import (
- "context"
- "fmt"
- "net/netip"
-
- "github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
- "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
- "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
- "github.com/AdguardTeam/golibs/errors"
- "github.com/miekg/dns"
-)
-
-// addProfile adds profile and device information, if any, to the request
-// information.
-func (mw *Middleware) addProfile(
- ctx context.Context,
- ri *agd.RequestInfo,
- req *dns.Msg,
- localAddr netip.AddrPort,
-) (err error) {
- defer func() { err = errors.Annotate(err, "getting profile from req: %w") }()
-
- var id agd.DeviceID
- if p := mw.srv.Protocol; p.IsStdEncrypted() {
- // Assume that mw.srvGrp.TLS is non-nil if p.IsStdEncrypted() is true.
- wildcards := mw.srvGrp.TLS.DeviceIDWildcards
- id, err = deviceIDFromContext(ctx, mw.srv.Protocol, wildcards)
- } else if p == agd.ProtoDNS {
- id, err = deviceIDFromEDNS(req)
- } else {
- // No DeviceID for DNSCrypt yet.
- return nil
- }
-
- if err != nil {
- return err
- }
-
- optlog.Debug3("init mw: got device id %q, raddr %s, and laddr %s", id, ri.RemoteIP, localAddr)
-
- prof, dev, byWhat, err := mw.profile(ctx, localAddr, ri.RemoteIP, id)
- if err != nil {
- if !errors.Is(err, profiledb.ErrDeviceNotFound) {
- // Very unlikely, since there is only one error type currently
- // returned from the default profile DB.
- return fmt.Errorf("unexpected profiledb error: %w", err)
- }
-
- optlog.Debug1("init mw: profile or device not found: %s", err)
- } else if prof.Deleted {
- optlog.Debug1("init mw: profile %s is deleted", prof.ID)
- } else {
- optlog.Debug3("init mw: found profile %s and device %s by %s", prof.ID, dev.ID, byWhat)
-
- ri.Device, ri.Profile = dev, prof
-
- // TODO(a.garipov): Consider using the global cloner here once it is
- // tested and optimized.
- ri.Messages = dnsmsg.NewConstructor(nil, prof.BlockingMode, prof.FilteredResponseTTL)
- }
-
- return nil
-}
-
-// Constants for the parameter by which a device has been found.
-const (
- byDeviceID = "device id"
- byDedicatedIP = "dedicated ip"
- byLinkedIP = "linked ip"
-)
-
-// errUnknownDedicated is returned by [Middleware.profile] if the request should
-// be dropped, because it's a request for an unknown dedicated IP address.
-const errUnknownDedicated errors.Error = "drop"
-
-// profile finds the profile by the client data.
-func (mw *Middleware) profile(
- ctx context.Context,
- localAddr netip.AddrPort,
- remoteIP netip.Addr,
- id agd.DeviceID,
-) (prof *agd.Profile, dev *agd.Device, byWhat string, err error) {
- if id != "" {
- prof, dev, err = mw.db.ProfileByDeviceID(ctx, id)
- if err != nil {
- return nil, nil, "", err
- }
-
- return prof, dev, byDeviceID, nil
- }
-
- if mw.srv.Protocol == agd.ProtoDNS {
- return mw.profileByAddrs(ctx, localAddr, remoteIP)
- }
-
- return nil, nil, "", profiledb.ErrDeviceNotFound
-}
-
-// profileByAddrs finds the profile by the remote and local addresses.
-func (mw *Middleware) profileByAddrs(
- ctx context.Context,
- localAddr netip.AddrPort,
- remoteIP netip.Addr,
-) (prof *agd.Profile, dev *agd.Device, byWhat string, err error) {
- if mw.srv.BindsToInterfaces() && !mw.srv.HasAddr(localAddr) {
- prof, dev, err = mw.db.ProfileByDedicatedIP(ctx, localAddr.Addr())
- if err == nil {
- return prof, dev, byDedicatedIP, nil
- } else if errors.Is(err, profiledb.ErrDeviceNotFound) {
- optlog.Debug1("init mw: unknown dedicated ip for server %s; dropping", mw.srv.Name)
-
- err = errUnknownDedicated
- }
-
- return nil, nil, "", err
- }
-
- if !mw.srv.LinkedIPEnabled {
- return nil, nil, "", profiledb.ErrDeviceNotFound
- }
-
- prof, dev, err = mw.db.ProfileByLinkedIP(ctx, remoteIP)
- if err != nil {
- return nil, nil, "", err
- }
-
- return prof, dev, byLinkedIP, nil
-}
diff --git a/internal/dnssvc/internal/initial/profile_internal_test.go b/internal/dnssvc/internal/initial/profile_internal_test.go
deleted file mode 100644
index 7417351..0000000
--- a/internal/dnssvc/internal/initial/profile_internal_test.go
+++ /dev/null
@@ -1,265 +0,0 @@
-package initial
-
-import (
- "context"
- "net/netip"
- "testing"
-
- "github.com/AdguardTeam/AdGuardDNS/internal/access"
- "github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
- "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
- "github.com/AdguardTeam/golibs/testutil"
- "github.com/stretchr/testify/assert"
-)
-
-// Bind data for tests.
-var (
- bindDataAddr = &agd.ServerBindData{
- AddrPort: netip.MustParseAddrPort("1.2.3.4:53"),
- }
-
- bindDataIface = &agd.ServerBindData{
- ListenConfig: &agdtest.ListenConfig{},
- PrefixAddr: &agdnet.PrefixNetAddr{
- Prefix: netip.MustParsePrefix("1.2.3.0/24"),
- Net: "",
- Port: 53,
- },
- }
-
- bindDataIfaceSingleIP = &agd.ServerBindData{
- ListenConfig: &agdtest.ListenConfig{},
- PrefixAddr: &agdnet.PrefixNetAddr{
- Prefix: netip.PrefixFrom(dnssvctest.ServerAddr, 32),
- Net: "",
- Port: dnssvctest.ServerAddrPort.Port(),
- },
- }
-)
-
-func TestMiddleware_profile(t *testing.T) {
- prof := &agd.Profile{
- Access: access.EmptyProfile{},
- ID: dnssvctest.ProfileID,
- DeviceIDs: []agd.DeviceID{
- dnssvctest.DeviceID,
- },
- }
-
- dev := &agd.Device{
- ID: dnssvctest.DeviceID,
- LinkedIP: dnssvctest.ClientAddr,
- DedicatedIPs: []netip.Addr{
- dnssvctest.ServerAddr,
- },
- }
-
- testCases := []struct {
- wantDev *agd.Device
- wantProf *agd.Profile
- wantByWhat string
- wantErrMsg string
- name string
- id agd.DeviceID
- proto agd.Protocol
- linkedIPEnabled bool
- }{{
- wantDev: nil,
- wantProf: nil,
- wantByWhat: "",
- wantErrMsg: "device not found",
- name: "no_device_id",
- id: "",
- proto: agd.ProtoDNS,
- linkedIPEnabled: true,
- }, {
- wantDev: dev,
- wantProf: prof,
- wantByWhat: byDeviceID,
- wantErrMsg: "",
- name: "device_id",
- id: dnssvctest.DeviceID,
- proto: agd.ProtoDNS,
- linkedIPEnabled: true,
- }, {
- wantDev: nil,
- wantProf: nil,
- wantByWhat: "",
- wantErrMsg: "device not found",
- name: "linked_ip_dot",
- id: "",
- proto: agd.ProtoDoT,
- linkedIPEnabled: true,
- }}
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- srv := dnssvctest.NewServer("test_server", tc.proto, bindDataAddr)
- srv.LinkedIPEnabled = tc.linkedIPEnabled
-
- mw := New(&Config{
- Server: srv,
- ProfileDB: newProfileDB(t, prof, dev, tc.wantByWhat),
- ProfileDBEnabled: true,
- })
-
- ctx := context.Background()
- gotProf, gotDev, gotByWhat, err := mw.profile(
- ctx,
- dnssvctest.ServerAddrPort,
- dnssvctest.ClientAddr,
- tc.id,
- )
- testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
- assert.Equal(t, tc.wantProf, gotProf)
- assert.Equal(t, tc.wantDev, gotDev)
- assert.Equal(t, tc.wantByWhat, gotByWhat)
- })
- }
-}
-
-func TestMiddleware_profileByAddrs(t *testing.T) {
- prof := &agd.Profile{
- Access: access.EmptyProfile{},
- ID: dnssvctest.ProfileID,
- DeviceIDs: []agd.DeviceID{
- dnssvctest.DeviceID,
- },
- }
-
- dev := &agd.Device{
- ID: dnssvctest.DeviceID,
- LinkedIP: dnssvctest.ClientAddr,
- DedicatedIPs: []netip.Addr{
- dnssvctest.ServerAddr,
- },
- }
-
- testCases := []struct {
- wantDev *agd.Device
- wantProf *agd.Profile
- wantByWhat string
- wantErrMsg string
- name string
- bindData []*agd.ServerBindData
- linkedIPEnabled bool
- }{{
- wantDev: dev,
- wantProf: prof,
- wantByWhat: byLinkedIP,
- wantErrMsg: "",
- name: "linked_ip",
- bindData: []*agd.ServerBindData{bindDataAddr},
- linkedIPEnabled: true,
- }, {
- wantDev: nil,
- wantProf: nil,
- wantByWhat: "",
- wantErrMsg: "device not found",
- name: "linked_ip_disabled",
- bindData: []*agd.ServerBindData{bindDataAddr},
- linkedIPEnabled: false,
- }, {
- wantDev: dev,
- wantProf: prof,
- wantByWhat: byDedicatedIP,
- wantErrMsg: "",
- name: "dedicated_ip",
- bindData: []*agd.ServerBindData{bindDataIface},
- linkedIPEnabled: true,
- }, {
- wantDev: nil,
- wantProf: nil,
- wantByWhat: "",
- wantErrMsg: "drop",
- name: "dedicated_ip_not_found",
- bindData: []*agd.ServerBindData{bindDataIface},
- linkedIPEnabled: true,
- }, {
- wantDev: nil,
- wantProf: nil,
- wantByWhat: "",
- wantErrMsg: "device not found",
- name: "dedicated_ip_and_single_ip",
- bindData: []*agd.ServerBindData{
- bindDataIface,
- bindDataIfaceSingleIP,
- },
- linkedIPEnabled: true,
- }}
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- srv := dnssvctest.NewServer("test_server", agd.ProtoDNS, tc.bindData...)
- srv.LinkedIPEnabled = tc.linkedIPEnabled
-
- mw := New(&Config{
- Server: srv,
- ProfileDB: newProfileDB(t, prof, dev, tc.wantByWhat),
- ProfileDBEnabled: true,
- })
-
- ctx := context.Background()
- gotProf, gotDev, gotByWhat, err := mw.profileByAddrs(
- ctx,
- dnssvctest.ServerAddrPort,
- dnssvctest.ClientAddr,
- )
- testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
- assert.Equal(t, tc.wantProf, gotProf)
- assert.Equal(t, tc.wantDev, gotDev)
- assert.Equal(t, tc.wantByWhat, gotByWhat)
- })
- }
-}
-
-// newProfileDB is a helper that creates a database returning prof and dev
-// depending on which parameter should be used to find them.
-func newProfileDB(
- t *testing.T,
- prof *agd.Profile,
- dev *agd.Device,
- byWhat string,
-) (db profiledb.Interface) {
- return &agdtest.ProfileDB{
- OnProfileByDeviceID: func(
- _ context.Context,
- gotID agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- assert.Equal(t, dnssvctest.DeviceID, gotID)
-
- if byWhat == byDeviceID {
- return prof, dev, nil
- }
-
- return nil, nil, profiledb.ErrDeviceNotFound
- },
- OnProfileByDedicatedIP: func(
- _ context.Context,
- gotLocalIP netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- assert.Equal(t, dnssvctest.ServerAddr, gotLocalIP)
-
- if byWhat == byDedicatedIP {
- return prof, dev, nil
- }
-
- return nil, nil, profiledb.ErrDeviceNotFound
- },
- OnProfileByLinkedIP: func(
- _ context.Context,
- gotRemoteIP netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- assert.Equal(t, dnssvctest.ClientAddr, gotRemoteIP)
-
- if byWhat == byLinkedIP {
- return prof, dev, nil
- }
-
- return nil, nil, profiledb.ErrDeviceNotFound
- },
- }
-}
diff --git a/internal/dnssvc/internal/initial/specialdomain_test.go b/internal/dnssvc/internal/initial/specialdomain_test.go
index 9024f82..0f6fa67 100644
--- a/internal/dnssvc/internal/initial/specialdomain_test.go
+++ b/internal/dnssvc/internal/initial/specialdomain_test.go
@@ -7,13 +7,13 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/initial"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
- "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
@@ -136,37 +136,32 @@ func TestMiddleware_ServeDNS_specialDomain(t *testing.T) {
return rw.WriteMsg(ctx, req, resp)
})
- onProfileByLinkedIP := func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- if !tc.hasProf {
- return nil, nil, profiledb.ErrDeviceNotFound
- }
-
- prof := &agd.Profile{
- Access: access.EmptyProfile{},
- BlockPrivateRelay: tc.profBlocked,
- BlockFirefoxCanary: tc.profBlocked,
- }
-
- return prof, &agd.Device{}, nil
- }
-
- db := &agdtest.ProfileDB{
- OnProfileByDeviceID: func(
+ ds := &dnssvctest.DeviceSetter{
+ OnSetDevice: func(
_ context.Context,
- _ agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
+ _ *dns.Msg,
+ ri *agd.RequestInfo,
+ _ netip.AddrPort,
+ ) (err error) {
+ if !tc.hasProf {
+ return nil
+ }
+
+ ri.Profile = &agd.Profile{
+ Access: access.EmptyProfile{},
+ BlockPrivateRelay: tc.profBlocked,
+ BlockFirefoxCanary: tc.profBlocked,
+ }
+
+ ri.Device = &agd.Device{
+ Auth: &agd.AuthSettings{
+ Enabled: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ },
+ }
+
+ return nil
},
- OnProfileByDedicatedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return nil, nil, profiledb.ErrDeviceNotFound
- },
- OnProfileByLinkedIP: onProfileByLinkedIP,
}
geoIP := &agdtest.GeoIP{
@@ -198,15 +193,16 @@ func TestMiddleware_ServeDNS_specialDomain(t *testing.T) {
Protocol: agd.ProtoDNS,
LinkedIPEnabled: true,
},
- ProfileDB: db,
- GeoIP: geoIP,
- ErrColl: errColl,
- ProfileDBEnabled: true,
+ DeviceSetter: ds,
+ GeoIP: geoIP,
+ ErrColl: errColl,
})
h := mw.Wrap(handler)
ctx := context.Background()
+ ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{})
+
rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.RemoteAddr)
req := &dns.Msg{
Question: []dns.Question{{
diff --git a/internal/dnssvc/internal/mainmw/debug.go b/internal/dnssvc/internal/mainmw/debug.go
index aa24c81..f3ff608 100644
--- a/internal/dnssvc/internal/mainmw/debug.go
+++ b/internal/dnssvc/internal/mainmw/debug.go
@@ -168,7 +168,7 @@ func (mw *Middleware) debugResponse(
state = "allowed"
case *filter.ResultBlocked:
state = "blocked"
- case *filter.ResultModified:
+ case *filter.ResultModifiedResponse, *filter.ResultModifiedRequest:
state = "modified"
default:
// Consider unhandled sum type members as unrecoverable programmer
diff --git a/internal/dnssvc/internal/mainmw/debug_internal_test.go b/internal/dnssvc/internal/mainmw/debug_internal_test.go
index e9f21bf..73d1016 100644
--- a/internal/dnssvc/internal/mainmw/debug_internal_test.go
+++ b/internal/dnssvc/internal/mainmw/debug_internal_test.go
@@ -143,7 +143,7 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
name: "request_result_modified",
domain: dnssvctest.DomainRewrittenFQDN,
reqInfo: defaultReqInfo,
- reqRes: &filter.ResultModified{
+ reqRes: &filter.ResultModifiedRequest{
Rule: rewriteRule,
Msg: dnsservertest.NewReq(
dnssvctest.DomainRewrittenCNAMEFQDN,
diff --git a/internal/dnssvc/internal/mainmw/filter.go b/internal/dnssvc/internal/mainmw/filter.go
index 0053f81..0920e42 100644
--- a/internal/dnssvc/internal/mainmw/filter.go
+++ b/internal/dnssvc/internal/mainmw/filter.go
@@ -62,7 +62,7 @@ func (mw *Middleware) filterRequest(
mw.reportf(ctx, "filtering request: %w", err)
}
- if mod, ok := reqRes.(*filter.ResultModified); ok && !mod.Msg.Response {
+ if mod, ok := reqRes.(*filter.ResultModifiedRequest); ok {
fctx.modifiedRequest = mod.Msg
}
@@ -84,10 +84,11 @@ func (mw *Middleware) filterResponse(
start := time.Now()
if modReq := fctx.modifiedRequest; modReq != nil {
- // Return the request name to its original state, since it was
- // previously rewritten by CNAME rewrite rule.
+ // Return the request ID and target name to their original values, since
+ // the request has previously been rewritten by a CNAME rewrite rule.
origReq := fctx.originalRequest
origResp := fctx.originalResponse
+ origResp.Id = origReq.Id
origResp.Question[0] = origReq.Question[0]
// Prepend the CNAME answer to the response and don't filter it.
@@ -133,7 +134,8 @@ func resultData(
blocked = false
case
*filter.ResultBlocked,
- *filter.ResultModified:
+ *filter.ResultModifiedResponse,
+ *filter.ResultModifiedRequest:
blocked = true
default:
// Consider unhandled sum type members as unrecoverable programmer
@@ -165,17 +167,13 @@ func (mw *Middleware) setFilteredResponse(
mw.reportf(ctx, "creating blocked resp for filtered req: %w", err)
fctx.filteredResponse = fctx.originalResponse
}
- case *filter.ResultAllowed:
+ case *filter.ResultAllowed, *filter.ResultModifiedRequest:
fctx.filteredResponse = fctx.originalResponse
- case *filter.ResultModified:
- if reqRes.Msg.Response {
- // Only use the request filtering result in case it's already a
- // response. Otherwise, it's a CNAME rewrite result, which isn't
- // filtered after resolving.
- fctx.filteredResponse = reqRes.Msg
- } else {
- fctx.filteredResponse = fctx.originalResponse
- }
+ case *filter.ResultModifiedResponse:
+ // Only use the request filtering result in case it's already a
+ // response. Otherwise, it's a CNAME rewrite result, which isn't
+ // filtered after resolving.
+ fctx.filteredResponse = reqRes.Msg
default:
// Consider unhandled sum type members as unrecoverable programmer
// errors.
@@ -189,7 +187,8 @@ func (mw *Middleware) setFilteredResponse(
// setFilteredResponseNoReq sets the response in fctx if the response filtering
// results require that. After calling setFilteredResponseNoReq,
// fctx.filteredResponse will not be nil. All errors are reported using
-// [Middleware.reportf].
+// [Middleware.reportf]. Note that rewrite results are not applied to
+// responses.
func (mw *Middleware) setFilteredResponseNoReq(
ctx context.Context,
fctx *filteringContext,
@@ -205,13 +204,11 @@ func (mw *Middleware) setFilteredResponseNoReq(
mw.reportf(ctx, "creating blocked resp for filtered resp: %w", err)
fctx.filteredResponse = fctx.originalResponse
}
- case *filter.ResultModified:
- // NOTE: Technically doesn't happen right now, since rewrites are not
- // applied to responses.
- fctx.filteredResponse = respRes.Msg
default:
- // Consider unhandled sum type members as unrecoverable programmer
- // errors.
+ // Consider [*filter.ResultModifiedResponse] and
+ // [*filter.ResultModifiedRequest] as unrecoverable programmer errors
+ // because rewrites are not applied to responses. And unhandled sum
+ // type members as well.
panic(&agd.ArgumentError{
Name: "respRes",
Message: fmt.Sprintf("unexpected type %T", respRes),
diff --git a/internal/dnssvc/internal/mainmw/filter_internal_test.go b/internal/dnssvc/internal/mainmw/filter_internal_test.go
index cfe8956..f7211ea 100644
--- a/internal/dnssvc/internal/mainmw/filter_internal_test.go
+++ b/internal/dnssvc/internal/mainmw/filter_internal_test.go
@@ -66,7 +66,7 @@ func TestMiddleware_setFilteredResponse(t *testing.T) {
name: "blocked_req",
wantTTL: fltRespTTL,
}, {
- reqRes: &filter.ResultModified{Msg: rewrResp},
+ reqRes: &filter.ResultModifiedResponse{Msg: rewrResp},
respRes: nil,
wantIP: rewrIP,
name: "modified_req",
@@ -83,12 +83,6 @@ func TestMiddleware_setFilteredResponse(t *testing.T) {
wantIP: blockIP,
name: "blocked_resp",
wantTTL: fltRespTTL,
- }, {
- reqRes: nil,
- respRes: &filter.ResultModified{Msg: rewrResp},
- wantIP: rewrIP,
- name: "modified_resp",
- wantTTL: fltRespTTL,
}}
ri := &agd.RequestInfo{
@@ -123,4 +117,20 @@ func TestMiddleware_setFilteredResponse(t *testing.T) {
assert.Equal(t, net.IP(tc.wantIP.AsSlice()), a.A)
})
}
+
+ t.Run("modified_resp", func(t *testing.T) {
+ wantPanicMsg := (&agd.ArgumentError{
+ Name: "respRes",
+ Message: fmt.Sprintf("unexpected type %T", &filter.ResultModifiedResponse{}),
+ }).Error()
+
+ assert.PanicsWithError(t, wantPanicMsg, func() {
+ fctx := &filteringContext{
+ requestResult: nil,
+ responseResult: &filter.ResultModifiedResponse{Msg: rewrResp},
+ }
+
+ mw.setFilteredResponse(context.Background(), fctx, ri)
+ })
+ })
}
diff --git a/internal/dnssvc/internal/mainmw/mainmw.go b/internal/dnssvc/internal/mainmw/mainmw.go
index a949be9..70f485f 100644
--- a/internal/dnssvc/internal/mainmw/mainmw.go
+++ b/internal/dnssvc/internal/mainmw/mainmw.go
@@ -26,17 +26,15 @@ import (
// Middleware is the main middleware of AdGuard DNS.
type Middleware struct {
- messages *dnsmsg.Constructor
- cloner *dnsmsg.Cloner
- fltCtxPool *syncutil.Pool[filteringContext]
- billStat billstat.Recorder
- errColl errcoll.Interface
- fltStrg filter.Storage
- geoIP geoip.Interface
- queryLog querylog.Interface
- ruleStat rulestat.Interface
- researchMetrics bool
- researchLogs bool
+ messages *dnsmsg.Constructor
+ cloner *dnsmsg.Cloner
+ fltCtxPool *syncutil.Pool[filteringContext]
+ billStat billstat.Recorder
+ errColl errcoll.Interface
+ fltStrg filter.Storage
+ geoIP geoip.Interface
+ queryLog querylog.Interface
+ ruleStat rulestat.Interface
}
// Config is the configuration structure for the main middleware. All fields
@@ -72,17 +70,6 @@ type Config struct {
// RuleStat is used to collect statistics about matched filtering rules and
// rule lists.
RuleStat rulestat.Interface
-
- // ResearchLogs controls whether logging of additional info for research
- // purposes is enabled. These logs may be overly verbose and are only
- // required temporary, that's why it's controlled by a separate setting.
- // This setting will only be used when ResearchMetrics is also set to true.
- ResearchLogs bool
-
- // ResearchMetrics controls whether research metrics are enabled or not.
- // This is a set of metrics that we may need temporary, so its collection is
- // controlled by a separate setting.
- ResearchMetrics bool
}
// New returns a new main middleware. c must not be nil.
@@ -90,17 +77,15 @@ func New(c *Config) (mw *Middleware) {
return &Middleware{
messages: c.Messages,
cloner: c.Cloner,
- fltCtxPool: syncutil.NewPool[filteringContext](func() (v *filteringContext) {
+ fltCtxPool: syncutil.NewPool(func() (v *filteringContext) {
return &filteringContext{}
}),
- billStat: c.BillStat,
- errColl: c.ErrColl,
- fltStrg: c.FilterStorage,
- geoIP: c.GeoIP,
- queryLog: c.QueryLog,
- ruleStat: c.RuleStat,
- researchMetrics: c.ResearchMetrics,
- researchLogs: c.ResearchLogs,
+ billStat: c.BillStat,
+ errColl: c.ErrColl,
+ fltStrg: c.FilterStorage,
+ geoIP: c.GeoIP,
+ queryLog: c.QueryLog,
+ ruleStat: c.RuleStat,
}
}
@@ -215,13 +200,13 @@ func (mw *Middleware) reportMetrics(fctx *filteringContext, ri *agd.RequestInfo)
asn = strconv.FormatUint(uint64(l.ASN), 10)
}
- // Here and below stick to using WithLabelValues instead of With in order
- // to avoid extra allocations on prometheus.Labels.
+ // Here and below stick to using WithLabelValues instead of With in order to
+ // avoid extra allocations on prometheus.Labels.
metrics.DNSSvcRequestByCountryTotal.WithLabelValues(cont, ctry).Inc()
metrics.DNSSvcRequestByASNTotal.WithLabelValues(ctry, asn).Inc()
- id, _, isBlocked := filteringData(fctx)
+ id, _, _ := filteringData(fctx)
metrics.DNSSvcRequestByFilterTotal.WithLabelValues(
string(id),
metrics.BoolString(ri.Profile == nil),
@@ -229,56 +214,6 @@ func (mw *Middleware) reportMetrics(fctx *filteringContext, ri *agd.RequestInfo)
metrics.DNSSvcFilteringDuration.Observe(fctx.elapsed.Seconds())
metrics.DNSSvcUsersCountUpdate(ri.RemoteIP)
-
- if mw.researchMetrics {
- reportResearchMetrics(ri, fctx.originalResponse, id, isBlocked, mw.researchLogs)
- }
-}
-
-// reportResearchMetrics reports research metrics to prometheus.
-func reportResearchMetrics(
- ri *agd.RequestInfo,
- origResp *dns.Msg,
- fltID agd.FilterListID,
- isBlocked bool,
- researchLogs bool,
-) {
- filteringEnabled := ri.FilteringGroup != nil &&
- ri.FilteringGroup.RuleListsEnabled &&
- len(ri.FilteringGroup.RuleListIDs) > 0
-
- // The current research metrics only count queries that come to public DNS
- // servers where filtering is enabled.
- if !filteringEnabled || ri.Profile != nil {
- return
- }
-
- var ctry string
- var subdiv string
- if l := ri.Location; l != nil {
- if l.ASN == 212772 {
- // Ignore AdGuard ASN specifically in order to avoid counting
- // queries that come from the monitoring. This part is ugly, but
- // since these metrics are a one-time deal, this is acceptable.
- //
- // TODO(ameshkov): Think of a better way later if we need to do that
- // again.
- return
- }
-
- ctry = string(l.Country)
- subdiv = l.TopSubdivision
- }
-
- metrics.ReportResearch(&metrics.ResearchData{
- OriginalResponse: origResp,
- FilterID: string(fltID),
- Country: ctry,
- TopSubdivision: subdiv,
- Host: ri.Host,
- QType: ri.QType,
- Blocked: isBlocked,
- }, researchLogs)
}
// reportf is a helper method for reporting non-critical errors.
diff --git a/internal/dnssvc/internal/mainmw/mainmw_test.go b/internal/dnssvc/internal/mainmw/mainmw_test.go
index 9b29b75..bb700ce 100644
--- a/internal/dnssvc/internal/mainmw/mainmw_test.go
+++ b/internal/dnssvc/internal/mainmw/mainmw_test.go
@@ -208,8 +208,6 @@ func TestMiddleware_Wrap(t *testing.T) {
}}
for _, tc := range testCases {
- tc := tc
-
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
@@ -228,16 +226,14 @@ func TestMiddleware_Wrap(t *testing.T) {
}
c := &mainmw.Config{
- Messages: agdtest.NewConstructor(),
- Cloner: agdtest.NewCloner(),
- BillStat: tc.billStat,
- ErrColl: errColl,
- FilterStorage: fltStrg,
- GeoIP: geoIP,
- QueryLog: queryLog,
- RuleStat: ruleStat,
- ResearchLogs: true,
- ResearchMetrics: true,
+ Messages: agdtest.NewConstructor(),
+ Cloner: agdtest.NewCloner(),
+ BillStat: tc.billStat,
+ ErrColl: errColl,
+ FilterStorage: fltStrg,
+ GeoIP: geoIP,
+ QueryLog: queryLog,
+ RuleStat: ruleStat,
}
mw := mainmw.New(c)
@@ -518,13 +514,13 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
Rule: testRuleBlockReq,
}
- resReqRewrite = &filter.ResultModified{
+ resReqRewrite = &filter.ResultModifiedResponse{
List: dnssvctest.FilterListID1,
Rule: testRuleRewrite,
Msg: respRewrite,
}
- resReqRewriteCNAME = &filter.ResultModified{
+ resReqRewriteCNAME = &filter.ResultModifiedRequest{
List: dnssvctest.FilterListID1,
Rule: testRuleRewriteCNAME,
Msg: reqRewriteCNAME,
@@ -643,8 +639,6 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
}}
for _, tc := range testCases {
- tc := tc
-
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
@@ -698,16 +692,14 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
}
c := &mainmw.Config{
- Messages: agdtest.NewConstructor(),
- Cloner: agdtest.NewCloner(),
- BillStat: tc.billStat,
- ErrColl: errColl,
- FilterStorage: fltStrg,
- GeoIP: geoIP,
- QueryLog: queryLog,
- RuleStat: ruleStat,
- ResearchLogs: true,
- ResearchMetrics: true,
+ Messages: agdtest.NewConstructor(),
+ Cloner: agdtest.NewCloner(),
+ BillStat: tc.billStat,
+ ErrColl: errColl,
+ FilterStorage: fltStrg,
+ GeoIP: geoIP,
+ QueryLog: queryLog,
+ RuleStat: ruleStat,
}
mw := mainmw.New(c)
diff --git a/internal/dnssvc/internal/preupstream/preupstream_test.go b/internal/dnssvc/internal/preupstream/preupstream_test.go
index 9880a8c..a3c6634 100644
--- a/internal/dnssvc/internal/preupstream/preupstream_test.go
+++ b/internal/dnssvc/internal/preupstream/preupstream_test.go
@@ -75,7 +75,7 @@ func TestPreUpstreamMwHandler_ServeDNS_withCache(t *testing.T) {
})
h := mw.Wrap(handler)
- for i := 0; i < N; i++ {
+ for range N {
req := dnsservertest.NewReq(reqHostname, dns.TypeA, dns.ClassINET)
addr := &net.UDPAddr{IP: dnssvctest.ClientIP, Port: 53}
nrw := dnsserver.NewNonWriterResponseWriter(addr, addr)
@@ -147,7 +147,7 @@ func TestPreUpstreamMwHandler_ServeDNS_withECSCache(t *testing.T) {
const N = 5
var nrw *dnsserver.NonWriterResponseWriter
- for i := 0; i < N; i++ {
+ for range N {
addr := &net.UDPAddr{IP: dnssvctest.ClientIP, Port: 53}
nrw = dnsserver.NewNonWriterResponseWriter(addr, addr)
req := dnsservertest.NewReq(reqHostname, dns.TypeA, dns.ClassINET)
diff --git a/internal/ecscache/cache.go b/internal/ecscache/cache.go
index ac1f0a8..02c22ac 100644
--- a/internal/ecscache/cache.go
+++ b/internal/ecscache/cache.go
@@ -2,16 +2,14 @@ package ecscache
import (
"encoding/binary"
- "fmt"
"hash/maphash"
"net/netip"
"time"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/optlog"
- "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/mathutil"
- "github.com/bluele/gcache"
"github.com/miekg/dns"
)
@@ -69,27 +67,19 @@ func (mw *Middleware) get(req *dns.Msg, cr *cacheRequest) (resp *dns.Msg, isECSD
// 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 itemFromCache(cache gcache.Cache, key uint64, cr *cacheRequest) (item *cacheItem, ok bool) {
- val, err := cache.Get(key)
- if err != nil {
- // Shouldn't happen, since we don't set a serialization function.
- if !errors.Is(err, gcache.KeyNotFoundError) {
- panic(fmt.Errorf("ecs-cache: getting cache item: %w", err))
- }
-
- return nil, false
- }
-
- item, ok = val.(*cacheItem)
+func itemFromCache(
+ cache agdcache.Interface[uint64, *cacheItem],
+ key uint64,
+ cr *cacheRequest,
+) (item *cacheItem, ok bool) {
+ item, ok = cache.Get(key)
if !ok {
- optlog.Error2("ecs-cache: bad type %T of cache item for host %q", val, cr.host)
-
return nil, false
}
// Check for cache key collisions.
if item.host != cr.host {
- optlog.Error2("ecs-cache: collision: bad cache item %v for host %q", val, cr.host)
+ optlog.Error2("ecs-cache: collision: bad cache item %v for host %q", item, cr.host)
return nil, false
}
@@ -157,12 +147,7 @@ func (mw *Middleware) set(resp *dns.Msg, cr *cacheRequest, respIsECSDependent bo
cachedResp := mw.cloner.Clone(resp)
- item := toCacheItem(cachedResp, cr.host)
- err := cache.SetWithExpire(key, item, exp)
- if err != nil {
- // Shouldn't happen, since we don't set a serialization function.
- panic(fmt.Errorf("ecs-cache: setting cache item: %w", err))
- }
+ cache.SetWithExpire(key, toCacheItem(cachedResp, cr.host), exp)
}
// cacheItem represents an item that we will store in the cache.
diff --git a/internal/ecscache/cache_internal_test.go b/internal/ecscache/cache_internal_test.go
index 7aa2090..de0e754 100644
--- a/internal/ecscache/cache_internal_test.go
+++ b/internal/ecscache/cache_internal_test.go
@@ -4,8 +4,8 @@ import (
"net/netip"
"testing"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
- "github.com/bluele/gcache"
"github.com/miekg/dns"
)
@@ -13,8 +13,12 @@ var msgSink *dns.Msg
func BenchmarkMiddleware_Get(b *testing.B) {
mw := &Middleware{
- cache: gcache.New(10).LRU().Build(),
- ecsCache: gcache.New(10).LRU().Build(),
+ cache: agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
+ Size: 10,
+ }),
+ ecsCache: agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
+ Size: 10,
+ }),
}
const (
@@ -33,7 +37,7 @@ func BenchmarkMiddleware_Get(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
msgSink, _ = mw.get(req, cr)
}
}
diff --git a/internal/ecscache/ecsblocklist.go b/internal/ecscache/ecsblocklist.go
index f1200ea..5f45f5e 100644
--- a/internal/ecscache/ecsblocklist.go
+++ b/internal/ecscache/ecsblocklist.go
@@ -2,8350 +2,8082 @@
package ecscache
+import "github.com/AdguardTeam/golibs/container"
+
// FakeECSFQDNs contains all domains that indicate ECS support, but in fact
// don't have one.
-var FakeECSFQDNs = map[string]struct{}{
- "01.cofile.net.": {},
- "011b2ef417d541e4b4a0753f94353476.pacloudflare.com.": {},
- "02.cofile.net.": {},
- "0272ac85-5199-4024-a555-397c3d825d95.prmutv.co.": {},
- "03.cofile.net.": {},
- "04.cofile.net.": {},
- "05.cofile.net.": {},
- "06.cofile.net.": {},
- "07.cofile.net.": {},
- "08.cofile.net.": {},
- "09.cofile.net.": {},
- "0cf.io.": {},
- "0cf17917-395b-4f25-91cc-db3bdd6044b0.prmutv.co.": {},
- "1.cn.pool.ntp.org.": {},
- "1.eu.dl.wireshark.org.": {},
- "10.cofile.net.": {},
- "103.chtsite.com.": {},
- "10m.com.cn.": {},
- "11-alarm-mop.meshare.com.": {},
- "11.cofile.net.": {},
- "1184-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.": {},
- "12-alarm-mop.meshare.com.": {},
- "12.cofile.net.": {},
- "126.net.": {},
- "13-alarm-mop.meshare.com.": {},
- "13.cofile.net.": {},
- "1365538595.rsc.cdn77.org.": {},
- "1394501235.rsc.cdn77.org.": {},
- "14-alarm-mop.meshare.com.": {},
- "14.cofile.net.": {},
- "15.cofile.net.": {},
- "16.cofile.net.": {},
- "163jiasu.com.": {},
- "163yun.com.": {},
- "1688.com.": {},
- "17.cofile.net.": {},
- "17173sf.com.": {},
- "17de4c16.akstat.io.": {},
- "18.cofile.net.": {},
- "18ea70d2d9a945cfb97d818ba71817dc.pacloudflare.com.": {},
- "19.cofile.net.": {},
- "192667-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.": {},
- "192991-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.": {},
- "193119-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.": {},
- "193259-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.": {},
- "193522-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.": {},
- "193597-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.": {},
- "1941-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.": {},
- "1weather.onelouder.com.": {},
- "2-01-49b5-0066.cdx.cedexis.net.": {},
- "2.401402081.west-gcloud.codm.activision.com.": {},
- "2.realtime.services.box.net.": {},
- "20.cofile.net.": {},
- "201205igp.gameloft.com.": {},
- "21cn.com.": {},
- "2acdb9b66bb242618283aadb21ede6c1.pacloudflare.com.": {},
- "2e4b93d1-a8ae-4a89-8885-6109135ac0de.prmutv.co.": {},
- "2talk.com.": {},
- "2tx.com.": {},
- "360.cn.": {},
- "360os.com.": {},
- "360safe.com.": {},
- "365.kdocs.cn.": {},
- "3a6b0682-f3e1-4576-a706-5eb4101b9cc3.prmutv.co.": {},
- "3aba5292-ba75-422b-8715-bd21146f7836.prmutv.co.": {},
- "3bjjlx-cdn-settings.appsflyersdk.com.": {},
- "3d2fb0bd-52fc-4b75-aaf5-2d436c172540.prmutv.co.": {},
- "4.401402081.west-gcloud.codm.activision.com.": {},
- "4.adsco.re.": {},
- "401402081.west-gcloud.codm.activision.com.": {},
- "4065-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.": {},
- "46a2e5c3c5a64e218b60f2c2ee76b750.pacloudflare.com.": {},
- "4974-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.": {},
- "507b28fb-2ef1-4c34-8bda-ba32030bb199.prmutv.co.": {},
- "520.jp.": {},
- "5d79bce7-5d2b-427e-a6c4-b89b6c7bf048.prmutv.co.": {},
- "6.401402081.west-gcloud.codm.activision.com.": {},
- "6093eccf-6734-4877-ac8b-83d6d0e27b46.prmutv.co.": {},
- "6536.apps.zdusercontent.com.": {},
- "68547f8f-2fd8-4ff3-9b63-51e86e2edee8.prmutv.co.": {},
- "6c3e19e3-d05e-45d1-8f79-fcd6cb2f3a21.prmutv.co.": {},
- "6o1s4z-launches.appsflyersdk.com.": {},
- "733868e706dd40d3a4a0588fc39b3df8.pacloudflare.com.": {},
- "789-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.": {},
- "7c7b02d4bc3d48dd81a7c7738d4de1ab.pacloudflare.com.": {},
- "8686c.com.": {},
- "88a66e5c-8fe8-48af-9c6c-3ec3f4983aad.prmutv.co.": {},
- "8fd3136c-39ae-4836-adeb-ea2f0db46980.prmutv.co.": {},
- "8x8.com.cdn.cloudflare.net.": {},
- "9pumbooc7hqedhjmeavbpmp5ik9u0ngr-data.customer.pendo.io.": {},
- "a-m-p.xyz.": {},
- "a.dtssrv.com.": {},
- "a.fc.namequery.com.": {},
- "a.nel.cloudflare.com.": {},
- "a.nitropay.com.": {},
- "a.ns.xx.fbcdn.net.": {},
- "a.tile.openstreetmap.org.": {},
- "a.tile.osm.org.": {},
- "a010.casalemedia.com.": {},
- "a011.casalemedia.com.": {},
- "a012.casalemedia.com.": {},
- "a013.casalemedia.com.": {},
- "a014.casalemedia.com.": {},
- "a015.casalemedia.com.": {},
- "a016.casalemedia.com.": {},
- "a017.casalemedia.com.": {},
- "a018.casalemedia.com.": {},
- "a019.casalemedia.com.": {},
- "a020.casalemedia.com.": {},
- "a022.casalemedia.com.": {},
- "a023.casalemedia.com.": {},
- "a024.casalemedia.com.": {},
- "a025.casalemedia.com.": {},
- "a026.casalemedia.com.": {},
- "a027.casalemedia.com.": {},
- "a028.casalemedia.com.": {},
- "a029.casalemedia.com.": {},
- "a030.casalemedia.com.": {},
- "a031.casalemedia.com.": {},
- "a032.casalemedia.com.": {},
- "a033.casalemedia.com.": {},
- "a035.casalemedia.com.": {},
- "a036.casalemedia.com.": {},
- "a038.casalemedia.com.": {},
- "a039.casalemedia.com.": {},
- "a040.casalemedia.com.": {},
- "a041.casalemedia.com.": {},
- "a042.casalemedia.com.": {},
- "a043.casalemedia.com.": {},
- "a044.casalemedia.com.": {},
- "a045.casalemedia.com.": {},
- "a046.casalemedia.com.": {},
- "a050.casalemedia.com.": {},
- "a054.casalemedia.com.": {},
- "a058.casalemedia.com.": {},
- "a074.casalemedia.com.": {},
- "a075.casalemedia.com.": {},
- "a088.casalemedia.com.": {},
- "a091.casalemedia.com.": {},
- "a095.casalemedia.com.": {},
- "a096.casalemedia.com.": {},
- "a097.casalemedia.com.": {},
- "a098.casalemedia.com.": {},
- "a099.casalemedia.com.": {},
- "a101.casalemedia.com.": {},
- "a119.casalemedia.com.": {},
- "a121.casalemedia.com.": {},
- "a123.casalemedia.com.": {},
- "a124.casalemedia.com.": {},
- "a126.casalemedia.com.": {},
- "a127.casalemedia.com.": {},
- "a128.casalemedia.com.": {},
- "a129.casalemedia.com.": {},
- "a131.casalemedia.com.": {},
- "a133.casalemedia.com.": {},
- "a134.casalemedia.com.": {},
- "a136.casalemedia.com.": {},
- "a137.casalemedia.com.": {},
- "a138.casalemedia.com.": {},
- "a139.casalemedia.com.": {},
- "a141.casalemedia.com.": {},
- "a143.casalemedia.com.": {},
- "a144.casalemedia.com.": {},
- "a145.casalemedia.com.": {},
- "a146.casalemedia.com.": {},
- "a147.casalemedia.com.": {},
- "a149.casalemedia.com.": {},
- "a150.casalemedia.com.": {},
- "a151.casalemedia.com.": {},
- "a152.casalemedia.com.": {},
- "a153.casalemedia.com.": {},
- "a156.casalemedia.com.": {},
- "a157.casalemedia.com.": {},
- "a158.casalemedia.com.": {},
- "a160.casalemedia.com.": {},
- "a161.casalemedia.com.": {},
- "a166.casalemedia.com.": {},
- "a169.casalemedia.com.": {},
- "a170.casalemedia.com.": {},
- "a172.casalemedia.com.": {},
- "a178.casalemedia.com.": {},
- "a179.casalemedia.com.": {},
- "a182.casalemedia.com.": {},
- "a186.casalemedia.com.": {},
- "a187.casalemedia.com.": {},
- "a188.casalemedia.com.": {},
- "a189.casalemedia.com.": {},
- "a190.casalemedia.com.": {},
- "a192.casalemedia.com.": {},
- "a195.casalemedia.com.": {},
- "a200.casalemedia.com.": {},
- "a2001.casalemedia.com.": {},
- "a2002.casalemedia.com.": {},
- "a2003.casalemedia.com.": {},
- "a2004.casalemedia.com.": {},
- "a2005.casalemedia.com.": {},
- "a2006.casalemedia.com.": {},
- "a2007.casalemedia.com.": {},
- "a2008.casalemedia.com.": {},
- "a201.casalemedia.com.": {},
- "a2010.casalemedia.com.": {},
- "a2011.casalemedia.com.": {},
- "a2012.casalemedia.com.": {},
- "a2013.casalemedia.com.": {},
- "a2015.casalemedia.com.": {},
- "a2016.casalemedia.com.": {},
- "a2019.casalemedia.com.": {},
- "a2020.casalemedia.com.": {},
- "a2021.casalemedia.com.": {},
- "a2022.casalemedia.com.": {},
- "a2023.casalemedia.com.": {},
- "a2024.casalemedia.com.": {},
- "a2025.casalemedia.com.": {},
- "a2026.casalemedia.com.": {},
- "a2027.casalemedia.com.": {},
- "a2030.casalemedia.com.": {},
- "a2031.casalemedia.com.": {},
- "a2033.casalemedia.com.": {},
- "a2034.casalemedia.com.": {},
- "a2035.casalemedia.com.": {},
- "a2036.casalemedia.com.": {},
- "a2037.casalemedia.com.": {},
- "a2038.casalemedia.com.": {},
- "a2039.casalemedia.com.": {},
- "a2040.casalemedia.com.": {},
- "a2041.casalemedia.com.": {},
- "a2042.casalemedia.com.": {},
- "a2043.casalemedia.com.": {},
- "a2044.casalemedia.com.": {},
- "a2045.casalemedia.com.": {},
- "a2046.casalemedia.com.": {},
- "a2047.casalemedia.com.": {},
- "a2048.casalemedia.com.": {},
- "a2049.casalemedia.com.": {},
- "a2050.casalemedia.com.": {},
- "a2051.casalemedia.com.": {},
- "a2052.casalemedia.com.": {},
- "a2053.casalemedia.com.": {},
- "a2054.casalemedia.com.": {},
- "a2055.casalemedia.com.": {},
- "a2056.casalemedia.com.": {},
- "a2057.casalemedia.com.": {},
- "a2058.casalemedia.com.": {},
- "a2060.casalemedia.com.": {},
- "a2561.casalemedia.com.": {},
- "a2562.casalemedia.com.": {},
- "a2563.casalemedia.com.": {},
- "a2564.casalemedia.com.": {},
- "a2565.casalemedia.com.": {},
- "a2566.casalemedia.com.": {},
- "a2568.casalemedia.com.": {},
- "a2569.casalemedia.com.": {},
- "a2570.casalemedia.com.": {},
- "a2571.casalemedia.com.": {},
- "a2572.casalemedia.com.": {},
- "a2573.casalemedia.com.": {},
- "a2574.casalemedia.com.": {},
- "a2575.casalemedia.com.": {},
- "a2576.casalemedia.com.": {},
- "a2577.casalemedia.com.": {},
- "a2578.casalemedia.com.": {},
- "a2579.casalemedia.com.": {},
- "a2580.casalemedia.com.": {},
- "a2582.casalemedia.com.": {},
- "a2583.casalemedia.com.": {},
- "a2584.casalemedia.com.": {},
- "a2585.casalemedia.com.": {},
- "a2587.casalemedia.com.": {},
- "a2588.casalemedia.com.": {},
- "a2589.casalemedia.com.": {},
- "a2591.casalemedia.com.": {},
- "a2592.casalemedia.com.": {},
- "a2593.casalemedia.com.": {},
- "a2594.casalemedia.com.": {},
- "a2595.casalemedia.com.": {},
- "a2596.casalemedia.com.": {},
- "a2597.casalemedia.com.": {},
- "a2598.casalemedia.com.": {},
- "a2599.casalemedia.com.": {},
- "a2601.casalemedia.com.": {},
- "a2603.casalemedia.com.": {},
- "a2605.casalemedia.com.": {},
- "a2606.casalemedia.com.": {},
- "a2607.casalemedia.com.": {},
- "a2608.casalemedia.com.": {},
- "a2609.casalemedia.com.": {},
- "a2611.casalemedia.com.": {},
- "a2612.casalemedia.com.": {},
- "a2613.casalemedia.com.": {},
- "a2614.casalemedia.com.": {},
- "a2615.casalemedia.com.": {},
- "a2616.casalemedia.com.": {},
- "a2617.casalemedia.com.": {},
- "a2618.casalemedia.com.": {},
- "a2619.casalemedia.com.": {},
- "a2620.casalemedia.com.": {},
- "a2621.casalemedia.com.": {},
- "a2622.casalemedia.com.": {},
- "a2624.casalemedia.com.": {},
- "a2625.casalemedia.com.": {},
- "a2626.casalemedia.com.": {},
- "a2627.casalemedia.com.": {},
- "a2628.casalemedia.com.": {},
- "a2629.casalemedia.com.": {},
- "a2630.casalemedia.com.": {},
- "a2631.casalemedia.com.": {},
- "a2632.casalemedia.com.": {},
- "a2633.casalemedia.com.": {},
- "a2634.casalemedia.com.": {},
- "a2635.casalemedia.com.": {},
- "a2636.casalemedia.com.": {},
- "a2637.casalemedia.com.": {},
- "a2638.casalemedia.com.": {},
- "a2639.casalemedia.com.": {},
- "a2640.casalemedia.com.": {},
- "a2641.casalemedia.com.": {},
- "a2642.casalemedia.com.": {},
- "a2643.casalemedia.com.": {},
- "a2645.casalemedia.com.": {},
- "a2646.casalemedia.com.": {},
- "a2647.casalemedia.com.": {},
- "a2648.casalemedia.com.": {},
- "a2649.casalemedia.com.": {},
- "a2a5c7f9-3fa0-4182-889a-15aa61acf59b.prmutv.co.": {},
- "a3.tuyacn.com.": {},
- "a314.gameloft.com.": {},
- "a463.casalemedia.com.": {},
- "a464.casalemedia.com.": {},
- "a465.casalemedia.com.": {},
- "a466.casalemedia.com.": {},
- "a467.casalemedia.com.": {},
- "a470.casalemedia.com.": {},
- "a471.casalemedia.com.": {},
- "a472.casalemedia.com.": {},
- "a473.casalemedia.com.": {},
- "a474.casalemedia.com.": {},
- "a475.casalemedia.com.": {},
- "a476.casalemedia.com.": {},
- "a477.casalemedia.com.": {},
- "a478.casalemedia.com.": {},
- "a479.casalemedia.com.": {},
- "a480.casalemedia.com.": {},
- "a5551.casalemedia.com.": {},
- "a5552.casalemedia.com.": {},
- "a5555.casalemedia.com.": {},
- "a5556.casalemedia.com.": {},
- "a5557.casalemedia.com.": {},
- "a5558.casalemedia.com.": {},
- "a5559.casalemedia.com.": {},
- "a5560.casalemedia.com.": {},
- "a5562.casalemedia.com.": {},
- "a5563.casalemedia.com.": {},
- "a5564.casalemedia.com.": {},
- "a5565.casalemedia.com.": {},
- "a5566.casalemedia.com.": {},
- "a5567.casalemedia.com.": {},
- "a5568.casalemedia.com.": {},
- "a5569.casalemedia.com.": {},
- "a5570.casalemedia.com.": {},
- "a5571.casalemedia.com.": {},
- "a5572.casalemedia.com.": {},
- "a5573.casalemedia.com.": {},
- "a5575.casalemedia.com.": {},
- "a5577.casalemedia.com.": {},
- "a5578.casalemedia.com.": {},
- "a5579.casalemedia.com.": {},
- "a5580.casalemedia.com.": {},
- "a5581.casalemedia.com.": {},
- "a5582.casalemedia.com.": {},
- "a5583.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.": {},
- "a5597.casalemedia.com.": {},
- "a5598.casalemedia.com.": {},
- "a5599.casalemedia.com.": {},
- "a55a84b3-9632-4869-b625-3d8ef43ed18d.prmutv.co.": {},
- "a5600.casalemedia.com.": {},
- "a5602.casalemedia.com.": {},
- "a5603.casalemedia.com.": {},
- "a5604.casalemedia.com.": {},
- "a5605.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.": {},
- "a5624.casalemedia.com.": {},
- "a5625.casalemedia.com.": {},
- "a5626.casalemedia.com.": {},
- "a5627.casalemedia.com.": {},
- "a5628.casalemedia.com.": {},
- "a5629.casalemedia.com.": {},
- "a5630.casalemedia.com.": {},
- "a5632.casalemedia.com.": {},
- "a5633.casalemedia.com.": {},
- "a5634.casalemedia.com.": {},
- "a5635.casalemedia.com.": {},
- "a5636.casalemedia.com.": {},
- "a5638.casalemedia.com.": {},
- "a5639.casalemedia.com.": {},
- "a5640.casalemedia.com.": {},
- "a5641.casalemedia.com.": {},
- "a5642.casalemedia.com.": {},
- "a5643.casalemedia.com.": {},
- "a5644.casalemedia.com.": {},
- "a5645.casalemedia.com.": {},
- "a5646.casalemedia.com.": {},
- "a5647.casalemedia.com.": {},
- "a5648.casalemedia.com.": {},
- "a5649.casalemedia.com.": {},
- "a5650.casalemedia.com.": {},
- "a5651.casalemedia.com.": {},
- "a5652.casalemedia.com.": {},
- "a5653.casalemedia.com.": {},
- "a5654.casalemedia.com.": {},
- "a5655.casalemedia.com.": {},
- "a5656.casalemedia.com.": {},
- "a5657.casalemedia.com.": {},
- "a5659.casalemedia.com.": {},
- "a5660.casalemedia.com.": {},
- "a5661.casalemedia.com.": {},
- "a5662.casalemedia.com.": {},
- "a5663.casalemedia.com.": {},
- "a5664.casalemedia.com.": {},
- "a5665.casalemedia.com.": {},
- "a5666.casalemedia.com.": {},
- "a5667.casalemedia.com.": {},
- "a5668.casalemedia.com.": {},
- "a5669.casalemedia.com.": {},
- "a5670.casalemedia.com.": {},
- "a57.foxsports.com.": {},
- "a6.smartnews-ads.com.": {},
- "a9695278-4085-40b3-9f02-8d4c38a6ff01.prmutv.co.": {},
- "aa-sync.quantummetric.com.": {},
- "aa.online-metrix.net.": {},
- "aa.quantummetric.com.": {},
- "aaa.a-mo.net.": {},
- "aaid.uyunad.com.": {},
- "ab.qq.com.": {},
- "abcsinsights.com.": {},
- "abmmscloud-my.sharepoint.com.": {},
- "abmmscloud.sharepoint.com.": {},
- "abroad-lzd.apilocate.amap.com.": {},
- "abroad.apilocate.amap.com.": {},
- "abtest-aws-us-east-01.saas.sensorsdata.com.": {},
- "accela.com.": {},
- "access.creditonebank.com.": {},
- "access.mp.lura.live.": {},
- "account.box.com.": {},
- "accountapi.agoda.com.": {},
- "accruent.com.": {},
- "accscdn4public.m.taobao.com.": {},
- "accurint.com.": {},
- "acdn.tinkoff.ru.": {},
- "acgvideo.com.": {},
- "achi.faceit.com.": {},
- "acme-v02.api.letsencrypt.org.": {},
- "acrobits.cz.": {},
- "acs4public.m.taobao.com.": {},
- "acsdk.gameyw.easebar.com.": {},
- "activate.academy.com.": {},
- "activation.cloud.techsmith.com.": {},
- "ad.sitemaji.com.": {},
- "adakami.id.": {},
- "adapex.io.": {},
- "adash-emas.cn-hangzhou.aliyuncs.com.": {},
- "adash.man.aliyuncs.com.": {},
- "adcell.com.": {},
- "addictpodcast.com.": {},
- "adi-sin-c-4.cico.com.": {},
- "adidas.com.multicdn.cloudinary.com.": {},
- "aditude.io.": {},
- "adlook.me.": {},
- "adm.wsms.haplat.net.": {},
- "admbk.wsms.haplat.net.": {},
- "admedo.com.": {},
- "adminmepcr-my.sharepoint.com.": {},
- "admitad.com.": {},
- "admixer.com.": {},
- "adoric.com.": {},
- "adquery.io.": {},
- "adrs.org.cn.": {},
- "adsco.re.": {},
- "adtarget.market.": {},
- "adtarget.me.": {},
- "advantage.purpleguys.com.": {},
- "advantage2.purpleguys.com.": {},
- "adventisthealthwest-my.sharepoint.com.": {},
- "adventisthealthwest.sharepoint.com.": {},
- "adview.com.": {},
- "advisorgroup-my.sharepoint.com.": {},
- "advlion.com.": {},
- "adx-sg-req.anythinktech.com.": {},
- "aee.myisolved.com.": {},
- "aepenergy-my.sharepoint.com.": {},
- "aepenergy.sharepoint.com.": {},
- "affyrtb.com.": {},
- "afss.zhiqinyun.cn.": {},
- "agd2.p.360.cn.": {},
- "agent.marketingcloudfx.com.": {},
- "agoda-my.sharepoint.com.": {},
- "agt.p.360.cn.": {},
- "aicdn.com.": {},
- "aid.send.microad.jp.": {},
- "aidata.io.": {},
- "aikenschools-my.sharepoint.com.": {},
- "aikenschools.sharepoint.com.": {},
- "ailunshenghuo.com.": {},
- "aiq-in.caranddriver.com.": {},
- "airasia.com.": {},
- "airasia.gw-dv.vip.": {},
- "airtame.com.": {},
- "airtory.com.": {},
- "ajcloud.net.": {},
- "akronchildrens-my.sharepoint.com.": {},
- "akronchildrens.sharepoint.com.": {},
- "alarm.wsms.haplat.net.": {},
- "alarmbk.wsms.haplat.net.": {},
- "alarmnet.com.": {},
- "albany.remotepc.com.": {},
- "album-sg01a.ocloud.heytapmobi.com.": {},
- "ali-picture-private-sg.oss-ap-southeast-1.aliyuncs.com.": {},
- "ali-sgp-messpush.meetyouintl.com.": {},
- "alialarm-sgp.oss-ap-southeast-1.aliyuncs.com.": {},
- "alibaba-inc.com.": {},
- "alibabachengdun.com.": {},
- "alibabacloud.com.": {},
- "alibabacorp.com.": {},
- "alibabausercontent.com.": {},
- "alicdn.com.": {},
- "aliexpress.ru.": {},
- "aliexpress.us.": {},
- "alikunlun.com.": {},
- "alikunlun.net.": {},
- "alive1.cloudbirds.cn.": {},
- "alive2.cloudbirds.cn.": {},
- "alive3.cloudbirds.cn.": {},
- "aliyun.com.": {},
- "aliyuncs.com.": {},
- "allieduniversalservices-my.sharepoint.com.": {},
- "allieduniversalservices.sharepoint.com.": {},
- "alog-default.umeng.com.": {},
- "aly.justuno.com.": {},
- "am1.ecdn2.bumbcdn.com.": {},
- "am3pap002.storage.live.com.": {},
- "am3pap003.storage.live.com.": {},
- "am3pap004.storage.live.com.": {},
- "am3pap005.storage.live.com.": {},
- "am3pap006.storage.live.com.": {},
- "am3pap007.storage.live.com.": {},
- "am4pap001.storage.live.com.": {},
- "amap.com.": {},
- "amc-theatres-res.cloudinary.com.": {},
- "amc-theatres.multicdn.cloudinary.com.": {},
- "amcor-my.sharepoint.com.": {},
- "amcor.sharepoint.com.": {},
- "amd.com.": {},
- "amdc-wapa.lazada.com.": {},
- "amdc.lazada.com.": {},
- "amdcopen.m.taobao.com.": {},
- "amdcopen.m.taobao.com.gds.alibabadns.com.": {},
- "americanchemicalsociety-my.sharepoint.com.": {},
- "amp.namequery.com.": {},
- "amp.permutive.com.": {},
- "ams-itm-radar-testobject.citrix.com.": {},
- "ams02pap001.storage.live.com.": {},
- "ams03pap001.storage.live.com.": {},
- "ams03pap002.storage.live.com.": {},
- "ams03pap003.storage.live.com.": {},
- "ams03pap004.storage.live.com.": {},
- "ams03pap005.storage.live.com.": {},
- "ams06pap001.storage.live.com.": {},
- "amsterdam.remotepc.com.": {},
- "amwinsusa-my.sharepoint.com.": {},
- "amwinsusa.sharepoint.com.": {},
- "analytics-2.athome.com.": {},
- "analytics-batch.blitz.gg.": {},
- "analytics-debugger.com.": {},
- "analytics-ingress-global.bitmovin.com.": {},
- "analytics.coachoutlet.com.": {},
- "analytics.duluthtrading.com.": {},
- "analytics.getshogun.com.": {},
- "analytics.gnc.com.": {},
- "analytics.languagetoolplus.com.": {},
- "analytics.qumucloud.com.": {},
- "analytics.trovit.com.": {},
- "android.crashsight.wetest.net.": {},
- "ankara.remotepc.com.": {},
- "anlian.co.": {},
- "announce.torrentsmd.com.": {},
- "anonymous.ads.brave.com.": {},
- "ansellhealthcare-my.sharepoint.com.": {},
- "ansys-my.sharepoint.com.": {},
- "ansys.sharepoint.com.": {},
- "anthem-app.quantummetric.com.": {},
- "anthropic.com.": {},
- "anxbrylkt.accounts.ondemand.com.": {},
- "aon.com.": {},
- "ap-southeast-1.log.aliyuncs.com.": {},
- "apcloud.xyz.": {},
- "api-analytics-us3.zepp.com.": {},
- "api-asyncgw-gcc-teams.usgovtrafficmanager.net.": {},
- "api-eu1.hubspot.com.": {},
- "api-ext.slickdeals.net.": {},
- "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-aeuc1a.smoot.apple.com.": {},
- "api-glb-aeuc1b.smoot.apple.com.": {},
- "api-glb-aeuw1b.smoot.apple.com.": {},
- "api-glb-aeuw3b.smoot.apple.com.": {},
- "api-glb-aeuw3c.smoot.apple.com.": {},
- "api-glb-ause1a.smoot.apple.com.": {},
- "api-glb-ause1b.smoot.apple.com.": {},
- "api-glb-ause1c.smoot.apple.com.": {},
- "api-glb-ause2a.smoot.apple.com.": {},
- "api-glb-ause2b.smoot.apple.com.": {},
- "api-glb-ause2c.smoot.apple.com.": {},
- "api-glb-ausw2b.smoot.apple.com.": {},
- "api-glb-ausw2c.smoot.apple.com.": {},
- "api-mayi.django.t.taobao.com.": {},
- "api-mifit-us2.zepp.com.": {},
- "api-mifit-us3.zepp.com.": {},
- "api-mp.muslimpro.com.": {},
- "api-na1.hubspot.com.": {},
- "api-php1-ovh.keepsolid.com.": {},
- "api-php2-ovh.keepsolid.com.": {},
- "api-php3-ovh.keepsolid.com.": {},
- "api-php4-ovh.keepsolid.com.": {},
- "api-pos.titank12.com.": {},
- "api-preview.luckyorange.com.": {},
- "api-sh.django.t.taobao.com.gds.alibabadns.com.": {},
- "api-skytone-6-drcn.cloud.dbankcloud.cn.": {},
- "api.adquery.io.": {},
- "api.ams.gcc.teams.microsoft.com.": {},
- "api.asm.skype.com.": {},
- "api.bobble.ai.": {},
- "api.bosch-wdw.com.": {},
- "api.box.com.": {},
- "api.btloader.com.": {},
- "api.cloud.tenda.com.cn.": {},
- "api.config-security.com.": {},
- "api.crobox.com.": {},
- "api.crush.163.com.": {},
- "api.dealersocket.com.": {},
- "api.deepl.com.": {},
- "api.do.buienalarm.nl.": {},
- "api.easeus.com.": {},
- "api.gleap.io.": {},
- "api.gravitec.media.": {},
- "api.grow.me.": {},
- "api.hetangsmart.com.": {},
- "api.icalendars.app.": {},
- "api.inboxsdk.com.": {},
- "api.k.163.com.": {},
- "api.kinogram.best.": {},
- "api.lightboxcdn.com.": {},
- "api.lululemon.com.": {},
- "api.lytics.io.": {},
- "api.mida.so.": {},
- "api.mintkeyboard.com.": {},
- "api.moyoung.com.": {},
- "api.mrg.agency.": {},
- "api.my.jbi.global.": {},
- "api.onedrive.com.": {},
- "api.permutive.app.": {},
- "api.permutive.com.": {},
- "api.pgf-asw0zz.com.": {},
- "api.pgf-thek63.com.": {},
- "api.playlnk.io.": {},
- "api.popin.cc.": {},
- "api.protonmail.ch.": {},
- "api.pushbullet.com.": {},
- "api.qsg1h.com.": {},
- "api.queryly.com.": {},
- "api.rethinkad.com.": {},
- "api.reverso.net.": {},
- "api.ringcentral.biz.": {},
- "api.rollbar.com.": {},
- "api.smartdeploy.com.": {},
- "api.snapchat.com.": {},
- "api.statsig.com.": {},
- "api.streak.com.": {},
- "api.surfshark.com.": {},
- "api.swishapps.ai.": {},
- "api.t3be3280.pw.adn.cloud.": {},
- "api.timehop.com.": {},
- "api.transitapp.com.": {},
- "api.tuisong.baidu.com.": {},
- "api.ultimate-guitar.com.": {},
- "api.un41h.com.": {},
- "api.unity.com.": {},
- "api.userlike.com.": {},
- "api.vieon.vn.": {},
- "api.vivoglobal.com.": {},
- "api000.backblazeb2.com.": {},
- "api001.backblazeb2.com.": {},
- "api002.backblazeb2.com.": {},
- "api3.aoneroom.com.": {},
- "apigroupinc-my.sharepoint.com.": {},
- "apiisgp.ezvizlife.com.": {},
- "apiisgp.hik-connect.com.": {},
- "apis.halifax-online.co.uk.": {},
- "apk.v-mate.mobi.": {},
- "apk.vidmate.net.": {},
- "app-atl.five9.com.": {},
- "app-eu1.hubspot.com.": {},
- "app-goal.com.": {},
- "app-scl.five9.com.": {},
- "app-sec-cn.heytapmobi.com.": {},
- "app-student.atitesting.com.": {},
- "app.adoric-om.com.": {},
- "app.box.com.": {},
- "app.cart-bot.net.": {},
- "app.cybba.solutions.": {},
- "app.grow.me.": {},
- "app.paces.jbi.global.": {},
- "app.pendo.qgenda.com.": {},
- "app.retinavue.net.": {},
- "app.sealsubscriptions.com.": {},
- "app.snapchat.com.": {},
- "app.sproutsocial.com.": {},
- "app.trustev.com.": {},
- "app.updates.digicert.com.": {},
- "app.wdesk.com.": {},
- "app.zoom.us.": {},
- "appcafe.gtm.starbucks.com.": {},
- "appcafe.starbucks.com.": {},
- "appconf.mail.163.com.": {},
- "appocean.media.": {},
- "apponline.research.qq.com.": {},
- "appriver.com.": {},
- "apps.gov.powerapps.us.": {},
- "apps.wix.com.": {},
- "appstoreonrt-stsdk.vivo.com.cn.": {},
- "appstoreort-stsdk.vivo.com.cn.": {},
- "apse1-red.pp.sgp.pvp.net.": {},
- "apv-launcher.minute.ly.": {},
- "apv-static.minute.ly.": {},
- "apv-static.tldw.me.": {},
- "ar2fnu-launches.appsflyersdk.com.": {},
- "aranera.com.": {},
- "ard.bmj.com.": {},
- "ardenthealthservices-my.sharepoint.com.": {},
- "ardenthealthservices.sharepoint.com.": {},
- "arenabg.com.": {},
- "aristotleinsight.com.": {},
- "arkdhs-my.sharepoint.com.": {},
- "arm1.maxhost.io.": {},
- "armh-my.sharepoint.com.": {},
- "armh.sharepoint.com.": {},
- "armmf.adobe.com.": {},
- "arms-retcode-sg.aliyuncs.com.": {},
- "arms-retcode.aliyuncs.com.": {},
- "arms.aliyuncs.com.": {},
- "armstrongceilings-my.sharepoint.com.": {},
- "arnoldclark1-my.sharepoint.com.": {},
- "arthrex-my.sharepoint.com.": {},
- "arup-my.sharepoint.com.": {},
- "arup.sharepoint.com.": {},
- "arupapc-my.sharepoint.com.": {},
- "as-api.asm.skype.com.": {},
- "as-prod.asyncgw.teams.microsoft.com.": {},
- "asheville.remotepc.com.": {},
- "asia-001.azure-apim.net.": {},
- "asia-adlog.vivoglobal.com.": {},
- "asia-browser.vivoglobal.com.": {},
- "asia-browserplat.vivoglobal.com.": {},
- "asia-config-appstore.vivoglobal.com.": {},
- "asia-cota.vivoglobal.com.": {},
- "asia-ex-adlog.vivoglobal.com.": {},
- "asia-exmagazineunlock-proxy.vivoglobal.com.": {},
- "asia-f-up.vivoglobal.com.": {},
- "asia-gamecenter.vivoglobal.com.": {},
- "asia-gsearch.vivoglobal.com.": {},
- "asia-magazineunlock.vivoglobal.com.": {},
- "asia-news-abroad-backstage-interface.vivoglobal.com.": {},
- "asia-news-abroad.vivo.com.": {},
- "asia-p.vivoglobal.com.": {},
- "asia-ro-up.vivoglobal.com.": {},
- "asia-rommc-api.vivoglobal.com.": {},
- "asia-romsp-unifyconfig.vivoglobal.com.": {},
- "asia-sms-api.vivoglobal.com.": {},
- "asia-st-romsp.vivoglobal.com.": {},
- "asia-st-sl.vivoglobal.com.": {},
- "asia-st-sysupgrade.vivoglobal.com.": {},
- "asia-stp.vivoglobal.com.": {},
- "asia-theme-api.vivoglobal.com.": {},
- "asia-timer-appstore.vivoglobal.com.": {},
- "asia-timesync.vivoglobal.com.": {},
- "asia-upload-appstore.vivoglobal.com.": {},
- "asia-usrsys-api.vivoglobal.com.": {},
- "asia-vgcmdm-api-tha.vivoglobal.com.": {},
- "asia-vnote.vivoglobal.com.": {},
- "asia-vpushonrt-stsdk.vivoglobal.com.": {},
- "asia-vpushort-stsdk.vivoglobal.com.": {},
- "asia-weather.vivoglobal.com.": {},
- "asia-wifi.vivoglobal.com.": {},
- "asia.remotepc.com.": {},
- "askprivate.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.": {},
- "asm-api-golocal-geo-uk-teams.trafficmanager.net.": {},
- "asm-api-prod-geo-am-skype.trafficmanager.net.": {},
- "asm-api-prod-geo-as-skype.trafficmanager.net.": {},
- "asm-api-prod-geo-eu-skype.trafficmanager.net.": {},
- "asm-api-prod-version-skype.trafficmanager.net.": {},
- "aspect-upush.umeng.com.": {},
- "asset.fwcdn3.com.": {},
- "asset.fwpub1.com.": {},
- "assets.a-mo.net.cdn.cloudflare.net.": {},
- "assets.api.stairwell.com.": {},
- "assets.apps.pa.gov.": {},
- "assets.fastly.carvana.io.": {},
- "assets.the-independent.com.": {},
- "assets0.procore.com.": {},
- "assets1.procore.com.": {},
- "assets2.procore.com.": {},
- "assets3.procore.com.": {},
- "assistant-dre.op.hicloud.com.": {},
- "astat.bugly.qcloud.com.": {},
- "async-motiondetection-us-1d.oss-us-west-1.aliyuncs.com.": {},
- "asyncim.zoom.us.": {},
- "atemda.com.": {},
- "ati.com.": {},
- "atipt-my.sharepoint.com.": {},
- "atipt.sharepoint.com.": {},
- "atlanta.remotepc.com.": {},
- "atlanta2.remotepc.com.": {},
- "atlanta3.remotepc.com.": {},
- "atlanta4.remotepc.com.": {},
- "atolin.ru.": {},
- "atriaseniorliving-my.sharepoint.com.": {},
- "au-prod.asyncgw.teams.microsoft.com.": {},
- "auburnschools-my.sharepoint.com.": {},
- "auckland.remotepc.com.": {},
- "audid.umeng.com.": {},
- "audio.vivintsky.com.": {},
- "audioscrobbler.com.": {},
- "audiostatlog.cc.easebar.com.": {},
- "auth-asg-en.aliyuncs.com.": {},
- "auth.bereal.com.": {},
- "auth.bereal.team.": {},
- "auth.hulu.com.": {},
- "auth.jbisumari.org.": {},
- "auth.riotgames.com.cdn.cloudflare.net.": {},
- "automate.itsasap.com.": {},
- "autonavi.com.": {},
- "autotrack.studyquicks.com.": {},
- "avalanche.autotrader.co.uk.": {},
- "avatar-us-1.kwcdn.com.": {},
- "avis-app.quantummetric.com.": {},
- "azchicago.remotepc.com.": {},
- "azchicago2.remotepc.com.": {},
- "azdcs-my.sharepoint.com.": {},
- "azioncdn.net.": {},
- "azmatch.adsrvr.org.": {},
- "azureford-my.sharepoint.com.": {},
- "azureford.sharepoint.com.": {},
- "azwus1-client-s.gateway.messenger.live.com.": {},
- "b.fssta.com.": {},
- "b.tile.openstreetmap.org.": {},
- "b.tile.osm.org.": {},
- "babico.name.tr.": {},
- "bablosoft.com.": {},
- "backend-l.deepl.com.": {},
- "badambiz.com.": {},
- "badoo.app.": {},
- "bahrain.remotepc.com.": {},
- "baike.com.": {},
- "baishan-cloud.net.": {},
- "ballstate-my.sharepoint.com.": {},
- "baltimore.remotepc.com.": {},
- "bam.nr-data.net.cdn.cloudflare.net.": {},
- "bangalore2.remotepc.com.": {},
- "bangalore3.remotepc.com.": {},
- "bangalore4.remotepc.com.": {},
- "bangkok.remotepc.com.": {},
- "bankozarks-my.sharepoint.com.": {},
- "bankwithunited-my.sharepoint.com.": {},
- "bankwithunited.sharepoint.com.": {},
- "baptisthealth-my.sharepoint.com.": {},
- "baptisthealth.sharepoint.com.": {},
- "barstoolsports.com.": {},
- "basised-my.sharepoint.com.": {},
- "batch.pbisrewards.com.": {},
- "bb.eight-cdn.com.": {},
- "bd1cec50-00d1-4ce9-9572-785857419a1e.prmutv.co.": {},
- "bdpnt-my.sharepoint.com.": {},
- "bdpnt.sharepoint.com.": {},
- "bdreporting.com.": {},
- "be.nortic.ogtic.gob.do.": {},
- "beacon-api.aliyuncs.com.": {},
- "beacon-sin1.rubiconproject.com.": {},
- "beacon.qq.com.": {},
- "beacons4.gvt2.com.": {},
- "beacons5.gvt2.com.": {},
- "beam.vivintsky.com.": {},
- "becn-my.sharepoint.com.": {},
- "becn.sharepoint.com.": {},
- "becpsn-my.sharepoint.com.": {},
- "becpsn.sharepoint.com.": {},
- "beizi.biz.": {},
- "belgium.remotepc.com.": {},
- "belgrad.remotepc.com.": {},
- "bend.remotepc.com.": {},
- "berryglobal-my.sharepoint.com.": {},
- "betting-api.onefootball.com.": {},
- "bgtfs.transitapp.com.": {},
- "bhsjaxinc0-my.sharepoint.com.": {},
- "bidder.adquery.io.": {},
- "bifrost.vivaldi.com.": {},
- "bik.gov.tr.": {},
- "biomerieux-my.sharepoint.com.": {},
- "biomerieux.sharepoint.com.": {},
- "bisdus-my.sharepoint.com.": {},
- "bitwarden.com.": {},
- "bkdllp-my.sharepoint.com.": {},
- "bkdllp.sharepoint.com.": {},
- "bl6pap003.storage.live.com.": {},
- "bl6pap003files.storage.live.com.": {},
- "bl6pap004.storage.live.com.": {},
- "bl6pap004files.storage.live.com.": {},
- "black-cat.crypto.com.": {},
- "blackboard.com.": {},
- "blackbox.dropbox-dns.com.": {},
- "blocksi-screenshots-us.s3.us-east-005.backblazeb2.com.": {},
- "blooket.com.multicdn.cloudinary.com.": {},
- "blueshieldca-my.sharepoint.com.": {},
- "blueshieldca.sharepoint.com.": {},
- "bluffdale.remotepc.com.": {},
- "blz04pap001.storage.live.com.": {},
- "blz04pap001files.storage.live.com.": {},
- "blz04pap002.storage.live.com.": {},
- "blz04pap003.storage.live.com.": {},
- "blz04pap004.storage.live.com.": {},
- "blz04pap005.storage.live.com.": {},
- "blz04pap006.storage.live.com.": {},
- "bmaus.bumble.com.": {},
- "bmoolbb-app.quantummetric.com.": {},
- "bmrn-my.sharepoint.com.": {},
- "bmrn.sharepoint.com.": {},
- "bn02pap001.storage.live.com.": {},
- "bn02pap001files.storage.live.com.": {},
- "bn1files.storage.live.com.": {},
- "bn3pap090files.storage.live.com.": {},
- "bna365-my.sharepoint.com.": {},
- "bnz05pap001.storage.live.com.": {},
- "bnz05pap001files.storage.live.com.": {},
- "bnz05pap002.storage.live.com.": {},
- "bnz05pap002files.storage.live.com.": {},
- "bnz06pap001.storage.live.com.": {},
- "bnz06pap001files.storage.live.com.": {},
- "bnz06pap002.storage.live.com.": {},
- "bnz06pap002files.storage.live.com.": {},
- "bnz06pap003.storage.live.com.": {},
- "bnz06pap003files.storage.live.com.": {},
- "bnz06pap004.storage.live.com.": {},
- "bnz06pap004files.storage.live.com.": {},
- "bnz07pap001.storage.live.com.": {},
- "bnz07pap001files.storage.live.com.": {},
- "bobble.ai.": {},
- "books-analytics-events.apple.com.": {},
- "booksy.com.": {},
- "bootstrapcdn.com.": {},
- "borgwarner-my.sharepoint.com.": {},
- "borgwarner.sharepoint.com.": {},
- "boston.remotepc.com.": {},
- "boston2.remotepc.com.": {},
- "bostonglobe.com.": {},
- "box.com.": {},
- "box.net.": {},
- "boxcloud.com.": {},
- "br.chat.si.riotgames.com.": {},
- "brand-assets.ringcentral.com.": {},
- "bratislava.remotepc.com.": {},
- "breitbart.com.": {},
- "brenntag01-my.sharepoint.com.": {},
- "brenntag01.sharepoint.com.": {},
- "brenntag01nam-my.sharepoint.com.": {},
- "brenntag01nam.sharepoint.com.": {},
- "bridge2bwb.com.": {},
- "bridgetonorg-my.sharepoint.com.": {},
- "broadstreetads.com.": {},
- "bscedge.com.": {},
- "bsprings.remotepc.com.": {},
- "bt.moack.co.kr.": {},
- "bthfa.jenzabarcloud.com.": {},
- "btrace.qq.com.": {},
- "bucharest.remotepc.com.": {},
- "bucharest1.remotepc.com.": {},
- "budapest.remotepc.com.": {},
- "buenosaires.remotepc.com.": {},
- "bugly.qcloud.com.": {},
- "bugreport.huorong.cn.": {},
- "bundler.nice-team.net.": {},
- "bunny.net.": {},
- "burbankschooldistrict111-my.sharepoint.com.": {},
- "burnsmcd-my.sharepoint.com.": {},
- "burnsmcd.sharepoint.com.": {},
- "businesswire.com.": {},
- "bw1-my.sharepoint.com.": {},
- "bw1.sharepoint.com.": {},
- "bwatch.bergankdv.com.": {},
- "bytecdn.cn.": {},
- "bytedance.net.": {},
- "c.4dex.io.": {},
- "c.fakespot.io.": {},
- "c.footprint.net.": {},
- "c.pub.network.": {},
- "c.tile.openstreetmap.org.": {},
- "c.tile.osm.org.": {},
- "c1.ttcache.com.": {},
- "c2.ttcache.com.": {},
- "c2c.wechat.com.": {},
- "c3.ttcache.com.": {},
- "c4.ttcache.com.": {},
- "c7l.cyberhaven.io.": {},
- "ca-prod.asyncgw.teams.microsoft.com.": {},
- "ca-tor-anx-r005.router.teamviewer.com.": {},
- "ca.gov.": {},
- "ca000.backblaze.com.": {},
- "ca001.backblaze.com.": {},
- "ca002.backblaze.com.": {},
- "ca80a1adb12a4fbdac5ffcbc944e9a61.pacloudflare.com.": {},
- "cachenetworks.com.": {},
- "cachingserviceapimpme.azure-api.net.": {},
- "cainiao.com.": {},
- "caixa.gov.br.": {},
- "california.remotepc.com.": {},
- "california2.remotepc.com.": {},
- "caltech.edu.": {},
- "camsoda.com.": {},
- "canada.remotepc.com.": {},
- "canberra.remotepc.com.": {},
- "capetown.remotepc.com.": {},
- "cardiff.remotepc.com.": {},
- "cardinalcorp-my.sharepoint.com.": {},
- "care.novaicare.com.": {},
- "caridisini.site.": {},
- "carystudio.com.": {},
- "cat.hbwrapper.com.": {},
- "cat2.hbwrapper.com.": {},
- "cavai.com.": {},
- "ccboemd-my.sharepoint.com.": {},
- "ccf.ivalua.com.": {},
- "cchmc-my.sharepoint.com.": {},
- "cchmc.sharepoint.com.": {},
- "ccs.umeng.com.": {},
- "ccsyncuuid.net.": {},
- "cdn-audio-gcp-media.getepic.com.": {},
- "cdn-c.bereal.network.": {},
- "cdn-f.heylink.me.": {},
- "cdn-gcp-media-drm.getepic.com.": {},
- "cdn-gcp-media.getepic.com.": {},
- "cdn-league-logos.theathletic.com.": {},
- "cdn-mc-eu1-fd5f74b2.bereal.network.": {},
- "cdn-t.vb24131crasosnemesis.com.": {},
- "cdn-us.algoliaradar.com.": {},
- "cdn-us1.bereal.network.": {},
- "cdn-video-gcp-media.getepic.com.": {},
- "cdn.bereal.network.": {},
- "cdn.ckeditor.com.": {},
- "cdn.conveythis.com.": {},
- "cdn.deepintent.com.": {},
- "cdn.fera.ai.": {},
- "cdn.ftd.agency.": {},
- "cdn.groupbycloud.com.": {},
- "cdn.hw.gcloudcs.com.": {},
- "cdn.instapagemetrics.com.": {},
- "cdn.overleaf.com.": {},
- "cdn.production.dochub.com.": {},
- "cdn.qq.com.": {},
- "cdn.rebuyengine.com.": {},
- "cdn.sierrapacificgroup.com.": {},
- "cdn.tapdb-dev.com.": {},
- "cdn.uxfeedback.ru.": {},
- "cdn1.wixdns.net.": {},
- "cdn140.picsart.com.": {},
- "cdn26.vizury.com.": {},
- "cdn271.picsart.com.": {},
- "cdnetworks.net.": {},
- "cdngeneral.rentcafe.com.": {},
- "cdngslb.com.": {},
- "cdns3.gigya.com.": {},
- "cdntm.hsbc.co.uk.": {},
- "cdnwidget.com.": {},
- "cds.swishapps.ai.": {},
- "cdt.ca.gov.": {},
- "cdtfa.ca.gov.": {},
- "cdxdns.com.": {},
- "cdxflare.com.": {},
- "cedexis-test.com.": {},
- "cedock.com.": {},
- "centertime.ksyun.com.": {},
- "centralmichigan-my.sharepoint.com.": {},
- "centrexit.com.": {},
- "cfa.fidelity.com.": {},
- "cform.loyalhealth.com.": {},
- "changehealthcare.com.": {},
- "channel5.com.": {},
- "charlotte.remotepc.com.": {},
- "check.unity.cn.": {},
- "check2.lloydsbank.co.uk.": {},
- "chennai.remotepc.com.": {},
- "chi01pap001.storage.live.com.": {},
- "chi01pap001files.storage.live.com.": {},
- "chi01pap002.storage.live.com.": {},
- "chi01pap002files.storage.live.com.": {},
- "chicago.remotepc.com.": {},
- "chicago2.remotepc.com.": {},
- "childrensmercy-my.sharepoint.com.": {},
- "childrensmercy.sharepoint.com.": {},
- "chinacache.net.": {},
- "chinaccl-a.haplat.net.": {},
- "chinaccl-b.haplat.net.": {},
- "chinaccl-c.haplat.net.": {},
- "choctawnationofoklahoma-my.sharepoint.com.": {},
- "choctawnationofoklahoma.sharepoint.com.": {},
- "chtsite.com.": {},
- "chubbgroup-my.sharepoint.com.": {},
- "chubbgroup.sharepoint.com.": {},
- "chumley.barstoolsports.com.": {},
- "cico.com.": {},
- "cinarra.com.": {},
- "cintas1-my.sharepoint.com.": {},
- "cintas1.sharepoint.com.": {},
- "cis.citrix.com.": {},
- "cisco-my.sharepoint.com.": {},
- "cisco.app.box.com.": {},
- "cisco.sharepoint.com.": {},
- "citrix.com.": {},
- "cityofelpaso-my.sharepoint.com.": {},
- "cjfgob-my.sharepoint.com.": {},
- "cl-data.ads.heytapmobi.com.": {},
- "cl2009.com.": {},
- "claude.ai.": {},
- "clearesult5-my.sharepoint.com.": {},
- "clearesult5.sharepoint.com.": {},
- "cleveland.remotepc.com.": {},
- "clevelandclinic-my.sharepoint.com.": {},
- "clevelandclinic.sharepoint.com.": {},
- "client-log.box.com.": {},
- "client-tracking.omiapp.me.": {},
- "client-updates.lumu.io.": {},
- "cliftonlarsonallen-my.sharepoint.com.": {},
- "cliftonlarsonallen.sharepoint.com.": {},
- "cloud-config-service.rtc.aliyuncs.com.": {},
- "cloud-rest.lenovomm.com.": {},
- "cloud.browser.360.cn.": {},
- "cloud.huawei.asia.": {},
- "cloud.ibm.com.": {},
- "cloud.typenetwork.com.": {},
- "cloud.vmp.onezapp.com.": {},
- "cloud.zoom.us.": {},
- "cloudbirds.cn.": {},
- "clouddata.turbowarp.org.": {},
- "cloudlinks.cn.": {},
- "cloudsvc.policypak.com.": {},
- "cloverparksd-my.sharepoint.com.": {},
- "cloverparksd.sharepoint.com.": {},
- "cm-x.mgid.com.": {},
- "cmgate.vip.qq.com.": {},
- "cmpassport.com.": {},
- "cms.ejoyspace.com.": {},
- "cn-beijing.log.aliyuncs.com.": {},
- "cn-hangzhou.log.aliyuncs.com.": {},
- "cn-hangzhou.oss-cdn.aliyun-inc.com.": {},
- "cn-hongkong.log.aliyuncs.com.": {},
- "cn-shanghai.log.aliyuncs.com.": {},
- "cn.gcloudcs.com.": {},
- "cn.mvconf.50union.com.": {},
- "cname.pendo.io.": {},
- "cnmc-my.sharepoint.com.": {},
- "cnmc.sharepoint.com.": {},
- "cnv2.mclean.50union.com.": {},
- "cnzz.com.": {},
- "co-vcode-od.vivoglobal.com.": {},
- "co.amx.rcs.telephony.goog.": {},
- "codacloud.net.": {},
- "code.etracker.com.": {},
- "codis-bak.ngb.haplat.net.": {},
- "codis.ngb.haplat.net.": {},
- "cofile.net.": {},
- "cohnreznick-my.sharepoint.com.": {},
- "cohnreznick.sharepoint.com.": {},
- "collect-v6.51.la.": {},
- "collect.trendyol.com.": {},
- "collector-api.frspecifics.com.": {},
- "collector.wdp.brave.com.": {},
- "colliervilleschools-my.sharepoint.com.": {},
- "columbus.remotepc.com.": {},
- "columbusk12oh-my.sharepoint.com.": {},
- "columbusk12oh.sharepoint.com.": {},
- "com.multicdn.cloudinary.com.": {},
- "com.yangyi19.com.": {},
- "cometservd1.pb.com.": {},
- "commerce.safe.360.cn.": {},
- "commercial.ocsp.identrust.com.": {},
- "common-afd.fe.1drv.com.": {},
- "common-afdrk.fe.1drv.com.": {},
- "common.xshareapp.com.": {},
- "compass.corebridgefinancial.com.": {},
- "compiles.overleafusercontent.com.": {},
- "config-inmobi-comtm.trafficmanager.net.": {},
- "config-security.com.": {},
- "config.a-m-p.xyz.": {},
- "config.inmobi.com.": {},
- "config.office.net.": {},
- "config.y5en.com.": {},
- "config2.cmpassport.com.": {},
- "configdl.teamviewer.com.": {},
- "conn-service-cn-03.allawntech.com.": {},
- "connect.garenanow.com.": {},
- "connectivitycheck.unisoc.com.": {},
- "consist.co.il.": {},
- "constel1-my.sharepoint.com.": {},
- "constel1.sharepoint.com.": {},
- "consumer-pepsico.okta.com.": {},
- "content-management-files.canva.com.": {},
- "content.citizensbankonline.com.": {},
- "content.discover.com.": {},
- "content.discovercard.com.": {},
- "content.ebanking-services.com.": {},
- "content.gap.com.": {},
- "content.lloydsbankinggroup.com.": {},
- "content.maxconnector.com.": {},
- "content.production.cdn.art19.com.": {},
- "content.ssctech.com.": {},
- "content22.bmo.com.": {},
- "content22.citibankonline.com.": {},
- "content22.citicards.com.": {},
- "content22.online.citi.com.": {},
- "context.reverso.net.": {},
- "control-out.mna.qq.com.": {},
- "cookie-sync.bidmyadz.com.": {},
- "coolkit.cc.": {},
- "copenhagen.remotepc.com.": {},
- "cordial.com.": {},
- "core.cdn.procore.com.": {},
- "core.gssv-play-prod.xboxlive.com.": {},
- "core.iprom.net.": {},
- "core.omiapp.me.": {},
- "corebridgefinancial-my.sharepoint.com.": {},
- "covers.vitalbook.com.": {},
- "coxauto.okta.com.": {},
- "cp.az.hmgroup.com.": {},
- "cp2.cloudflare.com.": {},
- "cpm.appocean.media.": {},
- "cpm.aserve1.net.": {},
- "cpm.qortex.ai.": {},
- "cpm.vuukle.net.": {},
- "cpm.xrtb.io.": {},
- "cpr-pusa01.app.blackbaud.net.": {},
- "cpx-research.com.": {},
- "cr00.biz.": {},
- "crash.xiaohongshu.com.": {},
- "crashlytics.com.": {},
- "crashsight.qq.com.": {},
- "crashsight.wetest.net.": {},
- "crobox.com.": {},
- "crobox.io.": {},
- "crossforward.com.": {},
- "crowd.transitapp.com.": {},
- "crowncastle-my.sharepoint.com.": {},
- "crowncastle.sharepoint.com.": {},
- "crush.163.com.": {},
- "crutchfield.com.": {},
- "cs.globalsun.io.": {},
- "csdn.net.": {},
- "cshealthforlife.com.": {},
- "cstse02.ultipro.com.": {},
- "cstsew02.ultipro.com.": {},
- "cstsn02.ultipro.com.": {},
- "ct.pinterest.com.": {},
- "cta-eu1.hubspot.com.": {},
- "cuco.softi9.pt.": {},
- "cummins365-my.sharepoint.com.": {},
- "cummins365.sharepoint.com.": {},
- "cunamutual-my.sharepoint.com.": {},
- "cunamutual.sharepoint.com.": {},
- "cust-dv.zentrick.com.": {},
- "customer.homedepot.com.": {},
- "cwc-my.sharepoint.com.": {},
- "cwc.sharepoint.com.": {},
- "cx.soft.360.cn.": {},
- "cx732.com.": {},
- "czechrepublic.remotepc.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.": {},
- "d3tracking.rbc.com.": {},
- "d6-gd.static.yximgs.com.": {},
- "d6691a17-6fdb-4d26-85d6-b3dd27f55f08.prmutv.co.": {},
- "d82f7a30-751a-4689-b7e9-19336a89ab46.prmutv.co.": {},
- "d837da8d.cloudsrv.minerva-labs.com.": {},
- "d9npma-inapps.appsflyersdk.com.": {},
- "da.toponadss.com.": {},
- "daemon.nanoleaf.me.": {},
- "daf.xp.apple.com.": {},
- "dallas.remotepc.com.": {},
- "dallas2.remotepc.com.": {},
- "dallas3.remotepc.com.": {},
- "dallas4.remotepc.com.": {},
- "dallas5.remotepc.com.": {},
- "dallaschildrens-my.sharepoint.com.": {},
- "dallaschildrens.sharepoint.com.": {},
- "dalu-my.sharepoint.com.": {},
- "dantri.com.vn.": {},
- "darden-sync.quantummetric.com.": {},
- "data-detect.nie.easebar.com.": {},
- "data.analytics.thomsonreuters.com.": {},
- "data.analytics.ux.quickbase.com.": {},
- "data.assist.chromeriver.com.": {},
- "data.bhrpendo.bamboohr.com.": {},
- "data.cw.edgenuity.com.": {},
- "data.dap.paylocity.com.": {},
- "data.data.achieve3000.com.": {},
- "data.data.aleks.com.": {},
- "data.data.mheducation.com.": {},
- "data.guide-app.zoominfo.co.": {},
- "data.guides.oncoursesystems.com.": {},
- "data.guides.percipio.com.": {},
- "data.guides.wdesk.com.": {},
- "data.hockeystack.com.": {},
- "data.investing.com.": {},
- "data.ipd.goto.com.": {},
- "data.kuiniuca.com.": {},
- "data.meitu.com.": {},
- "data.pendo-cdn.pluralsight.com.": {},
- "data.pendo-cobalt.westlaw.com.": {},
- "data.pendo-tracking.seismic.com.": {},
- "data.pendo.careporthealth.com.": {},
- "data.pendo.gomotive.com.": {},
- "data.pendo.looker.app.": {},
- "data.pendo.navimedix.com.": {},
- "data.pendo.progresslearning.com.": {},
- "data.pendo.statista.com.": {},
- "data.pendo.udsrv.com.": {},
- "data.pnd.liveperson.com.": {},
- "data.productanalytics.coconutcalendar.com.": {},
- "data.tracking.billtrust.com.": {},
- "data00.adlooxtracking.com.": {},
- "datamma.guides.nelnet.com.": {},
- "datasite.com.": {},
- "datatechdrift.com.": {},
- "datatheorem.com.": {},
- "db.onlinewebfonts.com.": {},
- "db3pap002.storage.live.com.": {},
- "db3pap003.storage.live.com.": {},
- "db3pap004.storage.live.com.": {},
- "db3pap006.storage.live.com.": {},
- "db3pap007.storage.live.com.": {},
- "db5pap001.storage.live.com.": {},
- "dc.di.atlas.samsung.com.": {},
- "dc.dqa.samsung.com.": {},
- "dc.wondershare.com.": {},
- "dcs-live.mp.lura.live.": {},
- "dcs-png.mp.lura.live.": {},
- "dcs-vod.mp.lura.live.": {},
- "dcs110-mcdn.mp.lura.live.": {},
- "dd.browser.360.cn.": {},
- "dd.meituan.com.": {},
- "ddata.huntingtonbank.com.": {},
- "dds.autodesk.com.": {},
- "de-idm.api.io.mi.com.": {},
- "de-prod.asyncgw.teams.microsoft.com.": {},
- "de.dt.rcs.telephony.goog.": {},
- "dealer.autopartners.net.": {},
- "dealmoon.com.": {},
- "decagon.ai.": {},
- "deepl.com.": {},
- "deliveroo.com.": {},
- "delivery.api.getadmiral.com.": {},
- "delivery.upremium.asia.": {},
- "dell-prod.actioniq.mr-in.com.": {},
- "delta.quantummetric.com.": {},
- "demant-my.sharepoint.com.": {},
- "demant.sharepoint.com.": {},
- "demeter-int-ecom-collect.trendyol.com.": {},
- "dentonstudent-my.sharepoint.com.": {},
- "denver.remotepc.com.": {},
- "dev2.keepsolid.com.": {},
- "deviceops.hstgps.com.": {},
- "dewmobile.net.": {},
- "dfaklj.tech.": {},
- "dfamilk-my.sharepoint.com.": {},
- "dfamilk.sharepoint.com.": {},
- "dfme.kleinanzeigen.de.": {},
- "dialpad.com.": {},
- "dickssportinggoods-app.quantummetric.com.": {},
- "dickssportinggoods-sync.quantummetric.com.": {},
- "dict.deepl.com.": {},
- "dict.ntes53.netease.com.": {},
- "dictvip-business.youdao.com.": {},
- "digiapp.vietcombank.com.vn.": {},
- "digiboy.ir.": {},
- "diligent.count.ly.": {},
- "dingtalk.com.": {},
- "dir.4.401402081.west-gcloud.codm.activision.com.": {},
- "direct.quic-proxy-gcpsg-v3.gcpsg.byteglb.com.": {},
- "discovery.ringcentral.biz.": {},
- "dispatcher.omiapp.me.": {},
- "dispatchosglobal.yuanshen.com.": {},
- "distservp1.pb.com.": {},
- "dl.boxcloud.com.": {},
- "dl.gmx.ch.": {},
- "dls-udc.dqa.samsung.com.": {},
- "dls.di.atlas.samsung.com.": {},
- "dm-us.hybrid.ai.": {},
- "dm1files.storage.live.com.": {},
- "dm2pap090files.storage.live.com.": {},
- "dmongo.adgrid.io.": {},
- "dns-e.ns4v.icu.": {},
- "dns-tunnel-check.googlezip.net.": {},
- "dns.alidns.com.": {},
- "dns101.register.com.": {},
- "dns23.llnwi.net.": {},
- "doceditor.wrike.com.": {},
- "docer-api.wps.cn.": {},
- "docs.live.net.": {},
- "document360.io.": {},
- "domaincfg.vivoglobal.com.": {},
- "donaldson-my.sharepoint.com.": {},
- "donaldson.sharepoint.com.": {},
- "donewyork1.remotepc.com.": {},
- "donewyork2.remotepc.com.": {},
- "donewyork3.remotepc.com.": {},
- "dorchester2-my.sharepoint.com.": {},
- "dorchester2.sharepoint.com.": {},
- "dosfo1.remotepc.com.": {},
- "dosfo2.remotepc.com.": {},
- "download.2.401402081.west-gcloud.codm.activision.com.": {},
- "download.avira.com.": {},
- "download.teamviewer.com.": {},
- "downloadcenter.genetec.com.": {},
- "downloads.vivaldi.com.": {},
- "dp.barclaysus.com.": {},
- "dp.im.weibo.cn.": {},
- "dpf.authorize.net.": {},
- "dpkg.mp.lura.live.": {},
- "dpool.sina.com.cn.": {},
- "dprprod-my.sharepoint.com.": {},
- "dprprod.sharepoint.com.": {},
- "dr.netease.im.": {},
- "dragate-cn.dc.heytapmobi.com.": {},
- "drfdisvc.walmart.com.": {},
- "drfirst.com.": {},
- "drsquatch.com.": {},
- "dsa-eu.hybrid.ai.": {},
- "dsm01pap001.storage.live.com.": {},
- "dsm01pap001files.storage.live.com.": {},
- "dsm01pap002.storage.live.com.": {},
- "dsm01pap002files.storage.live.com.": {},
- "dsm01pap003.storage.live.com.": {},
- "dsm01pap003files.storage.live.com.": {},
- "dsm01pap004.storage.live.com.": {},
- "dsm01pap004files.storage.live.com.": {},
- "dsm01pap005.storage.live.com.": {},
- "dsm01pap005files.storage.live.com.": {},
- "dsm01pap006.storage.live.com.": {},
- "dsm01pap006files.storage.live.com.": {},
- "dsm01pap007.storage.live.com.": {},
- "dsm01pap007files.storage.live.com.": {},
- "dsm01pap008.storage.live.com.": {},
- "dsm01pap008files.storage.live.com.": {},
- "dsm01pap009.storage.live.com.": {},
- "dsm01pap009files.storage.live.com.": {},
- "dsm01pap090files.storage.live.com.": {},
- "dsm04pap001.storage.live.com.": {},
- "dsm04pap001files.storage.live.com.": {},
- "dsm04pap002.storage.live.com.": {},
- "dsm04pap002files.storage.live.com.": {},
- "dsm04pap003.storage.live.com.": {},
- "dsm04pap003files.storage.live.com.": {},
- "dsp.tec-do.cn.": {},
- "dss.hybrid.ai.": {},
- "dstillery.com.": {},
- "dtscout.com.": {},
- "dualspaceapi.com.": {},
- "dub01pap001.storage.live.com.": {},
- "dub01pap002.storage.live.com.": {},
- "dub01pap003.storage.live.com.": {},
- "dub06pap001.storage.live.com.": {},
- "dub07pap001.storage.live.com.": {},
- "dub07pap002.storage.live.com.": {},
- "dubai.remotepc.com.": {},
- "dublin.remotepc.com.": {},
- "dun.163yun.com.": {},
- "dv.extremereach.com.": {},
- "dypnsapi.aliyuncs.com.": {},
- "dz.cyberhaven.io.": {},
- "e-10220.adzerk.net.": {},
- "e-189.21cn.com.": {},
- "e.189.cn.": {},
- "e.cdnwidget.com.": {},
- "e.userflow.com.": {},
- "e.viously.com.": {},
- "e1cef1f0-495f-4973-ba1c-880786e73a66.prmutv.co.": {},
- "e2c1.gcp.gvt2.com.": {},
- "e2c10.gcp.gvt2.com.": {},
- "e2c11.gcp.gvt2.com.": {},
- "e2c12.gcp.gvt2.com.": {},
- "e2c13.gcp.gvt2.com.": {},
- "e2c14.gcp.gvt2.com.": {},
- "e2c15.gcp.gvt2.com.": {},
- "e2c16.gcp.gvt2.com.": {},
- "e2c17.gcp.gvt2.com.": {},
- "e2c18.gcp.gvt2.com.": {},
- "e2c19.gcp.gvt2.com.": {},
- "e2c2.gcp.gvt2.com.": {},
- "e2c20.gcp.gvt2.com.": {},
- "e2c21.gcp.gvt2.com.": {},
- "e2c22.gcp.gvt2.com.": {},
- "e2c23.gcp.gvt2.com.": {},
- "e2c24.gcp.gvt2.com.": {},
- "e2c25.gcp.gvt2.com.": {},
- "e2c26.gcp.gvt2.com.": {},
- "e2c27.gcp.gvt2.com.": {},
- "e2c28.gcp.gvt2.com.": {},
- "e2c29.gcp.gvt2.com.": {},
- "e2c3.gcp.gvt2.com.": {},
- "e2c30.gcp.gvt2.com.": {},
- "e2c31.gcp.gvt2.com.": {},
- "e2c32.gcp.gvt2.com.": {},
- "e2c33.gcp.gvt2.com.": {},
- "e2c34.gcp.gvt2.com.": {},
- "e2c35.gcp.gvt2.com.": {},
- "e2c36.gcp.gvt2.com.": {},
- "e2c37.gcp.gvt2.com.": {},
- "e2c38.gcp.gvt2.com.": {},
- "e2c39.gcp.gvt2.com.": {},
- "e2c4.gcp.gvt2.com.": {},
- "e2c40.gcp.gvt2.com.": {},
- "e2c41.gcp.gvt2.com.": {},
- "e2c42.gcp.gvt2.com.": {},
- "e2c43.gcp.gvt2.com.": {},
- "e2c44.gcp.gvt2.com.": {},
- "e2c45.gcp.gvt2.com.": {},
- "e2c46.gcp.gvt2.com.": {},
- "e2c47.gcp.gvt2.com.": {},
- "e2c48.gcp.gvt2.com.": {},
- "e2c49.gcp.gvt2.com.": {},
- "e2c5.gcp.gvt2.com.": {},
- "e2c50.gcp.gvt2.com.": {},
- "e2c51.gcp.gvt2.com.": {},
- "e2c52.gcp.gvt2.com.": {},
- "e2c53.gcp.gvt2.com.": {},
- "e2c54.gcp.gvt2.com.": {},
- "e2c55.gcp.gvt2.com.": {},
- "e2c56.gcp.gvt2.com.": {},
- "e2c57.gcp.gvt2.com.": {},
- "e2c58.gcp.gvt2.com.": {},
- "e2c59.gcp.gvt2.com.": {},
- "e2c6.gcp.gvt2.com.": {},
- "e2c60.gcp.gvt2.com.": {},
- "e2c61.gcp.gvt2.com.": {},
- "e2c62.gcp.gvt2.com.": {},
- "e2c63.gcp.gvt2.com.": {},
- "e2c64.gcp.gvt2.com.": {},
- "e2c65.gcp.gvt2.com.": {},
- "e2c66.gcp.gvt2.com.": {},
- "e2c67.gcp.gvt2.com.": {},
- "e2c68.gcp.gvt2.com.": {},
- "e2c69.gcp.gvt2.com.": {},
- "e2c7.gcp.gvt2.com.": {},
- "e2c70.gcp.gvt2.com.": {},
- "e2c71.gcp.gvt2.com.": {},
- "e2c72.gcp.gvt2.com.": {},
- "e2c73.gcp.gvt2.com.": {},
- "e2c74.gcp.gvt2.com.": {},
- "e2c75.gcp.gvt2.com.": {},
- "e2c76.gcp.gvt2.com.": {},
- "e2c77.gcp.gvt2.com.": {},
- "e2c78.gcp.gvt2.com.": {},
- "e2c79.gcp.gvt2.com.": {},
- "e2c8.gcp.gvt2.com.": {},
- "e2c9.gcp.gvt2.com.": {},
- "e2cs01.gcp.gvt2.com.": {},
- "e2cs02.gcp.gvt2.com.": {},
- "e2cs03.gcp.gvt2.com.": {},
- "e2cs04.gcp.gvt2.com.": {},
- "e2cs05.gcp.gvt2.com.": {},
- "e2cs06.gcp.gvt2.com.": {},
- "e2cs07.gcp.gvt2.com.": {},
- "e2cs08.gcp.gvt2.com.": {},
- "e2cs09.gcp.gvt2.com.": {},
- "e2cs10.gcp.gvt2.com.": {},
- "e2cs11.gcp.gvt2.com.": {},
- "e2cs12.gcp.gvt2.com.": {},
- "e2cs13.gcp.gvt2.com.": {},
- "e2cs14.gcp.gvt2.com.": {},
- "e2cs15.gcp.gvt2.com.": {},
- "e2cs16.gcp.gvt2.com.": {},
- "e2cs17.gcp.gvt2.com.": {},
- "e2cs18.gcp.gvt2.com.": {},
- "e2cs19.gcp.gvt2.com.": {},
- "e2cs20.gcp.gvt2.com.": {},
- "e2cs21.gcp.gvt2.com.": {},
- "e2cs22.gcp.gvt2.com.": {},
- "e2cs23.gcp.gvt2.com.": {},
- "e2cs24.gcp.gvt2.com.": {},
- "e2cs25.gcp.gvt2.com.": {},
- "e2cs26.gcp.gvt2.com.": {},
- "e2cs27.gcp.gvt2.com.": {},
- "e2cs28.gcp.gvt2.com.": {},
- "e2cs29.gcp.gvt2.com.": {},
- "e2cs30.gcp.gvt2.com.": {},
- "e2cs31.gcp.gvt2.com.": {},
- "e2cs32.gcp.gvt2.com.": {},
- "e2cs33.gcp.gvt2.com.": {},
- "e2cs34.gcp.gvt2.com.": {},
- "e2cs35.gcp.gvt2.com.": {},
- "e2cs36.gcp.gvt2.com.": {},
- "e2cs37.gcp.gvt2.com.": {},
- "e2cs38.gcp.gvt2.com.": {},
- "e2cs39.gcp.gvt2.com.": {},
- "e2cs40.gcp.gvt2.com.": {},
- "e2cs41.gcp.gvt2.com.": {},
- "e2cs42.gcp.gvt2.com.": {},
- "e2cs43.gcp.gvt2.com.": {},
- "e2cs44.gcp.gvt2.com.": {},
- "e2cs45.gcp.gvt2.com.": {},
- "e2cs46.gcp.gvt2.com.": {},
- "e2cs47.gcp.gvt2.com.": {},
- "e2cs48.gcp.gvt2.com.": {},
- "e2cs49.gcp.gvt2.com.": {},
- "e2cs50.gcp.gvt2.com.": {},
- "e2cs51.gcp.gvt2.com.": {},
- "e2cs52.gcp.gvt2.com.": {},
- "e2cs53.gcp.gvt2.com.": {},
- "e2cs54.gcp.gvt2.com.": {},
- "e2cs55.gcp.gvt2.com.": {},
- "e43.ultipro.com.": {},
- "e488cdb0-e7cb-4d91-9648-60d437d8e491.prmutv.co.": {},
- "e5de3d23065c4748b155c28e6fa36f3e.pacloudflare.com.": {},
- "e99.cyberhaven.io.": {},
- "eafd-footprint.elasticafd.net.": {},
- "eafddirect.msedge.net.": {},
- "eagle-my.sharepoint.com.": {},
- "eagle.sharepoint.com.": {},
- "eago9.cyberhaven.io.": {},
- "eap-log-cn.allawntech.com.": {},
- "easemob.com.": {},
- "easeus.com.": {},
- "eastmoney.com.": {},
- "eastus2-gas.guestconfiguration.azure.com.": {},
- "ebaypay-app.quantummetric.com.": {},
- "ebaypay-sync.quantummetric.com.": {},
- "ecatholic.com.": {},
- "ecom.wixapps.net.": {},
- "ecommerce.iap.unity3d.com.": {},
- "ecs-gallatin-c2s.trafficmanager.net.": {},
- "edba.brealtime.com.": {},
- "edge.api.brightcove.com.": {},
- "edge.txryan.com.": {},
- "edgecdn.ru.": {},
- "edgedl.me.gvt1.com.": {},
- "edgelocation.ivanticloud.com.": {},
- "edisonintl-my.sharepoint.com.": {},
- "edisonintl.sharepoint.com.": {},
- "editor.wix.com.": {},
- "editorial.femaledaily.com.": {},
- "education-certification.youdao.com.": {},
- "eduinsightacademy.com.": {},
- "efercro.com.": {},
- "efs.ultipro.com.": {},
- "egateway.ultipro.com.": {},
- "ehmc-my.sharepoint.com.": {},
- "ehmc.sharepoint.com.": {},
- "eisaihhc-my.sharepoint.com.": {},
- "ejoyspace.com.": {},
- "ek6rpv-cdn-settings.appsflyersdk.com.": {},
- "elal-service.consist.co.il.": {},
- "elaracaring-my.sharepoint.com.": {},
- "ele.me.": {},
- "elemecdn.com.": {},
- "elonuniversity-my.sharepoint.com.": {},
- "em-tr4ck-settings.airtrfx.com.": {},
- "email.plumbenefits.com.": {},
- "email.ticketsatwork.com.": {},
- "emailaptitude.com.": {},
- "emerson-my.sharepoint.com.": {},
- "emerson.sharepoint.com.": {},
- "emo.v-mate.mobi.": {},
- "empirecat-my.sharepoint.com.": {},
- "endpointprotector.com.": {},
- "engage.wixapps.net.": {},
- "engagementapi.skype.com.": {},
- "engine.monetate.net.": {},
- "ent.box.com.": {},
- "enterprise-app.quantummetric.com.": {},
- "envoy-ios-prod.getepic.com.": {},
- "envysion.com.": {},
- "epic1-my.sharepoint.com.": {},
- "epic1.sharepoint.com.": {},
- "epicmobile.ohsu.edu.": {},
- "epoch.cloud.": {},
- "eponesh.com.": {},
- "eportal.fda.gov.ph.": {},
- "epsnj-my.sharepoint.com.": {},
- "epsnj.sharepoint.com.": {},
- "errlog.umeng.com.": {},
- "errlogos.umeng.com.": {},
- "errnewlog.umeng.com.": {},
- "errnewlogos.umeng.com.": {},
- "errortracking.deepl.com.": {},
- "esignlive.com.": {},
- "esm.archive.org.": {},
- "esosuite.net.": {},
- "estafetamx-my.sharepoint.com.": {},
- "etracker.com.": {},
- "etsv2.datalake.gameloft.com.": {},
- "eu-aa.online-metrix.net.": {},
- "eu-api.asm.skype.com.": {},
- "eu-gamecenter.api.intl.miui.com.": {},
- "eu-prod.asyncgw.teams.microsoft.com.": {},
- "eu-push.api.intl.miui.com.": {},
- "eu.galleryapi.micloud.xiaomi.net.": {},
- "eu.mvconf.50union.com.": {},
- "eu.statusapi.micloud.xiaomi.net.": {},
- "eu1.badoo.com.": {},
- "eu1.bumble.com.": {},
- "eu1.ecdn2.bumbcdn.com.": {},
- "eu1a-excel-collab.officeapps.live.com.": {},
- "euc-excel-collab.officeapps.live.com.": {},
- "euc-powerpoint-collab.officeapps.live.com.": {},
- "europe-west6-sybogames-gke-prod.cloudfunctions.net.": {},
- "europe.remotepc.com.": {},
- "eus.his.arc.azure.com.": {},
- "eus.his.hybridcompute.trafficmanager.net.": {},
- "eus2.guestagentsvc-prod.trafficmanager.net.": {},
- "eus2.his.arc.azure.com.": {},
- "euw1.chat.si.riotgames.com.": {},
- "eve.gameloft.com.": {},
- "event-tracking-project.ap-southeast-1.log.aliyuncs.com.": {},
- "event.evtm.53.com.": {},
- "event.togothermany.com.": {},
- "events.paramount.tech.": {},
- "events.statsigapi.net.": {},
- "events.swishapps.ai.": {},
- "exappupgrade.vivoglobal.com.": {},
- "excel-collab.officeapps.live.com.": {},
- "exodus.desync.com.": {},
- "exorigos.com.": {},
- "exp.host.": {},
- "expedia-app.quantummetric.com.": {},
- "experian-my.sharepoint.com.": {},
- "experimental-api.asm.skype.com.": {},
- "explicit-explicit.bing.net.trafficmanager.net.": {},
- "exponential.com.": {},
- "expresspros-my.sharepoint.com.": {},
- "expresspros.sharepoint.com.": {},
- "extension.faro.speechify.dev.": {},
- "external-ams2-1.xx.fbcdn.net.": {},
- "external-ams4-1.xx.fbcdn.net.": {},
- "external-atl3-1.xx.fbcdn.net.": {},
- "external-atl3-2.xx.fbcdn.net.": {},
- "external-ber1-1.xx.fbcdn.net.": {},
- "external-bos5-1.xx.fbcdn.net.": {},
- "external-bru2-1.xx.fbcdn.net.": {},
- "external-den2-1.xx.fbcdn.net.": {},
- "external-dfw5-1.xx.fbcdn.net.": {},
- "external-dfw5-2.xx.fbcdn.net.": {},
- "external-dus1-1.xx.fbcdn.net.": {},
- "external-fra3-1.xx.fbcdn.net.": {},
- "external-fra3-2.xx.fbcdn.net.": {},
- "external-fra5-1.xx.fbcdn.net.": {},
- "external-fra5-2.xx.fbcdn.net.": {},
- "external-ham3-1.xx.fbcdn.net.": {},
- "external-hou1-1.xx.fbcdn.net.": {},
- "external-iad3-1.xx.fbcdn.net.": {},
- "external-iad3-2.xx.fbcdn.net.": {},
- "external-lax3-1.xx.fbcdn.net.": {},
- "external-lax3-2.xx.fbcdn.net.": {},
- "external-lga3-1.xx.fbcdn.net.": {},
- "external-lga3-2.xx.fbcdn.net.": {},
- "external-lhr6-1.xx.fbcdn.net.": {},
- "external-lhr6-2.xx.fbcdn.net.": {},
- "external-lhr8-1.xx.fbcdn.net.": {},
- "external-lhr8-2.xx.fbcdn.net.": {},
- "external-man2-1.xx.fbcdn.net.": {},
- "external-mia3-1.xx.fbcdn.net.": {},
- "external-mia3-2.xx.fbcdn.net.": {},
- "external-msp1-1.xx.fbcdn.net.": {},
- "external-muc2-1.xx.fbcdn.net.": {},
- "external-ord5-1.xx.fbcdn.net.": {},
- "external-ord5-2.xx.fbcdn.net.": {},
- "external-sea1-1.xx.fbcdn.net.": {},
- "external-sjc3-1.xx.fbcdn.net.": {},
- "external-vie1-1.xx.fbcdn.net.": {},
- "external-waw1-1.xx.fbcdn.net.": {},
- "extranet-ipv4-pub-azams.alb.xiaomi.com.": {},
- "ezcollab-my.sharepoint.com.": {},
- "ezcollab.sharepoint.com.": {},
- "f.hubspotusercontent00.net.": {},
- "fa000000076.resources.office.net.": {},
- "fa000000110.resources.office.net.": {},
- "fa1f96ab-b693-40e4-82d5-8698592ef9ac.prmutv.co.": {},
- "faas.marktplaats.nl.": {},
- "faceunity.com.": {},
- "factor.reg.163.com.": {},
- "factset.com.": {},
- "fanyiegg.youdao.com.": {},
- "fastformstax.prosystemfx.com.": {},
- "fastly-cloud.typenetwork.com.": {},
- "fastly.cedexis-test.com.": {},
- "fastquote.fidelity.com.": {},
- "faves.grow.me.": {},
- "fbinsmi.sharepoint.com.": {},
- "fdccpaadaptor.forddirectservices.com.": {},
- "fe.xiaohongshu.com.": {},
- "featuregates.org.": {},
- "fed.federate365.com.": {},
- "feedbackify.com.": {},
- "feeder.co.": {},
- "feelinsonice.l.google.com.": {},
- "fef.amsub0302.manage.microsoft.com.": {},
- "fef.fxpasu01.manage.microsoft.us.": {},
- "fef.msua09.manage.microsoft.com.": {},
- "fef.msub06.manage.microsoft.com.": {},
- "fef.msub07.manage.microsoft.com.": {},
- "femaledaily.com.": {},
- "fengkongcloud.com.": {},
- "ferringgroup-my.sharepoint.com.": {},
- "ferringgroup.sharepoint.com.": {},
- "festo-my.sharepoint.com.": {},
- "ff.nordcurrent.com.": {},
- "fgwn01.ultipro.com.": {},
- "fi.telephony.goog.": {},
- "field59.com.": {},
- "files.jotform.com.": {},
- "files.zohopublic.eu.": {},
- "filters.adavoid.org.": {},
- "finalsite.com.": {},
- "finalsite.net.": {},
- "firebase.sgp1.digitaloceanspaces.com.": {},
- "fireeye.com.": {},
- "fiscal.treasury.gov.": {},
- "five9.com.": {},
- "flashcards.vitalsource.com.": {},
- "fleet.todyl.com.": {},
- "flip.to.": {},
- "flixcdn.com.": {},
- "flocktory.com.": {},
- "flypgs.com.": {},
- "flyspirit-my.sharepoint.com.": {},
- "flyspirit.sharepoint.com.": {},
- "fm.printaudit.com.": {},
- "fmcna-my.sharepoint.com.": {},
- "fmcna.sharepoint.com.": {},
- "fn.us.ipqscdn.com.": {},
- "fo.iemiq.com.": {},
- "forcesafesearch.google.com.": {},
- "forksystems.mm.fcix.net.": {},
- "form.jotform.com.": {},
- "forms-eu1.hscollectedforms.net.": {},
- "forms-eu1.hsforms.com.": {},
- "forms-eu1.hubspot.com.": {},
- "forthepeople0-my.sharepoint.com.": {},
- "forthepeople0.sharepoint.com.": {},
- "fortisimperious.com.": {},
- "fortworth.remotepc.com.": {},
- "foundation-ipv4.youdao.com.": {},
- "fpbns.net.": {},
- "fpdlp.applxweb.com.": {},
- "fr-prod.asyncgw.teams.microsoft.com.": {},
- "fr1.ecdn2.bumbcdn.com.": {},
- "fran.frvr.com.": {},
- "franecki.net.": {},
- "frankfurt.remotepc.com.": {},
- "fremont.remotepc.com.": {},
- "freseniusmedicalcare.com.": {},
- "fresnocounty-my.sharepoint.com.": {},
- "fs.ultiproworkplace.com.": {},
- "fsu-my.sharepoint.com.": {},
- "fsu.sharepoint.com.": {},
- "fticonsulting-my.sharepoint.com.": {},
- "fticonsulting.sharepoint.com.": {},
- "ftke02.ultipro.com.": {},
- "ftkew02.ultipro.com.": {},
- "ftkn01.ultipro.com.": {},
- "ftkn02.ultipro.com.": {},
- "ftp.ext.hp.com.edgekey.net.": {},
- "ftpm.amd.com.": {},
- "fuk01.ps5.update.playstation.net.": {},
- "fusd-my.sharepoint.com.": {},
- "fusd.sharepoint.com.": {},
- "fxltsbl.com.": {},
- "g.fastcdn.co.": {},
- "g9hc4.cn.": {},
- "ga.badambiz.com.": {},
- "galaxy.safe.360.cn.": {},
- "galaxyappstore.com.": {},
- "galeapps.gale.com.": {},
- "gameloft.com.": {},
- "gamemonkey.org.": {},
- "gamepigeon.net.": {},
- "gatag.it.": {},
- "gateway.costar.com.": {},
- "gateway.ultiproworkplace.com.": {},
- "gb.ee.rcs.telephony.goog.": {},
- "gb.o2.rcs.telephony.goog.": {},
- "gbc-common.online.office.com.": {},
- "gbc-excel.officeapps.live.com.": {},
- "gcash-api.pulseid.com.": {},
- "gccmod.ecs.office.com.": {},
- "gcdn.co.": {},
- "gce-beacons.gcp.gvt2.com.": {},
- "gcloud.qq.com.": {},
- "gcloudcs.com.": {},
- "gcloudsdk.com.": {},
- "gcs.sc-cdn.net.": {},
- "gdid.datalake.gameloft.com.": {},
- "geant.ocsp.sectigo.com.": {},
- "geappl.io.": {},
- "geappliances-my.sharepoint.com.": {},
- "geappliances.sharepoint.com.": {},
- "geico-app.quantummetric.com.": {},
- "geico-sync.quantummetric.com.": {},
- "geniusmonkey.com.": {},
- "geo-dra.platform.hicloud.com.": {},
- "getadmiral.com.": {},
- "getbutton.io.": {},
- "getnitropack.com.": {},
- "getpremise.com.": {},
- "getui.net.": {},
- "gfp.veta.naver.com.": {},
- "giraff.io.": {},
- "gitlab.com.": {},
- "gla.gameloft.com.": {},
- "glic-my.sharepoint.com.": {},
- "glic.sharepoint.com.": {},
- "global-tokenserver-la.headline.uodoo.com.": {},
- "global.datasite.com.": {},
- "globalsigncdn.com.cdn.cloudflare.net.": {},
- "globalsun.io.": {},
- "gnc.com.": {},
- "go.gale.com.": {},
- "go.stripchatgirls.com.": {},
- "goaffpro.com.": {},
- "goconfluent-my.sharepoint.com.": {},
- "goconfluent.sharepoint.com.": {},
- "google.org.": {},
- "googledomains.com.": {},
- "gosport.remotepc.com.": {},
- "gov-bam.nr-data.net.": {},
- "gov-bam.nr-data.net.cdn.cloudflare.net.": {},
- "gowustl-my.sharepoint.com.": {},
- "grab.zoom.us.": {},
- "gravitec.net.": {},
- "greenville.remotepc.com.": {},
- "group-ib.com.": {},
- "groupon.attn.tv.": {},
- "grouponeauto-my.sharepoint.com.": {},
- "grpc.vivintsky.com.": {},
- "gslb.finzfin.com.": {},
- "gslb.sgw.shopeemobile.com.": {},
- "gslb.xiaohongshu.com.": {},
- "gtimg.cn.": {},
- "guid.tpns.sgp.tencent.com.": {},
- "gva.be.": {},
- "gw5.push.mcp.weibo.cn.": {},
- "gwadar.cn.": {},
- "gx-api.geniex.com.": {},
- "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-fisglobal.online-metrix.net.": {},
- "h-homedepot.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-uptodate.online-metrix.net.": {},
- "h-v60nf4oj-qfp.online-metrix.net.": {},
- "h-walmart.online-metrix.net.": {},
- "h.app.wdesk.com.": {},
- "h.online-metrix.net.": {},
- "h107833-ecdn.mp.lura.live.": {},
- "h5sv6m.com.": {},
- "haka.ruselabs.com.": {},
- "hamina.remotepc.com.": {},
- "handmadewithjoann.com.": {},
- "hanoi.remotepc.com.": {},
- "hapsee.cn.": {},
- "harmonyoffice-my.sharepoint.com.": {},
- "harrisonk12msus-my.sharepoint.com.": {},
- "harry.lu.": {},
- "hawaii.remotepc.com.": {},
- "hbe199.hybrid.ai.": {},
- "hbopenbid-apac-v2.pubmnet.com.": {},
- "hbwrapper.com.": {},
- "hd-ext-v1.log.mgtv.com.": {},
- "hdi365-my.sharepoint.com.": {},
- "hdi365.sharepoint.com.": {},
- "hdp-raw-log.cn-shanghai.log.aliyuncs.com.": {},
- "hdsupplyinc-my.sharepoint.com.": {},
- "hdsupplyinc.sharepoint.com.": {},
- "healthequity-my.sharepoint.com.": {},
- "healthequity.sharepoint.com.": {},
- "hearst-prod.actioniq.mr-in.com.": {},
- "hecheck.bitmyanmar.info.": {},
- "helloid.com.": {},
- "hellomedian.com.": {},
- "hermes-us.inspidspad.com.": {},
- "hetangsmart.com.": {},
- "hexanaut-centralserver.coolmathgames.com.": {},
- "heytapdownload.com.": {},
- "heytapmobi.com.": {},
- "highwebmedia.com.": {},
- "highwire.org.": {},
- "hillingdon-my.sharepoint.com.": {},
- "hillsboroughcounty-my.sharepoint.com.": {},
- "hilton-my.sharepoint.com.": {},
- "hilton.sharepoint.com.": {},
- "hindustantimes.com.": {},
- "hisearch-dra.dt.dbankcloud.com.": {},
- "hismarttv.com.": {},
- "hismileteeth.com.": {},
- "hits.getelevar.com.": {},
- "hk.gcloudcs.com.": {},
- "hk.voice.gcloudcs.com.": {},
- "hk.wechat.com.": {},
- "hn1-cloud-entitlements.lol.qq.com.": {},
- "hn1-cloud-taas.lol.qq.com.": {},
- "hokgcloudv6.iegcom.com.": {},
- "holmeshelp.ucweb.com.": {},
- "home.highwire.org.": {},
- "homedepot-app.quantummetric.com.": {},
- "homedepot.quantummetric.com.": {},
- "honeywell.com.": {},
- "honeywellprod-my.sharepoint.com.": {},
- "honeywellprod.sharepoint.com.": {},
- "hongkong.remotepc.com.": {},
- "houstonmethodist1-my.sharepoint.com.": {},
- "houstonmethodist1.sharepoint.com.": {},
- "houtx-my.sharepoint.com.": {},
- "hpfalkaj.deepl.com.": {},
- "hpkaj.deepl.com.": {},
- "hpplay.cn.": {},
- "hrsa.gov.": {},
- "hstgps.com.": {},
- "html.it.": {},
- "html5.qq.com.": {},
- "htms.heytapmobi.com.": {},
- "httpdns.y5en.com.": {},
- "huan.tv.": {},
- "huaweicloud.com.": {},
- "hubble.netease.com.": {},
- "hubcloud.com.cn.": {},
- "hubspotemail.net.": {},
- "huion.cn.": {},
- "huntsvillecityschools-my.sharepoint.com.": {},
- "huorong.cn.": {},
- "hw.gcloudcs.com.": {},
- "hwapps-o.api.leiniao.com.": {},
- "hysteryale-my.sharepoint.com.": {},
- "hysteryale.sharepoint.com.": {},
- "hzmk.site.": {},
- "hzmklvdieo.com.": {},
- "i-sg01a.ocloud.heytapmobi.com.": {},
- "i.magazine.heytapmobi.com.": {},
- "i.omiapp.me.": {},
- "i6-vn.weather.oppomobile.com.": {},
- "iaas.jdcloud.com.": {},
- "ibm.account.box.com.": {},
- "ibm.box.com.": {},
- "ibsrv.net.": {},
- "ic-pb-ah.xhcdn.com.": {},
- "ic-ph-ah.xhcdn.com.": {},
- "ic-vt-ah.fullxhcdn.com.": {},
- "icalendars.app.": {},
- "iceholdings-my.sharepoint.com.": {},
- "iceholdings.sharepoint.com.": {},
- "ichano.cn.": {},
- "iconmonstr.com.": {},
- "icons.bitwarden.net.": {},
- "id-ooredoo.rcs.telephony.goog.": {},
- "id-telkom.rcs.telephony.goog.": {},
- "id-timer-appstore.vivoglobal.com.": {},
- "id.remoteutilities.com.": {},
- "idahofalls.remotepc.com.": {},
- "idchicago1.remotepc.com.": {},
- "iddallas1.remotepc.com.": {},
- "iddenver.remotepc.com.": {},
- "iddetroit.remotepc.com.": {},
- "identity.myisolved.com.": {},
- "idexonline-my.sharepoint.com.": {},
- "idhw-my.sharepoint.com.": {},
- "idhw.sharepoint.com.": {},
- "idlondon.remotepc.com.": {},
- "idmadrid.remotepc.com.": {},
- "idnewyork1.remotepc.com.": {},
- "idpix.media6degrees.com.": {},
- "idqqimg.com.": {},
- "idr.cdnwidget.com.": {},
- "ids.cdnwidget.com.": {},
- "iemiq.com.": {},
- "igame.gcloudcs.com.": {},
- "ijoysoftconnect.com.": {},
- "ilandcloud.com.": {},
- "illinoisstateuniversity-my.sharepoint.com.": {},
- "illuminateed.com.": {},
- "ilmn-my.sharepoint.com.": {},
- "ilmn.sharepoint.com.": {},
- "ilog-sea-aliyun.alipayplus.com.": {},
- "im.bluevoox.com.": {},
- "image-auto-captioning-computer-vision.cognitiveservices.azure.com.": {},
- "image.cnbcfm.com.": {},
- "image.myqcloud.com.": {},
- "image.online.adp.com.": {},
- "images.axios.com.": {},
- "images.babylist.com.": {},
- "images.crazygames.com.": {},
- "images.dable.io.": {},
- "images.leadconnectorhq.com.": {},
- "images.onefootball.com.": {},
- "images.wixstatic.com.": {},
- "imagetrendelite.com.": {},
- "imap.earthlink.net.": {},
- "imeclient.openspeech.cn.": {},
- "img-1.kwcdn.com.cdn.cloudflare.net.": {},
- "img.grouponcdn.com.edgekey.net.": {},
- "img.newspapers.com.": {},
- "img.yana.upday.com.": {},
- "img9.target.com.": {},
- "imga.corporateperks.com.": {},
- "imghst-de.com.": {},
- "imgix.ranker.com.": {},
- "imgproxy.leaflets.schwarz.": {},
- "imgs.signifyd.com.": {},
- "imoim.net.": {},
- "imolive2.com.": {},
- "imou-sg-ali-online-paas-private-cloud-picture.oss-ap-southeast-1.aliyuncs.com.": {},
- "imou-sg3-ali-online-paas-private-picture.oss-ap-southeast-1.aliyuncs.com.": {},
- "imoulife.com.": {},
- "impactify.media.": {},
- "imptrk.siteplug.com.": {},
- "in-api.asm.skype.com.": {},
- "in-exmagazineunlock-proxy.vivoglobal.com.": {},
- "in-prod.asyncgw.teams.microsoft.com.": {},
- "in-vcode-od.vivoglobal.com.": {},
- "in.gov.": {},
- "in.visitors.live.": {},
- "incitecpivotlimited-my.sharepoint.com.": {},
- "indianapolis.remotepc.com.": {},
- "inf.miui.com.": {},
- "ingame.qq.com.": {},
- "ingesteu.quantummetric.com.": {},
- "ingov-my.sharepoint.com.": {},
- "ingov.sharepoint.com.": {},
- "inneraudioms.cc.easebar.com.": {},
- "innersloth.com.": {},
- "innity.com.": {},
- "innity.net.": {},
- "ino.qq.com.": {},
- "inoreader.com.": {},
- "ins-qw3q8ofk.ias.tencent-cloud.net.": {},
- "inscr-my.sharepoint.com.": {},
- "inscr.sharepoint.com.": {},
- "inside-graph.com.cdn.cloudflare.net.": {},
- "insidemedia-my.sharepoint.com.": {},
- "insidemedia.sharepoint.com.": {},
- "insightgloballlc-my.sharepoint.com.": {},
- "inskinad.com.": {},
- "inspidspad.com.": {},
- "inspirebrands-app.quantummetric.com.": {},
- "inspirebrands-sync.quantummetric.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.": {},
- "instantmessaging-pa-us.googleapis.com.": {},
- "int.dpool.sina.com.cn.": {},
- "intel-my.sharepoint.com.": {},
- "intel.sharepoint.com.": {},
- "internetdownloadmanager.com.": {},
- "intl-im-conn.iq.com.": {},
- "intuit.zoom.us.": {},
- "iorad.com.": {},
- "ios-informationplatform.wps.cn.": {},
- "ios.crashsight.wetest.net.": {},
- "iot.hillrom.com.": {},
- "iowa.remotepc.com.": {},
- "ip-api.com.": {},
- "ip.acmeaom.com.": {},
- "ipa-business-sg.ap-southeast-1.log.aliyuncs.com.": {},
- "ipa-business.cn-hangzhou.log.aliyuncs.com.": {},
- "iphone-cdn-api.fitbit.com.": {},
- "ipinyou.com.": {},
- "iprofiles.apple.com.": {},
- "iprom.net.": {},
- "ipv4.cadc.absolute.com.": {},
- "ipv4.tracker.harry.lu.": {},
- "iq.com.": {},
- "irltoolkit.mm.fcix.net.": {},
- "ironmountain.cyberhaven.io.": {},
- "irvine.remotepc.com.": {},
- "isap.inskinad.com.": {},
- "iscorp.com.": {},
- "isjike.com.": {},
- "ispeech.org.": {},
- "istanbul.remotepc.com.": {},
- "itc.cn.": {},
- "itch.io.": {},
- "itch.zone.": {},
- "itinfoalvarezandmarsal-my.sharepoint.com.": {},
- "itinfoalvarezandmarsal.sharepoint.com.": {},
- "itm.cloud.com.": {},
- "itzmx.com.": {},
- "ivalua.com.": {},
- "ive8im-inapps.appsflyersdk.com.": {},
- "ivview.com.": {},
- "ivview.net.": {},
- "ivytechccofindiana-my.sharepoint.com.": {},
- "iwmapapi.americanexpress.com.": {},
- "ixav-cse.avlyun.com.": {},
- "izooto.com.": {},
- "jabfm.org.": {},
- "jazzpharma-my.sharepoint.com.": {},
- "jazzpharmaceuticals.cyberhaven.io.": {},
- "jbhunt-my.sharepoint.com.": {},
- "jbhunt.sharepoint.com.": {},
- "jcp-app.quantummetric.com.": {},
- "jdcloud.com.": {},
- "jeldweninc1-my.sharepoint.com.": {},
- "jeldweninc1.sharepoint.com.": {},
- "jjkeller-my.sharepoint.com.": {},
- "jnj-my.sharepoint.com.": {},
- "jocombssd.aristotleinsight.com.": {},
- "johannesburg.remotepc.com.": {},
- "johnmuirhealth.sharepoint.com.": {},
- "joox.com.": {},
- "jotfor.ms.": {},
- "journeymv.com.": {},
- "joynetgame.com.": {},
- "jp-prod.asyncgw.teams.microsoft.com.": {},
- "jp.cinarra.com.": {},
- "jp1.chat.si.riotgames.com.": {},
- "jpost.com.": {},
- "jpush.cn.": {},
- "jpush.io.": {},
- "js-eu1.hs-analytics.net.": {},
- "js-eu1.hs-banner.com.": {},
- "js-eu1.hs-scripts.com.": {},
- "js-eu1.hsadspixel.net.": {},
- "js-eu1.hscollectedforms.net.": {},
- "js-eu1.hsforms.net.": {},
- "js-eu1.hsleadflows.net.": {},
- "js-eu1.hubspot.com.": {},
- "js-eu1.hubspotfeedback.com.": {},
- "js.eruptr.io.": {},
- "jss.starbucks.com.": {},
- "jssprod-starbucks.trafficmanager.net.": {},
- "junglefrog.com.": {},
- "k.163.com.": {},
- "k8s1-event-tracker-am.indexexchange.com.": {},
- "k8s1-event-tracker-la.indexexchange.com.": {},
- "k8s1-event-tracker-ny.indexexchange.com.": {},
- "k8s1-event-tracker-sj.indexexchange.com.": {},
- "k8s1-event-tracker-va.indexexchange.com.": {},
- "k8s1-la-ext-lb.indexexchange.com.": {},
- "k8s1-ny-ext-lb.indexexchange.com.": {},
- "k8s1-va-ext-lb.indexexchange.com.": {},
- "kajicam.com.": {},
- "kameleoon.com.": {},
- "katespade.scene7.com.": {},
- "kc1-my.sharepoint.com.": {},
- "kc1.sharepoint.com.": {},
- "khsd-my.sharepoint.com.": {},
- "khsd.sharepoint.com.": {},
- "kic-ngfts.lge.com.": {},
- "kiev.remotepc.com.": {},
- "kiprotect.com.": {},
- "kisd365-my.sharepoint.com.": {},
- "kisd365.sharepoint.com.": {},
- "kit-uploads.fontawesome.com.": {},
- "kiwisizing.com.": {},
- "kjjinz-cdn-settings.appsflyersdk.com.": {},
- "klagenfurt.remotepc.com.": {},
- "knightlab.com.": {},
- "knock.app.": {},
- "knoxville.remotepc.com.": {},
- "kohcloud.tgpa.qq.com.": {},
- "komect.com.": {},
- "kootenaihealth-my.sharepoint.com.": {},
- "kornferry-my.sharepoint.com.": {},
- "kornferry.sharepoint.com.": {},
- "kstatic.googleusercontent.com.": {},
- "kumed-my.sharepoint.com.": {},
- "kumed.sharepoint.com.": {},
- "kunlunaq.com.": {},
- "kunlunar.com.": {},
- "kunluncan.com.": {},
- "kunlungr.com.": {},
- "kunlunhuf.com.": {},
- "kunlunno.com.": {},
- "kunlunsl.com.": {},
- "kunlunso.com.": {},
- "kv601.prod.do.dsp.mp.microsoft.com.edgekey.net.": {},
- "kwimgs.com.": {},
- "kzhi.tech.": {},
- "l.ec922003.com.": {},
- "l1-1.anzu.io.": {},
- "la-ak.vg.ac.pvp.net.": {},
- "la.remotepc.com.": {},
- "la1.chat.si.riotgames.com.": {},
- "la10.remotepc.com.": {},
- "la11.remotepc.com.": {},
- "la12.remotepc.com.": {},
- "la2.remotepc.com.": {},
- "la3.remotepc.com.": {},
- "la4.remotepc.com.": {},
- "la8.remotepc.com.": {},
- "la9.remotepc.com.": {},
- "lacounty-my.sharepoint.com.": {},
- "lacounty.sharepoint.com.": {},
- "lahuashanbx.com.": {},
- "lan.sdk.linkedin.com.": {},
- "lansing.remotepc.com.": {},
- "laptop-updates.brave.com.": {},
- "larksuite.com.": {},
- "lasd-my.sharepoint.com.": {},
- "lasd.sharepoint.com.": {},
- "lastwar-us.us-west-1.log.aliyuncs.com.": {},
- "laureatelatammx-my.sharepoint.com.": {},
- "laureatelatammx.sharepoint.com.": {},
- "lax.remotepc.com.": {},
- "layerxsecurity.com.": {},
- "lazada-msgacs.m.taobao.com.": {},
- "lazada-wallet.oss-ap-southeast-1.aliyuncs.com.": {},
- "lazada.co.id.": {},
- "lazada.co.th.": {},
- "lazada.com.": {},
- "lazada.com.my.": {},
- "lazada.com.ph.": {},
- "lazada.sg.": {},
- "lazada.vn.": {},
- "lcmchealth-my.sharepoint.com.": {},
- "lcmchealth.sharepoint.com.": {},
- "ldap.google.com.": {},
- "ldcorp.sharepoint.com.": {},
- "ldmnq.com.": {},
- "leadmanagerfx.com.": {},
- "leagueoflegends.com.": {},
- "leiniao.com.": {},
- "lenovomm.com.": {},
- "levect.com.": {},
- "level10gc.com.": {},
- "leveldata.poki.io.": {},
- "leviton-my.sharepoint.com.": {},
- "lexicon.33across.com.": {},
- "lianmeng.360.cn.": {},
- "libertyuniv-my.sharepoint.com.": {},
- "libertyuniv.sharepoint.com.": {},
- "liblynx.com.": {},
- "libra22-normal-useast2a.tiktokv.com.": {},
- "license.gonative.io.": {},
- "license.litespeedtech.com.": {},
- "license.unity3d.com.": {},
- "licensing.bitmovin.com.": {},
- "lichess.org.": {},
- "lightboxcdn.com.": {},
- "lightwidget.com.": {},
- "likr.tw.": {},
- "lima.remotepc.com.": {},
- "lincare-my.sharepoint.com.": {},
- "lincare.sharepoint.com.": {},
- "link-vision-picture-sgp.oss-ap-southeast-1.aliyuncs.com.": {},
- "liquipedia.net.": {},
- "lisbon.remotepc.com.": {},
- "lissabon.remotepc.com.": {},
- "list.tronlink.org.": {},
- "lists-e.tm-rt.sharepoint.com.": {},
- "lite.adakami.id.": {},
- "litedev.sgp.hik-connect.com.": {},
- "litespeedtech.com.": {},
- "littler-my.sharepoint.com.": {},
- "live.126.net.": {},
- "live.ngb.haplat.net.": {},
- "live3.ngb.haplat.net.": {},
- "live5.ngb.haplat.net.": {},
- "live74dh3d6.airspace-a.cbsivideo.com.": {},
- "livect.haplat.net.": {},
- "livedmpsk12ia-my.sharepoint.com.": {},
- "livedmpsk12ia.sharepoint.com.": {},
- "livekilleenisd-my.sharepoint.com.": {},
- "livekilleenisd.sharepoint.com.": {},
- "liveutmb-my.sharepoint.com.": {},
- "liveutmb.sharepoint.com.": {},
- "ljubljana.remotepc.com.": {},
- "local.adguard.org.": {},
- "local.info.g9hc4.cn.": {},
- "log-api.newrelic.com.cdn.cloudflare.net.": {},
- "log-yex.youdao.com.": {},
- "log.getadblock.com.": {},
- "log.lscreenc.com.": {},
- "log.umsns.com.": {},
- "log.zoom.us.": {},
- "logger.moviead55.ru.": {},
- "logging-service-prod.getepic.com.": {},
- "logging.mp.lura.live.": {},
- "login.cbc.ca.": {},
- "login.steampowered.com.": {},
- "login.teamviewer.com.": {},
- "loginradius.com.": {},
- "logs2.sportslocalmedia.com.": {},
- "logu.hpplay.cn.": {},
- "logus.xiaoyi.com.": {},
- "logx.optimizely.com.": {},
- "london.remotepc.com.": {},
- "london2.remotepc.com.": {},
- "london3.remotepc.com.": {},
- "london4.remotepc.com.": {},
- "london5.remotepc.com.": {},
- "london6.remotepc.com.": {},
- "london8.remotepc.com.": {},
- "look.360.cn.": {},
- "loopme.me.": {},
- "lptag-cdn.liveperson.net.": {},
- "lsagentrelay.lansweeper.com.": {},
- "lscreenc.com.": {},
- "ltfinc-my.sharepoint.com.": {},
- "ltfinc.sharepoint.com.": {},
- "ltfl.librarything.com.": {},
- "ltpnetwork-my.sharepoint.com.": {},
- "luckyorange.com.": {},
- "ludashi.com.": {},
- "lufthansa-app.quantummetric.com.": {},
- "lunamedia.live.": {},
- "luxembourg.remotepc.com.": {},
- "lycraservice-pa-cam-prod.googleapis.com.": {},
- "lyric.alarmnet.com.": {},
- "m.vidio.com.": {},
- "m104216-ucdn.mp.lura.live.": {},
- "m107833-mcdn.mp.lura.live.": {},
- "m109771-ecdn.mp.lura.live.": {},
- "m3.twinredads.com.": {},
- "macclog-as.rj.link.": {},
- "madrid.remotepc.com.": {},
- "maers.adrs.org.cn.": {},
- "magichue.net.": {},
- "maidenhead.remotepc.com.": {},
- "mail.proton.me.": {},
- "mail.superhuman.com.": {},
- "mailinblue.com.": {},
- "mailmissouri-my.sharepoint.com.": {},
- "mailmissouri.sharepoint.com.": {},
- "mailwsorg.zoho.com.": {},
- "maintenanceconnection.com.": {},
- "majorel365-my.sharepoint.com.": {},
- "malware-filter.gitlab.io.": {},
- "manage-selfhost.microsoft.com.": {},
- "manage.wix.com.": {},
- "manassas.remotepc.com.": {},
- "manchester.remotepc.com.": {},
- "manifest.prod.boltdns.net.": {},
- "maps.infoplaza.nl.": {},
- "marmot-cloud.com.": {},
- "marseille.remotepc.com.": {},
- "masonitecloud-my.sharepoint.com.": {},
- "masonitecloud.sharepoint.com.": {},
- "master1.teamviewer.com.": {},
- "master10.teamviewer.com.": {},
- "master11.teamviewer.com.": {},
- "master12.teamviewer.com.": {},
- "master13.teamviewer.com.": {},
- "master14.teamviewer.com.": {},
- "master15.teamviewer.com.": {},
- "master16.teamviewer.com.": {},
- "master2.teamviewer.com.": {},
- "master3.teamviewer.com.": {},
- "master4.teamviewer.com.": {},
- "master5.teamviewer.com.": {},
- "master6.teamviewer.com.": {},
- "master7.teamviewer.com.": {},
- "master8.teamviewer.com.": {},
- "master9.teamviewer.com.": {},
- "masterclass.com.": {},
- "masuk.store.": {},
- "matrix.netease.com.": {},
- "mattressfirm-my.sharepoint.com.": {},
- "max-l.mediav.com.": {},
- "maxpreps.com.": {},
- "mbboauth-1c.prd.cn.vwg-connect.cn.": {},
- "mcallen.remotepc.com.": {},
- "mcdermottinc-my.sharepoint.com.": {},
- "mcdermottinc.sharepoint.com.": {},
- "mcdermottwillemery-my.sharepoint.com.": {},
- "mcdermottwillemery.sharepoint.com.": {},
- "mcdn.podbean.com.": {},
- "mcpss-my.sharepoint.com.": {},
- "mcpss.sharepoint.com.": {},
- "mdap.tngdigital.com.my.": {},
- "mdp-upgrade-cn.heytapmobi.com.": {},
- "mdscpxchg.com.": {},
- "meari-oss-us.oss-us-west-1.aliyuncs.com.": {},
- "meari-us.oss-us-west-1.aliyuncs.com.": {},
- "medellin.remotepc.com.": {},
- "media-ams2-1.cdn.whatsapp.net.": {},
- "media-ams4-1.cdn.whatsapp.net.": {},
- "media-arn2-1.cdn.whatsapp.net.": {},
- "media-atl3-1.cdn.whatsapp.net.": {},
- "media-atl3-2.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-cgk1-1.cdn.whatsapp.net.": {},
- "media-cgk1-2.cdn.whatsapp.net.": {},
- "media-cgk1-3.cdn.whatsapp.net.": {},
- "media-den2-1.cdn.whatsapp.net.": {},
- "media-dfw5-1.cdn.whatsapp.net.": {},
- "media-dfw5-2.cdn.whatsapp.net.": {},
- "media-dus1-1.cdn.whatsapp.net.": {},
- "media-fra3-1.cdn.whatsapp.net.": {},
- "media-fra3-2.cdn.whatsapp.net.": {},
- "media-fra5-1.cdn.whatsapp.net.": {},
- "media-fra5-2.cdn.whatsapp.net.": {},
- "media-gig4-1.cdn.whatsapp.net.": {},
- "media-gru1-1.cdn.whatsapp.net.": {},
- "media-gru1-2.cdn.whatsapp.net.": {},
- "media-gua1-1.cdn.whatsapp.net.": {},
- "media-ham3-1.cdn.whatsapp.net.": {},
- "media-hel3-1.cdn.whatsapp.net.": {},
- "media-hkg1-1.cdn.whatsapp.net.": {},
- "media-hkg1-2.cdn.whatsapp.net.": {},
- "media-hkg4-1.cdn.whatsapp.net.": {},
- "media-hkg4-2.cdn.whatsapp.net.": {},
- "media-hou1-1.cdn.whatsapp.net.": {},
- "media-iad3-1.cdn.whatsapp.net.": {},
- "media-iad3-2.cdn.whatsapp.net.": {},
- "media-ist1-1.cdn.whatsapp.net.": {},
- "media-kul2-1.cdn.whatsapp.net.": {},
- "media-kul2-2.cdn.whatsapp.net.": {},
- "media-kul3-1.cdn.whatsapp.net.": {},
- "media-lax3-1.cdn.whatsapp.net.": {},
- "media-lax3-2.cdn.whatsapp.net.": {},
- "media-lga3-1.cdn.whatsapp.net.": {},
- "media-lga3-2.cdn.whatsapp.net.": {},
- "media-lhr6-1.cdn.whatsapp.net.": {},
- "media-lhr6-2.cdn.whatsapp.net.": {},
- "media-lhr8-1.cdn.whatsapp.net.": {},
- "media-lhr8-2.cdn.whatsapp.net.": {},
- "media-lim1-1.cdn.whatsapp.net.": {},
- "media-lis1-1.cdn.whatsapp.net.": {},
- "media-los2-1.cdn.whatsapp.net.": {},
- "media-mad1-1.cdn.whatsapp.net.": {},
- "media-mad2-1.cdn.whatsapp.net.": {},
- "media-man2-1.cdn.whatsapp.net.": {},
- "media-mct1-1.cdn.whatsapp.net.": {},
- "media-mia3-1.cdn.whatsapp.net.": {},
- "media-mia3-2.cdn.whatsapp.net.": {},
- "media-mrs2-1.cdn.whatsapp.net.": {},
- "media-mrs2-2.cdn.whatsapp.net.": {},
- "media-msp1-1.cdn.whatsapp.net.": {},
- "media-mty2-1.cdn.whatsapp.net.": {},
- "media-muc2-1.cdn.whatsapp.net.": {},
- "media-ord5-1.cdn.whatsapp.net.": {},
- "media-ord5-2.cdn.whatsapp.net.": {},
- "media-otp1-1.cdn.whatsapp.net.": {},
- "media-qro1-1.cdn.whatsapp.net.": {},
- "media-qro1-2.cdn.whatsapp.net.": {},
- "media-sea1-1.cdn.whatsapp.net.": {},
- "media-sin6-1.cdn.whatsapp.net.": {},
- "media-sin6-2.cdn.whatsapp.net.": {},
- "media-sin6-3.cdn.whatsapp.net.": {},
- "media-sin6-4.cdn.whatsapp.net.": {},
- "media-sjc3-1.cdn.whatsapp.net.": {},
- "media-sof1-1.cdn.whatsapp.net.": {},
- "media-sof1-2.cdn.whatsapp.net.": {},
- "media-vie1-1.cdn.whatsapp.net.": {},
- "media-waw1-1.cdn.whatsapp.net.": {},
- "media-xsp1-1.cdn.whatsapp.net.": {},
- "media-xsp1-2.cdn.whatsapp.net.": {},
- "media-xsp1-3.cdn.whatsapp.net.": {},
- "media-xsp2-1.cdn.whatsapp.net.": {},
- "media-yyz1-1.cdn.whatsapp.net.": {},
- "media.graphassets.com.": {},
- "media.ringcentral.com.": {},
- "media.superhuman.com.": {},
- "mediadata.xboxlive.com.": {},
- "mediadelivery.net.": {},
- "mediav.com.": {},
- "medline0-my.sharepoint.com.": {},
- "medline0.sharepoint.com.": {},
- "melbourne.remotepc.com.": {},
- "memphis.remotepc.com.": {},
- "metric.picodi.global.": {},
- "metrics-dre.dt.hihonorcloud.com.": {},
- "metrics5.data.hicloud.com.": {},
- "mexicocity.remotepc.com.": {},
- "mf.b37mrtl.ru.": {},
- "mgtv.com.": {},
- "mia-itm-radar-testobject.citrix.com.": {},
- "miami.remotepc.com.": {},
- "miami2.remotepc.com.": {},
- "miami3.remotepc.com.": {},
- "miami4.remotepc.com.": {},
- "miamidadecollegeprod-my.sharepoint.com.": {},
- "mib2clu8.car-cloud-cn.net.": {},
- "microad.jp.": {},
- "microchiptechnology-my.sharepoint.com.": {},
- "microchiptechnology.sharepoint.com.": {},
- "microsoft-my.sharepoint.com.": {},
- "microsoft.sharepoint.com.": {},
- "microvirt.com.": {},
- "mid4.linkedin.com.": {},
- "mida.so.": {},
- "mightytext.co.": {},
- "milan.remotepc.com.": {},
- "milestoneinternet.com.cdn.cloudflare.net.": {},
- "milwaukeetool-my.sharepoint.com.": {},
- "milwaukeetool.sharepoint.com.": {},
- "mimir.vivaldi.com.": {},
- "min-api.cryptocompare.com.": {},
- "mini.browser.360.cn.": {},
- "mintkeyboard.com.": {},
- "mirror.fcix.net.": {},
- "mirror.lstn.net.": {},
- "mirror.pit.teraswitch.com.": {},
- "mirror.steadfastnet.com.": {},
- "mirrors.rockylinux.org.": {},
- "mitek-my.sharepoint.com.": {},
- "mixi.media.": {},
- "mm-mm.bing.net.trafficmanager.net.": {},
- "mms.mckesson.com.": {},
- "mn31.ultipro.com.": {},
- "mn365-my.sharepoint.com.": {},
- "mn365.sharepoint.com.": {},
- "mobile-bank.cdn-tinkoff.ru.": {},
- "mobile-collector.cell.nr-data.net.": {},
- "mobile-collector.newrelic.com.cdn.cloudflare.net.": {},
- "mobile-nlp.vivo.com.cn.": {},
- "mobile.bereal.com.": {},
- "mobile.shuzilm.cn.": {},
- "mobiledataplan-pa.googleapis.com.": {},
- "mobilelog.upqzfile.com.": {},
- "mobilemaps-pa-gz.googleapis.com.": {},
- "mobilemaps.googleapis.com.": {},
- "modesto.remotepc.com.": {},
- "moni-onrt-stsdk.vivo.com.cn.": {},
- "monitor.fraudblocker.com.": {},
- "monitoring.getelevar.com.": {},
- "monitoring.worksighted.com.": {},
- "monsterenergycorp-my.sharepoint.com.": {},
- "monsterenergycorp.sharepoint.com.": {},
- "montage-updates.displaynote.com.": {},
- "monticello.remotepc.com.": {},
- "montreal.remotepc.com.": {},
- "motiondetection-us-1d.oss-us-west-1.aliyuncs.com.": {},
- "motiondetection-us.oss-us-west-1.aliyuncs.com.": {},
- "mouser.com.": {},
- "moviead55.ru.": {},
- "mp.360.cn.": {},
- "mp.theepochtimes.com.": {},
- "mpsaz-my.sharepoint.com.": {},
- "mpsaz.sharepoint.com.": {},
- "mpush-api.aliyun.com.": {},
- "mr.homedepot.com.": {},
- "mrisoftware.com.": {},
- "ms1app.pb.com.": {},
- "msch.f.360.cn.": {},
- "msdl.microsoft.com.": {},
- "msf.3g.qq.com.": {},
- "msg-img-hk.oss-cn-hongkong.aliyuncs.com.": {},
- "mstate-my.sharepoint.com.": {},
- "msync-im1-sgp-ga.easemob.com.": {},
- "mtb-app.quantummetric.com.": {},
- "mtrace.qq.com.": {},
- "mu.ariba.com.": {},
- "mumbai.remotepc.com.": {},
- "munich.remotepc.com.": {},
- "musical.ly.": {},
- "musicmatch-ssl.xboxlive.com.": {},
- "musicps.p2p.qq.com.": {},
- "musicpunch.p2p.qq.com.": {},
- "mvconf.f.360.cn.": {},
- "mvconf.uk.cloud.360safe.com.": {},
- "mvm.snapchat.com.": {},
- "mx-vcode-od.vivoglobal.com.": {},
- "mx.amx.rcs.telephony.goog.": {},
- "mxc-ios-app-logs-default.ap-southeast-1.log.aliyuncs.com.": {},
- "mxc-logs-data-processing.ap-southeast-1.log.aliyuncs.com.": {},
- "mxp-pusa01.app.blackbaud.net.": {},
- "mxptint.net.": {},
- "my.dealersocket.com.": {},
- "my.getadmiral.com.": {},
- "my.jbi.global.": {},
- "my.microsoftpersonalcontent.com.": {},
- "my.nalpeiron.com.": {},
- "my.pool.ntp.org.": {},
- "myccmortgage-my.sharepoint.com.": {},
- "mydigitalspace-my.sharepoint.com.": {},
- "mydigitalspace.sharepoint.com.": {},
- "mydrive.connect.aig.": {},
- "myisolved.com.": {},
- "mylonestar-my.sharepoint.com.": {},
- "mylonestar.sharepoint.com.": {},
- "myqcloud.com.": {},
- "myvscloud.com.": {},
- "myweblogon.com.": {},
- "myworkdaycdn.com.cn.": {},
- "n.gameads.io.": {},
- "n21.ultipro.com.": {},
- "n33.ultipro.com.": {},
- "na2.chat.si.riotgames.com.": {},
- "na2.docusign.net.": {},
- "nagich.co.il.": {},
- "najva.com.": {},
- "namequery.com.": {},
- "naperville.remotepc.com.": {},
- "nashville.remotepc.com.": {},
- "nationalheritageacademies-my.sharepoint.com.": {},
- "nationalheritageacademies.sharepoint.com.": {},
- "nationalmap.gov.": {},
- "nationalreview.com.": {},
- "nativecos.com.": {},
- "nc-centos-mirror.iwebfusion.net.": {},
- "nc.com.": {},
- "ncentral.centrexit.com.": {},
- "ncjb-my.sharepoint.com.": {},
- "nearme.com.cn.": {},
- "nechicago.remotepc.com.": {},
- "neonataltherapists.com.": {},
- "netapp-my.sharepoint.com.": {},
- "netapp.com.": {},
- "netapp.sharepoint.com.": {},
- "netease.com.": {},
- "netease.im.": {},
- "netpop.app.": {},
- "netpresenter.com.": {},
- "netsolssl.com.": {},
- "new.adblockplus.org.": {},
- "newcontinuum.net.": {},
- "newhanovercountyschools-my.sharepoint.com.": {},
- "newoldstamp.com.": {},
- "neworleans.remotepc.com.": {},
- "news-abroad.vivo.com.": {},
- "news-af.feednews.com.": {},
- "news-client.apple.com.": {},
- "news-events.apple.com.": {},
- "news-nar-aud.apple.com.": {},
- "news-sports-events.apple.com.": {},
- "newsletter-edge.apple.com.": {},
- "newsroom.bi.": {},
- "newyork.remotepc.com.": {},
- "newyork2.remotepc.com.": {},
- "newyork3.remotepc.com.": {},
- "nex.163.com.": {},
- "nexstar.amp.permutive.com.": {},
- "nexus2wlb.com.": {},
- "nexx360.io.": {},
- "nfm365-my.sharepoint.com.": {},
- "nfm365.sharepoint.com.": {},
- "ng1.angus.mrisoftware.com.": {},
- "ngb.haplat.net.": {},
- "nh.iz.do.": {},
- "nhhospitals-my.sharepoint.com.": {},
- "nhshumanservices423-my.sharepoint.com.": {},
- "nice-team.net.": {},
- "nie.netease.com.": {},
- "nieuwsblad.be.": {},
- "nike.com.multicdn.cloudinary.com.": {},
- "ninjakiwi.com.": {},
- "nio365-my.sharepoint.com.": {},
- "nio365.sharepoint.com.": {},
- "nitropay.com.": {},
- "nkcsd-my.sharepoint.com.": {},
- "nmhealth-my.sharepoint.com.": {},
- "nmhealth.sharepoint.com.": {},
- "noc.computerhelpnj.com.": {},
- "node.setupad.com.": {},
- "nordcurrent.com.": {},
- "norma-external-collect.meizu.com.": {},
- "nortic.ogtic.gob.do.": {},
- "notes-analytics-events.apple.com.": {},
- "notes.services.box.com.": {},
- "novaicare.com.": {},
- "novel.itoon.org.": {},
- "nps.gov.": {},
- "ns-cloud-a1.googledomains.com.": {},
- "ns-cloud-a2.googledomains.com.": {},
- "ns-cloud-a3.googledomains.com.": {},
- "ns-cloud-a4.googledomains.com.": {},
- "ns-cloud-b1.googledomains.com.": {},
- "ns-cloud-b2.googledomains.com.": {},
- "ns-cloud-b3.googledomains.com.": {},
- "ns-cloud-b4.googledomains.com.": {},
- "ns-cloud-c1.googledomains.com.": {},
- "ns-cloud-c2.googledomains.com.": {},
- "ns-cloud-c3.googledomains.com.": {},
- "ns-cloud-c4.googledomains.com.": {},
- "ns-cloud-d1.googledomains.com.": {},
- "ns-cloud-d2.googledomains.com.": {},
- "ns-cloud-d3.googledomains.com.": {},
- "ns-cloud-d4.googledomains.com.": {},
- "ns-cloud-e1.googledomains.com.": {},
- "ns-cloud-e2.googledomains.com.": {},
- "ns-cloud-e3.googledomains.com.": {},
- "ns-cloud-e4.googledomains.com.": {},
- "ns.aliyuncs.com.": {},
- "ns.identrust.com.": {},
- "ns0105.secondary.cloudflare.com.": {},
- "ns0160.secondary.cloudflare.com.": {},
- "ns1.101domain.com.": {},
- "ns1.bluehost.com.": {},
- "ns1.cloudflare.net.": {},
- "ns1.g.aaplimg.com.": {},
- "ns1.google.com.": {},
- "ns1.identrust.com.": {},
- "ns2.cloudflare.net.": {},
- "ns2.g.aaplimg.com.": {},
- "ns2.google.com.": {},
- "ns3.24shells.net.": {},
- "ns3.cloudflare.net.": {},
- "ns3.g.aaplimg.com.": {},
- "ns3.google.com.": {},
- "ns4.24shells.net.": {},
- "ns4.cloudflare.net.": {},
- "ns4.g.aaplimg.com.": {},
- "ns4.google.com.": {},
- "ns5.cloudflare.net.": {},
- "nsa.nalpeiron.com.": {},
- "nsatc.net.": {},
- "nsp-logserver-higeo-dre.obs.eu-west-101.myhuaweicloud.eu.": {},
- "ntes53.netease.com.": {},
- "ntp.aliyun.com.": {},
- "ntp.arlo.com.": {},
- "ntp.org.cn.": {},
- "ntp1.aliyun.com.": {},
- "ntp2.aliyun.com.": {},
- "ntp3.aliyun.com.": {},
- "ntp4.aliyun.com.": {},
- "ntpool0.603.newcontinuum.net.": {},
- "ntpool1.603.newcontinuum.net.": {},
- "nttlimited-my.sharepoint.com.": {},
- "nttlimited.sharepoint.com.": {},
- "nuremberg.remotepc.com.": {},
- "nvu-prd.mqtt.ivanticloud.com.": {},
- "nw14.ultipro.com.": {},
- "nwsalert.onelouder.com.": {},
- "nzz.ch.": {},
- "o15.officeredir.microsoft.com.": {},
- "o300810.mp.lura.live.": {},
- "oauth-analytics.ascendlearning.com.": {},
- "obe0-my.sharepoint.com.": {},
- "obihai.telephony.goog.": {},
- "obs.ap-southeast-3.myhuaweicloud.com.": {},
- "observability.bereal.com.": {},
- "obsproject.com.": {},
- "obus-dc2-cn.heytapmobi.com.": {},
- "obus-dc20058-cn.heytapmobi.com.": {},
- "obus-dc20123-cn.heytapmobi.com.": {},
- "obus-dctech-cn.heytapmobi.com.": {},
- "oc1.chat.si.riotgames.com.": {},
- "oclc.org.": {},
- "ocloud.oppomobile.com.": {},
- "ocps-xfer.kronos.net.": {},
- "ocpsfl-my.sharepoint.com.": {},
- "ocsa.office.microsoft.com.": {},
- "ocsp.identrust.com.": {},
- "ocsredir.officeapps.live.com.": {},
- "odw7bf.dood.video.": {},
- "office.microsoft.com.": {},
- "officepreviewredir.microsoft.com.": {},
- "officeredir.microsoft.com.": {},
- "offline.toc.shopeemobile.com.": {},
- "ogma.bereal.team.": {},
- "olatheschoolsorg-my.sharepoint.com.": {},
- "olatheschoolsorg.sharepoint.com.": {},
- "omats-my.sharepoint.com.": {},
- "omats.sharepoint.com.": {},
- "omiapp.me.": {},
- "omitech.site.": {},
- "omnihotels-my.sharepoint.com.": {},
- "on-hwapps-o.api.leiniao.com.": {},
- "onedrive.live.com.": {},
- "oneharman-my.sharepoint.com.": {},
- "oneharman.sharepoint.com.": {},
- "onekey1.cmpassport.com.": {},
- "oneplus.net.": {},
- "onethingpcs.com.": {},
- "onezapp.com.": {},
- "online.americanexpress.com.edgekey.net.": {},
- "onlinewebfonts.com.": {},
- "op.mykonf.com.": {},
- "opamarketplace.com.": {},
- "open.acgnxtracker.com.": {},
- "open.acgtracker.com.": {},
- "open.demonii.com.": {},
- "open.oppomobile.com.": {},
- "opencmp.net.": {},
- "opencolo.mm.fcix.net.": {},
- "opendsp.ru.": {},
- "openrice.com.": {},
- "opex-service-cn.allawntech.com.": {},
- "oppo.com.": {},
- "oppomobile.com.": {},
- "optimizely.com.": {},
- "optioncare-my.sharepoint.com.": {},
- "optioncare.sharepoint.com.": {},
- "orangeusdorg-my.sharepoint.com.": {},
- "oregon.remotepc.com.": {},
- "origin.fe-image-cache-ttp.useast8.byteglb.com.": {},
- "orlando.remotepc.com.": {},
- "osaka.remotepc.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-enet.aliyuncs.com.": {},
- "oss-eu-central-1.aliyuncs.com.": {},
- "oss-us-east-1.aliyuncs.com.": {},
- "oss-us-west-1.aliyuncs.com.": {},
- "otc.t-systems.com.": {},
- "otlp.nr-data.net.": {},
- "ott.deepl.com.": {},
- "oursummit-my.sharepoint.com.": {},
- "oursummit.sharepoint.com.": {},
- "overlay.ubisoft.com.": {},
- "overleaf.com.": {},
- "overleafusercontent.com.": {},
- "oversea-master-log.ap-southeast-1.log.aliyuncs.com.": {},
- "overseasccl-a.haplat.net.": {},
- "overseasccl-b.haplat.net.": {},
- "overseasccl-c.haplat.net.": {},
- "overseasccl-major-a.haplat.net.": {},
- "overseasccl-major-b.haplat.net.": {},
- "overseasccl-major-c.haplat.net.": {},
- "ovh.maxhost.io.": {},
- "oxmudr-launches.appsflyersdk.com.": {},
- "oxyinc-my.sharepoint.com.": {},
- "p-wonderidea-rdr.us-east-1.log.aliyuncs.com.": {},
- "p.adlooxtracking.com.": {},
- "p.placed.com.": {},
- "p.vivo.com.cn.": {},
- "p0-pu-private-useast8.tiktokv.com.": {},
- "p107609.cedexis-test.com.": {},
- "p107610.cedexis-test.com.": {},
- "p107611.cedexis-test.com.": {},
- "p109477.cedexis-test.com.": {},
- "p109522.cedexis-test.com.": {},
- "p20304.cedexis-test.com.": {},
- "p20305.cedexis-test.com.": {},
- "p20306.cedexis-test.com.": {},
- "p20307b.cedexis-test.com.": {},
- "p20308b.cedexis-test.com.": {},
- "p20309.cedexis-test.com.": {},
- "p20310.cedexis-test.com.": {},
- "p20311.cedexis-test.com.": {},
- "p20314.cedexis-test.com.": {},
- "p20315.cedexis-test.com.": {},
- "p23-mailws.icloud.com.": {},
- "p25-mailws.icloud.com.": {},
- "p2cdn.com.": {},
- "p2p-cal-2.anker-in.com.": {},
- "p2p-cal.anker-in.com.": {},
- "p2p-ohi-2.anker-in.com.": {},
- "p2p-par.anker-in.com.": {},
- "p2p-sgp.anker-in.com.": {},
- "p2p-vir.anker-in.com.": {},
- "p2p.qq.com.": {},
- "p2p2.cloudbirds.cn.": {},
- "p2p3.cloudbirds.cn.": {},
- "p2pm-ali.reolink.com.": {},
- "p2psy2.io.mi.com.": {},
- "p2psy3.io.mi.com.": {},
- "p30605.cedexis-test.com.": {},
- "p33-mailws.icloud.com.": {},
- "p33231.cedexis-test.com.": {},
- "p33232.cedexis-test.com.": {},
- "p33233.cedexis-test.com.": {},
- "p33234.cedexis-test.com.": {},
- "p33235.cedexis-test.com.": {},
- "p33236.cedexis-test.com.": {},
- "p33237.cedexis-test.com.": {},
- "p33238.cedexis-test.com.": {},
- "p33239.cedexis-test.com.": {},
- "p33240.cedexis-test.com.": {},
- "p33241.cedexis-test.com.": {},
- "p33242.cedexis-test.com.": {},
- "p33243.cedexis-test.com.": {},
- "p33244.cedexis-test.com.": {},
- "p33245.cedexis-test.com.": {},
- "p33246.cedexis-test.com.": {},
- "p33247.cedexis-test.com.": {},
- "p33248.cedexis-test.com.": {},
- "p33249.cedexis-test.com.": {},
- "p33250.cedexis-test.com.": {},
- "p33251.cedexis-test.com.": {},
- "p33252.cedexis-test.com.": {},
- "p33253.cedexis-test.com.": {},
- "p33254.cedexis-test.com.": {},
- "p33255.cedexis-test.com.": {},
- "p33256.cedexis-test.com.": {},
- "p33257.cedexis-test.com.": {},
- "p33258.cedexis-test.com.": {},
- "p33259.cedexis-test.com.": {},
- "p33260.cedexis-test.com.": {},
- "p34854.cedexis-test.com.": {},
- "p34855.cedexis-test.com.": {},
- "p34856.cedexis-test.com.": {},
- "p34857.cedexis-test.com.": {},
- "p34858.cedexis-test.com.": {},
- "p34859.cedexis-test.com.": {},
- "p34860.cedexis-test.com.": {},
- "p35883.cedexis-test.com.": {},
- "p38635.cedexis-test.com.": {},
- "p39604.cedexis-test.com.": {},
- "p3a-creative.brave.com.": {},
- "p3a-json.brave.com.": {},
- "p40-mailws.icloud.com.": {},
- "p40233.cedexis-test.com.": {},
- "p40234.cedexis-test.com.": {},
- "p40235.cedexis-test.com.": {},
- "p40236.cedexis-test.com.": {},
- "p40237.cedexis-test.com.": {},
- "p40238.cedexis-test.com.": {},
- "p40239.cedexis-test.com.": {},
- "p40255.cedexis-test.com.": {},
- "p40256.cedexis-test.com.": {},
- "p40257.cedexis-test.com.": {},
- "p40259.cedexis-test.com.": {},
- "p40261.cedexis-test.com.": {},
- "p40262.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.": {},
- "p41255.cedexis-test.com.": {},
- "p41256.cedexis-test.com.": {},
- "p41259.cedexis-test.com.": {},
- "p41261.cedexis-test.com.": {},
- "p41266.cedexis-test.com.": {},
- "p41267.cedexis-test.com.": {},
- "p41268.cedexis-test.com.": {},
- "p41272.cedexis-test.com.": {},
- "p41273.cedexis-test.com.": {},
- "p41274.cedexis-test.com.": {},
- "p41281.cedexis-test.com.": {},
- "p41905.cedexis-test.com.": {},
- "p42051.cedexis-test.com.": {},
- "p42052.cedexis-test.com.": {},
- "p42053.cedexis-test.com.": {},
- "p43671.cedexis-test.com.": {},
- "p43707.cedexis-test.com.": {},
- "p43773.cedexis-test.com.": {},
- "p43774.cedexis-test.com.": {},
- "p43775.cedexis-test.com.": {},
- "p43776.cedexis-test.com.": {},
- "p43813.cedexis-test.com.": {},
- "p45-mailws.icloud.com.": {},
- "p48434.cedexis-test.com.": {},
- "p48435.cedexis-test.com.": {},
- "p48436.cedexis-test.com.": {},
- "p48437.cedexis-test.com.": {},
- "p4p.arenabg.com.": {},
- "p52066.cedexis-test.com.": {},
- "p56745.cedexis-test.com.": {},
- "p56746.cedexis-test.com.": {},
- "p56747.cedexis-test.com.": {},
- "p76593.cedexis-test.com.": {},
- "p86069.cedexis-test.com.": {},
- "p86070.cedexis-test.com.": {},
- "p86071.cedexis-test.com.": {},
- "p86072.cedexis-test.com.": {},
- "p86073.cedexis-test.com.": {},
- "p86074.cedexis-test.com.": {},
- "p86075.cedexis-test.com.": {},
- "p86076.cedexis-test.com.": {},
- "p86077.cedexis-test.com.": {},
- "p86078.cedexis-test.com.": {},
- "p86079.cedexis-test.com.": {},
- "p86080.cedexis-test.com.": {},
- "p86081.cedexis-test.com.": {},
- "p86082.cedexis-test.com.": {},
- "p86083.cedexis-test.com.": {},
- "p86084.cedexis-test.com.": {},
- "p92860.cedexis-test.com.": {},
- "p92861.cedexis-test.com.": {},
- "p92862.cedexis-test.com.": {},
- "p93644.cedexis-test.com.": {},
- "p93645.cedexis-test.com.": {},
- "p93646.cedexis-test.com.": {},
- "p93647.cedexis-test.com.": {},
- "p93648.cedexis-test.com.": {},
- "p93649.cedexis-test.com.": {},
- "p93650.cedexis-test.com.": {},
- "p93651.cedexis-test.com.": {},
- "p95707.cedexis-test.com.": {},
- "p95708.cedexis-test.com.": {},
- "p95711.cedexis-test.com.": {},
- "p95717.cedexis-test.com.": {},
- "p95721.cedexis-test.com.": {},
- "p95722.cedexis-test.com.": {},
- "p95723.cedexis-test.com.": {},
- "p95724.cedexis-test.com.": {},
- "p95725.cedexis-test.com.": {},
- "p95726.cedexis-test.com.": {},
- "p95727.cedexis-test.com.": {},
- "p95728.cedexis-test.com.": {},
- "paccarnet.sharepoint.com.": {},
- "paducahix.mm.fcix.net.": {},
- "pai.googlezip.net.": {},
- "palermo.remotepc.com.": {},
- "palm.tech.": {},
- "panorama.wixapps.net.": {},
- "panthers-my.sharepoint.com.": {},
- "paris.remotepc.com.": {},
- "parkhill1-my.sharepoint.com.": {},
- "parkhill1.sharepoint.com.": {},
- "partition.enterprise.com.": {},
- "partnerboost.com.": {},
- "pasadena.remotepc.com.": {},
- "passportalmsp.com.": {},
- "pay.datatrans.com.": {},
- "paycorinc-my.sharepoint.com.": {},
- "paylocity1-my.sharepoint.com.": {},
- "paylocity1.sharepoint.com.": {},
- "payment.api.speechify.com.": {},
- "pbe1.chat.si.riotgames.com.": {},
- "pbs.btloader.com.": {},
- "pbsj.bricks-co.com.": {},
- "pc-store.lenovomm.cn.": {},
- "pcdn.brave.com.": {},
- "pcs.baidu.com.": {},
- "pd.cdnwidget.com.": {},
- "pd.eu.a.pvp.net.": {},
- "pdengagementapi.trafficmanager.net.": {},
- "pdfforge.org.": {},
- "pdrnetwork-my.sharepoint.com.": {},
- "penngaming-my.sharepoint.com.": {},
- "penngaming.sharepoint.com.": {},
- "penskeauto-my.sharepoint.com.": {},
- "penskeauto.sharepoint.com.": {},
- "peopleadmin.com.": {},
- "pepsico-my.sharepoint.com.": {},
- "pepsico.sharepoint.com.": {},
- "pepsico.zoom.us.": {},
- "perf-eu1.hsforms.com.": {},
- "permutive.arstechnica.com.": {},
- "permutive.businessinsider.com.": {},
- "permutive.com.": {},
- "permutive.newyorker.com.": {},
- "permutive.wired.com.": {},
- "perr.brightvpn.com.": {},
- "perrigo-my.sharepoint.com.": {},
- "perrigo.sharepoint.com.": {},
- "pf.intuit.com.": {},
- "pfgsales-my.sharepoint.com.": {},
- "pfgsales.sharepoint.com.": {},
- "ph.globe.rcs.telephony.goog.": {},
- "pharos.studyquicks.com.": {},
- "phoenix.remotepc.com.": {},
- "phoenix2.remotepc.com.": {},
- "phx02pap001.storage.live.com.": {},
- "phx02pap002.storage.live.com.": {},
- "phx02pap003.storage.live.com.": {},
- "phx02pap004.storage.live.com.": {},
- "phx02pap005.storage.live.com.": {},
- "phx02pap006.storage.live.com.": {},
- "phx02pap007.storage.live.com.": {},
- "pi2850.ci.managedwhitelisting.com.": {},
- "piano.io.": {},
- "pie-api.io.": {},
- "pikabu.ru.": {},
- "ping.getadblock.com.": {},
- "pingler.com.": {},
- "pingmesh.bigo.sg.": {},
- "pinimg.com.": {},
- "piojm.tech.": {},
- "pis.alicdn.com.": {},
- "pittsburgh.remotepc.com.": {},
- "pix.cdnwidget.com.": {},
- "pixel-sync.trafficmanager.net.": {},
- "pixel.adlooxtracking.com.": {},
- "pixel.gliacloud.com.": {},
- "pjcr-my.sharepoint.com.": {},
- "pkgconnect-my.sharepoint.com.": {},
- "pla-prod-scu-apim-01.azure-api.net.": {},
- "playmatic.video.": {},
- "playstream.media.": {},
- "plrm.zone.": {},
- "plrsrvcs.com.": {},
- "pm.geniusmonkey.com.": {},
- "pns.alicdn.com.": {},
- "pogothere.xyz.": {},
- "poizon.com.": {},
- "polarisind-my.sharepoint.com.": {},
- "polarisind.sharepoint.com.": {},
- "policy.www.tripadvisor.com.edge.tacdn.com.": {},
- "polling.zoom.us.": {},
- "polyfill.archive.org.": {},
- "popt.in.": {},
- "portal.mypearson.com.": {},
- "portal.myweblogon.com.": {},
- "portals.mobi.": {},
- "portland.remotepc.com.": {},
- "portlandoregongov-my.sharepoint.com.": {},
- "posthog.com.": {},
- "pov.spectrum.net.": {},
- "pow7.com.": {},
- "powerpoint-collab.officeapps.live.com.": {},
- "powerpushsell.site.": {},
- "ppgames.net.": {},
- "pr-pod3-smp-device.apple.com.": {},
- "pr-pod5-smp-device.apple.com.": {},
- "pragmaticplay.net.": {},
- "prebid-am.casalemedia.com.": {},
- "prebid-la.casalemedia.com.": {},
- "prebid-ny.casalemedia.com.": {},
- "prebid-sj.casalemedia.com.": {},
- "prebid-va.casalemedia.com.": {},
- "prebid.trustedstack.com.": {},
- "prebidserver.pixfuture.com.": {},
- "precisionmedicinegroup-my.sharepoint.com.": {},
- "precisionmedicinegroup.sharepoint.com.": {},
- "premierhealth-my.sharepoint.com.": {},
- "premierhealth.sharepoint.com.": {},
- "premium.xvpn.io.": {},
- "printaudit.com.": {},
- "pro-swishapps-aks-tm.trafficmanager.net.": {},
- "procore.com.": {},
- "prod-catalog-autosuggest-api.dickssportinggoods.com.": {},
- "prod-client-api.v.aaplimg.com.": {},
- "prod-default.lb.logrocket.network.": {},
- "prod-event-relay-api.v.aaplimg.com.": {},
- "prod-event-relay-books-api.v.aaplimg.com.": {},
- "prod-event-relay-notes-api.v.aaplimg.com.": {},
- "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-newsletter-edge.v.aaplimg.com.": {},
- "prod-rso.lol.qq.com.": {},
- "prod-weather-widget-event-gateway.v.aaplimg.com.": {},
- "prod.api.letsencrypt.org.": {},
- "prod.uno.demonware.net.": {},
- "prodimage.images-bn.com.": {},
- "production-login-assets0.cdn.procore.com.": {},
- "production-login-assets1.cdn.procore.com.": {},
- "production-login-assets2.cdn.procore.com.": {},
- "production-login-assets3.cdn.procore.com.": {},
- "production.kabutoservices.com.": {},
- "promega-my.sharepoint.com.": {},
- "prosperitybankusa.sharepoint.com.": {},
- "protonvpn.com.": {},
- "provaltech.com.": {},
- "proxy-safebrowsing.googleapis.com.": {},
- "proxy.mob.maps.yandex.net.": {},
- "ps.namequery.com.": {},
- "psav-my.sharepoint.com.": {},
- "psav.sharepoint.com.": {},
- "pshud.365lpodds.com.": {},
- "pths209-my.sharepoint.com.": {},
- "pttor-my.sharepoint.com.": {},
- "pttplc-my.sharepoint.com.": {},
- "pub.affilimateapis.com.": {},
- "pub.network.": {},
- "public.bn.files.1drv.com.": {},
- "public.boxcloud.com.": {},
- "public.dm.files.1drv.com.": {},
- "publictracker.xyz.": {},
- "publisher.liveperson.net.": {},
- "puffer.6.401402081.west-gcloud.codm.activision.com.": {},
- "puhsd210-my.sharepoint.com.": {},
- "puhsd210.sharepoint.com.": {},
- "pull-cmaf-f77-tt03.fcdn.eu.tiktokcdn.com.": {},
- "pull-flv-l77-gcp01.eu.tiktokcdn.com.": {},
- "pull-flv-l77-va01.tiktokcdn.com.": {},
- "punch.p2p.qq.com.": {},
- "pusd11net-my.sharepoint.com.": {},
- "pusd11net.sharepoint.com.": {},
- "push-row.zui.com.": {},
- "push.omiapp.me.": {},
- "pushcrew.com.": {},
- "pushmac.flexibits.com.": {},
- "pushmart.net.": {},
- "pushnetwork.com.": {},
- "pushtrs7.push.hicloud.com.": {},
- "puswdsprmtprs.dealersocket.com.": {},
- "puv.tt.browser.360.cn.": {},
- "pwa.zoom.us.": {},
- "px4.ads.linkedin.com.": {},
- "pypestream.com.": {},
- "qa.sockets.stackexchange.com.": {},
- "qagpublic.qg1.apps.qualys.ca.": {},
- "qagpublic.qg1.apps.qualys.co.uk.": {},
- "qagpublic.qg1.apps.qualys.com.": {},
- "qagpublic.qg1.apps.qualys.eu.": {},
- "qagpublic.qg2.apps.qualys.com.": {},
- "qagpublic.qg2.apps.qualys.eu.": {},
- "qagpublic.qg3.apps.qualys.com.": {},
- "qagpublic.qg4.apps.qualys.com.": {},
- "qcloud.com.": {},
- "qfp.intuit.com.": {},
- "qikify.com.": {},
- "qm.progressive.com.": {},
- "qookkagames.com.": {},
- "qorvo-my.sharepoint.com.": {},
- "qorvo.sharepoint.com.": {},
- "qpic.cn.": {},
- "qq.com.cn.": {},
- "qsbr.cf2.quoracdn.net.cdn.cloudflare.net.": {},
- "qualys.ca.": {},
- "qualys.com.": {},
- "qualys.eu.": {},
- "quantamagazine.org.": {},
- "quebeccity.remotepc.com.": {},
- "questdiagnostics.sharepoint.com.": {},
- "quotemedia.com.": {},
- "qurl.f.360.cn.": {},
- "qvc.com.": {},
- "qwant.com.": {},
- "qxwz.com.": {},
- "r.ingest-lr.com.": {},
- "r.intake-lr.com.": {},
- "r.logr-ingest.com.": {},
- "r.logrocket.io.": {},
- "r.lr-hv-in.com.": {},
- "r.lr-in-prod.com.": {},
- "r.lr-in.com.": {},
- "r.lr-ingest.com.": {},
- "r.lr-ingest.io.": {},
- "r.lr-intake.com.": {},
- "r.office.microsoft.com.": {},
- "r.superhuman.com.": {},
- "r.turn.com.": {},
- "r1---sn-a5meknzk.c.2mdn.net.": {},
- "r1---sn-ab5l6nk6.c.2mdn.net.": {},
- "r1---sn-ab5l6nkd.c.2mdn.net.": {},
- "r1---sn-ab5l6nr6.c.2mdn.net.": {},
- "r1---sn-ab5l6nrd.c.2mdn.net.": {},
- "r1---sn-ab5l6nrk.c.2mdn.net.": {},
- "r1---sn-ab5l6nrl.c.2mdn.net.": {},
- "r1---sn-ab5l6nrs.c.2mdn.net.": {},
- "r1---sn-ab5sznlk.c.2mdn.net.": {},
- "r1---sn-ab5sznzd.c.2mdn.net.": {},
- "r1---sn-ab5sznzk.c.2mdn.net.": {},
- "r1---sn-ab5sznzl.c.2mdn.net.": {},
- "r1---sn-ab5sznzr.c.2mdn.net.": {},
- "r1---sn-ab5sznzs.c.2mdn.net.": {},
- "r1---sn-ab5sznzz.c.2mdn.net.": {},
- "r1---sn-p5qddn7d.c.2mdn.net.": {},
- "r1---sn-p5qddn7k.c.2mdn.net.": {},
- "r1---sn-p5qddn7z.c.2mdn.net.": {},
- "r1---sn-p5qlsn7s.c.2mdn.net.": {},
- "r1---sn-p5qs7nsk.c.2mdn.net.": {},
- "r1---sn-p5qs7nzk.c.2mdn.net.": {},
- "r1---sn-q4fl6ndl.c.2mdn.net.": {},
- "r1---sn-q4fl6nss.c.2mdn.net.": {},
- "r1---sn-q4flrnl6.c.2mdn.net.": {},
- "r1---sn-q4flrnlz.c.2mdn.net.": {},
- "r1---sn-q4flrnsk.c.2mdn.net.": {},
- "r1---sn-q4fzen7y.c.2mdn.net.": {},
- "r1---sn-vgqskn67.c.2mdn.net.": {},
- "r1---sn-vgqskn6d.c.2mdn.net.": {},
- "r1---sn-vgqsknes.c.2mdn.net.": {},
- "r1---sn-vgqsknez.c.2mdn.net.": {},
- "r1---sn-vgqsknld.c.2mdn.net.": {},
- "r1---sn-vgqsknse.c.2mdn.net.": {},
- "r1---sn-vgqsknsk.c.2mdn.net.": {},
- "r1---sn-vgqsknz6.c.2mdn.net.": {},
- "r1---sn-vgqsknz7.c.2mdn.net.": {},
- "r1---sn-vgqsknzd.c.2mdn.net.": {},
- "r1---sn-vgqsknze.c.2mdn.net.": {},
- "r1---sn-vgqsknzr.c.2mdn.net.": {},
- "r1---sn-vgqsrn66.c.2mdn.net.": {},
- "r1---sn-vgqsrn67.c.2mdn.net.": {},
- "r1---sn-vgqsrn6e.c.2mdn.net.": {},
- "r1---sn-vgqsrn6l.c.2mdn.net.": {},
- "r1---sn-vgqsrn6z.c.2mdn.net.": {},
- "r1---sn-vgqsrne6.c.2mdn.net.": {},
- "r1---sn-vgqsrnld.c.2mdn.net.": {},
- "r1---sn-vgqsrnlk.c.2mdn.net.": {},
- "r1---sn-vgqsrnsd.c.2mdn.net.": {},
- "r1---sn-vgqsrnsy.c.2mdn.net.": {},
- "r1---sn-vgqsrnz7.c.2mdn.net.": {},
- "r1---sn-vgqsrnzk.c.2mdn.net.": {},
- "r1---sn-vgqsrnzs.c.2mdn.net.": {},
- "r1---sn-vgqsrnzz.c.2mdn.net.": {},
- "r2---sn-a5mekn6l.c.2mdn.net.": {},
- "r2---sn-ab5l6nk6.c.2mdn.net.": {},
- "r2---sn-ab5l6nkd.c.2mdn.net.": {},
- "r2---sn-ab5l6nr6.c.2mdn.net.": {},
- "r2---sn-ab5l6nrd.c.2mdn.net.": {},
- "r2---sn-ab5l6nrl.c.2mdn.net.": {},
- "r2---sn-ab5l6nrz.c.2mdn.net.": {},
- "r2---sn-ab5sznld.c.2mdn.net.": {},
- "r2---sn-ab5sznz6.c.2mdn.net.": {},
- "r2---sn-ab5sznze.c.2mdn.net.": {},
- "r2---sn-ab5sznzk.c.2mdn.net.": {},
- "r2---sn-ab5sznzl.c.2mdn.net.": {},
- "r2---sn-ab5sznzr.c.2mdn.net.": {},
- "r2---sn-ab5sznzy.c.2mdn.net.": {},
- "r2---sn-ab5sznzz.c.2mdn.net.": {},
- "r2---sn-p5qddn7k.c.2mdn.net.": {},
- "r2---sn-p5qlsn7s.c.2mdn.net.": {},
- "r2---sn-p5qlsnrl.c.2mdn.net.": {},
- "r2---sn-p5qlsnrr.c.2mdn.net.": {},
- "r2---sn-p5qs7nsr.c.2mdn.net.": {},
- "r2---sn-q4fl6n66.c.2mdn.net.": {},
- "r2---sn-q4flrn7r.c.2mdn.net.": {},
- "r2---sn-q4flrney.c.2mdn.net.": {},
- "r2---sn-q4flrnle.c.2mdn.net.": {},
- "r2---sn-q4flrnsd.c.2mdn.net.": {},
- "r2---sn-q4flrnsl.c.2mdn.net.": {},
- "r2---sn-q4flrnss.c.2mdn.net.": {},
- "r2---sn-q4fzen7y.c.2mdn.net.": {},
- "r2---sn-q4fzene7.c.2mdn.net.": {},
- "r2---sn-vgqskn66.c.2mdn.net.": {},
- "r2---sn-vgqskn67.c.2mdn.net.": {},
- "r2---sn-vgqskn6d.c.2mdn.net.": {},
- "r2---sn-vgqsknld.c.2mdn.net.": {},
- "r2---sn-vgqsknlk.c.2mdn.net.": {},
- "r2---sn-vgqsknlr.c.2mdn.net.": {},
- "r2---sn-vgqskns7.c.2mdn.net.": {},
- "r2---sn-vgqsknz7.c.2mdn.net.": {},
- "r2---sn-vgqsknzs.c.2mdn.net.": {},
- "r2---sn-vgqsknzy.c.2mdn.net.": {},
- "r2---sn-vgqsrn67.c.2mdn.net.": {},
- "r2---sn-vgqsrn6l.c.2mdn.net.": {},
- "r2---sn-vgqsrnlz.c.2mdn.net.": {},
- "r2---sn-vgqsrnzk.c.2mdn.net.": {},
- "r2---sn-vgqsrnzr.c.2mdn.net.": {},
- "r3---sn-a5m7lnld.c.2mdn.net.": {},
- "r3---sn-a5meknds.c.2mdn.net.": {},
- "r3---sn-a5mlrnls.c.2mdn.net.": {},
- "r3---sn-ab5l6ndy.c.2mdn.net.": {},
- "r3---sn-ab5l6nk6.c.2mdn.net.": {},
- "r3---sn-ab5l6nkd.c.2mdn.net.": {},
- "r3---sn-ab5l6nr6.c.2mdn.net.": {},
- "r3---sn-ab5l6nrk.c.2mdn.net.": {},
- "r3---sn-ab5l6nrl.c.2mdn.net.": {},
- "r3---sn-ab5l6nrr.c.2mdn.net.": {},
- "r3---sn-ab5l6nrs.c.2mdn.net.": {},
- "r3---sn-ab5l6nrz.c.2mdn.net.": {},
- "r3---sn-ab5sznld.c.2mdn.net.": {},
- "r3---sn-ab5sznz6.c.2mdn.net.": {},
- "r3---sn-ab5sznzd.c.2mdn.net.": {},
- "r3---sn-ab5sznze.c.2mdn.net.": {},
- "r3---sn-ab5sznzk.c.2mdn.net.": {},
- "r3---sn-ab5sznzl.c.2mdn.net.": {},
- "r3---sn-ab5sznzs.c.2mdn.net.": {},
- "r3---sn-ab5sznzy.c.2mdn.net.": {},
- "r3---sn-ab5sznzz.c.2mdn.net.": {},
- "r3---sn-p5qddn7d.c.2mdn.net.": {},
- "r3---sn-p5qddn7k.c.2mdn.net.": {},
- "r3---sn-p5qlsn6l.c.2mdn.net.": {},
- "r3---sn-p5qlsn76.c.2mdn.net.": {},
- "r3---sn-p5qlsn7s.c.2mdn.net.": {},
- "r3---sn-p5qlsnrl.c.2mdn.net.": {},
- "r3---sn-p5qlsny6.c.2mdn.net.": {},
- "r3---sn-p5qs7nzr.c.2mdn.net.": {},
- "r3---sn-p5qs7nzy.c.2mdn.net.": {},
- "r3---sn-q4fl6n6z.c.2mdn.net.": {},
- "r3---sn-q4fl6ndl.c.2mdn.net.": {},
- "r3---sn-q4fl6ndz.c.2mdn.net.": {},
- "r3---sn-q4fl6ns6.c.2mdn.net.": {},
- "r3---sn-q4flrnle.c.2mdn.net.": {},
- "r3---sn-q4fzen7l.c.2mdn.net.": {},
- "r3---sn-q4fzen7y.c.2mdn.net.": {},
- "r3---sn-q4fzene7.c.2mdn.net.": {},
- "r3---sn-vgqskn6z.c.2mdn.net.": {},
- "r3---sn-vgqsknez.c.2mdn.net.": {},
- "r3---sn-vgqsknld.c.2mdn.net.": {},
- "r3---sn-vgqsknlk.c.2mdn.net.": {},
- "r3---sn-vgqsknly.c.2mdn.net.": {},
- "r3---sn-vgqsknse.c.2mdn.net.": {},
- "r3---sn-vgqsknz7.c.2mdn.net.": {},
- "r3---sn-vgqsknzd.c.2mdn.net.": {},
- "r3---sn-vgqsknzl.c.2mdn.net.": {},
- "r3---sn-vgqsknzy.c.2mdn.net.": {},
- "r3---sn-vgqsrn67.c.2mdn.net.": {},
- "r3---sn-vgqsrn6z.c.2mdn.net.": {},
- "r3---sn-vgqsrned.c.2mdn.net.": {},
- "r3---sn-vgqsrnsy.c.2mdn.net.": {},
- "r3---sn-vgqsrnzd.c.2mdn.net.": {},
- "r3---sn-vgqsrnzk.c.2mdn.net.": {},
- "r3---sn-vgqsrnzs.c.2mdn.net.": {},
- "r3---sn-vgqsrnzz.c.2mdn.net.": {},
- "r4---sn-a5mekn6s.c.2mdn.net.": {},
- "r4---sn-a5mlrnlz.c.2mdn.net.": {},
- "r4---sn-ab5l6ndr.c.2mdn.net.": {},
- "r4---sn-ab5l6nk6.c.2mdn.net.": {},
- "r4---sn-ab5l6nkd.c.2mdn.net.": {},
- "r4---sn-ab5l6nr6.c.2mdn.net.": {},
- "r4---sn-ab5l6nrd.c.2mdn.net.": {},
- "r4---sn-ab5l6nrk.c.2mdn.net.": {},
- "r4---sn-ab5l6nrl.c.2mdn.net.": {},
- "r4---sn-ab5l6nrr.c.2mdn.net.": {},
- "r4---sn-ab5l6nrs.c.2mdn.net.": {},
- "r4---sn-ab5l6nrz.c.2mdn.net.": {},
- "r4---sn-ab5sznz6.c.2mdn.net.": {},
- "r4---sn-ab5sznzd.c.2mdn.net.": {},
- "r4---sn-ab5sznze.c.2mdn.net.": {},
- "r4---sn-ab5sznzl.c.2mdn.net.": {},
- "r4---sn-ab5sznzr.c.2mdn.net.": {},
- "r4---sn-ab5sznzs.c.2mdn.net.": {},
- "r4---sn-ab5sznzy.c.2mdn.net.": {},
- "r4---sn-p5qddn7k.c.2mdn.net.": {},
- "r4---sn-p5qlsn76.c.2mdn.net.": {},
- "r4---sn-p5qlsn7l.c.2mdn.net.": {},
- "r4---sn-p5qlsnd6.c.2mdn.net.": {},
- "r4---sn-p5qlsnrl.c.2mdn.net.": {},
- "r4---sn-p5qlsny6.c.2mdn.net.": {},
- "r4---sn-p5qs7nsr.c.2mdn.net.": {},
- "r4---sn-q4fl6n6z.c.2mdn.net.": {},
- "r4---sn-q4fl6ndl.c.2mdn.net.": {},
- "r4---sn-q4fl6nds.c.2mdn.net.": {},
- "r4---sn-q4fl6nsd.c.2mdn.net.": {},
- "r4---sn-q4fl6nsr.c.2mdn.net.": {},
- "r4---sn-q4fl6nz6.c.2mdn.net.": {},
- "r4---sn-q4flrnel.c.2mdn.net.": {},
- "r4---sn-q4flrney.c.2mdn.net.": {},
- "r4---sn-q4fzen7y.c.2mdn.net.": {},
- "r4---sn-vgqskn66.c.2mdn.net.": {},
- "r4---sn-vgqskn6s.c.2mdn.net.": {},
- "r4---sn-vgqskn6z.c.2mdn.net.": {},
- "r4---sn-vgqsknld.c.2mdn.net.": {},
- "r4---sn-vgqsknlr.c.2mdn.net.": {},
- "r4---sn-vgqsknls.c.2mdn.net.": {},
- "r4---sn-vgqsknsk.c.2mdn.net.": {},
- "r4---sn-vgqsknze.c.2mdn.net.": {},
- "r4---sn-vgqsknzk.c.2mdn.net.": {},
- "r4---sn-vgqsrn67.c.2mdn.net.": {},
- "r4---sn-vgqsrn6e.c.2mdn.net.": {},
- "r4---sn-vgqsrn6z.c.2mdn.net.": {},
- "r4---sn-vgqsrned.c.2mdn.net.": {},
- "r4---sn-vgqsrnl6.c.2mdn.net.": {},
- "r4---sn-vgqsrnld.c.2mdn.net.": {},
- "r4---sn-vgqsrnlk.c.2mdn.net.": {},
- "r4---sn-vgqsrnlz.c.2mdn.net.": {},
- "r4---sn-vgqsrns6.c.2mdn.net.": {},
- "r4---sn-vgqsrnsy.c.2mdn.net.": {},
- "r4---sn-vgqsrnz6.c.2mdn.net.": {},
- "r4---sn-vgqsrnzd.c.2mdn.net.": {},
- "r4---sn-vgqsrnzs.c.2mdn.net.": {},
- "r5---sn-a5meknds.c.2mdn.net.": {},
- "r5---sn-ab5l6ndr.c.2mdn.net.": {},
- "r5---sn-ab5l6nk6.c.2mdn.net.": {},
- "r5---sn-ab5l6nkd.c.2mdn.net.": {},
- "r5---sn-ab5l6nr6.c.2mdn.net.": {},
- "r5---sn-ab5l6nrd.c.2mdn.net.": {},
- "r5---sn-ab5l6nrk.c.2mdn.net.": {},
- "r5---sn-ab5l6nrl.c.2mdn.net.": {},
- "r5---sn-ab5l6nrs.c.2mdn.net.": {},
- "r5---sn-ab5l6nrz.c.2mdn.net.": {},
- "r5---sn-ab5sznld.c.2mdn.net.": {},
- "r5---sn-ab5sznlk.c.2mdn.net.": {},
- "r5---sn-ab5sznz6.c.2mdn.net.": {},
- "r5---sn-ab5sznzd.c.2mdn.net.": {},
- "r5---sn-ab5sznzl.c.2mdn.net.": {},
- "r5---sn-ab5sznzr.c.2mdn.net.": {},
- "r5---sn-ab5sznzs.c.2mdn.net.": {},
- "r5---sn-ab5sznzy.c.2mdn.net.": {},
- "r5---sn-ab5sznzz.c.2mdn.net.": {},
- "r5---sn-hp57ynl6.c.2mdn.net.": {},
- "r5---sn-p5qddn7d.c.2mdn.net.": {},
- "r5---sn-p5qddn7z.c.2mdn.net.": {},
- "r5---sn-p5qlsn6l.c.2mdn.net.": {},
- "r5---sn-p5qlsn76.c.2mdn.net.": {},
- "r5---sn-p5qlsn7s.c.2mdn.net.": {},
- "r5---sn-p5qlsnrr.c.2mdn.net.": {},
- "r5---sn-p5qs7n6d.c.2mdn.net.": {},
- "r5---sn-p5qs7nzk.c.2mdn.net.": {},
- "r5---sn-p5qs7nzr.c.2mdn.net.": {},
- "r5---sn-p5qs7nzy.c.2mdn.net.": {},
- "r5---sn-q4fl6ndl.c.2mdn.net.": {},
- "r5---sn-q4fl6nsr.c.2mdn.net.": {},
- "r5---sn-q4flrnsd.c.2mdn.net.": {},
- "r5---sn-q4flrnsl.c.2mdn.net.": {},
- "r5---sn-vgqskn67.c.2mdn.net.": {},
- "r5---sn-vgqskn6d.c.2mdn.net.": {},
- "r5---sn-vgqsknes.c.2mdn.net.": {},
- "r5---sn-vgqsknlk.c.2mdn.net.": {},
- "r5---sn-vgqsknlr.c.2mdn.net.": {},
- "r5---sn-vgqsknls.c.2mdn.net.": {},
- "r5---sn-vgqsknly.c.2mdn.net.": {},
- "r5---sn-vgqsknse.c.2mdn.net.": {},
- "r5---sn-vgqsknsk.c.2mdn.net.": {},
- "r5---sn-vgqsknz7.c.2mdn.net.": {},
- "r5---sn-vgqsknzl.c.2mdn.net.": {},
- "r5---sn-vgqsknzr.c.2mdn.net.": {},
- "r5---sn-vgqsknzs.c.2mdn.net.": {},
- "r5---sn-vgqsknzz.c.2mdn.net.": {},
- "r5---sn-vgqsrn66.c.2mdn.net.": {},
- "r5---sn-vgqsrn6e.c.2mdn.net.": {},
- "r5---sn-vgqsrn6l.c.2mdn.net.": {},
- "r5---sn-vgqsrnez.c.2mdn.net.": {},
- "r5---sn-vgqsrnl6.c.2mdn.net.": {},
- "r5---sn-vgqsrnld.c.2mdn.net.": {},
- "r5---sn-vgqsrnlk.c.2mdn.net.": {},
- "r5---sn-vgqsrnlz.c.2mdn.net.": {},
- "r5---sn-vgqsrnsy.c.2mdn.net.": {},
- "r5---sn-vgqsrnz6.c.2mdn.net.": {},
- "r5---sn-vgqsrnzd.c.2mdn.net.": {},
- "r5---sn-vgqsrnzk.c.2mdn.net.": {},
- "r5---sn-vgqsrnzr.c.2mdn.net.": {},
- "r5---sn-vgqsrnzs.c.2mdn.net.": {},
- "raccorp-my.sharepoint.com.": {},
- "raccorp.sharepoint.com.": {},
- "radar.cedexis.com.": {},
- "raleigh.remotepc.com.": {},
- "randomhouse.app.box.com.": {},
- "raspbian.raspberrypi.org.": {},
- "rba-screen.healthsafe-id.com.": {},
- "rba.onehealthcareid.com.": {},
- "rbmeuulvihtwm2eltjhwimi2.httpschecker.net.": {},
- "rcs-acs-mcc510.jibe.google.com.": {},
- "rcs-acs-tmobile-us.jibe.google.com.": {},
- "rcs-copper-us.googleapis.com.": {},
- "rcs-user-content-us.storage.googleapis.com.": {},
- "rcs.telephony.goog.": {},
- "rd.com.": {},
- "realtime.luckyorange.com.": {},
- "realtime.services.box.net.": {},
- "recharge-prod-apim.azure-api.net.": {},
- "recombee.com.": {},
- "recruiting.ultipro.com.": {},
- "recruiting2.ultipro.com.": {},
- "redcoolmedia.net.": {},
- "reedelsevier-my.sharepoint.com.": {},
- "reedelsevier.sharepoint.com.": {},
- "referconfigexternal.americanexpress.com.": {},
- "reflector.makerbot.com.": {},
- "registration.prap01.cmdagent.trafficmanager.net.": {},
- "registration.prau01.cmdagent.trafficmanager.net.": {},
- "registration.preu01.cmdagent.trafficmanager.net.": {},
- "registration.prna01.cmdagent.trafficmanager.net.": {},
- "regn-my.sharepoint.com.": {},
- "regn.sharepoint.com.": {},
- "reichelcormier.bid.": {},
- "rejuvenation.com.": {},
- "remote.control4.com.": {},
- "remote.melonhead.me.": {},
- "render.geozo.com.": {},
- "renklitoplar.com.": {},
- "replit.dev.": {},
- "repo.zabbix.com.": {},
- "republicservices-my.sharepoint.com.": {},
- "republicservices.sharepoint.com.": {},
- "request-global.czilladx.com.": {},
- "resc.cloudinary.com.cdn.cloudflare.net.": {},
- "resideo.com.": {},
- "resource.digitalinsight.com.": {},
- "restproxy-analytics.ascendlearning.com.": {},
- "restrict.youtube.com.": {},
- "restrictmoderate.youtube.com.": {},
- "retail.rpay.roku.com.": {},
- "retailrocket.net.": {},
- "retailstarbucks1com-my.sharepoint.com.": {},
- "retailstarbucks1com.sharepoint.com.": {},
- "retcode-us-west-1.arms.aliyuncs.com.": {},
- "rethinkad.com.": {},
- "retinavue.net.": {},
- "reverso.net.": {},
- "rhmail-my.sharepoint.com.": {},
- "rhmail.sharepoint.com.": {},
- "ri9864.ci.managedwhitelisting.com.": {},
- "richrelevance.com.": {},
- "ridgewireless.mm.fcix.net.": {},
- "rivergame.net.": {},
- "rivhs-my.sharepoint.com.": {},
- "rl.progressive.com.": {},
- "rl.quantummetric.com.": {},
- "rmm.acctek.com.": {},
- "rmm.aunalytics.com.": {},
- "rms-dra.platform.dbankcloud.com.": {},
- "rn-resource-app.xiaohongshu.com.": {},
- "roberthalf-my.sharepoint.com.": {},
- "roberthalf.sharepoint.com.": {},
- "roborock.com.": {},
- "rocketsutoledo-my.sharepoint.com.": {},
- "rockhillssch.aristotleinsight.com.": {},
- "rockwellautomation-my.sharepoint.com.": {},
- "rockwellautomation.sharepoint.com.": {},
- "rockylinux.org.": {},
- "rogueone.aristotleinsight.com.": {},
- "roieu.xyz.": {},
- "romsp-unifyconfig.vivo.com.cn.": {},
- "roninchain.com.": {},
- "rottentomatoes-app.quantummetric.com.": {},
- "router.teamviewer.com.": {},
- "roxy.azurefd.net.": {},
- "rpiexchange-my.sharepoint.com.": {},
- "rpt.cedexis.com.": {},
- "rq.wh.cmcm.com.": {},
- "rr1---sn-02o-ao3e.googlevideo.com.": {},
- "rr1---sn-0nnpbo5a-bggl.googlevideo.com.": {},
- "rr1---sn-0op8v4h5pox-cbgl.googlevideo.com.": {},
- "rr1---sn-2imern76.googlevideo.com.": {},
- "rr1---sn-2imern7d.googlevideo.com.": {},
- "rr1---sn-2imeyn7k.googlevideo.com.": {},
- "rr1---sn-2napbiu-p5ie.googlevideo.com.": {},
- "rr1---sn-2napbiu-p5ie.gvt1.com.": {},
- "rr1---sn-2pmxapm0n-gpje.googlevideo.com.": {},
- "rr1---sn-2pmxapm0n-gpjl.googlevideo.com.": {},
- "rr1---sn-2puupm-2pue.googlevideo.com.": {},
- "rr1---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.": {},
- "rr1---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.": {},
- "rr1---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.": {},
- "rr1---sn-2vgu0b5auxaxjvh-v2vk.googlevideo.com.": {},
- "rr1---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.": {},
- "rr1---sn-2vgu0b5auxaxjvh-v2vz.googlevideo.com.": {},
- "rr1---sn-30a7rne6.googlevideo.com.": {},
- "rr1---sn-30a7rned.googlevideo.com.": {},
- "rr1---sn-30a7rnek.googlevideo.com.": {},
- "rr1---sn-30a7rner.googlevideo.com.": {},
- "rr1---sn-30a7ynek.googlevideo.com.": {},
- "rr1---sn-30a7yner.googlevideo.com.": {},
- "rr1---sn-30a7yney.googlevideo.com.": {},
- "rr1---sn-30a7ynl7.googlevideo.com.": {},
- "rr1---sn-3jpm-hjpe.googlevideo.com.": {},
- "rr1---sn-3jpm-hjpe.gvt1.com.": {},
- "rr1---sn-3n4pcxg-pjul.googlevideo.com.": {},
- "rr1---sn-42a4pcxgoxu-hp5e.googlevideo.com.": {},
- "rr1---sn-4g5e6ns6.googlevideo.com.": {},
- "rr1---sn-4g5e6ns7.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.": {},
- "rr1---sn-4g5e6nze.googlevideo.com.": {},
- "rr1---sn-4g5e6nzl.googlevideo.com.": {},
- "rr1---sn-4g5e6nzs.googlevideo.com.": {},
- "rr1---sn-4g5e6nzz.googlevideo.com.": {},
- "rr1---sn-4g5edn6k.googlevideo.com.": {},
- "rr1---sn-4g5edn6r.googlevideo.com.": {},
- "rr1---sn-4g5edn6y.googlevideo.com.": {},
- "rr1---sn-4g5ednd7.googlevideo.com.": {},
- "rr1---sn-4g5edndd.googlevideo.com.": {},
- "rr1---sn-4g5ednde.googlevideo.com.": {},
- "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.": {},
- "rr1---sn-4g5ednld.googlevideo.com.": {},
- "rr1---sn-4g5ednly.googlevideo.com.": {},
- "rr1---sn-4g5edns6.googlevideo.com.": {},
- "rr1---sn-4g5edns7.googlevideo.com.": {},
- "rr1---sn-4g5ednsd.googlevideo.com.": {},
- "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-4g5ednsz.googlevideo.com.": {},
- "rr1---sn-4g5ednz7.googlevideo.com.": {},
- "rr1---sn-4g5lzne6.googlevideo.com.": {},
- "rr1---sn-4g5lznek.googlevideo.com.": {},
- "rr1---sn-4g5lzner.googlevideo.com.": {},
- "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-4jjo-apnl.googlevideo.com.": {},
- "rr1---sn-4pgnuapbiu-hiue.googlevideo.com.": {},
- "rr1---sn-4pgnuapbiu-hiul.googlevideo.com.": {},
- "rr1---sn-5gxo-in8l.googlevideo.com.": {},
- "rr1---sn-5gxo-in8s.googlevideo.com.": {},
- "rr1---sn-5hne6n6e.googlevideo.com.": {},
- "rr1---sn-5hne6n6l.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.": {},
- "rr1---sn-5hne6nzd.googlevideo.com.": {},
- "rr1---sn-5hne6nzk.googlevideo.com.": {},
- "rr1---sn-5hne6nzs.googlevideo.com.": {},
- "rr1---sn-5hne6nzy.googlevideo.com.": {},
- "rr1---sn-5hnednss.googlevideo.com.": {},
- "rr1---sn-5hnednsz.googlevideo.com.": {},
- "rr1---sn-5hnednsz.gvt1.com.": {},
- "rr1---sn-5hnekn76.googlevideo.com.": {},
- "rr1---sn-5hnekn7d.googlevideo.com.": {},
- "rr1---sn-5hnekn7k.googlevideo.com.": {},
- "rr1---sn-5hnekn7l.googlevideo.com.": {},
- "rr1---sn-5hnekn7s.googlevideo.com.": {},
- "rr1---sn-5hnekn7z.googlevideo.com.": {},
- "rr1---sn-5hneknee.googlevideo.com.": {},
- "rr1---sn-5hneknek.googlevideo.com.": {},
- "rr1---sn-5hneknes.googlevideo.com.": {},
- "rr1---sn-5pgnugx5h-hn2s.googlevideo.com.": {},
- "rr1---sn-5pgnugx5h-hn2z.googlevideo.com.": {},
- "rr1---sn-5uaezndd.googlevideo.com.": {},
- "rr1---sn-5uaezne6.googlevideo.com.": {},
- "rr1---sn-5uaezned.googlevideo.com.": {},
- "rr1---sn-5uaeznes.googlevideo.com.": {},
- "rr1---sn-5uaeznez.googlevideo.com.": {},
- "rr1---sn-5uaeznl6.googlevideo.com.": {},
- "rr1---sn-5uaeznld.googlevideo.com.": {},
- "rr1---sn-5uaeznls.googlevideo.com.": {},
- "rr1---sn-5uaeznly.googlevideo.com.": {},
- "rr1---sn-5uaeznlz.googlevideo.com.": {},
- "rr1---sn-5uaeznrz.googlevideo.com.": {},
- "rr1---sn-5uaezns7.googlevideo.com.": {},
- "rr1---sn-5uaeznse.googlevideo.com.": {},
- "rr1---sn-5uaeznsl.googlevideo.com.": {},
- "rr1---sn-5uaeznss.googlevideo.com.": {},
- "rr1---sn-5uaezny6.googlevideo.com.": {},
- "rr1---sn-5uaeznys.googlevideo.com.": {},
- "rr1---sn-5uaeznyz.googlevideo.com.": {},
- "rr1---sn-5uaeznze.googlevideo.com.": {},
- "rr1---sn-5ualdnle.googlevideo.com.": {},
- "rr1---sn-5ualdnll.googlevideo.com.": {},
- "rr1---sn-5ualdnlr.googlevideo.com.": {},
- "rr1---sn-5ualdnls.googlevideo.com.": {},
- "rr1---sn-5ualdns6.googlevideo.com.": {},
- "rr1---sn-5ualdns7.googlevideo.com.": {},
- "rr1---sn-5ualdnse.googlevideo.com.": {},
- "rr1---sn-5ualdnsk.googlevideo.com.": {},
- "rr1---sn-5ualdnsl.googlevideo.com.": {},
- "rr1---sn-5ualdnsr.googlevideo.com.": {},
- "rr1---sn-5ualdnss.googlevideo.com.": {},
- "rr1---sn-5ualdnsy.googlevideo.com.": {},
- "rr1---sn-5ualdnsz.googlevideo.com.": {},
- "rr1---sn-5ualdnz7.googlevideo.com.": {},
- "rr1---sn-5ualdnze.googlevideo.com.": {},
- "rr1---sn-8qj-nbo66.googlevideo.com.": {},
- "rr1---sn-8qj-nbo6y.googlevideo.com.": {},
- "rr1---sn-8xgp1vo-2iae.googlevideo.com.": {},
- "rr1---sn-8xgp1vo-2iae7.googlevideo.com.": {},
- "rr1---sn-8xgp1vo-2ial.googlevideo.com.": {},
- "rr1---sn-8xgp1vo-a5me.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-hjpl.googlevideo.com.": {},
- "rr1---sn-8xgp1vo-p5ie.googlevideo.com.": {},
- "rr1---sn-8xgp1vo-xfge.googlevideo.com.": {},
- "rr1---sn-8xgp1vo-xfgl.googlevideo.com.": {},
- "rr1---sn-8xgp1vo-xfgs.googlevideo.com.": {},
- "rr1---sn-9gv76n7l.googlevideo.com.": {},
- "rr1---sn-9gv76n7s.googlevideo.com.": {},
- "rr1---sn-9gv7ene6.googlevideo.com.": {},
- "rr1---sn-9gv7ened.googlevideo.com.": {},
- "rr1---sn-9gv7zn76.googlevideo.com.": {},
- "rr1---sn-9gv7zn7e.googlevideo.com.": {},
- "rr1---sn-9gv7zn7r.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-a5meknde.gvt1.com.": {},
- "rr1---sn-a5mekndl.googlevideo.com.": {},
- "rr1---sn-a5meknds.googlevideo.com.": {},
- "rr1---sn-a5mekndz.googlevideo.com.": {},
- "rr1---sn-a5meknsy.googlevideo.com.": {},
- "rr1---sn-a5meknzk.googlevideo.com.": {},
- "rr1---sn-a5meknzr.googlevideo.com.": {},
- "rr1---sn-a5meknzr.gvt1.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-a5msen7l.googlevideo.com.": {},
- "rr1---sn-a5msen7s.googlevideo.com.": {},
- "rr1---sn-a5msen7s.gvt1.com.": {},
- "rr1---sn-a5msen7z.googlevideo.com.": {},
- "rr1---sn-a5msenek.googlevideo.com.": {},
- "rr1---sn-a5msenes.googlevideo.com.": {},
- "rr1---sn-a5msenes.gvt1.com.": {},
- "rr1---sn-a5msenl7.googlevideo.com.": {},
- "rr1---sn-a5msenle.googlevideo.com.": {},
- "rr1---sn-a5msenle.gvt1.com.": {},
- "rr1---sn-a5msenll.googlevideo.com.": {},
- "rr1---sn-a5oj5nuxg-aone.googlevideo.com.": {},
- "rr1---sn-ab5l6ndr.googlevideo.com.": {},
- "rr1---sn-ab5l6nk6.googlevideo.com.": {},
- "rr1---sn-ab5l6nkd.googlevideo.com.": {},
- "rr1---sn-ab5l6nr6.googlevideo.com.": {},
- "rr1---sn-ab5l6nrd.googlevideo.com.": {},
- "rr1---sn-ab5l6nrk.googlevideo.com.": {},
- "rr1---sn-ab5l6nrl.googlevideo.com.": {},
- "rr1---sn-ab5l6nrr.googlevideo.com.": {},
- "rr1---sn-ab5l6nrs.googlevideo.com.": {},
- "rr1---sn-ab5l6nrz.googlevideo.com.": {},
- "rr1---sn-ab5sznld.googlevideo.com.": {},
- "rr1---sn-ab5sznlk.googlevideo.com.": {},
- "rr1---sn-ab5sznly.googlevideo.com.": {},
- "rr1---sn-ab5sznz6.googlevideo.com.": {},
- "rr1---sn-ab5sznzd.googlevideo.com.": {},
- "rr1---sn-ab5sznze.googlevideo.com.": {},
- "rr1---sn-ab5sznzk.googlevideo.com.": {},
- "rr1---sn-ab5sznzl.googlevideo.com.": {},
- "rr1---sn-ab5sznzr.googlevideo.com.": {},
- "rr1---sn-ab5sznzs.googlevideo.com.": {},
- "rr1---sn-ab5sznzy.googlevideo.com.": {},
- "rr1---sn-ab5sznzz.googlevideo.com.": {},
- "rr1---sn-aigl6n6s.googlevideo.com.": {},
- "rr1---sn-aigl6ned.googlevideo.com.": {},
- "rr1---sn-aigl6nek.googlevideo.com.": {},
- "rr1---sn-aigl6ner.googlevideo.com.": {},
- "rr1---sn-aigl6ney.googlevideo.com.": {},
- "rr1---sn-aigl6nl7.googlevideo.com.": {},
- "rr1---sn-aigl6ns6.googlevideo.com.": {},
- "rr1---sn-aigl6nsd.googlevideo.com.": {},
- "rr1---sn-aigl6nsk.googlevideo.com.": {},
- "rr1---sn-aigl6nsr.googlevideo.com.": {},
- "rr1---sn-aigl6nz7.googlevideo.com.": {},
- "rr1---sn-aigl6nze.googlevideo.com.": {},
- "rr1---sn-aigl6nzk.googlevideo.com.": {},
- "rr1---sn-aigl6nzl.googlevideo.com.": {},
- "rr1---sn-aigl6nzr.googlevideo.com.": {},
- "rr1---sn-aigl6nzs.googlevideo.com.": {},
- "rr1---sn-aigzrn76.googlevideo.com.": {},
- "rr1---sn-aigzrn7d.googlevideo.com.": {},
- "rr1---sn-aigzrn7e.googlevideo.com.": {},
- "rr1---sn-aigzrn7k.googlevideo.com.": {},
- "rr1---sn-aigzrn7l.googlevideo.com.": {},
- "rr1---sn-aigzrn7s.googlevideo.com.": {},
- "rr1---sn-aigzrn7z.googlevideo.com.": {},
- "rr1---sn-aigzrne7.googlevideo.com.": {},
- "rr1---sn-aigzrnld.googlevideo.com.": {},
- "rr1---sn-aigzrnse.googlevideo.com.": {},
- "rr1---sn-aigzrnsl.googlevideo.com.": {},
- "rr1---sn-aigzrnsr.googlevideo.com.": {},
- "rr1---sn-aigzrnss.googlevideo.com.": {},
- "rr1---sn-aigzrnsz.googlevideo.com.": {},
- "rr1---sn-aigzrnz7.googlevideo.com.": {},
- "rr1---sn-aigzrnze.googlevideo.com.": {},
- "rr1---sn-apn7en7s.googlevideo.com.": {},
- "rr1---sn-bg5oqxjvh-50nz.googlevideo.com.": {},
- "rr1---sn-bg5oqxjvh-jg2s.googlevideo.com.": {},
- "rr1---sn-bg5oqxjvh-xa2s.googlevideo.com.": {},
- "rr1---sn-bvvbax-2iae.googlevideo.com.": {},
- "rr1---sn-c0q7lnz7.googlevideo.com.": {},
- "rr1---sn-cvb7lne7.googlevideo.com.": {},
- "rr1---sn-cvb7lnee.googlevideo.com.": {},
- "rr1---sn-cvb7lnls.googlevideo.com.": {},
- "rr1---sn-cvb7lnlz.googlevideo.com.": {},
- "rr1---sn-cvb7sn7k.googlevideo.com.": {},
- "rr1---sn-cvb7sn7r.googlevideo.com.": {},
- "rr1---sn-fpnjoxu-h3xl.googlevideo.com.": {},
- "rr1---sn-fpnjoxu-hnol.googlevideo.com.": {},
- "rr1---sn-gpuuxg-hxhl.googlevideo.com.": {},
- "rr1---sn-gpuuxg-hxhl.gvt1.com.": {},
- "rr1---sn-gpuuxg-hxhs.googlevideo.com.": {},
- "rr1---sn-gpuuxg-hxhs.gvt1.com.": {},
- "rr1---sn-gvbxgn-tvf6.googlevideo.com.": {},
- "rr1---sn-gvbxgn-tvfz.googlevideo.com.": {},
- "rr1---sn-h0jeened.googlevideo.com.": {},
- "rr1---sn-h0jeenek.googlevideo.com.": {},
- "rr1---sn-h0jeener.googlevideo.com.": {},
- "rr1---sn-h0jeenl6.googlevideo.com.": {},
- "rr1---sn-h0jeenld.googlevideo.com.": {},
- "rr1---sn-h0jeenle.googlevideo.com.": {},
- "rr1---sn-h0jeln7e.googlevideo.com.": {},
- "rr1---sn-h0jeln7l.googlevideo.com.": {},
- "rr1---sn-h0jelne6.googlevideo.com.": {},
- "rr1---sn-h0jelne7.googlevideo.com.": {},
- "rr1---sn-h0jelnez.googlevideo.com.": {},
- "rr1---sn-hjoj-jaul.googlevideo.com.": {},
- "rr1---sn-hjoj-poul.googlevideo.com.": {},
- "rr1---sn-hoa7kn76.googlevideo.com.": {},
- "rr1---sn-hoa7kn7z.googlevideo.com.": {},
- "rr1---sn-hoa7rn76.googlevideo.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-hp57kndk.googlevideo.com.": {},
- "rr1---sn-hp57kndr.googlevideo.com.": {},
- "rr1---sn-hp57kndy.googlevideo.com.": {},
- "rr1---sn-hp57kndz.googlevideo.com.": {},
- "rr1---sn-hp57kndz.gvt1.com.": {},
- "rr1---sn-hp57yn7r.googlevideo.com.": {},
- "rr1---sn-hp57yn7r.gvt1.com.": {},
- "rr1---sn-hp57yn7y.googlevideo.com.": {},
- "rr1---sn-hp57ynl6.googlevideo.com.": {},
- "rr1---sn-hp57ynl6.gvt1.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-hp57ynss.gvt1.com.": {},
- "rr1---sn-hxgpu-qufs.googlevideo.com.": {},
- "rr1---sn-i3b7kn6s.googlevideo.com.": {},
- "rr1---sn-i3b7knld.googlevideo.com.": {},
- "rr1---sn-i3b7knlk.googlevideo.com.": {},
- "rr1---sn-i3b7kns6.googlevideo.com.": {},
- "rr1---sn-i3b7knsd.googlevideo.com.": {},
- "rr1---sn-i3b7knse.googlevideo.com.": {},
- "rr1---sn-i3b7knsl.googlevideo.com.": {},
- "rr1---sn-i3b7knzl.googlevideo.com.": {},
- "rr1---sn-i3b7knzs.googlevideo.com.": {},
- "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-i3belnlz.googlevideo.com.": {},
- "rr1---sn-i3bssn7e.googlevideo.com.": {},
- "rr1---sn-i5f5ppuxa-ioal.googlevideo.com.": {},
- "rr1---sn-i5goxu-i3bl.googlevideo.com.": {},
- "rr1---sn-i5h7lner.googlevideo.com.": {},
- "rr1---sn-i5h7lnl6.googlevideo.com.": {},
- "rr1---sn-i5h7lnll.googlevideo.com.": {},
- "rr1---sn-i5h7lnls.googlevideo.com.": {},
- "rr1---sn-i5heen7d.googlevideo.com.": {},
- "rr1---sn-i5heen7r.googlevideo.com.": {},
- "rr1---sn-i5heen7s.googlevideo.com.": {},
- "rr1---sn-jn2pgx4pcxg-w5os.googlevideo.com.": {},
- "rr1---sn-jvhj5nu-2iae.googlevideo.com.": {},
- "rr1---sn-jvhj5nu-2ial.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-jvhj5nu-qufe.googlevideo.com.": {},
- "rr1---sn-jvhj5nu-qufl.googlevideo.com.": {},
- "rr1---sn-jvhj5nu-qufs.googlevideo.com.": {},
- "rr1---sn-jvhj5nu-qufz.googlevideo.com.": {},
- "rr1---sn-jxopj-n5oe.googlevideo.com.": {},
- "rr1---sn-jxopj-n5oe.gvt1.com.": {},
- "rr1---sn-muxa-2iae.googlevideo.com.": {},
- "rr1---sn-n0g45pg-ncoe.googlevideo.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.": {},
- "rr1---sn-n4v7snll.googlevideo.com.": {},
- "rr1---sn-n4v7snlr.googlevideo.com.": {},
- "rr1---sn-n4v7snls.googlevideo.com.": {},
- "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-npoe7ndl.googlevideo.com.": {},
- "rr1---sn-npoe7nds.googlevideo.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-npoe7ns7.googlevideo.com.": {},
- "rr1---sn-npoe7nsd.googlevideo.com.": {},
- "rr1---sn-npoe7nsk.googlevideo.com.": {},
- "rr1---sn-npoe7nsl.googlevideo.com.": {},
- "rr1---sn-npoe7nsr.googlevideo.com.": {},
- "rr1---sn-npoe7nss.googlevideo.com.": {},
- "rr1---sn-npoe7nsy.googlevideo.com.": {},
- "rr1---sn-npoe7nz7.googlevideo.com.": {},
- "rr1---sn-npoeene6.googlevideo.com.": {},
- "rr1---sn-npoeened.googlevideo.com.": {},
- "rr1---sn-npoeenee.googlevideo.com.": {},
- "rr1---sn-npoeenek.googlevideo.com.": {},
- "rr1---sn-npoeener.googlevideo.com.": {},
- "rr1---sn-npoeeney.googlevideo.com.": {},
- "rr1---sn-npoeenl7.googlevideo.com.": {},
- "rr1---sn-npoeenle.googlevideo.com.": {},
- "rr1---sn-npoeenlk.googlevideo.com.": {},
- "rr1---sn-npoeenll.googlevideo.com.": {},
- "rr1---sn-npoeens7.googlevideo.com.": {},
- "rr1---sn-npoldn76.googlevideo.com.": {},
- "rr1---sn-npoldn7d.googlevideo.com.": {},
- "rr1---sn-npoldn7e.googlevideo.com.": {},
- "rr1---sn-npoldn7l.googlevideo.com.": {},
- "rr1---sn-npoldn7s.googlevideo.com.": {},
- "rr1---sn-npoldn7y.googlevideo.com.": {},
- "rr1---sn-npoldn7z.googlevideo.com.": {},
- "rr1---sn-npoldne7.googlevideo.com.": {},
- "rr1---sn-nuagpm-nuae.googlevideo.com.": {},
- "rr1---sn-nv0uixgo-5ual.googlevideo.com.": {},
- "rr1---sn-nv47ln6e.googlevideo.com.": {},
- "rr1---sn-nv47zn7r.googlevideo.com.": {},
- "rr1---sn-nv47zn7y.googlevideo.com.": {},
- "rr1---sn-nv47zne7.googlevideo.com.": {},
- "rr1---sn-nv47znee.googlevideo.com.": {},
- "rr1---sn-nv47znel.googlevideo.com.": {},
- "rr1---sn-nx57ynlk.googlevideo.com.": {},
- "rr1---sn-nx57ynlk.gvt1.com.": {},
- "rr1---sn-nx57ynsd.googlevideo.com.": {},
- "rr1---sn-nx57ynse.googlevideo.com.": {},
- "rr1---sn-nx57ynsk.googlevideo.com.": {},
- "rr1---sn-nx57ynsl.googlevideo.com.": {},
- "rr1---sn-nx57ynsl.gvt1.com.": {},
- "rr1---sn-nx57ynss.googlevideo.com.": {},
- "rr1---sn-nx57ynsz.googlevideo.com.": {},
- "rr1---sn-nx57ynsz.gvt1.com.": {},
- "rr1---sn-nx5s7n76.googlevideo.com.": {},
- "rr1---sn-nx5s7n76.gvt1.com.": {},
- "rr1---sn-nx5s7n7d.googlevideo.com.": {},
- "rr1---sn-nx5s7n7d.gvt1.com.": {},
- "rr1---sn-nx5s7n7s.googlevideo.com.": {},
- "rr1---sn-nx5s7n7y.googlevideo.com.": {},
- "rr1---sn-nx5s7n7y.gvt1.com.": {},
- "rr1---sn-nx5s7n7z.googlevideo.com.": {},
- "rr1---sn-nx5s7nee.googlevideo.com.": {},
- "rr1---sn-nx5s7nee.gvt1.com.": {},
- "rr1---sn-nx5s7nel.googlevideo.com.": {},
- "rr1---sn-o097znsd.googlevideo.com.": {},
- "rr1---sn-o097znse.googlevideo.com.": {},
- "rr1---sn-o097znsk.googlevideo.com.": {},
- "rr1---sn-o097znsl.googlevideo.com.": {},
- "rr1---sn-o097znsr.googlevideo.com.": {},
- "rr1---sn-o097znss.googlevideo.com.": {},
- "rr1---sn-o097znsz.googlevideo.com.": {},
- "rr1---sn-o097znz7.googlevideo.com.": {},
- "rr1---sn-o097znzd.googlevideo.com.": {},
- "rr1---sn-o097znze.googlevideo.com.": {},
- "rr1---sn-o097znzk.googlevideo.com.": {},
- "rr1---sn-o097znzr.googlevideo.com.": {},
- "rr1---sn-opnq-n5ue.googlevideo.com.": {},
- "rr1---sn-ounjvhh-acce.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-p5qlsn76.googlevideo.com.": {},
- "rr1---sn-p5qlsn7d.googlevideo.com.": {},
- "rr1---sn-p5qlsn7l.googlevideo.com.": {},
- "rr1---sn-p5qlsn7s.googlevideo.com.": {},
- "rr1---sn-p5qlsnd6.googlevideo.com.": {},
- "rr1---sn-p5qlsndd.googlevideo.com.": {},
- "rr1---sn-p5qlsndk.googlevideo.com.": {},
- "rr1---sn-p5qlsndr.googlevideo.com.": {},
- "rr1---sn-p5qlsndz.googlevideo.com.": {},
- "rr1---sn-p5qlsnrl.googlevideo.com.": {},
- "rr1---sn-p5qlsnrr.googlevideo.com.": {},
- "rr1---sn-p5qlsny6.googlevideo.com.": {},
- "rr1---sn-p5qs7n6d.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-pjnpu-5hfe.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-q4fl6n6d.gvt1.com.": {},
- "rr1---sn-q4fl6n6r.googlevideo.com.": {},
- "rr1---sn-q4fl6n6s.googlevideo.com.": {},
- "rr1---sn-q4fl6n6s.gvt1.com.": {},
- "rr1---sn-q4fl6n6y.googlevideo.com.": {},
- "rr1---sn-q4fl6n6z.googlevideo.com.": {},
- "rr1---sn-q4fl6n6z.gvt1.com.": {},
- "rr1---sn-q4fl6nd6.googlevideo.com.": {},
- "rr1---sn-q4fl6nd6.gvt1.com.": {},
- "rr1---sn-q4fl6nd7.googlevideo.com.": {},
- "rr1---sn-q4fl6nde.googlevideo.com.": {},
- "rr1---sn-q4fl6ndl.googlevideo.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-q4fl6nlz.gvt1.com.": {},
- "rr1---sn-q4fl6ns6.googlevideo.com.": {},
- "rr1---sn-q4fl6ns7.googlevideo.com.": {},
- "rr1---sn-q4fl6nsd.googlevideo.com.": {},
- "rr1---sn-q4fl6nsk.googlevideo.com.": {},
- "rr1---sn-q4fl6nsk.gvt1.com.": {},
- "rr1---sn-q4fl6nsl.googlevideo.com.": {},
- "rr1---sn-q4fl6nsr.googlevideo.com.": {},
- "rr1---sn-q4fl6nsr.gvt1.com.": {},
- "rr1---sn-q4fl6nss.googlevideo.com.": {},
- "rr1---sn-q4fl6nsy.googlevideo.com.": {},
- "rr1---sn-q4fl6nsy.gvt1.com.": {},
- "rr1---sn-q4fl6nz6.googlevideo.com.": {},
- "rr1---sn-q4fl6nz7.googlevideo.com.": {},
- "rr1---sn-q4fl6nzy.googlevideo.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-q4flrnek.gvt1.com.": {},
- "rr1---sn-q4flrnel.googlevideo.com.": {},
- "rr1---sn-q4flrnel.gvt1.com.": {},
- "rr1---sn-q4flrner.googlevideo.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-q4flrnl7.gvt1.com.": {},
- "rr1---sn-q4flrnld.googlevideo.com.": {},
- "rr1---sn-q4flrnld.gvt1.com.": {},
- "rr1---sn-q4flrnle.googlevideo.com.": {},
- "rr1---sn-q4flrnlz.googlevideo.com.": {},
- "rr1---sn-q4flrnlz.gvt1.com.": {},
- "rr1---sn-q4flrnsd.googlevideo.com.": {},
- "rr1---sn-q4flrnsd.gvt1.com.": {},
- "rr1---sn-q4flrnsk.googlevideo.com.": {},
- "rr1---sn-q4flrnsl.googlevideo.com.": {},
- "rr1---sn-q4flrnsl.gvt1.com.": {},
- "rr1---sn-q4flrnss.googlevideo.com.": {},
- "rr1---sn-q4fzen7e.googlevideo.com.": {},
- "rr1---sn-q4fzen7e.gvt1.com.": {},
- "rr1---sn-q4fzen7l.googlevideo.com.": {},
- "rr1---sn-q4fzen7r.googlevideo.com.": {},
- "rr1---sn-q4fzen7r.gvt1.com.": {},
- "rr1---sn-q4fzen7s.googlevideo.com.": {},
- "rr1---sn-q4fzen7y.googlevideo.com.": {},
- "rr1---sn-q4fzen7y.gvt1.com.": {},
- "rr1---sn-q4fzene7.googlevideo.com.": {},
- "rr1---sn-q4fzenee.googlevideo.com.": {},
- "rr1---sn-q4fzenee.gvt1.com.": {},
- "rr1---sn-qxo7rn7k.googlevideo.com.": {},
- "rr1---sn-qxo7rn7r.googlevideo.com.": {},
- "rr1---sn-qxoedn7k.googlevideo.com.": {},
- "rr1---sn-qxoedne7.googlevideo.com.": {},
- "rr1---sn-qxoednee.googlevideo.com.": {},
- "rr1---sn-u1hp55-5c.googlevideo.com.": {},
- "rr1---sn-uhvcpaxoa-5hne.googlevideo.com.": {},
- "rr1---sn-uhvcpaxoa-guhe.googlevideo.com.": {},
- "rr1---sn-v5goxu-jhi6.googlevideo.com.": {},
- "rr1---sn-v5goxu-jhi6.gvt1.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.": {},
- "rr1---sn-vgqskn6s.googlevideo.com.": {},
- "rr1---sn-vgqskn6z.googlevideo.com.": {},
- "rr1---sn-vgqskne6.googlevideo.com.": {},
- "rr1---sn-vgqskned.googlevideo.com.": {},
- "rr1---sn-vgqsknek.googlevideo.com.": {},
- "rr1---sn-vgqsknes.googlevideo.com.": {},
- "rr1---sn-vgqsknez.googlevideo.com.": {},
- "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-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-vgqsrn66.googlevideo.com.": {},
- "rr1---sn-vgqsrn67.googlevideo.com.": {},
- "rr1---sn-vgqsrn6e.googlevideo.com.": {},
- "rr1---sn-vgqsrn6l.googlevideo.com.": {},
- "rr1---sn-vgqsrn6z.googlevideo.com.": {},
- "rr1---sn-vgqsrne6.googlevideo.com.": {},
- "rr1---sn-vgqsrned.googlevideo.com.": {},
- "rr1---sn-vgqsrnek.googlevideo.com.": {},
- "rr1---sn-vgqsrnes.googlevideo.com.": {},
- "rr1---sn-vgqsrnez.googlevideo.com.": {},
- "rr1---sn-vgqsrnl6.googlevideo.com.": {},
- "rr1---sn-vgqsrnld.googlevideo.com.": {},
- "rr1---sn-vgqsrnlk.googlevideo.com.": {},
- "rr1---sn-vgqsrnll.googlevideo.com.": {},
- "rr1---sn-vgqsrnls.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.": {},
- "rr1---sn-vnix5o-28ql.googlevideo.com.": {},
- "rr1---sn-voxoxu-v3jl.googlevideo.com.": {},
- "rr1---sn-voxoxu-v3js.googlevideo.com.": {},
- "rr1---sn-xo5-co5l.googlevideo.com.": {},
- "rr1.sn-q4fl6n66.googlevideo.com.": {},
- "rr1.sn-q4fl6nds.googlevideo.com.": {},
- "rr1.sn-q4flrnsd.googlevideo.com.": {},
- "rr2---sn-02o-ao3e.googlevideo.com.": {},
- "rr2---sn-0nnpbo5a-bggl.googlevideo.com.": {},
- "rr2---sn-0op8v4h5pox-cbgl.googlevideo.com.": {},
- "rr2---sn-2imern76.googlevideo.com.": {},
- "rr2---sn-2imern7d.googlevideo.com.": {},
- "rr2---sn-2imeyn7k.googlevideo.com.": {},
- "rr2---sn-2napbiu-p5ie.googlevideo.com.": {},
- "rr2---sn-2napbiu-p5ie.gvt1.com.": {},
- "rr2---sn-2pmxapm0n-gpje.googlevideo.com.": {},
- "rr2---sn-2pmxapm0n-gpjl.googlevideo.com.": {},
- "rr2---sn-2puupm-2pue.googlevideo.com.": {},
- "rr2---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.": {},
- "rr2---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.": {},
- "rr2---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.": {},
- "rr2---sn-2vgu0b5auxaxjvh-v2vk.googlevideo.com.": {},
- "rr2---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.": {},
- "rr2---sn-2vgu0b5auxaxjvh-v2vz.googlevideo.com.": {},
- "rr2---sn-30a7rne6.googlevideo.com.": {},
- "rr2---sn-30a7rned.googlevideo.com.": {},
- "rr2---sn-30a7rnek.googlevideo.com.": {},
- "rr2---sn-30a7rner.googlevideo.com.": {},
- "rr2---sn-30a7yner.googlevideo.com.": {},
- "rr2---sn-30a7yney.googlevideo.com.": {},
- "rr2---sn-30a7ynl7.googlevideo.com.": {},
- "rr2---sn-3jpm-hjpe.googlevideo.com.": {},
- "rr2---sn-3jpm-hjpe.gvt1.com.": {},
- "rr2---sn-3n4pcxg-pjul.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.": {},
- "rr2---sn-4g5edn6y.googlevideo.com.": {},
- "rr2---sn-4g5ednd7.googlevideo.com.": {},
- "rr2---sn-4g5edndd.googlevideo.com.": {},
- "rr2---sn-4g5ednde.googlevideo.com.": {},
- "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.": {},
- "rr2---sn-4g5ednld.googlevideo.com.": {},
- "rr2---sn-4g5ednly.googlevideo.com.": {},
- "rr2---sn-4g5edns6.googlevideo.com.": {},
- "rr2---sn-4g5edns7.googlevideo.com.": {},
- "rr2---sn-4g5ednsd.googlevideo.com.": {},
- "rr2---sn-4g5ednse.googlevideo.com.": {},
- "rr2---sn-4g5ednsk.googlevideo.com.": {},
- "rr2---sn-4g5ednsl.googlevideo.com.": {},
- "rr2---sn-4g5ednsr.googlevideo.com.": {},
- "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.": {},
- "rr2---sn-4g5lzner.googlevideo.com.": {},
- "rr2---sn-4g5lznes.googlevideo.com.": {},
- "rr2---sn-4g5lznez.googlevideo.com.": {},
- "rr2---sn-4g5lznl6.googlevideo.com.": {},
- "rr2---sn-4g5lznl7.googlevideo.com.": {},
- "rr2---sn-4g5lznle.googlevideo.com.": {},
- "rr2---sn-4g5lznls.googlevideo.com.": {},
- "rr2---sn-4g5lznlz.googlevideo.com.": {},
- "rr2---sn-4jjo-apnl.googlevideo.com.": {},
- "rr2---sn-4pgnuapbiu-hiue.googlevideo.com.": {},
- "rr2---sn-4pgnuapbiu-hiul.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.": {},
- "rr2---sn-5hne6nsd.googlevideo.com.": {},
- "rr2---sn-5hne6nsk.googlevideo.com.": {},
- "rr2---sn-5hne6nsr.googlevideo.com.": {},
- "rr2---sn-5hne6nsy.googlevideo.com.": {},
- "rr2---sn-5hne6nsz.googlevideo.com.": {},
- "rr2---sn-5hne6nz6.googlevideo.com.": {},
- "rr2---sn-5hne6nzd.googlevideo.com.": {},
- "rr2---sn-5hne6nzk.googlevideo.com.": {},
- "rr2---sn-5hne6nzs.googlevideo.com.": {},
- "rr2---sn-5hne6nzy.googlevideo.com.": {},
- "rr2---sn-5hnednss.googlevideo.com.": {},
- "rr2---sn-5hnednsz.googlevideo.com.": {},
- "rr2---sn-5hnekn76.googlevideo.com.": {},
- "rr2---sn-5hnekn7d.googlevideo.com.": {},
- "rr2---sn-5hnekn7k.googlevideo.com.": {},
- "rr2---sn-5hnekn7l.googlevideo.com.": {},
- "rr2---sn-5hnekn7s.googlevideo.com.": {},
- "rr2---sn-5hnekn7z.googlevideo.com.": {},
- "rr2---sn-5hneknee.googlevideo.com.": {},
- "rr2---sn-5hneknek.googlevideo.com.": {},
- "rr2---sn-5hneknes.googlevideo.com.": {},
- "rr2---sn-5pgnugx5h-hn2s.googlevideo.com.": {},
- "rr2---sn-5pgnugx5h-hn2z.googlevideo.com.": {},
- "rr2---sn-5uaezndd.googlevideo.com.": {},
- "rr2---sn-5uaezne6.googlevideo.com.": {},
- "rr2---sn-5uaezned.googlevideo.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-5uaeznrz.googlevideo.com.": {},
- "rr2---sn-5uaezns7.googlevideo.com.": {},
- "rr2---sn-5uaeznse.googlevideo.com.": {},
- "rr2---sn-5uaeznsl.googlevideo.com.": {},
- "rr2---sn-5uaeznss.googlevideo.com.": {},
- "rr2---sn-5uaezny6.googlevideo.com.": {},
- "rr2---sn-5uaeznys.googlevideo.com.": {},
- "rr2---sn-5uaeznyz.googlevideo.com.": {},
- "rr2---sn-5uaeznze.googlevideo.com.": {},
- "rr2---sn-5ualdnle.googlevideo.com.": {},
- "rr2---sn-5ualdnll.googlevideo.com.": {},
- "rr2---sn-5ualdnlr.googlevideo.com.": {},
- "rr2---sn-5ualdnls.googlevideo.com.": {},
- "rr2---sn-5ualdns6.googlevideo.com.": {},
- "rr2---sn-5ualdns7.googlevideo.com.": {},
- "rr2---sn-5ualdnsd.googlevideo.com.": {},
- "rr2---sn-5ualdnse.googlevideo.com.": {},
- "rr2---sn-5ualdnsk.googlevideo.com.": {},
- "rr2---sn-5ualdnsl.googlevideo.com.": {},
- "rr2---sn-5ualdnsr.googlevideo.com.": {},
- "rr2---sn-5ualdnss.googlevideo.com.": {},
- "rr2---sn-5ualdnsy.googlevideo.com.": {},
- "rr2---sn-5ualdnsz.googlevideo.com.": {},
- "rr2---sn-5ualdnz7.googlevideo.com.": {},
- "rr2---sn-5ualdnze.googlevideo.com.": {},
- "rr2---sn-8qj-nbo66.googlevideo.com.": {},
- "rr2---sn-8qj-nbo6y.googlevideo.com.": {},
- "rr2---sn-8xgp1vo-2iae.googlevideo.com.": {},
- "rr2---sn-8xgp1vo-2iae7.googlevideo.com.": {},
- "rr2---sn-8xgp1vo-2ial.googlevideo.com.": {},
- "rr2---sn-8xgp1vo-2iay.googlevideo.com.": {},
- "rr2---sn-8xgp1vo-a5me.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-hjpl.googlevideo.com.": {},
- "rr2---sn-8xgp1vo-p5ie.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-9gv76n7z.googlevideo.com.": {},
- "rr2---sn-9gv7ene6.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-a5m7lnl6.gvt1.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-a5meknds.gvt1.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-a5mlrnll.gvt1.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-a5msenes.gvt1.com.": {},
- "rr2---sn-a5msenl7.googlevideo.com.": {},
- "rr2---sn-a5msenle.googlevideo.com.": {},
- "rr2---sn-a5msenle.gvt1.com.": {},
- "rr2---sn-a5msenll.googlevideo.com.": {},
- "rr2---sn-a5oj5nuxg-aone.googlevideo.com.": {},
- "rr2---sn-ab5l6ndr.googlevideo.com.": {},
- "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-ab5l6nrd.gvt1.com.": {},
- "rr2---sn-ab5l6nrk.googlevideo.com.": {},
- "rr2---sn-ab5l6nrl.googlevideo.com.": {},
- "rr2---sn-ab5l6nrr.googlevideo.com.": {},
- "rr2---sn-ab5l6nrs.googlevideo.com.": {},
- "rr2---sn-ab5l6nrz.googlevideo.com.": {},
- "rr2---sn-ab5sznld.googlevideo.com.": {},
- "rr2---sn-ab5sznlk.googlevideo.com.": {},
- "rr2---sn-ab5sznly.googlevideo.com.": {},
- "rr2---sn-ab5sznz6.googlevideo.com.": {},
- "rr2---sn-ab5sznzd.googlevideo.com.": {},
- "rr2---sn-ab5sznze.googlevideo.com.": {},
- "rr2---sn-ab5sznzk.googlevideo.com.": {},
- "rr2---sn-ab5sznzl.googlevideo.com.": {},
- "rr2---sn-ab5sznzr.googlevideo.com.": {},
- "rr2---sn-ab5sznzs.googlevideo.com.": {},
- "rr2---sn-ab5sznzy.googlevideo.com.": {},
- "rr2---sn-ab5sznzz.googlevideo.com.": {},
- "rr2---sn-aigl6n6s.googlevideo.com.": {},
- "rr2---sn-aigl6ned.googlevideo.com.": {},
- "rr2---sn-aigl6nek.googlevideo.com.": {},
- "rr2---sn-aigl6ner.googlevideo.com.": {},
- "rr2---sn-aigl6ney.googlevideo.com.": {},
- "rr2---sn-aigl6nl7.googlevideo.com.": {},
- "rr2---sn-aigl6ns6.googlevideo.com.": {},
- "rr2---sn-aigl6nsd.googlevideo.com.": {},
- "rr2---sn-aigl6nsk.googlevideo.com.": {},
- "rr2---sn-aigl6nsr.googlevideo.com.": {},
- "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.": {},
- "rr2---sn-aigzrn7d.googlevideo.com.": {},
- "rr2---sn-aigzrn7e.googlevideo.com.": {},
- "rr2---sn-aigzrn7k.googlevideo.com.": {},
- "rr2---sn-aigzrn7l.googlevideo.com.": {},
- "rr2---sn-aigzrn7s.googlevideo.com.": {},
- "rr2---sn-aigzrn7z.googlevideo.com.": {},
- "rr2---sn-aigzrne7.googlevideo.com.": {},
- "rr2---sn-aigzrnld.googlevideo.com.": {},
- "rr2---sn-aigzrnse.googlevideo.com.": {},
- "rr2---sn-aigzrnsl.googlevideo.com.": {},
- "rr2---sn-aigzrnsr.googlevideo.com.": {},
- "rr2---sn-aigzrnss.googlevideo.com.": {},
- "rr2---sn-aigzrnsz.googlevideo.com.": {},
- "rr2---sn-aigzrnz7.googlevideo.com.": {},
- "rr2---sn-aigzrnze.googlevideo.com.": {},
- "rr2---sn-aj5ua5-5c.googlevideo.com.": {},
- "rr2---sn-apn7en7e.googlevideo.com.": {},
- "rr2---sn-apn7en7l.googlevideo.com.": {},
- "rr2---sn-apn7en7s.googlevideo.com.": {},
- "rr2---sn-bg5oqxjvh-50nz.googlevideo.com.": {},
- "rr2---sn-bg5oqxjvh-jg2s.googlevideo.com.": {},
- "rr2---sn-bg5oqxjvh-xa2s.googlevideo.com.": {},
- "rr2---sn-bvvbax-2iae.googlevideo.com.": {},
- "rr2---sn-c0q7lnz7.googlevideo.com.": {},
- "rr2---sn-cvb7lne7.googlevideo.com.": {},
- "rr2---sn-cvb7lnee.googlevideo.com.": {},
- "rr2---sn-cvb7lnls.googlevideo.com.": {},
- "rr2---sn-cvb7lnlz.googlevideo.com.": {},
- "rr2---sn-cvb7sn7k.googlevideo.com.": {},
- "rr2---sn-cvb7sn7r.googlevideo.com.": {},
- "rr2---sn-fpnjoxu-h3xl.googlevideo.com.": {},
- "rr2---sn-fpnjoxu-hnol.googlevideo.com.": {},
- "rr2---sn-gpuuxg-hxhl.googlevideo.com.": {},
- "rr2---sn-gpuuxg-hxhl.gvt1.com.": {},
- "rr2---sn-gpuuxg-hxhs.googlevideo.com.": {},
- "rr2---sn-gpuuxg-hxhs.gvt1.com.": {},
- "rr2---sn-gvbxgn-tvf6.googlevideo.com.": {},
- "rr2---sn-gvbxgn-tvfz.googlevideo.com.": {},
- "rr2---sn-h0jeened.googlevideo.com.": {},
- "rr2---sn-h0jeenek.googlevideo.com.": {},
- "rr2---sn-h0jeener.googlevideo.com.": {},
- "rr2---sn-h0jeenld.googlevideo.com.": {},
- "rr2---sn-h0jeenle.googlevideo.com.": {},
- "rr2---sn-h0jeln7e.googlevideo.com.": {},
- "rr2---sn-h0jeln7l.googlevideo.com.": {},
- "rr2---sn-h0jelne6.googlevideo.com.": {},
- "rr2---sn-h0jelnes.googlevideo.com.": {},
- "rr2---sn-h0jelnez.googlevideo.com.": {},
- "rr2---sn-hjoj-gq0l.googlevideo.com.": {},
- "rr2---sn-hjoj-gq0l.gvt1.com.": {},
- "rr2---sn-hjoj-jaul.googlevideo.com.": {},
- "rr2---sn-hjoj-poul.googlevideo.com.": {},
- "rr2---sn-hoa7kn76.googlevideo.com.": {},
- "rr2---sn-hoa7kn7z.googlevideo.com.": {},
- "rr2---sn-hoa7rn76.googlevideo.com.": {},
- "rr2---sn-hoa7rn7z.googlevideo.com.": {},
- "rr2---sn-hp57kn6r.googlevideo.com.": {},
- "rr2---sn-hp57kn6r.gvt1.com.": {},
- "rr2---sn-hp57kn6y.googlevideo.com.": {},
- "rr2---sn-hp57knd6.googlevideo.com.": {},
- "rr2---sn-hp57kndd.googlevideo.com.": {},
- "rr2---sn-hp57kndk.googlevideo.com.": {},
- "rr2---sn-hp57kndr.googlevideo.com.": {},
- "rr2---sn-hp57knds.googlevideo.com.": {},
- "rr2---sn-hp57kndy.googlevideo.com.": {},
- "rr2---sn-hp57kndz.googlevideo.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-hp57ynl6.gvt1.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-hp57ynsl.gvt1.com.": {},
- "rr2---sn-hp57ynss.googlevideo.com.": {},
- "rr2---sn-hxgpu-qufs.googlevideo.com.": {},
- "rr2---sn-i3b7kn6s.googlevideo.com.": {},
- "rr2---sn-i3b7knld.googlevideo.com.": {},
- "rr2---sn-i3b7knlk.googlevideo.com.": {},
- "rr2---sn-i3b7kns6.googlevideo.com.": {},
- "rr2---sn-i3b7knsd.googlevideo.com.": {},
- "rr2---sn-i3b7knse.googlevideo.com.": {},
- "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-i3belnlz.googlevideo.com.": {},
- "rr2---sn-i3bssn7e.googlevideo.com.": {},
- "rr2---sn-i5f5ppuxa-ioal.googlevideo.com.": {},
- "rr2---sn-i5h7lner.googlevideo.com.": {},
- "rr2---sn-i5h7lnl6.googlevideo.com.": {},
- "rr2---sn-i5h7lnll.googlevideo.com.": {},
- "rr2---sn-i5h7lnls.googlevideo.com.": {},
- "rr2---sn-i5heen7d.googlevideo.com.": {},
- "rr2---sn-i5heen7r.googlevideo.com.": {},
- "rr2---sn-i5heen7s.googlevideo.com.": {},
- "rr2---sn-jn2pgx4pcxg-w5os.googlevideo.com.": {},
- "rr2---sn-jvhj5nu-2iae.googlevideo.com.": {},
- "rr2---sn-jvhj5nu-2ial.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-jvhj5nu-qufe.googlevideo.com.": {},
- "rr2---sn-jvhj5nu-qufl.googlevideo.com.": {},
- "rr2---sn-jvhj5nu-qufs.googlevideo.com.": {},
- "rr2---sn-jvhj5nu-qufz.googlevideo.com.": {},
- "rr2---sn-jxopj-n5oe.googlevideo.com.": {},
- "rr2---sn-jxopj-n5oe.gvt1.com.": {},
- "rr2---sn-jxopj-nh4e.googlevideo.com.": {},
- "rr2---sn-jxopj-nh4e.gvt1.com.": {},
- "rr2---sn-muxa-2iae.googlevideo.com.": {},
- "rr2---sn-n0g45pg-ncoe.googlevideo.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-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-npoe7ndl.googlevideo.com.": {},
- "rr2---sn-npoe7nds.googlevideo.com.": {},
- "rr2---sn-npoe7ne6.googlevideo.com.": {},
- "rr2---sn-npoe7ne7.googlevideo.com.": {},
- "rr2---sn-npoe7ned.googlevideo.com.": {},
- "rr2---sn-npoe7nek.googlevideo.com.": {},
- "rr2---sn-npoe7ner.googlevideo.com.": {},
- "rr2---sn-npoe7nes.googlevideo.com.": {},
- "rr2---sn-npoe7ney.googlevideo.com.": {},
- "rr2---sn-npoe7nez.googlevideo.com.": {},
- "rr2---sn-npoe7nl6.googlevideo.com.": {},
- "rr2---sn-npoe7nlz.googlevideo.com.": {},
- "rr2---sn-npoe7ns6.googlevideo.com.": {},
- "rr2---sn-npoe7ns7.googlevideo.com.": {},
- "rr2---sn-npoe7nsd.googlevideo.com.": {},
- "rr2---sn-npoe7nsk.googlevideo.com.": {},
- "rr2---sn-npoe7nsl.googlevideo.com.": {},
- "rr2---sn-npoe7nsr.googlevideo.com.": {},
- "rr2---sn-npoe7nss.googlevideo.com.": {},
- "rr2---sn-npoe7nsy.googlevideo.com.": {},
- "rr2---sn-npoe7nz7.googlevideo.com.": {},
- "rr2---sn-npoeene6.googlevideo.com.": {},
- "rr2---sn-npoeened.googlevideo.com.": {},
- "rr2---sn-npoeenee.googlevideo.com.": {},
- "rr2---sn-npoeenek.googlevideo.com.": {},
- "rr2---sn-npoeener.googlevideo.com.": {},
- "rr2---sn-npoeeney.googlevideo.com.": {},
- "rr2---sn-npoeenez.googlevideo.com.": {},
- "rr2---sn-npoeenl7.googlevideo.com.": {},
- "rr2---sn-npoeenle.googlevideo.com.": {},
- "rr2---sn-npoeenlk.googlevideo.com.": {},
- "rr2---sn-npoeenll.googlevideo.com.": {},
- "rr2---sn-npoeenly.googlevideo.com.": {},
- "rr2---sn-npoeens7.googlevideo.com.": {},
- "rr2---sn-npoldn76.googlevideo.com.": {},
- "rr2---sn-npoldn7d.googlevideo.com.": {},
- "rr2---sn-npoldn7e.googlevideo.com.": {},
- "rr2---sn-npoldn7l.googlevideo.com.": {},
- "rr2---sn-npoldn7s.googlevideo.com.": {},
- "rr2---sn-npoldn7y.googlevideo.com.": {},
- "rr2---sn-npoldn7z.googlevideo.com.": {},
- "rr2---sn-npoldne7.googlevideo.com.": {},
- "rr2---sn-nuagpm-nuae.googlevideo.com.": {},
- "rr2---sn-nv0uixgo-5ual.googlevideo.com.": {},
- "rr2---sn-nv47ln6e.googlevideo.com.": {},
- "rr2---sn-nv47zn7r.googlevideo.com.": {},
- "rr2---sn-nv47zn7y.googlevideo.com.": {},
- "rr2---sn-nv47zne7.googlevideo.com.": {},
- "rr2---sn-nv47znee.googlevideo.com.": {},
- "rr2---sn-nv47znel.googlevideo.com.": {},
- "rr2---sn-nx57ynlk.googlevideo.com.": {},
- "rr2---sn-nx57ynsd.googlevideo.com.": {},
- "rr2---sn-nx57ynsd.gvt1.com.": {},
- "rr2---sn-nx57ynsk.googlevideo.com.": {},
- "rr2---sn-nx57ynsl.googlevideo.com.": {},
- "rr2---sn-nx57ynss.googlevideo.com.": {},
- "rr2---sn-nx57ynss.gvt1.com.": {},
- "rr2---sn-nx57ynsz.googlevideo.com.": {},
- "rr2---sn-nx57ynsz.gvt1.com.": {},
- "rr2---sn-nx5s7n76.googlevideo.com.": {},
- "rr2---sn-nx5s7n7d.googlevideo.com.": {},
- "rr2---sn-nx5s7n7y.googlevideo.com.": {},
- "rr2---sn-nx5s7n7z.googlevideo.com.": {},
- "rr2---sn-nx5s7nee.googlevideo.com.": {},
- "rr2---sn-nx5s7nee.gvt1.com.": {},
- "rr2---sn-nx5s7nel.googlevideo.com.": {},
- "rr2---sn-nx5s7nel.gvt1.com.": {},
- "rr2---sn-o097znsd.googlevideo.com.": {},
- "rr2---sn-o097znse.googlevideo.com.": {},
- "rr2---sn-o097znsk.googlevideo.com.": {},
- "rr2---sn-o097znsl.googlevideo.com.": {},
- "rr2---sn-o097znsr.googlevideo.com.": {},
- "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-opnq-n5ue.googlevideo.com.": {},
- "rr2---sn-ounjvhh-acce.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-p5qlsn76.googlevideo.com.": {},
- "rr2---sn-p5qlsn7d.googlevideo.com.": {},
- "rr2---sn-p5qlsn7l.googlevideo.com.": {},
- "rr2---sn-p5qlsn7s.googlevideo.com.": {},
- "rr2---sn-p5qlsnd6.googlevideo.com.": {},
- "rr2---sn-p5qlsndd.googlevideo.com.": {},
- "rr2---sn-p5qlsndz.googlevideo.com.": {},
- "rr2---sn-p5qlsnrl.googlevideo.com.": {},
- "rr2---sn-p5qlsnrr.googlevideo.com.": {},
- "rr2---sn-p5qlsny6.googlevideo.com.": {},
- "rr2---sn-p5qs7n6d.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-pjnpu-5hfe.googlevideo.com.": {},
- "rr2---sn-pobpb-poql.googlevideo.com.": {},
- "rr2---sn-q4fl6n66.googlevideo.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-q4fl6n6z.googlevideo.com.": {},
- "rr2---sn-q4fl6nd6.googlevideo.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-q4fl6ns6.googlevideo.com.": {},
- "rr2---sn-q4fl6ns6.gvt1.com.": {},
- "rr2---sn-q4fl6ns7.googlevideo.com.": {},
- "rr2---sn-q4fl6ns7.gvt1.com.": {},
- "rr2---sn-q4fl6nsd.googlevideo.com.": {},
- "rr2---sn-q4fl6nsd.gvt1.com.": {},
- "rr2---sn-q4fl6nsk.googlevideo.com.": {},
- "rr2---sn-q4fl6nsk.gvt1.com.": {},
- "rr2---sn-q4fl6nsl.googlevideo.com.": {},
- "rr2---sn-q4fl6nsr.googlevideo.com.": {},
- "rr2---sn-q4fl6nss.googlevideo.com.": {},
- "rr2---sn-q4fl6nsy.googlevideo.com.": {},
- "rr2---sn-q4fl6nsy.gvt1.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-q4flrn7y.googlevideo.com.": {},
- "rr2---sn-q4flrn7y.gvt1.com.": {},
- "rr2---sn-q4flrne6.googlevideo.com.": {},
- "rr2---sn-q4flrne7.googlevideo.com.": {},
- "rr2---sn-q4flrnee.googlevideo.com.": {},
- "rr2---sn-q4flrnek.googlevideo.com.": {},
- "rr2---sn-q4flrnel.googlevideo.com.": {},
- "rr2---sn-q4flrner.googlevideo.com.": {},
- "rr2---sn-q4flrner.gvt1.com.": {},
- "rr2---sn-q4flrnes.googlevideo.com.": {},
- "rr2---sn-q4flrnes.gvt1.com.": {},
- "rr2---sn-q4flrney.googlevideo.com.": {},
- "rr2---sn-q4flrnez.googlevideo.com.": {},
- "rr2---sn-q4flrnl6.googlevideo.com.": {},
- "rr2---sn-q4flrnl7.googlevideo.com.": {},
- "rr2---sn-q4flrnld.googlevideo.com.": {},
- "rr2---sn-q4flrnld.gvt1.com.": {},
- "rr2---sn-q4flrnle.googlevideo.com.": {},
- "rr2---sn-q4flrnsd.googlevideo.com.": {},
- "rr2---sn-q4flrnsd.gvt1.com.": {},
- "rr2---sn-q4flrnsk.googlevideo.com.": {},
- "rr2---sn-q4flrnsl.googlevideo.com.": {},
- "rr2---sn-q4flrnsl.gvt1.com.": {},
- "rr2---sn-q4flrnss.googlevideo.com.": {},
- "rr2---sn-q4fzen7e.googlevideo.com.": {},
- "rr2---sn-q4fzen7l.googlevideo.com.": {},
- "rr2---sn-q4fzen7r.googlevideo.com.": {},
- "rr2---sn-q4fzen7s.googlevideo.com.": {},
- "rr2---sn-q4fzen7y.googlevideo.com.": {},
- "rr2---sn-q4fzene7.googlevideo.com.": {},
- "rr2---sn-q4fzene7.gvt1.com.": {},
- "rr2---sn-q4fzenee.googlevideo.com.": {},
- "rr2---sn-qxo7rn7k.googlevideo.com.": {},
- "rr2---sn-qxo7rn7r.googlevideo.com.": {},
- "rr2---sn-qxo7rn7y.googlevideo.com.": {},
- "rr2---sn-qxoedn7k.googlevideo.com.": {},
- "rr2---sn-qxoedne7.googlevideo.com.": {},
- "rr2---sn-qxoednee.googlevideo.com.": {},
- "rr2---sn-qxuxa-5xme.googlevideo.com.": {},
- "rr2---sn-u1hp55-5c.googlevideo.com.": {},
- "rr2---sn-uhvcpaxoa-5hne.googlevideo.com.": {},
- "rr2---sn-uhvcpaxoa-guhe.googlevideo.com.": {},
- "rr2---sn-v5goxu-jhi6.googlevideo.com.": {},
- "rr2---sn-v5goxu-jhi6.gvt1.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.": {},
- "rr2---sn-vgqskn6s.googlevideo.com.": {},
- "rr2---sn-vgqskn6z.googlevideo.com.": {},
- "rr2---sn-vgqskne6.googlevideo.com.": {},
- "rr2---sn-vgqskned.googlevideo.com.": {},
- "rr2---sn-vgqsknek.googlevideo.com.": {},
- "rr2---sn-vgqsknes.googlevideo.com.": {},
- "rr2---sn-vgqsknez.googlevideo.com.": {},
- "rr2---sn-vgqsknld.googlevideo.com.": {},
- "rr2---sn-vgqsknlk.googlevideo.com.": {},
- "rr2---sn-vgqsknll.googlevideo.com.": {},
- "rr2---sn-vgqsknlr.googlevideo.com.": {},
- "rr2---sn-vgqsknlr.gvt1.com.": {},
- "rr2---sn-vgqsknls.googlevideo.com.": {},
- "rr2---sn-vgqsknlz.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-vgqsknzd.gvt1.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-vgqsknzz.gvt1.com.": {},
- "rr2---sn-vgqsrn66.googlevideo.com.": {},
- "rr2---sn-vgqsrn67.googlevideo.com.": {},
- "rr2---sn-vgqsrn67.gvt1.com.": {},
- "rr2---sn-vgqsrn6e.googlevideo.com.": {},
- "rr2---sn-vgqsrn6l.googlevideo.com.": {},
- "rr2---sn-vgqsrn6l.gvt1.com.": {},
- "rr2---sn-vgqsrn6z.googlevideo.com.": {},
- "rr2---sn-vgqsrne6.googlevideo.com.": {},
- "rr2---sn-vgqsrned.googlevideo.com.": {},
- "rr2---sn-vgqsrnek.googlevideo.com.": {},
- "rr2---sn-vgqsrnes.googlevideo.com.": {},
- "rr2---sn-vgqsrnez.googlevideo.com.": {},
- "rr2---sn-vgqsrnl6.googlevideo.com.": {},
- "rr2---sn-vgqsrnld.googlevideo.com.": {},
- "rr2---sn-vgqsrnlk.googlevideo.com.": {},
- "rr2---sn-vgqsrnll.googlevideo.com.": {},
- "rr2---sn-vgqsrnls.googlevideo.com.": {},
- "rr2---sn-vgqsrnls.gvt1.com.": {},
- "rr2---sn-vgqsrnlz.googlevideo.com.": {},
- "rr2---sn-vgqsrns6.googlevideo.com.": {},
- "rr2---sn-vgqsrnsd.googlevideo.com.": {},
- "rr2---sn-vgqsrnsr.googlevideo.com.": {},
- "rr2---sn-vgqsrnsr.gvt1.com.": {},
- "rr2---sn-vgqsrnsy.googlevideo.com.": {},
- "rr2---sn-vgqsrnz6.googlevideo.com.": {},
- "rr2---sn-vgqsrnz7.googlevideo.com.": {},
- "rr2---sn-vgqsrnz7.gvt1.com.": {},
- "rr2---sn-vgqsrnzd.googlevideo.com.": {},
- "rr2---sn-vgqsrnzk.googlevideo.com.": {},
- "rr2---sn-vgqsrnzr.googlevideo.com.": {},
- "rr2---sn-vgqsrnzr.gvt1.com.": {},
- "rr2---sn-vgqsrnzs.googlevideo.com.": {},
- "rr2---sn-vgqsrnzy.googlevideo.com.": {},
- "rr2---sn-vgqsrnzz.googlevideo.com.": {},
- "rr2---sn-vnix5o-28ql.googlevideo.com.": {},
- "rr2---sn-voxoxu-v3jl.googlevideo.com.": {},
- "rr2---sn-voxoxu-v3js.googlevideo.com.": {},
- "rr2---sn-xo5-co5l.googlevideo.com.": {},
- "rr2.sn-5hnednsz.googlevideo.com.": {},
- "rr2.sn-q4fl6n6s.googlevideo.com.": {},
- "rr2.sn-q4fl6nd6.googlevideo.com.": {},
- "rr2.sn-q4fl6ndl.googlevideo.com.": {},
- "rr3---sn-0nnpbo5a-bggl.googlevideo.com.": {},
- "rr3---sn-2imern76.googlevideo.com.": {},
- "rr3---sn-2imeyn7k.googlevideo.com.": {},
- "rr3---sn-2napbiu-p5ie.googlevideo.com.": {},
- "rr3---sn-2napbiu-p5ie.gvt1.com.": {},
- "rr3---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.": {},
- "rr3---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.": {},
- "rr3---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.": {},
- "rr3---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.": {},
- "rr3---sn-2vgu0b5auxaxjvh-v2vz.googlevideo.com.": {},
- "rr3---sn-30a7rne6.googlevideo.com.": {},
- "rr3---sn-30a7rned.googlevideo.com.": {},
- "rr3---sn-30a7rnek.googlevideo.com.": {},
- "rr3---sn-30a7rner.googlevideo.com.": {},
- "rr3---sn-30a7ynek.googlevideo.com.": {},
- "rr3---sn-30a7yner.googlevideo.com.": {},
- "rr3---sn-30a7yney.googlevideo.com.": {},
- "rr3---sn-30a7ynl7.googlevideo.com.": {},
- "rr3---sn-3jpm-hjpe.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-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.": {},
- "rr3---sn-4g5edn6r.googlevideo.com.": {},
- "rr3---sn-4g5edn6y.googlevideo.com.": {},
- "rr3---sn-4g5ednd7.googlevideo.com.": {},
- "rr3---sn-4g5edndd.googlevideo.com.": {},
- "rr3---sn-4g5ednde.googlevideo.com.": {},
- "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.": {},
- "rr3---sn-4g5ednsk.googlevideo.com.": {},
- "rr3---sn-4g5ednsl.googlevideo.com.": {},
- "rr3---sn-4g5ednsr.googlevideo.com.": {},
- "rr3---sn-4g5ednss.googlevideo.com.": {},
- "rr3---sn-4g5ednsy.googlevideo.com.": {},
- "rr3---sn-4g5ednsz.googlevideo.com.": {},
- "rr3---sn-4g5ednz7.googlevideo.com.": {},
- "rr3---sn-4g5lzne6.googlevideo.com.": {},
- "rr3---sn-4g5lzned.googlevideo.com.": {},
- "rr3---sn-4g5lznek.googlevideo.com.": {},
- "rr3---sn-4g5lzner.googlevideo.com.": {},
- "rr3---sn-4g5lznes.googlevideo.com.": {},
- "rr3---sn-4g5lzney.googlevideo.com.": {},
- "rr3---sn-4g5lznez.googlevideo.com.": {},
- "rr3---sn-4g5lznl6.googlevideo.com.": {},
- "rr3---sn-4g5lznl7.googlevideo.com.": {},
- "rr3---sn-4g5lznle.googlevideo.com.": {},
- "rr3---sn-4g5lznls.googlevideo.com.": {},
- "rr3---sn-4g5lznlz.googlevideo.com.": {},
- "rr3---sn-5hne6n6e.googlevideo.com.": {},
- "rr3---sn-5hne6n6l.googlevideo.com.": {},
- "rr3---sn-5hne6ns6.googlevideo.com.": {},
- "rr3---sn-5hne6nsd.googlevideo.com.": {},
- "rr3---sn-5hne6nsk.googlevideo.com.": {},
- "rr3---sn-5hne6nsr.googlevideo.com.": {},
- "rr3---sn-5hne6nsy.googlevideo.com.": {},
- "rr3---sn-5hne6nsz.googlevideo.com.": {},
- "rr3---sn-5hne6nz6.googlevideo.com.": {},
- "rr3---sn-5hne6nzd.googlevideo.com.": {},
- "rr3---sn-5hne6nzk.googlevideo.com.": {},
- "rr3---sn-5hne6nzs.googlevideo.com.": {},
- "rr3---sn-5hne6nzy.googlevideo.com.": {},
- "rr3---sn-5hnednss.googlevideo.com.": {},
- "rr3---sn-5hnednsz.googlevideo.com.": {},
- "rr3---sn-5hnekn76.googlevideo.com.": {},
- "rr3---sn-5hnekn7d.googlevideo.com.": {},
- "rr3---sn-5hnekn7k.googlevideo.com.": {},
- "rr3---sn-5hnekn7l.googlevideo.com.": {},
- "rr3---sn-5hnekn7s.googlevideo.com.": {},
- "rr3---sn-5hnekn7z.googlevideo.com.": {},
- "rr3---sn-5hneknee.googlevideo.com.": {},
- "rr3---sn-5hneknek.googlevideo.com.": {},
- "rr3---sn-5hneknes.googlevideo.com.": {},
- "rr3---sn-5pgnugx5h-hn2z.googlevideo.com.": {},
- "rr3---sn-5uaezndd.googlevideo.com.": {},
- "rr3---sn-5uaezne6.googlevideo.com.": {},
- "rr3---sn-5uaezned.googlevideo.com.": {},
- "rr3---sn-5uaeznes.googlevideo.com.": {},
- "rr3---sn-5uaeznez.googlevideo.com.": {},
- "rr3---sn-5uaeznl6.googlevideo.com.": {},
- "rr3---sn-5uaeznld.googlevideo.com.": {},
- "rr3---sn-5uaeznls.googlevideo.com.": {},
- "rr3---sn-5uaeznly.googlevideo.com.": {},
- "rr3---sn-5uaeznlz.googlevideo.com.": {},
- "rr3---sn-5uaeznrz.googlevideo.com.": {},
- "rr3---sn-5uaezns7.googlevideo.com.": {},
- "rr3---sn-5uaeznse.googlevideo.com.": {},
- "rr3---sn-5uaeznsl.googlevideo.com.": {},
- "rr3---sn-5uaeznss.googlevideo.com.": {},
- "rr3---sn-5uaeznyz.googlevideo.com.": {},
- "rr3---sn-5uaeznze.googlevideo.com.": {},
- "rr3---sn-5ualdnle.googlevideo.com.": {},
- "rr3---sn-5ualdnll.googlevideo.com.": {},
- "rr3---sn-5ualdnlr.googlevideo.com.": {},
- "rr3---sn-5ualdnls.googlevideo.com.": {},
- "rr3---sn-5ualdns6.googlevideo.com.": {},
- "rr3---sn-5ualdns7.googlevideo.com.": {},
- "rr3---sn-5ualdnsd.googlevideo.com.": {},
- "rr3---sn-5ualdnse.googlevideo.com.": {},
- "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-5ualdnsz.googlevideo.com.": {},
- "rr3---sn-5ualdnz7.googlevideo.com.": {},
- "rr3---sn-5ualdnze.googlevideo.com.": {},
- "rr3---sn-8qj-nbo66.googlevideo.com.": {},
- "rr3---sn-8xgp1vo-2iae.googlevideo.com.": {},
- "rr3---sn-8xgp1vo-2iae7.googlevideo.com.": {},
- "rr3---sn-8xgp1vo-2ial.googlevideo.com.": {},
- "rr3---sn-8xgp1vo-2iay.googlevideo.com.": {},
- "rr3---sn-8xgp1vo-a5me.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-p5ie.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-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-a5m7lnld.googlevideo.com.": {},
- "rr3---sn-a5mekn6d.googlevideo.com.": {},
- "rr3---sn-a5mekn6d.gvt1.com.": {},
- "rr3---sn-a5mekn6k.googlevideo.com.": {},
- "rr3---sn-a5mekn6k.gvt1.com.": {},
- "rr3---sn-a5mekn6l.googlevideo.com.": {},
- "rr3---sn-a5mekn6l.gvt1.com.": {},
- "rr3---sn-a5mekn6r.googlevideo.com.": {},
- "rr3---sn-a5mekn6s.googlevideo.com.": {},
- "rr3---sn-a5meknd6.googlevideo.com.": {},
- "rr3---sn-a5meknde.googlevideo.com.": {},
- "rr3---sn-a5mekndl.googlevideo.com.": {},
- "rr3---sn-a5meknds.googlevideo.com.": {},
- "rr3---sn-a5meknds.gvt1.com.": {},
- "rr3---sn-a5mekndz.googlevideo.com.": {},
- "rr3---sn-a5meknsd.googlevideo.com.": {},
- "rr3---sn-a5meknsy.googlevideo.com.": {},
- "rr3---sn-a5meknzk.googlevideo.com.": {},
- "rr3---sn-a5meknzr.googlevideo.com.": {},
- "rr3---sn-a5meknzr.gvt1.com.": {},
- "rr3---sn-a5meknzs.googlevideo.com.": {},
- "rr3---sn-a5mlrnek.googlevideo.com.": {},
- "rr3---sn-a5mlrnl6.googlevideo.com.": {},
- "rr3---sn-a5mlrnll.googlevideo.com.": {},
- "rr3---sn-a5mlrnll.gvt1.com.": {},
- "rr3---sn-a5mlrnls.googlevideo.com.": {},
- "rr3---sn-a5mlrnlz.googlevideo.com.": {},
- "rr3---sn-a5mlrnlz.gvt1.com.": {},
- "rr3---sn-a5msen76.googlevideo.com.": {},
- "rr3---sn-a5msen7l.googlevideo.com.": {},
- "rr3---sn-a5msen7s.googlevideo.com.": {},
- "rr3---sn-a5msen7z.googlevideo.com.": {},
- "rr3---sn-a5msen7z.gvt1.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-a5msenll.googlevideo.com.": {},
- "rr3---sn-ab5l6ndr.googlevideo.com.": {},
- "rr3---sn-ab5l6ndy.googlevideo.com.": {},
- "rr3---sn-ab5l6nk6.googlevideo.com.": {},
- "rr3---sn-ab5l6nkd.googlevideo.com.": {},
- "rr3---sn-ab5l6nr6.googlevideo.com.": {},
- "rr3---sn-ab5l6nrd.googlevideo.com.": {},
- "rr3---sn-ab5l6nrk.googlevideo.com.": {},
- "rr3---sn-ab5l6nrl.googlevideo.com.": {},
- "rr3---sn-ab5l6nrr.googlevideo.com.": {},
- "rr3---sn-ab5l6nrs.googlevideo.com.": {},
- "rr3---sn-ab5l6nrz.googlevideo.com.": {},
- "rr3---sn-ab5l6nrz.gvt1.com.": {},
- "rr3---sn-ab5sznld.googlevideo.com.": {},
- "rr3---sn-ab5sznlk.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.": {},
- "rr3---sn-ab5sznzz.googlevideo.com.": {},
- "rr3---sn-aigl6n6s.googlevideo.com.": {},
- "rr3---sn-aigl6ned.googlevideo.com.": {},
- "rr3---sn-aigl6nek.googlevideo.com.": {},
- "rr3---sn-aigl6ner.googlevideo.com.": {},
- "rr3---sn-aigl6ney.googlevideo.com.": {},
- "rr3---sn-aigl6nl7.googlevideo.com.": {},
- "rr3---sn-aigl6ns6.googlevideo.com.": {},
- "rr3---sn-aigl6nsd.googlevideo.com.": {},
- "rr3---sn-aigl6nsk.googlevideo.com.": {},
- "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.": {},
- "rr3---sn-aigzrn76.googlevideo.com.": {},
- "rr3---sn-aigzrn7d.googlevideo.com.": {},
- "rr3---sn-aigzrn7e.googlevideo.com.": {},
- "rr3---sn-aigzrn7k.googlevideo.com.": {},
- "rr3---sn-aigzrn7l.googlevideo.com.": {},
- "rr3---sn-aigzrn7s.googlevideo.com.": {},
- "rr3---sn-aigzrn7z.googlevideo.com.": {},
- "rr3---sn-aigzrne7.googlevideo.com.": {},
- "rr3---sn-aigzrnld.googlevideo.com.": {},
- "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-aj5ua5-5c.googlevideo.com.": {},
- "rr3---sn-apn7en7e.googlevideo.com.": {},
- "rr3---sn-apn7en7l.googlevideo.com.": {},
- "rr3---sn-apn7en7s.googlevideo.com.": {},
- "rr3---sn-bg5oqxjvh-50nz.googlevideo.com.": {},
- "rr3---sn-c0q7lnz7.googlevideo.com.": {},
- "rr3---sn-cvb7lne7.googlevideo.com.": {},
- "rr3---sn-cvb7lnee.googlevideo.com.": {},
- "rr3---sn-cvb7lnl7.googlevideo.com.": {},
- "rr3---sn-cvb7lnls.googlevideo.com.": {},
- "rr3---sn-cvb7lnlz.googlevideo.com.": {},
- "rr3---sn-cvb7sn7k.googlevideo.com.": {},
- "rr3---sn-cvb7sn7r.googlevideo.com.": {},
- "rr3---sn-gpuuxg-hxhl.googlevideo.com.": {},
- "rr3---sn-gpuuxg-hxhl.gvt1.com.": {},
- "rr3---sn-gvbxgn-tvf6.googlevideo.com.": {},
- "rr3---sn-gvbxgn-tvfz.googlevideo.com.": {},
- "rr3---sn-h0jeened.googlevideo.com.": {},
- "rr3---sn-h0jeenek.googlevideo.com.": {},
- "rr3---sn-h0jeener.googlevideo.com.": {},
- "rr3---sn-h0jeenl6.googlevideo.com.": {},
- "rr3---sn-h0jeenld.googlevideo.com.": {},
- "rr3---sn-h0jeenle.googlevideo.com.": {},
- "rr3---sn-h0jeln7e.googlevideo.com.": {},
- "rr3---sn-h0jeln7l.googlevideo.com.": {},
- "rr3---sn-h0jelne6.googlevideo.com.": {},
- "rr3---sn-h0jelne7.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-jaul.googlevideo.com.": {},
- "rr3---sn-hjoj-poul.googlevideo.com.": {},
- "rr3---sn-hoa7kn76.googlevideo.com.": {},
- "rr3---sn-hoa7kn7z.googlevideo.com.": {},
- "rr3---sn-hoa7rn76.googlevideo.com.": {},
- "rr3---sn-hoa7rn7z.googlevideo.com.": {},
- "rr3---sn-hp57kn6r.googlevideo.com.": {},
- "rr3---sn-hp57kn6y.googlevideo.com.": {},
- "rr3---sn-hp57kn6y.gvt1.com.": {},
- "rr3---sn-hp57knd6.googlevideo.com.": {},
- "rr3---sn-hp57kndd.googlevideo.com.": {},
- "rr3---sn-hp57kndk.googlevideo.com.": {},
- "rr3---sn-hp57kndk.gvt1.com.": {},
- "rr3---sn-hp57kndr.googlevideo.com.": {},
- "rr3---sn-hp57kndr.gvt1.com.": {},
- "rr3---sn-hp57knds.googlevideo.com.": {},
- "rr3---sn-hp57kndy.googlevideo.com.": {},
- "rr3---sn-hp57kndz.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-hp57ynly.googlevideo.com.": {},
- "rr3---sn-hp57ynly.gvt1.com.": {},
- "rr3---sn-hp57yns7.googlevideo.com.": {},
- "rr3---sn-hp57ynse.googlevideo.com.": {},
- "rr3---sn-hp57ynse.gvt1.com.": {},
- "rr3---sn-hp57ynsl.googlevideo.com.": {},
- "rr3---sn-hp57ynsl.gvt1.com.": {},
- "rr3---sn-hp57ynss.googlevideo.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.": {},
- "rr3---sn-i3b7knse.googlevideo.com.": {},
- "rr3---sn-i3b7knsl.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-i3belnlz.googlevideo.com.": {},
- "rr3---sn-i3bssn7e.googlevideo.com.": {},
- "rr3---sn-i5f5ppuxa-ioal.googlevideo.com.": {},
- "rr3---sn-i5h7lnl6.googlevideo.com.": {},
- "rr3---sn-i5h7lnll.googlevideo.com.": {},
- "rr3---sn-i5h7lnls.googlevideo.com.": {},
- "rr3---sn-i5heen7d.googlevideo.com.": {},
- "rr3---sn-i5heen7r.googlevideo.com.": {},
- "rr3---sn-i5heen7s.googlevideo.com.": {},
- "rr3---sn-jn2pgx4pcxg-w5os.googlevideo.com.": {},
- "rr3---sn-jvhj5nu-2iae.googlevideo.com.": {},
- "rr3---sn-jvhj5nu-2ial.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-jvhj5nu-qufe.googlevideo.com.": {},
- "rr3---sn-jvhj5nu-qufl.googlevideo.com.": {},
- "rr3---sn-jvhj5nu-qufz.googlevideo.com.": {},
- "rr3---sn-jxopj-n5oe.googlevideo.com.": {},
- "rr3---sn-jxopj-n5oe.gvt1.com.": {},
- "rr3---sn-jxopj-nh4e.googlevideo.com.": {},
- "rr3---sn-jxopj-nh4e.gvt1.com.": {},
- "rr3---sn-muxa-2iae.googlevideo.com.": {},
- "rr3---sn-n4v7snee.googlevideo.com.": {},
- "rr3---sn-n4v7sney.googlevideo.com.": {},
- "rr3---sn-n4v7snl7.googlevideo.com.": {},
- "rr3---sn-n4v7snll.googlevideo.com.": {},
- "rr3---sn-n4v7snlr.googlevideo.com.": {},
- "rr3---sn-n4v7snls.googlevideo.com.": {},
- "rr3---sn-n4v7snly.googlevideo.com.": {},
- "rr3---sn-n4v7sns7.googlevideo.com.": {},
- "rr3---sn-n4v7snse.googlevideo.com.": {},
- "rr3---sn-npoe7ndl.googlevideo.com.": {},
- "rr3---sn-npoe7nds.googlevideo.com.": {},
- "rr3---sn-npoe7ne6.googlevideo.com.": {},
- "rr3---sn-npoe7ne7.googlevideo.com.": {},
- "rr3---sn-npoe7ned.googlevideo.com.": {},
- "rr3---sn-npoe7nek.googlevideo.com.": {},
- "rr3---sn-npoe7ner.googlevideo.com.": {},
- "rr3---sn-npoe7nes.googlevideo.com.": {},
- "rr3---sn-npoe7ney.googlevideo.com.": {},
- "rr3---sn-npoe7nez.googlevideo.com.": {},
- "rr3---sn-npoe7nl6.googlevideo.com.": {},
- "rr3---sn-npoe7nlz.googlevideo.com.": {},
- "rr3---sn-npoe7ns6.googlevideo.com.": {},
- "rr3---sn-npoe7ns7.googlevideo.com.": {},
- "rr3---sn-npoe7nsd.googlevideo.com.": {},
- "rr3---sn-npoe7nsk.googlevideo.com.": {},
- "rr3---sn-npoe7nsl.googlevideo.com.": {},
- "rr3---sn-npoe7nsr.googlevideo.com.": {},
- "rr3---sn-npoe7nss.googlevideo.com.": {},
- "rr3---sn-npoe7nsy.googlevideo.com.": {},
- "rr3---sn-npoe7nz7.googlevideo.com.": {},
- "rr3---sn-npoeene6.googlevideo.com.": {},
- "rr3---sn-npoeened.googlevideo.com.": {},
- "rr3---sn-npoeenee.googlevideo.com.": {},
- "rr3---sn-npoeenek.googlevideo.com.": {},
- "rr3---sn-npoeener.googlevideo.com.": {},
- "rr3---sn-npoeeney.googlevideo.com.": {},
- "rr3---sn-npoeenez.googlevideo.com.": {},
- "rr3---sn-npoeenl7.googlevideo.com.": {},
- "rr3---sn-npoeenle.googlevideo.com.": {},
- "rr3---sn-npoeenlk.googlevideo.com.": {},
- "rr3---sn-npoeenll.googlevideo.com.": {},
- "rr3---sn-npoeenly.googlevideo.com.": {},
- "rr3---sn-npoeens7.googlevideo.com.": {},
- "rr3---sn-npoldn76.googlevideo.com.": {},
- "rr3---sn-npoldn7d.googlevideo.com.": {},
- "rr3---sn-npoldn7e.googlevideo.com.": {},
- "rr3---sn-npoldn7l.googlevideo.com.": {},
- "rr3---sn-npoldn7s.googlevideo.com.": {},
- "rr3---sn-npoldn7y.googlevideo.com.": {},
- "rr3---sn-npoldn7z.googlevideo.com.": {},
- "rr3---sn-npoldne7.googlevideo.com.": {},
- "rr3---sn-nv47ln6e.googlevideo.com.": {},
- "rr3---sn-nv47lns6.googlevideo.com.": {},
- "rr3---sn-nv47zn7r.googlevideo.com.": {},
- "rr3---sn-nv47zn7y.googlevideo.com.": {},
- "rr3---sn-nv47zne7.googlevideo.com.": {},
- "rr3---sn-nv47znee.googlevideo.com.": {},
- "rr3---sn-nv47znel.googlevideo.com.": {},
- "rr3---sn-nx57ynlk.googlevideo.com.": {},
- "rr3---sn-nx57ynlk.gvt1.com.": {},
- "rr3---sn-nx57ynsd.googlevideo.com.": {},
- "rr3---sn-nx57ynse.googlevideo.com.": {},
- "rr3---sn-nx57ynsk.googlevideo.com.": {},
- "rr3---sn-nx57ynsk.gvt1.com.": {},
- "rr3---sn-nx57ynsl.googlevideo.com.": {},
- "rr3---sn-nx57ynss.googlevideo.com.": {},
- "rr3---sn-nx57ynsz.googlevideo.com.": {},
- "rr3---sn-nx5s7n76.googlevideo.com.": {},
- "rr3---sn-nx5s7n76.gvt1.com.": {},
- "rr3---sn-nx5s7n7d.googlevideo.com.": {},
- "rr3---sn-nx5s7n7d.gvt1.com.": {},
- "rr3---sn-nx5s7n7s.googlevideo.com.": {},
- "rr3---sn-nx5s7n7y.googlevideo.com.": {},
- "rr3---sn-nx5s7n7y.gvt1.com.": {},
- "rr3---sn-nx5s7n7z.googlevideo.com.": {},
- "rr3---sn-nx5s7nee.googlevideo.com.": {},
- "rr3---sn-nx5s7nel.googlevideo.com.": {},
- "rr3---sn-nx5s7nel.gvt1.com.": {},
- "rr3---sn-o097znsd.googlevideo.com.": {},
- "rr3---sn-o097znse.googlevideo.com.": {},
- "rr3---sn-o097znsk.googlevideo.com.": {},
- "rr3---sn-o097znsl.googlevideo.com.": {},
- "rr3---sn-o097znsr.googlevideo.com.": {},
- "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-ounjvhh-acce.googlevideo.com.": {},
- "rr3---sn-p5qddn76.googlevideo.com.": {},
- "rr3---sn-p5qddn7d.googlevideo.com.": {},
- "rr3---sn-p5qddn7k.googlevideo.com.": {},
- "rr3---sn-p5qddn7r.googlevideo.com.": {},
- "rr3---sn-p5qlsn6l.googlevideo.com.": {},
- "rr3---sn-p5qlsn76.googlevideo.com.": {},
- "rr3---sn-p5qlsn7d.googlevideo.com.": {},
- "rr3---sn-p5qlsn7l.googlevideo.com.": {},
- "rr3---sn-p5qlsn7s.googlevideo.com.": {},
- "rr3---sn-p5qlsnd6.googlevideo.com.": {},
- "rr3---sn-p5qlsndd.googlevideo.com.": {},
- "rr3---sn-p5qlsndk.googlevideo.com.": {},
- "rr3---sn-p5qlsndr.googlevideo.com.": {},
- "rr3---sn-p5qlsndz.googlevideo.com.": {},
- "rr3---sn-p5qlsnrl.googlevideo.com.": {},
- "rr3---sn-p5qlsny6.googlevideo.com.": {},
- "rr3---sn-p5qs7n6d.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-q4fl6n6d.gvt1.com.": {},
- "rr3---sn-q4fl6n6r.googlevideo.com.": {},
- "rr3---sn-q4fl6n6s.googlevideo.com.": {},
- "rr3---sn-q4fl6n6s.gvt1.com.": {},
- "rr3---sn-q4fl6n6y.googlevideo.com.": {},
- "rr3---sn-q4fl6n6z.googlevideo.com.": {},
- "rr3---sn-q4fl6n6z.gvt1.com.": {},
- "rr3---sn-q4fl6nd6.googlevideo.com.": {},
- "rr3---sn-q4fl6nd7.googlevideo.com.": {},
- "rr3---sn-q4fl6nde.googlevideo.com.": {},
- "rr3---sn-q4fl6nde.gvt1.com.": {},
- "rr3---sn-q4fl6ndl.googlevideo.com.": {},
- "rr3---sn-q4fl6ndl.gvt1.com.": {},
- "rr3---sn-q4fl6nds.googlevideo.com.": {},
- "rr3---sn-q4fl6ndz.googlevideo.com.": {},
- "rr3---sn-q4fl6nlz.googlevideo.com.": {},
- "rr3---sn-q4fl6ns6.googlevideo.com.": {},
- "rr3---sn-q4fl6ns6.gvt1.com.": {},
- "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-q4fl6nzy.gvt1.com.": {},
- "rr3---sn-q4flrn7k.googlevideo.com.": {},
- "rr3---sn-q4flrn7r.googlevideo.com.": {},
- "rr3---sn-q4flrn7r.gvt1.com.": {},
- "rr3---sn-q4flrn7y.googlevideo.com.": {},
- "rr3---sn-q4flrne6.googlevideo.com.": {},
- "rr3---sn-q4flrne6.gvt1.com.": {},
- "rr3---sn-q4flrne7.googlevideo.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-q4flrney.gvt1.com.": {},
- "rr3---sn-q4flrnez.googlevideo.com.": {},
- "rr3---sn-q4flrnl6.googlevideo.com.": {},
- "rr3---sn-q4flrnl7.googlevideo.com.": {},
- "rr3---sn-q4flrnl7.gvt1.com.": {},
- "rr3---sn-q4flrnld.googlevideo.com.": {},
- "rr3---sn-q4flrnle.googlevideo.com.": {},
- "rr3---sn-q4flrnle.gvt1.com.": {},
- "rr3---sn-q4flrnlz.googlevideo.com.": {},
- "rr3---sn-q4flrnlz.gvt1.com.": {},
- "rr3---sn-q4flrnsd.googlevideo.com.": {},
- "rr3---sn-q4flrnsk.googlevideo.com.": {},
- "rr3---sn-q4flrnsk.gvt1.com.": {},
- "rr3---sn-q4flrnsl.googlevideo.com.": {},
- "rr3---sn-q4flrnss.googlevideo.com.": {},
- "rr3---sn-q4fzen7e.googlevideo.com.": {},
- "rr3---sn-q4fzen7l.googlevideo.com.": {},
- "rr3---sn-q4fzen7l.gvt1.com.": {},
- "rr3---sn-q4fzen7r.googlevideo.com.": {},
- "rr3---sn-q4fzen7r.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-qxo7rn7k.googlevideo.com.": {},
- "rr3---sn-qxo7rn7r.googlevideo.com.": {},
- "rr3---sn-qxo7rn7y.googlevideo.com.": {},
- "rr3---sn-qxoedn7k.googlevideo.com.": {},
- "rr3---sn-qxoednee.googlevideo.com.": {},
- "rr3---sn-u1hp55-5c.googlevideo.com.": {},
- "rr3---sn-uhvcpaxoa-5hne.googlevideo.com.": {},
- "rr3---sn-uhvcpaxoa-guhe.googlevideo.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-vgqskn6z.gvt1.com.": {},
- "rr3---sn-vgqskne6.googlevideo.com.": {},
- "rr3---sn-vgqskned.googlevideo.com.": {},
- "rr3---sn-vgqsknek.googlevideo.com.": {},
- "rr3---sn-vgqsknez.googlevideo.com.": {},
- "rr3---sn-vgqsknld.googlevideo.com.": {},
- "rr3---sn-vgqsknlk.googlevideo.com.": {},
- "rr3---sn-vgqsknll.googlevideo.com.": {},
- "rr3---sn-vgqsknls.googlevideo.com.": {},
- "rr3---sn-vgqsknly.googlevideo.com.": {},
- "rr3---sn-vgqsknlz.googlevideo.com.": {},
- "rr3---sn-vgqskns7.googlevideo.com.": {},
- "rr3---sn-vgqsknse.googlevideo.com.": {},
- "rr3---sn-vgqsknsk.googlevideo.com.": {},
- "rr3---sn-vgqsknsk.gvt1.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-vgqsknzy.gvt1.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-vgqsrne6.googlevideo.com.": {},
- "rr3---sn-vgqsrned.googlevideo.com.": {},
- "rr3---sn-vgqsrnek.googlevideo.com.": {},
- "rr3---sn-vgqsrnes.googlevideo.com.": {},
- "rr3---sn-vgqsrnez.googlevideo.com.": {},
- "rr3---sn-vgqsrnl6.googlevideo.com.": {},
- "rr3---sn-vgqsrnld.googlevideo.com.": {},
- "rr3---sn-vgqsrnlk.googlevideo.com.": {},
- "rr3---sn-vgqsrnll.googlevideo.com.": {},
- "rr3---sn-vgqsrnls.googlevideo.com.": {},
- "rr3---sn-vgqsrnls.gvt1.com.": {},
- "rr3---sn-vgqsrnlz.googlevideo.com.": {},
- "rr3---sn-vgqsrns6.googlevideo.com.": {},
- "rr3---sn-vgqsrnsd.googlevideo.com.": {},
- "rr3---sn-vgqsrnsd.gvt1.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-vgqsrnzs.gvt1.com.": {},
- "rr3---sn-vgqsrnzy.googlevideo.com.": {},
- "rr3---sn-vgqsrnzy.gvt1.com.": {},
- "rr3---sn-vgqsrnzz.googlevideo.com.": {},
- "rr3---sn-vgqsrnzz.gvt1.com.": {},
- "rr3.sn-5hne6n6e.googlevideo.com.": {},
- "rr3.sn-hgn7rnls.googlevideo.com.": {},
- "rr3.sn-q4fl6n6r.googlevideo.com.": {},
- "rr3.sn-q4fl6nd7.googlevideo.com.": {},
- "rr3.sn-q4fl6nde.googlevideo.com.": {},
- "rr3.sn-q4fl6ns6.googlevideo.com.": {},
- "rr3.sn-q4flrn7r.googlevideo.com.": {},
- "rr3.sn-q4flrne6.googlevideo.com.": {},
- "rr3.sn-q4flrnee.googlevideo.com.": {},
- "rr3.sn-q4flrnld.googlevideo.com.": {},
- "rr3.sn-q4flrnsd.googlevideo.com.": {},
- "rr3.sn-q4fzen7r.googlevideo.com.": {},
- "rr4---sn-0nnpbo5a-bggl.googlevideo.com.": {},
- "rr4---sn-2imern76.googlevideo.com.": {},
- "rr4---sn-2imern7d.googlevideo.com.": {},
- "rr4---sn-2imeyn7k.googlevideo.com.": {},
- "rr4---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.": {},
- "rr4---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.": {},
- "rr4---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.": {},
- "rr4---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.": {},
- "rr4---sn-2vgu0b5auxaxjvh-v2vz.googlevideo.com.": {},
- "rr4---sn-30a7rne6.googlevideo.com.": {},
- "rr4---sn-30a7rned.googlevideo.com.": {},
- "rr4---sn-30a7rnek.googlevideo.com.": {},
- "rr4---sn-30a7rner.googlevideo.com.": {},
- "rr4---sn-30a7ynek.googlevideo.com.": {},
- "rr4---sn-30a7yner.googlevideo.com.": {},
- "rr4---sn-30a7yney.googlevideo.com.": {},
- "rr4---sn-30a7ynl7.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-4g5e6nsz.googlevideo.com.": {},
- "rr4---sn-4g5e6nz7.googlevideo.com.": {},
- "rr4---sn-4g5e6nze.googlevideo.com.": {},
- "rr4---sn-4g5e6nzl.googlevideo.com.": {},
- "rr4---sn-4g5e6nzs.googlevideo.com.": {},
- "rr4---sn-4g5e6nzz.googlevideo.com.": {},
- "rr4---sn-4g5edn6k.googlevideo.com.": {},
- "rr4---sn-4g5edn6r.googlevideo.com.": {},
- "rr4---sn-4g5edn6y.googlevideo.com.": {},
- "rr4---sn-4g5ednd7.googlevideo.com.": {},
- "rr4---sn-4g5edndd.googlevideo.com.": {},
- "rr4---sn-4g5ednde.googlevideo.com.": {},
- "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.": {},
- "rr4---sn-4g5ednld.googlevideo.com.": {},
- "rr4---sn-4g5ednly.googlevideo.com.": {},
- "rr4---sn-4g5edns6.googlevideo.com.": {},
- "rr4---sn-4g5edns7.googlevideo.com.": {},
- "rr4---sn-4g5ednsd.googlevideo.com.": {},
- "rr4---sn-4g5ednse.googlevideo.com.": {},
- "rr4---sn-4g5ednsk.googlevideo.com.": {},
- "rr4---sn-4g5ednsl.googlevideo.com.": {},
- "rr4---sn-4g5ednsr.googlevideo.com.": {},
- "rr4---sn-4g5ednss.googlevideo.com.": {},
- "rr4---sn-4g5ednsy.googlevideo.com.": {},
- "rr4---sn-4g5ednsz.googlevideo.com.": {},
- "rr4---sn-4g5ednz7.googlevideo.com.": {},
- "rr4---sn-4g5lzne6.googlevideo.com.": {},
- "rr4---sn-4g5lzned.googlevideo.com.": {},
- "rr4---sn-4g5lzner.googlevideo.com.": {},
- "rr4---sn-4g5lznes.googlevideo.com.": {},
- "rr4---sn-4g5lzney.googlevideo.com.": {},
- "rr4---sn-4g5lznez.googlevideo.com.": {},
- "rr4---sn-4g5lznl6.googlevideo.com.": {},
- "rr4---sn-4g5lznl7.googlevideo.com.": {},
- "rr4---sn-4g5lznle.googlevideo.com.": {},
- "rr4---sn-4g5lznls.googlevideo.com.": {},
- "rr4---sn-4g5lznlz.googlevideo.com.": {},
- "rr4---sn-5hne6n6e.googlevideo.com.": {},
- "rr4---sn-5hne6n6l.googlevideo.com.": {},
- "rr4---sn-5hne6ns6.googlevideo.com.": {},
- "rr4---sn-5hne6nsd.googlevideo.com.": {},
- "rr4---sn-5hne6nsk.googlevideo.com.": {},
- "rr4---sn-5hne6nsr.googlevideo.com.": {},
- "rr4---sn-5hne6nsy.googlevideo.com.": {},
- "rr4---sn-5hne6nsz.googlevideo.com.": {},
- "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.": {},
- "rr4---sn-5hnekn76.googlevideo.com.": {},
- "rr4---sn-5hnekn7d.googlevideo.com.": {},
- "rr4---sn-5hnekn7k.googlevideo.com.": {},
- "rr4---sn-5hnekn7l.googlevideo.com.": {},
- "rr4---sn-5hnekn7s.googlevideo.com.": {},
- "rr4---sn-5hnekn7z.googlevideo.com.": {},
- "rr4---sn-5hneknek.googlevideo.com.": {},
- "rr4---sn-5hneknes.googlevideo.com.": {},
- "rr4---sn-5pgnugx5h-hn2z.googlevideo.com.": {},
- "rr4---sn-5uaezndd.googlevideo.com.": {},
- "rr4---sn-5uaezne6.googlevideo.com.": {},
- "rr4---sn-5uaezned.googlevideo.com.": {},
- "rr4---sn-5uaeznes.googlevideo.com.": {},
- "rr4---sn-5uaeznez.googlevideo.com.": {},
- "rr4---sn-5uaeznl6.googlevideo.com.": {},
- "rr4---sn-5uaeznld.googlevideo.com.": {},
- "rr4---sn-5uaeznls.googlevideo.com.": {},
- "rr4---sn-5uaeznly.googlevideo.com.": {},
- "rr4---sn-5uaeznlz.googlevideo.com.": {},
- "rr4---sn-5uaeznrz.googlevideo.com.": {},
- "rr4---sn-5uaezns7.googlevideo.com.": {},
- "rr4---sn-5uaeznse.googlevideo.com.": {},
- "rr4---sn-5uaeznsl.googlevideo.com.": {},
- "rr4---sn-5uaeznss.googlevideo.com.": {},
- "rr4---sn-5uaezny6.googlevideo.com.": {},
- "rr4---sn-5uaeznys.googlevideo.com.": {},
- "rr4---sn-5uaeznyz.googlevideo.com.": {},
- "rr4---sn-5uaeznze.googlevideo.com.": {},
- "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-5ualdnsy.googlevideo.com.": {},
- "rr4---sn-5ualdnsz.googlevideo.com.": {},
- "rr4---sn-5ualdnz7.googlevideo.com.": {},
- "rr4---sn-5ualdnze.googlevideo.com.": {},
- "rr4---sn-8qj-nbo66.googlevideo.com.": {},
- "rr4---sn-8xgp1vo-2iae.googlevideo.com.": {},
- "rr4---sn-8xgp1vo-2iae7.googlevideo.com.": {},
- "rr4---sn-8xgp1vo-2ial.googlevideo.com.": {},
- "rr4---sn-8xgp1vo-2iay.googlevideo.com.": {},
- "rr4---sn-8xgp1vo-a5me.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-p5ie.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-9gv76n7l.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.": {},
- "rr4---sn-a5mekn6k.googlevideo.com.": {},
- "rr4---sn-a5mekn6k.gvt1.com.": {},
- "rr4---sn-a5mekn6l.googlevideo.com.": {},
- "rr4---sn-a5mekn6r.googlevideo.com.": {},
- "rr4---sn-a5mekn6r.gvt1.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-a5mekndl.gvt1.com.": {},
- "rr4---sn-a5meknds.googlevideo.com.": {},
- "rr4---sn-a5mekndz.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-a5mlrnl6.googlevideo.com.": {},
- "rr4---sn-a5mlrnll.googlevideo.com.": {},
- "rr4---sn-a5mlrnls.googlevideo.com.": {},
- "rr4---sn-a5mlrnlz.googlevideo.com.": {},
- "rr4---sn-a5msen7l.googlevideo.com.": {},
- "rr4---sn-a5msen7s.googlevideo.com.": {},
- "rr4---sn-a5msen7z.googlevideo.com.": {},
- "rr4---sn-a5msenek.googlevideo.com.": {},
- "rr4---sn-a5msenek.gvt1.com.": {},
- "rr4---sn-a5msenes.googlevideo.com.": {},
- "rr4---sn-a5msenl7.googlevideo.com.": {},
- "rr4---sn-a5msenle.googlevideo.com.": {},
- "rr4---sn-a5msenll.googlevideo.com.": {},
- "rr4---sn-ab5l6ndr.googlevideo.com.": {},
- "rr4---sn-ab5l6ndy.googlevideo.com.": {},
- "rr4---sn-ab5l6nk6.googlevideo.com.": {},
- "rr4---sn-ab5l6nkd.googlevideo.com.": {},
- "rr4---sn-ab5l6nkd.gvt1.com.": {},
- "rr4---sn-ab5l6nr6.googlevideo.com.": {},
- "rr4---sn-ab5l6nrd.googlevideo.com.": {},
- "rr4---sn-ab5l6nrk.googlevideo.com.": {},
- "rr4---sn-ab5l6nrl.googlevideo.com.": {},
- "rr4---sn-ab5l6nrr.googlevideo.com.": {},
- "rr4---sn-ab5l6nrs.googlevideo.com.": {},
- "rr4---sn-ab5l6nrz.googlevideo.com.": {},
- "rr4---sn-ab5sznld.googlevideo.com.": {},
- "rr4---sn-ab5sznlk.googlevideo.com.": {},
- "rr4---sn-ab5sznly.googlevideo.com.": {},
- "rr4---sn-ab5sznz6.googlevideo.com.": {},
- "rr4---sn-ab5sznzd.googlevideo.com.": {},
- "rr4---sn-ab5sznze.googlevideo.com.": {},
- "rr4---sn-ab5sznzk.googlevideo.com.": {},
- "rr4---sn-ab5sznzl.googlevideo.com.": {},
- "rr4---sn-ab5sznzl.gvt1.com.": {},
- "rr4---sn-ab5sznzr.googlevideo.com.": {},
- "rr4---sn-ab5sznzs.googlevideo.com.": {},
- "rr4---sn-ab5sznzy.googlevideo.com.": {},
- "rr4---sn-ab5sznzz.googlevideo.com.": {},
- "rr4---sn-aigl6n6s.googlevideo.com.": {},
- "rr4---sn-aigl6ned.googlevideo.com.": {},
- "rr4---sn-aigl6ney.googlevideo.com.": {},
- "rr4---sn-aigl6nl7.googlevideo.com.": {},
- "rr4---sn-aigl6ns6.googlevideo.com.": {},
- "rr4---sn-aigl6nsd.googlevideo.com.": {},
- "rr4---sn-aigl6nsk.googlevideo.com.": {},
- "rr4---sn-aigl6nsr.googlevideo.com.": {},
- "rr4---sn-aigl6nz7.googlevideo.com.": {},
- "rr4---sn-aigl6nze.googlevideo.com.": {},
- "rr4---sn-aigl6nzk.googlevideo.com.": {},
- "rr4---sn-aigl6nzl.googlevideo.com.": {},
- "rr4---sn-aigl6nzr.googlevideo.com.": {},
- "rr4---sn-aigl6nzs.googlevideo.com.": {},
- "rr4---sn-aigzrn76.googlevideo.com.": {},
- "rr4---sn-aigzrn7d.googlevideo.com.": {},
- "rr4---sn-aigzrn7e.googlevideo.com.": {},
- "rr4---sn-aigzrn7k.googlevideo.com.": {},
- "rr4---sn-aigzrn7l.googlevideo.com.": {},
- "rr4---sn-aigzrn7s.googlevideo.com.": {},
- "rr4---sn-aigzrn7z.googlevideo.com.": {},
- "rr4---sn-aigzrne7.googlevideo.com.": {},
- "rr4---sn-aigzrnld.googlevideo.com.": {},
- "rr4---sn-aigzrnse.googlevideo.com.": {},
- "rr4---sn-aigzrnsl.googlevideo.com.": {},
- "rr4---sn-aigzrnsr.googlevideo.com.": {},
- "rr4---sn-aigzrnss.googlevideo.com.": {},
- "rr4---sn-aigzrnsz.googlevideo.com.": {},
- "rr4---sn-aigzrnz7.googlevideo.com.": {},
- "rr4---sn-aigzrnze.googlevideo.com.": {},
- "rr4---sn-aj5ua5-5c.googlevideo.com.": {},
- "rr4---sn-apn7en7e.googlevideo.com.": {},
- "rr4---sn-apn7en7l.googlevideo.com.": {},
- "rr4---sn-apn7en7s.googlevideo.com.": {},
- "rr4---sn-bg5oqxjvh-50nz.googlevideo.com.": {},
- "rr4---sn-c0q7lnz7.googlevideo.com.": {},
- "rr4---sn-cvb7lne7.googlevideo.com.": {},
- "rr4---sn-cvb7lnee.googlevideo.com.": {},
- "rr4---sn-cvb7lnl7.googlevideo.com.": {},
- "rr4---sn-cvb7lnls.googlevideo.com.": {},
- "rr4---sn-cvb7lnlz.googlevideo.com.": {},
- "rr4---sn-cvb7sn7k.googlevideo.com.": {},
- "rr4---sn-cvb7sn7r.googlevideo.com.": {},
- "rr4---sn-gvbxgn-tvf6.googlevideo.com.": {},
- "rr4---sn-gvbxgn-tvfz.googlevideo.com.": {},
- "rr4---sn-h0jeened.googlevideo.com.": {},
- "rr4---sn-h0jeenek.googlevideo.com.": {},
- "rr4---sn-h0jeener.googlevideo.com.": {},
- "rr4---sn-h0jeenl6.googlevideo.com.": {},
- "rr4---sn-h0jeenld.googlevideo.com.": {},
- "rr4---sn-h0jeenle.googlevideo.com.": {},
- "rr4---sn-h0jeln7e.googlevideo.com.": {},
- "rr4---sn-h0jeln7l.googlevideo.com.": {},
- "rr4---sn-h0jelne6.googlevideo.com.": {},
- "rr4---sn-h0jelne7.googlevideo.com.": {},
- "rr4---sn-h0jelnes.googlevideo.com.": {},
- "rr4---sn-h0jelnez.googlevideo.com.": {},
- "rr4---sn-hjoj-gq0l.googlevideo.com.": {},
- "rr4---sn-hjoj-gq0l.gvt1.com.": {},
- "rr4---sn-hoa7kn76.googlevideo.com.": {},
- "rr4---sn-hoa7kn7z.googlevideo.com.": {},
- "rr4---sn-hoa7rn76.googlevideo.com.": {},
- "rr4---sn-hoa7rn7z.googlevideo.com.": {},
- "rr4---sn-hp57kn6r.googlevideo.com.": {},
- "rr4---sn-hp57kn6y.googlevideo.com.": {},
- "rr4---sn-hp57kndd.googlevideo.com.": {},
- "rr4---sn-hp57kndd.gvt1.com.": {},
- "rr4---sn-hp57kndk.googlevideo.com.": {},
- "rr4---sn-hp57kndr.googlevideo.com.": {},
- "rr4---sn-hp57knds.googlevideo.com.": {},
- "rr4---sn-hp57kndy.googlevideo.com.": {},
- "rr4---sn-hp57kndy.gvt1.com.": {},
- "rr4---sn-hp57yn7r.googlevideo.com.": {},
- "rr4---sn-hp57yn7y.googlevideo.com.": {},
- "rr4---sn-hp57yne7.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-hp57ynse.googlevideo.com.": {},
- "rr4---sn-hp57ynsl.googlevideo.com.": {},
- "rr4---sn-hp57ynss.googlevideo.com.": {},
- "rr4---sn-hp57ynss.gvt1.com.": {},
- "rr4---sn-i3b7kn6s.googlevideo.com.": {},
- "rr4---sn-i3b7knld.googlevideo.com.": {},
- "rr4---sn-i3b7knlk.googlevideo.com.": {},
- "rr4---sn-i3b7kns6.googlevideo.com.": {},
- "rr4---sn-i3b7knsd.googlevideo.com.": {},
- "rr4---sn-i3b7knse.googlevideo.com.": {},
- "rr4---sn-i3b7knsl.googlevideo.com.": {},
- "rr4---sn-i3b7knzs.googlevideo.com.": {},
- "rr4---sn-i3belne6.googlevideo.com.": {},
- "rr4---sn-i3belney.googlevideo.com.": {},
- "rr4---sn-i3belnl6.googlevideo.com.": {},
- "rr4---sn-i3belnl7.googlevideo.com.": {},
- "rr4---sn-i3belnll.googlevideo.com.": {},
- "rr4---sn-i3belnls.googlevideo.com.": {},
- "rr4---sn-i3belnlz.googlevideo.com.": {},
- "rr4---sn-i3bssn7e.googlevideo.com.": {},
- "rr4---sn-i5f5ppuxa-ioal.googlevideo.com.": {},
- "rr4---sn-i5h7lnl6.googlevideo.com.": {},
- "rr4---sn-i5h7lnll.googlevideo.com.": {},
- "rr4---sn-i5h7lnls.googlevideo.com.": {},
- "rr4---sn-i5heen7d.googlevideo.com.": {},
- "rr4---sn-i5heen7r.googlevideo.com.": {},
- "rr4---sn-i5heen7s.googlevideo.com.": {},
- "rr4---sn-jn2pgx4pcxg-w5os.googlevideo.com.": {},
- "rr4---sn-jvhj5nu-2iae.googlevideo.com.": {},
- "rr4---sn-jvhj5nu-2ial.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-jvhj5nu-qufe.googlevideo.com.": {},
- "rr4---sn-jvhj5nu-qufl.googlevideo.com.": {},
- "rr4---sn-jvhj5nu-qufs.googlevideo.com.": {},
- "rr4---sn-jvhj5nu-qufz.googlevideo.com.": {},
- "rr4---sn-jxopj-n5oe.googlevideo.com.": {},
- "rr4---sn-jxopj-nh4e.googlevideo.com.": {},
- "rr4---sn-jxopj-nh4e.gvt1.com.": {},
- "rr4---sn-muxa-2iae.googlevideo.com.": {},
- "rr4---sn-n4v7snee.googlevideo.com.": {},
- "rr4---sn-n4v7sney.googlevideo.com.": {},
- "rr4---sn-n4v7snl7.googlevideo.com.": {},
- "rr4---sn-n4v7snll.googlevideo.com.": {},
- "rr4---sn-n4v7snlr.googlevideo.com.": {},
- "rr4---sn-n4v7snls.googlevideo.com.": {},
- "rr4---sn-n4v7snly.googlevideo.com.": {},
- "rr4---sn-n4v7sns7.googlevideo.com.": {},
- "rr4---sn-n4v7snse.googlevideo.com.": {},
- "rr4---sn-npoe7ndl.googlevideo.com.": {},
- "rr4---sn-npoe7nds.googlevideo.com.": {},
- "rr4---sn-npoe7ne6.googlevideo.com.": {},
- "rr4---sn-npoe7ne7.googlevideo.com.": {},
- "rr4---sn-npoe7ned.googlevideo.com.": {},
- "rr4---sn-npoe7nek.googlevideo.com.": {},
- "rr4---sn-npoe7ner.googlevideo.com.": {},
- "rr4---sn-npoe7ney.googlevideo.com.": {},
- "rr4---sn-npoe7nez.googlevideo.com.": {},
- "rr4---sn-npoe7nl6.googlevideo.com.": {},
- "rr4---sn-npoe7nlz.googlevideo.com.": {},
- "rr4---sn-npoe7ns6.googlevideo.com.": {},
- "rr4---sn-npoe7ns7.googlevideo.com.": {},
- "rr4---sn-npoe7nsd.googlevideo.com.": {},
- "rr4---sn-npoe7nsk.googlevideo.com.": {},
- "rr4---sn-npoe7nsl.googlevideo.com.": {},
- "rr4---sn-npoe7nsr.googlevideo.com.": {},
- "rr4---sn-npoe7nss.googlevideo.com.": {},
- "rr4---sn-npoe7nsy.googlevideo.com.": {},
- "rr4---sn-npoe7nz7.googlevideo.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-npoeeney.googlevideo.com.": {},
- "rr4---sn-npoeenez.googlevideo.com.": {},
- "rr4---sn-npoeenl7.googlevideo.com.": {},
- "rr4---sn-npoeenle.googlevideo.com.": {},
- "rr4---sn-npoeenlk.googlevideo.com.": {},
- "rr4---sn-npoeenll.googlevideo.com.": {},
- "rr4---sn-npoeens7.googlevideo.com.": {},
- "rr4---sn-npoldn76.googlevideo.com.": {},
- "rr4---sn-npoldn7d.googlevideo.com.": {},
- "rr4---sn-npoldn7e.googlevideo.com.": {},
- "rr4---sn-npoldn7l.googlevideo.com.": {},
- "rr4---sn-npoldn7s.googlevideo.com.": {},
- "rr4---sn-npoldn7y.googlevideo.com.": {},
- "rr4---sn-npoldn7z.googlevideo.com.": {},
- "rr4---sn-npoldne7.googlevideo.com.": {},
- "rr4---sn-ntqe6n7r.googlevideo.com.": {},
- "rr4---sn-nv47ln6e.googlevideo.com.": {},
- "rr4---sn-nv47lns6.googlevideo.com.": {},
- "rr4---sn-nv47zn7r.googlevideo.com.": {},
- "rr4---sn-nv47znee.googlevideo.com.": {},
- "rr4---sn-nv47znel.googlevideo.com.": {},
- "rr4---sn-nx57ynlk.googlevideo.com.": {},
- "rr4---sn-nx57ynsd.googlevideo.com.": {},
- "rr4---sn-nx57ynse.googlevideo.com.": {},
- "rr4---sn-nx57ynse.gvt1.com.": {},
- "rr4---sn-nx57ynsk.googlevideo.com.": {},
- "rr4---sn-nx57ynsk.gvt1.com.": {},
- "rr4---sn-nx57ynsl.googlevideo.com.": {},
- "rr4---sn-nx57ynsl.gvt1.com.": {},
- "rr4---sn-nx57ynss.googlevideo.com.": {},
- "rr4---sn-nx57ynss.gvt1.com.": {},
- "rr4---sn-nx57ynsz.googlevideo.com.": {},
- "rr4---sn-nx5s7n76.googlevideo.com.": {},
- "rr4---sn-nx5s7n7d.googlevideo.com.": {},
- "rr4---sn-nx5s7n7d.gvt1.com.": {},
- "rr4---sn-nx5s7n7s.googlevideo.com.": {},
- "rr4---sn-nx5s7n7y.googlevideo.com.": {},
- "rr4---sn-nx5s7n7y.gvt1.com.": {},
- "rr4---sn-nx5s7n7z.googlevideo.com.": {},
- "rr4---sn-nx5s7nee.googlevideo.com.": {},
- "rr4---sn-nx5s7nee.gvt1.com.": {},
- "rr4---sn-nx5s7nel.googlevideo.com.": {},
- "rr4---sn-o097znsd.googlevideo.com.": {},
- "rr4---sn-o097znse.googlevideo.com.": {},
- "rr4---sn-o097znsk.googlevideo.com.": {},
- "rr4---sn-o097znsl.googlevideo.com.": {},
- "rr4---sn-o097znsr.googlevideo.com.": {},
- "rr4---sn-o097znss.googlevideo.com.": {},
- "rr4---sn-o097znsz.googlevideo.com.": {},
- "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-p5qddn76.googlevideo.com.": {},
- "rr4---sn-p5qddn7d.googlevideo.com.": {},
- "rr4---sn-p5qddn7k.googlevideo.com.": {},
- "rr4---sn-p5qddn7r.googlevideo.com.": {},
- "rr4---sn-p5qddn7z.googlevideo.com.": {},
- "rr4---sn-p5qlsn6l.googlevideo.com.": {},
- "rr4---sn-p5qlsn76.googlevideo.com.": {},
- "rr4---sn-p5qlsn7d.googlevideo.com.": {},
- "rr4---sn-p5qlsn7l.googlevideo.com.": {},
- "rr4---sn-p5qlsn7s.googlevideo.com.": {},
- "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-p5qs7nsk.googlevideo.com.": {},
- "rr4---sn-p5qs7nsr.googlevideo.com.": {},
- "rr4---sn-p5qs7nzk.googlevideo.com.": {},
- "rr4---sn-p5qs7nzr.googlevideo.com.": {},
- "rr4---sn-p5qs7nzy.googlevideo.com.": {},
- "rr4---sn-q4fl6n66.googlevideo.com.": {},
- "rr4---sn-q4fl6n66.gvt1.com.": {},
- "rr4---sn-q4fl6n6d.googlevideo.com.": {},
- "rr4---sn-q4fl6n6r.googlevideo.com.": {},
- "rr4---sn-q4fl6n6r.gvt1.com.": {},
- "rr4---sn-q4fl6n6s.googlevideo.com.": {},
- "rr4---sn-q4fl6n6s.gvt1.com.": {},
- "rr4---sn-q4fl6n6y.googlevideo.com.": {},
- "rr4---sn-q4fl6n6z.googlevideo.com.": {},
- "rr4---sn-q4fl6nd6.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-q4fl6nds.gvt1.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-q4fl6nss.gvt1.com.": {},
- "rr4---sn-q4fl6nsy.googlevideo.com.": {},
- "rr4---sn-q4fl6nsy.gvt1.com.": {},
- "rr4---sn-q4fl6nz6.googlevideo.com.": {},
- "rr4---sn-q4fl6nz7.googlevideo.com.": {},
- "rr4---sn-q4fl6nz7.gvt1.com.": {},
- "rr4---sn-q4fl6nzy.googlevideo.com.": {},
- "rr4---sn-q4flrn7k.googlevideo.com.": {},
- "rr4---sn-q4flrn7r.googlevideo.com.": {},
- "rr4---sn-q4flrn7y.googlevideo.com.": {},
- "rr4---sn-q4flrne6.googlevideo.com.": {},
- "rr4---sn-q4flrne7.googlevideo.com.": {},
- "rr4---sn-q4flrnee.googlevideo.com.": {},
- "rr4---sn-q4flrnek.googlevideo.com.": {},
- "rr4---sn-q4flrnek.gvt1.com.": {},
- "rr4---sn-q4flrnel.googlevideo.com.": {},
- "rr4---sn-q4flrnel.gvt1.com.": {},
- "rr4---sn-q4flrner.googlevideo.com.": {},
- "rr4---sn-q4flrner.gvt1.com.": {},
- "rr4---sn-q4flrnes.googlevideo.com.": {},
- "rr4---sn-q4flrney.googlevideo.com.": {},
- "rr4---sn-q4flrney.gvt1.com.": {},
- "rr4---sn-q4flrnez.googlevideo.com.": {},
- "rr4---sn-q4flrnl6.googlevideo.com.": {},
- "rr4---sn-q4flrnl6.gvt1.com.": {},
- "rr4---sn-q4flrnl7.googlevideo.com.": {},
- "rr4---sn-q4flrnld.googlevideo.com.": {},
- "rr4---sn-q4flrnld.gvt1.com.": {},
- "rr4---sn-q4flrnle.googlevideo.com.": {},
- "rr4---sn-q4flrnlz.googlevideo.com.": {},
- "rr4---sn-q4flrnlz.gvt1.com.": {},
- "rr4---sn-q4flrnsd.googlevideo.com.": {},
- "rr4---sn-q4flrnsk.googlevideo.com.": {},
- "rr4---sn-q4flrnsl.googlevideo.com.": {},
- "rr4---sn-q4flrnsl.gvt1.com.": {},
- "rr4---sn-q4flrnss.googlevideo.com.": {},
- "rr4---sn-q4fzen7e.googlevideo.com.": {},
- "rr4---sn-q4fzen7e.gvt1.com.": {},
- "rr4---sn-q4fzen7l.googlevideo.com.": {},
- "rr4---sn-q4fzen7r.googlevideo.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-qxo7rn7k.googlevideo.com.": {},
- "rr4---sn-qxo7rn7r.googlevideo.com.": {},
- "rr4---sn-qxo7rn7y.googlevideo.com.": {},
- "rr4---sn-qxoedn7k.googlevideo.com.": {},
- "rr4---sn-qxoedne7.googlevideo.com.": {},
- "rr4---sn-t0a7ln7d.googlevideo.com.": {},
- "rr4---sn-u1hp55-5c.googlevideo.com.": {},
- "rr4---sn-uhvcpaxoa-5hne.googlevideo.com.": {},
- "rr4---sn-uhvcpaxoa-guhe.googlevideo.com.": {},
- "rr4---sn-v5goxu-jhil.googlevideo.com.": {},
- "rr4---sn-v5goxu-jhil.gvt1.com.": {},
- "rr4---sn-vgqskn66.googlevideo.com.": {},
- "rr4---sn-vgqskn67.googlevideo.com.": {},
- "rr4---sn-vgqskn67.gvt1.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.": {},
- "rr4---sn-vgqsknez.googlevideo.com.": {},
- "rr4---sn-vgqsknez.gvt1.com.": {},
- "rr4---sn-vgqsknld.googlevideo.com.": {},
- "rr4---sn-vgqsknll.googlevideo.com.": {},
- "rr4---sn-vgqsknll.gvt1.com.": {},
- "rr4---sn-vgqsknlr.googlevideo.com.": {},
- "rr4---sn-vgqsknls.googlevideo.com.": {},
- "rr4---sn-vgqsknly.googlevideo.com.": {},
- "rr4---sn-vgqsknlz.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-vgqsknzs.gvt1.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-vgqsrne6.googlevideo.com.": {},
- "rr4---sn-vgqsrned.googlevideo.com.": {},
- "rr4---sn-vgqsrnek.googlevideo.com.": {},
- "rr4---sn-vgqsrnes.googlevideo.com.": {},
- "rr4---sn-vgqsrnez.googlevideo.com.": {},
- "rr4---sn-vgqsrnl6.googlevideo.com.": {},
- "rr4---sn-vgqsrnld.googlevideo.com.": {},
- "rr4---sn-vgqsrnlk.googlevideo.com.": {},
- "rr4---sn-vgqsrnll.googlevideo.com.": {},
- "rr4---sn-vgqsrnls.googlevideo.com.": {},
- "rr4---sn-vgqsrnlz.googlevideo.com.": {},
- "rr4---sn-vgqsrns6.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.": {},
- "rr4.sn-5hne6nzd.googlevideo.com.": {},
- "rr4.sn-q4fl6n6s.googlevideo.com.": {},
- "rr4.sn-q4fl6n6y.googlevideo.com.": {},
- "rr4.sn-q4flrner.googlevideo.com.": {},
- "rr5---sn-0nnpbo5a-bggl.googlevideo.com.": {},
- "rr5---sn-2imern76.googlevideo.com.": {},
- "rr5---sn-2imern7d.googlevideo.com.": {},
- "rr5---sn-2imeyn7k.googlevideo.com.": {},
- "rr5---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.": {},
- "rr5---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.": {},
- "rr5---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.": {},
- "rr5---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.": {},
- "rr5---sn-30a7rne6.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-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.": {},
- "rr5---sn-4g5e6nz7.googlevideo.com.": {},
- "rr5---sn-4g5e6nze.googlevideo.com.": {},
- "rr5---sn-4g5e6nzl.googlevideo.com.": {},
- "rr5---sn-4g5e6nzs.googlevideo.com.": {},
- "rr5---sn-4g5e6nzz.googlevideo.com.": {},
- "rr5---sn-4g5edn6k.googlevideo.com.": {},
- "rr5---sn-4g5edn6y.googlevideo.com.": {},
- "rr5---sn-4g5ednd7.googlevideo.com.": {},
- "rr5---sn-4g5edndd.googlevideo.com.": {},
- "rr5---sn-4g5ednde.googlevideo.com.": {},
- "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.": {},
- "rr5---sn-4g5ednld.googlevideo.com.": {},
- "rr5---sn-4g5ednly.googlevideo.com.": {},
- "rr5---sn-4g5edns6.googlevideo.com.": {},
- "rr5---sn-4g5edns7.googlevideo.com.": {},
- "rr5---sn-4g5ednsd.googlevideo.com.": {},
- "rr5---sn-4g5ednse.googlevideo.com.": {},
- "rr5---sn-4g5ednsk.googlevideo.com.": {},
- "rr5---sn-4g5ednsl.googlevideo.com.": {},
- "rr5---sn-4g5ednsr.googlevideo.com.": {},
- "rr5---sn-4g5ednss.googlevideo.com.": {},
- "rr5---sn-4g5ednsy.googlevideo.com.": {},
- "rr5---sn-4g5ednsz.googlevideo.com.": {},
- "rr5---sn-4g5ednz7.googlevideo.com.": {},
- "rr5---sn-4g5lzne6.googlevideo.com.": {},
- "rr5---sn-4g5lzned.googlevideo.com.": {},
- "rr5---sn-4g5lznek.googlevideo.com.": {},
- "rr5---sn-4g5lzner.googlevideo.com.": {},
- "rr5---sn-4g5lznes.googlevideo.com.": {},
- "rr5---sn-4g5lzney.googlevideo.com.": {},
- "rr5---sn-4g5lznez.googlevideo.com.": {},
- "rr5---sn-4g5lznl6.googlevideo.com.": {},
- "rr5---sn-4g5lznl7.googlevideo.com.": {},
- "rr5---sn-4g5lznle.googlevideo.com.": {},
- "rr5---sn-4g5lznls.googlevideo.com.": {},
- "rr5---sn-4g5lznlz.googlevideo.com.": {},
- "rr5---sn-5hne6n6e.googlevideo.com.": {},
- "rr5---sn-5hne6n6l.googlevideo.com.": {},
- "rr5---sn-5hne6ns6.googlevideo.com.": {},
- "rr5---sn-5hne6nsd.googlevideo.com.": {},
- "rr5---sn-5hne6nsk.googlevideo.com.": {},
- "rr5---sn-5hne6nsr.googlevideo.com.": {},
- "rr5---sn-5hne6nsy.googlevideo.com.": {},
- "rr5---sn-5hne6nsz.googlevideo.com.": {},
- "rr5---sn-5hne6nz6.googlevideo.com.": {},
- "rr5---sn-5hne6nzd.googlevideo.com.": {},
- "rr5---sn-5hne6nzk.googlevideo.com.": {},
- "rr5---sn-5hne6nzs.googlevideo.com.": {},
- "rr5---sn-5hne6nzy.googlevideo.com.": {},
- "rr5---sn-5hnednss.googlevideo.com.": {},
- "rr5---sn-5hnednsz.googlevideo.com.": {},
- "rr5---sn-5hnekn76.googlevideo.com.": {},
- "rr5---sn-5hnekn7d.googlevideo.com.": {},
- "rr5---sn-5hnekn7l.googlevideo.com.": {},
- "rr5---sn-5hnekn7s.googlevideo.com.": {},
- "rr5---sn-5hnekn7z.googlevideo.com.": {},
- "rr5---sn-5hneknee.googlevideo.com.": {},
- "rr5---sn-5hneknek.googlevideo.com.": {},
- "rr5---sn-5hneknes.googlevideo.com.": {},
- "rr5---sn-5pgnugx5h-hn2z.googlevideo.com.": {},
- "rr5---sn-5uaezndd.googlevideo.com.": {},
- "rr5---sn-5uaezne6.googlevideo.com.": {},
- "rr5---sn-5uaezned.googlevideo.com.": {},
- "rr5---sn-5uaeznes.googlevideo.com.": {},
- "rr5---sn-5uaeznez.googlevideo.com.": {},
- "rr5---sn-5uaeznl6.googlevideo.com.": {},
- "rr5---sn-5uaeznld.googlevideo.com.": {},
- "rr5---sn-5uaeznls.googlevideo.com.": {},
- "rr5---sn-5uaeznly.googlevideo.com.": {},
- "rr5---sn-5uaeznlz.googlevideo.com.": {},
- "rr5---sn-5uaeznrz.googlevideo.com.": {},
- "rr5---sn-5uaezns7.googlevideo.com.": {},
- "rr5---sn-5uaeznse.googlevideo.com.": {},
- "rr5---sn-5uaeznsl.googlevideo.com.": {},
- "rr5---sn-5uaeznss.googlevideo.com.": {},
- "rr5---sn-5uaezny6.googlevideo.com.": {},
- "rr5---sn-5uaeznys.googlevideo.com.": {},
- "rr5---sn-5uaeznze.googlevideo.com.": {},
- "rr5---sn-5ualdnll.googlevideo.com.": {},
- "rr5---sn-5ualdnlr.googlevideo.com.": {},
- "rr5---sn-5ualdnls.googlevideo.com.": {},
- "rr5---sn-5ualdns6.googlevideo.com.": {},
- "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.": {},
- "rr5---sn-5ualdnsy.googlevideo.com.": {},
- "rr5---sn-5ualdnsz.googlevideo.com.": {},
- "rr5---sn-5ualdnz7.googlevideo.com.": {},
- "rr5---sn-5ualdnze.googlevideo.com.": {},
- "rr5---sn-8qj-nbo66.googlevideo.com.": {},
- "rr5---sn-8xgp1vo-2iae.googlevideo.com.": {},
- "rr5---sn-8xgp1vo-2iae7.googlevideo.com.": {},
- "rr5---sn-8xgp1vo-2ial.googlevideo.com.": {},
- "rr5---sn-8xgp1vo-2iay.googlevideo.com.": {},
- "rr5---sn-8xgp1vo-a5me.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-p5ie.googlevideo.com.": {},
- "rr5---sn-8xgp1vo-vgqe.googlevideo.com.": {},
- "rr5---sn-8xgp1vo-xfge.googlevideo.com.": {},
- "rr5---sn-8xgp1vo-xfgl.googlevideo.com.": {},
- "rr5---sn-9gv76n7e.googlevideo.com.": {},
- "rr5---sn-9gv76n7l.googlevideo.com.": {},
- "rr5---sn-9gv76n7s.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.": {},
- "rr5---sn-a5mekn6d.googlevideo.com.": {},
- "rr5---sn-a5mekn6k.googlevideo.com.": {},
- "rr5---sn-a5mekn6r.googlevideo.com.": {},
- "rr5---sn-a5mekn6s.googlevideo.com.": {},
- "rr5---sn-a5mekn6z.googlevideo.com.": {},
- "rr5---sn-a5meknd6.googlevideo.com.": {},
- "rr5---sn-a5meknd6.gvt1.com.": {},
- "rr5---sn-a5meknde.googlevideo.com.": {},
- "rr5---sn-a5mekndl.googlevideo.com.": {},
- "rr5---sn-a5meknds.googlevideo.com.": {},
- "rr5---sn-a5meknds.gvt1.com.": {},
- "rr5---sn-a5mekndz.googlevideo.com.": {},
- "rr5---sn-a5mekndz.gvt1.com.": {},
- "rr5---sn-a5meknsd.googlevideo.com.": {},
- "rr5---sn-a5meknsy.googlevideo.com.": {},
- "rr5---sn-a5meknzk.googlevideo.com.": {},
- "rr5---sn-a5meknzr.googlevideo.com.": {},
- "rr5---sn-a5meknzs.googlevideo.com.": {},
- "rr5---sn-a5mlrnek.googlevideo.com.": {},
- "rr5---sn-a5mlrnl6.googlevideo.com.": {},
- "rr5---sn-a5mlrnll.googlevideo.com.": {},
- "rr5---sn-a5mlrnls.googlevideo.com.": {},
- "rr5---sn-a5mlrnls.gvt1.com.": {},
- "rr5---sn-a5mlrnlz.googlevideo.com.": {},
- "rr5---sn-a5mlrnlz.gvt1.com.": {},
- "rr5---sn-a5msen76.googlevideo.com.": {},
- "rr5---sn-a5msen7l.googlevideo.com.": {},
- "rr5---sn-a5msen7s.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-a5msenll.googlevideo.com.": {},
- "rr5---sn-ab5l6ndr.googlevideo.com.": {},
- "rr5---sn-ab5l6ndy.googlevideo.com.": {},
- "rr5---sn-ab5l6nk6.googlevideo.com.": {},
- "rr5---sn-ab5l6nkd.googlevideo.com.": {},
- "rr5---sn-ab5l6nr6.googlevideo.com.": {},
- "rr5---sn-ab5l6nrd.googlevideo.com.": {},
- "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-ab5sznlk.googlevideo.com.": {},
- "rr5---sn-ab5sznly.googlevideo.com.": {},
- "rr5---sn-ab5sznz6.googlevideo.com.": {},
- "rr5---sn-ab5sznz6.gvt1.com.": {},
- "rr5---sn-ab5sznzd.googlevideo.com.": {},
- "rr5---sn-ab5sznze.googlevideo.com.": {},
- "rr5---sn-ab5sznzk.googlevideo.com.": {},
- "rr5---sn-ab5sznzl.googlevideo.com.": {},
- "rr5---sn-ab5sznzr.googlevideo.com.": {},
- "rr5---sn-ab5sznzs.googlevideo.com.": {},
- "rr5---sn-ab5sznzy.googlevideo.com.": {},
- "rr5---sn-ab5sznzz.googlevideo.com.": {},
- "rr5---sn-aigl6n6s.googlevideo.com.": {},
- "rr5---sn-aigl6ned.googlevideo.com.": {},
- "rr5---sn-aigl6nek.googlevideo.com.": {},
- "rr5---sn-aigl6ner.googlevideo.com.": {},
- "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.": {},
- "rr5---sn-aigl6nze.googlevideo.com.": {},
- "rr5---sn-aigl6nzk.googlevideo.com.": {},
- "rr5---sn-aigl6nzl.googlevideo.com.": {},
- "rr5---sn-aigl6nzr.googlevideo.com.": {},
- "rr5---sn-aigl6nzs.googlevideo.com.": {},
- "rr5---sn-aigzrn76.googlevideo.com.": {},
- "rr5---sn-aigzrn7d.googlevideo.com.": {},
- "rr5---sn-aigzrn7e.googlevideo.com.": {},
- "rr5---sn-aigzrn7k.googlevideo.com.": {},
- "rr5---sn-aigzrn7l.googlevideo.com.": {},
- "rr5---sn-aigzrn7s.googlevideo.com.": {},
- "rr5---sn-aigzrn7z.googlevideo.com.": {},
- "rr5---sn-aigzrne7.googlevideo.com.": {},
- "rr5---sn-aigzrnld.googlevideo.com.": {},
- "rr5---sn-aigzrnse.googlevideo.com.": {},
- "rr5---sn-aigzrnsl.googlevideo.com.": {},
- "rr5---sn-aigzrnsr.googlevideo.com.": {},
- "rr5---sn-aigzrnss.googlevideo.com.": {},
- "rr5---sn-aigzrnsz.googlevideo.com.": {},
- "rr5---sn-aigzrnz7.googlevideo.com.": {},
- "rr5---sn-aigzrnze.googlevideo.com.": {},
- "rr5---sn-aj5ua5-5c.googlevideo.com.": {},
- "rr5---sn-apn7en7e.googlevideo.com.": {},
- "rr5---sn-apn7en7l.googlevideo.com.": {},
- "rr5---sn-apn7en7s.googlevideo.com.": {},
- "rr5---sn-c0q7lnz7.googlevideo.com.": {},
- "rr5---sn-cvb7lne7.googlevideo.com.": {},
- "rr5---sn-cvb7lnl7.googlevideo.com.": {},
- "rr5---sn-cvb7lnls.googlevideo.com.": {},
- "rr5---sn-cvb7lnlz.googlevideo.com.": {},
- "rr5---sn-cvb7sn7k.googlevideo.com.": {},
- "rr5---sn-cvb7sn7r.googlevideo.com.": {},
- "rr5---sn-h0jeened.googlevideo.com.": {},
- "rr5---sn-h0jeenek.googlevideo.com.": {},
- "rr5---sn-h0jeener.googlevideo.com.": {},
- "rr5---sn-h0jeenl6.googlevideo.com.": {},
- "rr5---sn-h0jeenld.googlevideo.com.": {},
- "rr5---sn-h0jeln7e.googlevideo.com.": {},
- "rr5---sn-h0jeln7l.googlevideo.com.": {},
- "rr5---sn-h0jelne6.googlevideo.com.": {},
- "rr5---sn-h0jelne7.googlevideo.com.": {},
- "rr5---sn-h0jelnes.googlevideo.com.": {},
- "rr5---sn-h0jelnez.googlevideo.com.": {},
- "rr5---sn-hoa7kn76.googlevideo.com.": {},
- "rr5---sn-hoa7kn7z.googlevideo.com.": {},
- "rr5---sn-hoa7rn76.googlevideo.com.": {},
- "rr5---sn-hoa7rn7z.googlevideo.com.": {},
- "rr5---sn-hp57kn6r.googlevideo.com.": {},
- "rr5---sn-hp57kn6y.googlevideo.com.": {},
- "rr5---sn-hp57kn6y.gvt1.com.": {},
- "rr5---sn-hp57knd6.googlevideo.com.": {},
- "rr5---sn-hp57knd6.gvt1.com.": {},
- "rr5---sn-hp57kndd.googlevideo.com.": {},
- "rr5---sn-hp57kndd.gvt1.com.": {},
- "rr5---sn-hp57kndk.googlevideo.com.": {},
- "rr5---sn-hp57kndr.googlevideo.com.": {},
- "rr5---sn-hp57knds.googlevideo.com.": {},
- "rr5---sn-hp57knds.gvt1.com.": {},
- "rr5---sn-hp57kndy.googlevideo.com.": {},
- "rr5---sn-hp57kndz.googlevideo.com.": {},
- "rr5---sn-hp57yn7y.googlevideo.com.": {},
- "rr5---sn-hp57yne7.googlevideo.com.": {},
- "rr5---sn-hp57ynee.googlevideo.com.": {},
- "rr5---sn-hp57ynl6.googlevideo.com.": {},
- "rr5---sn-hp57ynlr.googlevideo.com.": {},
- "rr5---sn-hp57ynlr.gvt1.com.": {},
- "rr5---sn-hp57ynly.googlevideo.com.": {},
- "rr5---sn-hp57yns7.googlevideo.com.": {},
- "rr5---sn-hp57ynse.googlevideo.com.": {},
- "rr5---sn-hp57ynsl.googlevideo.com.": {},
- "rr5---sn-hp57ynss.googlevideo.com.": {},
- "rr5---sn-i3b7kn6s.googlevideo.com.": {},
- "rr5---sn-i3b7knld.googlevideo.com.": {},
- "rr5---sn-i3b7kns6.googlevideo.com.": {},
- "rr5---sn-i3b7knsd.googlevideo.com.": {},
- "rr5---sn-i3b7knse.googlevideo.com.": {},
- "rr5---sn-i3b7knsl.googlevideo.com.": {},
- "rr5---sn-i3b7knzl.googlevideo.com.": {},
- "rr5---sn-i3b7knzs.googlevideo.com.": {},
- "rr5---sn-i3belne6.googlevideo.com.": {},
- "rr5---sn-i3belnl6.googlevideo.com.": {},
- "rr5---sn-i3belnl7.googlevideo.com.": {},
- "rr5---sn-i3belnll.googlevideo.com.": {},
- "rr5---sn-i3belnls.googlevideo.com.": {},
- "rr5---sn-i3bssn7e.googlevideo.com.": {},
- "rr5---sn-i5h7lner.googlevideo.com.": {},
- "rr5---sn-i5h7lnl6.googlevideo.com.": {},
- "rr5---sn-i5h7lnll.googlevideo.com.": {},
- "rr5---sn-i5h7lnls.googlevideo.com.": {},
- "rr5---sn-i5heen7r.googlevideo.com.": {},
- "rr5---sn-i5heen7s.googlevideo.com.": {},
- "rr5---sn-jn2pgx4pcxg-w5os.googlevideo.com.": {},
- "rr5---sn-jvhj5nu-2iae.googlevideo.com.": {},
- "rr5---sn-jvhj5nu-2ias.googlevideo.com.": {},
- "rr5---sn-jvhj5nu-nh4e.googlevideo.com.": {},
- "rr5---sn-jvhj5nu-nh4s.googlevideo.com.": {},
- "rr5---sn-jvhj5nu-nh4z.googlevideo.com.": {},
- "rr5---sn-jvhj5nu-qufe.googlevideo.com.": {},
- "rr5---sn-jvhj5nu-qufl.googlevideo.com.": {},
- "rr5---sn-jvhj5nu-qufs.googlevideo.com.": {},
- "rr5---sn-jxopj-n5oe.googlevideo.com.": {},
- "rr5---sn-jxopj-nh4e.googlevideo.com.": {},
- "rr5---sn-jxopj-nh4e.gvt1.com.": {},
- "rr5---sn-muxa-2iae.googlevideo.com.": {},
- "rr5---sn-n4v7snee.googlevideo.com.": {},
- "rr5---sn-n4v7sney.googlevideo.com.": {},
- "rr5---sn-n4v7snll.googlevideo.com.": {},
- "rr5---sn-n4v7snlr.googlevideo.com.": {},
- "rr5---sn-n4v7snls.googlevideo.com.": {},
- "rr5---sn-n4v7snly.googlevideo.com.": {},
- "rr5---sn-n4v7sns7.googlevideo.com.": {},
- "rr5---sn-n4v7snse.googlevideo.com.": {},
- "rr5---sn-npoe7ndl.googlevideo.com.": {},
- "rr5---sn-npoe7nds.googlevideo.com.": {},
- "rr5---sn-npoe7ne6.googlevideo.com.": {},
- "rr5---sn-npoe7ne7.googlevideo.com.": {},
- "rr5---sn-npoe7ned.googlevideo.com.": {},
- "rr5---sn-npoe7nek.googlevideo.com.": {},
- "rr5---sn-npoe7ner.googlevideo.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-npoe7ns7.googlevideo.com.": {},
- "rr5---sn-npoe7nsd.googlevideo.com.": {},
- "rr5---sn-npoe7nsk.googlevideo.com.": {},
- "rr5---sn-npoe7nsr.googlevideo.com.": {},
- "rr5---sn-npoe7nss.googlevideo.com.": {},
- "rr5---sn-npoe7nsy.googlevideo.com.": {},
- "rr5---sn-npoe7nz7.googlevideo.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-npoeenle.googlevideo.com.": {},
- "rr5---sn-npoeenlk.googlevideo.com.": {},
- "rr5---sn-npoeenll.googlevideo.com.": {},
- "rr5---sn-npoeenly.googlevideo.com.": {},
- "rr5---sn-npoeens7.googlevideo.com.": {},
- "rr5---sn-npoldn76.googlevideo.com.": {},
- "rr5---sn-npoldn7d.googlevideo.com.": {},
- "rr5---sn-npoldn7e.googlevideo.com.": {},
- "rr5---sn-npoldn7l.googlevideo.com.": {},
- "rr5---sn-npoldn7s.googlevideo.com.": {},
- "rr5---sn-npoldn7y.googlevideo.com.": {},
- "rr5---sn-npoldn7z.googlevideo.com.": {},
- "rr5---sn-npoldne7.googlevideo.com.": {},
- "rr5---sn-ntq7yns7.googlevideo.com.": {},
- "rr5---sn-nv47ln6e.googlevideo.com.": {},
- "rr5---sn-nv47lns6.googlevideo.com.": {},
- "rr5---sn-nv47lnsr.googlevideo.com.": {},
- "rr5---sn-nv47zn7r.googlevideo.com.": {},
- "rr5---sn-nv47zn7y.googlevideo.com.": {},
- "rr5---sn-nv47zne7.googlevideo.com.": {},
- "rr5---sn-nv47znee.googlevideo.com.": {},
- "rr5---sn-nv47znel.googlevideo.com.": {},
- "rr5---sn-nx57ynsd.googlevideo.com.": {},
- "rr5---sn-nx57ynse.googlevideo.com.": {},
- "rr5---sn-nx57ynse.gvt1.com.": {},
- "rr5---sn-nx57ynsk.googlevideo.com.": {},
- "rr5---sn-nx57ynsk.gvt1.com.": {},
- "rr5---sn-nx57ynsl.googlevideo.com.": {},
- "rr5---sn-nx57ynss.googlevideo.com.": {},
- "rr5---sn-nx57ynsz.googlevideo.com.": {},
- "rr5---sn-nx5s7n76.googlevideo.com.": {},
- "rr5---sn-nx5s7n76.gvt1.com.": {},
- "rr5---sn-nx5s7n7d.googlevideo.com.": {},
- "rr5---sn-nx5s7n7s.googlevideo.com.": {},
- "rr5---sn-nx5s7n7s.gvt1.com.": {},
- "rr5---sn-nx5s7n7y.googlevideo.com.": {},
- "rr5---sn-nx5s7n7y.gvt1.com.": {},
- "rr5---sn-nx5s7n7z.googlevideo.com.": {},
- "rr5---sn-nx5s7n7z.gvt1.com.": {},
- "rr5---sn-nx5s7nee.googlevideo.com.": {},
- "rr5---sn-nx5s7nee.gvt1.com.": {},
- "rr5---sn-nx5s7nel.googlevideo.com.": {},
- "rr5---sn-o097znsd.googlevideo.com.": {},
- "rr5---sn-o097znse.googlevideo.com.": {},
- "rr5---sn-o097znsk.googlevideo.com.": {},
- "rr5---sn-o097znsl.googlevideo.com.": {},
- "rr5---sn-o097znsr.googlevideo.com.": {},
- "rr5---sn-o097znss.googlevideo.com.": {},
- "rr5---sn-o097znsz.googlevideo.com.": {},
- "rr5---sn-o097znz7.googlevideo.com.": {},
- "rr5---sn-o097znzd.googlevideo.com.": {},
- "rr5---sn-o097znze.googlevideo.com.": {},
- "rr5---sn-o097znzk.googlevideo.com.": {},
- "rr5---sn-o097znzr.googlevideo.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-p5qlsn7d.googlevideo.com.": {},
- "rr5---sn-p5qlsn7l.googlevideo.com.": {},
- "rr5---sn-p5qlsn7s.googlevideo.com.": {},
- "rr5---sn-p5qlsnd6.googlevideo.com.": {},
- "rr5---sn-p5qlsndd.googlevideo.com.": {},
- "rr5---sn-p5qlsndz.googlevideo.com.": {},
- "rr5---sn-p5qlsnrl.googlevideo.com.": {},
- "rr5---sn-p5qlsnrr.googlevideo.com.": {},
- "rr5---sn-p5qlsny6.googlevideo.com.": {},
- "rr5---sn-p5qs7n6d.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-q4fl6n66.gvt1.com.": {},
- "rr5---sn-q4fl6n6d.googlevideo.com.": {},
- "rr5---sn-q4fl6n6d.gvt1.com.": {},
- "rr5---sn-q4fl6n6s.googlevideo.com.": {},
- "rr5---sn-q4fl6n6y.googlevideo.com.": {},
- "rr5---sn-q4fl6n6z.googlevideo.com.": {},
- "rr5---sn-q4fl6n6z.gvt1.com.": {},
- "rr5---sn-q4fl6nd6.googlevideo.com.": {},
- "rr5---sn-q4fl6nd7.googlevideo.com.": {},
- "rr5---sn-q4fl6nd7.gvt1.com.": {},
- "rr5---sn-q4fl6nde.googlevideo.com.": {},
- "rr5---sn-q4fl6ndl.googlevideo.com.": {},
- "rr5---sn-q4fl6nds.googlevideo.com.": {},
- "rr5---sn-q4fl6ndz.googlevideo.com.": {},
- "rr5---sn-q4fl6nlz.googlevideo.com.": {},
- "rr5---sn-q4fl6ns6.googlevideo.com.": {},
- "rr5---sn-q4fl6ns6.gvt1.com.": {},
- "rr5---sn-q4fl6ns7.googlevideo.com.": {},
- "rr5---sn-q4fl6nsd.googlevideo.com.": {},
- "rr5---sn-q4fl6nsd.gvt1.com.": {},
- "rr5---sn-q4fl6nsk.googlevideo.com.": {},
- "rr5---sn-q4fl6nsk.gvt1.com.": {},
- "rr5---sn-q4fl6nsl.googlevideo.com.": {},
- "rr5---sn-q4fl6nsl.gvt1.com.": {},
- "rr5---sn-q4fl6nsr.googlevideo.com.": {},
- "rr5---sn-q4fl6nss.googlevideo.com.": {},
- "rr5---sn-q4fl6nss.gvt1.com.": {},
- "rr5---sn-q4fl6nsy.googlevideo.com.": {},
- "rr5---sn-q4fl6nz6.googlevideo.com.": {},
- "rr5---sn-q4fl6nz7.googlevideo.com.": {},
- "rr5---sn-q4fl6nzy.googlevideo.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-q4flrnee.googlevideo.com.": {},
- "rr5---sn-q4flrnek.googlevideo.com.": {},
- "rr5---sn-q4flrnel.googlevideo.com.": {},
- "rr5---sn-q4flrnel.gvt1.com.": {},
- "rr5---sn-q4flrner.googlevideo.com.": {},
- "rr5---sn-q4flrner.gvt1.com.": {},
- "rr5---sn-q4flrnes.googlevideo.com.": {},
- "rr5---sn-q4flrney.googlevideo.com.": {},
- "rr5---sn-q4flrnez.googlevideo.com.": {},
- "rr5---sn-q4flrnl6.googlevideo.com.": {},
- "rr5---sn-q4flrnl6.gvt1.com.": {},
- "rr5---sn-q4flrnl7.googlevideo.com.": {},
- "rr5---sn-q4flrnl7.gvt1.com.": {},
- "rr5---sn-q4flrnld.googlevideo.com.": {},
- "rr5---sn-q4flrnld.gvt1.com.": {},
- "rr5---sn-q4flrnle.googlevideo.com.": {},
- "rr5---sn-q4flrnlz.googlevideo.com.": {},
- "rr5---sn-q4flrnsd.googlevideo.com.": {},
- "rr5---sn-q4flrnsk.googlevideo.com.": {},
- "rr5---sn-q4flrnsl.googlevideo.com.": {},
- "rr5---sn-q4flrnss.googlevideo.com.": {},
- "rr5---sn-q4flrnss.gvt1.com.": {},
- "rr5---sn-q4fzen7e.googlevideo.com.": {},
- "rr5---sn-q4fzen7l.googlevideo.com.": {},
- "rr5---sn-q4fzen7r.googlevideo.com.": {},
- "rr5---sn-q4fzen7r.gvt1.com.": {},
- "rr5---sn-q4fzen7s.googlevideo.com.": {},
- "rr5---sn-q4fzen7s.gvt1.com.": {},
- "rr5---sn-q4fzen7y.googlevideo.com.": {},
- "rr5---sn-q4fzene7.googlevideo.com.": {},
- "rr5---sn-q4fzenee.googlevideo.com.": {},
- "rr5---sn-qxo7rn7k.googlevideo.com.": {},
- "rr5---sn-qxo7rn7r.googlevideo.com.": {},
- "rr5---sn-qxo7rn7y.googlevideo.com.": {},
- "rr5---sn-qxoedn7k.googlevideo.com.": {},
- "rr5---sn-qxoedne7.googlevideo.com.": {},
- "rr5---sn-qxoednee.googlevideo.com.": {},
- "rr5---sn-t0a7ln7d.googlevideo.com.": {},
- "rr5---sn-u1hp55-5c.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-vgqskne6.googlevideo.com.": {},
- "rr5---sn-vgqskned.googlevideo.com.": {},
- "rr5---sn-vgqsknek.googlevideo.com.": {},
- "rr5---sn-vgqsknes.googlevideo.com.": {},
- "rr5---sn-vgqsknez.googlevideo.com.": {},
- "rr5---sn-vgqsknez.gvt1.com.": {},
- "rr5---sn-vgqsknlk.googlevideo.com.": {},
- "rr5---sn-vgqsknlr.googlevideo.com.": {},
- "rr5---sn-vgqsknlr.gvt1.com.": {},
- "rr5---sn-vgqsknls.googlevideo.com.": {},
- "rr5---sn-vgqsknls.gvt1.com.": {},
- "rr5---sn-vgqsknly.googlevideo.com.": {},
- "rr5---sn-vgqsknlz.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-vgqsknze.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-vgqsrn6e.googlevideo.com.": {},
- "rr5---sn-vgqsrn6l.googlevideo.com.": {},
- "rr5---sn-vgqsrn6z.googlevideo.com.": {},
- "rr5---sn-vgqsrn6z.gvt1.com.": {},
- "rr5---sn-vgqsrne6.googlevideo.com.": {},
- "rr5---sn-vgqsrnek.googlevideo.com.": {},
- "rr5---sn-vgqsrnes.googlevideo.com.": {},
- "rr5---sn-vgqsrnez.googlevideo.com.": {},
- "rr5---sn-vgqsrnl6.googlevideo.com.": {},
- "rr5---sn-vgqsrnld.googlevideo.com.": {},
- "rr5---sn-vgqsrnlk.googlevideo.com.": {},
- "rr5---sn-vgqsrnll.googlevideo.com.": {},
- "rr5---sn-vgqsrnls.googlevideo.com.": {},
- "rr5---sn-vgqsrnlz.googlevideo.com.": {},
- "rr5---sn-vgqsrns6.googlevideo.com.": {},
- "rr5---sn-vgqsrns6.gvt1.com.": {},
- "rr5---sn-vgqsrnsd.googlevideo.com.": {},
- "rr5---sn-vgqsrnsr.googlevideo.com.": {},
- "rr5---sn-vgqsrnsy.googlevideo.com.": {},
- "rr5---sn-vgqsrnsy.gvt1.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.": {},
- "rr5---sn-vgqsrnzz.gvt1.com.": {},
- "rr5.sn-ntq7yns7.googlevideo.com.": {},
- "rr5.sn-q4fl6nd7.googlevideo.com.": {},
- "rr5.sn-q4fl6nde.googlevideo.com.": {},
- "rr5.sn-q4flrne6.googlevideo.com.": {},
- "rr5.sn-q4flrnl6.googlevideo.com.": {},
- "rr5.sn-q4flrnl7.googlevideo.com.": {},
- "rr5.sn-q4flrnld.googlevideo.com.": {},
- "rr5.sn-q4fzen7e.googlevideo.com.": {},
- "rr5.sn-q4fzen7s.googlevideo.com.": {},
- "rr6---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.": {},
- "rr6---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.": {},
- "rr6---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.": {},
- "rr6---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.": {},
- "rr6---sn-5pgnugx5h-hn2z.googlevideo.com.": {},
- "rr6---sn-8qj-nbo66.googlevideo.com.": {},
- "rr6---sn-8xgp1vo-2iae.googlevideo.com.": {},
- "rr6---sn-8xgp1vo-2iae7.googlevideo.com.": {},
- "rr6---sn-8xgp1vo-2ial.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-ab5s.googlevideo.com.": {},
- "rr6---sn-8xgp1vo-ab5z.googlevideo.com.": {},
- "rr6---sn-8xgp1vo-p5ie.googlevideo.com.": {},
- "rr6---sn-8xgp1vo-vgqe.googlevideo.com.": {},
- "rr6---sn-8xgp1vo-xfgl.googlevideo.com.": {},
- "rr6---sn-8xgp1vo-xfgs.googlevideo.com.": {},
- "rr6---sn-i5f5ppuxa-ioal.googlevideo.com.": {},
- "rr6---sn-jvhj5nu-2iae.googlevideo.com.": {},
- "rr6---sn-jvhj5nu-2ial.googlevideo.com.": {},
- "rr6---sn-jvhj5nu-2ias.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-jvhj5nu-qufe.googlevideo.com.": {},
- "rr6---sn-jvhj5nu-qufl.googlevideo.com.": {},
- "rr6---sn-jvhj5nu-qufs.googlevideo.com.": {},
- "rr6---sn-jvhj5nu-qufz.googlevideo.com.": {},
- "rr6---sn-jxopj-n5oe.googlevideo.com.": {},
- "rr6---sn-jxopj-n5oe.gvt1.com.": {},
- "rr6---sn-jxopj-nh4e.googlevideo.com.": {},
- "rr6---sn-jxopj-nh4e.gvt1.com.": {},
- "rr6---sn-nv0ui4gvou-hape.googlevideo.com.": {},
- "rr7---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.": {},
- "rr7---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.": {},
- "rr7---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.": {},
- "rr7---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.": {},
- "rr7---sn-8qj-nbo66.googlevideo.com.": {},
- "rr7---sn-8xgp1vo-2iae.googlevideo.com.": {},
- "rr7---sn-8xgp1vo-2ial.googlevideo.com.": {},
- "rr7---sn-8xgp1vo-a5me.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-ab5s.googlevideo.com.": {},
- "rr7---sn-8xgp1vo-ab5z.googlevideo.com.": {},
- "rr7---sn-8xgp1vo-p5ie.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-nh4z.googlevideo.com.": {},
- "rr7---sn-jvhj5nu-qufl.googlevideo.com.": {},
- "rr7---sn-jvhj5nu-qufs.googlevideo.com.": {},
- "rr7---sn-jvhj5nu-qufz.googlevideo.com.": {},
- "rr7---sn-jxopj-n5oe.googlevideo.com.": {},
- "rr7---sn-jxopj-n5oe.gvt1.com.": {},
- "rr8---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.": {},
- "rr8---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.": {},
- "rr8---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.": {},
- "rr8---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.": {},
- "rr8---sn-8xgp1vo-2iae.googlevideo.com.": {},
- "rr8---sn-8xgp1vo-2ial.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-p5ie.googlevideo.com.": {},
- "rr8---sn-8xgp1vo-vgqe.googlevideo.com.": {},
- "rr8---sn-8xgp1vo-xfge.googlevideo.com.": {},
- "rr8---sn-8xgp1vo-xfgl.googlevideo.com.": {},
- "rr8---sn-bvvbax-2iae.googlevideo.com.": {},
- "rr8---sn-bvvbax-2ial.googlevideo.com.": {},
- "rs-stripe.alm.com.": {},
- "rs1.qq.com.": {},
- "rs2.qq.com.": {},
- "rsx.afterpay.com.": {},
- "rt.teramind.co.": {},
- "rtb-apac.rtbserve.io.": {},
- "rtb-eu.rtbserve.io.": {},
- "rtb-useast.creativedot.net.": {},
- "rtb-useast.openrtb.in.": {},
- "rtb-useast.rtbserve.io.": {},
- "rtb-uswest.rtbserve.io.": {},
- "rtb2-apac.xaprio.net.": {},
- "rtb2-eu.xaprio.net.": {},
- "rtb2-useast.xaprio.net.": {},
- "rtb2-uswest.xaprio.net.": {},
- "rtbasia.com.": {},
- "rtbsuperhub.com.": {},
- "rtbwave.com.": {},
- "rtlog22-normal-alisg.tiktokv.com.": {},
- "rttf.citrix.com.": {},
- "ru1.chat.si.riotgames.com.": {},
- "ruijienetworks.com.": {},
- "rumble.com.": {},
- "rumt-sg.com.": {},
- "rushenterprises.sharepoint.com.": {},
- "rutgersconnect-my.sharepoint.com.": {},
- "rxsafeway-my.sharepoint.com.": {},
- "rxsafeway.sharepoint.com.": {},
- "s-cs.send.microad.jp.": {},
- "s-rtb-pb.send.microad.jp.": {},
- "s.dblks.net.": {},
- "s.deepl.com.": {},
- "s.dualspaceapi.com.": {},
- "s.exitbee.com.": {},
- "s.optifine.net.": {},
- "s.q.easebar.com.": {},
- "s.seedtag.com.": {},
- "s1.thcdn.com.": {},
- "s3.us-east-005.backblazeb2.com.": {},
- "s7d6.scene7.com.": {},
- "sa1.chat.si.riotgames.com.": {},
- "sa2.chat.si.riotgames.com.": {},
- "sa3.chat.si.riotgames.com.": {},
- "sabre-app.quantummetric.com.": {},
- "sabre-sync.quantummetric.com.": {},
- "safelitegroup-my.sharepoint.com.": {},
- "saintasaph.remotepc.com.": {},
- "salesbridge-my.sharepoint.com.": {},
- "salesbridge.sharepoint.com.": {},
- "saltlakecity.remotepc.com.": {},
- "samsclub.quantummetric.com.": {},
- "san.support.hp.com.edgekey.net.": {},
- "sanantonio.remotepc.com.": {},
- "sanctionssearch.ofac.treas.gov.": {},
- "sandboxclient.retinavue.net.": {},
- "sandboxregister.retinavue.net.": {},
- "sandiego.remotepc.com.": {},
- "sandiegodc.remotepc.com.": {},
- "sanjagh.com.": {},
- "sanjose.remotepc.com.": {},
- "santandernet-my.sharepoint.com.": {},
- "santandernet.sharepoint.com.": {},
- "santiago.remotepc.com.": {},
- "sanxia.studyquicks.com.": {},
- "saopaulo.remotepc.com.": {},
- "saopaulo1.remotepc.com.": {},
- "saskpower-my.sharepoint.com.": {},
- "saspeed.igamecj.com.": {},
- "sat02pap001.storage.live.com.": {},
- "sat02pap001files.storage.live.com.": {},
- "sat02pap002.storage.live.com.": {},
- "sat02pap002files.storage.live.com.": {},
- "sat02pap003.storage.live.com.": {},
- "sat02pap003files.storage.live.com.": {},
- "sat02pap004.storage.live.com.": {},
- "sat02pap004files.storage.live.com.": {},
- "sat02pap005.storage.live.com.": {},
- "sat02pap005files.storage.live.com.": {},
- "sav.cynet.com.": {},
- "sc.cnbc.com.": {},
- "sc.zoom.us.": {},
- "scasurgery-my.sharepoint.com.": {},
- "scasurgery.sharepoint.com.": {},
- "scdss-my.sharepoint.com.": {},
- "schneidercorp.com.": {},
- "sciener.cn.": {},
- "sconf.f.360.cn.": {},
- "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-ber1-1.cdninstagram.com.": {},
- "scontent-ber1-1.xx.fbcdn.net.": {},
- "scontent-bkk1-1.xx.fbcdn.net.": {},
- "scontent-bkk1-2.xx.fbcdn.net.": {},
- "scontent-bog2-1.cdninstagram.com.": {},
- "scontent-bog2-1.xx.fbcdn.net.": {},
- "scontent-bog2-2.cdninstagram.com.": {},
- "scontent-bog2-2.xx.fbcdn.net.": {},
- "scontent-bos5-1.cdninstagram.com.": {},
- "scontent-bos5-1.xx.fbcdn.net.": {},
- "scontent-bru2-1.cdninstagram.com.": {},
- "scontent-bru2-1.xx.fbcdn.net.": {},
- "scontent-cdg4-1.cdninstagram.com.": {},
- "scontent-cdg4-1.xx.fbcdn.net.": {},
- "scontent-cdg4-2.cdninstagram.com.": {},
- "scontent-cdg4-2.xx.fbcdn.net.": {},
- "scontent-cdg4-3.cdninstagram.com.": {},
- "scontent-cdg4-3.xx.fbcdn.net.": {},
- "scontent-cgk1-1.cdninstagram.com.": {},
- "scontent-cgk1-1.xx.fbcdn.net.": {},
- "scontent-cgk1-2.cdninstagram.com.": {},
- "scontent-cgk1-2.xx.fbcdn.net.": {},
- "scontent-den2-1.cdninstagram.com.": {},
- "scontent-den2-1.xx.fbcdn.net.": {},
- "scontent-dfw5-1.cdninstagram.com.": {},
- "scontent-dfw5-1.xx.fbcdn.net.": {},
- "scontent-dfw5-2.cdninstagram.com.": {},
- "scontent-dfw5-2.xx.fbcdn.net.": {},
- "scontent-dus1-1.cdninstagram.com.": {},
- "scontent-dus1-1.xx.fbcdn.net.": {},
- "scontent-fra3-1.cdninstagram.com.": {},
- "scontent-fra3-1.xx.fbcdn.net.": {},
- "scontent-fra3-2.cdninstagram.com.": {},
- "scontent-fra3-2.xx.fbcdn.net.": {},
- "scontent-fra5-1.cdninstagram.com.": {},
- "scontent-fra5-1.xx.fbcdn.net.": {},
- "scontent-fra5-2.cdninstagram.com.": {},
- "scontent-fra5-2.xx.fbcdn.net.": {},
- "scontent-gmp1-1.cdninstagram.com.": {},
- "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.": {},
- "scontent-hkg1-2.cdninstagram.com.": {},
- "scontent-hkg1-2.xx.fbcdn.net.": {},
- "scontent-hkg4-1.cdninstagram.com.": {},
- "scontent-hkg4-1.xx.fbcdn.net.": {},
- "scontent-hkg4-2.cdninstagram.com.": {},
- "scontent-hkg4-2.xx.fbcdn.net.": {},
- "scontent-hou1-1.cdninstagram.com.": {},
- "scontent-hou1-1.xx.fbcdn.net.": {},
- "scontent-iad3-1.cdninstagram.com.": {},
- "scontent-iad3-1.xx.fbcdn.net.": {},
- "scontent-iad3-2.cdninstagram.com.": {},
- "scontent-iad3-2.xx.fbcdn.net.": {},
- "scontent-lax3-1.cdninstagram.com.": {},
- "scontent-lax3-1.xx.fbcdn.net.": {},
- "scontent-lax3-2.cdninstagram.com.": {},
- "scontent-lax3-2.xx.fbcdn.net.": {},
- "scontent-lga3-1.cdninstagram.com.": {},
- "scontent-lga3-1.xx.fbcdn.net.": {},
- "scontent-lga3-2.cdninstagram.com.": {},
- "scontent-lga3-2.xx.fbcdn.net.": {},
- "scontent-lhr6-1.cdninstagram.com.": {},
- "scontent-lhr6-1.xx.fbcdn.net.": {},
- "scontent-lhr6-2.cdninstagram.com.": {},
- "scontent-lhr6-2.xx.fbcdn.net.": {},
- "scontent-lhr8-1.cdninstagram.com.": {},
- "scontent-lhr8-1.xx.fbcdn.net.": {},
- "scontent-lhr8-2.cdninstagram.com.": {},
- "scontent-lhr8-2.xx.fbcdn.net.": {},
- "scontent-lis1-1.cdninstagram.com.": {},
- "scontent-lis1-1.xx.fbcdn.net.": {},
- "scontent-los2-1.xx.fbcdn.net.": {},
- "scontent-man2-1.cdninstagram.com.": {},
- "scontent-man2-1.xx.fbcdn.net.": {},
- "scontent-mia3-1.cdninstagram.com.": {},
- "scontent-mia3-1.xx.fbcdn.net.": {},
- "scontent-mia3-2.cdninstagram.com.": {},
- "scontent-mia3-2.xx.fbcdn.net.": {},
- "scontent-mnl1-1.xx.fbcdn.net.": {},
- "scontent-mnl1-2.xx.fbcdn.net.": {},
- "scontent-mrs2-1.cdninstagram.com.": {},
- "scontent-mrs2-1.xx.fbcdn.net.": {},
- "scontent-mrs2-2.cdninstagram.com.": {},
- "scontent-mrs2-2.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-ord5-1.cdninstagram.com.": {},
- "scontent-ord5-1.xx.fbcdn.net.": {},
- "scontent-ord5-2.cdninstagram.com.": {},
- "scontent-ord5-2.xx.fbcdn.net.": {},
- "scontent-prg1-1.cdninstagram.com.": {},
- "scontent-prg1-1.xx.fbcdn.net.": {},
- "scontent-qro1-1.cdninstagram.com.": {},
- "scontent-qro1-1.xx.fbcdn.net.": {},
- "scontent-qro1-2.cdninstagram.com.": {},
- "scontent-qro1-2.xx.fbcdn.net.": {},
- "scontent-sea1-1.cdninstagram.com.": {},
- "scontent-sea1-1.xx.fbcdn.net.": {},
- "scontent-sin6-1.cdninstagram.com.": {},
- "scontent-sin6-1.xx.fbcdn.net.": {},
- "scontent-sin6-2.cdninstagram.com.": {},
- "scontent-sin6-2.xx.fbcdn.net.": {},
- "scontent-sin6-3.cdninstagram.com.": {},
- "scontent-sin6-3.xx.fbcdn.net.": {},
- "scontent-sin6-4.cdninstagram.com.": {},
- "scontent-sin6-4.xx.fbcdn.net.": {},
- "scontent-sjc3-1.cdninstagram.com.": {},
- "scontent-sjc3-1.xx.fbcdn.net.": {},
- "scontent-sof1-1.xx.fbcdn.net.": {},
- "scontent-ssn1-1.cdninstagram.com.": {},
- "scontent-vie1-1.cdninstagram.com.": {},
- "scontent-vie1-1.xx.fbcdn.net.": {},
- "scontent-waw1-1.cdninstagram.com.": {},
- "scontent-waw1-1.xx.fbcdn.net.": {},
- "scontent-xsp1-1.cdninstagram.com.": {},
- "scontent-xsp1-1.xx.fbcdn.net.": {},
- "scontent-xsp1-2.cdninstagram.com.": {},
- "scontent-xsp1-2.xx.fbcdn.net.": {},
- "scontent-xsp1-3.cdninstagram.com.": {},
- "scontent-xsp1-3.xx.fbcdn.net.": {},
- "scontent-xsp2-1.cdninstagram.com.": {},
- "scontent-xsp2-1.xx.fbcdn.net.": {},
- "scontent-yyz1-1.cdninstagram.com.": {},
- "scontent-yyz1-1.xx.fbcdn.net.": {},
- "scotiabank.com.": {},
- "scraper2.onlineradiobox.com.": {},
- "scus.his.arc.azure.com.": {},
- "scus.his.hybridcompute.trafficmanager.net.": {},
- "sd-suggestions.operacdn.com.": {},
- "sdeconfig.kaspersky-labs.com.": {},
- "sdk.beizi.biz.": {},
- "sdk.canva.com.": {},
- "sdk.iad-04.braze.com.cdn.cloudflare.net.": {},
- "sdk.jetbluevacations.com.": {},
- "sdk.qcloud.com.": {},
- "sdkgate.pushv3.easebar.com.": {},
- "sdktmp.hubcloud.com.cn.": {},
- "sdn.lxdns.com.": {},
- "seagate.com.": {},
- "seagullscientific.com.": {},
- "sealsubscriptions.com.": {},
- "search.dnssearch.org.": {},
- "search.namequery.com.": {},
- "search.us.namequery.com.": {},
- "searchanise.com.": {},
- "searchfeed.adssquared.com.": {},
- "searchserverapi.com.": {},
- "seattle.remotepc.com.": {},
- "secaucus.remotepc.com.": {},
- "secure-web.cisco.com.": {},
- "secure.accurint.com.": {},
- "secure.skypeassets.com.": {},
- "secure.syndetics.com.": {},
- "secure5.arcot.com.": {},
- "securelink.rivhs.com.": {},
- "securelink.valleywisehealth.org.": {},
- "securityapi.d3-pr-tm.com.": {},
- "securitybankcorporation-my.sharepoint.com.": {},
- "securitybankcorporation.sharepoint.com.": {},
- "seedtag.com.": {},
- "segway.prod.k8s.onepeloton.com.": {},
- "send.microad.jp.": {},
- "sendibt3.com.": {},
- "sensei.ruselabs.com.": {},
- "sensorsdata.cn.": {},
- "sensorsdata.com.": {},
- "sentry.appodeal.com.": {},
- "sentry.archive.org.": {},
- "sentry.ksztone.com.": {},
- "sentry.quillbot.com.": {},
- "sentry.wrike.com.": {},
- "seoul.remotepc.com.": {},
- "sephora-live.inside-graph.com.cdn.cloudflare.net.": {},
- "serv.vuukle.com.": {},
- "serve.pubapp.network.": {},
- "served-by.pixfuture.com.": {},
- "server.10m.com.cn.": {},
- "server.bidstack.com.": {},
- "serverforge.org.": {},
- "service.minute.ly.": {},
- "service.weather.microsoft.com.": {},
- "service2.ultipro.com.": {},
- "servicebus101.myconnectsecure.com.": {},
- "servicebus102.myconnectsecure.com.": {},
- "servicebus103.myconnectsecure.com.": {},
- "servicebus104.myconnectsecure.com.": {},
- "services-mob.panerabread.com.": {},
- "services.lego.com.": {},
- "services.starfinanz.de.": {},
- "services.ucp.kaspersky-labs.com.": {},
- "servicetitan.com.": {},
- "servt.vuukle.com.": {},
- "servx.opamarketplace.com.": {},
- "servx.playstream.media.": {},
- "settings.live.net.": {},
- "settings.luckyorange.com.": {},
- "sewjn80htn-1.algolianet.com.": {},
- "sewjn80htn-2.algolianet.com.": {},
- "sewjn80htn-3.algolianet.com.": {},
- "sf-express.com.": {},
- "sg.api.translator.voice.gcloudsdk.com.": {},
- "sg1a-excel-collab.officeapps.live.com.": {},
- "sgmbocast.com.": {},
- "sgpcas.ezvizlife.com.": {},
- "shappify.com.": {},
- "share.connect.aig.": {},
- "sharenotes.co.": {},
- "sharpschool.com.": {},
- "shc6.y.qq.com.": {},
- "shop.mango.com.": {},
- "shopify-gtm-suite.getelevar.com.": {},
- "shoplazza.com.": {},
- "shortintl.push.oppomobile.com.": {},
- "shortpixel.ai.": {},
- "shoutout.wix.com.": {},
- "shredder-us.osi.office.net.": {},
- "shuzilm.cn.": {},
- "signin.ultipro.com.": {},
- "sina.com.": {},
- "sinaimg.cn.": {},
- "sip-backup.phonepower.com.": {},
- "sip-primary.phonepower.com.": {},
- "sip.ringcentral.com.": {},
- "sip112-1121.ringcentral.com.": {},
- "sip112-1131.ringcentral.com.": {},
- "sip112-1141.ringcentral.com.": {},
- "sip113-1121.ringcentral.com.": {},
- "sip113-1131.ringcentral.com.": {},
- "sip113-1141.ringcentral.com.": {},
- "sip121-1121.ringcentral.com.": {},
- "sip121-1131.ringcentral.com.": {},
- "sip121-1141.ringcentral.com.": {},
- "sip121-1241.ringcentral.com.": {},
- "sip123-1121.ringcentral.com.": {},
- "sip123-1131.ringcentral.com.": {},
- "sip123-1141.ringcentral.com.": {},
- "sip131-1121.ringcentral.com.": {},
- "sip131-1131.ringcentral.com.": {},
- "sip131-1141.ringcentral.com.": {},
- "sip132-1121.ringcentral.com.": {},
- "sip132-1131.ringcentral.com.": {},
- "sip132-1141.ringcentral.com.": {},
- "sip421-121.ringcentral.biz.": {},
- "sipis.acrobits.cz.": {},
- "sis-ipv6.jpush.cn.": {},
- "sitemaji.com.": {},
- "situsamc365-my.sharepoint.com.": {},
- "sjc.zoom.us.": {},
- "sjc04pap001.storage.live.com.": {},
- "sjc04pap001files.storage.live.com.": {},
- "sjc04pap002.storage.live.com.": {},
- "sjc04pap002files.storage.live.com.": {},
- "skanska-my.sharepoint.com.": {},
- "skims.com.": {},
- "skybet.com.": {},
- "skyglobal.sharepoint.com.": {},
- "skyward-lisdprod.iscorp.com.": {},
- "skyward-ocprod.iscorp.com.": {},
- "skyward.iscorp.com.": {},
- "slb.cynet.com.": {},
- "slickdealscdn.com.": {},
- "sm.cn.": {},
- "sm1.selectmedia.asia.": {},
- "smartcloudcon.com.": {},
- "smarthome.ctdevice.ott4china.com.": {},
- "smartpay.profitstars.com.": {},
- "smetrics.att.com.": {},
- "smoot-searchv2-aapse1c.v.aaplimg.com.": {},
- "smoot-searchv2-aeuc1a.v.aaplimg.com.": {},
- "smoot-searchv2-aeuc1b.v.aaplimg.com.": {},
- "smoot-searchv2-aeuw1b.v.aaplimg.com.": {},
- "smoot-searchv2-aeuw3b.v.aaplimg.com.": {},
- "smoot-searchv2-aeuw3c.v.aaplimg.com.": {},
- "smoot-searchv2-ause1a.v.aaplimg.com.": {},
- "smoot-searchv2-ause1b.v.aaplimg.com.": {},
- "smoot-searchv2-ause1c.v.aaplimg.com.": {},
- "smoot-searchv2-ause2a.v.aaplimg.com.": {},
- "smoot-searchv2-ause2b.v.aaplimg.com.": {},
- "smoot-searchv2-ause2c.v.aaplimg.com.": {},
- "smoot-searchv2-ausw2b.v.aaplimg.com.": {},
- "smoot-searchv2-ausw2c.v.aaplimg.com.": {},
- "smrcy-my.sharepoint.com.": {},
- "smrcy.sharepoint.com.": {},
- "sms-sg.ads.heytapmobile.com.": {},
- "sms.ads.heytapmobi.com.": {},
- "sn.api.np.km.playstation.net.": {},
- "snap-storage-cdn.l.google.com.": {},
- "snippet.affilimatejs.com.": {},
- "snokido.com.": {},
- "snz04pap001.storage.live.com.": {},
- "snz04pap001files.storage.live.com.": {},
- "snz04pap002.storage.live.com.": {},
- "snz04pap002files.storage.live.com.": {},
- "social.thescore.com.": {},
- "socialchain.app.": {},
- "sockets.stackexchange.com.": {},
- "sofia.remotepc.com.": {},
- "sohu.com.": {},
- "sohucs.com.": {},
- "solid.preyproject.com.": {},
- "sonar-akl1-1.xx.fbcdn.net.": {},
- "sonar-ams2-1.xx.fbcdn.net.": {},
- "sonar-ams4-1.xx.fbcdn.net.": {},
- "sonar-arn2-1.xx.fbcdn.net.": {},
- "sonar-atl3-1.xx.fbcdn.net.": {},
- "sonar-atl3-2.xx.fbcdn.net.": {},
- "sonar-bcn1-1.xx.fbcdn.net.": {},
- "sonar-ber1-1.xx.fbcdn.net.": {},
- "sonar-bkk1-1.xx.fbcdn.net.": {},
- "sonar-bkk1-2.xx.fbcdn.net.": {},
- "sonar-bog2-1.xx.fbcdn.net.": {},
- "sonar-bog2-2.xx.fbcdn.net.": {},
- "sonar-bom1-1.xx.fbcdn.net.": {},
- "sonar-bom1-2.xx.fbcdn.net.": {},
- "sonar-bom2-1.xx.fbcdn.net.": {},
- "sonar-bom2-2.xx.fbcdn.net.": {},
- "sonar-bos5-1.xx.fbcdn.net.": {},
- "sonar-bru2-1.xx.fbcdn.net.": {},
- "sonar-ccu1-1.xx.fbcdn.net.": {},
- "sonar-ccu1-2.xx.fbcdn.net.": {},
- "sonar-cdg4-1.xx.fbcdn.net.": {},
- "sonar-cdg4-2.xx.fbcdn.net.": {},
- "sonar-cdg4-3.xx.fbcdn.net.": {},
- "sonar-cgk1-1.xx.fbcdn.net.": {},
- "sonar-cgk1-2.xx.fbcdn.net.": {},
- "sonar-cgk1-3.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-den2-1.xx.fbcdn.net.": {},
- "sonar-dfw5-1.xx.fbcdn.net.": {},
- "sonar-dfw5-2.xx.fbcdn.net.": {},
- "sonar-doh1-1.xx.fbcdn.net.": {},
- "sonar-dub4-1.xx.fbcdn.net.": {},
- "sonar-dus1-1.xx.fbcdn.net.": {},
- "sonar-eze1-1.xx.fbcdn.net.": {},
- "sonar-fco2-1.xx.fbcdn.net.": {},
- "sonar-fml1-1.xx.fbcdn.net.": {},
- "sonar-fml20-1.xx.fbcdn.net.": {},
- "sonar-for1-1.xx.fbcdn.net.": {},
- "sonar-fra3-1.xx.fbcdn.net.": {},
- "sonar-fra3-2.xx.fbcdn.net.": {},
- "sonar-fra5-1.xx.fbcdn.net.": {},
- "sonar-fra5-2.xx.fbcdn.net.": {},
- "sonar-gig4-1.xx.fbcdn.net.": {},
- "sonar-gig4-2.xx.fbcdn.net.": {},
- "sonar-gmp1-1.xx.fbcdn.net.": {},
- "sonar-gru1-1.xx.fbcdn.net.": {},
- "sonar-gru1-2.xx.fbcdn.net.": {},
- "sonar-gru2-1.xx.fbcdn.net.": {},
- "sonar-gru2-2.xx.fbcdn.net.": {},
- "sonar-gua1-1.xx.fbcdn.net.": {},
- "sonar-ham3-1.xx.fbcdn.net.": {},
- "sonar-hbe1-1.xx.fbcdn.net.": {},
- "sonar-hbe1-2.xx.fbcdn.net.": {},
- "sonar-hel3-1.xx.fbcdn.net.": {},
- "sonar-hkg1-1.xx.fbcdn.net.": {},
- "sonar-hkg1-2.xx.fbcdn.net.": {},
- "sonar-hkg4-1.xx.fbcdn.net.": {},
- "sonar-hkg4-2.xx.fbcdn.net.": {},
- "sonar-hou1-1.xx.fbcdn.net.": {},
- "sonar-hyd1-1.xx.fbcdn.net.": {},
- "sonar-iad3-1.xx.fbcdn.net.": {},
- "sonar-iad3-2.xx.fbcdn.net.": {},
- "sonar-iev1-1.xx.fbcdn.net.": {},
- "sonar-ist1-1.xx.fbcdn.net.": {},
- "sonar-itm1-1.xx.fbcdn.net.": {},
- "sonar-jnb2-1.xx.fbcdn.net.": {},
- "sonar-kul2-1.xx.fbcdn.net.": {},
- "sonar-kul2-2.xx.fbcdn.net.": {},
- "sonar-kul3-1.xx.fbcdn.net.": {},
- "sonar-lax3-1.xx.fbcdn.net.": {},
- "sonar-lax3-2.xx.fbcdn.net.": {},
- "sonar-lga3-1.xx.fbcdn.net.": {},
- "sonar-lga3-2.xx.fbcdn.net.": {},
- "sonar-lhr6-1.xx.fbcdn.net.": {},
- "sonar-lhr6-2.xx.fbcdn.net.": {},
- "sonar-lhr8-1.xx.fbcdn.net.": {},
- "sonar-lhr8-2.xx.fbcdn.net.": {},
- "sonar-lim1-1.xx.fbcdn.net.": {},
- "sonar-lis1-1.xx.fbcdn.net.": {},
- "sonar-los2-1.xx.fbcdn.net.": {},
- "sonar-maa2-1.xx.fbcdn.net.": {},
- "sonar-maa2-2.xx.fbcdn.net.": {},
- "sonar-mad1-1.xx.fbcdn.net.": {},
- "sonar-mad2-1.xx.fbcdn.net.": {},
- "sonar-man2-1.xx.fbcdn.net.": {},
- "sonar-mba1-1.xx.fbcdn.net.": {},
- "sonar-mct1-1.xx.fbcdn.net.": {},
- "sonar-mia3-1.xx.fbcdn.net.": {},
- "sonar-mia3-2.xx.fbcdn.net.": {},
- "sonar-mnl1-1.xx.fbcdn.net.": {},
- "sonar-mnl1-2.xx.fbcdn.net.": {},
- "sonar-mrs2-1.xx.fbcdn.net.": {},
- "sonar-mrs2-2.xx.fbcdn.net.": {},
- "sonar-msp1-1.xx.fbcdn.net.": {},
- "sonar-mty2-1.xx.fbcdn.net.": {},
- "sonar-muc2-1.xx.fbcdn.net.": {},
- "sonar-mxp1-1.xx.fbcdn.net.": {},
- "sonar-mxp2-1.xx.fbcdn.net.": {},
- "sonar-nrt1-1.xx.fbcdn.net.": {},
- "sonar-nrt1-2.xx.fbcdn.net.": {},
- "sonar-ord5-1.xx.fbcdn.net.": {},
- "sonar-ord5-2.xx.fbcdn.net.": {},
- "sonar-otp1-1.xx.fbcdn.net.": {},
- "sonar-pmo1-1.xx.fbcdn.net.": {},
- "sonar-pnq1-1.xx.fbcdn.net.": {},
- "sonar-pnq1-2.xx.fbcdn.net.": {},
- "sonar-prg1-1.xx.fbcdn.net.": {},
- "sonar-qro1-1.xx.fbcdn.net.": {},
- "sonar-qro1-2.xx.fbcdn.net.": {},
- "sonar-scl2-1.xx.fbcdn.net.": {},
- "sonar-sea1-1.xx.fbcdn.net.": {},
- "sonar-sin6-1.xx.fbcdn.net.": {},
- "sonar-sin6-2.xx.fbcdn.net.": {},
- "sonar-sin6-3.xx.fbcdn.net.": {},
- "sonar-sin6-4.xx.fbcdn.net.": {},
- "sonar-sjc3-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-1.xx.fbcdn.net.": {},
- "sonar-tir3-2.xx.fbcdn.net.": {},
- "sonar-tpe1-1.xx.fbcdn.net.": {},
- "sonar-vie1-1.xx.fbcdn.net.": {},
- "sonar-waw1-1.xx.fbcdn.net.": {},
- "sonar-xsp1-1.xx.fbcdn.net.": {},
- "sonar-xsp1-2.xx.fbcdn.net.": {},
- "sonar-xsp1-3.xx.fbcdn.net.": {},
- "sonar-xsp2-1.xx.fbcdn.net.": {},
- "sonar-yyz1-1.xx.fbcdn.net.": {},
- "sonar-zrh1-1.xx.fbcdn.net.": {},
- "sonar.viously.com.": {},
- "sooners-my.sharepoint.com.": {},
- "sound-ai-stream.alibaba.com.": {},
- "southcarolina.remotepc.com.": {},
- "southfront.mm.fcix.net.": {},
- "sp.replit.com.": {},
- "sparteo.com.": {},
- "spc2com-my.sharepoint.com.": {},
- "spcdn.incartupsell.com.": {},
- "spectrumhealth-my.sharepoint.com.": {},
- "spectrumhealth.sharepoint.com.": {},
- "speedtest.gcore.com.": {},
- "spiny.ai.": {},
- "spion.savvy.security.": {},
- "splash-online-decision.xiaohongshu.com.": {},
- "splash.unity.cn.": {},
- "springfieldclinic-my.sharepoint.com.": {},
- "springfieldclinic.sharepoint.com.": {},
- "src.ebay-us.com.": {},
- "srv1.maxhost.io.": {},
- "ssafp.samsclub.com.": {},
- "ssc.independent.co.uk.": {},
- "ssctech.com.": {},
- "ssimn.org.": {},
- "sso.dealersocket.com.": {},
- "sso.services.box.net.": {},
- "ssp.hbrd.io.": {},
- "ssp.hybrid.ai.": {},
- "sstatic.net.": {},
- "ssxd.mediav.com.": {},
- "st-sysupgrade.vivo.com.cn.": {},
- "staffbase.com.": {},
- "stardustgod.com.": {},
- "starfinanz.de.": {},
- "startssl.com.": {},
- "stat.mixi.media.": {},
- "stat.pdfforge.org.": {},
- "statad.ru.": {},
- "static-ams2-1.xx.fbcdn.net.": {},
- "static-ams4-1.xx.fbcdn.net.": {},
- "static-atl3-1.xx.fbcdn.net.": {},
- "static-atl3-2.xx.fbcdn.net.": {},
- "static-bos5-1.xx.fbcdn.net.": {},
- "static-den2-1.xx.fbcdn.net.": {},
- "static-dfw5-1.xx.fbcdn.net.": {},
- "static-dfw5-2.xx.fbcdn.net.": {},
- "static-hou1-1.xx.fbcdn.net.": {},
- "static-iad3-1.xx.fbcdn.net.": {},
- "static-iad3-2.xx.fbcdn.net.": {},
- "static-lax3-1.xx.fbcdn.net.": {},
- "static-lax3-2.xx.fbcdn.net.": {},
- "static-lga3-1.xx.fbcdn.net.": {},
- "static-lga3-2.xx.fbcdn.net.": {},
- "static-lhr6-1.xx.fbcdn.net.": {},
- "static-lhr6-2.xx.fbcdn.net.": {},
- "static-lhr8-1.xx.fbcdn.net.": {},
- "static-man2-1.xx.fbcdn.net.": {},
- "static-mia3-1.xx.fbcdn.net.": {},
- "static-mia3-2.xx.fbcdn.net.": {},
- "static-msp1-1.xx.fbcdn.net.": {},
- "static-ord5-1.xx.fbcdn.net.": {},
- "static-ord5-2.xx.fbcdn.net.": {},
- "static-sea1-1.xx.fbcdn.net.": {},
- "static-sjc3-1.xx.fbcdn.net.": {},
- "static-vie1-1.xx.fbcdn.net.": {},
- "static-waw1-1.xx.fbcdn.net.": {},
- "static.fastly.carvana.io.": {},
- "static.foxnews.com.edgekey.net.": {},
- "static.independent.co.uk.": {},
- "static.mixi.media.": {},
- "static.nortoncdn.com.": {},
- "static.springbuilder.site.": {},
- "static.standard.co.uk.": {},
- "static.thcdn.com.": {},
- "static.writable.com.": {},
- "static2.mixi.media.": {},
- "static4.mixi.media.": {},
- "static7.mixi.media.": {},
- "static8.mixi.media.": {},
- "statistic.live.126.net.": {},
- "stats.adinplay.com.": {},
- "stats.aeries.com.": {},
- "stats.bannernow.com.": {},
- "stats.dell.com.": {},
- "stats.mightytext.co.": {},
- "stats.norton.com.": {},
- "stats.rip.": {},
- "stats.studyquicks.com.": {},
- "stats.transitapp.com.": {},
- "statsig.anthropic.com.": {},
- "statsigapi.net.": {},
- "stblaw0-my.sharepoint.com.": {},
- "stcdn.leadconnectorhq.com.": {},
- "stcharleshealthsystem-my.sharepoint.com.": {},
- "steelseries.com.": {},
- "stemchristie.rome2rio.com.": {},
- "stericyclecorp-my.sharepoint.com.": {},
- "stg-data.ads.heytapmobi.com.": {},
- "stockholm.remotepc.com.": {},
- "stocks-analytics-events.apple.com.": {},
- "stockx-app.quantummetric.com.": {},
- "storagecraft.com.": {},
- "store-dra.hispace.dbankcloud.cn.": {},
- "store.qq.com.": {},
- "streamhub.tech.": {},
- "streetviewpixels-pa.googleapis.com.": {},
- "stse02.ultipro.com.": {},
- "stsew02.ultipro.com.": {},
- "stsn02.ultipro.com.": {},
- "student.atitesting.com.": {},
- "studentjths-my.sharepoint.com.": {},
- "studentjths.sharepoint.com.": {},
- "studentsecisd-my.sharepoint.com.": {},
- "studentsecuedu66932-my.sharepoint.com.": {},
- "studentsecuedu66932.sharepoint.com.": {},
- "studenttuhsd-my.sharepoint.com.": {},
- "studenttuhsd.sharepoint.com.": {},
- "studyquicks.com.": {},
- "stun.2talk.com.": {},
- "stun.cdnbye.com.": {},
- "stun1.ringcentral.com.": {},
- "stun2.ringcentral.com.": {},
- "subs.theepochtimes.com.": {},
- "subway-sync.quantummetric.com.": {},
- "sumari-prod-1.srv.jbisumari.org.": {},
- "sumologic.com.": {},
- "sunamerica.com.": {},
- "sunmedia.tv.": {},
- "sunmi.com.": {},
- "sunocoinc-my.sharepoint.com.": {},
- "sunocoinc.sharepoint.com.": {},
- "supl.qxwz.com.": {},
- "support.powerschool.com.": {},
- "sutterhealth-my.sharepoint.com.": {},
- "sutterhealth.sharepoint.com.": {},
- "sv8.cyberhaven.io.": {},
- "svlive.serraview.com.": {},
- "switch.babybus.com.": {},
- "sydney-sydney-bing-com.trafficmanager.net.": {},
- "sydney.bing.com.": {},
- "sydney.remotepc.com.": {},
- "sync-1-us-west1-g.sync.services.mozilla.com.": {},
- "sync.bidence.net.": {},
- "sync.inmobi.com.": {},
- "sync.lunamedia.live.": {},
- "sync.opendsp.ru.": {},
- "sync.videowalldirect.com.": {},
- "syndetics.com.": {},
- "sysdk.cl2009.com.": {},
- "systemreportservices.genetec.com.": {},
- "t-odx.op-mobile.opera.com.": {},
- "t.adcell.com.": {},
- "t.marketingcloudfx.com.": {},
- "t.mookie1.com.": {},
- "t.nit.ro.": {},
- "t.poki.io.": {},
- "t.ssl.ak.dynamic.tiles.virtualearth.net.": {},
- "t1.tiles.virtualearth.net.": {},
- "t3.xiaohongshu.com.": {},
- "tag.winister.app.": {},
- "tags.adsafety.net.": {},
- "tags.natwest.com.": {},
- "taipei.remotepc.com.": {},
- "tamersunion.org.": {},
- "tampa.remotepc.com.": {},
- "tanx.com.": {},
- "tao.barstoolsports.com.": {},
- "taobao.com.": {},
- "tapecontent.net.": {},
- "tapestry-app.quantummetric.com.": {},
- "tarrantcounty-my.sharepoint.com.": {},
- "tasteofhome.com.": {},
- "tatracker-us.rivergame.net.": {},
- "taylorfarms1com-my.sharepoint.com.": {},
- "tbcache.com.": {},
- "tccprod01.honeywell.com.": {},
- "tccprod02.honeywell.com.": {},
- "tccprod03.honeywell.com.": {},
- "tcdnlive.com.": {},
- "tclclouds.com.": {},
- "tdcservices.tandemdiabetes.com.": {},
- "tdm.qq.com.": {},
- "teachingstrategies.com.": {},
- "teams.microsoft.com.": {},
- "teams.office.com.": {},
- "teamviewer.com.": {},
- "tec-do.cn.": {},
- "teddymobile.cn.": {},
- "telaviv.remotepc.com.": {},
- "telecom.shuzilm.cn.": {},
- "telemetry-sdk-inmobi-comtm.trafficmanager.net.": {},
- "telemetry.docusign.net.": {},
- "telemetry.savvy.security.": {},
- "telemetry.sdk.inmobi.com.": {},
- "telephony.goog.": {},
- "tencent-cloud.com.": {},
- "tencent-cloud.net.": {},
- "tencent.com.": {},
- "tencentmusic.com.": {},
- "tenda.com.cn.": {},
- "tepoch.finzfin.com.": {},
- "teraswitch.com.": {},
- "terms3.hicloud.com.": {},
- "testnjjhb.com.": {},
- "text.com.": {},
- "tfl-staticscdn.trafficmanager.net.": {},
- "tgp.qq.com.": {},
- "tgpa.qq.com.": {},
- "thanhnien.vn.": {},
- "thd.mr-in.com.": {},
- "thenewsbox.net.": {},
- "theoks.net.": {},
- "thetracker.org.": {},
- "think12stg.wpengine.com.": {},
- "thinkific.com.": {},
- "thinkingdata.cn.": {},
- "thm.visa.com.": {},
- "thm12.visa.com.": {},
- "thumb-v4.xhcdn.com.": {},
- "tigermailauburn-my.sharepoint.com.": {},
- "tigermailauburn.sharepoint.com.": {},
- "tile.openstreetmap.org.": {},
- "tile.osm.org.": {},
- "time.ecansol.net.": {},
- "time.lmtlabs.com.": {},
- "time.nest.com.": {},
- "time.pool.aliyun.com.": {},
- "time.walb.tech.": {},
- "time1.aliyun.com.": {},
- "time1.google.com.": {},
- "time2.aliyun.com.": {},
- "time2.google.com.": {},
- "time3.aliyun.com.": {},
- "time3.google.com.": {},
- "time4.google.com.": {},
- "timi-esports.qq.com.": {},
- "timken-my.sharepoint.com.": {},
- "tivan.naver.com.": {},
- "tkx.mp.lura.live.": {},
- "tlivecdn.com.": {},
- "tlivesource.com.": {},
- "tls-amap.dingtalk.com.": {},
- "tls12.eu01.nr-data.net.cdn.cloudflare.net.": {},
- "tls12.newrelic.com.cdn.cloudflare.net.": {},
- "tm.barclays.co.uk.": {},
- "tm.bdc-cdn.com.": {},
- "tm.cybersource.com.": {},
- "tm.regions.com.": {},
- "tmall.com.": {},
- "tmbbank-my.sharepoint.com.": {},
- "tmbbank.sharepoint.com.": {},
- "tmc-g2.tm-4.office.com.": {},
- "tmdeviceapi.tclking.com.": {},
- "tmfp.klarna.com.": {},
- "tmga.qq.com.": {},
- "tmge.alicdn.com.": {},
- "tmobile-app.quantummetric.com.": {},
- "tmobile-sync.quantummetric.com.": {},
- "tmx.td.com.": {},
- "tmx.tdbank.com.": {},
- "tmx.uptodate.com.": {},
- "tngdigital.com.my.": {},
- "today.line.me.": {},
- "tokyo.remotepc.com.": {},
- "tollbrothersinc-my.sharepoint.com.": {},
- "tollbrothersinc.sharepoint.com.": {},
- "top-widgets-va.us-east-1.log.aliyuncs.com.": {},
- "toronto.remotepc.com.": {},
- "tos-prd-api-mgmt.azure-api.net.": {},
- "towerhealth-my.sharepoint.com.": {},
- "towerhealth.sharepoint.com.": {},
- "tplay.qq.com.": {},
- "tpns.sgp.tencent.com.": {},
- "tpns.sh.tencent.com.": {},
- "tpns.tencent.com.": {},
- "tpsservice-files-inner.cn-hangzhou.oss-cdn.aliyun-inc.com.": {},
- "tqtli1-inapps.appsflyersdk.com.": {},
- "tr-tmc-geo.office.com.": {},
- "tr.p.360.cn.": {},
- "tr1.chat.si.riotgames.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-hz-de.hyper-torrent.com.": {},
- "tra-hz-fl.hyper-torrent.com.": {},
- "tra-lwb-sg.best61.com.": {},
- "tra-s4-us.best61.com.": {},
- "tra-tc-ind.apktorrents.com.": {},
- "tra-tc-ind.best82.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.": {},
- "trace.qq.com.": {},
- "track-eu1.hubspot.com.": {},
- "track.loopme.me.": {},
- "track.sendlane.com.": {},
- "track.ultimate-guitar.com.": {},
- "tracker-udp.gbitt.info.": {},
- "tracker.4.babico.name.tr.": {},
- "tracker.best61.com.": {},
- "tracker.ccp.ovh.": {},
- "tracker.files.fm.": {},
- "tracker.grepler.com.": {},
- "tracker.hyper-torrent.com.": {},
- "tracker.moeking.me.": {},
- "tracker.nwps.ws.": {},
- "tracker.theoks.net.": {},
- "tracker1.bt.moack.co.kr.": {},
- "tracker2.dler.org.": {},
- "tracking.eu.antskre.com.": {},
- "tracking.g2crowd.com.": {},
- "tracking.ksztone.com.": {},
- "tradplusad.com.": {},
- "trafficbass.com.": {},
- "transplace-my.sharepoint.com.": {},
- "traversal.syncromsp.com.": {},
- "treas.gov.": {},
- "treasury.gov.": {},
- "treasurydirect.gov.": {},
- "tribalfusion.com.": {},
- "trovit.com.": {},
- "ts1.qq.com.": {},
- "ts2.qq.com.": {},
- "tse1.explicit.bing.net.": {},
- "tse1.mm.bing.net.": {},
- "tse2.explicit.bing.net.": {},
- "tse2.mm.bing.net.": {},
- "tse3.explicit.bing.net.": {},
- "tse3.mm.bing.net.": {},
- "tse4.explicit.bing.net.": {},
- "tse4.mm.bing.net.": {},
- "tsms-dre.security.dbankcloud.com.": {},
- "tt.browser.360.cn.": {},
- "ttcache.com.": {},
- "ttigroup-my.sharepoint.com.": {},
- "ttigroup.sharepoint.com.": {},
- "tubecup.net.": {},
- "tuhsdk12azus-my.sharepoint.com.": {},
- "tuhsdk12azus.sharepoint.com.": {},
- "tunnel.googlezip.net.": {},
- "tuoitre.vn.": {},
- "tuya.com.": {},
- "tw.ntp.org.cn.": {},
- "twcgov-my.sharepoint.com.": {},
- "twcgov.sharepoint.com.": {},
- "txdot-my.sharepoint.com.": {},
- "txdot.sharepoint.com.": {},
- "txoag-my.sharepoint.com.": {},
- "txoag.sharepoint.com.": {},
- "tyjr-fgj.aliyun.com.vipgds.alibabadns.com.": {},
- "typenetwork.com.": {},
- "u.4dex.io.": {},
- "uapi.mp.360.cn.": {},
- "uber.zoom.us.": {},
- "uc.cn.": {},
- "ucweb.com.": {},
- "ud.reasonsecurity.com.": {},
- "udemycdn.com.": {},
- "udesk.cn.": {},
- "uk-api.asm.skype.com.": {},
- "uk-prod.asyncgw.teams.microsoft.com.": {},
- "ukc-excel-collab.officeapps.live.com.": {},
- "ukg.com.": {},
- "uks.his.arc.azure.com.": {},
- "uksouth-gas.guestconfiguration.azure.com.": {},
- "ukyuh.tech.": {},
- "ulikecam.com.": {},
- "uline-app.quantummetric.com.": {},
- "ulmoyc.com.": {},
- "ulta-app.quantummetric.com.": {},
- "ulta-sync.quantummetric.com.": {},
- "ulta.quantummetric.com.": {},
- "ultipro.com.": {},
- "ultiprotime.com.": {},
- "ultiproworkplace.com.": {},
- "umainesystem-my.sharepoint.com.": {},
- "umeng.com.": {},
- "unbxd.io.": {},
- "uncw4-my.sharepoint.com.": {},
- "uncw4.sharepoint.com.": {},
- "unicom.shuzilm.cn.": {},
- "unified-inbox-1-gw.ultipro.com.": {},
- "unified-inbox-2-gw.ultipro.com.": {},
- "union.barstoolsports.com.": {},
- "union.ucweb.com.": {},
- "unipay.qq.com.": {},
- "unisoc.com.": {},
- "united.quantummetric.com.": {},
- "unity.cn.": {},
- "universityofwieauclaire-my.sharepoint.com.": {},
- "update-master.ixsystems.com.": {},
- "update.360safe.com.": {},
- "update.huorong.cn.": {},
- "update.kingsoftstore.com.": {},
- "update.norton.securebrowser.com.": {},
- "update.pdfforge.org.": {},
- "update.vivaldi.com.": {},
- "updatechannel.sharegate.com.": {},
- "updaterservices.genetec.com.": {},
- "updatesnl.macrium.com.": {},
- "upload.app.box.com.": {},
- "upload.box.com.": {},
- "upload.ent.box.com.": {},
- "upload.gifshow.com.": {},
- "upload.ksapisrv.com.": {},
- "uploads.gamecoast.net.": {},
- "upravel.com.": {},
- "upremium.asia.": {},
- "upscore.com.": {},
- "upyun.com.": {},
- "urekamedia.com.": {},
- "us-api.asm.skype.com.": {},
- "us-atl-anx-r001.router.teamviewer.com.": {},
- "us-atl-anx-r002.router.teamviewer.com.": {},
- "us-atl-anx-r003.router.teamviewer.com.": {},
- "us-atl-anx-r004.router.teamviewer.com.": {},
- "us-atl-anx-r010.router.teamviewer.com.": {},
- "us-central1-adaptive-growth.cloudfunctions.net.": {},
- "us-central1-addshoppers-data-production.cloudfunctions.net.": {},
- "us-central1-affilimate.cloudfunctions.net.": {},
- "us-central1-amp-error-reporting.cloudfunctions.net.": {},
- "us-central1-blaze-today.cloudfunctions.net.": {},
- "us-central1-blazing-fire-8445.cloudfunctions.net.": {},
- "us-central1-bps-oi-production.cloudfunctions.net.": {},
- "us-central1-buzz-3eeb8.cloudfunctions.net.": {},
- "us-central1-castify-notifications-prod.cloudfunctions.net.": {},
- "us-central1-cohinc-146020.cloudfunctions.net.": {},
- "us-central1-digitalproducts-gabbo.cloudfunctions.net.": {},
- "us-central1-ds-specials-dev.cloudfunctions.net.": {},
- "us-central1-esi-consumer.cloudfunctions.net.": {},
- "us-central1-fsgenergy-shared.cloudfunctions.net.": {},
- "us-central1-gaggle-staging.cloudfunctions.net.": {},
- "us-central1-justbuild-cdb86.cloudfunctions.net.": {},
- "us-central1-live-prod-1-1.cloudfunctions.net.": {},
- "us-central1-locket-4252a.cloudfunctions.net.": {},
- "us-central1-mikmak-microservices.cloudfunctions.net.": {},
- "us-central1-muslim-pro-app.cloudfunctions.net.": {},
- "us-central1-noteit-4dca3.cloudfunctions.net.": {},
- "us-central1-royal-match-prod-cce6d.cloudfunctions.net.": {},
- "us-central1-shopify-instrumentat-ff788286.cloudfunctions.net.": {},
- "us-central1-speechifymobile.cloudfunctions.net.": {},
- "us-central1-sq-sgtm-prod.cloudfunctions.net.": {},
- "us-central1-teach-monster.cloudfunctions.net.": {},
- "us-central1-webgltest-17af1.cloudfunctions.net.": {},
- "us-central1-wetterapp-1.cloudfunctions.net.": {},
- "us-central1-wrapper-analytics-prod.cloudfunctions.net.": {},
- "us-dal-anx-r003.router.teamviewer.com.": {},
- "us-dal-anx-r006.router.teamviewer.com.": {},
- "us-dal-anx-r008.router.teamviewer.com.": {},
- "us-dal-anx-r010.router.teamviewer.com.": {},
- "us-den-anx-r001.router.teamviewer.com.": {},
- "us-den-anx-r004.router.teamviewer.com.": {},
- "us-den-anx-r005.router.teamviewer.com.": {},
- "us-den-anx-r006.router.teamviewer.com.": {},
- "us-den-anx-r007.router.teamviewer.com.": {},
- "us-den-anx-r010.router.teamviewer.com.": {},
- "us-east-1.console.aws.amazon.com.": {},
- "us-east-1.log.aliyuncs.com.": {},
- "us-east-2.console.cname-proxy.amazon.com.": {},
- "us-east4-chkp-gcp-rnd-threat-hunt-box.cloudfunctions.net.": {},
- "us-lax-anx-r006.router.teamviewer.com.": {},
- "us-lax-anx-r014.router.teamviewer.com.": {},
- "us-mia-anx-r003.router.teamviewer.com.": {},
- "us-mia-anx-r005.router.teamviewer.com.": {},
- "us-mia-anx-r009.router.teamviewer.com.": {},
- "us-mia-anx-r010.router.teamviewer.com.": {},
- "us-mia-anx-r011.router.teamviewer.com.": {},
- "us-mia-anx-r014.router.teamviewer.com.": {},
- "us-mia-anx-r015.router.teamviewer.com.": {},
- "us-njc-anx-r001.router.teamviewer.com.": {},
- "us-njc-anx-r002.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-r007.router.teamviewer.com.": {},
- "us-njc-anx-r008.router.teamviewer.com.": {},
- "us-njc-anx-r009.router.teamviewer.com.": {},
- "us-njc-anx-r010.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-r015.router.teamviewer.com.": {},
- "us-njc-anx-r016.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-pftk-temu-com.trafficmanager.net.": {},
- "us-prod.asyncgw.teams.microsoft.com.": {},
- "us-sea-anx-r001.router.teamviewer.com.": {},
- "us-sea-anx-r002.router.teamviewer.com.": {},
- "us-sea-anx-r003.router.teamviewer.com.": {},
- "us-sea-anx-r004.router.teamviewer.com.": {},
- "us-sea-anx-r005.router.teamviewer.com.": {},
- "us-sea-anx-r006.router.teamviewer.com.": {},
- "us-sea-anx-r007.router.teamviewer.com.": {},
- "us-sea-anx-r008.router.teamviewer.com.": {},
- "us-spectrum.rcs.telephony.goog.": {},
- "us-was-anx-r001.router.teamviewer.com.": {},
- "us-was-anx-r004.router.teamviewer.com.": {},
- "us-was-anx-r005.router.teamviewer.com.": {},
- "us-was-anx-r009.router.teamviewer.com.": {},
- "us-was-anx-r012.router.teamviewer.com.": {},
- "us-was-anx-r017.router.teamviewer.com.": {},
- "us-was-anx-r020.router.teamviewer.com.": {},
- "us-west-1.log.aliyuncs.com.": {},
- "us.att.rcs.telephony.goog.": {},
- "us.evidation.com.": {},
- "us.peerhub.net.": {},
- "us.pftk.temu.com.": {},
- "us.studyquicks.com.": {},
- "us.tmobile.rcs.telephony.goog.": {},
- "us.tracfone.rcs.telephony.goog.": {},
- "us.uscc.rcs.telephony.goog.": {},
- "us.v-cdn.net.": {},
- "us.xfinity.rcs.telephony.goog.": {},
- "us01.ws-api.ringcentral.com.": {},
- "us02.ws-api.ringcentral.com.": {},
- "us02log.zoom.us.": {},
- "us02polling.zoom.us.": {},
- "us02web.zoom.us.": {},
- "us02www3.zoom.us.": {},
- "us03.ws-api.ringcentral.com.": {},
- "us04asyncim.zoom.us.": {},
- "us04web.zoom.us.": {},
- "us04www3.zoom.us.": {},
- "us05web.zoom.us.": {},
- "us05www3.zoom.us.": {},
- "us06log.zoom.us.": {},
- "us06polling.zoom.us.": {},
- "us06web.zoom.us.": {},
- "us06www3.zoom.us.": {},
- "us1.ecdn2.badoocdn.com.": {},
- "us1.ecdn2.bumbcdn.com.": {},
- "us2.rtbsystem.org.": {},
- "us20.list-manage.com.": {},
- "us3a-powerpoint-collab.officeapps.live.com.": {},
- "us4a-powerpoint-collab.officeapps.live.com.": {},
- "us4b-excel-collab.officeapps.live.com.": {},
- "us4b-powerpoint-collab.officeapps.live.com.": {},
- "us8-excel-collab.officeapps.live.com.": {},
- "usbank.quantummetric.com.": {},
- "usc-excel-collab.officeapps.live.com.": {},
- "usc-powerpoint-collab.officeapps.live.com.": {},
- "usc-word-collab.officeapps.live.com.": {},
- "user.auth.xboxlive.com.": {},
- "userexperience.thehut.net.": {},
- "userflow.com.": {},
- "userlike.com.": {},
- "usgcorp-my.sharepoint.com.": {},
- "usgcorp.sharepoint.com.": {},
- "usgs.gov.": {},
- "usii-my.sharepoint.com.": {},
- "usii.sharepoint.com.": {},
- "uslbm-my.sharepoint.com.": {},
- "ussav.cynet.com.": {},
- "usslb.cynet.com.": {},
- "uswest-beacon.deepintent.com.": {},
- "uu.qq.com.": {},
- "uuidksinc.net.": {},
- "uvermont.mm.fcix.net.": {},
- "uvu365-my.sharepoint.com.": {},
- "uxfeedback.ru.": {},
- "uyunad.com.": {},
- "v.streaming.qq.com.": {},
- "v.vivintsky.com.": {},
- "v16-img.djvod.ndcimgs.com.": {},
- "v2-zj-shxcm.kwaicdn.com.": {},
- "v34.tiktokcdn.com.": {},
- "v39-as.tiktokcdn.com.": {},
- "v39-ca.tiktokcdn.com.": {},
- "v39-id.gts.byteoversea.net.": {},
- "v39-id.tiktokcdn.com.": {},
- "v39-my.gts.byteoversea.net.": {},
- "v39-row.gts.byteoversea.net.": {},
- "v39-row.tiktokcdn.com.": {},
- "v39-us.gts.byteoversea.net.": {},
- "v39-us.tiktokcdn.com.": {},
- "v39-vn-vnpt.tiktokcdn.com.": {},
- "v39.byteicdn.com.": {},
- "v45-ph-globe.tiktokcdn.com.": {},
- "v6-gdvod.kwaicdn.com.": {},
- "v8.analytics.pinsightmedia.com.": {},
- "v8engine.pinsightmedia.com.": {},
- "vadesecure.com.": {},
- "vador.com.": {},
- "vancitycu-my.sharepoint.com.": {},
- "vancitycu.sharepoint.com.": {},
- "varify.io.": {},
- "vast.playmatic.video.": {},
- "vb17123filippaaniketos.pw.": {},
- "vb24131crasosnemesis.com.": {},
- "vbw.vivoglobal.com.": {},
- "vconf.f.360.cn.": {},
- "verifone365-my.sharepoint.com.": {},
- "verifypass.com.": {},
- "verticals.wix.com.": {},
- "veteransunited-my.sharepoint.com.": {},
- "veteransunited.sharepoint.com.": {},
- "vexgateway.fastly.carvana.io.": {},
- "vfa.hpplay.cn.": {},
- "vgorigin.hakunaymatata.com.": {},
- "vhq.verifone.com.": {},
- "viadcorp-my.sharepoint.com.": {},
- "viadcorp.sharepoint.com.": {},
- "vibe.co.": {},
- "vibeaconstr.onezapp.com.": {},
- "vicoo.tech.": {},
- "video-atl3-1.xx.fbcdn.net.": {},
- "video-atl3-2.xx.fbcdn.net.": {},
- "video-bos5-1.xx.fbcdn.net.": {},
- "video-den2-1.xx.fbcdn.net.": {},
- "video-dfw5-1.xx.fbcdn.net.": {},
- "video-dfw5-2.xx.fbcdn.net.": {},
- "video-hou1-1.xx.fbcdn.net.": {},
- "video-iad3-1.xx.fbcdn.net.": {},
- "video-iad3-2.xx.fbcdn.net.": {},
- "video-lax3-1.xx.fbcdn.net.": {},
- "video-lax3-2.xx.fbcdn.net.": {},
- "video-lga3-1.xx.fbcdn.net.": {},
- "video-lga3-2.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-msp1-1.xx.fbcdn.net.": {},
- "video-ord5-1.xx.fbcdn.net.": {},
- "video-ord5-2.xx.fbcdn.net.": {},
- "video-sea1-1.xx.fbcdn.net.": {},
- "video-sjc3-1.xx.fbcdn.net.": {},
- "video.dailymail.co.uk.": {},
- "videocloud.cn-hangzhou.log.aliyuncs.com.": {},
- "videocontent-dra.himovie.dbankcloud.com.": {},
- "videoeditor-api-dra.cloud.huawei.com.": {},
- "videoqoe-fastly.stvidtest.net.": {},
- "videowalldirect.com.": {},
- "vidmate.net.": {},
- "vieon.vn.": {},
- "view2fa.prosourcehosted.com.": {},
- "vik-ca.moonactive.net.": {},
- "viously.com.": {},
- "vip-chinanet.ynuf.aliapp.org.": {},
- "vipads.live.": {},
- "virusinfo-cloudscan-cn.heytapmobi.com.": {},
- "visainc-my.sharepoint.com.": {},
- "visainc.sharepoint.com.": {},
- "visionserviceplan-my.sharepoint.com.": {},
- "visionserviceplan.sharepoint.com.": {},
- "visitor.fiftyt.com.": {},
- "visitors.live.": {},
- "vitalant-my.sharepoint.com.": {},
- "vividseats.com.": {},
- "vivoglobal.com.": {},
- "vms-videos.minutemediaservices.com.": {},
- "vn-viettel.rcs.telephony.goog.": {},
- "vn.pool.ntp.org.": {},
- "vod.ngb.haplat.net.": {},
- "vod3.ngb.haplat.net.": {},
- "vod5.ngb.haplat.net.": {},
- "voe.sx.": {},
- "voice.gcloudcs.com.": {},
- "voice.telephony.goog.": {},
- "volusiastudents-my.sharepoint.com.": {},
- "volusiastudents.sharepoint.com.": {},
- "vour.io.": {},
- "vpn.cshealthforlife.com.": {},
- "vpn.garypools.com.": {},
- "vpp-license-proxy.aliyuncs.com.": {},
- "vzuu.com.": {},
- "w.deepl.com.": {},
- "w24.cf.2ksports.com.": {},
- "w3.mp.lura.live.": {},
- "wallet.omiapp.me.": {},
- "walletconnect.com.": {},
- "walmart.quantummetric.com.": {},
- "walshgroup-my.sharepoint.com.": {},
- "wap.cmpassport.com.": {},
- "warsaw.remotepc.com.": {},
- "washoeschools-my.sharepoint.com.": {},
- "washoeschools.sharepoint.com.": {},
- "waynek12inus-my.sharepoint.com.": {},
- "wbte.drcedirect.com.": {},
- "wcpss-my.sharepoint.com.": {},
- "wcpss.sharepoint.com.": {},
- "wcsdpaorg-my.sharepoint.com.": {},
- "wct-2.com.": {},
- "weather-analytics-events.apple.com.": {},
- "weather-server-sg.allawnos.com.": {},
- "weather-server.allawntech.com.": {},
- "weather-widget-events.apple.com.": {},
- "weather.swishapps.ai.": {},
- "weathercn.com.": {},
- "weatheroffer.com.": {},
- "web-extract.constantcontact.com.": {},
- "web-g.kontiki.com.": {},
- "web.archive.org.": {},
- "web.fe.1drv.com.": {},
- "web.pypestream.com.": {},
- "web.voice.telephony.goog.": {},
- "web.wg1.kontiki.com.": {},
- "web1.remotepc.com.": {},
- "web3.drfirst.com.": {},
- "webapi.teamviewer.com.": {},
- "webapp.src.discover.com.": {},
- "webcast22-ws-alisg.tiktokv.com.": {},
- "webmd.com.": {},
- "weborama-tech.ru.": {},
- "webql-redesign.cnbcfm.com.": {},
- "webrad.io.": {},
- "websocket-01.app.pdq.com.": {},
- "websocket-04.app.pdq.com.": {},
- "wechatos.net.": {},
- "weibocdn.com.": {},
- "welcome.ultipro.com.": {},
- "wellspan-my.sharepoint.com.": {},
- "wellspan.sharepoint.com.": {},
- "wemuslim.com.": {},
- "wesingapp.com.": {},
- "westerngovernorsuniversity-my.sharepoint.com.": {},
- "westpalm.remotepc.com.": {},
- "westrockco-my.sharepoint.com.": {},
- "westrockco.sharepoint.com.": {},
- "wetype.weixin.qq.com.": {},
- "weu.his.arc.azure.com.": {},
- "wewjyw.qb6ges.com.": {},
- "wf-proxy-01.algolia.com.": {},
- "wf-proxy-02.algolia.com.": {},
- "wf-proxy-03.algolia.com.": {},
- "whitingturner-my.sharepoint.com.": {},
- "whitingturner.sharepoint.com.": {},
- "whizzco.com.": {},
- "wida-insight.drcedirect.com.": {},
- "widgets.leadconnectorhq.com.": {},
- "widgets.sociablekit.com.": {},
- "wifispot.io.": {},
- "wildcard.cdn.optimizely.com.edgekey.net.": {},
- "wildcard.dayforcehcm.com.edgekey.net.": {},
- "wildcard.ntv.io.edgekey.net.": {},
- "williamssonomainc-app.quantummetric.com.": {},
- "winscp.net.": {},
- "wizzair.com.": {},
- "wkhpe.com.": {},
- "wl.hpyrdr.com.": {},
- "wlgore-my.sharepoint.com.": {},
- "wlgore.sharepoint.com.": {},
- "word-collab.officeapps.live.com.": {},
- "workdaycdn.com.cn.": {},
- "worldnic.com.": {},
- "worldtimeserver.com.": {},
- "worldwideexpress2323-my.sharepoint.com.": {},
- "wosign.com.": {},
- "wp.safe.360.cn.": {},
- "wpcmdat.itsupport247.net.": {},
- "wpk-auth.ucweb.com.": {},
- "wpp.net.": {},
- "wpp.okta.com.": {},
- "wr.moyoung.com.": {},
- "wr.pvp.net.": {},
- "ws.gleap.io.": {},
- "ws.mybib.com.": {},
- "ws.tildacdn.com.": {},
- "ws1seg.rwjbh.org.": {},
- "wsfcsk12nc-my.sharepoint.com.": {},
- "wsfsbank-my.sharepoint.com.": {},
- "wsfsbank.sharepoint.com.": {},
- "wsms.haplat.net.": {},
- "wsoversea.com.": {},
- "wtpsnj-my.sharepoint.com.": {},
- "wtsparadigm.com.": {},
- "wtzw.com.": {},
- "wus2.his.arc.azure.com.": {},
- "wwt-my.sharepoint.com.": {},
- "wwt.sharepoint.com.": {},
- "www.2tx.com.": {},
- "www.aigconnect.aig.": {},
- "www.atitesting.com.": {},
- "www.automizely-analytics.com.": {},
- "www.bbc.co.uk.": {},
- "www.bbc.co.uk.pri.bbc.co.uk.": {},
- "www.bbc.com.": {},
- "www.bbc.com.pri.bbc.com.": {},
- "www.bbthat.com.": {},
- "www.bleepingcomputer.com.": {},
- "www.box.com.": {},
- "www.breitbart.com.": {},
- "www.bridge2bwb.com.": {},
- "www.calottery.com.": {},
- "www.cdn.viber.com.": {},
- "www.clearblue.com.": {},
- "www.cmpassport.com.": {},
- "www.dickssportinggoods.com.": {},
- "www.docusign.com.": {},
- "www.drugs.com.": {},
- "www.emjcd.com.": {},
- "www.esosuite.net.": {},
- "www.etsy.com.": {},
- "www.expedia.com.": {},
- "www.futbin.org.": {},
- "www.gbnews.com.": {},
- "www.gmc.com.": {},
- "www.google.org.": {},
- "www.handmadewithjoann.com.": {},
- "www.in.gov.": {},
- "www.independent.co.uk.": {},
- "www.inoreader.com.": {},
- "www.internetdownloadmanager.com.": {},
- "www.iorad.com.": {},
- "www.jimmyjohns.com.": {},
- "www.libertymutual.com.": {},
- "www.maintenanceconnection.com.": {},
- "www.mobileiron.com.": {},
- "www.nationalreview.com.": {},
- "www.nativecos.com.": {},
- "www.nba.com.": {},
- "www.nzz.ch.": {},
- "www.officedepot.com.": {},
- "www.overleaf.com.": {},
- "www.pingler.com.": {},
- "www.pnc.com.": {},
- "www.pool.ntp.org.": {},
- "www.rawstory.com.": {},
- "www.regions.com.": {},
- "www.scholastic.com.": {},
- "www.sciencedirect.com.": {},
- "www.searchanise.com.": {},
- "www.sevenrooms.com.": {},
- "www.startribune.com.": {},
- "www.startssl.com.": {},
- "www.users.storage.live.com.": {},
- "www.vipads.live.": {},
- "www.virustotal.com.": {},
- "www.wifispot.io.": {},
- "www.wix.com.": {},
- "www.worldtimeserver.com.": {},
- "www.zoom.us.": {},
- "www1.remotepc.com.": {},
- "www2.deepl.com.": {},
- "www3.zoom.us.": {},
- "wx.huion.cn.": {},
- "wxqcloud.qq.com.": {},
- "wxqcloud.qq.com.cn.": {},
- "wyze.com.": {},
- "x-flow.app.": {},
- "x.netease.com.": {},
- "x.research.qq.com.": {},
- "xfs-s108.xfsbb.com.": {},
- "xfs-s118.xfsbb.com.": {},
- "xfs-s127.xfsbb.com.": {},
- "xhcdn.com.": {},
- "xiaoyi-css-us-15d.oss-us-west-1.aliyuncs.com.": {},
- "xiaoyi-css-us-7d.oss-us-west-1.aliyuncs.com.": {},
- "xiaoyi.com.": {},
- "xintaicz.cn.": {},
- "xjp-msgacs.m.taobao.com.": {},
- "xmcsrv.net.": {},
- "xml-eu-v4.ezmob.com.": {},
- "xml-v4.ezmob.com.": {},
- "xml-v4.rtxfeed.com.": {},
- "xml.acertb.com.": {},
- "xml.blue-biddingz.org.": {},
- "xml.ezmob.com.": {},
- "xml.popmonetizer.net.": {},
- "xml.xmlking.com.": {},
- "xml.zeusadx.com.": {},
- "xp002.itsupport247.net.": {},
- "xp004.itsupport247.net.": {},
- "xp005.itsupport247.net.": {},
- "xp006.itsupport247.net.": {},
- "xp007.itsupport247.net.": {},
- "xp008.itsupport247.net.": {},
- "xp009.itsupport247.net.": {},
- "xp015.itsupport247.net.": {},
- "xp016.itsupport247.net.": {},
- "xp017.itsupport247.net.": {},
- "xp018.itsupport247.net.": {},
- "xp019.itsupport247.net.": {},
- "xpdrwp.itsupport247.net.": {},
- "xtom.com.": {},
- "yealink.com.": {},
- "yeezy.com.": {},
- "ymmobi.com.": {},
- "ynuf.aliapp.org.": {},
- "ynuf.aliapp.org.gds.alibabadns.com.": {},
- "yomedia.vn.": {},
- "yomeno.xyz.": {},
- "youngjoygame.com.": {},
- "yp.cdnstream1.com.": {},
- "ys7.com.": {},
- "yunxindns.com.": {},
- "yunxinfw.com.": {},
- "z-m-scontent-lis1-1.xx.fbcdn.net.": {},
- "z.cdn.adpool.bet.": {},
- "z.cdn.ftd.agency.": {},
- "z.cdn.trafficbass.com.": {},
- "zego.im.": {},
- "zemanta.com.": {},
- "zeotap.com.": {},
- "zhaohf.com.": {},
- "zigpoll.com.": {},
- "zimgs.cn.": {},
- "ziply.mm.fcix.net.": {},
- "zjcdn.com.yangyi19.com.": {},
- "zmedia.vn.": {},
- "zoom.us.": {},
- "ztoken.uyunad.com.": {},
- "zui.com.": {},
- "zurich.remotepc.com.": {},
- "zybooks.com.": {},
-}
+var FakeECSFQDNs = container.NewMapSet(
+ "01.cofile.net.",
+ "011b2ef417d541e4b4a0753f94353476.pacloudflare.com.",
+ "02.cofile.net.",
+ "0272ac85-5199-4024-a555-397c3d825d95.prmutv.co.",
+ "03.cofile.net.",
+ "04.cofile.net.",
+ "05.cofile.net.",
+ "06.cofile.net.",
+ "07.cofile.net.",
+ "08.cofile.net.",
+ "09.cofile.net.",
+ "0b732edd-087f-4c27-b0f6-5ff26d96cdf6.prmutv.co.",
+ "0cf.io.",
+ "0cf17917-395b-4f25-91cc-db3bdd6044b0.prmutv.co.",
+ "1.eu.dl.wireshark.org.",
+ "10.cofile.net.",
+ "103.chtsite.com.",
+ "10m.com.cn.",
+ "11-alarm-mop.meshare.com.",
+ "11.cofile.net.",
+ "12-alarm-mop.meshare.com.",
+ "12.cofile.net.",
+ "126.com.",
+ "126.net.",
+ "13-alarm-mop.meshare.com.",
+ "13.cofile.net.",
+ "14-alarm-mop.meshare.com.",
+ "14.cofile.net.",
+ "15.cofile.net.",
+ "16.cofile.net.",
+ "163jiasu.com.",
+ "163yun.com.",
+ "1688.com.",
+ "17.cofile.net.",
+ "18.cofile.net.",
+ "18ea70d2d9a945cfb97d818ba71817dc.pacloudflare.com.",
+ "19.cofile.net.",
+ "192667-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
+ "192991-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
+ "193119-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
+ "193259-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
+ "193522-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
+ "193565-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
+ "193592-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
+ "1941-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.",
+ "1weather.onelouder.com.",
+ "2.401402081.west-gcloud.codm.activision.com.",
+ "2.realtime.services.box.net.",
+ "20.cofile.net.",
+ "201205igp.gameloft.com.",
+ "2345.cc.",
+ "2acdb9b66bb242618283aadb21ede6c1.pacloudflare.com.",
+ "2e4b93d1-a8ae-4a89-8885-6109135ac0de.prmutv.co.",
+ "360.cn.",
+ "360os.com.",
+ "360safe.com.",
+ "3a6b0682-f3e1-4576-a706-5eb4101b9cc3.prmutv.co.",
+ "3aba5292-ba75-422b-8715-bd21146f7836.prmutv.co.",
+ "3d2fb0bd-52fc-4b75-aaf5-2d436c172540.prmutv.co.",
+ "4.401402081.west-gcloud.codm.activision.com.",
+ "4.adsco.re.",
+ "401402081.west-gcloud.codm.activision.com.",
+ "46a2e5c3c5a64e218b60f2c2ee76b750.pacloudflare.com.",
+ "507b28fb-2ef1-4c34-8bda-ba32030bb199.prmutv.co.",
+ "520.jp.",
+ "55a-8ballpool-mobile-live.pool.miniclippt.com.",
+ "5d79bce7-5d2b-427e-a6c4-b89b6c7bf048.prmutv.co.",
+ "6.401402081.west-gcloud.codm.activision.com.",
+ "6093eccf-6734-4877-ac8b-83d6d0e27b46.prmutv.co.",
+ "68547f8f-2fd8-4ff3-9b63-51e86e2edee8.prmutv.co.",
+ "6c3e19e3-d05e-45d1-8f79-fcd6cb2f3a21.prmutv.co.",
+ "6wrwmh247h-1.algolianet.com.",
+ "6wrwmh247h-2.algolianet.com.",
+ "6wrwmh247h-3.algolianet.com.",
+ "733868e706dd40d3a4a0588fc39b3df8.pacloudflare.com.",
+ "789-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.",
+ "7c7b02d4bc3d48dd81a7c7738d4de1ab.pacloudflare.com.",
+ "8686c.com.",
+ "88a66e5c-8fe8-48af-9c6c-3ec3f4983aad.prmutv.co.",
+ "8fd3136c-39ae-4836-adeb-ea2f0db46980.prmutv.co.",
+ "8x8.com.cdn.cloudflare.net.",
+ "9pumbooc7hqedhjmeavbpmp5ik9u0ngr-data.customer.pendo.io.",
+ "a-api.anthropic.com.",
+ "a-cdn.anthropic.com.",
+ "a-m-p.xyz.",
+ "a.fc.namequery.com.",
+ "a.getepic.com.",
+ "a.nel.cloudflare.com.",
+ "a.nitropay.com.",
+ "a.tile.openstreetmap.org.",
+ "a.tile.osm.org.",
+ "a010.casalemedia.com.",
+ "a011.casalemedia.com.",
+ "a012.casalemedia.com.",
+ "a013.casalemedia.com.",
+ "a015.casalemedia.com.",
+ "a016.casalemedia.com.",
+ "a017.casalemedia.com.",
+ "a018.casalemedia.com.",
+ "a019.casalemedia.com.",
+ "a020.casalemedia.com.",
+ "a021.casalemedia.com.",
+ "a022.casalemedia.com.",
+ "a023.casalemedia.com.",
+ "a024.casalemedia.com.",
+ "a025.casalemedia.com.",
+ "a026.casalemedia.com.",
+ "a027.casalemedia.com.",
+ "a028.casalemedia.com.",
+ "a029.casalemedia.com.",
+ "a030.casalemedia.com.",
+ "a031.casalemedia.com.",
+ "a032.casalemedia.com.",
+ "a033.casalemedia.com.",
+ "a034.casalemedia.com.",
+ "a035.casalemedia.com.",
+ "a036.casalemedia.com.",
+ "a037.casalemedia.com.",
+ "a038.casalemedia.com.",
+ "a040.casalemedia.com.",
+ "a041.casalemedia.com.",
+ "a042.casalemedia.com.",
+ "a043.casalemedia.com.",
+ "a044.casalemedia.com.",
+ "a045.casalemedia.com.",
+ "a046.casalemedia.com.",
+ "a050.casalemedia.com.",
+ "a054.casalemedia.com.",
+ "a058.casalemedia.com.",
+ "a074.casalemedia.com.",
+ "a075.casalemedia.com.",
+ "a088.casalemedia.com.",
+ "a091.casalemedia.com.",
+ "a095.casalemedia.com.",
+ "a096.casalemedia.com.",
+ "a097.casalemedia.com.",
+ "a098.casalemedia.com.",
+ "a099.casalemedia.com.",
+ "a101.casalemedia.com.",
+ "a119.casalemedia.com.",
+ "a121.casalemedia.com.",
+ "a123.casalemedia.com.",
+ "a124.casalemedia.com.",
+ "a126.casalemedia.com.",
+ "a127.casalemedia.com.",
+ "a128.casalemedia.com.",
+ "a129.casalemedia.com.",
+ "a131.casalemedia.com.",
+ "a132.casalemedia.com.",
+ "a134.casalemedia.com.",
+ "a136.casalemedia.com.",
+ "a137.casalemedia.com.",
+ "a138.casalemedia.com.",
+ "a140.casalemedia.com.",
+ "a141.casalemedia.com.",
+ "a143.casalemedia.com.",
+ "a144.casalemedia.com.",
+ "a145.casalemedia.com.",
+ "a146.casalemedia.com.",
+ "a147.casalemedia.com.",
+ "a149.casalemedia.com.",
+ "a150.casalemedia.com.",
+ "a151.casalemedia.com.",
+ "a152.casalemedia.com.",
+ "a153.casalemedia.com.",
+ "a156.casalemedia.com.",
+ "a157.casalemedia.com.",
+ "a158.casalemedia.com.",
+ "a159.casalemedia.com.",
+ "a160.casalemedia.com.",
+ "a166.casalemedia.com.",
+ "a169.casalemedia.com.",
+ "a170.casalemedia.com.",
+ "a172.casalemedia.com.",
+ "a178.casalemedia.com.",
+ "a179.casalemedia.com.",
+ "a182.casalemedia.com.",
+ "a187.casalemedia.com.",
+ "a188.casalemedia.com.",
+ "a190.casalemedia.com.",
+ "a195.casalemedia.com.",
+ "a200.casalemedia.com.",
+ "a2001.casalemedia.com.",
+ "a2002.casalemedia.com.",
+ "a2003.casalemedia.com.",
+ "a2004.casalemedia.com.",
+ "a2005.casalemedia.com.",
+ "a2006.casalemedia.com.",
+ "a2007.casalemedia.com.",
+ "a2008.casalemedia.com.",
+ "a2009.casalemedia.com.",
+ "a201.casalemedia.com.",
+ "a2010.casalemedia.com.",
+ "a2011.casalemedia.com.",
+ "a2012.casalemedia.com.",
+ "a2013.casalemedia.com.",
+ "a2014.casalemedia.com.",
+ "a2015.casalemedia.com.",
+ "a2016.casalemedia.com.",
+ "a2017.casalemedia.com.",
+ "a2018.casalemedia.com.",
+ "a2019.casalemedia.com.",
+ "a2020.casalemedia.com.",
+ "a2021.casalemedia.com.",
+ "a2022.casalemedia.com.",
+ "a2023.casalemedia.com.",
+ "a2024.casalemedia.com.",
+ "a2025.casalemedia.com.",
+ "a2026.casalemedia.com.",
+ "a2027.casalemedia.com.",
+ "a2028.casalemedia.com.",
+ "a2029.casalemedia.com.",
+ "a2030.casalemedia.com.",
+ "a2031.casalemedia.com.",
+ "a2032.casalemedia.com.",
+ "a2034.casalemedia.com.",
+ "a2035.casalemedia.com.",
+ "a2036.casalemedia.com.",
+ "a2037.casalemedia.com.",
+ "a2038.casalemedia.com.",
+ "a2039.casalemedia.com.",
+ "a2041.casalemedia.com.",
+ "a2042.casalemedia.com.",
+ "a2043.casalemedia.com.",
+ "a2044.casalemedia.com.",
+ "a2045.casalemedia.com.",
+ "a2046.casalemedia.com.",
+ "a2048.casalemedia.com.",
+ "a2049.casalemedia.com.",
+ "a2050.casalemedia.com.",
+ "a2051.casalemedia.com.",
+ "a2052.casalemedia.com.",
+ "a2053.casalemedia.com.",
+ "a2054.casalemedia.com.",
+ "a2055.casalemedia.com.",
+ "a2056.casalemedia.com.",
+ "a2057.casalemedia.com.",
+ "a2058.casalemedia.com.",
+ "a2059.casalemedia.com.",
+ "a2060.casalemedia.com.",
+ "a2561.casalemedia.com.",
+ "a2562.casalemedia.com.",
+ "a2563.casalemedia.com.",
+ "a2564.casalemedia.com.",
+ "a2565.casalemedia.com.",
+ "a2566.casalemedia.com.",
+ "a2567.casalemedia.com.",
+ "a2568.casalemedia.com.",
+ "a2569.casalemedia.com.",
+ "a2570.casalemedia.com.",
+ "a2571.casalemedia.com.",
+ "a2573.casalemedia.com.",
+ "a2574.casalemedia.com.",
+ "a2575.casalemedia.com.",
+ "a2576.casalemedia.com.",
+ "a2577.casalemedia.com.",
+ "a2578.casalemedia.com.",
+ "a2579.casalemedia.com.",
+ "a2580.casalemedia.com.",
+ "a2581.casalemedia.com.",
+ "a2582.casalemedia.com.",
+ "a2583.casalemedia.com.",
+ "a2584.casalemedia.com.",
+ "a2585.casalemedia.com.",
+ "a2586.casalemedia.com.",
+ "a2588.casalemedia.com.",
+ "a2589.casalemedia.com.",
+ "a2590.casalemedia.com.",
+ "a2591.casalemedia.com.",
+ "a2592.casalemedia.com.",
+ "a2593.casalemedia.com.",
+ "a2594.casalemedia.com.",
+ "a2595.casalemedia.com.",
+ "a2596.casalemedia.com.",
+ "a2597.casalemedia.com.",
+ "a2598.casalemedia.com.",
+ "a2599.casalemedia.com.",
+ "a2600.casalemedia.com.",
+ "a2601.casalemedia.com.",
+ "a2602.casalemedia.com.",
+ "a2603.casalemedia.com.",
+ "a2604.casalemedia.com.",
+ "a2605.casalemedia.com.",
+ "a2606.casalemedia.com.",
+ "a2607.casalemedia.com.",
+ "a2608.casalemedia.com.",
+ "a2610.casalemedia.com.",
+ "a2611.casalemedia.com.",
+ "a2612.casalemedia.com.",
+ "a2613.casalemedia.com.",
+ "a2614.casalemedia.com.",
+ "a2615.casalemedia.com.",
+ "a2616.casalemedia.com.",
+ "a2617.casalemedia.com.",
+ "a2618.casalemedia.com.",
+ "a2619.casalemedia.com.",
+ "a2620.casalemedia.com.",
+ "a2621.casalemedia.com.",
+ "a2622.casalemedia.com.",
+ "a2624.casalemedia.com.",
+ "a2625.casalemedia.com.",
+ "a2626.casalemedia.com.",
+ "a2629.casalemedia.com.",
+ "a2630.casalemedia.com.",
+ "a2631.casalemedia.com.",
+ "a2632.casalemedia.com.",
+ "a2633.casalemedia.com.",
+ "a2634.casalemedia.com.",
+ "a2635.casalemedia.com.",
+ "a2636.casalemedia.com.",
+ "a2637.casalemedia.com.",
+ "a2639.casalemedia.com.",
+ "a2640.casalemedia.com.",
+ "a2641.casalemedia.com.",
+ "a2642.casalemedia.com.",
+ "a2643.casalemedia.com.",
+ "a2644.casalemedia.com.",
+ "a2645.casalemedia.com.",
+ "a2646.casalemedia.com.",
+ "a2647.casalemedia.com.",
+ "a2648.casalemedia.com.",
+ "a2649.casalemedia.com.",
+ "a2650.casalemedia.com.",
+ "a2a5c7f9-3fa0-4182-889a-15aa61acf59b.prmutv.co.",
+ "a3.tuyacn.com.",
+ "a461.casalemedia.com.",
+ "a462.casalemedia.com.",
+ "a463.casalemedia.com.",
+ "a464.casalemedia.com.",
+ "a465.casalemedia.com.",
+ "a466.casalemedia.com.",
+ "a467.casalemedia.com.",
+ "a468.casalemedia.com.",
+ "a469.casalemedia.com.",
+ "a470.casalemedia.com.",
+ "a471.casalemedia.com.",
+ "a473.casalemedia.com.",
+ "a475.casalemedia.com.",
+ "a476.casalemedia.com.",
+ "a477.casalemedia.com.",
+ "a479.casalemedia.com.",
+ "a480.casalemedia.com.",
+ "a5555.casalemedia.com.",
+ "a5557.casalemedia.com.",
+ "a5558.casalemedia.com.",
+ "a5559.casalemedia.com.",
+ "a5561.casalemedia.com.",
+ "a5562.casalemedia.com.",
+ "a5563.casalemedia.com.",
+ "a5564.casalemedia.com.",
+ "a5565.casalemedia.com.",
+ "a5566.casalemedia.com.",
+ "a5567.casalemedia.com.",
+ "a5568.casalemedia.com.",
+ "a5569.casalemedia.com.",
+ "a5570.casalemedia.com.",
+ "a5571.casalemedia.com.",
+ "a5572.casalemedia.com.",
+ "a5573.casalemedia.com.",
+ "a5574.casalemedia.com.",
+ "a5576.casalemedia.com.",
+ "a5577.casalemedia.com.",
+ "a5578.casalemedia.com.",
+ "a5579.casalemedia.com.",
+ "a5580.casalemedia.com.",
+ "a5581.casalemedia.com.",
+ "a5582.casalemedia.com.",
+ "a5583.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.",
+ "a5592.casalemedia.com.",
+ "a5593.casalemedia.com.",
+ "a5594.casalemedia.com.",
+ "a5595.casalemedia.com.",
+ "a5596.casalemedia.com.",
+ "a5597.casalemedia.com.",
+ "a5598.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.",
+ "a5620.casalemedia.com.",
+ "a5621.casalemedia.com.",
+ "a5622.casalemedia.com.",
+ "a5623.casalemedia.com.",
+ "a5624.casalemedia.com.",
+ "a5625.casalemedia.com.",
+ "a5626.casalemedia.com.",
+ "a5627.casalemedia.com.",
+ "a5628.casalemedia.com.",
+ "a5629.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.",
+ "a5641.casalemedia.com.",
+ "a5642.casalemedia.com.",
+ "a5644.casalemedia.com.",
+ "a5646.casalemedia.com.",
+ "a5647.casalemedia.com.",
+ "a5648.casalemedia.com.",
+ "a5649.casalemedia.com.",
+ "a5650.casalemedia.com.",
+ "a5651.casalemedia.com.",
+ "a5652.casalemedia.com.",
+ "a5653.casalemedia.com.",
+ "a5654.casalemedia.com.",
+ "a5655.casalemedia.com.",
+ "a5656.casalemedia.com.",
+ "a5657.casalemedia.com.",
+ "a5658.casalemedia.com.",
+ "a5659.casalemedia.com.",
+ "a5660.casalemedia.com.",
+ "a5661.casalemedia.com.",
+ "a5662.casalemedia.com.",
+ "a5663.casalemedia.com.",
+ "a5664.casalemedia.com.",
+ "a5665.casalemedia.com.",
+ "a5667.casalemedia.com.",
+ "a5668.casalemedia.com.",
+ "a5669.casalemedia.com.",
+ "a57.foxsports.com.",
+ "a9695278-4085-40b3-9f02-8d4c38a6ff01.prmutv.co.",
+ "aa-sync.quantummetric.com.",
+ "aa.online-metrix.net.",
+ "aa.quantummetric.com.",
+ "aaid.uyunad.com.",
+ "ab.qq.com.",
+ "aba2c424-419a-4d03-9aed-2dca8a7139e4.prmutv.co.",
+ "abcsinsights.com.",
+ "abmmscloud-my.sharepoint.com.",
+ "abmmscloud.sharepoint.com.",
+ "abqix.mm.fcix.net.",
+ "abroad.apilocate.amap.com.",
+ "abtest-aws-us-east-01.saas.sensorsdata.com.",
+ "accela.com.",
+ "accentuate.io.",
+ "access.creditonebank.com.",
+ "access.mp.lura.live.",
+ "account.bbc.com.",
+ "account.box.com.",
+ "accountapi.agoda.com.",
+ "accscdn4public.m.taobao.com.",
+ "accurint.com.",
+ "acdn.tinkoff.ru.",
+ "acgvideo.com.",
+ "achi.faceit.com.",
+ "acm.org.",
+ "acme-v02.api.letsencrypt.org.",
+ "acrobits.cz.",
+ "acs4public.m.taobao.com.",
+ "activate.academy.com.",
+ "activation.cloud.techsmith.com.",
+ "ad.tagtoo.co.",
+ "adapex.io.",
+ "adash-emas.cn-hangzhou.aliyuncs.com.",
+ "adash.man.aliyuncs.com.",
+ "adashx.m.taobao.com.",
+ "adashx.m.taobao.com.w.kunlunhuf.com.",
+ "adashx.ut.alibaba.com.",
+ "adashx.ut.amap.com.",
+ "adashx.ut.dingtalk.com.",
+ "adcell.com.",
+ "adi-sin-c-4.cico.com.",
+ "aditude.io.",
+ "adlook.me.",
+ "adm.wsms.haplat.net.",
+ "admbk.wsms.haplat.net.",
+ "admedo.com.",
+ "admixer.com.",
+ "adoric.com.",
+ "adquery.io.",
+ "adrs.org.cn.",
+ "ads.adventive.com.",
+ "adsco.re.",
+ "adtarget.market.",
+ "advantage.purpleguys.com.",
+ "advantage2.purpleguys.com.",
+ "advantagecharter-my.sharepoint.com.",
+ "adventisthealthwest-my.sharepoint.com.",
+ "adventisthealthwest.sharepoint.com.",
+ "adview.com.",
+ "advlion.com.",
+ "adx-sg-req.anythinktech.com.",
+ "adx-vg-req.anythinktech.com.",
+ "adxbid.info.",
+ "aee.myisolved.com.",
+ "aepenergy-my.sharepoint.com.",
+ "aepenergy.sharepoint.com.",
+ "agd2.p.360.cn.",
+ "agent.marketingcloudfx.com.",
+ "agt.p.360.cn.",
+ "aicdn.com.",
+ "aid.send.microad.jp.",
+ "aidata.io.",
+ "aiq-in.caranddriver.com.",
+ "airasia.com.",
+ "airtory.com.",
+ "ajcloud.net.",
+ "akronchildrens-my.sharepoint.com.",
+ "akulaku.com.",
+ "alarm.wsms.haplat.net.",
+ "alarmbk.wsms.haplat.net.",
+ "alarmnet.com.",
+ "albany.remotepc.com.",
+ "album-sg01a.ocloud.heytapmobi.com.",
+ "ali-picture-private-sg.oss-ap-southeast-1.aliyuncs.com.",
+ "ali-sgp-messpush.meetyouintl.com.",
+ "alialarm-sgp.oss-ap-southeast-1.aliyuncs.com.",
+ "alibaba-inc.com.",
+ "alibabachengdun.com.",
+ "alibabacorp.com.",
+ "alibabausercontent.com.",
+ "alicdn.com.",
+ "aliexpress.ru.",
+ "aliexpress.us.",
+ "alikunlun.com.",
+ "alikunlun.net.",
+ "alivc-aio.cn-hangzhou.log.aliyuncs.com.",
+ "alive1.cloudbirds.cn.",
+ "alive2.cloudbirds.cn.",
+ "alive3.cloudbirds.cn.",
+ "aliyun.com.",
+ "aliyuncs.com.",
+ "allieduniversalservices-my.sharepoint.com.",
+ "allieduniversalservices.sharepoint.com.",
+ "altamedhealth.sharepoint.com.",
+ "am1.ecdn2.bumbcdn.com.",
+ "am3pap002.storage.live.com.",
+ "am3pap003.storage.live.com.",
+ "am3pap005.storage.live.com.",
+ "am3pap006.storage.live.com.",
+ "am3pap007.storage.live.com.",
+ "am4pap001.storage.live.com.",
+ "amap.com.",
+ "amc-theatres-res.cloudinary.com.",
+ "amcor-my.sharepoint.com.",
+ "amdc.lazada.com.",
+ "amdcopen.m.taobao.com.",
+ "amdcopen.m.taobao.com.gds.alibabadns.com.",
+ "americanchemicalsociety-my.sharepoint.com.",
+ "amp.namequery.com.",
+ "amp.permutive.com.",
+ "ams-itm-radar-testobject.citrix.com.",
+ "ams02pap001.storage.live.com.",
+ "ams03pap002.storage.live.com.",
+ "amsterdam.remotepc.com.",
+ "amwinsusa-my.sharepoint.com.",
+ "amwinsusa.sharepoint.com.",
+ "analytics-2.athome.com.",
+ "analytics-debugger.com.",
+ "analytics-ingress-global.bitmovin.com.",
+ "analytics.coach.com.",
+ "analytics.coachoutlet.com.",
+ "analytics.getshogun.com.",
+ "analytics.gnc.com.",
+ "analytics.languagetoolplus.com.",
+ "analytics.qumucloud.com.",
+ "analytics.talbots.com.",
+ "analytics.trovit.com.",
+ "android.crashsight.wetest.net.",
+ "ankara.remotepc.com.",
+ "anlian.co.",
+ "announce.torrentsmd.com.",
+ "anonymous.ads.brave.com.",
+ "answers.yext-pixel.com.",
+ "ansys-my.sharepoint.com.",
+ "ansys.sharepoint.com.",
+ "anthropic.com.",
+ "aon.com.",
+ "ap-southeast-1.log.aliyuncs.com.",
+ "api-analytics-us3.zepp.com.",
+ "api-asyncgw-gcc-teams.usgovtrafficmanager.net.",
+ "api-eu1.hubspot.com.",
+ "api-ext.slickdeals.net.",
+ "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-aeuc1b.smoot.apple.com.",
+ "api-glb-aeuw1b.smoot.apple.com.",
+ "api-glb-aeuw3b.smoot.apple.com.",
+ "api-glb-aeuw3c.smoot.apple.com.",
+ "api-glb-asae1b.smoot.apple.com.",
+ "api-glb-ause1a.smoot.apple.com.",
+ "api-glb-ause1b.smoot.apple.com.",
+ "api-glb-ause1c.smoot.apple.com.",
+ "api-glb-ause2a.smoot.apple.com.",
+ "api-glb-ause2b.smoot.apple.com.",
+ "api-glb-ause2c.smoot.apple.com.",
+ "api-glb-ausw2b.smoot.apple.com.",
+ "api-glb-ausw2c.smoot.apple.com.",
+ "api-mayi.django.t.taobao.com.",
+ "api-mifit-us3.zepp.com.",
+ "api-php1-ovh.keepsolid.com.",
+ "api-php2-ovh.keepsolid.com.",
+ "api-php3-ovh.keepsolid.com.",
+ "api-php4-ovh.keepsolid.com.",
+ "api-php9-ovh.keepsolid.com.",
+ "api-pos.titank12.com.",
+ "api-preview.luckyorange.com.",
+ "api-sh.django.t.taobao.com.gds.alibabadns.com.",
+ "api.adquery.io.",
+ "api.ams.gcc.teams.microsoft.com.",
+ "api.asm.skype.com.",
+ "api.bobble.ai.",
+ "api.bosch-wdw.com.",
+ "api.box.com.",
+ "api.btloader.com.",
+ "api.cloud.tenda.com.cn.",
+ "api.config-security.com.",
+ "api.crobox.com.",
+ "api.dealersocket.com.",
+ "api.deepl.com.",
+ "api.do.buienalarm.nl.",
+ "api.gleap.io.",
+ "api.goaffpro.com.",
+ "api.gravitec.media.",
+ "api.grow.me.",
+ "api.icalendars.app.",
+ "api.inboxsdk.com.",
+ "api.k.163.com.",
+ "api.kinogram.best.",
+ "api.lightboxcdn.com.",
+ "api.loyalhealth.com.",
+ "api.lytics.io.",
+ "api.meteoplaza.com.",
+ "api.mindbodyonline.com.",
+ "api.mintkeyboard.com.",
+ "api.moyoung.com.",
+ "api.mrg.agency.",
+ "api.my.jbi.global.",
+ "api.onedrive.com.",
+ "api.owhealth.com.",
+ "api.permutive.app.",
+ "api.permutive.com.",
+ "api.pgf-asqb7a.com.",
+ "api.pgf-thzvvo.com.",
+ "api.playlnk.io.",
+ "api.popin.cc.",
+ "api.pushbullet.com.",
+ "api.queryly.com.",
+ "api.reverso.net.",
+ "api.ringcentral.biz.",
+ "api.rollbar.com.",
+ "api.sbz.vn.",
+ "api.searchiq.co.",
+ "api.skybet.com.",
+ "api.smartdeploy.com.",
+ "api.snapchat.com.",
+ "api.sofascore.app.",
+ "api.sofascore.com.",
+ "api.streak.com.",
+ "api.swishapps.ai.",
+ "api.transitapp.com.",
+ "api.tx4.pw.adn.cloud.",
+ "api.ultimaker.com.",
+ "api.ultimate-guitar.com.",
+ "api.unity.com.",
+ "api.userlike.com.",
+ "api.vhx.tv.",
+ "api.vieon.vn.",
+ "api.vvxi2.com.",
+ "api000.backblazeb2.com.",
+ "api001.backblazeb2.com.",
+ "api002.backblazeb2.com.",
+ "apigroupinc-my.sharepoint.com.",
+ "apiisgp.ezvizlife.com.",
+ "apiisgp.hik-connect.com.",
+ "apimgmttmkoempweel99rngfdhyv9x4h8qv4sl6dfug9jtikbm.trafficmanager.net.",
+ "apk.v-mate.mobi.",
+ "apk.vidmate.net.",
+ "app-atl.five9.com.",
+ "app-eu1.hubspot.com.",
+ "app-goal.com.",
+ "app-scl.five9.com.",
+ "app-sec-cn.heytapmobi.com.",
+ "app-student.atitesting.com.",
+ "app.adoric-om.com.",
+ "app.box.com.",
+ "app.cart-bot.net.",
+ "app.cybba.solutions.",
+ "app.ee-share.com.",
+ "app.grow.me.",
+ "app.paces.jbi.global.",
+ "app.pendo.qgenda.com.",
+ "app.retinavue.net.",
+ "app.sealsubscriptions.com.",
+ "app.snapchat.com.",
+ "app.wdesk.com.",
+ "app.zoom.us.",
+ "appcafe.gtm.starbucks.com.",
+ "appcafe.starbucks.com.",
+ "appconf.mail.163.com.",
+ "appocean.media.",
+ "apponline.research.qq.com.",
+ "appriver.com.",
+ "apps.gov.powerapps.us.",
+ "apps.wix.com.",
+ "appstoreonrt-stsdk.vivo.com.cn.",
+ "appstoreort-stsdk.vivo.com.cn.",
+ "apr1308.mazefoam.com.",
+ "apv-launcher.minute.ly.",
+ "apv-static.minute.ly.",
+ "apv-static.tldw.me.",
+ "arbitrum.io.",
+ "ardenthealthservices-my.sharepoint.com.",
+ "ardenthealthservices.sharepoint.com.",
+ "arenabg.com.",
+ "aristotleinsight.com.",
+ "arm1.maxhost.io.",
+ "armh.sharepoint.com.",
+ "arms-retcode-sg.aliyuncs.com.",
+ "arms-retcode.aliyuncs.com.",
+ "arms.aliyuncs.com.",
+ "arnoldclark1-my.sharepoint.com.",
+ "arup-my.sharepoint.com.",
+ "arupapc-my.sharepoint.com.",
+ "as-api.asm.skype.com.",
+ "as-prod.asyncgw.teams.microsoft.com.",
+ "asheville.remotepc.com.",
+ "asia-001.azure-apim.net.",
+ "asia-adlog.vivoglobal.com.",
+ "asia-browser.vivoglobal.com.",
+ "asia-config-appstore.vivoglobal.com.",
+ "asia-cota.vivoglobal.com.",
+ "asia-ex-adlog.vivoglobal.com.",
+ "asia-exmagazineunlock-proxy.vivoglobal.com.",
+ "asia-f-up.vivoglobal.com.",
+ "asia-gamecenter.vivoglobal.com.",
+ "asia-gsearch.vivoglobal.com.",
+ "asia-magazineunlock.vivoglobal.com.",
+ "asia-news-abroad-backstage-interface.vivoglobal.com.",
+ "asia-news-abroad.vivo.com.",
+ "asia-p.vivoglobal.com.",
+ "asia-ro-up.vivoglobal.com.",
+ "asia-rommc-api.vivoglobal.com.",
+ "asia-romsp-unifyconfig.vivoglobal.com.",
+ "asia-sms-api.vivoglobal.com.",
+ "asia-st-romsp.vivoglobal.com.",
+ "asia-st-sl.vivoglobal.com.",
+ "asia-st-sysupgrade.vivoglobal.com.",
+ "asia-stp.vivoglobal.com.",
+ "asia-theme-api.vivoglobal.com.",
+ "asia-timer-appstore.vivoglobal.com.",
+ "asia-timesync.vivoglobal.com.",
+ "asia-upload-appstore.vivoglobal.com.",
+ "asia-usrsys-api.vivoglobal.com.",
+ "asia-vnote.vivoglobal.com.",
+ "asia-vpushonrt-stsdk.vivoglobal.com.",
+ "asia-vpushort-stsdk.vivoglobal.com.",
+ "asia-weather.vivoglobal.com.",
+ "asia-wifi.vivoglobal.com.",
+ "asia.remotepc.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.",
+ "asm-api-golocal-geo-uk-teams.trafficmanager.net.",
+ "asm-api-prod-geo-am-skype.trafficmanager.net.",
+ "asm-api-prod-geo-as-skype.trafficmanager.net.",
+ "asm-api-prod-geo-eu-skype.trafficmanager.net.",
+ "asm-api-prod-version-skype.trafficmanager.net.",
+ "aspect-upush.umeng.com.",
+ "asset.fwcdn3.com.",
+ "asset.fwpub1.com.",
+ "assets.api.stairwell.com.",
+ "assets.apps.pa.gov.",
+ "assets.basspro.com.",
+ "assets.bwbx.io.",
+ "assets.fastly.carvana.io.",
+ "assets.the-independent.com.",
+ "assistant-dre.op.hicloud.com.",
+ "async-motiondetection-us-1d.oss-us-west-1.aliyuncs.com.",
+ "asyncim.zoom.us.",
+ "atemda.com.",
+ "atipt-my.sharepoint.com.",
+ "atipt.sharepoint.com.",
+ "atlanta.remotepc.com.",
+ "atlanta2.remotepc.com.",
+ "atlanta3.remotepc.com.",
+ "atlanta4.remotepc.com.",
+ "au-prod.asyncgw.teams.microsoft.com.",
+ "auckland.remotepc.com.",
+ "audid.umeng.com.",
+ "audio.vivintsky.com.",
+ "audiostatlog.cc.easebar.com.",
+ "auth-asg-en.aliyuncs.com.",
+ "auth.bereal.com.",
+ "auth.ecobee.com.",
+ "auth.jbisumari.org.",
+ "auth.laureate.net.",
+ "auth.xello.world.",
+ "autohome.com.cn.",
+ "autonavi.com.",
+ "autotrack.studyquicks.com.",
+ "auvik.com.",
+ "avalanche.autotrader.co.uk.",
+ "avast.com.",
+ "azchicago.remotepc.com.",
+ "azchicago2.remotepc.com.",
+ "azdcs-my.sharepoint.com.",
+ "azioncdn.net.",
+ "azmatch.adsrvr.org.",
+ "azureford-my.sharepoint.com.",
+ "azureford.sharepoint.com.",
+ "b.fssta.com.",
+ "b.tile.openstreetmap.org.",
+ "b.tile.osm.org.",
+ "bablosoft.com.",
+ "backend-l.deepl.com.",
+ "backgroundcheck-my.sharepoint.com.",
+ "badambiz.com.",
+ "badoo.app.",
+ "bahrain.remotepc.com.",
+ "baishan-cloud.net.",
+ "ballstate-my.sharepoint.com.",
+ "baltimore.remotepc.com.",
+ "bam.nr-data.net.cdn.cloudflare.net.",
+ "bangalore2.remotepc.com.",
+ "bangalore3.remotepc.com.",
+ "bangalore4.remotepc.com.",
+ "bangkok.remotepc.com.",
+ "bankwithunited-my.sharepoint.com.",
+ "bankwithunited.sharepoint.com.",
+ "banners-inventory-weighted-geo.hyprmx.com.",
+ "baptisthealth-my.sharepoint.com.",
+ "baptisthealth.sharepoint.com.",
+ "barstoolsports.com.",
+ "bbzutils.tripcdn.cn.",
+ "bd1cec50-00d1-4ce9-9572-785857419a1e.prmutv.co.",
+ "bdfed.stitch.mlbinfra.com.",
+ "bdpnt-my.sharepoint.com.",
+ "bdreporting.com.",
+ "beacon-api.aliyuncs.com.",
+ "beacon.qq.com.",
+ "beacons4.gvt2.com.",
+ "beacons5.gvt2.com.",
+ "becn-my.sharepoint.com.",
+ "becn.sharepoint.com.",
+ "becpsn-my.sharepoint.com.",
+ "beizi.biz.",
+ "belgium.remotepc.com.",
+ "belgrad.remotepc.com.",
+ "bend.remotepc.com.",
+ "beneplace.com.",
+ "betlive.com.",
+ "bgtfs.transitapp.com.",
+ "bhsjaxinc0-my.sharepoint.com.",
+ "bidder.adquery.io.",
+ "bidmyqps.xyz.",
+ "bifrost.vivaldi.com.",
+ "bik.gov.tr.",
+ "billingsclinic-my.sharepoint.com.",
+ "biomerieux-my.sharepoint.com.",
+ "biomerieux.sharepoint.com.",
+ "bisdus-my.sharepoint.com.",
+ "bitbucket.org.",
+ "bitmyanmar.info.",
+ "bkdllp-my.sharepoint.com.",
+ "bl6pap003.storage.live.com.",
+ "bl6pap004.storage.live.com.",
+ "black-cat.crypto.com.",
+ "blackboard.com.",
+ "blackbox.dropbox-dns.com.",
+ "blk-app.com.",
+ "blocksi-screenshots-us.s3.us-east-005.backblazeb2.com.",
+ "blooket.com.multicdn.cloudinary.com.",
+ "bloomerang.co.",
+ "blueshieldca-my.sharepoint.com.",
+ "blueshieldca.sharepoint.com.",
+ "bluesnap.com.",
+ "bluffdale.remotepc.com.",
+ "blz04pap001.storage.live.com.",
+ "blz04pap002.storage.live.com.",
+ "blz04pap003.storage.live.com.",
+ "blz04pap005.storage.live.com.",
+ "blz04pap006.storage.live.com.",
+ "blz04pap007.storage.live.com.",
+ "bmaus.bumble.com.",
+ "bmcorg-my.sharepoint.com.",
+ "bmoolbb-app.quantummetric.com.",
+ "bmrn-my.sharepoint.com.",
+ "bn02pap001.storage.live.com.",
+ "bn02pap001files.storage.live.com.",
+ "bna365-my.sharepoint.com.",
+ "bnz05pap001.storage.live.com.",
+ "bnz05pap001files.storage.live.com.",
+ "bnz05pap002.storage.live.com.",
+ "bnz05pap002files.storage.live.com.",
+ "bnz06pap001.storage.live.com.",
+ "bnz06pap001files.storage.live.com.",
+ "bnz06pap002.storage.live.com.",
+ "bnz06pap002files.storage.live.com.",
+ "bnz06pap003.storage.live.com.",
+ "bnz06pap003files.storage.live.com.",
+ "bnz06pap004.storage.live.com.",
+ "bnz06pap004files.storage.live.com.",
+ "bnz07pap001.storage.live.com.",
+ "bnz07pap001files.storage.live.com.",
+ "bobble.ai.",
+ "books-analytics-events.apple.com.",
+ "books-personalization-server.apple.com.",
+ "booksy.com.",
+ "bootstrapcdn.com.",
+ "boston.remotepc.com.",
+ "boston2.remotepc.com.",
+ "bostonglobe.com.",
+ "box.com.",
+ "box.net.",
+ "boxcloud.com.",
+ "br.chat.si.riotgames.com.",
+ "brand-assets.ringcentral.com.",
+ "bratislava.remotepc.com.",
+ "breitbart.com.",
+ "brenntag01-my.sharepoint.com.",
+ "brenntag01.sharepoint.com.",
+ "brenntag01nam.sharepoint.com.",
+ "bridge2bwb.com.",
+ "bridgetonorg-my.sharepoint.com.",
+ "broadstreetads.com.",
+ "brocktonpublicschools-my.sharepoint.com.",
+ "bscedge.com.",
+ "bsprings.remotepc.com.",
+ "bt.moack.co.kr.",
+ "bthfa.jenzabarcloud.com.",
+ "btrace.qq.com.",
+ "bucharest.remotepc.com.",
+ "bucharest1.remotepc.com.",
+ "budapest.remotepc.com.",
+ "bufferapp.com.",
+ "bugly.qcloud.com.",
+ "bugreport.huorong.cn.",
+ "bundleb2b.net.",
+ "bundler.nice-team.net.",
+ "burnsmcd-my.sharepoint.com.",
+ "burnsmcd.sharepoint.com.",
+ "bw1-my.sharepoint.com.",
+ "bwatch.bergankdv.com.",
+ "bytecdn.cn.",
+ "bytedance.net.",
+ "c.4dex.io.",
+ "c.fakespot.io.",
+ "c.footprint.net.",
+ "c.pub.network.",
+ "c.tile.openstreetmap.org.",
+ "c.tile.osm.org.",
+ "c1.ttcache.com.",
+ "c2.ttcache.com.",
+ "c2c.wechat.com.",
+ "c3.ttcache.com.",
+ "c4.ttcache.com.",
+ "c6.glb.paypal.com.",
+ "c7l.cyberhaven.io.",
+ "c8ee9446-97ed-462f-a5e9-1af66c8e9104.prmutv.co.",
+ "ca-prod.asyncgw.teams.microsoft.com.",
+ "ca.gov.",
+ "ca000.backblaze.com.",
+ "ca001.backblaze.com.",
+ "ca002.backblaze.com.",
+ "ca80a1adb12a4fbdac5ffcbc944e9a61.pacloudflare.com.",
+ "cached-ad.fyber.com.",
+ "cached.rebuyengine.com.",
+ "cachenetworks.com.",
+ "caia.treasury.gov.",
+ "caidc.apis.honeywell.com.",
+ "cainiao.com.",
+ "caixa.gov.br.",
+ "california.remotepc.com.",
+ "camsoda.com.",
+ "canada.remotepc.com.",
+ "canberra.remotepc.com.",
+ "capetown.remotepc.com.",
+ "car-cloud-cn.net.",
+ "cardiff.remotepc.com.",
+ "cardinalcorp-my.sharepoint.com.",
+ "care.novaicare.com.",
+ "carystudio.com.",
+ "cat.hbwrapper.com.",
+ "cat1.hbwrapper.com.",
+ "cat2.hbwrapper.com.",
+ "catholichealth.net.",
+ "cbox.ws.",
+ "cbsipv4.shuzilm.cn.",
+ "ccf.ivalua.com.",
+ "cchmc-my.sharepoint.com.",
+ "cchmc.sharepoint.com.",
+ "ccs.umeng.com.",
+ "cdn-audio-gcp-media.getepic.com.",
+ "cdn-f.heylink.me.",
+ "cdn-gcp-media-drm.getepic.com.",
+ "cdn-gcp-media.getepic.com.",
+ "cdn-mc-eu1-fd5f74b2.bereal.network.",
+ "cdn-t.vb24131crasosnemesis.com.",
+ "cdn-us.algoliaradar.com.",
+ "cdn-us1.bereal.network.",
+ "cdn-video-gcp-media.getepic.com.",
+ "cdn.bereal.network.",
+ "cdn.coinzilla.io.",
+ "cdn.conveythis.com.",
+ "cdn.deepintent.com.",
+ "cdn.ftd.agency.",
+ "cdn.groupbycloud.com.",
+ "cdn.instapagemetrics.com.",
+ "cdn.overleaf.com.",
+ "cdn.piano.io.",
+ "cdn.preciso.net.",
+ "cdn.qq.com.",
+ "cdn.sierrapacificgroup.com.",
+ "cdn.skcrtxr.com.",
+ "cdn.staticfile.org.",
+ "cdn.tapdb-dev.com.",
+ "cdn.uxfeedback.ru.",
+ "cdn1.wixdns.net.",
+ "cdn11.bigcommerce.com.",
+ "cdnetworks.net.",
+ "cdngslb.com.",
+ "cdnimg.izooto.com.",
+ "cdntm.hsbc.co.uk.",
+ "cdnwidget.com.",
+ "cds.swishapps.ai.",
+ "cdt.ca.gov.",
+ "cdtfa.ca.gov.",
+ "cdxdns.com.",
+ "cdxflare.com.",
+ "cedexis-test.com.",
+ "cedock.com.",
+ "centralmichigan-my.sharepoint.com.",
+ "centrexit.com.",
+ "cfa.fidelity.com.",
+ "cform.loyalhealth.com.",
+ "changehealthcare.com.",
+ "charlotte.remotepc.com.",
+ "chat-masters-mongo-prod.streamlayer.io.",
+ "check2.lloydsbank.co.uk.",
+ "checkout.visa.com.",
+ "chek.zennolab.com.",
+ "chennai.remotepc.com.",
+ "chi-ns2.greengeeks.com.",
+ "chi01pap001.storage.live.com.",
+ "chi01pap001files.storage.live.com.",
+ "chi01pap002.storage.live.com.",
+ "chi01pap002files.storage.live.com.",
+ "chicago.remotepc.com.",
+ "chicago2.remotepc.com.",
+ "chinacache.net.",
+ "chinaccl-a.haplat.net.",
+ "chinaccl-b.haplat.net.",
+ "chinaccl-c.haplat.net.",
+ "chinatimes.com.",
+ "chippewavalley-my.sharepoint.com.",
+ "choctawnationofoklahoma-my.sharepoint.com.",
+ "choctawnationofoklahoma.sharepoint.com.",
+ "chtsite.com.",
+ "chubbgroup-my.sharepoint.com.",
+ "chubbgroup.sharepoint.com.",
+ "chumley.barstoolsports.com.",
+ "cico.com.",
+ "cignium-my.sharepoint.com.",
+ "cinarra.com.",
+ "cintas1.sharepoint.com.",
+ "cisco-my.sharepoint.com.",
+ "cisco.app.box.com.",
+ "cisco.sharepoint.com.",
+ "citrix.com.",
+ "cityofelpaso-my.sharepoint.com.",
+ "cjfgob-my.sharepoint.com.",
+ "cjfgob.sharepoint.com.",
+ "ckmap.mediav.com.",
+ "cl-data.ads.heytapmobi.com.",
+ "cl-gl1e62abf5.preprod-gcdn.co.",
+ "cl.vd.cloud.360safe.com.",
+ "cl2009.com.",
+ "claude.ai.",
+ "clearesult5-my.sharepoint.com.",
+ "clearesult5.sharepoint.com.",
+ "cleveland.remotepc.com.",
+ "clevelandclinic.sharepoint.com.",
+ "click-eu.precmd.com.",
+ "click.directrankcl.com.",
+ "click.pclk.name.",
+ "click.victoriassecret.com.",
+ "client-log.box.com.",
+ "client-tracking.omiapp.me.",
+ "client-updates.lumu.io.",
+ "cliftonlarsonallen.sharepoint.com.",
+ "clips-events.apple.com.",
+ "cloud-config-service.rtc.aliyuncs.com.",
+ "cloud-rest.lenovomm.com.",
+ "cloud.browser.360.cn.",
+ "cloud.typenetwork.com.",
+ "cloud.vmp.onezapp.com.",
+ "cloud.zoom.us.",
+ "cloudbirds.cn.",
+ "clouddata.turbowarp.org.",
+ "cloudflarecp.com.",
+ "cloudflareportal.com.",
+ "cloudlinks.cn.",
+ "cloudsvc.policypak.com.",
+ "cloverparksd-my.sharepoint.com.",
+ "cm-x.mgid.com.",
+ "cmgate.vip.qq.com.",
+ "cmpassport.com.",
+ "cms.ejoyspace.com.",
+ "cms.instiengage.com.",
+ "cn-beijing.log.aliyuncs.com.",
+ "cn-hangzhou.log.aliyuncs.com.",
+ "cn-hangzhou.oss-cdn.aliyun-inc.com.",
+ "cn-hongkong.log.aliyuncs.com.",
+ "cn-qingdao.log.aliyuncs.com.",
+ "cn-shanghai.log.aliyuncs.com.",
+ "cn-singapore-lls01-d01.sls-pub.farlightgames.com.",
+ "cn.gcloudcs.com.",
+ "cn.mvconf.50union.com.",
+ "cname.pendo.io.",
+ "cnbglobal-my.sharepoint.com.",
+ "cnmc-my.sharepoint.com.",
+ "cnmc.sharepoint.com.",
+ "cnv2.mclean.50union.com.",
+ "cnzz.com.",
+ "co-vcode-od.vivoglobal.com.",
+ "co.amx.rcs.telephony.goog.",
+ "codacloud.net.",
+ "code.etracker.com.",
+ "code.piano.io.",
+ "codepush.akulaku.net.",
+ "codis-bak.ngb.haplat.net.",
+ "codis.ngb.haplat.net.",
+ "cofile.net.",
+ "cohnreznick-my.sharepoint.com.",
+ "cohnreznick.sharepoint.com.",
+ "collect-v6.51.la.",
+ "collect.trendyol.com.",
+ "collector.getyourguide.com.",
+ "collector.seexh.com.",
+ "collector.wdp.brave.com.",
+ "collector.xhamster.com.",
+ "colliervilleschools-my.sharepoint.com.",
+ "columbus.remotepc.com.",
+ "columbusk12oh-my.sharepoint.com.",
+ "com.multicdn.cloudinary.com.",
+ "com.yangyi19.com.",
+ "cometglobal.cf.t3cloud.pb.com.",
+ "cometservd1.pb.com.",
+ "commerce.safe.360.cn.",
+ "commercial.ocsp.identrust.com.",
+ "common-afd.fe.1drv.com.",
+ "common-afdrk.fe.1drv.com.",
+ "common.xshareapp.com.",
+ "compass.corebridgefinancial.com.",
+ "compiles.overleafusercontent.com.",
+ "components.mywebsitebuilder.com.",
+ "concur.com.",
+ "config-inmobi-comtm.trafficmanager.net.",
+ "config-security.com.",
+ "config.a-m-p.xyz.",
+ "config.cmpassport.com.",
+ "config.content-settings.com.",
+ "config.inmobi.com.",
+ "config.office.net.",
+ "config.y5en.com.",
+ "config2.cmpassport.com.",
+ "configdl.teamviewer.com.",
+ "conn-service-cn-03.allawntech.com.",
+ "connect.garenanow.com.",
+ "connectivitycheck.unisoc.com.",
+ "constel1-my.sharepoint.com.",
+ "content.betfair.com.",
+ "content.citizensbankonline.com.",
+ "content.discover.com.",
+ "content.discovercard.com.",
+ "content.ebanking-services.com.",
+ "content.gap.com.",
+ "content.ibanking-services.com.",
+ "content.production.cdn.art19.com.",
+ "content.ssctech.com.",
+ "content22.bancanet.banamex.com.",
+ "content22.bmo.com.",
+ "content22.citibankonline.com.",
+ "content22.citicards.com.",
+ "content22.online.citi.com.",
+ "context.reverso.net.",
+ "control-out.mna.qq.com.",
+ "cookie-sync.bidmyadz.com.",
+ "cookiehub.eu.",
+ "coolkit.cc.",
+ "copenhagen.remotepc.com.",
+ "cordial.com.",
+ "core.gssv-play-prod.xboxlive.com.",
+ "core.iprom.net.",
+ "core.omiapp.me.",
+ "corebridgefinancial-my.sharepoint.com.",
+ "corebridgefinancial.com.",
+ "corpmdm.v.aaplimg.com.",
+ "corvel-my.sharepoint.com.",
+ "covers.vitalbook.com.",
+ "coyotesusd-my.sharepoint.com.",
+ "cp2.cloudflare.com.",
+ "cpm.appocean.media.",
+ "cpm.aserve1.net.",
+ "cpm.bidmyqps.xyz.",
+ "cpm.catapultx.com.",
+ "cpm.qortex.ai.",
+ "cpm.vuukle.net.",
+ "cpm.xrtb.io.",
+ "cpncorp-my.sharepoint.com.",
+ "cpr-pusa01.app.blackbaud.net.",
+ "cpx-research.com.",
+ "cr00.biz.",
+ "crash.xiaohongshu.com.",
+ "crashlytics.com.",
+ "crashsight.qq.com.",
+ "crashsight.wetest.net.",
+ "crobox.com.",
+ "crobox.io.",
+ "crossforward.com.",
+ "crowd.transitapp.com.",
+ "crowncastle-my.sharepoint.com.",
+ "crowncastle.sharepoint.com.",
+ "crrepo.com.",
+ "crutchfield.com.",
+ "cs.globalsun.io.",
+ "cs.openwebmedia.com.",
+ "csdn.net.",
+ "cshealthforlife.com.",
+ "cspire.com.",
+ "cstse02.ultipro.com.",
+ "cstsew02.ultipro.com.",
+ "cstsn02.ultipro.com.",
+ "cta-eu1.hubspot.com.",
+ "cuco.softi9.pt.",
+ "cummins365-my.sharepoint.com.",
+ "cummins365.sharepoint.com.",
+ "cunamutual-my.sharepoint.com.",
+ "cunamutual.sharepoint.com.",
+ "customer.homedepot.com.",
+ "cvs.quantummetric.com.",
+ "cwc.sharepoint.com.",
+ "cx.soft.360.cn.",
+ "czechrepublic.remotepc.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.",
+ "d3tracking.rbc.com.",
+ "d6691a17-6fdb-4d26-85d6-b3dd27f55f08.prmutv.co.",
+ "d82f7a30-751a-4689-b7e9-19336a89ab46.prmutv.co.",
+ "d837da8d.cloudsrv.minerva-labs.com.",
+ "da.toponadss.com.",
+ "daemon.nanoleaf.me.",
+ "dallas.remotepc.com.",
+ "dallas2.remotepc.com.",
+ "dallas3.remotepc.com.",
+ "dallas4.remotepc.com.",
+ "dallas5.remotepc.com.",
+ "dallaschildrens-my.sharepoint.com.",
+ "dallaschildrens.sharepoint.com.",
+ "dalu-my.sharepoint.com.",
+ "dantri.com.vn.",
+ "dapulse-res.cloudinary.com.",
+ "darden-sync.quantummetric.com.",
+ "data-graph.mlb.com.",
+ "data.analytics.thomsonreuters.com.",
+ "data.analytics.ux.quickbase.com.",
+ "data.assist.chromeriver.com.",
+ "data.bhrpendo.bamboohr.com.",
+ "data.cn-singapore-lls01-d01.sls-pub.farlightgames.com.",
+ "data.cw.edgenuity.com.",
+ "data.dap.paylocity.com.",
+ "data.data.achieve3000.com.",
+ "data.data.aleks.com.",
+ "data.data.mheducation.com.",
+ "data.guide-app.zoominfo.co.",
+ "data.guides.oncoursesystems.com.",
+ "data.guides.percipio.com.",
+ "data.guides.wdesk.com.",
+ "data.hockeystack.com.",
+ "data.investing.com.",
+ "data.ipd.goto.com.",
+ "data.kuiniuca.com.",
+ "data.meitu.com.",
+ "data.pendo-cdn.pluralsight.com.",
+ "data.pendo-cobalt.westlaw.com.",
+ "data.pendo-tracking.seismic.com.",
+ "data.pendo.careporthealth.com.",
+ "data.pendo.gomotive.com.",
+ "data.pendo.looker.app.",
+ "data.pendo.navimedix.com.",
+ "data.pendo.progresslearning.com.",
+ "data.pendo.saashr.com.",
+ "data.pendo.statista.com.",
+ "data.pendo.udsrv.com.",
+ "data.pnd.liveperson.com.",
+ "data.productanalytics.coconutcalendar.com.",
+ "data.queryly.com.",
+ "data.tracking.billtrust.com.",
+ "data00.adlooxtracking.com.",
+ "datadog.zendesk.com.",
+ "datamma.guides.nelnet.com.",
+ "datasite.com.",
+ "datatheorem.com.",
+ "db.onlinewebfonts.com.",
+ "db3pap002.storage.live.com.",
+ "db3pap003.storage.live.com.",
+ "db3pap005.storage.live.com.",
+ "db3pap006.storage.live.com.",
+ "db5pap001.storage.live.com.",
+ "dc-o.api.leiniao.com.",
+ "dc.di.atlas.samsung.com.",
+ "dc.dqa.samsung.com.",
+ "dc.wondershare.com.",
+ "dcs-live.mp.lura.live.",
+ "dcs-png.mp.lura.live.",
+ "dcs-vod.mp.lura.live.",
+ "dcs110-mcdn.mp.lura.live.",
+ "dd.browser.360.cn.",
+ "ddata.huntingtonbank.com.",
+ "de-prod.asyncgw.teams.microsoft.com.",
+ "de.dt.rcs.telephony.goog.",
+ "de.hlth.io.mi.com.",
+ "dealer.autopartners.net.",
+ "dealmoon.com.",
+ "decagon.ai.",
+ "deepl.com.",
+ "delivery.upremium.asia.",
+ "dell-prod.actioniq.mr-in.com.",
+ "delta.quantummetric.com.",
+ "demant-my.sharepoint.com.",
+ "demonii.com.",
+ "dentonstudent-my.sharepoint.com.",
+ "denver.remotepc.com.",
+ "deqik.com.",
+ "dev2.keepsolid.com.",
+ "deviceops.hstgps.com.",
+ "dewmobile.net.",
+ "dfaklj.tech.",
+ "dfamilk-my.sharepoint.com.",
+ "dfw.mcleodhosted.com.",
+ "dialpad.com.",
+ "dict.deepl.com.",
+ "dict.ntes53.netease.com.",
+ "dictvip-business.youdao.com.",
+ "digiapp.vietcombank.com.vn.",
+ "dingtalk.com.",
+ "dir.4.401402081.west-gcloud.codm.activision.com.",
+ "discovery.ringcentral.biz.",
+ "dispatcher.omiapp.me.",
+ "dispatchosglobal.yuanshen.com.",
+ "distservp1.pb.com.",
+ "dl.boxcloud.com.",
+ "dls-udc.dqa.samsung.com.",
+ "dls.di.atlas.samsung.com.",
+ "dm-us.hybrid.ai.",
+ "dmongo.adgrid.io.",
+ "dms.deckers.com.",
+ "dns-e.ns4v.icu.",
+ "dns-tunnel-check.googlezip.net.",
+ "dns.alidns.com.",
+ "dns101.register.com.",
+ "doceditor.wrike.com.",
+ "docer-api.wps.cn.",
+ "docs.live.net.",
+ "document360.io.",
+ "dodgeballhq.com.",
+ "domaincfg.vivoglobal.com.",
+ "donewyork1.remotepc.com.",
+ "donewyork2.remotepc.com.",
+ "donewyork3.remotepc.com.",
+ "dorchester2-my.sharepoint.com.",
+ "dorchester2.sharepoint.com.",
+ "dosfo1.remotepc.com.",
+ "dosfo2.remotepc.com.",
+ "download.2.401402081.west-gcloud.codm.activision.com.",
+ "downloadcenter.genetec.com.",
+ "downloads.vivaldi.com.",
+ "dp.barclaysus.com.",
+ "dp.im.weibo.cn.",
+ "dpf.authorize.net.",
+ "dpkg.mp.lura.live.",
+ "dpool.sina.com.cn.",
+ "dprprod-my.sharepoint.com.",
+ "dps.jp.cinarra.com.",
+ "dr.netease.im.",
+ "dragate-cn.dc.heytapmobi.com.",
+ "drfdisvc.walmart.com.",
+ "drops-register.ubi.com.",
+ "dsa-eu.hybrid.ai.",
+ "dsm01pap001.storage.live.com.",
+ "dsm01pap001files.storage.live.com.",
+ "dsm01pap002.storage.live.com.",
+ "dsm01pap002files.storage.live.com.",
+ "dsm01pap003.storage.live.com.",
+ "dsm01pap003files.storage.live.com.",
+ "dsm01pap004.storage.live.com.",
+ "dsm01pap004files.storage.live.com.",
+ "dsm01pap005.storage.live.com.",
+ "dsm01pap005files.storage.live.com.",
+ "dsm01pap006.storage.live.com.",
+ "dsm01pap006files.storage.live.com.",
+ "dsm01pap007.storage.live.com.",
+ "dsm01pap007files.storage.live.com.",
+ "dsm01pap008.storage.live.com.",
+ "dsm01pap008files.storage.live.com.",
+ "dsm01pap009.storage.live.com.",
+ "dsm01pap009files.storage.live.com.",
+ "dsm04pap001.storage.live.com.",
+ "dsm04pap001files.storage.live.com.",
+ "dsm04pap002.storage.live.com.",
+ "dsm04pap002files.storage.live.com.",
+ "dsm04pap003.storage.live.com.",
+ "dsm04pap003files.storage.live.com.",
+ "dsp.ads.umeng.com.",
+ "dstillery.com.",
+ "dtscout.com.",
+ "dualspaceapi.com.",
+ "dub01pap001.storage.live.com.",
+ "dub01pap002.storage.live.com.",
+ "dub06pap001.storage.live.com.",
+ "dubai.remotepc.com.",
+ "dublin.remotepc.com.",
+ "dun.163yun.com.",
+ "dypnsapi.aliyuncs.com.",
+ "dz.cyberhaven.io.",
+ "dzfread.cn.",
+ "e-189.21cn.com.",
+ "e.189.cn.",
+ "e.cdnwidget.com.",
+ "e.userflow.com.",
+ "e.viously.com.",
+ "e1cef1f0-495f-4973-ba1c-880786e73a66.prmutv.co.",
+ "e2c1.gcp.gvt2.com.",
+ "e2c10.gcp.gvt2.com.",
+ "e2c11.gcp.gvt2.com.",
+ "e2c12.gcp.gvt2.com.",
+ "e2c13.gcp.gvt2.com.",
+ "e2c14.gcp.gvt2.com.",
+ "e2c15.gcp.gvt2.com.",
+ "e2c16.gcp.gvt2.com.",
+ "e2c17.gcp.gvt2.com.",
+ "e2c18.gcp.gvt2.com.",
+ "e2c19.gcp.gvt2.com.",
+ "e2c2.gcp.gvt2.com.",
+ "e2c20.gcp.gvt2.com.",
+ "e2c21.gcp.gvt2.com.",
+ "e2c22.gcp.gvt2.com.",
+ "e2c23.gcp.gvt2.com.",
+ "e2c24.gcp.gvt2.com.",
+ "e2c25.gcp.gvt2.com.",
+ "e2c26.gcp.gvt2.com.",
+ "e2c27.gcp.gvt2.com.",
+ "e2c28.gcp.gvt2.com.",
+ "e2c29.gcp.gvt2.com.",
+ "e2c3.gcp.gvt2.com.",
+ "e2c30.gcp.gvt2.com.",
+ "e2c31.gcp.gvt2.com.",
+ "e2c32.gcp.gvt2.com.",
+ "e2c33.gcp.gvt2.com.",
+ "e2c34.gcp.gvt2.com.",
+ "e2c35.gcp.gvt2.com.",
+ "e2c36.gcp.gvt2.com.",
+ "e2c37.gcp.gvt2.com.",
+ "e2c38.gcp.gvt2.com.",
+ "e2c39.gcp.gvt2.com.",
+ "e2c4.gcp.gvt2.com.",
+ "e2c40.gcp.gvt2.com.",
+ "e2c41.gcp.gvt2.com.",
+ "e2c42.gcp.gvt2.com.",
+ "e2c43.gcp.gvt2.com.",
+ "e2c44.gcp.gvt2.com.",
+ "e2c45.gcp.gvt2.com.",
+ "e2c46.gcp.gvt2.com.",
+ "e2c47.gcp.gvt2.com.",
+ "e2c48.gcp.gvt2.com.",
+ "e2c49.gcp.gvt2.com.",
+ "e2c5.gcp.gvt2.com.",
+ "e2c50.gcp.gvt2.com.",
+ "e2c51.gcp.gvt2.com.",
+ "e2c52.gcp.gvt2.com.",
+ "e2c53.gcp.gvt2.com.",
+ "e2c54.gcp.gvt2.com.",
+ "e2c55.gcp.gvt2.com.",
+ "e2c56.gcp.gvt2.com.",
+ "e2c57.gcp.gvt2.com.",
+ "e2c58.gcp.gvt2.com.",
+ "e2c59.gcp.gvt2.com.",
+ "e2c6.gcp.gvt2.com.",
+ "e2c60.gcp.gvt2.com.",
+ "e2c61.gcp.gvt2.com.",
+ "e2c62.gcp.gvt2.com.",
+ "e2c63.gcp.gvt2.com.",
+ "e2c64.gcp.gvt2.com.",
+ "e2c65.gcp.gvt2.com.",
+ "e2c66.gcp.gvt2.com.",
+ "e2c67.gcp.gvt2.com.",
+ "e2c68.gcp.gvt2.com.",
+ "e2c69.gcp.gvt2.com.",
+ "e2c7.gcp.gvt2.com.",
+ "e2c70.gcp.gvt2.com.",
+ "e2c71.gcp.gvt2.com.",
+ "e2c72.gcp.gvt2.com.",
+ "e2c73.gcp.gvt2.com.",
+ "e2c74.gcp.gvt2.com.",
+ "e2c75.gcp.gvt2.com.",
+ "e2c76.gcp.gvt2.com.",
+ "e2c77.gcp.gvt2.com.",
+ "e2c78.gcp.gvt2.com.",
+ "e2c79.gcp.gvt2.com.",
+ "e2c8.gcp.gvt2.com.",
+ "e2c9.gcp.gvt2.com.",
+ "e2cs01.gcp.gvt2.com.",
+ "e2cs02.gcp.gvt2.com.",
+ "e2cs03.gcp.gvt2.com.",
+ "e2cs04.gcp.gvt2.com.",
+ "e2cs05.gcp.gvt2.com.",
+ "e2cs06.gcp.gvt2.com.",
+ "e2cs07.gcp.gvt2.com.",
+ "e2cs08.gcp.gvt2.com.",
+ "e2cs09.gcp.gvt2.com.",
+ "e2cs10.gcp.gvt2.com.",
+ "e2cs11.gcp.gvt2.com.",
+ "e2cs12.gcp.gvt2.com.",
+ "e2cs13.gcp.gvt2.com.",
+ "e2cs14.gcp.gvt2.com.",
+ "e2cs15.gcp.gvt2.com.",
+ "e2cs16.gcp.gvt2.com.",
+ "e2cs17.gcp.gvt2.com.",
+ "e2cs18.gcp.gvt2.com.",
+ "e2cs19.gcp.gvt2.com.",
+ "e2cs20.gcp.gvt2.com.",
+ "e2cs21.gcp.gvt2.com.",
+ "e2cs22.gcp.gvt2.com.",
+ "e2cs23.gcp.gvt2.com.",
+ "e2cs24.gcp.gvt2.com.",
+ "e2cs25.gcp.gvt2.com.",
+ "e2cs26.gcp.gvt2.com.",
+ "e2cs27.gcp.gvt2.com.",
+ "e2cs28.gcp.gvt2.com.",
+ "e2cs29.gcp.gvt2.com.",
+ "e2cs30.gcp.gvt2.com.",
+ "e2cs31.gcp.gvt2.com.",
+ "e2cs32.gcp.gvt2.com.",
+ "e2cs33.gcp.gvt2.com.",
+ "e2cs34.gcp.gvt2.com.",
+ "e2cs35.gcp.gvt2.com.",
+ "e2cs36.gcp.gvt2.com.",
+ "e2cs37.gcp.gvt2.com.",
+ "e2cs38.gcp.gvt2.com.",
+ "e2cs39.gcp.gvt2.com.",
+ "e2cs40.gcp.gvt2.com.",
+ "e2cs41.gcp.gvt2.com.",
+ "e2cs42.gcp.gvt2.com.",
+ "e2cs43.gcp.gvt2.com.",
+ "e2cs44.gcp.gvt2.com.",
+ "e2cs45.gcp.gvt2.com.",
+ "e2cs46.gcp.gvt2.com.",
+ "e2cs47.gcp.gvt2.com.",
+ "e2cs48.gcp.gvt2.com.",
+ "e2cs49.gcp.gvt2.com.",
+ "e2cs50.gcp.gvt2.com.",
+ "e2cs51.gcp.gvt2.com.",
+ "e2cs52.gcp.gvt2.com.",
+ "e2cs53.gcp.gvt2.com.",
+ "e2cs54.gcp.gvt2.com.",
+ "e2cs55.gcp.gvt2.com.",
+ "e43.ultipro.com.",
+ "e488cdb0-e7cb-4d91-9648-60d437d8e491.prmutv.co.",
+ "e5de3d23065c4748b155c28e6fa36f3e.pacloudflare.com.",
+ "e99.cyberhaven.io.",
+ "eafd-footprint.elasticafd.net.",
+ "eafddirect.msedge.net.",
+ "eagle-my.sharepoint.com.",
+ "eagle.haplat.net.",
+ "eagle.sharepoint.com.",
+ "eago9.cyberhaven.io.",
+ "easeus.com.",
+ "eastmoney.com.",
+ "eastus2-gas.guestconfiguration.azure.com.",
+ "ebaypay-app.quantummetric.com.",
+ "ebaypay-sync.quantummetric.com.",
+ "ecatholic.com.",
+ "ecom.wixapps.net.",
+ "ecommerce.iap.unity3d.com.",
+ "ecs-gallatin-c2s.trafficmanager.net.",
+ "ecs.tagtoo.co.",
+ "edge.api.brightcove.com.",
+ "edge.txryan.com.",
+ "edgecdn.ru.",
+ "edgedl.me.gvt1.com.",
+ "edgelocation.ivanticloud.com.",
+ "edisonintl-my.sharepoint.com.",
+ "edisonintl.sharepoint.com.",
+ "editor.wix.com.",
+ "edr.ringcentral.com.",
+ "education-certification.youdao.com.",
+ "ee-share.com.",
+ "efercro.com.",
+ "efs.ultipro.com.",
+ "egateway.ultipro.com.",
+ "ehmc-my.sharepoint.com.",
+ "ehmc.sharepoint.com.",
+ "eisaihhc-my.sharepoint.com.",
+ "ejoyspace.com.",
+ "elaracaring-my.sharepoint.com.",
+ "ele.me.",
+ "elemecdn.com.",
+ "emailaptitude.com.",
+ "emerson-my.sharepoint.com.",
+ "emerson.sharepoint.com.",
+ "emo.v-mate.mobi.",
+ "en.showsnob.com.",
+ "enaple.com.",
+ "endpointprotector.com.",
+ "engage.wixapps.net.",
+ "engagementapi.skype.com.",
+ "ent.box.com.",
+ "envoy-ios-prod.getepic.com.",
+ "envysion.com.",
+ "epdg.vowifi.cspire.com.",
+ "epic1-my.sharepoint.com.",
+ "epic1.sharepoint.com.",
+ "epicmobile.ohsu.edu.",
+ "epoch.cloud.",
+ "eponesh.com.",
+ "eportal.fda.gov.ph.",
+ "epsnj-my.sharepoint.com.",
+ "epsnj.sharepoint.com.",
+ "epsonconnect.com.",
+ "errlog.umeng.com.",
+ "errlogos.umeng.com.",
+ "errnewlog.umeng.com.",
+ "errnewlogos.umeng.com.",
+ "errortracking.deepl.com.",
+ "esignlive.com.",
+ "esm.archive.org.",
+ "essence.com.",
+ "estafetamx-my.sharepoint.com.",
+ "etracker.com.",
+ "etsv2.datalake.gameloft.com.",
+ "eu-aa.online-metrix.net.",
+ "eu-api.asm.skype.com.",
+ "eu-prod.asyncgw.teams.microsoft.com.",
+ "eu-push.api.intl.miui.com.",
+ "eu-west-1.console.aws.amazon.com.",
+ "eu.galleryapi.micloud.xiaomi.net.",
+ "eu.statusapi.micloud.xiaomi.net.",
+ "eu1.badoo.com.",
+ "eu1.bumble.com.",
+ "eu4-powerpoint-collab.officeapps.live.com.",
+ "euc-excel-collab.officeapps.live.com.",
+ "euc-powerpoint-collab.officeapps.live.com.",
+ "euler-saas-cn.heytapmobi.com.",
+ "europe-west1-skyuk-uk-pa-tds-prod.cloudfunctions.net.",
+ "europe.remotepc.com.",
+ "eus.his.arc.azure.com.",
+ "eus.his.hybridcompute.trafficmanager.net.",
+ "eus2.guestagentsvc-prod.trafficmanager.net.",
+ "eus2.his.arc.azure.com.",
+ "euw1.chat.si.riotgames.com.",
+ "eve.gameloft.com.",
+ "event-ingestion.yazio-analytics.com.",
+ "event-tracking-project.ap-southeast-1.log.aliyuncs.com.",
+ "event.evtm.53.com.",
+ "event.instiengage.com.",
+ "events.proper.io.",
+ "events.swishapps.ai.",
+ "exappupgrade.vivoglobal.com.",
+ "excel-collab.officeapps.live.com.",
+ "exodus.desync.com.",
+ "exp.host.",
+ "experimental-api.asm.skype.com.",
+ "explicit-explicit.bing.net.trafficmanager.net.",
+ "exponential.com.",
+ "expresspros-my.sharepoint.com.",
+ "expresspros.sharepoint.com.",
+ "extension.faro.speechify.dev.",
+ "external-ams2-1.xx.fbcdn.net.",
+ "external-ams4-1.xx.fbcdn.net.",
+ "external-atl3-1.xx.fbcdn.net.",
+ "external-atl3-2.xx.fbcdn.net.",
+ "external-ber1-1.xx.fbcdn.net.",
+ "external-bos5-1.xx.fbcdn.net.",
+ "external-bru2-1.xx.fbcdn.net.",
+ "external-den2-1.xx.fbcdn.net.",
+ "external-dfw5-1.xx.fbcdn.net.",
+ "external-dfw5-2.xx.fbcdn.net.",
+ "external-dus1-1.xx.fbcdn.net.",
+ "external-fra3-1.xx.fbcdn.net.",
+ "external-fra3-2.xx.fbcdn.net.",
+ "external-fra5-1.xx.fbcdn.net.",
+ "external-fra5-2.xx.fbcdn.net.",
+ "external-ham3-1.xx.fbcdn.net.",
+ "external-hou1-1.xx.fbcdn.net.",
+ "external-iad3-1.xx.fbcdn.net.",
+ "external-iad3-2.xx.fbcdn.net.",
+ "external-lax3-1.xx.fbcdn.net.",
+ "external-lax3-2.xx.fbcdn.net.",
+ "external-lga3-1.xx.fbcdn.net.",
+ "external-lga3-2.xx.fbcdn.net.",
+ "external-lhr6-1.xx.fbcdn.net.",
+ "external-lhr6-2.xx.fbcdn.net.",
+ "external-lhr8-1.xx.fbcdn.net.",
+ "external-lhr8-2.xx.fbcdn.net.",
+ "external-man2-1.xx.fbcdn.net.",
+ "external-mia3-1.xx.fbcdn.net.",
+ "external-mia3-2.xx.fbcdn.net.",
+ "external-msp1-1.xx.fbcdn.net.",
+ "external-muc2-1.xx.fbcdn.net.",
+ "external-ord5-1.xx.fbcdn.net.",
+ "external-ord5-2.xx.fbcdn.net.",
+ "external-sea1-1.xx.fbcdn.net.",
+ "external-sjc3-1.xx.fbcdn.net.",
+ "external-waw2-1.xx.fbcdn.net.",
+ "external-waw2-2.xx.fbcdn.net.",
+ "ezcollab-my.sharepoint.com.",
+ "ezojs.com.cdn.cloudflare.net.",
+ "f-p-sandbox.bytedance.net.",
+ "f1s.powerschool.com.",
+ "fa3fca7ce79f4b81a39f216e916397d5.pacloudflare.com.",
+ "faas.marktplaats.nl.",
+ "faceit.com.",
+ "factor.reg.163.com.",
+ "factset.com.",
+ "family.adguard-dns.com.",
+ "fanduel.quantummetric.com.",
+ "fanyiegg.youdao.com.",
+ "fastenal-my.sharepoint.com.",
+ "fastformstax.prosystemfx.com.",
+ "fastly-cloud.typenetwork.com.",
+ "fastly.cedexis-test.com.",
+ "faves.grow.me.",
+ "fbinsmi.sharepoint.com.",
+ "fdccpaadaptor.forddirectservices.com.",
+ "fe.xiaohongshu.com.",
+ "fed.federate365.com.",
+ "feedbackify.com.",
+ "feeder.co.",
+ "feelinsonice.l.google.com.",
+ "fef.amsub0302.manage.microsoft.com.",
+ "fef.fxpasu01.manage.microsoft.us.",
+ "fef.msua09.manage.microsoft.com.",
+ "fef.msub06.manage.microsoft.com.",
+ "fef.msub07.manage.microsoft.com.",
+ "femaledaily.com.",
+ "fengkongcloud.com.",
+ "ferringgroup-my.sharepoint.com.",
+ "fgwn01.ultipro.com.",
+ "fi.telephony.goog.",
+ "field59.com.",
+ "files.crazygames.com.",
+ "files.jotform.com.",
+ "finalsite.com.",
+ "finalsite.net.",
+ "firebase.sgp1.digitaloceanspaces.com.",
+ "fireeye.com.",
+ "fiscal.treasury.gov.",
+ "five9.com.",
+ "flashcards.vitalsource.com.",
+ "fleet.todyl.com.",
+ "flip.to.",
+ "flixcdn.com.",
+ "floodlight.design.",
+ "flyspirit-my.sharepoint.com.",
+ "fm.printaudit.com.",
+ "fmcna-my.sharepoint.com.",
+ "fmcna.sharepoint.com.",
+ "fmcschedule.com.",
+ "fn.us.ipqscdn.com.",
+ "fo.iemiq.com.",
+ "forcesafesearch.google.com.",
+ "forksystems.mm.fcix.net.",
+ "form.jotform.com.",
+ "forms-eu1.hscollectedforms.net.",
+ "forms-eu1.hsforms.com.",
+ "forms.hubspot.com.",
+ "fortisimperious.com.",
+ "fortworth.remotepc.com.",
+ "foundation-ipv4.youdao.com.",
+ "fpdlp.applxweb.com.",
+ "fr-prod.asyncgw.teams.microsoft.com.",
+ "fr1.ecdn2.bumbcdn.com.",
+ "fran.frvr.com.",
+ "frankfurt.remotepc.com.",
+ "fremont.remotepc.com.",
+ "freseniusmedicalcare.com.",
+ "fresnocounty-my.sharepoint.com.",
+ "fs.ultiproworkplace.com.",
+ "fsu-my.sharepoint.com.",
+ "fsu.sharepoint.com.",
+ "ftb.ca.gov.",
+ "fticonsulting-my.sharepoint.com.",
+ "fticonsulting.sharepoint.com.",
+ "ftke02.ultipro.com.",
+ "ftkew02.ultipro.com.",
+ "ftkn01.ultipro.com.",
+ "ftkn02.ultipro.com.",
+ "fusd-my.sharepoint.com.",
+ "fusd.sharepoint.com.",
+ "fxltsbl.com.",
+ "g10498469755.co.",
+ "g9hc4.cn.",
+ "galaxy.safe.360.cn.",
+ "galaxyappstore.com.",
+ "galeapps.gale.com.",
+ "gameloft.com.",
+ "gamemonkey.org.",
+ "gamepigeon.net.",
+ "gaspra.iad-03.braze.com.",
+ "gateway.ultiproworkplace.com.",
+ "gb.ee.rcs.telephony.goog.",
+ "gb.o2.rcs.telephony.goog.",
+ "gbc-owl.officeapps.live.com.",
+ "gbc-word-view.officeapps.live.com.",
+ "gcash-api.pulseid.com.",
+ "gccmod.ecs.office.com.",
+ "gcdn.co.",
+ "gce-beacons.gcp.gvt2.com.",
+ "gcloud.qq.com.",
+ "gcloudcs.com.",
+ "gcloudsdk.com.",
+ "gcs.garmin.com.",
+ "gcs.sc-cdn.net.",
+ "gdid.datalake.gameloft.com.",
+ "gdpr.loopme.com.",
+ "geappl.io.",
+ "geappliances-my.sharepoint.com.",
+ "geappliances.sharepoint.com.",
+ "geico-app.quantummetric.com.",
+ "geico-sync.quantummetric.com.",
+ "geniusmonkey.com.",
+ "geo-dra.platform.hicloud.com.",
+ "geoplugin.net.",
+ "geotargetly-api-1.com.",
+ "get-xmore-links8.com.",
+ "getadmiral.com.",
+ "getbutton.io.",
+ "getnitropack.com.",
+ "gettopple.com.",
+ "getui.net.",
+ "getxray.app.",
+ "gfmfxefsrr-my.sharepoint.com.",
+ "gifshow.com.",
+ "gitlab.com.",
+ "gla.gameloft.com.",
+ "glic-my.sharepoint.com.",
+ "glic.sharepoint.com.",
+ "global-tokenserver-la.headline.uodoo.com.",
+ "global.datasite.com.",
+ "globalsigncdn.com.cdn.cloudflare.net.",
+ "globalsun.io.",
+ "gnc.com.",
+ "go.gale.com.",
+ "go.myavlive.com.",
+ "goaffpro.com.",
+ "goconfluent-my.sharepoint.com.",
+ "goconfluent.sharepoint.com.",
+ "golf.com.",
+ "google.org.",
+ "googledomains.com.",
+ "googlesync.permutive.com.",
+ "gosport.remotepc.com.",
+ "gov-bam.nr-data.net.",
+ "gov-bam.nr-data.net.cdn.cloudflare.net.",
+ "grab.zoom.us.",
+ "gradle.org.",
+ "gravitec.net.",
+ "greenville.remotepc.com.",
+ "group-ib.com.",
+ "grouponeauto-my.sharepoint.com.",
+ "grpc-sdk.streamlayer.io.",
+ "grpc.streamlayer.io.",
+ "grpc.vivintsky.com.",
+ "gslb.finzfin.com.",
+ "gslb.sgw.shopeemobile.com.",
+ "gslb.xiaohongshu.com.",
+ "gstbocessscta-my.sharepoint.com.",
+ "gtimg.cn.",
+ "guid.tpns.sgp.tencent.com.",
+ "gw5.push.mcp.weibo.cn.",
+ "gwadar.cn.",
+ "gx-api.geniex.com.",
+ "gyazo.com.",
+ "gz0.googleusercontent.com.",
+ "h-5h8i3ud8.online-metrix.net.",
+ "h-adp.online-metrix.net.",
+ "h-discover.online-metrix.net.",
+ "h-e04kqxof.online-metrix.net.",
+ "h-ebay.online-metrix.net.",
+ "h-fisglobal.online-metrix.net.",
+ "h-homedepot.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-uptodate.online-metrix.net.",
+ "h-v60nf4oj-qfp.online-metrix.net.",
+ "h-walmart.online-metrix.net.",
+ "h.app.wdesk.com.",
+ "h.online-metrix.net.",
+ "h107833-ecdn.mp.lura.live.",
+ "haka.ruselabs.com.",
+ "hamina.remotepc.com.",
+ "handmadewithjoann.com.",
+ "hanoi.remotepc.com.",
+ "hapsee.cn.",
+ "harmonyoffice-my.sharepoint.com.",
+ "harrisonk12msus-my.sharepoint.com.",
+ "harry.lu.",
+ "hawaii.remotepc.com.",
+ "hazelcast.com.",
+ "hbe199.hybrid.ai.",
+ "hbopenbid-apac-v2.pubmnet.com.",
+ "hbwrapper.com.",
+ "hd-ext-v1.log.mgtv.com.",
+ "hdi365-my.sharepoint.com.",
+ "hdi365.sharepoint.com.",
+ "healthequity-my.sharepoint.com.",
+ "healthequity.sharepoint.com.",
+ "hearst-prod.actioniq.mr-in.com.",
+ "hecheck.bitmyanmar.info.",
+ "helloid.com.",
+ "hellomedian.com.",
+ "henricova-my.sharepoint.com.",
+ "hermes-us.inspidspad.com.",
+ "hetangsmart.com.",
+ "heytapdownload.com.",
+ "heytapmobi.com.",
+ "hiecheimaetu.com.",
+ "highpointuniversity-my.sharepoint.com.",
+ "highwebmedia.com.",
+ "highwire.org.",
+ "hillingdon-my.sharepoint.com.",
+ "hillsboroughcounty-my.sharepoint.com.",
+ "hisearch-dra.dt.dbankcloud.com.",
+ "hismarttv.com.",
+ "hismileteeth.com.",
+ "hits.getelevar.com.",
+ "hk.gcloudcs.com.",
+ "hk.wechat.com.",
+ "hk2.jiedian.stream.",
+ "home.highwire.org.",
+ "homedepot.quantummetric.com.",
+ "honeywell.com.",
+ "honeywellprod-my.sharepoint.com.",
+ "honeywellprod.sharepoint.com.",
+ "hongkong.remotepc.com.",
+ "houstonmethodist1.sharepoint.com.",
+ "houtx-my.sharepoint.com.",
+ "hpfalkaj.deepl.com.",
+ "hpkaj.deepl.com.",
+ "hpplay.cn.",
+ "hrsa.gov.",
+ "hstgps.com.",
+ "html.it.",
+ "html5.qq.com.",
+ "htms.heytapmobi.com.",
+ "httpdns.y5en.com.",
+ "huan.tv.",
+ "huaweicloud.com.",
+ "hubble.netease.com.",
+ "hubcloud.com.cn.",
+ "hubspotemail.net.",
+ "huion.cn.",
+ "huntsvillecityschools-my.sharepoint.com.",
+ "huorong.cn.",
+ "huroncg-my.sharepoint.com.",
+ "hwapps-o.api.leiniao.com.",
+ "hypixel.net.",
+ "hysteryale-my.sharepoint.com.",
+ "hysteryale.sharepoint.com.",
+ "hyvee.quantummetric.com.",
+ "hzmk.site.",
+ "hzmklvdieo.com.",
+ "i-sg01a.ocloud.heytapmobi.com.",
+ "i.discogs.com.",
+ "i.magazine.heytapmobi.com.",
+ "i.omiapp.me.",
+ "i.voe.sx.",
+ "i18n-va-api.faceueditor.com.ttdns2.com.",
+ "i6-vn.weather.oppomobile.com.",
+ "ia.51.la.",
+ "iaas.jdcloud.com.",
+ "ibm.account.box.com.",
+ "ibm.box.com.",
+ "ibm.monday.com.",
+ "ibsrv.net.",
+ "icalendars.app.",
+ "iceholdings.sharepoint.com.",
+ "ichano.cn.",
+ "iconmonstr.com.",
+ "icons.bitwarden.net.",
+ "id-ooredoo.rcs.telephony.goog.",
+ "id-telkom.rcs.telephony.goog.",
+ "id-timer-appstore.vivoglobal.com.",
+ "id.remoteutilities.com.",
+ "idahofalls.remotepc.com.",
+ "idchicago1.remotepc.com.",
+ "iddallas1.remotepc.com.",
+ "iddenver.remotepc.com.",
+ "iddetroit.remotepc.com.",
+ "identity.myisolved.com.",
+ "idexonline-my.sharepoint.com.",
+ "idhw-my.sharepoint.com.",
+ "idhw.sharepoint.com.",
+ "idlondon.remotepc.com.",
+ "idmadrid.remotepc.com.",
+ "idnewyork1.remotepc.com.",
+ "idpix.media6degrees.com.cdn.cloudflare.net.",
+ "idr.cdnwidget.com.",
+ "ids.cdnwidget.com.",
+ "iemiq.com.",
+ "if-sg.magzine.oppomobile.com.",
+ "igame.gcloudcs.com.",
+ "ijoysoftconnect.com.",
+ "ilandcloud.com.",
+ "illinoisstateuniversity-my.sharepoint.com.",
+ "illumina.okta.com.",
+ "ilmn-my.sharepoint.com.",
+ "ilmn.sharepoint.com.",
+ "ilog-sea-aliyun.alipayplus.com.",
+ "image.myqcloud.com.",
+ "image.online.adp.com.",
+ "images.babylist.com.",
+ "images.crazygames.com.",
+ "imagetrendelite.com.",
+ "imanageshare.com.",
+ "imap.earthlink.net.",
+ "imeclient.openspeech.cn.",
+ "img.poki.com.",
+ "img.vmmcdn.com.",
+ "img.yana.upday.com.",
+ "img9.target.com.",
+ "imghst-de.com.",
+ "imgix.ranker.com.",
+ "imgproxy.leaflets.schwarz.",
+ "imgs.signifyd.com.",
+ "imodules.com.",
+ "imoim.net.",
+ "imolive2.com.",
+ "imou-sg3-ali-online-paas-private-picture.oss-ap-southeast-1.aliyuncs.com.",
+ "imoulife.com.",
+ "imp.datafyhq.com.",
+ "impactify.media.",
+ "impactserving.com.",
+ "imptrk.siteplug.com.",
+ "in-api.asm.skype.com.",
+ "in-prod.asyncgw.teams.microsoft.com.",
+ "in.gov.",
+ "in.visitors.live.",
+ "indianapolis.remotepc.com.",
+ "inf.miui.com.",
+ "info.directpay.irs.gov.",
+ "ingov-my.sharepoint.com.",
+ "ingov.sharepoint.com.",
+ "inneraudioms.cc.easebar.com.",
+ "innity.com.",
+ "innity.net.",
+ "ino.qq.com.",
+ "inoreader.com.",
+ "ins-qw3q8ofk.ias.tencent-cloud.net.",
+ "inscr-my.sharepoint.com.",
+ "inscr.sharepoint.com.",
+ "insidemedia-my.sharepoint.com.",
+ "insidemedia.sharepoint.com.",
+ "inskinad.com.",
+ "inspidspad.com.",
+ "inspirebrands-sync.quantummetric.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.",
+ "instantmessaging-pa-us.googleapis.com.",
+ "int.dpool.sina.com.cn.",
+ "intel-my.sharepoint.com.",
+ "intel.sharepoint.com.",
+ "internal-api.monzo.com.",
+ "internetdownloadmanager.com.",
+ "intl-im-conn.iq.com.",
+ "iorad.com.",
+ "ios.crashsight.wetest.net.",
+ "iosack.tuisong.baidu.com.",
+ "iot.hillrom.com.",
+ "iowa.remotepc.com.",
+ "ip-api.com.",
+ "ip-data-service-prod.ecosec.on.epicgames.com.",
+ "ip.acmeaom.com.",
+ "ip0.zenno.services.",
+ "ipa-business-sg.ap-southeast-1.log.aliyuncs.com.",
+ "ipa-business.cn-hangzhou.log.aliyuncs.com.",
+ "ipinyou.com.",
+ "iprom.net.",
+ "ipv4.cadc.absolute.com.",
+ "ipv4.tracker.harry.lu.",
+ "irltoolkit.mm.fcix.net.",
+ "ironmountain.cyberhaven.io.",
+ "irvine.remotepc.com.",
+ "irx-api.indeed.com.",
+ "iscorp.com.",
+ "isjike.com.",
+ "itc.cn.",
+ "itch.io.",
+ "itch.zone.",
+ "itinfoalvarezandmarsal-my.sharepoint.com.",
+ "itinfoalvarezandmarsal.sharepoint.com.",
+ "itm.cloud.com.",
+ "itoon.org.",
+ "itzmx.com.",
+ "ivalua.com.",
+ "ivview.com.",
+ "izooto.com.",
+ "jabfm.org.",
+ "jasonresponsemeasure.com.",
+ "jbhunt-my.sharepoint.com.",
+ "jbhunt.sharepoint.com.",
+ "jdcloud.com.",
+ "jeldweninc1-my.sharepoint.com.",
+ "jetblue.asapp.com.",
+ "jnj-my.sharepoint.com.",
+ "johannesburg.remotepc.com.",
+ "johnmuirhealth-my.sharepoint.com.",
+ "johnsmanville365-my.sharepoint.com.",
+ "joox.com.",
+ "jotfor.ms.",
+ "joynetgame.com.",
+ "jp-prod.asyncgw.teams.microsoft.com.",
+ "jp.cinarra.com.",
+ "jp1.chat.si.riotgames.com.",
+ "jpost.com.",
+ "jpush.cn.",
+ "jpush.io.",
+ "jqjsgs.com.",
+ "js-eu1.hs-analytics.net.",
+ "js-eu1.hs-banner.com.",
+ "js-eu1.hs-scripts.com.",
+ "js-eu1.hsadspixel.net.",
+ "js-eu1.hscollectedforms.net.",
+ "js-eu1.hsforms.net.",
+ "js-eu1.hsleadflows.net.",
+ "js-eu1.hubspot.com.",
+ "js-eu1.hubspotfeedback.com.",
+ "js.eruptr.io.",
+ "jss.starbucks.com.",
+ "jssprod-starbucks.trafficmanager.net.",
+ "junglefrog.com.",
+ "justice.gov.",
+ "k.163.com.",
+ "k8s1-event-tracker-la.indexexchange.com.",
+ "k8s1-event-tracker-ny.indexexchange.com.",
+ "k8s1-event-tracker-sj.indexexchange.com.",
+ "k8s1-event-tracker-va.indexexchange.com.",
+ "k8s1-la-ext-lb.indexexchange.com.",
+ "k8s1-ny-ext-lb.indexexchange.com.",
+ "k8s1-va-ext-lb.indexexchange.com.",
+ "kajicam.com.",
+ "kc1-my.sharepoint.com.",
+ "khsd-my.sharepoint.com.",
+ "kiev.remotepc.com.",
+ "kiprotect.com.",
+ "kisd365-my.sharepoint.com.",
+ "kiwisizing.com.",
+ "klagenfurt.remotepc.com.",
+ "knightlab.com.",
+ "knock.app.",
+ "knoxville.remotepc.com.",
+ "komect.com.",
+ "kootenaihealth-my.sharepoint.com.",
+ "kornferry-my.sharepoint.com.",
+ "kornferry.sharepoint.com.",
+ "kstatic.googleusercontent.com.",
+ "kumed.sharepoint.com.",
+ "kunlunaq.com.",
+ "kunlunar.com.",
+ "kunlunca.com.",
+ "kunluncan.com.",
+ "kunlungr.com.",
+ "kunlunhuf.com.",
+ "kunlunno.com.",
+ "kunlunsl.com.",
+ "kunlunso.com.",
+ "kwimgs.com.",
+ "kzhi.tech.",
+ "la.remotepc.com.",
+ "la1.chat.si.riotgames.com.",
+ "la10.remotepc.com.",
+ "la11.remotepc.com.",
+ "la12.remotepc.com.",
+ "la2.remotepc.com.",
+ "la3.remotepc.com.",
+ "la4.remotepc.com.",
+ "la8.remotepc.com.",
+ "la9.remotepc.com.",
+ "labtech.corcystems.com.",
+ "lacounty-my.sharepoint.com.",
+ "lacounty.sharepoint.com.",
+ "lahuashanbx.com.",
+ "lan.sdk.linkedin.com.",
+ "lansing.remotepc.com.",
+ "lansweeper.com.",
+ "laohu.com.",
+ "laptop-updates.brave.com.",
+ "larksuite.com.",
+ "lasd.sharepoint.com.",
+ "lastwar-va.us-east-1.log.aliyuncs.com.",
+ "laureatelatammx-my.sharepoint.com.",
+ "laureatelatammx.sharepoint.com.",
+ "lax.remotepc.com.",
+ "layerxsecurity.com.",
+ "lazada-mobile.oss-ap-southeast-1.aliyuncs.com.",
+ "lazada-msgacs.m.taobao.com.",
+ "lazada.co.id.",
+ "lazada.co.th.",
+ "lazada.com.",
+ "lazada.com.my.",
+ "lazada.com.ph.",
+ "lazada.sg.",
+ "lazada.vn.",
+ "lcecorp-my.sharepoint.com.",
+ "lcmchealth-my.sharepoint.com.",
+ "ldap.google.com.",
+ "ldcorp.sharepoint.com.",
+ "leadmanagerfx.com.",
+ "leagueoflegends.com.",
+ "leiniao.com.",
+ "lenovomm.com.",
+ "levect.com.",
+ "level10gc.com.",
+ "leveldata.poki.io.",
+ "leviton-my.sharepoint.com.",
+ "lexicon.33across.com.",
+ "lexrich5.powerschool.com.",
+ "lianmeng.360.cn.",
+ "libertyuniv-my.sharepoint.com.",
+ "libertyuniv.sharepoint.com.",
+ "liblynx.com.",
+ "license.gonative.io.",
+ "license.litespeedtech.com.",
+ "license.unity3d.com.",
+ "licensing.bitmovin.com.",
+ "lichess.org.",
+ "lightwidget.com.",
+ "likr.tw.",
+ "lima.remotepc.com.",
+ "lincare-my.sharepoint.com.",
+ "lincare.sharepoint.com.",
+ "lineicons.com.",
+ "link-vision-picture-sgp.oss-ap-southeast-1.aliyuncs.com.",
+ "link.gale.com.",
+ "lissabon.remotepc.com.",
+ "list.tronlink.org.",
+ "lists-e.tm-rt.sharepoint.com.",
+ "litedev.sgp.hik-connect.com.",
+ "litedev.us.hik-connect.com.",
+ "litespeedtech.com.",
+ "littler-my.sharepoint.com.",
+ "live.126.net.",
+ "live.ngb.haplat.net.",
+ "live3.ngb.haplat.net.",
+ "live5.ngb.haplat.net.",
+ "livect.haplat.net.",
+ "livedmpsk12ia-my.sharepoint.com.",
+ "livedmpsk12ia.sharepoint.com.",
+ "livekilleenisd.sharepoint.com.",
+ "liveutmb-my.sharepoint.com.",
+ "liveutmb.sharepoint.com.",
+ "ljubljana.remotepc.com.",
+ "llbean.com.",
+ "local.adguard.org.",
+ "local.info.g9hc4.cn.",
+ "log-api.newrelic.com.cdn.cloudflare.net.",
+ "log-yex.youdao.com.",
+ "log.getadblock.com.",
+ "log.lscreenc.com.",
+ "log.zoom.us.",
+ "log1.cmpassport.com.",
+ "logger.moviead55.ru.",
+ "logging-service-prod.getepic.com.",
+ "logging.mp.lura.live.",
+ "login.sproutabout.com.",
+ "login.teamviewer.com.",
+ "login.wolterskluwer.com.",
+ "loginradius.com.",
+ "logs.getadblock.com.",
+ "logs2.sportslocalmedia.com.",
+ "logu.hpplay.cn.",
+ "logx.optimizely.com.",
+ "london.remotepc.com.",
+ "london2.remotepc.com.",
+ "london3.remotepc.com.",
+ "london4.remotepc.com.",
+ "london5.remotepc.com.",
+ "london6.remotepc.com.",
+ "london8.remotepc.com.",
+ "look.360.cn.",
+ "loopme.me.",
+ "lpd.lww.com.",
+ "lplcorp1-my.sharepoint.com.",
+ "lptag-cdn.liveperson.net.",
+ "lsagentrelay.lansweeper.com.",
+ "lscreenc.com.",
+ "ltfinc-my.sharepoint.com.",
+ "ltfinc.sharepoint.com.",
+ "ltfl.librarything.com.",
+ "ltpnetwork-my.sharepoint.com.",
+ "ludashi.com.",
+ "lufthansa-app.quantummetric.com.",
+ "lunamedia.live.",
+ "luxembourg.remotepc.com.",
+ "lycraservice-pa-cam-prod.googleapis.com.",
+ "lyric.alarmnet.com.",
+ "lzd-img-global.slatic.net.",
+ "m.bbb.org.",
+ "m.gds.taobao.com.",
+ "m.umeng.com.",
+ "m104216-ucdn.mp.lura.live.",
+ "m107833-mcdn.mp.lura.live.",
+ "m109771-ecdn.mp.lura.live.",
+ "macclog-as.rj.link.",
+ "madisonschools-my.sharepoint.com.",
+ "madrid.remotepc.com.",
+ "maers.adrs.org.cn.",
+ "magichue.net.",
+ "maidenhead.remotepc.com.",
+ "mail.superhuman.com.",
+ "mailinblue.com.",
+ "mailmissouri-my.sharepoint.com.",
+ "mainadv.com.",
+ "maintenanceconnection.com.",
+ "majorel365-my.sharepoint.com.",
+ "malware-filter.gitlab.io.",
+ "manage-selfhost.microsoft.com.",
+ "manage.wix.com.",
+ "manassas.remotepc.com.",
+ "manchester.remotepc.com.",
+ "manifest.prod.boltdns.net.",
+ "marmot-cloud.com.",
+ "marseille.remotepc.com.",
+ "masonitecloud-my.sharepoint.com.",
+ "master1.teamviewer.com.",
+ "master10.teamviewer.com.",
+ "master11.teamviewer.com.",
+ "master12.teamviewer.com.",
+ "master13.teamviewer.com.",
+ "master14.teamviewer.com.",
+ "master15.teamviewer.com.",
+ "master16.teamviewer.com.",
+ "master2.teamviewer.com.",
+ "master3.teamviewer.com.",
+ "master4.teamviewer.com.",
+ "master5.teamviewer.com.",
+ "master6.teamviewer.com.",
+ "master7.teamviewer.com.",
+ "master8.teamviewer.com.",
+ "master9.teamviewer.com.",
+ "masuk.store.",
+ "mathematica-my.sharepoint.com.",
+ "mattressfirm-my.sharepoint.com.",
+ "mattressfirm.sharepoint.com.",
+ "max-l.mediav.com.",
+ "mbboauth-1c.prd.cn.vwg-connect.cn.",
+ "mcallen.remotepc.com.",
+ "mcdermottinc.sharepoint.com.",
+ "mcdermottwillemery-my.sharepoint.com.",
+ "mcdermottwillemery.sharepoint.com.",
+ "mcdn.podbean.com.",
+ "mcleodhosted.com.",
+ "mdap.tngdigital.com.my.",
+ "mdedge.com.",
+ "mdp-upgrade-cn.heytapmobi.com.",
+ "mdvdns.com.",
+ "meari-oss-us.oss-us-west-1.aliyuncs.com.",
+ "meari-us.oss-us-west-1.aliyuncs.com.",
+ "medellin.remotepc.com.",
+ "media-ams2-1.cdn.whatsapp.net.",
+ "media-ams4-1.cdn.whatsapp.net.",
+ "media-arn2-1.cdn.whatsapp.net.",
+ "media-atl3-1.cdn.whatsapp.net.",
+ "media-atl3-2.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-cgk1-1.cdn.whatsapp.net.",
+ "media-cgk1-2.cdn.whatsapp.net.",
+ "media-cgk2-1.cdn.whatsapp.net.",
+ "media-den2-1.cdn.whatsapp.net.",
+ "media-dfw5-1.cdn.whatsapp.net.",
+ "media-dfw5-2.cdn.whatsapp.net.",
+ "media-dus1-1.cdn.whatsapp.net.",
+ "media-fra3-1.cdn.whatsapp.net.",
+ "media-fra3-2.cdn.whatsapp.net.",
+ "media-fra5-1.cdn.whatsapp.net.",
+ "media-fra5-2.cdn.whatsapp.net.",
+ "media-gig4-1.cdn.whatsapp.net.",
+ "media-gru1-1.cdn.whatsapp.net.",
+ "media-gru1-2.cdn.whatsapp.net.",
+ "media-gru2-2.cdn.whatsapp.net.",
+ "media-gua1-1.cdn.whatsapp.net.",
+ "media-ham3-1.cdn.whatsapp.net.",
+ "media-hel3-1.cdn.whatsapp.net.",
+ "media-hkg1-1.cdn.whatsapp.net.",
+ "media-hkg1-2.cdn.whatsapp.net.",
+ "media-hkg4-1.cdn.whatsapp.net.",
+ "media-hkg4-2.cdn.whatsapp.net.",
+ "media-hou1-1.cdn.whatsapp.net.",
+ "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.",
+ "media-lax3-1.cdn.whatsapp.net.",
+ "media-lax3-2.cdn.whatsapp.net.",
+ "media-lga3-1.cdn.whatsapp.net.",
+ "media-lga3-2.cdn.whatsapp.net.",
+ "media-lhr6-1.cdn.whatsapp.net.",
+ "media-lhr6-2.cdn.whatsapp.net.",
+ "media-lhr8-1.cdn.whatsapp.net.",
+ "media-lhr8-2.cdn.whatsapp.net.",
+ "media-lim1-1.cdn.whatsapp.net.",
+ "media-lis1-1.cdn.whatsapp.net.",
+ "media-los2-1.cdn.whatsapp.net.",
+ "media-mad1-1.cdn.whatsapp.net.",
+ "media-mad2-1.cdn.whatsapp.net.",
+ "media-man2-1.cdn.whatsapp.net.",
+ "media-mct1-1.cdn.whatsapp.net.",
+ "media-mia3-1.cdn.whatsapp.net.",
+ "media-mia3-2.cdn.whatsapp.net.",
+ "media-mrs2-1.cdn.whatsapp.net.",
+ "media-msp1-1.cdn.whatsapp.net.",
+ "media-mty2-1.cdn.whatsapp.net.",
+ "media-muc2-1.cdn.whatsapp.net.",
+ "media-ord5-1.cdn.whatsapp.net.",
+ "media-ord5-2.cdn.whatsapp.net.",
+ "media-otp1-1.cdn.whatsapp.net.",
+ "media-qro1-1.cdn.whatsapp.net.",
+ "media-qro1-2.cdn.whatsapp.net.",
+ "media-scl2-1.cdn.whatsapp.net.",
+ "media-sea1-1.cdn.whatsapp.net.",
+ "media-sin6-1.cdn.whatsapp.net.",
+ "media-sin6-2.cdn.whatsapp.net.",
+ "media-sin6-3.cdn.whatsapp.net.",
+ "media-sin6-4.cdn.whatsapp.net.",
+ "media-sjc3-1.cdn.whatsapp.net.",
+ "media-sof1-1.cdn.whatsapp.net.",
+ "media-sof1-2.cdn.whatsapp.net.",
+ "media-waw2-1.cdn.whatsapp.net.",
+ "media-waw2-2.cdn.whatsapp.net.",
+ "media-xsp1-1.cdn.whatsapp.net.",
+ "media-xsp1-2.cdn.whatsapp.net.",
+ "media-xsp1-3.cdn.whatsapp.net.",
+ "media-xsp2-1.cdn.whatsapp.net.",
+ "media-xxc1-1.cdn.whatsapp.net.",
+ "media.blooket.com.multicdn.cloudinary.com.",
+ "media.crocs.com.",
+ "media.formula1.com.",
+ "media.graphassets.com.",
+ "media.ringcentral.com.",
+ "media.superhuman.com.",
+ "mediadelivery.net.",
+ "mediav.com.",
+ "medium.com.",
+ "medline0-my.sharepoint.com.",
+ "melbourne.remotepc.com.",
+ "memphis.remotepc.com.",
+ "metrics-dre.dt.dbankcloud.cn.",
+ "metrics-dre.dt.dbankcloud.com.",
+ "metrics5.data.hicloud.com.",
+ "mexicocity.remotepc.com.",
+ "mf.b37mrtl.ru.",
+ "mgtv.com.",
+ "miami.remotepc.com.",
+ "miami2.remotepc.com.",
+ "miami3.remotepc.com.",
+ "miami4.remotepc.com.",
+ "mib2clu8.car-cloud-cn.net.",
+ "microad.jp.",
+ "microchiptechnology-my.sharepoint.com.",
+ "microchiptechnology.sharepoint.com.",
+ "microsoft-my.sharepoint.com.",
+ "microvirt.com.",
+ "mid4.linkedin.com.",
+ "milan.remotepc.com.",
+ "milestoneinternet.com.cdn.cloudflare.net.",
+ "milwaukeetool-my.sharepoint.com.",
+ "milwaukeetool.com.",
+ "milwaukeetool.sharepoint.com.",
+ "mimir2.vivaldi.com.",
+ "min-api.cryptocompare.com.",
+ "mini.browser.360.cn.",
+ "mintkeyboard.com.",
+ "mirror.centos.iad1.serverforge.org.",
+ "mirror.fcix.net.",
+ "mirror.lstn.net.",
+ "mirrors.rockylinux.org.",
+ "mitek-my.sharepoint.com.",
+ "mixi.media.",
+ "mizuhogroup-my.sharepoint.com.",
+ "mm-mm.bing.net.trafficmanager.net.",
+ "mm.zhangchu.net.",
+ "mms.mckesson.com.",
+ "mn365-my.sharepoint.com.",
+ "mn365.sharepoint.com.",
+ "mno.lgaiwmc1d.com.",
+ "mobile-bank.cdn-tinkoff.ru.",
+ "mobile-collector.newrelic.com.cdn.cloudflare.net.",
+ "mobile.bereal.com.",
+ "mobile.shuzilm.cn.",
+ "mobile.useinsider.com.",
+ "mobiledataplan-pa.googleapis.com.",
+ "mobilelog.upqzfile.com.",
+ "mobilemaps-pa-gz.googleapis.com.",
+ "mobilemaps.googleapis.com.",
+ "modelportrait.xiaohongshu.com.",
+ "modesto.remotepc.com.",
+ "molor-app-logs-default.ap-southeast-1.log.aliyuncs.com.",
+ "moni-onrt-stsdk.vivo.com.cn.",
+ "monitor.fraudblocker.com.",
+ "monitoring.getelevar.com.",
+ "monitoring.worksighted.com.",
+ "monsterenergycorp-my.sharepoint.com.",
+ "montage-updates.displaynote.com.",
+ "monticello.remotepc.com.",
+ "montreal.remotepc.com.",
+ "motiondetection-us-1d.oss-us-west-1.aliyuncs.com.",
+ "motiondetection-us.oss-us-west-1.aliyuncs.com.",
+ "mottandbow.com.",
+ "mouser.com.",
+ "moviead55.ru.",
+ "mp.360.cn.",
+ "mp.midasbuy.com.",
+ "mp.theepochtimes.com.",
+ "mpsaz-my.sharepoint.com.",
+ "mpsaz.sharepoint.com.",
+ "mpush-api.aliyun.com.",
+ "mrisoftware.com.",
+ "mrodevicemgr.officeapps.live.com.",
+ "ms1app.pb.com.",
+ "msch.f.360.cn.",
+ "msdl.microsoft.com.",
+ "msf.3g.qq.com.",
+ "msg-img-hk.oss-cn-hongkong.aliyuncs.com.",
+ "msg-intl.qy.net.",
+ "mstate-my.sharepoint.com.",
+ "msync-im1-sgp-ga.easemob.com.",
+ "mtb-app.quantummetric.com.",
+ "mtrace.qq.com.",
+ "mu.ariba.com.",
+ "mumbai.remotepc.com.",
+ "mumu.nie.netease.com.",
+ "munich.remotepc.com.",
+ "muscache.cn.",
+ "musicps.p2p.qq.com.",
+ "musicpunch.p2p.qq.com.",
+ "mvconf.f.360.cn.",
+ "mvconf.uk.cloud.360safe.com.",
+ "mvm.snapchat.com.",
+ "mx-vcode-od.vivoglobal.com.",
+ "mx.amx.rcs.telephony.goog.",
+ "mxp-pusa01.app.blackbaud.net.",
+ "mxptint.net.",
+ "my.dealersocket.com.",
+ "my.getadmiral.com.",
+ "my.jbi.global.",
+ "my.microsoftpersonalcontent.com.",
+ "my.nalpeiron.com.",
+ "mydigitalspace.sharepoint.com.",
+ "mydrive.connect.aig.",
+ "myidb2b.cardinalhealth.com.",
+ "myisolved.com.",
+ "mylonestar-my.sharepoint.com.",
+ "myou.cvte.com.",
+ "myqcloud.com.",
+ "mystery-game-tile.poki.io.",
+ "myvscloud.com.",
+ "myweblogon.com.",
+ "mywebsitebuilder.com.",
+ "myworkdaycdn.com.cn.",
+ "n.gameads.io.",
+ "n13.ultipro.com.",
+ "n21.ultipro.com.",
+ "n21c.ultipro.com.",
+ "n22.ultipro.com.",
+ "n32.ultipro.com.",
+ "n33.ultipro.com.",
+ "n34.ultipro.com.",
+ "n35.ultipro.com.",
+ "na2.chat.si.riotgames.com.",
+ "najva.com.",
+ "namequery.com.",
+ "naperville.remotepc.com.",
+ "nashville.remotepc.com.",
+ "nationalheritageacademies-my.sharepoint.com.",
+ "nationalmap.gov.",
+ "nationalreview.com.",
+ "nationworldnews.com.",
+ "nativecos.com.",
+ "nc.com.",
+ "ncentral.centrexit.com.",
+ "ncjb-my.sharepoint.com.",
+ "nearme.com.cn.",
+ "nechicago.remotepc.com.",
+ "neonataltherapists.com.",
+ "net.multicdn.cloudinary.com.",
+ "netapp-my.sharepoint.com.",
+ "netapp.sharepoint.com.",
+ "netease.com.",
+ "netease.im.",
+ "netpop.app.",
+ "netpresenter.com.",
+ "netsolssl.com.",
+ "new.adblockplus.org.",
+ "newcontinuum.net.",
+ "newoldstamp.com.",
+ "neworleans.remotepc.com.",
+ "newrepublic.com.",
+ "news-abroad.vivo.com.",
+ "news-af.feednews.com.",
+ "news-client.apple.com.",
+ "news-events.apple.com.",
+ "news-global.cloud.",
+ "news-nar-aud.apple.com.",
+ "news-sports-events.apple.com.",
+ "newsletter-edge.apple.com.",
+ "newsroom.bi.",
+ "newyork.remotepc.com.",
+ "newyork2.remotepc.com.",
+ "newyork3.remotepc.com.",
+ "nex.163.com.",
+ "nexpart.com.",
+ "nexstar.amp.permutive.com.",
+ "nexus2wlb.com.",
+ "nexx360.io.",
+ "nfm365-my.sharepoint.com.",
+ "nfm365.sharepoint.com.",
+ "ng1.angus.mrisoftware.com.",
+ "ngb.haplat.net.",
+ "nhshumanservices423-my.sharepoint.com.",
+ "nice-team.net.",
+ "nie.netease.com.",
+ "nieuwsblad.be.",
+ "nike.com.multicdn.cloudinary.com.",
+ "nio365-my.sharepoint.com.",
+ "nitropay.com.",
+ "nkcsd-my.sharepoint.com.",
+ "nmhealth-my.sharepoint.com.",
+ "nmhealth.sharepoint.com.",
+ "noc.computerhelpnj.com.",
+ "node.setupad.com.",
+ "nordcurrent.com.",
+ "norma-external-collect.meizu.com.",
+ "northcentralus-gas.guestconfiguration.azure.com.",
+ "notes-analytics-events.apple.com.",
+ "notes.services.box.com.",
+ "notifications.bitwarden.com.",
+ "novaicare.com.",
+ "novel.itoon.org.",
+ "nps.gov.",
+ "ns-cloud-a1.googledomains.com.",
+ "ns-cloud-a2.googledomains.com.",
+ "ns-cloud-a3.googledomains.com.",
+ "ns-cloud-a4.googledomains.com.",
+ "ns-cloud-b1.googledomains.com.",
+ "ns-cloud-b2.googledomains.com.",
+ "ns-cloud-b3.googledomains.com.",
+ "ns-cloud-b4.googledomains.com.",
+ "ns-cloud-c1.googledomains.com.",
+ "ns-cloud-c2.googledomains.com.",
+ "ns-cloud-c3.googledomains.com.",
+ "ns-cloud-c4.googledomains.com.",
+ "ns-cloud-d1.googledomains.com.",
+ "ns-cloud-d2.googledomains.com.",
+ "ns-cloud-d3.googledomains.com.",
+ "ns-cloud-d4.googledomains.com.",
+ "ns-cloud-e1.googledomains.com.",
+ "ns-cloud-e2.googledomains.com.",
+ "ns-cloud-e3.googledomains.com.",
+ "ns-cloud-e4.googledomains.com.",
+ "ns.aliyuncs.com.",
+ "ns.identrust.com.",
+ "ns0105.secondary.cloudflare.com.",
+ "ns0160.secondary.cloudflare.com.",
+ "ns1.a0.impervasecuredns.net.",
+ "ns1.cloudflare.net.",
+ "ns1.digitalocean.com.",
+ "ns1.g.aaplimg.com.",
+ "ns1.google.com.",
+ "ns1.identrust.com.",
+ "ns2.cloudflare.net.",
+ "ns2.g.aaplimg.com.",
+ "ns2.google.com.",
+ "ns3.24shells.net.",
+ "ns3.cloudflare.net.",
+ "ns3.g.aaplimg.com.",
+ "ns3.google.com.",
+ "ns4.24shells.net.",
+ "ns4.cloudflare.net.",
+ "ns4.g.aaplimg.com.",
+ "ns4.google.com.",
+ "ns5.cloudflare.net.",
+ "nsa.nalpeiron.com.",
+ "nsatc.net.",
+ "nsl.lenovo.com.cn.",
+ "ntes53.netease.com.",
+ "ntp.aliyun.com.",
+ "ntp.arlo.com.",
+ "ntp.arlo.com.cdn.cloudflare.net.",
+ "ntp.org.cn.",
+ "ntp1.aliyun.com.",
+ "ntp2.aliyun.com.",
+ "ntp3.aliyun.com.",
+ "ntp4.aliyun.com.",
+ "ntp5.aliyun.com.",
+ "nttlimited-my.sharepoint.com.",
+ "nttlimited.sharepoint.com.",
+ "nvu-prd.mqtt.ivanticloud.com.",
+ "nw14.ultipro.com.",
+ "nw16.ultipro.com.",
+ "nwr.mmcdn.com.",
+ "nwr.static.mmcdn.com.",
+ "nwsalert.onelouder.com.",
+ "nysif-my.sharepoint.com.",
+ "o1.d.meituan.net.",
+ "o300810.mp.lura.live.",
+ "oauth-analytics.ascendlearning.com.",
+ "obe0-my.sharepoint.com.",
+ "obihai.telephony.goog.",
+ "obs.ap-southeast-3.myhuaweicloud.com.",
+ "obsproject.com.",
+ "obus-dc20058-cn.heytapmobi.com.",
+ "obus-dc20123-cn.heytapmobi.com.",
+ "obus-dc20157-cn.heytapmobi.com.",
+ "obus-dctech-cn.heytapmobi.com.",
+ "oc1.chat.si.riotgames.com.",
+ "oc2vjq-cdn-settings.appsflyersdk.com.",
+ "oclc.org.",
+ "ocloud.oppomobile.com.",
+ "ocps-xfer.kronos.net.",
+ "ocsen-slb.com.",
+ "ocsp.identrust.com.",
+ "ocsp.wosign.com.",
+ "ocsredir.officeapps.live.com.",
+ "odc.osi.office365.us.",
+ "odw7bf.dood.video.",
+ "oec22-normal-alisg.tokopediax.com.",
+ "oec22-normal-useast1a.tokopediax.com.",
+ "office.microsoft.com.",
+ "office365lds-my.sharepoint.com.",
+ "office365lds.sharepoint.com.",
+ "ogma.bereal.com.",
+ "ok12-custom-crtrs.okta.com.",
+ "ok14-custom-crtrs.okta.com.",
+ "ok7-crtrs.tng.okta.com.",
+ "ok7-custom-crtrs.okta.com.",
+ "okko.tv.",
+ "olatheschoolsorg-my.sharepoint.com.",
+ "olatheschoolsorg.sharepoint.com.",
+ "ollama.com.",
+ "omats-my.sharepoint.com.",
+ "omats.sharepoint.com.",
+ "omiapp.me.",
+ "omitech.site.",
+ "omnihotels-my.sharepoint.com.",
+ "on-hwapps-o.api.leiniao.com.",
+ "onecms-res.cloudinary.com.",
+ "onedrive.live.com.",
+ "oneharman-my.sharepoint.com.",
+ "oneharman.sharepoint.com.",
+ "onekey1.cmpassport.com.",
+ "oneplus.net.",
+ "onethingpcs.com.",
+ "onezapp.com.",
+ "onlinewebfonts.com.",
+ "op.mykonf.com.",
+ "opamarketplace.com.",
+ "open.acgnxtracker.com.",
+ "open.acgtracker.com.",
+ "open.demonii.com.",
+ "open.oppomobile.com.",
+ "opencmp.net.",
+ "opencolo.mm.fcix.net.",
+ "opendsp.ru.",
+ "openlane.cyberhaven.io.",
+ "openrice.com.",
+ "openwebmedia.com.",
+ "opex-service-cn.allawntech.com.",
+ "oppo.com.",
+ "oppomobile.com.",
+ "optimize.ulinq.asia.",
+ "optimize.urekamedia.com.",
+ "optimizely.com.",
+ "optioncare-my.sharepoint.com.",
+ "or-mirror.iwebfusion.net.",
+ "orangeusdorg-my.sharepoint.com.",
+ "oregon.remotepc.com.",
+ "origin.fe-image-cache-ttp.useast8.byteglb.com.",
+ "orlando.remotepc.com.",
+ "osaka.remotepc.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-enet.aliyuncs.com.",
+ "oss-eu-central-1.aliyuncs.com.",
+ "oss-us-east-1.aliyuncs.com.",
+ "oss-us-west-1.aliyuncs.com.",
+ "ota.lenovo.com.",
+ "otc.t-systems.com.",
+ "ott.deepl.com.",
+ "oval.id.",
+ "overleaf.com.",
+ "overleafusercontent.com.",
+ "oversea-master-log.ap-southeast-1.log.aliyuncs.com.",
+ "overseasccl-a.haplat.net.",
+ "overseasccl-b.haplat.net.",
+ "overseasccl-c.haplat.net.",
+ "overseasccl-major-a.haplat.net.",
+ "overseasccl-major-b.haplat.net.",
+ "overseasccl-major-c.haplat.net.",
+ "ovh.maxhost.io.",
+ "oxyinc-my.sharepoint.com.",
+ "p-wonderidea-rdr.us-east-1.log.aliyuncs.com.",
+ "p.adlooxtracking.com.",
+ "p.placed.com.",
+ "p.vivo.com.cn.",
+ "p0-pu-private-useast8.tiktokv.com.",
+ "p107609.cedexis-test.com.",
+ "p107610.cedexis-test.com.",
+ "p107611.cedexis-test.com.",
+ "p109477.cedexis-test.com.",
+ "p109522.cedexis-test.com.",
+ "p14-buy.itunes.apple.com.",
+ "p17-buy.itunes.apple.com.",
+ "p17000.cedexis-test.com.",
+ "p20304.cedexis-test.com.",
+ "p20305.cedexis-test.com.",
+ "p20306.cedexis-test.com.",
+ "p20307b.cedexis-test.com.",
+ "p20308b.cedexis-test.com.",
+ "p20309.cedexis-test.com.",
+ "p20310.cedexis-test.com.",
+ "p20311.cedexis-test.com.",
+ "p20314.cedexis-test.com.",
+ "p20315.cedexis-test.com.",
+ "p25-buy.itunes.apple.com.",
+ "p27-buy.itunes.apple.com.",
+ "p2p-cal-2.anker-in.com.",
+ "p2p-cal.anker-in.com.",
+ "p2p-ohi-2.anker-in.com.",
+ "p2p-par.anker-in.com.",
+ "p2p-sgp.anker-in.com.",
+ "p2p-vir.anker-in.com.",
+ "p2p.qq.com.",
+ "p2p2.cloudbirds.cn.",
+ "p2p3.cloudbirds.cn.",
+ "p2pm-ali.reolink.com.",
+ "p2psy2.io.mi.com.",
+ "p30605.cedexis-test.com.",
+ "p31-buy.itunes.apple.com.",
+ "p33231.cedexis-test.com.",
+ "p33232.cedexis-test.com.",
+ "p33233.cedexis-test.com.",
+ "p33234.cedexis-test.com.",
+ "p33235.cedexis-test.com.",
+ "p33236.cedexis-test.com.",
+ "p33237.cedexis-test.com.",
+ "p33238.cedexis-test.com.",
+ "p33239.cedexis-test.com.",
+ "p33240.cedexis-test.com.",
+ "p33241.cedexis-test.com.",
+ "p33242.cedexis-test.com.",
+ "p33243.cedexis-test.com.",
+ "p33244.cedexis-test.com.",
+ "p33245.cedexis-test.com.",
+ "p33246.cedexis-test.com.",
+ "p33247.cedexis-test.com.",
+ "p33248.cedexis-test.com.",
+ "p33249.cedexis-test.com.",
+ "p33250.cedexis-test.com.",
+ "p33251.cedexis-test.com.",
+ "p33252.cedexis-test.com.",
+ "p33253.cedexis-test.com.",
+ "p33254.cedexis-test.com.",
+ "p33255.cedexis-test.com.",
+ "p33256.cedexis-test.com.",
+ "p33257.cedexis-test.com.",
+ "p33258.cedexis-test.com.",
+ "p33259.cedexis-test.com.",
+ "p33260.cedexis-test.com.",
+ "p34854.cedexis-test.com.",
+ "p34855.cedexis-test.com.",
+ "p34856.cedexis-test.com.",
+ "p34857.cedexis-test.com.",
+ "p34858.cedexis-test.com.",
+ "p34859.cedexis-test.com.",
+ "p34860.cedexis-test.com.",
+ "p35-buy.itunes.apple.com.",
+ "p35883.cedexis-test.com.",
+ "p36-mailws.icloud.com.",
+ "p39604.cedexis-test.com.",
+ "p3a-creative.brave.com.",
+ "p3a-json.brave.com.",
+ "p40-buy.itunes.apple.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.",
+ "p41-buy.itunes.apple.com.",
+ "p41237.cedexis-test.com.",
+ "p41238.cedexis-test.com.",
+ "p41259.cedexis-test.com.",
+ "p41267.cedexis-test.com.",
+ "p41268.cedexis-test.com.",
+ "p41273.cedexis-test.com.",
+ "p41274.cedexis-test.com.",
+ "p41905.cedexis-test.com.",
+ "p42051.cedexis-test.com.",
+ "p42052.cedexis-test.com.",
+ "p42053.cedexis-test.com.",
+ "p43671.cedexis-test.com.",
+ "p43707.cedexis-test.com.",
+ "p43773.cedexis-test.com.",
+ "p43774.cedexis-test.com.",
+ "p43775.cedexis-test.com.",
+ "p43776.cedexis-test.com.",
+ "p48434.cedexis-test.com.",
+ "p48435.cedexis-test.com.",
+ "p48436.cedexis-test.com.",
+ "p49-buy.itunes.apple.com.",
+ "p4p.arenabg.com.",
+ "p51-buy.itunes.apple.com.",
+ "p52066.cedexis-test.com.",
+ "p53-buy.itunes.apple.com.",
+ "p56745.cedexis-test.com.",
+ "p56746.cedexis-test.com.",
+ "p56747.cedexis-test.com.",
+ "p76593.cedexis-test.com.",
+ "p8-buy.itunes.apple.com.",
+ "p86072.cedexis-test.com.",
+ "p86075.cedexis-test.com.",
+ "p86077.cedexis-test.com.",
+ "p92860.cedexis-test.com.",
+ "p92861.cedexis-test.com.",
+ "p92862.cedexis-test.com.",
+ "p95707.cedexis-test.com.",
+ "p95708.cedexis-test.com.",
+ "p95711.cedexis-test.com.",
+ "p95717.cedexis-test.com.",
+ "p95721.cedexis-test.com.",
+ "p95722.cedexis-test.com.",
+ "p95723.cedexis-test.com.",
+ "p95724.cedexis-test.com.",
+ "p95725.cedexis-test.com.",
+ "p95726.cedexis-test.com.",
+ "p95727.cedexis-test.com.",
+ "p95728.cedexis-test.com.",
+ "paccarnet.sharepoint.com.",
+ "paducahix.mm.fcix.net.",
+ "pai.googlezip.net.",
+ "palermo.remotepc.com.",
+ "palm.tech.",
+ "panorama.wixapps.net.",
+ "panthers-my.sharepoint.com.",
+ "paramount.com.",
+ "paris.remotepc.com.",
+ "parkhill1-my.sharepoint.com.",
+ "partition.enterprise.com.",
+ "partnerboost.com.",
+ "partners-api.pinterest.com.",
+ "pasadena.remotepc.com.",
+ "passportalmsp.com.",
+ "pay.datatrans.com.",
+ "paycorinc-my.sharepoint.com.",
+ "paylocity1-my.sharepoint.com.",
+ "payment.api.speechify.com.",
+ "payments.worldpay.com.",
+ "pbe1.chat.si.riotgames.com.",
+ "pbs-us-east.ay.delivery.",
+ "pbs.btloader.com.",
+ "pbsj.bricks-co.com.",
+ "pc-store.lenovomm.cn.",
+ "pcdn.brave.com.",
+ "pd.cdnwidget.com.",
+ "pdengagementapi.trafficmanager.net.",
+ "pdfforge.org.",
+ "pdrnetwork-my.sharepoint.com.",
+ "penngaming-my.sharepoint.com.",
+ "penngaming.sharepoint.com.",
+ "penskeauto.sharepoint.com.",
+ "peopleadmin.com.",
+ "pepsico-my.sharepoint.com.",
+ "pepsico.sharepoint.com.",
+ "pepsico.zoom.us.",
+ "perf-eu1.hsforms.com.",
+ "permutive.arstechnica.com.",
+ "permutive.businessinsider.com.",
+ "permutive.com.",
+ "permutive.newyorker.com.",
+ "permutive.wired.com.",
+ "perr.brightvpn.com.",
+ "perrigo-my.sharepoint.com.",
+ "pf.intuit.com.",
+ "pfgsales-my.sharepoint.com.",
+ "pfgsales.sharepoint.com.",
+ "pgsth.kargo.com.",
+ "ph.globe.rcs.telephony.goog.",
+ "pharos.studyquicks.com.",
+ "phoenix.remotepc.com.",
+ "phoenix2.remotepc.com.",
+ "phonehome.hazelcast.com.",
+ "phx02pap001.storage.live.com.",
+ "phx02pap002.storage.live.com.",
+ "phx02pap003.storage.live.com.",
+ "phx02pap004.storage.live.com.",
+ "phx02pap005.storage.live.com.",
+ "phx02pap006.storage.live.com.",
+ "phx02pap008.storage.live.com.",
+ "pi2850.ci.managedwhitelisting.com.",
+ "piano.io.",
+ "picsart.com.cdn.cloudflare.net.",
+ "pie-api.io.",
+ "ping.citrix.com.",
+ "ping.getadblock.com.",
+ "pingler.com.",
+ "pingmesh.bigo.sg.",
+ "piojm.tech.",
+ "pis.alicdn.com.",
+ "pittsburgh.remotepc.com.",
+ "pix.cdnwidget.com.",
+ "pixel-sync.trafficmanager.net.",
+ "pixel.gliacloud.com.",
+ "pjcr-my.sharepoint.com.",
+ "pkgconnect-my.sharepoint.com.",
+ "pla-prod-scu-apim-01.azure-api.net.",
+ "playstream.media.",
+ "plrm.zone.",
+ "plrsrvcs.com.",
+ "pm.geniusmonkey.com.",
+ "poizon.com.",
+ "polarisind-my.sharepoint.com.",
+ "polarisind.sharepoint.com.",
+ "polling.zoom.us.",
+ "polyfill.archive.org.",
+ "popt.in.",
+ "portal.myweblogon.com.",
+ "portals.mobi.",
+ "portland.remotepc.com.",
+ "portlandoregongov-my.sharepoint.com.",
+ "post.ksosoft.com.",
+ "posthog.com.",
+ "pov.spectrum.net.",
+ "pow7.com.",
+ "powerpoint-collab.officeapps.live.com.",
+ "pp.topgblzzz.com.",
+ "ppgames.net.",
+ "pps.feednews.com.",
+ "pragmaticplay.net.",
+ "prebid-la.casalemedia.com.",
+ "prebid-sj.casalemedia.com.",
+ "prebid-va.casalemedia.com.",
+ "prebid.trustedstack.com.",
+ "prebidserver.pixfuture.com.",
+ "precisionmedicinegroup.sharepoint.com.",
+ "prem-pt1.365lpodds.com.",
+ "prem-pt2.365lpodds.com.",
+ "prem-pt3.365lpodds.com.",
+ "premierhealth-my.sharepoint.com.",
+ "premium.xvpn.io.",
+ "printaudit.com.",
+ "printfriendly.com.",
+ "pro-swishapps-aks-tm.trafficmanager.net.",
+ "procore.com.",
+ "prod-client-api.v.aaplimg.com.",
+ "prod-default.lb.logrocket.network.",
+ "prod-event-relay-api.v.aaplimg.com.",
+ "prod-event-relay-books-api.v.aaplimg.com.",
+ "prod-event-relay-notes-api.v.aaplimg.com.",
+ "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-newsletter-edge.v.aaplimg.com.",
+ "prod-weather-widget-event-gateway.v.aaplimg.com.",
+ "prod.api.letsencrypt.org.",
+ "prod.uno.demonware.net.",
+ "production.kabutoservices.com.",
+ "promega-my.sharepoint.com.",
+ "protontech.ch.",
+ "protonvpn.com.",
+ "provaltech.com.",
+ "proxy-safebrowsing.googleapis.com.",
+ "proxy.mob.maps.yandex.net.",
+ "ps.namequery.com.",
+ "psav-my.sharepoint.com.",
+ "psav.sharepoint.com.",
+ "pshud.365lpodds.com.",
+ "pshud.365lpodds.com.cdn.cloudflare.net.",
+ "pths209-my.sharepoint.com.",
+ "pub.affilimateapis.com.",
+ "pub.network.",
+ "public.bn.files.1drv.com.",
+ "public.boxcloud.com.",
+ "public.dm.files.1drv.com.",
+ "public.sn.files.1drv.com.",
+ "publicfaas.vasdgame.com.",
+ "publictracker.xyz.",
+ "publisher.liveperson.net.",
+ "puffer.6.401402081.west-gcloud.codm.activision.com.",
+ "puhsd210-my.sharepoint.com.",
+ "puhsd210.sharepoint.com.",
+ "pull-flv-f58-tt03.fcdn.eu.tiktokcdn.com.",
+ "punch.p2p.qq.com.",
+ "pusd11net-my.sharepoint.com.",
+ "push-row.zui.com.",
+ "pushcrew.com.",
+ "pushmac.flexibits.com.",
+ "pushmart.net.",
+ "pushnetwork.com.",
+ "pushtimize.com.",
+ "pushtrs7.push.hicloud.com.",
+ "puswdsprmtprs.dealersocket.com.",
+ "puv.tt.browser.360.cn.",
+ "pw.mediav.com.",
+ "pwa.zoom.us.",
+ "pwaweblogin.wmpvp.com.",
+ "pwcgov-my.sharepoint.com.",
+ "px4.ads.linkedin.com.",
+ "qa.sockets.stackexchange.com.",
+ "qagpublic.qg1.apps.qualys.ca.",
+ "qagpublic.qg1.apps.qualys.co.uk.",
+ "qagpublic.qg1.apps.qualys.com.",
+ "qagpublic.qg1.apps.qualys.eu.",
+ "qagpublic.qg2.apps.qualys.com.",
+ "qagpublic.qg2.apps.qualys.eu.",
+ "qagpublic.qg3.apps.qualys.com.",
+ "qagpublic.qg4.apps.qualys.com.",
+ "qfp.intuit.com.",
+ "qikify.com.",
+ "qiniudns.com.",
+ "qookkagames.com.",
+ "qorvo-my.sharepoint.com.",
+ "qpic.cn.",
+ "qq.com.cn.",
+ "qualys.ca.",
+ "qualys.com.",
+ "qualys.eu.",
+ "quantamagazine.org.",
+ "quebeccity.remotepc.com.",
+ "questdiagnostics.sharepoint.com.",
+ "questionpro.com.",
+ "quickcep.com.",
+ "quotemedia.com.",
+ "qurl.f.360.cn.",
+ "qvc.com.",
+ "qxwz.com.",
+ "r.ingest-lr.com.",
+ "r.intake-lr.com.",
+ "r.logr-ingest.com.",
+ "r.logrocket.io.",
+ "r.lr-hv-in.com.",
+ "r.lr-in-prod.com.",
+ "r.lr-in.com.",
+ "r.lr-ingest.com.",
+ "r.lr-ingest.io.",
+ "r.lr-intake.com.",
+ "r.superhuman.com.",
+ "r1---sn-a5mlrnll.c.2mdn.net.",
+ "r1---sn-ab5l6ndr.c.2mdn.net.",
+ "r1---sn-ab5l6nk6.c.2mdn.net.",
+ "r1---sn-ab5l6nkd.c.2mdn.net.",
+ "r1---sn-ab5l6nr6.c.2mdn.net.",
+ "r1---sn-ab5l6nrd.c.2mdn.net.",
+ "r1---sn-ab5l6nrk.c.2mdn.net.",
+ "r1---sn-ab5l6nrl.c.2mdn.net.",
+ "r1---sn-ab5l6nrs.c.2mdn.net.",
+ "r1---sn-ab5l6nrz.c.2mdn.net.",
+ "r1---sn-ab5sznld.c.2mdn.net.",
+ "r1---sn-ab5sznlk.c.2mdn.net.",
+ "r1---sn-ab5sznz6.c.2mdn.net.",
+ "r1---sn-ab5sznzd.c.2mdn.net.",
+ "r1---sn-ab5sznze.c.2mdn.net.",
+ "r1---sn-ab5sznzk.c.2mdn.net.",
+ "r1---sn-ab5sznzl.c.2mdn.net.",
+ "r1---sn-ab5sznzr.c.2mdn.net.",
+ "r1---sn-ab5sznzs.c.2mdn.net.",
+ "r1---sn-ab5sznzy.c.2mdn.net.",
+ "r1---sn-ab5sznzz.c.2mdn.net.",
+ "r1---sn-aigl6nzl.c.2mdn.net.",
+ "r1---sn-npoldn76.c.2mdn.net.",
+ "r1---sn-p5qddn7d.c.2mdn.net.",
+ "r1---sn-p5qddn7k.c.2mdn.net.",
+ "r1---sn-p5qlsn76.c.2mdn.net.",
+ "r1---sn-p5qlsnrl.c.2mdn.net.",
+ "r1---sn-p5qs7nsr.c.2mdn.net.",
+ "r1---sn-p5qs7nzk.c.2mdn.net.",
+ "r1---sn-q4fl6n6r.c.2mdn.net.",
+ "r1---sn-q4fl6n6s.c.2mdn.net.",
+ "r1---sn-q4fl6nds.c.2mdn.net.",
+ "r1---sn-q4fl6nsl.c.2mdn.net.",
+ "r1---sn-q4fl6nss.c.2mdn.net.",
+ "r1---sn-q4fl6nz7.c.2mdn.net.",
+ "r1---sn-q4flrne6.c.2mdn.net.",
+ "r1---sn-q4flrnld.c.2mdn.net.",
+ "r1---sn-q4flrnsd.c.2mdn.net.",
+ "r1---sn-q4flrnsk.c.2mdn.net.",
+ "r1---sn-vgqskn66.c.2mdn.net.",
+ "r1---sn-vgqskn6z.c.2mdn.net.",
+ "r1---sn-vgqsknek.c.2mdn.net.",
+ "r1---sn-vgqsknlr.c.2mdn.net.",
+ "r1---sn-vgqsknsk.c.2mdn.net.",
+ "r1---sn-vgqsknz7.c.2mdn.net.",
+ "r1---sn-vgqsknzl.c.2mdn.net.",
+ "r1---sn-vgqsknzr.c.2mdn.net.",
+ "r1---sn-vgqsknzy.c.2mdn.net.",
+ "r1---sn-vgqsrn66.c.2mdn.net.",
+ "r1---sn-vgqsrn67.c.2mdn.net.",
+ "r1---sn-vgqsrn6e.c.2mdn.net.",
+ "r1---sn-vgqsrn6l.c.2mdn.net.",
+ "r1---sn-vgqsrnlk.c.2mdn.net.",
+ "r1---sn-vgqsrns6.c.2mdn.net.",
+ "r1---sn-vgqsrnsd.c.2mdn.net.",
+ "r1---sn-vgqsrnsr.c.2mdn.net.",
+ "r1---sn-vgqsrnsy.c.2mdn.net.",
+ "r1---sn-vgqsrnz7.c.2mdn.net.",
+ "r1---sn-vgqsrnzk.c.2mdn.net.",
+ "r2---sn-a5mekn6k.c.2mdn.net.",
+ "r2---sn-ab5l6nk6.c.2mdn.net.",
+ "r2---sn-ab5l6nkd.c.2mdn.net.",
+ "r2---sn-ab5l6nr6.c.2mdn.net.",
+ "r2---sn-ab5l6nrd.c.2mdn.net.",
+ "r2---sn-ab5l6nrl.c.2mdn.net.",
+ "r2---sn-ab5l6nrr.c.2mdn.net.",
+ "r2---sn-ab5l6nrz.c.2mdn.net.",
+ "r2---sn-ab5sznld.c.2mdn.net.",
+ "r2---sn-ab5sznz6.c.2mdn.net.",
+ "r2---sn-ab5sznzd.c.2mdn.net.",
+ "r2---sn-ab5sznze.c.2mdn.net.",
+ "r2---sn-ab5sznzk.c.2mdn.net.",
+ "r2---sn-ab5sznzl.c.2mdn.net.",
+ "r2---sn-ab5sznzy.c.2mdn.net.",
+ "r2---sn-ab5sznzz.c.2mdn.net.",
+ "r2---sn-p5qddn7k.c.2mdn.net.",
+ "r2---sn-p5qddn7r.c.2mdn.net.",
+ "r2---sn-p5qlsnrr.c.2mdn.net.",
+ "r2---sn-q4fl6n66.c.2mdn.net.",
+ "r2---sn-q4fl6nds.c.2mdn.net.",
+ "r2---sn-q4fl6ns6.c.2mdn.net.",
+ "r2---sn-q4fl6nsy.c.2mdn.net.",
+ "r2---sn-q4fl6nz6.c.2mdn.net.",
+ "r2---sn-q4flrnel.c.2mdn.net.",
+ "r2---sn-q4flrnld.c.2mdn.net.",
+ "r2---sn-q4flrnle.c.2mdn.net.",
+ "r2---sn-q4fzen7y.c.2mdn.net.",
+ "r2---sn-q4fzene7.c.2mdn.net.",
+ "r2---sn-vgqskn66.c.2mdn.net.",
+ "r2---sn-vgqsknld.c.2mdn.net.",
+ "r2---sn-vgqsknlk.c.2mdn.net.",
+ "r2---sn-vgqsknzz.c.2mdn.net.",
+ "r2---sn-vgqsrn6e.c.2mdn.net.",
+ "r2---sn-vgqsrne6.c.2mdn.net.",
+ "r2---sn-vgqsrnls.c.2mdn.net.",
+ "r2---sn-vgqsrnlz.c.2mdn.net.",
+ "r2---sn-vgqsrnzd.c.2mdn.net.",
+ "r2---sn-vgqsrnzs.c.2mdn.net.",
+ "r2---sn-vgqsrnzz.c.2mdn.net.",
+ "r3---sn-ab5l6ndy.c.2mdn.net.",
+ "r3---sn-ab5l6nkd.c.2mdn.net.",
+ "r3---sn-ab5l6nr6.c.2mdn.net.",
+ "r3---sn-ab5l6nrd.c.2mdn.net.",
+ "r3---sn-ab5l6nrk.c.2mdn.net.",
+ "r3---sn-ab5l6nrl.c.2mdn.net.",
+ "r3---sn-ab5l6nrr.c.2mdn.net.",
+ "r3---sn-ab5l6nrs.c.2mdn.net.",
+ "r3---sn-ab5sznld.c.2mdn.net.",
+ "r3---sn-ab5sznz6.c.2mdn.net.",
+ "r3---sn-ab5sznze.c.2mdn.net.",
+ "r3---sn-ab5sznzk.c.2mdn.net.",
+ "r3---sn-ab5sznzs.c.2mdn.net.",
+ "r3---sn-ab5sznzy.c.2mdn.net.",
+ "r3---sn-ab5sznzz.c.2mdn.net.",
+ "r3---sn-p5qlsn7d.c.2mdn.net.",
+ "r3---sn-p5qs7nsr.c.2mdn.net.",
+ "r3---sn-q4fl6n6z.c.2mdn.net.",
+ "r3---sn-q4fl6nsk.c.2mdn.net.",
+ "r3---sn-q4fzen7l.c.2mdn.net.",
+ "r3---sn-q4fzen7s.c.2mdn.net.",
+ "r3---sn-q4fzene7.c.2mdn.net.",
+ "r3---sn-vgqskn6d.c.2mdn.net.",
+ "r3---sn-vgqskn6z.c.2mdn.net.",
+ "r3---sn-vgqsknlr.c.2mdn.net.",
+ "r3---sn-vgqsknzr.c.2mdn.net.",
+ "r3---sn-vgqsknzy.c.2mdn.net.",
+ "r3---sn-vgqsrnez.c.2mdn.net.",
+ "r3---sn-vgqsrnlk.c.2mdn.net.",
+ "r3---sn-vgqsrnsy.c.2mdn.net.",
+ "r3---sn-vgqsrnz7.c.2mdn.net.",
+ "r3---sn-vgqsrnzd.c.2mdn.net.",
+ "r3---sn-vgqsrnzz.c.2mdn.net.",
+ "r4---sn-ab5l6ndr.c.2mdn.net.",
+ "r4---sn-ab5l6nk6.c.2mdn.net.",
+ "r4---sn-ab5l6nkd.c.2mdn.net.",
+ "r4---sn-ab5l6nr6.c.2mdn.net.",
+ "r4---sn-ab5l6nrd.c.2mdn.net.",
+ "r4---sn-ab5l6nrk.c.2mdn.net.",
+ "r4---sn-ab5l6nrl.c.2mdn.net.",
+ "r4---sn-ab5l6nrr.c.2mdn.net.",
+ "r4---sn-ab5l6nrs.c.2mdn.net.",
+ "r4---sn-ab5l6nrz.c.2mdn.net.",
+ "r4---sn-ab5sznld.c.2mdn.net.",
+ "r4---sn-ab5sznzd.c.2mdn.net.",
+ "r4---sn-ab5sznze.c.2mdn.net.",
+ "r4---sn-ab5sznzl.c.2mdn.net.",
+ "r4---sn-ab5sznzr.c.2mdn.net.",
+ "r4---sn-ab5sznzs.c.2mdn.net.",
+ "r4---sn-ab5sznzy.c.2mdn.net.",
+ "r4---sn-ab5sznzz.c.2mdn.net.",
+ "r4---sn-nx57ynsz.c.2mdn.net.",
+ "r4---sn-p5qlsn7d.c.2mdn.net.",
+ "r4---sn-p5qlsn7l.c.2mdn.net.",
+ "r4---sn-q4fl6nds.c.2mdn.net.",
+ "r4---sn-q4fl6nsd.c.2mdn.net.",
+ "r4---sn-q4fl6nzy.c.2mdn.net.",
+ "r4---sn-q4flrnel.c.2mdn.net.",
+ "r4---sn-q4flrnld.c.2mdn.net.",
+ "r4---sn-vgqskn66.c.2mdn.net.",
+ "r4---sn-vgqskn6s.c.2mdn.net.",
+ "r4---sn-vgqskn6z.c.2mdn.net.",
+ "r4---sn-vgqsknld.c.2mdn.net.",
+ "r4---sn-vgqsknll.c.2mdn.net.",
+ "r4---sn-vgqsknlr.c.2mdn.net.",
+ "r4---sn-vgqsknse.c.2mdn.net.",
+ "r4---sn-vgqsknsk.c.2mdn.net.",
+ "r4---sn-vgqsknz7.c.2mdn.net.",
+ "r4---sn-vgqsknzd.c.2mdn.net.",
+ "r4---sn-vgqsknzk.c.2mdn.net.",
+ "r4---sn-vgqsknzl.c.2mdn.net.",
+ "r4---sn-vgqsknzy.c.2mdn.net.",
+ "r4---sn-vgqsknzz.c.2mdn.net.",
+ "r4---sn-vgqsrn6z.c.2mdn.net.",
+ "r4---sn-vgqsrnl6.c.2mdn.net.",
+ "r4---sn-vgqsrns6.c.2mdn.net.",
+ "r4---sn-vgqsrnsy.c.2mdn.net.",
+ "r4---sn-vgqsrnzd.c.2mdn.net.",
+ "r5---sn-ab5l6nk6.c.2mdn.net.",
+ "r5---sn-ab5l6nr6.c.2mdn.net.",
+ "r5---sn-ab5l6nrd.c.2mdn.net.",
+ "r5---sn-ab5l6nrk.c.2mdn.net.",
+ "r5---sn-ab5l6nrl.c.2mdn.net.",
+ "r5---sn-ab5l6nrs.c.2mdn.net.",
+ "r5---sn-ab5l6nrz.c.2mdn.net.",
+ "r5---sn-ab5sznly.c.2mdn.net.",
+ "r5---sn-ab5sznz6.c.2mdn.net.",
+ "r5---sn-ab5sznzd.c.2mdn.net.",
+ "r5---sn-ab5sznzk.c.2mdn.net.",
+ "r5---sn-ab5sznzl.c.2mdn.net.",
+ "r5---sn-ab5sznzr.c.2mdn.net.",
+ "r5---sn-ab5sznzs.c.2mdn.net.",
+ "r5---sn-ab5sznzy.c.2mdn.net.",
+ "r5---sn-ab5sznzz.c.2mdn.net.",
+ "r5---sn-npoe7nsk.c.2mdn.net.",
+ "r5---sn-p5qddn7d.c.2mdn.net.",
+ "r5---sn-p5qlsn6l.c.2mdn.net.",
+ "r5---sn-p5qlsn76.c.2mdn.net.",
+ "r5---sn-p5qs7nzk.c.2mdn.net.",
+ "r5---sn-p5qs7nzy.c.2mdn.net.",
+ "r5---sn-q4fl6ndz.c.2mdn.net.",
+ "r5---sn-q4flrnsd.c.2mdn.net.",
+ "r5---sn-q4fzen7y.c.2mdn.net.",
+ "r5---sn-vgqskn67.c.2mdn.net.",
+ "r5---sn-vgqskn6d.c.2mdn.net.",
+ "r5---sn-vgqskn6s.c.2mdn.net.",
+ "r5---sn-vgqsknes.c.2mdn.net.",
+ "r5---sn-vgqsknsk.c.2mdn.net.",
+ "r5---sn-vgqsknz6.c.2mdn.net.",
+ "r5---sn-vgqsknze.c.2mdn.net.",
+ "r5---sn-vgqsknzl.c.2mdn.net.",
+ "r5---sn-vgqsknzs.c.2mdn.net.",
+ "r5---sn-vgqsrn66.c.2mdn.net.",
+ "r5---sn-vgqsrn67.c.2mdn.net.",
+ "r5---sn-vgqsrn6e.c.2mdn.net.",
+ "r5---sn-vgqsrn6z.c.2mdn.net.",
+ "r5---sn-vgqsrned.c.2mdn.net.",
+ "r5---sn-vgqsrnek.c.2mdn.net.",
+ "r5---sn-vgqsrnld.c.2mdn.net.",
+ "r5---sn-vgqsrnls.c.2mdn.net.",
+ "r5---sn-vgqsrnlz.c.2mdn.net.",
+ "r5---sn-vgqsrnz6.c.2mdn.net.",
+ "r5---sn-vgqsrnzk.c.2mdn.net.",
+ "raccorp-my.sharepoint.com.",
+ "radar.cedexis.com.",
+ "radar.com.",
+ "raleigh.remotepc.com.",
+ "randomhouse.app.box.com.",
+ "rba-screen.healthsafe-id.com.",
+ "rba.onehealthcareid.com.",
+ "rbm-us.storage.googleapis.com.",
+ "rcs-acs-mcc510.jibe.google.com.",
+ "rcs-acs-tmobile-us.jibe.google.com.",
+ "rcs-copper-us.googleapis.com.",
+ "rcs-user-content-us.storage.googleapis.com.",
+ "rcs.telephony.goog.",
+ "rd.com.",
+ "realtime.arena.im.",
+ "realtime.luckyorange.com.",
+ "realtime.services.box.net.",
+ "recombee.com.",
+ "recruiting.ultipro.com.",
+ "recruiting2.ultipro.com.",
+ "reedelsevier.sharepoint.com.",
+ "reef.com.",
+ "reflector.makerbot.com.",
+ "regions.com.",
+ "registration.prap01.cmdagent.trafficmanager.net.",
+ "registration.prau01.cmdagent.trafficmanager.net.",
+ "registration.preu01.cmdagent.trafficmanager.net.",
+ "registration.prna01.cmdagent.trafficmanager.net.",
+ "regn-my.sharepoint.com.",
+ "regn.sharepoint.com.",
+ "rejuvenation.com.",
+ "relay.shhnowisnottheti.me.",
+ "remote-config.gslb.sgw.shopeemobile.com.",
+ "remote.control4.com.",
+ "remote.melonhead.me.",
+ "repo.zabbix.com.",
+ "republicservices-my.sharepoint.com.",
+ "requality.android.shouji.sogou.com.",
+ "request-global.czilladx.com.",
+ "resideo.com.",
+ "resource.digitalinsight.com.",
+ "restproxy-analytics.ascendlearning.com.",
+ "restrict.youtube.com.",
+ "restrictmoderate.youtube.com.",
+ "retailrocket.net.",
+ "retailstarbucks1com-my.sharepoint.com.",
+ "retailstarbucks1com.sharepoint.com.",
+ "retcode-us-west-1.arms.aliyuncs.com.",
+ "rethinkad.com.",
+ "retinavue.net.",
+ "reverso.net.",
+ "rexel.sharepoint.com.",
+ "rhmail-my.sharepoint.com.",
+ "ri9864.ci.managedwhitelisting.com.",
+ "richrelevance.com.",
+ "ridge.com.",
+ "rivergame.net.",
+ "rivhs-my.sharepoint.com.",
+ "rl.progressive.com.",
+ "rl.quantummetric.com.",
+ "rmm.acctek.com.",
+ "rmm.aunalytics.com.",
+ "rmm.creativeplanning.com.",
+ "rmm2.jmark.com.",
+ "rms-dra.platform.dbankcloud.com.",
+ "rn-resource-app.xiaohongshu.com.",
+ "roberthalf-my.sharepoint.com.",
+ "roberthalf.sharepoint.com.",
+ "roborock.com.",
+ "rocketsutoledo-my.sharepoint.com.",
+ "rockwellautomation-my.sharepoint.com.",
+ "rockwellautomation.sharepoint.com.",
+ "rockylinux.org.",
+ "rogueone.aristotleinsight.com.",
+ "romsp-unifyconfig.vivo.com.cn.",
+ "router.teamviewer.com.",
+ "roxy.azurefd.net.",
+ "rpiexchange-my.sharepoint.com.",
+ "rpt.cedexis.com.",
+ "rq.wh.cmcm.com.",
+ "rr1---sn-02o-ao3e.googlevideo.com.",
+ "rr1---sn-0nnpbo5a-bggl.googlevideo.com.",
+ "rr1---sn-0op8v4h5pox-cbgl.googlevideo.com.",
+ "rr1---sn-2imern76.googlevideo.com.",
+ "rr1---sn-2imern76.gvt1.com.",
+ "rr1---sn-2imern7d.googlevideo.com.",
+ "rr1---sn-2imern7d.gvt1.com.",
+ "rr1---sn-2imeyn7k.googlevideo.com.",
+ "rr1---sn-2napbiu-p5ie.googlevideo.com.",
+ "rr1---sn-2napbiu-p5ie.gvt1.com.",
+ "rr1---sn-2oaig5-55.googlevideo.com.",
+ "rr1---sn-2pmxapm0n-gpje.googlevideo.com.",
+ "rr1---sn-2pmxapm0n-gpjl.googlevideo.com.",
+ "rr1---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr1---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
+ "rr1---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
+ "rr1---sn-2vgu0b5auxaxjvh-v2vk.googlevideo.com.",
+ "rr1---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
+ "rr1---sn-30a7rne6.googlevideo.com.",
+ "rr1---sn-30a7rned.googlevideo.com.",
+ "rr1---sn-30a7rnek.googlevideo.com.",
+ "rr1---sn-30a7rner.googlevideo.com.",
+ "rr1---sn-30a7ynek.googlevideo.com.",
+ "rr1---sn-30a7yner.googlevideo.com.",
+ "rr1---sn-30a7ynl7.googlevideo.com.",
+ "rr1---sn-3jpm-hjpe.googlevideo.com.",
+ "rr1---sn-3n4pcxg-pjul.googlevideo.com.",
+ "rr1---sn-3n4pcxg-pjuz.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.",
+ "rr1---sn-4g5e6nze.googlevideo.com.",
+ "rr1---sn-4g5e6nzl.googlevideo.com.",
+ "rr1---sn-4g5e6nzs.googlevideo.com.",
+ "rr1---sn-4g5e6nzz.googlevideo.com.",
+ "rr1---sn-4g5edn6k.googlevideo.com.",
+ "rr1---sn-4g5edn6y.googlevideo.com.",
+ "rr1---sn-4g5ednd7.googlevideo.com.",
+ "rr1---sn-4g5edndd.googlevideo.com.",
+ "rr1---sn-4g5ednde.googlevideo.com.",
+ "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.",
+ "rr1---sn-4g5ednld.googlevideo.com.",
+ "rr1---sn-4g5ednly.googlevideo.com.",
+ "rr1---sn-4g5edns6.googlevideo.com.",
+ "rr1---sn-4g5edns7.googlevideo.com.",
+ "rr1---sn-4g5ednsd.googlevideo.com.",
+ "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-4g5ednsz.googlevideo.com.",
+ "rr1---sn-4g5ednz7.googlevideo.com.",
+ "rr1---sn-4g5lzne6.googlevideo.com.",
+ "rr1---sn-4g5lzned.googlevideo.com.",
+ "rr1---sn-4g5lznek.googlevideo.com.",
+ "rr1---sn-4g5lzner.googlevideo.com.",
+ "rr1---sn-4g5lznes.googlevideo.com.",
+ "rr1---sn-4g5lzney.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-4pgnuapbiu-hiul.googlevideo.com.",
+ "rr1---sn-5gxo-in8l.googlevideo.com.",
+ "rr1---sn-5gxo-in8s.googlevideo.com.",
+ "rr1---sn-5hne6n6e.googlevideo.com.",
+ "rr1---sn-5hne6n6l.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.",
+ "rr1---sn-5hne6nz6.gvt1.com.",
+ "rr1---sn-5hne6nzd.googlevideo.com.",
+ "rr1---sn-5hne6nzk.googlevideo.com.",
+ "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-5hnekn7k.googlevideo.com.",
+ "rr1---sn-5hnekn7l.googlevideo.com.",
+ "rr1---sn-5hnekn7s.googlevideo.com.",
+ "rr1---sn-5hnekn7z.googlevideo.com.",
+ "rr1---sn-5hneknee.googlevideo.com.",
+ "rr1---sn-5hneknek.googlevideo.com.",
+ "rr1---sn-5hneknes.googlevideo.com.",
+ "rr1---sn-5pgnugx5h-hn2s.googlevideo.com.",
+ "rr1---sn-5pgnugx5h-hn2z.googlevideo.com.",
+ "rr1---sn-5uaezndd.googlevideo.com.",
+ "rr1---sn-5uaezne6.googlevideo.com.",
+ "rr1---sn-5uaezned.googlevideo.com.",
+ "rr1---sn-5uaeznes.googlevideo.com.",
+ "rr1---sn-5uaeznez.googlevideo.com.",
+ "rr1---sn-5uaeznl6.googlevideo.com.",
+ "rr1---sn-5uaeznld.googlevideo.com.",
+ "rr1---sn-5uaeznly.googlevideo.com.",
+ "rr1---sn-5uaeznlz.googlevideo.com.",
+ "rr1---sn-5uaeznrz.googlevideo.com.",
+ "rr1---sn-5uaezns7.googlevideo.com.",
+ "rr1---sn-5uaeznse.googlevideo.com.",
+ "rr1---sn-5uaeznsl.googlevideo.com.",
+ "rr1---sn-5uaeznss.googlevideo.com.",
+ "rr1---sn-5uaezny6.googlevideo.com.",
+ "rr1---sn-5uaeznys.googlevideo.com.",
+ "rr1---sn-5uaeznyz.googlevideo.com.",
+ "rr1---sn-5uaeznze.googlevideo.com.",
+ "rr1---sn-5ualdnle.googlevideo.com.",
+ "rr1---sn-5ualdnll.googlevideo.com.",
+ "rr1---sn-5ualdnlr.googlevideo.com.",
+ "rr1---sn-5ualdnls.googlevideo.com.",
+ "rr1---sn-5ualdns6.googlevideo.com.",
+ "rr1---sn-5ualdns7.googlevideo.com.",
+ "rr1---sn-5ualdnsd.googlevideo.com.",
+ "rr1---sn-5ualdnse.googlevideo.com.",
+ "rr1---sn-5ualdnsk.googlevideo.com.",
+ "rr1---sn-5ualdnsl.googlevideo.com.",
+ "rr1---sn-5ualdnsr.googlevideo.com.",
+ "rr1---sn-5ualdnss.googlevideo.com.",
+ "rr1---sn-5ualdnsy.googlevideo.com.",
+ "rr1---sn-5ualdnsz.googlevideo.com.",
+ "rr1---sn-5ualdnz7.googlevideo.com.",
+ "rr1---sn-5ualdnze.googlevideo.com.",
+ "rr1---sn-8qj-i5okl.googlevideo.com.",
+ "rr1---sn-8qj-nbo66.googlevideo.com.",
+ "rr1---sn-8qj-nbo6y.googlevideo.com.",
+ "rr1---sn-8xgp1vo-2iae.googlevideo.com.",
+ "rr1---sn-8xgp1vo-2iae7.googlevideo.com.",
+ "rr1---sn-8xgp1vo-2ial.googlevideo.com.",
+ "rr1---sn-8xgp1vo-2iay.googlevideo.com.",
+ "rr1---sn-8xgp1vo-a5me.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-p5ie.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-9gv7ene6.googlevideo.com.",
+ "rr1---sn-9gv7ened.googlevideo.com.",
+ "rr1---sn-9gv7zn76.googlevideo.com.",
+ "rr1---sn-9gv7zn7e.googlevideo.com.",
+ "rr1---sn-9gv7zn7r.googlevideo.com.",
+ "rr1---sn-a5m7lnl6.googlevideo.com.",
+ "rr1---sn-a5m7lnl6.gvt1.com.",
+ "rr1---sn-a5m7lnld.googlevideo.com.",
+ "rr1---sn-a5mekn6d.googlevideo.com.",
+ "rr1---sn-a5mekn6k.googlevideo.com.",
+ "rr1---sn-a5mekn6k.gvt1.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-a5meknsy.googlevideo.com.",
+ "rr1---sn-a5meknzk.googlevideo.com.",
+ "rr1---sn-a5meknzk.gvt1.com.",
+ "rr1---sn-a5meknzl.googlevideo.com.",
+ "rr1---sn-a5meknzl.gvt1.com.",
+ "rr1---sn-a5meknzr.googlevideo.com.",
+ "rr1---sn-a5meknzr.gvt1.com.",
+ "rr1---sn-a5meknzs.googlevideo.com.",
+ "rr1---sn-a5mlrnek.googlevideo.com.",
+ "rr1---sn-a5mlrnl6.googlevideo.com.",
+ "rr1---sn-a5mlrnl6.gvt1.com.",
+ "rr1---sn-a5mlrnll.googlevideo.com.",
+ "rr1---sn-a5mlrnll.gvt1.com.",
+ "rr1---sn-a5mlrnls.googlevideo.com.",
+ "rr1---sn-a5mlrnlz.googlevideo.com.",
+ "rr1---sn-a5msen76.googlevideo.com.",
+ "rr1---sn-a5msen7l.googlevideo.com.",
+ "rr1---sn-a5msen7s.googlevideo.com.",
+ "rr1---sn-a5msen7z.googlevideo.com.",
+ "rr1---sn-a5msenek.googlevideo.com.",
+ "rr1---sn-a5msener.googlevideo.com.",
+ "rr1---sn-a5msenes.googlevideo.com.",
+ "rr1---sn-a5msenes.gvt1.com.",
+ "rr1---sn-a5msenl7.googlevideo.com.",
+ "rr1---sn-a5msenle.googlevideo.com.",
+ "rr1---sn-a5msenle.gvt1.com.",
+ "rr1---sn-a5msenll.googlevideo.com.",
+ "rr1---sn-a5msenll.gvt1.com.",
+ "rr1---sn-a5oj5nuxg-aone.googlevideo.com.",
+ "rr1---sn-ab5l6ndr.googlevideo.com.",
+ "rr1---sn-ab5l6ndy.googlevideo.com.",
+ "rr1---sn-ab5l6ndy.gvt1.com.",
+ "rr1---sn-ab5l6nk6.googlevideo.com.",
+ "rr1---sn-ab5l6nkd.googlevideo.com.",
+ "rr1---sn-ab5l6nr6.googlevideo.com.",
+ "rr1---sn-ab5l6nrd.googlevideo.com.",
+ "rr1---sn-ab5l6nrd.gvt1.com.",
+ "rr1---sn-ab5l6nrk.googlevideo.com.",
+ "rr1---sn-ab5l6nrk.gvt1.com.",
+ "rr1---sn-ab5l6nrl.googlevideo.com.",
+ "rr1---sn-ab5l6nrr.googlevideo.com.",
+ "rr1---sn-ab5l6nrs.googlevideo.com.",
+ "rr1---sn-ab5l6nrz.googlevideo.com.",
+ "rr1---sn-ab5sznld.googlevideo.com.",
+ "rr1---sn-ab5sznlk.googlevideo.com.",
+ "rr1---sn-ab5sznly.googlevideo.com.",
+ "rr1---sn-ab5sznz6.googlevideo.com.",
+ "rr1---sn-ab5sznz6.gvt1.com.",
+ "rr1---sn-ab5sznzd.googlevideo.com.",
+ "rr1---sn-ab5sznzd.gvt1.com.",
+ "rr1---sn-ab5sznze.googlevideo.com.",
+ "rr1---sn-ab5sznzk.googlevideo.com.",
+ "rr1---sn-ab5sznzk.gvt1.com.",
+ "rr1---sn-ab5sznzl.googlevideo.com.",
+ "rr1---sn-ab5sznzl.gvt1.com.",
+ "rr1---sn-ab5sznzr.googlevideo.com.",
+ "rr1---sn-ab5sznzr.gvt1.com.",
+ "rr1---sn-ab5sznzs.googlevideo.com.",
+ "rr1---sn-ab5sznzy.googlevideo.com.",
+ "rr1---sn-ab5sznzz.googlevideo.com.",
+ "rr1---sn-aigl6n6s.googlevideo.com.",
+ "rr1---sn-aigl6nek.googlevideo.com.",
+ "rr1---sn-aigl6ner.googlevideo.com.",
+ "rr1---sn-aigl6ney.googlevideo.com.",
+ "rr1---sn-aigl6nl7.googlevideo.com.",
+ "rr1---sn-aigl6ns6.googlevideo.com.",
+ "rr1---sn-aigl6nsd.googlevideo.com.",
+ "rr1---sn-aigl6nsk.googlevideo.com.",
+ "rr1---sn-aigl6nsr.googlevideo.com.",
+ "rr1---sn-aigl6nz7.googlevideo.com.",
+ "rr1---sn-aigl6nzk.googlevideo.com.",
+ "rr1---sn-aigl6nzl.googlevideo.com.",
+ "rr1---sn-aigl6nzr.googlevideo.com.",
+ "rr1---sn-aigl6nzr.gvt1.com.",
+ "rr1---sn-aigl6nzs.googlevideo.com.",
+ "rr1---sn-aigzrn76.googlevideo.com.",
+ "rr1---sn-aigzrn7d.googlevideo.com.",
+ "rr1---sn-aigzrn7e.googlevideo.com.",
+ "rr1---sn-aigzrn7k.googlevideo.com.",
+ "rr1---sn-aigzrn7l.googlevideo.com.",
+ "rr1---sn-aigzrn7s.googlevideo.com.",
+ "rr1---sn-aigzrn7z.googlevideo.com.",
+ "rr1---sn-aigzrnld.googlevideo.com.",
+ "rr1---sn-aigzrnse.googlevideo.com.",
+ "rr1---sn-aigzrnsl.googlevideo.com.",
+ "rr1---sn-aigzrnsr.googlevideo.com.",
+ "rr1---sn-aigzrnss.googlevideo.com.",
+ "rr1---sn-aigzrnsz.googlevideo.com.",
+ "rr1---sn-aigzrnz7.googlevideo.com.",
+ "rr1---sn-aigzrnze.googlevideo.com.",
+ "rr1---sn-aj5ua5-5c.googlevideo.com.",
+ "rr1---sn-apn7en7s.googlevideo.com.",
+ "rr1---sn-bg5oqxjvh-50nz.googlevideo.com.",
+ "rr1---sn-bg5oqxjvh-jg2s.googlevideo.com.",
+ "rr1---sn-bg5oqxjvh-xa2s.googlevideo.com.",
+ "rr1---sn-cvb7lne7.googlevideo.com.",
+ "rr1---sn-cvb7lnee.googlevideo.com.",
+ "rr1---sn-cvb7lnls.googlevideo.com.",
+ "rr1---sn-cvb7lnlz.googlevideo.com.",
+ "rr1---sn-cvb7sn7k.googlevideo.com.",
+ "rr1---sn-cvb7sn7r.googlevideo.com.",
+ "rr1---sn-h0jeened.googlevideo.com.",
+ "rr1---sn-h0jeenl6.googlevideo.com.",
+ "rr1---sn-h0jeenld.googlevideo.com.",
+ "rr1---sn-h0jeenle.googlevideo.com.",
+ "rr1---sn-h0jeln7e.googlevideo.com.",
+ "rr1---sn-h0jelne6.googlevideo.com.",
+ "rr1---sn-h0jelnes.googlevideo.com.",
+ "rr1---sn-h0jelnez.googlevideo.com.",
+ "rr1---sn-hjoj-jaul.googlevideo.com.",
+ "rr1---sn-hjoj-poul.googlevideo.com.",
+ "rr1---sn-hoa7kn76.googlevideo.com.",
+ "rr1---sn-hoa7kn7z.googlevideo.com.",
+ "rr1---sn-hoa7rn76.googlevideo.com.",
+ "rr1---sn-hp57kn6r.googlevideo.com.",
+ "rr1---sn-hp57kn6y.googlevideo.com.",
+ "rr1---sn-hp57kn6y.gvt1.com.",
+ "rr1---sn-hp57knd6.googlevideo.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-hp57yn7r.googlevideo.com.",
+ "rr1---sn-hp57yn7r.gvt1.com.",
+ "rr1---sn-hp57yn7y.googlevideo.com.",
+ "rr1---sn-hp57yn7y.gvt1.com.",
+ "rr1---sn-hp57ynee.googlevideo.com.",
+ "rr1---sn-hp57ynl6.googlevideo.com.",
+ "rr1---sn-hp57ynlr.googlevideo.com.",
+ "rr1---sn-hp57yns7.googlevideo.com.",
+ "rr1---sn-hp57ynse.googlevideo.com.",
+ "rr1---sn-hp57ynse.gvt1.com.",
+ "rr1---sn-hp57ynsl.googlevideo.com.",
+ "rr1---sn-hp57ynsl.gvt1.com.",
+ "rr1---sn-hp57ynss.googlevideo.com.",
+ "rr1---sn-hxgpu-qufs.googlevideo.com.",
+ "rr1---sn-i3b7kn6s.googlevideo.com.",
+ "rr1---sn-i3b7knld.googlevideo.com.",
+ "rr1---sn-i3b7knlk.googlevideo.com.",
+ "rr1---sn-i3b7kns6.googlevideo.com.",
+ "rr1---sn-i3b7knsd.googlevideo.com.",
+ "rr1---sn-i3b7knse.googlevideo.com.",
+ "rr1---sn-i3b7knsl.googlevideo.com.",
+ "rr1---sn-i3b7knzl.googlevideo.com.",
+ "rr1---sn-i3b7knzs.googlevideo.com.",
+ "rr1---sn-i3belne6.googlevideo.com.",
+ "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-i3belnlz.googlevideo.com.",
+ "rr1---sn-i3bssn7e.googlevideo.com.",
+ "rr1---sn-i5f5ppuxa-ioal.googlevideo.com.",
+ "rr1---sn-i5goxu-i3bl.googlevideo.com.",
+ "rr1---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr1---sn-jvhj5nu-2iae.googlevideo.com.",
+ "rr1---sn-jvhj5nu-2ial.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-jvhj5nu-qufe.googlevideo.com.",
+ "rr1---sn-jvhj5nu-qufs.googlevideo.com.",
+ "rr1---sn-jvhj5nu-qufz.googlevideo.com.",
+ "rr1---sn-jxopj-n5oe.googlevideo.com.",
+ "rr1---sn-jxopj-n5oe.gvt1.com.",
+ "rr1---sn-muxa-2iae.googlevideo.com.",
+ "rr1---sn-n0g45pg-ncoe.googlevideo.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.",
+ "rr1---sn-n4v7snll.googlevideo.com.",
+ "rr1---sn-n4v7snlr.googlevideo.com.",
+ "rr1---sn-n4v7snls.googlevideo.com.",
+ "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-npoe7ndl.googlevideo.com.",
+ "rr1---sn-npoe7nds.googlevideo.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-npoe7nlz.googlevideo.com.",
+ "rr1---sn-npoe7ns6.googlevideo.com.",
+ "rr1---sn-npoe7ns7.googlevideo.com.",
+ "rr1---sn-npoe7nsd.googlevideo.com.",
+ "rr1---sn-npoe7nsk.googlevideo.com.",
+ "rr1---sn-npoe7nsl.googlevideo.com.",
+ "rr1---sn-npoe7nsr.googlevideo.com.",
+ "rr1---sn-npoe7nss.googlevideo.com.",
+ "rr1---sn-npoe7nsy.googlevideo.com.",
+ "rr1---sn-npoe7nz7.googlevideo.com.",
+ "rr1---sn-npoeene6.googlevideo.com.",
+ "rr1---sn-npoeened.googlevideo.com.",
+ "rr1---sn-npoeenee.googlevideo.com.",
+ "rr1---sn-npoeenek.googlevideo.com.",
+ "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-npoeenll.googlevideo.com.",
+ "rr1---sn-npoeens7.googlevideo.com.",
+ "rr1---sn-npoldn76.googlevideo.com.",
+ "rr1---sn-npoldn7d.googlevideo.com.",
+ "rr1---sn-npoldn7e.googlevideo.com.",
+ "rr1---sn-npoldn7l.googlevideo.com.",
+ "rr1---sn-npoldn7s.googlevideo.com.",
+ "rr1---sn-npoldn7y.googlevideo.com.",
+ "rr1---sn-npoldn7z.googlevideo.com.",
+ "rr1---sn-npoldne7.googlevideo.com.",
+ "rr1---sn-ntqe6nel.googlevideo.com.",
+ "rr1---sn-nuagpm-nuae.googlevideo.com.",
+ "rr1---sn-nv0ui4gvou-hape.googlevideo.com.",
+ "rr1---sn-nv0uixgo-5ual.googlevideo.com.",
+ "rr1---sn-nx57ynlk.googlevideo.com.",
+ "rr1---sn-nx57ynlk.gvt1.com.",
+ "rr1---sn-nx57ynsd.googlevideo.com.",
+ "rr1---sn-nx57ynsd.gvt1.com.",
+ "rr1---sn-nx57ynse.googlevideo.com.",
+ "rr1---sn-nx57ynsk.googlevideo.com.",
+ "rr1---sn-nx57ynsk.gvt1.com.",
+ "rr1---sn-nx57ynsl.googlevideo.com.",
+ "rr1---sn-nx57ynsl.gvt1.com.",
+ "rr1---sn-nx57ynss.googlevideo.com.",
+ "rr1---sn-nx57ynsz.googlevideo.com.",
+ "rr1---sn-nx57ynsz.gvt1.com.",
+ "rr1---sn-nx5s7n76.googlevideo.com.",
+ "rr1---sn-nx5s7n7d.googlevideo.com.",
+ "rr1---sn-nx5s7n7s.googlevideo.com.",
+ "rr1---sn-nx5s7n7y.googlevideo.com.",
+ "rr1---sn-nx5s7n7z.googlevideo.com.",
+ "rr1---sn-nx5s7nee.googlevideo.com.",
+ "rr1---sn-nx5s7nee.gvt1.com.",
+ "rr1---sn-nx5s7nel.googlevideo.com.",
+ "rr1---sn-o097znsd.googlevideo.com.",
+ "rr1---sn-o097znse.googlevideo.com.",
+ "rr1---sn-o097znsk.googlevideo.com.",
+ "rr1---sn-o097znsl.googlevideo.com.",
+ "rr1---sn-o097znsr.googlevideo.com.",
+ "rr1---sn-o097znss.googlevideo.com.",
+ "rr1---sn-o097znsz.googlevideo.com.",
+ "rr1---sn-o097znz7.googlevideo.com.",
+ "rr1---sn-o097znzd.googlevideo.com.",
+ "rr1---sn-o097znze.googlevideo.com.",
+ "rr1---sn-o097znzk.googlevideo.com.",
+ "rr1---sn-o097znzr.googlevideo.com.",
+ "rr1---sn-opnq-n5ue.googlevideo.com.",
+ "rr1---sn-ounjvhh-acce.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-p5qlsn76.googlevideo.com.",
+ "rr1---sn-p5qlsn7d.googlevideo.com.",
+ "rr1---sn-p5qlsn7l.googlevideo.com.",
+ "rr1---sn-p5qlsn7s.googlevideo.com.",
+ "rr1---sn-p5qlsnd6.googlevideo.com.",
+ "rr1---sn-p5qlsndd.googlevideo.com.",
+ "rr1---sn-p5qlsndk.googlevideo.com.",
+ "rr1---sn-p5qlsndr.googlevideo.com.",
+ "rr1---sn-p5qlsnrl.googlevideo.com.",
+ "rr1---sn-p5qlsnrr.googlevideo.com.",
+ "rr1---sn-p5qlsny6.googlevideo.com.",
+ "rr1---sn-p5qs7n6d.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-pjnpu-5hfe.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-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-q4fl6nds.googlevideo.com.",
+ "rr1---sn-q4fl6ndz.googlevideo.com.",
+ "rr1---sn-q4fl6nlz.googlevideo.com.",
+ "rr1---sn-q4fl6ns6.googlevideo.com.",
+ "rr1---sn-q4fl6ns6.gvt1.com.",
+ "rr1---sn-q4fl6ns7.googlevideo.com.",
+ "rr1---sn-q4fl6nsd.googlevideo.com.",
+ "rr1---sn-q4fl6nsl.googlevideo.com.",
+ "rr1---sn-q4fl6nss.googlevideo.com.",
+ "rr1---sn-q4fl6nsy.googlevideo.com.",
+ "rr1---sn-q4fl6nsy.gvt1.com.",
+ "rr1---sn-q4fl6nz6.googlevideo.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-q4flrn7r.gvt1.com.",
+ "rr1---sn-q4flrn7y.googlevideo.com.",
+ "rr1---sn-q4flrn7y.gvt1.com.",
+ "rr1---sn-q4flrne6.googlevideo.com.",
+ "rr1---sn-q4flrne7.googlevideo.com.",
+ "rr1---sn-q4flrnee.googlevideo.com.",
+ "rr1---sn-q4flrnek.googlevideo.com.",
+ "rr1---sn-q4flrnek.gvt1.com.",
+ "rr1---sn-q4flrnel.googlevideo.com.",
+ "rr1---sn-q4flrner.googlevideo.com.",
+ "rr1---sn-q4flrnes.googlevideo.com.",
+ "rr1---sn-q4flrney.googlevideo.com.",
+ "rr1---sn-q4flrnez.googlevideo.com.",
+ "rr1---sn-q4flrnez.gvt1.com.",
+ "rr1---sn-q4flrnl6.googlevideo.com.",
+ "rr1---sn-q4flrnl6.gvt1.com.",
+ "rr1---sn-q4flrnl7.googlevideo.com.",
+ "rr1---sn-q4flrnld.googlevideo.com.",
+ "rr1---sn-q4flrnle.googlevideo.com.",
+ "rr1---sn-q4flrnle.gvt1.com.",
+ "rr1---sn-q4flrnlz.googlevideo.com.",
+ "rr1---sn-q4flrnsd.googlevideo.com.",
+ "rr1---sn-q4flrnsk.googlevideo.com.",
+ "rr1---sn-q4flrnsk.gvt1.com.",
+ "rr1---sn-q4flrnsl.googlevideo.com.",
+ "rr1---sn-q4flrnsl.gvt1.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-q4fzen7r.googlevideo.com.",
+ "rr1---sn-q4fzen7r.gvt1.com.",
+ "rr1---sn-q4fzen7s.googlevideo.com.",
+ "rr1---sn-q4fzen7y.googlevideo.com.",
+ "rr1---sn-q4fzen7y.gvt1.com.",
+ "rr1---sn-q4fzene7.googlevideo.com.",
+ "rr1---sn-q4fzenee.googlevideo.com.",
+ "rr1---sn-qxo7rn7k.googlevideo.com.",
+ "rr1---sn-qxo7rn7r.googlevideo.com.",
+ "rr1---sn-qxoedn7k.googlevideo.com.",
+ "rr1---sn-qxoedne7.googlevideo.com.",
+ "rr1---sn-qxoednee.googlevideo.com.",
+ "rr1---sn-t0a7lnee.googlevideo.com.",
+ "rr1---sn-t0a7sn7d.googlevideo.com.",
+ "rr1---sn-u1hp55-5c.googlevideo.com.",
+ "rr1---sn-u1hp55-5c.gvt1.com.",
+ "rr1---sn-uhvcpaxoa-5hne.googlevideo.com.",
+ "rr1---sn-uhvcpaxoa-guhe.googlevideo.com.",
+ "rr1---sn-v53a5oqnji-4oul.googlevideo.com.",
+ "rr1---sn-v5goxu-jhi6.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.",
+ "rr1---sn-vgqskn6s.googlevideo.com.",
+ "rr1---sn-vgqskn6z.googlevideo.com.",
+ "rr1---sn-vgqskne6.googlevideo.com.",
+ "rr1---sn-vgqskned.googlevideo.com.",
+ "rr1---sn-vgqsknek.googlevideo.com.",
+ "rr1---sn-vgqsknek.gvt1.com.",
+ "rr1---sn-vgqsknes.googlevideo.com.",
+ "rr1---sn-vgqsknez.googlevideo.com.",
+ "rr1---sn-vgqsknlk.googlevideo.com.",
+ "rr1---sn-vgqsknll.googlevideo.com.",
+ "rr1---sn-vgqsknlr.googlevideo.com.",
+ "rr1---sn-vgqsknlr.gvt1.com.",
+ "rr1---sn-vgqsknls.googlevideo.com.",
+ "rr1---sn-vgqsknlz.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-vgqsrn66.googlevideo.com.",
+ "rr1---sn-vgqsrn67.googlevideo.com.",
+ "rr1---sn-vgqsrn6e.googlevideo.com.",
+ "rr1---sn-vgqsrn6e.gvt1.com.",
+ "rr1---sn-vgqsrn6l.googlevideo.com.",
+ "rr1---sn-vgqsrn6l.gvt1.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.",
+ "rr1---sn-vgqsrnes.googlevideo.com.",
+ "rr1---sn-vgqsrnez.googlevideo.com.",
+ "rr1---sn-vgqsrnl6.googlevideo.com.",
+ "rr1---sn-vgqsrnld.googlevideo.com.",
+ "rr1---sn-vgqsrnld.gvt1.com.",
+ "rr1---sn-vgqsrnlk.googlevideo.com.",
+ "rr1---sn-vgqsrnll.googlevideo.com.",
+ "rr1---sn-vgqsrnls.googlevideo.com.",
+ "rr1---sn-vgqsrnls.gvt1.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-vgqsrnz6.gvt1.com.",
+ "rr1---sn-vgqsrnz7.googlevideo.com.",
+ "rr1---sn-vgqsrnz7.gvt1.com.",
+ "rr1---sn-vgqsrnzd.googlevideo.com.",
+ "rr1---sn-vgqsrnzk.googlevideo.com.",
+ "rr1---sn-vgqsrnzk.gvt1.com.",
+ "rr1---sn-vgqsrnzr.googlevideo.com.",
+ "rr1---sn-vgqsrnzs.googlevideo.com.",
+ "rr1---sn-vgqsrnzy.googlevideo.com.",
+ "rr1---sn-vgqsrnzy.gvt1.com.",
+ "rr1---sn-vgqsrnzz.googlevideo.com.",
+ "rr1---sn-vgqsrnzz.gvt1.com.",
+ "rr1---sn-vnix5o-28ql.googlevideo.com.",
+ "rr1---sn-voxoxu-v3jl.googlevideo.com.",
+ "rr1---sn-voxoxu-v3js.googlevideo.com.",
+ "rr1---sn-xo5-co5l.googlevideo.com.",
+ "rr1.sn-5hnekn7l.googlevideo.com.",
+ "rr1.sn-q4fl6ndl.googlevideo.com.",
+ "rr1.sn-q4flrne7.googlevideo.com.",
+ "rr1.sn-q4flrnss.googlevideo.com.",
+ "rr1.sn-q4fzen7r.googlevideo.com.",
+ "rr1.sn-q4fzenee.googlevideo.com.",
+ "rr1.sn-t0a7sn7d.googlevideo.com.",
+ "rr10---sn-bvvbax-2ial.googlevideo.com.",
+ "rr11---sn-bvvbax-2ial.googlevideo.com.",
+ "rr12---sn-bvvbax-2ial.googlevideo.com.",
+ "rr2---sn-02o-ao3e.googlevideo.com.",
+ "rr2---sn-0nnpbo5a-bggl.googlevideo.com.",
+ "rr2---sn-0op8v4h5pox-cbgl.googlevideo.com.",
+ "rr2---sn-2imern76.googlevideo.com.",
+ "rr2---sn-2imern7d.googlevideo.com.",
+ "rr2---sn-2imeyn7k.googlevideo.com.",
+ "rr2---sn-2imeyn7k.gvt1.com.",
+ "rr2---sn-2napbiu-p5ie.googlevideo.com.",
+ "rr2---sn-2napbiu-p5ie.gvt1.com.",
+ "rr2---sn-2pmxapm0n-gpje.googlevideo.com.",
+ "rr2---sn-2pmxapm0n-gpjl.googlevideo.com.",
+ "rr2---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr2---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
+ "rr2---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
+ "rr2---sn-2vgu0b5auxaxjvh-v2vk.googlevideo.com.",
+ "rr2---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
+ "rr2---sn-2vgu0b5auxaxjvh-v2vz.googlevideo.com.",
+ "rr2---sn-30a7rne6.googlevideo.com.",
+ "rr2---sn-30a7rned.googlevideo.com.",
+ "rr2---sn-30a7rnek.googlevideo.com.",
+ "rr2---sn-30a7rner.googlevideo.com.",
+ "rr2---sn-30a7yner.googlevideo.com.",
+ "rr2---sn-30a7yney.googlevideo.com.",
+ "rr2---sn-30a7ynl7.googlevideo.com.",
+ "rr2---sn-3jpm-hjpe.googlevideo.com.",
+ "rr2---sn-3n4pcxg-pjul.googlevideo.com.",
+ "rr2---sn-3n4pcxg-pjuz.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.",
+ "rr2---sn-4g5edn6y.googlevideo.com.",
+ "rr2---sn-4g5ednd7.googlevideo.com.",
+ "rr2---sn-4g5edndd.googlevideo.com.",
+ "rr2---sn-4g5ednde.googlevideo.com.",
+ "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.",
+ "rr2---sn-4g5ednld.googlevideo.com.",
+ "rr2---sn-4g5ednly.googlevideo.com.",
+ "rr2---sn-4g5edns6.googlevideo.com.",
+ "rr2---sn-4g5edns7.googlevideo.com.",
+ "rr2---sn-4g5ednsd.googlevideo.com.",
+ "rr2---sn-4g5ednse.googlevideo.com.",
+ "rr2---sn-4g5ednsk.googlevideo.com.",
+ "rr2---sn-4g5ednsl.googlevideo.com.",
+ "rr2---sn-4g5ednsr.googlevideo.com.",
+ "rr2---sn-4g5ednss.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.",
+ "rr2---sn-4g5lzner.googlevideo.com.",
+ "rr2---sn-4g5lznes.googlevideo.com.",
+ "rr2---sn-4g5lzney.googlevideo.com.",
+ "rr2---sn-4g5lznez.googlevideo.com.",
+ "rr2---sn-4g5lznl6.googlevideo.com.",
+ "rr2---sn-4g5lznl7.googlevideo.com.",
+ "rr2---sn-4g5lznle.googlevideo.com.",
+ "rr2---sn-4g5lznls.googlevideo.com.",
+ "rr2---sn-4g5lznlz.googlevideo.com.",
+ "rr2---sn-4pgnuapbiu-hiul.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.",
+ "rr2---sn-5hne6nsd.googlevideo.com.",
+ "rr2---sn-5hne6nsk.googlevideo.com.",
+ "rr2---sn-5hne6nsr.googlevideo.com.",
+ "rr2---sn-5hne6nsy.googlevideo.com.",
+ "rr2---sn-5hne6nsz.googlevideo.com.",
+ "rr2---sn-5hne6nz6.googlevideo.com.",
+ "rr2---sn-5hne6nzd.googlevideo.com.",
+ "rr2---sn-5hne6nzk.googlevideo.com.",
+ "rr2---sn-5hne6nzs.googlevideo.com.",
+ "rr2---sn-5hne6nzy.googlevideo.com.",
+ "rr2---sn-5hnednss.googlevideo.com.",
+ "rr2---sn-5hnednsz.googlevideo.com.",
+ "rr2---sn-5hnekn76.googlevideo.com.",
+ "rr2---sn-5hnekn7d.googlevideo.com.",
+ "rr2---sn-5hnekn7k.googlevideo.com.",
+ "rr2---sn-5hnekn7l.googlevideo.com.",
+ "rr2---sn-5hnekn7s.googlevideo.com.",
+ "rr2---sn-5hnekn7z.googlevideo.com.",
+ "rr2---sn-5hneknee.googlevideo.com.",
+ "rr2---sn-5hneknek.googlevideo.com.",
+ "rr2---sn-5hneknes.googlevideo.com.",
+ "rr2---sn-5pgnugx5h-hn2z.googlevideo.com.",
+ "rr2---sn-5uaezndd.googlevideo.com.",
+ "rr2---sn-5uaezne6.googlevideo.com.",
+ "rr2---sn-5uaezned.googlevideo.com.",
+ "rr2---sn-5uaeznez.googlevideo.com.",
+ "rr2---sn-5uaeznl6.googlevideo.com.",
+ "rr2---sn-5uaeznld.googlevideo.com.",
+ "rr2---sn-5uaeznly.googlevideo.com.",
+ "rr2---sn-5uaeznlz.googlevideo.com.",
+ "rr2---sn-5uaeznrz.googlevideo.com.",
+ "rr2---sn-5uaezns7.googlevideo.com.",
+ "rr2---sn-5uaeznse.googlevideo.com.",
+ "rr2---sn-5uaeznsl.googlevideo.com.",
+ "rr2---sn-5uaeznss.googlevideo.com.",
+ "rr2---sn-5uaezny6.googlevideo.com.",
+ "rr2---sn-5uaeznys.googlevideo.com.",
+ "rr2---sn-5uaeznyz.googlevideo.com.",
+ "rr2---sn-5uaeznze.googlevideo.com.",
+ "rr2---sn-5ualdnle.googlevideo.com.",
+ "rr2---sn-5ualdnll.googlevideo.com.",
+ "rr2---sn-5ualdnlr.googlevideo.com.",
+ "rr2---sn-5ualdnls.googlevideo.com.",
+ "rr2---sn-5ualdns6.googlevideo.com.",
+ "rr2---sn-5ualdns7.googlevideo.com.",
+ "rr2---sn-5ualdnsd.googlevideo.com.",
+ "rr2---sn-5ualdnse.googlevideo.com.",
+ "rr2---sn-5ualdnsk.googlevideo.com.",
+ "rr2---sn-5ualdnsl.googlevideo.com.",
+ "rr2---sn-5ualdnsr.googlevideo.com.",
+ "rr2---sn-5ualdnss.googlevideo.com.",
+ "rr2---sn-5ualdnsy.googlevideo.com.",
+ "rr2---sn-5ualdnsz.googlevideo.com.",
+ "rr2---sn-5ualdnz7.googlevideo.com.",
+ "rr2---sn-5ualdnze.googlevideo.com.",
+ "rr2---sn-8qj-i5ody.googlevideo.com.",
+ "rr2---sn-8qj-i5okl.googlevideo.com.",
+ "rr2---sn-8qj-nbo66.googlevideo.com.",
+ "rr2---sn-8qj-nbo6y.googlevideo.com.",
+ "rr2---sn-8xgp1vo-2iae.googlevideo.com.",
+ "rr2---sn-8xgp1vo-2iae7.googlevideo.com.",
+ "rr2---sn-8xgp1vo-2ial.googlevideo.com.",
+ "rr2---sn-8xgp1vo-2iay.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-nh4e.googlevideo.com.",
+ "rr2---sn-8xgp1vo-p5ie.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-9gv76n7s.googlevideo.com.",
+ "rr2---sn-9gv76n7z.googlevideo.com.",
+ "rr2---sn-9gv7ene6.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-a5m7lnl6.gvt1.com.",
+ "rr2---sn-a5m7lnld.googlevideo.com.",
+ "rr2---sn-a5mekn6d.googlevideo.com.",
+ "rr2---sn-a5mekn6k.googlevideo.com.",
+ "rr2---sn-a5mekn6k.gvt1.com.",
+ "rr2---sn-a5mekn6l.googlevideo.com.",
+ "rr2---sn-a5mekn6r.googlevideo.com.",
+ "rr2---sn-a5mekn6r.gvt1.com.",
+ "rr2---sn-a5mekn6s.googlevideo.com.",
+ "rr2---sn-a5mekn6z.googlevideo.com.",
+ "rr2---sn-a5meknd6.googlevideo.com.",
+ "rr2---sn-a5meknde.googlevideo.com.",
+ "rr2---sn-a5meknde.gvt1.com.",
+ "rr2---sn-a5mekndl.googlevideo.com.",
+ "rr2---sn-a5meknds.googlevideo.com.",
+ "rr2---sn-a5meknds.gvt1.com.",
+ "rr2---sn-a5mekndz.googlevideo.com.",
+ "rr2---sn-a5meknsd.googlevideo.com.",
+ "rr2---sn-a5meknsd.gvt1.com.",
+ "rr2---sn-a5meknsy.googlevideo.com.",
+ "rr2---sn-a5meknzk.googlevideo.com.",
+ "rr2---sn-a5meknzl.googlevideo.com.",
+ "rr2---sn-a5meknzr.googlevideo.com.",
+ "rr2---sn-a5mlrnek.googlevideo.com.",
+ "rr2---sn-a5mlrnl6.googlevideo.com.",
+ "rr2---sn-a5mlrnl6.gvt1.com.",
+ "rr2---sn-a5mlrnll.googlevideo.com.",
+ "rr2---sn-a5mlrnls.googlevideo.com.",
+ "rr2---sn-a5mlrnls.gvt1.com.",
+ "rr2---sn-a5mlrnlz.googlevideo.com.",
+ "rr2---sn-a5msen76.googlevideo.com.",
+ "rr2---sn-a5msen7l.googlevideo.com.",
+ "rr2---sn-a5msen7s.googlevideo.com.",
+ "rr2---sn-a5msen7s.gvt1.com.",
+ "rr2---sn-a5msen7z.googlevideo.com.",
+ "rr2---sn-a5msenek.googlevideo.com.",
+ "rr2---sn-a5msener.googlevideo.com.",
+ "rr2---sn-a5msener.gvt1.com.",
+ "rr2---sn-a5msenes.googlevideo.com.",
+ "rr2---sn-a5msenl7.googlevideo.com.",
+ "rr2---sn-a5msenle.googlevideo.com.",
+ "rr2---sn-a5msenll.googlevideo.com.",
+ "rr2---sn-ab5l6ndr.googlevideo.com.",
+ "rr2---sn-ab5l6ndy.googlevideo.com.",
+ "rr2---sn-ab5l6nk6.googlevideo.com.",
+ "rr2---sn-ab5l6nk6.gvt1.com.",
+ "rr2---sn-ab5l6nkd.googlevideo.com.",
+ "rr2---sn-ab5l6nkd.gvt1.com.",
+ "rr2---sn-ab5l6nr6.googlevideo.com.",
+ "rr2---sn-ab5l6nrd.googlevideo.com.",
+ "rr2---sn-ab5l6nrk.googlevideo.com.",
+ "rr2---sn-ab5l6nrl.googlevideo.com.",
+ "rr2---sn-ab5l6nrr.googlevideo.com.",
+ "rr2---sn-ab5l6nrs.googlevideo.com.",
+ "rr2---sn-ab5l6nrs.gvt1.com.",
+ "rr2---sn-ab5l6nrz.googlevideo.com.",
+ "rr2---sn-ab5sznld.googlevideo.com.",
+ "rr2---sn-ab5sznlk.googlevideo.com.",
+ "rr2---sn-ab5sznly.googlevideo.com.",
+ "rr2---sn-ab5sznz6.googlevideo.com.",
+ "rr2---sn-ab5sznz6.gvt1.com.",
+ "rr2---sn-ab5sznzd.googlevideo.com.",
+ "rr2---sn-ab5sznze.googlevideo.com.",
+ "rr2---sn-ab5sznzk.googlevideo.com.",
+ "rr2---sn-ab5sznzk.gvt1.com.",
+ "rr2---sn-ab5sznzl.googlevideo.com.",
+ "rr2---sn-ab5sznzr.googlevideo.com.",
+ "rr2---sn-ab5sznzs.googlevideo.com.",
+ "rr2---sn-ab5sznzs.gvt1.com.",
+ "rr2---sn-ab5sznzy.googlevideo.com.",
+ "rr2---sn-ab5sznzz.googlevideo.com.",
+ "rr2---sn-aigl6n6s.googlevideo.com.",
+ "rr2---sn-aigl6ned.googlevideo.com.",
+ "rr2---sn-aigl6nek.googlevideo.com.",
+ "rr2---sn-aigl6ner.googlevideo.com.",
+ "rr2---sn-aigl6ney.googlevideo.com.",
+ "rr2---sn-aigl6nl7.googlevideo.com.",
+ "rr2---sn-aigl6ns6.googlevideo.com.",
+ "rr2---sn-aigl6nsd.googlevideo.com.",
+ "rr2---sn-aigl6nsk.googlevideo.com.",
+ "rr2---sn-aigl6nsr.googlevideo.com.",
+ "rr2---sn-aigl6nsr.gvt1.com.",
+ "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.",
+ "rr2---sn-aigzrn7d.googlevideo.com.",
+ "rr2---sn-aigzrn7e.googlevideo.com.",
+ "rr2---sn-aigzrn7k.googlevideo.com.",
+ "rr2---sn-aigzrn7l.googlevideo.com.",
+ "rr2---sn-aigzrn7s.googlevideo.com.",
+ "rr2---sn-aigzrn7z.googlevideo.com.",
+ "rr2---sn-aigzrnld.googlevideo.com.",
+ "rr2---sn-aigzrnse.googlevideo.com.",
+ "rr2---sn-aigzrnsl.googlevideo.com.",
+ "rr2---sn-aigzrnsr.googlevideo.com.",
+ "rr2---sn-aigzrnss.googlevideo.com.",
+ "rr2---sn-aigzrnsz.googlevideo.com.",
+ "rr2---sn-aigzrnz7.googlevideo.com.",
+ "rr2---sn-aigzrnze.googlevideo.com.",
+ "rr2---sn-apn7en7e.googlevideo.com.",
+ "rr2---sn-apn7en7l.googlevideo.com.",
+ "rr2---sn-apn7en7s.googlevideo.com.",
+ "rr2---sn-bg5oqxjvh-50nz.googlevideo.com.",
+ "rr2---sn-bg5oqxjvh-jg2s.googlevideo.com.",
+ "rr2---sn-bg5oqxjvh-xa2s.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-fpnjoxu-h3xl.googlevideo.com.",
+ "rr2---sn-fpnjoxu-hnol.googlevideo.com.",
+ "rr2---sn-h0jeener.googlevideo.com.",
+ "rr2---sn-h0jeenl6.googlevideo.com.",
+ "rr2---sn-h0jeenld.googlevideo.com.",
+ "rr2---sn-h0jeenle.googlevideo.com.",
+ "rr2---sn-h0jelne6.googlevideo.com.",
+ "rr2---sn-h0jelnes.googlevideo.com.",
+ "rr2---sn-h0jelnez.googlevideo.com.",
+ "rr2---sn-hgn7yn7l.googlevideo.com.",
+ "rr2---sn-hjoj-gq0l.googlevideo.com.",
+ "rr2---sn-hjoj-gq0l.gvt1.com.",
+ "rr2---sn-hjoj-jaul.googlevideo.com.",
+ "rr2---sn-hjoj-poul.googlevideo.com.",
+ "rr2---sn-hoa7kn76.googlevideo.com.",
+ "rr2---sn-hoa7kn7z.googlevideo.com.",
+ "rr2---sn-hoa7rn76.googlevideo.com.",
+ "rr2---sn-hoa7rn7z.googlevideo.com.",
+ "rr2---sn-hp57kn6y.googlevideo.com.",
+ "rr2---sn-hp57knd6.googlevideo.com.",
+ "rr2---sn-hp57knd6.gvt1.com.",
+ "rr2---sn-hp57kndd.googlevideo.com.",
+ "rr2---sn-hp57kndk.googlevideo.com.",
+ "rr2---sn-hp57kndk.gvt1.com.",
+ "rr2---sn-hp57kndr.googlevideo.com.",
+ "rr2---sn-hp57kndr.gvt1.com.",
+ "rr2---sn-hp57knds.googlevideo.com.",
+ "rr2---sn-hp57kndy.googlevideo.com.",
+ "rr2---sn-hp57kndz.googlevideo.com.",
+ "rr2---sn-hp57kndz.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-hp57ynlr.gvt1.com.",
+ "rr2---sn-hp57ynly.googlevideo.com.",
+ "rr2---sn-hp57yns7.googlevideo.com.",
+ "rr2---sn-hp57ynse.googlevideo.com.",
+ "rr2---sn-hp57ynsl.googlevideo.com.",
+ "rr2---sn-hp57ynss.googlevideo.com.",
+ "rr2---sn-hxgpu-qufs.googlevideo.com.",
+ "rr2---sn-i3b7kn6s.googlevideo.com.",
+ "rr2---sn-i3b7knld.googlevideo.com.",
+ "rr2---sn-i3b7knlk.googlevideo.com.",
+ "rr2---sn-i3b7kns6.googlevideo.com.",
+ "rr2---sn-i3b7knsd.googlevideo.com.",
+ "rr2---sn-i3b7knse.googlevideo.com.",
+ "rr2---sn-i3b7knsl.googlevideo.com.",
+ "rr2---sn-i3b7knzl.googlevideo.com.",
+ "rr2---sn-i3b7knzs.googlevideo.com.",
+ "rr2---sn-i3belne6.googlevideo.com.",
+ "rr2---sn-i3belnl6.googlevideo.com.",
+ "rr2---sn-i3belnl7.googlevideo.com.",
+ "rr2---sn-i3belnll.googlevideo.com.",
+ "rr2---sn-i3belnls.googlevideo.com.",
+ "rr2---sn-i3belnlz.googlevideo.com.",
+ "rr2---sn-i3bssn7e.googlevideo.com.",
+ "rr2---sn-i5f5ppuxa-ioal.googlevideo.com.",
+ "rr2---sn-i5goxu-i3bl.googlevideo.com.",
+ "rr2---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr2---sn-jvhj5nu-2iae.googlevideo.com.",
+ "rr2---sn-jvhj5nu-2ial.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-jvhj5nu-qufe.googlevideo.com.",
+ "rr2---sn-jvhj5nu-qufl.googlevideo.com.",
+ "rr2---sn-jvhj5nu-qufs.googlevideo.com.",
+ "rr2---sn-jvhj5nu-qufz.googlevideo.com.",
+ "rr2---sn-jxopj-n5oe.googlevideo.com.",
+ "rr2---sn-jxopj-n5oe.gvt1.com.",
+ "rr2---sn-jxopj-nh4e.googlevideo.com.",
+ "rr2---sn-jxopj-nh4e.gvt1.com.",
+ "rr2---sn-muxa-2iae.googlevideo.com.",
+ "rr2---sn-n0g45pg-ncoe.googlevideo.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-npoe7ndl.googlevideo.com.",
+ "rr2---sn-npoe7nds.googlevideo.com.",
+ "rr2---sn-npoe7ne6.googlevideo.com.",
+ "rr2---sn-npoe7ne7.googlevideo.com.",
+ "rr2---sn-npoe7ned.googlevideo.com.",
+ "rr2---sn-npoe7nek.googlevideo.com.",
+ "rr2---sn-npoe7ner.googlevideo.com.",
+ "rr2---sn-npoe7nes.googlevideo.com.",
+ "rr2---sn-npoe7ney.googlevideo.com.",
+ "rr2---sn-npoe7nez.googlevideo.com.",
+ "rr2---sn-npoe7nl6.googlevideo.com.",
+ "rr2---sn-npoe7nlz.googlevideo.com.",
+ "rr2---sn-npoe7ns6.googlevideo.com.",
+ "rr2---sn-npoe7ns7.googlevideo.com.",
+ "rr2---sn-npoe7nsd.googlevideo.com.",
+ "rr2---sn-npoe7nsk.googlevideo.com.",
+ "rr2---sn-npoe7nsl.googlevideo.com.",
+ "rr2---sn-npoe7nsr.googlevideo.com.",
+ "rr2---sn-npoe7nss.googlevideo.com.",
+ "rr2---sn-npoe7nsy.googlevideo.com.",
+ "rr2---sn-npoe7nz7.googlevideo.com.",
+ "rr2---sn-npoeene6.googlevideo.com.",
+ "rr2---sn-npoeened.googlevideo.com.",
+ "rr2---sn-npoeenee.googlevideo.com.",
+ "rr2---sn-npoeener.googlevideo.com.",
+ "rr2---sn-npoeeney.googlevideo.com.",
+ "rr2---sn-npoeenez.googlevideo.com.",
+ "rr2---sn-npoeenl7.googlevideo.com.",
+ "rr2---sn-npoeenle.googlevideo.com.",
+ "rr2---sn-npoeenlk.googlevideo.com.",
+ "rr2---sn-npoeenll.googlevideo.com.",
+ "rr2---sn-npoeens7.googlevideo.com.",
+ "rr2---sn-npoldn76.googlevideo.com.",
+ "rr2---sn-npoldn7d.googlevideo.com.",
+ "rr2---sn-npoldn7l.googlevideo.com.",
+ "rr2---sn-npoldn7s.googlevideo.com.",
+ "rr2---sn-npoldn7y.googlevideo.com.",
+ "rr2---sn-npoldn7z.googlevideo.com.",
+ "rr2---sn-npoldne7.googlevideo.com.",
+ "rr2---sn-nuagpm-nuae.googlevideo.com.",
+ "rr2---sn-nv0ui4gvou-hape.googlevideo.com.",
+ "rr2---sn-nv0uixgo-5ual.googlevideo.com.",
+ "rr2---sn-nx57ynlk.googlevideo.com.",
+ "rr2---sn-nx57ynlk.gvt1.com.",
+ "rr2---sn-nx57ynsd.googlevideo.com.",
+ "rr2---sn-nx57ynsd.gvt1.com.",
+ "rr2---sn-nx57ynsk.googlevideo.com.",
+ "rr2---sn-nx57ynsk.gvt1.com.",
+ "rr2---sn-nx57ynsl.googlevideo.com.",
+ "rr2---sn-nx57ynsl.gvt1.com.",
+ "rr2---sn-nx57ynss.googlevideo.com.",
+ "rr2---sn-nx57ynss.gvt1.com.",
+ "rr2---sn-nx57ynsz.googlevideo.com.",
+ "rr2---sn-nx57ynsz.gvt1.com.",
+ "rr2---sn-nx5s7n76.googlevideo.com.",
+ "rr2---sn-nx5s7n7d.googlevideo.com.",
+ "rr2---sn-nx5s7n7d.gvt1.com.",
+ "rr2---sn-nx5s7n7y.googlevideo.com.",
+ "rr2---sn-nx5s7n7z.googlevideo.com.",
+ "rr2---sn-nx5s7nee.googlevideo.com.",
+ "rr2---sn-nx5s7nee.gvt1.com.",
+ "rr2---sn-o097znsd.googlevideo.com.",
+ "rr2---sn-o097znse.googlevideo.com.",
+ "rr2---sn-o097znsl.googlevideo.com.",
+ "rr2---sn-o097znsr.googlevideo.com.",
+ "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-opnq-n5ue.googlevideo.com.",
+ "rr2---sn-ounjvhh-acce.googlevideo.com.",
+ "rr2---sn-oxgpj-5ace.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-p5qlsn76.googlevideo.com.",
+ "rr2---sn-p5qlsn7d.googlevideo.com.",
+ "rr2---sn-p5qlsn7l.googlevideo.com.",
+ "rr2---sn-p5qlsn7s.googlevideo.com.",
+ "rr2---sn-p5qlsnd6.googlevideo.com.",
+ "rr2---sn-p5qlsndd.googlevideo.com.",
+ "rr2---sn-p5qlsndz.googlevideo.com.",
+ "rr2---sn-p5qlsnrl.googlevideo.com.",
+ "rr2---sn-p5qlsnrr.googlevideo.com.",
+ "rr2---sn-p5qlsny6.googlevideo.com.",
+ "rr2---sn-p5qs7n6d.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-pjnpu-5hfe.googlevideo.com.",
+ "rr2---sn-pobpb-poql.googlevideo.com.",
+ "rr2---sn-q4fl6n66.googlevideo.com.",
+ "rr2---sn-q4fl6n6d.googlevideo.com.",
+ "rr2---sn-q4fl6n6d.gvt1.com.",
+ "rr2---sn-q4fl6n6r.googlevideo.com.",
+ "rr2---sn-q4fl6n6r.gvt1.com.",
+ "rr2---sn-q4fl6n6s.googlevideo.com.",
+ "rr2---sn-q4fl6n6y.googlevideo.com.",
+ "rr2---sn-q4fl6n6y.gvt1.com.",
+ "rr2---sn-q4fl6n6z.googlevideo.com.",
+ "rr2---sn-q4fl6nd6.googlevideo.com.",
+ "rr2---sn-q4fl6nd7.googlevideo.com.",
+ "rr2---sn-q4fl6nd7.gvt1.com.",
+ "rr2---sn-q4fl6nde.googlevideo.com.",
+ "rr2---sn-q4fl6ndl.googlevideo.com.",
+ "rr2---sn-q4fl6nds.googlevideo.com.",
+ "rr2---sn-q4fl6ndz.googlevideo.com.",
+ "rr2---sn-q4fl6ndz.gvt1.com.",
+ "rr2---sn-q4fl6nlz.googlevideo.com.",
+ "rr2---sn-q4fl6ns6.googlevideo.com.",
+ "rr2---sn-q4fl6ns6.gvt1.com.",
+ "rr2---sn-q4fl6ns7.googlevideo.com.",
+ "rr2---sn-q4fl6ns7.gvt1.com.",
+ "rr2---sn-q4fl6nsd.googlevideo.com.",
+ "rr2---sn-q4fl6nsd.gvt1.com.",
+ "rr2---sn-q4fl6nsk.googlevideo.com.",
+ "rr2---sn-q4fl6nsk.gvt1.com.",
+ "rr2---sn-q4fl6nsl.googlevideo.com.",
+ "rr2---sn-q4fl6nsr.googlevideo.com.",
+ "rr2---sn-q4fl6nsr.gvt1.com.",
+ "rr2---sn-q4fl6nss.googlevideo.com.",
+ "rr2---sn-q4fl6nsy.googlevideo.com.",
+ "rr2---sn-q4fl6nsy.gvt1.com.",
+ "rr2---sn-q4fl6nz6.googlevideo.com.",
+ "rr2---sn-q4fl6nz6.gvt1.com.",
+ "rr2---sn-q4fl6nz7.googlevideo.com.",
+ "rr2---sn-q4fl6nz7.gvt1.com.",
+ "rr2---sn-q4fl6nzy.googlevideo.com.",
+ "rr2---sn-q4fl6nzy.gvt1.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-q4flrner.googlevideo.com.",
+ "rr2---sn-q4flrner.gvt1.com.",
+ "rr2---sn-q4flrnes.googlevideo.com.",
+ "rr2---sn-q4flrnes.gvt1.com.",
+ "rr2---sn-q4flrney.googlevideo.com.",
+ "rr2---sn-q4flrnez.googlevideo.com.",
+ "rr2---sn-q4flrnez.gvt1.com.",
+ "rr2---sn-q4flrnl6.googlevideo.com.",
+ "rr2---sn-q4flrnl7.googlevideo.com.",
+ "rr2---sn-q4flrnld.googlevideo.com.",
+ "rr2---sn-q4flrnld.gvt1.com.",
+ "rr2---sn-q4flrnle.googlevideo.com.",
+ "rr2---sn-q4flrnlz.googlevideo.com.",
+ "rr2---sn-q4flrnlz.gvt1.com.",
+ "rr2---sn-q4flrnsd.googlevideo.com.",
+ "rr2---sn-q4flrnsk.googlevideo.com.",
+ "rr2---sn-q4flrnsk.gvt1.com.",
+ "rr2---sn-q4flrnsl.googlevideo.com.",
+ "rr2---sn-q4flrnsl.gvt1.com.",
+ "rr2---sn-q4flrnss.googlevideo.com.",
+ "rr2---sn-q4fzen7e.googlevideo.com.",
+ "rr2---sn-q4fzen7l.googlevideo.com.",
+ "rr2---sn-q4fzen7r.googlevideo.com.",
+ "rr2---sn-q4fzen7r.gvt1.com.",
+ "rr2---sn-q4fzen7s.googlevideo.com.",
+ "rr2---sn-q4fzen7y.googlevideo.com.",
+ "rr2---sn-q4fzene7.googlevideo.com.",
+ "rr2---sn-q4fzenee.googlevideo.com.",
+ "rr2---sn-q4fzenee.gvt1.com.",
+ "rr2---sn-qxo7rn7k.googlevideo.com.",
+ "rr2---sn-qxo7rn7r.googlevideo.com.",
+ "rr2---sn-qxo7rn7y.googlevideo.com.",
+ "rr2---sn-qxoedn7k.googlevideo.com.",
+ "rr2---sn-qxoedne7.googlevideo.com.",
+ "rr2---sn-qxoednee.googlevideo.com.",
+ "rr2---sn-u1hp55-5c.googlevideo.com.",
+ "rr2---sn-u1hp55-5c.gvt1.com.",
+ "rr2---sn-uhvcpaxoa-5hne.googlevideo.com.",
+ "rr2---sn-uhvcpaxoa-guhe.googlevideo.com.",
+ "rr2---sn-v53a5oqnji-4oul.googlevideo.com.",
+ "rr2---sn-v5goxu-jhi6.googlevideo.com.",
+ "rr2---sn-v5goxu-jhi6.gvt1.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.",
+ "rr2---sn-vgqskn6s.googlevideo.com.",
+ "rr2---sn-vgqskn6z.googlevideo.com.",
+ "rr2---sn-vgqskne6.googlevideo.com.",
+ "rr2---sn-vgqskned.googlevideo.com.",
+ "rr2---sn-vgqsknek.googlevideo.com.",
+ "rr2---sn-vgqsknek.gvt1.com.",
+ "rr2---sn-vgqsknes.googlevideo.com.",
+ "rr2---sn-vgqsknez.googlevideo.com.",
+ "rr2---sn-vgqsknez.gvt1.com.",
+ "rr2---sn-vgqsknld.googlevideo.com.",
+ "rr2---sn-vgqsknld.gvt1.com.",
+ "rr2---sn-vgqsknlk.googlevideo.com.",
+ "rr2---sn-vgqsknll.googlevideo.com.",
+ "rr2---sn-vgqsknls.googlevideo.com.",
+ "rr2---sn-vgqsknlz.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-vgqsrn6l.googlevideo.com.",
+ "rr2---sn-vgqsrn6l.gvt1.com.",
+ "rr2---sn-vgqsrn6z.googlevideo.com.",
+ "rr2---sn-vgqsrne6.googlevideo.com.",
+ "rr2---sn-vgqsrned.googlevideo.com.",
+ "rr2---sn-vgqsrnek.googlevideo.com.",
+ "rr2---sn-vgqsrnes.googlevideo.com.",
+ "rr2---sn-vgqsrnez.googlevideo.com.",
+ "rr2---sn-vgqsrnl6.googlevideo.com.",
+ "rr2---sn-vgqsrnld.googlevideo.com.",
+ "rr2---sn-vgqsrnlk.googlevideo.com.",
+ "rr2---sn-vgqsrnll.googlevideo.com.",
+ "rr2---sn-vgqsrnls.googlevideo.com.",
+ "rr2---sn-vgqsrnls.gvt1.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-vgqsrnsy.gvt1.com.",
+ "rr2---sn-vgqsrnz6.googlevideo.com.",
+ "rr2---sn-vgqsrnz7.googlevideo.com.",
+ "rr2---sn-vgqsrnzd.googlevideo.com.",
+ "rr2---sn-vgqsrnzk.googlevideo.com.",
+ "rr2---sn-vgqsrnzk.gvt1.com.",
+ "rr2---sn-vgqsrnzr.googlevideo.com.",
+ "rr2---sn-vgqsrnzs.googlevideo.com.",
+ "rr2---sn-vgqsrnzy.googlevideo.com.",
+ "rr2---sn-vgqsrnzz.googlevideo.com.",
+ "rr2---sn-vnix5o-28ql.googlevideo.com.",
+ "rr2---sn-voxoxu-v3js.googlevideo.com.",
+ "rr2---sn-xo5-co5l.googlevideo.com.",
+ "rr2.sn-5hnekn7d.googlevideo.com.",
+ "rr2.sn-a5mekndz.googlevideo.com.",
+ "rr2.sn-a5meknzr.googlevideo.com.",
+ "rr2.sn-q4fl6n6y.googlevideo.com.",
+ "rr2.sn-q4fl6nsk.googlevideo.com.",
+ "rr3---sn-0nnpbo5a-bggl.googlevideo.com.",
+ "rr3---sn-2imern76.googlevideo.com.",
+ "rr3---sn-2imern76.gvt1.com.",
+ "rr3---sn-2imeyn7k.googlevideo.com.",
+ "rr3---sn-2imeyn7k.gvt1.com.",
+ "rr3---sn-2napbiu-p5ie.googlevideo.com.",
+ "rr3---sn-2napbiu-p5ie.gvt1.com.",
+ "rr3---sn-2oaig5-55.googlevideo.com.",
+ "rr3---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr3---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
+ "rr3---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
+ "rr3---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
+ "rr3---sn-2vgu0b5auxaxjvh-v2vz.googlevideo.com.",
+ "rr3---sn-30a7rne6.googlevideo.com.",
+ "rr3---sn-30a7rned.googlevideo.com.",
+ "rr3---sn-30a7rnek.googlevideo.com.",
+ "rr3---sn-30a7rner.googlevideo.com.",
+ "rr3---sn-30a7ynek.googlevideo.com.",
+ "rr3---sn-30a7yner.googlevideo.com.",
+ "rr3---sn-30a7yney.googlevideo.com.",
+ "rr3---sn-30a7ynl7.googlevideo.com.",
+ "rr3---sn-3jpm-hjpe.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.",
+ "rr3---sn-4g5edn6r.googlevideo.com.",
+ "rr3---sn-4g5edn6y.googlevideo.com.",
+ "rr3---sn-4g5ednd7.googlevideo.com.",
+ "rr3---sn-4g5edndd.googlevideo.com.",
+ "rr3---sn-4g5ednde.googlevideo.com.",
+ "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.",
+ "rr3---sn-4g5ednsk.googlevideo.com.",
+ "rr3---sn-4g5ednsl.googlevideo.com.",
+ "rr3---sn-4g5ednsr.googlevideo.com.",
+ "rr3---sn-4g5ednss.googlevideo.com.",
+ "rr3---sn-4g5ednsz.googlevideo.com.",
+ "rr3---sn-4g5ednz7.googlevideo.com.",
+ "rr3---sn-4g5lzne6.googlevideo.com.",
+ "rr3---sn-4g5lzned.googlevideo.com.",
+ "rr3---sn-4g5lznek.googlevideo.com.",
+ "rr3---sn-4g5lzner.googlevideo.com.",
+ "rr3---sn-4g5lznes.googlevideo.com.",
+ "rr3---sn-4g5lzney.googlevideo.com.",
+ "rr3---sn-4g5lznez.googlevideo.com.",
+ "rr3---sn-4g5lznl6.googlevideo.com.",
+ "rr3---sn-4g5lznl7.googlevideo.com.",
+ "rr3---sn-4g5lznle.googlevideo.com.",
+ "rr3---sn-4g5lznls.googlevideo.com.",
+ "rr3---sn-4g5lznlz.googlevideo.com.",
+ "rr3---sn-5hne6n6e.googlevideo.com.",
+ "rr3---sn-5hne6n6l.googlevideo.com.",
+ "rr3---sn-5hne6ns6.googlevideo.com.",
+ "rr3---sn-5hne6nsd.googlevideo.com.",
+ "rr3---sn-5hne6nsk.googlevideo.com.",
+ "rr3---sn-5hne6nsr.googlevideo.com.",
+ "rr3---sn-5hne6nsy.googlevideo.com.",
+ "rr3---sn-5hne6nsz.googlevideo.com.",
+ "rr3---sn-5hne6nz6.googlevideo.com.",
+ "rr3---sn-5hne6nzd.googlevideo.com.",
+ "rr3---sn-5hne6nzk.googlevideo.com.",
+ "rr3---sn-5hne6nzs.googlevideo.com.",
+ "rr3---sn-5hne6nzy.googlevideo.com.",
+ "rr3---sn-5hnednss.googlevideo.com.",
+ "rr3---sn-5hnednsz.googlevideo.com.",
+ "rr3---sn-5hnekn76.googlevideo.com.",
+ "rr3---sn-5hnekn7d.googlevideo.com.",
+ "rr3---sn-5hnekn7k.googlevideo.com.",
+ "rr3---sn-5hnekn7l.googlevideo.com.",
+ "rr3---sn-5hnekn7s.googlevideo.com.",
+ "rr3---sn-5hnekn7z.googlevideo.com.",
+ "rr3---sn-5hneknee.googlevideo.com.",
+ "rr3---sn-5hneknek.googlevideo.com.",
+ "rr3---sn-5hneknes.googlevideo.com.",
+ "rr3---sn-5pgnugx5h-hn2z.googlevideo.com.",
+ "rr3---sn-5uaezndd.googlevideo.com.",
+ "rr3---sn-5uaezne6.googlevideo.com.",
+ "rr3---sn-5uaezned.googlevideo.com.",
+ "rr3---sn-5uaeznes.googlevideo.com.",
+ "rr3---sn-5uaeznez.googlevideo.com.",
+ "rr3---sn-5uaeznl6.googlevideo.com.",
+ "rr3---sn-5uaeznld.googlevideo.com.",
+ "rr3---sn-5uaeznly.googlevideo.com.",
+ "rr3---sn-5uaeznlz.googlevideo.com.",
+ "rr3---sn-5uaeznrz.googlevideo.com.",
+ "rr3---sn-5uaezns7.googlevideo.com.",
+ "rr3---sn-5uaeznse.googlevideo.com.",
+ "rr3---sn-5uaeznsl.googlevideo.com.",
+ "rr3---sn-5uaeznss.googlevideo.com.",
+ "rr3---sn-5uaeznze.googlevideo.com.",
+ "rr3---sn-5ualdnle.googlevideo.com.",
+ "rr3---sn-5ualdnll.googlevideo.com.",
+ "rr3---sn-5ualdnlr.googlevideo.com.",
+ "rr3---sn-5ualdnls.googlevideo.com.",
+ "rr3---sn-5ualdns6.googlevideo.com.",
+ "rr3---sn-5ualdns7.googlevideo.com.",
+ "rr3---sn-5ualdnsd.googlevideo.com.",
+ "rr3---sn-5ualdnse.googlevideo.com.",
+ "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-5ualdnsz.googlevideo.com.",
+ "rr3---sn-5ualdnz7.googlevideo.com.",
+ "rr3---sn-5ualdnze.googlevideo.com.",
+ "rr3---sn-8qj-i5ody.googlevideo.com.",
+ "rr3---sn-8qj-nbo66.googlevideo.com.",
+ "rr3---sn-8xgp1vo-2iae.googlevideo.com.",
+ "rr3---sn-8xgp1vo-2iae7.googlevideo.com.",
+ "rr3---sn-8xgp1vo-2ial.googlevideo.com.",
+ "rr3---sn-8xgp1vo-2iay.googlevideo.com.",
+ "rr3---sn-8xgp1vo-a5me.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-p5ie.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-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-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-a5meknd6.googlevideo.com.",
+ "rr3---sn-a5meknd6.gvt1.com.",
+ "rr3---sn-a5meknde.googlevideo.com.",
+ "rr3---sn-a5mekndl.googlevideo.com.",
+ "rr3---sn-a5meknds.googlevideo.com.",
+ "rr3---sn-a5mekndz.googlevideo.com.",
+ "rr3---sn-a5mekndz.gvt1.com.",
+ "rr3---sn-a5meknsd.googlevideo.com.",
+ "rr3---sn-a5meknsy.googlevideo.com.",
+ "rr3---sn-a5meknzk.googlevideo.com.",
+ "rr3---sn-a5meknzk.gvt1.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-a5mlrnl6.gvt1.com.",
+ "rr3---sn-a5mlrnll.googlevideo.com.",
+ "rr3---sn-a5mlrnll.gvt1.com.",
+ "rr3---sn-a5mlrnls.googlevideo.com.",
+ "rr3---sn-a5mlrnlz.googlevideo.com.",
+ "rr3---sn-a5msen76.googlevideo.com.",
+ "rr3---sn-a5msen7l.googlevideo.com.",
+ "rr3---sn-a5msen7s.googlevideo.com.",
+ "rr3---sn-a5msen7z.googlevideo.com.",
+ "rr3---sn-a5msenek.googlevideo.com.",
+ "rr3---sn-a5msenek.gvt1.com.",
+ "rr3---sn-a5msener.googlevideo.com.",
+ "rr3---sn-a5msenes.googlevideo.com.",
+ "rr3---sn-a5msenl7.googlevideo.com.",
+ "rr3---sn-a5msenle.googlevideo.com.",
+ "rr3---sn-a5msenle.gvt1.com.",
+ "rr3---sn-a5msenll.googlevideo.com.",
+ "rr3---sn-ab5l6ndr.googlevideo.com.",
+ "rr3---sn-ab5l6ndy.googlevideo.com.",
+ "rr3---sn-ab5l6nk6.googlevideo.com.",
+ "rr3---sn-ab5l6nkd.googlevideo.com.",
+ "rr3---sn-ab5l6nr6.googlevideo.com.",
+ "rr3---sn-ab5l6nrd.googlevideo.com.",
+ "rr3---sn-ab5l6nrk.googlevideo.com.",
+ "rr3---sn-ab5l6nrl.googlevideo.com.",
+ "rr3---sn-ab5l6nrr.googlevideo.com.",
+ "rr3---sn-ab5l6nrs.googlevideo.com.",
+ "rr3---sn-ab5l6nrs.gvt1.com.",
+ "rr3---sn-ab5l6nrz.googlevideo.com.",
+ "rr3---sn-ab5l6nrz.gvt1.com.",
+ "rr3---sn-ab5sznld.googlevideo.com.",
+ "rr3---sn-ab5sznlk.googlevideo.com.",
+ "rr3---sn-ab5sznlk.gvt1.com.",
+ "rr3---sn-ab5sznly.googlevideo.com.",
+ "rr3---sn-ab5sznly.gvt1.com.",
+ "rr3---sn-ab5sznz6.googlevideo.com.",
+ "rr3---sn-ab5sznzd.googlevideo.com.",
+ "rr3---sn-ab5sznze.googlevideo.com.",
+ "rr3---sn-ab5sznzk.googlevideo.com.",
+ "rr3---sn-ab5sznzk.gvt1.com.",
+ "rr3---sn-ab5sznzl.googlevideo.com.",
+ "rr3---sn-ab5sznzr.googlevideo.com.",
+ "rr3---sn-ab5sznzr.gvt1.com.",
+ "rr3---sn-ab5sznzs.googlevideo.com.",
+ "rr3---sn-ab5sznzy.googlevideo.com.",
+ "rr3---sn-ab5sznzz.googlevideo.com.",
+ "rr3---sn-ab5sznzz.gvt1.com.",
+ "rr3---sn-aigl6n6s.googlevideo.com.",
+ "rr3---sn-aigl6ned.googlevideo.com.",
+ "rr3---sn-aigl6nek.googlevideo.com.",
+ "rr3---sn-aigl6nek.gvt1.com.",
+ "rr3---sn-aigl6ner.googlevideo.com.",
+ "rr3---sn-aigl6ney.googlevideo.com.",
+ "rr3---sn-aigl6nl7.googlevideo.com.",
+ "rr3---sn-aigl6ns6.googlevideo.com.",
+ "rr3---sn-aigl6nsd.googlevideo.com.",
+ "rr3---sn-aigl6nsd.gvt1.com.",
+ "rr3---sn-aigl6nsk.googlevideo.com.",
+ "rr3---sn-aigl6nsr.googlevideo.com.",
+ "rr3---sn-aigl6nz7.googlevideo.com.",
+ "rr3---sn-aigl6nzk.googlevideo.com.",
+ "rr3---sn-aigl6nzl.googlevideo.com.",
+ "rr3---sn-aigl6nzr.googlevideo.com.",
+ "rr3---sn-aigl6nzs.googlevideo.com.",
+ "rr3---sn-aigzrn76.googlevideo.com.",
+ "rr3---sn-aigzrn7d.googlevideo.com.",
+ "rr3---sn-aigzrn7e.googlevideo.com.",
+ "rr3---sn-aigzrn7k.googlevideo.com.",
+ "rr3---sn-aigzrn7l.googlevideo.com.",
+ "rr3---sn-aigzrn7s.googlevideo.com.",
+ "rr3---sn-aigzrn7z.googlevideo.com.",
+ "rr3---sn-aigzrnld.googlevideo.com.",
+ "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-aj5ua5-5c.googlevideo.com.",
+ "rr3---sn-apn7en7e.googlevideo.com.",
+ "rr3---sn-apn7en7l.googlevideo.com.",
+ "rr3---sn-apn7en7s.googlevideo.com.",
+ "rr3---sn-bg5oqxjvh-50nz.googlevideo.com.",
+ "rr3---sn-cvb7lne7.googlevideo.com.",
+ "rr3---sn-cvb7lnee.googlevideo.com.",
+ "rr3---sn-cvb7lnls.googlevideo.com.",
+ "rr3---sn-cvb7lnlz.googlevideo.com.",
+ "rr3---sn-cvb7sn7k.googlevideo.com.",
+ "rr3---sn-cvb7sn7r.googlevideo.com.",
+ "rr3---sn-h0jeened.googlevideo.com.",
+ "rr3---sn-h0jeenek.googlevideo.com.",
+ "rr3---sn-h0jeenl6.googlevideo.com.",
+ "rr3---sn-h0jeenld.googlevideo.com.",
+ "rr3---sn-h0jeenle.googlevideo.com.",
+ "rr3---sn-h0jeln7e.googlevideo.com.",
+ "rr3---sn-h0jelne6.googlevideo.com.",
+ "rr3---sn-h0jelne7.googlevideo.com.",
+ "rr3---sn-h0jelnes.googlevideo.com.",
+ "rr3---sn-h0jelnez.googlevideo.com.",
+ "rr3---sn-hjoj-gq0l.googlevideo.com.",
+ "rr3---sn-hjoj-gq0l.gvt1.com.",
+ "rr3---sn-hjoj-jaul.googlevideo.com.",
+ "rr3---sn-hjoj-poul.googlevideo.com.",
+ "rr3---sn-hoa7kn76.googlevideo.com.",
+ "rr3---sn-hoa7kn7z.googlevideo.com.",
+ "rr3---sn-hoa7rn76.googlevideo.com.",
+ "rr3---sn-hoa7rn7z.googlevideo.com.",
+ "rr3---sn-hp57kn6r.googlevideo.com.",
+ "rr3---sn-hp57kn6r.gvt1.com.",
+ "rr3---sn-hp57kn6y.googlevideo.com.",
+ "rr3---sn-hp57knd6.googlevideo.com.",
+ "rr3---sn-hp57kndd.googlevideo.com.",
+ "rr3---sn-hp57kndk.googlevideo.com.",
+ "rr3---sn-hp57kndr.googlevideo.com.",
+ "rr3---sn-hp57knds.googlevideo.com.",
+ "rr3---sn-hp57kndy.googlevideo.com.",
+ "rr3---sn-hp57yn7r.googlevideo.com.",
+ "rr3---sn-hp57yn7y.googlevideo.com.",
+ "rr3---sn-hp57yne7.googlevideo.com.",
+ "rr3---sn-hp57ynee.googlevideo.com.",
+ "rr3---sn-hp57ynee.gvt1.com.",
+ "rr3---sn-hp57ynl6.googlevideo.com.",
+ "rr3---sn-hp57ynlr.googlevideo.com.",
+ "rr3---sn-hp57ynlr.gvt1.com.",
+ "rr3---sn-hp57ynly.googlevideo.com.",
+ "rr3---sn-hp57ynly.gvt1.com.",
+ "rr3---sn-hp57yns7.googlevideo.com.",
+ "rr3---sn-hp57ynse.googlevideo.com.",
+ "rr3---sn-hp57ynsl.googlevideo.com.",
+ "rr3---sn-hp57ynss.googlevideo.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.",
+ "rr3---sn-i3b7knse.googlevideo.com.",
+ "rr3---sn-i3b7knsl.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-i3belnlz.googlevideo.com.",
+ "rr3---sn-i3bssn7e.googlevideo.com.",
+ "rr3---sn-i5f5ppuxa-ioal.googlevideo.com.",
+ "rr3---sn-i5goxu-i3bl.googlevideo.com.",
+ "rr3---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr3---sn-jvhj5nu-2iae.googlevideo.com.",
+ "rr3---sn-jvhj5nu-2ial.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-jvhj5nu-qufe.googlevideo.com.",
+ "rr3---sn-jvhj5nu-qufl.googlevideo.com.",
+ "rr3---sn-jvhj5nu-qufz.googlevideo.com.",
+ "rr3---sn-jxopj-n5oe.googlevideo.com.",
+ "rr3---sn-jxopj-n5oe.gvt1.com.",
+ "rr3---sn-jxopj-nh4e.googlevideo.com.",
+ "rr3---sn-jxopj-nh4e.gvt1.com.",
+ "rr3---sn-muxa-2iae.googlevideo.com.",
+ "rr3---sn-n4v7snee.googlevideo.com.",
+ "rr3---sn-n4v7sney.googlevideo.com.",
+ "rr3---sn-n4v7snl7.googlevideo.com.",
+ "rr3---sn-n4v7snll.googlevideo.com.",
+ "rr3---sn-n4v7snlr.googlevideo.com.",
+ "rr3---sn-n4v7snls.googlevideo.com.",
+ "rr3---sn-n4v7snly.googlevideo.com.",
+ "rr3---sn-n4v7sns7.googlevideo.com.",
+ "rr3---sn-n4v7snse.googlevideo.com.",
+ "rr3---sn-npoe7ndl.googlevideo.com.",
+ "rr3---sn-npoe7nds.googlevideo.com.",
+ "rr3---sn-npoe7ne6.googlevideo.com.",
+ "rr3---sn-npoe7ne7.googlevideo.com.",
+ "rr3---sn-npoe7ned.googlevideo.com.",
+ "rr3---sn-npoe7nek.googlevideo.com.",
+ "rr3---sn-npoe7ner.googlevideo.com.",
+ "rr3---sn-npoe7nes.googlevideo.com.",
+ "rr3---sn-npoe7ney.googlevideo.com.",
+ "rr3---sn-npoe7nez.googlevideo.com.",
+ "rr3---sn-npoe7nl6.googlevideo.com.",
+ "rr3---sn-npoe7nlz.googlevideo.com.",
+ "rr3---sn-npoe7ns6.googlevideo.com.",
+ "rr3---sn-npoe7ns7.googlevideo.com.",
+ "rr3---sn-npoe7nsd.googlevideo.com.",
+ "rr3---sn-npoe7nsk.googlevideo.com.",
+ "rr3---sn-npoe7nsl.googlevideo.com.",
+ "rr3---sn-npoe7nsr.googlevideo.com.",
+ "rr3---sn-npoe7nss.googlevideo.com.",
+ "rr3---sn-npoe7nsy.googlevideo.com.",
+ "rr3---sn-npoe7nz7.googlevideo.com.",
+ "rr3---sn-npoeene6.googlevideo.com.",
+ "rr3---sn-npoeened.googlevideo.com.",
+ "rr3---sn-npoeenee.googlevideo.com.",
+ "rr3---sn-npoeenek.googlevideo.com.",
+ "rr3---sn-npoeener.googlevideo.com.",
+ "rr3---sn-npoeenez.googlevideo.com.",
+ "rr3---sn-npoeenl7.googlevideo.com.",
+ "rr3---sn-npoeenle.googlevideo.com.",
+ "rr3---sn-npoeenlk.googlevideo.com.",
+ "rr3---sn-npoeenll.googlevideo.com.",
+ "rr3---sn-npoeenly.googlevideo.com.",
+ "rr3---sn-npoeens7.googlevideo.com.",
+ "rr3---sn-npoldn76.googlevideo.com.",
+ "rr3---sn-npoldn7d.googlevideo.com.",
+ "rr3---sn-npoldn7e.googlevideo.com.",
+ "rr3---sn-npoldn7l.googlevideo.com.",
+ "rr3---sn-npoldn7s.googlevideo.com.",
+ "rr3---sn-npoldn7y.googlevideo.com.",
+ "rr3---sn-npoldn7z.googlevideo.com.",
+ "rr3---sn-npoldne7.googlevideo.com.",
+ "rr3---sn-nv0ui4gvou-hape.googlevideo.com.",
+ "rr3---sn-nx57ynsd.googlevideo.com.",
+ "rr3---sn-nx57ynsd.gvt1.com.",
+ "rr3---sn-nx57ynsk.googlevideo.com.",
+ "rr3---sn-nx57ynsl.googlevideo.com.",
+ "rr3---sn-nx57ynss.googlevideo.com.",
+ "rr3---sn-nx57ynsz.googlevideo.com.",
+ "rr3---sn-nx57ynsz.gvt1.com.",
+ "rr3---sn-nx5s7n76.googlevideo.com.",
+ "rr3---sn-nx5s7n76.gvt1.com.",
+ "rr3---sn-nx5s7n7d.googlevideo.com.",
+ "rr3---sn-nx5s7n7d.gvt1.com.",
+ "rr3---sn-nx5s7n7y.googlevideo.com.",
+ "rr3---sn-nx5s7n7y.gvt1.com.",
+ "rr3---sn-nx5s7n7z.googlevideo.com.",
+ "rr3---sn-nx5s7n7z.gvt1.com.",
+ "rr3---sn-nx5s7nee.googlevideo.com.",
+ "rr3---sn-nx5s7nee.gvt1.com.",
+ "rr3---sn-o097znsd.googlevideo.com.",
+ "rr3---sn-o097znse.googlevideo.com.",
+ "rr3---sn-o097znsk.googlevideo.com.",
+ "rr3---sn-o097znsl.googlevideo.com.",
+ "rr3---sn-o097znsr.googlevideo.com.",
+ "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-ounjvhh-acce.googlevideo.com.",
+ "rr3---sn-p5qddn76.googlevideo.com.",
+ "rr3---sn-p5qddn7d.googlevideo.com.",
+ "rr3---sn-p5qddn7k.googlevideo.com.",
+ "rr3---sn-p5qddn7r.googlevideo.com.",
+ "rr3---sn-p5qlsn6l.googlevideo.com.",
+ "rr3---sn-p5qlsn76.googlevideo.com.",
+ "rr3---sn-p5qlsn7d.googlevideo.com.",
+ "rr3---sn-p5qlsn7l.googlevideo.com.",
+ "rr3---sn-p5qlsn7s.googlevideo.com.",
+ "rr3---sn-p5qlsnd6.googlevideo.com.",
+ "rr3---sn-p5qlsndd.googlevideo.com.",
+ "rr3---sn-p5qlsndk.googlevideo.com.",
+ "rr3---sn-p5qlsndr.googlevideo.com.",
+ "rr3---sn-p5qlsndz.googlevideo.com.",
+ "rr3---sn-p5qlsnrl.googlevideo.com.",
+ "rr3---sn-p5qlsny6.googlevideo.com.",
+ "rr3---sn-p5qs7n6d.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-q4fl6n66.gvt1.com.",
+ "rr3---sn-q4fl6n6d.googlevideo.com.",
+ "rr3---sn-q4fl6n6d.gvt1.com.",
+ "rr3---sn-q4fl6n6r.googlevideo.com.",
+ "rr3---sn-q4fl6n6r.gvt1.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-q4fl6nd6.googlevideo.com.",
+ "rr3---sn-q4fl6nd7.googlevideo.com.",
+ "rr3---sn-q4fl6nde.googlevideo.com.",
+ "rr3---sn-q4fl6ndl.googlevideo.com.",
+ "rr3---sn-q4fl6nds.googlevideo.com.",
+ "rr3---sn-q4fl6nds.gvt1.com.",
+ "rr3---sn-q4fl6ndz.googlevideo.com.",
+ "rr3---sn-q4fl6ndz.gvt1.com.",
+ "rr3---sn-q4fl6nlz.googlevideo.com.",
+ "rr3---sn-q4fl6nlz.gvt1.com.",
+ "rr3---sn-q4fl6ns6.googlevideo.com.",
+ "rr3---sn-q4fl6ns6.gvt1.com.",
+ "rr3---sn-q4fl6nsd.googlevideo.com.",
+ "rr3---sn-q4fl6nsd.gvt1.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-q4fl6nsy.gvt1.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-q4fl6nzy.gvt1.com.",
+ "rr3---sn-q4flrn7k.googlevideo.com.",
+ "rr3---sn-q4flrn7k.gvt1.com.",
+ "rr3---sn-q4flrn7r.googlevideo.com.",
+ "rr3---sn-q4flrn7r.gvt1.com.",
+ "rr3---sn-q4flrn7y.googlevideo.com.",
+ "rr3---sn-q4flrne6.googlevideo.com.",
+ "rr3---sn-q4flrne7.googlevideo.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-q4flrney.googlevideo.com.",
+ "rr3---sn-q4flrney.gvt1.com.",
+ "rr3---sn-q4flrnez.googlevideo.com.",
+ "rr3---sn-q4flrnez.gvt1.com.",
+ "rr3---sn-q4flrnl6.googlevideo.com.",
+ "rr3---sn-q4flrnl6.gvt1.com.",
+ "rr3---sn-q4flrnl7.googlevideo.com.",
+ "rr3---sn-q4flrnl7.gvt1.com.",
+ "rr3---sn-q4flrnld.googlevideo.com.",
+ "rr3---sn-q4flrnld.gvt1.com.",
+ "rr3---sn-q4flrnle.googlevideo.com.",
+ "rr3---sn-q4flrnle.gvt1.com.",
+ "rr3---sn-q4flrnlz.googlevideo.com.",
+ "rr3---sn-q4flrnsd.googlevideo.com.",
+ "rr3---sn-q4flrnsd.gvt1.com.",
+ "rr3---sn-q4flrnsk.googlevideo.com.",
+ "rr3---sn-q4flrnsk.gvt1.com.",
+ "rr3---sn-q4flrnsl.googlevideo.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-q4fzen7r.googlevideo.com.",
+ "rr3---sn-q4fzen7r.gvt1.com.",
+ "rr3---sn-q4fzen7s.googlevideo.com.",
+ "rr3---sn-q4fzen7s.gvt1.com.",
+ "rr3---sn-q4fzen7y.googlevideo.com.",
+ "rr3---sn-q4fzen7y.gvt1.com.",
+ "rr3---sn-q4fzene7.googlevideo.com.",
+ "rr3---sn-q4fzene7.gvt1.com.",
+ "rr3---sn-q4fzenee.googlevideo.com.",
+ "rr3---sn-q4fzenee.gvt1.com.",
+ "rr3---sn-qxo7rn7k.googlevideo.com.",
+ "rr3---sn-qxo7rn7r.googlevideo.com.",
+ "rr3---sn-qxo7rn7y.googlevideo.com.",
+ "rr3---sn-qxoedn7k.googlevideo.com.",
+ "rr3---sn-qxoednee.googlevideo.com.",
+ "rr3---sn-u1hp55-5c.googlevideo.com.",
+ "rr3---sn-uhvcpaxoa-5hne.googlevideo.com.",
+ "rr3---sn-uhvcpaxoa-guhe.googlevideo.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-vgqsknek.gvt1.com.",
+ "rr3---sn-vgqsknes.googlevideo.com.",
+ "rr3---sn-vgqsknes.gvt1.com.",
+ "rr3---sn-vgqsknez.googlevideo.com.",
+ "rr3---sn-vgqsknld.googlevideo.com.",
+ "rr3---sn-vgqsknld.gvt1.com.",
+ "rr3---sn-vgqsknlk.googlevideo.com.",
+ "rr3---sn-vgqsknll.googlevideo.com.",
+ "rr3---sn-vgqsknlr.googlevideo.com.",
+ "rr3---sn-vgqsknls.googlevideo.com.",
+ "rr3---sn-vgqsknly.googlevideo.com.",
+ "rr3---sn-vgqsknlz.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-vgqsknzd.gvt1.com.",
+ "rr3---sn-vgqsknze.googlevideo.com.",
+ "rr3---sn-vgqsknzk.googlevideo.com.",
+ "rr3---sn-vgqsknzk.gvt1.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-vgqsknzz.gvt1.com.",
+ "rr3---sn-vgqsrn66.googlevideo.com.",
+ "rr3---sn-vgqsrn67.googlevideo.com.",
+ "rr3---sn-vgqsrn6e.googlevideo.com.",
+ "rr3---sn-vgqsrn6l.googlevideo.com.",
+ "rr3---sn-vgqsrn6l.gvt1.com.",
+ "rr3---sn-vgqsrn6z.googlevideo.com.",
+ "rr3---sn-vgqsrn6z.gvt1.com.",
+ "rr3---sn-vgqsrne6.googlevideo.com.",
+ "rr3---sn-vgqsrned.googlevideo.com.",
+ "rr3---sn-vgqsrnek.googlevideo.com.",
+ "rr3---sn-vgqsrnes.googlevideo.com.",
+ "rr3---sn-vgqsrnez.googlevideo.com.",
+ "rr3---sn-vgqsrnl6.googlevideo.com.",
+ "rr3---sn-vgqsrnl6.gvt1.com.",
+ "rr3---sn-vgqsrnld.googlevideo.com.",
+ "rr3---sn-vgqsrnlk.googlevideo.com.",
+ "rr3---sn-vgqsrnll.googlevideo.com.",
+ "rr3---sn-vgqsrnll.gvt1.com.",
+ "rr3---sn-vgqsrnls.googlevideo.com.",
+ "rr3---sn-vgqsrnls.gvt1.com.",
+ "rr3---sn-vgqsrnlz.googlevideo.com.",
+ "rr3---sn-vgqsrns6.googlevideo.com.",
+ "rr3---sn-vgqsrnsd.googlevideo.com.",
+ "rr3---sn-vgqsrnsr.googlevideo.com.",
+ "rr3---sn-vgqsrnsr.gvt1.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-vgqsrnzk.gvt1.com.",
+ "rr3---sn-vgqsrnzr.googlevideo.com.",
+ "rr3---sn-vgqsrnzs.googlevideo.com.",
+ "rr3---sn-vgqsrnzy.googlevideo.com.",
+ "rr3---sn-vgqsrnzz.googlevideo.com.",
+ "rr3.sn-a5meknzr.googlevideo.com.",
+ "rr3.sn-q4fl6n66.googlevideo.com.",
+ "rr3.sn-q4flrne7.googlevideo.com.",
+ "rr4---sn-0nnpbo5a-bggl.googlevideo.com.",
+ "rr4---sn-2imern76.googlevideo.com.",
+ "rr4---sn-2imern76.gvt1.com.",
+ "rr4---sn-2imern7d.googlevideo.com.",
+ "rr4---sn-2imeyn7k.googlevideo.com.",
+ "rr4---sn-2imeyn7k.gvt1.com.",
+ "rr4---sn-2oaig5-55.googlevideo.com.",
+ "rr4---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr4---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
+ "rr4---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
+ "rr4---sn-2vgu0b5auxaxjvh-v2vz.googlevideo.com.",
+ "rr4---sn-30a7rne6.googlevideo.com.",
+ "rr4---sn-30a7rned.googlevideo.com.",
+ "rr4---sn-30a7rnek.googlevideo.com.",
+ "rr4---sn-30a7rner.googlevideo.com.",
+ "rr4---sn-30a7ynek.googlevideo.com.",
+ "rr4---sn-30a7yner.googlevideo.com.",
+ "rr4---sn-30a7yney.googlevideo.com.",
+ "rr4---sn-30a7ynl7.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-4g5e6nsz.googlevideo.com.",
+ "rr4---sn-4g5e6nz7.googlevideo.com.",
+ "rr4---sn-4g5e6nze.googlevideo.com.",
+ "rr4---sn-4g5e6nzl.googlevideo.com.",
+ "rr4---sn-4g5e6nzs.googlevideo.com.",
+ "rr4---sn-4g5e6nzz.googlevideo.com.",
+ "rr4---sn-4g5edn6r.googlevideo.com.",
+ "rr4---sn-4g5edn6y.googlevideo.com.",
+ "rr4---sn-4g5ednd7.googlevideo.com.",
+ "rr4---sn-4g5edndd.googlevideo.com.",
+ "rr4---sn-4g5ednde.googlevideo.com.",
+ "rr4---sn-4g5edndk.googlevideo.com.",
+ "rr4---sn-4g5edndl.googlevideo.com.",
+ "rr4---sn-4g5edndr.googlevideo.com.",
+ "rr4---sn-4g5edndy.googlevideo.com.",
+ "rr4---sn-4g5edndz.googlevideo.com.",
+ "rr4---sn-4g5ednkl.googlevideo.com.",
+ "rr4---sn-4g5ednld.googlevideo.com.",
+ "rr4---sn-4g5ednly.googlevideo.com.",
+ "rr4---sn-4g5edns6.googlevideo.com.",
+ "rr4---sn-4g5edns7.googlevideo.com.",
+ "rr4---sn-4g5ednsd.googlevideo.com.",
+ "rr4---sn-4g5ednse.googlevideo.com.",
+ "rr4---sn-4g5ednsk.googlevideo.com.",
+ "rr4---sn-4g5ednsl.googlevideo.com.",
+ "rr4---sn-4g5ednsr.googlevideo.com.",
+ "rr4---sn-4g5ednss.googlevideo.com.",
+ "rr4---sn-4g5ednsz.googlevideo.com.",
+ "rr4---sn-4g5ednz7.googlevideo.com.",
+ "rr4---sn-4g5lzne6.googlevideo.com.",
+ "rr4---sn-4g5lzned.googlevideo.com.",
+ "rr4---sn-4g5lzner.googlevideo.com.",
+ "rr4---sn-4g5lznes.googlevideo.com.",
+ "rr4---sn-4g5lzney.googlevideo.com.",
+ "rr4---sn-4g5lznez.googlevideo.com.",
+ "rr4---sn-4g5lznl6.googlevideo.com.",
+ "rr4---sn-4g5lznl7.googlevideo.com.",
+ "rr4---sn-4g5lznle.googlevideo.com.",
+ "rr4---sn-4g5lznls.googlevideo.com.",
+ "rr4---sn-4g5lznlz.googlevideo.com.",
+ "rr4---sn-5hne6n6e.googlevideo.com.",
+ "rr4---sn-5hne6n6l.googlevideo.com.",
+ "rr4---sn-5hne6ns6.googlevideo.com.",
+ "rr4---sn-5hne6nsd.googlevideo.com.",
+ "rr4---sn-5hne6nsr.googlevideo.com.",
+ "rr4---sn-5hne6nsy.googlevideo.com.",
+ "rr4---sn-5hne6nsz.googlevideo.com.",
+ "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.",
+ "rr4---sn-5hnekn76.googlevideo.com.",
+ "rr4---sn-5hnekn7d.googlevideo.com.",
+ "rr4---sn-5hnekn7k.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.",
+ "rr4---sn-5pgnugx5h-hn2z.googlevideo.com.",
+ "rr4---sn-5uaezndd.googlevideo.com.",
+ "rr4---sn-5uaezne6.googlevideo.com.",
+ "rr4---sn-5uaezned.googlevideo.com.",
+ "rr4---sn-5uaeznes.googlevideo.com.",
+ "rr4---sn-5uaeznez.googlevideo.com.",
+ "rr4---sn-5uaeznl6.googlevideo.com.",
+ "rr4---sn-5uaeznld.googlevideo.com.",
+ "rr4---sn-5uaeznly.googlevideo.com.",
+ "rr4---sn-5uaeznlz.googlevideo.com.",
+ "rr4---sn-5uaeznrz.googlevideo.com.",
+ "rr4---sn-5uaezns7.googlevideo.com.",
+ "rr4---sn-5uaeznse.googlevideo.com.",
+ "rr4---sn-5uaeznsl.googlevideo.com.",
+ "rr4---sn-5uaeznss.googlevideo.com.",
+ "rr4---sn-5uaezny6.googlevideo.com.",
+ "rr4---sn-5uaeznys.googlevideo.com.",
+ "rr4---sn-5uaeznyz.googlevideo.com.",
+ "rr4---sn-5uaeznze.googlevideo.com.",
+ "rr4---sn-5ualdnle.googlevideo.com.",
+ "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-5ualdnsy.googlevideo.com.",
+ "rr4---sn-5ualdnsz.googlevideo.com.",
+ "rr4---sn-5ualdnz7.googlevideo.com.",
+ "rr4---sn-5ualdnze.googlevideo.com.",
+ "rr4---sn-8qj-i5ody.googlevideo.com.",
+ "rr4---sn-8qj-nbo66.googlevideo.com.",
+ "rr4---sn-8xgp1vo-2iae.googlevideo.com.",
+ "rr4---sn-8xgp1vo-2iae7.googlevideo.com.",
+ "rr4---sn-8xgp1vo-2ial.googlevideo.com.",
+ "rr4---sn-8xgp1vo-2iay.googlevideo.com.",
+ "rr4---sn-8xgp1vo-a5me.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-hp5e.googlevideo.com.",
+ "rr4---sn-8xgp1vo-nh4e.googlevideo.com.",
+ "rr4---sn-8xgp1vo-p5ie.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-9gv76n7l.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-a5m7lnl6.gvt1.com.",
+ "rr4---sn-a5m7lnld.googlevideo.com.",
+ "rr4---sn-a5m7lnld.gvt1.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-a5meknds.gvt1.com.",
+ "rr4---sn-a5mekndz.googlevideo.com.",
+ "rr4---sn-a5meknsd.googlevideo.com.",
+ "rr4---sn-a5meknsy.googlevideo.com.",
+ "rr4---sn-a5meknzk.googlevideo.com.",
+ "rr4---sn-a5meknzl.googlevideo.com.",
+ "rr4---sn-a5meknzr.googlevideo.com.",
+ "rr4---sn-a5meknzr.gvt1.com.",
+ "rr4---sn-a5meknzs.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-a5msenes.googlevideo.com.",
+ "rr4---sn-a5msenes.gvt1.com.",
+ "rr4---sn-a5msenl7.googlevideo.com.",
+ "rr4---sn-a5msenle.googlevideo.com.",
+ "rr4---sn-a5msenle.gvt1.com.",
+ "rr4---sn-a5msenll.googlevideo.com.",
+ "rr4---sn-ab5l6ndr.googlevideo.com.",
+ "rr4---sn-ab5l6ndy.googlevideo.com.",
+ "rr4---sn-ab5l6ndy.gvt1.com.",
+ "rr4---sn-ab5l6nk6.googlevideo.com.",
+ "rr4---sn-ab5l6nk6.gvt1.com.",
+ "rr4---sn-ab5l6nkd.googlevideo.com.",
+ "rr4---sn-ab5l6nkd.gvt1.com.",
+ "rr4---sn-ab5l6nr6.googlevideo.com.",
+ "rr4---sn-ab5l6nrd.googlevideo.com.",
+ "rr4---sn-ab5l6nrk.googlevideo.com.",
+ "rr4---sn-ab5l6nrl.googlevideo.com.",
+ "rr4---sn-ab5l6nrr.googlevideo.com.",
+ "rr4---sn-ab5l6nrr.gvt1.com.",
+ "rr4---sn-ab5l6nrs.googlevideo.com.",
+ "rr4---sn-ab5l6nrz.googlevideo.com.",
+ "rr4---sn-ab5sznld.googlevideo.com.",
+ "rr4---sn-ab5sznlk.googlevideo.com.",
+ "rr4---sn-ab5sznly.googlevideo.com.",
+ "rr4---sn-ab5sznz6.googlevideo.com.",
+ "rr4---sn-ab5sznzd.googlevideo.com.",
+ "rr4---sn-ab5sznze.googlevideo.com.",
+ "rr4---sn-ab5sznzk.googlevideo.com.",
+ "rr4---sn-ab5sznzl.googlevideo.com.",
+ "rr4---sn-ab5sznzr.googlevideo.com.",
+ "rr4---sn-ab5sznzr.gvt1.com.",
+ "rr4---sn-ab5sznzs.googlevideo.com.",
+ "rr4---sn-ab5sznzy.googlevideo.com.",
+ "rr4---sn-ab5sznzy.gvt1.com.",
+ "rr4---sn-ab5sznzz.googlevideo.com.",
+ "rr4---sn-aigl6n6s.googlevideo.com.",
+ "rr4---sn-aigl6ned.googlevideo.com.",
+ "rr4---sn-aigl6ner.googlevideo.com.",
+ "rr4---sn-aigl6ney.googlevideo.com.",
+ "rr4---sn-aigl6nl7.googlevideo.com.",
+ "rr4---sn-aigl6ns6.googlevideo.com.",
+ "rr4---sn-aigl6nsd.googlevideo.com.",
+ "rr4---sn-aigl6nsk.googlevideo.com.",
+ "rr4---sn-aigl6nsr.googlevideo.com.",
+ "rr4---sn-aigl6nz7.googlevideo.com.",
+ "rr4---sn-aigl6nze.googlevideo.com.",
+ "rr4---sn-aigl6nzk.googlevideo.com.",
+ "rr4---sn-aigl6nzl.googlevideo.com.",
+ "rr4---sn-aigl6nzr.googlevideo.com.",
+ "rr4---sn-aigl6nzs.googlevideo.com.",
+ "rr4---sn-aigzrn76.googlevideo.com.",
+ "rr4---sn-aigzrn7d.googlevideo.com.",
+ "rr4---sn-aigzrn7e.googlevideo.com.",
+ "rr4---sn-aigzrn7k.googlevideo.com.",
+ "rr4---sn-aigzrn7l.googlevideo.com.",
+ "rr4---sn-aigzrn7s.googlevideo.com.",
+ "rr4---sn-aigzrn7z.googlevideo.com.",
+ "rr4---sn-aigzrnld.googlevideo.com.",
+ "rr4---sn-aigzrnse.googlevideo.com.",
+ "rr4---sn-aigzrnsl.googlevideo.com.",
+ "rr4---sn-aigzrnsr.googlevideo.com.",
+ "rr4---sn-aigzrnss.googlevideo.com.",
+ "rr4---sn-aigzrnsz.googlevideo.com.",
+ "rr4---sn-aigzrnz7.googlevideo.com.",
+ "rr4---sn-aigzrnze.googlevideo.com.",
+ "rr4---sn-aj5ua5-5c.googlevideo.com.",
+ "rr4---sn-apn7en7e.googlevideo.com.",
+ "rr4---sn-apn7en7l.googlevideo.com.",
+ "rr4---sn-apn7en7s.googlevideo.com.",
+ "rr4---sn-bg5oqxjvh-50nz.googlevideo.com.",
+ "rr4---sn-cvb7lne7.googlevideo.com.",
+ "rr4---sn-cvb7lnee.googlevideo.com.",
+ "rr4---sn-cvb7lnl7.googlevideo.com.",
+ "rr4---sn-cvb7lnls.googlevideo.com.",
+ "rr4---sn-cvb7lnlz.googlevideo.com.",
+ "rr4---sn-cvb7sn7k.googlevideo.com.",
+ "rr4---sn-cvb7sn7r.googlevideo.com.",
+ "rr4---sn-h0jeened.googlevideo.com.",
+ "rr4---sn-h0jeenl6.googlevideo.com.",
+ "rr4---sn-h0jeenld.googlevideo.com.",
+ "rr4---sn-h0jeenle.googlevideo.com.",
+ "rr4---sn-h0jelne6.googlevideo.com.",
+ "rr4---sn-h0jelne7.googlevideo.com.",
+ "rr4---sn-h0jelnes.googlevideo.com.",
+ "rr4---sn-h0jelnez.googlevideo.com.",
+ "rr4---sn-hjoj-gq0l.googlevideo.com.",
+ "rr4---sn-hjoj-gq0l.gvt1.com.",
+ "rr4---sn-hoa7kn76.googlevideo.com.",
+ "rr4---sn-hoa7kn7z.googlevideo.com.",
+ "rr4---sn-hoa7rn76.googlevideo.com.",
+ "rr4---sn-hoa7rn7z.googlevideo.com.",
+ "rr4---sn-hp57kn6y.googlevideo.com.",
+ "rr4---sn-hp57knd6.googlevideo.com.",
+ "rr4---sn-hp57kndd.googlevideo.com.",
+ "rr4---sn-hp57kndk.googlevideo.com.",
+ "rr4---sn-hp57kndk.gvt1.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.",
+ "rr4---sn-hp57yn7r.googlevideo.com.",
+ "rr4---sn-hp57yn7y.googlevideo.com.",
+ "rr4---sn-hp57yne7.googlevideo.com.",
+ "rr4---sn-hp57ynly.googlevideo.com.",
+ "rr4---sn-hp57yns7.googlevideo.com.",
+ "rr4---sn-hp57ynse.googlevideo.com.",
+ "rr4---sn-hp57ynsl.googlevideo.com.",
+ "rr4---sn-hp57ynss.googlevideo.com.",
+ "rr4---sn-i3b7kn6s.googlevideo.com.",
+ "rr4---sn-i3b7knld.googlevideo.com.",
+ "rr4---sn-i3b7knlk.googlevideo.com.",
+ "rr4---sn-i3b7kns6.googlevideo.com.",
+ "rr4---sn-i3b7knsd.googlevideo.com.",
+ "rr4---sn-i3b7knse.googlevideo.com.",
+ "rr4---sn-i3b7knsl.googlevideo.com.",
+ "rr4---sn-i3b7knzs.googlevideo.com.",
+ "rr4---sn-i3belne6.googlevideo.com.",
+ "rr4---sn-i3belnl6.googlevideo.com.",
+ "rr4---sn-i3belnl7.googlevideo.com.",
+ "rr4---sn-i3belnll.googlevideo.com.",
+ "rr4---sn-i3belnls.googlevideo.com.",
+ "rr4---sn-i3belnlz.googlevideo.com.",
+ "rr4---sn-i3bssn7e.googlevideo.com.",
+ "rr4---sn-i5f5ppuxa-ioal.googlevideo.com.",
+ "rr4---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr4---sn-jvhj5nu-2iae.googlevideo.com.",
+ "rr4---sn-jvhj5nu-2ial.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-jvhj5nu-qufe.googlevideo.com.",
+ "rr4---sn-jvhj5nu-qufl.googlevideo.com.",
+ "rr4---sn-jvhj5nu-qufs.googlevideo.com.",
+ "rr4---sn-jvhj5nu-qufz.googlevideo.com.",
+ "rr4---sn-jxopj-n5oe.googlevideo.com.",
+ "rr4---sn-jxopj-n5oe.gvt1.com.",
+ "rr4---sn-jxopj-nh4e.googlevideo.com.",
+ "rr4---sn-jxopj-nh4e.gvt1.com.",
+ "rr4---sn-muxa-2iae.googlevideo.com.",
+ "rr4---sn-n4v7snee.googlevideo.com.",
+ "rr4---sn-n4v7snl7.googlevideo.com.",
+ "rr4---sn-n4v7snll.googlevideo.com.",
+ "rr4---sn-n4v7snlr.googlevideo.com.",
+ "rr4---sn-n4v7snls.googlevideo.com.",
+ "rr4---sn-n4v7snly.googlevideo.com.",
+ "rr4---sn-n4v7sns7.googlevideo.com.",
+ "rr4---sn-n4v7snse.googlevideo.com.",
+ "rr4---sn-npoe7ndl.googlevideo.com.",
+ "rr4---sn-npoe7nds.googlevideo.com.",
+ "rr4---sn-npoe7ne6.googlevideo.com.",
+ "rr4---sn-npoe7ne7.googlevideo.com.",
+ "rr4---sn-npoe7ned.googlevideo.com.",
+ "rr4---sn-npoe7nek.googlevideo.com.",
+ "rr4---sn-npoe7ner.googlevideo.com.",
+ "rr4---sn-npoe7nes.googlevideo.com.",
+ "rr4---sn-npoe7ney.googlevideo.com.",
+ "rr4---sn-npoe7nez.googlevideo.com.",
+ "rr4---sn-npoe7nl6.googlevideo.com.",
+ "rr4---sn-npoe7nlz.googlevideo.com.",
+ "rr4---sn-npoe7ns6.googlevideo.com.",
+ "rr4---sn-npoe7ns7.googlevideo.com.",
+ "rr4---sn-npoe7nsd.googlevideo.com.",
+ "rr4---sn-npoe7nsk.googlevideo.com.",
+ "rr4---sn-npoe7nsl.googlevideo.com.",
+ "rr4---sn-npoe7nsr.googlevideo.com.",
+ "rr4---sn-npoe7nss.googlevideo.com.",
+ "rr4---sn-npoe7nsy.googlevideo.com.",
+ "rr4---sn-npoe7nz7.googlevideo.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-npoeeney.googlevideo.com.",
+ "rr4---sn-npoeenez.googlevideo.com.",
+ "rr4---sn-npoeenl7.googlevideo.com.",
+ "rr4---sn-npoeenle.googlevideo.com.",
+ "rr4---sn-npoeenlk.googlevideo.com.",
+ "rr4---sn-npoeenll.googlevideo.com.",
+ "rr4---sn-npoeens7.googlevideo.com.",
+ "rr4---sn-npoldn76.googlevideo.com.",
+ "rr4---sn-npoldn7d.googlevideo.com.",
+ "rr4---sn-npoldn7e.googlevideo.com.",
+ "rr4---sn-npoldn7l.googlevideo.com.",
+ "rr4---sn-npoldn7s.googlevideo.com.",
+ "rr4---sn-npoldn7y.googlevideo.com.",
+ "rr4---sn-npoldne7.googlevideo.com.",
+ "rr4---sn-ntq7yney.googlevideo.com.",
+ "rr4---sn-nv0ui4gvou-hape.googlevideo.com.",
+ "rr4---sn-nx57ynlk.googlevideo.com.",
+ "rr4---sn-nx57ynlk.gvt1.com.",
+ "rr4---sn-nx57ynsd.googlevideo.com.",
+ "rr4---sn-nx57ynsk.googlevideo.com.",
+ "rr4---sn-nx57ynsl.googlevideo.com.",
+ "rr4---sn-nx57ynss.googlevideo.com.",
+ "rr4---sn-nx57ynss.gvt1.com.",
+ "rr4---sn-nx57ynsz.googlevideo.com.",
+ "rr4---sn-nx57ynsz.gvt1.com.",
+ "rr4---sn-nx5s7n76.googlevideo.com.",
+ "rr4---sn-nx5s7n7d.googlevideo.com.",
+ "rr4---sn-nx5s7n7d.gvt1.com.",
+ "rr4---sn-nx5s7n7s.googlevideo.com.",
+ "rr4---sn-nx5s7n7y.googlevideo.com.",
+ "rr4---sn-nx5s7n7y.gvt1.com.",
+ "rr4---sn-nx5s7n7z.googlevideo.com.",
+ "rr4---sn-nx5s7nee.googlevideo.com.",
+ "rr4---sn-nx5s7nel.googlevideo.com.",
+ "rr4---sn-nx5s7nel.gvt1.com.",
+ "rr4---sn-o097znsd.googlevideo.com.",
+ "rr4---sn-o097znse.googlevideo.com.",
+ "rr4---sn-o097znsk.googlevideo.com.",
+ "rr4---sn-o097znsl.googlevideo.com.",
+ "rr4---sn-o097znsr.googlevideo.com.",
+ "rr4---sn-o097znss.googlevideo.com.",
+ "rr4---sn-o097znsz.googlevideo.com.",
+ "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-p5qddn76.googlevideo.com.",
+ "rr4---sn-p5qddn7d.googlevideo.com.",
+ "rr4---sn-p5qddn7k.googlevideo.com.",
+ "rr4---sn-p5qddn7r.googlevideo.com.",
+ "rr4---sn-p5qddn7z.googlevideo.com.",
+ "rr4---sn-p5qlsn6l.googlevideo.com.",
+ "rr4---sn-p5qlsn76.googlevideo.com.",
+ "rr4---sn-p5qlsn7d.googlevideo.com.",
+ "rr4---sn-p5qlsn7l.googlevideo.com.",
+ "rr4---sn-p5qlsn7s.googlevideo.com.",
+ "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-p5qs7nsk.googlevideo.com.",
+ "rr4---sn-p5qs7nsr.googlevideo.com.",
+ "rr4---sn-p5qs7nzk.googlevideo.com.",
+ "rr4---sn-p5qs7nzr.googlevideo.com.",
+ "rr4---sn-p5qs7nzy.googlevideo.com.",
+ "rr4---sn-q4fl6n66.googlevideo.com.",
+ "rr4---sn-q4fl6n6d.googlevideo.com.",
+ "rr4---sn-q4fl6n6d.gvt1.com.",
+ "rr4---sn-q4fl6n6r.googlevideo.com.",
+ "rr4---sn-q4fl6n6r.gvt1.com.",
+ "rr4---sn-q4fl6n6s.googlevideo.com.",
+ "rr4---sn-q4fl6n6s.gvt1.com.",
+ "rr4---sn-q4fl6n6y.googlevideo.com.",
+ "rr4---sn-q4fl6n6y.gvt1.com.",
+ "rr4---sn-q4fl6n6z.googlevideo.com.",
+ "rr4---sn-q4fl6n6z.gvt1.com.",
+ "rr4---sn-q4fl6nd6.googlevideo.com.",
+ "rr4---sn-q4fl6nd6.gvt1.com.",
+ "rr4---sn-q4fl6nd7.googlevideo.com.",
+ "rr4---sn-q4fl6nd7.gvt1.com.",
+ "rr4---sn-q4fl6nde.googlevideo.com.",
+ "rr4---sn-q4fl6nde.gvt1.com.",
+ "rr4---sn-q4fl6ndl.googlevideo.com.",
+ "rr4---sn-q4fl6nds.googlevideo.com.",
+ "rr4---sn-q4fl6nds.gvt1.com.",
+ "rr4---sn-q4fl6ndz.googlevideo.com.",
+ "rr4---sn-q4fl6ndz.gvt1.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-q4fl6nsk.gvt1.com.",
+ "rr4---sn-q4fl6nsl.googlevideo.com.",
+ "rr4---sn-q4fl6nsr.googlevideo.com.",
+ "rr4---sn-q4fl6nsr.gvt1.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-q4flrne6.googlevideo.com.",
+ "rr4---sn-q4flrne7.googlevideo.com.",
+ "rr4---sn-q4flrne7.gvt1.com.",
+ "rr4---sn-q4flrnee.googlevideo.com.",
+ "rr4---sn-q4flrnek.googlevideo.com.",
+ "rr4---sn-q4flrnel.googlevideo.com.",
+ "rr4---sn-q4flrner.googlevideo.com.",
+ "rr4---sn-q4flrner.gvt1.com.",
+ "rr4---sn-q4flrnes.googlevideo.com.",
+ "rr4---sn-q4flrney.googlevideo.com.",
+ "rr4---sn-q4flrney.gvt1.com.",
+ "rr4---sn-q4flrnez.googlevideo.com.",
+ "rr4---sn-q4flrnez.gvt1.com.",
+ "rr4---sn-q4flrnl6.googlevideo.com.",
+ "rr4---sn-q4flrnl6.gvt1.com.",
+ "rr4---sn-q4flrnl7.googlevideo.com.",
+ "rr4---sn-q4flrnl7.gvt1.com.",
+ "rr4---sn-q4flrnld.googlevideo.com.",
+ "rr4---sn-q4flrnle.googlevideo.com.",
+ "rr4---sn-q4flrnle.gvt1.com.",
+ "rr4---sn-q4flrnlz.googlevideo.com.",
+ "rr4---sn-q4flrnlz.gvt1.com.",
+ "rr4---sn-q4flrnsd.googlevideo.com.",
+ "rr4---sn-q4flrnsk.googlevideo.com.",
+ "rr4---sn-q4flrnsk.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-q4fzen7r.googlevideo.com.",
+ "rr4---sn-q4fzen7s.googlevideo.com.",
+ "rr4---sn-q4fzen7y.googlevideo.com.",
+ "rr4---sn-q4fzen7y.gvt1.com.",
+ "rr4---sn-q4fzene7.googlevideo.com.",
+ "rr4---sn-q4fzene7.gvt1.com.",
+ "rr4---sn-q4fzenee.googlevideo.com.",
+ "rr4---sn-q4fzenee.gvt1.com.",
+ "rr4---sn-qxo7rn7k.googlevideo.com.",
+ "rr4---sn-qxo7rn7r.googlevideo.com.",
+ "rr4---sn-qxo7rn7y.googlevideo.com.",
+ "rr4---sn-qxoedn7k.googlevideo.com.",
+ "rr4---sn-qxoedne7.googlevideo.com.",
+ "rr4---sn-t0a7lnee.googlevideo.com.",
+ "rr4---sn-t0a7sn7d.googlevideo.com.",
+ "rr4---sn-u1hp55-5c.googlevideo.com.",
+ "rr4---sn-uhvcpaxoa-5hne.googlevideo.com.",
+ "rr4---sn-uhvcpaxoa-guhe.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-vgqskn6s.gvt1.com.",
+ "rr4---sn-vgqskn6z.googlevideo.com.",
+ "rr4---sn-vgqskn6z.gvt1.com.",
+ "rr4---sn-vgqskne6.googlevideo.com.",
+ "rr4---sn-vgqsknek.googlevideo.com.",
+ "rr4---sn-vgqsknek.gvt1.com.",
+ "rr4---sn-vgqsknes.googlevideo.com.",
+ "rr4---sn-vgqsknez.googlevideo.com.",
+ "rr4---sn-vgqsknld.googlevideo.com.",
+ "rr4---sn-vgqsknld.gvt1.com.",
+ "rr4---sn-vgqsknll.googlevideo.com.",
+ "rr4---sn-vgqsknlr.googlevideo.com.",
+ "rr4---sn-vgqsknlr.gvt1.com.",
+ "rr4---sn-vgqsknls.googlevideo.com.",
+ "rr4---sn-vgqsknly.googlevideo.com.",
+ "rr4---sn-vgqsknlz.googlevideo.com.",
+ "rr4---sn-vgqskns7.googlevideo.com.",
+ "rr4---sn-vgqskns7.gvt1.com.",
+ "rr4---sn-vgqsknse.googlevideo.com.",
+ "rr4---sn-vgqsknsk.googlevideo.com.",
+ "rr4---sn-vgqsknz6.googlevideo.com.",
+ "rr4---sn-vgqsknz6.gvt1.com.",
+ "rr4---sn-vgqsknz7.googlevideo.com.",
+ "rr4---sn-vgqsknz7.gvt1.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-vgqsrn6l.gvt1.com.",
+ "rr4---sn-vgqsrn6z.googlevideo.com.",
+ "rr4---sn-vgqsrn6z.gvt1.com.",
+ "rr4---sn-vgqsrne6.googlevideo.com.",
+ "rr4---sn-vgqsrned.googlevideo.com.",
+ "rr4---sn-vgqsrnek.googlevideo.com.",
+ "rr4---sn-vgqsrnes.googlevideo.com.",
+ "rr4---sn-vgqsrnez.googlevideo.com.",
+ "rr4---sn-vgqsrnl6.googlevideo.com.",
+ "rr4---sn-vgqsrnld.googlevideo.com.",
+ "rr4---sn-vgqsrnlk.googlevideo.com.",
+ "rr4---sn-vgqsrnll.googlevideo.com.",
+ "rr4---sn-vgqsrnls.googlevideo.com.",
+ "rr4---sn-vgqsrnls.gvt1.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-vgqsrnz7.gvt1.com.",
+ "rr4---sn-vgqsrnzd.googlevideo.com.",
+ "rr4---sn-vgqsrnzk.googlevideo.com.",
+ "rr4---sn-vgqsrnzk.gvt1.com.",
+ "rr4---sn-vgqsrnzr.googlevideo.com.",
+ "rr4---sn-vgqsrnzs.googlevideo.com.",
+ "rr4---sn-vgqsrnzy.googlevideo.com.",
+ "rr4---sn-vgqsrnzz.googlevideo.com.",
+ "rr4.sn-5hne6nsd.googlevideo.com.",
+ "rr4.sn-5hne6nzk.googlevideo.com.",
+ "rr4.sn-5hnednsz.googlevideo.com.",
+ "rr4.sn-5hneknee.googlevideo.com.",
+ "rr4.sn-a5mekndz.googlevideo.com.",
+ "rr4.sn-q4fl6n6d.googlevideo.com.",
+ "rr4.sn-q4flrnek.googlevideo.com.",
+ "rr4.sn-q4flrnle.googlevideo.com.",
+ "rr4.sn-q4flrnsl.googlevideo.com.",
+ "rr4.sn-q4fzen7r.googlevideo.com.",
+ "rr5---sn-0nnpbo5a-bggl.googlevideo.com.",
+ "rr5---sn-2imern76.googlevideo.com.",
+ "rr5---sn-2imern76.gvt1.com.",
+ "rr5---sn-2imern7d.googlevideo.com.",
+ "rr5---sn-2imern7d.gvt1.com.",
+ "rr5---sn-2oaig5-55.googlevideo.com.",
+ "rr5---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr5---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
+ "rr5---sn-30a7rne6.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-30a7ynl7.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.",
+ "rr5---sn-4g5e6nz7.googlevideo.com.",
+ "rr5---sn-4g5e6nze.googlevideo.com.",
+ "rr5---sn-4g5e6nzl.googlevideo.com.",
+ "rr5---sn-4g5e6nzs.googlevideo.com.",
+ "rr5---sn-4g5e6nzz.googlevideo.com.",
+ "rr5---sn-4g5edn6k.googlevideo.com.",
+ "rr5---sn-4g5edn6r.googlevideo.com.",
+ "rr5---sn-4g5edn6y.googlevideo.com.",
+ "rr5---sn-4g5ednd7.googlevideo.com.",
+ "rr5---sn-4g5edndd.googlevideo.com.",
+ "rr5---sn-4g5ednde.googlevideo.com.",
+ "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.",
+ "rr5---sn-4g5ednld.googlevideo.com.",
+ "rr5---sn-4g5ednly.googlevideo.com.",
+ "rr5---sn-4g5edns6.googlevideo.com.",
+ "rr5---sn-4g5edns7.googlevideo.com.",
+ "rr5---sn-4g5ednsd.googlevideo.com.",
+ "rr5---sn-4g5ednse.googlevideo.com.",
+ "rr5---sn-4g5ednsk.googlevideo.com.",
+ "rr5---sn-4g5ednsl.googlevideo.com.",
+ "rr5---sn-4g5ednsr.googlevideo.com.",
+ "rr5---sn-4g5ednss.googlevideo.com.",
+ "rr5---sn-4g5ednsz.googlevideo.com.",
+ "rr5---sn-4g5ednz7.googlevideo.com.",
+ "rr5---sn-4g5lzne6.googlevideo.com.",
+ "rr5---sn-4g5lzned.googlevideo.com.",
+ "rr5---sn-4g5lznek.googlevideo.com.",
+ "rr5---sn-4g5lzner.googlevideo.com.",
+ "rr5---sn-4g5lznes.googlevideo.com.",
+ "rr5---sn-4g5lzney.googlevideo.com.",
+ "rr5---sn-4g5lznez.googlevideo.com.",
+ "rr5---sn-4g5lznl6.googlevideo.com.",
+ "rr5---sn-4g5lznl7.googlevideo.com.",
+ "rr5---sn-4g5lznle.googlevideo.com.",
+ "rr5---sn-4g5lznls.googlevideo.com.",
+ "rr5---sn-4g5lznlz.googlevideo.com.",
+ "rr5---sn-5hne6n6e.googlevideo.com.",
+ "rr5---sn-5hne6n6e.gvt1.com.",
+ "rr5---sn-5hne6n6l.googlevideo.com.",
+ "rr5---sn-5hne6ns6.googlevideo.com.",
+ "rr5---sn-5hne6nsd.googlevideo.com.",
+ "rr5---sn-5hne6nsk.googlevideo.com.",
+ "rr5---sn-5hne6nsr.googlevideo.com.",
+ "rr5---sn-5hne6nsy.googlevideo.com.",
+ "rr5---sn-5hne6nsz.googlevideo.com.",
+ "rr5---sn-5hne6nz6.googlevideo.com.",
+ "rr5---sn-5hne6nzd.googlevideo.com.",
+ "rr5---sn-5hne6nzk.googlevideo.com.",
+ "rr5---sn-5hne6nzs.googlevideo.com.",
+ "rr5---sn-5hne6nzy.googlevideo.com.",
+ "rr5---sn-5hnednss.googlevideo.com.",
+ "rr5---sn-5hnednsz.googlevideo.com.",
+ "rr5---sn-5hnekn7d.googlevideo.com.",
+ "rr5---sn-5hnekn7k.googlevideo.com.",
+ "rr5---sn-5hnekn7l.googlevideo.com.",
+ "rr5---sn-5hnekn7s.googlevideo.com.",
+ "rr5---sn-5hnekn7z.googlevideo.com.",
+ "rr5---sn-5hneknee.googlevideo.com.",
+ "rr5---sn-5hneknek.googlevideo.com.",
+ "rr5---sn-5hneknes.googlevideo.com.",
+ "rr5---sn-5pgnugx5h-hn2z.googlevideo.com.",
+ "rr5---sn-5uaezndd.googlevideo.com.",
+ "rr5---sn-5uaezne6.googlevideo.com.",
+ "rr5---sn-5uaezned.googlevideo.com.",
+ "rr5---sn-5uaeznes.googlevideo.com.",
+ "rr5---sn-5uaeznez.googlevideo.com.",
+ "rr5---sn-5uaeznl6.googlevideo.com.",
+ "rr5---sn-5uaeznld.googlevideo.com.",
+ "rr5---sn-5uaeznly.googlevideo.com.",
+ "rr5---sn-5uaeznlz.googlevideo.com.",
+ "rr5---sn-5uaeznrz.googlevideo.com.",
+ "rr5---sn-5uaezns7.googlevideo.com.",
+ "rr5---sn-5uaeznse.googlevideo.com.",
+ "rr5---sn-5uaeznsl.googlevideo.com.",
+ "rr5---sn-5uaeznss.googlevideo.com.",
+ "rr5---sn-5uaezny6.googlevideo.com.",
+ "rr5---sn-5uaeznys.googlevideo.com.",
+ "rr5---sn-5uaeznze.googlevideo.com.",
+ "rr5---sn-5ualdnle.googlevideo.com.",
+ "rr5---sn-5ualdnll.googlevideo.com.",
+ "rr5---sn-5ualdnlr.googlevideo.com.",
+ "rr5---sn-5ualdnls.googlevideo.com.",
+ "rr5---sn-5ualdns6.googlevideo.com.",
+ "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.",
+ "rr5---sn-5ualdnsy.googlevideo.com.",
+ "rr5---sn-5ualdnsz.googlevideo.com.",
+ "rr5---sn-5ualdnz7.googlevideo.com.",
+ "rr5---sn-5ualdnze.googlevideo.com.",
+ "rr5---sn-8qj-i5ody.googlevideo.com.",
+ "rr5---sn-8qj-nbo66.googlevideo.com.",
+ "rr5---sn-8xgp1vo-2iae.googlevideo.com.",
+ "rr5---sn-8xgp1vo-2iae7.googlevideo.com.",
+ "rr5---sn-8xgp1vo-2ial.googlevideo.com.",
+ "rr5---sn-8xgp1vo-2iay.googlevideo.com.",
+ "rr5---sn-8xgp1vo-a5me.googlevideo.com.",
+ "rr5---sn-8xgp1vo-ab56.googlevideo.com.",
+ "rr5---sn-8xgp1vo-ab5d.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-p5ie.googlevideo.com.",
+ "rr5---sn-8xgp1vo-vgqe.googlevideo.com.",
+ "rr5---sn-8xgp1vo-xfge.googlevideo.com.",
+ "rr5---sn-8xgp1vo-xfgl.googlevideo.com.",
+ "rr5---sn-9gv76n7e.googlevideo.com.",
+ "rr5---sn-9gv76n7l.googlevideo.com.",
+ "rr5---sn-9gv76n7s.googlevideo.com.",
+ "rr5---sn-9gv7ene6.googlevideo.com.",
+ "rr5---sn-9gv7ened.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.",
+ "rr5---sn-a5mekn6d.googlevideo.com.",
+ "rr5---sn-a5mekn6d.gvt1.com.",
+ "rr5---sn-a5mekn6k.googlevideo.com.",
+ "rr5---sn-a5mekn6k.gvt1.com.",
+ "rr5---sn-a5mekn6l.googlevideo.com.",
+ "rr5---sn-a5mekn6l.gvt1.com.",
+ "rr5---sn-a5mekn6r.googlevideo.com.",
+ "rr5---sn-a5mekn6r.gvt1.com.",
+ "rr5---sn-a5mekn6s.googlevideo.com.",
+ "rr5---sn-a5mekn6z.googlevideo.com.",
+ "rr5---sn-a5meknd6.googlevideo.com.",
+ "rr5---sn-a5meknd6.gvt1.com.",
+ "rr5---sn-a5meknde.googlevideo.com.",
+ "rr5---sn-a5mekndl.googlevideo.com.",
+ "rr5---sn-a5meknds.googlevideo.com.",
+ "rr5---sn-a5meknds.gvt1.com.",
+ "rr5---sn-a5mekndz.googlevideo.com.",
+ "rr5---sn-a5mekndz.gvt1.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-a5meknzs.googlevideo.com.",
+ "rr5---sn-a5mlrnek.googlevideo.com.",
+ "rr5---sn-a5mlrnek.gvt1.com.",
+ "rr5---sn-a5mlrnl6.googlevideo.com.",
+ "rr5---sn-a5mlrnll.googlevideo.com.",
+ "rr5---sn-a5mlrnll.gvt1.com.",
+ "rr5---sn-a5mlrnls.googlevideo.com.",
+ "rr5---sn-a5mlrnlz.googlevideo.com.",
+ "rr5---sn-a5mlrnlz.gvt1.com.",
+ "rr5---sn-a5msen76.googlevideo.com.",
+ "rr5---sn-a5msen7l.googlevideo.com.",
+ "rr5---sn-a5msen7s.googlevideo.com.",
+ "rr5---sn-a5msenek.googlevideo.com.",
+ "rr5---sn-a5msener.googlevideo.com.",
+ "rr5---sn-a5msener.gvt1.com.",
+ "rr5---sn-a5msenes.googlevideo.com.",
+ "rr5---sn-a5msenes.gvt1.com.",
+ "rr5---sn-a5msenl7.googlevideo.com.",
+ "rr5---sn-a5msenle.googlevideo.com.",
+ "rr5---sn-a5msenle.gvt1.com.",
+ "rr5---sn-a5msenll.googlevideo.com.",
+ "rr5---sn-ab5l6ndr.googlevideo.com.",
+ "rr5---sn-ab5l6ndy.googlevideo.com.",
+ "rr5---sn-ab5l6nk6.googlevideo.com.",
+ "rr5---sn-ab5l6nkd.googlevideo.com.",
+ "rr5---sn-ab5l6nr6.googlevideo.com.",
+ "rr5---sn-ab5l6nr6.gvt1.com.",
+ "rr5---sn-ab5l6nrd.googlevideo.com.",
+ "rr5---sn-ab5l6nrd.gvt1.com.",
+ "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-ab5l6nrz.gvt1.com.",
+ "rr5---sn-ab5sznld.googlevideo.com.",
+ "rr5---sn-ab5sznlk.googlevideo.com.",
+ "rr5---sn-ab5sznlk.gvt1.com.",
+ "rr5---sn-ab5sznly.googlevideo.com.",
+ "rr5---sn-ab5sznz6.googlevideo.com.",
+ "rr5---sn-ab5sznz6.gvt1.com.",
+ "rr5---sn-ab5sznzd.googlevideo.com.",
+ "rr5---sn-ab5sznze.googlevideo.com.",
+ "rr5---sn-ab5sznzk.googlevideo.com.",
+ "rr5---sn-ab5sznzl.googlevideo.com.",
+ "rr5---sn-ab5sznzr.googlevideo.com.",
+ "rr5---sn-ab5sznzs.googlevideo.com.",
+ "rr5---sn-ab5sznzs.gvt1.com.",
+ "rr5---sn-ab5sznzy.googlevideo.com.",
+ "rr5---sn-ab5sznzy.gvt1.com.",
+ "rr5---sn-ab5sznzz.googlevideo.com.",
+ "rr5---sn-aigl6n6s.googlevideo.com.",
+ "rr5---sn-aigl6ned.googlevideo.com.",
+ "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-aigl6nsk.gvt1.com.",
+ "rr5---sn-aigl6nsr.googlevideo.com.",
+ "rr5---sn-aigl6nz7.googlevideo.com.",
+ "rr5---sn-aigl6nze.googlevideo.com.",
+ "rr5---sn-aigl6nzk.googlevideo.com.",
+ "rr5---sn-aigl6nzk.gvt1.com.",
+ "rr5---sn-aigl6nzl.googlevideo.com.",
+ "rr5---sn-aigl6nzr.googlevideo.com.",
+ "rr5---sn-aigl6nzs.googlevideo.com.",
+ "rr5---sn-aigl6nzs.gvt1.com.",
+ "rr5---sn-aigzrn76.googlevideo.com.",
+ "rr5---sn-aigzrn7d.googlevideo.com.",
+ "rr5---sn-aigzrn7e.googlevideo.com.",
+ "rr5---sn-aigzrn7k.googlevideo.com.",
+ "rr5---sn-aigzrn7l.googlevideo.com.",
+ "rr5---sn-aigzrn7s.googlevideo.com.",
+ "rr5---sn-aigzrn7z.googlevideo.com.",
+ "rr5---sn-aigzrnld.googlevideo.com.",
+ "rr5---sn-aigzrnse.googlevideo.com.",
+ "rr5---sn-aigzrnsl.googlevideo.com.",
+ "rr5---sn-aigzrnsr.googlevideo.com.",
+ "rr5---sn-aigzrnss.googlevideo.com.",
+ "rr5---sn-aigzrnsz.googlevideo.com.",
+ "rr5---sn-aigzrnz7.googlevideo.com.",
+ "rr5---sn-aigzrnze.googlevideo.com.",
+ "rr5---sn-aj5ua5-5c.googlevideo.com.",
+ "rr5---sn-apn7en7l.googlevideo.com.",
+ "rr5---sn-apn7en7s.googlevideo.com.",
+ "rr5---sn-cvb7lne7.googlevideo.com.",
+ "rr5---sn-cvb7lnl7.googlevideo.com.",
+ "rr5---sn-cvb7lnls.googlevideo.com.",
+ "rr5---sn-cvb7lnlz.googlevideo.com.",
+ "rr5---sn-cvb7sn7k.googlevideo.com.",
+ "rr5---sn-cvb7sn7r.googlevideo.com.",
+ "rr5---sn-h0jeened.googlevideo.com.",
+ "rr5---sn-h0jeenek.googlevideo.com.",
+ "rr5---sn-h0jeenl6.googlevideo.com.",
+ "rr5---sn-h0jeenld.googlevideo.com.",
+ "rr5---sn-h0jeenle.googlevideo.com.",
+ "rr5---sn-h0jeln7l.googlevideo.com.",
+ "rr5---sn-h0jelne6.googlevideo.com.",
+ "rr5---sn-h0jelne7.googlevideo.com.",
+ "rr5---sn-h0jelnes.googlevideo.com.",
+ "rr5---sn-h0jelnez.googlevideo.com.",
+ "rr5---sn-hgn7rnls.googlevideo.com.",
+ "rr5---sn-hoa7kn76.googlevideo.com.",
+ "rr5---sn-hoa7kn7z.googlevideo.com.",
+ "rr5---sn-hoa7rn76.googlevideo.com.",
+ "rr5---sn-hoa7rn7z.googlevideo.com.",
+ "rr5---sn-hp57kn6r.googlevideo.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-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-hp57kndz.googlevideo.com.",
+ "rr5---sn-hp57kndz.gvt1.com.",
+ "rr5---sn-hp57yn7r.googlevideo.com.",
+ "rr5---sn-hp57yn7y.googlevideo.com.",
+ "rr5---sn-hp57yne7.googlevideo.com.",
+ "rr5---sn-hp57yne7.gvt1.com.",
+ "rr5---sn-hp57ynee.googlevideo.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-hp57ynss.googlevideo.com.",
+ "rr5---sn-i3b7kn6s.googlevideo.com.",
+ "rr5---sn-i3b7knld.googlevideo.com.",
+ "rr5---sn-i3b7knlk.googlevideo.com.",
+ "rr5---sn-i3b7kns6.googlevideo.com.",
+ "rr5---sn-i3b7knsd.googlevideo.com.",
+ "rr5---sn-i3b7knse.googlevideo.com.",
+ "rr5---sn-i3b7knsl.googlevideo.com.",
+ "rr5---sn-i3b7knzl.googlevideo.com.",
+ "rr5---sn-i3b7knzs.googlevideo.com.",
+ "rr5---sn-i3belne6.googlevideo.com.",
+ "rr5---sn-i3belney.googlevideo.com.",
+ "rr5---sn-i3belnl6.googlevideo.com.",
+ "rr5---sn-i3belnl7.googlevideo.com.",
+ "rr5---sn-i3belnll.googlevideo.com.",
+ "rr5---sn-i3belnls.googlevideo.com.",
+ "rr5---sn-i3belnlz.googlevideo.com.",
+ "rr5---sn-i3bssn7e.googlevideo.com.",
+ "rr5---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr5---sn-jvhj5nu-2iae.googlevideo.com.",
+ "rr5---sn-jvhj5nu-2ias.googlevideo.com.",
+ "rr5---sn-jvhj5nu-nh4e.googlevideo.com.",
+ "rr5---sn-jvhj5nu-nh4s.googlevideo.com.",
+ "rr5---sn-jvhj5nu-nh4z.googlevideo.com.",
+ "rr5---sn-jvhj5nu-qufe.googlevideo.com.",
+ "rr5---sn-jvhj5nu-qufl.googlevideo.com.",
+ "rr5---sn-jvhj5nu-qufs.googlevideo.com.",
+ "rr5---sn-jxopj-n5oe.googlevideo.com.",
+ "rr5---sn-jxopj-n5oe.gvt1.com.",
+ "rr5---sn-jxopj-nh4e.googlevideo.com.",
+ "rr5---sn-jxopj-nh4e.gvt1.com.",
+ "rr5---sn-muxa-2iae.googlevideo.com.",
+ "rr5---sn-n4v7snee.googlevideo.com.",
+ "rr5---sn-n4v7sney.googlevideo.com.",
+ "rr5---sn-n4v7snl7.googlevideo.com.",
+ "rr5---sn-n4v7snll.googlevideo.com.",
+ "rr5---sn-n4v7snlr.googlevideo.com.",
+ "rr5---sn-n4v7snlr.gvt1.com.",
+ "rr5---sn-n4v7snls.googlevideo.com.",
+ "rr5---sn-n4v7snly.googlevideo.com.",
+ "rr5---sn-n4v7sns7.googlevideo.com.",
+ "rr5---sn-n4v7snse.googlevideo.com.",
+ "rr5---sn-npoe7ndl.googlevideo.com.",
+ "rr5---sn-npoe7nds.googlevideo.com.",
+ "rr5---sn-npoe7ne6.googlevideo.com.",
+ "rr5---sn-npoe7ne7.googlevideo.com.",
+ "rr5---sn-npoe7ned.googlevideo.com.",
+ "rr5---sn-npoe7nek.googlevideo.com.",
+ "rr5---sn-npoe7ner.googlevideo.com.",
+ "rr5---sn-npoe7nes.googlevideo.com.",
+ "rr5---sn-npoe7nez.googlevideo.com.",
+ "rr5---sn-npoe7nl6.googlevideo.com.",
+ "rr5---sn-npoe7nlz.googlevideo.com.",
+ "rr5---sn-npoe7ns6.googlevideo.com.",
+ "rr5---sn-npoe7ns7.googlevideo.com.",
+ "rr5---sn-npoe7nsd.googlevideo.com.",
+ "rr5---sn-npoe7nsk.googlevideo.com.",
+ "rr5---sn-npoe7nsl.googlevideo.com.",
+ "rr5---sn-npoe7nss.googlevideo.com.",
+ "rr5---sn-npoe7nsy.googlevideo.com.",
+ "rr5---sn-npoe7nz7.googlevideo.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-npoeenll.googlevideo.com.",
+ "rr5---sn-npoeenly.googlevideo.com.",
+ "rr5---sn-npoeens7.googlevideo.com.",
+ "rr5---sn-npoldn76.googlevideo.com.",
+ "rr5---sn-npoldn7d.googlevideo.com.",
+ "rr5---sn-npoldn7e.googlevideo.com.",
+ "rr5---sn-npoldn7l.googlevideo.com.",
+ "rr5---sn-npoldn7s.googlevideo.com.",
+ "rr5---sn-npoldn7y.googlevideo.com.",
+ "rr5---sn-npoldn7z.googlevideo.com.",
+ "rr5---sn-npoldne7.googlevideo.com.",
+ "rr5---sn-nv0ui4gvou-hape.googlevideo.com.",
+ "rr5---sn-nx57ynlk.googlevideo.com.",
+ "rr5---sn-nx57ynlk.gvt1.com.",
+ "rr5---sn-nx57ynse.googlevideo.com.",
+ "rr5---sn-nx57ynse.gvt1.com.",
+ "rr5---sn-nx57ynsk.googlevideo.com.",
+ "rr5---sn-nx57ynsk.gvt1.com.",
+ "rr5---sn-nx57ynsl.googlevideo.com.",
+ "rr5---sn-nx57ynsl.gvt1.com.",
+ "rr5---sn-nx57ynss.googlevideo.com.",
+ "rr5---sn-nx57ynss.gvt1.com.",
+ "rr5---sn-nx57ynsz.googlevideo.com.",
+ "rr5---sn-nx57ynsz.gvt1.com.",
+ "rr5---sn-nx5s7n76.googlevideo.com.",
+ "rr5---sn-nx5s7n7d.googlevideo.com.",
+ "rr5---sn-nx5s7n7s.googlevideo.com.",
+ "rr5---sn-nx5s7n7z.googlevideo.com.",
+ "rr5---sn-nx5s7n7z.gvt1.com.",
+ "rr5---sn-nx5s7nee.googlevideo.com.",
+ "rr5---sn-nx5s7nel.googlevideo.com.",
+ "rr5---sn-nx5s7nel.gvt1.com.",
+ "rr5---sn-o097znsd.googlevideo.com.",
+ "rr5---sn-o097znse.googlevideo.com.",
+ "rr5---sn-o097znsk.googlevideo.com.",
+ "rr5---sn-o097znsl.googlevideo.com.",
+ "rr5---sn-o097znsr.googlevideo.com.",
+ "rr5---sn-o097znss.googlevideo.com.",
+ "rr5---sn-o097znsz.googlevideo.com.",
+ "rr5---sn-o097znz7.googlevideo.com.",
+ "rr5---sn-o097znzd.googlevideo.com.",
+ "rr5---sn-o097znze.googlevideo.com.",
+ "rr5---sn-o097znzk.googlevideo.com.",
+ "rr5---sn-o097znzr.googlevideo.com.",
+ "rr5---sn-o097znzr.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-p5qlsn7d.googlevideo.com.",
+ "rr5---sn-p5qlsn7l.googlevideo.com.",
+ "rr5---sn-p5qlsn7s.googlevideo.com.",
+ "rr5---sn-p5qlsnd6.googlevideo.com.",
+ "rr5---sn-p5qlsndd.googlevideo.com.",
+ "rr5---sn-p5qlsndk.googlevideo.com.",
+ "rr5---sn-p5qlsndz.googlevideo.com.",
+ "rr5---sn-p5qlsnrl.googlevideo.com.",
+ "rr5---sn-p5qlsny6.googlevideo.com.",
+ "rr5---sn-p5qs7n6d.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-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-q4fl6nd6.googlevideo.com.",
+ "rr5---sn-q4fl6nd7.googlevideo.com.",
+ "rr5---sn-q4fl6nd7.gvt1.com.",
+ "rr5---sn-q4fl6nde.googlevideo.com.",
+ "rr5---sn-q4fl6ndl.googlevideo.com.",
+ "rr5---sn-q4fl6ndl.gvt1.com.",
+ "rr5---sn-q4fl6nds.googlevideo.com.",
+ "rr5---sn-q4fl6ndz.googlevideo.com.",
+ "rr5---sn-q4fl6ndz.gvt1.com.",
+ "rr5---sn-q4fl6nlz.googlevideo.com.",
+ "rr5---sn-q4fl6nlz.gvt1.com.",
+ "rr5---sn-q4fl6ns6.googlevideo.com.",
+ "rr5---sn-q4fl6ns6.gvt1.com.",
+ "rr5---sn-q4fl6ns7.googlevideo.com.",
+ "rr5---sn-q4fl6nsd.googlevideo.com.",
+ "rr5---sn-q4fl6nsk.googlevideo.com.",
+ "rr5---sn-q4fl6nsk.gvt1.com.",
+ "rr5---sn-q4fl6nsl.googlevideo.com.",
+ "rr5---sn-q4fl6nsl.gvt1.com.",
+ "rr5---sn-q4fl6nsr.googlevideo.com.",
+ "rr5---sn-q4fl6nsr.gvt1.com.",
+ "rr5---sn-q4fl6nss.googlevideo.com.",
+ "rr5---sn-q4fl6nsy.googlevideo.com.",
+ "rr5---sn-q4fl6nsy.gvt1.com.",
+ "rr5---sn-q4fl6nz6.googlevideo.com.",
+ "rr5---sn-q4fl6nz6.gvt1.com.",
+ "rr5---sn-q4fl6nz7.googlevideo.com.",
+ "rr5---sn-q4fl6nzy.googlevideo.com.",
+ "rr5---sn-q4flrn7k.googlevideo.com.",
+ "rr5---sn-q4flrn7r.googlevideo.com.",
+ "rr5---sn-q4flrn7r.gvt1.com.",
+ "rr5---sn-q4flrn7y.googlevideo.com.",
+ "rr5---sn-q4flrne6.googlevideo.com.",
+ "rr5---sn-q4flrne7.googlevideo.com.",
+ "rr5---sn-q4flrnee.googlevideo.com.",
+ "rr5---sn-q4flrnee.gvt1.com.",
+ "rr5---sn-q4flrnek.googlevideo.com.",
+ "rr5---sn-q4flrnel.googlevideo.com.",
+ "rr5---sn-q4flrnel.gvt1.com.",
+ "rr5---sn-q4flrner.googlevideo.com.",
+ "rr5---sn-q4flrner.gvt1.com.",
+ "rr5---sn-q4flrnes.googlevideo.com.",
+ "rr5---sn-q4flrnes.gvt1.com.",
+ "rr5---sn-q4flrney.googlevideo.com.",
+ "rr5---sn-q4flrnez.googlevideo.com.",
+ "rr5---sn-q4flrnez.gvt1.com.",
+ "rr5---sn-q4flrnl6.googlevideo.com.",
+ "rr5---sn-q4flrnl7.googlevideo.com.",
+ "rr5---sn-q4flrnld.googlevideo.com.",
+ "rr5---sn-q4flrnle.googlevideo.com.",
+ "rr5---sn-q4flrnlz.googlevideo.com.",
+ "rr5---sn-q4flrnlz.gvt1.com.",
+ "rr5---sn-q4flrnsd.googlevideo.com.",
+ "rr5---sn-q4flrnsk.googlevideo.com.",
+ "rr5---sn-q4flrnsk.gvt1.com.",
+ "rr5---sn-q4flrnsl.googlevideo.com.",
+ "rr5---sn-q4flrnsl.gvt1.com.",
+ "rr5---sn-q4flrnss.googlevideo.com.",
+ "rr5---sn-q4flrnss.gvt1.com.",
+ "rr5---sn-q4fzen7e.googlevideo.com.",
+ "rr5---sn-q4fzen7e.gvt1.com.",
+ "rr5---sn-q4fzen7l.googlevideo.com.",
+ "rr5---sn-q4fzen7l.gvt1.com.",
+ "rr5---sn-q4fzen7r.googlevideo.com.",
+ "rr5---sn-q4fzen7r.gvt1.com.",
+ "rr5---sn-q4fzen7s.googlevideo.com.",
+ "rr5---sn-q4fzen7y.googlevideo.com.",
+ "rr5---sn-q4fzene7.googlevideo.com.",
+ "rr5---sn-q4fzenee.googlevideo.com.",
+ "rr5---sn-qxo7rn7k.googlevideo.com.",
+ "rr5---sn-qxo7rn7r.googlevideo.com.",
+ "rr5---sn-qxo7rn7y.googlevideo.com.",
+ "rr5---sn-qxoedn7k.googlevideo.com.",
+ "rr5---sn-qxoedne7.googlevideo.com.",
+ "rr5---sn-qxoednee.googlevideo.com.",
+ "rr5---sn-u1hp55-5c.googlevideo.com.",
+ "rr5---sn-vgqskn66.googlevideo.com.",
+ "rr5---sn-vgqskn67.googlevideo.com.",
+ "rr5---sn-vgqskn67.gvt1.com.",
+ "rr5---sn-vgqskn6d.googlevideo.com.",
+ "rr5---sn-vgqskn6s.googlevideo.com.",
+ "rr5---sn-vgqskn6s.gvt1.com.",
+ "rr5---sn-vgqskn6z.googlevideo.com.",
+ "rr5---sn-vgqskne6.googlevideo.com.",
+ "rr5---sn-vgqskned.googlevideo.com.",
+ "rr5---sn-vgqsknek.googlevideo.com.",
+ "rr5---sn-vgqsknek.gvt1.com.",
+ "rr5---sn-vgqsknes.googlevideo.com.",
+ "rr5---sn-vgqsknez.googlevideo.com.",
+ "rr5---sn-vgqsknez.gvt1.com.",
+ "rr5---sn-vgqsknll.googlevideo.com.",
+ "rr5---sn-vgqsknlr.googlevideo.com.",
+ "rr5---sn-vgqsknls.googlevideo.com.",
+ "rr5---sn-vgqsknly.googlevideo.com.",
+ "rr5---sn-vgqsknlz.googlevideo.com.",
+ "rr5---sn-vgqskns7.googlevideo.com.",
+ "rr5---sn-vgqskns7.gvt1.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-vgqsknze.googlevideo.com.",
+ "rr5---sn-vgqsknzk.googlevideo.com.",
+ "rr5---sn-vgqsknzk.gvt1.com.",
+ "rr5---sn-vgqsknzl.googlevideo.com.",
+ "rr5---sn-vgqsknzr.googlevideo.com.",
+ "rr5---sn-vgqsknzr.gvt1.com.",
+ "rr5---sn-vgqsknzs.googlevideo.com.",
+ "rr5---sn-vgqsknzy.googlevideo.com.",
+ "rr5---sn-vgqsknzz.googlevideo.com.",
+ "rr5---sn-vgqsrn66.googlevideo.com.",
+ "rr5---sn-vgqsrn66.gvt1.com.",
+ "rr5---sn-vgqsrn67.googlevideo.com.",
+ "rr5---sn-vgqsrn6e.googlevideo.com.",
+ "rr5---sn-vgqsrn6l.googlevideo.com.",
+ "rr5---sn-vgqsrn6l.gvt1.com.",
+ "rr5---sn-vgqsrn6z.googlevideo.com.",
+ "rr5---sn-vgqsrne6.googlevideo.com.",
+ "rr5---sn-vgqsrne6.gvt1.com.",
+ "rr5---sn-vgqsrned.googlevideo.com.",
+ "rr5---sn-vgqsrnek.googlevideo.com.",
+ "rr5---sn-vgqsrnes.googlevideo.com.",
+ "rr5---sn-vgqsrnez.googlevideo.com.",
+ "rr5---sn-vgqsrnl6.googlevideo.com.",
+ "rr5---sn-vgqsrnld.googlevideo.com.",
+ "rr5---sn-vgqsrnlk.googlevideo.com.",
+ "rr5---sn-vgqsrnll.googlevideo.com.",
+ "rr5---sn-vgqsrnls.googlevideo.com.",
+ "rr5---sn-vgqsrnls.gvt1.com.",
+ "rr5---sn-vgqsrnlz.googlevideo.com.",
+ "rr5---sn-vgqsrns6.googlevideo.com.",
+ "rr5---sn-vgqsrnsd.googlevideo.com.",
+ "rr5---sn-vgqsrnsr.googlevideo.com.",
+ "rr5---sn-vgqsrnsy.googlevideo.com.",
+ "rr5---sn-vgqsrnz6.googlevideo.com.",
+ "rr5---sn-vgqsrnz6.gvt1.com.",
+ "rr5---sn-vgqsrnz7.googlevideo.com.",
+ "rr5---sn-vgqsrnzd.googlevideo.com.",
+ "rr5---sn-vgqsrnzk.googlevideo.com.",
+ "rr5---sn-vgqsrnzk.gvt1.com.",
+ "rr5---sn-vgqsrnzr.googlevideo.com.",
+ "rr5---sn-vgqsrnzs.googlevideo.com.",
+ "rr5---sn-vgqsrnzs.gvt1.com.",
+ "rr5---sn-vgqsrnzy.googlevideo.com.",
+ "rr5---sn-vgqsrnzz.googlevideo.com.",
+ "rr5.sn-a5meknzr.googlevideo.com.",
+ "rr5.sn-q4fl6nd6.googlevideo.com.",
+ "rr5.sn-q4fl6nde.googlevideo.com.",
+ "rr5.sn-q4flrnle.googlevideo.com.",
+ "rr6---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr6---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
+ "rr6---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
+ "rr6---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
+ "rr6---sn-5pgnugx5h-hn2z.googlevideo.com.",
+ "rr6---sn-8qj-i5ody.googlevideo.com.",
+ "rr6---sn-8qj-nbo66.googlevideo.com.",
+ "rr6---sn-8xgp1vo-2iae.googlevideo.com.",
+ "rr6---sn-8xgp1vo-2iae7.googlevideo.com.",
+ "rr6---sn-8xgp1vo-2ial.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-ab5s.googlevideo.com.",
+ "rr6---sn-8xgp1vo-ab5z.googlevideo.com.",
+ "rr6---sn-8xgp1vo-p5ie.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-bvvbax-2ial.googlevideo.com.",
+ "rr6---sn-i5f5ppuxa-ioal.googlevideo.com.",
+ "rr6---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
+ "rr6---sn-jvhj5nu-2iae.googlevideo.com.",
+ "rr6---sn-jvhj5nu-2ial.googlevideo.com.",
+ "rr6---sn-jvhj5nu-2ias.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-jvhj5nu-qufe.googlevideo.com.",
+ "rr6---sn-jvhj5nu-qufl.googlevideo.com.",
+ "rr6---sn-jvhj5nu-qufs.googlevideo.com.",
+ "rr6---sn-jvhj5nu-qufz.googlevideo.com.",
+ "rr6---sn-jxopj-n5oe.googlevideo.com.",
+ "rr6---sn-jxopj-n5oe.gvt1.com.",
+ "rr6---sn-jxopj-nh4e.googlevideo.com.",
+ "rr6---sn-jxopj-nh4e.gvt1.com.",
+ "rr6---sn-nv0ui4gvou-hape.googlevideo.com.",
+ "rr7---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr7---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
+ "rr7---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
+ "rr7---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
+ "rr7---sn-8qj-nbo66.googlevideo.com.",
+ "rr7---sn-8xgp1vo-2iae.googlevideo.com.",
+ "rr7---sn-8xgp1vo-2ial.googlevideo.com.",
+ "rr7---sn-8xgp1vo-a5me.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-ab5s.googlevideo.com.",
+ "rr7---sn-8xgp1vo-ab5z.googlevideo.com.",
+ "rr7---sn-8xgp1vo-vgqe.googlevideo.com.",
+ "rr7---sn-8xgp1vo-xfge.googlevideo.com.",
+ "rr7---sn-bvvbax-2ial.googlevideo.com.",
+ "rr7---sn-jvhj5nu-nh4e.googlevideo.com.",
+ "rr7---sn-jvhj5nu-nh4l.googlevideo.com.",
+ "rr7---sn-jvhj5nu-nh4z.googlevideo.com.",
+ "rr7---sn-jvhj5nu-qufl.googlevideo.com.",
+ "rr7---sn-jvhj5nu-qufs.googlevideo.com.",
+ "rr7---sn-jvhj5nu-qufz.googlevideo.com.",
+ "rr7---sn-jxopj-n5oe.googlevideo.com.",
+ "rr7---sn-jxopj-n5oe.gvt1.com.",
+ "rr8---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr8---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
+ "rr8---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
+ "rr8---sn-8xgp1vo-2iae.googlevideo.com.",
+ "rr8---sn-8xgp1vo-2ial.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-ab5z.googlevideo.com.",
+ "rr8---sn-8xgp1vo-p5ie.googlevideo.com.",
+ "rr8---sn-8xgp1vo-vgqe.googlevideo.com.",
+ "rr8---sn-8xgp1vo-xfge.googlevideo.com.",
+ "rr8---sn-8xgp1vo-xfgl.googlevideo.com.",
+ "rr8---sn-bvvbax-2ial.googlevideo.com.",
+ "rs-stripe.alm.com.",
+ "rs1.qq.com.",
+ "rs2.qq.com.",
+ "rsx.afterpay.com.",
+ "rt.teramind.co.",
+ "rtb-apac.rtbserve.io.",
+ "rtb-eu.rtbserve.io.",
+ "rtb-useast.creativedot.net.",
+ "rtb-useast.openrtb.in.",
+ "rtb-useast.rtbserve.io.",
+ "rtb-uswest.rtbserve.io.",
+ "rtb2-eu.xaprio.net.",
+ "rtb2-useast.xaprio.net.",
+ "rtb2-uswest.xaprio.net.",
+ "rtbasia.com.",
+ "rtbbpowaq.com.",
+ "rtbsuperhub.com.",
+ "rtbsystem.com.",
+ "rtbwave.com.",
+ "rttf.citrix.com.",
+ "ru1.chat.si.riotgames.com.",
+ "ruijienetworks.com.",
+ "rum.smartrecruiters.com.",
+ "rum22.perf.linkedin.com.",
+ "rumble.com.",
+ "rumt-sg.com.",
+ "rutgersconnect-my.sharepoint.com.",
+ "rxsafeway-my.sharepoint.com.",
+ "rxsafeway.sharepoint.com.",
+ "s-cdn.anthropic.com.",
+ "s-cs.send.microad.jp.",
+ "s-light.tiket.photos.",
+ "s-pinimg-com-cdn-cloudflare-net.pinimg.com.",
+ "s-rtb-pb.send.microad.jp.",
+ "s.deepl.com.",
+ "s.exitbee.com.",
+ "s.optifine.net.",
+ "s.q.easebar.com.",
+ "s.seedtag.com.",
+ "s1.thcdn.com.",
+ "s3.us-east-005.backblazeb2.com.",
+ "sa1.chat.si.riotgames.com.",
+ "sa2.chat.si.riotgames.com.",
+ "sa3.chat.si.riotgames.com.",
+ "saas.sensorsdata.com.",
+ "sabre-sync.quantummetric.com.",
+ "safebrowsing.fdown.net.",
+ "saintasaph.remotepc.com.",
+ "salesbridge-my.sharepoint.com.",
+ "saltlakecity.remotepc.com.",
+ "samsclub.quantummetric.com.",
+ "sanantonio.remotepc.com.",
+ "sanctionssearch.ofac.treas.gov.",
+ "sandbox.wdesk.com.",
+ "sandboxclient.retinavue.net.",
+ "sandboxregister.retinavue.net.",
+ "sandiego.remotepc.com.",
+ "sandiegodc.remotepc.com.",
+ "sanguan.online.",
+ "sanjagh.com.",
+ "sanjose.remotepc.com.",
+ "santandernet-my.sharepoint.com.",
+ "santandernet.sharepoint.com.",
+ "santiago.remotepc.com.",
+ "sanxia.studyquicks.com.",
+ "saopaulo.remotepc.com.",
+ "saopaulo1.remotepc.com.",
+ "saskpower-my.sharepoint.com.",
+ "saspeed.igamecj.com.",
+ "sat02pap001.storage.live.com.",
+ "sat02pap001files.storage.live.com.",
+ "sat02pap002.storage.live.com.",
+ "sat02pap002files.storage.live.com.",
+ "sat02pap003.storage.live.com.",
+ "sat02pap003files.storage.live.com.",
+ "sat02pap004.storage.live.com.",
+ "sat02pap004files.storage.live.com.",
+ "sat02pap005.storage.live.com.",
+ "sat02pap005files.storage.live.com.",
+ "satismeter.com.",
+ "sazerac-my.sharepoint.com.",
+ "sc.zoom.us.",
+ "scasurgery-my.sharepoint.com.",
+ "scdss-my.sharepoint.com.",
+ "schneidercorp.com.",
+ "science.blitz.gg.",
+ "sciener.cn.",
+ "scm.capside.com.",
+ "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-ber1-1.cdninstagram.com.",
+ "scontent-ber1-1.xx.fbcdn.net.",
+ "scontent-bog2-1.cdninstagram.com.",
+ "scontent-bog2-1.xx.fbcdn.net.",
+ "scontent-bog2-2.xx.fbcdn.net.",
+ "scontent-bos5-1.cdninstagram.com.",
+ "scontent-bos5-1.xx.fbcdn.net.",
+ "scontent-bru2-1.cdninstagram.com.",
+ "scontent-bru2-1.xx.fbcdn.net.",
+ "scontent-cdg4-1.cdninstagram.com.",
+ "scontent-cdg4-1.xx.fbcdn.net.",
+ "scontent-cdg4-2.cdninstagram.com.",
+ "scontent-cdg4-2.xx.fbcdn.net.",
+ "scontent-cdg4-3.cdninstagram.com.",
+ "scontent-cdg4-3.xx.fbcdn.net.",
+ "scontent-cgk1-1.xx.fbcdn.net.",
+ "scontent-cgk1-2.cdninstagram.com.",
+ "scontent-cgk1-2.xx.fbcdn.net.",
+ "scontent-cgk2-1.xx.fbcdn.net.",
+ "scontent-den2-1.cdninstagram.com.",
+ "scontent-den2-1.xx.fbcdn.net.",
+ "scontent-dfw5-1.cdninstagram.com.",
+ "scontent-dfw5-1.xx.fbcdn.net.",
+ "scontent-dfw5-2.cdninstagram.com.",
+ "scontent-dfw5-2.xx.fbcdn.net.",
+ "scontent-dus1-1.cdninstagram.com.",
+ "scontent-dus1-1.xx.fbcdn.net.",
+ "scontent-fra3-1.cdninstagram.com.",
+ "scontent-fra3-1.xx.fbcdn.net.",
+ "scontent-fra3-2.cdninstagram.com.",
+ "scontent-fra3-2.xx.fbcdn.net.",
+ "scontent-fra5-1.cdninstagram.com.",
+ "scontent-fra5-1.xx.fbcdn.net.",
+ "scontent-fra5-2.cdninstagram.com.",
+ "scontent-fra5-2.xx.fbcdn.net.",
+ "scontent-gmp1-1.cdninstagram.com.",
+ "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.",
+ "scontent-hkg1-2.cdninstagram.com.",
+ "scontent-hkg1-2.xx.fbcdn.net.",
+ "scontent-hkg4-1.cdninstagram.com.",
+ "scontent-hkg4-1.xx.fbcdn.net.",
+ "scontent-hkg4-2.cdninstagram.com.",
+ "scontent-hkg4-2.xx.fbcdn.net.",
+ "scontent-hou1-1.cdninstagram.com.",
+ "scontent-hou1-1.xx.fbcdn.net.",
+ "scontent-iad3-1.cdninstagram.com.",
+ "scontent-iad3-1.xx.fbcdn.net.",
+ "scontent-iad3-2.cdninstagram.com.",
+ "scontent-iad3-2.xx.fbcdn.net.",
+ "scontent-lax3-1.cdninstagram.com.",
+ "scontent-lax3-1.xx.fbcdn.net.",
+ "scontent-lax3-2.cdninstagram.com.",
+ "scontent-lax3-2.xx.fbcdn.net.",
+ "scontent-lga3-1.cdninstagram.com.",
+ "scontent-lga3-1.xx.fbcdn.net.",
+ "scontent-lga3-2.cdninstagram.com.",
+ "scontent-lga3-2.xx.fbcdn.net.",
+ "scontent-lhr6-1.cdninstagram.com.",
+ "scontent-lhr6-1.xx.fbcdn.net.",
+ "scontent-lhr6-2.cdninstagram.com.",
+ "scontent-lhr6-2.xx.fbcdn.net.",
+ "scontent-lhr8-1.cdninstagram.com.",
+ "scontent-lhr8-1.xx.fbcdn.net.",
+ "scontent-lhr8-2.cdninstagram.com.",
+ "scontent-lhr8-2.xx.fbcdn.net.",
+ "scontent-lis1-1.cdninstagram.com.",
+ "scontent-lis1-1.xx.fbcdn.net.",
+ "scontent-man2-1.cdninstagram.com.",
+ "scontent-man2-1.xx.fbcdn.net.",
+ "scontent-mia3-1.cdninstagram.com.",
+ "scontent-mia3-1.xx.fbcdn.net.",
+ "scontent-mia3-2.cdninstagram.com.",
+ "scontent-mia3-2.xx.fbcdn.net.",
+ "scontent-mnl1-1.xx.fbcdn.net.",
+ "scontent-mnl1-2.xx.fbcdn.net.",
+ "scontent-mrs2-1.cdninstagram.com.",
+ "scontent-mrs2-1.xx.fbcdn.net.",
+ "scontent-mrs2-2.cdninstagram.com.",
+ "scontent-mrs2-2.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-ord5-1.cdninstagram.com.",
+ "scontent-ord5-1.xx.fbcdn.net.",
+ "scontent-ord5-2.cdninstagram.com.",
+ "scontent-ord5-2.xx.fbcdn.net.",
+ "scontent-prg1-1.cdninstagram.com.",
+ "scontent-prg1-1.xx.fbcdn.net.",
+ "scontent-qro1-1.cdninstagram.com.",
+ "scontent-qro1-1.xx.fbcdn.net.",
+ "scontent-qro1-2.cdninstagram.com.",
+ "scontent-qro1-2.xx.fbcdn.net.",
+ "scontent-scl2-1.cdninstagram.com.",
+ "scontent-sea1-1.cdninstagram.com.",
+ "scontent-sea1-1.xx.fbcdn.net.",
+ "scontent-sin6-1.cdninstagram.com.",
+ "scontent-sin6-1.xx.fbcdn.net.",
+ "scontent-sin6-2.cdninstagram.com.",
+ "scontent-sin6-2.xx.fbcdn.net.",
+ "scontent-sin6-3.cdninstagram.com.",
+ "scontent-sin6-3.xx.fbcdn.net.",
+ "scontent-sin6-4.cdninstagram.com.",
+ "scontent-sin6-4.xx.fbcdn.net.",
+ "scontent-sjc3-1.cdninstagram.com.",
+ "scontent-sjc3-1.xx.fbcdn.net.",
+ "scontent-ssn1-1.cdninstagram.com.",
+ "scontent-tpe1-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-xsp1-1.cdninstagram.com.",
+ "scontent-xsp1-1.xx.fbcdn.net.",
+ "scontent-xsp1-2.cdninstagram.com.",
+ "scontent-xsp1-2.xx.fbcdn.net.",
+ "scontent-xsp1-3.cdninstagram.com.",
+ "scontent-xsp1-3.xx.fbcdn.net.",
+ "scontent-xsp2-1.cdninstagram.com.",
+ "scontent-xsp2-1.xx.fbcdn.net.",
+ "scontent-yyz1-1.cdninstagram.com.",
+ "scontent-yyz1-1.xx.fbcdn.net.",
+ "scraper2.onlineradiobox.com.",
+ "scus.his.arc.azure.com.",
+ "sdk-os.mpsdk.easebar.com.",
+ "sdk.beizi.biz.",
+ "sdk.parone.io.",
+ "sdk.qcloud.com.",
+ "sdktmp.hubcloud.com.cn.",
+ "sdn.lxdns.com.",
+ "seabroadnet.com.",
+ "seagate.com.",
+ "seagullscientific.com.",
+ "seal.networksolutions.com.",
+ "sealsubscriptions.com.",
+ "search.dnssearch.org.",
+ "search.namequery.com.",
+ "search.sunbiz.org.",
+ "search.us.namequery.com.",
+ "searchanise.com.",
+ "searchnews-dre.dt.dbankcloud.com.",
+ "searchserverapi.com.",
+ "seattle.remotepc.com.",
+ "secaucus.remotepc.com.",
+ "secure.accurint.com.",
+ "secure.paymentech.com.",
+ "secure.syndetics.com.",
+ "secureanalytic.com.",
+ "securelink.rivhs.com.",
+ "securelink.valleywisehealth.org.",
+ "securityapi.d3-pr-tm.com.",
+ "securitybankcorporation-my.sharepoint.com.",
+ "securitybankcorporation.sharepoint.com.",
+ "seedtag.com.",
+ "seexh.com.",
+ "send.microad.jp.",
+ "sendibt3.com.",
+ "sensei.ruselabs.com.",
+ "sensorsdata.cn.",
+ "sensorsdata.com.",
+ "sentry.appodeal.com.",
+ "sentry.archive.org.",
+ "sentry.ksztone.com.",
+ "sentry.quillbot.com.",
+ "sentry.wrike.com.",
+ "seoul.remotepc.com.",
+ "serv.vuukle.com.",
+ "served-by.pixfuture.com.",
+ "server.bidstack.com.",
+ "serverforge.org.",
+ "service.ringcentral.com.",
+ "service2.ultipro.com.",
+ "servicebus101.myconnectsecure.com.",
+ "servicebus102.myconnectsecure.com.",
+ "servicebus103.myconnectsecure.com.",
+ "servicebus104.myconnectsecure.com.",
+ "servicer.idealmedia.io.",
+ "services.lego.com.",
+ "services.ucp.kaspersky-labs.com.",
+ "servicetitan.com.",
+ "servr.vuukle.com.",
+ "servt.vuukle.com.",
+ "servx.opamarketplace.com.",
+ "servx.playstream.media.",
+ "session.bbc.co.uk.",
+ "session.bbc.co.uk.pri.bbc.co.uk.",
+ "session.bbc.com.",
+ "settings.live.net.",
+ "settings.luckyorange.com.",
+ "sevenrooms.com.",
+ "sewjn80htn-3.algolianet.com.",
+ "sexfortokens.com.",
+ "sf-express.com.",
+ "sg.api.translator.voice.gcloudsdk.com.",
+ "sg.hlth.io.mi.com.",
+ "sg.mmstat.com.",
+ "sg1.jiedian.stream.",
+ "sg1a-excel-collab.officeapps.live.com.",
+ "sgmbocast.com.",
+ "sgminorshort.wechat.com.",
+ "sgpcas.ezvizlife.com.",
+ "share.connect.aig.",
+ "sharpschool.com.",
+ "shc6.y.qq.com.",
+ "shopify-gtm-suite.getelevar.com.",
+ "shoplazza.com.",
+ "shortpixel.ai.",
+ "shoutout.wix.com.",
+ "shuzilm.cn.",
+ "signin.ultipro.com.",
+ "silversiri.com.",
+ "sina.com.",
+ "sinaimg.cn.",
+ "sip-backup.phonepower.com.",
+ "sip-primary.phonepower.com.",
+ "sip.ringcentral.com.",
+ "sip112-1121.ringcentral.com.",
+ "sip112-1131.ringcentral.com.",
+ "sip112-1141.ringcentral.com.",
+ "sip113-1121.ringcentral.com.",
+ "sip113-1131.ringcentral.com.",
+ "sip113-1141.ringcentral.com.",
+ "sip121-1111.ringcentral.com.",
+ "sip121-1121.ringcentral.com.",
+ "sip121-1131.ringcentral.com.",
+ "sip121-1141.ringcentral.com.",
+ "sip121-1241.ringcentral.com.",
+ "sip123-1121.ringcentral.com.",
+ "sip123-1131.ringcentral.com.",
+ "sip123-1141.ringcentral.com.",
+ "sip131-1121.ringcentral.com.",
+ "sip131-1131.ringcentral.com.",
+ "sip131-1141.ringcentral.com.",
+ "sip131-1231.ringcentral.com.",
+ "sip132-1111.ringcentral.com.",
+ "sip132-1121.ringcentral.com.",
+ "sip132-1131.ringcentral.com.",
+ "sip132-1141.ringcentral.com.",
+ "sip421-121.ringcentral.biz.",
+ "sipis.acrobits.cz.",
+ "site-config.com.",
+ "sitemaji.com.",
+ "situsamc365-my.sharepoint.com.",
+ "sjc.zoom.us.",
+ "sjc04pap001.storage.live.com.",
+ "sjc04pap001files.storage.live.com.",
+ "sjc04pap002.storage.live.com.",
+ "sjc04pap002files.storage.live.com.",
+ "skanska-my.sharepoint.com.",
+ "skyts.net.",
+ "skyward-lisdprod.iscorp.com.",
+ "skyward-ocprod.iscorp.com.",
+ "skyward.iscorp.com.",
+ "sl.streamhub.tech.",
+ "slickdealscdn.com.",
+ "sm.cn.",
+ "sm1.selectmedia.asia.",
+ "smartcloudcon.com.",
+ "smarthome.ctdevice.ott4china.com.",
+ "smartpay.profitstars.com.",
+ "smbstatic.sgp1.digitaloceanspaces.com.",
+ "smoot-searchv2-aapse1c.v.aaplimg.com.",
+ "smoot-searchv2-aeuc1a.v.aaplimg.com.",
+ "smoot-searchv2-aeuc1b.v.aaplimg.com.",
+ "smoot-searchv2-aeuw1b.v.aaplimg.com.",
+ "smoot-searchv2-aeuw3b.v.aaplimg.com.",
+ "smoot-searchv2-aeuw3c.v.aaplimg.com.",
+ "smoot-searchv2-ause1a.v.aaplimg.com.",
+ "smoot-searchv2-ause1b.v.aaplimg.com.",
+ "smoot-searchv2-ause1c.v.aaplimg.com.",
+ "smoot-searchv2-ause2a.v.aaplimg.com.",
+ "smoot-searchv2-ause2b.v.aaplimg.com.",
+ "smoot-searchv2-ause2c.v.aaplimg.com.",
+ "smoot-searchv2-ausw2b.v.aaplimg.com.",
+ "smoot-searchv2-ausw2c.v.aaplimg.com.",
+ "smrcy-my.sharepoint.com.",
+ "smrcy.sharepoint.com.",
+ "sms.ads.heytapmobi.com.",
+ "snap-storage-cdn.l.google.com.",
+ "snippet.affilimatejs.com.",
+ "snokido.com.",
+ "snz04pap001.storage.live.com.",
+ "snz04pap001files.storage.live.com.",
+ "snz04pap002.storage.live.com.",
+ "snz04pap002files.storage.live.com.",
+ "sobot.com.",
+ "socialchain.app.",
+ "sockets.stackexchange.com.",
+ "sofia.remotepc.com.",
+ "sohu.com.",
+ "sohucs.com.",
+ "solid.preyproject.com.",
+ "sonar-akl1-1.xx.fbcdn.net.",
+ "sonar-ams2-1.xx.fbcdn.net.",
+ "sonar-ams4-1.xx.fbcdn.net.",
+ "sonar-arn2-1.xx.fbcdn.net.",
+ "sonar-atl3-1.xx.fbcdn.net.",
+ "sonar-atl3-2.xx.fbcdn.net.",
+ "sonar-bcn1-1.xx.fbcdn.net.",
+ "sonar-ber1-1.xx.fbcdn.net.",
+ "sonar-bkk1-1.xx.fbcdn.net.",
+ "sonar-bkk1-2.xx.fbcdn.net.",
+ "sonar-bog2-1.xx.fbcdn.net.",
+ "sonar-bog2-2.xx.fbcdn.net.",
+ "sonar-bom1-1.xx.fbcdn.net.",
+ "sonar-bom1-2.xx.fbcdn.net.",
+ "sonar-bom2-2.xx.fbcdn.net.",
+ "sonar-bos5-1.xx.fbcdn.net.",
+ "sonar-bru2-1.xx.fbcdn.net.",
+ "sonar-ccu1-1.xx.fbcdn.net.",
+ "sonar-ccu1-2.xx.fbcdn.net.",
+ "sonar-cdg4-1.xx.fbcdn.net.",
+ "sonar-cdg4-2.xx.fbcdn.net.",
+ "sonar-cdg4-3.xx.fbcdn.net.",
+ "sonar-cgk1-1.xx.fbcdn.net.",
+ "sonar-cgk1-2.xx.fbcdn.net.",
+ "sonar-cgk2-1.xx.fbcdn.net.",
+ "sonar-cph2-1.xx.fbcdn.net.",
+ "sonar-cpt1-1.xx.fbcdn.net.",
+ "sonar-del1-1.xx.fbcdn.net.",
+ "sonar-del2-1.xx.fbcdn.net.",
+ "sonar-den2-1.xx.fbcdn.net.",
+ "sonar-dfw5-1.xx.fbcdn.net.",
+ "sonar-dfw5-2.xx.fbcdn.net.",
+ "sonar-doh1-1.xx.fbcdn.net.",
+ "sonar-dub4-1.xx.fbcdn.net.",
+ "sonar-dus1-1.xx.fbcdn.net.",
+ "sonar-eze1-1.xx.fbcdn.net.",
+ "sonar-fco2-1.xx.fbcdn.net.",
+ "sonar-fml1-1.xx.fbcdn.net.",
+ "sonar-fml20-1.xx.fbcdn.net.",
+ "sonar-for1-1.xx.fbcdn.net.",
+ "sonar-fra3-1.xx.fbcdn.net.",
+ "sonar-fra3-2.xx.fbcdn.net.",
+ "sonar-fra5-1.xx.fbcdn.net.",
+ "sonar-fra5-2.xx.fbcdn.net.",
+ "sonar-gig4-1.xx.fbcdn.net.",
+ "sonar-gig4-2.xx.fbcdn.net.",
+ "sonar-gmp1-1.xx.fbcdn.net.",
+ "sonar-gru1-2.xx.fbcdn.net.",
+ "sonar-gru2-1.xx.fbcdn.net.",
+ "sonar-gru2-2.xx.fbcdn.net.",
+ "sonar-gua1-1.xx.fbcdn.net.",
+ "sonar-ham3-1.xx.fbcdn.net.",
+ "sonar-hbe1-1.xx.fbcdn.net.",
+ "sonar-hbe1-2.xx.fbcdn.net.",
+ "sonar-hel3-1.xx.fbcdn.net.",
+ "sonar-hkg1-1.xx.fbcdn.net.",
+ "sonar-hkg1-2.xx.fbcdn.net.",
+ "sonar-hkg4-1.xx.fbcdn.net.",
+ "sonar-hkg4-2.xx.fbcdn.net.",
+ "sonar-hou1-1.xx.fbcdn.net.",
+ "sonar-hyd1-1.xx.fbcdn.net.",
+ "sonar-iad3-1.xx.fbcdn.net.",
+ "sonar-iad3-2.xx.fbcdn.net.",
+ "sonar-iev1-1.xx.fbcdn.net.",
+ "sonar-ist1-1.xx.fbcdn.net.",
+ "sonar-ist1-2.xx.fbcdn.net.",
+ "sonar-itm1-1.xx.fbcdn.net.",
+ "sonar-jnb2-1.xx.fbcdn.net.",
+ "sonar-kul2-1.xx.fbcdn.net.",
+ "sonar-kul2-2.xx.fbcdn.net.",
+ "sonar-kul3-1.xx.fbcdn.net.",
+ "sonar-lax3-1.xx.fbcdn.net.",
+ "sonar-lax3-2.xx.fbcdn.net.",
+ "sonar-lga3-1.xx.fbcdn.net.",
+ "sonar-lga3-2.xx.fbcdn.net.",
+ "sonar-lhr6-1.xx.fbcdn.net.",
+ "sonar-lhr6-2.xx.fbcdn.net.",
+ "sonar-lhr8-1.xx.fbcdn.net.",
+ "sonar-lhr8-2.xx.fbcdn.net.",
+ "sonar-lim1-1.xx.fbcdn.net.",
+ "sonar-lis1-1.xx.fbcdn.net.",
+ "sonar-los2-1.xx.fbcdn.net.",
+ "sonar-maa2-1.xx.fbcdn.net.",
+ "sonar-maa2-2.xx.fbcdn.net.",
+ "sonar-mad1-1.xx.fbcdn.net.",
+ "sonar-mad2-1.xx.fbcdn.net.",
+ "sonar-man2-1.xx.fbcdn.net.",
+ "sonar-mba1-1.xx.fbcdn.net.",
+ "sonar-mct1-1.xx.fbcdn.net.",
+ "sonar-mia3-1.xx.fbcdn.net.",
+ "sonar-mia3-2.xx.fbcdn.net.",
+ "sonar-mnl1-1.xx.fbcdn.net.",
+ "sonar-mnl1-2.xx.fbcdn.net.",
+ "sonar-mrs2-1.xx.fbcdn.net.",
+ "sonar-mrs2-2.xx.fbcdn.net.",
+ "sonar-msp1-1.xx.fbcdn.net.",
+ "sonar-mty2-1.xx.fbcdn.net.",
+ "sonar-muc2-1.xx.fbcdn.net.",
+ "sonar-mxp1-1.xx.fbcdn.net.",
+ "sonar-mxp2-1.xx.fbcdn.net.",
+ "sonar-nrt1-1.xx.fbcdn.net.",
+ "sonar-nrt1-2.xx.fbcdn.net.",
+ "sonar-ord5-1.xx.fbcdn.net.",
+ "sonar-ord5-2.xx.fbcdn.net.",
+ "sonar-otp1-1.xx.fbcdn.net.",
+ "sonar-pmo1-1.xx.fbcdn.net.",
+ "sonar-pnq1-1.xx.fbcdn.net.",
+ "sonar-pnq1-2.xx.fbcdn.net.",
+ "sonar-prg1-1.xx.fbcdn.net.",
+ "sonar-qro1-1.xx.fbcdn.net.",
+ "sonar-qro1-2.xx.fbcdn.net.",
+ "sonar-scl2-1.xx.fbcdn.net.",
+ "sonar-sea1-1.xx.fbcdn.net.",
+ "sonar-sin6-1.xx.fbcdn.net.",
+ "sonar-sin6-2.xx.fbcdn.net.",
+ "sonar-sin6-3.xx.fbcdn.net.",
+ "sonar-sin6-4.xx.fbcdn.net.",
+ "sonar-sjc3-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-1.xx.fbcdn.net.",
+ "sonar-tir3-2.xx.fbcdn.net.",
+ "sonar-tpe1-1.xx.fbcdn.net.",
+ "sonar-vie1-1.xx.fbcdn.net.",
+ "sonar-waw2-1.xx.fbcdn.net.",
+ "sonar-waw2-2.xx.fbcdn.net.",
+ "sonar-xsp1-1.xx.fbcdn.net.",
+ "sonar-xsp1-2.xx.fbcdn.net.",
+ "sonar-xsp1-3.xx.fbcdn.net.",
+ "sonar-xsp2-1.xx.fbcdn.net.",
+ "sonar-xxc1-1.xx.fbcdn.net.",
+ "sonar-yyz1-1.xx.fbcdn.net.",
+ "sonar-zrh1-1.xx.fbcdn.net.",
+ "sonar.viously.com.",
+ "sooners-my.sharepoint.com.",
+ "sound-ai-stream.alibaba.com.",
+ "southcarolina.remotepc.com.",
+ "southfront.mm.fcix.net.",
+ "sp.replit.com.",
+ "spadsync.com.",
+ "sparteo.com.",
+ "spc2com-my.sharepoint.com.",
+ "spcdn.incartupsell.com.",
+ "spec.cloud.360safe.com.",
+ "spectrumhealth-my.sharepoint.com.",
+ "spectrumhealth.sharepoint.com.",
+ "speedtest.asymptote.cc.",
+ "speedtest.sjc.timkevin.us.",
+ "spiny.ai.",
+ "spion.savvy.security.",
+ "splash-online-decision.xiaohongshu.com.",
+ "springfieldclinic-my.sharepoint.com.",
+ "springfieldclinic.sharepoint.com.",
+ "src.ebay-us.com.",
+ "srv2.maxhost.io.",
+ "ssafp.samsclub.com.",
+ "ssc.independent.co.uk.",
+ "ssctech.com.",
+ "ssl.geoplugin.net.",
+ "sso.8x8.com.",
+ "sso.readingeggs.com.",
+ "sso.services.box.net.",
+ "ssp.hbrd.io.",
+ "ssp.hybrid.ai.",
+ "sstatic.net.",
+ "ssxd.mediav.com.",
+ "st-sysupgrade.vivo.com.cn.",
+ "st.edge.oregon.edge2.salesforce.com.",
+ "stack.imgur.com.",
+ "staffbase.com.",
+ "stardustgod.com.",
+ "startssl.com.",
+ "stat.gspaceteam.com.",
+ "stat.lianmeng.360.cn.",
+ "stat.mixi.media.",
+ "stat.pdfforge.org.",
+ "statad.ru.",
+ "static-ams2-1.xx.fbcdn.net.",
+ "static-ams4-1.xx.fbcdn.net.",
+ "static-atl3-1.xx.fbcdn.net.",
+ "static-atl3-2.xx.fbcdn.net.",
+ "static-bos5-1.xx.fbcdn.net.",
+ "static-den2-1.xx.fbcdn.net.",
+ "static-dfw5-1.xx.fbcdn.net.",
+ "static-dfw5-2.xx.fbcdn.net.",
+ "static-hou1-1.xx.fbcdn.net.",
+ "static-iad3-1.xx.fbcdn.net.",
+ "static-iad3-2.xx.fbcdn.net.",
+ "static-lax3-1.xx.fbcdn.net.",
+ "static-lax3-2.xx.fbcdn.net.",
+ "static-lga3-1.xx.fbcdn.net.",
+ "static-lga3-2.xx.fbcdn.net.",
+ "static-lhr6-1.xx.fbcdn.net.",
+ "static-lhr6-2.xx.fbcdn.net.",
+ "static-lhr8-1.xx.fbcdn.net.",
+ "static-lhr8-2.xx.fbcdn.net.",
+ "static-man2-1.xx.fbcdn.net.",
+ "static-mia3-1.xx.fbcdn.net.",
+ "static-mia3-2.xx.fbcdn.net.",
+ "static-msp1-1.xx.fbcdn.net.",
+ "static-ord5-1.xx.fbcdn.net.",
+ "static-ord5-2.xx.fbcdn.net.",
+ "static-sea1-1.xx.fbcdn.net.",
+ "static-sjc3-1.xx.fbcdn.net.",
+ "static.avito.ru.",
+ "static.fastly.carvana.io.",
+ "static.independent.co.uk.",
+ "static.standard.co.uk.",
+ "static.thcdn.com.",
+ "static.writable.com.",
+ "static.zara.net.",
+ "static1.mixi.media.",
+ "static2.mixi.media.",
+ "static4.mixi.media.",
+ "static8.mixi.media.",
+ "statistic.live.126.net.",
+ "stats.adinplay.com.",
+ "stats.aeries.com.",
+ "stats.bannernow.com.",
+ "stats.dell.com.",
+ "stats.ftb.ca.gov.",
+ "stats.rip.",
+ "stats.studyquicks.com.",
+ "stats.transitapp.com.",
+ "statsapi.mlb.com.cdn.cloudflare.net.",
+ "statsig.anthropic.com.",
+ "stcharleshealthsystem-my.sharepoint.com.",
+ "steamcommunity.com.",
+ "stemchristie.rome2rio.com.",
+ "stericyclecorp-my.sharepoint.com.",
+ "stg-data-in.ads.heytapmobile.com.",
+ "stg-data.ads.heytapmobi.com.",
+ "stockholm.remotepc.com.",
+ "stocks-analytics-events.apple.com.",
+ "storage.procore.com.",
+ "storagecraft.com.",
+ "store-dra.hispace.dbankcloud.cn.",
+ "store.qq.com.",
+ "stream-production.avcdn.net.akamaized.net.",
+ "streamhub.tech.",
+ "streetviewpixels-pa.googleapis.com.",
+ "stse02.ultipro.com.",
+ "stsew02.ultipro.com.",
+ "stsn02.ultipro.com.",
+ "student.atitesting.com.",
+ "studentjths-my.sharepoint.com.",
+ "studentsecisd-my.sharepoint.com.",
+ "studentsecuedu66932-my.sharepoint.com.",
+ "studentsecuedu66932.sharepoint.com.",
+ "studenttuhsd-my.sharepoint.com.",
+ "studenttuhsd.sharepoint.com.",
+ "studyquicks.com.",
+ "stun-anycast.l.google.com.",
+ "stun.cdnbye.com.",
+ "stun.l.google.com.",
+ "stun1.ringcentral.com.",
+ "stun101.signon.gravityshavings.net.",
+ "stun102.signon.gravityshavings.net.",
+ "stun103.signon.gravityshavings.net.",
+ "stun104.signon.gravityshavings.net.",
+ "stun105.signon.gravityshavings.net.",
+ "stun106.signon.gravityshavings.net.",
+ "stun107.signon.gravityshavings.net.",
+ "stun108.signon.gravityshavings.net.",
+ "stun2.ringcentral.com.",
+ "stvinc-my.sharepoint.com.",
+ "subs.theepochtimes.com.",
+ "subway-sync.quantummetric.com.",
+ "sumari-prod-1.srv.jbisumari.org.",
+ "sumologic.com.",
+ "sunamerica.com.",
+ "sunmedia.tv.",
+ "sunmi.com.",
+ "sunnbird.com.",
+ "sunocoinc-my.sharepoint.com.",
+ "sunocoinc.sharepoint.com.",
+ "supl.qxwz.com.",
+ "support-leagueoflegends.riotgames.com.",
+ "support.powerschool.com.",
+ "surgerypartners-my.sharepoint.com.",
+ "sutterhealth-my.sharepoint.com.",
+ "sutterhealth.sharepoint.com.",
+ "sv8.cyberhaven.io.",
+ "svgrepo.com.",
+ "svlive.serraview.com.",
+ "swifttrans-my.sharepoint.com.",
+ "switch.babybus.com.",
+ "sydney.remotepc.com.",
+ "sync-1-us-west1-g.sync.services.mozilla.com.",
+ "sync.bidence.net.",
+ "sync.inmobi.com.",
+ "sync.opendsp.ru.",
+ "sync.videowalldirect.com.",
+ "syndetics.com.",
+ "systemreportservices.genetec.com.",
+ "t-odx.op-mobile.opera.com.",
+ "t.360playvid.info.",
+ "t.adcell.com.",
+ "t.marketingcloudfx.com.",
+ "t.mookie1.com.",
+ "t.poki.io.",
+ "t.wepay.com.",
+ "t3.nhentai.net.",
+ "t3.xiaohongshu.com.",
+ "tag.winister.app.",
+ "tags.growingio.com.",
+ "tags.natwest.com.",
+ "taipei.remotepc.com.",
+ "tampa.remotepc.com.",
+ "tanx.com.",
+ "tao.barstoolsports.com.",
+ "taobao.com.",
+ "tapecontent.net.",
+ "tarrantcounty-my.sharepoint.com.",
+ "tasteofhome.com.",
+ "tatracker-us.rivergame.net.",
+ "taylorfarms1com-my.sharepoint.com.",
+ "tbcache.com.",
+ "tbcdn.cn.",
+ "tccprod01.honeywell.com.",
+ "tccprod02.honeywell.com.",
+ "tccprod03.honeywell.com.",
+ "tcdnlive.com.",
+ "tch.quora.com.",
+ "tclclouds.com.",
+ "tdcservices.tandemdiabetes.com.",
+ "tdm.qq.com.",
+ "teams.microsoft.com.",
+ "teamviewer.com.",
+ "teddymobile.cn.",
+ "telaviv.remotepc.com.",
+ "telecom.shuzilm.cn.",
+ "telemetry-sdk-inmobi-comtm.trafficmanager.net.",
+ "telemetry.sdk.inmobi.com.",
+ "telephony.goog.",
+ "tencent-cloud.com.",
+ "tencent-cloud.net.",
+ "tencentmusic.com.",
+ "tenda.com.cn.",
+ "tenpay.com.",
+ "terms3.hicloud.com.",
+ "testnjjhb.com.",
+ "text.com.",
+ "tgpa.qq.com.",
+ "thanhnien.vn.",
+ "theoks.net.",
+ "thetracker.org.",
+ "think12stg.wpengine.com.",
+ "thinkific.com.",
+ "thinkingdata.cn.",
+ "thm.visa.com.",
+ "thm12.visa.com.",
+ "thumb-v1.xhcdn.com.",
+ "thumb-v3.xhcdn.com.",
+ "thumb-v4.xhcdn.com.",
+ "thumb-v8.xhcdn.com.",
+ "thumb.live.mmcdn.com.",
+ "tickets.com.",
+ "tigermailauburn-my.sharepoint.com.",
+ "tile.openstreetmap.org.",
+ "tile.osm.org.",
+ "time.ecansol.net.",
+ "time.lmtlabs.com.",
+ "time.nest.com.",
+ "time.pool.aliyun.com.",
+ "time.walb.tech.",
+ "time1.aliyun.com.",
+ "time1.google.com.",
+ "time2.aliyun.com.",
+ "time2.google.com.",
+ "time3.aliyun.com.",
+ "time3.google.com.",
+ "time4.google.com.",
+ "timi-esports.qq.com.",
+ "timken-my.sharepoint.com.",
+ "tkx.mp.lura.live.",
+ "tlivecdn.com.",
+ "tlivesource.com.",
+ "tls-amap.dingtalk.com.",
+ "tls12.eu01.nr-data.net.cdn.cloudflare.net.",
+ "tls12.newrelic.com.cdn.cloudflare.net.",
+ "tm.barclays.co.uk.",
+ "tm.bdc-cdn.com.",
+ "tm.cybersource.com.",
+ "tm.regions.com.",
+ "tmall.com.",
+ "tmc-g2.tm-4.office.com.",
+ "tmfp.klarna.com.",
+ "tmga.qq.com.",
+ "tmge.alicdn.com.",
+ "tmobile-sync.quantummetric.com.",
+ "tmx.tdbank.com.",
+ "tmx.uptodate.com.",
+ "tngdigital.com.my.",
+ "tokyo.remotepc.com.",
+ "tollbrothersinc-my.sharepoint.com.",
+ "tollbrothersinc.sharepoint.com.",
+ "top-widgets-va.us-east-1.log.aliyuncs.com.",
+ "toronto.remotepc.com.",
+ "tos-prd-api-mgmt.azure-api.net.",
+ "totallyacdn.com.",
+ "towerhealth-my.sharepoint.com.",
+ "tplay.qq.com.",
+ "tpns.sgp.tencent.com.",
+ "tpns.sh.tencent.com.",
+ "tpns.tencent.com.",
+ "tpsservice-files-inner.cn-hangzhou.oss-cdn.aliyun-inc.com.",
+ "tr.p.360.cn.",
+ "tr1.chat.si.riotgames.com.",
+ "trace.qq.com.",
+ "track-eu1.hubspot.com.",
+ "track.loopme.me.",
+ "track.sendlane.com.",
+ "tracker-udp.gbitt.info.",
+ "tracker.ccp.ovh.",
+ "tracker.files.fm.",
+ "tracker.grepler.com.",
+ "tracker.moeking.me.",
+ "tracker.nitropay.com.",
+ "tracker.nwps.ws.",
+ "tracker.theoks.net.",
+ "tracker.therarbg.com.",
+ "tracker1.bt.moack.co.kr.",
+ "tracker2.dler.org.",
+ "tracking.eu.antskre.com.",
+ "tracking.ksztone.com.",
+ "tractor.attn.tv.",
+ "tradplusad.com.",
+ "transplace-my.sharepoint.com.",
+ "transsion-miniapp-android-cdn.oss-eu-central-1.aliyuncs.com.",
+ "traversal.syncromsp.com.",
+ "treas.gov.",
+ "treasury.gov.",
+ "tremfya.com.",
+ "tribalfusion.com.",
+ "trk-assets.nutigeneby.com.",
+ "trovit.com.",
+ "ts1.mm.bing.net.",
+ "ts1.qq.com.",
+ "ts2.mm.bing.net.",
+ "ts2.qq.com.",
+ "ts3.mm.bing.net.",
+ "tse1.explicit.bing.net.",
+ "tse1.mm.bing.net.",
+ "tse2.explicit.bing.net.",
+ "tse2.mm.bing.net.",
+ "tse3.explicit.bing.net.",
+ "tse3.mm.bing.net.",
+ "tse4.explicit.bing.net.",
+ "tse4.mm.bing.net.",
+ "tsg-hdp-raw-log.data.cn-singapore-lls01-d01.sls-pub.farlightgames.com.",
+ "tsms-dre.security.dbankcloud.com.",
+ "tt.browser.360.cn.",
+ "ttcache.com.",
+ "ttigroup-my.sharepoint.com.",
+ "ttuhscep.cyberhaven.io.",
+ "tubecup.net.",
+ "tuhsdk12azus-my.sharepoint.com.",
+ "tunnel.googlezip.net.",
+ "tuoitre.vn.",
+ "tusd1-my.sharepoint.com.",
+ "tuya.com.",
+ "tw.ntp.org.cn.",
+ "twcgov-my.sharepoint.com.",
+ "txdot.sharepoint.com.",
+ "txoag-my.sharepoint.com.",
+ "tyjr-fgj.aliyun.com.vipgds.alibabadns.com.",
+ "u.4dex.io.",
+ "uapi.mp.360.cn.",
+ "uber.zoom.us.",
+ "uc.chatra-usercontent.com.",
+ "uc.cn.",
+ "ucus.ucweb.com.",
+ "ucweb.com.",
+ "udemycdn.com.",
+ "udesk.cn.",
+ "ue.lenovomm.cn.",
+ "uk-api.asm.skype.com.",
+ "uk-prod.asyncgw.teams.microsoft.com.",
+ "ukc-excel-collab.officeapps.live.com.",
+ "ukg.com.",
+ "uks.his.arc.azure.com.",
+ "uksouth-gas.guestconfiguration.azure.com.",
+ "ukyuh.tech.",
+ "ulikecam.com.",
+ "ulinq.asia.",
+ "ulta-sync.quantummetric.com.",
+ "ulta.quantummetric.com.",
+ "ultipro.com.",
+ "ultiprotime.com.",
+ "ultiproworkplace.com.",
+ "umeng.com.",
+ "uncw4-my.sharepoint.com.",
+ "uncw4.sharepoint.com.",
+ "unicom.shuzilm.cn.",
+ "unified-inbox-1-gw.ultipro.com.",
+ "unified-inbox-2-gw.ultipro.com.",
+ "union.barstoolsports.com.",
+ "union.ucweb.com.",
+ "unipay.qq.com.",
+ "unisoc.com.",
+ "united.quantummetric.com.",
+ "unitrends.com.",
+ "unity.cn.",
+ "universityofwieauclaire-my.sharepoint.com.",
+ "update.360safe.com.",
+ "update.ee-share.com.",
+ "update.huorong.cn.",
+ "update.kingsoftstore.com.",
+ "update.logmein.com.",
+ "update.vivaldi.com.",
+ "updatechannel.sharegate.com.",
+ "updaterservices.genetec.com.",
+ "updatesnl.macrium.com.",
+ "upload.app.box.com.",
+ "upload.box.com.",
+ "upload.ent.box.com.",
+ "upload.gifshow.com.",
+ "upload.ksapisrv.com.",
+ "uploads.gamecoast.net.",
+ "upravel.com.",
+ "upremium.asia.",
+ "upward-app.com.",
+ "urekamedia.com.",
+ "us-01.ws-api.ringcentral.com.",
+ "us-02.ws-api.ringcentral.com.",
+ "us-03.ws-api.ringcentral.com.",
+ "us-api.asm.skype.com.",
+ "us-atl-anx-r001.router.teamviewer.com.",
+ "us-atl-anx-r010.router.teamviewer.com.",
+ "us-central1-adaptive-growth.cloudfunctions.net.",
+ "us-central1-addshoppers-data-production.cloudfunctions.net.",
+ "us-central1-aeo-datasci-microsrv-pr-afe8.cloudfunctions.net.",
+ "us-central1-affilimate.cloudfunctions.net.",
+ "us-central1-amp-error-reporting.cloudfunctions.net.",
+ "us-central1-blaze-today.cloudfunctions.net.",
+ "us-central1-bps-oi-production.cloudfunctions.net.",
+ "us-central1-buzz-3eeb8.cloudfunctions.net.",
+ "us-central1-castify-notifications-prod.cloudfunctions.net.",
+ "us-central1-cohinc-146020.cloudfunctions.net.",
+ "us-central1-digitalproducts-gabbo.cloudfunctions.net.",
+ "us-central1-ds-specials-dev.cloudfunctions.net.",
+ "us-central1-esi-consumer.cloudfunctions.net.",
+ "us-central1-fail1v1.cloudfunctions.net.",
+ "us-central1-fsgenergy-shared.cloudfunctions.net.",
+ "us-central1-gaggle-staging.cloudfunctions.net.",
+ "us-central1-justbuild-cdb86.cloudfunctions.net.",
+ "us-central1-live-prod-1-1.cloudfunctions.net.",
+ "us-central1-locket-4252a.cloudfunctions.net.",
+ "us-central1-mikmak-microservices.cloudfunctions.net.",
+ "us-central1-muslim-pro-app.cloudfunctions.net.",
+ "us-central1-noteit-4dca3.cloudfunctions.net.",
+ "us-central1-royal-match-prod-cce6d.cloudfunctions.net.",
+ "us-central1-shopify-instrumentat-ff788286.cloudfunctions.net.",
+ "us-central1-speechifymobile.cloudfunctions.net.",
+ "us-central1-sq-sgtm-prod.cloudfunctions.net.",
+ "us-central1-teach-monster.cloudfunctions.net.",
+ "us-central1-webgltest-17af1.cloudfunctions.net.",
+ "us-central1-wetterapp-1.cloudfunctions.net.",
+ "us-central1-wise-arch-107501.cloudfunctions.net.",
+ "us-central1-wrapper-analytics-prod.cloudfunctions.net.",
+ "us-dal-anx-r001.router.teamviewer.com.",
+ "us-dal-anx-r003.router.teamviewer.com.",
+ "us-dal-anx-r004.router.teamviewer.com.",
+ "us-dal-anx-r005.router.teamviewer.com.",
+ "us-dal-anx-r006.router.teamviewer.com.",
+ "us-dal-anx-r007.router.teamviewer.com.",
+ "us-dal-anx-r008.router.teamviewer.com.",
+ "us-dal-anx-r009.router.teamviewer.com.",
+ "us-dal-anx-r010.router.teamviewer.com.",
+ "us-east-1.log.aliyuncs.com.",
+ "us-east4-chkp-gcp-rnd-threat-hunt-box.cloudfunctions.net.",
+ "us-lax-anx-r003.router.teamviewer.com.",
+ "us-lax-anx-r006.router.teamviewer.com.",
+ "us-lax-anx-r007.router.teamviewer.com.",
+ "us-lax-anx-r009.router.teamviewer.com.",
+ "us-lax-anx-r012.router.teamviewer.com.",
+ "us-lax-anx-r013.router.teamviewer.com.",
+ "us-lax-anx-r014.router.teamviewer.com.",
+ "us-lax-anx-r015.router.teamviewer.com.",
+ "us-lax-gcp-r005.router.teamviewer.com.",
+ "us-mia-anx-r003.router.teamviewer.com.",
+ "us-mia-anx-r006.router.teamviewer.com.",
+ "us-mia-anx-r011.router.teamviewer.com.",
+ "us-mia-anx-r012.router.teamviewer.com.",
+ "us-njc-anx-r008.router.teamviewer.com.",
+ "us-njc-anx-r013.router.teamviewer.com.",
+ "us-njc-anx-r014.router.teamviewer.com.",
+ "us-njc-anx-r018.router.teamviewer.com.",
+ "us-oma-gcp-r002.router.teamviewer.com.",
+ "us-pftk-temu-com.trafficmanager.net.",
+ "us-prod.asyncgw.teams.microsoft.com.",
+ "us-sea-anx-r001.router.teamviewer.com.",
+ "us-sea-anx-r002.router.teamviewer.com.",
+ "us-sea-anx-r003.router.teamviewer.com.",
+ "us-sea-anx-r004.router.teamviewer.com.",
+ "us-sea-anx-r005.router.teamviewer.com.",
+ "us-sea-anx-r007.router.teamviewer.com.",
+ "us-spectrum.rcs.telephony.goog.",
+ "us-was-anx-r012.router.teamviewer.com.",
+ "us-was-anx-r019.router.teamviewer.com.",
+ "us-was-anx-r020.router.teamviewer.com.",
+ "us-west-1.log.aliyuncs.com.",
+ "us.att.rcs.telephony.goog.",
+ "us.evidation.com.",
+ "us.peerhub.net.",
+ "us.pftk.temu.com.",
+ "us.tmobile.rcs.telephony.goog.",
+ "us.tracfone.rcs.telephony.goog.",
+ "us.uscc.rcs.telephony.goog.",
+ "us.xfinity.rcs.telephony.goog.",
+ "us02.ws-api.ringcentral.com.",
+ "us02log.zoom.us.",
+ "us02polling.zoom.us.",
+ "us02web.zoom.us.",
+ "us02www3.zoom.us.",
+ "us03.ws-api.ringcentral.com.",
+ "us04asyncim.zoom.us.",
+ "us04nws-platform.zoom.us.",
+ "us04nws.zoom.us.",
+ "us04web.zoom.us.",
+ "us04www3.zoom.us.",
+ "us05nws-platform.zoom.us.",
+ "us05nws.zoom.us.",
+ "us05web.zoom.us.",
+ "us05www3.zoom.us.",
+ "us06log.zoom.us.",
+ "us06polling.zoom.us.",
+ "us06web.zoom.us.",
+ "us06www3.zoom.us.",
+ "us1.ecdn2.badoocdn.com.",
+ "us1.ecdn2.bumbcdn.com.",
+ "us2.iceporn.xxx.",
+ "us2.rtbsystem.org.",
+ "us4s-word-collab.officeapps.live.com.",
+ "usbank.quantummetric.com.",
+ "usc-excel-collab.officeapps.live.com.",
+ "usc-powerpoint-collab.officeapps.live.com.",
+ "usc-word-collab.officeapps.live.com.",
+ "uscourts.gov.",
+ "useinsider.com.",
+ "usemotion.com.",
+ "user.jpush.cn.",
+ "userexperience.thehut.net.",
+ "userflow.com.",
+ "userlike.com.",
+ "usgcorp.sharepoint.com.",
+ "usgs.gov.",
+ "usii-my.sharepoint.com.",
+ "usii.sharepoint.com.",
+ "uslbm-my.sharepoint.com.",
+ "ussav.cynet.com.",
+ "usslb.cynet.com.",
+ "uswest-beacon.deepintent.com.",
+ "uu.qq.com.",
+ "uuidksinc.net.",
+ "uvermont.mm.fcix.net.",
+ "uvu365-my.sharepoint.com.",
+ "uxfeedback.ru.",
+ "uyunad.com.",
+ "v.streaming.qq.com.",
+ "v.vivintsky.com.",
+ "v2-zj-shxcm.kwaicdn.com.",
+ "v34.tiktokcdn.com.",
+ "v39-as.tiktokcdn.com.",
+ "v39-ca.tiktokcdn.com.",
+ "v39-id-telin.tiktokcdn.com.",
+ "v39-id.tiktokcdn.com.",
+ "v39-my.tiktokcdn.com.",
+ "v39-row.gts.byteoversea.net.",
+ "v39-row.tiktokcdn.com.",
+ "v39-us.gts.byteoversea.net.",
+ "v39-us.tiktokcdn.com.",
+ "v45-ph-globe.tiktokcdn.com.",
+ "v6-gdvod.kwaicdn.com.",
+ "v8.analytics.pinsightmedia.com.",
+ "v8engine.pinsightmedia.com.",
+ "vador.com.",
+ "valleychildrensorg-my.sharepoint.com.",
+ "vancitycu-my.sharepoint.com.",
+ "varify.io.",
+ "vb24131crasosnemesis.com.",
+ "vbw.vivoglobal.com.",
+ "vconf.f.360.cn.",
+ "veraxen.com.",
+ "veronanetworks.mm.fcix.net.",
+ "verticals.wix.com.",
+ "veteransunited-my.sharepoint.com.",
+ "veteransunited.sharepoint.com.",
+ "vexgateway.fastly.carvana.io.",
+ "vfa.hpplay.cn.",
+ "vgorigin.hakunaymatata.com.",
+ "viadcorp-my.sharepoint.com.",
+ "vibe.co.",
+ "vibeaconstr.onezapp.com.",
+ "vicoo.tech.",
+ "vidamx-my.sharepoint.com.",
+ "video-atl3-1.xx.fbcdn.net.",
+ "video-atl3-2.xx.fbcdn.net.",
+ "video-bos5-1.xx.fbcdn.net.",
+ "video-den2-1.xx.fbcdn.net.",
+ "video-dfw5-1.xx.fbcdn.net.",
+ "video-dfw5-2.xx.fbcdn.net.",
+ "video-hou1-1.xx.fbcdn.net.",
+ "video-iad3-1.xx.fbcdn.net.",
+ "video-iad3-2.xx.fbcdn.net.",
+ "video-lax3-1.xx.fbcdn.net.",
+ "video-lax3-2.xx.fbcdn.net.",
+ "video-lga3-1.xx.fbcdn.net.",
+ "video-lga3-2.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-msp1-1.xx.fbcdn.net.",
+ "video-ord5-1.xx.fbcdn.net.",
+ "video-ord5-2.xx.fbcdn.net.",
+ "video-sea1-1.xx.fbcdn.net.",
+ "video-sjc3-1.xx.fbcdn.net.",
+ "videocloud.cn-hangzhou.log.aliyuncs.com.",
+ "videocontent-dra.himovie.dbankcloud.com.",
+ "videoqoe-fastly.stvidtest.net.",
+ "vidmate.net.",
+ "vieon.vn.",
+ "view.adbravotech.com.",
+ "view2fa.prosourcehosted.com.",
+ "vik-ca.moonactive.net.",
+ "village365-my.sharepoint.com.",
+ "viously.com.",
+ "vip-chinanet.ynuf.aliapp.org.",
+ "vipads.live.",
+ "virusinfo-cloudscan-cn.heytapmobi.com.",
+ "visainc.sharepoint.com.",
+ "visionserviceplan-my.sharepoint.com.",
+ "visionserviceplan.sharepoint.com.",
+ "visitor.fiftyt.com.",
+ "visitors.live.",
+ "vitalant-my.sharepoint.com.",
+ "vivoglobal.com.",
+ "vlscppe.microsoft.com.",
+ "vn-viettel.rcs.telephony.goog.",
+ "vn.pool.ntp.org.",
+ "vod.ngb.haplat.net.",
+ "vod3.ngb.haplat.net.",
+ "vod5.ngb.haplat.net.",
+ "voe.sx.",
+ "voice.gcloudcs.com.",
+ "voice.telephony.goog.",
+ "volusiastudents-my.sharepoint.com.",
+ "volusiastudents.sharepoint.com.",
+ "vpn.cshealthforlife.com.",
+ "vpn.garypools.com.",
+ "vpn1.ocso.com.",
+ "vpp-license-proxy.aliyuncs.com.",
+ "vzuu.com.",
+ "w.deepl.com.",
+ "w0.peakpx.com.",
+ "w3.mp.lura.live.",
+ "wabtec.okta.com.",
+ "waf.rippecloud.com.",
+ "walletconnect.com.",
+ "walshgroup-my.sharepoint.com.",
+ "wanmei.com.",
+ "wap.cmpassport.com.",
+ "warsaw.remotepc.com.",
+ "washoeschools-my.sharepoint.com.",
+ "washoeschools.sharepoint.com.",
+ "wbte.drcedirect.com.",
+ "wcpss-my.sharepoint.com.",
+ "wcsdpaorg-my.sharepoint.com.",
+ "weather-analytics-events.apple.com.",
+ "weather-server-sg.allawnos.com.",
+ "weather-server.allawntech.com.",
+ "weather-widget-events.apple.com.",
+ "weather.swishapps.ai.",
+ "weathercn.com.",
+ "weatheroffer.com.",
+ "web-assets.cdn4dd.com.",
+ "web-g.kontiki.com.",
+ "web-static.archive.org.",
+ "web.archive.org.",
+ "web.fe.1drv.com.",
+ "web.tagembed.com.",
+ "web.voice.telephony.goog.",
+ "web.wg1.kontiki.com.",
+ "web1.remotepc.com.",
+ "webapi.teamviewer.com.",
+ "webapp.src.discover.com.",
+ "webmd.com.",
+ "weborama-tech.ru.",
+ "webrad.io.",
+ "websocket.app.pdq.com.",
+ "wechatos.net.",
+ "weibocdn.com.",
+ "welcome.ultipro.com.",
+ "wellspan.sharepoint.com.",
+ "westelm.com.",
+ "westerngovernorsuniversity-my.sharepoint.com.",
+ "westpalm.remotepc.com.",
+ "westrockco-my.sharepoint.com.",
+ "westrockco.sharepoint.com.",
+ "wetype.weixin.qq.com.",
+ "weu.his.arc.azure.com.",
+ "wewjyw.qb6ges.com.",
+ "wf-proxy-01.algolia.com.",
+ "wf-proxy-02.algolia.com.",
+ "wf-proxy-03.algolia.com.",
+ "whitingturner-my.sharepoint.com.",
+ "whitingturner.sharepoint.com.",
+ "whm.develop.dev.experiancs.com.",
+ "widget.tagembed.com.",
+ "wifispot.io.",
+ "winscp.net.",
+ "wipro365.sharepoint.com.",
+ "wkhpe.com.",
+ "wlgore-my.sharepoint.com.",
+ "wlgore.sharepoint.com.",
+ "wn.safe.360.cn.",
+ "word-collab.officeapps.live.com.",
+ "workdaycdn.com.cn.",
+ "worldnic.com.",
+ "worldtimeserver.com.",
+ "worldwideexpress2323-my.sharepoint.com.",
+ "wosign.com.",
+ "wp-thumbnail.parone.io.",
+ "wp.safe.360.cn.",
+ "wpp.net.",
+ "wr.moyoung.com.",
+ "wr.pvp.net.",
+ "ws.gleap.io.",
+ "ws.mybib.com.",
+ "ws.tildacdn.com.",
+ "ws1seg.rwjbh.org.",
+ "wsfcsk12nc-my.sharepoint.com.",
+ "wsfsbank-my.sharepoint.com.",
+ "wsfsbank.sharepoint.com.",
+ "wsms.haplat.net.",
+ "wsoversea.com.",
+ "wtpsnj-my.sharepoint.com.",
+ "wtsparadigm.com.",
+ "wtzw.com.",
+ "wus2.his.arc.azure.com.",
+ "wwt-my.sharepoint.com.",
+ "wwt.sharepoint.com.",
+ "www.247mirror.com.",
+ "www.aigconnect.aig.",
+ "www.automizely-analytics.com.",
+ "www.bbc.co.uk.",
+ "www.bbc.co.uk.pri.bbc.co.uk.",
+ "www.bbc.com.",
+ "www.bbc.com.pri.bbc.com.",
+ "www.bbthat.com.",
+ "www.bleepingcomputer.com.",
+ "www.box.com.",
+ "www.breitbart.com.",
+ "www.bridge2bwb.com.",
+ "www.cmpassport.com.",
+ "www.dhl.de.",
+ "www.docusign.com.",
+ "www.enaple.com.",
+ "www.essence.com.",
+ "www.etsy.com.",
+ "www.fanatics.com.",
+ "www.fmcschedule.com.",
+ "www.gbnews.com.",
+ "www.geoplugin.net.",
+ "www.google.org.",
+ "www.gslb.pinterest.net.",
+ "www.handmadewithjoann.com.",
+ "www.imanageshare.com.",
+ "www.in.gov.",
+ "www.independent.co.uk.",
+ "www.inoreader.com.",
+ "www.iorad.com.",
+ "www.jdpower.com.",
+ "www.jhnet.com.",
+ "www.jimmyjohns.com.",
+ "www.jpost.com.",
+ "www.klj888.cn.",
+ "www.mainadv.com.",
+ "www.maintenanceconnection.com.",
+ "www.mottandbow.com.",
+ "www.nationalreview.com.",
+ "www.nativecos.com.",
+ "www.overleaf.com.",
+ "www.pingler.com.",
+ "www.pool.ntp.org.",
+ "www.printfriendly.com.",
+ "www.rawstory.com.",
+ "www.regions.com.",
+ "www.searchanise.com.",
+ "www.sevenrooms.com.",
+ "www.shopmyexchange.com.",
+ "www.snokido.com.",
+ "www.soso.com.",
+ "www.standard.co.uk.",
+ "www.stickermule.com.",
+ "www.thenews.com.pk.",
+ "www.timeanddate.com.cdn.cloudflare.net.",
+ "www.upward-app.com.",
+ "www.users.storage.live.com.",
+ "www.vipads.live.",
+ "www.virustotal.com.",
+ "www.wifispot.io.",
+ "www.wix.com.",
+ "www.worldtimeserver.com.",
+ "www.xnxx.tv.",
+ "www.yext.com.",
+ "www.youngla.com.",
+ "www.zoom.us.",
+ "www.zscaler.com.",
+ "www1.remotepc.com.",
+ "www2.deepl.com.",
+ "www3.zoom.us.",
+ "wx.huion.cn.",
+ "wxqcloud.qq.com.",
+ "wxqcloud.qq.com.cn.",
+ "wyze-app-monitor.wyzecam.com.",
+ "wyze.com.",
+ "x-flow.app.",
+ "x.netease.com.",
+ "x.research.qq.com.",
+ "xapads.com.",
+ "xhpingcdn.com.",
+ "xiaoyi-css-us-15d.oss-us-west-1.aliyuncs.com.",
+ "xiaoyi-css-us-7d.oss-us-west-1.aliyuncs.com.",
+ "xiaoyi.com.",
+ "xintaicz.cn.",
+ "xjp-msgacs.m.taobao.com.",
+ "xmcsrv.net.",
+ "xml-eu-v4.ezmob.com.",
+ "xml-v4.ezmob.com.",
+ "xml.cachegorilla.com.",
+ "xml.car-bidpush.org.",
+ "xml.cow-timerbudder.org.",
+ "xml.ezmob.com.",
+ "xml.popmonetizer.net.",
+ "xml.xmlking.com.",
+ "xml.yellow-resultsbidder.com.",
+ "xml.zeusadx.com.",
+ "xp002.itsupport247.net.",
+ "xp004.itsupport247.net.",
+ "xp005.itsupport247.net.",
+ "xp006.itsupport247.net.",
+ "xp007.itsupport247.net.",
+ "xp008.itsupport247.net.",
+ "xp009.itsupport247.net.",
+ "xp015.itsupport247.net.",
+ "xp016.itsupport247.net.",
+ "xp017.itsupport247.net.",
+ "xp018.itsupport247.net.",
+ "xp019.itsupport247.net.",
+ "xpdrwp.itsupport247.net.",
+ "xtom.com.",
+ "yazio-analytics.com.",
+ "yealink.com.",
+ "ymmobi.com.",
+ "ynuf.aliapp.org.",
+ "ynuf.aliapp.org.gds.alibabadns.com.",
+ "yomedia.vn.",
+ "yomeno.xyz.",
+ "youngjoygame.com.",
+ "youtooz.com.",
+ "yp.cdnstream1.com.",
+ "yunxindns.com.",
+ "z-m-scontent-lis1-1.xx.fbcdn.net.",
+ "z.cdn.ftd.agency.",
+ "z.cdn.trafficbass.com.",
+ "zachryholdings-my.sharepoint.com.",
+ "zego.im.",
+ "zendesk.okta.com.",
+ "zenno.services.",
+ "zeotap.com.",
+ "zhangchu.net.",
+ "zimgs.cn.",
+ "ziply.mm.fcix.net.",
+ "zjcdn.com.yangyi19.com.",
+ "zoom.us.",
+ "ztoken.uyunad.com.",
+ "zui.com.",
+ "zurich.remotepc.com.",
+ "zybooks.com.",
+)
diff --git a/internal/ecscache/ecsblocklist_generate.go b/internal/ecscache/ecsblocklist_generate.go
index 2a414a0..abc27cb 100644
--- a/internal/ecscache/ecsblocklist_generate.go
+++ b/internal/ecscache/ecsblocklist_generate.go
@@ -57,13 +57,15 @@ const tmplStr = `// Code generated by go run ./ecsblocklist_generate.go; DO NOT
package ecscache
+import "github.com/AdguardTeam/golibs/container"
+
// FakeECSFQDNs contains all domains that indicate ECS support, but in fact
// don't have one.
-var FakeECSFQDNs = map[string]struct{}{
+var FakeECSFQDNs = container.NewMapSet(
{{- range $_, $h := . }}
- {{ printf "\"%s.\": {}," $h }}
+ {{ printf "%q" ( printf "%s." $h ) }},
{{- end }}
-}
+)
`
// check is a simple error checker.
diff --git a/internal/ecscache/ecscache.go b/internal/ecscache/ecscache.go
index 8f8f131..6889db7 100644
--- a/internal/ecscache/ecscache.go
+++ b/internal/ecscache/ecscache.go
@@ -8,6 +8,7 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
@@ -17,7 +18,6 @@ import (
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/syncutil"
- "github.com/bluele/gcache"
"github.com/miekg/dns"
)
@@ -27,10 +27,10 @@ type Middleware struct {
cloner *dnsmsg.Cloner
// cache is the LRU cache for results indicating no support for ECS.
- cache gcache.Cache
+ cache agdcache.Interface[uint64, *cacheItem]
// ecsCache is the LRU cache for results indicating ECS support.
- ecsCache gcache.Cache
+ ecsCache agdcache.Interface[uint64, *cacheItem]
// geoIP is used to get subnets for countries.
geoIP geoip.Interface
@@ -73,10 +73,14 @@ type MiddlewareConfig struct {
// be nil.
func NewMiddleware(c *MiddlewareConfig) (m *Middleware) {
return &Middleware{
- cloner: c.Cloner,
- cache: gcache.New(c.Size).LRU().Build(),
- ecsCache: gcache.New(c.ECSSize).LRU().Build(),
- geoIP: c.GeoIP,
+ cloner: c.Cloner,
+ cache: agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
+ Size: c.Size,
+ }),
+ ecsCache: agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
+ Size: c.ECSSize,
+ }),
+ geoIP: c.GeoIP,
cacheReqPool: syncutil.NewPool(func() (req *cacheRequest) {
return &cacheRequest{}
}),
@@ -215,10 +219,10 @@ func (mw *Middleware) writeUpstreamResponse(
respIsECS := respIsECSDependent(scope, req.Question[0].Name)
if respIsECS {
metrics.ECSCacheLookupHasSupportMisses.Inc()
- metrics.ECSHasSupportCacheSize.Set(float64(mw.ecsCache.Len(false)))
+ metrics.ECSHasSupportCacheSize.Set(float64(mw.ecsCache.Len()))
} else {
metrics.ECSCacheLookupNoSupportMisses.Inc()
- metrics.ECSNoSupportCacheSize.Set(float64(mw.cache.Len(false)))
+ metrics.ECSNoSupportCacheSize.Set(float64(mw.cache.Len()))
cr.subnet = netutil.ZeroPrefix(ecsFam)
}
@@ -350,12 +354,10 @@ func (mh *mwHandler) ServeDNS(
// where an authoritative nameserver incorrectly echoes our ECS data.
//
// See https://datatracker.ietf.org/doc/html/rfc7871#section-7.2.1.
-func respIsECSDependent(scope uint8, host string) (ok bool) {
+func respIsECSDependent(scope uint8, fqdn string) (ok bool) {
if scope == 0 {
return false
}
- _, isFake := FakeECSFQDNs[host]
-
- return !isFake
+ return !FakeECSFQDNs.Has(fqdn)
}
diff --git a/internal/ecscache/ecscache_test.go b/internal/ecscache/ecscache_test.go
index 0a67b96..530676f 100644
--- a/internal/ecscache/ecscache_test.go
+++ b/internal/ecscache/ecscache_test.go
@@ -20,7 +20,6 @@ import (
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "golang.org/x/exp/maps"
)
func TestMain(m *testing.M) {
@@ -216,7 +215,7 @@ func TestMiddleware_Wrap_noECS(t *testing.T) {
}
var msg *dns.Msg
- for i := 0; i < N; i++ {
+ for range N {
msg = exchange(t, ri, withCache, tc.req)
}
@@ -256,7 +255,16 @@ func TestMiddleware_Wrap_ecs(t *testing.T) {
ip := net.IP{1, 2, 3, 0}
aReq := newAReq(reqHostname, ip)
- fakeECSReq := newAReq(maps.Keys(ecscache.FakeECSFQDNs)[0], ip)
+
+ var fakeECSFQDN string
+ ecscache.FakeECSFQDNs.Range(func(s string) (cont bool) {
+ fakeECSFQDN = s
+
+ return false
+ })
+ require.NotZero(t, fakeECSFQDN)
+
+ fakeECSReq := newAReq(fakeECSFQDN, ip)
subnet := netip.PrefixFrom(netip.AddrFrom4([4]byte(ip)), prefixLen)
const ctry = geoip.CountryAD
@@ -377,7 +385,7 @@ func TestMiddleware_Wrap_ecs(t *testing.T) {
}
var msg *dns.Msg
- for i := 0; i < N; i++ {
+ for range N {
msg = exchange(t, ri, withCache, tc.req)
}
require.NotNil(t, msg)
diff --git a/internal/errcoll/sentry.go b/internal/errcoll/sentry.go
index d3a289c..5dbbc4f 100644
--- a/internal/errcoll/sentry.go
+++ b/internal/errcoll/sentry.go
@@ -1,6 +1,7 @@
package errcoll
import (
+ "cmp"
"context"
"io"
"net"
@@ -182,9 +183,11 @@ type sentryTags = map[string]string
// tagsFromCtx returns Sentry tags based on the information from ctx.
func tagsFromCtx(ctx context.Context) (tags sentryTags) {
tags = sentryTags{
+ // TODO(a.garipov): Use a standard version package.
"git_revision": agd.Revision(),
}
+ // TODO(a.garipov): Consider splitting agdctx package.
var reqID agd.RequestID
if ri, ok := agd.RequestInfoFromContext(ctx); ok {
tags["filtering_group_id"] = string(ri.FilteringGroup.ID)
@@ -228,9 +231,5 @@ func toASCII(s string) (ascii string) {
ascii = strconv.QuoteToASCII(s)
ascii = ascii[1 : len(ascii)-1]
- if ascii == "" {
- ascii = "(empty)"
- }
-
- return ascii
+ return cmp.Or(ascii, "(empty)")
}
diff --git a/internal/experiment/experiment.go b/internal/experiment/experiment.go
new file mode 100644
index 0000000..71b8753
--- /dev/null
+++ b/internal/experiment/experiment.go
@@ -0,0 +1,55 @@
+// Package experiment occasionally contains code for one-off experiments.
+// Experiments can be enabled using the EXPERIMENTS environment variable, which
+// is a comma-separated list of experiment IDs.
+//
+// Please keep every experiment in its own file.
+//
+// Since the code living here is short-living, the following requirements do not
+// apply:
+//
+// - Comments may be skipped.
+// - Some errors may be logged or ignored.
+// - Tests may be lacking.
+// - The environment may be read here as opposed to package cmd.
+// - init() is allowed.
+package experiment
+
+import (
+ "os"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/golibs/log"
+ "github.com/AdguardTeam/golibs/stringutil"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+func init() {
+ expStr := os.Getenv("EXPERIMENTS")
+ if expStr == "" {
+ return
+ }
+
+ expIDs := stringutil.SplitTrimmed(expStr, ",")
+ for _, id := range expIDs {
+ switch id {
+ // NOTE: Add experiments here in the following format:
+ // case idMyExp:
+ // enableMyExp()
+ default:
+ log.Error("experiment: no experiment with id %q", id)
+ }
+ }
+
+ enableMetrics()
+}
+
+// enableMetrics sets the labels with enabled experiments and sets the gauge
+// value to 1.
+func enableMetrics() {
+ expGauge := metrics.ExperimentGauge(prometheus.Labels{
+ // NOTE: Add experiments here in the following format:
+ // idMyExp: metrics.BoolString(expMyExpEnabled),
+ })
+
+ expGauge.Set(1)
+}
diff --git a/internal/filter/filter.go b/internal/filter/filter.go
index 91652b5..d567777 100644
--- a/internal/filter/filter.go
+++ b/internal/filter/filter.go
@@ -19,7 +19,8 @@ type Interface = internal.Interface
//
// - [*ResultAllowed]
// - [*ResultBlocked]
-// - [*ResultModified]
+// - [*ResultModifiedResponse]
+// - [*ResultModifiedRequest]
type Result = internal.Result
// ResultAllowed means that this request or response was allowed by an allowlist
@@ -30,9 +31,13 @@ type ResultAllowed = internal.ResultAllowed
// rule within the given filter list.
type ResultBlocked = internal.ResultBlocked
-// ResultModified means that this request or response was rewritten or modified
-// by a rewrite rule within the given filter list.
-type ResultModified = internal.ResultModified
+// ResultModifiedResponse means that this response was rewritten or modified by
+// a rewrite rule within the given filter list.
+type ResultModifiedResponse = internal.ResultModifiedResponse
+
+// ResultModifiedRequest means that this request was modified by a rewrite rule
+// within the given filter list.
+type ResultModifiedRequest = internal.ResultModifiedRequest
// Hash matching for safe-browsing and adult-content blocking
diff --git a/internal/filter/filter_test.go b/internal/filter/filter_test.go
index 724fdc4..8be9144 100644
--- a/internal/filter/filter_test.go
+++ b/internal/filter/filter_test.go
@@ -69,24 +69,23 @@ const (
safeSearchHost = "duckduckgo.com"
safeSearchRespHost = "safe.duckduckgo.com"
- safeSearchIPHost = "www.yandex.by"
+ safeSearchIPv4Host = "www.yandex.by"
+ safeSearchIPv6Host = "www.google.com"
safeBrowsingHost = "scam.example.net"
safeBrowsingSubHost = "subsub.sub." + safeBrowsingHost
safeBrowsingSubFQDN = safeBrowsingSubHost + "."
- safeBrowsingSafeHost = "safe.dns.example.net"
+ safeBrowsingReplHost = "safe.dns.example.net"
+ safeBrowsingReplFQDN = safeBrowsingReplHost + "."
)
-// Common immutable values. Keep in sync with ./testdata/filter and
-// ./safesearchhost.csv.
+// Common immutable values. Keep in sync with ./testdata/ files.
var (
blockedIP4 = net.IP{6, 6, 6, 13}
allowedIP4 = net.IP{7, 7, 7, 42}
- safeBrowsingSafeIP4 = netip.MustParseAddr("94.140.14.14")
-
safeSearchIPRespIP4 = netip.MustParseAddr("213.180.193.56")
- safeSearchIPRespIP6 = netip.MustParseAddr("1:203:1:203:1:203:1:203")
+ safeSearchIPRespIP6 = netip.MustParseAddr("2001:4860:4802:32::78")
)
// Common clients. Keep in sync with ./testdata/filter.
@@ -181,8 +180,6 @@ func prepareConf(t testing.TB) (c *filter.DefaultStorageConfig) {
NewRegDomains: &hashprefix.Filter{},
Now: time.Now,
ErrColl: nil,
- Resolver: nil,
- Cloner: agdtest.NewCloner(),
CacheDir: cacheDir,
CustomFilterCacheSize: 100,
SafeSearchCacheSize: 100,
diff --git a/internal/filter/hashprefix/filter.go b/internal/filter/hashprefix/filter.go
index 4e6c523..92fbca4 100644
--- a/internal/filter/hashprefix/filter.go
+++ b/internal/filter/hashprefix/filter.go
@@ -3,18 +3,19 @@ package hashprefix
import (
"context"
"fmt"
+ "net/netip"
"net/url"
"strings"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
- "github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/resultcache"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
@@ -36,9 +37,6 @@ type FilterConfig struct {
// ErrColl is used to collect non-critical and rare errors.
ErrColl errcoll.Interface
- // Resolver is used to resolve hosts for the hash-prefix filter.
- Resolver agdnet.Resolver
-
// ID is the ID of this hash storage for logging and error reporting.
ID agd.FilterListID
@@ -46,9 +44,10 @@ type FilterConfig struct {
// hostnames, one per line.
CachePath string
- // ReplacementHost is the replacement host for this filter. Queries
- // matched by the filter receive a response with the IP addresses of
- // this host.
+ // ReplacementHost is the replacement host for this filter. Queries matched
+ // by the filter receive a response with the IP addresses of this host. If
+ // ReplacementHost contains a valid IP, that IP is used. Otherwise, it
+ // should be a valid domain name.
ReplacementHost string
// Staleness is the time after which a file is considered stale.
@@ -60,6 +59,9 @@ type FilterConfig struct {
// TODO(a.garipov): Currently unused. See AGDNS-398.
CacheTTL time.Duration
+ // RefreshTimeout is the timeout for the filter update operation.
+ RefreshTimeout time.Duration
+
// CacheSize is the size of the filter's result cache.
CacheSize int
@@ -67,30 +69,75 @@ type FilterConfig struct {
MaxSize uint64
}
+// cacheItem represents an item that we will store in the cache.
+type cacheItem struct {
+ // res is the filtering result.
+ res internal.Result
+
+ // host is the cached normalized hostname for later cache key collision
+ // checks.
+ host string
+}
+
+// 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 agdcache.Interface[internal.CacheKey, *cacheItem],
+ key internal.CacheKey,
+ host string,
+) (item *cacheItem, ok bool) {
+ item, ok = cache.Get(key)
+ if !ok {
+ return nil, false
+ }
+
+ if item.host != host {
+ optlog.Error2("hashprefix: collision: bad cache item %v for host %q", item, host)
+
+ return nil, false
+ }
+
+ return item, true
+}
+
// Filter is a filter that matches hosts by their hashes based on a
// hash-prefix table.
type Filter struct {
cloner *dnsmsg.Cloner
hashes *Storage
refr *internal.Refreshable
- resCache *resultcache.Cache[*internal.ResultModified]
- resolver agdnet.Resolver
+ resCache agdcache.Interface[internal.CacheKey, *cacheItem]
errColl errcoll.Interface
id agd.FilterListID
- repHost string
+ repIP netip.Addr
+ repFQDN string
}
// NewFilter returns a new hash-prefix filter. c must not be nil.
func NewFilter(c *FilterConfig) (f *Filter, err error) {
id := c.ID
f = &Filter{
- cloner: c.Cloner,
- hashes: c.Hashes,
- resCache: resultcache.New[*internal.ResultModified](c.CacheSize),
- resolver: c.Resolver,
- errColl: c.ErrColl,
- id: id,
- repHost: c.ReplacementHost,
+ cloner: c.Cloner,
+ hashes: c.Hashes,
+ resCache: agdcache.NewLRU[internal.CacheKey, *cacheItem](&agdcache.LRUConfig{
+ Size: c.CacheSize,
+ }),
+ errColl: c.ErrColl,
+ id: id,
+ }
+
+ repHost := c.ReplacementHost
+ ip, err := netip.ParseAddr(repHost)
+ if err != nil {
+ err = netutil.ValidateDomainName(repHost)
+ if err != nil {
+ return nil, fmt.Errorf("replacement host: %w", err)
+ }
+
+ f.repFQDN = dns.Fqdn(repHost)
+ } else {
+ f.repIP = ip
}
f.refr = internal.NewRefreshable(&internal.RefreshableConfig{
@@ -98,9 +145,8 @@ func NewFilter(c *FilterConfig) (f *Filter, err error) {
ID: id,
CachePath: c.CachePath,
Staleness: c.Staleness,
- // TODO(ameshkov): Consider making configurable.
- Timeout: internal.DefaultFilterRefreshTimeout,
- MaxSize: c.MaxSize,
+ Timeout: c.RefreshTimeout,
+ MaxSize: c.MaxSize,
})
err = f.refresh(context.Background(), true)
@@ -116,24 +162,18 @@ func NewFilter(c *FilterConfig) (f *Filter, err error) {
var _ internal.RequestFilter = (*Filter)(nil)
// FilterRequest implements the [internal.RequestFilter] interface for
-// *Filter. It modifies the response if host matches f.
+// *Filter. It modifies the request or response if host matches f.
func (f *Filter) FilterRequest(
ctx context.Context,
req *dns.Msg,
ri *agd.RequestInfo,
) (r internal.Result, err error) {
host, qt, cl := ri.Host, ri.QType, ri.QClass
- cacheKey := resultcache.DefaultKey(host, qt, cl, false)
- rm, ok := f.resCache.Get(cacheKey)
+ cacheKey := internal.NewCacheKey(host, qt, cl, false)
+ item, ok := itemFromCache(f.resCache, cacheKey, host)
f.updateCacheLookupsMetrics(ok)
if ok {
- if rm == nil {
- // Return nil explicitly instead of modifying CloneForReq to return
- // nil if the result is nil to avoid a “non-nil nil” value.
- return nil, nil
- }
-
- return rm.CloneForReq(f.cloner, req), nil
+ return f.clonedResult(req, item.res), nil
}
fam, ok := isFilterable(qt)
@@ -152,34 +192,25 @@ func (f *Filter) FilterRequest(
}
if matched == "" {
- f.resCache.Set(cacheKey, nil)
+ f.resCache.Set(cacheKey, &cacheItem{
+ res: nil,
+ host: host,
+ })
return nil, nil
}
- ctx, cancel := context.WithTimeout(ctx, internal.DefaultResolveTimeout)
- defer cancel()
-
- result, err := f.filteredResponse(ctx, req, ri, fam)
+ r, err = f.filteredResult(req, matched, ri, fam)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return nil, err
}
- rm = &internal.ResultModified{
- Msg: result,
- List: f.id,
- Rule: agd.FilterRuleText(matched),
- }
+ f.setInCache(cacheKey, r, host)
- // Copy the result to make sure that modifications to the result message
- // down the pipeline don't interfere with the cached value.
- //
- // See AGDNS-359.
- f.resCache.Set(cacheKey, rm.Clone(f.cloner))
- f.updateCacheSizeMetrics(f.resCache.ItemCount())
+ f.updateCacheSizeMetrics(f.resCache.Len())
- return rm, nil
+ return r, nil
}
// ID implements the [internal.RequestFilter] interface for *Filter.
@@ -200,9 +231,55 @@ func isFilterable(qt dnsmsg.RRType) (fam netutil.AddrFamily, ok bool) {
return fam, fam != netutil.AddrFamilyNone
}
-// filteredResponse returns a filtered response.
-func (f *Filter) filteredResponse(
- ctx context.Context,
+// clonedResult returns a clone of the result based on its type. r must be nil,
+// [*internal.ResultModifiedRequest], or [*internal.ResultModifiedResponse].
+func (f *Filter) clonedResult(req *dns.Msg, r internal.Result) (clone internal.Result) {
+ switch r := r.(type) {
+ case nil:
+ return nil
+ case *internal.ResultModifiedRequest:
+ return r.Clone(f.cloner)
+ case *internal.ResultModifiedResponse:
+ return r.CloneForReq(f.cloner, req)
+ default:
+ panic(fmt.Errorf("hashprefix: unexpected type for result: %T(%[1]v)", r))
+ }
+}
+
+// filteredResult returns a filtered request or response.
+func (f *Filter) filteredResult(
+ req *dns.Msg,
+ matched string,
+ ri *agd.RequestInfo,
+ fam netutil.AddrFamily,
+) (r internal.Result, err error) {
+ if f.repFQDN != "" {
+ // Assume that the repFQDN is a valid domain name then.
+ req = f.cloner.Clone(req)
+ req.Question[0].Name = dns.Fqdn(f.repFQDN)
+
+ return &internal.ResultModifiedRequest{
+ Msg: req,
+ List: f.id,
+ Rule: agd.FilterRuleText(matched),
+ }, nil
+ }
+
+ resp, err := f.respForFamily(req, ri, fam)
+ if err != nil {
+ return nil, fmt.Errorf("filter %s: creating modified result: %w", f.id, err)
+ }
+
+ return &internal.ResultModifiedResponse{
+ Msg: resp,
+ List: f.id,
+ Rule: agd.FilterRuleText(matched),
+ }, nil
+}
+
+// respForFamily returns a filtered response in accordance with the protocol
+// family and question type.
+func (f *Filter) respForFamily(
req *dns.Msg,
ri *agd.RequestInfo,
fam netutil.AddrFamily,
@@ -212,31 +289,43 @@ func (f *Filter) filteredResponse(
// blocked response. See AGDNS-1551.
//
// TODO(ameshkov): Consider putting the resolved IP addresses into hints
- // to show the blocked page here as well.
- resp, err = ri.Messages.NewBlockedRespMsg(req)
- if err != nil {
- return nil, fmt.Errorf("filter %s: creating blocked result: %w", f.id, err)
- }
-
- return resp, nil
+ // to show the blocked page here as well?
+ return ri.Messages.NewBlockedRespMsg(req)
}
- ctx, cancel := context.WithTimeout(ctx, internal.DefaultResolveTimeout)
- defer cancel()
+ ip := f.repIP
- ips, err := f.resolver.LookupNetIP(ctx, fam, f.repHost)
- if err != nil {
- errcoll.Collectf(ctx, f.errColl, "filter %s: resolving: %w", f.id, err)
-
- return ri.Messages.NewMsgSERVFAIL(req), nil
+ switch {
+ case ip.Is4() && fam == netutil.AddrFamilyIPv4:
+ return ri.Messages.NewIPRespMsg(req, ip)
+ case ip.Is6() && fam == netutil.AddrFamilyIPv6:
+ return ri.Messages.NewIPRespMsg(req, ip)
+ default:
+ return ri.Messages.NewMsgNODATA(req), nil
}
+}
- resp, err = ri.Messages.NewIPRespMsg(req, ips...)
- if err != nil {
- return nil, fmt.Errorf("filter %s: creating modified result: %w", f.id, err)
+// setInCache sets r in cache. It clones the result to make sure that
+// modifications to the result message down the pipeline don't interfere with
+// the cached value. r must be either [*internal.ResultModifiedRequest] or
+// [*internal.ResultModifiedResponse].
+//
+// See AGDNS-359.
+func (f *Filter) setInCache(k internal.CacheKey, r internal.Result, host string) {
+ switch r := r.(type) {
+ case *internal.ResultModifiedRequest:
+ f.resCache.Set(k, &cacheItem{
+ res: r.Clone(f.cloner),
+ host: host,
+ })
+ case *internal.ResultModifiedResponse:
+ f.resCache.Set(k, &cacheItem{
+ res: r.Clone(f.cloner),
+ host: host,
+ })
+ default:
+ panic(fmt.Errorf("hashprefix: unexpected type for result: %T(%[1]v)", r))
}
-
- return resp, nil
}
// updateCacheSizeMetrics updates cache size metrics.
@@ -278,7 +367,16 @@ var _ agdservice.Refresher = (*Filter)(nil)
// Refresh implements the [agdservice.Refresher] interface for *Filter.
func (f *Filter) Refresh(ctx context.Context) (err error) {
- return f.refresh(ctx, false)
+ // TODO(a.garipov): Use slog.
+ log.Info("hashprefix_filter_refresh: %s: started", f.id)
+ defer log.Info("hashprefix_filter_refresh: %s: finished", f.id)
+
+ err = f.refresh(ctx, false)
+ if err != nil {
+ errcoll.Collectf(ctx, f.errColl, "hashprefix_filter_refresh: %w", err)
+ }
+
+ return err
}
// refresh reloads and resets the hash-filter data. If acceptStale is true, do
@@ -295,7 +393,7 @@ func (f *Filter) refresh(ctx context.Context, acceptStale bool) (err error) {
fltIDStr := string(f.id)
metrics.SetStatusGauge(metrics.FilterUpdatedStatus.WithLabelValues(fltIDStr), err)
if err != nil {
- return fmt.Errorf("resetting: %w", err)
+ return fmt.Errorf("%s: resetting: %w", f.id, err)
}
f.resCache.Clear()
diff --git a/internal/filter/hashprefix/filter_test.go b/internal/filter/hashprefix/filter_test.go
index 4b911ff..0171d23 100644
--- a/internal/filter/hashprefix/filter_test.go
+++ b/internal/filter/hashprefix/filter_test.go
@@ -15,21 +15,254 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/filtertest"
- "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-func TestFilter_FilterRequest(t *testing.T) {
- cachePath, srvURL := filtertest.PrepareRefreshable(t, nil, testHost, http.StatusOK)
+func TestFilter_FilterRequest_host(t *testing.T) {
+ testCases := []struct {
+ name string
+ host string
+ replHost string
+ wantRule agd.FilterRuleText
+ qType dnsmsg.RRType
+ wantResult bool
+ }{{
+ name: "host_not_a_or_aaaa",
+ host: testHost,
+ replHost: testReplHost,
+ wantRule: "",
+ qType: dns.TypeTXT,
+ wantResult: false,
+ }, {
+ name: "host_success",
+ host: testHost,
+ replHost: testReplHost,
+ wantRule: testHost,
+ qType: dns.TypeA,
+ wantResult: true,
+ }, {
+ name: "host_success_subdomain",
+ host: "a.b.c." + testHost,
+ replHost: testReplHost,
+ wantRule: testHost,
+ qType: dns.TypeA,
+ wantResult: true,
+ }, {
+ name: "host_no_match",
+ host: testOtherHost,
+ replHost: testReplHost,
+ wantRule: "",
+ qType: dns.TypeA,
+ wantResult: false,
+ }, {
+ name: "ip_not_a_or_aaaa",
+ host: testHost,
+ replHost: filtertest.SafeBrowsingReplIPv4Str,
+ wantRule: "",
+ qType: dns.TypeTXT,
+ wantResult: false,
+ }, {
+ name: "ip_success",
+ host: testHost,
+ replHost: filtertest.SafeBrowsingReplIPv4Str,
+ wantRule: testHost,
+ qType: dns.TypeA,
+ wantResult: true,
+ }, {
+ name: "ip_success_subdomain",
+ host: "a.b.c." + testHost,
+ replHost: filtertest.SafeBrowsingReplIPv4Str,
+ wantRule: testHost,
+ qType: dns.TypeA,
+ wantResult: true,
+ }, {
+ name: "ip_no_match",
+ replHost: filtertest.SafeBrowsingReplIPv4Str,
+ host: testOtherHost,
+ wantRule: "",
+ qType: dns.TypeA,
+ wantResult: false,
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ f := newFilter(t, tc.replHost)
+
+ req := dnsservertest.NewReq(
+ dns.Fqdn(tc.host),
+ tc.qType,
+ dns.ClassINET,
+ )
+ ri := &agd.RequestInfo{
+ Messages: agdtest.NewConstructor(),
+ Host: tc.host,
+ QType: tc.qType,
+ }
+
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+
+ r, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
+
+ var wantRes internal.Result
+ if tc.wantResult {
+ if tc.replHost == testReplHost {
+ wantRes = newModReqResult(req, tc.wantRule)
+ } else {
+ wantRes = newModRespResult(t, req, ri.Messages, filtertest.SafeBrowsingReplIPv4)
+ }
+ }
+
+ assert.Equal(t, wantRes, r)
+ })
+ }
+
+ require.True(t, t.Run("cached_success", func(t *testing.T) {
+ f := newFilter(t, testReplHost)
+
+ req := dnsservertest.NewReq(
+ dns.Fqdn(testHost),
+ dns.TypeA,
+ dns.ClassINET,
+ )
+ ri := &agd.RequestInfo{
+ Messages: agdtest.NewConstructor(),
+ Host: testHost,
+ QType: dns.TypeA,
+ }
+
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+
+ original, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
+
+ cached, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
+
+ // Do not check the ID as it is new for every clone.
+ originalRM := testutil.RequireTypeAssert[*internal.ResultModifiedRequest](t, original)
+ cachedRM := testutil.RequireTypeAssert[*internal.ResultModifiedRequest](t, cached)
+ cachedRM.Msg.Id = originalRM.Msg.Id
+
+ assert.Equal(t, cached, original)
+ }))
+
+ require.True(t, t.Run("cached_no_match", func(t *testing.T) {
+ f := newFilter(t, testReplHost)
+
+ req := dnsservertest.NewReq(
+ dns.Fqdn(testOtherHost),
+ dns.TypeA,
+ dns.ClassINET,
+ )
+ ri := &agd.RequestInfo{
+ Messages: agdtest.NewConstructor(),
+ Host: testOtherHost,
+ QType: dns.TypeA,
+ }
+
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+
+ r, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
+
+ cached, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
+
+ assert.Equal(t, cached, r)
+ }))
+
+ require.True(t, t.Run("https", func(t *testing.T) {
+ f := newFilter(t, testReplHost)
+
+ req := dnsservertest.NewReq(dns.Fqdn(testHost), dns.TypeHTTPS, dns.ClassINET)
+ ri := &agd.RequestInfo{
+ Messages: agdtest.NewConstructor(),
+ Host: testHost,
+ QType: dns.TypeHTTPS,
+ }
+
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+
+ r, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
+ require.NotNil(t, r)
+
+ assert.Equal(t, newModReqResult(req, testHost), r)
+ }))
+
+ require.True(t, t.Run("https_ip", func(t *testing.T) {
+ f := newFilter(t, filtertest.SafeBrowsingReplIPv4Str)
+
+ req := dnsservertest.NewReq(dns.Fqdn(testHost), dns.TypeHTTPS, dns.ClassINET)
+ ri := &agd.RequestInfo{
+ Messages: agdtest.NewConstructor(),
+ Host: testHost,
+ QType: dns.TypeHTTPS,
+ }
+
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+
+ r, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
+ require.NotNil(t, r)
+
+ m := testutil.RequireTypeAssert[*internal.ResultModifiedResponse](t, r)
+ require.NotNil(t, m.Msg)
+ require.Len(t, m.Msg.Question, 1)
+
+ assert.Equal(t, m.Msg.Question[0].Qtype, dns.TypeHTTPS)
+ assert.Len(t, m.Msg.Answer, 0)
+ }))
+}
+
+// newModRespResult is a helper for creating modified results for tests.
+func newModRespResult(
+ tb testing.TB,
+ req *dns.Msg,
+ messages *dnsmsg.Constructor,
+ replIP netip.Addr,
+) (r *internal.ResultModifiedResponse) {
+ tb.Helper()
+
+ resp, err := messages.NewIPRespMsg(req, replIP)
+ require.NoError(tb, err)
+
+ return &internal.ResultModifiedResponse{
+ Msg: resp,
+ List: testFltListID,
+ Rule: testHost,
+ }
+}
+
+// newModReqResult is a helper for creating modified results for tests.
+func newModReqResult(
+ req *dns.Msg,
+ rule agd.FilterRuleText,
+) (r *internal.ResultModifiedRequest) {
+ req = dnsmsg.Clone(req)
+ req.Question[0].Name = dns.Fqdn(testReplHost)
+
+ return &internal.ResultModifiedRequest{
+ Msg: req,
+ List: testFltListID,
+ Rule: rule,
+ }
+}
+
+// newFilter is a helper constructor for tests.
+func newFilter(tb testing.TB, replHost string) (f *hashprefix.Filter) {
+ tb.Helper()
+
+ cachePath, srvURL := filtertest.PrepareRefreshable(tb, nil, testHost, http.StatusOK)
strg, err := hashprefix.NewStorage("")
- require.NoError(t, err)
+ require.NoError(tb, err)
- replIP := netip.MustParseAddr("1.2.3.4")
- f, err := hashprefix.NewFilter(&hashprefix.FilterConfig{
+ f, err = hashprefix.NewFilter(&hashprefix.FilterConfig{
Cloner: agdtest.NewCloner(),
Hashes: strg,
URL: srvURL,
@@ -38,168 +271,17 @@ func TestFilter_FilterRequest(t *testing.T) {
panic("not implemented")
},
},
- Resolver: &agdtest.Resolver{
- OnLookupNetIP: func(
- _ context.Context,
- _ netutil.AddrFamily,
- _ string,
- ) (ips []netip.Addr, err error) {
- return []netip.Addr{replIP}, nil
- },
- },
ID: agd.FilterListIDAdultBlocking,
CachePath: cachePath,
- ReplacementHost: "repl.example",
+ ReplacementHost: replHost,
Staleness: filtertest.Staleness,
CacheTTL: filtertest.CacheTTL,
CacheSize: 1,
MaxSize: filtertest.FilterMaxSize,
})
- require.NoError(t, err)
-
- messages := agdtest.NewConstructor()
-
- testCases := []struct {
- name string
- host string
- qType dnsmsg.RRType
- wantResult bool
- }{{
- name: "not_a_or_aaaa",
- host: testHost,
- qType: dns.TypeTXT,
- wantResult: false,
- }, {
- name: "success",
- host: testHost,
- qType: dns.TypeA,
- wantResult: true,
- }, {
- name: "success_subdomain",
- host: "a.b.c." + testHost,
- qType: dns.TypeA,
- wantResult: true,
- }, {
- name: "no_match",
- host: testOtherHost,
- qType: dns.TypeA,
- wantResult: false,
- }}
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- req := dnsservertest.NewReq(
- dns.Fqdn(tc.host),
- tc.qType,
- dns.ClassINET,
- )
- ri := &agd.RequestInfo{
- Messages: messages,
- Host: tc.host,
- QType: tc.qType,
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
-
- var r internal.Result
- r, err = f.FilterRequest(ctx, req, ri)
- require.NoError(t, err)
-
- if tc.wantResult {
- wantRes := newModifiedResult(t, req, messages, replIP)
- assert.Equal(t, wantRes, r)
- } else {
- assert.Nil(t, r)
- }
- })
- }
-
- t.Run("cached_success", func(t *testing.T) {
- req := dnsservertest.NewReq(
- dns.Fqdn(testHost),
- dns.TypeA,
- dns.ClassINET,
- )
- ri := &agd.RequestInfo{
- Messages: messages,
- Host: testHost,
- QType: dns.TypeA,
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
-
- var r internal.Result
- r, err = f.FilterRequest(ctx, req, ri)
- require.NoError(t, err)
-
- wantRes := newModifiedResult(t, req, messages, replIP)
- assert.Equal(t, wantRes, r)
- })
-
- t.Run("cached_no_match", func(t *testing.T) {
- req := dnsservertest.NewReq(
- dns.Fqdn(testOtherHost),
- dns.TypeA,
- dns.ClassINET,
- )
- ri := &agd.RequestInfo{
- Messages: messages,
- Host: testOtherHost,
- QType: dns.TypeA,
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
-
- var r internal.Result
- r, err = f.FilterRequest(ctx, req, ri)
- require.NoError(t, err)
-
- assert.Nil(t, r)
- })
-
- t.Run("https", func(t *testing.T) {
- req := dnsservertest.NewReq(dns.Fqdn(testHost), dns.TypeHTTPS, dns.ClassINET)
- ri := &agd.RequestInfo{
- Messages: messages,
- Host: testHost,
- QType: dns.TypeHTTPS,
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
-
- var r internal.Result
- r, err = f.FilterRequest(ctx, req, ri)
- require.NoError(t, err)
- require.NotNil(t, r)
-
- m := testutil.RequireTypeAssert[*internal.ResultModified](t, r)
- require.NotNil(t, m.Msg)
- require.Len(t, m.Msg.Question, 1)
-
- assert.Equal(t, m.Msg.Question[0].Qtype, dns.TypeHTTPS)
- assert.Len(t, m.Msg.Answer, 0)
- })
-}
-
-// newModifiedResult is a helper for creating modified results for tests.
-func newModifiedResult(
- tb testing.TB,
- req *dns.Msg,
- messages *dnsmsg.Constructor,
- replIP netip.Addr,
-) (r *internal.ResultModified) {
- resp, err := messages.NewIPRespMsg(req, replIP)
require.NoError(tb, err)
- return &internal.ResultModified{
- Msg: resp,
- List: testFltListID,
- Rule: testHost,
- }
+ return f
}
func TestFilter_Refresh(t *testing.T) {
@@ -218,18 +300,9 @@ func TestFilter_Refresh(t *testing.T) {
panic("not implemented")
},
},
- Resolver: &agdtest.Resolver{
- OnLookupNetIP: func(
- _ context.Context,
- _ netutil.AddrFamily,
- _ string,
- ) (ips []netip.Addr, err error) {
- panic("not implemented")
- },
- },
ID: agd.FilterListIDAdultBlocking,
CachePath: cachePath,
- ReplacementHost: "",
+ ReplacementHost: testReplHost,
Staleness: filtertest.Staleness,
CacheTTL: filtertest.CacheTTL,
CacheSize: 1,
@@ -237,8 +310,7 @@ func TestFilter_Refresh(t *testing.T) {
})
require.NoError(t, err)
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
err = f.Refresh(ctx)
assert.NoError(t, err)
@@ -264,7 +336,6 @@ func TestFilter_FilterRequest_staleCache(t *testing.T) {
strg, err := hashprefix.NewStorage("")
require.NoError(t, err)
- replIP := netip.MustParseAddr("1.2.3.4")
fconf := &hashprefix.FilterConfig{
Cloner: agdtest.NewCloner(),
Hashes: strg,
@@ -274,18 +345,9 @@ func TestFilter_FilterRequest_staleCache(t *testing.T) {
panic("not implemented")
},
},
- Resolver: &agdtest.Resolver{
- OnLookupNetIP: func(
- _ context.Context,
- _ netutil.AddrFamily,
- _ string,
- ) (ips []netip.Addr, err error) {
- return []netip.Addr{replIP}, nil
- },
- },
ID: agd.FilterListIDAdultBlocking,
CachePath: cachePath,
- ReplacementHost: "repl.example",
+ ReplacementHost: testReplHost,
Staleness: filtertest.Staleness,
CacheTTL: filtertest.CacheTTL,
CacheSize: 1,
@@ -309,60 +371,48 @@ func TestFilter_FilterRequest_staleCache(t *testing.T) {
testOtherHostReq := dnsservertest.NewReq(dns.Fqdn(testOtherHost), dns.TypeA, dns.ClassINET)
testOtherReqInfo := &agd.RequestInfo{Messages: messages, Host: testOtherHost, QType: dns.TypeA}
- t.Run("hit_cached_host", func(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
+ require.True(t, t.Run("hit_cached_host", func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
var r internal.Result
r, err = f.FilterRequest(ctx, testOtherHostReq, testOtherReqInfo)
require.NoError(t, err)
- var resp *dns.Msg
- resp, err = messages.NewIPRespMsg(testOtherHostReq, replIP)
- require.NoError(t, err)
+ assert.Equal(t, newModReqResult(testOtherHostReq, testOtherHost), r)
+ }))
- assert.Equal(t, &internal.ResultModified{
- Msg: resp,
- List: testFltListID,
- Rule: testOtherHost,
- }, r)
- })
-
- t.Run("refresh", func(t *testing.T) {
+ require.True(t, t.Run("refresh", func(t *testing.T) {
// Make the cache stale.
now := time.Now()
err = os.Chtimes(cachePath, now, now.Add(-2*fconf.Staleness))
require.NoError(t, err)
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
err = f.Refresh(ctx)
assert.NoError(t, err)
testutil.RequireReceive(t, refrCh, filtertest.Timeout)
- })
+ }))
- t.Run("previously_cached", func(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
+ require.True(t, t.Run("previously_cached", func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
var r internal.Result
r, err = f.FilterRequest(ctx, testOtherHostReq, testOtherReqInfo)
require.NoError(t, err)
assert.Nil(t, r)
- })
+ }))
- t.Run("new_host", func(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
+ require.True(t, t.Run("new_host", func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
var r internal.Result
r, err = f.FilterRequest(ctx, testHostReq, testReqInfo)
require.NoError(t, err)
- wantRes := newModifiedResult(t, testHostReq, messages, replIP)
+ wantRes := newModReqResult(testHostReq, testHost)
assert.Equal(t, wantRes, r)
- })
+ }))
}
diff --git a/internal/filter/hashprefix/hashprefix_test.go b/internal/filter/hashprefix/hashprefix_test.go
index de2de4f..9f4bb7a 100644
--- a/internal/filter/hashprefix/hashprefix_test.go
+++ b/internal/filter/hashprefix/hashprefix_test.go
@@ -17,5 +17,6 @@ const testFltListID = agd.FilterListIDAdultBlocking
// Common hostnames for tests.
const (
testHost = "porn.example"
+ testReplHost = "repl.example"
testOtherHost = "otherporn.example"
)
diff --git a/internal/filter/hashprefix/matcher.go b/internal/filter/hashprefix/matcher.go
index cc9eaee..7fd0cbc 100644
--- a/internal/filter/hashprefix/matcher.go
+++ b/internal/filter/hashprefix/matcher.go
@@ -7,7 +7,7 @@ import (
"strings"
"github.com/AdguardTeam/AdGuardDNS/internal/optlog"
- "github.com/AdguardTeam/golibs/stringutil"
+ "github.com/AdguardTeam/golibs/container"
)
// Matcher is a hash-prefix matcher that uses the hash-prefix storages as the
@@ -73,7 +73,7 @@ func prefixesFromStr(prefixesStr string) (hashPrefixes []Prefix, err error) {
return nil, nil
}
- prefixSet := stringutil.NewSet()
+ prefixSet := container.NewMapSet[string]()
prefixStrs := strings.Split(prefixesStr, ".")
for _, s := range prefixStrs {
switch l := len(s); l {
diff --git a/internal/filter/hashprefix/storage.go b/internal/filter/hashprefix/storage.go
index 5209b21..0fdf105 100644
--- a/internal/filter/hashprefix/storage.go
+++ b/internal/filter/hashprefix/storage.go
@@ -92,7 +92,7 @@ func (s *Storage) Hashes(prefs []Prefix) (hashes []string) {
str := b.String()
hashes = make([]string, 0, l)
- for i := 0; i < l; i++ {
+ for i := range l {
hashes = append(hashes, str[i*hashEncLen:(i+1)*hashEncLen])
}
diff --git a/internal/filter/hashprefix/storage_test.go b/internal/filter/hashprefix/storage_test.go
index b77d625..c57bb2a 100644
--- a/internal/filter/hashprefix/storage_test.go
+++ b/internal/filter/hashprefix/storage_test.go
@@ -82,7 +82,7 @@ func BenchmarkStorage_Hashes(b *testing.B) {
const N = 10_000
var hosts []string
- for i := 0; i < N; i++ {
+ for i := range N {
hosts = append(hosts, fmt.Sprintf("%d."+testHost, i))
}
@@ -90,7 +90,7 @@ func BenchmarkStorage_Hashes(b *testing.B) {
require.NoError(b, err)
var hashPrefixes []hashprefix.Prefix
- for i := 0; i < 4; i++ {
+ for i := range 4 {
hashPrefixes = append(hashPrefixes, hashprefix.Prefix{hosts[i][0], hosts[i][1]})
}
@@ -100,7 +100,7 @@ func BenchmarkStorage_Hashes(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
strsSink = s.Hashes(hps)
}
})
@@ -122,7 +122,7 @@ func BenchmarkStorage_ResetHosts(b *testing.B) {
const N = 1_000
var hosts []string
- for i := 0; i < N; i++ {
+ for i := range N {
hosts = append(hosts, fmt.Sprintf("%d."+testHost, i))
}
@@ -132,7 +132,7 @@ func BenchmarkStorage_ResetHosts(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
_, errSink = s.Reset(hostnames)
}
diff --git a/internal/filter/internal/cachekey.go b/internal/filter/internal/cachekey.go
new file mode 100644
index 0000000..9394a1a
--- /dev/null
+++ b/internal/filter/internal/cachekey.go
@@ -0,0 +1,36 @@
+package internal
+
+import (
+ "encoding/binary"
+ "hash/maphash"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/golibs/mathutil"
+)
+
+// 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 host, qt, and isAns using the
+// 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())
+}
diff --git a/internal/filter/internal/composite/composite.go b/internal/filter/internal/composite/composite.go
index 02bd248..7ac0bd2 100644
--- a/internal/filter/internal/composite/composite.go
+++ b/internal/filter/internal/composite/composite.go
@@ -14,7 +14,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/safesearch"
"github.com/AdguardTeam/AdGuardDNS/internal/optlog"
- "github.com/AdguardTeam/urlfilter/rules"
"github.com/miekg/dns"
)
@@ -127,8 +126,7 @@ func (f *Filter) FilterRequest(
// Firstly, check the profile's rule-list filtering, the custom rules, and
// the rules from blocked services settings.
- host := ri.Host
- rlRes := f.filterWithRuleLists(ri, host, ri.QType, req)
+ rlRes := f.filterReqWithRuleLists(ri, req)
switch flRes := rlRes.(type) {
case *internal.ResultAllowed:
// Skip any additional filtering if the domain is explicitly allowed by
@@ -136,8 +134,12 @@ func (f *Filter) FilterRequest(
if flRes.List == agd.FilterListIDCustom {
return flRes, nil
}
- case *internal.ResultBlocked:
- // Skip any additional filtering if the domain is already blocked.
+ case
+ *internal.ResultBlocked,
+ *internal.ResultModifiedRequest,
+ *internal.ResultModifiedResponse:
+ // Skip any additional filtering if the query is already blocked or
+ // modified.
return flRes, nil
default:
// Go on.
@@ -159,9 +161,55 @@ func (f *Filter) FilterRequest(
return rlRes, nil
}
+// filterReqWithRuleLists filters one question's information through all rule
+// list filters of the composite filter. req must not be nil.
+func (f *Filter) filterReqWithRuleLists(ri *agd.RequestInfo, req *dns.Msg) (r internal.Result) {
+ ip, host, qt := ri.RemoteIP, ri.Host, ri.QType
+
+ ufRes := &rulelist.URLFilterResult{}
+ if f.custom != nil {
+ // Only use the device name for custom filters of profiles with devices.
+ var devName string
+ if d := ri.Device; d != nil {
+ devName = string(d.Name)
+ }
+
+ id := agd.FilterListIDCustom
+ dr := f.custom.DNSResult(ip, devName, host, qt, false)
+ mod := rulelist.ProcessDNSRewrites(ri.Messages, req, dr.DNSRewrites(), host, 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(dr)
+ }
+
+ for _, rl := range f.ruleLists {
+ id, _ := rl.ID()
+ dr := rl.DNSResult(ip, "", host, qt, false)
+ mod := rulelist.ProcessDNSRewrites(ri.Messages, req, dr.DNSRewrites(), host, id)
+ if mod != nil {
+ // DNS rewrites have higher priority, so a modified request must be
+ // returned immediately.
+ return mod
+ }
+
+ ufRes.Add(dr)
+ }
+
+ for _, rl := range f.svcLists {
+ ufRes.Add(rl.DNSResult(ip, "", host, qt, false))
+ }
+
+ return ufRes.ToInternal(f, qt)
+}
+
// FilterResponse implements the [internal.Interface] interface for *Filter. It
// returns the action created from the filter list network rule with the highest
-// priority. If f is empty, it returns nil with no error.
+// priority. If f is empty, it returns nil with no error. Note that rewrite
+// results are not applied to responses.
func (f *Filter) FilterResponse(
_ context.Context,
resp *dns.Msg,
@@ -193,7 +241,35 @@ func (f *Filter) filterAnswer(ri *agd.RequestInfo, ans dns.RR) (r internal.Resul
return nil
}
- return f.filterWithRuleLists(ri, host, rrType, nil)
+ return f.filterRespWithRuleLists(ri, host, rrType)
+}
+
+// filterRespWithRuleLists filters one answer's information through all
+// rule-list filters of the composite filter.
+func (f *Filter) filterRespWithRuleLists(
+ ri *agd.RequestInfo,
+ host string,
+ rrType dnsmsg.RRType,
+) (r internal.Result) {
+ ufRes := &rulelist.URLFilterResult{}
+ for _, rl := range f.ruleLists {
+ ufRes.Add(rl.DNSResult(ri.RemoteIP, "", host, rrType, true))
+ }
+
+ if f.custom != nil {
+ var devName string
+ if d := ri.Device; d != nil {
+ devName = string(d.Name)
+ }
+
+ ufRes.Add(f.custom.DNSResult(ri.RemoteIP, devName, host, rrType, true))
+ }
+
+ for _, rl := range f.svcLists {
+ ufRes.Add(rl.DNSResult(ri.RemoteIP, "", host, rrType, true))
+ }
+
+ return ufRes.ToInternal(f, rrType)
}
// filterHTTPSAnswer filters HTTPS answers information through all rule list
@@ -221,7 +297,7 @@ func (f *Filter) filterSVCBHint(
ri *agd.RequestInfo,
) (r internal.Result) {
for _, s := range strings.Split(hint, ",") {
- r = f.filterWithRuleLists(ri, s, dns.TypeHTTPS, nil)
+ r = f.filterRespWithRuleLists(ri, s, dns.TypeHTTPS)
if r != nil {
return r
}
@@ -255,55 +331,13 @@ func (f *Filter) isEmpty() (ok bool) {
len(f.reqFilters) == 0)
}
-// filterWithRuleLists filters one question's or answer's information through
-// all rule list filters of the composite filter. If req is nil, the message is
-// assumed to be a response.
-func (f *Filter) filterWithRuleLists(
- ri *agd.RequestInfo,
- host string,
- rrType dnsmsg.RRType,
- req *dns.Msg,
-) (r internal.Result) {
- var devName string
- if d := ri.Device; d != nil {
- devName = string(d.Name)
- }
+// type check
+var _ rulelist.IDMapper = (*Filter)(nil)
- ufRes := &urlFilterResult{}
- isAnswer := req == nil
- for _, rl := range f.ruleLists {
- ufRes.add(rl.DNSResult(ri.RemoteIP, devName, host, rrType, isAnswer))
- }
-
- if f.custom != nil {
- dr := f.custom.DNSResult(ri.RemoteIP, devName, host, rrType, isAnswer)
- // Collect only custom $dnsrewrite rules. It's much easier to process
- // dnsrewrite rules only from one list, cause when there is no problem
- // with merging them among different lists.
- if !isAnswer {
- modified := processDNSRewrites(ri.Messages, req, dr.DNSRewrites(), host)
- if modified != nil {
- return modified
- }
- }
-
- ufRes.add(dr)
- }
-
- for _, rl := range f.svcLists {
- ufRes.add(rl.DNSResult(ri.RemoteIP, devName, host, rrType, isAnswer))
- }
-
- if nr := rules.GetDNSBasicRule(ufRes.networkRules); nr != nil {
- return f.ruleDataToResult(nr.FilterListID, nr.RuleText, nr.Whitelist)
- }
-
- return f.hostsRulesToResult(ufRes.hostRules4, ufRes.hostRules6, rrType)
-}
-
-// mustRuleListDataByURLFilterID returns the rule list data by its synthetic
-// integer ID in the urlfilter engine. It panics if id is not found.
-func (f *Filter) mustRuleListDataByURLFilterID(
+// Map implements the [rulelist.IDMapper] interface for *Filter. It returns the
+// rule list data by its synthetic integer ID in the urlfilter engine. It
+// panics if id is not found.
+func (f *Filter) Map(
id int,
) (fltID agd.FilterListID, svcID agd.BlockedServiceID) {
for _, rl := range f.ruleLists {
@@ -326,69 +360,3 @@ func (f *Filter) mustRuleListDataByURLFilterID(
// list filters in the composite filter.
panic(fmt.Errorf("filter: synthetic id %d not found", id))
}
-
-// hostsRulesToResult converts /etc/hosts-style rules into a filtering action.
-func (f *Filter) hostsRulesToResult(
- hostRules4 []*rules.HostRule,
- hostRules6 []*rules.HostRule,
- rrType dnsmsg.RRType,
-) (r internal.Result) {
- if len(hostRules4) == 0 && len(hostRules6) == 0 {
- return nil
- }
-
- // Only use the first matched rule, since we currently don't care about the
- // IP addresses in the rule. If the request is neither an A one nor an AAAA
- // one, or if there are no matching rules of the requested type, then use
- // whatever rule isn't empty.
- //
- // See also AGDNS-591.
- var resHostRule *rules.HostRule
- if rrType == dns.TypeA && len(hostRules4) > 0 {
- resHostRule = hostRules4[0]
- } else if rrType == dns.TypeAAAA && len(hostRules6) > 0 {
- resHostRule = hostRules6[0]
- } else {
- if len(hostRules4) > 0 {
- resHostRule = hostRules4[0]
- } else {
- resHostRule = hostRules6[0]
- }
- }
-
- return f.ruleDataToResult(resHostRule.FilterListID, resHostRule.RuleText, false)
-}
-
-// ruleDataToResult converts a urlfilter rule data into a filtering result.
-func (f *Filter) ruleDataToResult(
- urlFilterID int,
- ruleText string,
- allowlist bool,
-) (r internal.Result) {
- // Use the urlFilterID crutch to find the actual IDs of the filtering rule
- // list and blocked service.
- fltID, svcID := f.mustRuleListDataByURLFilterID(urlFilterID)
-
- var rule agd.FilterRuleText
- if fltID == agd.FilterListIDBlockedService {
- rule = agd.FilterRuleText(svcID)
- } else {
- rule = agd.FilterRuleText(ruleText)
- }
-
- if allowlist {
- optlog.Debug2("rule list %s: allowed by rule %s", fltID, rule)
-
- return &internal.ResultAllowed{
- List: fltID,
- Rule: rule,
- }
- }
-
- optlog.Debug2("rule list %s: blocked by rule %s", fltID, rule)
-
- return &internal.ResultBlocked{
- List: fltID,
- Rule: rule,
- }
-}
diff --git a/internal/filter/internal/composite/composite_internal_test.go b/internal/filter/internal/composite/composite_internal_test.go
index fb097c2..6f3d4a7 100644
--- a/internal/filter/internal/composite/composite_internal_test.go
+++ b/internal/filter/internal/composite/composite_internal_test.go
@@ -18,7 +18,7 @@ var (
resultSink internal.Result
)
-func BenchmarkFilter_FilterWithRuleLists(b *testing.B) {
+func BenchmarkFilter_FilterReqWithRuleLists(b *testing.B) {
blockingRL, err := rulelist.NewFromString(filtertest.BlockRule+"\n", "test", "", 0, false)
require.NoError(b, err)
@@ -38,15 +38,15 @@ func BenchmarkFilter_FilterWithRuleLists(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
- resultSink = f.filterWithRuleLists(ri, filtertest.ReqHost, dns.TypeCNAME, req)
+ for range b.N {
+ resultSink = f.filterReqWithRuleLists(ri, req)
}
- // Most recent results, on a MBP 14 with Apple M1 Pro chip:
+ // Most recent results, on a ThinkPad X13 with a Ryzen Pro 7 CPU:
//
- // goos: darwin
- // goarch: arm64
- // pkg: github.com/AdguardTeam/urlfilter
- // BenchmarkFilter_FilterWithRuleLists
- // BenchmarkFilter_FilterWithRuleLists-8 1623212 698.0 ns/op 161 B/op 6 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_FilterWithRuleLists-16 464508 2449 ns/op 162 B/op 6 allocs/op
}
diff --git a/internal/filter/internal/composite/composite_test.go b/internal/filter/internal/composite/composite_test.go
index e35914a..ec56ec6 100644
--- a/internal/filter/internal/composite/composite_test.go
+++ b/internal/filter/internal/composite/composite_test.go
@@ -16,7 +16,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/filtertest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/safesearch"
- "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
@@ -60,9 +59,9 @@ func newImmutable(tb testing.TB, text string, id agd.FilterListID) (rl *rulelist
// and ri use [filtertest.ReqFQDN], [dns.TypeA], and [dns.ClassINET] for the
// request data.
func newReqData(tb testing.TB) (ctx context.Context, req *dns.Msg, ri *agd.RequestInfo) {
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- tb.Cleanup(cancel)
+ tb.Helper()
+ ctx = testutil.ContextWithTimeout(tb, filtertest.Timeout)
req = dnsservertest.NewReq(filtertest.ReqFQDN, dns.TypeA, dns.ClassINET)
ri = &agd.RequestInfo{
Messages: agdtest.NewConstructor(),
@@ -105,21 +104,14 @@ func TestFilter_nil(t *testing.T) {
}
}
-func TestFilter_FilterRequest_client(t *testing.T) {
+func TestFilter_FilterRequest_customWithClientName(t *testing.T) {
const (
devName = "MyDevice"
blockRule = filtertest.BlockRule + "$client=" + devName
)
- rl := newFromStr(t, blockRule, testFltListID1)
-
- wantRes := &internal.ResultBlocked{
- List: testFltListID1,
- Rule: blockRule,
- }
-
f := composite.New(&composite.Config{
- RuleLists: []*rulelist.Refreshable{rl},
+ Custom: newImmutable(t, blockRule, agd.FilterListIDCustom),
})
ctx, req, ri := newReqData(t)
@@ -135,6 +127,11 @@ func TestFilter_FilterRequest_client(t *testing.T) {
res, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
+ wantRes := &internal.ResultBlocked{
+ List: agd.FilterListIDCustom,
+ Rule: blockRule,
+ }
+
assert.Equal(t, wantRes, res)
}
@@ -216,6 +213,7 @@ func TestFilter_FilterRequest_dnsrewrite(t *testing.T) {
dnsRewriteRuleSOA = filtertest.BlockRule + "$dnsrewrite=NOERROR;SOA;ns1." +
filtertest.ReqFQDN + " hostmaster." + filtertest.ReqFQDN + " 1 3600 1800 604800 86400"
dnsRewriteTypedRules = dnsRewriteRuleTXT + "\n" + dnsRewriteRuleSOA
+ dnsRewriteRulePopup = filtertest.BlockRule + "$dnsrewrite=" + filtertest.PopupBlockPageHost
)
var (
@@ -225,6 +223,7 @@ func TestFilter_FilterRequest_dnsrewrite(t *testing.T) {
rlCustomCname = newImmutable(t, dnsRewriteRuleCname, agd.FilterListIDCustom)
rlCustom2Rules = newImmutable(t, dnsRewrite2Rules, agd.FilterListIDCustom)
rlCustomTyped = newImmutable(t, dnsRewriteTypedRules, agd.FilterListIDCustom)
+ rlPopup = newFromStr(t, dnsRewriteRulePopup, agd.FilterListIDAdGuardPopup)
)
req := dnsservertest.NewReq(filtertest.ReqFQDN, dns.TypeA, dns.ClassINET)
@@ -260,7 +259,7 @@ func TestFilter_FilterRequest_dnsrewrite(t *testing.T) {
}, {
custom: rlCustomRefused,
req: req,
- wantRes: &internal.ResultModified{
+ wantRes: &internal.ResultModifiedResponse{
Msg: dnsservertest.NewResp(dns.RcodeRefused, req),
List: agd.FilterListIDCustom,
Rule: dnsRewriteRuleRefused,
@@ -270,7 +269,7 @@ func TestFilter_FilterRequest_dnsrewrite(t *testing.T) {
}, {
custom: rlCustomCname,
req: req,
- wantRes: &internal.ResultModified{
+ wantRes: &internal.ResultModifiedRequest{
Msg: modifiedReq,
List: agd.FilterListIDCustom,
Rule: dnsRewriteRuleCname,
@@ -280,7 +279,7 @@ func TestFilter_FilterRequest_dnsrewrite(t *testing.T) {
}, {
custom: rlCustom2Rules,
req: req,
- wantRes: &internal.ResultModified{
+ wantRes: &internal.ResultModifiedResponse{
Msg: dnsservertest.NewResp(dns.RcodeSuccess, req, dnsservertest.SectionAnswer{
dnsservertest.NewA(
filtertest.ReqFQDN,
@@ -301,7 +300,7 @@ func TestFilter_FilterRequest_dnsrewrite(t *testing.T) {
}, {
custom: rlCustomTyped,
req: txtReq,
- wantRes: &internal.ResultModified{
+ wantRes: &internal.ResultModifiedResponse{
Msg: dnsservertest.NewResp(dns.RcodeSuccess, txtReq, dnsservertest.SectionAnswer{
dnsservertest.NewTXT(
filtertest.ReqFQDN,
@@ -317,12 +316,22 @@ func TestFilter_FilterRequest_dnsrewrite(t *testing.T) {
}, {
custom: rlCustomTyped,
req: soaReq,
- wantRes: &internal.ResultModified{
+ wantRes: &internal.ResultModifiedResponse{
Msg: dnsservertest.NewResp(dns.RcodeSuccess, soaReq),
List: agd.FilterListIDCustom,
},
name: "dnsrewrite_soa",
ruleLists: []*rulelist.Refreshable{},
+ }, {
+ custom: nil,
+ req: req,
+ wantRes: &internal.ResultModifiedRequest{
+ Msg: dnsservertest.NewReq(filtertest.PopupBlockPageFQDN, dns.TypeA, dns.ClassINET),
+ List: agd.FilterListIDAdGuardPopup,
+ Rule: dnsRewriteRulePopup,
+ },
+ name: "dnsrewrite_popup",
+ ruleLists: []*rulelist.Refreshable{rlPopup},
}}
for _, tc := range testCases {
@@ -342,7 +351,7 @@ func TestFilter_FilterRequest_dnsrewrite(t *testing.T) {
res, fltErr := f.FilterRequest(ctx, tc.req, ri)
require.NoError(t, fltErr)
- assert.Equal(t, tc.wantRes, res)
+ filtertest.AssertEqualResult(t, tc.wantRes, res)
})
}
}
@@ -444,7 +453,6 @@ func TestFilter_FilterRequest_safeSearch(t *testing.T) {
const fltListID = agd.FilterListIDGeneralSafeSearch
gen := safesearch.New(&safesearch.Config{
- Cloner: agdtest.NewCloner(),
Refreshable: &internal.RefreshableConfig{
URL: srvURL,
ID: fltListID,
@@ -453,28 +461,11 @@ func TestFilter_FilterRequest_safeSearch(t *testing.T) {
Timeout: filtertest.Timeout,
MaxSize: filtertest.FilterMaxSize,
},
- Resolver: &agdtest.Resolver{
- OnLookupNetIP: func(
- _ context.Context,
- _ netutil.AddrFamily,
- _ string,
- ) (ips []netip.Addr, err error) {
- return []netip.Addr{safeSearchIP}, nil
- },
- },
- ErrColl: &agdtest.ErrorCollector{
- OnCollect: func(_ context.Context, _ error) {
- panic("not implemented")
- },
- },
CacheTTL: 1 * time.Minute,
CacheSize: 100,
})
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
-
- err := gen.Refresh(ctx, false)
+ err := gen.Refresh(testutil.ContextWithTimeout(t, filtertest.Timeout), false)
require.NoError(t, err)
f := composite.New(&composite.Config{
@@ -488,7 +479,7 @@ func TestFilter_FilterRequest_safeSearch(t *testing.T) {
wantResp := dnsservertest.NewResp(dns.RcodeSuccess, req, dnsservertest.SectionAnswer{
dnsservertest.NewA(filtertest.ReqFQDN, agdtest.FilteredResponseTTLSec, safeSearchIP),
})
- want := &internal.ResultModified{
+ want := &internal.ResultModifiedResponse{
Msg: wantResp,
List: fltListID,
Rule: filtertest.ReqHost,
diff --git a/internal/filter/internal/composite/dnsresult.go b/internal/filter/internal/composite/dnsresult.go
deleted file mode 100644
index 7d4cd27..0000000
--- a/internal/filter/internal/composite/dnsresult.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package composite
-
-import (
- "github.com/AdguardTeam/urlfilter"
- "github.com/AdguardTeam/urlfilter/rules"
-)
-
-// urlFilterResult is an entity simplifying the collection and compilation of
-// urlfilter results.
-//
-// TODO(a.garipov): Think of ways to move all urlfilter result processing to
-// ./internal/rulelist.
-type urlFilterResult struct {
- networkRules []*rules.NetworkRule
- hostRules4 []*rules.HostRule
- hostRules6 []*rules.HostRule
-}
-
-// add appends the rules from dr to the slices within r. If dr is nil, add does
-// nothing.
-func (r *urlFilterResult) add(dr *urlfilter.DNSResult) {
- if dr != nil {
- r.networkRules = append(r.networkRules, dr.NetworkRules...)
- r.hostRules4 = append(r.hostRules4, dr.HostRulesV4...)
- r.hostRules6 = append(r.hostRules6, dr.HostRulesV6...)
- }
-}
diff --git a/internal/filter/internal/custom/custom.go b/internal/filter/internal/custom/custom.go
index 9f1e973..db728a5 100644
--- a/internal/filter/internal/custom/custom.go
+++ b/internal/filter/internal/custom/custom.go
@@ -9,25 +9,24 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
- "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
- "github.com/bluele/gcache"
)
// Filters contains custom filters made from custom filtering rules of profiles.
type Filters struct {
- cache gcache.Cache
+ cache agdcache.Interface[agd.ProfileID, *customFilterCacheItem]
errColl errcoll.Interface
}
// New returns a new custom filter storage.
-func New(cache gcache.Cache, errColl errcoll.Interface) (f *Filters) {
+func New(conf *agdcache.LRUConfig, errColl errcoll.Interface) (f *Filters) {
return &Filters{
- cache: cache,
+ cache: agdcache.NewLRU[agd.ProfileID, *customFilterCacheItem](conf),
errColl: errColl,
}
}
@@ -101,15 +100,11 @@ func (f *Filters) Get(ctx context.Context, p *agd.Profile) (rl *rulelist.Immutab
// get returns the cached custom rule-list filter, if there is one and the
// profile hasn't changed since the filter was cached.
func (f *Filters) get(p *agd.Profile) (rl *rulelist.Immutable) {
- itemVal, err := f.cache.Get(p.ID)
- if errors.Is(err, gcache.KeyNotFoundError) {
+ item, ok := f.cache.Get(p.ID)
+ if !ok {
return nil
- } else if err != nil {
- // Shouldn't happen, since we don't set a serialization function.
- panic(err)
}
- item := itemVal.(*customFilterCacheItem)
if item.updTime.Before(p.UpdateTime) {
return nil
}
@@ -119,16 +114,10 @@ func (f *Filters) get(p *agd.Profile) (rl *rulelist.Immutable) {
// set caches the custom rule-list filter.
func (f *Filters) set(p *agd.Profile, rl *rulelist.Immutable) {
- item := &customFilterCacheItem{
+ f.cache.Set(p.ID, &customFilterCacheItem{
updTime: p.UpdateTime,
ruleList: rl,
- }
-
- err := f.cache.Set(p.ID, item)
- if err != nil {
- // Shouldn't happen, since we don't set a serialization function.
- panic(err)
- }
+ })
}
// customFilterCacheItem is an item of the custom filter cache.
diff --git a/internal/filter/internal/custom/custom_test.go b/internal/filter/internal/custom/custom_test.go
index 136a5c6..55d0600 100644
--- a/internal/filter/internal/custom/custom_test.go
+++ b/internal/filter/internal/custom/custom_test.go
@@ -6,11 +6,11 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/custom"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
"github.com/AdguardTeam/golibs/testutil"
- "github.com/bluele/gcache"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -24,7 +24,9 @@ const testProfID agd.ProfileID = "prof1234"
func TestFilters_Get(t *testing.T) {
f := custom.New(
- gcache.New(1).LRU().Build(),
+ &agdcache.LRUConfig{
+ Size: 1,
+ },
&agdtest.ErrorCollector{
OnCollect: func(ctx context.Context, err error) { panic("not implemented") },
},
@@ -54,7 +56,9 @@ var ruleListSink *rulelist.Immutable
func BenchmarkFilters_Get(b *testing.B) {
f := custom.New(
- gcache.New(1).LRU().Build(),
+ &agdcache.LRUConfig{
+ Size: 1,
+ },
&agdtest.ErrorCollector{
OnCollect: func(ctx context.Context, err error) { panic("not implemented") },
},
@@ -75,7 +79,7 @@ func BenchmarkFilters_Get(b *testing.B) {
b.Run("cache", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
ruleListSink = f.Get(ctx, p)
}
})
@@ -83,7 +87,7 @@ func BenchmarkFilters_Get(b *testing.B) {
b.Run("no_cache", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
// Update the time on each iteration to make sure that the cache is
// never used.
p.UpdateTime = p.UpdateTime.Add(1 * time.Millisecond)
diff --git a/internal/filter/internal/filtertest/filtertest.go b/internal/filter/internal/filtertest/filtertest.go
index 76d9789..37db06e 100644
--- a/internal/filter/internal/filtertest/filtertest.go
+++ b/internal/filter/internal/filtertest/filtertest.go
@@ -14,9 +14,12 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/testutil"
"github.com/c2h5oh/datasize"
+ "github.com/miekg/dns"
+ "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -24,14 +27,34 @@ import (
// [ReqHost].
const BlockRule = "|" + ReqHost + "^"
+// Common string representations of IP adddresses.
+const (
+ SafeBrowsingReplIPv4Str = "192.0.2.1"
+ PopupReplIPv4Str = "192.0.2.3"
+)
+
+// Common IP addresses for tests.
+var (
+ SafeBrowsingReplIPv4 = netip.MustParseAddr(SafeBrowsingReplIPv4Str)
+ PopupReplIPv4 = netip.MustParseAddr(PopupReplIPv4Str)
+)
+
// RemoteIP is the common client IP for filtering tests
var RemoteIP = netip.MustParseAddr("1.2.3.4")
-// ReqHost is the common request host for filtering tests.
-const ReqHost = "www.host.example"
+const (
+ // ReqHost is the common request host for filtering tests.
+ ReqHost = "www.host.example"
-// ReqFQDN is the common request FQDN for filtering tests.
-const ReqFQDN = ReqHost + "."
+ // ReqFQDN is the FQDN version of ReqHost.
+ ReqFQDN = ReqHost + "."
+
+ // PopupBlockPageHost is the common popup block-page host for tests.
+ PopupBlockPageHost = "ad-block.adguard.example"
+
+ // PopupBlockPageFQDN is the FQDN version of PopupBlockPageHost.
+ PopupBlockPageFQDN = PopupBlockPageHost + "."
+)
// ServerName is the common server name for filtering tests.
const ServerName = "testServer/1.0"
@@ -49,6 +72,42 @@ const Timeout = 1 * time.Second
// tests.
const FilterMaxSize = 640 * uint64(datasize.KB)
+// AssertEqualResult is a test helper that compares two results taking
+// [internal.ResultModifiedRequest] and its difference in IDs into account.
+func AssertEqualResult(tb testing.TB, want, got internal.Result) (ok bool) {
+ tb.Helper()
+
+ wantRM, ok := want.(*internal.ResultModifiedRequest)
+ if !ok {
+ return assert.Equal(tb, want, got)
+ }
+
+ gotRM := testutil.RequireTypeAssert[*internal.ResultModifiedRequest](tb, got)
+
+ return assert.Equal(tb, wantRM.List, gotRM.List) &&
+ assert.Equal(tb, wantRM.Rule, gotRM.Rule) &&
+ assertEqualRequests(tb, wantRM.Msg, gotRM.Msg)
+}
+
+// assertEqualRequests is a test helper that compares two DNS requests ignoring
+// the ID.
+//
+// TODO(a.garipov): Move to golibs?
+func assertEqualRequests(tb testing.TB, want, got *dns.Msg) (ok bool) {
+ tb.Helper()
+
+ if want == nil {
+ return assert.Nil(tb, got)
+ }
+
+ // Use a shallow clone, because this should be enough to fix the ID.
+ gotWithID := &dns.Msg{}
+ *gotWithID = *got
+ gotWithID.Id = want.Id
+
+ return assert.Equal(tb, want, gotWithID)
+}
+
// PrepareRefreshable launches an HTTP server serving the given text and code,
// as well as creates a cache file. If code is zero, the server isn't started.
// If reqCh not nil, a signal is sent every time the server is called. The
diff --git a/internal/filter/internal/internal.go b/internal/filter/internal/internal.go
index 9549afe..89d8f5a 100644
--- a/internal/filter/internal/internal.go
+++ b/internal/filter/internal/internal.go
@@ -23,10 +23,6 @@ type Interface interface {
FilterResponse(ctx context.Context, resp *dns.Msg, ri *agd.RequestInfo) (r Result, err error)
}
-// DefaultFilterRefreshTimeout is the default timeout to use when fetching
-// filter lists data.
-const DefaultFilterRefreshTimeout = 3 * time.Minute
-
// DefaultResolveTimeout is the default timeout for resolving hosts for
// safe-search and safe-browsing filters.
//
diff --git a/internal/filter/internal/refreshable_test.go b/internal/filter/internal/refreshable_test.go
index c453d9f..4eacb57 100644
--- a/internal/filter/internal/refreshable_test.go
+++ b/internal/filter/internal/refreshable_test.go
@@ -1,7 +1,6 @@
package internal_test
import (
- "context"
"net/http"
"os"
"path/filepath"
@@ -118,9 +117,7 @@ func TestRefreshable_Refresh(t *testing.T) {
f := internal.NewRefreshable(c)
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
-
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
gotText, err := f.Refresh(ctx, tc.acceptStale)
if tc.expectReq {
testutil.RequireReceive(t, reqCh, filtertest.Timeout)
@@ -171,11 +168,9 @@ func TestRefreshable_Refresh_properStaleness(t *testing.T) {
f := internal.NewRefreshable(c)
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
-
var err error
var now time.Time
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
go func() {
<-reqCh
now = time.Now()
diff --git a/internal/filter/internal/result.go b/internal/filter/internal/result.go
index 08edf2e..ecfef17 100644
--- a/internal/filter/internal/result.go
+++ b/internal/filter/internal/result.go
@@ -13,7 +13,8 @@ import (
//
// - [*ResultAllowed]
// - [*ResultBlocked]
-// - [*ResultModified]
+// - [*ResultModifiedResponse]
+// - [*ResultModifiedRequest]
type Result interface {
// MatchedRule returns data about the matched rule and its rule list.
MatchedRule() (id agd.FilterListID, text agd.FilterRuleText)
@@ -32,12 +33,12 @@ type ResultAllowed struct {
// type check
var _ Result = (*ResultAllowed)(nil)
-// MatchedRule implements the Result interface for *ResultAllowed.
+// MatchedRule implements the [Result] interface for *ResultAllowed.
func (a *ResultAllowed) MatchedRule() (id agd.FilterListID, text agd.FilterRuleText) {
return a.List, a.Rule
}
-// isResult implements the Result interface for *ResultAllowed.
+// isResult implements the [Result] interface for *ResultAllowed.
func (*ResultAllowed) isResult() {}
// ResultBlocked means that this request or response was blocked by a blocklist
@@ -50,18 +51,18 @@ type ResultBlocked struct {
// type check
var _ Result = (*ResultBlocked)(nil)
-// MatchedRule implements the Result interface for *ResultBlocked.
+// MatchedRule implements the [Result] interface for *ResultBlocked.
func (b *ResultBlocked) MatchedRule() (id agd.FilterListID, text agd.FilterRuleText) {
return b.List, b.Rule
}
-// isResult implements the Result interface for *ResultBlocked.
+// isResult implements the [Result] interface for *ResultBlocked.
func (*ResultBlocked) isResult() {}
-// ResultModified means that this request or response was rewritten or modified
-// by a rewrite rule within the given filter list.
-type ResultModified struct {
- // Msg is the new, rewritten or modified request or response.
+// ResultModifiedResponse means that this response was rewritten or modified by
+// a rewrite rule within the given filter list.
+type ResultModifiedResponse struct {
+ // Msg is the new, rewritten or modified response.
Msg *dns.Msg
// List is the ID of the filter list.
@@ -72,21 +73,21 @@ type ResultModified struct {
}
// type check
-var _ Result = (*ResultModified)(nil)
+var _ Result = (*ResultModifiedResponse)(nil)
-// MatchedRule implements the Result interface for *ResultModified.
-func (m *ResultModified) MatchedRule() (id agd.FilterListID, text agd.FilterRuleText) {
+// MatchedRule implements the [Result] interface for *ResultModifiedResponse.
+func (m *ResultModifiedResponse) MatchedRule() (id agd.FilterListID, text agd.FilterRuleText) {
return m.List, m.Rule
}
-// isResult implements the Result interface for *ResultModified.
-func (*ResultModified) isResult() {}
+// isResult implements the [Result] interface for *ResultModifiedResponse.
+func (*ResultModifiedResponse) isResult() {}
// Clone returns a deep clone of m.
-func (m *ResultModified) Clone(c *dnsmsg.Cloner) (clone *ResultModified) {
+func (m *ResultModifiedResponse) Clone(c *dnsmsg.Cloner) (clone *ResultModifiedResponse) {
msg := c.Clone(m.Msg)
- return &ResultModified{
+ return &ResultModifiedResponse{
Msg: msg,
List: m.List,
Rule: m.Rule,
@@ -94,7 +95,10 @@ func (m *ResultModified) Clone(c *dnsmsg.Cloner) (clone *ResultModified) {
}
// CloneForReq returns a deep clone of m with Msg set as a reply to req, if any.
-func (m *ResultModified) CloneForReq(c *dnsmsg.Cloner, req *dns.Msg) (clone *ResultModified) {
+func (m *ResultModifiedResponse) CloneForReq(
+ c *dnsmsg.Cloner,
+ req *dns.Msg,
+) (clone *ResultModifiedResponse) {
msg := c.Clone(m.Msg)
// TODO(a.garipov): This will become invalid if Msg ever contains a
@@ -102,7 +106,43 @@ func (m *ResultModified) CloneForReq(c *dnsmsg.Cloner, req *dns.Msg) (clone *Res
// find a better way to cache as much of the response as possible.
msg.SetReply(req)
- return &ResultModified{
+ return &ResultModifiedResponse{
+ Msg: msg,
+ List: m.List,
+ Rule: m.Rule,
+ }
+}
+
+// ResultModifiedRequest means that this request was rewritten or modified by a
+// rewrite rule within the given filter list.
+type ResultModifiedRequest struct {
+ // Msg is the new, rewritten or modified request.
+ Msg *dns.Msg
+
+ // List is the ID of the filter list.
+ List agd.FilterListID
+
+ // Rule is the filtering rule that triggered the rewrite.
+ Rule agd.FilterRuleText
+}
+
+// type check
+var _ Result = (*ResultModifiedRequest)(nil)
+
+// MatchedRule implements the [Result] interface for *ResultModifiedRequest.
+func (m *ResultModifiedRequest) MatchedRule() (id agd.FilterListID, text agd.FilterRuleText) {
+ return m.List, m.Rule
+}
+
+// isResult implements the [Result] interface for *ResultModifiedRequest.
+func (*ResultModifiedRequest) isResult() {}
+
+// Clone returns a deep clone of m with a new ID.
+func (m *ResultModifiedRequest) Clone(c *dnsmsg.Cloner) (clone *ResultModifiedRequest) {
+ msg := c.Clone(m.Msg)
+ msg.Id = dns.Id()
+
+ return &ResultModifiedRequest{
Msg: msg,
List: m.List,
Rule: m.Rule,
diff --git a/internal/filter/internal/resultcache/resultcache.go b/internal/filter/internal/resultcache/resultcache.go
deleted file mode 100644
index ea4b4d9..0000000
--- a/internal/filter/internal/resultcache/resultcache.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// Package resultcache contains a cache for filtering results.
-package resultcache
-
-import (
- "encoding/binary"
- "fmt"
- "hash/maphash"
-
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
- "github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/mathutil"
- "github.com/bluele/gcache"
-)
-
-// Cache is a wrapper around [gcache.Cache] to simplify rare error handling.
-type Cache[T any] struct {
- // TODO(a.garipov): This cache should actually be an LRU + expiration cache,
- // but all current implementations are suboptimal. See AGDNS-398.
- cache gcache.Cache
-}
-
-// New returns a new LRU result cache with the given size.
-func New[T any](size int) (c *Cache[T]) {
- return &Cache[T]{
- cache: gcache.New(size).LRU().Build(),
- }
-}
-
-// Clear clears the cache. If c is nil, nothing is done.
-func (c *Cache[T]) Clear() {
- if c != nil {
- c.cache.Purge()
- }
-}
-
-// Key is the type of result cache keys.
-type Key uint64
-
-// Get returns the cached result, if any. If c is nil, Get returns a zero T and
-// false.
-func (c *Cache[T]) Get(k Key) (r T, ok bool) {
- if c == nil {
- return r, false
- }
-
- v, err := c.cache.Get(k)
- if err != nil {
- if !errors.Is(err, gcache.KeyNotFoundError) {
- // Shouldn't happen, since we don't set a serialization function.
- panic(fmt.Errorf("resultcache: getting cache item: %w", err))
- }
-
- return r, false
- }
-
- return v.(T), true
-}
-
-// ItemCount returns the number of items in the cache. This may include items
-// that have expired, but have not yet been cleaned up. If c is nil, ItemCount
-// returns 0.
-func (c *Cache[T]) ItemCount() (n int) {
- if c == nil {
- return 0
- }
-
- return c.cache.Len(false)
-}
-
-// Set sets the cached result. If c is nil, nothing is done.
-func (c *Cache[T]) Set(k Key, r T) {
- if c != nil {
- err := c.cache.Set(k, r)
- if err != nil {
- // Shouldn't happen, since we don't set a serialization function.
- panic(fmt.Errorf("resultcache: setting cache item: %w", err))
- }
- }
-}
-
-// hashSeed is the seed used by all hashes to create hash keys.
-var hashSeed = maphash.MakeSeed()
-
-// DefaultKey produces a cache key based on host, qt, and isAns using the
-// default algorithm.
-func DefaultKey(host string, qt dnsmsg.RRType, cl dnsmsg.Class, isAns bool) (k Key) {
- // 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 Key(h.Sum64())
-}
diff --git a/internal/filter/internal/resultcache/resultcache_test.go b/internal/filter/internal/resultcache/resultcache_test.go
deleted file mode 100644
index aaa0190..0000000
--- a/internal/filter/internal/resultcache/resultcache_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package resultcache_test
-
-import (
- "testing"
-
- "github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/resultcache"
- "github.com/miekg/dns"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-// Common keys for tests.
-var (
- testKey = resultcache.DefaultKey("example.com", dns.TypeA, dns.ClassINET, true)
- otherKey = resultcache.DefaultKey("example.org", dns.TypeAAAA, dns.ClassINET, false)
-)
-
-// val is the common value for tests.
-const val = 123
-
-func TestCache(t *testing.T) {
- c := resultcache.New[int](100)
-
- c.Set(testKey, val)
-
- n := c.ItemCount()
- assert.Equal(t, n, 1)
-
- res, ok := c.Get(testKey)
- assert.Equal(t, res, val)
- assert.True(t, ok)
-
- res, ok = c.Get(otherKey)
- assert.Equal(t, res, 0)
- assert.False(t, ok)
-
- c.Clear()
-
- n = c.ItemCount()
- assert.Equal(t, n, 0)
-}
-
-func TestCache_nil(t *testing.T) {
- require.NotPanics(t, func() {
- var c *resultcache.Cache[int]
- c.Set(testKey, val)
-
- n := c.ItemCount()
- assert.Equal(t, n, 0)
-
- res, ok := c.Get(testKey)
- assert.Equal(t, res, 0)
- assert.False(t, ok)
-
- c.Clear()
- })
-}
diff --git a/internal/filter/internal/composite/dnsrewrite.go b/internal/filter/internal/rulelist/dnsrewrite.go
similarity index 93%
rename from internal/filter/internal/composite/dnsrewrite.go
rename to internal/filter/internal/rulelist/dnsrewrite.go
index ddaab3d..bef009f 100644
--- a/internal/filter/internal/composite/dnsrewrite.go
+++ b/internal/filter/internal/rulelist/dnsrewrite.go
@@ -1,4 +1,4 @@
-package composite
+package rulelist
import (
"fmt"
@@ -14,15 +14,16 @@ import (
"github.com/miekg/dns"
)
-// processDNSRewrites processes $dnsrewrite rules dnsr and creates a filtering
-// result, if necessary. res.List, if any, is set to [agd.FilterListIDCustom].
-func processDNSRewrites(
+// ProcessDNSRewrites processes $dnsrewrite rules dnsr and creates a filtering
+// result, if id allows it. res.List, if any, is set to id.
+func ProcessDNSRewrites(
messages *dnsmsg.Constructor,
req *dns.Msg,
dnsr []*rules.NetworkRule,
host string,
-) (res *internal.ResultModified) {
- if len(dnsr) == 0 {
+ id agd.FilterListID,
+) (res internal.Result) {
+ if len(dnsr) == 0 || !id.SupportsDNSRewrite() {
return nil
}
@@ -38,9 +39,9 @@ func processDNSRewrites(
req = dnsmsg.Clone(req)
req.Question[0].Name = dns.Fqdn(resCanonName)
- return &internal.ResultModified{
+ return &internal.ResultModifiedRequest{
Msg: req,
- List: agd.FilterListIDCustom,
+ List: id,
Rule: dnsRewriteResult.ResRuleText,
}
}
@@ -49,9 +50,9 @@ func processDNSRewrites(
resp := messages.NewRespMsg(req)
resp.Rcode = dnsRewriteResult.RCode
- return &internal.ResultModified{
+ return &internal.ResultModifiedResponse{
Msg: resp,
- List: agd.FilterListIDCustom,
+ List: id,
Rule: dnsRewriteResult.ResRuleText,
}
}
@@ -61,9 +62,9 @@ func processDNSRewrites(
return nil
}
- return &internal.ResultModified{
+ return &internal.ResultModifiedResponse{
Msg: resp,
- List: agd.FilterListIDCustom,
+ List: id,
}
}
diff --git a/internal/filter/internal/rulelist/refreshable.go b/internal/filter/internal/rulelist/refreshable.go
index 625ff24..8196845 100644
--- a/internal/filter/internal/rulelist/refreshable.go
+++ b/internal/filter/internal/rulelist/refreshable.go
@@ -45,9 +45,8 @@ func NewRefreshable(
ID: c.ID,
CachePath: c.CachePath,
Staleness: c.Staleness,
- // TODO(ameshkov): Consider making configurable.
- Timeout: internal.DefaultFilterRefreshTimeout,
- MaxSize: c.MaxSize,
+ Timeout: c.Timeout,
+ MaxSize: c.MaxSize,
}),
}
@@ -119,13 +118,14 @@ func (f *Refreshable) Refresh(ctx context.Context, acceptStale bool) (err error)
s, err := filterlist.NewRuleStorage([]filterlist.RuleList{strList})
if err != nil {
- return fmt.Errorf("creating rule storage: %w", err)
+ return fmt.Errorf("%s: creating rule storage: %w", f.id, err)
}
f.mu.Lock()
defer f.mu.Unlock()
f.cache.Clear()
+
f.engine = urlfilter.NewDNSEngine(s)
log.Info("%s: reset %d rules", f.id, f.engine.RulesCount)
diff --git a/internal/filter/internal/rulelist/refreshable_test.go b/internal/filter/internal/rulelist/refreshable_test.go
index 93ceff8..6acf38f 100644
--- a/internal/filter/internal/rulelist/refreshable_test.go
+++ b/internal/filter/internal/rulelist/refreshable_test.go
@@ -1,7 +1,6 @@
package rulelist_test
import (
- "context"
"net/http"
"net/netip"
"testing"
@@ -92,9 +91,7 @@ func TestRefreshable_Refresh(t *testing.T) {
true,
)
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
-
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
err := rl.Refresh(ctx, false)
require.NoError(t, err)
diff --git a/internal/filter/internal/rulelist/result.go b/internal/filter/internal/rulelist/result.go
new file mode 100644
index 0000000..79b68ea
--- /dev/null
+++ b/internal/filter/internal/rulelist/result.go
@@ -0,0 +1,95 @@
+package rulelist
+
+import (
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
+ "github.com/AdguardTeam/urlfilter"
+ "github.com/AdguardTeam/urlfilter/rules"
+ "github.com/miekg/dns"
+)
+
+// URLFilterResult is an entity simplifying the collection and compilation of
+// urlfilter results.
+type URLFilterResult struct {
+ networkRules []*rules.NetworkRule
+ hostRules4 []*rules.HostRule
+ hostRules6 []*rules.HostRule
+}
+
+// Add appends the rules from dr to the slices within r. If dr is nil, Add does
+// nothing.
+func (r *URLFilterResult) Add(dr *urlfilter.DNSResult) {
+ if dr != nil {
+ r.networkRules = append(r.networkRules, dr.NetworkRules...)
+ r.hostRules4 = append(r.hostRules4, dr.HostRulesV4...)
+ r.hostRules6 = append(r.hostRules6, dr.HostRulesV6...)
+ }
+}
+
+// ToInternal converts a result of using several urlfilter rulelists into an
+// internal.Result.
+func (r *URLFilterResult) ToInternal(m IDMapper, rrType dnsmsg.RRType) (res internal.Result) {
+ if nr := rules.GetDNSBasicRule(r.networkRules); nr != nil {
+ return ruleDataToResult(m, nr.FilterListID, nr.RuleText, nr.Whitelist)
+ }
+
+ return r.hostsRulesToResult(m, rrType)
+}
+
+// IDMapper maps an internal urlfilter ID to AdGuard DNS IDs.
+type IDMapper interface {
+ Map(ufID int) (id agd.FilterListID, svcID agd.BlockedServiceID)
+}
+
+// hostsRulesToResult converts /etc/hosts-style rules into a filtering result.
+func (r *URLFilterResult) hostsRulesToResult(m IDMapper, rrType dnsmsg.RRType) (res internal.Result) {
+ if len(r.hostRules4) == 0 && len(r.hostRules6) == 0 {
+ return nil
+ }
+
+ // Only use the first matched rule, since we currently don't care about the
+ // IP addresses in the rule. If the request is neither an A one nor an AAAA
+ // one, or if there are no matching rules of the requested type, then use
+ // whatever rule isn't empty.
+ //
+ // 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]
+ } else {
+ if len(r.hostRules4) > 0 {
+ resHostRule = r.hostRules4[0]
+ } else {
+ resHostRule = r.hostRules6[0]
+ }
+ }
+
+ return ruleDataToResult(m, resHostRule.FilterListID, resHostRule.RuleText, false)
+}
+
+// ruleDataToResult converts a urlfilter rule data into a filtering result.
+func ruleDataToResult(m IDMapper, ufID int, ruleText string, isAllowlist bool) (r internal.Result) {
+ fltID, svcID := m.Map(ufID)
+
+ var rule agd.FilterRuleText
+ if fltID == agd.FilterListIDBlockedService {
+ rule = agd.FilterRuleText(svcID)
+ } else {
+ rule = agd.FilterRuleText(ruleText)
+ }
+
+ if isAllowlist {
+ return &internal.ResultAllowed{
+ List: fltID,
+ Rule: rule,
+ }
+ }
+
+ return &internal.ResultBlocked{
+ List: fltID,
+ Rule: rule,
+ }
+}
diff --git a/internal/filter/internal/rulelist/rulelist.go b/internal/filter/internal/rulelist/rulelist.go
index 0fdf18a..3302d38 100644
--- a/internal/filter/internal/rulelist/rulelist.go
+++ b/internal/filter/internal/rulelist/rulelist.go
@@ -8,8 +8,10 @@ import (
"net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
- "github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/resultcache"
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
+ "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist"
"github.com/miekg/dns"
@@ -28,6 +30,47 @@ func newURLFilterID() (id int) {
return int(rand.Int31())
}
+type (
+ // resultCache is a convenient alias for cache to keep types in check.
+ resultCache = agdcache.Interface[internal.CacheKey, *cacheItem]
+
+ // resultCacheEmpty is a convenient alias for empty cache to keep types in
+ // check. See [filter.DNSResult].
+ resultCacheEmpty = agdcache.Empty[internal.CacheKey, *cacheItem]
+)
+
+// cacheItem represents an item that we will store in the cache.
+type cacheItem struct {
+ // res is the DNS filtering result.
+ res *urlfilter.DNSResult
+
+ // host is the cached normalized hostname for later cache key collision
+ // checks.
+ host string
+}
+
+// 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 internal.CacheKey,
+ host string,
+) (item *cacheItem, ok bool) {
+ item, ok = cache.Get(key)
+ if !ok {
+ return nil, false
+ }
+
+ if item.host != host {
+ optlog.Error2("rulelist: collision: bad cache item %v for host %q", item, host)
+
+ return nil, false
+ }
+
+ return item, true
+}
+
// filter is the basic rule-list filter that doesn't refresh or change in any
// other way.
type filter struct {
@@ -41,7 +84,7 @@ type filter struct {
// cache contains cached results of filtering.
//
// TODO(ameshkov): Add metrics for these caches.
- cache *resultcache.Cache[*urlfilter.DNSResult]
+ cache resultCache
// id is the filter list ID, if any.
id agd.FilterListID
@@ -72,7 +115,11 @@ func newFilter(
}
if useMemCache {
- f.cache = resultcache.New[*urlfilter.DNSResult](memCacheSize)
+ f.cache = agdcache.NewLRU[internal.CacheKey, *cacheItem](&agdcache.LRUConfig{
+ Size: memCacheSize,
+ })
+ } else {
+ f.cache = resultCacheEmpty{}
}
// TODO(a.garipov): Add filterlist.BytesRuleList.
@@ -102,17 +149,18 @@ func (f *filter) DNSResult(
isAns bool,
) (res *urlfilter.DNSResult) {
var ok bool
- var cacheKey resultcache.Key
+ var cacheKey internal.CacheKey
+ var item *cacheItem
// Don't waste resources on computing the cache key if the cache is not
// enabled.
- useCache := f.cache != nil
- if useCache {
+ _, emptyCache := f.cache.(resultCacheEmpty)
+ if !emptyCache {
// TODO(a.garipov): Add real class here.
- cacheKey = resultcache.DefaultKey(host, rrType, dns.ClassINET, isAns)
- res, ok = f.cache.Get(cacheKey)
+ cacheKey = internal.NewCacheKey(host, rrType, dns.ClassINET, isAns)
+ item, ok = itemFromCache(f.cache, cacheKey, host)
if ok {
- return res
+ return item.res
}
}
@@ -129,9 +177,10 @@ func (f *filter) DNSResult(
res = nil
}
- if useCache {
- f.cache.Set(cacheKey, res)
- }
+ f.cache.Set(cacheKey, &cacheItem{
+ res: res,
+ host: host,
+ })
return res
}
diff --git a/internal/filter/internal/safesearch/safesearch.go b/internal/filter/internal/safesearch/safesearch.go
index 6a4e786..0dc055f 100644
--- a/internal/filter/internal/safesearch/safesearch.go
+++ b/internal/filter/internal/safesearch/safesearch.go
@@ -5,47 +5,26 @@ package safesearch
import (
"context"
"fmt"
- "net/netip"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
- "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
- "github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/resultcache"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
- "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
- "github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
)
// Filter modifies the results of queries to search-engine addresses and
// rewrites them to the IP addresses of their safe versions.
type Filter struct {
- cloner *dnsmsg.Cloner
- resCache *resultcache.Cache[*internal.ResultModified]
- flt *rulelist.Refreshable
- resolver agdnet.Resolver
- errColl errcoll.Interface
- id agd.FilterListID
+ flt *rulelist.Refreshable
}
// Config contains configuration for the safe-search filter.
type Config struct {
- // Cloner is used to clone messages taken from filtering-result cache.
- Cloner *dnsmsg.Cloner
-
// Refreshable is the configuration of the refreshable filter-list within
// the safe-search filter.
Refreshable *internal.RefreshableConfig
- // Resolver is used to resolve the IP addresses of replacement hosts.
- Resolver agdnet.Resolver
-
- // ErrColl is used to report errors of replacement-host resolving.
- ErrColl errcoll.Interface
-
// CacheTTL is the time to live of the result cache-items.
//
//lint:ignore U1000 TODO(a.garipov): Currently unused. See AGDNS-398.
@@ -59,13 +38,7 @@ type Config struct {
// refresh should be called explicitly if necessary.
func New(c *Config) (f *Filter) {
return &Filter{
- cloner: c.Cloner,
- resCache: resultcache.New[*internal.ResultModified](c.CacheSize),
- // Don't use the rule list cache, since safeSearch already has its own.
- flt: rulelist.NewRefreshable(c.Refreshable, 0, false),
- resolver: c.Resolver,
- errColl: c.ErrColl,
- id: c.Refreshable.ID,
+ flt: rulelist.NewRefreshable(c.Refreshable, c.CacheSize, true),
}
}
@@ -80,136 +53,49 @@ func (f *Filter) FilterRequest(
ri *agd.RequestInfo,
) (r internal.Result, err error) {
qt := ri.QType
- fam := netutil.AddrFamilyFromRRType(qt)
- if fam == netutil.AddrFamilyNone {
+ switch qt {
+ case dns.TypeA, dns.TypeAAAA, dns.TypeHTTPS:
+ // Go on.
+ default:
return nil, nil
}
host := ri.Host
- cacheKey := resultcache.DefaultKey(host, qt, ri.QClass, false)
- rm, ok := f.resCache.Get(cacheKey)
- if ok {
- if rm == nil {
- // Return nil explicitly instead of modifying CloneForReq to return
- // nil if the result is nil to avoid a “non-nil nil” value.
- return nil, nil
- }
+ dr := f.flt.DNSResult(ri.RemoteIP, "", host, qt, false)
+ id, _ := f.flt.ID()
- return rm.CloneForReq(f.cloner, req), nil
+ r = rulelist.ProcessDNSRewrites(ri.Messages, req, dr.DNSRewrites(), host, id)
+
+ replaceRule(r, host)
+
+ return r, nil
+}
+
+// replaceRule replaces the r.Rule with host if r is not nil. r must be nil,
+// [*internal.ResultModifiedRequest], or [*internal.ResultModifiedResponse].
+func replaceRule(r internal.Result, host string) {
+ rule := agd.FilterRuleText(host)
+ switch r := r.(type) {
+ case nil:
+ // Do nothing.
+ case *internal.ResultModifiedRequest:
+ r.Rule = rule
+ case *internal.ResultModifiedResponse:
+ r.Rule = rule
+ default:
+ panic(fmt.Errorf("safesearch: unexpected type for result: %T(%[1]v)", r))
}
-
- repHost, ip, ok := f.safeSearchHost(host, qt)
- if !ok {
- optlog.Debug2("filter %s: host %q is not on the list", f.id, host)
-
- f.resCache.Set(cacheKey, nil)
-
- return nil, nil
- }
-
- result, err := f.newRespMsg(ctx, req, fam, ri, ip, repHost)
- if err != nil {
- return nil, fmt.Errorf("filter %s: creating modified result: %w", f.id, err)
- }
-
- rm = &internal.ResultModified{
- Msg: result,
- List: f.id,
- Rule: agd.FilterRuleText(host),
- }
-
- // Copy the result to make sure that modifications to the result message
- // down the pipeline don't interfere with the cached value.
- //
- // See AGDNS-359.
- f.resCache.Set(cacheKey, rm.Clone(f.cloner))
-
- return rm, nil
}
// ID implements the [internal.RequestFilter] interface for *Filter.
func (f *Filter) ID() (id agd.FilterListID) {
- return f.id
-}
+ id, _ = f.flt.ID()
-// newRespMsg returns a response messages for provided ip and host.
-func (f *Filter) newRespMsg(
- ctx context.Context,
- req *dns.Msg,
- fam netutil.AddrFamily,
- ri *agd.RequestInfo,
- ip netip.Addr,
- cname string,
-) (msg *dns.Msg, err error) {
- host := cname
- if ip != (netip.Addr{}) {
- // TODO(d.kolyshev): There is no need to resolve this IP if it matches
- // question fam.
- host = ip.String()
- }
-
- optlog.Debug2("filter %s: found host %q", f.id, host)
-
- ctx, cancel := context.WithTimeout(ctx, internal.DefaultResolveTimeout)
- defer cancel()
-
- ips, err := f.resolver.LookupNetIP(ctx, fam, host)
- if err != nil {
- errcoll.Collectf(ctx, f.errColl, "filter %s: resolving: %w", f.id, err)
-
- return ri.Messages.NewMsgSERVFAIL(req), nil
- }
-
- if cname != "" {
- return ri.Messages.NewCNAMEWithIPs(req, dns.Fqdn(cname), ips...)
- }
-
- return ri.Messages.NewIPRespMsg(req, ips...)
-}
-
-// safeSearchHost returns the replacement host for the given host and question
-// type, if any. qt should be either [dns.TypeA] or [dns.TypeAAAA].
-func (f *Filter) safeSearchHost(
- host string,
- qt dnsmsg.RRType,
-) (ssHost string, ip netip.Addr, ok bool) {
- dr := f.flt.DNSResult(netip.Addr{}, "", host, qt, false)
- if dr == nil {
- return "", netip.Addr{}, false
- }
-
- for _, nr := range dr.DNSRewrites() {
- drw := nr.DNSRewrite
- if drw.RCode != dns.RcodeSuccess {
- continue
- }
-
- if nc := drw.NewCNAME; nc != "" {
- return nc, netip.Addr{}, true
- }
-
- // All the rules in safe search rule lists are expected to have either
- // A/AAAA or CNAME type.
- switch drw.RRType {
- case dns.TypeA, dns.TypeAAAA:
- return "", drw.Value.(netip.Addr), true
- default:
- continue
- }
- }
-
- return "", netip.Addr{}, false
+ return id
}
// Refresh reloads the rule list data. If acceptStale is true, and the cache
// file exists, the data is read from there regardless of its staleness.
func (f *Filter) Refresh(ctx context.Context, acceptStale bool) (err error) {
- err = f.flt.Refresh(ctx, acceptStale)
- if err != nil {
- return err
- }
-
- f.resCache.Clear()
-
- return nil
+ return f.flt.Refresh(ctx, acceptStale)
}
diff --git a/internal/filter/internal/safesearch/safesearch_test.go b/internal/filter/internal/safesearch/safesearch_test.go
index 6e5f821..44688bf 100644
--- a/internal/filter/internal/safesearch/safesearch_test.go
+++ b/internal/filter/internal/safesearch/safesearch_test.go
@@ -1,11 +1,9 @@
package safesearch_test
import (
- "context"
"net"
"net/http"
"net/netip"
- "path/filepath"
"testing"
"time"
@@ -16,8 +14,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/filtertest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/safesearch"
- "github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
@@ -36,10 +32,6 @@ const testSafeIPStr = "1.2.3.4"
// search-engine-ip.example.
var testIPOfEngineWithIP = netip.MustParseAddr(testSafeIPStr)
-// testIPOfEngineWithDomain is the IP address of the safe version of
-// search-engine-domain.example.
-var testIPOfEngineWithDomain = netip.MustParseAddr("1.2.3.5")
-
// Common domain names for tests.
const (
testOther = "other.example"
@@ -56,91 +48,57 @@ func TestFilter(t *testing.T) {
reqCh := make(chan struct{}, 1)
cachePath, srvURL := filtertest.PrepareRefreshable(t, reqCh, testFilterRules, http.StatusOK)
- id, err := agd.NewFilterListID(filepath.Base(cachePath))
- require.NoError(t, err)
-
f := safesearch.New(&safesearch.Config{
- Cloner: agdtest.NewCloner(),
Refreshable: &internal.RefreshableConfig{
- ID: id,
+ ID: agd.FilterListIDGeneralSafeSearch,
URL: srvURL,
CachePath: cachePath,
Staleness: filtertest.Staleness,
Timeout: filtertest.Timeout,
MaxSize: filtertest.FilterMaxSize,
},
- Resolver: &agdtest.Resolver{
- OnLookupNetIP: func(
- _ context.Context,
- _ netutil.AddrFamily,
- host string,
- ) (ips []netip.Addr, err error) {
- switch host {
- case testSafeIPStr:
- return []netip.Addr{testIPOfEngineWithIP}, nil
- case testSafeDomain:
- return []netip.Addr{testIPOfEngineWithDomain}, nil
- default:
- return nil, errors.Error("test resolver error")
- }
- },
- },
- ErrColl: &agdtest.ErrorCollector{
- OnCollect: func(ctx context.Context, err error) {
- panic("not implemented")
- },
- },
CacheTTL: 1 * time.Minute,
CacheSize: 100,
})
- refrCtx, refrCancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(refrCancel)
-
- err = f.Refresh(refrCtx, true)
- require.NoError(t, err)
+ refrErr := f.Refresh(testutil.ContextWithTimeout(t, filtertest.Timeout), true)
+ require.NoError(t, refrErr)
testutil.RequireReceive(t, reqCh, filtertest.Timeout)
- t.Run("no_match", func(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
-
+ require.True(t, t.Run("no_match", func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
req, ri := newReq(t, testOther, dns.TypeA)
- res, fltErr := f.FilterRequest(ctx, req, ri)
- require.NoError(t, fltErr)
+ res, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
assert.Nil(t, res)
- t.Run("cached", func(t *testing.T) {
- res, fltErr = f.FilterRequest(ctx, req, ri)
- require.NoError(t, fltErr)
+ require.True(t, t.Run("cached", func(t *testing.T) {
+ res, err = f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
// TODO(a.garipov): Find a way to make caches more inspectable.
assert.Nil(t, res)
- })
- })
-
- t.Run("txt", func(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
+ }))
+ }))
+ require.True(t, t.Run("txt", func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
req, ri := newReq(t, testEngineWithIP, dns.TypeTXT)
- res, fltErr := f.FilterRequest(ctx, req, ri)
- require.NoError(t, fltErr)
+ res, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
assert.Nil(t, res)
- })
-
- t.Run("ip", func(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
+ }))
+ require.True(t, t.Run("ip", func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
req, ri := newReq(t, testEngineWithIP, dns.TypeA)
- res, fltErr := f.FilterRequest(ctx, req, ri)
- require.NoError(t, fltErr)
+ res, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
- rm := testutil.RequireTypeAssert[*internal.ResultModified](t, res)
+ rm := testutil.RequireTypeAssert[*internal.ResultModifiedResponse](t, res)
require.Len(t, rm.Msg.Answer, 1)
assert.Equal(t, rm.Rule, agd.FilterRuleText(testEngineWithIP))
@@ -152,40 +110,56 @@ func TestFilter(t *testing.T) {
newReq, newRI := newReq(t, testEngineWithIP, dns.TypeA)
var cachedRes internal.Result
- cachedRes, fltErr = f.FilterRequest(ctx, newReq, newRI)
- require.NoError(t, fltErr)
+ cachedRes, err = f.FilterRequest(ctx, newReq, newRI)
+ require.NoError(t, err)
// Do not assert that the results are the same, since a modified
// result of a safe search is always cloned. But assert that the
// non-clonable fields are equal and that the message has reply
// fields set properly.
- cachedRM := testutil.RequireTypeAssert[*internal.ResultModified](t, cachedRes)
- assert.NotSame(t, cachedRM, rm)
- assert.Equal(t, cachedRM.Msg.Id, newReq.Id)
- assert.Equal(t, cachedRM.List, rm.List)
- assert.Equal(t, cachedRM.Rule, rm.Rule)
+ cachedMR := testutil.RequireTypeAssert[*internal.ResultModifiedResponse](t, cachedRes)
+ assert.NotSame(t, cachedMR, rm)
+ assert.Equal(t, cachedMR.Msg.Id, newReq.Id)
+ assert.Equal(t, cachedMR.List, rm.List)
+ assert.Equal(t, cachedMR.Rule, rm.Rule)
})
- })
-
- t.Run("domain", func(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), filtertest.Timeout)
- t.Cleanup(cancel)
+ }))
+ require.True(t, t.Run("domain", func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
req, ri := newReq(t, testEngineWithDomain, dns.TypeA)
- res, fltErr := f.FilterRequest(ctx, req, ri)
- require.NoError(t, fltErr)
+ res, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
- rm := testutil.RequireTypeAssert[*internal.ResultModified](t, res)
- require.Len(t, rm.Msg.Answer, 2)
+ rm := testutil.RequireTypeAssert[*internal.ResultModifiedRequest](t, res)
+ require.NotNil(t, rm.Msg)
+ require.Len(t, rm.Msg.Question, 1)
+ assert.False(t, rm.Msg.Response)
assert.Equal(t, rm.Rule, agd.FilterRuleText(testEngineWithDomain))
- cname := testutil.RequireTypeAssert[*dns.CNAME](t, rm.Msg.Answer[0])
- assert.Equal(t, dns.Fqdn(testSafeDomain), cname.Target)
+ q := rm.Msg.Question[0]
+ assert.Equal(t, dns.TypeA, q.Qtype)
+ assert.Equal(t, dns.Fqdn(testSafeDomain), q.Name)
+ }))
- a := testutil.RequireTypeAssert[*dns.A](t, rm.Msg.Answer[1])
- assert.Equal(t, net.IP(testIPOfEngineWithDomain.AsSlice()), a.A)
- })
+ require.True(t, t.Run("https", func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+ req, ri := newReq(t, testEngineWithDomain, dns.TypeHTTPS)
+ res, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
+
+ rm := testutil.RequireTypeAssert[*internal.ResultModifiedRequest](t, res)
+ require.NotNil(t, rm.Msg)
+ require.Len(t, rm.Msg.Question, 1)
+
+ assert.False(t, rm.Msg.Response)
+ assert.Equal(t, rm.Rule, agd.FilterRuleText(testEngineWithDomain))
+
+ q := rm.Msg.Question[0]
+ assert.Equal(t, dns.TypeHTTPS, q.Qtype)
+ assert.Equal(t, dns.Fqdn(testSafeDomain), q.Name)
+ }))
}
// newReq is a test helper that returns the DNS request and its accompanying
diff --git a/internal/filter/storage.go b/internal/filter/storage.go
index 928d7e7..e7f4b84 100644
--- a/internal/filter/storage.go
+++ b/internal/filter/storage.go
@@ -11,9 +11,8 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
@@ -24,7 +23,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/serviceblock"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/log"
- "github.com/bluele/gcache"
)
// Storage is a storage for filters.
@@ -88,6 +86,10 @@ type DefaultStorage struct {
// often the filter rule lists are updated from the index.
refreshIvl time.Duration
+ // ruleListRefreshTimeout is the timeout for the filter update operation of
+ // each rule-list.
+ ruleListRefreshTimeout time.Duration
+
// RuleListCacheSize defines the size of the LRU cache of rule-list
// filtering results.
ruleListCacheSize int
@@ -143,15 +145,10 @@ type DefaultStorageConfig struct {
// Now is a function that returns current time.
Now func() (now time.Time)
- // ErrColl is used to collect non-critical and rare errors.
+ // ErrColl is used to collect non-critical and rare errors as well as
+ // refresh errors.
ErrColl errcoll.Interface
- // Resolver is used to resolve hosts in safe search.
- Resolver agdnet.Resolver
-
- // Cloner is used to clone messages taken from filtering-result caches.
- Cloner *dnsmsg.Cloner
-
// CacheDir is the path to the directory where the cached filter files are
// put. The directory must exist.
CacheDir string
@@ -179,6 +176,14 @@ type DefaultStorageConfig struct {
// staleness, which can cause issues. Consider splitting the two.
RefreshIvl time.Duration
+ // IndexRefreshTimeout is the timeout for the filter rule-list index update
+ // operation.
+ IndexRefreshTimeout time.Duration
+
+ // RuleListRefreshTimeout is the timeout for the filter update operation of
+ // each rule-list.
+ RuleListRefreshTimeout time.Duration
+
// UseRuleListCache, if true, enables rule list cache.
UseRuleListCache bool
@@ -187,38 +192,34 @@ type DefaultStorageConfig struct {
MaxRuleListSize uint64
}
+// svcIdxRefreshTimeout is the default timeout to use when fetching the
+// blocked-service index.
+const svcIdxRefreshTimeout = 3 * time.Minute
+
// NewDefaultStorage returns a new filter storage. c must not be nil.
func NewDefaultStorage(c *DefaultStorageConfig) (s *DefaultStorage, err error) {
genSafeSearch := safesearch.New(&safesearch.Config{
- Cloner: c.Cloner,
Refreshable: &internal.RefreshableConfig{
URL: c.GeneralSafeSearchRulesURL,
ID: agd.FilterListIDGeneralSafeSearch,
CachePath: filepath.Join(c.CacheDir, string(agd.FilterListIDGeneralSafeSearch)),
Staleness: c.RefreshIvl,
- // TODO(ameshkov): Consider making configurable.
- Timeout: internal.DefaultFilterRefreshTimeout,
- MaxSize: c.MaxRuleListSize,
+ Timeout: c.RuleListRefreshTimeout,
+ MaxSize: c.MaxRuleListSize,
},
- Resolver: c.Resolver,
- ErrColl: c.ErrColl,
CacheTTL: c.SafeSearchCacheTTL,
CacheSize: c.SafeSearchCacheSize,
})
ytSafeSearch := safesearch.New(&safesearch.Config{
- Cloner: c.Cloner,
Refreshable: &internal.RefreshableConfig{
URL: c.YoutubeSafeSearchRulesURL,
ID: agd.FilterListIDYoutubeSafeSearch,
CachePath: filepath.Join(c.CacheDir, string(agd.FilterListIDYoutubeSafeSearch)),
Staleness: c.RefreshIvl,
- // TODO(ameshkov): Consider making configurable.
- Timeout: internal.DefaultFilterRefreshTimeout,
- MaxSize: c.MaxRuleListSize,
+ Timeout: c.RuleListRefreshTimeout,
+ MaxSize: c.MaxRuleListSize,
},
- Resolver: c.Resolver,
- ErrColl: c.ErrColl,
CacheTTL: c.SafeSearchCacheTTL,
CacheSize: c.SafeSearchCacheSize,
})
@@ -229,8 +230,7 @@ func NewDefaultStorage(c *DefaultStorageConfig) (s *DefaultStorage, err error) {
ID: "rule_list_index",
CachePath: filepath.Join(c.CacheDir, ruleListIndexFilename),
Staleness: c.RefreshIvl,
- // TODO(ameshkov): Consider making configurable.
- Timeout: internal.DefaultFilterRefreshTimeout,
+ Timeout: c.IndexRefreshTimeout,
// TODO(a.garipov): Consider using a different limit here.
MaxSize: c.MaxRuleListSize,
})
@@ -242,7 +242,7 @@ func NewDefaultStorage(c *DefaultStorageConfig) (s *DefaultStorage, err error) {
CachePath: filepath.Join(c.CacheDir, serviceIndexFilename),
Staleness: c.RefreshIvl,
// TODO(ameshkov): Consider making configurable.
- Timeout: internal.DefaultFilterRefreshTimeout,
+ Timeout: svcIdxRefreshTimeout,
// TODO(a.garipov): Consider using a different limit here.
MaxSize: c.MaxRuleListSize,
})
@@ -259,14 +259,17 @@ func NewDefaultStorage(c *DefaultStorageConfig) (s *DefaultStorage, err error) {
now: c.Now,
errColl: c.ErrColl,
customFilters: custom.New(
- gcache.New(c.CustomFilterCacheSize).LRU().Build(),
+ &agdcache.LRUConfig{
+ Size: c.CustomFilterCacheSize,
+ },
c.ErrColl,
),
- cacheDir: c.CacheDir,
- refreshIvl: c.RefreshIvl,
- ruleListCacheSize: c.RuleListCacheSize,
- useRuleListCache: c.UseRuleListCache,
- maxRuleListSize: c.MaxRuleListSize,
+ cacheDir: c.CacheDir,
+ refreshIvl: c.RefreshIvl,
+ ruleListRefreshTimeout: c.RuleListRefreshTimeout,
+ ruleListCacheSize: c.RuleListCacheSize,
+ maxRuleListSize: c.MaxRuleListSize,
+ useRuleListCache: c.UseRuleListCache,
}
err = s.refresh(context.Background(), true)
@@ -478,7 +481,32 @@ const strgLogPrefix = "filter storage: refresh"
// Refresh implements the [agdservice.Refresher] interface for *DefaultStorage.
func (s *DefaultStorage) Refresh(ctx context.Context) (err error) {
- return s.refresh(ctx, false)
+ // TODO(a.garipov): Use slog.
+ log.Info("filters_refresh: started")
+ defer log.Info("filters_refresh: finished")
+
+ err = s.refresh(ctx, false)
+ if err != nil {
+ errcoll.Collectf(ctx, s.errColl, "filters_refresh: %w", enrichFromContext(ctx, err))
+ }
+
+ return err
+}
+
+// enrichFromContext adds information from ctx to origErr if it can assume that
+// origErr is caused by ctx being canceled.
+func enrichFromContext(ctx context.Context, origErr error) (err error) {
+ if ctx.Err() == nil {
+ return origErr
+ }
+
+ // Assume that a deadline is always present here in non-test code.
+ dl, _ := ctx.Deadline()
+
+ // Strip monotonic-clock values.
+ dl = dl.Truncate(0)
+
+ return fmt.Errorf("storage refresh with deadline at %s: %w", dl, origErr)
}
// refresh is the inner method of Refresh that allows accepting stale files. It
@@ -500,26 +528,32 @@ func (s *DefaultStorage) refresh(ctx context.Context, acceptStale bool) (err err
ruleLists := make(filteringRuleLists, len(resp.Filters))
for _, fl := range fls {
s.addRuleList(ctx, ruleLists, fl, acceptStale)
+
+ if ctxErr := ctx.Err(); ctxErr != nil {
+ // If the context has already been canceled, no need to continue, as
+ // the other refreshes won't be able to finish either way.
+ err = fmt.Errorf("after refreshing rule lists: %w", ctxErr)
+ log.Error("filters_refresh: %s", err)
+
+ return err
+ }
}
log.Info("%s: got %d filter lists from index after compilation", strgLogPrefix, len(ruleLists))
err = s.services.Refresh(ctx, s.ruleListCacheSize, s.useRuleListCache, acceptStale)
if err != nil {
- const errFmt = "refreshing blocked services: %w"
- errcoll.Collectf(ctx, s.errColl, errFmt, err)
-
- return fmt.Errorf(errFmt, err)
+ return fmt.Errorf("refreshing blocked services: %w", err)
}
err = s.genSafeSearch.Refresh(ctx, acceptStale)
if err != nil {
- return fmt.Errorf("refreshing safe search: %w", err)
+ return fmt.Errorf("refreshing general safe search: %w", err)
}
err = s.ytSafeSearch.Refresh(ctx, acceptStale)
if err != nil {
- return fmt.Errorf("refreshing safe search: %w", err)
+ return fmt.Errorf("refreshing youtube safe search: %w", err)
}
s.setRuleLists(ruleLists)
@@ -548,9 +582,8 @@ func (s *DefaultStorage) addRuleList(
ID: fl.id,
CachePath: filepath.Join(s.cacheDir, fltIDStr),
Staleness: s.refreshIvl,
- // TODO(ameshkov): Consider making configurable.
- Timeout: internal.DefaultFilterRefreshTimeout,
- MaxSize: s.maxRuleListSize,
+ Timeout: s.ruleListRefreshTimeout,
+ MaxSize: s.maxRuleListSize,
},
s.ruleListCacheSize,
s.useRuleListCache,
@@ -566,7 +599,7 @@ func (s *DefaultStorage) addRuleList(
return
}
- errcoll.Collectf(ctx, s.errColl, "%s: refreshing %q: %w", strgLogPrefix, fl.id, err)
+ errcoll.Collectf(ctx, s.errColl, "%s: %w", strgLogPrefix, err)
metrics.FilterUpdatedStatus.WithLabelValues(fltIDStr).Set(0)
// If we can't get the new filter, and there is an old version of the same
diff --git a/internal/filter/storage_test.go b/internal/filter/storage_test.go
index f28d230..a2407ca 100644
--- a/internal/filter/storage_test.go
+++ b/internal/filter/storage_test.go
@@ -3,7 +3,6 @@ package filter_test
import (
"context"
"io"
- "net/netip"
"os"
"path/filepath"
"testing"
@@ -130,16 +129,6 @@ func TestStorage_FilterFromContext_customAllow(t *testing.T) {
OnCollect: func(_ context.Context, err error) { panic("not implemented") },
}
- resolver := &agdtest.Resolver{
- OnLookupNetIP: func(
- _ context.Context,
- _ netutil.AddrFamily,
- _ string,
- ) (ips []netip.Addr, err error) {
- return []netip.Addr{safeBrowsingSafeIP4}, nil
- },
- }
-
// Initialize the hashes file and use it with the storage.
tmpFile, err := os.CreateTemp(t.TempDir(), "")
require.NoError(t, err)
@@ -157,10 +146,9 @@ func TestStorage_FilterFromContext_customAllow(t *testing.T) {
Cloner: agdtest.NewCloner(),
Hashes: hashes,
ErrColl: errColl,
- Resolver: resolver,
ID: agd.FilterListIDSafeBrowsing,
CachePath: tmpFile.Name(),
- ReplacementHost: safeBrowsingSafeHost,
+ ReplacementHost: safeBrowsingReplHost,
Staleness: filtertest.Staleness,
CacheTTL: filtertest.CacheTTL,
CacheSize: 100,
@@ -168,7 +156,6 @@ func TestStorage_FilterFromContext_customAllow(t *testing.T) {
require.NoError(t, err)
c.ErrColl = errColl
- c.Resolver = resolver
s, err := filter.NewDefaultStorage(c)
require.NoError(t, err)
@@ -227,16 +214,6 @@ func TestStorage_FilterFromContext_schedule(t *testing.T) {
OnCollect: func(_ context.Context, err error) { panic("not implemented") },
}
- resolver := &agdtest.Resolver{
- OnLookupNetIP: func(
- _ context.Context,
- _ netutil.AddrFamily,
- _ string,
- ) (ips []netip.Addr, err error) {
- return []netip.Addr{safeBrowsingSafeIP4}, nil
- },
- }
-
// Initialize the hashes file and use it with the storage.
tmpFile, err := os.CreateTemp(t.TempDir(), "")
require.NoError(t, err)
@@ -255,10 +232,9 @@ func TestStorage_FilterFromContext_schedule(t *testing.T) {
Cloner: agdtest.NewCloner(),
Hashes: hashes,
ErrColl: errColl,
- Resolver: resolver,
ID: agd.FilterListIDAdultBlocking,
CachePath: tmpFile.Name(),
- ReplacementHost: safeBrowsingSafeHost,
+ ReplacementHost: filtertest.SafeBrowsingReplIPv4Str,
Staleness: filtertest.Staleness,
CacheTTL: filtertest.CacheTTL,
CacheSize: 100,
@@ -270,7 +246,6 @@ func TestStorage_FilterFromContext_schedule(t *testing.T) {
}
c.ErrColl = errColl
- c.Resolver = resolver
s, err := filter.NewDefaultStorage(c)
require.NoError(t, err)
@@ -341,10 +316,16 @@ func TestStorage_FilterFromContext_schedule(t *testing.T) {
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- rm := testutil.RequireTypeAssert[*filter.ResultModified](t, r)
+ rm := testutil.RequireTypeAssert[*filter.ResultModifiedResponse](t, r)
assert.Equal(t, rm.Rule, agd.FilterRuleText(safeBrowsingHost))
assert.Equal(t, rm.List, agd.FilterListIDAdultBlocking)
+
+ ans := testutil.RequireTypeAssert[*dns.A](t, rm.Msg.Answer[0])
+
+ ansIP, err := netutil.IPToAddr(ans.A, netutil.AddrFamilyIPv4)
+ assert.NoError(t, err)
+ assert.Equal(t, filtertest.SafeBrowsingReplIPv4, ansIP)
}
func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
@@ -363,12 +344,6 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
RuleListsEnabled: true,
}
- p := &agd.Profile{
- RuleListIDs: []agd.FilterListID{testFilterID},
- FilteringEnabled: true,
- RuleListsEnabled: true,
- }
-
t.Run("blocked", func(t *testing.T) {
req := &dns.Msg{
Question: []dns.Question{{
@@ -469,56 +444,6 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
assert.Equal(t, ra.List, testFilterID)
})
- t.Run("blocked_device", func(t *testing.T) {
- req := &dns.Msg{
- Question: []dns.Question{{
- Name: blockedDeviceFQDN,
- Qtype: dns.TypeA,
- Qclass: dns.ClassINET,
- }},
- }
-
- ri := newReqInfo(g, p, blockedDeviceHost, deviceIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
-
- f := s.FilterFromContext(ctx, ri)
- require.NotNil(t, f)
-
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
- require.NoError(t, err)
-
- rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
-
- assert.Contains(t, rb.Rule, blockedDeviceHost)
- assert.Equal(t, rb.List, testFilterID)
- })
-
- t.Run("allowed_device", func(t *testing.T) {
- req := &dns.Msg{
- Question: []dns.Question{{
- Name: allowedDeviceFQDN,
- Qtype: dns.TypeA,
- Qclass: dns.ClassINET,
- }},
- }
-
- ri := newReqInfo(g, p, allowedDeviceHost, deviceIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
-
- f := s.FilterFromContext(ctx, ri)
- require.NotNil(t, f)
-
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
- require.NoError(t, err)
-
- ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
-
- assert.Contains(t, ra.Rule, allowedDeviceHost)
- assert.Equal(t, ra.List, testFilterID)
- })
-
t.Run("none", func(t *testing.T) {
req := &dns.Msg{
Question: []dns.Question{{
@@ -542,6 +467,74 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
})
}
+func TestStorage_FilterFromContext_customDevice(t *testing.T) {
+ c := prepareConf(t)
+ c.ErrColl = &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) { panic("not implemented") },
+ }
+
+ s, errStrg := filter.NewDefaultStorage(c)
+ require.NoError(t, errStrg)
+
+ g := &agd.FilteringGroup{}
+ p := &agd.Profile{
+ CustomRules: []agd.FilterRuleText{
+ `||blocked-device.example.com^$client="My Device"`,
+ `@@||allowed-device.example.com^$client="My Device"`,
+ },
+ FilteringEnabled: true,
+ RuleListsEnabled: true,
+ }
+
+ t.Run("blocked_device", func(t *testing.T) {
+ req := &dns.Msg{
+ Question: []dns.Question{{
+ Name: blockedDeviceFQDN,
+ Qtype: dns.TypeA,
+ Qclass: dns.ClassINET,
+ }},
+ }
+
+ ri := newReqInfo(g, p, blockedDeviceHost, deviceIP, dns.TypeA)
+ ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+
+ f := s.FilterFromContext(ctx, ri)
+ require.NotNil(t, f)
+
+ r, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
+
+ rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
+
+ assert.Contains(t, rb.Rule, blockedDeviceHost)
+ assert.Equal(t, rb.List, agd.FilterListIDCustom)
+ })
+
+ t.Run("allowed_device", func(t *testing.T) {
+ req := &dns.Msg{
+ Question: []dns.Question{{
+ Name: allowedDeviceFQDN,
+ Qtype: dns.TypeA,
+ Qclass: dns.ClassINET,
+ }},
+ }
+
+ ri := newReqInfo(g, p, allowedDeviceHost, deviceIP, dns.TypeA)
+ ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+
+ f := s.FilterFromContext(ctx, ri)
+ require.NotNil(t, f)
+
+ r, err := f.FilterRequest(ctx, req, ri)
+ require.NoError(t, err)
+
+ ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
+
+ assert.Contains(t, ra.Rule, allowedDeviceHost)
+ assert.Equal(t, ra.List, agd.FilterListIDCustom)
+ })
+}
+
func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
c := prepareConf(t)
@@ -742,26 +735,15 @@ func TestStorage_FilterFromContext_safeBrowsing(t *testing.T) {
},
}
- resolver := &agdtest.Resolver{
- OnLookupNetIP: func(
- _ context.Context,
- _ netutil.AddrFamily,
- _ string,
- ) (ips []netip.Addr, err error) {
- return []netip.Addr{safeBrowsingSafeIP4}, nil
- },
- }
-
c := prepareConf(t)
c.SafeBrowsing, err = hashprefix.NewFilter(&hashprefix.FilterConfig{
Cloner: agdtest.NewCloner(),
Hashes: hashes,
ErrColl: errColl,
- Resolver: resolver,
ID: agd.FilterListIDSafeBrowsing,
CachePath: cachePath,
- ReplacementHost: safeBrowsingSafeHost,
+ ReplacementHost: safeBrowsingReplHost,
Staleness: filtertest.Staleness,
CacheTTL: filtertest.CacheTTL,
CacheSize: 100,
@@ -769,7 +751,6 @@ func TestStorage_FilterFromContext_safeBrowsing(t *testing.T) {
require.NoError(t, err)
c.ErrColl = errColl
- c.Resolver = resolver
s, err := filter.NewDefaultStorage(c)
require.NoError(t, err)
@@ -803,38 +784,16 @@ func TestStorage_FilterFromContext_safeBrowsing(t *testing.T) {
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- rm := testutil.RequireTypeAssert[*filter.ResultModified](t, r)
+ rm := testutil.RequireTypeAssert[*filter.ResultModifiedRequest](t, r)
+ assert.Equal(t, rm.Msg.Question[0].Name, safeBrowsingReplFQDN)
assert.Equal(t, rm.Rule, agd.FilterRuleText(safeBrowsingHost))
assert.Equal(t, rm.List, agd.FilterListIDSafeBrowsing)
}
func TestStorage_FilterFromContext_safeSearch(t *testing.T) {
- numLookupIP := 0
- resolver := &agdtest.Resolver{
- OnLookupNetIP: func(
- _ context.Context,
- fam netutil.AddrFamily,
- _ string,
- ) (ips []netip.Addr, err error) {
- numLookupIP++
-
- if fam == netutil.AddrFamilyIPv4 {
- return []netip.Addr{safeSearchIPRespIP4}, nil
- }
-
- return []netip.Addr{safeSearchIPRespIP6}, nil
- },
- }
-
c := prepareConf(t)
- c.ErrColl = &agdtest.ErrorCollector{
- OnCollect: func(_ context.Context, err error) { panic("not implemented") },
- }
-
- c.Resolver = resolver
-
s, err := filter.NewDefaultStorage(c)
require.NoError(t, err)
@@ -847,51 +806,42 @@ func TestStorage_FilterFromContext_safeSearch(t *testing.T) {
ttl := uint32(agdtest.FilteredResponseTTLSec)
testCases := []struct {
- name string
- host string
- want []dns.RR
- rrtype uint16
- wantLookups int
+ name string
+ host string
+ want []dns.RR
+ rrtype uint16
+ wantReq bool
}{{
want: []dns.RR{
- dnsservertest.NewA(safeSearchIPHost, ttl, safeSearchIPRespIP4),
+ dnsservertest.NewA(safeSearchIPv4Host, ttl, safeSearchIPRespIP4),
},
- name: "ip4",
- host: safeSearchIPHost,
- rrtype: dns.TypeA,
- wantLookups: 1,
+ name: "ip4",
+ host: safeSearchIPv4Host,
+ rrtype: dns.TypeA,
+ wantReq: false,
}, {
want: []dns.RR{
- dnsservertest.NewAAAA(safeSearchIPHost, ttl, safeSearchIPRespIP6),
+ dnsservertest.NewAAAA(safeSearchIPv6Host, ttl, safeSearchIPRespIP6),
},
- name: "ip6",
- host: safeSearchIPHost,
- rrtype: dns.TypeAAAA,
- wantLookups: 1,
+ name: "ip6",
+ host: safeSearchIPv6Host,
+ rrtype: dns.TypeAAAA,
+ wantReq: false,
}, {
- want: []dns.RR{
- dnsservertest.NewCNAME(safeSearchHost, ttl, safeSearchRespHost),
- dnsservertest.NewA(safeSearchRespHost, ttl, safeSearchIPRespIP4),
- },
- name: "host_ip4",
- host: safeSearchHost,
- rrtype: dns.TypeA,
- wantLookups: 1,
+ want: nil,
+ name: "host_ip4",
+ host: safeSearchHost,
+ rrtype: dns.TypeA,
+ wantReq: true,
}, {
- want: []dns.RR{
- dnsservertest.NewCNAME(safeSearchHost, ttl, safeSearchRespHost),
- dnsservertest.NewAAAA(safeSearchRespHost, ttl, safeSearchIPRespIP6),
- },
- name: "host_ip6",
- host: safeSearchHost,
- rrtype: dns.TypeAAAA,
- wantLookups: 1,
+ want: nil,
+ name: "host_ip6",
+ host: safeSearchHost,
+ rrtype: dns.TypeAAAA,
+ wantReq: true,
}}
for _, tc := range testCases {
- numLookupIP = 0
- req := dnsservertest.CreateMessage(tc.host, tc.rrtype)
-
t.Run(tc.name, func(t *testing.T) {
ri := newReqInfo(g, nil, tc.host, clientIP, tc.rrtype)
ctx := agd.ContextWithRequestInfo(context.Background(), ri)
@@ -899,19 +849,32 @@ func TestStorage_FilterFromContext_safeSearch(t *testing.T) {
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
+ req := dnsservertest.CreateMessage(tc.host, tc.rrtype)
+
var r filter.Result
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
+ require.NotNil(t, r)
- assert.Equal(t, tc.wantLookups, numLookupIP)
+ id, rule := r.MatchedRule()
+ assert.Contains(t, rule, tc.host)
+ assert.Equal(t, id, agd.FilterListIDGeneralSafeSearch)
- rm := testutil.RequireTypeAssert[*filter.ResultModified](t, r)
- assert.Contains(t, rm.Rule, tc.host)
- assert.Equal(t, rm.List, agd.FilterListIDGeneralSafeSearch)
+ var msg *dns.Msg
+ if tc.wantReq {
+ rm := testutil.RequireTypeAssert[*filter.ResultModifiedRequest](t, r)
- res := rm.Msg
- require.NotNil(t, res)
- require.Equal(t, tc.want, res.Answer)
+ msg = rm.Msg
+ } else {
+ rm := testutil.RequireTypeAssert[*filter.ResultModifiedResponse](t, r)
+
+ msg = rm.Msg
+ }
+
+ require.NotNil(t, msg)
+
+ assert.Equal(t, tc.wantReq, !msg.Response)
+ assert.Equal(t, tc.want, msg.Answer)
})
}
}
@@ -931,7 +894,7 @@ func BenchmarkStorage_NewDefaultStorage(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
defaultStorageSink, errSink = filter.NewDefaultStorage(c)
}
diff --git a/internal/filter/testdata/filter b/internal/filter/testdata/filter
index 8fbf2c4..f02e8d8 100644
--- a/internal/filter/testdata/filter
+++ b/internal/filter/testdata/filter
@@ -5,8 +5,6 @@
# Per-Client Blocking
||blocked-client.example.com^$client=1.2.3.4
@@||allowed-client.example.com^$client=1.2.3.4
-||blocked-device.example.com^$client="My Device"
-@@||allowed-device.example.com^$client="My Device"
#
# IP-level blocking.
6.6.6.13
diff --git a/internal/filter/testdata/general_safe_search b/internal/filter/testdata/general_safe_search
index 6df5453..cbfa1ff 100644
--- a/internal/filter/testdata/general_safe_search
+++ b/internal/filter/testdata/general_safe_search
@@ -1,4 +1,6 @@
# CNAME rewrite.
||duckduckgo.com^$dnsrewrite=NOERROR;CNAME;safe.duckduckgo.com
-# IP rewrite.
+# IPv4 rewrite.
||www.yandex.by^$dnsrewrite=NOERROR;A;213.180.193.56
+# IPv6 rewrite.
+||www.google.com^$dnsrewrite=NOERROR;AAAA;2001:4860:4802:32::78
diff --git a/internal/geoip/asntops.go b/internal/geoip/asntops.go
index 59bd5e2..fddea5e 100644
--- a/internal/geoip/asntops.go
+++ b/internal/geoip/asntops.go
@@ -2,3171 +2,3160 @@
package geoip
+import "github.com/AdguardTeam/golibs/container"
+
// DefaultTopASNs contains all specially handled ASNs.
-var DefaultTopASNs = map[ASN]struct{}{
- 2: {},
- 174: {},
- 209: {},
- 224: {},
- 577: {},
- 701: {},
- 719: {},
- 786: {},
- 803: {},
- 812: {},
- 834: {},
- 852: {},
- 855: {},
- 1136: {},
- 1213: {},
- 1221: {},
- 1241: {},
- 1257: {},
- 1267: {},
- 1299: {},
- 1403: {},
- 1547: {},
- 1680: {},
- 1756: {},
- 1759: {},
- 1835: {},
- 1836: {},
- 1901: {},
- 1955: {},
- 2018: {},
- 2108: {},
- 2110: {},
- 2116: {},
- 2119: {},
- 2497: {},
- 2514: {},
- 2516: {},
- 2518: {},
- 2519: {},
- 2527: {},
- 2586: {},
- 2588: {},
- 2602: {},
- 2607: {},
- 2609: {},
- 2611: {},
- 2740: {},
- 2847: {},
- 2852: {},
- 2856: {},
- 2860: {},
- 3132: {},
- 3178: {},
- 3209: {},
- 3212: {},
- 3215: {},
- 3216: {},
- 3221: {},
- 3223: {},
- 3225: {},
- 3238: {},
- 3243: {},
- 3249: {},
- 3255: {},
- 3269: {},
- 3292: {},
- 3301: {},
- 3303: {},
- 3308: {},
- 3320: {},
- 3326: {},
- 3329: {},
- 3342: {},
- 3352: {},
- 3356: {},
- 3399: {},
- 3462: {},
- 3549: {},
- 3605: {},
- 3695: {},
- 3741: {},
- 3758: {},
- 3786: {},
- 3816: {},
- 3855: {},
- 4007: {},
- 4134: {},
- 4230: {},
- 4515: {},
- 4528: {},
- 4538: {},
- 4540: {},
- 4609: {},
- 4638: {},
- 4657: {},
- 4685: {},
- 4713: {},
- 4721: {},
- 4725: {},
- 4739: {},
- 4760: {},
- 4761: {},
- 4764: {},
- 4766: {},
- 4768: {},
- 4771: {},
- 4773: {},
- 4775: {},
- 4780: {},
- 4788: {},
- 4804: {},
- 4808: {},
- 4812: {},
- 4817: {},
- 4818: {},
- 4837: {},
- 4847: {},
- 5089: {},
- 5378: {},
- 5384: {},
- 5390: {},
- 5391: {},
- 5408: {},
- 5410: {},
- 5413: {},
- 5416: {},
- 5432: {},
- 5466: {},
- 5483: {},
- 5504: {},
- 5518: {},
- 5532: {},
- 5578: {},
- 5603: {},
- 5607: {},
- 5610: {},
- 5617: {},
- 5639: {},
- 5645: {},
- 5650: {},
- 5713: {},
- 5769: {},
- 6057: {},
- 6079: {},
- 6128: {},
- 6147: {},
- 6167: {},
- 6306: {},
- 6327: {},
- 6400: {},
- 6407: {},
- 6461: {},
- 6535: {},
- 6568: {},
- 6639: {},
- 6661: {},
- 6677: {},
- 6697: {},
- 6700: {},
- 6703: {},
- 6713: {},
- 6730: {},
- 6739: {},
- 6752: {},
- 6758: {},
- 6769: {},
- 6772: {},
- 6799: {},
- 6805: {},
- 6810: {},
- 6821: {},
- 6830: {},
- 6843: {},
- 6848: {},
- 6849: {},
- 6855: {},
- 6866: {},
- 6871: {},
- 6876: {},
- 6939: {},
- 7018: {},
- 7029: {},
- 7049: {},
- 7057: {},
- 7122: {},
- 7131: {},
- 7303: {},
- 7418: {},
- 7438: {},
- 7470: {},
- 7482: {},
- 7497: {},
- 7522: {},
- 7524: {},
- 7545: {},
- 7552: {},
- 7565: {},
- 7642: {},
- 7679: {},
- 7713: {},
- 7727: {},
- 7738: {},
- 7794: {},
- 7922: {},
- 7979: {},
- 7992: {},
- 8014: {},
- 8048: {},
- 8053: {},
- 8075: {},
- 8151: {},
- 8167: {},
- 8193: {},
- 8200: {},
- 8251: {},
- 8257: {},
- 8273: {},
- 8290: {},
- 8301: {},
- 8339: {},
- 8346: {},
- 8359: {},
- 8369: {},
- 8374: {},
- 8376: {},
- 8386: {},
- 8400: {},
- 8402: {},
- 8412: {},
- 8422: {},
- 8437: {},
- 8445: {},
- 8447: {},
- 8449: {},
- 8452: {},
- 8462: {},
- 8468: {},
- 8473: {},
- 8544: {},
- 8551: {},
- 8560: {},
- 8585: {},
- 8612: {},
- 8632: {},
- 8661: {},
- 8680: {},
- 8681: {},
- 8697: {},
- 8708: {},
- 8717: {},
- 8728: {},
- 8744: {},
- 8758: {},
- 8764: {},
- 8767: {},
- 8772: {},
- 8778: {},
- 8781: {},
- 8818: {},
- 8821: {},
- 8829: {},
- 8847: {},
- 8849: {},
- 8866: {},
- 8881: {},
- 8887: {},
- 8926: {},
- 8948: {},
- 8953: {},
- 8966: {},
- 8990: {},
- 9002: {},
- 9008: {},
- 9009: {},
- 9031: {},
- 9038: {},
- 9044: {},
- 9050: {},
- 9051: {},
- 9063: {},
- 9070: {},
- 9105: {},
- 9119: {},
- 9121: {},
- 9125: {},
- 9129: {},
- 9145: {},
- 9146: {},
- 9155: {},
- 9158: {},
- 9198: {},
- 9231: {},
- 9245: {},
- 9246: {},
- 9249: {},
- 9260: {},
- 9269: {},
- 9299: {},
- 9303: {},
- 9304: {},
- 9316: {},
- 9318: {},
- 9329: {},
- 9335: {},
- 9341: {},
- 9351: {},
- 9354: {},
- 9365: {},
- 9381: {},
- 9416: {},
- 9431: {},
- 9443: {},
- 9471: {},
- 9484: {},
- 9500: {},
- 9506: {},
- 9534: {},
- 9541: {},
- 9595: {},
- 9605: {},
- 9617: {},
- 9644: {},
- 9674: {},
- 9694: {},
- 9751: {},
- 9770: {},
- 9790: {},
- 9808: {},
- 9824: {},
- 9829: {},
- 9845: {},
- 9873: {},
- 9876: {},
- 9902: {},
- 9908: {},
- 9919: {},
- 9922: {},
- 9924: {},
- 9930: {},
- 9931: {},
- 9934: {},
- 9976: {},
- 9988: {},
- 9997: {},
- 10010: {},
- 10013: {},
- 10030: {},
- 10036: {},
- 10066: {},
- 10075: {},
- 10094: {},
- 10099: {},
- 10101: {},
- 10103: {},
- 10118: {},
- 10131: {},
- 10139: {},
- 10143: {},
- 10214: {},
- 10219: {},
- 10226: {},
- 10269: {},
- 10292: {},
- 10299: {},
- 10396: {},
- 10474: {},
- 10617: {},
- 10620: {},
- 10796: {},
- 11014: {},
- 11081: {},
- 11139: {},
- 11172: {},
- 11232: {},
- 11259: {},
- 11260: {},
- 11290: {},
- 11315: {},
- 11351: {},
- 11426: {},
- 11427: {},
- 11492: {},
- 11556: {},
- 11562: {},
- 11580: {},
- 11594: {},
- 11664: {},
- 11721: {},
- 11776: {},
- 11814: {},
- 11816: {},
- 11830: {},
- 11845: {},
- 11888: {},
- 12066: {},
- 12083: {},
- 12127: {},
- 12252: {},
- 12271: {},
- 12297: {},
- 12301: {},
- 12302: {},
- 12322: {},
- 12334: {},
- 12338: {},
- 12353: {},
- 12361: {},
- 12365: {},
- 12389: {},
- 12390: {},
- 12392: {},
- 12400: {},
- 12414: {},
- 12430: {},
- 12436: {},
- 12455: {},
- 12479: {},
- 12491: {},
- 12496: {},
- 12552: {},
- 12570: {},
- 12576: {},
- 12578: {},
- 12590: {},
- 12605: {},
- 12638: {},
- 12668: {},
- 12684: {},
- 12709: {},
- 12714: {},
- 12716: {},
- 12735: {},
- 12741: {},
- 12754: {},
- 12764: {},
- 12767: {},
- 12793: {},
- 12810: {},
- 12829: {},
- 12849: {},
- 12874: {},
- 12876: {},
- 12880: {},
- 12912: {},
- 12929: {},
- 12946: {},
- 12958: {},
- 12969: {},
- 12975: {},
- 12978: {},
- 12997: {},
- 13000: {},
- 13030: {},
- 13036: {},
- 13037: {},
- 13045: {},
- 13046: {},
- 13092: {},
- 13099: {},
- 13101: {},
- 13110: {},
- 13122: {},
- 13124: {},
- 13127: {},
- 13156: {},
- 13170: {},
- 13188: {},
- 13189: {},
- 13194: {},
- 13280: {},
- 13285: {},
- 13306: {},
- 13335: {},
- 13489: {},
- 13682: {},
- 13771: {},
- 13999: {},
- 14061: {},
- 14080: {},
- 14117: {},
- 14259: {},
- 14434: {},
- 14522: {},
- 14593: {},
- 14618: {},
- 14638: {},
- 14709: {},
- 14754: {},
- 14813: {},
- 14868: {},
- 14979: {},
- 14988: {},
- 15146: {},
- 15344: {},
- 15366: {},
- 15377: {},
- 15378: {},
- 15389: {},
- 15397: {},
- 15399: {},
- 15404: {},
- 15405: {},
- 15433: {},
- 15435: {},
- 15457: {},
- 15474: {},
- 15480: {},
- 15502: {},
- 15511: {},
- 15516: {},
- 15525: {},
- 15542: {},
- 15547: {},
- 15557: {},
- 15600: {},
- 15614: {},
- 15659: {},
- 15704: {},
- 15706: {},
- 15723: {},
- 15735: {},
- 15736: {},
- 15751: {},
- 15766: {},
- 15774: {},
- 15796: {},
- 15802: {},
- 15805: {},
- 15808: {},
- 15836: {},
- 15895: {},
- 15897: {},
- 15924: {},
- 15935: {},
- 15943: {},
- 15955: {},
- 15958: {},
- 15962: {},
- 15964: {},
- 15965: {},
- 15994: {},
- 16010: {},
- 16019: {},
- 16028: {},
- 16058: {},
- 16086: {},
- 16095: {},
- 16116: {},
- 16117: {},
- 16135: {},
- 16178: {},
- 16185: {},
- 16202: {},
- 16223: {},
- 16229: {},
- 16232: {},
- 16246: {},
- 16276: {},
- 16302: {},
- 16322: {},
- 16333: {},
- 16334: {},
- 16342: {},
- 16345: {},
- 16367: {},
- 16413: {},
- 16437: {},
- 16509: {},
- 16591: {},
- 16592: {},
- 16629: {},
- 16637: {},
- 16705: {},
- 16735: {},
- 16814: {},
- 16906: {},
- 16960: {},
- 17072: {},
- 17079: {},
- 17400: {},
- 17411: {},
- 17421: {},
- 17451: {},
- 17458: {},
- 17470: {},
- 17480: {},
- 17488: {},
- 17501: {},
- 17506: {},
- 17511: {},
- 17529: {},
- 17539: {},
- 17547: {},
- 17552: {},
- 17557: {},
- 17621: {},
- 17622: {},
- 17623: {},
- 17639: {},
- 17665: {},
- 17670: {},
- 17676: {},
- 17698: {},
- 17716: {},
- 17726: {},
- 17806: {},
- 17809: {},
- 17816: {},
- 17828: {},
- 17839: {},
- 17853: {},
- 17858: {},
- 17882: {},
- 17893: {},
- 17924: {},
- 17976: {},
- 17993: {},
- 18001: {},
- 18004: {},
- 18013: {},
- 18024: {},
- 18049: {},
- 18053: {},
- 18081: {},
- 18106: {},
- 18126: {},
- 18144: {},
- 18182: {},
- 18199: {},
- 18200: {},
- 18209: {},
- 18278: {},
- 18371: {},
- 18390: {},
- 18399: {},
- 18403: {},
- 18419: {},
- 18734: {},
- 18747: {},
- 18809: {},
- 18822: {},
- 18840: {},
- 18881: {},
- 19016: {},
- 19037: {},
- 19108: {},
- 19114: {},
- 19180: {},
- 19182: {},
- 19246: {},
- 19422: {},
- 19429: {},
- 19447: {},
- 19624: {},
- 19626: {},
- 19711: {},
- 19863: {},
- 19889: {},
- 20001: {},
- 20057: {},
- 20115: {},
- 20207: {},
- 20255: {},
- 20294: {},
- 20299: {},
- 20365: {},
- 20473: {},
- 20485: {},
- 20626: {},
- 20634: {},
- 20661: {},
- 20676: {},
- 20719: {},
- 20723: {},
- 20771: {},
- 20776: {},
- 20804: {},
- 20845: {},
- 20846: {},
- 20860: {},
- 20875: {},
- 20880: {},
- 20904: {},
- 20910: {},
- 20911: {},
- 20963: {},
- 20978: {},
- 21001: {},
- 21003: {},
- 21021: {},
- 21040: {},
- 21050: {},
- 21107: {},
- 21183: {},
- 21211: {},
- 21230: {},
- 21232: {},
- 21246: {},
- 21271: {},
- 21277: {},
- 21283: {},
- 21299: {},
- 21334: {},
- 21351: {},
- 21412: {},
- 21430: {},
- 21450: {},
- 21466: {},
- 21491: {},
- 21497: {},
- 21502: {},
- 21559: {},
- 21575: {},
- 21599: {},
- 21744: {},
- 21804: {},
- 21826: {},
- 21859: {},
- 21928: {},
- 21949: {},
- 21996: {},
- 22047: {},
- 22069: {},
- 22085: {},
- 22313: {},
- 22351: {},
- 22394: {},
- 22423: {},
- 22581: {},
- 22690: {},
- 22724: {},
- 22773: {},
- 22869: {},
- 22884: {},
- 22927: {},
- 22933: {},
- 22995: {},
- 23114: {},
- 23201: {},
- 23243: {},
- 23383: {},
- 23470: {},
- 23487: {},
- 23520: {},
- 23655: {},
- 23657: {},
- 23673: {},
- 23674: {},
- 23688: {},
- 23693: {},
- 23700: {},
- 23750: {},
- 23752: {},
- 23764: {},
- 23860: {},
- 23889: {},
- 23900: {},
- 23923: {},
- 23944: {},
- 23955: {},
- 23956: {},
- 23959: {},
- 23969: {},
- 24016: {},
- 24033: {},
- 24086: {},
- 24157: {},
- 24158: {},
- 24163: {},
- 24164: {},
- 24165: {},
- 24186: {},
- 24203: {},
- 24309: {},
- 24323: {},
- 24337: {},
- 24378: {},
- 24389: {},
- 24400: {},
- 24432: {},
- 24439: {},
- 24444: {},
- 24445: {},
- 24492: {},
- 24499: {},
- 24547: {},
- 24550: {},
- 24559: {},
- 24560: {},
- 24589: {},
- 24608: {},
- 24631: {},
- 24641: {},
- 24651: {},
- 24691: {},
- 24722: {},
- 24743: {},
- 24751: {},
- 24757: {},
- 24800: {},
- 24812: {},
- 24822: {},
- 24835: {},
- 24851: {},
- 24852: {},
- 24863: {},
- 24875: {},
- 24921: {},
- 24940: {},
- 24955: {},
- 24961: {},
- 25003: {},
- 25019: {},
- 25106: {},
- 25117: {},
- 25129: {},
- 25133: {},
- 25135: {},
- 25139: {},
- 25144: {},
- 25159: {},
- 25184: {},
- 25190: {},
- 25229: {},
- 25248: {},
- 25250: {},
- 25255: {},
- 25274: {},
- 25310: {},
- 25369: {},
- 25374: {},
- 25400: {},
- 25406: {},
- 25424: {},
- 25429: {},
- 25441: {},
- 25447: {},
- 25454: {},
- 25467: {},
- 25471: {},
- 25472: {},
- 25491: {},
- 25496: {},
- 25512: {},
- 25513: {},
- 25543: {},
- 25596: {},
- 25607: {},
- 25620: {},
- 25668: {},
- 25695: {},
- 25820: {},
- 26130: {},
- 26210: {},
- 26383: {},
- 26599: {},
- 26611: {},
- 26615: {},
- 26617: {},
- 26932: {},
- 27651: {},
- 27653: {},
- 27660: {},
- 27665: {},
- 27668: {},
- 27672: {},
- 27680: {},
- 27694: {},
- 27695: {},
- 27696: {},
- 27699: {},
- 27708: {},
- 27717: {},
- 27725: {},
- 27729: {},
- 27734: {},
- 27738: {},
- 27742: {},
- 27745: {},
- 27747: {},
- 27757: {},
- 27759: {},
- 27773: {},
- 27775: {},
- 27781: {},
- 27789: {},
- 27796: {},
- 27800: {},
- 27813: {},
- 27831: {},
- 27833: {},
- 27837: {},
- 27839: {},
- 27843: {},
- 27866: {},
- 27876: {},
- 27882: {},
- 27884: {},
- 27887: {},
- 27889: {},
- 27895: {},
- 27901: {},
- 27903: {},
- 27923: {},
- 27924: {},
- 27927: {},
- 27928: {},
- 27932: {},
- 27947: {},
- 27951: {},
- 27983: {},
- 27984: {},
- 27995: {},
- 28005: {},
- 28006: {},
- 28007: {},
- 28009: {},
- 28015: {},
- 28024: {},
- 28032: {},
- 28036: {},
- 28048: {},
- 28075: {},
- 28080: {},
- 28094: {},
- 28103: {},
- 28104: {},
- 28118: {},
- 28126: {},
- 28146: {},
- 28171: {},
- 28182: {},
- 28186: {},
- 28198: {},
- 28201: {},
- 28210: {},
- 28220: {},
- 28258: {},
- 28343: {},
- 28398: {},
- 28403: {},
- 28432: {},
- 28458: {},
- 28469: {},
- 28481: {},
- 28509: {},
- 28512: {},
- 28530: {},
- 28531: {},
- 28532: {},
- 28534: {},
- 28536: {},
- 28537: {},
- 28541: {},
- 28545: {},
- 28548: {},
- 28554: {},
- 28555: {},
- 28573: {},
- 28580: {},
- 28598: {},
- 28649: {},
- 28656: {},
- 28668: {},
- 28669: {},
- 28683: {},
- 28685: {},
- 28698: {},
- 28717: {},
- 28725: {},
- 28753: {},
- 28760: {},
- 28787: {},
- 28812: {},
- 28840: {},
- 28854: {},
- 28858: {},
- 28884: {},
- 28885: {},
- 28909: {},
- 28952: {},
- 28964: {},
- 28972: {},
- 29027: {},
- 29030: {},
- 29031: {},
- 29039: {},
- 29049: {},
- 29061: {},
- 29070: {},
- 29084: {},
- 29091: {},
- 29119: {},
- 29124: {},
- 29170: {},
- 29194: {},
- 29208: {},
- 29238: {},
- 29244: {},
- 29247: {},
- 29256: {},
- 29286: {},
- 29310: {},
- 29314: {},
- 29355: {},
- 29357: {},
- 29405: {},
- 29447: {},
- 29465: {},
- 29485: {},
- 29492: {},
- 29497: {},
- 29518: {},
- 29544: {},
- 29555: {},
- 29571: {},
- 29580: {},
- 29600: {},
- 29614: {},
- 29667: {},
- 29687: {},
- 29695: {},
- 29975: {},
- 30036: {},
- 30058: {},
- 30526: {},
- 30600: {},
- 30619: {},
- 30689: {},
- 30722: {},
- 30764: {},
- 30844: {},
- 30860: {},
- 30873: {},
- 30896: {},
- 30929: {},
- 30969: {},
- 30982: {},
- 30985: {},
- 30986: {},
- 30990: {},
- 30992: {},
- 30999: {},
- 31012: {},
- 31027: {},
- 31037: {},
- 31042: {},
- 31117: {},
- 31122: {},
- 31126: {},
- 31127: {},
- 31133: {},
- 31143: {},
- 31148: {},
- 31163: {},
- 31169: {},
- 31200: {},
- 31204: {},
- 31205: {},
- 31208: {},
- 31213: {},
- 31224: {},
- 31242: {},
- 31246: {},
- 31252: {},
- 31272: {},
- 31287: {},
- 31390: {},
- 31404: {},
- 31423: {},
- 31452: {},
- 31499: {},
- 31510: {},
- 31543: {},
- 31549: {},
- 31608: {},
- 31615: {},
- 31642: {},
- 31655: {},
- 31689: {},
- 31721: {},
- 31725: {},
- 31898: {},
- 31960: {},
- 32020: {},
- 32098: {},
- 32398: {},
- 32860: {},
- 33363: {},
- 33392: {},
- 33567: {},
- 33576: {},
- 33582: {},
- 33763: {},
- 33765: {},
- 33771: {},
- 33779: {},
- 33781: {},
- 33788: {},
- 33796: {},
- 33874: {},
- 33883: {},
- 33885: {},
- 33915: {},
- 33922: {},
- 33983: {},
- 34001: {},
- 34058: {},
- 34087: {},
- 34113: {},
- 34120: {},
- 34170: {},
- 34187: {},
- 34224: {},
- 34244: {},
- 34245: {},
- 34263: {},
- 34295: {},
- 34296: {},
- 34347: {},
- 34362: {},
- 34447: {},
- 34471: {},
- 34515: {},
- 34525: {},
- 34533: {},
- 34547: {},
- 34557: {},
- 34569: {},
- 34577: {},
- 34594: {},
- 34636: {},
- 34661: {},
- 34666: {},
- 34700: {},
- 34702: {},
- 34705: {},
- 34718: {},
- 34724: {},
- 34743: {},
- 34754: {},
- 34772: {},
- 34779: {},
- 34781: {},
- 34797: {},
- 34803: {},
- 34814: {},
- 34857: {},
- 34876: {},
- 34916: {},
- 34918: {},
- 34977: {},
- 34984: {},
- 34989: {},
- 35046: {},
- 35047: {},
- 35063: {},
- 35091: {},
- 35104: {},
- 35132: {},
- 35141: {},
- 35158: {},
- 35179: {},
- 35191: {},
- 35197: {},
- 35223: {},
- 35228: {},
- 35244: {},
- 35297: {},
- 35311: {},
- 35320: {},
- 35328: {},
- 35346: {},
- 35362: {},
- 35370: {},
- 35394: {},
- 35432: {},
- 35444: {},
- 35457: {},
- 35467: {},
- 35518: {},
- 35546: {},
- 35549: {},
- 35566: {},
- 35567: {},
- 35568: {},
- 35612: {},
- 35613: {},
- 35699: {},
- 35706: {},
- 35725: {},
- 35729: {},
- 35732: {},
- 35753: {},
- 35765: {},
- 35790: {},
- 35805: {},
- 35807: {},
- 35819: {},
- 35892: {},
- 35900: {},
- 35911: {},
- 35913: {},
- 35916: {},
- 36040: {},
- 36290: {},
- 36352: {},
- 36445: {},
- 36492: {},
- 36511: {},
- 36549: {},
- 36599: {},
- 36864: {},
- 36865: {},
- 36866: {},
- 36873: {},
- 36874: {},
- 36884: {},
- 36890: {},
- 36892: {},
- 36902: {},
- 36903: {},
- 36905: {},
- 36907: {},
- 36908: {},
- 36909: {},
- 36912: {},
- 36913: {},
- 36914: {},
- 36920: {},
- 36923: {},
- 36924: {},
- 36925: {},
- 36926: {},
- 36930: {},
- 36935: {},
- 36937: {},
- 36939: {},
- 36947: {},
- 36958: {},
- 36962: {},
- 36963: {},
- 36969: {},
- 36974: {},
- 36977: {},
- 36986: {},
- 36988: {},
- 36992: {},
- 36994: {},
- 36996: {},
- 36999: {},
- 37002: {},
- 37004: {},
- 37006: {},
- 37009: {},
- 37014: {},
- 37020: {},
- 37027: {},
- 37030: {},
- 37035: {},
- 37037: {},
- 37049: {},
- 37053: {},
- 37054: {},
- 37057: {},
- 37061: {},
- 37063: {},
- 37069: {},
- 37073: {},
- 37074: {},
- 37075: {},
- 37076: {},
- 37081: {},
- 37084: {},
- 37090: {},
- 37094: {},
- 37098: {},
- 37100: {},
- 37105: {},
- 37110: {},
- 37113: {},
- 37119: {},
- 37123: {},
- 37124: {},
- 37129: {},
- 37133: {},
- 37136: {},
- 37141: {},
- 37143: {},
- 37148: {},
- 37154: {},
- 37164: {},
- 37168: {},
- 37173: {},
- 37182: {},
- 37183: {},
- 37184: {},
- 37187: {},
- 37189: {},
- 37190: {},
- 37196: {},
- 37203: {},
- 37204: {},
- 37205: {},
- 37208: {},
- 37215: {},
- 37223: {},
- 37228: {},
- 37229: {},
- 37233: {},
- 37257: {},
- 37282: {},
- 37284: {},
- 37287: {},
- 37294: {},
- 37303: {},
- 37305: {},
- 37309: {},
- 37313: {},
- 37315: {},
- 37323: {},
- 37326: {},
- 37334: {},
- 37336: {},
- 37337: {},
- 37340: {},
- 37342: {},
- 37343: {},
- 37349: {},
- 37358: {},
- 37371: {},
- 37385: {},
- 37395: {},
- 37406: {},
- 37410: {},
- 37424: {},
- 37425: {},
- 37427: {},
- 37430: {},
- 37440: {},
- 37447: {},
- 37449: {},
- 37451: {},
- 37453: {},
- 37457: {},
- 37460: {},
- 37461: {},
- 37463: {},
- 37473: {},
- 37487: {},
- 37492: {},
- 37503: {},
- 37508: {},
- 37517: {},
- 37524: {},
- 37526: {},
- 37529: {},
- 37531: {},
- 37532: {},
- 37541: {},
- 37550: {},
- 37552: {},
- 37559: {},
- 37563: {},
- 37575: {},
- 37577: {},
- 37584: {},
- 37594: {},
- 37604: {},
- 37611: {},
- 37612: {},
- 37614: {},
- 37616: {},
- 37621: {},
- 37622: {},
- 37637: {},
- 37638: {},
- 37642: {},
- 37645: {},
- 37649: {},
- 37654: {},
- 37662: {},
- 37665: {},
- 37671: {},
- 37678: {},
- 37680: {},
- 37682: {},
- 37693: {},
- 37697: {},
- 37705: {},
- 37713: {},
- 37721: {},
- 37963: {},
- 38008: {},
- 38009: {},
- 38019: {},
- 38067: {},
- 38077: {},
- 38136: {},
- 38186: {},
- 38193: {},
- 38195: {},
- 38198: {},
- 38201: {},
- 38203: {},
- 38209: {},
- 38227: {},
- 38235: {},
- 38247: {},
- 38264: {},
- 38266: {},
- 38322: {},
- 38442: {},
- 38466: {},
- 38511: {},
- 38527: {},
- 38553: {},
- 38565: {},
- 38600: {},
- 38623: {},
- 38710: {},
- 38742: {},
- 38800: {},
- 38819: {},
- 38841: {},
- 38875: {},
- 38901: {},
- 38919: {},
- 38987: {},
- 38999: {},
- 39007: {},
- 39010: {},
- 39013: {},
- 39032: {},
- 39067: {},
- 39120: {},
- 39122: {},
- 39184: {},
- 39216: {},
- 39232: {},
- 39251: {},
- 39273: {},
- 39280: {},
- 39344: {},
- 39351: {},
- 39354: {},
- 39375: {},
- 39386: {},
- 39397: {},
- 39402: {},
- 39455: {},
- 39501: {},
- 39507: {},
- 39544: {},
- 39574: {},
- 39603: {},
- 39608: {},
- 39611: {},
- 39642: {},
- 39647: {},
- 39650: {},
- 39699: {},
- 39737: {},
- 39766: {},
- 39798: {},
- 39823: {},
- 39824: {},
- 39826: {},
- 39891: {},
- 40029: {},
- 40065: {},
- 40788: {},
- 40945: {},
- 40980: {},
- 41011: {},
- 41032: {},
- 41046: {},
- 41096: {},
- 41124: {},
- 41164: {},
- 41202: {},
- 41228: {},
- 41230: {},
- 41273: {},
- 41275: {},
- 41313: {},
- 41329: {},
- 41330: {},
- 41371: {},
- 41378: {},
- 41435: {},
- 41454: {},
- 41496: {},
- 41549: {},
- 41557: {},
- 41563: {},
- 41564: {},
- 41627: {},
- 41676: {},
- 41697: {},
- 41704: {},
- 41733: {},
- 41738: {},
- 41750: {},
- 41798: {},
- 41820: {},
- 41833: {},
- 41872: {},
- 41881: {},
- 41897: {},
- 41937: {},
- 41956: {},
- 41966: {},
- 41997: {},
- 41998: {},
- 42003: {},
- 42013: {},
- 42082: {},
- 42090: {},
- 42109: {},
- 42183: {},
- 42232: {},
- 42298: {},
- 42306: {},
- 42313: {},
- 42334: {},
- 42337: {},
- 42437: {},
- 42455: {},
- 42525: {},
- 42532: {},
- 42541: {},
- 42555: {},
- 42560: {},
- 42571: {},
- 42580: {},
- 42581: {},
- 42610: {},
- 42652: {},
- 42673: {},
- 42682: {},
- 42689: {},
- 42708: {},
- 42713: {},
- 42772: {},
- 42779: {},
- 42781: {},
- 42828: {},
- 42837: {},
- 42841: {},
- 42863: {},
- 42864: {},
- 42908: {},
- 42912: {},
- 42925: {},
- 42947: {},
- 42956: {},
- 42960: {},
- 42961: {},
- 42991: {},
- 43019: {},
- 43060: {},
- 43094: {},
- 43139: {},
- 43197: {},
- 43205: {},
- 43242: {},
- 43248: {},
- 43341: {},
- 43350: {},
- 43447: {},
- 43451: {},
- 43452: {},
- 43456: {},
- 43513: {},
- 43529: {},
- 43533: {},
- 43557: {},
- 43568: {},
- 43612: {},
- 43627: {},
- 43653: {},
- 43700: {},
- 43708: {},
- 43733: {},
- 43754: {},
- 43766: {},
- 43824: {},
- 43870: {},
- 43883: {},
- 43892: {},
- 43905: {},
- 43925: {},
- 43939: {},
- 43940: {},
- 44021: {},
- 44027: {},
- 44034: {},
- 44086: {},
- 44087: {},
- 44134: {},
- 44143: {},
- 44208: {},
- 44213: {},
- 44217: {},
- 44244: {},
- 44247: {},
- 44272: {},
- 44285: {},
- 44327: {},
- 44377: {},
- 44391: {},
- 44395: {},
- 44436: {},
- 44477: {},
- 44483: {},
- 44489: {},
- 44546: {},
- 44558: {},
- 44566: {},
- 44631: {},
- 44702: {},
- 44725: {},
- 44735: {},
- 44869: {},
- 44901: {},
- 44925: {},
- 45007: {},
- 45090: {},
- 45102: {},
- 45143: {},
- 45177: {},
- 45178: {},
- 45193: {},
- 45230: {},
- 45245: {},
- 45271: {},
- 45305: {},
- 45345: {},
- 45355: {},
- 45356: {},
- 45410: {},
- 45430: {},
- 45458: {},
- 45461: {},
- 45498: {},
- 45543: {},
- 45558: {},
- 45588: {},
- 45609: {},
- 45629: {},
- 45637: {},
- 45650: {},
- 45669: {},
- 45727: {},
- 45754: {},
- 45758: {},
- 45763: {},
- 45766: {},
- 45773: {},
- 45879: {},
- 45891: {},
- 45899: {},
- 45905: {},
- 45916: {},
- 45918: {},
- 45925: {},
- 45935: {},
- 45960: {},
- 46198: {},
- 46408: {},
- 46562: {},
- 46573: {},
- 46650: {},
- 46868: {},
- 47116: {},
- 47132: {},
- 47139: {},
- 47159: {},
- 47169: {},
- 47217: {},
- 47232: {},
- 47237: {},
- 47253: {},
- 47304: {},
- 47331: {},
- 47377: {},
- 47394: {},
- 47402: {},
- 47485: {},
- 47499: {},
- 47524: {},
- 47583: {},
- 47588: {},
- 47589: {},
- 47782: {},
- 47790: {},
- 47798: {},
- 47881: {},
- 47883: {},
- 47887: {},
- 47898: {},
- 47956: {},
- 47959: {},
- 47962: {},
- 48092: {},
- 48161: {},
- 48190: {},
- 48206: {},
- 48252: {},
- 48288: {},
- 48359: {},
- 48431: {},
- 48437: {},
- 48492: {},
- 48503: {},
- 48506: {},
- 48551: {},
- 48629: {},
- 48675: {},
- 48685: {},
- 48695: {},
- 48728: {},
- 48830: {},
- 48832: {},
- 48847: {},
- 48887: {},
- 48917: {},
- 48926: {},
- 48953: {},
- 48966: {},
- 49040: {},
- 49044: {},
- 49056: {},
- 49100: {},
- 49101: {},
- 49103: {},
- 49115: {},
- 49117: {},
- 49129: {},
- 49183: {},
- 49221: {},
- 49223: {},
- 49242: {},
- 49273: {},
- 49282: {},
- 49392: {},
- 49528: {},
- 49561: {},
- 49567: {},
- 49628: {},
- 49724: {},
- 49770: {},
- 49798: {},
- 49800: {},
- 49808: {},
- 49826: {},
- 49889: {},
- 49902: {},
- 49914: {},
- 49981: {},
- 49985: {},
- 50010: {},
- 50025: {},
- 50084: {},
- 50181: {},
- 50186: {},
- 50223: {},
- 50231: {},
- 50242: {},
- 50251: {},
- 50266: {},
- 50274: {},
- 50304: {},
- 50316: {},
- 50334: {},
- 50349: {},
- 50411: {},
- 50463: {},
- 50467: {},
- 50500: {},
- 50581: {},
- 50593: {},
- 50597: {},
- 50613: {},
- 50616: {},
- 50627: {},
- 50635: {},
- 50648: {},
- 50670: {},
- 50673: {},
- 50685: {},
- 50710: {},
- 50718: {},
- 50749: {},
- 50767: {},
- 50810: {},
- 50821: {},
- 50825: {},
- 50925: {},
- 50953: {},
- 50959: {},
- 50962: {},
- 50973: {},
- 50979: {},
- 51018: {},
- 51056: {},
- 51074: {},
- 51110: {},
- 51167: {},
- 51175: {},
- 51184: {},
- 51207: {},
- 51265: {},
- 51319: {},
- 51336: {},
- 51342: {},
- 51346: {},
- 51375: {},
- 51395: {},
- 51407: {},
- 51430: {},
- 51495: {},
- 51504: {},
- 51582: {},
- 51604: {},
- 51615: {},
- 51653: {},
- 51684: {},
- 51765: {},
- 51784: {},
- 51809: {},
- 51825: {},
- 51852: {},
- 51896: {},
- 52075: {},
- 52145: {},
- 52195: {},
- 52228: {},
- 52233: {},
- 52238: {},
- 52242: {},
- 52253: {},
- 52257: {},
- 52260: {},
- 52262: {},
- 52263: {},
- 52286: {},
- 52312: {},
- 52322: {},
- 52323: {},
- 52341: {},
- 52361: {},
- 52362: {},
- 52363: {},
- 52373: {},
- 52381: {},
- 52398: {},
- 52405: {},
- 52409: {},
- 52412: {},
- 52433: {},
- 52436: {},
- 52444: {},
- 52455: {},
- 52465: {},
- 52468: {},
- 52471: {},
- 52613: {},
- 52783: {},
- 52974: {},
- 53006: {},
- 53667: {},
- 53764: {},
- 53913: {},
- 54198: {},
- 54252: {},
- 54614: {},
- 54825: {},
- 54994: {},
- 55330: {},
- 55391: {},
- 55392: {},
- 55424: {},
- 55427: {},
- 55430: {},
- 55501: {},
- 55577: {},
- 55685: {},
- 55699: {},
- 55769: {},
- 55805: {},
- 55821: {},
- 55836: {},
- 55850: {},
- 55853: {},
- 55872: {},
- 55900: {},
- 55915: {},
- 55933: {},
- 55943: {},
- 55944: {},
- 56017: {},
- 56030: {},
- 56040: {},
- 56041: {},
- 56042: {},
- 56044: {},
- 56046: {},
- 56047: {},
- 56048: {},
- 56055: {},
- 56089: {},
- 56099: {},
- 56120: {},
- 56167: {},
- 56207: {},
- 56231: {},
- 56262: {},
- 56293: {},
- 56300: {},
- 56329: {},
- 56349: {},
- 56478: {},
- 56484: {},
- 56491: {},
- 56497: {},
- 56568: {},
- 56653: {},
- 56655: {},
- 56665: {},
- 56696: {},
- 56704: {},
- 56747: {},
- 56902: {},
- 57013: {},
- 57016: {},
- 57043: {},
- 57070: {},
- 57112: {},
- 57133: {},
- 57134: {},
- 57218: {},
- 57223: {},
- 57248: {},
- 57256: {},
- 57269: {},
- 57293: {},
- 57344: {},
- 57370: {},
- 57374: {},
- 57388: {},
- 57389: {},
- 57491: {},
- 57513: {},
- 57564: {},
- 57566: {},
- 57588: {},
- 57608: {},
- 57630: {},
- 57722: {},
- 57728: {},
- 57760: {},
- 57761: {},
- 57764: {},
- 57794: {},
- 57852: {},
- 57869: {},
- 57888: {},
- 58056: {},
- 58061: {},
- 58065: {},
- 58098: {},
- 58130: {},
- 58224: {},
- 58254: {},
- 58264: {},
- 58322: {},
- 58328: {},
- 58453: {},
- 58460: {},
- 58461: {},
- 58485: {},
- 58504: {},
- 58507: {},
- 58524: {},
- 58610: {},
- 58656: {},
- 58682: {},
- 58689: {},
- 58715: {},
- 58717: {},
- 58731: {},
- 58821: {},
- 58893: {},
- 58895: {},
- 58945: {},
- 58952: {},
- 59078: {},
- 59125: {},
- 59126: {},
- 59127: {},
- 59253: {},
- 59257: {},
- 59362: {},
- 59371: {},
- 59381: {},
- 59443: {},
- 59497: {},
- 59588: {},
- 59625: {},
- 59668: {},
- 59702: {},
- 59729: {},
- 59847: {},
- 59861: {},
- 59890: {},
- 59931: {},
- 59989: {},
- 60016: {},
- 60068: {},
- 60258: {},
- 60294: {},
- 60352: {},
- 60367: {},
- 60372: {},
- 60377: {},
- 60398: {},
- 60471: {},
- 60517: {},
- 60636: {},
- 60725: {},
- 60757: {},
- 60781: {},
- 60806: {},
- 60895: {},
- 60999: {},
- 61010: {},
- 61071: {},
- 61135: {},
- 61143: {},
- 61154: {},
- 61189: {},
- 61272: {},
- 61275: {},
- 61287: {},
- 61307: {},
- 61317: {},
- 61461: {},
- 61466: {},
- 61478: {},
- 61512: {},
- 61996: {},
- 62005: {},
- 62013: {},
- 62099: {},
- 62161: {},
- 62179: {},
- 62183: {},
- 62211: {},
- 62212: {},
- 62240: {},
- 62250: {},
- 62337: {},
- 62563: {},
- 63023: {},
- 63199: {},
- 63526: {},
- 63852: {},
- 63859: {},
- 63945: {},
- 63949: {},
- 63969: {},
- 63991: {},
- 63996: {},
- 64022: {},
- 64043: {},
- 64073: {},
- 64098: {},
- 64105: {},
- 64126: {},
- 64134: {},
- 64270: {},
- 64286: {},
- 64443: {},
- 64466: {},
- 131090: {},
- 131111: {},
- 131178: {},
- 131207: {},
- 131267: {},
- 131284: {},
- 131429: {},
- 131445: {},
- 131464: {},
- 131471: {},
- 131591: {},
- 131596: {},
- 131627: {},
- 131706: {},
- 131769: {},
- 132045: {},
- 132061: {},
- 132080: {},
- 132148: {},
- 132165: {},
- 132167: {},
- 132173: {},
- 132199: {},
- 132203: {},
- 132222: {},
- 132298: {},
- 132429: {},
- 132447: {},
- 132449: {},
- 132462: {},
- 132468: {},
- 132471: {},
- 132513: {},
- 132525: {},
- 132618: {},
- 132686: {},
- 132831: {},
- 132857: {},
- 133012: {},
- 133076: {},
- 133206: {},
- 133287: {},
- 133334: {},
- 133384: {},
- 133385: {},
- 133481: {},
- 133524: {},
- 133533: {},
- 133579: {},
- 133606: {},
- 133612: {},
- 133623: {},
- 133661: {},
- 133748: {},
- 133752: {},
- 133875: {},
- 133894: {},
- 133982: {},
- 134090: {},
- 134113: {},
- 134134: {},
- 134204: {},
- 134356: {},
- 134467: {},
- 134489: {},
- 134562: {},
- 134651: {},
- 134674: {},
- 134697: {},
- 134707: {},
- 134714: {},
- 134715: {},
- 134732: {},
- 134739: {},
- 134762: {},
- 134774: {},
- 134783: {},
- 134806: {},
- 134840: {},
- 134972: {},
- 134995: {},
- 135043: {},
- 135069: {},
- 135126: {},
- 135298: {},
- 135300: {},
- 135327: {},
- 135341: {},
- 135375: {},
- 135376: {},
- 135377: {},
- 135405: {},
- 135407: {},
- 135409: {},
- 135477: {},
- 135478: {},
- 135589: {},
- 135600: {},
- 135607: {},
- 135887: {},
- 136030: {},
- 136039: {},
- 136093: {},
- 136119: {},
- 136141: {},
- 136167: {},
- 136210: {},
- 136224: {},
- 136238: {},
- 136255: {},
- 136258: {},
- 136380: {},
- 136384: {},
- 136400: {},
- 136442: {},
- 136454: {},
- 136477: {},
- 136479: {},
- 136480: {},
- 136515: {},
- 136525: {},
- 136538: {},
- 136557: {},
- 136787: {},
- 136873: {},
- 136897: {},
- 136907: {},
- 136950: {},
- 136969: {},
- 136994: {},
- 137047: {},
- 137080: {},
- 137226: {},
- 137236: {},
- 137409: {},
- 137412: {},
- 137424: {},
- 137449: {},
- 137453: {},
- 137477: {},
- 137526: {},
- 137561: {},
- 137811: {},
- 137824: {},
- 137853: {},
- 137872: {},
- 137891: {},
- 137895: {},
- 137959: {},
- 137967: {},
- 137989: {},
- 138064: {},
- 138089: {},
- 138179: {},
- 138197: {},
- 138368: {},
- 138384: {},
- 138423: {},
- 138529: {},
- 138590: {},
- 138606: {},
- 138634: {},
- 138655: {},
- 138754: {},
- 138886: {},
- 138997: {},
- 139009: {},
- 139029: {},
- 139043: {},
- 139224: {},
- 139285: {},
- 139325: {},
- 139580: {},
- 139609: {},
- 139628: {},
- 139741: {},
- 139759: {},
- 139831: {},
- 139841: {},
- 139879: {},
- 139898: {},
- 139922: {},
- 139967: {},
- 139981: {},
- 139994: {},
- 140045: {},
- 140061: {},
- 140072: {},
- 140100: {},
- 140210: {},
- 140220: {},
- 140265: {},
- 140292: {},
- 140330: {},
- 140401: {},
- 140499: {},
- 140504: {},
- 140726: {},
- 140900: {},
- 140989: {},
- 141015: {},
- 141024: {},
- 141031: {},
- 141047: {},
- 141145: {},
- 141212: {},
- 141216: {},
- 141224: {},
- 141226: {},
- 141421: {},
- 141607: {},
- 141680: {},
- 141681: {},
- 141711: {},
- 141767: {},
- 141995: {},
- 142032: {},
- 142065: {},
- 142120: {},
- 142352: {},
- 142552: {},
- 147049: {},
- 147184: {},
- 149024: {},
- 149034: {},
- 149360: {},
- 149660: {},
- 149707: {},
- 149768: {},
- 149771: {},
- 149866: {},
- 150131: {},
- 150153: {},
- 150155: {},
- 150371: {},
- 150683: {},
- 150692: {},
- 150750: {},
- 150774: {},
- 151080: {},
- 151396: {},
- 196640: {},
- 196735: {},
- 196838: {},
- 196874: {},
- 196925: {},
- 196961: {},
- 197071: {},
- 197077: {},
- 197119: {},
- 197207: {},
- 197225: {},
- 197248: {},
- 197296: {},
- 197301: {},
- 197350: {},
- 197398: {},
- 197423: {},
- 197556: {},
- 197623: {},
- 197663: {},
- 197674: {},
- 197704: {},
- 197706: {},
- 197830: {},
- 197862: {},
- 197882: {},
- 197897: {},
- 198068: {},
- 198252: {},
- 198259: {},
- 198265: {},
- 198279: {},
- 198288: {},
- 198440: {},
- 198441: {},
- 198471: {},
- 198589: {},
- 198605: {},
- 198632: {},
- 198651: {},
- 198668: {},
- 198735: {},
- 198785: {},
- 198820: {},
- 198961: {},
- 198966: {},
- 199128: {},
- 199140: {},
- 199274: {},
- 199276: {},
- 199284: {},
- 199346: {},
- 199469: {},
- 199490: {},
- 199493: {},
- 199524: {},
- 199620: {},
- 199636: {},
- 199698: {},
- 199731: {},
- 199739: {},
- 199995: {},
- 200088: {},
- 200134: {},
- 200154: {},
- 200313: {},
- 200436: {},
- 200446: {},
- 200590: {},
- 200640: {},
- 200651: {},
- 200665: {},
- 200697: {},
- 200724: {},
- 200736: {},
- 200740: {},
- 200742: {},
- 200845: {},
- 200865: {},
- 201019: {},
- 201073: {},
- 201150: {},
- 201167: {},
- 201187: {},
- 201241: {},
- 201249: {},
- 201290: {},
- 201411: {},
- 201476: {},
- 201502: {},
- 201505: {},
- 201603: {},
- 201749: {},
- 201767: {},
- 201776: {},
- 201838: {},
- 201884: {},
- 201890: {},
- 201986: {},
- 201997: {},
- 202085: {},
- 202087: {},
- 202098: {},
- 202103: {},
- 202204: {},
- 202254: {},
- 202293: {},
- 202354: {},
- 202422: {},
- 202433: {},
- 202441: {},
- 202448: {},
- 202468: {},
- 202498: {},
- 202561: {},
- 202613: {},
- 202632: {},
- 202662: {},
- 202672: {},
- 202699: {},
- 202870: {},
- 202914: {},
- 202921: {},
- 202931: {},
- 202940: {},
- 202987: {},
- 203020: {},
- 203136: {},
- 203206: {},
- 203214: {},
- 203217: {},
- 203409: {},
- 203424: {},
- 203448: {},
- 203451: {},
- 203459: {},
- 203561: {},
- 203622: {},
- 203675: {},
- 203680: {},
- 203735: {},
- 203811: {},
- 203877: {},
- 203912: {},
- 203953: {},
- 203964: {},
- 203971: {},
- 203995: {},
- 203999: {},
- 204106: {},
- 204108: {},
- 204151: {},
- 204165: {},
- 204170: {},
- 204171: {},
- 204267: {},
- 204274: {},
- 204279: {},
- 204342: {},
- 204356: {},
- 204390: {},
- 204393: {},
- 204403: {},
- 204429: {},
- 204467: {},
- 204566: {},
- 204595: {},
- 204649: {},
- 204731: {},
- 204802: {},
- 204804: {},
- 204873: {},
- 204894: {},
- 204902: {},
- 204918: {},
- 204957: {},
- 205015: {},
- 205110: {},
- 205119: {},
- 205168: {},
- 205244: {},
- 205254: {},
- 205278: {},
- 205285: {},
- 205293: {},
- 205362: {},
- 205367: {},
- 205368: {},
- 205371: {},
- 205400: {},
- 205473: {},
- 205547: {},
- 205619: {},
- 205638: {},
- 205647: {},
- 205714: {},
- 205832: {},
- 205889: {},
- 205984: {},
- 206026: {},
- 206065: {},
- 206067: {},
- 206119: {},
- 206194: {},
- 206206: {},
- 206238: {},
- 206262: {},
- 206283: {},
- 206358: {},
- 206375: {},
- 206406: {},
- 206446: {},
- 206471: {},
- 206485: {},
- 206557: {},
- 206610: {},
- 206611: {},
- 206641: {},
- 206666: {},
- 206774: {},
- 206783: {},
- 206920: {},
- 206977: {},
- 207044: {},
- 207081: {},
- 207097: {},
- 207137: {},
- 207154: {},
- 207164: {},
- 207187: {},
- 207192: {},
- 207251: {},
- 207348: {},
- 207355: {},
- 207369: {},
- 207375: {},
- 207493: {},
- 207541: {},
- 207569: {},
- 207589: {},
- 207651: {},
- 207713: {},
- 207728: {},
- 207782: {},
- 207786: {},
- 207790: {},
- 207810: {},
- 207876: {},
- 207980: {},
- 207990: {},
- 207991: {},
- 208286: {},
- 208320: {},
- 208339: {},
- 208365: {},
- 208555: {},
- 208592: {},
- 208645: {},
- 208670: {},
- 208730: {},
- 208734: {},
- 208888: {},
- 208905: {},
- 208909: {},
- 208972: {},
- 208997: {},
- 209001: {},
- 209012: {},
- 209046: {},
- 209049: {},
- 209240: {},
- 209262: {},
- 209277: {},
- 209360: {},
- 209424: {},
- 209442: {},
- 209491: {},
- 209641: {},
- 209839: {},
- 209854: {},
- 210003: {},
- 210021: {},
- 210079: {},
- 210095: {},
- 210125: {},
- 210147: {},
- 210150: {},
- 210218: {},
- 210273: {},
- 210278: {},
- 210315: {},
- 210402: {},
- 210616: {},
- 210625: {},
- 210644: {},
- 210748: {},
- 210808: {},
- 210964: {},
- 210974: {},
- 211028: {},
- 211057: {},
- 211098: {},
- 211210: {},
- 211211: {},
- 211356: {},
- 211385: {},
- 211450: {},
- 211468: {},
- 211504: {},
- 211555: {},
- 211559: {},
- 211790: {},
- 211913: {},
- 211995: {},
- 212046: {},
- 212183: {},
- 212238: {},
- 212330: {},
- 212444: {},
- 212449: {},
- 212531: {},
- 212572: {},
- 212616: {},
- 212637: {},
- 212645: {},
- 212655: {},
- 212661: {},
- 212752: {},
- 212766: {},
- 212865: {},
- 212897: {},
- 212898: {},
- 212910: {},
- 212999: {},
- 213155: {},
- 213250: {},
- 213261: {},
- 213295: {},
- 213373: {},
- 213398: {},
- 213402: {},
- 262145: {},
- 262146: {},
- 262159: {},
- 262179: {},
- 262181: {},
- 262186: {},
- 262188: {},
- 262191: {},
- 262197: {},
- 262202: {},
- 262210: {},
- 262215: {},
- 262221: {},
- 262223: {},
- 262234: {},
- 262239: {},
- 262241: {},
- 262253: {},
- 262262: {},
- 262354: {},
- 262378: {},
- 262459: {},
- 262468: {},
- 262481: {},
- 262589: {},
- 262663: {},
- 262753: {},
- 262773: {},
- 262916: {},
- 262932: {},
- 263073: {},
- 263170: {},
- 263175: {},
- 263189: {},
- 263210: {},
- 263222: {},
- 263224: {},
- 263238: {},
- 263242: {},
- 263245: {},
- 263327: {},
- 263686: {},
- 263689: {},
- 263694: {},
- 263698: {},
- 263699: {},
- 263702: {},
- 263703: {},
- 263717: {},
- 263725: {},
- 263749: {},
- 263750: {},
- 263751: {},
- 263761: {},
- 263762: {},
- 263763: {},
- 263765: {},
- 263781: {},
- 263783: {},
- 263791: {},
- 263792: {},
- 263793: {},
- 263805: {},
- 263809: {},
- 263824: {},
- 263980: {},
- 264605: {},
- 264609: {},
- 264628: {},
- 264635: {},
- 264637: {},
- 264640: {},
- 264642: {},
- 264645: {},
- 264646: {},
- 264663: {},
- 264668: {},
- 264681: {},
- 264685: {},
- 264694: {},
- 264696: {},
- 264731: {},
- 264733: {},
- 264738: {},
- 264744: {},
- 264746: {},
- 264750: {},
- 264756: {},
- 264770: {},
- 264778: {},
- 264779: {},
- 264780: {},
- 264783: {},
- 264796: {},
- 264800: {},
- 264814: {},
- 264821: {},
- 264825: {},
- 264837: {},
- 264838: {},
- 264844: {},
- 264847: {},
- 265509: {},
- 265540: {},
- 265594: {},
- 265605: {},
- 265631: {},
- 265632: {},
- 265633: {},
- 265636: {},
- 265675: {},
- 265684: {},
- 265688: {},
- 265691: {},
- 265698: {},
- 265706: {},
- 265711: {},
- 265721: {},
- 265724: {},
- 265727: {},
- 265767: {},
- 265780: {},
- 265798: {},
- 265799: {},
- 265816: {},
- 265818: {},
- 265822: {},
- 265855: {},
- 265862: {},
- 265867: {},
- 266445: {},
- 266668: {},
- 266673: {},
- 266677: {},
- 266698: {},
- 266725: {},
- 266730: {},
- 266734: {},
- 266742: {},
- 266755: {},
- 266779: {},
- 266783: {},
- 266792: {},
- 266802: {},
- 266809: {},
- 266814: {},
- 266815: {},
- 266832: {},
- 266841: {},
- 266853: {},
- 266858: {},
- 266860: {},
- 266870: {},
- 266880: {},
- 266893: {},
- 266894: {},
- 266904: {},
- 267684: {},
- 267685: {},
- 267699: {},
- 267705: {},
- 267708: {},
- 267713: {},
- 267749: {},
- 267761: {},
- 267765: {},
- 267790: {},
- 267795: {},
- 267797: {},
- 267803: {},
- 267809: {},
- 267828: {},
- 267837: {},
- 267845: {},
- 267846: {},
- 267882: {},
- 267883: {},
- 267904: {},
- 267917: {},
- 268323: {},
- 268976: {},
- 269725: {},
- 269729: {},
- 269730: {},
- 269733: {},
- 269734: {},
- 269736: {},
- 269738: {},
- 269748: {},
- 269749: {},
- 269750: {},
- 269763: {},
- 269769: {},
- 269780: {},
- 269782: {},
- 269783: {},
- 269788: {},
- 269797: {},
- 269804: {},
- 269806: {},
- 269816: {},
- 269820: {},
- 269822: {},
- 269831: {},
- 269832: {},
- 269838: {},
- 269840: {},
- 269843: {},
- 269846: {},
- 269853: {},
- 269857: {},
- 269862: {},
- 269894: {},
- 269901: {},
- 269908: {},
- 269919: {},
- 269921: {},
- 269927: {},
- 269931: {},
- 269934: {},
- 269936: {},
- 269940: {},
- 269946: {},
- 269950: {},
- 269953: {},
- 269955: {},
- 269965: {},
- 269974: {},
- 269976: {},
- 270026: {},
- 270029: {},
- 270035: {},
- 270036: {},
- 270049: {},
- 270052: {},
- 270058: {},
- 270068: {},
- 270071: {},
- 270096: {},
- 270098: {},
- 270108: {},
- 270161: {},
- 270814: {},
- 271773: {},
- 271785: {},
- 271791: {},
- 271793: {},
- 271795: {},
- 271799: {},
- 271806: {},
- 271808: {},
- 271812: {},
- 271814: {},
- 271819: {},
- 271822: {},
- 271835: {},
- 271837: {},
- 271855: {},
- 271868: {},
- 271874: {},
- 271899: {},
- 271907: {},
- 271909: {},
- 271911: {},
- 271929: {},
- 271930: {},
- 271935: {},
- 271942: {},
- 271965: {},
- 271971: {},
- 271978: {},
- 271985: {},
- 271988: {},
- 272011: {},
- 272015: {},
- 272025: {},
- 272026: {},
- 272057: {},
- 272062: {},
- 272083: {},
- 272102: {},
- 272110: {},
- 272112: {},
- 272120: {},
- 272122: {},
- 272134: {},
- 272809: {},
- 272818: {},
- 272836: {},
- 272853: {},
- 272867: {},
- 272882: {},
- 272916: {},
- 272946: {},
- 272955: {},
- 327687: {},
- 327693: {},
- 327697: {},
- 327707: {},
- 327712: {},
- 327714: {},
- 327716: {},
- 327724: {},
- 327725: {},
- 327728: {},
- 327738: {},
- 327747: {},
- 327750: {},
- 327756: {},
- 327765: {},
- 327768: {},
- 327769: {},
- 327770: {},
- 327776: {},
- 327782: {},
- 327786: {},
- 327799: {},
- 327802: {},
- 327819: {},
- 327828: {},
- 327830: {},
- 327862: {},
- 327864: {},
- 327871: {},
- 327879: {},
- 327885: {},
- 327900: {},
- 327901: {},
- 327903: {},
- 327931: {},
- 327932: {},
- 327934: {},
- 327947: {},
- 327956: {},
- 327972: {},
- 327975: {},
- 327987: {},
- 327991: {},
- 327996: {},
- 328061: {},
- 328073: {},
- 328075: {},
- 328079: {},
- 328088: {},
- 328111: {},
- 328136: {},
- 328140: {},
- 328144: {},
- 328169: {},
- 328178: {},
- 328191: {},
- 328196: {},
- 328198: {},
- 328200: {},
- 328207: {},
- 328223: {},
- 328228: {},
- 328244: {},
- 328250: {},
- 328253: {},
- 328258: {},
- 328271: {},
- 328286: {},
- 328297: {},
- 328304: {},
- 328309: {},
- 328310: {},
- 328316: {},
- 328319: {},
- 328331: {},
- 328341: {},
- 328358: {},
- 328411: {},
- 328436: {},
- 328442: {},
- 328469: {},
- 328471: {},
- 328473: {},
- 328475: {},
- 328479: {},
- 328480: {},
- 328488: {},
- 328490: {},
- 328494: {},
- 328500: {},
- 328509: {},
- 328510: {},
- 328514: {},
- 328535: {},
- 328539: {},
- 328546: {},
- 328549: {},
- 328566: {},
- 328570: {},
- 328581: {},
- 328586: {},
- 328590: {},
- 328594: {},
- 328605: {},
- 328608: {},
- 328610: {},
- 328611: {},
- 328614: {},
- 328619: {},
- 328636: {},
- 328638: {},
- 328652: {},
- 328659: {},
- 328676: {},
- 328679: {},
- 328697: {},
- 328702: {},
- 328708: {},
- 328727: {},
- 328733: {},
- 328734: {},
- 328753: {},
- 328755: {},
- 328770: {},
- 328817: {},
- 328835: {},
- 328844: {},
- 328850: {},
- 328856: {},
- 328858: {},
- 328880: {},
- 328887: {},
- 328891: {},
- 328895: {},
- 328919: {},
- 328923: {},
- 328941: {},
- 328943: {},
- 328954: {},
- 328959: {},
- 328961: {},
- 328965: {},
- 328975: {},
- 328977: {},
- 328987: {},
- 328988: {},
- 328993: {},
- 328997: {},
- 329014: {},
- 329027: {},
- 329028: {},
- 329029: {},
- 329044: {},
- 329048: {},
- 329074: {},
- 329078: {},
- 329082: {},
- 329101: {},
- 329103: {},
- 329129: {},
- 329135: {},
- 329167: {},
- 329170: {},
- 329174: {},
- 329177: {},
- 329183: {},
- 329192: {},
- 329205: {},
- 329211: {},
- 393275: {},
- 393629: {},
- 393894: {},
- 394311: {},
- 394381: {},
- 395561: {},
- 395570: {},
- 395965: {},
- 396304: {},
- 396338: {},
- 396357: {},
- 396982: {},
- 397563: {},
- 397961: {},
- 398228: {},
- 398721: {},
- 399382: {},
- 399674: {},
- 399686: {},
- 399724: {},
- 400266: {},
-}
+var DefaultTopASNs = container.NewMapSet[ASN](
+ 2,
+ 3,
+ 6,
+ 174,
+ 209,
+ 224,
+ 577,
+ 701,
+ 719,
+ 803,
+ 812,
+ 852,
+ 855,
+ 906,
+ 932,
+ 967,
+ 1136,
+ 1213,
+ 1221,
+ 1241,
+ 1257,
+ 1267,
+ 1299,
+ 1403,
+ 1443,
+ 1547,
+ 1659,
+ 1680,
+ 1741,
+ 1759,
+ 1835,
+ 1836,
+ 1897,
+ 1955,
+ 2018,
+ 2107,
+ 2108,
+ 2110,
+ 2116,
+ 2119,
+ 2497,
+ 2514,
+ 2516,
+ 2518,
+ 2519,
+ 2527,
+ 2586,
+ 2588,
+ 2607,
+ 2609,
+ 2740,
+ 2847,
+ 2852,
+ 2856,
+ 2860,
+ 3132,
+ 3209,
+ 3212,
+ 3215,
+ 3216,
+ 3221,
+ 3223,
+ 3225,
+ 3238,
+ 3243,
+ 3249,
+ 3255,
+ 3258,
+ 3269,
+ 3292,
+ 3301,
+ 3303,
+ 3308,
+ 3320,
+ 3326,
+ 3329,
+ 3352,
+ 3356,
+ 3363,
+ 3399,
+ 3462,
+ 3549,
+ 3559,
+ 3605,
+ 3695,
+ 3737,
+ 3741,
+ 3758,
+ 3786,
+ 3816,
+ 3855,
+ 4007,
+ 4134,
+ 4181,
+ 4230,
+ 4515,
+ 4538,
+ 4540,
+ 4609,
+ 4638,
+ 4657,
+ 4685,
+ 4713,
+ 4721,
+ 4725,
+ 4739,
+ 4760,
+ 4761,
+ 4764,
+ 4766,
+ 4768,
+ 4771,
+ 4773,
+ 4775,
+ 4780,
+ 4788,
+ 4804,
+ 4808,
+ 4812,
+ 4817,
+ 4818,
+ 4837,
+ 4847,
+ 5089,
+ 5378,
+ 5384,
+ 5390,
+ 5391,
+ 5410,
+ 5413,
+ 5416,
+ 5432,
+ 5466,
+ 5483,
+ 5504,
+ 5518,
+ 5532,
+ 5578,
+ 5603,
+ 5607,
+ 5610,
+ 5617,
+ 5639,
+ 5645,
+ 5650,
+ 5713,
+ 5769,
+ 6057,
+ 6079,
+ 6128,
+ 6147,
+ 6167,
+ 6181,
+ 6306,
+ 6327,
+ 6400,
+ 6407,
+ 6535,
+ 6568,
+ 6621,
+ 6639,
+ 6661,
+ 6677,
+ 6697,
+ 6700,
+ 6703,
+ 6713,
+ 6730,
+ 6739,
+ 6752,
+ 6758,
+ 6772,
+ 6799,
+ 6805,
+ 6810,
+ 6821,
+ 6830,
+ 6843,
+ 6848,
+ 6849,
+ 6855,
+ 6866,
+ 6871,
+ 6876,
+ 6939,
+ 7018,
+ 7029,
+ 7049,
+ 7057,
+ 7122,
+ 7131,
+ 7303,
+ 7315,
+ 7418,
+ 7438,
+ 7470,
+ 7477,
+ 7482,
+ 7497,
+ 7522,
+ 7524,
+ 7545,
+ 7552,
+ 7565,
+ 7642,
+ 7679,
+ 7713,
+ 7727,
+ 7738,
+ 7794,
+ 7862,
+ 7922,
+ 7992,
+ 8014,
+ 8048,
+ 8053,
+ 8075,
+ 8151,
+ 8167,
+ 8193,
+ 8200,
+ 8251,
+ 8257,
+ 8273,
+ 8290,
+ 8301,
+ 8339,
+ 8346,
+ 8359,
+ 8369,
+ 8374,
+ 8376,
+ 8386,
+ 8400,
+ 8402,
+ 8412,
+ 8422,
+ 8437,
+ 8445,
+ 8447,
+ 8449,
+ 8452,
+ 8462,
+ 8473,
+ 8542,
+ 8544,
+ 8551,
+ 8560,
+ 8585,
+ 8612,
+ 8632,
+ 8661,
+ 8680,
+ 8681,
+ 8697,
+ 8708,
+ 8717,
+ 8728,
+ 8758,
+ 8764,
+ 8767,
+ 8772,
+ 8781,
+ 8814,
+ 8818,
+ 8821,
+ 8847,
+ 8849,
+ 8866,
+ 8881,
+ 8887,
+ 8896,
+ 8926,
+ 8948,
+ 8953,
+ 8966,
+ 8978,
+ 8990,
+ 9002,
+ 9008,
+ 9009,
+ 9031,
+ 9038,
+ 9044,
+ 9050,
+ 9051,
+ 9063,
+ 9070,
+ 9105,
+ 9119,
+ 9121,
+ 9123,
+ 9125,
+ 9129,
+ 9145,
+ 9146,
+ 9155,
+ 9158,
+ 9198,
+ 9231,
+ 9245,
+ 9246,
+ 9249,
+ 9260,
+ 9269,
+ 9299,
+ 9304,
+ 9312,
+ 9316,
+ 9318,
+ 9329,
+ 9335,
+ 9341,
+ 9351,
+ 9354,
+ 9365,
+ 9381,
+ 9416,
+ 9432,
+ 9443,
+ 9471,
+ 9484,
+ 9500,
+ 9506,
+ 9534,
+ 9541,
+ 9595,
+ 9605,
+ 9617,
+ 9621,
+ 9644,
+ 9674,
+ 9676,
+ 9751,
+ 9781,
+ 9790,
+ 9808,
+ 9824,
+ 9829,
+ 9845,
+ 9873,
+ 9876,
+ 9902,
+ 9908,
+ 9919,
+ 9922,
+ 9924,
+ 9930,
+ 9931,
+ 9934,
+ 9976,
+ 9988,
+ 10010,
+ 10013,
+ 10030,
+ 10036,
+ 10066,
+ 10075,
+ 10085,
+ 10094,
+ 10099,
+ 10118,
+ 10131,
+ 10139,
+ 10143,
+ 10214,
+ 10219,
+ 10226,
+ 10269,
+ 10292,
+ 10299,
+ 10396,
+ 10474,
+ 10620,
+ 10796,
+ 11014,
+ 11081,
+ 11139,
+ 11172,
+ 11259,
+ 11260,
+ 11290,
+ 11315,
+ 11351,
+ 11426,
+ 11427,
+ 11492,
+ 11556,
+ 11562,
+ 11594,
+ 11664,
+ 11776,
+ 11814,
+ 11816,
+ 11830,
+ 11845,
+ 11888,
+ 11992,
+ 12066,
+ 12083,
+ 12091,
+ 12252,
+ 12271,
+ 12297,
+ 12301,
+ 12302,
+ 12322,
+ 12334,
+ 12338,
+ 12353,
+ 12365,
+ 12389,
+ 12390,
+ 12392,
+ 12400,
+ 12406,
+ 12414,
+ 12426,
+ 12430,
+ 12436,
+ 12455,
+ 12479,
+ 12491,
+ 12496,
+ 12508,
+ 12552,
+ 12570,
+ 12576,
+ 12578,
+ 12605,
+ 12668,
+ 12709,
+ 12714,
+ 12716,
+ 12735,
+ 12741,
+ 12754,
+ 12764,
+ 12767,
+ 12810,
+ 12829,
+ 12849,
+ 12874,
+ 12876,
+ 12912,
+ 12929,
+ 12946,
+ 12958,
+ 12969,
+ 12975,
+ 12978,
+ 12997,
+ 13000,
+ 13030,
+ 13036,
+ 13037,
+ 13044,
+ 13045,
+ 13046,
+ 13099,
+ 13101,
+ 13110,
+ 13122,
+ 13124,
+ 13127,
+ 13156,
+ 13170,
+ 13188,
+ 13189,
+ 13194,
+ 13208,
+ 13213,
+ 13280,
+ 13285,
+ 13306,
+ 13335,
+ 13489,
+ 13771,
+ 13999,
+ 14061,
+ 14080,
+ 14117,
+ 14259,
+ 14434,
+ 14522,
+ 14593,
+ 14618,
+ 14638,
+ 14709,
+ 14754,
+ 14813,
+ 14868,
+ 14979,
+ 14988,
+ 15146,
+ 15344,
+ 15366,
+ 15377,
+ 15378,
+ 15389,
+ 15397,
+ 15399,
+ 15404,
+ 15433,
+ 15435,
+ 15457,
+ 15474,
+ 15480,
+ 15502,
+ 15511,
+ 15516,
+ 15525,
+ 15547,
+ 15557,
+ 15600,
+ 15614,
+ 15623,
+ 15659,
+ 15704,
+ 15706,
+ 15723,
+ 15735,
+ 15751,
+ 15766,
+ 15774,
+ 15796,
+ 15802,
+ 15805,
+ 15808,
+ 15836,
+ 15895,
+ 15897,
+ 15924,
+ 15943,
+ 15955,
+ 15958,
+ 15962,
+ 15964,
+ 15975,
+ 15994,
+ 16006,
+ 16010,
+ 16019,
+ 16028,
+ 16058,
+ 16082,
+ 16086,
+ 16116,
+ 16117,
+ 16135,
+ 16178,
+ 16190,
+ 16202,
+ 16223,
+ 16232,
+ 16246,
+ 16276,
+ 16281,
+ 16322,
+ 16333,
+ 16342,
+ 16345,
+ 16354,
+ 16437,
+ 16509,
+ 16591,
+ 16592,
+ 16629,
+ 16637,
+ 16705,
+ 16735,
+ 16814,
+ 16906,
+ 16960,
+ 17072,
+ 17079,
+ 17400,
+ 17411,
+ 17421,
+ 17451,
+ 17458,
+ 17470,
+ 17480,
+ 17488,
+ 17501,
+ 17506,
+ 17511,
+ 17529,
+ 17547,
+ 17551,
+ 17552,
+ 17557,
+ 17621,
+ 17622,
+ 17623,
+ 17638,
+ 17639,
+ 17665,
+ 17670,
+ 17676,
+ 17698,
+ 17705,
+ 17716,
+ 17726,
+ 17809,
+ 17816,
+ 17828,
+ 17849,
+ 17853,
+ 17858,
+ 17882,
+ 17893,
+ 17924,
+ 17976,
+ 17981,
+ 17993,
+ 18001,
+ 18004,
+ 18013,
+ 18024,
+ 18049,
+ 18053,
+ 18081,
+ 18106,
+ 18126,
+ 18144,
+ 18182,
+ 18199,
+ 18200,
+ 18209,
+ 18371,
+ 18390,
+ 18399,
+ 18403,
+ 18412,
+ 18419,
+ 18429,
+ 18734,
+ 18747,
+ 18809,
+ 18822,
+ 18840,
+ 18881,
+ 19037,
+ 19108,
+ 19114,
+ 19180,
+ 19182,
+ 19246,
+ 19422,
+ 19429,
+ 19515,
+ 19624,
+ 19711,
+ 19863,
+ 19889,
+ 19978,
+ 20001,
+ 20011,
+ 20055,
+ 20057,
+ 20115,
+ 20207,
+ 20255,
+ 20294,
+ 20299,
+ 20365,
+ 20473,
+ 20485,
+ 20626,
+ 20634,
+ 20661,
+ 20676,
+ 20712,
+ 20723,
+ 20771,
+ 20776,
+ 20804,
+ 20845,
+ 20846,
+ 20875,
+ 20880,
+ 20910,
+ 20911,
+ 20928,
+ 20960,
+ 20963,
+ 20978,
+ 21001,
+ 21003,
+ 21021,
+ 21040,
+ 21050,
+ 21107,
+ 21127,
+ 21183,
+ 21211,
+ 21230,
+ 21232,
+ 21246,
+ 21271,
+ 21277,
+ 21283,
+ 21299,
+ 21331,
+ 21334,
+ 21351,
+ 21412,
+ 21430,
+ 21450,
+ 21491,
+ 21497,
+ 21502,
+ 21559,
+ 21575,
+ 21599,
+ 21744,
+ 21804,
+ 21826,
+ 21859,
+ 21928,
+ 21949,
+ 21996,
+ 22047,
+ 22069,
+ 22085,
+ 22423,
+ 22581,
+ 22724,
+ 22773,
+ 22869,
+ 22884,
+ 22927,
+ 22933,
+ 22995,
+ 23114,
+ 23201,
+ 23243,
+ 23383,
+ 23470,
+ 23487,
+ 23520,
+ 23655,
+ 23673,
+ 23674,
+ 23688,
+ 23693,
+ 23700,
+ 23750,
+ 23752,
+ 23764,
+ 23860,
+ 23889,
+ 23917,
+ 23923,
+ 23944,
+ 23955,
+ 23956,
+ 23969,
+ 24016,
+ 24033,
+ 24086,
+ 24157,
+ 24158,
+ 24164,
+ 24186,
+ 24203,
+ 24309,
+ 24337,
+ 24378,
+ 24389,
+ 24400,
+ 24432,
+ 24439,
+ 24441,
+ 24444,
+ 24445,
+ 24492,
+ 24499,
+ 24547,
+ 24550,
+ 24559,
+ 24560,
+ 24589,
+ 24608,
+ 24651,
+ 24691,
+ 24722,
+ 24743,
+ 24757,
+ 24800,
+ 24812,
+ 24822,
+ 24835,
+ 24851,
+ 24852,
+ 24863,
+ 24875,
+ 24877,
+ 24921,
+ 24940,
+ 24955,
+ 24991,
+ 25019,
+ 25106,
+ 25117,
+ 25124,
+ 25129,
+ 25133,
+ 25135,
+ 25139,
+ 25144,
+ 25159,
+ 25184,
+ 25190,
+ 25211,
+ 25229,
+ 25248,
+ 25250,
+ 25255,
+ 25274,
+ 25369,
+ 25374,
+ 25400,
+ 25406,
+ 25429,
+ 25441,
+ 25454,
+ 25467,
+ 25471,
+ 25472,
+ 25491,
+ 25496,
+ 25512,
+ 25513,
+ 25521,
+ 25543,
+ 25607,
+ 25620,
+ 25668,
+ 26130,
+ 26210,
+ 26599,
+ 26611,
+ 26615,
+ 26617,
+ 26932,
+ 27651,
+ 27653,
+ 27660,
+ 27665,
+ 27668,
+ 27672,
+ 27694,
+ 27695,
+ 27696,
+ 27699,
+ 27708,
+ 27717,
+ 27725,
+ 27729,
+ 27734,
+ 27738,
+ 27740,
+ 27742,
+ 27745,
+ 27747,
+ 27757,
+ 27759,
+ 27768,
+ 27773,
+ 27775,
+ 27781,
+ 27789,
+ 27800,
+ 27813,
+ 27831,
+ 27833,
+ 27837,
+ 27839,
+ 27843,
+ 27866,
+ 27876,
+ 27882,
+ 27884,
+ 27887,
+ 27889,
+ 27895,
+ 27901,
+ 27903,
+ 27923,
+ 27924,
+ 27927,
+ 27928,
+ 27932,
+ 27947,
+ 27951,
+ 27953,
+ 27955,
+ 27983,
+ 27984,
+ 27988,
+ 27995,
+ 28005,
+ 28006,
+ 28009,
+ 28015,
+ 28022,
+ 28024,
+ 28032,
+ 28036,
+ 28048,
+ 28049,
+ 28075,
+ 28080,
+ 28094,
+ 28104,
+ 28110,
+ 28118,
+ 28126,
+ 28146,
+ 28182,
+ 28186,
+ 28191,
+ 28198,
+ 28201,
+ 28210,
+ 28220,
+ 28258,
+ 28270,
+ 28343,
+ 28398,
+ 28403,
+ 28409,
+ 28458,
+ 28469,
+ 28481,
+ 28509,
+ 28512,
+ 28530,
+ 28531,
+ 28532,
+ 28534,
+ 28536,
+ 28537,
+ 28545,
+ 28548,
+ 28554,
+ 28555,
+ 28573,
+ 28580,
+ 28598,
+ 28649,
+ 28668,
+ 28683,
+ 28685,
+ 28725,
+ 28753,
+ 28760,
+ 28787,
+ 28812,
+ 28840,
+ 28851,
+ 28884,
+ 28885,
+ 28919,
+ 28952,
+ 28954,
+ 28964,
+ 28972,
+ 29027,
+ 29030,
+ 29031,
+ 29049,
+ 29061,
+ 29070,
+ 29084,
+ 29091,
+ 29119,
+ 29124,
+ 29170,
+ 29194,
+ 29208,
+ 29238,
+ 29244,
+ 29247,
+ 29256,
+ 29286,
+ 29300,
+ 29310,
+ 29314,
+ 29355,
+ 29357,
+ 29447,
+ 29465,
+ 29485,
+ 29492,
+ 29497,
+ 29518,
+ 29544,
+ 29555,
+ 29571,
+ 29580,
+ 29582,
+ 29600,
+ 29614,
+ 29687,
+ 29695,
+ 29975,
+ 30036,
+ 30058,
+ 30526,
+ 30600,
+ 30619,
+ 30689,
+ 30722,
+ 30764,
+ 30844,
+ 30873,
+ 30896,
+ 30925,
+ 30929,
+ 30969,
+ 30982,
+ 30985,
+ 30986,
+ 30987,
+ 30990,
+ 30992,
+ 30999,
+ 31012,
+ 31027,
+ 31029,
+ 31037,
+ 31042,
+ 31117,
+ 31122,
+ 31126,
+ 31127,
+ 31133,
+ 31143,
+ 31148,
+ 31163,
+ 31169,
+ 31200,
+ 31204,
+ 31205,
+ 31213,
+ 31224,
+ 31242,
+ 31246,
+ 31252,
+ 31272,
+ 31287,
+ 31404,
+ 31423,
+ 31452,
+ 31499,
+ 31543,
+ 31549,
+ 31615,
+ 31655,
+ 31679,
+ 31721,
+ 31725,
+ 31726,
+ 31898,
+ 32020,
+ 32098,
+ 32398,
+ 32860,
+ 33363,
+ 33392,
+ 33567,
+ 33576,
+ 33582,
+ 33763,
+ 33765,
+ 33771,
+ 33779,
+ 33781,
+ 33796,
+ 33874,
+ 33883,
+ 33885,
+ 33915,
+ 33922,
+ 33983,
+ 34001,
+ 34058,
+ 34087,
+ 34120,
+ 34170,
+ 34187,
+ 34224,
+ 34244,
+ 34295,
+ 34296,
+ 34362,
+ 34368,
+ 34447,
+ 34458,
+ 34471,
+ 34525,
+ 34533,
+ 34547,
+ 34557,
+ 34569,
+ 34594,
+ 34606,
+ 34661,
+ 34666,
+ 34700,
+ 34718,
+ 34724,
+ 34743,
+ 34772,
+ 34779,
+ 34781,
+ 34797,
+ 34803,
+ 34857,
+ 34876,
+ 34916,
+ 34918,
+ 34977,
+ 34984,
+ 34989,
+ 35046,
+ 35047,
+ 35063,
+ 35091,
+ 35104,
+ 35132,
+ 35141,
+ 35179,
+ 35191,
+ 35197,
+ 35223,
+ 35228,
+ 35244,
+ 35297,
+ 35311,
+ 35313,
+ 35320,
+ 35328,
+ 35346,
+ 35362,
+ 35370,
+ 35394,
+ 35432,
+ 35444,
+ 35457,
+ 35467,
+ 35518,
+ 35549,
+ 35566,
+ 35567,
+ 35568,
+ 35612,
+ 35699,
+ 35706,
+ 35725,
+ 35729,
+ 35732,
+ 35753,
+ 35773,
+ 35790,
+ 35805,
+ 35807,
+ 35819,
+ 35892,
+ 35900,
+ 35911,
+ 36290,
+ 36352,
+ 36445,
+ 36492,
+ 36511,
+ 36549,
+ 36864,
+ 36865,
+ 36866,
+ 36868,
+ 36873,
+ 36874,
+ 36884,
+ 36890,
+ 36892,
+ 36902,
+ 36903,
+ 36905,
+ 36907,
+ 36908,
+ 36909,
+ 36912,
+ 36914,
+ 36920,
+ 36924,
+ 36925,
+ 36926,
+ 36930,
+ 36935,
+ 36937,
+ 36939,
+ 36947,
+ 36958,
+ 36962,
+ 36963,
+ 36974,
+ 36977,
+ 36988,
+ 36992,
+ 36994,
+ 36996,
+ 36998,
+ 36999,
+ 37002,
+ 37006,
+ 37009,
+ 37012,
+ 37014,
+ 37020,
+ 37027,
+ 37030,
+ 37035,
+ 37037,
+ 37049,
+ 37053,
+ 37054,
+ 37057,
+ 37061,
+ 37063,
+ 37069,
+ 37073,
+ 37075,
+ 37076,
+ 37081,
+ 37084,
+ 37090,
+ 37094,
+ 37098,
+ 37100,
+ 37105,
+ 37110,
+ 37113,
+ 37119,
+ 37123,
+ 37124,
+ 37129,
+ 37133,
+ 37136,
+ 37140,
+ 37141,
+ 37143,
+ 37148,
+ 37154,
+ 37164,
+ 37168,
+ 37173,
+ 37183,
+ 37184,
+ 37187,
+ 37190,
+ 37196,
+ 37203,
+ 37204,
+ 37205,
+ 37208,
+ 37211,
+ 37215,
+ 37219,
+ 37223,
+ 37228,
+ 37229,
+ 37233,
+ 37236,
+ 37254,
+ 37257,
+ 37282,
+ 37284,
+ 37287,
+ 37294,
+ 37303,
+ 37305,
+ 37309,
+ 37313,
+ 37315,
+ 37323,
+ 37326,
+ 37332,
+ 37334,
+ 37336,
+ 37337,
+ 37340,
+ 37342,
+ 37343,
+ 37349,
+ 37358,
+ 37371,
+ 37376,
+ 37385,
+ 37395,
+ 37406,
+ 37410,
+ 37424,
+ 37425,
+ 37427,
+ 37429,
+ 37430,
+ 37440,
+ 37447,
+ 37449,
+ 37451,
+ 37453,
+ 37457,
+ 37460,
+ 37461,
+ 37473,
+ 37492,
+ 37508,
+ 37517,
+ 37524,
+ 37526,
+ 37529,
+ 37531,
+ 37532,
+ 37541,
+ 37542,
+ 37545,
+ 37550,
+ 37552,
+ 37559,
+ 37563,
+ 37575,
+ 37577,
+ 37580,
+ 37584,
+ 37586,
+ 37594,
+ 37611,
+ 37612,
+ 37614,
+ 37616,
+ 37621,
+ 37622,
+ 37637,
+ 37642,
+ 37645,
+ 37649,
+ 37654,
+ 37665,
+ 37671,
+ 37678,
+ 37680,
+ 37682,
+ 37693,
+ 37697,
+ 37705,
+ 37713,
+ 37721,
+ 37963,
+ 38008,
+ 38009,
+ 38077,
+ 38136,
+ 38172,
+ 38176,
+ 38195,
+ 38198,
+ 38201,
+ 38203,
+ 38235,
+ 38247,
+ 38264,
+ 38266,
+ 38322,
+ 38442,
+ 38466,
+ 38511,
+ 38553,
+ 38565,
+ 38600,
+ 38623,
+ 38742,
+ 38800,
+ 38805,
+ 38819,
+ 38841,
+ 38851,
+ 38875,
+ 38901,
+ 38919,
+ 38999,
+ 39007,
+ 39010,
+ 39032,
+ 39067,
+ 39093,
+ 39122,
+ 39184,
+ 39216,
+ 39232,
+ 39246,
+ 39251,
+ 39273,
+ 39280,
+ 39308,
+ 39344,
+ 39374,
+ 39375,
+ 39397,
+ 39401,
+ 39402,
+ 39501,
+ 39507,
+ 39603,
+ 39608,
+ 39611,
+ 39615,
+ 39642,
+ 39647,
+ 39650,
+ 39699,
+ 39766,
+ 39791,
+ 39798,
+ 39823,
+ 39824,
+ 39826,
+ 39891,
+ 39906,
+ 40676,
+ 40786,
+ 40788,
+ 40945,
+ 40980,
+ 41046,
+ 41096,
+ 41124,
+ 41164,
+ 41202,
+ 41228,
+ 41313,
+ 41329,
+ 41330,
+ 41371,
+ 41378,
+ 41454,
+ 41496,
+ 41549,
+ 41557,
+ 41563,
+ 41564,
+ 41627,
+ 41676,
+ 41697,
+ 41704,
+ 41712,
+ 41733,
+ 41738,
+ 41745,
+ 41750,
+ 41798,
+ 41820,
+ 41833,
+ 41872,
+ 41881,
+ 41897,
+ 41922,
+ 41937,
+ 41956,
+ 41997,
+ 41998,
+ 42003,
+ 42013,
+ 42082,
+ 42109,
+ 42183,
+ 42205,
+ 42232,
+ 42248,
+ 42298,
+ 42306,
+ 42313,
+ 42334,
+ 42337,
+ 42343,
+ 42390,
+ 42437,
+ 42455,
+ 42525,
+ 42532,
+ 42541,
+ 42560,
+ 42571,
+ 42580,
+ 42581,
+ 42610,
+ 42652,
+ 42673,
+ 42682,
+ 42689,
+ 42708,
+ 42713,
+ 42772,
+ 42779,
+ 42828,
+ 42837,
+ 42841,
+ 42863,
+ 42864,
+ 42905,
+ 42908,
+ 42912,
+ 42925,
+ 42960,
+ 42961,
+ 42991,
+ 43019,
+ 43060,
+ 43139,
+ 43197,
+ 43205,
+ 43242,
+ 43256,
+ 43350,
+ 43406,
+ 43451,
+ 43452,
+ 43513,
+ 43529,
+ 43533,
+ 43557,
+ 43568,
+ 43612,
+ 43627,
+ 43633,
+ 43653,
+ 43700,
+ 43708,
+ 43733,
+ 43754,
+ 43766,
+ 43791,
+ 43824,
+ 43883,
+ 43925,
+ 43939,
+ 43940,
+ 44021,
+ 44027,
+ 44034,
+ 44087,
+ 44090,
+ 44134,
+ 44143,
+ 44213,
+ 44217,
+ 44234,
+ 44244,
+ 44272,
+ 44313,
+ 44327,
+ 44377,
+ 44391,
+ 44395,
+ 44477,
+ 44483,
+ 44489,
+ 44558,
+ 44566,
+ 44631,
+ 44702,
+ 44725,
+ 44735,
+ 44869,
+ 44894,
+ 44901,
+ 44925,
+ 45090,
+ 45102,
+ 45143,
+ 45168,
+ 45177,
+ 45178,
+ 45193,
+ 45245,
+ 45271,
+ 45305,
+ 45345,
+ 45355,
+ 45356,
+ 45458,
+ 45461,
+ 45498,
+ 45543,
+ 45558,
+ 45588,
+ 45609,
+ 45650,
+ 45669,
+ 45727,
+ 45754,
+ 45758,
+ 45763,
+ 45766,
+ 45879,
+ 45891,
+ 45899,
+ 45905,
+ 45916,
+ 45918,
+ 45925,
+ 45935,
+ 45960,
+ 46198,
+ 46408,
+ 46650,
+ 46868,
+ 47139,
+ 47159,
+ 47169,
+ 47217,
+ 47232,
+ 47234,
+ 47237,
+ 47253,
+ 47262,
+ 47330,
+ 47331,
+ 47376,
+ 47377,
+ 47394,
+ 47485,
+ 47524,
+ 47588,
+ 47589,
+ 47702,
+ 47782,
+ 47790,
+ 47794,
+ 47883,
+ 47887,
+ 47898,
+ 47956,
+ 47959,
+ 47962,
+ 48092,
+ 48133,
+ 48161,
+ 48190,
+ 48206,
+ 48252,
+ 48260,
+ 48288,
+ 48359,
+ 48418,
+ 48431,
+ 48492,
+ 48503,
+ 48506,
+ 48629,
+ 48642,
+ 48675,
+ 48695,
+ 48728,
+ 48830,
+ 48832,
+ 48847,
+ 48861,
+ 48887,
+ 48904,
+ 48917,
+ 48926,
+ 48966,
+ 49040,
+ 49044,
+ 49056,
+ 49091,
+ 49100,
+ 49101,
+ 49117,
+ 49129,
+ 49223,
+ 49273,
+ 49282,
+ 49419,
+ 49528,
+ 49561,
+ 49567,
+ 49602,
+ 49628,
+ 49724,
+ 49770,
+ 49798,
+ 49800,
+ 49808,
+ 49824,
+ 49849,
+ 49889,
+ 49902,
+ 49914,
+ 49981,
+ 49985,
+ 50010,
+ 50025,
+ 50181,
+ 50223,
+ 50231,
+ 50251,
+ 50266,
+ 50274,
+ 50294,
+ 50304,
+ 50318,
+ 50334,
+ 50349,
+ 50360,
+ 50411,
+ 50463,
+ 50467,
+ 50482,
+ 50500,
+ 50558,
+ 50581,
+ 50593,
+ 50613,
+ 50616,
+ 50635,
+ 50666,
+ 50670,
+ 50685,
+ 50718,
+ 50767,
+ 50770,
+ 50810,
+ 50821,
+ 50825,
+ 50920,
+ 50925,
+ 50953,
+ 50959,
+ 50971,
+ 50973,
+ 50979,
+ 51018,
+ 51020,
+ 51056,
+ 51104,
+ 51110,
+ 51142,
+ 51167,
+ 51175,
+ 51184,
+ 51207,
+ 51265,
+ 51336,
+ 51341,
+ 51346,
+ 51375,
+ 51407,
+ 51430,
+ 51495,
+ 51504,
+ 51582,
+ 51604,
+ 51615,
+ 51653,
+ 51684,
+ 51765,
+ 51784,
+ 51809,
+ 51825,
+ 51852,
+ 51896,
+ 52075,
+ 52228,
+ 52233,
+ 52238,
+ 52242,
+ 52251,
+ 52253,
+ 52257,
+ 52260,
+ 52262,
+ 52263,
+ 52300,
+ 52312,
+ 52323,
+ 52341,
+ 52361,
+ 52362,
+ 52363,
+ 52373,
+ 52391,
+ 52398,
+ 52405,
+ 52409,
+ 52412,
+ 52433,
+ 52436,
+ 52444,
+ 52455,
+ 52465,
+ 52468,
+ 52471,
+ 52477,
+ 52613,
+ 52783,
+ 52974,
+ 53006,
+ 53667,
+ 53764,
+ 53913,
+ 54198,
+ 54614,
+ 54994,
+ 55020,
+ 55081,
+ 55330,
+ 55391,
+ 55392,
+ 55424,
+ 55427,
+ 55430,
+ 55501,
+ 55577,
+ 55685,
+ 55699,
+ 55769,
+ 55805,
+ 55821,
+ 55836,
+ 55850,
+ 55853,
+ 55872,
+ 55900,
+ 55915,
+ 55933,
+ 55943,
+ 55944,
+ 55990,
+ 56017,
+ 56030,
+ 56040,
+ 56041,
+ 56044,
+ 56046,
+ 56047,
+ 56048,
+ 56055,
+ 56089,
+ 56099,
+ 56120,
+ 56167,
+ 56207,
+ 56231,
+ 56262,
+ 56293,
+ 56300,
+ 56329,
+ 56410,
+ 56478,
+ 56484,
+ 56497,
+ 56515,
+ 56548,
+ 56568,
+ 56653,
+ 56655,
+ 56665,
+ 56696,
+ 56704,
+ 56709,
+ 56803,
+ 56902,
+ 57000,
+ 57013,
+ 57016,
+ 57070,
+ 57112,
+ 57133,
+ 57134,
+ 57172,
+ 57184,
+ 57218,
+ 57248,
+ 57256,
+ 57269,
+ 57293,
+ 57332,
+ 57344,
+ 57370,
+ 57374,
+ 57388,
+ 57389,
+ 57443,
+ 57491,
+ 57513,
+ 57564,
+ 57566,
+ 57608,
+ 57630,
+ 57728,
+ 57743,
+ 57760,
+ 57761,
+ 57764,
+ 57778,
+ 57794,
+ 57852,
+ 57869,
+ 57888,
+ 58061,
+ 58065,
+ 58118,
+ 58224,
+ 58264,
+ 58321,
+ 58322,
+ 58424,
+ 58453,
+ 58460,
+ 58461,
+ 58485,
+ 58504,
+ 58507,
+ 58519,
+ 58524,
+ 58593,
+ 58610,
+ 58655,
+ 58656,
+ 58682,
+ 58689,
+ 58715,
+ 58717,
+ 58731,
+ 58821,
+ 58895,
+ 58945,
+ 58952,
+ 59078,
+ 59108,
+ 59125,
+ 59126,
+ 59253,
+ 59257,
+ 59317,
+ 59443,
+ 59497,
+ 59573,
+ 59588,
+ 59625,
+ 59668,
+ 59702,
+ 59729,
+ 59770,
+ 59847,
+ 59861,
+ 59890,
+ 59895,
+ 59931,
+ 59989,
+ 60068,
+ 60111,
+ 60213,
+ 60258,
+ 60294,
+ 60304,
+ 60352,
+ 60367,
+ 60372,
+ 60377,
+ 60407,
+ 60471,
+ 60517,
+ 60588,
+ 60636,
+ 60715,
+ 60725,
+ 60757,
+ 60781,
+ 60806,
+ 60886,
+ 61071,
+ 61079,
+ 61112,
+ 61135,
+ 61143,
+ 61154,
+ 61189,
+ 61272,
+ 61275,
+ 61287,
+ 61307,
+ 61317,
+ 61461,
+ 61466,
+ 61478,
+ 61512,
+ 61588,
+ 62005,
+ 62013,
+ 62161,
+ 62179,
+ 62183,
+ 62211,
+ 62240,
+ 62282,
+ 62336,
+ 62337,
+ 62419,
+ 62563,
+ 62627,
+ 63023,
+ 63199,
+ 63473,
+ 63526,
+ 63852,
+ 63859,
+ 63945,
+ 63949,
+ 63969,
+ 63991,
+ 64037,
+ 64043,
+ 64073,
+ 64098,
+ 64105,
+ 64134,
+ 64453,
+ 64466,
+ 131090,
+ 131111,
+ 131178,
+ 131198,
+ 131207,
+ 131267,
+ 131284,
+ 131429,
+ 131445,
+ 131464,
+ 131471,
+ 131584,
+ 131591,
+ 131596,
+ 131602,
+ 131627,
+ 132045,
+ 132061,
+ 132080,
+ 132148,
+ 132165,
+ 132167,
+ 132173,
+ 132199,
+ 132203,
+ 132204,
+ 132222,
+ 132298,
+ 132447,
+ 132449,
+ 132462,
+ 132468,
+ 132471,
+ 132480,
+ 132513,
+ 132618,
+ 132825,
+ 132831,
+ 133012,
+ 133076,
+ 133206,
+ 133287,
+ 133334,
+ 133384,
+ 133385,
+ 133480,
+ 133481,
+ 133524,
+ 133606,
+ 133612,
+ 133623,
+ 133661,
+ 133752,
+ 133875,
+ 133897,
+ 133982,
+ 134090,
+ 134134,
+ 134204,
+ 134356,
+ 134467,
+ 134489,
+ 134562,
+ 134651,
+ 134674,
+ 134697,
+ 134707,
+ 134714,
+ 134715,
+ 134732,
+ 134739,
+ 134772,
+ 134774,
+ 134783,
+ 134806,
+ 134840,
+ 134995,
+ 135043,
+ 135126,
+ 135298,
+ 135300,
+ 135327,
+ 135341,
+ 135375,
+ 135376,
+ 135377,
+ 135405,
+ 135407,
+ 135409,
+ 135477,
+ 135478,
+ 135589,
+ 135600,
+ 135607,
+ 135887,
+ 136000,
+ 136030,
+ 136039,
+ 136093,
+ 136119,
+ 136141,
+ 136167,
+ 136188,
+ 136210,
+ 136238,
+ 136255,
+ 136258,
+ 136380,
+ 136384,
+ 136442,
+ 136454,
+ 136477,
+ 136479,
+ 136480,
+ 136515,
+ 136525,
+ 136538,
+ 136557,
+ 136780,
+ 136787,
+ 136873,
+ 136897,
+ 136907,
+ 136950,
+ 136969,
+ 136972,
+ 136975,
+ 136994,
+ 137029,
+ 137047,
+ 137080,
+ 137226,
+ 137409,
+ 137412,
+ 137425,
+ 137449,
+ 137526,
+ 137561,
+ 137811,
+ 137824,
+ 137872,
+ 137880,
+ 137959,
+ 137967,
+ 138014,
+ 138089,
+ 138167,
+ 138168,
+ 138179,
+ 138197,
+ 138322,
+ 138346,
+ 138368,
+ 138384,
+ 138423,
+ 138500,
+ 138519,
+ 138529,
+ 138590,
+ 138607,
+ 138629,
+ 138638,
+ 138640,
+ 138655,
+ 138684,
+ 138754,
+ 138886,
+ 138915,
+ 138964,
+ 139003,
+ 139009,
+ 139029,
+ 139043,
+ 139203,
+ 139224,
+ 139285,
+ 139580,
+ 139628,
+ 139741,
+ 139759,
+ 139766,
+ 139831,
+ 139841,
+ 139849,
+ 139879,
+ 139898,
+ 139922,
+ 139952,
+ 139967,
+ 139994,
+ 140045,
+ 140072,
+ 140096,
+ 140220,
+ 140292,
+ 140401,
+ 140499,
+ 140686,
+ 140867,
+ 140900,
+ 140948,
+ 140989,
+ 141024,
+ 141031,
+ 141039,
+ 141047,
+ 141127,
+ 141140,
+ 141145,
+ 141199,
+ 141215,
+ 141216,
+ 141342,
+ 141421,
+ 141607,
+ 141680,
+ 141681,
+ 141704,
+ 141711,
+ 141767,
+ 141778,
+ 141883,
+ 141995,
+ 142065,
+ 142295,
+ 142352,
+ 142541,
+ 142552,
+ 142647,
+ 147049,
+ 147293,
+ 147314,
+ 149024,
+ 149034,
+ 149359,
+ 149360,
+ 149419,
+ 149456,
+ 149771,
+ 149866,
+ 150131,
+ 150153,
+ 150222,
+ 150331,
+ 150371,
+ 150452,
+ 150683,
+ 150692,
+ 150750,
+ 150774,
+ 151080,
+ 151341,
+ 151396,
+ 151636,
+ 151802,
+ 151983,
+ 196640,
+ 196735,
+ 196737,
+ 196838,
+ 196874,
+ 196900,
+ 196925,
+ 196961,
+ 197119,
+ 197207,
+ 197225,
+ 197296,
+ 197301,
+ 197324,
+ 197350,
+ 197423,
+ 197556,
+ 197623,
+ 197637,
+ 197674,
+ 197704,
+ 197706,
+ 197830,
+ 197862,
+ 197882,
+ 197897,
+ 198023,
+ 198068,
+ 198252,
+ 198259,
+ 198265,
+ 198279,
+ 198288,
+ 198440,
+ 198441,
+ 198504,
+ 198589,
+ 198605,
+ 198668,
+ 198735,
+ 198820,
+ 198961,
+ 198966,
+ 199061,
+ 199140,
+ 199239,
+ 199276,
+ 199284,
+ 199469,
+ 199490,
+ 199493,
+ 199524,
+ 199620,
+ 199698,
+ 199707,
+ 199731,
+ 199739,
+ 199987,
+ 199995,
+ 200019,
+ 200134,
+ 200154,
+ 200313,
+ 200446,
+ 200565,
+ 200590,
+ 200640,
+ 200665,
+ 200724,
+ 200736,
+ 200740,
+ 200742,
+ 200845,
+ 200865,
+ 201011,
+ 201019,
+ 201031,
+ 201073,
+ 201089,
+ 201167,
+ 201187,
+ 201235,
+ 201241,
+ 201249,
+ 201363,
+ 201411,
+ 201502,
+ 201505,
+ 201577,
+ 201596,
+ 201603,
+ 201746,
+ 201749,
+ 201767,
+ 201776,
+ 201838,
+ 201884,
+ 201890,
+ 201986,
+ 201997,
+ 202023,
+ 202080,
+ 202087,
+ 202098,
+ 202103,
+ 202204,
+ 202243,
+ 202254,
+ 202282,
+ 202293,
+ 202422,
+ 202433,
+ 202441,
+ 202468,
+ 202498,
+ 202561,
+ 202613,
+ 202616,
+ 202619,
+ 202632,
+ 202635,
+ 202651,
+ 202662,
+ 202870,
+ 202872,
+ 202914,
+ 202921,
+ 202940,
+ 202943,
+ 202965,
+ 202987,
+ 203020,
+ 203106,
+ 203136,
+ 203206,
+ 203214,
+ 203217,
+ 203409,
+ 203424,
+ 203446,
+ 203448,
+ 203451,
+ 203459,
+ 203561,
+ 203622,
+ 203675,
+ 203680,
+ 203735,
+ 203811,
+ 203827,
+ 203877,
+ 203912,
+ 203936,
+ 203953,
+ 203971,
+ 203995,
+ 203999,
+ 204106,
+ 204108,
+ 204151,
+ 204165,
+ 204168,
+ 204170,
+ 204249,
+ 204274,
+ 204279,
+ 204317,
+ 204342,
+ 204356,
+ 204403,
+ 204457,
+ 204592,
+ 204595,
+ 204601,
+ 204649,
+ 204666,
+ 204793,
+ 204816,
+ 204873,
+ 204918,
+ 204957,
+ 204986,
+ 205015,
+ 205110,
+ 205119,
+ 205134,
+ 205168,
+ 205244,
+ 205254,
+ 205277,
+ 205278,
+ 205293,
+ 205362,
+ 205368,
+ 205473,
+ 205547,
+ 205623,
+ 205638,
+ 205647,
+ 205714,
+ 205800,
+ 205832,
+ 205872,
+ 205889,
+ 206026,
+ 206065,
+ 206067,
+ 206088,
+ 206119,
+ 206194,
+ 206206,
+ 206238,
+ 206260,
+ 206262,
+ 206283,
+ 206358,
+ 206375,
+ 206406,
+ 206478,
+ 206485,
+ 206519,
+ 206557,
+ 206610,
+ 206666,
+ 206774,
+ 206783,
+ 206920,
+ 207044,
+ 207097,
+ 207137,
+ 207154,
+ 207192,
+ 207251,
+ 207281,
+ 207369,
+ 207375,
+ 207464,
+ 207502,
+ 207569,
+ 207589,
+ 207645,
+ 207713,
+ 207728,
+ 207782,
+ 207810,
+ 207876,
+ 207980,
+ 207990,
+ 207991,
+ 208040,
+ 208286,
+ 208320,
+ 208324,
+ 208339,
+ 208365,
+ 208555,
+ 208570,
+ 208592,
+ 208668,
+ 208670,
+ 208671,
+ 208708,
+ 208730,
+ 208734,
+ 208864,
+ 208905,
+ 208972,
+ 208997,
+ 209046,
+ 209049,
+ 209193,
+ 209240,
+ 209262,
+ 209277,
+ 209302,
+ 209360,
+ 209424,
+ 209442,
+ 209531,
+ 209828,
+ 209835,
+ 209839,
+ 209854,
+ 210003,
+ 210016,
+ 210021,
+ 210125,
+ 210147,
+ 210152,
+ 210162,
+ 210179,
+ 210218,
+ 210273,
+ 210278,
+ 210315,
+ 210402,
+ 210616,
+ 210625,
+ 210644,
+ 210693,
+ 210740,
+ 210808,
+ 210964,
+ 210974,
+ 211028,
+ 211057,
+ 211147,
+ 211210,
+ 211211,
+ 211309,
+ 211322,
+ 211356,
+ 211385,
+ 211450,
+ 211468,
+ 211559,
+ 211689,
+ 211720,
+ 211790,
+ 211908,
+ 211913,
+ 211995,
+ 212046,
+ 212050,
+ 212183,
+ 212238,
+ 212330,
+ 212444,
+ 212449,
+ 212531,
+ 212538,
+ 212572,
+ 212616,
+ 212637,
+ 212645,
+ 212655,
+ 212661,
+ 212766,
+ 212898,
+ 212910,
+ 212986,
+ 212999,
+ 213155,
+ 213295,
+ 213320,
+ 213398,
+ 213402,
+ 215284,
+ 215423,
+ 215501,
+ 215733,
+ 215746,
+ 215904,
+ 215910,
+ 216071,
+ 216139,
+ 216200,
+ 216259,
+ 216312,
+ 216374,
+ 262145,
+ 262146,
+ 262149,
+ 262159,
+ 262179,
+ 262181,
+ 262186,
+ 262191,
+ 262196,
+ 262197,
+ 262202,
+ 262210,
+ 262220,
+ 262223,
+ 262234,
+ 262239,
+ 262241,
+ 262253,
+ 262262,
+ 262287,
+ 262354,
+ 262378,
+ 262459,
+ 262468,
+ 262481,
+ 262589,
+ 262659,
+ 262753,
+ 262773,
+ 262916,
+ 262932,
+ 263073,
+ 263175,
+ 263189,
+ 263210,
+ 263222,
+ 263223,
+ 263224,
+ 263238,
+ 263242,
+ 263245,
+ 263327,
+ 263684,
+ 263686,
+ 263689,
+ 263694,
+ 263698,
+ 263703,
+ 263717,
+ 263725,
+ 263749,
+ 263750,
+ 263751,
+ 263761,
+ 263762,
+ 263763,
+ 263765,
+ 263783,
+ 263791,
+ 263792,
+ 263805,
+ 263824,
+ 263980,
+ 264605,
+ 264609,
+ 264628,
+ 264635,
+ 264637,
+ 264642,
+ 264645,
+ 264646,
+ 264663,
+ 264681,
+ 264685,
+ 264694,
+ 264696,
+ 264733,
+ 264738,
+ 264744,
+ 264746,
+ 264750,
+ 264770,
+ 264778,
+ 264779,
+ 264780,
+ 264783,
+ 264796,
+ 264814,
+ 264821,
+ 264825,
+ 264837,
+ 264838,
+ 264844,
+ 264847,
+ 265540,
+ 265561,
+ 265594,
+ 265606,
+ 265608,
+ 265631,
+ 265632,
+ 265636,
+ 265675,
+ 265684,
+ 265686,
+ 265688,
+ 265691,
+ 265706,
+ 265721,
+ 265724,
+ 265727,
+ 265745,
+ 265759,
+ 265767,
+ 265780,
+ 265798,
+ 265799,
+ 265818,
+ 265822,
+ 265855,
+ 265862,
+ 265867,
+ 266445,
+ 266668,
+ 266673,
+ 266698,
+ 266730,
+ 266734,
+ 266742,
+ 266755,
+ 266771,
+ 266783,
+ 266792,
+ 266802,
+ 266809,
+ 266814,
+ 266815,
+ 266832,
+ 266841,
+ 266853,
+ 266858,
+ 266860,
+ 266870,
+ 266880,
+ 266893,
+ 266894,
+ 266904,
+ 267684,
+ 267685,
+ 267699,
+ 267705,
+ 267708,
+ 267713,
+ 267749,
+ 267761,
+ 267765,
+ 267790,
+ 267795,
+ 267797,
+ 267803,
+ 267809,
+ 267828,
+ 267831,
+ 267845,
+ 267846,
+ 267869,
+ 267882,
+ 267883,
+ 267904,
+ 267916,
+ 267920,
+ 268323,
+ 268976,
+ 269036,
+ 269729,
+ 269730,
+ 269733,
+ 269734,
+ 269738,
+ 269747,
+ 269749,
+ 269750,
+ 269782,
+ 269783,
+ 269797,
+ 269804,
+ 269816,
+ 269820,
+ 269822,
+ 269831,
+ 269832,
+ 269838,
+ 269840,
+ 269846,
+ 269853,
+ 269857,
+ 269862,
+ 269894,
+ 269901,
+ 269905,
+ 269906,
+ 269908,
+ 269918,
+ 269919,
+ 269921,
+ 269927,
+ 269931,
+ 269934,
+ 269936,
+ 269940,
+ 269946,
+ 269950,
+ 269953,
+ 269955,
+ 269960,
+ 269964,
+ 269965,
+ 269973,
+ 269976,
+ 269984,
+ 269989,
+ 270007,
+ 270026,
+ 270029,
+ 270035,
+ 270036,
+ 270049,
+ 270052,
+ 270058,
+ 270068,
+ 270073,
+ 270084,
+ 270096,
+ 270102,
+ 270108,
+ 270161,
+ 270814,
+ 271773,
+ 271775,
+ 271781,
+ 271785,
+ 271791,
+ 271793,
+ 271795,
+ 271799,
+ 271808,
+ 271812,
+ 271814,
+ 271819,
+ 271822,
+ 271835,
+ 271837,
+ 271855,
+ 271868,
+ 271874,
+ 271899,
+ 271907,
+ 271909,
+ 271911,
+ 271929,
+ 271930,
+ 271931,
+ 271933,
+ 271942,
+ 271951,
+ 271962,
+ 271965,
+ 271969,
+ 271971,
+ 271996,
+ 272006,
+ 272011,
+ 272015,
+ 272018,
+ 272019,
+ 272026,
+ 272057,
+ 272059,
+ 272062,
+ 272082,
+ 272083,
+ 272099,
+ 272102,
+ 272106,
+ 272110,
+ 272112,
+ 272122,
+ 272129,
+ 272134,
+ 272809,
+ 272818,
+ 272827,
+ 272836,
+ 272838,
+ 272848,
+ 272868,
+ 272882,
+ 272886,
+ 272943,
+ 272955,
+ 272962,
+ 272979,
+ 272980,
+ 272991,
+ 273000,
+ 273048,
+ 273054,
+ 273093,
+ 273113,
+ 273133,
+ 327687,
+ 327693,
+ 327697,
+ 327707,
+ 327708,
+ 327712,
+ 327714,
+ 327716,
+ 327724,
+ 327738,
+ 327742,
+ 327747,
+ 327750,
+ 327756,
+ 327760,
+ 327765,
+ 327768,
+ 327769,
+ 327770,
+ 327776,
+ 327782,
+ 327786,
+ 327799,
+ 327802,
+ 327804,
+ 327819,
+ 327828,
+ 327830,
+ 327862,
+ 327863,
+ 327871,
+ 327885,
+ 327900,
+ 327901,
+ 327903,
+ 327931,
+ 327934,
+ 327947,
+ 327972,
+ 327975,
+ 327987,
+ 327991,
+ 327996,
+ 328061,
+ 328073,
+ 328075,
+ 328079,
+ 328088,
+ 328136,
+ 328140,
+ 328169,
+ 328191,
+ 328196,
+ 328198,
+ 328200,
+ 328207,
+ 328215,
+ 328223,
+ 328228,
+ 328250,
+ 328253,
+ 328282,
+ 328286,
+ 328297,
+ 328309,
+ 328310,
+ 328316,
+ 328319,
+ 328331,
+ 328341,
+ 328358,
+ 328411,
+ 328469,
+ 328471,
+ 328473,
+ 328475,
+ 328479,
+ 328480,
+ 328488,
+ 328490,
+ 328491,
+ 328494,
+ 328510,
+ 328514,
+ 328535,
+ 328539,
+ 328549,
+ 328576,
+ 328581,
+ 328586,
+ 328590,
+ 328594,
+ 328600,
+ 328605,
+ 328610,
+ 328611,
+ 328614,
+ 328619,
+ 328636,
+ 328638,
+ 328652,
+ 328659,
+ 328676,
+ 328697,
+ 328702,
+ 328708,
+ 328717,
+ 328727,
+ 328755,
+ 328777,
+ 328817,
+ 328844,
+ 328856,
+ 328858,
+ 328880,
+ 328895,
+ 328923,
+ 328939,
+ 328943,
+ 328954,
+ 328959,
+ 328961,
+ 328975,
+ 328977,
+ 328987,
+ 328988,
+ 328993,
+ 328997,
+ 329014,
+ 329027,
+ 329029,
+ 329044,
+ 329048,
+ 329078,
+ 329082,
+ 329094,
+ 329101,
+ 329110,
+ 329119,
+ 329129,
+ 329135,
+ 329167,
+ 329174,
+ 329177,
+ 329179,
+ 329183,
+ 329192,
+ 329205,
+ 329211,
+ 329219,
+ 329220,
+ 329253,
+ 329254,
+ 329261,
+ 329274,
+ 329286,
+ 329288,
+ 329301,
+ 329373,
+ 329387,
+ 393275,
+ 393629,
+ 394311,
+ 394381,
+ 394684,
+ 395561,
+ 395570,
+ 395965,
+ 396304,
+ 396338,
+ 396357,
+ 396420,
+ 396982,
+ 397961,
+ 398228,
+ 398721,
+ 399724,
+ 400266,
+ 400354,
+ 400618,
+)
// DefaultCountryTopASNs is a mapping of a country to their top ASNs.
var DefaultCountryTopASNs = map[Country]ASN{
CountryAD: 6752,
CountryAE: 5384,
- CountryAF: 55330,
+ CountryAF: 9009,
CountryAG: 11594,
CountryAI: 396304,
- CountryAL: 50616,
+ CountryAL: 42313,
CountryAM: 44395,
CountryAO: 37119,
CountryAR: 7303,
@@ -3178,14 +3167,14 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryAZ: 28787,
CountryBA: 9146,
CountryBB: 14813,
- CountryBD: 24432,
+ CountryBD: 24389,
CountryBE: 5432,
- CountryBF: 36924,
+ CountryBF: 37577,
CountryBG: 8866,
CountryBH: 5416,
CountryBI: 327799,
CountryBJ: 37424,
- CountryBM: 3855,
+ CountryBM: 32020,
CountryBN: 10094,
CountryBO: 6568,
CountryBQ: 27745,
@@ -3199,14 +3188,14 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryCD: 37020,
CountryCF: 37460,
CountryCG: 36924,
- CountryCH: 3303,
+ CountryCH: 6730,
CountryCI: 29571,
CountryCK: 10131,
CountryCL: 7418,
CountryCM: 36912,
CountryCN: 4134,
CountryCO: 10620,
- CountryCR: 11830,
+ CountryCR: 52263,
CountryCU: 27725,
CountryCV: 37517,
CountryCW: 52233,
@@ -3214,12 +3203,12 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryCZ: 5610,
CountryDE: 3320,
CountryDJ: 30990,
- CountryDK: 3292,
+ CountryDK: 13335,
CountryDM: 40945,
CountryDO: 6400,
CountryDZ: 36947,
CountryEC: 27947,
- CountryEE: 2586,
+ CountryEE: 44477,
CountryEG: 8452,
CountryER: 24757,
CountryES: 3352,
@@ -3237,7 +3226,7 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryGF: 3215,
CountryGG: 8680,
CountryGH: 30986,
- CountryGI: 8301,
+ CountryGI: 8772,
CountryGL: 8818,
CountryGM: 37552,
CountryGN: 37461,
@@ -3251,28 +3240,29 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryHK: 4760,
CountryHN: 14754,
CountryHR: 5391,
- CountryHT: 27653,
+ CountryHT: 52260,
CountryHU: 5483,
CountryID: 7713,
- CountryIE: 15502,
- CountryIL: 12400,
+ CountryIE: 6830,
+ CountryIL: 1680,
CountryIM: 13122,
CountryIN: 55836,
CountryIO: 17458,
CountryIQ: 203214,
- CountryIR: 197207,
- CountryIS: 44735,
+ CountryIR: 44244,
+ CountryIS: 44925,
CountryIT: 1267,
- CountryJE: 8680,
+ CountryJE: 8681,
CountryJM: 30689,
- CountryJO: 8376,
+ CountryJO: 48832,
CountryJP: 2516,
CountryKE: 33771,
CountryKG: 50223,
CountryKH: 38623,
- CountryKI: 135409,
- CountryKM: 328061,
- CountryKN: 14813,
+ CountryKI: 134783,
+ CountryKM: 36939,
+ CountryKN: 36290,
+ CountryKP: 13335,
CountryKR: 4766,
CountryKW: 29357,
CountryKY: 6639,
@@ -3280,14 +3270,14 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryLA: 131267,
CountryLB: 42003,
CountryLC: 15344,
- CountryLI: 20634,
+ CountryLI: 9009,
CountryLK: 18001,
CountryLR: 37094,
- CountryLS: 37057,
+ CountryLS: 33567,
CountryLT: 8764,
CountryLU: 53667,
CountryLV: 24921,
- CountryLY: 21003,
+ CountryLY: 328286,
CountryMA: 36903,
CountryMC: 6758,
CountryMD: 8926,
@@ -3303,8 +3293,8 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryMP: 7131,
CountryMQ: 3215,
CountryMR: 29544,
- CountryMS: 396304,
- CountryMT: 15735,
+ CountryMS: 11139,
+ CountryMT: 33874,
CountryMU: 23889,
CountryMV: 7642,
CountryMW: 37440,
@@ -3312,14 +3302,14 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryMY: 4788,
CountryMZ: 37342,
CountryNA: 36996,
- CountryNC: 18200,
+ CountryNC: 56089,
CountryNE: 37531,
+ CountryNF: 45168,
CountryNG: 29465,
CountryNI: 14754,
CountryNL: 1136,
- CountryNO: 2119,
+ CountryNO: 29695,
CountryNP: 17501,
- CountryNR: 140504,
CountryNZ: 9790,
CountryOM: 28885,
CountryPA: 11556,
@@ -3345,7 +3335,7 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountrySB: 45891,
CountrySC: 36958,
CountrySD: 15706,
- CountrySE: 3301,
+ CountrySE: 1257,
CountrySG: 4773,
CountrySH: 33763,
CountrySI: 5603,
@@ -3358,7 +3348,7 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountrySS: 37594,
CountryST: 328191,
CountrySV: 14754,
- CountrySX: 27781,
+ CountrySX: 27734,
CountrySY: 29256,
CountrySZ: 328169,
CountryTC: 394311,
@@ -3369,9 +3359,10 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryTL: 58731,
CountryTM: 20661,
CountryTN: 37705,
- CountryTO: 38201,
+ CountryTO: 38198,
CountryTR: 47331,
CountryTT: 27800,
+ CountryTV: 23917,
CountryTW: 3462,
CountryTZ: 36908,
CountryUA: 15895,
@@ -3379,12 +3370,13 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryUS: 7922,
CountryUY: 6057,
CountryUZ: 8193,
+ CountryVA: 8978,
CountryVC: 46408,
CountryVE: 8048,
- CountryVG: 11139,
+ CountryVG: 396357,
CountryVI: 14434,
CountryVN: 7552,
- CountryVU: 45355,
+ CountryVU: 9249,
CountryWF: 45879,
CountryWS: 38800,
CountryXK: 21246,
diff --git a/internal/geoip/asntops_generate.go b/internal/geoip/asntops_generate.go
index a821035..5f52bc9 100644
--- a/internal/geoip/asntops_generate.go
+++ b/internal/geoip/asntops_generate.go
@@ -37,6 +37,8 @@ func main() {
err = json.NewDecoder(resp.Body).Decode(&defaultCountryTopASNs)
check(err)
+ // Don't use a *container.MapSet here, because the map is iterated over in
+ // the template.
defaultTopASNs := map[geoip.ASN]struct{}{}
for _, asns := range defaultCountryTopASNs {
for _, asn := range asns {
@@ -72,12 +74,14 @@ const tmplStr = `// Code generated by go run ./asntops_generate.go; DO NOT EDIT.
package geoip
+import "github.com/AdguardTeam/golibs/container"
+
// DefaultTopASNs contains all specially handled ASNs.
-var DefaultTopASNs = map[ASN]struct{}{
+var DefaultTopASNs = container.NewMapSet[ASN](
{{- range $asn, $_ := .DefaultTopASNs }}
- {{ printf "%-7s {}," ( printf "%d:" $asn ) }}
+ {{ $asn }},
{{- end }}
-}
+)
// DefaultCountryTopASNs is a mapping of a country to their top ASNs.
var DefaultCountryTopASNs = map[Country]ASN{
diff --git a/internal/geoip/file.go b/internal/geoip/file.go
index e9fd29d..ba5923d 100644
--- a/internal/geoip/file.go
+++ b/internal/geoip/file.go
@@ -8,21 +8,21 @@ import (
"os"
"sync"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
- "github.com/bluele/gcache"
"github.com/oschwald/maxminddb-golang"
)
-// File Database
-
// FileConfig is the file-based GeoIP configuration structure.
type FileConfig struct {
// AllTopASNs contains all subnets from CountryTopASNs. While scanning the
- // statistics data file this list is used as a dictionary to check if the
- // current ASN included in CountryTopASNs.
- AllTopASNs map[ASN]struct{}
+ // statistics data file this set is used to check if the current ASN
+ // included in CountryTopASNs.
+ AllTopASNs *container.MapSet[ASN]
// CountryTopASNs is a mapping of a country to their top ASNs.
CountryTopASNs map[Country]ASN
@@ -44,7 +44,7 @@ type FileConfig struct {
// File is a file implementation of [geoip.Interface].
type File struct {
- allTopASNs map[ASN]struct{}
+ allTopASNs *container.MapSet[ASN]
countryTopASNs map[Country]ASN
// mu protects asn, country, country subnet maps, and caches against
@@ -65,8 +65,8 @@ type File struct {
ipv4LocationSubnets locationSubnets
ipv6LocationSubnets locationSubnets
- ipCache gcache.Cache
- hostCache gcache.Cache
+ ipCache agdcache.Interface[any, *Location]
+ hostCache agdcache.Interface[string, *Location]
asnPath string
countryPath string
@@ -227,14 +227,11 @@ func (f *File) Data(host string, ip netip.Addr) (l *Location, err error) {
}
cacheKey := ipToCacheKey(ip)
- locVal, err := f.ipCache.Get(cacheKey)
- if err == nil {
+ item, ok := f.ipCache.Get(cacheKey)
+ if ok {
metrics.GeoIPCacheLookupsHits.Inc()
- return locVal.(*Location), nil
- } else if !errors.Is(err, gcache.KeyNotFoundError) {
- // Shouldn't happen, since we don't set a serialization function.
- panic(fmt.Errorf("getting from ip cache: %w", err))
+ return item, nil
}
metrics.GeoIPCacheLookupsMisses.Inc()
@@ -264,21 +261,15 @@ func (f *File) Data(host string, ip netip.Addr) (l *Location, err error) {
// dataByHost returns GeoIP data that has been cached previously.
func (f *File) dataByHost(host string) (l *Location) {
- locVal, err := f.hostCache.Get(host)
- if err != nil {
- if errors.Is(err, gcache.KeyNotFoundError) {
- metrics.GeoIPHostCacheLookupsMisses.Inc()
+ item, ok := f.hostCache.Get(host)
- return nil
- }
+ metrics.IncrementCond(
+ ok,
+ metrics.GeoIPHostCacheLookupsHits,
+ metrics.GeoIPHostCacheLookupsMisses,
+ )
- // Shouldn't happen, since we don't set a serialization function.
- panic(fmt.Errorf("getting from host cache: %w", err))
- }
-
- metrics.GeoIPHostCacheLookupsHits.Inc()
-
- return locVal.(*Location)
+ return item
}
// asnResult is used to retrieve autonomous system number data from a GeoIP
@@ -343,26 +334,27 @@ func (f *File) setCtry(loc *Location, ip netip.Addr) (err error) {
// setCaches sets the GeoIP data into the caches.
func (f *File) setCaches(host string, ipCacheKey any, l *Location) {
- err := f.ipCache.Set(ipCacheKey, l)
- if err != nil {
- // Shouldn't happen, since we don't set a serialization function.
- panic(fmt.Errorf("setting ip cache: %w", err))
- }
+ f.ipCache.Set(ipCacheKey, l)
if host == "" {
return
}
- err = f.hostCache.Set(host, l)
- if err != nil {
- // Shouldn't happen, since we don't set a serialization function.
- panic(fmt.Errorf("setting host cache: %w", err))
- }
+ f.hostCache.Set(host, l)
}
// Refresh implements the [agdservice.Refresher] interface for *File. It
// reopens the GeoIP database files.
-func (f *File) Refresh(_ context.Context) (err error) {
+func (f *File) Refresh(ctx context.Context) (err error) {
+ // TODO(a.garipov): Use slog.
+ log.Info("geoip_refresh: started")
+ defer log.Info("geoip_refresh: finished")
+
+ return f.refresh()
+}
+
+// refresh reopens the GeoIP database files and resets subnet mappings.
+func (f *File) refresh() (err error) {
asn, err := geoIPFromFile(f.asnPath)
if err != nil {
metrics.GeoIPUpdateStatus.WithLabelValues(f.asnPath).Set(0)
@@ -392,13 +384,17 @@ func (f *File) Refresh(_ context.Context) (err error) {
f.asn, f.country = asn, country
- hostCacheBuilder := gcache.New(f.hostCacheSize)
- if f.hostCacheSize != 0 {
- hostCacheBuilder.LRU()
+ if f.hostCacheSize == 0 {
+ f.hostCache = agdcache.Empty[string, *Location]{}
+ } else {
+ f.hostCache = agdcache.NewLRU[string, *Location](&agdcache.LRUConfig{
+ Size: f.hostCacheSize,
+ })
}
- f.hostCache = hostCacheBuilder.Build()
- f.ipCache = gcache.New(f.ipCacheSize).LRU().Build()
+ f.ipCache = agdcache.NewLRU[any, *Location](&agdcache.LRUConfig{
+ Size: f.ipCacheSize,
+ })
return nil
}
diff --git a/internal/geoip/file_test.go b/internal/geoip/file_test.go
index 9c6d7d7..96c35a1 100644
--- a/internal/geoip/file_test.go
+++ b/internal/geoip/file_test.go
@@ -199,7 +199,7 @@ func BenchmarkFile_Data(b *testing.B) {
b.Run("cache", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
locSink, errSink = g.Data(testHost, testIPWithASN)
}
@@ -211,7 +211,7 @@ func BenchmarkFile_Data(b *testing.B) {
b.Run("no_cache", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for i := range b.N {
// Alternate between the two IPs to force cache misses.
if i%2 == 0 {
locSink, errSink = g.Data(testHost, ipCountry1)
@@ -237,7 +237,7 @@ func BenchmarkNewFile(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
fileSink, errSink = geoip.NewFile(conf)
}
diff --git a/internal/geoip/filescanner.go b/internal/geoip/filescanner.go
index 53ca035..4492312 100644
--- a/internal/geoip/filescanner.go
+++ b/internal/geoip/filescanner.go
@@ -9,8 +9,6 @@ import (
"github.com/oschwald/maxminddb-golang"
)
-// GeoIP Database File Scanning
-
// helper constants for filtering the country subnets based on recommendations
// from RFC 6177, https://developers.google.com/speed/public-dns/docs/ecs,
// and our experience with ECS.
@@ -92,7 +90,7 @@ func (f *File) resetLocationSubnets(asn, country *maxminddb.Reader) (ipv4, ipv6
return nil, nil, err
}
- if _, ok := f.allTopASNs[key.asn]; !ok {
+ if !f.allTopASNs.Has(key.asn) {
continue
}
diff --git a/internal/geoip/geoip_test.go b/internal/geoip/geoip_test.go
index 09aab3c..3e1ca36 100644
--- a/internal/geoip/geoip_test.go
+++ b/internal/geoip/geoip_test.go
@@ -5,6 +5,7 @@ import (
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/testutil"
)
@@ -27,16 +28,17 @@ const (
// Test ASN data.
var (
+ allTopASNs = container.NewMapSet(
+ countryTopASNs[geoip.CountryAU],
+ countryTopASNs[geoip.CountryJP],
+ countryTopASNs[geoip.CountryUS],
+ )
+
countryTopASNs = map[geoip.Country]geoip.ASN{
geoip.CountryAU: 1221,
geoip.CountryJP: 2516,
geoip.CountryUS: 7922,
}
- allTopASNs = map[geoip.ASN]struct{}{
- countryTopASNs[geoip.CountryAU]: {},
- countryTopASNs[geoip.CountryJP]: {},
- countryTopASNs[geoip.CountryUS]: {},
- }
)
// Test queries data. See [ASN], [city], and [country] testing datum.
diff --git a/internal/metrics/backend.go b/internal/metrics/backend.go
index fe36b5e..10061f8 100644
--- a/internal/metrics/backend.go
+++ b/internal/metrics/backend.go
@@ -59,8 +59,8 @@ var ProfilesSyncTime = promauto.NewGauge(prometheus.GaugeOpts{
Help: "The time when the user profiles were synced last time.",
})
-// ProfilesSyncStatus is a gauge with the profiles sync status. Set it to 1
-// if the sync was successful. Otherwise, set it to 0.
+// ProfilesSyncStatus is a gauge with the profiles sync status. Set it to 1
+// if the sync was successful. Otherwise, set it to 0.
var ProfilesSyncStatus = promauto.NewGauge(prometheus.GaugeOpts{
Name: "profiles_sync_status",
Subsystem: subsystemBackend,
diff --git a/internal/metrics/bindtodevice.go b/internal/metrics/bindtodevice.go
index 137c994..2f46d1e 100644
--- a/internal/metrics/bindtodevice.go
+++ b/internal/metrics/bindtodevice.go
@@ -49,11 +49,23 @@ var (
}, []string{"subnet"})
// BindToDeviceUDPWriteRequestsChanSize is a gauge with the current number
- // of UDP write requests in the buffer of the channel by each subnet.
+ // of UDP write requests in the buffer of the channel for each interface
+ // listener.
BindToDeviceUDPWriteRequestsChanSize = promauto.NewGaugeVec(prometheus.GaugeOpts{
Name: "udp_write_requests_chan_size",
Namespace: namespace,
Subsystem: subsystemBindToDevice,
Help: "The current number of UDP write requests in the channel.",
- }, []string{"subnet"})
+ }, []string{"name"})
+
+ // BindToDeviceUDPWriteDurationSeconds is a histogram of durations of UDP
+ // write operations. This histogram includes only the write itself and does
+ // not include deadline setting and resetting.
+ BindToDeviceUDPWriteDurationSeconds = promauto.NewHistogramVec(prometheus.HistogramOpts{
+ Name: "udp_write_duration_seconds",
+ Namespace: namespace,
+ Subsystem: subsystemBindToDevice,
+ Help: "The duration of a write to a UDP socket.",
+ Buckets: []float64{0.001, 0.01, 0.1, 1},
+ }, []string{"name"})
)
diff --git a/internal/metrics/dnsmsg.go b/internal/metrics/dnsmsg.go
index f4a3020..8c8f5c5 100644
--- a/internal/metrics/dnsmsg.go
+++ b/internal/metrics/dnsmsg.go
@@ -1,7 +1,6 @@
package metrics
import (
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
@@ -36,8 +35,7 @@ var (
// interface.
type ClonerStat struct{}
-// type check
-var _ dnsmsg.ClonerStat = ClonerStat{}
+// The type check is performed in the test file to prevent a dependency.
// OnClone implements the [dnsmsg.ClonerStat] interface for ClonerStat.
func (ClonerStat) OnClone(isFull bool) {
diff --git a/internal/metrics/dnsmsg_test.go b/internal/metrics/dnsmsg_test.go
new file mode 100644
index 0000000..3461403
--- /dev/null
+++ b/internal/metrics/dnsmsg_test.go
@@ -0,0 +1,9 @@
+package metrics_test
+
+import (
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+)
+
+// type check
+var _ dnsmsg.ClonerStat = metrics.ClonerStat{}
diff --git a/internal/metrics/dnssvc.go b/internal/metrics/dnssvc.go
index 0228201..d86cffc 100644
--- a/internal/metrics/dnssvc.go
+++ b/internal/metrics/dnssvc.go
@@ -100,11 +100,22 @@ var DNSSvcFilteringDuration = promauto.NewHistogram(prometheus.HistogramOpts{
},
})
-// DNSSvcUnknownDedicatedTotal is the counter of queries that have been dropped,
-// because the local-address data was not recognized.
-var DNSSvcUnknownDedicatedTotal = promauto.NewCounter(prometheus.CounterOpts{
- Name: "unknown_dedicated",
- Namespace: namespace,
- Subsystem: subsystemDNSSvc,
- Help: "The number of dropped queries for unrecognized dedicated addresses.",
-})
+var (
+ // DNSSvcUnknownDedicatedTotal is the counter of queries that have been dropped,
+ // because the local-address data was not recognized.
+ DNSSvcUnknownDedicatedTotal = promauto.NewCounter(prometheus.CounterOpts{
+ Name: "unknown_dedicated",
+ Namespace: namespace,
+ Subsystem: subsystemDNSSvc,
+ Help: "The number of dropped queries for unrecognized dedicated addresses.",
+ })
+
+ // DNSSvcDoHAuthFailsTotal is the counter of DoH basic authentication
+ // failures.
+ DNSSvcDoHAuthFailsTotal = promauto.NewCounter(prometheus.CounterOpts{
+ Name: "doh_authentication_fails",
+ Namespace: namespace,
+ Subsystem: subsystemDNSSvc,
+ Help: "The number of authentication failures for DoH auth.",
+ })
+)
diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go
index 110013c..c2405f7 100644
--- a/internal/metrics/metrics.go
+++ b/internal/metrics/metrics.go
@@ -1,6 +1,9 @@
// Package metrics contains definitions of most of the prometheus metrics
// that we use in AdGuard DNS.
//
+// NOTE: Prefer to not import any packages from the current module here,
+// because a lot of packages import metrics, and so import cycles may happen.
+//
// TODO(ameshkov): consider not using promauto.
package metrics
diff --git a/internal/metrics/research.go b/internal/metrics/research.go
index 3697216..a26d2e4 100644
--- a/internal/metrics/research.go
+++ b/internal/metrics/research.go
@@ -1,138 +1,20 @@
package metrics
import (
- "github.com/AdguardTeam/golibs/log"
- "github.com/miekg/dns"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
- "github.com/prometheus/common/model"
)
-// ResearchRequestsPerCountryTotal counts the total number of queries per
-// country from anonymous users.
-var ResearchRequestsPerCountryTotal = promauto.NewCounterVec(prometheus.CounterOpts{
- Name: "requests_per_country_total",
- Namespace: namespace,
- Subsystem: subsystemResearch,
- Help: "The total number of DNS queries per country from anonymous users.",
-}, []string{"country"})
-
-// ResearchBlockedRequestsPerCountryTotal counts the number of blocked queries
-// per country from anonymous users.
-var ResearchBlockedRequestsPerCountryTotal = promauto.NewCounterVec(prometheus.CounterOpts{
- Name: "blocked_per_country_total",
- Namespace: namespace,
- Subsystem: subsystemResearch,
- Help: "The number of blocked DNS queries per country from anonymous users.",
-}, []string{"filter", "country"})
-
-// ResearchRequestsPerSubdivTotal counts the total number of queries per country
-// from anonymous users.
-var ResearchRequestsPerSubdivTotal = promauto.NewCounterVec(prometheus.CounterOpts{
- Name: "requests_per_subdivision_total",
- Namespace: namespace,
- Subsystem: subsystemResearch,
- Help: `The total number of DNS queries per countries with top ` +
- `subdivision from anonymous users.`,
-}, []string{"country", "subdivision"})
-
-// ResearchBlockedRequestsPerSubdivTotal counts the number of blocked queries
-// per country from anonymous users.
-var ResearchBlockedRequestsPerSubdivTotal = promauto.NewCounterVec(prometheus.CounterOpts{
- Name: "blocked_per_subdivision_total",
- Namespace: namespace,
- Subsystem: subsystemResearch,
- Help: `The number of blocked DNS queries per countries with top ` +
- `subdivision from anonymous users.`,
-}, []string{"filter", "country", "subdivision"})
-
-// ResearchResponseECH counts the number of DNS responses with a ECH config.
-var ResearchResponseECH = promauto.NewCounter(prometheus.CounterOpts{
- Name: "response_ech",
- Namespace: namespace,
- Subsystem: subsystemResearch,
- Help: `The number of DNS responses with a ECH config.`,
-})
-
-// ResearchData contains data for research metrics.
-type ResearchData struct {
- OriginalResponse *dns.Msg
- FilterID string
- Country string
- TopSubdivision string
- Host string
- QType uint16
- Blocked bool
-}
-
-// ReportResearch reports metrics to prometheus that we may need to conduct
-// researches. If researchLogs is true, this method may also write additional
-// INFO-level logs.
-func ReportResearch(data *ResearchData, researchLogs bool) {
- ctry := data.Country
-
- var subdiv string
- if model.LabelValue(data.TopSubdivision).IsValid() {
- subdiv = data.TopSubdivision
- }
-
- if data.Blocked {
- reportResearchBlocked(data.FilterID, ctry, subdiv)
- }
-
- reportResearchRequest(ctry, subdiv)
-
- if data.QType == dns.TypeHTTPS {
- reportResearchECH(data.Host, data.OriginalResponse, researchLogs)
- }
-}
-
-// reportResearchECH checks if the response has ECH config and if it does,
-// reports to metrics and writes to log.
-func reportResearchECH(host string, origResp *dns.Msg, researchLogs bool) {
- if origResp == nil {
- return
- }
-
- for _, rr := range origResp.Answer {
- svcb, ok := rr.(*dns.HTTPS)
- if !ok {
- continue
- }
-
- reportECHConfig(svcb.SVCB, researchLogs, host)
- }
-}
-
-// reportECHConfig iterates over SVCB records, finds records with ECH
-// configuration, reports to metrics, and if researchLogs is enabled writes to
-// log.
-func reportECHConfig(svcb dns.SVCB, researchLogs bool, host string) {
- for _, v := range svcb.Value {
- if v.Key() != dns.SVCB_ECHCONFIG {
- continue
- }
-
- ResearchResponseECH.Inc()
-
- if researchLogs {
- log.Info("research: ech-enabled: %q", host)
- }
- }
-}
-
-// reportResearchBlocked reports on a blocked request to the research metrics.
-func reportResearchBlocked(fltID, ctry, subdiv string) {
- ResearchBlockedRequestsPerCountryTotal.WithLabelValues(fltID, ctry).Inc()
- if subdiv != "" {
- ResearchBlockedRequestsPerSubdivTotal.WithLabelValues(fltID, ctry, subdiv).Inc()
- }
-}
-
-// reportResearchBlocked reports on a request to the research metrics.
-func reportResearchRequest(ctry, subdiv string) {
- ResearchRequestsPerCountryTotal.WithLabelValues(ctry).Inc()
- if subdiv != "" {
- ResearchRequestsPerSubdivTotal.WithLabelValues(ctry, subdiv).Inc()
- }
+// ExperimentGauge returns the gauge used to inform about running experiments.
+func ExperimentGauge(constLabels prometheus.Labels) (g prometheus.Gauge) {
+ return promauto.NewGauge(
+ prometheus.GaugeOpts{
+ Name: "experiment_enabled",
+ Namespace: namespace,
+ Subsystem: subsystemResearch,
+ Help: `A metric with a constant value of 1 labeled by experiments that are available ` +
+ `and enabled.`,
+ ConstLabels: constLabels,
+ },
+ )
}
diff --git a/internal/metrics/tls.go b/internal/metrics/tls.go
index 9134d09..cfe677f 100644
--- a/internal/metrics/tls.go
+++ b/internal/metrics/tls.go
@@ -3,6 +3,7 @@ package metrics
import (
"crypto/tls"
"fmt"
+ "slices"
"strings"
"github.com/AdguardTeam/golibs/netutil"
@@ -108,10 +109,8 @@ func TLSMetricsAfterHandshake(
func TLSMetricsBeforeHandshake(proto string) (f func(*tls.ClientHelloInfo) (*tls.Config, error)) {
return func(info *tls.ClientHelloInfo) (*tls.Config, error) {
var maxVersion uint16
- for _, v := range info.SupportedVersions {
- if v > maxVersion {
- maxVersion = v
- }
+ if len(info.SupportedVersions) > 0 {
+ maxVersion = slices.Max(info.SupportedVersions)
}
supProtos := make([]string, len(info.SupportedProtos))
diff --git a/internal/metrics/usercount_internal_test.go b/internal/metrics/usercount_internal_test.go
index 230370e..198ded2 100644
--- a/internal/metrics/usercount_internal_test.go
+++ b/internal/metrics/usercount_internal_test.go
@@ -188,7 +188,7 @@ func TestUserCounter_simple(t *testing.T) {
for d, h := now.Day(), now.Hour(); now.Day() == d; h = now.Hour() {
t.Run(strconv.Itoa(now.Hour()), func(t *testing.T) {
for ; now.Hour() == h; now = now.Add(1 * time.Minute) {
- for i := 0; i < ipsPerMinute; i++ {
+ for range ipsPerMinute {
c.record(now, randIP(t, r, netutil.AddrFamilyIPv4), true)
}
}
@@ -213,7 +213,7 @@ func BenchmarkUserCounter_Estimate(b *testing.B) {
sparseCounter := newUserCounter()
for d, now := zeroTime.Day(), zeroTime; d == now.Day(); now = now.Add(time.Minute) {
r := rand.New(rand.NewSource(randSeed))
- for i := 0; i < n; i++ {
+ for range n {
sparseCounter.record(now, randIP(b, r, netutil.AddrFamilyIPv6), true)
}
}
@@ -221,7 +221,7 @@ func BenchmarkUserCounter_Estimate(b *testing.B) {
seqCounter := newUserCounter()
for d, now := zeroTime.Day(), zeroTime; d == now.Day(); now = now.Add(time.Minute) {
addr := netip.AddrFrom16([16]byte{})
- for i := 0; i < n; i++ {
+ for range n {
addr = addr.Next()
seqCounter.record(now, addr, true)
}
@@ -230,7 +230,7 @@ func BenchmarkUserCounter_Estimate(b *testing.B) {
b.Run("sparse", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
uint64Sink, uint64Sink = sparseCounter.estimate()
}
})
@@ -238,7 +238,7 @@ func BenchmarkUserCounter_Estimate(b *testing.B) {
b.Run("sequential", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
uint64Sink, uint64Sink = seqCounter.estimate()
}
})
diff --git a/internal/metrics/websvc.go b/internal/metrics/websvc.go
index e324e18..d31c3fc 100644
--- a/internal/metrics/websvc.go
+++ b/internal/metrics/websvc.go
@@ -10,7 +10,7 @@ var (
Name: "websvc_requests_total",
Namespace: namespace,
Subsystem: subsystemWebSvc,
- Help: "The number of DNS requests for websvc.",
+ Help: "The number of HTTP requests for websvc.",
}, []string{"kind"})
// WebSvcError404RequestsTotal is a counter with total number of
@@ -61,6 +61,12 @@ var (
"kind": "adult_blocking_page",
})
+ // WebSvcGeneralBlockingPageRequestsTotal is a counter with total number
+ // of requests for general blocking page.
+ WebSvcGeneralBlockingPageRequestsTotal = webSvcRequestsTotal.With(prometheus.Labels{
+ "kind": "general_blocking_page",
+ })
+
// WebSvcSafeBrowsingPageRequestsTotal is a counter with total number
// of requests for safe browsing page.
WebSvcSafeBrowsingPageRequestsTotal = webSvcRequestsTotal.With(prometheus.Labels{
diff --git a/internal/profiledb/internal/filecachepb/filecache.pb.go b/internal/profiledb/internal/filecachepb/filecache.pb.go
index 45097d3..a793cc2 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.31.0
-// protoc v4.25.1
+// protoc-gen-go v1.33.0
+// protoc v4.25.3
// source: filecache.proto
package filecachepb
@@ -653,8 +653,8 @@ type BlockingModeCustomIP struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Ipv4 []byte `protobuf:"bytes,1,opt,name=ipv4,proto3" json:"ipv4,omitempty"`
- Ipv6 []byte `protobuf:"bytes,2,opt,name=ipv6,proto3" json:"ipv6,omitempty"`
+ Ipv4 [][]byte `protobuf:"bytes,1,rep,name=ipv4,proto3" json:"ipv4,omitempty"`
+ Ipv6 [][]byte `protobuf:"bytes,2,rep,name=ipv6,proto3" json:"ipv6,omitempty"`
}
func (x *BlockingModeCustomIP) Reset() {
@@ -689,14 +689,14 @@ func (*BlockingModeCustomIP) Descriptor() ([]byte, []int) {
return file_filecache_proto_rawDescGZIP(), []int{6}
}
-func (x *BlockingModeCustomIP) GetIpv4() []byte {
+func (x *BlockingModeCustomIP) GetIpv4() [][]byte {
if x != nil {
return x.Ipv4
}
return nil
}
-func (x *BlockingModeCustomIP) GetIpv6() []byte {
+func (x *BlockingModeCustomIP) GetIpv6() [][]byte {
if x != nil {
return x.Ipv6
}
@@ -822,11 +822,12 @@ type Device struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- DeviceId string `protobuf:"bytes,1,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
- LinkedIp []byte `protobuf:"bytes,2,opt,name=linked_ip,json=linkedIp,proto3" json:"linked_ip,omitempty"`
- DeviceName string `protobuf:"bytes,3,opt,name=device_name,json=deviceName,proto3" json:"device_name,omitempty"`
- DedicatedIps [][]byte `protobuf:"bytes,4,rep,name=dedicated_ips,json=dedicatedIps,proto3" json:"dedicated_ips,omitempty"`
- FilteringEnabled bool `protobuf:"varint,5,opt,name=filtering_enabled,json=filteringEnabled,proto3" json:"filtering_enabled,omitempty"`
+ DeviceId string `protobuf:"bytes,1,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
+ LinkedIp []byte `protobuf:"bytes,2,opt,name=linked_ip,json=linkedIp,proto3" json:"linked_ip,omitempty"`
+ DeviceName string `protobuf:"bytes,3,opt,name=device_name,json=deviceName,proto3" json:"device_name,omitempty"`
+ DedicatedIps [][]byte `protobuf:"bytes,4,rep,name=dedicated_ips,json=dedicatedIps,proto3" json:"dedicated_ips,omitempty"`
+ FilteringEnabled bool `protobuf:"varint,5,opt,name=filtering_enabled,json=filteringEnabled,proto3" json:"filtering_enabled,omitempty"`
+ Authentication *AuthenticationSettings `protobuf:"bytes,6,opt,name=authentication,proto3" json:"authentication,omitempty"`
}
func (x *Device) Reset() {
@@ -896,6 +897,13 @@ func (x *Device) GetFilteringEnabled() bool {
return false
}
+func (x *Device) GetAuthentication() *AuthenticationSettings {
+ if x != nil {
+ return x.Authentication
+ }
+ return nil
+}
+
type AccessSettings struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1030,6 +1038,81 @@ func (x *CidrRange) GetPrefix() uint32 {
return 0
}
+type AuthenticationSettings struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ DohAuthOnly bool `protobuf:"varint,1,opt,name=doh_auth_only,json=dohAuthOnly,proto3" json:"doh_auth_only,omitempty"`
+ // Types that are assignable to DohPasswordHash:
+ //
+ // *AuthenticationSettings_PasswordHashBcrypt
+ DohPasswordHash isAuthenticationSettings_DohPasswordHash `protobuf_oneof:"doh_password_hash"`
+}
+
+func (x *AuthenticationSettings) Reset() {
+ *x = AuthenticationSettings{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_filecache_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *AuthenticationSettings) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AuthenticationSettings) ProtoMessage() {}
+
+func (x *AuthenticationSettings) ProtoReflect() protoreflect.Message {
+ mi := &file_filecache_proto_msgTypes[13]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use AuthenticationSettings.ProtoReflect.Descriptor instead.
+func (*AuthenticationSettings) Descriptor() ([]byte, []int) {
+ return file_filecache_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *AuthenticationSettings) GetDohAuthOnly() bool {
+ if x != nil {
+ return x.DohAuthOnly
+ }
+ return false
+}
+
+func (m *AuthenticationSettings) GetDohPasswordHash() isAuthenticationSettings_DohPasswordHash {
+ if m != nil {
+ return m.DohPasswordHash
+ }
+ return nil
+}
+
+func (x *AuthenticationSettings) GetPasswordHashBcrypt() []byte {
+ if x, ok := x.GetDohPasswordHash().(*AuthenticationSettings_PasswordHashBcrypt); ok {
+ return x.PasswordHashBcrypt
+ }
+ return nil
+}
+
+type isAuthenticationSettings_DohPasswordHash interface {
+ isAuthenticationSettings_DohPasswordHash()
+}
+
+type AuthenticationSettings_PasswordHashBcrypt struct {
+ PasswordHashBcrypt []byte `protobuf:"bytes,2,opt,name=password_hash_bcrypt,json=passwordHashBcrypt,proto3,oneof"`
+}
+
+func (*AuthenticationSettings_PasswordHashBcrypt) isAuthenticationSettings_DohPasswordHash() {}
+
var File_filecache_proto protoreflect.FileDescriptor
var file_filecache_proto_rawDesc = []byte{
@@ -1180,14 +1263,14 @@ var file_filecache_proto_rawDesc = []byte{
0x01, 0x28, 0x0d, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x3e, 0x0a, 0x14,
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x75, 0x73, 0x74,
- 0x6f, 0x6d, 0x49, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01, 0x20, 0x01,
+ 0x6f, 0x6d, 0x49, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01, 0x20, 0x03,
0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x36,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x36, 0x22, 0x16, 0x0a, 0x14,
+ 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x36, 0x22, 0x16, 0x0a, 0x14,
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x58, 0x44, 0x4f,
0x4d, 0x41, 0x49, 0x4e, 0x22, 0x14, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67,
0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x75, 0x6c, 0x6c, 0x49, 0x50, 0x22, 0x15, 0x0a, 0x13, 0x42, 0x6c,
0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x45, 0x46, 0x55, 0x53, 0x45,
- 0x44, 0x22, 0xb5, 0x01, 0x0a, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09,
+ 0x44, 0x22, 0x80, 0x02, 0x0a, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x69, 0x6e,
0x6b, 0x65, 0x64, 0x5f, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6c, 0x69,
@@ -1198,29 +1281,43 @@ var file_filecache_proto_rawDesc = []byte{
0x64, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x49, 0x70, 0x73, 0x12, 0x2b, 0x0a, 0x11,
0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69,
- 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x8a, 0x02, 0x0a, 0x0e, 0x41, 0x63,
- 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3b, 0x0a, 0x0e,
- 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x01,
- 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62,
- 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f,
- 0x77, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x69, 0x64, 0x72, 0x12, 0x3b, 0x0a, 0x0e, 0x62, 0x6c, 0x6f,
- 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28,
- 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x43, 0x69,
- 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69,
- 0x73, 0x74, 0x43, 0x69, 0x64, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c,
- 0x69, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x61,
- 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x62,
- 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18, 0x04, 0x20, 0x03,
- 0x28, 0x0d, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e,
- 0x12, 0x34, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x64, 0x6f,
- 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09,
- 0x52, 0x14, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69,
- 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x3d, 0x0a, 0x09, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61,
- 0x6e, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a,
- 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70,
- 0x72, 0x65, 0x66, 0x69, 0x78, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x63,
- 0x61, 0x63, 0x68, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x49, 0x0a, 0x0e, 0x61, 0x75, 0x74,
+ 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x41, 0x75,
+ 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74,
+ 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x8a, 0x02, 0x0a, 0x0e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53,
+ 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3b, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
+ 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x43, 0x69, 0x64, 0x72,
+ 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74,
+ 0x43, 0x69, 0x64, 0x72, 0x12, 0x3b, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73,
+ 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70,
+ 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e,
+ 0x67, 0x65, 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x69, 0x64,
+ 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61,
+ 0x73, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c,
+ 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c,
+ 0x69, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x62,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x62,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f,
+ 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x62, 0x6c, 0x6f,
+ 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x75, 0x6c, 0x65,
+ 0x73, 0x22, 0x3d, 0x0a, 0x09, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x18,
+ 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
+ 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66,
+ 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
+ 0x22, 0x85, 0x01, 0x0a, 0x16, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x64,
+ 0x6f, 0x68, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x0b, 0x64, 0x6f, 0x68, 0x41, 0x75, 0x74, 0x68, 0x4f, 0x6e, 0x6c, 0x79, 0x12,
+ 0x32, 0x0a, 0x14, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68,
+ 0x5f, 0x62, 0x63, 0x72, 0x79, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52,
+ 0x12, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x48, 0x61, 0x73, 0x68, 0x42, 0x63, 0x72,
+ 0x79, 0x70, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x64, 0x6f, 0x68, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77,
+ 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x66, 0x69,
+ 0x6c, 0x65, 0x63, 0x61, 0x63, 0x68, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x33,
}
var (
@@ -1235,7 +1332,7 @@ func file_filecache_proto_rawDescGZIP() []byte {
return file_filecache_proto_rawDescData
}
-var file_filecache_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
+var file_filecache_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
var file_filecache_proto_goTypes = []interface{}{
(*FileCache)(nil), // 0: profiledb.FileCache
(*Profile)(nil), // 1: profiledb.Profile
@@ -1250,11 +1347,12 @@ var file_filecache_proto_goTypes = []interface{}{
(*Device)(nil), // 10: profiledb.Device
(*AccessSettings)(nil), // 11: profiledb.AccessSettings
(*CidrRange)(nil), // 12: profiledb.CidrRange
- (*timestamppb.Timestamp)(nil), // 13: google.protobuf.Timestamp
- (*durationpb.Duration)(nil), // 14: google.protobuf.Duration
+ (*AuthenticationSettings)(nil), // 13: profiledb.AuthenticationSettings
+ (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp
+ (*durationpb.Duration)(nil), // 15: google.protobuf.Duration
}
var file_filecache_proto_depIdxs = []int32{
- 13, // 0: profiledb.FileCache.sync_time:type_name -> google.protobuf.Timestamp
+ 14, // 0: profiledb.FileCache.sync_time:type_name -> google.protobuf.Timestamp
1, // 1: profiledb.FileCache.profiles:type_name -> profiledb.Profile
10, // 2: profiledb.FileCache.devices:type_name -> profiledb.Device
2, // 3: profiledb.Profile.parental:type_name -> profiledb.ParentalProtectionSettings
@@ -1262,8 +1360,8 @@ var file_filecache_proto_depIdxs = []int32{
7, // 5: profiledb.Profile.blocking_mode_nxdomain:type_name -> profiledb.BlockingModeNXDOMAIN
8, // 6: profiledb.Profile.blocking_mode_null_ip:type_name -> profiledb.BlockingModeNullIP
9, // 7: profiledb.Profile.blocking_mode_refused:type_name -> profiledb.BlockingModeREFUSED
- 13, // 8: profiledb.Profile.update_time:type_name -> google.protobuf.Timestamp
- 14, // 9: profiledb.Profile.filtered_response_ttl:type_name -> google.protobuf.Duration
+ 14, // 8: profiledb.Profile.update_time:type_name -> google.protobuf.Timestamp
+ 15, // 9: profiledb.Profile.filtered_response_ttl:type_name -> google.protobuf.Duration
3, // 10: profiledb.Profile.safe_browsing:type_name -> profiledb.SafeBrowsingSettings
11, // 11: profiledb.Profile.access:type_name -> profiledb.AccessSettings
4, // 12: profiledb.ParentalProtectionSettings.schedule:type_name -> profiledb.ParentalProtectionSchedule
@@ -1274,13 +1372,14 @@ var file_filecache_proto_depIdxs = []int32{
5, // 17: profiledb.ParentalProtectionSchedule.fri:type_name -> profiledb.DayRange
5, // 18: profiledb.ParentalProtectionSchedule.sat:type_name -> profiledb.DayRange
5, // 19: profiledb.ParentalProtectionSchedule.sun:type_name -> profiledb.DayRange
- 12, // 20: profiledb.AccessSettings.allowlist_cidr:type_name -> profiledb.CidrRange
- 12, // 21: profiledb.AccessSettings.blocklist_cidr:type_name -> profiledb.CidrRange
- 22, // [22:22] is the sub-list for method output_type
- 22, // [22:22] is the sub-list for method input_type
- 22, // [22:22] is the sub-list for extension type_name
- 22, // [22:22] is the sub-list for extension extendee
- 0, // [0:22] is the sub-list for field type_name
+ 13, // 20: profiledb.Device.authentication:type_name -> profiledb.AuthenticationSettings
+ 12, // 21: profiledb.AccessSettings.allowlist_cidr:type_name -> profiledb.CidrRange
+ 12, // 22: profiledb.AccessSettings.blocklist_cidr:type_name -> profiledb.CidrRange
+ 23, // [23:23] is the sub-list for method output_type
+ 23, // [23:23] is the sub-list for method input_type
+ 23, // [23:23] is the sub-list for extension type_name
+ 23, // [23:23] is the sub-list for extension extendee
+ 0, // [0:23] is the sub-list for field type_name
}
func init() { file_filecache_proto_init() }
@@ -1445,6 +1544,18 @@ func file_filecache_proto_init() {
return nil
}
}
+ file_filecache_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*AuthenticationSettings); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
}
file_filecache_proto_msgTypes[1].OneofWrappers = []interface{}{
(*Profile_BlockingModeCustomIp)(nil),
@@ -1452,13 +1563,16 @@ func file_filecache_proto_init() {
(*Profile_BlockingModeNullIp)(nil),
(*Profile_BlockingModeRefused)(nil),
}
+ file_filecache_proto_msgTypes[13].OneofWrappers = []interface{}{
+ (*AuthenticationSettings_PasswordHashBcrypt)(nil),
+ }
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_filecache_proto_rawDesc,
NumEnums: 0,
- NumMessages: 13,
+ NumMessages: 14,
NumExtensions: 0,
NumServices: 0,
},
diff --git a/internal/profiledb/internal/filecachepb/filecache.proto b/internal/profiledb/internal/filecachepb/filecache.proto
index 0fdac2a..081f850 100644
--- a/internal/profiledb/internal/filecachepb/filecache.proto
+++ b/internal/profiledb/internal/filecachepb/filecache.proto
@@ -72,8 +72,8 @@ message DayRange {
}
message BlockingModeCustomIP {
- bytes ipv4 = 1;
- bytes ipv6 = 2;
+ repeated bytes ipv4 = 1;
+ repeated bytes ipv6 = 2;
}
message BlockingModeNXDOMAIN {}
@@ -88,6 +88,7 @@ message Device {
string device_name = 3;
repeated bytes dedicated_ips = 4;
bool filtering_enabled = 5;
+ AuthenticationSettings authentication = 6;
}
message AccessSettings {
@@ -102,3 +103,10 @@ message CidrRange {
bytes address = 1;
uint32 prefix = 2;
}
+
+message AuthenticationSettings {
+ bool doh_auth_only = 1;
+ oneof doh_password_hash {
+ bytes password_hash_bcrypt = 2;
+ }
+}
diff --git a/internal/profiledb/internal/filecachepb/filecachepb.go b/internal/profiledb/internal/filecachepb/filecachepb.go
index f24cf12..4d74394 100644
--- a/internal/profiledb/internal/filecachepb/filecachepb.go
+++ b/internal/profiledb/internal/filecachepb/filecachepb.go
@@ -8,6 +8,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdprotobuf"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
@@ -158,18 +159,22 @@ func (x *ParentalProtectionSchedule) toInternal() (s *agd.ParentalProtectionSche
func blockingModeToInternal(pbm isProfile_BlockingMode) (m dnsmsg.BlockingMode, err error) {
switch pbm := pbm.(type) {
case *Profile_BlockingModeCustomIp:
- custom := &dnsmsg.BlockingModeCustomIP{}
- err = custom.IPv4.UnmarshalBinary(pbm.BlockingModeCustomIp.Ipv4)
+ var ipv4 []netip.Addr
+ ipv4, err = agdprotobuf.ByteSlicesToIPs(pbm.BlockingModeCustomIp.Ipv4)
if err != nil {
- return nil, fmt.Errorf("bad custom ipv4: %w", err)
+ return nil, fmt.Errorf("bad v4 custom ips: %w", err)
}
- err = custom.IPv6.UnmarshalBinary(pbm.BlockingModeCustomIp.Ipv6)
+ var ipv6 []netip.Addr
+ ipv6, err = agdprotobuf.ByteSlicesToIPs(pbm.BlockingModeCustomIp.Ipv6)
if err != nil {
- return nil, fmt.Errorf("bad custom ipv6: %w", err)
+ return nil, fmt.Errorf("bad v6 custom ips: %w", err)
}
- return custom, nil
+ return &dnsmsg.BlockingModeCustomIP{
+ IPv4: ipv4,
+ IPv6: ipv6,
+ }, nil
case *Profile_BlockingModeNxdomain:
return &dnsmsg.BlockingModeNXDOMAIN{}, nil
case *Profile_BlockingModeNullIp:
@@ -212,7 +217,13 @@ func (x *Device) toInternal() (d *agd.Device, err error) {
return nil, fmt.Errorf("dedicated ips: %w", err)
}
+ auth, err := x.Authentication.toInternal()
+ if err != nil {
+ return nil, fmt.Errorf("auth: %s: %w", x.DeviceId, err)
+ }
+
return &agd.Device{
+ Auth: auth,
// Consider device IDs to have been prevalidated.
ID: agd.DeviceID(x.DeviceId),
LinkedIP: linkedIP,
@@ -223,6 +234,44 @@ func (x *Device) toInternal() (d *agd.Device, err error) {
}, nil
}
+// toInternal converts a protobuf auth settings structure to an internal one.
+// If x is nil, toInternal returns non-nil settings with Enabled field set to
+// false, otherwise it sets the Enabled field to true.
+func (x *AuthenticationSettings) toInternal() (s *agd.AuthSettings, err error) {
+ if x == nil {
+ return &agd.AuthSettings{
+ Enabled: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ }, nil
+ }
+
+ ph, err := dohPasswordToInternal(x.DohPasswordHash)
+ if err != nil {
+ return nil, fmt.Errorf("password hash: %w", err)
+ }
+
+ return &agd.AuthSettings{
+ PasswordHash: ph,
+ Enabled: true,
+ DoHAuthOnly: x.DohAuthOnly,
+ }, nil
+}
+
+// dohPasswordToInternal converts a protobuf DoH password hash sum-type to an
+// internal one. If pbp is nil, it returns nil.
+func dohPasswordToInternal(
+ pbp isAuthenticationSettings_DohPasswordHash,
+) (p agdpasswd.Authenticator, err error) {
+ switch pbp := pbp.(type) {
+ case nil:
+ return nil, nil
+ case *AuthenticationSettings_PasswordHashBcrypt:
+ return agdpasswd.NewPasswordHashBcrypt(pbp.PasswordHashBcrypt), nil
+ default:
+ return nil, fmt.Errorf("bad pb auth doh password hash %T(%[1]v)", pbp)
+ }
+}
+
// toInternal converts a protobuf safe browsing settings structure to an
// internal one.
func (x *SafeBrowsingSettings) toInternal() (s *agd.SafeBrowsingSettings) {
@@ -411,8 +460,8 @@ func blockingModeToProtobuf(m dnsmsg.BlockingMode) (pbBlockingMode isProfile_Blo
case *dnsmsg.BlockingModeCustomIP:
return &Profile_BlockingModeCustomIp{
BlockingModeCustomIp: &BlockingModeCustomIP{
- Ipv4: ipToBytes(m.IPv4),
- Ipv6: ipToBytes(m.IPv6),
+ Ipv4: ipsToByteSlices(m.IPv4),
+ Ipv6: ipsToByteSlices(m.IPv6),
},
}
case *dnsmsg.BlockingModeNXDOMAIN:
@@ -445,6 +494,7 @@ func devicesToProtobuf(devices []*agd.Device) (pbDevices []*Device) {
pbDevices = make([]*Device, 0, len(devices))
for _, d := range devices {
pbDevices = append(pbDevices, &Device{
+ Authentication: authToProtobuf(d.Auth),
DeviceId: string(d.ID),
LinkedIp: ipToBytes(d.LinkedIP),
DeviceName: string(d.Name),
@@ -456,6 +506,34 @@ func devicesToProtobuf(devices []*agd.Device) (pbDevices []*Device) {
return pbDevices
}
+// authToProtobuf converts an auth device settings to a protobuf struct.
+// Returns nil if the given settings have Enabled field set to false.
+func authToProtobuf(s *agd.AuthSettings) (a *AuthenticationSettings) {
+ if s == nil || !s.Enabled {
+ return nil
+ }
+
+ return &AuthenticationSettings{
+ DohAuthOnly: s.DoHAuthOnly,
+ DohPasswordHash: dohPasswordToProtobuf(s.PasswordHash),
+ }
+}
+
+// dohPasswordToProtobuf converts an auth password hash sum-type to a protobuf
+// one.
+func dohPasswordToProtobuf(p agdpasswd.Authenticator) (pbp isAuthenticationSettings_DohPasswordHash) {
+ switch p := p.(type) {
+ case agdpasswd.AllowAuthenticator:
+ return nil
+ case *agdpasswd.PasswordHashBcrypt:
+ return &AuthenticationSettings_PasswordHashBcrypt{
+ PasswordHashBcrypt: p.PasswordHash(),
+ }
+ default:
+ panic(fmt.Errorf("bad password hash %T(%[1]v)", p))
+ }
+}
+
// ipsToByteSlices is a wrapper around netip.Addr.MarshalBinary that ignores the
// always-nil errors.
func ipsToByteSlices(ips []netip.Addr) (data [][]byte) {
diff --git a/internal/profiledb/internal/filecachepb/filecachepb_internal_test.go b/internal/profiledb/internal/filecachepb/filecachepb_internal_test.go
index 9658447..4609951 100644
--- a/internal/profiledb/internal/filecachepb/filecachepb_internal_test.go
+++ b/internal/profiledb/internal/filecachepb/filecachepb_internal_test.go
@@ -65,7 +65,7 @@ func BenchmarkCache(b *testing.B) {
b.Run("to_protobuf", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
fileCacheSink = toProtobuf(cacheSink)
}
@@ -78,7 +78,7 @@ func BenchmarkCache(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
gotCache, errSink = toInternal(fileCacheSink)
}
@@ -89,7 +89,7 @@ func BenchmarkCache(b *testing.B) {
b.Run("encode", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
bytesSink, errSink = proto.Marshal(fileCacheSink)
}
@@ -100,7 +100,7 @@ func BenchmarkCache(b *testing.B) {
b.Run("decode", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
errSink = proto.Unmarshal(bytesSink, fileCacheSink)
}
diff --git a/internal/profiledb/internal/internal.go b/internal/profiledb/internal/internal.go
index da6491c..d2a5163 100644
--- a/internal/profiledb/internal/internal.go
+++ b/internal/profiledb/internal/internal.go
@@ -12,7 +12,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 = 9
+const FileCacheVersion = 11
// 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 c238417..28d608d 100644
--- a/internal/profiledb/internal/profiledbtest/profiledbtest.go
+++ b/internal/profiledb/internal/profiledbtest/profiledbtest.go
@@ -8,6 +8,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
@@ -28,6 +29,11 @@ func NewProfile(tb testing.TB) (p *agd.Profile, d *agd.Device) {
require.NoError(tb, err)
dev := &agd.Device{
+ Auth: &agd.AuthSettings{
+ Enabled: true,
+ DoHAuthOnly: true,
+ PasswordHash: agdpasswd.NewPasswordHashBcrypt([]byte("test")),
+ },
ID: DeviceID,
LinkedIP: netip.MustParseAddr("1.2.3.4"),
Name: "dev1",
diff --git a/internal/profiledb/profiledb.go b/internal/profiledb/profiledb.go
index 0991127..cdaf90d 100644
--- a/internal/profiledb/profiledb.go
+++ b/internal/profiledb/profiledb.go
@@ -12,6 +12,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb/internal"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb/internal/filecachepb"
@@ -77,6 +78,9 @@ type Config struct {
// Storage returns the data for this profile DB.
Storage Storage
+ // ErrColl is used to collect errors during refreshes.
+ ErrColl errcoll.Interface
+
// CacheFilePath is the path to the profile cache file. If cacheFilePath is
// the string "none", filesystem cache is disabled.
CacheFilePath string
@@ -104,6 +108,9 @@ type Default struct {
// of it.
refreshMu *sync.Mutex
+ // errColl is used to collect errors during refreshes.
+ errColl errcoll.Interface
+
// cache is the filesystem-cache storage used by this profile database.
cache internal.FileCacheStorage
@@ -165,6 +172,7 @@ func New(conf *Config) (db *Default, err error) {
db = &Default{
mapsMu: &sync.RWMutex{},
refreshMu: &sync.Mutex{},
+ errColl: conf.ErrColl,
cache: cacheStorage,
storage: conf.Storage,
syncTime: time.Time{},
@@ -215,14 +223,18 @@ var _ agdservice.Refresher = (*Default)(nil)
// TODO(a.garipov): Consider splitting the full refresh logic into a separate
// method.
func (db *Default) Refresh(ctx context.Context) (err error) {
+ // TODO(a.garipov): Use slog.
+ log.Debug("profiledb_refresh: started")
+ defer log.Debug("profiledb_refresh: finished")
+
sinceLastAttempt, isFullSync := db.needsFullSync()
- var totalProfiles, totalDevices int
+ var profNum, devNum int
startTime := time.Now()
defer func() {
metrics.ProfilesSyncTime.SetToCurrentTime()
- metrics.ProfilesCountGauge.Set(float64(totalProfiles))
- metrics.DevicesCountGauge.Set(float64(totalDevices))
+ metrics.ProfilesNewCountGauge.Set(float64(profNum))
+ metrics.DevicesNewCountGauge.Set(float64(devNum))
metrics.SetStatusGauge(metrics.ProfilesSyncStatus, err)
dur := time.Since(startTime).Seconds()
@@ -230,6 +242,10 @@ func (db *Default) Refresh(ctx context.Context) (err error) {
if isFullSync {
metrics.ProfilesFullSyncDuration.Set(dur)
}
+
+ if err != nil {
+ errcoll.Collectf(ctx, db.errColl, "profiledb_refresh: %w", err)
+ }
}()
reqID := agd.NewRequestID()
@@ -240,6 +256,11 @@ func (db *Default) Refresh(ctx context.Context) (err error) {
db.refreshMu.Lock()
defer db.refreshMu.Unlock()
+ defer func() {
+ metrics.ProfilesCountGauge.Set(float64(len(db.profiles)))
+ metrics.DevicesCountGauge.Set(float64(len(db.devices)))
+ }()
+
resp, err := db.fetchProfiles(ctx, sinceLastAttempt, isFullSync)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
@@ -250,13 +271,10 @@ func (db *Default) Refresh(ctx context.Context) (err error) {
devices := resp.Devices
db.setProfiles(profiles, devices, isFullSync)
- profNum := len(profiles)
- devNum := len(devices)
+ profNum = len(profiles)
+ devNum = len(devices)
log.Debug("profiledb: req %s: got %d profiles with %d devices", reqID, profNum, devNum)
- metrics.ProfilesNewCountGauge.Set(float64(profNum))
- metrics.DevicesNewCountGauge.Set(float64(devNum))
-
db.syncTime = resp.SyncTime
if isFullSync {
db.lastFullSync = time.Now()
@@ -264,8 +282,8 @@ func (db *Default) Refresh(ctx context.Context) (err error) {
err = db.cache.Store(&internal.FileCache{
SyncTime: resp.SyncTime,
- Profiles: resp.Profiles,
- Devices: resp.Devices,
+ Profiles: profiles,
+ Devices: devices,
Version: internal.FileCacheVersion,
})
if err != nil {
@@ -273,9 +291,6 @@ func (db *Default) Refresh(ctx context.Context) (err error) {
}
}
- totalProfiles = len(db.profiles)
- totalDevices = len(db.devices)
-
return nil
}
diff --git a/internal/profiledb/profiledb_test.go b/internal/profiledb/profiledb_test.go
index 5a3162c..615ddb5 100644
--- a/internal/profiledb/profiledb_test.go
+++ b/internal/profiledb/profiledb_test.go
@@ -92,9 +92,7 @@ func TestDefaultProfileDB(t *testing.T) {
db := newDefaultProfileDB(t, devicesCh)
t.Run("by_device_id", func(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
- defer cancel()
-
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
p, d, err := db.ProfileByDeviceID(ctx, profiledbtest.DeviceID)
require.NoError(t, err)
@@ -103,9 +101,7 @@ func TestDefaultProfileDB(t *testing.T) {
})
t.Run("by_dedicated_ip", func(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
- defer cancel()
-
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
p, d, err := db.ProfileByDedicatedIP(ctx, testDedicatedIPv4)
require.NoError(t, err)
@@ -114,9 +110,7 @@ func TestDefaultProfileDB(t *testing.T) {
})
t.Run("by_linked_ip", func(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
- defer cancel()
-
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
p, d, err := db.ProfileByLinkedIP(ctx, testClientIPv4)
require.NoError(t, err)
@@ -140,7 +134,7 @@ func TestDefaultProfileDB_ProfileByDedicatedIP_removedDevice(t *testing.T) {
db := newDefaultProfileDB(t, devicesCh)
- ctx := context.Background()
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
_, d, err := db.ProfileByDedicatedIP(ctx, testDedicatedIPv4)
require.NoError(t, err)
@@ -149,10 +143,12 @@ func TestDefaultProfileDB_ProfileByDedicatedIP_removedDevice(t *testing.T) {
// The second response, the device is removed.
devicesCh <- nil
+ ctx = testutil.ContextWithTimeout(t, testTimeout)
err = db.Refresh(ctx)
require.NoError(t, err)
assert.Eventually(t, func() (ok bool) {
+ ctx = testutil.ContextWithTimeout(t, testTimeout)
_, d, err = db.ProfileByDedicatedIP(ctx, testDedicatedIPv4)
return errors.Is(err, profiledb.ErrDeviceNotFound)
@@ -378,7 +374,7 @@ func BenchmarkDefaultProfileDB_ProfileByDeviceID(b *testing.B) {
b.Run("success", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
profSink, devSink, errSink = db.ProfileByDeviceID(ctx, profiledbtest.DeviceID)
}
@@ -392,7 +388,7 @@ func BenchmarkDefaultProfileDB_ProfileByDeviceID(b *testing.B) {
b.Run("not_found", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
profSink, devSink, errSink = db.ProfileByDeviceID(ctx, wrongDevID)
}
@@ -427,7 +423,7 @@ func BenchmarkDefaultProfileDB_ProfileByLinkedIP(b *testing.B) {
b.Run("success", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
profSink, devSink, errSink = db.ProfileByLinkedIP(ctx, testClientIPv4)
}
@@ -439,7 +435,7 @@ func BenchmarkDefaultProfileDB_ProfileByLinkedIP(b *testing.B) {
b.Run("not_found", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
profSink, devSink, errSink = db.ProfileByLinkedIP(ctx, testOtherClientIPv4)
}
@@ -476,7 +472,7 @@ func BenchmarkDefaultProfileDB_ProfileByDedicatedIP(b *testing.B) {
b.Run("success", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
profSink, devSink, errSink = db.ProfileByDedicatedIP(ctx, testClientIPv4)
}
@@ -488,7 +484,7 @@ func BenchmarkDefaultProfileDB_ProfileByDedicatedIP(b *testing.B) {
b.Run("not_found", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
profSink, devSink, errSink = db.ProfileByDedicatedIP(ctx, testOtherClientIPv4)
}
diff --git a/internal/querylog/entry.go b/internal/querylog/entry.go
index 2b1be77..a3c4fdd 100644
--- a/internal/querylog/entry.go
+++ b/internal/querylog/entry.go
@@ -42,6 +42,8 @@ type Entry struct {
DomainFQDN string
// RequestID is the ID of the request.
+ //
+ // TODO(a.garipov): Remove once not necessary anymore.
RequestID agd.RequestID
// ClientASN is the detected autonomous system number of the client's IP
@@ -120,7 +122,7 @@ func toResultCode(r filter.Result, resp bool) (c resultCode) {
}
return resultCodeReqBlocked
- case *filter.ResultModified:
+ case *filter.ResultModifiedResponse, *filter.ResultModifiedRequest:
return resultCodeModified
default:
// Consider unhandled sum type members as unrecoverable programmer
@@ -208,6 +210,11 @@ type jsonlEntry struct {
// The short name "q" stands for "question".
RequestType dnsmsg.RRType `json:"q"`
+ // Random is a random number added to an entry for easier deduplication.
+ //
+ // The short name "rn" stands for "random number".
+ Random uint16 `json:"rn"`
+
// ResultCode is the action taken with this request.
//
// The short name "f" stands for "filtering".
diff --git a/internal/querylog/fs.go b/internal/querylog/fs.go
index 03dd0a4..276fc98 100644
--- a/internal/querylog/fs.go
+++ b/internal/querylog/fs.go
@@ -15,30 +15,38 @@ import (
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/mathutil"
"github.com/AdguardTeam/golibs/syncutil"
+ "golang.org/x/exp/rand"
)
// FileSystemConfig is the configuration of the file system query log.
type FileSystemConfig struct {
// Path is the path to the log file.
Path string
+
+ // RandSeed is used to set the "rn" property in JSON objects.
+ RandSeed uint64
}
// NewFileSystem creates a new file system query log. The log is safe for
-// concurrent use.
+// concurrent use. c must not be nil.
func NewFileSystem(c *FileSystemConfig) (l *FileSystem) {
+ rng := rand.New(&rand.LockedSource{})
+ rng.Seed(c.RandSeed)
+
return &FileSystem{
- path: c.Path,
bufferPool: syncutil.NewPool(func() (v *entryBuffer) {
return &entryBuffer{
ent: &jsonlEntry{},
buf: &bytes.Buffer{},
}
}),
+ rng: rng,
+ path: c.Path,
}
}
// entryBuffer is a struct with two fields for caching entry that is being
-// written. Using this struct allows us to remove allocations on every write.
+// written. Using this struct allows us to remove allocations on every write.
type entryBuffer struct {
ent *jsonlEntry
buf *bytes.Buffer
@@ -50,6 +58,10 @@ type FileSystem struct {
// allocations when serializing query log items to JSON and writing them.
bufferPool *syncutil.Pool[entryBuffer]
+ // rng is used to generate random numbers for the "rn" property in the
+ // resulting JSON.
+ rng *rand.Rand
+
// path is the path to the query log file.
path string
}
@@ -93,6 +105,7 @@ func (l *FileSystem) Write(_ context.Context, e *Entry) (err error) {
ClientASN: e.ClientASN,
Elapsed: e.Elapsed,
RequestType: e.RequestType,
+ Random: uint16(l.rng.Uint32()),
DNSSEC: mathutil.BoolToNumber[uint8](e.DNSSEC),
Protocol: e.Protocol,
ResultCode: c,
diff --git a/internal/querylog/fs_test.go b/internal/querylog/fs_test.go
index 6528cce..c06547b 100644
--- a/internal/querylog/fs_test.go
+++ b/internal/querylog/fs_test.go
@@ -19,7 +19,8 @@ func TestFileSystem_Write(t *testing.T) {
require.NoError(t, err)
l := querylog.NewFileSystem(&querylog.FileSystemConfig{
- Path: f.Name(),
+ Path: f.Name(),
+ RandSeed: 0,
})
ctx := context.Background()
@@ -53,6 +54,7 @@ func TestFileSystem_Write(t *testing.T) {
"a":1234,
"e":5,
"q":1,
+ "rn":35121,
"f":2,
"s":1,
"p":8,
@@ -89,6 +91,7 @@ func TestFileSystem_Write(t *testing.T) {
"a":1234,
"e":5,
"q":1,
+ "rn":47387,
"f":1,
"s":1,
"p":8,
@@ -106,7 +109,8 @@ func BenchmarkFileSystem_Write_file(b *testing.B) {
require.NoError(b, err)
l := querylog.NewFileSystem(&querylog.FileSystemConfig{
- Path: f.Name(),
+ Path: f.Name(),
+ RandSeed: 0,
})
e := testEntry()
@@ -114,7 +118,7 @@ func BenchmarkFileSystem_Write_file(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
- for i := 0; i < b.N; i++ {
+ for range b.N {
errSink = l.Write(ctx, e)
}
@@ -126,5 +130,5 @@ func BenchmarkFileSystem_Write_file(b *testing.B) {
// goarch: amd64
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/querylog
// cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
- // BenchmarkFileSystem_Write_file-16 244162 5000 ns/op 200 B/op 3 allocs/op
+ // BenchmarkFileSystem_Write_file-16 152948 7662 ns/op 248 B/op 5 allocs/op
}
diff --git a/internal/rulestat/http.go b/internal/rulestat/http.go
index 2a333a1..264cc7e 100644
--- a/internal/rulestat/http.go
+++ b/internal/rulestat/http.go
@@ -13,33 +13,28 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
)
-// HTTP Uploader Rulestat
-
-// StatFilterListID is the ID of the filtering rule list for which we collect
-// statistics. This is a temporary restriction.
-//
-// TODO(ameshkov): Consider making configurable
-const StatFilterListID agd.FilterListID = "adguard_dns_filter"
-
-// StatFilterListLegacyID is the ID of the filtering rule list for which we
+// statFilterListLegacyID is the ID of the filtering rule list for which we
// collect statistics, as understood and accepted by the current backend. This
// is a temporary restriction.
//
// TODO(ameshkov): Consider making the backend accept the current IDs.
-const StatFilterListLegacyID agd.FilterListID = "15"
+const statFilterListLegacyID agd.FilterListID = "15"
// HTTP is the filtering rule statistics collector that uploads the statistics
// to the given URL when it's refreshed.
//
// TODO(a.garipov): Add tests.
type HTTP struct {
- url *url.URL
- http *agdhttp.Client
+ url *url.URL
+ http *agdhttp.Client
+ errColl errcoll.Interface
// mu protects stats and recordedHits.
mu *sync.Mutex
@@ -53,6 +48,9 @@ type statsSet = map[agd.FilterListID]map[agd.FilterRuleText]uint64
// HTTPConfig is the configuration structure for the filtering rule statistics
// collector that uploads the statistics to a URL. All fields are required.
type HTTPConfig struct {
+ // ErrColl is used to collect errors during refreshes.
+ ErrColl errcoll.Interface
+
// URL is the URL to which the statistics is uploaded.
URL *url.URL
}
@@ -60,13 +58,15 @@ type HTTPConfig struct {
// NewHTTP returns a new statistics collector with HTTP upload.
func NewHTTP(c *HTTPConfig) (s *HTTP) {
return &HTTP{
- mu: &sync.Mutex{},
- stats: statsSet{},
- url: netutil.CloneURL(c.URL),
+ url: netutil.CloneURL(c.URL),
http: agdhttp.NewClient(&agdhttp.ClientConfig{
// TODO(ameshkov): Consider making configurable.
Timeout: 30 * time.Second,
}),
+ errColl: c.ErrColl,
+
+ mu: &sync.Mutex{},
+ stats: statsSet{},
}
}
@@ -75,11 +75,11 @@ var _ Interface = (*HTTP)(nil)
// Collect implements the Interface interface for *HTTP.
func (s *HTTP) Collect(_ context.Context, id agd.FilterListID, text agd.FilterRuleText) {
- if id != StatFilterListID {
+ if id != agd.FilterListIDAdGuardDNS {
return
}
- id = StatFilterListLegacyID
+ id = statFilterListLegacyID
s.mu.Lock()
defer s.mu.Unlock()
@@ -106,15 +106,22 @@ var _ agdservice.Refresher = (*HTTP)(nil)
// uploads the collected statistics to s.u and starts collecting a new set of
// statistics.
func (s *HTTP) Refresh(ctx context.Context) (err error) {
- err = s.refresh(ctx)
+ // TODO(a.garipov): Use slog.
+ log.Info("rulestat_refresh: started")
+ defer log.Info("rulestat_refresh: finished")
- if err == nil {
- metrics.RuleStatUploadTimestamp.SetToCurrentTime()
+ err = s.refresh(ctx)
+ if err != nil {
+ errcoll.Collectf(ctx, s.errColl, "rulestat_refresh: %w", err)
+ metrics.SetStatusGauge(metrics.RuleStatUploadStatus, err)
+
+ return err
}
- metrics.SetStatusGauge(metrics.RuleStatUploadStatus, err)
+ metrics.RuleStatUploadTimestamp.SetToCurrentTime()
+ metrics.SetStatusGauge(metrics.RuleStatUploadStatus, nil)
- return err
+ return nil
}
// refresh uploads the collected statistics and resets the collected stats.
@@ -135,13 +142,8 @@ func (s *HTTP) refresh(ctx context.Context) (err error) {
}
defer func() { err = errors.WithDeferred(err, httpResp.Body.Close()) }()
- err = agdhttp.CheckStatus(httpResp, http.StatusOK)
- if err != nil {
- // Don't wrap the error, because it's informative enough as is.
- return err
- }
-
- return nil
+ // Don't wrap the error, because it's informative enough as is.
+ return agdhttp.CheckStatus(httpResp, http.StatusOK)
}
// replaceStats replaced the current stats of s with a new set and returns the
diff --git a/internal/rulestat/http_test.go b/internal/rulestat/http_test.go
index 908074e..2a14eff 100644
--- a/internal/rulestat/http_test.go
+++ b/internal/rulestat/http_test.go
@@ -11,6 +11,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
@@ -64,13 +65,13 @@ func TestHTTP_Collect(t *testing.T) {
h := rulestat.NewHTTP(conf)
t.Run(tc.name, func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
for _, rule := range tc.rules {
- h.Collect(context.Background(), rulestat.StatFilterListID, rule)
+ h.Collect(ctx, agd.FilterListIDAdGuardDNS, rule)
}
// Use the context different from the above one.
- ctx := context.Background()
- err := h.Refresh(ctx)
+ err := h.Refresh(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
assert.JSONEq(t, tc.want, b.String())
@@ -83,12 +84,19 @@ func TestHTTP_Refresh_errors(t *testing.T) {
const wantErrMsg = `uploading filter stats: Post "badscheme://0.0.0.0": ` +
`unsupported protocol scheme "badscheme"`
- h := rulestat.NewHTTP(&rulestat.HTTPConfig{URL: &url.URL{
- Scheme: "badscheme",
- Host: "0.0.0.0",
- }})
+ h := rulestat.NewHTTP(&rulestat.HTTPConfig{
+ ErrColl: &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) {
+ testutil.AssertErrorMsg(t, "rulestat_refresh: "+wantErrMsg, err)
+ },
+ },
+ URL: &url.URL{
+ Scheme: "badscheme",
+ Host: "0.0.0.0",
+ },
+ })
- err := h.Refresh(context.Background())
+ err := h.Refresh(testutil.ContextWithTimeout(t, testTimeout))
testutil.AssertErrorMsg(t, wantErrMsg, err)
})
@@ -96,10 +104,17 @@ func TestHTTP_Refresh_errors(t *testing.T) {
u := handleWithURL(t, http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
rw.WriteHeader(http.StatusInternalServerError)
}))
- h := rulestat.NewHTTP(&rulestat.HTTPConfig{URL: u})
+ h := rulestat.NewHTTP(&rulestat.HTTPConfig{
+ ErrColl: &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) {
+ require.NotNil(t, err)
+ },
+ },
+ URL: u,
+ })
var serr *agdhttp.StatusError
- err := h.Refresh(context.Background())
+ err := h.Refresh(testutil.ContextWithTimeout(t, testTimeout))
require.ErrorAs(t, err, &serr)
assert.Equal(t, http.StatusInternalServerError, serr.Got)
diff --git a/internal/rulestat/rulestat.go b/internal/rulestat/rulestat.go
index 507b2da..62b0e4b 100644
--- a/internal/rulestat/rulestat.go
+++ b/internal/rulestat/rulestat.go
@@ -7,8 +7,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
)
-// Common Types
-
// Interface is an ephemeral storage of the filtering rule list statistics
// interface.
//
diff --git a/internal/rulestat/rulestat_test.go b/internal/rulestat/rulestat_test.go
index 490814f..141a9a4 100644
--- a/internal/rulestat/rulestat_test.go
+++ b/internal/rulestat/rulestat_test.go
@@ -2,6 +2,7 @@ package rulestat_test
import (
"testing"
+ "time"
"github.com/AdguardTeam/golibs/testutil"
)
@@ -9,3 +10,6 @@ import (
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
+
+// testTimeout is the common timeout for tests.
+const testTimeout = 1 * time.Second
diff --git a/internal/tools/go.mod b/internal/tools/go.mod
index 8bbc4b1..96ff30a 100644
--- a/internal/tools/go.mod
+++ b/internal/tools/go.mod
@@ -1,22 +1,22 @@
module github.com/AdguardTeam/AdGuardDNS/internal/tools
-go 1.21.8
+go 1.22.4
require (
github.com/fzipp/gocyclo v0.6.0
- github.com/golangci/misspell v0.4.1
+ github.com/golangci/misspell v0.5.1
github.com/gordonklaus/ineffassign v0.1.0
github.com/kisielk/errcheck v1.7.0
github.com/kyoh86/looppointer v0.2.1
github.com/securego/gosec/v2 v2.19.0
github.com/uudashr/gocognit v1.1.2
- golang.org/x/tools v0.18.0
- golang.org/x/vuln v1.0.4
+ golang.org/x/tools v0.21.0
+ golang.org/x/vuln v1.1.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
- google.golang.org/protobuf v1.32.0
+ google.golang.org/protobuf v1.34.1
honnef.co/go/tools v0.4.7
mvdan.cc/gofumpt v0.6.0
- mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14
+ mvdan.cc/unparam v0.0.0-20240427195214-063aff900ca1
)
require (
@@ -28,9 +28,9 @@ require (
github.com/kyoh86/nolint v0.0.1 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 // indirect
- golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225 // indirect
- golang.org/x/mod v0.15.0 // indirect
- golang.org/x/sync v0.6.0 // indirect
- golang.org/x/sys v0.17.0 // indirect
+ golang.org/x/exp/typeparams v0.0.0-20240506185415-9bf2ced13842 // indirect
+ golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/sync v0.7.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/internal/tools/go.sum b/internal/tools/go.sum
index 907222a..b0470d2 100644
--- a/internal/tools/go.sum
+++ b/internal/tools/go.sum
@@ -12,8 +12,8 @@ github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
-github.com/golangci/misspell v0.4.1 h1:+y73iSicVy2PqyX7kmUefHusENlrP9YwuHZHPLGQj/g=
-github.com/golangci/misspell v0.4.1/go.mod h1:9mAN1quEo3DlpbaIKKyEvRxK1pwqR9s/Sea1bJCtlNI=
+github.com/golangci/misspell v0.5.1 h1:/SjR1clj5uDjNLwYzCahHwIOPmQgoH04AyQIiWGbhCM=
+github.com/golangci/misspell v0.5.1/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -63,26 +63,26 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
-golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225 h1:BzKNaIRXh1bD+1557OcFIHlpYBiVbK4zEyn8zBHi1SE=
-golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+golang.org/x/exp/typeparams v0.0.0-20240506185415-9bf2ced13842 h1:S62OJe0/hUkTgveY1HXZMHWBOy21DVrobMYz2cMCO64=
+golang.org/x/exp/typeparams v0.0.0-20240506185415-9bf2ced13842/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
-golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
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-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
-golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
-golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -93,8 +93,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
-golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
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=
@@ -107,17 +107,17 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
-golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
-golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
-golang.org/x/vuln v1.0.4 h1:SP0mPeg2PmGCu03V+61EcQiOjmpri2XijexKdzv8Z1I=
-golang.org/x/vuln v1.0.4/go.mod h1:NbJdUQhX8jY++FtuhrXs2Eyx0yePo9pF7nPlIjo9aaQ=
+golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
+golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/vuln v1.1.0 h1:ECEdI+aEtjpF90eqEcDL5Q11DWSZAw5PJQWlp0+gWqc=
+golang.org/x/vuln v1.1.0/go.mod h1:HT/Ar8fE34tbxWG2s7PYjVl+iIE4Er36/940Z+K540Y=
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/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y=
-google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
-google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
@@ -126,5 +126,5 @@ honnef.co/go/tools v0.4.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs=
honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0=
mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo=
mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA=
-mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14 h1:zCr3iRRgdk5eIikZNDphGcM6KGVTx3Yu+/Uu9Es254w=
-mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14/go.mod h1:ZzZjEpJDOmx8TdVU6umamY3Xy0UAQUI2DHbf05USVbI=
+mvdan.cc/unparam v0.0.0-20240427195214-063aff900ca1 h1:Nykk7fggxChwLK4rUPYESzeIwqsuxXXlFEAh5YhaMRo=
+mvdan.cc/unparam v0.0.0-20240427195214-063aff900ca1/go.mod h1:ZzZjEpJDOmx8TdVU6umamY3Xy0UAQUI2DHbf05USVbI=
diff --git a/internal/websvc/blockpage.go b/internal/websvc/blockpage.go
new file mode 100644
index 0000000..6853bc4
--- /dev/null
+++ b/internal/websvc/blockpage.go
@@ -0,0 +1,161 @@
+package websvc
+
+import (
+ "bytes"
+ "compress/gzip"
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
+ "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/log"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+// blockPageName is a type alias for strings that contain a block-page name for
+// logging and metrics.
+type blockPageName = string
+
+// blockPageName values.
+const (
+ adultBlockingName blockPageName = "adult blocking"
+ generalBlockingName blockPageName = "general blocking"
+ safeBrowsingName blockPageName = "safe browsing"
+)
+
+// blockPageServers is a helper function that converts a *BlockPageServer into
+// HTTP servers.
+func blockPageServers(
+ srv *BlockPageServer,
+ name string,
+ timeout time.Duration,
+) (srvs []*http.Server) {
+ if srv == nil {
+ return nil
+ }
+
+ h := blockPageHandler(name, srv.Content)
+ for _, b := range srv.Bind {
+ addr := b.Address.String()
+ errLog := log.StdLog(fmt.Sprintf("websvc: %s: %s", name, addr), log.DEBUG)
+ srvs = append(srvs, &http.Server{
+ Addr: addr,
+ Handler: h,
+ TLSConfig: b.TLS,
+ ErrorLog: errLog,
+ ReadTimeout: timeout,
+ WriteTimeout: timeout,
+ IdleTimeout: timeout,
+ ReadHeaderTimeout: timeout,
+ })
+ }
+
+ return srvs
+}
+
+// blockPageHandler returns an HTTP handler serving the block page content.
+// name is used for logging and metrics and must be one of blockPageName values.
+func blockPageHandler(name blockPageName, blockPage []byte) (h http.Handler) {
+ gzipped := mustGzip(name, blockPage)
+
+ f := func(w http.ResponseWriter, r *http.Request) {
+ // Set the Server header here, so that all responses carry it.
+ respHdr := w.Header()
+ respHdr.Set(httphdr.Server, agdhttp.UserAgent())
+
+ switch r.URL.Path {
+ case "/favicon.ico":
+ // Don't serve the HTML page to the favicon requests.
+ http.NotFound(w, r)
+ case "/robots.txt":
+ // Don't serve the HTML page to the robots.txt requests. Serve
+ // the predefined response instead.
+ serveRobotsDisallow(respHdr, w, name)
+ default:
+ serveBlockPage(w, r, name, blockPage, gzipped)
+ }
+ }
+
+ return http.HandlerFunc(f)
+}
+
+// mustGzip uses gzip to compress b. It panics with an informative error value
+// if there are any errors.
+func mustGzip(name string, b []byte) (compressed []byte) {
+ buf := &bytes.Buffer{}
+ zw, err := gzip.NewWriterLevel(buf, gzip.BestCompression)
+ if err != nil {
+ // Should never happen.
+ panic(fmt.Errorf("websvc: gzipping %q: %w", name, err))
+ }
+
+ _, err = zw.Write(b)
+ if err != nil {
+ // Should never happen.
+ panic(fmt.Errorf("websvc: writing gzipped %q: %w", name, err))
+ }
+
+ err = zw.Close()
+ if err != nil {
+ // Should never happen.
+ panic(fmt.Errorf("websvc: flushing gzipped %q: %w", name, err))
+ }
+
+ return buf.Bytes()
+}
+
+// serveBlockPage serves the block-page content taking compression headers into
+// account.
+func serveBlockPage(
+ w http.ResponseWriter,
+ r *http.Request,
+ name string,
+ blockPage []byte,
+ gzipped []byte,
+) {
+ respHdr := w.Header()
+ respHdr.Set(httphdr.ContentType, agdhttp.HdrValTextHTML)
+
+ content := blockPage
+
+ // TODO(a.garipov): Parse the quality value.
+ //
+ // TODO(a.garipov): Support other compression algorithms.
+ reqHdr := r.Header
+ if strings.Contains(reqHdr.Get(httphdr.AcceptEncoding), agdhttp.HdrValGzip) {
+ respHdr.Set(httphdr.ContentEncoding, agdhttp.HdrValGzip)
+ content = gzipped
+ }
+
+ // Use HTTP 500 status code to signal that this is a block page.
+ // See AGDNS-1952.
+ w.WriteHeader(http.StatusInternalServerError)
+
+ _, err := w.Write(content)
+ if err != nil {
+ logErrorByType(err, "websvc: %s: writing response: %s", name, err)
+ }
+
+ incBlockPageMetrics(name)
+}
+
+// incBlockPageMetrics increments the metrics for the block-page view
+// counts depending on the name of the block page.
+func incBlockPageMetrics(name blockPageName) {
+ var totalCtr prometheus.Counter
+ switch name {
+ case adultBlockingName:
+ totalCtr = metrics.WebSvcAdultBlockingPageRequestsTotal
+ case generalBlockingName:
+ totalCtr = metrics.WebSvcGeneralBlockingPageRequestsTotal
+ case safeBrowsingName:
+ totalCtr = metrics.WebSvcSafeBrowsingPageRequestsTotal
+ default:
+ panic(fmt.Errorf("metrics: bad websvc block-page metric name %q", name))
+ }
+
+ totalCtr.Inc()
+}
diff --git a/internal/websvc/blockpage_test.go b/internal/websvc/blockpage_test.go
new file mode 100644
index 0000000..6159dbf
--- /dev/null
+++ b/internal/websvc/blockpage_test.go
@@ -0,0 +1,146 @@
+package websvc_test
+
+import (
+ "compress/gzip"
+ "io"
+ "net/http"
+ "net/netip"
+ "net/url"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
+ "github.com/AdguardTeam/AdGuardDNS/internal/websvc"
+ "github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestBlockPageServers(t *testing.T) {
+ content := []byte("blocking page content\n")
+ notFoundContent := []byte("404 page not found\n")
+ robotsContent := []byte(agdhttp.RobotsDisallowAll)
+
+ const (
+ contentStatus = http.StatusInternalServerError
+ faviconStatus = http.StatusNotFound
+ robotsStatus = http.StatusOK
+ )
+
+ // TODO(a.garipov): Do not use hardcoded ports.
+ testCases := []struct {
+ updateConfig func(c *websvc.Config, bps *websvc.BlockPageServer)
+ addr netip.AddrPort
+ name string
+ }{{
+ updateConfig: func(c *websvc.Config, bps *websvc.BlockPageServer) {
+ c.AdultBlocking = bps
+ },
+ addr: netip.MustParseAddrPort("127.0.0.1:3000"),
+ name: "adult_blocking",
+ }, {
+ updateConfig: func(c *websvc.Config, bps *websvc.BlockPageServer) {
+ c.GeneralBlocking = bps
+ },
+ addr: netip.MustParseAddrPort("127.0.0.1:3001"),
+ name: "general_blocking",
+ }, {
+ updateConfig: func(c *websvc.Config, bps *websvc.BlockPageServer) {
+ c.SafeBrowsing = bps
+ },
+ addr: netip.MustParseAddrPort("127.0.0.1:3002"),
+ name: "safe_browsing",
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ bps := &websvc.BlockPageServer{
+ Content: content,
+ Bind: []*websvc.BindData{{
+ TLS: nil,
+ Address: tc.addr,
+ }},
+ }
+
+ conf := &websvc.Config{
+ Timeout: testTimeout,
+ }
+ tc.updateConfig(conf, bps)
+
+ startService(t, conf)
+
+ assertContent(t, tc.addr, "/", contentStatus, content)
+ assertContent(t, tc.addr, "/favicon.ico", faviconStatus, notFoundContent)
+ assertContent(t, tc.addr, "/robots.txt", robotsStatus, robotsContent)
+ })
+ }
+}
+
+func TestBlockPageServers_noBlockPages(t *testing.T) {
+ conf := &websvc.Config{
+ Timeout: testTimeout,
+ }
+
+ svc := websvc.New(conf)
+ require.NotNil(t, svc)
+
+ require.NotPanics(t, func() {
+ assert.NoError(t, svc.Start(testutil.ContextWithTimeout(t, testTimeout)))
+ assert.NoError(t, svc.Shutdown(testutil.ContextWithTimeout(t, testTimeout)))
+ })
+}
+
+func TestBlockPageServers_gzip(t *testing.T) {
+ addr := netip.MustParseAddrPort("127.0.0.1:3001")
+ content := []byte("generalBlockingContent")
+ bps := &websvc.BlockPageServer{
+ Content: content,
+ Bind: []*websvc.BindData{{
+ TLS: nil,
+ Address: addr,
+ }},
+ }
+
+ conf := &websvc.Config{
+ GeneralBlocking: bps,
+ }
+
+ startService(t, conf)
+
+ c := http.Client{
+ Timeout: testTimeout,
+ }
+
+ u := &url.URL{
+ Scheme: "http",
+ Host: addr.String(),
+ Path: "/",
+ }
+ req, err := http.NewRequest(http.MethodGet, u.String(), nil)
+ require.NoError(t, err)
+
+ req.Header.Set(httphdr.AcceptEncoding, agdhttp.HdrValGzip)
+
+ // First check health-check service URL. As the service could not be ready
+ // yet, check for it periodically.
+ var resp *http.Response
+ require.Eventually(t, func() (ok bool) {
+ resp, err = c.Do(req)
+
+ return err == nil
+ }, testTimeout, testTimeout/10)
+
+ zr, err := gzip.NewReader(resp.Body)
+ require.NoError(t, err)
+ testutil.CleanupAndRequireSuccess(t, zr.Close)
+
+ body, err := io.ReadAll(zr)
+ require.NoError(t, err)
+
+ assert.Equal(t, content, body)
+ assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
+ assert.Equal(t, agdhttp.UserAgent(), resp.Header.Get(httphdr.Server))
+ assert.Equal(t, agdhttp.HdrValGzip, resp.Header.Get(httphdr.ContentEncoding))
+}
diff --git a/internal/websvc/handler.go b/internal/websvc/handler.go
index c84273d..ac5b719 100644
--- a/internal/websvc/handler.go
+++ b/internal/websvc/handler.go
@@ -110,81 +110,6 @@ func (svc *Service) serveHTTP(w http.ResponseWriter, r *http.Request) {
}
}
-// safeBrowsingHandler returns an HTTP handler serving the block page from the
-// blockPagePath. name is used for logging and metrics.
-func safeBrowsingHandler(name string, blockPage []byte) (h http.Handler) {
- f := func(w http.ResponseWriter, r *http.Request) {
- hdr := w.Header()
- hdr.Set(httphdr.Server, agdhttp.UserAgent())
-
- switch r.URL.Path {
- case "/favicon.ico":
- // Don't serve the HTML page to the favicon requests.
- http.NotFound(w, r)
- case "/robots.txt":
- // Don't serve the HTML page to the robots.txt requests. Serve
- // the predefined response instead.
- serveRobotsDisallow(hdr, w, name)
- default:
- hdr.Set(httphdr.ContentType, agdhttp.HdrValTextHTML)
-
- _, err := w.Write(blockPage)
- if err != nil {
- logErrorByType(err, "websvc: %s: writing response: %s", name, err)
- }
-
- switch name {
- case adultBlockingName:
- metrics.WebSvcAdultBlockingPageRequestsTotal.Inc()
- case safeBrowsingName:
- metrics.WebSvcSafeBrowsingPageRequestsTotal.Inc()
- default:
- // Go on.
- }
- }
- }
-
- return http.HandlerFunc(f)
-}
-
-// StaticContent serves static content with the given content type.
-type StaticContent map[string]*StaticFile
-
-// serveHTTP serves the static content, if any. If the mapping doesn't include
-// the path from the request, served is false.
-func (sc StaticContent) serveHTTP(w http.ResponseWriter, r *http.Request) (served bool) {
- p := r.URL.Path
- f, ok := sc[p]
- if !ok {
- return false
- }
-
- h := w.Header()
- for k, v := range f.Headers {
- h[k] = v
- }
-
- w.WriteHeader(http.StatusOK)
-
- _, err := w.Write(f.Content)
- if err != nil {
- logErrorByType(err, "websvc: static content: writing %s: %s", p, err)
- }
-
- metrics.WebSvcStaticContentRequestsTotal.Inc()
-
- return true
-}
-
-// StaticFile is a single file in a StaticFS.
-type StaticFile struct {
- // Headers contains headers of the HTTP response.
- Headers http.Header
-
- // Content is the file content.
- Content []byte
-}
-
// serveRobotsDisallow writes predefined disallow-all response.
func serveRobotsDisallow(hdr http.Header, w http.ResponseWriter, name string) {
hdr.Set(httphdr.ContentType, agdhttp.HdrValTextPlain)
diff --git a/internal/websvc/handler_test.go b/internal/websvc/handler_test.go
index c5f9ed7..f501979 100644
--- a/internal/websvc/handler_test.go
+++ b/internal/websvc/handler_test.go
@@ -1,6 +1,7 @@
package websvc_test
import (
+ "io"
"net/http"
"net/http/httptest"
"net/url"
@@ -8,7 +9,6 @@ import (
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/websvc"
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/testutil"
@@ -20,7 +20,7 @@ func TestService_ServeHTTP(t *testing.T) {
mockHandler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
pt := testutil.PanicT{}
- _, err := w.Write([]byte("[]"))
+ _, err := io.WriteString(w, "[]")
require.NoError(pt, err)
})
@@ -30,18 +30,8 @@ func TestService_ServeHTTP(t *testing.T) {
Path: "/",
}
- staticContent := map[string]*websvc.StaticFile{
- "/favicon.ico": {
- Content: []byte{},
- Headers: http.Header{
- httphdr.ContentType: []string{"image/x-icon"},
- },
- },
- }
-
c := &websvc.Config{
RootRedirectURL: rootRedirectURL,
- StaticContent: staticContent,
DNSCheck: mockHandler,
}
@@ -50,24 +40,17 @@ func TestService_ServeHTTP(t *testing.T) {
var err error
require.NotPanics(t, func() {
- err = svc.Start(agdtest.ContextWithTimeout(t, testTimeout))
+ err = svc.Start(testutil.ContextWithTimeout(t, testTimeout))
})
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return svc.Shutdown(agdtest.ContextWithTimeout(t, testTimeout))
+ return svc.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
})
// DNSCheck path.
assertResponse(t, svc, "/dnscheck/test", http.StatusOK)
- // Static content path with headers.
- h := http.Header{
- httphdr.ContentType: []string{"image/x-icon"},
- httphdr.Server: []string{"AdGuardDNS/"},
- }
- assertResponseWithHeaders(t, svc, "/favicon.ico", http.StatusOK, h)
-
// Robots path.
assertResponse(t, svc, "/robots.txt", http.StatusOK)
@@ -93,6 +76,7 @@ func assertResponse(
Host: "127.0.0.1",
Path: path,
}).String(), strings.NewReader(""))
+
rw = httptest.NewRecorder()
svc.ServeHTTP(rw, r)
@@ -109,11 +93,11 @@ func assertResponseWithHeaders(
svc *websvc.Service,
path string,
statusCode int,
- header http.Header,
+ respHdr http.Header,
) {
t.Helper()
rw := assertResponse(t, svc, path, statusCode)
- assert.Equal(t, header, rw.Header())
+ assert.Equal(t, respHdr, rw.Header())
}
diff --git a/internal/websvc/static.go b/internal/websvc/static.go
new file mode 100644
index 0000000..6eccb49
--- /dev/null
+++ b/internal/websvc/static.go
@@ -0,0 +1,45 @@
+package websvc
+
+import (
+ "maps"
+ "net/http"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+)
+
+// StaticContent serves static content with the given content type. Elements
+// must not be nil.
+type StaticContent map[string]*StaticFile
+
+// StaticFile is a single file in a [StaticFS].
+type StaticFile struct {
+ // Headers contains headers of the HTTP response.
+ Headers http.Header
+
+ // Content is the file content.
+ Content []byte
+}
+
+// serveHTTP serves the static content, if any. If the mapping doesn't include
+// the path from the request, served is false.
+func (sc StaticContent) serveHTTP(w http.ResponseWriter, r *http.Request) (served bool) {
+ p := r.URL.Path
+ f, ok := sc[p]
+ if !ok {
+ return false
+ }
+
+ respHdr := w.Header()
+ maps.Copy(respHdr, f.Headers)
+
+ w.WriteHeader(http.StatusOK)
+
+ _, err := w.Write(f.Content)
+ if err != nil {
+ logErrorByType(err, "websvc: static content: writing %s: %s", p, err)
+ }
+
+ metrics.WebSvcStaticContentRequestsTotal.Inc()
+
+ return true
+}
diff --git a/internal/websvc/static_test.go b/internal/websvc/static_test.go
new file mode 100644
index 0000000..812c67b
--- /dev/null
+++ b/internal/websvc/static_test.go
@@ -0,0 +1,45 @@
+package websvc_test
+
+import (
+ "net/http"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/websvc"
+ "github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/stretchr/testify/require"
+)
+
+func TestService_ServeHTTP_static(t *testing.T) {
+ staticContent := map[string]*websvc.StaticFile{
+ "/favicon.ico": {
+ Content: []byte{},
+ Headers: http.Header{
+ httphdr.ContentType: []string{"image/x-icon"},
+ },
+ },
+ }
+
+ c := &websvc.Config{
+ StaticContent: staticContent,
+ }
+
+ svc := websvc.New(c)
+ require.NotNil(t, svc)
+
+ var err error
+ require.NotPanics(t, func() {
+ err = svc.Start(testutil.ContextWithTimeout(t, testTimeout))
+ })
+ require.NoError(t, err)
+
+ testutil.CleanupAndRequireSuccess(t, func() (err error) {
+ return svc.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
+ })
+
+ respHdr := http.Header{
+ httphdr.ContentType: []string{"image/x-icon"},
+ httphdr.Server: []string{"AdGuardDNS/"},
+ }
+ assertResponseWithHeaders(t, svc, "/favicon.ico", http.StatusOK, respHdr)
+}
diff --git a/internal/websvc/websvc.go b/internal/websvc/websvc.go
index 253aa27..b7510cc 100644
--- a/internal/websvc/websvc.go
+++ b/internal/websvc/websvc.go
@@ -18,12 +18,15 @@ import (
// Config is the AdGuard DNS web service configuration structure.
type Config struct {
- // SafeBrowsing is the optional safe browsing block page web server.
- SafeBrowsing *BlockPageServer
-
- // AdultBlocking is the optional adult blocking block page web server.
+ // AdultBlocking is the optional adult-blocking block-page web server.
AdultBlocking *BlockPageServer
+ // GeneralBlocking is the optional general block-page web server.
+ GeneralBlocking *BlockPageServer
+
+ // SafeBrowsing is the optional safe-browsing block-page web server.
+ SafeBrowsing *BlockPageServer
+
// LinkedIP is the optional linked IP web server.
LinkedIP *LinkedIPServer
@@ -97,10 +100,11 @@ type Service struct {
error404 []byte
error500 []byte
- linkedIP []*http.Server
- adultBlocking []*http.Server
- safeBrowsing []*http.Server
- nonDoH []*http.Server
+ linkedIP []*http.Server
+ adultBlocking []*http.Server
+ generalBlocking []*http.Server
+ safeBrowsing []*http.Server
+ nonDoH []*http.Server
}
// New returns a new properly initialized *Service. If c is nil, svc is a nil
@@ -118,8 +122,9 @@ func New(c *Config) (svc *Service) {
error404: c.Error404,
error500: c.Error500,
- adultBlocking: blockPageServers(c.AdultBlocking, adultBlockingName, c.Timeout),
- safeBrowsing: blockPageServers(c.SafeBrowsing, safeBrowsingName, c.Timeout),
+ adultBlocking: blockPageServers(c.AdultBlocking, adultBlockingName, c.Timeout),
+ generalBlocking: blockPageServers(c.GeneralBlocking, generalBlockingName, c.Timeout),
+ safeBrowsing: blockPageServers(c.SafeBrowsing, safeBrowsingName, c.Timeout),
}
if c.RootRedirectURL != nil {
@@ -164,42 +169,6 @@ func New(c *Config) (svc *Service) {
return svc
}
-// Names for safeBrowsingHandler for logging and metrics.
-const (
- safeBrowsingName = "safe browsing"
- adultBlockingName = "adult blocking"
-)
-
-// blockPageServers is a helper function that converts a *BlockPageServer into
-// HTTP servers.
-func blockPageServers(
- srv *BlockPageServer,
- name string,
- timeout time.Duration,
-) (srvs []*http.Server) {
- if srv == nil {
- return nil
- }
-
- h := safeBrowsingHandler(name, srv.Content)
- for _, b := range srv.Bind {
- addr := b.Address.String()
- errLog := log.StdLog(fmt.Sprintf("websvc: %s: %s", name, addr), log.DEBUG)
- srvs = append(srvs, &http.Server{
- Addr: addr,
- Handler: h,
- TLSConfig: b.TLS,
- ErrorLog: errLog,
- ReadTimeout: timeout,
- WriteTimeout: timeout,
- IdleTimeout: timeout,
- ReadHeaderTimeout: timeout,
- })
- }
-
- return srvs
-}
-
// type check
var _ service.Interface = (*Service)(nil)
@@ -221,18 +190,24 @@ func (svc *Service) Start(_ context.Context) (err error) {
log.Info("websvc: linked ip %s: server is started", srv.Addr)
}
- for _, srv := range svc.safeBrowsing {
- go mustStartServer(srv)
-
- log.Info("websvc: safe browsing %s: server is started", srv.Addr)
- }
-
for _, srv := range svc.adultBlocking {
go mustStartServer(srv)
log.Info("websvc: adult blocking %s: server is started", srv.Addr)
}
+ for _, srv := range svc.generalBlocking {
+ go mustStartServer(srv)
+
+ log.Info("websvc: general blocking %s: server is started", srv.Addr)
+ }
+
+ for _, srv := range svc.safeBrowsing {
+ go mustStartServer(srv)
+
+ log.Info("websvc: safe browsing %s: server is started", srv.Addr)
+ }
+
for _, srv := range svc.nonDoH {
go mustStartServer(srv)
@@ -280,11 +255,14 @@ func (svc *Service) Shutdown(ctx context.Context) (err error) {
name: "linked ip",
srvs: svc.linkedIP,
}, {
- name: "safe browsing",
- srvs: svc.safeBrowsing,
- }, {
- name: "adult blocking",
+ name: adultBlockingName,
srvs: svc.adultBlocking,
+ }, {
+ name: generalBlockingName,
+ srvs: svc.generalBlocking,
+ }, {
+ name: safeBrowsingName,
+ srvs: svc.safeBrowsing,
}, {
name: "non-doh",
srvs: svc.nonDoH,
diff --git a/internal/websvc/websvc_test.go b/internal/websvc/websvc_test.go
index f14f6ab..f4e0d7f 100644
--- a/internal/websvc/websvc_test.go
+++ b/internal/websvc/websvc_test.go
@@ -9,7 +9,6 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/websvc"
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/testutil"
@@ -27,47 +26,6 @@ func TestNew(t *testing.T) {
startService(t, &websvc.Config{})
}
-func TestBlockPageServers(t *testing.T) {
- notFoundContent := []byte("404 page not found\n")
- robotsContent := []byte(agdhttp.RobotsDisallowAll)
-
- safeBrowsingAddr := netip.MustParseAddrPort("127.0.0.1:3000")
- safeBrowsingContent := []byte("safeBrowsingContent")
- safeBrowsingBps := &websvc.BlockPageServer{
- Content: safeBrowsingContent,
- Bind: []*websvc.BindData{{
- TLS: nil,
- Address: safeBrowsingAddr,
- }},
- }
-
- adultBlockingAddr := netip.MustParseAddrPort("127.0.0.1:3001")
- adultBlockingContent := []byte("adultBlockingContent")
- adultBlockingBps := &websvc.BlockPageServer{
- Content: adultBlockingContent,
- Bind: []*websvc.BindData{{
- TLS: nil,
- Address: adultBlockingAddr,
- }},
- }
-
- c := &websvc.Config{
- SafeBrowsing: safeBrowsingBps,
- AdultBlocking: adultBlockingBps,
- Timeout: testTimeout,
- }
-
- startService(t, c)
-
- assertContent(t, safeBrowsingAddr, "/", http.StatusOK, safeBrowsingContent)
- assertContent(t, safeBrowsingAddr, "/favicon.ico", http.StatusNotFound, notFoundContent)
- assertContent(t, safeBrowsingAddr, "/robots.txt", http.StatusOK, robotsContent)
-
- assertContent(t, adultBlockingAddr, "/", http.StatusOK, adultBlockingContent)
- assertContent(t, adultBlockingAddr, "/favicon.ico", http.StatusNotFound, notFoundContent)
- assertContent(t, adultBlockingAddr, "/robots.txt", http.StatusOK, robotsContent)
-}
-
func TestService_NonDoH(t *testing.T) {
robotsContent := []byte(agdhttp.RobotsDisallowAll)
@@ -116,6 +74,8 @@ func TestService_NonDoH(t *testing.T) {
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
}
+// assertContent performs an HTTP GET request on the given address and port on
+// the given path and asserts that the status and content are as expected.
func assertContent(t *testing.T, addr netip.AddrPort, path string, status int, expected []byte) {
t.Helper()
@@ -127,16 +87,21 @@ func assertContent(t *testing.T, addr netip.AddrPort, path string, status int, e
var err error
var body []byte
- // First check health-check service URL.
- // As the service could not be ready yet, check for it periodically.
- require.Eventually(t, func() bool {
- resp, err = c.Get((&url.URL{
- Scheme: "http",
- Host: addr.String(),
- Path: path,
- }).String())
+ u := &url.URL{
+ Scheme: "http",
+ Host: addr.String(),
+ Path: path,
+ }
+ req, err := http.NewRequest(http.MethodGet, u.String(), nil)
+ require.NoError(t, err)
+
+ // First check health-check service URL. As the service could not be ready
+ // yet, check for it periodically.
+ require.Eventually(t, func() (ok bool) {
+ resp, err = c.Do(req)
+
return err == nil
- }, 1*time.Second, 100*time.Millisecond)
+ }, testTimeout, testTimeout/10)
body, err = io.ReadAll(resp.Body)
require.NoError(t, err)
@@ -146,6 +111,8 @@ func assertContent(t *testing.T, addr netip.AddrPort, path string, status int, e
assert.Equal(t, agdhttp.UserAgent(), resp.Header.Get(httphdr.Server))
}
+// startService creates and starts an instance of [*websvc.Service] from the
+// provided configuration.
func startService(t *testing.T, c *websvc.Config) {
t.Helper()
@@ -154,11 +121,11 @@ func startService(t *testing.T, c *websvc.Config) {
var err error
require.NotPanics(t, func() {
- err = svc.Start(agdtest.ContextWithTimeout(t, testTimeout))
+ err = svc.Start(testutil.ContextWithTimeout(t, testTimeout))
})
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return svc.Shutdown(agdtest.ContextWithTimeout(t, testTimeout))
+ return svc.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
})
}
diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh
index 330252a..bbb8c90 100644
--- a/scripts/make/go-lint.sh
+++ b/scripts/make/go-lint.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
@@ -51,8 +51,9 @@ set -f -u
#
# * Package unsafe is… unsafe.
#
-# * Packages golang.org/x/exp/slices and golang.org/x/net/context have been
-# moved into stdlib.
+# * Package golang.org/x/exp/slices has been moved into stdlib.
+#
+# * Package golang.org/x/net/context has been moved into stdlib.
#
# Currently, the only standard exception are files generated from protobuf
# schemas, which use package reflect. If your project needs more exceptions,
@@ -64,17 +65,17 @@ set -f -u
# to prevent excessive allocations.
#
# TODO(a.garipov): Add deprecated package golang.org/x/exp/maps and once all
-# projects switch to Go 1.22 or later.
+# projects switch to Go 1.23 or later.
blocklist_imports() {
git grep\
-e '[[:space:]]"errors"$'\
+ -e '[[:space:]]"golang.org/x/exp/slices"$'\
+ -e '[[:space:]]"golang.org/x/net/context"$'\
-e '[[:space:]]"io/ioutil"$'\
-e '[[:space:]]"log"$'\
-e '[[:space:]]"reflect"$'\
-e '[[:space:]]"sort"$'\
-e '[[:space:]]"unsafe"$'\
- -e '[[:space:]]"golang.org/x/exp/slices"$'\
- -e '[[:space:]]"golang.org/x/net/context"$'\
-n\
-- '*.go'\
':!*.pb.go'\
@@ -164,8 +165,6 @@ git ls-files -- 'Makefile' '*.conf' '*.go' '*.mod' '*.sh' '*.yaml' '*.yml'\
| xargs misspell --error\
| sed -e 's/^/misspell: /'
-run_linter looppointer ./... "$dnssrvmod"
-
run_linter nilness ./... "$dnssrvmod"
# Do not use fieldalignment on $dnssrvmod, because ameshkov likes to place
diff --git a/scripts/make/go-test.sh b/scripts/make/go-test.sh
index 1c5443f..fa81c6f 100644
--- a/scripts/make/go-test.sh
+++ b/scripts/make/go-test.sh
@@ -39,16 +39,18 @@ else
fi
readonly race_flags
-go="${GO:-go}"
count_flags='--count=1'
+cover_flags='--coverprofile=./cover.out'
+go="${GO:-go}"
shuffle_flags='--shuffle=on'
# TODO(ameshkov): Find out, why QUIC tests are so slow, and return to 30s.
timeout_flags="${TIMEOUT_FLAGS:---timeout=90s}"
-readonly go count_flags shuffle_flags timeout_flags
+readonly count_flags cover_flags go shuffle_flags timeout_flags
# TODO(a.garipov): Remove the dnsserver stuff once it is separated.
"$go" test\
"$count_flags"\
+ "$cover_flags"\
"$race_flags"\
"$shuffle_flags"\
"$timeout_flags"\
diff --git a/scripts/make/go-upd-tools.sh b/scripts/make/go-upd-tools.sh
index 7486661..787475a 100644
--- a/scripts/make/go-upd-tools.sh
+++ b/scripts/make/go-upd-tools.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: 1
+# AdGuard-Project-Version: 2
verbose="${VERBOSE:-0}"
readonly verbose
@@ -29,5 +29,6 @@ go="${GO:-go}"
readonly go
cd ./internal/tools/
-"$go" get -u
+
+"$go" get -u "$x_flags"
"$go" mod tidy