diff --git a/CHANGELOG.md b/CHANGELOG.md
index 51a89fa..76c5805 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,61 +1,45 @@
- # AdGuard DNS Changelog
+# AdGuard DNS changelog
-All notable environment, configuration file, and other changes to this project
-will be documented in this file.
+All notable environment, configuration file, and other changes to this project will be documented in this file.
-The format is **not** based on [Keep a Changelog][kec], since the project
-**doesn't** currently adhere to [Semantic Versioning][sem].
+The format is **not** based on [Keep a Changelog][kec], since the project **doesn't** currently adhere to [Semantic Versioning][sem].
[kec]: https://keepachangelog.com/en/1.0.0/
[sem]: https://semver.org/spec/v2.0.0.html
+## AGDNS-2254 / Build 779
+- The environment variables `BILLSTAT_API_KEY` and `PROFILES_API_KEY` have been added.
-## AGDNS-2048 / Build 750
+## AGDNS-2172 / Build 776
- * The environment variables `RESEARCH_LOGS` and `RESEARCH_METRICS` have been
- removed.
+- The version of the profile cache file has been incremented.
+## AGDNS-2048 / Build 750
+- The environment variables `RESEARCH_LOGS` and `RESEARCH_METRICS` have been removed.
-## AGDNS-2022 / Build 746
+## AGDNS-2022 / Build 746
- * The property `block_page_redirect` of objects within `server_groups` array
- has been removed.
+- The property `block_page_redirect` of objects within `server_groups` array has been removed.
+## AGDNS-1981 / Build 744
+- The objects within `server_groups` array had a change in their `block_page_redirect` configuration, it now supports arrays of IP addresses in `ipv4` and `ipv6` fields.
-## AGDNS-1981 / Build 744
+- Profile's file cache version was incremented. In case of `BlockingModeCustomIP` the `profile.blocking_mode` IPv4/IPv6 fields are now arrays of IP addresses.
- * The objects within `server_groups` array had a change in their
- `block_page_redirect` configuration, it now supports arrays of IP addresses
- in `ipv4` and `ipv6` fields.
+## AGDNS-2012 / Build 732
- * Profile's file cache version was incremented. In case of
- `BlockingModeCustomIP` the `profile.blocking_mode` IPv4/IPv6 fields are now
- arrays of IP addresses.
+- The querylog now has a new field, `"rn"`, which is a 16-bit unsigned random number. Field `"u"`, the unique request ID, is deprecated and may be removed in the future.
+## AGDNS-1879 / Build 729
+- Profile's file cache version was incremented. The new field `authentication` has been added to profile's device object.
-## AGDNS-2012 / Build 732
+## AGDNS-1934 / Build 728
- * The querylog now has a new field, `"rn"`, which is a 16-bit unsigned random
- number. Field `"u"`, the unique request ID, is deprecated and may be
- removed in the future.
-
-
-
-## AGDNS-1879 / Build 729
-
- * Profile's file cache version was incremented. The new field
- `authentication` has been added to profile's device object.
-
-
-
-## AGDNS-1934 / Build 728
-
- * The object `filters` has new properties: `index_refresh_timeout`, and
- `rule_list_refresh_timeout`. So replace this:
+- The object `filters` has new properties: `index_refresh_timeout`, and `rule_list_refresh_timeout`. So replace this:
```yaml
filters:
@@ -71,8 +55,7 @@ The format is **not** based on [Keep a Changelog][kec], since the project
rule_list_refresh_timeout: 1m
```
- * The objects `safe_browsing` and `adult_blocking` have a new property:
- `refresh_timeout`. So replace this:
+- The objects `safe_browsing` and `adult_blocking` have a new property: `refresh_timeout`. So replace this:
```yaml
safe_browsing:
@@ -94,19 +77,13 @@ The format is **not** based on [Keep a Changelog][kec], since the project
refresh_timeout: 1m
```
+## AGDNS-1954 / Build 726
+- The object `web` has a new optional property, `general_blocking`. Its format is the same as in `adult_blocking` and `safe_browsing`.
-## AGDNS-1954 / Build 726
+## AGDNS-1954 / Build 719
- * The object `web` has a new optional property, `general_blocking`. Its
- format is the same as in `adult_blocking` and `safe_browsing`.
-
-
-
-## AGDNS-1954 / Build 719
-
- * The objects within `server_groups` array have a new property
- `block_page_redirect`:
+- The objects within `server_groups` array have a new property `block_page_redirect`:
```yaml
block_page_redirect:
@@ -139,25 +116,13 @@ The format is **not** based on [Keep a Changelog][kec], since the project
enabled: false
```
+## AGDNS-1888 / Build 717
+- The new environment variable `PROFILES_ENABLED` has been added. With `0` value it disables user profiles and devices recognition, and billing. Its default value is `1`. Adjust the value, if necessary.
-## AGDNS-1888 / Build 717
+## AGDNS-1761 / Build 702
- * The new environment variable `PROFILES_ENABLED` has been added. With `0`
- value it disables user profiles and devices recognition, and billing. Its
- default value is `1`. Adjust the value, if necessary.
-
-
-
-## AGDNS-1761 / Build 702
-
- * The property `upstream` has been modified. Its property `timeout` has been
- replaced with the new property `servers.timeout` for each server in the
- `servers` list. Concomitantly the `fallback.timeout` has been replaced with
- `fallback.servers.timeout` for each fallback server. The `fallback.servers`
- now supports not only the addresses of the servers, but URLs in the
- `[scheme://]ip:port` format like it's done with the main servers. So replace
- this:
+- The property `upstream` has been modified. Its property `timeout` has been replaced with the new property `servers.timeout` for each server in the `servers` list. Concomitantly the `fallback.timeout` has been replaced with `fallback.servers.timeout` for each fallback server. The `fallback.servers` now supports not only the addresses of the servers, but URLs in the `[scheme://]ip:port` format like it's done with the main servers. So replace this:
```yaml
upstream:
@@ -190,12 +155,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the value and add new ones, if necessary.
+## AGDNS-698 / Build 701
-
-## AGDNS-698 / Build 701
-
- * The object `dns` has new properties: `read_timeout`, `tcp_idle_timeout`, and
- `write_timeout`. So replace this:
+- The object `dns` has new properties: `read_timeout`, `tcp_idle_timeout`, and `write_timeout`. So replace this:
```yaml
dns:
@@ -215,13 +177,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
The values in the example are previous defaults.
+## AGDNS-1751 / Build 691
-
-## AGDNS-1751 / Build 691
-
- * The property `upstream.server` has been removed. Its former content is
- moved to the newly added property `servers`, which now extended to contain
- a list of URLs of main upstream servers. So replace this:
+- The property `upstream.server` has been removed. Its former content is moved to the newly added property `servers`, which now extended to contain a list of URLs of main upstream servers. So replace this:
```yaml
upstream:
@@ -240,12 +198,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the value and add new ones, if necessary.
+## AGDNS-1759 / Build 684
-
-## AGDNS-1759 / Build 684
-
- * The object `backend` has a new property, `full_refresh_retry_interval`. So
- replace this:
+- The object `backend` has a new property, `full_refresh_retry_interval`. So replace this:
```yaml
backend:
@@ -264,20 +219,13 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the value, if necessary.
+## AGDNS-1744 / Build 681
+- Metric `forward_request_total` has a new label `network`. This label describes the network type (`tcp` or `udp`), over which an upstream has finished processing request.
-## AGDNS-1744 / Build 681
+## AGDNS-1738 / Build 678
- * Metric `forward_request_total` has a new label `network`. This label
- describes the network type (`tcp` or `udp`), over which an upstream has
- finished processing request.
-
-
-
-## AGDNS-1738 / Build 678
-
- * Object `dns` has a new property, describing maximum size of DNS response
- over UDP protocol.
+- Object `dns` has a new property, describing maximum size of DNS response over UDP protocol.
```yaml
dns:
@@ -285,14 +233,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
handle_timeout: 1s
```
+## AGDNS-1735 / Build 677
-
-## AGDNS-1735 / Build 677
-
- * The property `upstream.fallback` has been changed. Its former content is
- moved to the newly added property `servers`. The new property `timeout`,
- which describes query timeout to fallback servers, was added. So replace
- this:
+- The property `upstream.fallback` has been changed. Its former content is moved to the newly added property `servers`. The new property `timeout`, which describes query timeout to fallback servers, was added. So replace this:
```yaml
upstream:
@@ -312,27 +255,20 @@ The format is **not** based on [Keep a Changelog][kec], since the project
timeout: 1s
```
- Adjust the new values, if necessary. Note that the query timeout to fallback
- servers was previously defined with `upstream.timeout` property, which now
- describes the query timeout to the primary servers only.
+ Adjust the new values, if necessary. Note that the query timeout to fallback servers was previously defined with `upstream.timeout` property, which now describes the query timeout to the primary servers only.
+## AGDNS-1178 / Build 676
-
-## AGDNS-1178 / Build 676
-
- * The new object `dns` has been added:
+- The new object `dns` has been added:
```yaml
dns:
handle_timeout: 1s
```
+## AGDNS-1620 / Build 673
-
-## AGDNS-1620 / Build 673
-
- * Object `ratelimit` has two new properties: `quic` and `tcp`. They configure
- QUIC and TCP connection limits. Example configuration:
+- Object `ratelimit` has two new properties: `quic` and `tcp`. They configure QUIC and TCP connection limits. Example configuration:
```yaml
ratelimit:
@@ -345,27 +281,17 @@ The format is **not** based on [Keep a Changelog][kec], since the project
max_pipeline_count: 100
```
+## AGDNS-1684 / Build 661
+- Profile's file cache version was incremented. The new field `access` has been added.
-## AGDNS-1684 / Build 661
+## AGDNS-1664 / Build 636
- * Profile's file cache version was incremented. The new field `access` has
- been added.
+- The environment variables `BILLSTAT_URL` and `PROFILES_URL` no longer support HTTP(s) endpoints. Use GRPC(S) instead.
+## AGDNS-1667 / Build 633
-
-## AGDNS-1664 / Build 636
-
- * The environment variables `BILLSTAT_URL` and `PROFILES_URL` no longer
- support HTTP(s) endpoints. Use GRPC(S) instead.
-
-
-
-## AGDNS-1667 / Build 633
-
-* `ratelimit` configuration properties `back_off_count`, `back_off_duration`
- and `back_off_period` have been renamed to `backoff_count`,
- `backoff_duration` and `backoff_period`. So replace this:
+- `ratelimit` configuration properties `back_off_count`, `back_off_duration` and `back_off_period` have been renamed to `backoff_count`, `backoff_duration` and `backoff_period`. So replace this:
```yaml
ratelimit:
@@ -383,13 +309,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
backoff_duration: 30m
```
+## AGDNS-1607 / Build 617
-
-## AGDNS-1607 / Build 617
-
- * New configuration `access` has been added, it has an a list of AdBlock rules
- to block requests, and a lists of client subnets to block access from.
- Example configuration:
+- New configuration `access` has been added, it has an a list of AdBlock rules to block requests, and a lists of client subnets to block access from. Example configuration:
```yaml
access:
@@ -401,38 +323,23 @@ The format is **not** based on [Keep a Changelog][kec], since the project
- '2.2.2.0/8'
```
+## AGDNS-1619 / Build 611
+- Added a new metric `bill_stat_upload_duration` that counts the duration of billing statistics upload.
-## AGDNS-1619 / Build 611
+- The environment variable `BILLSTAT_URL`, which describes the endpoint for backend billing statistics uploader API, now supports GRPC endpoints.
- * Added a new metric `bill_stat_upload_duration` that counts the duration of
- billing statistics upload.
+## AGDNS-1600 / Build 582
- * The environment variable `BILLSTAT_URL`, which describes the endpoint for
- backend billing statistics uploader API, now supports GRPC endpoints.
+- The environment variable `PROFILES_CACHE_PATH` no longer supports JSON files. Use protobuf with `.pb` extension instead. The default value has been changed to `./profilecache.pb`.
+## AGDNS-1539 / Build 581
+- The environment variable `PROFILES_URL`, which describes the endpoint for profiles sync API, now supports GRPC endpoints.
-## AGDNS-1600 / Build 582
+## AGDNS-1579 / Build 580
- * The environment variable `PROFILES_CACHE_PATH` no longer supports JSON
- files. Use protobuf with `.pb` extension instead. The default value has
- been changed to `./profilecache.pb`.
-
-
-
-## AGDNS-1539 / Build 581
-
- * The environment variable `PROFILES_URL`, which describes the endpoint for
- profiles sync API, now supports GRPC endpoints.
-
-
-
-## AGDNS-1579 / Build 580
-
- * The optional property `bind_interfaces` of `server_groups.*.servers`
- objects has been changed, property `subnet` is now an array and has been
- renamed to `subnets`. So replace this:
+- The optional property `bind_interfaces` of `server_groups.*.servers` objects has been changed, property `subnet` is now an array and has been renamed to `subnets`. So replace this:
```yaml
bind_interfaces:
@@ -460,23 +367,15 @@ The format is **not** based on [Keep a Changelog][kec], since the project
- '10.0.0.1/32'
```
+## AGDNS-1537 / Build 566
+- The configuration property `filtering_groups.safe_browsing` has been changed, new properties have been added: `block_dangerous_domains` and `block_newly_registered_domains`.
-## AGDNS-1537 / Build 566
+## AGDNS-1580 / Build 562
- * The configuration property `filtering_groups.safe_browsing` has been changed,
- new properties have been added: `block_dangerous_domains` and
- `block_newly_registered_domains`.
+- The environment variable `DNSDB_PATH` has been removed.
-
-
-## AGDNS-1580 / Build 562
-
- * The environment variable `DNSDB_PATH` has been removed.
-
- * New configuration `dnsdb` has been added, it has an enabled/disabled flag
- and the property `max_size` which describes the maximum amount of records in
- the in-memory buffer. Example configuration:
+- New configuration `dnsdb` has been added, it has an enabled/disabled flag and the property `max_size` which describes the maximum amount of records in the in-memory buffer. Example configuration:
```yaml
dnsdb:
@@ -484,35 +383,23 @@ The format is **not** based on [Keep a Changelog][kec], since the project
max_size: 500000
```
+## AGDNS-1537 / Build 559
+- Configuration properties `safe_browsing.url` and `adult_blocking.url` are now removed. Use newly added environment variables `ADULT_BLOCKING_URL` and `SAFE_BROWSING_URL`.
-## AGDNS-1537 / Build 559
+- New environment variable `NEW_REG_DOMAINS_URL` has been added, this is the link to the source list of the newly registered domains.
- * Configuration properties `safe_browsing.url` and `adult_blocking.url` are
- now removed. Use newly added environment variables `ADULT_BLOCKING_URL` and
- `SAFE_BROWSING_URL`.
- * New environment variable `NEW_REG_DOMAINS_URL` has been added, this is the
- link to the source list of the newly registered domains.
+## AGDNS-1567 / Build 557
+- The environment variable `BACKEND_ENDPOINT` was replaced with three environment variables:
+ - `LINKED_IP_TARGET_URL`: the target URL to which linked IP API requests are proxied.
+ - `PROFILES_URL`: the endpoint for profiles sync API.
+ - `BILLSTAT_URL`: the endpoint for backend billing statistics uploader.
-## AGDNS-1567 / Build 557
+## AGDNS-1561 / Build 554
- * The environment variable `BACKEND_ENDPOINT` was replaced with three
- environment variables:
-
- * `LINKED_IP_TARGET_URL`: the target URL to which linked IP API requests
- are proxied.
- * `PROFILES_URL`: the endpoint for profiles sync API.
- * `BILLSTAT_URL`: the endpoint for backend billing statistics uploader.
-
-
-
-## AGDNS-1561 / Build 554
-
- * The `filters` object has a new property, `max_size`, which describes the
- maximum size of the downloadable content for a rule-list in a human-readable
- format. Example configuration:
+- The `filters` object has a new property, `max_size`, which describes the maximum size of the downloadable content for a rule-list in a human-readable format. Example configuration:
```yaml
filters:
@@ -520,12 +407,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
max_size: 256MB
```
+## AGDNS-1561 / Build 550
-
-## AGDNS-1561 / Build 550
-
- * Properties `so_sndbuf` and `so_rcvbuf` of object `network` have been changed.
- Now they are in a human-readable format. Example configuration:
+- Properties `so_sndbuf` and `so_rcvbuf` of object `network` have been changed. Now they are in a human-readable format. Example configuration:
```yaml
network:
@@ -533,10 +417,7 @@ The format is **not** based on [Keep a Changelog][kec], since the project
so_rcvbuf: 0
```
- * The object `filters` has been changed. Two properties,
- `rule_list_cache_size` and `use_rule_list_cache` have been extracted to the
- new object `rule_list_cache` and renamed to `size` and `enabled`. So
- replace this:
+- The object `filters` has been changed. Two properties, `rule_list_cache_size` and `use_rule_list_cache` have been extracted to the new object `rule_list_cache` and renamed to `size` and `enabled`. So replace this:
```yaml
filters:
@@ -565,29 +446,15 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the values, if necessary.
+## AGDNS-1566 / Build 549
+- There is now a new env variable `RESEARCH_LOGS` that controls whether logging of additional info for research purposes is enabled. These log records can be filtered out by `research:` prefix. The default value is `0`, i.e. additional logging is disabled. The first thing that is logged in this version is domains which responses have ECH config. The log will only be recorded when both `RESEARCH_LOGS` and `RESEARCH_METRICS` are set to `1`.
-## AGDNS-1566 / Build 549
+- Added a new research metric `dns_research_response_ech` that counts the number of responses with a ECH configuration.
- * There is now a new env variable `RESEARCH_LOGS` that controls whether
- logging of additional info for research purposes is enabled. These log
- records can be filtered out by `research:` prefix. The default value is
- `0`, i.e. additional logging is disabled. The first thing that is logged
- in this version is domains which responses have ECH config. The log will
- only be recorded when both `RESEARCH_LOGS` and `RESEARCH_METRICS` are set
- to `1`.
+## AGDNS-1556 / Build 547
- * Added a new research metric `dns_research_response_ech` that counts the
- number of responses with a ECH configuration.
-
-
-
-## AGDNS-1556 / Build 547
-
- * The object `cache` has a new property `ttl_override`. It describes the TTL
- override settings, such as the minimum TTL for cache items and the `enabled`
- switch. It overwrites the TTL from DNS response in case it's less than this
- minimum value. So replace this:
+- The object `cache` has a new property `ttl_override`. It describes the TTL override settings, such as the minimum TTL for cache items and the `enabled` switch. It overwrites the TTL from DNS response in case it's less than this minimum value. So replace this:
```yaml
cache:
@@ -611,12 +478,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the values, if necessary.
+## AGDNS-1498 / Build 527
-
-## AGDNS-1498 / Build 527
-
- * Object `ratelimit` has a new property, `connection_limit`, which allows
- setting stream-connection limits. Example configuration:
+- Object `ratelimit` has a new property, `connection_limit`, which allows setting stream-connection limits. Example configuration:
```yaml
ratelimit:
@@ -627,20 +491,13 @@ The format is **not** based on [Keep a Changelog][kec], since the project
resume: 800
```
+## AGDNS-1383 / Build 525
+- The environment variable `PROFILES_CACHE_PATH` is now sensitive to the file extension. Use `.json` for the previous behavior of encoding the cache into a JSON file or `.pb` for encoding it into protobuf. Other extensions are invalid.
-## AGDNS-1383 / Build 525
+## AGDNS-1381 / Build 518
- * The environment variable `PROFILES_CACHE_PATH` is now sensitive to the file
- extension. Use `.json` for the previous behavior of encoding the cache into
- a JSON file or `.pb` for encoding it into protobuf. Other extensions are
- invalid.
-
-
-
-## AGDNS-1381 / Build 518
-
- * The new object `network` has been added:
+- The new object `network` has been added:
```yaml
network:
@@ -648,32 +505,21 @@ The format is **not** based on [Keep a Changelog][kec], since the project
so_rcvbuf: 0
```
+## AGDNS-1383 / Build 515
+- The environment variable `PROFILES_CACHE_PATH` now has a new special value, `none`, which disables profile caching entirely. The default value of `./profilecache.json` has not been changed.
-## AGDNS-1383 / Build 515
+## AGDNS-1479 / Build 513
- * The environment variable `PROFILES_CACHE_PATH` now has a new special value,
- `none`, which disables profile caching entirely. The default value of
- `./profilecache.json` has not been changed.
+- The profile-cache version has been changed to `6`. Versions of the profile cache from `3` to `5` are invalid and should not be reused.
+## AGDNS-1473 / Build 506
+- The profile-cache version has been changed to `5`.
-## AGDNS-1479 / Build 513
+## AGDNS-1247 / Build 484
- * The profile-cache version has been changed to `6`. Versions of the profile
- cache from `3` to `5` are invalid and should not be reused.
-
-
-
-## AGDNS-1473 / Build 506
-
- * The profile-cache version has been changed to `5`.
-
-
-
-## AGDNS-1247 / Build 484
-
- * The new object `interface_listeners` has been added:
+- The new object `interface_listeners` has been added:
```yaml
interface_listeners:
@@ -687,8 +533,7 @@ The format is **not** based on [Keep a Changelog][kec], since the project
port': 5353
```
- * The objects within the `server_groups.*.servers` array have a new optional
- property, `bind_interfaces`:
+- The objects within the `server_groups.*.servers` array have a new optional property, `bind_interfaces`:
```yaml
server_groups:
@@ -706,28 +551,17 @@ The format is **not** based on [Keep a Changelog][kec], since the project
It is mutually exclusive with the current `bind_addresses` field.
+## AGDNS-1406 / Build 480
-
-## AGDNS-1406 / Build 480
-
- * The default behavior of the environment variable `DNSDB_PATH` has been
- changed. Previously, if the variable was unset then the default value,
- `./dnsdb.bolt`, was used, but if it was an empty string, DNSDB was disabled.
- Now both unset and empty value disable DNSDB, which is consistent with the
- documentation.
+- The default behavior of the environment variable `DNSDB_PATH` has been changed. Previously, if the variable was unset then the default value, `./dnsdb.bolt`, was used, but if it was an empty string, DNSDB was disabled. Now both unset and empty value disable DNSDB, which is consistent with the documentation.
This means that DNSDB is disabled by default.
- * The default configuration file path has been changed from `config.yml` to
- ./config.yaml
for consistency with other
- services.
+- The default configuration file path has been changed from `config.yml` to ./config.yaml
for consistency with other services.
+## AGDNS-916 / Build 456
-
-## AGDNS-916 / Build 456
-
- * `ratelimit` now defines rate of requests per second for IPv4 and IPv6
- addresses separately. So replace this:
+- `ratelimit` now defines rate of requests per second for IPv4 and IPv6 addresses separately. So replace this:
```yaml
ratelimit:
@@ -748,12 +582,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
subnet_key_len: 48
```
+## AGDNS-907 / Build 449
-
-## AGDNS-907 / Build 449
-
- * The objects within the `filtering_groups` have a new property,
- `block_firefox_canary`. So replace this:
+- The objects within the `filtering_groups` have a new property, `block_firefox_canary`. So replace this:
```yaml
filtering_groups:
@@ -774,23 +605,13 @@ The format is **not** based on [Keep a Changelog][kec], since the project
The recommended default value is `true`.
+## AGDNS-1308 / Build 447
+- There is now a new env variable `RESEARCH_METRICS` that controls whether collecting research metrics is enabled or not. Also, the first research metric is added: `dns_research_blocked_per_country_total`, it counts the number of blocked requests per country. Its default value is `0`, i.e. research metrics collection is disabled by default.
-## AGDNS-1308 / Build 447
+## AGDNS-1051 / Build 443
- * There is now a new env variable `RESEARCH_METRICS` that controls whether
- collecting research metrics is enabled or not. Also, the first research
- metric is added: `dns_research_blocked_per_country_total`, it counts the
- number of blocked requests per country. Its default value is `0`, i.e.
- research metrics collection is disabled by default.
-
-
-
-## AGDNS-1051 / Build 443
-
- * There are two changes in the keys of the `static_content` map. Firstly,
- properties `allow_origin` and `content_type` are removed. Secondly, a new
- property, called `headers`, is added. So replace this:
+- There are two changes in the keys of the `static_content` map. Firstly, properties `allow_origin` and `content_type` are removed. Secondly, a new property, called `headers`, is added. So replace this:
```yaml
static_content:
@@ -815,12 +636,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust or add the values, if necessary.
+## AGDNS-1278 / Build 423
-
-## AGDNS-1278 / Build 423
-
- * The object `filters` has two new properties, `rule_list_cache_size` and
- `use_rule_list_cache`. So replace this:
+- The object `filters` has two new properties, `rule_list_cache_size` and `use_rule_list_cache`. So replace this:
```yaml
filters:
@@ -846,12 +664,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the values, if necessary.
+## AGDNS-1278 / Build 422
-
-## AGDNS-1278 / Build 422
-
- * The object `filters` has a new property, `safe_search_cache_size`. So
- replace this:
+- The object `filters` has a new property, `safe_search_cache_size`. So replace this:
```yaml
filters:
@@ -874,36 +689,21 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the values, if necessary.
+## AGDNS-1174 / Build 397
+- DNS Server Check now responds with NODATA message to all non-A neither non-AAAA requests.
-## AGDNS-1174 / Build 397
+## AGDNS-911 / Build 375
- * DNS Server Check now responds with NODATA message to all non-A neither non-AAAA requests.
+- Added support for running a DoH3 server. No configuration changes are required to run it. If there was a DoH server configured, it will start listening for HTTP/3 connections on the same port where it listens for HTTP/2. Make sure that udp/443 is allowed in the iptables configuration on the server.
+## AGDNS-842 / Build 372
+- The new environment variable `PROFILES_CACHE_PATH` has been added. Its default value is `./profilecache.json`. Adjust the value, if necessary.
-## AGDNS-911 / Build 375
+## AGDNS-891 / Build 371
- * Added support for running a DoH3 server. No configuration changes are
- required to run it. If there was a DoH server configured, it will start
- listening for HTTP/3 connections on the same port where it listens for
- HTTP/2. Make sure that udp/443 is allowed in the iptables configuration on
- the server.
-
-
-
-## AGDNS-842 / Build 372
-
- * The new environment variable `PROFILES_CACHE_PATH` has been added. Its
- default value is `./profilecache.json`. Adjust the value, if necessary.
-
-
-
-## AGDNS-891 / Build 371
-
- * The property `server` of `upstream` object has been changed. Now it
- is a URL optionally starting with `tcp://` or `udp://`, and then an address
- in `ip:port` format.
+- The property `server` of `upstream` object has been changed. Now it is a URL optionally starting with `tcp://` or `udp://`, and then an address in `ip:port` format.
```yaml
upstream:
@@ -912,11 +712,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the value, if necessary.
+## AGDNS-1032 / Build 363
-
-## AGDNS-1032 / Build 363
-
- * The new optional field `static_content.*.allow_origin` has been added:
+- The new optional field `static_content.*.allow_origin` has been added:
```yaml
static_content:
@@ -924,25 +722,18 @@ The format is **not** based on [Keep a Changelog][kec], since the project
allow_origin: '*'
```
+## AGDNS-898 / Build 359
-
-## AGDNS-898 / Build 359
-
- * The new optional object `additional_metrics_info` has been added:
+- The new optional object `additional_metrics_info` has been added:
```yaml
additional_metrics_info:
test_key: 'test_value'
```
+## AGDNS-986 / Build 346
-
-## AGDNS-986 / Build 346
-
- * The new object `upstream.healthcheck` now contains all healthcheck-related
- fields, including the new field `domain_template`. Property
- `upstream.healthcheck_backoff_time` has been moved to
- `upstream.healthcheck.backoff_duration`. So replace this:
+- The new object `upstream.healthcheck` now contains all healthcheck-related fields, including the new field `domain_template`. Property `upstream.healthcheck_backoff_time` has been moved to `upstream.healthcheck.backoff_duration`. So replace this:
```yaml
upstream:
@@ -976,12 +767,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the new value, if necessary.
+## AGDNS-960 / Build 342
-
-## AGDNS-960 / Build 342
-
- * The property `domain` of `check` object has been changed to `domains`.
- So replace this:
+- The property `domain` of `check` object has been changed to `domains`. So replace this:
```yaml
check:
@@ -999,14 +787,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the news values, if necessary.
+## AGDNS-838 / Build 338
-
-## AGDNS-838 / Build 338
-
- * The object `upstream` has new properties, `healthcheck_enabled`,
- `healthcheck_interval`, `healthcheck_timeout`, and
- `healthcheck_backoff_time`.
- So replace this:
+- The object `upstream` has new properties, `healthcheck_enabled`, `healthcheck_interval`, `healthcheck_timeout`, and `healthcheck_backoff_time`. So replace this:
```yaml
upstream:
@@ -1034,20 +817,13 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the new values, if necessary.
+## Build 336
+- The environment variable `SSLKEYLOGFILE` has been renamed to `SSL_KEY_LOG_FILE`.
-## Build 336
+## AGDNS-915 / Build 334
- * The environment variable `SSLKEYLOGFILE` has been renamed to
- `SSL_KEY_LOG_FILE`.
-
-
-
-## AGDNS-915 / Build 334
-
- * The properties `subnet_key_ip_4_mask_len` and `subnet_key_ip_6_mask_len` of
- object `ratelimit` have been renamed to `ipv4_subnet_key_len` and
- `ipv6_subnet_key_len` correspondingly. So replace this:
+- The properties `subnet_key_ip_4_mask_len` and `subnet_key_ip_6_mask_len` of object `ratelimit` have been renamed to `ipv4_subnet_key_len` and `ipv6_subnet_key_len` correspondingly. So replace this:
```yaml
ratelimit:
@@ -1065,12 +841,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
ipv6_subnet_key_len: 48
```
+## AGDNS-915 / Build 333
-
-## AGDNS-915 / Build 333
-
- * The `ratelimit` object has two new properties, `subnet_key_ip_4_mask_len`
- and `subnet_key_ip_6_mask_len`. So replace this:
+- The `ratelimit` object has two new properties, `subnet_key_ip_4_mask_len` and `subnet_key_ip_6_mask_len`. So replace this:
```yaml
ratelimit:
@@ -1086,12 +859,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
subnet_key_ip_6_mask_len: 48
```
+## AGDNS-897 / Build 329
-
-## AGDNS-897 / Build 329
-
- * The objects within the `filtering_groups` have a new property,
- `block_private_relay`.
+- The objects within the `filtering_groups` have a new property, `block_private_relay`.
```yaml
filtering_groups:
@@ -1112,14 +882,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
The recommended default value is `false`.
+## AGDNS-624 / Build 320
-
-## AGDNS-624 / Build 320
-
- * The objects within `server_groups` array had a change in their DDR
- configuration. There was an opinion that the previous configuration was too
- limiting and that denormalized configuration is more self-describing. So
- replace this:
+- The objects within `server_groups` array had a change in their DDR configuration. There was an opinion that the previous configuration was too limiting and that denormalized configuration is more self-describing. So replace this:
```yaml
server_groups:
@@ -1161,14 +926,11 @@ The format is **not** based on [Keep a Changelog][kec], since the project
# …
```
- Adjust the values, if necessary. Make sure to synchronize and keep in sync
- the addresses and ports with the values of the server groups' servers.
+ Adjust the values, if necessary. Make sure to synchronize and keep in sync the addresses and ports with the values of the server groups' servers.
+## AGDNS-624 / Build 317
-
-## AGDNS-624 / Build 317
-
- * The objects within `server_groups` array have a new property `ddr_names`:
+- The objects within `server_groups` array have a new property `ddr_names`:
```yaml
server_groups:
@@ -1179,19 +941,11 @@ The format is **not** based on [Keep a Changelog][kec], since the project
# …
```
- It is empty by default. These values will be used for constructing a
- response for Discovery of Designated Resolvers. Empty value leads to a
- NODATA response. Adjust the new value, if necessary.
+ It is empty by default. These values will be used for constructing a response for Discovery of Designated Resolvers. Empty value leads to a NODATA response. Adjust the new value, if necessary.
+## AGDNS-624 / Build 314
-
-## AGDNS-624 / Build 314
-
- * The property `tls` of objects within the `server_groups.*.servers.*` array
- has been moved to the `server_group` object becoming common for the whole
- group. Any group having at least a single server of DoH/DoT/DoQ protocols
- will require the `tls` property specified. Any group having no encrypted
- resolvers will require the `tls` property absence. So replace this:
+- The property `tls` of objects within the `server_groups.*.servers.*` array has been moved to the `server_group` object becoming common for the whole group. Any group having at least a single server of DoH/DoT/DoQ protocols will require the `tls` property specified. Any group having no encrypted resolvers will require the `tls` property absence. So replace this:
```yaml
server_groups:
@@ -1223,11 +977,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the new value, if necessary.
+## AGDNS-829 / Build 308
-
-## AGDNS-829 / Build 308
-
- * The object `upstream` has a new property, `timeout`. So replace this:
+- The object `upstream` has a new property, `timeout`. So replace this:
```yaml
upstream:
@@ -1250,11 +1002,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the new value, if necessary.
+## AGDNS-286 / Build 307
-
-## AGDNS-286 / Build 307
-
- * The new object `connectivity_check` has been added:
+- The new object `connectivity_check` has been added:
```yaml
connectivity_check:
@@ -1262,12 +1012,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
probe_ipv6: '[2001:4860:4860::8888]:53'
```
+## AGDNS-745 / Build 298
-
-## AGDNS-745 / Build 298
-
- * The object `filters` has a new property, `refresh_timeout`. So replace
- this:
+- The object `filters` has a new property, `refresh_timeout`. So replace this:
```yaml
filters:
@@ -1288,12 +1035,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the values, if necessary.
+## AGDNS-608 / Build 273
-
-## AGDNS-608 / Build 273
-
- * The object `cache` has two new properties, `type` and `ecs_size`. So
- replace this:
+- The object `cache` has two new properties, `type` and `ecs_size`. So replace this:
```yaml
cache:
@@ -1311,34 +1055,22 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the values, if necessary.
+## AGDNS-327 / Build 259
-
-## AGDNS-327 / Build 259
-
- * Prometheus metric `dns_tls_handshake_total` has been updated with
- `server_name` label. This label represents "Server Name Indication"
- identifiers, grouped by endpoint identifier and known server names. All
- unknown server names are grouped in `other` label:
+- Prometheus metric `dns_tls_handshake_total` has been updated with `server_name` label. This label represents "Server Name Indication" identifiers, grouped by endpoint identifier and known server names. All unknown server names are grouped in `other` label:
```none
# TYPE dns_tls_handshake_total counter
dns_tls_handshake_total{cipher_suite="TLS_AES_128_GCM_SHA256",did_resume="0",negotiated_proto="",proto="tls",server_name="default_dot: other",tls_version="tls1.3"} 4
```
+## AGDNS-607 / Build 258
+- The special "disallow-all" response is served on `/robots.txt` requests to `web` module.
-## AGDNS-607 / Build 258
+## AGDNS-506 / Build 242
- * The special "disallow-all" response is served on `/robots.txt` requests to
- `web` module.
-
-
-
-## AGDNS-506 / Build 242
-
- * The property `cache_size` of object `geoip` has been renamed to
- `ip_cache_size`. Also, a new property named `host_cache_size` has been
- added. So replace this:
+- The property `cache_size` of object `geoip` has been renamed to `ip_cache_size`. Also, a new property named `host_cache_size` has been added. So replace this:
```yaml
geoip:
@@ -1357,12 +1089,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the new value, if necessary.
+## AGDNS-505 / Build 238
-
-## AGDNS-505 / Build 238
-
- * The object `backend` has a new property, `bill_stat_interval`. So replace
- this:
+- The object `backend` has a new property, `bill_stat_interval`. So replace this:
```yaml
backend:
@@ -1383,32 +1112,22 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the value, if necessary.
+## AGDNS-187 / Build 228
-
-## AGDNS-187 / Build 228
-
- * The new required environment variables `GENERAL_SAFE_SEARCH_URL` and
- `YOUTUBE_SAFE_SEARCH_URL` has been added. Those are expected to lead to
- plain text filters, for example:
+- The new required environment variables `GENERAL_SAFE_SEARCH_URL` and `YOUTUBE_SAFE_SEARCH_URL` has been added. Those are expected to lead to plain text filters, for example:
```sh
GENERAL_SAFE_SEARCH_URL='https://adguardteam.github.io/HostlistsRegistry/assets/engines_safe_search.txt'
YOUTUBE_SAFE_SEARCH_URL='https://adguardteam.github.io/HostlistsRegistry/assets/youtube_safe_search.txt'
```
+## AGDNS-344 / Build 226
+- The environment variables `CONSUL_DNSCHECK_KV_URL` and `CONSUL_DNSCHECK_SESSION_URL` are now unset by default. Which means that by default HTTP key-value database isn't used.
-## AGDNS-344 / Build 226
+## AGDNS-431 / Build 211
- * The environment variables `CONSUL_DNSCHECK_KV_URL` and
- `CONSUL_DNSCHECK_SESSION_URL` are now unset by default. Which means that by
- default HTTP key-value database isn't used.
-
-
-
-## AGDNS-431 / Build 211
-
- * The object `web` has a new optional property, `linked_ip`:
+- The object `web` has a new optional property, `linked_ip`:
```yaml
web:
@@ -1424,13 +1143,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
key: ./test/cert.key
```
+## AGDNS-425 / Build 209
-
-## AGDNS-425 / Build 209
-
- * The objects within the `server_groups.*.servers` array have a new optional
- property, `linked_ip_enabled`. It is `false` by default. Set to `true` to
- enable linked IP address detection on that server:
+- The objects within the `server_groups.*.servers` array have a new optional property, `linked_ip_enabled`. It is `false` by default. Set to `true` to enable linked IP address detection on that server:
```yaml
server_groups:
@@ -1444,27 +1159,19 @@ The format is **not** based on [Keep a Changelog][kec], since the project
# …
```
+## AGDNS-405 / Build 195
+- Used our fork of miekg/dns library to fix the EDNS0 TCP keep-alive issue.
-## AGDNS-405 / Build 195
+## AGDNS-341 / Build 183
- * Used our fork of miekg/dns library to fix the EDNS0 TCP keep-alive issue.
+- Removed the static DNS check `/info.txt`. Now that `web` module is available, it is no more needed since it can be configured via the `web` module.
+## AGDNS-341 / Build 179
+- The object `doh` has been removed.
-## AGDNS-341 / Build 183
-
- * Removed the static DNS check `/info.txt`. Now that `web` module is
- available, it is no more needed since it can be configured via the `web`
- module.
-
-
-
-## AGDNS-341 / Build 179
-
- * The object `doh` has been removed.
-
- * The new optional object `web` has been added:
+- The new optional object `web` has been added:
```yaml
web:
@@ -1509,63 +1216,39 @@ The format is **not** based on [Keep a Changelog][kec], since the project
timeout: 1m
```
+## AGDNS-367 / Build 164
+- The object `geoip` has a new property, `cache_size`.
-## AGDNS-367 / Build 164
+## AGDNS-310 / Build 153
- * The object `geoip` has a new property, `cache_size`.
-
-
-
-## AGDNS-310 / Build 153
-
- * The environment variable `LOG_OUTPUT` has been removed. Logs are now always
- written to stdout.
-
-
-
-## AGDNS-339 / Build 136
-
- * The environment variable `DNSDB_PATH` is now unset by default. Which means
- that by default DNSDB is disabled.
+- The environment variable `LOG_OUTPUT` has been removed. Logs are now always written to stdout.
+## AGDNS-339 / Build 136
+- The environment variable `DNSDB_PATH` is now unset by default. Which means that by default DNSDB is disabled.
## AGDNS-350 / Build 135
- * The new optional environment variable `SSLKEYLOGFILE` has been added.
+- The new optional environment variable `SSLKEYLOGFILE` has been added.
+## AGDNS-345 / Build 133
+- The object `check` has a new property, `node_location`.
-## AGDNS-345 / Build 133
+## AGDNS-322 / Build 116
- * The object `check` has a new property, `node_location`.
+- The property `device_id_wildcard_domains` in the objects within the `server_groups.*.servers` array has been renamed to the shorter `device_id_wildcards`.
+- The DNS names from certificates are not used to detect device IDs and perform additional validations anymore.
+## AGDNS-305 / Build 114
-## AGDNS-322 / Build 116
+- The new required environment variable `BLOCKED_SERVICE_INDEX_URL` has been added. It has no default value, so it's necessary to set it.
- * The property `device_id_wildcard_domains` in the objects within the
- `server_groups.*.servers` array has been renamed to the shorter
- `device_id_wildcards`.
+## AGDNS-319 / Build 113
- * The DNS names from certificates are not used to detect device IDs and
- perform additional validations anymore.
-
-
-
-## AGDNS-305 / Build 114
-
- * The new required environment variable `BLOCKED_SERVICE_INDEX_URL` has been
- added. It has no default value, so it's necessary to set it.
-
-
-
-## AGDNS-319 / Build 113
-
- * The objects within the `server_groups.*.servers` array have a new property,
- `tls.device_id_wildcard_domains`. It is an array of domain name wildcards
- used to detect device IDs. If necessary, add them:
+- The objects within the `server_groups.*.servers` array have a new property, `tls.device_id_wildcard_domains`. It is an array of domain name wildcards used to detect device IDs. If necessary, add them:
```yaml
server_groups:
@@ -1581,56 +1264,35 @@ The format is **not** based on [Keep a Changelog][kec], since the project
- *.dns.adguard.com
```
+## AGDNS-292 / Build 111
+- The environment variable `CONSUL_URL` has been renamed to `CONSUL_ALLOWLIST_URL`.
-## AGDNS-292 / Build 111
+- The new required environment variables `CONSUL_DNSCHECK_KV_URL` and `CONSUL_DNSCHECK_SESSION_URL` are added. They have no default value, so it's necessary to set them.
- * The environment variable `CONSUL_URL` has been renamed to
- `CONSUL_ALLOWLIST_URL`.
+- The object `check` has a new property, `ttl`. Set it to a human-readable duration, for example `1m`.
- * The new required environment variables `CONSUL_DNSCHECK_KV_URL` and
- `CONSUL_DNSCHECK_SESSION_URL` are added. They have no default value, so
- it's necessary to set them.
+## AGDNS-296 / Build 110
- * The object `check` has a new property, `ttl`. Set it to a human-readable
- duration, for example `1m`.
+- The property `parental.safe_search` of objects within the `filtering_groups` array is renamed to `parental.general_safe_search` to synchronize it with the backend.
+## Build 109
+- The object `log` has been removed. Its properties have been moved to the environment.
-## AGDNS-296 / Build 110
-
- * The property `parental.safe_search` of objects within the `filtering_groups`
- array is renamed to `parental.general_safe_search` to synchronize it with
- the backend.
-
-
-
-## Build 109
-
- * The object `log` has been removed. Its properties have been moved to the
- environment.
-
- * The new environment variable `LOG_OUTPUT` has been added. It is the path to
- the plain text log file. If `stdout`, writes to standard output. If
- `stderr`, writes to standard error.
+- The new environment variable `LOG_OUTPUT` has been added. It is the path to the plain text log file. If `stdout`, writes to standard output. If `stderr`, writes to standard error.
The default value is `stdout`, adjust the value, if necessary.
- * The new environment variable `LOG_TIMESTAMP` has been added. When it is set
- to `1`, timestamps are shown in the plain text logs. When set to `0`, they
- are
- not shown.
+- The new environment variable `LOG_TIMESTAMP` has been added. When it is set to `1`, timestamps are shown in the plain text logs. When set to `0`, they are not shown.
The default value is `1`, adjust the value, if necessary.
- * The environment variable `VERBOSE` doesn't support a set but empty value.
- Unset the value or replace it with a `0`.
+- The environment variable `VERBOSE` doesn't support a set but empty value. Unset the value or replace it with a `0`.
+## AGDNS-295 / Build 105
-
-## AGDNS-295 / Build 105
-
- * Another change in the objects within the `filtering_groups`. Before:
+- Another change in the objects within the `filtering_groups`. Before:
```yaml
filtering_groups:
@@ -1664,19 +1326,13 @@ The format is **not** based on [Keep a Changelog][kec], since the project
enabled: true
```
+## AGDNS-290 / Build 97
+- The object `check` has a new property, `node_name`.
-## AGDNS-290 / Build 97
+## AGDNS-287 / Build 96
- * The object `check` has a new property, `node_name`.
-
-
-
-## AGDNS-287 / Build 96
-
- * The objects within the `server_groups.*.servers` array have a new optional
- property in their `dnscrypt` objects, `inline`. Also, the property `config`
- is renamed to `config_path`. So replace this:
+- The objects within the `server_groups.*.servers` array have a new optional property in their `dnscrypt` objects, `inline`. Also, the property `config` is renamed to `config_path`. So replace this:
```yaml
server_groups:
@@ -1733,30 +1389,22 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the values, if necessary.
+## AGDNS-290 / Build 95
+- The property `server_name` of object `check` is removed.
-## AGDNS-290 / Build 95
+## AGDNS-272 / Build 94
- * The property `server_name` of object `check` is removed.
-
-
-
-## AGDNS-272 / Build 94
-
- * The new optional object `doh` has been added, which supplements the
- DNS-over-HTTP server configuration. Example:
+- The new optional object `doh` has been added, which supplements the DNS-over-HTTP server configuration. Example:
```yaml
doh:
root_redirect_url: "https://adguard-dns.com/"
```
+## AGDNS-140 / Build 90
-
-## AGDNS-140 / Build 90
-
- * The objects within the `server_groups.*.servers` array have a new property,
- `tls.session_keys`. So, if necessary, replace this:
+- The objects within the `server_groups.*.servers` array have a new property, `tls.session_keys`. So, if necessary, replace this:
```yaml
server_groups:
@@ -1796,12 +1444,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
# …
```
+## AGDNS-233 / Build 88
-
-## AGDNS-233 / Build 88
-
- * The object `backend` has a new property, `full_refresh_interval`. So
- replace this:
+- The object `backend` has a new property, `full_refresh_interval`. So replace this:
```yaml
backend:
@@ -1820,12 +1465,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Adjust the value, if necessary.
+## AGDNS-247 / Build 86
-
-## AGDNS-247 / Build 86
-
- * The new object `check` has been added, which configures the DNS checks
- mechanism. Example:
+- The new object `check` has been added, which configures the DNS checks mechanism. Example:
```yaml
check:
@@ -1839,29 +1481,19 @@ The format is **not** based on [Keep a Changelog][kec], since the project
server_name: "AdGuard DNS Default"
```
+## AGDNS-246 / Build 83
+- The new environment variable `RULESTAT_URL` has been added. Its default value is
, which means that no statistics are gathered. Adjust the value, if necessary.
-## AGDNS-246 / Build 83
+## AGDNS-245 / Build 74
- * The new environment variable `RULESTAT_URL` has been added. Its default
- value is
, which means that no statistics are gathered. Adjust
- the value, if necessary.
+- The new environment variable `DNSDB_PATH` has been added. Its default value is `./dnsdb.bolt`. Adjust the value, if necessary.
+## AGDNS-139 / Build 73
+- The new required environment variable `CONSUL_URL` has been added. It has no default value, so it's necessary to set it.
-## AGDNS-245 / Build 74
-
- * The new environment variable `DNSDB_PATH` has been added. Its default value
- is `./dnsdb.bolt`. Adjust the value, if necessary.
-
-
-
-## AGDNS-139 / Build 73
-
- * The new required environment variable `CONSUL_URL` has been added. It has
- no default value, so it's necessary to set it.
-
- * The ratelimit configuration for a server has changed from this:
+- The ratelimit configuration for a server has changed from this:
```yaml
ratelimit:
@@ -1892,44 +1524,31 @@ The format is **not** based on [Keep a Changelog][kec], since the project
See README.md for documentation.
+## AGDNS-154 / Build 71
+- The property `backend` of the `query_log` object is removed.
-## AGDNS-154 / Build 71
+## AGDNS-230 / Build 67
- * The property `backend` of the `query_log` object is removed.
+- The new required environment variable `FILTER_INDEX_URL` has been added. It has no default value, so it's necessary to set it.
+- The environment variable `BACKEND_ENDPOINT` is now required and has no default value.
+- Property `lists` of the `filters` object is removed.
-## AGDNS-230 / Build 67
+- A new property `refresh_interval` has been added to the `filters` object.
- * The new required environment variable `FILTER_INDEX_URL` has been added. It
- has no default value, so it's necessary to set it.
+## AGDNS-229 / Build 62
- * The environment variable `BACKEND_ENDPOINT` is now required and has no
- default value.
+- The new environment variable `FILTER_CACHE_PATH` has been added. Its default value is `./filters/`. Adjust the value, if necessary.
- * Property `lists` of the `filters` object is removed.
+- The `list` property of `safe_browsing` and `adult_blocking` objects as well as the `path` property of the `filters.lists` objects are removed.
- * A new property `refresh_interval` has been added to the `filters` object.
+- Property `url` of the `filters.lists` objects is now required.
+## AGDNS-188 / Build 61
-
-## AGDNS-229 / Build 62
-
- * The new environment variable `FILTER_CACHE_PATH` has been added. Its
- default value is `./filters/`. Adjust the value, if necessary.
-
- * The `list` property of `safe_browsing` and `adult_blocking` objects as well
- as the `path` property of the `filters.lists` objects are removed.
-
- * Property `url` of the `filters.lists` objects is now required.
-
-
-
-## AGDNS-188 / Build 61
-
- * The type of the `cache.size` property was changed from bytes to integer. So
- replace this:
+- The type of the `cache.size` property was changed from bytes to integer. So replace this:
```yaml
cache:
@@ -1945,14 +1564,11 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Set the new values accordingly.
+## AGDNS-149, AGDNS-150, AGDNS-189 / Build 52
+- The top-level object `parental` was renamed to `adult_blocking`.
-## AGDNS-149, AGDNS-150, AGDNS-189 / Build 52
-
- * The top-level object `parental` was renamed to `adult_blocking`.
-
- * The objects `safe_browsing` and `adult_blocking` have four new properties,
- `cache_size`, `cache_ttl`, `refresh_interval`, and `url`. So replace this:
+- The objects `safe_browsing` and `adult_blocking` have four new properties, `cache_size`, `cache_ttl`, `refresh_interval`, and `url`. So replace this:
```yaml
safe_browsing:
@@ -1986,8 +1602,7 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Set the new values accordingly.
- * The objects within the `filtering_groups` array have a new property,
- `block_adult`. So replace this:
+- The objects within the `filtering_groups` array have a new property, `block_adult`. So replace this:
```yaml
filtering_groups:
@@ -2020,9 +1635,7 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Set the new value accordingly.
- * The objects within the `filters.lists` array have a new property,
- `refresh_interval`. The property is only required when the property `url`
- is also set. So replace this:
+- The objects within the `filters.lists` array have a new property, `refresh_interval`. The property is only required when the property `url` is also set. So replace this:
```yaml
filters:
@@ -2055,12 +1668,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
Set the new value accordingly.
+## Build 45
-
-## Build 45
-
- * The property `youtube_restricted` was renamed to `youtube_safe_search`.
- So replace this:
+- The property `youtube_restricted` was renamed to `youtube_safe_search`. So replace this:
```yaml
filtering_groups:
@@ -2088,11 +1698,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
youtube_safe_search: true
```
+## AGDNS-152 / Build 43
-
-## AGDNS-152 / Build 43
-
- * The blocked response TTL parameter has been moved and renamed. From this:
+- The blocked response TTL parameter has been moved and renamed. From this:
```yaml
dns:
@@ -2108,11 +1716,9 @@ The format is **not** based on [Keep a Changelog][kec], since the project
The `dns` object has been completely removed.
+## AGDNS-177 / Build 40
-
-## AGDNS-177 / Build 40
-
- * The TLS configuration for a server has changed from this:
+- The TLS configuration for a server has changed from this:
```yaml
tls:
@@ -2134,14 +1740,11 @@ The format is **not** based on [Keep a Changelog][kec], since the project
key: /test/cert.key
```
- The domains to be used in device ID detection are now expected to be
- contained in the certificate's DNS Names section of SAN.
+ The domains to be used in device ID detection are now expected to be contained in the certificate's DNS Names section of SAN.
+## AGDNS-167 / Build 39
-
-## AGDNS-167 / Build 39
-
- * The filtering configuration has changed from this:
+- The filtering configuration has changed from this:
```yaml
filters:
diff --git a/Makefile b/Makefile
index 4365c85..d9e9238 100644
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,7 @@ VERBOSE.MACRO = $${VERBOSE:-0}
BRANCH = $$( git rev-parse --abbrev-ref HEAD )
GOAMD64 = v1
GOPROXY = https://proxy.golang.org|direct
-GOTOOLCHAIN = go1.22.4
+GOTOOLCHAIN = go1.22.5
RACE = 0
REVISION = $$( git rev-parse --short HEAD )
VERSION = 0
@@ -66,8 +66,8 @@ go-check: go-tools go-lint go-test
# A quick check to make sure that all operating systems relevant to the
# development of the project can be typechecked and built successfully.
go-os-check:
- env GOOS='darwin' "$(GO.MACRO)" vet ./internal/...
- env GOOS='linux' "$(GO.MACRO)" vet ./internal/...
+ env GOOS='darwin' "$(GO.MACRO)" vet ./internal/... ./internal/dnsserver/...
+ env GOOS='linux' "$(GO.MACRO)" vet ./internal/... ./internal/dnsserver/...
# Additionally, check the AdGuard Home OSs in the dnsserver module.
env GOOS='freebsd' "$(GO.MACRO)" vet ./internal/dnsserver/...
env GOOS='openbsd' "$(GO.MACRO)" vet ./internal/dnsserver/...
diff --git a/doc/debughttp.md b/doc/debughttp.md
index 0bbcd36..871f990 100644
--- a/doc/debughttp.md
+++ b/doc/debughttp.md
@@ -1,20 +1,75 @@
- # AdGuard DNS Debug HTTP API
+# AdGuard DNS debug HTTP API
-The AdGuard DNS debug HTTP API is served on [`LISTEN_PORT`][env-listen_port] and
-contains various private debugging information.
+The AdGuard DNS debug HTTP API is served on [`LISTEN_PORT`][env-listen_port] and contains various private debugging information.
-## Contents
+## Contents
- * [`GET /dnsdb/csv`](#dnsdb-csv)
- * [`GET /health-check`](#health-check)
- * [`GET /metrics`](#metrics)
- * [`GET /debug/pprof`](#pprof)
+- [`GET /health-check`](#health-check)
+- [`GET /metrics`](#metrics)
+- [`GET /debug/pprof`](#pprof)
+- [`POST /debug/api/refresh`](#api-refresh)
+- [`POST /dnsdb/csv`](#dnsdb-csv)
[env-listen_port]: environment.md#LISTEN_PORT
+## `GET /health-check`
+A simple health check API. Always responds with a `200 OK` status and the plain-text body `OK`.
-## `GET /dnsdb/csv`
+## `GET /metrics`
+
+Prometheus metrics HTTP API. See the [metrics page][metrics] for more details.
+
+[metrics]: metrics.md
+
+## `GET /debug/pprof`
+
+The HTTP interface of Go's [PProf HTTP API][pprof api].
+
+[pprof api]: https://pkg.go.dev/net/http/pprof
+
+## `POST /debug/api/refresh`
+
+Run some refresh jobs manually. This refresh does not alter the time of the next automatic refresh.
+
+Example request:
+
+```sh
+curl -d '{"ids":["*"]}' -v "http://${LISTEN_ADDR}:${LISTEN_PORT}/debug/api/refresh"
+```
+
+Request body example:
+
+```json
+{
+ "ids": [
+ "filter_storage",
+ "adult_blocking"
+ ]
+}
+```
+
+Supported IDs:
+
+- `adult_blocking`;
+- `filter_storage`;
+- `newly_registered_domains`;
+- `safe_browsing`.
+
+The special ID `*`, when used alone, causes all available refresh tasks to be performed. Use with caution.
+
+Response body example:
+
+```json
+{
+ "results": {
+ "adult_blocking": "ok",
+ "filter_storage": "ok"
+ }
+}
+```
+
+## `POST /dnsdb/csv`
The CSV dump of the current DNSDB statistics. Example of the output:
@@ -23,33 +78,4 @@ example.com,A,NOERROR,93.184.216.34,42
example.com,AAAA,NOERROR,2606:2800:220:1:248:1893:25c8:1946,123
```
-The response is sent with the `Transfer-Encoding` set to `chunked` and with an
-HTTP trailer named `X-Error` which describes errors that might have occurred
-during the database dump.
-
- > [!NOTE]
- > For legacy software reasons, despite the endpoint being a `GET` one, it
- > rotates the database, and so changes the internal state.
-
-
-
-## `GET /health-check`
-
-A simple health check API. Always responds with a `200 OK` status and the
-plain-text body `OK`.
-
-
-
-## `GET /metrics`
-
-Prometheus metrics HTTP API. See the [metrics page][metrics] for more details.
-
-[metrics]: metrics.md
-
-
-
-## `GET /debug/pprof`
-
-The HTTP interface of Go's [PProf HTTP API][pprof api].
-
-[pprof api]: https://pkg.go.dev/net/http/pprof
+The response is sent with the `Transfer-Encoding` set to `chunked` and with an HTTP trailer named `X-Error` which describes errors that might have occurred during the database dump.
diff --git a/doc/development.md b/doc/development.md
index 0eda125..bb25bc9 100644
--- a/doc/development.md
+++ b/doc/development.md
@@ -185,6 +185,7 @@ cp -f config.dist.yaml config.yaml
### Step 4: prepare the test data
```sh
+echo '
General content ahead' > ./test/block_page_general.html
echo 'Dangerous content ahead' > ./test/block_page_sb.html
echo 'Adult content ahead' > ./test/block_page_adult.html
echo 'Error 404' > ./test/error_404.html
diff --git a/doc/environment.md b/doc/environment.md
index 437c469..db52b91 100644
--- a/doc/environment.md
+++ b/doc/environment.md
@@ -1,175 +1,139 @@
- # AdGuard DNS Environment Configuration
+# AdGuard DNS environment configuration
-AdGuard DNS uses [environment variables][wiki-env] to store some of the more
-sensitive configuration. All other configuration is stored in the
-[configuration file][conf].
+AdGuard DNS uses [environment variables][wiki-env] to store some of the more sensitive configuration. All other configuration is stored in the [configuration file][conf].
-## Contents
+## Contents
- * [`ADULT_BLOCKING_URL`](#ADULT_BLOCKING_URL)
- * [`BILLSTAT_URL`](#BILLSTAT_URL)
- * [`BLOCKED_SERVICE_INDEX_URL`](#BLOCKED_SERVICE_INDEX_URL)
- * [`CONFIG_PATH`](#CONFIG_PATH)
- * [`CONSUL_ALLOWLIST_URL`](#CONSUL_ALLOWLIST_URL)
- * [`CONSUL_DNSCHECK_KV_URL`](#CONSUL_DNSCHECK_KV_URL)
- * [`CONSUL_DNSCHECK_SESSION_URL`](#CONSUL_DNSCHECK_SESSION_URL)
- * [`FILTER_CACHE_PATH`](#FILTER_CACHE_PATH)
- * [`FILTER_INDEX_URL`](#FILTER_INDEX_URL)
- * [`GENERAL_SAFE_SEARCH_URL`](#GENERAL_SAFE_SEARCH_URL)
- * [`GEOIP_ASN_PATH` and `GEOIP_COUNTRY_PATH`](#GEOIP_ASN_PATH)
- * [`LINKED_IP_TARGET_URL`](#LINKED_IP_TARGET_URL)
- * [`LISTEN_ADDR`](#LISTEN_ADDR)
- * [`LISTEN_PORT`](#LISTEN_PORT)
- * [`LOG_TIMESTAMP`](#LOG_TIMESTAMP)
- * [`NEW_REG_DOMAINS_URL`](#NEW_REG_DOMAINS_URL)
- * [`PROFILES_CACHE_PATH`](#PROFILES_CACHE_PATH)
- * [`PROFILES_ENABLED`](#PROFILES_ENABLED)
- * [`PROFILES_URL`](#PROFILES_URL)
- * [`QUERYLOG_PATH`](#QUERYLOG_PATH)
- * [`RULESTAT_URL`](#RULESTAT_URL)
- * [`SAFE_BROWSING_URL`](#SAFE_BROWSING_URL)
- * [`SENTRY_DSN`](#SENTRY_DSN)
- * [`SSL_KEY_LOG_FILE`](#SSL_KEY_LOG_FILE)
- * [`VERBOSE`](#VERBOSE)
- * [`YOUTUBE_SAFE_SEARCH_URL`](#YOUTUBE_SAFE_SEARCH_URL)
+- [`ADULT_BLOCKING_URL`](#ADULT_BLOCKING_URL)
+- [`BILLSTAT_API_KEY`](#BILLSTAT_API_KEY)
+- [`BILLSTAT_URL`](#BILLSTAT_URL)
+- [`BLOCKED_SERVICE_INDEX_URL`](#BLOCKED_SERVICE_INDEX_URL)
+- [`CONFIG_PATH`](#CONFIG_PATH)
+- [`CONSUL_ALLOWLIST_URL`](#CONSUL_ALLOWLIST_URL)
+- [`CONSUL_DNSCHECK_KV_URL`](#CONSUL_DNSCHECK_KV_URL)
+- [`CONSUL_DNSCHECK_SESSION_URL`](#CONSUL_DNSCHECK_SESSION_URL)
+- [`FILTER_CACHE_PATH`](#FILTER_CACHE_PATH)
+- [`FILTER_INDEX_URL`](#FILTER_INDEX_URL)
+- [`GENERAL_SAFE_SEARCH_URL`](#GENERAL_SAFE_SEARCH_URL)
+- [`GEOIP_ASN_PATH` and `GEOIP_COUNTRY_PATH`](#GEOIP_ASN_PATH)
+- [`LINKED_IP_TARGET_URL`](#LINKED_IP_TARGET_URL)
+- [`LISTEN_ADDR`](#LISTEN_ADDR)
+- [`LISTEN_PORT`](#LISTEN_PORT)
+- [`LOG_TIMESTAMP`](#LOG_TIMESTAMP)
+- [`NEW_REG_DOMAINS_URL`](#NEW_REG_DOMAINS_URL)
+- [`PROFILES_API_KEY`](#PROFILES_API_KEY)
+- [`PROFILES_CACHE_PATH`](#PROFILES_CACHE_PATH)
+- [`PROFILES_ENABLED`](#PROFILES_ENABLED)
+- [`PROFILES_URL`](#PROFILES_URL)
+- [`QUERYLOG_PATH`](#QUERYLOG_PATH)
+- [`RULESTAT_URL`](#RULESTAT_URL)
+- [`SAFE_BROWSING_URL`](#SAFE_BROWSING_URL)
+- [`SENTRY_DSN`](#SENTRY_DSN)
+- [`SSL_KEY_LOG_FILE`](#SSL_KEY_LOG_FILE)
+- [`VERBOSE`](#VERBOSE)
+- [`YOUTUBE_SAFE_SEARCH_URL`](#YOUTUBE_SAFE_SEARCH_URL)
[conf]: configuration.md
[wiki-env]: https://en.wikipedia.org/wiki/Environment_variable
-
-
-## `ADULT_BLOCKING_URL`
+## `ADULT_BLOCKING_URL`
The URL of source list of rules for adult blocking filter.
**Default:** No default value, the variable is **required.**
+## `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].
-## `BILLSTAT_URL`
+**Default:** **Unset.**
-The base backend URL for backend billing statistics uploader API. Supports
-GRPC (`grpc://` and`grpcs://`) URLs. See the [external HTTP API requirements
-section][ext-billstat].
+[RFC 6750]: https://datatracker.ietf.org/doc/html/rfc6750#section-2.1
+
+## `BILLSTAT_URL`
+
+The base backend URL for backend billing statistics uploader API. Supports GRPC (`grpc://` and`grpcs://`) URLs. See the [external HTTP API requirements section][ext-billstat].
**Default:** No default value, the variable is **required.**
[ext-billstat]: externalhttp.md#backend-billstat
+## `BLOCKED_SERVICE_INDEX_URL`
-
-## `BLOCKED_SERVICE_INDEX_URL`
-
-The URL of the blocked service index file server. See the [external HTTP API
-requirements section][ext-blocked] on the expected format of the response.
+The URL of the blocked service index file server. See the [external HTTP API requirements section][ext-blocked] on the expected format of the response.
**Default:** No default value, the variable is **required.**
[ext-blocked]: externalhttp.md#filters-blocked-services
-
-
-## `CONFIG_PATH`
+## `CONFIG_PATH`
The path to the configuration file.
**Default:** `./config.yaml`.
+## `CONSUL_ALLOWLIST_URL`
-
-## `CONSUL_ALLOWLIST_URL`
-
-The 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.
+The 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.**
[ext-consul]: externalhttp.md#consul
+## `CONSUL_DNSCHECK_KV_URL`
-
-## `CONSUL_DNSCHECK_KV_URL`
-
-The URL of the KV API of the Consul instance used as a key-value database for
-the DNS server checking. It must end with `/kv/` where ``
-is any non-empty namespace. If not specified, the
-[`CONSUL_DNSCHECK_SESSION_URL`](#CONSUL_DNSCHECK_SESSION_URL) is also
-omitted.
+The URL of the KV API of the Consul instance used as a key-value database for the DNS server checking. It must end with `/kv/` where `` is any non-empty namespace. If not specified, the [`CONSUL_DNSCHECK_SESSION_URL`](#CONSUL_DNSCHECK_SESSION_URL) is also omitted.
**Default:** **Unset.**
**Example:** `http://localhost:8500/v1/kv/test`
+## `CONSUL_DNSCHECK_SESSION_URL`
-
-## `CONSUL_DNSCHECK_SESSION_URL`
-
-The URL of the session API of the Consul instance used as a key-value database
-for the DNS server checking. If not specified, the
-[`CONSUL_DNSCHECK_KV_URL`](#CONSUL_DNSCHECK_KV_URL) is also omitted.
+The URL of the session API of the Consul instance used as a key-value database for the DNS server checking. If not specified, the [`CONSUL_DNSCHECK_KV_URL`](#CONSUL_DNSCHECK_KV_URL) is also omitted.
**Default:** **Unset.**
**Example:** `http://localhost:8500/v1/session/create`
+## `FILTER_CACHE_PATH`
-
-## `FILTER_CACHE_PATH`
-
-The path to the directory used to store the cached version of all filters and
-filter indexes.
+The path to the directory used to store the cached version of all filters and filter indexes.
**Default:** `./filters/`.
+## `FILTER_INDEX_URL`
-
-## `FILTER_INDEX_URL`
-
-The URL of the filtering rule index file server. See the [external HTTP API
-requirements section][ext-lists] on the expected format of the response.
+The URL of the filtering rule index file server. See the [external HTTP API requirements section][ext-lists] on the expected format of the response.
**Default:** No default value, the variable is **required.**
[ext-lists]: externalhttp.md#filters-lists
+## `GENERAL_SAFE_SEARCH_URL`
-
-## `GENERAL_SAFE_SEARCH_URL`
-
-The URL of the list of general safe search rewriting rules. See the [external
-HTTP API requirements section][ext-general] on the expected format of the
-response.
+The URL of the list of general safe search rewriting rules. See the [external HTTP API requirements section][ext-general] on the expected format of the response.
**Default:** No default value, the variable is **required.**
[ext-general]: externalhttp.md#filters-safe-search
+## `GEOIP_ASN_PATH` and `GEOIP_COUNTRY_PATH`
-
-## `GEOIP_ASN_PATH` and `GEOIP_COUNTRY_PATH`
-
-Paths to the files containing MaxMind GeoIP databases: for ASNs and for
-countries and continents respectively.
+Paths to the files containing MaxMind GeoIP databases: for ASNs and for countries and continents respectively.
**Default:** `./asn.mmdb` and `./country.mmdb`.
+## `LINKED_IP_TARGET_URL`
-
-## `LINKED_IP_TARGET_URL`
-
-The target URL to which linked IP API requests are proxied. In case [linked IP
-and dynamic DNS][conf-web-linked_ip] web server is configured, the variable is
-required. See the [external HTTP API requirements section][ext-linked_ip].
+The target URL to which linked IP API requests are proxied. In case [linked IP and dynamic DNS][conf-web-linked_ip] web server is configured, the variable is required. See the [external HTTP API requirements section][ext-linked_ip].
**Default:** **Unset.**
[conf-web-linked_ip]: configuration.md#web-linked_ip
[ext-linked_ip]: externalhttp.md#backend-linkip
-
-
-## `LISTEN_ADDR`
+## `LISTEN_ADDR`
The IP address on which to bind the [debug HTTP API][debughttp].
@@ -177,96 +141,77 @@ The IP address on which to bind the [debug HTTP API][debughttp].
[debughttp]: debughttp.md
+## `LISTEN_PORT`
-
-## `LISTEN_PORT`
-
-The port on which to bind the [debug HTTP API][debughttp], which includes the
-health check, Prometheus, `pprof`, and other endpoints.
+The port on which to bind the [debug HTTP API][debughttp], which includes the health check, Prometheus, `pprof`, and other endpoints.
**Default:** `8181`.
+## `LOG_TIMESTAMP`
-
-## `LOG_TIMESTAMP`
-
-If `1`, show timestamps in the plain text logs. If `0`, don't show the
-timestamps.
+If `1`, show timestamps in the plain text logs. If `0`, don't show the timestamps.
**Default:** `1`.
+## `NEW_REG_DOMAINS_URL`
-
-## `NEW_REG_DOMAINS_URL`
-
-The URL of source list of rules for newly registered domains safe browsing
-filter.
+The URL of source list of rules for newly registered domains safe browsing filter.
**Default:** No default value, the variable is **required.**
+## `PROFILES_API_KEY`
+The API key to use when authenticating queries to the profiles API, if any. The API key should be valid as defined by [RFC 6750].
-## `PROFILES_CACHE_PATH`
+**Default:** **Unset.**
+
+## `PROFILES_CACHE_PATH`
The path to the profile cache file:
-* `none` means that the profile caching is disabled.
+- `none` means that the profile caching is disabled.
-* A file with the extension `.pb` means that the profiles are cached in the
- protobuf format.
+- A file with the extension `.pb` means that the profiles are cached in the protobuf format.
- Use the following command to inspect the cache, assuming that the version is
- correct:
+ Use the following command to inspect the cache, assuming that the version is correct:
- ```sh
- protoc\
- --decode\
- profiledb.FileCache\
- ./internal/profiledb/internal/filecachepb/filecache.proto\
- < /path/to/profilecache.pb
- ```
+ ```sh
+ protoc\
+ --decode\
+ profiledb.FileCache\
+ ./internal/profiledb/internal/filecachepb/filecache.proto\
+ < /path/to/profilecache.pb
+ ```
-The profile cache is read on start and is later updated on every
-[full refresh][conf-backend-full_refresh_interval].
+The profile cache is read on start and is later updated on every [full refresh][conf-backend-full_refresh_interval].
**Default:** `./profilecache.pb`.
[conf-backend-full_refresh_interval]: configuration.md#backend-full_refresh_interval
-
-
-## `PROFILES_ENABLED`
+## `PROFILES_ENABLED`
If `0`, disables user profiles and devices recognition and billing.
**Default:** `1`.
+## `PROFILES_URL`
-
-## `PROFILES_URL`
-
-The base backend URL for profiles API. Supports GRPC (`grpc://` and`grpcs://`)
-URLs. See the [external API requirements section][ext-profiles].
+The base backend URL for profiles API. Supports GRPC (`grpc://` and`grpcs://`) URLs. See the [external API requirements section][ext-profiles].
**Default:** No default value, the variable is **required.**
[ext-profiles]: externalhttp.md#backend-profiles
-
-
-## `QUERYLOG_PATH`
+## `QUERYLOG_PATH`
The path to the file into which the query log is going to be written.
**Default:** `./querylog.jsonl`.
+## `RULESTAT_URL`
-
-## `RULESTAT_URL`
-
-The URL to send filtering rule list statistics to. If empty or unset, the
-collection of filtering rule statistics is disabled. See the [external HTTP API
-requirements section][ext-rulestat] on the expected format of the response.
+The URL to send filtering rule list statistics to. If empty or unset, the collection of filtering rule statistics is disabled. See the [external HTTP API requirements section][ext-rulestat] on the expected format of the response.
**Default:** **Unset.**
@@ -274,46 +219,32 @@ requirements section][ext-rulestat] on the expected format of the response.
[ext-rulestat]: externalhttp.md#rulestat
-
-
-## `SAFE_BROWSING_URL`
+## `SAFE_BROWSING_URL`
The URL of source list of rules for dangerous domains safe browsing filter.
**Default:** No default value, the variable is **required.**
+## `SENTRY_DSN`
-
-## `SENTRY_DSN`
-
-Sentry error collector address. The special value `stderr` makes AdGuard DNS
-print these errors to standard error.
+Sentry error collector address. The special value `stderr` makes AdGuard DNS print these errors to standard error.
**Default:** `stderr`.
+## `SSL_KEY_LOG_FILE`
-
-## `SSL_KEY_LOG_FILE`
-
-If set, TLS key logs are written to this file to allow other programs (i.e.
-Wireshark) to decrypt packets. **Must only be used for debug purposes**.
+If set, TLS key logs are written to this file to allow other programs (i.e. Wireshark) to decrypt packets. **Must only be used for debug purposes**.
**Default:** **Unset.**
+## `VERBOSE`
-
-## `VERBOSE`
-
-When set to `1`, enable verbose logging. When set to `0`, disable it.
+When set to `1`, enable verbose logging. When set to `0`, disable it.
**Default:** `0`.
+## `YOUTUBE_SAFE_SEARCH_URL`
-
-## `YOUTUBE_SAFE_SEARCH_URL`
-
-The URL of the list of YouTube-specific safe search rewriting rules. See the
-[external HTTP API requirements section][ext-general] on the expected format of
-the response.
+The URL of the list of YouTube-specific safe search rewriting rules. See the [external HTTP API requirements section][ext-general] on the expected format of the response.
**Default:** No default value, the variable is **required.**
diff --git a/doc/externalhttp.md b/doc/externalhttp.md
index 1d21f46..6a16428 100644
--- a/doc/externalhttp.md
+++ b/doc/externalhttp.md
@@ -114,8 +114,8 @@ This endpoint, defined by [`FILTER_INDEX_URL`][env-filters], must respond with a
{
"filters": [
{
- "downloadUrl": "https://cdn.example.com/assets/my_filter.txt",
- "id": "my_filter"
+ "filterKey": "my_filter",
+ "downloadUrl": "https://cdn.example.com/assets/my_filter.txt"
}
]
}
diff --git a/doc/querylog.md b/doc/querylog.md
index 2e74b4d..c88df44 100644
--- a/doc/querylog.md
+++ b/doc/querylog.md
@@ -58,8 +58,11 @@ rules to remember, which property means what. The properties are:
“destination”.
> [!NOTE]
- > AdGuard DNS uses the common user-assigned ISO 3166-1 alpha-2 code `XK`
- > for the partially-recognized state of the Republic of Kosovo.
+ > Just like in the `c` field, `XK` is used for the partially-recognized
+ > state of the Republic of Kosovo. In addition to that, the code `QN`,
+ > “Not Applicable”, is used when the resource-record type of the response
+ > does not contain any IP-address information (for example, responses to
+ > `TXT` requests).
**Example:** `"US"`
diff --git a/go.mod b/go.mod
index 90a6928..300d946 100644
--- a/go.mod
+++ b/go.mod
@@ -1,33 +1,33 @@
module github.com/AdguardTeam/AdGuardDNS
-go 1.22.4
+go 1.22.5
require (
- github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-00010101000000-000000000000
- github.com/AdguardTeam/golibs v0.23.2
- github.com/AdguardTeam/urlfilter v0.18.0
+ github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-20240607112746-5690301129fe
+ github.com/AdguardTeam/golibs v0.24.0
+ github.com/AdguardTeam/urlfilter v0.19.0
github.com/ameshkov/dnscrypt/v2 v2.3.0
- github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02
+ github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27
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.27.0
+ github.com/getsentry/sentry-go v0.28.1
github.com/google/renameio/v2 v2.0.0
- github.com/miekg/dns v1.1.58
- github.com/oschwald/maxminddb-golang v1.12.0
+ github.com/miekg/dns v1.1.61
+ github.com/oschwald/maxminddb-golang v1.13.0
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
- github.com/prometheus/client_golang v1.19.0
+ github.com/prometheus/client_golang v1.19.1
github.com/prometheus/client_model v0.6.1
- github.com/prometheus/common v0.52.3
- github.com/quic-go/quic-go v0.42.0
+ github.com/prometheus/common v0.54.0
+ github.com/quic-go/quic-go v0.45.0
github.com/stretchr/testify v1.9.0
- golang.org/x/crypto v0.22.0
- golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8
- golang.org/x/net v0.24.0
- golang.org/x/sys v0.19.0
+ golang.org/x/crypto v0.24.0
+ golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
+ golang.org/x/net v0.26.0
+ golang.org/x/sys v0.21.0
golang.org/x/time v0.5.0
- google.golang.org/grpc v1.63.2
- google.golang.org/protobuf v1.33.0
+ google.golang.org/grpc v1.64.0
+ google.golang.org/protobuf v1.34.2
gopkg.in/yaml.v2 v2.4.0
)
@@ -39,19 +39,19 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
- github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
- github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
- github.com/onsi/ginkgo/v2 v2.17.1 // indirect
- github.com/panjf2000/ants/v2 v2.9.1 // indirect
+ github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
+ github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8 // indirect
+ github.com/onsi/ginkgo/v2 v2.19.0 // indirect
+ github.com/panjf2000/ants/v2 v2.10.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/procfs v0.13.0 // indirect
+ github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
go.uber.org/mock v0.4.0 // indirect
- golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/mod v0.18.0 // indirect
golang.org/x/sync v0.7.0 // indirect
- golang.org/x/text v0.14.0 // indirect
- golang.org/x/tools v0.20.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240412170617-26222e5d3d56 // indirect
+ golang.org/x/text v0.16.0 // indirect
+ golang.org/x/tools v0.22.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 73e4466..7ce14f9 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,7 @@
-github.com/AdguardTeam/golibs v0.23.2 h1:rMjYantwtQ39e8G4zBQ6ZLlm4s3XH30Bc9VxhoOHwao=
-github.com/AdguardTeam/golibs v0.23.2/go.mod h1:o9i55Sx6v7qogRQeqaBfmLbC/pZqeMBWi015U5PTDY0=
-github.com/AdguardTeam/urlfilter v0.18.0 h1:ZZzwODC/ADpjJSODxySrrUnt/fvOCfGFaCW6j+wsGfQ=
-github.com/AdguardTeam/urlfilter v0.18.0/go.mod h1:IXxBwedLiZA2viyHkaFxY/8mjub0li2PXRg8a3d9Z1s=
+github.com/AdguardTeam/golibs v0.24.0 h1:qAnOq7BQtwSVo7Co9q703/n+nZ2Ap6smkugU9G9MomY=
+github.com/AdguardTeam/golibs v0.24.0/go.mod h1:9/vJcYznW7RlmCT/Qzi8XNZGj+ZbWfHZJmEXKnRpCAU=
+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/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=
@@ -10,8 +10,8 @@ github.com/ameshkov/dnscrypt/v2 v2.3.0 h1:pDXDF7eFa6Lw+04C0hoMh8kCAQM8NwUdFEllSP
github.com/ameshkov/dnscrypt/v2 v2.3.0/go.mod h1:N5hDwgx2cNb4Ay7AhvOSKst+eUiOZ/vbKRO9qMpQttE=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
-github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02 h1:bXAPYSbdYbS5VTy92NIUbeDI1qyggi+JYh5op9IFlcQ=
-github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c=
+github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27 h1:60m4tnanN1ctzIu4V3bfCNJ39BiOPSm1gHFlFjTkRE0=
+github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
@@ -28,22 +28,20 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
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.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
-github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
+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/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.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
-github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
-github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
+github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/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-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
-github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
+github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8 h1:ASJ/LAqdCHOyMYI+dwNxn7Rd8FscNkMyTr1KZU1JI/M=
+github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -52,16 +50,16 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
-github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
-github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
-github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
-github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
-github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
-github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
-github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
-github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
-github.com/panjf2000/ants/v2 v2.9.1 h1:Q5vh5xohbsZXGcD6hhszzGqB7jSSc2/CRr3QKIga8Kw=
-github.com/panjf2000/ants/v2 v2.9.1/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
+github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
+github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
+github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
+github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
+github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
+github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
+github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU=
+github.com/oschwald/maxminddb-golang v1.13.0/go.mod h1:BU0z8BfFVhi1LQaonTwwGQlsHUEu9pWNdMfmq4ztm0o=
+github.com/panjf2000/ants/v2 v2.10.0 h1:zhRg1pQUtkyRiOFo2Sbqwjp0GfBNo9cUY2/Grpx1p+8=
+github.com/panjf2000/ants/v2 v2.10.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible h1:IWzUvJ72xMjmrjR9q3H1PF+jwdN0uNQiR2t1BLNalyo=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
@@ -72,66 +70,65 @@ 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.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
-github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
+github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
+github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
-github.com/prometheus/common v0.52.3 h1:5f8uj6ZwHSscOGNdIQg6OiZv/ybiK2CO2q2drVZAQSA=
-github.com/prometheus/common v0.52.3/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
-github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
-github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
+github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8=
+github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ=
+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.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
-github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
-github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
+github.com/quic-go/quic-go v0.45.0 h1:OHmkQGM37luZITyTSu6ff03HP/2IrwDX1ZFiNEhSFUE=
+github.com/quic-go/quic-go v0.45.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
-github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4=
-github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4=
+github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
+github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
-github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
-github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
-github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
-github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
-github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
+github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
+github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
+github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
+github.com/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.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
-golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
-golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc=
-golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
-golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
+golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
+golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
+golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
+golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
+golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
+golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
-golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
-golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
-golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240412170617-26222e5d3d56 h1:zviK8GX4VlMstrK3JkexM5UHjH1VOkRebH9y3jhSBGk=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240412170617-26222e5d3d56/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
-google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
-google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
-google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
-google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
+golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 h1:Di6ANFilr+S60a4S61ZM00vLdw0IrQOSMS2/6mrnOU0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
+google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
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 c7ea491..2997e83 100644
--- a/go.work
+++ b/go.work
@@ -1,4 +1,4 @@
-go 1.22.4
+go 1.22.5
use (
.
diff --git a/go.work.sum b/go.work.sum
index 1d7941d..9f32795 100644
--- a/go.work.sum
+++ b/go.work.sum
@@ -3,19 +3,138 @@ cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
+cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
+cloud.google.com/go/accessapproval v1.7.5/go.mod h1:g88i1ok5dvQ9XJsxpUInWWvUBrIZhyPDPbk4T01OoJ0=
+cloud.google.com/go/accesscontextmanager v1.8.5/go.mod h1:TInEhcZ7V9jptGNqN3EzZ5XMhT6ijWxTGjzyETwmL0Q=
+cloud.google.com/go/aiplatform v1.60.0/go.mod h1:eTlGuHOahHprZw3Hio5VKmtThIOak5/qy6pzdsqcQnM=
+cloud.google.com/go/analytics v0.23.0/go.mod h1:YPd7Bvik3WS95KBok2gPXDqQPHy08TsCQG6CdUCb+u0=
+cloud.google.com/go/apigateway v1.6.5/go.mod h1:6wCwvYRckRQogyDDltpANi3zsCDl6kWi0b4Je+w2UiI=
+cloud.google.com/go/apigeeconnect v1.6.5/go.mod h1:MEKm3AiT7s11PqTfKE3KZluZA9O91FNysvd3E6SJ6Ow=
+cloud.google.com/go/apigeeregistry v0.8.3/go.mod h1:aInOWnqF4yMQx8kTjDqHNXjZGh/mxeNlAf52YqtASUs=
+cloud.google.com/go/appengine v1.8.5/go.mod h1:uHBgNoGLTS5di7BvU25NFDuKa82v0qQLjyMJLuPQrVo=
+cloud.google.com/go/area120 v0.8.5/go.mod h1:BcoFCbDLZjsfe4EkCnEq1LKvHSK0Ew/zk5UFu6GMyA0=
+cloud.google.com/go/artifactregistry v1.14.7/go.mod h1:0AUKhzWQzfmeTvT4SjfI4zjot72EMfrkvL9g9aRjnnM=
+cloud.google.com/go/asset v1.17.2/go.mod h1:SVbzde67ehddSoKf5uebOD1sYw8Ab/jD/9EIeWg99q4=
+cloud.google.com/go/assuredworkloads v1.11.5/go.mod h1:FKJ3g3ZvkL2D7qtqIGnDufFkHxwIpNM9vtmhvt+6wqk=
+cloud.google.com/go/automl v1.13.5/go.mod h1:MDw3vLem3yh+SvmSgeYUmUKqyls6NzSumDm9OJ3xJ1Y=
+cloud.google.com/go/baremetalsolution v1.2.4/go.mod h1:BHCmxgpevw9IEryE99HbYEfxXkAEA3hkMJbYYsHtIuY=
+cloud.google.com/go/batch v1.8.0/go.mod h1:k8V7f6VE2Suc0zUM4WtoibNrA6D3dqBpB+++e3vSGYc=
+cloud.google.com/go/beyondcorp v1.0.4/go.mod h1:Gx8/Rk2MxrvWfn4WIhHIG1NV7IBfg14pTKv1+EArVcc=
cloud.google.com/go/bigquery v1.8.0 h1:PQcPefKFdaIzjQFbiyOgAqyx8q5djaE7x9Sqe712DPA=
+cloud.google.com/go/bigquery v1.59.1/go.mod h1:VP1UJYgevyTwsV7desjzNzDND5p6hZB+Z8gZJN1GQUc=
+cloud.google.com/go/billing v1.18.2/go.mod h1:PPIwVsOOQ7xzbADCwNe8nvK776QpfrOAUkvKjCUcpSE=
+cloud.google.com/go/binaryauthorization v1.8.1/go.mod h1:1HVRyBerREA/nhI7yLang4Zn7vfNVA3okoAR9qYQJAQ=
+cloud.google.com/go/certificatemanager v1.7.5/go.mod h1:uX+v7kWqy0Y3NG/ZhNvffh0kuqkKZIXdvlZRO7z0VtM=
+cloud.google.com/go/channel v1.17.5/go.mod h1:FlpaOSINDAXgEext0KMaBq/vwpLMkkPAw9b2mApQeHc=
+cloud.google.com/go/cloudbuild v1.15.1/go.mod h1:gIofXZSu+XD2Uy+qkOrGKEx45zd7s28u/k8f99qKals=
+cloud.google.com/go/clouddms v1.7.4/go.mod h1:RdrVqoFG9RWI5AvZ81SxJ/xvxPdtcRhFotwdE79DieY=
+cloud.google.com/go/cloudtasks v1.12.6/go.mod h1:b7c7fe4+TJsFZfDyzO51F7cjq7HLUlRi/KZQLQjDsaY=
+cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk=
cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg=
cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40=
+cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU=
+cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls=
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
+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=
+cloud.google.com/go/datacatalog v1.19.3/go.mod h1:ra8V3UAsciBpJKQ+z9Whkxzxv7jmQg1hfODr3N3YPJ4=
+cloud.google.com/go/dataflow v0.9.5/go.mod h1:udl6oi8pfUHnL0z6UN9Lf9chGqzDMVqcYTcZ1aPnCZQ=
+cloud.google.com/go/dataform v0.9.2/go.mod h1:S8cQUwPNWXo7m/g3DhWHsLBoufRNn9EgFrMgne2j7cI=
+cloud.google.com/go/datafusion v1.7.5/go.mod h1:bYH53Oa5UiqahfbNK9YuYKteeD4RbQSNMx7JF7peGHc=
+cloud.google.com/go/datalabeling v0.8.5/go.mod h1:IABB2lxQnkdUbMnQaOl2prCOfms20mcPxDBm36lps+s=
+cloud.google.com/go/dataplex v1.14.2/go.mod h1:0oGOSFlEKef1cQeAHXy4GZPB/Ife0fz/PxBf+ZymA2U=
+cloud.google.com/go/dataproc/v2 v2.4.0/go.mod h1:3B1Ht2aRB8VZIteGxQS/iNSJGzt9+CA0WGnDVMEm7Z4=
+cloud.google.com/go/dataqna v0.8.5/go.mod h1:vgihg1mz6n7pb5q2YJF7KlXve6tCglInd6XO0JGOlWM=
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
+cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8=
+cloud.google.com/go/datastream v1.10.4/go.mod h1:7kRxPdxZxhPg3MFeCSulmAJnil8NJGGvSNdn4p1sRZo=
+cloud.google.com/go/deploy v1.17.1/go.mod h1:SXQyfsXrk0fBmgBHRzBjQbZhMfKZ3hMQBw5ym7MN/50=
+cloud.google.com/go/dialogflow v1.49.0/go.mod h1:dhVrXKETtdPlpPhE7+2/k4Z8FRNUp6kMV3EW3oz/fe0=
+cloud.google.com/go/dlp v1.11.2/go.mod h1:9Czi+8Y/FegpWzgSfkRlyz+jwW6Te9Rv26P3UfU/h/w=
+cloud.google.com/go/documentai v1.25.0/go.mod h1:ftLnzw5VcXkLItp6pw1mFic91tMRyfv6hHEY5br4KzY=
+cloud.google.com/go/domains v0.9.5/go.mod h1:dBzlxgepazdFhvG7u23XMhmMKBjrkoUNaw0A8AQB55Y=
+cloud.google.com/go/edgecontainer v1.1.5/go.mod h1:rgcjrba3DEDEQAidT4yuzaKWTbkTI5zAMu3yy6ZWS0M=
+cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU=
+cloud.google.com/go/essentialcontacts v1.6.6/go.mod h1:XbqHJGaiH0v2UvtuucfOzFXN+rpL/aU5BCZLn4DYl1Q=
+cloud.google.com/go/eventarc v1.13.4/go.mod h1:zV5sFVoAa9orc/52Q+OuYUG9xL2IIZTbbuTHC6JSY8s=
+cloud.google.com/go/filestore v1.8.1/go.mod h1:MbN9KcaM47DRTIuLfQhJEsjaocVebNtNQhSLhKCF5GM=
+cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ=
+cloud.google.com/go/functions v1.16.0/go.mod h1:nbNpfAG7SG7Duw/o1iZ6ohvL7mc6MapWQVpqtM29n8k=
+cloud.google.com/go/gkebackup v1.3.5/go.mod h1:KJ77KkNN7Wm1LdMopOelV6OodM01pMuK2/5Zt1t4Tvc=
+cloud.google.com/go/gkeconnect v0.8.5/go.mod h1:LC/rS7+CuJ5fgIbXv8tCD/mdfnlAadTaUufgOkmijuk=
+cloud.google.com/go/gkehub v0.14.5/go.mod h1:6bzqxM+a+vEH/h8W8ec4OJl4r36laxTs3A/fMNHJ0wA=
+cloud.google.com/go/gkemulticloud v1.1.1/go.mod h1:C+a4vcHlWeEIf45IB5FFR5XGjTeYhF83+AYIpTy4i2Q=
+cloud.google.com/go/gsuiteaddons v1.6.5/go.mod h1:Lo4P2IvO8uZ9W+RaC6s1JVxo42vgy+TX5a6hfBZ0ubs=
+cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI=
+cloud.google.com/go/iap v1.9.4/go.mod h1:vO4mSq0xNf/Pu6E5paORLASBwEmphXEjgCFg7aeNu1w=
+cloud.google.com/go/ids v1.4.5/go.mod h1:p0ZnyzjMWxww6d2DvMGnFwCsSxDJM666Iir1bK1UuBo=
+cloud.google.com/go/iot v1.7.5/go.mod h1:nq3/sqTz3HGaWJi1xNiX7F41ThOzpud67vwk0YsSsqs=
+cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI=
+cloud.google.com/go/language v1.12.3/go.mod h1:evFX9wECX6mksEva8RbRnr/4wi/vKGYnAJrTRXU8+f8=
+cloud.google.com/go/lifesciences v0.9.5/go.mod h1:OdBm0n7C0Osh5yZB7j9BXyrMnTRGBJIZonUMxo5CzPw=
+cloud.google.com/go/logging v1.9.0/go.mod h1:1Io0vnZv4onoUnsVUQY3HZ3Igb1nBchky0A0y7BBBhE=
+cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s=
+cloud.google.com/go/managedidentities v1.6.5/go.mod h1:fkFI2PwwyRQbjLxlm5bQ8SjtObFMW3ChBGNqaMcgZjI=
+cloud.google.com/go/maps v1.6.4/go.mod h1:rhjqRy8NWmDJ53saCfsXQ0LKwBHfi6OSh5wkq6BaMhI=
+cloud.google.com/go/mediatranslation v0.8.5/go.mod h1:y7kTHYIPCIfgyLbKncgqouXJtLsU+26hZhHEEy80fSs=
+cloud.google.com/go/memcache v1.10.5/go.mod h1:/FcblbNd0FdMsx4natdj+2GWzTq+cjZvMa1I+9QsuMA=
+cloud.google.com/go/metastore v1.13.4/go.mod h1:FMv9bvPInEfX9Ac1cVcRXp8EBBQnBcqH6gz3KvJ9BAE=
+cloud.google.com/go/monitoring v1.18.0/go.mod h1:c92vVBCeq/OB4Ioyo+NbN2U7tlg5ZH41PZcdvfc+Lcg=
+cloud.google.com/go/networkconnectivity v1.14.4/go.mod h1:PU12q++/IMnDJAB+3r+tJtuCXCfwfN+C6Niyj6ji1Po=
+cloud.google.com/go/networkmanagement v1.9.4/go.mod h1:daWJAl0KTFytFL7ar33I6R/oNBH8eEOX/rBNHrC/8TA=
+cloud.google.com/go/networksecurity v0.9.5/go.mod h1:KNkjH/RsylSGyyZ8wXpue8xpCEK+bTtvof8SBfIhMG8=
+cloud.google.com/go/notebooks v1.11.3/go.mod h1:0wQyI2dQC3AZyQqWnRsp+yA+kY4gC7ZIVP4Qg3AQcgo=
+cloud.google.com/go/optimization v1.6.3/go.mod h1:8ve3svp3W6NFcAEFr4SfJxrldzhUl4VMUJmhrqVKtYA=
+cloud.google.com/go/orchestration v1.8.5/go.mod h1:C1J7HesE96Ba8/hZ71ISTV2UAat0bwN+pi85ky38Yq8=
+cloud.google.com/go/orgpolicy v1.12.1/go.mod h1:aibX78RDl5pcK3jA8ysDQCFkVxLj3aOQqrbBaUL2V5I=
+cloud.google.com/go/osconfig v1.12.5/go.mod h1:D9QFdxzfjgw3h/+ZaAb5NypM8bhOMqBzgmbhzWViiW8=
+cloud.google.com/go/oslogin v1.13.1/go.mod h1:vS8Sr/jR7QvPWpCjNqy6LYZr5Zs1e8ZGW/KPn9gmhws=
+cloud.google.com/go/phishingprotection v0.8.5/go.mod h1:g1smd68F7mF1hgQPuYn3z8HDbNre8L6Z0b7XMYFmX7I=
+cloud.google.com/go/policytroubleshooter v1.10.3/go.mod h1:+ZqG3agHT7WPb4EBIRqUv4OyIwRTZvsVDHZ8GlZaoxk=
+cloud.google.com/go/privatecatalog v0.9.5/go.mod h1:fVWeBOVe7uj2n3kWRGlUQqR/pOd450J9yZoOECcQqJk=
cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU=
+cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE=
+cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0=
+cloud.google.com/go/recaptchaenterprise/v2 v2.9.2/go.mod h1:trwwGkfhCmp05Ll5MSJPXY7yvnO0p4v3orGANAFHAuU=
+cloud.google.com/go/recommendationengine v0.8.5/go.mod h1:A38rIXHGFvoPvmy6pZLozr0g59NRNREz4cx7F58HAsQ=
+cloud.google.com/go/recommender v1.12.1/go.mod h1:gf95SInWNND5aPas3yjwl0I572dtudMhMIG4ni8nr+0=
+cloud.google.com/go/redis v1.14.2/go.mod h1:g0Lu7RRRz46ENdFKQ2EcQZBAJ2PtJHJLuiiRuEXwyQw=
+cloud.google.com/go/resourcemanager v1.9.5/go.mod h1:hep6KjelHA+ToEjOfO3garMKi/CLYwTqeAw7YiEI9x8=
+cloud.google.com/go/resourcesettings v1.6.5/go.mod h1:WBOIWZraXZOGAgoR4ukNj0o0HiSMO62H9RpFi9WjP9I=
+cloud.google.com/go/retail v1.16.0/go.mod h1:LW7tllVveZo4ReWt68VnldZFWJRzsh9np+01J9dYWzE=
+cloud.google.com/go/run v1.3.4/go.mod h1:FGieuZvQ3tj1e9GnzXqrMABSuir38AJg5xhiYq+SF3o=
+cloud.google.com/go/scheduler v1.10.6/go.mod h1:pe2pNCtJ+R01E06XCDOJs1XvAMbv28ZsQEbqknxGOuE=
+cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4=
+cloud.google.com/go/security v1.15.5/go.mod h1:KS6X2eG3ynWjqcIX976fuToN5juVkF6Ra6c7MPnldtc=
+cloud.google.com/go/securitycenter v1.24.4/go.mod h1:PSccin+o1EMYKcFQzz9HMMnZ2r9+7jbc+LvPjXhpwcU=
+cloud.google.com/go/servicedirectory v1.11.4/go.mod h1:Bz2T9t+/Ehg6x+Y7Ycq5xiShYLD96NfEsWNHyitj1qM=
+cloud.google.com/go/shell v1.7.5/go.mod h1:hL2++7F47/IfpfTO53KYf1EC+F56k3ThfNEXd4zcuiE=
+cloud.google.com/go/spanner v1.56.0/go.mod h1:DndqtUKQAt3VLuV2Le+9Y3WTnq5cNKrnLb/Piqcj+h0=
+cloud.google.com/go/speech v1.21.1/go.mod h1:E5GHZXYQlkqWQwY5xRSLHw2ci5NMQNG52FfMU1aZrIA=
cloud.google.com/go/storage v1.10.0 h1:STgFzyU5/8miMl0//zKh2aQeTyeaUH3WN9bSUiJ09bA=
+cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY=
+cloud.google.com/go/storagetransfer v1.10.4/go.mod h1:vef30rZKu5HSEf/x1tK3WfWrL0XVoUQN/EPDRGPzjZs=
+cloud.google.com/go/talent v1.6.6/go.mod h1:y/WQDKrhVz12WagoarpAIyKKMeKGKHWPoReZ0g8tseQ=
+cloud.google.com/go/texttospeech v1.7.5/go.mod h1:tzpCuNWPwrNJnEa4Pu5taALuZL4QRRLcb+K9pbhXT6M=
+cloud.google.com/go/tpu v1.6.5/go.mod h1:P9DFOEBIBhuEcZhXi+wPoVy/cji+0ICFi4TtTkMHSSs=
+cloud.google.com/go/trace v1.10.5/go.mod h1:9hjCV1nGBCtXbAE4YK7OqJ8pmPYSxPA0I67JwRd5s3M=
+cloud.google.com/go/translate v1.10.1/go.mod h1:adGZcQNom/3ogU65N9UXHOnnSvjPwA/jKQUMnsYXOyk=
+cloud.google.com/go/video v1.20.4/go.mod h1:LyUVjyW+Bwj7dh3UJnUGZfyqjEto9DnrvTe1f/+QrW0=
+cloud.google.com/go/videointelligence v1.11.5/go.mod h1:/PkeQjpRponmOerPeJxNPuxvi12HlW7Em0lJO14FC3I=
+cloud.google.com/go/vision/v2 v2.8.0/go.mod h1:ocqDiA2j97pvgogdyhoxiQp2ZkDCyr0HWpicywGGRhU=
+cloud.google.com/go/vmmigration v1.7.5/go.mod h1:pkvO6huVnVWzkFioxSghZxIGcsstDvYiVCxQ9ZH3eYI=
+cloud.google.com/go/vmwareengine v1.1.1/go.mod h1:nMpdsIVkUrSaX8UvmnBhzVzG7PPvNYc5BszcvIVudYs=
+cloud.google.com/go/vpcaccess v1.7.5/go.mod h1:slc5ZRvvjP78c2dnL7m4l4R9GwL3wDLcpIWz6P/ziig=
+cloud.google.com/go/webrisk v1.9.5/go.mod h1:aako0Fzep1Q714cPEM5E+mtYX8/jsfegAuS8aivxy3U=
+cloud.google.com/go/websecurityscanner v1.6.5/go.mod h1:QR+DWaxAz2pWooylsBF854/Ijvuoa3FCyS1zBa1rAVQ=
+cloud.google.com/go/workflows v1.12.4/go.mod h1:yQ7HUqOkdJK4duVtMeBCAOPiN1ZF1E9pAMX51vpwB/w=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3 h1:hJiie5Bf3QucGRa4ymsAUOxyhYwGEz1xrsVk0P8erlw=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY=
@@ -51,6 +170,8 @@ github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKd
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
+github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
+github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE=
github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU=
github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
@@ -64,6 +185,8 @@ github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
+github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
@@ -74,9 +197,11 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89 h1:aPflPkRFkVwbW6dmcVqfgwp1i+UWGFH6VgR1Jim5Ygc=
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/chromedp/chromedp v0.9.2 h1:dKtNz4kApb06KuSXoTQIyUC2TrA0fhGDwNZf3bcgfKw=
@@ -100,6 +225,7 @@ github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk=
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
@@ -108,6 +234,8 @@ github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbi
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
+github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 h1:DBmgJDC9dTfkVyGgipamEh2BpGYxScCH1TOF1LL1cXc=
+github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM=
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=
@@ -117,18 +245,23 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM=
github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI=
github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
+github.com/envoyproxy/protoc-gen-validate 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/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=
github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
@@ -157,7 +290,10 @@ github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
@@ -167,6 +303,7 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
@@ -175,6 +312,8 @@ github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/gofiber/fiber/v2 v2.52.2 h1:b0rYH6b06Df+4NyrbdptQL8ifuxw/Tf2DgfkZkDaxEo=
+github.com/gofiber/fiber/v2 v2.52.2/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
@@ -187,51 +326,86 @@ github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/
github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
+github.com/golang/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=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7 h1:2hRPrmiwPrp3fQX967rNJIhQPtiGXdlQWAxKbKw3VHA=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
+github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs=
+github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99 h1:Ak8CrdlwwXwAZxzS66vgPt4U8yUZX7JwLvVR58FN5jM=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
+github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
+github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
+github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.5.0 h1:WcmKMm43DR7RdtlkEXQJyo5ws8iTp98CyhCCbOHMvNI=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -242,7 +416,11 @@ github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab h1:BA4a7pe
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465 h1:KwWnWVWCNtNq/ewIX7HIKnELmEx2nDP42yskD/pi7QE=
github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
+github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
+github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/influxdata/influxdb v1.7.6 h1:8mQ7A/V+3noMGCt/P9pD09ISaiz9XvgCk303UYA3gcs=
+github.com/iris-contrib/httpexpect/v2 v2.12.1 h1:3cTZSyBBen/kfjCtgNFoUKi1u0FVXNaAjyRJOo6AVS4=
+github.com/iris-contrib/httpexpect/v2 v2.12.1/go.mod h1:7+RB6W5oNClX7PTwJgJnsQP3ZuUUYB3u61KCqeSgZ88=
github.com/iris-contrib/jade v1.1.4 h1:WoYdfyJFfZIUgqNAeOyRfTNQZOksSlZ6+FnXR3AEpX0=
github.com/iris-contrib/jade v1.1.4/go.mod h1:EDqR+ur9piDl6DUgs6qRrlfzmlx/D5UybogqrXvJTBE=
github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw=
@@ -285,6 +463,8 @@ github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
+github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@@ -310,6 +490,7 @@ github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T
github.com/lucas-clemente/quic-go v0.27.1/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
+github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk=
github.com/mailgun/raymond/v2 v2.0.46 h1:aOYHhvTpF5USySJ0o7cpPno/Uh2I5qg2115K25A+Ft4=
github.com/mailgun/raymond/v2 v2.0.46/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw=
@@ -331,6 +512,10 @@ github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peK
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
@@ -341,6 +526,8 @@ github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXm
github.com/microcosm-cc/bluemonday v1.0.23 h1:SMZe2IGa0NuHvnVNAZ+6B38gsTbi5e4sViiWJyDDqFY=
github.com/microcosm-cc/bluemonday v1.0.23/go.mod h1:mN70sk7UkkF8TUr2IGBpNN0jAgStuPzlK76QuruE/z4=
github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
+github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -354,10 +541,13 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab h1:eFXv9Nu1lGbrNbj619aWwZfVF5HBrm9Plte8aNptuTI=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
+github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
+github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc=
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
+github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
@@ -372,23 +562,33 @@ github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaF
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/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_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
+github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.38.0/go.mod h1:MPCuRq7KBK2hNcfKj/1iD1BGuN3eAYMeNxp3T42LRUg=
github.com/quic-go/quic-go v0.39.4/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
+github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4 h1:Fth6mevc5rX7glNLpbAMJnqKlfIkcTjZCSHEeqvKbcI=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48 h1:vabduItPAIz9px5iryD5peyx7O3Ya8TBThapgXim98o=
@@ -441,6 +641,7 @@ github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:Udh
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e h1:qpG93cPwA5f7s/ZPBJnGOYQNK/vKsaDaseuKT5Asee8=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
+github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
@@ -449,12 +650,16 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/tdewolff/minify/v2 v2.12.4 h1:kejsHQMM17n6/gwdw53qsi6lg0TGddZADVyQOz1KMdE=
github.com/tdewolff/minify/v2 v2.12.4/go.mod h1:h+SRvSIX3kwgwTFOpSckvSxgax3uy8kZTSF1Ojrr3bk=
github.com/tdewolff/parse/v2 v2.6.4 h1:KCkDvNUMof10e3QExio9OPZJT8SbdKojLBumw8YZycQ=
github.com/tdewolff/parse/v2 v2.6.4/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs=
+github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
+github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
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=
@@ -463,10 +668,14 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc=
github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
+github.com/valyala/fasthttp v1.52.0 h1:wqBQpxH71XW0e2g+Og4dzQM8pk34aFYlA1Ga8db7gU0=
+github.com/valyala/fasthttp v1.52.0/go.mod h1:hf5C4QnVMkNXMspnsUlfM3WitlgYflyhHYoKol/szxQ=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
+github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/viant/assertly v0.4.8 h1:5x1GzBaRteIwTr5RAGFVG14uNeRFxVNbXPWrK2qAgpc=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0 h1:6TteTDQ68CjgcCe8wH3D3ZhUQQOJXMTbj/D9rkk2a1k=
@@ -475,17 +684,38 @@ github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1v2SRTV4cUmp4=
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
+github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
+github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
+github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
+github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yuin/goldmark v1.4.1 h1:/vn0k+RBvwlxEmP5E7SZMqNxPhfMVFEJiykr15/0XKM=
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
+go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
+go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
+go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc=
+go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
+go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go4.org v0.0.0-20180809161055-417644f6feb5 h1:+hE86LblG4AyDgwMCLTE6FOlM9+qjHSYS+rKqxUVdsM=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d h1:E2M5QgjZ/Jg+ObCQAudsXxuTsLj7Nl5RV/lZcQZmKSo=
@@ -494,13 +724,17 @@ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20221019170559-20944726eadf/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
@@ -508,17 +742,22 @@ golang.org/x/exp v0.0.0-20230306221820-f0f767cdffd6/go.mod h1:CxIveKay+FTh1D0yPZ
golang.org/x/exp v0.0.0-20230807204917-050eac23e9de/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
+golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
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=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -526,12 +765,18 @@ golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220516155154-20f960328961/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
@@ -540,8 +785,12 @@ golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -554,22 +803,35 @@ golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
+golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
+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/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=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -585,13 +847,20 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808 h1:+Kc94D8UVEVxJnLXp/+FMfqQARZtWHfVrcRtcG8aT3g=
golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
+golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk=
+golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
@@ -611,17 +880,29 @@ golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
+golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
+golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
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=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/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=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+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.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
@@ -632,6 +913,11 @@ golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
+golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
+golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
@@ -640,6 +926,7 @@ google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/api v0.30.0 h1:yfrXXP61wVuLb0vBcG6qaOoIoqYEzOQS8jum51jkv2w=
+google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -654,6 +941,8 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+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 v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8=
@@ -661,6 +950,8 @@ google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA
google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk=
google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe h1:USL2DhxfgRchafRvt/wYyyQNzwgL7ZiURcozOE/Pkvo=
google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
+google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
+google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw=
@@ -669,13 +960,38 @@ google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0=
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
+google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y=
+google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4=
+google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE=
+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=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
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.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+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.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
@@ -691,7 +1007,10 @@ grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJd
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
+moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=
+moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE=
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
diff --git a/internal/agd/agd.go b/internal/agd/agd.go
index 974cdd4..2d1349b 100644
--- a/internal/agd/agd.go
+++ b/internal/agd/agd.go
@@ -5,8 +5,6 @@ import (
"fmt"
)
-// Common Constants, Types, And Utilities
-
// firstNonIDRune returns the first non-printable or non-ASCII rune and its
// index. If slashes is true, it also looks for slashes. If there are no such
// runes, i is -1.
diff --git a/internal/agd/agd_test.go b/internal/agd/agd_test.go
index 9ba93db..7ddbe2d 100644
--- a/internal/agd/agd_test.go
+++ b/internal/agd/agd_test.go
@@ -1,11 +1,27 @@
package agd_test
import (
+ "strings"
"testing"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/golibs/testutil"
)
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
+
+// Common long strings for tests.
+var (
+ testLongStr = strings.Repeat("a", 200)
+ testLongStrUnicode = strings.Repeat("ы", 200)
+)
+
+// Common IDs for tests.
+const (
+ testHumanIDStr = "My-Device-X--10"
+ testHumanIDLowerStr = "my-device-x--10"
+
+ testHumanID agd.HumanID = testHumanIDStr
+)
diff --git a/internal/agd/device.go b/internal/agd/device.go
index 55d529c..62832aa 100644
--- a/internal/agd/device.go
+++ b/internal/agd/device.go
@@ -10,8 +10,6 @@ import (
"github.com/AdguardTeam/golibs/netutil"
)
-// Devices
-
// Device is a device of a device attached to a profile.
//
// NOTE: Do not change fields of this structure without incrementing
@@ -30,6 +28,10 @@ type Device struct {
// Name is the human-readable name of the device.
Name DeviceName
+ // HumanIDLower is the lower-case version of the normalized [HumanID] used
+ // to create this device, if any.
+ HumanIDLower HumanIDLower
+
// DedicatedIPs are the destination (server) IP-addresses dedicated to this
// device, if any. A device can use one of these addresses as a DNS server
// address for AdGuard DNS to recognize it.
diff --git a/internal/agd/device_test.go b/internal/agd/device_test.go
index ba46ee7..7e40610 100644
--- a/internal/agd/device_test.go
+++ b/internal/agd/device_test.go
@@ -1,7 +1,6 @@
package agd_test
import (
- "strings"
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
@@ -12,9 +11,6 @@ import (
func TestNewDeviceName(t *testing.T) {
t.Parallel()
- tooLong := strings.Repeat("a", 200)
- tooLongUnicode := strings.Repeat("ы", 200)
-
testCases := []struct {
name string
in string
@@ -33,12 +29,12 @@ func TestNewDeviceName(t *testing.T) {
wantErrMsg: "",
}, {
name: "too_long",
- in: tooLong,
- wantErrMsg: `bad device name "` + tooLong + `": too long: got 200 runes, max 128`,
+ in: testLongStr,
+ wantErrMsg: `bad device name "` + testLongStr + `": too long: got 200 runes, max 128`,
}, {
name: "too_long_unicode",
- in: tooLongUnicode,
- wantErrMsg: `bad device name "` + tooLongUnicode + `": too long: got 200 runes, max 128`,
+ in: testLongStrUnicode,
+ wantErrMsg: `bad device name "` + testLongStrUnicode + `": too long: got 200 runes, max 128`,
}}
for _, tc := range testCases {
diff --git a/internal/agd/devicetype.go b/internal/agd/devicetype.go
new file mode 100644
index 0000000..69ea71e
--- /dev/null
+++ b/internal/agd/devicetype.go
@@ -0,0 +1,82 @@
+package agd
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/AdguardTeam/golibs/errors"
+)
+
+// DeviceType is a type of a device as used in the Backend API.
+type DeviceType uint8
+
+// DeviceType values.
+//
+// Do not change the order. Keep in sync with the Backend API.
+const (
+ DeviceTypeNone DeviceType = 0
+ DeviceTypeWindows DeviceType = 1
+ DeviceTypeAndroid DeviceType = 2
+ DeviceTypeMacOS DeviceType = 3
+ DeviceTypeIOS DeviceType = 4
+ DeviceTypeLinux DeviceType = 5
+ DeviceTypeRouter DeviceType = 6
+ DeviceTypeSmartTV DeviceType = 7
+ DeviceTypeGameConsole DeviceType = 8
+ DeviceTypeOther DeviceType = 9
+)
+
+// deviceTypeStrings is a mapping between a device type and its default string
+// representation. Keep in sync with the DNS API.
+var deviceTypeStrings = []string{
+ DeviceTypeNone: "(none)",
+ DeviceTypeWindows: "win",
+ DeviceTypeAndroid: "adr",
+ DeviceTypeMacOS: "mac",
+ DeviceTypeIOS: "ios",
+ DeviceTypeLinux: "lnx",
+ DeviceTypeRouter: "rtr",
+ DeviceTypeSmartTV: "stv",
+ DeviceTypeGameConsole: "gam",
+ DeviceTypeOther: "otr",
+}
+
+// DeviceTypeFromDNS converts a string into a valid device type. s is assumed
+// to be from a DNS FQDN or HTTP path. The matching is case-insensitive, and
+// "(none)", the string representation of [DeviceTypeNone], is not recognized,
+// since it's not a valid type in the DNS API.
+func DeviceTypeFromDNS(s string) (dt DeviceType, err error) {
+ // Do not use [errors.Annotate] here, because it allocates even when the
+ // error is nil.
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("bad device type %q: %w", s, err)
+ }
+ }()
+
+ err = ValidateInclusion(len(s), 3, 3, UnitByte)
+ if err != nil {
+ // The error will be wrapped by the deferred helper.
+ return DeviceTypeNone, err
+ }
+
+ for i, dtStr := range deviceTypeStrings[1:] {
+ if strings.EqualFold(s, dtStr) {
+ return DeviceType(i + 1), nil
+ }
+ }
+
+ return DeviceTypeNone, errors.Error("unknown device type")
+}
+
+// type check
+var _ fmt.Stringer = DeviceTypeNone
+
+// String implements the [fmt.Stringer] interface for DeviceType.
+func (dt DeviceType) String() (s string) {
+ if int(dt) < len(deviceTypeStrings) {
+ return deviceTypeStrings[dt]
+ }
+
+ return fmt.Sprintf("!bad_device_type_%d", dt)
+}
diff --git a/internal/agd/devicetype_test.go b/internal/agd/devicetype_test.go
new file mode 100644
index 0000000..cd4088a
--- /dev/null
+++ b/internal/agd/devicetype_test.go
@@ -0,0 +1,68 @@
+package agd_test
+
+import (
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestDeviceTypeFromDNS(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ name string
+ in string
+ wantErrMsg string
+ want agd.DeviceType
+ }{{
+ name: "success",
+ in: "adr",
+ wantErrMsg: "",
+ want: agd.DeviceTypeAndroid,
+ }, {
+ name: "success_case",
+ in: "Adr",
+ wantErrMsg: "",
+ want: agd.DeviceTypeAndroid,
+ }, {
+ name: "too_long",
+ in: "windows",
+ wantErrMsg: `bad device type "windows": too long: got 7 bytes, max 3`,
+ want: agd.DeviceTypeNone,
+ }, {
+ name: "too_small",
+ in: "x",
+ wantErrMsg: `bad device type "x": too short: got 1 bytes, min 3`,
+ want: agd.DeviceTypeNone,
+ }, {
+ name: "none",
+ in: "(none)",
+ wantErrMsg: `bad device type "(none)": too long: got 6 bytes, max 3`,
+ want: agd.DeviceTypeNone,
+ }, {
+ name: "unknown",
+ in: "xxx",
+ wantErrMsg: `bad device type "xxx": unknown device type`,
+ want: agd.DeviceTypeNone,
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ got, err := agd.DeviceTypeFromDNS(tc.in)
+ assert.Equal(t, tc.want, got)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+ })
+ }
+}
+
+func TestDeviceType_String(t *testing.T) {
+ t.Parallel()
+
+ assert.Equal(t, "(none)", agd.DeviceTypeNone.String())
+ assert.Equal(t, "adr", agd.DeviceTypeAndroid.String())
+ assert.Equal(t, "!bad_device_type_42", agd.DeviceType(42).String())
+}
diff --git a/internal/agd/filterlist_test.go b/internal/agd/filterlist_test.go
index 4878a51..ceeebe6 100644
--- a/internal/agd/filterlist_test.go
+++ b/internal/agd/filterlist_test.go
@@ -12,8 +12,6 @@ import (
func TestNewFilterListID(t *testing.T) {
t.Parallel()
- tooLong := strings.Repeat("a", agd.MaxFilterListIDLen+1)
-
testCases := []struct {
name string
in string
@@ -28,8 +26,8 @@ func TestNewFilterListID(t *testing.T) {
wantErrMsg: `bad filter list id "": too short: got 0 bytes, min 1`,
}, {
name: "too_long",
- in: tooLong,
- wantErrMsg: `bad filter list id "` + tooLong + `": too long: got 129 bytes, max 128`,
+ in: testLongStr,
+ wantErrMsg: `bad filter list id "` + testLongStr + `": too long: got 200 bytes, max 128`,
}, {
name: "bad",
in: "bad/name",
diff --git a/internal/agd/humanid.go b/internal/agd/humanid.go
new file mode 100644
index 0000000..7427a98
--- /dev/null
+++ b/internal/agd/humanid.go
@@ -0,0 +1,279 @@
+package agd
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+ "unicode/utf8"
+
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/syncutil"
+)
+
+// HumanID is a more human-readable identifier of a device.
+type HumanID string
+
+const (
+ // MaxHumanIDLen is the maximum length of a human-readable device ID.
+ MaxHumanIDLen = netutil.MaxDomainLabelLen
+
+ // MinHumanIDLen is the minimum length of a human-readable device ID.
+ MinHumanIDLen = 1
+)
+
+// NewHumanID converts a simple string into a HumanID and makes sure that it's
+// valid. This should be preferred to a simple type conversion.
+//
+// TODO(a.garipov): Remove if it remains unused.
+func NewHumanID(s string) (id HumanID, err error) {
+ // Do not use [errors.Annotate] here, because it allocates even when the
+ // error is nil.
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("bad human id %q: %w", s, err)
+ }
+ }()
+
+ return newHumanID(s)
+}
+
+// newHumanID converts a simple string into a HumanID and makes sure that it's
+// valid. It does not wrap the error to be used in places where that could
+// create additional allocations.
+func newHumanID(s string) (id HumanID, err error) {
+ err = ValidateInclusion(len(s), MaxHumanIDLen, MinHumanIDLen, UnitByte)
+ if err != nil {
+ // Don't wrap the error, because the caller should do that.
+ return "", err
+ }
+
+ // TODO(a.garipov): Add boolean versions to netutil to avoid allocations of
+ // errors that aren't used.
+ err = netutil.ValidateHostnameLabel(s)
+ if err != nil {
+ // Don't wrap the error, because the caller should do that.
+ return "", err
+ }
+
+ if i := strings.Index(s, "---"); i >= 0 {
+ return "", fmt.Errorf("at index %d: max 2 consecutive hyphens are allowed", i)
+ }
+
+ return HumanID(s), nil
+}
+
+// HumanIDLower is the type for [HumanID] values that must be lowercase.
+type HumanIDLower string
+
+// NewHumanIDLower converts a simple string into a HumanIDLower and makes sure
+// that it's valid and lowercased. This should be preferred to a simple type
+// conversion.
+func NewHumanIDLower(s string) (id HumanIDLower, err error) {
+ // Do not use [errors.Annotate] here, because it allocates even when the
+ // error is nil.
+
+ humanID, err := newHumanID(s)
+ if err != nil {
+ return "", fmt.Errorf("bad lowercase human id %q: %w", s, err)
+ }
+
+ for i, r := range humanID {
+ if r >= 'A' && r <= 'Z' {
+ return "", fmt.Errorf(
+ "bad lowercase human id %q: at index %d: %q is not lowercase",
+ s,
+ i,
+ r,
+ )
+ }
+ }
+
+ return HumanIDLower(s), nil
+}
+
+// HumanIDToLower returns a lowercase version of id.
+func HumanIDToLower(id HumanID) (lower HumanIDLower) {
+ return HumanIDLower(strings.ToLower(string(id)))
+}
+
+// HumanIDParser normalizes and parses a HumanID from a string.
+type HumanIDParser struct {
+ pool *syncutil.Pool[bytes.Buffer]
+}
+
+// NewHumanIDParser creates a new HumanIDParser.
+func NewHumanIDParser() (p *HumanIDParser) {
+ return &HumanIDParser{
+ pool: syncutil.NewPool(func() (buf *bytes.Buffer) {
+ return bytes.NewBuffer(make([]byte, 0, netutil.MaxDomainNameLen))
+ }),
+ }
+}
+
+// ParseNormalized normalizes and parses a HumanID from a string that may have
+// issues, such as extra symbols that aren't supported. The normalization is
+// best-effort and may still fail, in which case id is empty and err is not nil.
+func (p *HumanIDParser) ParseNormalized(s string) (id HumanID, err error) {
+ id, err = newHumanID(s)
+ if err == nil {
+ return id, nil
+ }
+
+ // Do not use [errors.Annotate] here, because it allocates even when the
+ // error is nil.
+ original := s
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("bad non-normalized human id %q: %w", original, err)
+ }
+ }()
+
+ // Immediately validate it against the upper DNS hostname-length limit.
+ err = ValidateInclusion(len(s), netutil.MaxDomainNameLen, MinHumanIDLen, UnitByte)
+ if err != nil {
+ // Don't wrap the error, because there is already a deferred wrap, and
+ // the error is informative enough as is.
+ return "", err
+ }
+
+ buf := p.pool.Get()
+ defer func() { p.pool.Put(buf) }()
+
+ buf.Reset()
+ n := humanIDNormalizer{
+ buf: buf,
+ }
+
+ for s != "" {
+ r, sz := utf8.DecodeRuneInString(s)
+ s = s[sz:]
+
+ n.next(r)
+ }
+
+ s = n.result()
+ if s == "" || s == "-" {
+ return "", errors.Error("cannot normalize")
+ }
+
+ id, err = newHumanID(s)
+ if err != nil {
+ return "", err
+ }
+
+ return id, nil
+}
+
+// humanIDNormalizer is a stateful normalizer of human-readable device
+// identifiers.
+type humanIDNormalizer struct {
+ buf *bytes.Buffer
+ state uint8
+ prevRune rune
+ prevPrevRune rune
+}
+
+// [humanIDNormalizer] states.
+const (
+ humanIDNormStateInitial uint8 = iota
+ humanIDNormStateInvalid
+ humanIDNormStateValid
+)
+
+// next writes r to the buffer, if it is valid.
+func (p *humanIDNormalizer) next(r rune) {
+ switch p.state {
+ case humanIDNormStateInitial:
+ p.nextInitial(r)
+ case humanIDNormStateValid:
+ p.nextValid(r)
+ case humanIDNormStateInvalid:
+ p.nextInvalid(r)
+ default:
+ panic(fmt.Errorf("bad humanIDNormalizer state %d", p.state))
+ }
+}
+
+// nextInitial processes the initial state of the normalizer.
+func (p *humanIDNormalizer) nextInitial(r rune) {
+ if !netutil.IsValidHostOuterRune(r) {
+ return
+ }
+
+ p.state = humanIDNormStateValid
+ p.write(r)
+}
+
+// nextValid processes the valid state of the normalizer.
+func (p *humanIDNormalizer) nextValid(r rune) {
+ if r == '-' {
+ if p.prevPrevRune == '-' && p.prevRune == '-' {
+ p.buf.Truncate(p.buf.Len() - 2)
+ p.prevPrevRune = utf8.RuneError
+ p.prevRune = utf8.RuneError
+ p.state = humanIDNormStateInvalid
+
+ return
+ }
+
+ p.write(r)
+
+ return
+ }
+
+ if !netutil.IsValidHostOuterRune(r) {
+ p.truncateHyphens()
+ p.state = humanIDNormStateInvalid
+
+ return
+ }
+
+ p.write(r)
+}
+
+// truncateHyphens removes the unnecessary hyphens from the buffer if necessary.
+func (p *humanIDNormalizer) truncateHyphens() {
+ if p.prevRune != '-' {
+ return
+ }
+
+ if p.prevPrevRune == '-' {
+ p.buf.Truncate(p.buf.Len() - 2)
+ p.prevPrevRune = utf8.RuneError
+ } else {
+ p.buf.Truncate(p.buf.Len() - 1)
+ }
+
+ p.prevRune = utf8.RuneError
+}
+
+// nextInvalid processes the invalid state of the normalizer.
+func (p *humanIDNormalizer) nextInvalid(r rune) {
+ if !netutil.IsValidHostOuterRune(r) {
+ return
+ }
+
+ p.state = humanIDNormStateValid
+ if p.prevRune != '-' {
+ p.write('-')
+ }
+
+ p.write(r)
+}
+
+// write writes r to the buffer while also updating the previous runes.
+func (p *humanIDNormalizer) write(r rune) {
+ _, _ = p.buf.WriteRune(r)
+ p.prevPrevRune = p.prevRune
+ p.prevRune = r
+}
+
+// result returns the result of the normalization.
+func (p *humanIDNormalizer) result() (s string) {
+ b := p.buf.Bytes()
+ b = b[:min(len(b), MaxHumanIDLen)]
+ b = bytes.TrimRight(b, "-")
+
+ return string(b)
+}
diff --git a/internal/agd/humanid_test.go b/internal/agd/humanid_test.go
new file mode 100644
index 0000000..abc35d6
--- /dev/null
+++ b/internal/agd/humanid_test.go
@@ -0,0 +1,275 @@
+package agd_test
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestNewHumanID(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ name string
+ in string
+ wantErrMsg string
+ }{{
+ name: "success",
+ in: testHumanIDStr,
+ wantErrMsg: "",
+ }, {
+ name: "too_long",
+ in: testLongStr,
+ wantErrMsg: `bad human id "` + testLongStr + `": too long: got 200 bytes, max 63`,
+ }, {
+ name: "too_small",
+ in: "",
+ wantErrMsg: `bad human id "": too short: got 0 bytes, min 1`,
+ }, {
+ name: "bad_start",
+ in: "-My-Device-X--10",
+ wantErrMsg: `bad human id "-My-Device-X--10": bad hostname label "-My-Device-X--10": ` +
+ `bad hostname label rune '-'`,
+ }, {
+ name: "bad_middle",
+ in: "My-Device-X---10",
+ wantErrMsg: `bad human id "My-Device-X---10": at index 11: ` +
+ `max 2 consecutive hyphens are allowed`,
+ }, {
+ name: "bad_rune",
+ in: "My-Device-X--10!",
+ wantErrMsg: `bad human id "My-Device-X--10!": bad hostname label "My-Device-X--10!": ` +
+ `bad hostname label rune '!'`,
+ }, {
+ name: "bad_end",
+ in: "My-Device-X--10-",
+ wantErrMsg: `bad human id "My-Device-X--10-": bad hostname label "My-Device-X--10-": ` +
+ `bad hostname label rune '-'`,
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ id, err := agd.NewHumanID(tc.in)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+
+ if tc.wantErrMsg == "" {
+ assert.Equal(t, tc.in, string(id))
+ }
+ })
+ }
+}
+
+func TestNewHumanIDLower(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ name string
+ in string
+ wantErrMsg string
+ }{{
+ name: "success",
+ in: testHumanIDLowerStr,
+ wantErrMsg: "",
+ }, {
+ name: "bad_case",
+ in: "my-device-X--10",
+ wantErrMsg: `bad lowercase human id "my-device-X--10": at index 10: 'X' is not lowercase`,
+ }, {
+ name: "bad_rune",
+ in: "My-Device-X--10!",
+ wantErrMsg: `bad lowercase human id "My-Device-X--10!": ` +
+ `bad hostname label "My-Device-X--10!": bad hostname label rune '!'`,
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ id, err := agd.NewHumanIDLower(tc.in)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+
+ if tc.wantErrMsg == "" {
+ assert.Equal(t, tc.in, string(id))
+ }
+ })
+ }
+}
+
+func TestHumanIDParser_ParseNormalized(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ name string
+ in string
+ wantErrMsg string
+ wantID agd.HumanID
+ }{{
+ name: "success",
+ in: testHumanIDStr,
+ wantErrMsg: "",
+ wantID: testHumanID,
+ }, {
+ name: "too_long",
+ in: testLongStr,
+ wantErrMsg: "",
+ wantID: agd.HumanID(strings.Repeat("a", agd.MaxHumanIDLen)),
+ }, {
+ name: "too_small",
+ in: "",
+ wantErrMsg: `bad non-normalized human id "": too short: got 0 bytes, min 1`,
+ }, {
+ name: "bad_start",
+ in: "-My-Device-X--10",
+ wantErrMsg: "",
+ wantID: testHumanID,
+ }, {
+ name: "bad_middle",
+ in: "My-Device-X---10",
+ wantErrMsg: "",
+ wantID: "My-Device-X-10",
+ }, {
+ name: "bad_rune",
+ in: "My-Device-X--10!",
+ wantErrMsg: "",
+ wantID: testHumanID,
+ }, {
+ name: "bad_end",
+ in: "My-Device-X--10-",
+ wantErrMsg: "",
+ wantID: testHumanID,
+ }, {
+ name: "bad_chars_start",
+ in: "абв-My-Device-X--10",
+ wantErrMsg: "",
+ wantID: testHumanID,
+ }, {
+ name: "bad_chars_end",
+ in: "My-Device-X--10-абв",
+ wantErrMsg: "",
+ wantID: testHumanID,
+ }, {
+ name: "bad_chars_middle",
+ in: "My-Device-Xабв10",
+ wantErrMsg: "",
+ wantID: "My-Device-X-10",
+ }, {
+ name: "bad_chars_middle_hyphens",
+ in: "My-Device-X-абв-10",
+ wantErrMsg: "",
+ wantID: "My-Device-X-10",
+ }, {
+ name: "bad_chars_middle_two_hyphens",
+ in: "My-Device-X--абв--10",
+ wantErrMsg: "",
+ wantID: "My-Device-X-10",
+ }, {
+ name: "bad_chars_middle_two_hyphens_other",
+ in: "My-DeviceабвX--10",
+ wantErrMsg: "",
+ wantID: testHumanID,
+ }, {
+ name: "one_bad_char",
+ in: "!",
+ wantErrMsg: `bad non-normalized human id "!": cannot normalize`,
+ wantID: "",
+ }, {
+ name: "only_bad_chars",
+ in: "!!!",
+ wantErrMsg: `bad non-normalized human id "!!!": cannot normalize`,
+ wantID: "",
+ }}
+
+ p := agd.NewHumanIDParser()
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ id, err := p.ParseNormalized(tc.in)
+ assert.Equalf(t, tc.wantID, id, "original: %q", tc.in)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+ })
+ }
+}
+
+// Sinks for benchmarks.
+var (
+ humanIDSink agd.HumanID
+ errSink error
+)
+
+func BenchmarkHumanIDParser_ParseNormalized(b *testing.B) {
+ benchCases := []struct {
+ name string
+ in string
+ wantErrPresent bool
+ }{{
+ name: "valid",
+ in: testHumanIDStr,
+ wantErrPresent: false,
+ }, {
+ name: "normalized",
+ in: testHumanIDStr + "-!!!",
+ wantErrPresent: false,
+ }, {
+ name: "normalized_long",
+ in: testLongStr,
+ wantErrPresent: false,
+ }, {
+ name: "bad",
+ in: "!!!",
+ wantErrPresent: true,
+ }}
+
+ for _, bc := range benchCases {
+ b.Run(bc.name, func(b *testing.B) {
+ p := agd.NewHumanIDParser()
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for range b.N {
+ humanIDSink, errSink = p.ParseNormalized(bc.in)
+ }
+
+ if bc.wantErrPresent {
+ require.Empty(b, humanIDSink)
+ require.Error(b, errSink)
+ } else {
+ require.NotEmpty(b, humanIDSink)
+ require.NoError(b, errSink)
+ }
+ })
+ }
+
+ // Most recent result, on a ThinkPad X13 with a Ryzen Pro 7 CPU:
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/agd
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkHumanIDParser_ParseNormalized/valid-16 23716176 51.48 ns/op 0 B/op 0 allocs/op
+ // BenchmarkHumanIDParser_ParseNormalized/normalized-16 1000000 1071 ns/op 88 B/op 3 allocs/op
+ // BenchmarkHumanIDParser_ParseNormalized/normalized_long-16 504042 4086 ns/op 128 B/op 4 allocs/op
+ // BenchmarkHumanIDParser_ParseNormalized/bad-16 752247 1361 ns/op 184 B/op 5 allocs/op
+}
+
+func FuzzHumanIDParser_ParseNormalized(f *testing.F) {
+ p := agd.NewHumanIDParser()
+
+ f.Fuzz(func(t *testing.T, input string) {
+ s, err := p.ParseNormalized(input)
+ if err != nil {
+ require.Empty(t, s)
+
+ return
+ }
+
+ assert.NotEmpty(t, s)
+ assert.LessOrEqual(t, len(s), agd.MaxHumanIDLen)
+ })
+}
diff --git a/internal/agd/profile.go b/internal/agd/profile.go
index 382c6aa..a128492 100644
--- a/internal/agd/profile.go
+++ b/internal/agd/profile.go
@@ -11,8 +11,6 @@ import (
"github.com/AdguardTeam/golibs/errors"
)
-// Profiles
-
// Profile contains information about an AdGuard DNS profile. In other parts of
// the infrastructure, a profile is also called a “DNS server”. We call it
// profile, because it's less confusing.
@@ -139,6 +137,13 @@ type Profile struct {
// NOTE: Do not change fields of this structure without incrementing
// [internal/profiledb/internal.FileCacheVersion].
IPLogEnabled bool
+
+ // AutoDevicesEnabled shows if the automatic creation of devices using
+ // HumanIDs should be enabled for this profile.
+ //
+ // NOTE: Do not change fields of this structure without incrementing
+ // [internal/profiledb/internal.FileCacheVersion].
+ AutoDevicesEnabled bool
}
// ProfileID is the ID of a profile. It is an opaque string.
diff --git a/internal/agdcache/lru.go b/internal/agdcache/lru.go
index 228563a..3635b0e 100644
--- a/internal/agdcache/lru.go
+++ b/internal/agdcache/lru.go
@@ -82,25 +82,3 @@ func (c *LRU[K, T]) Len() (n int) {
return c.cache.Len(checkExpired)
}
-
-// Manager manages caches.
-type Manager struct {
- caches map[string]Clearer
-}
-
-// NewManager returns a new initialized *Manager.
-func NewManager() (m *Manager) {
- return &Manager{
- caches: map[string]Clearer{},
- }
-}
-
-// Add adds cache by id.
-func (m *Manager) Add(id string, cache Clearer) {
- m.caches[id] = cache
-}
-
-// ClearByID clears cache by id.
-func (m *Manager) ClearByID(id string) {
- m.caches[id].Clear()
-}
diff --git a/internal/agdcache/lru_test.go b/internal/agdcache/lru_test.go
index e9161d4..d6a1dd8 100644
--- a/internal/agdcache/lru_test.go
+++ b/internal/agdcache/lru_test.go
@@ -35,35 +35,3 @@ func TestLRU(t *testing.T) {
assert.Equal(t, 0, cache.Len())
}
-
-func TestManager(t *testing.T) {
- const (
- key = "key"
- val = 123
- id = "cacheID"
-
- nonExistingKey = "nonExistingKey"
- )
-
- cache := agdcache.NewLRU[string, int](&agdcache.LRUConfig{
- Size: 10,
- })
-
- cache.Set(key, val)
-
- assert.Equal(t, 1, cache.Len())
-
- v, ok := cache.Get(key)
- assert.Equal(t, val, v)
- assert.True(t, ok)
-
- v, ok = cache.Get(nonExistingKey)
- assert.Equal(t, 0, v)
- assert.False(t, ok)
-
- m := agdcache.NewManager()
- m.Add(id, cache)
- m.ClearByID(id)
-
- assert.Equal(t, 0, cache.Len())
-}
diff --git a/internal/agdcache/manager.go b/internal/agdcache/manager.go
new file mode 100644
index 0000000..70d4ac7
--- /dev/null
+++ b/internal/agdcache/manager.go
@@ -0,0 +1,89 @@
+package agdcache
+
+import (
+ "slices"
+ "sync"
+
+ "golang.org/x/exp/maps"
+)
+
+// Manager is the cache manager interface. All methods must be safe for
+// concurrent use.
+type Manager interface {
+ // Add adds cache by id. cache must not be nil.
+ //
+ // TODO(s.chzhen): Add Set method that rewrites the cache associated with
+ // id (current Add implementation).
+ //
+ // TODO(s.chzhen): Add panic on adding cache with duplicate id.
+ Add(id string, cache Clearer)
+
+ // ClearByID clears cache by id.
+ ClearByID(id string)
+}
+
+// DefaultManager implements the [Manager] interface that stores caches and can
+// clear them by id
+type DefaultManager struct {
+ mu *sync.Mutex
+ caches map[string]Clearer
+}
+
+// NewDefaultManager returns a new initialized *DefaultManager.
+func NewDefaultManager() (m *DefaultManager) {
+ return &DefaultManager{
+ mu: &sync.Mutex{},
+ caches: map[string]Clearer{},
+ }
+}
+
+// type check
+var _ Manager = (*DefaultManager)(nil)
+
+// Add implements the [Manager] interface for *DefaultManager. Note that it
+// replaces the saved cache with the same id if there is one.
+func (m *DefaultManager) Add(id string, cache Clearer) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ m.caches[id] = cache
+}
+
+// ClearByID implements the [Manager] interface for *DefaultManager.
+func (m *DefaultManager) ClearByID(id string) {
+ cache := m.findByID(id)
+ if cache != nil {
+ cache.Clear()
+ }
+}
+
+// findByID returns the stored cache by id or nil.
+func (m *DefaultManager) findByID(id string) (cache Clearer) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ return m.caches[id]
+}
+
+// IDs returns a sorted list of stored cache identifiers.
+func (m *DefaultManager) IDs() (ids []string) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ ids = maps.Keys(m.caches)
+ slices.Sort(ids)
+
+ return ids
+}
+
+// EmptyManager implements the [Manager] interface that does nothing.
+type EmptyManager struct{}
+
+// type check
+var _ Manager = EmptyManager{}
+
+// Add implements the [Manager] interface for *EmptyManager.
+func (EmptyManager) Add(_ string, _ Clearer) {}
+
+// ClearByID implements the [Manager] interface for *EmptyManager.
+func (EmptyManager) ClearByID(_ string) {}
diff --git a/internal/agdcache/manager_test.go b/internal/agdcache/manager_test.go
new file mode 100644
index 0000000..e21a855
--- /dev/null
+++ b/internal/agdcache/manager_test.go
@@ -0,0 +1,43 @@
+package agdcache_test
+
+import (
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestManager(t *testing.T) {
+ const (
+ cacheID = "cacheID"
+ cacheIDNonExisting = "non_existing_cache_id"
+ )
+
+ isCleared := false
+ mc := &mockClearer{
+ onClear: func() {
+ isCleared = true
+ },
+ }
+
+ m := agdcache.NewDefaultManager()
+ m.Add(cacheID, mc)
+ m.ClearByID(cacheID)
+
+ assert.True(t, isCleared)
+
+ assert.NotPanics(t, func() { m.ClearByID(cacheIDNonExisting) })
+}
+
+// mockClearer is the mock implementation of the [agdcache.Clearer] for tests.
+type mockClearer struct {
+ onClear func()
+}
+
+// type check
+var _ agdcache.Clearer = (*mockClearer)(nil)
+
+// Clear implements the [agdcache.Clearer] interface for *mockClearer.
+func (mc *mockClearer) Clear() {
+ mc.onClear()
+}
diff --git a/internal/agdtest/interface.go b/internal/agdtest/interface.go
index c5cd63b..b70d412 100644
--- a/internal/agdtest/interface.go
+++ b/internal/agdtest/interface.go
@@ -284,20 +284,55 @@ var _ profiledb.Interface = (*ProfileDB)(nil)
// ProfileDB is a [profiledb.Interface] for tests.
type ProfileDB struct {
- OnProfileByDeviceID func(
+ OnCreateAutoDevice func(
ctx context.Context,
- id agd.DeviceID,
+ id agd.ProfileID,
+ humanID agd.HumanID,
+ devType agd.DeviceType,
) (p *agd.Profile, d *agd.Device, err error)
+
OnProfileByDedicatedIP func(
ctx context.Context,
ip netip.Addr,
) (p *agd.Profile, d *agd.Device, err error)
+
+ OnProfileByDeviceID func(
+ ctx context.Context,
+ id agd.DeviceID,
+ ) (p *agd.Profile, d *agd.Device, err error)
+
+ OnProfileByHumanID func(
+ ctx context.Context,
+ id agd.ProfileID,
+ humanID agd.HumanIDLower,
+ ) (p *agd.Profile, d *agd.Device, err error)
+
OnProfileByLinkedIP func(
ctx context.Context,
ip netip.Addr,
) (p *agd.Profile, d *agd.Device, err error)
}
+// CreateAutoDevice implements the [profiledb.Interface] interface for
+// *ProfileDB.
+func (db *ProfileDB) CreateAutoDevice(
+ ctx context.Context,
+ id agd.ProfileID,
+ humanID agd.HumanID,
+ devType agd.DeviceType,
+) (p *agd.Profile, d *agd.Device, err error) {
+ return db.OnCreateAutoDevice(ctx, id, humanID, devType)
+}
+
+// ProfileByDedicatedIP implements the [profiledb.Interface] interface for
+// *ProfileDB.
+func (db *ProfileDB) ProfileByDedicatedIP(
+ ctx context.Context,
+ ip netip.Addr,
+) (p *agd.Profile, d *agd.Device, err error) {
+ return db.OnProfileByDedicatedIP(ctx, ip)
+}
+
// ProfileByDeviceID implements the [profiledb.Interface] interface for
// *ProfileDB.
func (db *ProfileDB) ProfileByDeviceID(
@@ -307,13 +342,14 @@ func (db *ProfileDB) ProfileByDeviceID(
return db.OnProfileByDeviceID(ctx, id)
}
-// ProfileByDedicatedIP implements the [profiledb.Interface] interface for
+// ProfileByHumanID implements the [profiledb.Interface] interface for
// *ProfileDB.
-func (db *ProfileDB) ProfileByDedicatedIP(
+func (db *ProfileDB) ProfileByHumanID(
ctx context.Context,
- ip netip.Addr,
+ id agd.ProfileID,
+ humanID agd.HumanIDLower,
) (p *agd.Profile, d *agd.Device, err error) {
- return db.OnProfileByDedicatedIP(ctx, ip)
+ return db.OnProfileByHumanID(ctx, id, humanID)
}
// ProfileByLinkedIP implements the [profiledb.Interface] interface for
@@ -328,19 +364,33 @@ func (db *ProfileDB) ProfileByLinkedIP(
// type check
var _ profiledb.Storage = (*ProfileStorage)(nil)
-// ProfileStorage is a profiledb.Storage for tests.
+// ProfileStorage is a [profiledb.Storage] implementation for tests.
type ProfileStorage struct {
+ OnCreateAutoDevice func(
+ ctx context.Context,
+ req *profiledb.StorageCreateAutoDeviceRequest,
+ ) (resp *profiledb.StorageCreateAutoDeviceResponse, err error)
+
OnProfiles func(
ctx context.Context,
- req *profiledb.StorageRequest,
- ) (resp *profiledb.StorageResponse, err error)
+ req *profiledb.StorageProfilesRequest,
+ ) (resp *profiledb.StorageProfilesResponse, err error)
+}
+
+// CreateAutoDevice implements the [profiledb.Storage] interface for
+// *ProfileStorage.
+func (s *ProfileStorage) CreateAutoDevice(
+ ctx context.Context,
+ req *profiledb.StorageCreateAutoDeviceRequest,
+) (resp *profiledb.StorageCreateAutoDeviceResponse, err error) {
+ return s.OnCreateAutoDevice(ctx, req)
}
// Profiles implements the [profiledb.Storage] interface for *ProfileStorage.
func (s *ProfileStorage) Profiles(
ctx context.Context,
- req *profiledb.StorageRequest,
-) (resp *profiledb.StorageResponse, err error) {
+ req *profiledb.StorageProfilesRequest,
+) (resp *profiledb.StorageProfilesResponse, err error) {
return s.OnProfiles(ctx, req)
}
diff --git a/internal/backendpb/backend.pb.go b/internal/backendpb/backend.pb.go
deleted file mode 100644
index dbbc954..0000000
--- a/internal/backendpb/backend.pb.go
+++ /dev/null
@@ -1,1789 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.33.0
-// protoc v4.25.3
-// source: backend.proto
-
-package backendpb
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- durationpb "google.golang.org/protobuf/types/known/durationpb"
- emptypb "google.golang.org/protobuf/types/known/emptypb"
- timestamppb "google.golang.org/protobuf/types/known/timestamppb"
- reflect "reflect"
- sync "sync"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type DNSProfilesRequest struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- SyncTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=sync_time,json=syncTime,proto3" json:"sync_time,omitempty"`
-}
-
-func (x *DNSProfilesRequest) Reset() {
- *x = DNSProfilesRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *DNSProfilesRequest) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*DNSProfilesRequest) ProtoMessage() {}
-
-func (x *DNSProfilesRequest) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use DNSProfilesRequest.ProtoReflect.Descriptor instead.
-func (*DNSProfilesRequest) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *DNSProfilesRequest) GetSyncTime() *timestamppb.Timestamp {
- if x != nil {
- return x.SyncTime
- }
- return nil
-}
-
-type DNSProfile struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- DnsId string `protobuf:"bytes,1,opt,name=dns_id,json=dnsId,proto3" json:"dns_id,omitempty"`
- FilteringEnabled bool `protobuf:"varint,2,opt,name=filtering_enabled,json=filteringEnabled,proto3" json:"filtering_enabled,omitempty"`
- QueryLogEnabled bool `protobuf:"varint,3,opt,name=query_log_enabled,json=queryLogEnabled,proto3" json:"query_log_enabled,omitempty"`
- Deleted bool `protobuf:"varint,4,opt,name=deleted,proto3" json:"deleted,omitempty"`
- SafeBrowsing *SafeBrowsingSettings `protobuf:"bytes,5,opt,name=safe_browsing,json=safeBrowsing,proto3" json:"safe_browsing,omitempty"`
- Parental *ParentalSettings `protobuf:"bytes,6,opt,name=parental,proto3" json:"parental,omitempty"`
- RuleLists *RuleListsSettings `protobuf:"bytes,7,opt,name=rule_lists,json=ruleLists,proto3" json:"rule_lists,omitempty"`
- Devices []*DeviceSettings `protobuf:"bytes,8,rep,name=devices,proto3" json:"devices,omitempty"`
- CustomRules []string `protobuf:"bytes,9,rep,name=custom_rules,json=customRules,proto3" json:"custom_rules,omitempty"`
- FilteredResponseTtl *durationpb.Duration `protobuf:"bytes,10,opt,name=filtered_response_ttl,json=filteredResponseTtl,proto3" json:"filtered_response_ttl,omitempty"`
- BlockPrivateRelay bool `protobuf:"varint,11,opt,name=block_private_relay,json=blockPrivateRelay,proto3" json:"block_private_relay,omitempty"`
- BlockFirefoxCanary bool `protobuf:"varint,12,opt,name=block_firefox_canary,json=blockFirefoxCanary,proto3" json:"block_firefox_canary,omitempty"`
- // Types that are assignable to BlockingMode:
- //
- // *DNSProfile_BlockingModeCustomIp
- // *DNSProfile_BlockingModeNxdomain
- // *DNSProfile_BlockingModeNullIp
- // *DNSProfile_BlockingModeRefused
- BlockingMode isDNSProfile_BlockingMode `protobuf_oneof:"blocking_mode"`
- IpLogEnabled bool `protobuf:"varint,17,opt,name=ip_log_enabled,json=ipLogEnabled,proto3" json:"ip_log_enabled,omitempty"`
- Access *AccessSettings `protobuf:"bytes,18,opt,name=access,proto3" json:"access,omitempty"`
-}
-
-func (x *DNSProfile) Reset() {
- *x = DNSProfile{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *DNSProfile) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*DNSProfile) ProtoMessage() {}
-
-func (x *DNSProfile) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[1]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use DNSProfile.ProtoReflect.Descriptor instead.
-func (*DNSProfile) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *DNSProfile) GetDnsId() string {
- if x != nil {
- return x.DnsId
- }
- return ""
-}
-
-func (x *DNSProfile) GetFilteringEnabled() bool {
- if x != nil {
- return x.FilteringEnabled
- }
- return false
-}
-
-func (x *DNSProfile) GetQueryLogEnabled() bool {
- if x != nil {
- return x.QueryLogEnabled
- }
- return false
-}
-
-func (x *DNSProfile) GetDeleted() bool {
- if x != nil {
- return x.Deleted
- }
- return false
-}
-
-func (x *DNSProfile) GetSafeBrowsing() *SafeBrowsingSettings {
- if x != nil {
- return x.SafeBrowsing
- }
- return nil
-}
-
-func (x *DNSProfile) GetParental() *ParentalSettings {
- if x != nil {
- return x.Parental
- }
- return nil
-}
-
-func (x *DNSProfile) GetRuleLists() *RuleListsSettings {
- if x != nil {
- return x.RuleLists
- }
- return nil
-}
-
-func (x *DNSProfile) GetDevices() []*DeviceSettings {
- if x != nil {
- return x.Devices
- }
- return nil
-}
-
-func (x *DNSProfile) GetCustomRules() []string {
- if x != nil {
- return x.CustomRules
- }
- return nil
-}
-
-func (x *DNSProfile) GetFilteredResponseTtl() *durationpb.Duration {
- if x != nil {
- return x.FilteredResponseTtl
- }
- return nil
-}
-
-func (x *DNSProfile) GetBlockPrivateRelay() bool {
- if x != nil {
- return x.BlockPrivateRelay
- }
- return false
-}
-
-func (x *DNSProfile) GetBlockFirefoxCanary() bool {
- if x != nil {
- return x.BlockFirefoxCanary
- }
- return false
-}
-
-func (m *DNSProfile) GetBlockingMode() isDNSProfile_BlockingMode {
- if m != nil {
- return m.BlockingMode
- }
- return nil
-}
-
-func (x *DNSProfile) GetBlockingModeCustomIp() *BlockingModeCustomIP {
- if x, ok := x.GetBlockingMode().(*DNSProfile_BlockingModeCustomIp); ok {
- return x.BlockingModeCustomIp
- }
- return nil
-}
-
-func (x *DNSProfile) GetBlockingModeNxdomain() *BlockingModeNXDOMAIN {
- if x, ok := x.GetBlockingMode().(*DNSProfile_BlockingModeNxdomain); ok {
- return x.BlockingModeNxdomain
- }
- return nil
-}
-
-func (x *DNSProfile) GetBlockingModeNullIp() *BlockingModeNullIP {
- if x, ok := x.GetBlockingMode().(*DNSProfile_BlockingModeNullIp); ok {
- return x.BlockingModeNullIp
- }
- return nil
-}
-
-func (x *DNSProfile) GetBlockingModeRefused() *BlockingModeREFUSED {
- if x, ok := x.GetBlockingMode().(*DNSProfile_BlockingModeRefused); ok {
- return x.BlockingModeRefused
- }
- return nil
-}
-
-func (x *DNSProfile) GetIpLogEnabled() bool {
- if x != nil {
- return x.IpLogEnabled
- }
- return false
-}
-
-func (x *DNSProfile) GetAccess() *AccessSettings {
- if x != nil {
- return x.Access
- }
- return nil
-}
-
-type isDNSProfile_BlockingMode interface {
- isDNSProfile_BlockingMode()
-}
-
-type DNSProfile_BlockingModeCustomIp struct {
- BlockingModeCustomIp *BlockingModeCustomIP `protobuf:"bytes,13,opt,name=blocking_mode_custom_ip,json=blockingModeCustomIp,proto3,oneof"`
-}
-
-type DNSProfile_BlockingModeNxdomain struct {
- BlockingModeNxdomain *BlockingModeNXDOMAIN `protobuf:"bytes,14,opt,name=blocking_mode_nxdomain,json=blockingModeNxdomain,proto3,oneof"`
-}
-
-type DNSProfile_BlockingModeNullIp struct {
- BlockingModeNullIp *BlockingModeNullIP `protobuf:"bytes,15,opt,name=blocking_mode_null_ip,json=blockingModeNullIp,proto3,oneof"`
-}
-
-type DNSProfile_BlockingModeRefused struct {
- BlockingModeRefused *BlockingModeREFUSED `protobuf:"bytes,16,opt,name=blocking_mode_refused,json=blockingModeRefused,proto3,oneof"`
-}
-
-func (*DNSProfile_BlockingModeCustomIp) isDNSProfile_BlockingMode() {}
-
-func (*DNSProfile_BlockingModeNxdomain) isDNSProfile_BlockingMode() {}
-
-func (*DNSProfile_BlockingModeNullIp) isDNSProfile_BlockingMode() {}
-
-func (*DNSProfile_BlockingModeRefused) isDNSProfile_BlockingMode() {}
-
-type SafeBrowsingSettings struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
- BlockDangerousDomains bool `protobuf:"varint,2,opt,name=block_dangerous_domains,json=blockDangerousDomains,proto3" json:"block_dangerous_domains,omitempty"`
- BlockNrd bool `protobuf:"varint,3,opt,name=block_nrd,json=blockNrd,proto3" json:"block_nrd,omitempty"`
-}
-
-func (x *SafeBrowsingSettings) Reset() {
- *x = SafeBrowsingSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *SafeBrowsingSettings) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SafeBrowsingSettings) ProtoMessage() {}
-
-func (x *SafeBrowsingSettings) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[2]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SafeBrowsingSettings.ProtoReflect.Descriptor instead.
-func (*SafeBrowsingSettings) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{2}
-}
-
-func (x *SafeBrowsingSettings) GetEnabled() bool {
- if x != nil {
- return x.Enabled
- }
- return false
-}
-
-func (x *SafeBrowsingSettings) GetBlockDangerousDomains() bool {
- if x != nil {
- return x.BlockDangerousDomains
- }
- return false
-}
-
-func (x *SafeBrowsingSettings) GetBlockNrd() bool {
- if x != nil {
- return x.BlockNrd
- }
- return false
-}
-
-type DeviceSettings struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
- Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
- FilteringEnabled bool `protobuf:"varint,3,opt,name=filtering_enabled,json=filteringEnabled,proto3" json:"filtering_enabled,omitempty"`
- LinkedIp []byte `protobuf:"bytes,4,opt,name=linked_ip,json=linkedIp,proto3" json:"linked_ip,omitempty"`
- DedicatedIps [][]byte `protobuf:"bytes,5,rep,name=dedicated_ips,json=dedicatedIps,proto3" json:"dedicated_ips,omitempty"`
- Authentication *AuthenticationSettings `protobuf:"bytes,6,opt,name=authentication,proto3" json:"authentication,omitempty"`
-}
-
-func (x *DeviceSettings) Reset() {
- *x = DeviceSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[3]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *DeviceSettings) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*DeviceSettings) ProtoMessage() {}
-
-func (x *DeviceSettings) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[3]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use DeviceSettings.ProtoReflect.Descriptor instead.
-func (*DeviceSettings) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{3}
-}
-
-func (x *DeviceSettings) GetId() string {
- if x != nil {
- return x.Id
- }
- return ""
-}
-
-func (x *DeviceSettings) GetName() string {
- if x != nil {
- return x.Name
- }
- return ""
-}
-
-func (x *DeviceSettings) GetFilteringEnabled() bool {
- if x != nil {
- return x.FilteringEnabled
- }
- return false
-}
-
-func (x *DeviceSettings) GetLinkedIp() []byte {
- if x != nil {
- return x.LinkedIp
- }
- return nil
-}
-
-func (x *DeviceSettings) GetDedicatedIps() [][]byte {
- if x != nil {
- return x.DedicatedIps
- }
- return nil
-}
-
-func (x *DeviceSettings) GetAuthentication() *AuthenticationSettings {
- if x != nil {
- return x.Authentication
- }
- return nil
-}
-
-type ParentalSettings struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
- BlockAdult bool `protobuf:"varint,2,opt,name=block_adult,json=blockAdult,proto3" json:"block_adult,omitempty"`
- GeneralSafeSearch bool `protobuf:"varint,3,opt,name=general_safe_search,json=generalSafeSearch,proto3" json:"general_safe_search,omitempty"`
- YoutubeSafeSearch bool `protobuf:"varint,4,opt,name=youtube_safe_search,json=youtubeSafeSearch,proto3" json:"youtube_safe_search,omitempty"`
- BlockedServices []string `protobuf:"bytes,5,rep,name=blocked_services,json=blockedServices,proto3" json:"blocked_services,omitempty"`
- Schedule *ScheduleSettings `protobuf:"bytes,6,opt,name=schedule,proto3" json:"schedule,omitempty"`
-}
-
-func (x *ParentalSettings) Reset() {
- *x = ParentalSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[4]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *ParentalSettings) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*ParentalSettings) ProtoMessage() {}
-
-func (x *ParentalSettings) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[4]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use ParentalSettings.ProtoReflect.Descriptor instead.
-func (*ParentalSettings) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{4}
-}
-
-func (x *ParentalSettings) GetEnabled() bool {
- if x != nil {
- return x.Enabled
- }
- return false
-}
-
-func (x *ParentalSettings) GetBlockAdult() bool {
- if x != nil {
- return x.BlockAdult
- }
- return false
-}
-
-func (x *ParentalSettings) GetGeneralSafeSearch() bool {
- if x != nil {
- return x.GeneralSafeSearch
- }
- return false
-}
-
-func (x *ParentalSettings) GetYoutubeSafeSearch() bool {
- if x != nil {
- return x.YoutubeSafeSearch
- }
- return false
-}
-
-func (x *ParentalSettings) GetBlockedServices() []string {
- if x != nil {
- return x.BlockedServices
- }
- return nil
-}
-
-func (x *ParentalSettings) GetSchedule() *ScheduleSettings {
- if x != nil {
- return x.Schedule
- }
- return nil
-}
-
-type ScheduleSettings struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Tmz string `protobuf:"bytes,1,opt,name=tmz,proto3" json:"tmz,omitempty"`
- WeeklyRange *WeeklyRange `protobuf:"bytes,2,opt,name=weeklyRange,proto3" json:"weeklyRange,omitempty"`
-}
-
-func (x *ScheduleSettings) Reset() {
- *x = ScheduleSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[5]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *ScheduleSettings) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*ScheduleSettings) ProtoMessage() {}
-
-func (x *ScheduleSettings) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[5]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use ScheduleSettings.ProtoReflect.Descriptor instead.
-func (*ScheduleSettings) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{5}
-}
-
-func (x *ScheduleSettings) GetTmz() string {
- if x != nil {
- return x.Tmz
- }
- return ""
-}
-
-func (x *ScheduleSettings) GetWeeklyRange() *WeeklyRange {
- if x != nil {
- return x.WeeklyRange
- }
- return nil
-}
-
-type WeeklyRange struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Mon *DayRange `protobuf:"bytes,1,opt,name=mon,proto3" json:"mon,omitempty"`
- Tue *DayRange `protobuf:"bytes,2,opt,name=tue,proto3" json:"tue,omitempty"`
- Wed *DayRange `protobuf:"bytes,3,opt,name=wed,proto3" json:"wed,omitempty"`
- Thu *DayRange `protobuf:"bytes,4,opt,name=thu,proto3" json:"thu,omitempty"`
- Fri *DayRange `protobuf:"bytes,5,opt,name=fri,proto3" json:"fri,omitempty"`
- Sat *DayRange `protobuf:"bytes,6,opt,name=sat,proto3" json:"sat,omitempty"`
- Sun *DayRange `protobuf:"bytes,7,opt,name=sun,proto3" json:"sun,omitempty"`
-}
-
-func (x *WeeklyRange) Reset() {
- *x = WeeklyRange{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[6]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *WeeklyRange) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*WeeklyRange) ProtoMessage() {}
-
-func (x *WeeklyRange) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[6]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use WeeklyRange.ProtoReflect.Descriptor instead.
-func (*WeeklyRange) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{6}
-}
-
-func (x *WeeklyRange) GetMon() *DayRange {
- if x != nil {
- return x.Mon
- }
- return nil
-}
-
-func (x *WeeklyRange) GetTue() *DayRange {
- if x != nil {
- return x.Tue
- }
- return nil
-}
-
-func (x *WeeklyRange) GetWed() *DayRange {
- if x != nil {
- return x.Wed
- }
- return nil
-}
-
-func (x *WeeklyRange) GetThu() *DayRange {
- if x != nil {
- return x.Thu
- }
- return nil
-}
-
-func (x *WeeklyRange) GetFri() *DayRange {
- if x != nil {
- return x.Fri
- }
- return nil
-}
-
-func (x *WeeklyRange) GetSat() *DayRange {
- if x != nil {
- return x.Sat
- }
- return nil
-}
-
-func (x *WeeklyRange) GetSun() *DayRange {
- if x != nil {
- return x.Sun
- }
- return nil
-}
-
-type DayRange struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Start *durationpb.Duration `protobuf:"bytes,1,opt,name=start,proto3" json:"start,omitempty"`
- End *durationpb.Duration `protobuf:"bytes,2,opt,name=end,proto3" json:"end,omitempty"`
-}
-
-func (x *DayRange) Reset() {
- *x = DayRange{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[7]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *DayRange) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*DayRange) ProtoMessage() {}
-
-func (x *DayRange) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[7]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use DayRange.ProtoReflect.Descriptor instead.
-func (*DayRange) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{7}
-}
-
-func (x *DayRange) GetStart() *durationpb.Duration {
- if x != nil {
- return x.Start
- }
- return nil
-}
-
-func (x *DayRange) GetEnd() *durationpb.Duration {
- if x != nil {
- return x.End
- }
- return nil
-}
-
-type RuleListsSettings struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
- Ids []string `protobuf:"bytes,2,rep,name=ids,proto3" json:"ids,omitempty"`
-}
-
-func (x *RuleListsSettings) Reset() {
- *x = RuleListsSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[8]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *RuleListsSettings) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*RuleListsSettings) ProtoMessage() {}
-
-func (x *RuleListsSettings) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[8]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use RuleListsSettings.ProtoReflect.Descriptor instead.
-func (*RuleListsSettings) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{8}
-}
-
-func (x *RuleListsSettings) GetEnabled() bool {
- if x != nil {
- return x.Enabled
- }
- return false
-}
-
-func (x *RuleListsSettings) GetIds() []string {
- if x != nil {
- return x.Ids
- }
- return nil
-}
-
-type BlockingModeCustomIP struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Ipv4 []byte `protobuf:"bytes,1,opt,name=ipv4,proto3" json:"ipv4,omitempty"`
- Ipv6 []byte `protobuf:"bytes,2,opt,name=ipv6,proto3" json:"ipv6,omitempty"`
-}
-
-func (x *BlockingModeCustomIP) Reset() {
- *x = BlockingModeCustomIP{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[9]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *BlockingModeCustomIP) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*BlockingModeCustomIP) ProtoMessage() {}
-
-func (x *BlockingModeCustomIP) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[9]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use BlockingModeCustomIP.ProtoReflect.Descriptor instead.
-func (*BlockingModeCustomIP) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{9}
-}
-
-func (x *BlockingModeCustomIP) GetIpv4() []byte {
- if x != nil {
- return x.Ipv4
- }
- return nil
-}
-
-func (x *BlockingModeCustomIP) GetIpv6() []byte {
- if x != nil {
- return x.Ipv6
- }
- return nil
-}
-
-type BlockingModeNXDOMAIN struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-}
-
-func (x *BlockingModeNXDOMAIN) Reset() {
- *x = BlockingModeNXDOMAIN{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[10]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *BlockingModeNXDOMAIN) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*BlockingModeNXDOMAIN) ProtoMessage() {}
-
-func (x *BlockingModeNXDOMAIN) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[10]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use BlockingModeNXDOMAIN.ProtoReflect.Descriptor instead.
-func (*BlockingModeNXDOMAIN) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{10}
-}
-
-type BlockingModeNullIP struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-}
-
-func (x *BlockingModeNullIP) Reset() {
- *x = BlockingModeNullIP{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[11]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *BlockingModeNullIP) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*BlockingModeNullIP) ProtoMessage() {}
-
-func (x *BlockingModeNullIP) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[11]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use BlockingModeNullIP.ProtoReflect.Descriptor instead.
-func (*BlockingModeNullIP) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{11}
-}
-
-type BlockingModeREFUSED struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-}
-
-func (x *BlockingModeREFUSED) Reset() {
- *x = BlockingModeREFUSED{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[12]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *BlockingModeREFUSED) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*BlockingModeREFUSED) ProtoMessage() {}
-
-func (x *BlockingModeREFUSED) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[12]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use BlockingModeREFUSED.ProtoReflect.Descriptor instead.
-func (*BlockingModeREFUSED) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{12}
-}
-
-type DeviceBillingStat struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- LastActivityTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=last_activity_time,json=lastActivityTime,proto3" json:"last_activity_time,omitempty"`
- DeviceId string `protobuf:"bytes,2,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
- ClientCountry string `protobuf:"bytes,3,opt,name=client_country,json=clientCountry,proto3" json:"client_country,omitempty"`
- // Protocol type. Possible values see here: https://bit.adguard.com/projects/DNS/repos/dns-server/browse#ql-properties
- Proto uint32 `protobuf:"varint,4,opt,name=proto,proto3" json:"proto,omitempty"`
- Asn uint32 `protobuf:"varint,5,opt,name=asn,proto3" json:"asn,omitempty"`
- Queries uint32 `protobuf:"varint,6,opt,name=queries,proto3" json:"queries,omitempty"`
-}
-
-func (x *DeviceBillingStat) Reset() {
- *x = DeviceBillingStat{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[13]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *DeviceBillingStat) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*DeviceBillingStat) ProtoMessage() {}
-
-func (x *DeviceBillingStat) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[13]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use DeviceBillingStat.ProtoReflect.Descriptor instead.
-func (*DeviceBillingStat) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{13}
-}
-
-func (x *DeviceBillingStat) GetLastActivityTime() *timestamppb.Timestamp {
- if x != nil {
- return x.LastActivityTime
- }
- return nil
-}
-
-func (x *DeviceBillingStat) GetDeviceId() string {
- if x != nil {
- return x.DeviceId
- }
- return ""
-}
-
-func (x *DeviceBillingStat) GetClientCountry() string {
- if x != nil {
- return x.ClientCountry
- }
- return ""
-}
-
-func (x *DeviceBillingStat) GetProto() uint32 {
- if x != nil {
- return x.Proto
- }
- return 0
-}
-
-func (x *DeviceBillingStat) GetAsn() uint32 {
- if x != nil {
- return x.Asn
- }
- return 0
-}
-
-func (x *DeviceBillingStat) GetQueries() uint32 {
- if x != nil {
- return x.Queries
- }
- return 0
-}
-
-type AccessSettings struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- AllowlistCidr []*CidrRange `protobuf:"bytes,1,rep,name=allowlist_cidr,json=allowlistCidr,proto3" json:"allowlist_cidr,omitempty"`
- BlocklistCidr []*CidrRange `protobuf:"bytes,2,rep,name=blocklist_cidr,json=blocklistCidr,proto3" json:"blocklist_cidr,omitempty"`
- AllowlistAsn []uint32 `protobuf:"varint,3,rep,packed,name=allowlist_asn,json=allowlistAsn,proto3" json:"allowlist_asn,omitempty"`
- BlocklistAsn []uint32 `protobuf:"varint,4,rep,packed,name=blocklist_asn,json=blocklistAsn,proto3" json:"blocklist_asn,omitempty"`
- BlocklistDomainRules []string `protobuf:"bytes,5,rep,name=blocklist_domain_rules,json=blocklistDomainRules,proto3" json:"blocklist_domain_rules,omitempty"`
- Enabled bool `protobuf:"varint,6,opt,name=enabled,proto3" json:"enabled,omitempty"`
-}
-
-func (x *AccessSettings) Reset() {
- *x = AccessSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[14]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *AccessSettings) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*AccessSettings) ProtoMessage() {}
-
-func (x *AccessSettings) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[14]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use AccessSettings.ProtoReflect.Descriptor instead.
-func (*AccessSettings) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{14}
-}
-
-func (x *AccessSettings) GetAllowlistCidr() []*CidrRange {
- if x != nil {
- return x.AllowlistCidr
- }
- return nil
-}
-
-func (x *AccessSettings) GetBlocklistCidr() []*CidrRange {
- if x != nil {
- return x.BlocklistCidr
- }
- return nil
-}
-
-func (x *AccessSettings) GetAllowlistAsn() []uint32 {
- if x != nil {
- return x.AllowlistAsn
- }
- return nil
-}
-
-func (x *AccessSettings) GetBlocklistAsn() []uint32 {
- if x != nil {
- return x.BlocklistAsn
- }
- return nil
-}
-
-func (x *AccessSettings) GetBlocklistDomainRules() []string {
- if x != nil {
- return x.BlocklistDomainRules
- }
- return nil
-}
-
-func (x *AccessSettings) GetEnabled() bool {
- if x != nil {
- return x.Enabled
- }
- return false
-}
-
-type CidrRange struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
- Prefix uint32 `protobuf:"varint,2,opt,name=prefix,proto3" json:"prefix,omitempty"`
-}
-
-func (x *CidrRange) Reset() {
- *x = CidrRange{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[15]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *CidrRange) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*CidrRange) ProtoMessage() {}
-
-func (x *CidrRange) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[15]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use CidrRange.ProtoReflect.Descriptor instead.
-func (*CidrRange) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{15}
-}
-
-func (x *CidrRange) GetAddress() []byte {
- if x != nil {
- return x.Address
- }
- return nil
-}
-
-func (x *CidrRange) GetPrefix() uint32 {
- if x != nil {
- return x.Prefix
- }
- return 0
-}
-
-type AuthenticationSettings struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- DohAuthOnly bool `protobuf:"varint,1,opt,name=doh_auth_only,json=dohAuthOnly,proto3" json:"doh_auth_only,omitempty"`
- // Types that are assignable to DohPasswordHash:
- //
- // *AuthenticationSettings_PasswordHashBcrypt
- DohPasswordHash isAuthenticationSettings_DohPasswordHash `protobuf_oneof:"doh_password_hash"`
-}
-
-func (x *AuthenticationSettings) Reset() {
- *x = AuthenticationSettings{}
- if protoimpl.UnsafeEnabled {
- mi := &file_backend_proto_msgTypes[16]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *AuthenticationSettings) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*AuthenticationSettings) ProtoMessage() {}
-
-func (x *AuthenticationSettings) ProtoReflect() protoreflect.Message {
- mi := &file_backend_proto_msgTypes[16]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use AuthenticationSettings.ProtoReflect.Descriptor instead.
-func (*AuthenticationSettings) Descriptor() ([]byte, []int) {
- return file_backend_proto_rawDescGZIP(), []int{16}
-}
-
-func (x *AuthenticationSettings) GetDohAuthOnly() bool {
- if x != nil {
- return x.DohAuthOnly
- }
- return false
-}
-
-func (m *AuthenticationSettings) GetDohPasswordHash() isAuthenticationSettings_DohPasswordHash {
- if m != nil {
- return m.DohPasswordHash
- }
- return nil
-}
-
-func (x *AuthenticationSettings) GetPasswordHashBcrypt() []byte {
- if x, ok := x.GetDohPasswordHash().(*AuthenticationSettings_PasswordHashBcrypt); ok {
- return x.PasswordHashBcrypt
- }
- return nil
-}
-
-type isAuthenticationSettings_DohPasswordHash interface {
- isAuthenticationSettings_DohPasswordHash()
-}
-
-type AuthenticationSettings_PasswordHashBcrypt struct {
- PasswordHashBcrypt []byte `protobuf:"bytes,2,opt,name=password_hash_bcrypt,json=passwordHashBcrypt,proto3,oneof"`
-}
-
-func (*AuthenticationSettings_PasswordHashBcrypt) isAuthenticationSettings_DohPasswordHash() {}
-
-var File_backend_proto protoreflect.FileDescriptor
-
-var file_backend_proto_rawDesc = []byte{
- 0x0a, 0x0d, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
- 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
- 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
- 0x1f, 0x67, 0x6f, 0x6f, 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, 0xc8, 0x07, 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, 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,
- 0xe4, 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
- 0x67, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
- 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
- 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, 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, 0x32, 0x8a, 0x01, 0x0a, 0x0a, 0x44, 0x4e, 0x53, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
- 0x12, 0x34, 0x0a, 0x0e, 0x67, 0x65, 0x74, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
- 0x65, 0x73, 0x12, 0x13, 0x2e, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73,
- 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f,
- 0x66, 0x69, 0x6c, 0x65, 0x30, 0x01, 0x12, 0x46, 0x0a, 0x16, 0x73, 0x61, 0x76, 0x65, 0x44, 0x65,
- 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74,
- 0x12, 0x12, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67,
- 0x53, 0x74, 0x61, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x42, 0x3d,
- 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x64, 0x67, 0x75, 0x61, 0x72, 0x64, 0x2e, 0x62, 0x61,
- 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
- 0x74, 0x65, 0x64, 0x42, 0x10, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73,
- 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0xa2, 0x02, 0x03, 0x44, 0x4e, 0x53, 0x62, 0x06, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
-
-var (
- file_backend_proto_rawDescOnce sync.Once
- file_backend_proto_rawDescData = file_backend_proto_rawDesc
-)
-
-func file_backend_proto_rawDescGZIP() []byte {
- file_backend_proto_rawDescOnce.Do(func() {
- file_backend_proto_rawDescData = protoimpl.X.CompressGZIP(file_backend_proto_rawDescData)
- })
- return file_backend_proto_rawDescData
-}
-
-var file_backend_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
-var file_backend_proto_goTypes = []interface{}{
- (*DNSProfilesRequest)(nil), // 0: DNSProfilesRequest
- (*DNSProfile)(nil), // 1: DNSProfile
- (*SafeBrowsingSettings)(nil), // 2: SafeBrowsingSettings
- (*DeviceSettings)(nil), // 3: DeviceSettings
- (*ParentalSettings)(nil), // 4: ParentalSettings
- (*ScheduleSettings)(nil), // 5: ScheduleSettings
- (*WeeklyRange)(nil), // 6: WeeklyRange
- (*DayRange)(nil), // 7: DayRange
- (*RuleListsSettings)(nil), // 8: RuleListsSettings
- (*BlockingModeCustomIP)(nil), // 9: BlockingModeCustomIP
- (*BlockingModeNXDOMAIN)(nil), // 10: BlockingModeNXDOMAIN
- (*BlockingModeNullIP)(nil), // 11: BlockingModeNullIP
- (*BlockingModeREFUSED)(nil), // 12: BlockingModeREFUSED
- (*DeviceBillingStat)(nil), // 13: DeviceBillingStat
- (*AccessSettings)(nil), // 14: AccessSettings
- (*CidrRange)(nil), // 15: CidrRange
- (*AuthenticationSettings)(nil), // 16: AuthenticationSettings
- (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp
- (*durationpb.Duration)(nil), // 18: google.protobuf.Duration
- (*emptypb.Empty)(nil), // 19: google.protobuf.Empty
-}
-var file_backend_proto_depIdxs = []int32{
- 17, // 0: DNSProfilesRequest.sync_time:type_name -> google.protobuf.Timestamp
- 2, // 1: DNSProfile.safe_browsing:type_name -> SafeBrowsingSettings
- 4, // 2: DNSProfile.parental:type_name -> ParentalSettings
- 8, // 3: DNSProfile.rule_lists:type_name -> RuleListsSettings
- 3, // 4: DNSProfile.devices:type_name -> DeviceSettings
- 18, // 5: DNSProfile.filtered_response_ttl:type_name -> google.protobuf.Duration
- 9, // 6: DNSProfile.blocking_mode_custom_ip:type_name -> BlockingModeCustomIP
- 10, // 7: DNSProfile.blocking_mode_nxdomain:type_name -> BlockingModeNXDOMAIN
- 11, // 8: DNSProfile.blocking_mode_null_ip:type_name -> BlockingModeNullIP
- 12, // 9: DNSProfile.blocking_mode_refused:type_name -> BlockingModeREFUSED
- 14, // 10: DNSProfile.access:type_name -> AccessSettings
- 16, // 11: DeviceSettings.authentication:type_name -> AuthenticationSettings
- 5, // 12: ParentalSettings.schedule:type_name -> ScheduleSettings
- 6, // 13: ScheduleSettings.weeklyRange:type_name -> WeeklyRange
- 7, // 14: WeeklyRange.mon:type_name -> DayRange
- 7, // 15: WeeklyRange.tue:type_name -> DayRange
- 7, // 16: WeeklyRange.wed:type_name -> DayRange
- 7, // 17: WeeklyRange.thu:type_name -> DayRange
- 7, // 18: WeeklyRange.fri:type_name -> DayRange
- 7, // 19: WeeklyRange.sat:type_name -> DayRange
- 7, // 20: WeeklyRange.sun:type_name -> DayRange
- 18, // 21: DayRange.start:type_name -> google.protobuf.Duration
- 18, // 22: DayRange.end:type_name -> google.protobuf.Duration
- 17, // 23: DeviceBillingStat.last_activity_time:type_name -> google.protobuf.Timestamp
- 15, // 24: AccessSettings.allowlist_cidr:type_name -> CidrRange
- 15, // 25: AccessSettings.blocklist_cidr:type_name -> CidrRange
- 0, // 26: DNSService.getDNSProfiles:input_type -> DNSProfilesRequest
- 13, // 27: DNSService.saveDevicesBillingStat:input_type -> DeviceBillingStat
- 1, // 28: DNSService.getDNSProfiles:output_type -> DNSProfile
- 19, // 29: DNSService.saveDevicesBillingStat:output_type -> google.protobuf.Empty
- 28, // [28:30] is the sub-list for method output_type
- 26, // [26:28] is the sub-list for method input_type
- 26, // [26:26] is the sub-list for extension type_name
- 26, // [26:26] is the sub-list for extension extendee
- 0, // [0:26] is the sub-list for field type_name
-}
-
-func init() { file_backend_proto_init() }
-func file_backend_proto_init() {
- if File_backend_proto != nil {
- return
- }
- if !protoimpl.UnsafeEnabled {
- file_backend_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*DNSProfilesRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*DNSProfile); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*SafeBrowsingSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*DeviceSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ParentalSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ScheduleSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*WeeklyRange); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*DayRange); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*RuleListsSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*BlockingModeCustomIP); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*BlockingModeNXDOMAIN); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*BlockingModeNullIP); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*BlockingModeREFUSED); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*DeviceBillingStat); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*AccessSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*CidrRange); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_backend_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*AuthenticationSettings); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
- file_backend_proto_msgTypes[1].OneofWrappers = []interface{}{
- (*DNSProfile_BlockingModeCustomIp)(nil),
- (*DNSProfile_BlockingModeNxdomain)(nil),
- (*DNSProfile_BlockingModeNullIp)(nil),
- (*DNSProfile_BlockingModeRefused)(nil),
- }
- file_backend_proto_msgTypes[16].OneofWrappers = []interface{}{
- (*AuthenticationSettings_PasswordHashBcrypt)(nil),
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_backend_proto_rawDesc,
- NumEnums: 0,
- NumMessages: 17,
- NumExtensions: 0,
- NumServices: 1,
- },
- GoTypes: file_backend_proto_goTypes,
- DependencyIndexes: file_backend_proto_depIdxs,
- MessageInfos: file_backend_proto_msgTypes,
- }.Build()
- File_backend_proto = out.File
- file_backend_proto_rawDesc = nil
- file_backend_proto_goTypes = nil
- file_backend_proto_depIdxs = nil
-}
diff --git a/internal/backendpb/backendpb.go b/internal/backendpb/backendpb.go
index 9c98cea..0173310 100644
--- a/internal/backendpb/backendpb.go
+++ b/internal/backendpb/backendpb.go
@@ -1,4 +1,6 @@
// Package backendpb contains the protobuf structures for the backend API.
+//
+// TODO(a.garipov): Move the generated code into a separate package.
package backendpb
import (
@@ -7,9 +9,11 @@ import (
"net/url"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/golibs/httphdr"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
+ "google.golang.org/grpc/metadata"
)
// newClient returns new properly initialized DNSServiceClient.
@@ -25,7 +29,7 @@ func newClient(apiURL *url.URL) (client DNSServiceClient, err error) {
return nil, fmt.Errorf("bad grpc url scheme %q", s)
}
- conn, err := grpc.Dial(apiURL.Host, grpc.WithTransportCredentials(creds))
+ conn, err := grpc.NewClient(apiURL.Host, grpc.WithTransportCredentials(creds))
if err != nil {
return nil, fmt.Errorf("dialing: %w", err)
}
@@ -41,3 +45,17 @@ func newClient(apiURL *url.URL) (client DNSServiceClient, err error) {
func reportf(ctx context.Context, errColl errcoll.Interface, format string, args ...any) {
errcoll.Collectf(ctx, errColl, "backendpb: "+format, args...)
}
+
+// ctxWithAuthentication adds the API key authentication header to the outgoing
+// request context if apiKey is not empty. If it is empty, ctx is parent.
+func ctxWithAuthentication(parent context.Context, apiKey string) (ctx context.Context) {
+ ctx = parent
+ if apiKey == "" {
+ return ctx
+ }
+
+ // TODO(a.garipov): Better validations for the key.
+ md := metadata.Pairs(httphdr.Authorization, fmt.Sprintf("Bearer %s", apiKey))
+
+ return metadata.NewOutgoingContext(ctx, md)
+}
diff --git a/internal/backendpb/backendpb_internal_test.go b/internal/backendpb/backendpb_internal_test.go
new file mode 100644
index 0000000..fe7c81c
--- /dev/null
+++ b/internal/backendpb/backendpb_internal_test.go
@@ -0,0 +1,37 @@
+package backendpb
+
+import (
+ "net/netip"
+ "testing"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/golibs/testutil"
+)
+
+func TestMain(m *testing.M) {
+ testutil.DiscardLogOutput(m)
+}
+
+// Common IDs for tests and their string forms.
+//
+// TODO(a.garipov): Move all or most tests into external and unexport these.
+const (
+ TestDeviceIDStr = "dev1234"
+ TestHumanIDStr = "My-Device-X--10"
+ TestHumanIDLowerStr = "my-device-x--10"
+ TestProfileIDStr = "prof1234"
+
+ TestDeviceID agd.DeviceID = TestDeviceIDStr
+ TestHumanID agd.HumanID = TestHumanIDStr
+ TestHumanIDLower agd.HumanIDLower = TestHumanIDLowerStr
+ TestProfileID agd.ProfileID = TestProfileIDStr
+)
+
+// TestUpdTime is the common update time for tests.
+var TestUpdTime = time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)
+
+// TestBind includes any IPv4 address.
+//
+// TODO(a.garipov): Add to golibs/netutil.
+var TestBind = netip.MustParsePrefix("0.0.0.0/0")
diff --git a/internal/backendpb/backendpb_test.go b/internal/backendpb/backendpb_test.go
index 43b8a60..f2e4ac0 100644
--- a/internal/backendpb/backendpb_test.go
+++ b/internal/backendpb/backendpb_test.go
@@ -1,6 +1,14 @@
package backendpb_test
-import "github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
+import (
+ "context"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
+)
+
+// testTimeout is the common timeout for tests.
+const testTimeout = 1 * time.Second
// testDNSServiceServer is the [backendpb.DNSServiceServer] for tests.
//
@@ -8,10 +16,18 @@ import "github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
// test.
type testDNSServiceServer struct {
backendpb.UnimplementedDNSServiceServer
+
+ //lint:ignore ST1003 Keep in sync with the generated code.
+ OnCreateDeviceByHumanId func(
+ ctx context.Context,
+ req *backendpb.CreateDeviceRequest,
+ ) (resp *backendpb.CreateDeviceResponse, err error)
+
OnGetDNSProfiles func(
req *backendpb.DNSProfilesRequest,
srv backendpb.DNSService_GetDNSProfilesServer,
) (err error)
+
OnSaveDevicesBillingStat func(
srv backendpb.DNSService_SaveDevicesBillingStatServer,
) (err error)
@@ -20,6 +36,17 @@ type testDNSServiceServer struct {
// type check
var _ backendpb.DNSServiceServer = (*testDNSServiceServer)(nil)
+// CreateDeviceByHumanId implements the [backendpb.DNSServiceServer] interface
+// for *testDNSServiceServer.
+//
+//lint:ignore ST1003 Keep in sync with the generated code.
+func (s *testDNSServiceServer) CreateDeviceByHumanId(
+ ctx context.Context,
+ req *backendpb.CreateDeviceRequest,
+) (resp *backendpb.CreateDeviceResponse, err error) {
+ return s.OnCreateDeviceByHumanId(ctx, req)
+}
+
// GetDNSProfiles implements the [backendpb.DNSServiceServer] interface for
// *testDNSServiceServer
func (s *testDNSServiceServer) GetDNSProfiles(
diff --git a/internal/backendpb/billstat.go b/internal/backendpb/billstat.go
index 88722fb..0b899ce 100644
--- a/internal/backendpb/billstat.go
+++ b/internal/backendpb/billstat.go
@@ -23,21 +23,24 @@ type BillStatConfig struct {
// 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
}
// NewBillStat creates a new billing statistics uploader. c must not be nil.
func NewBillStat(c *BillStatConfig) (b *BillStat, err error) {
- b = &BillStat{
- errColl: c.ErrColl,
- }
-
- b.client, err = newClient(c.Endpoint)
+ client, err := newClient(c.Endpoint)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return nil, err
}
- return b, nil
+ return &BillStat{
+ errColl: c.ErrColl,
+ client: client,
+ apiKey: c.APIKey,
+ }, nil
}
// BillStat is the implementation of the [billstat.Uploader] interface that
@@ -48,9 +51,8 @@ func NewBillStat(c *BillStatConfig) (b *BillStat, err error) {
// backendpb.Client.
type BillStat struct {
errColl errcoll.Interface
-
- // client is the current GRPC client.
- client DNSServiceClient
+ client DNSServiceClient
+ apiKey string
}
// type check
@@ -62,9 +64,10 @@ func (b *BillStat) Upload(ctx context.Context, records billstat.Records) (err er
return nil
}
+ ctx = ctxWithAuthentication(ctx, b.apiKey)
stream, err := b.client.SaveDevicesBillingStat(ctx)
if err != nil {
- return fmt.Errorf("opening stream: %w", err)
+ return fmt.Errorf("opening stream: %w", fixGRPCError(err))
}
for deviceID, record := range records {
@@ -76,7 +79,7 @@ func (b *BillStat) Upload(ctx context.Context, records billstat.Records) (err er
sendErr := stream.Send(recordToProtobuf(record, deviceID))
if sendErr != nil {
- return fmt.Errorf("uploading device %q record: %w", deviceID, sendErr)
+ return fmt.Errorf("uploading device %q record: %w", deviceID, fixGRPCError(sendErr))
}
}
diff --git a/internal/backendpb/billstat_test.go b/internal/backendpb/billstat_test.go
index db0988e..28580ce 100644
--- a/internal/backendpb/billstat_test.go
+++ b/internal/backendpb/billstat_test.go
@@ -24,6 +24,8 @@ import (
)
func TestBillStat_Upload(t *testing.T) {
+ t.Parallel()
+
const (
wantDeviceID = "test"
invalidDeviceID = "invalid"
@@ -43,6 +45,20 @@ func TestBillStat_Upload(t *testing.T) {
}
srv := &testDNSServiceServer{
+ OnCreateDeviceByHumanId: func(
+ ctx context.Context,
+ req *backendpb.CreateDeviceRequest,
+ ) (resp *backendpb.CreateDeviceResponse, err error) {
+ panic("not implemented")
+ },
+
+ OnGetDNSProfiles: func(
+ req *backendpb.DNSProfilesRequest,
+ srv backendpb.DNSService_GetDNSProfilesServer,
+ ) (err error) {
+ panic("not implemented")
+ },
+
OnSaveDevicesBillingStat: func(
srv backendpb.DNSService_SaveDevicesBillingStatServer,
) (err error) {
diff --git a/internal/backendpb/device.go b/internal/backendpb/device.go
new file mode 100644
index 0000000..c997fdc
--- /dev/null
+++ b/internal/backendpb/device.go
@@ -0,0 +1,161 @@
+package backendpb
+
+import (
+ "context"
+ "fmt"
+ "net/netip"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdprotobuf"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/golibs/netutil"
+)
+
+// devicesToInternal is a helper that converts the devices from protobuf to
+// AdGuard DNS devices.
+func devicesToInternal(
+ ctx context.Context,
+ ds []*DeviceSettings,
+ bindSet netutil.SubnetSet,
+ errColl errcoll.Interface,
+) (out []*agd.Device, ids []agd.DeviceID) {
+ l := len(ds)
+ if l == 0 {
+ return nil, nil
+ }
+
+ out = make([]*agd.Device, 0, l)
+ for _, d := range ds {
+ dev, err := d.toInternal(bindSet)
+ if err != nil {
+ var id string
+ if d != nil {
+ id = d.Id
+ }
+
+ reportf(ctx, errColl, "bad device settings for device with id %q: %w", id, err)
+ metrics.DevicesInvalidTotal.Inc()
+
+ continue
+ }
+
+ ids = append(ids, dev.ID)
+ out = append(out, dev)
+ }
+
+ return out, ids
+}
+
+// toInternal is a helper that converts device settings from backend protobuf
+// response to AdGuard DNS device object.
+func (ds *DeviceSettings) toInternal(bindSet netutil.SubnetSet) (dev *agd.Device, err error) {
+ if ds == nil {
+ return nil, fmt.Errorf("device is nil")
+ }
+
+ var linkedIP netip.Addr
+ err = linkedIP.UnmarshalBinary(ds.LinkedIp)
+ if err != nil {
+ return nil, fmt.Errorf("linked ip: %w", err)
+ }
+
+ var dedicatedIPs []netip.Addr
+ dedicatedIPs, err = ds.dedicatedIPsToInternal(bindSet)
+ if err != nil {
+ return nil, fmt.Errorf("dedicated ips: %w", err)
+ }
+
+ auth, err := ds.Authentication.toInternal()
+ if err != nil {
+ return nil, fmt.Errorf("auth: %w", err)
+ }
+
+ id, err := agd.NewDeviceID(ds.Id)
+ if err != nil {
+ return nil, fmt.Errorf("device id: %w", err)
+ }
+
+ name, err := agd.NewDeviceName(ds.Name)
+ if err != nil {
+ return nil, fmt.Errorf("device name: %w", err)
+ }
+
+ var humanID agd.HumanIDLower
+ if humanIDStr := ds.HumanIdLower; humanIDStr != "" {
+ humanID, err = agd.NewHumanIDLower(humanIDStr)
+ if err != nil {
+ return nil, fmt.Errorf("lowercase human id: %w", err)
+ }
+ }
+
+ return &agd.Device{
+ Auth: auth,
+ ID: id,
+ Name: name,
+ HumanIDLower: humanID,
+ LinkedIP: linkedIP,
+ DedicatedIPs: dedicatedIPs,
+ FilteringEnabled: ds.FilteringEnabled,
+ }, nil
+}
+
+// dedicatedIPsToInternal converts the dedicated IP data while also validating
+// it against the given bindSet.
+func (ds *DeviceSettings) dedicatedIPsToInternal(
+ bindSet netutil.SubnetSet,
+) (dedicatedIPs []netip.Addr, err error) {
+ dedicatedIPs, err = agdprotobuf.ByteSlicesToIPs(ds.DedicatedIps)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return nil, err
+ }
+
+ // TODO(d.kolyshev): Extract business logic validation.
+ for i, addr := range dedicatedIPs {
+ if !bindSet.Contains(addr) {
+ return nil, fmt.Errorf("at index %d: %q is not in bind data", i, addr)
+ }
+ }
+
+ return dedicatedIPs, nil
+}
+
+// toInternal converts a protobuf auth settings structure to an internal one.
+// If x is nil, toInternal returns non-nil settings with enabled field set to
+// false.
+func (x *AuthenticationSettings) toInternal() (s *agd.AuthSettings, err error) {
+ if x == nil {
+ return &agd.AuthSettings{
+ Enabled: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ }, nil
+ }
+
+ ph, err := dohPasswordToInternal(x.DohPasswordHash)
+ if err != nil {
+ return nil, fmt.Errorf("password hash: %w", err)
+ }
+
+ return &agd.AuthSettings{
+ PasswordHash: ph,
+ Enabled: true,
+ DoHAuthOnly: x.DohAuthOnly,
+ }, nil
+}
+
+// dohPasswordToInternal converts a protobuf DoH password hash sum-type to an
+// internal one.
+func dohPasswordToInternal(
+ pbp isAuthenticationSettings_DohPasswordHash,
+) (p agdpasswd.Authenticator, err error) {
+ switch pbp := pbp.(type) {
+ case nil:
+ return agdpasswd.AllowAuthenticator{}, nil
+ case *AuthenticationSettings_PasswordHashBcrypt:
+ return agdpasswd.NewPasswordHashBcrypt(pbp.PasswordHashBcrypt), nil
+ default:
+ return nil, fmt.Errorf("bad pb auth doh password hash %T(%[1]v)", pbp)
+ }
+}
diff --git a/internal/backendpb/dns.pb.go b/internal/backendpb/dns.pb.go
new file mode 100644
index 0000000..fbc1db0
--- /dev/null
+++ b/internal/backendpb/dns.pb.go
@@ -0,0 +1,2314 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.34.2
+// protoc v5.27.1
+// source: dns.proto
+
+package backendpb
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ durationpb "google.golang.org/protobuf/types/known/durationpb"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type DeviceType int32
+
+const (
+ DeviceType_INVALID DeviceType = 0
+ DeviceType_WINDOWS DeviceType = 1
+ DeviceType_ANDROID DeviceType = 2
+ DeviceType_MAC DeviceType = 3
+ DeviceType_IOS DeviceType = 4
+ DeviceType_LINUX DeviceType = 5
+ DeviceType_ROUTER DeviceType = 6
+ DeviceType_SMART_TV DeviceType = 7
+ DeviceType_GAME_CONSOLE DeviceType = 8
+ DeviceType_OTHER DeviceType = 9
+)
+
+// Enum value maps for DeviceType.
+var (
+ DeviceType_name = map[int32]string{
+ 0: "INVALID",
+ 1: "WINDOWS",
+ 2: "ANDROID",
+ 3: "MAC",
+ 4: "IOS",
+ 5: "LINUX",
+ 6: "ROUTER",
+ 7: "SMART_TV",
+ 8: "GAME_CONSOLE",
+ 9: "OTHER",
+ }
+ DeviceType_value = map[string]int32{
+ "INVALID": 0,
+ "WINDOWS": 1,
+ "ANDROID": 2,
+ "MAC": 3,
+ "IOS": 4,
+ "LINUX": 5,
+ "ROUTER": 6,
+ "SMART_TV": 7,
+ "GAME_CONSOLE": 8,
+ "OTHER": 9,
+ }
+)
+
+func (x DeviceType) Enum() *DeviceType {
+ p := new(DeviceType)
+ *p = x
+ return p
+}
+
+func (x DeviceType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (DeviceType) Descriptor() protoreflect.EnumDescriptor {
+ return file_dns_proto_enumTypes[0].Descriptor()
+}
+
+func (DeviceType) Type() protoreflect.EnumType {
+ return &file_dns_proto_enumTypes[0]
+}
+
+func (x DeviceType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use DeviceType.Descriptor instead.
+func (DeviceType) EnumDescriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{0}
+}
+
+type DNSProfilesRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ SyncTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=sync_time,json=syncTime,proto3" json:"sync_time,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *DNSProfilesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DNSProfilesRequest) ProtoMessage() {}
+
+func (x *DNSProfilesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DNSProfilesRequest.ProtoReflect.Descriptor instead.
+func (*DNSProfilesRequest) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *DNSProfilesRequest) GetSyncTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.SyncTime
+ }
+ return nil
+}
+
+type DNSProfile struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ DnsId string `protobuf:"bytes,1,opt,name=dns_id,json=dnsId,proto3" json:"dns_id,omitempty"`
+ FilteringEnabled bool `protobuf:"varint,2,opt,name=filtering_enabled,json=filteringEnabled,proto3" json:"filtering_enabled,omitempty"`
+ QueryLogEnabled bool `protobuf:"varint,3,opt,name=query_log_enabled,json=queryLogEnabled,proto3" json:"query_log_enabled,omitempty"`
+ Deleted bool `protobuf:"varint,4,opt,name=deleted,proto3" json:"deleted,omitempty"`
+ SafeBrowsing *SafeBrowsingSettings `protobuf:"bytes,5,opt,name=safe_browsing,json=safeBrowsing,proto3" json:"safe_browsing,omitempty"`
+ Parental *ParentalSettings `protobuf:"bytes,6,opt,name=parental,proto3" json:"parental,omitempty"`
+ RuleLists *RuleListsSettings `protobuf:"bytes,7,opt,name=rule_lists,json=ruleLists,proto3" json:"rule_lists,omitempty"`
+ Devices []*DeviceSettings `protobuf:"bytes,8,rep,name=devices,proto3" json:"devices,omitempty"`
+ CustomRules []string `protobuf:"bytes,9,rep,name=custom_rules,json=customRules,proto3" json:"custom_rules,omitempty"`
+ FilteredResponseTtl *durationpb.Duration `protobuf:"bytes,10,opt,name=filtered_response_ttl,json=filteredResponseTtl,proto3" json:"filtered_response_ttl,omitempty"`
+ BlockPrivateRelay bool `protobuf:"varint,11,opt,name=block_private_relay,json=blockPrivateRelay,proto3" json:"block_private_relay,omitempty"`
+ BlockFirefoxCanary bool `protobuf:"varint,12,opt,name=block_firefox_canary,json=blockFirefoxCanary,proto3" json:"block_firefox_canary,omitempty"`
+ // Types that are assignable to BlockingMode:
+ //
+ // *DNSProfile_BlockingModeCustomIp
+ // *DNSProfile_BlockingModeNxdomain
+ // *DNSProfile_BlockingModeNullIp
+ // *DNSProfile_BlockingModeRefused
+ BlockingMode isDNSProfile_BlockingMode `protobuf_oneof:"blocking_mode"`
+ IpLogEnabled bool `protobuf:"varint,17,opt,name=ip_log_enabled,json=ipLogEnabled,proto3" json:"ip_log_enabled,omitempty"`
+ Access *AccessSettings `protobuf:"bytes,18,opt,name=access,proto3" json:"access,omitempty"`
+ AutoDevicesEnabled bool `protobuf:"varint,19,opt,name=auto_devices_enabled,json=autoDevicesEnabled,proto3" json:"auto_devices_enabled,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *DNSProfile) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DNSProfile) ProtoMessage() {}
+
+func (x *DNSProfile) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DNSProfile.ProtoReflect.Descriptor instead.
+func (*DNSProfile) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *DNSProfile) GetDnsId() string {
+ if x != nil {
+ return x.DnsId
+ }
+ return ""
+}
+
+func (x *DNSProfile) GetFilteringEnabled() bool {
+ if x != nil {
+ return x.FilteringEnabled
+ }
+ return false
+}
+
+func (x *DNSProfile) GetQueryLogEnabled() bool {
+ if x != nil {
+ return x.QueryLogEnabled
+ }
+ return false
+}
+
+func (x *DNSProfile) GetDeleted() bool {
+ if x != nil {
+ return x.Deleted
+ }
+ return false
+}
+
+func (x *DNSProfile) GetSafeBrowsing() *SafeBrowsingSettings {
+ if x != nil {
+ return x.SafeBrowsing
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetParental() *ParentalSettings {
+ if x != nil {
+ return x.Parental
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetRuleLists() *RuleListsSettings {
+ if x != nil {
+ return x.RuleLists
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetDevices() []*DeviceSettings {
+ if x != nil {
+ return x.Devices
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetCustomRules() []string {
+ if x != nil {
+ return x.CustomRules
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetFilteredResponseTtl() *durationpb.Duration {
+ if x != nil {
+ return x.FilteredResponseTtl
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetBlockPrivateRelay() bool {
+ if x != nil {
+ return x.BlockPrivateRelay
+ }
+ return false
+}
+
+func (x *DNSProfile) GetBlockFirefoxCanary() bool {
+ if x != nil {
+ return x.BlockFirefoxCanary
+ }
+ return false
+}
+
+func (m *DNSProfile) GetBlockingMode() isDNSProfile_BlockingMode {
+ if m != nil {
+ return m.BlockingMode
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetBlockingModeCustomIp() *BlockingModeCustomIP {
+ if x, ok := x.GetBlockingMode().(*DNSProfile_BlockingModeCustomIp); ok {
+ return x.BlockingModeCustomIp
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetBlockingModeNxdomain() *BlockingModeNXDOMAIN {
+ if x, ok := x.GetBlockingMode().(*DNSProfile_BlockingModeNxdomain); ok {
+ return x.BlockingModeNxdomain
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetBlockingModeNullIp() *BlockingModeNullIP {
+ if x, ok := x.GetBlockingMode().(*DNSProfile_BlockingModeNullIp); ok {
+ return x.BlockingModeNullIp
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetBlockingModeRefused() *BlockingModeREFUSED {
+ if x, ok := x.GetBlockingMode().(*DNSProfile_BlockingModeRefused); ok {
+ return x.BlockingModeRefused
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetIpLogEnabled() bool {
+ if x != nil {
+ return x.IpLogEnabled
+ }
+ return false
+}
+
+func (x *DNSProfile) GetAccess() *AccessSettings {
+ if x != nil {
+ return x.Access
+ }
+ return nil
+}
+
+func (x *DNSProfile) GetAutoDevicesEnabled() bool {
+ if x != nil {
+ return x.AutoDevicesEnabled
+ }
+ return false
+}
+
+type isDNSProfile_BlockingMode interface {
+ isDNSProfile_BlockingMode()
+}
+
+type DNSProfile_BlockingModeCustomIp struct {
+ BlockingModeCustomIp *BlockingModeCustomIP `protobuf:"bytes,13,opt,name=blocking_mode_custom_ip,json=blockingModeCustomIp,proto3,oneof"`
+}
+
+type DNSProfile_BlockingModeNxdomain struct {
+ BlockingModeNxdomain *BlockingModeNXDOMAIN `protobuf:"bytes,14,opt,name=blocking_mode_nxdomain,json=blockingModeNxdomain,proto3,oneof"`
+}
+
+type DNSProfile_BlockingModeNullIp struct {
+ BlockingModeNullIp *BlockingModeNullIP `protobuf:"bytes,15,opt,name=blocking_mode_null_ip,json=blockingModeNullIp,proto3,oneof"`
+}
+
+type DNSProfile_BlockingModeRefused struct {
+ BlockingModeRefused *BlockingModeREFUSED `protobuf:"bytes,16,opt,name=blocking_mode_refused,json=blockingModeRefused,proto3,oneof"`
+}
+
+func (*DNSProfile_BlockingModeCustomIp) isDNSProfile_BlockingMode() {}
+
+func (*DNSProfile_BlockingModeNxdomain) isDNSProfile_BlockingMode() {}
+
+func (*DNSProfile_BlockingModeNullIp) isDNSProfile_BlockingMode() {}
+
+func (*DNSProfile_BlockingModeRefused) isDNSProfile_BlockingMode() {}
+
+type SafeBrowsingSettings struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
+ BlockDangerousDomains bool `protobuf:"varint,2,opt,name=block_dangerous_domains,json=blockDangerousDomains,proto3" json:"block_dangerous_domains,omitempty"`
+ BlockNrd bool `protobuf:"varint,3,opt,name=block_nrd,json=blockNrd,proto3" json:"block_nrd,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *SafeBrowsingSettings) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SafeBrowsingSettings) ProtoMessage() {}
+
+func (x *SafeBrowsingSettings) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SafeBrowsingSettings.ProtoReflect.Descriptor instead.
+func (*SafeBrowsingSettings) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *SafeBrowsingSettings) GetEnabled() bool {
+ if x != nil {
+ return x.Enabled
+ }
+ return false
+}
+
+func (x *SafeBrowsingSettings) GetBlockDangerousDomains() bool {
+ if x != nil {
+ return x.BlockDangerousDomains
+ }
+ return false
+}
+
+func (x *SafeBrowsingSettings) GetBlockNrd() bool {
+ if x != nil {
+ return x.BlockNrd
+ }
+ return false
+}
+
+type DeviceSettings struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ FilteringEnabled bool `protobuf:"varint,3,opt,name=filtering_enabled,json=filteringEnabled,proto3" json:"filtering_enabled,omitempty"`
+ LinkedIp []byte `protobuf:"bytes,4,opt,name=linked_ip,json=linkedIp,proto3" json:"linked_ip,omitempty"`
+ DedicatedIps [][]byte `protobuf:"bytes,5,rep,name=dedicated_ips,json=dedicatedIps,proto3" json:"dedicated_ips,omitempty"`
+ Authentication *AuthenticationSettings `protobuf:"bytes,6,opt,name=authentication,proto3" json:"authentication,omitempty"`
+ // Value in lower case. Will be empty for "ordinary" devices and non-empty for "automatically" created devices.
+ HumanIdLower string `protobuf:"bytes,7,opt,name=human_id_lower,json=humanIdLower,proto3" json:"human_id_lower,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *DeviceSettings) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeviceSettings) ProtoMessage() {}
+
+func (x *DeviceSettings) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeviceSettings.ProtoReflect.Descriptor instead.
+func (*DeviceSettings) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *DeviceSettings) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *DeviceSettings) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *DeviceSettings) GetFilteringEnabled() bool {
+ if x != nil {
+ return x.FilteringEnabled
+ }
+ return false
+}
+
+func (x *DeviceSettings) GetLinkedIp() []byte {
+ if x != nil {
+ return x.LinkedIp
+ }
+ return nil
+}
+
+func (x *DeviceSettings) GetDedicatedIps() [][]byte {
+ if x != nil {
+ return x.DedicatedIps
+ }
+ return nil
+}
+
+func (x *DeviceSettings) GetAuthentication() *AuthenticationSettings {
+ if x != nil {
+ return x.Authentication
+ }
+ return nil
+}
+
+func (x *DeviceSettings) GetHumanIdLower() string {
+ if x != nil {
+ return x.HumanIdLower
+ }
+ return ""
+}
+
+type ParentalSettings struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
+ BlockAdult bool `protobuf:"varint,2,opt,name=block_adult,json=blockAdult,proto3" json:"block_adult,omitempty"`
+ GeneralSafeSearch bool `protobuf:"varint,3,opt,name=general_safe_search,json=generalSafeSearch,proto3" json:"general_safe_search,omitempty"`
+ YoutubeSafeSearch bool `protobuf:"varint,4,opt,name=youtube_safe_search,json=youtubeSafeSearch,proto3" json:"youtube_safe_search,omitempty"`
+ BlockedServices []string `protobuf:"bytes,5,rep,name=blocked_services,json=blockedServices,proto3" json:"blocked_services,omitempty"`
+ Schedule *ScheduleSettings `protobuf:"bytes,6,opt,name=schedule,proto3" json:"schedule,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *ParentalSettings) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ParentalSettings) ProtoMessage() {}
+
+func (x *ParentalSettings) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ParentalSettings.ProtoReflect.Descriptor instead.
+func (*ParentalSettings) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ParentalSettings) GetEnabled() bool {
+ if x != nil {
+ return x.Enabled
+ }
+ return false
+}
+
+func (x *ParentalSettings) GetBlockAdult() bool {
+ if x != nil {
+ return x.BlockAdult
+ }
+ return false
+}
+
+func (x *ParentalSettings) GetGeneralSafeSearch() bool {
+ if x != nil {
+ return x.GeneralSafeSearch
+ }
+ return false
+}
+
+func (x *ParentalSettings) GetYoutubeSafeSearch() bool {
+ if x != nil {
+ return x.YoutubeSafeSearch
+ }
+ return false
+}
+
+func (x *ParentalSettings) GetBlockedServices() []string {
+ if x != nil {
+ return x.BlockedServices
+ }
+ return nil
+}
+
+func (x *ParentalSettings) GetSchedule() *ScheduleSettings {
+ if x != nil {
+ return x.Schedule
+ }
+ return nil
+}
+
+type ScheduleSettings struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Tmz string `protobuf:"bytes,1,opt,name=tmz,proto3" json:"tmz,omitempty"`
+ WeeklyRange *WeeklyRange `protobuf:"bytes,2,opt,name=weeklyRange,proto3" json:"weeklyRange,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *ScheduleSettings) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ScheduleSettings) ProtoMessage() {}
+
+func (x *ScheduleSettings) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ScheduleSettings.ProtoReflect.Descriptor instead.
+func (*ScheduleSettings) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *ScheduleSettings) GetTmz() string {
+ if x != nil {
+ return x.Tmz
+ }
+ return ""
+}
+
+func (x *ScheduleSettings) GetWeeklyRange() *WeeklyRange {
+ if x != nil {
+ return x.WeeklyRange
+ }
+ return nil
+}
+
+type WeeklyRange struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Mon *DayRange `protobuf:"bytes,1,opt,name=mon,proto3" json:"mon,omitempty"`
+ Tue *DayRange `protobuf:"bytes,2,opt,name=tue,proto3" json:"tue,omitempty"`
+ Wed *DayRange `protobuf:"bytes,3,opt,name=wed,proto3" json:"wed,omitempty"`
+ Thu *DayRange `protobuf:"bytes,4,opt,name=thu,proto3" json:"thu,omitempty"`
+ Fri *DayRange `protobuf:"bytes,5,opt,name=fri,proto3" json:"fri,omitempty"`
+ Sat *DayRange `protobuf:"bytes,6,opt,name=sat,proto3" json:"sat,omitempty"`
+ Sun *DayRange `protobuf:"bytes,7,opt,name=sun,proto3" json:"sun,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *WeeklyRange) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WeeklyRange) ProtoMessage() {}
+
+func (x *WeeklyRange) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use WeeklyRange.ProtoReflect.Descriptor instead.
+func (*WeeklyRange) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *WeeklyRange) GetMon() *DayRange {
+ if x != nil {
+ return x.Mon
+ }
+ return nil
+}
+
+func (x *WeeklyRange) GetTue() *DayRange {
+ if x != nil {
+ return x.Tue
+ }
+ return nil
+}
+
+func (x *WeeklyRange) GetWed() *DayRange {
+ if x != nil {
+ return x.Wed
+ }
+ return nil
+}
+
+func (x *WeeklyRange) GetThu() *DayRange {
+ if x != nil {
+ return x.Thu
+ }
+ return nil
+}
+
+func (x *WeeklyRange) GetFri() *DayRange {
+ if x != nil {
+ return x.Fri
+ }
+ return nil
+}
+
+func (x *WeeklyRange) GetSat() *DayRange {
+ if x != nil {
+ return x.Sat
+ }
+ return nil
+}
+
+func (x *WeeklyRange) GetSun() *DayRange {
+ if x != nil {
+ return x.Sun
+ }
+ return nil
+}
+
+type DayRange struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Start *durationpb.Duration `protobuf:"bytes,1,opt,name=start,proto3" json:"start,omitempty"`
+ End *durationpb.Duration `protobuf:"bytes,2,opt,name=end,proto3" json:"end,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *DayRange) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DayRange) ProtoMessage() {}
+
+func (x *DayRange) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DayRange.ProtoReflect.Descriptor instead.
+func (*DayRange) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *DayRange) GetStart() *durationpb.Duration {
+ if x != nil {
+ return x.Start
+ }
+ return nil
+}
+
+func (x *DayRange) GetEnd() *durationpb.Duration {
+ if x != nil {
+ return x.End
+ }
+ return nil
+}
+
+type RuleListsSettings struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
+ Ids []string `protobuf:"bytes,2,rep,name=ids,proto3" json:"ids,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *RuleListsSettings) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RuleListsSettings) ProtoMessage() {}
+
+func (x *RuleListsSettings) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RuleListsSettings.ProtoReflect.Descriptor instead.
+func (*RuleListsSettings) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *RuleListsSettings) GetEnabled() bool {
+ if x != nil {
+ return x.Enabled
+ }
+ return false
+}
+
+func (x *RuleListsSettings) GetIds() []string {
+ if x != nil {
+ return x.Ids
+ }
+ return nil
+}
+
+type BlockingModeCustomIP struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Ipv4 []byte `protobuf:"bytes,1,opt,name=ipv4,proto3" json:"ipv4,omitempty"`
+ Ipv6 []byte `protobuf:"bytes,2,opt,name=ipv6,proto3" json:"ipv6,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *BlockingModeCustomIP) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BlockingModeCustomIP) ProtoMessage() {}
+
+func (x *BlockingModeCustomIP) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BlockingModeCustomIP.ProtoReflect.Descriptor instead.
+func (*BlockingModeCustomIP) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *BlockingModeCustomIP) GetIpv4() []byte {
+ if x != nil {
+ return x.Ipv4
+ }
+ return nil
+}
+
+func (x *BlockingModeCustomIP) GetIpv6() []byte {
+ if x != nil {
+ return x.Ipv6
+ }
+ return nil
+}
+
+type BlockingModeNXDOMAIN struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+}
+
+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)
+ }
+}
+
+func (x *BlockingModeNXDOMAIN) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BlockingModeNXDOMAIN) ProtoMessage() {}
+
+func (x *BlockingModeNXDOMAIN) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[10]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BlockingModeNXDOMAIN.ProtoReflect.Descriptor instead.
+func (*BlockingModeNXDOMAIN) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{10}
+}
+
+type BlockingModeNullIP struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+}
+
+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)
+ }
+}
+
+func (x *BlockingModeNullIP) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BlockingModeNullIP) ProtoMessage() {}
+
+func (x *BlockingModeNullIP) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[11]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BlockingModeNullIP.ProtoReflect.Descriptor instead.
+func (*BlockingModeNullIP) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{11}
+}
+
+type BlockingModeREFUSED struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+}
+
+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)
+ }
+}
+
+func (x *BlockingModeREFUSED) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BlockingModeREFUSED) ProtoMessage() {}
+
+func (x *BlockingModeREFUSED) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[12]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BlockingModeREFUSED.ProtoReflect.Descriptor instead.
+func (*BlockingModeREFUSED) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{12}
+}
+
+type DeviceBillingStat struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ LastActivityTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=last_activity_time,json=lastActivityTime,proto3" json:"last_activity_time,omitempty"`
+ DeviceId string `protobuf:"bytes,2,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
+ ClientCountry string `protobuf:"bytes,3,opt,name=client_country,json=clientCountry,proto3" json:"client_country,omitempty"`
+ // Protocol type. Possible values see here: https://bit.adguard.com/projects/DNS/repos/dns-server/browse#ql-properties
+ Proto uint32 `protobuf:"varint,4,opt,name=proto,proto3" json:"proto,omitempty"`
+ Asn uint32 `protobuf:"varint,5,opt,name=asn,proto3" json:"asn,omitempty"`
+ Queries uint32 `protobuf:"varint,6,opt,name=queries,proto3" json:"queries,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *DeviceBillingStat) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeviceBillingStat) ProtoMessage() {}
+
+func (x *DeviceBillingStat) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[13]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeviceBillingStat.ProtoReflect.Descriptor instead.
+func (*DeviceBillingStat) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *DeviceBillingStat) GetLastActivityTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.LastActivityTime
+ }
+ return nil
+}
+
+func (x *DeviceBillingStat) GetDeviceId() string {
+ if x != nil {
+ return x.DeviceId
+ }
+ return ""
+}
+
+func (x *DeviceBillingStat) GetClientCountry() string {
+ if x != nil {
+ return x.ClientCountry
+ }
+ return ""
+}
+
+func (x *DeviceBillingStat) GetProto() uint32 {
+ if x != nil {
+ return x.Proto
+ }
+ return 0
+}
+
+func (x *DeviceBillingStat) GetAsn() uint32 {
+ if x != nil {
+ return x.Asn
+ }
+ return 0
+}
+
+func (x *DeviceBillingStat) GetQueries() uint32 {
+ if x != nil {
+ return x.Queries
+ }
+ return 0
+}
+
+type AccessSettings struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ AllowlistCidr []*CidrRange `protobuf:"bytes,1,rep,name=allowlist_cidr,json=allowlistCidr,proto3" json:"allowlist_cidr,omitempty"`
+ BlocklistCidr []*CidrRange `protobuf:"bytes,2,rep,name=blocklist_cidr,json=blocklistCidr,proto3" json:"blocklist_cidr,omitempty"`
+ AllowlistAsn []uint32 `protobuf:"varint,3,rep,packed,name=allowlist_asn,json=allowlistAsn,proto3" json:"allowlist_asn,omitempty"`
+ BlocklistAsn []uint32 `protobuf:"varint,4,rep,packed,name=blocklist_asn,json=blocklistAsn,proto3" json:"blocklist_asn,omitempty"`
+ BlocklistDomainRules []string `protobuf:"bytes,5,rep,name=blocklist_domain_rules,json=blocklistDomainRules,proto3" json:"blocklist_domain_rules,omitempty"`
+ Enabled bool `protobuf:"varint,6,opt,name=enabled,proto3" json:"enabled,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *AccessSettings) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AccessSettings) ProtoMessage() {}
+
+func (x *AccessSettings) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[14]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use AccessSettings.ProtoReflect.Descriptor instead.
+func (*AccessSettings) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *AccessSettings) GetAllowlistCidr() []*CidrRange {
+ if x != nil {
+ return x.AllowlistCidr
+ }
+ return nil
+}
+
+func (x *AccessSettings) GetBlocklistCidr() []*CidrRange {
+ if x != nil {
+ return x.BlocklistCidr
+ }
+ return nil
+}
+
+func (x *AccessSettings) GetAllowlistAsn() []uint32 {
+ if x != nil {
+ return x.AllowlistAsn
+ }
+ return nil
+}
+
+func (x *AccessSettings) GetBlocklistAsn() []uint32 {
+ if x != nil {
+ return x.BlocklistAsn
+ }
+ return nil
+}
+
+func (x *AccessSettings) GetBlocklistDomainRules() []string {
+ if x != nil {
+ return x.BlocklistDomainRules
+ }
+ return nil
+}
+
+func (x *AccessSettings) GetEnabled() bool {
+ if x != nil {
+ return x.Enabled
+ }
+ return false
+}
+
+type CidrRange struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
+ Prefix uint32 `protobuf:"varint,2,opt,name=prefix,proto3" json:"prefix,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *CidrRange) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CidrRange) ProtoMessage() {}
+
+func (x *CidrRange) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[15]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CidrRange.ProtoReflect.Descriptor instead.
+func (*CidrRange) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{15}
+}
+
+func (x *CidrRange) GetAddress() []byte {
+ if x != nil {
+ return x.Address
+ }
+ return nil
+}
+
+func (x *CidrRange) GetPrefix() uint32 {
+ if x != nil {
+ return x.Prefix
+ }
+ return 0
+}
+
+type AuthenticationSettings struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ DohAuthOnly bool `protobuf:"varint,1,opt,name=doh_auth_only,json=dohAuthOnly,proto3" json:"doh_auth_only,omitempty"`
+ // Types that are assignable to DohPasswordHash:
+ //
+ // *AuthenticationSettings_PasswordHashBcrypt
+ DohPasswordHash isAuthenticationSettings_DohPasswordHash `protobuf_oneof:"doh_password_hash"`
+}
+
+func (x *AuthenticationSettings) Reset() {
+ *x = AuthenticationSettings{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dns_proto_msgTypes[16]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *AuthenticationSettings) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AuthenticationSettings) ProtoMessage() {}
+
+func (x *AuthenticationSettings) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[16]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use AuthenticationSettings.ProtoReflect.Descriptor instead.
+func (*AuthenticationSettings) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{16}
+}
+
+func (x *AuthenticationSettings) GetDohAuthOnly() bool {
+ if x != nil {
+ return x.DohAuthOnly
+ }
+ return false
+}
+
+func (m *AuthenticationSettings) GetDohPasswordHash() isAuthenticationSettings_DohPasswordHash {
+ if m != nil {
+ return m.DohPasswordHash
+ }
+ return nil
+}
+
+func (x *AuthenticationSettings) GetPasswordHashBcrypt() []byte {
+ if x, ok := x.GetDohPasswordHash().(*AuthenticationSettings_PasswordHashBcrypt); ok {
+ return x.PasswordHashBcrypt
+ }
+ return nil
+}
+
+type isAuthenticationSettings_DohPasswordHash interface {
+ isAuthenticationSettings_DohPasswordHash()
+}
+
+type AuthenticationSettings_PasswordHashBcrypt struct {
+ PasswordHashBcrypt []byte `protobuf:"bytes,2,opt,name=password_hash_bcrypt,json=passwordHashBcrypt,proto3,oneof"`
+}
+
+func (*AuthenticationSettings_PasswordHashBcrypt) isAuthenticationSettings_DohPasswordHash() {}
+
+type CreateDeviceRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ DnsId string `protobuf:"bytes,1,opt,name=dns_id,json=dnsId,proto3" json:"dns_id,omitempty"`
+ HumanId string `protobuf:"bytes,2,opt,name=human_id,json=humanId,proto3" json:"human_id,omitempty"`
+ DeviceType DeviceType `protobuf:"varint,3,opt,name=device_type,json=deviceType,proto3,enum=DeviceType" json:"device_type,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *CreateDeviceRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateDeviceRequest) ProtoMessage() {}
+
+func (x *CreateDeviceRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[17]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreateDeviceRequest.ProtoReflect.Descriptor instead.
+func (*CreateDeviceRequest) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{17}
+}
+
+func (x *CreateDeviceRequest) GetDnsId() string {
+ if x != nil {
+ return x.DnsId
+ }
+ return ""
+}
+
+func (x *CreateDeviceRequest) GetHumanId() string {
+ if x != nil {
+ return x.HumanId
+ }
+ return ""
+}
+
+func (x *CreateDeviceRequest) GetDeviceType() DeviceType {
+ if x != nil {
+ return x.DeviceType
+ }
+ return DeviceType_INVALID
+}
+
+type CreateDeviceResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Device *DeviceSettings `protobuf:"bytes,1,opt,name=device,proto3" json:"device,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *CreateDeviceResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateDeviceResponse) ProtoMessage() {}
+
+func (x *CreateDeviceResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[18]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreateDeviceResponse.ProtoReflect.Descriptor instead.
+func (*CreateDeviceResponse) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *CreateDeviceResponse) GetDevice() *DeviceSettings {
+ if x != nil {
+ return x.Device
+ }
+ return nil
+}
+
+type RateLimitedError struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+ RetryDelay *durationpb.Duration `protobuf:"bytes,2,opt,name=retry_delay,json=retryDelay,proto3" json:"retry_delay,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *RateLimitedError) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RateLimitedError) ProtoMessage() {}
+
+func (x *RateLimitedError) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[19]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RateLimitedError.ProtoReflect.Descriptor instead.
+func (*RateLimitedError) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *RateLimitedError) GetMessage() string {
+ if x != nil {
+ return x.Message
+ }
+ return ""
+}
+
+func (x *RateLimitedError) GetRetryDelay() *durationpb.Duration {
+ if x != nil {
+ return x.RetryDelay
+ }
+ return nil
+}
+
+type DeviceQuotaExceededError struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *DeviceQuotaExceededError) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeviceQuotaExceededError) ProtoMessage() {}
+
+func (x *DeviceQuotaExceededError) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[20]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeviceQuotaExceededError.ProtoReflect.Descriptor instead.
+func (*DeviceQuotaExceededError) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *DeviceQuotaExceededError) GetMessage() string {
+ if x != nil {
+ return x.Message
+ }
+ return ""
+}
+
+type BadRequestError struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *BadRequestError) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BadRequestError) ProtoMessage() {}
+
+func (x *BadRequestError) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[21]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BadRequestError.ProtoReflect.Descriptor instead.
+func (*BadRequestError) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *BadRequestError) GetMessage() string {
+ if x != nil {
+ return x.Message
+ }
+ return ""
+}
+
+type AuthenticationFailedError struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+}
+
+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)
+ }
+}
+
+func (x *AuthenticationFailedError) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AuthenticationFailedError) ProtoMessage() {}
+
+func (x *AuthenticationFailedError) ProtoReflect() protoreflect.Message {
+ mi := &file_dns_proto_msgTypes[22]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use AuthenticationFailedError.ProtoReflect.Descriptor instead.
+func (*AuthenticationFailedError) Descriptor() ([]byte, []int) {
+ return file_dns_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *AuthenticationFailedError) GetMessage() string {
+ if x != nil {
+ return x.Message
+ }
+ return ""
+}
+
+var File_dns_proto protoreflect.FileDescriptor
+
+var file_dns_proto_rawDesc = []byte{
+ 0x0a, 0x09, 0x64, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f,
+ 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, 0xfa, 0x07, 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, 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, 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,
+}
+
+var (
+ file_dns_proto_rawDescOnce sync.Once
+ file_dns_proto_rawDescData = file_dns_proto_rawDesc
+)
+
+func file_dns_proto_rawDescGZIP() []byte {
+ file_dns_proto_rawDescOnce.Do(func() {
+ file_dns_proto_rawDescData = protoimpl.X.CompressGZIP(file_dns_proto_rawDescData)
+ })
+ return file_dns_proto_rawDescData
+}
+
+var file_dns_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_dns_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
+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
+ (*timestamppb.Timestamp)(nil), // 24: google.protobuf.Timestamp
+ (*durationpb.Duration)(nil), // 25: google.protobuf.Duration
+ (*emptypb.Empty)(nil), // 26: google.protobuf.Empty
+}
+var file_dns_proto_depIdxs = []int32{
+ 24, // 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
+ 25, // 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
+ 17, // 11: DeviceSettings.authentication:type_name -> AuthenticationSettings
+ 6, // 12: ParentalSettings.schedule:type_name -> ScheduleSettings
+ 7, // 13: ScheduleSettings.weeklyRange:type_name -> WeeklyRange
+ 8, // 14: WeeklyRange.mon:type_name -> DayRange
+ 8, // 15: WeeklyRange.tue:type_name -> DayRange
+ 8, // 16: WeeklyRange.wed:type_name -> DayRange
+ 8, // 17: WeeklyRange.thu:type_name -> DayRange
+ 8, // 18: WeeklyRange.fri:type_name -> DayRange
+ 8, // 19: WeeklyRange.sat:type_name -> DayRange
+ 8, // 20: WeeklyRange.sun:type_name -> DayRange
+ 25, // 21: DayRange.start:type_name -> google.protobuf.Duration
+ 25, // 22: DayRange.end:type_name -> google.protobuf.Duration
+ 24, // 23: DeviceBillingStat.last_activity_time:type_name -> google.protobuf.Timestamp
+ 16, // 24: AccessSettings.allowlist_cidr:type_name -> CidrRange
+ 16, // 25: AccessSettings.blocklist_cidr:type_name -> CidrRange
+ 0, // 26: CreateDeviceRequest.device_type:type_name -> DeviceType
+ 4, // 27: CreateDeviceResponse.device:type_name -> DeviceSettings
+ 25, // 28: RateLimitedError.retry_delay:type_name -> google.protobuf.Duration
+ 1, // 29: DNSService.getDNSProfiles:input_type -> DNSProfilesRequest
+ 14, // 30: DNSService.saveDevicesBillingStat:input_type -> DeviceBillingStat
+ 18, // 31: DNSService.createDeviceByHumanId:input_type -> CreateDeviceRequest
+ 2, // 32: DNSService.getDNSProfiles:output_type -> DNSProfile
+ 26, // 33: DNSService.saveDevicesBillingStat:output_type -> google.protobuf.Empty
+ 19, // 34: DNSService.createDeviceByHumanId:output_type -> CreateDeviceResponse
+ 32, // [32:35] is the sub-list for method output_type
+ 29, // [29:32] is the sub-list for method input_type
+ 29, // [29:29] is the sub-list for extension type_name
+ 29, // [29:29] is the sub-list for extension extendee
+ 0, // [0:29] is the sub-list for field type_name
+}
+
+func init() { file_dns_proto_init() }
+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[1].OneofWrappers = []any{
+ (*DNSProfile_BlockingModeCustomIp)(nil),
+ (*DNSProfile_BlockingModeNxdomain)(nil),
+ (*DNSProfile_BlockingModeNullIp)(nil),
+ (*DNSProfile_BlockingModeRefused)(nil),
+ }
+ file_dns_proto_msgTypes[16].OneofWrappers = []any{
+ (*AuthenticationSettings_PasswordHashBcrypt)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_dns_proto_rawDesc,
+ NumEnums: 1,
+ NumMessages: 23,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_dns_proto_goTypes,
+ DependencyIndexes: file_dns_proto_depIdxs,
+ EnumInfos: file_dns_proto_enumTypes,
+ MessageInfos: file_dns_proto_msgTypes,
+ }.Build()
+ File_dns_proto = out.File
+ file_dns_proto_rawDesc = nil
+ file_dns_proto_goTypes = nil
+ file_dns_proto_depIdxs = nil
+}
diff --git a/internal/backendpb/backend.proto b/internal/backendpb/dns.proto
similarity index 67%
rename from internal/backendpb/backend.proto
rename to internal/backendpb/dns.proto
index 2dc0bcd..3819c29 100644
--- a/internal/backendpb/backend.proto
+++ b/internal/backendpb/dns.proto
@@ -18,13 +18,31 @@ service DNSService {
The trailers headers will include a "sync_time", given in milliseconds,
that should be used for subsequent incremental DNS profile synchronization requests.
- */
+
+ This method may return the following errors:
+ - RateLimitedError: If too many "full sync" concurrent requests are made.
+ - AuthenticationFailedError: If the authentication failed.
+ */
rpc getDNSProfiles(DNSProfilesRequest) returns (stream DNSProfile);
/*
Stores devices activity.
- */
+
+ This method may return the following errors:
+ - AuthenticationFailedError: If the authentication failed.
+ */
rpc saveDevicesBillingStat(stream DeviceBillingStat) returns (google.protobuf.Empty);
+
+ /*
+ Create device by "human_id".
+
+ This method may return the following errors:
+ - RateLimitedError: If the request was made too frequently and the client must wait before retrying.
+ - DeviceQuotaExceededError: If the client has exceeded its quota for creating devices.
+ - BadRequestError: If the request is invalid: DNS server does not exist, creation of auto-devices is disabled or human_id validation failed.
+ - AuthenticationFailedError: If the authentication failed.
+ */
+ rpc createDeviceByHumanId(CreateDeviceRequest) returns (CreateDeviceResponse);
}
message DNSProfilesRequest {
@@ -52,6 +70,7 @@ message DNSProfile {
}
bool ip_log_enabled = 17;
AccessSettings access = 18;
+ bool auto_devices_enabled = 19;
}
message SafeBrowsingSettings {
@@ -67,6 +86,8 @@ message DeviceSettings {
bytes linked_ip = 4;
repeated bytes dedicated_ips = 5;
AuthenticationSettings authentication = 6;
+ // Value in lower case. Will be empty for "ordinary" devices and non-empty for "automatically" created devices.
+ string human_id_lower = 7;
}
message ParentalSettings {
@@ -144,3 +165,43 @@ message AuthenticationSettings {
bytes password_hash_bcrypt = 2;
}
}
+
+enum DeviceType {
+ INVALID = 0;
+ WINDOWS = 1;
+ ANDROID = 2;
+ MAC = 3;
+ IOS = 4;
+ LINUX = 5;
+ ROUTER = 6;
+ SMART_TV = 7;
+ GAME_CONSOLE = 8;
+ OTHER = 9;
+}
+
+message CreateDeviceRequest {
+ string dns_id = 1;
+ string human_id = 2;
+ DeviceType device_type = 3;
+}
+
+message CreateDeviceResponse {
+ DeviceSettings device = 1;
+}
+
+message RateLimitedError {
+ string message = 1;
+ google.protobuf.Duration retry_delay = 2;
+}
+
+message DeviceQuotaExceededError {
+ string message = 1;
+}
+
+message BadRequestError {
+ string message = 1;
+}
+
+message AuthenticationFailedError {
+ string message = 1;
+}
diff --git a/internal/backendpb/backend_grpc.pb.go b/internal/backendpb/dns_grpc.pb.go
similarity index 63%
rename from internal/backendpb/backend_grpc.pb.go
rename to internal/backendpb/dns_grpc.pb.go
index 34874b1..72957bb 100644
--- a/internal/backendpb/backend_grpc.pb.go
+++ b/internal/backendpb/dns_grpc.pb.go
@@ -1,8 +1,8 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
-// - protoc-gen-go-grpc v1.3.0
-// - protoc v4.25.3
-// source: backend.proto
+// - protoc-gen-go-grpc v1.4.0
+// - protoc v5.27.1
+// source: dns.proto
package backendpb
@@ -16,12 +16,13 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
-// Requires gRPC-Go v1.32.0 or later.
-const _ = grpc.SupportPackageIsVersion7
+// Requires gRPC-Go v1.62.0 or later.
+const _ = grpc.SupportPackageIsVersion8
const (
DNSService_GetDNSProfiles_FullMethodName = "/DNSService/getDNSProfiles"
DNSService_SaveDevicesBillingStat_FullMethodName = "/DNSService/saveDevicesBillingStat"
+ DNSService_CreateDeviceByHumanId_FullMethodName = "/DNSService/createDeviceByHumanId"
)
// DNSServiceClient is the client API for DNSService service.
@@ -34,9 +35,24 @@ type DNSServiceClient interface {
//
// The trailers headers will include a "sync_time", given in milliseconds,
// that should be used for subsequent incremental DNS profile synchronization requests.
+ //
+ // This method may return the following errors:
+ // - RateLimitedError: If too many "full sync" concurrent requests are made.
+ // - AuthenticationFailedError: If the authentication failed.
GetDNSProfiles(ctx context.Context, in *DNSProfilesRequest, opts ...grpc.CallOption) (DNSService_GetDNSProfilesClient, error)
// Stores devices activity.
+ //
+ // This method may return the following errors:
+ // - AuthenticationFailedError: If the authentication failed.
SaveDevicesBillingStat(ctx context.Context, opts ...grpc.CallOption) (DNSService_SaveDevicesBillingStatClient, error)
+ // Create device by "human_id".
+ //
+ // This method may return the following errors:
+ // - RateLimitedError: If the request was made too frequently and the client must wait before retrying.
+ // - DeviceQuotaExceededError: If the client has exceeded its quota for creating devices.
+ // - BadRequestError: If the request is invalid: DNS server does not exist, creation of auto-devices is disabled or human_id validation failed.
+ // - AuthenticationFailedError: If the authentication failed.
+ CreateDeviceByHumanId(ctx context.Context, in *CreateDeviceRequest, opts ...grpc.CallOption) (*CreateDeviceResponse, error)
}
type dNSServiceClient struct {
@@ -48,11 +64,12 @@ func NewDNSServiceClient(cc grpc.ClientConnInterface) DNSServiceClient {
}
func (c *dNSServiceClient) GetDNSProfiles(ctx context.Context, in *DNSProfilesRequest, opts ...grpc.CallOption) (DNSService_GetDNSProfilesClient, error) {
- stream, err := c.cc.NewStream(ctx, &DNSService_ServiceDesc.Streams[0], DNSService_GetDNSProfiles_FullMethodName, opts...)
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ stream, err := c.cc.NewStream(ctx, &DNSService_ServiceDesc.Streams[0], DNSService_GetDNSProfiles_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
- x := &dNSServiceGetDNSProfilesClient{stream}
+ x := &dNSServiceGetDNSProfilesClient{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
@@ -80,11 +97,12 @@ func (x *dNSServiceGetDNSProfilesClient) Recv() (*DNSProfile, error) {
}
func (c *dNSServiceClient) SaveDevicesBillingStat(ctx context.Context, opts ...grpc.CallOption) (DNSService_SaveDevicesBillingStatClient, error) {
- stream, err := c.cc.NewStream(ctx, &DNSService_ServiceDesc.Streams[1], DNSService_SaveDevicesBillingStat_FullMethodName, opts...)
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ stream, err := c.cc.NewStream(ctx, &DNSService_ServiceDesc.Streams[1], DNSService_SaveDevicesBillingStat_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
- x := &dNSServiceSaveDevicesBillingStatClient{stream}
+ x := &dNSServiceSaveDevicesBillingStatClient{ClientStream: stream}
return x, nil
}
@@ -113,6 +131,16 @@ func (x *dNSServiceSaveDevicesBillingStatClient) CloseAndRecv() (*emptypb.Empty,
return m, nil
}
+func (c *dNSServiceClient) CreateDeviceByHumanId(ctx context.Context, in *CreateDeviceRequest, opts ...grpc.CallOption) (*CreateDeviceResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(CreateDeviceResponse)
+ err := c.cc.Invoke(ctx, DNSService_CreateDeviceByHumanId_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
// DNSServiceServer is the server API for DNSService service.
// All implementations must embed UnimplementedDNSServiceServer
// for forward compatibility
@@ -123,9 +151,24 @@ type DNSServiceServer interface {
//
// The trailers headers will include a "sync_time", given in milliseconds,
// that should be used for subsequent incremental DNS profile synchronization requests.
+ //
+ // This method may return the following errors:
+ // - RateLimitedError: If too many "full sync" concurrent requests are made.
+ // - AuthenticationFailedError: If the authentication failed.
GetDNSProfiles(*DNSProfilesRequest, DNSService_GetDNSProfilesServer) error
// Stores devices activity.
+ //
+ // This method may return the following errors:
+ // - AuthenticationFailedError: If the authentication failed.
SaveDevicesBillingStat(DNSService_SaveDevicesBillingStatServer) error
+ // Create device by "human_id".
+ //
+ // This method may return the following errors:
+ // - RateLimitedError: If the request was made too frequently and the client must wait before retrying.
+ // - DeviceQuotaExceededError: If the client has exceeded its quota for creating devices.
+ // - BadRequestError: If the request is invalid: DNS server does not exist, creation of auto-devices is disabled or human_id validation failed.
+ // - AuthenticationFailedError: If the authentication failed.
+ CreateDeviceByHumanId(context.Context, *CreateDeviceRequest) (*CreateDeviceResponse, error)
mustEmbedUnimplementedDNSServiceServer()
}
@@ -139,6 +182,9 @@ func (UnimplementedDNSServiceServer) GetDNSProfiles(*DNSProfilesRequest, DNSServ
func (UnimplementedDNSServiceServer) SaveDevicesBillingStat(DNSService_SaveDevicesBillingStatServer) error {
return status.Errorf(codes.Unimplemented, "method SaveDevicesBillingStat not implemented")
}
+func (UnimplementedDNSServiceServer) CreateDeviceByHumanId(context.Context, *CreateDeviceRequest) (*CreateDeviceResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method CreateDeviceByHumanId not implemented")
+}
func (UnimplementedDNSServiceServer) mustEmbedUnimplementedDNSServiceServer() {}
// UnsafeDNSServiceServer may be embedded to opt out of forward compatibility for this service.
@@ -157,7 +203,7 @@ func _DNSService_GetDNSProfiles_Handler(srv interface{}, stream grpc.ServerStrea
if err := stream.RecvMsg(m); err != nil {
return err
}
- return srv.(DNSServiceServer).GetDNSProfiles(m, &dNSServiceGetDNSProfilesServer{stream})
+ return srv.(DNSServiceServer).GetDNSProfiles(m, &dNSServiceGetDNSProfilesServer{ServerStream: stream})
}
type DNSService_GetDNSProfilesServer interface {
@@ -174,7 +220,7 @@ func (x *dNSServiceGetDNSProfilesServer) Send(m *DNSProfile) error {
}
func _DNSService_SaveDevicesBillingStat_Handler(srv interface{}, stream grpc.ServerStream) error {
- return srv.(DNSServiceServer).SaveDevicesBillingStat(&dNSServiceSaveDevicesBillingStatServer{stream})
+ return srv.(DNSServiceServer).SaveDevicesBillingStat(&dNSServiceSaveDevicesBillingStatServer{ServerStream: stream})
}
type DNSService_SaveDevicesBillingStatServer interface {
@@ -199,13 +245,36 @@ func (x *dNSServiceSaveDevicesBillingStatServer) Recv() (*DeviceBillingStat, err
return m, nil
}
+func _DNSService_CreateDeviceByHumanId_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(CreateDeviceRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DNSServiceServer).CreateDeviceByHumanId(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: DNSService_CreateDeviceByHumanId_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DNSServiceServer).CreateDeviceByHumanId(ctx, req.(*CreateDeviceRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
// DNSService_ServiceDesc is the grpc.ServiceDesc for DNSService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var DNSService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "DNSService",
HandlerType: (*DNSServiceServer)(nil),
- Methods: []grpc.MethodDesc{},
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "createDeviceByHumanId",
+ Handler: _DNSService_CreateDeviceByHumanId_Handler,
+ },
+ },
Streams: []grpc.StreamDesc{
{
StreamName: "getDNSProfiles",
@@ -218,5 +287,5 @@ var DNSService_ServiceDesc = grpc.ServiceDesc{
ClientStreams: true,
},
},
- Metadata: "backend.proto",
+ Metadata: "dns.proto",
}
diff --git a/internal/backendpb/error.go b/internal/backendpb/error.go
new file mode 100644
index 0000000..ed79ff1
--- /dev/null
+++ b/internal/backendpb/error.go
@@ -0,0 +1,70 @@
+package backendpb
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
+ "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+)
+
+// fixGRPCError converts a gRPC error into an application error, if necessary.
+// That includes gRPC deadlines, which do not match [context.DeadlineExceeded]
+// correctly.
+//
+// It also updates the backend gRPC metrics depending on the type, see
+// [metrics.IncGRPCErrorsCounter].
+func fixGRPCError(err error) (res error) {
+ metricsType := metrics.GRPCErrorTypeOther
+ defer func() { metrics.IncGRPCErrorsCounter(metricsType) }()
+
+ s, ok := status.FromError(err)
+ if !ok {
+ // Return the error as-is.
+ return err
+ }
+
+ // See https://github.com/grpc/grpc-go/issues/4822.
+ //
+ // TODO(d.kolyshev): Remove after the grpc-go issue is fixed.
+ if s.Code() == codes.DeadlineExceeded {
+ metricsType = metrics.GRPCErrorTypeTimeout
+
+ return fmt.Errorf("grpc: %w; original message: %s", context.DeadlineExceeded, err)
+ }
+
+ for _, d := range s.Details() {
+ switch structErr := d.(type) {
+ case *AuthenticationFailedError:
+ metricsType = metrics.GRPCErrorTypeAuthentication
+
+ return &profiledb.AuthenticationFailedError{
+ Message: structErr.Message,
+ }
+ case *BadRequestError:
+ metricsType = metrics.GRPCErrorTypeBadRequest
+
+ return &profiledb.BadRequestError{
+ Message: structErr.Message,
+ }
+ case *DeviceQuotaExceededError:
+ metricsType = metrics.GRPCErrorTypeDeviceQuota
+
+ return &profiledb.DeviceQuotaExceededError{
+ Message: structErr.Message,
+ }
+ case *RateLimitedError:
+ metricsType = metrics.GRPCErrorTypeRateLimit
+
+ return &profiledb.RateLimitedError{
+ Message: structErr.Message,
+ RetryDelay: structErr.RetryDelay.AsDuration(),
+ }
+ }
+ }
+
+ // Return the error as-is.
+ return err
+}
diff --git a/internal/backendpb/profile.go b/internal/backendpb/profile.go
new file mode 100644
index 0000000..05f2c5a
--- /dev/null
+++ b/internal/backendpb/profile.go
@@ -0,0 +1,341 @@
+package backendpb
+
+import (
+ "context"
+ "fmt"
+ "net/netip"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/access"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/netutil"
+)
+
+// toInternal converts the protobuf-encoded data into a profile structure and
+// its device structures.
+func (x *DNSProfile) toInternal(
+ ctx context.Context,
+ updTime time.Time,
+ bindSet netutil.SubnetSet,
+ errColl errcoll.Interface,
+) (profile *agd.Profile, devices []*agd.Device, err error) {
+ if x == nil {
+ return nil, nil, fmt.Errorf("profile is nil")
+ }
+
+ parental, err := x.Parental.toInternal(ctx, errColl)
+ if err != nil {
+ return nil, nil, fmt.Errorf("parental: %w", err)
+ }
+
+ m, err := blockingModeToInternal(x.BlockingMode)
+ if err != nil {
+ return nil, nil, fmt.Errorf("blocking mode: %w", err)
+ }
+
+ devices, deviceIds := devicesToInternal(ctx, x.Devices, bindSet, errColl)
+ listsEnabled, listIDs := x.RuleLists.toInternal(ctx, errColl)
+
+ profID, err := agd.NewProfileID(x.DnsId)
+ if err != nil {
+ return nil, nil, fmt.Errorf("id: %w", err)
+ }
+
+ var fltRespTTL time.Duration
+ if respTTL := x.FilteredResponseTtl; respTTL != nil {
+ fltRespTTL = respTTL.AsDuration()
+ }
+
+ return &agd.Profile{
+ Parental: parental,
+ BlockingMode: m,
+ ID: profID,
+ UpdateTime: updTime,
+ DeviceIDs: deviceIds,
+ RuleListIDs: listIDs,
+ CustomRules: rulesToInternal(ctx, x.CustomRules, errColl),
+ FilteredResponseTTL: fltRespTTL,
+ FilteringEnabled: x.FilteringEnabled,
+ SafeBrowsing: x.SafeBrowsing.toInternal(),
+ Access: x.Access.toInternal(ctx, errColl),
+ RuleListsEnabled: listsEnabled,
+ QueryLogEnabled: x.QueryLogEnabled,
+ Deleted: x.Deleted,
+ BlockPrivateRelay: x.BlockPrivateRelay,
+ BlockFirefoxCanary: x.BlockFirefoxCanary,
+ IPLogEnabled: x.IpLogEnabled,
+ AutoDevicesEnabled: x.AutoDevicesEnabled,
+ }, devices, nil
+}
+
+// toInternal converts a protobuf parental-settings structure to an internal
+// one. If x is nil, toInternal returns nil.
+func (x *ParentalSettings) toInternal(
+ ctx context.Context,
+ errColl errcoll.Interface,
+) (s *agd.ParentalProtectionSettings, err error) {
+ if x == nil {
+ return nil, nil
+ }
+
+ schedule, err := x.Schedule.toInternal()
+ if err != nil {
+ return nil, fmt.Errorf("schedule: %w", err)
+ }
+
+ return &agd.ParentalProtectionSettings{
+ Schedule: schedule,
+ BlockedServices: blockedSvcsToInternal(ctx, errColl, x.BlockedServices),
+ Enabled: x.Enabled,
+ BlockAdult: x.BlockAdult,
+ GeneralSafeSearch: x.GeneralSafeSearch,
+ YoutubeSafeSearch: x.YoutubeSafeSearch,
+ }, nil
+}
+
+// toInternal converts protobuf safe-browsing settings to an internal structure.
+// If x is nil, toInternal returns nil.
+func (x *SafeBrowsingSettings) toInternal() (sb *agd.SafeBrowsingSettings) {
+ if x == nil {
+ return nil
+ }
+
+ return &agd.SafeBrowsingSettings{
+ Enabled: x.Enabled,
+ BlockDangerousDomains: x.BlockDangerousDomains,
+ BlockNewlyRegisteredDomains: x.BlockNrd,
+ }
+}
+
+// toInternal converts protobuf access settings to an internal structure. If x
+// is nil, toInternal returns [access.EmptyProfile].
+func (x *AccessSettings) toInternal(
+ ctx context.Context,
+ errColl errcoll.Interface,
+) (a access.Profile) {
+ if x == nil || !x.Enabled {
+ return access.EmptyProfile{}
+ }
+
+ return access.NewDefaultProfile(&access.ProfileConfig{
+ AllowedNets: cidrRangeToInternal(ctx, errColl, x.AllowlistCidr),
+ BlockedNets: cidrRangeToInternal(ctx, errColl, x.BlocklistCidr),
+ AllowedASN: asnToInternal(x.AllowlistAsn),
+ BlockedASN: asnToInternal(x.BlocklistAsn),
+ BlocklistDomainRules: x.BlocklistDomainRules,
+ })
+}
+
+// cidrRangeToInternal is a helper that converts a slice of CidrRange to the
+// slice of [netip.Prefix].
+func cidrRangeToInternal(
+ ctx context.Context,
+ errColl errcoll.Interface,
+ cidrs []*CidrRange,
+) (out []netip.Prefix) {
+ for i, c := range cidrs {
+ addr, ok := netip.AddrFromSlice(c.Address)
+ if !ok {
+ reportf(ctx, errColl, "bad cidr at index %d: %v", i, c.Address)
+
+ continue
+ }
+
+ out = append(out, netip.PrefixFrom(addr, int(c.Prefix)))
+ }
+
+ return out
+}
+
+// asnToInternal is a helper that converts a slice of ASNs to the slice of
+// [geoip.ASN].
+func asnToInternal(asns []uint32) (out []geoip.ASN) {
+ for _, asn := range asns {
+ out = append(out, geoip.ASN(asn))
+ }
+
+ return out
+}
+
+// blockedSvcsToInternal is a helper that converts the blocked service IDs from
+// the backend response to AdGuard DNS blocked service IDs.
+func blockedSvcsToInternal(
+ ctx context.Context,
+ errColl errcoll.Interface,
+ respSvcs []string,
+) (svcs []agd.BlockedServiceID) {
+ l := len(respSvcs)
+ if l == 0 {
+ return nil
+ }
+
+ svcs = make([]agd.BlockedServiceID, 0, l)
+ for i, s := range respSvcs {
+ id, err := agd.NewBlockedServiceID(s)
+ if err != nil {
+ reportf(ctx, errColl, "blocked service at index %d: %w", i, err)
+
+ continue
+ }
+
+ svcs = append(svcs, id)
+ }
+
+ return svcs
+}
+
+// toInternal converts a protobuf protection-schedule structure to an internal
+// one. If x is nil, toInternal returns nil.
+func (x *ScheduleSettings) toInternal() (sch *agd.ParentalProtectionSchedule, err error) {
+ if x == nil {
+ return nil, nil
+ }
+
+ sch = &agd.ParentalProtectionSchedule{}
+
+ sch.TimeZone, err = agdtime.LoadLocation(x.Tmz)
+ if err != nil {
+ return nil, fmt.Errorf("loading timezone: %w", err)
+ }
+
+ sch.Week = &agd.WeeklySchedule{}
+
+ w := x.WeeklyRange
+ days := []*DayRange{w.Sun, w.Mon, w.Tue, w.Wed, w.Thu, w.Fri, w.Sat}
+ for i, d := range days {
+ if d == nil {
+ sch.Week[i] = agd.ZeroLengthDayRange()
+
+ continue
+ }
+
+ sch.Week[i] = agd.DayRange{
+ Start: uint16(d.Start.AsDuration().Minutes()),
+ End: uint16(d.End.AsDuration().Minutes()),
+ }
+ }
+
+ for i, r := range sch.Week {
+ err = r.Validate()
+ if err != nil {
+ return nil, fmt.Errorf("weekday %s: %w", time.Weekday(i), err)
+ }
+ }
+
+ return sch, nil
+}
+
+// toInternal converts a protobuf custom blocking-mode to an internal one.
+// Assumes that at least one IP address is specified in the result blocking-mode
+// object.
+func (pbm *BlockingModeCustomIP) toInternal() (m dnsmsg.BlockingMode, err error) {
+ custom := &dnsmsg.BlockingModeCustomIP{}
+
+ // TODO(a.garipov): Only one IPv4 address is supported on protobuf side.
+ var ipv4Addr netip.Addr
+ err = ipv4Addr.UnmarshalBinary(pbm.Ipv4)
+ if err != nil {
+ return nil, fmt.Errorf("bad custom ipv4: %w", err)
+ } else if ipv4Addr.IsValid() {
+ custom.IPv4 = []netip.Addr{ipv4Addr}
+ }
+
+ // TODO(a.garipov): Only one IPv6 address is supported on protobuf side.
+ var ipv6Addr netip.Addr
+ err = ipv6Addr.UnmarshalBinary(pbm.Ipv6)
+ if err != nil {
+ return nil, fmt.Errorf("bad custom ipv6: %w", err)
+ } else if ipv6Addr.IsValid() {
+ custom.IPv6 = []netip.Addr{ipv6Addr}
+ }
+
+ if len(custom.IPv4)+len(custom.IPv6) == 0 {
+ return nil, errors.Error("no valid custom ips found")
+ }
+
+ return custom, nil
+}
+
+// blockingModeToInternal converts a protobuf blocking-mode sum-type to an
+// internal one. If pbm is nil, blockingModeToInternal returns a null-IP
+// blocking mode.
+func blockingModeToInternal(pbm isDNSProfile_BlockingMode) (m dnsmsg.BlockingMode, err error) {
+ switch pbm := pbm.(type) {
+ case nil:
+ return &dnsmsg.BlockingModeNullIP{}, nil
+ case *DNSProfile_BlockingModeCustomIp:
+ return pbm.BlockingModeCustomIp.toInternal()
+ case *DNSProfile_BlockingModeNxdomain:
+ return &dnsmsg.BlockingModeNXDOMAIN{}, nil
+ case *DNSProfile_BlockingModeNullIp:
+ return &dnsmsg.BlockingModeNullIP{}, nil
+ case *DNSProfile_BlockingModeRefused:
+ return &dnsmsg.BlockingModeREFUSED{}, nil
+ default:
+ // Consider unhandled type-switch cases programmer errors.
+ return nil, fmt.Errorf("bad pb blocking mode %T(%[1]v)", pbm)
+ }
+}
+
+// rulesToInternal is a helper that converts the filter rules from the backend
+// response to AdGuard DNS filtering rules.
+func rulesToInternal(
+ ctx context.Context,
+ respRules []string,
+ errColl errcoll.Interface,
+) (rules []agd.FilterRuleText) {
+ l := len(respRules)
+ if l == 0 {
+ return nil
+ }
+
+ rules = make([]agd.FilterRuleText, 0, l)
+ for i, r := range respRules {
+ text, err := agd.NewFilterRuleText(r)
+ if err != nil {
+ reportf(ctx, errColl, "rule at index %d: %w", i, err)
+
+ continue
+ }
+
+ rules = append(rules, text)
+ }
+
+ return rules
+}
+
+// toInternal is a helper that converts the filter lists from the backend
+// response to AdGuard DNS filter list ids. If x is nil, toInternal returns
+// false and nil.
+func (x *RuleListsSettings) toInternal(
+ ctx context.Context,
+ errColl errcoll.Interface,
+) (enabled bool, filterLists []agd.FilterListID) {
+ if x == nil {
+ return false, nil
+ }
+
+ l := len(x.Ids)
+ if l == 0 {
+ return x.Enabled, nil
+ }
+
+ filterLists = make([]agd.FilterListID, 0, l)
+ for i, f := range x.Ids {
+ id, err := agd.NewFilterListID(f)
+ if err != nil {
+ reportf(ctx, errColl, "filter id: at index %d: %w", i, err)
+
+ continue
+ }
+
+ filterLists = append(filterLists, id)
+ }
+
+ return x.Enabled, filterLists
+}
diff --git a/internal/backendpb/profile_internal_test.go b/internal/backendpb/profile_internal_test.go
new file mode 100644
index 0000000..1a59652
--- /dev/null
+++ b/internal/backendpb/profile_internal_test.go
@@ -0,0 +1,553 @@
+package backendpb
+
+import (
+ "context"
+ "net/netip"
+ "testing"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/access"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/golibs/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "google.golang.org/protobuf/types/known/durationpb"
+)
+
+func TestDNSProfile_ToInternal(t *testing.T) {
+ t.Parallel()
+
+ ctx := context.Background()
+
+ errColl := &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) {
+ panic(err)
+ },
+ }
+
+ t.Run("success", func(t *testing.T) {
+ t.Parallel()
+
+ got, gotDevices, err := NewTestDNSProfile(t).toInternal(ctx, TestUpdTime, TestBind, errColl)
+ require.NoError(t, err)
+
+ assert.Equal(t, newProfile(t), got)
+ assert.Equal(t, newDevices(t), gotDevices)
+ })
+
+ t.Run("success_bad_data", func(t *testing.T) {
+ t.Parallel()
+
+ var errCollErr error
+ savingErrColl := &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) {
+ errCollErr = err
+ },
+ }
+ got, gotDevices, err := newDNSProfileWithBadData(t).toInternal(
+ ctx,
+ TestUpdTime,
+ TestBind,
+ savingErrColl,
+ )
+ require.NoError(t, err)
+ testutil.AssertErrorMsg(
+ t,
+ `backendpb: bad device settings for device with id "inv-d-ip":`+
+ " dedicated ips: ip at index 0: unexpected slice size",
+ errCollErr,
+ )
+
+ assert.Equal(t, newProfile(t), got)
+ assert.Equal(t, newDevices(t), gotDevices)
+ })
+
+ t.Run("invalid_device_ded_ip", func(t *testing.T) {
+ t.Parallel()
+
+ var errCollErr error
+ savingErrColl := &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) {
+ errCollErr = err
+ },
+ }
+
+ bindSet := netip.MustParsePrefix("2.2.2.2/32")
+ got, gotDevices, err := NewTestDNSProfile(t).toInternal(
+ ctx,
+ TestUpdTime,
+ bindSet,
+ savingErrColl,
+ )
+ require.NoError(t, err)
+ testutil.AssertErrorMsg(
+ t,
+ `backendpb: bad device settings for device with id "`+TestDeviceIDStr+`":`+
+ " dedicated ips: at index 0: \"1.1.1.2\" is not in bind data",
+ errCollErr,
+ )
+
+ assert.NotEqual(t, newProfile(t), got)
+ assert.NotEqual(t, newDevices(t), gotDevices)
+ assert.Len(t, gotDevices, 3)
+ })
+
+ t.Run("empty", func(t *testing.T) {
+ t.Parallel()
+
+ var emptyDNSProfile *DNSProfile
+ _, _, err := emptyDNSProfile.toInternal(ctx, TestUpdTime, TestBind, errColl)
+ testutil.AssertErrorMsg(t, "profile is nil", err)
+ })
+
+ t.Run("deleted", func(t *testing.T) {
+ t.Parallel()
+
+ dp := &DNSProfile{
+ DnsId: TestProfileIDStr,
+ Deleted: true,
+ }
+
+ got, gotDevices, err := dp.toInternal(ctx, TestUpdTime, TestBind, errColl)
+ require.NoError(t, err)
+ require.NotNil(t, got)
+
+ assert.Equal(t, got.ID, TestProfileID)
+ assert.True(t, got.Deleted)
+ assert.Empty(t, gotDevices)
+ })
+
+ t.Run("inv_parental_sch_tmz", func(t *testing.T) {
+ t.Parallel()
+
+ dp := NewTestDNSProfile(t)
+ dp.Parental.Schedule.Tmz = "invalid"
+
+ _, _, err := dp.toInternal(ctx, TestUpdTime, TestBind, errColl)
+ testutil.AssertErrorMsg(
+ t,
+ "parental: schedule: loading timezone: unknown time zone invalid",
+ err,
+ )
+ })
+
+ t.Run("inv_parental_sch_day_range", func(t *testing.T) {
+ t.Parallel()
+
+ dp := NewTestDNSProfile(t)
+ dp.Parental.Schedule.WeeklyRange.Sun = &DayRange{
+ Start: durationpb.New(1000000000000),
+ End: nil,
+ }
+
+ _, _, err := dp.toInternal(ctx, TestUpdTime, TestBind, errColl)
+ testutil.AssertErrorMsg(
+ t,
+ "parental: schedule: weekday Sunday: bad day range: end 0 less than start 16",
+ err,
+ )
+ })
+
+ t.Run("inv_blocking_mode_v4", func(t *testing.T) {
+ t.Parallel()
+
+ dp := NewTestDNSProfile(t)
+ bm := dp.BlockingMode.(*DNSProfile_BlockingModeCustomIp)
+ bm.BlockingModeCustomIp.Ipv4 = []byte("1")
+
+ _, _, err := dp.toInternal(ctx, TestUpdTime, TestBind, errColl)
+ testutil.AssertErrorMsg(t, "blocking mode: bad custom ipv4: unexpected slice size", err)
+ })
+
+ t.Run("inv_blocking_mode_v6", func(t *testing.T) {
+ t.Parallel()
+
+ dp := NewTestDNSProfile(t)
+ bm := dp.BlockingMode.(*DNSProfile_BlockingModeCustomIp)
+ bm.BlockingModeCustomIp.Ipv6 = []byte("1")
+
+ _, _, err := dp.toInternal(ctx, TestUpdTime, TestBind, errColl)
+ testutil.AssertErrorMsg(t, "blocking mode: bad custom ipv6: unexpected slice size", err)
+ })
+
+ t.Run("nil_ips_blocking_mode", func(t *testing.T) {
+ t.Parallel()
+
+ dp := NewTestDNSProfile(t)
+ bm := dp.BlockingMode.(*DNSProfile_BlockingModeCustomIp)
+ bm.BlockingModeCustomIp.Ipv4 = nil
+ bm.BlockingModeCustomIp.Ipv6 = nil
+
+ _, _, err := dp.toInternal(ctx, TestUpdTime, TestBind, errColl)
+ testutil.AssertErrorMsg(t, "blocking mode: no valid custom ips found", err)
+ })
+
+ t.Run("nil_blocking_mode", func(t *testing.T) {
+ t.Parallel()
+
+ dp := NewTestDNSProfile(t)
+ dp.BlockingMode = nil
+
+ got, gotDevices, err := dp.toInternal(ctx, TestUpdTime, TestBind, errColl)
+ require.NoError(t, err)
+ require.NotNil(t, got)
+
+ wantProf := newProfile(t)
+ wantProf.BlockingMode = &dnsmsg.BlockingModeNullIP{}
+
+ assert.Equal(t, wantProf, got)
+ assert.Equal(t, newDevices(t), gotDevices)
+ })
+
+ t.Run("nil_access", func(t *testing.T) {
+ t.Parallel()
+
+ dp := NewTestDNSProfile(t)
+ dp.Access = nil
+
+ got, _, err := dp.toInternal(ctx, TestUpdTime, TestBind, errColl)
+ require.NoError(t, err)
+ require.NotNil(t, got)
+
+ assert.Equal(t, got.ID, TestProfileID)
+ assert.IsType(t, access.EmptyProfile{}, got.Access)
+ })
+
+ t.Run("access_disabled", func(t *testing.T) {
+ t.Parallel()
+
+ dp := NewTestDNSProfile(t)
+ dp.Access = &AccessSettings{
+ Enabled: false,
+ }
+
+ got, _, err := dp.toInternal(ctx, TestUpdTime, TestBind, errColl)
+ require.NoError(t, err)
+ require.NotNil(t, got)
+
+ assert.Equal(t, got.ID, TestProfileID)
+ assert.IsType(t, access.EmptyProfile{}, got.Access)
+ })
+}
+
+// newDNSProfileWithBadData returns a new instance of *DNSProfile with bad
+// devices data for tests.
+func newDNSProfileWithBadData(tb testing.TB) (dp *DNSProfile) {
+ tb.Helper()
+
+ invalidDevices := []*DeviceSettings{{
+ Id: "invalid-too-long-device-id",
+ Name: "device_name",
+ FilteringEnabled: true,
+ LinkedIp: ipToBytes(tb, netip.MustParseAddr("1.1.1.1")),
+ DedicatedIps: nil,
+ }, {
+ Id: "dev-name",
+ Name: "invalid-too-long-device-name-invalid-too-long-device-name-" +
+ "invalid-too-long-device-name-invalid-too-long-device-name-" +
+ "invalid-too-long-device-name-invalid-too-long-device-name",
+ FilteringEnabled: true,
+ LinkedIp: ipToBytes(tb, netip.MustParseAddr("1.1.1.1")),
+ DedicatedIps: nil,
+ }, {
+ Id: "inv-ip",
+ Name: "test-name",
+ FilteringEnabled: true,
+ LinkedIp: []byte("1"),
+ DedicatedIps: nil,
+ }, {
+ Id: "inv-d-ip",
+ Name: "test-name",
+ FilteringEnabled: true,
+ LinkedIp: ipToBytes(tb, netip.MustParseAddr("1.1.1.1")),
+ DedicatedIps: [][]byte{[]byte("1")},
+ }}
+
+ dp = NewTestDNSProfile(tb)
+ dp.Devices = append(dp.Devices, invalidDevices...)
+
+ return dp
+}
+
+// NewTestDNSProfile returns a new instance of *DNSProfile for tests.
+func NewTestDNSProfile(tb testing.TB) (dp *DNSProfile) {
+ tb.Helper()
+
+ dayRange := &DayRange{
+ Start: durationpb.New(0),
+ End: durationpb.New(59 * time.Minute),
+ }
+
+ devices := []*DeviceSettings{{
+ Id: TestDeviceIDStr,
+ Name: "1111aaaa-name",
+ FilteringEnabled: false,
+ LinkedIp: ipToBytes(tb, netip.MustParseAddr("1.1.1.1")),
+ DedicatedIps: [][]byte{ipToBytes(tb, netip.MustParseAddr("1.1.1.2"))},
+ }, {
+ Id: "2222bbbb",
+ Name: "2222bbbb-name",
+ FilteringEnabled: true,
+ LinkedIp: ipToBytes(tb, netip.MustParseAddr("2.2.2.2")),
+ DedicatedIps: nil,
+ Authentication: &AuthenticationSettings{
+ DohAuthOnly: true,
+ DohPasswordHash: &AuthenticationSettings_PasswordHashBcrypt{
+ PasswordHashBcrypt: []byte("test-hash"),
+ },
+ },
+ }, {
+ Id: "3333cccc",
+ Name: "3333cccc-name",
+ FilteringEnabled: false,
+ LinkedIp: ipToBytes(tb, netip.MustParseAddr("3.3.3.3")),
+ DedicatedIps: nil,
+ Authentication: &AuthenticationSettings{
+ DohAuthOnly: false,
+ DohPasswordHash: nil,
+ },
+ }, {
+ Id: "4444dddd",
+ Name: "My Auto-Device",
+ HumanIdLower: "my-auto--device",
+ FilteringEnabled: true,
+ }}
+
+ return &DNSProfile{
+ DnsId: TestProfileIDStr,
+ FilteringEnabled: true,
+ QueryLogEnabled: true,
+ Deleted: false,
+ SafeBrowsing: &SafeBrowsingSettings{
+ Enabled: true,
+ BlockDangerousDomains: true,
+ BlockNrd: false,
+ },
+ Parental: &ParentalSettings{
+ Enabled: false,
+ BlockAdult: false,
+ GeneralSafeSearch: false,
+ YoutubeSafeSearch: false,
+ BlockedServices: []string{"youtube"},
+ Schedule: &ScheduleSettings{
+ Tmz: "GMT",
+ WeeklyRange: &WeeklyRange{
+ Sun: nil,
+ Mon: dayRange,
+ Tue: dayRange,
+ Wed: dayRange,
+ Thu: dayRange,
+ Fri: dayRange,
+ Sat: nil,
+ },
+ },
+ },
+ RuleLists: &RuleListsSettings{
+ Enabled: true,
+ Ids: []string{"1"},
+ },
+ Devices: devices,
+ CustomRules: []string{"||example.org^"},
+ FilteredResponseTtl: durationpb.New(10 * time.Second),
+ BlockPrivateRelay: true,
+ BlockFirefoxCanary: true,
+ IpLogEnabled: true,
+ AutoDevicesEnabled: true,
+ BlockingMode: &DNSProfile_BlockingModeCustomIp{
+ BlockingModeCustomIp: &BlockingModeCustomIP{
+ Ipv4: ipToBytes(tb, netip.MustParseAddr("1.2.3.4")),
+ Ipv6: ipToBytes(tb, netip.MustParseAddr("1234::cdef")),
+ },
+ },
+ Access: &AccessSettings{
+ AllowlistCidr: []*CidrRange{{
+ Address: netip.MustParseAddr("1.1.1.0").AsSlice(),
+ Prefix: 24,
+ }},
+ BlocklistCidr: []*CidrRange{{
+ Address: netip.MustParseAddr("2.2.2.0").AsSlice(),
+ Prefix: 24,
+ }},
+ AllowlistAsn: []uint32{1},
+ BlocklistAsn: []uint32{2},
+ BlocklistDomainRules: []string{"block.test"},
+ Enabled: true,
+ },
+ }
+}
+
+// ipToBytes is a wrapper around netip.Addr.MarshalBinary.
+func ipToBytes(tb testing.TB, ip netip.Addr) (b []byte) {
+ tb.Helper()
+
+ b, err := ip.MarshalBinary()
+ require.NoError(tb, err)
+
+ return b
+}
+
+// newProfile returns a new profile for tests.
+func newProfile(tb testing.TB) (p *agd.Profile) {
+ tb.Helper()
+
+ wantLoc, err := agdtime.LoadLocation("GMT")
+ require.NoError(tb, err)
+
+ dayRange := agd.DayRange{
+ Start: 0,
+ End: 59,
+ }
+
+ wantParental := &agd.ParentalProtectionSettings{
+ Schedule: &agd.ParentalProtectionSchedule{
+ Week: &agd.WeeklySchedule{
+ agd.ZeroLengthDayRange(),
+ dayRange,
+ dayRange,
+ dayRange,
+ dayRange,
+ dayRange,
+ agd.ZeroLengthDayRange(),
+ },
+ TimeZone: wantLoc,
+ },
+ BlockedServices: []agd.BlockedServiceID{"youtube"},
+ Enabled: false,
+ BlockAdult: false,
+ GeneralSafeSearch: false,
+ YoutubeSafeSearch: false,
+ }
+
+ wantSafeBrowsing := &agd.SafeBrowsingSettings{
+ Enabled: true,
+ BlockDangerousDomains: true,
+ BlockNewlyRegisteredDomains: false,
+ }
+
+ wantBlockingMode := &dnsmsg.BlockingModeCustomIP{
+ IPv4: []netip.Addr{netip.MustParseAddr("1.2.3.4")},
+ IPv6: []netip.Addr{netip.MustParseAddr("1234::cdef")},
+ }
+
+ wantAccess := access.NewDefaultProfile(&access.ProfileConfig{
+ AllowedNets: []netip.Prefix{netip.MustParsePrefix("1.1.1.0/24")},
+ BlockedNets: []netip.Prefix{netip.MustParsePrefix("2.2.2.0/24")},
+ AllowedASN: []geoip.ASN{1},
+ BlockedASN: []geoip.ASN{2},
+ BlocklistDomainRules: []string{"block.test"},
+ })
+
+ return &agd.Profile{
+ Parental: wantParental,
+ BlockingMode: wantBlockingMode,
+ ID: TestProfileID,
+ UpdateTime: TestUpdTime,
+ DeviceIDs: []agd.DeviceID{
+ TestDeviceID,
+ "2222bbbb",
+ "3333cccc",
+ "4444dddd",
+ },
+ RuleListIDs: []agd.FilterListID{"1"},
+ CustomRules: []agd.FilterRuleText{"||example.org^"},
+ FilteredResponseTTL: 10 * time.Second,
+ SafeBrowsing: wantSafeBrowsing,
+ Access: wantAccess,
+ RuleListsEnabled: true,
+ FilteringEnabled: true,
+ QueryLogEnabled: true,
+ Deleted: false,
+ BlockPrivateRelay: true,
+ BlockFirefoxCanary: true,
+ IPLogEnabled: true,
+ AutoDevicesEnabled: true,
+ }
+}
+
+// newDevices returns a slice of test devices.
+func newDevices(t *testing.T) (d []*agd.Device) {
+ t.Helper()
+
+ return []*agd.Device{{
+ Auth: &agd.AuthSettings{
+ Enabled: false,
+ DoHAuthOnly: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ },
+ ID: TestDeviceID,
+ LinkedIP: netip.MustParseAddr("1.1.1.1"),
+ Name: "1111aaaa-name",
+ DedicatedIPs: []netip.Addr{netip.MustParseAddr("1.1.1.2")},
+ FilteringEnabled: false,
+ }, {
+ Auth: &agd.AuthSettings{
+ Enabled: true,
+ DoHAuthOnly: true,
+ PasswordHash: agdpasswd.NewPasswordHashBcrypt([]byte("test-hash")),
+ },
+ ID: "2222bbbb",
+ LinkedIP: netip.MustParseAddr("2.2.2.2"),
+ Name: "2222bbbb-name",
+ DedicatedIPs: nil,
+ FilteringEnabled: true,
+ }, {
+ Auth: &agd.AuthSettings{
+ Enabled: true,
+ DoHAuthOnly: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ },
+ ID: "3333cccc",
+ LinkedIP: netip.MustParseAddr("3.3.3.3"),
+ Name: "3333cccc-name",
+ DedicatedIPs: nil,
+ FilteringEnabled: false,
+ }, {
+ Auth: &agd.AuthSettings{
+ Enabled: false,
+ DoHAuthOnly: false,
+ PasswordHash: agdpasswd.AllowAuthenticator{},
+ },
+ ID: "4444dddd",
+ Name: "My Auto-Device",
+ HumanIDLower: "my-auto--device",
+ FilteringEnabled: true,
+ }}
+}
+
+var (
+ errSink error
+ profSink *agd.Profile
+)
+
+func BenchmarkDNSProfile_ToInternal(b *testing.B) {
+ dp := NewTestDNSProfile(b)
+ ctx := context.Background()
+
+ errColl := &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) {
+ panic(err)
+ },
+ }
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for range b.N {
+ profSink, _, errSink = dp.toInternal(ctx, TestUpdTime, TestBind, errColl)
+ }
+
+ require.NotNil(b, profSink)
+ require.NoError(b, errSink)
+
+ // Most recent result, on a ThinkPad X13:
+ // goos: linux
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/backendpb
+ // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
+ // BenchmarkDNSProfile_ToInternal
+ // BenchmarkDNSProfile_ToInternal-16 93568 19203 ns/op 1976 B/op 45 allocs/op
+}
diff --git a/internal/backendpb/profiledb.go b/internal/backendpb/profiledb.go
index 450619c..c2d4e17 100644
--- a/internal/backendpb/profiledb.go
+++ b/internal/backendpb/profiledb.go
@@ -4,26 +4,16 @@ import (
"context"
"fmt"
"io"
- "net/netip"
"net/url"
"strconv"
"time"
- "github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdprotobuf"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
- "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
- "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
- "google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
- "google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
)
@@ -40,6 +30,9 @@ type ProfileStorageConfig struct {
// 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
}
// ProfileStorage is the implementation of the [profiledb.Storage] interface
@@ -48,9 +41,8 @@ type ProfileStorageConfig struct {
type ProfileStorage struct {
bindSet netutil.SubnetSet
errColl errcoll.Interface
-
- // client is the current GRPC client.
- client DNSServiceClient
+ client DNSServiceClient
+ apiKey string
}
// NewProfileStorage returns a new [ProfileStorage] that retrieves information
@@ -64,26 +56,63 @@ func NewProfileStorage(c *ProfileStorageConfig) (s *ProfileStorage, err error) {
return &ProfileStorage{
bindSet: c.BindSet,
- client: client,
errColl: c.ErrColl,
+ client: client,
+ apiKey: c.APIKey,
}, nil
}
// type check
var _ profiledb.Storage = (*ProfileStorage)(nil)
+// CreateAutoDevice implements the [profile.Storage] interface for
+// *ProfileStorage.
+func (s *ProfileStorage) CreateAutoDevice(
+ ctx context.Context,
+ req *profiledb.StorageCreateAutoDeviceRequest,
+) (resp *profiledb.StorageCreateAutoDeviceResponse, err error) {
+ defer func() {
+ err = errors.Annotate(
+ err,
+ "creating auto device for profile %q and human id %q: %w",
+ req.ProfileID,
+ req.HumanID,
+ )
+ }()
+
+ ctx = ctxWithAuthentication(ctx, s.apiKey)
+ backendResp, err := s.client.CreateDeviceByHumanId(ctx, &CreateDeviceRequest{
+ DnsId: string(req.ProfileID),
+ HumanId: string(req.HumanID),
+ DeviceType: DeviceType(req.DeviceType),
+ })
+ if err != nil {
+ return nil, fmt.Errorf("calling backend: %w", fixGRPCError(err))
+ }
+
+ d, err := backendResp.Device.toInternal(s.bindSet)
+ if err != nil {
+ return nil, fmt.Errorf("converting device: %w", err)
+ }
+
+ return &profiledb.StorageCreateAutoDeviceResponse{
+ Device: d,
+ }, nil
+}
+
// Profiles implements the [profiledb.Storage] interface for *ProfileStorage.
func (s *ProfileStorage) Profiles(
ctx context.Context,
- req *profiledb.StorageRequest,
-) (resp *profiledb.StorageResponse, err error) {
+ req *profiledb.StorageProfilesRequest,
+) (resp *profiledb.StorageProfilesResponse, err error) {
+ ctx = ctxWithAuthentication(ctx, s.apiKey)
stream, err := s.client.GetDNSProfiles(ctx, toProtobuf(req))
if err != nil {
return nil, fmt.Errorf("loading profiles: %w", fixGRPCError(err))
}
defer func() { err = errors.WithDeferred(err, stream.CloseSend()) }()
- resp = &profiledb.StorageResponse{
+ resp = &profiledb.StorageProfilesResponse{
Profiles: []*agd.Profile{},
Devices: []*agd.Device{},
}
@@ -92,7 +121,7 @@ func (s *ProfileStorage) Profiles(
isFullSync: req.SyncTime.IsZero(),
}
- for {
+ for n := 1; ; n++ {
stats.startRecv()
profile, profErr := stream.Recv()
if profErr != nil {
@@ -100,7 +129,7 @@ func (s *ProfileStorage) Profiles(
break
}
- return nil, fmt.Errorf("receiving profile: %w", fixGRPCError(profErr))
+ return nil, fmt.Errorf("receiving profile #%d: %w", n, fixGRPCError(profErr))
}
stats.endRecv()
@@ -128,465 +157,8 @@ func (s *ProfileStorage) Profiles(
return resp, nil
}
-// fixGRPCError wraps GRPC error if needed. As the GRPC deadline error is not
-// correctly wrapped, this helper detects it by the status code and replaces it
-// with a simple DeadlineExceeded error.
-//
-// See https://github.com/grpc/grpc-go/issues/4822.
-//
-// TODO(d.kolyshev): Remove after the grpc-go issue is fixed.
-func fixGRPCError(err error) (wErr error) {
- st, ok := status.FromError(err)
- if ok && st.Code() == codes.DeadlineExceeded {
- err = fmt.Errorf("grpc: %w", context.DeadlineExceeded)
- }
-
- return err
-}
-
-// toInternal converts the protobuf-encoded data into a profile structure.
-func (x *DNSProfile) toInternal(
- ctx context.Context,
- updTime time.Time,
- bindSet netutil.SubnetSet,
- errColl errcoll.Interface,
-) (profile *agd.Profile, devices []*agd.Device, err error) {
- if x == nil {
- return nil, nil, fmt.Errorf("profile is nil")
- }
-
- parental, err := x.Parental.toInternal(ctx, errColl)
- if err != nil {
- return nil, nil, fmt.Errorf("parental: %w", err)
- }
-
- m, err := blockingModeToInternal(x.BlockingMode)
- if err != nil {
- return nil, nil, fmt.Errorf("blocking mode: %w", err)
- }
-
- devices, deviceIds := devicesToInternal(ctx, x.Devices, bindSet, errColl)
- listsEnabled, listIDs := x.RuleLists.toInternal(ctx, errColl)
-
- profID, err := agd.NewProfileID(x.DnsId)
- if err != nil {
- return nil, nil, fmt.Errorf("id: %w", err)
- }
-
- var fltRespTTL time.Duration
- if respTTL := x.FilteredResponseTtl; respTTL != nil {
- fltRespTTL = respTTL.AsDuration()
- }
-
- return &agd.Profile{
- Parental: parental,
- BlockingMode: m,
- ID: profID,
- UpdateTime: updTime,
- DeviceIDs: deviceIds,
- RuleListIDs: listIDs,
- CustomRules: rulesToInternal(ctx, x.CustomRules, errColl),
- FilteredResponseTTL: fltRespTTL,
- FilteringEnabled: x.FilteringEnabled,
- SafeBrowsing: x.SafeBrowsing.toInternal(),
- Access: x.Access.toInternal(ctx, errColl),
- RuleListsEnabled: listsEnabled,
- QueryLogEnabled: x.QueryLogEnabled,
- Deleted: x.Deleted,
- BlockPrivateRelay: x.BlockPrivateRelay,
- BlockFirefoxCanary: x.BlockFirefoxCanary,
- IPLogEnabled: x.IpLogEnabled,
- }, devices, nil
-}
-
-// toInternal converts a protobuf parental-settings structure to an internal
-// one. If x is nil, toInternal returns nil.
-func (x *ParentalSettings) toInternal(
- ctx context.Context,
- errColl errcoll.Interface,
-) (s *agd.ParentalProtectionSettings, err error) {
- if x == nil {
- return nil, nil
- }
-
- schedule, err := x.Schedule.toInternal()
- if err != nil {
- return nil, fmt.Errorf("schedule: %w", err)
- }
-
- return &agd.ParentalProtectionSettings{
- Schedule: schedule,
- BlockedServices: blockedSvcsToInternal(ctx, errColl, x.BlockedServices),
- Enabled: x.Enabled,
- BlockAdult: x.BlockAdult,
- GeneralSafeSearch: x.GeneralSafeSearch,
- YoutubeSafeSearch: x.YoutubeSafeSearch,
- }, nil
-}
-
-// toInternal converts protobuf safe-browsing settings to an internal structure.
-// If x is nil, toInternal returns nil.
-func (x *SafeBrowsingSettings) toInternal() (sb *agd.SafeBrowsingSettings) {
- if x == nil {
- return nil
- }
-
- return &agd.SafeBrowsingSettings{
- Enabled: x.Enabled,
- BlockDangerousDomains: x.BlockDangerousDomains,
- BlockNewlyRegisteredDomains: x.BlockNrd,
- }
-}
-
-// toInternal converts protobuf access settings to an internal structure. If x
-// is nil, toInternal returns [access.EmptyProfile].
-func (x *AccessSettings) toInternal(
- ctx context.Context,
- errColl errcoll.Interface,
-) (a access.Profile) {
- if x == nil || !x.Enabled {
- return access.EmptyProfile{}
- }
-
- return access.NewDefaultProfile(&access.ProfileConfig{
- AllowedNets: cidrRangeToInternal(ctx, errColl, x.AllowlistCidr),
- BlockedNets: cidrRangeToInternal(ctx, errColl, x.BlocklistCidr),
- AllowedASN: asnToInternal(x.AllowlistAsn),
- BlockedASN: asnToInternal(x.BlocklistAsn),
- BlocklistDomainRules: x.BlocklistDomainRules,
- })
-}
-
-// cidrRangeToInternal is a helper that converts a slice of CidrRange to the
-// slice of [netip.Prefix].
-func cidrRangeToInternal(
- ctx context.Context,
- errColl errcoll.Interface,
- cidrs []*CidrRange,
-) (out []netip.Prefix) {
- for i, c := range cidrs {
- addr, ok := netip.AddrFromSlice(c.Address)
- if !ok {
- reportf(ctx, errColl, "invalid cidr at index %d: %w", i)
-
- continue
- }
-
- out = append(out, netip.PrefixFrom(addr, int(c.Prefix)))
- }
-
- return out
-}
-
-// asnToInternal is a helper that converts a slice of ASNs to the slice of
-// [geoip.ASN].
-func asnToInternal(asns []uint32) (out []geoip.ASN) {
- for _, asn := range asns {
- out = append(out, geoip.ASN(asn))
- }
-
- return out
-}
-
-// blockedSvcsToInternal is a helper that converts the blocked service IDs from
-// the backend response to AdGuard DNS blocked service IDs.
-func blockedSvcsToInternal(
- ctx context.Context,
- errColl errcoll.Interface,
- respSvcs []string,
-) (svcs []agd.BlockedServiceID) {
- l := len(respSvcs)
- if l == 0 {
- return nil
- }
-
- svcs = make([]agd.BlockedServiceID, 0, l)
- for i, s := range respSvcs {
- id, err := agd.NewBlockedServiceID(s)
- if err != nil {
- reportf(ctx, errColl, "blocked service at index %d: %w", i, err)
-
- continue
- }
-
- svcs = append(svcs, id)
- }
-
- return svcs
-}
-
-// toInternal converts a protobuf protection-schedule structure to an internal
-// one. If x is nil, toInternal returns nil.
-func (x *ScheduleSettings) toInternal() (sch *agd.ParentalProtectionSchedule, err error) {
- if x == nil {
- return nil, nil
- }
-
- sch = &agd.ParentalProtectionSchedule{}
-
- sch.TimeZone, err = agdtime.LoadLocation(x.Tmz)
- if err != nil {
- return nil, fmt.Errorf("loading timezone: %w", err)
- }
-
- sch.Week = &agd.WeeklySchedule{}
-
- w := x.WeeklyRange
- days := []*DayRange{w.Sun, w.Mon, w.Tue, w.Wed, w.Thu, w.Fri, w.Sat}
- for i, d := range days {
- if d == nil {
- sch.Week[i] = agd.ZeroLengthDayRange()
-
- continue
- }
-
- sch.Week[i] = agd.DayRange{
- Start: uint16(d.Start.AsDuration().Minutes()),
- End: uint16(d.End.AsDuration().Minutes()),
- }
- }
-
- for i, r := range sch.Week {
- err = r.Validate()
- if err != nil {
- return nil, fmt.Errorf("weekday %s: %w", time.Weekday(i), err)
- }
- }
-
- return sch, nil
-}
-
-// toInternal converts a protobuf custom blocking-mode to an internal one.
-// Assumes that at least one IP address is specified in the result blocking-mode
-// object.
-func (pbm *BlockingModeCustomIP) toInternal() (m dnsmsg.BlockingMode, err error) {
- custom := &dnsmsg.BlockingModeCustomIP{}
-
- // TODO(a.garipov): Only one IPv4 address is supported on protobuf side.
- var ipv4Addr netip.Addr
- err = ipv4Addr.UnmarshalBinary(pbm.Ipv4)
- if err != nil {
- return nil, fmt.Errorf("bad custom ipv4: %w", err)
- } else if ipv4Addr.IsValid() {
- custom.IPv4 = []netip.Addr{ipv4Addr}
- }
-
- // TODO(a.garipov): Only one IPv6 address is supported on protobuf side.
- var ipv6Addr netip.Addr
- err = ipv6Addr.UnmarshalBinary(pbm.Ipv6)
- if err != nil {
- return nil, fmt.Errorf("bad custom ipv6: %w", err)
- } else if ipv6Addr.IsValid() {
- custom.IPv6 = []netip.Addr{ipv6Addr}
- }
-
- if len(custom.IPv4)+len(custom.IPv6) == 0 {
- return nil, errors.Error("no valid custom ips found")
- }
-
- return custom, nil
-}
-
-// blockingModeToInternal converts a protobuf blocking-mode sum-type to an
-// internal one. If pbm is nil, blockingModeToInternal returns a null-IP
-// blocking mode.
-func blockingModeToInternal(pbm isDNSProfile_BlockingMode) (m dnsmsg.BlockingMode, err error) {
- switch pbm := pbm.(type) {
- case nil:
- return &dnsmsg.BlockingModeNullIP{}, nil
- case *DNSProfile_BlockingModeCustomIp:
- return pbm.BlockingModeCustomIp.toInternal()
- case *DNSProfile_BlockingModeNxdomain:
- return &dnsmsg.BlockingModeNXDOMAIN{}, nil
- case *DNSProfile_BlockingModeNullIp:
- return &dnsmsg.BlockingModeNullIP{}, nil
- case *DNSProfile_BlockingModeRefused:
- return &dnsmsg.BlockingModeREFUSED{}, nil
- default:
- // Consider unhandled type-switch cases programmer errors.
- return nil, fmt.Errorf("bad pb blocking mode %T(%[1]v)", pbm)
- }
-}
-
-// devicesToInternal is a helper that converts the devices from protobuf to
-// AdGuard DNS devices.
-func devicesToInternal(
- ctx context.Context,
- ds []*DeviceSettings,
- bindSet netutil.SubnetSet,
- errColl errcoll.Interface,
-) (out []*agd.Device, ids []agd.DeviceID) {
- l := len(ds)
- if l == 0 {
- return nil, nil
- }
-
- out = make([]*agd.Device, 0, l)
- for _, d := range ds {
- dev, err := d.toInternal(bindSet)
- if err != nil {
- reportf(ctx, errColl, "invalid device settings: %w", err)
- metrics.DevicesInvalidTotal.Inc()
-
- continue
- }
-
- ids = append(ids, dev.ID)
- out = append(out, dev)
- }
-
- return out, ids
-}
-
-// toInternal is a helper that converts device settings from backend protobuf
-// response to AdGuard DNS device object.
-func (ds *DeviceSettings) toInternal(bindSet netutil.SubnetSet) (dev *agd.Device, err error) {
- if ds == nil {
- return nil, fmt.Errorf("device is nil")
- }
-
- var linkedIP netip.Addr
- err = linkedIP.UnmarshalBinary(ds.LinkedIp)
- if err != nil {
- return nil, fmt.Errorf("linked ip: %w", err)
- }
-
- var dedicatedIPs []netip.Addr
- dedicatedIPs, err = agdprotobuf.ByteSlicesToIPs(ds.DedicatedIps)
- if err != nil {
- return nil, fmt.Errorf("dedicated ips: %w", err)
- }
-
- // TODO(d.kolyshev): Extract business logic validation.
- for _, addr := range dedicatedIPs {
- if !bindSet.Contains(addr) {
- return nil, fmt.Errorf("dedicated ip %q is not in bind data", addr)
- }
- }
-
- auth, err := ds.Authentication.toInternal()
- if err != nil {
- return nil, fmt.Errorf("auth: %s: %w", ds.Id, err)
- }
-
- id, err := agd.NewDeviceID(ds.Id)
- if err != nil {
- return nil, fmt.Errorf("device id: %s: %w", ds.Id, err)
- }
-
- name, err := agd.NewDeviceName(ds.Name)
- if err != nil {
- return nil, fmt.Errorf("device name: %s: %w", ds.Name, err)
- }
-
- return &agd.Device{
- Auth: auth,
- ID: id,
- Name: name,
- LinkedIP: linkedIP,
- DedicatedIPs: dedicatedIPs,
- FilteringEnabled: ds.FilteringEnabled,
- }, nil
-}
-
-// toInternal converts a protobuf auth settings structure to an internal one.
-// If x is nil, toInternal returns non-nil settings with enabled field set to
-// false.
-func (x *AuthenticationSettings) toInternal() (s *agd.AuthSettings, err error) {
- if x == nil {
- return &agd.AuthSettings{
- Enabled: false,
- PasswordHash: agdpasswd.AllowAuthenticator{},
- }, nil
- }
-
- ph, err := dohPasswordToInternal(x.DohPasswordHash)
- if err != nil {
- return nil, fmt.Errorf("password hash: %w", err)
- }
-
- return &agd.AuthSettings{
- PasswordHash: ph,
- Enabled: true,
- DoHAuthOnly: x.DohAuthOnly,
- }, nil
-}
-
-// dohPasswordToInternal converts a protobuf DoH password hash sum-type to an
-// internal one.
-func dohPasswordToInternal(
- pbp isAuthenticationSettings_DohPasswordHash,
-) (p agdpasswd.Authenticator, err error) {
- switch pbp := pbp.(type) {
- case nil:
- return agdpasswd.AllowAuthenticator{}, nil
- case *AuthenticationSettings_PasswordHashBcrypt:
- return agdpasswd.NewPasswordHashBcrypt(pbp.PasswordHashBcrypt), nil
- default:
- return nil, fmt.Errorf("bad pb auth doh password hash %T(%[1]v)", pbp)
- }
-}
-
-// rulesToInternal is a helper that converts the filter rules from the backend
-// response to AdGuard DNS filtering rules.
-func rulesToInternal(
- ctx context.Context,
- respRules []string,
- errColl errcoll.Interface,
-) (rules []agd.FilterRuleText) {
- l := len(respRules)
- if l == 0 {
- return nil
- }
-
- rules = make([]agd.FilterRuleText, 0, l)
- for i, r := range respRules {
- text, err := agd.NewFilterRuleText(r)
- if err != nil {
- reportf(ctx, errColl, "rule at index %d: %w", i, err)
-
- continue
- }
-
- rules = append(rules, text)
- }
-
- return rules
-}
-
-// toInternal is a helper that converts the filter lists from the backend
-// response to AdGuard DNS filter list ids. If x is nil, toInternal returns
-// false and nil.
-func (x *RuleListsSettings) toInternal(
- ctx context.Context,
- errColl errcoll.Interface,
-) (enabled bool, filterLists []agd.FilterListID) {
- if x == nil {
- return false, nil
- }
-
- l := len(x.Ids)
- if l == 0 {
- return x.Enabled, nil
- }
-
- filterLists = make([]agd.FilterListID, 0, l)
- for _, f := range x.Ids {
- id, err := agd.NewFilterListID(f)
- if err != nil {
- reportf(ctx, errColl, "invalid filter id: %s: %w", f, err)
-
- continue
- }
-
- filterLists = append(filterLists, id)
- }
-
- return x.Enabled, filterLists
-}
-
// toProtobuf converts a storage request structure into the protobuf structure.
-func toProtobuf(r *profiledb.StorageRequest) (req *DNSProfilesRequest) {
+func toProtobuf(r *profiledb.StorageProfilesRequest) (req *DNSProfilesRequest) {
return &DNSProfilesRequest{
SyncTime: timestamppb.New(r.SyncTime),
}
@@ -603,7 +175,7 @@ func syncTimeFromTrailer(trailer metadata.MD) (syncTime time.Time, err error) {
syncTimeMs, err := strconv.ParseInt(st[0], 10, 64)
if err != nil {
- return syncTime, fmt.Errorf("invalid value: %w", err)
+ return syncTime, fmt.Errorf("bad value: %w", err)
}
return time.Unix(0, syncTimeMs*time.Millisecond.Nanoseconds()), nil
diff --git a/internal/backendpb/profiledb_internal_test.go b/internal/backendpb/profiledb_internal_test.go
index 055aeb6..a81b603 100644
--- a/internal/backendpb/profiledb_internal_test.go
+++ b/internal/backendpb/profiledb_internal_test.go
@@ -1,478 +1,18 @@
package backendpb
import (
- "context"
- "net/netip"
"strconv"
"testing"
"time"
- "github.com/AdguardTeam/AdGuardDNS/internal/access"
- "github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
- "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
"google.golang.org/grpc/metadata"
- "google.golang.org/protobuf/types/known/durationpb"
)
-func TestMain(m *testing.M) {
- testutil.DiscardLogOutput(m)
-}
-
-// testProfileID is the common profile ID for tests.
-const testProfileID agd.ProfileID = "prof1234"
-
-// TestUpdTime is the common update time for tests.
-var TestUpdTime = time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)
-
-// testBind includes any IPv4 address.
-var testBind = netip.MustParsePrefix("0.0.0.0/0")
-
-func TestDNSProfile_ToInternal(t *testing.T) {
- ctx := context.Background()
-
- errColl := &agdtest.ErrorCollector{
- OnCollect: func(_ context.Context, err error) {
- panic(err)
- },
- }
-
- t.Run("success", func(t *testing.T) {
- got, gotDevices, err := NewTestDNSProfile(t).toInternal(ctx, TestUpdTime, testBind, errColl)
- require.NoError(t, err)
-
- assert.Equal(t, newProfile(t), got)
- assert.Equal(t, newDevices(t), gotDevices)
- })
-
- t.Run("success_bad_data", func(t *testing.T) {
- var errCollErr error
- savingErrColl := &agdtest.ErrorCollector{
- OnCollect: func(_ context.Context, err error) {
- errCollErr = err
- },
- }
- got, gotDevices, err := newDNSProfileWithBadData(t).toInternal(
- ctx,
- TestUpdTime,
- testBind,
- savingErrColl,
- )
- require.NoError(t, err)
- testutil.AssertErrorMsg(t, "backendpb: invalid device settings:"+
- " dedicated ips: ip at index 0: unexpected slice size", errCollErr)
-
- assert.Equal(t, newProfile(t), got)
- assert.Equal(t, newDevices(t), gotDevices)
- })
-
- t.Run("invalid_device_ded_ip", func(t *testing.T) {
- var errCollErr error
- savingErrColl := &agdtest.ErrorCollector{
- OnCollect: func(_ context.Context, err error) {
- errCollErr = err
- },
- }
-
- bindSet := netip.MustParsePrefix("2.2.2.2/32")
- got, gotDevices, err := NewTestDNSProfile(t).toInternal(
- ctx,
- TestUpdTime,
- bindSet,
- savingErrColl,
- )
- require.NoError(t, err)
- testutil.AssertErrorMsg(t, "backendpb: invalid device settings:"+
- " dedicated ip \"1.1.1.2\" is not in bind data", errCollErr)
-
- assert.NotEqual(t, newProfile(t), got)
- assert.NotEqual(t, newDevices(t), gotDevices)
- assert.Len(t, gotDevices, 2)
- })
-
- t.Run("empty", func(t *testing.T) {
- var emptyDNSProfile *DNSProfile
- _, _, err := emptyDNSProfile.toInternal(ctx, TestUpdTime, testBind, errColl)
- testutil.AssertErrorMsg(t, "profile is nil", err)
- })
-
- t.Run("deleted", func(t *testing.T) {
- dp := &DNSProfile{
- DnsId: string(testProfileID),
- Deleted: true,
- }
-
- got, gotDevices, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
- require.NoError(t, err)
- require.NotNil(t, got)
-
- assert.Equal(t, got.ID, testProfileID)
- assert.True(t, got.Deleted)
- assert.Empty(t, gotDevices)
- })
-
- t.Run("inv_parental_sch_tmz", func(t *testing.T) {
- dp := NewTestDNSProfile(t)
- dp.Parental.Schedule.Tmz = "invalid"
-
- _, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
- testutil.AssertErrorMsg(t, "parental: schedule: loading timezone: unknown time zone invalid", err)
- })
-
- t.Run("inv_parental_sch_day_range", func(t *testing.T) {
- dp := NewTestDNSProfile(t)
- dp.Parental.Schedule.WeeklyRange.Sun = &DayRange{
- Start: durationpb.New(1000000000000),
- End: nil,
- }
-
- _, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
- testutil.AssertErrorMsg(t, "parental: schedule: weekday Sunday: bad day range: end 0 less than start 16", err)
- })
-
- t.Run("inv_blocking_mode_v4", func(t *testing.T) {
- dp := NewTestDNSProfile(t)
- bm := dp.BlockingMode.(*DNSProfile_BlockingModeCustomIp)
- bm.BlockingModeCustomIp.Ipv4 = []byte("1")
-
- _, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
- testutil.AssertErrorMsg(t, "blocking mode: bad custom ipv4: unexpected slice size", err)
- })
-
- t.Run("inv_blocking_mode_v6", func(t *testing.T) {
- dp := NewTestDNSProfile(t)
- bm := dp.BlockingMode.(*DNSProfile_BlockingModeCustomIp)
- bm.BlockingModeCustomIp.Ipv6 = []byte("1")
-
- _, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
- testutil.AssertErrorMsg(t, "blocking mode: bad custom ipv6: unexpected slice size", err)
- })
-
- t.Run("nil_ips_blocking_mode", func(t *testing.T) {
- dp := NewTestDNSProfile(t)
- bm := dp.BlockingMode.(*DNSProfile_BlockingModeCustomIp)
- bm.BlockingModeCustomIp.Ipv4 = nil
- bm.BlockingModeCustomIp.Ipv6 = nil
-
- _, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
- testutil.AssertErrorMsg(t, "blocking mode: no valid custom ips found", err)
- })
-
- t.Run("nil_blocking_mode", func(t *testing.T) {
- dp := NewTestDNSProfile(t)
- dp.BlockingMode = nil
-
- got, gotDevices, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
- require.NoError(t, err)
- require.NotNil(t, got)
-
- wantProf := newProfile(t)
- wantProf.BlockingMode = &dnsmsg.BlockingModeNullIP{}
-
- assert.Equal(t, wantProf, got)
- assert.Equal(t, newDevices(t), gotDevices)
- })
-
- t.Run("nil_access", func(t *testing.T) {
- dp := NewTestDNSProfile(t)
- dp.Access = nil
-
- got, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
- require.NoError(t, err)
- require.NotNil(t, got)
-
- assert.Equal(t, got.ID, testProfileID)
- assert.IsType(t, access.EmptyProfile{}, got.Access)
- })
-
- t.Run("access_disabled", func(t *testing.T) {
- dp := NewTestDNSProfile(t)
- dp.Access = &AccessSettings{
- Enabled: false,
- }
-
- got, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
- require.NoError(t, err)
- require.NotNil(t, got)
-
- assert.Equal(t, got.ID, testProfileID)
- assert.IsType(t, access.EmptyProfile{}, got.Access)
- })
-}
-
-// newDNSProfileWithBadData returns a new instance of *DNSProfile with bad
-// devices data for tests.
-func newDNSProfileWithBadData(tb testing.TB) (dp *DNSProfile) {
- tb.Helper()
-
- invalidDevices := []*DeviceSettings{{
- Id: "invalid-too-long-device-id",
- Name: "device_name",
- FilteringEnabled: true,
- LinkedIp: ipToBytes(tb, netip.MustParseAddr("1.1.1.1")),
- DedicatedIps: nil,
- }, {
- Id: "dev-name",
- Name: "invalid-too-long-device-name-invalid-too-long-device-name-" +
- "invalid-too-long-device-name-invalid-too-long-device-name-" +
- "invalid-too-long-device-name-invalid-too-long-device-name",
- FilteringEnabled: true,
- LinkedIp: ipToBytes(tb, netip.MustParseAddr("1.1.1.1")),
- DedicatedIps: nil,
- }, {
- Id: "inv-ip",
- Name: "test-name",
- FilteringEnabled: true,
- LinkedIp: []byte("1"),
- DedicatedIps: nil,
- }, {
- Id: "inv-d-ip",
- Name: "test-name",
- FilteringEnabled: true,
- LinkedIp: ipToBytes(tb, netip.MustParseAddr("1.1.1.1")),
- DedicatedIps: [][]byte{[]byte("1")},
- }}
-
- dp = NewTestDNSProfile(tb)
- dp.Devices = append(dp.Devices, invalidDevices...)
-
- return dp
-}
-
-// NewTestDNSProfile returns a new instance of *DNSProfile for tests.
-func NewTestDNSProfile(tb testing.TB) (dp *DNSProfile) {
- tb.Helper()
-
- dayRange := &DayRange{
- Start: durationpb.New(0),
- End: durationpb.New(59 * time.Minute),
- }
-
- devices := []*DeviceSettings{{
- Id: "1111aaaa",
- Name: "1111aaaa-name",
- FilteringEnabled: false,
- LinkedIp: ipToBytes(tb, netip.MustParseAddr("1.1.1.1")),
- DedicatedIps: [][]byte{ipToBytes(tb, netip.MustParseAddr("1.1.1.2"))},
- }, {
- Id: "2222bbbb",
- Name: "2222bbbb-name",
- FilteringEnabled: true,
- LinkedIp: ipToBytes(tb, netip.MustParseAddr("2.2.2.2")),
- DedicatedIps: nil,
- Authentication: &AuthenticationSettings{
- DohAuthOnly: true,
- DohPasswordHash: &AuthenticationSettings_PasswordHashBcrypt{
- PasswordHashBcrypt: []byte("test-hash"),
- },
- },
- }, {
- Id: "3333cccc",
- Name: "3333cccc-name",
- FilteringEnabled: false,
- LinkedIp: ipToBytes(tb, netip.MustParseAddr("3.3.3.3")),
- DedicatedIps: nil,
- Authentication: &AuthenticationSettings{
- DohAuthOnly: false,
- DohPasswordHash: nil,
- },
- }}
-
- return &DNSProfile{
- DnsId: string(testProfileID),
- FilteringEnabled: true,
- QueryLogEnabled: true,
- Deleted: false,
- SafeBrowsing: &SafeBrowsingSettings{
- Enabled: true,
- BlockDangerousDomains: true,
- BlockNrd: false,
- },
- Parental: &ParentalSettings{
- Enabled: false,
- BlockAdult: false,
- GeneralSafeSearch: false,
- YoutubeSafeSearch: false,
- BlockedServices: []string{"youtube"},
- Schedule: &ScheduleSettings{
- Tmz: "GMT",
- WeeklyRange: &WeeklyRange{
- Sun: nil,
- Mon: dayRange,
- Tue: dayRange,
- Wed: dayRange,
- Thu: dayRange,
- Fri: dayRange,
- Sat: nil,
- },
- },
- },
- RuleLists: &RuleListsSettings{
- Enabled: true,
- Ids: []string{"1"},
- },
- Devices: devices,
- CustomRules: []string{"||example.org^"},
- FilteredResponseTtl: durationpb.New(10 * time.Second),
- BlockPrivateRelay: true,
- BlockFirefoxCanary: true,
- IpLogEnabled: true,
- BlockingMode: &DNSProfile_BlockingModeCustomIp{
- BlockingModeCustomIp: &BlockingModeCustomIP{
- Ipv4: ipToBytes(tb, netip.MustParseAddr("1.2.3.4")),
- Ipv6: ipToBytes(tb, netip.MustParseAddr("1234::cdef")),
- },
- },
- Access: &AccessSettings{
- AllowlistCidr: []*CidrRange{{
- Address: netip.MustParseAddr("1.1.1.0").AsSlice(),
- Prefix: 24,
- }},
- BlocklistCidr: []*CidrRange{{
- Address: netip.MustParseAddr("2.2.2.0").AsSlice(),
- Prefix: 24,
- }},
- AllowlistAsn: []uint32{1},
- BlocklistAsn: []uint32{2},
- BlocklistDomainRules: []string{"block.test"},
- Enabled: true,
- },
- }
-}
-
-// newProfile returns a new profile for tests.
-func newProfile(tb testing.TB) (p *agd.Profile) {
- tb.Helper()
-
- wantLoc, err := agdtime.LoadLocation("GMT")
- require.NoError(tb, err)
-
- dayRange := agd.DayRange{
- Start: 0,
- End: 59,
- }
-
- wantParental := &agd.ParentalProtectionSettings{
- Schedule: &agd.ParentalProtectionSchedule{
- Week: &agd.WeeklySchedule{
- agd.ZeroLengthDayRange(),
- dayRange,
- dayRange,
- dayRange,
- dayRange,
- dayRange,
- agd.ZeroLengthDayRange(),
- },
- TimeZone: wantLoc,
- },
- BlockedServices: []agd.BlockedServiceID{"youtube"},
- Enabled: false,
- BlockAdult: false,
- GeneralSafeSearch: false,
- YoutubeSafeSearch: false,
- }
-
- wantSafeBrowsing := &agd.SafeBrowsingSettings{
- Enabled: true,
- BlockDangerousDomains: true,
- BlockNewlyRegisteredDomains: false,
- }
-
- wantBlockingMode := &dnsmsg.BlockingModeCustomIP{
- IPv4: []netip.Addr{netip.MustParseAddr("1.2.3.4")},
- IPv6: []netip.Addr{netip.MustParseAddr("1234::cdef")},
- }
-
- wantAccess := access.NewDefaultProfile(&access.ProfileConfig{
- AllowedNets: []netip.Prefix{netip.MustParsePrefix("1.1.1.0/24")},
- BlockedNets: []netip.Prefix{netip.MustParsePrefix("2.2.2.0/24")},
- AllowedASN: []geoip.ASN{1},
- BlockedASN: []geoip.ASN{2},
- BlocklistDomainRules: []string{"block.test"},
- })
-
- return &agd.Profile{
- Parental: wantParental,
- BlockingMode: wantBlockingMode,
- ID: testProfileID,
- UpdateTime: TestUpdTime,
- DeviceIDs: []agd.DeviceID{
- "1111aaaa",
- "2222bbbb",
- "3333cccc",
- },
- RuleListIDs: []agd.FilterListID{"1"},
- CustomRules: []agd.FilterRuleText{"||example.org^"},
- FilteredResponseTTL: 10 * time.Second,
- SafeBrowsing: wantSafeBrowsing,
- Access: wantAccess,
- RuleListsEnabled: true,
- FilteringEnabled: true,
- QueryLogEnabled: true,
- Deleted: false,
- BlockPrivateRelay: true,
- BlockFirefoxCanary: true,
- IPLogEnabled: true,
- }
-}
-
-// newDevices returns a slice of test devices.
-func newDevices(t *testing.T) (d []*agd.Device) {
- t.Helper()
-
- return []*agd.Device{{
- Auth: &agd.AuthSettings{
- Enabled: false,
- DoHAuthOnly: false,
- PasswordHash: agdpasswd.AllowAuthenticator{},
- },
- ID: "1111aaaa",
- LinkedIP: netip.MustParseAddr("1.1.1.1"),
- Name: "1111aaaa-name",
- DedicatedIPs: []netip.Addr{netip.MustParseAddr("1.1.1.2")},
- FilteringEnabled: false,
- }, {
- Auth: &agd.AuthSettings{
- Enabled: true,
- DoHAuthOnly: true,
- PasswordHash: agdpasswd.NewPasswordHashBcrypt([]byte("test-hash")),
- },
- ID: "2222bbbb",
- LinkedIP: netip.MustParseAddr("2.2.2.2"),
- Name: "2222bbbb-name",
- DedicatedIPs: nil,
- FilteringEnabled: true,
- }, {
- Auth: &agd.AuthSettings{
- Enabled: true,
- DoHAuthOnly: false,
- PasswordHash: agdpasswd.AllowAuthenticator{},
- },
- ID: "3333cccc",
- LinkedIP: netip.MustParseAddr("3.3.3.3"),
- Name: "3333cccc-name",
- DedicatedIPs: nil,
- FilteringEnabled: false,
- }}
-}
-
-// ipToBytes is a wrapper around netip.Addr.MarshalBinary.
-func ipToBytes(tb testing.TB, ip netip.Addr) (b []byte) {
- tb.Helper()
-
- b, err := ip.MarshalBinary()
- require.NoError(tb, err)
-
- return b
-}
-
func TestSyncTimeFromTrailer(t *testing.T) {
+ t.Parallel()
+
milliseconds := strconv.FormatInt(TestUpdTime.UnixMilli(), 10)
testCases := []struct {
@@ -492,7 +32,7 @@ func TestSyncTimeFromTrailer(t *testing.T) {
name: "empty_key",
}, {
in: metadata.MD{"sync_time": []string{""}},
- wantError: `invalid value: strconv.ParseInt: parsing "": invalid syntax`,
+ wantError: `bad value: strconv.ParseInt: parsing "": invalid syntax`,
want: time.Time{},
name: "empty_value",
}, {
@@ -510,36 +50,3 @@ func TestSyncTimeFromTrailer(t *testing.T) {
})
}
}
-
-var (
- errSink error
- profSink *agd.Profile
-)
-
-func BenchmarkDNSProfile_ToInternal(b *testing.B) {
- dp := NewTestDNSProfile(b)
- ctx := context.Background()
-
- errColl := &agdtest.ErrorCollector{
- OnCollect: func(_ context.Context, err error) {
- panic(err)
- },
- }
-
- b.ReportAllocs()
- b.ResetTimer()
- for range b.N {
- profSink, _, errSink = dp.toInternal(ctx, TestUpdTime, testBind, errColl)
- }
-
- require.NotNil(b, profSink)
- require.NoError(b, errSink)
-
- // Most recent result, on a ThinkPad X13:
- // goos: linux
- // goarch: amd64
- // pkg: github.com/AdguardTeam/AdGuardDNS/internal/backendpb
- // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
- // BenchmarkDNSProfile_ToInternal
- // BenchmarkDNSProfile_ToInternal-16 157513 10340 ns/op 1148 B/op 27 allocs/op
-}
diff --git a/internal/backendpb/profiledb_test.go b/internal/backendpb/profiledb_test.go
index dee6ee6..d11caa6 100644
--- a/internal/backendpb/profiledb_test.go
+++ b/internal/backendpb/profiledb_test.go
@@ -9,19 +9,117 @@ import (
"testing"
"time"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
"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"
"google.golang.org/grpc/metadata"
)
+func TestProfileStorage_CreateAutoDevice(t *testing.T) {
+ t.Parallel()
+
+ const devType = agd.DeviceTypeOther
+
+ gotReqCh := make(chan *backendpb.CreateDeviceRequest, 1)
+
+ srv := &testDNSServiceServer{
+ OnCreateDeviceByHumanId: func(
+ ctx context.Context,
+ req *backendpb.CreateDeviceRequest,
+ ) (resp *backendpb.CreateDeviceResponse, err error) {
+ defer func() {
+ pt := testutil.PanicT{}
+ testutil.RequireSend(pt, gotReqCh, req, testTimeout)
+ }()
+
+ return &backendpb.CreateDeviceResponse{
+ Device: &backendpb.DeviceSettings{
+ Id: backendpb.TestDeviceIDStr,
+ HumanIdLower: backendpb.TestHumanIDLowerStr,
+ },
+ }, nil
+ },
+
+ OnGetDNSProfiles: func(
+ req *backendpb.DNSProfilesRequest,
+ srv backendpb.DNSService_GetDNSProfilesServer,
+ ) (err error) {
+ panic("not implemented")
+ },
+
+ OnSaveDevicesBillingStat: func(
+ srv backendpb.DNSService_SaveDevicesBillingStatServer,
+ ) (err error) {
+ panic("not implemented")
+ },
+ }
+
+ errColl := &agdtest.ErrorCollector{
+ OnCollect: func(_ context.Context, err error) {
+ panic(err)
+ },
+ }
+
+ l, err := net.Listen("tcp", "localhost:0")
+ require.NoError(t, err)
+
+ s, err := backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
+ BindSet: backendpb.TestBind,
+ ErrColl: errColl,
+ Endpoint: &url.URL{
+ Scheme: "grpc",
+ Host: l.Addr().String(),
+ },
+ })
+ require.NoError(t, err)
+
+ grpcSrv := grpc.NewServer(
+ grpc.ConnectionTimeout(1*time.Second),
+ grpc.Creds(insecure.NewCredentials()),
+ )
+ backendpb.RegisterDNSServiceServer(grpcSrv, srv)
+
+ go func() {
+ pt := &testutil.PanicT{}
+
+ srvErr := grpcSrv.Serve(l)
+ require.NoError(pt, srvErr)
+ }()
+ t.Cleanup(grpcSrv.GracefulStop)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+
+ resp, err := s.CreateAutoDevice(ctx, &profiledb.StorageCreateAutoDeviceRequest{
+ ProfileID: backendpb.TestProfileID,
+ HumanID: backendpb.TestHumanID,
+ DeviceType: devType,
+ })
+ assert.NoError(t, err)
+
+ gotReq, ok := testutil.RequireReceive(t, gotReqCh, testTimeout)
+ require.True(t, ok)
+ require.NotNil(t, gotReq)
+
+ assert.Equal(t, backendpb.TestProfileIDStr, gotReq.DnsId)
+ assert.Equal(t, backendpb.TestHumanIDStr, gotReq.HumanId)
+ assert.Equal(t, backendpb.DeviceType(devType), gotReq.DeviceType)
+
+ require.NotNil(t, resp)
+ require.NotNil(t, resp.Device)
+
+ assert.Equal(t, backendpb.TestDeviceID, resp.Device.ID)
+ assert.Equal(t, backendpb.TestHumanIDLower, resp.Device.HumanIDLower)
+}
+
var (
errSink error
- respSink *profiledb.StorageResponse
+ respSink *profiledb.StorageProfilesResponse
)
func BenchmarkProfileStorage_Profiles(b *testing.B) {
@@ -32,6 +130,13 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
}
srv := &testDNSServiceServer{
+ OnCreateDeviceByHumanId: func(
+ ctx context.Context,
+ req *backendpb.CreateDeviceRequest,
+ ) (resp *backendpb.CreateDeviceResponse, err error) {
+ panic("not implemented")
+ },
+
OnGetDNSProfiles: func(
req *backendpb.DNSProfilesRequest,
srv backendpb.DNSService_GetDNSProfilesServer,
@@ -41,6 +146,12 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
return sendErr
},
+
+ OnSaveDevicesBillingStat: func(
+ srv backendpb.DNSService_SaveDevicesBillingStatServer,
+ ) (err error) {
+ panic("not implemented")
+ },
}
errColl := &agdtest.ErrorCollector{
@@ -77,7 +188,7 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
b.Cleanup(grpcSrv.GracefulStop)
ctx := context.Background()
- req := &profiledb.StorageRequest{}
+ req := &profiledb.StorageProfilesRequest{}
b.ReportAllocs()
b.ResetTimer()
@@ -94,5 +205,5 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/backendpb
// cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
// BenchmarkProfileStorage_Profiles
- // BenchmarkProfileStorage_Profiles-16 5347 245341 ns/op 15129 B/op 265 allocs/op
+ // BenchmarkProfileStorage_Profiles-16 4128 291646 ns/op 18578 B/op 341 allocs/op
}
diff --git a/internal/cmd/backend.go b/internal/cmd/backend.go
index 15bf237..340a60b 100644
--- a/internal/cmd/backend.go
+++ b/internal/cmd/backend.go
@@ -4,7 +4,7 @@ import (
"context"
"fmt"
"net/netip"
- "net/url"
+ "time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
@@ -12,6 +12,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/billstat"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/service"
@@ -103,8 +104,7 @@ func setupBillStat(
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (rec *billstat.RuntimeRecorder, err error) {
- apiURL := netutil.CloneURL(&envs.BillStatURL.URL)
- billStatUploader, err := setupBillStatUploader(apiURL, errColl)
+ billStatUploader, err := setupBillStatUploader(envs, errColl)
if err != nil {
return nil, fmt.Errorf("creating bill stat uploader: %w", err)
}
@@ -146,9 +146,8 @@ func setupProfDB(
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (profDB *profiledb.Default, err error) {
- apiURL := netutil.CloneURL(&envs.ProfilesURL.URL)
bindSet := collectBindSubnetSet(grps)
- profStrg, err := setupProfStorage(apiURL, bindSet, errColl)
+ profStrg, err := setupProfStorage(envs, bindSet, errColl)
if err != nil {
return nil, fmt.Errorf("creating profile storage: %w", err)
}
@@ -159,14 +158,16 @@ func setupProfDB(
ErrColl: errColl,
FullSyncIvl: conf.FullRefreshIvl.Duration,
FullSyncRetryIvl: conf.FullRefreshRetryIvl.Duration,
- InitialTimeout: timeout,
CacheFilePath: envs.ProfilesCachePath,
})
if err != nil {
return nil, fmt.Errorf("creating default profile database: %w", err)
}
- refrIvl := conf.RefreshIvl.Duration
+ err = initProfDB(profDB, timeout)
+ if err != nil {
+ return nil, fmt.Errorf("preparing default profile database: %w", err)
+ }
profDBRefr := agdservice.NewRefreshWorker(&agdservice.RefreshWorkerConfig{
Context: func() (ctx context.Context, cancel context.CancelFunc) {
@@ -174,7 +175,7 @@ func setupProfDB(
},
Refresher: profDB,
Name: "profiledb",
- Interval: refrIvl,
+ Interval: conf.RefreshIvl.Duration,
RefreshOnShutdown: false,
RandomizeStart: true,
})
@@ -188,6 +189,27 @@ func setupProfDB(
return profDB, nil
}
+// initProfDB refreshes the profile database initially. It logs an error if
+// it's a timeout, and returns it otherwise.
+func initProfDB(profDB *profiledb.Default, timeout time.Duration) (err error) {
+ ctx, cancel := context.WithTimeout(context.Background(), timeout)
+ defer cancel()
+
+ log.Info("main: initial profiledb refresh")
+
+ err = profDB.Refresh(ctx)
+ switch {
+ case err == nil:
+ log.Info("main: initial profiledb refresh succeeded")
+ case errors.Is(err, context.DeadlineExceeded):
+ log.Info("main: warning: initial profiledb refresh timeout: %s", err)
+ default:
+ return fmt.Errorf("initial refresh: %w", err)
+ }
+
+ return nil
+}
+
// collectBindSubnetSet returns a subnet set with IP addresses of servers in the
// provided server groups grps.
func collectBindSubnetSet(grps []*agd.ServerGroup) (s netutil.SubnetSet) {
@@ -223,36 +245,40 @@ const (
schemeGRPCS = "grpcs"
)
-// setupProfStorage creates and returns a profile storage depending on the
-// provided API URL.
-func setupProfStorage(
- apiURL *url.URL,
- bindSet netutil.SubnetSet,
- errColl errcoll.Interface,
-) (s profiledb.Storage, err error) {
- scheme := apiURL.Scheme
- if scheme == schemeGRPC || scheme == schemeGRPCS {
- return backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
- BindSet: bindSet,
- Endpoint: apiURL,
- ErrColl: errColl,
- })
- }
-
- return nil, fmt.Errorf("invalid backend api url: %s", apiURL)
-}
-
// setupBillStatUploader creates and returns a billstat uploader depending on
// the provided API URL.
func setupBillStatUploader(
- apiURL *url.URL,
+ envs *environments,
errColl errcoll.Interface,
) (s billstat.Uploader, err error) {
+ apiURL := netutil.CloneURL(&envs.BillStatURL.URL)
scheme := apiURL.Scheme
if scheme == schemeGRPC || scheme == schemeGRPCS {
return backendpb.NewBillStat(&backendpb.BillStatConfig{
ErrColl: errColl,
Endpoint: apiURL,
+ APIKey: envs.BillStatAPIKey,
+ })
+ }
+
+ return nil, fmt.Errorf("invalid backend api url: %s", apiURL)
+}
+
+// setupProfStorage creates and returns a profile storage depending on the
+// provided API URL.
+func setupProfStorage(
+ envs *environments,
+ bindSet netutil.SubnetSet,
+ errColl errcoll.Interface,
+) (s profiledb.Storage, err error) {
+ apiURL := netutil.CloneURL(&envs.ProfilesURL.URL)
+ scheme := apiURL.Scheme
+ if scheme == schemeGRPC || scheme == schemeGRPCS {
+ return backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
+ BindSet: bindSet,
+ ErrColl: errColl,
+ Endpoint: apiURL,
+ APIKey: envs.ProfilesAPIKey,
})
}
diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go
index 6ceb317..6cb381e 100644
--- a/internal/cmd/cmd.go
+++ b/internal/cmd/cmd.go
@@ -10,6 +10,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/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/debugsvc"
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
@@ -36,6 +37,9 @@ func Main() {
agd.InitRequestID()
+ // TODO(a.garipov, e.burkov): Consider adding timeouts for initialization.
+ ctx := context.Background()
+
// Log only to stdout and let users decide how to process it.
log.SetOutput(os.Stdout)
@@ -58,6 +62,10 @@ func Main() {
defer collectPanics(errColl)
+ // Cache manager
+
+ cacheManager := agdcache.NewDefaultManager()
+
// Configuration file
c, err := readConfig(envs.ConfPath)
@@ -86,7 +94,7 @@ func Main() {
geoIP, geoIPRefr := &geoip.File{}, &agdservice.RefreshWorker{}
geoIPErrCh := make(chan error, 1)
- go setupGeoIP(geoIP, geoIPRefr, geoIPErrCh, c.GeoIP, envs, errColl)
+ go setupGeoIP(geoIP, geoIPRefr, geoIPErrCh, c.GeoIP, envs, errColl, cacheManager)
// Safe-browsing and adult-blocking filters
@@ -98,55 +106,57 @@ func Main() {
maxFilterSize := c.Filters.MaxSize.Bytes()
cloner := dnsmsg.NewCloner(metrics.ClonerStat{})
- safeBrowsingHashes, safeBrowsingFilter, err := setupHashPrefixFilter(
- c.SafeBrowsing,
+
+ sbConf := c.SafeBrowsing.toInternal(
+ errColl,
cloner,
+ cacheManager,
agd.FilterListIDSafeBrowsing,
envs.SafeBrowsingURL,
envs.FilterCachePath,
maxFilterSize,
- sigHdlr,
- errColl,
)
+ sbHashes, sbFilter, err := setupHashPrefixFilter(ctx, sbConf, sigHdlr)
check(err)
- adultBlockingHashes, adultBlockingFilter, err := setupHashPrefixFilter(
- c.AdultBlocking,
+ abConf := c.AdultBlocking.toInternal(
+ errColl,
cloner,
+ cacheManager,
agd.FilterListIDAdultBlocking,
envs.AdultBlockingURL,
envs.FilterCachePath,
maxFilterSize,
- sigHdlr,
- errColl,
)
+ abHashes, abFilter, err := setupHashPrefixFilter(ctx, abConf, sigHdlr)
check(err)
- _, newRegDomainsFilter, err := setupHashPrefixFilter(
- // Reuse general safe browsing filter configuration.
- c.SafeBrowsing,
+ // Reuse general safe browsing filter configuration.
+ nrdConf := c.SafeBrowsing.toInternal(
+ errColl,
cloner,
+ cacheManager,
agd.FilterListIDNewRegDomains,
envs.NewRegDomainsURL,
envs.FilterCachePath,
maxFilterSize,
- sigHdlr,
- errColl,
)
+ _, nrdFilter, err := setupHashPrefixFilter(ctx, nrdConf, sigHdlr)
check(err)
// Filter storage and filtering groups
fltStrgConf := c.Filters.toInternal(
errColl,
+ cacheManager,
envs,
- safeBrowsingFilter,
- adultBlockingFilter,
- newRegDomainsFilter,
+ sbFilter,
+ abFilter,
+ nrdFilter,
)
fltRefrTimeout := c.Filters.RefreshTimeout.Duration
- fltStrg, err := setupFilterStorage(fltStrgConf, sigHdlr, fltRefrTimeout)
+ fltStrg, err := setupFilterStorage(ctx, fltStrgConf, sigHdlr, fltRefrTimeout)
check(err)
fltGroups, err := c.FilteringGroups.toInternal(fltStrg)
@@ -176,8 +186,6 @@ func Main() {
srvGrps, err := c.ServerGroups.toInternal(messages, btdMgr, fltGroups, c.RateLimit, c.DNS)
check(err)
- ctx := context.Background()
-
// Start the bind-to-device manager here, now that no further calls to
// btdMgr.ListenConfig are required.
err = btdMgr.Start(ctx)
@@ -220,7 +228,13 @@ func Main() {
// Rate limiting
consulAllowlistURL := &envs.ConsulAllowlistURL.URL
- rateLimiter, connLimiter, err := setupRateLimiter(c.RateLimit, consulAllowlistURL, sigHdlr, errColl)
+ rateLimiter, connLimiter, err := setupRateLimiter(
+ ctx,
+ c.RateLimit,
+ consulAllowlistURL,
+ sigHdlr,
+ errColl,
+ )
check(err)
// GeoIP database
@@ -251,15 +265,17 @@ func Main() {
// TODO(a.garipov): Consider making these configurable via the configuration
// file.
hashStorages := map[string]*hashprefix.Storage{
- filter.GeneralTXTSuffix: safeBrowsingHashes,
- filter.AdultBlockingTXTSuffix: adultBlockingHashes,
+ filter.GeneralTXTSuffix: sbHashes,
+ filter.AdultBlockingTXTSuffix: abHashes,
}
dnsConf := &dnssvc.Config{
Messages: messages,
Cloner: cloner,
+ CacheManager: cacheManager,
ControlConf: ctrlConf,
ConnLimiter: connLimiter,
+ HumanIDParser: agd.NewHumanIDParser(),
AccessManager: accessGlobal,
SafeBrowsing: hashprefix.NewMatcher(hashStorages),
BillStat: billStatRec,
@@ -307,7 +323,15 @@ func Main() {
// Debug HTTP-service
- debugSvc := debugsvc.New(envs.debugConf(dnsDB))
+ debugSvcConf := envs.debugConf(dnsDB)
+ debugSvcConf.Logger = slogLogger.With(slogutil.KeyPrefix, "debugsvc")
+ debugSvcConf.Refreshers = debugsvc.Refreshers{
+ "filter_storage": fltStrg,
+ string(agd.FilterListIDSafeBrowsing): sbFilter,
+ string(agd.FilterListIDAdultBlocking): abFilter,
+ string(agd.FilterListIDNewRegDomains): nrdFilter,
+ }
+ debugSvc := debugsvc.New(debugSvcConf)
// The debug HTTP service is considered critical, so its Start method panics
// instead of returning an error.
@@ -324,6 +348,9 @@ func Main() {
runtime.Version(),
)
+ // TODO(s.chzhen): Remove it.
+ log.Debug("cache manager ids: %q", cacheManager.IDs())
+
os.Exit(sigHdlr.Handle(ctx))
}
diff --git a/internal/cmd/env.go b/internal/cmd/env.go
index f5abc0e..442f15c 100644
--- a/internal/cmd/env.go
+++ b/internal/cmd/env.go
@@ -10,6 +10,7 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/debugsvc"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
@@ -25,8 +26,6 @@ import (
"github.com/getsentry/sentry-go"
)
-// Environment configuration
-
// environments represents the configuration that is kept in the environment.
type environments struct {
AdultBlockingURL *urlutil.URL `env:"ADULT_BLOCKING_URL,notEmpty"`
@@ -44,14 +43,16 @@ type environments struct {
SafeBrowsingURL *urlutil.URL `env:"SAFE_BROWSING_URL,notEmpty"`
YoutubeSafeSearchURL *urlutil.URL `env:"YOUTUBE_SAFE_SEARCH_URL,notEmpty"`
+ BillStatAPIKey string `env:"BILLSTAT_API_KEY"`
ConfPath string `env:"CONFIG_PATH" envDefault:"./config.yaml"`
FilterCachePath string `env:"FILTER_CACHE_PATH" envDefault:"./filters/"`
- ProfilesCachePath string `env:"PROFILES_CACHE_PATH" envDefault:"./profilecache.pb"`
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"`
QueryLogPath string `env:"QUERYLOG_PATH" envDefault:"./querylog.jsonl"`
- SentryDSN string `env:"SENTRY_DSN" envDefault:"stderr"`
SSLKeyLogFile string `env:"SSL_KEY_LOG_FILE"`
+ SentryDSN string `env:"SENTRY_DSN" envDefault:"stderr"`
ListenAddr net.IP `env:"LISTEN_ADDR" envDefault:"127.0.0.1"`
@@ -115,10 +116,15 @@ func (envs *environments) buildErrColl() (errColl errcoll.Interface, err error)
}
// geoIP returns an GeoIP database implementation from environment.
-func (envs *environments) geoIP(c *geoIPConfig) (g *geoip.File, err error) {
+func (envs *environments) geoIP(
+ ctx context.Context,
+ c *geoIPConfig,
+ cacheManager agdcache.Manager,
+) (g *geoip.File, err error) {
log.Debug("using geoip files %q and %q", envs.GeoIPASNPath, envs.GeoIPCountryPath)
- g, err = geoip.NewFile(&geoip.FileConfig{
+ g = geoip.NewFile(&geoip.FileConfig{
+ CacheManager: cacheManager,
ASNPath: envs.GeoIPASNPath,
CountryPath: envs.GeoIPCountryPath,
HostCacheSize: c.HostCacheSize,
@@ -126,8 +132,10 @@ func (envs *environments) geoIP(c *geoIPConfig) (g *geoip.File, err error) {
AllTopASNs: geoip.DefaultTopASNs,
CountryTopASNs: geoip.DefaultCountryTopASNs,
})
+
+ err = g.Refresh(ctx)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("creating geoip: initial refresh: %w", err)
}
return g, nil
@@ -155,7 +163,7 @@ func (envs *environments) debugConf(dnsDB dnsdb.Interface) (conf *debugsvc.Confi
DNSDBAddr: dnsDBAddr,
DNSDBHandler: dnsDBHdlr,
- HealthAddr: addr,
+ APIAddr: addr,
PprofAddr: addr,
PrometheusAddr: addr,
}
diff --git a/internal/cmd/filter.go b/internal/cmd/filter.go
index bff86c4..f78491e 100644
--- a/internal/cmd/filter.go
+++ b/internal/cmd/filter.go
@@ -5,6 +5,7 @@ import (
"fmt"
"time"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
@@ -63,6 +64,7 @@ type filtersConfig struct {
// cacheDir must exist. c is assumed to be valid.
func (c *filtersConfig) toInternal(
errColl errcoll.Interface,
+ cacheManager agdcache.Manager,
envs *environments,
safeBrowsing *hashprefix.Filter,
adultBlocking *hashprefix.Filter,
@@ -78,6 +80,7 @@ func (c *filtersConfig) toInternal(
NewRegDomains: newRegDomains,
Now: time.Now,
ErrColl: errColl,
+ CacheManager: cacheManager,
CacheDir: envs.FilterCachePath,
CustomFilterCacheSize: c.CustomFilterCacheSize,
SafeSearchCacheSize: c.SafeSearchCacheSize,
@@ -148,11 +151,14 @@ func (c *fltRuleListCache) validate() (err error) {
// setupFilterStorage creates and returns a filter storage as well as starts and
// registers its refresher in the signal handler.
func setupFilterStorage(
+ ctx context.Context,
conf *filter.DefaultStorageConfig,
sigHdlr *service.SignalHandler,
refreshTimeout time.Duration,
) (strg *filter.DefaultStorage, err error) {
- strg, err = filter.NewDefaultStorage(conf)
+ strg = filter.NewDefaultStorage(conf)
+
+ err = strg.RefreshInitial(ctx)
if err != nil {
return nil, fmt.Errorf("creating default filter storage: %w", err)
}
@@ -162,12 +168,12 @@ func setupFilterStorage(
return context.WithTimeout(context.Background(), refreshTimeout)
},
Refresher: strg,
- Name: "filters",
+ Name: "filter_storage",
Interval: conf.RefreshIvl,
RefreshOnShutdown: false,
RandomizeStart: false,
})
- err = refr.Start(context.Background())
+ err = refr.Start(ctx)
if err != nil {
return nil, fmt.Errorf("starting default filter storage update: %w", err)
}
diff --git a/internal/cmd/geoip.go b/internal/cmd/geoip.go
index 835151f..498c4ce 100644
--- a/internal/cmd/geoip.go
+++ b/internal/cmd/geoip.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
@@ -55,8 +56,12 @@ func setupGeoIP(
conf *geoIPConfig,
envs *environments,
errColl errcoll.Interface,
+ cacheManager agdcache.Manager,
) {
- geoIP, err := envs.geoIP(conf)
+ // TODO(e.burkov): Pass the context through arguments.
+ ctx := context.Background()
+
+ geoIP, err := envs.geoIP(ctx, conf, cacheManager)
if err != nil {
errCh <- fmt.Errorf("creating geoip: %w", err)
@@ -78,7 +83,7 @@ func setupGeoIP(
RefreshOnShutdown: false,
RandomizeStart: false,
})
- err = refr.Start(context.Background())
+ err = refr.Start(ctx)
if err != nil {
errCh <- fmt.Errorf("starting geoip refresher: %w", err)
diff --git a/internal/cmd/ratelimit.go b/internal/cmd/ratelimit.go
index 715888a..723fd1e 100644
--- a/internal/cmd/ratelimit.go
+++ b/internal/cmd/ratelimit.go
@@ -138,6 +138,7 @@ func (c *rateLimitConfig) validate() (err error) {
// setupRateLimiter creates and returns a backoff rate limiter as well as starts
// and registers its refresher in the signal handler.
func setupRateLimiter(
+ ctx context.Context,
conf *rateLimitConfig,
consulAllowlist *url.URL,
sigHdlr *service.SignalHandler,
@@ -145,9 +146,11 @@ func setupRateLimiter(
) (rateLimiter *ratelimit.Backoff, connLimiter *connlimiter.Limiter, err error) {
allowSubnets := netutil.UnembedPrefixes(conf.Allowlist.List)
allowlist := ratelimit.NewDynamicAllowlist(allowSubnets, nil)
- refresher, err := consul.NewAllowlistRefresher(allowlist, consulAllowlist, errColl)
+ refresher := consul.NewAllowlistRefresher(allowlist, consulAllowlist, errColl)
+
+ err = refresher.Refresh(ctx)
if err != nil {
- return nil, nil, fmt.Errorf("creating allowlist refresher: %w", err)
+ return nil, nil, fmt.Errorf("allowlist: initial refresh: %w", err)
}
refr := agdservice.NewRefreshWorker(&agdservice.RefreshWorkerConfig{
@@ -159,7 +162,7 @@ func setupRateLimiter(
RandomizeStart: false,
})
- err = refr.Start(context.Background())
+ err = refr.Start(ctx)
if err != nil {
return nil, nil, fmt.Errorf("starting allowlist refresher: %w", err)
}
diff --git a/internal/cmd/safebrowsing.go b/internal/cmd/safebrowsing.go
index acaebda..893fe51 100644
--- a/internal/cmd/safebrowsing.go
+++ b/internal/cmd/safebrowsing.go
@@ -6,6 +6,7 @@ import (
"path/filepath"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
@@ -46,18 +47,21 @@ type safeBrowsingConfig struct {
func (c *safeBrowsingConfig) toInternal(
errColl errcoll.Interface,
cloner *dnsmsg.Cloner,
+ cacheManager agdcache.Manager,
id agd.FilterListID,
url *urlutil.URL,
cacheDir string,
maxSize uint64,
-) (fltConf *hashprefix.FilterConfig, err error) {
+) (fltConf *hashprefix.FilterConfig) {
hashes, err := hashprefix.NewStorage("")
if err != nil {
- return nil, err
+ // Don't expect errors here because we pass an empty string.
+ panic(err)
}
return &hashprefix.FilterConfig{
Cloner: cloner,
+ CacheManager: cacheManager,
Hashes: hashes,
URL: netutil.CloneURL(&url.URL),
ErrColl: errColl,
@@ -69,7 +73,7 @@ func (c *safeBrowsingConfig) toInternal(
CacheTTL: c.CacheTTL.Duration,
CacheSize: c.CacheSize,
MaxSize: maxSize,
- }, nil
+ }
}
// validate returns an error if the safe browsing filter configuration is
@@ -96,23 +100,18 @@ func (c *safeBrowsingConfig) validate() (err error) {
// setupHashPrefixFilter creates and returns a hash-prefix filter as well as
// starts and registers its refresher in the signal handler.
func setupHashPrefixFilter(
- conf *safeBrowsingConfig,
- cloner *dnsmsg.Cloner,
- id agd.FilterListID,
- url *urlutil.URL,
- cachePath string,
- maxSize uint64,
+ ctx context.Context,
+ fltConf *hashprefix.FilterConfig,
sigHdlr *service.SignalHandler,
- errColl errcoll.Interface,
) (strg *hashprefix.Storage, flt *hashprefix.Filter, err error) {
- fltConf, err := conf.toInternal(errColl, cloner, id, url, cachePath, maxSize)
- if err != nil {
- return nil, nil, fmt.Errorf("configuring hash prefix filter %s: %w", id, err)
- }
-
flt, err = hashprefix.NewFilter(fltConf)
if err != nil {
- return nil, nil, fmt.Errorf("creating hash prefix filter %s: %w", id, err)
+ return nil, nil, fmt.Errorf("creating hash prefix filter %s: %w", fltConf.ID, err)
+ }
+
+ err = flt.RefreshInitial(ctx)
+ if err != nil {
+ return nil, nil, fmt.Errorf("initializing hash prefix filter %s: %w", fltConf.ID, err)
}
refr := agdservice.NewRefreshWorker(&agdservice.RefreshWorkerConfig{
@@ -122,14 +121,14 @@ func setupHashPrefixFilter(
return context.WithTimeout(context.Background(), fltConf.RefreshTimeout)
},
Refresher: flt,
- Name: string(id),
+ Name: string(fltConf.ID),
Interval: fltConf.Staleness,
RefreshOnShutdown: false,
RandomizeStart: false,
})
- err = refr.Start(context.Background())
+ err = refr.Start(ctx)
if err != nil {
- return nil, nil, fmt.Errorf("starting refresher for hash prefix filter %s: %w", id, err)
+ return nil, nil, fmt.Errorf("starting hash prefix filter %s refresher: %w", fltConf.ID, err)
}
sigHdlr.Add(refr)
diff --git a/internal/cmd/tls.go b/internal/cmd/tls.go
index abeb1ad..696fd5e 100644
--- a/internal/cmd/tls.go
+++ b/internal/cmd/tls.go
@@ -184,7 +184,8 @@ func (certs tlsConfigCerts) validate() (err error) {
// TLS Session Ticket Key Rotator
-// ticketRotator is a refresh worker that rereads and resets TLS session tickets.
+// ticketRotator is a refresh worker that rereads and resets TLS session
+// tickets. It should be initially refreshed before use.
type ticketRotator struct {
errColl errcoll.Interface
confs map[*tls.Config][]string
@@ -197,7 +198,7 @@ type ticketRotator struct {
func newTicketRotator(
errColl errcoll.Interface,
grps []*agd.ServerGroup,
-) (tr *ticketRotator, err error) {
+) (tr *ticketRotator) {
confs := map[*tls.Config][]string{}
for _, g := range grps {
@@ -213,17 +214,10 @@ func newTicketRotator(
}
}
- tr = &ticketRotator{
+ return &ticketRotator{
errColl: errColl,
confs: confs,
}
-
- err = tr.Refresh(context.Background())
- if err != nil {
- return nil, fmt.Errorf("initial session ticket refresh: %w", err)
- }
-
- return tr, nil
}
// sessTickLen is the length of a single TLS session ticket key in bytes.
@@ -320,9 +314,11 @@ func setupTicketRotator(
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (err error) {
- tickRot, err := newTicketRotator(errColl, srvGrps)
+ tickRot := newTicketRotator(errColl, srvGrps)
+
+ err = tickRot.Refresh(context.Background())
if err != nil {
- return fmt.Errorf("setting up ticket rotator: %w", err)
+ return fmt.Errorf("setting up ticket rotator: initial session ticket refresh: %w", err)
}
refr := agdservice.NewRefreshWorker(&agdservice.RefreshWorkerConfig{
diff --git a/internal/consul/allowlist.go b/internal/consul/allowlist.go
index 60ed0e7..bf9bd08 100644
--- a/internal/consul/allowlist.go
+++ b/internal/consul/allowlist.go
@@ -19,7 +19,8 @@ import (
"github.com/AdguardTeam/golibs/log"
)
-// AllowlistRefresher is a refresh wrapper that updates the allowlist.
+// AllowlistRefresher is a refresh wrapper that updates the allowlist. It
+// should be initially refreshed before use.
type AllowlistRefresher struct {
allowlist *ratelimit.DynamicAllowlist
http *agdhttp.Client
@@ -32,8 +33,8 @@ func NewAllowlistRefresher(
allowlist *ratelimit.DynamicAllowlist,
consulURL *url.URL,
errColl errcoll.Interface,
-) (l *AllowlistRefresher, err error) {
- l = &AllowlistRefresher{
+) (l *AllowlistRefresher) {
+ return &AllowlistRefresher{
allowlist: allowlist,
http: agdhttp.NewClient(&agdhttp.ClientConfig{
// TODO(a.garipov): Consider making configurable.
@@ -42,13 +43,6 @@ func NewAllowlistRefresher(
url: consulURL,
errColl: errColl,
}
-
- err = l.Refresh(context.Background())
- if err != nil {
- return nil, fmt.Errorf("initial refresh: %w", err)
- }
-
- return l, nil
}
// type check
diff --git a/internal/consul/allowlist_test.go b/internal/consul/allowlist_test.go
index bdae898..f294f98 100644
--- a/internal/consul/allowlist_test.go
+++ b/internal/consul/allowlist_test.go
@@ -8,6 +8,7 @@ import (
"net/netip"
"net/url"
"testing"
+ "time"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
@@ -22,6 +23,9 @@ func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
+// testTimeout is the common timeout for tests and contexts.
+const testTimeout = 1 * time.Second
+
// handleWithURL starts the test server with h, finishes it on cleanup, and
// returns it's URL.
//
@@ -83,12 +87,15 @@ func TestNewAllowlistRefresher(t *testing.T) {
},
}
- _, err := consul.NewAllowlistRefresher(al, u, errColl)
+ alr := consul.NewAllowlistRefresher(al, u, errColl)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ err := alr.Refresh(ctx)
require.NoError(t, err)
for _, ip := range tc.wantAllow {
var ok bool
- ok, err = al.IsAllowed(context.Background(), ip)
+ ok, err = al.IsAllowed(ctx, ip)
require.NoError(t, err)
assert.True(t, ok)
@@ -96,7 +103,7 @@ func TestNewAllowlistRefresher(t *testing.T) {
for _, ip := range tc.wantNotAllow {
var ok bool
- ok, err = al.IsAllowed(context.Background(), ip)
+ ok, err = al.IsAllowed(ctx, ip)
require.NoError(t, err)
assert.False(t, ok)
@@ -119,7 +126,10 @@ func TestNewAllowlistRefresher(t *testing.T) {
},
}
- _, err := consul.NewAllowlistRefresher(al, u, errColl)
+ alr := consul.NewAllowlistRefresher(al, u, errColl)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ err := alr.Refresh(ctx)
require.ErrorAs(t, err, &wantErr)
assert.Equal(t, wantErr.Got, status)
@@ -143,13 +153,12 @@ func TestAllowlistRefresher_Refresh_deadline(t *testing.T) {
},
}
- c, err := consul.NewAllowlistRefresher(al, u, errColl)
- require.NoError(t, err)
+ alr := consul.NewAllowlistRefresher(al, u, errColl)
ctx, cancel := context.WithCancel(context.Background())
cancel()
- err = c.Refresh(ctx)
+ err := alr.Refresh(ctx)
assert.ErrorIs(t, err, context.Canceled)
assert.ErrorIs(t, gotCollErr, context.Canceled)
}
diff --git a/internal/debugsvc/debugsvc.go b/internal/debugsvc/debugsvc.go
index dcee854..cda4a9b 100644
--- a/internal/debugsvc/debugsvc.go
+++ b/internal/debugsvc/debugsvc.go
@@ -4,11 +4,13 @@ package debugsvc
import (
"context"
"fmt"
- "io"
+ "log/slog"
"net/http"
+ "os"
"github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/log"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+ "github.com/AdguardTeam/golibs/osutil"
"github.com/AdguardTeam/golibs/pprofutil"
"github.com/AdguardTeam/golibs/service"
"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -17,16 +19,25 @@ import (
// Service is the HTTP service of AdGuard DNS. It serves prometheus metrics,
// pprof, health check, DNSDB, and other endpoints..
type Service struct {
- servers map[string]*server
- dnsDB http.Handler
+ log *slog.Logger
+ refrHdlr *refreshHandler
+ dnsDB http.Handler
+ servers map[string]*server
}
// Config is the AdGuard DNS HTTP service configuration structure.
type Config struct {
+ Logger *slog.Logger
+
DNSDBAddr string
DNSDBHandler http.Handler
- HealthAddr string
+ Refreshers Refreshers
+
+ // TODO(a.garipov): Consider using one address and removing addServer
+ // logic.
+
+ APIAddr string
PprofAddr string
PrometheusAddr string
}
@@ -34,6 +45,10 @@ type Config struct {
// New returns a new properly initialized *Service.
func New(c *Config) (svc *Service) {
svc = &Service{
+ log: c.Logger,
+ refrHdlr: &refreshHandler{
+ refrs: c.Refreshers,
+ },
servers: make(map[string]*server),
dnsDB: c.DNSDBHandler,
}
@@ -42,9 +57,9 @@ func New(c *Config) (svc *Service) {
svc.addServer(c.PrometheusAddr, "prometheus")
svc.addServer(c.PprofAddr, "pprof")
- // The health-check server causes panic if it doesn't start because the
- // server is needed to check if the dns server is active.
- svc.addServer(c.HealthAddr, "health-check")
+ // The health-check and API server causes panic if it doesn't start because
+ // the server is needed to check if the dns server is active.
+ svc.addServer(c.APIAddr, "api")
return svc
}
@@ -56,10 +71,10 @@ type server struct {
}
// startServer starts one server and panics if there is an unexpected error.
-func startServer(s *server) {
- defer log.OnPanicAndExit("startServer", 1)
+func startServer(ctx context.Context, l *slog.Logger, s *server) {
+ defer recoverAndExit(ctx, l)
- log.Info("debugsvc: %s: listen on %s", s.name, s.http.Addr)
+ l.Info("listening", "name", s.name, "addr", s.http.Addr)
srv := s.http
err := srv.ListenAndServe()
@@ -68,6 +83,29 @@ func startServer(s *server) {
}
}
+// recoverAndExit recovers a panic, logs it using l, and then exits with
+// [osutil.ExitCodeFailure].
+//
+// TODO(a.garipov): Move to golibs.
+func recoverAndExit(ctx context.Context, l *slog.Logger) {
+ v := recover()
+ if v == nil {
+ return
+ }
+
+ var args []any
+ if err, ok := v.(error); ok {
+ args = []any{slogutil.KeyError, err}
+ } else {
+ args = []any{"value", v}
+ }
+
+ l.ErrorContext(ctx, "recovered from panic", args...)
+ slogutil.PrintStack(ctx, l, slog.LevelError)
+
+ os.Exit(osutil.ExitCodeFailure)
+}
+
// type check
var _ service.Interface = (*Service)(nil)
@@ -78,9 +116,9 @@ var _ service.Interface = (*Service)(nil)
// TODO(a.garipov): Wait for the services to go online.
//
// TODO(a.garipov): Use the context for cancelation.
-func (svc *Service) Start(_ context.Context) (err error) {
+func (svc *Service) Start(ctx context.Context) (err error) {
for _, srv := range svc.servers {
- go startServer(srv)
+ go startServer(ctx, svc.log, srv)
}
return nil
@@ -98,10 +136,10 @@ func (svc *Service) Shutdown(ctx context.Context) (err error) {
srvNum++
- log.Info("debugsvc: %s: server is shutdown", srv.name)
+ svc.log.Info("server is shutdown", "name", srv.name)
}
- log.Info("debugsvc: servers shutdown: %d", srvNum)
+ svc.log.Info("all servers shutdown", "num", srvNum)
return nil
}
@@ -127,7 +165,7 @@ func (svc *Service) addServer(addr, name string) {
http: &http.Server{
Addr: addr,
Handler: mux,
- ErrorLog: log.StdLog("debugsvc", log.DEBUG),
+ ErrorLog: slog.NewLogLogger(svc.log.Handler(), slog.LevelDebug),
},
name: name,
}
@@ -143,35 +181,37 @@ func (svc *Service) addServer(addr, name string) {
// addHandler func returns the resMux that combine with the mux from args.
func (svc *Service) addHandler(serviceName string, mux *http.ServeMux) {
switch serviceName {
+ case "api":
+ svc.apiMux(mux)
case "dnsdb":
svc.dnsDBMux(mux)
- case "health-check":
- healthMux(mux)
case "pprof":
+ // TODO(a.garipov): Find ways to wrap pprof handlers.
pprofutil.RoutePprof(mux)
case "prometheus":
- promMux(mux)
+ svc.promMux(mux)
default:
panic(fmt.Errorf("debugsvc: could not find mux for service %q", serviceName))
}
}
+// apiMux adds the health-check and other debug API handlers to mux.
+func (svc *Service) apiMux(mux *http.ServeMux) {
+ mux.Handle("GET /health-check", svc.middleware(
+ http.HandlerFunc(serveHealthCheck),
+ slog.LevelDebug,
+ ))
+ mux.Handle("POST /debug/api/refresh", svc.middleware(svc.refrHdlr, slog.LevelInfo))
+}
+
// dnsDBMux adds the DNSDB CSV dump handler to mux.
+//
+// TODO(a.garipov): Tests.
func (svc *Service) dnsDBMux(mux *http.ServeMux) {
- mux.Handle("/dnsdb/csv", svc.dnsDB)
+ mux.Handle("POST /dnsdb/csv", svc.middleware(svc.dnsDB, slog.LevelInfo))
}
-// healthMux adds handler func to the mux from args for the health check service.
-func healthMux(mux *http.ServeMux) {
- mux.HandleFunc(
- "/health-check",
- func(w http.ResponseWriter, _ *http.Request) {
- _, _ = io.WriteString(w, "OK")
- },
- )
-}
-
-// promMux adds handler func to the mux from args for the prometheus service.
-func promMux(mux *http.ServeMux) {
- mux.Handle("/metrics", promhttp.Handler())
+// promMux adds the prometheus service handler to mux.
+func (svc *Service) promMux(mux *http.ServeMux) {
+ mux.Handle("GET /metrics", svc.middleware(promhttp.Handler(), slog.LevelDebug))
}
diff --git a/internal/debugsvc/debugsvc_test.go b/internal/debugsvc/debugsvc_test.go
index ae6bd4b..2deb7b9 100644
--- a/internal/debugsvc/debugsvc_test.go
+++ b/internal/debugsvc/debugsvc_test.go
@@ -1,21 +1,23 @@
package debugsvc_test
import (
+ "context"
"fmt"
"io"
"net/http"
+ "strings"
"testing"
"time"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/debugsvc"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-func TestMain(m *testing.M) {
- testutil.DiscardLogOutput(m)
-}
+// TODO(a.garipov): Improve and split tests.
// testTimeout is a common timeout for tests.
const testTimeout = 1 * time.Second
@@ -31,10 +33,21 @@ func TestService_Start(t *testing.T) {
require.NoError(pt, err)
})
+ refreshed := false
c := &debugsvc.Config{
- DNSDBAddr: addr,
- DNSDBHandler: h,
- HealthAddr: addr,
+ Logger: slogutil.NewDiscardLogger(),
+ DNSDBAddr: addr,
+ DNSDBHandler: h,
+ Refreshers: debugsvc.Refreshers{
+ "test": &agdtest.Refresher{
+ OnRefresh: func(_ context.Context) (err error) {
+ refreshed = true
+
+ return nil
+ },
+ },
+ },
+ APIAddr: addr,
PprofAddr: addr,
PrometheusAddr: addr,
}
@@ -58,15 +71,15 @@ func TestService_Start(t *testing.T) {
var resp *http.Response
var body []byte
- // First check health-check service URL.
- // As the service could not be ready yet, check for it in periodically.
+ // First check health-check service URL. As the service could not be ready
+ // yet, check for it in periodically.
require.Eventually(t, func() bool {
resp, err = client.Get(fmt.Sprintf("http://%s/health-check", addr))
return err == nil
}, 1*time.Second, 100*time.Millisecond)
body = readRespBody(t, resp)
- assert.Equal(t, []byte("OK"), body)
+ assert.Equal(t, []byte("OK\n"), body)
assert.Equal(t, http.StatusOK, resp.StatusCode)
// Check pprof service URL.
@@ -84,6 +97,18 @@ func TestService_Start(t *testing.T) {
body = readRespBody(t, resp)
assert.True(t, len(body) > 0)
assert.Equal(t, http.StatusOK, resp.StatusCode)
+
+ // Check refresh API.
+ reqBody := strings.NewReader(`{"ids":["test"]}`)
+ urlStr := fmt.Sprintf("http://%s/debug/api/refresh", addr)
+ resp, err = client.Post(urlStr, "application/json", reqBody)
+ require.NoError(t, err)
+
+ assert.True(t, refreshed)
+ assert.Equal(t, http.StatusOK, resp.StatusCode)
+
+ body = readRespBody(t, resp)
+ assert.Equal(t, []byte(`{"results":{"test":"ok"}}`+"\n"), body)
}
// readRespBody is a helper function that reads and returns
diff --git a/internal/debugsvc/handler.go b/internal/debugsvc/handler.go
new file mode 100644
index 0000000..e2a3018
--- /dev/null
+++ b/internal/debugsvc/handler.go
@@ -0,0 +1,24 @@
+package debugsvc
+
+import (
+ "io"
+ "net/http"
+
+ "github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+)
+
+// serveHealthCheck handles the GET /health-check endpoint.
+//
+// TODO(a.garipov): Move to golibs.
+func serveHealthCheck(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set(httphdr.ContentType, "text/plain")
+ w.WriteHeader(http.StatusOK)
+
+ _, err := io.WriteString(w, "OK\n")
+ if err != nil {
+ ctx := r.Context()
+ l := slogutil.MustLoggerFromContext(ctx)
+ l.DebugContext(ctx, "writing health-check response", slogutil.KeyError, err)
+ }
+}
diff --git a/internal/debugsvc/middleware.go b/internal/debugsvc/middleware.go
new file mode 100644
index 0000000..f8cda66
--- /dev/null
+++ b/internal/debugsvc/middleware.go
@@ -0,0 +1,62 @@
+package debugsvc
+
+import (
+ "log/slog"
+ "net/http"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
+ "github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+)
+
+// middleware is the base middleware for AdGuard DNS debug API that adds a
+// logger and logs the queries starting and finishing at the given level.
+func (svc *Service) middleware(h http.Handler, lvl slog.Level) (wrapped http.Handler) {
+ f := func(w http.ResponseWriter, r *http.Request) {
+ respHdr := w.Header()
+ respHdr.Add(httphdr.Server, agdhttp.UserAgent())
+
+ l := svc.log.With(
+ "raddr", r.RemoteAddr,
+ "method", r.Method,
+ "host", r.Host,
+ "request_uri", r.RequestURI,
+ )
+
+ ctx := slogutil.ContextWithLogger(r.Context(), l)
+ r = r.WithContext(ctx)
+
+ rw := &codeRecorderResponseWriter{
+ ResponseWriter: w,
+ }
+
+ l.Log(ctx, lvl, "started")
+ defer func() { l.Log(ctx, lvl, "finished", "code", rw.code) }()
+
+ h.ServeHTTP(rw, r)
+ }
+
+ return http.HandlerFunc(f)
+}
+
+// codeRecorderResponseWriter wraps an [http.ResponseWriter] allowing to save
+// the response code.
+//
+// TODO(a.garipov): Process zero code.
+//
+// TODO(a.garipov): Move to golibs.
+type codeRecorderResponseWriter struct {
+ http.ResponseWriter
+
+ code int
+}
+
+// type check
+var _ http.ResponseWriter = (*codeRecorderResponseWriter)(nil)
+
+// WriteHeader implements [http.ResponseWriter] for *codeRecorderResponseWriter.
+func (w *codeRecorderResponseWriter) WriteHeader(code int) {
+ w.code = code
+
+ w.ResponseWriter.WriteHeader(code)
+}
diff --git a/internal/debugsvc/refresh.go b/internal/debugsvc/refresh.go
new file mode 100644
index 0000000..46810c3
--- /dev/null
+++ b/internal/debugsvc/refresh.go
@@ -0,0 +1,128 @@
+package debugsvc
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "log/slog"
+ "net/http"
+ "slices"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/httphdr"
+ "github.com/AdguardTeam/golibs/logutil/slogutil"
+ "golang.org/x/exp/maps"
+)
+
+// RefresherID is a type alias for strings that represent IDs of refreshers.
+//
+// TODO(a.garipov): Consider a newtype with validations.
+type RefresherID = string
+
+// Refreshers is a type alias for maps of refresher IDs to Refreshers
+// themselves.
+type Refreshers map[RefresherID]agdservice.Refresher
+
+// refreshHandler performs debug refreshes.
+type refreshHandler struct {
+ refrs Refreshers
+}
+
+// refreshRequest describes the request to the POST /debug/api/refresh HTTP API.
+type refreshRequest struct {
+ IDs []RefresherID `json:"ids"`
+}
+
+// refreshResponse describes the response to the POST /debug/api/refresh HTTP
+// API.
+type refreshResponse struct {
+ Results map[RefresherID]string `json:"results"`
+}
+
+// type check
+var _ http.Handler = (*refreshHandler)(nil)
+
+// ServeHTTP implements the [http.Handler] interface for *refreshHandler.
+func (h *refreshHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+ l := slogutil.MustLoggerFromContext(ctx)
+
+ req := &refreshRequest{}
+ err := json.NewDecoder(r.Body).Decode(req)
+ if err != nil {
+ l.ErrorContext(ctx, "decoding request", slogutil.KeyError, err)
+ http.Error(w, err.Error(), http.StatusBadRequest)
+
+ return
+ }
+
+ resp := &refreshResponse{
+ Results: map[RefresherID]string{},
+ }
+
+ reqIDs, err := h.idsFromReq(req.IDs)
+ if err != nil {
+ l.ErrorContext(ctx, "validating request", slogutil.KeyError, err)
+ http.Error(w, err.Error(), http.StatusBadRequest)
+
+ return
+ }
+
+ for _, id := range reqIDs {
+ resp.Results[id] = h.refresh(ctx, l, id)
+ }
+
+ w.Header().Set(httphdr.ContentType, "application/json")
+ err = json.NewEncoder(w).Encode(resp)
+ if err != nil {
+ l.ErrorContext(ctx, "writing response", slogutil.KeyError, err)
+ }
+}
+
+// idsFromReq validates the form of the request and returns the IDs of
+// refreshers to refresh.
+func (h *refreshHandler) idsFromReq(reqIDs []RefresherID) (ids []RefresherID, err error) {
+ l := len(reqIDs)
+ switch l {
+ case 0:
+ return nil, errors.Error("no ids")
+ case 1:
+ if reqIDs[0] != "*" {
+ return reqIDs, nil
+ }
+
+ allIDs := maps.Keys(h.refrs)
+ slices.Sort(allIDs)
+
+ return allIDs, nil
+ default:
+ starIdx := slices.Index(reqIDs, "*")
+ if starIdx == -1 {
+ return reqIDs, nil
+ }
+
+ return nil, errors.Error(`"*" cannot be used with other ids`)
+ }
+}
+
+// refresh performs a single refresh and returns the result as a string.
+func (h *refreshHandler) refresh(ctx context.Context, l *slog.Logger, id RefresherID) (res string) {
+ r, ok := h.refrs[id]
+ if !ok {
+ return "error: refresher not found"
+ }
+
+ start := time.Now()
+ err := r.Refresh(ctx)
+ if err != nil {
+ l.ErrorContext(ctx, "refresher error", "id", id, slogutil.KeyError, err)
+
+ return fmt.Sprintf("error: %s", err)
+ }
+
+ l.InfoContext(ctx, "refresh finished", "id", id, "duration", time.Since(start))
+
+ return "ok"
+}
diff --git a/internal/dnsmsg/cloner_test.go b/internal/dnsmsg/cloner_test.go
index 961ba72..0827304 100644
--- a/internal/dnsmsg/cloner_test.go
+++ b/internal/dnsmsg/cloner_test.go
@@ -175,6 +175,7 @@ var clonerTestCases = []clonerTestCase{{
&dns.SVCBLocal{KeyCode: dns.SVCBKey(1234), Data: []byte{3, 2, 1, 0}},
&dns.SVCBMandatory{Code: []dns.SVCBKey{dns.SVCB_ALPN}},
&dns.SVCBNoDefaultAlpn{},
+ &dns.SVCBOhttp{},
&dns.SVCBPort{Port: 443},
}),
name: "resp_https",
@@ -195,6 +196,14 @@ var clonerTestCases = []clonerTestCase{{
name: "resp_https_empty_mandatory",
wantFull: assert.True,
handledByClone: true,
+}, {
+ msg: newHTTPSResp([]dns.SVCBKeyValue{
+ &dns.SVCBNoDefaultAlpn{},
+ &dns.SVCBOhttp{},
+ }),
+ name: "resp_https_empty_values",
+ wantFull: assert.True,
+ handledByClone: true,
}, {
msg: newHTTPSResp(nil),
name: "resp_https_nil_hint",
@@ -338,26 +347,27 @@ func BenchmarkClone(b *testing.B) {
// Most recent results, on a ThinkPad X13 with a Ryzen Pro 7 CPU:
//
- // goos: linux
+ // goos: darwin
// goarch: amd64
- // pkg: github.com/AdguardTeam/AdGuardDNS/internal/querylog
- // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
- // BenchmarkClone/req_a-16 24691725 250.1 ns/op 168 B/op 2 allocs/op
- // BenchmarkClone/resp_a-16 12547648 429.8 ns/op 256 B/op 5 allocs/op
- // BenchmarkClone/resp_a_many-16 10174539 602.5 ns/op 344 B/op 7 allocs/op
- // BenchmarkClone/resp_a_soa-16 10228933 600.0 ns/op 368 B/op 6 allocs/op
- // BenchmarkClone/req_aaaa-16 24920611 248.6 ns/op 168 B/op 2 allocs/op
- // BenchmarkClone/resp_aaaa-16 13603160 474.0 ns/op 264 B/op 5 allocs/op
- // BenchmarkClone/resp_cname_a-16 10398249 589.2 ns/op 320 B/op 6 allocs/op
- // BenchmarkClone/resp_mx-16 15299034 414.9 ns/op 248 B/op 4 allocs/op
- // BenchmarkClone/resp_ptr-16 14701116 386.7 ns/op 232 B/op 4 allocs/op
- // BenchmarkClone/resp_txt-16 11148487 495.6 ns/op 296 B/op 5 allocs/op
- // BenchmarkClone/resp_srv-16 16175085 398.3 ns/op 248 B/op 4 allocs/op
- // BenchmarkClone/resp_not_full-16 16115785 366.2 ns/op 248 B/op 4 allocs/op
- // BenchmarkClone/resp_https-16 2940937 1998 ns/op 880 B/op 24 allocs/op
- // BenchmarkClone/resp_https_empty_hint-16 8712819 744.4 ns/op 424 B/op 8 allocs/op
- // BenchmarkClone/resp_https_empty_mandatory-16 8605273 655.8 ns/op 384 B/op 7 allocs/op
- // BenchmarkClone/resp_a_ecs-16 7337880 777.1 ns/op 384 B/op 8 allocs/op
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg
+ // cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
+ // BenchmarkClone/req_a-12 8987066 123.7 ns/op 168 B/op 2 allocs/op
+ // BenchmarkClone/resp_a-12 5619037 212.7 ns/op 256 B/op 5 allocs/op
+ // BenchmarkClone/resp_a_many-12 4385636 273.2 ns/op 344 B/op 7 allocs/op
+ // BenchmarkClone/resp_a_soa-12 4533913 263.1 ns/op 368 B/op 6 allocs/op
+ // BenchmarkClone/req_aaaa-12 10196326 116.9 ns/op 168 B/op 2 allocs/op
+ // BenchmarkClone/resp_aaaa-12 5666234 211.8 ns/op 264 B/op 5 allocs/op
+ // BenchmarkClone/resp_cname_a-12 4713193 255.4 ns/op 320 B/op 6 allocs/op
+ // BenchmarkClone/resp_mx-12 6539623 181.8 ns/op 248 B/op 4 allocs/op
+ // BenchmarkClone/resp_ptr-12 6744601 179.8 ns/op 232 B/op 4 allocs/op
+ // BenchmarkClone/resp_txt-12 5120538 230.8 ns/op 296 B/op 5 allocs/op
+ // BenchmarkClone/resp_srv-12 6549402 181.5 ns/op 248 B/op 4 allocs/op
+ // BenchmarkClone/resp_not_full-12 6529968 181.4 ns/op 248 B/op 4 allocs/op
+ // BenchmarkClone/resp_https-12 1361680 880.8 ns/op 896 B/op 24 allocs/op
+ // BenchmarkClone/resp_https_empty_hint-12 3548672 345.3 ns/op 424 B/op 8 allocs/op
+ // BenchmarkClone/resp_https_empty_mandatory-12 4055365 291.6 ns/op 384 B/op 7 allocs/op
+ // BenchmarkClone/resp_https_empty_values-12 4434608 269.8 ns/op 376 B/op 6 allocs/op
+ // BenchmarkClone/resp_a_ecs-12 3741008 318.5 ns/op 384 B/op 8 allocs/op
}
func BenchmarkCloner_Clone(b *testing.B) {
@@ -388,28 +398,29 @@ func BenchmarkCloner_Clone(b *testing.B) {
// Most recent results, on a ThinkPad X13 with a Ryzen Pro 7 CPU:
//
- // goos: linux
+ // goos: darwin
// goarch: amd64
- // pkg: github.com/AdguardTeam/AdGuardDNS/internal/querylog
- // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
- // BenchmarkCloner_Clone/req_a-16 167307522 36.48 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_a-16 92398767 66.01 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_a_many-16 60790945 111.8 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_a_soa-16 61474227 91.50 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/req_aaaa-16 158363983 39.89 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_aaaa-16 72113028 76.83 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_cname_a-16 67518502 89.24 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_mx-16 89713944 70.96 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_ptr-16 87175648 67.42 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_txt-16 80373494 75.37 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_srv-16 85734901 70.36 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_not_full-16 28868667 211.3 ns/op 64 B/op 1 allocs/op
- // BenchmarkCloner_Clone/resp_https-16 13196191 402.3 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_https_empty_hint-16 48459688 125.6 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_https_empty_mandatory-16 63759298 96.10 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_https_nil_hint-16 89683288 66.75 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_a_ecs-16 53174110 119.6 ns/op 0 B/op 0 allocs/op
- // BenchmarkCloner_Clone/resp_a_ecs_nil-16 69814755 92.42 ns/op 0 B/op 0 allocs/op
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg
+ // cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
+ // BenchmarkCloner_Clone/req_a-12 28363105 39.40 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_a-12 17288836 72.96 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_a_many-12 11043524 105.9 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_a_soa-12 14058405 84.21 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/req_aaaa-12 31732440 37.61 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_aaaa-12 19054647 65.48 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_cname_a-12 13343605 90.35 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_mx-12 19749904 59.09 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_ptr-12 20109849 60.00 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_txt-12 17270551 64.07 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_srv-12 18197905 66.67 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_not_full-12 12713991 95.55 ns/op 64 B/op 1 allocs/op
+ // BenchmarkCloner_Clone/resp_https-12 3037629 395.9 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_https_empty_hint-12 10258635 119.3 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_https_empty_mandatory-12 14306239 82.14 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_https_empty_values-12 15568735 80.12 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_https_nil_hint-12 20536422 59.70 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_a_ecs-12 10978351 107.8 ns/op 0 B/op 0 allocs/op
+ // BenchmarkCloner_Clone/resp_a_ecs_nil-12 13626586 93.56 ns/op 0 B/op 0 allocs/op
}
func FuzzCloner_Clone(f *testing.F) {
diff --git a/internal/dnsmsg/httpscloner.go b/internal/dnsmsg/httpscloner.go
index 05b51e2..f6485e2 100644
--- a/internal/dnsmsg/httpscloner.go
+++ b/internal/dnsmsg/httpscloner.go
@@ -23,7 +23,6 @@ type httpsCloner struct {
ipv6hint *syncutil.Pool[dns.SVCBIPv6Hint]
local *syncutil.Pool[dns.SVCBLocal]
mandatory *syncutil.Pool[dns.SVCBMandatory]
- noDefALPN *syncutil.Pool[dns.SVCBNoDefaultAlpn]
port *syncutil.Pool[dns.SVCBPort]
// Miscellaneous.
@@ -59,9 +58,6 @@ func newHTTPSCloner() (c *httpsCloner) {
mandatory: syncutil.NewPool(func() (v *dns.SVCBMandatory) {
return &dns.SVCBMandatory{}
}),
- noDefALPN: syncutil.NewPool(func() (v *dns.SVCBNoDefaultAlpn) {
- return &dns.SVCBNoDefaultAlpn{}
- }),
port: syncutil.NewPool(func() (v *dns.SVCBPort) {
return &dns.SVCBPort{}
}),
@@ -94,8 +90,8 @@ func (c *httpsCloner) clone(rr *dns.HTTPS) (clone *dns.HTTPS, full bool) {
clone.Value = clone.Value[:0]
for _, orig := range rr.Value {
- valClone, valFull := c.cloneKV(orig)
- if !valFull {
+ valClone := c.cloneKV(orig)
+ if valClone == nil {
// This branch is only reached if there is a new SVCB key-value type
// in miekg/dns. Give up and just use their copy function.
return dns.Copy(rr).(*dns.HTTPS), false
@@ -107,12 +103,12 @@ func (c *httpsCloner) clone(rr *dns.HTTPS) (clone *dns.HTTPS, full bool) {
return clone, true
}
-// cloneKV returns a deep clone of orig. full is true if orig was recognized.
-func (c *httpsCloner) cloneKV(orig dns.SVCBKeyValue) (clone dns.SVCBKeyValue, full bool) {
+// cloneKV returns a deep clone of orig. clone is nil if orig wasn't
+// recognized.
+func (c *httpsCloner) cloneKV(orig dns.SVCBKeyValue) (clone dns.SVCBKeyValue) {
switch orig := orig.(type) {
case *dns.SVCBAlpn:
v := c.alpn.Get()
-
v.Alpn = appendIfNotNil(v.Alpn[:0], orig.Alpn)
clone = v
@@ -123,49 +119,57 @@ func (c *httpsCloner) cloneKV(orig dns.SVCBKeyValue) (clone dns.SVCBKeyValue, fu
clone = v
case *dns.SVCBECHConfig:
v := c.echconfig.Get()
-
v.ECH = appendIfNotNil(v.ECH[:0], orig.ECH)
- clone = v
- case *dns.SVCBIPv4Hint:
- v := c.ipv4hint.Get()
-
- v.Hint = c.appendIPs(v.Hint[:0], orig.Hint)
-
- clone = v
- case *dns.SVCBIPv6Hint:
- v := c.ipv6hint.Get()
-
- v.Hint = c.appendIPs(v.Hint[:0], orig.Hint)
-
clone = v
case *dns.SVCBLocal:
v := c.local.Get()
v.KeyCode = orig.KeyCode
-
v.Data = appendIfNotNil(v.Data[:0], orig.Data)
clone = v
case *dns.SVCBMandatory:
v := c.mandatory.Get()
-
v.Code = appendIfNotNil(v.Code[:0], orig.Code)
clone = v
- case *dns.SVCBNoDefaultAlpn:
- clone = c.noDefALPN.Get()
case *dns.SVCBPort:
v := c.port.Get()
*v = *orig
clone = v
+ case
+ *dns.SVCBNoDefaultAlpn,
+ *dns.SVCBOhttp:
+ // Just use the original value since these [dns.SVCBKeyValue] types are
+ // pointers to empty structures, so we're only interested in the actual
+ // type.
+ clone = orig
default:
- // This branch is only reached if there is a new SVCB key-value type
- // in miekg/dns.
- return nil, false
+ clone = c.cloneIfHint(orig)
}
- return clone, true
+ // This is only nil if there is a new SVCB key-value type in miekg/dns.
+ return clone
+}
+
+// cloneIfHint returns a deep clone of orig if it's either an [dns.SVCBIPv4Hint]
+// or [dns.SVCBIPv6Hint]. Otherwise, it returns nil.
+func (c *httpsCloner) cloneIfHint(orig dns.SVCBKeyValue) (clone dns.SVCBKeyValue) {
+ switch orig := orig.(type) {
+ case *dns.SVCBIPv4Hint:
+ v := c.ipv4hint.Get()
+ v.Hint = c.appendIPs(v.Hint[:0], orig.Hint)
+
+ return v
+ case *dns.SVCBIPv6Hint:
+ v := c.ipv6hint.Get()
+ v.Hint = c.appendIPs(v.Hint[:0], orig.Hint)
+
+ return v
+ default:
+ return nil
+ }
}
// appendIPs appends the clones of IP addresses from orig to hints and returns
@@ -220,10 +224,12 @@ func (c *httpsCloner) putKV(kv dns.SVCBKeyValue) {
c.local.Put(kv)
case *dns.SVCBMandatory:
c.mandatory.Put(kv)
- case *dns.SVCBNoDefaultAlpn:
- c.noDefALPN.Put(kv)
case *dns.SVCBPort:
c.port.Put(kv)
+ case
+ *dns.SVCBNoDefaultAlpn,
+ *dns.SVCBOhttp:
+ // Don't use pool for empty structures, see comment in [cloneKV].
default:
// This branch is only reached if there is a new SVCB key-value type
// in miekg/dns. Noting to do.
@@ -234,7 +240,6 @@ func (c *httpsCloner) putKV(kv dns.SVCBKeyValue) {
func (c *httpsCloner) putIPs(ips []net.IP) {
for _, ip := range ips {
if cap(ip) >= 16 {
- // nolint:looppointer // Slicing is used to get the array pointer.
c.ip.Put((*[16]byte)(ip[:16]))
}
}
diff --git a/internal/dnsserver/cache/cache_test.go b/internal/dnsserver/cache/cache_test.go
index 2083cdd..6a47f54 100644
--- a/internal/dnsserver/cache/cache_test.go
+++ b/internal/dnsserver/cache/cache_test.go
@@ -39,8 +39,8 @@ func TestMiddleware_Wrap(t *testing.T) {
testCases := []struct {
req *dns.Msg
resp *dns.Msg
- name string
minTTL *time.Duration
+ name string
wantNumReq int
wantTTL uint32
}{{
diff --git a/internal/dnsserver/context.go b/internal/dnsserver/context.go
index c89a756..0a23d15 100644
--- a/internal/dnsserver/context.go
+++ b/internal/dnsserver/context.go
@@ -133,9 +133,9 @@ type RequestInfo struct {
// StartTime is the request's start time. It's never zero value.
StartTime time.Time
- // TLSServerName is the server name field of the client's TLS hello request.
- // It is set only if the protocol of the server is either DoQ, DoT or DoH.
- // Note, that the original SNI is transformed to lower-case.
+ // TLSServerName is the original, non-lowercased server name field of the
+ // client's TLS hello request. It is set only if the protocol of the server
+ // is either DoQ, DoT or DoH.
//
// TODO(ameshkov): use r.TLS with DoH3 (see addRequestInfo).
TLSServerName string
diff --git a/internal/dnsserver/go.mod b/internal/dnsserver/go.mod
index 22f1ff3..6f9b518 100644
--- a/internal/dnsserver/go.mod
+++ b/internal/dnsserver/go.mod
@@ -1,21 +1,21 @@
module github.com/AdguardTeam/AdGuardDNS/internal/dnsserver
-go 1.22.4
+go 1.22.5
require (
- github.com/AdguardTeam/golibs v0.23.2
+ github.com/AdguardTeam/golibs v0.24.0
github.com/ameshkov/dnscrypt/v2 v2.3.0
github.com/ameshkov/dnsstamps v1.0.3
github.com/bluele/gcache v0.0.2
- github.com/miekg/dns v1.1.58
- github.com/panjf2000/ants/v2 v2.9.1
+ github.com/miekg/dns v1.1.61
+ 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.19.0
- github.com/quic-go/quic-go v0.42.0
+ github.com/prometheus/client_golang v1.19.1
+ github.com/quic-go/quic-go v0.45.0
github.com/stretchr/testify v1.9.0
- golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8
- golang.org/x/net v0.24.0
- golang.org/x/sys v0.19.0
+ golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
+ golang.org/x/net v0.26.0
+ golang.org/x/sys v0.21.0
)
require (
@@ -24,22 +24,21 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
- github.com/golang/protobuf v1.5.4 // indirect
- github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
+ github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
+ github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8 // indirect
github.com/kr/text v0.2.0 // indirect
- github.com/onsi/ginkgo/v2 v2.17.1 // indirect
+ github.com/onsi/ginkgo/v2 v2.19.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
- github.com/prometheus/common v0.52.3 // indirect
- github.com/prometheus/procfs v0.13.0 // indirect
+ github.com/prometheus/common v0.54.0 // indirect
+ github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
go.uber.org/mock v0.4.0 // indirect
- golang.org/x/crypto v0.22.0 // indirect
- golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/crypto v0.24.0 // indirect
+ golang.org/x/mod v0.18.0 // indirect
golang.org/x/sync v0.7.0 // indirect
- golang.org/x/text v0.14.0 // indirect
- golang.org/x/tools v0.20.0 // indirect
- google.golang.org/protobuf v1.33.0 // indirect
+ golang.org/x/text v0.16.0 // indirect
+ golang.org/x/tools v0.22.0 // indirect
+ google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/internal/dnsserver/go.sum b/internal/dnsserver/go.sum
index 2104d62..b91938e 100644
--- a/internal/dnsserver/go.sum
+++ b/internal/dnsserver/go.sum
@@ -1,5 +1,5 @@
-github.com/AdguardTeam/golibs v0.23.2 h1:rMjYantwtQ39e8G4zBQ6ZLlm4s3XH30Bc9VxhoOHwao=
-github.com/AdguardTeam/golibs v0.23.2/go.mod h1:o9i55Sx6v7qogRQeqaBfmLbC/pZqeMBWi015U5PTDY0=
+github.com/AdguardTeam/golibs v0.24.0 h1:qAnOq7BQtwSVo7Co9q703/n+nZ2Ap6smkugU9G9MomY=
+github.com/AdguardTeam/golibs v0.24.0/go.mod h1:9/vJcYznW7RlmCT/Qzi8XNZGj+ZbWfHZJmEXKnRpCAU=
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=
@@ -20,48 +20,45 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
-github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
-github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
+github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/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-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
-github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
+github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8 h1:ASJ/LAqdCHOyMYI+dwNxn7Rd8FscNkMyTr1KZU1JI/M=
+github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
-github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
-github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
-github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
-github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
-github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
-github.com/panjf2000/ants/v2 v2.9.1 h1:Q5vh5xohbsZXGcD6hhszzGqB7jSSc2/CRr3QKIga8Kw=
-github.com/panjf2000/ants/v2 v2.9.1/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
+github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
+github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
+github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
+github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
+github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
+github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
+github.com/panjf2000/ants/v2 v2.10.0 h1:zhRg1pQUtkyRiOFo2Sbqwjp0GfBNo9cUY2/Grpx1p+8=
+github.com/panjf2000/ants/v2 v2.10.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible h1:IWzUvJ72xMjmrjR9q3H1PF+jwdN0uNQiR2t1BLNalyo=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
-github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
+github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
+github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
-github.com/prometheus/common v0.52.3 h1:5f8uj6ZwHSscOGNdIQg6OiZv/ybiK2CO2q2drVZAQSA=
-github.com/prometheus/common v0.52.3/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
-github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
-github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
+github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8=
+github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ=
+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.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
-github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
-github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
+github.com/quic-go/quic-go v0.45.0 h1:OHmkQGM37luZITyTSu6ff03HP/2IrwDX1ZFiNEhSFUE=
+github.com/quic-go/quic-go v0.45.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
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=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
@@ -69,27 +66,27 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
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.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
-golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
-golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc=
-golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
-golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
+golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
+golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
+golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
+golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
+golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
+golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
-golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
-golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
-golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
-google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
-google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
+golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/pool/pool.go b/internal/dnsserver/pool/pool.go
index 4d1cc03..dbc22f0 100644
--- a/internal/dnsserver/pool/pool.go
+++ b/internal/dnsserver/pool/pool.go
@@ -18,21 +18,24 @@ const ErrClosed = errors.Error("the pool is closed")
// must use the context's deadline if it's specified.
type Factory func(ctx context.Context) (conn net.Conn, err error)
-// Pool is a structure that implements a net.Conn pool. Must be initialized
-// using the NewPool method.
+// Pool is a structure that implements a net.Conn pool.
type Pool struct {
- // IdleTimeout is the maximum TTL of an idle connection in the pool.
- // Connections that weren't used for more than the specified duration will
- // be closed. If set to 0, connections don't expire. Default value is 0.
- IdleTimeout time.Duration
+ // connsChanMu is used to synchronize the closing of connsChan.
+ connsChanMu *sync.RWMutex
// connsChan is the storage for our connections.
- connsChan chan *Conn
- connsChanMu sync.RWMutex
+ connsChan chan *Conn
- // factory is the Pool's factory method. It is called whenever there are no
+ // factory is the Pool's factory method. It is called whenever there are no
// more connections in the pool.
factory Factory
+
+ // IdleTimeout is the maximum TTL of an idle connection in the pool.
+ // Connections that weren't used for more than the specified duration will
+ // be closed. If set to 0, connections don't expire.
+ //
+ // TODO(a.garipov): Put into a config.
+ IdleTimeout time.Duration
}
// NewPool creates a new Pool instance. maxCapacity configures the maximum
@@ -40,8 +43,9 @@ type Pool struct {
// Put will close the connection instead of adding it to the pool.
func NewPool(maxCapacity int, factory Factory) (p *Pool) {
return &Pool{
- connsChan: make(chan *Conn, maxCapacity),
- factory: factory,
+ connsChan: make(chan *Conn, maxCapacity),
+ connsChanMu: &sync.RWMutex{},
+ factory: factory,
}
}
@@ -65,7 +69,7 @@ func (p *Pool) Get(ctx context.Context) (conn *Conn, err error) {
if isExpired(conn, p.IdleTimeout) {
// Close the expired connection immediately and look for a new
- // one. Ignoring the error here since it's not important what
+ // one. Ignoring the error here since it's not important what
// happens with it and I'd like to avoid logging
_ = conn.Close()
continue
diff --git a/internal/dnsserver/serverbase.go b/internal/dnsserver/serverbase.go
index ea9891a..686bcec 100644
--- a/internal/dnsserver/serverbase.go
+++ b/internal/dnsserver/serverbase.go
@@ -15,12 +15,6 @@ import (
// ConfigBase contains the necessary minimum that every Server needs to
// be initialized.
type ConfigBase struct {
- // Network is the network this server listens to. If empty, the server will
- // listen to all networks that are supposed to be used by the server's
- // protocol. Note, that it only makes sense for [ServerDNS],
- // [ServerDNSCrypt], and [ServerHTTPS].
- Network Network
-
// Handler is a handler that processes incoming DNS messages. If not set,
// the default handler, which returns error response to any query, is used.
Handler Handler
@@ -41,6 +35,12 @@ type ConfigBase struct {
// DNS server. If nil, an appropriate default ListenConfig is used.
ListenConfig netext.ListenConfig
+ // Network is the network this server listens to. If empty, the server will
+ // listen to all networks that are supposed to be used by the server's
+ // protocol. Note, that it only makes sense for [ServerDNS],
+ // [ServerDNSCrypt], and [ServerHTTPS].
+ Network Network
+
// Name is used for logging, and it may be used for perf counters reporting.
Name string
@@ -51,19 +51,6 @@ type ConfigBase struct {
// ServerBase implements base methods that every Server implementation uses.
type ServerBase struct {
- // name is used for logging and it may be used for perf counters reporting.
- name string
-
- // addr is the address the server listens to.
- addr string
-
- // proto is the server protocol.
- proto Protocol
-
- // network is the network to listen to. It only makes sense for the
- // following protocols: ProtoDNS, ProtoDNSCrypt, ProtoDoH.
- network Network
-
// handler is a handler that processes incoming DNS messages.
handler Handler
@@ -79,9 +66,6 @@ type ServerBase struct {
// listenConfig is used to set tcpListener and udpListener.
listenConfig netext.ListenConfig
- // Server operation
- // --
-
// tcpListener is used to accept new TCP connections. It is nil for servers
// that don't use TCP.
tcpListener net.Listener
@@ -90,15 +74,27 @@ type ServerBase struct {
// that don't use UDP.
udpListener net.PacketConn
- // Shutdown handling
- // --
+ // mu protects started, tcpListener, and udpListener.
+ mu *sync.RWMutex
- // lock protects started, tcpListener and udpListener.
- lock sync.RWMutex
- started bool
// wg tracks active workers (listeners or query processing). Shutdown
// won't finish until there's at least one active worker.
- wg sync.WaitGroup
+ wg *sync.WaitGroup
+
+ // name is used for logging and it may be used for perf counters reporting.
+ name string
+
+ // addr is the address the server listens to.
+ addr string
+
+ // network is the network to listen to. It only makes sense for the
+ // following protocols: [ProtoDNS], [ProtoDNSCrypt], [ProtoDoH].
+ network Network
+
+ // proto is the server protocol.
+ proto Protocol
+
+ started bool
}
// type check
@@ -108,15 +104,17 @@ var _ Server = (*ServerBase)(nil)
// some of its internal properties.
func newServerBase(proto Protocol, conf ConfigBase) (s *ServerBase) {
s = &ServerBase{
- name: conf.Name,
- addr: conf.Addr,
- proto: proto,
- network: conf.Network,
handler: conf.Handler,
+ reqCtx: conf.RequestContext,
metrics: conf.Metrics,
disposer: conf.Disposer,
listenConfig: conf.ListenConfig,
- reqCtx: conf.RequestContext,
+ mu: &sync.RWMutex{},
+ wg: &sync.WaitGroup{},
+ name: conf.Name,
+ addr: conf.Addr,
+ network: conf.Network,
+ proto: proto,
}
if s.reqCtx == nil {
@@ -473,8 +471,8 @@ func (s *ServerBase) waitShutdown(ctx context.Context) (err error) {
// isStarted returns true if the server is started.
func (s *ServerBase) isStarted() (started bool) {
- s.lock.RLock()
- defer s.lock.RUnlock()
+ s.mu.RLock()
+ defer s.mu.RUnlock()
return s.started
}
diff --git a/internal/dnsserver/serverdns.go b/internal/dnsserver/serverdns.go
index d6ce00a..02a2ab7 100644
--- a/internal/dnsserver/serverdns.go
+++ b/internal/dnsserver/serverdns.go
@@ -44,6 +44,15 @@ type ConfigDNS struct {
// not set it defaults to DefaultWriteTimeout.
WriteTimeout time.Duration
+ // TCPIdleTimeout is the timeout for waiting between multiple queries. If
+ // not set it defaults to [DefaultTCPIdleTimeout].
+ TCPIdleTimeout time.Duration
+
+ // MaxPipelineCount is the maximum number of simultaneously processing TCP
+ // messages per one connection. If MaxPipelineEnabled is true, it must be
+ // greater than zero.
+ MaxPipelineCount uint
+
// UDPSize is the size of the buffers used to read incoming UDP messages.
// If not set it defaults to [dns.MinMsgSize], 512 B.
UDPSize int
@@ -55,15 +64,6 @@ type ConfigDNS struct {
// MaxUDPRespSize is the maximum size of DNS response over UDP protocol.
MaxUDPRespSize uint16
- // TCPIdleTimeout is the timeout for waiting between multiple queries. If
- // not set it defaults to [DefaultTCPIdleTimeout].
- TCPIdleTimeout time.Duration
-
- // MaxPipelineCount is the maximum number of simultaneously processing TCP
- // messages per one connection. If MaxPipelineEnabled is true, it must be
- // greater than zero.
- MaxPipelineCount uint
-
// MaxPipelineEnabled, if true, enables TCP pipeline limiting.
MaxPipelineEnabled bool
}
@@ -143,8 +143,8 @@ func newServerDNS(proto Protocol, conf ConfigDNS) (s *ServerDNS) {
func (s *ServerDNS) Start(ctx context.Context) (err error) {
defer func() { err = errors.Annotate(err, "starting dns server: %w") }()
- s.lock.Lock()
- defer s.lock.Unlock()
+ s.mu.Lock()
+ defer s.mu.Unlock()
if s.started {
return ErrServerAlreadyStarted
@@ -243,8 +243,9 @@ func (s *ServerDNS) startServeTCP(ctx context.Context) {
// shutdown marks the server as stopped and closes active listeners.
func (s *ServerDNS) shutdown() (err error) {
- s.lock.Lock()
- defer s.lock.Unlock()
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
if !s.started {
return ErrServerNotStarted
}
diff --git a/internal/dnsserver/serverdns_test.go b/internal/dnsserver/serverdns_test.go
index 2fea08d..0f89ce8 100644
--- a/internal/dnsserver/serverdns_test.go
+++ b/internal/dnsserver/serverdns_test.go
@@ -25,11 +25,11 @@ func TestServerDNS_StartShutdown(t *testing.T) {
func TestServerDNS_integration_query(t *testing.T) {
testCases := []struct {
+ handler dnsserver.Handler
+ req *dns.Msg
+ wantMsg func(t *testing.T, m *dns.Msg)
name string
network dnsserver.Network
- req *dns.Msg
- handler dnsserver.Handler
- wantMsg func(t *testing.T, m *dns.Msg)
wantRecordsCount int
wantRCode int
wantTruncated bool
@@ -419,10 +419,10 @@ func TestServerDNS_integration_tcpMsgIgnore(t *testing.T) {
t.Parallel()
testCases := []struct {
+ expectedError func(err error)
name string
buf []byte
timeout time.Duration
- expectedError func(err error)
}{
{
name: "invalid_input_timeout",
diff --git a/internal/dnsserver/serverdnscrypt.go b/internal/dnsserver/serverdnscrypt.go
index e6c3125..98535a3 100644
--- a/internal/dnsserver/serverdnscrypt.go
+++ b/internal/dnsserver/serverdnscrypt.go
@@ -2,6 +2,7 @@ package dnsserver
import (
"context"
+ "fmt"
"net"
"time"
@@ -17,23 +18,20 @@ import (
type ConfigDNSCrypt struct {
ConfigBase
- // DNSCryptProviderName is a DNSCrypt provider name (see DNSCrypt spec).
- DNSCryptProviderName string
-
// DNSCryptResolverCert is a DNSCrypt server certificate.
DNSCryptResolverCert *dnscrypt.Cert
+
+ // DNSCryptProviderName is a DNSCrypt provider name (see DNSCrypt spec).
+ DNSCryptProviderName string
}
// ServerDNSCrypt is a DNSCrypt server implementation.
type ServerDNSCrypt struct {
*ServerBase
+ dnsCryptServer *dnscrypt.Server
+
conf ConfigDNSCrypt
-
- // Internal server properties
- // --
-
- dnsCryptServer *dnscrypt.Server // dnscrypt server instance
}
// type check
@@ -55,8 +53,8 @@ func NewServerDNSCrypt(conf ConfigDNSCrypt) (s *ServerDNSCrypt) {
func (s *ServerDNSCrypt) Start(ctx context.Context) (err error) {
defer func() { err = errors.Annotate(err, "starting dnscrypt server: %w") }()
- s.lock.Lock()
- defer s.lock.Unlock()
+ s.mu.Lock()
+ defer s.mu.Unlock()
// First, validate the protocol.
if s.proto != ProtoDNSCrypt {
@@ -116,24 +114,33 @@ func (s *ServerDNSCrypt) Shutdown(ctx context.Context) (err error) {
// startServe creates listeners and starts serving DNSCrypt.
func (s *ServerDNSCrypt) startServe(ctx context.Context) (err error) {
+ var errs []error
+
if s.network.CanUDP() {
err = s.listenUDP(ctx)
if err != nil {
- return err
+ // Don't wrap the error, because it's informative enough as is.
+ errs = append(errs, err)
}
-
- go s.startServeUDP(ctx)
}
if s.network.CanTCP() {
err = s.listenTCP(ctx)
if err != nil {
- return err
+ // Don't wrap the error, because it's informative enough as is.
+ errs = append(errs, err)
}
-
- go s.startServeTCP(ctx)
}
+ if len(errs) > 0 {
+ s.closeListeners()
+
+ return fmt.Errorf("creating listeners: %w", errors.Join(errs...))
+ }
+
+ go s.startServeUDP(ctx)
+ go s.startServeTCP(ctx)
+
return nil
}
@@ -176,8 +183,9 @@ func (s *ServerDNSCrypt) startServeTCP(ctx context.Context) {
// shutdown marks the server as stopped and closes active listeners.
func (s *ServerDNSCrypt) shutdown() (err error) {
- s.lock.Lock()
- defer s.lock.Unlock()
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
if !s.started {
return ErrServerNotStarted
}
diff --git a/internal/dnsserver/serverdnscrypt_test.go b/internal/dnsserver/serverdnscrypt_test.go
index c77205a..48adcb9 100644
--- a/internal/dnsserver/serverdnscrypt_test.go
+++ b/internal/dnsserver/serverdnscrypt_test.go
@@ -14,11 +14,10 @@ import (
func TestServerDNSCrypt_integration_query(t *testing.T) {
testCases := []struct {
- name string
- network dnsserver.Network
- req *dns.Msg
- // if nil, use DefaultTestHandler
handler dnsserver.Handler
+ req *dns.Msg
+ name string
+ network dnsserver.Network
expectedRecordsCount int
expectedRCode int
expectedTruncated bool
diff --git a/internal/dnsserver/serverdnstcp.go b/internal/dnsserver/serverdnstcp.go
index b11721e..504b580 100644
--- a/internal/dnsserver/serverdnstcp.go
+++ b/internal/dnsserver/serverdnstcp.go
@@ -8,7 +8,6 @@ import (
"io"
"net"
"slices"
- "strings"
"sync"
"time"
@@ -173,7 +172,7 @@ func (s *ServerDNS) acceptTCPMsg(
StartTime: time.Now(),
}
if cs, ok := conn.(tlsConnectionStater); ok {
- ri.TLSServerName = strings.ToLower(cs.ConnectionState().ServerName)
+ ri.TLSServerName = cs.ConnectionState().ServerName
}
reqCtx, reqCancel := s.requestContext()
diff --git a/internal/dnsserver/serverhttps.go b/internal/dnsserver/serverhttps.go
index a65f954..d24e323 100644
--- a/internal/dnsserver/serverhttps.go
+++ b/internal/dnsserver/serverhttps.go
@@ -58,8 +58,6 @@ var nextProtoDoH3 = []string{http3.NextProtoH3, http2.NextProtoTLS, "http/1.1"}
// will listen to both HTTP/2 and HTTP/3, but if you set it to NetworkTCP, the
// server will only use HTTP/2 and NetworkUDP will mean HTTP/3 only.
type ConfigHTTPS struct {
- ConfigBase
-
// TLSConfig is the TLS configuration for HTTPS. If not set and
// [ConfigBase.Network] is set to NetworkTCP the server will listen to
// plain HTTP.
@@ -69,6 +67,8 @@ type ConfigHTTPS struct {
// If it is empty, the server will return 404 for requests like that.
NonDNSHandler http.Handler
+ ConfigBase
+
// MaxStreamsPerPeer is the maximum number of concurrent streams that a peer
// is allowed to open.
MaxStreamsPerPeer int
@@ -124,8 +124,8 @@ func NewServerHTTPS(conf ConfigHTTPS) (s *ServerHTTPS) {
func (s *ServerHTTPS) Start(ctx context.Context) (err error) {
defer func() { err = errors.Annotate(err, "starting doh server: %w") }()
- s.lock.Lock()
- defer s.lock.Unlock()
+ s.mu.Lock()
+ defer s.mu.Unlock()
if s.started {
return ErrServerAlreadyStarted
@@ -241,8 +241,9 @@ func (s *ServerHTTPS) startH3Server(ctx context.Context) (err error) {
// shutdown marks the server as stopped and closes active listeners.
func (s *ServerHTTPS) shutdown(ctx context.Context) (err error) {
- s.lock.Lock()
- defer s.lock.Unlock()
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
if !s.started {
return ErrServerNotStarted
}
@@ -570,7 +571,7 @@ func addRequestInfo(parent context.Context, r *http.Request) (ctx context.Contex
}
if r.TLS != nil {
- ri.TLSServerName = strings.ToLower(r.TLS.ServerName)
+ ri.TLSServerName = r.TLS.ServerName
}
if username, pass, ok := r.BasicAuth(); ok {
diff --git a/internal/dnsserver/serverhttps_test.go b/internal/dnsserver/serverhttps_test.go
index 96b46ce..f91a555 100644
--- a/internal/dnsserver/serverhttps_test.go
+++ b/internal/dnsserver/serverhttps_test.go
@@ -524,7 +524,7 @@ func createDoH3Client(
) (c quic.EarlyConnection, e error) {
return quic.DialAddrEarly(ctx, httpsAddr.String(), tlsCfg, cfg)
},
- QuicConfig: quicConfig,
+ QUICConfig: quicConfig,
TLSClientConfig: tlsConfig,
}
diff --git a/internal/dnsserver/serverquic.go b/internal/dnsserver/serverquic.go
index 058b7ec..6adf214 100644
--- a/internal/dnsserver/serverquic.go
+++ b/internal/dnsserver/serverquic.go
@@ -7,7 +7,6 @@ import (
"fmt"
"io"
"net"
- "strings"
"sync"
"time"
@@ -141,8 +140,8 @@ var _ Server = (*ServerQUIC)(nil)
func (s *ServerQUIC) Start(ctx context.Context) (err error) {
defer func() { err = errors.Annotate(err, "starting doq server: %w") }()
- s.lock.Lock()
- defer s.lock.Unlock()
+ s.mu.Lock()
+ defer s.mu.Unlock()
if s.conf.TLSConfig == nil {
return errors.Error("tls config is required")
@@ -202,8 +201,9 @@ func (s *ServerQUIC) Shutdown(ctx context.Context) (err error) {
// shutdown marks the server as stopped and closes active listeners.
func (s *ServerQUIC) shutdown() (err error) {
- s.lock.Lock()
- defer s.lock.Unlock()
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
if !s.started {
return ErrServerNotStarted
}
@@ -371,7 +371,7 @@ func (s *ServerQUIC) serveQUICConn(ctx context.Context, conn quic.Connection) (e
ri := &RequestInfo{
StartTime: time.Now(),
- TLSServerName: strings.ToLower(conn.ConnectionState().TLS.ServerName),
+ TLSServerName: conn.ConnectionState().TLS.ServerName,
}
reqCtx, reqCancel := s.requestContext()
diff --git a/internal/dnsserver/servertls.go b/internal/dnsserver/servertls.go
index df433cb..ec68a75 100644
--- a/internal/dnsserver/servertls.go
+++ b/internal/dnsserver/servertls.go
@@ -11,10 +11,10 @@ import (
// ConfigTLS is a struct that needs to be passed to NewServerTLS to
// initialize a new ServerTLS instance.
type ConfigTLS struct {
- ConfigDNS
-
// TLSConfig is the TLS configuration for TLS.
TLSConfig *tls.Config
+
+ ConfigDNS
}
// ServerTLS implements a DNS-over-TLS server.
@@ -43,8 +43,8 @@ func NewServerTLS(conf ConfigTLS) (s *ServerTLS) {
func (s *ServerTLS) Start(ctx context.Context) (err error) {
defer func() { err = errors.Annotate(err, "starting dot server: %w") }()
- s.lock.Lock()
- defer s.lock.Unlock()
+ s.mu.Lock()
+ defer s.mu.Unlock()
if s.conf.TLSConfig == nil {
return errors.Error("tls config is required")
diff --git a/internal/dnsserver/servertls_test.go b/internal/dnsserver/servertls_test.go
index 1c1d1f5..5ab1a92 100644
--- a/internal/dnsserver/servertls_test.go
+++ b/internal/dnsserver/servertls_test.go
@@ -48,10 +48,10 @@ func TestServerTLS_integration_msgIgnore(t *testing.T) {
t.Parallel()
testCases := []struct {
+ expectedError func(t *testing.T, err error)
name string
buf []byte
timeout time.Duration
- expectedError func(t *testing.T, err error)
}{
{
name: "invalid_input_timeout",
diff --git a/internal/dnssvc/dnssvc.go b/internal/dnssvc/dnssvc.go
index 53178ed..3c390fb 100644
--- a/internal/dnssvc/dnssvc.go
+++ b/internal/dnssvc/dnssvc.go
@@ -12,6 +12,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/billstat"
"github.com/AdguardTeam/AdGuardDNS/internal/connlimiter"
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
@@ -48,6 +49,9 @@ type Config struct {
// of DNS responses for later reuse.
Cloner *dnsmsg.Cloner
+ // CacheManager is the global cache manager. CacheManager must not be nil.
+ CacheManager agdcache.Manager
+
// ControlConf is the configuration of socket options.
ControlConf *netext.ControlConfig
@@ -55,6 +59,10 @@ type Config struct {
// active stream-connections.
ConnLimiter *connlimiter.Limiter
+ // HumanIDParser is used to normalize and parse human-readable device
+ // identifiers.
+ HumanIDParser *agd.HumanIDParser
+
// AccessManager is used to block requests.
AccessManager access.Interface
@@ -168,6 +176,7 @@ func New(c *Config) (svc *Service, err error) {
// groups.
preUps := preupstream.New(&preupstream.Config{
Cloner: c.Cloner,
+ CacheManager: c.CacheManager,
DB: c.DNSDB,
GeoIP: c.GeoIP,
CacheSize: c.CacheSize,
@@ -549,6 +558,7 @@ func newDeviceSetter(c *Config, g *agd.ServerGroup, s *agd.Server) (ds deviceset
return devicesetter.NewDefault(&devicesetter.Config{
ProfileDB: c.ProfileDB,
+ HumanIDParser: c.HumanIDParser,
Server: s,
DeviceIDWildcards: g.TLS.DeviceIDWildcards,
})
diff --git a/internal/dnssvc/integration_test.go b/internal/dnssvc/integration_test.go
index 2d701ec..1f24ead 100644
--- a/internal/dnssvc/integration_test.go
+++ b/internal/dnssvc/integration_test.go
@@ -79,6 +79,22 @@ func newTestService(
}
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")
+ },
+
+ OnProfileByDedicatedIP: func(
+ _ context.Context,
+ _ netip.Addr,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+
OnProfileByDeviceID: func(
_ context.Context,
id agd.DeviceID,
@@ -87,12 +103,15 @@ func newTestService(
return prof, dev, nil
},
- OnProfileByDedicatedIP: func(
+
+ OnProfileByHumanID: func(
_ context.Context,
- _ netip.Addr,
+ _ agd.ProfileID,
+ _ agd.HumanIDLower,
) (p *agd.Profile, d *agd.Device, err error) {
panic("not implemented")
},
+
OnProfileByLinkedIP: func(
ctx context.Context,
ip netip.Addr,
diff --git a/internal/dnssvc/internal/devicesetter/device.go b/internal/dnssvc/internal/devicesetter/device.go
index 49d369e..21e5fbd 100644
--- a/internal/dnssvc/internal/devicesetter/device.go
+++ b/internal/dnssvc/internal/devicesetter/device.go
@@ -2,6 +2,7 @@ package devicesetter
import (
"context"
+ "fmt"
"net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
@@ -11,27 +12,35 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/optlog"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/log"
)
// findDevice returns a valid, non-deleted profile and device or nils. err is
-// only not nil when it's not [profiledb.ErrDeviceNotFound].
+// only not nil when it's not a not-found error from the profile database.
func (ds *Default) findDevice(
ctx context.Context,
laddr netip.AddrPort,
remoteIP netip.Addr,
id agd.DeviceID,
+ extID *extHumanID,
) (prof *agd.Profile, dev *agd.Device, err error) {
// TODO(a.garipov): Add package optslog for optimized slog logging?
- optlog.Debug3("devicesetter: got dev id %q, raddr %s, and laddr %s", id, remoteIP, laddr)
+ optlog.Debug4(
+ "devicesetter: got dev id %q, ext id present %t, raddr %s, and laddr %s",
+ id,
+ extID != nil,
+ remoteIP,
+ laddr,
+ )
- prof, dev, byWhat, err := ds.deviceFromDB(ctx, laddr, remoteIP, id)
+ prof, dev, byWhat, err := ds.deviceFromDB(ctx, laddr, remoteIP, id, extID)
if err != nil {
- if !errors.Is(err, profiledb.ErrDeviceNotFound) {
- // Don't wrap the error, because it's likely [errUnknownDedicated].
- return nil, nil, err
- }
+ // Don't wrap the error, because it's likely [ErrUnknownDedicated].
+ return nil, nil, err
+ }
- optlog.Debug1("devicesetter: profile or device not found: %s", err)
+ if prof == nil || dev == nil {
+ log.Debug("devicesetter: profile or device not found")
return nil, nil, nil
}
@@ -49,37 +58,121 @@ func (ds *Default) findDevice(
// Constants for the parameter by which a device has been found.
const (
- byDeviceID = "device id"
byDedicatedIP = "dedicated ip"
+ byDeviceID = "device id"
+ byHumanID = "human id"
byLinkedIP = "linked ip"
)
// deviceFromDB queries the profile DB for the profile and device by the client
-// data. It also returns the description of how it has found them.
+// data. It also returns the description of how it has found them. err is only
+// not nil when it's not a not-found error from the profile database.
func (ds *Default) deviceFromDB(
ctx context.Context,
laddr netip.AddrPort,
remoteIP netip.Addr,
id agd.DeviceID,
+ extID *extHumanID,
) (prof *agd.Profile, dev *agd.Device, byWhat string, err error) {
if id != "" {
prof, dev, err = ds.db.ProfileByDeviceID(ctx, id)
if err != nil {
- return nil, nil, "", err
+ // Don't wrap the error, as this is a hot path, and an error other
+ // than a not-found one is unlikely.
+ return nil, nil, "", removeNotFound(err)
}
return prof, dev, byDeviceID, nil
}
+ if extID != nil {
+ prof, dev, err = ds.deviceByExtID(ctx, extID)
+ if err == nil {
+ return prof, dev, byHumanID, nil
+ }
+
+ // Don't wrap the error, because it's informative enough as is.
+ return nil, nil, "", err
+ }
+
if ds.srv.Protocol == agd.ProtoDNS {
return ds.deviceByAddrs(ctx, laddr, remoteIP)
}
- return nil, nil, "", profiledb.ErrDeviceNotFound
+ return nil, nil, "", nil
+}
+
+// removeNotFound returns nil if err is one of the not-found errors from the
+// profile database.
+func removeNotFound(err error) (res error) {
+ if isProfileDBNotFound(err) {
+ return nil
+ }
+
+ return err
+}
+
+// deviceByExtID queries the profile DB for the profile and device by the
+// extended human-readable device identifier. extID must not be nil. err is
+// only not nil when it's not a not-found error from the profile database.
+func (ds *Default) deviceByExtID(
+ ctx context.Context,
+ extID *extHumanID,
+) (prof *agd.Profile, dev *agd.Device, err error) {
+ profID, humanID := extID.ProfileID, extID.HumanID
+ prof, dev, err = ds.db.ProfileByHumanID(ctx, profID, agd.HumanIDToLower(humanID))
+ switch {
+ case err == nil:
+ return prof, dev, nil
+ case errorIsOpt(err, profiledb.ErrProfileNotFound):
+ // No such profile, return immediately.
+ return nil, nil, nil
+ case errorIsOpt(err, profiledb.ErrDeviceNotFound):
+ // Go on and try to create.
+ default:
+ // Unlikely, so wrap.
+ return nil, nil, fmt.Errorf("querying profile db by human id: %w", err)
+ }
+
+ prof, dev, err = ds.db.CreateAutoDevice(ctx, profID, humanID, extID.DeviceType)
+ switch {
+ case err == nil:
+ return prof, dev, nil
+ case errorIsOpt(err, profiledb.ErrProfileNotFound):
+ // A rare case where a profile has been deleted between the check and
+ // the creation.
+ return nil, nil, nil
+ default:
+ return nil, nil, fmt.Errorf("creating autodevice: %w", err)
+ }
+}
+
+// isProfileDBNotFound returns true if err is one of the not-found errors from
+// the profile database.
+func isProfileDBNotFound(err error) (ok bool) {
+ return errorIsOpt(err, profiledb.ErrDeviceNotFound) ||
+ errorIsOpt(err, profiledb.ErrProfileNotFound)
+}
+
+// errorIsOpt is an optimized version of [errors.Is] that is faster in cases
+// where the error is returned directly or with one level of [fmt.Errorf].
+// target must be comparable.
+func errorIsOpt(err, target error) (ok bool) {
+ if err == target {
+ return true
+ }
+
+ unwrapped := errors.Unwrap(err)
+ if unwrapped == target {
+ return true
+ }
+
+ return unwrapped != nil && errors.Is(unwrapped, target)
}
// deviceByAddrs finds the profile and the device by the remote and local
-// addresses depending on the data and the server settings.
+// addresses depending on the data and the server settings. err is only not nil
+// when it's not a not-found error from the profile database.
func (ds *Default) deviceByAddrs(
ctx context.Context,
laddr netip.AddrPort,
@@ -88,6 +181,8 @@ func (ds *Default) deviceByAddrs(
if ds.srv.BindsToInterfaces() && !ds.srv.HasAddr(laddr) {
prof, dev, err = ds.deviceByLocalAddr(ctx, laddr.Addr())
if err != nil {
+ // Don't wrap the error, as this is a hot path, and an error about
+ // an unknown dedicated address might be common here.
return nil, nil, "", err
}
@@ -95,30 +190,36 @@ func (ds *Default) deviceByAddrs(
}
if !ds.srv.LinkedIPEnabled {
- return nil, nil, "", profiledb.ErrDeviceNotFound
+ return nil, nil, "", nil
}
prof, dev, err = ds.db.ProfileByLinkedIP(ctx, remoteIP)
if err != nil {
- return nil, nil, "", err
+ // Don't wrap the error, as this is a hot path, and an error other than
+ // a not-found one is unlikely.
+ return nil, nil, "", removeNotFound(err)
}
return prof, dev, byLinkedIP, nil
}
// deviceByLocalAddr finds the profile and the device by the local address.
+// deviceByLocalAddr replaces profiledb's not-found errors with
+// [ErrUnknownDedicated].
func (ds *Default) deviceByLocalAddr(
ctx context.Context,
localIP netip.Addr,
) (prof *agd.Profile, dev *agd.Device, err error) {
prof, dev, err = ds.db.ProfileByDedicatedIP(ctx, localIP)
if err != nil {
- if errors.Is(err, profiledb.ErrDeviceNotFound) {
+ if isProfileDBNotFound(err) {
optlog.Debug1("devicesetter: unknown dedicated ip for server %s; dropping", ds.srv.Name)
err = ErrUnknownDedicated
}
+ // Don't wrap the error, as this is a hot path, and a not-found error is
+ // common here.
return nil, nil, err
}
diff --git a/internal/dnssvc/internal/devicesetter/device_test.go b/internal/dnssvc/internal/devicesetter/device_test.go
index 10ce7ca..d5808d5 100644
--- a/internal/dnssvc/internal/devicesetter/device_test.go
+++ b/internal/dnssvc/internal/devicesetter/device_test.go
@@ -3,6 +3,7 @@ package devicesetter_test
import (
"context"
"net/netip"
+ "strings"
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
@@ -10,6 +11,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicesetter"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
@@ -44,7 +46,7 @@ func TestDefault_SetDevice_plainAddrs(t *testing.T) {
wantDev: devNormal,
wantErrMsg: "",
laddr: dnssvctest.ServerAddrPort,
- raddr: linkedAddrPort,
+ raddr: dnssvctest.LinkedAddrPort,
name: "linked_ip",
}, {
req: reqNormal,
@@ -53,7 +55,7 @@ func TestDefault_SetDevice_plainAddrs(t *testing.T) {
wantDev: nil,
wantErrMsg: "",
laddr: dnssvctest.ServerAddrPort,
- raddr: linkedAddrPort,
+ raddr: dnssvctest.LinkedAddrPort,
name: "linked_ip_not_supported",
}, {
req: reqNormal,
@@ -61,7 +63,7 @@ func TestDefault_SetDevice_plainAddrs(t *testing.T) {
wantProf: profNormal,
wantDev: devNormal,
wantErrMsg: "",
- laddr: dedicatedAddrPort,
+ laddr: dnssvctest.DedicatedAddrPort,
raddr: dnssvctest.ClientAddrPort,
name: "dedicated",
}, {
@@ -79,7 +81,7 @@ func TestDefault_SetDevice_plainAddrs(t *testing.T) {
wantProf: nil,
wantDev: nil,
wantErrMsg: "",
- laddr: dedicatedAddrPort,
+ laddr: dnssvctest.DedicatedAddrPort,
raddr: dnssvctest.ClientAddrPort,
name: "dedicated_not_supported",
}}
@@ -89,18 +91,38 @@ func TestDefault_SetDevice_plainAddrs(t *testing.T) {
t.Parallel()
profDB := &agdtest.ProfileDB{
- OnProfileByDedicatedIP: newOnProfileByDedicatedIP(dedicatedAddr),
+ 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")
},
- OnProfileByLinkedIP: newOnProfileByLinkedIP(linkedAddr),
+
+ OnProfileByHumanID: func(
+ _ context.Context,
+ _ agd.ProfileID,
+ _ agd.HumanIDLower,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ panic("not implemented")
+ },
+
+ OnProfileByLinkedIP: newOnProfileByLinkedIP(dnssvctest.LinkedAddr),
}
pf := devicesetter.NewDefault(&devicesetter.Config{
ProfileDB: profDB,
+ HumanIDParser: agd.NewHumanIDParser(),
Server: tc.srv,
DeviceIDWildcards: nil,
})
@@ -171,13 +193,32 @@ func TestDefault_SetDevice_plainEDNS(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,
@@ -188,6 +229,7 @@ func TestDefault_SetDevice_plainEDNS(t *testing.T) {
pf := devicesetter.NewDefault(&devicesetter.Config{
ProfileDB: profDB,
+ HumanIDParser: agd.NewHumanIDParser(),
Server: tc.srv,
DeviceIDWildcards: nil,
})
@@ -209,18 +251,37 @@ func TestDefault_SetDevice_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,
@@ -230,11 +291,12 @@ func TestDefault_SetDevice_deleted(t *testing.T) {
}
pf := devicesetter.NewDefault(&devicesetter.Config{
- ProfileDB: profDB,
- Server: srvPlainWithLinkedIP,
+ ProfileDB: profDB,
+ HumanIDParser: agd.NewHumanIDParser(),
+ Server: srvPlainWithLinkedIP,
})
- raddr := linkedAddrPort
+ raddr := dnssvctest.LinkedAddrPort
msgCons := agdtest.NewConstructor()
ri := &agd.RequestInfo{
Messages: msgCons,
@@ -249,3 +311,71 @@ func TestDefault_SetDevice_deleted(t *testing.T) {
assert.Nil(t, ri.Device)
assert.Same(t, msgCons, ri.Messages)
}
+
+func TestDefault_SetDevice_byHumanID(t *testing.T) {
+ t.Parallel()
+
+ // Use uppercase versions to make sure that the device setter recognizes the
+ // 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")
+ },
+ }
+
+ df := devicesetter.NewDefault(&devicesetter.Config{
+ ProfileDB: profDB,
+ HumanIDParser: agd.NewHumanIDParser(),
+ Server: srvDoT,
+ DeviceIDWildcards: []string{dnssvctest.DomainForDevices},
+ })
+
+ ctx := dnsserver.ContextWithRequestInfo(context.Background(), &dnsserver.RequestInfo{
+ TLSServerName: extIDStr + "." + dnssvctest.DomainForDevices,
+ })
+ ri := &agd.RequestInfo{
+ RemoteIP: dnssvctest.ClientAddr,
+ }
+
+ err := df.SetDevice(ctx, reqNormal, ri, dnssvctest.ServerAddrPort)
+ require.NoError(t, err)
+
+ assert.Equal(t, profNormal, ri.Profile)
+ assert.Equal(t, devAuto, ri.Device)
+}
diff --git a/internal/dnssvc/internal/devicesetter/deviceid.go b/internal/dnssvc/internal/devicesetter/devicedata.go
similarity index 63%
rename from internal/dnssvc/internal/devicesetter/deviceid.go
rename to internal/dnssvc/internal/devicesetter/devicedata.go
index 5092a16..bbb6b08 100644
--- a/internal/dnssvc/internal/devicesetter/deviceid.go
+++ b/internal/dnssvc/internal/devicesetter/devicedata.go
@@ -28,93 +28,102 @@ func supportsDeviceID(p agd.Protocol) (ok bool) {
}
}
-// deviceID extracts the device ID from the given parameters. If the device ID
-// is not found, it returns an empty ID and nil, as the lookup could also be
+// deviceData extracts the device data from the given parameters. If the device
+// data are not found, all results will be empty, as the lookup could also be
// done later by remote and local addresses.
-func (ds *Default) deviceID(
+func (ds *Default) deviceData(
req *dns.Msg,
srvReqInfo *dnsserver.RequestInfo,
-) (id agd.DeviceID, err error) {
+) (id agd.DeviceID, extID *extHumanID, err error) {
if ds.srv.Protocol.IsStdEncrypted() {
- return ds.deviceIDFromSrvReqInfo(srvReqInfo)
+ return ds.deviceDataFromSrvReqInfo(srvReqInfo)
}
- return deviceIDFromEDNS(req)
+ id, err = deviceIDFromEDNS(req)
+
+ return id, nil, err
}
-// deviceIDFromSrvReqInfo extracts device ID from the arguments. The ID is
-// extracted in the following manner:
+// deviceDataFromSrvReqInfo extracts device data from the arguments. The data
+// are extracted in the following manner:
//
-// 1. If applicable, the ID is firstly extracted from the DoH information, such
+// 1. If applicable, the data is first extracted from the DoH information, such
// as the userinfo or URL path.
//
-// 2. Secondly, the TLS Server Name is inspected using ds's device ID
-// wildcards.
+// 2. Secondly, the TLS Server Name is inspected using the device-ID wildcards
+// configured for the device setter.
//
// Any returned errors will have the underlying type of [*deviceIDError].
-func (ds *Default) deviceIDFromSrvReqInfo(
+func (ds *Default) deviceDataFromSrvReqInfo(
srvReqInfo *dnsserver.RequestInfo,
-) (id agd.DeviceID, err error) {
+) (id agd.DeviceID, extID *extHumanID, err error) {
if ds.srv.Protocol == agd.ProtoDoH {
- id, err = deviceIDForDoH(srvReqInfo)
- if id != "" || err != nil {
+ id, extID, err = ds.deviceDataForDoH(srvReqInfo)
+ if id != "" || extID != nil || err != nil {
// Don't wrap the error, because it's informative enough as is.
- return id, err
+ return id, extID, err
}
}
if len(ds.wildcardDomains) == 0 {
- return "", nil
+ return "", nil, nil
}
- id, err = ds.deviceIDFromCliSrvName(srvReqInfo.TLSServerName)
+ id, extID, err = ds.deviceDataFromCliSrvName(srvReqInfo.TLSServerName)
if err != nil {
- return "", newDeviceIDError(err, "tls server name")
+ return "", nil, newDeviceDataError(err, "tls server name")
}
- return id, nil
+ return id, extID, nil
}
-// deviceIDForDoH extracts a device ID from the DoH request information. The ID
-// is extracted firstly from the request's userinfo, if any, and then from the
-// URL path. srvReqInfo must not be nil.
+// deviceDataForDoH extracts the device data from the DoH request information.
+// The data are extracted first from the request's userinfo, if any, and then
+// from the URL path. srvReqInfo must not be nil.
//
-// Any returned errors will have the underlying type of [*deviceIDError].
-func deviceIDForDoH(srvReqInfo *dnsserver.RequestInfo) (id agd.DeviceID, err error) {
+// Any returned errors will have the underlying type of [*deviceDataError].
+func (ds *Default) deviceDataForDoH(
+ srvReqInfo *dnsserver.RequestInfo,
+) (id agd.DeviceID, extID *extHumanID, err error) {
if userinfo := srvReqInfo.Userinfo; userinfo != nil {
+ // Don't scan the userinfo for human-readable IDs, since they're not
+ // supported there.
id, err = agd.NewDeviceID(userinfo.Username())
if err != nil {
- return "", newDeviceIDError(err, "basic auth")
+ return "", nil, newDeviceDataError(err, "basic auth")
}
- return id, nil
+ return id, nil, nil
}
- id, err = deviceIDFromDoHURL(srvReqInfo.URL)
+ id, extID, err = ds.deviceDataFromDoHURL(srvReqInfo.URL)
if err != nil {
- return "", newDeviceIDError(err, "http url path")
+ return "", nil, newDeviceDataError(err, "http url path")
}
- // In case of empty device ID, we will continue the lookup process.
- return id, nil
+ // In case of empty device data, will continue the lookup process.
+ return id, extID, nil
}
-// deviceIDFromDoHURL extracts the device ID from the path of the DoH request.
-func deviceIDFromDoHURL(u *url.URL) (id agd.DeviceID, err error) {
+// deviceDataFromDoHURL extracts the device data from the path of the DoH
+// request.
+func (ds *Default) deviceDataFromDoHURL(
+ u *url.URL,
+) (id agd.DeviceID, extID *extHumanID, err error) {
parts, err := pathParts(u.Path)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
- return "", err
+ return "", nil, err
}
if len(parts) == 2 {
// Don't wrap the error, because it's informative enough as is.
- return agd.NewDeviceID(parts[1])
+ return ds.parseDeviceData(parts[1])
}
// pathParts guarantees that if there aren't two parts, there's only one,
// and it is a valid DNS path.
- return "", nil
+ return "", nil, nil
}
// pathParts splits and validates urlPath. If err is nil, parts has either one
@@ -142,35 +151,36 @@ func pathParts(urlPath string) (parts []string, err error) {
return parts, nil
}
-// deviceIDFromCliSrvName extracts and validates a device ID. cliSrvName is the
-// server name as sent by the client.
-func (ds *Default) deviceIDFromCliSrvName(cliSrvName string) (id agd.DeviceID, err error) {
+// deviceDataFromCliSrvName extracts and validates device data. cliSrvName is
+// the server name as sent by the client.
+func (ds *Default) deviceDataFromCliSrvName(
+ cliSrvName string,
+) (id agd.DeviceID, extID *extHumanID, err error) {
if cliSrvName == "" {
// No server name in ClientHello, so the request is probably made on the
// IP address.
- return "", nil
+ return "", nil, nil
}
matchedDomain := matchDomain(cliSrvName, ds.wildcardDomains)
if matchedDomain == "" {
- return "", nil
+ return "", nil, nil
}
optlog.Debug2("devicesetter: device id: matched %q from %q", matchedDomain, ds.wildcardDomains)
idStr := cliSrvName[:len(cliSrvName)-len(matchedDomain)-1]
- id, err = agd.NewDeviceID(idStr)
- if err != nil {
- // Don't wrap the error, because it's informative enough as is.
- return "", err
- }
- return id, nil
+ // Don't wrap the error, because it's informative enough as is.
+ return ds.parseDeviceData(idStr)
}
// matchDomain searches among domains for one the subdomain of which is sub. If
// there is no such domain, matchDomain returns an empty string.
func matchDomain(sub string, domains []string) (matchedDomain string) {
+ // TODO(a.garipov): Remove once netutil learns how to match domains in a
+ // case-insensitive way.
+ sub = strings.ToLower(sub)
for _, domain := range domains {
if netutil.IsImmediateSubdomain(sub, domain) {
return domain
@@ -195,7 +205,7 @@ const DnsmasqCPEIDOption uint16 = 65074
// dig @94.140.14.49 'edns-id.example' IN A\
// +ednsopt=65074:"$( printf 'abcd1234' | od -A n -t x1 | tr -d ' ' )"
//
-// Any returned errors will have the underlying type of [*deviceIDError].
+// Any returned errors will have the underlying type of [*deviceDataError].
func deviceIDFromEDNS(req *dns.Msg) (id agd.DeviceID, err error) {
option := req.IsEdns0()
if option == nil {
@@ -227,7 +237,7 @@ func deviceIDFromENDSOPT(opt dns.EDNS0) (id agd.DeviceID, err error) {
id, err = agd.NewDeviceID(string(o.Data))
if err != nil {
- return "", newDeviceIDError(err, "edns option")
+ return "", newDeviceDataError(err, "edns option")
}
return id, nil
diff --git a/internal/dnssvc/internal/devicesetter/deviceid_test.go b/internal/dnssvc/internal/devicesetter/devicedata_test.go
similarity index 84%
rename from internal/dnssvc/internal/devicesetter/deviceid_test.go
rename to internal/dnssvc/internal/devicesetter/devicedata_test.go
index 2c4ff0f..1dda733 100644
--- a/internal/dnssvc/internal/devicesetter/deviceid_test.go
+++ b/internal/dnssvc/internal/devicesetter/devicedata_test.go
@@ -89,12 +89,22 @@ func TestDefault_SetDevice_DoHAuth(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,
@@ -105,6 +115,15 @@ func TestDefault_SetDevice_DoHAuth(t *testing.T) {
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,
@@ -115,6 +134,7 @@ func TestDefault_SetDevice_DoHAuth(t *testing.T) {
df := devicesetter.NewDefault(&devicesetter.Config{
ProfileDB: profDB,
+ HumanIDParser: agd.NewHumanIDParser(),
Server: srvDoH,
DeviceIDWildcards: []string{},
})
@@ -205,18 +225,37 @@ func TestDefault_SetDevice_DoHAuthOnly(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,
@@ -227,6 +266,7 @@ func TestDefault_SetDevice_DoHAuthOnly(t *testing.T) {
df := devicesetter.NewDefault(&devicesetter.Config{
ProfileDB: profDB,
+ HumanIDParser: agd.NewHumanIDParser(),
Server: tc.srv,
DeviceIDWildcards: []string{dnssvctest.DeviceIDWildcard},
})
@@ -311,16 +351,37 @@ func TestDefault_SetDevice_DoH(t *testing.T) {
},
wantErrMsg: `http url path device id check: bad path "/other": not a dns path`,
name: "not_dns_path",
+ }, {
+ wantProf: profNormal,
+ wantDev: devAuto,
+ reqURL: &url.URL{
+ Path: path.Join(dnsserver.PathDoH, dnssvctest.HumanIDPath),
+ },
+ wantErrMsg: "",
+ 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,
@@ -335,6 +396,7 @@ func TestDefault_SetDevice_DoH(t *testing.T) {
df := devicesetter.NewDefault(&devicesetter.Config{
ProfileDB: profDB,
+ HumanIDParser: agd.NewHumanIDParser(),
Server: srvDoH,
DeviceIDWildcards: []string{},
})
@@ -401,16 +463,36 @@ func TestDefault_SetDevice_stdEncrypted(t *testing.T) {
cliSrvName: "!!!.d.dns.example",
name: "bad_id",
wildcards: []string{dnssvctest.DeviceIDWildcard},
+ }, {
+ wantProf: profNormal,
+ wantDev: devAuto,
+ wantErrMsg: "",
+ cliSrvName: dnssvctest.HumanIDSrvName,
+ name: "human_id_match",
+ wildcards: []string{dnssvctest.DeviceIDWildcard},
}}
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,
@@ -446,6 +528,7 @@ func TestDefault_SetDevice_stdEncrypted(t *testing.T) {
df := devicesetter.NewDefault(&devicesetter.Config{
ProfileDB: profDB,
+ HumanIDParser: agd.NewHumanIDParser(),
Server: sd.srv,
DeviceIDWildcards: tc.wildcards,
})
diff --git a/internal/dnssvc/internal/devicesetter/devicesetter.go b/internal/dnssvc/internal/devicesetter/devicesetter.go
index 455f47c..0e54612 100644
--- a/internal/dnssvc/internal/devicesetter/devicesetter.go
+++ b/internal/dnssvc/internal/devicesetter/devicesetter.go
@@ -44,10 +44,10 @@ var _ Interface = Empty{}
// SetDevice implements the [Interface] interface for Empty. It does nothing
// and returns nil.
func (Empty) SetDevice(
- ctx context.Context,
- req *dns.Msg,
- ri *agd.RequestInfo,
- laddr netip.AddrPort,
+ _ context.Context,
+ _ *dns.Msg,
+ _ *agd.RequestInfo,
+ _ netip.AddrPort,
) (err error) {
return nil
}
@@ -57,6 +57,10 @@ type Config struct {
// ProfileDB is used to find the profiles. It must not be nil.
ProfileDB profiledb.Interface
+ // HumanIDParser is used to normalize and parse human-readable device
+ // identifiers.
+ HumanIDParser *agd.HumanIDParser
+
// Server contains the data of the server for which the profiles are found.
// It must not be nil.
Server *agd.Server
@@ -69,6 +73,7 @@ type Config struct {
// Default is the default profile setter.
type Default struct {
db profiledb.Interface
+ humanIDParser *agd.HumanIDParser
srv *agd.Server
wildcardDomains []string
}
@@ -83,6 +88,7 @@ func NewDefault(c *Config) (ds *Default) {
return &Default{
db: c.ProfileDB,
+ humanIDParser: c.HumanIDParser,
srv: c.Server,
wildcardDomains: wildcardDomains,
}
@@ -104,13 +110,13 @@ func (ds *Default) SetDevice(
}
srvReqInfo := dnsserver.MustRequestInfoFromContext(ctx)
- id, err := ds.deviceID(req, srvReqInfo)
+ id, extID, err := ds.deviceData(req, srvReqInfo)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
}
- prof, dev, err := ds.findDevice(ctx, laddr, ri.RemoteIP, id)
+ prof, dev, err := ds.findDevice(ctx, laddr, ri.RemoteIP, id, extID)
if err != nil {
// Likely [errUnknownDedicated].
return fmt.Errorf("setting profile: %w", err)
diff --git a/internal/dnssvc/internal/devicesetter/devicesetter_test.go b/internal/dnssvc/internal/devicesetter/devicesetter_test.go
index 4004fd5..f7b2f7c 100644
--- a/internal/dnssvc/internal/devicesetter/devicesetter_test.go
+++ b/internal/dnssvc/internal/devicesetter/devicesetter_test.go
@@ -107,17 +107,6 @@ var (
}
)
-// Common addresses for tests.
-//
-// TODO(a.garipov): Move more common variables and constants to dnssvctest.
-var (
- linkedAddr = netip.MustParseAddr("192.0.2.1")
- dedicatedAddr = netip.MustParseAddr("192.0.2.2")
-
- linkedAddrPort = netip.AddrPortFrom(linkedAddr, 12345)
- dedicatedAddrPort = netip.AddrPortFrom(dedicatedAddr, 53)
-)
-
// Common profiles and devices for tests.
var (
profNormal = &agd.Profile{
@@ -139,7 +128,15 @@ var (
Enabled: false,
},
ID: dnssvctest.DeviceID,
- LinkedIP: linkedAddr,
+ LinkedIP: dnssvctest.LinkedAddr,
+ }
+
+ devAuto = &agd.Device{
+ Auth: &agd.AuthSettings{
+ Enabled: false,
+ },
+ ID: dnssvctest.DeviceID,
+ HumanIDLower: dnssvctest.HumanIDLower,
}
)
@@ -189,6 +186,32 @@ func newOnProfileByDeviceID(
}
}
+// newOnProfileByHumanID returns a function with the type of
+// [agdtest.ProfileDB.OnProfileByHumanID] that returns p and d only when id and
+// humanID are equal to the given one.
+func newOnProfileByHumanID(
+ wantProfID agd.ProfileID,
+ wantHumanID agd.HumanIDLower,
+) (
+ f func(
+ _ context.Context,
+ id agd.ProfileID,
+ humanID agd.HumanIDLower,
+ ) (p *agd.Profile, d *agd.Device, err error),
+) {
+ return func(
+ _ context.Context,
+ id agd.ProfileID,
+ humanID agd.HumanIDLower,
+ ) (p *agd.Profile, d *agd.Device, err error) {
+ if id == wantProfID && humanID == wantHumanID {
+ return profNormal, devAuto, nil
+ }
+
+ return nil, nil, profiledb.ErrDeviceNotFound
+ }
+}
+
// newOnProfileByLinkedIP returns a function with the type of
// [agdtest.ProfileDB.OnProfileByLinkedIP] that returns p and d only when
// remoteIP is equal to the given one.
@@ -208,6 +231,7 @@ func TestDefault_SetDevice_dnscrypt(t *testing.T) {
t.Parallel()
df := devicesetter.NewDefault(&devicesetter.Config{
+ HumanIDParser: agd.NewHumanIDParser(),
Server: &agd.Server{
Protocol: agd.ProtoDNSCrypt,
},
diff --git a/internal/dnssvc/internal/devicesetter/error.go b/internal/dnssvc/internal/devicesetter/error.go
index 3517989..aa0fa37 100644
--- a/internal/dnssvc/internal/devicesetter/error.go
+++ b/internal/dnssvc/internal/devicesetter/error.go
@@ -14,38 +14,38 @@ const (
ErrUnknownDedicated errors.Error = "unknown dedicated ip"
)
-// deviceIDError is an error about bad device ID or other issues found during
-// device ID checking.
-type deviceIDError struct {
+// deviceDataError is an error about bad device data or other issues found
+// during device data checking.
+type deviceDataError struct {
err error
typ string
}
// type check
-var _ error = (*deviceIDError)(nil)
+var _ error = (*deviceDataError)(nil)
-// newDeviceIDError is a helper constructor for device-ID errors.
-func newDeviceIDError(orig error, typ string) (err error) {
- return &deviceIDError{
+// newDeviceDataError is a helper constructor for device-data errors.
+func newDeviceDataError(orig error, typ string) (err error) {
+ return &deviceDataError{
err: orig,
typ: typ,
}
}
-// Error implements the error interface for *deviceIDError.
-func (err *deviceIDError) Error() (msg string) {
+// Error implements the error interface for *deviceDataError.
+func (err *deviceDataError) Error() (msg string) {
return fmt.Sprintf("%s device id check: %s", err.typ, err.err)
}
// type check
-var _ errors.Wrapper = (*deviceIDError)(nil)
+var _ errors.Wrapper = (*deviceDataError)(nil)
-// Unwrap implements the [errors.Wrapper] interface for *deviceIDError.
-func (err *deviceIDError) Unwrap() (unwrapped error) { return err.err }
+// Unwrap implements the [errors.Wrapper] interface for *deviceDataError.
+func (err *deviceDataError) Unwrap() (unwrapped error) { return err.err }
// type check
-var _ errcoll.SentryReportableError = (*deviceIDError)(nil)
+var _ errcoll.SentryReportableError = (*deviceDataError)(nil)
// IsSentryReportable implements the [errcoll.SentryReportableError] interface
-// for *deviceIDError.
-func (*deviceIDError) IsSentryReportable() (ok bool) { return false }
+// for *deviceDataError.
+func (*deviceDataError) IsSentryReportable() (ok bool) { return false }
diff --git a/internal/dnssvc/internal/devicesetter/humanid.go b/internal/dnssvc/internal/devicesetter/humanid.go
new file mode 100644
index 0000000..18c8142
--- /dev/null
+++ b/internal/dnssvc/internal/devicesetter/humanid.go
@@ -0,0 +1,86 @@
+package devicesetter
+
+import (
+ "strings"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/golibs/errors"
+)
+
+// extHumanID contains the data that can be parsed from an extended
+// human-readable device identifier.
+//
+// TODO(a.garipov): Optimize its allocation and freeing.
+type extHumanID struct {
+ HumanID agd.HumanID
+ ProfileID agd.ProfileID
+ DeviceType agd.DeviceType
+}
+
+// parseDeviceData returns either the device ID or the extended human-readable
+// ID data depending on what it can parse from the given string.
+//
+// TODO(a.garipov): Optimize error handling etc. based on profiles.
+func (ds *Default) parseDeviceData(s string) (id agd.DeviceID, extID *extHumanID, err error) {
+ if isLikelyExtHumanID(s) {
+ extID, err = ds.parseExtHumanID(s)
+
+ // Don't wrap the error, because it's informative enough as is.
+ return "", extID, err
+ }
+
+ // TODO(a.garipov): Remove once the profile database learns how to match
+ // IDs in a case-insensitive way.
+ s = strings.ToLower(s)
+ id, err = agd.NewDeviceID(s)
+
+ // Don't wrap the error, because it's informative enough as is.
+ return id, nil, err
+}
+
+// isLikelyExtHumanID returns true if s likely contains extended human-readable
+// device-ID information.
+func isLikelyExtHumanID(s string) (ok bool) {
+ return strings.Count(s, "-") >= 2
+}
+
+// parseExtHumanID parses the data about a device that is identified by a device
+// type, a profile ID, and a human-readable device ID.
+func (ds *Default) parseExtHumanID(s string) (extID *extHumanID, err error) {
+ defer func() { err = errors.Annotate(err, "parsing %q: %w", s) }()
+
+ parts := strings.SplitN(s, "-", 3)
+ if len(parts) != 3 {
+ // Technically shouldn't happen, as this function should only be called
+ // when isLikelyExtHumanID(s) is true.
+ return nil, errors.Error("not a valid ext human id")
+ }
+
+ // TODO(a.garipov): Use normalization.
+ dt, err := agd.DeviceTypeFromDNS(parts[0])
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return nil, err
+ }
+
+ // TODO(a.garipov): Remove once the profile database learns how to match
+ // IDs in a case-insensitive way.
+ profIDStr := strings.ToLower(parts[1])
+ profID, err := agd.NewProfileID(profIDStr)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return nil, err
+ }
+
+ humanID, err := ds.humanIDParser.ParseNormalized(parts[2])
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return nil, err
+ }
+
+ return &extHumanID{
+ HumanID: humanID,
+ ProfileID: profID,
+ DeviceType: dt,
+ }, nil
+}
diff --git a/internal/dnssvc/internal/devicesetter/humanid_test.go b/internal/dnssvc/internal/devicesetter/humanid_test.go
new file mode 100644
index 0000000..994ff40
--- /dev/null
+++ b/internal/dnssvc/internal/devicesetter/humanid_test.go
@@ -0,0 +1,100 @@
+package devicesetter_test
+
+import (
+ "context"
+ "net/netip"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicesetter"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/dnssvctest"
+ "github.com/AdguardTeam/golibs/testutil"
+)
+
+func TestDefault_SetDevice_humanID(t *testing.T) {
+ testCases := []struct {
+ name string
+ in string
+ wantErrMsg string
+ }{{
+ name: "bad_type",
+ in: "!!!-abcd1234-My-Device-X--10",
+ wantErrMsg: `tls server name device id check: parsing "!!!-abcd1234-My-Device-X--10": ` +
+ `bad device type "!!!": unknown device type`,
+ }, {
+ name: "bad_profile_id",
+ in: "otr-\x00-My-Device-X--10",
+ wantErrMsg: `tls server name device id check: parsing "otr-\x00-My-Device-X--10": ` +
+ `bad profile id: bad char '\x00' at index 0`,
+ }, {
+ name: "bad_human_id",
+ in: "otr-abcd1234-!!!",
+ wantErrMsg: `tls server name device id check: parsing "otr-abcd1234-!!!": ` +
+ `bad non-normalized human id "!!!": cannot normalize`,
+ }}
+
+ 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 := devicesetter.NewDefault(&devicesetter.Config{
+ ProfileDB: profDB,
+ HumanIDParser: agd.NewHumanIDParser(),
+ Server: srvDoT,
+ DeviceIDWildcards: []string{dnssvctest.DomainForDevices},
+ })
+
+ ctx := dnsserver.ContextWithRequestInfo(context.Background(), &dnsserver.RequestInfo{
+ TLSServerName: tc.in + "." + dnssvctest.DomainForDevices,
+ })
+ ri := &agd.RequestInfo{
+ RemoteIP: dnssvctest.ClientAddr,
+ }
+
+ err := df.SetDevice(ctx, reqNormal, ri, dnssvctest.ServerAddrPort)
+ testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
+ })
+ }
+}
diff --git a/internal/dnssvc/internal/dnssvctest/dnssvctest.go b/internal/dnssvc/internal/dnssvctest/dnssvctest.go
index dd596d8..fd68a68 100644
--- a/internal/dnssvc/internal/dnssvctest/dnssvctest.go
+++ b/internal/dnssvc/internal/dnssvctest/dnssvctest.go
@@ -5,6 +5,7 @@ package dnssvctest
import (
"crypto/tls"
"net"
+ "net/netip"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
@@ -14,18 +15,19 @@ import (
// Timeout is the common timeout for tests.
const Timeout time.Duration = 1 * time.Second
-// String representations of the common IDs for tests.
+// Common IDs for tests and their string representations.
const (
- DeviceIDStr = "dev1234"
- ProfileIDStr = "prof1234"
+ DeviceIDStr = "dev1234"
+ ProfileIDStr = "prof1234"
+ HumanIDStr = "My-Device-X--10"
+ HumanIDLowerStr = "my-device-x--10"
+
+ DeviceID agd.DeviceID = DeviceIDStr
+ ProfileID agd.ProfileID = ProfileIDStr
+ HumanID agd.HumanID = HumanIDStr
+ HumanIDLower agd.HumanIDLower = HumanIDLowerStr
)
-// DeviceID is the common device ID for tests.
-const DeviceID agd.DeviceID = DeviceIDStr
-
-// ProfileID is the common profile ID for tests.
-const ProfileID agd.ProfileID = ProfileIDStr
-
// String representations for the common filtering-rule list ID for tests.
const (
FilterListID1Str = "flt_1"
@@ -66,28 +68,62 @@ const (
// [agd.DeviceID] or use [DeviceIDSrvName].
DeviceIDWildcard = "*." + DomainForDevices
- // DeviceIDSrvName is the common client server-name for tests.
+ // DeviceIDSrvName is the common client server-name with a device ID for
+ // tests.
DeviceIDSrvName = DeviceIDStr + "." + DomainForDevices
+
+ // HumanIDPath is the common client URL path with human-readable device-data
+ // for tests.
+ HumanIDPath = "otr-" + ProfileIDStr + "-" + HumanIDStr
+
+ // HumanIDSrvName is the common client server-name with human-readable
+ // device-data for tests.
+ HumanIDSrvName = HumanIDPath + "." + DomainForDevices
+)
+
+// Use a constant block with iota to keep track of the unique final bytes of IP
+// addresses more easily.
+const (
+ ipByteZero = iota
+ ipByteClient
+ ipByteServer
+ ipByteDomain
+ ipByteLinked
+ ipByteDedicated
)
// Common addresses for tests.
var (
- ClientIP = net.IP{1, 2, 3, 4}
- RemoteAddr = &net.TCPAddr{
+ ClientIP = net.IP{192, 0, 2, ipByteClient}
+ ClientTCPAddr = &net.TCPAddr{
IP: ClientIP,
Port: 12345,
}
- ClientAddrPort = RemoteAddr.AddrPort()
+ ClientAddrPort = ClientTCPAddr.AddrPort()
ClientAddr = ClientAddrPort.Addr()
- LocalAddr = &net.TCPAddr{
- IP: net.IP{5, 6, 7, 8},
+ ServerTCPAddr = &net.TCPAddr{
+ IP: net.IP{192, 0, 2, ipByteServer},
Port: 54321,
}
- ServerAddrPort = LocalAddr.AddrPort()
+ ServerAddrPort = ServerTCPAddr.AddrPort()
ServerAddr = ServerAddrPort.Addr()
+
+ DomainAddrIPv4 = netip.AddrFrom4([4]byte{192, 0, 2, ipByteDomain})
+ DomainAddrIPv6 = netip.AddrFrom16([16]byte{
+ 0x20, 0x01, 0x0d, 0xb8,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, ipByteDomain,
+ })
+
+ LinkedAddr = netip.AddrFrom4([4]byte{192, 0, 2, ipByteLinked})
+ LinkedAddrPort = netip.AddrPortFrom(LinkedAddr, 12345)
+
+ DedicatedAddr = netip.AddrFrom4([4]byte{192, 0, 2, ipByteDedicated})
+ DedicatedAddrPort = netip.AddrPortFrom(DedicatedAddr, 53)
)
// NewServer is a helper that returns a new *agd.Server for tests.
diff --git a/internal/dnssvc/internal/initial/initial_test.go b/internal/dnssvc/internal/initial/initial_test.go
index ff52448..e5de34c 100644
--- a/internal/dnssvc/internal/initial/initial_test.go
+++ b/internal/dnssvc/internal/initial/initial_test.go
@@ -170,7 +170,7 @@ func TestMiddleware_Wrap(t *testing.T) {
TLSServerName: srvNameForProto(tc.device, resolverName, tc.srv.Protocol),
})
- rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.RemoteAddr)
+ rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.ClientTCPAddr)
req := &dns.Msg{
Question: []dns.Question{{
Name: tc.host,
@@ -278,7 +278,7 @@ func TestMiddleware_Wrap_error(t *testing.T) {
ctx := context.Background()
ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{})
- rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.RemoteAddr)
+ rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.ClientTCPAddr)
req := &dns.Msg{
Question: []dns.Question{{
Name: "www.example.com.",
@@ -652,7 +652,7 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
return rw.WriteMsg(ctx, req, resp)
})
- rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.RemoteAddr)
+ rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.ClientTCPAddr)
b.Run("success", func(b *testing.B) {
ds := &dnssvctest.DeviceSetter{
diff --git a/internal/dnssvc/internal/initial/specialdomain_test.go b/internal/dnssvc/internal/initial/specialdomain_test.go
index 0f6fa67..e231d80 100644
--- a/internal/dnssvc/internal/initial/specialdomain_test.go
+++ b/internal/dnssvc/internal/initial/specialdomain_test.go
@@ -203,7 +203,7 @@ func TestMiddleware_ServeDNS_specialDomain(t *testing.T) {
ctx := context.Background()
ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{})
- rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.RemoteAddr)
+ rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.ClientTCPAddr)
req := &dns.Msg{
Question: []dns.Question{{
Name: dns.Fqdn(tc.host),
diff --git a/internal/dnssvc/internal/mainmw/debug.go b/internal/dnssvc/internal/mainmw/debug.go
index f3ff608..e4e0048 100644
--- a/internal/dnssvc/internal/mainmw/debug.go
+++ b/internal/dnssvc/internal/mainmw/debug.go
@@ -17,17 +17,19 @@ import (
// Debug header name constants.
const (
- hdrNameResType = "res-type"
- hdrNameRuleListID = "rule-list-id"
- hdrNameRule = "rule"
- hdrNameClientIP = "client-ip"
- hdrNameServerIP = "server-ip"
- hdrNameDeviceID = "device-id"
- hdrNameProfileID = "profile-id"
- hdrNameCountry = "country"
hdrNameASN = "asn"
+ hdrNameClientIP = "client-ip"
+ hdrNameCountry = "country"
+ hdrNameDeviceID = "device-id"
+ hdrNameHumanID = "human-id"
+ hdrNameProfileID = "profile-id"
+ hdrNameResType = "res-type"
+ hdrNameRule = "rule"
+ hdrNameRuleListID = "rule-list-id"
+ hdrNameServerIP = "server-ip"
hdrNameSubdivision = "subdivision"
- hdrNameHost = "adguard-dns.com."
+
+ hdrDomain = "adguard-dns.com."
)
// writeDebugResponse writes the debug response to rw.
@@ -90,12 +92,10 @@ func (mw *Middleware) appendDebugExtraFromContext(
resp *dns.Msg,
) (err error) {
ri := agd.MustRequestInfoFromContext(ctx)
- if d := ri.Device; d != nil {
- setQuestionName(debugReq, "", hdrNameDeviceID)
- err = mw.messages.AppendDebugExtra(debugReq, resp, string(d.ID))
- if err != nil {
- return fmt.Errorf("adding %s extra: %w", hdrNameDeviceID, err)
- }
+ err = mw.appendDebugExtraFromDevice(ri.Device, debugReq, resp)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return err
}
if p := ri.Profile; p != nil {
@@ -117,8 +117,36 @@ func (mw *Middleware) appendDebugExtraFromContext(
return nil
}
+// appendDebugExtraFromDevice adds debug info to response got from devices data,
+// if any.
+func (mw *Middleware) appendDebugExtraFromDevice(
+ dev *agd.Device,
+ debugReq *dns.Msg,
+ resp *dns.Msg,
+) (err error) {
+ if dev == nil {
+ return nil
+ }
+
+ setQuestionName(debugReq, "", hdrNameDeviceID)
+ err = mw.messages.AppendDebugExtra(debugReq, resp, string(dev.ID))
+ if err != nil {
+ return fmt.Errorf("adding %s extra: %w", hdrNameDeviceID, err)
+ }
+
+ if humanID := dev.HumanIDLower; humanID != "" {
+ setQuestionName(debugReq, "", hdrNameHumanID)
+ err = mw.messages.AppendDebugExtra(debugReq, resp, string(humanID))
+ if err != nil {
+ return fmt.Errorf("adding %s extra: %w", hdrNameHumanID, err)
+ }
+ }
+
+ return nil
+}
+
// appendDebugExtraFromLocation adds debug info to response got from request
-// info location. loc should not be nil.
+// info location. loc must not be nil.
func (mw *Middleware) appendDebugExtraFromLocation(
loc *geoip.Location,
debugReq *dns.Msg,
@@ -221,9 +249,9 @@ func (mw *Middleware) addDebugExtraFromFiltering(
func setQuestionName(req *dns.Msg, prefix, suffix string) {
var strs []string
if prefix == "" {
- strs = []string{suffix, hdrNameHost}
+ strs = []string{suffix, hdrDomain}
} else {
- strs = []string{prefix, suffix, hdrNameHost}
+ strs = []string{prefix, suffix, hdrDomain}
}
req.Question[0].Name = strings.Join(strs, ".")
diff --git a/internal/dnssvc/internal/mainmw/debug_internal_test.go b/internal/dnssvc/internal/mainmw/debug_internal_test.go
index 73d1016..02084a9 100644
--- a/internal/dnssvc/internal/mainmw/debug_internal_test.go
+++ b/internal/dnssvc/internal/mainmw/debug_internal_test.go
@@ -226,7 +226,7 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- rw := dnsserver.NewNonWriterResponseWriter(dnssvctest.LocalAddr, dnssvctest.RemoteAddr)
+ rw := dnsserver.NewNonWriterResponseWriter(dnssvctest.ServerTCPAddr, dnssvctest.ClientTCPAddr)
ctx := agd.ContextWithRequestInfo(context.Background(), tc.reqInfo)
diff --git a/internal/dnssvc/internal/mainmw/mainmw_test.go b/internal/dnssvc/internal/mainmw/mainmw_test.go
index bb700ce..3a39cbd 100644
--- a/internal/dnssvc/internal/mainmw/mainmw_test.go
+++ b/internal/dnssvc/internal/mainmw/mainmw_test.go
@@ -244,7 +244,7 @@ func TestMiddleware_Wrap(t *testing.T) {
h := mw.Wrap(newSimpleHandler(t, tc.req, wantResp))
ctx := newContext(tc.device, tc.profile, reqHost, reqQType, reqStart)
- rw := dnsserver.NewNonWriterResponseWriter(dnssvctest.LocalAddr, dnssvctest.RemoteAddr)
+ rw := dnsserver.NewNonWriterResponseWriter(dnssvctest.ServerTCPAddr, dnssvctest.ClientTCPAddr)
err := h.ServeDNS(ctx, rw, tc.req)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
@@ -707,7 +707,7 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
h := mw.Wrap(newSimpleHandler(t, tc.wantUpsReq, tc.upsResp))
ctx := newContext(tc.device, tc.profile, reqHost, reqQType, reqStart)
- rw := dnsserver.NewNonWriterResponseWriter(dnssvctest.LocalAddr, dnssvctest.RemoteAddr)
+ rw := dnsserver.NewNonWriterResponseWriter(dnssvctest.ServerTCPAddr, dnssvctest.ClientTCPAddr)
err := h.ServeDNS(ctx, rw, tc.req)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
diff --git a/internal/dnssvc/internal/mainmw/record.go b/internal/dnssvc/internal/mainmw/record.go
index 7d9ab70..e4c2d1c 100644
--- a/internal/dnssvc/internal/mainmw/record.go
+++ b/internal/dnssvc/internal/mainmw/record.go
@@ -2,6 +2,7 @@ package mainmw
import (
"context"
+ "fmt"
"net"
"net/netip"
"time"
@@ -11,6 +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/querylog"
"github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
@@ -74,7 +76,7 @@ func (mw *Middleware) recordQueryInfo(
ProfileID: prof.ID,
DeviceID: devID,
ClientCountry: reqCtry,
- ResponseCountry: mw.responseCountry(ctx, fctx, ri, respIP),
+ ResponseCountry: mw.responseCountry(ctx, fctx, ri.Host, respIP, rcode),
DomainFQDN: q.Name,
ClientASN: reqASN,
Elapsed: uint16(time.Since(start).Milliseconds()),
@@ -93,30 +95,34 @@ func (mw *Middleware) recordQueryInfo(
}
// responseCountry returns the country of the response IP address based on the
-// request and filtering data.
+// request and filtering data. If rcode is not a NOERROR one or there is no
+// IP-address data in the response, ctry is [geoip.CountryNotApplicable].
func (mw *Middleware) responseCountry(
ctx context.Context,
fctx *filteringContext,
- ri *agd.RequestInfo,
+ host string,
respIP netip.Addr,
+ rcode dnsmsg.RCode,
) (ctry geoip.Country) {
- if respIP == (netip.Addr{}) || respIP.IsUnspecified() {
- return geoip.CountryNone
+ if rcode != dns.RcodeSuccess || respIP == (netip.Addr{}) || respIP.IsUnspecified() {
+ return geoip.CountryNotApplicable
}
- host := ri.Host
if modReq := fctx.modifiedRequest; modReq != nil {
// If the request was modified by CNAME rule, the actual result
// belongs to the hostname from that CNAME.
host = agdnet.NormalizeDomain(modReq.Question[0].Name)
}
- return mw.country(ctx, host, respIP)
+ ctry = mw.country(ctx, host, respIP)
+ optlog.Debug2("mainmw: got ctry %q for resp ip %v", ctry, respIP)
+
+ return ctry
}
// responseData is a helper that returns the response code, the first IP
// address, and the DNSSEC AD flag from the DNS query response if the answer has
-// the type of A or AAAA or an empty IP address otherwise.
+// the type of A, AAAA, or HTTPS or an empty IP address otherwise.
//
// If resp is nil or contains invalid data, it returns 0xff (an unassigned
// RCODE), net.Addr{}, and false. It reports all errors using
@@ -129,12 +135,23 @@ func (mw *Middleware) responseData(
return 0xff, netip.Addr{}, false
}
+ dnssec = resp.AuthenticatedData
+ rcode = dnsmsg.RCode(resp.Rcode)
+
+ ip, err := ipFromAnswer(resp.Answer)
+ if err != nil {
+ mw.reportf(ctx, "getting response data: %w", err)
+ }
+
+ return rcode, ip, dnssec
+}
+
+// ipFromAnswer returns the first IP address from the answer resource records.
+func ipFromAnswer(answer []dns.RR) (ip netip.Addr, err error) {
var rrType dns.Type
var fam netutil.AddrFamily
var netIP net.IP
- dnssec = resp.AuthenticatedData
- rcode = dnsmsg.RCode(resp.Rcode)
- for _, rr := range resp.Answer {
+ for _, rr := range answer {
switch v := rr.(type) {
case *dns.A:
fam = netutil.AddrFamilyIPv4
@@ -142,6 +159,8 @@ func (mw *Middleware) responseData(
case *dns.AAAA:
fam = netutil.AddrFamilyIPv6
rrType, netIP = dns.Type(v.Hdr.Rrtype), v.AAAA
+ case *dns.HTTPS:
+ return ipFromHTTPSRR(v)
default:
continue
}
@@ -149,15 +168,60 @@ func (mw *Middleware) responseData(
break
}
- if netIP != nil {
- var err error
- ip, err = netutil.IPToAddr(netIP, fam)
- if err != nil {
- mw.reportf(ctx, "converting %s resp data: %w", rrType, err)
+ if netIP == nil {
+ return netip.Addr{}, nil
+ }
+
+ ip, err = netutil.IPToAddr(netIP, fam)
+ if err != nil {
+ return netip.Addr{}, fmt.Errorf("converting %s resp data: %w", rrType, err)
+ }
+
+ return ip, nil
+}
+
+// ipFromHTTPSRR returns the data for the first IP hint in an HTTPS resource
+// record.
+func ipFromHTTPSRR(https *dns.HTTPS) (ip netip.Addr, err error) {
+ var fam netutil.AddrFamily
+ var netIP net.IP
+ for _, v := range https.Value {
+ fam, netIP = ipFromHTTPSRRKV(v)
+ if fam != netutil.AddrFamilyNone {
+ break
}
}
- return rcode, ip, dnssec
+ if netIP == nil {
+ return netip.Addr{}, nil
+ }
+
+ ip, err = netutil.IPToAddr(netIP, fam)
+ if err != nil {
+ return netip.Addr{}, fmt.Errorf("converting https rr %s hint data: %w", fam, err)
+ }
+
+ return ip, nil
+}
+
+// ipFromHTTPSRRKV returns the IP-address data from the IP hint of an HTTPS
+// resource record. If the hint does not contain an IP address, fam is
+// [netutil.AddrFamilyNone] and netIP is nil.
+func ipFromHTTPSRRKV(kv dns.SVCBKeyValue) (fam netutil.AddrFamily, netIP net.IP) {
+ switch kv := kv.(type) {
+ case *dns.SVCBIPv4Hint:
+ if len(kv.Hint) > 0 {
+ return netutil.AddrFamilyIPv4, kv.Hint[0]
+ }
+ case *dns.SVCBIPv6Hint:
+ if len(kv.Hint) > 0 {
+ return netutil.AddrFamilyIPv6, kv.Hint[0]
+ }
+ default:
+ // Go on.
+ }
+
+ return netutil.AddrFamilyNone, nil
}
// country is a wrapper around the GeoIP call that contains the handling of
diff --git a/internal/dnssvc/internal/mainmw/record_internal_test.go b/internal/dnssvc/internal/mainmw/record_internal_test.go
new file mode 100644
index 0000000..a8e92ea
--- /dev/null
+++ b/internal/dnssvc/internal/mainmw/record_internal_test.go
@@ -0,0 +1,201 @@
+package mainmw
+
+import (
+ "context"
+ "net/netip"
+ "testing"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/billstat"
+ "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/geoip"
+ "github.com/AdguardTeam/AdGuardDNS/internal/querylog"
+ "github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
+ "github.com/AdguardTeam/golibs/netutil"
+ "github.com/miekg/dns"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestMiddleware_recordQueryInfo_respCtry(t *testing.T) {
+ t.Parallel()
+
+ const (
+ fqdn = dnssvctest.DomainFQDN
+ class = dns.ClassINET
+ ttlSec = 10
+
+ testCtry = geoip.CountryAD
+ )
+
+ var (
+ reqA = dnsservertest.NewReq(fqdn, dns.TypeA, class)
+ reqAAAA = dnsservertest.NewReq(fqdn, dns.TypeAAAA, class)
+ reqTXT = dnsservertest.NewReq(fqdn, dns.TypeTXT, class)
+ reqHTTPS = dnsservertest.NewReq(fqdn, dns.TypeHTTPS, class)
+ )
+
+ testCases := []struct {
+ req *dns.Msg
+ name string
+ wantRespCtry geoip.Country
+ respAns []dns.RR
+ respRCode dnsmsg.RCode
+ wantGeoIP bool
+ }{{
+ req: reqA,
+ name: "empty",
+ wantRespCtry: geoip.CountryNotApplicable,
+ respAns: nil,
+ respRCode: dns.RcodeSuccess,
+ wantGeoIP: false,
+ }, {
+ req: reqA,
+ name: "refused",
+ wantRespCtry: geoip.CountryNotApplicable,
+ respAns: nil,
+ respRCode: dns.RcodeRefused,
+ wantGeoIP: false,
+ }, {
+ req: reqA,
+ name: "a",
+ wantRespCtry: testCtry,
+ respAns: []dns.RR{
+ dnsservertest.NewA(fqdn, ttlSec, dnssvctest.DomainAddrIPv4),
+ },
+ respRCode: dns.RcodeSuccess,
+ wantGeoIP: true,
+ }, {
+ req: reqA,
+ name: "a_unspec",
+ wantRespCtry: geoip.CountryNotApplicable,
+ respAns: []dns.RR{
+ dnsservertest.NewA(fqdn, ttlSec, netip.IPv4Unspecified()),
+ },
+ respRCode: dns.RcodeSuccess,
+ wantGeoIP: false,
+ }, {
+ req: reqAAAA,
+ name: "aaaa",
+ wantRespCtry: testCtry,
+ respAns: []dns.RR{
+ dnsservertest.NewAAAA(fqdn, ttlSec, dnssvctest.DomainAddrIPv6),
+ },
+ respRCode: dns.RcodeSuccess,
+ wantGeoIP: true,
+ }, {
+ req: reqTXT,
+ name: "txt",
+ wantRespCtry: geoip.CountryNotApplicable,
+ respAns: []dns.RR{
+ dnsservertest.NewTXT(fqdn, ttlSec),
+ },
+ respRCode: dns.RcodeSuccess,
+ wantGeoIP: false,
+ }, {
+ req: reqHTTPS,
+ name: "https_no_ips",
+ wantRespCtry: geoip.CountryNotApplicable,
+ respAns: []dns.RR{
+ dnsservertest.NewHTTPS(fqdn, ttlSec, nil, nil),
+ },
+ respRCode: dns.RcodeSuccess,
+ wantGeoIP: false,
+ }, {
+ req: reqHTTPS,
+ name: "https_ipv4",
+ wantRespCtry: testCtry,
+ respAns: []dns.RR{
+ dnsservertest.NewHTTPS(fqdn, ttlSec, []netip.Addr{dnssvctest.DomainAddrIPv4}, nil),
+ },
+ respRCode: dns.RcodeSuccess,
+ wantGeoIP: true,
+ }, {
+ req: reqHTTPS,
+ name: "https_ipv6",
+ wantRespCtry: testCtry,
+ respAns: []dns.RR{
+ dnsservertest.NewHTTPS(fqdn, ttlSec, nil, []netip.Addr{dnssvctest.DomainAddrIPv6}),
+ },
+ respRCode: dns.RcodeSuccess,
+ wantGeoIP: true,
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ loc := &geoip.Location{
+ 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")
+ }
+
+ return loc, nil
+ },
+ }
+
+ queryLogCalled := false
+ var gotRespCtry geoip.Country
+ queryLog := &agdtest.QueryLog{
+ OnWrite: func(_ context.Context, e *querylog.Entry) (err error) {
+ queryLogCalled = true
+
+ require.NotNil(t, e)
+ gotRespCtry = e.ResponseCountry
+
+ return nil
+ },
+ }
+
+ mw := &Middleware{
+ billStat: billstat.EmptyRecorder{},
+ geoIP: geoIP,
+ queryLog: queryLog,
+ ruleStat: rulestat.Empty{},
+ }
+
+ ctx := dnsserver.ContextWithRequestInfo(context.Background(), &dnsserver.RequestInfo{
+ StartTime: time.Now(),
+ })
+
+ fctx := &filteringContext{
+ originalRequest: tc.req,
+ filteredResponse: dnsservertest.NewResp(
+ int(tc.respRCode),
+ tc.req,
+ dnsservertest.SectionAnswer(tc.respAns),
+ ),
+ }
+
+ ri := &agd.RequestInfo{
+ Profile: &agd.Profile{
+ QueryLogEnabled: true,
+ },
+ Device: &agd.Device{},
+ QType: tc.req.Question[0].Qtype,
+ QClass: class,
+ }
+
+ mw.recordQueryInfo(ctx, fctx, ri)
+ require.True(t, queryLogCalled)
+
+ assert.Equal(t, gotRespCtry, tc.wantRespCtry)
+ })
+ }
+}
diff --git a/internal/dnssvc/internal/preservice/preservice_test.go b/internal/dnssvc/internal/preservice/preservice_test.go
index 34d0d8f..7a249e2 100644
--- a/internal/dnssvc/internal/preservice/preservice_test.go
+++ b/internal/dnssvc/internal/preservice/preservice_test.go
@@ -122,7 +122,7 @@ func TestPreServiceMwHandler_ServeDNS(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.RemoteAddr)
+ rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.ClientTCPAddr)
tctx := agd.ContextWithRequestInfo(ctx, tc.ri)
dnsCk := &agdtest.DNSCheck{
diff --git a/internal/dnssvc/internal/preupstream/preupstream.go b/internal/dnssvc/internal/preupstream/preupstream.go
index 27cd1bc..12c8b05 100644
--- a/internal/dnssvc/internal/preupstream/preupstream.go
+++ b/internal/dnssvc/internal/preupstream/preupstream.go
@@ -9,6 +9,7 @@ import (
"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"
@@ -27,6 +28,7 @@ import (
// 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
@@ -42,6 +44,9 @@ 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 dnsdb.Interface
@@ -72,6 +77,7 @@ type Config struct {
func New(c *Config) (mw *Middleware) {
return &Middleware{
cloner: c.Cloner,
+ cacheManager: c.CacheManager,
db: c.DB,
geoIP: c.GeoIP,
cacheMinTTL: c.CacheMinTTL,
@@ -135,6 +141,7 @@ func (mw *Middleware) wrapCacheMw(next dnsserver.Handler) (wrapped dnsserver.Han
if mw.useECSCache {
cacheMw = ecscache.NewMiddleware(&ecscache.MiddlewareConfig{
Cloner: mw.cloner,
+ CacheManager: mw.cacheManager,
GeoIP: mw.geoIP,
Size: mw.cacheSize,
ECSSize: mw.ecsCacheSize,
diff --git a/internal/dnssvc/internal/preupstream/preupstream_test.go b/internal/dnssvc/internal/preupstream/preupstream_test.go
index a3c6634..b6baff3 100644
--- a/internal/dnssvc/internal/preupstream/preupstream_test.go
+++ b/internal/dnssvc/internal/preupstream/preupstream_test.go
@@ -7,6 +7,7 @@ import (
"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/dnsserver"
@@ -122,6 +123,7 @@ func TestPreUpstreamMwHandler_ServeDNS_withECSCache(t *testing.T) {
mw := preupstream.New(&preupstream.Config{
Cloner: agdtest.NewCloner(),
+ CacheManager: agdcache.EmptyManager{},
DB: dnsdb.Empty{},
GeoIP: geoIP,
CacheSize: 100,
@@ -233,7 +235,7 @@ func TestPreUpstreamMwHandler_ServeDNS_androidMetric(t *testing.T) {
h := mw.Wrap(handler)
- rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.RemoteAddr)
+ rw := dnsserver.NewNonWriterResponseWriter(nil, dnssvctest.ClientTCPAddr)
err := h.ServeDNS(ctx, rw, tc.req)
require.NoError(t, err)
diff --git a/internal/ecscache/ecsblocklist.go b/internal/ecscache/ecsblocklist.go
index 5f45f5e..205e109 100644
--- a/internal/ecscache/ecsblocklist.go
+++ b/internal/ecscache/ecsblocklist.go
@@ -21,22 +21,26 @@ var FakeECSFQDNs = container.NewMapSet(
"0b732edd-087f-4c27-b0f6-5ff26d96cdf6.prmutv.co.",
"0cf.io.",
"0cf17917-395b-4f25-91cc-db3bdd6044b0.prmutv.co.",
- "1.eu.dl.wireshark.org.",
"10.cofile.net.",
+ "1024tera.com.",
+ "1024terabox.com.",
"103.chtsite.com.",
"10m.com.cn.",
"11-alarm-mop.meshare.com.",
"11.cofile.net.",
+ "1184-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.",
"12-alarm-mop.meshare.com.",
"12.cofile.net.",
"126.com.",
"126.net.",
"13-alarm-mop.meshare.com.",
"13.cofile.net.",
+ "1337.abcvg.info.",
"14-alarm-mop.meshare.com.",
"14.cofile.net.",
"15.cofile.net.",
"16.cofile.net.",
+ "163.com.",
"163jiasu.com.",
"163yun.com.",
"1688.com.",
@@ -44,14 +48,14 @@ var FakeECSFQDNs = container.NewMapSet(
"18.cofile.net.",
"18ea70d2d9a945cfb97d818ba71817dc.pacloudflare.com.",
"19.cofile.net.",
+ "191639-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
+ "1925505597.rsc.cdn77.org.",
"192667-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
"192991-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
- "193119-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
+ "193141-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
"193259-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
"193522-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
- "193565-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
"193592-ipv4v6e.farm.dprodmgd105.aa-rt.sharepoint.com.",
- "1941-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.",
"1weather.onelouder.com.",
"2.401402081.west-gcloud.codm.activision.com.",
"2.realtime.services.box.net.",
@@ -60,58 +64,56 @@ var FakeECSFQDNs = container.NewMapSet(
"2345.cc.",
"2acdb9b66bb242618283aadb21ede6c1.pacloudflare.com.",
"2e4b93d1-a8ae-4a89-8885-6109135ac0de.prmutv.co.",
+ "2owo1y.n0qq3z.com.",
+ "2talk.com.",
+ "3001.scriptcdn.net.",
"360.cn.",
"360os.com.",
"360safe.com.",
"3a6b0682-f3e1-4576-a706-5eb4101b9cc3.prmutv.co.",
"3aba5292-ba75-422b-8715-bd21146f7836.prmutv.co.",
"3d2fb0bd-52fc-4b75-aaf5-2d436c172540.prmutv.co.",
+ "3g.cn.",
"4.401402081.west-gcloud.codm.activision.com.",
"4.adsco.re.",
"401402081.west-gcloud.codm.activision.com.",
+ "4065-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.",
"46a2e5c3c5a64e218b60f2c2ee76b750.pacloudflare.com.",
+ "4974-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.",
"507b28fb-2ef1-4c34-8bda-ba32030bb199.prmutv.co.",
"520.jp.",
- "55a-8ballpool-mobile-live.pool.miniclippt.com.",
"5d79bce7-5d2b-427e-a6c4-b89b6c7bf048.prmutv.co.",
"6.401402081.west-gcloud.codm.activision.com.",
"6093eccf-6734-4877-ac8b-83d6d0e27b46.prmutv.co.",
- "68547f8f-2fd8-4ff3-9b63-51e86e2edee8.prmutv.co.",
+ "68794912.akstat.io.",
"6c3e19e3-d05e-45d1-8f79-fcd6cb2f3a21.prmutv.co.",
- "6wrwmh247h-1.algolianet.com.",
- "6wrwmh247h-2.algolianet.com.",
- "6wrwmh247h-3.algolianet.com.",
"733868e706dd40d3a4a0588fc39b3df8.pacloudflare.com.",
- "789-ipv4v6e.clump.dprodmgd105.aa-rt.sharepoint.com.",
- "7c7b02d4bc3d48dd81a7c7738d4de1ab.pacloudflare.com.",
"8686c.com.",
"88a66e5c-8fe8-48af-9c6c-3ec3f4983aad.prmutv.co.",
- "8fd3136c-39ae-4836-adeb-ea2f0db46980.prmutv.co.",
"8x8.com.cdn.cloudflare.net.",
"9pumbooc7hqedhjmeavbpmp5ik9u0ngr-data.customer.pendo.io.",
"a-api.anthropic.com.",
"a-cdn.anthropic.com.",
"a-m-p.xyz.",
"a.fc.namequery.com.",
+ "a.fsdn.com.",
"a.getepic.com.",
"a.nel.cloudflare.com.",
"a.nitropay.com.",
"a.tile.openstreetmap.org.",
"a.tile.osm.org.",
+ "a.vsstatic.com.",
"a010.casalemedia.com.",
- "a011.casalemedia.com.",
"a012.casalemedia.com.",
"a013.casalemedia.com.",
+ "a014.casalemedia.com.",
"a015.casalemedia.com.",
"a016.casalemedia.com.",
"a017.casalemedia.com.",
"a018.casalemedia.com.",
"a019.casalemedia.com.",
- "a020.casalemedia.com.",
"a021.casalemedia.com.",
- "a022.casalemedia.com.",
"a023.casalemedia.com.",
- "a024.casalemedia.com.",
"a025.casalemedia.com.",
"a026.casalemedia.com.",
"a027.casalemedia.com.",
@@ -119,26 +121,22 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
- "a042.casalemedia.com.",
"a043.casalemedia.com.",
"a044.casalemedia.com.",
- "a045.casalemedia.com.",
"a046.casalemedia.com.",
"a050.casalemedia.com.",
"a054.casalemedia.com.",
"a058.casalemedia.com.",
- "a074.casalemedia.com.",
"a075.casalemedia.com.",
- "a088.casalemedia.com.",
"a091.casalemedia.com.",
"a095.casalemedia.com.",
"a096.casalemedia.com.",
@@ -160,23 +158,23 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
"a147.casalemedia.com.",
"a149.casalemedia.com.",
"a150.casalemedia.com.",
"a151.casalemedia.com.",
"a152.casalemedia.com.",
"a153.casalemedia.com.",
- "a156.casalemedia.com.",
"a157.casalemedia.com.",
"a158.casalemedia.com.",
"a159.casalemedia.com.",
"a160.casalemedia.com.",
+ "a161.casalemedia.com.",
"a166.casalemedia.com.",
"a169.casalemedia.com.",
"a170.casalemedia.com.",
@@ -184,9 +182,11 @@ var FakeECSFQDNs = container.NewMapSet(
"a178.casalemedia.com.",
"a179.casalemedia.com.",
"a182.casalemedia.com.",
+ "a186.casalemedia.com.",
"a187.casalemedia.com.",
"a188.casalemedia.com.",
- "a190.casalemedia.com.",
+ "a189.casalemedia.com.",
+ "a192.casalemedia.com.",
"a195.casalemedia.com.",
"a200.casalemedia.com.",
"a2001.casalemedia.com.",
@@ -200,40 +200,35 @@ var FakeECSFQDNs = container.NewMapSet(
"a2009.casalemedia.com.",
"a201.casalemedia.com.",
"a2010.casalemedia.com.",
- "a2011.casalemedia.com.",
"a2012.casalemedia.com.",
"a2013.casalemedia.com.",
"a2014.casalemedia.com.",
- "a2015.casalemedia.com.",
"a2016.casalemedia.com.",
- "a2017.casalemedia.com.",
- "a2018.casalemedia.com.",
"a2019.casalemedia.com.",
"a2020.casalemedia.com.",
"a2021.casalemedia.com.",
- "a2022.casalemedia.com.",
"a2023.casalemedia.com.",
"a2024.casalemedia.com.",
- "a2025.casalemedia.com.",
"a2026.casalemedia.com.",
"a2027.casalemedia.com.",
"a2028.casalemedia.com.",
"a2029.casalemedia.com.",
"a2030.casalemedia.com.",
- "a2031.casalemedia.com.",
"a2032.casalemedia.com.",
+ "a2033.casalemedia.com.",
"a2034.casalemedia.com.",
"a2035.casalemedia.com.",
"a2036.casalemedia.com.",
"a2037.casalemedia.com.",
"a2038.casalemedia.com.",
"a2039.casalemedia.com.",
- "a2041.casalemedia.com.",
+ "a2040.casalemedia.com.",
"a2042.casalemedia.com.",
"a2043.casalemedia.com.",
"a2044.casalemedia.com.",
"a2045.casalemedia.com.",
"a2046.casalemedia.com.",
+ "a2047.casalemedia.com.",
"a2048.casalemedia.com.",
"a2049.casalemedia.com.",
"a2050.casalemedia.com.",
@@ -247,17 +242,12 @@ var FakeECSFQDNs = container.NewMapSet(
"a2058.casalemedia.com.",
"a2059.casalemedia.com.",
"a2060.casalemedia.com.",
+ "a24656750324.cdn.optimizely.com.",
"a2561.casalemedia.com.",
"a2562.casalemedia.com.",
"a2563.casalemedia.com.",
- "a2564.casalemedia.com.",
- "a2565.casalemedia.com.",
- "a2566.casalemedia.com.",
- "a2567.casalemedia.com.",
- "a2568.casalemedia.com.",
- "a2569.casalemedia.com.",
- "a2570.casalemedia.com.",
"a2571.casalemedia.com.",
+ "a2572.casalemedia.com.",
"a2573.casalemedia.com.",
"a2574.casalemedia.com.",
"a2575.casalemedia.com.",
@@ -272,27 +262,20 @@ var FakeECSFQDNs = container.NewMapSet(
"a2584.casalemedia.com.",
"a2585.casalemedia.com.",
"a2586.casalemedia.com.",
+ "a2587.casalemedia.com.",
"a2588.casalemedia.com.",
"a2589.casalemedia.com.",
- "a2590.casalemedia.com.",
"a2591.casalemedia.com.",
"a2592.casalemedia.com.",
- "a2593.casalemedia.com.",
- "a2594.casalemedia.com.",
- "a2595.casalemedia.com.",
"a2596.casalemedia.com.",
- "a2597.casalemedia.com.",
- "a2598.casalemedia.com.",
- "a2599.casalemedia.com.",
"a2600.casalemedia.com.",
"a2601.casalemedia.com.",
- "a2602.casalemedia.com.",
"a2603.casalemedia.com.",
"a2604.casalemedia.com.",
"a2605.casalemedia.com.",
"a2606.casalemedia.com.",
"a2607.casalemedia.com.",
- "a2608.casalemedia.com.",
+ "a2609.casalemedia.com.",
"a2610.casalemedia.com.",
"a2611.casalemedia.com.",
"a2612.casalemedia.com.",
@@ -303,12 +286,12 @@ var FakeECSFQDNs = container.NewMapSet(
"a2617.casalemedia.com.",
"a2618.casalemedia.com.",
"a2619.casalemedia.com.",
- "a2620.casalemedia.com.",
"a2621.casalemedia.com.",
"a2622.casalemedia.com.",
"a2624.casalemedia.com.",
"a2625.casalemedia.com.",
"a2626.casalemedia.com.",
+ "a2627.casalemedia.com.",
"a2629.casalemedia.com.",
"a2630.casalemedia.com.",
"a2631.casalemedia.com.",
@@ -318,6 +301,7 @@ var FakeECSFQDNs = container.NewMapSet(
"a2635.casalemedia.com.",
"a2636.casalemedia.com.",
"a2637.casalemedia.com.",
+ "a2638.casalemedia.com.",
"a2639.casalemedia.com.",
"a2640.casalemedia.com.",
"a2641.casalemedia.com.",
@@ -328,8 +312,6 @@ var FakeECSFQDNs = container.NewMapSet(
"a2646.casalemedia.com.",
"a2647.casalemedia.com.",
"a2648.casalemedia.com.",
- "a2649.casalemedia.com.",
- "a2650.casalemedia.com.",
"a2a5c7f9-3fa0-4182-889a-15aa61acf59b.prmutv.co.",
"a3.tuyacn.com.",
"a461.casalemedia.com.",
@@ -340,19 +322,23 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
- "a5555.casalemedia.com.",
+ "a5551.casalemedia.com.",
+ "a5556.casalemedia.com.",
"a5557.casalemedia.com.",
"a5558.casalemedia.com.",
"a5559.casalemedia.com.",
+ "a5560.casalemedia.com.",
"a5561.casalemedia.com.",
"a5562.casalemedia.com.",
"a5563.casalemedia.com.",
@@ -367,6 +353,7 @@ var FakeECSFQDNs = container.NewMapSet(
"a5572.casalemedia.com.",
"a5573.casalemedia.com.",
"a5574.casalemedia.com.",
+ "a5575.casalemedia.com.",
"a5576.casalemedia.com.",
"a5577.casalemedia.com.",
"a5578.casalemedia.com.",
@@ -394,7 +381,6 @@ var FakeECSFQDNs = container.NewMapSet(
"a55a84b3-9632-4869-b625-3d8ef43ed18d.prmutv.co.",
"a5600.casalemedia.com.",
"a5601.casalemedia.com.",
- "a5602.casalemedia.com.",
"a5603.casalemedia.com.",
"a5604.casalemedia.com.",
"a5605.casalemedia.com.",
@@ -409,10 +395,9 @@ var FakeECSFQDNs = container.NewMapSet(
"a5614.casalemedia.com.",
"a5615.casalemedia.com.",
"a5616.casalemedia.com.",
- "a5617.casalemedia.com.",
"a5618.casalemedia.com.",
+ "a5619.casalemedia.com.",
"a5620.casalemedia.com.",
- "a5621.casalemedia.com.",
"a5622.casalemedia.com.",
"a5623.casalemedia.com.",
"a5624.casalemedia.com.",
@@ -428,13 +413,14 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -455,93 +441,106 @@ var FakeECSFQDNs = container.NewMapSet(
"a5663.casalemedia.com.",
"a5664.casalemedia.com.",
"a5665.casalemedia.com.",
+ "a5666.casalemedia.com.",
"a5667.casalemedia.com.",
"a5668.casalemedia.com.",
"a5669.casalemedia.com.",
"a57.foxsports.com.",
"a9695278-4085-40b3-9f02-8d4c38a6ff01.prmutv.co.",
- "aa-sync.quantummetric.com.",
"aa.online-metrix.net.",
"aa.quantummetric.com.",
+ "aaa.a-mo.net.",
"aaid.uyunad.com.",
+ "ab.chatgpt.com.",
"ab.qq.com.",
"aba2c424-419a-4d03-9aed-2dca8a7139e4.prmutv.co.",
- "abcsinsights.com.",
+ "abcvg.info.",
"abmmscloud-my.sharepoint.com.",
"abmmscloud.sharepoint.com.",
"abqix.mm.fcix.net.",
"abroad.apilocate.amap.com.",
"abtest-aws-us-east-01.saas.sensorsdata.com.",
+ "abtest.omiapp.me.",
"accela.com.",
- "accentuate.io.",
- "access.creditonebank.com.",
+ "accenture.com.",
"access.mp.lura.live.",
"account.bbc.com.",
"account.box.com.",
+ "account.sogou.com.",
+ "account.ubisoft.com.",
"accountapi.agoda.com.",
+ "accounts.superhuman.com.",
"accscdn4public.m.taobao.com.",
"accurint.com.",
"acdn.tinkoff.ru.",
+ "acehardware.groupbycloud.com.",
"acgvideo.com.",
"achi.faceit.com.",
- "acm.org.",
+ "aciww-my.sharepoint.com.",
"acme-v02.api.letsencrypt.org.",
"acrobits.cz.",
"acs4public.m.taobao.com.",
+ "acsdk.gameyw.easebar.com.",
"activate.academy.com.",
"activation.cloud.techsmith.com.",
- "ad.tagtoo.co.",
+ "ad.broadstreetads.com.",
"adapex.io.",
"adash-emas.cn-hangzhou.aliyuncs.com.",
"adash.man.aliyuncs.com.",
- "adashx.m.taobao.com.",
- "adashx.m.taobao.com.w.kunlunhuf.com.",
- "adashx.ut.alibaba.com.",
- "adashx.ut.amap.com.",
- "adashx.ut.dingtalk.com.",
"adcell.com.",
+ "adgotest.cn-guangzhou.log.aliyuncs.com.",
"adi-sin-c-4.cico.com.",
+ "adiam.tech.",
+ "adidas.com.multicdn.cloudinary.com.",
"aditude.io.",
- "adlook.me.",
"adm.wsms.haplat.net.",
"admbk.wsms.haplat.net.",
- "admedo.com.",
+ "adminmepcr-my.sharepoint.com.",
"admixer.com.",
"adoric.com.",
- "adquery.io.",
"adrs.org.cn.",
- "ads.adventive.com.",
"adsco.re.",
"adtarget.market.",
+ "adtarget.me.",
+ "adtiming.com.",
"advantage.purpleguys.com.",
"advantage2.purpleguys.com.",
- "advantagecharter-my.sharepoint.com.",
"adventisthealthwest-my.sharepoint.com.",
"adventisthealthwest.sharepoint.com.",
"adview.com.",
"advlion.com.",
+ "adx-event-server.tec-do.cn.",
"adx-sg-req.anythinktech.com.",
- "adx-vg-req.anythinktech.com.",
- "adxbid.info.",
"aee.myisolved.com.",
"aepenergy-my.sharepoint.com.",
"aepenergy.sharepoint.com.",
+ "aeries.com.",
+ "afss.zhiqinyun.cn.",
"agd2.p.360.cn.",
+ "agent-logos.storage.googleapis.com.",
+ "agent.jumpcloud.com.",
"agent.marketingcloudfx.com.",
+ "agoda-my.sharepoint.com.",
+ "agoda.okta.com.",
"agt.p.360.cn.",
"aicdn.com.",
+ "aid.m.taobao.com.",
"aid.send.microad.jp.",
"aidata.io.",
+ "aigconnect.aig.",
+ "aigtech.okta.com.",
"aiq-in.caranddriver.com.",
"airasia.com.",
"airtory.com.",
+ "aisee.tv.",
"ajcloud.net.",
"akronchildrens-my.sharepoint.com.",
- "akulaku.com.",
+ "akronchildrens.sharepoint.com.",
"alarm.wsms.haplat.net.",
"alarmbk.wsms.haplat.net.",
"alarmnet.com.",
"albany.remotepc.com.",
+ "albertsons.okta.com.",
"album-sg01a.ocloud.heytapmobi.com.",
"ali-picture-private-sg.oss-ap-southeast-1.aliyuncs.com.",
"ali-sgp-messpush.meetyouintl.com.",
@@ -563,6 +562,12 @@ var FakeECSFQDNs = container.NewMapSet(
"aliyuncs.com.",
"allieduniversalservices-my.sharepoint.com.",
"allieduniversalservices.sharepoint.com.",
+ "alog-default.umeng.com.",
+ "alpha1-ap-public.val.qq.com.",
+ "alpha1-gp-ping-cq2.val.qq.com.",
+ "alpha1-gp-ping-gz2.val.qq.com.",
+ "alpha1-gp-ping-nj2.val.qq.com.",
+ "alpha1-gp-ping-tj2.val.qq.com.",
"altamedhealth.sharepoint.com.",
"am1.ecdn2.bumbcdn.com.",
"am3pap002.storage.live.com.",
@@ -574,19 +579,24 @@ var FakeECSFQDNs = container.NewMapSet(
"amap.com.",
"amc-theatres-res.cloudinary.com.",
"amcor-my.sharepoint.com.",
+ "amcor.sharepoint.com.",
+ "amdc-wapa.lazada.com.",
"amdc.lazada.com.",
"amdcopen.m.taobao.com.",
"amdcopen.m.taobao.com.gds.alibabadns.com.",
"americanchemicalsociety-my.sharepoint.com.",
+ "amjpn-my.sharepoint.com.",
"amp.namequery.com.",
"amp.permutive.com.",
+ "amplitudelab.usemotion.com.",
"ams-itm-radar-testobject.citrix.com.",
"ams02pap001.storage.live.com.",
"ams03pap002.storage.live.com.",
"amsterdam.remotepc.com.",
"amwinsusa-my.sharepoint.com.",
"amwinsusa.sharepoint.com.",
- "analytics-2.athome.com.",
+ "an3762.ci.managedwhitelisting.com.",
+ "analytex.userpilot.io.",
"analytics-debugger.com.",
"analytics-ingress-global.bitmovin.com.",
"analytics.coach.com.",
@@ -594,20 +604,24 @@ var FakeECSFQDNs = container.NewMapSet(
"analytics.getshogun.com.",
"analytics.gnc.com.",
"analytics.languagetoolplus.com.",
+ "analytics.pdf24.org.",
"analytics.qumucloud.com.",
"analytics.talbots.com.",
"analytics.trovit.com.",
"android.crashsight.wetest.net.",
- "ankara.remotepc.com.",
"anlian.co.",
"announce.torrentsmd.com.",
"anonymous.ads.brave.com.",
- "answers.yext-pixel.com.",
+ "ansellhealthcare-my.sharepoint.com.",
+ "ansellhealthcare.sharepoint.com.",
"ansys-my.sharepoint.com.",
"ansys.sharepoint.com.",
"anthropic.com.",
+ "antstream.com.",
+ "anxbrylkt.accounts.ondemand.com.",
"aon.com.",
"ap-southeast-1.log.aliyuncs.com.",
+ "apd-vodp2plogin.teg.tencent-cloud.net.",
"api-analytics-us3.zepp.com.",
"api-asyncgw-gcc-teams.usgovtrafficmanager.net.",
"api-eu1.hubspot.com.",
@@ -632,45 +646,54 @@ var FakeECSFQDNs = container.NewMapSet(
"api-mayi.django.t.taobao.com.",
"api-mifit-us3.zepp.com.",
"api-php1-ovh.keepsolid.com.",
+ "api-php10-ovh.keepsolid.com.",
+ "api-php11-ovh.keepsolid.com.",
"api-php2-ovh.keepsolid.com.",
- "api-php3-ovh.keepsolid.com.",
"api-php4-ovh.keepsolid.com.",
"api-php9-ovh.keepsolid.com.",
- "api-pos.titank12.com.",
+ "api-pinterest-com-eip-akadns-net.pinterest.com.",
"api-preview.luckyorange.com.",
"api-sh.django.t.taobao.com.gds.alibabadns.com.",
+ "api-skytone-4-drcn.cloud.dbankcloud.cn.",
"api.adquery.io.",
"api.ams.gcc.teams.microsoft.com.",
"api.asm.skype.com.",
+ "api.bitwarden.com.",
"api.bobble.ai.",
- "api.bosch-wdw.com.",
"api.box.com.",
"api.btloader.com.",
"api.cloud.tenda.com.cn.",
"api.config-security.com.",
"api.crobox.com.",
+ "api.crush.163.com.",
"api.dealersocket.com.",
"api.deepl.com.",
- "api.do.buienalarm.nl.",
+ "api.easeus.com.",
+ "api.fit-pay.com.",
+ "api.flashjoin.net.",
+ "api.fox.com.",
+ "api.get-just-api.com.",
+ "api.glanceapis.com.",
"api.gleap.io.",
- "api.goaffpro.com.",
"api.gravitec.media.",
"api.grow.me.",
"api.icalendars.app.",
"api.inboxsdk.com.",
- "api.k.163.com.",
"api.kinogram.best.",
"api.lightboxcdn.com.",
+ "api.look.163.com.",
"api.loyalhealth.com.",
+ "api.lumu.io.",
"api.lytics.io.",
- "api.meteoplaza.com.",
- "api.mindbodyonline.com.",
+ "api.mangacoin.net.",
+ "api.matetranslate.com.",
"api.mintkeyboard.com.",
+ "api.mobileapp.digital.costco.com.",
"api.moyoung.com.",
"api.mrg.agency.",
"api.my.jbi.global.",
+ "api.ne9cs.com.",
"api.onedrive.com.",
- "api.owhealth.com.",
"api.permutive.app.",
"api.permutive.com.",
"api.pgf-asqb7a.com.",
@@ -683,87 +706,112 @@ var FakeECSFQDNs = container.NewMapSet(
"api.ringcentral.biz.",
"api.rollbar.com.",
"api.sbz.vn.",
- "api.searchiq.co.",
- "api.skybet.com.",
"api.smartdeploy.com.",
"api.snapchat.com.",
"api.sofascore.app.",
"api.sofascore.com.",
+ "api.sound-machine.com.",
+ "api.starmakerstudios.com.",
"api.streak.com.",
"api.swishapps.ai.",
"api.transitapp.com.",
+ "api.tripadvisor.com.",
"api.tx4.pw.adn.cloud.",
"api.ultimaker.com.",
- "api.ultimate-guitar.com.",
"api.unity.com.",
"api.userlike.com.",
- "api.vhx.tv.",
- "api.vieon.vn.",
- "api.vvxi2.com.",
+ "api.vivoglobal.com.",
+ "api.wingstop.com.",
"api000.backblazeb2.com.",
"api001.backblazeb2.com.",
"api002.backblazeb2.com.",
+ "api004.backblazeb2.com.",
+ "api2.matetranslate.com.",
+ "api31-normal-cost-alisg-mys.tiktokv.com.",
+ "api64.ipify.org.",
"apigroupinc-my.sharepoint.com.",
+ "apigroupinc.sharepoint.com.",
"apiisgp.ezvizlife.com.",
"apiisgp.hik-connect.com.",
- "apimgmttmkoempweel99rngfdhyv9x4h8qv4sl6dfug9jtikbm.trafficmanager.net.",
+ "apim-dev-cn-pcm-ms-01.azure-api.cn.",
"apk.v-mate.mobi.",
"apk.vidmate.net.",
+ "aplo-evnt.com.",
"app-atl.five9.com.",
"app-eu1.hubspot.com.",
"app-goal.com.",
"app-scl.five9.com.",
"app-sec-cn.heytapmobi.com.",
- "app-student.atitesting.com.",
"app.adoric-om.com.",
"app.box.com.",
"app.cart-bot.net.",
"app.cybba.solutions.",
"app.ee-share.com.",
+ "app.envoy.com.",
"app.grow.me.",
+ "app.launchnotes.io.",
"app.paces.jbi.global.",
"app.pendo.qgenda.com.",
"app.retinavue.net.",
"app.sealsubscriptions.com.",
"app.snapchat.com.",
+ "app.talkjs.com.",
"app.wdesk.com.",
"app.zoom.us.",
"appcafe.gtm.starbucks.com.",
"appcafe.starbucks.com.",
- "appconf.mail.163.com.",
+ "appgrowth.com.",
+ "appinfo.dl.playstation.net.",
+ "applog.la4lbg.uae2grp.ucweb.com.",
"appocean.media.",
+ "appodealx-us.appgrowth.com.",
"apponline.research.qq.com.",
"appriver.com.",
"apps.gov.powerapps.us.",
+ "apps.mzstatic.com.",
"apps.wix.com.",
"appstoreonrt-stsdk.vivo.com.cn.",
"appstoreort-stsdk.vivo.com.cn.",
- "apr1308.mazefoam.com.",
"apv-launcher.minute.ly.",
"apv-static.minute.ly.",
"apv-static.tldw.me.",
- "arbitrum.io.",
+ "archive.org.",
"ardenthealthservices-my.sharepoint.com.",
"ardenthealthservices.sharepoint.com.",
"arenabg.com.",
+ "arentfox-my.sharepoint.com.",
"aristotleinsight.com.",
+ "ark.qq.com.",
+ "arkdhs-my.sharepoint.com.",
+ "arm-frontdoor-edge-geo.trafficmanager.net.",
"arm1.maxhost.io.",
+ "armh-my.sharepoint.com.",
"armh.sharepoint.com.",
"arms-retcode-sg.aliyuncs.com.",
"arms-retcode.aliyuncs.com.",
"arms.aliyuncs.com.",
+ "armstrongceilings-my.sharepoint.com.",
+ "armstrongceilings.sharepoint.com.",
"arnoldclark1-my.sharepoint.com.",
+ "arthrex-my.sharepoint.com.",
+ "arthrex.sharepoint.com.",
+ "artonetab.com.",
"arup-my.sharepoint.com.",
+ "arup.sharepoint.com.",
"arupapc-my.sharepoint.com.",
"as-api.asm.skype.com.",
"as-prod.asyncgw.teams.microsoft.com.",
+ "asanalytics.booking.com.",
"asheville.remotepc.com.",
"asia-001.azure-apim.net.",
"asia-adlog.vivoglobal.com.",
+ "asia-album-api.vivoglobal.com.",
"asia-browser.vivoglobal.com.",
+ "asia-browserplat.vivoglobal.com.",
"asia-config-appstore.vivoglobal.com.",
"asia-cota.vivoglobal.com.",
"asia-ex-adlog.vivoglobal.com.",
+ "asia-exbrowser.vivoglobal.com.",
"asia-exmagazineunlock-proxy.vivoglobal.com.",
"asia-f-up.vivoglobal.com.",
"asia-gamecenter.vivoglobal.com.",
@@ -785,11 +833,13 @@ var FakeECSFQDNs = container.NewMapSet(
"asia-timesync.vivoglobal.com.",
"asia-upload-appstore.vivoglobal.com.",
"asia-usrsys-api.vivoglobal.com.",
+ "asia-vgcmdm-api-tha.vivoglobal.com.",
"asia-vnote.vivoglobal.com.",
"asia-vpushonrt-stsdk.vivoglobal.com.",
"asia-vpushort-stsdk.vivoglobal.com.",
"asia-weather.vivoglobal.com.",
"asia-wifi.vivoglobal.com.",
+ "asia.gikken.co.",
"asia.remotepc.com.",
"asm-api-golocal-geo-am-teams.trafficmanager.net.",
"asm-api-golocal-geo-as-teams.trafficmanager.net.",
@@ -804,76 +854,88 @@ var FakeECSFQDNs = container.NewMapSet(
"asset.fwpub1.com.",
"assets.api.stairwell.com.",
"assets.apps.pa.gov.",
- "assets.basspro.com.",
"assets.bwbx.io.",
"assets.fastly.carvana.io.",
"assets.the-independent.com.",
"assistant-dre.op.hicloud.com.",
+ "astat.bugly.qcloud.com.",
"async-motiondetection-us-1d.oss-us-west-1.aliyuncs.com.",
"asyncim.zoom.us.",
- "atemda.com.",
+ "ati.com.",
"atipt-my.sharepoint.com.",
"atipt.sharepoint.com.",
+ "atl.mirrors.knownhost.com.",
"atlanta.remotepc.com.",
- "atlanta2.remotepc.com.",
"atlanta3.remotepc.com.",
"atlanta4.remotepc.com.",
+ "atoken.m.taobao.com.",
+ "atriaseniorliving-my.sharepoint.com.",
"au-prod.asyncgw.teams.microsoft.com.",
+ "auc-collabrtc.officeapps.live.com.",
"auckland.remotepc.com.",
"audid.umeng.com.",
"audio.vivintsky.com.",
+ "audioscrobbler.com.",
"audiostatlog.cc.easebar.com.",
+ "autel.com.",
"auth-asg-en.aliyuncs.com.",
"auth.bereal.com.",
- "auth.ecobee.com.",
+ "auth.hulu.com.",
+ "auth.ichano.cn.",
"auth.jbisumari.org.",
"auth.laureate.net.",
- "auth.xello.world.",
- "autohome.com.cn.",
+ "authorize.net.",
"autonavi.com.",
"autotrack.studyquicks.com.",
- "auvik.com.",
"avalanche.autotrader.co.uk.",
- "avast.com.",
+ "aveva-my.sharepoint.com.",
+ "axaltacs-my.sharepoint.com.",
+ "axaltacs.sharepoint.com.",
"azchicago.remotepc.com.",
"azchicago2.remotepc.com.",
"azdcs-my.sharepoint.com.",
+ "azeus1-client-s.gateway.messenger.live.com.",
"azioncdn.net.",
"azmatch.adsrvr.org.",
+ "azscus1-client-s.gateway.messenger.live.com.",
"azureford-my.sharepoint.com.",
"azureford.sharepoint.com.",
"b.fssta.com.",
"b.tile.openstreetmap.org.",
"b.tile.osm.org.",
+ "b1-data.ads.heytapmobi.com.",
+ "babel-statistics-android.dreport.meituan.net.",
+ "babico.name.tr.",
"bablosoft.com.",
+ "bachoco-my.sharepoint.com.",
"backend-l.deepl.com.",
"backgroundcheck-my.sharepoint.com.",
"badambiz.com.",
"badoo.app.",
"bahrain.remotepc.com.",
"baishan-cloud.net.",
- "ballstate-my.sharepoint.com.",
"baltimore.remotepc.com.",
"bam.nr-data.net.cdn.cloudflare.net.",
"bangalore2.remotepc.com.",
"bangalore3.remotepc.com.",
"bangalore4.remotepc.com.",
- "bangkok.remotepc.com.",
+ "bankindonesiagov-my.sharepoint.com.",
+ "bankozarks-my.sharepoint.com.",
+ "bankozarks.sharepoint.com.",
"bankwithunited-my.sharepoint.com.",
"bankwithunited.sharepoint.com.",
- "banners-inventory-weighted-geo.hyprmx.com.",
"baptisthealth-my.sharepoint.com.",
"baptisthealth.sharepoint.com.",
"barstoolsports.com.",
- "bbzutils.tripcdn.cn.",
"bd1cec50-00d1-4ce9-9572-785857419a1e.prmutv.co.",
- "bdfed.stitch.mlbinfra.com.",
"bdpnt-my.sharepoint.com.",
- "bdreporting.com.",
+ "bdpnt.sharepoint.com.",
"beacon-api.aliyuncs.com.",
+ "beacon-iad2.rubiconproject.com.",
"beacon.qq.com.",
"beacons4.gvt2.com.",
"beacons5.gvt2.com.",
+ "beam.hubvisor.io.",
"becn-my.sharepoint.com.",
"becn.sharepoint.com.",
"becpsn-my.sharepoint.com.",
@@ -881,35 +943,29 @@ var FakeECSFQDNs = container.NewMapSet(
"belgium.remotepc.com.",
"belgrad.remotepc.com.",
"bend.remotepc.com.",
- "beneplace.com.",
+ "berryglobal-my.sharepoint.com.",
+ "berryglobal.sharepoint.com.",
+ "betagro-my.sharepoint.com.",
"betlive.com.",
"bgtfs.transitapp.com.",
"bhsjaxinc0-my.sharepoint.com.",
- "bidder.adquery.io.",
- "bidmyqps.xyz.",
+ "bhsjaxinc0.sharepoint.com.",
"bifrost.vivaldi.com.",
"bik.gov.tr.",
- "billingsclinic-my.sharepoint.com.",
"biomerieux-my.sharepoint.com.",
"biomerieux.sharepoint.com.",
- "bisdus-my.sharepoint.com.",
"bitbucket.org.",
- "bitmyanmar.info.",
"bkdllp-my.sharepoint.com.",
+ "bkdllp.sharepoint.com.",
"bl6pap003.storage.live.com.",
"bl6pap004.storage.live.com.",
"black-cat.crypto.com.",
"blackboard.com.",
"blackbox.dropbox-dns.com.",
- "blk-app.com.",
- "blocksi-screenshots-us.s3.us-east-005.backblazeb2.com.",
- "blooket.com.multicdn.cloudinary.com.",
"bloomerang.co.",
"blueshieldca-my.sharepoint.com.",
"blueshieldca.sharepoint.com.",
- "bluesnap.com.",
"bluffdale.remotepc.com.",
- "blz04pap001.storage.live.com.",
"blz04pap002.storage.live.com.",
"blz04pap003.storage.live.com.",
"blz04pap005.storage.live.com.",
@@ -919,19 +975,16 @@ var FakeECSFQDNs = container.NewMapSet(
"bmcorg-my.sharepoint.com.",
"bmoolbb-app.quantummetric.com.",
"bmrn-my.sharepoint.com.",
+ "bmrn.sharepoint.com.",
"bn02pap001.storage.live.com.",
"bn02pap001files.storage.live.com.",
"bna365-my.sharepoint.com.",
+ "bna365.sharepoint.com.",
"bnz05pap001.storage.live.com.",
"bnz05pap001files.storage.live.com.",
"bnz05pap002.storage.live.com.",
"bnz05pap002files.storage.live.com.",
- "bnz06pap001.storage.live.com.",
- "bnz06pap001files.storage.live.com.",
"bnz06pap002.storage.live.com.",
- "bnz06pap002files.storage.live.com.",
- "bnz06pap003.storage.live.com.",
- "bnz06pap003files.storage.live.com.",
"bnz06pap004.storage.live.com.",
"bnz06pap004files.storage.live.com.",
"bnz07pap001.storage.live.com.",
@@ -941,39 +994,47 @@ var FakeECSFQDNs = container.NewMapSet(
"books-personalization-server.apple.com.",
"booksy.com.",
"bootstrapcdn.com.",
+ "bosecorp-my.sharepoint.com.",
+ "bosecorp.sharepoint.com.",
"boston.remotepc.com.",
"boston2.remotepc.com.",
"bostonglobe.com.",
"box.com.",
"box.net.",
- "boxcloud.com.",
"br.chat.si.riotgames.com.",
+ "brainx-dsp-sg.tec-do.cn.",
+ "brainx.tech.",
"brand-assets.ringcentral.com.",
"bratislava.remotepc.com.",
+ "brealtime.com.cdn.cloudflare.net.",
"breitbart.com.",
"brenntag01-my.sharepoint.com.",
"brenntag01.sharepoint.com.",
+ "brenntag01nam-my.sharepoint.com.",
"brenntag01nam.sharepoint.com.",
- "bridge2bwb.com.",
- "bridgetonorg-my.sharepoint.com.",
+ "bridge.tonapi.io.",
"broadstreetads.com.",
"brocktonpublicschools-my.sharepoint.com.",
+ "bronrt.stsdk.vivo.com.cn.",
"bscedge.com.",
"bsprings.remotepc.com.",
"bt.moack.co.kr.",
- "bthfa.jenzabarcloud.com.",
+ "bt2.archive.org.",
+ "btc.f2pool.com.",
"btrace.qq.com.",
"bucharest.remotepc.com.",
"bucharest1.remotepc.com.",
"budapest.remotepc.com.",
- "bufferapp.com.",
+ "buenosaires.remotepc.com.",
"bugly.qcloud.com.",
"bugreport.huorong.cn.",
- "bundleb2b.net.",
"bundler.nice-team.net.",
+ "burningmay.info.",
"burnsmcd-my.sharepoint.com.",
"burnsmcd.sharepoint.com.",
+ "busey-my.sharepoint.com.",
"bw1-my.sharepoint.com.",
+ "bw1.sharepoint.com.",
"bwatch.bergankdv.com.",
"bytecdn.cn.",
"bytedance.net.",
@@ -988,100 +1049,126 @@ var FakeECSFQDNs = container.NewMapSet(
"c2c.wechat.com.",
"c3.ttcache.com.",
"c4.ttcache.com.",
- "c6.glb.paypal.com.",
"c7l.cyberhaven.io.",
"c8ee9446-97ed-462f-a5e9-1af66c8e9104.prmutv.co.",
+ "ca-mon-gcp-r001.router.teamviewer.com.",
+ "ca-mon-gcp-r002.router.teamviewer.com.",
"ca-prod.asyncgw.teams.microsoft.com.",
+ "ca-tor-anx-r001.router.teamviewer.com.",
+ "ca-tor-anx-r002.router.teamviewer.com.",
+ "ca-tor-anx-r003.router.teamviewer.com.",
+ "ca-tor-anx-r004.router.teamviewer.com.",
+ "ca-tor-anx-r005.router.teamviewer.com.",
+ "ca-tor-anx-r006.router.teamviewer.com.",
+ "ca-tor-anx-r008.router.teamviewer.com.",
+ "ca-tor-anx-r010.router.teamviewer.com.",
+ "ca-tor-gcp-r001.router.teamviewer.com.",
+ "ca-tor-gcp-r002.router.teamviewer.com.",
+ "ca-tor-gcp-r003.router.teamviewer.com.",
+ "ca-tor-gcp-r005.router.teamviewer.com.",
+ "ca-van-anx-r002.router.teamviewer.com.",
+ "ca-van-anx-r007.router.teamviewer.com.",
+ "ca-van-anx-r009.router.teamviewer.com.",
"ca.gov.",
"ca000.backblaze.com.",
"ca001.backblaze.com.",
"ca002.backblaze.com.",
+ "ca004.backblaze.com.",
+ "ca5-excel-collab.officeapps.live.com.",
"ca80a1adb12a4fbdac5ffcbc944e9a61.pacloudflare.com.",
- "cached-ad.fyber.com.",
+ "cac-collabrtc.officeapps.live.com.",
"cached.rebuyengine.com.",
"cachenetworks.com.",
- "caia.treasury.gov.",
"caidc.apis.honeywell.com.",
"cainiao.com.",
"caixa.gov.br.",
"california.remotepc.com.",
+ "caltech.edu.",
+ "camoe.cn.",
"camsoda.com.",
"canada.remotepc.com.",
"canberra.remotepc.com.",
"capetown.remotepc.com.",
- "car-cloud-cn.net.",
+ "captaina.co.",
"cardiff.remotepc.com.",
"cardinalcorp-my.sharepoint.com.",
"care.novaicare.com.",
- "carystudio.com.",
+ "cartech365-my.sharepoint.com.",
"cat.hbwrapper.com.",
"cat1.hbwrapper.com.",
"cat2.hbwrapper.com.",
+ "cat3.hbwrapper.com.",
"catholichealth.net.",
"cbox.ws.",
"cbsipv4.shuzilm.cn.",
+ "ccare2.ccr1.com.",
+ "ccboemd-my.sharepoint.com.",
+ "cccis-my.sharepoint.com.",
"ccf.ivalua.com.",
"cchmc-my.sharepoint.com.",
"cchmc.sharepoint.com.",
"ccs.umeng.com.",
- "cdn-audio-gcp-media.getepic.com.",
- "cdn-f.heylink.me.",
"cdn-gcp-media-drm.getepic.com.",
"cdn-gcp-media.getepic.com.",
- "cdn-mc-eu1-fd5f74b2.bereal.network.",
- "cdn-t.vb24131crasosnemesis.com.",
+ "cdn-ima.33across.com.",
+ "cdn-pci.optimizely.com.",
+ "cdn-static.hulu.com.",
+ "cdn-t.e9d95b39c9982e3b965a27ac72ru971591.com.",
"cdn-us.algoliaradar.com.",
"cdn-us1.bereal.network.",
"cdn-video-gcp-media.getepic.com.",
+ "cdn.adtarget.market.",
+ "cdn.adtarget.me.",
+ "cdn.adtwister.me.",
"cdn.bereal.network.",
- "cdn.coinzilla.io.",
- "cdn.conveythis.com.",
+ "cdn.cloudimagesb.com.",
+ "cdn.cxense.com.",
"cdn.deepintent.com.",
"cdn.ftd.agency.",
+ "cdn.getyourguide.com.",
"cdn.groupbycloud.com.",
"cdn.instapagemetrics.com.",
- "cdn.overleaf.com.",
- "cdn.piano.io.",
- "cdn.preciso.net.",
+ "cdn.jetphotos.com.",
+ "cdn.nba.com.",
+ "cdn.plyr.io.",
"cdn.qq.com.",
"cdn.sierrapacificgroup.com.",
"cdn.skcrtxr.com.",
- "cdn.staticfile.org.",
"cdn.tapdb-dev.com.",
"cdn.uxfeedback.ru.",
+ "cdn1.onlineaccess1.com.",
"cdn1.wixdns.net.",
"cdn11.bigcommerce.com.",
+ "cdn3.optimizely.com.",
+ "cdn4.apple-mapkit.com.",
"cdnetworks.net.",
+ "cdnfp.accurint.com.",
"cdngslb.com.",
- "cdnimg.izooto.com.",
"cdntm.hsbc.co.uk.",
"cdnwidget.com.",
+ "cds.glanceapis.com.",
"cds.swishapps.ai.",
+ "cdsi.signal.org.",
"cdt.ca.gov.",
- "cdtfa.ca.gov.",
"cdxdns.com.",
"cdxflare.com.",
+ "cecivav6.uscis.gov.",
"cedexis-test.com.",
+ "cedexis.pc.cdn.bitgravity.com.",
"cedock.com.",
"centralmichigan-my.sharepoint.com.",
"centrexit.com.",
"cfa.fidelity.com.",
"cform.loyalhealth.com.",
+ "challenges.app.",
+ "change.org.cdn.cloudflare.net.",
"changehealthcare.com.",
"charlotte.remotepc.com.",
- "chat-masters-mongo-prod.streamlayer.io.",
"check2.lloydsbank.co.uk.",
- "checkout.visa.com.",
- "chek.zennolab.com.",
"chennai.remotepc.com.",
- "chi-ns2.greengeeks.com.",
"chi01pap001.storage.live.com.",
- "chi01pap001files.storage.live.com.",
"chi01pap002.storage.live.com.",
- "chi01pap002files.storage.live.com.",
- "chicago.remotepc.com.",
"chicago2.remotepc.com.",
- "chinacache.net.",
"chinaccl-a.haplat.net.",
"chinaccl-b.haplat.net.",
"chinaccl-c.haplat.net.",
@@ -1089,6 +1176,8 @@ var FakeECSFQDNs = container.NewMapSet(
"chippewavalley-my.sharepoint.com.",
"choctawnationofoklahoma-my.sharepoint.com.",
"choctawnationofoklahoma.sharepoint.com.",
+ "chopo-my.sharepoint.com.",
+ "chrome.com.",
"chtsite.com.",
"chubbgroup-my.sharepoint.com.",
"chubbgroup.sharepoint.com.",
@@ -1096,7 +1185,9 @@ var FakeECSFQDNs = container.NewMapSet(
"cico.com.",
"cignium-my.sharepoint.com.",
"cinarra.com.",
+ "cintas1-my.sharepoint.com.",
"cintas1.sharepoint.com.",
+ "cis.citrix.com.",
"cisco-my.sharepoint.com.",
"cisco.app.box.com.",
"cisco.sharepoint.com.",
@@ -1104,80 +1195,80 @@ var FakeECSFQDNs = container.NewMapSet(
"cityofelpaso-my.sharepoint.com.",
"cjfgob-my.sharepoint.com.",
"cjfgob.sharepoint.com.",
- "ckmap.mediav.com.",
"cl-data.ads.heytapmobi.com.",
- "cl-gl1e62abf5.preprod-gcdn.co.",
- "cl.vd.cloud.360safe.com.",
"cl2009.com.",
+ "clarksons-my.sharepoint.com.",
"claude.ai.",
"clearesult5-my.sharepoint.com.",
"clearesult5.sharepoint.com.",
"cleveland.remotepc.com.",
+ "clevelandclinic-my.sharepoint.com.",
"clevelandclinic.sharepoint.com.",
+ "cli.speedtest.net.",
"click-eu.precmd.com.",
- "click.directrankcl.com.",
"click.pclk.name.",
- "click.victoriassecret.com.",
"client-log.box.com.",
"client-tracking.omiapp.me.",
"client-updates.lumu.io.",
+ "client-upload.cn-shanghai.log.aliyuncs.com.",
+ "clients.us2.code42.com.",
+ "cliftonlarsonallen-my.sharepoint.com.",
"cliftonlarsonallen.sharepoint.com.",
- "clips-events.apple.com.",
+ "cllp-my.sharepoint.com.",
"cloud-config-service.rtc.aliyuncs.com.",
+ "cloud-links.net.",
"cloud-rest.lenovomm.com.",
"cloud.browser.360.cn.",
"cloud.typenetwork.com.",
"cloud.vmp.onezapp.com.",
"cloud.zoom.us.",
"cloudbirds.cn.",
- "clouddata.turbowarp.org.",
- "cloudflarecp.com.",
- "cloudflareportal.com.",
"cloudlinks.cn.",
"cloudsvc.policypak.com.",
"cloverparksd-my.sharepoint.com.",
"cm-x.mgid.com.",
+ "cm.mobydix.com.",
"cmgate.vip.qq.com.",
"cmpassport.com.",
"cms.ejoyspace.com.",
- "cms.instiengage.com.",
"cn-beijing.log.aliyuncs.com.",
+ "cn-guangzhou.log.aliyuncs.com.",
"cn-hangzhou.log.aliyuncs.com.",
"cn-hangzhou.oss-cdn.aliyun-inc.com.",
"cn-hongkong.log.aliyuncs.com.",
+ "cn-mib2high-mbbservices.audi-connect.cn.",
+ "cn-mib2plus.mbbservices-1a.audi-connect.cn.",
"cn-qingdao.log.aliyuncs.com.",
"cn-shanghai.log.aliyuncs.com.",
- "cn-singapore-lls01-d01.sls-pub.farlightgames.com.",
"cn.gcloudcs.com.",
"cn.mvconf.50union.com.",
"cname.pendo.io.",
"cnbglobal-my.sharepoint.com.",
"cnmc-my.sharepoint.com.",
"cnmc.sharepoint.com.",
+ "cnplug.ttlock.com.",
"cnv2.mclean.50union.com.",
"cnzz.com.",
"co-vcode-od.vivoglobal.com.",
"co.amx.rcs.telephony.goog.",
"codacloud.net.",
"code.etracker.com.",
- "code.piano.io.",
- "codepush.akulaku.net.",
"codis-bak.ngb.haplat.net.",
"codis.ngb.haplat.net.",
"cofile.net.",
"cohnreznick-my.sharepoint.com.",
"cohnreznick.sharepoint.com.",
- "collect-v6.51.la.",
+ "collabrtc-geo.rtc.trafficmanager.net.",
+ "collabrtc.officeapps.live.com.",
"collect.trendyol.com.",
- "collector.getyourguide.com.",
+ "collections.preveil.com.",
"collector.seexh.com.",
"collector.wdp.brave.com.",
"collector.xhamster.com.",
- "colliervilleschools-my.sharepoint.com.",
"columbus.remotepc.com.",
- "columbusk12oh-my.sharepoint.com.",
"com.multicdn.cloudinary.com.",
"com.yangyi19.com.",
+ "comet2.ct.pb.com.",
"cometglobal.cf.t3cloud.pb.com.",
"cometservd1.pb.com.",
"commerce.safe.360.cn.",
@@ -1187,8 +1278,7 @@ var FakeECSFQDNs = container.NewMapSet(
"common.xshareapp.com.",
"compass.corebridgefinancial.com.",
"compiles.overleafusercontent.com.",
- "components.mywebsitebuilder.com.",
- "concur.com.",
+ "comserver.eu1.mspa.n-able.com.",
"config-inmobi-comtm.trafficmanager.net.",
"config-security.com.",
"config.a-m-p.xyz.",
@@ -1199,17 +1289,20 @@ var FakeECSFQDNs = container.NewMapSet(
"config.y5en.com.",
"config2.cmpassport.com.",
"configdl.teamviewer.com.",
- "conn-service-cn-03.allawntech.com.",
+ "conn-service-eu-05.allawnos.com.",
"connect.garenanow.com.",
- "connectivitycheck.unisoc.com.",
+ "connect.idocdn.com.",
"constel1-my.sharepoint.com.",
- "content.betfair.com.",
+ "constel1.sharepoint.com.",
+ "consumer.huawei.com.",
+ "content-management-files.canva.com.",
"content.citizensbankonline.com.",
"content.discover.com.",
"content.discovercard.com.",
"content.ebanking-services.com.",
"content.gap.com.",
"content.ibanking-services.com.",
+ "content.maxconnector.com.",
"content.production.cdn.art19.com.",
"content.ssctech.com.",
"content22.bancanet.banamex.com.",
@@ -1220,7 +1313,6 @@ var FakeECSFQDNs = container.NewMapSet(
"context.reverso.net.",
"control-out.mna.qq.com.",
"cookie-sync.bidmyadz.com.",
- "cookiehub.eu.",
"coolkit.cc.",
"copenhagen.remotepc.com.",
"cordial.com.",
@@ -1229,16 +1321,22 @@ var FakeECSFQDNs = container.NewMapSet(
"core.omiapp.me.",
"corebridgefinancial-my.sharepoint.com.",
"corebridgefinancial.com.",
+ "corebridgefinancial.sharepoint.com.",
+ "coresite.mm.fcix.net.",
+ "corient-my.sharepoint.com.",
+ "corient.sharepoint.com.",
+ "coros-log.cn-beijing.log.aliyuncs.com.",
"corpmdm.v.aaplimg.com.",
+ "cortexmg.com.",
"corvel-my.sharepoint.com.",
- "covers.vitalbook.com.",
- "coyotesusd-my.sharepoint.com.",
- "cp2.cloudflare.com.",
+ "corvel.sharepoint.com.",
+ "cpgplc-my.sharepoint.com.",
+ "cpgplc.sharepoint.com.",
"cpm.appocean.media.",
"cpm.aserve1.net.",
- "cpm.bidmyqps.xyz.",
"cpm.catapultx.com.",
"cpm.qortex.ai.",
+ "cpm.unibots.in.",
"cpm.vuukle.net.",
"cpm.xrtb.io.",
"cpncorp-my.sharepoint.com.",
@@ -1249,32 +1347,41 @@ var FakeECSFQDNs = container.NewMapSet(
"crashlytics.com.",
"crashsight.qq.com.",
"crashsight.wetest.net.",
+ "creator.pdf24.org.",
+ "cred-prod-01.trafficmanager.net.",
+ "cred.microsoft.com.",
+ "crlocsp.cn.",
"crobox.com.",
"crobox.io.",
"crossforward.com.",
"crowd.transitapp.com.",
"crowncastle-my.sharepoint.com.",
"crowncastle.sharepoint.com.",
- "crrepo.com.",
- "crutchfield.com.",
+ "crt.sectigo.com.",
"cs.globalsun.io.",
- "cs.openwebmedia.com.",
"csdn.net.",
- "cshealthforlife.com.",
"cspire.com.",
"cstse02.ultipro.com.",
"cstsew02.ultipro.com.",
"cstsn02.ultipro.com.",
"cta-eu1.hubspot.com.",
+ "cubetecn.com.",
+ "cuco.inforlandia.pt.",
"cuco.softi9.pt.",
"cummins365-my.sharepoint.com.",
"cummins365.sharepoint.com.",
"cunamutual-my.sharepoint.com.",
"cunamutual.sharepoint.com.",
+ "cus-region.present.officeapps.live.com.",
+ "custom-dialogs.thescore.com.",
"customer.homedepot.com.",
- "cvs.quantummetric.com.",
+ "customer.iad-03.braze.com.",
+ "cvshealth.com.",
+ "cwc-my.sharepoint.com.",
"cwc.sharepoint.com.",
+ "cwmpb-as.ruijienetworks.com.",
"cx.soft.360.cn.",
+ "cxcs.microsoft.net.",
"czechrepublic.remotepc.com.",
"d.docs.live.net.",
"d.pub.network.",
@@ -1286,6 +1393,7 @@ var FakeECSFQDNs = container.NewMapSet(
"d82f7a30-751a-4689-b7e9-19336a89ab46.prmutv.co.",
"d837da8d.cloudsrv.minerva-labs.com.",
"da.toponadss.com.",
+ "daacloud-my.sharepoint.com.",
"daemon.nanoleaf.me.",
"dallas.remotepc.com.",
"dallas2.remotepc.com.",
@@ -1296,28 +1404,26 @@ var FakeECSFQDNs = container.NewMapSet(
"dallaschildrens.sharepoint.com.",
"dalu-my.sharepoint.com.",
"dantri.com.vn.",
- "dapulse-res.cloudinary.com.",
- "darden-sync.quantummetric.com.",
- "data-graph.mlb.com.",
+ "daraz.com.",
+ "data-tr.rethinkad.com.",
+ "data.airtame.com.",
"data.analytics.thomsonreuters.com.",
"data.analytics.ux.quickbase.com.",
"data.assist.chromeriver.com.",
"data.bhrpendo.bamboohr.com.",
- "data.cn-singapore-lls01-d01.sls-pub.farlightgames.com.",
"data.cw.edgenuity.com.",
"data.dap.paylocity.com.",
- "data.data.achieve3000.com.",
- "data.data.aleks.com.",
"data.data.mheducation.com.",
"data.guide-app.zoominfo.co.",
- "data.guides.oncoursesystems.com.",
"data.guides.percipio.com.",
- "data.guides.wdesk.com.",
"data.hockeystack.com.",
+ "data.info.costar.com.",
"data.investing.com.",
"data.ipd.goto.com.",
"data.kuiniuca.com.",
"data.meitu.com.",
+ "data.nelnet.studentaid.gov.",
+ "data.p3nd0.sproutsocial.com.",
"data.pendo-cdn.pluralsight.com.",
"data.pendo-cobalt.westlaw.com.",
"data.pendo-tracking.seismic.com.",
@@ -1325,7 +1431,7 @@ var FakeECSFQDNs = container.NewMapSet(
"data.pendo.gomotive.com.",
"data.pendo.looker.app.",
"data.pendo.navimedix.com.",
- "data.pendo.progresslearning.com.",
+ "data.pendo.phenompeople.com.",
"data.pendo.saashr.com.",
"data.pendo.statista.com.",
"data.pendo.udsrv.com.",
@@ -1333,16 +1439,20 @@ var FakeECSFQDNs = container.NewMapSet(
"data.productanalytics.coconutcalendar.com.",
"data.queryly.com.",
"data.tracking.billtrust.com.",
+ "data.useranalytics.global.datasite.com.",
"data00.adlooxtracking.com.",
- "datadog.zendesk.com.",
- "datamma.guides.nelnet.com.",
+ "datacollection.uve.weibo.com.",
+ "datasec-kmsex-cn.heytapmobi.com.",
+ "datasink.cloudlinks.cn.",
"datasite.com.",
"datatheorem.com.",
+ "dayunlinks.cn.",
"db.onlinewebfonts.com.",
"db3pap002.storage.live.com.",
"db3pap003.storage.live.com.",
"db3pap005.storage.live.com.",
"db3pap006.storage.live.com.",
+ "db3pap007.storage.live.com.",
"db5pap001.storage.live.com.",
"dc-o.api.leiniao.com.",
"dc.di.atlas.samsung.com.",
@@ -1357,24 +1467,24 @@ var FakeECSFQDNs = container.NewMapSet(
"de-prod.asyncgw.teams.microsoft.com.",
"de.dt.rcs.telephony.goog.",
"de.hlth.io.mi.com.",
- "dealer.autopartners.net.",
"dealmoon.com.",
"decagon.ai.",
- "deepl.com.",
+ "defensestorm.codacloud.net.",
"delivery.upremium.asia.",
"dell-prod.actioniq.mr-in.com.",
"delta.quantummetric.com.",
"demant-my.sharepoint.com.",
- "demonii.com.",
- "dentonstudent-my.sharepoint.com.",
+ "demant.sharepoint.com.",
+ "demeter-int-ecom-collect.trendyol.com.",
"denver.remotepc.com.",
- "deqik.com.",
+ "deploy.preveil.com.",
"dev2.keepsolid.com.",
"deviceops.hstgps.com.",
"dewmobile.net.",
"dfaklj.tech.",
"dfamilk-my.sharepoint.com.",
- "dfw.mcleodhosted.com.",
+ "dfamilk.okta.com.",
+ "dfamilk.sharepoint.com.",
"dialpad.com.",
"dict.deepl.com.",
"dict.ntes53.netease.com.",
@@ -1382,58 +1492,57 @@ var FakeECSFQDNs = container.NewMapSet(
"digiapp.vietcombank.com.vn.",
"dingtalk.com.",
"dir.4.401402081.west-gcloud.codm.activision.com.",
+ "discoverpacifico.com.",
"discovery.ringcentral.biz.",
"dispatcher.omiapp.me.",
"dispatchosglobal.yuanshen.com.",
"distservp1.pb.com.",
- "dl.boxcloud.com.",
+ "dl.episerver.net.",
"dls-udc.dqa.samsung.com.",
"dls.di.atlas.samsung.com.",
+ "dm-sg.hybrid.ai.",
"dm-us.hybrid.ai.",
- "dmongo.adgrid.io.",
- "dms.deckers.com.",
+ "dmv.ca.gov.",
"dns-e.ns4v.icu.",
"dns-tunnel-check.googlezip.net.",
"dns.alidns.com.",
+ "dns.cloudflare.com.",
+ "dns.rubyfish.cn.",
+ "dns1.nettica.com.",
"dns101.register.com.",
"doceditor.wrike.com.",
- "docer-api.wps.cn.",
"docs.live.net.",
"document360.io.",
- "dodgeballhq.com.",
- "domaincfg.vivoglobal.com.",
+ "donaldson-my.sharepoint.com.",
+ "donaldson.sharepoint.com.",
"donewyork1.remotepc.com.",
"donewyork2.remotepc.com.",
"donewyork3.remotepc.com.",
- "dorchester2-my.sharepoint.com.",
- "dorchester2.sharepoint.com.",
"dosfo1.remotepc.com.",
"dosfo2.remotepc.com.",
"download.2.401402081.west-gcloud.codm.activision.com.",
+ "download.avira.com.",
"downloadcenter.genetec.com.",
"downloads.vivaldi.com.",
"dp.barclaysus.com.",
"dp.im.weibo.cn.",
"dpf.authorize.net.",
- "dpkg.mp.lura.live.",
"dpool.sina.com.cn.",
"dprprod-my.sharepoint.com.",
- "dps.jp.cinarra.com.",
+ "dprprod.sharepoint.com.",
"dr.netease.im.",
"dragate-cn.dc.heytapmobi.com.",
+ "dreame.tech.",
"drfdisvc.walmart.com.",
- "drops-register.ubi.com.",
+ "drsquatch.com.",
"dsa-eu.hybrid.ai.",
"dsm01pap001.storage.live.com.",
"dsm01pap001files.storage.live.com.",
"dsm01pap002.storage.live.com.",
- "dsm01pap002files.storage.live.com.",
"dsm01pap003.storage.live.com.",
"dsm01pap003files.storage.live.com.",
"dsm01pap004.storage.live.com.",
"dsm01pap004files.storage.live.com.",
- "dsm01pap005.storage.live.com.",
- "dsm01pap005files.storage.live.com.",
"dsm01pap006.storage.live.com.",
"dsm01pap006files.storage.live.com.",
"dsm01pap007.storage.live.com.",
@@ -1442,12 +1551,9 @@ var FakeECSFQDNs = container.NewMapSet(
"dsm01pap008files.storage.live.com.",
"dsm01pap009.storage.live.com.",
"dsm01pap009files.storage.live.com.",
- "dsm04pap001.storage.live.com.",
- "dsm04pap001files.storage.live.com.",
"dsm04pap002.storage.live.com.",
"dsm04pap002files.storage.live.com.",
- "dsm04pap003.storage.live.com.",
- "dsm04pap003files.storage.live.com.",
+ "dsp-impr2.youdao.com.",
"dsp.ads.umeng.com.",
"dstillery.com.",
"dtscout.com.",
@@ -1460,7 +1566,6 @@ var FakeECSFQDNs = container.NewMapSet(
"dun.163yun.com.",
"dypnsapi.aliyuncs.com.",
"dz.cyberhaven.io.",
- "dzfread.cn.",
"e-189.21cn.com.",
"e.189.cn.",
"e.cdnwidget.com.",
@@ -1546,65 +1651,19 @@ var FakeECSFQDNs = container.NewMapSet(
"e2c79.gcp.gvt2.com.",
"e2c8.gcp.gvt2.com.",
"e2c9.gcp.gvt2.com.",
- "e2cs01.gcp.gvt2.com.",
- "e2cs02.gcp.gvt2.com.",
- "e2cs03.gcp.gvt2.com.",
"e2cs04.gcp.gvt2.com.",
- "e2cs05.gcp.gvt2.com.",
- "e2cs06.gcp.gvt2.com.",
- "e2cs07.gcp.gvt2.com.",
- "e2cs08.gcp.gvt2.com.",
- "e2cs09.gcp.gvt2.com.",
- "e2cs10.gcp.gvt2.com.",
- "e2cs11.gcp.gvt2.com.",
- "e2cs12.gcp.gvt2.com.",
"e2cs13.gcp.gvt2.com.",
- "e2cs14.gcp.gvt2.com.",
- "e2cs15.gcp.gvt2.com.",
- "e2cs16.gcp.gvt2.com.",
- "e2cs17.gcp.gvt2.com.",
- "e2cs18.gcp.gvt2.com.",
- "e2cs19.gcp.gvt2.com.",
- "e2cs20.gcp.gvt2.com.",
- "e2cs21.gcp.gvt2.com.",
"e2cs22.gcp.gvt2.com.",
- "e2cs23.gcp.gvt2.com.",
- "e2cs24.gcp.gvt2.com.",
- "e2cs25.gcp.gvt2.com.",
- "e2cs26.gcp.gvt2.com.",
- "e2cs27.gcp.gvt2.com.",
- "e2cs28.gcp.gvt2.com.",
"e2cs29.gcp.gvt2.com.",
- "e2cs30.gcp.gvt2.com.",
- "e2cs31.gcp.gvt2.com.",
- "e2cs32.gcp.gvt2.com.",
- "e2cs33.gcp.gvt2.com.",
- "e2cs34.gcp.gvt2.com.",
"e2cs35.gcp.gvt2.com.",
- "e2cs36.gcp.gvt2.com.",
"e2cs37.gcp.gvt2.com.",
"e2cs38.gcp.gvt2.com.",
"e2cs39.gcp.gvt2.com.",
- "e2cs40.gcp.gvt2.com.",
- "e2cs41.gcp.gvt2.com.",
- "e2cs42.gcp.gvt2.com.",
- "e2cs43.gcp.gvt2.com.",
"e2cs44.gcp.gvt2.com.",
- "e2cs45.gcp.gvt2.com.",
- "e2cs46.gcp.gvt2.com.",
- "e2cs47.gcp.gvt2.com.",
- "e2cs48.gcp.gvt2.com.",
"e2cs49.gcp.gvt2.com.",
- "e2cs50.gcp.gvt2.com.",
- "e2cs51.gcp.gvt2.com.",
- "e2cs52.gcp.gvt2.com.",
- "e2cs53.gcp.gvt2.com.",
- "e2cs54.gcp.gvt2.com.",
- "e2cs55.gcp.gvt2.com.",
"e43.ultipro.com.",
"e488cdb0-e7cb-4d91-9648-60d437d8e491.prmutv.co.",
"e5de3d23065c4748b155c28e6fa36f3e.pacloudflare.com.",
- "e99.cyberhaven.io.",
"eafd-footprint.elasticafd.net.",
"eafddirect.msedge.net.",
"eagle-my.sharepoint.com.",
@@ -1616,11 +1675,12 @@ var FakeECSFQDNs = container.NewMapSet(
"eastus2-gas.guestconfiguration.azure.com.",
"ebaypay-app.quantummetric.com.",
"ebaypay-sync.quantummetric.com.",
+ "ebm.bmj.com.",
"ecatholic.com.",
+ "ecco-my.sharepoint.com.",
+ "ecn.t3.tiles.virtualearth.net.",
"ecom.wixapps.net.",
- "ecommerce.iap.unity3d.com.",
"ecs-gallatin-c2s.trafficmanager.net.",
- "ecs.tagtoo.co.",
"edge.api.brightcove.com.",
"edge.txryan.com.",
"edgecdn.ru.",
@@ -1629,7 +1689,7 @@ var FakeECSFQDNs = container.NewMapSet(
"edisonintl-my.sharepoint.com.",
"edisonintl.sharepoint.com.",
"editor.wix.com.",
- "edr.ringcentral.com.",
+ "editorial.femaledaily.com.",
"education-certification.youdao.com.",
"ee-share.com.",
"efercro.com.",
@@ -1640,18 +1700,23 @@ var FakeECSFQDNs = container.NewMapSet(
"eisaihhc-my.sharepoint.com.",
"ejoyspace.com.",
"elaracaring-my.sharepoint.com.",
+ "elaracaring.sharepoint.com.",
"ele.me.",
"elemecdn.com.",
+ "email.ticketsatwork.com.",
"emailaptitude.com.",
"emerson-my.sharepoint.com.",
"emerson.sharepoint.com.",
"emo.v-mate.mobi.",
- "en.showsnob.com.",
- "enaple.com.",
+ "employersolution-my.sharepoint.com.",
"endpointprotector.com.",
"engage.wixapps.net.",
"engagementapi.skype.com.",
+ "engine.phn.doublepimp.com.",
+ "enplug.com.",
+ "ens.rest.gti.trellix.com.",
"ent.box.com.",
+ "enterprise.spendclarity.visa.com.",
"envoy-ios-prod.getepic.com.",
"envysion.com.",
"epdg.vowifi.cspire.com.",
@@ -1659,51 +1724,69 @@ var FakeECSFQDNs = container.NewMapSet(
"epic1.sharepoint.com.",
"epicmobile.ohsu.edu.",
"epoch.cloud.",
- "eponesh.com.",
"eportal.fda.gov.ph.",
"epsnj-my.sharepoint.com.",
"epsnj.sharepoint.com.",
- "epsonconnect.com.",
+ "epss.alibaba-inc.com.",
"errlog.umeng.com.",
"errlogos.umeng.com.",
"errnewlog.umeng.com.",
"errnewlogos.umeng.com.",
"errortracking.deepl.com.",
"esignlive.com.",
- "esm.archive.org.",
"essence.com.",
"estafetamx-my.sharepoint.com.",
+ "ethosenergygroup.sharepoint.com.",
"etracker.com.",
"etsv2.datalake.gameloft.com.",
"eu-aa.online-metrix.net.",
"eu-api.asm.skype.com.",
"eu-prod.asyncgw.teams.microsoft.com.",
"eu-push.api.intl.miui.com.",
- "eu-west-1.console.aws.amazon.com.",
"eu.galleryapi.micloud.xiaomi.net.",
+ "eu.i.posthog.com.",
"eu.statusapi.micloud.xiaomi.net.",
+ "eu.vg.ac.pvp.net.",
"eu1.badoo.com.",
"eu1.bumble.com.",
+ "eu1a-excel-collab.officeapps.live.com.",
+ "eu1a-powerpoint-collab.officeapps.live.com.",
+ "eu2.iceporn.xxx.",
+ "eu2a-excel-collab.officeapps.live.com.",
+ "eu2a-powerpoint-collab.officeapps.live.com.",
+ "eu2a-word-collab.officeapps.live.com.",
+ "eu4-excel-collab.ocs.trafficmanager.net.",
+ "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-powerpoint-geo.wac.trafficmanager.net.",
+ "euc-powerpoint.officeapps.live.com.",
+ "euc-word-edit-geo.wac.trafficmanager.net.",
+ "euc-word-edit.officeapps.live.com.",
+ "euc-word-view-geo.wac.trafficmanager.net.",
+ "euc-word-view.officeapps.live.com.",
"euler-saas-cn.heytapmobi.com.",
"europe-west1-skyuk-uk-pa-tds-prod.cloudfunctions.net.",
"europe.remotepc.com.",
+ "eus-www.sway-extensions.com.",
"eus.his.arc.azure.com.",
"eus.his.hybridcompute.trafficmanager.net.",
"eus2.guestagentsvc-prod.trafficmanager.net.",
"eus2.his.arc.azure.com.",
"euw1.chat.si.riotgames.com.",
"eve.gameloft.com.",
- "event-ingestion.yazio-analytics.com.",
"event-tracking-project.ap-southeast-1.log.aliyuncs.com.",
"event.evtm.53.com.",
- "event.instiengage.com.",
- "events.proper.io.",
+ "event.togothermany.com.",
"events.swishapps.ai.",
+ "ex-adreq-asia.vivoglobal.com.",
"exappupgrade.vivoglobal.com.",
"excel-collab.officeapps.live.com.",
+ "exitbee.com.",
"exodus.desync.com.",
"exp.host.",
"experimental-api.asm.skype.com.",
@@ -1711,12 +1794,11 @@ var FakeECSFQDNs = container.NewMapSet(
"exponential.com.",
"expresspros-my.sharepoint.com.",
"expresspros.sharepoint.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-ber1-1.xx.fbcdn.net.",
"external-bos5-1.xx.fbcdn.net.",
"external-bru2-1.xx.fbcdn.net.",
"external-den2-1.xx.fbcdn.net.",
@@ -1724,10 +1806,6 @@ var FakeECSFQDNs = container.NewMapSet(
"external-dfw5-2.xx.fbcdn.net.",
"external-dus1-1.xx.fbcdn.net.",
"external-fra3-1.xx.fbcdn.net.",
- "external-fra3-2.xx.fbcdn.net.",
- "external-fra5-1.xx.fbcdn.net.",
- "external-fra5-2.xx.fbcdn.net.",
- "external-ham3-1.xx.fbcdn.net.",
"external-hou1-1.xx.fbcdn.net.",
"external-iad3-1.xx.fbcdn.net.",
"external-iad3-2.xx.fbcdn.net.",
@@ -1743,29 +1821,29 @@ var FakeECSFQDNs = container.NewMapSet(
"external-mia3-1.xx.fbcdn.net.",
"external-mia3-2.xx.fbcdn.net.",
"external-msp1-1.xx.fbcdn.net.",
- "external-muc2-1.xx.fbcdn.net.",
"external-ord5-1.xx.fbcdn.net.",
"external-ord5-2.xx.fbcdn.net.",
+ "external-qro1-1.xx.fbcdn.net.",
+ "external-qro1-2.xx.fbcdn.net.",
"external-sea1-1.xx.fbcdn.net.",
"external-sjc3-1.xx.fbcdn.net.",
- "external-waw2-1.xx.fbcdn.net.",
- "external-waw2-2.xx.fbcdn.net.",
"ezcollab-my.sharepoint.com.",
- "ezojs.com.cdn.cloudflare.net.",
+ "ezcollab.sharepoint.com.",
"f-p-sandbox.bytedance.net.",
- "f1s.powerschool.com.",
+ "f389d50a-32e0-478b-9d4b-2d4592528bea.prmutv.co.",
"fa3fca7ce79f4b81a39f216e916397d5.pacloudflare.com.",
+ "faa37ffc-c269-46a8-b7ca-286d746e61e7.resources.office.net.",
"faas.marktplaats.nl.",
- "faceit.com.",
"factor.reg.163.com.",
"factset.com.",
- "family.adguard-dns.com.",
"fanduel.quantummetric.com.",
"fanyiegg.youdao.com.",
"fastenal-my.sharepoint.com.",
- "fastformstax.prosystemfx.com.",
+ "fastenal.sharepoint.com.",
+ "fastlane.rubiconproject.com.",
"fastly-cloud.typenetwork.com.",
"fastly.cedexis-test.com.",
+ "fastly.musiclike.top.",
"faves.grow.me.",
"fbinsmi.sharepoint.com.",
"fdccpaadaptor.forddirectservices.com.",
@@ -1779,13 +1857,14 @@ var FakeECSFQDNs = container.NewMapSet(
"fef.msua09.manage.microsoft.com.",
"fef.msub06.manage.microsoft.com.",
"fef.msub07.manage.microsoft.com.",
+ "fema.gov.",
"femaledaily.com.",
"fengkongcloud.com.",
"ferringgroup-my.sharepoint.com.",
"fgwn01.ultipro.com.",
+ "fhmc-my.sharepoint.com.",
"fi.telephony.goog.",
"field59.com.",
- "files.crazygames.com.",
"files.jotform.com.",
"finalsite.com.",
"finalsite.net.",
@@ -1794,15 +1873,16 @@ var FakeECSFQDNs = container.NewMapSet(
"fiscal.treasury.gov.",
"five9.com.",
"flashcards.vitalsource.com.",
+ "flashjoin.net.",
"fleet.todyl.com.",
"flip.to.",
"flixcdn.com.",
- "floodlight.design.",
+ "flypgs.com.",
"flyspirit-my.sharepoint.com.",
+ "flyspirit.sharepoint.com.",
"fm.printaudit.com.",
"fmcna-my.sharepoint.com.",
"fmcna.sharepoint.com.",
- "fmcschedule.com.",
"fn.us.ipqscdn.com.",
"fo.iemiq.com.",
"forcesafesearch.google.com.",
@@ -1810,124 +1890,135 @@ var FakeECSFQDNs = container.NewMapSet(
"form.jotform.com.",
"forms-eu1.hscollectedforms.net.",
"forms-eu1.hsforms.com.",
- "forms.hubspot.com.",
+ "forthepeople0-my.sharepoint.com.",
"fortisimperious.com.",
"fortworth.remotepc.com.",
"foundation-ipv4.youdao.com.",
+ "foxrothschild-my.sharepoint.com.",
"fpdlp.applxweb.com.",
+ "fpt.brainly.com.",
"fr-prod.asyncgw.teams.microsoft.com.",
"fr1.ecdn2.bumbcdn.com.",
"fran.frvr.com.",
"frankfurt.remotepc.com.",
+ "frc-collabrtc.officeapps.live.com.",
+ "free.publictracker.xyz.",
"fremont.remotepc.com.",
"freseniusmedicalcare.com.",
"fresnocounty-my.sharepoint.com.",
"fs.ultiproworkplace.com.",
"fsu-my.sharepoint.com.",
"fsu.sharepoint.com.",
- "ftb.ca.gov.",
"fticonsulting-my.sharepoint.com.",
"fticonsulting.sharepoint.com.",
"ftke02.ultipro.com.",
"ftkew02.ultipro.com.",
"ftkn01.ultipro.com.",
"ftkn02.ultipro.com.",
+ "fullsailedu-my.sharepoint.com.",
"fusd-my.sharepoint.com.",
"fusd.sharepoint.com.",
+ "futurefoundations-my.sharepoint.com.",
+ "futurefoundations.sharepoint.com.",
+ "futurhealth.com.",
"fxltsbl.com.",
- "g10498469755.co.",
+ "g.ezodn.com.",
+ "g1584674684.co.",
"g9hc4.cn.",
+ "ga.badambiz.com.",
"galaxy.safe.360.cn.",
"galaxyappstore.com.",
- "galeapps.gale.com.",
+ "gamecenter-api-dra.hispace.hihonorcloud.com.",
"gameloft.com.",
"gamemonkey.org.",
"gamepigeon.net.",
- "gaspra.iad-03.braze.com.",
+ "gardaworldcorp-my.sharepoint.com.",
"gateway.ultiproworkplace.com.",
+ "gb-vodafone.rcs.telephony.goog.",
"gb.ee.rcs.telephony.goog.",
"gb.o2.rcs.telephony.goog.",
- "gbc-owl.officeapps.live.com.",
+ "gbc-excel-collab.officeapps.live.com.",
"gbc-word-view.officeapps.live.com.",
+ "gbmcorp-my.sharepoint.com.",
+ "gc.apple.com.",
"gcash-api.pulseid.com.",
"gccmod.ecs.office.com.",
"gcdn.co.",
- "gce-beacons.gcp.gvt2.com.",
"gcloud.qq.com.",
"gcloudcs.com.",
"gcloudsdk.com.",
- "gcs.garmin.com.",
"gcs.sc-cdn.net.",
+ "gdc-reqs-a.ngb.haplat.net.",
+ "gdc-scouccl1.haplat.net.",
+ "gdc-scouccl2.haplat.net.",
"gdid.datalake.gameloft.com.",
"gdpr.loopme.com.",
"geappl.io.",
"geappliances-my.sharepoint.com.",
"geappliances.sharepoint.com.",
- "geico-app.quantummetric.com.",
"geico-sync.quantummetric.com.",
"geniusmonkey.com.",
"geo-dra.platform.hicloud.com.",
"geoplugin.net.",
- "geotargetly-api-1.com.",
- "get-xmore-links8.com.",
"getadmiral.com.",
"getbutton.io.",
"getnitropack.com.",
"gettopple.com.",
"getui.net.",
- "getxray.app.",
+ "gfbanruralgt-my.sharepoint.com.",
"gfmfxefsrr-my.sharepoint.com.",
- "gifshow.com.",
"gitlab.com.",
"gla.gameloft.com.",
"glic-my.sharepoint.com.",
"glic.sharepoint.com.",
"global-tokenserver-la.headline.uodoo.com.",
"global.datasite.com.",
+ "globalchat1.com.",
"globalsigncdn.com.cdn.cloudflare.net.",
"globalsun.io.",
+ "globalvale.sharepoint.com.",
+ "gme.qcloud.com.",
"gnc.com.",
- "go.gale.com.",
- "go.myavlive.com.",
+ "go.pdfforge.org.",
+ "go.xxxviijmp.com.",
"goaffpro.com.",
"goconfluent-my.sharepoint.com.",
"goconfluent.sharepoint.com.",
- "golf.com.",
+ "gohighlevel.com.",
+ "gonines.com.",
"google.org.",
"googledomains.com.",
"googlesync.permutive.com.",
"gosport.remotepc.com.",
"gov-bam.nr-data.net.",
"gov-bam.nr-data.net.cdn.cloudflare.net.",
+ "gowustl-my.sharepoint.com.",
"grab.zoom.us.",
- "gradle.org.",
"gravitec.net.",
+ "greatwolf-my.sharepoint.com.",
"greenville.remotepc.com.",
"group-ib.com.",
"grouponeauto-my.sharepoint.com.",
- "grpc-sdk.streamlayer.io.",
- "grpc.streamlayer.io.",
"grpc.vivintsky.com.",
+ "grs.dbankcloud.asia.",
"gslb.finzfin.com.",
"gslb.sgw.shopeemobile.com.",
"gslb.xiaohongshu.com.",
+ "gsp47-ssl.ls.apple.com.",
+ "gsp85-ssl.ls.apple.com.",
"gstbocessscta-my.sharepoint.com.",
"gtimg.cn.",
"guid.tpns.sgp.tencent.com.",
"gw5.push.mcp.weibo.cn.",
"gwadar.cn.",
- "gx-api.geniex.com.",
"gyazo.com.",
"gz0.googleusercontent.com.",
"h-5h8i3ud8.online-metrix.net.",
- "h-adp.online-metrix.net.",
"h-discover.online-metrix.net.",
"h-e04kqxof.online-metrix.net.",
"h-ebay.online-metrix.net.",
- "h-fisglobal.online-metrix.net.",
"h-homedepot.online-metrix.net.",
"h-online.citi.online-metrix.net.",
- "h-rbs-bank.online-metrix.net.",
"h-sdk.online-metrix.net.",
"h-signifyd.online-metrix.net.",
"h-uptodate.online-metrix.net.",
@@ -1935,107 +2026,117 @@ var FakeECSFQDNs = container.NewMapSet(
"h-walmart.online-metrix.net.",
"h.app.wdesk.com.",
"h.online-metrix.net.",
- "h107833-ecdn.mp.lura.live.",
- "haka.ruselabs.com.",
"hamina.remotepc.com.",
"handmadewithjoann.com.",
- "hanoi.remotepc.com.",
"hapsee.cn.",
- "harmonyoffice-my.sharepoint.com.",
- "harrisonk12msus-my.sharepoint.com.",
"harry.lu.",
"hawaii.remotepc.com.",
- "hazelcast.com.",
- "hbe199.hybrid.ai.",
+ "hbgk.net.",
"hbopenbid-apac-v2.pubmnet.com.",
"hbwrapper.com.",
- "hd-ext-v1.log.mgtv.com.",
"hdi365-my.sharepoint.com.",
"hdi365.sharepoint.com.",
+ "hdsupplyinc-my.sharepoint.com.",
+ "hdsupplyinc.sharepoint.com.",
"healthequity-my.sharepoint.com.",
"healthequity.sharepoint.com.",
- "hearst-prod.actioniq.mr-in.com.",
"hecheck.bitmyanmar.info.",
- "helloid.com.",
"hellomedian.com.",
+ "help.zscaler.com.",
+ "hengam.io.",
"henricova-my.sharepoint.com.",
"hermes-us.inspidspad.com.",
"hetangsmart.com.",
"heytapdownload.com.",
"heytapmobi.com.",
+ "hft-prod.actioniq.mr-in.com.",
"hiecheimaetu.com.",
- "highpointuniversity-my.sharepoint.com.",
- "highwebmedia.com.",
"highwire.org.",
"hillingdon-my.sharepoint.com.",
"hillsboroughcounty-my.sharepoint.com.",
"hisearch-dra.dt.dbankcloud.com.",
"hismarttv.com.",
- "hismileteeth.com.",
+ "hitachigroup-my.sharepoint.com.",
"hits.getelevar.com.",
"hk.gcloudcs.com.",
"hk.wechat.com.",
- "hk2.jiedian.stream.",
+ "hlana.gamedistribution.com.",
+ "hogarthww-my.sharepoint.com.",
"home.highwire.org.",
"homedepot.quantummetric.com.",
"honeywell.com.",
"honeywellprod-my.sharepoint.com.",
"honeywellprod.sharepoint.com.",
"hongkong.remotepc.com.",
+ "houstonmethodist1-my.sharepoint.com.",
"houstonmethodist1.sharepoint.com.",
"houtx-my.sharepoint.com.",
+ "houtx.sharepoint.com.",
+ "hpcc2013-my.sharepoint.com.",
"hpfalkaj.deepl.com.",
"hpkaj.deepl.com.",
"hpplay.cn.",
"hrsa.gov.",
"hstgps.com.",
- "html.it.",
"html5.qq.com.",
"htms.heytapmobi.com.",
+ "http2.monetate.edgekey.net.",
+ "httpdns.music.163.com.",
"httpdns.y5en.com.",
"huan.tv.",
"huaweicloud.com.",
+ "huaweicloudwaf.com.",
+ "hub.gibraltarsoftware.com.",
"hubble.netease.com.",
+ "hubble.officeapps.live.com.",
+ "hubblecontent.osi.office.net.",
"hubcloud.com.cn.",
"hubspotemail.net.",
"huion.cn.",
- "huntsvillecityschools-my.sharepoint.com.",
"huorong.cn.",
"huroncg-my.sharepoint.com.",
+ "huroncg.sharepoint.com.",
"hwapps-o.api.leiniao.com.",
- "hypixel.net.",
+ "hypergames.top.",
"hysteryale-my.sharepoint.com.",
"hysteryale.sharepoint.com.",
- "hyvee.quantummetric.com.",
- "hzmk.site.",
"hzmklvdieo.com.",
+ "i-pinimg-com-cdn-cloudflare-net.pinimg.com.cdn.cloudflare.net.",
"i-sg01a.ocloud.heytapmobi.com.",
- "i.discogs.com.",
+ "i.inspi-dsp.com.",
+ "i.ipromote.com.",
"i.magazine.heytapmobi.com.",
- "i.omiapp.me.",
+ "i.qchannel03.cn.",
"i.voe.sx.",
- "i18n-va-api.faceueditor.com.ttdns2.com.",
+ "i1-pinimg-com-cdn-cloudflare-net.pinimg.com.",
"i6-vn.weather.oppomobile.com.",
- "ia.51.la.",
"iaas.jdcloud.com.",
+ "iac-demo.idmgroup.com.",
+ "ibclick.stream.",
"ibm.account.box.com.",
"ibm.box.com.",
- "ibm.monday.com.",
"ibsrv.net.",
"icalendars.app.",
+ "iceholdings-my.sharepoint.com.",
"iceholdings.sharepoint.com.",
"ichano.cn.",
- "iconmonstr.com.",
"icons.bitwarden.net.",
"id-ooredoo.rcs.telephony.goog.",
"id-telkom.rcs.telephony.goog.",
"id-timer-appstore.vivoglobal.com.",
+ "id-xl.rcs.telephony.goog.",
+ "id.maxon.net.",
+ "id.nbc.com.",
"id.remoteutilities.com.",
+ "id.seexh.com.",
+ "id6.me.",
+ "id71.remoteutilities.com.",
"idahofalls.remotepc.com.",
"idchicago1.remotepc.com.",
"iddallas1.remotepc.com.",
"iddenver.remotepc.com.",
"iddetroit.remotepc.com.",
+ "identity.bitwarden.com.",
"identity.myisolved.com.",
"idexonline-my.sharepoint.com.",
"idhw-my.sharepoint.com.",
@@ -2043,131 +2144,132 @@ var FakeECSFQDNs = container.NewMapSet(
"idlondon.remotepc.com.",
"idmadrid.remotepc.com.",
"idnewyork1.remotepc.com.",
- "idpix.media6degrees.com.cdn.cloudflare.net.",
+ "idocdn.com.",
+ "idp.nature.com.",
+ "idqqimg.com.",
"idr.cdnwidget.com.",
"ids.cdnwidget.com.",
"iemiq.com.",
- "if-sg.magzine.oppomobile.com.",
"igame.gcloudcs.com.",
"ijoysoftconnect.com.",
"ilandcloud.com.",
"illinoisstateuniversity-my.sharepoint.com.",
- "illumina.okta.com.",
"ilmn-my.sharepoint.com.",
"ilmn.sharepoint.com.",
"ilog-sea-aliyun.alipayplus.com.",
+ "ima.mm.fcix.net.",
"image.myqcloud.com.",
"image.online.adp.com.",
- "images.babylist.com.",
"images.crazygames.com.",
+ "images.hellomagazine.com.",
"imagetrendelite.com.",
"imanageshare.com.",
"imap.earthlink.net.",
- "imeclient.openspeech.cn.",
- "img.poki.com.",
"img.vmmcdn.com.",
"img.yana.upday.com.",
"img9.target.com.",
+ "imgarena.com.",
"imghst-de.com.",
"imgix.ranker.com.",
- "imgproxy.leaflets.schwarz.",
"imgs.signifyd.com.",
- "imodules.com.",
"imoim.net.",
"imolive2.com.",
+ "imou-sg-ali-online-paas-iot-private-picture.oss-ap-southeast-1.aliyuncs.com.",
+ "imou-sg-ali-online-paas-private-cloud-picture.oss-ap-southeast-1.aliyuncs.com.",
"imou-sg3-ali-online-paas-private-picture.oss-ap-southeast-1.aliyuncs.com.",
"imoulife.com.",
"imp.datafyhq.com.",
+ "imp.impdelivery.xyz.",
"impactify.media.",
- "impactserving.com.",
"imptrk.siteplug.com.",
"in-api.asm.skype.com.",
+ "in-exmagazineunlock-proxy.vivoglobal.com.",
"in-prod.asyncgw.teams.microsoft.com.",
+ "in-vpushonrt-stsdk.vivoglobal.com.",
"in.gov.",
"in.visitors.live.",
+ "inc-collabrtc.officeapps.live.com.",
+ "inc-word-edit.officeapps.live.com.",
+ "incitecpivotlimited-my.sharepoint.com.",
+ "incitecpivotlimited.sharepoint.com.",
"indianapolis.remotepc.com.",
+ "indus.iad-01.braze.com.",
"inf.miui.com.",
- "info.directpay.irs.gov.",
"ingov-my.sharepoint.com.",
"ingov.sharepoint.com.",
- "inneraudioms.cc.easebar.com.",
"innity.com.",
"innity.net.",
- "ino.qq.com.",
"inoreader.com.",
- "ins-qw3q8ofk.ias.tencent-cloud.net.",
- "inscr-my.sharepoint.com.",
- "inscr.sharepoint.com.",
"insidemedia-my.sharepoint.com.",
"insidemedia.sharepoint.com.",
"inskinad.com.",
"inspidspad.com.",
+ "inspire.oktapreview.com.",
"inspirebrands-sync.quantummetric.com.",
"inspirebrands.quantummetric.com.",
"instantmessaging-pa-jms-ap.googleapis.com.",
"instantmessaging-pa-jms-eu.googleapis.com.",
"instantmessaging-pa-jms-preprod-us.googleapis.com.",
"instantmessaging-pa-jms-us.googleapis.com.",
- "instantmessaging-pa-us.googleapis.com.",
"int.dpool.sina.com.cn.",
"intel-my.sharepoint.com.",
"intel.sharepoint.com.",
- "internal-api.monzo.com.",
+ "interface9.music.163.com.",
+ "internal.engine.intl.mi.com.",
"internetdownloadmanager.com.",
"intl-im-conn.iq.com.",
- "iorad.com.",
"ios.crashsight.wetest.net.",
"iosack.tuisong.baidu.com.",
"iot.hillrom.com.",
"iowa.remotepc.com.",
"ip-api.com.",
- "ip-data-service-prod.ecosec.on.epicgames.com.",
"ip.acmeaom.com.",
- "ip0.zenno.services.",
"ipa-business-sg.ap-southeast-1.log.aliyuncs.com.",
"ipa-business.cn-hangzhou.log.aliyuncs.com.",
+ "ipfs.io.",
"ipinyou.com.",
+ "iprofiles.apple.com.",
"iprom.net.",
"ipv4.cadc.absolute.com.",
"ipv4.tracker.harry.lu.",
- "irltoolkit.mm.fcix.net.",
"ironmountain.cyberhaven.io.",
- "irvine.remotepc.com.",
- "irx-api.indeed.com.",
"iscorp.com.",
"isjike.com.",
+ "istatmenus.app.",
+ "it168.com.",
"itc.cn.",
"itch.io.",
"itch.zone.",
"itinfoalvarezandmarsal-my.sharepoint.com.",
"itinfoalvarezandmarsal.sharepoint.com.",
"itm.cloud.com.",
- "itoon.org.",
"itzmx.com.",
"ivalua.com.",
"ivview.com.",
+ "ivytechccofindiana-my.sharepoint.com.",
+ "ix-denver.mm.fcix.net.",
"izooto.com.",
"jabfm.org.",
- "jasonresponsemeasure.com.",
"jbhunt-my.sharepoint.com.",
"jbhunt.sharepoint.com.",
+ "jbpco-my.sharepoint.com.",
"jdcloud.com.",
"jeldweninc1-my.sharepoint.com.",
- "jetblue.asapp.com.",
+ "jeldweninc1.sharepoint.com.",
+ "jjkeller-my.sharepoint.com.",
"jnj-my.sharepoint.com.",
"johannesburg.remotepc.com.",
"johnmuirhealth-my.sharepoint.com.",
+ "johnmuirhealth.sharepoint.com.",
"johnsmanville365-my.sharepoint.com.",
- "joox.com.",
"jotfor.ms.",
- "joynetgame.com.",
"jp-prod.asyncgw.teams.microsoft.com.",
"jp.cinarra.com.",
"jp1.chat.si.riotgames.com.",
+ "jpc-collabrtc.officeapps.live.com.",
"jpost.com.",
"jpush.cn.",
"jpush.io.",
- "jqjsgs.com.",
"js-eu1.hs-analytics.net.",
"js-eu1.hs-banner.com.",
"js-eu1.hs-scripts.com.",
@@ -2176,46 +2278,52 @@ var FakeECSFQDNs = container.NewMapSet(
"js-eu1.hsforms.net.",
"js-eu1.hsleadflows.net.",
"js-eu1.hubspot.com.",
- "js-eu1.hubspotfeedback.com.",
"js.eruptr.io.",
"jss.starbucks.com.",
"jssprod-starbucks.trafficmanager.net.",
"junglefrog.com.",
"justice.gov.",
- "k.163.com.",
- "k8s1-event-tracker-la.indexexchange.com.",
- "k8s1-event-tracker-ny.indexexchange.com.",
- "k8s1-event-tracker-sj.indexexchange.com.",
- "k8s1-event-tracker-va.indexexchange.com.",
- "k8s1-la-ext-lb.indexexchange.com.",
- "k8s1-ny-ext-lb.indexexchange.com.",
- "k8s1-va-ext-lb.indexexchange.com.",
+ "k8s1-event-tracker-la.lb.indexww.com.",
+ "k8s1-event-tracker-ny.lb.indexww.com.",
+ "k8s1-event-tracker-sj.lb.indexww.com.",
+ "k8s1-event-tracker-va.lb.indexww.com.",
+ "k8s1-la-ext-haproxy.lb.indexww.com.",
+ "k8s1-ny-ext-haproxy.lb.indexww.com.",
+ "k8s1-va-ext-haproxy.lb.indexww.com.",
"kajicam.com.",
+ "kameleoon.com.",
"kc1-my.sharepoint.com.",
+ "kc1.sharepoint.com.",
+ "keells-my.sharepoint.com.",
+ "keells.sharepoint.com.",
"khsd-my.sharepoint.com.",
+ "khsd.sharepoint.com.",
"kiev.remotepc.com.",
"kiprotect.com.",
- "kisd365-my.sharepoint.com.",
"kiwisizing.com.",
"klagenfurt.remotepc.com.",
+ "kms8.msguides.com.",
"knightlab.com.",
"knock.app.",
"knoxville.remotepc.com.",
"komect.com.",
+ "komiku.id.",
"kootenaihealth-my.sharepoint.com.",
"kornferry-my.sharepoint.com.",
"kornferry.sharepoint.com.",
"kstatic.googleusercontent.com.",
+ "kumed-my.sharepoint.com.",
"kumed.sharepoint.com.",
"kunlunaq.com.",
"kunlunar.com.",
- "kunlunca.com.",
"kunluncan.com.",
"kunlungr.com.",
"kunlunhuf.com.",
- "kunlunno.com.",
"kunlunsl.com.",
"kunlunso.com.",
+ "kurogame.com.",
+ "kurogame.xyz.",
+ "kv801.prod.do.dsp.mp.microsoft.com.",
"kwimgs.com.",
"kzhi.tech.",
"la.remotepc.com.",
@@ -2228,24 +2336,32 @@ var FakeECSFQDNs = container.NewMapSet(
"la4.remotepc.com.",
"la8.remotepc.com.",
"la9.remotepc.com.",
+ "labcorp-holdings.okta.com.",
"labtech.corcystems.com.",
+ "labtech.iwsit.com.",
+ "labtech.myitpros.com.",
+ "lacledegas-my.sharepoint.com.",
"lacounty-my.sharepoint.com.",
"lacounty.sharepoint.com.",
"lahuashanbx.com.",
+ "laitramllc-my.sharepoint.com.",
+ "lakecountyil-my.sharepoint.com.",
"lan.sdk.linkedin.com.",
"lansing.remotepc.com.",
"lansweeper.com.",
- "laohu.com.",
"laptop-updates.brave.com.",
"larksuite.com.",
+ "lasd-my.sharepoint.com.",
"lasd.sharepoint.com.",
+ "last.fm.",
"lastwar-va.us-east-1.log.aliyuncs.com.",
+ "latamairlines.com.",
"laureatelatammx-my.sharepoint.com.",
"laureatelatammx.sharepoint.com.",
"lax.remotepc.com.",
"layerxsecurity.com.",
- "lazada-mobile.oss-ap-southeast-1.aliyuncs.com.",
"lazada-msgacs.m.taobao.com.",
+ "lazada-wallet.oss-ap-southeast-1.aliyuncs.com.",
"lazada.co.id.",
"lazada.co.th.",
"lazada.com.",
@@ -2253,12 +2369,15 @@ var FakeECSFQDNs = container.NewMapSet(
"lazada.com.ph.",
"lazada.sg.",
"lazada.vn.",
+ "lcdn-registration.apple.com.",
"lcecorp-my.sharepoint.com.",
"lcmchealth-my.sharepoint.com.",
+ "lcmchealth.sharepoint.com.",
"ldap.google.com.",
"ldcorp.sharepoint.com.",
"leadmanagerfx.com.",
- "leagueoflegends.com.",
+ "learningtools.onenote.com.",
+ "leggettplatt-my.sharepoint.com.",
"leiniao.com.",
"lenovomm.com.",
"levect.com.",
@@ -2266,16 +2385,16 @@ var FakeECSFQDNs = container.NewMapSet(
"leveldata.poki.io.",
"leviton-my.sharepoint.com.",
"lexicon.33across.com.",
- "lexrich5.powerschool.com.",
"lianmeng.360.cn.",
"libertyuniv-my.sharepoint.com.",
"libertyuniv.sharepoint.com.",
- "liblynx.com.",
"license.gonative.io.",
"license.litespeedtech.com.",
"license.unity3d.com.",
"licensing.bitmovin.com.",
+ "licensing.sbullet.com.",
"lichess.org.",
+ "lidl.com.",
"lightwidget.com.",
"likr.tw.",
"lima.remotepc.com.",
@@ -2283,45 +2402,48 @@ var FakeECSFQDNs = container.NewMapSet(
"lincare.sharepoint.com.",
"lineicons.com.",
"link-vision-picture-sgp.oss-ap-southeast-1.aliyuncs.com.",
- "link.gale.com.",
+ "link.law.com.",
+ "link.storjshare.io.",
+ "lisbon.remotepc.com.",
"lissabon.remotepc.com.",
"list.tronlink.org.",
"lists-e.tm-rt.sharepoint.com.",
+ "lists.theepochtimes.com.",
+ "litedev.sgp.ezvizlife.com.",
"litedev.sgp.hik-connect.com.",
"litedev.us.hik-connect.com.",
"litespeedtech.com.",
+ "littlecaesars.com.",
"littler-my.sharepoint.com.",
"live.126.net.",
"live.ngb.haplat.net.",
+ "live.qcloud.com.",
+ "live2support.com.",
"live3.ngb.haplat.net.",
"live5.ngb.haplat.net.",
+ "livechatenterprise.com.",
"livect.haplat.net.",
- "livedmpsk12ia-my.sharepoint.com.",
- "livedmpsk12ia.sharepoint.com.",
- "livekilleenisd.sharepoint.com.",
+ "liverpool.groupbycloud.com.",
"liveutmb-my.sharepoint.com.",
"liveutmb.sharepoint.com.",
"ljubljana.remotepc.com.",
- "llbean.com.",
+ "loandepot.zoom.us.",
"local.adguard.org.",
"local.info.g9hc4.cn.",
+ "loewshotels-my.sharepoint.com.",
"log-api.newrelic.com.cdn.cloudflare.net.",
"log-yex.youdao.com.",
"log.getadblock.com.",
- "log.lscreenc.com.",
+ "log.webmaxlogger.net.",
"log.zoom.us.",
"log1.cmpassport.com.",
+ "log2.cmpassport.com.",
"logger.moviead55.ru.",
"logging-service-prod.getepic.com.",
"logging.mp.lura.live.",
- "login.sproutabout.com.",
"login.teamviewer.com.",
- "login.wolterskluwer.com.",
- "loginradius.com.",
- "logs.getadblock.com.",
+ "login.zoominfo.com.",
"logs2.sportslocalmedia.com.",
- "logu.hpplay.cn.",
- "logx.optimizely.com.",
"london.remotepc.com.",
"london2.remotepc.com.",
"london3.remotepc.com.",
@@ -2329,32 +2451,38 @@ var FakeECSFQDNs = container.NewMapSet(
"london5.remotepc.com.",
"london6.remotepc.com.",
"london8.remotepc.com.",
+ "long.tv.",
"look.360.cn.",
"loopme.me.",
- "lpd.lww.com.",
"lplcorp1-my.sharepoint.com.",
+ "lplcorp1.sharepoint.com.",
+ "lplfinancial.app.box.com.",
"lptag-cdn.liveperson.net.",
"lsagentrelay.lansweeper.com.",
- "lscreenc.com.",
+ "lt.britecity.com.",
"ltfinc-my.sharepoint.com.",
"ltfinc.sharepoint.com.",
"ltfl.librarything.com.",
"ltpnetwork-my.sharepoint.com.",
+ "luckyorange.com.",
"ludashi.com.",
- "lufthansa-app.quantummetric.com.",
"lunamedia.live.",
"luxembourg.remotepc.com.",
+ "lwbnlive.accounts.ondemand.com.",
"lycraservice-pa-cam-prod.googleapis.com.",
"lyric.alarmnet.com.",
- "lzd-img-global.slatic.net.",
- "m.bbb.org.",
- "m.gds.taobao.com.",
+ "m.betlive.com.",
"m.umeng.com.",
- "m104216-ucdn.mp.lura.live.",
- "m107833-mcdn.mp.lura.live.",
- "m109771-ecdn.mp.lura.live.",
+ "m1.ubianet.com.",
+ "m110601-fcdn.mp.lura.live.",
+ "m2.ubianet.com.",
+ "m3.ubianet.com.",
+ "m333ku.lol.",
+ "m4.ubianet.com.",
+ "m5.ubianet.com.",
+ "m6.ubianet.com.",
"macclog-as.rj.link.",
- "madisonschools-my.sharepoint.com.",
+ "macdata.itsupport247.net.",
"madrid.remotepc.com.",
"maers.adrs.org.cn.",
"magichue.net.",
@@ -2362,18 +2490,26 @@ var FakeECSFQDNs = container.NewMapSet(
"mail.superhuman.com.",
"mailinblue.com.",
"mailmissouri-my.sharepoint.com.",
+ "mailmissouri.sharepoint.com.",
"mainadv.com.",
"maintenanceconnection.com.",
"majorel365-my.sharepoint.com.",
"malware-filter.gitlab.io.",
+ "mam.manage.microsoft.us.",
"manage-selfhost.microsoft.com.",
"manage.wix.com.",
+ "management.azure.com.",
+ "management.privatelink.azure.com.",
"manassas.remotepc.com.",
"manchester.remotepc.com.",
"manifest.prod.boltdns.net.",
+ "markelcorp-my.sharepoint.com.",
+ "market-global.smrtb.com.",
+ "marketing.beneplace.com.",
"marmot-cloud.com.",
"marseille.remotepc.com.",
"masonitecloud-my.sharepoint.com.",
+ "masonitecloud.sharepoint.com.",
"master1.teamviewer.com.",
"master10.teamviewer.com.",
"master11.teamviewer.com.",
@@ -2391,19 +2527,21 @@ var FakeECSFQDNs = container.NewMapSet(
"master8.teamviewer.com.",
"master9.teamviewer.com.",
"masuk.store.",
+ "matetranslate.com.",
"mathematica-my.sharepoint.com.",
+ "mativglobal-my.sharepoint.com.",
"mattressfirm-my.sharepoint.com.",
"mattressfirm.sharepoint.com.",
"max-l.mediav.com.",
"mbboauth-1c.prd.cn.vwg-connect.cn.",
"mcallen.remotepc.com.",
+ "mcdermottinc-my.sharepoint.com.",
"mcdermottinc.sharepoint.com.",
"mcdermottwillemery-my.sharepoint.com.",
"mcdermottwillemery.sharepoint.com.",
- "mcdn.podbean.com.",
- "mcleodhosted.com.",
+ "mclarenhealth-my.sharepoint.com.",
+ "mclarenhealth.sharepoint.com.",
"mdap.tngdigital.com.my.",
- "mdedge.com.",
"mdp-upgrade-cn.heytapmobi.com.",
"mdvdns.com.",
"meari-oss-us.oss-us-west-1.aliyuncs.com.",
@@ -2434,8 +2572,10 @@ var FakeECSFQDNs = container.NewMapSet(
"media-fra5-1.cdn.whatsapp.net.",
"media-fra5-2.cdn.whatsapp.net.",
"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.",
"media-gru2-2.cdn.whatsapp.net.",
"media-gua1-1.cdn.whatsapp.net.",
"media-ham3-1.cdn.whatsapp.net.",
@@ -2487,42 +2627,43 @@ var FakeECSFQDNs = container.NewMapSet(
"media-sjc3-1.cdn.whatsapp.net.",
"media-sof1-1.cdn.whatsapp.net.",
"media-sof1-2.cdn.whatsapp.net.",
- "media-waw2-1.cdn.whatsapp.net.",
- "media-waw2-2.cdn.whatsapp.net.",
+ "media-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-xxc1-1.cdn.whatsapp.net.",
- "media.blooket.com.multicdn.cloudinary.com.",
+ "media-yyz1-1.cdn.whatsapp.net.",
+ "media.blooket.com.",
"media.crocs.com.",
- "media.formula1.com.",
"media.graphassets.com.",
"media.ringcentral.com.",
"media.superhuman.com.",
- "mediadelivery.net.",
"mediav.com.",
- "medium.com.",
"medline0-my.sharepoint.com.",
+ "medline0.sharepoint.com.",
"melbourne.remotepc.com.",
"memphis.remotepc.com.",
- "metrics-dre.dt.dbankcloud.cn.",
- "metrics-dre.dt.dbankcloud.com.",
+ "menangtoto.net.",
+ "metric.picodi.global.",
+ "metrics-dre.dt.hihonorcloud.com.",
+ "metrics.dt.dbankcloud.cn.",
+ "metrics2.data.hicloud.com.",
"metrics5.data.hicloud.com.",
"mexicocity.remotepc.com.",
"mf.b37mrtl.ru.",
"mgtv.com.",
+ "mhaciendacr-my.sharepoint.com.",
"miami.remotepc.com.",
"miami2.remotepc.com.",
"miami3.remotepc.com.",
"miami4.remotepc.com.",
- "mib2clu8.car-cloud-cn.net.",
+ "miamidadecollegeprod-my.sharepoint.com.",
"microad.jp.",
"microchiptechnology-my.sharepoint.com.",
"microchiptechnology.sharepoint.com.",
- "microsoft-my.sharepoint.com.",
"microvirt.com.",
"mid4.linkedin.com.",
+ "mightytext.co.",
"milan.remotepc.com.",
"milestoneinternet.com.cdn.cloudflare.net.",
"milwaukeetool-my.sharepoint.com.",
@@ -2530,76 +2671,94 @@ var FakeECSFQDNs = container.NewMapSet(
"milwaukeetool.sharepoint.com.",
"mimir2.vivaldi.com.",
"min-api.cryptocompare.com.",
- "mini.browser.360.cn.",
"mintkeyboard.com.",
+ "mirror-mci.yuki.net.uk.",
+ "mirror.0xem.ma.",
"mirror.centos.iad1.serverforge.org.",
+ "mirror.dal.nexril.net.",
"mirror.fcix.net.",
+ "mirror.fmt-2.serverforge.org.",
"mirror.lstn.net.",
+ "mirror.mci-1.serverforge.org.",
+ "mirror.pilotfiber.com.",
+ "mirror.pit.teraswitch.com.",
+ "mirror.steadfastnet.com.",
+ "mirror.xenyth.net.",
"mirrors.rockylinux.org.",
"mitek-my.sharepoint.com.",
"mixi.media.",
"mizuhogroup-my.sharepoint.com.",
"mm-mm.bing.net.trafficmanager.net.",
- "mm.zhangchu.net.",
+ "mmods.site.",
"mms.mckesson.com.",
+ "mn31.ultipro.com.",
"mn365-my.sharepoint.com.",
"mn365.sharepoint.com.",
+ "mna.arenabreakout.com.",
"mno.lgaiwmc1d.com.",
+ "mnvoip.mm.fcix.net.",
+ "mobile-api.teamsnap.com.",
"mobile-bank.cdn-tinkoff.ru.",
"mobile-collector.newrelic.com.cdn.cloudflare.net.",
+ "mobile-protect-api.securetheorem.com.",
"mobile.bereal.com.",
"mobile.shuzilm.cn.",
- "mobile.useinsider.com.",
"mobiledataplan-pa.googleapis.com.",
- "mobilelog.upqzfile.com.",
"mobilemaps-pa-gz.googleapis.com.",
"mobilemaps.googleapis.com.",
+ "mobilesecuritycore-cdn.norton.com.",
+ "mobydix.com.",
"modelportrait.xiaohongshu.com.",
"modesto.remotepc.com.",
"molor-app-logs-default.ap-southeast-1.log.aliyuncs.com.",
"moni-onrt-stsdk.vivo.com.cn.",
- "monitor.fraudblocker.com.",
"monitoring.getelevar.com.",
"monitoring.worksighted.com.",
"monsterenergycorp-my.sharepoint.com.",
- "montage-updates.displaynote.com.",
+ "monsterenergycorp.sharepoint.com.",
"monticello.remotepc.com.",
"montreal.remotepc.com.",
+ "morningamidamaruhal.com.",
"motiondetection-us-1d.oss-us-west-1.aliyuncs.com.",
+ "motiondetection-us-7d.oss-us-west-1.aliyuncs.com.",
"motiondetection-us.oss-us-west-1.aliyuncs.com.",
- "mottandbow.com.",
"mouser.com.",
"moviead55.ru.",
"mp.360.cn.",
- "mp.midasbuy.com.",
- "mp.theepochtimes.com.",
"mpsaz-my.sharepoint.com.",
- "mpsaz.sharepoint.com.",
"mpush-api.aliyun.com.",
"mrisoftware.com.",
- "mrodevicemgr.officeapps.live.com.",
"ms1app.pb.com.",
"msch.f.360.cn.",
"msdl.microsoft.com.",
"msf.3g.qq.com.",
"msg-img-hk.oss-cn-hongkong.aliyuncs.com.",
- "msg-intl.qy.net.",
"mstate-my.sharepoint.com.",
"msync-im1-sgp-ga.easemob.com.",
- "mtb-app.quantummetric.com.",
+ "mtncloud-my.sharepoint.com.",
"mtrace.qq.com.",
+ "mtrics.akam.cdc.gov.",
"mu.ariba.com.",
"mumbai.remotepc.com.",
"mumu.nie.netease.com.",
"munich.remotepc.com.",
"muscache.cn.",
- "musicps.p2p.qq.com.",
+ "musical.ly.",
"musicpunch.p2p.qq.com.",
+ "musicstylingonline.com.",
"mvconf.f.360.cn.",
"mvconf.uk.cloud.360safe.com.",
- "mvm.snapchat.com.",
+ "mvision-us.moodmedia.com.",
+ "mx-mex-anx-r001.router.teamviewer.com.",
+ "mx-mex-anx-r002.router.teamviewer.com.",
+ "mx-mex-anx-r004.router.teamviewer.com.",
+ "mx-mex-anx-r006.router.teamviewer.com.",
+ "mx-mex-anx-r007.router.teamviewer.com.",
"mx-vcode-od.vivoglobal.com.",
"mx.amx.rcs.telephony.goog.",
+ "mx1.mailhostbox.com.",
+ "mx2.mailhostbox.com.",
+ "mx3.mailhostbox.com.",
"mxp-pusa01.app.blackbaud.net.",
"mxptint.net.",
"my.dealersocket.com.",
@@ -2607,28 +2766,32 @@ var FakeECSFQDNs = container.NewMapSet(
"my.jbi.global.",
"my.microsoftpersonalcontent.com.",
"my.nalpeiron.com.",
+ "myccmortgage-my.sharepoint.com.",
+ "myccmortgage.sharepoint.com.",
+ "mydigitalspace-my.sharepoint.com.",
"mydigitalspace.sharepoint.com.",
"mydrive.connect.aig.",
- "myidb2b.cardinalhealth.com.",
"myisolved.com.",
- "mylonestar-my.sharepoint.com.",
"myou.cvte.com.",
+ "myporn.club.",
"myqcloud.com.",
"mystery-game-tile.poki.io.",
"myvscloud.com.",
- "myweblogon.com.",
- "mywebsitebuilder.com.",
+ "mywallet.ads.brave.com.",
"myworkdaycdn.com.cn.",
- "n.gameads.io.",
+ "n-0-ny5x.ad-m.net.",
+ "n-able.com.cdn.cloudflare.net.",
"n13.ultipro.com.",
"n21.ultipro.com.",
"n21c.ultipro.com.",
"n22.ultipro.com.",
"n32.ultipro.com.",
"n33.ultipro.com.",
- "n34.ultipro.com.",
"n35.ultipro.com.",
+ "na119.epm.cyberark.com.",
+ "na159.epm.cyberark.com.",
"na2.chat.si.riotgames.com.",
+ "nab.com.au.",
"najva.com.",
"namequery.com.",
"naperville.remotepc.com.",
@@ -2636,14 +2799,18 @@ var FakeECSFQDNs = container.NewMapSet(
"nationalheritageacademies-my.sharepoint.com.",
"nationalmap.gov.",
"nationalreview.com.",
- "nationworldnews.com.",
"nativecos.com.",
+ "nawzryhwatm.broker.amsoveasea.com.",
+ "nba1-my.sharepoint.com.",
+ "nc-centos-mirror.iwebfusion.net.",
"nc.com.",
"ncentral.centrexit.com.",
"ncjb-my.sharepoint.com.",
"nearme.com.cn.",
"nechicago.remotepc.com.",
"neonataltherapists.com.",
+ "nephobox.com.",
+ "net-a-porter.com.",
"net.multicdn.cloudinary.com.",
"netapp-my.sharepoint.com.",
"netapp.sharepoint.com.",
@@ -2652,11 +2819,8 @@ var FakeECSFQDNs = container.NewMapSet(
"netpop.app.",
"netpresenter.com.",
"netsolssl.com.",
- "new.adblockplus.org.",
"newcontinuum.net.",
- "newoldstamp.com.",
"neworleans.remotepc.com.",
- "newrepublic.com.",
"news-abroad.vivo.com.",
"news-af.feednews.com.",
"news-client.apple.com.",
@@ -2664,6 +2828,7 @@ var FakeECSFQDNs = container.NewMapSet(
"news-global.cloud.",
"news-nar-aud.apple.com.",
"news-sports-events.apple.com.",
+ "news.apple.com.",
"newsletter-edge.apple.com.",
"newsroom.bi.",
"newyork.remotepc.com.",
@@ -2671,33 +2836,40 @@ var FakeECSFQDNs = container.NewMapSet(
"newyork3.remotepc.com.",
"nex.163.com.",
"nexpart.com.",
+ "nexril.net.",
"nexstar.amp.permutive.com.",
- "nexus2wlb.com.",
"nexx360.io.",
"nfm365-my.sharepoint.com.",
"nfm365.sharepoint.com.",
+ "nfpa.org.",
"ng1.angus.mrisoftware.com.",
"ngb.haplat.net.",
- "nhshumanservices423-my.sharepoint.com.",
+ "nhhospitals-my.sharepoint.com.",
+ "nhwimp.izooto.com.",
"nice-team.net.",
"nie.netease.com.",
"nieuwsblad.be.",
"nike.com.multicdn.cloudinary.com.",
"nio365-my.sharepoint.com.",
+ "nio365.sharepoint.com.",
+ "nist.gov.",
"nitropay.com.",
- "nkcsd-my.sharepoint.com.",
+ "nlb-r6nqdxb14905anz29t.eu-central-1.nlb.aliyuncs.com.",
+ "nlog.naver.com.",
"nmhealth-my.sharepoint.com.",
"nmhealth.sharepoint.com.",
+ "nnenix.mm.fcix.net.",
"noc.computerhelpnj.com.",
+ "nocix.mm.fcix.net.",
"node.setupad.com.",
"nordcurrent.com.",
"norma-external-collect.meizu.com.",
"northcentralus-gas.guestconfiguration.azure.com.",
"notes-analytics-events.apple.com.",
"notes.services.box.com.",
+ "notification.trk-sodales.com.",
"notifications.bitwarden.com.",
"novaicare.com.",
- "novel.itoon.org.",
"nps.gov.",
"ns-cloud-a1.googledomains.com.",
"ns-cloud-a2.googledomains.com.",
@@ -2723,15 +2895,15 @@ var FakeECSFQDNs = container.NewMapSet(
"ns.identrust.com.",
"ns0105.secondary.cloudflare.com.",
"ns0160.secondary.cloudflare.com.",
- "ns1.a0.impervasecuredns.net.",
"ns1.cloudflare.net.",
- "ns1.digitalocean.com.",
"ns1.g.aaplimg.com.",
"ns1.google.com.",
"ns1.identrust.com.",
+ "ns1.maxihost.com.br.",
"ns2.cloudflare.net.",
"ns2.g.aaplimg.com.",
"ns2.google.com.",
+ "ns2.maxihost.com.br.",
"ns3.24shells.net.",
"ns3.cloudflare.net.",
"ns3.g.aaplimg.com.",
@@ -2741,9 +2913,9 @@ var FakeECSFQDNs = container.NewMapSet(
"ns4.g.aaplimg.com.",
"ns4.google.com.",
"ns5.cloudflare.net.",
+ "ns59.worldnic.com.",
"nsa.nalpeiron.com.",
"nsatc.net.",
- "nsl.lenovo.com.cn.",
"ntes53.netease.com.",
"ntp.aliyun.com.",
"ntp.arlo.com.",
@@ -2756,48 +2928,44 @@ var FakeECSFQDNs = container.NewMapSet(
"ntp5.aliyun.com.",
"nttlimited-my.sharepoint.com.",
"nttlimited.sharepoint.com.",
+ "ntypm1-inapps.appsflyersdk.com.",
+ "nullroute.mm.fcix.net.",
+ "nuremberg.remotepc.com.",
"nvu-prd.mqtt.ivanticloud.com.",
"nw14.ultipro.com.",
"nw16.ultipro.com.",
+ "nwas.jpmorgan.com.",
"nwr.mmcdn.com.",
"nwr.static.mmcdn.com.",
"nwsalert.onelouder.com.",
"nysif-my.sharepoint.com.",
"o1.d.meituan.net.",
- "o300810.mp.lura.live.",
- "oauth-analytics.ascendlearning.com.",
"obe0-my.sharepoint.com.",
"obihai.telephony.goog.",
"obs.ap-southeast-3.myhuaweicloud.com.",
"obsproject.com.",
"obus-dc20058-cn.heytapmobi.com.",
"obus-dc20123-cn.heytapmobi.com.",
- "obus-dc20157-cn.heytapmobi.com.",
"obus-dctech-cn.heytapmobi.com.",
+ "obus-rudc-sg.heytapmobile.com.",
"oc1.chat.si.riotgames.com.",
- "oc2vjq-cdn-settings.appsflyersdk.com.",
"oclc.org.",
"ocloud.oppomobile.com.",
"ocps-xfer.kronos.net.",
- "ocsen-slb.com.",
"ocsp.identrust.com.",
- "ocsp.wosign.com.",
"ocsredir.officeapps.live.com.",
- "odc.osi.office365.us.",
+ "ocwen365-my.sharepoint.com.",
"odw7bf.dood.video.",
"oec22-normal-alisg.tokopediax.com.",
"oec22-normal-useast1a.tokopediax.com.",
"office.microsoft.com.",
"office365lds-my.sharepoint.com.",
"office365lds.sharepoint.com.",
+ "officepreviewredir.microsoft.com.",
+ "officeredir.microsoft.com.",
"ogma.bereal.com.",
- "ok12-custom-crtrs.okta.com.",
- "ok14-custom-crtrs.okta.com.",
- "ok7-crtrs.tng.okta.com.",
- "ok7-custom-crtrs.okta.com.",
+ "ohioix.mm.fcix.net.",
"okko.tv.",
- "olatheschoolsorg-my.sharepoint.com.",
- "olatheschoolsorg.sharepoint.com.",
"ollama.com.",
"omats-my.sharepoint.com.",
"omats.sharepoint.com.",
@@ -2805,7 +2973,7 @@ var FakeECSFQDNs = container.NewMapSet(
"omitech.site.",
"omnihotels-my.sharepoint.com.",
"on-hwapps-o.api.leiniao.com.",
- "onecms-res.cloudinary.com.",
+ "one-line.com.",
"onedrive.live.com.",
"oneharman-my.sharepoint.com.",
"oneharman.sharepoint.com.",
@@ -2813,19 +2981,23 @@ var FakeECSFQDNs = container.NewMapSet(
"oneplus.net.",
"onethingpcs.com.",
"onezapp.com.",
+ "online.kugou.com.",
+ "online.liebertpub.com.",
"onlinewebfonts.com.",
"op.mykonf.com.",
"opamarketplace.com.",
- "open.acgnxtracker.com.",
"open.acgtracker.com.",
"open.demonii.com.",
+ "open.live.bbc.co.uk.",
+ "open.live.bbc.co.uk.pri.bbc.co.uk.",
"open.oppomobile.com.",
+ "openapi.etsy.com.",
+ "openbox.mobilem.360.cn.",
"opencmp.net.",
"opencolo.mm.fcix.net.",
"opendsp.ru.",
"openlane.cyberhaven.io.",
"openrice.com.",
- "openwebmedia.com.",
"opex-service-cn.allawntech.com.",
"oppo.com.",
"oppomobile.com.",
@@ -2833,11 +3005,17 @@ var FakeECSFQDNs = container.NewMapSet(
"optimize.urekamedia.com.",
"optimizely.com.",
"optioncare-my.sharepoint.com.",
- "or-mirror.iwebfusion.net.",
- "orangeusdorg-my.sharepoint.com.",
+ "optioncare.sharepoint.com.",
"oregon.remotepc.com.",
+ "orga.openrice.com.",
+ "origin-tier2.steampipe.steamcontent.com.",
"origin.fe-image-cache-ttp.useast8.byteglb.com.",
"orlando.remotepc.com.",
+ "orthoclinical.sharepoint.com.",
+ "orthowalkway.com.",
+ "os7lm.6kvses.com.",
+ "osaic-my.sharepoint.com.",
+ "osaic.sharepoint.com.",
"osaka.remotepc.com.",
"oss-ap-southeast-1.aliyuncs.com.",
"oss-ap-southeast-5.aliyuncs.com.",
@@ -2850,10 +3028,10 @@ var FakeECSFQDNs = container.NewMapSet(
"oss-eu-central-1.aliyuncs.com.",
"oss-us-east-1.aliyuncs.com.",
"oss-us-west-1.aliyuncs.com.",
- "ota.lenovo.com.",
"otc.t-systems.com.",
+ "otnolatrnup.com.",
"ott.deepl.com.",
- "oval.id.",
+ "oursummit-my.sharepoint.com.",
"overleaf.com.",
"overleafusercontent.com.",
"oversea-master-log.ap-southeast-1.log.aliyuncs.com.",
@@ -2865,7 +3043,7 @@ var FakeECSFQDNs = container.NewMapSet(
"overseasccl-major-c.haplat.net.",
"ovh.maxhost.io.",
"oxyinc-my.sharepoint.com.",
- "p-wonderidea-rdr.us-east-1.log.aliyuncs.com.",
+ "oy24bn-inapps.appsflyersdk.com.",
"p.adlooxtracking.com.",
"p.placed.com.",
"p.vivo.com.cn.",
@@ -2875,21 +3053,19 @@ var FakeECSFQDNs = container.NewMapSet(
"p107611.cedexis-test.com.",
"p109477.cedexis-test.com.",
"p109522.cedexis-test.com.",
+ "p11-buy.itunes.apple.com.",
"p14-buy.itunes.apple.com.",
- "p17-buy.itunes.apple.com.",
- "p17000.cedexis-test.com.",
"p20304.cedexis-test.com.",
"p20305.cedexis-test.com.",
"p20306.cedexis-test.com.",
"p20307b.cedexis-test.com.",
"p20308b.cedexis-test.com.",
- "p20309.cedexis-test.com.",
"p20310.cedexis-test.com.",
"p20311.cedexis-test.com.",
"p20314.cedexis-test.com.",
"p20315.cedexis-test.com.",
- "p25-buy.itunes.apple.com.",
- "p27-buy.itunes.apple.com.",
+ "p24-buy.itunes.apple.com.",
+ "p2cdn.com.",
"p2p-cal-2.anker-in.com.",
"p2p-cal.anker-in.com.",
"p2p-ohi-2.anker-in.com.",
@@ -2901,52 +3077,30 @@ var FakeECSFQDNs = container.NewMapSet(
"p2p3.cloudbirds.cn.",
"p2pm-ali.reolink.com.",
"p2psy2.io.mi.com.",
+ "p30-buy.itunes.apple.com.",
"p30605.cedexis-test.com.",
- "p31-buy.itunes.apple.com.",
+ "p32-buy.itunes.apple.com.",
"p33231.cedexis-test.com.",
- "p33232.cedexis-test.com.",
- "p33233.cedexis-test.com.",
- "p33234.cedexis-test.com.",
- "p33235.cedexis-test.com.",
"p33236.cedexis-test.com.",
- "p33237.cedexis-test.com.",
- "p33238.cedexis-test.com.",
- "p33239.cedexis-test.com.",
- "p33240.cedexis-test.com.",
- "p33241.cedexis-test.com.",
- "p33242.cedexis-test.com.",
- "p33243.cedexis-test.com.",
- "p33244.cedexis-test.com.",
"p33245.cedexis-test.com.",
- "p33246.cedexis-test.com.",
- "p33247.cedexis-test.com.",
- "p33248.cedexis-test.com.",
"p33249.cedexis-test.com.",
"p33250.cedexis-test.com.",
"p33251.cedexis-test.com.",
- "p33252.cedexis-test.com.",
- "p33253.cedexis-test.com.",
"p33254.cedexis-test.com.",
"p33255.cedexis-test.com.",
"p33256.cedexis-test.com.",
- "p33257.cedexis-test.com.",
- "p33258.cedexis-test.com.",
"p33259.cedexis-test.com.",
- "p33260.cedexis-test.com.",
"p34854.cedexis-test.com.",
- "p34855.cedexis-test.com.",
"p34856.cedexis-test.com.",
- "p34857.cedexis-test.com.",
"p34858.cedexis-test.com.",
- "p34859.cedexis-test.com.",
- "p34860.cedexis-test.com.",
- "p35-buy.itunes.apple.com.",
+ "p35.gslb.bitgravity.com.",
"p35883.cedexis-test.com.",
- "p36-mailws.icloud.com.",
+ "p38-mailws.icloud.com.",
+ "p38635.cedexis-test.com.",
+ "p39266.cedexis-test.com.",
"p39604.cedexis-test.com.",
"p3a-creative.brave.com.",
"p3a-json.brave.com.",
- "p40-buy.itunes.apple.com.",
"p40255.cedexis-test.com.",
"p40256.cedexis-test.com.",
"p40259.cedexis-test.com.",
@@ -2958,7 +3112,6 @@ var FakeECSFQDNs = container.NewMapSet(
"p40488.cedexis-test.com.",
"p40491.cedexis-test.com.",
"p40952.cedexis-test.com.",
- "p41-buy.itunes.apple.com.",
"p41237.cedexis-test.com.",
"p41238.cedexis-test.com.",
"p41259.cedexis-test.com.",
@@ -2970,28 +3123,38 @@ var FakeECSFQDNs = container.NewMapSet(
"p42051.cedexis-test.com.",
"p42052.cedexis-test.com.",
"p42053.cedexis-test.com.",
+ "p43-buy.itunes.apple.com.",
"p43671.cedexis-test.com.",
"p43707.cedexis-test.com.",
"p43773.cedexis-test.com.",
"p43774.cedexis-test.com.",
"p43775.cedexis-test.com.",
"p43776.cedexis-test.com.",
+ "p44-buy.itunes.apple.com.",
+ "p48-buy.itunes.apple.com.",
"p48434.cedexis-test.com.",
"p48435.cedexis-test.com.",
"p48436.cedexis-test.com.",
- "p49-buy.itunes.apple.com.",
"p4p.arenabg.com.",
- "p51-buy.itunes.apple.com.",
+ "p5.d.meituan.net.",
+ "p52-buy.itunes.apple.com.",
+ "p52-mailws.icloud.com.",
"p52066.cedexis-test.com.",
- "p53-buy.itunes.apple.com.",
"p56745.cedexis-test.com.",
"p56746.cedexis-test.com.",
"p56747.cedexis-test.com.",
+ "p57-buy.itunes.apple.com.",
+ "p58-mailws.icloud.com.",
+ "p6.d.meituan.net.",
+ "p60-buy.itunes.apple.com.",
+ "p66-mailws.icloud.com.",
+ "p7-buy.itunes.apple.com.",
+ "p73-buy.itunes.apple.com.",
"p76593.cedexis-test.com.",
- "p8-buy.itunes.apple.com.",
"p86072.cedexis-test.com.",
"p86075.cedexis-test.com.",
"p86077.cedexis-test.com.",
+ "p9-buy.itunes.apple.com.",
"p92860.cedexis-test.com.",
"p92861.cedexis-test.com.",
"p92862.cedexis-test.com.",
@@ -3007,40 +3170,49 @@ var FakeECSFQDNs = container.NewMapSet(
"p95726.cedexis-test.com.",
"p95727.cedexis-test.com.",
"p95728.cedexis-test.com.",
+ "p9qlcv-cdn-settings.appsflyersdk.com.",
"paccarnet.sharepoint.com.",
"paducahix.mm.fcix.net.",
+ "page.portals.mobi.",
"pai.googlezip.net.",
"palermo.remotepc.com.",
"palm.tech.",
"panorama.wixapps.net.",
"panthers-my.sharepoint.com.",
- "paramount.com.",
+ "paramountplus.com.",
"paris.remotepc.com.",
"parkhill1-my.sharepoint.com.",
- "partition.enterprise.com.",
"partnerboost.com.",
"partners-api.pinterest.com.",
"pasadena.remotepc.com.",
+ "pascocountyfl-my.sharepoint.com.",
"passportalmsp.com.",
"pay.datatrans.com.",
"paycorinc-my.sharepoint.com.",
"paylocity1-my.sharepoint.com.",
- "payment.api.speechify.com.",
- "payments.worldpay.com.",
+ "paylocity1.sharepoint.com.",
+ "payment.omiapp.me.",
+ "pbcdn1.podbean.com.",
+ "pbdlsp1.pb.com.",
"pbe1.chat.si.riotgames.com.",
- "pbs-us-east.ay.delivery.",
"pbs.btloader.com.",
"pbsj.bricks-co.com.",
"pc-store.lenovomm.cn.",
+ "pc.crashsight.wetest.net.",
+ "pcbs.loyalty.riotgames.com.",
"pcdn.brave.com.",
"pd.cdnwidget.com.",
"pdengagementapi.trafficmanager.net.",
+ "pdf24.org.",
"pdfforge.org.",
"pdrnetwork-my.sharepoint.com.",
+ "pdrnetwork.sharepoint.com.",
"penngaming-my.sharepoint.com.",
"penngaming.sharepoint.com.",
+ "penskeauto-my.sharepoint.com.",
"penskeauto.sharepoint.com.",
"peopleadmin.com.",
+ "peplink.com.",
"pepsico-my.sharepoint.com.",
"pepsico.sharepoint.com.",
"pepsico.zoom.us.",
@@ -3048,20 +3220,19 @@ var FakeECSFQDNs = container.NewMapSet(
"permutive.arstechnica.com.",
"permutive.businessinsider.com.",
"permutive.com.",
- "permutive.newyorker.com.",
"permutive.wired.com.",
"perr.brightvpn.com.",
"perrigo-my.sharepoint.com.",
+ "perrigo.sharepoint.com.",
"pf.intuit.com.",
"pfgsales-my.sharepoint.com.",
"pfgsales.sharepoint.com.",
- "pgsth.kargo.com.",
+ "pg-prebid-server.rubiconproject.com.",
"ph.globe.rcs.telephony.goog.",
- "pharos.studyquicks.com.",
"phoenix.remotepc.com.",
"phoenix2.remotepc.com.",
"phonehome.hazelcast.com.",
- "phx02pap001.storage.live.com.",
+ "photoroom.com.",
"phx02pap002.storage.live.com.",
"phx02pap003.storage.live.com.",
"phx02pap004.storage.live.com.",
@@ -3070,55 +3241,61 @@ var FakeECSFQDNs = container.NewMapSet(
"phx02pap008.storage.live.com.",
"pi2850.ci.managedwhitelisting.com.",
"piano.io.",
- "picsart.com.cdn.cloudflare.net.",
- "pie-api.io.",
+ "pikabu.ru.",
"ping.citrix.com.",
"ping.getadblock.com.",
"pingler.com.",
"pingmesh.bigo.sg.",
+ "pinimg.com.",
+ "pinnaclebancorp.sharepoint.com.",
+ "pinsentmasonsmdm-my.sharepoint.com.",
+ "pinterest.ca.",
"piojm.tech.",
"pis.alicdn.com.",
"pittsburgh.remotepc.com.",
"pix.cdnwidget.com.",
"pixel-sync.trafficmanager.net.",
+ "pixel.adlooxtracking.com.",
"pixel.gliacloud.com.",
"pjcr-my.sharepoint.com.",
+ "pk-live.cn.",
"pkgconnect-my.sharepoint.com.",
+ "pkgconnect.sharepoint.com.",
"pla-prod-scu-apim-01.azure-api.net.",
"playstream.media.",
"plrm.zone.",
- "plrsrvcs.com.",
"pm.geniusmonkey.com.",
+ "pns.alicdn.com.",
"poizon.com.",
- "polarisind-my.sharepoint.com.",
- "polarisind.sharepoint.com.",
"polling.zoom.us.",
"polyfill.archive.org.",
"popt.in.",
- "portal.myweblogon.com.",
+ "portal.afterpay.com.",
"portals.mobi.",
"portland.remotepc.com.",
"portlandoregongov-my.sharepoint.com.",
- "post.ksosoft.com.",
"posthog.com.",
"pov.spectrum.net.",
"pow7.com.",
"powerpoint-collab.officeapps.live.com.",
- "pp.topgblzzz.com.",
"ppgames.net.",
+ "ppos.com.",
"pps.feednews.com.",
+ "ppsvc.prismray.io.",
+ "prageru.com.",
"pragmaticplay.net.",
"prebid-la.casalemedia.com.",
+ "prebid-ny.casalemedia.com.",
"prebid-sj.casalemedia.com.",
"prebid-va.casalemedia.com.",
"prebid.trustedstack.com.",
"prebidserver.pixfuture.com.",
+ "precisionmedicinegroup-my.sharepoint.com.",
"precisionmedicinegroup.sharepoint.com.",
- "prem-pt1.365lpodds.com.",
- "prem-pt2.365lpodds.com.",
- "prem-pt3.365lpodds.com.",
"premierhealth-my.sharepoint.com.",
+ "premierhealth.sharepoint.com.",
"premium.xvpn.io.",
+ "preroll.hostave3.net.",
"printaudit.com.",
"printfriendly.com.",
"pro-swishapps-aks-tm.trafficmanager.net.",
@@ -3134,9 +3311,9 @@ var FakeECSFQDNs = container.NewMapSet(
"prod-newsletter-edge.v.aaplimg.com.",
"prod-weather-widget-event-gateway.v.aaplimg.com.",
"prod.api.letsencrypt.org.",
- "prod.uno.demonware.net.",
"production.kabutoservices.com.",
"promega-my.sharepoint.com.",
+ "promos.investing.com.",
"protontech.ch.",
"protonvpn.com.",
"provaltech.com.",
@@ -3145,39 +3322,33 @@ var FakeECSFQDNs = container.NewMapSet(
"ps.namequery.com.",
"psav-my.sharepoint.com.",
"psav.sharepoint.com.",
- "pshud.365lpodds.com.",
- "pshud.365lpodds.com.cdn.cloudflare.net.",
- "pths209-my.sharepoint.com.",
+ "pttor-my.sharepoint.com.",
+ "pttplc-my.sharepoint.com.",
"pub.affilimateapis.com.",
"pub.network.",
+ "pubg-sg-community.playerinfinite.com.",
+ "public-prakerja.oss-ap-southeast-5.aliyuncs.com.",
"public.bn.files.1drv.com.",
- "public.boxcloud.com.",
"public.dm.files.1drv.com.",
- "public.sn.files.1drv.com.",
"publicfaas.vasdgame.com.",
"publictracker.xyz.",
"publisher.liveperson.net.",
+ "pubsub.checkvideo.net.",
"puffer.6.401402081.west-gcloud.codm.activision.com.",
- "puhsd210-my.sharepoint.com.",
- "puhsd210.sharepoint.com.",
- "pull-flv-f58-tt03.fcdn.eu.tiktokcdn.com.",
"punch.p2p.qq.com.",
- "pusd11net-my.sharepoint.com.",
"push-row.zui.com.",
+ "push.omiapp.me.",
"pushcrew.com.",
"pushmac.flexibits.com.",
"pushmart.net.",
- "pushnetwork.com.",
"pushtimize.com.",
"pushtrs7.push.hicloud.com.",
"puswdsprmtprs.dealersocket.com.",
"puv.tt.browser.360.cn.",
+ "pv.vipads.cc.",
"pw.mediav.com.",
- "pwa.zoom.us.",
"pwaweblogin.wmpvp.com.",
- "pwcgov-my.sharepoint.com.",
"px4.ads.linkedin.com.",
- "qa.sockets.stackexchange.com.",
"qagpublic.qg1.apps.qualys.ca.",
"qagpublic.qg1.apps.qualys.co.uk.",
"qagpublic.qg1.apps.qualys.com.",
@@ -3186,24 +3357,27 @@ var FakeECSFQDNs = container.NewMapSet(
"qagpublic.qg2.apps.qualys.eu.",
"qagpublic.qg3.apps.qualys.com.",
"qagpublic.qg4.apps.qualys.com.",
+ "qcloud-sg-datareceiver.kurogame.xyz.",
+ "qcloud.com.",
+ "qe-us-mobility.imanage.work.",
"qfp.intuit.com.",
"qikify.com.",
+ "qinglong.me.",
"qiniudns.com.",
+ "qiniup.com.",
"qookkagames.com.",
"qorvo-my.sharepoint.com.",
- "qpic.cn.",
+ "qorvo.sharepoint.com.",
"qq.com.cn.",
"qualys.ca.",
"qualys.com.",
"qualys.eu.",
- "quantamagazine.org.",
"quebeccity.remotepc.com.",
"questdiagnostics.sharepoint.com.",
- "questionpro.com.",
"quickcep.com.",
"quotemedia.com.",
+ "quoteninja.com.",
"qurl.f.360.cn.",
- "qvc.com.",
"qxwz.com.",
"r.ingest-lr.com.",
"r.intake-lr.com.",
@@ -3216,7 +3390,6 @@ var FakeECSFQDNs = container.NewMapSet(
"r.lr-ingest.io.",
"r.lr-intake.com.",
"r.superhuman.com.",
- "r1---sn-a5mlrnll.c.2mdn.net.",
"r1---sn-ab5l6ndr.c.2mdn.net.",
"r1---sn-ab5l6nk6.c.2mdn.net.",
"r1---sn-ab5l6nkd.c.2mdn.net.",
@@ -3224,10 +3397,11 @@ var FakeECSFQDNs = container.NewMapSet(
"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-ab5sznld.c.2mdn.net.",
- "r1---sn-ab5sznlk.c.2mdn.net.",
+ "r1---sn-ab5sznly.c.2mdn.net.",
"r1---sn-ab5sznz6.c.2mdn.net.",
"r1---sn-ab5sznzd.c.2mdn.net.",
"r1---sn-ab5sznze.c.2mdn.net.",
@@ -3237,116 +3411,112 @@ var FakeECSFQDNs = container.NewMapSet(
"r1---sn-ab5sznzs.c.2mdn.net.",
"r1---sn-ab5sznzy.c.2mdn.net.",
"r1---sn-ab5sznzz.c.2mdn.net.",
- "r1---sn-aigl6nzl.c.2mdn.net.",
- "r1---sn-npoldn76.c.2mdn.net.",
+ "r1---sn-nx57ynsk.c.2mdn.net.",
"r1---sn-p5qddn7d.c.2mdn.net.",
- "r1---sn-p5qddn7k.c.2mdn.net.",
- "r1---sn-p5qlsn76.c.2mdn.net.",
- "r1---sn-p5qlsnrl.c.2mdn.net.",
+ "r1---sn-p5qs7nsk.c.2mdn.net.",
"r1---sn-p5qs7nsr.c.2mdn.net.",
- "r1---sn-p5qs7nzk.c.2mdn.net.",
- "r1---sn-q4fl6n6r.c.2mdn.net.",
- "r1---sn-q4fl6n6s.c.2mdn.net.",
- "r1---sn-q4fl6nds.c.2mdn.net.",
- "r1---sn-q4fl6nsl.c.2mdn.net.",
- "r1---sn-q4fl6nss.c.2mdn.net.",
+ "r1---sn-q4fl6n6z.c.2mdn.net.",
"r1---sn-q4fl6nz7.c.2mdn.net.",
- "r1---sn-q4flrne6.c.2mdn.net.",
"r1---sn-q4flrnld.c.2mdn.net.",
- "r1---sn-q4flrnsd.c.2mdn.net.",
- "r1---sn-q4flrnsk.c.2mdn.net.",
- "r1---sn-vgqskn66.c.2mdn.net.",
+ "r1---sn-vgqskn67.c.2mdn.net.",
"r1---sn-vgqskn6z.c.2mdn.net.",
- "r1---sn-vgqsknek.c.2mdn.net.",
- "r1---sn-vgqsknlr.c.2mdn.net.",
- "r1---sn-vgqsknsk.c.2mdn.net.",
- "r1---sn-vgqsknz7.c.2mdn.net.",
- "r1---sn-vgqsknzl.c.2mdn.net.",
+ "r1---sn-vgqsknly.c.2mdn.net.",
+ "r1---sn-vgqsknse.c.2mdn.net.",
+ "r1---sn-vgqsknz6.c.2mdn.net.",
+ "r1---sn-vgqsknze.c.2mdn.net.",
"r1---sn-vgqsknzr.c.2mdn.net.",
"r1---sn-vgqsknzy.c.2mdn.net.",
- "r1---sn-vgqsrn66.c.2mdn.net.",
- "r1---sn-vgqsrn67.c.2mdn.net.",
- "r1---sn-vgqsrn6e.c.2mdn.net.",
- "r1---sn-vgqsrn6l.c.2mdn.net.",
+ "r1---sn-vgqsknzz.c.2mdn.net.",
+ "r1---sn-vgqsrne6.c.2mdn.net.",
+ "r1---sn-vgqsrnek.c.2mdn.net.",
+ "r1---sn-vgqsrnl6.c.2mdn.net.",
+ "r1---sn-vgqsrnld.c.2mdn.net.",
"r1---sn-vgqsrnlk.c.2mdn.net.",
- "r1---sn-vgqsrns6.c.2mdn.net.",
+ "r1---sn-vgqsrnls.c.2mdn.net.",
"r1---sn-vgqsrnsd.c.2mdn.net.",
- "r1---sn-vgqsrnsr.c.2mdn.net.",
"r1---sn-vgqsrnsy.c.2mdn.net.",
- "r1---sn-vgqsrnz7.c.2mdn.net.",
- "r1---sn-vgqsrnzk.c.2mdn.net.",
- "r2---sn-a5mekn6k.c.2mdn.net.",
+ "r1---sn-vgqsrnzy.c.2mdn.net.",
+ "r2---sn-a5mlrnl6.c.2mdn.net.",
+ "r2---sn-a5msenll.c.2mdn.net.",
"r2---sn-ab5l6nk6.c.2mdn.net.",
- "r2---sn-ab5l6nkd.c.2mdn.net.",
"r2---sn-ab5l6nr6.c.2mdn.net.",
"r2---sn-ab5l6nrd.c.2mdn.net.",
+ "r2---sn-ab5l6nrk.c.2mdn.net.",
"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-ab5sznld.c.2mdn.net.",
"r2---sn-ab5sznz6.c.2mdn.net.",
"r2---sn-ab5sznzd.c.2mdn.net.",
"r2---sn-ab5sznze.c.2mdn.net.",
"r2---sn-ab5sznzk.c.2mdn.net.",
"r2---sn-ab5sznzl.c.2mdn.net.",
+ "r2---sn-ab5sznzr.c.2mdn.net.",
+ "r2---sn-ab5sznzs.c.2mdn.net.",
"r2---sn-ab5sznzy.c.2mdn.net.",
"r2---sn-ab5sznzz.c.2mdn.net.",
- "r2---sn-p5qddn7k.c.2mdn.net.",
- "r2---sn-p5qddn7r.c.2mdn.net.",
- "r2---sn-p5qlsnrr.c.2mdn.net.",
+ "r2---sn-nx57ynsk.c.2mdn.net.",
+ "r2---sn-p5qlsn7l.c.2mdn.net.",
+ "r2---sn-p5qs7nsk.c.2mdn.net.",
"r2---sn-q4fl6n66.c.2mdn.net.",
"r2---sn-q4fl6nds.c.2mdn.net.",
- "r2---sn-q4fl6ns6.c.2mdn.net.",
- "r2---sn-q4fl6nsy.c.2mdn.net.",
- "r2---sn-q4fl6nz6.c.2mdn.net.",
- "r2---sn-q4flrnel.c.2mdn.net.",
- "r2---sn-q4flrnld.c.2mdn.net.",
- "r2---sn-q4flrnle.c.2mdn.net.",
+ "r2---sn-q4fl6nsk.c.2mdn.net.",
"r2---sn-q4fzen7y.c.2mdn.net.",
- "r2---sn-q4fzene7.c.2mdn.net.",
- "r2---sn-vgqskn66.c.2mdn.net.",
- "r2---sn-vgqsknld.c.2mdn.net.",
- "r2---sn-vgqsknlk.c.2mdn.net.",
- "r2---sn-vgqsknzz.c.2mdn.net.",
- "r2---sn-vgqsrn6e.c.2mdn.net.",
- "r2---sn-vgqsrne6.c.2mdn.net.",
- "r2---sn-vgqsrnls.c.2mdn.net.",
+ "r2---sn-vgqsrn66.c.2mdn.net.",
+ "r2---sn-vgqsrn67.c.2mdn.net.",
+ "r2---sn-vgqsrn6z.c.2mdn.net.",
+ "r2---sn-vgqsrnld.c.2mdn.net.",
"r2---sn-vgqsrnlz.c.2mdn.net.",
+ "r2---sn-vgqsrns6.c.2mdn.net.",
+ "r2---sn-vgqsrnsy.c.2mdn.net.",
"r2---sn-vgqsrnzd.c.2mdn.net.",
- "r2---sn-vgqsrnzs.c.2mdn.net.",
"r2---sn-vgqsrnzz.c.2mdn.net.",
+ "r3---sn-a5msenle.c.2mdn.net.",
+ "r3---sn-ab5l6ndr.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-ab5l6nrd.c.2mdn.net.",
"r3---sn-ab5l6nrk.c.2mdn.net.",
"r3---sn-ab5l6nrl.c.2mdn.net.",
- "r3---sn-ab5l6nrr.c.2mdn.net.",
"r3---sn-ab5l6nrs.c.2mdn.net.",
- "r3---sn-ab5sznld.c.2mdn.net.",
+ "r3---sn-ab5l6nrz.c.2mdn.net.",
+ "r3---sn-ab5sznlk.c.2mdn.net.",
+ "r3---sn-ab5sznly.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-ab5sznzz.c.2mdn.net.",
- "r3---sn-p5qlsn7d.c.2mdn.net.",
- "r3---sn-p5qs7nsr.c.2mdn.net.",
+ "r3---sn-nx57ynsk.c.2mdn.net.",
+ "r3---sn-p5qlsn7s.c.2mdn.net.",
+ "r3---sn-p5qlsnrr.c.2mdn.net.",
+ "r3---sn-p5qlsny6.c.2mdn.net.",
+ "r3---sn-p5qs7nsk.c.2mdn.net.",
+ "r3---sn-p5qs7nzr.c.2mdn.net.",
"r3---sn-q4fl6n6z.c.2mdn.net.",
- "r3---sn-q4fl6nsk.c.2mdn.net.",
+ "r3---sn-q4flrnl7.c.2mdn.net.",
"r3---sn-q4fzen7l.c.2mdn.net.",
- "r3---sn-q4fzen7s.c.2mdn.net.",
- "r3---sn-q4fzene7.c.2mdn.net.",
+ "r3---sn-q4fzenee.c.2mdn.net.",
"r3---sn-vgqskn6d.c.2mdn.net.",
"r3---sn-vgqskn6z.c.2mdn.net.",
- "r3---sn-vgqsknlr.c.2mdn.net.",
- "r3---sn-vgqsknzr.c.2mdn.net.",
+ "r3---sn-vgqsknes.c.2mdn.net.",
+ "r3---sn-vgqsknez.c.2mdn.net.",
+ "r3---sn-vgqsknll.c.2mdn.net.",
+ "r3---sn-vgqsknly.c.2mdn.net.",
+ "r3---sn-vgqsknse.c.2mdn.net.",
+ "r3---sn-vgqsknz7.c.2mdn.net.",
+ "r3---sn-vgqsknzl.c.2mdn.net.",
"r3---sn-vgqsknzy.c.2mdn.net.",
- "r3---sn-vgqsrnez.c.2mdn.net.",
+ "r3---sn-vgqsrn66.c.2mdn.net.",
+ "r3---sn-vgqsrnl6.c.2mdn.net.",
"r3---sn-vgqsrnlk.c.2mdn.net.",
- "r3---sn-vgqsrnsy.c.2mdn.net.",
- "r3---sn-vgqsrnz7.c.2mdn.net.",
- "r3---sn-vgqsrnzd.c.2mdn.net.",
+ "r3---sn-vgqsrnls.c.2mdn.net.",
+ "r3---sn-vgqsrnzy.c.2mdn.net.",
"r3---sn-vgqsrnzz.c.2mdn.net.",
"r4---sn-ab5l6ndr.c.2mdn.net.",
"r4---sn-ab5l6nk6.c.2mdn.net.",
@@ -3358,194 +3528,185 @@ var FakeECSFQDNs = container.NewMapSet(
"r4---sn-ab5l6nrr.c.2mdn.net.",
"r4---sn-ab5l6nrs.c.2mdn.net.",
"r4---sn-ab5l6nrz.c.2mdn.net.",
- "r4---sn-ab5sznld.c.2mdn.net.",
+ "r4---sn-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-nx57ynsz.c.2mdn.net.",
- "r4---sn-p5qlsn7d.c.2mdn.net.",
- "r4---sn-p5qlsn7l.c.2mdn.net.",
- "r4---sn-q4fl6nds.c.2mdn.net.",
+ "r4---sn-nx57ynsk.c.2mdn.net.",
+ "r4---sn-p5qddn76.c.2mdn.net.",
+ "r4---sn-p5qs7nsk.c.2mdn.net.",
+ "r4---sn-q4fl6nd7.c.2mdn.net.",
"r4---sn-q4fl6nsd.c.2mdn.net.",
- "r4---sn-q4fl6nzy.c.2mdn.net.",
- "r4---sn-q4flrnel.c.2mdn.net.",
+ "r4---sn-q4fl6nz6.c.2mdn.net.",
"r4---sn-q4flrnld.c.2mdn.net.",
- "r4---sn-vgqskn66.c.2mdn.net.",
+ "r4---sn-q4fzen7l.c.2mdn.net.",
"r4---sn-vgqskn6s.c.2mdn.net.",
"r4---sn-vgqskn6z.c.2mdn.net.",
- "r4---sn-vgqsknld.c.2mdn.net.",
- "r4---sn-vgqsknll.c.2mdn.net.",
"r4---sn-vgqsknlr.c.2mdn.net.",
- "r4---sn-vgqsknse.c.2mdn.net.",
- "r4---sn-vgqsknsk.c.2mdn.net.",
- "r4---sn-vgqsknz7.c.2mdn.net.",
"r4---sn-vgqsknzd.c.2mdn.net.",
- "r4---sn-vgqsknzk.c.2mdn.net.",
- "r4---sn-vgqsknzl.c.2mdn.net.",
- "r4---sn-vgqsknzy.c.2mdn.net.",
- "r4---sn-vgqsknzz.c.2mdn.net.",
- "r4---sn-vgqsrn6z.c.2mdn.net.",
+ "r4---sn-vgqsknzs.c.2mdn.net.",
+ "r4---sn-vgqsrn66.c.2mdn.net.",
"r4---sn-vgqsrnl6.c.2mdn.net.",
- "r4---sn-vgqsrns6.c.2mdn.net.",
"r4---sn-vgqsrnsy.c.2mdn.net.",
- "r4---sn-vgqsrnzd.c.2mdn.net.",
+ "r5---sn-a5mekn6s.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-npoe7nsk.c.2mdn.net.",
- "r5---sn-p5qddn7d.c.2mdn.net.",
- "r5---sn-p5qlsn6l.c.2mdn.net.",
- "r5---sn-p5qlsn76.c.2mdn.net.",
- "r5---sn-p5qs7nzk.c.2mdn.net.",
+ "r5---sn-nx57ynsk.c.2mdn.net.",
+ "r5---sn-p5qs7nsk.c.2mdn.net.",
"r5---sn-p5qs7nzy.c.2mdn.net.",
+ "r5---sn-q4fl6nd7.c.2mdn.net.",
"r5---sn-q4fl6ndz.c.2mdn.net.",
+ "r5---sn-q4fl6nss.c.2mdn.net.",
+ "r5---sn-q4flrnez.c.2mdn.net.",
"r5---sn-q4flrnsd.c.2mdn.net.",
- "r5---sn-q4fzen7y.c.2mdn.net.",
- "r5---sn-vgqskn67.c.2mdn.net.",
- "r5---sn-vgqskn6d.c.2mdn.net.",
- "r5---sn-vgqskn6s.c.2mdn.net.",
- "r5---sn-vgqsknes.c.2mdn.net.",
- "r5---sn-vgqsknsk.c.2mdn.net.",
+ "r5---sn-q4fzen7l.c.2mdn.net.",
+ "r5---sn-q4fzene7.c.2mdn.net.",
+ "r5---sn-vgqsknld.c.2mdn.net.",
+ "r5---sn-vgqsknlr.c.2mdn.net.",
+ "r5---sn-vgqsknly.c.2mdn.net.",
"r5---sn-vgqsknz6.c.2mdn.net.",
+ "r5---sn-vgqsknz7.c.2mdn.net.",
"r5---sn-vgqsknze.c.2mdn.net.",
"r5---sn-vgqsknzl.c.2mdn.net.",
"r5---sn-vgqsknzs.c.2mdn.net.",
- "r5---sn-vgqsrn66.c.2mdn.net.",
- "r5---sn-vgqsrn67.c.2mdn.net.",
- "r5---sn-vgqsrn6e.c.2mdn.net.",
- "r5---sn-vgqsrn6z.c.2mdn.net.",
- "r5---sn-vgqsrned.c.2mdn.net.",
- "r5---sn-vgqsrnek.c.2mdn.net.",
- "r5---sn-vgqsrnld.c.2mdn.net.",
+ "r5---sn-vgqsrnlk.c.2mdn.net.",
"r5---sn-vgqsrnls.c.2mdn.net.",
- "r5---sn-vgqsrnlz.c.2mdn.net.",
"r5---sn-vgqsrnz6.c.2mdn.net.",
- "r5---sn-vgqsrnzk.c.2mdn.net.",
+ "r5---sn-vgqsrnzz.c.2mdn.net.",
"raccorp-my.sharepoint.com.",
+ "raccorp.sharepoint.com.",
"radar.cedexis.com.",
"radar.com.",
"raleigh.remotepc.com.",
"randomhouse.app.box.com.",
+ "raspbian.raspberrypi.org.",
"rba-screen.healthsafe-id.com.",
"rba.onehealthcareid.com.",
+ "rbidsna5.stockx.com.",
+ "rbm-ap.storage.googleapis.com.",
"rbm-us.storage.googleapis.com.",
+ "rbmeuulvihtwm2eltjhwimi2.httpschecker.net.",
"rcs-acs-mcc510.jibe.google.com.",
+ "rcs-acs-tmo-us.jibe.google.com.",
"rcs-acs-tmobile-us.jibe.google.com.",
"rcs-copper-us.googleapis.com.",
- "rcs-user-content-us.storage.googleapis.com.",
"rcs.telephony.goog.",
"rd.com.",
- "realtime.arena.im.",
+ "realtime-data-api.transitapp.com.",
"realtime.luckyorange.com.",
"realtime.services.box.net.",
+ "recognition.lansweeper.com.",
"recombee.com.",
"recruiting.ultipro.com.",
"recruiting2.ultipro.com.",
+ "reedelsevier-my.sharepoint.com.",
"reedelsevier.sharepoint.com.",
- "reef.com.",
- "reflector.makerbot.com.",
+ "refpaucqkl.top.",
+ "region1.app-analytics-services.com.",
+ "regional.azure-api.net.",
"regions.com.",
- "registration.prap01.cmdagent.trafficmanager.net.",
- "registration.prau01.cmdagent.trafficmanager.net.",
- "registration.preu01.cmdagent.trafficmanager.net.",
"registration.prna01.cmdagent.trafficmanager.net.",
"regn-my.sharepoint.com.",
"regn.sharepoint.com.",
+ "reimicrosoft-my.sharepoint.com.",
"rejuvenation.com.",
- "relay.shhnowisnottheti.me.",
+ "related.queryly.com.",
"remote-config.gslb.sgw.shopeemobile.com.",
"remote.control4.com.",
- "remote.melonhead.me.",
+ "remoteassistance.support.services.microsoft.com.",
+ "rentonschools-my.sharepoint.com.",
"repo.zabbix.com.",
+ "repos.eggycrew.com.",
"republicservices-my.sharepoint.com.",
+ "republicservices.sharepoint.com.",
"requality.android.shouji.sogou.com.",
"request-global.czilladx.com.",
"resideo.com.",
"resource.digitalinsight.com.",
+ "restaurantguru.com.",
+ "restauth.opentable.com.",
"restproxy-analytics.ascendlearning.com.",
"restrict.youtube.com.",
"restrictmoderate.youtube.com.",
- "retailrocket.net.",
"retailstarbucks1com-my.sharepoint.com.",
"retailstarbucks1com.sharepoint.com.",
+ "retcode-sg-lazada.arms.aliyuncs.com.",
"retcode-us-west-1.arms.aliyuncs.com.",
"rethinkad.com.",
"retinavue.net.",
"reverso.net.",
"rexel.sharepoint.com.",
- "rhmail-my.sharepoint.com.",
"ri9864.ci.managedwhitelisting.com.",
"richrelevance.com.",
"ridge.com.",
+ "ridgewireless.mm.fcix.net.",
"rivergame.net.",
"rivhs-my.sharepoint.com.",
"rl.progressive.com.",
"rl.quantummetric.com.",
+ "rlm.haokan.mobi.",
"rmm.acctek.com.",
"rmm.aunalytics.com.",
"rmm.creativeplanning.com.",
+ "rmm.it-radix.com.",
"rmm2.jmark.com.",
"rms-dra.platform.dbankcloud.com.",
+ "rms-dre.platform.dbankcloud.com.",
"rn-resource-app.xiaohongshu.com.",
+ "roaming-df.officeapps.live.com.",
"roberthalf-my.sharepoint.com.",
"roberthalf.sharepoint.com.",
- "roborock.com.",
"rocketsutoledo-my.sharepoint.com.",
"rockwellautomation-my.sharepoint.com.",
"rockwellautomation.sharepoint.com.",
"rockylinux.org.",
- "rogueone.aristotleinsight.com.",
"romsp-unifyconfig.vivo.com.cn.",
"router.teamviewer.com.",
"roxy.azurefd.net.",
- "rpiexchange-my.sharepoint.com.",
"rpt.cedexis.com.",
+ "rq.upgrade.cmpc.cmcm.com.",
"rq.wh.cmcm.com.",
- "rr1---sn-02o-ao3e.googlevideo.com.",
"rr1---sn-0nnpbo5a-bggl.googlevideo.com.",
"rr1---sn-0op8v4h5pox-cbgl.googlevideo.com.",
- "rr1---sn-2imern76.googlevideo.com.",
- "rr1---sn-2imern76.gvt1.com.",
- "rr1---sn-2imern7d.googlevideo.com.",
- "rr1---sn-2imern7d.gvt1.com.",
- "rr1---sn-2imeyn7k.googlevideo.com.",
- "rr1---sn-2napbiu-p5ie.googlevideo.com.",
- "rr1---sn-2napbiu-p5ie.gvt1.com.",
+ "rr1---sn-2aqu-hoaly.googlevideo.com.",
+ "rr1---sn-2aqu-hoas7.googlevideo.com.",
+ "rr1---sn-2aqu-hoasz.googlevideo.com.",
"rr1---sn-2oaig5-55.googlevideo.com.",
- "rr1---sn-2pmxapm0n-gpje.googlevideo.com.",
- "rr1---sn-2pmxapm0n-gpjl.googlevideo.com.",
"rr1---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr1---sn-2vgu0b5auxaxjvh-apnz.googlevideo.com.",
"rr1---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
"rr1---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
"rr1---sn-2vgu0b5auxaxjvh-v2vk.googlevideo.com.",
"rr1---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
+ "rr1---sn-2vgu0b5auxaxjvh-v2vz.googlevideo.com.",
"rr1---sn-30a7rne6.googlevideo.com.",
"rr1---sn-30a7rned.googlevideo.com.",
"rr1---sn-30a7rnek.googlevideo.com.",
- "rr1---sn-30a7rner.googlevideo.com.",
"rr1---sn-30a7ynek.googlevideo.com.",
"rr1---sn-30a7yner.googlevideo.com.",
"rr1---sn-30a7ynl7.googlevideo.com.",
"rr1---sn-3jpm-hjpe.googlevideo.com.",
- "rr1---sn-3n4pcxg-pjul.googlevideo.com.",
"rr1---sn-3n4pcxg-pjuz.googlevideo.com.",
+ "rr1---sn-42u-nbozl.googlevideo.com.",
"rr1---sn-4g5e6ns6.googlevideo.com.",
"rr1---sn-4g5e6ns7.googlevideo.com.",
"rr1---sn-4g5e6nsd.googlevideo.com.",
@@ -3553,13 +3714,13 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-4g5e6nsr.googlevideo.com.",
"rr1---sn-4g5e6nss.googlevideo.com.",
"rr1---sn-4g5e6nsy.googlevideo.com.",
- "rr1---sn-4g5e6nsz.googlevideo.com.",
"rr1---sn-4g5e6nz7.googlevideo.com.",
"rr1---sn-4g5e6nze.googlevideo.com.",
"rr1---sn-4g5e6nzl.googlevideo.com.",
"rr1---sn-4g5e6nzs.googlevideo.com.",
"rr1---sn-4g5e6nzz.googlevideo.com.",
"rr1---sn-4g5edn6k.googlevideo.com.",
+ "rr1---sn-4g5edn6r.googlevideo.com.",
"rr1---sn-4g5edn6y.googlevideo.com.",
"rr1---sn-4g5ednd7.googlevideo.com.",
"rr1---sn-4g5edndd.googlevideo.com.",
@@ -3578,9 +3739,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-4g5ednsd.googlevideo.com.",
"rr1---sn-4g5ednse.googlevideo.com.",
"rr1---sn-4g5ednsk.googlevideo.com.",
- "rr1---sn-4g5ednsl.googlevideo.com.",
"rr1---sn-4g5ednsr.googlevideo.com.",
"rr1---sn-4g5ednss.googlevideo.com.",
+ "rr1---sn-4g5ednsy.googlevideo.com.",
"rr1---sn-4g5ednsz.googlevideo.com.",
"rr1---sn-4g5ednz7.googlevideo.com.",
"rr1---sn-4g5lzne6.googlevideo.com.",
@@ -3589,14 +3750,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-4g5lzner.googlevideo.com.",
"rr1---sn-4g5lznes.googlevideo.com.",
"rr1---sn-4g5lzney.googlevideo.com.",
+ "rr1---sn-4g5lznez.googlevideo.com.",
"rr1---sn-4g5lznl6.googlevideo.com.",
"rr1---sn-4g5lznl7.googlevideo.com.",
- "rr1---sn-4g5lznle.googlevideo.com.",
"rr1---sn-4g5lznls.googlevideo.com.",
"rr1---sn-4g5lznlz.googlevideo.com.",
- "rr1---sn-4pgnuapbiu-hiul.googlevideo.com.",
- "rr1---sn-5gxo-in8l.googlevideo.com.",
- "rr1---sn-5gxo-in8s.googlevideo.com.",
+ "rr1---sn-4jjo-apnl.googlevideo.com.",
"rr1---sn-5hne6n6e.googlevideo.com.",
"rr1---sn-5hne6n6l.googlevideo.com.",
"rr1---sn-5hne6ns6.googlevideo.com.",
@@ -3605,9 +3764,10 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-5hne6nsr.googlevideo.com.",
"rr1---sn-5hne6nsy.googlevideo.com.",
"rr1---sn-5hne6nsz.googlevideo.com.",
+ "rr1---sn-5hne6nsz.gvt1.com.",
"rr1---sn-5hne6nz6.googlevideo.com.",
- "rr1---sn-5hne6nz6.gvt1.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.",
@@ -3615,10 +3775,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-5hnednsz.googlevideo.com.",
"rr1---sn-5hnekn76.googlevideo.com.",
"rr1---sn-5hnekn7d.googlevideo.com.",
- "rr1---sn-5hnekn7k.googlevideo.com.",
"rr1---sn-5hnekn7l.googlevideo.com.",
"rr1---sn-5hnekn7s.googlevideo.com.",
- "rr1---sn-5hnekn7z.googlevideo.com.",
"rr1---sn-5hneknee.googlevideo.com.",
"rr1---sn-5hneknek.googlevideo.com.",
"rr1---sn-5hneknes.googlevideo.com.",
@@ -3630,19 +3788,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-5uaeznes.googlevideo.com.",
"rr1---sn-5uaeznez.googlevideo.com.",
"rr1---sn-5uaeznl6.googlevideo.com.",
- "rr1---sn-5uaeznld.googlevideo.com.",
- "rr1---sn-5uaeznly.googlevideo.com.",
"rr1---sn-5uaeznlz.googlevideo.com.",
- "rr1---sn-5uaeznrz.googlevideo.com.",
"rr1---sn-5uaezns7.googlevideo.com.",
"rr1---sn-5uaeznse.googlevideo.com.",
"rr1---sn-5uaeznsl.googlevideo.com.",
"rr1---sn-5uaeznss.googlevideo.com.",
- "rr1---sn-5uaezny6.googlevideo.com.",
- "rr1---sn-5uaeznys.googlevideo.com.",
- "rr1---sn-5uaeznyz.googlevideo.com.",
"rr1---sn-5uaeznze.googlevideo.com.",
- "rr1---sn-5ualdnle.googlevideo.com.",
"rr1---sn-5ualdnll.googlevideo.com.",
"rr1---sn-5ualdnlr.googlevideo.com.",
"rr1---sn-5ualdnls.googlevideo.com.",
@@ -3658,83 +3809,84 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-5ualdnsz.googlevideo.com.",
"rr1---sn-5ualdnz7.googlevideo.com.",
"rr1---sn-5ualdnze.googlevideo.com.",
+ "rr1---sn-8qj-i5o6k.googlevideo.com.",
"rr1---sn-8qj-i5okl.googlevideo.com.",
+ "rr1---sn-8qj-i5ozd.googlevideo.com.",
+ "rr1---sn-8qj-i5ozr.googlevideo.com.",
"rr1---sn-8qj-nbo66.googlevideo.com.",
"rr1---sn-8qj-nbo6y.googlevideo.com.",
"rr1---sn-8xgp1vo-2iae.googlevideo.com.",
- "rr1---sn-8xgp1vo-2iae7.googlevideo.com.",
"rr1---sn-8xgp1vo-2ial.googlevideo.com.",
"rr1---sn-8xgp1vo-2iay.googlevideo.com.",
- "rr1---sn-8xgp1vo-a5me.googlevideo.com.",
"rr1---sn-8xgp1vo-ab56.googlevideo.com.",
"rr1---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr1---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr1---sn-8xgp1vo-ab5l.googlevideo.com.",
"rr1---sn-8xgp1vo-ab5s.googlevideo.com.",
"rr1---sn-8xgp1vo-ab5z.googlevideo.com.",
+ "rr1---sn-8xgp1vo-hjpl.googlevideo.com.",
"rr1---sn-8xgp1vo-nh4e.googlevideo.com.",
"rr1---sn-8xgp1vo-p5ie.googlevideo.com.",
+ "rr1---sn-8xgp1vo-poql.googlevideo.com.",
"rr1---sn-8xgp1vo-xfge.googlevideo.com.",
"rr1---sn-8xgp1vo-xfgl.googlevideo.com.",
"rr1---sn-8xgp1vo-xfgs.googlevideo.com.",
"rr1---sn-9gv76n7e.googlevideo.com.",
"rr1---sn-9gv76n7l.googlevideo.com.",
- "rr1---sn-9gv76n7s.googlevideo.com.",
"rr1---sn-9gv7ene6.googlevideo.com.",
"rr1---sn-9gv7ened.googlevideo.com.",
"rr1---sn-9gv7zn76.googlevideo.com.",
"rr1---sn-9gv7zn7e.googlevideo.com.",
"rr1---sn-9gv7zn7r.googlevideo.com.",
"rr1---sn-a5m7lnl6.googlevideo.com.",
- "rr1---sn-a5m7lnl6.gvt1.com.",
"rr1---sn-a5m7lnld.googlevideo.com.",
"rr1---sn-a5mekn6d.googlevideo.com.",
"rr1---sn-a5mekn6k.googlevideo.com.",
"rr1---sn-a5mekn6k.gvt1.com.",
"rr1---sn-a5mekn6l.googlevideo.com.",
"rr1---sn-a5mekn6r.googlevideo.com.",
+ "rr1---sn-a5mekn6r.gvt1.com.",
"rr1---sn-a5mekn6s.googlevideo.com.",
"rr1---sn-a5mekn6z.googlevideo.com.",
"rr1---sn-a5meknd6.googlevideo.com.",
+ "rr1---sn-a5meknd6.gvt1.com.",
"rr1---sn-a5meknde.googlevideo.com.",
"rr1---sn-a5mekndl.googlevideo.com.",
"rr1---sn-a5meknds.googlevideo.com.",
+ "rr1---sn-a5meknds.gvt1.com.",
"rr1---sn-a5mekndz.googlevideo.com.",
"rr1---sn-a5meknsy.googlevideo.com.",
"rr1---sn-a5meknzk.googlevideo.com.",
"rr1---sn-a5meknzk.gvt1.com.",
"rr1---sn-a5meknzl.googlevideo.com.",
- "rr1---sn-a5meknzl.gvt1.com.",
"rr1---sn-a5meknzr.googlevideo.com.",
- "rr1---sn-a5meknzr.gvt1.com.",
"rr1---sn-a5meknzs.googlevideo.com.",
"rr1---sn-a5mlrnek.googlevideo.com.",
+ "rr1---sn-a5mlrnek.gvt1.com.",
"rr1---sn-a5mlrnl6.googlevideo.com.",
"rr1---sn-a5mlrnl6.gvt1.com.",
"rr1---sn-a5mlrnll.googlevideo.com.",
- "rr1---sn-a5mlrnll.gvt1.com.",
"rr1---sn-a5mlrnls.googlevideo.com.",
"rr1---sn-a5mlrnlz.googlevideo.com.",
+ "rr1---sn-a5mlrnlz.gvt1.com.",
"rr1---sn-a5msen76.googlevideo.com.",
"rr1---sn-a5msen7l.googlevideo.com.",
"rr1---sn-a5msen7s.googlevideo.com.",
"rr1---sn-a5msen7z.googlevideo.com.",
"rr1---sn-a5msenek.googlevideo.com.",
"rr1---sn-a5msener.googlevideo.com.",
- "rr1---sn-a5msenes.googlevideo.com.",
- "rr1---sn-a5msenes.gvt1.com.",
"rr1---sn-a5msenl7.googlevideo.com.",
+ "rr1---sn-a5msenl7.gvt1.com.",
"rr1---sn-a5msenle.googlevideo.com.",
- "rr1---sn-a5msenle.gvt1.com.",
"rr1---sn-a5msenll.googlevideo.com.",
- "rr1---sn-a5msenll.gvt1.com.",
- "rr1---sn-a5oj5nuxg-aone.googlevideo.com.",
"rr1---sn-ab5l6ndr.googlevideo.com.",
"rr1---sn-ab5l6ndy.googlevideo.com.",
- "rr1---sn-ab5l6ndy.gvt1.com.",
"rr1---sn-ab5l6nk6.googlevideo.com.",
+ "rr1---sn-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-ab5l6nrd.gvt1.com.",
"rr1---sn-ab5l6nrk.googlevideo.com.",
@@ -3742,7 +3894,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-ab5l6nrl.googlevideo.com.",
"rr1---sn-ab5l6nrr.googlevideo.com.",
"rr1---sn-ab5l6nrs.googlevideo.com.",
+ "rr1---sn-ab5l6nrs.gvt1.com.",
"rr1---sn-ab5l6nrz.googlevideo.com.",
+ "rr1---sn-ab5l6nrz.gvt1.com.",
"rr1---sn-ab5sznld.googlevideo.com.",
"rr1---sn-ab5sznlk.googlevideo.com.",
"rr1---sn-ab5sznly.googlevideo.com.",
@@ -3751,29 +3905,32 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-ab5sznzd.googlevideo.com.",
"rr1---sn-ab5sznzd.gvt1.com.",
"rr1---sn-ab5sznze.googlevideo.com.",
+ "rr1---sn-ab5sznze.gvt1.com.",
"rr1---sn-ab5sznzk.googlevideo.com.",
- "rr1---sn-ab5sznzk.gvt1.com.",
"rr1---sn-ab5sznzl.googlevideo.com.",
- "rr1---sn-ab5sznzl.gvt1.com.",
"rr1---sn-ab5sznzr.googlevideo.com.",
"rr1---sn-ab5sznzr.gvt1.com.",
"rr1---sn-ab5sznzs.googlevideo.com.",
"rr1---sn-ab5sznzy.googlevideo.com.",
"rr1---sn-ab5sznzz.googlevideo.com.",
+ "rr1---sn-ab5sznzz.gvt1.com.",
"rr1---sn-aigl6n6s.googlevideo.com.",
"rr1---sn-aigl6nek.googlevideo.com.",
"rr1---sn-aigl6ner.googlevideo.com.",
"rr1---sn-aigl6ney.googlevideo.com.",
+ "rr1---sn-aigl6ney.gvt1.com.",
"rr1---sn-aigl6nl7.googlevideo.com.",
+ "rr1---sn-aigl6nl7.gvt1.com.",
"rr1---sn-aigl6ns6.googlevideo.com.",
"rr1---sn-aigl6nsd.googlevideo.com.",
"rr1---sn-aigl6nsk.googlevideo.com.",
"rr1---sn-aigl6nsr.googlevideo.com.",
"rr1---sn-aigl6nz7.googlevideo.com.",
+ "rr1---sn-aigl6nze.googlevideo.com.",
"rr1---sn-aigl6nzk.googlevideo.com.",
"rr1---sn-aigl6nzl.googlevideo.com.",
+ "rr1---sn-aigl6nzl.gvt1.com.",
"rr1---sn-aigl6nzr.googlevideo.com.",
- "rr1---sn-aigl6nzr.gvt1.com.",
"rr1---sn-aigl6nzs.googlevideo.com.",
"rr1---sn-aigzrn76.googlevideo.com.",
"rr1---sn-aigzrn7d.googlevideo.com.",
@@ -3790,59 +3947,59 @@ 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-apn7en7s.googlevideo.com.",
- "rr1---sn-bg5oqxjvh-50nz.googlevideo.com.",
- "rr1---sn-bg5oqxjvh-jg2s.googlevideo.com.",
- "rr1---sn-bg5oqxjvh-xa2s.googlevideo.com.",
+ "rr1---sn-avbpj-cq5e.googlevideo.com.",
"rr1---sn-cvb7lne7.googlevideo.com.",
"rr1---sn-cvb7lnee.googlevideo.com.",
"rr1---sn-cvb7lnls.googlevideo.com.",
"rr1---sn-cvb7lnlz.googlevideo.com.",
"rr1---sn-cvb7sn7k.googlevideo.com.",
"rr1---sn-cvb7sn7r.googlevideo.com.",
- "rr1---sn-h0jeened.googlevideo.com.",
"rr1---sn-h0jeenl6.googlevideo.com.",
- "rr1---sn-h0jeenld.googlevideo.com.",
- "rr1---sn-h0jeenle.googlevideo.com.",
- "rr1---sn-h0jeln7e.googlevideo.com.",
"rr1---sn-h0jelne6.googlevideo.com.",
"rr1---sn-h0jelnes.googlevideo.com.",
"rr1---sn-h0jelnez.googlevideo.com.",
- "rr1---sn-hjoj-jaul.googlevideo.com.",
- "rr1---sn-hjoj-poul.googlevideo.com.",
+ "rr1---sn-h5gj5uxa-hutl.googlevideo.com.",
+ "rr1---sn-hgn7yn7e.googlevideo.com.",
"rr1---sn-hoa7kn76.googlevideo.com.",
"rr1---sn-hoa7kn7z.googlevideo.com.",
"rr1---sn-hoa7rn76.googlevideo.com.",
"rr1---sn-hp57kn6r.googlevideo.com.",
+ "rr1---sn-hp57kn6r.gvt1.com.",
"rr1---sn-hp57kn6y.googlevideo.com.",
- "rr1---sn-hp57kn6y.gvt1.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-hp57kndy.gvt1.com.",
"rr1---sn-hp57kndz.googlevideo.com.",
+ "rr1---sn-hp57kndz.gvt1.com.",
"rr1---sn-hp57yn7r.googlevideo.com.",
- "rr1---sn-hp57yn7r.gvt1.com.",
"rr1---sn-hp57yn7y.googlevideo.com.",
"rr1---sn-hp57yn7y.gvt1.com.",
+ "rr1---sn-hp57yne7.googlevideo.com.",
+ "rr1---sn-hp57yne7.gvt1.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-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-hp57ynsl.gvt1.com.",
"rr1---sn-hp57ynss.googlevideo.com.",
- "rr1---sn-hxgpu-qufs.googlevideo.com.",
+ "rr1---sn-hxugvoxupoj-poqz.googlevideo.com.",
"rr1---sn-i3b7kn6s.googlevideo.com.",
"rr1---sn-i3b7knld.googlevideo.com.",
- "rr1---sn-i3b7knlk.googlevideo.com.",
"rr1---sn-i3b7kns6.googlevideo.com.",
"rr1---sn-i3b7knsd.googlevideo.com.",
"rr1---sn-i3b7knse.googlevideo.com.",
@@ -3851,17 +4008,15 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-i3b7knzs.googlevideo.com.",
"rr1---sn-i3belne6.googlevideo.com.",
"rr1---sn-i3belney.googlevideo.com.",
- "rr1---sn-i3belnl6.googlevideo.com.",
"rr1---sn-i3belnl7.googlevideo.com.",
"rr1---sn-i3belnll.googlevideo.com.",
"rr1---sn-i3belnls.googlevideo.com.",
"rr1---sn-i3belnlz.googlevideo.com.",
"rr1---sn-i3bssn7e.googlevideo.com.",
- "rr1---sn-i5f5ppuxa-ioal.googlevideo.com.",
- "rr1---sn-i5goxu-i3bl.googlevideo.com.",
"rr1---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
"rr1---sn-jvhj5nu-2iae.googlevideo.com.",
"rr1---sn-jvhj5nu-2ial.googlevideo.com.",
+ "rr1---sn-jvhj5nu-2ias.googlevideo.com.",
"rr1---sn-jvhj5nu-nh4e.googlevideo.com.",
"rr1---sn-jvhj5nu-nh4l.googlevideo.com.",
"rr1---sn-jvhj5nu-nh4s.googlevideo.com.",
@@ -3869,26 +4024,22 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-jvhj5nu-qufe.googlevideo.com.",
"rr1---sn-jvhj5nu-qufs.googlevideo.com.",
"rr1---sn-jvhj5nu-qufz.googlevideo.com.",
- "rr1---sn-jxopj-n5oe.googlevideo.com.",
- "rr1---sn-jxopj-n5oe.gvt1.com.",
- "rr1---sn-muxa-2iae.googlevideo.com.",
- "rr1---sn-n0g45pg-ncoe.googlevideo.com.",
- "rr1---sn-n2uxaxjvh-j5xl.googlevideo.com.",
- "rr1---sn-n2uxaxjvh-j5xl.gvt1.com.",
+ "rr1---sn-jvooxqouf3-cqaz.googlevideo.com.",
"rr1---sn-n2uxaxjvh-j5xs.googlevideo.com.",
- "rr1---sn-n2uxaxjvh-j5xs.gvt1.com.",
"rr1---sn-n4v7snee.googlevideo.com.",
"rr1---sn-n4v7sney.googlevideo.com.",
"rr1---sn-n4v7snl7.googlevideo.com.",
+ "rr1---sn-n4v7snl7.gvt1.com.",
"rr1---sn-n4v7snll.googlevideo.com.",
"rr1---sn-n4v7snlr.googlevideo.com.",
"rr1---sn-n4v7snls.googlevideo.com.",
+ "rr1---sn-n4v7snls.gvt1.com.",
"rr1---sn-n4v7snly.googlevideo.com.",
"rr1---sn-n4v7sns7.googlevideo.com.",
"rr1---sn-n4v7snse.googlevideo.com.",
"rr1---sn-nh5gujvh-h4xe.googlevideo.com.",
- "rr1---sn-nh5gujvh-h4xe.gvt1.com.",
"rr1---sn-npoe7ndl.googlevideo.com.",
+ "rr1---sn-npoe7ndl.gvt1.com.",
"rr1---sn-npoe7nds.googlevideo.com.",
"rr1---sn-npoe7ne6.googlevideo.com.",
"rr1---sn-npoe7ne7.googlevideo.com.",
@@ -3898,9 +4049,11 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-npoe7nes.googlevideo.com.",
"rr1---sn-npoe7ney.googlevideo.com.",
"rr1---sn-npoe7nez.googlevideo.com.",
+ "rr1---sn-npoe7nl6.googlevideo.com.",
"rr1---sn-npoe7nlz.googlevideo.com.",
"rr1---sn-npoe7ns6.googlevideo.com.",
"rr1---sn-npoe7ns7.googlevideo.com.",
+ "rr1---sn-npoe7ns7.gvt1.com.",
"rr1---sn-npoe7nsd.googlevideo.com.",
"rr1---sn-npoe7nsk.googlevideo.com.",
"rr1---sn-npoe7nsl.googlevideo.com.",
@@ -3908,48 +4061,46 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-npoe7nss.googlevideo.com.",
"rr1---sn-npoe7nsy.googlevideo.com.",
"rr1---sn-npoe7nz7.googlevideo.com.",
+ "rr1---sn-npoe7nz7.gvt1.com.",
"rr1---sn-npoeene6.googlevideo.com.",
"rr1---sn-npoeened.googlevideo.com.",
"rr1---sn-npoeenee.googlevideo.com.",
- "rr1---sn-npoeenek.googlevideo.com.",
"rr1---sn-npoeener.googlevideo.com.",
"rr1---sn-npoeeney.googlevideo.com.",
"rr1---sn-npoeenez.googlevideo.com.",
"rr1---sn-npoeenl7.googlevideo.com.",
+ "rr1---sn-npoeenl7.gvt1.com.",
"rr1---sn-npoeenle.googlevideo.com.",
+ "rr1---sn-npoeenlk.googlevideo.com.",
"rr1---sn-npoeenll.googlevideo.com.",
+ "rr1---sn-npoeenly.googlevideo.com.",
"rr1---sn-npoeens7.googlevideo.com.",
"rr1---sn-npoldn76.googlevideo.com.",
"rr1---sn-npoldn7d.googlevideo.com.",
"rr1---sn-npoldn7e.googlevideo.com.",
"rr1---sn-npoldn7l.googlevideo.com.",
"rr1---sn-npoldn7s.googlevideo.com.",
+ "rr1---sn-npoldn7s.gvt1.com.",
"rr1---sn-npoldn7y.googlevideo.com.",
"rr1---sn-npoldn7z.googlevideo.com.",
"rr1---sn-npoldne7.googlevideo.com.",
- "rr1---sn-ntqe6nel.googlevideo.com.",
- "rr1---sn-nuagpm-nuae.googlevideo.com.",
- "rr1---sn-nv0ui4gvou-hape.googlevideo.com.",
- "rr1---sn-nv0uixgo-5ual.googlevideo.com.",
"rr1---sn-nx57ynlk.googlevideo.com.",
"rr1---sn-nx57ynlk.gvt1.com.",
"rr1---sn-nx57ynsd.googlevideo.com.",
"rr1---sn-nx57ynsd.gvt1.com.",
- "rr1---sn-nx57ynse.googlevideo.com.",
"rr1---sn-nx57ynsk.googlevideo.com.",
"rr1---sn-nx57ynsk.gvt1.com.",
"rr1---sn-nx57ynsl.googlevideo.com.",
"rr1---sn-nx57ynsl.gvt1.com.",
"rr1---sn-nx57ynss.googlevideo.com.",
+ "rr1---sn-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-nx5s7n7z.googlevideo.com.",
"rr1---sn-nx5s7nee.googlevideo.com.",
- "rr1---sn-nx5s7nee.gvt1.com.",
"rr1---sn-nx5s7nel.googlevideo.com.",
"rr1---sn-o097znsd.googlevideo.com.",
"rr1---sn-o097znse.googlevideo.com.",
@@ -3961,10 +4112,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-o097znz7.googlevideo.com.",
"rr1---sn-o097znzd.googlevideo.com.",
"rr1---sn-o097znze.googlevideo.com.",
+ "rr1---sn-o097znze.gvt1.com.",
"rr1---sn-o097znzk.googlevideo.com.",
"rr1---sn-o097znzr.googlevideo.com.",
- "rr1---sn-opnq-n5ue.googlevideo.com.",
- "rr1---sn-ounjvhh-acce.googlevideo.com.",
+ "rr1---sn-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.",
@@ -3984,122 +4137,108 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-p5qlsny6.googlevideo.com.",
"rr1---sn-p5qs7n6d.googlevideo.com.",
"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-p5qs7nzy.googlevideo.com.",
- "rr1---sn-paapovpnjxou0gt-nual.googlevideo.com.",
"rr1---sn-pjnpu-5hfe.googlevideo.com.",
- "rr1---sn-pobpb-poql.googlevideo.com.",
"rr1---sn-q4fl6n66.googlevideo.com.",
- "rr1---sn-q4fl6n66.gvt1.com.",
"rr1---sn-q4fl6n6d.googlevideo.com.",
"rr1---sn-q4fl6n6r.googlevideo.com.",
"rr1---sn-q4fl6n6s.googlevideo.com.",
- "rr1---sn-q4fl6n6s.gvt1.com.",
"rr1---sn-q4fl6n6y.googlevideo.com.",
- "rr1---sn-q4fl6n6y.gvt1.com.",
"rr1---sn-q4fl6n6z.googlevideo.com.",
- "rr1---sn-q4fl6n6z.gvt1.com.",
"rr1---sn-q4fl6nd6.googlevideo.com.",
+ "rr1---sn-q4fl6nd6.gvt1.com.",
"rr1---sn-q4fl6nd7.googlevideo.com.",
- "rr1---sn-q4fl6nd7.gvt1.com.",
"rr1---sn-q4fl6nde.googlevideo.com.",
- "rr1---sn-q4fl6nde.gvt1.com.",
"rr1---sn-q4fl6ndl.googlevideo.com.",
"rr1---sn-q4fl6nds.googlevideo.com.",
"rr1---sn-q4fl6ndz.googlevideo.com.",
"rr1---sn-q4fl6nlz.googlevideo.com.",
"rr1---sn-q4fl6ns6.googlevideo.com.",
- "rr1---sn-q4fl6ns6.gvt1.com.",
- "rr1---sn-q4fl6ns7.googlevideo.com.",
"rr1---sn-q4fl6nsd.googlevideo.com.",
+ "rr1---sn-q4fl6nsk.googlevideo.com.",
+ "rr1---sn-q4fl6nsk.gvt1.com.",
"rr1---sn-q4fl6nsl.googlevideo.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-q4fl6nz7.googlevideo.com.",
"rr1---sn-q4fl6nzy.googlevideo.com.",
"rr1---sn-q4fl6nzy.gvt1.com.",
"rr1---sn-q4flrn7k.googlevideo.com.",
"rr1---sn-q4flrn7r.googlevideo.com.",
- "rr1---sn-q4flrn7r.gvt1.com.",
"rr1---sn-q4flrn7y.googlevideo.com.",
- "rr1---sn-q4flrn7y.gvt1.com.",
"rr1---sn-q4flrne6.googlevideo.com.",
"rr1---sn-q4flrne7.googlevideo.com.",
"rr1---sn-q4flrnee.googlevideo.com.",
"rr1---sn-q4flrnek.googlevideo.com.",
- "rr1---sn-q4flrnek.gvt1.com.",
"rr1---sn-q4flrnel.googlevideo.com.",
"rr1---sn-q4flrner.googlevideo.com.",
"rr1---sn-q4flrnes.googlevideo.com.",
"rr1---sn-q4flrney.googlevideo.com.",
"rr1---sn-q4flrnez.googlevideo.com.",
- "rr1---sn-q4flrnez.gvt1.com.",
"rr1---sn-q4flrnl6.googlevideo.com.",
- "rr1---sn-q4flrnl6.gvt1.com.",
"rr1---sn-q4flrnl7.googlevideo.com.",
"rr1---sn-q4flrnld.googlevideo.com.",
"rr1---sn-q4flrnle.googlevideo.com.",
- "rr1---sn-q4flrnle.gvt1.com.",
"rr1---sn-q4flrnlz.googlevideo.com.",
+ "rr1---sn-q4flrnlz.gvt1.com.",
"rr1---sn-q4flrnsd.googlevideo.com.",
"rr1---sn-q4flrnsk.googlevideo.com.",
- "rr1---sn-q4flrnsk.gvt1.com.",
"rr1---sn-q4flrnsl.googlevideo.com.",
"rr1---sn-q4flrnsl.gvt1.com.",
"rr1---sn-q4flrnss.googlevideo.com.",
+ "rr1---sn-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-q4fzen7y.googlevideo.com.",
- "rr1---sn-q4fzen7y.gvt1.com.",
"rr1---sn-q4fzene7.googlevideo.com.",
"rr1---sn-q4fzenee.googlevideo.com.",
+ "rr1---sn-qpbp-30ar.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-t0a7sn7d.googlevideo.com.",
- "rr1---sn-u1hp55-5c.googlevideo.com.",
- "rr1---sn-u1hp55-5c.gvt1.com.",
- "rr1---sn-uhvcpaxoa-5hne.googlevideo.com.",
- "rr1---sn-uhvcpaxoa-guhe.googlevideo.com.",
"rr1---sn-v53a5oqnji-4oul.googlevideo.com.",
- "rr1---sn-v5goxu-jhi6.googlevideo.com.",
- "rr1---sn-v5goxu-jhil.googlevideo.com.",
- "rr1---sn-v5goxu-jhiz.googlevideo.com.",
"rr1---sn-vgqskn66.googlevideo.com.",
"rr1---sn-vgqskn67.googlevideo.com.",
"rr1---sn-vgqskn6d.googlevideo.com.",
+ "rr1---sn-vgqskn6d.gvt1.com.",
"rr1---sn-vgqskn6s.googlevideo.com.",
"rr1---sn-vgqskn6z.googlevideo.com.",
"rr1---sn-vgqskne6.googlevideo.com.",
"rr1---sn-vgqskned.googlevideo.com.",
"rr1---sn-vgqsknek.googlevideo.com.",
- "rr1---sn-vgqsknek.gvt1.com.",
"rr1---sn-vgqsknes.googlevideo.com.",
"rr1---sn-vgqsknez.googlevideo.com.",
+ "rr1---sn-vgqsknld.googlevideo.com.",
"rr1---sn-vgqsknlk.googlevideo.com.",
"rr1---sn-vgqsknll.googlevideo.com.",
"rr1---sn-vgqsknlr.googlevideo.com.",
- "rr1---sn-vgqsknlr.gvt1.com.",
"rr1---sn-vgqsknls.googlevideo.com.",
+ "rr1---sn-vgqsknly.googlevideo.com.",
"rr1---sn-vgqsknlz.googlevideo.com.",
"rr1---sn-vgqsknse.googlevideo.com.",
+ "rr1---sn-vgqsknse.gvt1.com.",
"rr1---sn-vgqsknsk.googlevideo.com.",
+ "rr1---sn-vgqsknsk.gvt1.com.",
"rr1---sn-vgqsknz6.googlevideo.com.",
"rr1---sn-vgqsknz7.googlevideo.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-vgqsknzr.googlevideo.com.",
@@ -4113,11 +4252,11 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-vgqsrn6l.googlevideo.com.",
"rr1---sn-vgqsrn6l.gvt1.com.",
"rr1---sn-vgqsrn6z.googlevideo.com.",
- "rr1---sn-vgqsrn6z.gvt1.com.",
"rr1---sn-vgqsrne6.googlevideo.com.",
"rr1---sn-vgqsrned.googlevideo.com.",
"rr1---sn-vgqsrnek.googlevideo.com.",
"rr1---sn-vgqsrnes.googlevideo.com.",
+ "rr1---sn-vgqsrnes.gvt1.com.",
"rr1---sn-vgqsrnez.googlevideo.com.",
"rr1---sn-vgqsrnl6.googlevideo.com.",
"rr1---sn-vgqsrnld.googlevideo.com.",
@@ -4125,51 +4264,54 @@ var FakeECSFQDNs = container.NewMapSet(
"rr1---sn-vgqsrnlk.googlevideo.com.",
"rr1---sn-vgqsrnll.googlevideo.com.",
"rr1---sn-vgqsrnls.googlevideo.com.",
- "rr1---sn-vgqsrnls.gvt1.com.",
"rr1---sn-vgqsrnlz.googlevideo.com.",
"rr1---sn-vgqsrns6.googlevideo.com.",
"rr1---sn-vgqsrnsd.googlevideo.com.",
"rr1---sn-vgqsrnsr.googlevideo.com.",
+ "rr1---sn-vgqsrnsr.gvt1.com.",
"rr1---sn-vgqsrnsy.googlevideo.com.",
"rr1---sn-vgqsrnz6.googlevideo.com.",
- "rr1---sn-vgqsrnz6.gvt1.com.",
"rr1---sn-vgqsrnz7.googlevideo.com.",
- "rr1---sn-vgqsrnz7.gvt1.com.",
"rr1---sn-vgqsrnzd.googlevideo.com.",
"rr1---sn-vgqsrnzk.googlevideo.com.",
- "rr1---sn-vgqsrnzk.gvt1.com.",
"rr1---sn-vgqsrnzr.googlevideo.com.",
"rr1---sn-vgqsrnzs.googlevideo.com.",
"rr1---sn-vgqsrnzy.googlevideo.com.",
- "rr1---sn-vgqsrnzy.gvt1.com.",
"rr1---sn-vgqsrnzz.googlevideo.com.",
"rr1---sn-vgqsrnzz.gvt1.com.",
- "rr1---sn-vnix5o-28ql.googlevideo.com.",
"rr1---sn-voxoxu-v3jl.googlevideo.com.",
"rr1---sn-voxoxu-v3js.googlevideo.com.",
- "rr1---sn-xo5-co5l.googlevideo.com.",
- "rr1.sn-5hnekn7l.googlevideo.com.",
- "rr1.sn-q4fl6ndl.googlevideo.com.",
+ "rr1.sn-5hne6nsz.googlevideo.com.",
+ "rr1.sn-a5mekn6s.googlevideo.com.",
+ "rr1.sn-a5meknde.googlevideo.com.",
+ "rr1.sn-a5mekndz.googlevideo.com.",
+ "rr1.sn-a5meknzr.googlevideo.com.",
+ "rr1.sn-a5mlrnll.googlevideo.com.",
+ "rr1.sn-a5mlrnlz.googlevideo.com.",
+ "rr1.sn-hgn7yn7e.googlevideo.com.",
+ "rr1.sn-hp57knd6.googlevideo.com.",
+ "rr1.sn-hp57knds.googlevideo.com.",
+ "rr1.sn-hp57kndy.googlevideo.com.",
+ "rr1.sn-hp57ynlr.googlevideo.com.",
+ "rr1.sn-hp57ynse.googlevideo.com.",
+ "rr1.sn-q4fl6n66.googlevideo.com.",
+ "rr1.sn-q4fl6nd7.googlevideo.com.",
"rr1.sn-q4flrne7.googlevideo.com.",
- "rr1.sn-q4flrnss.googlevideo.com.",
- "rr1.sn-q4fzen7r.googlevideo.com.",
- "rr1.sn-q4fzenee.googlevideo.com.",
- "rr1.sn-t0a7sn7d.googlevideo.com.",
- "rr10---sn-bvvbax-2ial.googlevideo.com.",
+ "rr1.sn-q4flrnsl.googlevideo.com.",
+ "rr1.sn-q4fzen7y.googlevideo.com.",
+ "rr1.sn-t0a7lnee.googlevideo.com.",
+ "rr10---sn-8qj-i5ozd.googlevideo.com.",
+ "rr11---sn-2vgu0b5auxaxjvh-apnl.googlevideo.com.",
+ "rr11---sn-8qj-i5ozd.googlevideo.com.",
"rr11---sn-bvvbax-2ial.googlevideo.com.",
- "rr12---sn-bvvbax-2ial.googlevideo.com.",
- "rr2---sn-02o-ao3e.googlevideo.com.",
+ "rr12---sn-8qj-i5ozd.googlevideo.com.",
"rr2---sn-0nnpbo5a-bggl.googlevideo.com.",
"rr2---sn-0op8v4h5pox-cbgl.googlevideo.com.",
- "rr2---sn-2imern76.googlevideo.com.",
- "rr2---sn-2imern7d.googlevideo.com.",
- "rr2---sn-2imeyn7k.googlevideo.com.",
- "rr2---sn-2imeyn7k.gvt1.com.",
- "rr2---sn-2napbiu-p5ie.googlevideo.com.",
- "rr2---sn-2napbiu-p5ie.gvt1.com.",
- "rr2---sn-2pmxapm0n-gpje.googlevideo.com.",
- "rr2---sn-2pmxapm0n-gpjl.googlevideo.com.",
+ "rr2---sn-2aqu-hoaly.googlevideo.com.",
+ "rr2---sn-2aqu-hoas7.googlevideo.com.",
+ "rr2---sn-2oaig5-55.googlevideo.com.",
"rr2---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr2---sn-2vgu0b5auxaxjvh-apnz.googlevideo.com.",
"rr2---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
"rr2---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
"rr2---sn-2vgu0b5auxaxjvh-v2vk.googlevideo.com.",
@@ -4183,8 +4325,10 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-30a7yney.googlevideo.com.",
"rr2---sn-30a7ynl7.googlevideo.com.",
"rr2---sn-3jpm-hjpe.googlevideo.com.",
- "rr2---sn-3n4pcxg-pjul.googlevideo.com.",
"rr2---sn-3n4pcxg-pjuz.googlevideo.com.",
+ "rr2---sn-42u-nboze.googlevideo.com.",
+ "rr2---sn-42u-nbozl.googlevideo.com.",
+ "rr2---sn-42u-nbozs.googlevideo.com.",
"rr2---sn-4g5e6ns6.googlevideo.com.",
"rr2---sn-4g5e6ns7.googlevideo.com.",
"rr2---sn-4g5e6nsd.googlevideo.com.",
@@ -4235,10 +4379,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-4g5lznle.googlevideo.com.",
"rr2---sn-4g5lznls.googlevideo.com.",
"rr2---sn-4g5lznlz.googlevideo.com.",
- "rr2---sn-4pgnuapbiu-hiul.googlevideo.com.",
- "rr2---sn-5gxo-in8l.googlevideo.com.",
- "rr2---sn-5gxo-in8s.googlevideo.com.",
+ "rr2---sn-4jjo-apnl.googlevideo.com.",
"rr2---sn-5hne6n6e.googlevideo.com.",
+ "rr2---sn-5hne6n6e.gvt1.com.",
"rr2---sn-5hne6n6l.googlevideo.com.",
"rr2---sn-5hne6ns6.googlevideo.com.",
"rr2---sn-5hne6nsd.googlevideo.com.",
@@ -4252,35 +4395,33 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-5hne6nzs.googlevideo.com.",
"rr2---sn-5hne6nzy.googlevideo.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-5hnekn7k.googlevideo.com.",
"rr2---sn-5hnekn7l.googlevideo.com.",
"rr2---sn-5hnekn7s.googlevideo.com.",
"rr2---sn-5hnekn7z.googlevideo.com.",
"rr2---sn-5hneknee.googlevideo.com.",
"rr2---sn-5hneknek.googlevideo.com.",
"rr2---sn-5hneknes.googlevideo.com.",
+ "rr2---sn-5pgnugx5h-hn2s.googlevideo.com.",
"rr2---sn-5pgnugx5h-hn2z.googlevideo.com.",
"rr2---sn-5uaezndd.googlevideo.com.",
"rr2---sn-5uaezne6.googlevideo.com.",
"rr2---sn-5uaezned.googlevideo.com.",
+ "rr2---sn-5uaeznes.googlevideo.com.",
"rr2---sn-5uaeznez.googlevideo.com.",
"rr2---sn-5uaeznl6.googlevideo.com.",
"rr2---sn-5uaeznld.googlevideo.com.",
- "rr2---sn-5uaeznly.googlevideo.com.",
"rr2---sn-5uaeznlz.googlevideo.com.",
- "rr2---sn-5uaeznrz.googlevideo.com.",
"rr2---sn-5uaezns7.googlevideo.com.",
"rr2---sn-5uaeznse.googlevideo.com.",
"rr2---sn-5uaeznsl.googlevideo.com.",
"rr2---sn-5uaeznss.googlevideo.com.",
"rr2---sn-5uaezny6.googlevideo.com.",
- "rr2---sn-5uaeznys.googlevideo.com.",
- "rr2---sn-5uaeznyz.googlevideo.com.",
"rr2---sn-5uaeznze.googlevideo.com.",
- "rr2---sn-5ualdnle.googlevideo.com.",
"rr2---sn-5ualdnll.googlevideo.com.",
"rr2---sn-5ualdnlr.googlevideo.com.",
"rr2---sn-5ualdnls.googlevideo.com.",
@@ -4296,12 +4437,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-5ualdnsz.googlevideo.com.",
"rr2---sn-5ualdnz7.googlevideo.com.",
"rr2---sn-5ualdnze.googlevideo.com.",
- "rr2---sn-8qj-i5ody.googlevideo.com.",
+ "rr2---sn-8qj-i5o6k.googlevideo.com.",
"rr2---sn-8qj-i5okl.googlevideo.com.",
+ "rr2---sn-8qj-i5ozd.googlevideo.com.",
"rr2---sn-8qj-nbo66.googlevideo.com.",
"rr2---sn-8qj-nbo6y.googlevideo.com.",
"rr2---sn-8xgp1vo-2iae.googlevideo.com.",
- "rr2---sn-8xgp1vo-2iae7.googlevideo.com.",
"rr2---sn-8xgp1vo-2ial.googlevideo.com.",
"rr2---sn-8xgp1vo-2iay.googlevideo.com.",
"rr2---sn-8xgp1vo-ab56.googlevideo.com.",
@@ -4310,8 +4451,10 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-8xgp1vo-ab5l.googlevideo.com.",
"rr2---sn-8xgp1vo-ab5s.googlevideo.com.",
"rr2---sn-8xgp1vo-ab5z.googlevideo.com.",
+ "rr2---sn-8xgp1vo-hjpl.googlevideo.com.",
"rr2---sn-8xgp1vo-nh4e.googlevideo.com.",
"rr2---sn-8xgp1vo-p5ie.googlevideo.com.",
+ "rr2---sn-8xgp1vo-poql.googlevideo.com.",
"rr2---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr2---sn-8xgp1vo-xfge.googlevideo.com.",
"rr2---sn-8xgp1vo-xfgl.googlevideo.com.",
@@ -4320,13 +4463,13 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-9gv76n7s.googlevideo.com.",
"rr2---sn-9gv76n7z.googlevideo.com.",
"rr2---sn-9gv7ene6.googlevideo.com.",
+ "rr2---sn-9gv7ened.googlevideo.com.",
"rr2---sn-9gv7zn76.googlevideo.com.",
"rr2---sn-9gv7zn7e.googlevideo.com.",
"rr2---sn-9gv7zn7r.googlevideo.com.",
- "rr2---sn-9gv7zn7y.googlevideo.com.",
"rr2---sn-a5m7lnl6.googlevideo.com.",
- "rr2---sn-a5m7lnl6.gvt1.com.",
"rr2---sn-a5m7lnld.googlevideo.com.",
+ "rr2---sn-a5m7lnld.gvt1.com.",
"rr2---sn-a5mekn6d.googlevideo.com.",
"rr2---sn-a5mekn6k.googlevideo.com.",
"rr2---sn-a5mekn6k.gvt1.com.",
@@ -4335,84 +4478,93 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-a5mekn6r.gvt1.com.",
"rr2---sn-a5mekn6s.googlevideo.com.",
"rr2---sn-a5mekn6z.googlevideo.com.",
+ "rr2---sn-a5mekn6z.gvt1.com.",
"rr2---sn-a5meknd6.googlevideo.com.",
+ "rr2---sn-a5meknd6.gvt1.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.",
- "rr2---sn-a5meknds.gvt1.com.",
"rr2---sn-a5mekndz.googlevideo.com.",
"rr2---sn-a5meknsd.googlevideo.com.",
- "rr2---sn-a5meknsd.gvt1.com.",
"rr2---sn-a5meknsy.googlevideo.com.",
"rr2---sn-a5meknzk.googlevideo.com.",
"rr2---sn-a5meknzl.googlevideo.com.",
"rr2---sn-a5meknzr.googlevideo.com.",
+ "rr2---sn-a5meknzs.googlevideo.com.",
"rr2---sn-a5mlrnek.googlevideo.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-a5mlrnls.gvt1.com.",
"rr2---sn-a5mlrnlz.googlevideo.com.",
- "rr2---sn-a5msen76.googlevideo.com.",
"rr2---sn-a5msen7l.googlevideo.com.",
"rr2---sn-a5msen7s.googlevideo.com.",
- "rr2---sn-a5msen7s.gvt1.com.",
"rr2---sn-a5msen7z.googlevideo.com.",
"rr2---sn-a5msenek.googlevideo.com.",
"rr2---sn-a5msener.googlevideo.com.",
"rr2---sn-a5msener.gvt1.com.",
"rr2---sn-a5msenes.googlevideo.com.",
+ "rr2---sn-a5msenes.gvt1.com.",
"rr2---sn-a5msenl7.googlevideo.com.",
"rr2---sn-a5msenle.googlevideo.com.",
"rr2---sn-a5msenll.googlevideo.com.",
"rr2---sn-ab5l6ndr.googlevideo.com.",
"rr2---sn-ab5l6ndy.googlevideo.com.",
+ "rr2---sn-ab5l6ndy.gvt1.com.",
"rr2---sn-ab5l6nk6.googlevideo.com.",
"rr2---sn-ab5l6nk6.gvt1.com.",
"rr2---sn-ab5l6nkd.googlevideo.com.",
- "rr2---sn-ab5l6nkd.gvt1.com.",
"rr2---sn-ab5l6nr6.googlevideo.com.",
+ "rr2---sn-ab5l6nr6.gvt1.com.",
"rr2---sn-ab5l6nrd.googlevideo.com.",
"rr2---sn-ab5l6nrk.googlevideo.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-ab5sznld.gvt1.com.",
"rr2---sn-ab5sznlk.googlevideo.com.",
+ "rr2---sn-ab5sznlk.gvt1.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-ab5sznze.gvt1.com.",
"rr2---sn-ab5sznzk.googlevideo.com.",
"rr2---sn-ab5sznzk.gvt1.com.",
"rr2---sn-ab5sznzl.googlevideo.com.",
+ "rr2---sn-ab5sznzl.gvt1.com.",
"rr2---sn-ab5sznzr.googlevideo.com.",
"rr2---sn-ab5sznzs.googlevideo.com.",
- "rr2---sn-ab5sznzs.gvt1.com.",
"rr2---sn-ab5sznzy.googlevideo.com.",
"rr2---sn-ab5sznzz.googlevideo.com.",
+ "rr2---sn-ab5sznzz.gvt1.com.",
"rr2---sn-aigl6n6s.googlevideo.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-aigl6nsk.googlevideo.com.",
+ "rr2---sn-aigl6nsk.gvt1.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.",
@@ -4428,60 +4580,58 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-aigzrnsz.googlevideo.com.",
"rr2---sn-aigzrnz7.googlevideo.com.",
"rr2---sn-aigzrnze.googlevideo.com.",
- "rr2---sn-apn7en7e.googlevideo.com.",
"rr2---sn-apn7en7l.googlevideo.com.",
"rr2---sn-apn7en7s.googlevideo.com.",
- "rr2---sn-bg5oqxjvh-50nz.googlevideo.com.",
- "rr2---sn-bg5oqxjvh-jg2s.googlevideo.com.",
- "rr2---sn-bg5oqxjvh-xa2s.googlevideo.com.",
+ "rr2---sn-avbpj-cq5e.googlevideo.com.",
"rr2---sn-cvb7lne7.googlevideo.com.",
"rr2---sn-cvb7lnee.googlevideo.com.",
+ "rr2---sn-cvb7lnls.googlevideo.com.",
"rr2---sn-cvb7lnlz.googlevideo.com.",
"rr2---sn-cvb7sn7k.googlevideo.com.",
"rr2---sn-cvb7sn7r.googlevideo.com.",
- "rr2---sn-fpnjoxu-h3xl.googlevideo.com.",
- "rr2---sn-fpnjoxu-hnol.googlevideo.com.",
- "rr2---sn-h0jeener.googlevideo.com.",
"rr2---sn-h0jeenl6.googlevideo.com.",
- "rr2---sn-h0jeenld.googlevideo.com.",
"rr2---sn-h0jeenle.googlevideo.com.",
"rr2---sn-h0jelne6.googlevideo.com.",
- "rr2---sn-h0jelnes.googlevideo.com.",
- "rr2---sn-h0jelnez.googlevideo.com.",
- "rr2---sn-hgn7yn7l.googlevideo.com.",
"rr2---sn-hjoj-gq0l.googlevideo.com.",
- "rr2---sn-hjoj-gq0l.gvt1.com.",
- "rr2---sn-hjoj-jaul.googlevideo.com.",
- "rr2---sn-hjoj-poul.googlevideo.com.",
"rr2---sn-hoa7kn76.googlevideo.com.",
"rr2---sn-hoa7kn7z.googlevideo.com.",
"rr2---sn-hoa7rn76.googlevideo.com.",
"rr2---sn-hoa7rn7z.googlevideo.com.",
- "rr2---sn-hp57kn6y.googlevideo.com.",
+ "rr2---sn-hp57kn6r.googlevideo.com.",
+ "rr2---sn-hp57kn6r.gvt1.com.",
"rr2---sn-hp57knd6.googlevideo.com.",
"rr2---sn-hp57knd6.gvt1.com.",
"rr2---sn-hp57kndd.googlevideo.com.",
+ "rr2---sn-hp57kndd.gvt1.com.",
"rr2---sn-hp57kndk.googlevideo.com.",
- "rr2---sn-hp57kndk.gvt1.com.",
"rr2---sn-hp57kndr.googlevideo.com.",
"rr2---sn-hp57kndr.gvt1.com.",
"rr2---sn-hp57knds.googlevideo.com.",
+ "rr2---sn-hp57knds.gvt1.com.",
"rr2---sn-hp57kndy.googlevideo.com.",
+ "rr2---sn-hp57kndy.gvt1.com.",
"rr2---sn-hp57kndz.googlevideo.com.",
"rr2---sn-hp57kndz.gvt1.com.",
"rr2---sn-hp57yn7r.googlevideo.com.",
+ "rr2---sn-hp57yn7r.gvt1.com.",
"rr2---sn-hp57yn7y.googlevideo.com.",
"rr2---sn-hp57yne7.googlevideo.com.",
"rr2---sn-hp57ynee.googlevideo.com.",
+ "rr2---sn-hp57ynee.gvt1.com.",
"rr2---sn-hp57ynl6.googlevideo.com.",
+ "rr2---sn-hp57ynl6.gvt1.com.",
"rr2---sn-hp57ynlr.googlevideo.com.",
"rr2---sn-hp57ynlr.gvt1.com.",
"rr2---sn-hp57ynly.googlevideo.com.",
"rr2---sn-hp57yns7.googlevideo.com.",
+ "rr2---sn-hp57yns7.gvt1.com.",
"rr2---sn-hp57ynse.googlevideo.com.",
+ "rr2---sn-hp57ynse.gvt1.com.",
"rr2---sn-hp57ynsl.googlevideo.com.",
+ "rr2---sn-hp57ynsl.gvt1.com.",
"rr2---sn-hp57ynss.googlevideo.com.",
- "rr2---sn-hxgpu-qufs.googlevideo.com.",
+ "rr2---sn-hp57ynss.gvt1.com.",
+ "rr2---sn-hxugvoxupoj-poqz.googlevideo.com.",
"rr2---sn-i3b7kn6s.googlevideo.com.",
"rr2---sn-i3b7knld.googlevideo.com.",
"rr2---sn-i3b7knlk.googlevideo.com.",
@@ -4491,18 +4641,17 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-i3b7knsl.googlevideo.com.",
"rr2---sn-i3b7knzl.googlevideo.com.",
"rr2---sn-i3b7knzs.googlevideo.com.",
- "rr2---sn-i3belne6.googlevideo.com.",
+ "rr2---sn-i3belney.googlevideo.com.",
"rr2---sn-i3belnl6.googlevideo.com.",
"rr2---sn-i3belnl7.googlevideo.com.",
"rr2---sn-i3belnll.googlevideo.com.",
"rr2---sn-i3belnls.googlevideo.com.",
"rr2---sn-i3belnlz.googlevideo.com.",
"rr2---sn-i3bssn7e.googlevideo.com.",
- "rr2---sn-i5f5ppuxa-ioal.googlevideo.com.",
- "rr2---sn-i5goxu-i3bl.googlevideo.com.",
"rr2---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
"rr2---sn-jvhj5nu-2iae.googlevideo.com.",
"rr2---sn-jvhj5nu-2ial.googlevideo.com.",
+ "rr2---sn-jvhj5nu-2ias.googlevideo.com.",
"rr2---sn-jvhj5nu-nh4e.googlevideo.com.",
"rr2---sn-jvhj5nu-nh4l.googlevideo.com.",
"rr2---sn-jvhj5nu-nh4s.googlevideo.com.",
@@ -4511,27 +4660,21 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-jvhj5nu-qufl.googlevideo.com.",
"rr2---sn-jvhj5nu-qufs.googlevideo.com.",
"rr2---sn-jvhj5nu-qufz.googlevideo.com.",
- "rr2---sn-jxopj-n5oe.googlevideo.com.",
- "rr2---sn-jxopj-n5oe.gvt1.com.",
+ "rr2---sn-jvooxqouf3-cqaz.googlevideo.com.",
"rr2---sn-jxopj-nh4e.googlevideo.com.",
"rr2---sn-jxopj-nh4e.gvt1.com.",
- "rr2---sn-muxa-2iae.googlevideo.com.",
- "rr2---sn-n0g45pg-ncoe.googlevideo.com.",
- "rr2---sn-n2uxaxjvh-j5xl.googlevideo.com.",
- "rr2---sn-n2uxaxjvh-j5xl.gvt1.com.",
"rr2---sn-n2uxaxjvh-j5xs.googlevideo.com.",
- "rr2---sn-n2uxaxjvh-j5xs.gvt1.com.",
"rr2---sn-n4v7snee.googlevideo.com.",
"rr2---sn-n4v7sney.googlevideo.com.",
"rr2---sn-n4v7snl7.googlevideo.com.",
"rr2---sn-n4v7snll.googlevideo.com.",
+ "rr2---sn-n4v7snll.gvt1.com.",
"rr2---sn-n4v7snlr.googlevideo.com.",
"rr2---sn-n4v7snls.googlevideo.com.",
"rr2---sn-n4v7snly.googlevideo.com.",
"rr2---sn-n4v7sns7.googlevideo.com.",
"rr2---sn-n4v7snse.googlevideo.com.",
"rr2---sn-nh5gujvh-h4xe.googlevideo.com.",
- "rr2---sn-nh5gujvh-h4xe.gvt1.com.",
"rr2---sn-npoe7ndl.googlevideo.com.",
"rr2---sn-npoe7nds.googlevideo.com.",
"rr2---sn-npoe7ne6.googlevideo.com.",
@@ -4544,11 +4687,10 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-npoe7nez.googlevideo.com.",
"rr2---sn-npoe7nl6.googlevideo.com.",
"rr2---sn-npoe7nlz.googlevideo.com.",
- "rr2---sn-npoe7ns6.googlevideo.com.",
"rr2---sn-npoe7ns7.googlevideo.com.",
+ "rr2---sn-npoe7ns7.gvt1.com.",
"rr2---sn-npoe7nsd.googlevideo.com.",
"rr2---sn-npoe7nsk.googlevideo.com.",
- "rr2---sn-npoe7nsl.googlevideo.com.",
"rr2---sn-npoe7nsr.googlevideo.com.",
"rr2---sn-npoe7nss.googlevideo.com.",
"rr2---sn-npoe7nsy.googlevideo.com.",
@@ -4556,6 +4698,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-npoeene6.googlevideo.com.",
"rr2---sn-npoeened.googlevideo.com.",
"rr2---sn-npoeenee.googlevideo.com.",
+ "rr2---sn-npoeenee.gvt1.com.",
+ "rr2---sn-npoeenek.googlevideo.com.",
"rr2---sn-npoeener.googlevideo.com.",
"rr2---sn-npoeeney.googlevideo.com.",
"rr2---sn-npoeenez.googlevideo.com.",
@@ -4563,38 +4707,37 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-npoeenle.googlevideo.com.",
"rr2---sn-npoeenlk.googlevideo.com.",
"rr2---sn-npoeenll.googlevideo.com.",
+ "rr2---sn-npoeenly.googlevideo.com.",
"rr2---sn-npoeens7.googlevideo.com.",
"rr2---sn-npoldn76.googlevideo.com.",
"rr2---sn-npoldn7d.googlevideo.com.",
+ "rr2---sn-npoldn7e.googlevideo.com.",
"rr2---sn-npoldn7l.googlevideo.com.",
"rr2---sn-npoldn7s.googlevideo.com.",
+ "rr2---sn-npoldn7s.gvt1.com.",
"rr2---sn-npoldn7y.googlevideo.com.",
"rr2---sn-npoldn7z.googlevideo.com.",
"rr2---sn-npoldne7.googlevideo.com.",
- "rr2---sn-nuagpm-nuae.googlevideo.com.",
- "rr2---sn-nv0ui4gvou-hape.googlevideo.com.",
- "rr2---sn-nv0uixgo-5ual.googlevideo.com.",
- "rr2---sn-nx57ynlk.googlevideo.com.",
- "rr2---sn-nx57ynlk.gvt1.com.",
+ "rr2---sn-ntqe6n76.googlevideo.com.",
"rr2---sn-nx57ynsd.googlevideo.com.",
"rr2---sn-nx57ynsd.gvt1.com.",
+ "rr2---sn-nx57ynse.googlevideo.com.",
"rr2---sn-nx57ynsk.googlevideo.com.",
"rr2---sn-nx57ynsk.gvt1.com.",
"rr2---sn-nx57ynsl.googlevideo.com.",
- "rr2---sn-nx57ynsl.gvt1.com.",
"rr2---sn-nx57ynss.googlevideo.com.",
"rr2---sn-nx57ynss.gvt1.com.",
"rr2---sn-nx57ynsz.googlevideo.com.",
"rr2---sn-nx57ynsz.gvt1.com.",
"rr2---sn-nx5s7n76.googlevideo.com.",
"rr2---sn-nx5s7n7d.googlevideo.com.",
- "rr2---sn-nx5s7n7d.gvt1.com.",
"rr2---sn-nx5s7n7y.googlevideo.com.",
"rr2---sn-nx5s7n7z.googlevideo.com.",
"rr2---sn-nx5s7nee.googlevideo.com.",
- "rr2---sn-nx5s7nee.gvt1.com.",
+ "rr2---sn-nx5s7nel.googlevideo.com.",
"rr2---sn-o097znsd.googlevideo.com.",
"rr2---sn-o097znse.googlevideo.com.",
+ "rr2---sn-o097znsk.googlevideo.com.",
"rr2---sn-o097znsl.googlevideo.com.",
"rr2---sn-o097znsr.googlevideo.com.",
"rr2---sn-o097znss.googlevideo.com.",
@@ -4604,8 +4747,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-o097znze.googlevideo.com.",
"rr2---sn-o097znzk.googlevideo.com.",
"rr2---sn-o097znzr.googlevideo.com.",
- "rr2---sn-opnq-n5ue.googlevideo.com.",
- "rr2---sn-ounjvhh-acce.googlevideo.com.",
"rr2---sn-oxgpj-5ace.googlevideo.com.",
"rr2---sn-p5qddn76.googlevideo.com.",
"rr2---sn-p5qddn7d.googlevideo.com.",
@@ -4619,151 +4760,127 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-p5qlsn7s.googlevideo.com.",
"rr2---sn-p5qlsnd6.googlevideo.com.",
"rr2---sn-p5qlsndd.googlevideo.com.",
+ "rr2---sn-p5qlsndr.googlevideo.com.",
"rr2---sn-p5qlsndz.googlevideo.com.",
"rr2---sn-p5qlsnrl.googlevideo.com.",
"rr2---sn-p5qlsnrr.googlevideo.com.",
"rr2---sn-p5qlsny6.googlevideo.com.",
"rr2---sn-p5qs7n6d.googlevideo.com.",
"rr2---sn-p5qs7nsk.googlevideo.com.",
+ "rr2---sn-p5qs7nsk.gvt1.com.",
"rr2---sn-p5qs7nsr.googlevideo.com.",
"rr2---sn-p5qs7nzk.googlevideo.com.",
"rr2---sn-p5qs7nzr.googlevideo.com.",
"rr2---sn-p5qs7nzy.googlevideo.com.",
- "rr2---sn-paapovpnjxou0gt-nual.googlevideo.com.",
"rr2---sn-pjnpu-5hfe.googlevideo.com.",
- "rr2---sn-pobpb-poql.googlevideo.com.",
"rr2---sn-q4fl6n66.googlevideo.com.",
"rr2---sn-q4fl6n6d.googlevideo.com.",
- "rr2---sn-q4fl6n6d.gvt1.com.",
"rr2---sn-q4fl6n6r.googlevideo.com.",
"rr2---sn-q4fl6n6r.gvt1.com.",
"rr2---sn-q4fl6n6s.googlevideo.com.",
"rr2---sn-q4fl6n6y.googlevideo.com.",
- "rr2---sn-q4fl6n6y.gvt1.com.",
"rr2---sn-q4fl6n6z.googlevideo.com.",
"rr2---sn-q4fl6nd6.googlevideo.com.",
"rr2---sn-q4fl6nd7.googlevideo.com.",
"rr2---sn-q4fl6nd7.gvt1.com.",
"rr2---sn-q4fl6nde.googlevideo.com.",
+ "rr2---sn-q4fl6nde.gvt1.com.",
"rr2---sn-q4fl6ndl.googlevideo.com.",
"rr2---sn-q4fl6nds.googlevideo.com.",
+ "rr2---sn-q4fl6nds.gvt1.com.",
"rr2---sn-q4fl6ndz.googlevideo.com.",
- "rr2---sn-q4fl6ndz.gvt1.com.",
- "rr2---sn-q4fl6nlz.googlevideo.com.",
"rr2---sn-q4fl6ns6.googlevideo.com.",
- "rr2---sn-q4fl6ns6.gvt1.com.",
"rr2---sn-q4fl6ns7.googlevideo.com.",
- "rr2---sn-q4fl6ns7.gvt1.com.",
"rr2---sn-q4fl6nsd.googlevideo.com.",
"rr2---sn-q4fl6nsd.gvt1.com.",
"rr2---sn-q4fl6nsk.googlevideo.com.",
"rr2---sn-q4fl6nsk.gvt1.com.",
"rr2---sn-q4fl6nsl.googlevideo.com.",
"rr2---sn-q4fl6nsr.googlevideo.com.",
- "rr2---sn-q4fl6nsr.gvt1.com.",
"rr2---sn-q4fl6nss.googlevideo.com.",
"rr2---sn-q4fl6nsy.googlevideo.com.",
- "rr2---sn-q4fl6nsy.gvt1.com.",
"rr2---sn-q4fl6nz6.googlevideo.com.",
"rr2---sn-q4fl6nz6.gvt1.com.",
"rr2---sn-q4fl6nz7.googlevideo.com.",
- "rr2---sn-q4fl6nz7.gvt1.com.",
"rr2---sn-q4fl6nzy.googlevideo.com.",
- "rr2---sn-q4fl6nzy.gvt1.com.",
"rr2---sn-q4flrn7k.googlevideo.com.",
"rr2---sn-q4flrn7r.googlevideo.com.",
- "rr2---sn-q4flrn7r.gvt1.com.",
"rr2---sn-q4flrn7y.googlevideo.com.",
"rr2---sn-q4flrne6.googlevideo.com.",
"rr2---sn-q4flrne7.googlevideo.com.",
- "rr2---sn-q4flrne7.gvt1.com.",
"rr2---sn-q4flrnee.googlevideo.com.",
- "rr2---sn-q4flrnee.gvt1.com.",
"rr2---sn-q4flrnek.googlevideo.com.",
"rr2---sn-q4flrnel.googlevideo.com.",
+ "rr2---sn-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-q4flrnez.googlevideo.com.",
- "rr2---sn-q4flrnez.gvt1.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-q4flrnlz.googlevideo.com.",
- "rr2---sn-q4flrnlz.gvt1.com.",
"rr2---sn-q4flrnsd.googlevideo.com.",
+ "rr2---sn-q4flrnsd.gvt1.com.",
"rr2---sn-q4flrnsk.googlevideo.com.",
- "rr2---sn-q4flrnsk.gvt1.com.",
"rr2---sn-q4flrnsl.googlevideo.com.",
- "rr2---sn-q4flrnsl.gvt1.com.",
"rr2---sn-q4flrnss.googlevideo.com.",
"rr2---sn-q4fzen7e.googlevideo.com.",
+ "rr2---sn-q4fzen7e.gvt1.com.",
"rr2---sn-q4fzen7l.googlevideo.com.",
+ "rr2---sn-q4fzen7l.gvt1.com.",
"rr2---sn-q4fzen7r.googlevideo.com.",
- "rr2---sn-q4fzen7r.gvt1.com.",
"rr2---sn-q4fzen7s.googlevideo.com.",
"rr2---sn-q4fzen7y.googlevideo.com.",
"rr2---sn-q4fzene7.googlevideo.com.",
+ "rr2---sn-q4fzene7.gvt1.com.",
"rr2---sn-q4fzenee.googlevideo.com.",
- "rr2---sn-q4fzenee.gvt1.com.",
"rr2---sn-qxo7rn7k.googlevideo.com.",
"rr2---sn-qxo7rn7r.googlevideo.com.",
"rr2---sn-qxo7rn7y.googlevideo.com.",
"rr2---sn-qxoedn7k.googlevideo.com.",
"rr2---sn-qxoedne7.googlevideo.com.",
"rr2---sn-qxoednee.googlevideo.com.",
- "rr2---sn-u1hp55-5c.googlevideo.com.",
- "rr2---sn-u1hp55-5c.gvt1.com.",
- "rr2---sn-uhvcpaxoa-5hne.googlevideo.com.",
- "rr2---sn-uhvcpaxoa-guhe.googlevideo.com.",
- "rr2---sn-v53a5oqnji-4oul.googlevideo.com.",
- "rr2---sn-v5goxu-jhi6.googlevideo.com.",
- "rr2---sn-v5goxu-jhi6.gvt1.com.",
- "rr2---sn-v5goxu-jhil.googlevideo.com.",
- "rr2---sn-v5goxu-jhiz.googlevideo.com.",
"rr2---sn-vgqskn66.googlevideo.com.",
"rr2---sn-vgqskn67.googlevideo.com.",
+ "rr2---sn-vgqskn67.gvt1.com.",
"rr2---sn-vgqskn6d.googlevideo.com.",
"rr2---sn-vgqskn6s.googlevideo.com.",
"rr2---sn-vgqskn6z.googlevideo.com.",
"rr2---sn-vgqskne6.googlevideo.com.",
"rr2---sn-vgqskned.googlevideo.com.",
"rr2---sn-vgqsknek.googlevideo.com.",
- "rr2---sn-vgqsknek.gvt1.com.",
"rr2---sn-vgqsknes.googlevideo.com.",
"rr2---sn-vgqsknez.googlevideo.com.",
- "rr2---sn-vgqsknez.gvt1.com.",
"rr2---sn-vgqsknld.googlevideo.com.",
- "rr2---sn-vgqsknld.gvt1.com.",
"rr2---sn-vgqsknlk.googlevideo.com.",
- "rr2---sn-vgqsknll.googlevideo.com.",
+ "rr2---sn-vgqsknlr.googlevideo.com.",
"rr2---sn-vgqsknls.googlevideo.com.",
"rr2---sn-vgqsknlz.googlevideo.com.",
"rr2---sn-vgqskns7.googlevideo.com.",
"rr2---sn-vgqsknse.googlevideo.com.",
+ "rr2---sn-vgqsknse.gvt1.com.",
"rr2---sn-vgqsknsk.googlevideo.com.",
"rr2---sn-vgqsknz6.googlevideo.com.",
"rr2---sn-vgqsknz7.googlevideo.com.",
"rr2---sn-vgqsknzd.googlevideo.com.",
"rr2---sn-vgqsknze.googlevideo.com.",
+ "rr2---sn-vgqsknze.gvt1.com.",
"rr2---sn-vgqsknzk.googlevideo.com.",
"rr2---sn-vgqsknzl.googlevideo.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-vgqsrn67.googlevideo.com.",
"rr2---sn-vgqsrn6e.googlevideo.com.",
"rr2---sn-vgqsrn6l.googlevideo.com.",
- "rr2---sn-vgqsrn6l.gvt1.com.",
"rr2---sn-vgqsrn6z.googlevideo.com.",
"rr2---sn-vgqsrne6.googlevideo.com.",
- "rr2---sn-vgqsrned.googlevideo.com.",
"rr2---sn-vgqsrnek.googlevideo.com.",
"rr2---sn-vgqsrnes.googlevideo.com.",
"rr2---sn-vgqsrnez.googlevideo.com.",
@@ -4771,40 +4888,50 @@ var FakeECSFQDNs = container.NewMapSet(
"rr2---sn-vgqsrnld.googlevideo.com.",
"rr2---sn-vgqsrnlk.googlevideo.com.",
"rr2---sn-vgqsrnll.googlevideo.com.",
+ "rr2---sn-vgqsrnll.gvt1.com.",
"rr2---sn-vgqsrnls.googlevideo.com.",
"rr2---sn-vgqsrnls.gvt1.com.",
"rr2---sn-vgqsrnlz.googlevideo.com.",
"rr2---sn-vgqsrns6.googlevideo.com.",
+ "rr2---sn-vgqsrns6.gvt1.com.",
"rr2---sn-vgqsrnsd.googlevideo.com.",
+ "rr2---sn-vgqsrnsd.gvt1.com.",
"rr2---sn-vgqsrnsr.googlevideo.com.",
"rr2---sn-vgqsrnsy.googlevideo.com.",
- "rr2---sn-vgqsrnsy.gvt1.com.",
"rr2---sn-vgqsrnz6.googlevideo.com.",
+ "rr2---sn-vgqsrnz6.gvt1.com.",
"rr2---sn-vgqsrnz7.googlevideo.com.",
"rr2---sn-vgqsrnzd.googlevideo.com.",
+ "rr2---sn-vgqsrnzd.gvt1.com.",
"rr2---sn-vgqsrnzk.googlevideo.com.",
- "rr2---sn-vgqsrnzk.gvt1.com.",
"rr2---sn-vgqsrnzr.googlevideo.com.",
"rr2---sn-vgqsrnzs.googlevideo.com.",
"rr2---sn-vgqsrnzy.googlevideo.com.",
"rr2---sn-vgqsrnzz.googlevideo.com.",
- "rr2---sn-vnix5o-28ql.googlevideo.com.",
+ "rr2---sn-vgqsrnzz.gvt1.com.",
+ "rr2---sn-voxoxu-v3jl.googlevideo.com.",
"rr2---sn-voxoxu-v3js.googlevideo.com.",
- "rr2---sn-xo5-co5l.googlevideo.com.",
- "rr2.sn-5hnekn7d.googlevideo.com.",
+ "rr2.sn-4g5edn6r.googlevideo.com.",
+ "rr2.sn-5hnekn7z.googlevideo.com.",
+ "rr2.sn-a5mekn6s.googlevideo.com.",
+ "rr2.sn-a5meknde.googlevideo.com.",
"rr2.sn-a5mekndz.googlevideo.com.",
"rr2.sn-a5meknzr.googlevideo.com.",
- "rr2.sn-q4fl6n6y.googlevideo.com.",
- "rr2.sn-q4fl6nsk.googlevideo.com.",
+ "rr2.sn-a5mlrnll.googlevideo.com.",
+ "rr2.sn-a5mlrnlz.googlevideo.com.",
+ "rr2.sn-aigl6nze.googlevideo.com.",
+ "rr2.sn-hp57knd6.googlevideo.com.",
+ "rr2.sn-hp57knds.googlevideo.com.",
+ "rr2.sn-hp57kndy.googlevideo.com.",
+ "rr2.sn-hp57ynl6.googlevideo.com.",
+ "rr2.sn-hp57ynse.googlevideo.com.",
+ "rr2.sn-q4fl6nz6.googlevideo.com.",
+ "rr2.sn-q4fzen7l.googlevideo.com.",
"rr3---sn-0nnpbo5a-bggl.googlevideo.com.",
- "rr3---sn-2imern76.googlevideo.com.",
- "rr3---sn-2imern76.gvt1.com.",
- "rr3---sn-2imeyn7k.googlevideo.com.",
- "rr3---sn-2imeyn7k.gvt1.com.",
- "rr3---sn-2napbiu-p5ie.googlevideo.com.",
- "rr3---sn-2napbiu-p5ie.gvt1.com.",
+ "rr3---sn-2aqu-hoas7.googlevideo.com.",
"rr3---sn-2oaig5-55.googlevideo.com.",
"rr3---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr3---sn-2vgu0b5auxaxjvh-apnz.googlevideo.com.",
"rr3---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
"rr3---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
"rr3---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
@@ -4824,7 +4951,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-4g5e6nsk.googlevideo.com.",
"rr3---sn-4g5e6nsr.googlevideo.com.",
"rr3---sn-4g5e6nss.googlevideo.com.",
- "rr3---sn-4g5e6nsy.googlevideo.com.",
"rr3---sn-4g5e6nsz.googlevideo.com.",
"rr3---sn-4g5e6nz7.googlevideo.com.",
"rr3---sn-4g5e6nze.googlevideo.com.",
@@ -4854,6 +4980,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-4g5ednsl.googlevideo.com.",
"rr3---sn-4g5ednsr.googlevideo.com.",
"rr3---sn-4g5ednss.googlevideo.com.",
+ "rr3---sn-4g5ednsy.googlevideo.com.",
"rr3---sn-4g5ednsz.googlevideo.com.",
"rr3---sn-4g5ednz7.googlevideo.com.",
"rr3---sn-4g5lzne6.googlevideo.com.",
@@ -4864,7 +4991,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-4g5lzney.googlevideo.com.",
"rr3---sn-4g5lznez.googlevideo.com.",
"rr3---sn-4g5lznl6.googlevideo.com.",
- "rr3---sn-4g5lznl7.googlevideo.com.",
"rr3---sn-4g5lznle.googlevideo.com.",
"rr3---sn-4g5lznls.googlevideo.com.",
"rr3---sn-4g5lznlz.googlevideo.com.",
@@ -4873,7 +4999,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-5hne6ns6.googlevideo.com.",
"rr3---sn-5hne6nsd.googlevideo.com.",
"rr3---sn-5hne6nsk.googlevideo.com.",
- "rr3---sn-5hne6nsr.googlevideo.com.",
"rr3---sn-5hne6nsy.googlevideo.com.",
"rr3---sn-5hne6nsz.googlevideo.com.",
"rr3---sn-5hne6nz6.googlevideo.com.",
@@ -4885,7 +5010,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-5hnednsz.googlevideo.com.",
"rr3---sn-5hnekn76.googlevideo.com.",
"rr3---sn-5hnekn7d.googlevideo.com.",
- "rr3---sn-5hnekn7k.googlevideo.com.",
"rr3---sn-5hnekn7l.googlevideo.com.",
"rr3---sn-5hnekn7s.googlevideo.com.",
"rr3---sn-5hnekn7z.googlevideo.com.",
@@ -4900,15 +5024,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-5uaeznez.googlevideo.com.",
"rr3---sn-5uaeznl6.googlevideo.com.",
"rr3---sn-5uaeznld.googlevideo.com.",
- "rr3---sn-5uaeznly.googlevideo.com.",
"rr3---sn-5uaeznlz.googlevideo.com.",
- "rr3---sn-5uaeznrz.googlevideo.com.",
"rr3---sn-5uaezns7.googlevideo.com.",
"rr3---sn-5uaeznse.googlevideo.com.",
"rr3---sn-5uaeznsl.googlevideo.com.",
"rr3---sn-5uaeznss.googlevideo.com.",
"rr3---sn-5uaeznze.googlevideo.com.",
- "rr3---sn-5ualdnle.googlevideo.com.",
"rr3---sn-5ualdnll.googlevideo.com.",
"rr3---sn-5ualdnlr.googlevideo.com.",
"rr3---sn-5ualdnls.googlevideo.com.",
@@ -4924,10 +5045,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-5ualdnsz.googlevideo.com.",
"rr3---sn-5ualdnz7.googlevideo.com.",
"rr3---sn-5ualdnze.googlevideo.com.",
- "rr3---sn-8qj-i5ody.googlevideo.com.",
+ "rr3---sn-8qj-i5ozr.googlevideo.com.",
"rr3---sn-8qj-nbo66.googlevideo.com.",
"rr3---sn-8xgp1vo-2iae.googlevideo.com.",
- "rr3---sn-8xgp1vo-2iae7.googlevideo.com.",
"rr3---sn-8xgp1vo-2ial.googlevideo.com.",
"rr3---sn-8xgp1vo-2iay.googlevideo.com.",
"rr3---sn-8xgp1vo-a5me.googlevideo.com.",
@@ -4951,26 +5071,24 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-9gv7zn76.googlevideo.com.",
"rr3---sn-9gv7zn7e.googlevideo.com.",
"rr3---sn-9gv7zn7r.googlevideo.com.",
+ "rr3---sn-a5m7lnl6.googlevideo.com.",
"rr3---sn-a5m7lnld.googlevideo.com.",
"rr3---sn-a5mekn6d.googlevideo.com.",
"rr3---sn-a5mekn6k.googlevideo.com.",
- "rr3---sn-a5mekn6k.gvt1.com.",
"rr3---sn-a5mekn6l.googlevideo.com.",
"rr3---sn-a5mekn6r.googlevideo.com.",
"rr3---sn-a5mekn6s.googlevideo.com.",
- "rr3---sn-a5meknd6.googlevideo.com.",
- "rr3---sn-a5meknd6.gvt1.com.",
+ "rr3---sn-a5mekn6s.gvt1.com.",
+ "rr3---sn-a5mekn6z.googlevideo.com.",
"rr3---sn-a5meknde.googlevideo.com.",
"rr3---sn-a5mekndl.googlevideo.com.",
"rr3---sn-a5meknds.googlevideo.com.",
"rr3---sn-a5mekndz.googlevideo.com.",
- "rr3---sn-a5mekndz.gvt1.com.",
"rr3---sn-a5meknsd.googlevideo.com.",
"rr3---sn-a5meknsy.googlevideo.com.",
- "rr3---sn-a5meknzk.googlevideo.com.",
- "rr3---sn-a5meknzk.gvt1.com.",
"rr3---sn-a5meknzl.googlevideo.com.",
"rr3---sn-a5meknzr.googlevideo.com.",
+ "rr3---sn-a5meknzr.gvt1.com.",
"rr3---sn-a5meknzs.googlevideo.com.",
"rr3---sn-a5mlrnek.googlevideo.com.",
"rr3---sn-a5mlrnl6.googlevideo.com.",
@@ -4989,28 +5107,32 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-a5msenes.googlevideo.com.",
"rr3---sn-a5msenl7.googlevideo.com.",
"rr3---sn-a5msenle.googlevideo.com.",
- "rr3---sn-a5msenle.gvt1.com.",
"rr3---sn-a5msenll.googlevideo.com.",
+ "rr3---sn-a5msenll.gvt1.com.",
"rr3---sn-ab5l6ndr.googlevideo.com.",
"rr3---sn-ab5l6ndy.googlevideo.com.",
+ "rr3---sn-ab5l6ndy.gvt1.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-ab5l6nr6.gvt1.com.",
"rr3---sn-ab5l6nrd.googlevideo.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-ab5sznlk.googlevideo.com.",
- "rr3---sn-ab5sznlk.gvt1.com.",
"rr3---sn-ab5sznly.googlevideo.com.",
- "rr3---sn-ab5sznly.gvt1.com.",
"rr3---sn-ab5sznz6.googlevideo.com.",
"rr3---sn-ab5sznzd.googlevideo.com.",
+ "rr3---sn-ab5sznzd.gvt1.com.",
"rr3---sn-ab5sznze.googlevideo.com.",
"rr3---sn-ab5sznzk.googlevideo.com.",
"rr3---sn-ab5sznzk.gvt1.com.",
@@ -5018,28 +5140,27 @@ var FakeECSFQDNs = container.NewMapSet(
"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-ab5sznzy.gvt1.com.",
"rr3---sn-ab5sznzz.googlevideo.com.",
- "rr3---sn-ab5sznzz.gvt1.com.",
"rr3---sn-aigl6n6s.googlevideo.com.",
- "rr3---sn-aigl6ned.googlevideo.com.",
"rr3---sn-aigl6nek.googlevideo.com.",
- "rr3---sn-aigl6nek.gvt1.com.",
- "rr3---sn-aigl6ner.googlevideo.com.",
"rr3---sn-aigl6ney.googlevideo.com.",
"rr3---sn-aigl6nl7.googlevideo.com.",
"rr3---sn-aigl6ns6.googlevideo.com.",
"rr3---sn-aigl6nsd.googlevideo.com.",
- "rr3---sn-aigl6nsd.gvt1.com.",
"rr3---sn-aigl6nsk.googlevideo.com.",
"rr3---sn-aigl6nsr.googlevideo.com.",
"rr3---sn-aigl6nz7.googlevideo.com.",
+ "rr3---sn-aigl6nze.googlevideo.com.",
"rr3---sn-aigl6nzk.googlevideo.com.",
"rr3---sn-aigl6nzl.googlevideo.com.",
+ "rr3---sn-aigl6nzl.gvt1.com.",
"rr3---sn-aigl6nzr.googlevideo.com.",
"rr3---sn-aigl6nzs.googlevideo.com.",
+ "rr3---sn-aigl6nzs.gvt1.com.",
"rr3---sn-aigzrn76.googlevideo.com.",
- "rr3---sn-aigzrn7d.googlevideo.com.",
"rr3---sn-aigzrn7e.googlevideo.com.",
"rr3---sn-aigzrn7k.googlevideo.com.",
"rr3---sn-aigzrn7l.googlevideo.com.",
@@ -5054,96 +5175,88 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-aigzrnz7.googlevideo.com.",
"rr3---sn-aigzrnze.googlevideo.com.",
"rr3---sn-aj5ua5-5c.googlevideo.com.",
- "rr3---sn-apn7en7e.googlevideo.com.",
- "rr3---sn-apn7en7l.googlevideo.com.",
"rr3---sn-apn7en7s.googlevideo.com.",
- "rr3---sn-bg5oqxjvh-50nz.googlevideo.com.",
"rr3---sn-cvb7lne7.googlevideo.com.",
- "rr3---sn-cvb7lnee.googlevideo.com.",
"rr3---sn-cvb7lnls.googlevideo.com.",
"rr3---sn-cvb7lnlz.googlevideo.com.",
"rr3---sn-cvb7sn7k.googlevideo.com.",
"rr3---sn-cvb7sn7r.googlevideo.com.",
- "rr3---sn-h0jeened.googlevideo.com.",
- "rr3---sn-h0jeenek.googlevideo.com.",
"rr3---sn-h0jeenl6.googlevideo.com.",
"rr3---sn-h0jeenld.googlevideo.com.",
- "rr3---sn-h0jeenle.googlevideo.com.",
- "rr3---sn-h0jeln7e.googlevideo.com.",
- "rr3---sn-h0jelne6.googlevideo.com.",
- "rr3---sn-h0jelne7.googlevideo.com.",
"rr3---sn-h0jelnes.googlevideo.com.",
"rr3---sn-h0jelnez.googlevideo.com.",
+ "rr3---sn-hgn7yn7e.googlevideo.com.",
"rr3---sn-hjoj-gq0l.googlevideo.com.",
- "rr3---sn-hjoj-gq0l.gvt1.com.",
- "rr3---sn-hjoj-jaul.googlevideo.com.",
- "rr3---sn-hjoj-poul.googlevideo.com.",
"rr3---sn-hoa7kn76.googlevideo.com.",
"rr3---sn-hoa7kn7z.googlevideo.com.",
"rr3---sn-hoa7rn76.googlevideo.com.",
"rr3---sn-hoa7rn7z.googlevideo.com.",
"rr3---sn-hp57kn6r.googlevideo.com.",
"rr3---sn-hp57kn6r.gvt1.com.",
- "rr3---sn-hp57kn6y.googlevideo.com.",
"rr3---sn-hp57knd6.googlevideo.com.",
+ "rr3---sn-hp57knd6.gvt1.com.",
"rr3---sn-hp57kndd.googlevideo.com.",
+ "rr3---sn-hp57kndd.gvt1.com.",
"rr3---sn-hp57kndk.googlevideo.com.",
+ "rr3---sn-hp57kndk.gvt1.com.",
"rr3---sn-hp57kndr.googlevideo.com.",
+ "rr3---sn-hp57kndr.gvt1.com.",
"rr3---sn-hp57knds.googlevideo.com.",
+ "rr3---sn-hp57knds.gvt1.com.",
"rr3---sn-hp57kndy.googlevideo.com.",
+ "rr3---sn-hp57kndz.googlevideo.com.",
+ "rr3---sn-hp57kndz.gvt1.com.",
"rr3---sn-hp57yn7r.googlevideo.com.",
"rr3---sn-hp57yn7y.googlevideo.com.",
"rr3---sn-hp57yne7.googlevideo.com.",
"rr3---sn-hp57ynee.googlevideo.com.",
- "rr3---sn-hp57ynee.gvt1.com.",
"rr3---sn-hp57ynl6.googlevideo.com.",
+ "rr3---sn-hp57ynl6.gvt1.com.",
"rr3---sn-hp57ynlr.googlevideo.com.",
"rr3---sn-hp57ynlr.gvt1.com.",
"rr3---sn-hp57ynly.googlevideo.com.",
- "rr3---sn-hp57ynly.gvt1.com.",
"rr3---sn-hp57yns7.googlevideo.com.",
+ "rr3---sn-hp57yns7.gvt1.com.",
"rr3---sn-hp57ynse.googlevideo.com.",
+ "rr3---sn-hp57ynse.gvt1.com.",
"rr3---sn-hp57ynsl.googlevideo.com.",
+ "rr3---sn-hp57ynsl.gvt1.com.",
"rr3---sn-hp57ynss.googlevideo.com.",
"rr3---sn-i3b7kn6s.googlevideo.com.",
"rr3---sn-i3b7knld.googlevideo.com.",
"rr3---sn-i3b7knlk.googlevideo.com.",
- "rr3---sn-i3b7kns6.googlevideo.com.",
"rr3---sn-i3b7knsd.googlevideo.com.",
"rr3---sn-i3b7knse.googlevideo.com.",
"rr3---sn-i3b7knsl.googlevideo.com.",
+ "rr3---sn-i3b7knzl.googlevideo.com.",
+ "rr3---sn-i3b7knzs.googlevideo.com.",
"rr3---sn-i3belne6.googlevideo.com.",
"rr3---sn-i3belney.googlevideo.com.",
"rr3---sn-i3belnl6.googlevideo.com.",
"rr3---sn-i3belnl7.googlevideo.com.",
- "rr3---sn-i3belnll.googlevideo.com.",
"rr3---sn-i3belnls.googlevideo.com.",
"rr3---sn-i3belnlz.googlevideo.com.",
"rr3---sn-i3bssn7e.googlevideo.com.",
- "rr3---sn-i5f5ppuxa-ioal.googlevideo.com.",
- "rr3---sn-i5goxu-i3bl.googlevideo.com.",
"rr3---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
"rr3---sn-jvhj5nu-2iae.googlevideo.com.",
"rr3---sn-jvhj5nu-2ial.googlevideo.com.",
+ "rr3---sn-jvhj5nu-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-n5oe.gvt1.com.",
"rr3---sn-jxopj-nh4e.googlevideo.com.",
"rr3---sn-jxopj-nh4e.gvt1.com.",
"rr3---sn-muxa-2iae.googlevideo.com.",
- "rr3---sn-n4v7snee.googlevideo.com.",
"rr3---sn-n4v7sney.googlevideo.com.",
"rr3---sn-n4v7snl7.googlevideo.com.",
"rr3---sn-n4v7snll.googlevideo.com.",
"rr3---sn-n4v7snlr.googlevideo.com.",
"rr3---sn-n4v7snls.googlevideo.com.",
- "rr3---sn-n4v7snly.googlevideo.com.",
"rr3---sn-n4v7sns7.googlevideo.com.",
"rr3---sn-n4v7snse.googlevideo.com.",
"rr3---sn-npoe7ndl.googlevideo.com.",
@@ -5162,7 +5275,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-npoe7ns7.googlevideo.com.",
"rr3---sn-npoe7nsd.googlevideo.com.",
"rr3---sn-npoe7nsk.googlevideo.com.",
- "rr3---sn-npoe7nsl.googlevideo.com.",
+ "rr3---sn-npoe7nsk.gvt1.com.",
"rr3---sn-npoe7nsr.googlevideo.com.",
"rr3---sn-npoe7nss.googlevideo.com.",
"rr3---sn-npoe7nsy.googlevideo.com.",
@@ -5172,6 +5285,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-npoeenee.googlevideo.com.",
"rr3---sn-npoeenek.googlevideo.com.",
"rr3---sn-npoeener.googlevideo.com.",
+ "rr3---sn-npoeeney.googlevideo.com.",
"rr3---sn-npoeenez.googlevideo.com.",
"rr3---sn-npoeenl7.googlevideo.com.",
"rr3---sn-npoeenle.googlevideo.com.",
@@ -5184,40 +5298,46 @@ 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-nv0ui4gvou-hape.googlevideo.com.",
+ "rr3---sn-ntqe6n76.googlevideo.com.",
+ "rr3---sn-nx57ynlk.googlevideo.com.",
+ "rr3---sn-nx57ynlk.gvt1.com.",
"rr3---sn-nx57ynsd.googlevideo.com.",
- "rr3---sn-nx57ynsd.gvt1.com.",
+ "rr3---sn-nx57ynse.googlevideo.com.",
+ "rr3---sn-nx57ynse.gvt1.com.",
"rr3---sn-nx57ynsk.googlevideo.com.",
+ "rr3---sn-nx57ynsk.gvt1.com.",
"rr3---sn-nx57ynsl.googlevideo.com.",
+ "rr3---sn-nx57ynsl.gvt1.com.",
"rr3---sn-nx57ynss.googlevideo.com.",
+ "rr3---sn-nx57ynss.gvt1.com.",
"rr3---sn-nx57ynsz.googlevideo.com.",
"rr3---sn-nx57ynsz.gvt1.com.",
"rr3---sn-nx5s7n76.googlevideo.com.",
- "rr3---sn-nx5s7n76.gvt1.com.",
"rr3---sn-nx5s7n7d.googlevideo.com.",
- "rr3---sn-nx5s7n7d.gvt1.com.",
"rr3---sn-nx5s7n7y.googlevideo.com.",
"rr3---sn-nx5s7n7y.gvt1.com.",
"rr3---sn-nx5s7n7z.googlevideo.com.",
- "rr3---sn-nx5s7n7z.gvt1.com.",
"rr3---sn-nx5s7nee.googlevideo.com.",
- "rr3---sn-nx5s7nee.gvt1.com.",
"rr3---sn-o097znsd.googlevideo.com.",
"rr3---sn-o097znse.googlevideo.com.",
"rr3---sn-o097znsk.googlevideo.com.",
+ "rr3---sn-o097znsk.gvt1.com.",
"rr3---sn-o097znsl.googlevideo.com.",
"rr3---sn-o097znsr.googlevideo.com.",
+ "rr3---sn-o097znsr.gvt1.com.",
"rr3---sn-o097znss.googlevideo.com.",
"rr3---sn-o097znsz.googlevideo.com.",
"rr3---sn-o097znz7.googlevideo.com.",
+ "rr3---sn-o097znz7.gvt1.com.",
"rr3---sn-o097znzd.googlevideo.com.",
"rr3---sn-o097znze.googlevideo.com.",
"rr3---sn-o097znzk.googlevideo.com.",
"rr3---sn-o097znzr.googlevideo.com.",
- "rr3---sn-ounjvhh-acce.googlevideo.com.",
+ "rr3---sn-oj5hn5-55.googlevideo.com.",
"rr3---sn-p5qddn76.googlevideo.com.",
"rr3---sn-p5qddn7d.googlevideo.com.",
"rr3---sn-p5qddn7k.googlevideo.com.",
@@ -5233,6 +5353,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-p5qlsndr.googlevideo.com.",
"rr3---sn-p5qlsndz.googlevideo.com.",
"rr3---sn-p5qlsnrl.googlevideo.com.",
+ "rr3---sn-p5qlsnrr.googlevideo.com.",
"rr3---sn-p5qlsny6.googlevideo.com.",
"rr3---sn-p5qs7n6d.googlevideo.com.",
"rr3---sn-p5qs7nsk.googlevideo.com.",
@@ -5240,117 +5361,85 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-p5qs7nzk.googlevideo.com.",
"rr3---sn-p5qs7nzr.googlevideo.com.",
"rr3---sn-p5qs7nzy.googlevideo.com.",
- "rr3---sn-pobpb-poql.googlevideo.com.",
"rr3---sn-q4fl6n66.googlevideo.com.",
"rr3---sn-q4fl6n66.gvt1.com.",
"rr3---sn-q4fl6n6d.googlevideo.com.",
- "rr3---sn-q4fl6n6d.gvt1.com.",
"rr3---sn-q4fl6n6r.googlevideo.com.",
"rr3---sn-q4fl6n6r.gvt1.com.",
"rr3---sn-q4fl6n6s.googlevideo.com.",
- "rr3---sn-q4fl6n6s.gvt1.com.",
"rr3---sn-q4fl6n6y.googlevideo.com.",
"rr3---sn-q4fl6n6y.gvt1.com.",
"rr3---sn-q4fl6n6z.googlevideo.com.",
- "rr3---sn-q4fl6n6z.gvt1.com.",
"rr3---sn-q4fl6nd6.googlevideo.com.",
- "rr3---sn-q4fl6nd7.googlevideo.com.",
"rr3---sn-q4fl6nde.googlevideo.com.",
"rr3---sn-q4fl6ndl.googlevideo.com.",
"rr3---sn-q4fl6nds.googlevideo.com.",
- "rr3---sn-q4fl6nds.gvt1.com.",
"rr3---sn-q4fl6ndz.googlevideo.com.",
- "rr3---sn-q4fl6ndz.gvt1.com.",
"rr3---sn-q4fl6nlz.googlevideo.com.",
- "rr3---sn-q4fl6nlz.gvt1.com.",
"rr3---sn-q4fl6ns6.googlevideo.com.",
"rr3---sn-q4fl6ns6.gvt1.com.",
+ "rr3---sn-q4fl6ns7.googlevideo.com.",
"rr3---sn-q4fl6nsd.googlevideo.com.",
- "rr3---sn-q4fl6nsd.gvt1.com.",
- "rr3---sn-q4fl6nsk.googlevideo.com.",
- "rr3---sn-q4fl6nsk.gvt1.com.",
"rr3---sn-q4fl6nsl.googlevideo.com.",
"rr3---sn-q4fl6nsl.gvt1.com.",
"rr3---sn-q4fl6nsr.googlevideo.com.",
"rr3---sn-q4fl6nss.googlevideo.com.",
"rr3---sn-q4fl6nsy.googlevideo.com.",
- "rr3---sn-q4fl6nsy.gvt1.com.",
"rr3---sn-q4fl6nz6.googlevideo.com.",
- "rr3---sn-q4fl6nz6.gvt1.com.",
"rr3---sn-q4fl6nz7.googlevideo.com.",
- "rr3---sn-q4fl6nz7.gvt1.com.",
"rr3---sn-q4fl6nzy.googlevideo.com.",
- "rr3---sn-q4fl6nzy.gvt1.com.",
"rr3---sn-q4flrn7k.googlevideo.com.",
- "rr3---sn-q4flrn7k.gvt1.com.",
"rr3---sn-q4flrn7r.googlevideo.com.",
- "rr3---sn-q4flrn7r.gvt1.com.",
"rr3---sn-q4flrn7y.googlevideo.com.",
"rr3---sn-q4flrne6.googlevideo.com.",
"rr3---sn-q4flrne7.googlevideo.com.",
- "rr3---sn-q4flrnee.googlevideo.com.",
- "rr3---sn-q4flrnee.gvt1.com.",
"rr3---sn-q4flrnek.googlevideo.com.",
- "rr3---sn-q4flrnek.gvt1.com.",
"rr3---sn-q4flrnel.googlevideo.com.",
"rr3---sn-q4flrner.googlevideo.com.",
+ "rr3---sn-q4flrner.gvt1.com.",
+ "rr3---sn-q4flrnes.googlevideo.com.",
"rr3---sn-q4flrney.googlevideo.com.",
- "rr3---sn-q4flrney.gvt1.com.",
"rr3---sn-q4flrnez.googlevideo.com.",
- "rr3---sn-q4flrnez.gvt1.com.",
"rr3---sn-q4flrnl6.googlevideo.com.",
- "rr3---sn-q4flrnl6.gvt1.com.",
"rr3---sn-q4flrnl7.googlevideo.com.",
- "rr3---sn-q4flrnl7.gvt1.com.",
- "rr3---sn-q4flrnld.googlevideo.com.",
- "rr3---sn-q4flrnld.gvt1.com.",
"rr3---sn-q4flrnle.googlevideo.com.",
- "rr3---sn-q4flrnle.gvt1.com.",
"rr3---sn-q4flrnlz.googlevideo.com.",
+ "rr3---sn-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-q4fzen7e.googlevideo.com.",
- "rr3---sn-q4fzen7e.gvt1.com.",
"rr3---sn-q4fzen7l.googlevideo.com.",
"rr3---sn-q4fzen7l.gvt1.com.",
"rr3---sn-q4fzen7r.googlevideo.com.",
"rr3---sn-q4fzen7r.gvt1.com.",
"rr3---sn-q4fzen7s.googlevideo.com.",
- "rr3---sn-q4fzen7s.gvt1.com.",
"rr3---sn-q4fzen7y.googlevideo.com.",
- "rr3---sn-q4fzen7y.gvt1.com.",
"rr3---sn-q4fzene7.googlevideo.com.",
- "rr3---sn-q4fzene7.gvt1.com.",
"rr3---sn-q4fzenee.googlevideo.com.",
"rr3---sn-q4fzenee.gvt1.com.",
+ "rr3---sn-qpbp-30ar.googlevideo.com.",
"rr3---sn-qxo7rn7k.googlevideo.com.",
"rr3---sn-qxo7rn7r.googlevideo.com.",
"rr3---sn-qxo7rn7y.googlevideo.com.",
"rr3---sn-qxoedn7k.googlevideo.com.",
+ "rr3---sn-qxoedne7.googlevideo.com.",
"rr3---sn-qxoednee.googlevideo.com.",
- "rr3---sn-u1hp55-5c.googlevideo.com.",
- "rr3---sn-uhvcpaxoa-5hne.googlevideo.com.",
- "rr3---sn-uhvcpaxoa-guhe.googlevideo.com.",
- "rr3---sn-v5goxu-jhil.googlevideo.com.",
"rr3---sn-vgqskn66.googlevideo.com.",
"rr3---sn-vgqskn67.googlevideo.com.",
"rr3---sn-vgqskn6d.googlevideo.com.",
+ "rr3---sn-vgqskn6d.gvt1.com.",
"rr3---sn-vgqskn6s.googlevideo.com.",
"rr3---sn-vgqskn6z.googlevideo.com.",
"rr3---sn-vgqskne6.googlevideo.com.",
"rr3---sn-vgqskned.googlevideo.com.",
"rr3---sn-vgqsknek.googlevideo.com.",
- "rr3---sn-vgqsknek.gvt1.com.",
"rr3---sn-vgqsknes.googlevideo.com.",
- "rr3---sn-vgqsknes.gvt1.com.",
"rr3---sn-vgqsknez.googlevideo.com.",
"rr3---sn-vgqsknld.googlevideo.com.",
"rr3---sn-vgqsknld.gvt1.com.",
- "rr3---sn-vgqsknlk.googlevideo.com.",
"rr3---sn-vgqsknll.googlevideo.com.",
"rr3---sn-vgqsknlr.googlevideo.com.",
"rr3---sn-vgqsknls.googlevideo.com.",
@@ -5360,96 +5449,113 @@ var FakeECSFQDNs = container.NewMapSet(
"rr3---sn-vgqsknse.googlevideo.com.",
"rr3---sn-vgqsknsk.googlevideo.com.",
"rr3---sn-vgqsknz6.googlevideo.com.",
+ "rr3---sn-vgqsknz6.gvt1.com.",
"rr3---sn-vgqsknz7.googlevideo.com.",
"rr3---sn-vgqsknzd.googlevideo.com.",
- "rr3---sn-vgqsknzd.gvt1.com.",
"rr3---sn-vgqsknze.googlevideo.com.",
"rr3---sn-vgqsknzk.googlevideo.com.",
- "rr3---sn-vgqsknzk.gvt1.com.",
"rr3---sn-vgqsknzl.googlevideo.com.",
"rr3---sn-vgqsknzr.googlevideo.com.",
+ "rr3---sn-vgqsknzr.gvt1.com.",
"rr3---sn-vgqsknzs.googlevideo.com.",
"rr3---sn-vgqsknzy.googlevideo.com.",
+ "rr3---sn-vgqsknzy.gvt1.com.",
"rr3---sn-vgqsknzz.googlevideo.com.",
- "rr3---sn-vgqsknzz.gvt1.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-vgqsrn6l.googlevideo.com.",
- "rr3---sn-vgqsrn6l.gvt1.com.",
"rr3---sn-vgqsrn6z.googlevideo.com.",
- "rr3---sn-vgqsrn6z.gvt1.com.",
"rr3---sn-vgqsrne6.googlevideo.com.",
"rr3---sn-vgqsrned.googlevideo.com.",
"rr3---sn-vgqsrnek.googlevideo.com.",
"rr3---sn-vgqsrnes.googlevideo.com.",
"rr3---sn-vgqsrnez.googlevideo.com.",
"rr3---sn-vgqsrnl6.googlevideo.com.",
- "rr3---sn-vgqsrnl6.gvt1.com.",
"rr3---sn-vgqsrnld.googlevideo.com.",
"rr3---sn-vgqsrnlk.googlevideo.com.",
"rr3---sn-vgqsrnll.googlevideo.com.",
"rr3---sn-vgqsrnll.gvt1.com.",
"rr3---sn-vgqsrnls.googlevideo.com.",
- "rr3---sn-vgqsrnls.gvt1.com.",
"rr3---sn-vgqsrnlz.googlevideo.com.",
+ "rr3---sn-vgqsrnlz.gvt1.com.",
"rr3---sn-vgqsrns6.googlevideo.com.",
+ "rr3---sn-vgqsrns6.gvt1.com.",
"rr3---sn-vgqsrnsd.googlevideo.com.",
"rr3---sn-vgqsrnsr.googlevideo.com.",
- "rr3---sn-vgqsrnsr.gvt1.com.",
"rr3---sn-vgqsrnsy.googlevideo.com.",
+ "rr3---sn-vgqsrnsy.gvt1.com.",
"rr3---sn-vgqsrnz6.googlevideo.com.",
"rr3---sn-vgqsrnz7.googlevideo.com.",
"rr3---sn-vgqsrnzd.googlevideo.com.",
"rr3---sn-vgqsrnzk.googlevideo.com.",
- "rr3---sn-vgqsrnzk.gvt1.com.",
"rr3---sn-vgqsrnzr.googlevideo.com.",
"rr3---sn-vgqsrnzs.googlevideo.com.",
+ "rr3---sn-vgqsrnzs.gvt1.com.",
"rr3---sn-vgqsrnzy.googlevideo.com.",
"rr3---sn-vgqsrnzz.googlevideo.com.",
+ "rr3---sn-vgqsrnzz.gvt1.com.",
+ "rr3.sn-5hnekn7z.googlevideo.com.",
+ "rr3.sn-a5mekn6s.googlevideo.com.",
+ "rr3.sn-a5meknde.googlevideo.com.",
+ "rr3.sn-a5mekndz.googlevideo.com.",
"rr3.sn-a5meknzr.googlevideo.com.",
- "rr3.sn-q4fl6n66.googlevideo.com.",
+ "rr3.sn-a5mlrnll.googlevideo.com.",
+ "rr3.sn-a5mlrnlz.googlevideo.com.",
+ "rr3.sn-hp57knds.googlevideo.com.",
+ "rr3.sn-hp57kndy.googlevideo.com.",
+ "rr3.sn-hp57ynl6.googlevideo.com.",
+ "rr3.sn-hp57ynlr.googlevideo.com.",
+ "rr3.sn-hp57ynse.googlevideo.com.",
+ "rr3.sn-ntqe6n76.googlevideo.com.",
+ "rr3.sn-q4fl6n6z.googlevideo.com.",
+ "rr3.sn-q4fl6ns6.googlevideo.com.",
+ "rr3.sn-q4fl6nsy.googlevideo.com.",
"rr3.sn-q4flrne7.googlevideo.com.",
+ "rr3.sn-q4fzen7l.googlevideo.com.",
"rr4---sn-0nnpbo5a-bggl.googlevideo.com.",
- "rr4---sn-2imern76.googlevideo.com.",
- "rr4---sn-2imern76.gvt1.com.",
- "rr4---sn-2imern7d.googlevideo.com.",
- "rr4---sn-2imeyn7k.googlevideo.com.",
- "rr4---sn-2imeyn7k.gvt1.com.",
+ "rr4---sn-2aqu-hoas7.googlevideo.com.",
+ "rr4---sn-2aqu-hoasz.googlevideo.com.",
"rr4---sn-2oaig5-55.googlevideo.com.",
"rr4---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr4---sn-2vgu0b5auxaxjvh-apnz.googlevideo.com.",
"rr4---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
+ "rr4---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
"rr4---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
"rr4---sn-2vgu0b5auxaxjvh-v2vz.googlevideo.com.",
"rr4---sn-30a7rne6.googlevideo.com.",
- "rr4---sn-30a7rned.googlevideo.com.",
"rr4---sn-30a7rnek.googlevideo.com.",
"rr4---sn-30a7rner.googlevideo.com.",
"rr4---sn-30a7ynek.googlevideo.com.",
"rr4---sn-30a7yner.googlevideo.com.",
"rr4---sn-30a7yney.googlevideo.com.",
"rr4---sn-30a7ynl7.googlevideo.com.",
+ "rr4---sn-42u-nbozz.googlevideo.com.",
"rr4---sn-4g5e6ns6.googlevideo.com.",
"rr4---sn-4g5e6ns7.googlevideo.com.",
"rr4---sn-4g5e6nsd.googlevideo.com.",
"rr4---sn-4g5e6nsk.googlevideo.com.",
"rr4---sn-4g5e6nsr.googlevideo.com.",
"rr4---sn-4g5e6nss.googlevideo.com.",
- "rr4---sn-4g5e6nsy.googlevideo.com.",
"rr4---sn-4g5e6nsz.googlevideo.com.",
"rr4---sn-4g5e6nz7.googlevideo.com.",
"rr4---sn-4g5e6nze.googlevideo.com.",
"rr4---sn-4g5e6nzl.googlevideo.com.",
"rr4---sn-4g5e6nzs.googlevideo.com.",
"rr4---sn-4g5e6nzz.googlevideo.com.",
+ "rr4---sn-4g5edn6k.googlevideo.com.",
"rr4---sn-4g5edn6r.googlevideo.com.",
"rr4---sn-4g5edn6y.googlevideo.com.",
"rr4---sn-4g5ednd7.googlevideo.com.",
"rr4---sn-4g5edndd.googlevideo.com.",
"rr4---sn-4g5ednde.googlevideo.com.",
"rr4---sn-4g5edndk.googlevideo.com.",
+ "rr4---sn-4g5edndk.gvt1.com.",
"rr4---sn-4g5edndl.googlevideo.com.",
"rr4---sn-4g5edndr.googlevideo.com.",
+ "rr4---sn-4g5ednds.googlevideo.com.",
"rr4---sn-4g5edndy.googlevideo.com.",
"rr4---sn-4g5edndz.googlevideo.com.",
"rr4---sn-4g5ednkl.googlevideo.com.",
@@ -5463,10 +5569,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-4g5ednsl.googlevideo.com.",
"rr4---sn-4g5ednsr.googlevideo.com.",
"rr4---sn-4g5ednss.googlevideo.com.",
+ "rr4---sn-4g5ednsy.googlevideo.com.",
"rr4---sn-4g5ednsz.googlevideo.com.",
"rr4---sn-4g5ednz7.googlevideo.com.",
"rr4---sn-4g5lzne6.googlevideo.com.",
"rr4---sn-4g5lzned.googlevideo.com.",
+ "rr4---sn-4g5lznek.googlevideo.com.",
"rr4---sn-4g5lzner.googlevideo.com.",
"rr4---sn-4g5lznes.googlevideo.com.",
"rr4---sn-4g5lzney.googlevideo.com.",
@@ -5480,10 +5588,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-5hne6n6l.googlevideo.com.",
"rr4---sn-5hne6ns6.googlevideo.com.",
"rr4---sn-5hne6nsd.googlevideo.com.",
+ "rr4---sn-5hne6nsk.googlevideo.com.",
"rr4---sn-5hne6nsr.googlevideo.com.",
"rr4---sn-5hne6nsy.googlevideo.com.",
"rr4---sn-5hne6nsz.googlevideo.com.",
"rr4---sn-5hne6nz6.googlevideo.com.",
+ "rr4---sn-5hne6nz6.gvt1.com.",
"rr4---sn-5hne6nzd.googlevideo.com.",
"rr4---sn-5hne6nzk.googlevideo.com.",
"rr4---sn-5hne6nzs.googlevideo.com.",
@@ -5492,7 +5602,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-5hnednsz.googlevideo.com.",
"rr4---sn-5hnekn76.googlevideo.com.",
"rr4---sn-5hnekn7d.googlevideo.com.",
- "rr4---sn-5hnekn7k.googlevideo.com.",
"rr4---sn-5hnekn7l.googlevideo.com.",
"rr4---sn-5hnekn7s.googlevideo.com.",
"rr4---sn-5hnekn7z.googlevideo.com.",
@@ -5507,18 +5616,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-5uaeznez.googlevideo.com.",
"rr4---sn-5uaeznl6.googlevideo.com.",
"rr4---sn-5uaeznld.googlevideo.com.",
- "rr4---sn-5uaeznly.googlevideo.com.",
"rr4---sn-5uaeznlz.googlevideo.com.",
- "rr4---sn-5uaeznrz.googlevideo.com.",
"rr4---sn-5uaezns7.googlevideo.com.",
"rr4---sn-5uaeznse.googlevideo.com.",
"rr4---sn-5uaeznsl.googlevideo.com.",
"rr4---sn-5uaeznss.googlevideo.com.",
- "rr4---sn-5uaezny6.googlevideo.com.",
- "rr4---sn-5uaeznys.googlevideo.com.",
- "rr4---sn-5uaeznyz.googlevideo.com.",
"rr4---sn-5uaeznze.googlevideo.com.",
- "rr4---sn-5ualdnle.googlevideo.com.",
"rr4---sn-5ualdnll.googlevideo.com.",
"rr4---sn-5ualdnlr.googlevideo.com.",
"rr4---sn-5ualdnls.googlevideo.com.",
@@ -5534,22 +5637,20 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-5ualdnsz.googlevideo.com.",
"rr4---sn-5ualdnz7.googlevideo.com.",
"rr4---sn-5ualdnze.googlevideo.com.",
- "rr4---sn-8qj-i5ody.googlevideo.com.",
+ "rr4---sn-8qj-i5o6k.googlevideo.com.",
+ "rr4---sn-8qj-i5ozd.googlevideo.com.",
+ "rr4---sn-8qj-i5ozr.googlevideo.com.",
"rr4---sn-8qj-nbo66.googlevideo.com.",
"rr4---sn-8xgp1vo-2iae.googlevideo.com.",
- "rr4---sn-8xgp1vo-2iae7.googlevideo.com.",
"rr4---sn-8xgp1vo-2ial.googlevideo.com.",
"rr4---sn-8xgp1vo-2iay.googlevideo.com.",
- "rr4---sn-8xgp1vo-a5me.googlevideo.com.",
"rr4---sn-8xgp1vo-ab56.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5l.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5s.googlevideo.com.",
"rr4---sn-8xgp1vo-ab5z.googlevideo.com.",
- "rr4---sn-8xgp1vo-hp5e.googlevideo.com.",
"rr4---sn-8xgp1vo-nh4e.googlevideo.com.",
- "rr4---sn-8xgp1vo-p5ie.googlevideo.com.",
"rr4---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr4---sn-8xgp1vo-xfge.googlevideo.com.",
"rr4---sn-8xgp1vo-xfgl.googlevideo.com.",
@@ -5564,20 +5665,17 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-9gv7zn7e.googlevideo.com.",
"rr4---sn-9gv7zn7r.googlevideo.com.",
"rr4---sn-a5m7lnl6.googlevideo.com.",
- "rr4---sn-a5m7lnl6.gvt1.com.",
"rr4---sn-a5m7lnld.googlevideo.com.",
- "rr4---sn-a5m7lnld.gvt1.com.",
"rr4---sn-a5mekn6d.googlevideo.com.",
"rr4---sn-a5mekn6k.googlevideo.com.",
"rr4---sn-a5mekn6l.googlevideo.com.",
"rr4---sn-a5mekn6r.googlevideo.com.",
- "rr4---sn-a5mekn6s.googlevideo.com.",
+ "rr4---sn-a5mekn6r.gvt1.com.",
"rr4---sn-a5mekn6z.googlevideo.com.",
"rr4---sn-a5meknd6.googlevideo.com.",
"rr4---sn-a5meknde.googlevideo.com.",
"rr4---sn-a5mekndl.googlevideo.com.",
"rr4---sn-a5meknds.googlevideo.com.",
- "rr4---sn-a5meknds.gvt1.com.",
"rr4---sn-a5mekndz.googlevideo.com.",
"rr4---sn-a5meknsd.googlevideo.com.",
"rr4---sn-a5meknsy.googlevideo.com.",
@@ -5586,62 +5684,71 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-a5meknzr.googlevideo.com.",
"rr4---sn-a5meknzr.gvt1.com.",
"rr4---sn-a5meknzs.googlevideo.com.",
+ "rr4---sn-a5mlrnek.googlevideo.com.",
+ "rr4---sn-a5mlrnek.gvt1.com.",
"rr4---sn-a5mlrnl6.googlevideo.com.",
+ "rr4---sn-a5mlrnl6.gvt1.com.",
"rr4---sn-a5mlrnll.googlevideo.com.",
"rr4---sn-a5mlrnls.googlevideo.com.",
+ "rr4---sn-a5mlrnls.gvt1.com.",
"rr4---sn-a5mlrnlz.googlevideo.com.",
+ "rr4---sn-a5mlrnlz.gvt1.com.",
"rr4---sn-a5msen76.googlevideo.com.",
"rr4---sn-a5msen7l.googlevideo.com.",
"rr4---sn-a5msen7s.googlevideo.com.",
"rr4---sn-a5msen7z.googlevideo.com.",
"rr4---sn-a5msenek.googlevideo.com.",
+ "rr4---sn-a5msener.googlevideo.com.",
"rr4---sn-a5msenes.googlevideo.com.",
- "rr4---sn-a5msenes.gvt1.com.",
"rr4---sn-a5msenl7.googlevideo.com.",
"rr4---sn-a5msenle.googlevideo.com.",
- "rr4---sn-a5msenle.gvt1.com.",
"rr4---sn-a5msenll.googlevideo.com.",
"rr4---sn-ab5l6ndr.googlevideo.com.",
"rr4---sn-ab5l6ndy.googlevideo.com.",
- "rr4---sn-ab5l6ndy.gvt1.com.",
"rr4---sn-ab5l6nk6.googlevideo.com.",
"rr4---sn-ab5l6nk6.gvt1.com.",
"rr4---sn-ab5l6nkd.googlevideo.com.",
- "rr4---sn-ab5l6nkd.gvt1.com.",
"rr4---sn-ab5l6nr6.googlevideo.com.",
+ "rr4---sn-ab5l6nr6.gvt1.com.",
"rr4---sn-ab5l6nrd.googlevideo.com.",
"rr4---sn-ab5l6nrk.googlevideo.com.",
+ "rr4---sn-ab5l6nrk.gvt1.com.",
"rr4---sn-ab5l6nrl.googlevideo.com.",
"rr4---sn-ab5l6nrr.googlevideo.com.",
- "rr4---sn-ab5l6nrr.gvt1.com.",
"rr4---sn-ab5l6nrs.googlevideo.com.",
+ "rr4---sn-ab5l6nrs.gvt1.com.",
"rr4---sn-ab5l6nrz.googlevideo.com.",
"rr4---sn-ab5sznld.googlevideo.com.",
"rr4---sn-ab5sznlk.googlevideo.com.",
"rr4---sn-ab5sznly.googlevideo.com.",
"rr4---sn-ab5sznz6.googlevideo.com.",
"rr4---sn-ab5sznzd.googlevideo.com.",
+ "rr4---sn-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-ab5sznzl.gvt1.com.",
"rr4---sn-ab5sznzr.googlevideo.com.",
"rr4---sn-ab5sznzr.gvt1.com.",
"rr4---sn-ab5sznzs.googlevideo.com.",
"rr4---sn-ab5sznzy.googlevideo.com.",
- "rr4---sn-ab5sznzy.gvt1.com.",
"rr4---sn-ab5sznzz.googlevideo.com.",
"rr4---sn-aigl6n6s.googlevideo.com.",
- "rr4---sn-aigl6ned.googlevideo.com.",
+ "rr4---sn-aigl6nek.googlevideo.com.",
"rr4---sn-aigl6ner.googlevideo.com.",
- "rr4---sn-aigl6ney.googlevideo.com.",
"rr4---sn-aigl6nl7.googlevideo.com.",
"rr4---sn-aigl6ns6.googlevideo.com.",
+ "rr4---sn-aigl6ns6.gvt1.com.",
"rr4---sn-aigl6nsd.googlevideo.com.",
+ "rr4---sn-aigl6nsd.gvt1.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-aigl6nzk.gvt1.com.",
"rr4---sn-aigl6nzl.googlevideo.com.",
"rr4---sn-aigl6nzr.googlevideo.com.",
"rr4---sn-aigl6nzs.googlevideo.com.",
@@ -5660,49 +5767,59 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-aigzrnsz.googlevideo.com.",
"rr4---sn-aigzrnz7.googlevideo.com.",
"rr4---sn-aigzrnze.googlevideo.com.",
- "rr4---sn-aj5ua5-5c.googlevideo.com.",
- "rr4---sn-apn7en7e.googlevideo.com.",
"rr4---sn-apn7en7l.googlevideo.com.",
"rr4---sn-apn7en7s.googlevideo.com.",
- "rr4---sn-bg5oqxjvh-50nz.googlevideo.com.",
"rr4---sn-cvb7lne7.googlevideo.com.",
"rr4---sn-cvb7lnee.googlevideo.com.",
- "rr4---sn-cvb7lnl7.googlevideo.com.",
"rr4---sn-cvb7lnls.googlevideo.com.",
"rr4---sn-cvb7lnlz.googlevideo.com.",
"rr4---sn-cvb7sn7k.googlevideo.com.",
"rr4---sn-cvb7sn7r.googlevideo.com.",
- "rr4---sn-h0jeened.googlevideo.com.",
- "rr4---sn-h0jeenl6.googlevideo.com.",
"rr4---sn-h0jeenld.googlevideo.com.",
- "rr4---sn-h0jeenle.googlevideo.com.",
"rr4---sn-h0jelne6.googlevideo.com.",
- "rr4---sn-h0jelne7.googlevideo.com.",
"rr4---sn-h0jelnes.googlevideo.com.",
"rr4---sn-h0jelnez.googlevideo.com.",
+ "rr4---sn-h5gj5uxa-hutl.googlevideo.com.",
+ "rr4---sn-hgn7rnls.googlevideo.com.",
"rr4---sn-hjoj-gq0l.googlevideo.com.",
- "rr4---sn-hjoj-gq0l.gvt1.com.",
"rr4---sn-hoa7kn76.googlevideo.com.",
"rr4---sn-hoa7kn7z.googlevideo.com.",
"rr4---sn-hoa7rn76.googlevideo.com.",
"rr4---sn-hoa7rn7z.googlevideo.com.",
+ "rr4---sn-hp57kn6r.googlevideo.com.",
+ "rr4---sn-hp57kn6r.gvt1.com.",
"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-hp57kndk.gvt1.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-hp57kndz.googlevideo.com.",
+ "rr4---sn-hp57kndz.gvt1.com.",
"rr4---sn-hp57yn7r.googlevideo.com.",
+ "rr4---sn-hp57yn7r.gvt1.com.",
"rr4---sn-hp57yn7y.googlevideo.com.",
+ "rr4---sn-hp57yn7y.gvt1.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-hp57yns7.gvt1.com.",
"rr4---sn-hp57ynse.googlevideo.com.",
+ "rr4---sn-hp57ynse.gvt1.com.",
"rr4---sn-hp57ynsl.googlevideo.com.",
+ "rr4---sn-hp57ynsl.gvt1.com.",
"rr4---sn-hp57ynss.googlevideo.com.",
"rr4---sn-i3b7kn6s.googlevideo.com.",
"rr4---sn-i3b7knld.googlevideo.com.",
@@ -5710,19 +5827,17 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-i3b7kns6.googlevideo.com.",
"rr4---sn-i3b7knsd.googlevideo.com.",
"rr4---sn-i3b7knse.googlevideo.com.",
- "rr4---sn-i3b7knsl.googlevideo.com.",
+ "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.",
- "rr4---sn-i3belnls.googlevideo.com.",
"rr4---sn-i3belnlz.googlevideo.com.",
"rr4---sn-i3bssn7e.googlevideo.com.",
- "rr4---sn-i5f5ppuxa-ioal.googlevideo.com.",
"rr4---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
"rr4---sn-jvhj5nu-2iae.googlevideo.com.",
"rr4---sn-jvhj5nu-2ial.googlevideo.com.",
+ "rr4---sn-jvhj5nu-2ias.googlevideo.com.",
"rr4---sn-jvhj5nu-nh4e.googlevideo.com.",
"rr4---sn-jvhj5nu-nh4l.googlevideo.com.",
"rr4---sn-jvhj5nu-nh4s.googlevideo.com.",
@@ -5731,12 +5846,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-jvhj5nu-qufl.googlevideo.com.",
"rr4---sn-jvhj5nu-qufs.googlevideo.com.",
"rr4---sn-jvhj5nu-qufz.googlevideo.com.",
- "rr4---sn-jxopj-n5oe.googlevideo.com.",
- "rr4---sn-jxopj-n5oe.gvt1.com.",
"rr4---sn-jxopj-nh4e.googlevideo.com.",
- "rr4---sn-jxopj-nh4e.gvt1.com.",
- "rr4---sn-muxa-2iae.googlevideo.com.",
"rr4---sn-n4v7snee.googlevideo.com.",
+ "rr4---sn-n4v7sney.googlevideo.com.",
"rr4---sn-n4v7snl7.googlevideo.com.",
"rr4---sn-n4v7snll.googlevideo.com.",
"rr4---sn-n4v7snlr.googlevideo.com.",
@@ -5746,6 +5858,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-n4v7snse.googlevideo.com.",
"rr4---sn-npoe7ndl.googlevideo.com.",
"rr4---sn-npoe7nds.googlevideo.com.",
+ "rr4---sn-npoe7nds.gvt1.com.",
"rr4---sn-npoe7ne6.googlevideo.com.",
"rr4---sn-npoe7ne7.googlevideo.com.",
"rr4---sn-npoe7ned.googlevideo.com.",
@@ -5758,6 +5871,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-npoe7nlz.googlevideo.com.",
"rr4---sn-npoe7ns6.googlevideo.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.",
@@ -5767,7 +5881,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-npoe7nz7.googlevideo.com.",
"rr4---sn-npoeene6.googlevideo.com.",
"rr4---sn-npoeened.googlevideo.com.",
+ "rr4---sn-npoeened.gvt1.com.",
"rr4---sn-npoeenee.googlevideo.com.",
+ "rr4---sn-npoeenee.gvt1.com.",
"rr4---sn-npoeenek.googlevideo.com.",
"rr4---sn-npoeener.googlevideo.com.",
"rr4---sn-npoeeney.googlevideo.com.",
@@ -5776,35 +5892,38 @@ var FakeECSFQDNs = container.NewMapSet(
"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-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-ntq7yney.googlevideo.com.",
- "rr4---sn-nv0ui4gvou-hape.googlevideo.com.",
+ "rr4---sn-ntq7yned.googlevideo.com.",
+ "rr4---sn-ntq7yns7.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-nx57ynsl.gvt1.com.",
"rr4---sn-nx57ynss.googlevideo.com.",
"rr4---sn-nx57ynss.gvt1.com.",
"rr4---sn-nx57ynsz.googlevideo.com.",
- "rr4---sn-nx57ynsz.gvt1.com.",
"rr4---sn-nx5s7n76.googlevideo.com.",
- "rr4---sn-nx5s7n7d.googlevideo.com.",
- "rr4---sn-nx5s7n7d.gvt1.com.",
"rr4---sn-nx5s7n7s.googlevideo.com.",
"rr4---sn-nx5s7n7y.googlevideo.com.",
- "rr4---sn-nx5s7n7y.gvt1.com.",
- "rr4---sn-nx5s7n7z.googlevideo.com.",
"rr4---sn-nx5s7nee.googlevideo.com.",
+ "rr4---sn-nx5s7nee.gvt1.com.",
"rr4---sn-nx5s7nel.googlevideo.com.",
- "rr4---sn-nx5s7nel.gvt1.com.",
"rr4---sn-o097znsd.googlevideo.com.",
"rr4---sn-o097znse.googlevideo.com.",
"rr4---sn-o097znsk.googlevideo.com.",
@@ -5813,10 +5932,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-o097znss.googlevideo.com.",
"rr4---sn-o097znsz.googlevideo.com.",
"rr4---sn-o097znz7.googlevideo.com.",
+ "rr4---sn-o097znz7.gvt1.com.",
"rr4---sn-o097znzd.googlevideo.com.",
"rr4---sn-o097znze.googlevideo.com.",
"rr4---sn-o097znzk.googlevideo.com.",
"rr4---sn-o097znzr.googlevideo.com.",
+ "rr4---sn-oj5hn5-55.googlevideo.com.",
"rr4---sn-p5qddn76.googlevideo.com.",
"rr4---sn-p5qddn7d.googlevideo.com.",
"rr4---sn-p5qddn7k.googlevideo.com.",
@@ -5833,38 +5954,29 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-p5qlsndz.googlevideo.com.",
"rr4---sn-p5qlsnrl.googlevideo.com.",
"rr4---sn-p5qlsnrr.googlevideo.com.",
- "rr4---sn-p5qlsny6.googlevideo.com.",
"rr4---sn-p5qs7n6d.googlevideo.com.",
"rr4---sn-p5qs7nsk.googlevideo.com.",
+ "rr4---sn-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-q4fl6n6d.googlevideo.com.",
- "rr4---sn-q4fl6n6d.gvt1.com.",
"rr4---sn-q4fl6n6r.googlevideo.com.",
- "rr4---sn-q4fl6n6r.gvt1.com.",
"rr4---sn-q4fl6n6s.googlevideo.com.",
- "rr4---sn-q4fl6n6s.gvt1.com.",
"rr4---sn-q4fl6n6y.googlevideo.com.",
- "rr4---sn-q4fl6n6y.gvt1.com.",
"rr4---sn-q4fl6n6z.googlevideo.com.",
- "rr4---sn-q4fl6n6z.gvt1.com.",
"rr4---sn-q4fl6nd6.googlevideo.com.",
"rr4---sn-q4fl6nd6.gvt1.com.",
"rr4---sn-q4fl6nd7.googlevideo.com.",
- "rr4---sn-q4fl6nd7.gvt1.com.",
"rr4---sn-q4fl6nde.googlevideo.com.",
"rr4---sn-q4fl6nde.gvt1.com.",
"rr4---sn-q4fl6ndl.googlevideo.com.",
"rr4---sn-q4fl6nds.googlevideo.com.",
- "rr4---sn-q4fl6nds.gvt1.com.",
"rr4---sn-q4fl6ndz.googlevideo.com.",
- "rr4---sn-q4fl6ndz.gvt1.com.",
"rr4---sn-q4fl6nlz.googlevideo.com.",
"rr4---sn-q4fl6ns6.googlevideo.com.",
- "rr4---sn-q4fl6ns6.gvt1.com.",
"rr4---sn-q4fl6ns7.googlevideo.com.",
"rr4---sn-q4fl6nsd.googlevideo.com.",
"rr4---sn-q4fl6nsd.gvt1.com.",
@@ -5872,95 +5984,77 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-q4fl6nsk.gvt1.com.",
"rr4---sn-q4fl6nsl.googlevideo.com.",
"rr4---sn-q4fl6nsr.googlevideo.com.",
- "rr4---sn-q4fl6nsr.gvt1.com.",
"rr4---sn-q4fl6nss.googlevideo.com.",
+ "rr4---sn-q4fl6nss.gvt1.com.",
"rr4---sn-q4fl6nsy.googlevideo.com.",
- "rr4---sn-q4fl6nsy.gvt1.com.",
"rr4---sn-q4fl6nz6.googlevideo.com.",
- "rr4---sn-q4fl6nz6.gvt1.com.",
"rr4---sn-q4fl6nz7.googlevideo.com.",
- "rr4---sn-q4fl6nz7.gvt1.com.",
"rr4---sn-q4fl6nzy.googlevideo.com.",
"rr4---sn-q4fl6nzy.gvt1.com.",
"rr4---sn-q4flrn7k.googlevideo.com.",
"rr4---sn-q4flrn7r.googlevideo.com.",
- "rr4---sn-q4flrn7r.gvt1.com.",
"rr4---sn-q4flrn7y.googlevideo.com.",
- "rr4---sn-q4flrne6.googlevideo.com.",
+ "rr4---sn-q4flrn7y.gvt1.com.",
"rr4---sn-q4flrne7.googlevideo.com.",
- "rr4---sn-q4flrne7.gvt1.com.",
"rr4---sn-q4flrnee.googlevideo.com.",
"rr4---sn-q4flrnek.googlevideo.com.",
"rr4---sn-q4flrnel.googlevideo.com.",
+ "rr4---sn-q4flrnel.gvt1.com.",
"rr4---sn-q4flrner.googlevideo.com.",
- "rr4---sn-q4flrner.gvt1.com.",
"rr4---sn-q4flrnes.googlevideo.com.",
"rr4---sn-q4flrney.googlevideo.com.",
"rr4---sn-q4flrney.gvt1.com.",
"rr4---sn-q4flrnez.googlevideo.com.",
- "rr4---sn-q4flrnez.gvt1.com.",
"rr4---sn-q4flrnl6.googlevideo.com.",
- "rr4---sn-q4flrnl6.gvt1.com.",
"rr4---sn-q4flrnl7.googlevideo.com.",
- "rr4---sn-q4flrnl7.gvt1.com.",
"rr4---sn-q4flrnld.googlevideo.com.",
+ "rr4---sn-q4flrnld.gvt1.com.",
"rr4---sn-q4flrnle.googlevideo.com.",
- "rr4---sn-q4flrnle.gvt1.com.",
"rr4---sn-q4flrnlz.googlevideo.com.",
- "rr4---sn-q4flrnlz.gvt1.com.",
"rr4---sn-q4flrnsd.googlevideo.com.",
+ "rr4---sn-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-q4fzen7e.googlevideo.com.",
"rr4---sn-q4fzen7l.googlevideo.com.",
+ "rr4---sn-q4fzen7l.gvt1.com.",
"rr4---sn-q4fzen7r.googlevideo.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-qpbp-30ar.googlevideo.com.",
"rr4---sn-qxo7rn7k.googlevideo.com.",
"rr4---sn-qxo7rn7r.googlevideo.com.",
"rr4---sn-qxo7rn7y.googlevideo.com.",
"rr4---sn-qxoedn7k.googlevideo.com.",
"rr4---sn-qxoedne7.googlevideo.com.",
- "rr4---sn-t0a7lnee.googlevideo.com.",
- "rr4---sn-t0a7sn7d.googlevideo.com.",
- "rr4---sn-u1hp55-5c.googlevideo.com.",
- "rr4---sn-uhvcpaxoa-5hne.googlevideo.com.",
- "rr4---sn-uhvcpaxoa-guhe.googlevideo.com.",
- "rr4---sn-v5goxu-jhil.googlevideo.com.",
+ "rr4---sn-qxoednee.googlevideo.com.",
"rr4---sn-vgqskn66.googlevideo.com.",
"rr4---sn-vgqskn67.googlevideo.com.",
"rr4---sn-vgqskn6d.googlevideo.com.",
+ "rr4---sn-vgqskn6d.gvt1.com.",
"rr4---sn-vgqskn6s.googlevideo.com.",
- "rr4---sn-vgqskn6s.gvt1.com.",
"rr4---sn-vgqskn6z.googlevideo.com.",
- "rr4---sn-vgqskn6z.gvt1.com.",
"rr4---sn-vgqskne6.googlevideo.com.",
"rr4---sn-vgqsknek.googlevideo.com.",
- "rr4---sn-vgqsknek.gvt1.com.",
"rr4---sn-vgqsknes.googlevideo.com.",
"rr4---sn-vgqsknez.googlevideo.com.",
+ "rr4---sn-vgqsknez.gvt1.com.",
"rr4---sn-vgqsknld.googlevideo.com.",
- "rr4---sn-vgqsknld.gvt1.com.",
"rr4---sn-vgqsknll.googlevideo.com.",
"rr4---sn-vgqsknlr.googlevideo.com.",
- "rr4---sn-vgqsknlr.gvt1.com.",
"rr4---sn-vgqsknls.googlevideo.com.",
+ "rr4---sn-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-vgqsknz6.googlevideo.com.",
- "rr4---sn-vgqsknz6.gvt1.com.",
"rr4---sn-vgqsknz7.googlevideo.com.",
"rr4---sn-vgqsknz7.gvt1.com.",
"rr4---sn-vgqsknzd.googlevideo.com.",
@@ -5970,6 +6064,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-vgqsknzr.googlevideo.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-vgqsrn67.googlevideo.com.",
@@ -5977,7 +6072,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-vgqsrn6l.googlevideo.com.",
"rr4---sn-vgqsrn6l.gvt1.com.",
"rr4---sn-vgqsrn6z.googlevideo.com.",
- "rr4---sn-vgqsrn6z.gvt1.com.",
"rr4---sn-vgqsrne6.googlevideo.com.",
"rr4---sn-vgqsrned.googlevideo.com.",
"rr4---sn-vgqsrnek.googlevideo.com.",
@@ -5987,41 +6081,51 @@ var FakeECSFQDNs = container.NewMapSet(
"rr4---sn-vgqsrnld.googlevideo.com.",
"rr4---sn-vgqsrnlk.googlevideo.com.",
"rr4---sn-vgqsrnll.googlevideo.com.",
+ "rr4---sn-vgqsrnll.gvt1.com.",
"rr4---sn-vgqsrnls.googlevideo.com.",
- "rr4---sn-vgqsrnls.gvt1.com.",
"rr4---sn-vgqsrnlz.googlevideo.com.",
+ "rr4---sn-vgqsrnlz.gvt1.com.",
"rr4---sn-vgqsrns6.googlevideo.com.",
"rr4---sn-vgqsrnsd.googlevideo.com.",
"rr4---sn-vgqsrnsr.googlevideo.com.",
"rr4---sn-vgqsrnsy.googlevideo.com.",
"rr4---sn-vgqsrnz6.googlevideo.com.",
"rr4---sn-vgqsrnz7.googlevideo.com.",
- "rr4---sn-vgqsrnz7.gvt1.com.",
"rr4---sn-vgqsrnzd.googlevideo.com.",
+ "rr4---sn-vgqsrnzd.gvt1.com.",
"rr4---sn-vgqsrnzk.googlevideo.com.",
- "rr4---sn-vgqsrnzk.gvt1.com.",
"rr4---sn-vgqsrnzr.googlevideo.com.",
"rr4---sn-vgqsrnzs.googlevideo.com.",
"rr4---sn-vgqsrnzy.googlevideo.com.",
"rr4---sn-vgqsrnzz.googlevideo.com.",
- "rr4.sn-5hne6nsd.googlevideo.com.",
- "rr4.sn-5hne6nzk.googlevideo.com.",
- "rr4.sn-5hnednsz.googlevideo.com.",
- "rr4.sn-5hneknee.googlevideo.com.",
+ "rr4---sn-vgqsrnzz.gvt1.com.",
+ "rr4.sn-4g5ednsr.googlevideo.com.",
+ "rr4.sn-a5meknde.googlevideo.com.",
"rr4.sn-a5mekndz.googlevideo.com.",
- "rr4.sn-q4fl6n6d.googlevideo.com.",
- "rr4.sn-q4flrnek.googlevideo.com.",
+ "rr4.sn-a5meknzr.googlevideo.com.",
+ "rr4.sn-a5mlrnll.googlevideo.com.",
+ "rr4.sn-a5mlrnlz.googlevideo.com.",
+ "rr4.sn-hgn7rnls.googlevideo.com.",
+ "rr4.sn-hp57knd6.googlevideo.com.",
+ "rr4.sn-hp57knds.googlevideo.com.",
+ "rr4.sn-hp57kndy.googlevideo.com.",
+ "rr4.sn-hp57ynl6.googlevideo.com.",
+ "rr4.sn-hp57ynlr.googlevideo.com.",
+ "rr4.sn-hp57ynse.googlevideo.com.",
+ "rr4.sn-ntq7yned.googlevideo.com.",
+ "rr4.sn-q4fl6n66.googlevideo.com.",
+ "rr4.sn-q4fl6n6y.googlevideo.com.",
+ "rr4.sn-q4fl6nzy.googlevideo.com.",
"rr4.sn-q4flrnle.googlevideo.com.",
- "rr4.sn-q4flrnsl.googlevideo.com.",
- "rr4.sn-q4fzen7r.googlevideo.com.",
+ "rr4.sn-q4flrnlz.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-2aqu-hoasz.googlevideo.com.",
"rr5---sn-2oaig5-55.googlevideo.com.",
"rr5---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
+ "rr5---sn-2vgu0b5auxaxjvh-apnl.googlevideo.com.",
"rr5---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
+ "rr5---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
+ "rr5---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
"rr5---sn-30a7rne6.googlevideo.com.",
"rr5---sn-30a7rned.googlevideo.com.",
"rr5---sn-30a7rnek.googlevideo.com.",
@@ -6029,6 +6133,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-30a7ynek.googlevideo.com.",
"rr5---sn-30a7yner.googlevideo.com.",
"rr5---sn-30a7ynl7.googlevideo.com.",
+ "rr5---sn-42u-nboze.googlevideo.com.",
"rr5---sn-4g5e6ns6.googlevideo.com.",
"rr5---sn-4g5e6ns7.googlevideo.com.",
"rr5---sn-4g5e6nsd.googlevideo.com.",
@@ -6043,11 +6148,9 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-4g5e6nzs.googlevideo.com.",
"rr5---sn-4g5e6nzz.googlevideo.com.",
"rr5---sn-4g5edn6k.googlevideo.com.",
- "rr5---sn-4g5edn6r.googlevideo.com.",
"rr5---sn-4g5edn6y.googlevideo.com.",
"rr5---sn-4g5ednd7.googlevideo.com.",
"rr5---sn-4g5edndd.googlevideo.com.",
- "rr5---sn-4g5ednde.googlevideo.com.",
"rr5---sn-4g5edndk.googlevideo.com.",
"rr5---sn-4g5edndl.googlevideo.com.",
"rr5---sn-4g5edndr.googlevideo.com.",
@@ -6065,6 +6168,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-4g5ednsl.googlevideo.com.",
"rr5---sn-4g5ednsr.googlevideo.com.",
"rr5---sn-4g5ednss.googlevideo.com.",
+ "rr5---sn-4g5ednsy.googlevideo.com.",
"rr5---sn-4g5ednsz.googlevideo.com.",
"rr5---sn-4g5ednz7.googlevideo.com.",
"rr5---sn-4g5lzne6.googlevideo.com.",
@@ -6080,7 +6184,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-4g5lznls.googlevideo.com.",
"rr5---sn-4g5lznlz.googlevideo.com.",
"rr5---sn-5hne6n6e.googlevideo.com.",
- "rr5---sn-5hne6n6e.gvt1.com.",
"rr5---sn-5hne6n6l.googlevideo.com.",
"rr5---sn-5hne6ns6.googlevideo.com.",
"rr5---sn-5hne6nsd.googlevideo.com.",
@@ -6095,8 +6198,8 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-5hne6nzy.googlevideo.com.",
"rr5---sn-5hnednss.googlevideo.com.",
"rr5---sn-5hnednsz.googlevideo.com.",
+ "rr5---sn-5hnekn76.googlevideo.com.",
"rr5---sn-5hnekn7d.googlevideo.com.",
- "rr5---sn-5hnekn7k.googlevideo.com.",
"rr5---sn-5hnekn7l.googlevideo.com.",
"rr5---sn-5hnekn7s.googlevideo.com.",
"rr5---sn-5hnekn7z.googlevideo.com.",
@@ -6111,17 +6214,12 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-5uaeznez.googlevideo.com.",
"rr5---sn-5uaeznl6.googlevideo.com.",
"rr5---sn-5uaeznld.googlevideo.com.",
- "rr5---sn-5uaeznly.googlevideo.com.",
"rr5---sn-5uaeznlz.googlevideo.com.",
- "rr5---sn-5uaeznrz.googlevideo.com.",
"rr5---sn-5uaezns7.googlevideo.com.",
"rr5---sn-5uaeznse.googlevideo.com.",
"rr5---sn-5uaeznsl.googlevideo.com.",
"rr5---sn-5uaeznss.googlevideo.com.",
- "rr5---sn-5uaezny6.googlevideo.com.",
- "rr5---sn-5uaeznys.googlevideo.com.",
"rr5---sn-5uaeznze.googlevideo.com.",
- "rr5---sn-5ualdnle.googlevideo.com.",
"rr5---sn-5ualdnll.googlevideo.com.",
"rr5---sn-5ualdnlr.googlevideo.com.",
"rr5---sn-5ualdnls.googlevideo.com.",
@@ -6137,124 +6235,120 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-5ualdnsz.googlevideo.com.",
"rr5---sn-5ualdnz7.googlevideo.com.",
"rr5---sn-5ualdnze.googlevideo.com.",
- "rr5---sn-8qj-i5ody.googlevideo.com.",
+ "rr5---sn-8qj-i5o6k.googlevideo.com.",
+ "rr5---sn-8qj-i5ozd.googlevideo.com.",
+ "rr5---sn-8qj-i5ozr.googlevideo.com.",
"rr5---sn-8qj-nbo66.googlevideo.com.",
"rr5---sn-8xgp1vo-2iae.googlevideo.com.",
- "rr5---sn-8xgp1vo-2iae7.googlevideo.com.",
"rr5---sn-8xgp1vo-2ial.googlevideo.com.",
"rr5---sn-8xgp1vo-2iay.googlevideo.com.",
- "rr5---sn-8xgp1vo-a5me.googlevideo.com.",
"rr5---sn-8xgp1vo-ab56.googlevideo.com.",
"rr5---sn-8xgp1vo-ab5d.googlevideo.com.",
+ "rr5---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr5---sn-8xgp1vo-ab5l.googlevideo.com.",
"rr5---sn-8xgp1vo-ab5s.googlevideo.com.",
"rr5---sn-8xgp1vo-ab5z.googlevideo.com.",
"rr5---sn-8xgp1vo-nh4e.googlevideo.com.",
- "rr5---sn-8xgp1vo-p5ie.googlevideo.com.",
"rr5---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr5---sn-8xgp1vo-xfge.googlevideo.com.",
"rr5---sn-8xgp1vo-xfgl.googlevideo.com.",
"rr5---sn-9gv76n7e.googlevideo.com.",
"rr5---sn-9gv76n7l.googlevideo.com.",
"rr5---sn-9gv76n7s.googlevideo.com.",
+ "rr5---sn-9gv76n7z.googlevideo.com.",
"rr5---sn-9gv7ene6.googlevideo.com.",
"rr5---sn-9gv7ened.googlevideo.com.",
+ "rr5---sn-9gv7zn76.googlevideo.com.",
"rr5---sn-9gv7zn7e.googlevideo.com.",
"rr5---sn-9gv7zn7r.googlevideo.com.",
- "rr5---sn-9gv7zn7y.googlevideo.com.",
"rr5---sn-a5m7lnl6.googlevideo.com.",
+ "rr5---sn-a5m7lnl6.gvt1.com.",
"rr5---sn-a5m7lnld.googlevideo.com.",
"rr5---sn-a5mekn6d.googlevideo.com.",
- "rr5---sn-a5mekn6d.gvt1.com.",
"rr5---sn-a5mekn6k.googlevideo.com.",
- "rr5---sn-a5mekn6k.gvt1.com.",
"rr5---sn-a5mekn6l.googlevideo.com.",
- "rr5---sn-a5mekn6l.gvt1.com.",
"rr5---sn-a5mekn6r.googlevideo.com.",
- "rr5---sn-a5mekn6r.gvt1.com.",
"rr5---sn-a5mekn6s.googlevideo.com.",
"rr5---sn-a5mekn6z.googlevideo.com.",
"rr5---sn-a5meknd6.googlevideo.com.",
- "rr5---sn-a5meknd6.gvt1.com.",
"rr5---sn-a5meknde.googlevideo.com.",
"rr5---sn-a5mekndl.googlevideo.com.",
"rr5---sn-a5meknds.googlevideo.com.",
- "rr5---sn-a5meknds.gvt1.com.",
"rr5---sn-a5mekndz.googlevideo.com.",
- "rr5---sn-a5mekndz.gvt1.com.",
"rr5---sn-a5meknsd.googlevideo.com.",
"rr5---sn-a5meknsy.googlevideo.com.",
"rr5---sn-a5meknzk.googlevideo.com.",
- "rr5---sn-a5meknzl.googlevideo.com.",
+ "rr5---sn-a5meknzk.gvt1.com.",
"rr5---sn-a5meknzr.googlevideo.com.",
- "rr5---sn-a5meknzs.googlevideo.com.",
+ "rr5---sn-a5meknzr.gvt1.com.",
"rr5---sn-a5mlrnek.googlevideo.com.",
- "rr5---sn-a5mlrnek.gvt1.com.",
"rr5---sn-a5mlrnl6.googlevideo.com.",
"rr5---sn-a5mlrnll.googlevideo.com.",
"rr5---sn-a5mlrnll.gvt1.com.",
"rr5---sn-a5mlrnls.googlevideo.com.",
"rr5---sn-a5mlrnlz.googlevideo.com.",
- "rr5---sn-a5mlrnlz.gvt1.com.",
"rr5---sn-a5msen76.googlevideo.com.",
+ "rr5---sn-a5msen76.gvt1.com.",
"rr5---sn-a5msen7l.googlevideo.com.",
"rr5---sn-a5msen7s.googlevideo.com.",
"rr5---sn-a5msenek.googlevideo.com.",
"rr5---sn-a5msener.googlevideo.com.",
"rr5---sn-a5msener.gvt1.com.",
"rr5---sn-a5msenes.googlevideo.com.",
- "rr5---sn-a5msenes.gvt1.com.",
"rr5---sn-a5msenl7.googlevideo.com.",
"rr5---sn-a5msenle.googlevideo.com.",
- "rr5---sn-a5msenle.gvt1.com.",
"rr5---sn-a5msenll.googlevideo.com.",
- "rr5---sn-ab5l6ndr.googlevideo.com.",
+ "rr5---sn-a5msenll.gvt1.com.",
"rr5---sn-ab5l6ndy.googlevideo.com.",
"rr5---sn-ab5l6nk6.googlevideo.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.",
"rr5---sn-ab5l6nrz.googlevideo.com.",
"rr5---sn-ab5l6nrz.gvt1.com.",
"rr5---sn-ab5sznld.googlevideo.com.",
+ "rr5---sn-ab5sznld.gvt1.com.",
"rr5---sn-ab5sznlk.googlevideo.com.",
- "rr5---sn-ab5sznlk.gvt1.com.",
"rr5---sn-ab5sznly.googlevideo.com.",
"rr5---sn-ab5sznz6.googlevideo.com.",
- "rr5---sn-ab5sznz6.gvt1.com.",
"rr5---sn-ab5sznzd.googlevideo.com.",
+ "rr5---sn-ab5sznzd.gvt1.com.",
"rr5---sn-ab5sznze.googlevideo.com.",
+ "rr5---sn-ab5sznze.gvt1.com.",
"rr5---sn-ab5sznzk.googlevideo.com.",
"rr5---sn-ab5sznzl.googlevideo.com.",
+ "rr5---sn-ab5sznzl.gvt1.com.",
"rr5---sn-ab5sznzr.googlevideo.com.",
"rr5---sn-ab5sznzs.googlevideo.com.",
"rr5---sn-ab5sznzs.gvt1.com.",
"rr5---sn-ab5sznzy.googlevideo.com.",
- "rr5---sn-ab5sznzy.gvt1.com.",
"rr5---sn-ab5sznzz.googlevideo.com.",
+ "rr5---sn-ab5sznzz.gvt1.com.",
"rr5---sn-aigl6n6s.googlevideo.com.",
"rr5---sn-aigl6ned.googlevideo.com.",
+ "rr5---sn-aigl6nek.googlevideo.com.",
"rr5---sn-aigl6ney.googlevideo.com.",
"rr5---sn-aigl6nl7.googlevideo.com.",
"rr5---sn-aigl6ns6.googlevideo.com.",
"rr5---sn-aigl6nsd.googlevideo.com.",
"rr5---sn-aigl6nsk.googlevideo.com.",
- "rr5---sn-aigl6nsk.gvt1.com.",
"rr5---sn-aigl6nsr.googlevideo.com.",
"rr5---sn-aigl6nz7.googlevideo.com.",
"rr5---sn-aigl6nze.googlevideo.com.",
"rr5---sn-aigl6nzk.googlevideo.com.",
- "rr5---sn-aigl6nzk.gvt1.com.",
"rr5---sn-aigl6nzl.googlevideo.com.",
"rr5---sn-aigl6nzr.googlevideo.com.",
+ "rr5---sn-aigl6nzr.gvt1.com.",
"rr5---sn-aigl6nzs.googlevideo.com.",
- "rr5---sn-aigl6nzs.gvt1.com.",
"rr5---sn-aigzrn76.googlevideo.com.",
"rr5---sn-aigzrn7d.googlevideo.com.",
"rr5---sn-aigzrn7e.googlevideo.com.",
@@ -6270,57 +6364,57 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-aigzrnsz.googlevideo.com.",
"rr5---sn-aigzrnz7.googlevideo.com.",
"rr5---sn-aigzrnze.googlevideo.com.",
- "rr5---sn-aj5ua5-5c.googlevideo.com.",
"rr5---sn-apn7en7l.googlevideo.com.",
"rr5---sn-apn7en7s.googlevideo.com.",
"rr5---sn-cvb7lne7.googlevideo.com.",
- "rr5---sn-cvb7lnl7.googlevideo.com.",
+ "rr5---sn-cvb7lnee.googlevideo.com.",
"rr5---sn-cvb7lnls.googlevideo.com.",
"rr5---sn-cvb7lnlz.googlevideo.com.",
"rr5---sn-cvb7sn7k.googlevideo.com.",
"rr5---sn-cvb7sn7r.googlevideo.com.",
- "rr5---sn-h0jeened.googlevideo.com.",
- "rr5---sn-h0jeenek.googlevideo.com.",
- "rr5---sn-h0jeenl6.googlevideo.com.",
"rr5---sn-h0jeenld.googlevideo.com.",
- "rr5---sn-h0jeenle.googlevideo.com.",
- "rr5---sn-h0jeln7l.googlevideo.com.",
"rr5---sn-h0jelne6.googlevideo.com.",
- "rr5---sn-h0jelne7.googlevideo.com.",
"rr5---sn-h0jelnes.googlevideo.com.",
"rr5---sn-h0jelnez.googlevideo.com.",
- "rr5---sn-hgn7rnls.googlevideo.com.",
+ "rr5---sn-h5gj5uxa-hutl.googlevideo.com.",
"rr5---sn-hoa7kn76.googlevideo.com.",
"rr5---sn-hoa7kn7z.googlevideo.com.",
"rr5---sn-hoa7rn76.googlevideo.com.",
"rr5---sn-hoa7rn7z.googlevideo.com.",
"rr5---sn-hp57kn6r.googlevideo.com.",
- "rr5---sn-hp57kn6y.googlevideo.com.",
+ "rr5---sn-hp57kn6r.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-hp57kndk.gvt1.com.",
"rr5---sn-hp57kndr.googlevideo.com.",
"rr5---sn-hp57kndr.gvt1.com.",
"rr5---sn-hp57knds.googlevideo.com.",
"rr5---sn-hp57knds.gvt1.com.",
"rr5---sn-hp57kndy.googlevideo.com.",
+ "rr5---sn-hp57kndy.gvt1.com.",
"rr5---sn-hp57kndz.googlevideo.com.",
"rr5---sn-hp57kndz.gvt1.com.",
"rr5---sn-hp57yn7r.googlevideo.com.",
"rr5---sn-hp57yn7y.googlevideo.com.",
+ "rr5---sn-hp57yn7y.gvt1.com.",
"rr5---sn-hp57yne7.googlevideo.com.",
"rr5---sn-hp57yne7.gvt1.com.",
"rr5---sn-hp57ynee.googlevideo.com.",
+ "rr5---sn-hp57ynl6.googlevideo.com.",
+ "rr5---sn-hp57ynl6.gvt1.com.",
"rr5---sn-hp57ynlr.googlevideo.com.",
"rr5---sn-hp57ynlr.gvt1.com.",
"rr5---sn-hp57ynly.googlevideo.com.",
"rr5---sn-hp57ynly.gvt1.com.",
"rr5---sn-hp57yns7.googlevideo.com.",
- "rr5---sn-hp57yns7.gvt1.com.",
"rr5---sn-hp57ynse.googlevideo.com.",
"rr5---sn-hp57ynsl.googlevideo.com.",
+ "rr5---sn-hp57ynsl.gvt1.com.",
"rr5---sn-hp57ynss.googlevideo.com.",
+ "rr5---sn-hp57ynss.gvt1.com.",
"rr5---sn-i3b7kn6s.googlevideo.com.",
"rr5---sn-i3b7knld.googlevideo.com.",
"rr5---sn-i3b7knlk.googlevideo.com.",
@@ -6342,27 +6436,27 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-jvhj5nu-2iae.googlevideo.com.",
"rr5---sn-jvhj5nu-2ias.googlevideo.com.",
"rr5---sn-jvhj5nu-nh4e.googlevideo.com.",
+ "rr5---sn-jvhj5nu-nh4l.googlevideo.com.",
"rr5---sn-jvhj5nu-nh4s.googlevideo.com.",
"rr5---sn-jvhj5nu-nh4z.googlevideo.com.",
"rr5---sn-jvhj5nu-qufe.googlevideo.com.",
"rr5---sn-jvhj5nu-qufl.googlevideo.com.",
"rr5---sn-jvhj5nu-qufs.googlevideo.com.",
- "rr5---sn-jxopj-n5oe.googlevideo.com.",
- "rr5---sn-jxopj-n5oe.gvt1.com.",
+ "rr5---sn-jvhj5nu-qufz.googlevideo.com.",
"rr5---sn-jxopj-nh4e.googlevideo.com.",
"rr5---sn-jxopj-nh4e.gvt1.com.",
- "rr5---sn-muxa-2iae.googlevideo.com.",
"rr5---sn-n4v7snee.googlevideo.com.",
"rr5---sn-n4v7sney.googlevideo.com.",
"rr5---sn-n4v7snl7.googlevideo.com.",
"rr5---sn-n4v7snll.googlevideo.com.",
"rr5---sn-n4v7snlr.googlevideo.com.",
- "rr5---sn-n4v7snlr.gvt1.com.",
"rr5---sn-n4v7snls.googlevideo.com.",
"rr5---sn-n4v7snly.googlevideo.com.",
"rr5---sn-n4v7sns7.googlevideo.com.",
"rr5---sn-n4v7snse.googlevideo.com.",
+ "rr5---sn-n4v7snse.gvt1.com.",
"rr5---sn-npoe7ndl.googlevideo.com.",
+ "rr5---sn-npoe7ndl.gvt1.com.",
"rr5---sn-npoe7nds.googlevideo.com.",
"rr5---sn-npoe7ne6.googlevideo.com.",
"rr5---sn-npoe7ne7.googlevideo.com.",
@@ -6370,6 +6464,7 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -6378,6 +6473,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-npoe7nsd.googlevideo.com.",
"rr5---sn-npoe7nsk.googlevideo.com.",
"rr5---sn-npoe7nsl.googlevideo.com.",
+ "rr5---sn-npoe7nsr.googlevideo.com.",
"rr5---sn-npoe7nss.googlevideo.com.",
"rr5---sn-npoe7nsy.googlevideo.com.",
"rr5---sn-npoe7nz7.googlevideo.com.",
@@ -6392,34 +6488,28 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-npoeenle.googlevideo.com.",
"rr5---sn-npoeenlk.googlevideo.com.",
"rr5---sn-npoeenll.googlevideo.com.",
- "rr5---sn-npoeenly.googlevideo.com.",
"rr5---sn-npoeens7.googlevideo.com.",
"rr5---sn-npoldn76.googlevideo.com.",
"rr5---sn-npoldn7d.googlevideo.com.",
"rr5---sn-npoldn7e.googlevideo.com.",
"rr5---sn-npoldn7l.googlevideo.com.",
"rr5---sn-npoldn7s.googlevideo.com.",
+ "rr5---sn-npoldn7s.gvt1.com.",
"rr5---sn-npoldn7y.googlevideo.com.",
"rr5---sn-npoldn7z.googlevideo.com.",
"rr5---sn-npoldne7.googlevideo.com.",
- "rr5---sn-nv0ui4gvou-hape.googlevideo.com.",
"rr5---sn-nx57ynlk.googlevideo.com.",
"rr5---sn-nx57ynlk.gvt1.com.",
"rr5---sn-nx57ynse.googlevideo.com.",
"rr5---sn-nx57ynse.gvt1.com.",
"rr5---sn-nx57ynsk.googlevideo.com.",
"rr5---sn-nx57ynsk.gvt1.com.",
- "rr5---sn-nx57ynsl.googlevideo.com.",
- "rr5---sn-nx57ynsl.gvt1.com.",
"rr5---sn-nx57ynss.googlevideo.com.",
- "rr5---sn-nx57ynss.gvt1.com.",
"rr5---sn-nx57ynsz.googlevideo.com.",
- "rr5---sn-nx57ynsz.gvt1.com.",
"rr5---sn-nx5s7n76.googlevideo.com.",
"rr5---sn-nx5s7n7d.googlevideo.com.",
"rr5---sn-nx5s7n7s.googlevideo.com.",
"rr5---sn-nx5s7n7z.googlevideo.com.",
- "rr5---sn-nx5s7n7z.gvt1.com.",
"rr5---sn-nx5s7nee.googlevideo.com.",
"rr5---sn-nx5s7nel.googlevideo.com.",
"rr5---sn-nx5s7nel.gvt1.com.",
@@ -6435,7 +6525,7 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-o097znze.googlevideo.com.",
"rr5---sn-o097znzk.googlevideo.com.",
"rr5---sn-o097znzr.googlevideo.com.",
- "rr5---sn-o097znzr.gvt1.com.",
+ "rr5---sn-oj5hn5-55.googlevideo.com.",
"rr5---sn-p5qddn76.googlevideo.com.",
"rr5---sn-p5qddn7d.googlevideo.com.",
"rr5---sn-p5qddn7k.googlevideo.com.",
@@ -6460,79 +6550,67 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-p5qs7nzy.googlevideo.com.",
"rr5---sn-q4fl6n66.googlevideo.com.",
"rr5---sn-q4fl6n6d.googlevideo.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-q4fl6nd6.googlevideo.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.",
+ "rr5---sn-q4fl6nds.gvt1.com.",
"rr5---sn-q4fl6ndz.googlevideo.com.",
- "rr5---sn-q4fl6ndz.gvt1.com.",
"rr5---sn-q4fl6nlz.googlevideo.com.",
- "rr5---sn-q4fl6nlz.gvt1.com.",
"rr5---sn-q4fl6ns6.googlevideo.com.",
- "rr5---sn-q4fl6ns6.gvt1.com.",
"rr5---sn-q4fl6ns7.googlevideo.com.",
"rr5---sn-q4fl6nsd.googlevideo.com.",
+ "rr5---sn-q4fl6nsd.gvt1.com.",
"rr5---sn-q4fl6nsk.googlevideo.com.",
- "rr5---sn-q4fl6nsk.gvt1.com.",
"rr5---sn-q4fl6nsl.googlevideo.com.",
- "rr5---sn-q4fl6nsl.gvt1.com.",
"rr5---sn-q4fl6nsr.googlevideo.com.",
- "rr5---sn-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-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-q4flrne7.googlevideo.com.",
"rr5---sn-q4flrnee.googlevideo.com.",
- "rr5---sn-q4flrnee.gvt1.com.",
"rr5---sn-q4flrnek.googlevideo.com.",
"rr5---sn-q4flrnel.googlevideo.com.",
- "rr5---sn-q4flrnel.gvt1.com.",
"rr5---sn-q4flrner.googlevideo.com.",
- "rr5---sn-q4flrner.gvt1.com.",
"rr5---sn-q4flrnes.googlevideo.com.",
- "rr5---sn-q4flrnes.gvt1.com.",
"rr5---sn-q4flrney.googlevideo.com.",
"rr5---sn-q4flrnez.googlevideo.com.",
- "rr5---sn-q4flrnez.gvt1.com.",
"rr5---sn-q4flrnl6.googlevideo.com.",
"rr5---sn-q4flrnl7.googlevideo.com.",
"rr5---sn-q4flrnld.googlevideo.com.",
"rr5---sn-q4flrnle.googlevideo.com.",
"rr5---sn-q4flrnlz.googlevideo.com.",
- "rr5---sn-q4flrnlz.gvt1.com.",
"rr5---sn-q4flrnsd.googlevideo.com.",
"rr5---sn-q4flrnsk.googlevideo.com.",
- "rr5---sn-q4flrnsk.gvt1.com.",
"rr5---sn-q4flrnsl.googlevideo.com.",
- "rr5---sn-q4flrnsl.gvt1.com.",
"rr5---sn-q4flrnss.googlevideo.com.",
"rr5---sn-q4flrnss.gvt1.com.",
"rr5---sn-q4fzen7e.googlevideo.com.",
"rr5---sn-q4fzen7e.gvt1.com.",
"rr5---sn-q4fzen7l.googlevideo.com.",
- "rr5---sn-q4fzen7l.gvt1.com.",
"rr5---sn-q4fzen7r.googlevideo.com.",
"rr5---sn-q4fzen7r.gvt1.com.",
"rr5---sn-q4fzen7s.googlevideo.com.",
+ "rr5---sn-q4fzen7s.gvt1.com.",
"rr5---sn-q4fzen7y.googlevideo.com.",
"rr5---sn-q4fzene7.googlevideo.com.",
+ "rr5---sn-q4fzene7.gvt1.com.",
"rr5---sn-q4fzenee.googlevideo.com.",
"rr5---sn-qxo7rn7k.googlevideo.com.",
"rr5---sn-qxo7rn7r.googlevideo.com.",
@@ -6540,29 +6618,29 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-qxoedn7k.googlevideo.com.",
"rr5---sn-qxoedne7.googlevideo.com.",
"rr5---sn-qxoednee.googlevideo.com.",
- "rr5---sn-u1hp55-5c.googlevideo.com.",
"rr5---sn-vgqskn66.googlevideo.com.",
"rr5---sn-vgqskn67.googlevideo.com.",
"rr5---sn-vgqskn67.gvt1.com.",
"rr5---sn-vgqskn6d.googlevideo.com.",
+ "rr5---sn-vgqskn6d.gvt1.com.",
"rr5---sn-vgqskn6s.googlevideo.com.",
"rr5---sn-vgqskn6s.gvt1.com.",
"rr5---sn-vgqskn6z.googlevideo.com.",
"rr5---sn-vgqskne6.googlevideo.com.",
"rr5---sn-vgqskned.googlevideo.com.",
"rr5---sn-vgqsknek.googlevideo.com.",
- "rr5---sn-vgqsknek.gvt1.com.",
"rr5---sn-vgqsknes.googlevideo.com.",
"rr5---sn-vgqsknez.googlevideo.com.",
- "rr5---sn-vgqsknez.gvt1.com.",
+ "rr5---sn-vgqsknld.googlevideo.com.",
+ "rr5---sn-vgqsknlk.googlevideo.com.",
+ "rr5---sn-vgqsknlk.gvt1.com.",
"rr5---sn-vgqsknll.googlevideo.com.",
"rr5---sn-vgqsknlr.googlevideo.com.",
- "rr5---sn-vgqsknls.googlevideo.com.",
"rr5---sn-vgqsknly.googlevideo.com.",
"rr5---sn-vgqsknlz.googlevideo.com.",
"rr5---sn-vgqskns7.googlevideo.com.",
- "rr5---sn-vgqskns7.gvt1.com.",
"rr5---sn-vgqsknse.googlevideo.com.",
+ "rr5---sn-vgqsknse.gvt1.com.",
"rr5---sn-vgqsknsk.googlevideo.com.",
"rr5---sn-vgqsknz6.googlevideo.com.",
"rr5---sn-vgqsknz7.googlevideo.com.",
@@ -6572,19 +6650,16 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-vgqsknzk.gvt1.com.",
"rr5---sn-vgqsknzl.googlevideo.com.",
"rr5---sn-vgqsknzr.googlevideo.com.",
- "rr5---sn-vgqsknzr.gvt1.com.",
"rr5---sn-vgqsknzs.googlevideo.com.",
"rr5---sn-vgqsknzy.googlevideo.com.",
"rr5---sn-vgqsknzz.googlevideo.com.",
"rr5---sn-vgqsrn66.googlevideo.com.",
- "rr5---sn-vgqsrn66.gvt1.com.",
"rr5---sn-vgqsrn67.googlevideo.com.",
+ "rr5---sn-vgqsrn67.gvt1.com.",
"rr5---sn-vgqsrn6e.googlevideo.com.",
"rr5---sn-vgqsrn6l.googlevideo.com.",
- "rr5---sn-vgqsrn6l.gvt1.com.",
"rr5---sn-vgqsrn6z.googlevideo.com.",
"rr5---sn-vgqsrne6.googlevideo.com.",
- "rr5---sn-vgqsrne6.gvt1.com.",
"rr5---sn-vgqsrned.googlevideo.com.",
"rr5---sn-vgqsrnek.googlevideo.com.",
"rr5---sn-vgqsrnes.googlevideo.com.",
@@ -6595,37 +6670,48 @@ var FakeECSFQDNs = container.NewMapSet(
"rr5---sn-vgqsrnll.googlevideo.com.",
"rr5---sn-vgqsrnls.googlevideo.com.",
"rr5---sn-vgqsrnls.gvt1.com.",
- "rr5---sn-vgqsrnlz.googlevideo.com.",
"rr5---sn-vgqsrns6.googlevideo.com.",
"rr5---sn-vgqsrnsd.googlevideo.com.",
+ "rr5---sn-vgqsrnsd.gvt1.com.",
"rr5---sn-vgqsrnsr.googlevideo.com.",
"rr5---sn-vgqsrnsy.googlevideo.com.",
"rr5---sn-vgqsrnz6.googlevideo.com.",
- "rr5---sn-vgqsrnz6.gvt1.com.",
"rr5---sn-vgqsrnz7.googlevideo.com.",
"rr5---sn-vgqsrnzd.googlevideo.com.",
"rr5---sn-vgqsrnzk.googlevideo.com.",
- "rr5---sn-vgqsrnzk.gvt1.com.",
"rr5---sn-vgqsrnzr.googlevideo.com.",
"rr5---sn-vgqsrnzs.googlevideo.com.",
"rr5---sn-vgqsrnzs.gvt1.com.",
"rr5---sn-vgqsrnzy.googlevideo.com.",
"rr5---sn-vgqsrnzz.googlevideo.com.",
+ "rr5.sn-5hne6nsd.googlevideo.com.",
+ "rr5.sn-a5mekn6s.googlevideo.com.",
+ "rr5.sn-a5meknde.googlevideo.com.",
+ "rr5.sn-a5mekndz.googlevideo.com.",
"rr5.sn-a5meknzr.googlevideo.com.",
- "rr5.sn-q4fl6nd6.googlevideo.com.",
- "rr5.sn-q4fl6nde.googlevideo.com.",
- "rr5.sn-q4flrnle.googlevideo.com.",
+ "rr5.sn-a5mlrnll.googlevideo.com.",
+ "rr5.sn-a5mlrnlz.googlevideo.com.",
+ "rr5.sn-hp57knds.googlevideo.com.",
+ "rr5.sn-hp57kndy.googlevideo.com.",
+ "rr5.sn-hp57ynse.googlevideo.com.",
+ "rr5.sn-q4fl6nzy.googlevideo.com.",
+ "rr5.sn-q4flrne6.googlevideo.com.",
+ "rr5.sn-q4fzen7s.googlevideo.com.",
+ "rr6---sn-2aqu-hoas7.googlevideo.com.",
+ "rr6---sn-2aqu-hoasz.googlevideo.com.",
"rr6---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
"rr6---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
"rr6---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
"rr6---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
+ "rr6---sn-42u-nbozl.googlevideo.com.",
+ "rr6---sn-42u-nbozs.googlevideo.com.",
+ "rr6---sn-42u-nbozz.googlevideo.com.",
"rr6---sn-5pgnugx5h-hn2z.googlevideo.com.",
- "rr6---sn-8qj-i5ody.googlevideo.com.",
+ "rr6---sn-8qj-i5o6k.googlevideo.com.",
+ "rr6---sn-8qj-i5ozr.googlevideo.com.",
"rr6---sn-8qj-nbo66.googlevideo.com.",
"rr6---sn-8xgp1vo-2iae.googlevideo.com.",
- "rr6---sn-8xgp1vo-2iae7.googlevideo.com.",
"rr6---sn-8xgp1vo-2ial.googlevideo.com.",
- "rr6---sn-8xgp1vo-a5me.googlevideo.com.",
"rr6---sn-8xgp1vo-ab56.googlevideo.com.",
"rr6---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr6---sn-8xgp1vo-ab5e.googlevideo.com.",
@@ -6637,8 +6723,6 @@ var FakeECSFQDNs = container.NewMapSet(
"rr6---sn-8xgp1vo-xfge.googlevideo.com.",
"rr6---sn-8xgp1vo-xfgl.googlevideo.com.",
"rr6---sn-8xgp1vo-xfgs.googlevideo.com.",
- "rr6---sn-bvvbax-2ial.googlevideo.com.",
- "rr6---sn-i5f5ppuxa-ioal.googlevideo.com.",
"rr6---sn-jn2pgx4pcxg-w5os.googlevideo.com.",
"rr6---sn-jvhj5nu-2iae.googlevideo.com.",
"rr6---sn-jvhj5nu-2ial.googlevideo.com.",
@@ -6651,19 +6735,19 @@ var FakeECSFQDNs = container.NewMapSet(
"rr6---sn-jvhj5nu-qufl.googlevideo.com.",
"rr6---sn-jvhj5nu-qufs.googlevideo.com.",
"rr6---sn-jvhj5nu-qufz.googlevideo.com.",
- "rr6---sn-jxopj-n5oe.googlevideo.com.",
- "rr6---sn-jxopj-n5oe.gvt1.com.",
"rr6---sn-jxopj-nh4e.googlevideo.com.",
"rr6---sn-jxopj-nh4e.gvt1.com.",
- "rr6---sn-nv0ui4gvou-hape.googlevideo.com.",
+ "rr7---sn-2aqu-hoas7.googlevideo.com.",
+ "rr7---sn-2aqu-hoasz.googlevideo.com.",
"rr7---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
"rr7---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
"rr7---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
"rr7---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
+ "rr7---sn-42u-nbozl.googlevideo.com.",
+ "rr7---sn-8qj-i5ozd.googlevideo.com.",
+ "rr7---sn-8qj-i5ozr.googlevideo.com.",
"rr7---sn-8qj-nbo66.googlevideo.com.",
"rr7---sn-8xgp1vo-2iae.googlevideo.com.",
- "rr7---sn-8xgp1vo-2ial.googlevideo.com.",
- "rr7---sn-8xgp1vo-a5me.googlevideo.com.",
"rr7---sn-8xgp1vo-ab56.googlevideo.com.",
"rr7---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr7---sn-8xgp1vo-ab5e.googlevideo.com.",
@@ -6672,30 +6756,35 @@ var FakeECSFQDNs = container.NewMapSet(
"rr7---sn-8xgp1vo-ab5z.googlevideo.com.",
"rr7---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr7---sn-8xgp1vo-xfge.googlevideo.com.",
- "rr7---sn-bvvbax-2ial.googlevideo.com.",
"rr7---sn-jvhj5nu-nh4e.googlevideo.com.",
"rr7---sn-jvhj5nu-nh4l.googlevideo.com.",
"rr7---sn-jvhj5nu-nh4z.googlevideo.com.",
+ "rr7---sn-jvhj5nu-qufe.googlevideo.com.",
"rr7---sn-jvhj5nu-qufl.googlevideo.com.",
"rr7---sn-jvhj5nu-qufs.googlevideo.com.",
"rr7---sn-jvhj5nu-qufz.googlevideo.com.",
- "rr7---sn-jxopj-n5oe.googlevideo.com.",
- "rr7---sn-jxopj-n5oe.gvt1.com.",
+ "rr8---sn-2aqu-hoas7.googlevideo.com.",
+ "rr8---sn-2aqu-hoasz.googlevideo.com.",
"rr8---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com.",
"rr8---sn-2vgu0b5auxaxjvh-v2vd.googlevideo.com.",
"rr8---sn-2vgu0b5auxaxjvh-v2ve.googlevideo.com.",
- "rr8---sn-8xgp1vo-2iae.googlevideo.com.",
+ "rr8---sn-2vgu0b5auxaxjvh-v2vl.googlevideo.com.",
+ "rr8---sn-42u-nbozs.googlevideo.com.",
+ "rr8---sn-8qj-i5o6k.googlevideo.com.",
+ "rr8---sn-8qj-i5ozd.googlevideo.com.",
+ "rr8---sn-8qj-i5ozr.googlevideo.com.",
"rr8---sn-8xgp1vo-2ial.googlevideo.com.",
"rr8---sn-8xgp1vo-ab56.googlevideo.com.",
"rr8---sn-8xgp1vo-ab5d.googlevideo.com.",
"rr8---sn-8xgp1vo-ab5e.googlevideo.com.",
"rr8---sn-8xgp1vo-ab5l.googlevideo.com.",
"rr8---sn-8xgp1vo-ab5z.googlevideo.com.",
- "rr8---sn-8xgp1vo-p5ie.googlevideo.com.",
"rr8---sn-8xgp1vo-vgqe.googlevideo.com.",
"rr8---sn-8xgp1vo-xfge.googlevideo.com.",
"rr8---sn-8xgp1vo-xfgl.googlevideo.com.",
- "rr8---sn-bvvbax-2ial.googlevideo.com.",
+ "rr8---sn-bvvbax-2iae.googlevideo.com.",
+ "rr9---sn-2vgu0b5auxaxjvh-apnl.googlevideo.com.",
+ "rr9---sn-8qj-i5ozd.googlevideo.com.",
"rs-stripe.alm.com.",
"rs1.qq.com.",
"rs2.qq.com.",
@@ -6710,80 +6799,86 @@ var FakeECSFQDNs = container.NewMapSet(
"rtb2-eu.xaprio.net.",
"rtb2-useast.xaprio.net.",
"rtb2-uswest.xaprio.net.",
- "rtbasia.com.",
- "rtbbpowaq.com.",
"rtbsuperhub.com.",
- "rtbsystem.com.",
- "rtbwave.com.",
"rttf.citrix.com.",
"ru1.chat.si.riotgames.com.",
+ "ru3419.ci.managedwhitelisting.com.",
+ "rubyfish.cn.",
"ruijienetworks.com.",
- "rum.smartrecruiters.com.",
- "rum22.perf.linkedin.com.",
+ "rule34video.com.",
+ "rum.optimizely.com.",
"rumble.com.",
"rumt-sg.com.",
- "rutgersconnect-my.sharepoint.com.",
+ "rushenterprises.sharepoint.com.",
+ "rutubelist.ru.",
"rxsafeway-my.sharepoint.com.",
"rxsafeway.sharepoint.com.",
"s-cdn.anthropic.com.",
"s-cs.send.microad.jp.",
- "s-light.tiket.photos.",
- "s-pinimg-com-cdn-cloudflare-net.pinimg.com.",
"s-rtb-pb.send.microad.jp.",
+ "s.dblks.net.",
"s.deepl.com.",
"s.exitbee.com.",
"s.optifine.net.",
"s.q.easebar.com.",
"s.seedtag.com.",
+ "s01.live2support.com.",
"s1.thcdn.com.",
- "s3.us-east-005.backblazeb2.com.",
+ "s2-a.time.mci1.us.rozint.net.",
+ "s2-b.time.mci1.us.rozint.net.",
+ "sa.dmv.ca.gov.",
"sa1.chat.si.riotgames.com.",
"sa2.chat.si.riotgames.com.",
"sa3.chat.si.riotgames.com.",
"saas.sensorsdata.com.",
"sabre-sync.quantummetric.com.",
- "safebrowsing.fdown.net.",
+ "safelitegroup-my.sharepoint.com.",
"saintasaph.remotepc.com.",
+ "sales.ai.dynamics.com.",
"salesbridge-my.sharepoint.com.",
+ "salesbridge.sharepoint.com.",
"saltlakecity.remotepc.com.",
+ "samhealthanon.genetec.com.",
+ "samip.genetec.com.",
+ "sampkac.genetec.com.",
"samsclub.quantummetric.com.",
"sanantonio.remotepc.com.",
"sanctionssearch.ofac.treas.gov.",
"sandbox.wdesk.com.",
"sandboxclient.retinavue.net.",
"sandboxregister.retinavue.net.",
+ "sandc4-my.sharepoint.com.",
"sandiego.remotepc.com.",
"sandiegodc.remotepc.com.",
"sanguan.online.",
- "sanjagh.com.",
"sanjose.remotepc.com.",
"santandernet-my.sharepoint.com.",
"santandernet.sharepoint.com.",
"santiago.remotepc.com.",
- "sanxia.studyquicks.com.",
"saopaulo.remotepc.com.",
"saopaulo1.remotepc.com.",
"saskpower-my.sharepoint.com.",
+ "sasoffice365-my.sharepoint.com.",
"saspeed.igamecj.com.",
"sat02pap001.storage.live.com.",
- "sat02pap001files.storage.live.com.",
"sat02pap002.storage.live.com.",
- "sat02pap002files.storage.live.com.",
"sat02pap003.storage.live.com.",
- "sat02pap003files.storage.live.com.",
"sat02pap004.storage.live.com.",
- "sat02pap004files.storage.live.com.",
- "sat02pap005.storage.live.com.",
- "sat02pap005files.storage.live.com.",
- "satismeter.com.",
"sazerac-my.sharepoint.com.",
+ "sazerac.sharepoint.com.",
+ "sb-ssl.brave.com.",
+ "sbcounty.sharepoint.com.",
"sc.zoom.us.",
+ "scanservice1.qg3.apps.qualys.com.",
"scasurgery-my.sharepoint.com.",
+ "scasurgery.sharepoint.com.",
"scdss-my.sharepoint.com.",
+ "scdss.sharepoint.com.",
+ "scheduler.eagle.haplat.net.",
"schneidercorp.com.",
+ "schoolsfirstfcu-my.sharepoint.com.",
"science.blitz.gg.",
"sciener.cn.",
- "scm.capside.com.",
"scontent-ams2-1.cdninstagram.com.",
"scontent-ams2-1.xx.fbcdn.net.",
"scontent-ams4-1.cdninstagram.com.",
@@ -6796,8 +6891,11 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-atl3-2.xx.fbcdn.net.",
"scontent-ber1-1.cdninstagram.com.",
"scontent-ber1-1.xx.fbcdn.net.",
+ "scontent-bkk1-1.xx.fbcdn.net.",
+ "scontent-bkk1-2.xx.fbcdn.net.",
"scontent-bog2-1.cdninstagram.com.",
"scontent-bog2-1.xx.fbcdn.net.",
+ "scontent-bog2-2.cdninstagram.com.",
"scontent-bog2-2.xx.fbcdn.net.",
"scontent-bos5-1.cdninstagram.com.",
"scontent-bos5-1.xx.fbcdn.net.",
@@ -6809,9 +6907,11 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-cdg4-2.xx.fbcdn.net.",
"scontent-cdg4-3.cdninstagram.com.",
"scontent-cdg4-3.xx.fbcdn.net.",
+ "scontent-cgk1-1.cdninstagram.com.",
"scontent-cgk1-1.xx.fbcdn.net.",
"scontent-cgk1-2.cdninstagram.com.",
"scontent-cgk1-2.xx.fbcdn.net.",
+ "scontent-cgk2-1.cdninstagram.com.",
"scontent-cgk2-1.xx.fbcdn.net.",
"scontent-den2-1.cdninstagram.com.",
"scontent-den2-1.xx.fbcdn.net.",
@@ -6821,6 +6921,7 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-dfw5-2.xx.fbcdn.net.",
"scontent-dus1-1.cdninstagram.com.",
"scontent-dus1-1.xx.fbcdn.net.",
+ "scontent-fmx1-1.cdninstagram.com.",
"scontent-fra3-1.cdninstagram.com.",
"scontent-fra3-1.xx.fbcdn.net.",
"scontent-fra3-2.cdninstagram.com.",
@@ -6830,6 +6931,14 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
+ "scontent-gru1-2.xx.fbcdn.net.",
+ "scontent-gru2-1.cdninstagram.com.",
+ "scontent-gru2-1.xx.fbcdn.net.",
+ "scontent-gru2-2.cdninstagram.com.",
+ "scontent-gru2-2.xx.fbcdn.net.",
"scontent-ham3-1.cdninstagram.com.",
"scontent-ham3-1.xx.fbcdn.net.",
"scontent-hel3-1.cdninstagram.com.",
@@ -6863,8 +6972,7 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-lhr8-1.xx.fbcdn.net.",
"scontent-lhr8-2.cdninstagram.com.",
"scontent-lhr8-2.xx.fbcdn.net.",
- "scontent-lis1-1.cdninstagram.com.",
- "scontent-lis1-1.xx.fbcdn.net.",
+ "scontent-los2-1.xx.fbcdn.net.",
"scontent-man2-1.cdninstagram.com.",
"scontent-man2-1.xx.fbcdn.net.",
"scontent-mia3-1.cdninstagram.com.",
@@ -6883,17 +6991,16 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-mty2-1.xx.fbcdn.net.",
"scontent-muc2-1.cdninstagram.com.",
"scontent-muc2-1.xx.fbcdn.net.",
+ "scontent-mxp2-1.cdninstagram.com.",
+ "scontent-mxp2-1.xx.fbcdn.net.",
"scontent-ord5-1.cdninstagram.com.",
"scontent-ord5-1.xx.fbcdn.net.",
"scontent-ord5-2.cdninstagram.com.",
"scontent-ord5-2.xx.fbcdn.net.",
- "scontent-prg1-1.cdninstagram.com.",
- "scontent-prg1-1.xx.fbcdn.net.",
"scontent-qro1-1.cdninstagram.com.",
"scontent-qro1-1.xx.fbcdn.net.",
"scontent-qro1-2.cdninstagram.com.",
"scontent-qro1-2.xx.fbcdn.net.",
- "scontent-scl2-1.cdninstagram.com.",
"scontent-sea1-1.cdninstagram.com.",
"scontent-sea1-1.xx.fbcdn.net.",
"scontent-sin6-1.cdninstagram.com.",
@@ -6907,6 +7014,7 @@ var FakeECSFQDNs = container.NewMapSet(
"scontent-sjc3-1.cdninstagram.com.",
"scontent-sjc3-1.xx.fbcdn.net.",
"scontent-ssn1-1.cdninstagram.com.",
+ "scontent-ssn1-1.xx.fbcdn.net.",
"scontent-tpe1-1.xx.fbcdn.net.",
"scontent-vie1-1.cdninstagram.com.",
"scontent-vie1-1.xx.fbcdn.net.",
@@ -6924,34 +7032,41 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
+ "scripts.grow.me.",
+ "scus-region.present.officeapps.live.com.",
"scus.his.arc.azure.com.",
- "sdk-os.mpsdk.easebar.com.",
+ "scus.his.hybridcompute.trafficmanager.net.",
+ "sdk-event-sg.ap-southeast-1.log.aliyuncs.com.",
"sdk.beizi.biz.",
- "sdk.parone.io.",
+ "sdk.iad-06.braze.com.cdn.cloudflare.net.",
"sdk.qcloud.com.",
+ "sdkgate.pushv3.easebar.com.",
"sdktmp.hubcloud.com.cn.",
"sdn.lxdns.com.",
- "seabroadnet.com.",
+ "se2cds.com.",
"seagate.com.",
"seagullscientific.com.",
- "seal.networksolutions.com.",
"sealsubscriptions.com.",
"search.dnssearch.org.",
"search.namequery.com.",
"search.sunbiz.org.",
"search.us.namequery.com.",
- "searchanise.com.",
"searchnews-dre.dt.dbankcloud.com.",
"searchserverapi.com.",
"seattle.remotepc.com.",
"secaucus.remotepc.com.",
+ "secgw-overseas.base.youku.tv.",
"secure.accurint.com.",
- "secure.paymentech.com.",
"secure.syndetics.com.",
- "secureanalytic.com.",
+ "secure5.arcot.com.",
+ "securej.chase.com.",
+ "securelink.med.usc.edu.",
"securelink.rivhs.com.",
- "securelink.valleywisehealth.org.",
+ "securetheorem.com.",
+ "security.cisco.com.",
"securityapi.d3-pr-tm.com.",
"securitybankcorporation-my.sharepoint.com.",
"securitybankcorporation.sharepoint.com.",
@@ -6959,28 +7074,31 @@ var FakeECSFQDNs = container.NewMapSet(
"seexh.com.",
"send.microad.jp.",
"sendibt3.com.",
- "sensei.ruselabs.com.",
"sensorsdata.cn.",
"sensorsdata.com.",
+ "sentry-webapp.quillbot.com.",
"sentry.appodeal.com.",
"sentry.archive.org.",
- "sentry.ksztone.com.",
"sentry.quillbot.com.",
"sentry.wrike.com.",
"seoul.remotepc.com.",
"serv.vuukle.com.",
"served-by.pixfuture.com.",
- "server.bidstack.com.",
+ "server.10m.com.cn.",
"serverforge.org.",
- "service.ringcentral.com.",
+ "service-aggregation-layer.juno.ea.com.",
"service2.ultipro.com.",
"servicebus101.myconnectsecure.com.",
"servicebus102.myconnectsecure.com.",
- "servicebus103.myconnectsecure.com.",
- "servicebus104.myconnectsecure.com.",
- "servicer.idealmedia.io.",
+ "servicebus1021.myconnectsecure.com.",
+ "servicebus1022.myconnectsecure.com.",
+ "servicebus1023.myconnectsecure.com.",
+ "servicebus1024.myconnectsecure.com.",
+ "servicebus1041.myconnectsecure.com.",
+ "servicebus1042.myconnectsecure.com.",
+ "servicebus1043.myconnectsecure.com.",
+ "servicebus105.myconnectsecure.com.",
"services.lego.com.",
- "services.ucp.kaspersky-labs.com.",
"servicetitan.com.",
"servr.vuukle.com.",
"servt.vuukle.com.",
@@ -6992,27 +7110,27 @@ var FakeECSFQDNs = container.NewMapSet(
"settings.live.net.",
"settings.luckyorange.com.",
"sevenrooms.com.",
+ "sewjn80htn-1.algolianet.com.",
"sewjn80htn-3.algolianet.com.",
- "sexfortokens.com.",
"sf-express.com.",
+ "sg-sdk-event.ap-southeast-1.log.aliyuncs.com.",
"sg.api.translator.voice.gcloudsdk.com.",
"sg.hlth.io.mi.com.",
- "sg.mmstat.com.",
- "sg1.jiedian.stream.",
"sg1a-excel-collab.officeapps.live.com.",
+ "sg1a-powerpoint-collab.officeapps.live.com.",
"sgmbocast.com.",
- "sgminorshort.wechat.com.",
"sgpcas.ezvizlife.com.",
"share.connect.aig.",
"sharpschool.com.",
- "shc6.y.qq.com.",
"shopify-gtm-suite.getelevar.com.",
"shoplazza.com.",
"shortpixel.ai.",
"shoutout.wix.com.",
+ "shp.ee.",
"shuzilm.cn.",
+ "sialiagames.com.tw.",
+ "sigmob.cn.",
"signin.ultipro.com.",
- "silversiri.com.",
"sina.com.",
"sinaimg.cn.",
"sip-backup.phonepower.com.",
@@ -7024,38 +7142,37 @@ var FakeECSFQDNs = container.NewMapSet(
"sip113-1121.ringcentral.com.",
"sip113-1131.ringcentral.com.",
"sip113-1141.ringcentral.com.",
- "sip121-1111.ringcentral.com.",
"sip121-1121.ringcentral.com.",
"sip121-1131.ringcentral.com.",
"sip121-1141.ringcentral.com.",
- "sip121-1241.ringcentral.com.",
+ "sip123-1111.ringcentral.com.",
"sip123-1121.ringcentral.com.",
"sip123-1131.ringcentral.com.",
"sip123-1141.ringcentral.com.",
+ "sip123-1231.ringcentral.com.",
+ "sip123-1241.ringcentral.com.",
"sip131-1121.ringcentral.com.",
"sip131-1131.ringcentral.com.",
"sip131-1141.ringcentral.com.",
"sip131-1231.ringcentral.com.",
- "sip132-1111.ringcentral.com.",
+ "sip131-1241.ringcentral.com.",
"sip132-1121.ringcentral.com.",
"sip132-1131.ringcentral.com.",
"sip132-1141.ringcentral.com.",
"sip421-121.ringcentral.biz.",
"sipis.acrobits.cz.",
+ "sis-ipv6.jpush.cn.",
"site-config.com.",
- "sitemaji.com.",
+ "siteassets.parastorage.com.",
"situsamc365-my.sharepoint.com.",
+ "situsamc365.sharepoint.com.",
"sjc.zoom.us.",
"sjc04pap001.storage.live.com.",
- "sjc04pap001files.storage.live.com.",
"sjc04pap002.storage.live.com.",
- "sjc04pap002files.storage.live.com.",
"skanska-my.sharepoint.com.",
+ "skyglobal.sharepoint.com.",
"skyts.net.",
- "skyward-lisdprod.iscorp.com.",
- "skyward-ocprod.iscorp.com.",
"skyward.iscorp.com.",
- "sl.streamhub.tech.",
"slickdealscdn.com.",
"sm.cn.",
"sm1.selectmedia.asia.",
@@ -7084,13 +7201,12 @@ var FakeECSFQDNs = container.NewMapSet(
"snippet.affilimatejs.com.",
"snokido.com.",
"snz04pap001.storage.live.com.",
- "snz04pap001files.storage.live.com.",
"snz04pap002.storage.live.com.",
- "snz04pap002files.storage.live.com.",
"sobot.com.",
"socialchain.app.",
"sockets.stackexchange.com.",
"sofia.remotepc.com.",
+ "sogo.com.",
"sohu.com.",
"sohucs.com.",
"solid.preyproject.com.",
@@ -7108,6 +7224,7 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-bog2-2.xx.fbcdn.net.",
"sonar-bom1-1.xx.fbcdn.net.",
"sonar-bom1-2.xx.fbcdn.net.",
+ "sonar-bom2-1.xx.fbcdn.net.",
"sonar-bom2-2.xx.fbcdn.net.",
"sonar-bos5-1.xx.fbcdn.net.",
"sonar-bru2-1.xx.fbcdn.net.",
@@ -7122,7 +7239,9 @@ var FakeECSFQDNs = container.NewMapSet(
"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.",
@@ -7132,7 +7251,7 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-eze1-1.xx.fbcdn.net.",
"sonar-fco2-1.xx.fbcdn.net.",
"sonar-fml1-1.xx.fbcdn.net.",
- "sonar-fml20-1.xx.fbcdn.net.",
+ "sonar-fmx1-1.xx.fbcdn.net.",
"sonar-for1-1.xx.fbcdn.net.",
"sonar-fra3-1.xx.fbcdn.net.",
"sonar-fra3-2.xx.fbcdn.net.",
@@ -7141,6 +7260,7 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-gig4-1.xx.fbcdn.net.",
"sonar-gig4-2.xx.fbcdn.net.",
"sonar-gmp1-1.xx.fbcdn.net.",
+ "sonar-gru1-1.xx.fbcdn.net.",
"sonar-gru1-2.xx.fbcdn.net.",
"sonar-gru2-1.xx.fbcdn.net.",
"sonar-gru2-2.xx.fbcdn.net.",
@@ -7226,27 +7346,24 @@ var FakeECSFQDNs = container.NewMapSet(
"sonar-xsp1-2.xx.fbcdn.net.",
"sonar-xsp1-3.xx.fbcdn.net.",
"sonar-xsp2-1.xx.fbcdn.net.",
- "sonar-xxc1-1.xx.fbcdn.net.",
"sonar-yyz1-1.xx.fbcdn.net.",
"sonar-zrh1-1.xx.fbcdn.net.",
"sonar.viously.com.",
"sooners-my.sharepoint.com.",
"sound-ai-stream.alibaba.com.",
+ "sound-machine.com.",
"southcarolina.remotepc.com.",
"southfront.mm.fcix.net.",
- "sp.replit.com.",
+ "southlandind-my.sharepoint.com.",
"spadsync.com.",
"sparteo.com.",
"spc2com-my.sharepoint.com.",
- "spcdn.incartupsell.com.",
- "spec.cloud.360safe.com.",
+ "spc2com.sharepoint.com.",
"spectrumhealth-my.sharepoint.com.",
"spectrumhealth.sharepoint.com.",
- "speedtest.asymptote.cc.",
- "speedtest.sjc.timkevin.us.",
+ "speedtest.dailymotion.com.",
"spiny.ai.",
"spion.savvy.security.",
- "splash-online-decision.xiaohongshu.com.",
"springfieldclinic-my.sharepoint.com.",
"springfieldclinic.sharepoint.com.",
"src.ebay-us.com.",
@@ -7254,27 +7371,28 @@ var FakeECSFQDNs = container.NewMapSet(
"ssafp.samsclub.com.",
"ssc.independent.co.uk.",
"ssctech.com.",
+ "ssimn.org.",
"ssl.geoplugin.net.",
- "sso.8x8.com.",
- "sso.readingeggs.com.",
+ "ssl.translatoruser.net.",
+ "ssl.vizury.com.",
"sso.services.box.net.",
"ssp.hbrd.io.",
"ssp.hybrid.ai.",
+ "sss.pk-live.cn.",
"sstatic.net.",
- "ssxd.mediav.com.",
"st-sysupgrade.vivo.com.cn.",
- "st.edge.oregon.edge2.salesforce.com.",
- "stack.imgur.com.",
+ "st15.lvhyww.com.",
"staffbase.com.",
+ "staging-bam.nr-data.net.",
+ "standaard.be.",
+ "standard-svr-terminal.transsion-message.com.",
"stardustgod.com.",
+ "starrydyn.com.",
"startssl.com.",
"stat.gspaceteam.com.",
"stat.lianmeng.360.cn.",
- "stat.mixi.media.",
"stat.pdfforge.org.",
"statad.ru.",
- "static-ams2-1.xx.fbcdn.net.",
- "static-ams4-1.xx.fbcdn.net.",
"static-atl3-1.xx.fbcdn.net.",
"static-atl3-2.xx.fbcdn.net.",
"static-bos5-1.xx.fbcdn.net.",
@@ -7288,11 +7406,8 @@ 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-lhr8-2.xx.fbcdn.net.",
- "static-man2-1.xx.fbcdn.net.",
"static-mia3-1.xx.fbcdn.net.",
"static-mia3-2.xx.fbcdn.net.",
"static-msp1-1.xx.fbcdn.net.",
@@ -7301,56 +7416,50 @@ var FakeECSFQDNs = container.NewMapSet(
"static-sea1-1.xx.fbcdn.net.",
"static-sjc3-1.xx.fbcdn.net.",
"static.avito.ru.",
+ "static.ctctcdn.com.",
"static.fastly.carvana.io.",
"static.independent.co.uk.",
- "static.standard.co.uk.",
+ "static.parastorage.com.",
"static.thcdn.com.",
- "static.writable.com.",
"static.zara.net.",
- "static1.mixi.media.",
"static2.mixi.media.",
- "static4.mixi.media.",
- "static8.mixi.media.",
- "statistic.live.126.net.",
+ "static5.mixi.media.",
+ "static6.mixi.media.",
"stats.adinplay.com.",
"stats.aeries.com.",
- "stats.bannernow.com.",
- "stats.dell.com.",
- "stats.ftb.ca.gov.",
+ "stats.mightytext.co.",
"stats.rip.",
- "stats.studyquicks.com.",
"stats.transitapp.com.",
- "statsapi.mlb.com.cdn.cloudflare.net.",
"statsig.anthropic.com.",
+ "stblaw0-my.sharepoint.com.",
"stcharleshealthsystem-my.sharepoint.com.",
- "steamcommunity.com.",
+ "stcharleshealthsystem.sharepoint.com.",
"stemchristie.rome2rio.com.",
"stericyclecorp-my.sharepoint.com.",
+ "stewarttitle-my.sharepoint.com.",
"stg-data-in.ads.heytapmobile.com.",
"stg-data.ads.heytapmobi.com.",
+ "stl.us.ssimn.org.",
"stockholm.remotepc.com.",
"stocks-analytics-events.apple.com.",
- "storage.procore.com.",
+ "storage.cloud.kargo.com.",
"storagecraft.com.",
"store-dra.hispace.dbankcloud.cn.",
"store.qq.com.",
- "stream-production.avcdn.net.akamaized.net.",
- "streamhub.tech.",
+ "store.ubi.com.",
"streetviewpixels-pa.googleapis.com.",
"stse02.ultipro.com.",
"stsew02.ultipro.com.",
"stsn02.ultipro.com.",
"student.atitesting.com.",
- "studentjths-my.sharepoint.com.",
- "studentsecisd-my.sharepoint.com.",
- "studentsecuedu66932-my.sharepoint.com.",
- "studentsecuedu66932.sharepoint.com.",
- "studenttuhsd-my.sharepoint.com.",
- "studenttuhsd.sharepoint.com.",
+ "studio.airtory.com.",
"studyquicks.com.",
- "stun-anycast.l.google.com.",
+ "stun.2talk.com.",
+ "stun.acrobits.cz.",
"stun.cdnbye.com.",
"stun.l.google.com.",
+ "stun.voxgratia.org.",
+ "stun1.l.google.com.",
"stun1.ringcentral.com.",
"stun101.signon.gravityshavings.net.",
"stun102.signon.gravityshavings.net.",
@@ -7360,29 +7469,30 @@ var FakeECSFQDNs = container.NewMapSet(
"stun106.signon.gravityshavings.net.",
"stun107.signon.gravityshavings.net.",
"stun108.signon.gravityshavings.net.",
+ "stun2.l.google.com.",
"stun2.ringcentral.com.",
+ "stun3.l.google.com.",
+ "stun4.l.google.com.",
"stvinc-my.sharepoint.com.",
- "subs.theepochtimes.com.",
"subway-sync.quantummetric.com.",
+ "suggest.v-mate.mobi.",
"sumari-prod-1.srv.jbisumari.org.",
"sumologic.com.",
- "sunamerica.com.",
"sunmedia.tv.",
"sunmi.com.",
"sunnbird.com.",
"sunocoinc-my.sharepoint.com.",
"sunocoinc.sharepoint.com.",
"supl.qxwz.com.",
- "support-leagueoflegends.riotgames.com.",
"support.powerschool.com.",
- "surgerypartners-my.sharepoint.com.",
+ "suramericana-my.sharepoint.com.",
"sutterhealth-my.sharepoint.com.",
"sutterhealth.sharepoint.com.",
"sv8.cyberhaven.io.",
- "svgrepo.com.",
"svlive.serraview.com.",
"swifttrans-my.sharepoint.com.",
"switch.babybus.com.",
+ "swsim.stamps.com.",
"sydney.remotepc.com.",
"sync-1-us-west1-g.sync.services.mozilla.com.",
"sync.bidence.net.",
@@ -7392,71 +7502,90 @@ var FakeECSFQDNs = container.NewMapSet(
"syndetics.com.",
"systemreportservices.genetec.com.",
"t-odx.op-mobile.opera.com.",
- "t.360playvid.info.",
"t.adcell.com.",
+ "t.exitbee.com.",
"t.marketingcloudfx.com.",
"t.mookie1.com.",
"t.poki.io.",
- "t.wepay.com.",
"t3.nhentai.net.",
"t3.xiaohongshu.com.",
"tag.winister.app.",
- "tags.growingio.com.",
+ "tagcommander.com.",
"tags.natwest.com.",
- "taipei.remotepc.com.",
+ "talk-websocket.hyvor.com.",
"tampa.remotepc.com.",
"tanx.com.",
- "tao.barstoolsports.com.",
"taobao.com.",
"tapecontent.net.",
+ "target.digitalaudience.io.",
"tarrantcounty-my.sharepoint.com.",
"tasteofhome.com.",
"tatracker-us.rivergame.net.",
"taylorfarms1com-my.sharepoint.com.",
"tbcache.com.",
"tbcdn.cn.",
+ "tbxkhv-launches.appsflyersdk.com.",
"tccprod01.honeywell.com.",
+ "tccprod01.resideo.com.",
"tccprod02.honeywell.com.",
+ "tccprod02.resideo.com.",
"tccprod03.honeywell.com.",
+ "tccprod03.resideo.com.",
"tcdnlive.com.",
- "tch.quora.com.",
"tclclouds.com.",
"tdcservices.tandemdiabetes.com.",
"tdm.qq.com.",
"teams.microsoft.com.",
+ "teams.office.com.",
"teamviewer.com.",
+ "tec-do.cn.",
"teddymobile.cn.",
- "telaviv.remotepc.com.",
"telecom.shuzilm.cn.",
+ "telegraph-sync.quantummetric.com.",
"telemetry-sdk-inmobi-comtm.trafficmanager.net.",
- "telemetry.sdk.inmobi.com.",
+ "telemetry.docusign.net.",
+ "telemetry.savvy.security.",
"telephony.goog.",
+ "teleport.media.",
"tencent-cloud.com.",
"tencent-cloud.net.",
"tencentmusic.com.",
"tenda.com.cn.",
+ "tenethealth-my.sharepoint.com.",
"tenpay.com.",
+ "terabox.app.",
+ "terabox.com.",
+ "terabox1024.com.",
+ "teraboxapp.com.",
+ "teraswitch.com.",
"terms3.hicloud.com.",
- "testnjjhb.com.",
- "text.com.",
+ "tgp.qq.com.",
"tgpa.qq.com.",
"thanhnien.vn.",
+ "thecityoftulsa-my.sharepoint.com.",
+ "thenetworkpro.net.",
"theoks.net.",
- "thetracker.org.",
- "think12stg.wpengine.com.",
"thinkific.com.",
"thinkingdata.cn.",
"thm.visa.com.",
"thm12.visa.com.",
- "thumb-v1.xhcdn.com.",
- "thumb-v3.xhcdn.com.",
- "thumb-v4.xhcdn.com.",
- "thumb-v8.xhcdn.com.",
- "thumb.live.mmcdn.com.",
- "tickets.com.",
+ "thumb-v0.xhcdn.com.",
"tigermailauburn-my.sharepoint.com.",
+ "tigermailauburn.sharepoint.com.",
"tile.openstreetmap.org.",
"tile.osm.org.",
+ "time-a-b.nist.gov.",
+ "time-a-g.nist.gov.",
+ "time-a.nist.gov.",
+ "time-a.timefreq.bldrdoc.gov.",
+ "time-b-b.nist.gov.",
+ "time-b-g.nist.gov.",
+ "time-b.nist.gov.",
+ "time-b.timefreq.bldrdoc.gov.",
+ "time-c-b.nist.gov.",
+ "time-c-g.nist.gov.",
+ "time-c.timefreq.bldrdoc.gov.",
+ "time-nw.nist.gov.",
"time.ecansol.net.",
"time.lmtlabs.com.",
"time.nest.com.",
@@ -7471,73 +7600,110 @@ var FakeECSFQDNs = container.NewMapSet(
"time4.google.com.",
"timi-esports.qq.com.",
"timken-my.sharepoint.com.",
+ "tk-ot.advlion.com.",
+ "tkda.mosspf.com.",
+ "tkda.mossru.com.",
"tkx.mp.lura.live.",
"tlivecdn.com.",
"tlivesource.com.",
"tls-amap.dingtalk.com.",
"tls12.eu01.nr-data.net.cdn.cloudflare.net.",
"tls12.newrelic.com.cdn.cloudflare.net.",
+ "tlsext.com.",
"tm.barclays.co.uk.",
"tm.bdc-cdn.com.",
"tm.cybersource.com.",
"tm.regions.com.",
"tmall.com.",
+ "tmbbank-my.sharepoint.com.",
+ "tmbbank.sharepoint.com.",
"tmc-g2.tm-4.office.com.",
- "tmfp.klarna.com.",
+ "tmfsdktcp.m.qq.com.",
"tmga.qq.com.",
"tmge.alicdn.com.",
"tmobile-sync.quantummetric.com.",
+ "tmx.bestbuy.com.",
"tmx.tdbank.com.",
"tmx.uptodate.com.",
"tngdigital.com.my.",
+ "together.plex.tv.",
"tokyo.remotepc.com.",
"tollbrothersinc-my.sharepoint.com.",
"tollbrothersinc.sharepoint.com.",
- "top-widgets-va.us-east-1.log.aliyuncs.com.",
"toronto.remotepc.com.",
- "tos-prd-api-mgmt.azure-api.net.",
- "totallyacdn.com.",
"towerhealth-my.sharepoint.com.",
+ "towerhealth.sharepoint.com.",
"tplay.qq.com.",
+ "tpns.gz2.tencent.com.",
"tpns.sgp.tencent.com.",
"tpns.sh.tencent.com.",
"tpns.tencent.com.",
"tpsservice-files-inner.cn-hangzhou.oss-cdn.aliyun-inc.com.",
+ "tr-tmc-geo.office.com.",
"tr.p.360.cn.",
"tr1.chat.si.riotgames.com.",
+ "tra-ac-ae.apktorrents.com.",
+ "tra-ac-ae2.apktorrents.com.",
+ "tra-ac-ae2.best82.com.",
+ "tra-ac-id.apktorrents.com.",
+ "tra-ac-id.best82.com.",
+ "tra-ac-id2.apktorrents.com.",
+ "tra-ac-id2.best82.com.",
+ "tra-ac-ind.apktorrents.com.",
+ "tra-ac-ind.best82.com.",
+ "tra-ac-mas.apktorrents.com.",
+ "tra-ac-mas.best82.com.",
+ "tra-hz-de.hyper-torrent.com.",
+ "tra-hz-fl.hyper-torrent.com.",
+ "tra-lwb-sg.best61.com.",
+ "tra-s4-us.best61.com.",
+ "tra-tc-ind.apktorrents.com.",
+ "tra-tc-ind.best82.com.",
+ "tra-the-br.apktorrents.com.",
+ "tra-the-br.best82.com.",
+ "tra-the-tr.apktorrents.com.",
+ "tra-the-tr.best82.com.",
+ "tra-ved-br.apktorrents.com.",
+ "tra-ved-br.best82.com.",
+ "tra-ved-in.apktorrents.com.",
+ "tra-ved-in.best82.com.",
+ "tra-ved-ru.apktorrents.com.",
+ "tra-ved-ru.best82.com.",
"trace.qq.com.",
"track-eu1.hubspot.com.",
"track.loopme.me.",
"track.sendlane.com.",
+ "track.tubrtb.com.",
+ "trackedlink.net.",
"tracker-udp.gbitt.info.",
+ "tracker.auctor.tv.",
+ "tracker.best61.com.",
"tracker.ccp.ovh.",
"tracker.files.fm.",
"tracker.grepler.com.",
- "tracker.moeking.me.",
+ "tracker.hownetwork.xyz.",
+ "tracker.hyper-torrent.com.",
"tracker.nitropay.com.",
"tracker.nwps.ws.",
"tracker.theoks.net.",
"tracker.therarbg.com.",
"tracker1.bt.moack.co.kr.",
+ "tracker1.myporn.club.",
"tracker2.dler.org.",
- "tracking.eu.antskre.com.",
+ "tracking.eu.flamtyr.com.",
"tracking.ksztone.com.",
- "tractor.attn.tv.",
"tradplusad.com.",
+ "transactional-api.hu-manity.co.",
"transplace-my.sharepoint.com.",
"transsion-miniapp-android-cdn.oss-eu-central-1.aliyuncs.com.",
"traversal.syncromsp.com.",
"treas.gov.",
"treasury.gov.",
- "tremfya.com.",
"tribalfusion.com.",
- "trk-assets.nutigeneby.com.",
"trovit.com.",
- "ts1.mm.bing.net.",
+ "trxpg.com.",
"ts1.qq.com.",
- "ts2.mm.bing.net.",
"ts2.qq.com.",
- "ts3.mm.bing.net.",
"tse1.explicit.bing.net.",
"tse1.mm.bing.net.",
"tse2.explicit.bing.net.",
@@ -7546,35 +7712,51 @@ var FakeECSFQDNs = container.NewMapSet(
"tse3.mm.bing.net.",
"tse4.explicit.bing.net.",
"tse4.mm.bing.net.",
- "tsg-hdp-raw-log.data.cn-singapore-lls01-d01.sls-pub.farlightgames.com.",
- "tsms-dre.security.dbankcloud.com.",
+ "tt-s.junklyads.com.",
"tt.browser.360.cn.",
"ttcache.com.",
"ttigroup-my.sharepoint.com.",
+ "ttigroup.sharepoint.com.",
"ttuhscep.cyberhaven.io.",
"tubecup.net.",
- "tuhsdk12azus-my.sharepoint.com.",
"tunnel.googlezip.net.",
+ "tunnel.web.trustedsource.org.",
"tuoitre.vn.",
"tusd1-my.sharepoint.com.",
"tuya.com.",
"tw.ntp.org.cn.",
+ "tw2.cdn.adtwister.me.",
"twcgov-my.sharepoint.com.",
+ "twcgov.sharepoint.com.",
+ "twcloud2.ucbj.net.",
+ "twcloudgz1.ucbj.net.",
+ "tx-mirror.tier.net.",
+ "txcomptroller-my.sharepoint.com.",
+ "txdot-my.sharepoint.com.",
"txdot.sharepoint.com.",
"txoag-my.sharepoint.com.",
+ "txoag.okta.com.",
+ "txoag.sharepoint.com.",
"tyjr-fgj.aliyun.com.vipgds.alibabadns.com.",
"u.4dex.io.",
"uapi.mp.360.cn.",
"uber.zoom.us.",
- "uc.chatra-usercontent.com.",
+ "ublockorigin.pages.dev.",
"uc.cn.",
- "ucus.ucweb.com.",
+ "uchc-my.sharepoint.com.",
+ "uci-my.sharepoint.com.",
+ "uci.sharepoint.com.",
"ucweb.com.",
"udemycdn.com.",
"udesk.cn.",
- "ue.lenovomm.cn.",
"uk-api.asm.skype.com.",
"uk-prod.asyncgw.teams.microsoft.com.",
+ "uk3-excel-collab.officeapps.live.com.",
+ "uk3-powerpoint-collab.officeapps.live.com.",
+ "uk3-word-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.",
"uks.his.arc.azure.com.",
@@ -7587,10 +7769,10 @@ var FakeECSFQDNs = container.NewMapSet(
"ultipro.com.",
"ultiprotime.com.",
"ultiproworkplace.com.",
+ "umami.is.",
"umeng.com.",
- "uncw4-my.sharepoint.com.",
- "uncw4.sharepoint.com.",
"unicom.shuzilm.cn.",
+ "unification.useinsider.com.",
"unified-inbox-1-gw.ultipro.com.",
"unified-inbox-2-gw.ultipro.com.",
"union.barstoolsports.com.",
@@ -7600,49 +7782,52 @@ var FakeECSFQDNs = container.NewMapSet(
"united.quantummetric.com.",
"unitrends.com.",
"unity.cn.",
- "universityofwieauclaire-my.sharepoint.com.",
+ "unls.mep.go.cr.",
+ "uodoo.com.",
"update.360safe.com.",
- "update.ee-share.com.",
"update.huorong.cn.",
"update.kingsoftstore.com.",
- "update.logmein.com.",
+ "update.pdfforge.org.",
"update.vivaldi.com.",
"updatechannel.sharegate.com.",
"updaterservices.genetec.com.",
"updatesnl.macrium.com.",
- "upload.app.box.com.",
- "upload.box.com.",
- "upload.ent.box.com.",
- "upload.gifshow.com.",
- "upload.ksapisrv.com.",
"uploads.gamecoast.net.",
"upravel.com.",
"upremium.asia.",
- "upward-app.com.",
"urekamedia.com.",
"us-01.ws-api.ringcentral.com.",
"us-02.ws-api.ringcentral.com.",
"us-03.ws-api.ringcentral.com.",
+ "us-04.ws-api.ringcentral.com.",
+ "us-05.ws-api.ringcentral.com.",
+ "us-06.ws-api.ringcentral.com.",
"us-api.asm.skype.com.",
"us-atl-anx-r001.router.teamviewer.com.",
+ "us-atl-anx-r002.router.teamviewer.com.",
+ "us-atl-anx-r003.router.teamviewer.com.",
+ "us-atl-anx-r004.router.teamviewer.com.",
+ "us-atl-anx-r005.router.teamviewer.com.",
+ "us-atl-anx-r006.router.teamviewer.com.",
+ "us-atl-anx-r008.router.teamviewer.com.",
+ "us-atl-anx-r009.router.teamviewer.com.",
"us-atl-anx-r010.router.teamviewer.com.",
+ "us-c.docebopaas.com.",
"us-central1-adaptive-growth.cloudfunctions.net.",
"us-central1-addshoppers-data-production.cloudfunctions.net.",
"us-central1-aeo-datasci-microsrv-pr-afe8.cloudfunctions.net.",
- "us-central1-affilimate.cloudfunctions.net.",
+ "us-central1-ah-acemarketingteam.cloudfunctions.net.",
"us-central1-amp-error-reporting.cloudfunctions.net.",
"us-central1-blaze-today.cloudfunctions.net.",
"us-central1-bps-oi-production.cloudfunctions.net.",
- "us-central1-buzz-3eeb8.cloudfunctions.net.",
"us-central1-castify-notifications-prod.cloudfunctions.net.",
+ "us-central1-clubroom-prod.cloudfunctions.net.",
"us-central1-cohinc-146020.cloudfunctions.net.",
"us-central1-digitalproducts-gabbo.cloudfunctions.net.",
"us-central1-ds-specials-dev.cloudfunctions.net.",
"us-central1-esi-consumer.cloudfunctions.net.",
- "us-central1-fail1v1.cloudfunctions.net.",
"us-central1-fsgenergy-shared.cloudfunctions.net.",
"us-central1-gaggle-staging.cloudfunctions.net.",
- "us-central1-justbuild-cdb86.cloudfunctions.net.",
"us-central1-live-prod-1-1.cloudfunctions.net.",
"us-central1-locket-4252a.cloudfunctions.net.",
"us-central1-mikmak-microservices.cloudfunctions.net.",
@@ -7652,12 +7837,18 @@ var FakeECSFQDNs = container.NewMapSet(
"us-central1-shopify-instrumentat-ff788286.cloudfunctions.net.",
"us-central1-speechifymobile.cloudfunctions.net.",
"us-central1-sq-sgtm-prod.cloudfunctions.net.",
- "us-central1-teach-monster.cloudfunctions.net.",
- "us-central1-webgltest-17af1.cloudfunctions.net.",
- "us-central1-wetterapp-1.cloudfunctions.net.",
"us-central1-wise-arch-107501.cloudfunctions.net.",
"us-central1-wrapper-analytics-prod.cloudfunctions.net.",
+ "us-chi-anx-r001.router.teamviewer.com.",
+ "us-chi-anx-r002.router.teamviewer.com.",
+ "us-chi-anx-r004.router.teamviewer.com.",
+ "us-chi-anx-r005.router.teamviewer.com.",
+ "us-cmh-gcp-r001.router.teamviewer.com.",
+ "us-cmh-gcp-r002.router.teamviewer.com.",
+ "us-cmh-gcp-r004.router.teamviewer.com.",
+ "us-cmh-gcp-r005.router.teamviewer.com.",
"us-dal-anx-r001.router.teamviewer.com.",
+ "us-dal-anx-r002.router.teamviewer.com.",
"us-dal-anx-r003.router.teamviewer.com.",
"us-dal-anx-r004.router.teamviewer.com.",
"us-dal-anx-r005.router.teamviewer.com.",
@@ -7666,53 +7857,133 @@ var FakeECSFQDNs = container.NewMapSet(
"us-dal-anx-r008.router.teamviewer.com.",
"us-dal-anx-r009.router.teamviewer.com.",
"us-dal-anx-r010.router.teamviewer.com.",
+ "us-dal-gcp-r001.router.teamviewer.com.",
+ "us-dal-gcp-r002.router.teamviewer.com.",
+ "us-dal-gcp-r003.router.teamviewer.com.",
+ "us-dal-gcp-r004.router.teamviewer.com.",
+ "us-dal-gcp-r005.router.teamviewer.com.",
+ "us-den-anx-r002.router.teamviewer.com.",
+ "us-den-anx-r003.router.teamviewer.com.",
+ "us-den-anx-r005.router.teamviewer.com.",
+ "us-den-anx-r006.router.teamviewer.com.",
+ "us-den-anx-r007.router.teamviewer.com.",
+ "us-den-anx-r008.router.teamviewer.com.",
"us-east-1.log.aliyuncs.com.",
"us-east4-chkp-gcp-rnd-threat-hunt-box.cloudfunctions.net.",
+ "us-hnl-anx-r001.router.teamviewer.com.",
+ "us-iad-gcp-r001.router.teamviewer.com.",
+ "us-iad-gcp-r002.router.teamviewer.com.",
+ "us-iad-gcp-r003.router.teamviewer.com.",
+ "us-iad-gcp-r004.router.teamviewer.com.",
+ "us-iad-gcp-r005.router.teamviewer.com.",
+ "us-las-gcp-r001.router.teamviewer.com.",
+ "us-las-gcp-r002.router.teamviewer.com.",
+ "us-las-gcp-r003.router.teamviewer.com.",
+ "us-las-gcp-r005.router.teamviewer.com.",
"us-lax-anx-r003.router.teamviewer.com.",
"us-lax-anx-r006.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-r010.router.teamviewer.com.",
+ "us-lax-anx-r011.router.teamviewer.com.",
"us-lax-anx-r012.router.teamviewer.com.",
"us-lax-anx-r013.router.teamviewer.com.",
- "us-lax-anx-r014.router.teamviewer.com.",
"us-lax-anx-r015.router.teamviewer.com.",
+ "us-lax-gcp-r001.router.teamviewer.com.",
+ "us-lax-gcp-r002.router.teamviewer.com.",
+ "us-lax-gcp-r003.router.teamviewer.com.",
"us-lax-gcp-r005.router.teamviewer.com.",
"us-mia-anx-r003.router.teamviewer.com.",
+ "us-mia-anx-r004.router.teamviewer.com.",
+ "us-mia-anx-r005.router.teamviewer.com.",
"us-mia-anx-r006.router.teamviewer.com.",
+ "us-mia-anx-r007.router.teamviewer.com.",
+ "us-mia-anx-r008.router.teamviewer.com.",
+ "us-mia-anx-r009.router.teamviewer.com.",
+ "us-mia-anx-r010.router.teamviewer.com.",
"us-mia-anx-r011.router.teamviewer.com.",
"us-mia-anx-r012.router.teamviewer.com.",
- "us-njc-anx-r008.router.teamviewer.com.",
+ "us-mia-anx-r013.router.teamviewer.com.",
+ "us-mia-anx-r014.router.teamviewer.com.",
+ "us-mia-anx-r015.router.teamviewer.com.",
+ "us-mks-gcp-r001.router.teamviewer.com.",
+ "us-mks-gcp-r002.router.teamviewer.com.",
+ "us-mks-gcp-r003.router.teamviewer.com.",
+ "us-mks-gcp-r005.router.teamviewer.com.",
+ "us-njc-anx-r002.router.teamviewer.com.",
+ "us-njc-anx-r003.router.teamviewer.com.",
+ "us-njc-anx-r004.router.teamviewer.com.",
+ "us-njc-anx-r005.router.teamviewer.com.",
+ "us-njc-anx-r006.router.teamviewer.com.",
+ "us-njc-anx-r007.router.teamviewer.com.",
+ "us-njc-anx-r009.router.teamviewer.com.",
+ "us-njc-anx-r010.router.teamviewer.com.",
+ "us-njc-anx-r011.router.teamviewer.com.",
+ "us-njc-anx-r012.router.teamviewer.com.",
"us-njc-anx-r013.router.teamviewer.com.",
"us-njc-anx-r014.router.teamviewer.com.",
+ "us-njc-anx-r015.router.teamviewer.com.",
+ "us-njc-anx-r016.router.teamviewer.com.",
+ "us-njc-anx-r017.router.teamviewer.com.",
"us-njc-anx-r018.router.teamviewer.com.",
+ "us-njc-anx-r019.router.teamviewer.com.",
+ "us-oma-gcp-r001.router.teamviewer.com.",
"us-oma-gcp-r002.router.teamviewer.com.",
+ "us-oma-gcp-r003.router.teamviewer.com.",
+ "us-oma-gcp-r004.router.teamviewer.com.",
+ "us-oma-gcp-r005.router.teamviewer.com.",
+ "us-pdx-gcp-r001.router.teamviewer.com.",
+ "us-pdx-gcp-r002.router.teamviewer.com.",
+ "us-pdx-gcp-r003.router.teamviewer.com.",
+ "us-pdx-gcp-r004.router.teamviewer.com.",
+ "us-pdx-gcp-r005.router.teamviewer.com.",
"us-pftk-temu-com.trafficmanager.net.",
"us-prod.asyncgw.teams.microsoft.com.",
"us-sea-anx-r001.router.teamviewer.com.",
"us-sea-anx-r002.router.teamviewer.com.",
"us-sea-anx-r003.router.teamviewer.com.",
- "us-sea-anx-r004.router.teamviewer.com.",
"us-sea-anx-r005.router.teamviewer.com.",
+ "us-sea-anx-r006.router.teamviewer.com.",
"us-sea-anx-r007.router.teamviewer.com.",
+ "us-slc-gcp-r001.router.teamviewer.com.",
+ "us-slc-gcp-r002.router.teamviewer.com.",
+ "us-slc-gcp-r004.router.teamviewer.com.",
+ "us-slc-gcp-r005.router.teamviewer.com.",
"us-spectrum.rcs.telephony.goog.",
+ "us-was-anx-r001.router.teamviewer.com.",
+ "us-was-anx-r002.router.teamviewer.com.",
+ "us-was-anx-r003.router.teamviewer.com.",
+ "us-was-anx-r004.router.teamviewer.com.",
+ "us-was-anx-r005.router.teamviewer.com.",
+ "us-was-anx-r006.router.teamviewer.com.",
+ "us-was-anx-r007.router.teamviewer.com.",
+ "us-was-anx-r008.router.teamviewer.com.",
+ "us-was-anx-r009.router.teamviewer.com.",
+ "us-was-anx-r010.router.teamviewer.com.",
+ "us-was-anx-r011.router.teamviewer.com.",
"us-was-anx-r012.router.teamviewer.com.",
+ "us-was-anx-r013.router.teamviewer.com.",
+ "us-was-anx-r014.router.teamviewer.com.",
+ "us-was-anx-r015.router.teamviewer.com.",
+ "us-was-anx-r016.router.teamviewer.com.",
+ "us-was-anx-r017.router.teamviewer.com.",
+ "us-was-anx-r018.router.teamviewer.com.",
"us-was-anx-r019.router.teamviewer.com.",
"us-was-anx-r020.router.teamviewer.com.",
"us-west-1.log.aliyuncs.com.",
+ "us-west-2.console.aws.amazon.com.",
"us.att.rcs.telephony.goog.",
"us.evidation.com.",
- "us.peerhub.net.",
"us.pftk.temu.com.",
"us.tmobile.rcs.telephony.goog.",
"us.tracfone.rcs.telephony.goog.",
"us.uscc.rcs.telephony.goog.",
"us.xfinity.rcs.telephony.goog.",
- "us02.ws-api.ringcentral.com.",
"us02log.zoom.us.",
"us02polling.zoom.us.",
"us02web.zoom.us.",
"us02www3.zoom.us.",
- "us03.ws-api.ringcentral.com.",
"us04asyncim.zoom.us.",
"us04nws-platform.zoom.us.",
"us04nws.zoom.us.",
@@ -7727,43 +7998,72 @@ var FakeECSFQDNs = container.NewMapSet(
"us06web.zoom.us.",
"us06www3.zoom.us.",
"us1.ecdn2.badoocdn.com.",
- "us1.ecdn2.bumbcdn.com.",
- "us2.iceporn.xxx.",
"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.officeapps.live.com.",
+ "us4a-excel-collab.officeapps.live.com.",
+ "us4a-powerpoint-collab.officeapps.live.com.",
+ "us4a-word-collab.officeapps.live.com.",
+ "us4b-excel-collab.ocs.trafficmanager.net.",
+ "us4b-excel-collab.officeapps.live.com.",
+ "us4b-powerpoint-collab.ocs.trafficmanager.net.",
+ "us4b-powerpoint-collab.officeapps.live.com.",
+ "us4b-word-collab.ocs.trafficmanager.net.",
+ "us4b-word-collab.officeapps.live.com.",
+ "us4s-excel-collab.officeapps.live.com.",
+ "us4s-powerpoint-collab.officeapps.live.com.",
"us4s-word-collab.officeapps.live.com.",
+ "us7-excel-collab.ocs.trafficmanager.net.",
+ "us7-excel-collab.officeapps.live.com.",
+ "us7-powerpoint-collab.officeapps.live.com.",
+ "us7-word-collab.officeapps.live.com.",
+ "us8-excel-collab.ocs.trafficmanager.net.",
+ "us8-excel-collab.officeapps.live.com.",
+ "us8-powerpoint-collab.ocs.trafficmanager.net.",
+ "us8-powerpoint-collab.officeapps.live.com.",
+ "us8-word-collab.officeapps.live.com.",
+ "us8.five9.com.",
+ "us8n-excel-collab.officeapps.live.com.",
+ "us8n-powerpoint-collab.officeapps.live.com.",
+ "us9.five9.com.",
"usbank.quantummetric.com.",
+ "usc-collabrtc-geo.rtc.trafficmanager.net.",
+ "usc-collabrtc.officeapps.live.com.",
+ "usc-excel-collab-geo.ocs.trafficmanager.net.",
"usc-excel-collab.officeapps.live.com.",
"usc-powerpoint-collab.officeapps.live.com.",
"usc-word-collab.officeapps.live.com.",
- "uscourts.gov.",
- "useinsider.com.",
- "usemotion.com.",
- "user.jpush.cn.",
- "userexperience.thehut.net.",
+ "usc.edu.",
+ "user.auth.xboxlive.com.",
"userflow.com.",
"userlike.com.",
+ "usgcorp-my.sharepoint.com.",
"usgcorp.sharepoint.com.",
"usgs.gov.",
"usii-my.sharepoint.com.",
"usii.sharepoint.com.",
"uslbm-my.sharepoint.com.",
+ "uslbm.sharepoint.com.",
"ussav.cynet.com.",
+ "usserver.serverapi.org.",
"usslb.cynet.com.",
"uswest-beacon.deepintent.com.",
"uu.qq.com.",
"uuidksinc.net.",
"uvermont.mm.fcix.net.",
- "uvu365-my.sharepoint.com.",
+ "uvmx-my.sharepoint.com.",
"uxfeedback.ru.",
"uyunad.com.",
- "v.streaming.qq.com.",
"v.vivintsky.com.",
"v2-zj-shxcm.kwaicdn.com.",
- "v34.tiktokcdn.com.",
"v39-as.tiktokcdn.com.",
"v39-ca.tiktokcdn.com.",
"v39-id-telin.tiktokcdn.com.",
- "v39-id.tiktokcdn.com.",
+ "v39-id.gts.byteoversea.net.",
+ "v39-mx.tiktokcdn.com.",
"v39-my.tiktokcdn.com.",
"v39-row.gts.byteoversea.net.",
"v39-row.tiktokcdn.com.",
@@ -7773,14 +8073,21 @@ var FakeECSFQDNs = container.NewMapSet(
"v6-gdvod.kwaicdn.com.",
"v8.analytics.pinsightmedia.com.",
"v8engine.pinsightmedia.com.",
- "vador.com.",
+ "va.v.liveperson.net.",
+ "vadesecure.com.",
"valleychildrensorg-my.sharepoint.com.",
"vancitycu-my.sharepoint.com.",
+ "vancitycu.sharepoint.com.",
"varify.io.",
- "vb24131crasosnemesis.com.",
+ "vault.bitwarden.com.",
"vbw.vivoglobal.com.",
+ "vcb-ott.cdn-vnpay.vn.",
"vconf.f.360.cn.",
- "veraxen.com.",
+ "vdn.line-scdn.net.",
+ "veeco-my.sharepoint.com.",
+ "vela.iad-01.braze.com.",
+ "venafi.com.",
+ "veralto-my.sharepoint.com.",
"veronanetworks.mm.fcix.net.",
"verticals.wix.com.",
"veteransunited-my.sharepoint.com.",
@@ -7789,10 +8096,11 @@ var FakeECSFQDNs = container.NewMapSet(
"vfa.hpplay.cn.",
"vgorigin.hakunaymatata.com.",
"viadcorp-my.sharepoint.com.",
+ "viadcorp.sharepoint.com.",
"vibe.co.",
"vibeaconstr.onezapp.com.",
+ "vicegolf.com.",
"vicoo.tech.",
- "vidamx-my.sharepoint.com.",
"video-atl3-1.xx.fbcdn.net.",
"video-atl3-2.xx.fbcdn.net.",
"video-bos5-1.xx.fbcdn.net.",
@@ -7817,89 +8125,100 @@ var FakeECSFQDNs = container.NewMapSet(
"video-ord5-2.xx.fbcdn.net.",
"video-sea1-1.xx.fbcdn.net.",
"video-sjc3-1.xx.fbcdn.net.",
+ "video.ltwebstatic.com.",
"videocloud.cn-hangzhou.log.aliyuncs.com.",
+ "videocontent-dra.himovie.dbankcloud.cn.",
"videocontent-dra.himovie.dbankcloud.com.",
+ "videoeditor-api-dra.cloud.huawei.com.",
"videoqoe-fastly.stvidtest.net.",
+ "vidhide.com.",
"vidmate.net.",
- "vieon.vn.",
- "view.adbravotech.com.",
- "view2fa.prosourcehosted.com.",
"vik-ca.moonactive.net.",
"village365-my.sharepoint.com.",
+ "village365.sharepoint.com.",
"viously.com.",
"vip-chinanet.ynuf.aliapp.org.",
"vipads.live.",
+ "virgul.com.",
"virusinfo-cloudscan-cn.heytapmobi.com.",
+ "visainc-my.sharepoint.com.",
"visainc.sharepoint.com.",
+ "visaonline.com.",
"visionserviceplan-my.sharepoint.com.",
"visionserviceplan.sharepoint.com.",
"visitor.fiftyt.com.",
"visitors.live.",
"vitalant-my.sharepoint.com.",
+ "vitalant.sharepoint.com.",
"vivoglobal.com.",
"vlscppe.microsoft.com.",
"vn-viettel.rcs.telephony.goog.",
"vn.pool.ntp.org.",
+ "vn2-red.lol.sgp.pvp.net.",
+ "vnt.xhamster.com.",
+ "vntsnotificationservice.visa.com.",
"vod.ngb.haplat.net.",
"vod3.ngb.haplat.net.",
"vod5.ngb.haplat.net.",
"voe.sx.",
"voice.gcloudcs.com.",
"voice.telephony.goog.",
- "volusiastudents-my.sharepoint.com.",
- "volusiastudents.sharepoint.com.",
- "vpn.cshealthforlife.com.",
- "vpn.garypools.com.",
+ "volico.mm.fcix.net.",
+ "voya.com.",
"vpn1.ocso.com.",
"vpp-license-proxy.aliyuncs.com.",
+ "vr46.dxnt.net.",
+ "vu.okta.com.",
+ "vx9dle.n0qq3z.com.",
"vzuu.com.",
"w.deepl.com.",
- "w0.peakpx.com.",
"w3.mp.lura.live.",
"wabtec.okta.com.",
- "waf.rippecloud.com.",
+ "wageworks.com.",
+ "waitrose.com.",
"walletconnect.com.",
"walshgroup-my.sharepoint.com.",
- "wanmei.com.",
- "wap.cmpassport.com.",
+ "walshgroup.sharepoint.com.",
+ "wangyiyun-js.oss-cn-shanghai.aliyuncs.com.",
+ "wap.sogou.com.",
"warsaw.remotepc.com.",
"washoeschools-my.sharepoint.com.",
"washoeschools.sharepoint.com.",
- "wbte.drcedirect.com.",
+ "wc.js.ubembed.com.cdn.cloudflare.net.",
"wcpss-my.sharepoint.com.",
- "wcsdpaorg-my.sharepoint.com.",
+ "wcpss.sharepoint.com.",
"weather-analytics-events.apple.com.",
"weather-server-sg.allawnos.com.",
"weather-server.allawntech.com.",
"weather-widget-events.apple.com.",
+ "weather.herewetest.com.",
"weather.swishapps.ai.",
"weathercn.com.",
"weatheroffer.com.",
- "web-assets.cdn4dd.com.",
"web-g.kontiki.com.",
"web-static.archive.org.",
- "web.archive.org.",
"web.fe.1drv.com.",
- "web.tagembed.com.",
"web.voice.telephony.goog.",
- "web.wg1.kontiki.com.",
"web1.remotepc.com.",
"webapi.teamviewer.com.",
- "webapp.src.discover.com.",
+ "webed.dm-event.net.",
"webmd.com.",
- "weborama-tech.ru.",
- "webrad.io.",
"websocket.app.pdq.com.",
"wechatos.net.",
+ "weerrhoop.cc.",
+ "wehtga-launches.appsflyersdk.com.",
"weibocdn.com.",
"welcome.ultipro.com.",
+ "wellspan-my.sharepoint.com.",
"wellspan.sharepoint.com.",
- "westelm.com.",
+ "wemuslim.com.",
+ "wesingapp.com.",
"westerngovernorsuniversity-my.sharepoint.com.",
+ "westerngovernorsuniversity.sharepoint.com.",
"westpalm.remotepc.com.",
"westrockco-my.sharepoint.com.",
"westrockco.sharepoint.com.",
- "wetype.weixin.qq.com.",
+ "westus-gas.guestconfiguration.azure.com.",
"weu.his.arc.azure.com.",
"wewjyw.qb6ges.com.",
"wf-proxy-01.algolia.com.",
@@ -7907,9 +8226,11 @@ var FakeECSFQDNs = container.NewMapSet(
"wf-proxy-03.algolia.com.",
"whitingturner-my.sharepoint.com.",
"whitingturner.sharepoint.com.",
- "whm.develop.dev.experiancs.com.",
- "widget.tagembed.com.",
+ "whm.usa.experian.com.",
+ "widgets.outbrain.com.",
+ "widgets.sociablekit.com.",
"wifispot.io.",
+ "wildcard.dayforcehcm.com.edgekey.net.",
"winscp.net.",
"wipro365.sharepoint.com.",
"wkhpe.com.",
@@ -7921,28 +8242,27 @@ var FakeECSFQDNs = container.NewMapSet(
"worldnic.com.",
"worldtimeserver.com.",
"worldwideexpress2323-my.sharepoint.com.",
+ "worldwideexpress2323.sharepoint.com.",
"wosign.com.",
- "wp-thumbnail.parone.io.",
+ "wp-log.api.useinsider.com.",
"wp.safe.360.cn.",
- "wpp.net.",
"wr.moyoung.com.",
"wr.pvp.net.",
"ws.gleap.io.",
"ws.mybib.com.",
"ws.tildacdn.com.",
- "ws1seg.rwjbh.org.",
"wsfcsk12nc-my.sharepoint.com.",
"wsfsbank-my.sharepoint.com.",
"wsfsbank.sharepoint.com.",
"wsms.haplat.net.",
"wsoversea.com.",
+ "wsp.teamviewer.com.",
+ "wss-web.freshchat.com.",
"wtpsnj-my.sharepoint.com.",
- "wtsparadigm.com.",
"wtzw.com.",
"wus2.his.arc.azure.com.",
"wwt-my.sharepoint.com.",
"wwt.sharepoint.com.",
- "www.247mirror.com.",
"www.aigconnect.aig.",
"www.automizely-analytics.com.",
"www.bbc.co.uk.",
@@ -7950,68 +8270,77 @@ var FakeECSFQDNs = container.NewMapSet(
"www.bbc.com.",
"www.bbc.com.pri.bbc.com.",
"www.bbthat.com.",
- "www.bleepingcomputer.com.",
"www.box.com.",
"www.breitbart.com.",
- "www.bridge2bwb.com.",
+ "www.census.gov.",
"www.cmpassport.com.",
- "www.dhl.de.",
+ "www.coolmathgames.com.",
+ "www.crocs.com.",
"www.docusign.com.",
- "www.enaple.com.",
+ "www.ecb.europa.eu.",
+ "www.entrust.net.",
"www.essence.com.",
"www.etsy.com.",
- "www.fanatics.com.",
- "www.fmcschedule.com.",
+ "www.ezcater.com.",
"www.gbnews.com.",
"www.geoplugin.net.",
+ "www.globo.com.",
"www.google.org.",
- "www.gslb.pinterest.net.",
"www.handmadewithjoann.com.",
+ "www.honeywell.com.",
"www.imanageshare.com.",
"www.in.gov.",
"www.independent.co.uk.",
"www.inoreader.com.",
- "www.iorad.com.",
- "www.jdpower.com.",
- "www.jhnet.com.",
"www.jimmyjohns.com.",
"www.jpost.com.",
- "www.klj888.cn.",
+ "www.justice.gov.",
+ "www.kit22.com.",
"www.mainadv.com.",
"www.maintenanceconnection.com.",
- "www.mottandbow.com.",
+ "www.mytalkdesk.com.",
"www.nationalreview.com.",
"www.nativecos.com.",
+ "www.newsnow.co.uk.",
+ "www.oracle.com.",
"www.overleaf.com.",
"www.pingler.com.",
"www.pool.ntp.org.",
"www.printfriendly.com.",
"www.rawstory.com.",
+ "www.redcort.com.",
"www.regions.com.",
- "www.searchanise.com.",
+ "www.researchgate.net.",
"www.sevenrooms.com.",
- "www.shopmyexchange.com.",
- "www.snokido.com.",
- "www.soso.com.",
+ "www.sofascore.com.",
"www.standard.co.uk.",
+ "www.steamcommunity.com.",
"www.stickermule.com.",
- "www.thenews.com.pk.",
- "www.timeanddate.com.cdn.cloudflare.net.",
- "www.upward-app.com.",
+ "www.terabox.com.",
+ "www.tripadvisor.co.uk.",
"www.users.storage.live.com.",
+ "www.vicegolf.com.",
"www.vipads.live.",
"www.virustotal.com.",
"www.wifispot.io.",
+ "www.wingstop.com.",
"www.wix.com.",
"www.worldtimeserver.com.",
- "www.xnxx.tv.",
- "www.yext.com.",
- "www.youngla.com.",
+ "www.youku.tv.",
+ "www.ziprecruiter.com.",
"www.zoom.us.",
- "www.zscaler.com.",
"www1.remotepc.com.",
+ "www1.signon2.gravityshavings.net.",
"www2.deepl.com.",
+ "www2.netx360.com.",
+ "www2.signon2.gravityshavings.net.",
+ "www3.signon2.gravityshavings.net.",
"www3.zoom.us.",
+ "www4.signon2.gravityshavings.net.",
+ "www5.signon2.gravityshavings.net.",
+ "www6.signon2.gravityshavings.net.",
+ "www7.signon2.gravityshavings.net.",
+ "www8.signon2.gravityshavings.net.",
"wx.huion.cn.",
"wxqcloud.qq.com.",
"wxqcloud.qq.com.cn.",
@@ -8019,12 +8348,11 @@ var FakeECSFQDNs = container.NewMapSet(
"wyze.com.",
"x-flow.app.",
"x.netease.com.",
- "x.research.qq.com.",
"xapads.com.",
+ "xbox-guide-public.rec.mp.microsoft.com.",
"xhpingcdn.com.",
"xiaoyi-css-us-15d.oss-us-west-1.aliyuncs.com.",
"xiaoyi-css-us-7d.oss-us-west-1.aliyuncs.com.",
- "xiaoyi.com.",
"xintaicz.cn.",
"xjp-msgacs.m.taobao.com.",
"xmcsrv.net.",
@@ -8032,11 +8360,8 @@ var FakeECSFQDNs = container.NewMapSet(
"xml-v4.ezmob.com.",
"xml.cachegorilla.com.",
"xml.car-bidpush.org.",
- "xml.cow-timerbudder.org.",
- "xml.ezmob.com.",
"xml.popmonetizer.net.",
"xml.xmlking.com.",
- "xml.yellow-resultsbidder.com.",
"xml.zeusadx.com.",
"xp002.itsupport247.net.",
"xp004.itsupport247.net.",
@@ -8052,32 +8377,34 @@ var FakeECSFQDNs = container.NewMapSet(
"xp019.itsupport247.net.",
"xpdrwp.itsupport247.net.",
"xtom.com.",
- "yazio-analytics.com.",
"yealink.com.",
- "ymmobi.com.",
+ "yengo.com.",
+ "yescoin.gold.",
+ "yinhe.net.",
+ "yn17vh.com.",
"ynuf.aliapp.org.",
"ynuf.aliapp.org.gds.alibabadns.com.",
"yomedia.vn.",
"yomeno.xyz.",
+ "yosmart.com.",
+ "youku.tv.",
"youngjoygame.com.",
- "youtooz.com.",
"yp.cdnstream1.com.",
+ "yumao.puata.info.",
"yunxindns.com.",
- "z-m-scontent-lis1-1.xx.fbcdn.net.",
- "z.cdn.ftd.agency.",
+ "yunxinfw.com.",
+ "z.betterhelp.com.",
+ "z.cdn.adpool.bet.",
+ "z.cdn.adtarget.market.",
+ "z.cdn.adtwister.me.",
"z.cdn.trafficbass.com.",
- "zachryholdings-my.sharepoint.com.",
"zego.im.",
- "zendesk.okta.com.",
"zenno.services.",
- "zeotap.com.",
- "zhangchu.net.",
"zimgs.cn.",
"ziply.mm.fcix.net.",
"zjcdn.com.yangyi19.com.",
+ "zog.link.",
"zoom.us.",
- "ztoken.uyunad.com.",
"zui.com.",
"zurich.remotepc.com.",
- "zybooks.com.",
)
diff --git a/internal/ecscache/ecscache.go b/internal/ecscache/ecscache.go
index 6889db7..eb50b51 100644
--- a/internal/ecscache/ecscache.go
+++ b/internal/ecscache/ecscache.go
@@ -21,6 +21,12 @@ import (
"github.com/miekg/dns"
)
+// Constants that define cache identifiers for the cache manager.
+const (
+ CacheIDWithECS = "ecscache_with_ecs"
+ CacheIDNoECS = "ecscache_no_ecs"
+)
+
// Middleware is a dnsserver.Middleware with ECS-aware caching.
type Middleware struct {
// cloner is the memory-efficient cloner of DNS messages.
@@ -50,6 +56,9 @@ type MiddlewareConfig 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
+
// GeoIP is the GeoIP database used to get subnets for countries. It must
// not be nil.
GeoIP geoip.Interface
@@ -69,18 +78,25 @@ type MiddlewareConfig struct {
UseTTLOverride bool
}
-// NewMiddleware initializes a new ECS-aware LRU caching middleware. c must not
-// be nil.
+// NewMiddleware initializes a new ECS-aware LRU caching middleware. It also
+// adds the caches with IDs [CacheIDNoECS] and [CacheIDWithECS] to the cache
+// manager. c must not be nil.
func NewMiddleware(c *MiddlewareConfig) (m *Middleware) {
+ cache := agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
+ Size: c.Size,
+ })
+ ecsCache := agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
+ Size: c.ECSSize,
+ })
+
+ c.CacheManager.Add(CacheIDNoECS, cache)
+ c.CacheManager.Add(CacheIDWithECS, ecsCache)
+
return &Middleware{
- cloner: c.Cloner,
- cache: agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
- Size: c.Size,
- }),
- ecsCache: agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
- Size: c.ECSSize,
- }),
- geoIP: c.GeoIP,
+ cloner: c.Cloner,
+ cache: cache,
+ ecsCache: ecsCache,
+ geoIP: c.GeoIP,
cacheReqPool: syncutil.NewPool(func() (req *cacheRequest) {
return &cacheRequest{}
}),
diff --git a/internal/ecscache/ecscache_test.go b/internal/ecscache/ecscache_test.go
index 530676f..e6e755b 100644
--- a/internal/ecscache/ecscache_test.go
+++ b/internal/ecscache/ecscache_test.go
@@ -9,6 +9,7 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
@@ -686,6 +687,7 @@ func newWithCache(
h,
ecscache.NewMiddleware(&ecscache.MiddlewareConfig{
Cloner: agdtest.NewCloner(),
+ CacheManager: agdcache.EmptyManager{},
GeoIP: geoIP,
Size: 100,
ECSSize: 100,
diff --git a/internal/filter/filter_test.go b/internal/filter/filter_test.go
index 8be9144..1b8778f 100644
--- a/internal/filter/filter_test.go
+++ b/internal/filter/filter_test.go
@@ -13,6 +13,7 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
@@ -99,8 +100,9 @@ var (
const testDataFiltersTmpl = `{
"filters": [
{
- "filterId": %q,
- "downloadUrl":"http://example.com"
+ "filterKey": %q,
+ "filterId": 42,
+ "downloadUrl": "http://example.com"
}
]
}
@@ -180,6 +182,7 @@ func prepareConf(t testing.TB) (c *filter.DefaultStorageConfig) {
NewRegDomains: &hashprefix.Filter{},
Now: time.Now,
ErrColl: nil,
+ CacheManager: agdcache.EmptyManager{},
CacheDir: cacheDir,
CustomFilterCacheSize: 100,
SafeSearchCacheSize: 100,
diff --git a/internal/filter/hashprefix/filter.go b/internal/filter/hashprefix/filter.go
index 92fbca4..a0667d5 100644
--- a/internal/filter/hashprefix/filter.go
+++ b/internal/filter/hashprefix/filter.go
@@ -28,6 +28,9 @@ type FilterConfig struct {
// Cloner is used to clone messages taken from filtering-result cache.
Cloner *dnsmsg.Cloner
+ // CacheManager is the global cache manager. CacheManager must not be nil.
+ CacheManager agdcache.Manager
+
// Hashes are the hostname hashes for this filter.
Hashes *Storage
@@ -101,8 +104,8 @@ func itemFromCache(
return item, true
}
-// Filter is a filter that matches hosts by their hashes based on a
-// hash-prefix table.
+// Filter is a filter that matches hosts by their hashes based on a hash-prefix
+// table. It should be initially refreshed with [Filter.RefreshInitial].
type Filter struct {
cloner *dnsmsg.Cloner
hashes *Storage
@@ -114,17 +117,24 @@ type Filter struct {
repFQDN string
}
-// NewFilter returns a new hash-prefix filter. c must not be nil.
+// NewFilter returns a new hash-prefix filter. It also adds the caches with IDs
+// [FilterListIDAdultBlocking], [FilterListIDSafeBrowsing], and
+// [FilterListIDNewRegDomains] to the cache manager. c must not be nil.
func NewFilter(c *FilterConfig) (f *Filter, err error) {
id := c.ID
+
+ resCache := agdcache.NewLRU[internal.CacheKey, *cacheItem](&agdcache.LRUConfig{
+ Size: c.CacheSize,
+ })
+
+ c.CacheManager.Add(string(id), resCache)
+
f = &Filter{
- cloner: c.Cloner,
- hashes: c.Hashes,
- resCache: agdcache.NewLRU[internal.CacheKey, *cacheItem](&agdcache.LRUConfig{
- Size: c.CacheSize,
- }),
- errColl: c.ErrColl,
- id: id,
+ cloner: c.Cloner,
+ hashes: c.Hashes,
+ resCache: resCache,
+ errColl: c.ErrColl,
+ id: id,
}
repHost := c.ReplacementHost
@@ -149,12 +159,6 @@ func NewFilter(c *FilterConfig) (f *Filter, err error) {
MaxSize: c.MaxSize,
})
- err = f.refresh(context.Background(), true)
- if err != nil {
- // Don't wrap the error, because it's informative enough as is.
- return nil, err
- }
-
return f, nil
}
@@ -379,6 +383,20 @@ func (f *Filter) Refresh(ctx context.Context) (err error) {
return err
}
+// RefreshInitial loads the content of the filter, using cached files if any,
+// regardless of their staleness.
+func (f *Filter) RefreshInitial(ctx context.Context) (err error) {
+ log.Info("hashprefix filter: initial refresh started")
+ defer log.Info("hashprefix filter: initial refresh finished")
+
+ err = f.refresh(ctx, true)
+ if err != nil {
+ return fmt.Errorf("refreshing hashprefix filter initially: %w", err)
+ }
+
+ return nil
+}
+
// refresh reloads and resets the hash-filter data. If acceptStale is true, do
// not try to load the list from its URL when there is already a file in the
// cache directory, regardless of its staleness.
diff --git a/internal/filter/hashprefix/filter_test.go b/internal/filter/hashprefix/filter_test.go
index 0171d23..9105b71 100644
--- a/internal/filter/hashprefix/filter_test.go
+++ b/internal/filter/hashprefix/filter_test.go
@@ -9,6 +9,7 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
@@ -21,6 +22,9 @@ import (
"github.com/stretchr/testify/require"
)
+// testTimeout is the common timeout for tests and contexts.
+const testTimeout = 10 * time.Second
+
func TestFilter_FilterRequest_host(t *testing.T) {
testCases := []struct {
name string
@@ -263,9 +267,10 @@ func newFilter(tb testing.TB, replHost string) (f *hashprefix.Filter) {
require.NoError(tb, err)
f, err = hashprefix.NewFilter(&hashprefix.FilterConfig{
- Cloner: agdtest.NewCloner(),
- Hashes: strg,
- URL: srvURL,
+ Cloner: agdtest.NewCloner(),
+ CacheManager: agdcache.EmptyManager{},
+ Hashes: strg,
+ URL: srvURL,
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) {
panic("not implemented")
@@ -281,6 +286,9 @@ func newFilter(tb testing.TB, replHost string) (f *hashprefix.Filter) {
})
require.NoError(tb, err)
+ ctx := testutil.ContextWithTimeout(tb, testTimeout)
+ require.NoError(tb, f.RefreshInitial(ctx))
+
return f
}
@@ -292,9 +300,10 @@ func TestFilter_Refresh(t *testing.T) {
require.NoError(t, err)
f, err := hashprefix.NewFilter(&hashprefix.FilterConfig{
- Cloner: agdtest.NewCloner(),
- Hashes: strg,
- URL: srvURL,
+ Cloner: agdtest.NewCloner(),
+ CacheManager: agdcache.EmptyManager{},
+ Hashes: strg,
+ URL: srvURL,
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) {
panic("not implemented")
@@ -310,7 +319,10 @@ func TestFilter_Refresh(t *testing.T) {
})
require.NoError(t, err)
- ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, f.RefreshInitial(ctx))
+
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
err = f.Refresh(ctx)
assert.NoError(t, err)
@@ -337,9 +349,10 @@ func TestFilter_FilterRequest_staleCache(t *testing.T) {
require.NoError(t, err)
fconf := &hashprefix.FilterConfig{
- Cloner: agdtest.NewCloner(),
- Hashes: strg,
- URL: srvURL,
+ Cloner: agdtest.NewCloner(),
+ CacheManager: agdcache.EmptyManager{},
+ Hashes: strg,
+ URL: srvURL,
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) {
panic("not implemented")
@@ -356,6 +369,9 @@ func TestFilter_FilterRequest_staleCache(t *testing.T) {
f, err := hashprefix.NewFilter(fconf)
require.NoError(t, err)
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, f.RefreshInitial(ctx))
+
messages := agdtest.NewConstructor()
// Test the following:
@@ -372,7 +388,7 @@ func TestFilter_FilterRequest_staleCache(t *testing.T) {
testOtherReqInfo := &agd.RequestInfo{Messages: messages, Host: testOtherHost, QType: dns.TypeA}
require.True(t, t.Run("hit_cached_host", func(t *testing.T) {
- ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
var r internal.Result
r, err = f.FilterRequest(ctx, testOtherHostReq, testOtherReqInfo)
@@ -387,7 +403,7 @@ func TestFilter_FilterRequest_staleCache(t *testing.T) {
err = os.Chtimes(cachePath, now, now.Add(-2*fconf.Staleness))
require.NoError(t, err)
- ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
err = f.Refresh(ctx)
assert.NoError(t, err)
@@ -396,7 +412,7 @@ func TestFilter_FilterRequest_staleCache(t *testing.T) {
}))
require.True(t, t.Run("previously_cached", func(t *testing.T) {
- ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
var r internal.Result
r, err = f.FilterRequest(ctx, testOtherHostReq, testOtherReqInfo)
@@ -406,7 +422,7 @@ func TestFilter_FilterRequest_staleCache(t *testing.T) {
}))
require.True(t, t.Run("new_host", func(t *testing.T) {
- ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
var r internal.Result
r, err = f.FilterRequest(ctx, testHostReq, testReqInfo)
diff --git a/internal/filter/hashprefix/storage.go b/internal/filter/hashprefix/storage.go
index 0fdf105..3f73296 100644
--- a/internal/filter/hashprefix/storage.go
+++ b/internal/filter/hashprefix/storage.go
@@ -25,11 +25,12 @@ type Storage struct {
hashSuffixes *atomic.Pointer[suffixMap]
}
-// suffixMap is a convenient alias for a map of has prefixes to its suffixes.
+// suffixMap is a convenient alias for a map of hash prefixes to its suffixes.
type suffixMap = map[Prefix][]suffix
// NewStorage returns a new hash storage containing hashes of the domain names
-// listed in hostnames, one domain name per line.
+// listed in hostnames, one domain name per line, requirements are described in
+// [Storage.Reset]. Empty string causes no errors.
func NewStorage(hostnames string) (s *Storage, err error) {
s = &Storage{
resetMu: &sync.Mutex{},
diff --git a/internal/filter/index.go b/internal/filter/index.go
index 32673fc..07012cd 100644
--- a/internal/filter/index.go
+++ b/internal/filter/index.go
@@ -1,6 +1,7 @@
package filter
import (
+ "cmp"
"context"
"net/url"
@@ -16,9 +17,12 @@ type filterIndexResp struct {
// filterIndexRespFilter is the struct for a filter from 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"`
- ID string `json:"filterId"`
+ FilterID any `json:"filterId"`
+ Key string `json:"filterKey"`
}
// filterIndexFilterData is the data of a single item in the filtering-rule
@@ -35,9 +39,11 @@ func (r *filterIndexResp) toInternal(
) (fls []*filterIndexFilterData) {
fls = make([]*filterIndexFilterData, 0, len(r.Filters))
for _, rf := range r.Filters {
- id, err := agd.NewFilterListID(rf.ID)
+ rfFltID, _ := rf.FilterID.(string)
+ rfID := cmp.Or(rf.Key, rfFltID)
+ id, err := agd.NewFilterListID(rfID)
if err != nil {
- errcoll.Collectf(ctx, errColl, "%s: validating id %q: %w", strgLogPrefix, rf.ID, err)
+ errcoll.Collectf(ctx, errColl, "%s: validating id/key %q: %w", strgLogPrefix, rfID, err)
continue
}
diff --git a/internal/filter/internal/composite/composite_internal_test.go b/internal/filter/internal/composite/composite_internal_test.go
index 6f3d4a7..b642302 100644
--- a/internal/filter/internal/composite/composite_internal_test.go
+++ b/internal/filter/internal/composite/composite_internal_test.go
@@ -19,7 +19,12 @@ var (
)
func BenchmarkFilter_FilterReqWithRuleLists(b *testing.B) {
- blockingRL, err := rulelist.NewFromString(filtertest.BlockRule+"\n", "test", "", 0, false)
+ blockingRL, err := rulelist.NewFromString(
+ filtertest.BlockRule+"\n",
+ "test",
+ "",
+ rulelist.ResultCacheEmpty{},
+ )
require.NoError(b, err)
f := New(&Config{
diff --git a/internal/filter/internal/composite/composite_test.go b/internal/filter/internal/composite/composite_test.go
index ec56ec6..f94e6d4 100644
--- a/internal/filter/internal/composite/composite_test.go
+++ b/internal/filter/internal/composite/composite_test.go
@@ -37,7 +37,7 @@ const (
func newFromStr(tb testing.TB, text string, id agd.FilterListID) (rl *rulelist.Refreshable) {
tb.Helper()
- rl, err := rulelist.NewFromString(text, id, "", 0, false)
+ rl, err := rulelist.NewFromString(text, id, "", rulelist.ResultCacheEmpty{})
require.NoError(tb, err)
return rl
@@ -48,7 +48,7 @@ func newFromStr(tb testing.TB, text string, id agd.FilterListID) (rl *rulelist.R
func newImmutable(tb testing.TB, text string, id agd.FilterListID) (rl *rulelist.Immutable) {
tb.Helper()
- rl, err := rulelist.NewImmutable(text, id, "", 0, false)
+ rl, err := rulelist.NewImmutable(text, id, "", rulelist.ResultCacheEmpty{})
require.NoError(tb, err)
return rl
@@ -452,18 +452,20 @@ func TestFilter_FilterRequest_safeSearch(t *testing.T) {
const fltListID = agd.FilterListIDGeneralSafeSearch
- gen := safesearch.New(&safesearch.Config{
- Refreshable: &internal.RefreshableConfig{
- URL: srvURL,
- ID: fltListID,
- CachePath: cachePath,
- Staleness: filtertest.Staleness,
- Timeout: filtertest.Timeout,
- MaxSize: filtertest.FilterMaxSize,
+ gen := safesearch.New(
+ &safesearch.Config{
+ Refreshable: &internal.RefreshableConfig{
+ URL: srvURL,
+ ID: fltListID,
+ CachePath: cachePath,
+ Staleness: filtertest.Staleness,
+ Timeout: filtertest.Timeout,
+ MaxSize: filtertest.FilterMaxSize,
+ },
+ CacheTTL: 1 * time.Minute,
},
- CacheTTL: 1 * time.Minute,
- CacheSize: 100,
- })
+ rulelist.NewResultCache(100, true),
+ )
err := gen.Refresh(testutil.ContextWithTimeout(t, filtertest.Timeout), false)
require.NoError(t, err)
@@ -494,8 +496,7 @@ func TestFilter_FilterRequest_services(t *testing.T) {
filtertest.BlockRule,
agd.FilterListIDBlockedService,
svcID,
- 0,
- false,
+ rulelist.ResultCacheEmpty{},
)
require.NoError(t, err)
diff --git a/internal/filter/internal/custom/custom.go b/internal/filter/internal/custom/custom.go
index db728a5..4c69804 100644
--- a/internal/filter/internal/custom/custom.go
+++ b/internal/filter/internal/custom/custom.go
@@ -23,10 +23,19 @@ type Filters struct {
errColl errcoll.Interface
}
-// New returns a new custom filter storage.
-func New(conf *agdcache.LRUConfig, errColl errcoll.Interface) (f *Filters) {
+// New returns a new custom filter storage. It also adds the cache with ID
+// [agd.FilterListIDCustom] to the cache manager.
+func New(
+ conf *agdcache.LRUConfig,
+ errColl errcoll.Interface,
+ cacheManager agdcache.Manager,
+) (f *Filters) {
+ cache := agdcache.NewLRU[agd.ProfileID, *customFilterCacheItem](conf)
+
+ cacheManager.Add(string(agd.FilterListIDCustom), cache)
+
return &Filters{
- cache: agdcache.NewLRU[agd.ProfileID, *customFilterCacheItem](conf),
+ cache: cache,
errColl: errColl,
}
}
@@ -77,8 +86,7 @@ func (f *Filters) Get(ctx context.Context, p *agd.Profile) (rl *rulelist.Immutab
// doesn't take $client rules into account.
//
// TODO(a.garipov): Consider enabling caching if necessary.
- 0,
- false,
+ rulelist.ResultCacheEmpty{},
)
if err != nil {
// In a rare situation where the custom rules are so badly formed that
diff --git a/internal/filter/internal/custom/custom_test.go b/internal/filter/internal/custom/custom_test.go
index 55d0600..ff144d7 100644
--- a/internal/filter/internal/custom/custom_test.go
+++ b/internal/filter/internal/custom/custom_test.go
@@ -30,6 +30,7 @@ func TestFilters_Get(t *testing.T) {
&agdtest.ErrorCollector{
OnCollect: func(ctx context.Context, err error) { panic("not implemented") },
},
+ agdcache.EmptyManager{},
)
p := &agd.Profile{
@@ -62,6 +63,7 @@ func BenchmarkFilters_Get(b *testing.B) {
&agdtest.ErrorCollector{
OnCollect: func(ctx context.Context, err error) { panic("not implemented") },
},
+ agdcache.EmptyManager{},
)
p := &agd.Profile{
diff --git a/internal/filter/internal/rulelist/immutable.go b/internal/filter/internal/rulelist/immutable.go
index 8126a34..09e21e2 100644
--- a/internal/filter/internal/rulelist/immutable.go
+++ b/internal/filter/internal/rulelist/immutable.go
@@ -26,11 +26,10 @@ func NewImmutable(
text string,
id agd.FilterListID,
svcID agd.BlockedServiceID,
- memCacheSize int,
- useMemCache bool,
+ cache ResultCache,
) (f *Immutable, err error) {
f = &Immutable{}
- f.filter, err = newFilter(text, id, svcID, memCacheSize, useMemCache)
+ f.filter, err = newFilter(text, id, svcID, cache)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return nil, err
diff --git a/internal/filter/internal/rulelist/refreshable.go b/internal/filter/internal/rulelist/refreshable.go
index 8196845..234f201 100644
--- a/internal/filter/internal/rulelist/refreshable.go
+++ b/internal/filter/internal/rulelist/refreshable.go
@@ -33,11 +33,7 @@ type Refreshable struct {
// NewRefreshable returns a new refreshable DNS request and response filter
// based on the provided rule list. c must be non-nil. The initial refresh
// should be called explicitly if necessary.
-func NewRefreshable(
- c *internal.RefreshableConfig,
- memCacheSize int,
- useMemCache bool,
-) (f *Refreshable) {
+func NewRefreshable(c *internal.RefreshableConfig, cache ResultCache) (f *Refreshable) {
f = &Refreshable{
mu: &sync.RWMutex{},
refr: internal.NewRefreshable(&internal.RefreshableConfig{
@@ -51,7 +47,7 @@ func NewRefreshable(
}
var err error
- f.filter, err = newFilter("", c.ID, "", memCacheSize, useMemCache)
+ f.filter, err = newFilter("", c.ID, "", cache)
if err != nil {
// Should never happen, since text is empty.
panic(fmt.Errorf("unexpected filter error: %w", err))
@@ -68,20 +64,18 @@ func NewFromString(
text string,
id agd.FilterListID,
svcID agd.BlockedServiceID,
- memCacheSize int,
- useMemCache bool,
+ cache ResultCache,
) (f *Refreshable, err error) {
- f = &Refreshable{
- mu: &sync.RWMutex{},
- }
-
- f.filter, err = newFilter(text, id, svcID, memCacheSize, useMemCache)
+ filter, err := newFilter(text, id, svcID, cache)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return nil, err
}
- return f, nil
+ return &Refreshable{
+ mu: &sync.RWMutex{},
+ filter: filter,
+ }, nil
}
// DNSResult returns the result of applying the urlfilter DNS filtering engine.
diff --git a/internal/filter/internal/rulelist/refreshable_test.go b/internal/filter/internal/rulelist/refreshable_test.go
index 6acf38f..7676229 100644
--- a/internal/filter/internal/rulelist/refreshable_test.go
+++ b/internal/filter/internal/rulelist/refreshable_test.go
@@ -32,14 +32,20 @@ const testFltListID agd.FilterListID = "fl1"
const testBlockRule = "||" + testReqHost + "\n"
func TestRefreshable_RulesCount(t *testing.T) {
- rl, err := rulelist.NewFromString(testBlockRule, testFltListID, "", 0, false)
+ rl, err := rulelist.NewFromString(
+ testBlockRule,
+ testFltListID,
+ "",
+ rulelist.ResultCacheEmpty{},
+ )
require.NoError(t, err)
assert.Equal(t, 1, rl.RulesCount())
}
func TestRefreshable_DNSResult_cache(t *testing.T) {
- rl, err := rulelist.NewFromString(testBlockRule, testFltListID, "", 100, true)
+ cache := rulelist.NewResultCache(100, true)
+ rl, err := rulelist.NewFromString(testBlockRule, testFltListID, "", cache)
require.NoError(t, err)
const qt = dns.TypeA
@@ -69,7 +75,12 @@ func TestRefreshable_DNSResult_cache(t *testing.T) {
func TestRefreshable_ID(t *testing.T) {
const svcID = agd.BlockedServiceID("test_service")
- rl, err := rulelist.NewFromString(testBlockRule, testFltListID, svcID, 0, false)
+ rl, err := rulelist.NewFromString(
+ testBlockRule,
+ testFltListID,
+ svcID,
+ rulelist.ResultCacheEmpty{},
+ )
require.NoError(t, err)
gotID, gotSvcID := rl.ID()
@@ -87,8 +98,7 @@ func TestRefreshable_Refresh(t *testing.T) {
Staleness: filtertest.Staleness,
MaxSize: filtertest.FilterMaxSize,
},
- 100,
- true,
+ rulelist.NewResultCache(100, true),
)
ctx := testutil.ContextWithTimeout(t, filtertest.Timeout)
diff --git a/internal/filter/internal/rulelist/rulelist.go b/internal/filter/internal/rulelist/rulelist.go
index 3302d38..afde13e 100644
--- a/internal/filter/internal/rulelist/rulelist.go
+++ b/internal/filter/internal/rulelist/rulelist.go
@@ -31,16 +31,42 @@ func newURLFilterID() (id int) {
}
type (
- // resultCache is a convenient alias for cache to keep types in check.
- resultCache = agdcache.Interface[internal.CacheKey, *cacheItem]
+ // ResultCache is a convenient alias for cache to keep types in check.
+ ResultCache = agdcache.Interface[internal.CacheKey, *CacheItem]
- // resultCacheEmpty is a convenient alias for empty cache to keep types in
+ // ResultCacheEmpty is a convenient alias for empty cache to keep types in
// check. See [filter.DNSResult].
- resultCacheEmpty = agdcache.Empty[internal.CacheKey, *cacheItem]
+ ResultCacheEmpty = agdcache.Empty[internal.CacheKey, *CacheItem]
)
-// cacheItem represents an item that we will store in the cache.
-type cacheItem struct {
+// NewResultCache returns a new initialized cache with the given size. If
+// useCache is false, it returns a cache implementation that does nothing.
+func NewResultCache(size int, useCache bool) (cache ResultCache) {
+ if !useCache {
+ return ResultCacheEmpty{}
+ }
+
+ return agdcache.NewLRU[internal.CacheKey, *CacheItem](&agdcache.LRUConfig{
+ Size: size,
+ })
+}
+
+// NewManagedResultCache is like [NewResultCache] but it also adds a newly
+// created cache to the cache manager by id.
+func NewManagedResultCache(
+ m agdcache.Manager,
+ id string,
+ size int,
+ useCache bool,
+) (cache ResultCache) {
+ cache = NewResultCache(size, useCache)
+ m.Add(id, cache)
+
+ return cache
+}
+
+// CacheItem represents an item that we will store in the cache.
+type CacheItem struct {
// res is the DNS filtering result.
res *urlfilter.DNSResult
@@ -53,10 +79,10 @@ type cacheItem struct {
// detect key collisions. If there is a key collision, it returns nil and
// false.
func itemFromCache(
- cache resultCache,
+ cache ResultCache,
key internal.CacheKey,
host string,
-) (item *cacheItem, ok bool) {
+) (item *CacheItem, ok bool) {
item, ok = cache.Get(key)
if !ok {
return nil, false
@@ -84,7 +110,7 @@ type filter struct {
// cache contains cached results of filtering.
//
// TODO(ameshkov): Add metrics for these caches.
- cache resultCache
+ cache ResultCache
// id is the filter list ID, if any.
id agd.FilterListID
@@ -105,23 +131,15 @@ func newFilter(
text string,
id agd.FilterListID,
svcID agd.BlockedServiceID,
- memCacheSize int,
- useMemCache bool,
+ cache agdcache.Interface[internal.CacheKey, *CacheItem],
) (f *filter, err error) {
f = &filter{
+ cache: cache,
id: id,
svcID: svcID,
urlFilterID: newURLFilterID(),
}
- if useMemCache {
- f.cache = agdcache.NewLRU[internal.CacheKey, *cacheItem](&agdcache.LRUConfig{
- Size: memCacheSize,
- })
- } else {
- f.cache = resultCacheEmpty{}
- }
-
// TODO(a.garipov): Add filterlist.BytesRuleList.
strList := &filterlist.StringRuleList{
ID: f.urlFilterID,
@@ -150,11 +168,11 @@ func (f *filter) DNSResult(
) (res *urlfilter.DNSResult) {
var ok bool
var cacheKey internal.CacheKey
- var item *cacheItem
+ var item *CacheItem
// Don't waste resources on computing the cache key if the cache is not
// enabled.
- _, emptyCache := f.cache.(resultCacheEmpty)
+ _, emptyCache := f.cache.(ResultCacheEmpty)
if !emptyCache {
// TODO(a.garipov): Add real class here.
cacheKey = internal.NewCacheKey(host, rrType, dns.ClassINET, isAns)
@@ -177,7 +195,7 @@ func (f *filter) DNSResult(
res = nil
}
- f.cache.Set(cacheKey, &cacheItem{
+ f.cache.Set(cacheKey, &CacheItem{
res: res,
host: host,
})
diff --git a/internal/filter/internal/safesearch/safesearch.go b/internal/filter/internal/safesearch/safesearch.go
index 0dc055f..a1f7a96 100644
--- a/internal/filter/internal/safesearch/safesearch.go
+++ b/internal/filter/internal/safesearch/safesearch.go
@@ -29,16 +29,13 @@ type Config struct {
//
//lint:ignore U1000 TODO(a.garipov): Currently unused. See AGDNS-398.
CacheTTL time.Duration
-
- // CacheSize is the number of items in the result cache.
- CacheSize int
}
// New returns a new safe-search filter. c must not be nil. The initial
// refresh should be called explicitly if necessary.
-func New(c *Config) (f *Filter) {
+func New(c *Config, cache rulelist.ResultCache) (f *Filter) {
return &Filter{
- flt: rulelist.NewRefreshable(c.Refreshable, c.CacheSize, true),
+ flt: rulelist.NewRefreshable(c.Refreshable, cache),
}
}
diff --git a/internal/filter/internal/safesearch/safesearch_test.go b/internal/filter/internal/safesearch/safesearch_test.go
index 44688bf..817db37 100644
--- a/internal/filter/internal/safesearch/safesearch_test.go
+++ b/internal/filter/internal/safesearch/safesearch_test.go
@@ -13,6 +13,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/filtertest"
+ "github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/safesearch"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
@@ -48,18 +49,20 @@ func TestFilter(t *testing.T) {
reqCh := make(chan struct{}, 1)
cachePath, srvURL := filtertest.PrepareRefreshable(t, reqCh, testFilterRules, http.StatusOK)
- f := safesearch.New(&safesearch.Config{
- Refreshable: &internal.RefreshableConfig{
- ID: agd.FilterListIDGeneralSafeSearch,
- URL: srvURL,
- CachePath: cachePath,
- Staleness: filtertest.Staleness,
- Timeout: filtertest.Timeout,
- MaxSize: filtertest.FilterMaxSize,
+ f := safesearch.New(
+ &safesearch.Config{
+ Refreshable: &internal.RefreshableConfig{
+ ID: agd.FilterListIDGeneralSafeSearch,
+ URL: srvURL,
+ CachePath: cachePath,
+ Staleness: filtertest.Staleness,
+ Timeout: filtertest.Timeout,
+ MaxSize: filtertest.FilterMaxSize,
+ },
+ CacheTTL: 1 * time.Minute,
},
- CacheTTL: 1 * time.Minute,
- CacheSize: 100,
- })
+ rulelist.NewResultCache(100, true),
+ )
refrErr := f.Refresh(testutil.ContextWithTimeout(t, filtertest.Timeout), true)
require.NoError(t, refrErr)
diff --git a/internal/filter/internal/serviceblock/index.go b/internal/filter/internal/serviceblock/index.go
index f6f4f5e..44254de 100644
--- a/internal/filter/internal/serviceblock/index.go
+++ b/internal/filter/internal/serviceblock/index.go
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
"github.com/AdguardTeam/golibs/errors"
@@ -22,6 +23,7 @@ type indexResp struct {
func (r *indexResp) toInternal(
ctx context.Context,
errColl errcoll.Interface,
+ cacheManager agdcache.Manager,
cacheSize int,
useCache bool,
) (services serviceRuleLists, err error) {
@@ -37,7 +39,8 @@ func (r *indexResp) toInternal(
svcID agd.BlockedServiceID
rl *rulelist.Immutable
)
- svcID, rl, err = svc.toInternal(ctx, errColl, cacheSize, useCache)
+
+ svcID, rl, err = svc.toInternal(ctx, errColl, cacheManager, cacheSize, useCache)
if err != nil {
errs[i] = fmt.Errorf("service at index %d: %w", i, err)
@@ -62,10 +65,13 @@ type indexRespService struct {
Rules []string `json:"rules"`
}
-// toInternal converts the service from the index to a rule-list filter.
+// toInternal converts the service from the index to a rule-list filter. It
+// also adds the cache with ID "[agd.FilterListIDBlockedService]/[svc.ID]" to
+// the cache manager.
func (svc *indexRespService) toInternal(
ctx context.Context,
errColl errcoll.Interface,
+ cacheManager agdcache.Manager,
cacheSize int,
useCache bool,
) (svcID agd.BlockedServiceID, rl *rulelist.Immutable, err error) {
@@ -80,18 +86,24 @@ func (svc *indexRespService) toInternal(
log.Info("warning: %s", reportErr)
}
+ fltIDStr := string(agd.FilterListIDBlockedService) + "/" + string(svcID)
+ cache := rulelist.NewManagedResultCache(
+ cacheManager,
+ fltIDStr,
+ cacheSize,
+ useCache,
+ )
rl, err = rulelist.NewImmutable(
strings.Join(svc.Rules, "\n"),
agd.FilterListIDBlockedService,
svcID,
- cacheSize,
- useCache,
+ cache,
)
if err != nil {
return "", nil, fmt.Errorf("compiling %s: %w", svc.ID, err)
}
- log.Info("%s/%s: got %d rules", agd.FilterListIDBlockedService, svcID, rl.RulesCount())
+ log.Info("%s: got %d rules", fltIDStr, rl.RulesCount())
return svcID, rl, nil
}
diff --git a/internal/filter/internal/serviceblock/serviceblock.go b/internal/filter/internal/serviceblock/serviceblock.go
index 10b762f..e15e11a 100644
--- a/internal/filter/internal/serviceblock/serviceblock.go
+++ b/internal/filter/internal/serviceblock/serviceblock.go
@@ -11,6 +11,7 @@ import (
"sync"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/rulelist"
@@ -77,6 +78,7 @@ func (f *Filter) RuleLists(
// Refresh loads new service data from the index URL.
func (f *Filter) Refresh(
ctx context.Context,
+ cacheManager agdcache.Manager,
cacheSize int,
useCache bool,
acceptStale bool,
@@ -94,7 +96,7 @@ func (f *Filter) Refresh(
return err
}
- services, err := resp.toInternal(ctx, f.errColl, cacheSize, useCache)
+ services, err := resp.toInternal(ctx, f.errColl, cacheManager, cacheSize, useCache)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
diff --git a/internal/filter/internal/serviceblock/serviceblock_test.go b/internal/filter/internal/serviceblock/serviceblock_test.go
index ef03f7c..3e0785b 100644
--- a/internal/filter/internal/serviceblock/serviceblock_test.go
+++ b/internal/filter/internal/serviceblock/serviceblock_test.go
@@ -6,6 +6,7 @@ import (
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/internal/filtertest"
@@ -70,7 +71,7 @@ func TestFilter(t *testing.T) {
f := serviceblock.New(refr, errColl)
ctx := context.Background()
- err := f.Refresh(ctx, 0, false, false)
+ err := f.Refresh(ctx, agdcache.EmptyManager{}, 0, false, false)
require.NoError(t, err)
testutil.RequireReceive(t, reqCh, filtertest.Timeout)
diff --git a/internal/filter/storage.go b/internal/filter/storage.go
index e7f4b84..0e0d4ed 100644
--- a/internal/filter/storage.go
+++ b/internal/filter/storage.go
@@ -38,7 +38,8 @@ type Storage interface {
// DefaultStorage is the default storage for filters, including the filters
// based on rule lists, custom filters of profiles, safe browsing, and safe
-// search ones.
+// search ones. It should be initially refreshed with
+// [DefaultStorage.RefreshInitial].
type DefaultStorage struct {
// refr is the helper entity containing the refreshable part of the index
// refresh and caching logic.
@@ -75,6 +76,9 @@ type DefaultStorage struct {
// errors.
errColl errcoll.Interface
+ // cacheManager is the global cache manager. cacheManager must not be nil.
+ cacheManager agdcache.Manager
+
// customFilters is the storage of custom filters for profiles.
customFilters *custom.Filters
@@ -149,6 +153,9 @@ type DefaultStorageConfig struct {
// refresh errors.
ErrColl errcoll.Interface
+ // CacheManager is the global cache manager. CacheManager must not be nil.
+ CacheManager agdcache.Manager
+
// CacheDir is the path to the directory where the cached filter files are
// put. The directory must exist.
CacheDir string
@@ -196,33 +203,53 @@ type DefaultStorageConfig struct {
// blocked-service index.
const svcIdxRefreshTimeout = 3 * time.Minute
-// NewDefaultStorage returns a new filter storage. c must not be nil.
-func NewDefaultStorage(c *DefaultStorageConfig) (s *DefaultStorage, err error) {
- genSafeSearch := safesearch.New(&safesearch.Config{
- Refreshable: &internal.RefreshableConfig{
- URL: c.GeneralSafeSearchRulesURL,
- ID: agd.FilterListIDGeneralSafeSearch,
- CachePath: filepath.Join(c.CacheDir, string(agd.FilterListIDGeneralSafeSearch)),
- Staleness: c.RefreshIvl,
- Timeout: c.RuleListRefreshTimeout,
- MaxSize: c.MaxRuleListSize,
+// NewDefaultStorage returns a new filter storage. It also adds the caches with
+// IDs [agd.FilterListIDGeneralSafeSearch] and
+// [agd.FilterListIDYoutubeSafeSearch] to the cache manager. c must not be nil.
+func NewDefaultStorage(c *DefaultStorageConfig) (s *DefaultStorage) {
+ fltIDGenSafeSearchStr := string(agd.FilterListIDGeneralSafeSearch)
+ genSafeSearchCache := rulelist.NewManagedResultCache(
+ c.CacheManager,
+ fltIDGenSafeSearchStr,
+ c.SafeSearchCacheSize,
+ true,
+ )
+ genSafeSearch := safesearch.New(
+ &safesearch.Config{
+ Refreshable: &internal.RefreshableConfig{
+ URL: c.GeneralSafeSearchRulesURL,
+ ID: agd.FilterListIDGeneralSafeSearch,
+ CachePath: filepath.Join(c.CacheDir, fltIDGenSafeSearchStr),
+ Staleness: c.RefreshIvl,
+ Timeout: c.RuleListRefreshTimeout,
+ MaxSize: c.MaxRuleListSize,
+ },
+ CacheTTL: c.SafeSearchCacheTTL,
},
- CacheTTL: c.SafeSearchCacheTTL,
- CacheSize: c.SafeSearchCacheSize,
- })
+ genSafeSearchCache,
+ )
- ytSafeSearch := safesearch.New(&safesearch.Config{
- Refreshable: &internal.RefreshableConfig{
- URL: c.YoutubeSafeSearchRulesURL,
- ID: agd.FilterListIDYoutubeSafeSearch,
- CachePath: filepath.Join(c.CacheDir, string(agd.FilterListIDYoutubeSafeSearch)),
- Staleness: c.RefreshIvl,
- Timeout: c.RuleListRefreshTimeout,
- MaxSize: c.MaxRuleListSize,
+ fltIDYTSafeSearchStr := string(agd.FilterListIDYoutubeSafeSearch)
+ ytSafeSearchCache := rulelist.NewManagedResultCache(
+ c.CacheManager,
+ fltIDYTSafeSearchStr,
+ c.SafeSearchCacheSize,
+ true,
+ )
+ ytSafeSearch := safesearch.New(
+ &safesearch.Config{
+ Refreshable: &internal.RefreshableConfig{
+ URL: c.YoutubeSafeSearchRulesURL,
+ ID: agd.FilterListIDYoutubeSafeSearch,
+ CachePath: filepath.Join(c.CacheDir, fltIDYTSafeSearchStr),
+ Staleness: c.RefreshIvl,
+ Timeout: c.RuleListRefreshTimeout,
+ MaxSize: c.MaxRuleListSize,
+ },
+ CacheTTL: c.SafeSearchCacheTTL,
},
- CacheTTL: c.SafeSearchCacheTTL,
- CacheSize: c.SafeSearchCacheSize,
- })
+ ytSafeSearchCache,
+ )
ruleListIdxRefr := internal.NewRefreshable(&internal.RefreshableConfig{
URL: c.FilterIndexURL,
@@ -247,7 +274,7 @@ func NewDefaultStorage(c *DefaultStorageConfig) (s *DefaultStorage, err error) {
MaxSize: c.MaxRuleListSize,
})
- s = &DefaultStorage{
+ return &DefaultStorage{
refr: ruleListIdxRefr,
mu: &sync.RWMutex{},
services: serviceblock.New(svcIdxRefr, c.ErrColl),
@@ -258,11 +285,13 @@ func NewDefaultStorage(c *DefaultStorageConfig) (s *DefaultStorage, err error) {
ytSafeSearch: ytSafeSearch,
now: c.Now,
errColl: c.ErrColl,
+ cacheManager: c.CacheManager,
customFilters: custom.New(
&agdcache.LRUConfig{
Size: c.CustomFilterCacheSize,
},
c.ErrColl,
+ c.CacheManager,
),
cacheDir: c.CacheDir,
refreshIvl: c.RefreshIvl,
@@ -271,13 +300,6 @@ func NewDefaultStorage(c *DefaultStorageConfig) (s *DefaultStorage, err error) {
maxRuleListSize: c.MaxRuleListSize,
useRuleListCache: c.UseRuleListCache,
}
-
- err = s.refresh(context.Background(), true)
- if err != nil {
- return nil, fmt.Errorf("initial refresh: %w", err)
- }
-
- return s, nil
}
// type check
@@ -493,6 +515,20 @@ func (s *DefaultStorage) Refresh(ctx context.Context) (err error) {
return err
}
+// RefreshInitial loads the content of the storage, using cached files if any,
+// regardless of their staleness.
+func (s *DefaultStorage) RefreshInitial(ctx context.Context) (err error) {
+ log.Info("filter storage: initial refresh started")
+ defer log.Info("filter storage: initial refresh finished")
+
+ err = s.refresh(ctx, true)
+ if err != nil {
+ return fmt.Errorf("refreshing filter storage initially: %w", err)
+ }
+
+ return nil
+}
+
// enrichFromContext adds information from ctx to origErr if it can assume that
// origErr is caused by ctx being canceled.
func enrichFromContext(ctx context.Context, origErr error) (err error) {
@@ -509,9 +545,9 @@ func enrichFromContext(ctx context.Context, origErr error) (err error) {
return fmt.Errorf("storage refresh with deadline at %s: %w", dl, origErr)
}
-// refresh is the inner method of Refresh that allows accepting stale files. It
-// refreshes the index from the index URL and updates all rule list filters, as
-// well as the service filters.
+// refresh refreshes the index from the index URL and updates all rule list
+// filters, as well as the service filters. If acceptStale is true, the cache
+// files are used regardless of their staleness.
func (s *DefaultStorage) refresh(ctx context.Context, acceptStale bool) (err error) {
resp, err := s.loadIndex(ctx, acceptStale)
if err != nil {
@@ -541,7 +577,13 @@ func (s *DefaultStorage) refresh(ctx context.Context, acceptStale bool) (err err
log.Info("%s: got %d filter lists from index after compilation", strgLogPrefix, len(ruleLists))
- err = s.services.Refresh(ctx, s.ruleListCacheSize, s.useRuleListCache, acceptStale)
+ err = s.services.Refresh(
+ ctx,
+ s.cacheManager,
+ s.ruleListCacheSize,
+ s.useRuleListCache,
+ acceptStale,
+ )
if err != nil {
return fmt.Errorf("refreshing blocked services: %w", err)
}
@@ -562,7 +604,8 @@ func (s *DefaultStorage) refresh(ctx context.Context, acceptStale bool) (err err
}
// addRuleList adds the data from fl to ruleLists and handles all validations
-// and errors.
+// and errors. It also adds the cache with [filterIndexFilterData.id] to the
+// cache manager.
func (s *DefaultStorage) addRuleList(
ctx context.Context,
ruleLists filteringRuleLists,
@@ -576,6 +619,13 @@ func (s *DefaultStorage) addRuleList(
}
fltIDStr := string(fl.id)
+ cache := rulelist.NewManagedResultCache(
+ s.cacheManager,
+ fltIDStr,
+ s.ruleListCacheSize,
+ s.useRuleListCache,
+ )
+
rl := rulelist.NewRefreshable(
&internal.RefreshableConfig{
URL: fl.url,
@@ -585,8 +635,7 @@ func (s *DefaultStorage) addRuleList(
Timeout: s.ruleListRefreshTimeout,
MaxSize: s.maxRuleListSize,
},
- s.ruleListCacheSize,
- s.useRuleListCache,
+ cache,
)
err := rl.Refresh(ctx, acceptStale)
if err == nil {
diff --git a/internal/filter/storage_test.go b/internal/filter/storage_test.go
index a2407ca..743bc5a 100644
--- a/internal/filter/storage_test.go
+++ b/internal/filter/storage_test.go
@@ -9,6 +9,7 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
@@ -22,6 +23,9 @@ import (
"github.com/stretchr/testify/require"
)
+// testTimeout is the common timeout for tests and contexts.
+const testTimeout = 10 * time.Second
+
// TODO(a.garipov): Refactor the common stages, such as storage initialization,
// into a single method.
@@ -31,8 +35,10 @@ func TestStorage_FilterFromContext(t *testing.T) {
OnCollect: func(_ context.Context, err error) { panic("not implemented") },
}
- s, err := filter.NewDefaultStorage(c)
- require.NoError(t, err)
+ s := filter.NewDefaultStorage(c)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, s.RefreshInitial(ctx))
p := &agd.Profile{
ID: "prof1234",
@@ -60,14 +66,14 @@ func TestStorage_FilterFromContext(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, p, blockedHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
+ r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
@@ -85,14 +91,14 @@ func TestStorage_FilterFromContext(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, p, customHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
+ r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
@@ -110,14 +116,14 @@ func TestStorage_FilterFromContext(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, &agd.Profile{}, customHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
+ r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
assert.Nil(t, r)
@@ -142,8 +148,9 @@ func TestStorage_FilterFromContext_customAllow(t *testing.T) {
c := prepareConf(t)
- c.SafeBrowsing, err = hashprefix.NewFilter(&hashprefix.FilterConfig{
+ safeBrowsing, err := hashprefix.NewFilter(&hashprefix.FilterConfig{
Cloner: agdtest.NewCloner(),
+ CacheManager: agdcache.EmptyManager{},
Hashes: hashes,
ErrColl: errColl,
ID: agd.FilterListIDSafeBrowsing,
@@ -155,10 +162,14 @@ func TestStorage_FilterFromContext_customAllow(t *testing.T) {
})
require.NoError(t, err)
- c.ErrColl = errColl
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, safeBrowsing.RefreshInitial(ctx))
- s, err := filter.NewDefaultStorage(c)
- require.NoError(t, err)
+ c.ErrColl = errColl
+ c.SafeBrowsing = safeBrowsing
+
+ s := filter.NewDefaultStorage(c)
+ require.NoError(t, s.RefreshInitial(ctx))
const safeBrowsingAllowRule = "@@||" + safeBrowsingHost + "^"
p := &agd.Profile{
@@ -190,8 +201,9 @@ func TestStorage_FilterFromContext_customAllow(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, p, safeBrowsingSubHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
@@ -228,8 +240,9 @@ func TestStorage_FilterFromContext_schedule(t *testing.T) {
c := prepareConf(t)
// Use AdultBlocking, because SafeBrowsing is NOT affected by the schedule.
- c.AdultBlocking, err = hashprefix.NewFilter(&hashprefix.FilterConfig{
+ adultBlocking, err := hashprefix.NewFilter(&hashprefix.FilterConfig{
Cloner: agdtest.NewCloner(),
+ CacheManager: agdcache.EmptyManager{},
Hashes: hashes,
ErrColl: errColl,
ID: agd.FilterListIDAdultBlocking,
@@ -241,14 +254,17 @@ func TestStorage_FilterFromContext_schedule(t *testing.T) {
})
require.NoError(t, err)
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, adultBlocking.RefreshInitial(ctx))
+
c.Now = func() (t time.Time) {
return nowTime
}
-
c.ErrColl = errColl
+ c.AdultBlocking = adultBlocking
- s, err := filter.NewDefaultStorage(c)
- require.NoError(t, err)
+ s := filter.NewDefaultStorage(c)
+ require.NoError(t, s.RefreshInitial(ctx))
// Set up our profile with the schedule that disables filtering at the
// current moment.
@@ -294,8 +310,9 @@ func TestStorage_FilterFromContext_schedule(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, p, safeBrowsingSubHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
// The adult blocking filter should not be triggered, since we're within the
// schedule.
@@ -335,8 +352,10 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
OnCollect: func(_ context.Context, err error) { panic("not implemented") },
}
- s, err := filter.NewDefaultStorage(c)
- require.NoError(t, err)
+ s := filter.NewDefaultStorage(c)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, s.RefreshInitial(ctx))
g := &agd.FilteringGroup{
ID: "default",
@@ -353,14 +372,14 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, nil, blockedHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
+ r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
@@ -378,14 +397,14 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, nil, allowedHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
+ r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
@@ -403,14 +422,14 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, nil, blockedClientHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
+ r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
@@ -428,14 +447,14 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, nil, allowedClientHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
+ r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
@@ -453,14 +472,14 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, nil, otherNetHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
+ r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
assert.Nil(t, r)
@@ -473,8 +492,10 @@ func TestStorage_FilterFromContext_customDevice(t *testing.T) {
OnCollect: func(_ context.Context, err error) { panic("not implemented") },
}
- s, errStrg := filter.NewDefaultStorage(c)
- require.NoError(t, errStrg)
+ s := filter.NewDefaultStorage(c)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, s.RefreshInitial(ctx))
g := &agd.FilteringGroup{}
p := &agd.Profile{
@@ -495,8 +516,9 @@ func TestStorage_FilterFromContext_customDevice(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, p, blockedDeviceHost, deviceIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
@@ -519,8 +541,9 @@ func TestStorage_FilterFromContext_customDevice(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, p, allowedDeviceHost, deviceIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
@@ -542,8 +565,10 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
OnCollect: func(_ context.Context, err error) { panic("not implemented") },
}
- s, err := filter.NewDefaultStorage(c)
- require.NoError(t, err)
+ s := filter.NewDefaultStorage(c)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, s.RefreshInitial(ctx))
g := &agd.FilteringGroup{
ID: "default",
@@ -551,8 +576,9 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
RuleListsEnabled: true,
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, nil, otherNetHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
@@ -571,8 +597,7 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
}},
}
- var r filter.Result
- r, err = f.FilterResponse(ctx, resp, ri)
+ r, err := f.FilterResponse(ctx, resp, ri)
require.NoError(t, err)
rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
@@ -589,8 +614,7 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
}},
}
- var r filter.Result
- r, err = f.FilterResponse(ctx, resp, ri)
+ r, err := f.FilterResponse(ctx, resp, ri)
require.NoError(t, err)
ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
@@ -607,8 +631,7 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
}},
}
- var r filter.Result
- r, err = f.FilterResponse(ctx, resp, ri)
+ r, err := f.FilterResponse(ctx, resp, ri)
require.NoError(t, err)
rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
@@ -625,8 +648,7 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
}},
}
- var r filter.Result
- r, err = f.FilterResponse(ctx, resp, ri)
+ r, err := f.FilterResponse(ctx, resp, ri)
require.NoError(t, err)
ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
@@ -643,8 +665,7 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
}},
}
- var r filter.Result
- r, err = f.FilterResponse(ctx, resp, ri)
+ r, err := f.FilterResponse(ctx, resp, ri)
require.NoError(t, err)
rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
@@ -661,8 +682,7 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
}},
}
- var r filter.Result
- r, err = f.FilterResponse(ctx, req, ri)
+ r, err := f.FilterResponse(ctx, req, ri)
require.NoError(t, err)
ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
@@ -679,8 +699,7 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
}},
}
- var r filter.Result
- r, err = f.FilterResponse(ctx, req, ri)
+ r, err := f.FilterResponse(ctx, req, ri)
require.NoError(t, err)
assert.Nil(t, r)
@@ -694,8 +713,7 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
}},
}
- var r filter.Result
- r, err = f.FilterResponse(ctx, req, ri)
+ r, err := f.FilterResponse(ctx, req, ri)
require.NoError(t, err)
rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
@@ -712,8 +730,7 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
}},
}
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
+ r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
assert.Nil(t, r)
@@ -735,10 +752,10 @@ func TestStorage_FilterFromContext_safeBrowsing(t *testing.T) {
},
}
- c := prepareConf(t)
-
- c.SafeBrowsing, err = hashprefix.NewFilter(&hashprefix.FilterConfig{
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ safeBrowsing, err := hashprefix.NewFilter(&hashprefix.FilterConfig{
Cloner: agdtest.NewCloner(),
+ CacheManager: agdcache.EmptyManager{},
Hashes: hashes,
ErrColl: errColl,
ID: agd.FilterListIDSafeBrowsing,
@@ -749,11 +766,14 @@ func TestStorage_FilterFromContext_safeBrowsing(t *testing.T) {
CacheSize: 100,
})
require.NoError(t, err)
+ require.NoError(t, safeBrowsing.RefreshInitial(ctx))
+ c := prepareConf(t)
c.ErrColl = errColl
+ c.SafeBrowsing = safeBrowsing
- s, err := filter.NewDefaultStorage(c)
- require.NoError(t, err)
+ s := filter.NewDefaultStorage(c)
+ require.NoError(t, s.RefreshInitial(ctx))
g := &agd.FilteringGroup{
ID: "default",
@@ -774,14 +794,14 @@ func TestStorage_FilterFromContext_safeBrowsing(t *testing.T) {
}},
}
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, nil, safeBrowsingSubHost, clientIP, dns.TypeA)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
+ r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
rm := testutil.RequireTypeAssert[*filter.ResultModifiedRequest](t, r)
@@ -794,8 +814,10 @@ func TestStorage_FilterFromContext_safeBrowsing(t *testing.T) {
func TestStorage_FilterFromContext_safeSearch(t *testing.T) {
c := prepareConf(t)
- s, err := filter.NewDefaultStorage(c)
- require.NoError(t, err)
+ s := filter.NewDefaultStorage(c)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, s.RefreshInitial(ctx))
g := &agd.FilteringGroup{
ID: "default",
@@ -843,16 +865,16 @@ func TestStorage_FilterFromContext_safeSearch(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
+ ctx = testutil.ContextWithTimeout(t, filtertest.Timeout)
ri := newReqInfo(g, nil, tc.host, clientIP, tc.rrtype)
- ctx := agd.ContextWithRequestInfo(context.Background(), ri)
+ ctx = agd.ContextWithRequestInfo(ctx, ri)
f := s.FilterFromContext(ctx, ri)
require.NotNil(t, f)
req := dnsservertest.CreateMessage(tc.host, tc.rrtype)
- var r filter.Result
- r, err = f.FilterRequest(ctx, req, ri)
+ r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
require.NotNil(t, r)
@@ -879,32 +901,35 @@ func TestStorage_FilterFromContext_safeSearch(t *testing.T) {
}
}
+// Typed sinks for benchmarks.
var (
- defaultStorageSink *filter.DefaultStorage
- errSink error
+ errSink error
)
-func BenchmarkStorage_NewDefaultStorage(b *testing.B) {
+func BenchmarkStorage_DefaultStorage_Initialize(b *testing.B) {
c := prepareConf(b)
c.ErrColl = &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, err error) { panic("not implemented") },
}
+ s := filter.NewDefaultStorage(c)
+ ctx := context.Background()
+
b.ReportAllocs()
b.ResetTimer()
for range b.N {
- defaultStorageSink, errSink = filter.NewDefaultStorage(c)
+ errSink = s.RefreshInitial(ctx)
}
- assert.NotNil(b, defaultStorageSink)
assert.NoError(b, errSink)
// Recent result on MBP 15:
//
- // goos: darwin
- // goarch: amd64
- // cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
- // BenchmarkStorage_NewDefaultStorage/success-12 3238 344513 ns/op 198096 B/op 952 allocs/op
+ // goos: darwin
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/filter
+ // cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
+ // BenchmarkStorage_DefaultStorage_Initialize-12 5301 221029 ns/op 260449 B/op 806 allocs/op
}
diff --git a/internal/geoip/asntops.go b/internal/geoip/asntops.go
index fddea5e..9a25c7a 100644
--- a/internal/geoip/asntops.go
+++ b/internal/geoip/asntops.go
@@ -7,14 +7,18 @@ import "github.com/AdguardTeam/golibs/container"
// DefaultTopASNs contains all specially handled ASNs.
var DefaultTopASNs = container.NewMapSet[ASN](
2,
- 3,
- 6,
+ 137,
174,
209,
224,
+ 513,
+ 559,
577,
+ 680,
701,
719,
+ 766,
+ 786,
803,
812,
852,
@@ -22,6 +26,8 @@ var DefaultTopASNs = container.NewMapSet[ASN](
906,
932,
967,
+ 984,
+ 1103,
1136,
1213,
1221,
@@ -30,15 +36,17 @@ var DefaultTopASNs = container.NewMapSet[ASN](
1267,
1299,
1403,
- 1443,
1547,
1659,
1680,
- 1741,
+ 1756,
1759,
+ 1764,
1835,
1836,
+ 1853,
1897,
+ 1930,
1955,
2018,
2107,
@@ -46,6 +54,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
2110,
2116,
2119,
+ 2471,
2497,
2514,
2516,
@@ -54,8 +63,11 @@ var DefaultTopASNs = container.NewMapSet[ASN](
2527,
2586,
2588,
+ 2602,
2607,
2609,
+ 2611,
+ 2614,
2740,
2847,
2852,
@@ -67,7 +79,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
3215,
3216,
3221,
- 3223,
3225,
3238,
3243,
@@ -82,9 +93,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
3320,
3326,
3329,
+ 3342,
3352,
3356,
- 3363,
3399,
3462,
3549,
@@ -99,13 +110,14 @@ var DefaultTopASNs = container.NewMapSet[ASN](
3855,
4007,
4134,
- 4181,
+ 4158,
4230,
4515,
4538,
4540,
4609,
4638,
+ 4651,
4657,
4685,
4713,
@@ -121,6 +133,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
4773,
4775,
4780,
+ 4785,
4788,
4804,
4808,
@@ -129,18 +142,21 @@ var DefaultTopASNs = container.NewMapSet[ASN](
4818,
4837,
4847,
+ 5087,
5089,
5378,
5384,
5390,
5391,
+ 5408,
5410,
5413,
5416,
5432,
+ 5438,
5466,
+ 5479,
5483,
- 5504,
5518,
5532,
5578,
@@ -159,15 +175,16 @@ var DefaultTopASNs = container.NewMapSet[ASN](
6147,
6167,
6181,
+ 6206,
6306,
6327,
6400,
6407,
6535,
6568,
- 6621,
6639,
6661,
+ 6663,
6677,
6697,
6700,
@@ -177,6 +194,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
6739,
6752,
6758,
+ 6769,
6772,
6799,
6805,
@@ -190,10 +208,10 @@ var DefaultTopASNs = container.NewMapSet[ASN](
6866,
6871,
6876,
+ 6877,
6939,
7018,
7029,
- 7049,
7057,
7122,
7131,
@@ -202,7 +220,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
7418,
7438,
7470,
- 7477,
7482,
7497,
7522,
@@ -218,27 +235,30 @@ var DefaultTopASNs = container.NewMapSet[ASN](
7794,
7862,
7922,
+ 7979,
7992,
8014,
8048,
8053,
8075,
+ 8094,
8151,
8167,
8193,
8200,
+ 8240,
8251,
8257,
- 8273,
- 8290,
8301,
8339,
8346,
8359,
+ 8368,
8369,
8374,
8376,
8386,
+ 8399,
8400,
8402,
8412,
@@ -249,11 +269,13 @@ var DefaultTopASNs = container.NewMapSet[ASN](
8449,
8452,
8462,
+ 8468,
8473,
8542,
8544,
8551,
8560,
+ 8562,
8585,
8612,
8632,
@@ -267,7 +289,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
8758,
8764,
8767,
+ 8771,
8772,
+ 8778,
8781,
8814,
8818,
@@ -276,7 +300,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
8849,
8866,
8881,
- 8887,
8896,
8926,
8948,
@@ -284,7 +307,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
8966,
8978,
8990,
- 9002,
9008,
9009,
9031,
@@ -304,7 +326,10 @@ var DefaultTopASNs = container.NewMapSet[ASN](
9146,
9155,
9158,
+ 9172,
+ 9186,
9198,
+ 9199,
9231,
9245,
9246,
@@ -324,7 +349,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
9365,
9381,
9416,
- 9432,
9443,
9471,
9484,
@@ -332,15 +356,17 @@ var DefaultTopASNs = container.NewMapSet[ASN](
9506,
9534,
9541,
+ 9587,
9595,
9605,
9617,
- 9621,
9644,
9674,
- 9676,
+ 9694,
9751,
- 9781,
+ 9756,
+ 9762,
+ 9770,
9790,
9808,
9824,
@@ -350,7 +376,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
9876,
9902,
9908,
- 9919,
9922,
9924,
9930,
@@ -358,15 +383,17 @@ var DefaultTopASNs = container.NewMapSet[ASN](
9934,
9976,
9988,
+ 9997,
10010,
- 10013,
+ 10019,
10030,
10036,
10066,
10075,
- 10085,
10094,
10099,
+ 10101,
+ 10103,
10118,
10131,
10139,
@@ -378,32 +405,38 @@ var DefaultTopASNs = container.NewMapSet[ASN](
10292,
10299,
10396,
+ 10429,
10474,
+ 10617,
10620,
10796,
+ 10834,
11014,
11081,
11139,
11172,
+ 11232,
11259,
11260,
11290,
11315,
11351,
+ 11367,
11426,
11427,
11492,
11556,
11562,
+ 11580,
11594,
11664,
+ 11721,
11776,
11814,
11816,
11830,
11845,
11888,
- 11992,
12066,
12083,
12091,
@@ -412,10 +445,13 @@ var DefaultTopASNs = container.NewMapSet[ASN](
12297,
12301,
12302,
+ 12312,
12322,
12334,
12338,
+ 12350,
12353,
+ 12361,
12365,
12389,
12390,
@@ -428,14 +464,15 @@ var DefaultTopASNs = container.NewMapSet[ASN](
12436,
12455,
12479,
+ 12483,
12491,
- 12496,
- 12508,
12552,
12570,
12576,
12578,
+ 12597,
12605,
+ 12615,
12668,
12709,
12714,
@@ -465,18 +502,16 @@ var DefaultTopASNs = container.NewMapSet[ASN](
13044,
13045,
13046,
+ 13092,
13099,
- 13101,
13110,
13122,
13124,
13127,
13156,
- 13170,
13188,
13189,
13194,
- 13208,
13213,
13280,
13285,
@@ -492,7 +527,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
14434,
14522,
14593,
- 14618,
14638,
14709,
14754,
@@ -505,12 +539,14 @@ var DefaultTopASNs = container.NewMapSet[ASN](
15366,
15377,
15378,
+ 15383,
15389,
15397,
15399,
15404,
15433,
15435,
+ 15440,
15457,
15474,
15480,
@@ -539,12 +575,13 @@ var DefaultTopASNs = container.NewMapSet[ASN](
15895,
15897,
15924,
+ 15935,
15943,
15955,
15958,
15962,
15964,
- 15975,
+ 15965,
15994,
16006,
16010,
@@ -557,18 +594,22 @@ var DefaultTopASNs = container.NewMapSet[ASN](
16117,
16135,
16178,
+ 16185,
16190,
16202,
16223,
+ 16229,
16232,
16246,
16276,
- 16281,
16322,
16333,
16342,
16345,
+ 16347,
16354,
+ 16367,
+ 16413,
16437,
16509,
16591,
@@ -578,7 +619,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
16705,
16735,
16814,
- 16906,
16960,
17072,
17079,
@@ -587,6 +627,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
17421,
17451,
17458,
+ 17465,
17470,
17480,
17488,
@@ -600,7 +641,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
17557,
17621,
17622,
- 17623,
17638,
17639,
17665,
@@ -608,12 +648,11 @@ var DefaultTopASNs = container.NewMapSet[ASN](
17676,
17698,
17705,
+ 17709,
17716,
- 17726,
17809,
17816,
17828,
- 17849,
17853,
17858,
17882,
@@ -624,7 +663,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
17993,
18001,
18004,
- 18013,
18024,
18049,
18053,
@@ -642,14 +680,14 @@ var DefaultTopASNs = container.NewMapSet[ASN](
18403,
18412,
18419,
- 18429,
+ 18678,
18734,
18747,
18809,
18822,
18840,
18881,
- 19037,
+ 19016,
19108,
19114,
19180,
@@ -657,11 +695,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
19246,
19422,
19429,
- 19515,
19624,
19711,
19863,
- 19889,
19978,
20001,
20011,
@@ -675,23 +711,21 @@ var DefaultTopASNs = container.NewMapSet[ASN](
20365,
20473,
20485,
+ 20545,
20626,
20634,
20661,
20676,
- 20712,
+ 20719,
20723,
20771,
20776,
20804,
20845,
- 20846,
20875,
20880,
20910,
20911,
- 20928,
- 20960,
20963,
20978,
21001,
@@ -699,10 +733,13 @@ var DefaultTopASNs = container.NewMapSet[ASN](
21021,
21040,
21050,
+ 21056,
+ 21069,
+ 21100,
21107,
- 21127,
21183,
21211,
+ 21221,
21230,
21232,
21246,
@@ -716,6 +753,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
21412,
21430,
21450,
+ 21466,
21491,
21497,
21502,
@@ -732,23 +770,28 @@ var DefaultTopASNs = container.NewMapSet[ASN](
22047,
22069,
22085,
+ 22313,
22423,
- 22581,
+ 22690,
22724,
+ 22735,
22773,
22869,
22884,
22927,
22933,
22995,
+ 23031,
23114,
23201,
23243,
23383,
- 23470,
23487,
23520,
+ 23563,
+ 23650,
23655,
+ 23657,
23673,
23674,
23688,
@@ -756,7 +799,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
23700,
23750,
23752,
- 23764,
23860,
23889,
23917,
@@ -768,12 +810,17 @@ var DefaultTopASNs = container.NewMapSet[ASN](
24016,
24033,
24086,
+ 24088,
+ 24138,
24157,
24158,
+ 24163,
24164,
+ 24165,
24186,
24203,
24309,
+ 24323,
24337,
24378,
24389,
@@ -781,7 +828,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
24432,
24439,
24441,
- 24444,
24445,
24492,
24499,
@@ -791,29 +837,32 @@ var DefaultTopASNs = container.NewMapSet[ASN](
24560,
24589,
24608,
+ 24645,
24651,
24691,
24722,
- 24743,
+ 24744,
+ 24751,
24757,
24800,
24812,
24822,
24835,
- 24851,
24852,
24863,
24875,
24877,
+ 24889,
24921,
24940,
+ 24953,
24955,
- 24991,
+ 24961,
+ 25003,
25019,
+ 25094,
25106,
25117,
- 25124,
- 25129,
25133,
25135,
25139,
@@ -821,31 +870,34 @@ var DefaultTopASNs = container.NewMapSet[ASN](
25159,
25184,
25190,
- 25211,
25229,
25248,
25250,
25255,
25274,
+ 25310,
25369,
25374,
+ 25375,
25400,
25406,
+ 25424,
25429,
25441,
25454,
25467,
25471,
25472,
+ 25490,
25491,
- 25496,
25512,
25513,
- 25521,
+ 25528,
25543,
25607,
25620,
25668,
+ 25695,
26130,
26210,
26599,
@@ -858,6 +910,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
27660,
27665,
27668,
+ 27669,
27672,
27694,
27695,
@@ -869,7 +922,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
27729,
27734,
27738,
- 27740,
27742,
27745,
27747,
@@ -882,6 +934,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
27789,
27800,
27813,
+ 27818,
27831,
27833,
27837,
@@ -903,13 +956,10 @@ var DefaultTopASNs = container.NewMapSet[ASN](
27932,
27947,
27951,
- 27953,
- 27955,
27983,
27984,
27988,
27995,
- 28005,
28006,
28009,
28015,
@@ -922,14 +972,12 @@ var DefaultTopASNs = container.NewMapSet[ASN](
28075,
28080,
28094,
+ 28103,
28104,
- 28110,
28118,
28126,
28146,
- 28182,
28186,
- 28191,
28198,
28201,
28210,
@@ -939,7 +987,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
28343,
28398,
28403,
- 28409,
28458,
28469,
28481,
@@ -951,15 +998,16 @@ var DefaultTopASNs = container.NewMapSet[ASN](
28534,
28536,
28537,
+ 28541,
28545,
28548,
28554,
28555,
28573,
- 28580,
28598,
28649,
28668,
+ 28669,
28683,
28685,
28725,
@@ -968,17 +1016,18 @@ var DefaultTopASNs = container.NewMapSet[ASN](
28787,
28812,
28840,
- 28851,
+ 28854,
+ 28878,
28884,
28885,
28919,
28952,
- 28954,
28964,
28972,
29027,
29030,
- 29031,
+ 29032,
+ 29039,
29049,
29061,
29070,
@@ -987,18 +1036,18 @@ var DefaultTopASNs = container.NewMapSet[ASN](
29119,
29124,
29170,
- 29194,
29208,
29238,
29244,
29247,
29256,
29286,
- 29300,
29310,
29314,
+ 29321,
29355,
29357,
+ 29405,
29447,
29465,
29485,
@@ -1017,6 +1066,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
29975,
30036,
30058,
+ 30272,
30526,
30600,
30619,
@@ -1024,11 +1074,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
30722,
30764,
30844,
+ 30848,
30873,
30896,
- 30925,
- 30929,
- 30969,
30982,
30985,
30986,
@@ -1038,9 +1086,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
30999,
31012,
31027,
- 31029,
31037,
31042,
+ 31115,
31117,
31122,
31126,
@@ -1049,6 +1097,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
31143,
31148,
31163,
+ 31167,
31169,
31200,
31204,
@@ -1056,25 +1105,31 @@ var DefaultTopASNs = container.NewMapSet[ASN](
31213,
31224,
31242,
+ 31245,
31246,
31252,
31272,
31287,
31404,
31423,
+ 31435,
31452,
31499,
+ 31510,
31543,
31549,
31615,
+ 31642,
31655,
- 31679,
+ 31689,
31721,
31725,
- 31726,
+ 31856,
31898,
+ 31960,
32020,
32098,
+ 32189,
32398,
32860,
33363,
@@ -1082,14 +1137,16 @@ var DefaultTopASNs = container.NewMapSet[ASN](
33567,
33576,
33582,
+ 33588,
33763,
33765,
33771,
33779,
33781,
+ 33788,
33796,
+ 33852,
33874,
- 33883,
33885,
33915,
33922,
@@ -1097,50 +1154,54 @@ var DefaultTopASNs = container.NewMapSet[ASN](
34001,
34058,
34087,
- 34120,
34170,
34187,
34224,
34244,
+ 34245,
34295,
34296,
+ 34306,
+ 34318,
+ 34347,
34362,
- 34368,
34447,
34458,
- 34471,
+ 34515,
34525,
34533,
34547,
34557,
34569,
+ 34577,
34594,
34606,
34661,
34666,
34700,
+ 34702,
+ 34705,
34718,
34724,
34743,
34772,
34779,
- 34781,
34797,
34803,
34857,
34876,
- 34916,
34918,
34977,
34984,
34989,
35046,
35047,
- 35063,
35091,
35104,
+ 35107,
35132,
35141,
+ 35158,
35179,
35191,
35197,
@@ -1149,47 +1210,43 @@ var DefaultTopASNs = container.NewMapSet[ASN](
35244,
35297,
35311,
- 35313,
35320,
35328,
35346,
35362,
35370,
- 35394,
35432,
35444,
35457,
- 35467,
35518,
+ 35525,
35549,
35566,
35567,
35568,
35612,
+ 35613,
35699,
35706,
35725,
35729,
- 35732,
35753,
- 35773,
35790,
35805,
35807,
35819,
- 35892,
35900,
35911,
36290,
36352,
- 36445,
+ 36408,
+ 36435,
36492,
36511,
36549,
36864,
36865,
36866,
- 36868,
36873,
36874,
36884,
@@ -1202,8 +1259,11 @@ var DefaultTopASNs = container.NewMapSet[ASN](
36908,
36909,
36912,
+ 36913,
36914,
+ 36916,
36920,
+ 36923,
36924,
36925,
36926,
@@ -1212,9 +1272,14 @@ var DefaultTopASNs = container.NewMapSet[ASN](
36937,
36939,
36947,
+ 36955,
36958,
+ 36959,
36962,
36963,
+ 36965,
+ 36969,
+ 36972,
36974,
36977,
36988,
@@ -1230,6 +1295,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37014,
37020,
37027,
+ 37028,
37030,
37035,
37037,
@@ -1241,6 +1307,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37063,
37069,
37073,
+ 37074,
37075,
37076,
37081,
@@ -1258,17 +1325,18 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37129,
37133,
37136,
- 37140,
37141,
- 37143,
37148,
37154,
+ 37163,
37164,
37168,
37173,
+ 37182,
37183,
37184,
37187,
+ 37189,
37190,
37196,
37203,
@@ -1282,7 +1350,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37228,
37229,
37233,
- 37236,
37254,
37257,
37282,
@@ -1293,9 +1360,8 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37305,
37309,
37313,
- 37315,
37323,
- 37326,
+ 37329,
37332,
37334,
37336,
@@ -1304,6 +1370,8 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37342,
37343,
37349,
+ 37350,
+ 37353,
37358,
37371,
37376,
@@ -1311,9 +1379,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37395,
37406,
37410,
+ 37414,
37424,
37425,
- 37427,
37429,
37430,
37440,
@@ -1325,9 +1393,13 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37460,
37461,
37473,
+ 37475,
+ 37480,
+ 37487,
37492,
37508,
37517,
+ 37518,
37524,
37526,
37529,
@@ -1340,17 +1412,18 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37552,
37559,
37563,
+ 37564,
+ 37566,
37575,
37577,
37580,
+ 37582,
37584,
- 37586,
- 37594,
+ 37604,
37611,
37612,
37614,
37616,
- 37621,
37622,
37637,
37642,
@@ -1363,25 +1436,27 @@ var DefaultTopASNs = container.NewMapSet[ASN](
37680,
37682,
37693,
- 37697,
37705,
37713,
37721,
+ 37731,
37963,
38008,
38009,
+ 38067,
38077,
+ 38107,
38136,
- 38172,
- 38176,
38195,
38198,
38201,
38203,
+ 38209,
38235,
38247,
38264,
38266,
+ 38286,
38322,
38442,
38466,
@@ -1395,60 +1470,61 @@ var DefaultTopASNs = container.NewMapSet[ASN](
38805,
38819,
38841,
- 38851,
38875,
38901,
38919,
+ 38987,
38999,
39007,
39010,
+ 39013,
39032,
39067,
39093,
- 39122,
39184,
+ 39190,
39216,
39232,
- 39246,
39251,
39273,
39280,
- 39308,
39344,
+ 39351,
39374,
- 39375,
+ 39377,
39397,
39401,
39402,
39501,
- 39507,
+ 39544,
+ 39568,
39603,
39608,
39611,
- 39615,
39642,
39647,
- 39650,
+ 39686,
39699,
39766,
- 39791,
39798,
39823,
39824,
39826,
39891,
- 39906,
- 40676,
+ 39927,
+ 40029,
40786,
40788,
40945,
- 40980,
+ 40981,
+ 40994,
41046,
41096,
41124,
41164,
41202,
41228,
+ 41230,
41313,
41329,
41330,
@@ -1462,39 +1538,36 @@ var DefaultTopASNs = container.NewMapSet[ASN](
41564,
41627,
41676,
- 41697,
41704,
- 41712,
41733,
41738,
- 41745,
41750,
41798,
41820,
41833,
- 41872,
- 41881,
41897,
- 41922,
41937,
41956,
+ 41966,
41997,
41998,
42003,
42013,
42082,
+ 42083,
42109,
+ 42162,
42183,
- 42205,
+ 42186,
42232,
- 42248,
+ 42235,
42298,
42306,
42313,
+ 42318,
42334,
42337,
- 42343,
- 42390,
+ 42346,
42437,
42455,
42525,
@@ -1505,9 +1578,10 @@ var DefaultTopASNs = container.NewMapSet[ASN](
42580,
42581,
42610,
+ 42621,
+ 42638,
42652,
42673,
- 42682,
42689,
42708,
42713,
@@ -1516,9 +1590,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
42828,
42837,
42841,
+ 42852,
42863,
42864,
- 42905,
42908,
42912,
42925,
@@ -1527,48 +1601,54 @@ var DefaultTopASNs = container.NewMapSet[ASN](
42991,
43019,
43060,
+ 43068,
43139,
43197,
43205,
43242,
+ 43248,
43256,
+ 43268,
+ 43277,
43350,
+ 43356,
43406,
43451,
43452,
43513,
43529,
43533,
+ 43548,
43557,
- 43568,
43612,
43627,
- 43633,
- 43653,
43700,
43708,
43733,
43754,
43766,
- 43791,
+ 43768,
+ 43769,
43824,
+ 43870,
43883,
+ 43892,
+ 43905,
43925,
43939,
43940,
+ 43994,
44021,
44027,
44034,
+ 44086,
44087,
- 44090,
44134,
44143,
44213,
44217,
44234,
44244,
- 44272,
- 44313,
44327,
44377,
44391,
@@ -1576,29 +1656,31 @@ var DefaultTopASNs = container.NewMapSet[ASN](
44477,
44483,
44489,
+ 44515,
44558,
44566,
- 44631,
44702,
- 44725,
+ 44708,
44735,
+ 44769,
44869,
- 44894,
- 44901,
44925,
+ 45007,
45090,
45102,
45143,
- 45168,
45177,
45178,
45193,
45245,
+ 45267,
45271,
45305,
45345,
+ 45349,
45355,
45356,
+ 45430,
45458,
45461,
45498,
@@ -1625,121 +1707,116 @@ var DefaultTopASNs = container.NewMapSet[ASN](
46198,
46408,
46650,
- 46868,
+ 47114,
+ 47132,
47139,
47159,
47169,
+ 47204,
47217,
47232,
- 47234,
47237,
47253,
- 47262,
- 47330,
47331,
- 47376,
47377,
47394,
+ 47474,
47485,
47524,
47588,
47589,
- 47702,
47782,
47790,
- 47794,
+ 47798,
47883,
47887,
47898,
47956,
- 47959,
47962,
+ 48014,
48092,
- 48133,
+ 48147,
48161,
+ 48181,
48190,
48206,
+ 48233,
48252,
48260,
48288,
- 48359,
48418,
48431,
+ 48437,
48492,
48503,
48506,
48629,
48642,
+ 48661,
48675,
- 48695,
+ 48685,
+ 48721,
48728,
48830,
48832,
48847,
- 48861,
48887,
- 48904,
48917,
48926,
+ 48944,
48966,
- 49040,
- 49044,
+ 49020,
49056,
49091,
49100,
49101,
49117,
49129,
+ 49183,
49223,
+ 49242,
49273,
49282,
- 49419,
+ 49285,
+ 49292,
+ 49460,
49528,
49561,
- 49567,
- 49602,
49628,
49724,
- 49770,
49798,
49800,
49808,
- 49824,
- 49849,
+ 49826,
+ 49840,
49889,
49902,
+ 49911,
49914,
49981,
- 49985,
50010,
- 50025,
50181,
+ 50195,
50223,
- 50231,
50251,
50266,
50274,
50294,
50304,
- 50318,
- 50334,
50349,
- 50360,
50411,
50463,
50467,
50482,
50500,
- 50558,
50581,
- 50593,
50613,
50616,
50635,
- 50666,
+ 50648,
50670,
+ 50673,
50685,
- 50718,
50767,
50770,
50810,
@@ -1749,14 +1826,17 @@ var DefaultTopASNs = container.NewMapSet[ASN](
50925,
50953,
50959,
- 50971,
+ 50962,
50973,
50979,
+ 51002,
51018,
51020,
+ 51026,
51056,
51104,
51110,
+ 51132,
51142,
51167,
51175,
@@ -1764,36 +1844,34 @@ var DefaultTopASNs = container.NewMapSet[ASN](
51207,
51265,
51336,
- 51341,
51346,
51375,
+ 51395,
51407,
51430,
- 51495,
51504,
51582,
51604,
- 51615,
+ 51648,
51653,
51684,
51765,
51784,
51809,
51825,
- 51852,
+ 51878,
51896,
52075,
+ 52116,
52228,
52233,
52238,
52242,
- 52251,
52253,
52257,
52260,
52262,
52263,
- 52300,
52312,
52323,
52341,
@@ -1801,7 +1879,8 @@ var DefaultTopASNs = container.NewMapSet[ASN](
52362,
52363,
52373,
- 52391,
+ 52381,
+ 52389,
52398,
52405,
52409,
@@ -1810,12 +1889,9 @@ var DefaultTopASNs = container.NewMapSet[ASN](
52436,
52444,
52455,
- 52465,
52468,
52471,
- 52477,
52613,
- 52783,
52974,
53006,
53667,
@@ -1824,9 +1900,10 @@ var DefaultTopASNs = container.NewMapSet[ASN](
54198,
54614,
54994,
- 55020,
- 55081,
+ 55256,
+ 55329,
55330,
+ 55387,
55391,
55392,
55424,
@@ -1867,186 +1944,191 @@ var DefaultTopASNs = container.NewMapSet[ASN](
56262,
56293,
56300,
+ 56309,
56329,
+ 56349,
+ 56400,
56410,
+ 56456,
+ 56468,
56478,
- 56484,
+ 56491,
+ 56496,
56497,
- 56515,
- 56548,
56568,
+ 56630,
56653,
56655,
56665,
56696,
56704,
- 56709,
- 56803,
+ 56800,
56902,
57000,
- 57013,
57016,
+ 57043,
57070,
57112,
57133,
57134,
- 57172,
- 57184,
57218,
- 57248,
+ 57223,
57256,
57269,
57293,
- 57332,
57344,
57370,
57374,
57388,
57389,
- 57443,
57491,
57513,
+ 57547,
57564,
57566,
- 57608,
+ 57606,
57630,
+ 57634,
+ 57722,
57728,
57743,
57760,
- 57761,
57764,
57778,
57794,
57852,
57869,
57888,
+ 57916,
58061,
58065,
- 58118,
+ 58098,
+ 58130,
58224,
- 58264,
- 58321,
+ 58309,
58322,
- 58424,
+ 58328,
58453,
58460,
58461,
58485,
58504,
58507,
- 58519,
58524,
- 58593,
+ 58539,
+ 58541,
+ 58542,
58610,
58655,
58656,
58682,
58689,
+ 58697,
58715,
58717,
58731,
58821,
+ 58879,
58895,
58945,
58952,
- 59078,
- 59108,
59125,
- 59126,
59253,
59257,
59317,
- 59443,
+ 59318,
+ 59362,
59497,
- 59573,
59588,
59625,
59668,
59702,
59729,
- 59770,
59847,
59861,
59890,
- 59895,
59931,
59989,
60068,
60111,
- 60213,
60258,
60294,
- 60304,
60352,
60367,
60372,
60377,
- 60407,
+ 60405,
+ 60415,
60471,
60517,
+ 60587,
60588,
60636,
- 60715,
+ 60656,
+ 60690,
60725,
60757,
60781,
60806,
- 60886,
- 61071,
+ 60829,
+ 60871,
+ 60999,
61079,
61112,
61135,
+ 61138,
61143,
- 61154,
61189,
+ 61211,
61272,
61275,
61287,
61307,
61317,
+ 61449,
61461,
61466,
+ 61468,
61478,
61512,
61588,
- 62005,
62013,
+ 62099,
62161,
62179,
62183,
62211,
62240,
+ 62250,
62282,
62336,
- 62337,
62419,
62563,
- 62627,
+ 62651,
63023,
63199,
- 63473,
63526,
63852,
63859,
+ 63888,
63945,
63949,
63969,
63991,
64037,
- 64043,
64073,
64098,
64105,
64134,
- 64453,
64466,
131090,
131111,
131178,
- 131198,
131207,
131267,
131284,
+ 131322,
+ 131325,
131429,
131445,
131464,
@@ -2054,11 +2136,13 @@ var DefaultTopASNs = container.NewMapSet[ASN](
131584,
131591,
131596,
- 131602,
131627,
+ 131706,
+ 131769,
+ 131925,
+ 132021,
132045,
132061,
- 132080,
132148,
132165,
132167,
@@ -2066,40 +2150,40 @@ var DefaultTopASNs = container.NewMapSet[ASN](
132199,
132203,
132204,
- 132222,
+ 132255,
132298,
132447,
- 132449,
132462,
132468,
132471,
- 132480,
132513,
132618,
- 132825,
132831,
- 133012,
133076,
- 133206,
- 133287,
+ 133199,
133334,
133384,
133385,
- 133480,
133481,
133524,
+ 133533,
133606,
133612,
+ 133613,
133623,
133661,
133752,
+ 133774,
133875,
+ 133894,
133897,
133982,
134090,
+ 134113,
134134,
134204,
134356,
+ 134420,
134467,
134489,
134562,
@@ -2107,100 +2191,113 @@ var DefaultTopASNs = container.NewMapSet[ASN](
134674,
134697,
134707,
+ 134711,
134714,
134715,
134732,
134739,
- 134772,
+ 134761,
+ 134762,
+ 134768,
134774,
134783,
- 134806,
134840,
134995,
135043,
+ 135069,
135126,
135298,
- 135300,
135327,
135341,
+ 135371,
135375,
135376,
135377,
135405,
135407,
135409,
+ 135427,
135477,
135478,
135589,
135600,
135607,
135887,
+ 135905,
136000,
136030,
136039,
136093,
136119,
- 136141,
136167,
- 136188,
+ 136168,
136210,
+ 136224,
+ 136229,
136238,
+ 136239,
136255,
- 136258,
136380,
136384,
136442,
- 136454,
136477,
136479,
136480,
136515,
136525,
- 136538,
+ 136530,
136557,
+ 136748,
136780,
136787,
+ 136802,
136873,
136897,
136907,
+ 136919,
+ 136921,
136950,
136969,
136972,
136975,
136994,
- 137029,
137047,
137080,
+ 137187,
137226,
137409,
137412,
- 137425,
+ 137424,
137449,
+ 137453,
+ 137503,
137526,
137561,
- 137811,
+ 137580,
+ 137693,
+ 137697,
137824,
+ 137853,
137872,
137880,
+ 137895,
137959,
137967,
+ 137989,
138014,
138089,
+ 138123,
138167,
138168,
138179,
138197,
- 138322,
- 138346,
138368,
138384,
138423,
- 138500,
- 138519,
+ 138506,
138529,
138590,
- 138607,
- 138629,
+ 138634,
138638,
138640,
138655,
@@ -2209,21 +2306,22 @@ var DefaultTopASNs = container.NewMapSet[ASN](
138886,
138915,
138964,
+ 138965,
+ 138997,
139003,
139009,
139029,
139043,
- 139203,
+ 139080,
139224,
- 139285,
- 139580,
+ 139238,
+ 139325,
+ 139609,
139628,
139741,
139759,
139766,
139831,
- 139841,
- 139849,
139879,
139898,
139922,
@@ -2231,74 +2329,75 @@ var DefaultTopASNs = container.NewMapSet[ASN](
139967,
139994,
140045,
+ 140061,
140072,
- 140096,
140220,
140292,
140401,
+ 140457,
140499,
- 140686,
- 140867,
+ 140504,
+ 140594,
+ 140707,
140900,
- 140948,
140989,
141024,
141031,
141039,
141047,
- 141127,
- 141140,
141145,
- 141199,
- 141215,
+ 141177,
141216,
141342,
141421,
141607,
- 141680,
141681,
- 141704,
141711,
141767,
141778,
141883,
141995,
+ 142051,
142065,
+ 142271,
142295,
142352,
- 142541,
142552,
142647,
147049,
- 147293,
- 147314,
+ 147176,
+ 147184,
149024,
149034,
+ 149173,
149359,
149360,
149419,
149456,
+ 149707,
149771,
+ 149810,
149866,
- 150131,
- 150153,
- 150222,
+ 150309,
150331,
150371,
150452,
150683,
150692,
+ 150748,
150750,
150774,
151080,
151341,
151396,
+ 151498,
151636,
- 151802,
151983,
+ 152093,
+ 152605,
196640,
196735,
- 196737,
+ 196775,
196838,
196874,
196900,
@@ -2307,16 +2406,19 @@ var DefaultTopASNs = container.NewMapSet[ASN](
197119,
197207,
197225,
+ 197248,
197296,
197301,
- 197324,
197350,
197423,
+ 197451,
+ 197470,
+ 197540,
+ 197547,
197556,
197623,
- 197637,
+ 197648,
197674,
- 197704,
197706,
197830,
197862,
@@ -2325,69 +2427,70 @@ var DefaultTopASNs = container.NewMapSet[ASN](
198023,
198068,
198252,
- 198259,
198265,
198279,
198288,
198440,
- 198441,
198504,
198589,
198605,
+ 198632,
198668,
198735,
198820,
+ 198890,
198961,
198966,
- 199061,
+ 199081,
199140,
- 199239,
+ 199155,
+ 199173,
199276,
- 199284,
+ 199468,
199469,
- 199490,
199493,
199524,
199620,
+ 199636,
199698,
199707,
199731,
199739,
- 199987,
199995,
200019,
200134,
200154,
200313,
200446,
- 200565,
200590,
200640,
+ 200651,
200665,
200724,
200736,
200740,
- 200742,
200845,
200865,
+ 201000,
201011,
201019,
- 201031,
+ 201041,
201073,
201089,
+ 201107,
+ 201150,
201167,
201187,
201235,
201241,
201249,
- 201363,
+ 201322,
201411,
201502,
201505,
+ 201540,
201577,
- 201596,
201603,
- 201746,
201749,
201767,
201776,
@@ -2397,88 +2500,72 @@ var DefaultTopASNs = container.NewMapSet[ASN](
201986,
201997,
202023,
- 202080,
202087,
202098,
202103,
202204,
- 202243,
202254,
- 202282,
202293,
- 202422,
+ 202391,
202433,
202441,
202468,
202498,
202561,
202613,
- 202616,
- 202619,
202632,
202635,
- 202651,
202662,
+ 202672,
+ 202710,
+ 202759,
202870,
- 202872,
202914,
202921,
+ 202931,
202940,
- 202943,
- 202965,
202987,
203020,
- 203106,
203136,
203206,
203214,
203217,
203409,
203424,
- 203446,
- 203448,
203451,
203459,
203561,
203622,
203675,
203680,
- 203735,
203811,
- 203827,
203877,
203912,
+ 203916,
203936,
203953,
203971,
203995,
- 203999,
204106,
204108,
204151,
204165,
- 204168,
204170,
- 204249,
204274,
204279,
204317,
204342,
204356,
+ 204390,
204403,
204457,
204592,
204595,
- 204601,
- 204649,
- 204666,
+ 204716,
204793,
- 204816,
- 204873,
204918,
204957,
204986,
- 205015,
205110,
205119,
205134,
@@ -2487,25 +2574,24 @@ var DefaultTopASNs = container.NewMapSet[ASN](
205254,
205277,
205278,
- 205293,
205362,
+ 205367,
205368,
- 205473,
+ 205371,
+ 205546,
205547,
- 205623,
205638,
205647,
205714,
205800,
205832,
- 205872,
205889,
+ 205984,
206026,
206065,
206067,
- 206088,
+ 206092,
206119,
- 206194,
206206,
206238,
206260,
@@ -2514,82 +2600,82 @@ var DefaultTopASNs = container.NewMapSet[ASN](
206358,
206375,
206406,
- 206478,
- 206485,
- 206519,
+ 206471,
+ 206472,
206557,
206610,
+ 206635,
206666,
206774,
206783,
+ 206804,
+ 206892,
+ 206912,
206920,
+ 206977,
207044,
207097,
207137,
- 207154,
+ 207164,
207192,
207251,
207281,
207369,
207375,
- 207464,
207502,
207569,
207589,
- 207645,
+ 207617,
207713,
207728,
207782,
207810,
207876,
207980,
- 207990,
207991,
- 208040,
+ 208031,
+ 208149,
208286,
208320,
208324,
208339,
- 208365,
- 208555,
- 208570,
208592,
208668,
- 208670,
208671,
208708,
208730,
208734,
208864,
208905,
+ 208909,
208972,
208997,
+ 209001,
209046,
209049,
209193,
209240,
209262,
+ 209273,
209277,
209302,
209360,
209424,
209442,
- 209531,
- 209828,
+ 209613,
+ 209733,
209835,
209839,
209854,
210003,
210016,
210021,
- 210125,
210147,
- 210152,
- 210162,
- 210179,
+ 210150,
210218,
210273,
210278,
+ 210306,
210315,
210402,
210616,
@@ -2597,40 +2683,37 @@ var DefaultTopASNs = container.NewMapSet[ASN](
210644,
210693,
210740,
+ 210748,
210808,
- 210964,
- 210974,
211028,
211057,
- 211147,
+ 211196,
211210,
211211,
211309,
211322,
211356,
- 211385,
- 211450,
+ 211418,
+ 211458,
211468,
+ 211504,
211559,
- 211689,
211720,
- 211790,
211908,
211913,
211995,
212046,
- 212050,
212183,
212238,
212330,
- 212444,
+ 212435,
212449,
212531,
- 212538,
212572,
212616,
212637,
212645,
+ 212652,
212655,
212661,
212766,
@@ -2639,64 +2722,74 @@ var DefaultTopASNs = container.NewMapSet[ASN](
212986,
212999,
213155,
+ 213250,
213295,
213320,
+ 213373,
213398,
213402,
+ 215157,
215284,
+ 215287,
+ 215346,
+ 215416,
215423,
215501,
+ 215540,
215733,
215746,
- 215904,
215910,
+ 215946,
+ 216046,
216071,
+ 216086,
216139,
216200,
- 216259,
- 216312,
+ 216325,
216374,
262145,
262146,
262149,
262159,
- 262179,
262181,
262186,
+ 262187,
+ 262188,
262191,
- 262196,
262197,
262202,
262210,
- 262220,
+ 262215,
262223,
262234,
262239,
262241,
+ 262248,
262253,
262262,
- 262287,
262354,
262378,
262459,
262468,
262481,
+ 262494,
262589,
- 262659,
262753,
262773,
262916,
262932,
263073,
+ 263170,
263175,
- 263189,
263210,
+ 263216,
263222,
- 263223,
263224,
263238,
263242,
263245,
+ 263248,
+ 263292,
263327,
263684,
263686,
@@ -2706,6 +2799,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
263703,
263717,
263725,
+ 263732,
263749,
263750,
263751,
@@ -2716,9 +2810,11 @@ var DefaultTopASNs = container.NewMapSet[ASN](
263783,
263791,
263792,
+ 263793,
263805,
263824,
263980,
+ 264221,
264605,
264609,
264628,
@@ -2728,33 +2824,33 @@ var DefaultTopASNs = container.NewMapSet[ASN](
264645,
264646,
264663,
- 264681,
264685,
264694,
264696,
+ 264719,
+ 264731,
264733,
264738,
- 264744,
- 264746,
264750,
+ 264756,
+ 264758,
264770,
264778,
264779,
264780,
- 264783,
- 264796,
+ 264800,
+ 264811,
264814,
264821,
264825,
264837,
264838,
- 264844,
264847,
265540,
265561,
265594,
+ 265605,
265606,
- 265608,
265631,
265632,
265636,
@@ -2763,12 +2859,11 @@ var DefaultTopASNs = container.NewMapSet[ASN](
265686,
265688,
265691,
- 265706,
+ 265711,
265721,
265724,
265727,
- 265745,
- 265759,
+ 265762,
265767,
265780,
265798,
@@ -2781,67 +2876,69 @@ var DefaultTopASNs = container.NewMapSet[ASN](
266445,
266668,
266673,
+ 266686,
+ 266694,
266698,
- 266730,
+ 266725,
266734,
266742,
266755,
- 266771,
- 266783,
- 266792,
+ 266757,
266802,
+ 266805,
266809,
266814,
266815,
- 266832,
+ 266830,
+ 266831,
266841,
266853,
266858,
266860,
266870,
+ 266876,
266880,
266893,
- 266894,
266904,
267684,
267685,
267699,
+ 267702,
267705,
267708,
267713,
267749,
267761,
267765,
+ 267767,
267790,
267795,
267797,
267803,
267809,
267828,
- 267831,
267845,
267846,
- 267869,
267882,
267883,
- 267904,
267916,
- 267920,
268323,
268976,
- 269036,
269729,
269730,
269733,
269734,
269738,
- 269747,
269749,
- 269750,
+ 269769,
+ 269780,
269782,
269783,
+ 269788,
+ 269794,
269797,
269804,
+ 269806,
269816,
269820,
269822,
@@ -2849,16 +2946,14 @@ var DefaultTopASNs = container.NewMapSet[ASN](
269832,
269838,
269840,
+ 269843,
269846,
269853,
- 269857,
269862,
269894,
+ 269898,
269901,
- 269905,
- 269906,
269908,
- 269918,
269919,
269921,
269927,
@@ -2868,7 +2963,6 @@ var DefaultTopASNs = container.NewMapSet[ASN](
269940,
269946,
269950,
- 269953,
269955,
269960,
269964,
@@ -2878,6 +2972,7 @@ var DefaultTopASNs = container.NewMapSet[ASN](
269984,
269989,
270007,
+ 270009,
270026,
270029,
270035,
@@ -2886,28 +2981,22 @@ var DefaultTopASNs = container.NewMapSet[ASN](
270052,
270058,
270068,
- 270073,
- 270084,
270096,
- 270102,
+ 270098,
270108,
270161,
270814,
271773,
- 271775,
271781,
271785,
271791,
- 271793,
271795,
- 271799,
+ 271806,
271808,
271812,
271814,
271819,
- 271822,
271835,
- 271837,
271855,
271868,
271874,
@@ -2917,127 +3006,148 @@ var DefaultTopASNs = container.NewMapSet[ASN](
271911,
271929,
271930,
- 271931,
271933,
- 271942,
- 271951,
- 271962,
+ 271935,
+ 271936,
+ 271943,
271965,
- 271969,
+ 271968,
271971,
- 271996,
- 272006,
- 272011,
272015,
272018,
- 272019,
272026,
+ 272037,
272057,
272059,
- 272062,
- 272082,
272083,
- 272099,
+ 272095,
272102,
272106,
272110,
272112,
+ 272120,
272122,
- 272129,
272134,
272809,
272818,
- 272827,
272836,
- 272838,
272848,
- 272868,
+ 272851,
272882,
272886,
- 272943,
- 272955,
+ 272906,
+ 272916,
+ 272921,
+ 272946,
+ 272954,
272962,
- 272979,
- 272980,
+ 272978,
272991,
- 273000,
+ 272998,
+ 273019,
+ 273024,
273048,
273054,
+ 273063,
+ 273066,
+ 273067,
273093,
+ 273095,
273113,
+ 273121,
273133,
+ 273155,
+ 273171,
+ 273309,
327687,
327693,
+ 327694,
327697,
+ 327700,
327707,
- 327708,
327712,
327714,
327716,
327724,
327738,
327742,
- 327747,
327750,
327756,
327760,
327765,
- 327768,
327769,
327770,
+ 327771,
327776,
327782,
327786,
+ 327794,
+ 327795,
327799,
327802,
327804,
- 327819,
+ 327809,
+ 327820,
327828,
+ 327829,
327830,
327862,
- 327863,
+ 327864,
327871,
327885,
327900,
327901,
327903,
+ 327907,
327931,
327934,
+ 327941,
327947,
327972,
327975,
- 327987,
- 327991,
+ 327983,
+ 327992,
327996,
328061,
+ 328068,
328073,
328075,
+ 328076,
328079,
328088,
+ 328111,
+ 328118,
328136,
328140,
328169,
+ 328178,
+ 328187,
328191,
328196,
328198,
328200,
328207,
- 328215,
328223,
328228,
+ 328244,
+ 328249,
328250,
328253,
- 328282,
+ 328258,
+ 328259,
+ 328271,
328286,
328297,
328309,
328310,
- 328316,
328319,
328331,
+ 328333,
328341,
328358,
328411,
+ 328436,
+ 328442,
328469,
328471,
328473,
@@ -3052,64 +3162,69 @@ var DefaultTopASNs = container.NewMapSet[ASN](
328514,
328535,
328539,
+ 328546,
328549,
- 328576,
+ 328567,
+ 328570,
328581,
328586,
328590,
328594,
- 328600,
+ 328604,
328605,
328610,
- 328611,
328614,
328619,
- 328636,
328638,
- 328652,
328659,
328676,
328697,
328702,
328708,
+ 328716,
328717,
328727,
+ 328734,
+ 328753,
328755,
328777,
328817,
+ 328824,
328844,
+ 328849,
328856,
328858,
328880,
- 328895,
+ 328919,
328923,
328939,
328943,
+ 328949,
328954,
328959,
328961,
- 328975,
+ 328965,
328977,
+ 328979,
328987,
328988,
328993,
328997,
+ 329006,
329014,
+ 329020,
+ 329021,
329027,
329029,
+ 329041,
329044,
- 329048,
329078,
329082,
- 329094,
329101,
329110,
- 329119,
329129,
329135,
329167,
- 329174,
- 329177,
329179,
329183,
329192,
@@ -3118,16 +3233,19 @@ var DefaultTopASNs = container.NewMapSet[ASN](
329219,
329220,
329253,
- 329254,
- 329261,
+ 329255,
329274,
- 329286,
- 329288,
329301,
+ 329310,
329373,
329387,
+ 329390,
+ 329411,
+ 329415,
393275,
+ 393559,
393629,
+ 393894,
394311,
394381,
394684,
@@ -3142,20 +3260,20 @@ var DefaultTopASNs = container.NewMapSet[ASN](
397961,
398228,
398721,
+ 398901,
+ 399077,
399724,
400266,
- 400354,
- 400618,
)
// DefaultCountryTopASNs is a mapping of a country to their top ASNs.
var DefaultCountryTopASNs = map[Country]ASN{
CountryAD: 6752,
CountryAE: 5384,
- CountryAF: 9009,
+ CountryAF: 55330,
CountryAG: 11594,
CountryAI: 396304,
- CountryAL: 42313,
+ CountryAL: 50616,
CountryAM: 44395,
CountryAO: 37119,
CountryAR: 7303,
@@ -3164,10 +3282,10 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryAU: 1221,
CountryAW: 11816,
CountryAX: 3238,
- CountryAZ: 28787,
+ CountryAZ: 8814,
CountryBA: 9146,
CountryBB: 14813,
- CountryBD: 24389,
+ CountryBD: 24432,
CountryBE: 5432,
CountryBF: 37577,
CountryBG: 8866,
@@ -3178,11 +3296,11 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryBN: 10094,
CountryBO: 6568,
CountryBQ: 27745,
- CountryBR: 28573,
+ CountryBR: 26599,
CountryBS: 15146,
CountryBT: 18024,
CountryBW: 14988,
- CountryBY: 6697,
+ CountryBY: 25106,
CountryBZ: 10269,
CountryCA: 812,
CountryCD: 37020,
@@ -3191,19 +3309,19 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryCH: 6730,
CountryCI: 29571,
CountryCK: 10131,
- CountryCL: 7418,
- CountryCM: 36912,
+ CountryCL: 27651,
+ CountryCM: 30992,
CountryCN: 4134,
CountryCO: 10620,
- CountryCR: 52263,
+ CountryCR: 11830,
CountryCU: 27725,
CountryCV: 37517,
- CountryCW: 52233,
+ CountryCW: 27660,
CountryCY: 6866,
CountryCZ: 5610,
CountryDE: 3320,
CountryDJ: 30990,
- CountryDK: 13335,
+ CountryDK: 212238,
CountryDM: 40945,
CountryDO: 6400,
CountryDZ: 36947,
@@ -3215,7 +3333,6 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryET: 24757,
CountryFI: 51765,
CountryFJ: 38442,
- CountryFK: 204649,
CountryFM: 139759,
CountryFO: 15389,
CountryFR: 3215,
@@ -3226,15 +3343,15 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryGF: 3215,
CountryGG: 8680,
CountryGH: 30986,
- CountryGI: 8772,
+ CountryGI: 202087,
CountryGL: 8818,
- CountryGM: 37552,
+ CountryGM: 25250,
CountryGN: 37461,
- CountryGP: 3215,
+ CountryGP: 16028,
CountryGQ: 37173,
CountryGR: 6799,
CountryGT: 14754,
- CountryGU: 9246,
+ CountryGU: 7131,
CountryGW: 37559,
CountryGY: 19863,
CountryHK: 4760,
@@ -3243,39 +3360,39 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryHT: 52260,
CountryHU: 5483,
CountryID: 7713,
- CountryIE: 6830,
+ CountryIE: 15502,
CountryIL: 1680,
CountryIM: 13122,
CountryIN: 55836,
CountryIO: 17458,
CountryIQ: 203214,
- CountryIR: 44244,
- CountryIS: 44925,
+ CountryIR: 197207,
+ CountryIS: 44735,
CountryIT: 1267,
CountryJE: 8681,
CountryJM: 30689,
- CountryJO: 48832,
+ CountryJO: 8376,
CountryJP: 2516,
CountryKE: 33771,
CountryKG: 50223,
CountryKH: 38623,
- CountryKI: 134783,
- CountryKM: 36939,
+ CountryKI: 135409,
+ CountryKM: 328061,
CountryKN: 36290,
CountryKP: 13335,
CountryKR: 4766,
CountryKW: 29357,
CountryKY: 6639,
CountryKZ: 206026,
- CountryLA: 131267,
+ CountryLA: 9873,
CountryLB: 42003,
CountryLC: 15344,
- CountryLI: 9009,
+ CountryLI: 20634,
CountryLK: 18001,
- CountryLR: 37094,
- CountryLS: 33567,
+ CountryLR: 37410,
+ CountryLS: 37057,
CountryLT: 8764,
- CountryLU: 53667,
+ CountryLU: 6661,
CountryLV: 24921,
CountryLY: 328286,
CountryMA: 36903,
@@ -3287,29 +3404,29 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryMH: 24439,
CountryMK: 6821,
CountryML: 30985,
- CountryMM: 13335,
+ CountryMM: 136255,
CountryMN: 17882,
CountryMO: 4609,
CountryMP: 7131,
- CountryMQ: 3215,
+ CountryMQ: 20776,
CountryMR: 29544,
- CountryMS: 11139,
+ CountryMS: 396304,
CountryMT: 33874,
CountryMU: 23889,
CountryMV: 7642,
- CountryMW: 37440,
+ CountryMW: 37294,
CountryMX: 8151,
CountryMY: 4788,
CountryMZ: 37342,
CountryNA: 36996,
- CountryNC: 56089,
+ CountryNC: 18200,
CountryNE: 37531,
- CountryNF: 45168,
CountryNG: 29465,
CountryNI: 14754,
CountryNL: 1136,
CountryNO: 29695,
CountryNP: 17501,
+ CountryNR: 140504,
CountryNZ: 9790,
CountryOM: 28885,
CountryPA: 11556,
@@ -3319,14 +3436,15 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryPH: 9299,
CountryPK: 45669,
CountryPL: 5617,
- CountryPM: 3695,
+ CountryPM: 198605,
+ CountryPN: 198605,
CountryPR: 14638,
CountryPS: 12975,
- CountryPT: 3243,
+ CountryPT: 12353,
CountryPW: 17893,
CountryPY: 23201,
- CountryQA: 42298,
- CountryRE: 3215,
+ CountryQA: 8781,
+ CountryRE: 49902,
CountryRO: 8708,
CountryRS: 8400,
CountryRU: 8359,
@@ -3336,22 +3454,22 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountrySC: 36958,
CountrySD: 15706,
CountrySE: 1257,
- CountrySG: 4773,
+ CountrySG: 13335,
CountrySH: 33763,
- CountrySI: 5603,
+ CountrySI: 3212,
CountrySK: 6855,
CountrySL: 36988,
CountrySM: 15433,
CountrySN: 8346,
CountrySO: 37371,
CountrySR: 27775,
- CountrySS: 37594,
+ CountrySS: 328755,
CountryST: 328191,
CountrySV: 14754,
- CountrySX: 27734,
+ CountrySX: 27781,
CountrySY: 29256,
CountrySZ: 328169,
- CountryTC: 394311,
+ CountryTC: 22933,
CountryTD: 327802,
CountryTG: 36924,
CountryTH: 131445,
@@ -3367,16 +3485,16 @@ var DefaultCountryTopASNs = map[Country]ASN{
CountryTZ: 36908,
CountryUA: 15895,
CountryUG: 37075,
- CountryUS: 7922,
+ CountryUS: 21928,
CountryUY: 6057,
CountryUZ: 8193,
CountryVA: 8978,
CountryVC: 46408,
CountryVE: 8048,
- CountryVG: 396357,
+ CountryVG: 22069,
CountryVI: 14434,
CountryVN: 7552,
- CountryVU: 9249,
+ CountryVU: 45355,
CountryWF: 45879,
CountryWS: 38800,
CountryXK: 21246,
diff --git a/internal/geoip/country.go b/internal/geoip/country.go
index d4a3369..b304823 100644
--- a/internal/geoip/country.go
+++ b/internal/geoip/country.go
@@ -19,6 +19,18 @@ type Country string
const (
// CountryNone is an invalid or unknown country code.
CountryNone Country = ""
+
+ // CountryNotApplicable is the user-assigned ISO 3166-1 alpha-2 code used
+ // when a country of origin cannot be determined due to a lack of
+ // information, for example a response of the record type that doesn't
+ // contain an IP address.
+ CountryNotApplicable Country = "QN"
+
+ // CountryXK is the user-assigned ISO 3166-1 alpha-2 code for Republic of
+ // Kosovo. Kosovo does not have a recognized ISO 3166 code, but it is still
+ // an entity whose user-assigned code is relatively common.
+ CountryXK Country = "XK"
+
// CountryAD is the ISO 3166-1 alpha-2 code for
// Andorra.
CountryAD Country = "AD"
@@ -766,11 +778,6 @@ const (
// CountryZW is the ISO 3166-1 alpha-2 code for
// Zimbabwe.
CountryZW Country = "ZW"
-
- // CountryXK is the user-assigned ISO 3166-1 alpha-2 code for Republic of
- // Kosovo. Kosovo does not have a recognized ISO 3166 code, but it is still
- // an entity whose user-assigned code is relatively common.
- CountryXK Country = "XK"
)
// NewCountry converts s into a Country while also validating it. Prefer to use
diff --git a/internal/geoip/country_generate.go b/internal/geoip/country_generate.go
index e522656..7ebbc8a 100644
--- a/internal/geoip/country_generate.go
+++ b/internal/geoip/country_generate.go
@@ -78,17 +78,25 @@ type Country string
// user-assigned ones.
const (
// CountryNone is an invalid or unknown country code.
- CountryNone Country = ""{{ range . }}
- {{ $name := (index . 0) -}}
- {{ $code := (index . 1) -}}
- // Country{{$code}} is the ISO 3166-1 alpha-2 code for
- // {{ $name }}.
- Country{{$code}} Country = {{ printf "%q" $code }}{{ end }}
+ CountryNone Country = ""
+
+ // CountryNotApplicable is the user-assigned ISO 3166-1 alpha-2 code used
+ // when a country of origin cannot be determined due to a lack of
+ // information, for example a response of the record type that doesn't
+ // contain an IP address.
+ CountryNotApplicable Country = "QN"
// CountryXK is the user-assigned ISO 3166-1 alpha-2 code for Republic of
// Kosovo. Kosovo does not have a recognized ISO 3166 code, but it is still
// an entity whose user-assigned code is relatively common.
CountryXK Country = "XK"
+{{ range . }}
+ {{ $name := (index . 0) -}}
+ {{ $code := (index . 1) -}}
+ // Country{{ $code }} is the ISO 3166-1 alpha-2 code for
+ // {{ $name }}.
+ Country{{ $code }} Country = {{ printf "%q" $code }}
+{{- end }}
)
// NewCountry converts s into a Country while also validating it. Prefer to use
diff --git a/internal/geoip/file.go b/internal/geoip/file.go
index ba5923d..6136d40 100644
--- a/internal/geoip/file.go
+++ b/internal/geoip/file.go
@@ -17,8 +17,17 @@ import (
"github.com/oschwald/maxminddb-golang"
)
+// Constants that define cache identifiers for the cache manager.
+const (
+ CacheIDIP = "geoip_ip"
+ CacheIDHost = "geoip_host"
+)
+
// FileConfig is the file-based GeoIP configuration structure.
type FileConfig struct {
+ // CacheManager is the global cache manager. CacheManager must not be nil.
+ CacheManager agdcache.Manager
+
// AllTopASNs contains all subnets from CountryTopASNs. While scanning the
// statistics data file this set is used to check if the current ASN
// included in CountryTopASNs.
@@ -42,7 +51,8 @@ type FileConfig struct {
IPCacheSize int
}
-// File is a file implementation of [geoip.Interface].
+// File is a file implementation of [geoip.Interface]. It should be initially
+// refreshed before use.
type File struct {
allTopASNs *container.MapSet[ASN]
countryTopASNs map[Country]ASN
@@ -70,9 +80,6 @@ type File struct {
asnPath string
countryPath string
-
- ipCacheSize int
- hostCacheSize int
}
// countrySubnets is a country-to-subnet mapping.
@@ -108,30 +115,38 @@ func newLocationKey(asn ASN, ctry Country, subdiv string) (l locationKey) {
}
}
-// NewFile returns a new GeoIP database that reads information from a file.
-func NewFile(c *FileConfig) (f *File, err error) {
- f = &File{
+// NewFile returns a new GeoIP database that reads information from a file. It
+// also adds the caches with IDs [CacheIDIP] and [CacheIDHost] to the cache
+// manager.
+func NewFile(c *FileConfig) (f *File) {
+ var hostCache agdcache.Interface[string, *Location]
+ if c.HostCacheSize == 0 {
+ hostCache = agdcache.Empty[string, *Location]{}
+ } else {
+ hostCache = agdcache.NewLRU[string, *Location](&agdcache.LRUConfig{
+ Size: c.HostCacheSize,
+ })
+ }
+
+ ipCache := agdcache.NewLRU[any, *Location](&agdcache.LRUConfig{
+ Size: c.IPCacheSize,
+ })
+
+ c.CacheManager.Add(CacheIDHost, hostCache)
+ c.CacheManager.Add(CacheIDIP, ipCache)
+
+ return &File{
mu: &sync.RWMutex{},
+ ipCache: ipCache,
+ hostCache: hostCache,
+
asnPath: c.ASNPath,
countryPath: c.CountryPath,
- ipCacheSize: c.IPCacheSize,
- hostCacheSize: c.HostCacheSize,
-
allTopASNs: c.AllTopASNs,
countryTopASNs: c.CountryTopASNs,
}
-
- // TODO(a.garipov): Consider adding software module ID into the contexts and
- // adding base contexts.
- ctx := context.Background()
- err = f.Refresh(ctx)
- if err != nil {
- return nil, fmt.Errorf("initial refresh: %w", err)
- }
-
- return f, nil
}
// ipToCacheKey returns the cache key for ip. The cache key is a three-byte
@@ -384,17 +399,8 @@ func (f *File) refresh() (err error) {
f.asn, f.country = asn, country
- if f.hostCacheSize == 0 {
- f.hostCache = agdcache.Empty[string, *Location]{}
- } else {
- f.hostCache = agdcache.NewLRU[string, *Location](&agdcache.LRUConfig{
- Size: f.hostCacheSize,
- })
- }
-
- f.ipCache = agdcache.NewLRU[any, *Location](&agdcache.LRUConfig{
- Size: f.ipCacheSize,
- })
+ f.hostCache.Clear()
+ f.ipCache.Clear()
return nil
}
diff --git a/internal/geoip/file_test.go b/internal/geoip/file_test.go
index 96c35a1..2e0c3b1 100644
--- a/internal/geoip/file_test.go
+++ b/internal/geoip/file_test.go
@@ -1,12 +1,16 @@
package geoip_test
import (
+ "context"
"net/netip"
"testing"
+ "time"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -14,8 +18,23 @@ import (
// type check
var _ agdservice.Refresher = (*geoip.File)(nil)
+// testTimeout is the common timeout for tests and contexts.
+const testTimeout = 1 * time.Second
+
+// newFile creates a new *geoip.File with the given configuration and refreshes
+// it initially.
+func newFile(tb testing.TB, conf *geoip.FileConfig) (g *geoip.File) {
+ g = geoip.NewFile(conf)
+
+ ctx := testutil.ContextWithTimeout(tb, testTimeout)
+ require.NoError(tb, g.Refresh(ctx))
+
+ return g
+}
+
func TestFile_Data_cityDB(t *testing.T) {
conf := &geoip.FileConfig{
+ CacheManager: agdcache.EmptyManager{},
ASNPath: asnPath,
CountryPath: cityPath,
HostCacheSize: 0,
@@ -24,8 +43,7 @@ func TestFile_Data_cityDB(t *testing.T) {
CountryTopASNs: countryTopASNs,
}
- g, err := geoip.NewFile(conf)
- require.NoError(t, err)
+ g := newFile(t, conf)
d, err := g.Data(testHost, testIPWithASN)
require.NoError(t, err)
@@ -42,6 +60,7 @@ func TestFile_Data_cityDB(t *testing.T) {
func TestFile_Data_countryDB(t *testing.T) {
conf := &geoip.FileConfig{
+ CacheManager: agdcache.EmptyManager{},
ASNPath: asnPath,
CountryPath: countryPath,
HostCacheSize: 0,
@@ -50,8 +69,7 @@ func TestFile_Data_countryDB(t *testing.T) {
CountryTopASNs: countryTopASNs,
}
- g, err := geoip.NewFile(conf)
- require.NoError(t, err)
+ g := newFile(t, conf)
d, err := g.Data(testHost, testIPWithASN)
require.NoError(t, err)
@@ -68,6 +86,7 @@ func TestFile_Data_countryDB(t *testing.T) {
func TestFile_Data_hostCache(t *testing.T) {
conf := &geoip.FileConfig{
+ CacheManager: agdcache.EmptyManager{},
ASNPath: asnPath,
CountryPath: cityPath,
HostCacheSize: 1,
@@ -76,8 +95,7 @@ func TestFile_Data_hostCache(t *testing.T) {
CountryTopASNs: countryTopASNs,
}
- g, err := geoip.NewFile(conf)
- require.NoError(t, err)
+ g := newFile(t, conf)
d, err := g.Data(testHost, testIPWithASN)
require.NoError(t, err)
@@ -97,6 +115,7 @@ func TestFile_Data_hostCache(t *testing.T) {
func TestFile_SubnetByLocation(t *testing.T) {
conf := &geoip.FileConfig{
+ CacheManager: agdcache.EmptyManager{},
ASNPath: asnPath,
CountryPath: cityPath,
HostCacheSize: 0,
@@ -105,8 +124,7 @@ func TestFile_SubnetByLocation(t *testing.T) {
CountryTopASNs: countryTopASNs,
}
- g, cErr := geoip.NewFile(conf)
- require.NoError(t, cErr)
+ g := newFile(t, conf)
testCases := []struct {
name string
@@ -169,13 +187,13 @@ func TestFile_SubnetByLocation(t *testing.T) {
// Sinks for benchmarks.
var (
- errSink error
- fileSink *geoip.File
- locSink *geoip.Location
+ errSink error
+ locSink *geoip.Location
)
func BenchmarkFile_Data(b *testing.B) {
conf := &geoip.FileConfig{
+ CacheManager: agdcache.EmptyManager{},
ASNPath: asnPath,
CountryPath: cityPath,
HostCacheSize: 0,
@@ -184,8 +202,7 @@ func BenchmarkFile_Data(b *testing.B) {
CountryTopASNs: geoip.DefaultCountryTopASNs,
}
- g, err := geoip.NewFile(conf)
- require.NoError(b, err)
+ g := newFile(b, conf)
ipCountry1 := testIPWithCountry
@@ -225,8 +242,9 @@ func BenchmarkFile_Data(b *testing.B) {
})
}
-func BenchmarkNewFile(b *testing.B) {
+func BenchmarkFile_Refresh(b *testing.B) {
conf := &geoip.FileConfig{
+ CacheManager: agdcache.EmptyManager{},
ASNPath: asnPath,
CountryPath: cityPath,
HostCacheSize: 0,
@@ -235,19 +253,23 @@ func BenchmarkNewFile(b *testing.B) {
CountryTopASNs: geoip.DefaultCountryTopASNs,
}
+ ctx := context.Background()
+ g := geoip.NewFile(conf)
+
b.ReportAllocs()
b.ResetTimer()
+
for range b.N {
- fileSink, errSink = geoip.NewFile(conf)
+ errSink = g.Refresh(ctx)
}
- assert.NotNil(b, fileSink)
assert.NoError(b, errSink)
// Recent result on MBP 15:
//
- // goos: darwin
- // goarch: amd64
- // cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
- // BenchmarkNewFile-12 2192 532262 ns/op 180929 B/op 5980 allocs/op
+ // goos: darwin
+ // goarch: amd64
+ // pkg: github.com/AdguardTeam/AdGuardDNS/internal/geoip
+ // cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
+ // BenchmarkFile_Refresh-12 807 1405013 ns/op 585430 B/op 18141 allocs/op
}
diff --git a/internal/metrics/backend.go b/internal/metrics/backend.go
index 10061f8..c40df3d 100644
--- a/internal/metrics/backend.go
+++ b/internal/metrics/backend.go
@@ -1,6 +1,8 @@
package metrics
import (
+ "fmt"
+
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
@@ -132,3 +134,55 @@ var (
"is_full_sync": "0",
})
)
+
+// gRPC error types for [IncGRPCErrorsCounter].
+const (
+ GRPCErrorTypeAuthentication = "auth"
+ GRPCErrorTypeBadRequest = "bad_req"
+ GRPCErrorTypeDeviceQuota = "dev_quota"
+ GRPCErrorTypeOther = "other"
+ GRPCErrorTypeRateLimit = "rate_limit"
+ GRPCErrorTypeTimeout = "timeout"
+)
+
+// IncGRPCErrorsCounter increments the gRPC errors counter based on the type.
+// typ must be a valid type.
+func IncGRPCErrorsCounter(typ string) {
+ var ctr prometheus.Counter
+ switch typ {
+ case GRPCErrorTypeAuthentication:
+ ctr = grpcErrorsTotalAuthentication
+ case GRPCErrorTypeBadRequest:
+ ctr = grpcErrorsTotalBadRequest
+ case GRPCErrorTypeDeviceQuota:
+ ctr = grpcErrorsTotalDeviceQuota
+ case GRPCErrorTypeOther:
+ ctr = grpcErrorsTotalOther
+ case GRPCErrorTypeRateLimit:
+ ctr = grpcErrorsTotalRateLimit
+ case GRPCErrorTypeTimeout:
+ ctr = grpcErrorsTotalTimeout
+ default:
+ panic(fmt.Errorf("metrics.IncGRPCErrorsCounter: bad type %q", typ))
+ }
+
+ ctr.Inc()
+}
+
+// grpcErrorsTotal is a vector of counters of gRPC errors by type. This block
+// contains it and the related counters by type.
+var (
+ grpcErrorsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
+ Name: "grpc_errors_total",
+ Subsystem: subsystemBackend,
+ Namespace: namespace,
+ Help: "The total number of errors by type.",
+ }, []string{"type"})
+
+ grpcErrorsTotalAuthentication = grpcErrorsTotal.WithLabelValues(GRPCErrorTypeAuthentication)
+ grpcErrorsTotalBadRequest = grpcErrorsTotal.WithLabelValues(GRPCErrorTypeBadRequest)
+ grpcErrorsTotalDeviceQuota = grpcErrorsTotal.WithLabelValues(GRPCErrorTypeDeviceQuota)
+ grpcErrorsTotalOther = grpcErrorsTotal.WithLabelValues(GRPCErrorTypeOther)
+ grpcErrorsTotalRateLimit = grpcErrorsTotal.WithLabelValues(GRPCErrorTypeRateLimit)
+ grpcErrorsTotalTimeout = grpcErrorsTotal.WithLabelValues(GRPCErrorTypeTimeout)
+)
diff --git a/internal/profiledb/error.go b/internal/profiledb/error.go
index 40814ec..9d82168 100644
--- a/internal/profiledb/error.go
+++ b/internal/profiledb/error.go
@@ -1,7 +1,78 @@
package profiledb
-import "github.com/AdguardTeam/golibs/errors"
+import (
+ "fmt"
+ "time"
+
+ "github.com/AdguardTeam/golibs/errors"
+)
// ErrDeviceNotFound is an error returned by lookup methods when a device
// couldn't be found.
const ErrDeviceNotFound errors.Error = "device not found"
+
+// ErrProfileNotFound is an error returned by lookup methods when a profile
+// couldn't be found.
+const ErrProfileNotFound errors.Error = "profile not found"
+
+// AuthenticationFailedError is returned by methods of [Storage] when the
+// authentication to the storage fails.
+type AuthenticationFailedError struct {
+ Message string
+}
+
+// type check
+var _ error = (*AuthenticationFailedError)(nil)
+
+// Error implements the [error] interface for *AuthenticationFailedError.
+func (err *AuthenticationFailedError) Error() (msg string) {
+ return err.Message
+}
+
+// BadRequestError is returned by methods of [Storage] when the request is
+// malformed.
+type BadRequestError struct {
+ Message string
+}
+
+// type check
+var _ error = (*BadRequestError)(nil)
+
+// Error implements the [error] interface for *BadRequestError.
+func (err *BadRequestError) Error() (msg string) {
+ return err.Message
+}
+
+// DeviceQuotaExceededError is returned by [Storage.CreateAutoDevice] when the
+// profile has exceeded the number of devices it can create.
+type DeviceQuotaExceededError struct {
+ Message string
+}
+
+// type check
+var _ error = (*DeviceQuotaExceededError)(nil)
+
+// Error implements the [error] interface for *DeviceQuotaExceededError.
+func (err *DeviceQuotaExceededError) Error() (msg string) {
+ return err.Message
+}
+
+// RateLimitedError is returned by methods of [Storage] when the requests are
+// made too often.
+type RateLimitedError struct {
+ // Message is the error message from the storage.
+ Message string
+
+ // RetryDelay is the hint to use for when to retry the request.
+ //
+ // TODO(a.garipov): Use in [Default.Refresh].
+ RetryDelay time.Duration
+}
+
+// type check
+var _ error = (*RateLimitedError)(nil)
+
+// Error implements the [error] interface for *RateLimitedError.
+func (err *RateLimitedError) Error() (msg string) {
+ return fmt.Sprintf("rate limited: %s; retry in %s", err.Message, err.RetryDelay)
+}
diff --git a/internal/profiledb/internal/filecachepb/filecache.pb.go b/internal/profiledb/internal/filecachepb/filecache.pb.go
index a793cc2..148fb36 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.33.0
-// protoc v4.25.3
+// protoc-gen-go v1.34.2
+// protoc v5.27.1
// source: filecache.proto
package filecachepb
@@ -98,7 +98,9 @@ type Profile struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Parental *ParentalProtectionSettings `protobuf:"bytes,1,opt,name=parental,proto3" json:"parental,omitempty"`
+ Access *AccessSettings `protobuf:"bytes,21,opt,name=access,proto3" json:"access,omitempty"`
+ Parental *ParentalProtectionSettings `protobuf:"bytes,1,opt,name=parental,proto3" json:"parental,omitempty"`
+ SafeBrowsing *SafeBrowsingSettings `protobuf:"bytes,19,opt,name=safe_browsing,json=safeBrowsing,proto3" json:"safe_browsing,omitempty"`
// Types that are assignable to BlockingMode:
//
// *Profile_BlockingModeCustomIp
@@ -114,15 +116,14 @@ type Profile struct {
FilteredResponseTtl *durationpb.Duration `protobuf:"bytes,11,opt,name=filtered_response_ttl,json=filteredResponseTtl,proto3" json:"filtered_response_ttl,omitempty"`
FilteringEnabled bool `protobuf:"varint,12,opt,name=filtering_enabled,json=filteringEnabled,proto3" json:"filtering_enabled,omitempty"`
// Deprecated: Marked as deprecated in filecache.proto.
- SafeBrowsingEnabled bool `protobuf:"varint,13,opt,name=safe_browsing_enabled,json=safeBrowsingEnabled,proto3" json:"safe_browsing_enabled,omitempty"`
- RuleListsEnabled bool `protobuf:"varint,14,opt,name=rule_lists_enabled,json=ruleListsEnabled,proto3" json:"rule_lists_enabled,omitempty"`
- QueryLogEnabled bool `protobuf:"varint,15,opt,name=query_log_enabled,json=queryLogEnabled,proto3" json:"query_log_enabled,omitempty"`
- Deleted bool `protobuf:"varint,16,opt,name=deleted,proto3" json:"deleted,omitempty"`
- BlockPrivateRelay bool `protobuf:"varint,17,opt,name=block_private_relay,json=blockPrivateRelay,proto3" json:"block_private_relay,omitempty"`
- BlockFirefoxCanary bool `protobuf:"varint,18,opt,name=block_firefox_canary,json=blockFirefoxCanary,proto3" json:"block_firefox_canary,omitempty"`
- SafeBrowsing *SafeBrowsingSettings `protobuf:"bytes,19,opt,name=safe_browsing,json=safeBrowsing,proto3" json:"safe_browsing,omitempty"`
- IpLogEnabled bool `protobuf:"varint,20,opt,name=ip_log_enabled,json=ipLogEnabled,proto3" json:"ip_log_enabled,omitempty"`
- Access *AccessSettings `protobuf:"bytes,21,opt,name=access,proto3" json:"access,omitempty"`
+ SafeBrowsingEnabled bool `protobuf:"varint,13,opt,name=safe_browsing_enabled,json=safeBrowsingEnabled,proto3" json:"safe_browsing_enabled,omitempty"`
+ RuleListsEnabled bool `protobuf:"varint,14,opt,name=rule_lists_enabled,json=ruleListsEnabled,proto3" json:"rule_lists_enabled,omitempty"`
+ QueryLogEnabled bool `protobuf:"varint,15,opt,name=query_log_enabled,json=queryLogEnabled,proto3" json:"query_log_enabled,omitempty"`
+ Deleted bool `protobuf:"varint,16,opt,name=deleted,proto3" json:"deleted,omitempty"`
+ BlockPrivateRelay bool `protobuf:"varint,17,opt,name=block_private_relay,json=blockPrivateRelay,proto3" json:"block_private_relay,omitempty"`
+ BlockFirefoxCanary bool `protobuf:"varint,18,opt,name=block_firefox_canary,json=blockFirefoxCanary,proto3" json:"block_firefox_canary,omitempty"`
+ IpLogEnabled bool `protobuf:"varint,20,opt,name=ip_log_enabled,json=ipLogEnabled,proto3" json:"ip_log_enabled,omitempty"`
+ AutoDevicesEnabled bool `protobuf:"varint,22,opt,name=auto_devices_enabled,json=autoDevicesEnabled,proto3" json:"auto_devices_enabled,omitempty"`
}
func (x *Profile) Reset() {
@@ -157,6 +158,13 @@ func (*Profile) Descriptor() ([]byte, []int) {
return file_filecache_proto_rawDescGZIP(), []int{1}
}
+func (x *Profile) GetAccess() *AccessSettings {
+ if x != nil {
+ return x.Access
+ }
+ return nil
+}
+
func (x *Profile) GetParental() *ParentalProtectionSettings {
if x != nil {
return x.Parental
@@ -164,6 +172,13 @@ func (x *Profile) GetParental() *ParentalProtectionSettings {
return nil
}
+func (x *Profile) GetSafeBrowsing() *SafeBrowsingSettings {
+ if x != nil {
+ return x.SafeBrowsing
+ }
+ return nil
+}
+
func (m *Profile) GetBlockingMode() isProfile_BlockingMode {
if m != nil {
return m.BlockingMode
@@ -291,13 +306,6 @@ func (x *Profile) GetBlockFirefoxCanary() bool {
return false
}
-func (x *Profile) GetSafeBrowsing() *SafeBrowsingSettings {
- if x != nil {
- return x.SafeBrowsing
- }
- return nil
-}
-
func (x *Profile) GetIpLogEnabled() bool {
if x != nil {
return x.IpLogEnabled
@@ -305,11 +313,11 @@ func (x *Profile) GetIpLogEnabled() bool {
return false
}
-func (x *Profile) GetAccess() *AccessSettings {
+func (x *Profile) GetAutoDevicesEnabled() bool {
if x != nil {
- return x.Access
+ return x.AutoDevicesEnabled
}
- return nil
+ return false
}
type isProfile_BlockingMode interface {
@@ -822,12 +830,13 @@ type Device struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
+ Authentication *AuthenticationSettings `protobuf:"bytes,6,opt,name=authentication,proto3" json:"authentication,omitempty"`
DeviceId string `protobuf:"bytes,1,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
- LinkedIp []byte `protobuf:"bytes,2,opt,name=linked_ip,json=linkedIp,proto3" json:"linked_ip,omitempty"`
DeviceName string `protobuf:"bytes,3,opt,name=device_name,json=deviceName,proto3" json:"device_name,omitempty"`
+ HumanIdLower string `protobuf:"bytes,7,opt,name=human_id_lower,json=humanIdLower,proto3" json:"human_id_lower,omitempty"`
+ LinkedIp []byte `protobuf:"bytes,2,opt,name=linked_ip,json=linkedIp,proto3" json:"linked_ip,omitempty"`
DedicatedIps [][]byte `protobuf:"bytes,4,rep,name=dedicated_ips,json=dedicatedIps,proto3" json:"dedicated_ips,omitempty"`
FilteringEnabled bool `protobuf:"varint,5,opt,name=filtering_enabled,json=filteringEnabled,proto3" json:"filtering_enabled,omitempty"`
- Authentication *AuthenticationSettings `protobuf:"bytes,6,opt,name=authentication,proto3" json:"authentication,omitempty"`
}
func (x *Device) Reset() {
@@ -862,6 +871,13 @@ func (*Device) Descriptor() ([]byte, []int) {
return file_filecache_proto_rawDescGZIP(), []int{10}
}
+func (x *Device) GetAuthentication() *AuthenticationSettings {
+ if x != nil {
+ return x.Authentication
+ }
+ return nil
+}
+
func (x *Device) GetDeviceId() string {
if x != nil {
return x.DeviceId
@@ -869,6 +885,20 @@ func (x *Device) GetDeviceId() string {
return ""
}
+func (x *Device) GetDeviceName() string {
+ if x != nil {
+ return x.DeviceName
+ }
+ return ""
+}
+
+func (x *Device) GetHumanIdLower() string {
+ if x != nil {
+ return x.HumanIdLower
+ }
+ return ""
+}
+
func (x *Device) GetLinkedIp() []byte {
if x != nil {
return x.LinkedIp
@@ -876,13 +906,6 @@ func (x *Device) GetLinkedIp() []byte {
return nil
}
-func (x *Device) GetDeviceName() string {
- if x != nil {
- return x.DeviceName
- }
- return ""
-}
-
func (x *Device) GetDedicatedIps() [][]byte {
if x != nil {
return x.DedicatedIps
@@ -897,13 +920,6 @@ func (x *Device) GetFilteringEnabled() bool {
return false
}
-func (x *Device) GetAuthentication() *AuthenticationSettings {
- if x != nil {
- return x.Authentication
- }
- return nil
-}
-
type AccessSettings struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1133,191 +1149,196 @@ var file_filecache_proto_rawDesc = []byte{
0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64,
0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01,
- 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xa5, 0x09, 0x0a, 0x07,
- 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e,
- 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x66,
- 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x50, 0x72,
- 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
- 0x52, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x12, 0x58, 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, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72,
- 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 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, 0x57, 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, 0x03,
+ 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xd7, 0x09, 0x0a, 0x07,
+ 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73,
+ 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
+ 0x65, 0x64, 0x62, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
+ 0x67, 0x73, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x41, 0x0a, 0x08, 0x70, 0x61,
+ 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70,
+ 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61,
+ 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69,
+ 0x6e, 0x67, 0x73, 0x52, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x12, 0x44, 0x0a,
+ 0x0d, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x13,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62,
- 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, 0x52, 0x0a,
- 0x15, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x6e,
- 0x75, 0x6c, 0x6c, 0x5f, 0x69, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70,
- 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 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, 0x54, 0x0a, 0x15, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f,
- 0x64, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 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, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69,
- 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f,
- 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
- 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 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, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54,
- 0x69, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64,
- 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49,
- 0x64, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f,
- 0x69, 0x64, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x75, 0x6c, 0x65, 0x4c,
- 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d,
- 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x0a, 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, 0x0b, 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, 0x2b, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x74,
- 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0c, 0x20,
- 0x01, 0x28, 0x08, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x45, 0x6e,
- 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x15, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x62, 0x72,
- 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0d,
- 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x13, 0x73, 0x61, 0x66, 0x65, 0x42, 0x72,
- 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2c, 0x0a,
- 0x12, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62,
- 0x6c, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x75, 0x6c, 0x65, 0x4c,
- 0x69, 0x73, 0x74, 0x73, 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, 0x0f, 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, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65,
- 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61,
- 0x74, 0x65, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x11, 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, 0x12, 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, 0x44, 0x0a, 0x0d, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x62, 0x72, 0x6f, 0x77,
- 0x73, 0x69, 0x6e, 0x67, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f,
- 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 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, 0x24, 0x0a, 0x0e, 0x69, 0x70, 0x5f,
- 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28,
- 0x08, 0x52, 0x0c, 0x69, 0x70, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,
- 0x31, 0x0a, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x41, 0x63, 0x63, 0x65,
- 0x73, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65,
- 0x73, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d,
- 0x6f, 0x64, 0x65, 0x22, 0xa5, 0x02, 0x0a, 0x1a, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c,
- 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
- 0x67, 0x73, 0x12, 0x41, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62,
- 0x2e, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x08, 0x73, 0x63, 0x68,
- 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64,
- 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
- 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
- 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x79, 0x6f, 0x75, 0x74, 0x75, 0x62,
- 0x65, 0x53, 0x61, 0x66, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x22, 0xad, 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, 0x43, 0x0a, 0x1e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f,
- 0x6e, 0x65, 0x77, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64,
- 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b,
- 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x65, 0x77, 0x6c, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
- 0x65, 0x72, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x22, 0xca, 0x02, 0x0a, 0x1a,
- 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69,
- 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74,
- 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x12, 0x25, 0x0a, 0x03, 0x6d, 0x6f, 0x6e, 0x18, 0x02,
+ 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, 0x58, 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, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62,
+ 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, 0x57, 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, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
+ 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 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, 0x52, 0x0a, 0x15, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69,
+ 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x5f, 0x69, 0x70, 0x18,
+ 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64,
+ 0x62, 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, 0x54, 0x0a, 0x15, 0x62, 0x6c,
+ 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x75,
+ 0x73, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x66,
+ 0x69, 0x6c, 0x65, 0x64, 0x62, 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, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12,
+ 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07,
+ 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, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a,
+ 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09,
+ 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x72,
+ 0x75, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x09, 0x20, 0x03,
+ 0x28, 0x09, 0x52, 0x0b, 0x72, 0x75, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, 0x12,
+ 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18,
+ 0x0a, 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, 0x0b, 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, 0x2b, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x65,
+ 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x66, 0x69,
+ 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x36,
+ 0x0a, 0x15, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 0x5f,
+ 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18,
+ 0x01, 0x52, 0x13, 0x73, 0x61, 0x66, 0x65, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 0x45,
+ 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x6c,
+ 0x69, 0x73, 0x74, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x10, 0x72, 0x75, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x73, 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, 0x0f, 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, 0x10, 0x20, 0x01, 0x28,
+ 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x6c,
+ 0x6f, 0x63, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x65, 0x6c, 0x61,
+ 0x79, 0x18, 0x11, 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, 0x12, 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, 0x24, 0x0a, 0x0e,
+ 0x69, 0x70, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x14,
+ 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x70, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c,
+ 0x65, 0x64, 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, 0x16, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x12, 0x61, 0x75, 0x74, 0x6f, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x61,
+ 0x62, 0x6c, 0x65, 0x64, 0x42, 0x0f, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67,
+ 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0xa5, 0x02, 0x0a, 0x1a, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74,
+ 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74,
+ 0x69, 0x6e, 0x67, 0x73, 0x12, 0x41, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
+ 0x64, 0x62, 0x2e, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x65,
+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x08, 0x73,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
+ 0x09, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x79, 0x6f, 0x75, 0x74,
+ 0x75, 0x62, 0x65, 0x53, 0x61, 0x66, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x22, 0xad, 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, 0x43, 0x0a, 0x1e, 0x62, 0x6c, 0x6f, 0x63,
+ 0x6b, 0x5f, 0x6e, 0x65, 0x77, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
+ 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x1b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x65, 0x77, 0x6c, 0x79, 0x52, 0x65, 0x67, 0x69,
+ 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x22, 0xca, 0x02,
+ 0x0a, 0x1a, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63,
+ 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09,
+ 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x12, 0x25, 0x0a, 0x03, 0x6d, 0x6f, 0x6e,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
+ 0x64, 0x62, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x6d, 0x6f, 0x6e,
+ 0x12, 0x25, 0x0a, 0x03, 0x74, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e,
+ 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e,
+ 0x67, 0x65, 0x52, 0x03, 0x74, 0x75, 0x65, 0x12, 0x25, 0x0a, 0x03, 0x77, 0x65, 0x64, 0x18, 0x04,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62,
- 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x6d, 0x6f, 0x6e, 0x12, 0x25,
- 0x0a, 0x03, 0x74, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72,
+ 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x77, 0x65, 0x64, 0x12, 0x25,
+ 0x0a, 0x03, 0x74, 0x68, 0x75, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72,
0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65,
- 0x52, 0x03, 0x74, 0x75, 0x65, 0x12, 0x25, 0x0a, 0x03, 0x77, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01,
+ 0x52, 0x03, 0x74, 0x68, 0x75, 0x12, 0x25, 0x0a, 0x03, 0x66, 0x72, 0x69, 0x18, 0x06, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x44,
- 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x77, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x03,
- 0x74, 0x68, 0x75, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x66,
+ 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x66, 0x72, 0x69, 0x12, 0x25, 0x0a, 0x03,
+ 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03,
- 0x74, 0x68, 0x75, 0x12, 0x25, 0x0a, 0x03, 0x66, 0x72, 0x69, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
+ 0x73, 0x61, 0x74, 0x12, 0x25, 0x0a, 0x03, 0x73, 0x75, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x44, 0x61, 0x79,
- 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x66, 0x72, 0x69, 0x12, 0x25, 0x0a, 0x03, 0x73, 0x61,
- 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
- 0x65, 0x64, 0x62, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x73, 0x61,
- 0x74, 0x12, 0x25, 0x0a, 0x03, 0x73, 0x75, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
- 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61,
- 0x6e, 0x67, 0x65, 0x52, 0x03, 0x73, 0x75, 0x6e, 0x22, 0x32, 0x0a, 0x08, 0x44, 0x61, 0x79, 0x52,
- 0x61, 0x6e, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x0d, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e,
- 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x3e, 0x0a, 0x14,
- 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x75, 0x73, 0x74,
- 0x6f, 0x6d, 0x49, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01, 0x20, 0x03,
- 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x36,
- 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x36, 0x22, 0x16, 0x0a, 0x14,
- 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x58, 0x44, 0x4f,
- 0x4d, 0x41, 0x49, 0x4e, 0x22, 0x14, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67,
- 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x75, 0x6c, 0x6c, 0x49, 0x50, 0x22, 0x15, 0x0a, 0x13, 0x42, 0x6c,
- 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x45, 0x46, 0x55, 0x53, 0x45,
- 0x44, 0x22, 0x80, 0x02, 0x0a, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09,
- 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x69, 0x6e,
- 0x6b, 0x65, 0x64, 0x5f, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6c, 0x69,
- 0x6e, 0x6b, 0x65, 0x64, 0x49, 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
+ 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x73, 0x75, 0x6e, 0x22, 0x32, 0x0a, 0x08, 0x44, 0x61,
+ 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03,
+ 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x3e,
+ 0x0a, 0x14, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x75,
+ 0x73, 0x74, 0x6f, 0x6d, 0x49, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01,
+ 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70,
+ 0x76, 0x36, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x36, 0x22, 0x16,
+ 0x0a, 0x14, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x58,
+ 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x22, 0x14, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69,
+ 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x75, 0x6c, 0x6c, 0x49, 0x50, 0x22, 0x15, 0x0a, 0x13,
+ 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x45, 0x46, 0x55,
+ 0x53, 0x45, 0x44, 0x22, 0xa6, 0x02, 0x0a, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x49,
+ 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
+ 0x64, 0x62, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65,
+ 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76,
+ 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65,
+ 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76,
- 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x64, 0x69, 0x63,
- 0x61, 0x74, 0x65, 0x64, 0x5f, 0x69, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c,
- 0x64, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x49, 0x70, 0x73, 0x12, 0x2b, 0x0a, 0x11,
- 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
- 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69,
- 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x49, 0x0a, 0x0e, 0x61, 0x75, 0x74,
- 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x41, 0x75,
- 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74,
- 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x8a, 0x02, 0x0a, 0x0e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53,
- 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3b, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
- 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
- 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x43, 0x69, 0x64, 0x72,
- 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74,
- 0x43, 0x69, 0x64, 0x72, 0x12, 0x3b, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73,
- 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70,
- 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e,
- 0x67, 0x65, 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x69, 0x64,
- 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61,
- 0x73, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c,
- 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c,
- 0x69, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x62,
- 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x62,
- 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f,
- 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x62, 0x6c, 0x6f,
- 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x75, 0x6c, 0x65,
- 0x73, 0x22, 0x3d, 0x0a, 0x09, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x18,
- 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
- 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66,
- 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
- 0x22, 0x85, 0x01, 0x0a, 0x16, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x64,
- 0x6f, 0x68, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x08, 0x52, 0x0b, 0x64, 0x6f, 0x68, 0x41, 0x75, 0x74, 0x68, 0x4f, 0x6e, 0x6c, 0x79, 0x12,
- 0x32, 0x0a, 0x14, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68,
- 0x5f, 0x62, 0x63, 0x72, 0x79, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52,
- 0x12, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x48, 0x61, 0x73, 0x68, 0x42, 0x63, 0x72,
- 0x79, 0x70, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x64, 0x6f, 0x68, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77,
- 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x66, 0x69,
- 0x6c, 0x65, 0x63, 0x61, 0x63, 0x68, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x33,
+ 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 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, 0x12, 0x1b, 0x0a,
+ 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x5f, 0x69, 0x70, 0x18, 0x02, 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, 0x04, 0x20, 0x03, 0x28,
+ 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x49, 0x70, 0x73, 0x12,
+ 0x2b, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61,
+ 0x62, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x74,
+ 0x65, 0x72, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x8a, 0x02, 0x0a,
+ 0x0e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
+ 0x3b, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64,
+ 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
+ 0x65, 0x64, 0x62, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x61,
+ 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x69, 0x64, 0x72, 0x12, 0x3b, 0x0a, 0x0e,
+ 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x64, 0x62,
+ 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63,
+ 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x69, 0x64, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6c, 0x6c,
+ 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d,
+ 0x52, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12, 0x23,
+ 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18,
+ 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74,
+ 0x41, 0x73, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74,
+ 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20,
+ 0x03, 0x28, 0x09, 0x52, 0x14, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x44, 0x6f,
+ 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x3d, 0x0a, 0x09, 0x43, 0x69, 0x64,
+ 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
+ 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
+ 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
+ 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x85, 0x01, 0x0a, 0x16, 0x41, 0x75, 0x74,
+ 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69,
+ 0x6e, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x64, 0x6f, 0x68, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f,
+ 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x64, 0x6f, 0x68, 0x41,
+ 0x75, 0x74, 0x68, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x61, 0x73, 0x73, 0x77,
+ 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x62, 0x63, 0x72, 0x79, 0x70, 0x74, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x12, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
+ 0x64, 0x48, 0x61, 0x73, 0x68, 0x42, 0x63, 0x72, 0x79, 0x70, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x64,
+ 0x6f, 0x68, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68,
+ 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x63, 0x61, 0x63, 0x68, 0x65, 0x70,
+ 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1333,7 +1354,7 @@ func file_filecache_proto_rawDescGZIP() []byte {
}
var file_filecache_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
-var file_filecache_proto_goTypes = []interface{}{
+var file_filecache_proto_goTypes = []any{
(*FileCache)(nil), // 0: profiledb.FileCache
(*Profile)(nil), // 1: profiledb.Profile
(*ParentalProtectionSettings)(nil), // 2: profiledb.ParentalProtectionSettings
@@ -1355,15 +1376,15 @@ var file_filecache_proto_depIdxs = []int32{
14, // 0: profiledb.FileCache.sync_time:type_name -> google.protobuf.Timestamp
1, // 1: profiledb.FileCache.profiles:type_name -> profiledb.Profile
10, // 2: profiledb.FileCache.devices:type_name -> profiledb.Device
- 2, // 3: profiledb.Profile.parental:type_name -> profiledb.ParentalProtectionSettings
- 6, // 4: profiledb.Profile.blocking_mode_custom_ip:type_name -> profiledb.BlockingModeCustomIP
- 7, // 5: profiledb.Profile.blocking_mode_nxdomain:type_name -> profiledb.BlockingModeNXDOMAIN
- 8, // 6: profiledb.Profile.blocking_mode_null_ip:type_name -> profiledb.BlockingModeNullIP
- 9, // 7: profiledb.Profile.blocking_mode_refused:type_name -> profiledb.BlockingModeREFUSED
- 14, // 8: profiledb.Profile.update_time:type_name -> google.protobuf.Timestamp
- 15, // 9: profiledb.Profile.filtered_response_ttl:type_name -> google.protobuf.Duration
- 3, // 10: profiledb.Profile.safe_browsing:type_name -> profiledb.SafeBrowsingSettings
- 11, // 11: profiledb.Profile.access:type_name -> profiledb.AccessSettings
+ 11, // 3: profiledb.Profile.access:type_name -> profiledb.AccessSettings
+ 2, // 4: profiledb.Profile.parental:type_name -> profiledb.ParentalProtectionSettings
+ 3, // 5: profiledb.Profile.safe_browsing:type_name -> profiledb.SafeBrowsingSettings
+ 6, // 6: profiledb.Profile.blocking_mode_custom_ip:type_name -> profiledb.BlockingModeCustomIP
+ 7, // 7: profiledb.Profile.blocking_mode_nxdomain:type_name -> profiledb.BlockingModeNXDOMAIN
+ 8, // 8: profiledb.Profile.blocking_mode_null_ip:type_name -> profiledb.BlockingModeNullIP
+ 9, // 9: profiledb.Profile.blocking_mode_refused:type_name -> profiledb.BlockingModeREFUSED
+ 14, // 10: profiledb.Profile.update_time:type_name -> google.protobuf.Timestamp
+ 15, // 11: profiledb.Profile.filtered_response_ttl:type_name -> google.protobuf.Duration
4, // 12: profiledb.ParentalProtectionSettings.schedule:type_name -> profiledb.ParentalProtectionSchedule
5, // 13: profiledb.ParentalProtectionSchedule.mon:type_name -> profiledb.DayRange
5, // 14: profiledb.ParentalProtectionSchedule.tue:type_name -> profiledb.DayRange
@@ -1388,7 +1409,7 @@ func file_filecache_proto_init() {
return
}
if !protoimpl.UnsafeEnabled {
- file_filecache_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*FileCache); i {
case 0:
return &v.state
@@ -1400,7 +1421,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*Profile); i {
case 0:
return &v.state
@@ -1412,7 +1433,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*ParentalProtectionSettings); i {
case 0:
return &v.state
@@ -1424,7 +1445,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[3].Exporter = func(v any, i int) any {
switch v := v.(*SafeBrowsingSettings); i {
case 0:
return &v.state
@@ -1436,7 +1457,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[4].Exporter = func(v any, i int) any {
switch v := v.(*ParentalProtectionSchedule); i {
case 0:
return &v.state
@@ -1448,7 +1469,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[5].Exporter = func(v any, i int) any {
switch v := v.(*DayRange); i {
case 0:
return &v.state
@@ -1460,7 +1481,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[6].Exporter = func(v any, i int) any {
switch v := v.(*BlockingModeCustomIP); i {
case 0:
return &v.state
@@ -1472,7 +1493,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[7].Exporter = func(v any, i int) any {
switch v := v.(*BlockingModeNXDOMAIN); i {
case 0:
return &v.state
@@ -1484,7 +1505,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[8].Exporter = func(v any, i int) any {
switch v := v.(*BlockingModeNullIP); i {
case 0:
return &v.state
@@ -1496,7 +1517,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[9].Exporter = func(v any, i int) any {
switch v := v.(*BlockingModeREFUSED); i {
case 0:
return &v.state
@@ -1508,7 +1529,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[10].Exporter = func(v any, i int) any {
switch v := v.(*Device); i {
case 0:
return &v.state
@@ -1520,7 +1541,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[11].Exporter = func(v any, i int) any {
switch v := v.(*AccessSettings); i {
case 0:
return &v.state
@@ -1532,7 +1553,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[12].Exporter = func(v any, i int) any {
switch v := v.(*CidrRange); i {
case 0:
return &v.state
@@ -1544,7 +1565,7 @@ func file_filecache_proto_init() {
return nil
}
}
- file_filecache_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+ file_filecache_proto_msgTypes[13].Exporter = func(v any, i int) any {
switch v := v.(*AuthenticationSettings); i {
case 0:
return &v.state
@@ -1557,13 +1578,13 @@ func file_filecache_proto_init() {
}
}
}
- file_filecache_proto_msgTypes[1].OneofWrappers = []interface{}{
+ file_filecache_proto_msgTypes[1].OneofWrappers = []any{
(*Profile_BlockingModeCustomIp)(nil),
(*Profile_BlockingModeNxdomain)(nil),
(*Profile_BlockingModeNullIp)(nil),
(*Profile_BlockingModeRefused)(nil),
}
- file_filecache_proto_msgTypes[13].OneofWrappers = []interface{}{
+ file_filecache_proto_msgTypes[13].OneofWrappers = []any{
(*AuthenticationSettings_PasswordHashBcrypt)(nil),
}
type x struct{}
diff --git a/internal/profiledb/internal/filecachepb/filecache.proto b/internal/profiledb/internal/filecachepb/filecache.proto
index 081f850..23213e2 100644
--- a/internal/profiledb/internal/filecachepb/filecache.proto
+++ b/internal/profiledb/internal/filecachepb/filecache.proto
@@ -15,7 +15,9 @@ message FileCache {
}
message Profile {
+ AccessSettings access = 21;
ParentalProtectionSettings parental = 1;
+ SafeBrowsingSettings safe_browsing = 19;
oneof blocking_mode {
BlockingModeCustomIP blocking_mode_custom_ip = 2;
BlockingModeNXDOMAIN blocking_mode_nxdomain = 3;
@@ -35,9 +37,8 @@ message Profile {
bool deleted = 16;
bool block_private_relay = 17;
bool block_firefox_canary = 18;
- SafeBrowsingSettings safe_browsing = 19;
bool ip_log_enabled = 20;
- AccessSettings access = 21;
+ bool auto_devices_enabled = 22;
}
message ParentalProtectionSettings {
@@ -83,12 +84,13 @@ message BlockingModeNullIP {}
message BlockingModeREFUSED {}
message Device {
+ AuthenticationSettings authentication = 6;
string device_id = 1;
- bytes linked_ip = 2;
string device_name = 3;
+ string human_id_lower = 7;
+ bytes linked_ip = 2;
repeated bytes dedicated_ips = 4;
bool filtering_enabled = 5;
- AuthenticationSettings authentication = 6;
}
message AccessSettings {
diff --git a/internal/profiledb/internal/filecachepb/filecachepb.go b/internal/profiledb/internal/filecachepb/filecachepb.go
index 4d74394..8b691d3 100644
--- a/internal/profiledb/internal/filecachepb/filecachepb.go
+++ b/internal/profiledb/internal/filecachepb/filecachepb.go
@@ -99,6 +99,7 @@ func (x *Profile) toInternal() (prof *agd.Profile, err error) {
BlockPrivateRelay: x.BlockPrivateRelay,
BlockFirefoxCanary: x.BlockFirefoxCanary,
IPLogEnabled: x.IpLogEnabled,
+ AutoDevicesEnabled: x.AutoDevicesEnabled,
}, nil
}
@@ -228,7 +229,9 @@ func (x *Device) toInternal() (d *agd.Device, err error) {
ID: agd.DeviceID(x.DeviceId),
LinkedIP: linkedIP,
// Consider device names to have been prevalidated.
- Name: agd.DeviceName(x.DeviceName),
+ Name: agd.DeviceName(x.DeviceName),
+ // Consider lowercase HumanIDs to have been prevalidated.
+ HumanIDLower: agd.HumanIDLower(x.HumanIdLower),
DedicatedIPs: dedicatedIPs,
FilteringEnabled: x.FilteringEnabled,
}, nil
@@ -354,6 +357,7 @@ func profilesToProtobuf(profiles []*agd.Profile) (pbProfiles []*Profile) {
BlockPrivateRelay: p.BlockPrivateRelay,
BlockFirefoxCanary: p.BlockFirefoxCanary,
IpLogEnabled: p.IPLogEnabled,
+ AutoDevicesEnabled: p.AutoDevicesEnabled,
})
}
@@ -497,6 +501,7 @@ func devicesToProtobuf(devices []*agd.Device) (pbDevices []*Device) {
Authentication: authToProtobuf(d.Auth),
DeviceId: string(d.ID),
LinkedIp: ipToBytes(d.LinkedIP),
+ HumanIdLower: string(d.HumanIDLower),
DeviceName: string(d.Name),
DedicatedIps: ipsToByteSlices(d.DedicatedIPs),
FilteringEnabled: d.FilteringEnabled,
@@ -521,7 +526,9 @@ func authToProtobuf(s *agd.AuthSettings) (a *AuthenticationSettings) {
// dohPasswordToProtobuf converts an auth password hash sum-type to a protobuf
// one.
-func dohPasswordToProtobuf(p agdpasswd.Authenticator) (pbp isAuthenticationSettings_DohPasswordHash) {
+func dohPasswordToProtobuf(
+ p agdpasswd.Authenticator,
+) (pbp isAuthenticationSettings_DohPasswordHash) {
switch p := p.(type) {
case agdpasswd.AllowAuthenticator:
return nil
diff --git a/internal/profiledb/internal/internal.go b/internal/profiledb/internal/internal.go
index d2a5163..5510b7c 100644
--- a/internal/profiledb/internal/internal.go
+++ b/internal/profiledb/internal/internal.go
@@ -12,7 +12,7 @@ import (
// FileCacheVersion is the version of cached data structure. It must be
// manually incremented on every change in [agd.Device], [agd.Profile], and any
// file-cache structures.
-const FileCacheVersion = 11
+const FileCacheVersion = 12
// CacheVersionError is returned from [FileCacheStorage.Load] method if the
// stored cache version doesn't match current [FileCacheVersion].
diff --git a/internal/profiledb/internal/profiledbtest/profiledbtest.go b/internal/profiledb/internal/profiledbtest/profiledbtest.go
index 28d608d..1d65e30 100644
--- a/internal/profiledb/internal/profiledbtest/profiledbtest.go
+++ b/internal/profiledb/internal/profiledbtest/profiledbtest.go
@@ -18,8 +18,17 @@ import (
// ProfileID is the profile ID for tests.
const ProfileID agd.ProfileID = "prof1234"
-// DeviceID is the profile ID for tests.
-const DeviceID agd.DeviceID = "dev1234"
+// Device IDs for tests.
+const (
+ DeviceID agd.DeviceID = "dev1234"
+ DeviceIDAuto agd.DeviceID = "auto1234"
+)
+
+// HumanID values for tests.
+const (
+ HumanID agd.HumanID = "My-Device-X--10"
+ HumanIDLower agd.HumanIDLower = "my-device-x--10"
+)
// NewProfile returns the common profile and device for tests.
func NewProfile(tb testing.TB) (p *agd.Profile, d *agd.Device) {
@@ -87,5 +96,6 @@ func NewProfile(tb testing.TB) (p *agd.Profile, d *agd.Device) {
BlockPrivateRelay: true,
BlockFirefoxCanary: true,
IPLogEnabled: true,
+ AutoDevicesEnabled: true,
}, dev
}
diff --git a/internal/profiledb/profiledb.go b/internal/profiledb/profiledb.go
index cdaf90d..ca0a28e 100644
--- a/internal/profiledb/profiledb.go
+++ b/internal/profiledb/profiledb.go
@@ -21,22 +21,44 @@ import (
)
// Interface is the local database of user profiles and devices.
+//
+// NOTE: All returned values must not be modified.
type Interface interface {
- // ProfileByDeviceID returns the profile and the device identified by id.
- ProfileByDeviceID(
+ // CreateAutoDevice creates a new automatic device for the given profile
+ // with the given human-readable device ID and device type. All arguments
+ // must be valid.
+ CreateAutoDevice(
ctx context.Context,
- id agd.DeviceID,
+ id agd.ProfileID,
+ humanID agd.HumanID,
+ devType agd.DeviceType,
) (p *agd.Profile, d *agd.Device, err error)
// ProfileByDedicatedIP returns the profile and the device identified by its
- // dedicated DNS server IP address.
+ // dedicated DNS server IP address. ip must be valid.
ProfileByDedicatedIP(
ctx context.Context,
ip netip.Addr,
) (p *agd.Profile, d *agd.Device, err error)
+ // ProfileByDeviceID returns the profile and the device identified by id.
+ // id must be valid.
+ ProfileByDeviceID(
+ ctx context.Context,
+ id agd.DeviceID,
+ ) (p *agd.Profile, d *agd.Device, err error)
+
+ // ProfileByHumanID returns the profile and the device identified by the
+ // profile ID and the lowercase version of the human-readable device ID.
+ // id and humanIDLower must be valid.
+ ProfileByHumanID(
+ ctx context.Context,
+ id agd.ProfileID,
+ humanIDLower agd.HumanIDLower,
+ ) (p *agd.Profile, d *agd.Device, err error)
+
// ProfileByLinkedIP returns the profile and the device identified by its
- // linked IP address.
+ // linked IP address. ip must be valid.
ProfileByLinkedIP(ctx context.Context, ip netip.Addr) (p *agd.Profile, d *agd.Device, err error)
}
@@ -50,6 +72,24 @@ type Disabled struct{}
// profiles database is disabled.
const profilesDBUnexpectedCall string = "profiles db: unexpected call to %s"
+// CreateAutoDevice implements the [Interface] interface for *Disabled.
+func (d *Disabled) CreateAutoDevice(
+ _ context.Context,
+ _ agd.ProfileID,
+ _ agd.HumanID,
+ _ agd.DeviceType,
+) (_ *agd.Profile, _ *agd.Device, _ error) {
+ panic(fmt.Errorf(profilesDBUnexpectedCall, "CreateAutoDevice"))
+}
+
+// ProfileByDedicatedIP implements the [Interface] interface for *Disabled.
+func (d *Disabled) ProfileByDedicatedIP(
+ _ context.Context,
+ _ netip.Addr,
+) (_ *agd.Profile, _ *agd.Device, _ error) {
+ panic(fmt.Errorf(profilesDBUnexpectedCall, "ProfileByDedicatedIP"))
+}
+
// ProfileByDeviceID implements the [Interface] interface for *Disabled.
func (d *Disabled) ProfileByDeviceID(
_ context.Context,
@@ -58,11 +98,13 @@ func (d *Disabled) ProfileByDeviceID(
panic(fmt.Errorf(profilesDBUnexpectedCall, "ProfileByDeviceID"))
}
-// ProfileByDedicatedIP implements the [Interface] interface for *Disabled.
-func (d *Disabled) ProfileByDedicatedIP(
- _ context.Context, _ netip.Addr,
+// ProfileByHumanID implements the [Interface] interface for *Disabled.
+func (d *Disabled) ProfileByHumanID(
+ _ context.Context,
+ _ agd.ProfileID,
+ _ agd.HumanIDLower,
) (_ *agd.Profile, _ *agd.Device, _ error) {
- panic(fmt.Errorf(profilesDBUnexpectedCall, "ProfileByDedicatedIP"))
+ panic(fmt.Errorf(profilesDBUnexpectedCall, "ProfileByHumanID"))
}
// ProfileByLinkedIP implements the [Interface] interface for *Disabled.
@@ -92,16 +134,14 @@ type Config struct {
// FullSyncRetryIvl is the interval between two retries of full
// synchronizations with the storage.
FullSyncRetryIvl time.Duration
-
- // InitialTimeout is the timeout for initial refresh.
- InitialTimeout time.Duration
}
// Default is the default in-memory implementation of the [Interface] interface
-// that can refresh itself from the provided storage.
+// that can refresh itself from the provided storage. It should be initially
+// refreshed before use.
type Default struct {
// mapsMu protects the profiles, devices, deviceIDToProfileID,
- // linkedIPToDeviceID, and dedicatedIPToDeviceID maps.
+ // dedicatedIPToDeviceID, humanIDToDeviceID, and linkedIPToDeviceID maps.
mapsMu *sync.RWMutex
// refreshMu serializes Refresh calls and access to all values used inside
@@ -123,16 +163,20 @@ type Default struct {
// devices maps device IDs to device records.
devices map[agd.DeviceID]*agd.Device
- // deviceIDToProfileID maps device IDs to the ID of their profile.
- deviceIDToProfileID map[agd.DeviceID]agd.ProfileID
-
- // linkedIPToDeviceID maps linked IP addresses to the IDs of their devices.
- linkedIPToDeviceID map[netip.Addr]agd.DeviceID
-
// dedicatedIPToDeviceID maps dedicated IP addresses to the IDs of their
// devices.
dedicatedIPToDeviceID map[netip.Addr]agd.DeviceID
+ // deviceIDToProfileID maps device IDs to the ID of their profile.
+ deviceIDToProfileID map[agd.DeviceID]agd.ProfileID
+
+ // humanIDToDeviceID maps human-readable device-ID data to the IDs of the
+ // devices.
+ humanIDToDeviceID map[humanIDKey]agd.DeviceID
+
+ // linkedIPToDeviceID maps linked IP addresses to the IDs of their devices.
+ linkedIPToDeviceID map[netip.Addr]agd.DeviceID
+
// syncTime is the time of the last synchronization point. It is received
// from the storage during a refresh and is then used in consecutive
// requests to the storage, unless it's a full synchronization.
@@ -155,6 +199,16 @@ type Default struct {
fullSyncRetryIvl time.Duration
}
+// humanIDKey is the data necessary to identify a device by the lowercase
+// version of its human-readable identifier and the ID of its profile.
+type humanIDKey struct {
+ // lower is the lowercase version of the human-readable device ID.
+ lower agd.HumanIDLower
+
+ // profile is the ID of the profile for the device.
+ profile agd.ProfileID
+}
+
// New returns a new default in-memory profile database with a filesystem cache.
// The initial refresh is performed immediately with the given timeout, beyond
// which an empty profiledb is returned. If cacheFilePath is the string "none",
@@ -181,8 +235,9 @@ func New(conf *Config) (db *Default, err error) {
profiles: make(map[agd.ProfileID]*agd.Profile),
devices: make(map[agd.DeviceID]*agd.Device),
deviceIDToProfileID: make(map[agd.DeviceID]agd.ProfileID),
- linkedIPToDeviceID: make(map[netip.Addr]agd.DeviceID),
dedicatedIPToDeviceID: make(map[netip.Addr]agd.DeviceID),
+ humanIDToDeviceID: make(map[humanIDKey]agd.DeviceID),
+ linkedIPToDeviceID: make(map[netip.Addr]agd.DeviceID),
fullSyncIvl: conf.FullSyncIvl,
fullSyncRetryIvl: conf.FullSyncRetryIvl,
}
@@ -192,24 +247,6 @@ func New(conf *Config) (db *Default, err error) {
log.Error("profiledb: fs cache: loading: %s", err)
}
- ctx, cancel := context.WithTimeout(context.Background(), conf.InitialTimeout)
- defer cancel()
-
- log.Info("profiledb: initial refresh")
-
- err = db.Refresh(ctx)
- if err != nil {
- if errors.Is(err, context.DeadlineExceeded) {
- log.Info("profiledb: warning: initial refresh timeout: %s", err)
-
- return db, nil
- }
-
- return nil, fmt.Errorf("initial refresh: %w", err)
- }
-
- log.Info("profiledb: initial refresh succeeded")
-
return db, nil
}
@@ -302,7 +339,7 @@ func (db *Default) fetchProfiles(
ctx context.Context,
sinceLastAttempt time.Duration,
isFullSync bool,
-) (sr *StorageResponse, err error) {
+) (sr *StorageProfilesResponse, err error) {
syncTime := db.syncTime
if isFullSync {
log.Info("profiledb: full sync, %s since last attempt", sinceLastAttempt)
@@ -310,7 +347,7 @@ func (db *Default) fetchProfiles(
syncTime = time.Time{}
}
- sr, err = db.storage.Profiles(ctx, &StorageRequest{
+ sr, err = db.storage.Profiles(ctx, &StorageProfilesRequest{
SyncTime: syncTime,
})
if err == nil {
@@ -402,9 +439,10 @@ func (db *Default) setProfiles(profiles []*agd.Profile, devices []*agd.Device, i
if isFullSync {
clear(db.profiles)
clear(db.devices)
- clear(db.deviceIDToProfileID)
- clear(db.linkedIPToDeviceID)
clear(db.dedicatedIPToDeviceID)
+ clear(db.deviceIDToProfileID)
+ clear(db.humanIDToDeviceID)
+ clear(db.linkedIPToDeviceID)
}
for _, p := range profiles {
@@ -415,23 +453,143 @@ func (db *Default) setProfiles(profiles []*agd.Profile, devices []*agd.Device, i
}
}
+ db.setDevices(devices)
+}
+
+// setDevices adds or updates the data for the given devices. It assumes that
+// db.mapsMu is locked for writing.
+func (db *Default) setDevices(devices []*agd.Device) {
for _, d := range devices {
devID := d.ID
db.devices[devID] = d
+ for _, dedIP := range d.DedicatedIPs {
+ db.dedicatedIPToDeviceID[dedIP] = devID
+ }
+
if d.LinkedIP != (netip.Addr{}) {
db.linkedIPToDeviceID[d.LinkedIP] = devID
}
- for _, dedIP := range d.DedicatedIPs {
- db.dedicatedIPToDeviceID[dedIP] = devID
+ if d.HumanIDLower == "" {
+ continue
}
+
+ profID, ok := db.deviceIDToProfileID[devID]
+ if !ok {
+ log.Info("profiledb: warning: no prof id for dev %q", devID)
+
+ continue
+ }
+
+ db.humanIDToDeviceID[humanIDKey{
+ lower: d.HumanIDLower,
+ profile: profID,
+ }] = devID
}
}
// type check
var _ Interface = (*Default)(nil)
+// CreateAutoDevice implements the [Interface] interface for *Default.
+func (db *Default) CreateAutoDevice(
+ ctx context.Context,
+ id agd.ProfileID,
+ humanID agd.HumanID,
+ devType agd.DeviceType,
+) (p *agd.Profile, d *agd.Device, err error) {
+ var ok bool
+ func() {
+ db.mapsMu.RLock()
+ defer db.mapsMu.RUnlock()
+
+ p, ok = db.profiles[id]
+ }()
+ if !ok {
+ return nil, nil, ErrProfileNotFound
+ }
+
+ if !p.AutoDevicesEnabled {
+ // If the user did not enable the automatic devices feature, treat it
+ // the same as if this profile did not exist.
+ return nil, nil, ErrProfileNotFound
+ }
+
+ resp, err := db.storage.CreateAutoDevice(ctx, &StorageCreateAutoDeviceRequest{
+ ProfileID: id,
+ HumanID: humanID,
+ DeviceType: devType,
+ })
+ if err != nil {
+ return nil, nil, err
+ }
+
+ d = resp.Device
+
+ func() {
+ db.mapsMu.Lock()
+ defer db.mapsMu.Unlock()
+
+ // TODO(a.garipov): Technically, we must also update p.DeviceIDs, but
+ // this is hard to do without races, since all methods of the profile
+ // database return values as opposed to clones. This can cause issues
+ // when the same device is used both by a HumanID and a DeviceID, but we
+ // consider this situation to be relatively rare.
+
+ db.setDevices([]*agd.Device{d})
+ }()
+
+ return p, d, nil
+}
+
+// ProfileByDedicatedIP implements the [Interface] interface for *Default. ip
+// must be valid.
+func (db *Default) ProfileByDedicatedIP(
+ ctx context.Context,
+ ip netip.Addr,
+) (p *agd.Profile, d *agd.Device, err error) {
+ // Do not use errors.Annotate here, because it allocates even when the error
+ // is nil. Also do not use fmt.Errorf in a defer, because it allocates when
+ // a device is not found, which is the most common case.
+
+ db.mapsMu.RLock()
+ defer db.mapsMu.RUnlock()
+
+ id, ok := db.dedicatedIPToDeviceID[ip]
+ if !ok {
+ return nil, nil, ErrDeviceNotFound
+ }
+
+ const errPrefix = "profile by device dedicated ip"
+ p, d, err = db.profileByDeviceID(ctx, id)
+ if err != nil {
+ if errors.Is(err, ErrDeviceNotFound) {
+ // Probably, the device has been deleted. Remove it from our
+ // profile DB in a goroutine, since that requires a write lock.
+ go db.removeDedicatedIP(ip)
+ }
+
+ // Don't add the device ID to the error here, since it is already added
+ // by profileByDeviceID.
+ return nil, nil, fmt.Errorf("%s: %w", errPrefix, err)
+ }
+
+ if !slices.Contains(d.DedicatedIPs, ip) {
+ // Perhaps, the device has changed its dedicated IPs. Remove it from
+ // our profile DB in a goroutine, since that requires a write lock.
+ go db.removeDedicatedIP(ip)
+
+ return nil, nil, fmt.Errorf(
+ "%s: rechecking dedicated ips: %w",
+ errPrefix,
+ ErrDeviceNotFound,
+ )
+ }
+
+ return p, d, nil
+}
+
// ProfileByDeviceID implements the [Interface] interface for *Default.
func (db *Default) ProfileByDeviceID(
ctx context.Context,
@@ -464,7 +622,7 @@ func (db *Default) profileByDeviceID(
// from our profile DB in a goroutine, since that requires a write lock.
go db.removeDevice(id)
- return nil, nil, fmt.Errorf("empty profile: %w", ErrDeviceNotFound)
+ return nil, nil, ErrProfileNotFound
}
// Reinspect the devices in the profile record to make sure that the device
@@ -478,10 +636,15 @@ func (db *Default) profileByDeviceID(
}
if d == nil {
- // Perhaps, the device has been deleted from this profile. May happen
- // when the device was found by a linked IP. Remove it from our profile
- // DB in a goroutine, since that requires a write lock.
- go db.removeDevice(id)
+ if !p.AutoDevicesEnabled {
+ // Perhaps, the device has been deleted from this profile. May
+ // happen when the device was found by a linked IP. Remove it from
+ // our profile DB in a goroutine, since that requires a write lock.
+ //
+ // Do not do that for profiles with enabled autodevices, though.
+ // See the TODO in [Default.CreateAutoDevice].
+ go db.removeDevice(id)
+ }
return nil, nil, fmt.Errorf("rechecking devices: %w", ErrDeviceNotFound)
}
@@ -500,6 +663,84 @@ func (db *Default) removeDevice(id agd.DeviceID) {
delete(db.deviceIDToProfileID, id)
}
+// removeDedicatedIP removes the device link for the given dedicated IP address
+// from the profile database. It is intended to be used as a goroutine.
+func (db *Default) removeDedicatedIP(ip netip.Addr) {
+ defer log.OnPanicAndExit("removeDedicatedIP", 1)
+
+ db.mapsMu.Lock()
+ defer db.mapsMu.Unlock()
+
+ delete(db.dedicatedIPToDeviceID, ip)
+}
+
+// ProfileByHumanID implements the [Interface] interface for *Default.
+func (db *Default) ProfileByHumanID(
+ ctx context.Context,
+ id agd.ProfileID,
+ humanID agd.HumanIDLower,
+) (p *agd.Profile, d *agd.Device, err error) {
+ // Do not use errors.Annotate here, because it allocates even when the error
+ // is nil. Also do not use fmt.Errorf in a defer, because it allocates when
+ // a device is not found, which is the most common case.
+
+ db.mapsMu.RLock()
+ defer db.mapsMu.RUnlock()
+
+ // NOTE: It's important to check the profile and return ErrProfileNotFound
+ // here to prevent the device setter from trying to create a device for a
+ // profile that doesn't exist.
+ p, ok := db.profiles[id]
+ if !ok {
+ return nil, nil, ErrProfileNotFound
+ }
+
+ k := humanIDKey{
+ lower: humanID,
+ profile: id,
+ }
+ devID, ok := db.humanIDToDeviceID[k]
+ if !ok {
+ return nil, nil, ErrDeviceNotFound
+ }
+
+ const errPrefix = "profile by human id"
+ p, d, err = db.profileByDeviceID(ctx, devID)
+ if err != nil {
+ if errors.Is(err, ErrDeviceNotFound) {
+ // Probably, the device has been deleted. Remove it from our
+ // profile DB in a goroutine, since that requires a write lock.
+ go db.removeHumanID(k)
+ }
+
+ // Don't add the device ID to the error here, since it is already added
+ // by profileByDeviceID.
+ return nil, nil, fmt.Errorf("%s: %w", errPrefix, err)
+ }
+
+ if humanID != d.HumanIDLower {
+ // Perhaps, the device has changed its human ID, for example by being
+ // transformed into a normal device.. Remove it from our profile DB in
+ // a goroutine, since that requires a write lock.
+ go db.removeHumanID(k)
+
+ return nil, nil, fmt.Errorf("%s: rechecking human id: %w", errPrefix, ErrDeviceNotFound)
+ }
+
+ return p, d, nil
+}
+
+// removeHumanID removes the device link for the given key from the profile
+// database. It is intended to be used as a goroutine.
+func (db *Default) removeHumanID(k humanIDKey) {
+ defer log.OnPanicAndExit("removeHumanID", 1)
+
+ db.mapsMu.Lock()
+ defer db.mapsMu.Unlock()
+
+ delete(db.humanIDToDeviceID, k)
+}
+
// ProfileByLinkedIP implements the [Interface] interface for *Default. ip must
// be valid.
func (db *Default) ProfileByLinkedIP(
@@ -544,7 +785,7 @@ func (db *Default) ProfileByLinkedIP(
go db.removeLinkedIP(ip)
return nil, nil, fmt.Errorf(
- "%s: %q doesn't match: %w",
+ "%s: %q does not match: %w",
errPrefix,
d.LinkedIP,
ErrDeviceNotFound,
@@ -564,61 +805,3 @@ func (db *Default) removeLinkedIP(ip netip.Addr) {
delete(db.linkedIPToDeviceID, ip)
}
-
-// ProfileByDedicatedIP implements the [Interface] interface for *Default. ip
-// must be valid.
-func (db *Default) ProfileByDedicatedIP(
- ctx context.Context,
- ip netip.Addr,
-) (p *agd.Profile, d *agd.Device, err error) {
- // Do not use errors.Annotate here, because it allocates even when the error
- // is nil. Also do not use fmt.Errorf in a defer, because it allocates when
- // a device is not found, which is the most common case.
-
- db.mapsMu.RLock()
- defer db.mapsMu.RUnlock()
-
- id, ok := db.dedicatedIPToDeviceID[ip]
- if !ok {
- return nil, nil, ErrDeviceNotFound
- }
-
- const errPrefix = "profile by device dedicated ip"
- p, d, err = db.profileByDeviceID(ctx, id)
- if err != nil {
- if errors.Is(err, ErrDeviceNotFound) {
- // Probably, the device has been deleted. Remove it from our
- // profile DB in a goroutine, since that requires a write lock.
- go db.removeDedicatedIP(ip)
- }
-
- // Don't add the device ID to the error here, since it is already added
- // by profileByDeviceID.
- return nil, nil, fmt.Errorf("%s: %w", errPrefix, err)
- }
-
- if ipIdx := slices.Index(d.DedicatedIPs, ip); ipIdx < 0 {
- // Perhaps, the device has changed its dedicated IPs. Remove it from
- // our profile DB in a goroutine, since that requires a write lock.
- go db.removeDedicatedIP(ip)
-
- return nil, nil, fmt.Errorf(
- "%s: rechecking dedicated ips: %w",
- errPrefix,
- ErrDeviceNotFound,
- )
- }
-
- return p, d, nil
-}
-
-// removeDedicatedIP removes the device link for the given dedicated IP address
-// from the profile database. It is intended to be used as a goroutine.
-func (db *Default) removeDedicatedIP(ip netip.Addr) {
- defer log.OnPanicAndExit("removeDedicatedIP", 1)
-
- db.mapsMu.Lock()
- defer db.mapsMu.Unlock()
-
- delete(db.dedicatedIPToDeviceID, ip)
-}
diff --git a/internal/profiledb/profiledb_test.go b/internal/profiledb/profiledb_test.go
index 615ddb5..85f3c5c 100644
--- a/internal/profiledb/profiledb_test.go
+++ b/internal/profiledb/profiledb_test.go
@@ -26,11 +26,11 @@ func TestMain(m *testing.M) {
// Common IPs for tests
var (
- testClientIPv4 = netip.MustParseAddr("1.2.3.4")
- testOtherClientIPv4 = netip.MustParseAddr("1.2.3.5")
+ testClientIPv4 = netip.MustParseAddr("192.0.2.1")
+ testOtherClientIPv4 = netip.MustParseAddr("192.0.2.2")
- testDedicatedIPv4 = netip.MustParseAddr("1.2.4.5")
- testOtherDedicatedIPv4 = netip.MustParseAddr("1.2.4.6")
+ testDedicatedIPv4 = netip.MustParseAddr("192.0.2.3")
+ testOtherDedicatedIPv4 = netip.MustParseAddr("192.0.2.4")
)
// testTimeout is the common timeout for tests.
@@ -44,15 +44,15 @@ func newDefaultProfileDB(tb testing.TB, devices <-chan []*agd.Device) (db *profi
onProfiles := func(
_ context.Context,
- _ *profiledb.StorageRequest,
- ) (resp *profiledb.StorageResponse, err error) {
+ _ *profiledb.StorageProfilesRequest,
+ ) (resp *profiledb.StorageProfilesResponse, err error) {
devices, _ := testutil.RequireReceive(tb, devices, testTimeout)
devIDs := make([]agd.DeviceID, 0, len(devices))
for _, d := range devices {
devIDs = append(devIDs, d.ID)
}
- return &profiledb.StorageResponse{
+ return &profiledb.StorageProfilesResponse{
Profiles: []*agd.Profile{{
BlockingMode: &dnsmsg.BlockingModeNullIP{},
ID: profiledbtest.ProfileID,
@@ -63,6 +63,12 @@ func newDefaultProfileDB(tb testing.TB, devices <-chan []*agd.Device) (db *profi
}
ps := &agdtest.ProfileStorage{
+ OnCreateAutoDevice: func(
+ _ context.Context,
+ _ *profiledb.StorageCreateAutoDeviceRequest,
+ ) (resp *profiledb.StorageCreateAutoDeviceResponse, err error) {
+ panic("not implemented")
+ },
OnProfiles: onProfiles,
}
@@ -70,56 +76,90 @@ func newDefaultProfileDB(tb testing.TB, devices <-chan []*agd.Device) (db *profi
Storage: ps,
FullSyncIvl: 1 * time.Minute,
FullSyncRetryIvl: 1 * time.Minute,
- InitialTimeout: testTimeout,
CacheFilePath: "none",
})
require.NoError(tb, err)
+ ctx := testutil.ContextWithTimeout(tb, testTimeout)
+ require.NoError(tb, db.Refresh(ctx))
+
return db
}
func TestDefaultProfileDB(t *testing.T) {
- dev := &agd.Device{
- ID: profiledbtest.DeviceID,
- LinkedIP: testClientIPv4,
- DedicatedIPs: []netip.Addr{
- testDedicatedIPv4,
+ t.Parallel()
+
+ const (
+ devIdxDefault = iota
+ devIdxAuto
+ )
+
+ devices := []*agd.Device{
+ devIdxDefault: {
+ ID: profiledbtest.DeviceID,
+ LinkedIP: testClientIPv4,
+ DedicatedIPs: []netip.Addr{
+ testDedicatedIPv4,
+ },
+ },
+ devIdxAuto: {
+ ID: profiledbtest.DeviceIDAuto,
+ HumanIDLower: profiledbtest.HumanIDLower,
},
}
- devicesCh := make(chan []*agd.Device, 1)
- devicesCh <- []*agd.Device{dev}
+ devicesCh := make(chan []*agd.Device, 2)
+ devicesCh <- devices
db := newDefaultProfileDB(t, devicesCh)
- t.Run("by_device_id", func(t *testing.T) {
- ctx := testutil.ContextWithTimeout(t, testTimeout)
- p, d, err := db.ProfileByDeviceID(ctx, profiledbtest.DeviceID)
- require.NoError(t, err)
-
- assert.Equal(t, profiledbtest.ProfileID, p.ID)
- assert.Equal(t, d, dev)
- })
-
t.Run("by_dedicated_ip", func(t *testing.T) {
+ t.Parallel()
+
ctx := testutil.ContextWithTimeout(t, testTimeout)
p, d, err := db.ProfileByDedicatedIP(ctx, testDedicatedIPv4)
require.NoError(t, err)
assert.Equal(t, profiledbtest.ProfileID, p.ID)
- assert.Equal(t, d, dev)
+ assert.Equal(t, d, devices[devIdxDefault])
+ })
+
+ t.Run("by_device_id", func(t *testing.T) {
+ t.Parallel()
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ p, d, err := db.ProfileByDeviceID(ctx, profiledbtest.DeviceID)
+ require.NoError(t, err)
+
+ assert.Equal(t, profiledbtest.ProfileID, p.ID)
+ assert.Equal(t, d, devices[devIdxDefault])
+ })
+
+ t.Run("by_human_id", func(t *testing.T) {
+ t.Parallel()
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ p, d, err := db.ProfileByHumanID(ctx, profiledbtest.ProfileID, profiledbtest.HumanIDLower)
+ require.NoError(t, err)
+
+ assert.Equal(t, profiledbtest.ProfileID, p.ID)
+ assert.Equal(t, d, devices[devIdxAuto])
})
t.Run("by_linked_ip", func(t *testing.T) {
+ t.Parallel()
+
ctx := testutil.ContextWithTimeout(t, testTimeout)
p, d, err := db.ProfileByLinkedIP(ctx, testClientIPv4)
require.NoError(t, err)
assert.Equal(t, profiledbtest.ProfileID, p.ID)
- assert.Equal(t, d, dev)
+ assert.Equal(t, d, devices[devIdxDefault])
})
}
func TestDefaultProfileDB_ProfileByDedicatedIP_removedDevice(t *testing.T) {
+ t.Parallel()
+
dev := &agd.Device{
ID: profiledbtest.DeviceID,
DedicatedIPs: []netip.Addr{
@@ -156,6 +196,8 @@ func TestDefaultProfileDB_ProfileByDedicatedIP_removedDevice(t *testing.T) {
}
func TestDefaultProfileDB_ProfileByDedicatedIP_deviceNewIP(t *testing.T) {
+ t.Parallel()
+
dev := &agd.Device{
ID: profiledbtest.DeviceID,
DedicatedIPs: []netip.Addr{
@@ -199,7 +241,81 @@ func TestDefaultProfileDB_ProfileByDedicatedIP_deviceNewIP(t *testing.T) {
}, testTimeout, testTimeout/10)
}
+func TestDefaultProfileDB_ProfileByHumanID_removedDevice(t *testing.T) {
+ t.Parallel()
+
+ dev := &agd.Device{
+ ID: profiledbtest.DeviceIDAuto,
+ HumanIDLower: profiledbtest.HumanIDLower,
+ }
+
+ devicesCh := make(chan []*agd.Device, 2)
+
+ // The first response, the device is still there.
+ devicesCh <- []*agd.Device{dev}
+
+ db := newDefaultProfileDB(t, devicesCh)
+
+ ctx := context.Background()
+ _, d, err := db.ProfileByHumanID(ctx, profiledbtest.ProfileID, profiledbtest.HumanIDLower)
+ require.NoError(t, err)
+
+ assert.Equal(t, d, dev)
+
+ // The second response, the device is removed.
+ devicesCh <- nil
+
+ err = db.Refresh(ctx)
+ require.NoError(t, err)
+
+ assert.Eventually(t, func() (ok bool) {
+ _, d, err = db.ProfileByHumanID(ctx, profiledbtest.ProfileID, profiledbtest.HumanIDLower)
+
+ return errors.Is(err, profiledb.ErrDeviceNotFound)
+ }, testTimeout, testTimeout/10)
+}
+
+func TestDefaultProfileDB_ProfileByHumanID_deviceNotAuto(t *testing.T) {
+ t.Parallel()
+
+ dev := &agd.Device{
+ ID: profiledbtest.DeviceIDAuto,
+ HumanIDLower: profiledbtest.HumanIDLower,
+ }
+
+ devicesCh := make(chan []*agd.Device, 2)
+
+ // The first response, the device is still there.
+ devicesCh <- []*agd.Device{dev}
+
+ db := newDefaultProfileDB(t, devicesCh)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ _, d, err := db.ProfileByHumanID(ctx, profiledbtest.ProfileID, profiledbtest.HumanIDLower)
+ require.NoError(t, err)
+
+ assert.Equal(t, d, dev)
+
+ // The second response, the device is now a non-auto device.
+ devicesCh <- []*agd.Device{{
+ ID: profiledbtest.DeviceIDAuto,
+ }}
+
+ ctx = testutil.ContextWithTimeout(t, testTimeout)
+ err = db.Refresh(ctx)
+ require.NoError(t, err)
+
+ assert.Eventually(t, func() (ok bool) {
+ ctx = testutil.ContextWithTimeout(t, testTimeout)
+ _, d, err = db.ProfileByHumanID(ctx, profiledbtest.ProfileID, profiledbtest.HumanIDLower)
+
+ return errors.Is(err, profiledb.ErrDeviceNotFound)
+ }, testTimeout, testTimeout/10)
+}
+
func TestDefaultProfileDB_ProfileByLinkedIP_removedDevice(t *testing.T) {
+ t.Parallel()
+
dev := &agd.Device{
ID: profiledbtest.DeviceID,
LinkedIP: testClientIPv4,
@@ -232,6 +348,8 @@ func TestDefaultProfileDB_ProfileByLinkedIP_removedDevice(t *testing.T) {
}
func TestDefaultProfileDB_ProfileByLinkedIP_deviceNewIP(t *testing.T) {
+ t.Parallel()
+
dev := &agd.Device{
ID: profiledbtest.DeviceID,
LinkedIP: testClientIPv4,
@@ -274,17 +392,25 @@ func TestDefaultProfileDB_ProfileByLinkedIP_deviceNewIP(t *testing.T) {
}
func TestDefaultProfileDB_fileCache_success(t *testing.T) {
+ t.Parallel()
+
var gotSyncTime time.Time
onProfiles := func(
_ context.Context,
- req *profiledb.StorageRequest,
- ) (resp *profiledb.StorageResponse, err error) {
+ req *profiledb.StorageProfilesRequest,
+ ) (resp *profiledb.StorageProfilesResponse, err error) {
gotSyncTime = req.SyncTime
- return &profiledb.StorageResponse{}, nil
+ return &profiledb.StorageProfilesResponse{}, nil
}
ps := &agdtest.ProfileStorage{
+ OnCreateAutoDevice: func(
+ _ context.Context,
+ _ *profiledb.StorageCreateAutoDeviceRequest,
+ ) (resp *profiledb.StorageCreateAutoDeviceResponse, err error) {
+ panic("not implemented")
+ },
OnProfiles: onProfiles,
}
@@ -307,12 +433,14 @@ func TestDefaultProfileDB_fileCache_success(t *testing.T) {
Storage: ps,
FullSyncIvl: 1 * time.Minute,
FullSyncRetryIvl: 1 * time.Minute,
- InitialTimeout: testTimeout,
CacheFilePath: cacheFilePath,
})
require.NoError(t, err)
require.NotNil(t, db)
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, db.Refresh(ctx))
+
assert.Equal(t, wantSyncTime, gotSyncTime)
p, d, err := db.ProfileByDeviceID(context.Background(), dev.ID)
@@ -322,15 +450,23 @@ func TestDefaultProfileDB_fileCache_success(t *testing.T) {
}
func TestDefaultProfileDB_fileCache_badVersion(t *testing.T) {
+ t.Parallel()
+
storageCalled := false
ps := &agdtest.ProfileStorage{
+ OnCreateAutoDevice: func(
+ _ context.Context,
+ _ *profiledb.StorageCreateAutoDeviceRequest,
+ ) (resp *profiledb.StorageCreateAutoDeviceResponse, err error) {
+ panic("not implemented")
+ },
OnProfiles: func(
_ context.Context,
- _ *profiledb.StorageRequest,
- ) (resp *profiledb.StorageResponse, err error) {
+ _ *profiledb.StorageProfilesRequest,
+ ) (resp *profiledb.StorageProfilesResponse, err error) {
storageCalled = true
- return &profiledb.StorageResponse{}, nil
+ return &profiledb.StorageProfilesResponse{}, nil
},
}
@@ -345,14 +481,75 @@ func TestDefaultProfileDB_fileCache_badVersion(t *testing.T) {
Storage: ps,
FullSyncIvl: 1 * time.Minute,
FullSyncRetryIvl: 1 * time.Minute,
- InitialTimeout: testTimeout,
CacheFilePath: cacheFilePath,
})
assert.NoError(t, err)
assert.NotNil(t, db)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, db.Refresh(ctx))
+
assert.True(t, storageCalled)
}
+func TestDefaultProfileDB_CreateAutoDevice(t *testing.T) {
+ t.Parallel()
+
+ wantDev := &agd.Device{
+ ID: profiledbtest.DeviceIDAuto,
+ HumanIDLower: profiledbtest.HumanIDLower,
+ }
+ wantProf := &agd.Profile{
+ BlockingMode: &dnsmsg.BlockingModeNullIP{},
+ ID: profiledbtest.ProfileID,
+ DeviceIDs: nil,
+ AutoDevicesEnabled: true,
+ }
+
+ ps := &agdtest.ProfileStorage{
+ OnCreateAutoDevice: func(
+ _ context.Context,
+ _ *profiledb.StorageCreateAutoDeviceRequest,
+ ) (resp *profiledb.StorageCreateAutoDeviceResponse, err error) {
+ return &profiledb.StorageCreateAutoDeviceResponse{
+ Device: wantDev,
+ }, nil
+ },
+ OnProfiles: func(
+ _ context.Context,
+ _ *profiledb.StorageProfilesRequest,
+ ) (resp *profiledb.StorageProfilesResponse, err error) {
+ return &profiledb.StorageProfilesResponse{
+ Profiles: []*agd.Profile{wantProf},
+ Devices: nil,
+ }, nil
+ },
+ }
+
+ db, err := profiledb.New(&profiledb.Config{
+ Storage: ps,
+ FullSyncIvl: 1 * time.Minute,
+ FullSyncRetryIvl: 1 * time.Minute,
+ CacheFilePath: "none",
+ })
+ require.NoError(t, err)
+ require.NotNil(t, db)
+
+ ctx := testutil.ContextWithTimeout(t, testTimeout)
+ require.NoError(t, db.Refresh(ctx))
+
+ p, d, err := db.CreateAutoDevice(
+ ctx,
+ profiledbtest.ProfileID,
+ profiledbtest.HumanID,
+ agd.DeviceTypeOther,
+ )
+ require.NoError(t, err)
+
+ assert.Equal(t, wantDev, d)
+ assert.Equal(t, wantProf, p)
+}
+
// Sinks for benchmarks.
var (
profSink *agd.Profile
@@ -404,8 +601,8 @@ func BenchmarkDefaultProfileDB_ProfileByDeviceID(b *testing.B) {
// goarch: amd64
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/profiledb
// cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
- // BenchmarkDefaultProfileDB_ProfileByDeviceID/success-16 59396382 21.36 ns/op 0 B/op 0 allocs/op
- // BenchmarkDefaultProfileDB_ProfileByDeviceID/not_found-16 74497800 16.45 ns/op 0 B/op 0 allocs/op
+ // BenchmarkDefaultProfileDB_ProfileByDeviceID/success-16 55459413 23.43 ns/op 0 B/op 0 allocs/op
+ // BenchmarkDefaultProfileDB_ProfileByDeviceID/not_found-16 61798608 17.87 ns/op 0 B/op 0 allocs/op
}
func BenchmarkDefaultProfileDB_ProfileByLinkedIP(b *testing.B) {
@@ -451,8 +648,8 @@ func BenchmarkDefaultProfileDB_ProfileByLinkedIP(b *testing.B) {
// goarch: amd64
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/profiledb
// cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
- // BenchmarkDefaultProfileDB_ProfileByLinkedIP/success-16 24822542 44.11 ns/op 0 B/op 0 allocs/op
- // BenchmarkDefaultProfileDB_ProfileByLinkedIP/not_found-16 63539154 20.04 ns/op 0 B/op 0 allocs/op
+ // BenchmarkDefaultProfileDB_ProfileByLinkedIP/success-16 26068507 44.23 ns/op 0 B/op 0 allocs/op
+ // BenchmarkDefaultProfileDB_ProfileByLinkedIP/not_found-16 53764724 22.63 ns/op 0 B/op 0 allocs/op
}
func BenchmarkDefaultProfileDB_ProfileByDedicatedIP(b *testing.B) {
@@ -500,6 +697,6 @@ func BenchmarkDefaultProfileDB_ProfileByDedicatedIP(b *testing.B) {
// goarch: amd64
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/profiledb
// cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
- // BenchmarkDefaultProfileDB_ProfileByDedicatedIP/success-16 22697658 48.19 ns/op 0 B/op 0 allocs/op
- // BenchmarkDefaultProfileDB_ProfileByDedicatedIP/not_found-16 61062061 19.89 ns/op 0 B/op 0 allocs/op
+ // BenchmarkDefaultProfileDB_ProfileByDedicatedIP/success-16 26034816 48.21 ns/op 0 B/op 0 allocs/op
+ // BenchmarkDefaultProfileDB_ProfileByDedicatedIP/not_found-16 54165615 22.38 ns/op 0 B/op 0 allocs/op
}
diff --git a/internal/profiledb/storage.go b/internal/profiledb/storage.go
index b3b68ed..eab23e5 100644
--- a/internal/profiledb/storage.go
+++ b/internal/profiledb/storage.go
@@ -8,21 +8,51 @@ import (
)
// Storage is a storage from which an [Default] receives data about profiles and
-// devices.
+// devices. All methods must be safe for concurrent use.
+//
+// TODO(a.garipov): Consider separating into a new package along with its
+// errors.
type Storage interface {
+ // CreateAutoDevice creates an auto device based on the given data.
+ // req must not be nil.
+ CreateAutoDevice(
+ ctx context.Context,
+ req *StorageCreateAutoDeviceRequest,
+ ) (resp *StorageCreateAutoDeviceResponse, err error)
+
// Profiles returns profile and device data that has changed since
// req.SyncTime. req must not be nil.
- Profiles(ctx context.Context, req *StorageRequest) (resp *StorageResponse, err error)
+ Profiles(
+ ctx context.Context,
+ req *StorageProfilesRequest,
+ ) (resp *StorageProfilesResponse, err error)
}
-// StorageRequest is the request to [Storage] for profiles and devices.
-type StorageRequest struct {
+// StorageCreateAutoDeviceRequest contains the data for a call to the
+// [Storage.CreateAutoDevice] method. All fields should be valid.
+type StorageCreateAutoDeviceRequest struct {
+ ProfileID agd.ProfileID
+ HumanID agd.HumanID
+ DeviceType agd.DeviceType
+}
+
+// StorageCreateAutoDeviceResponse is the response from the
+// [Storage.CreateAutoDevice] method.
+type StorageCreateAutoDeviceResponse struct {
+ // Device is the resulting device. If the error returned with this response
+ // is nil, Device is never nil.
+ Device *agd.Device
+}
+
+// StorageProfilesRequest contains the data for a call to the [Storage.Profiles]
+// method.
+type StorageProfilesRequest struct {
// SyncTime is the last time profiles were synced.
SyncTime time.Time
}
-// StorageResponse is the ProfileStorage.Profiles response.
-type StorageResponse struct {
+// StorageProfilesResponse is the response from the [Storage.Profiles] method.
+type StorageProfilesResponse struct {
// SyncTime is the time that should be saved and used as the next
// [ProfilesRequest.SyncTime].
SyncTime time.Time
diff --git a/internal/tools/go.mod b/internal/tools/go.mod
index 96ff30a..9eeab4c 100644
--- a/internal/tools/go.mod
+++ b/internal/tools/go.mod
@@ -1,26 +1,26 @@
module github.com/AdguardTeam/AdGuardDNS/internal/tools
-go 1.22.4
+go 1.22.5
require (
github.com/fzipp/gocyclo v0.6.0
- github.com/golangci/misspell v0.5.1
+ github.com/golangci/misspell v0.6.0
github.com/gordonklaus/ineffassign v0.1.0
github.com/kisielk/errcheck v1.7.0
github.com/kyoh86/looppointer v0.2.1
- github.com/securego/gosec/v2 v2.19.0
+ github.com/securego/gosec/v2 v2.20.0
github.com/uudashr/gocognit v1.1.2
- golang.org/x/tools v0.21.0
- golang.org/x/vuln v1.1.0
- google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
- google.golang.org/protobuf v1.34.1
+ golang.org/x/tools v0.22.0
+ golang.org/x/vuln v1.1.2
+ google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.4.0
+ google.golang.org/protobuf v1.34.2
honnef.co/go/tools v0.4.7
mvdan.cc/gofumpt v0.6.0
- mvdan.cc/unparam v0.0.0-20240427195214-063aff900ca1
+ mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f
)
require (
- github.com/BurntSushi/toml v1.3.2 // indirect
+ github.com/BurntSushi/toml v1.4.0 // indirect
github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.6.0 // indirect
@@ -28,9 +28,10 @@ require (
github.com/kyoh86/nolint v0.0.1 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 // indirect
- golang.org/x/exp/typeparams v0.0.0-20240506185415-9bf2ced13842 // indirect
- golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/exp/typeparams v0.0.0-20240613232115-7f521ea00fb8 // indirect
+ golang.org/x/mod v0.18.0 // indirect
golang.org/x/sync v0.7.0 // indirect
- golang.org/x/sys v0.20.0 // indirect
+ golang.org/x/sys v0.21.0 // indirect
+ golang.org/x/telemetry v0.0.0-20240614130327-d92499019833 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/internal/tools/go.sum b/internal/tools/go.sum
index b0470d2..8f512d6 100644
--- a/internal/tools/go.sum
+++ b/internal/tools/go.sum
@@ -1,5 +1,5 @@
-github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
-github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
+github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg=
github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -8,18 +8,18 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
-github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
-github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
-github.com/golangci/misspell v0.5.1 h1:/SjR1clj5uDjNLwYzCahHwIOPmQgoH04AyQIiWGbhCM=
-github.com/golangci/misspell v0.5.1/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
+github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
+github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
+github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
-github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
+github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@@ -38,16 +38,16 @@ github.com/kyoh86/looppointer v0.2.1 h1:Jx9fnkBj/JrIryBLMTYNTj9rvc2SrPS98Dg0w7fx
github.com/kyoh86/looppointer v0.2.1/go.mod h1:q358WcM8cMWU+5vzqukvaZtnJi1kw/MpRHQm3xvTrjw=
github.com/kyoh86/nolint v0.0.1 h1:GjNxDEkVn2wAxKHtP7iNTrRxytRZ1wXxLV5j4XzGfRU=
github.com/kyoh86/nolint v0.0.1/go.mod h1:1ZiZZ7qqrZ9dZegU96phwVcdQOMKIqRzFJL3ewq9gtI=
-github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
-github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
-github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo=
-github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0=
+github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g=
+github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
+github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
+github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
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/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-github.com/securego/gosec/v2 v2.19.0 h1:gl5xMkOI0/E6Hxx0XCY2XujA3V7SNSefA8sC+3f1gnk=
-github.com/securego/gosec/v2 v2.19.0/go.mod h1:hOkDcHz9J/XIgIlPDXalxjeVYsHxoWUc5zJSHxcB8YM=
+github.com/securego/gosec/v2 v2.20.0 h1:z/d5qp1niWa2avgFyUIglYTYYuGq2LrJwNj1HRVXsqc=
+github.com/securego/gosec/v2 v2.20.0/go.mod h1:hkiArbBZLwK1cehBcg3oFWUlYPWTBffPwwJVWChu83o=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/uudashr/gocognit v1.1.2 h1:l6BAEKJqQH2UpKAPKdMfZf5kE4W/2xk8pfU1OVLvniI=
@@ -63,21 +63,21 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
-golang.org/x/exp/typeparams v0.0.0-20240506185415-9bf2ced13842 h1:S62OJe0/hUkTgveY1HXZMHWBOy21DVrobMYz2cMCO64=
-golang.org/x/exp/typeparams v0.0.0-20240506185415-9bf2ced13842/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+golang.org/x/exp/typeparams v0.0.0-20240613232115-7f521ea00fb8 h1:+ZJmEdDFzH5H0CnzOrwgbH3elHctfTecW9X0k2tkn5M=
+golang.org/x/exp/typeparams v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
+golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
-golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -93,31 +93,33 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
-golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/telemetry v0.0.0-20240614130327-d92499019833 h1:fY9J7jgRT8h0DU8TKsSNFBZAnxKhzoprAILMRpKQa8Q=
+golang.org/x/telemetry v0.0.0-20240614130327-d92499019833/go.mod h1:n38mvGdgc4dA684EC4NwQwoPKSw4jyKw8/DgZHDA1Dk=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
-golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
-golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-golang.org/x/vuln v1.1.0 h1:ECEdI+aEtjpF90eqEcDL5Q11DWSZAw5PJQWlp0+gWqc=
-golang.org/x/vuln v1.1.0/go.mod h1:HT/Ar8fE34tbxWG2s7PYjVl+iIE4Er36/940Z+K540Y=
+golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
+golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/vuln v1.1.2 h1:UkLxe+kAMcrNBpGrFbU0Mc5l7cX97P2nhy21wx5+Qbk=
+golang.org/x/vuln v1.1.2/go.mod h1:2o3fRKD8Uz9AraAL3lwd/grWBv+t+SeJnPcqBUJrY24=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA=
-google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y=
-google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
-google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.4.0 h1:9SxA29VM43MF5Z9dQu694wmY5t8E/Gxr7s+RSxiIDmc=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.4.0/go.mod h1:yZOK5zhQMiALmuweVdIVoQPa6eIJyXn2B9g5dJDhqX4=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
@@ -126,5 +128,5 @@ honnef.co/go/tools v0.4.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs=
honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0=
mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo=
mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA=
-mvdan.cc/unparam v0.0.0-20240427195214-063aff900ca1 h1:Nykk7fggxChwLK4rUPYESzeIwqsuxXXlFEAh5YhaMRo=
-mvdan.cc/unparam v0.0.0-20240427195214-063aff900ca1/go.mod h1:ZzZjEpJDOmx8TdVU6umamY3Xy0UAQUI2DHbf05USVbI=
+mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U=
+mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ=
diff --git a/scripts/backend/main.go b/scripts/backend/main.go
index c946a21..c469f4e 100644
--- a/scripts/backend/main.go
+++ b/scripts/backend/main.go
@@ -3,16 +3,21 @@
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/log"
+ "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"
@@ -20,38 +25,77 @@ import (
)
func main() {
+ l := slogutil.New(nil)
+
const listenAddr = "localhost:6062"
- l, err := net.Listen("tcp", listenAddr)
+ lsnr, err := net.Listen("tcp", listenAddr)
if err != nil {
- log.Fatalf("getting listener: %s", err)
+ l.Error("getting listener", slogutil.KeyError, err)
+
+ os.Exit(osutil.ExitCodeFailure)
}
grpcSrv := grpc.NewServer()
- srv := &mockDNSServiceServer{}
+ srv := &mockDNSServiceServer{
+ log: slogutil.New(nil),
+ }
backendpb.RegisterDNSServiceServer(grpcSrv, srv)
- log.Info("staring serving on %s", listenAddr)
- err = grpcSrv.Serve(l)
+ l.Info("staring serving", "laddr", listenAddr)
+ err = grpcSrv.Serve(lsnr)
if err != nil {
- log.Fatalf("serving grpc: %s", err)
+ l.Error("serving grpc", slogutil.KeyError, err)
+
+ 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 backendpb.DNSService_GetDNSProfilesServer,
) (err error) {
- log.Info("getting dns profiles: sync time: %s", req.SyncTime.AsTime())
+ 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)
@@ -60,9 +104,9 @@ func (s *mockDNSServiceServer) GetDNSProfiles(
}
srv.SetTrailer(trailerMD)
- err = srv.Send(mockDNSProfile())
+ err = srv.Send(newDNSProfile())
if err != nil {
- log.Info("sending dns profile: %s", err)
+ s.log.WarnContext(ctx, "sending dns profile", slogutil.KeyError, err)
}
return nil
@@ -73,8 +117,13 @@ func (s *mockDNSServiceServer) GetDNSProfiles(
func (s *mockDNSServiceServer) SaveDevicesBillingStat(
srv backendpb.DNSService_SaveDevicesBillingStatServer,
) (err error) {
+ ctx := srv.Context()
+ md, _ := metadata.FromIncomingContext(ctx)
+ s.log.InfoContext(ctx, "saving devices", "auth", md.Get(httphdr.Authorization))
+
for {
- bs, err := srv.Recv()
+ var bs *backendpb.DeviceBillingStat
+ bs, err = srv.Recv()
if err != nil {
if errors.Is(err, io.EOF) {
return srv.SendAndClose(&emptypb.Empty{})
@@ -83,12 +132,12 @@ func (s *mockDNSServiceServer) SaveDevicesBillingStat(
}
}
- log.Info("saving billing stat: device: %q", bs.DeviceId)
+ s.log.InfoContext(ctx, "saving billing stat", "device_id", bs.DeviceId)
}
}
-// mockDNSProfile returns a mock instance of [*backendpb.DNSProfile].
-func mockDNSProfile() (dp *backendpb.DNSProfile) {
+// 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),
@@ -100,13 +149,19 @@ func mockDNSProfile() (dp *backendpb.DNSProfile) {
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,
+ DnsId: "mock1234",
+ FilteringEnabled: true,
+ QueryLogEnabled: true,
+ Deleted: false,
+ AutoDevicesEnabled: true,
+ IpLogEnabled: true,
SafeBrowsing: &backendpb.SafeBrowsingSettings{
Enabled: true,
BlockDangerousDomains: true,
diff --git a/scripts/make/go-fuzz.sh b/scripts/make/go-fuzz.sh
index 792c5af..8d9b03d 100644
--- a/scripts/make/go-fuzz.sh
+++ b/scripts/make/go-fuzz.sh
@@ -53,4 +53,17 @@ readonly go count_flags shuffle_flags timeout_flags fuzztime_flags
"$v_flags"\
"$fuzztime_flags"\
--fuzz="FuzzCloner_Clone"\
- ./internal/dnsmsg/;
+ ./internal/dnsmsg/\
+ ;
+
+"$go" test\
+ "$count_flags"\
+ "$shuffle_flags"\
+ "$race_flags"\
+ "$timeout_flags"\
+ "$x_flags"\
+ "$v_flags"\
+ "$fuzztime_flags"\
+ --fuzz="FuzzHumanIDParser_ParseNormalized"\
+ ./internal/agd/\
+ ;
diff --git a/scripts/make/go-gen.sh b/scripts/make/go-gen.sh
index 6955d44..4199983 100644
--- a/scripts/make/go-gen.sh
+++ b/scripts/make/go-gen.sh
@@ -49,11 +49,11 @@ readonly go
(
cd ./internal/backendpb/
protoc\
- --go-grpc_opt=Mbackend.proto=./backendpb\
+ --go-grpc_opt=Mdns.proto=./backendpb\
--go-grpc_opt=paths=source_relative\
--go-grpc_out=.\
- --go_opt=Mbackend.proto=./backendpb\
+ --go_opt=Mdns.proto=./backendpb\
--go_opt=paths=source_relative\
--go_out=.\
- ./backend.proto
+ ./dns.proto
)
diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh
index bbb8c90..595c008 100644
--- a/scripts/make/go-lint.sh
+++ b/scripts/make/go-lint.sh
@@ -167,36 +167,29 @@ git ls-files -- 'Makefile' '*.conf' '*.go' '*.mod' '*.sh' '*.yaml' '*.yml'\
run_linter nilness ./... "$dnssrvmod"
-# Do not use fieldalignment on $dnssrvmod, because ameshkov likes to place
-# struct fields in an order that he considers more readable.
+# TODO(a.garipov): Remove the grep crutch once golang/go#60509 is fixed.
#
-# TODO(a.garipov): Remove the loop once golang/go#60509, golang/go#61574 are
-# fixed.
-(
- run_linter fieldalignment ./main.go
- run_linter -e shadow --strict ./main.go
+# TODO(a.garipov): Add a filtering function to run_linter.
+fieldalignment_output="$( fieldalignment ./... "$dnssrvmod" 2>&1 | grep -e '\.pb\.go' -v || : )"
+readonly fieldalignment_output
- set +f
- for d in ./internal/*/ ./internal/*/*/ ./internal/*/*/*/
- do
- case "$d"
- in
- (*/testdata/*|\
- ./internal/dnsserver/*|\
- ./internal/backendpb/|\
- ./internal/profiledb/internal/filecachepb/|\
- ./internal/tools/)
- continue
- ;;
- (*)
- run_linter fieldalignment "$d"
- run_linter -e shadow --strict "$d"
- ;;
- esac
- done
-)
+if [ "$fieldalignment_output" != '' ]
+then
+ printf '%s\n' "$fieldalignment_output"
-run_linter -e shadow --strict "$dnssrvmod"
+ exit 1
+fi
+
+# TODO(a.garipov): Remove the grep crutch once golang/go#61574 is fixed.
+shadow_output="$( shadow --strict ./... "$dnssrvmod" 2>&1 | grep -e '\.pb\.go' -v || : )"
+readonly shadow_output
+
+if [ "$shadow_output" != '' ]
+then
+ printf '%s\n' "$shadow_output"
+
+ exit 1
+fi
run_linter gosec --quiet ./... "$dnssrvmod"