From 5690301129feeefd34ca2201a731d88ec42dbe45 Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Fri, 7 Jun 2024 14:27:46 +0300 Subject: [PATCH] Sync v2.7.0 --- CHANGELOG.md | 95 + Makefile | 6 +- config.dist.yaml | 80 +- doc/configuration.md | 113 +- doc/development.md | 30 +- doc/environment.md | 21 - doc/http.md | 6 +- doc/querylog.md | 13 +- go.mod | 48 +- go.sum | 101 +- go.work | 2 +- go.work.sum | 53 +- internal/access/engine_internal_test.go | 3 +- internal/access/profile_test.go | 4 +- internal/agd/device.go | 21 + internal/agd/device_test.go | 1 - internal/agd/filterlist.go | 37 +- internal/agd/filterlist_test.go | 2 - internal/agd/requestid_test.go | 2 +- internal/agd/servergroup.go | 93 +- internal/agdcache/agdcache.go | 59 + internal/agdcache/lru.go | 106 + internal/agdcache/lru_test.go | 69 + internal/agdhttp/agdhttp.go | 1 + internal/agdhttp/client.go | 15 +- internal/agdnet/resolver.go | 213 - internal/agdnet/resolver_test.go | 88 - internal/agdpasswd/authenticator.go | 51 + internal/agdpasswd/authenticator_test.go | 49 + internal/agdservice/refresh.go | 77 +- internal/agdservice/refresh_test.go | 55 +- internal/agdtest/agdtest.go | 15 - internal/agdtest/interface.go | 27 +- internal/backendpb/backend.pb.go | 425 +- internal/backendpb/backend.proto | 8 + internal/backendpb/backend_grpc.pb.go | 2 +- internal/backendpb/profiledb.go | 89 +- internal/backendpb/profiledb_internal_test.go | 77 +- internal/backendpb/profiledb_test.go | 2 +- internal/billstat/runtime.go | 19 +- internal/billstat/runtime_test.go | 14 +- internal/bindtodevice/chanpacketconn_linux.go | 9 +- .../chanpacketconn_linux_internal_test.go | 17 +- .../bindtodevice/interfacelistener_linux.go | 103 +- .../listenconfig_linux_internal_test.go | 2 +- internal/bindtodevice/manager_linux.go | 39 +- internal/bindtodevice/manager_linux_test.go | 4 +- .../socket_linux_internal_test.go | 10 +- internal/cmd/additional.go | 2 +- internal/cmd/backend.go | 26 +- internal/cmd/cmd.go | 14 +- internal/cmd/config.go | 3 +- internal/cmd/ddr.go | 6 +- internal/cmd/env.go | 17 +- internal/cmd/error.go | 18 - internal/cmd/filter.go | 55 +- internal/cmd/filteringgroup.go | 6 +- internal/cmd/geoip.go | 22 +- internal/cmd/ifacelistener.go | 4 +- internal/cmd/ratelimit.go | 21 +- internal/cmd/safebrowsing.go | 30 +- internal/cmd/server.go | 12 +- internal/cmd/servergroup.go | 275 +- internal/cmd/tls.go | 38 +- internal/cmd/upstream.go | 21 +- internal/cmd/websvc.go | 29 +- internal/consul/allowlist.go | 15 +- internal/consul/allowlist_test.go | 34 +- internal/debugsvc/debugsvc_test.go | 5 +- internal/dnsdb/buffer.go | 19 +- internal/dnsdb/http.go | 9 +- internal/dnsdb/http_test.go | 4 +- internal/dnsdb/record.go | 6 +- internal/dnsmsg/blockingmode.go | 12 +- internal/dnsmsg/cloner.go | 4 +- internal/dnsmsg/cloner_test.go | 4 +- internal/dnsmsg/constructor.go | 21 +- internal/dnsmsg/constructor_test.go | 17 +- internal/dnsserver/cache/cache_test.go | 2 +- internal/dnsserver/dnsserver.go | 4 +- internal/dnsserver/dnsserver_test.go | 15 - internal/dnsserver/dnsservertest/handler.go | 2 +- internal/dnsserver/forward/forward.go | 5 + internal/dnsserver/forward/forward_test.go | 14 +- .../dnsserver/forward/healthcheck_test.go | 15 +- .../dnsserver/forward/upstreamplain_test.go | 16 +- internal/dnsserver/go.mod | 43 +- internal/dnsserver/go.sum | 86 +- .../dnsserver/netext/packetconn_linux_test.go | 2 +- internal/dnsserver/pool/conn.go | 2 +- internal/dnsserver/pool/pool.go | 14 +- internal/dnsserver/prometheus/cache_test.go | 2 +- .../prometheus/initsyncmap_internal_test.go | 6 +- .../dnsserver/prometheus/ratelimit_test.go | 6 +- internal/dnsserver/prometheus/server_test.go | 10 +- internal/dnsserver/protocol.go | 2 +- internal/dnsserver/ratelimit/backoff.go | 7 +- .../dnsserver/ratelimit/ratelimit_test.go | 2 +- internal/dnsserver/serverbase.go | 2 +- internal/dnsserver/serverbench_test.go | 14 +- internal/dnsserver/serverdns.go | 27 +- internal/dnsserver/serverdns_test.go | 5 +- internal/dnsserver/serverdnsudp.go | 14 +- internal/dnsserver/serverhttps.go | 54 +- internal/dnsserver/serverhttps_test.go | 1 - internal/dnsserver/serverhttpsjson.go | 6 +- internal/dnsserver/serverquic.go | 46 +- internal/dnsserver/serverquic_test.go | 10 +- internal/dnsserver/servertls_test.go | 5 +- internal/dnsserver/ttl.go | 2 +- internal/dnssvc/dnssvc.go | 61 +- internal/dnssvc/dnssvc_test.go | 5 +- internal/dnssvc/integration_test.go | 23 +- .../dnssvc/internal/devicesetter/device.go | 187 + .../internal/devicesetter/device_test.go | 251 + .../dnssvc/internal/devicesetter/deviceid.go | 234 + .../internal/devicesetter/deviceid_test.go | 468 + .../internal/devicesetter/devicesetter.go | 124 + .../devicesetter/devicesetter_test.go | 222 + .../dnssvc/internal/devicesetter/error.go | 51 + .../dnssvc/internal/dnssvctest/dnssvctest.go | 17 +- .../dnssvc/internal/dnssvctest/interface.go | 37 + internal/dnssvc/internal/initial/deviceid.go | 208 - .../initial/deviceid_internal_test.go | 270 - internal/dnssvc/internal/initial/initial.go | 92 +- .../dnssvc/internal/initial/initial_test.go | 292 +- internal/dnssvc/internal/initial/location.go | 60 + internal/dnssvc/internal/initial/profile.go | 131 - .../internal/initial/profile_internal_test.go | 265 - .../internal/initial/specialdomain_test.go | 64 +- internal/dnssvc/internal/mainmw/debug.go | 2 +- .../internal/mainmw/debug_internal_test.go | 2 +- internal/dnssvc/internal/mainmw/filter.go | 39 +- .../internal/mainmw/filter_internal_test.go | 24 +- internal/dnssvc/internal/mainmw/mainmw.go | 103 +- .../dnssvc/internal/mainmw/mainmw_test.go | 44 +- .../internal/preupstream/preupstream_test.go | 4 +- internal/ecscache/cache.go | 33 +- internal/ecscache/cache_internal_test.go | 12 +- internal/ecscache/ecsblocklist.go | 16422 ++++++++-------- internal/ecscache/ecsblocklist_generate.go | 8 +- internal/ecscache/ecscache.go | 28 +- internal/ecscache/ecscache_test.go | 16 +- internal/errcoll/sentry.go | 9 +- internal/experiment/experiment.go | 55 + internal/filter/filter.go | 13 +- internal/filter/filter_test.go | 15 +- internal/filter/hashprefix/filter.go | 242 +- internal/filter/hashprefix/filter_test.go | 466 +- internal/filter/hashprefix/hashprefix_test.go | 1 + internal/filter/hashprefix/matcher.go | 4 +- internal/filter/hashprefix/storage.go | 2 +- internal/filter/hashprefix/storage_test.go | 10 +- internal/filter/internal/cachekey.go | 36 + .../filter/internal/composite/composite.go | 212 +- .../composite/composite_internal_test.go | 18 +- .../internal/composite/composite_test.go | 67 +- .../filter/internal/composite/dnsresult.go | 27 - internal/filter/internal/custom/custom.go | 27 +- .../filter/internal/custom/custom_test.go | 14 +- .../filter/internal/filtertest/filtertest.go | 67 +- internal/filter/internal/internal.go | 4 - internal/filter/internal/refreshable_test.go | 9 +- internal/filter/internal/result.go | 76 +- .../internal/resultcache/resultcache.go | 103 - .../internal/resultcache/resultcache_test.go | 57 - .../{composite => rulelist}/dnsrewrite.go | 25 +- .../filter/internal/rulelist/refreshable.go | 8 +- .../internal/rulelist/refreshable_test.go | 5 +- internal/filter/internal/rulelist/result.go | 95 + internal/filter/internal/rulelist/rulelist.go | 73 +- .../filter/internal/safesearch/safesearch.go | 176 +- .../internal/safesearch/safesearch_test.go | 144 +- internal/filter/storage.go | 117 +- internal/filter/storage_test.go | 289 +- internal/filter/testdata/filter | 2 - internal/filter/testdata/general_safe_search | 4 +- internal/geoip/asntops.go | 6368 +++--- internal/geoip/asntops_generate.go | 10 +- internal/geoip/file.go | 84 +- internal/geoip/file_test.go | 6 +- internal/geoip/filescanner.go | 4 +- internal/geoip/geoip_test.go | 12 +- internal/metrics/backend.go | 4 +- internal/metrics/bindtodevice.go | 16 +- internal/metrics/dnsmsg.go | 4 +- internal/metrics/dnsmsg_test.go | 9 + internal/metrics/dnssvc.go | 27 +- internal/metrics/metrics.go | 3 + internal/metrics/research.go | 142 +- internal/metrics/tls.go | 7 +- internal/metrics/usercount_internal_test.go | 10 +- internal/metrics/websvc.go | 8 +- .../internal/filecachepb/filecache.pb.go | 216 +- .../internal/filecachepb/filecache.proto | 12 +- .../internal/filecachepb/filecachepb.go | 94 +- .../filecachepb/filecachepb_internal_test.go | 8 +- internal/profiledb/internal/internal.go | 2 +- .../internal/profiledbtest/profiledbtest.go | 6 + internal/profiledb/profiledb.go | 41 +- internal/profiledb/profiledb_test.go | 28 +- internal/querylog/entry.go | 9 +- internal/querylog/fs.go | 19 +- internal/querylog/fs_test.go | 12 +- internal/rulestat/http.go | 60 +- internal/rulestat/http_test.go | 35 +- internal/rulestat/rulestat.go | 2 - internal/rulestat/rulestat_test.go | 4 + internal/tools/go.mod | 20 +- internal/tools/go.sum | 40 +- internal/websvc/blockpage.go | 161 + internal/websvc/blockpage_test.go | 146 + internal/websvc/handler.go | 75 - internal/websvc/handler_test.go | 30 +- internal/websvc/static.go | 45 + internal/websvc/static_test.go | 45 + internal/websvc/websvc.go | 90 +- internal/websvc/websvc_test.go | 73 +- scripts/make/go-lint.sh | 15 +- scripts/make/go-test.sh | 6 +- scripts/make/go-upd-tools.sh | 5 +- 221 files changed, 17414 insertions(+), 16436 deletions(-) create mode 100644 internal/agdcache/agdcache.go create mode 100644 internal/agdcache/lru.go create mode 100644 internal/agdcache/lru_test.go delete mode 100644 internal/agdnet/resolver.go delete mode 100644 internal/agdnet/resolver_test.go create mode 100644 internal/agdpasswd/authenticator.go create mode 100644 internal/agdpasswd/authenticator_test.go create mode 100644 internal/dnssvc/internal/devicesetter/device.go create mode 100644 internal/dnssvc/internal/devicesetter/device_test.go create mode 100644 internal/dnssvc/internal/devicesetter/deviceid.go create mode 100644 internal/dnssvc/internal/devicesetter/deviceid_test.go create mode 100644 internal/dnssvc/internal/devicesetter/devicesetter.go create mode 100644 internal/dnssvc/internal/devicesetter/devicesetter_test.go create mode 100644 internal/dnssvc/internal/devicesetter/error.go create mode 100644 internal/dnssvc/internal/dnssvctest/interface.go delete mode 100644 internal/dnssvc/internal/initial/deviceid.go delete mode 100644 internal/dnssvc/internal/initial/deviceid_internal_test.go create mode 100644 internal/dnssvc/internal/initial/location.go delete mode 100644 internal/dnssvc/internal/initial/profile.go delete mode 100644 internal/dnssvc/internal/initial/profile_internal_test.go create mode 100644 internal/experiment/experiment.go create mode 100644 internal/filter/internal/cachekey.go delete mode 100644 internal/filter/internal/composite/dnsresult.go delete mode 100644 internal/filter/internal/resultcache/resultcache.go delete mode 100644 internal/filter/internal/resultcache/resultcache_test.go rename internal/filter/internal/{composite => rulelist}/dnsrewrite.go (93%) create mode 100644 internal/filter/internal/rulelist/result.go create mode 100644 internal/metrics/dnsmsg_test.go create mode 100644 internal/websvc/blockpage.go create mode 100644 internal/websvc/blockpage_test.go create mode 100644 internal/websvc/static.go create mode 100644 internal/websvc/static_test.go 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