diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1525252..9c4ef7a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,94 @@ The format is **not** based on [Keep a Changelog][kec], since the project **does
[kec]: https://keepachangelog.com/en/1.0.0/
[sem]: https://semver.org/spec/v2.0.0.html
+## AGDNS-2484/ Build 886
+
+- Property `type` of the `ratelimit` object has been moved to the underlying `allowlist` object. So replace this:
+
+ ```yaml
+ ratelimit:
+ type: 'consul'
+ # …
+ allowlist:
+ # …
+ ```
+
+ with this:
+
+ ```yaml
+ ratelimit:
+ # …
+ allowlist:
+ type: 'consul'
+ # …
+ ```
+
+## AGDNS-2443 / Build 877
+
+- The object `filters` has new properties: `ede_enabled`, and `sde_enabled`. So replace this:
+
+ ```yaml
+ filters:
+ # …
+ ```
+
+ with this:
+
+ ```yaml
+ filters:
+ # …
+ ede_enabled: true
+ sde_enabled: true
+ ```
+
+## AGDNS-2456 / Build 873
+
+- The environment variables `BACKEND_RATELIMIT_URL` and `BACKEND_RATELIMIT_API_KEY` have been added.
+
+- Added the `type` property within the `ratelimit` object. So add it:
+
+ ```yaml
+ ratelimit:
+ type: 'consul'
+ # …
+ ```
+
+## AGDNS-2431 / Build 872
+
+- The objects `ratelimit.ipv4` and `ratelimit.ipv6` have been modified. Its `rps` properties have been replaced with the new properties `count` and `interval`. So replace this:
+
+ ```yaml
+ ratelimit:
+ # …
+ ipv4:
+ rps: 30
+ ipv6:
+ rps: 300
+ ```
+
+ with this:
+
+ ```yaml
+ ratelimit:
+ # …
+ ipv4:
+ # …
+ count: 300
+ interval: 10s
+ ipv6:
+ # …
+ count: 3000
+ interval: 10s
+ ```
+
+ Adjust the value and add new ones, if necessary.
+
+## AGDNS-2457 / Build 871
+
+- The environment variables `DNSCHECK_REMOTEKV_URL` and `DNSCHECK_REMOTEKV_API_KEY` have been added.
+
+- The property `kv.type` within the `check` object now supports the `backend` value.
+
## AGDNS-2468 / Build 869
- The environment variable `PROFILES_MAX_RESP_SIZE` has been added. It sets the maximum size of the response from the profiles endpoint of the backend API. The default value is `8MB`.
diff --git a/Makefile b/Makefile
index d75f046..cbdf6a4 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ BRANCH = $${BRANCH:-$$(git rev-parse --abbrev-ref HEAD)}
GOAMD64 = v1
GOPROXY = https://proxy.golang.org|direct
GOTELEMETRY = off
-GOTOOLCHAIN = go1.23.1
+GOTOOLCHAIN = go1.23.2
RACE = 0
REVISION = $${REVISION:-$$(git rev-parse --short HEAD)}
VERSION = 0
diff --git a/config.dist.yaml b/config.dist.yaml
index 170a4ed..c12d370 100644
--- a/config.dist.yaml
+++ b/config.dist.yaml
@@ -10,15 +10,19 @@ ratelimit:
response_size_estimate: 1KB
# Rate limit options for IPv4 addresses.
ipv4:
- # Rate of requests per second for one subnet for IPv4 addresses.
- rps: 30
+ # Requests per configured interval for one subnet for IPv4 addresses.
+ count: 300
+ # The time during which to count the number of requests.
+ interval: 10s
# The lengths of the subnet prefixes used to calculate rate limiter
# bucket keys for IPv4 addresses.
subnet_key_len: 24
# Rate limit options for IPv6 addresses.
ipv6:
- # Rate of requests per second for one subnet for IPv6 addresses.
- rps: 300
+ # Requests per configured interval for one subnet for IPv6 addresses.
+ count: 3000
+ # The time during which to count the number of requests.
+ interval: 10s
# The lengths of the subnet prefixes used to calculate rate limiter
# bucket keys for IPv6 addresses.
subnet_key_len: 48
@@ -40,6 +44,9 @@ ratelimit:
- '127.0.0.1/24'
# Time between two updates of allow list.
refresh_interval: 1h
+ # Defines where the rate limiting settings are received from. Allowed
+ # values are "backend" and "consul".
+ type: 'consul'
# Configuration for the stream connection limiting.
connection_limit:
@@ -167,8 +174,8 @@ geoip:
check:
# Domains to use for DNS checking.
kv:
- # Defines the type of remote kay-value storage. Allowed values are
- # "consul" and "redis".
+ # Defines the type of remote key-value storage. Allowed values are
+ # "backend", "consul", and "redis".
type: 'consul'
# For how long to keep the information about the client.
ttl: 30s
@@ -313,6 +320,10 @@ filters:
enabled: true
# The size of the LRU cache of rule-list filtering results.
size: 10000
+ # Enable the Extended DNS Errors feature.
+ ede_enabled: true
+ # Enable the Structured DNS Errors feature. Requires ede_enabled: true.
+ sde_enabled: true
# Filtering groups are a set of different filtering configurations. These
# filtering configurations are then used by server_groups.
diff --git a/doc/configuration.md b/doc/configuration.md
index c1655f5..34e45e3 100644
--- a/doc/configuration.md
+++ b/doc/configuration.md
@@ -104,9 +104,13 @@ The `ratelimit` object has the following properties:
- `ipv4`: The ipv4 configuration object. It has the following fields:
- - `rps`: The rate of requests per second for one subnet. Requests above this are counted in the backoff count.
+ - `count`: Requests per configured interval for one subnet for IPv4 addresses. Requests above this are counted in the backoff count.
- **Example:** `30`.
+ **Example:** `300`.
+
+ - `interval`: The time during which to count the number of requests.
+
+ **Example:** `10s`.
- `ipv4-subnet_key_len`: The length of the subnet prefix used to calculate rate limiter bucket keys.
@@ -134,7 +138,11 @@ The `ratelimit` object has the following properties:
**Example:** `30s`.
-For example, if `backoff_period` is `1m`, `backoff_count` is `10`, and `ipv4-rps` is `5`, a client (meaning all IP addresses within the subnet defined by `ipv4-subnet_key_len`) that made 15 requests in one second or 6 requests (one above `rps`) every second for 10 seconds within one minute, the client is blocked for `backoff_duration`.
+ - `type`: Defines where the rate limit settings are received from. Allowed values are `backend` and `consul`.
+
+ **Example:** `consul`.
+
+For example, if `backoff_period` is `1m`, `backoff_count` is `10`, `ipv4-count` is `5`, and `ipv4-interval` is `1s`, a client (meaning all IP addresses within the subnet defined by `ipv4-subnet_key_len`) that made 15 requests in one second or 6 requests (one above `rps`) every second for 10 seconds within one minute, the client is blocked for `backoff_duration`.
### Stream connection limit
@@ -370,12 +378,14 @@ The `check` object has the following properties:
- `kv`: Remote key-value storage settings. It has the following properties:
- - `type`: Type of the remote KV storage. Allowed values are `consul` and `redis`.
+ - `type`: Type of the remote KV storage. Allowed values are `backend`, `consul`, and `redis`.
**Example:** `consul`.
- `ttl`: For how long to keep the information about a single user in remote KV, as a human-readable duration.
+ For `backend`, the TTL must be greater than `0s`.
+
For `consul`, the TTL must be between `10s` and `1d`. Note that the actual TTL can be up to twice as long.
For `redis`, the TTL must be greater than or equal to `1ms`.
@@ -592,6 +602,14 @@ The `filters` object has the following properties:
**Example:** `10000`.
+- `ede_enabled`: Shows if Extended DNS Error codes should be added.
+
+ **Example:** `true`.
+
+- `sde_enabled`: Shows if the experimental Structured DNS Errors feature should be enabled. `ede_enabled` must be `true` to enable SDE.
+
+ **Example:** `true`.
+
[env-blocked_services]: environment.md#BLOCKED_SERVICE_INDEX_URL
## Filtering groups
diff --git a/doc/development.md b/doc/development.md
index 385c433..f118d11 100644
--- a/doc/development.md
+++ b/doc/development.md
@@ -159,7 +159,7 @@ You'll need to supply the following:
See the [external HTTP API documentation][externalhttp].
-You may use `go run ./scripts/backend` to start mock GRPC server for `BILLSTAT_URL` and `PROFILES_URL` endpoints.
+You may use `go run ./scripts/backend` to start mock GRPC server for `BACKEND_PROFILES_URL`, `BILLSTAT_URL`, `DNSCHECK_REMOTEKV_URL`, and `PROFILES_URL` endpoints.
You may need to change the listen ports in `config.yaml` which are less than 1024 to some other ports. Otherwise, `sudo` or `doas` is required to run `AdGuardDNS`.
diff --git a/doc/environment.md b/doc/environment.md
index cda8b27..76c5d49 100644
--- a/doc/environment.md
+++ b/doc/environment.md
@@ -6,6 +6,8 @@ AdGuard DNS uses [environment variables][wiki-env] to store some of the more sen
- [`ADULT_BLOCKING_ENABLED`](#ADULT_BLOCKING_ENABLED)
- [`ADULT_BLOCKING_URL`](#ADULT_BLOCKING_URL)
+- [`BACKEND_RATELIMIT_API_KEY`](#BACKEND_RATELIMIT_API_KEY)
+- [`BACKEND_RATELIMIT_URL`](#BACKEND_RATELIMIT_URL)
- [`BILLSTAT_API_KEY`](#BILLSTAT_API_KEY)
- [`BILLSTAT_URL`](#BILLSTAT_URL)
- [`BLOCKED_SERVICE_ENABLED`](#BLOCKED_SERVICE_ENABLED)
@@ -14,6 +16,8 @@ AdGuard DNS uses [environment variables][wiki-env] to store some of the more sen
- [`CONSUL_ALLOWLIST_URL`](#CONSUL_ALLOWLIST_URL)
- [`CONSUL_DNSCHECK_KV_URL`](#CONSUL_DNSCHECK_KV_URL)
- [`CONSUL_DNSCHECK_SESSION_URL`](#CONSUL_DNSCHECK_SESSION_URL)
+- [`DNSCHECK_REMOTEKV_API_KEY`](#DNSCHECK_REMOTEKV_API_KEY)
+- [`DNSCHECK_REMOTEKV_URL`](#DNSCHECK_REMOTEKV_URL)
- [`FILTER_CACHE_PATH`](#FILTER_CACHE_PATH)
- [`FILTER_INDEX_URL`](#FILTER_INDEX_URL)
- [`GENERAL_SAFE_ENABLED`](#GENERAL_SAFE_SEARCH_ENABLED)
@@ -62,6 +66,21 @@ The HTTP(S) URL of source list of rules for adult blocking filter.
**Default:** No default value, the variable is required if `ADULT_BLOCKING_ENABLED` is set to `1`.
+## `BACKEND_RATELIMIT_API_KEY`
+
+The API key to use when authenticating requests to the backend rate limiter API, if any. The API key should be valid as defined by [RFC 6750].
+
+**Default:** **Unset.**
+
+## `BACKEND_RATELIMIT_URL`
+
+The base backend URL for backend rate limiter. Supports gRPC(S) (`grpc://` and `grpcs://`) URLs. See the [external API requirements section][ext-backend-ratelimit].
+
+**Default:** No default value, the variable is required if the [type][conf-ratelimit-type] of rate limiter is `backend` in the configuration file.
+
+[conf-ratelimit-type]: configuration.md#ratelimit-type
+[ext-backend-ratelimit]: externalhttp.md#backend-ratelimit
+
## `BILLSTAT_API_KEY`
The API key to use when authenticating queries to the billing statistics API, if any. The API key should be valid as defined by [RFC 6750].
@@ -72,7 +91,7 @@ The API key to use when authenticating queries to the billing statistics API, if
## `BILLSTAT_URL`
-The base backend URL for backend billing statistics uploader API. Supports gRPC(S) (`grpc://` and`grpcs://`) URLs. See the [external HTTP API requirements section][ext-billstat].
+The base backend URL for backend billing statistics uploader API. Supports gRPC(S) (`grpc://` and `grpcs://`) URLs. See the [external HTTP API requirements section][ext-billstat].
**Default:** No default value, the variable is required if there is at least one [server group][conf-sg] with profiles enabled.
@@ -103,7 +122,7 @@ The path to the configuration file.
The HTTP(S) URL of the Consul instance serving the dynamic part of the rate-limit allowlist. See the [external HTTP API requirements section][ext-consul] on the expected format of the response.
-**Default:** No default value, the variable is **required.**
+**Default:** No default value, the variable is required if the [type][conf-ratelimit-type] of rate limiter is `consul` in the configuration file.
[ext-consul]: externalhttp.md#consul
@@ -123,6 +142,20 @@ The HTTP(S) URL of the session API of the Consul instance used as a key-value da
**Example:** `http://localhost:8500/v1/session/create`
+## `DNSCHECK_REMOTEKV_API_KEY`
+
+The API key to use when authenticating queries to the backend key-value database API, if any. The API key should be valid as defined by [RFC 6750].
+
+**Default:** **Unset.**
+
+## `DNSCHECK_REMOTEKV_URL`
+
+The base backend URL used as a key-value database for the DNS server checking. Supports gRPC(S) (`grpc://` and`grpcs://`) URLs. See the [external API requirements section][ext-backend-dnscheck].
+
+**Default:** **Unset.**
+
+[ext-backend-dnscheck]: externalhttp.md#backend-dnscheck
+
## `FILTER_CACHE_PATH`
The path to the directory used to store the cached version of all filters and filter indexes.
@@ -238,11 +271,11 @@ The profile cache is read on start and is later updated on every [full refresh][
The maximum size of the response from the profiles API in a human-readable format.
-**Default:** `8MB`.
+**Default:** `64MB`.
## `PROFILES_URL`
-The base backend URL for profiles API. Supports gRPC(S) (`grpc://` and`grpcs://`) URLs. See the [external API requirements section][ext-profiles].
+The base backend URL for profiles API. Supports gRPC(S) (`grpc://` and `grpcs://`) URLs. See the [external API requirements section][ext-profiles].
**Default:** No default value, the variable is required if there is at least one [server group][conf-sg] with profiles enabled.
@@ -252,7 +285,7 @@ The base backend URL for profiles API. Supports gRPC(S) (`grpc://` and`grpcs://`
Redis server address. Can be an IP address or a hostname.
-**Default:** No default value, the variable if required if the [type][conf-check-kv-type] of remote KV storage for DNS server checking is `redis` in the configuration file.
+**Default:** No default value, the variable is required if the [type][conf-check-kv-type] of remote KV storage for DNS server checking is `redis` in the configuration file.
[conf-check-kv-type]: configuration.md#check-kv-type
diff --git a/doc/externalhttp.md b/doc/externalhttp.md
index d50f09e..364b069 100644
--- a/doc/externalhttp.md
+++ b/doc/externalhttp.md
@@ -10,7 +10,9 @@ AdGuard DNS uses information from external HTTP APIs for filtering and other pie
## Contents
- [Backend billing statistics](#backend-billstat)
+- [Backend DNSCheck service](#backend-dnscheck)
- [Backend profiles service](#backend-profiles)
+- [Backend ratelimit service](#backend-ratelimit)
- [Consul key-value storage](#consul)
- [Filtering](#filters)
- [Blocked services](#filters-blocked-services)
@@ -28,6 +30,15 @@ This service is disabled when all server groups have property [`profiles_enabled
[env-billstat_url]: environment.md#BILLSTAT_URL
[conf-srvgrp-prof]: configuration.md#sg-*-profiles_enabled
+## Backend DNSCheck service
+
+This is the service to which the [`DNSCHECK_REMOTEKV_URL`][env-dnscheck_remotekv_url] environment variable points. Supports gRPC(s) URLs. The service must correspond to `./internal/backendpb/dns.proto`.
+
+This service is only enabled when the `check.kv` object has the [`type`][conf-check-kv-type] property set to `backend`.
+
+[env-dnscheck_remotekv_url]: environment.md#DNSCHECK_REMOTEKV_URL
+[conf-check-kv-type]: configuration.md#check-kv-type
+
## Backend profiles service
This is the service to which the [`PROFILES_URL`][env-profiles_url] environment variable points. Supports gRPC(s) URLs. The service must correspond to `./internal/backendpb/dns.proto`.
@@ -36,6 +47,15 @@ This service is disabled when all server groups have property [`profiles_enabled
[env-profiles_url]: environment.md#PROFILES_URL
+## Backend ratelimit_service
+
+This is the service to which the [`BACKEND_RATELIMIT_URL`][env-backend_ratelimit_url] environment variable points. Supports gRPC(s) URLs. The service must correspond to `./internal/backendpb/dns.proto`.
+
+This service is only enabled when the `ratelimit` object has the [`type`][conf-ratelimit-type] property set to `backend`.
+
+[conf-ratelimit-type]: configuration.md#ratelimit-type
+[env-backend_ratelimit_url]: environment.md#BACKEND_RATELIMIT_URL
+
## Consul key-value storage
A [Consul][consul-io] service can be used for the DNS server check and dynamic rate-limit allowlist features. Currently used endpoints can be seen in the documentation of the [`CONSUL_ALLOWLIST_URL`][env-consul-allowlist], [`CONSUL_DNSCHECK_KV_URL`][env-consul-dnscheck-kv], and [`CONSUL_DNSCHECK_SESSION_URL`][env-consul-dnscheck-session] environment variables.
diff --git a/go.mod b/go.mod
index f502ad6..2279a23 100644
--- a/go.mod
+++ b/go.mod
@@ -1,34 +1,34 @@
module github.com/AdguardTeam/AdGuardDNS
-go 1.23.1
+go 1.23.2
require (
github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-20240607112746-5690301129fe
- github.com/AdguardTeam/golibs v0.28.0
- github.com/AdguardTeam/urlfilter v0.19.0
+ github.com/AdguardTeam/golibs v0.30.1
+ github.com/AdguardTeam/urlfilter v0.20.0
github.com/ameshkov/dnscrypt/v2 v2.3.0
github.com/axiomhq/hyperloglog v0.2.0
github.com/bluele/gcache v0.0.2
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500
github.com/caarlos0/env/v7 v7.1.0
- github.com/getsentry/sentry-go v0.28.1
+ github.com/getsentry/sentry-go v0.29.1
github.com/gomodule/redigo v1.9.2
github.com/google/renameio/v2 v2.0.0
github.com/miekg/dns v1.1.62
github.com/oschwald/maxminddb-golang v1.13.1
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
- github.com/prometheus/client_golang v1.20.1
+ github.com/prometheus/client_golang v1.20.5
github.com/prometheus/client_model v0.6.1
- github.com/prometheus/common v0.55.0
- github.com/quic-go/quic-go v0.47.0
+ github.com/prometheus/common v0.60.0
+ github.com/quic-go/quic-go v0.48.1
github.com/stretchr/testify v1.9.0
- golang.org/x/crypto v0.27.0
- golang.org/x/exp v0.0.0-20240909161429-701f63a606c0
- golang.org/x/net v0.29.0
- golang.org/x/sys v0.25.0
- golang.org/x/time v0.6.0
- google.golang.org/grpc v1.65.0
- google.golang.org/protobuf v1.34.2
+ golang.org/x/crypto v0.28.0
+ golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
+ golang.org/x/net v0.30.0
+ golang.org/x/sys v0.26.0
+ golang.org/x/time v0.7.0
+ google.golang.org/grpc v1.67.1
+ google.golang.org/protobuf v1.35.1
gopkg.in/yaml.v2 v2.4.0
)
@@ -41,24 +41,21 @@ require (
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/v3 v3.0.0 // indirect
- github.com/google/pprof v0.0.0-20240929191954-255acd752d31 // indirect
- github.com/klauspost/compress v1.17.9 // indirect
+ github.com/google/pprof v0.0.0-20241023014458-598669927662 // indirect
+ github.com/klauspost/compress v1.17.11 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
github.com/panjf2000/ants/v2 v2.10.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
- go.uber.org/mock v0.4.0 // indirect
+ go.uber.org/mock v0.5.0 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/sync v0.8.0 // indirect
- golang.org/x/text v0.18.0 // indirect
- golang.org/x/tools v0.25.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
+ golang.org/x/text v0.19.0 // indirect
+ golang.org/x/tools v0.26.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace github.com/AdguardTeam/AdGuardDNS/internal/dnsserver => ./internal/dnsserver
-
-// TODO(a.garipov): Remove once https://github.com/quic-go/quic-go/pull/4685 is merged.
-replace github.com/quic-go/quic-go => github.com/ainar-g/quic-go v0.0.0-20240930125330-446bd86056fd
diff --git a/go.sum b/go.sum
index 5ba8856..125acca 100644
--- a/go.sum
+++ b/go.sum
@@ -1,13 +1,11 @@
-github.com/AdguardTeam/golibs v0.28.0 h1:SK1q8SqkkJ/61pp2abTmio90S4QpteYK9rtgROfnrb4=
-github.com/AdguardTeam/golibs v0.28.0/go.mod h1:iWdjXPCwmK2g2FKIb/OwEPnovSXeMqRhI8FWLxF5oxE=
-github.com/AdguardTeam/urlfilter v0.19.0 h1:q7eH13+yNETlpD/VD3u5rLQOripcUdEktqZFy+KiQLk=
-github.com/AdguardTeam/urlfilter v0.19.0/go.mod h1:+N54ZvxqXYLnXuvpaUhK2exDQW+djZBRSb6F6j0rkBY=
+github.com/AdguardTeam/golibs v0.30.1 h1:/yv7dq2h7WXw/jTDxkE3FP9zHerRT+i03PZRHJX4fPU=
+github.com/AdguardTeam/golibs v0.30.1/go.mod h1:FkwcNQEJoGsgDGXcalrVa/4gWbE68KsmE2guXWtBQUE=
+github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs=
+github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk=
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/ainar-g/quic-go v0.0.0-20240930125330-446bd86056fd h1:mw4LqrCiv3vcKuCxBRg7kA17xfHKM+9hZgFWmyhe/AY=
-github.com/ainar-g/quic-go v0.0.0-20240930125330-446bd86056fd/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
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=
@@ -29,8 +27,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
-github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k=
-github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg=
+github.com/getsentry/sentry-go v0.29.1 h1:DyZuChN8Hz3ARxGVV8ePaNXh1dQ7d76AiB117xcREwA=
+github.com/getsentry/sentry-go v0.29.1/go.mod h1:x3AtIzN01d6SiWkderzaH28Tm0lgkafpJ5Bm3li39O0=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
@@ -43,12 +41,12 @@ github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s
github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw=
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-20240929191954-255acd752d31 h1:LcRdQWywSgfi5jPsYZ1r2avbbs5IQ5wtyhMBCcokyo4=
-github.com/google/pprof v0.0.0-20240929191954-255acd752d31/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/google/pprof v0.0.0-20241023014458-598669927662 h1:SKMkD83p7FwUqKmBsPdLHF5dNyxq3jOWwu9w9UyH5vA=
+github.com/google/pprof v0.0.0-20241023014458-598669927662/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
-github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
+github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
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=
@@ -79,16 +77,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.20.1 h1:IMJXHOD6eARkQpxo8KkhgEVFlBNm+nkrFUyGlIu7Na8=
-github.com/prometheus/client_golang v1.20.1/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
+github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
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.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
-github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA=
+github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
+github.com/quic-go/quic-go v0.48.1 h1:y/8xmfWI9qmGTc+lBr4jKRUWLGSlSigv847ULJ4hYXA=
+github.com/quic-go/quic-go v0.48.1/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
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.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
@@ -109,33 +109,33 @@ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+F
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/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.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
-golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
-golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
-golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
+go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
+go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
+golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
+golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
+golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
+golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
-golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
-golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
+golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
-golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
-golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
-golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
-golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
-golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
-golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
-google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
-google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
-google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
-google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
+golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
+golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
+golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
+golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
+google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
+google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
+google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
+google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
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 71f59a2..b86714e 100644
--- a/go.work
+++ b/go.work
@@ -1,4 +1,4 @@
-go 1.23.1
+go 1.23.2
use (
.
diff --git a/go.work.sum b/go.work.sum
index 3cec561..1d88e00 100644
--- a/go.work.sum
+++ b/go.work.sum
@@ -1,5 +1,6 @@
cel.dev/expr v0.15.0 h1:O1jzfJCQBfL5BFoYktaxwIhuttaQPsVWerH9/EEKx0w=
cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
+cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
@@ -45,6 +46,7 @@ cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGB
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
+cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
cloud.google.com/go/contactcenterinsights v1.13.0/go.mod h1:ieq5d5EtHsu8vhe2y3amtZ+BE+AQwX5qAy7cpo0POsI=
cloud.google.com/go/container v1.31.0/go.mod h1:7yABn5s3Iv3lmw7oMmyGbeV6tQj86njcTijkkGuvdZA=
cloud.google.com/go/containeranalysis v0.11.4/go.mod h1:cVZT7rXYBS9NG1rhQbWL9pWbXCKHWJPYraE8/FTSYPE=
@@ -156,6 +158,9 @@ github.com/AdguardTeam/golibs v0.19.0/go.mod h1:3WunclLLfrVAq7fYQRhd6f168FHOEMss
github.com/AdguardTeam/golibs v0.25.2/go.mod h1:HaTyS2wCbxFudjht9N/+/Qf1b5cMad2BAYSwe7DPCXI=
github.com/AdguardTeam/golibs v0.25.3 h1:A06JZGSuAhAC0uq/s7IlNsv/V8TyNJfLalB0vhkd1vA=
github.com/AdguardTeam/golibs v0.25.3/go.mod h1:HaTyS2wCbxFudjht9N/+/Qf1b5cMad2BAYSwe7DPCXI=
+github.com/AdguardTeam/golibs v0.30.0/go.mod h1:vjw1OVZG6BYyoqGRY88U4LCJLOMfhBFhU0UJBdaSAuQ=
+github.com/AdguardTeam/golibs v0.30.1 h1:/yv7dq2h7WXw/jTDxkE3FP9zHerRT+i03PZRHJX4fPU=
+github.com/AdguardTeam/golibs v0.30.1/go.mod h1:FkwcNQEJoGsgDGXcalrVa/4gWbE68KsmE2guXWtBQUE=
github.com/AdguardTeam/gomitmproxy v0.2.0 h1:rvCOf17pd1/CnMyMQW891zrEiIQBpQ8cIGjKN9pinUU=
github.com/AdguardTeam/gomitmproxy v0.2.1 h1:p9gr8Er1TYvf+7ic81Ax1sZ62UNCsMTZNbm7tC59S9o=
github.com/AdguardTeam/gomitmproxy v0.2.1/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
@@ -245,6 +250,7 @@ github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 h1:DBmgJDC9dTfkVyGgipa
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM=
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
+github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
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=
@@ -262,12 +268,14 @@ github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1
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/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
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/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
@@ -338,6 +346,7 @@ 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/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
+github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -576,6 +585,7 @@ github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwb
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
@@ -677,6 +687,7 @@ github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
+github.com/urfave/negroni/v3 v3.1.1/go.mod h1:jWvnX03kcSjDBl/ShB0iHvx5uOs7mAzZXW+JvJ5XYAs=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc=
@@ -828,6 +839,7 @@ golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
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=
@@ -912,6 +924,7 @@ golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
+golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
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.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -1000,6 +1013,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
+google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:vh/N7795ftP0AkN1w8XKqN4w1OdUKXW5Eummda+ofv8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
diff --git a/internal/agdhttp/client.go b/internal/agdhttp/client.go
index 85a22a6..93010cc 100644
--- a/internal/agdhttp/client.go
+++ b/internal/agdhttp/client.go
@@ -10,6 +10,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
)
// Client is a wrapper around http.Client.
@@ -93,6 +94,7 @@ func (c *Client) do(
req.Header.Set(httphdr.UserAgent, c.userAgent)
resp, err = c.http.Do(req)
+ urlutil.RedactUserinfoInURLError(u, err)
if err != nil && resp != nil && resp.Header != nil {
// A non-nil Response with a non-nil error only occurs when
// CheckRedirect fails.
diff --git a/internal/agdhttp/url.go b/internal/agdhttp/url.go
index 7745036..d4c014c 100644
--- a/internal/agdhttp/url.go
+++ b/internal/agdhttp/url.go
@@ -5,51 +5,13 @@ import (
"net/url"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
)
-// Known scheme constants.
-//
-// TODO(a.garipov): Move to agdurl or golibs.
-//
-// TODO(a.garipov): Use more.
-const (
- SchemeFile = "file"
- SchemeGRPC = "grpc"
- SchemeGRPCS = "grpcs"
- SchemeHTTP = "http"
- SchemeHTTPS = "https"
-)
-
-// CheckGRPCURLScheme returns true if s is a valid gRPC URL scheme. That is,
-// [SchemeGRPC] or [SchemeGRPCS]
-//
-// TODO(a.garipov): Move to golibs?
-func CheckGRPCURLScheme(s string) (ok bool) {
- switch s {
- case SchemeGRPC, SchemeGRPCS:
- return true
- default:
- return false
- }
-}
-
-// CheckHTTPURLScheme returns true if s is a valid HTTP URL scheme. That is,
-// [SchemeHTTP] or [SchemeHTTPS]
-//
-// TODO(a.garipov): Move to golibs?
-func CheckHTTPURLScheme(s string) (ok bool) {
- switch s {
- case SchemeHTTP, SchemeHTTPS:
- return true
- default:
- return false
- }
-}
-
// ParseHTTPURL parses an absolute URL and makes sure that it is a valid HTTP(S)
// URL. All returned errors will have the underlying type [*url.Error].
//
-// TODO(a.garipov): Define as a type?
+// TODO(a.garipov): Define as a type?
func ParseHTTPURL(s string) (u *url.URL, err error) {
u, err = url.Parse(s)
if err != nil {
@@ -63,7 +25,7 @@ func ParseHTTPURL(s string) (u *url.URL, err error) {
URL: s,
Err: errors.Error("empty host"),
}
- case !CheckHTTPURLScheme(u.Scheme):
+ case !urlutil.IsValidHTTPURLScheme(u.Scheme):
return nil, &url.Error{
Op: "parse",
URL: s,
diff --git a/internal/agdhttp/url_test.go b/internal/agdhttp/url_test.go
index c9255f9..0694e67 100644
--- a/internal/agdhttp/url_test.go
+++ b/internal/agdhttp/url_test.go
@@ -6,12 +6,19 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
)
+// Common user credentials for tests.
+const (
+ testUsername = "user"
+ testPassword = "pass"
+)
+
func TestParseHTTPURL(t *testing.T) {
- goodURL := testURL()
+ goodURL := testURL(url.UserPassword(testUsername, testPassword))
badSchemeURL := netutil.CloneURL(goodURL)
badSchemeURL.Scheme = "ftp"
@@ -61,10 +68,11 @@ func TestParseHTTPURL(t *testing.T) {
}
}
-func testURL() (u *url.URL) {
+// testURL is a helper function that returns an url with dummy values.
+func testURL(info *url.Userinfo) (u *url.URL) {
return &url.URL{
- Scheme: agdhttp.SchemeHTTP,
- User: url.UserPassword("user", "pass"),
+ Scheme: urlutil.SchemeHTTP,
+ User: info,
Host: "example.com",
Path: "/a/b/c/",
RawQuery: "d=e",
diff --git a/internal/agdtest/agdtest.go b/internal/agdtest/agdtest.go
index 2364a84..6816907 100644
--- a/internal/agdtest/agdtest.go
+++ b/internal/agdtest/agdtest.go
@@ -3,6 +3,7 @@
package agdtest
import (
+ "net/url"
"testing"
"time"
@@ -18,7 +19,7 @@ const FilteredResponseTTL = FilteredResponseTTLSec * time.Second
// number to simplify message creation.
const FilteredResponseTTLSec = 10
-// NewConstructorWithTTL returns a standard dnsmsg.Constructor for tests, using
+// NewConstructorWithTTL returns a standard *dnsmsg.Constructor for tests, using
// ttl as the TTL for filtered responses.
func NewConstructorWithTTL(tb testing.TB, ttl time.Duration) (c *dnsmsg.Constructor) {
tb.Helper()
@@ -26,28 +27,57 @@ func NewConstructorWithTTL(tb testing.TB, ttl time.Duration) (c *dnsmsg.Construc
c, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
Cloner: NewCloner(),
BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ StructuredErrors: NewSDEConfig(true),
FilteredResponseTTL: ttl,
+ EDEEnabled: true,
})
require.NoError(tb, err)
return c
}
-// NewConstructor returns a standard dnsmsg.Constructor for tests, using
-// [FilteredResponseTTL] as the TTL for filtered responses.
+// NewConstructor returns a standard *dnsmsg.Constructor for tests, using
+// [FilteredResponseTTL] as the TTL for filtered responses. The returned
+// constructor also has the Structured DNS Errors feature enabled.
func NewConstructor(tb testing.TB) (c *dnsmsg.Constructor) {
tb.Helper()
c, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
Cloner: NewCloner(),
BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ StructuredErrors: NewSDEConfig(true),
FilteredResponseTTL: FilteredResponseTTL,
+ EDEEnabled: true,
})
require.NoError(tb, err)
return c
}
+// SDEText is a test Structured DNS Error text.
+//
+// NOTE: Keep in sync with [NewSDEConfig].
+//
+// TODO(e.burkov): Add some helper when this message becomes configurable.
+const SDEText = `{` +
+ `"j":"Filtering",` +
+ `"o":"Test Org",` +
+ `"c":["mailto:support@dns.example"]` +
+ `}`
+
+// NewSDEConfig returns a standard *dnsmsg.StructuredDNSErrorsConfig for tests.
+func NewSDEConfig(enabled bool) (c *dnsmsg.StructuredDNSErrorsConfig) {
+ return &dnsmsg.StructuredDNSErrorsConfig{
+ Contact: []*url.URL{{
+ Scheme: "mailto",
+ Opaque: "support@dns.example",
+ }},
+ Justification: "Filtering",
+ Organization: "Test Org",
+ Enabled: enabled,
+ }
+}
+
// NewCloner returns a standard dnsmsg.Cloner for tests.
func NewCloner() (c *dnsmsg.Cloner) {
return dnsmsg.NewCloner(dnsmsg.EmptyClonerStat{})
diff --git a/internal/agdtest/interface.go b/internal/agdtest/interface.go
index 93d9d5a..e492594 100644
--- a/internal/agdtest/interface.go
+++ b/internal/agdtest/interface.go
@@ -116,7 +116,7 @@ func (r *Refresher) Refresh(ctx context.Context) (err error) {
// type check
var _ billstat.Recorder = (*BillStatRecorder)(nil)
-// BillStatRecorder is a billstat.Recorder for tests.
+// BillStatRecorder is a [billstat.Recorder] for tests.
type BillStatRecorder struct {
OnRecord func(
ctx context.Context,
@@ -128,7 +128,7 @@ type BillStatRecorder struct {
)
}
-// Record implements the billstat.Recorder interface for *BillStatRecorder.
+// Record implements the [billstat.Recorder] interface for *BillStatRecorder.
func (r *BillStatRecorder) Record(
ctx context.Context,
id agd.DeviceID,
@@ -143,12 +143,12 @@ func (r *BillStatRecorder) Record(
// type check
var _ billstat.Uploader = (*BillStatUploader)(nil)
-// BillStatUploader is a billstat.Uploader for tests.
+// BillStatUploader is a [billstat.Uploader] for tests.
type BillStatUploader struct {
OnUpload func(ctx context.Context, records billstat.Records) (err error)
}
-// Upload implements the billstat.Uploader interface for *BillStatUploader.
+// Upload implements the [billstat.Uploader] interface for *BillStatUploader.
func (b *BillStatUploader) Upload(ctx context.Context, records billstat.Records) (err error) {
return b.OnUpload(ctx, records)
}
@@ -158,7 +158,7 @@ func (b *BillStatUploader) Upload(ctx context.Context, records billstat.Records)
// type check
var _ dnscheck.Interface = (*DNSCheck)(nil)
-// DNSCheck is a dnscheck.Interface for tests.
+// DNSCheck is a [dnscheck.Interface] for tests.
type DNSCheck struct {
OnCheck func(ctx context.Context, req *dns.Msg, ri *agd.RequestInfo) (reqp *dns.Msg, err error)
}
@@ -177,12 +177,12 @@ func (db *DNSCheck) Check(
// type check
var _ dnsdb.Interface = (*DNSDB)(nil)
-// DNSDB is a dnsdb.Interface for tests.
+// DNSDB is a [dnsdb.Interface] for tests.
type DNSDB struct {
OnRecord func(ctx context.Context, resp *dns.Msg, ri *agd.RequestInfo)
}
-// Record implements the dnsdb.Interface interface for *DNSDB.
+// Record implements the [dnsdb.Interface] interface for *DNSDB.
func (db *DNSDB) Record(ctx context.Context, resp *dns.Msg, ri *agd.RequestInfo) {
db.OnRecord(ctx, resp, ri)
}
@@ -204,7 +204,7 @@ func (c *ErrorCollector) Collect(ctx context.Context, err error) {
c.OnCollect(ctx, err)
}
-// NewErrorCollector returns a new [ErrorCollector] all methods of which panic.
+// NewErrorCollector returns a new *ErrorCollector all methods of which panic.
func NewErrorCollector() (c *ErrorCollector) {
return &ErrorCollector{
OnCollect: func(_ context.Context, err error) {
@@ -297,21 +297,38 @@ func (s *FilterStorage) HasListID(id agd.FilterListID) (ok bool) {
// type check
var _ geoip.Interface = (*GeoIP)(nil)
-// GeoIP is a geoip.Interface for tests.
+// GeoIP is a [geoip.Interface] for tests.
type GeoIP struct {
- OnSubnetByLocation func(l *geoip.Location, fam netutil.AddrFamily) (n netip.Prefix, err error)
OnData func(host string, ip netip.Addr) (l *geoip.Location, err error)
+ OnSubnetByLocation func(l *geoip.Location, fam netutil.AddrFamily) (n netip.Prefix, err error)
}
-// SubnetByLocation implements the geoip.Interface interface for *GeoIP.
-func (g *GeoIP) SubnetByLocation(l *geoip.Location, fam netutil.AddrFamily,
+// Data implements the [geoip.Interface] interface for *GeoIP.
+func (g *GeoIP) Data(host string, ip netip.Addr) (l *geoip.Location, err error) {
+ return g.OnData(host, ip)
+}
+
+// SubnetByLocation implements the [geoip.Interface] interface for *GeoIP.
+func (g *GeoIP) SubnetByLocation(
+ l *geoip.Location,
+ fam netutil.AddrFamily,
) (n netip.Prefix, err error) {
return g.OnSubnetByLocation(l, fam)
}
-// Data implements the geoip.Interface interface for *GeoIP.
-func (g *GeoIP) Data(host string, ip netip.Addr) (l *geoip.Location, err error) {
- return g.OnData(host, ip)
+// NewGeoIP returns a new *GeoIP all methods of which panic.
+func NewGeoIP() (c *GeoIP) {
+ return &GeoIP{
+ OnData: func(host string, ip netip.Addr) (l *geoip.Location, err error) {
+ panic(fmt.Errorf("unexpected call to GeoIP.Data(%v, %v)", host, ip))
+ },
+ OnSubnetByLocation: func(
+ l *geoip.Location,
+ fam netutil.AddrFamily,
+ ) (n netip.Prefix, err error) {
+ panic(fmt.Errorf("unexpected call to GeoIP.SubnetByLocation(%v, %v)", l, fam))
+ },
+ }
}
// Package profiledb
@@ -398,6 +415,58 @@ func (db *ProfileDB) ProfileByLinkedIP(
return db.OnProfileByLinkedIP(ctx, ip)
}
+// NewProfileDB returns a new *ProfileDB all methods of which panic.
+func NewProfileDB() (db *ProfileDB) {
+ return &ProfileDB{
+ OnCreateAutoDevice: func(
+ _ context.Context,
+ id agd.ProfileID,
+ humanID agd.HumanID,
+ devType agd.DeviceType,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic(fmt.Errorf(
+ "unexpected call to ProfileDB.CreateAutoDevice(%v, %v, %v)",
+ id,
+ humanID,
+ devType,
+ ))
+ },
+
+ OnProfileByDedicatedIP: func(
+ _ context.Context,
+ ip netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic(fmt.Errorf("unexpected call to ProfileDB.ProfileByDedicatedIP(%v)", ip))
+ },
+
+ OnProfileByDeviceID: func(
+ _ context.Context,
+ id agd.DeviceID,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic(fmt.Errorf("unexpected call to ProfileDB.ProfileByDeviceID(%v)", id))
+ },
+
+ OnProfileByHumanID: func(
+ _ context.Context,
+ profID agd.ProfileID,
+ humanID agd.HumanIDLower,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic(fmt.Errorf(
+ "unexpected call to ProfileDB.ProfileByHumanID(%v, %v)",
+ profID,
+ humanID,
+ ))
+ },
+
+ OnProfileByLinkedIP: func(
+ _ context.Context,
+ ip netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic(fmt.Errorf("unexpected call to ProfileDB.ProfileByLinkedIP(%v)", ip))
+ },
+ }
+}
+
// type check
var _ profiledb.Storage = (*ProfileStorage)(nil)
@@ -436,12 +505,12 @@ func (s *ProfileStorage) Profiles(
// type check
var _ querylog.Interface = (*QueryLog)(nil)
-// QueryLog is a querylog.Interface for tests.
+// QueryLog is a [querylog.Interface] for tests.
type QueryLog struct {
OnWrite func(ctx context.Context, e *querylog.Entry) (err error)
}
-// Write implements the querylog.Interface interface for *QueryLog.
+// Write implements the [querylog.Interface] interface for *QueryLog.
func (ql *QueryLog) Write(ctx context.Context, e *querylog.Entry) (err error) {
return ql.OnWrite(ctx, e)
}
@@ -451,12 +520,12 @@ func (ql *QueryLog) Write(ctx context.Context, e *querylog.Entry) (err error) {
// type check
var _ rulestat.Interface = (*RuleStat)(nil)
-// RuleStat is a rulestat.Interface for tests.
+// RuleStat is a [rulestat.Interface] for tests.
type RuleStat struct {
OnCollect func(ctx context.Context, id agd.FilterListID, text agd.FilterRuleText)
}
-// Collect implements the rulestat.Interface interface for *RuleStat.
+// Collect implements the [rulestat.Interface] interface for *RuleStat.
func (s *RuleStat) Collect(ctx context.Context, id agd.FilterListID, text agd.FilterRuleText) {
s.OnCollect(ctx, id, text)
}
@@ -501,7 +570,7 @@ func (c *ListenConfig) ListenPacket(
// type check
var _ ratelimit.Interface = (*RateLimit)(nil)
-// RateLimit is a ratelimit.Interface for tests.
+// RateLimit is a [ratelimit.Interface] for tests.
type RateLimit struct {
OnIsRateLimited func(
ctx context.Context,
@@ -511,7 +580,7 @@ type RateLimit struct {
OnCountResponses func(ctx context.Context, resp *dns.Msg, ip netip.Addr)
}
-// IsRateLimited implements the ratelimit.Interface interface for *RateLimit.
+// IsRateLimited implements the [ratelimit.Interface] interface for *RateLimit.
func (l *RateLimit) IsRateLimited(
ctx context.Context,
req *dns.Msg,
@@ -520,12 +589,27 @@ func (l *RateLimit) IsRateLimited(
return l.OnIsRateLimited(ctx, req, ip)
}
-// CountResponses implements the ratelimit.Interface interface for
-// *RateLimit.
+// CountResponses implements the [ratelimit.Interface] interface for *RateLimit.
func (l *RateLimit) CountResponses(ctx context.Context, req *dns.Msg, ip netip.Addr) {
l.OnCountResponses(ctx, req, ip)
}
+// NewRateLimit returns a new *RateLimit all methods of which panic.
+func NewRateLimit() (c *RateLimit) {
+ return &RateLimit{
+ OnIsRateLimited: func(
+ _ context.Context,
+ req *dns.Msg,
+ addr netip.Addr,
+ ) (shouldDrop, isAllowlisted bool, err error) {
+ panic(fmt.Errorf("unexpected call to RateLimit.IsRateLimited(%v, %v)", req, addr))
+ },
+ OnCountResponses: func(_ context.Context, resp *dns.Msg, addr netip.Addr) {
+ panic(fmt.Errorf("unexpected call to RateLimit.CountResponses(%v, %v)", resp, addr))
+ },
+ }
+}
+
// RemoteKV is an [remotekv.Interface] implementation for tests.
type RemoteKV struct {
OnGet func(ctx context.Context, key string) (val []byte, ok bool, err error)
diff --git a/internal/backendpb/backendpb.go b/internal/backendpb/backendpb.go
index 0173310..9b1fdd5 100644
--- a/internal/backendpb/backendpb.go
+++ b/internal/backendpb/backendpb.go
@@ -16,8 +16,8 @@ import (
"google.golang.org/grpc/metadata"
)
-// newClient returns new properly initialized DNSServiceClient.
-func newClient(apiURL *url.URL) (client DNSServiceClient, err error) {
+// newClient returns new properly initialized gRPC connection to the API server.
+func newClient(apiURL *url.URL) (client *grpc.ClientConn, err error) {
var creds credentials.TransportCredentials
switch s := apiURL.Scheme; s {
case "grpc":
@@ -38,7 +38,7 @@ func newClient(apiURL *url.URL) (client DNSServiceClient, err error) {
// called right before the initial refresh.
conn.Connect()
- return NewDNSServiceClient(conn), nil
+ return conn, nil
}
// reportf is a helper method for reporting non-critical errors.
diff --git a/internal/backendpb/backendpb_test.go b/internal/backendpb/backendpb_test.go
index 2f0d438..fe36a10 100644
--- a/internal/backendpb/backendpb_test.go
+++ b/internal/backendpb/backendpb_test.go
@@ -65,3 +65,39 @@ func (s *testDNSServiceServer) SaveDevicesBillingStat(
) (err error) {
return s.OnSaveDevicesBillingStat(srv)
}
+
+// testRemoteKVServiceServer is the [backendpb.RemoteKVServiceServer] for tests.
+type testRemoteKVServiceServer struct {
+ backendpb.UnimplementedRemoteKVServiceServer
+
+ OnGet func(
+ ctx context.Context,
+ req *backendpb.RemoteKVGetRequest,
+ ) (resp *backendpb.RemoteKVGetResponse, err error)
+
+ OnSet func(
+ ctx context.Context,
+ req *backendpb.RemoteKVSetRequest,
+ ) (resp *backendpb.RemoteKVSetResponse, err error)
+}
+
+// type check
+var _ backendpb.RemoteKVServiceServer = (*testRemoteKVServiceServer)(nil)
+
+// Get implements the [backendpb.RemoteKVServiceServer] interface for
+// *testRemoteKVServiceServer.
+func (s *testRemoteKVServiceServer) Get(
+ ctx context.Context,
+ req *backendpb.RemoteKVGetRequest,
+) (resp *backendpb.RemoteKVGetResponse, err error) {
+ return s.OnGet(ctx, req)
+}
+
+// Set implements the [backendpb.RemoteKVServiceServer] interface for
+// *testRemoteKVServiceServer.
+func (s *testRemoteKVServiceServer) Set(
+ ctx context.Context,
+ req *backendpb.RemoteKVSetRequest,
+) (resp *backendpb.RemoteKVSetResponse, err error) {
+ return s.OnSet(ctx, req)
+}
diff --git a/internal/backendpb/billstat.go b/internal/backendpb/billstat.go
index 18456e4..3547bed 100644
--- a/internal/backendpb/billstat.go
+++ b/internal/backendpb/billstat.go
@@ -42,7 +42,7 @@ func NewBillStat(c *BillStatConfig) (b *BillStat, err error) {
return &BillStat{
errColl: c.ErrColl,
metrics: c.Metrics,
- client: client,
+ client: NewDNSServiceClient(client),
apiKey: c.APIKey,
}, nil
}
diff --git a/internal/backendpb/dns.pb.go b/internal/backendpb/dns.pb.go
index f9f093b..aa71698 100644
--- a/internal/backendpb/dns.pb.go
+++ b/internal/backendpb/dns.pb.go
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.34.2
-// protoc v5.27.1
+// protoc-gen-go v1.35.1
+// protoc v5.28.3
// source: dns.proto
package backendpb
@@ -93,6 +93,87 @@ func (DeviceType) EnumDescriptor() ([]byte, []int) {
return file_dns_proto_rawDescGZIP(), []int{0}
}
+type RateLimitSettingsRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+}
+
+func (x *RateLimitSettingsRequest) Reset() {
+ *x = RateLimitSettingsRequest{}
+ mi := &file_dns_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RateLimitSettingsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RateLimitSettingsRequest) ProtoMessage() {}
+
+func (x *RateLimitSettingsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RateLimitSettingsRequest.ProtoReflect.Descriptor instead.
+func (*RateLimitSettingsRequest) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{0}
+}
+
+type RateLimitSettingsResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ AllowedSubnets []*CidrRange `protobuf:"bytes,1,rep,name=allowed_subnets,json=allowedSubnets,proto3" json:"allowed_subnets,omitempty"`
+}
+
+func (x *RateLimitSettingsResponse) Reset() {
+ *x = RateLimitSettingsResponse{}
+ mi := &file_dns_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RateLimitSettingsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RateLimitSettingsResponse) ProtoMessage() {}
+
+func (x *RateLimitSettingsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RateLimitSettingsResponse.ProtoReflect.Descriptor instead.
+func (*RateLimitSettingsResponse) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *RateLimitSettingsResponse) GetAllowedSubnets() []*CidrRange {
+ if x != nil {
+ return x.AllowedSubnets
+ }
+ return nil
+}
+
type DNSProfilesRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -103,11 +184,9 @@ type DNSProfilesRequest struct {
func (x *DNSProfilesRequest) Reset() {
*x = DNSProfilesRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *DNSProfilesRequest) String() string {
@@ -117,8 +196,8 @@ func (x *DNSProfilesRequest) String() string {
func (*DNSProfilesRequest) ProtoMessage() {}
func (x *DNSProfilesRequest) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[2]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -130,7 +209,7 @@ func (x *DNSProfilesRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use DNSProfilesRequest.ProtoReflect.Descriptor instead.
func (*DNSProfilesRequest) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{0}
+ return file_dns_proto_rawDescGZIP(), []int{2}
}
func (x *DNSProfilesRequest) GetSyncTime() *timestamppb.Timestamp {
@@ -172,11 +251,9 @@ type DNSProfile struct {
func (x *DNSProfile) Reset() {
*x = DNSProfile{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *DNSProfile) String() string {
@@ -186,8 +263,8 @@ func (x *DNSProfile) String() string {
func (*DNSProfile) ProtoMessage() {}
func (x *DNSProfile) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[1]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[3]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -199,7 +276,7 @@ func (x *DNSProfile) ProtoReflect() protoreflect.Message {
// Deprecated: Use DNSProfile.ProtoReflect.Descriptor instead.
func (*DNSProfile) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{1}
+ return file_dns_proto_rawDescGZIP(), []int{3}
}
func (x *DNSProfile) GetDnsId() string {
@@ -389,11 +466,9 @@ type SafeBrowsingSettings struct {
func (x *SafeBrowsingSettings) Reset() {
*x = SafeBrowsingSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *SafeBrowsingSettings) String() string {
@@ -403,8 +478,8 @@ func (x *SafeBrowsingSettings) String() string {
func (*SafeBrowsingSettings) ProtoMessage() {}
func (x *SafeBrowsingSettings) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[2]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[4]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -416,7 +491,7 @@ func (x *SafeBrowsingSettings) ProtoReflect() protoreflect.Message {
// Deprecated: Use SafeBrowsingSettings.ProtoReflect.Descriptor instead.
func (*SafeBrowsingSettings) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{2}
+ return file_dns_proto_rawDescGZIP(), []int{4}
}
func (x *SafeBrowsingSettings) GetEnabled() bool {
@@ -457,11 +532,9 @@ type DeviceSettings struct {
func (x *DeviceSettings) Reset() {
*x = DeviceSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[3]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *DeviceSettings) String() string {
@@ -471,8 +544,8 @@ func (x *DeviceSettings) String() string {
func (*DeviceSettings) ProtoMessage() {}
func (x *DeviceSettings) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[3]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[5]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -484,7 +557,7 @@ func (x *DeviceSettings) ProtoReflect() protoreflect.Message {
// Deprecated: Use DeviceSettings.ProtoReflect.Descriptor instead.
func (*DeviceSettings) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{3}
+ return file_dns_proto_rawDescGZIP(), []int{5}
}
func (x *DeviceSettings) GetId() string {
@@ -551,11 +624,9 @@ type ParentalSettings struct {
func (x *ParentalSettings) Reset() {
*x = ParentalSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[4]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *ParentalSettings) String() string {
@@ -565,8 +636,8 @@ func (x *ParentalSettings) String() string {
func (*ParentalSettings) ProtoMessage() {}
func (x *ParentalSettings) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[4]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[6]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -578,7 +649,7 @@ func (x *ParentalSettings) ProtoReflect() protoreflect.Message {
// Deprecated: Use ParentalSettings.ProtoReflect.Descriptor instead.
func (*ParentalSettings) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{4}
+ return file_dns_proto_rawDescGZIP(), []int{6}
}
func (x *ParentalSettings) GetEnabled() bool {
@@ -634,11 +705,9 @@ type ScheduleSettings struct {
func (x *ScheduleSettings) Reset() {
*x = ScheduleSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[5]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *ScheduleSettings) String() string {
@@ -648,8 +717,8 @@ func (x *ScheduleSettings) String() string {
func (*ScheduleSettings) ProtoMessage() {}
func (x *ScheduleSettings) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[5]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[7]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -661,7 +730,7 @@ func (x *ScheduleSettings) ProtoReflect() protoreflect.Message {
// Deprecated: Use ScheduleSettings.ProtoReflect.Descriptor instead.
func (*ScheduleSettings) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{5}
+ return file_dns_proto_rawDescGZIP(), []int{7}
}
func (x *ScheduleSettings) GetTmz() string {
@@ -694,11 +763,9 @@ type WeeklyRange struct {
func (x *WeeklyRange) Reset() {
*x = WeeklyRange{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[6]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *WeeklyRange) String() string {
@@ -708,8 +775,8 @@ func (x *WeeklyRange) String() string {
func (*WeeklyRange) ProtoMessage() {}
func (x *WeeklyRange) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[6]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[8]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -721,7 +788,7 @@ func (x *WeeklyRange) ProtoReflect() protoreflect.Message {
// Deprecated: Use WeeklyRange.ProtoReflect.Descriptor instead.
func (*WeeklyRange) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{6}
+ return file_dns_proto_rawDescGZIP(), []int{8}
}
func (x *WeeklyRange) GetMon() *DayRange {
@@ -784,11 +851,9 @@ type DayRange struct {
func (x *DayRange) Reset() {
*x = DayRange{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[7]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *DayRange) String() string {
@@ -798,8 +863,8 @@ func (x *DayRange) String() string {
func (*DayRange) ProtoMessage() {}
func (x *DayRange) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[7]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[9]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -811,7 +876,7 @@ func (x *DayRange) ProtoReflect() protoreflect.Message {
// Deprecated: Use DayRange.ProtoReflect.Descriptor instead.
func (*DayRange) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{7}
+ return file_dns_proto_rawDescGZIP(), []int{9}
}
func (x *DayRange) GetStart() *durationpb.Duration {
@@ -839,11 +904,9 @@ type RuleListsSettings struct {
func (x *RuleListsSettings) Reset() {
*x = RuleListsSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[8]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *RuleListsSettings) String() string {
@@ -853,8 +916,8 @@ func (x *RuleListsSettings) String() string {
func (*RuleListsSettings) ProtoMessage() {}
func (x *RuleListsSettings) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[8]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[10]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -866,7 +929,7 @@ func (x *RuleListsSettings) ProtoReflect() protoreflect.Message {
// Deprecated: Use RuleListsSettings.ProtoReflect.Descriptor instead.
func (*RuleListsSettings) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{8}
+ return file_dns_proto_rawDescGZIP(), []int{10}
}
func (x *RuleListsSettings) GetEnabled() bool {
@@ -894,11 +957,9 @@ type BlockingModeCustomIP struct {
func (x *BlockingModeCustomIP) Reset() {
*x = BlockingModeCustomIP{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[9]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *BlockingModeCustomIP) String() string {
@@ -908,8 +969,8 @@ func (x *BlockingModeCustomIP) String() string {
func (*BlockingModeCustomIP) ProtoMessage() {}
func (x *BlockingModeCustomIP) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[9]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[11]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -921,7 +982,7 @@ func (x *BlockingModeCustomIP) ProtoReflect() protoreflect.Message {
// Deprecated: Use BlockingModeCustomIP.ProtoReflect.Descriptor instead.
func (*BlockingModeCustomIP) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{9}
+ return file_dns_proto_rawDescGZIP(), []int{11}
}
func (x *BlockingModeCustomIP) GetIpv4() []byte {
@@ -946,11 +1007,9 @@ type BlockingModeNXDOMAIN struct {
func (x *BlockingModeNXDOMAIN) Reset() {
*x = BlockingModeNXDOMAIN{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[10]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *BlockingModeNXDOMAIN) String() string {
@@ -960,8 +1019,8 @@ func (x *BlockingModeNXDOMAIN) String() string {
func (*BlockingModeNXDOMAIN) ProtoMessage() {}
func (x *BlockingModeNXDOMAIN) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[10]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[12]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -973,7 +1032,7 @@ func (x *BlockingModeNXDOMAIN) ProtoReflect() protoreflect.Message {
// Deprecated: Use BlockingModeNXDOMAIN.ProtoReflect.Descriptor instead.
func (*BlockingModeNXDOMAIN) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{10}
+ return file_dns_proto_rawDescGZIP(), []int{12}
}
type BlockingModeNullIP struct {
@@ -984,11 +1043,9 @@ type BlockingModeNullIP struct {
func (x *BlockingModeNullIP) Reset() {
*x = BlockingModeNullIP{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[11]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *BlockingModeNullIP) String() string {
@@ -998,8 +1055,8 @@ func (x *BlockingModeNullIP) String() string {
func (*BlockingModeNullIP) ProtoMessage() {}
func (x *BlockingModeNullIP) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[11]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[13]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1011,7 +1068,7 @@ func (x *BlockingModeNullIP) ProtoReflect() protoreflect.Message {
// Deprecated: Use BlockingModeNullIP.ProtoReflect.Descriptor instead.
func (*BlockingModeNullIP) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{11}
+ return file_dns_proto_rawDescGZIP(), []int{13}
}
type BlockingModeREFUSED struct {
@@ -1022,11 +1079,9 @@ type BlockingModeREFUSED struct {
func (x *BlockingModeREFUSED) Reset() {
*x = BlockingModeREFUSED{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[12]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *BlockingModeREFUSED) String() string {
@@ -1036,8 +1091,8 @@ func (x *BlockingModeREFUSED) String() string {
func (*BlockingModeREFUSED) ProtoMessage() {}
func (x *BlockingModeREFUSED) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[12]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[14]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1049,7 +1104,7 @@ func (x *BlockingModeREFUSED) ProtoReflect() protoreflect.Message {
// Deprecated: Use BlockingModeREFUSED.ProtoReflect.Descriptor instead.
func (*BlockingModeREFUSED) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{12}
+ return file_dns_proto_rawDescGZIP(), []int{14}
}
type DeviceBillingStat struct {
@@ -1068,11 +1123,9 @@ type DeviceBillingStat struct {
func (x *DeviceBillingStat) Reset() {
*x = DeviceBillingStat{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[13]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[15]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *DeviceBillingStat) String() string {
@@ -1082,8 +1135,8 @@ func (x *DeviceBillingStat) String() string {
func (*DeviceBillingStat) ProtoMessage() {}
func (x *DeviceBillingStat) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[13]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[15]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1095,7 +1148,7 @@ func (x *DeviceBillingStat) ProtoReflect() protoreflect.Message {
// Deprecated: Use DeviceBillingStat.ProtoReflect.Descriptor instead.
func (*DeviceBillingStat) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{13}
+ return file_dns_proto_rawDescGZIP(), []int{15}
}
func (x *DeviceBillingStat) GetLastActivityTime() *timestamppb.Timestamp {
@@ -1155,11 +1208,9 @@ type AccessSettings struct {
func (x *AccessSettings) Reset() {
*x = AccessSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[14]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[16]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *AccessSettings) String() string {
@@ -1169,8 +1220,8 @@ func (x *AccessSettings) String() string {
func (*AccessSettings) ProtoMessage() {}
func (x *AccessSettings) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[14]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[16]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1182,7 +1233,7 @@ func (x *AccessSettings) ProtoReflect() protoreflect.Message {
// Deprecated: Use AccessSettings.ProtoReflect.Descriptor instead.
func (*AccessSettings) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{14}
+ return file_dns_proto_rawDescGZIP(), []int{16}
}
func (x *AccessSettings) GetAllowlistCidr() []*CidrRange {
@@ -1238,11 +1289,9 @@ type CidrRange struct {
func (x *CidrRange) Reset() {
*x = CidrRange{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[15]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[17]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *CidrRange) String() string {
@@ -1252,8 +1301,8 @@ func (x *CidrRange) String() string {
func (*CidrRange) ProtoMessage() {}
func (x *CidrRange) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[15]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[17]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1265,7 +1314,7 @@ func (x *CidrRange) ProtoReflect() protoreflect.Message {
// Deprecated: Use CidrRange.ProtoReflect.Descriptor instead.
func (*CidrRange) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{15}
+ return file_dns_proto_rawDescGZIP(), []int{17}
}
func (x *CidrRange) GetAddress() []byte {
@@ -1296,11 +1345,9 @@ type AuthenticationSettings struct {
func (x *AuthenticationSettings) Reset() {
*x = AuthenticationSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[16]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[18]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *AuthenticationSettings) String() string {
@@ -1310,8 +1357,8 @@ func (x *AuthenticationSettings) String() string {
func (*AuthenticationSettings) ProtoMessage() {}
func (x *AuthenticationSettings) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[16]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[18]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1323,7 +1370,7 @@ func (x *AuthenticationSettings) ProtoReflect() protoreflect.Message {
// Deprecated: Use AuthenticationSettings.ProtoReflect.Descriptor instead.
func (*AuthenticationSettings) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{16}
+ return file_dns_proto_rawDescGZIP(), []int{18}
}
func (x *AuthenticationSettings) GetDohAuthOnly() bool {
@@ -1369,11 +1416,9 @@ type CreateDeviceRequest struct {
func (x *CreateDeviceRequest) Reset() {
*x = CreateDeviceRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[17]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[19]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *CreateDeviceRequest) String() string {
@@ -1383,8 +1428,8 @@ func (x *CreateDeviceRequest) String() string {
func (*CreateDeviceRequest) ProtoMessage() {}
func (x *CreateDeviceRequest) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[17]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[19]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1396,7 +1441,7 @@ func (x *CreateDeviceRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use CreateDeviceRequest.ProtoReflect.Descriptor instead.
func (*CreateDeviceRequest) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{17}
+ return file_dns_proto_rawDescGZIP(), []int{19}
}
func (x *CreateDeviceRequest) GetDnsId() string {
@@ -1430,11 +1475,9 @@ type CreateDeviceResponse struct {
func (x *CreateDeviceResponse) Reset() {
*x = CreateDeviceResponse{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[18]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[20]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *CreateDeviceResponse) String() string {
@@ -1444,8 +1487,8 @@ func (x *CreateDeviceResponse) String() string {
func (*CreateDeviceResponse) ProtoMessage() {}
func (x *CreateDeviceResponse) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[18]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[20]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1457,7 +1500,7 @@ func (x *CreateDeviceResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use CreateDeviceResponse.ProtoReflect.Descriptor instead.
func (*CreateDeviceResponse) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{18}
+ return file_dns_proto_rawDescGZIP(), []int{20}
}
func (x *CreateDeviceResponse) GetDevice() *DeviceSettings {
@@ -1478,11 +1521,9 @@ type RateLimitedError struct {
func (x *RateLimitedError) Reset() {
*x = RateLimitedError{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[19]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[21]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *RateLimitedError) String() string {
@@ -1492,8 +1533,8 @@ func (x *RateLimitedError) String() string {
func (*RateLimitedError) ProtoMessage() {}
func (x *RateLimitedError) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[19]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[21]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1505,7 +1546,7 @@ func (x *RateLimitedError) ProtoReflect() protoreflect.Message {
// Deprecated: Use RateLimitedError.ProtoReflect.Descriptor instead.
func (*RateLimitedError) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{19}
+ return file_dns_proto_rawDescGZIP(), []int{21}
}
func (x *RateLimitedError) GetMessage() string {
@@ -1532,11 +1573,9 @@ type DeviceQuotaExceededError struct {
func (x *DeviceQuotaExceededError) Reset() {
*x = DeviceQuotaExceededError{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[20]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[22]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *DeviceQuotaExceededError) String() string {
@@ -1546,8 +1585,8 @@ func (x *DeviceQuotaExceededError) String() string {
func (*DeviceQuotaExceededError) ProtoMessage() {}
func (x *DeviceQuotaExceededError) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[20]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[22]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1559,7 +1598,7 @@ func (x *DeviceQuotaExceededError) ProtoReflect() protoreflect.Message {
// Deprecated: Use DeviceQuotaExceededError.ProtoReflect.Descriptor instead.
func (*DeviceQuotaExceededError) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{20}
+ return file_dns_proto_rawDescGZIP(), []int{22}
}
func (x *DeviceQuotaExceededError) GetMessage() string {
@@ -1579,11 +1618,9 @@ type BadRequestError struct {
func (x *BadRequestError) Reset() {
*x = BadRequestError{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[21]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[23]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *BadRequestError) String() string {
@@ -1593,8 +1630,8 @@ func (x *BadRequestError) String() string {
func (*BadRequestError) ProtoMessage() {}
func (x *BadRequestError) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[21]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[23]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1606,7 +1643,7 @@ func (x *BadRequestError) ProtoReflect() protoreflect.Message {
// Deprecated: Use BadRequestError.ProtoReflect.Descriptor instead.
func (*BadRequestError) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{21}
+ return file_dns_proto_rawDescGZIP(), []int{23}
}
func (x *BadRequestError) GetMessage() string {
@@ -1626,11 +1663,9 @@ type AuthenticationFailedError struct {
func (x *AuthenticationFailedError) Reset() {
*x = AuthenticationFailedError{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[22]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[24]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *AuthenticationFailedError) String() string {
@@ -1640,8 +1675,8 @@ func (x *AuthenticationFailedError) String() string {
func (*AuthenticationFailedError) ProtoMessage() {}
func (x *AuthenticationFailedError) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[22]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[24]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1653,7 +1688,7 @@ func (x *AuthenticationFailedError) ProtoReflect() protoreflect.Message {
// Deprecated: Use AuthenticationFailedError.ProtoReflect.Descriptor instead.
func (*AuthenticationFailedError) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{22}
+ return file_dns_proto_rawDescGZIP(), []int{24}
}
func (x *AuthenticationFailedError) GetMessage() string {
@@ -1675,11 +1710,9 @@ type RateLimitSettings struct {
func (x *RateLimitSettings) Reset() {
*x = RateLimitSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_dns_proto_msgTypes[23]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_dns_proto_msgTypes[25]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *RateLimitSettings) String() string {
@@ -1689,8 +1722,8 @@ func (x *RateLimitSettings) String() string {
func (*RateLimitSettings) ProtoMessage() {}
func (x *RateLimitSettings) ProtoReflect() protoreflect.Message {
- mi := &file_dns_proto_msgTypes[23]
- if protoimpl.UnsafeEnabled && x != nil {
+ mi := &file_dns_proto_msgTypes[25]
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1702,7 +1735,7 @@ func (x *RateLimitSettings) ProtoReflect() protoreflect.Message {
// Deprecated: Use RateLimitSettings.ProtoReflect.Descriptor instead.
func (*RateLimitSettings) Descriptor() ([]byte, []int) {
- return file_dns_proto_rawDescGZIP(), []int{23}
+ return file_dns_proto_rawDescGZIP(), []int{25}
}
func (x *RateLimitSettings) GetEnabled() bool {
@@ -1726,6 +1759,227 @@ func (x *RateLimitSettings) GetClientCidr() []*CidrRange {
return nil
}
+type RemoteKVGetRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
+}
+
+func (x *RemoteKVGetRequest) Reset() {
+ *x = RemoteKVGetRequest{}
+ mi := &file_dns_proto_msgTypes[26]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoteKVGetRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoteKVGetRequest) ProtoMessage() {}
+
+func (x *RemoteKVGetRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[26]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RemoteKVGetRequest.ProtoReflect.Descriptor instead.
+func (*RemoteKVGetRequest) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{26}
+}
+
+func (x *RemoteKVGetRequest) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+type RemoteKVGetResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Types that are assignable to Value:
+ //
+ // *RemoteKVGetResponse_Data
+ // *RemoteKVGetResponse_Empty
+ Value isRemoteKVGetResponse_Value `protobuf_oneof:"value"`
+}
+
+func (x *RemoteKVGetResponse) Reset() {
+ *x = RemoteKVGetResponse{}
+ mi := &file_dns_proto_msgTypes[27]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoteKVGetResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoteKVGetResponse) ProtoMessage() {}
+
+func (x *RemoteKVGetResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[27]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RemoteKVGetResponse.ProtoReflect.Descriptor instead.
+func (*RemoteKVGetResponse) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{27}
+}
+
+func (m *RemoteKVGetResponse) GetValue() isRemoteKVGetResponse_Value {
+ if m != nil {
+ return m.Value
+ }
+ return nil
+}
+
+func (x *RemoteKVGetResponse) GetData() []byte {
+ if x, ok := x.GetValue().(*RemoteKVGetResponse_Data); ok {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *RemoteKVGetResponse) GetEmpty() *emptypb.Empty {
+ if x, ok := x.GetValue().(*RemoteKVGetResponse_Empty); ok {
+ return x.Empty
+ }
+ return nil
+}
+
+type isRemoteKVGetResponse_Value interface {
+ isRemoteKVGetResponse_Value()
+}
+
+type RemoteKVGetResponse_Data struct {
+ Data []byte `protobuf:"bytes,1,opt,name=data,proto3,oneof"`
+}
+
+type RemoteKVGetResponse_Empty struct {
+ Empty *emptypb.Empty `protobuf:"bytes,2,opt,name=empty,proto3,oneof"`
+}
+
+func (*RemoteKVGetResponse_Data) isRemoteKVGetResponse_Value() {}
+
+func (*RemoteKVGetResponse_Empty) isRemoteKVGetResponse_Value() {}
+
+type RemoteKVSetRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+ Ttl *durationpb.Duration `protobuf:"bytes,3,opt,name=ttl,proto3" json:"ttl,omitempty"`
+}
+
+func (x *RemoteKVSetRequest) Reset() {
+ *x = RemoteKVSetRequest{}
+ mi := &file_dns_proto_msgTypes[28]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoteKVSetRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoteKVSetRequest) ProtoMessage() {}
+
+func (x *RemoteKVSetRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[28]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RemoteKVSetRequest.ProtoReflect.Descriptor instead.
+func (*RemoteKVSetRequest) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{28}
+}
+
+func (x *RemoteKVSetRequest) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+func (x *RemoteKVSetRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *RemoteKVSetRequest) GetTtl() *durationpb.Duration {
+ if x != nil {
+ return x.Ttl
+ }
+ return nil
+}
+
+type RemoteKVSetResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+}
+
+func (x *RemoteKVSetResponse) Reset() {
+ *x = RemoteKVSetResponse{}
+ mi := &file_dns_proto_msgTypes[29]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoteKVSetResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoteKVSetResponse) ProtoMessage() {}
+
+func (x *RemoteKVSetResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[29]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RemoteKVSetResponse.ProtoReflect.Descriptor instead.
+func (*RemoteKVSetResponse) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{29}
+}
+
var File_dns_proto protoreflect.FileDescriptor
var file_dns_proto_rawDesc = []byte{
@@ -1735,264 +1989,301 @@ var file_dns_proto_rawDesc = []byte{
0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d,
- 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4d, 0x0a, 0x12, 0x44, 0x4e, 0x53,
- 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x37, 0x0a, 0x09, 0x73, 0x79, 0x6e, 0x63, 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, 0x08,
- 0x73, 0x79, 0x6e, 0x63, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xad, 0x08, 0x0a, 0x0a, 0x44, 0x4e, 0x53,
- 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x6e, 0x73, 0x5f, 0x69,
- 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x6e, 0x73, 0x49, 0x64, 0x12, 0x2b,
- 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62,
- 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x74, 0x65,
- 0x72, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x71,
- 0x75, 0x65, 0x72, 0x79, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x6f, 0x67,
- 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74,
- 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65,
- 0x64, 0x12, 0x3a, 0x0a, 0x0d, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x69,
- 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x53, 0x61, 0x66, 0x65, 0x42,
- 0x72, 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52,
- 0x0c, 0x73, 0x61, 0x66, 0x65, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 0x12, 0x2d, 0x0a,
- 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x11, 0x2e, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
- 0x67, 0x73, 0x52, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x12, 0x31, 0x0a, 0x0a,
- 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x12, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x53, 0x65, 0x74, 0x74,
- 0x69, 0x6e, 0x67, 0x73, 0x52, 0x09, 0x72, 0x75, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x12,
- 0x29, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b,
- 0x32, 0x0f, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
- 0x73, 0x52, 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75,
- 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09,
- 0x52, 0x0b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x4d, 0x0a,
- 0x15, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x5f, 0x74, 0x74, 0x6c, 0x18, 0x0a, 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, 0x13, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65,
- 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x74, 0x6c, 0x12, 0x2e, 0x0a, 0x13,
- 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x65,
- 0x6c, 0x61, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
- 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x30, 0x0a, 0x14,
- 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x69, 0x72, 0x65, 0x66, 0x6f, 0x78, 0x5f, 0x63, 0x61,
- 0x6e, 0x61, 0x72, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63,
- 0x6b, 0x46, 0x69, 0x72, 0x65, 0x66, 0x6f, 0x78, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x12, 0x4e,
- 0x0a, 0x17, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f,
- 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x69, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x15, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x75,
- 0x73, 0x74, 0x6f, 0x6d, 0x49, 0x50, 0x48, 0x00, 0x52, 0x14, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69,
- 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x49, 0x70, 0x12, 0x4d,
- 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f,
- 0x6e, 0x78, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15,
- 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x58, 0x44,
- 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x48, 0x00, 0x52, 0x14, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e,
- 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x78, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x48, 0x0a,
- 0x15, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x6e,
- 0x75, 0x6c, 0x6c, 0x5f, 0x69, 0x70, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x42,
- 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x75, 0x6c, 0x6c, 0x49,
- 0x50, 0x48, 0x00, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64,
- 0x65, 0x4e, 0x75, 0x6c, 0x6c, 0x49, 0x70, 0x12, 0x4a, 0x0a, 0x15, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
- 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64,
- 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e,
- 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x45, 0x46, 0x55, 0x53, 0x45, 0x44, 0x48, 0x00, 0x52, 0x13,
- 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x66, 0x75,
- 0x73, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x69, 0x70, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e,
- 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x70, 0x4c,
- 0x6f, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x27, 0x0a, 0x06, 0x61, 0x63, 0x63,
- 0x65, 0x73, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x41, 0x63, 0x63, 0x65,
- 0x73, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65,
- 0x73, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63,
- 0x65, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08,
- 0x52, 0x12, 0x61, 0x75, 0x74, 0x6f, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x61,
- 0x62, 0x6c, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6d,
- 0x69, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c,
- 0x69, 0x6d, 0x69, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x09, 0x72, 0x61,
- 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
- 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x14, 0x53, 0x61, 0x66,
- 0x65, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 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, 0x36, 0x0a, 0x17, 0x62,
- 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x64, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x6f, 0x75, 0x73, 0x5f, 0x64,
- 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x62, 0x6c,
- 0x6f, 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, 0x8a, 0x02, 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, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01,
- 0x28, 0x08, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61,
- 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x5f, 0x69,
- 0x70, 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, 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, 0x12, 0x24, 0x0a, 0x0e, 0x68, 0x75, 0x6d, 0x61, 0x6e,
- 0x5f, 0x69, 0x64, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x0c, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x49, 0x64, 0x4c, 0x6f, 0x77, 0x65, 0x72, 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, 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, 0x03, 0x65,
- 0x6e, 0x64, 0x22, 0x3f, 0x0a, 0x11, 0x52, 0x75, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x53,
+ 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1a, 0x0a, 0x18, 0x52, 0x61, 0x74,
+ 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x50, 0x0a, 0x19, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d,
+ 0x69, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x73, 0x75,
+ 0x62, 0x6e, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x69,
+ 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64,
+ 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x22, 0x4d, 0x0a, 0x12, 0x44, 0x4e, 0x53, 0x50, 0x72,
+ 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x37, 0x0a,
+ 0x09, 0x73, 0x79, 0x6e, 0x63, 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, 0x08, 0x73, 0x79,
+ 0x6e, 0x63, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xad, 0x08, 0x0a, 0x0a, 0x44, 0x4e, 0x53, 0x50, 0x72,
+ 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x6e, 0x73, 0x5f, 0x69, 0x64, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x6e, 0x73, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11,
+ 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
+ 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69,
+ 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x71, 0x75, 0x65,
+ 0x72, 0x79, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x6f, 0x67, 0x45, 0x6e,
+ 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12,
+ 0x3a, 0x0a, 0x0d, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67,
+ 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x53, 0x61, 0x66, 0x65, 0x42, 0x72, 0x6f,
+ 0x77, 0x73, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0c, 0x73,
+ 0x61, 0x66, 0x65, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 0x12, 0x2d, 0x0a, 0x08, 0x70,
+ 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e,
+ 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
+ 0x52, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x12, 0x31, 0x0a, 0x0a, 0x72, 0x75,
+ 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12,
+ 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
+ 0x67, 0x73, 0x52, 0x09, 0x72, 0x75, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x12, 0x29, 0x0a,
+ 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f,
+ 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52,
+ 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x73, 0x74,
+ 0x6f, 0x6d, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b,
+ 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x4d, 0x0a, 0x15, 0x66,
+ 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x5f, 0x74, 0x74, 0x6c, 0x18, 0x0a, 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, 0x13, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x74, 0x6c, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x6c,
+ 0x6f, 0x63, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x65, 0x6c, 0x61,
+ 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x50, 0x72,
+ 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x62, 0x6c,
+ 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x69, 0x72, 0x65, 0x66, 0x6f, 0x78, 0x5f, 0x63, 0x61, 0x6e, 0x61,
+ 0x72, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x46,
+ 0x69, 0x72, 0x65, 0x66, 0x6f, 0x78, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x12, 0x4e, 0x0a, 0x17,
+ 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x75,
+ 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x69, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e,
+ 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x75, 0x73, 0x74,
+ 0x6f, 0x6d, 0x49, 0x50, 0x48, 0x00, 0x52, 0x14, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67,
+ 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x49, 0x70, 0x12, 0x4d, 0x0a, 0x16,
+ 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x78,
+ 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x42,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x58, 0x44, 0x4f, 0x4d,
+ 0x41, 0x49, 0x4e, 0x48, 0x00, 0x52, 0x14, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d,
+ 0x6f, 0x64, 0x65, 0x4e, 0x78, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x48, 0x0a, 0x15, 0x62,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x75, 0x6c,
+ 0x6c, 0x5f, 0x69, 0x70, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x42, 0x6c, 0x6f,
+ 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x75, 0x6c, 0x6c, 0x49, 0x50, 0x48,
+ 0x00, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e,
+ 0x75, 0x6c, 0x6c, 0x49, 0x70, 0x12, 0x4a, 0x0a, 0x15, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e,
+ 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x18, 0x10,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d,
+ 0x6f, 0x64, 0x65, 0x52, 0x45, 0x46, 0x55, 0x53, 0x45, 0x44, 0x48, 0x00, 0x52, 0x13, 0x62, 0x6c,
+ 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x66, 0x75, 0x73, 0x65,
+ 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x69, 0x70, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62,
+ 0x6c, 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x70, 0x4c, 0x6f, 0x67,
+ 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x27, 0x0a, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73,
+ 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
+ 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73,
+ 0x12, 0x30, 0x0a, 0x14, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73,
+ 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12,
+ 0x61, 0x75, 0x74, 0x6f, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c,
+ 0x65, 0x64, 0x12, 0x31, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74,
+ 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d,
+ 0x69, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x09, 0x72, 0x61, 0x74, 0x65,
+ 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e,
+ 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x14, 0x53, 0x61, 0x66, 0x65, 0x42,
+ 0x72, 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 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, 0x36, 0x0a, 0x17, 0x62, 0x6c, 0x6f,
+ 0x63, 0x6b, 0x5f, 0x64, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x6f, 0x75, 0x73, 0x5f, 0x64, 0x6f, 0x6d,
+ 0x61, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x62, 0x6c, 0x6f, 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, 0x8a,
+ 0x02, 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, 0x69,
+ 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x10, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c,
+ 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x5f, 0x69, 0x70, 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, 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, 0x12, 0x24, 0x0a, 0x0e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x5f, 0x69,
+ 0x64, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x68,
+ 0x75, 0x6d, 0x61, 0x6e, 0x49, 0x64, 0x4c, 0x6f, 0x77, 0x65, 0x72, 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, 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, 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, 0x22, 0x75, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
+ 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a,
+ 0x06, 0x64, 0x6e, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64,
+ 0x6e, 0x73, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x5f, 0x69, 0x64,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x49, 0x64, 0x12,
+ 0x2c, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70,
+ 0x65, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3f, 0x0a,
+ 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65,
+ 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x68,
+ 0x0a, 0x10, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x45, 0x72, 0x72,
+ 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x0b,
+ 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 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, 0x0a, 0x72, 0x65,
+ 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x22, 0x34, 0x0a, 0x18, 0x44, 0x65, 0x76, 0x69,
+ 0x63, 0x65, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x45,
+ 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2b,
+ 0x0a, 0x0f, 0x42, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f,
+ 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x35, 0x0a, 0x19, 0x41,
+ 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x61, 0x69,
+ 0x6c, 0x65, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73,
+ 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61,
+ 0x67, 0x65, 0x22, 0x6c, 0x0a, 0x11, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 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, 0x22, 0x75, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61,
- 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x15, 0x0a, 0x06, 0x64, 0x6e, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x05, 0x64, 0x6e, 0x73, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x5f,
- 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x49,
- 0x64, 0x12, 0x2c, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54,
- 0x79, 0x70, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22,
- 0x3f, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63,
- 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
- 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
- 0x22, 0x68, 0x0a, 0x10, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x45,
- 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a,
- 0x0a, 0x0b, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 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, 0x0a,
- 0x72, 0x65, 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x22, 0x34, 0x0a, 0x18, 0x44, 0x65,
- 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65,
- 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
- 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
- 0x22, 0x2b, 0x0a, 0x0f, 0x42, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x72,
- 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x35, 0x0a,
- 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46,
- 0x61, 0x69, 0x6c, 0x65, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65,
- 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73,
- 0x73, 0x61, 0x67, 0x65, 0x22, 0x6c, 0x0a, 0x11, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69,
- 0x74, 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, 0x72, 0x70, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
- 0x52, 0x03, 0x72, 0x70, 0x73, 0x12, 0x2b, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f,
- 0x63, 0x69, 0x64, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x69, 0x64,
- 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x69,
- 0x64, 0x72, 0x2a, 0x87, 0x01, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70,
- 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0b,
- 0x0a, 0x07, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x41,
- 0x4e, 0x44, 0x52, 0x4f, 0x49, 0x44, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x41, 0x43, 0x10,
- 0x03, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4f, 0x53, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x49,
- 0x4e, 0x55, 0x58, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x52, 0x10,
- 0x06, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x5f, 0x54, 0x56, 0x10, 0x07, 0x12,
- 0x10, 0x0a, 0x0c, 0x47, 0x41, 0x4d, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, 0x45, 0x10,
- 0x08, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x09, 0x32, 0xd0, 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, 0x12, 0x44, 0x0a, 0x15, 0x63, 0x72, 0x65,
- 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x79, 0x48, 0x75, 0x6d, 0x61, 0x6e,
- 0x49, 0x64, 0x12, 0x14, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63,
- 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
- 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 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,
+ 0x64, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x70, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03,
+ 0x72, 0x70, 0x73, 0x12, 0x2b, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x69,
+ 0x64, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52,
+ 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x69, 0x64, 0x72,
+ 0x22, 0x26, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x47, 0x65, 0x74, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x64, 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f,
+ 0x74, 0x65, 0x4b, 0x56, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x14, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52,
+ 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x05, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x48, 0x00, 0x52, 0x05,
+ 0x65, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x67,
+ 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x03, 0x74, 0x74,
+ 0x6c, 0x18, 0x03, 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, 0x74, 0x74, 0x6c, 0x22, 0x15, 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x74,
+ 0x65, 0x4b, 0x56, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x87,
+ 0x01, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a,
+ 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x49,
+ 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4e, 0x44, 0x52, 0x4f,
+ 0x49, 0x44, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x41, 0x43, 0x10, 0x03, 0x12, 0x07, 0x0a,
+ 0x03, 0x49, 0x4f, 0x53, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x10,
+ 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x52, 0x10, 0x06, 0x12, 0x0c, 0x0a,
+ 0x08, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x5f, 0x54, 0x56, 0x10, 0x07, 0x12, 0x10, 0x0a, 0x0c, 0x47,
+ 0x41, 0x4d, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, 0x45, 0x10, 0x08, 0x12, 0x09, 0x0a,
+ 0x05, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x09, 0x32, 0xd0, 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, 0x12, 0x44, 0x0a, 0x15, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44,
+ 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x79, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x14,
+ 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76,
+ 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x61, 0x0a, 0x10, 0x52,
+ 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
+ 0x4d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53,
+ 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69,
+ 0x6d, 0x69, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x65,
+ 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x75,
+ 0x0a, 0x0f, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x12, 0x30, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x12, 0x13, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74,
+ 0x65, 0x4b, 0x56, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e,
+ 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x03, 0x73, 0x65, 0x74, 0x12, 0x13, 0x2e, 0x52, 0x65, 0x6d,
+ 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x14, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 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 (
@@ -2008,80 +2299,95 @@ func file_dns_proto_rawDescGZIP() []byte {
}
var file_dns_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_dns_proto_msgTypes = make([]protoimpl.MessageInfo, 24)
+var file_dns_proto_msgTypes = make([]protoimpl.MessageInfo, 30)
var file_dns_proto_goTypes = []any{
(DeviceType)(0), // 0: DeviceType
- (*DNSProfilesRequest)(nil), // 1: DNSProfilesRequest
- (*DNSProfile)(nil), // 2: DNSProfile
- (*SafeBrowsingSettings)(nil), // 3: SafeBrowsingSettings
- (*DeviceSettings)(nil), // 4: DeviceSettings
- (*ParentalSettings)(nil), // 5: ParentalSettings
- (*ScheduleSettings)(nil), // 6: ScheduleSettings
- (*WeeklyRange)(nil), // 7: WeeklyRange
- (*DayRange)(nil), // 8: DayRange
- (*RuleListsSettings)(nil), // 9: RuleListsSettings
- (*BlockingModeCustomIP)(nil), // 10: BlockingModeCustomIP
- (*BlockingModeNXDOMAIN)(nil), // 11: BlockingModeNXDOMAIN
- (*BlockingModeNullIP)(nil), // 12: BlockingModeNullIP
- (*BlockingModeREFUSED)(nil), // 13: BlockingModeREFUSED
- (*DeviceBillingStat)(nil), // 14: DeviceBillingStat
- (*AccessSettings)(nil), // 15: AccessSettings
- (*CidrRange)(nil), // 16: CidrRange
- (*AuthenticationSettings)(nil), // 17: AuthenticationSettings
- (*CreateDeviceRequest)(nil), // 18: CreateDeviceRequest
- (*CreateDeviceResponse)(nil), // 19: CreateDeviceResponse
- (*RateLimitedError)(nil), // 20: RateLimitedError
- (*DeviceQuotaExceededError)(nil), // 21: DeviceQuotaExceededError
- (*BadRequestError)(nil), // 22: BadRequestError
- (*AuthenticationFailedError)(nil), // 23: AuthenticationFailedError
- (*RateLimitSettings)(nil), // 24: RateLimitSettings
- (*timestamppb.Timestamp)(nil), // 25: google.protobuf.Timestamp
- (*durationpb.Duration)(nil), // 26: google.protobuf.Duration
- (*emptypb.Empty)(nil), // 27: google.protobuf.Empty
+ (*RateLimitSettingsRequest)(nil), // 1: RateLimitSettingsRequest
+ (*RateLimitSettingsResponse)(nil), // 2: RateLimitSettingsResponse
+ (*DNSProfilesRequest)(nil), // 3: DNSProfilesRequest
+ (*DNSProfile)(nil), // 4: DNSProfile
+ (*SafeBrowsingSettings)(nil), // 5: SafeBrowsingSettings
+ (*DeviceSettings)(nil), // 6: DeviceSettings
+ (*ParentalSettings)(nil), // 7: ParentalSettings
+ (*ScheduleSettings)(nil), // 8: ScheduleSettings
+ (*WeeklyRange)(nil), // 9: WeeklyRange
+ (*DayRange)(nil), // 10: DayRange
+ (*RuleListsSettings)(nil), // 11: RuleListsSettings
+ (*BlockingModeCustomIP)(nil), // 12: BlockingModeCustomIP
+ (*BlockingModeNXDOMAIN)(nil), // 13: BlockingModeNXDOMAIN
+ (*BlockingModeNullIP)(nil), // 14: BlockingModeNullIP
+ (*BlockingModeREFUSED)(nil), // 15: BlockingModeREFUSED
+ (*DeviceBillingStat)(nil), // 16: DeviceBillingStat
+ (*AccessSettings)(nil), // 17: AccessSettings
+ (*CidrRange)(nil), // 18: CidrRange
+ (*AuthenticationSettings)(nil), // 19: AuthenticationSettings
+ (*CreateDeviceRequest)(nil), // 20: CreateDeviceRequest
+ (*CreateDeviceResponse)(nil), // 21: CreateDeviceResponse
+ (*RateLimitedError)(nil), // 22: RateLimitedError
+ (*DeviceQuotaExceededError)(nil), // 23: DeviceQuotaExceededError
+ (*BadRequestError)(nil), // 24: BadRequestError
+ (*AuthenticationFailedError)(nil), // 25: AuthenticationFailedError
+ (*RateLimitSettings)(nil), // 26: RateLimitSettings
+ (*RemoteKVGetRequest)(nil), // 27: RemoteKVGetRequest
+ (*RemoteKVGetResponse)(nil), // 28: RemoteKVGetResponse
+ (*RemoteKVSetRequest)(nil), // 29: RemoteKVSetRequest
+ (*RemoteKVSetResponse)(nil), // 30: RemoteKVSetResponse
+ (*timestamppb.Timestamp)(nil), // 31: google.protobuf.Timestamp
+ (*durationpb.Duration)(nil), // 32: google.protobuf.Duration
+ (*emptypb.Empty)(nil), // 33: google.protobuf.Empty
}
var file_dns_proto_depIdxs = []int32{
- 25, // 0: DNSProfilesRequest.sync_time:type_name -> google.protobuf.Timestamp
- 3, // 1: DNSProfile.safe_browsing:type_name -> SafeBrowsingSettings
- 5, // 2: DNSProfile.parental:type_name -> ParentalSettings
- 9, // 3: DNSProfile.rule_lists:type_name -> RuleListsSettings
- 4, // 4: DNSProfile.devices:type_name -> DeviceSettings
- 26, // 5: DNSProfile.filtered_response_ttl:type_name -> google.protobuf.Duration
- 10, // 6: DNSProfile.blocking_mode_custom_ip:type_name -> BlockingModeCustomIP
- 11, // 7: DNSProfile.blocking_mode_nxdomain:type_name -> BlockingModeNXDOMAIN
- 12, // 8: DNSProfile.blocking_mode_null_ip:type_name -> BlockingModeNullIP
- 13, // 9: DNSProfile.blocking_mode_refused:type_name -> BlockingModeREFUSED
- 15, // 10: DNSProfile.access:type_name -> AccessSettings
- 24, // 11: DNSProfile.rate_limit:type_name -> RateLimitSettings
- 17, // 12: DeviceSettings.authentication:type_name -> AuthenticationSettings
- 6, // 13: ParentalSettings.schedule:type_name -> ScheduleSettings
- 7, // 14: ScheduleSettings.weeklyRange:type_name -> WeeklyRange
- 8, // 15: WeeklyRange.mon:type_name -> DayRange
- 8, // 16: WeeklyRange.tue:type_name -> DayRange
- 8, // 17: WeeklyRange.wed:type_name -> DayRange
- 8, // 18: WeeklyRange.thu:type_name -> DayRange
- 8, // 19: WeeklyRange.fri:type_name -> DayRange
- 8, // 20: WeeklyRange.sat:type_name -> DayRange
- 8, // 21: WeeklyRange.sun:type_name -> DayRange
- 26, // 22: DayRange.start:type_name -> google.protobuf.Duration
- 26, // 23: DayRange.end:type_name -> google.protobuf.Duration
- 25, // 24: DeviceBillingStat.last_activity_time:type_name -> google.protobuf.Timestamp
- 16, // 25: AccessSettings.allowlist_cidr:type_name -> CidrRange
- 16, // 26: AccessSettings.blocklist_cidr:type_name -> CidrRange
- 0, // 27: CreateDeviceRequest.device_type:type_name -> DeviceType
- 4, // 28: CreateDeviceResponse.device:type_name -> DeviceSettings
- 26, // 29: RateLimitedError.retry_delay:type_name -> google.protobuf.Duration
- 16, // 30: RateLimitSettings.client_cidr:type_name -> CidrRange
- 1, // 31: DNSService.getDNSProfiles:input_type -> DNSProfilesRequest
- 14, // 32: DNSService.saveDevicesBillingStat:input_type -> DeviceBillingStat
- 18, // 33: DNSService.createDeviceByHumanId:input_type -> CreateDeviceRequest
- 2, // 34: DNSService.getDNSProfiles:output_type -> DNSProfile
- 27, // 35: DNSService.saveDevicesBillingStat:output_type -> google.protobuf.Empty
- 19, // 36: DNSService.createDeviceByHumanId:output_type -> CreateDeviceResponse
- 34, // [34:37] is the sub-list for method output_type
- 31, // [31:34] is the sub-list for method input_type
- 31, // [31:31] is the sub-list for extension type_name
- 31, // [31:31] is the sub-list for extension extendee
- 0, // [0:31] is the sub-list for field type_name
+ 18, // 0: RateLimitSettingsResponse.allowed_subnets:type_name -> CidrRange
+ 31, // 1: DNSProfilesRequest.sync_time:type_name -> google.protobuf.Timestamp
+ 5, // 2: DNSProfile.safe_browsing:type_name -> SafeBrowsingSettings
+ 7, // 3: DNSProfile.parental:type_name -> ParentalSettings
+ 11, // 4: DNSProfile.rule_lists:type_name -> RuleListsSettings
+ 6, // 5: DNSProfile.devices:type_name -> DeviceSettings
+ 32, // 6: DNSProfile.filtered_response_ttl:type_name -> google.protobuf.Duration
+ 12, // 7: DNSProfile.blocking_mode_custom_ip:type_name -> BlockingModeCustomIP
+ 13, // 8: DNSProfile.blocking_mode_nxdomain:type_name -> BlockingModeNXDOMAIN
+ 14, // 9: DNSProfile.blocking_mode_null_ip:type_name -> BlockingModeNullIP
+ 15, // 10: DNSProfile.blocking_mode_refused:type_name -> BlockingModeREFUSED
+ 17, // 11: DNSProfile.access:type_name -> AccessSettings
+ 26, // 12: DNSProfile.rate_limit:type_name -> RateLimitSettings
+ 19, // 13: DeviceSettings.authentication:type_name -> AuthenticationSettings
+ 8, // 14: ParentalSettings.schedule:type_name -> ScheduleSettings
+ 9, // 15: ScheduleSettings.weeklyRange:type_name -> WeeklyRange
+ 10, // 16: WeeklyRange.mon:type_name -> DayRange
+ 10, // 17: WeeklyRange.tue:type_name -> DayRange
+ 10, // 18: WeeklyRange.wed:type_name -> DayRange
+ 10, // 19: WeeklyRange.thu:type_name -> DayRange
+ 10, // 20: WeeklyRange.fri:type_name -> DayRange
+ 10, // 21: WeeklyRange.sat:type_name -> DayRange
+ 10, // 22: WeeklyRange.sun:type_name -> DayRange
+ 32, // 23: DayRange.start:type_name -> google.protobuf.Duration
+ 32, // 24: DayRange.end:type_name -> google.protobuf.Duration
+ 31, // 25: DeviceBillingStat.last_activity_time:type_name -> google.protobuf.Timestamp
+ 18, // 26: AccessSettings.allowlist_cidr:type_name -> CidrRange
+ 18, // 27: AccessSettings.blocklist_cidr:type_name -> CidrRange
+ 0, // 28: CreateDeviceRequest.device_type:type_name -> DeviceType
+ 6, // 29: CreateDeviceResponse.device:type_name -> DeviceSettings
+ 32, // 30: RateLimitedError.retry_delay:type_name -> google.protobuf.Duration
+ 18, // 31: RateLimitSettings.client_cidr:type_name -> CidrRange
+ 33, // 32: RemoteKVGetResponse.empty:type_name -> google.protobuf.Empty
+ 32, // 33: RemoteKVSetRequest.ttl:type_name -> google.protobuf.Duration
+ 3, // 34: DNSService.getDNSProfiles:input_type -> DNSProfilesRequest
+ 16, // 35: DNSService.saveDevicesBillingStat:input_type -> DeviceBillingStat
+ 20, // 36: DNSService.createDeviceByHumanId:input_type -> CreateDeviceRequest
+ 1, // 37: RateLimitService.getRateLimitSettings:input_type -> RateLimitSettingsRequest
+ 27, // 38: RemoteKVService.get:input_type -> RemoteKVGetRequest
+ 29, // 39: RemoteKVService.set:input_type -> RemoteKVSetRequest
+ 4, // 40: DNSService.getDNSProfiles:output_type -> DNSProfile
+ 33, // 41: DNSService.saveDevicesBillingStat:output_type -> google.protobuf.Empty
+ 21, // 42: DNSService.createDeviceByHumanId:output_type -> CreateDeviceResponse
+ 2, // 43: RateLimitService.getRateLimitSettings:output_type -> RateLimitSettingsResponse
+ 28, // 44: RemoteKVService.get:output_type -> RemoteKVGetResponse
+ 30, // 45: RemoteKVService.set:output_type -> RemoteKVSetResponse
+ 40, // [40:46] is the sub-list for method output_type
+ 34, // [34:40] is the sub-list for method input_type
+ 34, // [34:34] is the sub-list for extension type_name
+ 34, // [34:34] is the sub-list for extension extendee
+ 0, // [0:34] is the sub-list for field type_name
}
func init() { file_dns_proto_init() }
@@ -2089,314 +2395,28 @@ func file_dns_proto_init() {
if File_dns_proto != nil {
return
}
- if !protoimpl.UnsafeEnabled {
- file_dns_proto_msgTypes[0].Exporter = func(v any, i int) any {
- switch v := v.(*DNSProfilesRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[1].Exporter = func(v any, i int) any {
- switch v := v.(*DNSProfile); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[2].Exporter = func(v any, i int) any {
- switch v := v.(*SafeBrowsingSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[3].Exporter = func(v any, i int) any {
- switch v := v.(*DeviceSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[4].Exporter = func(v any, i int) any {
- switch v := v.(*ParentalSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[5].Exporter = func(v any, i int) any {
- switch v := v.(*ScheduleSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[6].Exporter = func(v any, i int) any {
- switch v := v.(*WeeklyRange); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[7].Exporter = func(v any, i int) any {
- switch v := v.(*DayRange); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[8].Exporter = func(v any, i int) any {
- switch v := v.(*RuleListsSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[9].Exporter = func(v any, i int) any {
- switch v := v.(*BlockingModeCustomIP); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[10].Exporter = func(v any, i int) any {
- switch v := v.(*BlockingModeNXDOMAIN); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[11].Exporter = func(v any, i int) any {
- switch v := v.(*BlockingModeNullIP); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[12].Exporter = func(v any, i int) any {
- switch v := v.(*BlockingModeREFUSED); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[13].Exporter = func(v any, i int) any {
- switch v := v.(*DeviceBillingStat); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[14].Exporter = func(v any, i int) any {
- switch v := v.(*AccessSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[15].Exporter = func(v any, i int) any {
- switch v := v.(*CidrRange); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[16].Exporter = func(v any, i int) any {
- switch v := v.(*AuthenticationSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[17].Exporter = func(v any, i int) any {
- switch v := v.(*CreateDeviceRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[18].Exporter = func(v any, i int) any {
- switch v := v.(*CreateDeviceResponse); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[19].Exporter = func(v any, i int) any {
- switch v := v.(*RateLimitedError); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[20].Exporter = func(v any, i int) any {
- switch v := v.(*DeviceQuotaExceededError); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[21].Exporter = func(v any, i int) any {
- switch v := v.(*BadRequestError); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[22].Exporter = func(v any, i int) any {
- switch v := v.(*AuthenticationFailedError); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_dns_proto_msgTypes[23].Exporter = func(v any, i int) any {
- switch v := v.(*RateLimitSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
- file_dns_proto_msgTypes[1].OneofWrappers = []any{
+ file_dns_proto_msgTypes[3].OneofWrappers = []any{
(*DNSProfile_BlockingModeCustomIp)(nil),
(*DNSProfile_BlockingModeNxdomain)(nil),
(*DNSProfile_BlockingModeNullIp)(nil),
(*DNSProfile_BlockingModeRefused)(nil),
}
- file_dns_proto_msgTypes[16].OneofWrappers = []any{
+ file_dns_proto_msgTypes[18].OneofWrappers = []any{
(*AuthenticationSettings_PasswordHashBcrypt)(nil),
}
+ file_dns_proto_msgTypes[27].OneofWrappers = []any{
+ (*RemoteKVGetResponse_Data)(nil),
+ (*RemoteKVGetResponse_Empty)(nil),
+ }
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_dns_proto_rawDesc,
NumEnums: 1,
- NumMessages: 24,
+ NumMessages: 30,
NumExtensions: 0,
- NumServices: 1,
+ NumServices: 3,
},
GoTypes: file_dns_proto_goTypes,
DependencyIndexes: file_dns_proto_depIdxs,
diff --git a/internal/backendpb/dns.proto b/internal/backendpb/dns.proto
index 4653e9d..4c14fb3 100644
--- a/internal/backendpb/dns.proto
+++ b/internal/backendpb/dns.proto
@@ -45,6 +45,42 @@ service DNSService {
rpc createDeviceByHumanId(CreateDeviceRequest) returns (CreateDeviceResponse);
}
+service RateLimitService {
+
+ /*
+ Gets rate limit settings.
+ */
+ rpc getRateLimitSettings(RateLimitSettingsRequest) returns (RateLimitSettingsResponse);
+}
+
+service RemoteKVService {
+
+ /**
+ Get the value for the specified key.
+
+ This method may return the following errors:
+ - AuthenticationFailedError: If the authentication failed.
+ */
+ rpc get(RemoteKVGetRequest) returns (RemoteKVGetResponse);
+
+ /**
+ Set the value for the specified key.
+
+ This method may return the following errors:
+ - AuthenticationFailedError: If the authentication failed.
+ - BadRequestError: If the request is invalid: value size exceeds the 512kb.
+ */
+ rpc set(RemoteKVSetRequest) returns (RemoteKVSetResponse);
+}
+
+message RateLimitSettingsRequest {
+
+}
+
+message RateLimitSettingsResponse {
+ repeated CidrRange allowed_subnets = 1;
+}
+
message DNSProfilesRequest {
google.protobuf.Timestamp sync_time = 1;
}
@@ -212,3 +248,24 @@ message RateLimitSettings {
uint32 rps = 2;
repeated CidrRange client_cidr = 3;
}
+
+message RemoteKVGetRequest {
+ string key = 1;
+}
+
+message RemoteKVGetResponse {
+ oneof value {
+ bytes data = 1;
+ google.protobuf.Empty empty = 2;
+ }
+}
+
+message RemoteKVSetRequest {
+ string key = 1;
+ bytes data = 2;
+ google.protobuf.Duration ttl = 3;
+}
+
+message RemoteKVSetResponse {
+
+}
diff --git a/internal/backendpb/dns_grpc.pb.go b/internal/backendpb/dns_grpc.pb.go
index 4ff7dff..945451c 100644
--- a/internal/backendpb/dns_grpc.pb.go
+++ b/internal/backendpb/dns_grpc.pb.go
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
-// - protoc v5.27.1
+// - protoc v5.28.3
// source: dns.proto
package backendpb
@@ -235,3 +235,269 @@ var DNSService_ServiceDesc = grpc.ServiceDesc{
},
Metadata: "dns.proto",
}
+
+const (
+ RateLimitService_GetRateLimitSettings_FullMethodName = "/RateLimitService/getRateLimitSettings"
+)
+
+// RateLimitServiceClient is the client API for RateLimitService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type RateLimitServiceClient interface {
+ // Gets rate limit settings.
+ GetRateLimitSettings(ctx context.Context, in *RateLimitSettingsRequest, opts ...grpc.CallOption) (*RateLimitSettingsResponse, error)
+}
+
+type rateLimitServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewRateLimitServiceClient(cc grpc.ClientConnInterface) RateLimitServiceClient {
+ return &rateLimitServiceClient{cc}
+}
+
+func (c *rateLimitServiceClient) GetRateLimitSettings(ctx context.Context, in *RateLimitSettingsRequest, opts ...grpc.CallOption) (*RateLimitSettingsResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(RateLimitSettingsResponse)
+ err := c.cc.Invoke(ctx, RateLimitService_GetRateLimitSettings_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// RateLimitServiceServer is the server API for RateLimitService service.
+// All implementations must embed UnimplementedRateLimitServiceServer
+// for forward compatibility.
+type RateLimitServiceServer interface {
+ // Gets rate limit settings.
+ GetRateLimitSettings(context.Context, *RateLimitSettingsRequest) (*RateLimitSettingsResponse, error)
+ mustEmbedUnimplementedRateLimitServiceServer()
+}
+
+// UnimplementedRateLimitServiceServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedRateLimitServiceServer struct{}
+
+func (UnimplementedRateLimitServiceServer) GetRateLimitSettings(context.Context, *RateLimitSettingsRequest) (*RateLimitSettingsResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetRateLimitSettings not implemented")
+}
+func (UnimplementedRateLimitServiceServer) mustEmbedUnimplementedRateLimitServiceServer() {}
+func (UnimplementedRateLimitServiceServer) testEmbeddedByValue() {}
+
+// UnsafeRateLimitServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to RateLimitServiceServer will
+// result in compilation errors.
+type UnsafeRateLimitServiceServer interface {
+ mustEmbedUnimplementedRateLimitServiceServer()
+}
+
+func RegisterRateLimitServiceServer(s grpc.ServiceRegistrar, srv RateLimitServiceServer) {
+ // If the following call pancis, it indicates UnimplementedRateLimitServiceServer was
+ // embedded by pointer and is nil. This will cause panics if an
+ // unimplemented method is ever invoked, so we test this at initialization
+ // time to prevent it from happening at runtime later due to I/O.
+ if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+ t.testEmbeddedByValue()
+ }
+ s.RegisterService(&RateLimitService_ServiceDesc, srv)
+}
+
+func _RateLimitService_GetRateLimitSettings_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RateLimitSettingsRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RateLimitServiceServer).GetRateLimitSettings(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RateLimitService_GetRateLimitSettings_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RateLimitServiceServer).GetRateLimitSettings(ctx, req.(*RateLimitSettingsRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// RateLimitService_ServiceDesc is the grpc.ServiceDesc for RateLimitService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var RateLimitService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "RateLimitService",
+ HandlerType: (*RateLimitServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "getRateLimitSettings",
+ Handler: _RateLimitService_GetRateLimitSettings_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "dns.proto",
+}
+
+const (
+ RemoteKVService_Get_FullMethodName = "/RemoteKVService/get"
+ RemoteKVService_Set_FullMethodName = "/RemoteKVService/set"
+)
+
+// RemoteKVServiceClient is the client API for RemoteKVService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type RemoteKVServiceClient interface {
+ // *
+ // Get the value for the specified key.
+ //
+ // This method may return the following errors:
+ // - AuthenticationFailedError: If the authentication failed.
+ Get(ctx context.Context, in *RemoteKVGetRequest, opts ...grpc.CallOption) (*RemoteKVGetResponse, error)
+ // *
+ // Set the value for the specified key.
+ //
+ // This method may return the following errors:
+ // - AuthenticationFailedError: If the authentication failed.
+ // - BadRequestError: If the request is invalid: value size exceeds the 512kb.
+ Set(ctx context.Context, in *RemoteKVSetRequest, opts ...grpc.CallOption) (*RemoteKVSetResponse, error)
+}
+
+type remoteKVServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewRemoteKVServiceClient(cc grpc.ClientConnInterface) RemoteKVServiceClient {
+ return &remoteKVServiceClient{cc}
+}
+
+func (c *remoteKVServiceClient) Get(ctx context.Context, in *RemoteKVGetRequest, opts ...grpc.CallOption) (*RemoteKVGetResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(RemoteKVGetResponse)
+ err := c.cc.Invoke(ctx, RemoteKVService_Get_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteKVServiceClient) Set(ctx context.Context, in *RemoteKVSetRequest, opts ...grpc.CallOption) (*RemoteKVSetResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(RemoteKVSetResponse)
+ err := c.cc.Invoke(ctx, RemoteKVService_Set_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// RemoteKVServiceServer is the server API for RemoteKVService service.
+// All implementations must embed UnimplementedRemoteKVServiceServer
+// for forward compatibility.
+type RemoteKVServiceServer interface {
+ // *
+ // Get the value for the specified key.
+ //
+ // This method may return the following errors:
+ // - AuthenticationFailedError: If the authentication failed.
+ Get(context.Context, *RemoteKVGetRequest) (*RemoteKVGetResponse, error)
+ // *
+ // Set the value for the specified key.
+ //
+ // This method may return the following errors:
+ // - AuthenticationFailedError: If the authentication failed.
+ // - BadRequestError: If the request is invalid: value size exceeds the 512kb.
+ Set(context.Context, *RemoteKVSetRequest) (*RemoteKVSetResponse, error)
+ mustEmbedUnimplementedRemoteKVServiceServer()
+}
+
+// UnimplementedRemoteKVServiceServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedRemoteKVServiceServer struct{}
+
+func (UnimplementedRemoteKVServiceServer) Get(context.Context, *RemoteKVGetRequest) (*RemoteKVGetResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Get not implemented")
+}
+func (UnimplementedRemoteKVServiceServer) Set(context.Context, *RemoteKVSetRequest) (*RemoteKVSetResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Set not implemented")
+}
+func (UnimplementedRemoteKVServiceServer) mustEmbedUnimplementedRemoteKVServiceServer() {}
+func (UnimplementedRemoteKVServiceServer) testEmbeddedByValue() {}
+
+// UnsafeRemoteKVServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to RemoteKVServiceServer will
+// result in compilation errors.
+type UnsafeRemoteKVServiceServer interface {
+ mustEmbedUnimplementedRemoteKVServiceServer()
+}
+
+func RegisterRemoteKVServiceServer(s grpc.ServiceRegistrar, srv RemoteKVServiceServer) {
+ // If the following call pancis, it indicates UnimplementedRemoteKVServiceServer was
+ // embedded by pointer and is nil. This will cause panics if an
+ // unimplemented method is ever invoked, so we test this at initialization
+ // time to prevent it from happening at runtime later due to I/O.
+ if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+ t.testEmbeddedByValue()
+ }
+ s.RegisterService(&RemoteKVService_ServiceDesc, srv)
+}
+
+func _RemoteKVService_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RemoteKVGetRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteKVServiceServer).Get(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteKVService_Get_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteKVServiceServer).Get(ctx, req.(*RemoteKVGetRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteKVService_Set_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RemoteKVSetRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteKVServiceServer).Set(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteKVService_Set_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteKVServiceServer).Set(ctx, req.(*RemoteKVSetRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// RemoteKVService_ServiceDesc is the grpc.ServiceDesc for RemoteKVService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var RemoteKVService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "RemoteKVService",
+ HandlerType: (*RemoteKVServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "get",
+ Handler: _RemoteKVService_Get_Handler,
+ },
+ {
+ MethodName: "set",
+ Handler: _RemoteKVService_Set_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "dns.proto",
+}
diff --git a/internal/backendpb/profiledb.go b/internal/backendpb/profiledb.go
index 5a301cd..25d75e9 100644
--- a/internal/backendpb/profiledb.go
+++ b/internal/backendpb/profiledb.go
@@ -81,7 +81,7 @@ func NewProfileStorage(c *ProfileStorageConfig) (s *ProfileStorage, err error) {
return &ProfileStorage{
bindSet: c.BindSet,
errColl: c.ErrColl,
- client: client,
+ client: NewDNSServiceClient(client),
logger: c.Logger,
metrics: c.Metrics,
apiKey: c.APIKey,
diff --git a/internal/backendpb/ratelimiter.go b/internal/backendpb/ratelimiter.go
new file mode 100644
index 0000000..fa67d14
--- /dev/null
+++ b/internal/backendpb/ratelimiter.go
@@ -0,0 +1,103 @@
+package backendpb
+
+import (
+ "context"
+ "fmt"
+ "log/slog"
+ "net/url"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
+ "github.com/AdguardTeam/AdGuardDNS/internal/consul"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+)
+
+// RateLimiterConfig is the configuration structure for the business logic
+// backend rate limiter.
+type RateLimiterConfig struct {
+ // Logger is used for logging the operation of the rate limiter. It must
+ // not be nil.
+ Logger *slog.Logger
+
+ // GRPCMetrics is used for the collection of the protobuf errors.
+ GRPCMetrics Metrics
+
+ // Metrics is used to collect allowlist statistics.
+ Metrics consul.Metrics
+
+ // Allowlist is the allowlist to update.
+ Allowlist *ratelimit.DynamicAllowlist
+
+ // ErrColl is used to collect errors during refreshes.
+ ErrColl errcoll.Interface
+
+ // Endpoint is the backend API URL. The scheme should be either "grpc" or
+ // "grpcs". It must not be nil.
+ Endpoint *url.URL
+
+ // APIKey is the API key used for authentication, if any. If empty, no
+ // authentication is performed.
+ APIKey string
+}
+
+// RateLimiter is the implementation of the [agdservice.Refresher] interface
+// that retrieves the rate limit settings from the business logic backend.
+type RateLimiter struct {
+ logger *slog.Logger
+ grpcMetrics Metrics
+ metrics consul.Metrics
+ allowlist *ratelimit.DynamicAllowlist
+ errColl errcoll.Interface
+ client RateLimitServiceClient
+ apiKey string
+}
+
+// NewRateLimiter creates a new properly initialized rate limiter. c must not
+// be nil.
+func NewRateLimiter(c *RateLimiterConfig) (l *RateLimiter, err error) {
+ client, err := newClient(c.Endpoint)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return nil, err
+ }
+
+ return &RateLimiter{
+ logger: c.Logger,
+ grpcMetrics: c.GRPCMetrics,
+ metrics: c.Metrics,
+ allowlist: c.Allowlist,
+ errColl: c.ErrColl,
+ client: NewRateLimitServiceClient(client),
+ apiKey: c.APIKey,
+ }, nil
+}
+
+// type check
+var _ agdservice.Refresher = (*RateLimiter)(nil)
+
+// Refresh implements the [agdservice.Refresher] interface for *RateLimiter.
+func (l *RateLimiter) Refresh(ctx context.Context) (err error) {
+ l.logger.InfoContext(ctx, "refresh started")
+ defer l.logger.InfoContext(ctx, "refresh finished")
+
+ defer func() { l.metrics.SetStatus(ctx, err) }()
+
+ ctx = ctxWithAuthentication(ctx, l.apiKey)
+ backendResp, err := l.client.GetRateLimitSettings(ctx, &RateLimitSettingsRequest{})
+ if err != nil {
+ return fmt.Errorf(
+ "loading backend rate limit settings: %w",
+ fixGRPCError(ctx, l.grpcMetrics, err),
+ )
+ }
+
+ allowedSubnets := backendResp.AllowedSubnets
+ prefixes := cidrRangeToInternal(ctx, l.errColl, allowedSubnets)
+ l.allowlist.Update(prefixes)
+
+ l.logger.InfoContext(ctx, "refresh successful", "num_records", len(prefixes))
+
+ l.metrics.SetSize(ctx, len(prefixes))
+
+ return nil
+}
diff --git a/internal/backendpb/ratelimiter_test.go b/internal/backendpb/ratelimiter_test.go
new file mode 100644
index 0000000..dc86e7e
--- /dev/null
+++ b/internal/backendpb/ratelimiter_test.go
@@ -0,0 +1,110 @@
+package backendpb_test
+
+import (
+ "context"
+ "net"
+ "net/netip"
+ "net/url"
+ "testing"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
+ "github.com/AdguardTeam/AdGuardDNS/internal/consul"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
+)
+
+// testRateLimitServiceServer is the [backendpb.RateLimitServiceServer] for
+// tests.
+type testRateLimitServiceServer struct {
+ backendpb.UnimplementedRateLimitServiceServer
+
+ OnGetRateLimitSettings func(
+ ctx context.Context,
+ req *backendpb.RateLimitSettingsRequest,
+ ) (resp *backendpb.RateLimitSettingsResponse, err error)
+}
+
+// type check
+var _ backendpb.DNSServiceServer = (*testDNSServiceServer)(nil)
+
+// GetRateLimitSettings implements the [backendpb.RateLimitServiceServer]
+// interface for *testRateLimitServiceServer.
+func (s *testRateLimitServiceServer) GetRateLimitSettings(
+ ctx context.Context,
+ req *backendpb.RateLimitSettingsRequest,
+) (resp *backendpb.RateLimitSettingsResponse, err error) {
+ return s.OnGetRateLimitSettings(ctx, req)
+}
+
+func TestRateLimiter_Refresh(t *testing.T) {
+ var (
+ allowedIP = netip.MustParseAddr("1.2.3.4")
+ notAllowedIP = netip.MustParseAddr("4.3.2.1")
+
+ cidr = &backendpb.CidrRange{
+ Address: allowedIP.AsSlice(),
+ Prefix: 32,
+ }
+ )
+
+ srv := &testRateLimitServiceServer{
+ OnGetRateLimitSettings: func(
+ ctx context.Context,
+ req *backendpb.RateLimitSettingsRequest,
+ ) (resp *backendpb.RateLimitSettingsResponse, err error) {
+ return &backendpb.RateLimitSettingsResponse{
+ AllowedSubnets: []*backendpb.CidrRange{cidr},
+ }, nil
+ },
+ }
+
+ ln, err := net.Listen("tcp", "localhost:0")
+ require.NoError(t, err)
+
+ grpcSrv := grpc.NewServer(
+ grpc.ConnectionTimeout(1*time.Second),
+ grpc.Creds(insecure.NewCredentials()),
+ )
+ backendpb.RegisterRateLimitServiceServer(grpcSrv, srv)
+
+ go func() {
+ pt := testutil.PanicT{}
+
+ srvErr := grpcSrv.Serve(ln)
+ require.NoError(pt, srvErr)
+ }()
+ t.Cleanup(grpcSrv.GracefulStop)
+
+ allowlist := ratelimit.NewDynamicAllowlist(nil, nil)
+ l, err := backendpb.NewRateLimiter(&backendpb.RateLimiterConfig{
+ Logger: slogutil.NewDiscardLogger(),
+ Metrics: consul.EmptyMetrics{},
+ GRPCMetrics: backendpb.EmptyMetrics{},
+ Allowlist: allowlist,
+ Endpoint: &url.URL{
+ Scheme: "grpc",
+ Host: ln.Addr().String(),
+ },
+ })
+ require.NoError(t, err)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ err = l.Refresh(ctx)
+ require.NoError(t, err)
+
+ ok, err := allowlist.IsAllowed(ctx, allowedIP)
+ require.NoError(t, err)
+
+ assert.True(t, ok)
+
+ ok, err = allowlist.IsAllowed(ctx, notAllowedIP)
+ require.NoError(t, err)
+
+ assert.False(t, ok)
+}
diff --git a/internal/backendpb/remotekv.go b/internal/backendpb/remotekv.go
new file mode 100644
index 0000000..09810d4
--- /dev/null
+++ b/internal/backendpb/remotekv.go
@@ -0,0 +1,96 @@
+package backendpb
+
+import (
+ "context"
+ "fmt"
+ "net/url"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/remotekv"
+ "google.golang.org/protobuf/types/known/durationpb"
+)
+
+// RemoteKVConfig is the configuration for the business logic backend key-value
+// storage.
+type RemoteKVConfig struct {
+ // Metrics is used for the collection of the remote key-value storage
+ // statistics.
+ //
+ // TODO(e.burkov): Perhaps, it worths of a separate metrics interface,
+ // since it's only used for the collection of the protobuf errors.
+ Metrics Metrics
+
+ // Endpoint is the backend API URL. The scheme should be either "grpc" or
+ // "grpcs".
+ Endpoint *url.URL
+
+ // APIKey is the API key used for authentication, if any.
+ APIKey string
+
+ // TTL is the TTL of the values in the storage.
+ TTL time.Duration
+}
+
+// RemoteKV is the implementation of the [remotekv.Interface] interface that
+// uses the business logic backend as the key-value storage. It is safe for
+// concurrent use.
+type RemoteKV struct {
+ metrics Metrics
+ client RemoteKVServiceClient
+ apiKey string
+ ttl time.Duration
+}
+
+// NewRemoteKV returns a new [RemoteKV] that retrieves information from the
+// business logic backend.
+func NewRemoteKV(c *RemoteKVConfig) (kv *RemoteKV, err error) {
+ client, err := newClient(c.Endpoint)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return nil, err
+ }
+
+ return &RemoteKV{
+ metrics: c.Metrics,
+ client: NewRemoteKVServiceClient(client),
+ apiKey: c.APIKey,
+ ttl: c.TTL,
+ }, nil
+}
+
+// type check
+var _ remotekv.Interface = (*RemoteKV)(nil)
+
+// Get implements the [remotekv.Interface] interface for *RemoteKV.
+func (kv *RemoteKV) Get(ctx context.Context, key string) (val []byte, ok bool, err error) {
+ req := &RemoteKVGetRequest{
+ Key: key,
+ }
+
+ ctx = ctxWithAuthentication(ctx, kv.apiKey)
+ resp, err := kv.client.Get(ctx, req)
+ if err != nil {
+ return nil, false, fmt.Errorf("getting %q key: %w", key, fixGRPCError(ctx, kv.metrics, err))
+ }
+
+ val = resp.GetData()
+
+ return val, val != nil, nil
+}
+
+// Set implements the [remotekv.Interface] interface for *RemoteKV.
+func (kv *RemoteKV) Set(ctx context.Context, key string, val []byte) (err error) {
+ req := &RemoteKVSetRequest{
+ Key: key,
+ Data: val,
+ Ttl: durationpb.New(kv.ttl),
+ }
+
+ ctx = ctxWithAuthentication(ctx, kv.apiKey)
+ _, err = kv.client.Set(ctx, req)
+ if err != nil {
+ return fmt.Errorf("setting %q key: %w", key, fixGRPCError(ctx, kv.metrics, err))
+ }
+
+ return nil
+}
diff --git a/internal/backendpb/remotekv_test.go b/internal/backendpb/remotekv_test.go
new file mode 100644
index 0000000..612ae7e
--- /dev/null
+++ b/internal/backendpb/remotekv_test.go
@@ -0,0 +1,106 @@
+package backendpb_test
+
+import (
+ "context"
+ "net"
+ "net/url"
+ "testing"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
+)
+
+func TestRemoteKV_Get(t *testing.T) {
+ const testTTL = 10 * time.Second
+
+ pt := &testutil.PanicT{}
+
+ strg := map[string][]byte{}
+ srv := &testRemoteKVServiceServer{
+ OnGet: func(
+ ctx context.Context,
+ req *backendpb.RemoteKVGetRequest,
+ ) (resp *backendpb.RemoteKVGetResponse, err error) {
+ resp = &backendpb.RemoteKVGetResponse{
+ Value: &backendpb.RemoteKVGetResponse_Empty{},
+ }
+
+ if val, ok := strg[req.Key]; ok {
+ resp.Value = &backendpb.RemoteKVGetResponse_Data{Data: val}
+ }
+
+ return resp, nil
+ },
+
+ OnSet: func(
+ ctx context.Context,
+ req *backendpb.RemoteKVSetRequest,
+ ) (resp *backendpb.RemoteKVSetResponse, err error) {
+ require.Equal(pt, testTTL, req.Ttl.AsDuration())
+
+ strg[req.Key] = req.Data
+
+ return &backendpb.RemoteKVSetResponse{}, nil
+ },
+ }
+
+ l, err := net.Listen("tcp", "localhost:0")
+ require.NoError(t, err)
+
+ grpcSrv := grpc.NewServer(
+ grpc.ConnectionTimeout(1*time.Second),
+ grpc.Creds(insecure.NewCredentials()),
+ )
+ backendpb.RegisterRemoteKVServiceServer(grpcSrv, srv)
+
+ go func() {
+ srvErr := grpcSrv.Serve(l)
+ require.NoError(pt, srvErr)
+ }()
+ t.Cleanup(grpcSrv.GracefulStop)
+
+ kv, err := backendpb.NewRemoteKV(&backendpb.RemoteKVConfig{
+ Metrics: backendpb.EmptyMetrics{},
+ Endpoint: &url.URL{
+ Scheme: "grpc",
+ Host: l.Addr().String(),
+ },
+ APIKey: "apikey",
+ TTL: testTTL,
+ })
+ require.NoError(t, err)
+
+ const (
+ keyWithData = "key"
+ keyNoData = "unknown"
+ )
+
+ t.Run("success", func(t *testing.T) {
+ val := []byte("value")
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+
+ setErr := kv.Set(ctx, keyWithData, val)
+ require.NoError(t, setErr)
+
+ gotVal, ok, getErr := kv.Get(ctx, keyWithData)
+ require.NoError(t, getErr)
+ require.True(t, ok)
+
+ assert.Equal(t, val, gotVal)
+ })
+
+ t.Run("not_found", func(t *testing.T) {
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+
+ val, ok, getErr := kv.Get(ctx, keyNoData)
+ require.NoError(t, getErr)
+ require.False(t, ok)
+
+ assert.Nil(t, val)
+ })
+}
diff --git a/internal/bindtodevice/connindex_linux.go b/internal/bindtodevice/connindex_linux.go
index 70614a3..765d85f 100644
--- a/internal/bindtodevice/connindex_linux.go
+++ b/internal/bindtodevice/connindex_linux.go
@@ -20,23 +20,19 @@ type connIndex struct {
}
// subnetCompare is a comparison function for the two subnets. It returns -1 if
-// x sorts before y, 1 if x sorts after y, and 0 if their relative sorting
+// a sorts before b, 1 if a sorts after b, and 0 if their relative sorting
// position is the same.
-func subnetCompare(x, y netip.Prefix) (cmp int) {
- if x == y {
- return 0
- }
+func subnetCompare(a, b netip.Prefix) (cmp int) {
+ aAddr, aBits := a.Addr(), a.Bits()
+ bAddr, bBits := b.Addr(), b.Bits()
- xAddr, xBits := x.Addr(), x.Bits()
- yAddr, yBits := y.Addr(), y.Bits()
- if xBits == yBits {
- return xAddr.Compare(yAddr)
- }
-
- if xBits > yBits {
+ switch {
+ case aBits > bBits:
return -1
- } else {
+ case aBits < bBits:
return 1
+ default:
+ return aAddr.Compare(bAddr)
}
}
@@ -45,8 +41,8 @@ func subnetCompare(x, y netip.Prefix) (cmp int) {
//
// TODO(a.garipov): Merge with [addListenerChannel].
func (idx *connIndex) addPacketConn(c *chanPacketConn) (err error) {
- cmpFunc := func(x, y *chanPacketConn) (cmp int) {
- return subnetCompare(x.subnet, y.subnet)
+ cmpFunc := func(a, b *chanPacketConn) (cmp int) {
+ return subnetCompare(a.subnet, b.subnet)
}
newIdx, ok := slices.BinarySearchFunc(idx.packetConns, c, cmpFunc)
@@ -67,8 +63,8 @@ func (idx *connIndex) addPacketConn(c *chanPacketConn) (err error) {
//
// TODO(a.garipov): Merge with [addPacketConnChannel].
func (idx *connIndex) addListener(l *chanListener) (err error) {
- cmpFunc := func(x, y *chanListener) (cmp int) {
- return subnetCompare(x.subnet, y.subnet)
+ cmpFunc := func(a, b *chanListener) (cmp int) {
+ return subnetCompare(a.subnet, b.subnet)
}
newIdx, ok := slices.BinarySearchFunc(idx.listeners, l, cmpFunc)
diff --git a/internal/cmd/backend.go b/internal/cmd/backend.go
index 181456f..d37728e 100644
--- a/internal/cmd/backend.go
+++ b/internal/cmd/backend.go
@@ -6,7 +6,6 @@ import (
"log/slog"
"time"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
"github.com/AdguardTeam/AdGuardDNS/internal/billstat"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
@@ -14,6 +13,7 @@ import (
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/timeutil"
)
@@ -100,8 +100,9 @@ func newBillStatUploader(
mtrc backendpb.Metrics,
) (s billstat.Uploader, err error) {
apiURL := netutil.CloneURL(&envs.BillStatURL.URL)
- if !agdhttp.CheckGRPCURLScheme(apiURL.Scheme) {
- return nil, fmt.Errorf("invalid backend api url: %s", apiURL)
+ err = urlutil.ValidateGRPCURL(apiURL)
+ if err != nil {
+ return nil, fmt.Errorf("billstat api url: %w", err)
}
return backendpb.NewBillStat(&backendpb.BillStatConfig{
diff --git a/internal/cmd/builder.go b/internal/cmd/builder.go
index 7904eb7..a081d7e 100644
--- a/internal/cmd/builder.go
+++ b/internal/cmd/builder.go
@@ -6,6 +6,7 @@ import (
"log/slog"
"maps"
"net/netip"
+ "net/url"
"path"
"path/filepath"
"slices"
@@ -14,7 +15,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
"github.com/AdguardTeam/AdGuardDNS/internal/billstat"
@@ -38,9 +38,11 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
"github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
+ "github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
"github.com/AdguardTeam/AdGuardDNS/internal/websvc"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/osutil"
"github.com/AdguardTeam/golibs/service"
"github.com/c2h5oh/datasize"
@@ -112,6 +114,8 @@ type builder struct {
ruleStat rulestat.Interface
safeBrowsing *hashprefix.Filter
safeBrowsingHashes *hashprefix.Storage
+ sdeConf *dnsmsg.StructuredDNSErrorsConfig
+ tlsMtrc tlsconfig.Metrics
webSvc *websvc.Service
// The fields below are initialized later, just like with the fields above,
@@ -556,12 +560,42 @@ func (b *builder) initBindToDevice(ctx context.Context) (err error) {
return nil
}
+// Constants for the experimental Structured DNS Errors feature.
+//
+// TODO(a.garipov): Make configurable.
+const (
+ sdeJustification = "Filtered by AdGuard DNS"
+ sdeOrganization = "AdGuard DNS"
+)
+
+// Variables for the experimental Structured DNS Errors feature.
+//
+// TODO(a.garipov): Make configurable.
+var (
+ sdeContactURL = &url.URL{
+ Scheme: "mailto",
+ Opaque: "support@adguard-dns.io",
+ }
+)
+
// initMsgConstructor initializes the common DNS message constructor.
func (b *builder) initMsgConstructor(ctx context.Context) (err error) {
+ fltConf := b.conf.Filters
+ b.sdeConf = &dnsmsg.StructuredDNSErrorsConfig{
+ Contact: []*url.URL{
+ sdeContactURL,
+ },
+ Justification: sdeJustification,
+ Organization: sdeOrganization,
+ Enabled: fltConf.SDEEnabled,
+ }
+
b.messages, err = dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
Cloner: b.cloner,
BlockingMode: &dnsmsg.BlockingModeNullIP{},
- FilteredResponseTTL: b.conf.Filters.ResponseTTL.Duration,
+ StructuredErrors: b.sdeConf,
+ FilteredResponseTTL: fltConf.ResponseTTL.Duration,
+ EDEEnabled: fltConf.EDEEnabled,
})
if err != nil {
return fmt.Errorf("creating dns message constructor: %w", err)
@@ -579,8 +613,17 @@ func (b *builder) initMsgConstructor(ctx context.Context) (err error) {
// - [builder.initFilteringGroups]
// - [builder.initMsgConstructor]
func (b *builder) initServerGroups(ctx context.Context) (err error) {
+ mtrc, err := metrics.NewTLSConfig(b.mtrcNamespace, b.promRegisterer)
+ if err != nil {
+ return fmt.Errorf("registering tls metrics: %w", err)
+ }
+
+ b.tlsMtrc = mtrc
+
c := b.conf
b.serverGroups, err = c.ServerGroups.toInternal(
+ ctx,
+ mtrc,
b.messages,
b.btdManager,
b.filteringGroups,
@@ -671,7 +714,7 @@ func (b *builder) initTLS(ctx context.Context) (err error) {
}
}
- tickRot := newTicketRotator(b.baseLogger, b.errColl, b.serverGroups)
+ tickRot := newTicketRotator(b.baseLogger, b.errColl, b.tlsMtrc, b.serverGroups)
err = tickRot.Refresh(ctx)
if err != nil {
return fmt.Errorf("initial session ticket refresh: %w", err)
@@ -700,6 +743,29 @@ func (b *builder) initTLS(ctx context.Context) (err error) {
return nil
}
+// initGRPCMetrics initializes the gRPC metrics if necessary.
+func (b *builder) initGRPCMetrics(ctx context.Context) (err error) {
+ switch {
+ case
+ b.profilesEnabled,
+ b.conf.Check.RemoteKV.Type == kvModeBackend,
+ b.conf.RateLimit.Allowlist.Type == rlAllowlistTypeBackend:
+ // Go on.
+ default:
+ // Don't initialize the metrics if no protobuf backend is used.
+ return nil
+ }
+
+ b.backendGRPCMtrc, err = metrics.NewBackendPB(b.mtrcNamespace, b.promRegisterer)
+ if err != nil {
+ return fmt.Errorf("registering backendbp metrics: %w", err)
+ }
+
+ b.logger.DebugContext(ctx, "initialized grpc metrics")
+
+ return nil
+}
+
// initBillStat initializes the billing-statistics recorder if necessary. It
// also adds the refresher with ID [debugIDBillStat] to the debug refreshers.
func (b *builder) initBillStat(ctx context.Context) (err error) {
@@ -709,11 +775,6 @@ func (b *builder) initBillStat(ctx context.Context) (err error) {
return nil
}
- b.backendGRPCMtrc, err = metrics.NewBackendPB(b.mtrcNamespace, b.promRegisterer)
- if err != nil {
- return fmt.Errorf("registering backendbp metrics: %w", err)
- }
-
upl, err := newBillStatUploader(b.env, b.errColl, b.backendGRPCMtrc)
if err != nil {
return fmt.Errorf("creating billstat uploader: %w", err)
@@ -760,9 +821,9 @@ func (b *builder) initBillStat(ctx context.Context) (err error) {
// initProfileDB initializes the profile database if necessary.
//
-// [builder.initBillStat] and [builder.initServerGroups] must be called before
-// this method. It also adds the refresher with ID [debugIDProfileDB] to the
-// debug refreshers.
+// [builder.initGRPCMetrics] and [builder.initServerGroups] must be called
+// before this method. It also adds the refresher with ID [debugIDProfileDB] to
+// the debug refreshers.
func (b *builder) initProfileDB(ctx context.Context) (err error) {
if !b.profilesEnabled {
b.profileDB = &profiledb.Disabled{}
@@ -771,8 +832,9 @@ func (b *builder) initProfileDB(ctx context.Context) (err error) {
}
apiURL := netutil.CloneURL(&b.env.ProfilesURL.URL)
- if !agdhttp.CheckGRPCURLScheme(apiURL.Scheme) {
- return fmt.Errorf("invalid backend api url: %s", apiURL)
+ err = urlutil.ValidateGRPCURL(apiURL)
+ if err != nil {
+ return fmt.Errorf("profile api url: %w", err)
}
respSzEst := b.conf.RateLimit.ResponseSizeEstimate
@@ -842,7 +904,8 @@ func (b *builder) initProfileDB(ctx context.Context) (err error) {
// initDNSCheck initializes the DNS checker.
//
-// [builder.initMsgConstructor] must be called before this method.
+// [builder.initGRPCMetrics] and [builder.initMsgConstructor] must be called
+// before this method.
func (b *builder) initDNSCheck(ctx context.Context) (err error) {
b.dnsCheck = b.plugins.DNSCheck()
if b.dnsCheck != nil {
@@ -853,7 +916,14 @@ func (b *builder) initDNSCheck(ctx context.Context) (err error) {
c := b.conf.Check
- checkConf, err := c.toInternal(b.env, b.messages, b.errColl, b.mtrcNamespace, b.promRegisterer)
+ checkConf, err := c.toInternal(
+ b.env,
+ b.messages,
+ b.errColl,
+ b.mtrcNamespace,
+ b.promRegisterer,
+ b.backendGRPCMtrc,
+ )
if err != nil {
return fmt.Errorf("initializing dnscheck: %w", err)
}
@@ -911,18 +981,44 @@ func (b *builder) initRuleStat(ctx context.Context) (err error) {
// well as starts and registers the rate-limiter refresher in the signal
// handler. It also adds the refresher with ID [debugIDAllowlist] to the debug
// refreshers.
+//
+// [builder.initGRPCMetrics] must be called before this method.
func (b *builder) initRateLimiter(ctx context.Context) (err error) {
c := b.conf.RateLimit
allowSubnets := netutil.UnembedPrefixes(c.Allowlist.List)
allowlist := ratelimit.NewDynamicAllowlist(allowSubnets, nil)
- updater := consul.NewAllowlistUpdater(&consul.AllowlistUpdaterConfig{
- Logger: b.baseLogger.With(slogutil.KeyPrefix, "ratelimit_allowlist_updater"),
- Allowlist: allowlist,
- ConsulURL: &b.env.ConsulAllowlistURL.URL,
- ErrColl: b.errColl,
- // TODO(a.garipov): Make configurable.
- Timeout: 15 * time.Second,
- })
+
+ typ := b.conf.RateLimit.Allowlist.Type
+ mtrc, err := metrics.NewAllowlist(b.mtrcNamespace, b.promRegisterer, typ)
+ if err != nil {
+ return fmt.Errorf("ratelimit metrics: %w", err)
+ }
+
+ var updater agdservice.Refresher
+ if typ == rlAllowlistTypeBackend {
+ updater, err = backendpb.NewRateLimiter(&backendpb.RateLimiterConfig{
+ Logger: b.baseLogger.With(slogutil.KeyPrefix, "backend_ratelimiter"),
+ Metrics: mtrc,
+ GRPCMetrics: b.backendGRPCMtrc,
+ Allowlist: allowlist,
+ Endpoint: &b.env.BackendRateLimitURL.URL,
+ ErrColl: b.errColl,
+ APIKey: b.env.BackendRateLimitAPIKey,
+ })
+ if err != nil {
+ return fmt.Errorf("ratelimit: %w", err)
+ }
+ } else {
+ updater = consul.NewAllowlistUpdater(&consul.AllowlistUpdaterConfig{
+ Logger: b.baseLogger.With(slogutil.KeyPrefix, "ratelimit_allowlist_updater"),
+ Allowlist: allowlist,
+ ConsulURL: &b.env.ConsulAllowlistURL.URL,
+ ErrColl: b.errColl,
+ Metrics: mtrc,
+ // TODO(a.garipov): Make configurable.
+ Timeout: 15 * time.Second,
+ })
+ }
err = updater.Refresh(ctx)
if err != nil {
@@ -956,9 +1052,11 @@ func (b *builder) initRateLimiter(ctx context.Context) (err error) {
// initWeb initializes the web service, starts it, and registers it in the
// signal handler.
+//
+// [builder.initServerGroups] must be called before this method.
func (b *builder) initWeb(ctx context.Context) (err error) {
c := b.conf.Web
- webConf, err := c.toInternal(b.env, b.dnsCheck, b.errColl)
+ webConf, err := c.toInternal(ctx, b.env, b.dnsCheck, b.errColl, b.tlsMtrc)
if err != nil {
return fmt.Errorf("converting web configuration: %w", err)
}
@@ -1057,45 +1155,55 @@ func (b *builder) initDNS(ctx context.Context) (err error) {
b.fwdHandler = forward.NewHandler(b.conf.Upstream.toInternal(b.baseLogger))
b.dnsDB = b.conf.DNSDB.toInternal(b.errColl)
- cacheConf := b.conf.Cache
- dnsConf := &dnssvc.Config{
+ dnsHdlrsConf := &dnssvc.HandlersConfig{
BaseLogger: b.baseLogger,
- Messages: b.messages,
+ Cache: b.conf.Cache.toInternal(),
Cloner: b.cloner,
- ControlConf: b.controlConf,
- ConnLimiter: b.connLimit,
HumanIDParser: agd.NewHumanIDParser(),
+ Messages: b.messages,
PluginRegistry: b.plugins,
+ StructuredErrors: b.sdeConf,
AccessManager: b.access,
- SafeBrowsing: b.hashMatcher,
BillStat: b.billStat,
CacheManager: b.cacheManager,
- ProfileDB: b.profileDB,
- PrometheusRegisterer: b.promRegisterer,
DNSCheck: b.dnsCheck,
- NonDNS: b.webSvc,
DNSDB: b.dnsDB,
ErrColl: b.errColl,
FilterStorage: b.filterStorage,
GeoIP: b.geoIP,
Handler: b.fwdHandler,
+ HashMatcher: b.hashMatcher,
+ ProfileDB: b.profileDB,
+ PrometheusRegisterer: b.promRegisterer,
QueryLog: b.queryLog(),
- RuleStat: b.ruleStat,
RateLimit: b.rateLimit,
+ RuleStat: b.ruleStat,
MetricsNamespace: b.mtrcNamespace,
FilteringGroups: b.filteringGroups,
ServerGroups: b.serverGroups,
- HandleTimeout: b.conf.DNS.HandleTimeout.Duration,
- CacheSize: cacheConf.Size,
- ECSCacheSize: cacheConf.ECSSize,
- CacheMinTTL: cacheConf.TTLOverride.Min.Duration,
- UseCacheTTLOverride: cacheConf.TTLOverride.Enabled,
- UseECSCache: cacheConf.Type == cacheTypeECS,
+ EDEEnabled: b.conf.Filters.EDEEnabled,
+ }
+
+ dnsHdlrs, err := dnssvc.NewHandlers(ctx, dnsHdlrsConf)
+ if err != nil {
+ return fmt.Errorf("dns handlers: %w", err)
+ }
+
+ dnsConf := &dnssvc.Config{
+ Handlers: dnsHdlrs,
+ Cloner: b.cloner,
+ ControlConf: b.controlConf,
+ ConnLimiter: b.connLimit,
+ NonDNS: b.webSvc,
+ ErrColl: b.errColl,
+ MetricsNamespace: b.mtrcNamespace,
+ ServerGroups: b.serverGroups,
+ HandleTimeout: b.conf.DNS.HandleTimeout.Duration,
}
b.dnsSvc, err = dnssvc.New(dnsConf)
if err != nil {
- return fmt.Errorf("initializing dns: %w", err)
+ return fmt.Errorf("dns service: %w", err)
}
b.logger.DebugContext(ctx, "initialized dns")
diff --git a/internal/cmd/cache.go b/internal/cmd/cache.go
index fd9d483..ef222a7 100644
--- a/internal/cmd/cache.go
+++ b/internal/cmd/cache.go
@@ -3,6 +3,7 @@ package cmd
import (
"fmt"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/timeutil"
)
@@ -43,6 +44,28 @@ const (
cacheTypeSimple = "simple"
)
+// toInternal converts c to the cache configuration for the DNS server. c must
+// be valid.
+func (c *cacheConfig) toInternal() (cacheConf *dnssvc.CacheConfig) {
+ var typ dnssvc.CacheType
+ if c.Size == 0 {
+ // TODO(a.garipov): Add as a type in the configuration file.
+ typ = dnssvc.CacheTypeNone
+ } else if c.Type == cacheTypeSimple {
+ typ = dnssvc.CacheTypeSimple
+ } else {
+ typ = dnssvc.CacheTypeECS
+ }
+
+ return &dnssvc.CacheConfig{
+ MinTTL: c.TTLOverride.Min.Duration,
+ ECSCount: c.ECSSize,
+ NoECSCount: c.Size,
+ Type: typ,
+ OverrideCacheTTL: c.TTLOverride.Enabled,
+ }
+}
+
// type check
var _ validator = (*cacheConfig)(nil)
diff --git a/internal/cmd/check.go b/internal/cmd/check.go
index 5075cf8..142f771 100644
--- a/internal/cmd/check.go
+++ b/internal/cmd/check.go
@@ -7,6 +7,7 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
+ "github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
@@ -54,8 +55,9 @@ func (c *checkConfig) toInternal(
errColl errcoll.Interface,
namespace string,
reg prometheus.Registerer,
+ backendMtrc backendpb.Metrics,
) (conf *dnscheck.RemoteKVConfig, err error) {
- kv, err := newDNSCheckKV(c, envs, namespace, reg)
+ kv, err := newRemoteKV(c.RemoteKV, envs, namespace, reg, backendMtrc)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return nil, err
@@ -85,21 +87,33 @@ const maxRespSize = 1 * datasize.MB
// [remotekv.KeyNamespace].
const keyNamespaceCheck = "check"
-// newDNSCheckKV returns a new properly initialized remote key-value storage.
-func newDNSCheckKV(
- conf *checkConfig,
+// newRemoteKV returns a new properly initialized remote key-value storage.
+func newRemoteKV(
+ c *remoteKVConfig,
envs *environment,
namespace string,
reg prometheus.Registerer,
+ backendMtrc backendpb.Metrics,
) (kv remotekv.Interface, err error) {
- if conf.RemoteKV.Type == kvModeRedis {
+ switch c.Type {
+ case kvModeBackend:
+ kv, err = backendpb.NewRemoteKV(&backendpb.RemoteKVConfig{
+ Metrics: backendMtrc,
+ Endpoint: &envs.DNSCheckRemoteKVURL.URL,
+ APIKey: envs.DNSCheckRemoteKVAPIKey,
+ TTL: c.TTL.Duration,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("initializing backend dnscheck kv: %w", err)
+ }
+ case kvModeRedis:
var redisKVMtrc rediskv.Metrics
redisKVMtrc, err = metrics.NewRedisKV(namespace, reg)
if err != nil {
return nil, fmt.Errorf("registering redis kv metrics: %w", err)
}
- kv := rediskv.NewRedisKV(&rediskv.RedisKVConfig{
+ redisKV := rediskv.NewRedisKV(&rediskv.RedisKVConfig{
Metrics: redisKVMtrc,
Addr: &netutil.HostPort{
Host: envs.RedisAddr,
@@ -108,18 +122,20 @@ func newDNSCheckKV(
MaxActive: envs.RedisMaxActive,
MaxIdle: envs.RedisMaxIdle,
IdleTimeout: envs.RedisIdleTimeout.Duration,
- TTL: conf.RemoteKV.TTL.Duration,
+ TTL: c.TTL.Duration,
})
- return remotekv.NewKeyNamespace(&remotekv.KeyNamespaceConfig{
- KV: kv,
+ kv = remotekv.NewKeyNamespace(&remotekv.KeyNamespaceConfig{
+ KV: redisKV,
Prefix: fmt.Sprintf("%s:%s:", envs.RedisKeyPrefix, keyNamespaceCheck),
- }), nil
- }
+ })
+ case kvModeConsul:
+ consulKVURL := envs.ConsulDNSCheckKVURL
+ consulSessionURL := envs.ConsulDNSCheckSessionURL
+ if consulKVURL == nil || consulSessionURL == nil {
+ return remotekv.Empty{}, nil
+ }
- consulKVURL := envs.ConsulDNSCheckKVURL
- consulSessionURL := envs.ConsulDNSCheckSessionURL
- if consulKVURL != nil && consulSessionURL != nil {
kv, err = consulkv.NewKV(&consulkv.Config{
URL: &consulKVURL.URL,
SessionURL: &consulSessionURL.URL,
@@ -129,14 +145,14 @@ func newDNSCheckKV(
}),
// TODO(ameshkov): Consider making configurable.
Limiter: rate.NewLimiter(rate.Limit(200)/60, 1),
- TTL: conf.RemoteKV.TTL.Duration,
+ TTL: c.TTL.Duration,
MaxRespSize: maxRespSize,
})
if err != nil {
- return nil, fmt.Errorf("initializing consul dnscheck: %w", err)
+ return nil, fmt.Errorf("initializing consul dnscheck kv: %w", err)
}
- } else {
- kv = remotekv.Empty{}
+ default:
+ return remotekv.Empty{}, nil
}
return kv, nil
@@ -221,15 +237,16 @@ func validateNonNilIPs(ips []netip.Addr, fam netutil.AddrFamily) (err error) {
// DNSCheck key-value database modes.
const (
- kvModeConsul = "consul"
- kvModeRedis = "redis"
+ kvModeBackend = "backend"
+ kvModeConsul = "consul"
+ kvModeRedis = "redis"
)
// remoteKVConfig is remote key-value store configuration for DNS server
// checking.
type remoteKVConfig struct {
// Type defines the type of remote key-value store. Allowed values are
- // [kvModeConsul] and [kvModeRedis].
+ // [kvModeBackend], [kvModeConsul] and [kvModeRedis].
Type string `yaml:"type"`
// TTL defines, for how long to keep the information about a single client.
@@ -248,6 +265,10 @@ func (c *remoteKVConfig) validate() (err error) {
ttl := c.TTL
switch c.Type {
+ case kvModeBackend:
+ if ttl.Duration <= 0 {
+ return newNotPositiveError("ttl", ttl)
+ }
case kvModeConsul:
if ttl.Duration < consulkv.MinTTL || ttl.Duration > consulkv.MaxTTL {
return fmt.Errorf(
@@ -270,7 +291,7 @@ func (c *remoteKVConfig) validate() (err error) {
case "":
return fmt.Errorf("type: %w", errors.ErrEmptyValue)
default:
- return fmt.Errorf("type: %q: %w", c.Type, errors.ErrBadEnumValue)
+ return fmt.Errorf("type: %w: %q", errors.ErrBadEnumValue, c.Type)
}
return nil
diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go
index ad342fc..f66aba5 100644
--- a/internal/cmd/cmd.go
+++ b/internal/cmd/cmd.go
@@ -100,6 +100,8 @@ func Main(plugins *plugin.Registry) {
errors.Check(b.initTLS(ctx))
+ errors.Check(b.initGRPCMetrics(ctx))
+
errors.Check(b.initBillStat(ctx))
errors.Check(b.initProfileDB(ctx))
diff --git a/internal/cmd/env.go b/internal/cmd/env.go
index a469de2..ff5f027 100644
--- a/internal/cmd/env.go
+++ b/internal/cmd/env.go
@@ -6,9 +6,10 @@ import (
"math"
"net"
"net/http"
+ "net/url"
"os"
+ "strings"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/debugsvc"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
@@ -25,13 +26,17 @@ import (
)
// environment represents the configuration that is kept in the environment.
+//
+// TODO(e.burkov, a.garipov): Name variables more consistently.
type environment struct {
AdultBlockingURL *urlutil.URL `env:"ADULT_BLOCKING_URL"`
+ BackendRateLimitURL *urlutil.URL `env:"BACKEND_RATELIMIT_URL"`
BillStatURL *urlutil.URL `env:"BILLSTAT_URL"`
BlockedServiceIndexURL *urlutil.URL `env:"BLOCKED_SERVICE_INDEX_URL"`
- ConsulAllowlistURL *urlutil.URL `env:"CONSUL_ALLOWLIST_URL,notEmpty"`
+ ConsulAllowlistURL *urlutil.URL `env:"CONSUL_ALLOWLIST_URL"`
ConsulDNSCheckKVURL *urlutil.URL `env:"CONSUL_DNSCHECK_KV_URL"`
ConsulDNSCheckSessionURL *urlutil.URL `env:"CONSUL_DNSCHECK_SESSION_URL"`
+ DNSCheckRemoteKVURL *urlutil.URL `env:"DNSCHECK_REMOTEKV_URL"`
FilterIndexURL *urlutil.URL `env:"FILTER_INDEX_URL,notEmpty"`
GeneralSafeSearchURL *urlutil.URL `env:"GENERAL_SAFE_SEARCH_URL"`
LinkedIPTargetURL *urlutil.URL `env:"LINKED_IP_TARGET_URL"`
@@ -41,23 +46,25 @@ type environment struct {
SafeBrowsingURL *urlutil.URL `env:"SAFE_BROWSING_URL"`
YoutubeSafeSearchURL *urlutil.URL `env:"YOUTUBE_SAFE_SEARCH_URL"`
- BillStatAPIKey string `env:"BILLSTAT_API_KEY"`
- ConfPath string `env:"CONFIG_PATH" envDefault:"./config.yaml"`
- FilterCachePath string `env:"FILTER_CACHE_PATH" envDefault:"./filters/"`
- GeoIPASNPath string `env:"GEOIP_ASN_PATH" envDefault:"./asn.mmdb"`
- GeoIPCountryPath string `env:"GEOIP_COUNTRY_PATH" envDefault:"./country.mmdb"`
- ProfilesAPIKey string `env:"PROFILES_API_KEY"`
- ProfilesCachePath string `env:"PROFILES_CACHE_PATH" envDefault:"./profilecache.pb"`
- RedisAddr string `env:"REDIS_ADDR"`
- RedisKeyPrefix string `env:"REDIS_KEY_PREFIX" envDefault:"agdns"`
- QueryLogPath string `env:"QUERYLOG_PATH" envDefault:"./querylog.jsonl"`
- SSLKeyLogFile string `env:"SSL_KEY_LOG_FILE"`
- SentryDSN string `env:"SENTRY_DSN" envDefault:"stderr"`
- WebStaticDir string `env:"WEB_STATIC_DIR"`
+ BackendRateLimitAPIKey string `env:"BACKEND_RATELIMIT_API_KEY"`
+ BillStatAPIKey string `env:"BILLSTAT_API_KEY"`
+ ConfPath string `env:"CONFIG_PATH" envDefault:"./config.yaml"`
+ DNSCheckRemoteKVAPIKey string `env:"DNSCHECK_REMOTEKV_API_KEY"`
+ FilterCachePath string `env:"FILTER_CACHE_PATH" envDefault:"./filters/"`
+ GeoIPASNPath string `env:"GEOIP_ASN_PATH" envDefault:"./asn.mmdb"`
+ GeoIPCountryPath string `env:"GEOIP_COUNTRY_PATH" envDefault:"./country.mmdb"`
+ ProfilesAPIKey string `env:"PROFILES_API_KEY"`
+ ProfilesCachePath string `env:"PROFILES_CACHE_PATH" envDefault:"./profilecache.pb"`
+ RedisAddr string `env:"REDIS_ADDR"`
+ RedisKeyPrefix string `env:"REDIS_KEY_PREFIX" envDefault:"agdns"`
+ QueryLogPath string `env:"QUERYLOG_PATH" envDefault:"./querylog.jsonl"`
+ SSLKeyLogFile string `env:"SSL_KEY_LOG_FILE"`
+ SentryDSN string `env:"SENTRY_DSN" envDefault:"stderr"`
+ WebStaticDir string `env:"WEB_STATIC_DIR"`
ListenAddr net.IP `env:"LISTEN_ADDR" envDefault:"127.0.0.1"`
- ProfilesMaxRespSize datasize.ByteSize `env:"PROFILES_MAX_RESP_SIZE" envDefault:"8MB"`
+ ProfilesMaxRespSize datasize.ByteSize `env:"PROFILES_MAX_RESP_SIZE" envDefault:"64MB"`
RedisIdleTimeout timeutil.Duration `env:"REDIS_IDLE_TIMEOUT" envDefault:"30s"`
@@ -100,7 +107,8 @@ func (envs *environment) validate() (err error) {
errs = envs.validateHTTPURLs(errs)
- if s := envs.FilterIndexURL.Scheme; s != agdhttp.SchemeFile && !agdhttp.CheckHTTPURLScheme(s) {
+ if s := envs.FilterIndexURL.Scheme; !strings.EqualFold(s, urlutil.SchemeFile) &&
+ !urlutil.IsValidHTTPURLScheme(s) {
errs = append(errs, fmt.Errorf(
"env %s: not a valid http(s) url or file uri",
"FILTER_INDEX_URL",
@@ -140,10 +148,6 @@ func (envs *environment) validateHTTPURLs(errs []error) (res []error) {
url: envs.BlockedServiceIndexURL,
name: "BLOCKED_SERVICE_INDEX_URL",
isRequired: bool(envs.BlockedServiceEnabled),
- }, {
- url: envs.ConsulAllowlistURL,
- name: "CONSUL_ALLOWLIST_URL",
- isRequired: true,
}, {
url: envs.ConsulDNSCheckKVURL,
name: "CONSUL_DNSCHECK_KV_URL",
@@ -184,15 +188,14 @@ func (envs *environment) validateHTTPURLs(errs []error) (res []error) {
continue
}
- u := urlData.url
- if u == nil {
- res = append(res, fmt.Errorf("env %s: %w", urlData.name, errors.ErrEmptyValue))
-
- continue
+ var u *url.URL
+ if urlData.url != nil {
+ u = &urlData.url.URL
}
- if !agdhttp.CheckHTTPURLScheme(u.Scheme) {
- res = append(res, fmt.Errorf("env %s: not a valid http(s) url", urlData.name))
+ err := urlutil.ValidateHTTPURL(u)
+ if err != nil {
+ res = append(res, fmt.Errorf("env %s: %w", urlData.name, err))
}
}
@@ -227,59 +230,86 @@ func (envs *environment) validateWebStaticDir() (err error) {
// validateFromValidConfig returns an error if environment variables that depend
// on configuration properties contain errors. conf is expected to be valid.
func (envs *environment) validateFromValidConfig(conf *configuration) (err error) {
- err = envs.validateRedis(conf)
- if err != nil {
- // Don't wrap the error, because it's informative enough as is.
- return err
- }
-
- if !conf.isProfilesEnabled() {
- return nil
- }
-
- if envs.ProfilesMaxRespSize > math.MaxInt {
- return fmt.Errorf(
- "PROFILES_MAX_RESP_SIZE: %w: must be less than or equal to %s, got %s",
- errors.ErrOutOfRange,
- datasize.ByteSize(math.MaxInt),
- envs.ProfilesMaxRespSize,
- )
- }
-
- return envs.validateProfilesURLs()
-}
-
-// validateRedis returns an error if environment variables for Redis as a remote
-// key-value store for DNS server checking contain errors.
-func (envs *environment) validateRedis(conf *configuration) (err error) {
- if conf.Check.RemoteKV.Type != kvModeRedis {
- return nil
- }
-
var errs []error
- if envs.RedisAddr == "" {
- errs = append(errs, fmt.Errorf("REDIS_ADDR: %q", errors.ErrEmptyValue))
+
+ switch typ := conf.Check.RemoteKV.Type; typ {
+ case kvModeRedis:
+ errs = envs.validateRedis(errs)
+ case kvModeBackend:
+ errs = envs.validateBackendKV(errs)
+ default:
+ // Probably consul.
}
- if envs.RedisIdleTimeout.Duration <= 0 {
- errs = append(errs, newNotPositiveError("REDIS_IDLE_TIMEOUT", envs.RedisIdleTimeout))
+ if conf.isProfilesEnabled() {
+ errs = envs.validateProfilesURLs(errs)
+
+ if envs.ProfilesMaxRespSize > math.MaxInt {
+ errs = append(errs, fmt.Errorf(
+ "PROFILES_MAX_RESP_SIZE: %w: must be less than or equal to %s, got %s",
+ errors.ErrOutOfRange,
+ datasize.ByteSize(math.MaxInt),
+ envs.ProfilesMaxRespSize,
+ ))
+ }
}
- if envs.RedisMaxActive < 0 {
- errs = append(errs, newNegativeError("REDIS_MAX_ACTIVE", envs.RedisMaxActive))
- }
-
- if envs.RedisMaxIdle < 0 {
- errs = append(errs, newNegativeError("REDIS_MAX_IDLE", envs.RedisMaxIdle))
- }
+ errs = envs.validateRateLimitURLs(conf, errs)
return errors.Join(errs...)
}
+// validateRedis appends validation errors to the given errs if environment
+// variables for Redis contain errors.
+func (envs *environment) validateRedis(errs []error) (withRedis []error) {
+ withRedis = errs
+
+ if envs.RedisAddr == "" {
+ err := fmt.Errorf("REDIS_ADDR: %q", errors.ErrEmptyValue)
+ withRedis = append(withRedis, err)
+ }
+
+ if envs.RedisIdleTimeout.Duration <= 0 {
+ err := newNotPositiveError("REDIS_IDLE_TIMEOUT", envs.RedisIdleTimeout)
+ withRedis = append(withRedis, err)
+ }
+
+ if envs.RedisMaxActive < 0 {
+ err := newNegativeError("REDIS_MAX_ACTIVE", envs.RedisMaxActive)
+ withRedis = append(withRedis, err)
+ }
+
+ if envs.RedisMaxIdle < 0 {
+ err := newNegativeError("REDIS_MAX_IDLE", envs.RedisMaxIdle)
+ withRedis = append(withRedis, err)
+ }
+
+ return withRedis
+}
+
+// validateBackendKV appends validation errors to the given errs if environment
+// variables for a backend key-value store contain errors.
+func (envs *environment) validateBackendKV(errs []error) (withKV []error) {
+ withKV = errs
+
+ var u *url.URL
+ if envs.DNSCheckRemoteKVURL != nil {
+ u = &envs.DNSCheckRemoteKVURL.URL
+ }
+
+ err := urlutil.ValidateGRPCURL(u)
+ if err != nil {
+ withKV = append(withKV, fmt.Errorf("env DNSCHECK_REMOTEKV_URL: %w", err))
+ }
+
+ return withKV
+}
+
// validateProfilesURLs appends validation errors to the given errs if profiles
-// URLs in environment variables are invalid. All errors are appended to errs
-// and returned as res.
-func (envs *environment) validateProfilesURLs() (err error) {
+// URLs in environment variables are invalid.
+func (envs *environment) validateProfilesURLs(errs []error) (withURLs []error) {
+ withURLs = errs
+
grpcOnlyURLs := []*urlEnvData{{
url: envs.BillStatURL,
name: "BILLSTAT_URL",
@@ -290,24 +320,52 @@ func (envs *environment) validateProfilesURLs() (err error) {
isRequired: true,
}}
- var res []error
for _, urlData := range grpcOnlyURLs {
if !urlData.isRequired {
continue
}
- if urlData.url == nil {
- res = append(res, fmt.Errorf("env %s: %w", urlData.name, errors.ErrEmptyValue))
-
- continue
+ var u *url.URL
+ if urlData.url != nil {
+ u = &urlData.url.URL
}
- if !agdhttp.CheckGRPCURLScheme(urlData.url.Scheme) {
- res = append(res, fmt.Errorf("env %s: not a valid grpc(s) url", urlData.name))
+ err := urlutil.ValidateGRPCURL(u)
+ if err != nil {
+ withURLs = append(withURLs, fmt.Errorf("env %s: %w", urlData.name, err))
}
}
- return errors.Join(res...)
+ return withURLs
+}
+
+// validateRateLimitURLs appends validation errors to the given errs if rate
+// limit URLs in environment variables are invalid.
+func (envs *environment) validateRateLimitURLs(
+ conf *configuration,
+ errs []error,
+) (withURLs []error) {
+ rlURL := envs.BackendRateLimitURL
+ rlEnv := "BACKEND_RATELIMIT_URL"
+ validateFunc := urlutil.ValidateGRPCURL
+
+ if conf.RateLimit.Allowlist.Type == rlAllowlistTypeConsul {
+ rlURL = envs.ConsulAllowlistURL
+ rlEnv = "CONSUL_ALLOWLIST_URL"
+ validateFunc = urlutil.ValidateHTTPURL
+ }
+
+ var u *url.URL
+ if rlURL != nil {
+ u = &rlURL.URL
+ }
+
+ err := validateFunc(u)
+ if err != nil {
+ return append(errs, fmt.Errorf("env %s: %w", rlEnv, err))
+ }
+
+ return errs
}
// configureLogs sets the configuration for the plain text logs. It also
diff --git a/internal/cmd/filter.go b/internal/cmd/filter.go
index c7e8acf..ee27585 100644
--- a/internal/cmd/filter.go
+++ b/internal/cmd/filter.go
@@ -58,6 +58,12 @@ type filtersConfig struct {
// MaxSize is the maximum size of the downloadable filtering rule-list.
MaxSize datasize.ByteSize `yaml:"max_size"`
+
+ // EDEEnabled enables the Extended DNS Errors feature.
+ EDEEnabled bool `yaml:"ede_enabled"`
+
+ // SDEEnabled enables the experimental Structured DNS Errors feature.
+ SDEEnabled bool `yaml:"sde_enabled"`
}
// toInternal converts c to the filter storage configuration for the DNS server.
@@ -117,33 +123,31 @@ var _ validator = (*filtersConfig)(nil)
// validate implements the [validator] interface for *filtersConfig.
func (c *filtersConfig) validate() (err error) {
- switch {
- case c == nil:
+ if c == nil {
return errors.ErrNoValue
- case c.SafeSearchCacheSize <= 0:
- return newNotPositiveError("safe_search_cache_size", c.SafeSearchCacheSize)
- case c.ResponseTTL.Duration <= 0:
- return newNotPositiveError("response_ttl", c.ResponseTTL)
- case c.RefreshIvl.Duration <= 0:
- return newNotPositiveError("refresh_interval", c.RefreshIvl)
- case c.RefreshTimeout.Duration <= 0:
- return newNotPositiveError("refresh_timeout", c.RefreshTimeout)
- case c.IndexRefreshTimeout.Duration <= 0:
- return newNotPositiveError("index_refresh_timeout", c.IndexRefreshTimeout)
- case c.RuleListRefreshTimeout.Duration <= 0:
- return newNotPositiveError("rule_list_refresh_timeout", c.RuleListRefreshTimeout)
- case c.MaxSize <= 0:
- return newNotPositiveError("max_size", c.MaxSize)
- default:
- // Go on.
+ }
+
+ errs := []error{
+ validatePositive("custom_filter_cache_size", c.CustomFilterCacheSize),
+ validatePositive("safe_search_cache_size", c.SafeSearchCacheSize),
+ validatePositive("response_ttl", c.ResponseTTL),
+ validatePositive("refresh_interval", c.RefreshIvl),
+ validatePositive("refresh_timeout", c.RefreshTimeout),
+ validatePositive("index_refresh_timeout", c.IndexRefreshTimeout),
+ validatePositive("rule_list_refresh_timeout", c.RuleListRefreshTimeout),
+ validatePositive("max_size", c.MaxSize),
+ }
+
+ if !c.EDEEnabled && c.SDEEnabled {
+ errs = append(errs, errors.Error("ede must be enabled to enable sde"))
}
err = c.RuleListCache.validate()
if err != nil {
- return fmt.Errorf("rule_list_cache: %w", err)
+ errs = append(errs, fmt.Errorf("rule_list_cache: %w", err))
}
- return nil
+ return errors.Join(errs...)
}
// fltRuleListCache contains filtering rule-list cache configuration.
diff --git a/internal/cmd/plugin/plugin.go b/internal/cmd/plugin/plugin.go
index 1405247..e3f2b1b 100644
--- a/internal/cmd/plugin/plugin.go
+++ b/internal/cmd/plugin/plugin.go
@@ -4,6 +4,7 @@ package plugin
import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
)
@@ -13,16 +14,19 @@ import (
type Registry struct {
dnscheck dnscheck.Interface
mainMwMtrc metrics.MainMiddleware
+ postInitMw dnsserver.Middleware
}
// NewRegistry returns a new registry with the given custom implementations.
func NewRegistry(
dnsCk dnscheck.Interface,
mainMwMtrc metrics.MainMiddleware,
+ postInitMw dnsserver.Middleware,
) (r *Registry) {
return &Registry{
dnscheck: dnsCk,
mainMwMtrc: mainMwMtrc,
+ postInitMw: postInitMw,
}
}
@@ -44,3 +48,13 @@ func (r *Registry) MainMiddlewareMetrics() (mainMwMtrc metrics.MainMiddleware) {
return r.mainMwMtrc
}
+
+// PostInitialMiddleware returns a custom implementation of the post-initial
+// middleware, if any.
+func (r *Registry) PostInitialMiddleware() (postInitMw dnsserver.Middleware) {
+ if r == nil {
+ return nil
+ }
+
+ return r.postInitMw
+}
diff --git a/internal/cmd/ratelimit.go b/internal/cmd/ratelimit.go
index 9a14929..b107f20 100644
--- a/internal/cmd/ratelimit.go
+++ b/internal/cmd/ratelimit.go
@@ -15,6 +15,12 @@ import (
"github.com/c2h5oh/datasize"
)
+// Constants for rate limit settings endpoints.
+const (
+ rlAllowlistTypeBackend = "backend"
+ rlAllowlistTypeConsul = "consul"
+)
+
// rateLimitConfig is the configuration of the instance's rate limiting.
type rateLimitConfig struct {
// AllowList is the allowlist of clients.
@@ -57,20 +63,14 @@ type rateLimitConfig struct {
RefuseANY bool `yaml:"refuse_any"`
}
-// allowListConfig is the consul allow list configuration.
-type allowListConfig struct {
- // List contains IPs and CIDRs.
- List []netutil.Prefix `yaml:"list"`
-
- // RefreshIvl time between two updates of allow list from the Consul URL.
- RefreshIvl timeutil.Duration `yaml:"refresh_interval"`
-}
-
// rateLimitOptions allows define maximum number of requests for IPv4 or IPv6
// addresses.
type rateLimitOptions struct {
- // RPS is the maximum number of requests per second.
- RPS uint `yaml:"rps"`
+ // Count is the maximum number of requests per interval.
+ Count uint `yaml:"count"`
+
+ // Interval is the time during which to count the number of requests.
+ Interval timeutil.Duration `yaml:"interval"`
// SubnetKeyLen is the length of the subnet prefix used to calculate
// rate limiter bucket keys.
@@ -87,7 +87,8 @@ func (o *rateLimitOptions) validate() (err error) {
}
return cmp.Or(
- validatePositive("rps", o.RPS),
+ validatePositive("count", o.Count),
+ validatePositive("interval", o.Interval),
validatePositive("subnet_key_len", o.SubnetKeyLen),
)
}
@@ -100,9 +101,11 @@ func (c *rateLimitConfig) toInternal(al ratelimit.Allowlist) (conf *ratelimit.Ba
ResponseSizeEstimate: c.ResponseSizeEstimate,
Duration: c.BackoffDuration.Duration,
Period: c.BackoffPeriod.Duration,
- IPv4RPS: c.IPv4.RPS,
+ IPv4Count: c.IPv4.Count,
+ IPv4Interval: c.IPv4.Interval.Duration,
IPv4SubnetKeyLen: c.IPv4.SubnetKeyLen,
- IPv6RPS: c.IPv6.RPS,
+ IPv6Count: c.IPv6.Count,
+ IPv6Interval: c.IPv6.Interval.Duration,
IPv6SubnetKeyLen: c.IPv6.SubnetKeyLen,
Count: c.BackoffCount,
RefuseANY: c.RefuseANY,
@@ -114,14 +117,12 @@ var _ validator = (*rateLimitConfig)(nil)
// validate implements the [validator] interface for *rateLimitConfig.
func (c *rateLimitConfig) validate() (err error) {
- switch {
- case c == nil:
+ if c == nil {
return errors.ErrNoValue
- case c.Allowlist == nil:
- return fmt.Errorf("allowlist: %w", errors.ErrNoValue)
}
return cmp.Or(
+ validateProp("allowlist", c.Allowlist.validate),
validateProp("connection_limit", c.ConnectionLimit.validate),
validateProp("ipv4", c.IPv4.validate),
validateProp("ipv6", c.IPv6.validate),
@@ -131,10 +132,41 @@ func (c *rateLimitConfig) validate() (err error) {
validatePositive("backoff_duration", c.BackoffDuration),
validatePositive("backoff_period", c.BackoffPeriod),
validatePositive("response_size_estimate", c.ResponseSizeEstimate),
- validatePositive("allowlist.refresh_interval", c.Allowlist.RefreshIvl),
)
}
+// allowListConfig is the consul allow list configuration.
+type allowListConfig struct {
+ // Type defines where the rate limit settings are received from. Allowed
+ // values are [rlAllowlistTypeBackend] and [rlAllowlistTypeConsul].
+ Type string `yaml:"type"`
+
+ // List contains IPs and CIDRs.
+ List []netutil.Prefix `yaml:"list"`
+
+ // RefreshIvl time between two updates of allow list from the Consul URL.
+ RefreshIvl timeutil.Duration `yaml:"refresh_interval"`
+}
+
+// type check
+var _ validator = (*allowListConfig)(nil)
+
+// validate implements the [validator] interface for *allowListConfig.
+func (c *allowListConfig) validate() (err error) {
+ if c == nil {
+ return errors.ErrNoValue
+ }
+
+ switch c.Type {
+ case rlAllowlistTypeBackend, rlAllowlistTypeConsul:
+ // Go on.
+ default:
+ return fmt.Errorf("type: %w: %q", errors.ErrBadEnumValue, c.Type)
+ }
+
+ return validatePositive("refresh_interval", c.RefreshIvl)
+}
+
// connLimitConfig is the configuration structure for the stream-connection
// limiter.
type connLimitConfig struct {
diff --git a/internal/cmd/server.go b/internal/cmd/server.go
index 334f530..11bb88a 100644
--- a/internal/cmd/server.go
+++ b/internal/cmd/server.go
@@ -6,7 +6,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/bindtodevice"
- "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors"
)
@@ -14,6 +14,7 @@ import (
// toInternal returns the configuration of DNS servers for a single server
// group. srvs and other parts of the configuration must be valid.
func (srvs servers) toInternal(
+ mtrc tlsconfig.Metrics,
tlsConfig *agd.TLS,
btdMgr *bindtodevice.Manager,
ratelimitConf *rateLimitConfig,
@@ -68,8 +69,8 @@ func (srvs servers) toInternal(
tlsConf := tlsConfig.Conf.Clone()
// Attach the functions that will count TLS handshake metrics.
- tlsConf.GetConfigForClient = metrics.TLSMetricsBeforeHandshake(string(srv.Protocol))
- tlsConf.VerifyConnection = metrics.TLSMetricsAfterHandshake(
+ tlsConf.GetConfigForClient = mtrc.BeforeHandshake(string(srv.Protocol))
+ tlsConf.VerifyConnection = mtrc.AfterHandshake(
string(srv.Protocol),
srv.Name,
tlsConfig.DeviceDomains,
diff --git a/internal/cmd/servergroup.go b/internal/cmd/servergroup.go
index 3ad9b52..6c9dea4 100644
--- a/internal/cmd/servergroup.go
+++ b/internal/cmd/servergroup.go
@@ -1,11 +1,13 @@
package cmd
import (
+ "context"
"fmt"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/bindtodevice"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors"
)
@@ -17,6 +19,8 @@ type serverGroups []*serverGroup
// toInternal returns the configuration for all server groups in the DNS
// service. srvGrps and other parts of the configuration must be valid.
func (srvGrps serverGroups) toInternal(
+ ctx context.Context,
+ mtrc tlsconfig.Metrics,
messages *dnsmsg.Constructor,
btdMgr *bindtodevice.Manager,
fltGrps map[agd.FilteringGroupID]*agd.FilteringGroup,
@@ -32,7 +36,7 @@ func (srvGrps serverGroups) toInternal(
}
var tlsConf *agd.TLS
- tlsConf, err = g.TLS.toInternal()
+ tlsConf, err = g.TLS.toInternal(ctx, mtrc)
if err != nil {
return nil, fmt.Errorf("tls: %w", err)
}
@@ -45,7 +49,13 @@ func (srvGrps serverGroups) toInternal(
ProfilesEnabled: g.ProfilesEnabled,
}
- svcSrvGrps[i].Servers, err = g.Servers.toInternal(tlsConf, btdMgr, ratelimitConf, dnsConf)
+ svcSrvGrps[i].Servers, err = g.Servers.toInternal(
+ mtrc,
+ tlsConf,
+ btdMgr,
+ ratelimitConf,
+ dnsConf,
+ )
if err != nil {
return nil, fmt.Errorf("server group %q: %w", g.Name, err)
}
diff --git a/internal/cmd/tickrot.go b/internal/cmd/tickrot.go
index e134dd1..fe6431b 100644
--- a/internal/cmd/tickrot.go
+++ b/internal/cmd/tickrot.go
@@ -10,7 +10,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/tlsconfig"
"github.com/AdguardTeam/golibs/logutil/slogutil"
)
@@ -19,6 +19,7 @@ import (
type ticketRotator struct {
logger *slog.Logger
errColl errcoll.Interface
+ mtrc tlsconfig.Metrics
confs map[*tls.Config][]string
}
@@ -29,6 +30,7 @@ type ticketRotator struct {
func newTicketRotator(
logger *slog.Logger,
errColl errcoll.Interface,
+ mtrc tlsconfig.Metrics,
grps []*agd.ServerGroup,
) (tr *ticketRotator) {
confs := map[*tls.Config][]string{}
@@ -49,6 +51,7 @@ func newTicketRotator(
return &ticketRotator{
logger: logger.With(slogutil.KeyPrefix, "tickrot"),
errColl: errColl,
+ mtrc: mtrc,
confs: confs,
}
}
@@ -81,7 +84,7 @@ func (r *ticketRotator) Refresh(ctx context.Context) (err error) {
var key [sessTickLen]byte
key, err = readSessionTicketKey(fileName)
if err != nil {
- metrics.TLSSessionTicketsRotateStatus.Set(0)
+ r.mtrc.SetSessionTicketRotationStatus(ctx, false)
return fmt.Errorf("session ticket for srv %s: %w", conf.ServerName, err)
}
@@ -96,8 +99,7 @@ func (r *ticketRotator) Refresh(ctx context.Context) (err error) {
conf.SetSessionTicketKeys(keys)
}
- metrics.TLSSessionTicketsRotateStatus.Set(1)
- metrics.TLSSessionTicketsRotateTime.SetToCurrentTime()
+ r.mtrc.SetSessionTicketRotationStatus(ctx, true)
return nil
}
diff --git a/internal/cmd/tls.go b/internal/cmd/tls.go
index 9624436..4692140 100644
--- a/internal/cmd/tls.go
+++ b/internal/cmd/tls.go
@@ -1,6 +1,7 @@
package cmd
import (
+ "context"
"crypto/tls"
"crypto/x509"
"fmt"
@@ -9,10 +10,9 @@ import (
"strings"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors"
- "github.com/prometheus/client_golang/prometheus"
)
// tlsConfig are the TLS settings of a DNS server, if any.
@@ -37,12 +37,15 @@ type tlsConfig struct {
// toInternal converts c to the TLS configuration for a DNS server. c must be
// valid.
-func (c *tlsConfig) toInternal() (conf *agd.TLS, err error) {
+func (c *tlsConfig) toInternal(
+ ctx context.Context,
+ mtrc tlsconfig.Metrics,
+) (conf *agd.TLS, err error) {
if c == nil {
return nil, nil
}
- tlsConf, err := c.Certificates.toInternal()
+ tlsConf, err := c.Certificates.toInternal(ctx, mtrc)
if err != nil {
return nil, fmt.Errorf("certificates: %w", err)
}
@@ -123,7 +126,10 @@ type tlsConfigCert struct {
type tlsConfigCerts []*tlsConfigCert
// toInternal converts certs to a TLS configuration. certs must be valid.
-func (certs tlsConfigCerts) toInternal() (conf *tls.Config, err error) {
+func (certs tlsConfigCerts) toInternal(
+ ctx context.Context,
+ mtrc tlsconfig.Metrics,
+) (conf *tls.Config, err error) {
if len(certs) == 0 {
return nil, nil
}
@@ -146,13 +152,8 @@ func (certs tlsConfigCerts) toInternal() (conf *tls.Config, err error) {
tlsCerts[i] = cert
authAlgo, subj := leaf.PublicKeyAlgorithm.String(), leaf.Subject.String()
- metrics.TLSCertificateInfo.With(prometheus.Labels{
- "auth_algo": authAlgo,
- "subject": subj,
- }).Set(1)
- metrics.TLSCertificateNotAfter.With(prometheus.Labels{
- "subject": subj,
- }).Set(float64(leaf.NotAfter.Unix()))
+
+ mtrc.SetCertificateInfo(ctx, authAlgo, subj, leaf.NotAfter)
}
return &tls.Config{
diff --git a/internal/cmd/websvc.go b/internal/cmd/websvc.go
index 614b310..64b38d1 100644
--- a/internal/cmd/websvc.go
+++ b/internal/cmd/websvc.go
@@ -1,6 +1,7 @@
package cmd
import (
+ "context"
"encoding/base64"
"fmt"
"maps"
@@ -13,6 +14,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
"github.com/AdguardTeam/AdGuardDNS/internal/websvc"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/httphdr"
@@ -62,9 +64,11 @@ type webConfig struct {
// toInternal converts c to the AdGuardDNS web service configuration. c must be
// valid.
func (c *webConfig) toInternal(
+ ctx context.Context,
envs *environment,
dnsCk dnscheck.Interface,
errColl errcoll.Interface,
+ mtrc tlsconfig.Metrics,
) (conf *websvc.Config, err error) {
if c == nil {
return nil, nil
@@ -83,7 +87,7 @@ func (c *webConfig) toInternal(
conf.RootRedirectURL = netutil.CloneURL(&c.RootRedirectURL.URL)
}
- conf.LinkedIP, err = c.LinkedIP.toInternal(envs.LinkedIPTargetURL)
+ conf.LinkedIP, err = c.LinkedIP.toInternal(ctx, mtrc, envs.LinkedIPTargetURL)
if err != nil {
return nil, fmt.Errorf("converting linked_ip: %w", err)
}
@@ -107,7 +111,7 @@ func (c *webConfig) toInternal(
}}
for _, bp := range blockPages {
- *bp.webConfPtr, err = bp.conf.toInternal()
+ *bp.webConfPtr, err = bp.conf.toInternal(ctx, mtrc)
if err != nil {
return nil, fmt.Errorf("%s: %w", bp.name, err)
}
@@ -119,7 +123,7 @@ func (c *webConfig) toInternal(
return nil, err
}
- conf.NonDoHBind, err = c.NonDoHBind.toInternal()
+ conf.NonDoHBind, err = c.NonDoHBind.toInternal(ctx, mtrc)
if err != nil {
return nil, fmt.Errorf("converting non_doh_bind: %w", err)
}
@@ -225,6 +229,8 @@ type linkedIPServer struct {
// toInternal converts s to a linkedIP server configuration. s must be valid.
func (s *linkedIPServer) toInternal(
+ ctx context.Context,
+ mtrc tlsconfig.Metrics,
targetURL *urlutil.URL,
) (srv *websvc.LinkedIPServer, err error) {
if s == nil {
@@ -232,7 +238,7 @@ func (s *linkedIPServer) toInternal(
}
srv = &websvc.LinkedIPServer{}
- srv.Bind, err = s.Bind.toInternal()
+ srv.Bind, err = s.Bind.toInternal(ctx, mtrc)
if err != nil {
return nil, fmt.Errorf("converting bind: %w", err)
}
@@ -280,7 +286,10 @@ type blockPageServer struct {
}
// toInternal converts s to a block page server configuration. s must be valid.
-func (s *blockPageServer) toInternal() (conf *websvc.BlockPageServerConfig, err error) {
+func (s *blockPageServer) toInternal(
+ ctx context.Context,
+ mtrc tlsconfig.Metrics,
+) (conf *websvc.BlockPageServerConfig, err error) {
if s == nil {
return nil, nil
}
@@ -289,7 +298,7 @@ func (s *blockPageServer) toInternal() (conf *websvc.BlockPageServerConfig, err
ContentFilePath: s.BlockPage,
}
- conf.Bind, err = s.Bind.toInternal()
+ conf.Bind, err = s.Bind.toInternal(ctx, mtrc)
if err != nil {
return nil, fmt.Errorf("converting bind: %w", err)
}
@@ -326,11 +335,14 @@ type bindData []*bindItem
// toInternal converts bd to bind data for the AdGuard DNS web service. bd must
// be valid.
-func (bd bindData) toInternal() (data []*websvc.BindData, err error) {
+func (bd bindData) toInternal(
+ ctx context.Context,
+ mtrc tlsconfig.Metrics,
+) (data []*websvc.BindData, err error) {
data = make([]*websvc.BindData, len(bd))
for i, d := range bd {
- data[i], err = d.toInternal()
+ data[i], err = d.toInternal(ctx, mtrc)
if err != nil {
return nil, fmt.Errorf("bind data at index %d: %w", i, err)
}
@@ -369,8 +381,11 @@ type bindItem struct {
// toInternal converts i to bind data for the AdGuard DNS web service. i must
// be valid.
-func (i *bindItem) toInternal() (data *websvc.BindData, err error) {
- tlsConf, err := i.Certificates.toInternal()
+func (i *bindItem) toInternal(
+ ctx context.Context,
+ mtrc tlsconfig.Metrics,
+) (data *websvc.BindData, err error) {
+ tlsConf, err := i.Certificates.toInternal(ctx, mtrc)
if err != nil {
return nil, fmt.Errorf("certificates: %w", err)
}
diff --git a/internal/consul/allowlist.go b/internal/consul/allowlist.go
index 3c64098..a1d2023 100644
--- a/internal/consul/allowlist.go
+++ b/internal/consul/allowlist.go
@@ -15,7 +15,6 @@ import (
"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/netutil/urlutil"
)
@@ -28,6 +27,7 @@ type AllowlistUpdater struct {
http *agdhttp.Client
url *url.URL
errColl errcoll.Interface
+ metrics Metrics
}
// AllowlistUpdaterConfig is the configuration structure for the allowlist
@@ -45,6 +45,9 @@ type AllowlistUpdaterConfig struct {
// ErrColl is used to collect errors during refreshes.
ErrColl errcoll.Interface
+ // Metrics is used to collect allowlist statistics.
+ Metrics Metrics
+
// Timeout is the timeout for Consul queries.
Timeout time.Duration
}
@@ -60,6 +63,7 @@ func NewAllowlistUpdater(c *AllowlistUpdaterConfig) (upd *AllowlistUpdater) {
}),
url: c.ConsulURL,
errColl: c.ErrColl,
+ metrics: c.Metrics,
}
}
@@ -72,10 +76,7 @@ func (upd *AllowlistUpdater) Refresh(ctx context.Context) (err error) {
upd.logger.InfoContext(ctx, "refresh started")
defer upd.logger.InfoContext(ctx, "refresh finished")
- defer func() {
- metrics.ConsulAllowlistUpdateTime.SetToCurrentTime()
- metrics.SetStatusGauge(metrics.ConsulAllowlistUpdateStatus, err)
- }()
+ defer func() { upd.metrics.SetStatus(ctx, err) }()
consulNets, err := upd.loadConsul(ctx)
if err != nil {
@@ -89,13 +90,11 @@ func (upd *AllowlistUpdater) Refresh(ctx context.Context) (err error) {
ctx,
"refresh successful",
"num_records", len(consulNets),
- "url", &urlutil.URL{
- URL: *upd.url,
- },
+ "url", urlutil.RedactUserinfo(upd.url),
)
upd.allowlist.Update(consulNets)
- metrics.ConsulAllowlistSize.Set(float64(len(consulNets)))
+ upd.metrics.SetSize(ctx, len(consulNets))
return nil
}
@@ -107,7 +106,7 @@ type consulRecord struct {
// loadConsul fetches, decodes, and returns the list of IP networks from consul.
func (upd *AllowlistUpdater) loadConsul(ctx context.Context) (nets []netip.Prefix, err error) {
- defer func() { err = errors.Annotate(err, "loading allowlist nets from %s: %w", upd.url) }()
+ defer func() { err = errors.Annotate(err, "loading allowlist nets: %w") }()
httpResp, err := upd.http.Get(ctx, upd.url)
if err != nil {
diff --git a/internal/consul/allowlist_test.go b/internal/consul/allowlist_test.go
index c315466..d6faf8a 100644
--- a/internal/consul/allowlist_test.go
+++ b/internal/consul/allowlist_test.go
@@ -83,6 +83,7 @@ func TestNewAllowlistUpdater(t *testing.T) {
Allowlist: al,
ConsulURL: u,
ErrColl: agdtest.NewErrorCollector(),
+ Metrics: consul.EmptyMetrics{},
Timeout: testTimeout,
})
@@ -128,6 +129,7 @@ func TestNewAllowlistUpdater(t *testing.T) {
Allowlist: al,
ConsulURL: u,
ErrColl: errColl,
+ Metrics: consul.EmptyMetrics{},
Timeout: testTimeout,
})
@@ -161,6 +163,7 @@ func TestAllowlistUpdater_Refresh_deadline(t *testing.T) {
Allowlist: al,
ConsulURL: u,
ErrColl: errColl,
+ Metrics: consul.EmptyMetrics{},
Timeout: testTimeout,
})
diff --git a/internal/consul/metrics.go b/internal/consul/metrics.go
new file mode 100644
index 0000000..4b7d8eb
--- /dev/null
+++ b/internal/consul/metrics.go
@@ -0,0 +1,26 @@
+package consul
+
+import "context"
+
+// Metrics is an interface that is used for the collection of the allowlist
+// statistics.
+type Metrics interface {
+ // SetSize sets the number of received subnets.
+ SetSize(ctx context.Context, n int)
+
+ // SetStatus sets the status and time of the allowlist refresh attempt.
+ SetStatus(ctx context.Context, err error)
+}
+
+// EmptyMetrics is the implementation of the [Metrics] interface that does
+// nothing.
+type EmptyMetrics struct{}
+
+// type check
+var _ Metrics = EmptyMetrics{}
+
+// SetSize implements the [Metrics] interface for EmptyMetrics.
+func (EmptyMetrics) SetSize(_ context.Context, _ int) {}
+
+// SetStatus plements the [Metrics] interface for EmptyMetrics.
+func (EmptyMetrics) SetStatus(_ context.Context, _ error) {}
diff --git a/internal/debugsvc/debugsvc_test.go b/internal/debugsvc/debugsvc_test.go
index 4c51646..9e8a4bf 100644
--- a/internal/debugsvc/debugsvc_test.go
+++ b/internal/debugsvc/debugsvc_test.go
@@ -15,6 +15,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/debugsvc"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil/httputil"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -92,7 +93,7 @@ func TestService_Start(t *testing.T) {
})
srvURL := &url.URL{
- Scheme: agdhttp.SchemeHTTP,
+ Scheme: urlutil.SchemeHTTP,
Host: addr,
}
diff --git a/internal/dnscheck/remotekv.go b/internal/dnscheck/remotekv.go
index c104dbf..4e94aa5 100644
--- a/internal/dnscheck/remotekv.go
+++ b/internal/dnscheck/remotekv.go
@@ -201,18 +201,21 @@ func (cc *RemoteKV) newInfo(ri *agd.RequestInfo) (inf *info) {
}
// resp returns the corresponding response.
+//
+// TODO(e.burkov): Inspect the reason for using different message constructors
+// for different DNS types, and consider using only one of them.
func (cc *RemoteKV) resp(ri *agd.RequestInfo, req *dns.Msg) (resp *dns.Msg, err error) {
qt := ri.QType
if qt != dns.TypeA && qt != dns.TypeAAAA {
- return ri.Messages.NewMsgNODATA(req), nil
+ return ri.Messages.NewRespRCode(req, dns.RcodeSuccess), nil
}
if qt == dns.TypeA {
- return cc.messages.NewIPRespMsg(req, cc.ipv4...)
+ return cc.messages.NewRespIP(req, cc.ipv4...)
}
- return cc.messages.NewIPRespMsg(req, cc.ipv6...)
+ return cc.messages.NewRespIP(req, cc.ipv6...)
}
// type check
diff --git a/internal/dnscheck/remotekv_test.go b/internal/dnscheck/remotekv_test.go
index 0add623..700d78a 100644
--- a/internal/dnscheck/remotekv_test.go
+++ b/internal/dnscheck/remotekv_test.go
@@ -17,6 +17,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/remotekv"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -86,7 +87,7 @@ func TestConsul_ServeHTTP(t *testing.T) {
t.Run("hit", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, (&url.URL{
- Scheme: "http",
+ Scheme: urlutil.SchemeHTTP,
Host: randomid + "-" + checkDomain,
Path: "/dnscheck/test",
}).String(), strings.NewReader(""))
@@ -103,7 +104,7 @@ func TestConsul_ServeHTTP(t *testing.T) {
t.Run("miss", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, (&url.URL{
- Scheme: "http",
+ Scheme: urlutil.SchemeHTTP,
Host: "non" + randomid + "-" + checkDomain,
Path: "/dnscheck/test",
}).String(), strings.NewReader(""))
diff --git a/internal/dnsdb/http_test.go b/internal/dnsdb/http_test.go
index 1fd6b7d..ebe3713 100644
--- a/internal/dnsdb/http_test.go
+++ b/internal/dnsdb/http_test.go
@@ -18,13 +18,14 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDefault_ServeHTTP(t *testing.T) {
- const dname = "some-domain.name"
+ const domain = "domain.example"
testIP := netip.MustParseAddr("1.2.3.4")
@@ -39,7 +40,7 @@ func TestDefault_ServeHTTP(t *testing.T) {
rcode,
dnsservertest.NewReq(name, qtype, dns.ClassINET),
dnsservertest.SectionAnswer{
- dnsservertest.NewA(dname, 0, testIP),
+ dnsservertest.NewA(domain, 0, testIP),
},
)
}
@@ -52,38 +53,38 @@ func TestDefault_ServeHTTP(t *testing.T) {
}{{
name: "single",
msgs: []*dns.Msg{
- newMsg(dns.RcodeSuccess, dname, dns.TypeA),
+ newMsg(dns.RcodeSuccess, domain, dns.TypeA),
},
wantHdr: successHdr,
- wantResp: [][]byte{[]byte(dname + `,A,NOERROR,` + testIP.String() + `,1`)},
+ wantResp: [][]byte{[]byte(domain + `,A,NOERROR,` + testIP.String() + `,1`)},
}, {
name: "existing",
msgs: []*dns.Msg{
- newMsg(dns.RcodeSuccess, dname, dns.TypeA),
- newMsg(dns.RcodeSuccess, dname, dns.TypeA),
+ newMsg(dns.RcodeSuccess, domain, dns.TypeA),
+ newMsg(dns.RcodeSuccess, domain, dns.TypeA),
},
wantHdr: successHdr,
- wantResp: [][]byte{[]byte(dname + `,A,NOERROR,` + testIP.String() + `,2`)},
+ wantResp: [][]byte{[]byte(domain + `,A,NOERROR,` + testIP.String() + `,2`)},
}, {
name: "different",
msgs: []*dns.Msg{
- newMsg(dns.RcodeSuccess, dname, dns.TypeA),
- newMsg(dns.RcodeSuccess, "sub."+dname, dns.TypeA),
+ newMsg(dns.RcodeSuccess, domain, dns.TypeA),
+ newMsg(dns.RcodeSuccess, "sub."+domain, dns.TypeA),
},
wantHdr: successHdr,
wantResp: [][]byte{
- []byte("sub." + dname + `,A,NOERROR,` + testIP.String() + `,1`),
- []byte(dname + `,A,NOERROR,` + testIP.String() + `,1`),
+ []byte("sub." + domain + `,A,NOERROR,` + testIP.String() + `,1`),
+ []byte(domain + `,A,NOERROR,` + testIP.String() + `,1`),
},
}, {
name: "non-recordable",
msgs: []*dns.Msg{
// Not NOERROR.
- newMsg(dns.RcodeBadName, dname, dns.TypeA),
+ newMsg(dns.RcodeBadName, domain, dns.TypeA),
// Not A/AAAA.
- newMsg(dns.RcodeSuccess, dname, dns.TypeSRV),
+ newMsg(dns.RcodeSuccess, domain, dns.TypeSRV),
// Android metrics.
- newMsg(dns.RcodeSuccess, dname+"-dnsotls-ds.metric.gstatic.com.", dns.TypeA),
+ newMsg(dns.RcodeSuccess, domain+"-dnsotls-ds.metric.gstatic.com.", dns.TypeA),
},
wantHdr: successHdr,
wantResp: [][]byte{},
@@ -109,7 +110,10 @@ func TestDefault_ServeHTTP(t *testing.T) {
r := httptest.NewRequest(
http.MethodGet,
- (&url.URL{Scheme: "http", Host: "example.com"}).String(),
+ (&url.URL{
+ Scheme: urlutil.SchemeHTTP,
+ Host: "dnsdb.example",
+ }).String(),
nil,
)
r.Header.Add(httphdr.AcceptEncoding, agdhttp.HdrValGzip)
diff --git a/internal/dnsmsg/constructor.go b/internal/dnsmsg/constructor.go
index 869185c..3ed4b36 100644
--- a/internal/dnsmsg/constructor.go
+++ b/internal/dnsmsg/constructor.go
@@ -15,6 +15,11 @@ type ConstructorConfig struct {
// Cloner used to clone DNS messages. It must not be nil.
Cloner *Cloner
+ // StructuredErrors is the configuration for the experimental Structured DNS
+ // Errors feature. It must not be nil. If enabled,
+ // [ConstructorConfig.Enabled] should also be true.
+ StructuredErrors *StructuredDNSErrorsConfig
+
// BlockingMode is the blocking mode to use in
// [Constructor.NewBlockedRespMsg]. It must not be nil.
BlockingMode BlockingMode
@@ -22,6 +27,9 @@ type ConstructorConfig struct {
// FilteredResponseTTL is the time-to-live value used for responses created
// by this message constructor. It must be non-negative.
FilteredResponseTTL time.Duration
+
+ // EDEEnabled enables the addition of the Extended DNS Error (EDE) codes.
+ EDEEnabled bool
}
// validate checks the configuration for errors.
@@ -33,13 +41,19 @@ func (conf *ConstructorConfig) validate() (err error) {
errs = append(errs, err)
}
+ err = conf.StructuredErrors.validate(conf.EDEEnabled)
+ if err != nil {
+ err = fmt.Errorf("structured errors: %w", err)
+ errs = append(errs, err)
+ }
+
if conf.BlockingMode == nil {
err = fmt.Errorf("blocking mode: %w", errors.ErrNoValue)
errs = append(errs, err)
}
if conf.FilteredResponseTTL < 0 {
- err = fmt.Errorf("filtered response TTL: %w", errors.ErrNegative)
+ err = fmt.Errorf("filtered response ttl: %w", errors.ErrNegative)
errs = append(errs, err)
}
@@ -51,7 +65,9 @@ func (conf *ConstructorConfig) validate() (err error) {
type Constructor struct {
cloner *Cloner
blockingMode BlockingMode
+ sde string
fltRespTTL time.Duration
+ edeEnabled bool
}
// NewConstructor returns a properly initialized constructor using conf.
@@ -60,10 +76,17 @@ func NewConstructor(conf *ConstructorConfig) (c *Constructor, err error) {
return nil, fmt.Errorf("configuration: %w", err)
}
+ var sde string
+ if sdeConf := conf.StructuredErrors; sdeConf.Enabled {
+ sde = sdeConf.iJSON()
+ }
+
return &Constructor{
cloner: conf.Cloner,
blockingMode: conf.BlockingMode,
+ sde: sde,
fltRespTTL: conf.FilteredResponseTTL,
+ edeEnabled: conf.EDEEnabled,
}, nil
}
@@ -72,156 +95,6 @@ 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) {
- switch m := c.blockingMode.(type) {
- case *BlockingModeCustomIP:
- return c.newBlockedCustomIPRespMsg(req, m)
- case *BlockingModeNullIP:
- switch qt := req.Question[0].Qtype; qt {
- case dns.TypeA, dns.TypeAAAA:
- return c.NewIPRespMsg(req, netip.Addr{})
- default:
- return c.NewMsgNODATA(req), nil
- }
- case *BlockingModeNXDOMAIN:
- return c.NewMsgNXDOMAIN(req), nil
- case *BlockingModeREFUSED:
- return c.NewMsgREFUSED(req), nil
- default:
- // Consider unhandled sum type members as unrecoverable programmer
- // errors.
- panic(fmt.Errorf("unexpected type %T", c.blockingMode))
- }
-}
-
-// newBlockedCustomIPRespMsg returns a blocked DNS response message with either
-// the custom IPs from the blocking mode options or a NODATA one.
-func (c *Constructor) newBlockedCustomIPRespMsg(
- req *dns.Msg,
- m *BlockingModeCustomIP,
-) (msg *dns.Msg, err error) {
- switch qt := req.Question[0].Qtype; qt {
- case dns.TypeA:
- if len(m.IPv4) > 0 {
- return c.NewIPRespMsg(req, m.IPv4...)
- }
- case dns.TypeAAAA:
- if len(m.IPv6) > 0 {
- return c.NewIPRespMsg(req, m.IPv6...)
- }
- default:
- // Go on.
- }
-
- return c.NewMsgNODATA(req), nil
-}
-
-// NewIPRespMsg returns a DNS A or AAAA response message with the given IP
-// addresses. If any IP address is nil, it is replaced by an unspecified (aka
-// null) IP. The TTL is also set to c.FilteredResponseTTL.
-func (c *Constructor) NewIPRespMsg(req *dns.Msg, ips ...netip.Addr) (msg *dns.Msg, err error) {
- switch qt := req.Question[0].Qtype; qt {
- case dns.TypeA:
- return c.newMsgA(req, ips...)
- case dns.TypeAAAA:
- return c.newMsgAAAA(req, ips...)
- default:
- return nil, fmt.Errorf("bad qtype for a or aaaa resp: %d", qt)
- }
-}
-
-// NewCNAMEWithIPs generates a filtered response to req with CNAME record and
-// provided ips. cname is the fully-qualified name and must not be empty, ips
-// must be of the same family.
-func (c *Constructor) NewCNAMEWithIPs(
- req *dns.Msg,
- cname string,
- ips ...netip.Addr,
-) (resp *dns.Msg, err error) {
- resp = c.NewRespMsg(req)
-
- resp.Answer = make([]dns.RR, 0, len(ips)+1)
- resp.Answer = append(resp.Answer, c.NewAnswerCNAME(req, cname))
-
- var ans dns.RR
- for i, ip := range ips {
- switch qt := req.Question[0].Qtype; qt {
- case dns.TypeA:
- ans, err = c.NewAnswerA(cname, ip)
- case dns.TypeAAAA:
- ans, err = c.NewAnswerAAAA(cname, ip)
- default:
- return nil, fmt.Errorf("bad qtype for a or aaaa resp: %d", qt)
- }
-
- if err != nil {
- return nil, fmt.Errorf("bad ip at idx %d: %w", i, err)
- }
-
- resp.Answer = append(resp.Answer, ans)
- }
-
- return resp, err
-}
-
-// NewMsgFORMERR returns a properly initialized FORMERR response.
-func (c *Constructor) NewMsgFORMERR(req *dns.Msg) (resp *dns.Msg) {
- return c.newMsgRCode(req, dns.RcodeFormatError)
-}
-
-// NewMsgNXDOMAIN returns a properly initialized NXDOMAIN response.
-func (c *Constructor) NewMsgNXDOMAIN(req *dns.Msg) (resp *dns.Msg) {
- return c.newMsgRCode(req, dns.RcodeNameError)
-}
-
-// NewMsgREFUSED returns a properly initialized REFUSED response.
-func (c *Constructor) NewMsgREFUSED(req *dns.Msg) (resp *dns.Msg) {
- return c.newMsgRCode(req, dns.RcodeRefused)
-}
-
-// NewMsgSERVFAIL returns a properly initialized SERVFAIL response.
-func (c *Constructor) NewMsgSERVFAIL(req *dns.Msg) (resp *dns.Msg) {
- return c.newMsgRCode(req, dns.RcodeServerFailure)
-}
-
-// NewMsgNODATA returns a properly initialized NODATA response.
-//
-// See https://www.rfc-editor.org/rfc/rfc2308#section-2.2.
-func (c *Constructor) NewMsgNODATA(req *dns.Msg) (resp *dns.Msg) {
- return c.newMsgRCode(req, dns.RcodeSuccess)
-}
-
-// newMsgRCode returns a properly initialized response with the given RCode.
-func (c *Constructor) newMsgRCode(req *dns.Msg, rc RCode) (resp *dns.Msg) {
- resp = (&dns.Msg{}).SetRcode(req, int(rc))
- resp.Ns = c.newSOARecords(req)
- resp.RecursionAvailable = true
-
- return resp
-}
-
-// NewTXTRespMsg returns a DNS TXT response message with the given strings as
-// content. The TTL is also set to c.FilteredResponseTTL.
-func (c *Constructor) NewTXTRespMsg(req *dns.Msg, strs ...string) (msg *dns.Msg, err error) {
- ans, err := c.NewAnswerTXT(req, strs)
- if err != nil {
- return nil, err
- }
-
- msg = c.NewRespMsg(req)
- msg.Answer = append(msg.Answer, ans)
-
- return msg, nil
-}
-
// AppendDebugExtra appends to response message a DNS TXT extra with CHAOS
// class.
func (c *Constructor) AppendDebugExtra(req, resp *dns.Msg, str string) (err error) {
@@ -386,26 +259,23 @@ func (c *Constructor) newSOARecords(req *dns.Msg) (soaRecs []dns.RR) {
zone = req.Question[0].Name
}
- // TODO(a.garipov): A lot of this is copied from AdGuard Home and needs
- // to be inspected and refactored.
+ // TODO(a.garipov): A lot of this is copied from AdGuard Home and needs to
+ // be inspected and refactored.
soa := &dns.SOA{
- // values copied from verisign's nonexistent .com domain
- // their exact values are not important in our use case because they are used for domain transfers between primary/secondary DNS servers
+ // Use values from verisign's nonexistent.com domain. Their exact
+ // values are not important in our use case because they are used for
+ // domain transfers between primary/secondary DNS servers.
Refresh: 1800,
Retry: 900,
Expire: 604800,
Minttl: 86400,
- // copied from AdGuard DNS
+ // Copied from AdGuard DNS.
Ns: "fake-for-negative-caching.adguard.com.",
Serial: 100500,
- // rest is request-specific
- Hdr: dns.RR_Header{
- Name: zone,
- Rrtype: dns.TypeSOA,
- Ttl: uint32(c.fltRespTTL.Seconds()),
- Class: dns.ClassINET,
- },
- Mbox: "hostmaster.", // zone will be appended later if it's not empty or "."
+ // Rest is request-specific.
+ Hdr: c.newHdrWithClass(zone, dns.TypeSOA, dns.ClassINET),
+ // Zone will be appended later if it's not empty or ".".
+ Mbox: "hostmaster.",
}
if len(zone) > 0 && zone[0] != '.' {
@@ -415,25 +285,10 @@ func (c *Constructor) newSOARecords(req *dns.Msg) (soaRecs []dns.RR) {
return []dns.RR{soa}
}
-// NewRespMsg creates a DNS response for req and sets all necessary flags and
-// fields. It also guarantees that req.Question will be not empty.
-func (c *Constructor) NewRespMsg(req *dns.Msg) (resp *dns.Msg) {
- resp = &dns.Msg{
- MsgHdr: dns.MsgHdr{
- RecursionAvailable: true,
- },
- Compress: true,
- }
-
- resp.SetReply(req)
-
- return resp
-}
-
// newMsgA returns a new DNS response with the given IPv4 addresses. If any IP
// address is nil, it is replaced by an unspecified (aka null) IP, 0.0.0.0.
func (c *Constructor) newMsgA(req *dns.Msg, ips ...netip.Addr) (msg *dns.Msg, err error) {
- msg = c.NewRespMsg(req)
+ msg = c.NewResp(req)
for i, ip := range ips {
var ans dns.RR
ans, err = c.NewAnswerA(req.Question[0].Name, ip)
@@ -450,7 +305,7 @@ func (c *Constructor) newMsgA(req *dns.Msg, ips ...netip.Addr) (msg *dns.Msg, er
// newMsgAAAA returns a new DNS response with the given IPv6 addresses. If any
// IP address is nil, it is replaced by an unspecified (aka null) IP, [::].
func (c *Constructor) newMsgAAAA(req *dns.Msg, ips ...netip.Addr) (msg *dns.Msg, err error) {
- msg = c.NewRespMsg(req)
+ msg = c.NewResp(req)
for i, ip := range ips {
var ans dns.RR
ans, err = c.NewAnswerAAAA(req.Question[0].Name, ip)
diff --git a/internal/dnsmsg/constructor_test.go b/internal/dnsmsg/constructor_test.go
index 941dca1..74e3be4 100644
--- a/internal/dnsmsg/constructor_test.go
+++ b/internal/dnsmsg/constructor_test.go
@@ -1,18 +1,16 @@
package dnsmsg_test
import (
- "net"
- "net/netip"
+ "net/url"
"strings"
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
)
// newTXTExtra is a helper constructor of the expected extra data.
@@ -27,311 +25,88 @@ func newTXTExtra(ttl uint32, strs ...string) (extra []dns.RR) {
}}
}
-// newConstructor returns a new dnsmsg.Constructor with [testFltRespTTL].
-func newConstructor(tb testing.TB) (c *dnsmsg.Constructor) {
- msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
- Cloner: dnsmsg.NewCloner(dnsmsg.EmptyClonerStat{}),
- BlockingMode: &dnsmsg.BlockingModeNullIP{},
- FilteredResponseTTL: agdtest.FilteredResponseTTL,
- })
- require.NoError(tb, err)
-
- return msgs
-}
-
-func TestConstructor_NewBlockedRespMsg_nullIP(t *testing.T) {
- t.Parallel()
-
- msgs := newConstructor(t)
-
- testCases := []struct {
- name string
- wantAnsNum int
- qt dnsmsg.RRType
- }{{
- name: "a",
- wantAnsNum: 1,
- qt: dns.TypeA,
- }, {
- name: "aaaa",
- wantAnsNum: 1,
- qt: dns.TypeAAAA,
- }, {
- name: "txt",
- wantAnsNum: 0,
- qt: dns.TypeTXT,
- }}
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- t.Parallel()
-
- req := dnsservertest.NewReq(testFQDN, tc.qt, dns.ClassINET)
-
- resp, respErr := msgs.NewBlockedRespMsg(req)
- require.NoError(t, respErr)
- require.NotNil(t, resp)
-
- assert.Equal(t, dns.RcodeSuccess, resp.Rcode)
-
- if tc.wantAnsNum == 0 {
- assert.Empty(t, resp.Answer)
-
- require.Len(t, resp.Ns, 1)
-
- nsTTL := resp.Ns[0].Header().Ttl
- assert.Equal(t, uint32(agdtest.FilteredResponseTTLSec), nsTTL)
- } else {
- require.Len(t, resp.Answer, 1)
-
- ansTTL := resp.Answer[0].Header().Ttl
- assert.Equal(t, uint32(agdtest.FilteredResponseTTLSec), ansTTL)
- }
- })
- }
-}
-
-func TestConstructor_NewBlockedRespMsg_customIP(t *testing.T) {
+func TestNewConstructor(t *testing.T) {
t.Parallel()
cloner := agdtest.NewCloner()
-
- testCases := []struct {
- blockingMode dnsmsg.BlockingMode
- name string
- wantA bool
- wantAAAA bool
- }{{
- blockingMode: &dnsmsg.BlockingModeCustomIP{
- IPv4: []netip.Addr{testIPv4},
- IPv6: []netip.Addr{testIPv6},
- },
- name: "both",
- wantA: true,
- wantAAAA: true,
- }, {
- blockingMode: &dnsmsg.BlockingModeCustomIP{
- IPv4: []netip.Addr{testIPv4},
- },
- name: "ipv4_only",
- wantA: true,
- wantAAAA: false,
- }, {
- blockingMode: &dnsmsg.BlockingModeCustomIP{
- IPv6: []netip.Addr{testIPv6},
- },
- name: "ipv6_only",
- wantA: false,
- wantAAAA: true,
- }, {
- blockingMode: &dnsmsg.BlockingModeCustomIP{
- IPv4: []netip.Addr{},
- IPv6: []netip.Addr{},
- },
- name: "empty",
- wantA: false,
- wantAAAA: false,
- }}
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- t.Parallel()
-
- msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
- Cloner: cloner,
- BlockingMode: tc.blockingMode,
- FilteredResponseTTL: agdtest.FilteredResponseTTL,
- })
- require.NoError(t, err)
-
- reqA := dnsservertest.NewReq(testFQDN, dns.TypeA, dns.ClassINET)
- respA, err := msgs.NewBlockedRespMsg(reqA)
- require.NoError(t, err)
- require.NotNil(t, respA)
-
- assert.Equal(t, dns.RcodeSuccess, respA.Rcode)
-
- if tc.wantA {
- require.Len(t, respA.Answer, 1)
-
- a := testutil.RequireTypeAssert[*dns.A](t, respA.Answer[0])
- assert.Equal(t, net.IP(testIPv4.AsSlice()), a.A)
- } else {
- assert.Empty(t, respA.Answer)
- }
-
- reqAAAA := dnsservertest.NewReq(testFQDN, dns.TypeAAAA, dns.ClassINET)
- respAAAA, err := msgs.NewBlockedRespMsg(reqAAAA)
- require.NoError(t, err)
- require.NotNil(t, respAAAA)
-
- assert.Equal(t, dns.RcodeSuccess, respAAAA.Rcode)
-
- if tc.wantAAAA {
- require.Len(t, respAAAA.Answer, 1)
-
- aaaa := testutil.RequireTypeAssert[*dns.AAAA](t, respAAAA.Answer[0])
- assert.Equal(t, net.IP(testIPv6.AsSlice()), aaaa.AAAA)
- } else {
- assert.Empty(t, respAAAA.Answer)
- }
- })
- }
-}
-
-func TestConstructor_NewBlockedRespMsg_noAnswer(t *testing.T) {
- t.Parallel()
-
- req := dnsservertest.NewReq(testFQDN, dns.TypeA, dns.ClassINET)
- cloner := agdtest.NewCloner()
-
- testCases := []struct {
- blockingMode dnsmsg.BlockingMode
- name string
- rcode dnsmsg.RCode
- }{{
- blockingMode: &dnsmsg.BlockingModeNXDOMAIN{},
- name: "nxdomain",
- rcode: dns.RcodeNameError,
- }, {
- blockingMode: &dnsmsg.BlockingModeREFUSED{},
- name: "refused",
- rcode: dns.RcodeRefused,
- }}
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- t.Parallel()
-
- msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
- Cloner: cloner,
- BlockingMode: tc.blockingMode,
- FilteredResponseTTL: agdtest.FilteredResponseTTL,
- })
- require.NoError(t, err)
-
- resp, err := msgs.NewBlockedRespMsg(req)
- require.NoError(t, err)
- require.NotNil(t, resp)
-
- assert.Equal(t, tc.rcode, dnsmsg.RCode(resp.Rcode))
- assert.Empty(t, resp.Answer)
-
- require.Len(t, resp.Ns, 1)
-
- nsTTL := resp.Ns[0].Header().Ttl
- assert.Equal(t, uint32(agdtest.FilteredResponseTTLSec), nsTTL)
- })
- }
-}
-
-func TestConstructor_noAnswerMethods(t *testing.T) {
- t.Parallel()
-
- msgs := newConstructor(t)
-
- req := dnsservertest.NewReq(testFQDN, dns.TypeA, dns.ClassINET)
-
- testCases := []struct {
- method func(req *dns.Msg) (resp *dns.Msg)
- name string
- want dnsmsg.RCode
- }{{
- method: msgs.NewMsgFORMERR,
- name: "formerr",
- want: dns.RcodeFormatError,
- }, {
- method: msgs.NewMsgNXDOMAIN,
- name: "nxdomain",
- want: dns.RcodeNameError,
- }, {
- method: msgs.NewMsgREFUSED,
- name: "refused",
- want: dns.RcodeRefused,
- }, {
- method: msgs.NewMsgSERVFAIL,
- name: "servfail",
- want: dns.RcodeServerFailure,
- }, {
- method: msgs.NewMsgNODATA,
- name: "nodata",
- want: dns.RcodeSuccess,
- }}
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- t.Parallel()
-
- resp := tc.method(req)
- require.NotNil(t, resp)
- require.Len(t, resp.Ns, 1)
-
- assert.Empty(t, resp.Answer)
- assert.Equal(t, tc.want, dnsmsg.RCode(resp.Rcode))
-
- nsTTL := resp.Ns[0].Header().Ttl
- assert.Equal(t, uint32(agdtest.FilteredResponseTTLSec), nsTTL)
- })
- }
-}
-
-func TestConstructor_NewTXTRespMsg(t *testing.T) {
- t.Parallel()
-
- msgs := newConstructor(t)
-
- req := dnsservertest.NewReq(testFQDN, dns.TypeTXT, dns.ClassINET)
- tooLong := strings.Repeat("1", dnsmsg.MaxTXTStringLen+1)
+ badContactURL := errors.Must(url.Parse("invalid-scheme://devteam@adguard.com"))
testCases := []struct {
name string
+ conf *dnsmsg.ConstructorConfig
wantErrMsg string
- strs []string
}{{
- name: "success",
+ name: "good",
+ conf: &dnsmsg.ConstructorConfig{
+ Cloner: cloner,
+ StructuredErrors: agdtest.NewSDEConfig(true),
+ BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ FilteredResponseTTL: agdtest.FilteredResponseTTL,
+ EDEEnabled: true,
+ },
wantErrMsg: "",
- strs: []string{"111"},
}, {
- name: "success_many",
- wantErrMsg: "",
- strs: []string{"111", "222"},
+ name: "all_bad",
+ conf: &dnsmsg.ConstructorConfig{
+ FilteredResponseTTL: -1,
+ },
+ wantErrMsg: "configuration: " +
+ "cloner: no value\n" +
+ "structured errors: no value\n" +
+ "blocking mode: no value\n" +
+ "filtered response ttl: negative value",
}, {
- name: "success_nil",
- wantErrMsg: "",
- strs: nil,
+ name: "sde_enabled",
+ conf: &dnsmsg.ConstructorConfig{
+ Cloner: cloner,
+ StructuredErrors: agdtest.NewSDEConfig(true),
+ BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ FilteredResponseTTL: agdtest.FilteredResponseTTL,
+ EDEEnabled: false,
+ },
+ wantErrMsg: "configuration: structured errors: " +
+ "ede must be enabled to enable sde",
}, {
- name: "success_empty",
- wantErrMsg: "",
- strs: []string{},
+ name: "sde_empty",
+ conf: &dnsmsg.ConstructorConfig{
+ Cloner: cloner,
+ StructuredErrors: &dnsmsg.StructuredDNSErrorsConfig{
+ Enabled: true,
+ },
+ BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ FilteredResponseTTL: agdtest.FilteredResponseTTL,
+ EDEEnabled: true,
+ },
+ wantErrMsg: "configuration: structured errors: " +
+ "contact data: empty value\n" +
+ "justification: empty value",
}, {
- name: "too_long",
- wantErrMsg: "txt string at index 0: too long: got 256 bytes, max 255",
- strs: []string{tooLong},
+ name: "sde_bad",
+ conf: &dnsmsg.ConstructorConfig{
+ Cloner: cloner,
+ StructuredErrors: &dnsmsg.StructuredDNSErrorsConfig{
+ Enabled: true,
+ Contact: []*url.URL{badContactURL, nil},
+ Justification: "\uFFFE",
+ Organization: "\uFFFE",
+ },
+ BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ FilteredResponseTTL: agdtest.FilteredResponseTTL,
+ EDEEnabled: true,
+ },
+ wantErrMsg: "configuration: structured errors: " +
+ `contact data: at index 0: scheme: bad enum value: "invalid-scheme"` + "\n" +
+ "contact data: at index 1: no value\n" +
+ "justification: bad code point at index 0\n" +
+ "organization: bad code point at index 0",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
- resp, respErr := msgs.NewTXTRespMsg(req, tc.strs...)
- testutil.AssertErrorMsg(t, tc.wantErrMsg, respErr)
-
- if tc.wantErrMsg != "" {
- return
- }
-
- require.NotNil(t, resp)
-
- assert.Equal(t, dns.RcodeSuccess, resp.Rcode)
-
- require.Len(t, resp.Answer, 1)
-
- ans := resp.Answer[0]
- ansTTL := ans.Header().Ttl
- assert.Equal(t, uint32(agdtest.FilteredResponseTTLSec), ansTTL)
-
- txt := testutil.RequireTypeAssert[*dns.TXT](t, ans)
- assert.Equal(t, tc.strs, txt.Txt)
+ _, err := dnsmsg.NewConstructor(tc.conf)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
})
}
}
@@ -339,7 +114,7 @@ func TestConstructor_NewTXTRespMsg(t *testing.T) {
func TestConstructor_AppendDebugExtra(t *testing.T) {
t.Parallel()
- msgs := newConstructor(t)
+ msgs := agdtest.NewConstructor(t)
shortText := "This is a short test text"
longText := strings.Repeat("a", 2*dnsmsg.MaxTXTStringLen)
diff --git a/internal/dnsmsg/dnsmsg_test.go b/internal/dnsmsg/dnsmsg_test.go
index b382846..83dea9b 100644
--- a/internal/dnsmsg/dnsmsg_test.go
+++ b/internal/dnsmsg/dnsmsg_test.go
@@ -78,7 +78,9 @@ func TestClone(t *testing.T) {
},
name: "empty_slice_ans",
}, {
- msg: dnsservertest.NewReq(testFQDN, dns.TypeA, dns.ClassINET),
+ msg: dnsservertest.NewReq(testFQDN, dns.TypeA, dns.ClassINET, dnsservertest.SectionExtra{
+ dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{}),
+ }),
name: "a",
}}
diff --git a/internal/dnsmsg/optcloner.go b/internal/dnsmsg/optcloner.go
index 0627f0e..507eaa7 100644
--- a/internal/dnsmsg/optcloner.go
+++ b/internal/dnsmsg/optcloner.go
@@ -72,8 +72,7 @@ func (c *optCloner) clone(rr *dns.OPT) (clone *dns.OPT, full bool) {
optClone = opt
case *dns.EDNS0_EDE:
opt := c.ede.Get()
- opt.InfoCode = orig.InfoCode
- opt.ExtraText = orig.ExtraText
+ *opt = *orig
optClone = opt
case *dns.EDNS0_SUBNET:
diff --git a/internal/dnsmsg/response.go b/internal/dnsmsg/response.go
new file mode 100644
index 0000000..bf4f7ce
--- /dev/null
+++ b/internal/dnsmsg/response.go
@@ -0,0 +1,228 @@
+package dnsmsg
+
+import (
+ "fmt"
+ "net/netip"
+
+ "github.com/miekg/dns"
+)
+
+// NewResp creates a response DNS message for req and sets all necessary flags
+// and fields. resp contains no resource records.
+func (c *Constructor) NewResp(req *dns.Msg) (resp *dns.Msg) {
+ return (&dns.Msg{
+ MsgHdr: dns.MsgHdr{
+ RecursionAvailable: true,
+ },
+ Compress: true,
+ }).SetReply(req)
+}
+
+// NewBlockedResp returns a blocked response DNS message based on the
+// constructor's blocking mode.
+func (c *Constructor) NewBlockedResp(req *dns.Msg) (msg *dns.Msg, err error) {
+ switch m := c.blockingMode.(type) {
+ case *BlockingModeCustomIP:
+ return c.newBlockedCustomIPResp(req, m)
+ case *BlockingModeNullIP:
+ switch qt := req.Question[0].Qtype; qt {
+ case dns.TypeA, dns.TypeAAAA:
+ return c.NewBlockedNullIPResp(req)
+ default:
+ msg = c.NewBlockedRespRCode(req, dns.RcodeSuccess)
+ msg.Ns = c.newSOARecords(req)
+ }
+ case *BlockingModeNXDOMAIN:
+ msg = c.NewBlockedRespRCode(req, dns.RcodeNameError)
+ msg.Ns = c.newSOARecords(req)
+ case *BlockingModeREFUSED:
+ msg = c.NewBlockedRespRCode(req, dns.RcodeRefused)
+ msg.Ns = c.newSOARecords(req)
+ default:
+ // Consider unhandled sum type members as unrecoverable programmer
+ // errors.
+ panic(fmt.Errorf("unexpected type %T", c.blockingMode))
+ }
+
+ return msg, nil
+}
+
+// NewRespRCode returns a response DNS message with given response code and a
+// predefined authority section.
+//
+// Use [dns.RcodeSuccess] for a proper NODATA response, see
+// https://www.rfc-editor.org/rfc/rfc2308#section-2.2.
+func (c *Constructor) NewRespRCode(req *dns.Msg, rc RCode) (resp *dns.Msg) {
+ resp = c.NewResp(req)
+ resp.Rcode = int(rc)
+
+ resp.Ns = c.newSOARecords(req)
+
+ return resp
+}
+
+// NewBlockedRespRCode returns a blocked response DNS message with given
+// response code.
+//
+// TODO(e.burkov): Add SOA records to the response, like in
+// [Constructor.NewRespRCode].
+func (c *Constructor) NewBlockedRespRCode(req *dns.Msg, rc RCode) (resp *dns.Msg) {
+ resp = c.NewResp(req)
+ resp.Rcode = int(rc)
+
+ c.AddEDE(req, resp, dns.ExtendedErrorCodeFiltered)
+
+ return resp
+}
+
+// NewRespTXT returns a DNS TXT response message with the given strings as
+// content. The TTL of the TXT answer is set to c.FilteredResponseTTL.
+func (c *Constructor) NewRespTXT(req *dns.Msg, strs ...string) (msg *dns.Msg, err error) {
+ ans, err := c.NewAnswerTXT(req, strs)
+ if err != nil {
+ return nil, err
+ }
+
+ msg = c.NewResp(req)
+ msg.Answer = append(msg.Answer, ans)
+
+ return msg, nil
+}
+
+// NewRespIP returns an A or AAAA DNS response message with the given IP
+// addresses. If any IP address is nil, it is replaced by an unspecified (aka
+// null) IP. The TTL is also set to c.FilteredResponseTTL.
+func (c *Constructor) NewRespIP(req *dns.Msg, ips ...netip.Addr) (msg *dns.Msg, err error) {
+ switch qt := req.Question[0].Qtype; qt {
+ case dns.TypeA:
+ return c.newMsgA(req, ips...)
+ case dns.TypeAAAA:
+ return c.newMsgAAAA(req, ips...)
+ default:
+ return nil, fmt.Errorf("bad qtype for a or aaaa resp: %d", qt)
+ }
+}
+
+// NewBlockedRespIP returns an A or AAAA DNS response message with the given IP
+// addresses. The TTL of each record is set to c.FilteredResponseTTL. ips
+// should not contain zero values due to the extended error code semantics, use
+// [NewBlockedNullIPResp] for this case.
+//
+// TODO(a.garipov): Consider merging with [NewRespIP] if AddEDE with the Forged
+// Answer code isn't used again.
+func (c *Constructor) NewBlockedRespIP(req *dns.Msg, ips ...netip.Addr) (msg *dns.Msg, err error) {
+ switch qt := req.Question[0].Qtype; qt {
+ case dns.TypeA:
+ msg, err = c.newMsgA(req, ips...)
+ case dns.TypeAAAA:
+ msg, err = c.newMsgAAAA(req, ips...)
+ default:
+ return nil, fmt.Errorf("bad qtype for an ip resp: %d", qt)
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ return msg, nil
+}
+
+// NewBlockedNullIPResp returns a blocked A or AAAA DNS response message with an
+// unspecified (aka null) IP address. The TTL of the record is set to the
+// constructor's FilteredResponseTTL.
+func (c *Constructor) NewBlockedNullIPResp(req *dns.Msg) (resp *dns.Msg, err error) {
+ switch qt := req.Question[0].Qtype; qt {
+ case dns.TypeA:
+ resp, err = c.newMsgA(req, netip.Addr{})
+ case dns.TypeAAAA:
+ resp, err = c.newMsgAAAA(req, netip.Addr{})
+ default:
+ err = fmt.Errorf("bad qtype for an ip resp: %d", qt)
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ c.AddEDE(req, resp, dns.ExtendedErrorCodeFiltered)
+
+ return resp, nil
+}
+
+// AddEDE adds an Extended DNS Error (EDE) option to the blocked response
+// message, if the feature is enabled in the Constructor and the request
+// indicates EDNS support. It does not overwrite EDE if there already is one.
+// req and resp must not be nil.
+func (c *Constructor) AddEDE(req, resp *dns.Msg, code uint16) {
+ if !c.edeEnabled {
+ return
+ }
+
+ reqOpt := req.IsEdns0()
+ if reqOpt == nil {
+ // Requestor doesn't implement EDNS, see
+ // https://datatracker.ietf.org/doc/html/rfc6891#section-7.
+ return
+ }
+
+ respOpt := resp.IsEdns0()
+ if respOpt == nil {
+ respOpt = newOPT(c.cloner, reqOpt.UDPSize(), reqOpt.Do())
+ resp.Extra = append(resp.Extra, respOpt)
+ } else if findEDE(respOpt) != nil {
+ // Do not add an EDE option if there already is one.
+ return
+ }
+
+ sdeText := c.sdeForReqOpt(reqOpt)
+
+ respOpt.Option = append(respOpt.Option, newEDNS0EDE(c.cloner, code, sdeText))
+}
+
+// findEDE returns the EDE option if there is one. opt must not be nil.
+func findEDE(opt *dns.OPT) (ede *dns.EDNS0_EDE) {
+ for _, o := range opt.Option {
+ var ok bool
+ if ede, ok = o.(*dns.EDNS0_EDE); ok {
+ return ede
+ }
+ }
+
+ return nil
+}
+
+// sdeForReqOpt returns either the configured SDE text or empty string depending
+// on the request's EDNS options.
+func (c *Constructor) sdeForReqOpt(reqOpt *dns.OPT) (sde string) {
+ ede := findEDE(reqOpt)
+ if ede != nil && ede.InfoCode == 0 && ede.ExtraText == "" {
+ return c.sde
+ }
+
+ return ""
+}
+
+// newBlockedCustomIPResp returns a blocked DNS response message with either the
+// custom IPs from the blocking mode options or a NODATA one.
+func (c *Constructor) newBlockedCustomIPResp(
+ req *dns.Msg,
+ m *BlockingModeCustomIP,
+) (msg *dns.Msg, err error) {
+ switch qt := req.Question[0].Qtype; qt {
+ case dns.TypeA:
+ if len(m.IPv4) > 0 {
+ return c.NewBlockedRespIP(req, m.IPv4...)
+ }
+ case dns.TypeAAAA:
+ if len(m.IPv6) > 0 {
+ return c.NewBlockedRespIP(req, m.IPv6...)
+ }
+ default:
+ // Go on.
+ }
+
+ msg = c.NewBlockedRespRCode(req, dns.RcodeSuccess)
+ msg.Ns = c.newSOARecords(req)
+
+ return msg, nil
+}
diff --git a/internal/dnsmsg/response_test.go b/internal/dnsmsg/response_test.go
new file mode 100644
index 0000000..c9663f3
--- /dev/null
+++ b/internal/dnsmsg/response_test.go
@@ -0,0 +1,416 @@
+package dnsmsg_test
+
+import (
+ "net/netip"
+ "strings"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/miekg/dns"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestConstructor_NewBlockedResp_nullIP(t *testing.T) {
+ t.Parallel()
+
+ msgs := agdtest.NewConstructor(t)
+ reqExtra := dnsservertest.SectionExtra{
+ dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{}),
+ }
+
+ filteredSDE := dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{
+ InfoCode: dns.ExtendedErrorCodeFiltered,
+ ExtraText: agdtest.SDEText,
+ })
+
+ testCases := []struct {
+ name string
+ wantAns []dns.RR
+ wantExtra []dns.RR
+ qt dnsmsg.RRType
+ }{{
+ name: "a",
+ wantAns: []dns.RR{dnsservertest.NewA(
+ testFQDN, agdtest.FilteredResponseTTLSec, netip.IPv4Unspecified(),
+ )},
+ wantExtra: []dns.RR{filteredSDE},
+ qt: dns.TypeA,
+ }, {
+ name: "aaaa",
+ wantAns: []dns.RR{dnsservertest.NewAAAA(
+ testFQDN, agdtest.FilteredResponseTTLSec, netip.IPv6Unspecified(),
+ )},
+ wantExtra: []dns.RR{filteredSDE},
+ qt: dns.TypeAAAA,
+ }, {
+ name: "txt",
+ wantAns: nil,
+ wantExtra: []dns.RR{filteredSDE},
+ qt: dns.TypeTXT,
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ req := dnsservertest.NewReq(testFQDN, tc.qt, dns.ClassINET, reqExtra)
+
+ resp, respErr := msgs.NewBlockedResp(req)
+ require.NoError(t, respErr)
+ require.NotNil(t, resp)
+
+ assert.Equal(t, dns.RcodeSuccess, resp.Rcode)
+ assert.Equal(t, tc.wantAns, resp.Answer)
+ assert.Equal(t, tc.wantExtra, resp.Extra)
+ })
+ }
+}
+
+func TestConstructor_NewBlockedResp_customIP(t *testing.T) {
+ t.Parallel()
+
+ cloner := agdtest.NewCloner()
+
+ // TODO(a.garipov): Test the forged extra as well if the EDE with that code
+ // is used again.
+ reqExtra := dnsservertest.SectionExtra{
+ dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{}),
+ }
+ filteredExtra := dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{
+ InfoCode: dns.ExtendedErrorCodeFiltered,
+ ExtraText: agdtest.SDEText,
+ })
+
+ ansA := dnsservertest.NewA(testFQDN, agdtest.FilteredResponseTTLSec, testIPv4)
+ ansAAAA := dnsservertest.NewAAAA(testFQDN, agdtest.FilteredResponseTTLSec, testIPv6)
+
+ testCases := []struct {
+ blockingMode dnsmsg.BlockingMode
+ name string
+ wantAnsA []dns.RR
+ wantAnsAAAA []dns.RR
+ wantExtraA []dns.RR
+ wantExtraAAAA []dns.RR
+ }{{
+ blockingMode: &dnsmsg.BlockingModeCustomIP{
+ IPv4: []netip.Addr{testIPv4},
+ IPv6: []netip.Addr{testIPv6},
+ },
+ name: "both",
+ wantAnsA: []dns.RR{ansA},
+ wantAnsAAAA: []dns.RR{ansAAAA},
+ wantExtraA: nil,
+ wantExtraAAAA: nil,
+ }, {
+ blockingMode: &dnsmsg.BlockingModeCustomIP{
+ IPv4: []netip.Addr{testIPv4},
+ },
+ name: "ipv4_only",
+ wantAnsA: []dns.RR{ansA},
+ wantAnsAAAA: nil,
+ wantExtraA: nil,
+ wantExtraAAAA: []dns.RR{filteredExtra},
+ }, {
+ blockingMode: &dnsmsg.BlockingModeCustomIP{
+ IPv6: []netip.Addr{testIPv6},
+ },
+ name: "ipv6_only",
+ wantAnsA: nil,
+ wantAnsAAAA: []dns.RR{ansAAAA},
+ wantExtraA: []dns.RR{filteredExtra},
+ wantExtraAAAA: nil,
+ }, {
+ blockingMode: &dnsmsg.BlockingModeCustomIP{
+ IPv4: []netip.Addr{},
+ IPv6: []netip.Addr{},
+ },
+ name: "empty",
+ wantAnsA: nil,
+ wantAnsAAAA: nil,
+ wantExtraA: []dns.RR{filteredExtra},
+ wantExtraAAAA: []dns.RR{filteredExtra},
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
+ Cloner: cloner,
+ BlockingMode: tc.blockingMode,
+ StructuredErrors: agdtest.NewSDEConfig(true),
+ FilteredResponseTTL: agdtest.FilteredResponseTTL,
+ EDEEnabled: true,
+ })
+ require.NoError(t, err)
+
+ t.Run("a", func(t *testing.T) {
+ t.Parallel()
+
+ req := dnsservertest.NewReq(testFQDN, dns.TypeA, dns.ClassINET, reqExtra)
+ resp, respErr := msgs.NewBlockedResp(req)
+ require.NoError(t, respErr)
+ require.NotNil(t, resp)
+
+ assert.Equal(t, dns.RcodeSuccess, resp.Rcode)
+ assert.Equal(t, tc.wantAnsA, resp.Answer)
+ assert.Equal(t, tc.wantExtraA, resp.Extra)
+ })
+
+ t.Run("aaaa", func(t *testing.T) {
+ t.Parallel()
+
+ req := dnsservertest.NewReq(testFQDN, dns.TypeAAAA, dns.ClassINET, reqExtra)
+ resp, respErr := msgs.NewBlockedResp(req)
+ require.NoError(t, respErr)
+ require.NotNil(t, resp)
+
+ assert.Equal(t, dns.RcodeSuccess, resp.Rcode)
+ assert.Equal(t, tc.wantAnsAAAA, resp.Answer)
+ assert.Equal(t, tc.wantExtraAAAA, resp.Extra)
+ })
+ })
+ }
+}
+
+func TestConstructor_NewBlockedResp_nodata(t *testing.T) {
+ t.Parallel()
+
+ req := dnsservertest.NewReq(testFQDN, dns.TypeA, dns.ClassINET, dnsservertest.SectionExtra{
+ dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{}),
+ })
+ cloner := agdtest.NewCloner()
+
+ wantExtra := []dns.RR{dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{
+ InfoCode: dns.ExtendedErrorCodeFiltered,
+ ExtraText: agdtest.SDEText,
+ })}
+
+ testCases := []struct {
+ blockingMode dnsmsg.BlockingMode
+ name string
+ rcode dnsmsg.RCode
+ }{{
+ blockingMode: &dnsmsg.BlockingModeNXDOMAIN{},
+ name: "nxdomain",
+ rcode: dns.RcodeNameError,
+ }, {
+ blockingMode: &dnsmsg.BlockingModeREFUSED{},
+ name: "refused",
+ rcode: dns.RcodeRefused,
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
+ Cloner: cloner,
+ BlockingMode: tc.blockingMode,
+ StructuredErrors: agdtest.NewSDEConfig(true),
+ FilteredResponseTTL: agdtest.FilteredResponseTTL,
+ EDEEnabled: true,
+ })
+ require.NoError(t, err)
+
+ resp, err := msgs.NewBlockedResp(req)
+ require.NoError(t, err)
+ require.NotNil(t, resp)
+
+ assert.Equal(t, tc.rcode, dnsmsg.RCode(resp.Rcode))
+ assert.Empty(t, resp.Answer)
+
+ require.Len(t, resp.Ns, 1)
+
+ nsTTL := resp.Ns[0].Header().Ttl
+ assert.Equal(t, uint32(agdtest.FilteredResponseTTLSec), nsTTL)
+
+ assert.Equal(t, wantExtra, resp.Extra)
+ })
+ }
+}
+
+func TestConstructor_NewBlockedResp_sde(t *testing.T) {
+ t.Parallel()
+
+ reqEDNS := dnsservertest.NewReq(testFQDN, dns.TypeA, dns.ClassINET, dnsservertest.SectionExtra{
+ dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{}),
+ })
+ reqNoEDNS := dnsservertest.NewReq(testFQDN, dns.TypeA, dns.ClassINET)
+
+ wantAns := []dns.RR{
+ dnsservertest.NewA(testFQDN, agdtest.FilteredResponseTTLSec, netip.IPv4Unspecified()),
+ }
+
+ testCases := []struct {
+ req *dns.Msg
+ sde *dnsmsg.StructuredDNSErrorsConfig
+ name string
+ wantExtra []dns.RR
+ ede bool
+ }{{
+ req: reqEDNS,
+ sde: agdtest.NewSDEConfig(true),
+ name: "ede_sde",
+ wantExtra: []dns.RR{
+ dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{
+ InfoCode: dns.ExtendedErrorCodeFiltered,
+ ExtraText: agdtest.SDEText,
+ }),
+ },
+ ede: true,
+ }, {
+ req: reqEDNS,
+ sde: agdtest.NewSDEConfig(false),
+ name: "ede_no_sde",
+ wantExtra: []dns.RR{
+ dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{
+ InfoCode: dns.ExtendedErrorCodeFiltered,
+ }),
+ },
+ ede: true,
+ }, {
+ req: reqEDNS,
+ sde: agdtest.NewSDEConfig(false),
+ name: "no_ede",
+ wantExtra: nil,
+ ede: false,
+ }, {
+ req: reqNoEDNS,
+ sde: agdtest.NewSDEConfig(true),
+ name: "unsupported_ede_sde",
+ wantExtra: nil,
+ ede: true,
+ }, {
+ req: reqNoEDNS,
+ sde: agdtest.NewSDEConfig(false),
+ name: "unsupported_ede_no_sde",
+ wantExtra: nil,
+ ede: true,
+ }, {
+ req: reqNoEDNS,
+ sde: agdtest.NewSDEConfig(false),
+ name: "unsupported_no_ede",
+ wantExtra: nil,
+ ede: false,
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
+ Cloner: agdtest.NewCloner(),
+ BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ StructuredErrors: tc.sde,
+ FilteredResponseTTL: agdtest.FilteredResponseTTL,
+ EDEEnabled: tc.ede,
+ })
+ require.NoError(t, err)
+
+ resp, err := msgs.NewBlockedResp(tc.req)
+ require.NoError(t, err)
+ require.NotNil(t, resp)
+
+ assert.Equal(t, dns.RcodeSuccess, resp.Rcode)
+ assert.Equal(t, wantAns, resp.Answer)
+ assert.Equal(t, tc.wantExtra, resp.Extra)
+ })
+ }
+}
+
+func TestConstructor_NewRespRCode(t *testing.T) {
+ t.Parallel()
+
+ msgs := agdtest.NewConstructor(t)
+ req := dnsservertest.NewReq(testFQDN, dns.TypeA, dns.ClassINET, dnsservertest.SectionExtra{
+ dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{}),
+ })
+
+ for rcode, name := range dns.RcodeToString {
+ t.Run(name, func(t *testing.T) {
+ t.Parallel()
+
+ resp := msgs.NewRespRCode(req, dnsmsg.RCode(rcode))
+ require.NotNil(t, resp)
+ require.Empty(t, resp.Answer)
+
+ assert.Equal(t, rcode, resp.Rcode)
+
+ require.Len(t, resp.Ns, 1)
+
+ nsTTL := resp.Ns[0].Header().Ttl
+ assert.Equal(t, uint32(agdtest.FilteredResponseTTLSec), nsTTL)
+
+ assert.Empty(t, resp.Extra)
+ })
+ }
+}
+
+func TestConstructor_NewRespTXT(t *testing.T) {
+ t.Parallel()
+
+ msgs := agdtest.NewConstructor(t)
+
+ req := dnsservertest.NewReq(testFQDN, dns.TypeTXT, dns.ClassINET, dnsservertest.SectionExtra{
+ dnsservertest.NewOPT(true, dns.MaxMsgSize, &dns.EDNS0_EDE{}),
+ })
+ tooLong := strings.Repeat("1", dnsmsg.MaxTXTStringLen+1)
+
+ testCases := []struct {
+ name string
+ wantErrMsg string
+ strs []string
+ }{{
+ name: "success",
+ wantErrMsg: "",
+ strs: []string{"111"},
+ }, {
+ name: "success_many",
+ wantErrMsg: "",
+ strs: []string{"111", "222"},
+ }, {
+ name: "success_nil",
+ wantErrMsg: "",
+ strs: nil,
+ }, {
+ name: "success_empty",
+ wantErrMsg: "",
+ strs: []string{},
+ }, {
+ name: "too_long",
+ wantErrMsg: "txt string at index 0: too long: got 256 bytes, max 255",
+ strs: []string{tooLong},
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ resp, respErr := msgs.NewRespTXT(req, tc.strs...)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, respErr)
+
+ if tc.wantErrMsg != "" {
+ return
+ }
+
+ require.NotNil(t, resp)
+
+ assert.Equal(t, dns.RcodeSuccess, resp.Rcode)
+
+ require.Len(t, resp.Answer, 1)
+
+ ans := resp.Answer[0]
+ txt := testutil.RequireTypeAssert[*dns.TXT](t, ans)
+
+ assert.Equal(t, uint32(agdtest.FilteredResponseTTLSec), txt.Hdr.Ttl)
+ assert.Equal(t, tc.strs, txt.Txt)
+
+ assert.Empty(t, resp.Extra)
+ })
+ }
+}
diff --git a/internal/dnsmsg/rrconstructor.go b/internal/dnsmsg/rrconstructor.go
index 0cb49ee..732bfd0 100644
--- a/internal/dnsmsg/rrconstructor.go
+++ b/internal/dnsmsg/rrconstructor.go
@@ -140,3 +140,36 @@ func newTXT(c *Cloner, txt []string) (rr *dns.TXT) {
return rr
}
+
+// newOPT constructs a new resource record of type OPT, optionally using c to
+// allocate the structure.
+func newOPT(c *Cloner, udpSize uint16, doBit bool) (opt *dns.OPT) {
+ if c == nil {
+ opt = &dns.OPT{}
+ } else {
+ opt = c.opt.rr.Get()
+ opt.Option = opt.Option[:0]
+ }
+
+ opt.Hdr.Name = "."
+ opt.Hdr.Rrtype = dns.TypeOPT
+ opt.SetUDPSize(udpSize)
+ opt.SetDo(doBit)
+
+ return opt
+}
+
+// newEDNS0EDE constructs a new resource record of type EDNS0_EDE, optionally
+// using c to allocate the structure.
+func newEDNS0EDE(c *Cloner, infoCode uint16, extraText string) (opt *dns.EDNS0_EDE) {
+ if c == nil {
+ opt = &dns.EDNS0_EDE{}
+ } else {
+ opt = c.opt.ede.Get()
+ }
+
+ opt.InfoCode = infoCode
+ opt.ExtraText = extraText
+
+ return opt
+}
diff --git a/internal/dnsmsg/structurederror.go b/internal/dnsmsg/structurederror.go
new file mode 100644
index 0000000..6d87943
--- /dev/null
+++ b/internal/dnsmsg/structurederror.go
@@ -0,0 +1,143 @@
+package dnsmsg
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/url"
+ "strings"
+ "unicode"
+
+ "github.com/AdguardTeam/golibs/errors"
+)
+
+// StructuredDNSErrorsConfig is the configuration structure for the experimental
+// Structured DNS Errors feature.
+//
+// See https://www.ietf.org/archive/id/draft-ietf-dnsop-structured-dns-error-09.html.
+//
+// TODO(a.garipov): Add sub-error?
+type StructuredDNSErrorsConfig struct {
+ // Justification for this particular DNS filtering. It must not be empty.
+ Justification string
+
+ // Organization is an optional description of the organization.
+ Organization string
+
+ // Contact information for the DNS service. It must not be empty. All
+ // items must not be nil and must be valid mailto, sips, or tel URLs.
+ Contact []*url.URL
+
+ // Enabled, if true, enables the experimental Structured DNS Errors feature.
+ Enabled bool
+}
+
+// iJSON returns the I-JSON representation of this configuration. c must be
+// valid.
+func (c *StructuredDNSErrorsConfig) iJSON() (s string) {
+ data := &structuredDNSErrorData{
+ Justification: c.Justification,
+ Organization: c.Organization,
+ }
+
+ for _, cont := range c.Contact {
+ data.Contact = append(data.Contact, cont.String())
+ }
+
+ // The only error that could be returned here is a type error from JSON
+ // encoding, and these should never happen.
+ b := errors.Must(json.Marshal(data))
+
+ return string(b)
+}
+
+// structuredDNSErrorData is the structure for the JSON representation of the
+// SDE data.
+//
+// TODO(a.garipov): Add sub-error?
+type structuredDNSErrorData struct {
+ Justification string `json:"j"`
+ Organization string `json:"o,omitempty"`
+ Contact []string `json:"c"`
+}
+
+// forbiddenRanges contains the ranges of forbidden code points for structured
+// DNS errors according to the I-JSON specification.
+//
+// See https://datatracker.ietf.org/doc/html/rfc7493#section-2.1.
+var forbiddenRanges = []*unicode.RangeTable{unicode.Cs, unicode.Noncharacter_Code_Point}
+
+// isSurrogateOrNonCharacter returns true if r is a surrogate or a non-character
+// code point.
+func isSurrogateOrNonCharacter(r rune) (ok bool) {
+ return unicode.IsOneOf(forbiddenRanges, r)
+}
+
+// validateSDEString returns an error if s contains a surrogate or a
+// non-character code point. It always returns nil for an empty string.
+func validateSDEString(s string) (err error) {
+ if i := strings.IndexFunc(s, isSurrogateOrNonCharacter); i >= 0 {
+ return fmt.Errorf("bad code point at index %d", i)
+ }
+
+ return nil
+}
+
+// validate checks the configuration for errors.
+func (c *StructuredDNSErrorsConfig) validate(edeEnabled bool) (err error) {
+ if c == nil {
+ return errors.ErrNoValue
+ }
+
+ if !c.Enabled {
+ return nil
+ } else if !edeEnabled {
+ return errors.Error("ede must be enabled to enable sde")
+ }
+
+ var errs []error
+ if len(c.Contact) == 0 {
+ err = fmt.Errorf("contact data: %w", errors.ErrEmptyValue)
+ errs = append(errs, err)
+ }
+
+ for i, cont := range c.Contact {
+ err = validateSDEContactURL(cont)
+ if err != nil {
+ err = fmt.Errorf("contact data: at index %d: %w", i, err)
+ errs = append(errs, err)
+ }
+ }
+
+ if c.Justification == "" {
+ err = fmt.Errorf("justification: %w", errors.ErrEmptyValue)
+ errs = append(errs, err)
+ } else if err = validateSDEString(c.Justification); err != nil {
+ err = fmt.Errorf("justification: %w", err)
+ errs = append(errs, err)
+ }
+
+ if err = validateSDEString(c.Organization); err != nil {
+ err = fmt.Errorf("organization: %w", err)
+ errs = append(errs, err)
+ }
+
+ return errors.Join(errs...)
+}
+
+// validateSDEContactURL returns an error if u is not a valid SDE contact URL.
+// It doesn't check for bad code points in the URL since [url.URL.String]
+// escapes them.
+func validateSDEContactURL(u *url.URL) (err error) {
+ if u == nil {
+ return errors.ErrNoValue
+ }
+
+ switch strings.ToLower(u.Scheme) {
+ case "mailto", "sips", "tel":
+ // TODO(a.garipov): Consider more thorough validations for each scheme.
+ default:
+ return fmt.Errorf("scheme: %w: %q", errors.ErrBadEnumValue, u.Scheme)
+ }
+
+ return nil
+}
diff --git a/internal/dnsserver/cache/cache.go b/internal/dnsserver/cache/cache.go
index 8dcf89a..85ed4d6 100644
--- a/internal/dnsserver/cache/cache.go
+++ b/internal/dnsserver/cache/cache.go
@@ -31,8 +31,8 @@ type Middleware struct {
// cacheMinTTL is the minimum supported TTL for cache items.
cacheMinTTL time.Duration
- // useTTLOverride shows if the TTL overrides logic should be used.
- useTTLOverride bool
+ // overrideTTL shows if the TTL overrides logic should be used.
+ overrideTTL bool
}
// MiddlewareConfig is the configuration structure for NewMiddleware.
@@ -49,8 +49,8 @@ type MiddlewareConfig struct {
// MinTTL is the minimum supported TTL for cache items.
MinTTL time.Duration
- // UseTTLOverride shows if the TTL overrides logic should be used.
- UseTTLOverride bool
+ // OverrideTTL shows if the TTL overrides logic should be used.
+ OverrideTTL bool
}
// NewMiddleware initializes a new LRU caching middleware. c must not be nil.
@@ -63,10 +63,10 @@ func NewMiddleware(c *MiddlewareConfig) (m *Middleware) {
}
return &Middleware{
- metrics: metrics,
- cache: gcache.New(c.Size).LRU().Build(),
- cacheMinTTL: c.MinTTL,
- useTTLOverride: c.UseTTLOverride,
+ metrics: metrics,
+ cache: gcache.New(c.Size).LRU().Build(),
+ cacheMinTTL: c.MinTTL,
+ overrideTTL: c.OverrideTTL,
}
}
@@ -150,7 +150,7 @@ func (m *Middleware) set(msg *dns.Msg) (err error) {
}
exp := time.Duration(ttl) * time.Second
- if m.useTTLOverride && msg.Rcode != dns.RcodeServerFailure {
+ if m.overrideTTL && msg.Rcode != dns.RcodeServerFailure {
exp = max(exp, m.cacheMinTTL)
setMinTTL(msg, uint32(exp.Seconds()))
}
diff --git a/internal/dnsserver/cache/cache_test.go b/internal/dnsserver/cache/cache_test.go
index 6a47f54..aa4b291 100644
--- a/internal/dnsserver/cache/cache_test.go
+++ b/internal/dnsserver/cache/cache_test.go
@@ -186,9 +186,9 @@ func TestMiddleware_Wrap(t *testing.T) {
withCache := dnsserver.WithMiddlewares(
handler,
cache.NewMiddleware(&cache.MiddlewareConfig{
- Size: 100,
- MinTTL: minTTL,
- UseTTLOverride: tc.minTTL != nil,
+ Size: 100,
+ MinTTL: minTTL,
+ OverrideTTL: tc.minTTL != nil,
}),
)
diff --git a/internal/dnsserver/dnsservertest/handler.go b/internal/dnsserver/dnsservertest/handler.go
index ca0c6b3..940afe0 100644
--- a/internal/dnsserver/dnsservertest/handler.go
+++ b/internal/dnsserver/dnsservertest/handler.go
@@ -2,6 +2,7 @@ package dnsservertest
import (
"context"
+ "fmt"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
@@ -13,9 +14,15 @@ import (
// AnswerTTL is the default TTL of the test handler's answers.
const AnswerTTL time.Duration = 100 * time.Second
-// CreateTestHandler creates a [dnsserver.Handler] with the specified
+// NewDefaultHandler returns a simple handler that always returns a response
+// with a single A record.
+func NewDefaultHandler() (handler dnsserver.Handler) {
+ return NewDefaultHandlerWithCount(1)
+}
+
+// NewDefaultHandlerWithCount creates a [dnsserver.Handler] with the specified
// parameters. All responses will have the [TestAnsTTL] TTL.
-func CreateTestHandler(recordsCount int) (h dnsserver.Handler) {
+func NewDefaultHandlerWithCount(recordsCount int) (h dnsserver.Handler) {
f := func(ctx context.Context, rw dnsserver.ResponseWriter, req *dns.Msg) (err error) {
// Check that necessary context keys are set.
si := dnsserver.MustServerInfoFromContext(ctx)
@@ -49,8 +56,12 @@ func CreateTestHandler(recordsCount int) (h dnsserver.Handler) {
return dnsserver.HandlerFunc(f)
}
-// DefaultHandler returns a simple handler that always returns a response with
-// a single A record.
-func DefaultHandler() (handler dnsserver.Handler) {
- return CreateTestHandler(1)
+// NewPanicHandler returns a DNS handler that panics with an error.
+func NewPanicHandler() (handler dnsserver.Handler) {
+ f := func(ctx context.Context, rw dnsserver.ResponseWriter, req *dns.Msg) (err error) {
+ // TODO(a.garipov): Add a helper for these kinds of errors to golibs.
+ panic(fmt.Errorf("unexpected call to ServeDNS(%v, %v)", rw, req))
+ }
+
+ return dnsserver.HandlerFunc(f)
}
diff --git a/internal/dnsserver/dnsservertest/msg.go b/internal/dnsserver/dnsservertest/msg.go
index e2c144a..e3cc89f 100644
--- a/internal/dnsserver/dnsservertest/msg.go
+++ b/internal/dnsserver/dnsservertest/msg.go
@@ -273,6 +273,22 @@ func NewNS(name string, ttl uint32, ns string) (rr dns.RR) {
}
}
+// NewOPT constructs the new resource record of type OPT.
+func NewOPT(do bool, udpSize uint16, opts ...dns.EDNS0) (rr dns.RR) {
+ opt := &dns.OPT{
+ Hdr: dns.RR_Header{
+ Name: ".",
+ Rrtype: dns.TypeOPT,
+ },
+ Option: opts,
+ }
+
+ opt.SetDo(do)
+ opt.SetUDPSize(udpSize)
+
+ return opt
+}
+
// NewECSExtra constructs a new OPT RR for the extra section.
func NewECSExtra(ip net.IP, fam uint16, mask, scope uint8) (extra dns.RR) {
return &dns.OPT{
@@ -300,11 +316,8 @@ func NewEDNS0Padding(msgLen int, UDPBufferSize uint16) (extra dns.RR) {
padLen := requestPaddingBlockSize - msgLen%requestPaddingBlockSize
// Truncate padding to fit in UDP buffer.
- if msgLen+padLen > int(UDPBufferSize) {
- padLen = int(UDPBufferSize) - msgLen
- if padLen < 0 {
- padLen = 0
- }
+ if bufSzInt := int(UDPBufferSize); msgLen+padLen > bufSzInt {
+ padLen = max(bufSzInt-msgLen, 0)
}
return &dns.OPT{
diff --git a/internal/dnsserver/forward/forward_test.go b/internal/dnsserver/forward/forward_test.go
index 94215fa..5e9cb4e 100644
--- a/internal/dnsserver/forward/forward_test.go
+++ b/internal/dnsserver/forward/forward_test.go
@@ -23,7 +23,7 @@ func TestMain(m *testing.M) {
const testTimeout = 1 * time.Second
func TestHandler_ServeDNS(t *testing.T) {
- srv, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
+ srv, addr := dnsservertest.RunDNSServer(t, dnsservertest.NewDefaultHandler())
// No-fallbacks handler.
handler := forward.NewHandler(&forward.HandlerConfig{
@@ -47,7 +47,7 @@ func TestHandler_ServeDNS(t *testing.T) {
}
func TestHandler_ServeDNS_fallbackNetError(t *testing.T) {
- srv, _ := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
+ srv, _ := dnsservertest.RunDNSServer(t, dnsservertest.NewDefaultHandler())
handler := forward.NewHandler(&forward.HandlerConfig{
UpstreamsAddresses: []*forward.UpstreamPlainConfig{{
Network: forward.NetworkAny,
diff --git a/internal/dnsserver/forward/healthcheck_test.go b/internal/dnsserver/forward/healthcheck_test.go
index 3b014ef..254a336 100644
--- a/internal/dnsserver/forward/healthcheck_test.go
+++ b/internal/dnsserver/forward/healthcheck_test.go
@@ -20,7 +20,7 @@ func TestHandler_Refresh(t *testing.T) {
var upstreamIsUp atomic.Bool
var upstreamRequestsCount atomic.Int64
- defaultHandler := dnsservertest.DefaultHandler()
+ defaultHandler := dnsservertest.NewDefaultHandler()
// This handler writes an empty message if upstreamUp flag is false.
handlerFunc := dnsserver.HandlerFunc(func(
diff --git a/internal/dnsserver/forward/upstreamplain_test.go b/internal/dnsserver/forward/upstreamplain_test.go
index 860266b..b3123d6 100644
--- a/internal/dnsserver/forward/upstreamplain_test.go
+++ b/internal/dnsserver/forward/upstreamplain_test.go
@@ -36,7 +36,7 @@ func TestUpstreamPlain_Exchange(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- _, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
+ _, addr := dnsservertest.RunDNSServer(t, dnsservertest.NewDefaultHandler())
ups := forward.NewUpstreamPlain(&forward.UpstreamPlainConfig{
Network: tc.network,
Address: netip.MustParseAddrPort(addr),
@@ -65,7 +65,7 @@ func TestUpstreamPlain_Exchange_truncated(t *testing.T) {
rw.LocalAddr(),
rw.RemoteAddr(),
)
- handler := dnsservertest.DefaultHandler()
+ handler := dnsservertest.NewDefaultHandler()
err = handler.ServeDNS(ctx, nrw, req)
if err != nil {
return err
diff --git a/internal/dnsserver/go.mod b/internal/dnsserver/go.mod
index 61ba79a..a9d8c73 100644
--- a/internal/dnsserver/go.mod
+++ b/internal/dnsserver/go.mod
@@ -1,9 +1,9 @@
module github.com/AdguardTeam/AdGuardDNS/internal/dnsserver
-go 1.23.1
+go 1.23.2
require (
- github.com/AdguardTeam/golibs v0.28.0
+ github.com/AdguardTeam/golibs v0.30.1
github.com/ameshkov/dnscrypt/v2 v2.3.0
github.com/ameshkov/dnsstamps v1.0.3
github.com/bluele/gcache v0.0.2
@@ -11,12 +11,12 @@ require (
github.com/miekg/dns v1.1.62
github.com/panjf2000/ants/v2 v2.10.0
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
- github.com/prometheus/client_golang v1.20.1
- github.com/quic-go/quic-go v0.47.0
+ github.com/prometheus/client_golang v1.20.5
+ github.com/quic-go/quic-go v0.48.1
github.com/stretchr/testify v1.9.0
- golang.org/x/exp v0.0.0-20240909161429-701f63a606c0
- golang.org/x/net v0.29.0
- golang.org/x/sys v0.25.0
+ golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
+ golang.org/x/net v0.30.0
+ golang.org/x/sys v0.26.0
)
require (
@@ -26,22 +26,23 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
- github.com/google/pprof v0.0.0-20240929191954-255acd752d31 // indirect
+ github.com/google/pprof v0.0.0-20241023014458-598669927662 // indirect
+ github.com/klauspost/compress v1.17.11 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
- github.com/prometheus/common v0.55.0 // indirect
+ github.com/prometheus/common v0.60.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
- go.uber.org/mock v0.4.0 // indirect
- golang.org/x/crypto v0.27.0 // indirect
+ go.uber.org/mock v0.5.0 // indirect
+ golang.org/x/crypto v0.28.0 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/sync v0.8.0 // indirect
- golang.org/x/text v0.18.0 // indirect
- golang.org/x/time v0.6.0 // indirect
- golang.org/x/tools v0.25.0 // indirect
- google.golang.org/protobuf v1.34.2 // indirect
+ golang.org/x/text v0.19.0 // indirect
+ golang.org/x/time v0.7.0 // indirect
+ golang.org/x/tools v0.26.0 // indirect
+ google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/internal/dnsserver/go.sum b/internal/dnsserver/go.sum
index e27a1c6..870bc08 100644
--- a/internal/dnsserver/go.sum
+++ b/internal/dnsserver/go.sum
@@ -1,4 +1,5 @@
-github.com/AdguardTeam/golibs v0.28.0 h1:SK1q8SqkkJ/61pp2abTmio90S4QpteYK9rtgROfnrb4=
+github.com/AdguardTeam/golibs v0.30.1 h1:/yv7dq2h7WXw/jTDxkE3FP9zHerRT+i03PZRHJX4fPU=
+github.com/AdguardTeam/golibs v0.30.1/go.mod h1:FkwcNQEJoGsgDGXcalrVa/4gWbE68KsmE2guXWtBQUE=
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=
@@ -25,10 +26,10 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
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-20240929191954-255acd752d31 h1:LcRdQWywSgfi5jPsYZ1r2avbbs5IQ5wtyhMBCcokyo4=
-github.com/google/pprof v0.0.0-20240929191954-255acd752d31/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
-github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
-github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/google/pprof v0.0.0-20241023014458-598669927662 h1:SKMkD83p7FwUqKmBsPdLHF5dNyxq3jOWwu9w9UyH5vA=
+github.com/google/pprof v0.0.0-20241023014458-598669927662/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
+github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
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=
@@ -47,18 +48,18 @@ github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
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.20.1 h1:IMJXHOD6eARkQpxo8KkhgEVFlBNm+nkrFUyGlIu7Na8=
-github.com/prometheus/client_golang v1.20.1/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
+github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
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.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
-github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA=
+github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
-github.com/quic-go/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y=
-github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E=
+github.com/quic-go/quic-go v0.48.1 h1:y/8xmfWI9qmGTc+lBr4jKRUWLGSlSigv847ULJ4hYXA=
+github.com/quic-go/quic-go v0.48.1/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
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=
@@ -69,29 +70,29 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
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.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
-golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
-golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
-golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
+go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
+go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
+golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
+golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
+golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
+golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
-golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
-golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
+golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
-golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
-golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
-golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
-golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
-golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
-golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
-google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
-google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
+golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
+golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
+golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
+golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
+google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
+google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
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/prometheus/cache_test.go b/internal/dnsserver/prometheus/cache_test.go
index 0b80841..05545ac 100644
--- a/internal/dnsserver/prometheus/cache_test.go
+++ b/internal/dnsserver/prometheus/cache_test.go
@@ -23,7 +23,7 @@ func TestCacheMetricsListener_integration_cache(t *testing.T) {
})
handlerWithMiddleware := dnsserver.WithMiddlewares(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
cacheMiddleware,
)
diff --git a/internal/dnsserver/prometheus/forward_test.go b/internal/dnsserver/prometheus/forward_test.go
index e1bacf5..5913fa6 100644
--- a/internal/dnsserver/prometheus/forward_test.go
+++ b/internal/dnsserver/prometheus/forward_test.go
@@ -18,7 +18,7 @@ import (
// normal unit test, we create a forward handler, emulate a query and then
// check if prom metrics were incremented.
func TestForwardMetricsListener_integration_request(t *testing.T) {
- srv, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
+ srv, addr := dnsservertest.RunDNSServer(t, dnsservertest.NewDefaultHandler())
// Initialize a new forward.Handler and set the metrics listener.
handler := forward.NewHandler(&forward.HandlerConfig{
diff --git a/internal/dnsserver/prometheus/ratelimit_test.go b/internal/dnsserver/prometheus/ratelimit_test.go
index 1706794..97a126c 100644
--- a/internal/dnsserver/prometheus/ratelimit_test.go
+++ b/internal/dnsserver/prometheus/ratelimit_test.go
@@ -19,16 +19,21 @@ import (
// normal unit test, we create a cache middleware, emulate a query and then
// check if prom metrics were incremented.
func TestRateLimiterMetricsListener_integration_cache(t *testing.T) {
- rps := 5
+ const (
+ count = 5
+ ivl = time.Second
+ )
rl := ratelimit.NewBackoff(&ratelimit.BackoffConfig{
Allowlist: ratelimit.NewDynamicAllowlist([]netip.Prefix{}, []netip.Prefix{}),
Period: time.Minute,
Duration: time.Minute,
- Count: uint(rps),
+ Count: count,
ResponseSizeEstimate: 1 * datasize.KB,
- IPv4RPS: uint(rps),
- IPv6RPS: uint(rps),
+ IPv4Count: count,
+ IPv4Interval: ivl,
+ IPv6Count: count,
+ IPv6Interval: ivl,
RefuseANY: true,
})
rlMw, err := ratelimit.NewMiddleware(&ratelimit.MiddlewareConfig{
@@ -38,7 +43,7 @@ func TestRateLimiterMetricsListener_integration_cache(t *testing.T) {
require.NoError(t, err)
handlerWithMiddleware := dnsserver.WithMiddlewares(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
rlMw,
)
@@ -55,7 +60,7 @@ func TestRateLimiterMetricsListener_integration_cache(t *testing.T) {
err = handlerWithMiddleware.ServeDNS(ctx, nrw, req)
require.NoError(t, err)
- if i < rps {
+ if i < count {
dnsservertest.RequireResponse(t, req, nrw.Msg(), 1, dns.RcodeSuccess, false)
} else {
require.Nil(t, nrw.Msg())
diff --git a/internal/dnsserver/prometheus/server_test.go b/internal/dnsserver/prometheus/server_test.go
index 23c6910..f52a3b1 100644
--- a/internal/dnsserver/prometheus/server_test.go
+++ b/internal/dnsserver/prometheus/server_test.go
@@ -24,7 +24,7 @@ func TestServerMetricsListener_integration_requestLifetime(t *testing.T) {
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Handler: dnsservertest.DefaultHandler(),
+ Handler: dnsservertest.NewDefaultHandler(),
Metrics: prometheus.NewServerMetricsListener(testNamespace),
},
}
diff --git a/internal/dnsserver/ratelimit/backoff.go b/internal/dnsserver/ratelimit/backoff.go
index 27fb89b..09d0ec0 100644
--- a/internal/dnsserver/ratelimit/backoff.go
+++ b/internal/dnsserver/ratelimit/backoff.go
@@ -36,19 +36,29 @@ type BackoffConfig struct {
// as several responses.
ResponseSizeEstimate datasize.ByteSize
- // IPv4RPS is the maximum number of requests per second allowed from a
- // single subnet for IPv4 addresses. Any requests above this rate are
- // counted as the client's backoff count. RPS must be greater than zero.
- IPv4RPS uint
+ // IPv4Count is the maximum number of requests per a specified interval
+ // allowed from a single subnet for IPv4 addresses. Any requests above this
+ // rate are counted as the client's backoff count. It must be greater than
+ // zero.
+ IPv4Count uint
+
+ // IPv4Interval is the time during which to count the number of requests
+ // for IPv4 addresses.
+ IPv4Interval time.Duration
// IPv4SubnetKeyLen is the length of the subnet prefix used to calculate
// rate limiter bucket keys for IPv4 addresses. Must be greater than zero.
IPv4SubnetKeyLen int
- // IPv6RPS is the maximum number of requests per second allowed from a
- // single subnet for IPv6 addresses. Any requests above this rate are
- // counted as the client's backoff count. RPS must be greater than zero.
- IPv6RPS uint
+ // IPv6Count is the maximum number of requests per a specified interval
+ // allowed from a single subnet for IPv6 addresses. Any requests above this
+ // rate are counted as the client's backoff count. It must be greater than
+ // zero.
+ IPv6Count uint
+
+ // IPv6Interval is the time during which to count the number of requests
+ // for IPv6 addresses.
+ IPv6Interval time.Duration
// IPv6SubnetKeyLen is the length of the subnet prefix used to calculate
// rate limiter bucket keys for IPv6 addresses. Must be greater than zero.
@@ -75,9 +85,11 @@ type Backoff struct {
allowlist Allowlist
respSzEst datasize.ByteSize
count uint
- ipv4rps uint
+ ipv4Count uint
+ ipv4Interval time.Duration
ipv4SubnetKeyLen int
- ipv6rps uint
+ ipv6Count uint
+ ipv6Interval time.Duration
ipv6SubnetKeyLen int
refuseANY bool
}
@@ -93,9 +105,11 @@ func NewBackoff(c *BackoffConfig) (l *Backoff) {
allowlist: c.Allowlist,
respSzEst: c.ResponseSizeEstimate,
count: c.Count,
- ipv4rps: c.IPv4RPS,
+ ipv4Count: c.IPv4Count,
+ ipv4Interval: c.IPv4Interval,
ipv4SubnetKeyLen: c.IPv4SubnetKeyLen,
- ipv6rps: c.IPv6RPS,
+ ipv6Count: c.IPv6Count,
+ ipv6Interval: c.IPv6Interval,
ipv6SubnetKeyLen: c.IPv6SubnetKeyLen,
refuseANY: c.RefuseANY,
}
@@ -133,12 +147,12 @@ func (l *Backoff) IsRateLimited(
return true, false, nil
}
- rps := l.ipv4rps
+ count, ivl := l.ipv4Count, l.ipv4Interval
if ip.Is6() {
- rps = l.ipv6rps
+ count, ivl = l.ipv6Count, l.ipv6Interval
}
- return l.hasHitRateLimit(key, rps), false, nil
+ return l.hasHitRateLimit(key, count, ivl), false, nil
}
// validateAddr returns an error if addr is not a valid IPv4 or IPv6 address.
@@ -198,15 +212,15 @@ func (l *Backoff) incBackoff(key string) {
l.hitCounters.SetDefault(key, counter)
}
-// hasHitRateLimit checks value for a subnet with rps as a maximum number
-// requests per second.
-func (l *Backoff) hasHitRateLimit(subnetIPStr string, rps uint) (ok bool) {
+// hasHitRateLimit checks if the value of requests for given subnet hit the
+// maximum count of requests per given interval.
+func (l *Backoff) hasHitRateLimit(subnetIPStr string, count uint, ivl time.Duration) (ok bool) {
var r *RequestCounter
rVal, ok := l.reqCounters.Get(subnetIPStr)
if ok {
r = rVal.(*RequestCounter)
} else {
- r = NewRequestCounter(rps, time.Second)
+ r = NewRequestCounter(count, ivl)
l.reqCounters.SetDefault(subnetIPStr, r)
}
diff --git a/internal/dnsserver/ratelimit/ratelimit_test.go b/internal/dnsserver/ratelimit/ratelimit_test.go
index 8b2168d..adf5f17 100644
--- a/internal/dnsserver/ratelimit/ratelimit_test.go
+++ b/internal/dnsserver/ratelimit/ratelimit_test.go
@@ -22,7 +22,10 @@ func TestMain(m *testing.M) {
}
func TestRatelimitMiddleware(t *testing.T) {
- const rps = 10
+ const (
+ rps = 10
+ ivl = time.Second
+ )
persistent := []netip.Prefix{
netip.MustParsePrefix("4.3.2.1/8"),
@@ -99,9 +102,11 @@ func TestRatelimitMiddleware(t *testing.T) {
Duration: time.Minute,
Count: rps,
ResponseSizeEstimate: 128 * datasize.B,
- IPv4RPS: rps,
+ IPv4Count: rps,
+ IPv4Interval: ivl,
IPv4SubnetKeyLen: 24,
- IPv6RPS: rps,
+ IPv6Count: rps,
+ IPv6Interval: ivl,
IPv6SubnetKeyLen: 48,
RefuseANY: true,
})
@@ -112,7 +117,7 @@ func TestRatelimitMiddleware(t *testing.T) {
require.NoError(t, err)
withMw := dnsserver.WithMiddlewares(
- dnsservertest.CreateTestHandler(tc.respCount),
+ dnsservertest.NewDefaultHandlerWithCount(tc.respCount),
rlMw,
)
diff --git a/internal/dnsserver/serverbase.go b/internal/dnsserver/serverbase.go
index 686bcec..5f54f1e 100644
--- a/internal/dnsserver/serverbase.go
+++ b/internal/dnsserver/serverbase.go
@@ -309,6 +309,10 @@ func (s *ServerBase) serveDNSMsgInternal(
s.metrics.OnError(ctx, err)
resp = genErrorResponse(req, dns.RcodeServerFailure)
+ if isNonCriticalNetError(err) {
+ addEDE(req, resp, dns.ExtendedErrorCodeNetworkError, "")
+ }
+
err = rw.WriteMsg(ctx, req, resp)
if err != nil {
log.Debug("[%d]: error writing a response: %s", req.Id, err)
@@ -316,6 +320,28 @@ func (s *ServerBase) serveDNSMsgInternal(
}
}
+// addEDE adds an Extended DNS Error (EDE) option to the blocked response
+// message, if the request indicates EDNS support.
+func addEDE(req, resp *dns.Msg, code uint16, text string) {
+ reqOpt := req.IsEdns0()
+ if reqOpt == nil {
+ // Requestor doesn't implement EDNS, see
+ // https://datatracker.ietf.org/doc/html/rfc6891#section-7.
+ return
+ }
+
+ respOpt := resp.IsEdns0()
+ if respOpt == nil {
+ resp.SetEdns0(reqOpt.UDPSize(), reqOpt.Do())
+ respOpt = resp.Extra[len(resp.Extra)-1].(*dns.OPT)
+ }
+
+ respOpt.Option = append(respOpt.Option, &dns.EDNS0_EDE{
+ InfoCode: code,
+ ExtraText: text,
+ })
+}
+
// acceptMsg checks if we should process the incoming DNS query.
func (s *ServerBase) acceptMsg(m *dns.Msg) (action dns.MsgAcceptAction) {
if m.Response {
diff --git a/internal/dnsserver/serverbench_test.go b/internal/dnsserver/serverbench_test.go
index c1c5bb1..b245661 100644
--- a/internal/dnsserver/serverbench_test.go
+++ b/internal/dnsserver/serverbench_test.go
@@ -37,7 +37,7 @@ func BenchmarkServeDNS(b *testing.B) {
for _, tc := range testCases {
b.Run(tc.name, func(b *testing.B) {
- _, addr := dnsservertest.RunDNSServer(b, dnsservertest.DefaultHandler())
+ _, addr := dnsservertest.RunDNSServer(b, dnsservertest.NewDefaultHandler())
// Prepare a test message.
m := new(dns.Msg)
@@ -105,7 +105,7 @@ func readMsg(resBuf []byte, network dnsserver.Network, conn net.Conn) (err error
func BenchmarkServeTLS(b *testing.B) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
- addr := dnsservertest.RunTLSServer(b, dnsservertest.DefaultHandler(), tlsConfig)
+ addr := dnsservertest.RunTLSServer(b, dnsservertest.NewDefaultHandler(), tlsConfig)
// Prepare a test message
m := new(dns.Msg)
@@ -171,7 +171,7 @@ func BenchmarkServeDoH(b *testing.B) {
for _, tc := range testCases {
b.Run(tc.name, func(b *testing.B) {
srv, err := dnsservertest.RunLocalHTTPSServer(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
tc.tlsConfig,
nil,
)
@@ -250,7 +250,7 @@ func BenchmarkServeDNSCrypt(b *testing.B) {
Net: string(tc.network),
}
- s := dnsservertest.RunDNSCryptServer(b, dnsservertest.DefaultHandler())
+ s := dnsservertest.RunDNSCryptServer(b, dnsservertest.NewDefaultHandler())
stamp := dnsstamps.ServerStamp{
ServerAddrStr: s.ServerAddr,
ServerPk: s.ResolverPk,
@@ -282,7 +282,7 @@ func BenchmarkServeDNSCrypt(b *testing.B) {
func BenchmarkServeQUIC(b *testing.B) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
srv, addr, err := dnsservertest.RunLocalQUICServer(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
tlsConfig,
)
require.NoError(b, err)
diff --git a/internal/dnsserver/serverdns_test.go b/internal/dnsserver/serverdns_test.go
index 0f89ce8..0a7634c 100644
--- a/internal/dnsserver/serverdns_test.go
+++ b/internal/dnsserver/serverdns_test.go
@@ -20,7 +20,7 @@ import (
)
func TestServerDNS_StartShutdown(t *testing.T) {
- _, _ = dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
+ _, _ = dnsservertest.RunDNSServer(t, dnsservertest.NewDefaultHandler())
}
func TestServerDNS_integration_query(t *testing.T) {
@@ -42,7 +42,7 @@ func TestServerDNS_integration_query(t *testing.T) {
{Name: "example.org.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
},
},
- handler: dnsservertest.DefaultHandler(),
+ handler: dnsservertest.NewDefaultHandler(),
wantRecordsCount: 1,
wantRCode: dns.RcodeSuccess,
}, {
@@ -54,7 +54,7 @@ func TestServerDNS_integration_query(t *testing.T) {
{Name: "example.org.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
},
},
- handler: dnsservertest.DefaultHandler(),
+ handler: dnsservertest.NewDefaultHandler(),
wantRecordsCount: 1,
wantRCode: dns.RcodeSuccess,
}, {
@@ -89,7 +89,7 @@ func TestServerDNS_integration_query(t *testing.T) {
},
},
},
- handler: dnsservertest.DefaultHandler(),
+ handler: dnsservertest.NewDefaultHandler(),
wantMsg: func(t *testing.T, m *dns.Msg) {
opt := m.IsEdns0()
require.NotNil(t, opt)
@@ -109,7 +109,7 @@ func TestServerDNS_integration_query(t *testing.T) {
{Name: "example.org.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
},
},
- handler: dnsservertest.DefaultHandler(),
+ handler: dnsservertest.NewDefaultHandler(),
wantRecordsCount: 0,
wantRCode: dns.RcodeFormatError,
}, {
@@ -122,7 +122,7 @@ func TestServerDNS_integration_query(t *testing.T) {
{Name: "eXaMplE.oRg.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
},
},
- handler: dnsservertest.DefaultHandler(),
+ handler: dnsservertest.NewDefaultHandler(),
wantRecordsCount: 1,
wantRCode: dns.RcodeSuccess,
}, {
@@ -136,7 +136,7 @@ func TestServerDNS_integration_query(t *testing.T) {
{Name: "example.org.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
},
},
- handler: dnsservertest.DefaultHandler(),
+ handler: dnsservertest.NewDefaultHandler(),
wantRecordsCount: 0,
wantRCode: dns.RcodeNotImplemented,
}, {
@@ -170,7 +170,7 @@ func TestServerDNS_integration_query(t *testing.T) {
{Name: "example.org.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
},
},
- handler: dnsservertest.DefaultHandler(),
+ handler: dnsservertest.NewDefaultHandler(),
wantRecordsCount: 1,
wantRCode: dns.RcodeSuccess,
}, {
@@ -185,7 +185,7 @@ func TestServerDNS_integration_query(t *testing.T) {
},
},
// Set a handler that generates a large response
- handler: dnsservertest.CreateTestHandler(64),
+ handler: dnsservertest.NewDefaultHandlerWithCount(64),
wantRecordsCount: 0,
wantRCode: dns.RcodeSuccess,
wantTruncated: true,
@@ -210,7 +210,7 @@ func TestServerDNS_integration_query(t *testing.T) {
},
},
// Set a handler that generates a large response
- handler: dnsservertest.CreateTestHandler(64),
+ handler: dnsservertest.NewDefaultHandlerWithCount(64),
wantRecordsCount: 64,
wantRCode: dns.RcodeSuccess,
wantTruncated: false,
@@ -226,7 +226,7 @@ func TestServerDNS_integration_query(t *testing.T) {
},
},
// Set a handler that generates a large response
- handler: dnsservertest.CreateTestHandler(64),
+ handler: dnsservertest.NewDefaultHandlerWithCount(64),
// No truncate
wantRecordsCount: 64,
wantRCode: dns.RcodeSuccess,
@@ -257,7 +257,7 @@ func TestServerDNS_integration_query(t *testing.T) {
},
},
},
- handler: dnsservertest.DefaultHandler(),
+ handler: dnsservertest.NewDefaultHandler(),
wantRecordsCount: 1,
wantRCode: dns.RcodeSuccess,
}}
@@ -304,7 +304,7 @@ func TestServerDNS_integration_tcpQueriesPipelining(t *testing.T) {
// As per RFC 7766 we should support queries pipelining for TCP, that is
// server must be able to process incoming queries in parallel and write
// responses possibly out of order within the same connection.
- _, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
+ _, addr := dnsservertest.RunDNSServer(t, dnsservertest.NewDefaultHandler())
// Establish a connection.
conn, err := net.Dial("tcp", addr)
@@ -372,7 +372,7 @@ func TestServerDNS_integration_tcpQueriesPipelining(t *testing.T) {
}
func TestServerDNS_integration_udpMsgIgnore(t *testing.T) {
- _, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
+ _, addr := dnsservertest.RunDNSServer(t, dnsservertest.NewDefaultHandler())
conn, err := net.Dial("udp", addr)
require.Nil(t, err)
@@ -469,7 +469,7 @@ func TestServerDNS_integration_tcpMsgIgnore(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
- _, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
+ _, addr := dnsservertest.RunDNSServer(t, dnsservertest.NewDefaultHandler())
conn, err := net.Dial("tcp", addr)
require.Nil(t, err)
diff --git a/internal/dnsserver/serverdnscrypt_test.go b/internal/dnsserver/serverdnscrypt_test.go
index 48adcb9..3365b69 100644
--- a/internal/dnsserver/serverdnscrypt_test.go
+++ b/internal/dnsserver/serverdnscrypt_test.go
@@ -49,7 +49,7 @@ func TestServerDNSCrypt_integration_query(t *testing.T) {
name: "udp_truncate_response",
network: dnsserver.NetworkUDP,
// Set a handler that generates a large response
- handler: dnsservertest.CreateTestHandler(64),
+ handler: dnsservertest.NewDefaultHandlerWithCount(64),
// DNSCrypt server removes all records from a truncated response
expectedRecordsCount: 0,
expectedRCode: dns.RcodeSuccess,
@@ -66,7 +66,7 @@ func TestServerDNSCrypt_integration_query(t *testing.T) {
name: "udp_edns0_no_truncate",
network: dnsserver.NetworkUDP,
// Set a handler that generates a large response
- handler: dnsservertest.CreateTestHandler(64),
+ handler: dnsservertest.NewDefaultHandlerWithCount(64),
expectedRecordsCount: 64,
expectedRCode: dns.RcodeSuccess,
expectedTruncated: false,
@@ -89,7 +89,7 @@ func TestServerDNSCrypt_integration_query(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
handler := tc.handler
if tc.handler == nil {
- handler = dnsservertest.DefaultHandler()
+ handler = dnsservertest.NewDefaultHandler()
}
s := dnsservertest.RunDNSCryptServer(t, handler)
diff --git a/internal/dnsserver/serverhttps.go b/internal/dnsserver/serverhttps.go
index d24e323..848d80b 100644
--- a/internal/dnsserver/serverhttps.go
+++ b/internal/dnsserver/serverhttps.go
@@ -19,6 +19,7 @@ import (
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/miekg/dns"
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/http3"
@@ -304,9 +305,9 @@ func (s *ServerHTTPS) serveHTTPS(ctx context.Context, hs *http.Server, l net.Lis
// application won't be able to continue listening to DoH.
defer s.handlePanicAndExit(ctx)
- scheme := "https"
+ scheme := urlutil.SchemeHTTPS
if s.conf.TLSConfig == nil {
- scheme = "http"
+ scheme = urlutil.SchemeHTTP
}
u := &url.URL{
diff --git a/internal/dnsserver/serverhttps_test.go b/internal/dnsserver/serverhttps_test.go
index f91a555..9b9c9c6 100644
--- a/internal/dnsserver/serverhttps_test.go
+++ b/internal/dnsserver/serverhttps_test.go
@@ -109,7 +109,7 @@ func TestServerHTTPS_integration_serveRequests(t *testing.T) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
srv, err := dnsservertest.RunLocalHTTPSServer(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
tlsConfig,
nil,
)
@@ -146,7 +146,7 @@ func TestServerHTTPS_integration_nonDNSHandler(t *testing.T) {
})
srv, err := dnsservertest.RunLocalHTTPSServer(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
nil,
testHandler,
)
@@ -321,7 +321,7 @@ func TestDNSMsgToJSONMsg(t *testing.T) {
func TestServerHTTPS_integration_ENDS0Padding(t *testing.T) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
srv, err := dnsservertest.RunLocalHTTPSServer(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
tlsConfig,
nil,
)
@@ -346,7 +346,7 @@ func TestServerHTTPS_integration_ENDS0Padding(t *testing.T) {
func TestServerHTTPS_0RTT(t *testing.T) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
srv, err := dnsservertest.RunLocalHTTPSServer(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
tlsConfig,
nil,
)
@@ -514,7 +514,7 @@ func createDoH3Client(
tlsConfig = tlsConfig.Clone()
tlsConfig.NextProtos = []string{http3.NextProtoH3}
- transport := &http3.RoundTripper{
+ transport := &http3.Transport{
DisableCompression: true,
Dial: func(
ctx context.Context,
diff --git a/internal/dnsserver/serverhttpsjson.go b/internal/dnsserver/serverhttpsjson.go
index 19a3db5..9415942 100644
--- a/internal/dnsserver/serverhttpsjson.go
+++ b/internal/dnsserver/serverhttpsjson.go
@@ -7,13 +7,18 @@ import (
"strconv"
"strings"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/miekg/dns"
)
// 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
-// and there's no "edns_client_subnet".
+//
+// NOTE: This API differs from the Google one in the following ways:
+// 1. The "Comment" field is not implemented.
+// 2. The "edns_client_subnet" query parameter is not supported.
+// 3. The "sde" query parameter is added and supported for the experimental
+// Structured DNS Errors feature.
type JSONMsg struct {
Question []JSONQuestion `json:"Question"`
Answer []JSONAnswer `json:"Answer"`
@@ -26,13 +31,13 @@ type JSONMsg struct {
Status int `json:"Status"`
}
-// JSONQuestion is a part of JSONMsg definition.
+// JSONQuestion is a part of [JSONMsg] definition.
type JSONQuestion struct {
Name string `json:"name"`
Type uint16 `json:"type"`
}
-// JSONAnswer is a part of JSONMsg definition.
+// JSONAnswer is a part of [JSONMsg] definition.
type JSONAnswer struct {
Name string `json:"name"`
Data string `json:"data"`
@@ -41,7 +46,7 @@ type JSONAnswer struct {
Class uint16 `json:"class"`
}
-// DNSMsgToJSONMsg converts the *dns.Msg to the JSON format (*JSONMsg).
+// DNSMsgToJSONMsg converts the *dns.Msg to the JSON format.
func DNSMsgToJSONMsg(m *dns.Msg) (msg *JSONMsg) {
msg = &JSONMsg{
Status: m.Rcode,
@@ -74,9 +79,9 @@ func DNSMsgToJSONMsg(m *dns.Msg) (msg *JSONMsg) {
func rrToJSON(rr dns.RR) (j JSONAnswer) {
hdr := rr.Header()
- // Extracting the RR value is a bit tricky since miekg/dns does not
- // expose the necessary methods. This way we can benefit from the
- // proper string serialization code that's used inside miekg/dns.
+ // Extracting the RR value is a bit tricky since miekg/dns does not expose
+ // the necessary methods. This way we can benefit from the proper string
+ // serialization code that's used inside miekg/dns.
hdrStr := hdr.String()
valStr := rr.String()
data := strings.TrimLeft(strings.TrimPrefix(valStr, hdrStr), " ")
@@ -90,19 +95,17 @@ func rrToJSON(rr dns.RR) (j JSONAnswer) {
}
}
-// dnsMsgToJSON converts the *dns.Msg to the JSON format (JSONMsg) and returns
-// it in the serialized form.
+// dnsMsgToJSON converts the *dns.Msg to the JSON format and returns it in the
+// serialized form.
func dnsMsgToJSON(m *dns.Msg) (b []byte, err error) {
- msg := DNSMsgToJSONMsg(m)
- return json.Marshal(msg)
+ return json.Marshal(DNSMsgToJSONMsg(m))
}
// httpRequestToMsgJSON builds a DNS message from the request parameters.
-// We use the same parameters as the ones defined here:
-// https://developers.google.com/speed/public-dns/docs/doh/json#supported_parameters
-// Some parameters are not supported: "ct", "edns_client_subnet".
-func httpRequestToMsgJSON(req *http.Request) (b []byte, err error) {
- q := req.URL.Query()
+//
+// See [JSONMsg].
+func httpRequestToMsgJSON(httpReq *http.Request) (b []byte, err error) {
+ q := httpReq.URL.Query()
// Query name, the only required parameter.
name := q.Get("name")
@@ -111,71 +114,91 @@ func httpRequestToMsgJSON(req *http.Request) (b []byte, err error) {
return nil, ErrInvalidArgument
}
- // RR type can be represented as a number in [1, 65535] or a
- // canonical string (case-insensitive, such as A or AAAA).
- var t uint16
- t, err = urlQueryParameterToUint16(q, "type", dns.TypeA, dns.StringToType)
+ // RR type can be represented as a number in [1, 65535] or a canonical
+ // string (case-insensitive, such as A or AAAA).
+ qt, err := urlQueryParameterToUint16(q, "type", dns.TypeA, dns.StringToType)
if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
return nil, err
}
- // Query class can be represented as a number in [1, 65535] or a
- // canonical string (case-insensitive).
- var qc uint16
- qc, err = urlQueryParameterToUint16(q, "qc", dns.ClassINET, dns.StringToClass)
+ // Query class can be represented as a number in [1, 65535] or a canonical
+ // string (case-insensitive).
+ qc, err := urlQueryParameterToUint16(q, "qc", dns.ClassINET, dns.StringToClass)
if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
return nil, err
}
- // The CD (Checking Disabled) flag. Use cd=1, or cd=true to disable
- // DNSSEC validation; use cd=0, cd=false, or no cd parameter to
- // enable DNSSEC validation.
- var cd bool
- cd, err = urlQueryParameterToBoolean(q, "cd", false)
+ // The CD (Checking Disabled) flag. Use cd=1, or cd=true to disable DNSSEC
+ // validation; use cd=0, cd=false, or no cd parameter to enable DNSSEC
+ // validation.
+ cd, err := urlQueryParameterToBoolean(q, "cd", false)
if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
return nil, err
}
- // The DO (DNSSEC OK) flag. Use do=1, or do=true to include DNSSEC
- // records (RRSIG, NSEC, NSEC3); use do=0, do=false, or no do parameter
- // to omit DNSSEC records.
- var do bool
- do, err = urlQueryParameterToBoolean(q, "do", false)
+ // The DO (DNSSEC OK) flag. Use do=1 (or do=true) to include DNSSEC records
+ // (RRSIG, NSEC, NSEC3); use do=0 (do=false) or no do parameter to omit
+ // DNSSEC records.
+ do, err := urlQueryParameterToBoolean(q, "do", false)
if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return nil, err
+ }
+
+ // The experimental Structured DNS Errors feature.
+ sde, err := urlQueryParameterToBoolean(q, "sde", false)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
return nil, err
}
// Now build a DNS message with all those parameters
- r := &dns.Msg{
+ req := &dns.Msg{
MsgHdr: dns.MsgHdr{
Id: dns.Id(),
CheckingDisabled: cd,
RecursionDesired: true,
},
- Question: []dns.Question{
- {
- Name: dns.Fqdn(name),
- Qtype: t,
- Qclass: qc,
- },
- },
+ Question: []dns.Question{{
+ Name: dns.Fqdn(name),
+ Qtype: qt,
+ Qclass: qc,
+ }},
}
- if do {
- r.SetEdns0(dns.MaxMsgSize, do)
+ setEDNSFromQuery(req, do, sde)
+
+ return req.Pack()
+}
+
+// setEDNSFromQuery sets the EDNS parameters on the request depending on the
+// query parameters.
+func setEDNSFromQuery(req *dns.Msg, do, sde bool) {
+ if !do && !sde {
+ return
}
- return r.Pack()
+ req.SetEdns0(dns.MaxMsgSize, do)
+
+ if sde {
+ opt := req.Extra[0].(*dns.OPT)
+ opt.Option = append(opt.Option, &dns.EDNS0_EDE{})
+ }
}
// 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.
func urlQueryParameterToUint16(
q url.Values,
name string,
defaultValue uint16,
strValuesMap map[string]uint16,
) (v uint16, err error) {
+ defer func() { err = errors.Annotate(err, "parameter %q: %w", name) }()
+
strValue := q.Get(name)
uintValue, convErr := strconv.ParseUint(strValue, 10, 16)
switch {
@@ -199,12 +222,8 @@ func urlQueryParameterToUint16(
}
// urlQueryParameterToBoolean is a helper function that extracts a boolean value
-// from a query parameter. See httpRequestToMsgJSON to see how it's used.
-func urlQueryParameterToBoolean(
- q url.Values,
- name string,
- defaultValue bool,
-) (v bool, err error) {
+// from a query parameter.
+func urlQueryParameterToBoolean(q url.Values, name string, defaultValue bool) (v bool, err error) {
strValue := q.Get(name)
switch strValue {
case "1", "true", "True":
diff --git a/internal/dnsserver/serverquic_test.go b/internal/dnsserver/serverquic_test.go
index b2e08bc..0eadfcd 100644
--- a/internal/dnsserver/serverquic_test.go
+++ b/internal/dnsserver/serverquic_test.go
@@ -25,7 +25,7 @@ import (
func TestServerQUIC_integration_query(t *testing.T) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
srv, addr, err := dnsservertest.RunLocalQUICServer(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
tlsConfig,
)
require.NoError(t, err)
@@ -74,7 +74,7 @@ func TestServerQUIC_integration_query(t *testing.T) {
func TestServerQUIC_integration_ENDS0Padding(t *testing.T) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
srv, addr, err := dnsservertest.RunLocalQUICServer(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
tlsConfig,
)
require.NoError(t, err)
@@ -108,7 +108,7 @@ func TestServerQUIC_integration_ENDS0Padding(t *testing.T) {
func TestServerQUIC_integration_0RTT(t *testing.T) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
srv, addr, err := dnsservertest.RunLocalQUICServer(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
tlsConfig,
)
require.NoError(t, err)
@@ -146,7 +146,7 @@ func TestServerQUIC_integration_0RTT(t *testing.T) {
func TestServerQUIC_integration_largeQuery(t *testing.T) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
srv, addr, err := dnsservertest.RunLocalQUICServer(
- dnsservertest.DefaultHandler(),
+ dnsservertest.NewDefaultHandler(),
tlsConfig,
)
require.NoError(t, err)
diff --git a/internal/dnsserver/servertls_test.go b/internal/dnsserver/servertls_test.go
index 5ab1a92..16af47c 100644
--- a/internal/dnsserver/servertls_test.go
+++ b/internal/dnsserver/servertls_test.go
@@ -17,7 +17,7 @@ import (
func TestServerTLS_integration_queryTLS(t *testing.T) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
- addr := dnsservertest.RunTLSServer(t, dnsservertest.DefaultHandler(), tlsConfig)
+ addr := dnsservertest.RunTLSServer(t, dnsservertest.NewDefaultHandler(), tlsConfig)
// Create a test message.
req := new(dns.Msg)
@@ -94,7 +94,7 @@ func TestServerTLS_integration_msgIgnore(t *testing.T) {
t.Parallel()
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
- h := dnsservertest.DefaultHandler()
+ h := dnsservertest.NewDefaultHandler()
addr := dnsservertest.RunTLSServer(t, h, tlsConfig)
conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
@@ -120,7 +120,7 @@ func TestServerTLS_integration_msgIgnore(t *testing.T) {
func TestServerTLS_integration_noTruncateQuery(t *testing.T) {
// Handler that writes a huge response which would not fit
// into a UDP response, but it should fit a TCP response just okay.
- handler := dnsservertest.CreateTestHandler(64)
+ handler := dnsservertest.NewDefaultHandlerWithCount(64)
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
addr := dnsservertest.RunTLSServer(t, handler, tlsConfig)
@@ -155,7 +155,7 @@ func TestServerTLS_integration_queriesPipelining(t *testing.T) {
// i.e. we should be able to process incoming queries in parallel and
// write responses out of order.
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
- addr := dnsservertest.RunTLSServer(t, dnsservertest.DefaultHandler(), tlsConfig)
+ addr := dnsservertest.RunTLSServer(t, dnsservertest.NewDefaultHandler(), tlsConfig)
// First - establish a connection
conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
@@ -221,7 +221,7 @@ func TestServerTLS_integration_queriesPipelining(t *testing.T) {
func TestServerTLS_integration_ENDS0Padding(t *testing.T) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
- addr := dnsservertest.RunTLSServer(t, dnsservertest.DefaultHandler(), tlsConfig)
+ addr := dnsservertest.RunTLSServer(t, dnsservertest.NewDefaultHandler(), tlsConfig)
req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
req.Extra = []dns.RR{dnsservertest.NewEDNS0Padding(req.Len(), dns.DefaultMsgSize)}
diff --git a/internal/dnssvc/config.go b/internal/dnssvc/config.go
new file mode 100644
index 0000000..1c01ad9
--- /dev/null
+++ b/internal/dnssvc/config.go
@@ -0,0 +1,228 @@
+package dnssvc
+
+import (
+ "log/slog"
+ "net/http"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/access"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
+ "github.com/AdguardTeam/AdGuardDNS/internal/billstat"
+ "github.com/AdguardTeam/AdGuardDNS/internal/cmd/plugin"
+ "github.com/AdguardTeam/AdGuardDNS/internal/connlimiter"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/netext"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter"
+ "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
+ "github.com/AdguardTeam/AdGuardDNS/internal/querylog"
+ "github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+// Config is the configuration of the AdGuard DNS service.
+type Config struct {
+ // Handlers are the handlers to use in this DNS service.
+ Handlers Handlers
+
+ // NewListener, when set, is used instead of the package-level function
+ // [NewListener] when creating a DNS listener.
+ //
+ // TODO(a.garipov): This is only used for tests. Replace with a
+ // [netext.ListenConfig].
+ NewListener NewListenerFunc
+
+ // Cloner is used to clone messages more efficiently by disposing of parts
+ // of DNS responses for later reuse. It must not be nil.
+ Cloner *dnsmsg.Cloner
+
+ // ControlConf is the configuration of socket options.
+ ControlConf *netext.ControlConfig
+
+ // ConnLimiter, if not nil, is used to limit the number of simultaneously
+ // active stream-connections.
+ ConnLimiter *connlimiter.Limiter
+
+ // ErrColl is the error collector that is used to collect critical and
+ // non-critical errors. It must not be nil.
+ ErrColl errcoll.Interface
+
+ // NonDNS is the handler for non-DNS HTTP requests. It must not be nil.
+ NonDNS http.Handler
+
+ // MetricsNamespace is a namespace for Prometheus metrics. It must be a
+ // valid Prometheus metric label.
+ MetricsNamespace string
+
+ // ServerGroups are the DNS server groups. Each element must be non-nil.
+ ServerGroups []*agd.ServerGroup
+
+ // HandleTimeout defines the timeout for the entire handling of a single
+ // query. It must be greater than zero.
+ HandleTimeout time.Duration
+}
+
+// NewListenerFunc is the type for DNS listener constructors.
+type NewListenerFunc func(
+ srv *agd.Server,
+ baseConf dnsserver.ConfigBase,
+ nonDNS http.Handler,
+) (l Listener, err error)
+
+// Listener is a type alias for dnsserver.Server to make internal naming more
+// consistent.
+type Listener = dnsserver.Server
+
+// HandlersConfig is the configuration necessary to create or wrap the main DNS
+// handler.
+//
+// TODO(a.garipov): Consider adding validation functions.
+type HandlersConfig struct {
+ // BaseLogger is used to create loggers with custom prefixes for middlewares
+ // and the service itself. It must not be nil.
+ BaseLogger *slog.Logger
+
+ // Cloner is used to clone messages more efficiently by disposing of parts
+ // of DNS responses for later reuse. It must not be nil.
+ Cloner *dnsmsg.Cloner
+
+ // Cache is the configuration for the DNS cache.
+ Cache *CacheConfig
+
+ // HumanIDParser is used to normalize and parse human-readable device
+ // identifiers. It must not be nil if at least one server group has
+ // profiles enabled.
+ HumanIDParser *agd.HumanIDParser
+
+ // Messages is the message constructor used to create blocked and other
+ // messages for this DNS service. It must not be nil.
+ Messages *dnsmsg.Constructor
+
+ // PluginRegistry is used to override configuration parameters.
+ PluginRegistry *plugin.Registry
+
+ // StructuredErrors is the configuration for the experimental Structured DNS
+ // Errors feature in the profiles' message constructors. It must not be
+ // nil.
+ StructuredErrors *dnsmsg.StructuredDNSErrorsConfig
+
+ // AccessManager is used to block requests. It must not be nil.
+ AccessManager access.Interface
+
+ // BillStat is used to collect billing statistics. It must not be nil.
+ BillStat billstat.Recorder
+
+ // CacheManager is the global cache manager. It must not be nil.
+ CacheManager agdcache.Manager
+
+ // DNSCheck is used by clients to check if they use AdGuard DNS. It must
+ // not be nil.
+ DNSCheck dnscheck.Interface
+
+ // DNSDB is used to update anonymous statistics about DNS queries. It must
+ // not be nil.
+ DNSDB dnsdb.Interface
+
+ // ErrColl is the error collector that is used to collect critical and
+ // non-critical errors. It must not be nil.
+ ErrColl errcoll.Interface
+
+ // FilterStorage is the storage of all filters. It must not be nil.
+ FilterStorage filter.Storage
+
+ // GeoIP is the GeoIP database used to detect geographic data about IP
+ // addresses in requests and responses. It must not be nil.
+ GeoIP geoip.Interface
+
+ // Handler is the ultimate handler of the DNS query to be wrapped by
+ // middlewares. It must not be nil.
+ Handler dnsserver.Handler
+
+ // HashMatcher is the safe-browsing hash matcher for TXT queries. It must
+ // not be nil.
+ HashMatcher filter.HashMatcher
+
+ // ProfileDB is the AdGuard DNS profile database used to fetch data about
+ // profiles, devices, and so on. It must not be nil if at least one server
+ // group has profiles enabled.
+ ProfileDB profiledb.Interface
+
+ // PrometheusRegisterer is used to register Prometheus metrics. It must not
+ // be nil.
+ PrometheusRegisterer prometheus.Registerer
+
+ // QueryLog is used to write the logs into. It must not be nil.
+ QueryLog querylog.Interface
+
+ // RateLimit is used for allow or decline requests. It must not be nil.
+ RateLimit ratelimit.Interface
+
+ // RuleStat is used to collect statistics about matched filtering rules and
+ // rule lists. It must not be nil.
+ RuleStat rulestat.Interface
+
+ // MetricsNamespace is a namespace for Prometheus metrics. It must be a
+ // valid Prometheus metric label.
+ MetricsNamespace string
+
+ // FilteringGroups are the DNS filtering groups. Each element must be
+ // non-nil.
+ FilteringGroups map[agd.FilteringGroupID]*agd.FilteringGroup
+
+ // ServerGroups are the DNS server groups for which to build handlers. Each
+ // element and its servers must be non-nil.
+ ServerGroups []*agd.ServerGroup
+
+ // EDEEnabled enables the addition of the Extended DNS Error (EDE) codes in
+ // the profiles' message constructors.
+ EDEEnabled bool
+}
+
+// Handlers contains the map of handlers for each server of each server group.
+// The pointers are the same as those passed in a [HandlersConfig] to
+// [NewHandlers].
+type Handlers map[HandlerKey]dnsserver.Handler
+
+// HandlerKey is a key for the [Handlers] map.
+type HandlerKey struct {
+ Server *agd.Server
+ ServerGroup *agd.ServerGroup
+}
+
+// CacheConfig is the configuration for the DNS cache.
+type CacheConfig struct {
+ // MinTTL is the minimum supported TTL for cache items.
+ MinTTL time.Duration
+
+ // ECSCount is the size of the DNS cache for domain names that support
+ // ECS, in entries. It must be greater than zero if [CacheConfig.CacheType]
+ // is [CacheTypeECS].
+ ECSCount int
+
+ // NoECSCount is the size of the DNS cache for domain names that don't
+ // support ECS, in entries. It must be greater than zero if
+ // [CacheConfig.CacheType] is [CacheTypeSimple] or [CacheTypeECS].
+ NoECSCount int
+
+ // Type is the cache type. It must be valid.
+ Type CacheType
+
+ // OverrideCacheTTL shows if the TTL overriding logic should be used.
+ OverrideCacheTTL bool
+}
+
+// CacheType is the type of the cache to use.
+type CacheType uint8
+
+// CacheType constants.
+const (
+ CacheTypeNone CacheType = iota + 1
+ CacheTypeSimple
+ CacheTypeECS
+)
diff --git a/internal/dnssvc/context.go b/internal/dnssvc/context.go
new file mode 100644
index 0000000..3e054bc
--- /dev/null
+++ b/internal/dnssvc/context.go
@@ -0,0 +1,35 @@
+package dnssvc
+
+import (
+ "context"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
+)
+
+// contextConstructor is a [dnsserver.ContextConstructor] implementation that
+// returns a context with the given timeout as well as a new [agd.RequestID].
+type contextConstructor struct {
+ timeout time.Duration
+}
+
+// newContextConstructor returns a new properly initialized *contextConstructor.
+func newContextConstructor(timeout time.Duration) (c *contextConstructor) {
+ return &contextConstructor{
+ timeout: timeout,
+ }
+}
+
+// type check
+var _ dnsserver.ContextConstructor = (*contextConstructor)(nil)
+
+// New implements the [dnsserver.ContextConstructor] interface for
+// *contextConstructor. It returns a context with a new [agd.RequestID] as well
+// as its timeout and the corresponding cancelation function.
+func (c *contextConstructor) New() (ctx context.Context, cancel context.CancelFunc) {
+ ctx, cancel = context.WithTimeout(context.Background(), c.timeout)
+ ctx = agd.WithRequestID(ctx, agd.NewRequestID())
+
+ return ctx, cancel
+}
diff --git a/internal/dnssvc/dnssvc.go b/internal/dnssvc/dnssvc.go
index b4714fa..5d8e314 100644
--- a/internal/dnssvc/dnssvc.go
+++ b/internal/dnssvc/dnssvc.go
@@ -7,289 +7,27 @@ package dnssvc
import (
"context"
"fmt"
- "log/slog"
"net/http"
- "time"
- "github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
- "github.com/AdguardTeam/AdGuardDNS/internal/billstat"
- "github.com/AdguardTeam/AdGuardDNS/internal/cmd/plugin"
"github.com/AdguardTeam/AdGuardDNS/internal/connlimiter"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/netext"
dnssrvprom "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/prometheus"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicefinder"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/initial"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/mainmw"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/preservice"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/preupstream"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/ratelimitmw"
- "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
- "github.com/AdguardTeam/AdGuardDNS/internal/filter"
- "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
- "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
- "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
- "github.com/AdguardTeam/AdGuardDNS/internal/querylog"
- "github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
"github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/service"
"github.com/miekg/dns"
- "github.com/prometheus/client_golang/prometheus"
)
-// Config is the configuration of the AdGuard DNS service.
-type Config struct {
- // BaseLogger is used to create loggers with custom prefixes for middlewares
- // and the service itself.
- BaseLogger *slog.Logger
-
- // Messages is the message constructor used to create blocked and other
- // messages for this DNS service.
- Messages *dnsmsg.Constructor
-
- // Cloner is used to clone messages more efficiently by disposing of parts
- // of DNS responses for later reuse.
- Cloner *dnsmsg.Cloner
-
- // ControlConf is the configuration of socket options.
- ControlConf *netext.ControlConfig
-
- // ConnLimiter, if not nil, is used to limit the number of simultaneously
- // active stream-connections.
- ConnLimiter *connlimiter.Limiter
-
- // HumanIDParser is used to normalize and parse human-readable device
- // identifiers.
- HumanIDParser *agd.HumanIDParser
-
- // PluginRegistry is used to override configuration parameters.
- PluginRegistry *plugin.Registry
-
- // AccessManager is used to block requests.
- AccessManager access.Interface
-
- // SafeBrowsing is the safe browsing TXT hash matcher.
- SafeBrowsing filter.HashMatcher
-
- // BillStat is used to collect billing statistics.
- BillStat billstat.Recorder
-
- // CacheManager is the global cache manager. CacheManager must not be nil.
- CacheManager agdcache.Manager
-
- // ProfileDB is the AdGuard DNS profile database used to fetch data about
- // profiles, devices, and so on.
- ProfileDB profiledb.Interface
-
- // PrometheusRegisterer is used to register Prometheus metrics.
- PrometheusRegisterer prometheus.Registerer
-
- // DNSCheck is used by clients to check if they use AdGuard DNS.
- DNSCheck dnscheck.Interface
-
- // NonDNS is the handler for non-DNS HTTP requests.
- NonDNS http.Handler
-
- // DNSDB is used to update anonymous statistics about DNS queries.
- DNSDB dnsdb.Interface
-
- // ErrColl is the error collector that is used to collect critical and
- // non-critical errors.
- ErrColl errcoll.Interface
-
- // FilterStorage is the storage of all filters.
- FilterStorage filter.Storage
-
- // GeoIP is the GeoIP database used to detect geographic data about IP
- // addresses in requests and responses.
- GeoIP geoip.Interface
-
- // QueryLog is used to write the logs into.
- QueryLog querylog.Interface
-
- // RuleStat is used to collect statistics about matched filtering rules and
- // rule lists.
- RuleStat rulestat.Interface
-
- // NewListener, when set, is used instead of the package-level function
- // NewListener when creating a DNS listener.
- //
- // TODO(a.garipov): The handler and service logic should really not be
- // intertwined in this way. See AGDNS-1327.
- NewListener NewListenerFunc
-
- // Handler is used as the main DNS handler instead of a simple forwarder.
- // It must not be nil.
- //
- // TODO(a.garipov): Think of a better way to make the DNS server logic more
- // testable.
- Handler dnsserver.Handler
-
- // RateLimit is used for allow or decline requests.
- RateLimit ratelimit.Interface
-
- // MetricsNamespace is a namespace for Prometheus metrics. It must be a
- // valid Prometheus metric label.
- MetricsNamespace string
-
- // FilteringGroups are the DNS filtering groups. Each element must be
- // non-nil.
- FilteringGroups map[agd.FilteringGroupID]*agd.FilteringGroup
-
- // ServerGroups are the DNS server groups. Each element must be non-nil.
- ServerGroups []*agd.ServerGroup
-
- // HandleTimeout defines the timeout for the entire handling of a single
- // query.
- HandleTimeout time.Duration
-
- // CacheSize is the size of the DNS cache for domain names that don't
- // support ECS.
- //
- // TODO(a.garipov): Extract this and following fields to cache configuration
- // struct.
- CacheSize int
-
- // ECSCacheSize is the size of the DNS cache for domain names that support
- // ECS.
- ECSCacheSize int
-
- // CacheMinTTL is the minimum supported TTL for cache items. This setting
- // is used when UseCacheTTLOverride set to true.
- CacheMinTTL time.Duration
-
- // UseCacheTTLOverride shows if the TTL overrides logic should be used.
- UseCacheTTLOverride bool
-
- // UseECSCache shows if the EDNS Client Subnet (ECS) aware cache should be
- // used.
- UseECSCache bool
+// Service is the main DNS service of AdGuard DNS.
+type Service struct {
+ groups []*serverGroup
}
-type (
- // MainMiddlewareMetrics is a re-export of the internal filtering-middleware
- // metrics interface.
- MainMiddlewareMetrics = mainmw.Metrics
-
- // RatelimitMiddlewareMetrics is a re-export of the metrics interface of the
- // internal access and ratelimiting middleware.
- RatelimitMiddlewareMetrics = ratelimitmw.Metrics
-)
-
-// New returns a new DNS service.
-func New(c *Config) (svc *Service, err error) {
- // Use either the configured listener initializer or the default one.
- newListener := c.NewListener
- if newListener == nil {
- newListener = NewListener
- }
-
- // Configure the end of the request handling pipeline.
- handler := c.Handler
- if handler == nil {
- return nil, errors.Error("handler in config must not be nil")
- }
-
- // Configure the pre-upstream middleware common for all servers of all
- // groups.
- preUps := preupstream.New(&preupstream.Config{
- Cloner: c.Cloner,
- CacheManager: c.CacheManager,
- DB: c.DNSDB,
- GeoIP: c.GeoIP,
- CacheSize: c.CacheSize,
- ECSCacheSize: c.ECSCacheSize,
- UseECSCache: c.UseECSCache,
- CacheMinTTL: c.CacheMinTTL,
- UseCacheTTLOverride: c.UseCacheTTLOverride,
- })
- handler = preUps.Wrap(handler)
-
- errCollListener := &errCollMetricsListener{
- errColl: c.ErrColl,
- baseListener: dnssrvprom.NewServerMetricsListener(c.MetricsNamespace),
- }
-
- // Configure the service itself.
- groups := make([]*serverGroup, len(c.ServerGroups))
- svc = &Service{
- groups: groups,
- }
-
- mainMwMtrc, err := newMainMiddlewareMetrics(c)
- if err != nil {
- // Don't wrap the error, because it's informative enough as is.
- return nil, err
- }
-
- rlMwMtrc, err := metrics.NewDefaultRatelimitMiddleware(c.MetricsNamespace, c.PrometheusRegisterer)
- if err != nil {
- // Don't wrap the error, because it's informative enough as is.
- return nil, err
- }
-
- for i, srvGrp := range c.ServerGroups {
- // The Filtering Middlewares
- //
- // These are middlewares common to all filtering and server groups.
- // They change the flow of request handling, so they are separated.
-
- dnsHdlr := dnsserver.WithMiddlewares(
- handler,
- preservice.New(&preservice.Config{
- Messages: c.Messages,
- HashMatcher: c.SafeBrowsing,
- Checker: c.DNSCheck,
- }),
- mainmw.New(&mainmw.Config{
- Metrics: mainMwMtrc,
- Messages: c.Messages,
- Cloner: c.Cloner,
- BillStat: c.BillStat,
- ErrColl: c.ErrColl,
- FilterStorage: c.FilterStorage,
- GeoIP: c.GeoIP,
- QueryLog: c.QueryLog,
- RuleStat: c.RuleStat,
- }),
- )
-
- var servers []*server
- servers, err = newServers(c, srvGrp, dnsHdlr, rlMwMtrc, errCollListener, newListener)
- if err != nil {
- return nil, fmt.Errorf("group %q: %w", srvGrp.Name, err)
- }
-
- groups[i] = &serverGroup{
- name: srvGrp.Name,
- servers: servers,
- }
- }
-
- return svc, nil
-}
-
-// newMainMiddlewareMetrics returns a filtering-middleware metrics
-// implementation from the config.
-func newMainMiddlewareMetrics(c *Config) (mainMwMtrc MainMiddlewareMetrics, err error) {
- mainMwMtrc = c.PluginRegistry.MainMiddlewareMetrics()
- if mainMwMtrc != nil {
- return mainMwMtrc, nil
- }
-
- mainMwMtrc, err = metrics.NewDefaultMainMiddleware(c.MetricsNamespace, c.PrometheusRegisterer)
- if err != nil {
- return nil, fmt.Errorf("mainmw metrics: %w", err)
- }
-
- return mainMwMtrc, nil
+// serverGroup is a group of servers.
+type serverGroup struct {
+ name agd.ServerGroupName
+ servers []*server
}
// server is a group of listeners.
@@ -303,27 +41,171 @@ type server struct {
listeners []*listener
}
-// serverGroup is a group of servers.
-type serverGroup struct {
- name agd.ServerGroupName
- servers []*server
+// listener is a Listener along with some of its associated data.
+type listener struct {
+ Listener
+
+ name string
}
-// Service is the main DNS service of AdGuard DNS.
-type Service struct {
- groups []*serverGroup
-}
-
-// mustStartListener starts l and panics on any error.
-func mustStartListener(
- grp agd.ServerGroupName,
- srv agd.ServerName,
- l *listener,
-) {
- err := l.Start(context.Background())
- if err != nil {
- panic(fmt.Errorf("group %q: server %q: starting %q: %w", grp, srv, l.name, err))
+// New returns a new DNS service.
+func New(c *Config) (svc *Service, err error) {
+ // Use either the configured listener initializer or the default one.
+ newListener := c.NewListener
+ if newListener == nil {
+ newListener = NewListener
}
+
+ errCollListener := &errCollMetricsListener{
+ errColl: c.ErrColl,
+ baseListener: dnssrvprom.NewServerMetricsListener(c.MetricsNamespace),
+ }
+
+ // Configure the service itself.
+ groups := make([]*serverGroup, 0, len(c.ServerGroups))
+
+ for _, srvGrp := range c.ServerGroups {
+ g := &serverGroup{
+ name: srvGrp.Name,
+ }
+
+ g.servers, err = newServers(c, srvGrp, errCollListener, newListener)
+ if err != nil {
+ return nil, fmt.Errorf("group %q: %w", srvGrp.Name, err)
+ }
+
+ groups = append(groups, g)
+ }
+
+ svc = &Service{
+ groups: groups,
+ }
+
+ return svc, nil
+}
+
+// newServers creates a slice of servers.
+func newServers(
+ c *Config,
+ srvGrp *agd.ServerGroup,
+ errCollListener *errCollMetricsListener,
+ newListener NewListenerFunc,
+) (servers []*server, err error) {
+ servers = make([]*server, 0, len(srvGrp.Servers))
+
+ for _, srv := range srvGrp.Servers {
+ k := HandlerKey{
+ Server: srv,
+ ServerGroup: srvGrp,
+ }
+ handler, ok := c.Handlers[k]
+ if !ok {
+ return nil, fmt.Errorf("no handler for server %q of group %q", srv.Name, srvGrp.Name)
+ }
+
+ s := &server{
+ name: srv.Name,
+ handler: handler,
+ }
+
+ s.listeners, err = newListeners(c, srv, handler, errCollListener, newListener)
+ if err != nil {
+ return nil, fmt.Errorf("server %q: %w", s.name, err)
+ }
+
+ servers = append(servers, s)
+ }
+
+ return servers, nil
+}
+
+// newListeners creates a slice of listeners for a server.
+func newListeners(
+ c *Config,
+ srv *agd.Server,
+ handler dnsserver.Handler,
+ errCollListener *errCollMetricsListener,
+ newListener NewListenerFunc,
+) (listeners []*listener, err error) {
+ bindData := srv.BindData()
+ listeners = make([]*listener, 0, len(bindData))
+ for i, bindData := range bindData {
+ var addr string
+ if bindData.PrefixAddr == nil {
+ addr = bindData.AddrPort.String()
+ } else {
+ addr = bindData.PrefixAddr.String()
+ }
+
+ proto := srv.Protocol
+
+ name := listenerName(srv.Name, addr, proto)
+ baseConf := dnsserver.ConfigBase{
+ Network: dnsserver.NetworkAny,
+ Handler: handler,
+ Metrics: errCollListener,
+ Disposer: c.Cloner,
+ RequestContext: newContextConstructor(c.HandleTimeout),
+ ListenConfig: newListenConfig(
+ bindData.ListenConfig,
+ c.ControlConf,
+ c.ConnLimiter,
+ proto,
+ ),
+ Name: name,
+ Addr: addr,
+ }
+
+ l := &listener{
+ name: name,
+ }
+
+ l.Listener, err = newListener(srv, baseConf, c.NonDNS)
+ if err != nil {
+ return nil, fmt.Errorf("bind data at index %d: %w", i, err)
+ }
+
+ listeners = append(listeners, l)
+ }
+
+ return listeners, nil
+}
+
+// listenerName returns a standard name for a listener.
+func listenerName(srvName agd.ServerName, addr string, proto agd.Protocol) (name string) {
+ return fmt.Sprintf("%s/%s/%s", srvName, proto, addr)
+}
+
+// newListenConfig returns the netext.ListenConfig used by the plain-DNS
+// servers. The resulting ListenConfig sets additional socket flags and
+// processes the control messages of connections created with ListenPacket.
+// Additionally, if l is not nil, it is used to limit the number of
+// simultaneously active stream-connections.
+func newListenConfig(
+ original netext.ListenConfig,
+ ctrlConf *netext.ControlConfig,
+ l *connlimiter.Limiter,
+ p agd.Protocol,
+) (lc netext.ListenConfig) {
+ if original != nil {
+ if l == nil {
+ return original
+ }
+
+ return connlimiter.NewListenConfig(original, l)
+ }
+
+ if p == agd.ProtoDNS {
+ lc = netext.DefaultListenConfigWithOOB(ctrlConf)
+ } else {
+ lc = netext.DefaultListenConfig(ctrlConf)
+ }
+
+ if l != nil {
+ lc = connlimiter.NewListenConfig(lc, l)
+ }
+
+ return lc
}
// type check
@@ -331,13 +213,13 @@ var _ service.Interface = (*Service)(nil)
// Start implements the [service.Interface] interface for *Service. It panics
// if one of the listeners could not start.
-func (svc *Service) Start(_ context.Context) (err error) {
+func (svc *Service) Start(ctx context.Context) (err error) {
for _, g := range svc.groups {
for _, s := range g.servers {
for _, l := range s.listeners {
// Consider inability to start any one DNS listener a fatal
// error.
- mustStartListener(g.name, s.name, l)
+ mustStartListener(ctx, g.name, s.name, l)
}
}
}
@@ -345,17 +227,17 @@ func (svc *Service) Start(_ context.Context) (err error) {
return nil
}
-// shutdownListeners is a helper function that shuts down all listeners of a
-// server.
-func shutdownListeners(ctx context.Context, listeners []*listener) (err error) {
- for _, l := range listeners {
- err = l.Shutdown(ctx)
- if err != nil {
- return fmt.Errorf("shutting down listener %q: %w", l.name, err)
- }
+// mustStartListener starts l and panics on any error.
+func mustStartListener(
+ ctx context.Context,
+ srvGrp agd.ServerGroupName,
+ srv agd.ServerName,
+ l *listener,
+) {
+ err := l.Start(ctx)
+ if err != nil {
+ panic(fmt.Errorf("group %q: server %q: starting %q: %w", srvGrp, srv, l.name, err))
}
-
- return nil
}
// Shutdown implements the [service.Interface] interface for *Service.
@@ -378,9 +260,22 @@ func (svc *Service) Shutdown(ctx context.Context) (err error) {
return nil
}
+// shutdownListeners is a helper function that shuts down all listeners of a
+// server.
+func shutdownListeners(ctx context.Context, listeners []*listener) (err error) {
+ for _, l := range listeners {
+ err = l.Shutdown(ctx)
+ if err != nil {
+ return fmt.Errorf("shutting down listener %q: %w", l.name, err)
+ }
+ }
+
+ return nil
+}
+
// Handle is a simple helper to test the handling of DNS requests.
//
-// TODO(a.garipov): Remove once the mainmw refactoring is complete.
+// TODO(a.garipov): Remove once the refactoring is complete.
func (svc *Service) Handle(
ctx context.Context,
grpName agd.ServerGroupName,
@@ -417,33 +312,10 @@ func (svc *Service) Handle(
return srv.handler.ServeDNS(ctx, rw, r)
}
-// Listener is a type alias for dnsserver.Server to make internal naming more
-// consistent.
-type Listener = dnsserver.Server
-
-// NewListenerFunc is the type for DNS listener constructors.
-type NewListenerFunc func(
- s *agd.Server,
- baseConf dnsserver.ConfigBase,
- nonDNS http.Handler,
-) (l Listener, err error)
-
-// listener is a Listener along with some of its associated data.
-type listener struct {
- Listener
-
- name string
-}
-
-// listenerName returns a standard name for a listener.
-func listenerName(srvName agd.ServerName, addr string, proto agd.Protocol) (name string) {
- return fmt.Sprintf("%s/%s/%s", srvName, proto, addr)
-}
-
// NewListener returns a new Listener. It is the default DNS listener
// constructor.
//
-// TODO(a.garipov): Replace this in tests with [netext.ListenConfig].
+// TODO(a.garipov): Replace this in tests with [netext.ListenConfig].
func NewListener(
s *agd.Server,
baseConf dnsserver.ConfigBase,
@@ -500,213 +372,8 @@ func NewListener(
TLSConfig: s.TLS,
})
default:
- return nil, fmt.Errorf("bad protocol %v", p)
+ return nil, fmt.Errorf("protocol: %w: %d", errors.ErrBadEnumValue, p)
}
return l, nil
}
-
-// contextConstructor is a [dnsserver.ContextConstructor] implementation that
-// that returns a context with the given timeout as well as a new
-// [agd.RequestID].
-type contextConstructor struct {
- timeout time.Duration
-}
-
-// newContextConstructor returns a new properly initialized *contextConstructor.
-func newContextConstructor(timeout time.Duration) (c *contextConstructor) {
- return &contextConstructor{
- timeout: timeout,
- }
-}
-
-// type check
-var _ dnsserver.ContextConstructor = (*contextConstructor)(nil)
-
-// New implements the [dnsserver.ContextConstructor] interface for
-// *contextConstructor. It returns a context with a new [agd.RequestID] as well
-// as its timeout and the corresponding cancelation function.
-func (c *contextConstructor) New() (ctx context.Context, cancel context.CancelFunc) {
- ctx, cancel = context.WithTimeout(context.Background(), c.timeout)
- ctx = agd.WithRequestID(ctx, agd.NewRequestID())
-
- return ctx, cancel
-}
-
-// newServers creates a slice of servers.
-//
-// TODO(a.garipov): Refactor this into a builder pattern.
-func newServers(
- c *Config,
- srvGrp *agd.ServerGroup,
- handler dnsserver.Handler,
- rlMwMtrc ratelimitmw.Metrics,
- errCollListener *errCollMetricsListener,
- newListener NewListenerFunc,
-) (servers []*server, err error) {
- servers = make([]*server, len(srvGrp.Servers))
-
- for i, s := range srvGrp.Servers {
- // The Initial Middlewares
- //
- // These middlewares are either specific to the server or must be the
- // furthest away from the handler and thus are the first to process
- // a request.
-
- // Assume that all the validations have been made during the
- // configuration validation step back in package cmd. If we ever get
- // new ways of receiving configuration, remove this assumption and
- // validate fg.
- fg := c.FilteringGroups[srvGrp.FilteringGroup]
-
- df := newDeviceFinder(c, srvGrp, s)
- rlm := ratelimitmw.New(&ratelimitmw.Config{
- Logger: c.BaseLogger.With(slogutil.KeyPrefix, "ratelimitmw"),
- Messages: c.Messages,
- FilteringGroup: fg,
- ServerGroup: srvGrp,
- Server: s,
- AccessManager: c.AccessManager,
- DeviceFinder: df,
- ErrColl: c.ErrColl,
- GeoIP: c.GeoIP,
- Metrics: rlMwMtrc,
- Limiter: c.RateLimit,
- // Only apply rate-limiting logic to plain DNS.
- Protocols: []agd.Protocol{agd.ProtoDNS},
- })
- if err != nil {
- return nil, fmt.Errorf("ratelimit: %w", err)
- }
-
- imw := initial.New(&initial.Config{
- Logger: c.BaseLogger.With(slogutil.KeyPrefix, "initmw"),
- })
-
- h := dnsserver.WithMiddlewares(
- handler,
-
- // Keep the rate limiting and access middlewares as the outer ones
- // to make sure that the application logic isn't touched if the
- // request is ratelimited or blocked by access settings.
- rlm,
- imw,
- )
-
- srvName := s.Name
-
- var listeners []*listener
- listeners, err = newListeners(c, s, h, errCollListener, newListener)
- if err != nil {
- return nil, fmt.Errorf("server %q: %w", srvName, err)
- }
-
- servers[i] = &server{
- name: srvName,
- handler: h,
- listeners: listeners,
- }
- }
-
- return servers, nil
-}
-
-// newDeviceFinder returns a new [agd.DeviceFinder] for a server based on the
-// configuration.
-func newDeviceFinder(c *Config, g *agd.ServerGroup, s *agd.Server) (df agd.DeviceFinder) {
- if !g.ProfilesEnabled {
- return agd.EmptyDeviceFinder{}
- }
-
- return devicefinder.NewDefault(&devicefinder.Config{
- Logger: c.BaseLogger.With(slogutil.KeyPrefix, "devicefinder"),
- ProfileDB: c.ProfileDB,
- HumanIDParser: c.HumanIDParser,
- Server: s,
- DeviceDomains: g.TLS.DeviceDomains,
- })
-}
-
-// newServers creates a slice of listeners for a server.
-func newListeners(
- c *Config,
- srv *agd.Server,
- handler dnsserver.Handler,
- errCollListener *errCollMetricsListener,
- newListener NewListenerFunc,
-) (listeners []*listener, err error) {
- bindData := srv.BindData()
- listeners = make([]*listener, 0, len(bindData))
- for i, bindData := range bindData {
- var addr string
- if bindData.PrefixAddr == nil {
- addr = bindData.AddrPort.String()
- } else {
- addr = bindData.PrefixAddr.String()
- }
-
- proto := srv.Protocol
-
- name := listenerName(srv.Name, addr, proto)
- baseConf := dnsserver.ConfigBase{
- Network: dnsserver.NetworkAny,
- Handler: handler,
- Metrics: errCollListener,
- Disposer: c.Cloner,
- RequestContext: newContextConstructor(c.HandleTimeout),
- ListenConfig: newListenConfig(
- bindData.ListenConfig,
- c.ControlConf,
- c.ConnLimiter,
- proto,
- ),
- Name: name,
- Addr: addr,
- }
-
- var l Listener
- l, err = newListener(srv, baseConf, c.NonDNS)
- if err != nil {
- return nil, fmt.Errorf("bind data at index %d: %w", i, err)
- }
-
- listeners = append(listeners, &listener{
- name: name,
- Listener: l,
- })
- }
-
- return listeners, nil
-}
-
-// newListenConfig returns the netext.ListenConfig used by the plain-DNS
-// servers. The resulting ListenConfig sets additional socket flags and
-// processes the control messages of connections created with ListenPacket.
-// Additionally, if l is not nil, it is used to limit the number of
-// simultaneously active stream-connections.
-func newListenConfig(
- original netext.ListenConfig,
- ctrlConf *netext.ControlConfig,
- l *connlimiter.Limiter,
- p agd.Protocol,
-) (lc netext.ListenConfig) {
- if original != nil {
- if l == nil {
- return original
- }
-
- return connlimiter.NewListenConfig(original, l)
- }
-
- if p == agd.ProtoDNS {
- lc = netext.DefaultListenConfigWithOOB(ctrlConf)
- } else {
- lc = netext.DefaultListenConfig(ctrlConf)
- }
-
- if l != nil {
- lc = connlimiter.NewListenConfig(lc, l)
- }
-
- return lc
-}
diff --git a/internal/dnssvc/dnssvc_test.go b/internal/dnssvc/dnssvc_test.go
index c0bfde6..6c91802 100644
--- a/internal/dnssvc/dnssvc_test.go
+++ b/internal/dnssvc/dnssvc_test.go
@@ -10,26 +10,17 @@ 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"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
- "github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-func TestMain(m *testing.M) {
- testutil.DiscardLogOutput(m)
-}
-
-// testSrvGrpName is the [agd.ServerGroupName] for tests.
-const testSrvGrpName agd.ServerGroupName = "test_group"
-
// type check
var _ agdservice.Refresher = (*forward.Handler)(nil)
@@ -159,16 +150,23 @@ func TestService_Start(t *testing.T) {
AddrPort: netip.MustParseAddrPort("127.0.0.1:53"),
})
+ srvGrp := &agd.ServerGroup{
+ Name: dnssvctest.ServerGroupName,
+ Servers: []*agd.Server{srv},
+ }
+
+ k := dnssvc.HandlerKey{
+ Server: srv,
+ ServerGroup: srvGrp,
+ }
+
c := &dnssvc.Config{
- BaseLogger: slogutil.NewDiscardLogger(),
- NewListener: newTestListenerFunc(tl),
- PrometheusRegisterer: agdtest.NewTestPrometheusRegisterer(),
- Handler: dnsservertest.DefaultHandler(),
- MetricsNamespace: "test_start",
- ServerGroups: []*agd.ServerGroup{{
- Name: "test_group",
- Servers: []*agd.Server{srv},
- }},
+ NewListener: newTestListenerFunc(tl),
+ Handlers: dnssvc.Handlers{
+ k: dnsservertest.NewDefaultHandler(),
+ },
+ MetricsNamespace: "test_start",
+ ServerGroups: []*agd.ServerGroup{srvGrp},
}
svc, err := dnssvc.New(c)
@@ -206,15 +204,25 @@ func TestNew(t *testing.T) {
}),
}
+ srvGrp := &agd.ServerGroup{
+ Name: dnssvctest.ServerGroupName,
+ Servers: srvs,
+ }
+
+ handlers := dnssvc.Handlers{}
+ for _, srv := range srvs {
+ k := dnssvc.HandlerKey{
+ Server: srv,
+ ServerGroup: srvGrp,
+ }
+
+ handlers[k] = dnsservertest.NewDefaultHandler()
+ }
+
c := &dnssvc.Config{
- BaseLogger: slogutil.NewDiscardLogger(),
- Handler: dnsservertest.DefaultHandler(),
- PrometheusRegisterer: agdtest.NewTestPrometheusRegisterer(),
- MetricsNamespace: "test_new",
- ServerGroups: []*agd.ServerGroup{{
- Name: "test_group",
- Servers: srvs,
- }},
+ Handlers: handlers,
+ MetricsNamespace: "test_new",
+ ServerGroups: []*agd.ServerGroup{srvGrp},
}
svc, err := dnssvc.New(c)
diff --git a/internal/dnssvc/handler.go b/internal/dnssvc/handler.go
new file mode 100644
index 0000000..49f5f2c
--- /dev/null
+++ b/internal/dnssvc/handler.go
@@ -0,0 +1,211 @@
+package dnssvc
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/cache"
+ dnssrvprom "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/prometheus"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicefinder"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/initial"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/mainmw"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/preservice"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/preupstream"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/ratelimitmw"
+ "github.com/AdguardTeam/AdGuardDNS/internal/ecscache"
+ "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+)
+
+// NewHandlers returns the main DNS handlers wrapped in all necessary
+// middlewares. c must not be nil.
+func NewHandlers(ctx context.Context, c *HandlersConfig) (handlers Handlers, err error) {
+ handler := wrapPreUpstreamMw(ctx, c)
+
+ mainMwMtrc, err := newMainMiddlewareMetrics(c)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return nil, err
+ }
+
+ mainMw := mainmw.New(&mainmw.Config{
+ Cloner: c.Cloner,
+ Logger: c.BaseLogger.With(slogutil.KeyPrefix, "mainmw"),
+ Messages: c.Messages,
+ BillStat: c.BillStat,
+ ErrColl: c.ErrColl,
+ FilterStorage: c.FilterStorage,
+ GeoIP: c.GeoIP,
+ QueryLog: c.QueryLog,
+ Metrics: mainMwMtrc,
+ RuleStat: c.RuleStat,
+ })
+
+ handler = mainMw.Wrap(handler)
+
+ preSvcMw := preservice.New(&preservice.Config{
+ Logger: c.BaseLogger.With(slogutil.KeyPrefix, "presvcmw"),
+ Messages: c.Messages,
+ HashMatcher: c.HashMatcher,
+ Checker: c.DNSCheck,
+ })
+
+ handler = preSvcMw.Wrap(handler)
+
+ postInitMw := c.PluginRegistry.PostInitialMiddleware()
+ if postInitMw != nil {
+ handler = postInitMw.Wrap(handler)
+ }
+
+ initMw := initial.New(&initial.Config{
+ Logger: c.BaseLogger.With(slogutil.KeyPrefix, "initmw"),
+ })
+
+ handler = initMw.Wrap(handler)
+
+ return newHandlersForServers(c, handler)
+}
+
+// wrapPreUpstreamMw returns the handler wrapped into the pre-upstream
+// middlewares.
+//
+// TODO(a.garipov): Adapt the cache tests that previously were in package
+// preupstream.
+func wrapPreUpstreamMw(ctx context.Context, c *HandlersConfig) (wrapped dnsserver.Handler) {
+ // TODO(a.garipov): Use in other places if necessary.
+ l := c.BaseLogger.With(slogutil.KeyPrefix, "dnssvc")
+
+ wrapped = c.Handler
+ switch conf := c.Cache; conf.Type {
+ case CacheTypeNone:
+ l.WarnContext(ctx, "cache disabled")
+ case CacheTypeSimple:
+ l.InfoContext(ctx, "plain cache enabled", "count", conf.NoECSCount)
+
+ cacheMw := cache.NewMiddleware(&cache.MiddlewareConfig{
+ // TODO(a.garipov): Do not use promauto and refactor.
+ MetricsListener: dnssrvprom.NewCacheMetricsListener(metrics.Namespace()),
+ Size: conf.NoECSCount,
+ MinTTL: conf.MinTTL,
+ OverrideTTL: conf.OverrideCacheTTL,
+ })
+
+ wrapped = cacheMw.Wrap(wrapped)
+ case CacheTypeECS:
+ l.InfoContext(
+ ctx,
+ "ecs cache enabled",
+ "ecs_count", conf.ECSCount,
+ "no_ecs_count", conf.NoECSCount,
+ )
+
+ cacheMw := ecscache.NewMiddleware(&ecscache.MiddlewareConfig{
+ Cloner: c.Cloner,
+ Logger: c.BaseLogger.With(slogutil.KeyPrefix, "ecscache"),
+ CacheManager: c.CacheManager,
+ GeoIP: c.GeoIP,
+ NoECSCount: conf.NoECSCount,
+ ECSCount: conf.ECSCount,
+ MinTTL: conf.MinTTL,
+ OverrideTTL: conf.OverrideCacheTTL,
+ })
+
+ wrapped = cacheMw.Wrap(wrapped)
+ default:
+ panic(fmt.Errorf("cache type: %w: %d", errors.ErrBadEnumValue, conf.Type))
+ }
+
+ preUps := preupstream.New(ctx, &preupstream.Config{
+ DB: c.DNSDB,
+ })
+
+ wrapped = preUps.Wrap(wrapped)
+
+ return wrapped
+}
+
+// newMainMiddlewareMetrics returns a filtering-middleware metrics
+// implementation from the config.
+func newMainMiddlewareMetrics(c *HandlersConfig) (mainMwMtrc MainMiddlewareMetrics, err error) {
+ mainMwMtrc = c.PluginRegistry.MainMiddlewareMetrics()
+ if mainMwMtrc != nil {
+ return mainMwMtrc, nil
+ }
+
+ mainMwMtrc, err = metrics.NewDefaultMainMiddleware(c.MetricsNamespace, c.PrometheusRegisterer)
+ if err != nil {
+ return nil, fmt.Errorf("mainmw metrics: %w", err)
+ }
+
+ return mainMwMtrc, nil
+}
+
+// newHandlersForServers returns a handler map for each server group and each
+// server.
+func newHandlersForServers(c *HandlersConfig, h dnsserver.Handler) (handlers Handlers, err error) {
+ rlMwMtrc, err := metrics.NewDefaultRatelimitMiddleware(c.MetricsNamespace, c.PrometheusRegisterer)
+ if err != nil {
+ return nil, fmt.Errorf("ratelimit middleware metrics: %w", err)
+ }
+
+ handlers = Handlers{}
+
+ rlMwLogger := c.BaseLogger.With(slogutil.KeyPrefix, "ratelimitmw")
+ for _, srvGrp := range c.ServerGroups {
+ fltGrp, ok := c.FilteringGroups[srvGrp.FilteringGroup]
+ if !ok {
+ return nil, fmt.Errorf(
+ "no filtering group %q for server group %q",
+ srvGrp.FilteringGroup,
+ srvGrp.Name,
+ )
+ }
+
+ for _, srv := range srvGrp.Servers {
+ rlMw := ratelimitmw.New(&ratelimitmw.Config{
+ Logger: rlMwLogger,
+ Messages: c.Messages,
+ FilteringGroup: fltGrp,
+ ServerGroup: srvGrp,
+ Server: srv,
+ StructuredErrors: c.StructuredErrors,
+ AccessManager: c.AccessManager,
+ DeviceFinder: newDeviceFinder(c, srvGrp, srv),
+ ErrColl: c.ErrColl,
+ GeoIP: c.GeoIP,
+ Metrics: rlMwMtrc,
+ Limiter: c.RateLimit,
+ Protocols: []agd.Protocol{agd.ProtoDNS},
+ EDEEnabled: c.EDEEnabled,
+ })
+
+ k := HandlerKey{
+ Server: srv,
+ ServerGroup: srvGrp,
+ }
+
+ handlers[k] = rlMw.Wrap(h)
+ }
+ }
+
+ return handlers, nil
+}
+
+// newDeviceFinder returns a new agd.DeviceFinder for a server based on the
+// configuration. All arguments must not be nil.
+func newDeviceFinder(c *HandlersConfig, g *agd.ServerGroup, s *agd.Server) (df agd.DeviceFinder) {
+ if !g.ProfilesEnabled {
+ return agd.EmptyDeviceFinder{}
+ }
+
+ return devicefinder.NewDefault(&devicefinder.Config{
+ Logger: c.BaseLogger.With(slogutil.KeyPrefix, "devicefinder"),
+ ProfileDB: c.ProfileDB,
+ HumanIDParser: c.HumanIDParser,
+ Server: s,
+ DeviceDomains: g.TLS.DeviceDomains,
+ })
+}
diff --git a/internal/dnssvc/handler_test.go b/internal/dnssvc/handler_test.go
new file mode 100644
index 0000000..39a7474
--- /dev/null
+++ b/internal/dnssvc/handler_test.go
@@ -0,0 +1,188 @@
+package dnssvc_test
+
+import (
+ "context"
+ "net/netip"
+ "path"
+ "testing"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter"
+ "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/AdGuardDNS/internal/querylog"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/miekg/dns"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestNewHandlers(t *testing.T) {
+ t.Parallel()
+
+ accessMgr := &agdtest.AccessManager{
+ OnIsBlockedHost: func(host string, qt uint16) (blocked bool) { panic("not implemented") },
+ OnIsBlockedIP: func(ip netip.Addr) (blocked bool) { panic("not implemented") },
+ }
+
+ billStat := &agdtest.BillStatRecorder{
+ OnRecord: func(
+ _ context.Context,
+ _ agd.DeviceID,
+ _ geoip.Country,
+ _ geoip.ASN,
+ _ time.Time,
+ _ agd.Protocol,
+ ) {
+ panic("not implemented")
+ },
+ }
+
+ dnsCk := &agdtest.DNSCheck{
+ OnCheck: func(
+ _ context.Context,
+ _ *dns.Msg,
+ _ *agd.RequestInfo,
+ ) (resp *dns.Msg, err error) {
+ panic("not implemented")
+ },
+ }
+
+ dnsDB := &agdtest.DNSDB{
+ OnRecord: func(_ context.Context, _ *dns.Msg, _ *agd.RequestInfo) {
+ panic("not implemented")
+ },
+ }
+
+ fltGrps := map[agd.FilteringGroupID]*agd.FilteringGroup{
+ dnssvctest.FilteringGroupID: {
+ ID: dnssvctest.FilteringGroupID,
+ RuleListIDs: []agd.FilterListID{dnssvctest.FilterListID1},
+ RuleListsEnabled: true,
+ },
+ }
+
+ fltStrg := &agdtest.FilterStorage{
+ OnFilterFromContext: func(_ context.Context, _ *agd.RequestInfo) (f filter.Interface) {
+ panic("not implemented")
+ },
+ OnHasListID: func(_ agd.FilterListID) (ok bool) { panic("not implemented") },
+ }
+
+ hashMatcher := &agdtest.HashMatcher{
+ OnMatchByPrefix: func(
+ _ context.Context,
+ _ string,
+ ) (hashes []string, matched bool, err error) {
+ panic("not implemented")
+ },
+ }
+
+ queryLog := &agdtest.QueryLog{
+ OnWrite: func(_ context.Context, _ *querylog.Entry) (err error) {
+ panic("not implemented")
+ },
+ }
+
+ ruleStat := &agdtest.RuleStat{
+ OnCollect: func(_ context.Context, _ agd.FilterListID, _ agd.FilterRuleText) {
+ panic("not implemented")
+ },
+ }
+
+ srv := dnssvctest.NewServer(dnssvctest.ServerName, agd.ProtoDoT, &agd.ServerBindData{
+ AddrPort: dnssvctest.ServerAddrPort,
+ })
+
+ srvGrp := &agd.ServerGroup{
+ DDR: &agd.DDR{
+ Enabled: true,
+ },
+ TLS: &agd.TLS{},
+ Name: dnssvctest.ServerGroupName,
+ FilteringGroup: dnssvctest.FilteringGroupID,
+ Servers: []*agd.Server{srv},
+ ProfilesEnabled: true,
+ }
+
+ testCases := []struct {
+ cacheConf *dnssvc.CacheConfig
+ name string
+ }{{
+ cacheConf: &dnssvc.CacheConfig{
+ Type: dnssvc.CacheTypeNone,
+ },
+ name: "no_cache",
+ }, {
+ cacheConf: &dnssvc.CacheConfig{
+ MinTTL: 10 * time.Second,
+ NoECSCount: 100,
+ Type: dnssvc.CacheTypeSimple,
+ OverrideCacheTTL: true,
+ },
+ name: "cache_simple",
+ }, {
+ cacheConf: &dnssvc.CacheConfig{
+ MinTTL: 10 * time.Second,
+ ECSCount: 100,
+ NoECSCount: 100,
+ Type: dnssvc.CacheTypeECS,
+ OverrideCacheTTL: true,
+ },
+ name: "cache_ecs",
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ ctx := testutil.ContextWithTimeout(t, dnssvctest.Timeout)
+ handlers, err := dnssvc.NewHandlers(ctx, &dnssvc.HandlersConfig{
+ BaseLogger: slogutil.NewDiscardLogger(),
+ Cloner: agdtest.NewCloner(),
+ Cache: tc.cacheConf,
+ HumanIDParser: agd.NewHumanIDParser(),
+ Messages: agdtest.NewConstructor(t),
+ PluginRegistry: nil,
+ StructuredErrors: agdtest.NewSDEConfig(true),
+ AccessManager: accessMgr,
+ BillStat: billStat,
+ // TODO(a.garipov): Create a test implementation?
+ CacheManager: agdcache.EmptyManager{},
+ DNSCheck: dnsCk,
+ DNSDB: dnsDB,
+ ErrColl: agdtest.NewErrorCollector(),
+ FilterStorage: fltStrg,
+ GeoIP: agdtest.NewGeoIP(),
+ Handler: dnsservertest.NewPanicHandler(),
+ HashMatcher: hashMatcher,
+ ProfileDB: agdtest.NewProfileDB(),
+ PrometheusRegisterer: agdtest.NewTestPrometheusRegisterer(),
+ QueryLog: queryLog,
+ RateLimit: agdtest.NewRateLimit(),
+ RuleStat: ruleStat,
+ MetricsNamespace: path.Base(t.Name()),
+ FilteringGroups: fltGrps,
+ ServerGroups: []*agd.ServerGroup{srvGrp},
+ EDEEnabled: true,
+ })
+ require.NoError(t, err)
+
+ assert.Len(t, handlers, 1)
+
+ for k, v := range handlers {
+ assert.Same(t, srv, k.Server)
+ assert.Same(t, srvGrp, k.ServerGroup)
+ assert.NotNil(t, v)
+
+ break
+ }
+ })
+ }
+}
diff --git a/internal/dnssvc/integration_test.go b/internal/dnssvc/integration_test.go
index 82a1623..dc63f64 100644
--- a/internal/dnssvc/integration_test.go
+++ b/internal/dnssvc/integration_test.go
@@ -11,6 +11,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
@@ -19,6 +20,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
"github.com/AdguardTeam/golibs/logutil/slogutil"
@@ -46,7 +48,7 @@ import (
// from the service. The channels must not be nil. Each sending to a channel
// wrapped with [testutil.RequireSend] using [dnssvctest.Timeout].
//
-// It also uses the [dnsservertest.DefaultHandler] to create the DNS handler.
+// It also uses the [dnsservertest.NewDefaultHandler] to create the DNS handler.
func newTestService(
t testing.TB,
flt filter.Interface,
@@ -81,46 +83,14 @@ func newTestService(
QueryLogEnabled: true,
}
- db := &agdtest.ProfileDB{
- OnCreateAutoDevice: func(
- ctx context.Context,
- id agd.ProfileID,
- humanID agd.HumanID,
- devType agd.DeviceType,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
+ profDB := agdtest.NewProfileDB()
+ profDB.OnProfileByDeviceID = func(
+ _ context.Context,
+ id agd.DeviceID,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ testutil.RequireSend(pt, profileDBCh, id, dnssvctest.Timeout)
- OnProfileByDedicatedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
-
- OnProfileByDeviceID: func(
- _ context.Context,
- id agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- testutil.RequireSend(pt, profileDBCh, id, dnssvctest.Timeout)
-
- return prof, dev, nil
- },
-
- OnProfileByHumanID: func(
- _ context.Context,
- _ agd.ProfileID,
- _ agd.HumanIDLower,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
-
- OnProfileByLinkedIP: func(
- ctx context.Context,
- ip netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
+ return prof, dev, nil
}
accessManager := &agdtest.AccessManager{
@@ -145,18 +115,12 @@ func newTestService(
Continent: geoip.ContinentEU,
ASN: 42,
}
- geoIP := &agdtest.GeoIP{
- OnSubnetByLocation: func(
- _ *geoip.Location,
- _ netutil.AddrFamily,
- ) (n netip.Prefix, err error) {
- panic("not implemented")
- },
- OnData: func(host string, _ netip.Addr) (l *geoip.Location, err error) {
- testutil.RequireSend(pt, geoIPCh, host, dnssvctest.Timeout)
- return loc, nil
- },
+ geoIP := agdtest.NewGeoIP()
+ geoIP.OnData = func(host string, _ netip.Addr) (l *geoip.Location, err error) {
+ testutil.RequireSend(pt, geoIPCh, host, dnssvctest.Timeout)
+
+ return loc, nil
}
fltStrg := &agdtest.FilterStorage{
@@ -205,25 +169,38 @@ func newTestService(
},
}
- rl := &agdtest.RateLimit{
- OnIsRateLimited: func(
- _ context.Context,
- _ *dns.Msg,
- _ netip.Addr,
- ) (drop, allowlisted bool, err error) {
- return true, false, nil
- },
- OnCountResponses: func(_ context.Context, _ *dns.Msg, _ netip.Addr) {
- panic("not implemented")
- },
+ rl := agdtest.NewRateLimit()
+ rl.OnIsRateLimited = func(
+ _ context.Context,
+ _ *dns.Msg,
+ _ netip.Addr,
+ ) (shouldDrop, isAllowlisted bool, err error) {
+ return true, false, nil
}
- testFltGrpID := agd.FilteringGroupID("1234")
+ srvGrps := []*agd.ServerGroup{{
+ DDR: &agd.DDR{
+ Enabled: true,
+ },
+ TLS: &agd.TLS{
+ DeviceDomains: []string{dnssvctest.DomainForDevices},
+ },
+ Name: dnssvctest.ServerGroupName,
+ FilteringGroup: dnssvctest.FilteringGroupID,
+ Servers: []*agd.Server{srv},
+ ProfilesEnabled: true,
+ }}
- c := &dnssvc.Config{
- BaseLogger: slogutil.NewDiscardLogger(),
- AccessManager: accessManager,
- Messages: agdtest.NewConstructor(t),
+ hdlrConf := &dnssvc.HandlersConfig{
+ BaseLogger: slogutil.NewDiscardLogger(),
+ Cache: &dnssvc.CacheConfig{
+ Type: dnssvc.CacheTypeNone,
+ },
+ StructuredErrors: agdtest.NewSDEConfig(true),
+ Cloner: agdtest.NewCloner(),
+ HumanIDParser: agd.NewHumanIDParser(),
+ Messages: agdtest.NewConstructor(t),
+ AccessManager: accessManager,
BillStat: &agdtest.BillStatRecorder{
OnRecord: func(
_ context.Context,
@@ -235,42 +212,47 @@ func newTestService(
) {
},
},
- ProfileDB: db,
- PrometheusRegisterer: agdtest.NewTestPrometheusRegisterer(),
+ CacheManager: agdcache.EmptyManager{},
DNSCheck: dnsCk,
- NonDNS: http.NotFoundHandler(),
DNSDB: dnsDB,
ErrColl: errColl,
FilterStorage: fltStrg,
GeoIP: geoIP,
+ Handler: dnsservertest.NewDefaultHandler(),
+ HashMatcher: hashprefix.NewMatcher(nil),
+ ProfileDB: profDB,
+ PrometheusRegisterer: agdtest.NewTestPrometheusRegisterer(),
QueryLog: ql,
- RuleStat: ruleStat,
- NewListener: newTestListenerFunc(tl),
- Handler: dnsservertest.DefaultHandler(),
RateLimit: rl,
+ RuleStat: ruleStat,
MetricsNamespace: path.Base(t.Name()),
FilteringGroups: map[agd.FilteringGroupID]*agd.FilteringGroup{
- testFltGrpID: {
- ID: testFltGrpID,
+ dnssvctest.FilteringGroupID: {
+ ID: dnssvctest.FilteringGroupID,
RuleListIDs: []agd.FilterListID{dnssvctest.FilterListID1},
RuleListsEnabled: true,
},
},
- ServerGroups: []*agd.ServerGroup{{
- DDR: &agd.DDR{
- Enabled: true,
- },
- TLS: &agd.TLS{
- DeviceDomains: []string{dnssvctest.DomainForDevices},
- },
- Name: testSrvGrpName,
- FilteringGroup: testFltGrpID,
- Servers: []*agd.Server{srv},
- ProfilesEnabled: true,
- }},
+ ServerGroups: srvGrps,
+ EDEEnabled: true,
}
- svc, err := dnssvc.New(c)
+ ctx := context.Background()
+ handlers, err := dnssvc.NewHandlers(ctx, hdlrConf)
+ require.NoError(t, err)
+
+ c := &dnssvc.Config{
+ Handlers: handlers,
+ NewListener: newTestListenerFunc(tl),
+ Cloner: agdtest.NewCloner(),
+ ErrColl: errColl,
+ NonDNS: http.NotFoundHandler(),
+ MetricsNamespace: path.Base(t.Name()),
+ ServerGroups: srvGrps,
+ HandleTimeout: dnssvctest.Timeout,
+ }
+
+ svc, err = dnssvc.New(c)
require.NoError(t, err)
require.NotNil(t, svc)
@@ -283,6 +265,7 @@ func newTestService(
return svc, srvAddr
}
+// TODO(a.garipov): Refactor to test handlers separately from the service.
func TestService_Wrap(t *testing.T) {
profileDBCh := make(chan agd.DeviceID, 1)
querylogCh := make(chan *querylog.Entry, 1)
@@ -346,7 +329,7 @@ func TestService_Wrap(t *testing.T) {
TLSServerName: dnssvctest.DeviceIDSrvName,
})
- err := svc.Handle(ctx, testSrvGrpName, dnssvctest.ServerName, rw, req)
+ err := svc.Handle(ctx, dnssvctest.ServerGroupName, dnssvctest.ServerName, rw, req)
require.NoError(t, err)
resp := rw.Msg()
@@ -420,7 +403,7 @@ func TestService_Wrap(t *testing.T) {
TLSServerName: dnssvctest.DeviceIDSrvName,
})
- err := svc.Handle(ctx, testSrvGrpName, dnssvctest.ServerName, rw, req)
+ err := svc.Handle(ctx, dnssvctest.ServerGroupName, dnssvctest.ServerName, rw, req)
require.NoError(t, err)
resp := rw.Msg()
diff --git a/internal/dnssvc/internal/devicefinder/device_test.go b/internal/dnssvc/internal/devicefinder/device_test.go
index 4f097bf..e558de7 100644
--- a/internal/dnssvc/internal/devicefinder/device_test.go
+++ b/internal/dnssvc/internal/devicefinder/device_test.go
@@ -80,35 +80,9 @@ func TestDefault_Find_plainAddrs(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
- profDB := &agdtest.ProfileDB{
- OnCreateAutoDevice: func(
- ctx context.Context,
- id agd.ProfileID,
- humanID agd.HumanID,
- devType agd.DeviceType,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
-
- OnProfileByDedicatedIP: newOnProfileByDedicatedIP(dnssvctest.DedicatedAddr),
-
- OnProfileByDeviceID: func(
- _ context.Context,
- _ agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
-
- OnProfileByHumanID: func(
- _ context.Context,
- _ agd.ProfileID,
- _ agd.HumanIDLower,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
-
- OnProfileByLinkedIP: newOnProfileByLinkedIP(dnssvctest.LinkedAddr),
- }
+ profDB := agdtest.NewProfileDB()
+ profDB.OnProfileByDedicatedIP = newOnProfileByDedicatedIP(dnssvctest.DedicatedAddr)
+ profDB.OnProfileByLinkedIP = newOnProfileByLinkedIP(dnssvctest.LinkedAddr)
df := devicefinder.NewDefault(&devicefinder.Config{
Logger: slogutil.NewDiscardLogger(),
@@ -177,40 +151,8 @@ func TestDefault_Find_plainEDNS(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
- profDB := &agdtest.ProfileDB{
- OnCreateAutoDevice: func(
- ctx context.Context,
- id agd.ProfileID,
- humanID agd.HumanID,
- devType agd.DeviceType,
- ) (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")
- },
-
- OnProfileByDeviceID: newOnProfileByDeviceID(dnssvctest.DeviceID),
-
- OnProfileByHumanID: func(
- _ context.Context,
- _ agd.ProfileID,
- _ agd.HumanIDLower,
- ) (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")
- },
- }
+ profDB := agdtest.NewProfileDB()
+ profDB.OnProfileByDeviceID = newOnProfileByDeviceID(dnssvctest.DeviceID)
df := devicefinder.NewDefault(&devicefinder.Config{
Logger: slogutil.NewDiscardLogger(),
@@ -231,44 +173,12 @@ func TestDefault_Find_plainEDNS(t *testing.T) {
func TestDefault_Find_deleted(t *testing.T) {
t.Parallel()
- profDB := &agdtest.ProfileDB{
- OnCreateAutoDevice: func(
- ctx context.Context,
- id agd.ProfileID,
- humanID agd.HumanID,
- devType agd.DeviceType,
- ) (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")
- },
-
- OnProfileByDeviceID: func(
- _ context.Context,
- _ agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
-
- OnProfileByHumanID: func(
- _ context.Context,
- _ agd.ProfileID,
- _ agd.HumanIDLower,
- ) (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
- },
+ profDB := agdtest.NewProfileDB()
+ profDB.OnProfileByLinkedIP = func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ return profDeleted, devNormal, nil
}
df := devicefinder.NewDefault(&devicefinder.Config{
@@ -291,44 +201,21 @@ func TestDefault_Find_byHumanID(t *testing.T) {
// device-type and profile data regardless of the case.
extIDStr := "OTR-" + strings.ToUpper(dnssvctest.ProfileIDStr) + "-" + dnssvctest.HumanIDStr + "-!!!"
- profDB := &agdtest.ProfileDB{
- OnCreateAutoDevice: func(
- ctx context.Context,
- id agd.ProfileID,
- humanID agd.HumanID,
- devType agd.DeviceType,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return profNormal, devAuto, nil
- },
-
- 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) {
- panic("not implemented")
- },
-
- OnProfileByHumanID: func(
- _ context.Context,
- _ agd.ProfileID,
- _ agd.HumanIDLower,
- ) (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) {
- panic("not implemented")
- },
+ profDB := agdtest.NewProfileDB()
+ profDB.OnCreateAutoDevice = func(
+ ctx context.Context,
+ id agd.ProfileID,
+ humanID agd.HumanID,
+ devType agd.DeviceType,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ return profNormal, devAuto, nil
+ }
+ profDB.OnProfileByHumanID = func(
+ _ context.Context,
+ _ agd.ProfileID,
+ _ agd.HumanIDLower,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ return nil, nil, profiledb.ErrDeviceNotFound
}
df := devicefinder.NewDefault(&devicefinder.Config{
diff --git a/internal/dnssvc/internal/devicefinder/devicedata_test.go b/internal/dnssvc/internal/devicefinder/devicedata_test.go
index f06c261..18d7997 100644
--- a/internal/dnssvc/internal/devicefinder/devicedata_test.go
+++ b/internal/dnssvc/internal/devicefinder/devicedata_test.go
@@ -2,7 +2,6 @@ package devicefinder_test
import (
"context"
- "net/netip"
"net/url"
"path"
"testing"
@@ -88,48 +87,16 @@ func TestDefault_Find_DoHAuth(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
- profDB := &agdtest.ProfileDB{
- OnCreateAutoDevice: func(
- ctx context.Context,
- id agd.ProfileID,
- humanID agd.HumanID,
- devType agd.DeviceType,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
+ profDB := agdtest.NewProfileDB()
+ profDB.OnProfileByDeviceID = func(
+ _ context.Context,
+ devID agd.DeviceID,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ if tc.profDBDev != nil {
+ return profNormal, tc.profDBDev, nil
+ }
- 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
- },
-
- OnProfileByHumanID: func(
- _ context.Context,
- _ agd.ProfileID,
- _ agd.HumanIDLower,
- ) (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")
- },
+ return nil, nil, profiledb.ErrDeviceNotFound
}
df := devicefinder.NewDefault(&devicefinder.Config{
@@ -220,44 +187,12 @@ func TestDefault_Find_DoHAuthOnly(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
- profDB := &agdtest.ProfileDB{
- OnCreateAutoDevice: func(
- ctx context.Context,
- id agd.ProfileID,
- humanID agd.HumanID,
- devType agd.DeviceType,
- ) (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")
- },
-
- OnProfileByDeviceID: func(
- _ context.Context,
- devID agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- return profNormal, tc.profDBDev, nil
- },
-
- OnProfileByHumanID: func(
- _ context.Context,
- _ agd.ProfileID,
- _ agd.HumanIDLower,
- ) (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")
- },
+ profDB := agdtest.NewProfileDB()
+ profDB.OnProfileByDeviceID = func(
+ _ context.Context,
+ devID agd.DeviceID,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ return profNormal, tc.profDBDev, nil
}
df := devicefinder.NewDefault(&devicefinder.Config{
@@ -351,34 +286,9 @@ func TestDefault_Find_DoH(t *testing.T) {
name: "human_id_path_match",
}}
- profDB := &agdtest.ProfileDB{
- OnCreateAutoDevice: func(
- ctx context.Context,
- id agd.ProfileID,
- humanID agd.HumanID,
- devType agd.DeviceType,
- ) (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")
- },
-
- OnProfileByDeviceID: newOnProfileByDeviceID(dnssvctest.DeviceID),
-
- OnProfileByHumanID: newOnProfileByHumanID(dnssvctest.ProfileID, dnssvctest.HumanIDLower),
-
- OnProfileByLinkedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
- }
+ profDB := agdtest.NewProfileDB()
+ profDB.OnProfileByDeviceID = newOnProfileByDeviceID(dnssvctest.DeviceID)
+ profDB.OnProfileByHumanID = newOnProfileByHumanID(dnssvctest.ProfileID, dnssvctest.HumanIDLower)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@@ -450,34 +360,9 @@ func TestDefault_Find_stdEncrypted(t *testing.T) {
deviceDomains: []string{dnssvctest.DomainForDevices},
}}
- profDB := &agdtest.ProfileDB{
- OnCreateAutoDevice: func(
- ctx context.Context,
- id agd.ProfileID,
- humanID agd.HumanID,
- devType agd.DeviceType,
- ) (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")
- },
-
- OnProfileByDeviceID: newOnProfileByDeviceID(dnssvctest.DeviceID),
-
- OnProfileByHumanID: newOnProfileByHumanID(dnssvctest.ProfileID, dnssvctest.HumanIDLower),
-
- OnProfileByLinkedIP: func(
- _ context.Context,
- _ netip.Addr,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
- }
+ profDB := agdtest.NewProfileDB()
+ profDB.OnProfileByDeviceID = newOnProfileByDeviceID(dnssvctest.DeviceID)
+ profDB.OnProfileByHumanID = newOnProfileByHumanID(dnssvctest.ProfileID, dnssvctest.HumanIDLower)
srvData := []struct {
srv *agd.Server
diff --git a/internal/dnssvc/internal/devicefinder/humanid_test.go b/internal/dnssvc/internal/devicefinder/humanid_test.go
index 676a6b1..a70c4ad 100644
--- a/internal/dnssvc/internal/devicefinder/humanid_test.go
+++ b/internal/dnssvc/internal/devicefinder/humanid_test.go
@@ -1,8 +1,6 @@
package devicefinder_test
import (
- "context"
- "net/netip"
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
@@ -49,53 +47,13 @@ func TestDefault_Find_humanID(t *testing.T) {
in: "otr-abcd1234-!!!",
}}
- profDB := &agdtest.ProfileDB{
- OnCreateAutoDevice: func(
- ctx context.Context,
- id agd.ProfileID,
- humanID agd.HumanID,
- devType agd.DeviceType,
- ) (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")
- },
-
- OnProfileByDeviceID: func(
- _ context.Context,
- devID agd.DeviceID,
- ) (p *agd.Profile, d *agd.Device, err error) {
- panic("not implemented")
- },
-
- OnProfileByHumanID: func(
- _ context.Context,
- _ agd.ProfileID,
- _ agd.HumanIDLower,
- ) (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")
- },
- }
-
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
df := devicefinder.NewDefault(&devicefinder.Config{
Logger: slogutil.NewDiscardLogger(),
- ProfileDB: profDB,
+ ProfileDB: agdtest.NewProfileDB(),
HumanIDParser: agd.NewHumanIDParser(),
Server: srvDoT,
DeviceDomains: []string{dnssvctest.DomainForDevices},
diff --git a/internal/dnssvc/internal/dnssvctest/dnssvctest.go b/internal/dnssvc/internal/dnssvctest/dnssvctest.go
index a5cdc67..65f0cfb 100644
--- a/internal/dnssvc/internal/dnssvctest/dnssvctest.go
+++ b/internal/dnssvc/internal/dnssvctest/dnssvctest.go
@@ -55,8 +55,16 @@ const (
DomainRewrittenCNAMEFQDN = DomainRewrittenCNAME + "."
)
-// ServerName is the common server name for tests.
-const ServerName agd.ServerName = "test_server_dns_tls"
+const (
+ // FilteringGroupID is the common filtering-group ID for tests.
+ FilteringGroupID agd.FilteringGroupID = "test_filtering_group"
+
+ // ServerName is the common server name for tests.
+ ServerName agd.ServerName = "test_server_dns_tls"
+
+ // ServerGroupName is the common server-group name for tests.
+ ServerGroupName agd.ServerGroupName = "test_server_group"
+)
const (
// DomainForDevices is the upper-level domain name for requests with device
diff --git a/internal/dnssvc/internal/initial/specialdomain.go b/internal/dnssvc/internal/initial/specialdomain.go
index 81a8415..d79d102 100644
--- a/internal/dnssvc/internal/initial/specialdomain.go
+++ b/internal/dnssvc/internal/initial/specialdomain.go
@@ -29,8 +29,8 @@ const (
// Resolvers for querying the resolver with unknown or absent name.
DDRDomain = DDRLabel + "." + ResolverARPADomain
- // FirefoxCanaryHost is the hostname that Firefox uses to check if it
- // should use its own DNS-over-HTTPS settings.
+ // FirefoxCanaryHost is the hostname that Firefox uses to check if it should
+ // use its own DNS-over-HTTPS settings.
//
// See https://support.mozilla.org/en-US/kb/configuring-networks-disable-dns-over-https.
FirefoxCanaryHost = "use-application-dns.net"
@@ -56,6 +56,11 @@ func (mw *Middleware) reqInfoSpecialHandler(
return nil, ""
}
+ // As per RFC-9462 section 6.4, resolvers SHOULD respond to queries of any
+ // type other than SVCB for _dns.resolver.arpa. with NODATA and queries of
+ // any type for any domain name under resolver.arpa with NODATA.
+ //
+ // TODO(e.burkov): Consider adding SOA records for these NODATA responses.
if mw.isDDRRequest(ri) {
if _, ok := ri.DeviceResult.(*agd.DeviceResultAuthenticationFailure); ok {
return mw.handleDDRNoData, "ddr_doh"
@@ -84,8 +89,6 @@ type reqInfoHandlerFunc func(
ri *agd.RequestInfo,
) (err error)
-// DDR And Resolver ARPA Domain
-
// isDDRRequest determines if the message is the request for Discovery of
// Designated Resolvers as defined by the RFC draft. The request is considered
// ARPA if the requested host is a subdomain of resolver.arpa SUDN.
@@ -141,8 +144,8 @@ func isDDRDomain(ri *agd.RequestInfo, host string) (ok bool) {
return false
}
-// handleDDR checks if the request is for the Discovery of Designated Resolvers
-// and writes a response if needed.
+// handleDDR responds to Discovery of Designated Resolvers (DDR) queries with a
+// response containing the designated resolvers.
func (mw *Middleware) handleDDR(
ctx context.Context,
rw dnsserver.ResponseWriter,
@@ -157,11 +160,11 @@ func (mw *Middleware) handleDDR(
return rw.WriteMsg(ctx, req, mw.newRespDDR(req, ri))
}
- return rw.WriteMsg(ctx, req, ri.Messages.NewMsgNXDOMAIN(req))
+ return rw.WriteMsg(ctx, req, ri.Messages.NewRespRCode(req, dns.RcodeNameError))
}
-// handleDDRNoData processes DDR (Discovery of Designated Resolvers) requests
-// for devices which need NODATA response and writes the response if needed.
+// handleDDRNoData responds to Discovery of Designated Resolvers (DDR) queries
+// with a NODATA response.
func (mw *Middleware) handleDDRNoData(
ctx context.Context,
rw dnsserver.ResponseWriter,
@@ -173,17 +176,17 @@ func (mw *Middleware) handleDDRNoData(
metrics.DNSSvcDDRRequestsTotal.Inc()
if ri.ServerGroup.DDR.Enabled {
- return rw.WriteMsg(ctx, req, ri.Messages.NewMsgNODATA(req))
+ return rw.WriteMsg(ctx, req, ri.Messages.NewRespRCode(req, dns.RcodeSuccess))
}
- return rw.WriteMsg(ctx, req, ri.Messages.NewMsgNXDOMAIN(req))
+ return rw.WriteMsg(ctx, req, ri.Messages.NewRespRCode(req, dns.RcodeNameError))
}
// newRespDDR returns a new Discovery of Designated Resolvers response copying
// it from the prebuilt templates in srvGrp and modifying it in accordance with
// the request data. req must not be nil.
func (mw *Middleware) newRespDDR(req *dns.Msg, ri *agd.RequestInfo) (resp *dns.Msg) {
- resp = ri.Messages.NewRespMsg(req)
+ resp = ri.Messages.NewResp(req)
name := req.Question[0].Name
ddr := ri.ServerGroup.DDR
@@ -210,7 +213,8 @@ func (mw *Middleware) newRespDDR(req *dns.Msg, ri *agd.RequestInfo) (resp *dns.M
return resp
}
-// handleBadResolverARPA writes a NODATA response.
+// handleBadResolverARPA responds to badly formed resolver.arpa queries with a
+// NODATA response.
func (mw *Middleware) handleBadResolverARPA(
ctx context.Context,
rw dnsserver.ResponseWriter,
@@ -219,7 +223,8 @@ func (mw *Middleware) handleBadResolverARPA(
) (err error) {
metrics.DNSSvcBadResolverARPA.Inc()
- err = rw.WriteMsg(ctx, req, ri.Messages.NewRespMsg(req))
+ resp := ri.Messages.NewRespRCode(req, dns.RcodeSuccess)
+ err = rw.WriteMsg(ctx, req, resp)
return errors.Annotate(err, "writing nodata resp for %q: %w", ri.Host)
}
@@ -257,8 +262,6 @@ func (mw *Middleware) specialDomainHandler(
return nil, ""
}
-// Apple Private Relay
-
// shouldBlockPrivateRelay returns true if the query is for an Apple Private
// Relay check domain and the request information or profile indicates that
// Apple Private Relay should be blocked.
@@ -280,13 +283,12 @@ func (mw *Middleware) handlePrivateRelay(
) (err error) {
metrics.DNSSvcApplePrivateRelayRequestsTotal.Inc()
- err = rw.WriteMsg(ctx, req, ri.Messages.NewMsgNXDOMAIN(req))
+ resp := ri.Messages.NewRespRCode(req, dns.RcodeNameError)
+ err = rw.WriteMsg(ctx, req, resp)
return errors.Annotate(err, "writing private relay resp: %w")
}
-// Firefox canary domain
-
// shouldBlockFirefoxCanary returns true if the query is for a Firefox canary
// domain and the request information or profile indicates that Firefox canary
// domain should be blocked.
@@ -298,8 +300,8 @@ func shouldBlockFirefoxCanary(ri *agd.RequestInfo, prof *agd.Profile) (ok bool)
return ri.FilteringGroup.BlockFirefoxCanary
}
-// handleFirefoxCanary checks if the request is for the fully-qualified domain
-// name that Firefox uses to check DoH settings and writes a response if needed.
+// handleFirefoxCanary responds to Firefox canary domain queries with a REFUSED
+// response.
func (mw *Middleware) handleFirefoxCanary(
ctx context.Context,
rw dnsserver.ResponseWriter,
@@ -308,7 +310,7 @@ func (mw *Middleware) handleFirefoxCanary(
) (err error) {
metrics.DNSSvcFirefoxRequestsTotal.Inc()
- resp := ri.Messages.NewMsgREFUSED(req)
+ resp := ri.Messages.NewRespRCode(req, dns.RcodeRefused)
err = rw.WriteMsg(ctx, req, resp)
return errors.Annotate(err, "writing firefox canary resp: %w")
diff --git a/internal/dnssvc/internal/mainmw/debug_internal_test.go b/internal/dnssvc/internal/mainmw/debug_internal_test.go
index a19d528..4a1580b 100644
--- a/internal/dnssvc/internal/mainmw/debug_internal_test.go
+++ b/internal/dnssvc/internal/mainmw/debug_internal_test.go
@@ -44,7 +44,9 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
Cloner: cloner,
BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ StructuredErrors: agdtest.NewSDEConfig(true),
FilteredResponseTTL: agdtest.FilteredResponseTTL,
+ EDEEnabled: true,
})
require.NoError(t, err)
diff --git a/internal/dnssvc/internal/mainmw/filter.go b/internal/dnssvc/internal/mainmw/filter.go
index 0920e42..72b1a73 100644
--- a/internal/dnssvc/internal/mainmw/filter.go
+++ b/internal/dnssvc/internal/mainmw/filter.go
@@ -162,7 +162,7 @@ func (mw *Middleware) setFilteredResponse(
mw.setFilteredResponseNoReq(ctx, fctx, ri)
case *filter.ResultBlocked:
var err error
- fctx.filteredResponse, err = ri.Messages.NewBlockedRespMsg(fctx.originalRequest)
+ fctx.filteredResponse, err = ri.Messages.NewBlockedResp(fctx.originalRequest)
if err != nil {
mw.reportf(ctx, "creating blocked resp for filtered req: %w", err)
fctx.filteredResponse = fctx.originalResponse
@@ -199,7 +199,7 @@ func (mw *Middleware) setFilteredResponseNoReq(
fctx.filteredResponse = fctx.originalResponse
case *filter.ResultBlocked:
var err error
- fctx.filteredResponse, err = ri.Messages.NewBlockedRespMsg(fctx.originalRequest)
+ fctx.filteredResponse, err = ri.Messages.NewBlockedResp(fctx.originalRequest)
if err != nil {
mw.reportf(ctx, "creating blocked resp for filtered resp: %w", err)
fctx.filteredResponse = fctx.originalResponse
diff --git a/internal/dnssvc/internal/mainmw/mainmw.go b/internal/dnssvc/internal/mainmw/mainmw.go
index 1fab249..1442636 100644
--- a/internal/dnssvc/internal/mainmw/mainmw.go
+++ b/internal/dnssvc/internal/mainmw/mainmw.go
@@ -4,6 +4,7 @@ package mainmw
import (
"context"
+ "log/slog"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
@@ -14,7 +15,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
- "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
+ "github.com/AdguardTeam/AdGuardDNS/internal/optslog"
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
"github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
"github.com/AdguardTeam/golibs/errors"
@@ -24,14 +25,15 @@ import (
// Middleware is the main middleware of AdGuard DNS.
type Middleware struct {
- messages *dnsmsg.Constructor
cloner *dnsmsg.Cloner
fltCtxPool *syncutil.Pool[filteringContext]
- metrics Metrics
+ logger *slog.Logger
+ messages *dnsmsg.Constructor
billStat billstat.Recorder
errColl errcoll.Interface
fltStrg filter.Storage
geoIP geoip.Interface
+ metrics Metrics
queryLog querylog.Interface
ruleStat rulestat.Interface
}
@@ -39,19 +41,17 @@ type Middleware struct {
// Config is the configuration structure for the main middleware. All fields
// must be non-nil.
type Config struct {
- // Metrics is used to collect the statistics.
- Metrics Metrics
+ // Cloner is used to clone messages more efficiently by disposing of parts
+ // of DNS responses for later reuse.
+ Cloner *dnsmsg.Cloner
+
+ // Logger is used to log the operation of the middleware.
+ Logger *slog.Logger
// Messages is the message constructor used to create blocked and other
// messages for this middleware.
Messages *dnsmsg.Constructor
- // Cloner is used to clone messages more efficiently by disposing of parts
- // of DNS responses for later reuse.
- //
- // TODO(a.garipov): Use.
- Cloner *dnsmsg.Cloner
-
// BillStat is used to collect billing statistics.
BillStat billstat.Recorder
@@ -66,6 +66,9 @@ type Config struct {
// addresses in requests and responses.
GeoIP geoip.Interface
+ // Metrics is used to collect the statistics.
+ Metrics Metrics
+
// QueryLog is used to write the logs into.
QueryLog querylog.Interface
@@ -77,16 +80,17 @@ type Config struct {
// New returns a new main middleware. c must not be nil.
func New(c *Config) (mw *Middleware) {
return &Middleware{
- metrics: c.Metrics,
- messages: c.Messages,
- cloner: c.Cloner,
+ cloner: c.Cloner,
fltCtxPool: syncutil.NewPool(func() (v *filteringContext) {
return &filteringContext{}
}),
+ logger: c.Logger,
+ messages: c.Messages,
billStat: c.BillStat,
errColl: c.ErrColl,
fltStrg: c.FilterStorage,
geoIP: c.GeoIP,
+ metrics: c.Metrics,
queryLog: c.QueryLog,
ruleStat: c.RuleStat,
}
@@ -106,8 +110,20 @@ func (mw *Middleware) Wrap(next dnsserver.Handler) (wrapped dnsserver.Handler) {
defer mw.fltCtxPool.Put(fctx)
ri := agd.MustRequestInfoFromContext(ctx)
- optlog.Debug2("processing request %q from %s", ri.ID, ri.RemoteIP)
- defer optlog.Debug2("finished processing request %q from %s", ri.ID, ri.RemoteIP)
+ optslog.Debug2(
+ ctx,
+ mw.logger,
+ "processing request",
+ "req_id", ri.ID,
+ "remote_ip", ri.RemoteIP,
+ )
+ defer optslog.Debug2(
+ ctx,
+ mw.logger,
+ "finished processing request",
+ "req_id", ri.ID,
+ "remote_ip", ri.RemoteIP,
+ )
flt := mw.fltStrg.FilterFromContext(ctx, ri)
mw.filterRequest(ctx, fctx, flt, ri)
@@ -184,10 +200,12 @@ func (mw *Middleware) nextParams(
ctx = agd.ContextWithRequestInfo(ctx, modReqInfo)
- optlog.Debug2(
- "mainmw: request for %q rewritten to %q by CNAME rewrite rule",
- ri.Host,
- modReqInfo.Host,
+ optslog.Debug2(
+ ctx,
+ mw.logger,
+ "request rewritten by cname rewrite rule",
+ "orig_host", ri.Host,
+ "mod_host", modReqInfo.Host,
)
return ctx, origRW, modReq
diff --git a/internal/dnssvc/internal/mainmw/mainmw_test.go b/internal/dnssvc/internal/mainmw/mainmw_test.go
index 9893b12..e904b8b 100644
--- a/internal/dnssvc/internal/mainmw/mainmw_test.go
+++ b/internal/dnssvc/internal/mainmw/mainmw_test.go
@@ -17,17 +17,13 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
- "github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-func TestMain(m *testing.M) {
- testutil.DiscardLogOutput(m)
-}
-
// Common constants for tests.
const (
testASN geoip.ASN = 12345
@@ -121,24 +117,17 @@ func TestMiddleware_Wrap(t *testing.T) {
OnHasListID: func(_ agd.FilterListID) (ok bool) { panic("not implemented") },
}
- geoIP := &agdtest.GeoIP{
- OnSubnetByLocation: func(
- _ *geoip.Location,
- _ netutil.AddrFamily,
- ) (n netip.Prefix, err error) {
- panic("not implemented")
- },
- OnData: func(host string, addr netip.Addr) (l *geoip.Location, err error) {
- pt := testutil.PanicT{}
- require.Equal(pt, dnssvctest.Domain, host)
- if addr.Is4() {
- require.Equal(pt, addr, testRespAddr4)
- } else if addr.Is6() {
- require.Equal(pt, addr, testRespAddr6)
- }
+ geoIP := agdtest.NewGeoIP()
+ geoIP.OnData = func(host string, addr netip.Addr) (l *geoip.Location, err error) {
+ pt := testutil.PanicT{}
+ require.Equal(pt, dnssvctest.Domain, host)
+ if addr.Is4() {
+ require.Equal(pt, addr, testRespAddr4)
+ } else if addr.Is6() {
+ require.Equal(pt, addr, testRespAddr6)
+ }
- return nil, nil
- },
+ return nil, nil
}
ruleStat := &agdtest.RuleStat{
@@ -153,7 +142,9 @@ func TestMiddleware_Wrap(t *testing.T) {
msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
Cloner: cloner,
BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ StructuredErrors: agdtest.NewSDEConfig(true),
FilteredResponseTTL: agdtest.FilteredResponseTTL,
+ EDEEnabled: true,
})
require.NoError(t, err)
@@ -227,13 +218,14 @@ func TestMiddleware_Wrap(t *testing.T) {
}
c := &mainmw.Config{
- Metrics: mainmw.EmptyMetrics{},
- Messages: msgs,
Cloner: cloner,
+ Logger: slogutil.NewDiscardLogger(),
+ Messages: msgs,
BillStat: tc.billStat,
ErrColl: agdtest.NewErrorCollector(),
FilterStorage: fltStrg,
GeoIP: geoIP,
+ Metrics: mainmw.EmptyMetrics{},
QueryLog: queryLog,
RuleStat: ruleStat,
}
@@ -411,16 +403,9 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
}
)
- geoIP := &agdtest.GeoIP{
- OnSubnetByLocation: func(
- _ *geoip.Location,
- _ netutil.AddrFamily,
- ) (n netip.Prefix, err error) {
- panic("not implemented")
- },
- OnData: func(host string, addr netip.Addr) (l *geoip.Location, err error) {
- return nil, nil
- },
+ geoIP := agdtest.NewGeoIP()
+ geoIP.OnData = func(_ string, _ netip.Addr) (l *geoip.Location, err error) {
+ return nil, nil
}
var (
@@ -537,7 +522,9 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
Cloner: cloner,
BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ StructuredErrors: agdtest.NewSDEConfig(true),
FilteredResponseTTL: agdtest.FilteredResponseTTL,
+ EDEEnabled: true,
})
require.NoError(t, err)
@@ -701,13 +688,14 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
}
c := &mainmw.Config{
- Metrics: mainmw.EmptyMetrics{},
- Messages: msgs,
Cloner: cloner,
+ Logger: slogutil.NewDiscardLogger(),
+ Messages: msgs,
BillStat: tc.billStat,
ErrColl: agdtest.NewErrorCollector(),
FilterStorage: fltStrg,
GeoIP: geoIP,
+ Metrics: mainmw.EmptyMetrics{},
QueryLog: queryLog,
RuleStat: ruleStat,
}
diff --git a/internal/dnssvc/internal/mainmw/record.go b/internal/dnssvc/internal/mainmw/record.go
index 4fc39a9..9065adc 100644
--- a/internal/dnssvc/internal/mainmw/record.go
+++ b/internal/dnssvc/internal/mainmw/record.go
@@ -12,7 +12,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
- "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
+ "github.com/AdguardTeam/AdGuardDNS/internal/optslog"
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
"github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
@@ -112,8 +112,7 @@ func (mw *Middleware) responseCountry(
}
ctry = mw.country(ctx, host, respIP)
- // TODO(a.garipov): Use optslog.Trace2.
- optlog.Debug2("mainmw: got ctry %q for resp ip %v", ctry, respIP)
+ optslog.Trace2(ctx, mw.logger, "geoip for resp", "ctry", ctry, "resp_ip", respIP)
return ctry
}
diff --git a/internal/dnssvc/internal/mainmw/record_internal_test.go b/internal/dnssvc/internal/mainmw/record_internal_test.go
index 4daaee3..7bcadb7 100644
--- a/internal/dnssvc/internal/mainmw/record_internal_test.go
+++ b/internal/dnssvc/internal/mainmw/record_internal_test.go
@@ -16,7 +16,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
"github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
- "github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -134,20 +134,13 @@ func TestMiddleware_recordQueryInfo_respCtry(t *testing.T) {
Country: testCtry,
}
- geoIP := &agdtest.GeoIP{
- OnSubnetByLocation: func(
- _ *geoip.Location,
- _ netutil.AddrFamily,
- ) (n netip.Prefix, err error) {
- panic("not implemented")
- },
- OnData: func(_ string, _ netip.Addr) (l *geoip.Location, err error) {
- if !tc.wantGeoIP {
- t.Error("unexpected call to geoip")
- }
+ geoIP := agdtest.NewGeoIP()
+ geoIP.OnData = func(_ string, _ netip.Addr) (l *geoip.Location, err error) {
+ if !tc.wantGeoIP {
+ t.Error("unexpected call to geoip")
+ }
- return loc, nil
- },
+ return loc, nil
}
queryLogCalled := false
@@ -164,6 +157,7 @@ func TestMiddleware_recordQueryInfo_respCtry(t *testing.T) {
}
mw := &Middleware{
+ logger: slogutil.NewDiscardLogger(),
billStat: billstat.EmptyRecorder{},
geoIP: geoIP,
queryLog: queryLog,
diff --git a/internal/dnssvc/internal/preservice/preservice.go b/internal/dnssvc/internal/preservice/preservice.go
index 4864e5d..120d6d6 100644
--- a/internal/dnssvc/internal/preservice/preservice.go
+++ b/internal/dnssvc/internal/preservice/preservice.go
@@ -5,15 +5,16 @@ package preservice
import (
"context"
"fmt"
+ "log/slog"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
- "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
+ "github.com/AdguardTeam/AdGuardDNS/internal/optslog"
"github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/log"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/miekg/dns"
)
@@ -22,19 +23,18 @@ import (
// names that may be filtered by safe browsing or parental control filters as
// well as handling of the DNS-server check queries.
type Middleware struct {
- // messages is used to construct TXT responses.
- messages *dnsmsg.Constructor
-
- // hashMatcher is the safe browsing DNS hashMatcher.
+ logger *slog.Logger
+ messages *dnsmsg.Constructor
hashMatcher filter.HashMatcher
-
- // checker is used to detect and process DNS-check requests.
- checker dnscheck.Interface
+ checker dnscheck.Interface
}
// Config is the configurational structure for the preservice middleware. All
// fields must be non-nil.
type Config struct {
+ // Logger is used to log the operation of the middleware.
+ Logger *slog.Logger
+
// Messages is used to construct TXT responses.
Messages *dnsmsg.Constructor
@@ -48,6 +48,7 @@ type Config struct {
// New returns a new preservice middleware. c must not be nil.
func New(c *Config) (mw *Middleware) {
return &Middleware{
+ logger: c.Logger,
messages: c.Messages,
hashMatcher: c.HashMatcher,
checker: c.Checker,
@@ -60,7 +61,7 @@ var _ dnsserver.Middleware = (*Middleware)(nil)
// Wrap implements the [dnsserver.Middleware] interface for *Middleware.
func (mw *Middleware) Wrap(next dnsserver.Handler) (wrapped dnsserver.Handler) {
f := func(ctx context.Context, rw dnsserver.ResponseWriter, req *dns.Msg) (err error) {
- defer func() { err = errors.Annotate(err, "preservice mw: %w") }()
+ defer func() { err = errors.Annotate(err, "presvcmw: %w") }()
ri := agd.MustRequestInfoFromContext(ctx)
if ri.QType == dns.TypeTXT {
@@ -71,13 +72,20 @@ func (mw *Middleware) Wrap(next dnsserver.Handler) (wrapped dnsserver.Handler) {
resp, err := mw.checker.Check(ctx, req, ri)
if err != nil {
return fmt.Errorf("calling dnscheck: %w", err)
- } else if resp != nil {
- return errors.Annotate(rw.WriteMsg(ctx, req, resp), "writing dnscheck response: %w")
}
- // Don't wrap the error, because this is the main flow, and there is
- // already [errors.Annotate] here.
- return next.ServeDNS(ctx, rw, req)
+ if resp == nil {
+ // Don't wrap the error, because this is the main flow, and there is
+ // already [errors.Annotate] here.
+ return next.ServeDNS(ctx, rw, req)
+ }
+
+ err = rw.WriteMsg(ctx, req, resp)
+ if err != nil {
+ return fmt.Errorf("writing dnscheck response: %w", err)
+ }
+
+ return nil
}
return dnsserver.HandlerFunc(f)
@@ -92,15 +100,19 @@ func (mw *Middleware) respondWithHashes(
req *dns.Msg,
ri *agd.RequestInfo,
) (err error) {
- optlog.Debug1("preservice mw: safe browsing: got txt req for %q", ri.Host)
+ optslog.Debug1(ctx, mw.logger, "got txt req", "host", ri.Host)
hashes, matched, err := mw.hashMatcher.MatchByPrefix(ctx, ri.Host)
if err != nil {
// Don't return or collect this error to prevent DDoS of the error
// collector by sending bad requests.
- log.Error("preservice mw: safe browsing: matching hashes: %s", err)
+ mw.logger.ErrorContext(
+ ctx,
+ "matching hashes",
+ slogutil.KeyError, err,
+ )
- resp := mw.messages.NewMsgREFUSED(req)
+ resp := mw.messages.NewRespRCode(req, dns.RcodeRefused)
err = rw.WriteMsg(ctx, req, resp)
return errors.Annotate(err, "writing refused response: %w")
@@ -110,7 +122,7 @@ func (mw *Middleware) respondWithHashes(
return next.ServeDNS(ctx, rw, req)
}
- resp, err := mw.messages.NewTXTRespMsg(req, hashes...)
+ resp, err := mw.messages.NewRespTXT(req, hashes...)
if err != nil {
// Technically should never happen since the only error that could arise
// in [dnsmsg.Constructor.NewTXTRespMsg] is the one about request type
@@ -118,7 +130,7 @@ func (mw *Middleware) respondWithHashes(
return fmt.Errorf("creating safe browsing result: %w", err)
}
- optlog.Debug1("preservice mw: safe browsing: writing hashes %q", hashes)
+ optslog.Debug1(ctx, mw.logger, "writing hashes", "hashes", hashes)
err = rw.WriteMsg(ctx, req, resp)
if err != nil {
diff --git a/internal/dnssvc/internal/preservice/preservice_test.go b/internal/dnssvc/internal/preservice/preservice_test.go
index 2cffe48..01a7b30 100644
--- a/internal/dnssvc/internal/preservice/preservice_test.go
+++ b/internal/dnssvc/internal/preservice/preservice_test.go
@@ -17,18 +17,16 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
"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 TestMain(m *testing.M) {
- testutil.DiscardLogOutput(m)
-}
-
func TestPreServiceMwHandler_ServeDNS(t *testing.T) {
+ t.Parallel()
+
const safeBrowsingHost = "scam.example.net."
var (
@@ -124,6 +122,8 @@ func TestPreServiceMwHandler_ServeDNS(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.ClientTCPAddr)
tctx := agd.ContextWithRequestInfo(ctx, tc.ri)
@@ -152,16 +152,19 @@ func TestPreServiceMwHandler_ServeDNS(t *testing.T) {
msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
Cloner: cloner,
BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ StructuredErrors: agdtest.NewSDEConfig(true),
FilteredResponseTTL: ttl * time.Second,
+ EDEEnabled: true,
})
require.NoError(t, err)
mw := preservice.New(&preservice.Config{
+ Logger: slogutil.NewDiscardLogger(),
Messages: msgs,
HashMatcher: hashMatcher,
Checker: dnsCk,
})
- handler := dnsservertest.DefaultHandler()
+ handler := dnsservertest.NewDefaultHandler()
h := mw.Wrap(handler)
err = h.ServeDNS(tctx, rw, tc.req)
diff --git a/internal/dnssvc/internal/preupstream/preupstream.go b/internal/dnssvc/internal/preupstream/preupstream.go
index eecdd7d..6c3d4bd 100644
--- a/internal/dnssvc/internal/preupstream/preupstream.go
+++ b/internal/dnssvc/internal/preupstream/preupstream.go
@@ -1,91 +1,40 @@
-// Package preupstream contains the middleware that prepares records for
-// upstream handling and caches them, as well as records anonymous DNS
+// Package preupstream contains the middleware that records anonymous DNS
// statistics.
+//
+// TODO(a.garipov): Consider merging with mainmw if not expanded.
package preupstream
import (
"context"
"fmt"
- "time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/cache"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/prometheus"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal"
- "github.com/AdguardTeam/AdGuardDNS/internal/ecscache"
- "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
- "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
)
// Middleware is a middleware that prepares records for caching and upstream
// handling as well as records anonymous DNS statistics.
type Middleware struct {
- cloner *dnsmsg.Cloner
- cacheManager agdcache.Manager
- db dnsdb.Interface
- geoIP geoip.Interface
- cacheMinTTL time.Duration
- cacheSize int
- ecsCacheSize int
- useECSCache bool
- useCacheTTLOverride bool
+ db dnsdb.Interface
}
-// Config is the configurational structure for the preupstream middleware. DB
-// must not be nil.
+// Config is the configuration structure for the preupstream middleware.
type Config struct {
- // Cloner is used to clone messages taken from cache.
- Cloner *dnsmsg.Cloner
-
- // CacheManager is the global cache manager. CacheManager must not be nil.
- CacheManager agdcache.Manager
-
- // DB is used to update anonymous statistics about DNS queries.
+ // DB is used to update anonymous statistics about DNS queries. It must not
+ // be nil.
DB dnsdb.Interface
-
- // GeoIP is the GeoIP database used to detect geographic data about IP
- // addresses in requests and responses.
- GeoIP geoip.Interface
-
- // CacheMinTTL is the minimum supported TTL for cache items.
- CacheMinTTL time.Duration
-
- // CacheSize is the size of the DNS cache for domain names that don't
- // support ECS.
- CacheSize int
-
- // ECSCacheSize is the size of the DNS cache for domain names that support
- // ECS.
- ECSCacheSize int
-
- // UseECSCache shows if the EDNS Client Subnet (ECS) aware cache should be
- // used.
- UseECSCache bool
-
- // UseCacheTTLOverride shows if the TTL overrides logic should be used.
- UseCacheTTLOverride bool
}
// New returns a new preupstream middleware. c must not be nil.
-func New(c *Config) (mw *Middleware) {
+func New(ctx context.Context, c *Config) (mw *Middleware) {
return &Middleware{
- cloner: c.Cloner,
- cacheManager: c.CacheManager,
- db: c.DB,
- geoIP: c.GeoIP,
- cacheMinTTL: c.CacheMinTTL,
- cacheSize: c.CacheSize,
- ecsCacheSize: c.ECSCacheSize,
- useECSCache: c.UseECSCache,
- useCacheTTLOverride: c.UseCacheTTLOverride,
+ db: c.DB,
}
}
@@ -94,10 +43,8 @@ var _ dnsserver.Middleware = (*Middleware)(nil)
// Wrap implements the [dnsserver.Middleware] interface for *Middleware.
func (mw *Middleware) Wrap(next dnsserver.Handler) (wrapped dnsserver.Handler) {
- next = mw.wrapCacheMw(next)
-
f := func(ctx context.Context, rw dnsserver.ResponseWriter, req *dns.Msg) (err error) {
- defer func() { err = errors.Annotate(err, "preupstream mw: %w") }()
+ defer func() { err = errors.Annotate(err, "preupstreammw: %w") }()
if rn := agdnet.AndroidMetricDomainReplacement(req.Question[0].Name); rn != "" {
// Don't wrap the error, because it's informative enough as is.
@@ -127,40 +74,6 @@ func (mw *Middleware) Wrap(next dnsserver.Handler) (wrapped dnsserver.Handler) {
return dnsserver.HandlerFunc(f)
}
-// wrapCacheMw does nothing if cacheSize is zero otherwise returns wrapped
-// handler with caching middleware which is ECS-aware or not.
-//
-// TODO(s.chzhen): Consider separating caching middleware.
-func (mw *Middleware) wrapCacheMw(next dnsserver.Handler) (wrapped dnsserver.Handler) {
- log.Info("cache: size: %d, ecs: %t", mw.cacheSize, mw.useECSCache)
-
- if mw.cacheSize == 0 {
- return next
- }
-
- var cacheMw dnsserver.Middleware
- if mw.useECSCache {
- cacheMw = ecscache.NewMiddleware(&ecscache.MiddlewareConfig{
- Cloner: mw.cloner,
- CacheManager: mw.cacheManager,
- GeoIP: mw.geoIP,
- Size: mw.cacheSize,
- ECSSize: mw.ecsCacheSize,
- MinTTL: mw.cacheMinTTL,
- UseTTLOverride: mw.useCacheTTLOverride,
- })
- } else {
- cacheMw = cache.NewMiddleware(&cache.MiddlewareConfig{
- MetricsListener: prometheus.NewCacheMetricsListener(metrics.Namespace()),
- Size: mw.cacheSize,
- MinTTL: mw.cacheMinTTL,
- UseTTLOverride: mw.useCacheTTLOverride,
- })
- }
-
- return cacheMw.Wrap(next)
-}
-
// serveAndroidMetric makes sure we avoid resolving random Android DoT, DoH
// metric domains. replName is the replacement domain name to use to improve
// caching of these metric domains.
diff --git a/internal/dnssvc/internal/preupstream/preupstream_test.go b/internal/dnssvc/internal/preupstream/preupstream_test.go
index 89f842f..0d89388 100644
--- a/internal/dnssvc/internal/preupstream/preupstream_test.go
+++ b/internal/dnssvc/internal/preupstream/preupstream_test.go
@@ -2,180 +2,36 @@ package preupstream_test
import (
"context"
- "net"
- "net/netip"
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
"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/AdGuardDNS/internal/dnssvc/internal/preupstream"
- "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
- "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 TestMain(m *testing.M) {
- testutil.DiscardLogOutput(m)
-}
-
-const (
- reqHostname = "example.com."
- defaultTTL = 3600
-)
-
-func TestPreUpstreamMwHandler_ServeDNS_withCache(t *testing.T) {
- aReq := dnsservertest.NewReq(reqHostname, dns.TypeA, dns.ClassINET)
-
- resp := dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
- dnsservertest.NewA(reqHostname, defaultTTL, dnssvctest.ClientAddr),
- })
- ctx := agd.ContextWithRequestInfo(context.Background(), &agd.RequestInfo{
- Host: aReq.Question[0].Name,
- })
-
- const N = 5
- testCases := []struct {
- name string
- cacheSize int
- wantNumReq int
- }{{
- name: "no_cache",
- cacheSize: 0,
- wantNumReq: N,
- }, {
- name: "with_cache",
- cacheSize: 100,
- wantNumReq: 1,
- }}
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- numReq := 0
- handler := dnsserver.HandlerFunc(func(
- ctx context.Context,
- rw dnsserver.ResponseWriter,
- req *dns.Msg,
- ) error {
- numReq++
-
- return rw.WriteMsg(ctx, req, resp)
- })
-
- mw := preupstream.New(&preupstream.Config{
- Cloner: agdtest.NewCloner(),
- DB: dnsdb.Empty{},
- CacheSize: tc.cacheSize,
- })
- h := mw.Wrap(handler)
-
- for range N {
- req := dnsservertest.NewReq(reqHostname, dns.TypeA, dns.ClassINET)
- addr := &net.UDPAddr{IP: dnssvctest.ClientIP, Port: 53}
- nrw := dnsserver.NewNonWriterResponseWriter(addr, addr)
-
- err := h.ServeDNS(ctx, nrw, req)
- require.NoError(t, err)
- }
-
- assert.Equal(t, tc.wantNumReq, numReq)
- })
- }
-}
-
-func TestPreUpstreamMwHandler_ServeDNS_withECSCache(t *testing.T) {
- aReq := dnsservertest.NewReq(reqHostname, dns.TypeA, dns.ClassINET)
- subnet := netip.MustParsePrefix("1.2.3.4/24")
-
- const ctry = geoip.CountryAD
-
- resp := dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
- dnsservertest.NewA(reqHostname, defaultTTL, dnssvctest.ClientAddr),
- })
-
- numReq := 0
- handler := dnsserver.HandlerFunc(
- func(ctx context.Context, rw dnsserver.ResponseWriter, req *dns.Msg) error {
- numReq++
-
- return rw.WriteMsg(ctx, req, resp)
- },
- )
-
- geoIP := &agdtest.GeoIP{
- OnSubnetByLocation: func(
- _ *geoip.Location,
- _ netutil.AddrFamily,
- ) (n netip.Prefix, err error) {
- return netip.MustParsePrefix("1.2.0.0/16"), nil
- },
- OnData: func(_ string, _ netip.Addr) (_ *geoip.Location, _ error) {
- panic("not implemented")
- },
- }
-
- mw := preupstream.New(&preupstream.Config{
- Cloner: agdtest.NewCloner(),
- CacheManager: agdcache.EmptyManager{},
- DB: dnsdb.Empty{},
- GeoIP: geoIP,
- CacheSize: 100,
- ECSCacheSize: 100,
- UseECSCache: true,
- })
- h := mw.Wrap(handler)
-
- ctx := agd.ContextWithRequestInfo(context.Background(), &agd.RequestInfo{
- Location: &geoip.Location{
- Country: ctry,
- },
- ECS: &dnsmsg.ECS{
- Location: &geoip.Location{
- Country: ctry,
- },
- Subnet: subnet,
- Scope: 0,
- },
- Host: aReq.Question[0].Name,
- RemoteIP: dnssvctest.ClientAddr,
- })
-
- const N = 5
- var nrw *dnsserver.NonWriterResponseWriter
- for range N {
- addr := &net.UDPAddr{IP: dnssvctest.ClientIP, Port: 53}
- nrw = dnsserver.NewNonWriterResponseWriter(addr, addr)
- req := dnsservertest.NewReq(reqHostname, dns.TypeA, dns.ClassINET)
-
- err := h.ServeDNS(ctx, nrw, req)
- require.NoError(t, err)
- }
-
- assert.Equal(t, 1, numReq)
-}
-
func TestPreUpstreamMwHandler_ServeDNS_androidMetric(t *testing.T) {
- mw := preupstream.New(&preupstream.Config{
- Cloner: agdtest.NewCloner(),
- DB: dnsdb.Empty{},
+ t.Parallel()
+
+ ctx := testutil.ContextWithTimeout(t, dnssvctest.Timeout)
+ mw := preupstream.New(ctx, &preupstream.Config{
+ DB: dnsdb.Empty{},
})
- req := dnsservertest.CreateMessage(reqHostname, dns.TypeA)
- resp := new(dns.Msg).SetReply(req)
+ req := dnsservertest.CreateMessage(dnssvctest.DomainFQDN, dns.TypeA)
+ defaultResp := new(dns.Msg).SetReply(req)
- ctx := context.Background()
ctx = agd.ContextWithRequestInfo(ctx, &agd.RequestInfo{})
- ipA := netip.MustParseAddr("1.2.3.4")
- ipB := netip.MustParseAddr("1.2.3.5")
+ ipA := dnssvctest.ClientAddr
+ ipB := ipA.Next()
const ttl = 100
@@ -192,20 +48,20 @@ func TestPreUpstreamMwHandler_ServeDNS_androidMetric(t *testing.T) {
wantAns []dns.RR
}{{
name: "no_changes",
- req: dnsservertest.CreateMessage(reqHostname, dns.TypeA),
- resp: resp,
- wantName: reqHostname,
+ req: dnsservertest.CreateMessage(dnssvctest.DomainFQDN, dns.TypeA),
+ resp: dnsmsg.Clone(defaultResp),
+ wantName: dnssvctest.DomainFQDN,
wantAns: nil,
}, {
name: "android-tls-metric",
req: dnsservertest.CreateMessage("12345678"+tlsDomain, dns.TypeA),
- resp: resp,
+ resp: dnsmsg.Clone(defaultResp),
wantName: "00000000" + tlsDomain,
wantAns: nil,
}, {
name: "android-https-metric",
req: dnsservertest.CreateMessage("123456"+httpsDomain, dns.TypeA),
- resp: resp,
+ resp: dnsmsg.Clone(defaultResp),
wantName: "000000" + httpsDomain,
wantAns: nil,
}, {
@@ -224,6 +80,8 @@ func TestPreUpstreamMwHandler_ServeDNS_androidMetric(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
handler := dnsserver.HandlerFunc(func(
ctx context.Context,
rw dnsserver.ResponseWriter,
diff --git a/internal/dnssvc/internal/ratelimitmw/access_test.go b/internal/dnssvc/internal/ratelimitmw/access_test.go
index 5d7c248..51b5656 100644
--- a/internal/dnssvc/internal/ratelimitmw/access_test.go
+++ b/internal/dnssvc/internal/ratelimitmw/access_test.go
@@ -18,7 +18,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/logutil/slogutil"
- "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
@@ -56,16 +55,9 @@ func TestMiddleware_Wrap_access(t *testing.T) {
)
require.NoError(t, errAccess)
- geoIP := &agdtest.GeoIP{
- OnSubnetByLocation: func(
- _ *geoip.Location,
- _ netutil.AddrFamily,
- ) (n netip.Prefix, err error) {
- panic("not implemented")
- },
- OnData: func(_ string, _ netip.Addr) (l *geoip.Location, err error) {
- return nil, nil
- },
+ geoIP := agdtest.NewGeoIP()
+ geoIP.OnData = func(_ string, _ netip.Addr) (l *geoip.Location, err error) {
+ return nil, nil
}
rlMw := ratelimitmw.New(&ratelimitmw.Config{
@@ -77,7 +69,8 @@ func TestMiddleware_Wrap_access(t *testing.T) {
// Use a DoT server to prevent ratelimiting.
Protocol: agd.ProtoDoT,
},
- AccessManager: accessMgr,
+ StructuredErrors: agdtest.NewSDEConfig(true),
+ AccessManager: accessMgr,
DeviceFinder: &agdtest.DeviceFinder{
OnFind: func(_ context.Context, _ *dns.Msg, _, _ netip.AddrPort) (r agd.DeviceResult) {
return nil
@@ -86,21 +79,11 @@ func TestMiddleware_Wrap_access(t *testing.T) {
ErrColl: agdtest.NewErrorCollector(),
GeoIP: geoIP,
Metrics: ratelimitmw.EmptyMetrics{},
- Limiter: &agdtest.RateLimit{
- OnIsRateLimited: func(
- _ context.Context,
- _ *dns.Msg,
- _ netip.Addr,
- ) (shouldDrop, isAllowlisted bool, err error) {
- panic("not implemented")
- },
- OnCountResponses: func(_ context.Context, _ *dns.Msg, _ netip.Addr) {
- panic("not implemented")
- },
- },
+ Limiter: agdtest.NewRateLimit(),
Protocols: []agd.Protocol{
agd.ProtoDNS,
},
+ EDEEnabled: true,
})
testCases := []struct {
diff --git a/internal/dnssvc/internal/ratelimitmw/ratelimitmw.go b/internal/dnssvc/internal/ratelimitmw/ratelimitmw.go
index 16efd7f..338dfad 100644
--- a/internal/dnssvc/internal/ratelimitmw/ratelimitmw.go
+++ b/internal/dnssvc/internal/ratelimitmw/ratelimitmw.go
@@ -34,6 +34,7 @@ type Middleware struct {
logger *slog.Logger
messages *dnsmsg.Constructor
pool *syncutil.Pool[agd.RequestInfo]
+ sdeConf *dnsmsg.StructuredDNSErrorsConfig
accessManager access.Interface
deviceFinder agd.DeviceFinder
errColl errcoll.Interface
@@ -41,6 +42,7 @@ type Middleware struct {
limiter ratelimit.Interface
metrics Metrics
protos []dnsserver.Protocol
+ edeEnabled bool
}
// Config is the configuration structure for the access and ratelimiting
@@ -61,6 +63,10 @@ type Config struct {
// Server is the current server which serves the request.
Server *agd.Server
+ // StructuredErrors is the configuration for the experimental Structured DNS
+ // Errors feature for the profiles' message constructors.
+ StructuredErrors *dnsmsg.StructuredDNSErrorsConfig
+
// AccessManager is the global access manager.
AccessManager access.Interface
@@ -82,6 +88,10 @@ type Config struct {
// Protocols is a list of protocols this middleware applies ratelimiting
// logic to. Protocols must not be changed after calling [New].
Protocols []agd.Protocol
+
+ // EDEEnabled enables the addition of the Extended DNS Error (EDE) codes in
+ // the profiles' message constructors.
+ EDEEnabled bool
}
// New returns a new access middleware. c must not be nil.
@@ -98,6 +108,7 @@ func New(c *Config) (mw *Middleware) {
Proto: c.Server.Protocol,
}
}),
+ sdeConf: c.StructuredErrors,
accessManager: c.AccessManager,
deviceFinder: c.DeviceFinder,
errColl: c.ErrColl,
@@ -105,6 +116,7 @@ func New(c *Config) (mw *Middleware) {
limiter: c.Limiter,
metrics: c.Metrics,
protos: c.Protocols,
+ edeEnabled: c.EDEEnabled,
}
}
@@ -172,7 +184,8 @@ func (mw *Middleware) processLocationErr(
// We've got a bad ECS option. Log and respond with a FORMERR immediately.
optslog.Debug1(ctx, mw.logger, "ecs error", slogutil.KeyError, origErr)
- writeErr := rw.WriteMsg(ctx, req, mw.messages.NewMsgFORMERR(req))
+ resp := mw.messages.NewRespRCode(req, dns.RcodeFormatError)
+ writeErr := rw.WriteMsg(ctx, req, resp)
writeErr = errors.Annotate(writeErr, "writing formerr resp: %w")
return errors.WithDeferred(origErr, writeErr)
diff --git a/internal/dnssvc/internal/ratelimitmw/requestinfo.go b/internal/dnssvc/internal/ratelimitmw/requestinfo.go
index bf4b330..7e6df09 100644
--- a/internal/dnssvc/internal/ratelimitmw/requestinfo.go
+++ b/internal/dnssvc/internal/ratelimitmw/requestinfo.go
@@ -56,7 +56,9 @@ func (mw *Middleware) newRequestInfo(
messages, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
Cloner: cloner,
BlockingMode: p.BlockingMode,
+ StructuredErrors: mw.sdeConf,
FilteredResponseTTL: p.FilteredResponseTTL,
+ EDEEnabled: mw.edeEnabled,
})
if err != nil {
err = fmt.Errorf("creating constructor for profile %q: %w", p.ID, err)
diff --git a/internal/dnssvc/reexport.go b/internal/dnssvc/reexport.go
new file mode 100644
index 0000000..7e3ca11
--- /dev/null
+++ b/internal/dnssvc/reexport.go
@@ -0,0 +1,16 @@
+package dnssvc
+
+import (
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/mainmw"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/ratelimitmw"
+)
+
+type (
+ // MainMiddlewareMetrics is a re-export of the internal filtering-middleware
+ // metrics interface.
+ MainMiddlewareMetrics = mainmw.Metrics
+
+ // RatelimitMiddlewareMetrics is a re-export of the metrics interface of the
+ // internal access and ratelimiting middleware.
+ RatelimitMiddlewareMetrics = ratelimitmw.Metrics
+)
diff --git a/internal/ecscache/cache.go b/internal/ecscache/cache.go
index fa3b915..08ed43c 100644
--- a/internal/ecscache/cache.go
+++ b/internal/ecscache/cache.go
@@ -1,6 +1,7 @@
package ecscache
import (
+ "context"
"encoding/binary"
"hash/maphash"
"net/netip"
@@ -8,7 +9,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
- "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
+ "github.com/AdguardTeam/AdGuardDNS/internal/optslog"
"github.com/AdguardTeam/golibs/mathutil"
"github.com/miekg/dns"
)
@@ -43,9 +44,13 @@ type cacheRequest struct {
// there is one. If the host was found in the cache for domain names that
// support ECS, isECSDependent is true. cr, cr.req, and cr.subnet must not be
// nil.
-func (mw *Middleware) get(req *dns.Msg, cr *cacheRequest) (resp *dns.Msg, isECSDependent bool) {
+func (mw *Middleware) get(
+ ctx context.Context,
+ req *dns.Msg,
+ cr *cacheRequest,
+) (resp *dns.Msg, isECSDependent bool) {
key := mw.toCacheKey(cr, false)
- item, ok := itemFromCache(mw.cache, key, cr)
+ item, ok := mw.itemFromCache(ctx, mw.cache, key, cr)
if ok {
return fromCacheItem(item, mw.cloner, req, cr.reqDO), false
} else if cr.isECSDeclined {
@@ -54,7 +59,7 @@ func (mw *Middleware) get(req *dns.Msg, cr *cacheRequest) (resp *dns.Msg, isECSD
// Try ECS-aware cache.
key = mw.toCacheKey(cr, true)
- item, ok = itemFromCache(mw.ecsCache, key, cr)
+ item, ok = mw.itemFromCache(ctx, mw.ecsCache, key, cr)
if ok {
return fromCacheItem(item, mw.cloner, req, cr.reqDO), true
}
@@ -65,7 +70,8 @@ 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(
+func (mw *Middleware) itemFromCache(
+ ctx context.Context,
cache agdcache.Interface[uint64, *cacheItem],
key uint64,
cr *cacheRequest,
@@ -77,7 +83,7 @@ func itemFromCache(
// Check for cache key collisions.
if item.host != cr.host {
- optlog.Error2("ecs-cache: collision: bad cache item %v for host %q", item, cr.host)
+ optslog.Warn2(ctx, mw.logger, "cache collision", "item", item, "host", cr.host)
return nil, false
}
@@ -136,7 +142,7 @@ func (mw *Middleware) set(resp *dns.Msg, cr *cacheRequest, respIsECSDependent bo
}
exp := time.Duration(ttl) * time.Second
- if mw.useTTLOverride && resp.Rcode != dns.RcodeServerFailure {
+ if mw.overrideTTL && resp.Rcode != dns.RcodeServerFailure {
exp = max(exp, mw.cacheMinTTL)
dnsmsg.SetMinTTL(resp, uint32(exp.Seconds()))
}
diff --git a/internal/ecscache/cache_internal_test.go b/internal/ecscache/cache_internal_test.go
index de0e754..2084b07 100644
--- a/internal/ecscache/cache_internal_test.go
+++ b/internal/ecscache/cache_internal_test.go
@@ -1,6 +1,7 @@
package ecscache
import (
+ "context"
"net/netip"
"testing"
@@ -35,9 +36,11 @@ func BenchmarkMiddleware_Get(b *testing.B) {
reqDO: true,
}
+ ctx := context.Background()
+
b.ReportAllocs()
b.ResetTimer()
for range b.N {
- msgSink, _ = mw.get(req, cr)
+ msgSink, _ = mw.get(ctx, req, cr)
}
}
diff --git a/internal/ecscache/ecsblocklist.go b/internal/ecscache/ecsblocklist.go
index b3ff467..7f0e84f 100644
--- a/internal/ecscache/ecsblocklist.go
+++ b/internal/ecscache/ecsblocklist.go
@@ -10,12 +10,13 @@ var FakeECSFQDNs = container.NewMapSet(
"0231034e888a4837a17fd85b1ab159.ba.tenant.api.powerplatform.com.",
"0272ac85-5199-4024-a555-397c3d825d95.prmutv.co.",
"0b732edd-087f-4c27-b0f6-5ff26d96cdf6.prmutv.co.",
- "0bb8856ba8259ec33e3d-a40599a114f3a4c6d0979c3ffe0b2bf5.ssl.cf2.rackcdn.com.",
"0cf.io.",
"0cf17917-395b-4f25-91cc-db3bdd6044b0.prmutv.co.",
+ "1024tera.com.",
"1024terabox.com.",
"103.chtsite.com.",
"11-alarm-mop.meshare.com.",
+ "11222.cn.",
"12-alarm-mop.meshare.com.",
"126.com.",
"126.net.",
@@ -26,11 +27,11 @@ var FakeECSFQDNs = container.NewMapSet(
"163jiasu.com.",
"163yun.com.",
"1688.com.",
- "173bf105.akstat.io.",
+ "173bf104.akstat.io.",
+ "173bf10f.akstat.io.",
"18ea70d2d9a945cfb97d818ba71817dc.pacloudflare.com.",
"2.401402081.west-gcloud.codm.activision.com.",
"2.realtime.services.box.net.",
- "201205igp.gameloft.com.",
"2acdb9b66bb242618283aadb21ede6c1.pacloudflare.com.",
"2e4b93d1-a8ae-4a89-8885-6109135ac0de.prmutv.co.",
"2owo1y.n0qq3z.com.",
@@ -42,7 +43,12 @@ var FakeECSFQDNs = container.NewMapSet(
"4.401402081.west-gcloud.codm.activision.com.",
"4.adsco.re.",
"401402081.west-gcloud.codm.activision.com.",
+ "404.playrix.com.",
"4186979c18134d1eae82ec64dbfc9af2.pacloudflare.com.",
+ "41ku.cn.",
+ "46799.apps.zdusercontent.com.",
+ "46a2e5c3c5a64e218b60f2c2ee76b750.pacloudflare.com.",
+ "481528.com.",
"4b32bb64ce554875ae3f8836479c89d4.pacloudflare.com.",
"507b28fb-2ef1-4c34-8bda-ba32030bb199.prmutv.co.",
"520.jp.",
@@ -50,9 +56,8 @@ var FakeECSFQDNs = container.NewMapSet(
"5nines.com.",
"6.401402081.west-gcloud.codm.activision.com.",
"6093eccf-6734-4877-ac8b-83d6d0e27b46.prmutv.co.",
- "6c3e19e3-d05e-45d1-8f79-fcd6cb2f3a21.prmutv.co.",
+ "66yahoo.com.",
"733868e706dd40d3a4a0588fc39b3df8.pacloudflare.com.",
- "79423.analytics.edgekey.net.",
"7c7b02d4bc3d48dd81a7c7738d4de1ab.pacloudflare.com.",
"82fff5ef370dea21b562bafc3aa751.85.environment.api.powerplatform.com.",
"88a66e5c-8fe8-48af-9c6c-3ec3f4983aad.prmutv.co.",
@@ -62,152 +67,14 @@ var FakeECSFQDNs = container.NewMapSet(
"a-api.anthropic.com.",
"a-cdn.anthropic.com.",
"a-m-p.xyz.",
+ "a.ad.gt.cdn.cloudflare.net.",
"a.getepic.com.",
+ "a.klaviyo.com.cdn.cloudflare.net.",
"a.nel.cloudflare.com.",
"a.nitropay.com.",
- "a.poki.com.",
- "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.",
- "a039.casalemedia.com.",
- "a040.casalemedia.com.",
- "a041.casalemedia.com.",
- "a043.casalemedia.com.",
- "a044.casalemedia.com.",
- "a046.casalemedia.com.",
- "a049.casalemedia.com.",
- "a050.casalemedia.com.",
- "a054.casalemedia.com.",
- "a058.casalemedia.com.",
- "a074.casalemedia.com.",
- "a075.casalemedia.com.",
- "a077.casalemedia.com.",
- "a084.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.",
- "a108.casalemedia.com.",
- "a119.casalemedia.com.",
- "a121.casalemedia.com.",
- "a123.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.",
- "a139.casalemedia.com.",
- "a140.casalemedia.com.",
- "a141.casalemedia.com.",
- "a143.casalemedia.com.",
- "a144.casalemedia.com.",
- "a145.casalemedia.com.",
- "a146.casalemedia.com.",
- "a1463.casalemedia.com.",
- "a1469.casalemedia.com.",
- "a147.casalemedia.com.",
- "a1472.casalemedia.com.",
- "a1478.casalemedia.com.",
- "a149.casalemedia.com.",
- "a1490.casalemedia.com.",
- "a1496.casalemedia.com.",
- "a1497.casalemedia.com.",
- "a150.casalemedia.com.",
- "a1506.casalemedia.com.",
- "a151.casalemedia.com.",
- "a152.casalemedia.com.",
- "a1523.casalemedia.com.",
- "a1524.casalemedia.com.",
- "a1525.casalemedia.com.",
- "a153.casalemedia.com.",
- "a1530.casalemedia.com.",
- "a1541.casalemedia.com.",
- "a1542.casalemedia.com.",
- "a1550.casalemedia.com.",
- "a156.casalemedia.com.",
- "a157.casalemedia.com.",
- "a1575.casalemedia.com.",
- "a1579.casalemedia.com.",
- "a158.casalemedia.com.",
- "a1585.casalemedia.com.",
- "a159.casalemedia.com.",
- "a1591.casalemedia.com.",
- "a1594.casalemedia.com.",
- "a1598.casalemedia.com.",
- "a160.casalemedia.com.",
- "a1602.casalemedia.com.",
- "a1605.casalemedia.com.",
- "a161.casalemedia.com.",
- "a1617.casalemedia.com.",
- "a1623.casalemedia.com.",
- "a1629.casalemedia.com.",
- "a1631.casalemedia.com.",
- "a1635.casalemedia.com.",
- "a1637.casalemedia.com.",
- "a1641.casalemedia.com.",
- "a1651.casalemedia.com.",
- "a1656.casalemedia.com.",
- "a1658.casalemedia.com.",
- "a166.casalemedia.com.",
- "a1665.casalemedia.com.",
- "a1667.casalemedia.com.",
- "a1669.casalemedia.com.",
- "a1670.casalemedia.com.",
- "a1681.casalemedia.com.",
- "a1682.casalemedia.com.",
- "a1683.casalemedia.com.",
- "a1687.casalemedia.com.",
- "a1689.casalemedia.com.",
- "a169.casalemedia.com.",
- "a1691.casalemedia.com.",
- "a1695.casalemedia.com.",
- "a1698.casalemedia.com.",
- "a1700.casalemedia.com.",
- "a172.casalemedia.com.",
- "a177.casalemedia.com.",
- "a178.casalemedia.com.",
- "a179.casalemedia.com.",
- "a182.casalemedia.com.",
- "a187.casalemedia.com.",
- "a189.casalemedia.com.",
- "a190.casalemedia.com.",
- "a195.casalemedia.com.",
- "a200.casalemedia.com.",
- "a201.casalemedia.com.",
- "a21006071257.cdn.optimizely.com.",
+ "a.researchgate.net.",
+ "a.vsstatic.com.",
+ "a19558781057.cdn.optimizely.com.",
"a2321.casalemedia.com.",
"a2322.casalemedia.com.",
"a2323.casalemedia.com.",
@@ -224,19 +91,19 @@ var FakeECSFQDNs = container.NewMapSet(
"a2334.casalemedia.com.",
"a2335.casalemedia.com.",
"a2336.casalemedia.com.",
- "a2337.casalemedia.com.",
"a2338.casalemedia.com.",
"a2339.casalemedia.com.",
- "a2340.casalemedia.com.",
"a2341.casalemedia.com.",
"a2342.casalemedia.com.",
"a2344.casalemedia.com.",
"a2345.casalemedia.com.",
- "a2346.casalemedia.com.",
+ "a2347.casalemedia.com.",
"a2348.casalemedia.com.",
+ "a2349.casalemedia.com.",
"a2350.casalemedia.com.",
"a2351.casalemedia.com.",
"a2352.casalemedia.com.",
+ "a2353.casalemedia.com.",
"a2354.casalemedia.com.",
"a2355.casalemedia.com.",
"a2356.casalemedia.com.",
@@ -264,11 +131,11 @@ var FakeECSFQDNs = container.NewMapSet(
"a2378.casalemedia.com.",
"a2379.casalemedia.com.",
"a2380.casalemedia.com.",
- "a2381.casalemedia.com.",
"a2382.casalemedia.com.",
"a2383.casalemedia.com.",
"a2384.casalemedia.com.",
"a2385.casalemedia.com.",
+ "a2386.casalemedia.com.",
"a2387.casalemedia.com.",
"a2388.casalemedia.com.",
"a2389.casalemedia.com.",
@@ -277,6 +144,7 @@ var FakeECSFQDNs = container.NewMapSet(
"a2392.casalemedia.com.",
"a2393.casalemedia.com.",
"a2394.casalemedia.com.",
+ "a2395.casalemedia.com.",
"a2396.casalemedia.com.",
"a2397.casalemedia.com.",
"a2398.casalemedia.com.",
@@ -285,15 +153,19 @@ var FakeECSFQDNs = container.NewMapSet(
"a2401.casalemedia.com.",
"a2402.casalemedia.com.",
"a2403.casalemedia.com.",
+ "a2404.casalemedia.com.",
"a2405.casalemedia.com.",
"a2406.casalemedia.com.",
- "a2407.casalemedia.com.",
"a2408.casalemedia.com.",
+ "a2409.casalemedia.com.",
+ "a2410.casalemedia.com.",
"a2411.casalemedia.com.",
+ "a2412.casalemedia.com.",
"a2413.casalemedia.com.",
"a2414.casalemedia.com.",
"a2415.casalemedia.com.",
"a2416.casalemedia.com.",
+ "a2417.casalemedia.com.",
"a2418.casalemedia.com.",
"a2419.casalemedia.com.",
"a2420.casalemedia.com.",
@@ -302,15 +174,16 @@ var FakeECSFQDNs = container.NewMapSet(
"a2423.casalemedia.com.",
"a2424.casalemedia.com.",
"a2425.casalemedia.com.",
+ "a2426.casalemedia.com.",
"a2427.casalemedia.com.",
"a2428.casalemedia.com.",
"a2429.casalemedia.com.",
+ "a2430.casalemedia.com.",
"a2431.casalemedia.com.",
"a2432.casalemedia.com.",
"a2433.casalemedia.com.",
"a2434.casalemedia.com.",
"a2435.casalemedia.com.",
- "a2436.casalemedia.com.",
"a2437.casalemedia.com.",
"a2438.casalemedia.com.",
"a2439.casalemedia.com.",
@@ -318,6 +191,7 @@ var FakeECSFQDNs = container.NewMapSet(
"a2441.casalemedia.com.",
"a2442.casalemedia.com.",
"a2443.casalemedia.com.",
+ "a2444.casalemedia.com.",
"a2445.casalemedia.com.",
"a2446.casalemedia.com.",
"a2447.casalemedia.com.",
@@ -326,18 +200,17 @@ var FakeECSFQDNs = container.NewMapSet(
"a2450.casalemedia.com.",
"a2451.casalemedia.com.",
"a2452.casalemedia.com.",
+ "a2453.casalemedia.com.",
"a2454.casalemedia.com.",
"a2455.casalemedia.com.",
"a2456.casalemedia.com.",
"a2457.casalemedia.com.",
- "a2458.casalemedia.com.",
+ "a2459.casalemedia.com.",
"a2460.casalemedia.com.",
"a2461.casalemedia.com.",
"a2462.casalemedia.com.",
- "a2463.casalemedia.com.",
"a2464.casalemedia.com.",
"a2465.casalemedia.com.",
- "a2466.casalemedia.com.",
"a2467.casalemedia.com.",
"a2468.casalemedia.com.",
"a2469.casalemedia.com.",
@@ -355,7 +228,6 @@ var FakeECSFQDNs = container.NewMapSet(
"a2481.casalemedia.com.",
"a2482.casalemedia.com.",
"a2483.casalemedia.com.",
- "a2484.casalemedia.com.",
"a2485.casalemedia.com.",
"a2486.casalemedia.com.",
"a2487.casalemedia.com.",
@@ -367,7 +239,6 @@ var FakeECSFQDNs = container.NewMapSet(
"a2494.casalemedia.com.",
"a2495.casalemedia.com.",
"a2496.casalemedia.com.",
- "a2497.casalemedia.com.",
"a2498.casalemedia.com.",
"a2499.casalemedia.com.",
"a2500.casalemedia.com.",
@@ -377,7 +248,6 @@ var FakeECSFQDNs = container.NewMapSet(
"a2504.casalemedia.com.",
"a2505.casalemedia.com.",
"a2506.casalemedia.com.",
- "a2507.casalemedia.com.",
"a2508.casalemedia.com.",
"a2509.casalemedia.com.",
"a2510.casalemedia.com.",
@@ -388,87 +258,300 @@ var FakeECSFQDNs = container.NewMapSet(
"a2515.casalemedia.com.",
"a2516.casalemedia.com.",
"a2517.casalemedia.com.",
+ "a2518.casalemedia.com.",
"a2519.casalemedia.com.",
- "a252.casalemedia.com.",
"a2520.casalemedia.com.",
"a2521.casalemedia.com.",
- "a2522.casalemedia.com.",
"a2523.casalemedia.com.",
"a2524.casalemedia.com.",
"a2525.casalemedia.com.",
"a2526.casalemedia.com.",
"a2527.casalemedia.com.",
"a2528.casalemedia.com.",
- "a254.casalemedia.com.",
- "a255.casalemedia.com.",
- "a260.casalemedia.com.",
- "a2801.casalemedia.com.",
- "a2802.casalemedia.com.",
- "a2806.casalemedia.com.",
- "a2811.casalemedia.com.",
- "a2829.casalemedia.com.",
- "a2832.casalemedia.com.",
- "a2834.casalemedia.com.",
- "a2842.casalemedia.com.",
- "a2844.casalemedia.com.",
- "a2848.casalemedia.com.",
- "a2851.casalemedia.com.",
- "a2870.casalemedia.com.",
- "a2877.casalemedia.com.",
- "a2878.casalemedia.com.",
- "a2880.casalemedia.com.",
- "a2882.casalemedia.com.",
- "a2890.casalemedia.com.",
- "a2891.casalemedia.com.",
- "a2897.casalemedia.com.",
- "a2900.casalemedia.com.",
- "a2902.casalemedia.com.",
- "a2904.casalemedia.com.",
- "a2905.casalemedia.com.",
- "a2912.casalemedia.com.",
- "a2918.casalemedia.com.",
- "a2920.casalemedia.com.",
- "a2933.casalemedia.com.",
- "a2934.casalemedia.com.",
- "a2938.casalemedia.com.",
- "a2949.casalemedia.com.",
+ "a2529.casalemedia.com.",
+ "a25758810713.cdn.optimizely.com.",
+ "a2681.casalemedia.com.",
+ "a2682.casalemedia.com.",
+ "a2683.casalemedia.com.",
+ "a2684.casalemedia.com.",
+ "a2685.casalemedia.com.",
+ "a2686.casalemedia.com.",
+ "a2689.casalemedia.com.",
+ "a2690.casalemedia.com.",
+ "a2691.casalemedia.com.",
+ "a2692.casalemedia.com.",
+ "a2693.casalemedia.com.",
+ "a2694.casalemedia.com.",
+ "a2695.casalemedia.com.",
+ "a2696.casalemedia.com.",
+ "a2697.casalemedia.com.",
+ "a2698.casalemedia.com.",
+ "a2699.casalemedia.com.",
+ "a2700.casalemedia.com.",
+ "a2701.casalemedia.com.",
+ "a2702.casalemedia.com.",
+ "a2703.casalemedia.com.",
+ "a2704.casalemedia.com.",
+ "a2705.casalemedia.com.",
+ "a2706.casalemedia.com.",
+ "a2707.casalemedia.com.",
+ "a2708.casalemedia.com.",
+ "a2709.casalemedia.com.",
+ "a2710.casalemedia.com.",
+ "a2711.casalemedia.com.",
+ "a2712.casalemedia.com.",
+ "a2713.casalemedia.com.",
+ "a2714.casalemedia.com.",
+ "a2715.casalemedia.com.",
+ "a2717.casalemedia.com.",
+ "a2719.casalemedia.com.",
+ "a2720.casalemedia.com.",
+ "a2721.casalemedia.com.",
+ "a2722.casalemedia.com.",
+ "a2723.casalemedia.com.",
+ "a2724.casalemedia.com.",
+ "a2725.casalemedia.com.",
+ "a2726.casalemedia.com.",
+ "a2727.casalemedia.com.",
+ "a2728.casalemedia.com.",
+ "a2729.casalemedia.com.",
+ "a2730.casalemedia.com.",
+ "a2731.casalemedia.com.",
+ "a2732.casalemedia.com.",
+ "a2733.casalemedia.com.",
+ "a2734.casalemedia.com.",
+ "a2736.casalemedia.com.",
+ "a2737.casalemedia.com.",
+ "a2738.casalemedia.com.",
+ "a2739.casalemedia.com.",
+ "a2741.casalemedia.com.",
+ "a2742.casalemedia.com.",
+ "a2743.casalemedia.com.",
+ "a2744.casalemedia.com.",
+ "a2745.casalemedia.com.",
+ "a2746.casalemedia.com.",
+ "a2747.casalemedia.com.",
+ "a2748.casalemedia.com.",
+ "a2749.casalemedia.com.",
+ "a2750.casalemedia.com.",
+ "a2751.casalemedia.com.",
+ "a2752.casalemedia.com.",
+ "a2753.casalemedia.com.",
+ "a2754.casalemedia.com.",
+ "a2755.casalemedia.com.",
+ "a2756.casalemedia.com.",
+ "a2757.casalemedia.com.",
+ "a2758.casalemedia.com.",
+ "a2759.casalemedia.com.",
+ "a2760.casalemedia.com.",
+ "a2761.casalemedia.com.",
+ "a2762.casalemedia.com.",
+ "a2763.casalemedia.com.",
+ "a2764.casalemedia.com.",
+ "a2765.casalemedia.com.",
+ "a2766.casalemedia.com.",
+ "a2767.casalemedia.com.",
+ "a2768.casalemedia.com.",
+ "a2769.casalemedia.com.",
+ "a2770.casalemedia.com.",
+ "a2771.casalemedia.com.",
+ "a2772.casalemedia.com.",
+ "a2773.casalemedia.com.",
+ "a2774.casalemedia.com.",
+ "a2776.casalemedia.com.",
+ "a2777.casalemedia.com.",
+ "a2778.casalemedia.com.",
+ "a2779.casalemedia.com.",
+ "a2780.casalemedia.com.",
+ "a2781.casalemedia.com.",
+ "a2782.casalemedia.com.",
+ "a2783.casalemedia.com.",
+ "a2784.casalemedia.com.",
+ "a2785.casalemedia.com.",
+ "a2786.casalemedia.com.",
+ "a2787.casalemedia.com.",
+ "a2788.casalemedia.com.",
+ "a2790.casalemedia.com.",
+ "a2791.casalemedia.com.",
+ "a2793.casalemedia.com.",
+ "a2794.casalemedia.com.",
+ "a2795.casalemedia.com.",
+ "a2796.casalemedia.com.",
+ "a2797.casalemedia.com.",
+ "a2798.casalemedia.com.",
+ "a2799.casalemedia.com.",
+ "a2800.casalemedia.com.",
"a2a5c7f9-3fa0-4182-889a-15aa61acf59b.prmutv.co.",
"a3.tuyacn.com.",
- "a364.casalemedia.com.",
- "a367.casalemedia.com.",
- "a375.casalemedia.com.",
- "a376.casalemedia.com.",
- "a377.casalemedia.com.",
- "a381.casalemedia.com.",
- "a385.casalemedia.com.",
- "a390.casalemedia.com.",
- "a398.casalemedia.com.",
- "a401.casalemedia.com.",
- "a407.casalemedia.com.",
- "a408.casalemedia.com.",
- "a412.casalemedia.com.",
- "a415.casalemedia.com.",
- "a417.casalemedia.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.",
- "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.",
+ "a3551.casalemedia.com.",
+ "a3552.casalemedia.com.",
+ "a3553.casalemedia.com.",
+ "a3554.casalemedia.com.",
+ "a3555.casalemedia.com.",
+ "a3556.casalemedia.com.",
+ "a3557.casalemedia.com.",
+ "a3558.casalemedia.com.",
+ "a3559.casalemedia.com.",
+ "a3560.casalemedia.com.",
+ "a3562.casalemedia.com.",
+ "a3563.casalemedia.com.",
+ "a3564.casalemedia.com.",
+ "a3565.casalemedia.com.",
+ "a3566.casalemedia.com.",
+ "a3567.casalemedia.com.",
+ "a3568.casalemedia.com.",
+ "a3569.casalemedia.com.",
+ "a3570.casalemedia.com.",
+ "a3571.casalemedia.com.",
+ "a3572.casalemedia.com.",
+ "a3573.casalemedia.com.",
+ "a3574.casalemedia.com.",
+ "a3575.casalemedia.com.",
+ "a3578.casalemedia.com.",
+ "a3579.casalemedia.com.",
+ "a3580.casalemedia.com.",
+ "a3581.casalemedia.com.",
+ "a3582.casalemedia.com.",
+ "a3583.casalemedia.com.",
+ "a3584.casalemedia.com.",
+ "a3585.casalemedia.com.",
+ "a3586.casalemedia.com.",
+ "a3587.casalemedia.com.",
+ "a3589.casalemedia.com.",
+ "a3590.casalemedia.com.",
+ "a3591.casalemedia.com.",
+ "a3592.casalemedia.com.",
+ "a3593.casalemedia.com.",
+ "a3594.casalemedia.com.",
+ "a3595.casalemedia.com.",
+ "a3596.casalemedia.com.",
+ "a3597.casalemedia.com.",
+ "a3598.casalemedia.com.",
+ "a3599.casalemedia.com.",
+ "a3600.casalemedia.com.",
+ "a3601.casalemedia.com.",
+ "a3602.casalemedia.com.",
+ "a3603.casalemedia.com.",
+ "a3604.casalemedia.com.",
+ "a3605.casalemedia.com.",
+ "a3606.casalemedia.com.",
+ "a3607.casalemedia.com.",
+ "a3608.casalemedia.com.",
+ "a3609.casalemedia.com.",
+ "a3610.casalemedia.com.",
+ "a3611.casalemedia.com.",
+ "a3612.casalemedia.com.",
+ "a3613.casalemedia.com.",
+ "a3614.casalemedia.com.",
+ "a3615.casalemedia.com.",
+ "a3616.casalemedia.com.",
+ "a3617.casalemedia.com.",
+ "a3618.casalemedia.com.",
+ "a3619.casalemedia.com.",
+ "a3620.casalemedia.com.",
+ "a3621.casalemedia.com.",
+ "a3622.casalemedia.com.",
+ "a3623.casalemedia.com.",
+ "a3624.casalemedia.com.",
+ "a3625.casalemedia.com.",
+ "a3626.casalemedia.com.",
+ "a3627.casalemedia.com.",
+ "a3628.casalemedia.com.",
+ "a3629.casalemedia.com.",
+ "a3630.casalemedia.com.",
+ "a3631.casalemedia.com.",
+ "a3632.casalemedia.com.",
+ "a3633.casalemedia.com.",
+ "a3634.casalemedia.com.",
+ "a3635.casalemedia.com.",
+ "a3636.casalemedia.com.",
+ "a3637.casalemedia.com.",
+ "a3638.casalemedia.com.",
+ "a3639.casalemedia.com.",
+ "a3640.casalemedia.com.",
+ "a3641.casalemedia.com.",
+ "a3642.casalemedia.com.",
+ "a3644.casalemedia.com.",
+ "a3645.casalemedia.com.",
+ "a3646.casalemedia.com.",
+ "a3647.casalemedia.com.",
+ "a3648.casalemedia.com.",
+ "a3649.casalemedia.com.",
+ "a3650.casalemedia.com.",
+ "a3651.casalemedia.com.",
+ "a3652.casalemedia.com.",
+ "a3653.casalemedia.com.",
+ "a3654.casalemedia.com.",
+ "a3656.casalemedia.com.",
+ "a3657.casalemedia.com.",
+ "a3658.casalemedia.com.",
+ "a3659.casalemedia.com.",
+ "a3660.casalemedia.com.",
+ "a3661.casalemedia.com.",
+ "a3662.casalemedia.com.",
+ "a3663.casalemedia.com.",
+ "a3664.casalemedia.com.",
+ "a3666.casalemedia.com.",
+ "a3667.casalemedia.com.",
+ "a3668.casalemedia.com.",
+ "a3669.casalemedia.com.",
+ "a3670.casalemedia.com.",
+ "a3671.casalemedia.com.",
+ "a3672.casalemedia.com.",
+ "a3673.casalemedia.com.",
+ "a3675.casalemedia.com.",
+ "a3676.casalemedia.com.",
+ "a3677.casalemedia.com.",
+ "a3678.casalemedia.com.",
+ "a3679.casalemedia.com.",
+ "a3680.casalemedia.com.",
+ "a3681.casalemedia.com.",
+ "a3683.casalemedia.com.",
+ "a3684.casalemedia.com.",
+ "a3685.casalemedia.com.",
+ "a3686.casalemedia.com.",
+ "a3687.casalemedia.com.",
+ "a3688.casalemedia.com.",
+ "a3689.casalemedia.com.",
+ "a3690.casalemedia.com.",
+ "a3691.casalemedia.com.",
+ "a3692.casalemedia.com.",
+ "a3693.casalemedia.com.",
+ "a3694.casalemedia.com.",
+ "a3695.casalemedia.com.",
+ "a3696.casalemedia.com.",
+ "a3698.casalemedia.com.",
+ "a3699.casalemedia.com.",
+ "a3700.casalemedia.com.",
+ "a3702.casalemedia.com.",
+ "a3703.casalemedia.com.",
+ "a3704.casalemedia.com.",
+ "a3705.casalemedia.com.",
+ "a3706.casalemedia.com.",
+ "a3707.casalemedia.com.",
+ "a3708.casalemedia.com.",
+ "a3709.casalemedia.com.",
+ "a3710.casalemedia.com.",
+ "a3711.casalemedia.com.",
+ "a3712.casalemedia.com.",
+ "a3713.casalemedia.com.",
+ "a3714.casalemedia.com.",
+ "a3715.casalemedia.com.",
+ "a3716.casalemedia.com.",
+ "a3717.casalemedia.com.",
+ "a3718.casalemedia.com.",
+ "a3719.casalemedia.com.",
+ "a3720.casalemedia.com.",
+ "a3721.casalemedia.com.",
+ "a3722.casalemedia.com.",
+ "a3723.casalemedia.com.",
+ "a3724.casalemedia.com.",
+ "a3725.casalemedia.com.",
+ "a3726.casalemedia.com.",
+ "a3727.casalemedia.com.",
+ "a3728.casalemedia.com.",
+ "a3729.casalemedia.com.",
+ "a3730.casalemedia.com.",
"a5551.casalemedia.com.",
"a5555.casalemedia.com.",
"a5556.casalemedia.com.",
@@ -488,14 +571,12 @@ var FakeECSFQDNs = container.NewMapSet(
"a5570.casalemedia.com.",
"a5571.casalemedia.com.",
"a5572.casalemedia.com.",
- "a5574.casalemedia.com.",
+ "a5573.casalemedia.com.",
"a5575.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.",
@@ -505,13 +586,11 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -528,7 +607,7 @@ var FakeECSFQDNs = container.NewMapSet(
"a5611.casalemedia.com.",
"a5612.casalemedia.com.",
"a5613.casalemedia.com.",
- "a5615.casalemedia.com.",
+ "a5614.casalemedia.com.",
"a5616.casalemedia.com.",
"a5617.casalemedia.com.",
"a5618.casalemedia.com.",
@@ -540,48 +619,19 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
- "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.",
- "a5658.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.",
"a5671.casalemedia.com.",
"a5672.casalemedia.com.",
"a5673.casalemedia.com.",
@@ -591,20 +641,21 @@ var FakeECSFQDNs = container.NewMapSet(
"a5677.casalemedia.com.",
"a5678.casalemedia.com.",
"a5679.casalemedia.com.",
- "a568.casalemedia.com.",
+ "a5680.casalemedia.com.",
"a5681.casalemedia.com.",
+ "a5682.casalemedia.com.",
"a5683.casalemedia.com.",
"a5684.casalemedia.com.",
+ "a5685.casalemedia.com.",
"a5686.casalemedia.com.",
"a5687.casalemedia.com.",
+ "a5688.casalemedia.com.",
"a5689.casalemedia.com.",
- "a569.casalemedia.com.",
"a5690.casalemedia.com.",
"a5691.casalemedia.com.",
"a5692.casalemedia.com.",
"a5693.casalemedia.com.",
"a5694.casalemedia.com.",
- "a5695.casalemedia.com.",
"a5696.casalemedia.com.",
"a5697.casalemedia.com.",
"a5698.casalemedia.com.",
@@ -616,127 +667,220 @@ var FakeECSFQDNs = container.NewMapSet(
"a5704.casalemedia.com.",
"a5705.casalemedia.com.",
"a5706.casalemedia.com.",
+ "a5707.casalemedia.com.",
"a5708.casalemedia.com.",
"a5709.casalemedia.com.",
"a5710.casalemedia.com.",
- "a576.casalemedia.com.",
"a5776.casalemedia.com.",
"a5777.casalemedia.com.",
"a5778.casalemedia.com.",
"a5779.casalemedia.com.",
- "a578.casalemedia.com.",
"a5780.casalemedia.com.",
"a5781.casalemedia.com.",
- "a5782.casalemedia.com.",
"a5783.casalemedia.com.",
"a5784.casalemedia.com.",
"a5786.casalemedia.com.",
"a5787.casalemedia.com.",
"a5788.casalemedia.com.",
"a5789.casalemedia.com.",
- "a579.casalemedia.com.",
"a5790.casalemedia.com.",
- "a5791.casalemedia.com.",
"a5792.casalemedia.com.",
"a5793.casalemedia.com.",
"a5794.casalemedia.com.",
+ "a5795.casalemedia.com.",
+ "a5796.casalemedia.com.",
"a5797.casalemedia.com.",
+ "a5798.casalemedia.com.",
"a5799.casalemedia.com.",
- "a580.casalemedia.com.",
- "a5800.casalemedia.com.",
"a5801.casalemedia.com.",
"a5802.casalemedia.com.",
- "a5803.casalemedia.com.",
"a5804.casalemedia.com.",
"a5805.casalemedia.com.",
- "a5806.casalemedia.com.",
"a5807.casalemedia.com.",
+ "a5808.casalemedia.com.",
"a5809.casalemedia.com.",
+ "a581.casalemedia.com.",
"a5810.casalemedia.com.",
- "a5811.casalemedia.com.",
"a5812.casalemedia.com.",
- "a5814.casalemedia.com.",
+ "a5813.casalemedia.com.",
"a5815.casalemedia.com.",
+ "a582.casalemedia.com.",
+ "a583.casalemedia.com.",
+ "a584.casalemedia.com.",
+ "a585.casalemedia.com.",
+ "a586.casalemedia.com.",
+ "a587.casalemedia.com.",
+ "a588.casalemedia.com.",
+ "a589.casalemedia.com.",
+ "a590.casalemedia.com.",
+ "a591.casalemedia.com.",
+ "a592.casalemedia.com.",
+ "a593.casalemedia.com.",
+ "a595.casalemedia.com.",
+ "a597.casalemedia.com.",
+ "a599.casalemedia.com.",
+ "a600.casalemedia.com.",
+ "a601.casalemedia.com.",
+ "a602.casalemedia.com.",
+ "a603.casalemedia.com.",
+ "a605.casalemedia.com.",
+ "a606.casalemedia.com.",
+ "a607.casalemedia.com.",
+ "a608.casalemedia.com.",
+ "a609.casalemedia.com.",
+ "a610.casalemedia.com.",
+ "a611.casalemedia.com.",
+ "a612.casalemedia.com.",
+ "a613.casalemedia.com.",
+ "a614.casalemedia.com.",
+ "a615.casalemedia.com.",
+ "a617.casalemedia.com.",
+ "a618.casalemedia.com.",
+ "a619.casalemedia.com.",
+ "a620.casalemedia.com.",
+ "a621.casalemedia.com.",
+ "a622.casalemedia.com.",
+ "a623.casalemedia.com.",
+ "a624.casalemedia.com.",
+ "a625.casalemedia.com.",
+ "a626.casalemedia.com.",
+ "a627.casalemedia.com.",
+ "a628.casalemedia.com.",
+ "a629.casalemedia.com.",
+ "a630.casalemedia.com.",
+ "a632.casalemedia.com.",
+ "a633.casalemedia.com.",
+ "a634.casalemedia.com.",
+ "a635.casalemedia.com.",
+ "a636.casalemedia.com.",
+ "a637.casalemedia.com.",
+ "a638.casalemedia.com.",
+ "a639.casalemedia.com.",
+ "a640.casalemedia.com.",
+ "a922.casalemedia.com.",
+ "a923.casalemedia.com.",
+ "a924.casalemedia.com.",
+ "a925.casalemedia.com.",
+ "a926.casalemedia.com.",
+ "a927.casalemedia.com.",
+ "a928.casalemedia.com.",
+ "a929.casalemedia.com.",
+ "a930.casalemedia.com.",
+ "a931.casalemedia.com.",
+ "a932.casalemedia.com.",
+ "a933.casalemedia.com.",
+ "a934.casalemedia.com.",
+ "a936.casalemedia.com.",
+ "a937.casalemedia.com.",
+ "a938.casalemedia.com.",
+ "a939.casalemedia.com.",
+ "a940.casalemedia.com.",
+ "a941.casalemedia.com.",
+ "a942.casalemedia.com.",
+ "a943.casalemedia.com.",
+ "a944.casalemedia.com.",
+ "a945.casalemedia.com.",
+ "a946.casalemedia.com.",
+ "a947.casalemedia.com.",
+ "a948.casalemedia.com.",
+ "a950.casalemedia.com.",
+ "a951.casalemedia.com.",
+ "a952.casalemedia.com.",
+ "a953.casalemedia.com.",
+ "a954.casalemedia.com.",
+ "a955.casalemedia.com.",
+ "a956.casalemedia.com.",
+ "a957.casalemedia.com.",
+ "a958.casalemedia.com.",
+ "a959.casalemedia.com.",
+ "a961.casalemedia.com.",
+ "a962.casalemedia.com.",
+ "a963.casalemedia.com.",
+ "a964.casalemedia.com.",
+ "a965.casalemedia.com.",
+ "a966.casalemedia.com.",
+ "a967.casalemedia.com.",
+ "a968.casalemedia.com.",
"a9695278-4085-40b3-9f02-8d4c38a6ff01.prmutv.co.",
+ "a970.casalemedia.com.",
+ "a971.casalemedia.com.",
+ "a972.casalemedia.com.",
+ "a973.casalemedia.com.",
+ "a974.casalemedia.com.",
+ "a975.casalemedia.com.",
+ "a977.casalemedia.com.",
+ "a979.casalemedia.com.",
+ "a980.casalemedia.com.",
"aa.online-metrix.net.",
"aa.quantummetric.com.",
"ab.qq.com.",
"aba2c424-419a-4d03-9aed-2dca8a7139e4.prmutv.co.",
- "ably-realtime.com.",
- "abm2.listenloop.com.",
"abroad.apilocate.amap.com.",
"abtest-aws-us-east-01.saas.sensorsdata.com.",
- "abtest.omiapp.me.",
- "ac.flixcart.com.",
"accela.com.",
"accentuate.io.",
"access.mp.lura.live.",
"account.box.com.",
- "account.sogou.com.",
+ "account.msa.msidentity.com.",
"accountapi.agoda.com.",
- "accounts.ikea.com.",
- "accounts.intuit.com.",
"accurint.com.",
"acdn.tinkoff.ru.",
"acgvideo.com.",
"achi.faceit.com.",
"acme-v02.api.letsencrypt.org.",
"acp.haplat.net.",
- "acpbk.haplat.net.",
"acrobits.cz.",
"acsdk.gameyw.easebar.com.",
"activate.academy.com.",
"ad1.adfarm1.adition.com.",
"ad11.adfarm1.adition.com.",
"ad11p.adfarm1.adition.com.",
- "ad13.adfarm1.adition.com.",
+ "ad2.adfarm1.adition.com.",
+ "ad3.adfarm1.adition.com.",
+ "ad4.adfarm1.adition.com.",
"adapex.io.",
"adash.man.aliyuncs.com.",
- "adashx.ut.amap.com.",
"adblock.telemetry.getadblock.com.",
"adcell.com.",
"adder.feeder.co.",
"additionfi.com.",
"adfarm1.adition.com.",
"adiam.tech.",
- "adintl.cn.",
"adition.com.",
"aditude.io.",
"adm.wsms.haplat.net.",
"admbk.wsms.haplat.net.",
"admixer.com.",
- "adobelogin-weighted-prod07.prod.ims.adobejanus.com.",
"adoric.com.",
"adrs.org.cn.",
"adsco.re.",
"adsolut.in.",
"adtarget.market.",
"adtarget.me.",
+ "adtechnacity.com.",
"advantage.purpleguys.com.",
"advantage2.purpleguys.com.",
+ "adventisthealthwest.sharepoint.com.",
"adview.com.",
+ "adx-os.bridgeoos.com.",
"adx-sg-req.anythinktech.com.",
"adxpremium.services.",
- "ae.nflximg.net.",
"aee.myisolved.com.",
"aeries.com.",
- "afd-eus2-guestagentsvc-prod.trafficmanager.net.",
"afd-lnkd.www.linkedin.com.",
"affpa.top.",
"afss.zhiqinyun.cn.",
- "agent-logos.storage.googleapis.com.",
+ "afterpay.com.",
"agent.marketingcloudfx.com.",
"ai-voice.cloudbirds.cn.",
- "aic-gfts.lge.com.",
"aicdn.com.",
"aid.send.microad.jp.",
"aidata.io.",
+ "aiq-in.caranddriver.com.",
"airasia.com.",
"airtory.com.",
"aisee.tv.",
"ajcloud.net.",
- "akinkanalang876.wixsite.com.",
- "akrdinfo.cn.",
"akulaku.com.",
"alarm.wsms.haplat.net.",
"alarmbk.wsms.haplat.net.",
@@ -753,7 +897,6 @@ var FakeECSFQDNs = container.NewMapSet(
"alive2.cloudbirds.cn.",
"alive3.cloudbirds.cn.",
"aliyuncs.com.",
- "alljoyn.org.",
"alpha1-ap-public.val.qq.com.",
"alpha1-gp-ping-cq2.val.qq.com.",
"alpha1-gp-ping-gz2.val.qq.com.",
@@ -762,8 +905,7 @@ var FakeECSFQDNs = container.NewMapSet(
"amd.com.",
"amdcopen.m.taobao.com.",
"amdcopen.m.taobao.com.gds.alibabadns.com.",
- "amp-api.videos.apple.com.",
- "amp.namequery.com.",
+ "americanexpress.com.edgekey.net.",
"amp.permutive.com.",
"amplitudelab.usemotion.com.",
"ams-itm-radar-testobject.citrix.com.",
@@ -777,32 +919,34 @@ var FakeECSFQDNs = container.NewMapSet(
"analytics.languagetoolplus.com.",
"analytics.pdf24.org.",
"analytics.qumucloud.com.",
- "analytics.talbots.com.",
"analytics.trovit.com.",
+ "analyticssystems.net.",
"android.crashsight.wetest.net.",
"anlian.co.",
"announce.torrentsmd.com.",
+ "answers.yext-pixel.com.",
"anthropic.com.",
"antstream.com.",
"aon.com.",
- "ap.sd-rtn.com.",
"api-analytics-us3.zepp.com.",
"api-asyncgw-gcc-teams.usgovtrafficmanager.net.",
+ "api-cdn.prod.life360.com.",
"api-eu1.hubspot.com.",
"api-glb-aaps1b.smoot.apple.com.",
"api-glb-aapse1c.smoot.apple.com.",
"api-glb-aeun1a.smoot.apple.com.",
+ "api-glb-aeun1b.smoot.apple.com.",
"api-glb-aeus2a.smoot.apple.com.",
+ "api-glb-aeus2b.smoot.apple.com.",
"api-glb-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-player.musicstylingonline.com.",
@@ -820,13 +964,14 @@ var FakeECSFQDNs = container.NewMapSet(
"api.config-security.com.",
"api.crobox.com.",
"api.crush.163.com.",
+ "api.crxcavator.io.",
"api.dealersocket.com.",
"api.deepl.com.",
- "api.digitalinsight.com.cdn.cloudflare.net.",
- "api.foxnews.com.",
"api.glanceapis.com.",
"api.gleap.io.",
"api.gravitec.media.",
+ "api.gravitec.net.",
+ "api.gx.me.",
"api.icalendars.app.",
"api.inboxsdk.com.",
"api.ipgeolocation.io.",
@@ -834,20 +979,20 @@ var FakeECSFQDNs = container.NewMapSet(
"api.kinogram.best.",
"api.lightboxcdn.com.",
"api.loyalhealth.com.",
- "api.m.taobao.com.",
+ "api.mangacoin.net.",
"api.matetranslate.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.pushbullet.com.",
"api.queryly.com.",
+ "api.radiotime.com.",
+ "api.recs.sky.com.",
"api.reverso.net.",
"api.ringcentral.biz.",
"api.rollbar.com.",
@@ -856,43 +1001,42 @@ var FakeECSFQDNs = container.NewMapSet(
"api.sobot.com.",
"api.streak.com.",
"api.swishapps.ai.",
- "api.taplytics.com.",
- "api.trainerize.com.",
+ "api.tiles.virtualearth.net.",
"api.transitapp.com.",
- "api.triptease.io.",
"api.tx4.pw.adn.cloud.",
"api.ultimaker.com.",
"api.ultimate-guitar.com.",
"api.unity.com.",
"api.us.minga.io.",
"api.vieon.vn.",
- "api.weglot.com.",
+ "api.voicemod.net.",
"api.workjam.com.",
+ "api.y41w4.com.",
"api000.backblazeb2.com.",
"api001.backblazeb2.com.",
"api002.backblazeb2.com.",
- "api2.chase.com.",
"api2.matetranslate.com.",
+ "apiblink.ru.",
"apiisgp.ezvizlife.com.",
"apiisgp.hik-connect.com.",
- "apim-dev-cn-pcm-ms-01.azure-api.cn.",
"apimgmttmgpxfqy6dfjiqfsk6t67i30fgsnfhah4rrjw51coy3.trafficmanager.net.",
- "apio.lloydsbank.co.uk.",
"apis.live.net.",
- "apis.lloydsbank.co.uk.",
"apitm.toolmatrix.plus.",
- "apituner.ecbsn.com.",
"apk.v-mate.mobi.",
"apk.vidmate.net.",
"aplo-evnt.com.",
+ "apm.gotokeep.com.",
"app-atl.five9.com.",
"app-eu1.hubspot.com.",
"app-goal.com.",
"app-scl.five9.com.",
+ "app-student.atitesting.com.",
"app.adoric-om.com.",
"app.box.com.",
"app.cart-bot.net.",
"app.cybba.solutions.",
+ "app.divvy.co.",
+ "app.docusign.com.",
"app.ee-share.com.",
"app.paces.jbi.global.",
"app.pendo.qgenda.com.",
@@ -906,21 +1050,20 @@ var FakeECSFQDNs = container.NewMapSet(
"appcafe.starbucks.com.",
"appconf.mail.163.com.",
"appdump.nie.easebar.com.",
- "appgrowth.com.",
"applog.matrix.easebar.com.",
"appocean.media.",
"apponline.research.qq.com.",
- "apps-ds.shopifynetwork.com.",
- "apps.foxnews.com.edgekey.net.",
"apps.wix.com.",
"appstoreonrt-stsdk.vivo.com.cn.",
"appstoreort-stsdk.vivo.com.cn.",
- "arbiter.warframe.com.",
+ "apro-api.collegeboard.org.",
"arenabg.com.",
"aristotleinsight.com.",
"arm-frontdoor-edge-geo.trafficmanager.net.",
"arm1.maxhost.io.",
"arms-retcode-sg.aliyuncs.com.",
+ "arms.aliyuncs.com.",
+ "arnoldclark1-my.sharepoint.com.",
"arup.sharepoint.com.",
"as-api.asm.skype.com.",
"as-prod.asyncgw.teams.microsoft.com.",
@@ -935,8 +1078,8 @@ var FakeECSFQDNs = container.NewMapSet(
"asia-cota.vivoglobal.com.",
"asia-ex-adlog.vivoglobal.com.",
"asia-exbrowser.vivoglobal.com.",
+ "asia-exbrowsercrp.vivoglobal.com.",
"asia-exmagazineunlock-proxy.vivoglobal.com.",
- "asia-f-up.vivoglobal.com.",
"asia-gamecenter.vivoglobal.com.",
"asia-gsearch.vivoglobal.com.",
"asia-magazineunlock.vivoglobal.com.",
@@ -961,7 +1104,6 @@ var FakeECSFQDNs = container.NewMapSet(
"asia-vpushonrt-stsdk.vivoglobal.com.",
"asia-vpushort-stsdk.vivoglobal.com.",
"asia-weather.vivoglobal.com.",
- "asia-wifi.vivoglobal.com.",
"asia.gikken.co.",
"asia.remotepc.com.",
"asm-api-golocal-geo-am-teams.trafficmanager.net.",
@@ -973,12 +1115,15 @@ var FakeECSFQDNs = container.NewMapSet(
"asm-api-prod-geo-eu-skype.trafficmanager.net.",
"asset.fwcdn3.com.",
"asset.fwpub1.com.",
- "assets-prod.servicetitan.com.",
+ "assets-cms.thescore.com.",
+ "assets-www.xbox.com.",
"assets.api.stairwell.com.",
+ "assets.mayoclinic.org.",
+ "assets.thdstatic.com.edgekey.net.",
"assistant-dre.op.hicloud.com.",
"astemo-am.spectrum.colortokens.com.",
+ "async-motiondetection-us-1d.oss-us-west-1.aliyuncs.com.",
"asyncim.zoom.us.",
- "athena.archive.org.",
"ati.com.",
"atlanta.remotepc.com.",
"atlanta3.remotepc.com.",
@@ -988,37 +1133,34 @@ var FakeECSFQDNs = container.NewMapSet(
"au.footballbros.io.",
"auc-collabrtc.officeapps.live.com.",
"auckland.remotepc.com.",
- "audio-public.canva.com.",
+ "audio-ssl.itunes.apple.com.",
"audio.vivintsky.com.",
"audiostatlog.cc.easebar.com.",
- "aura-dsp.com.",
"australiaeast.api.cognitive.microsoft.com.",
"auth-l7.bereal.com.",
"auth.bereal.com.",
- "auth.ichano.cn.",
+ "auth.cengage.com.",
"auth.jbisumari.org.",
- "auth.laureate.net.",
- "auth.services.adobe.com.cdn.cloudflare.net.",
- "auth.syf.com.",
+ "auth.tesla.com.",
"autohome.com.cn.",
- "autolinkmaker.itunes.apple.com.",
"autotrack.studyquicks.com.",
"avalanche.autotrader.co.uk.",
- "avaya.com.",
"aws-aus-e-rdvz.g.nssvc.net.",
"aws-bz-s-rdvz.g.nssvc.net.",
+ "ayads.co.",
"az-us-sc-features.netscalergateway.net.",
"azchicago.remotepc.com.",
"azchicago2.remotepc.com.",
"azeus1-client-s.gateway.messenger.live.com.",
"azioncdn.net.",
- "azmatch.adsrvr.org.",
"azscus1-client-s.gateway.messenger.live.com.",
"azwcus1-client-s.gateway.messenger.live.com.",
"azwus1-client-s.gateway.messenger.live.com.",
"azwus2-client-s.gateway.messenger.live.com.",
"b1-nldc1.zemanta.com.",
+ "b1-wndc1.zemanta.com.",
"b1t-nldc1.zemanta.com.",
+ "b1t-wndc1.zemanta.com.",
"b2b.filesyscrm.com.",
"bablosoft.com.",
"backend-l.deepl.com.",
@@ -1028,14 +1170,16 @@ var FakeECSFQDNs = container.NewMapSet(
"baishan-cloud.net.",
"baltimore.remotepc.com.",
"bam.nr-data.net.cdn.cloudflare.net.",
+ "bancomermovil.com.",
"bangalore2.remotepc.com.",
"bangalore3.remotepc.com.",
"bangalore4.remotepc.com.",
"bangkok.remotepc.com.",
"barstoolsports.com.",
- "basf.com.",
"bd1cec50-00d1-4ce9-9572-785857419a1e.prmutv.co.",
- "beacon-sjc2.rubiconproject.com.",
+ "bdpnt-my.sharepoint.com.",
+ "bea.gov.",
+ "beacon-iad2.rubiconproject.com.",
"beacon.qq.com.",
"beacons4.gvt2.com.",
"beacons5.gvt2.com.",
@@ -1043,10 +1187,13 @@ var FakeECSFQDNs = container.NewMapSet(
"belgium.remotepc.com.",
"belgrad.remotepc.com.",
"bend.remotepc.com.",
+ "benefitfocus.com.",
"bgtfs.transitapp.com.",
+ "bi-tracker-global.rivergame.net.",
+ "bidmyadz.com.",
"bidster.net.",
- "bifrost-https-v4.gw.postman.com.cdn.cloudflare.net.",
"bifrost.vivaldi.com.",
+ "bigcommerce.com.cdn.cloudflare.net.",
"bigdata.talkie-ai.com.",
"bik.gov.tr.",
"bl6pap003.storage.live.com.",
@@ -1054,15 +1201,14 @@ var FakeECSFQDNs = container.NewMapSet(
"black-cat.crypto.com.",
"blackboard.com.",
"blackbox.dropbox-dns.com.",
- "blog.csdn.net.",
+ "block64.com.",
+ "blockchain.info.",
"bloomerang.co.",
"bluffdale.remotepc.com.",
"blz04pap002.storage.live.com.",
- "blz04pap003.storage.live.com.",
"blz04pap005.storage.live.com.",
"blz04pap006.storage.live.com.",
- "blz04pap007.storage.live.com.",
- "bmoolbb-app.quantummetric.com.",
+ "bmaus.bumble.com.",
"bn02pap001.storage.live.com.",
"bnz05pap001.storage.live.com.",
"bnz06pap002.storage.live.com.",
@@ -1079,21 +1225,16 @@ var FakeECSFQDNs = container.NewMapSet(
"box.com.",
"box.net.",
"br.chat.si.riotgames.com.",
- "brainx.tech.",
"bratislava.remotepc.com.",
"brazilsouth.api.cognitive.microsoft.com.",
- "brc-collabrtc.officeapps.live.com.",
"breitbart.com.",
"bridge.tonapi.io.",
- "britishairways.com.",
"broadstreetads.com.",
"broker-ws-prod-cag-sg.vasdgame.com.",
- "browsingpublic.trendyol.com.",
"bscedge.com.",
"bsprings.remotepc.com.",
"bssrvc66.com.",
"bt.moack.co.kr.",
- "bt2.archive.org.",
"btrace.qq.com.",
"bucharest.remotepc.com.",
"bucharest1.remotepc.com.",
@@ -1101,21 +1242,18 @@ var FakeECSFQDNs = container.NewMapSet(
"bugly.qcloud.com.",
"bugreport.huorong.cn.",
"bundler.nice-team.net.",
- "burnsmcd.sharepoint.com.",
"bytecdn.cn.",
"bytedance.net.",
"c.4dex.io.",
"c.fakespot.io.",
- "c.footprint.net.",
"c.pub.network.",
"c1.ttcache.com.",
- "c13.groundctl.com.",
- "c2-eu.piano.io.",
"c2.ttcache.com.",
"c2c.wechat.com.",
"c3.ttcache.com.",
"c4.ttcache.com.",
"c7l.cyberhaven.io.",
+ "c8ee9446-97ed-462f-a5e9-1af66c8e9104.prmutv.co.",
"ca-prod.asyncgw.teams.microsoft.com.",
"ca.gov.",
"ca.rogers.rcs.telephony.goog.",
@@ -1127,19 +1265,19 @@ var FakeECSFQDNs = container.NewMapSet(
"cachenetworks.com.",
"caldav.163.com.",
"california.remotepc.com.",
- "campaign-archive.com.",
- "cams.gratis.",
"camsoda.com.",
"canada.remotepc.com.",
"canadacentral.api.cognitive.microsoft.com.",
"canadaeast.api.cognitive.microsoft.com.",
"canberra.remotepc.com.",
"capetown.remotepc.com.",
+ "capi.elements.video.cdn.cloudflare.net.",
"captaina.co.",
"car-cloud-cn.net.",
"cardiff.remotepc.com.",
"care.novaicare.com.",
"carters.com.",
+ "cartx.cloud.",
"carystudio.com.",
"cat1.hbwrapper.com.",
"cat2.hbwrapper.com.",
@@ -1149,71 +1287,62 @@ var FakeECSFQDNs = container.NewMapSet(
"cbsipv4.shuzilm.cn.",
"cc.easebar.com.",
"ccf.ivalua.com.",
+ "cdml02.contentdm.oclc.org.",
"cdn-audio-gcp-media.getepic.com.",
- "cdn-client.medium.com.",
+ "cdn-cname.pendo.io.",
"cdn-gcp-media-drm.getepic.com.",
"cdn-gcp-media.getepic.com.",
"cdn-gcp.getepic.com.",
"cdn-us.algoliaradar.com.",
"cdn-video-gcp-media.getepic.com.",
"cdn.adjust.com.",
- "cdn.adpool.bet.",
"cdn.adtarget.market.",
"cdn.adtarget.me.",
- "cdn.adtwister.me.",
+ "cdn.chargeafter.com.",
"cdn.conveythis.com.",
"cdn.deepintent.com.",
- "cdn.flashtalking.com.edgekey.net.",
- "cdn.ftd.agency.",
+ "cdn.flyaa.aa.com.",
"cdn.groupbycloud.com.",
"cdn.hw.gcloudcs.com.",
+ "cdn.instamed.com.",
"cdn.instapagemetrics.com.",
- "cdn.logr-ingest.com.",
+ "cdn.jsdelivrs.com.",
"cdn.overleaf.com.",
"cdn.qq.com.",
"cdn.registerdisney.go.com.",
"cdn.sierrapacificgroup.com.",
- "cdn.sitestatic.net.",
"cdn.skcrtxr.com.",
"cdn.t-bank-app.ru.",
"cdn.tapdb-dev.com.",
+ "cdn.themoneytizer.fr.",
"cdn.us.minga.io.",
"cdn.uxfeedback.ru.",
"cdn1.wixdns.net.",
- "cdnapi.kaltura.com.",
"cdnetworks.net.",
"cdngslb.com.",
"cdntm.hsbc.co.uk.",
"cdnwidget.com.",
"cds.swishapps.ai.",
"cdsi.signal.org.",
- "cdt.ca.gov.",
- "cdxdns.com.",
- "cdxflare.com.",
- "cec.hpsmart.com.",
"cedexis-test.com.",
"cedock.com.",
- "center00.deltaork.com.",
- "center01.deltaork.com.",
- "center02.deltaork.com.",
- "center03.deltaork.com.",
+ "cef.com.br.",
+ "cekdptonline.kpu.go.id.",
"center04.deltaork.com.",
- "center05.deltaork.com.",
- "center06.deltaork.com.",
"center07.deltaork.com.",
"center08.deltaork.com.",
- "center09.deltaork.com.",
"centralindia.api.cognitive.microsoft.com.",
"centralus.api.cognitive.microsoft.com.",
"centrexit.com.",
"certs.t-bank-app.ru.",
- "cf.perf.linkedin.com.",
"cfa.fidelity.com.",
+ "cform.loyalhealth.com.",
+ "cgi.twns.qq.com.",
"changehealthcare.com.",
+ "chargeafter.com.",
"charlotte.remotepc.com.",
"check2.lloydsbank.co.uk.",
"chennai.remotepc.com.",
- "chess.com.",
"chi01pap001.storage.live.com.",
"chi01pap002.storage.live.com.",
"chicago2.remotepc.com.",
@@ -1223,14 +1352,15 @@ var FakeECSFQDNs = container.NewMapSet(
"chinaccl-a.haplat.net.",
"chinaccl-b.haplat.net.",
"chinaccl-c.haplat.net.",
- "christianbook.com.",
"chrome.com.",
"chtsite.com.",
"chub1.imp.us.contentkeeper.net.",
+ "chujingapp.com.",
"cicd-release-api.dalyfeds.com.",
"cinarra.com.",
"cis.citrix.com.",
"cisco.app.box.com.",
+ "citiretailservices.citibankonline.com.",
"citrix-cloud-content.customer.pendo.io.",
"citrix-cloud-data.customer.pendo.io.",
"citrix-sharefile-content.customer.pendo.io.",
@@ -1238,13 +1368,16 @@ var FakeECSFQDNs = container.NewMapSet(
"citrix.com.",
"cl-data.ads.heytapmobi.com.",
"cl-gl036e4fc3.gcdn.co.",
+ "cl-glffabd6cc.maps.cdn.orange.com.",
"cl2009.com.",
+ "classroom6x.gitlab.io.",
"claude.ai.",
"cleveland.remotepc.com.",
+ "cli.speedtest.net.",
"click-eu.preclknu.com.",
- "click-v4.cldirplarimo.com.",
- "click-v4.exclkplat.com.",
"click-v4.expdirclk.com.",
+ "click.admeking.com.",
+ "click.pclk.name.",
"click.preclknu.com.",
"clickiocmp.com.",
"client-log.box.com.",
@@ -1252,36 +1385,40 @@ var FakeECSFQDNs = container.NewMapSet(
"client-tracking.omiapp.me.",
"client-updates.lumu.io.",
"client.mail.163.com.",
+ "client.perimeterx.net.edgekey.net.",
+ "client.ppe.repmap.microsoft.com.",
"clientlog3.music.163.com.",
+ "clientsettingscdn.roblox.com.edgekey.net.",
+ "cliftonlarsonallen-my.sharepoint.com.",
"cloud-agent.policypak.com.",
"cloud-config-service.rtc.aliyuncs.com.",
"cloud-links.net.",
"cloud-rest.lenovomm.com.",
- "cloud.huawei.ru.",
+ "cloud.browser.360.cn.",
"cloud.ibm.com.",
"cloud.vmp.onezapp.com.",
+ "cloud.xm-cdn.com.",
"cloud.zoom.us.",
"cloudbirds.cn.",
"clouddata.turbowarp.org.",
+ "cloudflareperf.com.",
"cloudlinks.cn.",
"cloudscdn.info.",
"cloudsvc.policypak.com.",
"cm-x.mgid.com.",
- "cm.mobydix.com.",
- "cmegroup.com.",
"cmgate.vip.qq.com.",
"cmpassport.com.",
"cn-hangzhou.oss-cdn.aliyun-inc.com.",
"cn-mib2high-mbbservices.audi-connect.cn.",
"cn-mib2plus.mbbservices-1a.audi-connect.cn.",
"cn.gcloudcs.com.",
+ "cname.cordial.com.",
"cname.pendo.io.",
"cnplug.ttlock.com.",
+ "cnvid.site.",
"cnzz.com.",
"co-vcode-od.vivoglobal.com.",
- "co.amx.rcs.telephony.goog.",
"codacloud.net.",
- "code.etracker.com.",
"codepush.akulaku.net.",
"codis-bak.ngb.haplat.net.",
"codis.ngb.haplat.net.",
@@ -1290,72 +1427,81 @@ var FakeECSFQDNs = container.NewMapSet(
"collect.quickcep.com.",
"collect.trendyol.com.",
"collector.quillbot.com.",
- "collector.seexh.com.",
+ "collector.therealxh.com.",
"collector.wdp.brave.com.",
"collector.xhamster.com.",
+ "collector.xhamster.desi.",
"columbus.remotepc.com.",
"com.yangyi19.com.",
"cometglobal.cf.t3cloud.pb.com.",
"cometservd1.pb.com.",
+ "commerce.nbcuni.com.",
+ "commercial.ocsp.identrust.com.",
"common-afd.fe.1drv.com.",
"common-afdrk.fe.1drv.com.",
"common.xshareapp.com.",
+ "community.spiceworks.com.cdn.cloudflare.net.",
"compiles.overleafusercontent.com.",
+ "comserver.global.mspa.n-able.com.",
"config-security.com.",
+ "config-toolbar.ducunt.com.",
"config.a-m-p.xyz.",
"config.cmpassport.com.",
"config.content-settings.com.",
+ "config.inmobi.com.",
"config.office.net.",
- "config.onefootball.com.",
- "config.trackingplan.com.",
"config.y5en.com.",
"config2.cmpassport.com.",
"configdl.teamviewer.com.",
"connect.garenanow.com.",
"contacts.zoho.com.",
- "content.citizensbankonline.com.",
- "content.cxpublic.com.",
+ "content.assist.chromeriver.com.",
+ "content.bhrpendo.bamboohr.com.",
+ "content.data.aleks.com.",
+ "content.data.mheducation.com.",
"content.discover.com.",
"content.discovercard.com.",
"content.ebanking-services.com.",
+ "content.fisglobal.com.",
"content.gap.com.",
"content.help.explorelearning.com.",
"content.maxconnector.com.",
+ "content.pendo.careporthealth.com.",
"content.pendo.follettdestiny.com.",
- "content.pncmc.com.",
+ "content.pendo.saashr.com.",
"content.productinsights.blackline.com.",
- "content22.bancanet.banamex.com.",
+ "content.readiness.imaginelearning.com.",
"content22.bmo.com.",
"content22.citicards.com.",
"content22.online.citi.com.",
"context.reverso.net.",
"control-out.mna.qq.com.",
+ "coolccloud.com.",
"coolkit.cc.",
"copenhagen.remotepc.com.",
"cordial.com.",
- "core.gssv-play-prod.xboxlive.com.",
"core.iprom.net.",
"core.omiapp.me.",
"corpmdm.v.aaplimg.com.",
"cosmos.azure.com.",
"countly.mail.163.com.",
"covers.vitalbook.com.",
- "cp2.cloudflare.com.",
"cpisolutions.com.",
"cpm.appocean.media.",
"cpm.aserve1.net.",
- "cpm.catapultx.com.",
"cpm.qortex.ai.",
"cpm.vuukle.net.",
"cpm.xrtb.io.",
"cpr-pusa01.app.blackbaud.net.",
+ "cpt96125.shopvoxpopulus.com.",
"cpx-research.com.",
"crash.xiaohongshu.com.",
"crashlytics.com.",
"crashsight.qq.com.",
"crashsight.wetest.net.",
- "creative.bbrdbr.com.",
"creator.pdf24.org.",
+ "creditmaven.com.",
+ "crl.americanexpress.com.",
"crlocsp.cn.",
"croatia.remotepc.com.",
"crobox.com.",
@@ -1366,7 +1512,6 @@ var FakeECSFQDNs = container.NewMapSet(
"cs.nex8.net.",
"cs.playdigo.com.",
"csdn.net.",
- "cspire.com.",
"cstse02.ultipro.com.",
"cstsew02.ultipro.com.",
"cstsn02.ultipro.com.",
@@ -1374,8 +1519,6 @@ var FakeECSFQDNs = container.NewMapSet(
"cti.roku.com.",
"ctmail.com.",
"customer.homedepot.com.",
- "cvision.media.net.",
- "cvpn-blr.ras.qualcomm.com.",
"cvs.quantummetric.com.",
"cwogzftn.usw.stape.io.",
"czechrepublic.remotepc.com.",
@@ -1385,7 +1528,9 @@ var FakeECSFQDNs = container.NewMapSet(
"d2fb08da-1c03-4c8a-978f-ad8a96b4c31f.prmutv.co.",
"d3-pr-cu-tm-secapi.trafficmanager.net.",
"d6691a17-6fdb-4d26-85d6-b3dd27f55f08.prmutv.co.",
+ "d82f7a30-751a-4689-b7e9-19336a89ab46.prmutv.co.",
"d837da8d.cloudsrv.minerva-labs.com.",
+ "da.footballbros.io.",
"da.mosspf.com.",
"da.toponadss.com.",
"daemon.nanoleaf.me.",
@@ -1410,7 +1555,6 @@ var FakeECSFQDNs = container.NewMapSet(
"data.data.mheducation.com.",
"data.guide-app.zoominfo.co.",
"data.guides.oncoursesystems.com.",
- "data.guides.percipio.com.",
"data.hockeystack.com.",
"data.investing.com.",
"data.ipd.goto.com.",
@@ -1422,13 +1566,12 @@ var FakeECSFQDNs = container.NewMapSet(
"data.pendo-tracking.seismic.com.",
"data.pendo.careporthealth.com.",
"data.pendo.gomotive.com.",
- "data.pendo.progresslearning.com.",
"data.pendo.saashr.com.",
"data.pendo.udsrv.com.",
"data.pendoanalytics.dayforcehcm.com.",
- "data.productanalytics.coconutcalendar.com.",
"data.productinsights.blackline.com.",
"data.queryly.com.",
+ "data.readiness.imaginelearning.com.",
"data.tracking.billtrust.com.",
"data.useranalytics.global.datasite.com.",
"data00.adlooxtracking.com.",
@@ -1439,12 +1582,11 @@ var FakeECSFQDNs = container.NewMapSet(
"dayunlinks.cn.",
"dc-o.api.leiniao.com.",
"dc.ads.linkedin.com.",
+ "dc.cftls.t.co.cdn.cloudflare.net.",
"dc.di.atlas.samsung.com.",
"dc.dqa.samsung.com.",
"dc.sigmob.cn.",
"dc.wondershare.com.",
- "dcs-live-ue1.mp.lura.live.",
- "dcs-live-uw1.mp.lura.live.",
"dcs-live.mp.lura.live.",
"dcs-png.mp.lura.live.",
"dcs-vod.mp.lura.live.",
@@ -1452,32 +1594,32 @@ var FakeECSFQDNs = container.NewMapSet(
"dcs110-mcdn.mp.lura.live.",
"ddata.huntingtonbank.com.",
"ddnsclient.ivview.net.",
+ "de-idm.api.io.mi.com.",
+ "de-odc.samsungapps.com.",
"de-prod.asyncgw.teams.microsoft.com.",
"de.dt.rcs.telephony.goog.",
"de.hlth.io.mi.com.",
"dealmoon.com.",
- "dec-collabrtc.officeapps.live.com.",
"decagon.ai.",
"delivery.upremium.asia.",
"dell-prod.actioniq.mr-in.com.",
- "dellupdater.dell.com.",
"delta.quantummetric.com.",
"demeter-int-ecom-collect.trendyol.com.",
"demeter-tr-core-collect.trendyol.com.",
"denver.remotepc.com.",
- "designer-api.hu-manity.co.",
+ "dev.av380.net.",
+ "devc.zztfly.com.",
"deviceapi.ca1.absolute.com.",
"deviceops.hstgps.com.",
"dewu.com.",
- "dexx.ai.",
+ "dexerto.media.",
"dfaklj.tech.",
"dhs.gov.",
"dialpad.com.",
- "dicontent.creditkarma.com.",
+ "dicontent.ckapis.com.",
"dict.deepl.com.",
"dict.ntes53.netease.com.",
"dictvip-business.youdao.com.",
- "diffuser-cdn.app-us1.com.",
"digiapp.vietcombank.com.vn.",
"digiboy.ir.",
"digitalcardservice.com.",
@@ -1486,7 +1628,6 @@ var FakeECSFQDNs = container.NewMapSet(
"discovery.ringcentral.biz.",
"dispatcher.omiapp.me.",
"dispatchosglobal.yuanshen.com.",
- "distribution.hulu.com.",
"distservp1.pb.com.",
"divide.dalyfeds.com.",
"dl2.discordapp.net.",
@@ -1496,40 +1637,37 @@ var FakeECSFQDNs = container.NewMapSet(
"dmv.ca.gov.",
"dns-e.ns4v.icu.",
"dns-tunnel-check.googlezip.net.",
- "dns.cloudflare.com.",
"dns.rubyfish.cn.",
"dns1.nettica.com.",
"dns101.register.com.",
+ "dns23.llnwi.net.",
"doceditor.wrike.com.",
"docs.live.net.",
"docs.zoom.us.",
"doctrack.fda.gov.ph.",
"document360.io.",
"domaincfg.vivoglobal.com.",
+ "donaldson-my.sharepoint.com.",
"donewyork1.remotepc.com.",
"donewyork2.remotepc.com.",
"donewyork3.remotepc.com.",
"dosfo1.remotepc.com.",
"dosfo2.remotepc.com.",
- "douyin.starrydyn.com.",
"dowjones-prod.actioniq.mr-in.com.",
"download.2.401402081.west-gcloud.codm.activision.com.",
- "download.amd.com.",
- "download.lenovo.com.edgekey.net.",
"downloadcenter.genetec.com.",
"dp.barclaysus.com.",
"dp.im.weibo.cn.",
"dpf.authorize.net.",
"dpool.sina.com.cn.",
"dr.netease.im.",
- "dragate-sg.dc.heytapmobi.com.",
"dreame.tech.",
"drfdisvc.walmart.com.",
+ "drop-assets.ea.com.",
"drsquatch.com.",
- "drummond.mixtubeapp.com.",
"ds.gsma.com.",
+ "dsa-eu.hybrid.ai.",
"dsm01pap001.storage.live.com.",
- "dsm01pap002.storage.live.com.",
"dsm01pap003.storage.live.com.",
"dsm01pap004.storage.live.com.",
"dsm01pap007.storage.live.com.",
@@ -1540,16 +1678,18 @@ var FakeECSFQDNs = container.NewMapSet(
"dsp-cookie.adfarm1.adition.com.",
"dsp-trk.eskimi.com.",
"dsp-trvm.eskimi.com.",
- "dss.hybrid.ai.",
+ "dspcluster.adfarm1.adition.com.",
+ "dspx.tv.",
"dstillery.com.",
"dt.netease.im.",
"dtscout.com.",
+ "dualspaceapi.com.",
"dubai.remotepc.com.",
"dublin.remotepc.com.",
"dun.163yun.com.",
"dz.cyberhaven.io.",
+ "dzfread.cn.",
"e-189.21cn.com.",
- "e-bea.dc2.ovid.com.",
"e.189.cn.",
"e.cdnwidget.com.",
"e.userflow.com.",
@@ -1633,6 +1773,7 @@ var FakeECSFQDNs = container.NewMapSet(
"e2c79.gcp.gvt2.com.",
"e2c8.gcp.gvt2.com.",
"e2c80.gcp.gvt2.com.",
+ "e2c81.gcp.gvt2.com.",
"e2c9.gcp.gvt2.com.",
"e2cs01.gcp.gvt2.com.",
"e2cs02.gcp.gvt2.com.",
@@ -1688,11 +1829,10 @@ var FakeECSFQDNs = container.NewMapSet(
"e2cs53.gcp.gvt2.com.",
"e2cs54.gcp.gvt2.com.",
"e2cs55.gcp.gvt2.com.",
+ "e3c12f53-768d-4aa2-8e31-b8d0ee6320b1.prmutv.co.",
"e43.ultipro.com.",
"e488cdb0-e7cb-4d91-9648-60d437d8e491.prmutv.co.",
"e5de3d23065c4748b155c28e6fa36f3e.pacloudflare.com.",
- "e65uuo.jiaoshuanggb.com.",
- "ea.com.",
"ea.footballbros.io.",
"eafddirect.msedge.net.",
"eagle.haplat.net.",
@@ -1701,113 +1841,97 @@ var FakeECSFQDNs = container.NewMapSet(
"eastasia.api.cognitive.microsoft.com.",
"eastmoney.com.",
"eastus.api.cognitive.microsoft.com.",
- "eastus2-gas.guestconfiguration.azure.com.",
"eastus2.api.cognitive.microsoft.com.",
"ecatholic.com.",
- "ecdd.walkme.com.",
- "ecdn.teacherspayteachers.com.",
"ecom.wixapps.net.",
- "ecommerce.iap.unity3d.com.",
"ecs-gallatin-c2s.trafficmanager.net.",
"ed.link.",
"edevice.toshiba-solutions.com.",
- "edge.personalizer.io.",
- "edge.rgs.pmc.pay.riotgames.com.",
- "edge.sitecorecloud.io.",
- "edge.txryan.com.",
+ "edge.xero.com.",
"edgecdn.ru.",
"edgedl.me.gvt1.com.",
"edgelocation.ivanticloud.com.",
"editor.wix.com.",
"editorial.femaledaily.com.",
"edna.id.",
- "edpms.doh.gov.ph.",
"education-certification.youdao.com.",
"ee-share.com.",
"efercro.com.",
"efs.ultipro.com.",
"egateway.ultipro.com.",
"ei.dyn-rev.app.",
- "eitri.api.useinsider.com.",
+ "ejoyspace.com.",
"elemecdn.com.",
+ "elixarco.com.",
+ "elonuniversity-my.sharepoint.com.",
"emailaptitude.com.",
- "emo.v-mate.mobi.",
- "emp.bbci.co.uk.edgekey.net.",
"employers.indeed.com.",
"endpointprotector.com.",
"engage.wixapps.net.",
"engagementapi.skype.com.",
+ "engine.phn.doublepimp.com.",
"enplug.com.",
"ent.box.com.",
- "enthusiastgaming.com.",
+ "entitlements.auth.riotgames.com.",
"envoy-ios-prod.getepic.com.",
"envysion.com.",
"epdg.vowifi.cspire.com.",
"epicmobile.ohsu.edu.",
- "epoch.cloud.",
"eponesh.com.",
"eportal.fda.gov.ph.",
"epubgame.com.",
"errortracking.deepl.com.",
"esignlive.com.",
- "esm.archive.org.",
"essence.com.",
- "etail.mysynchrony.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.account.riotgames.com.",
"eu.global.market.xiaomi.com.",
- "eu.inspidspad.com.",
- "eu.mvconf.50union.com.",
"eu.statusapi.micloud.xiaomi.net.",
- "eu.whatfix.com.",
"eu1.badoo.com.",
"eu1a-excel-collab.officeapps.live.com.",
"eu1a-powerpoint-collab.officeapps.live.com.",
"eu1a-word-collab.officeapps.live.com.",
- "eu2.concursolutions.com.",
+ "eu2a-excel-collab.officeapps.live.com.",
+ "eu2a-powerpoint-collab.officeapps.live.com.",
"eu4-excel-collab.officeapps.live.com.",
"eu4-powerpoint-collab.officeapps.live.com.",
- "eu4-word-collab.officeapps.live.com.",
- "euc-collabrtc-geo.rtc.trafficmanager.net.",
"euc-collabrtc.officeapps.live.com.",
"euc-excel-collab.officeapps.live.com.",
"euc-powerpoint-collab.officeapps.live.com.",
- "euc-word-edit-geo.wac.trafficmanager.net.",
"euler-saas-cn.heytapmobi.com.",
"europe-west1-skyuk-uk-pa-tds-prod.cloudfunctions.net.",
"europe.remotepc.com.",
- "eus2-region.present.officeapps.live.com.",
"euw1.chat.si.riotgames.com.",
"eve.gameloft.com.",
"event.evtm.53.com.",
- "event.togothermany.com.",
+ "events.attentivemobile.com.",
"events.glanceapis.com.",
"events.swishapps.ai.",
- "ew33.ultipro.com.",
"ex-adreq-asia.vivoglobal.com.",
+ "exacti.us.",
"exappupgrade.vivoglobal.com.",
+ "exb.quicknewsfeed.online.",
"excel-collab-geo.ocs.trafficmanager.net.",
"excel-collab.officeapps.live.com.",
+ "excel-geo.wac.trafficmanager.net.",
"exodus.desync.com.",
"exp.host.",
"exponential.com.",
- "ext.securifyprotect.com.",
"extension.faro.speechify.dev.",
"extension.savvy.security.",
"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-atl3-3.xx.fbcdn.net.",
"external-bos5-1.xx.fbcdn.net.",
"external-den2-1.xx.fbcdn.net.",
"external-dfw5-1.xx.fbcdn.net.",
"external-dfw5-2.xx.fbcdn.net.",
- "external-fra3-1.xx.fbcdn.net.",
"external-hou1-1.xx.fbcdn.net.",
"external-iad3-1.xx.fbcdn.net.",
"external-iad3-2.xx.fbcdn.net.",
@@ -1828,26 +1952,19 @@ var FakeECSFQDNs = container.NewMapSet(
"external-phx1-1.xx.fbcdn.net.",
"external-sea1-1.xx.fbcdn.net.",
"external-sjc3-1.xx.fbcdn.net.",
- "f-p-sandbox.bytedance.net.",
"f002.backblazeb2.com.",
- "fa000000120.resources.office.net.",
- "fa000000131.resources.office.net.",
- "fa1f96ab-b693-40e4-82d5-8698592ef9ac.prmutv.co.",
- "fa3fca7ce79f4b81a39f216e916397d5.pacloudflare.com.",
+ "f9tg.com.",
"faas.marktplaats.nl.",
"factor.reg.163.com.",
"factset.com.",
"fanatics.ent.box.com.",
"fanduel.quantummetric.com.",
- "fastenal-my.sharepoint.com.",
- "fastformstax.prosystemfx.com.",
+ "fanyiegg.youdao.com.",
+ "fcix.net.",
"fdccpaadaptor.forddirectservices.com.",
"fe.xiaohongshu.com.",
- "featureflags.lavasoft.com.",
"fed.federate365.com.",
- "feed-stub.com.",
"feeder.co.",
- "feedly.com.",
"feelinsonice.l.google.com.",
"fef.amsub0302.manage.microsoft.com.",
"fef.fxpasu01.manage.microsoft.us.",
@@ -1864,52 +1981,57 @@ var FakeECSFQDNs = container.NewMapSet(
"field59.com.",
"files.jotform.com.",
"filesyscrm.com.",
+ "filter.revrtb.net.",
"finalsite.com.",
"finalsite.net.",
+ "fincen.gov.",
"fireeye.com.",
- "fisherinvestments.com.",
+ "fishdom-cdn.playrix.com.",
"five9.com.",
"flashcards.vitalsource.com.",
"flashjoin.net.",
- "fledge.teads.tv.",
"flip.to.",
"flixcdn.com.",
- "fm.cnbc.com.",
+ "flypgs.com.",
"fm.printaudit.com.",
"fn.us.ipqscdn.com.",
"fo.iemiq.com.",
"foisonad.com.",
"forcesafesearch.google.com.",
+ "forethought.ai.",
"form.jotform.com.",
"forms-eu1.hscollectedforms.net.",
"forms-eu1.hsforms.com.",
"forms-eu1.hubspot.com.",
+ "forms-na1.hubspot.com.",
"fortisimperious.com.",
"fortworth.remotepc.com.",
+ "fotpro135alto.com.",
"foundation-ipv4.youdao.com.",
+ "fp-ca-bell.rcs.telephony.goog.",
"fp-de-carrier-vodafone.rcs.telephony.goog.",
"fp-de-telefonica.rcs.telephony.goog.",
"fp-gb-ee.rcs.telephony.goog.",
"fp-us-att.rcs.telephony.goog.",
"fp-us-carrier-spectrum.rcs.telephony.goog.",
+ "fp-us-cspire.rcs.telephony.goog.",
"fp-us-tmobile.rcs.telephony.goog.",
"fp-us-uscc.rcs.telephony.goog.",
"fp-us-verizon.rcs.telephony.goog.",
"fp-us-xfinity.rcs.telephony.goog.",
+ "fp.ca.rogers.rcs.telephony.goog.",
"fp.de.dt.rcs.telephony.goog.",
"fp.ps.easebar.com.",
"fp.us.tracfone.rcs.telephony.goog.",
"fp4-us-att.rcs.telephony.goog.",
+ "fp4-us-tmobile.rcs.telephony.goog.",
"fp4-us-verizon.rcs.telephony.goog.",
"fpdlp.applxweb.com.",
"fpt.brainly.com.",
"fr-prod.asyncgw.teams.microsoft.com.",
- "fra-01.braze.eu.cdn.cloudflare.net.",
"fran.frvr.com.",
"francecentral.api.cognitive.microsoft.com.",
"frankfurt.remotepc.com.",
- "frc-collabrtc.officeapps.live.com.",
- "freight.api.dat.com.",
"fremont.remotepc.com.",
"freseniusmedicalcare.com.",
"fs.ultiproworkplace.com.",
@@ -1917,19 +2039,23 @@ var FakeECSFQDNs = container.NewMapSet(
"ftkew02.ultipro.com.",
"ftkn01.ultipro.com.",
"ftkn02.ultipro.com.",
- "functions.classroomscreen.com.",
+ "ftp.ext.hp.com.edgekey.net.",
+ "func-fhcc-bacdnlqayn.cn-shenzhen.fcapp.run.",
+ "futuretechuu.com.",
"fxltsbl.com.",
+ "g10498469755.co.",
"g9hc4.cn.",
"ga.badambiz.com.",
"galaxyappstore.com.",
"gameloft.com.",
"gamemonkey.org.",
"gamepigeon.net.",
+ "gamingcontext.xboxlive.com.",
"gateway.ultiproworkplace.com.",
- "gb-vodafone.rcs.telephony.goog.",
"gb.ee.rcs.telephony.goog.",
"gb.o2.rcs.telephony.goog.",
- "gbc-excel-collab.officeapps.live.com.",
+ "gbc-powerpoint.officeapps.live.com.",
+ "gbc-word-edit.officeapps.live.com.",
"gccmod.ecs.office.com.",
"gcdn.co.",
"gcloud.qq.com.",
@@ -1940,14 +2066,15 @@ var FakeECSFQDNs = container.NewMapSet(
"gdc-scouccl1.haplat.net.",
"gdc-scouccl2.haplat.net.",
"gdid.datalake.gameloft.com.",
+ "gdp.haplat.net.",
"geappl.io.",
- "geico-app.quantummetric.com.",
+ "geappliances.sharepoint.com.",
"geico-sync.quantummetric.com.",
+ "genetherapyhub.com.",
"geniusmonkey.com.",
- "geo-dc.adobe.com.",
"geo-dra.platform.hicloud.com.",
- "geo.cnbc.com.",
- "geoip.apps.avada.io.",
+ "geocodeservice.costco.com.",
+ "geometrygame.org.",
"geoplugin.net.",
"germanywestcentral.api.cognitive.microsoft.com.",
"getadmiral.com.",
@@ -1955,22 +2082,24 @@ var FakeECSFQDNs = container.NewMapSet(
"getnitropack.com.",
"gettopple.com.",
"getui.net.",
- "gfts.lge.com.",
"gifer.com.",
"gifshow.com.",
+ "git.rancher.io.",
"gitlab.com.",
"gla.gameloft.com.",
- "global-eds.prismray.io.",
+ "gleap.io.",
"global-tokenserver-la.headline.uodoo.com.",
"global.datasite.com.",
- "global.gme.qcloud.com.",
+ "globalapi.smart2pay.com.",
+ "globalgme.com.",
"globalsigncdn.com.cdn.cloudflare.net.",
"globalsun.io.",
- "globalvale.sharepoint.com.",
"gme.qcloud.com.",
"gnc.com.",
+ "go.blcdog.com.",
"goaffpro.com.",
"gohighlevel.com.",
+ "gonines.com.",
"good-loop.com.",
"google.org.",
"googledomains.com.",
@@ -1985,9 +2114,9 @@ var FakeECSFQDNs = container.NewMapSet(
"group-ib.com.",
"grow.me.",
"grpc.vivintsky.com.",
- "gslb.finzfin.com.",
"gslb.xiaohongshu.com.",
- "gsp85-cn-ssl.ls.apple.com.",
+ "gsp85-ssl.ls.apple.com.",
+ "gtimg.cn.",
"gtm.deepl.com.",
"gtm.vividseats.com.",
"guid.tpns.sgp.tencent.com.",
@@ -1996,6 +2125,7 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -2012,34 +2142,37 @@ var FakeECSFQDNs = container.NewMapSet(
"hanoi.remotepc.com.",
"hapsee.cn.",
"hapseemate.cn.",
- "harmonyoffice-my.sharepoint.com.",
"harry.lu.",
"hawaii.remotepc.com.",
"hbopenbid-apac-v2.pubmnet.com.",
"hbwrapper.com.",
- "heart.bmj.com.",
+ "hcaptcha.com.",
"hecheck.bitmyanmar.info.",
"hello.idocdn.com.",
"helloid.com.",
- "hermes-us.inspidspad.com.",
+ "hermes-us.inspi-dsp.com.",
"hetangsmart.com.",
"heytapdownload.com.",
"heytapmobi.com.",
"hft-prod.actioniq.mr-in.com.",
"highwire.org.",
+ "hillsboroughcounty-my.sharepoint.com.",
"hisearch-dra.dt.dbankcloud.com.",
"hismarttv.com.",
"hits.getelevar.com.",
- "hiya-dist.e8779dac8790f4da93c09f34e73b7c7b.r2.cloudflarestorage.com.",
"hk.gcloudcs.com.",
"hk.ntp.org.cn.",
"hk.wechat.com.",
+ "holid.io.",
"holykjvbible.com.",
"home.highwire.org.",
"honeywell.com.",
"hongkong.remotepc.com.",
"hornetsecurity.com.",
+ "hotapi16-normal-ie.tiktokv.eu.",
+ "hotukdeals.com.",
"hpfal.deepl.com.",
+ "hpkaj.deepl.com.",
"hpplay.cn.",
"hrsa.gov.",
"hstgps.com.",
@@ -2047,15 +2180,16 @@ var FakeECSFQDNs = container.NewMapSet(
"html5.qq.com.",
"htms.heytapmobi.com.",
"httpdns.y5en.com.",
- "httpdns.yunxindns.com.",
"huan.tv.",
"huaweicloud.com.",
"huaweicloudwaf.com.",
+ "hub.gibraltarsoftware.com.",
"hubble.netease.com.",
"hubcloud.com.cn.",
"hubspotemail.net.",
"huion.cn.",
"huorong.cn.",
+ "hw.118114.net.",
"hw.gcloudcs.com.",
"hwapps-o.api.leiniao.com.",
"hzmklvdieo.com.",
@@ -2066,11 +2200,9 @@ var FakeECSFQDNs = container.NewMapSet(
"i.one-bid.com.",
"i.qchannel03.cn.",
"i.voe.sx.",
- "i5.walmartimages.com.",
- "i5.walmartimages.com.mx.",
"i6-vn.weather.oppomobile.com.",
"iaas.jdcloud.com.",
- "iac-demo.idmgroup.com.",
+ "iappscontent.courts.state.ny.us.",
"ibm.account.box.com.",
"ibm.box.com.",
"ibsrv.net.",
@@ -2081,11 +2213,9 @@ var FakeECSFQDNs = container.NewMapSet(
"id-ooredoo.rcs.telephony.goog.",
"id-telkom.rcs.telephony.goog.",
"id-timer-appstore.vivoglobal.com.",
- "id.seexh.com.",
- "id.tv.global.mi.com.",
+ "id.therealxh.com.",
"idahofalls.remotepc.com.",
"idchicago1.remotepc.com.",
- "idcta.api.bbc.com.",
"iddallas1.remotepc.com.",
"iddenver.remotepc.com.",
"iddetroit.remotepc.com.",
@@ -2099,28 +2229,27 @@ var FakeECSFQDNs = container.NewMapSet(
"igame.gcloudcs.com.",
"ijoysoftconnect.com.",
"ikki.youdao.com.",
- "il1.nayax.net.",
+ "illuminate.zendesk.com.",
"ilog-sea-aliyun.alipayplus.com.",
- "im-x.jd.com.",
- "im.uniqlo.com.",
"image.myqcloud.com.",
"image.online.adp.com.",
+ "images.emailaptitude.com.",
+ "images.gopuff.com.",
"imagetolink.com.",
"imagetrendelite.com.",
"imap.163.com.",
+ "imap.earthlink.net.",
+ "img-3.kwcdn.com.",
"img2021.navyfederal.org.",
"img9.target.com.",
- "imgc.nxjimg.com.",
"imghst-de.com.",
"imgs.signifyd.com.",
- "imodules.com.",
- "imoim.net.",
- "imolive2.com.",
"imotech.site.",
"imou-sg-ali-online-paas-iot-private-picture.oss-ap-southeast-1.aliyuncs.com.",
"imou-sg3-ali-online-paas-private-picture.oss-ap-southeast-1.aliyuncs.com.",
"imoulife.com.",
- "impacthero.co.",
+ "imp.admeking.com.",
+ "imp.adx.roockmobile.com.",
"impactify.media.",
"imptrk.siteplug.com.",
"in-api.asm.skype.com.",
@@ -2130,18 +2259,17 @@ var FakeECSFQDNs = container.NewMapSet(
"in.gov.",
"in.visitors.live.",
"inc-collabrtc.officeapps.live.com.",
- "inc-excel.officeapps.live.com.",
"indianapolis.remotepc.com.",
"inf.miui.com.",
- "informa.com.",
- "ingov.zendesk.com.",
+ "ingov.sharepoint.com.",
+ "init.clmbosean.space.",
"inneraudioms.cc.easebar.com.",
"innity.com.",
"innity.net.",
+ "ino.qq.com.",
"ins-tgrfs7t3.ias.tencent-cloud.net.",
- "inside-graph.com.cdn.cloudflare.net.",
"inskinad.com.",
- "inspidspad.com.",
+ "inspi-dsp.com.",
"inspirebrands-sync.quantummetric.com.",
"inspirebrands.quantummetric.com.",
"instantmessaging-pa-jms-ap.googleapis.com.",
@@ -2150,7 +2278,6 @@ var FakeECSFQDNs = container.NewMapSet(
"instantmessaging-pa-jms-us.googleapis.com.",
"instatus.com.",
"int.dpool.sina.com.cn.",
- "internal.engine.intl.mi.com.",
"internetdownloadmanager.com.",
"intl-im-conn.iq.com.",
"intuit.zoom.us.",
@@ -2160,16 +2287,18 @@ var FakeECSFQDNs = container.NewMapSet(
"iowa.remotepc.com.",
"ip-api.com.",
"ip.istatmenus.app.",
- "ip.remotepc.com.",
- "ipinyou.com.",
+ "ipfs.io.",
+ "iphonesubmissions.apple.com.",
+ "ipm.atm.youku.com.",
"iprofiles.apple.com.",
"iprom.net.",
"ipv4.cadc.absolute.com.",
+ "ipv4.geojs.io.",
+ "ipv4.sdiptest.com.",
"ipv4.tracker.harry.lu.",
+ "ipv6-4.sdiptest.com.",
"iq.com.",
"iscorp.com.",
- "ispeech.org.",
- "issuepcdn.freeterabox.com.",
"istanbul.remotepc.com.",
"istatmenus.app.",
"italynorth.api.cognitive.microsoft.com.",
@@ -2179,18 +2308,17 @@ var FakeECSFQDNs = container.NewMapSet(
"itemorder.com.",
"itm.cloud.com.",
"itoon.org.",
- "itunes.apple.com.edgekey.net.",
"itzmx.com.",
"ivalua.com.",
+ "ivt.np.community.playstation.net.",
"ivview.com.",
"ivview.net.",
"izatcloud.net.",
"jabfm.org.",
"japanwest.api.cognitive.microsoft.com.",
- "jbisumari.org.",
"jdcloud.com.",
- "jenzabarcloud.com.",
"jhahosted.com.",
+ "jishiyuchat.com.",
"johannesburg.remotepc.com.",
"jotfor.ms.",
"jp-prod.asyncgw.teams.microsoft.com.",
@@ -2200,18 +2328,19 @@ var FakeECSFQDNs = container.NewMapSet(
"jpost.com.",
"jpush.cn.",
"jpush.io.",
+ "jqueryui.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.aiservice.vn.",
"js.eruptr.io.",
+ "js.hs-analytics.net.",
"js.volumental.com.",
- "jsapi.lightboxcdn.com.",
- "jsdelivr.net.cdn.cloudflare.net.",
+ "jsdelivr.net.",
"jsonatm.broker.tplay.qq.com.",
"jss.starbucks.com.",
"jssprod-starbucks.trafficmanager.net.",
@@ -2229,11 +2358,11 @@ var FakeECSFQDNs = container.NewMapSet(
"k8s1-la-ext-haproxy.lb.indexww.com.",
"k8s1-ny-ext-haproxy.lb.indexww.com.",
"k8s1-sj-ext-haproxy.lb.indexww.com.",
+ "k8s1-va-ext-haproxy.lb.indexww.com.",
"kajicam.com.",
- "kamalaharris.com.",
+ "karmanow.com.",
"kelvin.education.",
"kiev.remotepc.com.",
- "kiprotect.com.",
"kirkland.zoom.us.",
"kiwisizing.com.",
"klagenfurt.remotepc.com.",
@@ -2251,7 +2380,10 @@ var FakeECSFQDNs = container.NewMapSet(
"kunlunhuf.com.",
"kunlunsl.com.",
"kunlunso.com.",
+ "kunvertads.com.",
+ "kurogame.xyz.",
"kwimgs.com.",
+ "kzhi.tech.",
"la.remotepc.com.",
"la1.chat.si.riotgames.com.",
"la10.remotepc.com.",
@@ -2262,11 +2394,11 @@ var FakeECSFQDNs = container.NewMapSet(
"la4.remotepc.com.",
"la8.remotepc.com.",
"la9.remotepc.com.",
+ "labtech.corcystems.com.",
"labtech.myitpros.com.",
"lahuashanbx.com.",
"lalapush.com.",
"lan.sdk.linkedin.com.",
- "landing.adobe.com.",
"lansing.remotepc.com.",
"lansweeper.com.",
"larksuite.com.",
@@ -2275,32 +2407,31 @@ var FakeECSFQDNs = container.NewMapSet(
"layerxsecurity.com.",
"lazpay-fe-kyc-module-file.oss-ap-southeast-1.aliyuncs.com.",
"ldap.google.com.",
+ "ldgslb.com.",
"ldmnq.com.",
+ "ldy.ieypg.com.",
"leadmanagerfx.com.",
"leihuo.netease.com.",
"leiniao.com.",
- "lenovomm.com.",
"levect.com.",
"level10gc.com.",
"leveldata.poki.io.",
"lexicon.33across.com.",
"lianmeng.360.cn.",
- "librarydaap.itunes.apple.com.",
"libretexts.org.",
"license.gonative.io.",
"license.litespeedtech.com.",
"license.unity3d.com.",
"licensing.bitmovin.com.",
- "licensing.sbullet.com.",
"lichess.org.",
"lightwidget.com.",
"likr.tw.",
- "lima-tpgateway3.factset.com.",
"lima.remotepc.com.",
"lineicons.com.",
"linguee.com.",
"link-ga-hz-azure.yunxinfw.com.",
"link-vision-picture-sg-v2.oss-ap-southeast-1.aliyuncs.com.",
+ "links.officedepot.com.mx.",
"lisbon.remotepc.com.",
"lissabon.remotepc.com.",
"list.tronlink.org.",
@@ -2309,34 +2440,39 @@ var FakeECSFQDNs = container.NewMapSet(
"litespeedtech.com.",
"live.126.net.",
"live.ngb.haplat.net.",
- "live.shopee.com.br.",
"live2.ngb.haplat.net.",
"live3.ngb.haplat.net.",
"live4.ngb.haplat.net.",
"live5.ngb.haplat.net.",
"live6.ngb.haplat.net.",
"livect.haplat.net.",
- "livekilleenisd.sharepoint.com.",
+ "livedmpsk12ia.sharepoint.com.",
+ "liveoversea10.ngb.haplat.net.",
+ "liveoversea5.ngb.haplat.net.",
+ "liveoversea6.ngb.haplat.net.",
+ "liveoversea7.ngb.haplat.net.",
+ "liveoversea8.ngb.haplat.net.",
+ "liveoversea9.ngb.haplat.net.",
"ljubljana.remotepc.com.",
"loandepot.zoom.us.",
"local.adguard.org.",
"local.info.g9hc4.cn.",
"log-api.newrelic.com.cdn.cloudflare.net.",
- "log-yex.youdao.com.",
+ "log-auth.zztfly.com.",
"log.getadblock.com.",
"log.webmaxlogger.net.",
"log.zoom.us.",
"log1.cmpassport.com.",
"log2.cmpassport.com.",
- "log22-normal-alisg.tiktokv.com.",
- "logger.moviead55.ru.",
"logging-service-prod.getepic.com.",
"logging.mp.lura.live.",
+ "loggly.com.",
+ "login.newrelic.com.",
"login.teamviewer.com.",
"login.vivaldi.net.",
+ "logs.impactify.media.",
"logs2.sportslocalmedia.com.",
"logu.hpplay.cn.",
- "logus.xiaoyi.com.",
"logx.optimizely.com.",
"lol.sw.game.qq.com.",
"london.remotepc.com.",
@@ -2348,17 +2484,14 @@ var FakeECSFQDNs = container.NewMapSet(
"london8.remotepc.com.",
"long.tv.",
"look.360.cn.",
- "love8.ltd.",
"lpa.ds.gsma.com.",
"lplfinancial.app.box.com.",
- "lptkw.s4xx6.com.",
"lsagentrelay.lansweeper.com.",
"ltfl.librarything.com.",
"ludashi.com.",
"luxembourg.remotepc.com.",
"lycraservice-pa-cam-prod.googleapis.com.",
"lyric.alarmnet.com.",
- "m.sogo.com.",
"m1.ubianet.com.",
"m110601-fcdn.mp.lura.live.",
"m2.ubianet.com.",
@@ -2366,27 +2499,29 @@ var FakeECSFQDNs = container.NewMapSet(
"m4.ubianet.com.",
"m5.ubianet.com.",
"m6.ubianet.com.",
+ "ma.officedepot.com.",
+ "macarne.com.",
"macclog-as.rj.link.",
"madrid.remotepc.com.",
"maers.adrs.org.cn.",
+ "magic.link.",
"magichue.net.",
- "magna.com.",
"maidenhead.remotepc.com.",
"mail.superhuman.com.",
"mailinblue.com.",
+ "main.clmbosean.space.",
"maintenanceconnection.com.",
- "makerbot.com.",
"malware-filter.gitlab.io.",
"mam.manage.microsoft.us.",
- "mam.netease.com.",
+ "manage-selfhost.microsoft.com.",
"manage.wix.com.",
"management.azure.com.",
"management.privatelink.azure.com.",
"manassas.remotepc.com.",
"manchester.remotepc.com.",
+ "marketingassets.staples.com.",
"marmot-cloud.com.",
"marseille.remotepc.com.",
- "masonitecloud-my.sharepoint.com.",
"master1.teamviewer.com.",
"master10.teamviewer.com.",
"master11.teamviewer.com.",
@@ -2406,15 +2541,15 @@ var FakeECSFQDNs = container.NewMapSet(
"match.adfarm1.adition.com.",
"matetranslate.com.",
"matrix.netease.com.",
- "maumeredegale.wixsite.com.",
"max-l.mediav.com.",
"mbboauth-1c.prd.cn.vwg-connect.cn.",
"mcallen.remotepc.com.",
"mcds.dalyfeds.com.",
- "mclarenhealth.sharepoint.com.",
"mcount.easebar.com.",
"mdap.tngdigital.com.my.",
+ "mdiasrv.com.cdn.cloudflare.net.",
"mdlg.pb13bonnie.com.",
+ "mdp-upgrade-cn.heytapmobi.com.",
"meari-oss-us.oss-us-west-1.aliyuncs.com.",
"meari-us.oss-us-west-1.aliyuncs.com.",
"medellin.remotepc.com.",
@@ -2423,7 +2558,7 @@ var FakeECSFQDNs = container.NewMapSet(
"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-atl3-3.cdn.whatsapp.net.",
"media-bog2-1.cdn.whatsapp.net.",
"media-bog2-2.cdn.whatsapp.net.",
"media-bos5-1.cdn.whatsapp.net.",
@@ -2438,14 +2573,11 @@ var FakeECSFQDNs = container.NewMapSet(
"media-dfw5-1.cdn.whatsapp.net.",
"media-dfw5-2.cdn.whatsapp.net.",
"media-dus1-1.cdn.whatsapp.net.",
- "media-for1-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-gateway.mlb.com.",
"media-gig4-1.cdn.whatsapp.net.",
- "media-gig4-2.cdn.whatsapp.net.",
"media-gru1-1.cdn.whatsapp.net.",
"media-gru1-2.cdn.whatsapp.net.",
"media-gru2-1.cdn.whatsapp.net.",
@@ -2461,7 +2593,6 @@ var FakeECSFQDNs = container.NewMapSet(
"media-iad3-1.cdn.whatsapp.net.",
"media-iad3-2.cdn.whatsapp.net.",
"media-ist1-1.cdn.whatsapp.net.",
- "media-ist1-2.cdn.whatsapp.net.",
"media-kul2-1.cdn.whatsapp.net.",
"media-kul2-2.cdn.whatsapp.net.",
"media-kul3-1.cdn.whatsapp.net.",
@@ -2490,51 +2621,38 @@ var FakeECSFQDNs = container.NewMapSet(
"media-qro1-2.cdn.whatsapp.net.",
"media-scl2-1.cdn.whatsapp.net.",
"media-sea1-1.cdn.whatsapp.net.",
+ "media-sin11-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-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.defense.gov.",
- "media.pa.betrivers.com.",
+ "media.expedia.com.",
"media.ringcentral.com.",
- "media.subway.com.",
"media.superhuman.com.",
- "media.united.com.",
+ "media.tinkoff.ru.",
+ "mediafuse.com.",
"mediav.com.",
- "medicinetechnet.com.",
"melbourne.remotepc.com.",
- "member.virginpulse.com.",
"memphis.remotepc.com.",
- "mercadolibre.com.ar.",
- "messages.indeed.com.",
+ "metadata.decagon.ai.",
"metric.picodiglobal.com.",
"metrics-dre.dt.dbankcloud.cn.",
"metrics-dre.dt.dbankcloud.com.",
"metrics-dre.dt.hihonorcloud.com.",
"metrics5.data.hicloud.com.",
"mexicocity.remotepc.com.",
- "mf.b37mrtl.ru.",
"mgbsdknaeast.matrix.easebar.com.",
"mgspabst.prismray.io.",
"mgspfacts.prismray.io.",
"mgsphdr1.prismray.io.",
- "mgspmess.prismray.io.",
"mgsppres.prismray.io.",
"mgsppros1.prismray.io.",
- "mgsppros2.prismray.io.",
- "mgsppush.prismray.io.",
- "mgspsc.prismray.io.",
"mgsptele.prismray.io.",
- "mgspturn.prismray.io.",
"mgtv.com.",
"miami.remotepc.com.",
"miami2.remotepc.com.",
@@ -2544,18 +2662,17 @@ var FakeECSFQDNs = container.NewMapSet(
"microad.jp.",
"microvirt.com.",
"mid4.linkedin.com.",
- "midfield.mlbstatic.com.",
"migu.cn.",
"milan.remotepc.com.",
- "milestoneinternet.com.cdn.cloudflare.net.",
- "milwaukeetool.com.",
"mimir2.vivaldi.com.",
"min-api.cryptocompare.com.",
"mini.browser.360.cn.",
"minigame.vip.",
"mintkeyboard.com.",
"mixi.media.",
+ "mlmannouncements.pearson.com.",
"mmods.site.",
+ "mobile-bank.cdn-tinkoff.ru.",
"mobile-collector.newrelic.com.cdn.cloudflare.net.",
"mobile-l7.bereal.com.",
"mobile-protect-api.securetheorem.com.",
@@ -2564,16 +2681,16 @@ var FakeECSFQDNs = container.NewMapSet(
"mobiledataplan-pa.googleapis.com.",
"mobilemaps-pa-gz.googleapis.com.",
"mobilemaps.googleapis.com.",
- "mobydix.com.",
+ "mobilesecuritycore-cdn.norton.com.edgekey.net.",
"modelportrait.xiaohongshu.com.",
"modesto.remotepc.com.",
- "mon0-misc-hl.amemv.com.",
"moni-onrt-stsdk.vivo.com.cn.",
"monitoring.getelevar.com.",
"monitoring.worksighted.com.",
"montage-updates.displaynote.com.",
"monticello.remotepc.com.",
"montreal.remotepc.com.",
+ "monumetric.com.",
"morningstar.zoom.us.",
"motiondetection-us-1d.oss-us-west-1.aliyuncs.com.",
"motiondetection-us-7d.oss-us-west-1.aliyuncs.com.",
@@ -2581,21 +2698,24 @@ var FakeECSFQDNs = container.NewMapSet(
"mouser.com.",
"mp.360.cn.",
"mrisoftware.com.",
+ "ms.applvn.com.",
"ms1app.pb.com.",
- "msch.f.360.cn.",
"msdl.microsoft.com.",
- "mservices.navyfcu.org.",
"msf.3g.qq.com.",
"msg-img-hk.oss-cn-hongkong.aliyuncs.com.",
- "msync-im1-sgp-ga.easemob.com.",
+ "msg.cmpassport.com.",
"mtrace.qq.com.",
"mumbai.remotepc.com.",
"munich.remotepc.com.",
- "muscache.cn.",
+ "music.163.com.",
+ "music.163.com.163jiasu.com.",
+ "musical.ly.",
"musicps.p2p.qq.com.",
"musicpunch.p2p.qq.com.",
"musicstylingonline.com.",
"mw.footballbros.io.",
+ "mw.mw2.global.",
+ "mweb-hb.presage.io.",
"mx-vcode-od.vivoglobal.com.",
"mx.amx.rcs.telephony.goog.",
"mxp-pusa01.app.blackbaud.net.",
@@ -2604,30 +2724,29 @@ var FakeECSFQDNs = container.NewMapSet(
"my.dealersocket.com.",
"my.getadmiral.com.",
"my.jbi.global.",
+ "my.microsoftpersonalcontent.com.",
"my.nalpeiron.com.",
"myim3banner.kloc.co.",
"myisolved.com.",
- "myou.cvte.com.",
"myporn.club.",
"myqcloud.com.",
"mystery-game-tile.poki.io.",
"myvscloud.com.",
"myworkdaycdn.com.cn.",
- "n13.ultipro.com.",
- "n21.ultipro.com.",
- "n21c.ultipro.com.",
"n33.ultipro.com.",
"n35.ultipro.com.",
- "na113.epm.cyberark.com.",
- "na121.epm.cyberark.com.",
+ "na120.epm.cyberark.com.",
"na2.chat.si.riotgames.com.",
"nab.com.au.",
"najva.com.",
"namequery.com.",
+ "nanoleaf.me.",
"naperville.remotepc.com.",
"nashville.remotepc.com.",
- "nationalmap.gov.",
+ "nationalreview.com.",
"nativecos.com.",
+ "nc-pod1-smp-device.apple.com.",
+ "nc-pod5-smp-device.apple.com.",
"nc.com.",
"ncentral.centrexit.com.",
"nearme.com.cn.",
@@ -2655,19 +2774,17 @@ var FakeECSFQDNs = container.NewMapSet(
"newyork3.remotepc.com.",
"nex.163.com.",
"nexstar.amp.permutive.com.",
+ "nextinsure.com.",
"nexx360.io.",
"ng1.angus.mrisoftware.com.",
"ngb.haplat.net.",
"nice-team.net.",
"nie.netease.com.",
- "niemanlab.org.",
- "nieuwsblad.be.",
"nist.gov.",
"nitroapps.co.",
"nitropay.com.",
"noc.computerhelpnj.com.",
"node.setupad.com.",
- "nodejs.org.",
"nokia.com.",
"nordcurrent.com.",
"norma-external-collect.meizu.com.",
@@ -2676,8 +2793,10 @@ var FakeECSFQDNs = container.NewMapSet(
"norwayeast.api.cognitive.microsoft.com.",
"notes-analytics-events.apple.com.",
"notes.services.box.com.",
+ "notification889.com.",
+ "notify.music.163.com.",
"novaicare.com.",
- "novel.itoon.org.",
+ "npmjs.com.",
"nps.gov.",
"ns-cloud-a1.googledomains.com.",
"ns-cloud-a2.googledomains.com.",
@@ -2703,6 +2822,7 @@ var FakeECSFQDNs = container.NewMapSet(
"ns.identrust.com.",
"ns0105.secondary.cloudflare.com.",
"ns0160.secondary.cloudflare.com.",
+ "ns1.a0.impervasecuredns.net.",
"ns1.cloudflare.net.",
"ns1.g.aaplimg.com.",
"ns1.google.com.",
@@ -2724,7 +2844,6 @@ var FakeECSFQDNs = container.NewMapSet(
"ntes53.netease.com.",
"ntp.aliyun.com.",
"ntp.arlo.com.",
- "ntp.arlo.com.cdn.cloudflare.net.",
"ntp.org.cn.",
"ntp1.aliyun.com.",
"ntp1.huan.tv.",
@@ -2736,48 +2855,52 @@ var FakeECSFQDNs = container.NewMapSet(
"nuremberg.remotepc.com.",
"nv.gov.",
"nvu-prd.mqtt.ivanticloud.com.",
+ "nvz-prd-apim.ivanticloud.com.",
"nwr.mmcdn.com.",
"nwr.static.mmcdn.com.",
"nws-platform.zoom.us.",
"nwsalert.onelouder.com.",
"nycourts.gov.",
"nycrt.marphezis.com.",
- "oauth.gov.online.office365.us.",
- "oauth.ring.com.cdn.cloudflare.net.",
+ "o.quizlet.com.",
+ "oauth.ws.sonos.com.",
"obihai.telephony.goog.",
"obs.ap-southeast-3.myhuaweicloud.com.",
"observability-l7.bereal.com.",
+ "observability.bereal.com.",
"obsproject.com.",
"obus-dc20058-cn.heytapmobi.com.",
"obus-dc20123-cn.heytapmobi.com.",
+ "obus-dc20157-cn.heytapmobi.com.",
"obus-dctech-cn.heytapmobi.com.",
"oclc.org.",
"ocloud.oppomobile.com.",
- "ocmant.com.",
"ocps-xfer.kronos.net.",
- "ocsp.comodoca.com.",
- "ocsp.entrust.net.",
"ocsp.identrust.com.",
- "octaneai.com.",
+ "octossp.com.",
"odrs.fda.gov.ph.",
"odw7bf.dood.video.",
"oec22-normal-alisg.tokopediax.com.",
+ "oec22-normal-useast2a.tiktokv.com.",
"office.microsoft.com.",
- "officepreviewredir.microsoft.com.",
+ "officeathand.att.com.",
"ogma-l7.bereal.com.",
"ogma.bereal.com.",
+ "ojp.gov.",
"okko.tv.",
"ollama.com.",
"omaha.formlabs.com.",
"omiapp.me.",
"omitech.site.",
"omnibus.gm.com.",
+ "omt.garmin.com.",
"on-hwapps-o.api.leiniao.com.",
- "on-hweudc-conf-o.api.leiniao.com.",
+ "one.newrelic.com.",
"onekey1.cmpassport.com.",
"oneplus.net.",
"onethingpcs.com.",
"onezapp.com.",
+ "online-stopwatch.com.",
"onlinewebfonts.com.",
"op.mykonf.com.",
"opamarketplace.com.",
@@ -2786,16 +2909,17 @@ var FakeECSFQDNs = container.NewMapSet(
"opencmp.net.",
"opendsp.ru.",
"openrice.com.",
- "operationchicken.com.",
"opex-service-cn.allawntech.com.",
"oppo.com.",
+ "oppomobile.com.",
"optimize.ulinq.asia.",
"optimize.urekamedia.com.",
"optimizely.com.",
+ "orangehire.com.au.",
"oregon.remotepc.com.",
- "origin.com.",
"origin.fe-image-cache-ttp.useast8.byteglb.com.",
"orlando.remotepc.com.",
+ "ort.stsdk.vivo.com.cn.",
"os7lm.6kvses.com.",
"osaka.remotepc.com.",
"oss-ap-southeast-1.aliyuncs.com.",
@@ -2817,11 +2941,16 @@ var FakeECSFQDNs = container.NewMapSet(
"overseasccl-major-b.haplat.net.",
"overseasccl-major-c.haplat.net.",
"ovh.maxhost.io.",
+ "ovidsp.ovid.com.",
"p.adlooxtracking.com.",
+ "p.teads.tv.",
"p0-pu-private-useast8.tiktokv.us.",
"p107609.cedexis-test.com.",
"p109522.cedexis-test.com.",
- "p16-buy.itunes.apple.com.",
+ "p11-buy.itunes.apple.com.",
+ "p12-buy.itunes.apple.com.",
+ "p13.zdusercontent.com.",
+ "p2-buy.itunes.apple.com.",
"p20304.cedexis-test.com.",
"p20305.cedexis-test.com.",
"p20306.cedexis-test.com.",
@@ -2831,6 +2960,7 @@ var FakeECSFQDNs = container.NewMapSet(
"p20311.cedexis-test.com.",
"p20314.cedexis-test.com.",
"p20315.cedexis-test.com.",
+ "p26-buy.itunes.apple.com.",
"p2p-cal-2.anker-in.com.",
"p2p-cal-3.anker-in.com.",
"p2p-cal.anker-in.com.",
@@ -2840,8 +2970,8 @@ var FakeECSFQDNs = container.NewMapSet(
"p2p2.cloudbirds.cn.",
"p2p3.cloudbirds.cn.",
"p2pm-ali.reolink.com.",
+ "p3-buy.itunes.apple.com.",
"p30605.cedexis-test.com.",
- "p33-buy.itunes.apple.com.",
"p33231.cedexis-test.com.",
"p33236.cedexis-test.com.",
"p33242.cedexis-test.com.",
@@ -2859,11 +2989,10 @@ var FakeECSFQDNs = container.NewMapSet(
"p35883.cedexis-test.com.",
"p38635.cedexis-test.com.",
"p39604.cedexis-test.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.",
@@ -2877,11 +3006,11 @@ var FakeECSFQDNs = container.NewMapSet(
"p48434.cedexis-test.com.",
"p48435.cedexis-test.com.",
"p48436.cedexis-test.com.",
- "p49-buy.itunes.apple.com.",
"p4p.arenabg.com.",
- "p50-buy.itunes.apple.com.",
"p52066.cedexis-test.com.",
"p56745.cedexis-test.com.",
+ "p70-buy.itunes.apple.com.",
+ "p71-buy.itunes.apple.com.",
"p76593.cedexis-test.com.",
"p86075.cedexis-test.com.",
"p86077.cedexis-test.com.",
@@ -2898,11 +3027,13 @@ var FakeECSFQDNs = container.NewMapSet(
"partnerboost.com.",
"pasadena.remotepc.com.",
"passportalmsp.com.",
+ "pat-issuer.cloudflare.com.",
"payment.api.speechify.com.",
"payment.omiapp.me.",
"pbdlsp1.pb.com.",
"pbe1.chat.si.riotgames.com.",
"pbs.btloader.com.",
+ "pc-store-lb.lenovomm.cn.",
"pc-store.lenovomm.cn.",
"pc.crashsight.wetest.net.",
"pc.perfsight.wetest.net.",
@@ -2910,20 +3041,23 @@ var FakeECSFQDNs = container.NewMapSet(
"pd.cdnwidget.com.",
"pdf24.org.",
"pdfforge.org.",
+ "peloton.netlifyglobalcdn.com.",
+ "penngaming-my.sharepoint.com.",
"peopleadmin.com.",
"perf-eu1.hsforms.com.",
- "perfops2.byte-test.com.",
"perfsight.qq.com.",
"perfsight.wetest.net.",
+ "perkspot-api.perkspot.com.",
"permutive.arstechnica.com.",
"permutive.businessinsider.com.",
- "permutive.com.",
+ "permutive.newyorker.com.",
"perr.brightvpn.com.",
"pf.intuit.com.",
"pharos.studyquicks.com.",
"phoenix.remotepc.com.",
"phoenix2.remotepc.com.",
"phonebridge.zoho.com.",
+ "phonepower.com.",
"photoroom.com.",
"phx02pap002.storage.live.com.",
"phx02pap003.storage.live.com.",
@@ -2932,15 +3066,15 @@ var FakeECSFQDNs = container.NewMapSet(
"phx02pap006.storage.live.com.",
"phx02pap008.storage.live.com.",
"pi2850.ci.managedwhitelisting.com.",
- "piano.io.",
"pic.rutubelist.ru.",
- "pics.ebaystatic.com.",
+ "picodiglobal.com.",
+ "piicmgvmss.polaris.com.",
"pikabu.ru.",
+ "pin.apiblink.ru.",
"ping.getadblock.com.",
"pingler.com.",
"pingma.qq.com.",
"pingmesh.bigo.sg.",
- "piojm.tech.",
"pitk.unioneeu.com.",
"pittsburgh.remotepc.com.",
"pix.cdnwidget.com.",
@@ -2952,38 +3086,44 @@ var FakeECSFQDNs = container.NewMapSet(
"planner.cloud.microsoft.",
"platform-alib.linkedin.cn.",
"platform-alib.linkedin.cn.w.kunlunaq.com.",
+ "platform.foxitcloud.com.",
+ "playercdn.jivox.com.cdn.cloudflare.net.",
"playstream.media.",
"plrm.zone.",
"pm.geniusmonkey.com.",
+ "podcastswaves.com.",
"poizon.com.",
"polandcentral.api.cognitive.microsoft.com.",
"polling.zoom.us.",
- "polyfill.archive.org.",
+ "polymarket.com.",
+ "poopstream.co.",
"pop-convert.com.",
"popt.in.",
- "portal.discover.com.",
"portal.us.ubianet.com.",
+ "portals.mobi.",
"portland.remotepc.com.",
"posthog.com.",
+ "potatovpn.com.",
"pov.spectrum.net.",
"powerpoint-collab.officeapps.live.com.",
- "powerschool.com.",
+ "pp.ringcentral.biz.",
"ppgames.net.",
"ppos.com.",
- "pptservicescast.gcc.osi.office365.us.",
- "pragmaticplay.net.",
"prebid-la.casalemedia.com.",
"prebid-ny.casalemedia.com.",
"prebid-va.casalemedia.com.",
"prebid.trustedstack.com.",
"prebidserver.pixfuture.com.",
+ "premierhealth-my.sharepoint.com.",
"premium.xvpn.io.",
- "prepareplanes.com.",
"printaudit.com.",
"printfriendly.com.",
+ "prism.app-us1.com.",
+ "privy.io.",
"pro-glswish-aks-tm.trafficmanager.net.",
"pro-swishapps-aks-tm.trafficmanager.net.",
"procore.com.",
+ "prod-catalog-product-api.dickssportinggoods.com.",
"prod-client-api.v.aaplimg.com.",
"prod-default.lb.logrocket.network.",
"prod-event-relay-api.v.aaplimg.com.",
@@ -2992,24 +3132,20 @@ var FakeECSFQDNs = container.NewMapSet(
"prod-event-relay-sports-api.v.aaplimg.com.",
"prod-event-relay-stocks-api.v.aaplimg.com.",
"prod-event-relay-weather-api.v.aaplimg.com.",
+ "prod-frs.content.classy.org.",
"prod-newsletter-edge.v.aaplimg.com.",
"prod-tasks.trafficmanager.net.",
"prod-weather-widget-event-gateway.v.aaplimg.com.",
"prod.api.letsencrypt.org.",
- "prod.do.dsp.mp.microsoft.com.edgekey.net.",
"production.kabutoservices.com.",
- "profile.indeed.com.",
- "profiler-collector.dalyfeds.com.",
+ "prolearning.nwea.org.",
"proquest.com.",
"protonvpn.com.",
"provaltech.com.",
"proxy-safebrowsing.googleapis.com.",
"proxy.mob.maps.yandex.net.",
"ps.namequery.com.",
- "psnobj.prod.dl.playstation.net.",
- "psyche.co.",
"pub.affilimateapis.com.",
- "pub.doubleverify.com.cdn.cloudflare.net.",
"pub.network.",
"public-api.uxfeedback.ru.",
"publicfaas.vasdgame.com.",
@@ -3017,7 +3153,9 @@ var FakeECSFQDNs = container.NewMapSet(
"puffer.6.401402081.west-gcloud.codm.activision.com.",
"pull-flv-f58-tt03.fcdn.eu.tiktokcdn.com.",
"punch.p2p.qq.com.",
+ "push-ads-cn.heytapmobi.com.",
"push-row.zui.com.",
+ "push.bitdefender.net.",
"push.omiapp.me.",
"pushcrew.com.",
"pushimg.com.",
@@ -3032,12 +3170,14 @@ var FakeECSFQDNs = container.NewMapSet(
"qagpublic.qg1.apps.qualys.co.uk.",
"qagpublic.qg1.apps.qualys.com.",
"qagpublic.qg1.apps.qualys.eu.",
+ "qagpublic.qg1.apps.qualys.in.",
"qagpublic.qg2.apps.qualys.com.",
"qagpublic.qg2.apps.qualys.eu.",
"qagpublic.qg3.apps.qualys.com.",
"qagpublic.qg4.apps.qualys.com.",
"qatarcentral.api.cognitive.microsoft.com.",
"qc-static.coccoc.com.",
+ "qcloud.com.",
"qfp.intuit.com.",
"qiezibenpao.com.",
"qinglong.me.",
@@ -3045,14 +3185,18 @@ var FakeECSFQDNs = container.NewMapSet(
"qiniup.com.",
"qiyukf.com.",
"qookkagames.com.",
+ "qortex.ai.",
+ "qpic.cn.",
"qualcomm.cn.",
"qualcomm.com.",
"qualys.ca.",
"qualys.com.",
"qualys.eu.",
- "quantamagazine.org.",
+ "qualys.in.",
+ "quantil.com.",
"quantummetric.com.",
"quebeccity.remotepc.com.",
+ "questionai.com.",
"quicinc.com.",
"quickcep.com.",
"qxwz.com.",
@@ -3061,7 +3205,6 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -3069,63 +3212,69 @@ var FakeECSFQDNs = container.NewMapSet(
"r.lr-intake.com.",
"r.lrkt-in.com.",
"r.superhuman.com.",
- "r1---sn-2imeyn7k.c.2mdn.net.",
- "r1---sn-a5meknzk.c.2mdn.net.",
- "r1---sn-a5mlrnls.c.2mdn.net.",
- "r1---sn-a5mlrnlz.c.2mdn.net.",
- "r1---sn-ab5l6ndr.c.2mdn.net.",
+ "r1---sn-a5msenle.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-ab5l6nrr.c.2mdn.net.",
+ "r1---sn-ab5l6nrs.c.2mdn.net.",
"r1---sn-ab5l6nrz.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-ab5sznzr.c.2mdn.net.",
"r1---sn-ab5sznzs.c.2mdn.net.",
"r1---sn-ab5sznzy.c.2mdn.net.",
"r1---sn-ab5sznzz.c.2mdn.net.",
"r1---sn-ajab55-55.c.2mdn.net.",
+ "r1---sn-jxopj-nh4e.googlevideo.com.",
+ "r1---sn-nh5gujvh-h4xe.googlevideo.com.",
+ "r1---sn-o097znsr.c.2mdn.net.",
+ "r1---sn-p5qddn76.c.2mdn.net.",
+ "r1---sn-p5qddn7d.c.2mdn.net.",
"r1---sn-p5qddn7r.c.2mdn.net.",
+ "r1---sn-p5qlsn6l.c.2mdn.net.",
"r1---sn-p5qlsn7l.c.2mdn.net.",
- "r1---sn-p5qs7n6d.c.2mdn.net.",
+ "r1---sn-p5qlsnrl.c.2mdn.net.",
+ "r1---sn-p5qlsnrr.c.2mdn.net.",
"r1---sn-p5qs7nsk.c.2mdn.net.",
- "r1---sn-q4fl6n66.c.2mdn.net.",
+ "r1---sn-p5qs7nzr.c.2mdn.net.",
"r1---sn-q4fl6n6d.c.2mdn.net.",
"r1---sn-q4fl6nd7.c.2mdn.net.",
- "r1---sn-q4fl6ndl.c.2mdn.net.",
- "r1---sn-q4fl6ns7.c.2mdn.net.",
- "r1---sn-q4fl6nsd.c.2mdn.net.",
"r1---sn-q4fl6nsk.c.2mdn.net.",
- "r1---sn-q4fl6nsr.c.2mdn.net.",
- "r1---sn-q4fl6nz7.c.2mdn.net.",
- "r1---sn-q4flrnee.c.2mdn.net.",
- "r1---sn-q4flrnsk.c.2mdn.net.",
+ "r1---sn-q4flrne7.c.2mdn.net.",
+ "r1---sn-q4flrner.c.2mdn.net.",
+ "r1---sn-q4flrnez.c.2mdn.net.",
+ "r1---sn-q4flrnlz.c.2mdn.net.",
"r1---sn-q4flrnsl.c.2mdn.net.",
- "r1---sn-q4fzen7l.c.2mdn.net.",
+ "r1---sn-q4fzene7.c.2mdn.net.",
+ "r1---sn-vgqskn66.c.2mdn.net.",
"r1---sn-vgqskn67.c.2mdn.net.",
"r1---sn-vgqskn6d.c.2mdn.net.",
- "r1---sn-vgqskne6.c.2mdn.net.",
+ "r1---sn-vgqskn6s.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-vgqsknze.c.2mdn.net.",
- "r1---sn-vgqsknzk.c.2mdn.net.",
+ "r1---sn-vgqsknzl.c.2mdn.net.",
+ "r1---sn-vgqsknzs.c.2mdn.net.",
"r1---sn-vgqsknzy.c.2mdn.net.",
- "r1---sn-vgqsknzz.c.2mdn.net.",
+ "r1---sn-vgqsrn6e.c.2mdn.net.",
+ "r1---sn-vgqsrn6l.c.2mdn.net.",
+ "r1---sn-vgqsrne6.c.2mdn.net.",
+ "r1---sn-vgqsrnez.c.2mdn.net.",
+ "r1---sn-vgqsrnl6.c.2mdn.net.",
"r1---sn-vgqsrnld.c.2mdn.net.",
- "r1---sn-vgqsrnsy.c.2mdn.net.",
+ "r1---sn-vgqsrnsd.c.2mdn.net.",
+ "r1---sn-vgqsrnz7.c.2mdn.net.",
"r1---sn-vgqsrnzd.c.2mdn.net.",
- "r1---sn-vgqsrnzr.c.2mdn.net.",
+ "r1---sn-vgqsrnzs.c.2mdn.net.",
"r1---sn-vgqsrnzz.c.2mdn.net.",
+ "r1---sn-voxoxu-v3jl.googlevideo.com.",
+ "r1---sn-voxoxu-v3js.googlevideo.com.",
"r2---sn-2napbiu-p5ie.gvt1.com.",
- "r2---sn-a5mekndz.c.2mdn.net.",
- "r2---sn-ab5l6ndr.c.2mdn.net.",
+ "r2---sn-a5mekn6d.c.2mdn.net.",
"r2---sn-ab5l6nk6.c.2mdn.net.",
"r2---sn-ab5l6nkd.c.2mdn.net.",
"r2---sn-ab5l6nr6.c.2mdn.net.",
@@ -3134,216 +3283,238 @@ var FakeECSFQDNs = container.NewMapSet(
"r2---sn-ab5l6nrl.c.2mdn.net.",
"r2---sn-ab5l6nrr.c.2mdn.net.",
"r2---sn-ab5l6nrs.c.2mdn.net.",
+ "r2---sn-ab5l6nrz.c.2mdn.net.",
"r2---sn-ab5sznz6.c.2mdn.net.",
"r2---sn-ab5sznzd.c.2mdn.net.",
+ "r2---sn-ab5sznze.c.2mdn.net.",
"r2---sn-ab5sznzk.c.2mdn.net.",
"r2---sn-ab5sznzl.c.2mdn.net.",
"r2---sn-ab5sznzr.c.2mdn.net.",
"r2---sn-ab5sznzs.c.2mdn.net.",
"r2---sn-ab5sznzy.c.2mdn.net.",
"r2---sn-ab5sznzz.c.2mdn.net.",
- "r2---sn-nx57ynsk.c.2mdn.net.",
+ "r2---sn-ajab55-55.c.2mdn.net.",
+ "r2---sn-hp57ynly.c.2mdn.net.",
+ "r2---sn-jxopj-nh4e.googlevideo.com.",
+ "r2---sn-nh5gujvh-h4xe.googlevideo.com.",
+ "r2---sn-npoldn7z.c.2mdn.net.",
"r2---sn-p5qddn7z.c.2mdn.net.",
- "r2---sn-p5qlsn6l.c.2mdn.net.",
- "r2---sn-p5qs7n6d.c.2mdn.net.",
- "r2---sn-p5qs7nsk.c.2mdn.net.",
+ "r2---sn-p5qlsn7s.c.2mdn.net.",
+ "r2---sn-p5qs7nsr.c.2mdn.net.",
+ "r2---sn-p5qs7nzy.c.2mdn.net.",
+ "r2---sn-q4fl6n66.c.2mdn.net.",
"r2---sn-q4fl6n6d.c.2mdn.net.",
- "r2---sn-q4fl6nz6.c.2mdn.net.",
- "r2---sn-q4flrn7r.c.2mdn.net.",
- "r2---sn-q4flrne7.c.2mdn.net.",
- "r2---sn-q4flrnl7.c.2mdn.net.",
- "r2---sn-q4flrnsk.c.2mdn.net.",
+ "r2---sn-q4fl6nsk.c.2mdn.net.",
+ "r2---sn-q4fl6nsr.c.2mdn.net.",
+ "r2---sn-q4flrnlz.c.2mdn.net.",
"r2---sn-q4flrnsl.c.2mdn.net.",
- "r2---sn-q4flrnss.c.2mdn.net.",
"r2---sn-q4fzen7l.c.2mdn.net.",
- "r2---sn-q4fzen7y.c.2mdn.net.",
+ "r2---sn-q4fzene7.c.2mdn.net.",
"r2---sn-q4fzenee.c.2mdn.net.",
- "r2---sn-vgqskn66.c.2mdn.net.",
- "r2---sn-vgqskn67.c.2mdn.net.",
+ "r2---sn-vgqskn6s.c.2mdn.net.",
+ "r2---sn-vgqskn6z.c.2mdn.net.",
"r2---sn-vgqsknld.c.2mdn.net.",
- "r2---sn-vgqsknly.c.2mdn.net.",
"r2---sn-vgqsknlz.c.2mdn.net.",
- "r2---sn-vgqsknse.c.2mdn.net.",
"r2---sn-vgqsknsk.c.2mdn.net.",
"r2---sn-vgqsknze.c.2mdn.net.",
- "r2---sn-vgqsknzs.c.2mdn.net.",
- "r2---sn-vgqsknzy.c.2mdn.net.",
+ "r2---sn-vgqsknzl.c.2mdn.net.",
"r2---sn-vgqsknzz.c.2mdn.net.",
- "r2---sn-vgqsrn66.c.2mdn.net.",
"r2---sn-vgqsrn67.c.2mdn.net.",
- "r2---sn-vgqsrned.c.2mdn.net.",
+ "r2---sn-vgqsrn6e.c.2mdn.net.",
"r2---sn-vgqsrnld.c.2mdn.net.",
- "r2---sn-vgqsrnlk.c.2mdn.net.",
- "r2---sn-vgqsrnsd.c.2mdn.net.",
+ "r2---sn-vgqsrnlz.c.2mdn.net.",
"r2---sn-vgqsrnsr.c.2mdn.net.",
+ "r2---sn-vgqsrnsy.c.2mdn.net.",
"r2---sn-vgqsrnz7.c.2mdn.net.",
+ "r2---sn-vgqsrnzd.c.2mdn.net.",
+ "r2---sn-vgqsrnzk.c.2mdn.net.",
"r2---sn-vgqsrnzr.c.2mdn.net.",
- "r2---sn-vgqsrnzz.c.2mdn.net.",
- "r3---sn-2imern76.c.2mdn.net.",
- "r3---sn-2imeyn7k.c.2mdn.net.",
+ "r2---sn-voxoxu-v3jl.googlevideo.com.",
+ "r2---sn-voxoxu-v3js.googlevideo.com.",
+ "r2-t.trackedlink.net.",
"r3---sn-2napbiu-p5ie.gvt1.com.",
"r3---sn-a5mekn6r.c.2mdn.net.",
- "r3---sn-a5mlrnl6.c.2mdn.net.",
+ "r3---sn-a5meknzl.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-ab5sznzr.c.2mdn.net.",
"r3---sn-ab5sznzs.c.2mdn.net.",
"r3---sn-ab5sznzy.c.2mdn.net.",
- "r3---sn-npoe7ndl.c.2mdn.net.",
- "r3---sn-nx57ynsk.c.2mdn.net.",
+ "r3---sn-ab5sznzz.c.2mdn.net.",
+ "r3---sn-jxopj-nh4e.googlevideo.com.",
+ "r3---sn-p5qddn76.c.2mdn.net.",
+ "r3---sn-p5qlsn6l.c.2mdn.net.",
"r3---sn-p5qlsn76.c.2mdn.net.",
+ "r3---sn-p5qlsn7s.c.2mdn.net.",
"r3---sn-p5qlsndk.c.2mdn.net.",
- "r3---sn-p5qs7nsk.c.2mdn.net.",
- "r3---sn-p5qs7nsr.c.2mdn.net.",
- "r3---sn-q4fl6n6s.c.2mdn.net.",
+ "r3---sn-p5qs7nzy.c.2mdn.net.",
+ "r3---sn-q4fl6n66.c.2mdn.net.",
+ "r3---sn-q4fl6n6d.c.2mdn.net.",
+ "r3---sn-q4fl6ndl.c.2mdn.net.",
"r3---sn-q4fl6ndz.c.2mdn.net.",
- "r3---sn-q4fl6nsl.c.2mdn.net.",
- "r3---sn-q4fl6nsr.c.2mdn.net.",
- "r3---sn-q4fl6nzy.c.2mdn.net.",
+ "r3---sn-q4fl6nss.c.2mdn.net.",
+ "r3---sn-q4flrne6.c.2mdn.net.",
+ "r3---sn-q4flrnsk.c.2mdn.net.",
"r3---sn-q4flrnsl.c.2mdn.net.",
- "r3---sn-q4flrnss.c.2mdn.net.",
- "r3---sn-q4fzen7l.c.2mdn.net.",
- "r3---sn-q4fzene7.c.2mdn.net.",
- "r3---sn-vgqskn67.c.2mdn.net.",
+ "r3---sn-q4fzen7s.c.2mdn.net.",
+ "r3---sn-vgqskn66.c.2mdn.net.",
"r3---sn-vgqskn6d.c.2mdn.net.",
- "r3---sn-vgqskn6z.c.2mdn.net.",
+ "r3---sn-vgqskned.c.2mdn.net.",
"r3---sn-vgqsknes.c.2mdn.net.",
- "r3---sn-vgqsknlk.c.2mdn.net.",
+ "r3---sn-vgqsknll.c.2mdn.net.",
"r3---sn-vgqskns7.c.2mdn.net.",
- "r3---sn-vgqsknse.c.2mdn.net.",
- "r3---sn-vgqsknsk.c.2mdn.net.",
+ "r3---sn-vgqsknzd.c.2mdn.net.",
"r3---sn-vgqsknzs.c.2mdn.net.",
"r3---sn-vgqsknzy.c.2mdn.net.",
- "r3---sn-vgqsrn66.c.2mdn.net.",
+ "r3---sn-vgqsrn6e.c.2mdn.net.",
"r3---sn-vgqsrn6l.c.2mdn.net.",
- "r3---sn-vgqsrnld.c.2mdn.net.",
- "r3---sn-vgqsrnll.c.2mdn.net.",
+ "r3---sn-vgqsrnes.c.2mdn.net.",
"r3---sn-vgqsrnlz.c.2mdn.net.",
+ "r3---sn-vgqsrnsr.c.2mdn.net.",
+ "r3---sn-vgqsrnsy.c.2mdn.net.",
"r3---sn-vgqsrnz7.c.2mdn.net.",
"r3---sn-vgqsrnzd.c.2mdn.net.",
"r3---sn-vgqsrnzs.c.2mdn.net.",
+ "r3---sn-vgqsrnzy.c.2mdn.net.",
"r3---sn-vgqsrnzz.c.2mdn.net.",
- "r4---sn-a5mekn6k.c.2mdn.net.",
- "r4---sn-a5meknsd.c.2mdn.net.",
- "r4---sn-a5meknzr.c.2mdn.net.",
- "r4---sn-a5mlrnlz.c.2mdn.net.",
- "r4---sn-a5msenle.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-ab5sznly.c.2mdn.net.",
"r4---sn-ab5sznz6.c.2mdn.net.",
- "r4---sn-ab5sznzd.c.2mdn.net.",
"r4---sn-ab5sznze.c.2mdn.net.",
"r4---sn-ab5sznzk.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-hp57knds.c.2mdn.net.",
- "r4---sn-nx57ynsk.c.2mdn.net.",
+ "r4---sn-jxopj-nh4e.googlevideo.com.",
+ "r4---sn-npoe7nsy.c.2mdn.net.",
+ "r4---sn-npoldn7y.c.2mdn.net.",
+ "r4---sn-p5qddn76.c.2mdn.net.",
"r4---sn-p5qddn7r.c.2mdn.net.",
- "r4---sn-p5qddn7z.c.2mdn.net.",
- "r4---sn-p5qlsn7s.c.2mdn.net.",
+ "r4---sn-p5qlsn6l.c.2mdn.net.",
+ "r4---sn-p5qlsn7d.c.2mdn.net.",
+ "r4---sn-p5qlsnrr.c.2mdn.net.",
+ "r4---sn-p5qs7n6d.c.2mdn.net.",
"r4---sn-p5qs7nsk.c.2mdn.net.",
+ "r4---sn-p5qs7nsr.c.2mdn.net.",
+ "r4---sn-p5qs7nzk.c.2mdn.net.",
+ "r4---sn-p5qs7nzy.c.2mdn.net.",
+ "r4---sn-q4fl6n66.c.2mdn.net.",
+ "r4---sn-q4fl6n6d.c.2mdn.net.",
+ "r4---sn-q4fl6nd7.c.2mdn.net.",
+ "r4---sn-q4fl6ndl.c.2mdn.net.",
+ "r4---sn-q4fl6nss.c.2mdn.net.",
+ "r4---sn-q4fl6nsy.c.2mdn.net.",
+ "r4---sn-q4flrn7k.c.2mdn.net.",
+ "r4---sn-q4flrnez.c.2mdn.net.",
+ "r4---sn-q4flrnsd.c.2mdn.net.",
"r4---sn-q4flrnsk.c.2mdn.net.",
"r4---sn-q4fzen7l.c.2mdn.net.",
"r4---sn-q4fzen7r.c.2mdn.net.",
"r4---sn-vgqskn66.c.2mdn.net.",
- "r4---sn-vgqskn6z.c.2mdn.net.",
"r4---sn-vgqsknld.c.2mdn.net.",
"r4---sn-vgqsknlk.c.2mdn.net.",
+ "r4---sn-vgqsknly.c.2mdn.net.",
"r4---sn-vgqsknlz.c.2mdn.net.",
"r4---sn-vgqskns7.c.2mdn.net.",
"r4---sn-vgqsknz6.c.2mdn.net.",
"r4---sn-vgqsknzd.c.2mdn.net.",
- "r4---sn-vgqsknzr.c.2mdn.net.",
+ "r4---sn-vgqsknzk.c.2mdn.net.",
"r4---sn-vgqsknzs.c.2mdn.net.",
"r4---sn-vgqsknzy.c.2mdn.net.",
- "r4---sn-vgqsrn67.c.2mdn.net.",
- "r4---sn-vgqsrnek.c.2mdn.net.",
- "r4---sn-vgqsrnl6.c.2mdn.net.",
- "r4---sn-vgqsrnlk.c.2mdn.net.",
- "r4---sn-vgqsrnsd.c.2mdn.net.",
- "r4---sn-vgqsrnz7.c.2mdn.net.",
- "r4---sn-vgqsrnzd.c.2mdn.net.",
+ "r4---sn-vgqsrn6l.c.2mdn.net.",
+ "r4---sn-vgqsrnez.c.2mdn.net.",
+ "r4---sn-vgqsrns6.c.2mdn.net.",
+ "r4---sn-vgqsrnsr.c.2mdn.net.",
+ "r4---sn-vgqsrnsy.c.2mdn.net.",
+ "r4---sn-vgqsrnz6.c.2mdn.net.",
"r4---sn-vgqsrnzk.c.2mdn.net.",
"r4---sn-vgqsrnzz.c.2mdn.net.",
- "r5---sn-a5m7lnld.c.2mdn.net.",
- "r5---sn-a5meknde.c.2mdn.net.",
- "r5---sn-a5meknds.c.2mdn.net.",
- "r5---sn-a5msen7z.c.2mdn.net.",
- "r5---sn-ab5l6ndr.c.2mdn.net.",
- "r5---sn-ab5l6ndy.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-ab5l6nrr.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-ab5sznze.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-ajab55-55.c.2mdn.net.",
- "r5---sn-nx57ynsk.c.2mdn.net.",
+ "r5---sn-jxopj-nh4e.googlevideo.com.",
+ "r5---sn-nx57ynsl.c.2mdn.net.",
+ "r5---sn-p5qddn76.c.2mdn.net.",
+ "r5---sn-p5qddn7k.c.2mdn.net.",
+ "r5---sn-p5qlsn7d.c.2mdn.net.",
"r5---sn-p5qlsn7s.c.2mdn.net.",
- "r5---sn-p5qs7nsk.c.2mdn.net.",
+ "r5---sn-p5qlsndk.c.2mdn.net.",
+ "r5---sn-p5qlsnrr.c.2mdn.net.",
+ "r5---sn-p5qlsny6.c.2mdn.net.",
+ "r5---sn-p5qs7nsr.c.2mdn.net.",
"r5---sn-p5qs7nzy.c.2mdn.net.",
- "r5---sn-q4fl6n6z.c.2mdn.net.",
- "r5---sn-q4fl6ndl.c.2mdn.net.",
"r5---sn-q4fl6nsk.c.2mdn.net.",
+ "r5---sn-q4fl6nz6.c.2mdn.net.",
"r5---sn-q4fl6nzy.c.2mdn.net.",
"r5---sn-q4flrn7k.c.2mdn.net.",
- "r5---sn-q4flrnld.c.2mdn.net.",
+ "r5---sn-q4flrnlz.c.2mdn.net.",
+ "r5---sn-q4flrnsd.c.2mdn.net.",
+ "r5---sn-q4flrnsl.c.2mdn.net.",
"r5---sn-q4fzen7l.c.2mdn.net.",
- "r5---sn-q4fzen7y.c.2mdn.net.",
+ "r5---sn-qjp5q5-55.c.2mdn.net.",
"r5---sn-vgqskn67.c.2mdn.net.",
- "r5---sn-vgqskn6s.c.2mdn.net.",
+ "r5---sn-vgqskn6d.c.2mdn.net.",
"r5---sn-vgqskn6z.c.2mdn.net.",
- "r5---sn-vgqsknly.c.2mdn.net.",
- "r5---sn-vgqsknlz.c.2mdn.net.",
+ "r5---sn-vgqsknlr.c.2mdn.net.",
+ "r5---sn-vgqsknz6.c.2mdn.net.",
+ "r5---sn-vgqsknze.c.2mdn.net.",
+ "r5---sn-vgqsknzs.c.2mdn.net.",
"r5---sn-vgqsknzy.c.2mdn.net.",
"r5---sn-vgqsknzz.c.2mdn.net.",
+ "r5---sn-vgqsrn66.c.2mdn.net.",
"r5---sn-vgqsrn67.c.2mdn.net.",
- "r5---sn-vgqsrn6e.c.2mdn.net.",
+ "r5---sn-vgqsrn6l.c.2mdn.net.",
"r5---sn-vgqsrne6.c.2mdn.net.",
+ "r5---sn-vgqsrnek.c.2mdn.net.",
+ "r5---sn-vgqsrnez.c.2mdn.net.",
"r5---sn-vgqsrnl6.c.2mdn.net.",
"r5---sn-vgqsrnlk.c.2mdn.net.",
- "r5---sn-vgqsrnlz.c.2mdn.net.",
- "r5---sn-vgqsrnsr.c.2mdn.net.",
- "r5---sn-vgqsrnsy.c.2mdn.net.",
- "r5---sn-vgqsrnzz.c.2mdn.net.",
+ "r5---sn-vgqsrnz7.c.2mdn.net.",
+ "r6---sn-jxopj-nh4e.googlevideo.com.",
"radar.cedexis.com.",
"radar.com.",
"radyushin.com.",
"railway.app.",
"raleigh.remotepc.com.",
- "rapi.av380.net.",
+ "randomhouse.app.box.com.",
"rba-screen.healthsafe-id.com.",
"rba.onehealthcareid.com.",
"rbdata.boostymark.com.",
+ "rbhs7ex3.onequince.com.",
"rbm-us.storage.googleapis.com.",
"rcs-acs-att-us.jibe.google.com.",
"rcs-acs-mcc311.jibe.google.com.",
@@ -3358,20 +3529,22 @@ var FakeECSFQDNs = container.NewMapSet(
"recombee.com.",
"recruiting.ultipro.com.",
"recruiting2.ultipro.com.",
+ "referralrock.com.",
"reflector.makerbot.com.",
- "region1.app-measurement.com.",
+ "refpaucqkl.top.",
"regions.com.",
"registration.prna01.cmdagent.trafficmanager.net.",
"related.queryly.com.",
+ "relay.shhnowisnottheti.me.",
"remote-config.gslb.sgw.shopeemobile.com.",
"remote.control4.com.",
"repo.zabbix.com.",
+ "requality.android.shouji.sogou.com.",
"request-global.czilladx.com.",
- "researchgate.net.",
"resideo.com.",
- "resizer.otstatic.com.",
"resource.digitalinsight.com.",
- "resources.finalsite.net.",
+ "resources.office.net.edgekey.net.",
+ "rest.iad-01.braze.com.",
"restproxy-analytics.ascendlearning.com.",
"restrict.youtube.com.",
"restrictmoderate.youtube.com.",
@@ -3386,16 +3559,13 @@ var FakeECSFQDNs = container.NewMapSet(
"rl.progressive.com.",
"rl.quantummetric.com.",
"rlm.haokan.mobi.",
- "rmkcdn.successfactors.com.",
"rmm.aunalytics.com.",
- "rmm.creativeplanning.com.",
"rmm2.jmark.com.",
"rms-dra.platform.dbankcloud.com.",
"rn-resource-app.xiaohongshu.com.",
"roborock.com.",
"rockylinux.org.",
- "rogueone.aristotleinsight.com.",
- "romsp-unifyconfig.vivo.com.cn.",
+ "roockmobile.com.",
"router.teamviewer.com.",
"roxy.azurefd.net.",
"rpt.cedexis.com.",
@@ -3409,7 +3579,6 @@ var FakeECSFQDNs = container.NewMapSet(
"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-30a7rne6.googlevideo.com.",
@@ -3432,6 +3601,7 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -3444,6 +3614,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-4g5edndl.googlevideo.com.",
"rr1---sn-4g5edndr.googlevideo.com.",
"rr1---sn-4g5ednds.googlevideo.com.",
+ "rr1---sn-4g5ednds.gvt1.com.",
"rr1---sn-4g5edndy.googlevideo.com.",
"rr1---sn-4g5edndz.googlevideo.com.",
"rr1---sn-4g5ednkl.googlevideo.com.",
@@ -3469,52 +3640,53 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-4g5lznez.googlevideo.com.",
"rr1---sn-4g5lznl6.googlevideo.com.",
"rr1---sn-4g5lznl7.googlevideo.com.",
+ "rr1---sn-4g5lznle.googlevideo.com.",
"rr1---sn-4g5lznls.googlevideo.com.",
"rr1---sn-4g5lznlz.googlevideo.com.",
+ "rr1---sn-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
+ "rr1---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
+ "rr1---sn-5abxgpxuxaxjvh-9n4s.googlevideo.com.",
+ "rr1---sn-5abxgpxuxaxjvh-9n4z.googlevideo.com.",
"rr1---sn-5axnug5-hxm6.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-5hne6nsy.gvt1.com.",
"rr1---sn-5hne6nsz.googlevideo.com.",
"rr1---sn-5hne6nz6.googlevideo.com.",
+ "rr1---sn-5hne6nzd.googlevideo.com.",
+ "rr1---sn-5hne6nzd.gvt1.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-5hnekn7l.googlevideo.com.",
"rr1---sn-5hnekn7s.googlevideo.com.",
"rr1---sn-5hnekn7z.googlevideo.com.",
- "rr1---sn-5hnekn7z.gvt1.com.",
"rr1---sn-5hneknee.googlevideo.com.",
- "rr1---sn-5hneknee.gvt1.com.",
"rr1---sn-5hneknek.googlevideo.com.",
"rr1---sn-5hneknes.googlevideo.com.",
- "rr1---sn-5hneknes.gvt1.com.",
- "rr1---sn-5jn5a5n35-5ojs.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-5uaeznel.googlevideo.com.",
"rr1---sn-5uaeznes.googlevideo.com.",
"rr1---sn-5uaeznez.googlevideo.com.",
"rr1---sn-5uaeznl6.googlevideo.com.",
- "rr1---sn-5uaeznld.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-5uaeznys.googlevideo.com.",
- "rr1---sn-5uaeznyz.googlevideo.com.",
+ "rr1---sn-5uaezny6.googlevideo.com.",
+ "rr1---sn-5uaeznze.googlevideo.com.",
"rr1---sn-5ualdnle.googlevideo.com.",
"rr1---sn-5ualdnll.googlevideo.com.",
"rr1---sn-5ualdnlr.googlevideo.com.",
@@ -3531,38 +3703,40 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-5ualdnsz.googlevideo.com.",
"rr1---sn-5ualdnz7.googlevideo.com.",
"rr1---sn-5ualdnze.googlevideo.com.",
- "rr1---sn-8qj-i5okl.googlevideo.com.",
+ "rr1---sn-8pxuuxa-nbo6s.googlevideo.com.",
"rr1---sn-8qj-nbo66.googlevideo.com.",
"rr1---sn-8qj-nbo6y.googlevideo.com.",
+ "rr1---sn-8xgp1vo-2iae7.googlevideo.com.",
+ "rr1---sn-8xgp1vo-a5me.googlevideo.com.",
"rr1---sn-8xgp1vo-a5ml.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-p5ie.googlevideo.com.",
"rr1---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr1---sn-8xgp1vo-xfge.googlevideo.com.",
- "rr1---sn-8xgp1vo-xfgl.googlevideo.com.",
"rr1---sn-8xgp1vo-xfgs.googlevideo.com.",
"rr1---sn-9gv76n7e.googlevideo.com.",
"rr1---sn-9gv76n7s.googlevideo.com.",
"rr1---sn-9gv76n7z.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-9gv7zn7y.googlevideo.com.",
"rr1---sn-a5m7lnl6.googlevideo.com.",
"rr1---sn-a5m7lnl6.gvt1.com.",
"rr1---sn-a5m7lnld.googlevideo.com.",
- "rr1---sn-a5m7lnld.gvt1.com.",
"rr1---sn-a5mekn6d.googlevideo.com.",
+ "rr1---sn-a5mekn6d.gvt1.com.",
+ "rr1---sn-a5mekn6k.googlevideo.com.",
"rr1---sn-a5mekn6l.googlevideo.com.",
"rr1---sn-a5mekn6r.googlevideo.com.",
- "rr1---sn-a5mekn6r.gvt1.com.",
"rr1---sn-a5mekn6s.googlevideo.com.",
- "rr1---sn-a5mekn6s.gvt1.com.",
"rr1---sn-a5mekn6z.googlevideo.com.",
"rr1---sn-a5meknd6.googlevideo.com.",
"rr1---sn-a5meknd6.gvt1.com.",
@@ -3571,49 +3745,45 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-a5mekndl.googlevideo.com.",
"rr1---sn-a5mekndl.gvt1.com.",
"rr1---sn-a5meknds.googlevideo.com.",
- "rr1---sn-a5meknds.gvt1.com.",
"rr1---sn-a5mekndz.googlevideo.com.",
"rr1---sn-a5mekndz.gvt1.com.",
"rr1---sn-a5meknsd.googlevideo.com.",
"rr1---sn-a5meknsy.googlevideo.com.",
"rr1---sn-a5meknzk.googlevideo.com.",
+ "rr1---sn-a5meknzk.gvt1.com.",
"rr1---sn-a5meknzl.googlevideo.com.",
"rr1---sn-a5meknzr.googlevideo.com.",
"rr1---sn-a5meknzr.gvt1.com.",
"rr1---sn-a5meknzs.googlevideo.com.",
"rr1---sn-a5mlrnek.googlevideo.com.",
- "rr1---sn-a5mlrnek.gvt1.com.",
"rr1---sn-a5mlrnl6.googlevideo.com.",
"rr1---sn-a5mlrnl6.gvt1.com.",
"rr1---sn-a5mlrnll.googlevideo.com.",
"rr1---sn-a5mlrnls.googlevideo.com.",
+ "rr1---sn-a5mlrnls.gvt1.com.",
"rr1---sn-a5mlrnlz.googlevideo.com.",
"rr1---sn-a5mlrnlz.gvt1.com.",
+ "rr1---sn-a5msen76.googlevideo.com.",
+ "rr1---sn-a5msen76.gvt1.com.",
"rr1---sn-a5msen7l.googlevideo.com.",
"rr1---sn-a5msen7s.googlevideo.com.",
"rr1---sn-a5msen7z.googlevideo.com.",
"rr1---sn-a5msenek.googlevideo.com.",
+ "rr1---sn-a5msenek.gvt1.com.",
"rr1---sn-a5msener.googlevideo.com.",
"rr1---sn-a5msenes.googlevideo.com.",
"rr1---sn-a5msenes.gvt1.com.",
"rr1---sn-a5msenl7.googlevideo.com.",
- "rr1---sn-a5msenl7.gvt1.com.",
"rr1---sn-a5msenle.googlevideo.com.",
- "rr1---sn-a5msenle.gvt1.com.",
"rr1---sn-a5msenll.googlevideo.com.",
"rr1---sn-ab5l6ndr.googlevideo.com.",
"rr1---sn-ab5l6ndy.googlevideo.com.",
"rr1---sn-ab5l6nk6.googlevideo.com.",
- "rr1---sn-ab5l6nk6.gvt1.com.",
"rr1---sn-ab5l6nkd.googlevideo.com.",
- "rr1---sn-ab5l6nkd.gvt1.com.",
"rr1---sn-ab5l6nr6.googlevideo.com.",
- "rr1---sn-ab5l6nr6.gvt1.com.",
"rr1---sn-ab5l6nrd.googlevideo.com.",
"rr1---sn-ab5l6nrk.googlevideo.com.",
- "rr1---sn-ab5l6nrk.gvt1.com.",
"rr1---sn-ab5l6nrl.googlevideo.com.",
- "rr1---sn-ab5l6nrl.gvt1.com.",
"rr1---sn-ab5l6nrr.googlevideo.com.",
"rr1---sn-ab5l6nrs.googlevideo.com.",
"rr1---sn-ab5l6nrz.googlevideo.com.",
@@ -3621,7 +3791,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-ab5sznly.googlevideo.com.",
"rr1---sn-ab5sznly.gvt1.com.",
"rr1---sn-ab5sznz6.googlevideo.com.",
- "rr1---sn-ab5sznz6.gvt1.com.",
"rr1---sn-ab5sznzd.googlevideo.com.",
"rr1---sn-ab5sznze.googlevideo.com.",
"rr1---sn-ab5sznzk.googlevideo.com.",
@@ -3631,22 +3800,25 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-ab5sznzs.googlevideo.com.",
"rr1---sn-ab5sznzy.googlevideo.com.",
"rr1---sn-ab5sznzz.googlevideo.com.",
- "rr1---sn-ab5sznzz.gvt1.com.",
"rr1---sn-aigl6n6s.googlevideo.com.",
"rr1---sn-aigl6ned.googlevideo.com.",
"rr1---sn-aigl6nek.googlevideo.com.",
+ "rr1---sn-aigl6nek.gvt1.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-aigl6nsd.gvt1.com.",
"rr1---sn-aigl6nsk.googlevideo.com.",
"rr1---sn-aigl6nsr.googlevideo.com.",
+ "rr1---sn-aigl6nsr.gvt1.com.",
"rr1---sn-aigl6nz7.googlevideo.com.",
"rr1---sn-aigl6nze.googlevideo.com.",
"rr1---sn-aigl6nze.gvt1.com.",
"rr1---sn-aigl6nzk.googlevideo.com.",
"rr1---sn-aigl6nzl.googlevideo.com.",
+ "rr1---sn-aigl6nzl.gvt1.com.",
"rr1---sn-aigl6nzr.googlevideo.com.",
"rr1---sn-aigl6nzs.googlevideo.com.",
"rr1---sn-aigzrn76.googlevideo.com.",
@@ -3664,11 +3836,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-aigzrnsz.googlevideo.com.",
"rr1---sn-aigzrnz7.googlevideo.com.",
"rr1---sn-aigzrnze.googlevideo.com.",
+ "rr1---sn-aj5ua5-5c.googlevideo.com.",
"rr1---sn-ajab55-55.googlevideo.com.",
"rr1---sn-avbpj-cq5e.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.",
@@ -3678,44 +3848,38 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-fpnjoxu-hnol.googlevideo.com.",
"rr1---sn-gpuuxg-hxhl.googlevideo.com.",
"rr1---sn-gpuuxg-hxhs.googlevideo.com.",
- "rr1---sn-gpuuxg-hxhs.gvt1.com.",
"rr1---sn-gpuuxg-hxhz.googlevideo.com.",
"rr1---sn-gpuuxg-hxhz.gvt1.com.",
- "rr1---sn-hgn7rn7y.googlevideo.com.",
- "rr1---sn-hgn7ynek.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-hoa7rn7z.googlevideo.com.",
"rr1---sn-hp57kn6r.googlevideo.com.",
"rr1---sn-hp57kn6y.googlevideo.com.",
- "rr1---sn-hp57knd6.googlevideo.com.",
"rr1---sn-hp57kndd.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-hp57knds.gvt1.com.",
"rr1---sn-hp57kndy.googlevideo.com.",
"rr1---sn-hp57kndz.googlevideo.com.",
- "rr1---sn-hp57kndz.gvt1.com.",
"rr1---sn-hp57yn7r.googlevideo.com.",
"rr1---sn-hp57yn7y.googlevideo.com.",
- "rr1---sn-hp57yn7y.gvt1.com.",
"rr1---sn-hp57yne7.googlevideo.com.",
"rr1---sn-hp57ynee.googlevideo.com.",
"rr1---sn-hp57ynl6.googlevideo.com.",
- "rr1---sn-hp57ynl6.gvt1.com.",
"rr1---sn-hp57ynlr.googlevideo.com.",
- "rr1---sn-hp57ynlr.gvt1.com.",
"rr1---sn-hp57ynly.googlevideo.com.",
+ "rr1---sn-hp57ynly.gvt1.com.",
"rr1---sn-hp57yns7.googlevideo.com.",
+ "rr1---sn-hp57yns7.gvt1.com.",
"rr1---sn-hp57ynse.googlevideo.com.",
- "rr1---sn-hp57ynse.gvt1.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.",
@@ -3724,6 +3888,7 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -3732,19 +3897,23 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-i3belnls.googlevideo.com.",
"rr1---sn-i3belnlz.googlevideo.com.",
"rr1---sn-i3bssn7e.googlevideo.com.",
- "rr1---sn-i5f5ppuxa-ioal.googlevideo.com.",
"rr1---sn-i5f5ppuxa-ioas.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-2ias.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-qufl.googlevideo.com.",
+ "rr1---sn-jvhj5nu-qufs.googlevideo.com.",
"rr1---sn-jvooxqouf3-cqaz.googlevideo.com.",
"rr1---sn-jxopj-n5oe.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.",
@@ -3757,7 +3926,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-nh5gujvh-h4xe.googlevideo.com.",
"rr1---sn-nh5gujvh-h4xe.gvt1.com.",
"rr1---sn-npoe7ndl.googlevideo.com.",
- "rr1---sn-npoe7ndl.gvt1.com.",
"rr1---sn-npoe7nds.googlevideo.com.",
"rr1---sn-npoe7ne6.googlevideo.com.",
"rr1---sn-npoe7ne7.googlevideo.com.",
@@ -3770,10 +3938,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-npoe7nl6.googlevideo.com.",
"rr1---sn-npoe7nlz.googlevideo.com.",
"rr1---sn-npoe7ns6.googlevideo.com.",
+ "rr1---sn-npoe7ns6.gvt1.com.",
"rr1---sn-npoe7ns7.googlevideo.com.",
- "rr1---sn-npoe7ns7.gvt1.com.",
"rr1---sn-npoe7nsd.googlevideo.com.",
+ "rr1---sn-npoe7nsd.gvt1.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.",
@@ -3790,57 +3960,55 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-npoeenlk.googlevideo.com.",
"rr1---sn-npoeenll.googlevideo.com.",
"rr1---sn-npoeenly.googlevideo.com.",
+ "rr1---sn-npoeenly.gvt1.com.",
"rr1---sn-npoeens7.googlevideo.com.",
"rr1---sn-npoldn76.googlevideo.com.",
"rr1---sn-npoldn7d.googlevideo.com.",
"rr1---sn-npoldn7e.googlevideo.com.",
- "rr1---sn-npoldn7e.gvt1.com.",
"rr1---sn-npoldn7l.googlevideo.com.",
"rr1---sn-npoldn7s.googlevideo.com.",
"rr1---sn-npoldn7s.gvt1.com.",
"rr1---sn-npoldn7y.googlevideo.com.",
"rr1---sn-npoldn7z.googlevideo.com.",
"rr1---sn-npoldne7.googlevideo.com.",
- "rr1---sn-ntq7ynle.googlevideo.com.",
+ "rr1---sn-ntqe6nee.googlevideo.com.",
"rr1---sn-nuagpm-nuae.googlevideo.com.",
"rr1---sn-nv0uixgo-5ual.googlevideo.com.",
"rr1---sn-nx57ynlk.googlevideo.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-nx57ynss.gvt1.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-nx5s7n7y.gvt1.com.",
+ "rr1---sn-nx5s7nee.googlevideo.com.",
"rr1---sn-nx5s7nel.googlevideo.com.",
- "rr1---sn-nx5s7nel.gvt1.com.",
"rr1---sn-o097znsd.googlevideo.com.",
"rr1---sn-o097znse.googlevideo.com.",
"rr1---sn-o097znsk.googlevideo.com.",
+ "rr1---sn-o097znsk.gvt1.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-o097znz7.gvt1.com.",
"rr1---sn-o097znzd.googlevideo.com.",
- "rr1---sn-o097znzd.gvt1.com.",
"rr1---sn-o097znze.googlevideo.com.",
"rr1---sn-o097znzk.googlevideo.com.",
"rr1---sn-o097znzr.googlevideo.com.",
- "rr1---sn-o097znzr.gvt1.com.",
"rr1---sn-oj5hn5-55.googlevideo.com.",
"rr1---sn-oxgpj-5ace.googlevideo.com.",
"rr1---sn-p5qddn76.googlevideo.com.",
"rr1---sn-p5qddn7d.googlevideo.com.",
"rr1---sn-p5qddn7k.googlevideo.com.",
- "rr1---sn-p5qddn7k.gvt1.com.",
"rr1---sn-p5qddn7r.googlevideo.com.",
"rr1---sn-p5qddn7z.googlevideo.com.",
"rr1---sn-p5qlsn6l.googlevideo.com.",
@@ -3851,7 +4019,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-p5qlsnd6.googlevideo.com.",
"rr1---sn-p5qlsndk.googlevideo.com.",
"rr1---sn-p5qlsndr.googlevideo.com.",
- "rr1---sn-p5qlsndr.gvt1.com.",
"rr1---sn-p5qlsndz.googlevideo.com.",
"rr1---sn-p5qlsnrl.googlevideo.com.",
"rr1---sn-p5qlsnrr.googlevideo.com.",
@@ -3860,20 +4027,16 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-p5qs7nsk.googlevideo.com.",
"rr1---sn-p5qs7nsk.gvt1.com.",
"rr1---sn-p5qs7nsr.googlevideo.com.",
- "rr1---sn-p5qs7nzk.googlevideo.com.",
"rr1---sn-p5qs7nzr.googlevideo.com.",
- "rr1---sn-p5qs7nzr.gvt1.com.",
"rr1---sn-paapovpnjxou0gt-nual.googlevideo.com.",
"rr1---sn-paapovpnjxou0gt-nuas.googlevideo.com.",
"rr1---sn-pjnpu-5hfe.googlevideo.com.",
"rr1---sn-pjx-nwv6.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-q4fl6n6r.gvt1.com.",
"rr1---sn-q4fl6n6s.googlevideo.com.",
"rr1---sn-q4fl6n6s.gvt1.com.",
"rr1---sn-q4fl6n6y.googlevideo.com.",
@@ -3883,63 +4046,57 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-q4fl6nd7.googlevideo.com.",
"rr1---sn-q4fl6nd7.gvt1.com.",
"rr1---sn-q4fl6nde.googlevideo.com.",
- "rr1---sn-q4fl6nde.gvt1.com.",
"rr1---sn-q4fl6ndl.googlevideo.com.",
"rr1---sn-q4fl6ndl.gvt1.com.",
"rr1---sn-q4fl6nds.googlevideo.com.",
"rr1---sn-q4fl6nds.gvt1.com.",
"rr1---sn-q4fl6ndz.googlevideo.com.",
+ "rr1---sn-q4fl6ndz.gvt1.com.",
"rr1---sn-q4fl6nlz.googlevideo.com.",
+ "rr1---sn-q4fl6nlz.gvt1.com.",
"rr1---sn-q4fl6ns6.googlevideo.com.",
+ "rr1---sn-q4fl6ns6.gvt1.com.",
"rr1---sn-q4fl6ns7.googlevideo.com.",
+ "rr1---sn-q4fl6ns7.gvt1.com.",
"rr1---sn-q4fl6nsd.googlevideo.com.",
+ "rr1---sn-q4fl6nsd.gvt1.com.",
"rr1---sn-q4fl6nsk.googlevideo.com.",
- "rr1---sn-q4fl6nsk.gvt1.com.",
"rr1---sn-q4fl6nsl.googlevideo.com.",
"rr1---sn-q4fl6nsl.gvt1.com.",
"rr1---sn-q4fl6nsr.googlevideo.com.",
"rr1---sn-q4fl6nss.googlevideo.com.",
"rr1---sn-q4fl6nsy.googlevideo.com.",
- "rr1---sn-q4fl6nsy.gvt1.com.",
- "rr1---sn-q4fl6nz6.googlevideo.com.",
- "rr1---sn-q4fl6nz6.gvt1.com.",
"rr1---sn-q4fl6nz7.googlevideo.com.",
"rr1---sn-q4fl6nz7.gvt1.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-q4flrne6.gvt1.com.",
"rr1---sn-q4flrne7.googlevideo.com.",
"rr1---sn-q4flrnee.googlevideo.com.",
"rr1---sn-q4flrnek.googlevideo.com.",
"rr1---sn-q4flrnel.googlevideo.com.",
"rr1---sn-q4flrner.googlevideo.com.",
- "rr1---sn-q4flrner.gvt1.com.",
- "rr1---sn-q4flrnes.googlevideo.com.",
- "rr1---sn-q4flrnes.gvt1.com.",
"rr1---sn-q4flrney.googlevideo.com.",
"rr1---sn-q4flrnez.googlevideo.com.",
"rr1---sn-q4flrnl6.googlevideo.com.",
"rr1---sn-q4flrnl7.googlevideo.com.",
"rr1---sn-q4flrnld.googlevideo.com.",
- "rr1---sn-q4flrnld.gvt1.com.",
+ "rr1---sn-q4flrnle.googlevideo.com.",
"rr1---sn-q4flrnlz.googlevideo.com.",
+ "rr1---sn-q4flrnlz.gvt1.com.",
"rr1---sn-q4flrnsd.googlevideo.com.",
"rr1---sn-q4flrnsd.gvt1.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-q4flrnss.gvt1.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-q4fzen7s.gvt1.com.",
"rr1---sn-q4fzen7y.googlevideo.com.",
@@ -3947,84 +4104,73 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-q4fzene7.googlevideo.com.",
"rr1---sn-q4fzene7.gvt1.com.",
"rr1---sn-q4fzenee.googlevideo.com.",
- "rr1---sn-q4fzenee.gvt1.com.",
+ "rr1---sn-qjp5q5-55.googlevideo.com.",
"rr1---sn-qxo7rn7k.googlevideo.com.",
"rr1---sn-qxo7rn7r.googlevideo.com.",
"rr1---sn-qxo7rn7y.googlevideo.com.",
"rr1---sn-qxoedn7k.googlevideo.com.",
"rr1---sn-qxoedne7.googlevideo.com.",
"rr1---sn-qxoednee.googlevideo.com.",
- "rr1---sn-t0a7lnee.googlevideo.com.",
"rr1---sn-u1hp55-5c.googlevideo.com.",
+ "rr1---sn-uqnuxaxjvh-hnoe.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-vgqskn66.gvt1.com.",
"rr1---sn-vgqskn67.googlevideo.com.",
"rr1---sn-vgqskn67.gvt1.com.",
"rr1---sn-vgqskn6d.googlevideo.com.",
"rr1---sn-vgqskn6s.googlevideo.com.",
"rr1---sn-vgqskn6z.googlevideo.com.",
- "rr1---sn-vgqskn6z.gvt1.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-vgqsknez.gvt1.com.",
"rr1---sn-vgqsknld.googlevideo.com.",
"rr1---sn-vgqsknlk.googlevideo.com.",
- "rr1---sn-vgqsknlk.gvt1.com.",
"rr1---sn-vgqsknll.googlevideo.com.",
- "rr1---sn-vgqsknll.gvt1.com.",
"rr1---sn-vgqsknlr.googlevideo.com.",
"rr1---sn-vgqsknls.googlevideo.com.",
"rr1---sn-vgqsknly.googlevideo.com.",
"rr1---sn-vgqskns7.googlevideo.com.",
- "rr1---sn-vgqskns7.gvt1.com.",
"rr1---sn-vgqsknse.googlevideo.com.",
"rr1---sn-vgqsknsk.googlevideo.com.",
"rr1---sn-vgqsknz6.googlevideo.com.",
- "rr1---sn-vgqsknz6.gvt1.com.",
"rr1---sn-vgqsknz7.googlevideo.com.",
- "rr1---sn-vgqsknz7.gvt1.com.",
"rr1---sn-vgqsknzd.googlevideo.com.",
+ "rr1---sn-vgqsknzd.gvt1.com.",
"rr1---sn-vgqsknze.googlevideo.com.",
- "rr1---sn-vgqsknze.gvt1.com.",
"rr1---sn-vgqsknzk.googlevideo.com.",
"rr1---sn-vgqsknzl.googlevideo.com.",
- "rr1---sn-vgqsknzl.gvt1.com.",
"rr1---sn-vgqsknzr.googlevideo.com.",
"rr1---sn-vgqsknzs.googlevideo.com.",
"rr1---sn-vgqsknzy.googlevideo.com.",
"rr1---sn-vgqsknzz.googlevideo.com.",
+ "rr1---sn-vgqsknzz.gvt1.com.",
"rr1---sn-vgqsrn66.googlevideo.com.",
- "rr1---sn-vgqsrn66.gvt1.com.",
"rr1---sn-vgqsrn67.googlevideo.com.",
- "rr1---sn-vgqsrn67.gvt1.com.",
"rr1---sn-vgqsrn6e.googlevideo.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-vgqsrne6.gvt1.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-vgqsrnl6.gvt1.com.",
"rr1---sn-vgqsrnld.googlevideo.com.",
+ "rr1---sn-vgqsrnlk.googlevideo.com.",
"rr1---sn-vgqsrnll.googlevideo.com.",
- "rr1---sn-vgqsrnll.gvt1.com.",
"rr1---sn-vgqsrnls.googlevideo.com.",
"rr1---sn-vgqsrnlz.googlevideo.com.",
- "rr1---sn-vgqsrnlz.gvt1.com.",
"rr1---sn-vgqsrns6.googlevideo.com.",
"rr1---sn-vgqsrnsd.googlevideo.com.",
"rr1---sn-vgqsrnsr.googlevideo.com.",
- "rr1---sn-vgqsrnsr.gvt1.com.",
"rr1---sn-vgqsrnsy.googlevideo.com.",
"rr1---sn-vgqsrnz6.googlevideo.com.",
"rr1---sn-vgqsrnz7.googlevideo.com.",
@@ -4032,33 +4178,19 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-vgqsrnzd.googlevideo.com.",
"rr1---sn-vgqsrnzk.googlevideo.com.",
"rr1---sn-vgqsrnzr.googlevideo.com.",
- "rr1---sn-vgqsrnzr.gvt1.com.",
"rr1---sn-vgqsrnzs.googlevideo.com.",
"rr1---sn-vgqsrnzy.googlevideo.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-5hneknee.googlevideo.com.",
- "rr1.sn-hgn7rn7y.googlevideo.com.",
- "rr1.sn-hp57knds.googlevideo.com.",
- "rr1.sn-hp57kndz.googlevideo.com.",
- "rr1.sn-nx57ynsk.googlevideo.com.",
- "rr1.sn-p5qs7nsk.googlevideo.com.",
- "rr1.sn-q4fl6n6z.googlevideo.com.",
+ "rr1.sn-q4fl6nd7.googlevideo.com.",
+ "rr1.sn-q4fl6ns7.googlevideo.com.",
"rr1.sn-q4fl6nsd.googlevideo.com.",
- "rr1.sn-q4fl6nsy.googlevideo.com.",
"rr1.sn-q4flrnee.googlevideo.com.",
- "rr1.sn-q4flrnes.googlevideo.com.",
"rr1.sn-q4flrnlz.googlevideo.com.",
- "rr1.sn-q4fzen7e.googlevideo.com.",
- "rr1.sn-q4fzen7l.googlevideo.com.",
- "rr1.sn-q4fzen7r.googlevideo.com.",
- "rr1.sn-q4fzen7y.googlevideo.com.",
- "rr1.sn-t0a7lnee.googlevideo.com.",
- "rr1.sn-vgqsrnzz.googlevideo.com.",
+ "rr1.sn-q4flrnsl.googlevideo.com.",
+ "rr1.sn-q4flrnss.googlevideo.com.",
"rr2---sn-0nnpbo5a-bggl.googlevideo.com.",
"rr2---sn-0op8v4h5pox-cbgl.googlevideo.com.",
"rr2---sn-2imern76.googlevideo.com.",
@@ -4066,12 +4198,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-2imeyn7k.googlevideo.com.",
"rr2---sn-2napbiu-p5ie.googlevideo.com.",
"rr2---sn-2napbiu-p5ie.gvt1.com.",
- "rr2---sn-2oaig5-55.googlevideo.com.",
"rr2---sn-2pmxapm0n-gpje.googlevideo.com.",
"rr2---sn-2pmxapm0n-gpjl.googlevideo.com.",
"rr2---sn-30a7rne6.googlevideo.com.",
- "rr2---sn-30a7rned.googlevideo.com.",
- "rr2---sn-30a7rnek.googlevideo.com.",
"rr2---sn-30a7rner.googlevideo.com.",
"rr2---sn-30a7ynek.googlevideo.com.",
"rr2---sn-30a7yner.googlevideo.com.",
@@ -4084,12 +4213,13 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -4103,7 +4233,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-4g5edndy.googlevideo.com.",
"rr2---sn-4g5edndz.googlevideo.com.",
"rr2---sn-4g5ednkl.googlevideo.com.",
- "rr2---sn-4g5ednkl.gvt1.com.",
"rr2---sn-4g5ednld.googlevideo.com.",
"rr2---sn-4g5ednly.googlevideo.com.",
"rr2---sn-4g5edns6.googlevideo.com.",
@@ -4125,14 +4254,19 @@ var FakeECSFQDNs = container.NewMapSet(
"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-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
+ "rr2---sn-5abxgpxuxaxjvh-9n4s.googlevideo.com.",
+ "rr2---sn-5abxgpxuxaxjvh-9n4z.googlevideo.com.",
"rr2---sn-5axnug5-hxm6.googlevideo.com.",
- "rr2---sn-5gxo-in8l.googlevideo.com.",
"rr2---sn-5gxo-in8s.googlevideo.com.",
"rr2---sn-5hne6n6e.googlevideo.com.",
+ "rr2---sn-5hne6n6e.gvt1.com.",
"rr2---sn-5hne6n6l.googlevideo.com.",
+ "rr2---sn-5hne6n6l.gvt1.com.",
"rr2---sn-5hne6ns6.googlevideo.com.",
"rr2---sn-5hne6nsd.googlevideo.com.",
"rr2---sn-5hne6nsk.googlevideo.com.",
@@ -4140,41 +4274,36 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-5hne6nsy.googlevideo.com.",
"rr2---sn-5hne6nsz.googlevideo.com.",
"rr2---sn-5hne6nz6.googlevideo.com.",
+ "rr2---sn-5hne6nz6.gvt1.com.",
"rr2---sn-5hne6nzd.googlevideo.com.",
- "rr2---sn-5hne6nzd.gvt1.com.",
"rr2---sn-5hne6nzk.googlevideo.com.",
"rr2---sn-5hne6nzs.googlevideo.com.",
"rr2---sn-5hne6nzy.googlevideo.com.",
- "rr2---sn-5hne6nzy.gvt1.com.",
"rr2---sn-5hnednss.googlevideo.com.",
- "rr2---sn-5hnednss.gvt1.com.",
"rr2---sn-5hnednsz.googlevideo.com.",
"rr2---sn-5hnednsz.gvt1.com.",
"rr2---sn-5hnekn76.googlevideo.com.",
"rr2---sn-5hnekn7d.googlevideo.com.",
"rr2---sn-5hnekn7l.googlevideo.com.",
- "rr2---sn-5hnekn7l.gvt1.com.",
"rr2---sn-5hnekn7s.googlevideo.com.",
"rr2---sn-5hnekn7z.googlevideo.com.",
"rr2---sn-5hneknee.googlevideo.com.",
"rr2---sn-5hneknek.googlevideo.com.",
- "rr2---sn-5hneknek.gvt1.com.",
"rr2---sn-5hneknes.googlevideo.com.",
- "rr2---sn-5hneknes.gvt1.com.",
- "rr2---sn-5jn5a5n35-5ojs.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-5uaeznel.googlevideo.com.",
"rr2---sn-5uaeznes.googlevideo.com.",
"rr2---sn-5uaeznez.googlevideo.com.",
"rr2---sn-5uaeznl6.googlevideo.com.",
- "rr2---sn-5uaeznrz.googlevideo.com.",
+ "rr2---sn-5uaeznld.googlevideo.com.",
+ "rr2---sn-5uaeznlz.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.",
@@ -4193,9 +4322,10 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-5ualdnsz.googlevideo.com.",
"rr2---sn-5ualdnz7.googlevideo.com.",
"rr2---sn-5ualdnze.googlevideo.com.",
- "rr2---sn-8qj-i5okl.googlevideo.com.",
+ "rr2---sn-8pxuuxa-nbo6l.googlevideo.com.",
"rr2---sn-8qj-nbo66.googlevideo.com.",
"rr2---sn-8qj-nbo6y.googlevideo.com.",
+ "rr2---sn-8xgp1vo-2iae7.googlevideo.com.",
"rr2---sn-8xgp1vo-a5ml.googlevideo.com.",
"rr2---sn-8xgp1vo-ab56.googlevideo.com.",
"rr2---sn-8xgp1vo-ab5d.googlevideo.com.",
@@ -4205,30 +4335,34 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-8xgp1vo-ab5z.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-9gv76n7l.googlevideo.com.",
"rr2---sn-9gv76n7s.googlevideo.com.",
"rr2---sn-9gv76n7z.googlevideo.com.",
"rr2---sn-9gv7ene6.googlevideo.com.",
"rr2---sn-9gv7ened.googlevideo.com.",
+ "rr2---sn-9gv7zn76.googlevideo.com.",
"rr2---sn-9gv7zn7e.googlevideo.com.",
+ "rr2---sn-9gv7zn7y.googlevideo.com.",
"rr2---sn-a5m7lnl6.googlevideo.com.",
+ "rr2---sn-a5m7lnl6.gvt1.com.",
"rr2---sn-a5m7lnld.googlevideo.com.",
+ "rr2---sn-a5m7lnld.gvt1.com.",
"rr2---sn-a5mekn6d.googlevideo.com.",
"rr2---sn-a5mekn6d.gvt1.com.",
"rr2---sn-a5mekn6k.googlevideo.com.",
+ "rr2---sn-a5mekn6k.gvt1.com.",
"rr2---sn-a5mekn6l.googlevideo.com.",
- "rr2---sn-a5mekn6l.gvt1.com.",
"rr2---sn-a5mekn6r.googlevideo.com.",
"rr2---sn-a5mekn6r.gvt1.com.",
"rr2---sn-a5mekn6s.googlevideo.com.",
- "rr2---sn-a5mekn6s.gvt1.com.",
"rr2---sn-a5mekn6z.googlevideo.com.",
"rr2---sn-a5mekn6z.gvt1.com.",
"rr2---sn-a5meknd6.googlevideo.com.",
"rr2---sn-a5meknde.googlevideo.com.",
+ "rr2---sn-a5meknde.gvt1.com.",
"rr2---sn-a5mekndl.googlevideo.com.",
"rr2---sn-a5mekndl.gvt1.com.",
"rr2---sn-a5meknds.googlevideo.com.",
@@ -4240,20 +4374,21 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-a5meknzk.googlevideo.com.",
"rr2---sn-a5meknzk.gvt1.com.",
"rr2---sn-a5meknzl.googlevideo.com.",
- "rr2---sn-a5meknzl.gvt1.com.",
"rr2---sn-a5meknzr.googlevideo.com.",
+ "rr2---sn-a5meknzr.gvt1.com.",
"rr2---sn-a5mlrnl6.googlevideo.com.",
+ "rr2---sn-a5mlrnl6.gvt1.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-a5msen7l.gvt1.com.",
"rr2---sn-a5msen7s.googlevideo.com.",
"rr2---sn-a5msen7z.googlevideo.com.",
"rr2---sn-a5msenek.googlevideo.com.",
+ "rr2---sn-a5msenek.gvt1.com.",
"rr2---sn-a5msener.googlevideo.com.",
- "rr2---sn-a5msener.gvt1.com.",
"rr2---sn-a5msenes.googlevideo.com.",
"rr2---sn-a5msenes.gvt1.com.",
"rr2---sn-a5msenl7.googlevideo.com.",
@@ -4261,7 +4396,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-a5msenle.googlevideo.com.",
"rr2---sn-a5msenle.gvt1.com.",
"rr2---sn-a5msenll.googlevideo.com.",
- "rr2---sn-a5msenll.gvt1.com.",
"rr2---sn-ab5l6ndr.googlevideo.com.",
"rr2---sn-ab5l6ndy.googlevideo.com.",
"rr2---sn-ab5l6nk6.googlevideo.com.",
@@ -4270,20 +4404,15 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-ab5l6nr6.gvt1.com.",
"rr2---sn-ab5l6nrd.googlevideo.com.",
"rr2---sn-ab5l6nrk.googlevideo.com.",
- "rr2---sn-ab5l6nrk.gvt1.com.",
"rr2---sn-ab5l6nrl.googlevideo.com.",
"rr2---sn-ab5l6nrr.googlevideo.com.",
"rr2---sn-ab5l6nrr.gvt1.com.",
"rr2---sn-ab5l6nrs.googlevideo.com.",
- "rr2---sn-ab5l6nrs.gvt1.com.",
"rr2---sn-ab5l6nrz.googlevideo.com.",
- "rr2---sn-ab5l6nrz.gvt1.com.",
"rr2---sn-ab5sznld.googlevideo.com.",
"rr2---sn-ab5sznly.googlevideo.com.",
"rr2---sn-ab5sznz6.googlevideo.com.",
- "rr2---sn-ab5sznz6.gvt1.com.",
"rr2---sn-ab5sznzd.googlevideo.com.",
- "rr2---sn-ab5sznzd.gvt1.com.",
"rr2---sn-ab5sznze.googlevideo.com.",
"rr2---sn-ab5sznzk.googlevideo.com.",
"rr2---sn-ab5sznzl.googlevideo.com.",
@@ -4292,27 +4421,22 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-ab5sznzs.googlevideo.com.",
"rr2---sn-ab5sznzy.googlevideo.com.",
"rr2---sn-ab5sznzz.googlevideo.com.",
- "rr2---sn-ab5sznzz.gvt1.com.",
"rr2---sn-aigl6n6s.googlevideo.com.",
- "rr2---sn-aigl6n6s.gvt1.com.",
"rr2---sn-aigl6ned.googlevideo.com.",
"rr2---sn-aigl6nek.googlevideo.com.",
"rr2---sn-aigl6ner.googlevideo.com.",
- "rr2---sn-aigl6ner.gvt1.com.",
"rr2---sn-aigl6ney.googlevideo.com.",
"rr2---sn-aigl6nl7.googlevideo.com.",
"rr2---sn-aigl6ns6.googlevideo.com.",
- "rr2---sn-aigl6nsd.googlevideo.com.",
- "rr2---sn-aigl6nsd.gvt1.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-aigl6nzs.gvt1.com.",
"rr2---sn-aigzrn76.googlevideo.com.",
"rr2---sn-aigzrn7d.googlevideo.com.",
"rr2---sn-aigzrn7e.googlevideo.com.",
@@ -4329,10 +4453,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-aigzrnz7.googlevideo.com.",
"rr2---sn-aigzrnze.googlevideo.com.",
"rr2---sn-aj5ua5-5c.googlevideo.com.",
+ "rr2---sn-ajab55-55.googlevideo.com.",
"rr2---sn-avbpj-cq5e.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-cvb7lnls.googlevideo.com.",
@@ -4343,18 +4465,21 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-fpnjoxu-hnol.googlevideo.com.",
"rr2---sn-gpuuxg-hxhl.googlevideo.com.",
"rr2---sn-gpuuxg-hxhs.googlevideo.com.",
- "rr2---sn-gpuuxg-hxhs.gvt1.com.",
"rr2---sn-gpuuxg-hxhz.googlevideo.com.",
- "rr2---sn-gpuuxg-hxhz.gvt1.com.",
+ "rr2---sn-hgn7rn7r.googlevideo.com.",
+ "rr2---sn-hjoj-gq0l.googlevideo.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-hp57kndk.gvt1.com.",
"rr2---sn-hp57kndr.googlevideo.com.",
"rr2---sn-hp57knds.googlevideo.com.",
"rr2---sn-hp57knds.gvt1.com.",
@@ -4362,18 +4487,17 @@ var FakeECSFQDNs = container.NewMapSet(
"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-hp57yns7.gvt1.com.",
"rr2---sn-hp57ynse.googlevideo.com.",
"rr2---sn-hp57ynsl.googlevideo.com.",
"rr2---sn-hp57ynsl.gvt1.com.",
"rr2---sn-hp57ynss.googlevideo.com.",
- "rr2---sn-hp57ynss.gvt1.com.",
"rr2---sn-hxgpu-qufs.googlevideo.com.",
"rr2---sn-i3b7kn6s.googlevideo.com.",
"rr2---sn-i3b7knld.googlevideo.com.",
@@ -4381,7 +4505,6 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -4392,31 +4515,34 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-i3belnls.googlevideo.com.",
"rr2---sn-i3belnlz.googlevideo.com.",
"rr2---sn-i3bssn7e.googlevideo.com.",
- "rr2---sn-i5f5ppuxa-ioal.googlevideo.com.",
"rr2---sn-i5f5ppuxa-ioas.googlevideo.com.",
"rr2---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
"rr2---sn-jvhj5nu-2iae.googlevideo.com.",
+ "rr2---sn-jvhj5nu-2ial.googlevideo.com.",
+ "rr2---sn-jvhj5nu-2ias.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-qufz.googlevideo.com.",
"rr2---sn-jvooxqouf3-cqaz.googlevideo.com.",
"rr2---sn-jxopj-n5oe.googlevideo.com.",
"rr2---sn-jxopj-nh4e.googlevideo.com.",
"rr2---sn-jxopj-nh4e.gvt1.com.",
"rr2---sn-n2uxaxjvh-j5xl.googlevideo.com.",
+ "rr2---sn-n2uxaxjvh-j5xl.gvt1.com.",
"rr2---sn-n2uxaxjvh-j5xs.googlevideo.com.",
+ "rr2---sn-n2uxaxjvh-j5xs.gvt1.com.",
"rr2---sn-n4v7snee.googlevideo.com.",
"rr2---sn-n4v7sney.googlevideo.com.",
"rr2---sn-n4v7snl7.googlevideo.com.",
"rr2---sn-n4v7snll.googlevideo.com.",
"rr2---sn-n4v7snlr.googlevideo.com.",
"rr2---sn-n4v7snls.googlevideo.com.",
- "rr2---sn-n4v7snls.gvt1.com.",
"rr2---sn-n4v7snly.googlevideo.com.",
"rr2---sn-n4v7sns7.googlevideo.com.",
"rr2---sn-n4v7snse.googlevideo.com.",
- "rr2---sn-n4v7snse.gvt1.com.",
"rr2---sn-nh5gujvh-h4xe.googlevideo.com.",
"rr2---sn-nh5gujvh-h4xe.gvt1.com.",
"rr2---sn-npoe7ndl.googlevideo.com.",
@@ -4433,10 +4559,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-npoe7nlz.googlevideo.com.",
"rr2---sn-npoe7ns6.googlevideo.com.",
"rr2---sn-npoe7ns7.googlevideo.com.",
- "rr2---sn-npoe7ns7.gvt1.com.",
"rr2---sn-npoe7nsd.googlevideo.com.",
- "rr2---sn-npoe7nsd.gvt1.com.",
"rr2---sn-npoe7nsk.googlevideo.com.",
+ "rr2---sn-npoe7nsl.googlevideo.com.",
"rr2---sn-npoe7nsr.googlevideo.com.",
"rr2---sn-npoe7nss.googlevideo.com.",
"rr2---sn-npoe7nsy.googlevideo.com.",
@@ -4448,7 +4573,6 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -4456,7 +4580,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-npoeens7.googlevideo.com.",
"rr2---sn-npoldn76.googlevideo.com.",
"rr2---sn-npoldn7d.googlevideo.com.",
- "rr2---sn-npoldn7d.gvt1.com.",
"rr2---sn-npoldn7e.googlevideo.com.",
"rr2---sn-npoldn7l.googlevideo.com.",
"rr2---sn-npoldn7s.googlevideo.com.",
@@ -4464,29 +4587,26 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-npoldn7y.googlevideo.com.",
"rr2---sn-npoldn7z.googlevideo.com.",
"rr2---sn-npoldne7.googlevideo.com.",
- "rr2---sn-ntq7yney.googlevideo.com.",
+ "rr2---sn-ntq7yned.googlevideo.com.",
"rr2---sn-nuagpm-nuae.googlevideo.com.",
"rr2---sn-nv0uixgo-5ual.googlevideo.com.",
"rr2---sn-nx57ynlk.googlevideo.com.",
"rr2---sn-nx57ynsd.googlevideo.com.",
"rr2---sn-nx57ynsd.gvt1.com.",
"rr2---sn-nx57ynse.googlevideo.com.",
- "rr2---sn-nx57ynse.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-nx5s7n7s.googlevideo.com.",
"rr2---sn-nx5s7n7y.googlevideo.com.",
- "rr2---sn-nx5s7n7y.gvt1.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-o097znsk.googlevideo.com.",
@@ -4500,26 +4620,22 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-o097znzk.googlevideo.com.",
"rr2---sn-o097znzr.googlevideo.com.",
"rr2---sn-oj5hn5-55.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-p5qddn7z.gvt1.com.",
"rr2---sn-p5qlsn6l.googlevideo.com.",
- "rr2---sn-p5qlsn6l.gvt1.com.",
"rr2---sn-p5qlsn76.googlevideo.com.",
"rr2---sn-p5qlsn7d.googlevideo.com.",
+ "rr2---sn-p5qlsn7d.gvt1.com.",
"rr2---sn-p5qlsn7l.googlevideo.com.",
"rr2---sn-p5qlsn7s.googlevideo.com.",
"rr2---sn-p5qlsnd6.googlevideo.com.",
- "rr2---sn-p5qlsndk.googlevideo.com.",
"rr2---sn-p5qlsndr.googlevideo.com.",
"rr2---sn-p5qlsndz.googlevideo.com.",
"rr2---sn-p5qlsnrl.googlevideo.com.",
"rr2---sn-p5qlsnrr.googlevideo.com.",
- "rr2---sn-p5qlsnrr.gvt1.com.",
"rr2---sn-p5qlsny6.googlevideo.com.",
"rr2---sn-p5qs7n6d.googlevideo.com.",
"rr2---sn-p5qs7nsk.googlevideo.com.",
@@ -4530,7 +4646,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-paapovpnjxou0gt-nual.googlevideo.com.",
"rr2---sn-paapovpnjxou0gt-nuas.googlevideo.com.",
"rr2---sn-pjnpu-5hfe.googlevideo.com.",
- "rr2---sn-pjx-nwv6.googlevideo.com.",
"rr2---sn-pobpb-poql.googlevideo.com.",
"rr2---sn-q4fl6n66.googlevideo.com.",
"rr2---sn-q4fl6n66.gvt1.com.",
@@ -4541,7 +4656,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-q4fl6n6s.googlevideo.com.",
"rr2---sn-q4fl6n6s.gvt1.com.",
"rr2---sn-q4fl6n6y.googlevideo.com.",
- "rr2---sn-q4fl6n6y.gvt1.com.",
"rr2---sn-q4fl6n6z.googlevideo.com.",
"rr2---sn-q4fl6n6z.gvt1.com.",
"rr2---sn-q4fl6nd7.googlevideo.com.",
@@ -4555,7 +4669,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-q4fl6nlz.googlevideo.com.",
"rr2---sn-q4fl6ns6.googlevideo.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.",
@@ -4563,40 +4676,37 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-q4fl6nsl.googlevideo.com.",
"rr2---sn-q4fl6nsl.gvt1.com.",
"rr2---sn-q4fl6nsr.googlevideo.com.",
+ "rr2---sn-q4fl6nsr.gvt1.com.",
"rr2---sn-q4fl6nss.googlevideo.com.",
- "rr2---sn-q4fl6nss.gvt1.com.",
"rr2---sn-q4fl6nsy.googlevideo.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-q4flrn7k.gvt1.com.",
"rr2---sn-q4flrn7r.googlevideo.com.",
- "rr2---sn-q4flrn7r.gvt1.com.",
"rr2---sn-q4flrn7y.googlevideo.com.",
"rr2---sn-q4flrne6.googlevideo.com.",
- "rr2---sn-q4flrne6.gvt1.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-q4flrnek.gvt1.com.",
"rr2---sn-q4flrnel.googlevideo.com.",
+ "rr2---sn-q4flrnel.gvt1.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-q4flrney.gvt1.com.",
"rr2---sn-q4flrnez.googlevideo.com.",
"rr2---sn-q4flrnl6.googlevideo.com.",
+ "rr2---sn-q4flrnl6.gvt1.com.",
"rr2---sn-q4flrnl7.googlevideo.com.",
"rr2---sn-q4flrnld.googlevideo.com.",
"rr2---sn-q4flrnld.gvt1.com.",
"rr2---sn-q4flrnle.googlevideo.com.",
- "rr2---sn-q4flrnle.gvt1.com.",
+ "rr2---sn-q4flrnlz.googlevideo.com.",
"rr2---sn-q4flrnsd.googlevideo.com.",
"rr2---sn-q4flrnsd.gvt1.com.",
"rr2---sn-q4flrnsk.googlevideo.com.",
@@ -4611,9 +4721,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-q4fzen7r.googlevideo.com.",
"rr2---sn-q4fzen7r.gvt1.com.",
"rr2---sn-q4fzen7s.googlevideo.com.",
- "rr2---sn-q4fzen7y.googlevideo.com.",
+ "rr2---sn-q4fzen7s.gvt1.com.",
"rr2---sn-q4fzene7.googlevideo.com.",
- "rr2---sn-q4fzene7.gvt1.com.",
"rr2---sn-q4fzenee.googlevideo.com.",
"rr2---sn-q4fzenee.gvt1.com.",
"rr2---sn-qjp5q5-55.googlevideo.com.",
@@ -4624,59 +4733,46 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-qxoedne7.googlevideo.com.",
"rr2---sn-qxoednee.googlevideo.com.",
"rr2---sn-u1hp55-5c.googlevideo.com.",
+ "rr2---sn-uqnuxaxjvh-hnoe.googlevideo.com.",
"rr2---sn-v53a5oqnji-4oul.googlevideo.com.",
"rr2---sn-v5goxu-jhi6.googlevideo.com.",
"rr2---sn-v5goxu-jhil.googlevideo.com.",
"rr2---sn-v5goxu-jhiz.googlevideo.com.",
- "rr2---sn-vgqskn66.googlevideo.com.",
- "rr2---sn-vgqskn66.gvt1.com.",
"rr2---sn-vgqskn67.googlevideo.com.",
+ "rr2---sn-vgqskn67.gvt1.com.",
"rr2---sn-vgqskn6d.googlevideo.com.",
"rr2---sn-vgqskn6s.googlevideo.com.",
- "rr2---sn-vgqskn6s.gvt1.com.",
"rr2---sn-vgqskn6z.googlevideo.com.",
- "rr2---sn-vgqskn6z.gvt1.com.",
+ "rr2---sn-vgqskne6.googlevideo.com.",
"rr2---sn-vgqskned.googlevideo.com.",
- "rr2---sn-vgqskned.gvt1.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-vgqsknlk.googlevideo.com.",
- "rr2---sn-vgqsknlk.gvt1.com.",
"rr2---sn-vgqsknll.googlevideo.com.",
- "rr2---sn-vgqsknll.gvt1.com.",
"rr2---sn-vgqsknlr.googlevideo.com.",
"rr2---sn-vgqsknls.googlevideo.com.",
"rr2---sn-vgqsknly.googlevideo.com.",
+ "rr2---sn-vgqsknly.gvt1.com.",
"rr2---sn-vgqsknlz.googlevideo.com.",
"rr2---sn-vgqskns7.googlevideo.com.",
- "rr2---sn-vgqsknse.googlevideo.com.",
"rr2---sn-vgqsknsk.googlevideo.com.",
- "rr2---sn-vgqsknsk.gvt1.com.",
"rr2---sn-vgqsknz6.googlevideo.com.",
- "rr2---sn-vgqsknz6.gvt1.com.",
"rr2---sn-vgqsknz7.googlevideo.com.",
- "rr2---sn-vgqsknz7.gvt1.com.",
"rr2---sn-vgqsknzd.googlevideo.com.",
"rr2---sn-vgqsknze.googlevideo.com.",
"rr2---sn-vgqsknzk.googlevideo.com.",
"rr2---sn-vgqsknzl.googlevideo.com.",
- "rr2---sn-vgqsknzl.gvt1.com.",
"rr2---sn-vgqsknzr.googlevideo.com.",
+ "rr2---sn-vgqsknzr.gvt1.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-vgqsrn66.gvt1.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-vgqsrn6z.gvt1.com.",
"rr2---sn-vgqsrne6.googlevideo.com.",
@@ -4687,17 +4783,13 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-vgqsrnl6.googlevideo.com.",
"rr2---sn-vgqsrnld.googlevideo.com.",
"rr2---sn-vgqsrnlk.googlevideo.com.",
- "rr2---sn-vgqsrnlk.gvt1.com.",
"rr2---sn-vgqsrnll.googlevideo.com.",
"rr2---sn-vgqsrnls.googlevideo.com.",
- "rr2---sn-vgqsrnls.gvt1.com.",
"rr2---sn-vgqsrnlz.googlevideo.com.",
- "rr2---sn-vgqsrnlz.gvt1.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-vgqsrnz7.gvt1.com.",
@@ -4711,20 +4803,10 @@ var FakeECSFQDNs = container.NewMapSet(
"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-5hneknek.googlevideo.com.",
- "rr2.sn-aigl6ney.googlevideo.com.",
"rr2.sn-hp57knds.googlevideo.com.",
- "rr2.sn-ntq7yney.googlevideo.com.",
- "rr2.sn-nx57ynsk.googlevideo.com.",
- "rr2.sn-p5qs7nsk.googlevideo.com.",
- "rr2.sn-q4fl6nlz.googlevideo.com.",
+ "rr2.sn-ntq7yned.googlevideo.com.",
"rr2.sn-q4fl6nsk.googlevideo.com.",
- "rr2.sn-q4flrnee.googlevideo.com.",
- "rr2.sn-q4flrnel.googlevideo.com.",
- "rr2.sn-q4flrnl7.googlevideo.com.",
- "rr2.sn-q4fzen7l.googlevideo.com.",
- "rr2.sn-vgqsrnzz.googlevideo.com.",
+ "rr2.sn-q4fl6nsr.googlevideo.com.",
"rr3---sn-0nnpbo5a-bggl.googlevideo.com.",
"rr3---sn-2imern76.googlevideo.com.",
"rr3---sn-2imern7d.googlevideo.com.",
@@ -4732,7 +4814,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-2napbiu-p5ie.googlevideo.com.",
"rr3---sn-2napbiu-p5ie.gvt1.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.",
@@ -4760,7 +4841,6 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -4776,13 +4856,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-4g5ednsk.googlevideo.com.",
"rr3---sn-4g5ednsl.googlevideo.com.",
"rr3---sn-4g5ednsr.googlevideo.com.",
- "rr3---sn-4g5ednsy.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-4g5lznek.gvt1.com.",
"rr3---sn-4g5lzner.googlevideo.com.",
"rr3---sn-4g5lznes.googlevideo.com.",
"rr3---sn-4g5lzney.googlevideo.com.",
@@ -4792,50 +4871,46 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-4g5lznle.googlevideo.com.",
"rr3---sn-4g5lznls.googlevideo.com.",
"rr3---sn-4g5lznlz.googlevideo.com.",
+ "rr3---sn-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
+ "rr3---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
+ "rr3---sn-5abxgpxuxaxjvh-9n4z.googlevideo.com.",
"rr3---sn-5hne6n6e.googlevideo.com.",
"rr3---sn-5hne6n6l.googlevideo.com.",
"rr3---sn-5hne6ns6.googlevideo.com.",
"rr3---sn-5hne6nsd.googlevideo.com.",
- "rr3---sn-5hne6nsd.gvt1.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-5hne6nz6.gvt1.com.",
"rr3---sn-5hne6nzd.googlevideo.com.",
"rr3---sn-5hne6nzk.googlevideo.com.",
"rr3---sn-5hne6nzs.googlevideo.com.",
"rr3---sn-5hne6nzy.googlevideo.com.",
- "rr3---sn-5hne6nzy.gvt1.com.",
"rr3---sn-5hnednss.googlevideo.com.",
"rr3---sn-5hnednsz.googlevideo.com.",
- "rr3---sn-5hnednsz.gvt1.com.",
"rr3---sn-5hnekn76.googlevideo.com.",
"rr3---sn-5hnekn7d.googlevideo.com.",
"rr3---sn-5hnekn7l.googlevideo.com.",
"rr3---sn-5hnekn7s.googlevideo.com.",
- "rr3---sn-5hnekn7s.gvt1.com.",
"rr3---sn-5hnekn7z.googlevideo.com.",
"rr3---sn-5hneknee.googlevideo.com.",
"rr3---sn-5hneknek.googlevideo.com.",
"rr3---sn-5hneknes.googlevideo.com.",
- "rr3---sn-5hneknes.gvt1.com.",
- "rr3---sn-5pgnugx5h-hn2z.googlevideo.com.",
"rr3---sn-5uaezndd.googlevideo.com.",
"rr3---sn-5uaezne6.googlevideo.com.",
"rr3---sn-5uaezned.googlevideo.com.",
+ "rr3---sn-5uaeznel.googlevideo.com.",
"rr3---sn-5uaeznes.googlevideo.com.",
+ "rr3---sn-5uaeznez.googlevideo.com.",
"rr3---sn-5uaeznl6.googlevideo.com.",
"rr3---sn-5uaeznld.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-5uaezny6.googlevideo.com.",
- "rr3---sn-5uaeznys.googlevideo.com.",
"rr3---sn-5uaeznyz.googlevideo.com.",
"rr3---sn-5uaeznze.googlevideo.com.",
"rr3---sn-5ualdnle.googlevideo.com.",
@@ -4855,6 +4930,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-5ualdnz7.googlevideo.com.",
"rr3---sn-5ualdnze.googlevideo.com.",
"rr3---sn-8qj-nbo66.googlevideo.com.",
+ "rr3---sn-8xgp1vo-2iae7.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.",
@@ -4871,93 +4948,85 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-9gv76n7z.googlevideo.com.",
"rr3---sn-9gv7ene6.googlevideo.com.",
"rr3---sn-9gv7ened.googlevideo.com.",
+ "rr3---sn-9gv7zn76.googlevideo.com.",
"rr3---sn-9gv7zn7e.googlevideo.com.",
"rr3---sn-9gv7zn7r.googlevideo.com.",
"rr3---sn-9gv7zn7y.googlevideo.com.",
"rr3---sn-a5m7lnl6.googlevideo.com.",
"rr3---sn-a5m7lnld.googlevideo.com.",
- "rr3---sn-a5m7lnld.gvt1.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-a5mekn6r.gvt1.com.",
"rr3---sn-a5mekn6s.googlevideo.com.",
"rr3---sn-a5mekn6s.gvt1.com.",
"rr3---sn-a5mekn6z.googlevideo.com.",
- "rr3---sn-a5mekn6z.gvt1.com.",
"rr3---sn-a5meknd6.googlevideo.com.",
"rr3---sn-a5meknd6.gvt1.com.",
"rr3---sn-a5meknde.googlevideo.com.",
"rr3---sn-a5mekndl.googlevideo.com.",
+ "rr3---sn-a5mekndl.gvt1.com.",
"rr3---sn-a5meknds.googlevideo.com.",
"rr3---sn-a5mekndz.googlevideo.com.",
+ "rr3---sn-a5mekndz.gvt1.com.",
"rr3---sn-a5meknsd.googlevideo.com.",
- "rr3---sn-a5meknsd.gvt1.com.",
"rr3---sn-a5meknsy.googlevideo.com.",
"rr3---sn-a5meknzk.googlevideo.com.",
"rr3---sn-a5meknzl.googlevideo.com.",
"rr3---sn-a5meknzr.googlevideo.com.",
"rr3---sn-a5meknzs.googlevideo.com.",
"rr3---sn-a5mlrnek.googlevideo.com.",
- "rr3---sn-a5mlrnek.gvt1.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-a5mlrnls.gvt1.com.",
"rr3---sn-a5mlrnlz.googlevideo.com.",
"rr3---sn-a5msen76.googlevideo.com.",
+ "rr3---sn-a5msen76.gvt1.com.",
"rr3---sn-a5msen7l.googlevideo.com.",
"rr3---sn-a5msen7s.googlevideo.com.",
+ "rr3---sn-a5msen7s.gvt1.com.",
"rr3---sn-a5msen7z.googlevideo.com.",
"rr3---sn-a5msener.googlevideo.com.",
- "rr3---sn-a5msener.gvt1.com.",
"rr3---sn-a5msenes.googlevideo.com.",
- "rr3---sn-a5msenes.gvt1.com.",
"rr3---sn-a5msenl7.googlevideo.com.",
"rr3---sn-a5msenl7.gvt1.com.",
"rr3---sn-a5msenle.googlevideo.com.",
"rr3---sn-a5msenll.googlevideo.com.",
- "rr3---sn-a5msenll.gvt1.com.",
"rr3---sn-ab5l6ndr.googlevideo.com.",
"rr3---sn-ab5l6ndy.googlevideo.com.",
"rr3---sn-ab5l6nk6.googlevideo.com.",
"rr3---sn-ab5l6nk6.gvt1.com.",
"rr3---sn-ab5l6nkd.googlevideo.com.",
+ "rr3---sn-ab5l6nkd.gvt1.com.",
"rr3---sn-ab5l6nr6.googlevideo.com.",
"rr3---sn-ab5l6nrd.googlevideo.com.",
"rr3---sn-ab5l6nrd.gvt1.com.",
"rr3---sn-ab5l6nrk.googlevideo.com.",
"rr3---sn-ab5l6nrl.googlevideo.com.",
+ "rr3---sn-ab5l6nrl.gvt1.com.",
"rr3---sn-ab5l6nrr.googlevideo.com.",
- "rr3---sn-ab5l6nrr.gvt1.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-ab5sznly.googlevideo.com.",
"rr3---sn-ab5sznz6.googlevideo.com.",
- "rr3---sn-ab5sznz6.gvt1.com.",
"rr3---sn-ab5sznzd.googlevideo.com.",
- "rr3---sn-ab5sznzd.gvt1.com.",
"rr3---sn-ab5sznze.googlevideo.com.",
- "rr3---sn-ab5sznze.gvt1.com.",
"rr3---sn-ab5sznzk.googlevideo.com.",
"rr3---sn-ab5sznzl.googlevideo.com.",
"rr3---sn-ab5sznzr.googlevideo.com.",
- "rr3---sn-ab5sznzr.gvt1.com.",
"rr3---sn-ab5sznzs.googlevideo.com.",
- "rr3---sn-ab5sznzs.gvt1.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.",
@@ -4967,7 +5036,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-aigl6nze.googlevideo.com.",
"rr3---sn-aigl6nze.gvt1.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.",
@@ -4985,15 +5053,13 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-aigzrnsz.googlevideo.com.",
"rr3---sn-aigzrnz7.googlevideo.com.",
"rr3---sn-aigzrnze.googlevideo.com.",
- "rr3---sn-aj5ua5-5c.googlevideo.com.",
- "rr3---sn-ajab55-55.googlevideo.com.",
- "rr3---sn-bg5oqxjvh-50nz.googlevideo.com.",
"rr3---sn-cvb7lne7.googlevideo.com.",
- "rr3---sn-cvb7lnls.googlevideo.com.",
"rr3---sn-cvb7lnlz.googlevideo.com.",
"rr3---sn-cvb7sn7r.googlevideo.com.",
"rr3---sn-gpuuxg-hxhl.googlevideo.com.",
- "rr3---sn-gpuuxg-hxhl.gvt1.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.",
@@ -5001,28 +5067,28 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-hp57kn6r.googlevideo.com.",
"rr3---sn-hp57kn6r.gvt1.com.",
"rr3---sn-hp57kn6y.googlevideo.com.",
+ "rr3---sn-hp57kn6y.gvt1.com.",
"rr3---sn-hp57knd6.googlevideo.com.",
"rr3---sn-hp57knd6.gvt1.com.",
"rr3---sn-hp57kndd.googlevideo.com.",
- "rr3---sn-hp57kndd.gvt1.com.",
+ "rr3---sn-hp57kndk.googlevideo.com.",
"rr3---sn-hp57kndr.googlevideo.com.",
+ "rr3---sn-hp57kndr.gvt1.com.",
"rr3---sn-hp57knds.googlevideo.com.",
- "rr3---sn-hp57knds.gvt1.com.",
"rr3---sn-hp57kndy.googlevideo.com.",
- "rr3---sn-hp57kndy.gvt1.com.",
"rr3---sn-hp57kndz.googlevideo.com.",
"rr3---sn-hp57yn7r.googlevideo.com.",
"rr3---sn-hp57yn7y.googlevideo.com.",
- "rr3---sn-hp57yn7y.gvt1.com.",
"rr3---sn-hp57yne7.googlevideo.com.",
- "rr3---sn-hp57yne7.gvt1.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-hp57yns7.gvt1.com.",
"rr3---sn-hp57ynse.googlevideo.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.",
@@ -5034,18 +5100,23 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-i3b7knzl.googlevideo.com.",
"rr3---sn-i3b7knzs.googlevideo.com.",
"rr3---sn-i3belne6.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-jn2pgx4pcxg-w5os.googlevideo.com.",
"rr3---sn-jvhj5nu-2iae.googlevideo.com.",
+ "rr3---sn-jvhj5nu-2ial.googlevideo.com.",
+ "rr3---sn-jvhj5nu-2ias.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-qufs.googlevideo.com.",
+ "rr3---sn-jvhj5nu-qufz.googlevideo.com.",
"rr3---sn-jxopj-n5oe.googlevideo.com.",
"rr3---sn-jxopj-nh4e.googlevideo.com.",
"rr3---sn-jxopj-nh4e.gvt1.com.",
@@ -5056,14 +5127,15 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-n4v7snlr.googlevideo.com.",
"rr3---sn-n4v7snls.googlevideo.com.",
"rr3---sn-n4v7snly.googlevideo.com.",
+ "rr3---sn-n4v7snly.gvt1.com.",
"rr3---sn-n4v7sns7.googlevideo.com.",
"rr3---sn-n4v7snse.googlevideo.com.",
- "rr3---sn-n4v7snse.gvt1.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.",
@@ -5072,9 +5144,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-npoe7nlz.googlevideo.com.",
"rr3---sn-npoe7ns6.googlevideo.com.",
"rr3---sn-npoe7ns7.googlevideo.com.",
- "rr3---sn-npoe7ns7.gvt1.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.",
@@ -5097,29 +5169,27 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-npoldn7e.googlevideo.com.",
"rr3---sn-npoldn7l.googlevideo.com.",
"rr3---sn-npoldn7s.googlevideo.com.",
- "rr3---sn-npoldn7s.gvt1.com.",
"rr3---sn-npoldn7y.googlevideo.com.",
"rr3---sn-npoldn7z.googlevideo.com.",
"rr3---sn-npoldne7.googlevideo.com.",
- "rr3---sn-ntqe6nes.googlevideo.com.",
"rr3---sn-nx57ynlk.googlevideo.com.",
- "rr3---sn-nx57ynlk.gvt1.com.",
"rr3---sn-nx57ynsd.googlevideo.com.",
+ "rr3---sn-nx57ynsd.gvt1.com.",
"rr3---sn-nx57ynsk.googlevideo.com.",
- "rr3---sn-nx57ynsk.gvt1.com.",
"rr3---sn-nx57ynsl.googlevideo.com.",
"rr3---sn-nx57ynss.googlevideo.com.",
"rr3---sn-nx57ynss.gvt1.com.",
+ "rr3---sn-nx57ynsz.googlevideo.com.",
"rr3---sn-nx5s7n76.googlevideo.com.",
"rr3---sn-nx5s7n7d.googlevideo.com.",
"rr3---sn-nx5s7n7s.googlevideo.com.",
"rr3---sn-nx5s7n7y.googlevideo.com.",
"rr3---sn-nx5s7n7z.googlevideo.com.",
"rr3---sn-nx5s7nee.googlevideo.com.",
+ "rr3---sn-nx5s7nel.googlevideo.com.",
"rr3---sn-o097znsd.googlevideo.com.",
"rr3---sn-o097znse.googlevideo.com.",
"rr3---sn-o097znsk.googlevideo.com.",
- "rr3---sn-o097znsk.gvt1.com.",
"rr3---sn-o097znsl.googlevideo.com.",
"rr3---sn-o097znsr.googlevideo.com.",
"rr3---sn-o097znss.googlevideo.com.",
@@ -5128,12 +5198,13 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-o097znzd.googlevideo.com.",
"rr3---sn-o097znze.googlevideo.com.",
"rr3---sn-o097znzk.googlevideo.com.",
+ "rr3---sn-o097znzr.googlevideo.com.",
"rr3---sn-oj5hn5-55.googlevideo.com.",
- "rr3---sn-oj5hn5-55.gvt1.com.",
"rr3---sn-p5qddn76.googlevideo.com.",
"rr3---sn-p5qddn7d.googlevideo.com.",
"rr3---sn-p5qddn7k.googlevideo.com.",
"rr3---sn-p5qddn7r.googlevideo.com.",
+ "rr3---sn-p5qddn7z.googlevideo.com.",
"rr3---sn-p5qlsn6l.googlevideo.com.",
"rr3---sn-p5qlsn76.googlevideo.com.",
"rr3---sn-p5qlsn7d.googlevideo.com.",
@@ -5148,8 +5219,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-p5qlsny6.googlevideo.com.",
"rr3---sn-p5qs7n6d.googlevideo.com.",
"rr3---sn-p5qs7nsk.googlevideo.com.",
- "rr3---sn-p5qs7nsk.gvt1.com.",
"rr3---sn-p5qs7nsr.googlevideo.com.",
+ "rr3---sn-p5qs7nsr.gvt1.com.",
"rr3---sn-p5qs7nzk.googlevideo.com.",
"rr3---sn-p5qs7nzr.googlevideo.com.",
"rr3---sn-p5qs7nzy.googlevideo.com.",
@@ -5165,13 +5236,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-q4fl6n6z.googlevideo.com.",
"rr3---sn-q4fl6n6z.gvt1.com.",
"rr3---sn-q4fl6nd7.googlevideo.com.",
- "rr3---sn-q4fl6nd7.gvt1.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-q4fl6nds.gvt1.com.",
"rr3---sn-q4fl6ndz.googlevideo.com.",
"rr3---sn-q4fl6ndz.gvt1.com.",
"rr3---sn-q4fl6nlz.googlevideo.com.",
@@ -5183,63 +5249,50 @@ var FakeECSFQDNs = container.NewMapSet(
"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-q4fl6nsr.gvt1.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-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-q4flrn7y.gvt1.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-q4flrner.gvt1.com.",
"rr3---sn-q4flrnes.googlevideo.com.",
- "rr3---sn-q4flrnes.gvt1.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-q4flrnlz.googlevideo.com.",
- "rr3---sn-q4flrnlz.gvt1.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-q4flrnss.gvt1.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-q4fzenee.googlevideo.com.",
- "rr3---sn-q4fzenee.gvt1.com.",
"rr3---sn-qjp5q5-55.googlevideo.com.",
"rr3---sn-qxo7rn7k.googlevideo.com.",
"rr3---sn-qxo7rn7r.googlevideo.com.",
@@ -5250,78 +5303,56 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-u1hp55-5c.googlevideo.com.",
"rr3---sn-v5goxu-jhil.googlevideo.com.",
"rr3---sn-vgqskn66.googlevideo.com.",
- "rr3---sn-vgqskn66.gvt1.com.",
"rr3---sn-vgqskn67.googlevideo.com.",
- "rr3---sn-vgqskn67.gvt1.com.",
"rr3---sn-vgqskn6d.googlevideo.com.",
"rr3---sn-vgqskn6d.gvt1.com.",
"rr3---sn-vgqskn6s.googlevideo.com.",
"rr3---sn-vgqskn6s.gvt1.com.",
"rr3---sn-vgqskn6z.googlevideo.com.",
"rr3---sn-vgqskne6.googlevideo.com.",
- "rr3---sn-vgqskne6.gvt1.com.",
"rr3---sn-vgqskned.googlevideo.com.",
+ "rr3---sn-vgqskned.gvt1.com.",
"rr3---sn-vgqsknek.googlevideo.com.",
"rr3---sn-vgqsknes.googlevideo.com.",
"rr3---sn-vgqsknez.googlevideo.com.",
- "rr3---sn-vgqsknez.gvt1.com.",
"rr3---sn-vgqsknld.googlevideo.com.",
- "rr3---sn-vgqsknld.gvt1.com.",
"rr3---sn-vgqsknlk.googlevideo.com.",
- "rr3---sn-vgqsknlk.gvt1.com.",
"rr3---sn-vgqsknll.googlevideo.com.",
- "rr3---sn-vgqsknll.gvt1.com.",
"rr3---sn-vgqsknlr.googlevideo.com.",
"rr3---sn-vgqsknly.googlevideo.com.",
"rr3---sn-vgqsknlz.googlevideo.com.",
- "rr3---sn-vgqsknlz.gvt1.com.",
"rr3---sn-vgqskns7.googlevideo.com.",
- "rr3---sn-vgqskns7.gvt1.com.",
"rr3---sn-vgqsknse.googlevideo.com.",
"rr3---sn-vgqsknse.gvt1.com.",
"rr3---sn-vgqsknsk.googlevideo.com.",
"rr3---sn-vgqsknz6.googlevideo.com.",
- "rr3---sn-vgqsknz6.gvt1.com.",
"rr3---sn-vgqsknz7.googlevideo.com.",
- "rr3---sn-vgqsknz7.gvt1.com.",
"rr3---sn-vgqsknzd.googlevideo.com.",
"rr3---sn-vgqsknze.googlevideo.com.",
- "rr3---sn-vgqsknze.gvt1.com.",
"rr3---sn-vgqsknzk.googlevideo.com.",
"rr3---sn-vgqsknzl.googlevideo.com.",
- "rr3---sn-vgqsknzl.gvt1.com.",
"rr3---sn-vgqsknzr.googlevideo.com.",
"rr3---sn-vgqsknzr.gvt1.com.",
"rr3---sn-vgqsknzs.googlevideo.com.",
- "rr3---sn-vgqsknzs.gvt1.com.",
"rr3---sn-vgqsknzy.googlevideo.com.",
- "rr3---sn-vgqsknzy.gvt1.com.",
"rr3---sn-vgqsknzz.googlevideo.com.",
"rr3---sn-vgqsrn66.googlevideo.com.",
- "rr3---sn-vgqsrn66.gvt1.com.",
"rr3---sn-vgqsrn67.googlevideo.com.",
- "rr3---sn-vgqsrn67.gvt1.com.",
"rr3---sn-vgqsrn6e.googlevideo.com.",
- "rr3---sn-vgqsrn6e.gvt1.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-vgqsrne6.gvt1.com.",
"rr3---sn-vgqsrned.googlevideo.com.",
"rr3---sn-vgqsrnek.googlevideo.com.",
"rr3---sn-vgqsrnes.googlevideo.com.",
- "rr3---sn-vgqsrnes.gvt1.com.",
"rr3---sn-vgqsrnez.googlevideo.com.",
"rr3---sn-vgqsrnl6.googlevideo.com.",
- "rr3---sn-vgqsrnl6.gvt1.com.",
"rr3---sn-vgqsrnld.googlevideo.com.",
- "rr3---sn-vgqsrnld.gvt1.com.",
+ "rr3---sn-vgqsrnlk.googlevideo.com.",
"rr3---sn-vgqsrnll.googlevideo.com.",
"rr3---sn-vgqsrnls.googlevideo.com.",
"rr3---sn-vgqsrnlz.googlevideo.com.",
- "rr3---sn-vgqsrnlz.gvt1.com.",
"rr3---sn-vgqsrns6.googlevideo.com.",
"rr3---sn-vgqsrnsd.googlevideo.com.",
"rr3---sn-vgqsrnsr.googlevideo.com.",
@@ -5329,31 +5360,25 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-vgqsrnsy.googlevideo.com.",
"rr3---sn-vgqsrnz6.googlevideo.com.",
"rr3---sn-vgqsrnz7.googlevideo.com.",
- "rr3---sn-vgqsrnz7.gvt1.com.",
"rr3---sn-vgqsrnzd.googlevideo.com.",
+ "rr3---sn-vgqsrnzd.gvt1.com.",
"rr3---sn-vgqsrnzk.googlevideo.com.",
"rr3---sn-vgqsrnzr.googlevideo.com.",
- "rr3---sn-vgqsrnzr.gvt1.com.",
"rr3---sn-vgqsrnzs.googlevideo.com.",
"rr3---sn-vgqsrnzy.googlevideo.com.",
"rr3---sn-vgqsrnzz.googlevideo.com.",
- "rr3---sn-vgqsrnzz.gvt1.com.",
"rr3.sn-5hnednss.googlevideo.com.",
- "rr3.sn-5hnednsz.googlevideo.com.",
- "rr3.sn-hp57knds.googlevideo.com.",
- "rr3.sn-p5qs7nsk.googlevideo.com.",
- "rr3.sn-q4fl6n66.googlevideo.com.",
- "rr3.sn-q4fl6nds.googlevideo.com.",
- "rr3.sn-q4fl6ndz.googlevideo.com.",
+ "rr3.sn-5hneknee.googlevideo.com.",
+ "rr3.sn-q4fl6nd7.googlevideo.com.",
+ "rr3.sn-q4fl6nsy.googlevideo.com.",
+ "rr3.sn-q4flrn7k.googlevideo.com.",
"rr3.sn-q4fzen7l.googlevideo.com.",
- "rr3.sn-vgqsknly.googlevideo.com.",
- "rr3.sn-vgqsknzd.googlevideo.com.",
- "rr3.sn-vgqsrnzz.googlevideo.com.",
+ "rr3.sn-q4fzenee.googlevideo.com.",
"rr4---sn-0nnpbo5a-bggl.googlevideo.com.",
"rr4---sn-2imern76.googlevideo.com.",
"rr4---sn-2imern7d.googlevideo.com.",
- "rr4---sn-2oaig5-55.googlevideo.com.",
- "rr4---sn-30a7rne6.googlevideo.com.",
+ "rr4---sn-2imeyn7k.googlevideo.com.",
+ "rr4---sn-30a7rned.googlevideo.com.",
"rr4---sn-30a7rnek.googlevideo.com.",
"rr4---sn-30a7rner.googlevideo.com.",
"rr4---sn-30a7ynek.googlevideo.com.",
@@ -5397,6 +5422,7 @@ var FakeECSFQDNs = container.NewMapSet(
"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-4g5lznek.googlevideo.com.",
@@ -5406,8 +5432,13 @@ var FakeECSFQDNs = container.NewMapSet(
"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-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
+ "rr4---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
+ "rr4---sn-5abxgpxuxaxjvh-9n4z.googlevideo.com.",
+ "rr4---sn-5abxgpxuxaxjvh-j1az.googlevideo.com.",
"rr4---sn-5hne6n6e.googlevideo.com.",
"rr4---sn-5hne6n6l.googlevideo.com.",
"rr4---sn-5hne6ns6.googlevideo.com.",
@@ -5415,18 +5446,15 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-5hne6nsk.googlevideo.com.",
"rr4---sn-5hne6nsr.googlevideo.com.",
"rr4---sn-5hne6nsy.googlevideo.com.",
- "rr4---sn-5hne6nsy.gvt1.com.",
"rr4---sn-5hne6nsz.googlevideo.com.",
"rr4---sn-5hne6nz6.googlevideo.com.",
+ "rr4---sn-5hne6nz6.gvt1.com.",
"rr4---sn-5hne6nzd.googlevideo.com.",
"rr4---sn-5hne6nzk.googlevideo.com.",
"rr4---sn-5hne6nzs.googlevideo.com.",
- "rr4---sn-5hne6nzs.gvt1.com.",
"rr4---sn-5hne6nzy.googlevideo.com.",
- "rr4---sn-5hne6nzy.gvt1.com.",
"rr4---sn-5hnednss.googlevideo.com.",
"rr4---sn-5hnednsz.googlevideo.com.",
- "rr4---sn-5hnednsz.gvt1.com.",
"rr4---sn-5hnekn76.googlevideo.com.",
"rr4---sn-5hnekn7d.googlevideo.com.",
"rr4---sn-5hnekn7l.googlevideo.com.",
@@ -5434,23 +5462,21 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-5hnekn7z.googlevideo.com.",
"rr4---sn-5hneknee.googlevideo.com.",
"rr4---sn-5hneknek.googlevideo.com.",
- "rr4---sn-5hneknek.gvt1.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-5uaeznel.googlevideo.com.",
"rr4---sn-5uaeznes.googlevideo.com.",
"rr4---sn-5uaeznez.googlevideo.com.",
"rr4---sn-5uaeznl6.googlevideo.com.",
"rr4---sn-5uaeznld.googlevideo.com.",
- "rr4---sn-5uaeznrz.googlevideo.com.",
+ "rr4---sn-5uaeznlz.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.",
@@ -5469,50 +5495,46 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-5ualdnsz.googlevideo.com.",
"rr4---sn-5ualdnz7.googlevideo.com.",
"rr4---sn-5ualdnze.googlevideo.com.",
+ "rr4---sn-8pxuuxa-nbo6s.googlevideo.com.",
"rr4---sn-8qj-nbo66.googlevideo.com.",
+ "rr4---sn-8xgp1vo-2iae7.googlevideo.com.",
"rr4---sn-8xgp1vo-ab56.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5e.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-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-9gv7zn7y.googlevideo.com.",
"rr4---sn-a5m7lnl6.googlevideo.com.",
"rr4---sn-a5m7lnld.googlevideo.com.",
- "rr4---sn-a5m7lnld.gvt1.com.",
"rr4---sn-a5mekn6d.googlevideo.com.",
- "rr4---sn-a5mekn6d.gvt1.com.",
"rr4---sn-a5mekn6k.googlevideo.com.",
- "rr4---sn-a5mekn6k.gvt1.com.",
"rr4---sn-a5mekn6l.googlevideo.com.",
+ "rr4---sn-a5mekn6l.gvt1.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-a5meknd6.gvt1.com.",
"rr4---sn-a5meknde.googlevideo.com.",
+ "rr4---sn-a5meknde.gvt1.com.",
"rr4---sn-a5mekndl.googlevideo.com.",
"rr4---sn-a5meknds.googlevideo.com.",
"rr4---sn-a5meknds.gvt1.com.",
"rr4---sn-a5mekndz.googlevideo.com.",
- "rr4---sn-a5mekndz.gvt1.com.",
"rr4---sn-a5meknsd.googlevideo.com.",
"rr4---sn-a5meknsy.googlevideo.com.",
- "rr4---sn-a5meknzk.googlevideo.com.",
- "rr4---sn-a5meknzk.gvt1.com.",
"rr4---sn-a5meknzl.googlevideo.com.",
- "rr4---sn-a5meknzr.googlevideo.com.",
"rr4---sn-a5meknzs.googlevideo.com.",
"rr4---sn-a5mlrnek.googlevideo.com.",
"rr4---sn-a5mlrnl6.googlevideo.com.",
@@ -5520,9 +5542,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-a5mlrnll.gvt1.com.",
"rr4---sn-a5mlrnls.googlevideo.com.",
"rr4---sn-a5mlrnlz.googlevideo.com.",
- "rr4---sn-a5mlrnlz.gvt1.com.",
"rr4---sn-a5msen76.googlevideo.com.",
"rr4---sn-a5msen7l.googlevideo.com.",
+ "rr4---sn-a5msen7l.gvt1.com.",
"rr4---sn-a5msen7s.googlevideo.com.",
"rr4---sn-a5msen7z.googlevideo.com.",
"rr4---sn-a5msenek.googlevideo.com.",
@@ -5537,10 +5559,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-ab5l6ndr.googlevideo.com.",
"rr4---sn-ab5l6ndy.googlevideo.com.",
"rr4---sn-ab5l6nk6.googlevideo.com.",
- "rr4---sn-ab5l6nk6.gvt1.com.",
"rr4---sn-ab5l6nkd.googlevideo.com.",
"rr4---sn-ab5l6nr6.googlevideo.com.",
- "rr4---sn-ab5l6nr6.gvt1.com.",
"rr4---sn-ab5l6nrd.googlevideo.com.",
"rr4---sn-ab5l6nrk.googlevideo.com.",
"rr4---sn-ab5l6nrl.googlevideo.com.",
@@ -5553,19 +5573,14 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-ab5sznly.googlevideo.com.",
"rr4---sn-ab5sznz6.googlevideo.com.",
"rr4---sn-ab5sznzd.googlevideo.com.",
- "rr4---sn-ab5sznzd.gvt1.com.",
"rr4---sn-ab5sznze.googlevideo.com.",
- "rr4---sn-ab5sznze.gvt1.com.",
"rr4---sn-ab5sznzk.googlevideo.com.",
- "rr4---sn-ab5sznzk.gvt1.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-ab5sznzz.googlevideo.com.",
- "rr4---sn-ab5sznzz.gvt1.com.",
"rr4---sn-aigl6n6s.googlevideo.com.",
- "rr4---sn-aigl6n6s.gvt1.com.",
"rr4---sn-aigl6nek.googlevideo.com.",
"rr4---sn-aigl6ner.googlevideo.com.",
"rr4---sn-aigl6ney.googlevideo.com.",
@@ -5574,6 +5589,7 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -5594,15 +5610,13 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-aigzrnsz.googlevideo.com.",
"rr4---sn-aigzrnz7.googlevideo.com.",
"rr4---sn-aigzrnze.googlevideo.com.",
- "rr4---sn-ajab55-55.googlevideo.com.",
- "rr4---sn-ajab55-55.gvt1.com.",
- "rr4---sn-bg5oqxjvh-50nz.googlevideo.com.",
"rr4---sn-cvb7lne7.googlevideo.com.",
"rr4---sn-cvb7lnee.googlevideo.com.",
"rr4---sn-cvb7lnls.googlevideo.com.",
"rr4---sn-cvb7lnlz.googlevideo.com.",
"rr4---sn-cvb7sn7k.googlevideo.com.",
"rr4---sn-cvb7sn7r.googlevideo.com.",
+ "rr4---sn-hjoj-gq0l.googlevideo.com.",
"rr4---sn-hoa7kn76.googlevideo.com.",
"rr4---sn-hoa7kn7z.googlevideo.com.",
"rr4---sn-hoa7rn76.googlevideo.com.",
@@ -5611,28 +5625,27 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-hp57kn6y.googlevideo.com.",
"rr4---sn-hp57kn6y.gvt1.com.",
"rr4---sn-hp57knd6.googlevideo.com.",
- "rr4---sn-hp57knd6.gvt1.com.",
"rr4---sn-hp57kndd.googlevideo.com.",
- "rr4---sn-hp57kndd.gvt1.com.",
- "rr4---sn-hp57kndk.googlevideo.com.",
"rr4---sn-hp57kndr.googlevideo.com.",
+ "rr4---sn-hp57kndr.gvt1.com.",
"rr4---sn-hp57knds.googlevideo.com.",
"rr4---sn-hp57knds.gvt1.com.",
"rr4---sn-hp57kndy.googlevideo.com.",
+ "rr4---sn-hp57kndy.gvt1.com.",
"rr4---sn-hp57kndz.googlevideo.com.",
"rr4---sn-hp57yn7r.googlevideo.com.",
"rr4---sn-hp57yn7y.googlevideo.com.",
"rr4---sn-hp57yne7.googlevideo.com.",
"rr4---sn-hp57ynee.googlevideo.com.",
"rr4---sn-hp57ynl6.googlevideo.com.",
- "rr4---sn-hp57ynl6.gvt1.com.",
"rr4---sn-hp57ynlr.googlevideo.com.",
- "rr4---sn-hp57ynlr.gvt1.com.",
"rr4---sn-hp57ynly.googlevideo.com.",
+ "rr4---sn-hp57ynly.gvt1.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.",
@@ -5643,7 +5656,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-i3b7knzl.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.",
@@ -5652,10 +5664,14 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-i3bssn7e.googlevideo.com.",
"rr4---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
"rr4---sn-jvhj5nu-2iae.googlevideo.com.",
+ "rr4---sn-jvhj5nu-2ial.googlevideo.com.",
+ "rr4---sn-jvhj5nu-2ias.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-qufz.googlevideo.com.",
"rr4---sn-jxopj-n5oe.googlevideo.com.",
"rr4---sn-jxopj-nh4e.googlevideo.com.",
"rr4---sn-jxopj-nh4e.gvt1.com.",
@@ -5669,8 +5685,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-n4v7sns7.googlevideo.com.",
"rr4---sn-n4v7snse.googlevideo.com.",
"rr4---sn-npoe7ndl.googlevideo.com.",
+ "rr4---sn-npoe7ndl.gvt1.com.",
"rr4---sn-npoe7nds.googlevideo.com.",
- "rr4---sn-npoe7ne6.googlevideo.com.",
"rr4---sn-npoe7ne7.googlevideo.com.",
"rr4---sn-npoe7ned.googlevideo.com.",
"rr4---sn-npoe7nek.googlevideo.com.",
@@ -5681,13 +5697,15 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-npoe7nl6.googlevideo.com.",
"rr4---sn-npoe7nlz.googlevideo.com.",
"rr4---sn-npoe7ns6.googlevideo.com.",
+ "rr4---sn-npoe7ns6.gvt1.com.",
"rr4---sn-npoe7ns7.googlevideo.com.",
- "rr4---sn-npoe7ns7.gvt1.com.",
"rr4---sn-npoe7nsd.googlevideo.com.",
"rr4---sn-npoe7nsk.googlevideo.com.",
+ "rr4---sn-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.",
@@ -5695,28 +5713,27 @@ var FakeECSFQDNs = container.NewMapSet(
"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-npoeenly.googlevideo.com.",
"rr4---sn-npoeens7.googlevideo.com.",
+ "rr4---sn-npoeens7.gvt1.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-npoldn7s.gvt1.com.",
"rr4---sn-npoldn7y.googlevideo.com.",
"rr4---sn-npoldn7z.googlevideo.com.",
"rr4---sn-npoldne7.googlevideo.com.",
- "rr4---sn-ntq7yner.googlevideo.com.",
"rr4---sn-nx57ynlk.googlevideo.com.",
+ "rr4---sn-nx57ynlk.gvt1.com.",
"rr4---sn-nx57ynsd.googlevideo.com.",
"rr4---sn-nx57ynsd.gvt1.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-nx57ynss.googlevideo.com.",
"rr4---sn-nx57ynsz.googlevideo.com.",
@@ -5726,7 +5743,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-nx5s7n7y.googlevideo.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.",
@@ -5734,7 +5750,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-o097znsl.googlevideo.com.",
"rr4---sn-o097znsr.googlevideo.com.",
"rr4---sn-o097znss.googlevideo.com.",
- "rr4---sn-o097znss.gvt1.com.",
"rr4---sn-o097znsz.googlevideo.com.",
"rr4---sn-o097znz7.googlevideo.com.",
"rr4---sn-o097znzd.googlevideo.com.",
@@ -5745,13 +5760,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-p5qddn76.googlevideo.com.",
"rr4---sn-p5qddn7d.googlevideo.com.",
"rr4---sn-p5qddn7k.googlevideo.com.",
- "rr4---sn-p5qddn7k.gvt1.com.",
"rr4---sn-p5qddn7r.googlevideo.com.",
- "rr4---sn-p5qddn7r.gvt1.com.",
- "rr4---sn-p5qddn7z.googlevideo.com.",
"rr4---sn-p5qlsn6l.googlevideo.com.",
"rr4---sn-p5qlsn76.googlevideo.com.",
- "rr4---sn-p5qlsn76.gvt1.com.",
"rr4---sn-p5qlsn7d.googlevideo.com.",
"rr4---sn-p5qlsn7l.googlevideo.com.",
"rr4---sn-p5qlsn7s.googlevideo.com.",
@@ -5759,33 +5770,26 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-p5qlsndk.googlevideo.com.",
"rr4---sn-p5qlsndz.googlevideo.com.",
"rr4---sn-p5qlsnrl.googlevideo.com.",
- "rr4---sn-p5qlsnrl.gvt1.com.",
"rr4---sn-p5qlsnrr.googlevideo.com.",
"rr4---sn-p5qlsny6.googlevideo.com.",
"rr4---sn-p5qs7n6d.googlevideo.com.",
"rr4---sn-p5qs7nsk.googlevideo.com.",
- "rr4---sn-p5qs7nsk.gvt1.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-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-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-q4fl6ndl.gvt1.com.",
"rr4---sn-q4fl6nds.googlevideo.com.",
"rr4---sn-q4fl6nds.gvt1.com.",
"rr4---sn-q4fl6ndz.googlevideo.com.",
@@ -5794,66 +5798,54 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-q4fl6ns6.googlevideo.com.",
"rr4---sn-q4fl6ns6.gvt1.com.",
"rr4---sn-q4fl6ns7.googlevideo.com.",
- "rr4---sn-q4fl6ns7.gvt1.com.",
"rr4---sn-q4fl6nsd.googlevideo.com.",
"rr4---sn-q4fl6nsd.gvt1.com.",
"rr4---sn-q4fl6nsk.googlevideo.com.",
"rr4---sn-q4fl6nsl.googlevideo.com.",
- "rr4---sn-q4fl6nsl.gvt1.com.",
"rr4---sn-q4fl6nsr.googlevideo.com.",
- "rr4---sn-q4fl6nsr.gvt1.com.",
"rr4---sn-q4fl6nss.googlevideo.com.",
"rr4---sn-q4fl6nsy.googlevideo.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-q4flrn7k.gvt1.com.",
"rr4---sn-q4flrn7r.googlevideo.com.",
"rr4---sn-q4flrn7y.googlevideo.com.",
"rr4---sn-q4flrn7y.gvt1.com.",
"rr4---sn-q4flrne7.googlevideo.com.",
+ "rr4---sn-q4flrne7.gvt1.com.",
"rr4---sn-q4flrnee.googlevideo.com.",
"rr4---sn-q4flrnee.gvt1.com.",
"rr4---sn-q4flrnek.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-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-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-q4flrnsd.gvt1.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-q4flrnss.gvt1.com.",
"rr4---sn-q4fzen7e.googlevideo.com.",
"rr4---sn-q4fzen7e.gvt1.com.",
"rr4---sn-q4fzen7l.googlevideo.com.",
"rr4---sn-q4fzen7l.gvt1.com.",
"rr4---sn-q4fzen7r.googlevideo.com.",
- "rr4---sn-q4fzen7r.gvt1.com.",
"rr4---sn-q4fzen7s.googlevideo.com.",
- "rr4---sn-q4fzen7s.gvt1.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-qjp5q5-55.googlevideo.com.",
"rr4---sn-qxo7rn7k.googlevideo.com.",
"rr4---sn-qxo7rn7r.googlevideo.com.",
"rr4---sn-qxo7rn7y.googlevideo.com.",
@@ -5866,51 +5858,42 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-vgqskn66.googlevideo.com.",
"rr4---sn-vgqskn66.gvt1.com.",
"rr4---sn-vgqskn67.googlevideo.com.",
+ "rr4---sn-vgqskn67.gvt1.com.",
"rr4---sn-vgqskn6d.googlevideo.com.",
+ "rr4---sn-vgqskn6d.gvt1.com.",
"rr4---sn-vgqskn6s.googlevideo.com.",
"rr4---sn-vgqskn6z.googlevideo.com.",
"rr4---sn-vgqskne6.googlevideo.com.",
- "rr4---sn-vgqskne6.gvt1.com.",
+ "rr4---sn-vgqskned.googlevideo.com.",
"rr4---sn-vgqsknek.googlevideo.com.",
+ "rr4---sn-vgqsknes.googlevideo.com.",
+ "rr4---sn-vgqsknez.googlevideo.com.",
"rr4---sn-vgqsknld.googlevideo.com.",
"rr4---sn-vgqsknlk.googlevideo.com.",
"rr4---sn-vgqsknlk.gvt1.com.",
"rr4---sn-vgqsknll.googlevideo.com.",
- "rr4---sn-vgqsknll.gvt1.com.",
"rr4---sn-vgqsknlr.googlevideo.com.",
- "rr4---sn-vgqsknlr.gvt1.com.",
"rr4---sn-vgqsknls.googlevideo.com.",
- "rr4---sn-vgqsknls.gvt1.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-vgqsknse.gvt1.com.",
"rr4---sn-vgqsknsk.googlevideo.com.",
- "rr4---sn-vgqsknsk.gvt1.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-vgqsknze.gvt1.com.",
"rr4---sn-vgqsknzk.googlevideo.com.",
- "rr4---sn-vgqsknzk.gvt1.com.",
"rr4---sn-vgqsknzl.googlevideo.com.",
- "rr4---sn-vgqsknzl.gvt1.com.",
"rr4---sn-vgqsknzr.googlevideo.com.",
- "rr4---sn-vgqsknzr.gvt1.com.",
"rr4---sn-vgqsknzs.googlevideo.com.",
"rr4---sn-vgqsknzy.googlevideo.com.",
- "rr4---sn-vgqsknzy.gvt1.com.",
"rr4---sn-vgqsknzz.googlevideo.com.",
"rr4---sn-vgqsrn66.googlevideo.com.",
- "rr4---sn-vgqsrn66.gvt1.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.",
@@ -5918,23 +5901,17 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-vgqsrnek.googlevideo.com.",
"rr4---sn-vgqsrnes.googlevideo.com.",
"rr4---sn-vgqsrnez.googlevideo.com.",
- "rr4---sn-vgqsrnez.gvt1.com.",
- "rr4---sn-vgqsrnl6.googlevideo.com.",
- "rr4---sn-vgqsrnl6.gvt1.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-vgqsrnlz.gvt1.com.",
"rr4---sn-vgqsrns6.googlevideo.com.",
- "rr4---sn-vgqsrns6.gvt1.com.",
"rr4---sn-vgqsrnsd.googlevideo.com.",
- "rr4---sn-vgqsrnsd.gvt1.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-vgqsrnzr.googlevideo.com.",
@@ -5942,22 +5919,20 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-vgqsrnzy.googlevideo.com.",
"rr4---sn-vgqsrnzy.gvt1.com.",
"rr4---sn-vgqsrnzz.googlevideo.com.",
- "rr4---sn-vgqsrnzz.gvt1.com.",
- "rr4.sn-hp57knds.googlevideo.com.",
- "rr4.sn-ntq7yner.googlevideo.com.",
- "rr4.sn-nx57ynsk.googlevideo.com.",
- "rr4.sn-p5qs7nsk.googlevideo.com.",
- "rr4.sn-q4fl6nd7.googlevideo.com.",
- "rr4.sn-q4fl6nss.googlevideo.com.",
- "rr4.sn-q4fzen7e.googlevideo.com.",
- "rr4.sn-q4fzen7l.googlevideo.com.",
- "rr4.sn-q4fzen7r.googlevideo.com.",
- "rr4.sn-vgqsrnzz.googlevideo.com.",
+ "rr4.sn-5hne6n6l.googlevideo.com.",
+ "rr4.sn-5hne6nsd.googlevideo.com.",
+ "rr4.sn-q4fl6n66.googlevideo.com.",
+ "rr4.sn-q4fl6ndl.googlevideo.com.",
+ "rr4.sn-q4fl6nsk.googlevideo.com.",
+ "rr4.sn-q4flrner.googlevideo.com.",
+ "rr4.sn-q4flrnes.googlevideo.com.",
+ "rr4.sn-q4flrnld.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-2imeyn7k.googlevideo.com.",
- "rr5---sn-2oaig5-55.googlevideo.com.",
"rr5---sn-30a7rne6.googlevideo.com.",
"rr5---sn-30a7rned.googlevideo.com.",
"rr5---sn-30a7rnek.googlevideo.com.",
@@ -5971,9 +5946,9 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -5985,19 +5960,23 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-4g5ednde.googlevideo.com.",
"rr5---sn-4g5edndk.googlevideo.com.",
"rr5---sn-4g5edndl.googlevideo.com.",
+ "rr5---sn-4g5edndl.gvt1.com.",
"rr5---sn-4g5edndr.googlevideo.com.",
"rr5---sn-4g5ednds.googlevideo.com.",
"rr5---sn-4g5edndy.googlevideo.com.",
+ "rr5---sn-4g5edndy.gvt1.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.",
@@ -6010,52 +5989,49 @@ var FakeECSFQDNs = container.NewMapSet(
"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-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
+ "rr5---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
"rr5---sn-5hne6n6e.googlevideo.com.",
+ "rr5---sn-5hne6n6e.gvt1.com.",
"rr5---sn-5hne6n6l.googlevideo.com.",
- "rr5---sn-5hne6n6l.gvt1.com.",
"rr5---sn-5hne6ns6.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-5hne6nz6.gvt1.com.",
"rr5---sn-5hne6nzd.googlevideo.com.",
"rr5---sn-5hne6nzk.googlevideo.com.",
"rr5---sn-5hne6nzs.googlevideo.com.",
"rr5---sn-5hne6nzy.googlevideo.com.",
- "rr5---sn-5hne6nzy.gvt1.com.",
"rr5---sn-5hnednss.googlevideo.com.",
"rr5---sn-5hnednsz.googlevideo.com.",
- "rr5---sn-5hnednsz.gvt1.com.",
"rr5---sn-5hnekn76.googlevideo.com.",
"rr5---sn-5hnekn7d.googlevideo.com.",
"rr5---sn-5hnekn7l.googlevideo.com.",
- "rr5---sn-5hnekn7l.gvt1.com.",
"rr5---sn-5hnekn7s.googlevideo.com.",
"rr5---sn-5hnekn7z.googlevideo.com.",
"rr5---sn-5hneknee.googlevideo.com.",
- "rr5---sn-5hneknee.gvt1.com.",
"rr5---sn-5hneknek.googlevideo.com.",
"rr5---sn-5hneknek.gvt1.com.",
"rr5---sn-5hneknes.googlevideo.com.",
"rr5---sn-5hneknes.gvt1.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-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-5uaeznyz.googlevideo.com.",
"rr5---sn-5uaeznze.googlevideo.com.",
"rr5---sn-5ualdnle.googlevideo.com.",
@@ -6074,7 +6050,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-5ualdnsz.googlevideo.com.",
"rr5---sn-5ualdnz7.googlevideo.com.",
"rr5---sn-5ualdnze.googlevideo.com.",
+ "rr5---sn-8pxuuxa-nbo6l.googlevideo.com.",
"rr5---sn-8qj-nbo66.googlevideo.com.",
+ "rr5---sn-8xgp1vo-2iae7.googlevideo.com.",
"rr5---sn-8xgp1vo-a5me.googlevideo.com.",
"rr5---sn-8xgp1vo-ab56.googlevideo.com.",
"rr5---sn-8xgp1vo-ab5d.googlevideo.com.",
@@ -6086,7 +6064,6 @@ var FakeECSFQDNs = container.NewMapSet(
"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-9gv76n7z.googlevideo.com.",
"rr5---sn-9gv7ene6.googlevideo.com.",
@@ -6099,67 +6076,54 @@ var FakeECSFQDNs = container.NewMapSet(
"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-a5mekn6s.gvt1.com.",
"rr5---sn-a5mekn6z.googlevideo.com.",
- "rr5---sn-a5mekn6z.gvt1.com.",
"rr5---sn-a5meknd6.googlevideo.com.",
- "rr5---sn-a5meknd6.gvt1.com.",
"rr5---sn-a5meknde.googlevideo.com.",
- "rr5---sn-a5meknde.gvt1.com.",
"rr5---sn-a5mekndl.googlevideo.com.",
+ "rr5---sn-a5mekndl.gvt1.com.",
"rr5---sn-a5meknds.googlevideo.com.",
"rr5---sn-a5mekndz.googlevideo.com.",
"rr5---sn-a5meknsd.googlevideo.com.",
"rr5---sn-a5meknsy.googlevideo.com.",
"rr5---sn-a5meknsy.gvt1.com.",
"rr5---sn-a5meknzk.googlevideo.com.",
- "rr5---sn-a5meknzk.gvt1.com.",
"rr5---sn-a5meknzr.googlevideo.com.",
- "rr5---sn-a5meknzr.gvt1.com.",
"rr5---sn-a5meknzs.googlevideo.com.",
+ "rr5---sn-a5meknzs.gvt1.com.",
"rr5---sn-a5mlrnek.googlevideo.com.",
+ "rr5---sn-a5mlrnek.gvt1.com.",
"rr5---sn-a5mlrnl6.googlevideo.com.",
+ "rr5---sn-a5mlrnl6.gvt1.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-a5msen76.gvt1.com.",
"rr5---sn-a5msen7l.googlevideo.com.",
"rr5---sn-a5msen7s.googlevideo.com.",
"rr5---sn-a5msen7z.googlevideo.com.",
"rr5---sn-a5msenek.googlevideo.com.",
- "rr5---sn-a5msenek.gvt1.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-a5msenl7.gvt1.com.",
"rr5---sn-a5msenle.googlevideo.com.",
- "rr5---sn-a5msenle.gvt1.com.",
"rr5---sn-a5msenll.googlevideo.com.",
"rr5---sn-a5msenll.gvt1.com.",
"rr5---sn-ab5l6ndr.googlevideo.com.",
"rr5---sn-ab5l6ndy.googlevideo.com.",
- "rr5---sn-ab5l6ndy.gvt1.com.",
"rr5---sn-ab5l6nk6.googlevideo.com.",
- "rr5---sn-ab5l6nk6.gvt1.com.",
"rr5---sn-ab5l6nkd.googlevideo.com.",
- "rr5---sn-ab5l6nkd.gvt1.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-ab5l6nrk.gvt1.com.",
"rr5---sn-ab5l6nrl.googlevideo.com.",
- "rr5---sn-ab5l6nrl.gvt1.com.",
"rr5---sn-ab5l6nrr.googlevideo.com.",
"rr5---sn-ab5l6nrs.googlevideo.com.",
"rr5---sn-ab5l6nrs.gvt1.com.",
@@ -6168,29 +6132,25 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-ab5sznld.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-ab5sznze.gvt1.com.",
"rr5---sn-ab5sznzk.googlevideo.com.",
"rr5---sn-ab5sznzk.gvt1.com.",
"rr5---sn-ab5sznzl.googlevideo.com.",
- "rr5---sn-ab5sznzl.gvt1.com.",
"rr5---sn-ab5sznzr.googlevideo.com.",
+ "rr5---sn-ab5sznzr.gvt1.com.",
"rr5---sn-ab5sznzs.googlevideo.com.",
"rr5---sn-ab5sznzy.googlevideo.com.",
"rr5---sn-ab5sznzy.gvt1.com.",
"rr5---sn-ab5sznzz.googlevideo.com.",
- "rr5---sn-ab5sznzz.gvt1.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-aigl6ner.gvt1.com.",
"rr5---sn-aigl6nl7.googlevideo.com.",
- "rr5---sn-aigl6ns6.googlevideo.com.",
"rr5---sn-aigl6nsd.googlevideo.com.",
- "rr5---sn-aigl6nsd.gvt1.com.",
"rr5---sn-aigl6nsk.googlevideo.com.",
"rr5---sn-aigl6nsr.googlevideo.com.",
"rr5---sn-aigl6nz7.googlevideo.com.",
@@ -6216,7 +6176,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-aigzrnze.googlevideo.com.",
"rr5---sn-aj5ua5-5c.googlevideo.com.",
"rr5---sn-ajab55-55.googlevideo.com.",
- "rr5---sn-bg5oqxjvh-50nz.googlevideo.com.",
"rr5---sn-cvb7lne7.googlevideo.com.",
"rr5---sn-cvb7lnee.googlevideo.com.",
"rr5---sn-cvb7lnls.googlevideo.com.",
@@ -6228,37 +6187,31 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-hoa7rn76.googlevideo.com.",
"rr5---sn-hoa7rn7z.googlevideo.com.",
"rr5---sn-hp57kn6r.googlevideo.com.",
- "rr5---sn-hp57kn6r.gvt1.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-hp57kndy.gvt1.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-hp57ynee.googlevideo.com.",
"rr5---sn-hp57ynl6.googlevideo.com.",
+ "rr5---sn-hp57ynl6.gvt1.com.",
"rr5---sn-hp57ynlr.googlevideo.com.",
- "rr5---sn-hp57ynly.googlevideo.com.",
- "rr5---sn-hp57ynly.gvt1.com.",
- "rr5---sn-hp57yns7.googlevideo.com.",
"rr5---sn-hp57ynse.googlevideo.com.",
+ "rr5---sn-hp57ynse.gvt1.com.",
"rr5---sn-hp57ynsl.googlevideo.com.",
- "rr5---sn-hp57ynsl.gvt1.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.",
@@ -6272,9 +6225,11 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-i3belnlz.googlevideo.com.",
"rr5---sn-i3bssn7e.googlevideo.com.",
"rr5---sn-jn2pgx4pcxg-w5os.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-qufs.googlevideo.com.",
"rr5---sn-jxopj-n5oe.googlevideo.com.",
"rr5---sn-jxopj-nh4e.googlevideo.com.",
"rr5---sn-jxopj-nh4e.gvt1.com.",
@@ -6286,7 +6241,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-n4v7snls.googlevideo.com.",
"rr5---sn-n4v7snly.googlevideo.com.",
"rr5---sn-n4v7sns7.googlevideo.com.",
- "rr5---sn-n4v7sns7.gvt1.com.",
"rr5---sn-n4v7snse.googlevideo.com.",
"rr5---sn-npoe7ndl.googlevideo.com.",
"rr5---sn-npoe7nds.googlevideo.com.",
@@ -6294,20 +6248,21 @@ var FakeECSFQDNs = container.NewMapSet(
"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-npoe7ns7.gvt1.com.",
"rr5---sn-npoe7nsd.googlevideo.com.",
- "rr5---sn-npoe7nsd.gvt1.com.",
"rr5---sn-npoe7nsk.googlevideo.com.",
+ "rr5---sn-npoe7nsl.googlevideo.com.",
"rr5---sn-npoe7nsr.googlevideo.com.",
"rr5---sn-npoe7nss.googlevideo.com.",
- "rr5---sn-npoe7nss.gvt1.com.",
"rr5---sn-npoe7nsy.googlevideo.com.",
+ "rr5---sn-npoe7nsy.gvt1.com.",
"rr5---sn-npoe7nz7.googlevideo.com.",
"rr5---sn-npoeene6.googlevideo.com.",
"rr5---sn-npoeened.googlevideo.com.",
@@ -6316,50 +6271,46 @@ var FakeECSFQDNs = container.NewMapSet(
"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-npoldn76.gvt1.com.",
"rr5---sn-npoldn7d.googlevideo.com.",
"rr5---sn-npoldn7e.googlevideo.com.",
"rr5---sn-npoldn7l.googlevideo.com.",
+ "rr5---sn-npoldn7l.gvt1.com.",
"rr5---sn-npoldn7s.googlevideo.com.",
- "rr5---sn-npoldn7s.gvt1.com.",
"rr5---sn-npoldn7y.googlevideo.com.",
"rr5---sn-npoldn7z.googlevideo.com.",
"rr5---sn-npoldne7.googlevideo.com.",
- "rr5---sn-ntqe6nel.googlevideo.com.",
+ "rr5---sn-ntq7yns7.googlevideo.com.",
+ "rr5---sn-ntqe6n76.googlevideo.com.",
+ "rr5---sn-ntqe6n7r.googlevideo.com.",
+ "rr5---sn-ntqe6nee.googlevideo.com.",
"rr5---sn-nx57ynlk.googlevideo.com.",
- "rr5---sn-nx57ynlk.gvt1.com.",
"rr5---sn-nx57ynsd.googlevideo.com.",
- "rr5---sn-nx57ynsd.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-nx57ynss.googlevideo.com.",
- "rr5---sn-nx57ynss.gvt1.com.",
"rr5---sn-nx57ynsz.googlevideo.com.",
"rr5---sn-nx5s7n76.googlevideo.com.",
- "rr5---sn-nx5s7n76.gvt1.com.",
"rr5---sn-nx5s7n7d.googlevideo.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-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-o097znsr.gvt1.com.",
"rr5---sn-o097znss.googlevideo.com.",
"rr5---sn-o097znsz.googlevideo.com.",
"rr5---sn-o097znz7.googlevideo.com.",
@@ -6376,37 +6327,32 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-p5qlsn6l.googlevideo.com.",
"rr5---sn-p5qlsn76.googlevideo.com.",
"rr5---sn-p5qlsn7d.googlevideo.com.",
- "rr5---sn-p5qlsn7d.gvt1.com.",
"rr5---sn-p5qlsn7l.googlevideo.com.",
"rr5---sn-p5qlsn7s.googlevideo.com.",
"rr5---sn-p5qlsnd6.googlevideo.com.",
"rr5---sn-p5qlsndk.googlevideo.com.",
"rr5---sn-p5qlsndr.googlevideo.com.",
- "rr5---sn-p5qlsndr.gvt1.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-p5qs7n6d.gvt1.com.",
"rr5---sn-p5qs7nsk.googlevideo.com.",
- "rr5---sn-p5qs7nsk.gvt1.com.",
"rr5---sn-p5qs7nsr.googlevideo.com.",
"rr5---sn-p5qs7nzk.googlevideo.com.",
"rr5---sn-p5qs7nzr.googlevideo.com.",
"rr5---sn-p5qs7nzy.googlevideo.com.",
"rr5---sn-q4fl6n66.googlevideo.com.",
"rr5---sn-q4fl6n6d.googlevideo.com.",
+ "rr5---sn-q4fl6n6d.gvt1.com.",
"rr5---sn-q4fl6n6r.googlevideo.com.",
- "rr5---sn-q4fl6n6r.gvt1.com.",
"rr5---sn-q4fl6n6s.googlevideo.com.",
- "rr5---sn-q4fl6n6s.gvt1.com.",
"rr5---sn-q4fl6n6y.googlevideo.com.",
- "rr5---sn-q4fl6n6y.gvt1.com.",
"rr5---sn-q4fl6n6z.googlevideo.com.",
+ "rr5---sn-q4fl6n6z.gvt1.com.",
"rr5---sn-q4fl6nd7.googlevideo.com.",
+ "rr5---sn-q4fl6nd7.gvt1.com.",
"rr5---sn-q4fl6nde.googlevideo.com.",
- "rr5---sn-q4fl6nde.gvt1.com.",
"rr5---sn-q4fl6ndl.googlevideo.com.",
"rr5---sn-q4fl6ndl.gvt1.com.",
"rr5---sn-q4fl6nds.googlevideo.com.",
@@ -6414,52 +6360,39 @@ var FakeECSFQDNs = container.NewMapSet(
"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-q4fl6nsd.googlevideo.com.",
"rr5---sn-q4fl6nsd.gvt1.com.",
"rr5---sn-q4fl6nsk.googlevideo.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-q4fl6nss.gvt1.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-q4fl6nz7.gvt1.com.",
"rr5---sn-q4fl6nzy.googlevideo.com.",
- "rr5---sn-q4fl6nzy.gvt1.com.",
"rr5---sn-q4flrn7k.googlevideo.com.",
"rr5---sn-q4flrn7k.gvt1.com.",
"rr5---sn-q4flrn7r.googlevideo.com.",
- "rr5---sn-q4flrn7r.gvt1.com.",
"rr5---sn-q4flrn7y.googlevideo.com.",
"rr5---sn-q4flrne6.googlevideo.com.",
"rr5---sn-q4flrne6.gvt1.com.",
"rr5---sn-q4flrne7.googlevideo.com.",
"rr5---sn-q4flrnee.googlevideo.com.",
- "rr5---sn-q4flrnee.gvt1.com.",
"rr5---sn-q4flrnek.googlevideo.com.",
- "rr5---sn-q4flrnek.gvt1.com.",
- "rr5---sn-q4flrnel.googlevideo.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-q4flrnl7.googlevideo.com.",
+ "rr5---sn-q4flrnl6.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-q4flrnsd.gvt1.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.",
@@ -6472,10 +6405,10 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-q4fzen7s.googlevideo.com.",
"rr5---sn-q4fzen7s.gvt1.com.",
"rr5---sn-q4fzen7y.googlevideo.com.",
+ "rr5---sn-q4fzen7y.gvt1.com.",
"rr5---sn-q4fzene7.googlevideo.com.",
"rr5---sn-q4fzene7.gvt1.com.",
"rr5---sn-q4fzenee.googlevideo.com.",
- "rr5---sn-q4fzenee.gvt1.com.",
"rr5---sn-qjp5q5-55.googlevideo.com.",
"rr5---sn-qxo7rn7k.googlevideo.com.",
"rr5---sn-qxo7rn7r.googlevideo.com.",
@@ -6485,100 +6418,83 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-qxoednee.googlevideo.com.",
"rr5---sn-u1hp55-5c.googlevideo.com.",
"rr5---sn-vgqskn66.googlevideo.com.",
- "rr5---sn-vgqskn66.gvt1.com.",
"rr5---sn-vgqskn67.googlevideo.com.",
"rr5---sn-vgqskn6d.googlevideo.com.",
- "rr5---sn-vgqskn6d.gvt1.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-vgqsknek.gvt1.com.",
"rr5---sn-vgqsknes.googlevideo.com.",
"rr5---sn-vgqsknez.googlevideo.com.",
- "rr5---sn-vgqsknez.gvt1.com.",
"rr5---sn-vgqsknld.googlevideo.com.",
"rr5---sn-vgqsknlk.googlevideo.com.",
"rr5---sn-vgqsknlk.gvt1.com.",
"rr5---sn-vgqsknll.googlevideo.com.",
- "rr5---sn-vgqsknll.gvt1.com.",
"rr5---sn-vgqsknlr.googlevideo.com.",
- "rr5---sn-vgqsknlr.gvt1.com.",
"rr5---sn-vgqsknls.googlevideo.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-vgqsknz6.gvt1.com.",
"rr5---sn-vgqsknz7.googlevideo.com.",
- "rr5---sn-vgqsknz7.gvt1.com.",
"rr5---sn-vgqsknzd.googlevideo.com.",
"rr5---sn-vgqsknze.googlevideo.com.",
"rr5---sn-vgqsknzk.googlevideo.com.",
"rr5---sn-vgqsknzl.googlevideo.com.",
- "rr5---sn-vgqsknzl.gvt1.com.",
"rr5---sn-vgqsknzr.googlevideo.com.",
+ "rr5---sn-vgqsknzr.gvt1.com.",
"rr5---sn-vgqsknzs.googlevideo.com.",
- "rr5---sn-vgqsknzs.gvt1.com.",
"rr5---sn-vgqsknzy.googlevideo.com.",
"rr5---sn-vgqsknzz.googlevideo.com.",
+ "rr5---sn-vgqsknzz.gvt1.com.",
"rr5---sn-vgqsrn66.googlevideo.com.",
- "rr5---sn-vgqsrn66.gvt1.com.",
"rr5---sn-vgqsrn67.googlevideo.com.",
"rr5---sn-vgqsrn6e.googlevideo.com.",
+ "rr5---sn-vgqsrn6e.gvt1.com.",
"rr5---sn-vgqsrn6l.googlevideo.com.",
- "rr5---sn-vgqsrn6l.gvt1.com.",
"rr5---sn-vgqsrn6z.googlevideo.com.",
- "rr5---sn-vgqsrn6z.gvt1.com.",
"rr5---sn-vgqsrne6.googlevideo.com.",
"rr5---sn-vgqsrned.googlevideo.com.",
"rr5---sn-vgqsrnek.googlevideo.com.",
"rr5---sn-vgqsrnes.googlevideo.com.",
"rr5---sn-vgqsrnes.gvt1.com.",
"rr5---sn-vgqsrnez.googlevideo.com.",
- "rr5---sn-vgqsrnez.gvt1.com.",
"rr5---sn-vgqsrnl6.googlevideo.com.",
"rr5---sn-vgqsrnl6.gvt1.com.",
"rr5---sn-vgqsrnld.googlevideo.com.",
- "rr5---sn-vgqsrnld.gvt1.com.",
"rr5---sn-vgqsrnlk.googlevideo.com.",
- "rr5---sn-vgqsrnlk.gvt1.com.",
"rr5---sn-vgqsrnll.googlevideo.com.",
+ "rr5---sn-vgqsrnls.googlevideo.com.",
"rr5---sn-vgqsrnlz.googlevideo.com.",
- "rr5---sn-vgqsrnlz.gvt1.com.",
"rr5---sn-vgqsrns6.googlevideo.com.",
"rr5---sn-vgqsrnsd.googlevideo.com.",
- "rr5---sn-vgqsrnsd.gvt1.com.",
"rr5---sn-vgqsrnsr.googlevideo.com.",
- "rr5---sn-vgqsrnsr.gvt1.com.",
"rr5---sn-vgqsrnsy.googlevideo.com.",
"rr5---sn-vgqsrnsy.gvt1.com.",
"rr5---sn-vgqsrnz6.googlevideo.com.",
"rr5---sn-vgqsrnz6.gvt1.com.",
"rr5---sn-vgqsrnz7.googlevideo.com.",
- "rr5---sn-vgqsrnz7.gvt1.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-vgqsrnzy.gvt1.com.",
"rr5---sn-vgqsrnzz.googlevideo.com.",
- "rr5---sn-vgqsrnzz.gvt1.com.",
- "rr5.sn-a5mekn6k.googlevideo.com.",
+ "rr5.sn-5hneknes.googlevideo.com.",
"rr5.sn-hp57knds.googlevideo.com.",
- "rr5.sn-ntqe6nel.googlevideo.com.",
- "rr5.sn-nx57ynsk.googlevideo.com.",
- "rr5.sn-p5qs7nsk.googlevideo.com.",
- "rr5.sn-q4fl6nss.googlevideo.com.",
- "rr5.sn-q4flrn7y.googlevideo.com.",
- "rr5.sn-q4fzen7l.googlevideo.com.",
- "rr5.sn-vgqsrnzz.googlevideo.com.",
- "rr6---sn-5pgnugx5h-hn2z.googlevideo.com.",
+ "rr5.sn-ntq7yns7.googlevideo.com.",
+ "rr5.sn-ntqe6n7r.googlevideo.com.",
+ "rr5.sn-ntqe6nee.googlevideo.com.",
+ "rr5.sn-q4fl6ndl.googlevideo.com.",
+ "rr5.sn-q4flrne6.googlevideo.com.",
+ "rr5.sn-q4flrne7.googlevideo.com.",
+ "rr5.sn-q4flrnld.googlevideo.com.",
+ "rr6---sn-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
+ "rr6---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
+ "rr6---sn-8pxuuxa-nbo6l.googlevideo.com.",
"rr6---sn-8qj-nbo66.googlevideo.com.",
"rr6---sn-8xgp1vo-a5me.googlevideo.com.",
"rr6---sn-8xgp1vo-ab56.googlevideo.com.",
@@ -6592,17 +6508,23 @@ var FakeECSFQDNs = container.NewMapSet(
"rr6---sn-8xgp1vo-xfge.googlevideo.com.",
"rr6---sn-8xgp1vo-xfgl.googlevideo.com.",
"rr6---sn-8xgp1vo-xfgs.googlevideo.com.",
- "rr6---sn-bg5oqxjvh-50nz.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-qufz.googlevideo.com.",
"rr6---sn-jxopj-n5oe.googlevideo.com.",
"rr6---sn-jxopj-nh4e.googlevideo.com.",
"rr6---sn-jxopj-nh4e.gvt1.com.",
+ "rr7---sn-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
+ "rr7---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
+ "rr7---sn-8pxuuxa-nbo6l.googlevideo.com.",
"rr7---sn-8qj-nbo66.googlevideo.com.",
"rr7---sn-8xgp1vo-a5me.googlevideo.com.",
"rr7---sn-8xgp1vo-ab56.googlevideo.com.",
@@ -6610,14 +6532,18 @@ var FakeECSFQDNs = container.NewMapSet(
"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-jvhj5nu-nh4e.googlevideo.com.",
"rr7---sn-jvhj5nu-nh4l.googlevideo.com.",
"rr7---sn-jvhj5nu-nh4s.googlevideo.com.",
"rr7---sn-jvhj5nu-nh4z.googlevideo.com.",
+ "rr7---sn-jvhj5nu-qufs.googlevideo.com.",
+ "rr7---sn-jvhj5nu-qufz.googlevideo.com.",
"rr7---sn-jxopj-n5oe.googlevideo.com.",
+ "rr8---sn-5abxgpxuxaxjvh-9n4e.googlevideo.com.",
+ "rr8---sn-5abxgpxuxaxjvh-9n4l.googlevideo.com.",
+ "rr8---sn-8pxuuxa-nbo6l.googlevideo.com.",
"rr8---sn-8xgp1vo-ab56.googlevideo.com.",
"rr8---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr8---sn-8xgp1vo-ab5e.googlevideo.com.",
@@ -6632,60 +6558,61 @@ var FakeECSFQDNs = container.NewMapSet(
"rs2.qq.com.",
"rsmjournals.com.",
"rsx.afterpay.com.",
+ "rt.applvn.com.",
"rt.teramind.co.",
+ "rta.www.wrike.com.",
"rtb-apac.rtbserve.io.",
"rtb-eu.rtbserve.io.",
+ "rtb-useast-v4.qortex.ai.",
"rtb-useast.creativedot.net.",
- "rtb-useast.openrtb.in.",
"rtb-useast.rtbserve.io.",
"rtb-uswest-v4.qortex.ai.",
- "rtb-uswest.rtbserve.io.",
"rtb2-eu.xaprio.net.",
"rtb2-useast.xaprio.net.",
- "rtb2-uswest.xaprio.net.",
- "rtbasia.com.",
"rtbsuperhub.com.",
"rtbwave.com.",
"rttf.citrix.com.",
"ru.global.market.xiaomi.com.",
- "ru.hlth.io.mi.com.",
- "ru3419.ci.managedwhitelisting.com.",
"rubyfish.cn.",
"rudder.immivision.net.",
"ruijienetworks.com.",
"rule34video.com.",
- "rum-collectors.us2.sumologic.com.",
+ "rum.perfops.cdb.cdn.orange.com.",
+ "rum.perfops.mdb.cdn.orange.com.",
"rumble.com.",
"rumt-sg.com.",
+ "rutgersconnect-my.sharepoint.com.",
"rutubelist.ru.",
"s-cdn.anthropic.com.",
"s-cs.send.microad.jp.",
- "s-pinimg-com-edgekey-net.pinimg.com.",
- "s-rtb-pb.send.microad.jp.",
+ "s-light.tiket.photos.",
"s.deepl.com.",
"s.q.easebar.com.",
"s.seedtag.com.",
- "s1-word-view-15.cdn.office.net.",
"s2-a.time.mci1.us.rozint.net.",
"s2-b.time.mci1.us.rozint.net.",
- "s3.global-e.com.",
+ "s3-advertising.zalopay.vn.",
+ "s9.gifyu.com.",
"sa1.chat.si.riotgames.com.",
"sa2.chat.si.riotgames.com.",
"sa3.chat.si.riotgames.com.",
"saas.sensorsdata.com.",
"sach.gopsahome.info.",
+ "sadmin.brightcove.com.",
"saintasaph.remotepc.com.",
+ "salesbridge-my.sharepoint.com.",
"saltlakecity.remotepc.com.",
- "sams-checkin.mobile.walmart.com.",
"samsclub.quantummetric.com.",
"sanantonio.remotepc.com.",
+ "sandbox.wdesk.com.",
"sandboxclient.retinavue.net.",
"sandboxregister.retinavue.net.",
"sandiego.remotepc.com.",
"sandiegodc.remotepc.com.",
+ "sanguan.online.",
"sanjose.remotepc.com.",
- "santandernet.sharepoint.com.",
"santiago.remotepc.com.",
+ "sanxia.studyquicks.com.",
"saopaulo.remotepc.com.",
"saopaulo1.remotepc.com.",
"sat02pap001.storage.live.com.",
@@ -6695,7 +6622,6 @@ var FakeECSFQDNs = container.NewMapSet(
"sc.zoom.us.",
"scheduler.eagle.haplat.net.",
"schneidercorp.com.",
- "science.blitz.gg.",
"sciener.cn.",
"scm.haplat.net.",
"scontent-ams2-1.cdninstagram.com.",
@@ -6703,12 +6629,13 @@ var FakeECSFQDNs = container.NewMapSet(
"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-atl3-3.cdninstagram.com.",
+ "scontent-atl3-3.xx.fbcdn.net.",
"scontent-bkk1-1.xx.fbcdn.net.",
"scontent-bkk1-2.xx.fbcdn.net.",
"scontent-bog2-1.cdninstagram.com.",
@@ -6739,7 +6666,6 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-dfw5-2.xx.fbcdn.net.",
"scontent-dus1-1.cdninstagram.com.",
"scontent-dus1-1.xx.fbcdn.net.",
- "scontent-for1-1.cdninstagram.com.",
"scontent-fra3-1.cdninstagram.com.",
"scontent-fra3-1.xx.fbcdn.net.",
"scontent-fra3-2.cdninstagram.com.",
@@ -6748,6 +6674,7 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-fra5-1.xx.fbcdn.net.",
"scontent-fra5-2.cdninstagram.com.",
"scontent-fra5-2.xx.fbcdn.net.",
+ "scontent-gmp1-1.cdninstagram.com.",
"scontent-gru1-1.cdninstagram.com.",
"scontent-gru1-1.xx.fbcdn.net.",
"scontent-gru1-2.cdninstagram.com.",
@@ -6759,6 +6686,7 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-ham3-1.cdninstagram.com.",
"scontent-ham3-1.xx.fbcdn.net.",
"scontent-hel3-1.cdninstagram.com.",
+ "scontent-hel3-1.xx.fbcdn.net.",
"scontent-hkg1-1.cdninstagram.com.",
"scontent-hkg1-1.xx.fbcdn.net.",
"scontent-hkg1-2.cdninstagram.com.",
@@ -6789,7 +6717,6 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-lhr8-1.xx.fbcdn.net.",
"scontent-lhr8-2.cdninstagram.com.",
"scontent-lhr8-2.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.",
@@ -6816,6 +6743,8 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-qro1-2.xx.fbcdn.net.",
"scontent-sea1-1.cdninstagram.com.",
"scontent-sea1-1.xx.fbcdn.net.",
+ "scontent-sin11-1.cdninstagram.com.",
+ "scontent-sin11-1.xx.fbcdn.net.",
"scontent-sin6-1.cdninstagram.com.",
"scontent-sin6-1.xx.fbcdn.net.",
"scontent-sin6-2.cdninstagram.com.",
@@ -6839,26 +6768,22 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
"scouccl1.haplat.net.",
"scouccl2.haplat.net.",
"scraper2.onlineradiobox.com.",
- "sdds3.sophosupd.com.",
"sdgframeonyc01.frameo.net.",
"sdgframeonyc02.frameo.net.",
- "sdk-api-us.maticooads.com.",
- "sdk-assets.teads.tv.",
"sdk.beizi.biz.",
- "sdk.iad-04.braze.com.cdn.cloudflare.net.",
- "sdk.iad-08.braze.com.cdn.cloudflare.net.",
+ "sdk.iad-01.braze.com.cdn.cloudflare.net.",
+ "sdk.iad-07.braze.com.cdn.cloudflare.net.",
"sdk.qcloud.com.",
"sdkgate.pushv3.easebar.com.",
"sdktmp.hubcloud.com.cn.",
"sdn.lxdns.com.",
"sdn.qtlcname.com.",
+ "seabroadnet.com.",
"seagate.com.",
"seagullscientific.com.",
"sealsubscriptions.com.",
@@ -6868,37 +6793,40 @@ var FakeECSFQDNs = container.NewMapSet(
"searchserverapi.com.",
"seattle.remotepc.com.",
"secaucus.remotepc.com.",
+ "secure-oldnavy.gap.com.",
+ "secure-signals.permutive.app.",
"secure.accurint.com.",
"secure.syndetics.com.",
- "secure2.cdn.fastclick.net.edgekey.net.",
"securelink.med.usc.edu.",
"securetheorem.com.",
"securityapi.d3-pr-tm.com.",
- "securybrowsenow.com.",
"seedtag.com.",
- "seexh.com.",
"send.microad.jp.",
+ "sendspace.com.",
"sensorsdata.cn.",
"sensorsdata.com.",
+ "sensorsgateway.com.",
"sentry-pro.bssrvc66.com.",
"sentry-webapp.quillbot.com.",
"sentry.appodeal.com.",
- "sentry.archive.org.",
- "sentry.blum.codes.",
"sentry.quillbot.com.",
"sentry.radyushin.com.",
+ "sentry.voicemod.net.",
"sentry.wrike.com.",
"seoul.remotepc.com.",
"served-by.pixfuture.com.",
- "servedby.flashtalking.com.",
- "service.weather.microsoft.com.",
+ "service-light.gamesafe.qq.com.",
+ "service.toonblast.net.",
"service2.ultipro.com.",
"servicebus1021.myconnectsecure.com.",
"servicebus1022.myconnectsecure.com.",
"servicebus1023.myconnectsecure.com.",
"servicebus1024.myconnectsecure.com.",
- "services.intralinks.com.",
+ "servicebus1041.myconnectsecure.com.",
+ "services.gradle.org.",
"services.lego.com.",
+ "services.listrak.com.cdn.cloudflare.net.",
+ "services2.risevision.com.",
"servicetitan.com.",
"servx.opamarketplace.com.",
"servx.playstream.media.",
@@ -6915,17 +6843,20 @@ var FakeECSFQDNs = container.NewMapSet(
"sgfp.tongdun.net.",
"sgmbocast.com.",
"sgpcas.ezvizlife.com.",
+ "share.fcgame.net.",
"sharpschool.com.",
"shc6.y.qq.com.",
+ "shop.roadster.com.",
"shopcircle.co.",
"shopify-gtm-suite.getelevar.com.",
"shortpixel.ai.",
+ "show-sb.com.",
"shp.ee.",
"shrinetheme.com.",
"shuzilm.cn.",
- "si2.schwabinstitutional.com.",
"sigma-performance-h73na.proxima.nie.easebar.com.",
"signin.ultipro.com.",
+ "signup.live.com.",
"sina.com.",
"sinaimg.cn.",
"sip-backup.phonepower.com.",
@@ -6944,8 +6875,6 @@ var FakeECSFQDNs = container.NewMapSet(
"sip123-1121.ringcentral.com.",
"sip123-1131.ringcentral.com.",
"sip123-1141.ringcentral.com.",
- "sip123-1211.ringcentral.com.",
- "sip131-1111.ringcentral.com.",
"sip131-1121.ringcentral.com.",
"sip131-1131.ringcentral.com.",
"sip131-1141.ringcentral.com.",
@@ -6953,14 +6882,13 @@ var FakeECSFQDNs = container.NewMapSet(
"sip132-1131.ringcentral.com.",
"sip132-1141.ringcentral.com.",
"sip421-121.ringcentral.biz.",
- "sipis.acrobits.cz.",
"site-config.com.",
"sjc.zoom.us.",
"sjc04pap001.storage.live.com.",
"sjc04pap002.storage.live.com.",
- "skims.com.",
"skyapi.onedrive.live.com.",
"skyapi.policies.live.net.",
+ "skydrivesync.policies.live.net.",
"skyts.net.",
"skyward-gprod.iscorp.com.",
"skyward-lisdprod.iscorp.com.",
@@ -6970,24 +6898,26 @@ var FakeECSFQDNs = container.NewMapSet(
"sm1.selectmedia.asia.",
"smartcloudcon.com.",
"smarthome.ctdevice.ott4china.com.",
- "smarttag.rubiconproject.com.",
"smoot-searchv2-aapse1c.v.aaplimg.com.",
+ "smoot-searchv2-aeun1a.v.aaplimg.com.",
+ "smoot-searchv2-aeun1b.v.aaplimg.com.",
"smoot-searchv2-aeus2a.v.aaplimg.com.",
+ "smoot-searchv2-aeus2b.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.sharepoint.com.",
"sms.ads.heytapmobi.com.",
"snap-storage-cdn.l.google.com.",
"snippet.affilimatejs.com.",
"snokido.com.",
"snz04pap001.storage.live.com.",
- "snz04pap002.storage.live.com.",
"so1506.ci.managedwhitelisting.com.",
"sobot.com.",
"socialchain.app.",
@@ -6997,13 +6927,13 @@ var FakeECSFQDNs = container.NewMapSet(
"sohu.com.",
"sohucs.com.",
"solid.preyproject.com.",
- "solidworks.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-atl3-3.xx.fbcdn.net.",
"sonar-bcn1-1.xx.fbcdn.net.",
"sonar-ber1-1.xx.fbcdn.net.",
"sonar-bkk1-1.xx.fbcdn.net.",
@@ -7023,10 +6953,6 @@ var FakeECSFQDNs = container.NewMapSet(
"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-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.",
@@ -7037,8 +6963,9 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-fco2-1.xx.fbcdn.net.",
"sonar-fml1-1.xx.fbcdn.net.",
"sonar-fml20-1.xx.fbcdn.net.",
- "sonar-fmx1-1.xx.fbcdn.net.",
"sonar-for1-1.xx.fbcdn.net.",
+ "sonar-for2-1.xx.fbcdn.net.",
+ "sonar-for2-2.xx.fbcdn.net.",
"sonar-fra3-1.xx.fbcdn.net.",
"sonar-fra3-2.xx.fbcdn.net.",
"sonar-fra5-1.xx.fbcdn.net.",
@@ -7090,6 +7017,7 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-man2-1.xx.fbcdn.net.",
"sonar-mba1-1.xx.fbcdn.net.",
"sonar-mct1-1.xx.fbcdn.net.",
+ "sonar-mct1-2.xx.fbcdn.net.",
"sonar-mia3-1.xx.fbcdn.net.",
"sonar-mia3-2.xx.fbcdn.net.",
"sonar-mnl1-1.xx.fbcdn.net.",
@@ -7116,6 +7044,7 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-qro1-2.xx.fbcdn.net.",
"sonar-scl2-1.xx.fbcdn.net.",
"sonar-sea1-1.xx.fbcdn.net.",
+ "sonar-sin11-1.xx.fbcdn.net.",
"sonar-sin6-1.xx.fbcdn.net.",
"sonar-sin6-2.xx.fbcdn.net.",
"sonar-sin6-3.xx.fbcdn.net.",
@@ -7134,38 +7063,41 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
+ "soulapp.cn.",
"southafricanorth.api.cognitive.microsoft.com.",
"southcarolina.remotepc.com.",
"southeastasia.api.cognitive.microsoft.com.",
"southindia.api.cognitive.microsoft.com.",
- "sp.itunes.apple.com.edgekey.net.",
"spadsync.com.",
"sparteo.com.",
+ "speedtest.sv5.macarne.com.",
"spiny.ai.",
"spion.savvy.security.",
+ "split-tool.com.",
"sq.bls.mdt.qq.com.",
"src.ebay-us.com.",
"srv.stalker.to.",
+ "srv2.maxhost.io.",
"ssafp.samsclub.com.",
"ssctech.com.",
+ "ssl-avd.innity.net.",
"ssl.geoplugin.net.",
"sso.services.box.net.",
- "ssp.hbrd.io.",
"ssp.hybrid.ai.",
"sstatic.net.",
"ssxd.mediav.com.",
"st-sysupgrade.vivo.com.cn.",
"stable.dl2.discordapp.net.",
"staffbase.com.",
+ "stags.bluekai.com.",
+ "stalker.to.",
+ "standwithcrypto.org.",
"stardustgod.com.",
"starrydyn.com.",
"startssl.com.",
- "stash.webstaurantstore.com.",
- "stat.360safe.com.",
"stat.pdfforge.org.",
"statad.ru.",
"static-atl3-1.xx.fbcdn.net.",
@@ -7181,7 +7113,6 @@ var FakeECSFQDNs = container.NewMapSet(
"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-mia3-1.xx.fbcdn.net.",
@@ -7189,39 +7120,35 @@ var FakeECSFQDNs = container.NewMapSet(
"static-msp1-1.xx.fbcdn.net.",
"static-ord5-1.xx.fbcdn.net.",
"static-ord5-2.xx.fbcdn.net.",
- "static-redesign.cnbcfm.com.",
"static-sea1-1.xx.fbcdn.net.",
"static-sjc3-1.xx.fbcdn.net.",
+ "static.atgsvcs.com.",
"static.avito.ru.",
"static.getliner.com.",
- "static.kwcdn.com.",
- "static.zdassets.com.",
- "static3.mixi.media.",
+ "static.mytonwallet.io.",
+ "static.sharepointonline.com.",
+ "static1.teacherspayteachers.com.",
+ "static5.mixi.media.",
"static6.mixi.media.",
- "static7.mixi.media.",
"static8.mixi.media.",
- "stats.adinplay.com.",
+ "staticview.msn.com.edgekey.net.",
"stats.aeries.com.",
"stats.rip.",
"stats.transitapp.com.",
"statsig.anthropic.com.",
- "statsjs.klevu.com.",
- "stemchristie.rome2rio.com.",
- "stevemadden.com.",
"stg-data-in.ads.heytapmobile.com.",
"stg-data.ads.heytapmobi.com.",
"stockholm.remotepc.com.",
"stocks-analytics-events.apple.com.",
"store-dra.hispace.dbankcloud.cn.",
"store.qq.com.",
- "streamhub.tech.",
"streetviewpixels-pa.googleapis.com.",
+ "stripchat.ooo.",
"stse02.ultipro.com.",
"stsew02.ultipro.com.",
"stsn02.ultipro.com.",
"student.atitesting.com.",
"studyquicks.com.",
- "stun.2talk.com.",
"stun.acrobits.cz.",
"stun.cdnbye.com.",
"stun.cloudflare.com.",
@@ -7232,15 +7159,15 @@ var FakeECSFQDNs = container.NewMapSet(
"stun2.ringcentral.com.",
"stun3.l.google.com.",
"stun4.l.google.com.",
- "stylitics.com.",
"su6786.ci.managedwhitelisting.com.",
+ "submittals-ui-service.pages.procore.com.",
"sumari-prod-1.srv.jbisumari.org.",
"sumologic.com.",
+ "sun.hac.lp1.d4c.nintendo.net.",
"sunmi.com.",
"supl.qxwz.com.",
- "support.dkbinnovative.com.",
+ "support.oracle.com.",
"support.powerschool.com.",
- "support.ricoh.com.",
"sv8.cyberhaven.io.",
"svlive.serraview.com.",
"swag.maxhost.io.",
@@ -7254,26 +7181,25 @@ var FakeECSFQDNs = container.NewMapSet(
"sync.oraki.io.",
"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.poki.io.",
- "t3.nhentai.net.",
"t3.xiaohongshu.com.",
"tag.winister.app.",
+ "tags.bluekai.com.edgekey.net.",
"tags.natwest.com.",
- "tags.tiqcdn.com.edgekey.net.",
"taipei.remotepc.com.",
+ "talon-service-prod.ecosec.on.epicgames.com.",
"tampa.remotepc.com.",
"tapecontent.net.",
"tapsell.ir.",
+ "target.digitalaudience.io.",
"tasks.office.com.",
"tasteofhome.com.",
"tatracker-us.rivergame.net.",
- "tbunet.com.",
"tccprod01.honeywell.com.",
"tccprod01.resideo.com.",
"tccprod02.honeywell.com.",
@@ -7281,34 +7207,38 @@ var FakeECSFQDNs = container.NewMapSet(
"tccprod03.honeywell.com.",
"tccprod03.resideo.com.",
"tcdnlive.com.",
- "tcdnos.com.",
"tclclouds.com.",
"tdcservices.tandemdiabetes.com.",
"tdm.qq.com.",
"teamviewer.com.",
+ "techcommunity.microsoft.com.",
"teddymobile.cn.",
"telecom.shuzilm.cn.",
"telemetry-sdk-inmobi-comtm.trafficmanager.net.",
"telemetry.savvy.security.",
+ "telemetry.sdk.inmobi.com.",
"telephony.goog.",
"teleport.media.",
+ "template.net.",
"tencent-cloud.com.",
"tencent-cloud.net.",
"tencentmusic.com.",
"tenda.com.cn.",
+ "tenpay.com.",
"terabox.app.",
+ "terabox.com.",
"terabox1024.com.",
"terms3.hicloud.com.",
- "test3.dantri.com.vn.",
"tgp.qq.com.",
"tgpa.qq.com.",
"thanhnien.vn.",
"theoks.net.",
- "thingiverse.com.",
+ "therealxh.com.",
+ "thetracker.org.",
"thinkific.com.",
"thm.visa.com.",
"thm12.visa.com.",
- "thor.sslauth.sonos.com.",
+ "thumb-v0.xhpingcdn.com.",
"time-a-b.nist.gov.",
"time-a-g.nist.gov.",
"time-a.nist.gov.",
@@ -7325,18 +7255,22 @@ var FakeECSFQDNs = container.NewMapSet(
"time.ecansol.net.",
"time.lmtlabs.com.",
"time.nest.com.",
+ "time.tritan.gg.",
"time.walb.tech.",
"time1.aliyun.com.",
"time1.google.com.",
"time2.aliyun.com.",
"time2.google.com.",
+ "time2.tritan.gg.",
"time3.aliyun.com.",
"time3.google.com.",
"time4.google.com.",
"timi-esports.qq.com.",
- "tk-sg.anythinktech.com.",
+ "tinnhiemmang.vn.",
+ "titank12.com.",
+ "tk.bridgeoos.com.",
"tk.mosspf.com.",
- "tkda.mosspf.com.",
+ "tk.mossru.com.",
"tkda.mossru.com.",
"tkx.mp.lura.live.",
"tlivecdn.com.",
@@ -7358,11 +7292,12 @@ var FakeECSFQDNs = container.NewMapSet(
"tngdigital.com.my.",
"tokyo.remotepc.com.",
"tongdun.net.",
+ "topgadgetlife.com.",
"toronto.remotepc.com.",
"toshiba-solutions.com.",
"touch-us.xiaoyi.com.",
+ "township-cdn.playrix.com.",
"tplay.qq.com.",
- "tpns.gz2.tencent.com.",
"tpns.sgp.tencent.com.",
"tpns.sh.tencent.com.",
"tpns.tencent.com.",
@@ -7373,10 +7308,18 @@ var FakeECSFQDNs = container.NewMapSet(
"tra-ac-ae2.best82.com.",
"tra-ac-id.apktorrents.com.",
"tra-ac-id.best82.com.",
+ "tra-ac-id2.apktorrents.com.",
"tra-ac-id2.best82.com.",
"tra-ac-ind.apktorrents.com.",
"tra-ac-ind.best82.com.",
"tra-ac-mas.apktorrents.com.",
+ "tra-ac-mas.best82.com.",
+ "tra-ard-id.apktorrents.com.",
+ "tra-ard-id.best82.com.",
+ "tra-hd-id.apktorrents.com.",
+ "tra-hd-id.best82.com.",
+ "tra-ht-id.apktorrents.com.",
+ "tra-ht-id.best82.com.",
"tra-hz-de.hyper-torrent.com.",
"tra-hz-fl.hyper-torrent.com.",
"tra-lwb-sg.best61.com.",
@@ -7395,10 +7338,11 @@ var FakeECSFQDNs = container.NewMapSet(
"tra-ved-ru.best82.com.",
"trace.qq.com.",
"track-eu1.hubspot.com.",
- "track.opentable.com.",
+ "track.easeus.com.",
"track.sendlane.com.",
"trackedlink.net.",
"tracker-udp.gbitt.info.",
+ "tracker.auctor.tv.",
"tracker.best61.com.",
"tracker.ccp.ovh.",
"tracker.files.fm.",
@@ -7409,18 +7353,19 @@ var FakeECSFQDNs = container.NewMapSet(
"tracker.nwps.ws.",
"tracker.theoks.net.",
"tracker1.bt.moack.co.kr.",
+ "tracker1.myporn.club.",
"tracker2.dler.org.",
"tracking.eu.flamtyr.com.",
"tracking.ksztone.com.",
+ "tradovateapi.com.",
"tradplusad.com.",
"transaccional.saludtotal.com.co.",
"traversal.syncromsp.com.",
"treas.gov.",
"treasury.gov.",
"tribalfusion.com.",
- "trivago.com.",
"trovit.com.",
- "ts.trafget.com.",
+ "trustlist.adobe.com.",
"ts1.qq.com.",
"ts2.qq.com.",
"tse1.explicit.bing.net.",
@@ -7431,31 +7376,28 @@ var FakeECSFQDNs = container.NewMapSet(
"tubecup.net.",
"tunnel.googlezip.net.",
"tuoitre.vn.",
- "tuya.com.",
- "tvx.adgrx.com.",
+ "turn.cloudflare.com.",
"tw.ntp.org.cn.",
+ "twcgov-my.sharepoint.com.",
"twcloudgz.ucbj.net.",
"twcloudgz1.ucbj.net.",
- "txcmmov.a.etoote.com.",
- "txqcmmov.a.etoote.com.",
"tydevice.com.",
"u.4dex.io.",
"uaenorth.api.cognitive.microsoft.com.",
"uapi.mp.360.cn.",
+ "ubeethiesemo.com.",
"uber.zoom.us.",
"uc.cn.",
"ucweb.com.",
"udemycdn.com.",
- "udns.weixin.qq.com.",
"ue.lenovomm.cn.",
"uhabo.com.",
"uk-api.asm.skype.com.",
+ "uk-odc.samsungapps.com.",
"uk-prod.asyncgw.teams.microsoft.com.",
"uk3-excel-collab.officeapps.live.com.",
"uk3-powerpoint-collab.officeapps.live.com.",
"uk5-excel-collab.officeapps.live.com.",
- "ukc-collabrtc-geo.rtc.trafficmanager.net.",
- "ukc-collabrtc.officeapps.live.com.",
"ukc-excel-collab.officeapps.live.com.",
"ukg.com.",
"ukyuh.tech.",
@@ -7467,28 +7409,25 @@ var FakeECSFQDNs = container.NewMapSet(
"umami.is.",
"umeng.com.",
"unicom.shuzilm.cn.",
- "unification.useinsider.com.",
+ "uniconsent.com.",
"unified-inbox-1-gw.ultipro.com.",
"unified-inbox-2-gw.ultipro.com.",
- "union.ucweb.com.",
"unipay.qq.com.",
"unisoc.com.",
"united.quantummetric.com.",
"unity.cn.",
"uodoo.com.",
"up.railway.app.",
- "update-solarwinds.2d585.cdn.bitdefender.net.",
+ "update.ee-share.com.",
"update.huorong.cn.",
"update.kingsoftstore.com.",
"update.vivaldi.com.",
"update.yealink.com.",
"updatechannel.sharegate.com.",
+ "updater.prntscr.com.",
+ "updater.skillbrains.com.",
"updaterservices.genetec.com.",
"updatesnl.macrium.com.",
- "upgrade.long.tv.",
- "upload3.systemmonitor.co.uk.",
- "upload3.systemmonitor.us.cdn.cloudflare.net.",
- "upload4.systemmonitor.us.cdn.cloudflare.net.",
"upravel.com.",
"upremium.asia.",
"urekamedia.com.",
@@ -7499,28 +7438,28 @@ var FakeECSFQDNs = container.NewMapSet(
"us-05.ws-api.ringcentral.com.",
"us-06.ws-api.ringcentral.com.",
"us-api.asm.skype.com.",
- "us-atl-anx-r009.router.teamviewer.com.",
+ "us-atl-anx-r001.router.teamviewer.com.",
+ "us-atl-anx-r002.router.teamviewer.com.",
+ "us-atl-anx-r005.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-amp-error-reporting.cloudfunctions.net.",
"us-central1-bps-oi-production.cloudfunctions.net.",
"us-central1-clubroom-prod.cloudfunctions.net.",
+ "us-central1-darden-main.cloudfunctions.net.",
"us-central1-digitalproducts-gabbo.cloudfunctions.net.",
+ "us-central1-ds-specials-dev.cloudfunctions.net.",
"us-central1-fsgenergy-shared.cloudfunctions.net.",
"us-central1-gaggle-staging.cloudfunctions.net.",
"us-central1-justbuild-cdb86.cloudfunctions.net.",
- "us-central1-kitsune-271319.cloudfunctions.net.",
"us-central1-kube-ownlocal.cloudfunctions.net.",
"us-central1-launchpad-169908.cloudfunctions.net.",
"us-central1-live-prod-1-1.cloudfunctions.net.",
"us-central1-locket-4252a.cloudfunctions.net.",
- "us-central1-marketplace-production-east4.cloudfunctions.net.",
"us-central1-mikmak-microservices.cloudfunctions.net.",
"us-central1-muslim-pro-app.cloudfunctions.net.",
"us-central1-noteit-4dca3.cloudfunctions.net.",
- "us-central1-omg-na-prd-brandometer-gcp-ca.cloudfunctions.net.",
- "us-central1-propane-fusion-170222.cloudfunctions.net.",
"us-central1-royal-match-prod-cce6d.cloudfunctions.net.",
"us-central1-shopify-instrumentat-ff788286.cloudfunctions.net.",
"us-central1-speechifymobile.cloudfunctions.net.",
@@ -7528,52 +7467,54 @@ var FakeECSFQDNs = container.NewMapSet(
"us-central1-teach-monster.cloudfunctions.net.",
"us-central1-webgltest-17af1.cloudfunctions.net.",
"us-central1-wise-arch-107501.cloudfunctions.net.",
- "us-cmh-gcp-r002.router.teamviewer.com.",
+ "us-dal-anx-r001.router.teamviewer.com.",
"us-dal-anx-r007.router.teamviewer.com.",
"us-dal-anx-r009.router.teamviewer.com.",
"us-dal-anx-r010.router.teamviewer.com.",
+ "us-dal-gcp-r002.router.teamviewer.com.",
"us-den-anx-r001.router.teamviewer.com.",
+ "us-den-anx-r005.router.teamviewer.com.",
"us-device-scheduler.ymcs.yealink.com.",
"us-device.ymcs.yealink.com.",
+ "us-east-1.console.aws.amazon.com.",
"us-east4-chkp-gcp-rnd-threat-hunt-box.cloudfunctions.net.",
- "us-las-gcp-r003.router.teamviewer.com.",
- "us-las-gcp-r004.router.teamviewer.com.",
- "us-lax-anx-r003.router.teamviewer.com.",
- "us-lax-anx-r010.router.teamviewer.com.",
+ "us-lax-anx-r007.router.teamviewer.com.",
+ "us-lax-anx-r008.router.teamviewer.com.",
+ "us-lax-anx-r009.router.teamviewer.com.",
"us-lax-anx-r011.router.teamviewer.com.",
- "us-lax-anx-r013.router.teamviewer.com.",
+ "us-lax-anx-r012.router.teamviewer.com.",
+ "us-lax-anx-r014.router.teamviewer.com.",
"us-lax-anx-r015.router.teamviewer.com.",
+ "us-lax-gcp-r002.router.teamviewer.com.",
+ "us-lax-gcp-r004.router.teamviewer.com.",
"us-mia-anx-r003.router.teamviewer.com.",
- "us-mia-anx-r006.router.teamviewer.com.",
+ "us-mia-anx-r004.router.teamviewer.com.",
"us-mia-anx-r009.router.teamviewer.com.",
- "us-mia-anx-r011.router.teamviewer.com.",
- "us-mia-anx-r012.router.teamviewer.com.",
"us-mia-anx-r013.router.teamviewer.com.",
- "us-njc-anx-r010.router.teamviewer.com.",
- "us-njc-anx-r011.router.teamviewer.com.",
- "us-ntl.np.community.playstation.net.",
- "us-oma-gcp-r002.router.teamviewer.com.",
- "us-pdx-gcp-r004.router.teamviewer.com.",
+ "us-mks-gcp-r003.router.teamviewer.com.",
+ "us-njc-anx-r005.router.teamviewer.com.",
+ "us-njc-anx-r008.router.teamviewer.com.",
+ "us-njc-anx-r015.router.teamviewer.com.",
"us-prod.asyncgw.teams.microsoft.com.",
- "us-sea-anx-r002.router.teamviewer.com.",
+ "us-sea-anx-r005.router.teamviewer.com.",
"us-sea-anx-r007.router.teamviewer.com.",
+ "us-slc-gcp-r001.router.teamviewer.com.",
+ "us-slc-gcp-r002.router.teamviewer.com.",
+ "us-slc-gcp-r003.router.teamviewer.com.",
"us-spectrum.rcs.telephony.goog.",
- "us-was-anx-r004.router.teamviewer.com.",
- "us-was-anx-r006.router.teamviewer.com.",
- "us-was-anx-r008.router.teamviewer.com.",
- "us-was-anx-r010.router.teamviewer.com.",
"us-was-anx-r011.router.teamviewer.com.",
- "us-was-anx-r012.router.teamviewer.com.",
- "us-was-anx-r015.router.teamviewer.com.",
- "us-was-anx-r017.router.teamviewer.com.",
- "us-was-anx-r019.router.teamviewer.com.",
+ "us-was-anx-r014.router.teamviewer.com.",
"us.att.rcs.telephony.goog.",
+ "us.evidation.com.",
+ "us.hdtvcloud.com.",
"us.hlth.io.mi.com.",
+ "us.questionai.com.",
"us.tmobile.rcs.telephony.goog.",
"us.tracfone.rcs.telephony.goog.",
"us.ubianet.com.",
"us.uscc.rcs.telephony.goog.",
"us.xfinity.rcs.telephony.goog.",
+ "us01docs.zoom.us.",
"us02log.zoom.us.",
"us02polling.zoom.us.",
"us02web.zoom.us.",
@@ -7581,6 +7522,7 @@ var FakeECSFQDNs = container.NewMapSet(
"us04asyncim.zoom.us.",
"us04nws-platform.zoom.us.",
"us04nws.zoom.us.",
+ "us04st3.zoom.us.",
"us04web.zoom.us.",
"us04www3.zoom.us.",
"us05nws-platform.zoom.us.",
@@ -7591,11 +7533,11 @@ var FakeECSFQDNs = container.NewMapSet(
"us06polling.zoom.us.",
"us06web.zoom.us.",
"us06www3.zoom.us.",
- "us1111.alicdn.com.edgekey.net.",
- "us2.rtbsystem.org.",
"us3a-excel-collab.ocs.trafficmanager.net.",
"us3a-excel-collab.officeapps.live.com.",
+ "us3a-powerpoint-collab.ocs.trafficmanager.net.",
"us3a-powerpoint-collab.officeapps.live.com.",
+ "us3a-word-collab.ocs.trafficmanager.net.",
"us3a-word-collab.officeapps.live.com.",
"us4a-excel-collab.officeapps.live.com.",
"us4a-powerpoint-collab.officeapps.live.com.",
@@ -7628,23 +7570,30 @@ var FakeECSFQDNs = container.NewMapSet(
"usc-powerpoint-collab.officeapps.live.com.",
"usc-word-collab.officeapps.live.com.",
"usc.edu.",
+ "usc.pods.officeapps.live.com.",
"uscis.gov.",
+ "usdoj.gov.",
+ "use3-assets.a-mo.net.",
+ "use4.s.seedtag.com.",
"useast.quantumdex.io.",
- "userexperience.thehut.net.",
+ "usefulcontentsites.com.",
"usgs.gov.",
"ussav.cynet.com.",
"usserver.serverapi.org.",
"usslb.cynet.com.",
"usw.stape.io.",
"uswest-beacon.deepintent.com.",
+ "ut.hzshudian.com.",
"uu.qq.com.",
"uuidksinc.net.",
+ "uwcu.cyberhaven.io.",
+ "uworld.com.",
"uxfeedback.ru.",
"v.vivintsky.com.",
"v39-as.tiktokcdn.com.",
"v39-ca.tiktokcdn.com.",
"v39-id-telin.tiktokcdn.com.",
- "v39-mx.tiktokcdn.com.",
+ "v39-id.gts.byteoversea.net.",
"v39-row.gts.byteoversea.net.",
"v39-row.tiktokcdn.com.",
"v39-us.gts.byteoversea.net.",
@@ -7655,21 +7604,22 @@ var FakeECSFQDNs = container.NewMapSet(
"v6-gdvod.kwaicdn.com.",
"v8.analytics.pinsightmedia.com.",
"v8engine.pinsightmedia.com.",
- "vadesecure.com.",
"vador.com.",
+ "valleychildrensorg-my.sharepoint.com.",
"vbw.vivoglobal.com.",
+ "vcsa.vmware.com.cdn.cloudflare.net.",
"venafi.com.",
- "veoneer.com.",
- "verafin.okta.com.",
"verification.fda.gov.ph.",
"verticals.wix.com.",
- "vexgateway.fastly.carvana.io.",
"vfa.hpplay.cn.",
+ "vgorigin.hakunaymatata.com.",
+ "vi.vipr.ebaydesc.com.",
"vibe.co.",
"vibeaconstr.onezapp.com.",
"vicoo.tech.",
"video-atl3-1.xx.fbcdn.net.",
"video-atl3-2.xx.fbcdn.net.",
+ "video-atl3-3.xx.fbcdn.net.",
"video-bos5-1.xx.fbcdn.net.",
"video-den2-1.xx.fbcdn.net.",
"video-dfw5-1.xx.fbcdn.net.",
@@ -7693,11 +7643,10 @@ var FakeECSFQDNs = container.NewMapSet(
"video-phx1-1.xx.fbcdn.net.",
"video-sea1-1.xx.fbcdn.net.",
"video-sjc3-1.xx.fbcdn.net.",
- "video.foxnews.com.",
- "videocontent-dra.himovie.dbankcloud.cn.",
"videocontent-dra.himovie.dbankcloud.com.",
"vidmate.net.",
"vieon.vn.",
+ "view.admeking.com.",
"vik-ca.moonactive.net.",
"vik-game.moonactive.net.",
"viously.com.",
@@ -7708,6 +7657,9 @@ var FakeECSFQDNs = container.NewMapSet(
"vitality.io.",
"vividseats.com.",
"vivoglobal.com.",
+ "vn-viettel.rcs.telephony.goog.",
+ "vn2-red.lol.sgp.pvp.net.",
+ "vntsnotificationservice.visa.com.cdn.cloudflare.net.",
"vod.ngb.haplat.net.",
"vod2.ngb.haplat.net.",
"vod3.ngb.haplat.net.",
@@ -7717,6 +7669,7 @@ var FakeECSFQDNs = container.NewMapSet(
"voe.sx.",
"voice.gcloudcs.com.",
"voice.telephony.goog.",
+ "vote.donaldjtrump.com.",
"voya.com.",
"vpn1.ocso.com.",
"vx9dle.n0qq3z.com.",
@@ -7725,105 +7678,108 @@ var FakeECSFQDNs = container.NewMapSet(
"w25.cf.2ksports.com.",
"w3.mp.lura.live.",
"wahapanih.xyz.",
+ "wap.cmpassport.com.",
"warsaw.remotepc.com.",
- "wavemaxpro.com.",
"wayfinding-hub-gateway-atl.ultipro.com.",
"wayfinding-hub-gateway-plas1.ultipro.com.",
+ "wb.qq.com.",
+ "wcsdpaorg-my.sharepoint.com.",
+ "wd5-impl.workdaycdn.com.",
+ "we.footballbros.io.",
"weather-analytics-events.apple.com.",
"weather-server-sg.allawnos.com.",
"weather-server.allawntech.com.",
"weather-widget-events.apple.com.",
"weather.swishapps.ai.",
+ "weather.transsion-os.com.",
"weathercn.com.",
- "weatherwidget.io.",
- "web-api.ikea.com.",
- "web-static.archive.org.",
+ "web-assets.stockx.com.",
+ "web-assets.stylitics.com.cdn.cloudflare.net.",
+ "web-static.mindbox.ru.",
+ "web.archive.org.",
"web.voice.telephony.goog.",
"web1.remotepc.com.",
"webapi.teamviewer.com.",
"webmd.com.",
- "webservices.global-e.com.",
"websocket.app.pdq.com.",
"wechatos.net.",
- "weerrhoop.cc.",
"wegame.com.cn.",
"weibocdn.com.",
"welcome.ultipro.com.",
"wemuslim.com.",
+ "wesingapp.com.",
"westcentralus.api.cognitive.microsoft.com.",
"westeurope.api.cognitive.microsoft.com.",
"westpalm.remotepc.com.",
"westus.api.cognitive.microsoft.com.",
"westus2.api.cognitive.microsoft.com.",
"westus3.api.cognitive.microsoft.com.",
- "wewjyw.qb6ges.com.",
- "whiteboard-session.nearpod.com.",
"whitingturner-my.sharepoint.com.",
"whitingturner.sharepoint.com.",
- "whm.usa.experian.com.",
- "whova.com.",
- "widget.cloudinary.com.",
- "widgets.media.weather.com.",
"wifispot.io.",
- "wildcard.s-msn.com.edgekey.net.",
- "win-rtb2-useast.xaprio.net.",
+ "wild.ww.np.dl.playstation.net.edgekey.net.",
+ "windows.policies.live.net.",
"winscp.net.",
"wkhpe.com.",
"wmt.dev.",
"word-collab.officeapps.live.com.",
"wordreference.com.",
"workdaycdn.com.cn.",
- "worksighted.com.",
"worldnic.com.",
"worldtimeserver.com.",
"wosign.com.",
+ "wpsw.listrak.com.",
"wr.moyoung.com.",
"wr.pvp.net.",
"ws.gleap.io.",
"ws.mybib.com.",
+ "ws.thales.monumetric.com.",
"ws.tildacdn.com.",
- "ws.toasttab.com.",
"wsdcc.haplat.net.",
- "wsms.haplat.net.",
"wsoversea.com.",
- "wsrv.nl.",
+ "wss-web.freshchat.com.",
+ "www.481528.com.",
"www.aigconnect.aig.",
"www.americanexpress.com.edgekey.net.",
- "www.animefox.sbs.",
"www.automizely-analytics.com.",
- "www.bol.com.",
+ "www.belkin.com.",
"www.breitbart.com.",
- "www.carmax.com.",
+ "www.brilliantearth.com.",
+ "www.census.gov.",
"www.chrome.com.",
"www.claudeusercontent.com.",
"www.cmpassport.com.",
- "www.cnbc.com.edgekey.net.",
- "www.costco.com.",
- "www.credible.com.",
"www.ctmail.com.",
- "www.drugs.com.",
- "www.foodnetwork.com.",
- "www.gap.com.",
+ "www.ebay.com.",
+ "www.education.com.",
+ "www.epicgames.com.",
+ "www.fda.gov.",
+ "www.fiverr.com.",
+ "www.garmin.com.",
+ "www.geappliances.com.",
"www.geoplugin.net.",
"www.google.org.",
"www.in.gov.",
"www.internetdownloadmanager.com.",
"www.jimmyjohns.com.",
- "www.jpost.com.",
"www.maintenanceconnection.com.",
- "www.marksandspencer.com.",
+ "www.mcmaster.com.",
"www.nativecos.com.",
- "www.niemanlab.org.",
+ "www.originplatform.com.",
"www.overleaf.com.",
"www.pingler.com.",
+ "www.potterybarn.com.",
"www.printfriendly.com.",
+ "www.questionai.com.",
"www.regions.com.",
- "www.servicenow.com.",
+ "www.rockchip.com.",
+ "www.se.com.",
"www.sevenrooms.com.",
- "www.snokido.com.",
- "www.sogou.com.",
- "www.starbucks.com.",
+ "www.southwest.com.",
+ "www.startssl.com.",
"www.stickermule.com.",
+ "www.terabox.com.",
+ "www.trivago.com.",
"www.users.storage.live.com.",
"www.vipads.live.",
"www.virustotal.com.",
@@ -7832,36 +7788,39 @@ var FakeECSFQDNs = container.NewMapSet(
"www.wifispot.io.",
"www.wix.com.",
"www.worldtimeserver.com.",
- "www.writable.com.",
- "www.zappos.com.edgekey.net.",
- "www.zdf.de.",
+ "www.zenaps.com.",
"www.zoom.com.",
"www.zoom.us.",
"www1.remotepc.com.",
- "www10.wellsfargomedia.com.",
- "www11.wellsfargomedia.com.",
+ "www14.wellsfargomedia.com.",
"www2.deepl.com.",
"www3.zoom.us.",
+ "wx.huion.cn.",
"wxqcloud.qq.com.",
"wxqcloud.qq.com.cn.",
- "wyze-re-rule-svc.wyzecam.com.",
"wyze.com.",
"x-flow.app.",
- "x.netease.com.",
- "x1.c.lencr.org.",
+ "xedo.me.",
"xhpingcdn.com.",
"xiaoyi.com.",
+ "xinqiucc.com.",
"xintaicz.cn.",
"xmcsrv.net.",
+ "xml-eu-v4.ezmob.com.",
"xml.acertb.com.",
"xml.adservtday.com.",
+ "xml.cachegorilla.com.",
+ "xml.ezmob.com.",
+ "xml.kunvertads.com.",
+ "xml.popmonetizer.net.",
"xml.responseservez.com.",
"xml.revrtb.net.",
"xml.servsserverz.com.",
"xml.xmlking.com.",
+ "xml.xmlwolf.com.",
"xml.zeusadx.com.",
+ "xmlking.com.",
"xmt.paze.com.",
- "xp.apple.com.",
"xp001.itsupport247.net.",
"xp002.itsupport247.net.",
"xp003.itsupport247.net.",
@@ -7878,22 +7837,24 @@ var FakeECSFQDNs = container.NewMapSet(
"xp019.itsupport247.net.",
"yalla.live.",
"yealink.com.",
+ "yh.yardiaspire.com.",
+ "ymmobi.com.",
"yomedia.vn.",
"yomeno.xyz.",
"yosmart.com.",
- "yp.cdnstream1.com.",
"yunxindns.com.",
"yunxinfw.com.",
+ "z-long.cn.",
"z.cdn.adpool.bet.",
"z.cdn.adtarget.market.",
+ "z.cdn.xbeat.space.",
+ "zdx.uber.com.",
"zemanta.com.",
- "zenno.services.",
"zjcdn.com.yangyi19.com.",
- "zmedia.vn.",
"zog.link.",
"zoom.us.",
- "zorvian.com.",
"zui.com.",
"zurich.remotepc.com.",
"zybooks.com.",
+ "zztfly.com.",
)
diff --git a/internal/ecscache/ecsblocklist_generate.go b/internal/ecscache/ecsblocklist_generate.go
index abc27cb..5571240 100644
--- a/internal/ecscache/ecsblocklist_generate.go
+++ b/internal/ecscache/ecsblocklist_generate.go
@@ -4,7 +4,9 @@ package main
import (
"bytes"
+ "context"
"io"
+ "log/slog"
"net/http"
"os"
"slices"
@@ -12,41 +14,42 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/httphdr"
- "github.com/AdguardTeam/golibs/log"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/golibs/osutil"
)
func main() {
+ ctx := context.Background()
+ logger := slogutil.New(nil)
+ defer slogutil.RecoverAndExit(ctx, logger, osutil.ExitCodeFailure)
+
c := &http.Client{
Timeout: 10 * time.Second,
}
- req, err := http.NewRequest(http.MethodGet, fakeECSBlocklistURL, nil)
- check(err)
+ req := errors.Must(http.NewRequest(http.MethodGet, fakeECSBlocklistURL, nil))
req.Header.Add(httphdr.UserAgent, agdhttp.UserAgent())
- resp, err := c.Do(req)
- check(err)
- defer log.OnCloserError(resp.Body, log.ERROR)
+ resp := errors.Must(c.Do(req))
+ defer slogutil.CloseAndLog(ctx, logger, resp.Body, slog.LevelError)
- out, err := os.OpenFile("./ecsblocklist.go", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o664)
- check(err)
- defer log.OnCloserError(out, log.ERROR)
+ out := errors.Must(os.OpenFile("./ecsblocklist.go", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o664))
+ defer slogutil.CloseAndLog(ctx, logger, out, slog.LevelError)
- contents, err := io.ReadAll(resp.Body)
- check(err)
+ contents := errors.Must(io.ReadAll(resp.Body))
lines := bytes.Split(contents, []byte("\n"))
lines = lines[:len(lines)-1]
slices.SortStableFunc(lines, bytes.Compare)
- tmpl, err := template.New("main").Parse(tmplStr)
- check(err)
+ tmpl := template.Must(template.New("main").Parse(tmplStr))
- err = tmpl.Execute(out, lines)
- check(err)
+ err := tmpl.Execute(out, lines)
+ errors.Check(err)
}
// fakeECSBlocklistURL is the default URL from where to get ECS fake domains.
@@ -67,10 +70,3 @@ var FakeECSFQDNs = container.NewMapSet(
{{- end }}
)
`
-
-// check is a simple error checker.
-func check(err error) {
- if err != nil {
- panic(err)
- }
-}
diff --git a/internal/ecscache/ecscache.go b/internal/ecscache/ecscache.go
index 542fc57..d426db4 100644
--- a/internal/ecscache/ecscache.go
+++ b/internal/ecscache/ecscache.go
@@ -5,6 +5,7 @@ package ecscache
import (
"context"
"fmt"
+ "log/slog"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
@@ -13,9 +14,8 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
- "github.com/AdguardTeam/AdGuardDNS/internal/optlog"
+ "github.com/AdguardTeam/AdGuardDNS/internal/optslog"
"github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/syncutil"
"github.com/miekg/dns"
@@ -33,6 +33,12 @@ type Middleware struct {
// cloner is the memory-efficient cloner of DNS messages.
cloner *dnsmsg.Cloner
+ // cacheReqPool is a pool of cache requests.
+ cacheReqPool *syncutil.Pool[cacheRequest]
+
+ // logger is used to log the operation of the middleware.
+ logger *slog.Logger
+
// cache is the LRU cache for results indicating no support for ECS.
cache agdcache.Interface[uint64, *cacheItem]
@@ -42,22 +48,23 @@ type Middleware struct {
// geoIP is used to get subnets for countries.
geoIP geoip.Interface
- // cacheReqPool is a pool of cache requests.
- cacheReqPool *syncutil.Pool[cacheRequest]
-
// cacheMinTTL is the minimum supported TTL for cache items.
cacheMinTTL time.Duration
- // useTTLOverride shows if the TTL overrides logic should be used.
- useTTLOverride bool
+ // overrideTTL shows if the TTL overrides logic should be used.
+ overrideTTL bool
}
-// MiddlewareConfig is the configuration structure for NewMiddleware.
+// MiddlewareConfig is the configuration structure for [NewMiddleware].
type MiddlewareConfig struct {
- // Cloner is used to clone messages taken from cache.
+ // Cloner is used to clone messages taken from cache. It must not be nil.
Cloner *dnsmsg.Cloner
- // CacheManager is the global cache manager. CacheManager must not be nil.
+ // Logger is used to log the operation of the middleware. It must not be
+ // nil.
+ Logger *slog.Logger
+
+ // CacheManager is the global cache manager. It must not be nil.
CacheManager agdcache.Manager
// GeoIP is the GeoIP database used to get subnets for countries. It must
@@ -67,16 +74,16 @@ type MiddlewareConfig struct {
// MinTTL is the minimum supported TTL for cache items.
MinTTL time.Duration
- // Size is the number of entities to hold in the cache for hosts that don't
- // support ECS. It must be greater than zero.
- Size int
+ // NoECSCount is the number of entities to hold in the cache for hosts that
+ // don't support ECS, in entries. It must be greater than zero.
+ NoECSCount int
- // ECSSize is the number of entities to hold in the cache for hosts that
- // support ECS. It must be greater than zero.
- ECSSize int
+ // ECSCount is the number of entities to hold in the cache for hosts that
+ // support ECS, in entries. It must be greater than zero.
+ ECSCount int
- // UseTTLOverride shows if the TTL overrides logic should be used.
- UseTTLOverride bool
+ // OverrideTTL shows if the TTL overrides logic should be used.
+ OverrideTTL bool
}
// NewMiddleware initializes a new ECS-aware LRU caching middleware. It also
@@ -84,25 +91,26 @@ type MiddlewareConfig struct {
// manager. c must not be nil.
func NewMiddleware(c *MiddlewareConfig) (m *Middleware) {
cache := agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
- Size: c.Size,
+ Size: c.NoECSCount,
})
ecsCache := agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
- Size: c.ECSSize,
+ Size: c.ECSCount,
})
c.CacheManager.Add(cacheIDNoECS, cache)
c.CacheManager.Add(cacheIDWithECS, ecsCache)
return &Middleware{
- cloner: c.Cloner,
- cache: cache,
- ecsCache: ecsCache,
- geoIP: c.GeoIP,
+ cloner: c.Cloner,
+ logger: c.Logger,
cacheReqPool: syncutil.NewPool(func() (req *cacheRequest) {
return &cacheRequest{}
}),
- cacheMinTTL: c.MinTTL,
- useTTLOverride: c.UseTTLOverride,
+ cache: cache,
+ ecsCache: ecsCache,
+ geoIP: c.GeoIP,
+ cacheMinTTL: c.MinTTL,
+ overrideTTL: c.OverrideTTL,
}
}
@@ -224,8 +232,7 @@ func (mw *Middleware) writeUpstreamResponse(
return fmt.Errorf("getting ecs from resp: %w", err)
}
- // TODO(a.garipov): Use optslog.Trace2.
- optlog.Debug2("ecscache: upstream: %s/%d", subnet, scope)
+ optslog.Trace2(ctx, mw.logger, "upstream data", "subnet", subnet, "scope", scope)
reqDO := cr.reqDO
rmHopToHopData(resp, ri.QType, reqDO)
@@ -304,7 +311,7 @@ func (mh *mwHandler) ServeDNS(
// Cache key calculation shouldn't consider the subnet of the cache
// request in this case, but the actual DNS request generated on cache
// miss will use this data.
- log.Debug("ecscache: explicitly declined ecs")
+ mw.logger.DebugContext(ctx, "explicitly declined ecs")
cr.subnet = netutil.ZeroPrefix(ecsFam)
} else {
@@ -319,21 +326,28 @@ func (mh *mwHandler) ServeDNS(
)
}
- optlog.Debug3("ecscache: got ctry %s, asn %d, subnet %s", loc.Country, loc.ASN, cr.subnet)
+ optslog.Debug3(
+ ctx,
+ mw.logger,
+ "request data",
+ "ctry", loc.Country,
+ "asn", loc.ASN,
+ "subnet", cr.subnet,
+ )
}
// Try getting a cached result using the subnet of the location or zero one
// when explicitly requested by user. If there is one, write, increment the
// metrics, and return. See also [writeCachedResponse].
- resp, respIsECS := mw.get(req, cr)
+ resp, respIsECS := mw.get(ctx, req, cr)
if resp != nil {
- optlog.Debug1("ecscache: using cached response (ecs-aware: %t)", respIsECS)
+ optslog.Debug1(ctx, mw.logger, "using cached response", "ecs_aware", respIsECS)
// Don't wrap the error, because it's informative enough as is.
return writeCachedResponse(ctx, rw, req, resp, ri.ECS, ecsFam, respIsECS)
}
- log.Debug("ecscache: no cached response")
+ mw.logger.DebugContext(ctx, "no cached response")
// Perform an upstream request with the ECS data for the location or zero
// one on circumstances described above. If successful, write, increment
diff --git a/internal/ecscache/ecscache_test.go b/internal/ecscache/ecscache_test.go
index bcffa1f..ef1e221 100644
--- a/internal/ecscache/ecscache_test.go
+++ b/internal/ecscache/ecscache_test.go
@@ -16,6 +16,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/ecscache"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
@@ -23,10 +24,6 @@ import (
"github.com/stretchr/testify/require"
)
-func TestMain(m *testing.M) {
- testutil.DiscardLogOutput(m)
-}
-
// Common test domain names.
const (
reqHostname = "example.com."
@@ -668,31 +665,29 @@ func newWithCache(
pt := testutil.PanicT{}
- // TODO(a.garipov): Actually test ASNs once we have the data.
- geoIP := &agdtest.GeoIP{
- OnSubnetByLocation: func(
- l *geoip.Location,
- _ netutil.AddrFamily,
- ) (n netip.Prefix, err error) {
- require.Equal(pt, wantCtry, l.Country)
+ geoIP := agdtest.NewGeoIP()
- return geoIPNet, nil
- },
- OnData: func(_ string, _ netip.Addr) (_ *geoip.Location, _ error) {
- panic("not implemented")
- },
+ // TODO(a.garipov): Actually test ASNs once we have the data.
+ geoIP.OnSubnetByLocation = func(
+ l *geoip.Location,
+ _ netutil.AddrFamily,
+ ) (n netip.Prefix, err error) {
+ require.Equal(pt, wantCtry, l.Country)
+
+ return geoIPNet, nil
}
return dnsserver.WithMiddlewares(
h,
ecscache.NewMiddleware(&ecscache.MiddlewareConfig{
- Cloner: agdtest.NewCloner(),
- CacheManager: agdcache.EmptyManager{},
- GeoIP: geoIP,
- Size: 100,
- ECSSize: 100,
- MinTTL: minTTL,
- UseTTLOverride: useTTLOverride,
+ Cloner: agdtest.NewCloner(),
+ Logger: slogutil.NewDiscardLogger(),
+ CacheManager: agdcache.EmptyManager{},
+ GeoIP: geoIP,
+ NoECSCount: 100,
+ ECSCount: 100,
+ MinTTL: minTTL,
+ OverrideTTL: useTTLOverride,
}),
)
}
diff --git a/internal/filter/filter_test.go b/internal/filter/filter_test.go
index da2c85e..063d5ba 100644
--- a/internal/filter/filter_test.go
+++ b/internal/filter/filter_test.go
@@ -98,7 +98,6 @@ const testDataFiltersTmpl = `{
"filters": [
{
"filterKey": %q,
- "filterId": 42,
"downloadUrl": "http://example.com"
}
]
diff --git a/internal/filter/hashprefix/filter.go b/internal/filter/hashprefix/filter.go
index bc1cc05..a5baca7 100644
--- a/internal/filter/hashprefix/filter.go
+++ b/internal/filter/hashprefix/filter.go
@@ -310,18 +310,23 @@ func (f *Filter) respForFamily(
//
// TODO(ameshkov): Consider putting the resolved IP addresses into hints
// to show the blocked page here as well?
- return ri.Messages.NewBlockedRespMsg(req)
+ return ri.Messages.NewBlockedResp(req)
}
ip := f.repIP
switch {
case ip.Is4() && fam == netutil.AddrFamilyIPv4:
- return ri.Messages.NewIPRespMsg(req, ip)
+ return ri.Messages.NewBlockedRespIP(req, ip)
case ip.Is6() && fam == netutil.AddrFamilyIPv6:
- return ri.Messages.NewIPRespMsg(req, ip)
+ return ri.Messages.NewBlockedRespIP(req, ip)
default:
- return ri.Messages.NewMsgNODATA(req), nil
+ // TODO(e.burkov): Use [dnsmsg.Constructor.NewBlockedRespRCode] when it
+ // adds SOA records.
+ resp = ri.Messages.NewRespRCode(req, dns.RcodeSuccess)
+ ri.Messages.AddEDE(req, resp, dns.ExtendedErrorCodeFiltered)
+
+ return resp, nil
}
}
diff --git a/internal/filter/hashprefix/filter_test.go b/internal/filter/hashprefix/filter_test.go
index 8567c0c..3322495 100644
--- a/internal/filter/hashprefix/filter_test.go
+++ b/internal/filter/hashprefix/filter_test.go
@@ -234,7 +234,7 @@ func newModRespResult(
) (r *internal.ResultModifiedResponse) {
tb.Helper()
- resp, err := messages.NewIPRespMsg(req, replIP)
+ resp, err := messages.NewRespIP(req, replIP)
require.NoError(tb, err)
return &internal.ResultModifiedResponse{
@@ -370,7 +370,9 @@ func TestFilter_FilterRequest_staleCache(t *testing.T) {
msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
Cloner: cloner,
BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ StructuredErrors: agdtest.NewSDEConfig(true),
FilteredResponseTTL: agdtest.FilteredResponseTTL,
+ EDEEnabled: true,
})
require.NoError(t, err)
diff --git a/internal/filter/index.go b/internal/filter/index.go
index 74c66a8..f962d6a 100644
--- a/internal/filter/index.go
+++ b/internal/filter/index.go
@@ -10,50 +10,97 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/golibs/errors"
)
-// filterIndexResp is the struct for the JSON response from a filter index API.
-type filterIndexResp struct {
- Filters []*filterIndexRespFilter `json:"filters"`
-}
-
-// filterIndexRespFilter is the struct for a filter from the JSON response from
-// a filter index API.
+// indexResp is the struct for the JSON response from a filter index API.
//
-// TODO(a.garipov): Remove ID once the index switches the format completely.
-type filterIndexRespFilter struct {
- DownloadURL string `json:"downloadUrl"`
- FilterID any `json:"filterId"`
- Key string `json:"filterKey"`
+// TODO(a.garipov): Consider validating uniqueness of the keys.
+type indexResp struct {
+ Filters []*indexRespFilter `json:"filters"`
}
-// filterIndexFilterData is the data of a single item in the filtering-rule
-// index response.
-type filterIndexFilterData struct {
+// indexRespFilter is the struct for a filter from the JSON response from a
+// filter index API.
+//
+// NOTE: Keep these strings instead of unmarshalers to make sure that objects
+// with invalid data do not prevent valid objects from being used.
+type indexRespFilter struct {
+ // DownloadURL contains the URL to use for downloading this filter.
+ DownloadURL string `json:"downloadUrl"`
+
+ // Key contains the ID of the filter as a string.
+ Key string `json:"filterKey"`
+}
+
+// compare is the comparison function for filters in the index. f and other may
+// be nil; nil filters are sorted after non-nil ones.
+func (f *indexRespFilter) compare(other *indexRespFilter) (res int) {
+ if f == nil {
+ if other == nil {
+ return 0
+ }
+
+ return 1
+ } else if other == nil {
+ return -1
+ }
+
+ return cmp.Compare(f.Key, other.Key)
+}
+
+// validate returns an error if f is invalid.
+func (f *indexRespFilter) validate() (err error) {
+ if f == nil {
+ return errors.ErrNoValue
+ }
+
+ var errs []error
+
+ // TODO(a.garipov): Use urlutil.URL or add IsValidURLString to golibs.
+ if f.DownloadURL == "" {
+ errs = append(errs, fmt.Errorf("downloadUrl: %w", errors.ErrEmptyValue))
+ }
+
+ if f.Key == "" {
+ errs = append(errs, fmt.Errorf("filterKey: %w", errors.ErrEmptyValue))
+ }
+
+ return errors.Join(errs...)
+}
+
+// indexData is the data of a single item in the filtering-rule index response.
+type indexData struct {
url *url.URL
id agd.FilterListID
}
-// toInternal converts the filters from the index to []*filterIndexFilterData.
-func (r *filterIndexResp) toInternal(
+// toInternal converts the filters from the index to []*indexData. All errors
+// are logged and collected. logger and errColl must not be nil.
+func (r *indexResp) toInternal(
ctx context.Context,
logger *slog.Logger,
errColl errcoll.Interface,
-) (fls []*filterIndexFilterData) {
- fls = make([]*filterIndexFilterData, 0, len(r.Filters))
- for _, rf := range r.Filters {
- rfFltID, _ := rf.FilterID.(string)
- rfID := cmp.Or(rf.Key, rfFltID)
- id, err := agd.NewFilterListID(rfID)
+) (fls []*indexData) {
+ fls = make([]*indexData, 0, len(r.Filters))
+ for i, rf := range r.Filters {
+ err := rf.validate()
if err != nil {
- err = fmt.Errorf("validating id/key: %w", err)
+ err = fmt.Errorf("validating filter at index %d: %w", i, err)
errcoll.Collect(ctx, errColl, logger, "index response", err)
continue
}
- var u *url.URL
- u, err = agdhttp.ParseHTTPURL(rf.DownloadURL)
+ id, err := agd.NewFilterListID(rf.Key)
+ if err != nil {
+ err = fmt.Errorf("validating id/key: %w", err)
+ errcoll.Collect(ctx, errColl, logger, "index response ids", err)
+
+ continue
+ }
+
+ u, err := agdhttp.ParseHTTPURL(rf.DownloadURL)
if err != nil {
err = fmt.Errorf("validating url: %w", err)
errcoll.Collect(ctx, errColl, logger, "index response", err)
@@ -61,7 +108,7 @@ func (r *filterIndexResp) toInternal(
continue
}
- fls = append(fls, &filterIndexFilterData{
+ fls = append(fls, &indexData{
url: u,
id: id,
})
diff --git a/internal/filter/index_internal_test.go b/internal/filter/index_internal_test.go
new file mode 100644
index 0000000..d40f9b5
--- /dev/null
+++ b/internal/filter/index_internal_test.go
@@ -0,0 +1,37 @@
+package filter
+
+import (
+ "slices"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestIndexRespFilter_compare(t *testing.T) {
+ var (
+ fltA = &indexRespFilter{
+ Key: "a",
+ }
+ fltB = &indexRespFilter{
+ Key: "b",
+ }
+ )
+
+ want := []*indexRespFilter{
+ fltA,
+ fltB,
+ nil,
+ nil,
+ }
+
+ got := []*indexRespFilter{
+ fltB,
+ nil,
+ fltA,
+ nil,
+ }
+
+ slices.SortStableFunc(got, (*indexRespFilter).compare)
+
+ assert.Equal(t, want, got)
+}
diff --git a/internal/filter/internal/composite/composite_internal_test.go b/internal/filter/internal/composite/composite_internal_test.go
index 416ed9a..f8be5c8 100644
--- a/internal/filter/internal/composite/composite_internal_test.go
+++ b/internal/filter/internal/composite/composite_internal_test.go
@@ -32,9 +32,13 @@ func BenchmarkFilter_FilterReqWithRuleLists(b *testing.B) {
})
msgs, err := dnsmsg.NewConstructor(&dnsmsg.ConstructorConfig{
- Cloner: dnsmsg.NewCloner(dnsmsg.EmptyClonerStat{}),
- BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ Cloner: dnsmsg.NewCloner(dnsmsg.EmptyClonerStat{}),
+ BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ StructuredErrors: &dnsmsg.StructuredDNSErrorsConfig{
+ Enabled: false,
+ },
FilteredResponseTTL: filtertest.Staleness,
+ EDEEnabled: false,
})
require.NoError(b, err)
diff --git a/internal/filter/internal/refreshable.go b/internal/filter/internal/refreshable.go
index 2626a1a..18864c4 100644
--- a/internal/filter/internal/refreshable.go
+++ b/internal/filter/internal/refreshable.go
@@ -40,8 +40,8 @@ type RefreshableConfig struct {
// Logger is used to log errors during refreshes.
Logger *slog.Logger
- // URL is the URL used to refresh the filter. URL should not be nil. The
- // scheme of the URL should be one of: "file", "http", or "https".
+ // URL is the URL used to refresh the filter. URL should be either a file
+ // URL or an HTTP(S) URL and should not be nil.
URL *url.URL
// ID is the filter list ID for this filter.
@@ -65,7 +65,8 @@ type RefreshableConfig struct {
func NewRefreshable(c *RefreshableConfig) (f *Refreshable, err error) {
if c.URL == nil {
return nil, fmt.Errorf("internal.NewRefreshable: nil url for refreshable with ID %q", c.ID)
- } else if s := c.URL.Scheme; s != agdhttp.SchemeFile && !agdhttp.CheckHTTPURLScheme(s) {
+ } else if s := c.URL.Scheme; !strings.EqualFold(s, urlutil.SchemeFile) &&
+ !urlutil.IsValidHTTPURLScheme(s) {
return nil, fmt.Errorf("internal.NewRefreshable: bad url scheme %q", s)
}
@@ -90,7 +91,7 @@ func NewRefreshable(c *RefreshableConfig) (f *Refreshable, err error) {
func (f *Refreshable) Refresh(ctx context.Context, acceptStale bool) (text string, err error) {
defer func() { err = errors.Annotate(err, "%s: %w", f.id) }()
- if f.url.Scheme == agdhttp.SchemeFile {
+ if strings.EqualFold(f.url.Scheme, urlutil.SchemeFile) {
text, err = f.refreshFromFileOnly(ctx)
} else {
text, err = f.useCachedOrRefreshFromURL(ctx, acceptStale)
@@ -130,13 +131,12 @@ func (f *Refreshable) useCachedOrRefreshFromURL(
}
if text == "" {
- f.logger.InfoContext(ctx, "refreshing from url", "url", &urlutil.URL{
- URL: *f.url,
- })
+ ru := urlutil.RedactUserinfo(f.url)
+ f.logger.InfoContext(ctx, "refreshing from url", "url", ru)
text, err = f.refreshFromURL(ctx, now)
if err != nil {
- return "", fmt.Errorf("refreshing from url %q: %w", f.url.Redacted(), err)
+ return "", fmt.Errorf("refreshing from url %q: %w", ru, err)
}
} else {
f.logger.InfoContext(ctx, "using cached data from file", "path", f.cachePath)
@@ -213,9 +213,7 @@ func (f *Refreshable) refreshFromURL(
"code", resp.StatusCode,
"content-length", resp.ContentLength,
"server", resp.Header.Get(httphdr.Server),
- "url", &urlutil.URL{
- URL: *f.url,
- },
+ "url", urlutil.RedactUserinfo(f.url),
)
err = agdhttp.CheckStatus(resp, http.StatusOK)
diff --git a/internal/filter/internal/refreshable_test.go b/internal/filter/internal/refreshable_test.go
index a55cf65..34e4b5e 100644
--- a/internal/filter/internal/refreshable_test.go
+++ b/internal/filter/internal/refreshable_test.go
@@ -9,10 +9,10 @@ import (
"testing"
"time"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/filtertest"
"github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -221,7 +221,7 @@ func TestRefreshable_Refresh_fileURL(t *testing.T) {
c := &internal.RefreshableConfig{
Logger: slogutil.NewDiscardLogger(),
URL: &url.URL{
- Scheme: agdhttp.SchemeFile,
+ Scheme: urlutil.SchemeFile,
Path: fltFile.Name(),
},
ID: refrID,
diff --git a/internal/filter/internal/rulelist/dnsrewrite.go b/internal/filter/internal/rulelist/dnsrewrite.go
index 6f16063..e0a8267 100644
--- a/internal/filter/internal/rulelist/dnsrewrite.go
+++ b/internal/filter/internal/rulelist/dnsrewrite.go
@@ -46,8 +46,10 @@ func ProcessDNSRewrites(
}
if dnsRewriteResult.RCode != dns.RcodeSuccess {
- resp := messages.NewRespMsg(req)
- resp.Rcode = dnsRewriteResult.RCode
+ // #nosec G115 -- The value of dnsRewriteResult.RCode comes from the
+ // urlfilter package, where it either parsed by [dns.StringToRcode] or
+ // defined statically.
+ resp := messages.NewBlockedRespRCode(req, dnsmsg.RCode(dnsRewriteResult.RCode))
return &internal.ResultModifiedResponse{
Msg: resp,
@@ -115,9 +117,9 @@ func processDNSRewriteRules(dnsr []*rules.NetworkRule) (res *dnsRewriteResult) {
return dnsrr
}
-// filterDNSRewrite handles dnsrewrite filters. It constructs a DNS
-// response and returns it. dnsrr.RCode should be dns.RcodeSuccess and contain
-// a non-empty dnsrr.Response.
+// filterDNSRewrite handles dnsrewrite filters. It constructs a DNS response
+// and returns it. dnsrr.RCode should be [dns.RcodeSuccess] and contain a
+// non-empty dnsrr.Response.
func filterDNSRewrite(
messages *dnsmsg.Constructor,
req *dns.Msg,
@@ -127,7 +129,8 @@ func filterDNSRewrite(
return nil, errors.Error("no dns rewrite rule responses")
}
- resp = messages.NewRespMsg(req)
+ // TODO(e.burkov): Use another constructor method for this.
+ resp = messages.NewBlockedRespRCode(req, dns.RcodeSuccess)
rr := req.Question[0].Qtype
values := dnsrr.Response[rr]
diff --git a/internal/filter/internal/rulelist/refreshable.go b/internal/filter/internal/rulelist/refreshable.go
index 3cb9f34..cbd8b37 100644
--- a/internal/filter/internal/rulelist/refreshable.go
+++ b/internal/filter/internal/rulelist/refreshable.go
@@ -5,12 +5,13 @@ import (
"fmt"
"log/slog"
"net/netip"
+ "strings"
"sync"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist"
)
@@ -42,7 +43,7 @@ func NewRefreshable(c *internal.RefreshableConfig, cache ResultCache) (f *Refres
mu: &sync.RWMutex{},
}
- if c.URL.Scheme == agdhttp.SchemeFile {
+ if strings.EqualFold(c.URL.Scheme, urlutil.SchemeFile) {
return nil, fmt.Errorf("unsupported url %q", c.URL)
}
diff --git a/internal/filter/storage.go b/internal/filter/storage.go
index 7811ea4..597bf2a 100644
--- a/internal/filter/storage.go
+++ b/internal/filter/storage.go
@@ -8,6 +8,7 @@ import (
"net/url"
"path"
"path/filepath"
+ "slices"
"strings"
"sync"
"time"
@@ -684,7 +685,7 @@ func (s *DefaultStorage) refresh(ctx context.Context, acceptStale bool) (err err
func (s *DefaultStorage) addRuleList(
ctx context.Context,
ruleLists filteringRuleLists,
- fl *filterIndexFilterData,
+ fl *indexData,
acceptStale bool,
) {
if _, ok := ruleLists[fl.id]; ok {
@@ -741,7 +742,7 @@ func (s *DefaultStorage) addRuleList(
func (s *DefaultStorage) reportRuleListError(
ctx context.Context,
ruleLists filteringRuleLists,
- fl *filterIndexFilterData,
+ fl *indexData,
err error,
) {
errcoll.Collect(ctx, s.errColl, s.logger, "rule-list error", err)
@@ -756,22 +757,24 @@ func (s *DefaultStorage) reportRuleListError(
}
// loadIndex fetches, decodes, and returns the filter list index data of the
-// storage.
+// storage. resp.Filters are sorted.
func (s *DefaultStorage) loadIndex(
ctx context.Context,
acceptStale bool,
-) (resp *filterIndexResp, err error) {
+) (resp *indexResp, err error) {
text, err := s.refr.Refresh(ctx, acceptStale)
if err != nil {
return nil, fmt.Errorf("loading index: %w", err)
}
- resp = &filterIndexResp{}
+ resp = &indexResp{}
err = json.NewDecoder(strings.NewReader(text)).Decode(resp)
if err != nil {
return nil, fmt.Errorf("decoding: %w", err)
}
+ slices.SortStableFunc(resp.Filters, (*indexRespFilter).compare)
+
return resp, nil
}
diff --git a/internal/geoip/asntops.go b/internal/geoip/asntops.go
index 3fd1355..596ec23 100644
--- a/internal/geoip/asntops.go
+++ b/internal/geoip/asntops.go
@@ -6,10 +6,12 @@ import "github.com/AdguardTeam/golibs/container"
// DefaultTopASNs contains all specially handled ASNs.
var DefaultTopASNs = container.NewMapSet[ASN](
+ 3,
137,
174,
209,
224,
+ 376,
559,
577,
701,
@@ -21,6 +23,8 @@ var DefaultTopASNs = container.NewMapSet[ASN](
812,
852,
855,
+ 906,
+ 932,
967,
984,
1103,
@@ -36,13 +40,12 @@ var DefaultTopASNs = container.NewMapSet[ASN](
1653,
1659,
1680,
- 1741,
- 1756,
1759,
1764,
1835,
1836,
1853,
+ 1886,
1897,
1930,
1955,
@@ -52,22 +55,23 @@ var DefaultTopASNs = container.NewMapSet[ASN](
2110,
2116,
2119,
+ 2199,
2200,
+ 2470,
2497,
2514,
2516,
2518,
2519,
2527,
- 2547,
2586,
2588,
2602,
2607,
2609,
2611,
+ 2614,
2740,
- 2843,
2847,
2850,
2852,
@@ -85,10 +89,10 @@ var DefaultTopASNs = container.NewMapSet[ASN](
3243,
3249,
3255,
- 3258,
3269,
3292,
3301,
+ 3302,
3303,
3308,
3320,
@@ -98,6 +102,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
3352,
3356,
3363,
+ 3399,
3462,
3549,
3559,
@@ -107,16 +112,15 @@ var DefaultTopASNs = container.NewMapSet[ASN](
3741,
3758,
3786,
- 3790,
3816,
3855,
4007,
4134,
4181,
4230,
+ 4515,
4538,
4609,
- 4616,
4638,
4651,
4657,
@@ -140,22 +144,26 @@ var DefaultTopASNs = container.NewMapSet[ASN](
4812,
4817,
4818,
+ 4826,
4837,
4847,
5089,
+ 5377,
5378,
5384,
+ 5385,
5390,
5391,
+ 5394,
5408,
5410,
5413,
5416,
5432,
5466,
+ 5479,
5483,
5518,
- 5532,
5578,
5603,
5607,
@@ -177,6 +185,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
6327,
6400,
6407,
+ 6412,
+ 6429,
+ 6453,
6535,
6568,
6639,
@@ -191,6 +202,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
6739,
6752,
6758,
+ 6769,
6772,
6799,
6802,
@@ -215,8 +227,10 @@ var DefaultTopASNs = container.NewMapSet[ASN](
7315,
7418,
7438,
+ 7470,
7482,
7497,
+ 7511,
7522,
7524,
7545,
@@ -229,11 +243,13 @@ var DefaultTopASNs = container.NewMapSet[ASN](
7794,
7862,
7922,
+ 7979,
7992,
8014,
8048,
8053,
8075,
+ 8094,
8151,
8167,
8193,
@@ -241,7 +257,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
8220,
8251,
8257,
- 8285,
8290,
8301,
8339,
@@ -266,11 +281,11 @@ var DefaultTopASNs = container.NewMapSet[ASN](
8468,
8473,
8517,
- 8540,
8542,
8544,
8551,
8560,
+ 8562,
8585,
8612,
8632,
@@ -278,7 +293,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
8680,
8681,
8697,
- 8699,
8708,
8717,
8728,
@@ -295,7 +309,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
8849,
8866,
8881,
- 8896,
8926,
8948,
8953,
@@ -324,9 +337,8 @@ var DefaultTopASNs = container.NewMapSet[ASN](
9155,
9158,
9198,
- 9199,
+ 9208,
9231,
- 9241,
9245,
9246,
9249,
@@ -334,7 +346,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
9269,
9299,
9304,
- 9312,
9316,
9318,
9329,
@@ -345,6 +356,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
9365,
9381,
9416,
+ 9431,
9443,
9471,
9484,
@@ -358,7 +370,10 @@ var DefaultTopASNs = container.NewMapSet[ASN](
9617,
9644,
9674,
+ 9676,
+ 9694,
9751,
+ 9770,
9790,
9808,
9824,
@@ -367,29 +382,28 @@ var DefaultTopASNs = container.NewMapSet[ASN](
9873,
9902,
9908,
- 9919,
9922,
9924,
9930,
9931,
9934,
+ 9976,
9981,
9988,
10010,
10013,
10030,
10036,
+ 10054,
10066,
10075,
10094,
10099,
10101,
- 10103,
10118,
10131,
10139,
10143,
- 10214,
10219,
10222,
10226,
@@ -399,7 +413,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
10396,
10429,
10474,
- 10617,
10620,
10796,
10834,
@@ -420,7 +433,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
11492,
11556,
11562,
- 11580,
11594,
11664,
11776,
@@ -429,11 +441,11 @@ var DefaultTopASNs = container.NewMapSet[ASN](
11830,
11845,
11888,
- 11992,
12046,
12066,
12083,
12091,
+ 12150,
12252,
12271,
12297,
@@ -442,6 +454,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
12322,
12334,
12338,
+ 12350,
12353,
12361,
12365,
@@ -458,14 +471,13 @@ var DefaultTopASNs = container.NewMapSet[ASN](
12455,
12479,
12491,
- 12508,
+ 12496,
12552,
+ 12556,
12570,
12576,
12578,
- 12597,
12605,
- 12620,
12668,
12684,
12709,
@@ -477,6 +489,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
12764,
12810,
12829,
+ 12835,
12849,
12874,
12876,
@@ -484,6 +497,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
12929,
12946,
12958,
+ 12963,
12969,
12975,
12978,
@@ -501,35 +515,31 @@ var DefaultTopASNs = container.NewMapSet[ASN](
13124,
13127,
13156,
- 13170,
13188,
13189,
13194,
- 13208,
- 13213,
13280,
13285,
13306,
13335,
13489,
+ 13682,
13771,
13999,
14061,
14080,
14117,
- 14232,
14259,
14434,
14522,
- 14534,
14537,
14593,
- 14618,
14638,
14709,
14754,
14813,
14868,
+ 14956,
14979,
14988,
15146,
@@ -544,6 +554,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
15397,
15399,
15404,
+ 15405,
15419,
15433,
15435,
@@ -559,7 +570,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
15557,
15600,
15614,
- 15623,
15659,
15704,
15706,
@@ -579,7 +589,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
15958,
15962,
15964,
- 15965,
15994,
16010,
16019,
@@ -596,6 +605,8 @@ var DefaultTopASNs = container.NewMapSet[ASN](
16223,
16229,
16232,
+ 16234,
+ 16245,
16246,
16276,
16322,
@@ -623,7 +634,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
17411,
17421,
17451,
+ 17456,
17458,
+ 17465,
17470,
17480,
17488,
@@ -643,12 +656,10 @@ var DefaultTopASNs = container.NewMapSet[ASN](
17676,
17698,
17709,
- 17716,
- 17726,
17809,
17816,
17828,
- 17849,
+ 17839,
17853,
17858,
17882,
@@ -658,7 +669,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
17993,
18001,
18004,
- 18021,
+ 18013,
18024,
18049,
18053,
@@ -670,7 +681,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
18199,
18200,
18209,
- 18371,
18390,
18399,
18403,
@@ -678,6 +688,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
18419,
18429,
18734,
+ 18747,
18809,
18822,
18840,
@@ -693,6 +704,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
19626,
19711,
19863,
+ 19901,
19978,
20001,
20011,
@@ -707,22 +719,21 @@ var DefaultTopASNs = container.NewMapSet[ASN](
20473,
20485,
20545,
- 20582,
+ 20626,
20634,
20661,
- 20676,
20719,
20723,
20771,
20776,
20804,
20845,
- 20846,
20860,
20875,
20880,
20910,
20911,
+ 20928,
20940,
20963,
20978,
@@ -731,7 +742,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
21021,
21040,
21050,
+ 21056,
21107,
+ 21127,
21183,
21211,
21230,
@@ -745,6 +758,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
21351,
21412,
21430,
+ 21449,
21450,
21491,
21497,
@@ -762,11 +776,13 @@ var DefaultTopASNs = container.NewMapSet[ASN](
22047,
22069,
22085,
+ 22313,
22423,
22581,
22652,
22690,
22724,
+ 22735,
22773,
22869,
22884,
@@ -776,9 +792,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
23114,
23201,
23243,
- 23383,
23487,
23520,
+ 23563,
23655,
23657,
23673,
@@ -798,6 +814,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
23956,
23969,
24016,
+ 24033,
24086,
24088,
24157,
@@ -805,7 +822,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
24163,
24164,
24165,
- 24183,
24186,
24203,
24309,
@@ -815,7 +831,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
24400,
24432,
24439,
- 24441,
24444,
24445,
24492,
@@ -827,12 +842,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
24589,
24608,
24631,
- 24634,
- 24645,
24651,
24691,
24722,
- 24751,
24757,
24800,
24812,
@@ -846,7 +858,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
24940,
24955,
25019,
- 25094,
+ 25031,
25106,
25117,
25133,
@@ -856,35 +868,41 @@ var DefaultTopASNs = container.NewMapSet[ASN](
25159,
25184,
25190,
+ 25206,
25229,
25248,
25250,
25255,
25273,
+ 25274,
25310,
25369,
25374,
25375,
25400,
25406,
+ 25424,
25429,
25441,
25447,
25454,
- 25467,
25471,
25472,
25491,
+ 25509,
25512,
25513,
+ 25521,
25528,
25543,
25607,
25620,
25668,
+ 25695,
26130,
26210,
- 26317,
+ 26383,
+ 26523,
26599,
26611,
26615,
@@ -919,6 +937,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
27796,
27800,
27813,
+ 27828,
27831,
27833,
27837,
@@ -940,7 +959,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
27932,
27947,
27951,
- 27955,
27983,
27984,
27988,
@@ -948,20 +966,20 @@ var DefaultTopASNs = container.NewMapSet[ASN](
28006,
28009,
28015,
- 28022,
28024,
28032,
+ 28033,
28036,
28048,
- 28049,
+ 28067,
28075,
+ 28080,
28094,
28103,
28104,
28118,
28126,
28146,
- 28182,
28186,
28198,
28201,
@@ -978,7 +996,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
28509,
28512,
28530,
- 28531,
28532,
28534,
28536,
@@ -991,6 +1008,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
28598,
28649,
28668,
+ 28682,
28683,
28685,
28717,
@@ -1000,6 +1018,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
28787,
28812,
28840,
+ 28849,
28851,
28854,
28878,
@@ -1007,9 +1026,12 @@ var DefaultTopASNs = container.NewMapSet[ASN](
28885,
28919,
28952,
+ 28964,
28972,
29027,
29030,
+ 29031,
+ 29039,
29049,
29061,
29070,
@@ -1017,8 +1039,8 @@ var DefaultTopASNs = container.NewMapSet[ASN](
29091,
29119,
29124,
+ 29148,
29170,
- 29182,
29208,
29238,
29244,
@@ -1027,28 +1049,23 @@ var DefaultTopASNs = container.NewMapSet[ASN](
29286,
29310,
29314,
- 29348,
29355,
29357,
- 29384,
29405,
29447,
29465,
29485,
29492,
- 29497,
29518,
29544,
- 29545,
29555,
29571,
29580,
29582,
29584,
- 29600,
29614,
- 29657,
29687,
+ 29694,
29695,
29975,
30036,
@@ -1063,7 +1080,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
30844,
30848,
30873,
- 30896,
30982,
30983,
30985,
@@ -1084,6 +1100,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
31143,
31148,
31163,
+ 31169,
31200,
31204,
31205,
@@ -1094,24 +1111,24 @@ var DefaultTopASNs = container.NewMapSet[ASN](
31246,
31250,
31252,
+ 31257,
31272,
31287,
- 31390,
31404,
31423,
31435,
31452,
31499,
- 31510,
31543,
31549,
31615,
+ 31642,
31655,
31679,
31689,
31721,
31725,
- 31863,
+ 31726,
31898,
31960,
32020,
@@ -1137,23 +1154,22 @@ var DefaultTopASNs = container.NewMapSet[ASN](
33885,
33915,
33922,
- 33943,
- 33947,
+ 33924,
33983,
34001,
34058,
34087,
+ 34120,
34170,
34187,
34224,
34244,
34245,
+ 34263,
34295,
34296,
- 34306,
34318,
34362,
- 34376,
34447,
34458,
34471,
@@ -1164,12 +1180,14 @@ var DefaultTopASNs = container.NewMapSet[ASN](
34547,
34557,
34569,
+ 34577,
34594,
+ 34606,
+ 34636,
34661,
34666,
34700,
34702,
- 34705,
34718,
34724,
34743,
@@ -1177,40 +1195,40 @@ var DefaultTopASNs = container.NewMapSet[ASN](
34779,
34797,
34803,
- 34820,
34857,
34876,
- 34916,
- 34927,
34977,
34984,
- 34989,
+ 35007,
35046,
35047,
35091,
35104,
35132,
35141,
- 35158,
35179,
35191,
35197,
35223,
+ 35224,
35228,
35244,
+ 35277,
35297,
35311,
- 35320,
35328,
35346,
35362,
+ 35370,
+ 35394,
35432,
35444,
35457,
35518,
- 35546,
35549,
+ 35566,
35567,
+ 35568,
35612,
35613,
35699,
@@ -1221,22 +1239,20 @@ var DefaultTopASNs = container.NewMapSet[ASN](
35790,
35805,
35807,
+ 35816,
35819,
- 35892,
35900,
35911,
36290,
36408,
36511,
36549,
- 36599,
36864,
36865,
36866,
- 36868,
36873,
36874,
- 36881,
+ 36877,
36884,
36890,
36892,
@@ -1249,9 +1265,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
36912,
36913,
36914,
- 36916,
36920,
- 36923,
36924,
36925,
36926,
@@ -1261,10 +1275,8 @@ var DefaultTopASNs = container.NewMapSet[ASN](
36947,
36955,
36958,
- 36959,
36962,
36963,
- 36965,
36968,
36972,
36974,
@@ -1282,6 +1294,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37014,
37020,
37027,
+ 37028,
37030,
37035,
37037,
@@ -1295,6 +1308,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37073,
37075,
37076,
+ 37081,
37084,
37090,
37094,
@@ -1306,13 +1320,14 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37119,
37123,
37124,
+ 37126,
37129,
37133,
37136,
37141,
- 37143,
37148,
37154,
+ 37163,
37164,
37168,
37173,
@@ -1334,7 +1349,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37228,
37229,
37233,
- 37254,
37257,
37273,
37282,
@@ -1345,7 +1359,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37305,
37309,
37313,
- 37315,
37323,
37329,
37332,
@@ -1357,6 +1370,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37343,
37349,
37350,
+ 37353,
37358,
37371,
37376,
@@ -1364,9 +1378,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37395,
37406,
37410,
- 37414,
37424,
37425,
+ 37429,
37430,
37440,
37447,
@@ -1379,11 +1393,11 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37463,
37473,
37475,
- 37480,
37487,
37492,
37503,
37508,
+ 37515,
37517,
37518,
37524,
@@ -1398,9 +1412,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37552,
37559,
37563,
- 37568,
- 37569,
- 37571,
37575,
37577,
37580,
@@ -1408,6 +1419,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37584,
37594,
37604,
+ 37608,
37611,
37612,
37614,
@@ -1418,25 +1430,24 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37645,
37649,
37654,
- 37662,
37665,
37671,
- 37675,
- 37677,
37678,
37680,
37682,
37693,
- 37697,
37705,
37721,
+ 37722,
+ 37723,
+ 37731,
37963,
38009,
38067,
38077,
+ 38082,
38107,
38136,
- 38172,
38176,
38195,
38198,
@@ -1447,6 +1458,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
38247,
38264,
38266,
+ 38286,
38322,
38442,
38466,
@@ -1457,6 +1469,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
38600,
38623,
38742,
+ 38794,
38800,
38805,
38819,
@@ -1464,41 +1477,36 @@ var DefaultTopASNs = container.NewMapSet[ASN](
38851,
38875,
38901,
- 38987,
+ 38932,
38999,
39007,
39010,
- 39013,
39032,
39067,
39074,
- 39120,
- 39122,
39184,
39216,
39232,
- 39246,
- 39251,
39273,
- 39279,
39280,
39344,
+ 39351,
39374,
39397,
39402,
39440,
- 39455,
39501,
+ 39544,
+ 39571,
+ 39574,
39603,
39608,
39611,
- 39615,
39642,
39686,
39699,
- 39766,
+ 39823,
39824,
- 39826,
39891,
39906,
39927,
@@ -1506,55 +1514,58 @@ var DefaultTopASNs = container.NewMapSet[ASN](
40786,
40788,
40945,
- 40980,
+ 40994,
+ 41007,
41068,
41096,
41124,
41164,
41202,
- 41228,
41230,
+ 41280,
41329,
41330,
- 41371,
+ 41354,
41378,
+ 41436,
41454,
41496,
41549,
41557,
41563,
41564,
- 41627,
41676,
+ 41697,
41704,
+ 41712,
+ 41714,
41733,
41738,
41745,
41750,
41798,
41833,
- 41871,
41872,
- 41878,
+ 41881,
41897,
- 41922,
41956,
41966,
41997,
+ 41998,
42003,
42013,
42082,
42083,
42109,
+ 42162,
42183,
- 42189,
+ 42232,
42298,
42306,
42313,
42334,
42337,
42437,
- 42455,
42473,
42532,
42541,
@@ -1562,9 +1573,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
42571,
42580,
42581,
+ 42586,
42610,
42652,
- 42689,
42708,
42713,
42772,
@@ -1573,17 +1584,14 @@ var DefaultTopASNs = container.NewMapSet[ASN](
42837,
42841,
42863,
- 42905,
+ 42864,
42908,
42912,
42925,
42961,
42991,
43019,
- 43030,
43060,
- 43061,
- 43070,
43139,
43197,
43205,
@@ -1592,41 +1600,40 @@ var DefaultTopASNs = container.NewMapSet[ASN](
43256,
43350,
43375,
+ 43406,
43451,
43452,
43513,
43529,
43533,
+ 43568,
43612,
43627,
- 43641,
43700,
43733,
43754,
43766,
43769,
43824,
- 43883,
- 43905,
43925,
43939,
43940,
- 43972,
44021,
44027,
44034,
44086,
44087,
44090,
+ 44124,
44134,
44143,
44213,
44217,
- 44218,
44234,
44244,
- 44306,
- 44324,
+ 44272,
+ 44309,
+ 44313,
44327,
44377,
44384,
@@ -1641,22 +1648,20 @@ var DefaultTopASNs = container.NewMapSet[ASN](
44631,
44702,
44708,
- 44725,
44735,
+ 44814,
44869,
- 44925,
45090,
45102,
45143,
45177,
45178,
- 45179,
45193,
+ 45230,
45245,
45271,
45305,
45345,
- 45349,
45355,
45356,
45361,
@@ -1673,19 +1678,19 @@ var DefaultTopASNs = container.NewMapSet[ASN](
45637,
45650,
45669,
+ 45671,
45700,
45754,
45758,
45763,
45766,
45773,
+ 45780,
45879,
45891,
45899,
- 45903,
45905,
45916,
- 45918,
45925,
45935,
45960,
@@ -1693,57 +1698,58 @@ var DefaultTopASNs = container.NewMapSet[ASN](
46408,
46650,
46868,
- 47110,
47114,
+ 47132,
47139,
47159,
47169,
+ 47171,
47204,
47217,
47232,
+ 47234,
47237,
47253,
- 47292,
47331,
47377,
47394,
- 47474,
47485,
47524,
- 47583,
+ 47556,
47588,
47589,
47790,
- 47794,
47798,
+ 47881,
47883,
47887,
- 47890,
47898,
- 47943,
47956,
47962,
48014,
48092,
+ 48101,
+ 48133,
+ 48147,
48161,
- 48181,
48190,
48206,
48252,
48260,
- 48271,
48288,
+ 48359,
+ 48418,
48431,
48437,
48480,
48492,
48503,
48506,
- 48551,
+ 48602,
48629,
48675,
- 48685,
48695,
+ 48715,
48728,
48789,
48830,
@@ -1757,50 +1763,52 @@ var DefaultTopASNs = container.NewMapSet[ASN](
49056,
49100,
49101,
- 49110,
- 49113,
49115,
- 49117,
49129,
49223,
49242,
49273,
49285,
- 49472,
+ 49290,
49561,
49628,
49724,
49770,
49800,
49808,
- 49840,
- 49847,
- 49870,
+ 49824,
+ 49826,
49889,
49902,
49911,
+ 49914,
49981,
+ 49985,
50010,
50053,
50181,
+ 50195,
50223,
+ 50242,
50251,
50261,
50266,
50274,
+ 50294,
+ 50304,
50334,
50349,
+ 50411,
50463,
50467,
50482,
50500,
- 50506,
- 50563,
50581,
- 50593,
50613,
50616,
+ 50624,
50635,
+ 50648,
50670,
50685,
50749,
@@ -1809,7 +1817,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
50810,
50821,
50825,
- 50920,
50925,
50953,
50959,
@@ -1818,25 +1825,22 @@ var DefaultTopASNs = container.NewMapSet[ASN](
50979,
51018,
51020,
- 51056,
- 51069,
+ 51026,
51104,
51110,
- 51142,
51167,
51175,
51184,
51207,
- 51247,
51265,
51336,
- 51342,
51346,
51375,
+ 51395,
+ 51399,
51407,
51430,
- 51495,
- 51500,
+ 51469,
51504,
51582,
51645,
@@ -1847,10 +1851,11 @@ var DefaultTopASNs = container.NewMapSet[ASN](
51809,
51825,
51847,
- 51852,
+ 51878,
51896,
51964,
- 52075,
+ 52080,
+ 52116,
52228,
52233,
52238,
@@ -1860,8 +1865,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
52260,
52262,
52263,
- 52286,
- 52300,
52312,
52323,
52341,
@@ -1869,9 +1872,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
52362,
52363,
52373,
- 52381,
52398,
52405,
+ 52409,
52412,
52433,
52436,
@@ -1881,19 +1884,18 @@ var DefaultTopASNs = container.NewMapSet[ASN](
52468,
52471,
52613,
- 52783,
52974,
53006,
- 53338,
53667,
53764,
54198,
54614,
+ 54801,
54994,
55033,
- 55081,
55329,
55330,
+ 55387,
55391,
55392,
55424,
@@ -1901,7 +1903,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
55430,
55501,
55577,
- 55636,
55685,
55699,
55720,
@@ -1911,7 +1912,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
55836,
55850,
55853,
- 55900,
+ 55872,
55915,
55933,
55943,
@@ -1939,21 +1940,22 @@ var DefaultTopASNs = container.NewMapSet[ASN](
56329,
56349,
56369,
+ 56400,
56410,
- 56456,
56478,
- 56561,
+ 56491,
56568,
+ 56572,
56653,
56655,
56656,
56665,
56696,
56704,
+ 56803,
56902,
- 56926,
+ 56933,
56971,
- 56983,
57000,
57013,
57016,
@@ -1961,24 +1963,23 @@ var DefaultTopASNs = container.NewMapSet[ASN](
57070,
57112,
57134,
+ 57184,
57218,
- 57248,
- 57256,
+ 57223,
57269,
+ 57279,
57293,
57344,
57370,
57374,
57388,
57389,
- 57391,
57443,
+ 57491,
57513,
57564,
57566,
- 57606,
57630,
- 57695,
57728,
57743,
57760,
@@ -1986,21 +1987,17 @@ var DefaultTopASNs = container.NewMapSet[ASN](
57764,
57778,
57794,
- 57826,
57852,
57869,
+ 57873,
57888,
- 58044,
- 58056,
58061,
58065,
- 58118,
58130,
58224,
- 58254,
58299,
- 58309,
58322,
+ 58328,
58453,
58460,
58461,
@@ -2019,56 +2016,60 @@ var DefaultTopASNs = container.NewMapSet[ASN](
58717,
58731,
58821,
+ 58893,
58895,
58945,
58952,
+ 58955,
+ 59108,
59125,
- 59127,
- 59253,
59257,
59317,
59318,
59355,
59362,
- 59381,
- 59463,
+ 59441,
59497,
+ 59577,
59588,
59625,
59668,
59702,
59729,
- 59860,
+ 59847,
59861,
59890,
59989,
+ 60016,
60068,
- 60111,
- 60171,
60258,
+ 60277,
60294,
+ 60296,
+ 60304,
60352,
60367,
60372,
60377,
+ 60398,
60415,
60471,
- 60533,
60587,
60636,
60656,
60690,
60725,
- 60754,
60757,
60781,
60806,
- 60976,
+ 60849,
+ 60895,
60999,
- 61010,
+ 61071,
61079,
61112,
61135,
+ 61138,
61143,
61174,
61189,
@@ -2077,9 +2078,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
61275,
61287,
61307,
- 61317,
- 61424,
- 61437,
61449,
61461,
61466,
@@ -2091,12 +2089,14 @@ var DefaultTopASNs = container.NewMapSet[ASN](
62059,
62161,
62179,
+ 62183,
62211,
- 62214,
+ 62212,
62240,
62250,
62282,
62336,
+ 62337,
62419,
62563,
62627,
@@ -2111,16 +2111,13 @@ var DefaultTopASNs = container.NewMapSet[ASN](
63962,
63969,
63991,
- 64037,
64043,
64050,
64073,
64098,
64105,
- 64126,
64134,
64443,
- 64453,
64466,
131090,
131111,
@@ -2128,7 +2125,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
131207,
131267,
131284,
- 131322,
131325,
131429,
131445,
@@ -2139,12 +2135,12 @@ var DefaultTopASNs = container.NewMapSet[ASN](
131596,
131602,
131627,
+ 131706,
131769,
132021,
132045,
132061,
132080,
- 132104,
132148,
132165,
132167,
@@ -2155,27 +2151,25 @@ var DefaultTopASNs = container.NewMapSet[ASN](
132222,
132255,
132298,
+ 132347,
132429,
132447,
- 132449,
132462,
132468,
132471,
- 132525,
- 132608,
132618,
+ 132686,
132831,
132857,
133012,
133076,
- 133192,
133199,
133200,
- 133206,
133334,
133384,
133385,
- 133480,
+ 133401,
+ 133433,
133481,
133524,
133533,
@@ -2189,15 +2183,17 @@ var DefaultTopASNs = container.NewMapSet[ASN](
133875,
133894,
133897,
+ 133957,
133982,
134090,
134113,
134134,
134204,
- 134220,
134356,
134420,
+ 134467,
134489,
+ 134525,
134562,
134651,
134674,
@@ -2210,14 +2206,14 @@ var DefaultTopASNs = container.NewMapSet[ASN](
134762,
134768,
134783,
- 134788,
+ 134810,
134840,
- 134968,
- 134972,
134995,
135043,
+ 135069,
135126,
135298,
+ 135333,
135341,
135371,
135375,
@@ -2237,19 +2233,23 @@ var DefaultTopASNs = container.NewMapSet[ASN](
136030,
136039,
136093,
+ 136119,
136141,
136167,
+ 136168,
136195,
136210,
- 136229,
+ 136224,
136238,
136255,
- 136258,
+ 136379,
136380,
136384,
136400,
136442,
136454,
+ 136474,
+ 136477,
136479,
136480,
136515,
@@ -2259,37 +2259,43 @@ var DefaultTopASNs = container.NewMapSet[ASN](
136780,
136787,
136873,
- 136907,
136919,
- 136920,
+ 136958,
136969,
+ 136986,
136994,
137047,
137080,
137187,
- 137226,
+ 137259,
137409,
137412,
137424,
137449,
137453,
137503,
+ 137511,
137526,
+ 137549,
137561,
137693,
137697,
137872,
+ 137891,
137895,
+ 137905,
137959,
137967,
137989,
138089,
+ 138109,
138164,
138167,
138168,
138179,
138197,
138322,
+ 138345,
138346,
138368,
138384,
@@ -2302,28 +2308,25 @@ var DefaultTopASNs = container.NewMapSet[ASN](
138655,
138754,
138886,
+ 138902,
138915,
- 138934,
+ 138958,
138964,
138965,
- 138997,
139003,
139009,
139029,
139043,
- 139049,
139224,
139238,
+ 139285,
+ 139381,
139609,
- 139628,
- 139651,
- 139741,
+ 139659,
139759,
139820,
139831,
- 139837,
139841,
- 139879,
139898,
139922,
139952,
@@ -2333,19 +2336,15 @@ var DefaultTopASNs = container.NewMapSet[ASN](
140045,
140061,
140072,
- 140091,
- 140096,
140220,
140292,
140401,
- 140457,
140499,
140504,
+ 140659,
140707,
- 140867,
140900,
140989,
- 141015,
141024,
141031,
141039,
@@ -2353,7 +2352,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
141145,
141177,
141216,
- 141224,
141342,
141421,
141607,
@@ -2363,40 +2361,45 @@ var DefaultTopASNs = container.NewMapSet[ASN](
141767,
141778,
141995,
+ 142032,
142065,
142295,
- 142386,
+ 142352,
142539,
142647,
147049,
147302,
+ 147314,
149034,
149173,
149359,
149360,
149419,
149456,
- 149487,
+ 149521,
149660,
149707,
149771,
150153,
+ 150331,
150371,
- 150407,
+ 150381,
+ 150452,
150683,
150692,
- 150721,
150748,
150750,
150774,
- 150797,
+ 150812,
+ 151066,
151080,
151341,
151396,
+ 151482,
151983,
- 152140,
152317,
- 152596,
+ 152337,
+ 152466,
152605,
152677,
196640,
@@ -2414,88 +2417,81 @@ var DefaultTopASNs = container.NewMapSet[ASN](
197423,
197540,
197556,
+ 197623,
+ 197648,
197706,
- 197716,
197830,
197862,
197882,
197897,
- 198002,
198004,
198023,
- 198068,
- 198247,
198256,
198265,
198279,
198288,
198440,
+ 198441,
198471,
- 198482,
- 198499,
+ 198504,
+ 198537,
198589,
198605,
198668,
- 198820,
198890,
198961,
198966,
199081,
- 199128,
199140,
199155,
199276,
- 199326,
- 199374,
199469,
199490,
199493,
199524,
- 199620,
199636,
+ 199698,
199707,
199731,
199739,
- 199768,
199785,
199811,
+ 199995,
200019,
200134,
200154,
+ 200200,
200313,
- 200355,
200446,
200590,
200612,
- 200640,
- 200651,
- 200665,
- 200698,
+ 200628,
200724,
200736,
200740,
+ 200742,
200845,
200865,
200899,
+ 200923,
+ 200964,
201019,
201073,
201089,
+ 201096,
+ 201107,
201120,
+ 201150,
201167,
- 201187,
201241,
201249,
- 201322,
- 201363,
201411,
- 201502,
201505,
+ 201540,
201577,
201589,
- 201601,
+ 201596,
201603,
- 201701,
- 201746,
201749,
201767,
201776,
@@ -2508,6 +2504,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
202087,
202098,
202103,
+ 202204,
202254,
202293,
202422,
@@ -2515,21 +2512,19 @@ var DefaultTopASNs = container.NewMapSet[ASN](
202441,
202468,
202498,
- 202558,
202561,
202613,
+ 202616,
202618,
202632,
202635,
202651,
202662,
202710,
- 202759,
+ 202722,
202870,
202921,
- 202931,
202940,
- 202960,
202987,
203020,
203136,
@@ -2537,18 +2532,18 @@ var DefaultTopASNs = container.NewMapSet[ASN](
203214,
203217,
203257,
- 203409,
203424,
- 203448,
+ 203446,
203451,
- 203561,
203622,
203675,
203680,
- 203811,
+ 203715,
+ 203827,
203877,
203912,
203916,
+ 203917,
203936,
203953,
203964,
@@ -2558,32 +2553,35 @@ var DefaultTopASNs = container.NewMapSet[ASN](
204020,
204106,
204108,
+ 204149,
204151,
204165,
204170,
204274,
204279,
+ 204281,
204317,
- 204342,
204403,
- 204410,
+ 204429,
204457,
- 204565,
+ 204566,
+ 204592,
204595,
+ 204650,
204716,
- 204802,
- 204816,
+ 204894,
204918,
204957,
204986,
- 205015,
205110,
+ 205168,
205244,
205254,
+ 205275,
+ 205278,
205293,
- 205367,
205368,
- 205371,
+ 205516,
205547,
205638,
205645,
@@ -2596,116 +2594,129 @@ var DefaultTopASNs = container.NewMapSet[ASN](
206026,
206065,
206067,
+ 206092,
206119,
- 206170,
206206,
206238,
206260,
206262,
206283,
- 206358,
+ 206351,
206375,
- 206391,
206406,
+ 206446,
206471,
206485,
206519,
206557,
206610,
206666,
+ 206774,
206783,
206804,
206892,
- 206920,
+ 206912,
206928,
206977,
207044,
207097,
207137,
- 207159,
+ 207154,
207192,
+ 207246,
207251,
207348,
207369,
207375,
207474,
+ 207502,
+ 207541,
207569,
207589,
+ 207617,
207713,
207782,
+ 207790,
207810,
207876,
- 207980,
207990,
207991,
+ 208149,
208286,
208320,
208324,
208339,
- 208448,
208570,
208592,
208671,
208730,
208734,
- 208859,
208864,
208905,
+ 208909,
208972,
208997,
209012,
209046,
209049,
209193,
+ 209196,
209240,
209262,
+ 209273,
209277,
- 209302,
209360,
209424,
209442,
209491,
+ 209531,
209835,
209839,
209854,
209948,
+ 210001,
210003,
210016,
210021,
210022,
210125,
210147,
+ 210150,
210218,
+ 210273,
210278,
210315,
210402,
+ 210509,
210616,
210625,
210644,
210693,
210740,
- 210797,
+ 210808,
210964,
211028,
211057,
+ 211147,
+ 211196,
211210,
211211,
211235,
+ 211250,
211309,
- 211322,
211356,
- 211385,
211450,
211468,
- 211504,
- 211555,
211559,
- 211689,
+ 211774,
211908,
+ 211913,
211995,
+ 212046,
212183,
212238,
212330,
+ 212444,
212449,
212531,
212572,
@@ -2715,36 +2726,36 @@ var DefaultTopASNs = container.NewMapSet[ASN](
212645,
212655,
212661,
- 212766,
212898,
+ 212910,
212986,
212999,
- 213139,
213155,
213295,
213320,
213398,
213402,
214739,
- 214798,
+ 214869,
+ 214990,
215052,
215284,
215287,
+ 215304,
215346,
215355,
215416,
- 215421,
215423,
215501,
215540,
215733,
215746,
- 215886,
215910,
+ 215921,
216071,
216086,
216139,
- 216200,
+ 216183,
216312,
216325,
216374,
@@ -2757,8 +2768,10 @@ var DefaultTopASNs = container.NewMapSet[ASN](
262186,
262191,
262197,
+ 262199,
262202,
262210,
+ 262220,
262223,
262234,
262239,
@@ -2769,6 +2782,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
262287,
262354,
262378,
+ 262459,
262468,
262481,
262494,
@@ -2778,22 +2792,24 @@ var DefaultTopASNs = container.NewMapSet[ASN](
262773,
262916,
262932,
+ 263026,
263073,
- 263170,
+ 263175,
263210,
- 263218,
+ 263216,
263222,
263224,
263238,
263242,
263245,
+ 263248,
263292,
263327,
- 263684,
263686,
263689,
263694,
263698,
+ 263699,
263703,
263717,
263725,
@@ -2801,7 +2817,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
263750,
263751,
263759,
- 263761,
263762,
263763,
263765,
@@ -2809,6 +2824,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
263785,
263791,
263792,
+ 263793,
263805,
263824,
263980,
@@ -2816,6 +2832,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
264605,
264609,
264628,
+ 264631,
264635,
264637,
264640,
@@ -2823,47 +2840,50 @@ var DefaultTopASNs = container.NewMapSet[ASN](
264645,
264646,
264663,
- 264676,
264685,
264694,
264696,
264731,
+ 264732,
264733,
264738,
264744,
264750,
264756,
+ 264758,
264770,
264778,
264779,
264780,
264783,
- 264796,
264814,
264821,
264825,
264837,
264838,
264847,
- 264984,
265509,
265540,
265561,
265594,
265606,
- 265608,
+ 265629,
265631,
265632,
265636,
- 265641,
+ 265662,
+ 265663,
265675,
265684,
- 265688,
265691,
+ 265705,
+ 265706,
265711,
265721,
265727,
+ 265728,
265735,
+ 265749,
265757,
265767,
265780,
@@ -2872,37 +2892,36 @@ var DefaultTopASNs = container.NewMapSet[ASN](
265816,
265818,
265822,
+ 265826,
+ 265840,
265855,
265867,
266445,
266668,
266673,
- 266677,
- 266686,
- 266698,
- 266704,
- 266716,
- 266725,
+ 266694,
266734,
+ 266742,
266755,
266757,
+ 266762,
266792,
266802,
+ 266809,
266812,
266814,
266815,
+ 266831,
266841,
266853,
266858,
266860,
- 266876,
266880,
266893,
266894,
266904,
267684,
267685,
- 267692,
267699,
267705,
267708,
@@ -2910,20 +2929,25 @@ var DefaultTopASNs = container.NewMapSet[ASN](
267749,
267761,
267765,
- 267790,
267795,
+ 267796,
267797,
267803,
267809,
+ 267815,
267828,
+ 267837,
267845,
267846,
267869,
267882,
+ 267883,
+ 267896,
267904,
- 267920,
268323,
+ 268976,
269036,
+ 269194,
269729,
269730,
269733,
@@ -2932,9 +2956,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
269749,
269750,
269769,
- 269780,
269782,
269783,
+ 269794,
269797,
269804,
269806,
@@ -2945,35 +2969,35 @@ var DefaultTopASNs = container.NewMapSet[ASN](
269832,
269838,
269840,
+ 269843,
269846,
269853,
269862,
- 269878,
269894,
- 269898,
269901,
269908,
269918,
269919,
269921,
- 269926,
269927,
269931,
269934,
- 269936,
269940,
269946,
+ 269953,
269955,
269960,
269964,
269965,
+ 269973,
269976,
- 269981,
+ 269983,
269984,
+ 269986,
269989,
270007,
+ 270023,
270026,
- 270029,
270035,
270036,
270049,
@@ -2981,26 +3005,26 @@ var DefaultTopASNs = container.NewMapSet[ASN](
270058,
270068,
270071,
- 270073,
270096,
- 270098,
270108,
270158,
270161,
+ 270186,
271773,
271781,
- 271785,
271791,
271795,
- 271806,
+ 271804,
271808,
+ 271812,
271814,
- 271816,
271819,
- 271822,
271835,
+ 271837,
271868,
271874,
+ 271880,
+ 271898,
271899,
271907,
271909,
@@ -3010,92 +3034,84 @@ var DefaultTopASNs = container.NewMapSet[ASN](
271932,
271933,
271935,
+ 271936,
271942,
- 271945,
271951,
- 271962,
271965,
271971,
- 271982,
+ 271978,
+ 271996,
272011,
- 272019,
+ 272018,
272026,
272027,
272037,
+ 272057,
272059,
- 272062,
- 272065,
272083,
- 272095,
272099,
272102,
272106,
+ 272109,
272110,
272112,
272120,
272122,
- 272123,
272134,
272809,
272818,
272836,
272851,
272882,
+ 272886,
272906,
272914,
272916,
- 272921,
+ 272953,
272955,
272978,
+ 272980,
272991,
- 273000,
+ 273019,
273054,
- 273063,
273067,
- 273078,
273093,
273113,
+ 273123,
273133,
273155,
273171,
273172,
- 273231,
- 273237,
- 273309,
- 273843,
- 273844,
+ 273189,
327687,
327693,
327697,
327700,
327707,
+ 327708,
327712,
- 327714,
327716,
327724,
327728,
+ 327733,
327738,
- 327747,
327750,
327756,
327760,
327765,
- 327768,
327769,
- 327770,
+ 327771,
327776,
327782,
327786,
327794,
327795,
- 327798,
327799,
327802,
327804,
- 327814,
327819,
+ 327820,
327828,
- 327829,
327830,
327862,
327863,
@@ -3112,22 +3128,23 @@ var DefaultTopASNs = container.NewMapSet[ASN](
327941,
327972,
327975,
- 327987,
- 327990,
327991,
327992,
- 328001,
+ 327996,
328061,
328068,
328073,
+ 328075,
328079,
328088,
328111,
- 328118,
328136,
328140,
+ 328146,
+ 328154,
328169,
328181,
+ 328182,
328191,
328196,
328198,
@@ -3137,17 +3154,15 @@ var DefaultTopASNs = container.NewMapSet[ASN](
328228,
328250,
328253,
- 328258,
- 328282,
+ 328269,
328284,
328286,
328297,
- 328304,
- 328310,
- 328316,
+ 328317,
328319,
328331,
328341,
+ 328344,
328358,
328411,
328436,
@@ -3156,25 +3171,26 @@ var DefaultTopASNs = container.NewMapSet[ASN](
328469,
328471,
328473,
+ 328475,
328479,
328480,
328488,
328490,
328494,
+ 328509,
328510,
328514,
- 328517,
328535,
328539,
328546,
328549,
+ 328567,
328570,
+ 328576,
328581,
328586,
328590,
328594,
- 328600,
- 328604,
328605,
328610,
328611,
@@ -3189,27 +3205,20 @@ var DefaultTopASNs = container.NewMapSet[ASN](
328708,
328717,
328727,
+ 328733,
328734,
- 328753,
+ 328743,
328755,
- 328770,
- 328777,
328817,
- 328824,
- 328835,
328844,
328849,
- 328850,
328856,
- 328857,
328858,
328880,
328895,
328899,
328923,
- 328939,
328943,
- 328950,
328954,
328959,
328961,
@@ -3223,45 +3232,45 @@ var DefaultTopASNs = container.NewMapSet[ASN](
328997,
329006,
329014,
+ 329020,
+ 329021,
329027,
- 329028,
329029,
329044,
- 329048,
+ 329074,
329078,
329082,
329101,
- 329103,
- 329126,
329129,
329135,
- 329155,
329167,
329169,
329170,
+ 329174,
329179,
329183,
329192,
329205,
329211,
329219,
+ 329220,
329227,
329253,
329254,
- 329255,
329261,
329274,
+ 329286,
329301,
- 329373,
329387,
329390,
- 329411,
+ 329413,
329415,
329422,
329437,
329472,
393275,
393629,
+ 393894,
394311,
394381,
394684,
@@ -3277,10 +3286,8 @@ var DefaultTopASNs = container.NewMapSet[ASN](
398228,
398721,
398901,
- 399444,
399498,
399724,
- 400099,
400619,
)
@@ -3291,8 +3298,8 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryAF: 55330,
CountryAG: 11594,
CountryAI: 396304,
- CountryAL: 50616,
- CountryAM: 44395,
+ CountryAL: 50973,
+ CountryAM: 43733,
CountryAO: 37119,
CountryAQ: 199707,
CountryAR: 7303,
@@ -3310,7 +3317,7 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryBG: 8866,
CountryBH: 5416,
CountryBI: 327799,
- CountryBJ: 328228,
+ CountryBJ: 37424,
CountryBM: 32020,
CountryBN: 10094,
CountryBO: 6568,
@@ -3323,31 +3330,32 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryBZ: 10269,
CountryCA: 812,
CountryCD: 37020,
- CountryCF: 328079,
+ CountryCF: 37460,
CountryCG: 36924,
CountryCH: 6730,
CountryCI: 29571,
CountryCK: 10131,
CountryCL: 27651,
- CountryCM: 30992,
+ CountryCM: 36912,
CountryCN: 4134,
CountryCO: 27831,
CountryCR: 52263,
CountryCU: 27725,
CountryCV: 37517,
- CountryCW: 11081,
+ CountryCW: 52233,
CountryCY: 6866,
CountryCZ: 5610,
CountryDE: 3320,
CountryDJ: 30990,
- CountryDK: 212238,
+ CountryDK: 13335,
CountryDM: 40945,
CountryDO: 6400,
CountryDZ: 36947,
CountryEC: 27947,
CountryEE: 3249,
CountryEG: 8452,
- CountryER: 212238,
+ CountryEH: 6713,
+ CountryER: 24757,
CountryES: 3352,
CountryET: 24757,
CountryFI: 51765,
@@ -3362,11 +3370,11 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryGF: 16028,
CountryGG: 8680,
CountryGH: 30986,
- CountryGI: 8301,
+ CountryGI: 202087,
CountryGL: 8818,
CountryGM: 37552,
CountryGN: 37461,
- CountryGP: 3215,
+ CountryGP: 16028,
CountryGQ: 37173,
CountryGR: 6799,
CountryGT: 14754,
@@ -3376,17 +3384,17 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryHK: 4760,
CountryHN: 14754,
CountryHR: 5391,
- CountryHT: 52260,
+ CountryHT: 27653,
CountryHU: 5483,
CountryID: 7713,
CountryIE: 15502,
- CountryIL: 1680,
+ CountryIL: 12400,
CountryIM: 13122,
CountryIN: 55836,
CountryIO: 17458,
CountryIQ: 203214,
CountryIR: 197207,
- CountryIS: 44735,
+ CountryIS: 56704,
CountryIT: 1267,
CountryJE: 8680,
CountryJM: 30689,
@@ -3395,20 +3403,20 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryKE: 33771,
CountryKG: 47237,
CountryKH: 38623,
- CountryKI: 134783,
- CountryKM: 328061,
+ CountryKI: 135409,
+ CountryKM: 36939,
CountryKN: 11139,
CountryKR: 4766,
CountryKW: 29357,
CountryKY: 6639,
CountryKZ: 206026,
CountryLA: 9873,
- CountryLB: 42003,
+ CountryLB: 38999,
CountryLC: 15344,
CountryLI: 136787,
CountryLK: 18001,
CountryLR: 37410,
- CountryLS: 37057,
+ CountryLS: 33567,
CountryLT: 8764,
CountryLU: 6661,
CountryLV: 24921,
@@ -3417,7 +3425,7 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryMC: 6758,
CountryMD: 8926,
CountryME: 43940,
- CountryMF: 14593,
+ CountryMF: 33392,
CountryMG: 37054,
CountryMH: 24439,
CountryMK: 6821,
@@ -3426,9 +3434,9 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryMN: 17882,
CountryMO: 4609,
CountryMP: 7131,
- CountryMQ: 3215,
+ CountryMQ: 20776,
CountryMR: 29544,
- CountryMS: 396304,
+ CountryMS: 11139,
CountryMT: 12709,
CountryMU: 23889,
CountryMV: 7642,
@@ -3436,15 +3444,16 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryMX: 8151,
CountryMY: 4788,
CountryMZ: 37342,
- CountryNA: 37009,
- CountryNC: 18200,
- CountryNE: 37531,
+ CountryNA: 36996,
+ CountryNC: 17480,
+ CountryNE: 37233,
CountryNG: 29465,
CountryNI: 14754,
CountryNL: 1136,
CountryNO: 9009,
CountryNP: 17501,
CountryNR: 140504,
+ CountryNU: 198605,
CountryNZ: 9790,
CountryOM: 28885,
CountryPA: 11556,
@@ -3455,12 +3464,12 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryPK: 45669,
CountryPL: 5617,
CountryPM: 3695,
- CountryPR: 14638,
+ CountryPR: 21928,
CountryPS: 12975,
CountryPT: 12353,
CountryPW: 17893,
CountryPY: 23201,
- CountryQA: 42298,
+ CountryQA: 8781,
CountryRE: 199140,
CountryRO: 8708,
CountryRS: 8400,
@@ -3468,19 +3477,19 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryRW: 36890,
CountrySA: 39891,
CountrySB: 45891,
- CountrySC: 131464,
+ CountrySC: 36958,
CountrySD: 15706,
CountrySE: 13335,
CountrySG: 4773,
- CountrySH: 198605,
- CountrySI: 5603,
+ CountrySH: 37645,
+ CountrySI: 3212,
CountrySK: 6855,
CountrySL: 37164,
CountrySM: 15433,
CountrySN: 8346,
CountrySO: 37371,
CountrySR: 27775,
- CountrySS: 328755,
+ CountrySS: 37594,
CountryST: 328191,
CountrySV: 14754,
CountrySX: 27781,
@@ -3498,19 +3507,19 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryTR: 47331,
CountryTT: 27800,
CountryTW: 3462,
- CountryTZ: 36908,
+ CountryTZ: 37035,
CountryUA: 15895,
CountryUG: 37075,
- CountryUS: 21928,
+ CountryUS: 7922,
CountryUY: 6057,
CountryUZ: 8193,
CountryVA: 8978,
CountryVC: 46408,
CountryVE: 8048,
- CountryVG: 11139,
+ CountryVG: 396357,
CountryVI: 14434,
CountryVN: 7552,
- CountryVU: 9249,
+ CountryVU: 132429,
CountryWF: 45879,
CountryWS: 38800,
CountryXK: 21246,
@@ -3518,5 +3527,5 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryYT: 3215,
CountryZA: 37457,
CountryZM: 37287,
- CountryZW: 56696,
+ CountryZW: 37204,
}
diff --git a/internal/geoip/asntops_generate.go b/internal/geoip/asntops_generate.go
index 6b08537..d1a70bc 100644
--- a/internal/geoip/asntops_generate.go
+++ b/internal/geoip/asntops_generate.go
@@ -13,6 +13,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/osutil"
@@ -27,22 +28,22 @@ func main() {
Timeout: 10 * time.Second,
}
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, countriesASNURL, nil)
- check(err)
+ req := errors.Must(http.NewRequestWithContext(ctx, http.MethodGet, countriesASNURL, nil))
req.Header.Add(httphdr.UserAgent, agdhttp.UserAgent())
- resp, err := c.Do(req)
- check(err)
+ resp := errors.Must(c.Do(req))
defer slogutil.CloseAndLog(ctx, logger, resp.Body, slog.LevelError)
- out, err := os.OpenFile("./asntops.go", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o664)
- check(err)
+ err := agdhttp.CheckStatus(resp, http.StatusOK)
+ errors.Check(err)
+
+ out := errors.Must(os.OpenFile("./asntops.go", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o664))
defer slogutil.CloseAndLog(ctx, logger, out, slog.LevelError)
defaultCountryTopASNs := map[geoip.Country][]geoip.ASN{}
err = json.NewDecoder(resp.Body).Decode(&defaultCountryTopASNs)
- check(err)
+ errors.Check(err)
// Don't use a *container.MapSet here, because the map is iterated over in
// the template.
@@ -65,11 +66,10 @@ func main() {
DefaultCountryTopASNs: defaultCountryTopASNs,
}
- tmpl, err := template.New("main").Parse(tmplStr)
- check(err)
+ tmpl := template.Must(template.New("main").Parse(tmplStr))
err = tmpl.Execute(out, tmplData)
- check(err)
+ errors.Check(err)
}
// countriesASNURL is the default URL to get the per-country top ASN statistics
@@ -101,10 +101,3 @@ var DefaultCountryTopASNs = map[Country]ASN{
{{- end }}
}
`
-
-// check is a simple error checker.
-func check(err error) {
- if err != nil {
- panic(err)
- }
-}
diff --git a/internal/geoip/country.go b/internal/geoip/country.go
index a095cf3..21a198c 100644
--- a/internal/geoip/country.go
+++ b/internal/geoip/country.go
@@ -9,8 +9,6 @@ import (
"github.com/AdguardTeam/golibs/errors"
)
-// Country Codes
-
// Country represents an ISO 3166-1 alpha-2 country code.
type Country string
diff --git a/internal/geoip/country_generate.go b/internal/geoip/country_generate.go
index 97c2bf9..3601699 100644
--- a/internal/geoip/country_generate.go
+++ b/internal/geoip/country_generate.go
@@ -14,6 +14,7 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/osutil"
@@ -28,22 +29,18 @@ func main() {
Timeout: 10 * time.Second,
}
- req, err := http.NewRequest(http.MethodGet, csvURL, nil)
- check(err)
+ req := errors.Must(http.NewRequest(http.MethodGet, csvURL, nil))
req.Header.Add(httphdr.UserAgent, agdhttp.UserAgent())
- resp, err := c.Do(req)
- check(err)
+ resp := errors.Must(c.Do(req))
defer slogutil.CloseAndLog(ctx, logger, resp.Body, slog.LevelError)
- out, err := os.OpenFile("./country.go", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o664)
- check(err)
+ out := errors.Must(os.OpenFile("./country.go", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o664))
defer slogutil.CloseAndLog(ctx, logger, out, slog.LevelError)
r := csv.NewReader(resp.Body)
- rows, err := r.ReadAll()
- check(err)
+ rows := errors.Must(r.ReadAll())
// Skip the first row, as it is a header.
rows = rows[1:]
@@ -54,11 +51,10 @@ func main() {
return strings.Compare(a[1], b[1])
})
- tmpl, err := template.New("main").Parse(tmplStr)
- check(err)
+ tmpl := template.Must(template.New("main").Parse(tmplStr))
- err = tmpl.Execute(out, rows)
- check(err)
+ err := tmpl.Execute(out, rows)
+ errors.Check(err)
}
// csvURL is the default URL of the information about country codes.
@@ -76,8 +72,6 @@ import (
"github.com/AdguardTeam/golibs/errors"
)
-// Country Codes
-
// Country represents an ISO 3166-1 alpha-2 country code.
type Country string
@@ -165,10 +159,3 @@ func isUserAssigned(s string) (ok bool) {
}
}
`
-
-// check is a simple error checker.
-func check(err error) {
- if err != nil {
- panic(err)
- }
-}
diff --git a/internal/metrics/consul.go b/internal/metrics/consul.go
index d7f45d7..57ef5e4 100644
--- a/internal/metrics/consul.go
+++ b/internal/metrics/consul.go
@@ -1,33 +1,109 @@
package metrics
import (
+ "context"
+ "fmt"
+
+ "github.com/AdguardTeam/golibs/container"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/promauto"
)
-var (
- // ConsulAllowlistSize is a gauge with the number of records in the
- // ratelimit allowlist loaded from Consul.
- ConsulAllowlistSize = promauto.NewGauge(prometheus.GaugeOpts{
- Subsystem: subsystemConsul,
- Namespace: namespace,
- Name: "allowlist_size",
- Help: "Size of the ratelimit allowlist loaded from Consul.",
- })
- // ConsulAllowlistUpdateStatus is a gauge with the status of the last
- // ratelimit allowlist update. 1 means success.
- ConsulAllowlistUpdateStatus = promauto.NewGauge(prometheus.GaugeOpts{
- Subsystem: subsystemConsul,
- Namespace: namespace,
- Name: "allowlist_update_status",
- Help: "Status of the last ratelimit allowlist update. 1 means success.",
- })
- // ConsulAllowlistUpdateTime is a gauge with the timestamp of the last
- // ratelimit allowlist update.
- ConsulAllowlistUpdateTime = promauto.NewGauge(prometheus.GaugeOpts{
- Subsystem: subsystemConsul,
- Namespace: namespace,
- Name: "allowlist_update_timestamp",
- Help: "Timestamp of the last ratelimit allowlist update.",
- })
-)
+// Allowlist is the Prometheus-based implementation of the [consul.Metrics]
+// interface.
+type Allowlist struct {
+ // size is a gauge with the number of loaded records in the ratelimit
+ // allowlist.
+ size prometheus.Gauge
+
+ // updateStatus is a gauge with the status of the last ratelimit allowlist
+ // update. 1 means success.
+ updateStatus prometheus.Gauge
+
+ // updateTime is a gauge with the timestamp of the last ratelimit allowlist
+ // update.
+ updateTime prometheus.Gauge
+}
+
+// NewAllowlist registers the Consul allowlist metrics in reg and returns a
+// properly initialized [Allowlist].
+func NewAllowlist(
+ namespace string,
+ reg prometheus.Registerer,
+ typ string,
+) (m *Allowlist, err error) {
+ switch typ {
+ case subsystemBackend, subsystemConsul:
+ // Go on.
+ default:
+ return nil, fmt.Errorf("subsystem: %w: %q", errors.ErrBadEnumValue, typ)
+ }
+
+ const (
+ size = "allowlist_size"
+ updateStatus = "allowlist_update_status"
+ updateTime = "allowlist_update_timestamp"
+ )
+
+ labels := prometheus.Labels{"type": typ}
+
+ m = &Allowlist{
+ size: prometheus.NewGauge(prometheus.GaugeOpts{
+ Subsystem: subsystemRateLimit,
+ Namespace: namespace,
+ Name: size,
+ Help: "Size of the loaded ratelimit allowlist.",
+ ConstLabels: labels,
+ }),
+ updateStatus: prometheus.NewGauge(prometheus.GaugeOpts{
+ Subsystem: subsystemRateLimit,
+ Namespace: namespace,
+ Name: updateStatus,
+ Help: "Status of the last ratelimit allowlist update. 1 means success.",
+ ConstLabels: labels,
+ }),
+ updateTime: prometheus.NewGauge(prometheus.GaugeOpts{
+ Subsystem: subsystemRateLimit,
+ Namespace: namespace,
+ Name: updateTime,
+ Help: "Timestamp of the last ratelimit allowlist update.",
+ ConstLabels: labels,
+ }),
+ }
+
+ var errs []error
+ collectors := container.KeyValues[string, prometheus.Collector]{{
+ Key: size,
+ Value: m.size,
+ }, {
+ Key: updateStatus,
+ Value: m.updateStatus,
+ }, {
+ Key: updateTime,
+ Value: m.updateTime,
+ }}
+
+ for _, c := range collectors {
+ err = reg.Register(c.Value)
+ if err != nil {
+ errs = append(errs, fmt.Errorf("registering metrics %q: %w", c.Key, err))
+ }
+ }
+
+ if err = errors.Join(errs...); err != nil {
+ return nil, err
+ }
+
+ return m, nil
+}
+
+// SetSize implements the [consul.Metrics] interface for *Allowlist.
+func (m *Allowlist) SetSize(_ context.Context, n int) {
+ m.size.Set(float64(n))
+}
+
+// SetStatus implements the [consul.Metrics] interface for *Allowlist.
+func (m *Allowlist) SetStatus(_ context.Context, err error) {
+ m.updateTime.SetToCurrentTime()
+ SetStatusGauge(m.updateStatus, err)
+}
diff --git a/internal/metrics/metrics_test.go b/internal/metrics/metrics_test.go
index 18f79eb..0a50d9c 100644
--- a/internal/metrics/metrics_test.go
+++ b/internal/metrics/metrics_test.go
@@ -3,11 +3,13 @@ package metrics_test
import (
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
"github.com/AdguardTeam/AdGuardDNS/internal/billstat"
+ "github.com/AdguardTeam/AdGuardDNS/internal/consul"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
"github.com/AdguardTeam/AdGuardDNS/internal/remotekv/rediskv"
+ "github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
)
// type check
@@ -17,6 +19,7 @@ import (
var (
_ backendpb.Metrics = (*metrics.BackendPB)(nil)
_ billstat.Metrics = (*metrics.Billstat)(nil)
+ _ consul.Metrics = (*metrics.Allowlist)(nil)
_ dnsmsg.ClonerStat = metrics.ClonerStat{}
_ dnssvc.MainMiddlewareMetrics = (*metrics.DefaultMainMiddleware)(nil)
_ dnssvc.MainMiddlewareMetrics = metrics.MainMiddleware(nil)
@@ -24,4 +27,5 @@ var (
_ dnssvc.RatelimitMiddlewareMetrics = metrics.RatelimitMiddleware(nil)
_ profiledb.Metrics = (*metrics.ProfileDB)(nil)
_ rediskv.Metrics = (*metrics.RedisKV)(nil)
+ _ tlsconfig.Metrics = (*metrics.TLSConfig)(nil)
)
diff --git a/internal/metrics/tls.go b/internal/metrics/tls.go
index 3001dd7..e38d2b8 100644
--- a/internal/metrics/tls.go
+++ b/internal/metrics/tls.go
@@ -1,112 +1,148 @@
package metrics
import (
+ "context"
"crypto/tls"
"fmt"
"slices"
"strings"
+ "time"
+ "github.com/AdguardTeam/golibs/container"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/promauto"
)
-var (
- // TLSCertificateInfo is a gauge with the authentication algorithm of
- // the certificate.
- TLSCertificateInfo = promauto.NewGaugeVec(prometheus.GaugeOpts{
- Name: "cert_info",
- Namespace: namespace,
- Subsystem: subsystemTLS,
- Help: "Authentication algorithm and other information about the certificate.",
- }, []string{"auth_algo", "subject"})
+// TLSConfig is the Prometheus-based implementation of the [tlsconfig.Metrics]
+// interface.
+type TLSConfig struct {
+ // certificateInfo is a gauge with the authentication algorithm of the
+ // certificate.
+ certificateInfo *prometheus.GaugeVec
- // TLSCertificateNotAfter is a gauge with the time when the certificate
+ // certificateNotAfter is a gauge with the time when the certificate
// expires.
- TLSCertificateNotAfter = promauto.NewGaugeVec(prometheus.GaugeOpts{
- Name: "cert_not_after",
- Namespace: namespace,
- Subsystem: subsystemTLS,
- Help: "Time when the certificate expires.",
- }, []string{"subject"})
+ certificateNotAfter *prometheus.GaugeVec
- // TLSSessionTicketsRotateStatus is a gauge with the status of the last
- // tickets rotation.
- TLSSessionTicketsRotateStatus = promauto.NewGauge(prometheus.GaugeOpts{
- Name: "session_tickets_rotate_status",
- Namespace: namespace,
- Subsystem: subsystemTLS,
- Help: "Status of the last tickets rotation.",
- })
- // TLSSessionTicketsRotateTime is a gauge with the time when the TLS session
+ // sessionTicketsRotateStatus is a gauge with the status of the last tickets
+ // rotation.
+ sessionTicketsRotateStatus prometheus.Gauge
+
+ // sessionTicketsRotateTime is a gauge with the time when the TLS session
// tickets were rotated.
- TLSSessionTicketsRotateTime = promauto.NewGauge(prometheus.GaugeOpts{
- Name: "session_tickets_rotate_time",
- Namespace: namespace,
- Subsystem: subsystemTLS,
- Help: "Time when the TLS session tickets were rotated.",
- })
- // TLSHandshakeAttemptsTotal is a counter with the total number of attempts
- // to establish a TLS connection. "supported_protos" is a comma-separated
- // list of the protocols supported by the client.
- TLSHandshakeAttemptsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
- Name: "handshake_attempts_total",
- Namespace: namespace,
- Subsystem: subsystemTLS,
- Help: "Total count of TLS handshakes.",
- }, []string{
- "proto",
- "supported_protos",
- "tls_version",
- })
- // TLSHandshakeTotal is a counter with the total count of TLS handshakes.
- TLSHandshakeTotal = promauto.NewCounterVec(prometheus.CounterOpts{
- Name: "handshake_total",
- Namespace: namespace,
- Subsystem: subsystemTLS,
- Help: "Total count of TLS handshakes.",
- }, []string{
- "proto",
- "tls_version",
- "did_resume",
- "cipher_suite",
- "negotiated_proto",
- "server_name",
- })
-)
+ sessionTicketsRotateTime prometheus.Gauge
-// TLSMetricsAfterHandshake is a function that needs to be passed to
-// *tls.Config VerifyConnection.
-func TLSMetricsAfterHandshake(
- proto string,
- srvName string,
- devDomains []string,
- srvCerts []tls.Certificate,
-) (f func(tls.ConnectionState) error) {
- return func(state tls.ConnectionState) error {
- sLabel := serverNameToLabel(state.ServerName, srvName, devDomains, srvCerts)
+ // handshakeAttemptsTotal is a counter with the total number of attempts to
+ // establish a TLS connection. "supported_protos" is a comma-separated list
+ // of the protocols supported by the client.
+ handshakeAttemptsTotal *prometheus.CounterVec
- // Stick to using WithLabelValues instead of With in order to avoid
- // extra allocations on prometheus.Labels. The labels order is VERY
- // important here.
- TLSHandshakeTotal.WithLabelValues(
- proto,
- tlsVersionToString(state.Version),
- BoolString(state.DidResume),
- tls.CipherSuiteName(state.CipherSuite),
- // Don't validate the negotiated protocol since it's expected to
- // contain only ASCII after negotiation itself.
- state.NegotiatedProtocol,
- sLabel,
- ).Inc()
-
- return nil
- }
+ // handshakeTotal is a counter with the total count of TLS handshakes.
+ handshakeTotal *prometheus.CounterVec
}
-// TLSMetricsBeforeHandshake is a function that needs to be passed to
-// *tls.Config GetConfigForClient.
-func TLSMetricsBeforeHandshake(proto string) (f func(*tls.ClientHelloInfo) (*tls.Config, error)) {
+// NewTLSConfig registers the TLS related metrics in reg and returns a properly
+// initialized [TLSConfig].
+func NewTLSConfig(namespace string, reg prometheus.Registerer) (m *TLSConfig, err error) {
+ const (
+ certInfo = "cert_info"
+ certNotAfter = "cert_not_after"
+ sessTicketsRotateStatus = "session_tickets_rotate_status"
+ sessTicketsRotateTime = "session_tickets_rotate_time"
+ handshakeAttemptsTotal = "handshake_attempts_total"
+ handshakeTotal = "handshake_total"
+ )
+
+ m = &TLSConfig{
+ certificateInfo: prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Name: certInfo,
+ Namespace: namespace,
+ Subsystem: subsystemTLS,
+ Help: "Authentication algorithm and other information about the certificate.",
+ }, []string{"auth_algo", "subject"}),
+ certificateNotAfter: prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Name: certNotAfter,
+ Namespace: namespace,
+ Subsystem: subsystemTLS,
+ Help: "Time when the certificate expires.",
+ }, []string{"subject"}),
+ sessionTicketsRotateStatus: prometheus.NewGauge(prometheus.GaugeOpts{
+ Name: sessTicketsRotateStatus,
+ Namespace: namespace,
+ Subsystem: subsystemTLS,
+ Help: "Status of the last tickets rotation.",
+ }),
+ sessionTicketsRotateTime: prometheus.NewGauge(prometheus.GaugeOpts{
+ Name: sessTicketsRotateTime,
+ Namespace: namespace,
+ Subsystem: subsystemTLS,
+ Help: "Time when the TLS session tickets were rotated.",
+ }),
+ handshakeAttemptsTotal: prometheus.NewCounterVec(prometheus.CounterOpts{
+ Name: handshakeAttemptsTotal,
+ Namespace: namespace,
+ Subsystem: subsystemTLS,
+ Help: "Total count of TLS handshakes.",
+ }, []string{
+ "proto",
+ "supported_protos",
+ "tls_version",
+ }),
+ handshakeTotal: prometheus.NewCounterVec(prometheus.CounterOpts{
+ Name: handshakeTotal,
+ Namespace: namespace,
+ Subsystem: subsystemTLS,
+ Help: "Total count of TLS handshakes.",
+ }, []string{
+ "proto",
+ "tls_version",
+ "did_resume",
+ "cipher_suite",
+ "negotiated_proto",
+ "server_name",
+ }),
+ }
+
+ var errs []error
+ collectors := container.KeyValues[string, prometheus.Collector]{{
+ Key: certInfo,
+ Value: m.certificateInfo,
+ }, {
+ Key: certNotAfter,
+ Value: m.certificateNotAfter,
+ }, {
+ Key: sessTicketsRotateStatus,
+ Value: m.sessionTicketsRotateStatus,
+ }, {
+ Key: sessTicketsRotateTime,
+ Value: m.sessionTicketsRotateTime,
+ }, {
+ Key: handshakeAttemptsTotal,
+ Value: m.handshakeAttemptsTotal,
+ }, {
+ Key: handshakeTotal,
+ Value: m.handshakeTotal,
+ }}
+
+ for _, c := range collectors {
+ err = reg.Register(c.Value)
+ if err != nil {
+ errs = append(errs, fmt.Errorf("registering metrics %q: %w", c.Key, err))
+ }
+ }
+
+ if err = errors.Join(errs...); err != nil {
+ return nil, err
+ }
+
+ return m, nil
+}
+
+// BeforeHandshake implements the [tlsconfig.Metrics] interface for *TLSConfig.
+func (m *TLSConfig) BeforeHandshake(
+ proto string,
+) (f func(*tls.ClientHelloInfo) (*tls.Config, error)) {
return func(info *tls.ClientHelloInfo) (*tls.Config, error) {
var maxVersion uint16
if len(info.SupportedVersions) > 0 {
@@ -121,7 +157,7 @@ func TLSMetricsBeforeHandshake(proto string) (f func(*tls.ClientHelloInfo) (*tls
// Stick to using WithLabelValues instead of With in order to avoid
// extra allocations on prometheus.Labels. The labels order is VERY
// important here.
- TLSHandshakeAttemptsTotal.WithLabelValues(
+ m.handshakeAttemptsTotal.WithLabelValues(
proto,
strings.Join(supProtos, ","),
tlsVersionToString(maxVersion),
@@ -131,6 +167,60 @@ func TLSMetricsBeforeHandshake(proto string) (f func(*tls.ClientHelloInfo) (*tls
}
}
+// AfterHandshake implements the [tlsconfig.Metrics] interface for *TLSConfig.
+func (m *TLSConfig) AfterHandshake(
+ proto string,
+ srvName string,
+ devDomains []string,
+ srvCerts []tls.Certificate,
+) (f func(tls.ConnectionState) error) {
+ return func(state tls.ConnectionState) error {
+ sLabel := serverNameToLabel(state.ServerName, srvName, devDomains, srvCerts)
+
+ // Stick to using WithLabelValues instead of With in order to avoid
+ // extra allocations on prometheus.Labels. The labels order is VERY
+ // important here.
+ m.handshakeTotal.WithLabelValues(
+ proto,
+ tlsVersionToString(state.Version),
+ BoolString(state.DidResume),
+ tls.CipherSuiteName(state.CipherSuite),
+ // Don't validate the negotiated protocol since it's expected to
+ // contain only ASCII after negotiation itself.
+ state.NegotiatedProtocol,
+ sLabel,
+ ).Inc()
+
+ return nil
+ }
+}
+
+// SetCertificateInfo implements the [tlsconfig.Metrics] interface for
+// *TLSConfig.
+func (m *TLSConfig) SetCertificateInfo(_ context.Context, algo, subj string, notAfter time.Time) {
+ m.certificateInfo.With(prometheus.Labels{
+ "auth_algo": algo,
+ "subject": subj,
+ }).Set(1)
+
+ m.certificateNotAfter.With(prometheus.Labels{
+ "subject": subj,
+ }).Set(float64(notAfter.Unix()))
+}
+
+// SetSessionTicketRotationStatus implements the [tlsconfig.Metrics] interface
+// for *TLSConfig.
+func (m *TLSConfig) SetSessionTicketRotationStatus(_ context.Context, enabled bool) {
+ if !enabled {
+ m.sessionTicketsRotateStatus.Set(0)
+
+ return
+ }
+
+ m.sessionTicketsRotateStatus.Set(1)
+ m.sessionTicketsRotateTime.SetToCurrentTime()
+}
+
// tlsVersionToString converts TLS version to string.
func tlsVersionToString(ver uint16) (tlsVersion string) {
switch ver {
diff --git a/internal/metrics/tls_test.go b/internal/metrics/tls_test.go
index 6eb7d1f..6f4c042 100644
--- a/internal/metrics/tls_test.go
+++ b/internal/metrics/tls_test.go
@@ -12,7 +12,12 @@ import (
"github.com/stretchr/testify/require"
)
-func TestTLSMetricsAfterHandshake(t *testing.T) {
+func TestTLSConfig_AfterHandshake(t *testing.T) {
+ // TODO(s.chzhen): Consider using [agdtest.PrometheusRegisterer].
+ reg := prometheus.NewRegistry()
+ m, err := metrics.NewTLSConfig(metrics.Namespace(), reg)
+ require.NoError(t, err)
+
serverName := "test_server"
devDomains := []string{"d.adguard-dns.com"}
dnsNames := []string{
@@ -87,18 +92,19 @@ func TestTLSMetricsAfterHandshake(t *testing.T) {
cert := tls.Certificate{Leaf: &x509Cert}
- listener := metrics.TLSMetricsAfterHandshake(
+ listener := m.AfterHandshake(
"",
serverName,
tc.devDomains,
[]tls.Certificate{cert},
)
- err := listener(tls.ConnectionState{ServerName: tc.connectionServerName})
+ err = listener(tls.ConnectionState{ServerName: tc.connectionServerName})
require.NoError(t, err)
- metricFamilies, err := prometheus.DefaultGatherer.Gather()
+ var metricFamilies []*io_prometheus_client.MetricFamily
+ metricFamilies, err = reg.Gather()
require.NoError(t, err)
require.NotNil(t, metricFamilies)
@@ -140,11 +146,14 @@ func findLabel(ms []*io_prometheus_client.Metric, label string) (ok bool) {
return false
}
-func TestTLSMetricsBeforeHandshake(t *testing.T) {
- f := metrics.TLSMetricsBeforeHandshake("srv-name")
+func TestTLSConfig_BeforeHandshake(t *testing.T) {
+ reg := prometheus.NewRegistry()
+ m, err := metrics.NewTLSConfig(metrics.Namespace(), reg)
+ require.NoError(t, err)
+
+ f := m.BeforeHandshake("srv-name")
var conf *tls.Config
- var err error
require.NotPanics(t, func() {
conf, err = f(&tls.ClientHelloInfo{
SupportedProtos: []string{"\xC0\xC1\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"},
diff --git a/internal/optlog/optlog.go b/internal/optlog/optlog.go
index 3884f5f..8f03e90 100644
--- a/internal/optlog/optlog.go
+++ b/internal/optlog/optlog.go
@@ -7,37 +7,9 @@ import (
"github.com/AdguardTeam/golibs/log"
)
-// Debug1 is an ugly hack to prevent [log.Debug] from allocating.
-func Debug1[T1 any](msg string, arg1 T1) {
- if log.GetLevel() >= log.DEBUG {
- log.Debug(msg, arg1)
- }
-}
-
-// Debug2 is an ugly hack to prevent [log.Debug] from allocating.
-func Debug2[T1, T2 any](msg string, arg1 T1, arg2 T2) {
- if log.GetLevel() >= log.DEBUG {
- log.Debug(msg, arg1, arg2)
- }
-}
-
// Debug3 is an ugly hack to prevent [log.Debug] from allocating.
func Debug3[T1, T2, T3 any](msg string, arg1 T1, arg2 T2, arg3 T3) {
if log.GetLevel() >= log.DEBUG {
log.Debug(msg, arg1, arg2, arg3)
}
}
-
-// Debug4 is an ugly hack to prevent [log.Debug] from allocating.
-func Debug4[T1, T2, T3, T4 any](msg string, arg1 T1, arg2 T2, arg3 T3, arg4 T4) {
- if log.GetLevel() >= log.DEBUG {
- log.Debug(msg, arg1, arg2, arg3, arg4)
- }
-}
-
-// Error2 is an ugly hack to prevent [log.Error] from allocating.
-func Error2[T1, T2 any](msg string, arg1 T1, arg2 T2) {
- if log.GetLevel() >= log.ERROR {
- log.Error(msg, arg1, arg2)
- }
-}
diff --git a/internal/optslog/optslog.go b/internal/optslog/optslog.go
index b373b36..ca4b9c7 100644
--- a/internal/optslog/optslog.go
+++ b/internal/optslog/optslog.go
@@ -13,7 +13,7 @@ import (
)
// Trace1 is an optimized version of [slog.Logger.Log] that prevents it from
-// from allocating when debugging is not necessary.
+// allocating when debugging is not necessary.
func Trace1[T1 any](ctx context.Context, l *slog.Logger, msg, name1 string, arg1 T1) {
if l.Enabled(ctx, slogutil.LevelTrace) {
l.Log(ctx, slogutil.LevelTrace, msg, name1, arg1)
@@ -21,7 +21,7 @@ func Trace1[T1 any](ctx context.Context, l *slog.Logger, msg, name1 string, arg1
}
// Trace2 is an optimized version of [slog.Logger.Log] that prevents it from
-// from allocating when debugging is not necessary.
+// allocating when debugging is not necessary.
func Trace2[T1, T2 any](
ctx context.Context,
l *slog.Logger,
@@ -35,7 +35,7 @@ func Trace2[T1, T2 any](
}
// Trace3 is an optimized version of [slog.Logger.Log] that prevents it from
-// from allocating when debugging is not necessary.
+// allocating when debugging is not necessary.
func Trace3[T1, T2, T3 any](
ctx context.Context,
l *slog.Logger,
@@ -50,7 +50,7 @@ func Trace3[T1, T2, T3 any](
}
// Debug1 is an optimized version of [slog.Logger.DebugContext] that prevents it
-// from from allocating when debugging is not necessary.
+// from allocating when debugging is not necessary.
func Debug1[T1 any](ctx context.Context, l *slog.Logger, msg, name1 string, arg1 T1) {
if l.Enabled(ctx, slog.LevelDebug) {
l.DebugContext(ctx, msg, name1, arg1)
@@ -58,7 +58,7 @@ func Debug1[T1 any](ctx context.Context, l *slog.Logger, msg, name1 string, arg1
}
// Debug2 is an optimized version of [slog.Logger.DebugContext] that prevents it
-// from from allocating when debugging is not necessary.
+// from allocating when debugging is not necessary.
func Debug2[T1, T2 any](
ctx context.Context,
l *slog.Logger,
@@ -72,7 +72,7 @@ func Debug2[T1, T2 any](
}
// Debug3 is an optimized version of [slog.Logger.DebugContext] that prevents it
-// from from allocating when debugging is not necessary.
+// from allocating when debugging is not necessary.
func Debug3[T1, T2, T3 any](
ctx context.Context,
l *slog.Logger,
@@ -87,7 +87,7 @@ func Debug3[T1, T2, T3 any](
}
// Debug4 is an optimized version of [slog.Logger.DebugContext] that prevents it
-// from from allocating when debugging is not necessary.
+// from allocating when debugging is not necessary.
func Debug4[T1, T2, T3, T4 any](
ctx context.Context,
l *slog.Logger,
@@ -101,3 +101,17 @@ func Debug4[T1, T2, T3, T4 any](
l.DebugContext(ctx, msg, name1, arg1, name2, arg2, name3, arg3, name4, arg4)
}
}
+
+// Warn2 is an optimized version of [slog.Logger.WarnContext] that prevents it
+// from allocating when debugging is not necessary.
+func Warn2[T1, T2 any](
+ ctx context.Context,
+ l *slog.Logger,
+ msg string,
+ name1 string, arg1 T1,
+ name2 string, arg2 T2,
+) {
+ if l.Enabled(ctx, slog.LevelWarn) {
+ l.WarnContext(ctx, msg, name1, arg1, name2, arg2)
+ }
+}
diff --git a/internal/profiledb/internal/filecachepb/filecache.pb.go b/internal/profiledb/internal/filecachepb/filecache.pb.go
index a7dce21..10a5db1 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.34.2
-// protoc v5.27.1
+// protoc-gen-go v1.35.1
+// protoc v5.28.3
// source: filecache.proto
package filecachepb
@@ -35,11 +35,9 @@ type FileCache struct {
func (x *FileCache) Reset() {
*x = FileCache{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *FileCache) String() string {
@@ -50,7 +48,7 @@ func (*FileCache) ProtoMessage() {}
func (x *FileCache) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -129,11 +127,9 @@ type Profile struct {
func (x *Profile) Reset() {
*x = Profile{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *Profile) String() string {
@@ -144,7 +140,7 @@ func (*Profile) ProtoMessage() {}
func (x *Profile) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[1]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -371,11 +367,9 @@ type ParentalProtectionSettings struct {
func (x *ParentalProtectionSettings) Reset() {
*x = ParentalProtectionSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *ParentalProtectionSettings) String() string {
@@ -386,7 +380,7 @@ func (*ParentalProtectionSettings) ProtoMessage() {}
func (x *ParentalProtectionSettings) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[2]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -455,11 +449,9 @@ type SafeBrowsingSettings struct {
func (x *SafeBrowsingSettings) Reset() {
*x = SafeBrowsingSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[3]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *SafeBrowsingSettings) String() string {
@@ -470,7 +462,7 @@ func (*SafeBrowsingSettings) ProtoMessage() {}
func (x *SafeBrowsingSettings) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[3]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -523,11 +515,9 @@ type ParentalProtectionSchedule struct {
func (x *ParentalProtectionSchedule) Reset() {
*x = ParentalProtectionSchedule{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[4]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *ParentalProtectionSchedule) String() string {
@@ -538,7 +528,7 @@ func (*ParentalProtectionSchedule) ProtoMessage() {}
func (x *ParentalProtectionSchedule) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[4]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -620,11 +610,9 @@ type DayRange struct {
func (x *DayRange) Reset() {
*x = DayRange{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[5]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *DayRange) String() string {
@@ -635,7 +623,7 @@ func (*DayRange) ProtoMessage() {}
func (x *DayRange) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[5]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -675,11 +663,9 @@ type BlockingModeCustomIP struct {
func (x *BlockingModeCustomIP) Reset() {
*x = BlockingModeCustomIP{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[6]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *BlockingModeCustomIP) String() string {
@@ -690,7 +676,7 @@ func (*BlockingModeCustomIP) ProtoMessage() {}
func (x *BlockingModeCustomIP) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[6]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -727,11 +713,9 @@ type BlockingModeNXDOMAIN struct {
func (x *BlockingModeNXDOMAIN) Reset() {
*x = BlockingModeNXDOMAIN{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[7]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *BlockingModeNXDOMAIN) String() string {
@@ -742,7 +726,7 @@ func (*BlockingModeNXDOMAIN) ProtoMessage() {}
func (x *BlockingModeNXDOMAIN) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[7]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -765,11 +749,9 @@ type BlockingModeNullIP struct {
func (x *BlockingModeNullIP) Reset() {
*x = BlockingModeNullIP{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[8]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *BlockingModeNullIP) String() string {
@@ -780,7 +762,7 @@ func (*BlockingModeNullIP) ProtoMessage() {}
func (x *BlockingModeNullIP) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[8]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -803,11 +785,9 @@ type BlockingModeREFUSED struct {
func (x *BlockingModeREFUSED) Reset() {
*x = BlockingModeREFUSED{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[9]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *BlockingModeREFUSED) String() string {
@@ -818,7 +798,7 @@ func (*BlockingModeREFUSED) ProtoMessage() {}
func (x *BlockingModeREFUSED) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[9]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -849,11 +829,9 @@ type Device struct {
func (x *Device) Reset() {
*x = Device{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[10]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *Device) String() string {
@@ -864,7 +842,7 @@ func (*Device) ProtoMessage() {}
func (x *Device) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[10]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -942,11 +920,9 @@ type AccessSettings struct {
func (x *AccessSettings) Reset() {
*x = AccessSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[11]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *AccessSettings) String() string {
@@ -957,7 +933,7 @@ func (*AccessSettings) ProtoMessage() {}
func (x *AccessSettings) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[11]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1018,11 +994,9 @@ type CidrRange struct {
func (x *CidrRange) Reset() {
*x = CidrRange{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[12]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *CidrRange) String() string {
@@ -1033,7 +1007,7 @@ func (*CidrRange) ProtoMessage() {}
func (x *CidrRange) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[12]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1076,11 +1050,9 @@ type AuthenticationSettings struct {
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)
- }
+ mi := &file_filecache_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *AuthenticationSettings) String() string {
@@ -1091,7 +1063,7 @@ func (*AuthenticationSettings) ProtoMessage() {}
func (x *AuthenticationSettings) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[13]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1149,11 +1121,9 @@ type RateLimitSettings struct {
func (x *RateLimitSettings) Reset() {
*x = RateLimitSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_filecache_proto_msgTypes[14]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_filecache_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *RateLimitSettings) String() string {
@@ -1164,7 +1134,7 @@ func (*RateLimitSettings) ProtoMessage() {}
func (x *RateLimitSettings) ProtoReflect() protoreflect.Message {
mi := &file_filecache_proto_msgTypes[14]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -1493,188 +1463,6 @@ func file_filecache_proto_init() {
if File_filecache_proto != nil {
return
}
- if !protoimpl.UnsafeEnabled {
- file_filecache_proto_msgTypes[0].Exporter = func(v any, i int) any {
- switch v := v.(*FileCache); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[1].Exporter = func(v any, i int) any {
- switch v := v.(*Profile); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[2].Exporter = func(v any, i int) any {
- switch v := v.(*ParentalProtectionSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[3].Exporter = func(v any, i int) any {
- switch v := v.(*SafeBrowsingSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[4].Exporter = func(v any, i int) any {
- switch v := v.(*ParentalProtectionSchedule); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[5].Exporter = func(v any, i int) any {
- switch v := v.(*DayRange); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[6].Exporter = func(v any, i int) any {
- switch v := v.(*BlockingModeCustomIP); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[7].Exporter = func(v any, i int) any {
- switch v := v.(*BlockingModeNXDOMAIN); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[8].Exporter = func(v any, i int) any {
- switch v := v.(*BlockingModeNullIP); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[9].Exporter = func(v any, i int) any {
- switch v := v.(*BlockingModeREFUSED); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[10].Exporter = func(v any, i int) any {
- switch v := v.(*Device); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[11].Exporter = func(v any, i int) any {
- switch v := v.(*AccessSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[12].Exporter = func(v any, i int) any {
- switch v := v.(*CidrRange); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_filecache_proto_msgTypes[13].Exporter = func(v any, i int) any {
- 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[14].Exporter = func(v any, i int) any {
- switch v := v.(*RateLimitSettings); 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 = []any{
(*Profile_BlockingModeCustomIp)(nil),
(*Profile_BlockingModeNxdomain)(nil),
diff --git a/internal/querylog/querylog_test.go b/internal/querylog/querylog_test.go
index ff7996a..085b257 100644
--- a/internal/querylog/querylog_test.go
+++ b/internal/querylog/querylog_test.go
@@ -1,21 +1,15 @@
package querylog_test
import (
- "testing"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
- "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
)
-func TestMain(m *testing.M) {
- testutil.DiscardLogOutput(m)
-}
-
// testRequestID is the common request ID for tests.
var testRequestID = agd.NewRequestID()
diff --git a/internal/tlsconfig/manager.go b/internal/tlsconfig/manager.go
new file mode 100644
index 0000000..f6e35c0
--- /dev/null
+++ b/internal/tlsconfig/manager.go
@@ -0,0 +1,286 @@
+package tlsconfig
+
+import (
+ "cmp"
+ "context"
+ "crypto/tls"
+ "fmt"
+ "io"
+ "log/slog"
+ "maps"
+ "os"
+ "path/filepath"
+ "slices"
+ "strings"
+ "sync"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/golibs/errors"
+)
+
+// Manager stores and updates TLS configurations.
+type Manager interface {
+ // Add returns an initialized TLS configuration using the provided paths to
+ // a certificate and a key. certPath and keyPath must not be empty.
+ Add(ctx context.Context, certPath, keyPath string) (c *tls.Config, err error)
+}
+
+// DefaultManagerConfig is the configuration structure for [DefaultManager].
+//
+// TODO(s.chzhen): Use it.
+type DefaultManagerConfig struct {
+ // Logger is used for logging the operation of the TLS manager.
+ Logger *slog.Logger
+
+ // ErrColl is used to collect TLS related errors.
+ ErrColl errcoll.Interface
+
+ // Metrics is used to collect TLS related statistics.
+ Metrics RefreshMetrics
+
+ // KeyLogFilename, if not empty, is the name of the TLS key log file.
+ KeyLogFilename string
+
+ // SessionTicketPaths are paths to files containing the TLS session tickets.
+ SessionTicketPaths []string
+}
+
+// certWithKey contains a certificate path and a key path.
+type certWithKey struct {
+ certPath string
+ keyPath string
+}
+
+// compare is a comparison function for the certWithKey. It returns -1 if a
+// sorts before b, 1 if a sorts after b, and 0 if their relative sorting
+// position is the same. The sorting prioritizes certificate paths first, and
+// then key paths.
+func (a certWithKey) compare(b certWithKey) (r int) {
+ return cmp.Or(
+ strings.Compare(a.certPath, b.certPath),
+ strings.Compare(a.keyPath, b.keyPath),
+ )
+}
+
+// DefaultManager is the default implementation of [Manager].
+type DefaultManager struct {
+ // mu prtotects configs, sessionTickets.
+ mu *sync.Mutex
+ logger *slog.Logger
+ errColl errcoll.Interface
+ metrics RefreshMetrics
+ keyLogWriter io.Writer
+ configs map[certWithKey]*tls.Config
+ sessTicketPaths []string
+}
+
+// NewDefaultManager returns a new initialized *DefaultManager.
+func NewDefaultManager(conf *DefaultManagerConfig) (m *DefaultManager, err error) {
+ var kl io.Writer
+ fn := conf.KeyLogFilename
+ if fn != "" {
+ kl, err = tlsKeyLogWriter(fn)
+ if err != nil {
+ return nil, fmt.Errorf("initializing tls key log writer: %w", err)
+ }
+ }
+
+ return &DefaultManager{
+ mu: &sync.Mutex{},
+ logger: conf.Logger,
+ errColl: conf.ErrColl,
+ metrics: conf.Metrics,
+ keyLogWriter: kl,
+ configs: make(map[certWithKey]*tls.Config),
+ sessTicketPaths: conf.SessionTicketPaths,
+ }, nil
+}
+
+// type check
+var _ Manager = (*DefaultManager)(nil)
+
+// Add implements the [Manager] interface for *DefaultManager.
+func (m *DefaultManager) Add(
+ ctx context.Context,
+ certPath string,
+ keyPath string,
+) (conf *tls.Config, err error) {
+ ck := certWithKey{
+ certPath: certPath,
+ keyPath: keyPath,
+ }
+
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ if conf = m.configs[ck]; conf != nil {
+ return conf, nil
+ }
+
+ return m.add(ctx, ck)
+}
+
+// add returns a new TLS configuration from the provided certificate and key
+// paths. m.mu must be locked.
+func (m *DefaultManager) add(ctx context.Context, ck certWithKey) (conf *tls.Config, err error) {
+ cert, err := tls.LoadX509KeyPair(ck.certPath, ck.keyPath)
+ if err != nil {
+ return nil, fmt.Errorf("loading certificate: %w", err)
+ }
+
+ authAlgo := cert.Leaf.PublicKeyAlgorithm.String()
+ subj := cert.Leaf.Subject.String()
+ m.metrics.SetCertificateInfo(ctx, authAlgo, subj, cert.Leaf.NotAfter)
+
+ if conf = m.configs[ck]; conf != nil {
+ conf.GetCertificate = func(h *tls.ClientHelloInfo) (c *tls.Certificate, err error) {
+ return &cert, nil
+ }
+
+ m.logger.InfoContext(ctx, "refreshed config", "cert", ck.certPath, "key", ck.keyPath)
+
+ return conf, nil
+ }
+
+ conf = &tls.Config{
+ GetCertificate: func(clientHello *tls.ClientHelloInfo) (c *tls.Certificate, err error) {
+ return &cert, nil
+ },
+ MinVersion: tls.VersionTLS12,
+ MaxVersion: tls.VersionTLS13,
+ KeyLogWriter: m.keyLogWriter,
+ }
+
+ m.configs[ck] = conf
+
+ m.logger.InfoContext(ctx, "added config", "cert", ck.certPath, "key", ck.keyPath)
+
+ return conf, nil
+}
+
+// type check
+var _ agdservice.Refresher = (*DefaultManager)(nil)
+
+// Refresh implements the [agdservice.Refresher] interface for *DefaultManager.
+func (m *DefaultManager) Refresh(ctx context.Context) (err error) {
+ m.logger.DebugContext(ctx, "refresh started")
+ defer m.logger.DebugContext(ctx, "refresh finished")
+
+ defer func() {
+ if err != nil {
+ errcoll.Collect(ctx, m.errColl, m.logger, "cerificate refresh failed", err)
+ }
+ }()
+
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ var errs []error
+ for _, ck := range slices.SortedFunc(maps.Keys(m.configs), certWithKey.compare) {
+ _, err = m.add(ctx, ck)
+ errs = append(errs, err)
+ }
+
+ err = errors.Join(errs...)
+ if err != nil {
+ return fmt.Errorf("refreshing tls certificates: %w", err)
+ }
+
+ m.logger.InfoContext(ctx, "refresh successful", "num_configs", len(m.configs))
+
+ return nil
+}
+
+// sessTickLen is the length of a single TLS session ticket key in bytes.
+//
+// NOTE: Unlike Nginx, Go's crypto/tls doesn't use the random bytes from the
+// session ticket keys as-is, but instead hashes these bytes and uses the first
+// 48 bytes of the hashed data as the key name, the AES key, and the HMAC key.
+const sessTickLen = 32
+
+// sessionTicket is a type alias for a single TLS session ticket.
+type sessionTicket = [sessTickLen]byte
+
+// RotateTickets rereads and resets TLS session tickets.
+func (m *DefaultManager) RotateTickets(ctx context.Context) (err error) {
+ m.logger.DebugContext(ctx, "ticket rotation started")
+ defer m.logger.DebugContext(ctx, "ticket rotation finished")
+
+ files := m.sessTicketPaths
+ if len(files) == 0 {
+ return nil
+ }
+
+ defer func() {
+ if err != nil {
+ m.metrics.SetSessionTicketRotationStatus(ctx, false)
+ errcoll.Collect(ctx, m.errColl, m.logger, "ticket rotation failed", err)
+ }
+ }()
+
+ tickets := make([]sessionTicket, 0, len(files))
+ for _, fileName := range files {
+ var ticket sessionTicket
+ ticket, err = readSessionTicketKey(fileName)
+ if err != nil {
+ return fmt.Errorf("reading sesion ticket: %w", err)
+ }
+
+ tickets = append(tickets, ticket)
+ }
+
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ for _, conf := range m.configs {
+ conf.SetSessionTicketKeys(tickets)
+ }
+
+ m.logger.InfoContext(
+ ctx,
+ "ticket rotation successful",
+ "num_configs", len(m.configs),
+ "num_tickets", len(tickets),
+ )
+
+ m.metrics.SetSessionTicketRotationStatus(ctx, true)
+
+ return nil
+}
+
+// readSessionTicketKey reads a single TLS session ticket from a file.
+func readSessionTicketKey(fn string) (ticket sessionTicket, err error) {
+ // #nosec G304 -- Trust the file paths that are given to us in the
+ // configuration file.
+ b, err := os.ReadFile(fn)
+ if err != nil {
+ return ticket, fmt.Errorf("reading session ticket: %w", err)
+ }
+
+ tickLen := len(b)
+ if tickLen != sessTickLen {
+ return ticket, fmt.Errorf(
+ "session ticket in %s: bad len %d, want %d",
+ fn,
+ tickLen,
+ sessTickLen,
+ )
+ }
+
+ return sessionTicket(b), nil
+}
+
+// tlsKeyLogWriter returns a writer for logging TLS secrets to keyLogFilename.
+func tlsKeyLogWriter(keyLogFilename string) (kl io.Writer, err error) {
+ path := filepath.Clean(keyLogFilename)
+
+ // TODO(a.garipov): Consider closing the file when we add SIGHUP support.
+ kl, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return nil, err
+ }
+
+ return kl, nil
+}
diff --git a/internal/tlsconfig/manager_test.go b/internal/tlsconfig/manager_test.go
new file mode 100644
index 0000000..60d2bcc
--- /dev/null
+++ b/internal/tlsconfig/manager_test.go
@@ -0,0 +1,175 @@
+package tlsconfig_test
+
+import (
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/tls"
+ "crypto/x509"
+ "encoding/pem"
+ "math/big"
+ "os"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// testTimeout is the common timeout for tests and contexts.
+const testTimeout = 1 * time.Second
+
+// newCertAndKey is a helper function that generates certificate and key.
+func newCertAndKey(tb testing.TB, n int64) (certDER []byte, key *rsa.PrivateKey) {
+ tb.Helper()
+
+ key, err := rsa.GenerateKey(rand.Reader, 2048)
+ require.NoError(tb, err)
+
+ certTmpl := &x509.Certificate{
+ SerialNumber: big.NewInt(n),
+ }
+
+ certDER, err = x509.CreateCertificate(rand.Reader, certTmpl, certTmpl, &key.PublicKey, key)
+ require.NoError(tb, err)
+
+ return certDER, key
+}
+
+// writeCertAndKey is a helper function that writes certificate and key to
+// specified paths.
+func writeCertAndKey(
+ tb testing.TB,
+ certDER []byte,
+ certPath string,
+ key *rsa.PrivateKey,
+ keyPath string,
+) {
+ tb.Helper()
+
+ certFile, err := os.OpenFile(certPath, os.O_WRONLY|os.O_CREATE, 0o600)
+ require.NoError(tb, err)
+
+ defer func() {
+ err = certFile.Close()
+ require.NoError(tb, err)
+ }()
+
+ err = pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certDER})
+ require.NoError(tb, err)
+
+ keyFile, err := os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE, 0o600)
+ require.NoError(tb, err)
+
+ defer func() {
+ err = keyFile.Close()
+ require.NoError(tb, err)
+ }()
+
+ err = pem.Encode(keyFile, &pem.Block{
+ Type: "RSA PRIVATE KEY",
+ Bytes: x509.MarshalPKCS1PrivateKey(key),
+ })
+ require.NoError(tb, err)
+}
+
+// writeSesionKey is a helper function that writes generated session key to
+// specified path.
+func writeSessionKey(tb testing.TB, sessKeyPath string) {
+ tb.Helper()
+
+ var sessKey [32]byte
+ _, err := rand.Read(sessKey[:])
+ require.NoError(tb, err)
+
+ keyFile, err := os.OpenFile(sessKeyPath, os.O_WRONLY|os.O_CREATE, 0o600)
+ require.NoError(tb, err)
+
+ defer func() {
+ err = keyFile.Close()
+ require.NoError(tb, err)
+ }()
+
+ _, err = keyFile.Write(sessKey[:])
+ require.NoError(tb, err)
+}
+
+func TestDefaultManager_Refresh(t *testing.T) {
+ t.Parallel()
+
+ const (
+ snBefore int64 = 1
+ snAfter int64 = 2
+ )
+
+ m, err := tlsconfig.NewDefaultManager(&tlsconfig.DefaultManagerConfig{
+ Logger: slogutil.NewDiscardLogger(),
+ ErrColl: agdtest.NewErrorCollector(),
+ Metrics: tlsconfig.EmptyRefreshMetrics{},
+ })
+ require.NoError(t, err)
+
+ certDER, key := newCertAndKey(t, snBefore)
+
+ tmpDir := t.TempDir()
+ certPath := filepath.Join(tmpDir, "cert.pem")
+ keyPath := filepath.Join(tmpDir, "key.pem")
+
+ writeCertAndKey(t, certDER, certPath, key, keyPath)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ conf, err := m.Add(ctx, certPath, keyPath)
+ require.NoError(t, err)
+
+ cert, err := conf.GetCertificate(&tls.ClientHelloInfo{})
+ require.NoError(t, err)
+
+ assert.Equal(t, snBefore, cert.Leaf.SerialNumber.Int64())
+
+ certDER, key = newCertAndKey(t, snAfter)
+ writeCertAndKey(t, certDER, certPath, key, keyPath)
+
+ err = m.Refresh(ctx)
+ require.NoError(t, err)
+
+ cert, err = conf.GetCertificate(&tls.ClientHelloInfo{})
+ require.NoError(t, err)
+
+ assert.Equal(t, snAfter, cert.Leaf.SerialNumber.Int64())
+}
+
+func TestDefaultManager_RotateTickets(t *testing.T) {
+ t.Parallel()
+
+ tmpDir := t.TempDir()
+ sessKeyPath := filepath.Join(tmpDir, "sess.key")
+ writeSessionKey(t, sessKeyPath)
+
+ m, err := tlsconfig.NewDefaultManager(&tlsconfig.DefaultManagerConfig{
+ Logger: slogutil.NewDiscardLogger(),
+ ErrColl: agdtest.NewErrorCollector(),
+ Metrics: tlsconfig.EmptyRefreshMetrics{},
+ SessionTicketPaths: []string{sessKeyPath},
+ })
+ require.NoError(t, err)
+
+ certDER, key := newCertAndKey(t, 1)
+
+ certPath := filepath.Join(tmpDir, "cert.pem")
+ keyPath := filepath.Join(tmpDir, "key.pem")
+
+ writeCertAndKey(t, certDER, certPath, key, keyPath)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ _, err = m.Add(ctx, certPath, keyPath)
+ require.NoError(t, err)
+
+ err = m.RotateTickets(ctx)
+ require.NoError(t, err)
+
+ // TODO(s.chzhen): Find a way to test session ticket changes.
+}
diff --git a/internal/tlsconfig/metrics.go b/internal/tlsconfig/metrics.go
new file mode 100644
index 0000000..30b0096
--- /dev/null
+++ b/internal/tlsconfig/metrics.go
@@ -0,0 +1,92 @@
+package tlsconfig
+
+import (
+ "context"
+ "crypto/tls"
+ "time"
+)
+
+// Metrics is an interface that is used for the collection of the TLS related
+// statistics.
+type Metrics interface {
+ // BeforeHandshake returns a function that needs to be passed to
+ // [tls.Config.GetConfigForClient]. f must not be nil.
+ BeforeHandshake(proto string) (f func(*tls.ClientHelloInfo) (c *tls.Config, err error))
+
+ // AfterHandshake returns a function that needs to be passed to
+ // [tls.Config.VerifyConnection]. f must not be nil.
+ AfterHandshake(
+ proto string,
+ srvName string,
+ devDomains []string,
+ srvCerts []tls.Certificate,
+ ) (f func(s tls.ConnectionState) (err error))
+
+ // RefreshMetrics gathers statistics during updates.
+ //
+ // TODO(s.chzhen): Separate it.
+ RefreshMetrics
+}
+
+// RefreshMetrics is an interface that is used to collect statistics during TLS
+// certificate and TLS session ticket updates.
+type RefreshMetrics interface {
+ // SetCertificateInfo sets the TLS certificate information.
+ SetCertificateInfo(ctx context.Context, algo, subj string, notAfter time.Time)
+
+ // SetSessionTicketRotationStatus sets the TLS session ticket rotation
+ // status.
+ SetSessionTicketRotationStatus(ctx context.Context, enabled bool)
+}
+
+// EmptyMetrics is the implementation of the [Metrics] interface that does
+// nothing.
+type EmptyMetrics struct{}
+
+// type check
+var _ Metrics = EmptyMetrics{}
+
+// BeforeHandshake implements the [Metrics] interface for EmptyMetrics by
+// returning a function that does nothing.
+func (EmptyMetrics) BeforeHandshake(
+ _ string,
+) (f func(info *tls.ClientHelloInfo) (c *tls.Config, err error)) {
+ return func(info *tls.ClientHelloInfo) (*tls.Config, error) {
+ return nil, nil
+ }
+}
+
+// AfterHandshake implements the [Metrics] interface for EmptyMetrics by
+// returning a function that does nothing.
+func (EmptyMetrics) AfterHandshake(
+ _ string,
+ _ string,
+ _ []string,
+ _ []tls.Certificate,
+) (f func(s tls.ConnectionState) (err error)) {
+ return func(tls.ConnectionState) error {
+ return nil
+ }
+}
+
+// SetCertificateInfo implements the [Metrics] interface for EmptyMetrics.
+func (EmptyMetrics) SetCertificateInfo(_ context.Context, _, _ string, _ time.Time) {}
+
+// SetSessionTicketRotationStatus implements the [Metrics] interface for
+// EmptyMetrics.
+func (EmptyMetrics) SetSessionTicketRotationStatus(_ context.Context, _ bool) {}
+
+// EmptyRefreshMetrics is the implementation of the [RefreshMetrics] interface
+// that does nothing.
+type EmptyRefreshMetrics struct{}
+
+// type check
+var _ RefreshMetrics = EmptyRefreshMetrics{}
+
+// SetCertificateInfo implements the [RefreshMetrics] interface for
+// EmptyRefreshMetrics.
+func (EmptyRefreshMetrics) SetCertificateInfo(_ context.Context, _, _ string, _ time.Time) {}
+
+// SetSessionTicketRotationStatus implements the [RefreshMetrics] interface for
+// EmptyRefreshMetrics.
+func (EmptyRefreshMetrics) SetSessionTicketRotationStatus(_ context.Context, _ bool) {}
diff --git a/internal/tlsconfig/tlsconfig.go b/internal/tlsconfig/tlsconfig.go
new file mode 100644
index 0000000..83f34f4
--- /dev/null
+++ b/internal/tlsconfig/tlsconfig.go
@@ -0,0 +1,3 @@
+// Package tlsconfig contains TLS related interfaces, helpers, and
+// implementations.
+package tlsconfig
diff --git a/internal/tools/go.mod b/internal/tools/go.mod
index 7a5eaed..0a02d17 100644
--- a/internal/tools/go.mod
+++ b/internal/tools/go.mod
@@ -1,32 +1,32 @@
module github.com/AdguardTeam/AdGuardDNS/internal/tools
-go 1.23.1
+go 1.23.2
require (
github.com/fzipp/gocyclo v0.6.0
github.com/golangci/misspell v0.6.0
github.com/gordonklaus/ineffassign v0.1.0
github.com/jstemmer/go-junit-report/v2 v2.1.0
- github.com/kisielk/errcheck v1.7.0
+ github.com/kisielk/errcheck v1.8.0
github.com/securego/gosec/v2 v2.21.4
github.com/uudashr/gocognit v1.1.3
- golang.org/x/tools v0.25.0
+ golang.org/x/tools v0.26.0
golang.org/x/vuln v1.1.3
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1
- google.golang.org/protobuf v1.34.2
+ google.golang.org/protobuf v1.35.1
honnef.co/go/tools v0.5.1
mvdan.cc/gofumpt v0.7.0
- mvdan.cc/sh/v3 v3.9.0
+ mvdan.cc/sh/v3 v3.10.0
mvdan.cc/unparam v0.0.0-20240917084806-57a3b4290ba3
)
require (
- cloud.google.com/go v0.115.1 // indirect
+ cloud.google.com/go v0.116.0 // indirect
cloud.google.com/go/ai v0.8.2 // indirect
- cloud.google.com/go/auth v0.9.5 // indirect
+ cloud.google.com/go/auth v0.9.9 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
cloud.google.com/go/compute/metadata v0.5.2 // indirect
- cloud.google.com/go/longrunning v0.6.1 // indirect
+ cloud.google.com/go/longrunning v0.6.2 // indirect
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
@@ -44,27 +44,27 @@ require (
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.opencensus.io v0.24.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect
- go.opentelemetry.io/otel v1.30.0 // indirect
- go.opentelemetry.io/otel/metric v1.30.0 // indirect
- go.opentelemetry.io/otel/trace v1.30.0 // indirect
- golang.org/x/crypto v0.27.0 // indirect
- golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
- golang.org/x/exp/typeparams v0.0.0-20240909161429-701f63a606c0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect
+ go.opentelemetry.io/otel v1.31.0 // indirect
+ go.opentelemetry.io/otel/metric v1.31.0 // indirect
+ go.opentelemetry.io/otel/trace v1.31.0 // indirect
+ golang.org/x/crypto v0.28.0 // indirect
+ golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
+ golang.org/x/exp/typeparams v0.0.0-20241009180824-f66d83c29e7c // indirect
golang.org/x/mod v0.21.0 // indirect
- golang.org/x/net v0.29.0 // indirect
+ golang.org/x/net v0.30.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.8.0 // indirect
- golang.org/x/sys v0.25.0 // indirect
- golang.org/x/telemetry v0.0.0-20240927214544-e9e6960092dd // indirect
- golang.org/x/term v0.24.0 // indirect
- golang.org/x/text v0.18.0 // indirect
- golang.org/x/time v0.6.0 // indirect
- google.golang.org/api v0.199.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 // indirect
- google.golang.org/grpc v1.67.0 // indirect
+ golang.org/x/sys v0.26.0 // indirect
+ golang.org/x/telemetry v0.0.0-20241017030730-50079b310951 // indirect
+ golang.org/x/term v0.25.0 // indirect
+ golang.org/x/text v0.19.0 // indirect
+ golang.org/x/time v0.7.0 // indirect
+ google.golang.org/api v0.203.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
+ google.golang.org/grpc v1.67.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
mvdan.cc/editorconfig v0.3.0 // indirect
)
diff --git a/internal/tools/go.sum b/internal/tools/go.sum
index 16b8dc8..779bc3f 100644
--- a/internal/tools/go.sum
+++ b/internal/tools/go.sum
@@ -1,16 +1,16 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ=
-cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc=
+cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
+cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
cloud.google.com/go/ai v0.8.2 h1:LEaQwqBv+k2ybrcdTtCTc9OPZXoEdcQaGrfvDYS6Bnk=
cloud.google.com/go/ai v0.8.2/go.mod h1:Wb3EUUGWwB6yHBaUf/+oxUq/6XbCaU1yh0GrwUS8lr4=
-cloud.google.com/go/auth v0.9.5 h1:4CTn43Eynw40aFVr3GpPqsQponx2jv0BQpjvajsbbzw=
-cloud.google.com/go/auth v0.9.5/go.mod h1:Xo0n7n66eHyOWWCnitop6870Ilwo3PiZyodVkkH1xWM=
+cloud.google.com/go/auth v0.9.9 h1:BmtbpNQozo8ZwW2t7QJjnrQtdganSdmqeIBxHxNkEZQ=
+cloud.google.com/go/auth v0.9.9/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
-cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc=
-cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0=
+cloud.google.com/go/longrunning v0.6.2 h1:xjDfh1pQcWPEvnfjZmwjKQEcHnpz6lHjfy7Fo0MK+hc=
+cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
@@ -91,8 +91,8 @@ github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5
github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
github.com/jstemmer/go-junit-report/v2 v2.1.0 h1:X3+hPYlSczH9IMIpSC9CQSZA0L+BipYafciZUWHEmsc=
github.com/jstemmer/go-junit-report/v2 v2.1.0/go.mod h1:mgHVr7VUo5Tn8OLVr1cKnLuEy0M92wdRntM99h7RkgQ=
-github.com/kisielk/errcheck v1.7.0 h1:+SbscKmWJ5mOK/bO1zS60F5I9WwZDWOfRsC4RwfwRV0=
-github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ=
+github.com/kisielk/errcheck v1.8.0 h1:ZX/URYa7ilESY19ik/vBmCn6zdGQLxACwjAcWbHlYlg=
+github.com/kisielk/errcheck v1.8.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ=
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=
@@ -125,26 +125,26 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJu
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 h1:hCq2hNMwsegUvPzI7sPOvtO9cqyy5GbWt/Ybp2xrx8Q=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0/go.mod h1:LqaApwGx/oUmzsbqxkzuBvyoPpkxk3JQWnqfVrJ3wCA=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI=
-go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
-go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
-go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
-go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
-go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
-go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 h1:yMkBS9yViCc7U7yeLzJPM2XizlfdVvBRSmsQDWu6qc0=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0/go.mod h1:n8MR6/liuGB5EmTETUBeU5ZgqMOlqKRxUaqPQBOANZ8=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
+go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
+go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
+go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
+go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
+go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
+go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
-golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
+golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
-golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
-golang.org/x/exp/typeparams v0.0.0-20240909161429-701f63a606c0 h1:bVwtbF629Xlyxk6xLQq2TDYmqP0uiWaet5LwRebuY0k=
-golang.org/x/exp/typeparams v0.0.0-20240909161429-701f63a606c0/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
+golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
+golang.org/x/exp/typeparams v0.0.0-20241009180824-f66d83c29e7c h1:F/15/6p7LyGUSoP0GE5CB/U9+TNEER1foNOP5sWLLnI=
+golang.org/x/exp/typeparams v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -159,8 +159,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
-golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
+golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
@@ -177,19 +177,19 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
-golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/telemetry v0.0.0-20240927214544-e9e6960092dd h1:cSUM3UgI7q2QZ4WBwDOGo5eFhZG4eGUkpdFporYHwpQ=
-golang.org/x/telemetry v0.0.0-20240927214544-e9e6960092dd/go.mod h1:PsFMgI0jiuY7j+qwXANuh9a/x5kQESTSnRow3gapUyk=
+golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
+golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/telemetry v0.0.0-20241017030730-50079b310951 h1:VIsPFKAgj0HiIP3VzW4sSLxbZ9GnRitkOBt0bwqYl3Q=
+golang.org/x/telemetry v0.0.0-20241017030730-50079b310951/go.mod h1:uskmY3Y2C5OU/HAtQlc9Jq98qE2bf7H3kCPFgkab838=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
-golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
+golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
+golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
-golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
-golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
-golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
+golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
+golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -197,32 +197,32 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
-golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
+golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
+golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/vuln v1.1.3 h1:NPGnvPOTgnjBc9HTaUx+nj+EaUYxl5SJOWqaDYGaFYw=
golang.org/x/vuln v1.1.3/go.mod h1:7Le6Fadm5FOqE9C926BCD0g12NWyhg7cxV4BwcPFuNY=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.199.0 h1:aWUXClp+VFJmqE0JPvpZOK3LDQMyFKYIow4etYd9qxs=
-google.golang.org/api v0.199.0/go.mod h1:ohG4qSztDJmZdjK/Ar6MhbAmb/Rpi4JHOqagsh90K28=
+google.golang.org/api v0.203.0 h1:SrEeuwU3S11Wlscsn+LA1kb/Y5xT8uggJSkIhD08NAU=
+google.golang.org/api v0.203.0/go.mod h1:BuOVyCSYEPwJb3npWvDnNmFI92f3GeRnHNkETneT3SI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61 h1:pAjq8XSSzXoP9ya73v/w+9QEAAJNluLrpmMq5qFJQNY=
-google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:O6rP0uBq4k0mdi/b4ZEMAZjkhYWhS815kCvaMha4VN8=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1:N9BgCIAUvn/M+p4NJccWPWb3BWh88+zyL0ll9HgbEeM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw=
+google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
-google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
+google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
+google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -234,8 +234,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
-google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
+google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -249,7 +249,7 @@ mvdan.cc/editorconfig v0.3.0 h1:D1D2wLYEYGpawWT5SpM5pRivgEgXjtEXwC9MWhEY0gQ=
mvdan.cc/editorconfig v0.3.0/go.mod h1:NcJHuDtNOTEJ6251indKiWuzK6+VcrMuLzGMLKBFupQ=
mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU=
mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo=
-mvdan.cc/sh/v3 v3.9.0 h1:it14fyjCdQUk4jf/aYxLO3FG8jFarR9GzMCtnlvvD7c=
-mvdan.cc/sh/v3 v3.9.0/go.mod h1:cdBk8bgoiBI7lSZqK5JhUuq7OB64VQ7fgm85xelw3Nk=
+mvdan.cc/sh/v3 v3.10.0 h1:v9z7N1DLZ7owyLM/SXZQkBSXcwr2IGMm2LY2pmhVXj4=
+mvdan.cc/sh/v3 v3.10.0/go.mod h1:z/mSSVyLFGZzqb3ZIKojjyqIx/xbmz/UHdCSv9HmqXY=
mvdan.cc/unparam v0.0.0-20240917084806-57a3b4290ba3 h1:YkmTN1n5U60NM02j7TCSWRlW3fqNiuXe/eVXf0dLFN8=
mvdan.cc/unparam v0.0.0-20240917084806-57a3b4290ba3/go.mod h1:z5yboO1sP1Q9pcfvS597TpfbNXQjphDlkCJHzt13ybc=
diff --git a/internal/websvc/blockpage_test.go b/internal/websvc/blockpage_test.go
index 1314926..fa14bc2 100644
--- a/internal/websvc/blockpage_test.go
+++ b/internal/websvc/blockpage_test.go
@@ -12,6 +12,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/websvc"
"github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -122,7 +123,7 @@ func TestBlockPageServers_gzip(t *testing.T) {
}
u := &url.URL{
- Scheme: "http",
+ Scheme: urlutil.SchemeHTTP,
Host: addr.String(),
Path: "/",
}
diff --git a/internal/websvc/handler_test.go b/internal/websvc/handler_test.go
index a790631..881dee4 100644
--- a/internal/websvc/handler_test.go
+++ b/internal/websvc/handler_test.go
@@ -11,6 +11,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/websvc"
"github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -25,7 +26,7 @@ func TestService_ServeHTTP(t *testing.T) {
})
rootRedirectURL := &url.URL{
- Scheme: "http",
+ Scheme: urlutil.SchemeHTTP,
Host: "adguard-dns.com",
Path: "/",
}
@@ -73,7 +74,7 @@ func assertResponse(
t.Helper()
r := httptest.NewRequest(http.MethodGet, (&url.URL{
- Scheme: "http",
+ Scheme: urlutil.SchemeHTTP,
Host: "127.0.0.1",
Path: path,
}).String(), strings.NewReader(""))
diff --git a/internal/websvc/linkip_internal_test.go b/internal/websvc/linkip_internal_test.go
index 8a4f1dc..46aad12 100644
--- a/internal/websvc/linkip_internal_test.go
+++ b/internal/websvc/linkip_internal_test.go
@@ -12,6 +12,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -107,8 +108,8 @@ func TestLinkedIPProxy_ServeHTTP(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
r := httptest.NewRequest(tc.method, (&url.URL{
- Scheme: "http",
- Host: "www.example.com",
+ Scheme: urlutil.SchemeHTTP,
+ Host: "link-ip.example",
Path: tc.path,
}).String(), strings.NewReader(""))
@@ -117,7 +118,7 @@ func TestLinkedIPProxy_ServeHTTP(t *testing.T) {
r.Header.Set(httphdr.Forwarded, "1.1.1.1")
r.Header.Set(httphdr.TrueClientIP, "1.1.1.1")
r.Header.Set(httphdr.XForwardedFor, "1.1.1.1")
- r.Header.Set(httphdr.XForwardedHost, "forward.example.org")
+ r.Header.Set(httphdr.XForwardedHost, "forward.example")
r.Header.Set(httphdr.XForwardedProto, "https")
r.Header.Set(httphdr.XRealIP, "1.1.1.1")
diff --git a/internal/websvc/websvc_test.go b/internal/websvc/websvc_test.go
index c25efea..2a6158c 100644
--- a/internal/websvc/websvc_test.go
+++ b/internal/websvc/websvc_test.go
@@ -11,6 +11,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/websvc"
"github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -62,7 +63,7 @@ func TestService_NonDoH(t *testing.T) {
}
resp, err := client.Get((&url.URL{
- Scheme: "http",
+ Scheme: urlutil.SchemeHTTP,
Host: nonDoHPort.String(),
Path: "/other",
}).String())
@@ -89,7 +90,7 @@ func assertContent(t *testing.T, addr netip.AddrPort, path string, status int, e
var body []byte
u := &url.URL{
- Scheme: "http",
+ Scheme: urlutil.SchemeHTTP,
Host: addr.String(),
Path: path,
}
diff --git a/scripts/backend/dns.go b/scripts/backend/dns.go
new file mode 100644
index 0000000..3c83b89
--- /dev/null
+++ b/scripts/backend/dns.go
@@ -0,0 +1,202 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "log/slog"
+ "net/netip"
+ "strconv"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/metadata"
+ "google.golang.org/protobuf/types/known/durationpb"
+ "google.golang.org/protobuf/types/known/emptypb"
+)
+
+// mockDNSServiceServer is the mock [backendpb.DNSServiceServer].
+type mockDNSServiceServer struct {
+ backendpb.UnimplementedDNSServiceServer
+ log *slog.Logger
+}
+
+// newMockDNSServiceServer creates a new instance of *mockDNSServiceServer.
+func newMockDNSServiceServer(log *slog.Logger) (srv *mockDNSServiceServer) {
+ return &mockDNSServiceServer{
+ log: log,
+ }
+}
+
+// type check
+var _ backendpb.DNSServiceServer = (*mockDNSServiceServer)(nil)
+
+// CreateDeviceByHumanId implements the [backendpb.DNSServiceServer] interface
+// for *mockDNSServiceServer.
+//
+//lint:ignore ST1003 The name is necessary for the interface.
+func (s *mockDNSServiceServer) CreateDeviceByHumanId(
+ ctx context.Context,
+ req *backendpb.CreateDeviceRequest,
+) (resp *backendpb.CreateDeviceResponse, err error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ s.log.InfoContext(
+ ctx,
+ "creating by id",
+ "auth", md.Get(httphdr.Authorization),
+ "req", req,
+ )
+
+ p := newDNSProfile()
+
+ return &backendpb.CreateDeviceResponse{
+ Device: p.Devices[1],
+ }, nil
+}
+
+// GetDNSProfiles implements the [backendpb.DNSServiceServer] interface for
+// *mockDNSServiceServer
+func (s *mockDNSServiceServer) GetDNSProfiles(
+ req *backendpb.DNSProfilesRequest,
+ srv grpc.ServerStreamingServer[backendpb.DNSProfile],
+) (err error) {
+ ctx := srv.Context()
+ md, _ := metadata.FromIncomingContext(ctx)
+ s.log.InfoContext(
+ ctx,
+ "getting dns profiles",
+ "auth", md.Get(httphdr.Authorization),
+ "sync_time", req.SyncTime.AsTime(),
+ )
+
+ t := time.Now()
+ syncTime := strconv.FormatInt(t.UnixMilli(), 10)
+ trailerMD := metadata.MD{
+ "sync_time": []string{syncTime},
+ }
+
+ srv.SetTrailer(trailerMD)
+ err = srv.Send(newDNSProfile())
+ if err != nil {
+ s.log.WarnContext(ctx, "sending dns profile", slogutil.KeyError, err)
+ }
+
+ return nil
+}
+
+// SaveDevicesBillingStat implements the [backendpb.DNSServiceServer] interface
+// for *mockDNSServiceServer
+func (s *mockDNSServiceServer) SaveDevicesBillingStat(
+ srv grpc.ClientStreamingServer[backendpb.DeviceBillingStat, emptypb.Empty],
+) (err error) {
+ ctx := srv.Context()
+ md, _ := metadata.FromIncomingContext(ctx)
+ s.log.InfoContext(ctx, "saving devices", "auth", md.Get(httphdr.Authorization))
+
+ for {
+ var bs *backendpb.DeviceBillingStat
+ bs, err = srv.Recv()
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ return srv.SendAndClose(&emptypb.Empty{})
+ } else {
+ return fmt.Errorf("receiving billing stat: %w", err)
+ }
+ }
+
+ s.log.InfoContext(ctx, "saving billing stat", "device_id", bs.DeviceId)
+ }
+}
+
+// newDNSProfile returns a mock instance of [*backendpb.DNSProfile].
+func newDNSProfile() (dp *backendpb.DNSProfile) {
+ dayRange := &backendpb.DayRange{
+ Start: durationpb.New(0),
+ End: durationpb.New(59 * time.Minute),
+ }
+
+ devices := []*backendpb.DeviceSettings{{
+ Id: "test",
+ Name: "test-name",
+ FilteringEnabled: false,
+ LinkedIp: []byte{1, 1, 1, 1},
+ DedicatedIps: [][]byte{{127, 0, 0, 1}},
+ }, {
+ Id: "auto",
+ Name: "My Device X-10",
+ HumanIdLower: "my-device-x--10",
+ }}
+
+ return &backendpb.DNSProfile{
+ DnsId: "mock1234",
+ FilteringEnabled: true,
+ QueryLogEnabled: true,
+ Deleted: false,
+ AutoDevicesEnabled: true,
+ IpLogEnabled: true,
+ SafeBrowsing: &backendpb.SafeBrowsingSettings{
+ Enabled: true,
+ BlockDangerousDomains: true,
+ BlockNrd: false,
+ },
+ Parental: &backendpb.ParentalSettings{
+ Enabled: false,
+ BlockAdult: false,
+ GeneralSafeSearch: false,
+ YoutubeSafeSearch: false,
+ BlockedServices: []string{"youtube"},
+ Schedule: &backendpb.ScheduleSettings{
+ Tmz: "GMT",
+ WeeklyRange: &backendpb.WeeklyRange{
+ Sun: nil,
+ Mon: dayRange,
+ Tue: dayRange,
+ Wed: dayRange,
+ Thu: dayRange,
+ Fri: dayRange,
+ Sat: nil,
+ },
+ },
+ },
+ Access: &backendpb.AccessSettings{
+ AllowlistCidr: []*backendpb.CidrRange{{
+ Address: netip.MustParseAddr("1.1.1.0").AsSlice(),
+ Prefix: 24,
+ }},
+ BlocklistCidr: []*backendpb.CidrRange{{
+ Address: netip.MustParseAddr("2.2.2.0").AsSlice(),
+ Prefix: 24,
+ }},
+ AllowlistAsn: []uint32{1},
+ BlocklistAsn: []uint32{2},
+ BlocklistDomainRules: []string{"block.test"},
+ Enabled: true,
+ },
+ RuleLists: &backendpb.RuleListsSettings{
+ Enabled: true,
+ Ids: []string{"1"},
+ },
+ Devices: devices,
+ CustomRules: []string{"||example.org^"},
+ FilteredResponseTtl: durationpb.New(10 * time.Second),
+ BlockPrivateRelay: true,
+ BlockFirefoxCanary: true,
+ BlockingMode: &backendpb.DNSProfile_BlockingModeCustomIp{
+ BlockingModeCustomIp: &backendpb.BlockingModeCustomIP{
+ Ipv4: []byte{1, 2, 3, 4},
+ },
+ },
+ RateLimit: &backendpb.RateLimitSettings{
+ ClientCidr: []*backendpb.CidrRange{{
+ Address: netip.MustParseAddr("3.3.3.0").AsSlice(),
+ Prefix: 24,
+ }},
+ Rps: 100,
+ Enabled: true,
+ },
+ }
+}
diff --git a/scripts/backend/main.go b/scripts/backend/main.go
index d586ae9..c794fd0 100644
--- a/scripts/backend/main.go
+++ b/scripts/backend/main.go
@@ -1,33 +1,22 @@
-// backend contains mock GRPC server for BILLSTAT_URL and PROFILES_URL
-// endpoints.
+// main implements a single mock GRPC server for backend services defined by
+// BILLSTAT_URL, PROFILES_URL, and REMOTE_KV_URL environment variables.
package main
import (
- "context"
- "fmt"
- "io"
- "log/slog"
"net"
- "net/netip"
"os"
- "strconv"
- "time"
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
- "github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/osutil"
"google.golang.org/grpc"
- "google.golang.org/grpc/metadata"
- "google.golang.org/protobuf/types/known/durationpb"
- "google.golang.org/protobuf/types/known/emptypb"
)
func main() {
l := slogutil.New(nil)
const listenAddr = "localhost:6062"
+
lsnr, err := net.Listen("tcp", listenAddr)
if err != nil {
l.Error("getting listener", slogutil.KeyError, err)
@@ -36,10 +25,14 @@ func main() {
}
grpcSrv := grpc.NewServer()
- srv := &mockDNSServiceServer{
- log: slogutil.New(nil),
- }
- backendpb.RegisterDNSServiceServer(grpcSrv, srv)
+ dnsSrv := newMockDNSServiceServer(l.With(slogutil.KeyPrefix, "dns"))
+ backendpb.RegisterDNSServiceServer(grpcSrv, dnsSrv)
+
+ kvSrv := newMockRemoteKVServiceServer(l.With(slogutil.KeyPrefix, "remote_kv"))
+ backendpb.RegisterRemoteKVServiceServer(grpcSrv, kvSrv)
+
+ rateLimitSrv := newMockRateLimitServiceServer(l.With(slogutil.KeyPrefix, "rate_limiter"))
+ backendpb.RegisterRateLimitServiceServer(grpcSrv, rateLimitSrv)
l.Info("staring serving", "laddr", listenAddr)
err = grpcSrv.Serve(lsnr)
@@ -49,178 +42,3 @@ func main() {
os.Exit(osutil.ExitCodeFailure)
}
}
-
-// mockDNSServiceServer is the mock [backendpb.DNSServiceServer].
-type mockDNSServiceServer struct {
- backendpb.UnimplementedDNSServiceServer
- log *slog.Logger
-}
-
-// type check
-var _ backendpb.DNSServiceServer = (*mockDNSServiceServer)(nil)
-
-// CreateDeviceByHumanId implements the [backendpb.DNSServiceServer] interface
-// for *mockDNSServiceServer.
-//
-//lint:ignore ST1003 The name is necessary for the interface.
-func (s *mockDNSServiceServer) CreateDeviceByHumanId(
- ctx context.Context,
- req *backendpb.CreateDeviceRequest,
-) (resp *backendpb.CreateDeviceResponse, err error) {
- md, _ := metadata.FromIncomingContext(ctx)
- s.log.InfoContext(
- ctx,
- "creating by id",
- "auth", md.Get(httphdr.Authorization),
- "req", req,
- )
-
- p := newDNSProfile()
-
- return &backendpb.CreateDeviceResponse{
- Device: p.Devices[1],
- }, nil
-}
-
-// GetDNSProfiles implements the [backendpb.DNSServiceServer] interface for
-// *mockDNSServiceServer
-func (s *mockDNSServiceServer) GetDNSProfiles(
- req *backendpb.DNSProfilesRequest,
- srv grpc.ServerStreamingServer[backendpb.DNSProfile],
-) (err error) {
- ctx := srv.Context()
- md, _ := metadata.FromIncomingContext(ctx)
- s.log.InfoContext(
- ctx,
- "getting dns profiles",
- "auth", md.Get(httphdr.Authorization),
- "sync_time", req.SyncTime.AsTime(),
- )
-
- t := time.Now()
- syncTime := strconv.FormatInt(t.UnixMilli(), 10)
- trailerMD := metadata.MD{
- "sync_time": []string{syncTime},
- }
-
- srv.SetTrailer(trailerMD)
- err = srv.Send(newDNSProfile())
- if err != nil {
- s.log.WarnContext(ctx, "sending dns profile", slogutil.KeyError, err)
- }
-
- return nil
-}
-
-// SaveDevicesBillingStat implements the [backendpb.DNSServiceServer] interface
-// for *mockDNSServiceServer
-func (s *mockDNSServiceServer) SaveDevicesBillingStat(
- srv grpc.ClientStreamingServer[backendpb.DeviceBillingStat, emptypb.Empty],
-) (err error) {
- ctx := srv.Context()
- md, _ := metadata.FromIncomingContext(ctx)
- s.log.InfoContext(ctx, "saving devices", "auth", md.Get(httphdr.Authorization))
-
- for {
- var bs *backendpb.DeviceBillingStat
- bs, err = srv.Recv()
- if err != nil {
- if errors.Is(err, io.EOF) {
- return srv.SendAndClose(&emptypb.Empty{})
- } else {
- return fmt.Errorf("receiving billing stat: %w", err)
- }
- }
-
- s.log.InfoContext(ctx, "saving billing stat", "device_id", bs.DeviceId)
- }
-}
-
-// newDNSProfile returns a mock instance of [*backendpb.DNSProfile].
-func newDNSProfile() (dp *backendpb.DNSProfile) {
- dayRange := &backendpb.DayRange{
- Start: durationpb.New(0),
- End: durationpb.New(59 * time.Minute),
- }
-
- devices := []*backendpb.DeviceSettings{{
- Id: "test",
- Name: "test-name",
- FilteringEnabled: false,
- LinkedIp: []byte{1, 1, 1, 1},
- DedicatedIps: [][]byte{{127, 0, 0, 1}},
- }, {
- Id: "auto",
- Name: "My Device X-10",
- HumanIdLower: "my-device-x--10",
- }}
-
- return &backendpb.DNSProfile{
- DnsId: "mock1234",
- FilteringEnabled: true,
- QueryLogEnabled: true,
- Deleted: false,
- AutoDevicesEnabled: true,
- IpLogEnabled: true,
- SafeBrowsing: &backendpb.SafeBrowsingSettings{
- Enabled: true,
- BlockDangerousDomains: true,
- BlockNrd: false,
- },
- Parental: &backendpb.ParentalSettings{
- Enabled: false,
- BlockAdult: false,
- GeneralSafeSearch: false,
- YoutubeSafeSearch: false,
- BlockedServices: []string{"youtube"},
- Schedule: &backendpb.ScheduleSettings{
- Tmz: "GMT",
- WeeklyRange: &backendpb.WeeklyRange{
- Sun: nil,
- Mon: dayRange,
- Tue: dayRange,
- Wed: dayRange,
- Thu: dayRange,
- Fri: dayRange,
- Sat: nil,
- },
- },
- },
- Access: &backendpb.AccessSettings{
- AllowlistCidr: []*backendpb.CidrRange{{
- Address: netip.MustParseAddr("1.1.1.0").AsSlice(),
- Prefix: 24,
- }},
- BlocklistCidr: []*backendpb.CidrRange{{
- Address: netip.MustParseAddr("2.2.2.0").AsSlice(),
- Prefix: 24,
- }},
- AllowlistAsn: []uint32{1},
- BlocklistAsn: []uint32{2},
- BlocklistDomainRules: []string{"block.test"},
- Enabled: true,
- },
- RuleLists: &backendpb.RuleListsSettings{
- Enabled: true,
- Ids: []string{"1"},
- },
- Devices: devices,
- CustomRules: []string{"||example.org^"},
- FilteredResponseTtl: durationpb.New(10 * time.Second),
- BlockPrivateRelay: true,
- BlockFirefoxCanary: true,
- BlockingMode: &backendpb.DNSProfile_BlockingModeCustomIp{
- BlockingModeCustomIp: &backendpb.BlockingModeCustomIP{
- Ipv4: []byte{1, 2, 3, 4},
- },
- },
- RateLimit: &backendpb.RateLimitSettings{
- ClientCidr: []*backendpb.CidrRange{{
- Address: netip.MustParseAddr("3.3.3.0").AsSlice(),
- Prefix: 24,
- }},
- Rps: 100,
- Enabled: true,
- },
- }
-}
diff --git a/scripts/backend/ratelimiter.go b/scripts/backend/ratelimiter.go
new file mode 100644
index 0000000..b41decb
--- /dev/null
+++ b/scripts/backend/ratelimiter.go
@@ -0,0 +1,51 @@
+package main
+
+import (
+ "context"
+ "log/slog"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
+ "github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/netutil"
+ "google.golang.org/grpc/metadata"
+)
+
+// mockRateLimitServiceServer is the mock [backendpb.RateLimiteServiceServer].
+type mockRateLimitServiceServer struct {
+ backendpb.UnimplementedRateLimitServiceServer
+ log *slog.Logger
+}
+
+// newMockRateLimitServiceServer creates a new instance of
+// *mockRateLimitServiceServer.
+func newMockRateLimitServiceServer(log *slog.Logger) (srv *mockRateLimitServiceServer) {
+ return &mockRateLimitServiceServer{
+ log: log,
+ }
+}
+
+// type check
+var _ backendpb.RateLimitServiceServer = (*mockRateLimitServiceServer)(nil)
+
+// Get implements the [backendpb.RateLimitServiceServer] interface for
+// *mockRateLimitServiceServer.
+func (s *mockRateLimitServiceServer) GetRateLimitSettings(
+ ctx context.Context,
+ req *backendpb.RateLimitSettingsRequest,
+) (resp *backendpb.RateLimitSettingsResponse, err error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+
+ s.log.InfoContext(
+ ctx,
+ "getting",
+ "auth", md.Get(httphdr.Authorization),
+ "req", req,
+ )
+
+ return &backendpb.RateLimitSettingsResponse{
+ AllowedSubnets: []*backendpb.CidrRange{{
+ Address: netutil.IPv4Localhost().AsSlice(),
+ Prefix: 8,
+ }},
+ }, nil
+}
diff --git a/scripts/backend/remotekv.go b/scripts/backend/remotekv.go
new file mode 100644
index 0000000..53ce6e6
--- /dev/null
+++ b/scripts/backend/remotekv.go
@@ -0,0 +1,83 @@
+package main
+
+import (
+ "context"
+ "log/slog"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
+ "github.com/AdguardTeam/golibs/httphdr"
+ "github.com/patrickmn/go-cache"
+ "google.golang.org/grpc/metadata"
+)
+
+// mockRemoteKVServiceServer is the mock [backendpb.RemoteKVServiceServer].
+type mockRemoteKVServiceServer struct {
+ backendpb.UnimplementedRemoteKVServiceServer
+ log *slog.Logger
+ strg *cache.Cache
+}
+
+// newMockRemoteKVServiceServer creates a new instance of
+// *mockRemoteKVServiceServer.
+func newMockRemoteKVServiceServer(log *slog.Logger) (srv *mockRemoteKVServiceServer) {
+ const (
+ defaultCacheExp = 30 * time.Second
+ defaultCacheGC = 1 * time.Minute
+ )
+
+ return &mockRemoteKVServiceServer{
+ log: log,
+ strg: cache.New(defaultCacheExp, defaultCacheGC),
+ }
+}
+
+// type check
+var _ backendpb.RemoteKVServiceServer = (*mockRemoteKVServiceServer)(nil)
+
+// Get implements the [backendpb.RemoteKVServiceServer] interface for
+// *mockRemoteKVServiceServer.
+func (s *mockRemoteKVServiceServer) Get(
+ ctx context.Context,
+ req *backendpb.RemoteKVGetRequest,
+) (resp *backendpb.RemoteKVGetResponse, err error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ s.log.InfoContext(
+ ctx,
+ "getting",
+ "auth", md.Get(httphdr.Authorization),
+ "req", req,
+ )
+
+ resp = &backendpb.RemoteKVGetResponse{
+ Value: &backendpb.RemoteKVGetResponse_Empty{},
+ }
+
+ val, ok := s.strg.Get(req.Key)
+ if ok {
+ resp.Value = &backendpb.RemoteKVGetResponse_Data{
+ Data: val.([]byte),
+ }
+ }
+
+ return resp, nil
+}
+
+// Set implements the [backendpb.RemoteKVServiceServer] interface for
+// *mockRemoteKVServiceServer.
+func (s *mockRemoteKVServiceServer) Set(
+ ctx context.Context,
+ req *backendpb.RemoteKVSetRequest,
+) (resp *backendpb.RemoteKVSetResponse, err error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ s.log.InfoContext(
+ ctx,
+ "setting",
+ "auth", md.Get(httphdr.Authorization),
+ "req", req,
+ )
+
+ s.strg.Set(req.Key, req.Data, req.Ttl.AsDuration())
+
+ return &backendpb.RemoteKVSetResponse{}, err
+}