mirror of
https://github.com/AdguardTeam/AdGuardDNS.git
synced 2025-12-23 23:38:37 -05:00
Sync v2.15.0
This commit is contained in:
32
CHANGELOG.md
32
CHANGELOG.md
@@ -7,6 +7,38 @@ The format is **not** based on [Keep a Changelog][kec], since the project **does
|
||||
[kec]: https://keepachangelog.com/en/1.0.0/
|
||||
[sem]: https://semver.org/spec/v2.0.0.html
|
||||
|
||||
## AGDNS-3018 / Build 1033
|
||||
|
||||
- The environment variables `DNSCHECK_KV_TTL`, `DNSCHECK_KV_TYPE` have been added.
|
||||
|
||||
- The property `check.kv.ttl` has been removed. Use `DNSCHECK_KV_TTL` environment variable instead.
|
||||
|
||||
- The property `check.kv.type` has been removed. Use `DNSCHECK_KV_TYPE` environment variable instead.
|
||||
|
||||
- The environment variable `RATELIMIT_ALLOWLIST_TYPE` have been added.
|
||||
|
||||
- The property `ratelimit.allowlist.type` has been removed. Use `RATELIMIT_ALLOWLIST_TYPE` environment variable instead.
|
||||
|
||||
## AGDNS-2983 / Build 1020
|
||||
|
||||
- The environment variable `NODE_NAME` has been added.
|
||||
|
||||
- The property `check.node_name` has been removed. Use `NODE_NAME` environment variable instead.
|
||||
|
||||
## AGDNS-2864 / Build 1014
|
||||
|
||||
- The environment variables `CUSTOM_DOMAINS_API_KEY`, `CUSTOM_DOMAINS_CACHE_PATH`, `CUSTOM_DOMAINS_ENABLED`, `CUSTOM_DOMAINS_REFRESH_INTERVAL`, and `CUSTOM_DOMAINS_URL` have been added.
|
||||
|
||||
## AGDNS-2984 / Build 1013
|
||||
|
||||
- The environment variable `REDIS_ADDR` has been changed to `REDIS_HOST`.
|
||||
|
||||
- The default value of environment variable `REDIS_IDLE_TIMEOUT` has been changed from `30s` to `5m`.
|
||||
|
||||
- The default value of environment variable `REDIS_MAX_ACTIVE` has been changed from `10` to `100`.
|
||||
|
||||
- The default value of environment variable `REDIS_MAX_IDLE` has been changed from `3` to `100`.
|
||||
|
||||
## AGDNS-2864 / Build 1000
|
||||
|
||||
- The environment variables `SESSION_TICKET_API_KEY`, `SESSION_TICKET_CACHE_PATH`, `SESSION_TICKET_INDEX_NAME`, `SESSION_TICKET_REFRESH_INTERVAL`, `SESSION_TICKET_TYPE`, `SESSION_TICKET_URL` have been added.
|
||||
|
||||
2
Makefile
2
Makefile
@@ -24,7 +24,7 @@ BRANCH = $${BRANCH:-$$(git rev-parse --abbrev-ref HEAD)}
|
||||
GOAMD64 = v1
|
||||
GOPROXY = https://proxy.golang.org|direct
|
||||
GOTELEMETRY = off
|
||||
GOTOOLCHAIN = go1.24.3
|
||||
GOTOOLCHAIN = go1.24.5
|
||||
RACE = 0
|
||||
REVISION = $${REVISION:-$$(git rev-parse --short HEAD)}
|
||||
VERSION = 0
|
||||
|
||||
@@ -44,9 +44,6 @@ ratelimit:
|
||||
- '127.0.0.1/24'
|
||||
# Time between two updates of allow list.
|
||||
refresh_interval: 1h
|
||||
# Defines where the rate limiting settings are received from. Allowed
|
||||
# values are "backend" and "consul".
|
||||
type: 'consul'
|
||||
|
||||
# Configuration for the stream connection limiting.
|
||||
connection_limit:
|
||||
@@ -174,20 +171,11 @@ geoip:
|
||||
# DNS checking configuration.
|
||||
check:
|
||||
# Domains to use for DNS checking.
|
||||
kv:
|
||||
# Defines the type of remote key-value storage. Allowed values are
|
||||
# "backend", "cache", "consul", and "redis".
|
||||
type: 'cache'
|
||||
# For how long to keep the information about the client.
|
||||
ttl: 30s
|
||||
# Domains to use for DNS checking.
|
||||
domains:
|
||||
- dnscheck.adguard-dns.com
|
||||
- dnscheck.adguard.com
|
||||
# Location of this node.
|
||||
node_location: 'ams'
|
||||
# Name of this node.
|
||||
node_name: 'eu-1.dns.example.com'
|
||||
# IPs to respond with.
|
||||
ipv4:
|
||||
- 1.2.3.4
|
||||
|
||||
@@ -138,10 +138,6 @@ The `ratelimit` object has the following properties:
|
||||
|
||||
**Example:** `30s`.
|
||||
|
||||
- <a href="#ratelimit-allowlist-type" id="ratelimit-allowlist-type" name="ratelimit-allowlist-type">`type`</a>: Defines where the rate limit settings are received from. Allowed values are `backend` and `consul`.
|
||||
|
||||
**Example:** `consul`.
|
||||
|
||||
For example, if `backoff_period` is `1m`, `backoff_count` is `10`, `ipv4-count` is `5`, and `ipv4-interval` is `1s`, a client (meaning all IP addresses within the subnet defined by `ipv4-subnet_key_len`) that made 15 requests in one second or 6 requests (one above `rps`) every second for 10 seconds within one minute, the client is blocked for `backoff_duration`.
|
||||
|
||||
### <a href="#ratelimit-connection_limit" id="ratelimit-connection_limit" name="ratelimit-connection_limit">Stream connection limit</a>
|
||||
@@ -378,24 +374,6 @@ The `geoip` object has the following properties:
|
||||
|
||||
The `check` object has the following properties:
|
||||
|
||||
- <a href="#check_kv" id="check_kv" name="check_kv">`kv`</a>: Remote key-value storage settings. It has the following properties:
|
||||
|
||||
- <a href="#check-kv-type" id="check-kv-type" name="check-kv-type">`type`</a>: Type of the remote KV storage. Allowed values are `backend`, `cache`, `consul`, and `redis`.
|
||||
|
||||
**Example:** `consul`.
|
||||
|
||||
- <a href="#check-kv-ttl" id="check-kv-ttl" name="check-kv-ttl">`ttl`</a>: For how long to keep the information about a single user in remote KV, as a human-readable duration.
|
||||
|
||||
For `backend`, the TTL must be greater than `0s`.
|
||||
|
||||
For `cache`, the TTL is not used.
|
||||
|
||||
For `consul`, the TTL must be between `10s` and `1d`. Note that the actual TTL can be up to twice as long.
|
||||
|
||||
For `redis`, the TTL must be greater than or equal to `1ms`.
|
||||
|
||||
**Example:** `30s`.
|
||||
|
||||
- <a href="#check-domains" id="check-domains" name="check-domains">`domains`</a>: The domain suffixes to which random IDs are prepended using a hyphen.
|
||||
|
||||
**Property example:**
|
||||
@@ -410,10 +388,6 @@ The `check` object has the following properties:
|
||||
|
||||
**Example:** `ams`.
|
||||
|
||||
- <a href="#check-node_name" id="check-node_name" name="check-node_name">`node_name`</a>: The name of this server node.
|
||||
|
||||
**Example:** `eu-1.dns.example.com`.
|
||||
|
||||
- <a href="#check-ipv4" id="check-ipv4" name="check-ipv4">`ipv4` and `ipv6`</a>: Arrays of IPv4 or IPv6 addresses with which to respond to `A` and `AAAA` queries correspondingly. Generally, those should be the IP addresses of the AdGuard DNS [main HTTP API][http-dnscheck] for the DNS server check feature to work properly. In a development setup, that means the localhost addresses.
|
||||
|
||||
**Property examples:**
|
||||
|
||||
@@ -31,6 +31,7 @@ example.com. 17597 IN A 93.184.216.34
|
||||
;; ADDITIONAL SECTION:
|
||||
client-ip.adguard-dns.com. 10 CH TXT "127.0.0.1"
|
||||
server-ip.adguard-dns.com. 10 CH TXT "94.140.14.14"
|
||||
node-name.adguard-dns.com. 10 CH TXT "lon-1"
|
||||
resp.res-type.adguard-dns.com. 10 CH TXT "normal"
|
||||
|
||||
;; Query time: 26 msec
|
||||
@@ -59,6 +60,14 @@ In the `ADDITIONAL SECTION`, the following debug information is returned:
|
||||
server-ip.adguard-dns.com. 10 CH TXT "127.0.0.1"
|
||||
```
|
||||
|
||||
- <a href="#additional-node-name" id="additional-node-name" name="additional-node-name">`additional-node-name`</a>: The name of this server node. The full name is `node-name.adguard-dns.com`.
|
||||
|
||||
**Example:**
|
||||
|
||||
```none
|
||||
node-name.adguard-dns.com. 10 CH TXT "lon-1"
|
||||
```
|
||||
|
||||
- <a href="#additional-device-id" id="additional-device-id" name="additional-device-id">`device-id`</a>: The ID of the device as detected by the server, if any. The full name is `device-id.adguard-dns.com`.
|
||||
|
||||
**Example:**
|
||||
|
||||
@@ -103,16 +103,20 @@ Supported IDs:
|
||||
|
||||
- `allowlist`
|
||||
- `billstat`
|
||||
- `custom_domain_db`
|
||||
- `filters/hashprefix/adult_blocking`
|
||||
- `filters/hashprefix/newly_registered_domains`
|
||||
- `filters/hashprefix/safe_browsing`
|
||||
- `filters/storage`
|
||||
- `geoip`
|
||||
- `profiledb`
|
||||
- `profiledb_full`
|
||||
- `profiledb`
|
||||
- `rulestat`
|
||||
- `ticket_rotator`
|
||||
- `tlsconfig`
|
||||
- `websvc`
|
||||
|
||||
As well as IDs under `plugin/`, if any.
|
||||
|
||||
The special ID `*`, when used alone, causes all available refresh tasks to be performed. Note that it performs full profile DB refresh. Use with caution.
|
||||
|
||||
|
||||
@@ -16,7 +16,14 @@ AdGuard DNS uses [environment variables][wiki-env] to store some of the more sen
|
||||
- [`CONSUL_ALLOWLIST_URL`](#CONSUL_ALLOWLIST_URL)
|
||||
- [`CONSUL_DNSCHECK_KV_URL`](#CONSUL_DNSCHECK_KV_URL)
|
||||
- [`CONSUL_DNSCHECK_SESSION_URL`](#CONSUL_DNSCHECK_SESSION_URL)
|
||||
- [`CUSTOM_DOMAINS_API_KEY`](#CUSTOM_DOMAINS_API_KEY)
|
||||
- [`CUSTOM_DOMAINS_CACHE_PATH`](#CUSTOM_DOMAINS_CACHE_PATH)
|
||||
- [`CUSTOM_DOMAINS_ENABLED`](#CUSTOM_DOMAINS_ENABLED)
|
||||
- [`CUSTOM_DOMAINS_REFRESH_INTERVAL`](#CUSTOM_DOMAINS_REFRESH_INTERVAL)
|
||||
- [`CUSTOM_DOMAINS_URL`](#CUSTOM_DOMAINS_URL)
|
||||
- [`DNSCHECK_CACHE_KV_SIZE`](#DNSCHECK_CACHE_KV_SIZE)
|
||||
- [`DNSCHECK_KV_TTL`](#DNSCHECK_KV_TTL)
|
||||
- [`DNSCHECK_KV_TYPE`](#DNSCHECK_KV_TYPE)
|
||||
- [`DNSCHECK_REMOTEKV_API_KEY`](#DNSCHECK_REMOTEKV_API_KEY)
|
||||
- [`DNSCHECK_REMOTEKV_URL`](#DNSCHECK_REMOTEKV_URL)
|
||||
- [`FILTER_CACHE_PATH`](#FILTER_CACHE_PATH)
|
||||
@@ -32,16 +39,22 @@ AdGuard DNS uses [environment variables][wiki-env] to store some of the more sen
|
||||
- [`METRICS_NAMESPACE`](#METRICS_NAMESPACE)
|
||||
- [`NEW_REG_DOMAINS_ENABLED`](#NEW_REG_DOMAINS_ENABLED)
|
||||
- [`NEW_REG_DOMAINS_URL`](#NEW_REG_DOMAINS_URL)
|
||||
- [`NODE_NAME`](#NODE_NAME)
|
||||
- [`PROFILES_API_KEY`](#PROFILES_API_KEY)
|
||||
- [`PROFILES_CACHE_PATH`](#PROFILES_CACHE_PATH)
|
||||
- [`PROFILES_URL`](#PROFILES_URL)
|
||||
- [`REDIS_ADDR`](#REDIS_ADDR)
|
||||
- [`REDIS_DB`](#REDIS_DB)
|
||||
- [`REDIS_HOST`](#REDIS_HOST)
|
||||
- [`REDIS_KEY_PREFIX`](#REDIS_KEY_PREFIX)
|
||||
- [`REDIS_MAX_ACTIVE`](#REDIS_MAX_ACTIVE)
|
||||
- [`REDIS_MAX_CONN_LIFETIME`](#REDIS_MAX_CONN_LIFETIME)
|
||||
- [`REDIS_MAX_IDLE`](#REDIS_MAX_IDLE)
|
||||
- [`REDIS_NETWORK`](#REDIS_NETWORK)
|
||||
- [`REDIS_IDLE_TIMEOUT`](#REDIS_IDLE_TIMEOUT)
|
||||
- [`REDIS_PORT`](#REDIS_PORT)
|
||||
- [`REDIS_WAIT`](#REDIS_WAIT)
|
||||
- [`QUERYLOG_PATH`](#QUERYLOG_PATH)
|
||||
- [`RATELIMIT_ALLOWLIST_TYPE`](#RATELIMIT_ALLOWLIST_TYPE)
|
||||
- [`RULESTAT_URL`](#RULESTAT_URL)
|
||||
- [`SAFE_BROWSING_ENABLED`](#SAFE_BROWSING_ENABLED)
|
||||
- [`SAFE_BROWSING_URL`](#SAFE_BROWSING_URL)
|
||||
@@ -148,17 +161,59 @@ The HTTP(S) URL of the session API of the Consul instance used as a key-value da
|
||||
|
||||
**Default:** **Unset.**
|
||||
|
||||
**Example:** `http://localhost:8500/v1/session/create`
|
||||
## <a href="#CUSTOM_DOMAINS_API_KEY" id="CUSTOM_DOMAINS_API_KEY" name="CUSTOM_DOMAINS_API_KEY">`CUSTOM_DOMAINS_API_KEY`</a>
|
||||
|
||||
The API key to use when authenticating queries to the backend custom-domain API, if any. The API key should be valid as defined by [RFC 6750].
|
||||
|
||||
**Default:** No default value, the variable is required if `CUSTOM_DOMAINS_ENABLED` is set to `1`.
|
||||
|
||||
## <a href="#CUSTOM_DOMAINS_CACHE_PATH" id="CUSTOM_DOMAINS_CACHE_PATH" name="CUSTOM_DOMAINS_CACHE_PATH">`CUSTOM_DOMAINS_CACHE_PATH`</a>
|
||||
|
||||
The path to directory for storing the downloaded certificate and private-key data.
|
||||
|
||||
**Default:** No default value, a valid directory path is required if `CUSTOM_DOMAINS_ENABLED` is set to `1`.
|
||||
|
||||
## <a href="#CUSTOM_DOMAINS_ENABLED" id="CUSTOM_DOMAINS_ENABLED" name="CUSTOM_DOMAINS_ENABLED">`CUSTOM_DOMAINS_ENABLED`</a>
|
||||
|
||||
When set to `1`, enable the custom-domains feature. When set to `0`, disable it.
|
||||
|
||||
**Default:** `1`.
|
||||
|
||||
## <a href="#CUSTOM_DOMAINS_REFRESH_INTERVAL" id="CUSTOM_DOMAINS_REFRESH_INTERVAL" name="CUSTOM_DOMAINS_REFRESH_INTERVAL">`CUSTOM_DOMAINS_REFRESH_INTERVAL`</a>
|
||||
|
||||
The interval that defines how often to query the backend for the custom-domain data, as a human-readable duration.
|
||||
|
||||
**Default:** No default value, a positive value is required if `CUSTOM_DOMAINS_ENABLED` is set to `1`.
|
||||
|
||||
**Example:** `1m`
|
||||
|
||||
## <a href="#CUSTOM_DOMAINS_URL" id="CUSTOM_DOMAINS_URL" name="CUSTOM_DOMAINS_URL">`CUSTOM_DOMAINS_URL`</a>
|
||||
|
||||
The URL of the gRPC(S) API for the custom-domain data.
|
||||
|
||||
**Default:** No default value, the variable is required if `CUSTOM_DOMAINS_ENABLED` is set to `1`.
|
||||
|
||||
## <a href="#DNSCHECK_CACHE_KV_SIZE" id="DNSCHECK_CACHE_KV_SIZE" name="DNSCHECK_CACHE_KV_SIZE">`DNSCHECK_CACHE_KV_SIZE`</a>
|
||||
|
||||
The maximum number of the local cache key-value database entries for the DNS server checking.
|
||||
|
||||
**Default:** No default value, a positive value is required if the [type][conf-dnscheck-type] of the database is set to `cache`.
|
||||
**Default:** No default value, a positive value is required if `DNSCHECK_KV_TYPE` is set to `cache`.
|
||||
|
||||
**Example:** `1000`
|
||||
|
||||
[conf-dnscheck-type]: configuration.md#check-kv-type
|
||||
## <a href="#DNSCHECK_KV_TTL" id="DNSCHECK_KV_TTL" name="DNSCHECK_KV_TTL">`DNSCHECK_KV_TTL`</a>
|
||||
|
||||
For how long to keep the information about a single user in remote KV, as a human-readable duration.
|
||||
|
||||
**Default:** **Unset.**
|
||||
|
||||
**Example:** `1m`
|
||||
|
||||
## <a href="#DNSCHECK_KV_TYPE" id="DNSCHECK_KV_TYPE" name="DNSCHECK_KV_TYPE">`DNSCHECK_KV_TYPE`</a>
|
||||
|
||||
Type of the remote KV storage. Allowed values are `backend`, `cache`, `consul`, and `redis`.
|
||||
|
||||
**Default:** **Unset.**
|
||||
|
||||
## <a href="#DNSCHECK_REMOTEKV_API_KEY" id="DNSCHECK_REMOTEKV_API_KEY" name="DNSCHECK_REMOTEKV_API_KEY">`DNSCHECK_REMOTEKV_API_KEY`</a>
|
||||
|
||||
@@ -269,6 +324,15 @@ The HTTP(S) URL of source list of rules for newly registered domains safe browsi
|
||||
|
||||
**Default:** No default value, the variable is required if `NEW_REG_DOMAINS_ENABLED` is set to `1`.
|
||||
|
||||
## <a href="#NODE_NAME" id="NODE_NAME" name="NODE_NAME">`NODE_NAME`</a>
|
||||
|
||||
The name of this server node. Used in [debug DNS API][debug-dns-api] and [DNS checking][http-dnscheck].
|
||||
|
||||
[debug-dns-api]: debugdns.md#additional-node-name
|
||||
[http-dnscheck]: http.md#dnscheck-test
|
||||
|
||||
**Default:** No default value, the variable is **required.**
|
||||
|
||||
## <a href="#PROFILES_API_KEY" id="PROFILES_API_KEY" name="PROFILES_API_KEY">`PROFILES_API_KEY`</a>
|
||||
|
||||
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].
|
||||
@@ -313,13 +377,17 @@ The base backend URL for profiles API. Supports gRPC(S) (`grpc://` and `grpcs://
|
||||
|
||||
[ext-profiles]: externalhttp.md#backend-profiles
|
||||
|
||||
## <a href="#REDIS_ADDR" id="REDIS_ADDR" name="REDIS_ADDR">`REDIS_ADDR`</a>
|
||||
## <a href="#REDIS_DB" id="REDIS_DB" name="REDIS_DB">`REDIS_DB`</a>
|
||||
|
||||
The index of Redis database to use.
|
||||
|
||||
**Default:** `0`.
|
||||
|
||||
## <a href="#REDIS_HOST" id="REDIS_HOST" name="REDIS_HOST">`REDIS_HOST`</a>
|
||||
|
||||
Redis server address. Can be an IP address or a hostname.
|
||||
|
||||
**Default:** No default value, the variable is required if the [type][conf-check-kv-type] of remote KV storage for DNS server checking is `redis` in the configuration file.
|
||||
|
||||
[conf-check-kv-type]: configuration.md#check-kv-type
|
||||
**Default:** `localhost`, the variable is required if `DNSCHECK_KV_TYPE` is set to `redis`.
|
||||
|
||||
## <a href="#REDIS_KEY_PREFIX" id="REDIS_KEY_PREFIX" name="REDIS_KEY_PREFIX">`REDIS_KEY_PREFIX`</a>
|
||||
|
||||
@@ -331,19 +399,37 @@ The prefix for Redis keys.
|
||||
|
||||
The maximum number of active Redis connections.
|
||||
|
||||
**Default:** `10`.
|
||||
**Default:** `100`.
|
||||
|
||||
## <a href="#REDIS_MAX_CONN_LIFETIME" id="REDIS_MAX_CONN_LIFETIME" name="REDIS_MAX_CONN_LIFETIME">`REDIS_MAX_CONN_LIFETIME`</a>
|
||||
|
||||
The maximum total duration of connections in a pool.
|
||||
|
||||
**Default:** `0s`, which means that the lifetime is not limited.
|
||||
|
||||
## <a href="#REDIS_MAX_IDLE" id="REDIS_MAX_IDLE" name="REDIS_MAX_IDLE">`REDIS_MAX_IDLE`</a>
|
||||
|
||||
The maximum number of idle Redis connections.
|
||||
|
||||
**Default:** `3`.
|
||||
**Default:** `100`.
|
||||
|
||||
## <a href="#REDIS_NETWORK" id="REDIS_NETWORK" name="REDIS_NETWORK">`REDIS_NETWORK`</a>
|
||||
|
||||
Kind of IP protocol version to use:
|
||||
|
||||
- `ip` means both;
|
||||
- `ip4` means IPv4 only;
|
||||
- `ip6` means IPv6 only.
|
||||
|
||||
All other values are invalid.
|
||||
|
||||
**Default:** `ip4`.
|
||||
|
||||
## <a href="#REDIS_IDLE_TIMEOUT" id="REDIS_IDLE_TIMEOUT" name="REDIS_IDLE_TIMEOUT">`REDIS_IDLE_TIMEOUT`</a>
|
||||
|
||||
How long until idle Redis connections are closed, as a human-readable duration.
|
||||
|
||||
**Default:** `30s`.
|
||||
**Default:** `5m`.
|
||||
|
||||
## <a href="#REDIS_PORT" id="REDIS_PORT" name="REDIS_PORT">`REDIS_PORT`</a>
|
||||
|
||||
@@ -351,12 +437,26 @@ Redis server port.
|
||||
|
||||
**Default:** `6379`.
|
||||
|
||||
## <a href="#REDIS_WAIT" id="REDIS_WAIT" name="REDIS_WAIT">`REDIS_WAIT`</a>
|
||||
|
||||
It selects if the pool must wait for a connection once the `REDIS_MAX_ACTIVE` limit is reached.
|
||||
|
||||
**Default:** `1`, which means to wait.
|
||||
|
||||
## <a href="#QUERYLOG_PATH" id="QUERYLOG_PATH" name="QUERYLOG_PATH">`QUERYLOG_PATH`</a>
|
||||
|
||||
The path to the file into which the query log is going to be written.
|
||||
|
||||
**Default:** `./querylog.jsonl`.
|
||||
|
||||
## <a href="#RATELIMIT_ALLOWLIST_TYPE" id="RATELIMIT_ALLOWLIST_TYPE" name="RATELIMIT_ALLOWLIST_TYPE">`RATELIMIT_ALLOWLIST_TYPE`</a>
|
||||
|
||||
Defines where the rate limit settings are received from. Allowed values are `backend` and `consul`.
|
||||
|
||||
**Default:** **Unset.**
|
||||
|
||||
**Example:** `consul`.
|
||||
|
||||
## <a href="#RULESTAT_URL" id="RULESTAT_URL" name="RULESTAT_URL">`RULESTAT_URL`</a>
|
||||
|
||||
The HTTP(S) 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.
|
||||
|
||||
@@ -34,10 +34,10 @@ This service is disabled when all server groups have property [`profiles_enabled
|
||||
|
||||
This is the service to which the [`DNSCHECK_REMOTEKV_URL`][env-dnscheck_remotekv_url] environment variable points. Supports gRPC(s) URLs. The service must correspond to `./internal/backendpb/dns.proto`.
|
||||
|
||||
This service is only enabled when the `check.kv` object has the [`type`][conf-check-kv-type] property set to `backend`.
|
||||
This service is only enabled when the [`DNSCHECK_KV_TYPE`][env-dnscheck_kv_type] environment variable is set to `backend`.
|
||||
|
||||
[env-dnscheck_remotekv_url]: environment.md#DNSCHECK_REMOTEKV_URL
|
||||
[conf-check-kv-type]: configuration.md#check-kv-type
|
||||
[env-dnscheck_kv_type]: environment.md#DNSCHECK_KV_TYPE
|
||||
|
||||
## <a href="#backend-profiles" id="backend-profiles" name="backend-profiles">Backend profiles service</a>
|
||||
|
||||
|
||||
64
go.mod
64
go.mod
@@ -1,17 +1,18 @@
|
||||
module github.com/AdguardTeam/AdGuardDNS
|
||||
|
||||
go 1.24.3
|
||||
go 1.24.5
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-20240607112746-5690301129fe
|
||||
github.com/AdguardTeam/golibs v0.32.11
|
||||
// NOTE: Do not change the pseudoversion.
|
||||
github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-00010101000000-000000000000
|
||||
github.com/AdguardTeam/golibs v0.32.15
|
||||
github.com/AdguardTeam/urlfilter v0.20.0
|
||||
github.com/ameshkov/dnscrypt/v2 v2.4.0
|
||||
github.com/axiomhq/hyperloglog v0.2.5
|
||||
github.com/bluele/gcache v0.0.2
|
||||
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500
|
||||
github.com/caarlos0/env/v7 v7.1.0
|
||||
github.com/getsentry/sentry-go v0.33.0
|
||||
github.com/getsentry/sentry-go v0.34.0
|
||||
github.com/gomodule/redigo v1.9.2
|
||||
github.com/google/renameio/v2 v2.0.0
|
||||
github.com/miekg/dns v1.1.66
|
||||
@@ -22,25 +23,26 @@ require (
|
||||
github.com/prometheus/common v0.64.0
|
||||
github.com/quic-go/quic-go v0.52.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/crypto v0.38.0
|
||||
golang.org/x/net v0.40.0
|
||||
golang.org/x/sys v0.33.0
|
||||
golang.org/x/time v0.11.0
|
||||
google.golang.org/grpc v1.72.2
|
||||
golang.org/x/crypto v0.39.0
|
||||
golang.org/x/net v0.41.0
|
||||
golang.org/x/sys v0.34.0
|
||||
golang.org/x/time v0.12.0
|
||||
google.golang.org/grpc v1.73.0
|
||||
google.golang.org/protobuf v1.36.6
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.121.2 // indirect
|
||||
cloud.google.com/go/ai v0.12.0 // indirect
|
||||
cloud.google.com/go/auth v0.16.1 // indirect
|
||||
cloud.google.com/go v0.121.3 // indirect
|
||||
cloud.google.com/go/ai v0.12.1 // indirect
|
||||
cloud.google.com/go/auth v0.16.2 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.7 // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/ameshkov/dnsstamps v1.0.3 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/caarlos0/env/v11 v11.3.1 // indirect
|
||||
github.com/ccojocar/zxcvbn-go v1.0.4 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
@@ -53,7 +55,7 @@ require (
|
||||
github.com/golangci/misspell v0.7.0 // indirect
|
||||
github.com/google/generative-ai-go v0.20.1 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a // indirect
|
||||
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
@@ -71,36 +73,36 @@ require (
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/securego/gosec/v2 v2.22.4 // indirect
|
||||
github.com/securego/gosec/v2 v2.22.5 // indirect
|
||||
github.com/uudashr/gocognit v1.2.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.36.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
|
||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
go.uber.org/mock v0.5.2 // indirect
|
||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20250531010427-b6e5de432a8b // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||
golang.org/x/mod v0.26.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20250603144755-9a9ac2102d0e // indirect
|
||||
golang.org/x/term v0.32.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b // indirect
|
||||
golang.org/x/term v0.33.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
golang.org/x/vuln v1.1.4 // indirect
|
||||
google.golang.org/api v0.236.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/api v0.241.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
honnef.co/go/tools v0.6.1 // indirect
|
||||
mvdan.cc/editorconfig v0.3.0 // indirect
|
||||
mvdan.cc/gofumpt v0.8.0 // indirect
|
||||
mvdan.cc/sh/v3 v3.11.0 // indirect
|
||||
mvdan.cc/sh/v3 v3.12.0 // indirect
|
||||
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 // indirect
|
||||
)
|
||||
|
||||
|
||||
126
go.sum
126
go.sum
@@ -1,17 +1,17 @@
|
||||
cloud.google.com/go v0.121.2 h1:v2qQpN6Dx9x2NmwrqlesOt3Ys4ol5/lFZ6Mg1B7OJCg=
|
||||
cloud.google.com/go v0.121.2/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw=
|
||||
cloud.google.com/go/ai v0.12.0 h1:i9k0U14BhejPY+yKTm9VTCjRAA3PwYvf4s/zhSkHof0=
|
||||
cloud.google.com/go/ai v0.12.0/go.mod h1:SEbNRRerz779yMT0qjDYG245m96WO8Flieiv+/fU9GQ=
|
||||
cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
|
||||
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
|
||||
cloud.google.com/go v0.121.3 h1:84RD+hQXNdY5Sw/MWVAx5O9Aui/rd5VQ9HEcdN19afo=
|
||||
cloud.google.com/go v0.121.3/go.mod h1:6vWF3nJWRrEUv26mMB3FEIU/o1MQNVPG1iHdisa2SJc=
|
||||
cloud.google.com/go/ai v0.12.1 h1:m1n/VjUuHS+pEO/2R4/VbuuEIkgk0w67fDQvFaMngM0=
|
||||
cloud.google.com/go/ai v0.12.1/go.mod h1:5vIPNe1ZQsVZqCliXIPL4QnhObQQY4d9hAGHdVc4iw4=
|
||||
cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
|
||||
cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
|
||||
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
|
||||
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
|
||||
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
|
||||
github.com/AdguardTeam/golibs v0.32.11 h1:75EquS8SWvzsM3JFJY0359ZBw66jDjAegteHzh9nSw8=
|
||||
github.com/AdguardTeam/golibs v0.32.11/go.mod h1:LXr0gqqZuVpt+L+bP3Nnr0/CecLmm3rxkdgyyW5JXXM=
|
||||
github.com/AdguardTeam/golibs v0.32.15 h1:arDRDWiZCH3g5Onr8AqMnOHhaOppNoBpgC3DNhmeDeA=
|
||||
github.com/AdguardTeam/golibs v0.32.15/go.mod h1:G9CzUOzx87J+2u+eClJrrwWD7lMbROvuUnT8uvDUzIA=
|
||||
github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs=
|
||||
github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
@@ -28,6 +28,8 @@ github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
||||
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 h1:6lhrsTEnloDPXyeZBvSYvQf8u86jbKehZPVDDlkgDl4=
|
||||
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
|
||||
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
|
||||
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
|
||||
github.com/caarlos0/env/v7 v7.1.0 h1:9lzTF5amyQeWHZzuZeKlCb5FWSUxpG1js43mhbY8ozg=
|
||||
github.com/caarlos0/env/v7 v7.1.0/go.mod h1:LPPWniDUq4JaO6Q41vtlyikhMknqymCLBw0eX4dcH1E=
|
||||
github.com/ccojocar/zxcvbn-go v1.0.4 h1:FWnCIRMXPj43ukfX000kvBZvV6raSxakYr1nzyNrUcc=
|
||||
@@ -42,8 +44,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
|
||||
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
|
||||
github.com/getsentry/sentry-go v0.33.0 h1:YWyDii0KGVov3xOaamOnF0mjOrqSjBqwv48UEzn7QFg=
|
||||
github.com/getsentry/sentry-go v0.33.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
|
||||
github.com/getsentry/sentry-go v0.34.0 h1:1FCHBVp8TfSc8L10zqSwXUZNiOSF+10qw4czjarTiY4=
|
||||
github.com/getsentry/sentry-go v0.34.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
@@ -70,8 +72,8 @@ github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4=
|
||||
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
|
||||
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18=
|
||||
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
|
||||
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
|
||||
@@ -144,8 +146,8 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/securego/gosec/v2 v2.22.4 h1:21VdNGcKicFSv6rUDBc0cEtEl7lWyCKZxKIm0iwvrIM=
|
||||
github.com/securego/gosec/v2 v2.22.4/go.mod h1:ww5Yie7KJ3AH8XZQTletkW5zOmIse6FACs/Ys8VR3qE=
|
||||
github.com/securego/gosec/v2 v2.22.5 h1:ySws9uwOeE42DsG54v2moaJfh7r08Ev7SAYJuoMDfRA=
|
||||
github.com/securego/gosec/v2 v2.22.5/go.mod h1:AWfgrFsVewk5LKobsPWlygCHt8K91boVPyL6GUZG5NY=
|
||||
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=
|
||||
@@ -167,20 +169,20 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 h1:rbRJ8BBoVMsQShESYZ0FkvcITu8X8QNwJogcLUmDNNw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0/go.mod h1:ru6KHrNtNHxM4nD/vd6QrLVWgKhxPYgblq4VAtNawTQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
@@ -189,64 +191,64 @@ go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b h1:QoALfVG9rhQ/M7vYDScfPdWjGL9dlsVVM5VGh7aKoAA=
|
||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
||||
golang.org/x/exp/typeparams v0.0.0-20250531010427-b6e5de432a8b h1:BYXmVbbiQZNvDQnJIC37pAGLxabO8CGWgWEZrCtjXbk=
|
||||
golang.org/x/exp/typeparams v0.0.0-20250531010427-b6e5de432a8b/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||
golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b h1:KdrhdYPDUvJTvrDK9gdjfFd6JTk8vA1WJoldYSi0kHo=
|
||||
golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
|
||||
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20250603144755-9a9ac2102d0e h1:Rux3cpb+5sgvNBpSMHqlgFcZUZnkNuo6WDW6Z/zcAus=
|
||||
golang.org/x/telemetry v0.0.0-20250603144755-9a9ac2102d0e/go.mod h1:QNvpSH4vItB4zw8JazOv6Ba3fs1TorwPx9cCU6qTIdE=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ=
|
||||
golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
|
||||
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
|
||||
golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.236.0 h1:CAiEiDVtO4D/Qja2IA9VzlFrgPnK3XVMmRoJZlSWbc0=
|
||||
google.golang.org/api v0.236.0/go.mod h1:X1WF9CU2oTc+Jml1tiIxGmWFK/UZezdqEu09gcxZAj4=
|
||||
google.golang.org/api v0.241.0 h1:QKwqWQlkc6O895LchPEDUSYr22Xp3NCxpQRiWTB6avE=
|
||||
google.golang.org/api v0.241.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
|
||||
google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
|
||||
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
@@ -264,7 +266,7 @@ mvdan.cc/editorconfig v0.3.0 h1:D1D2wLYEYGpawWT5SpM5pRivgEgXjtEXwC9MWhEY0gQ=
|
||||
mvdan.cc/editorconfig v0.3.0/go.mod h1:NcJHuDtNOTEJ6251indKiWuzK6+VcrMuLzGMLKBFupQ=
|
||||
mvdan.cc/gofumpt v0.8.0 h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k=
|
||||
mvdan.cc/gofumpt v0.8.0/go.mod h1:vEYnSzyGPmjvFkqJWtXkh79UwPWP9/HMxQdGEXZHjpg=
|
||||
mvdan.cc/sh/v3 v3.11.0 h1:q5h+XMDRfUGUedCqFFsjoFjrhwf2Mvtt1rkMvVz0blw=
|
||||
mvdan.cc/sh/v3 v3.11.0/go.mod h1:LRM+1NjoYCzuq/WZ6y44x14YNAI0NK7FLPeQSaFagGg=
|
||||
mvdan.cc/sh/v3 v3.12.0 h1:ejKUR7ONP5bb+UGHGEG/k9V5+pRVIyD+LsZz7o8KHrI=
|
||||
mvdan.cc/sh/v3 v3.12.0/go.mod h1:Se6Cj17eYSn+sNooLZiEUnNNmNxg0imoYlTu4CyaGyg=
|
||||
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 h1:WjUu4yQoT5BHT1w8Zu56SP8367OuBV5jvo+4Ulppyf8=
|
||||
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4/go.mod h1:rthT7OuvRbaGcd5ginj6dA2oLE7YNlta9qhBNNdCaLE=
|
||||
|
||||
509
go.work.sum
509
go.work.sum
File diff suppressed because it is too large
Load Diff
@@ -11,8 +11,7 @@ import (
|
||||
|
||||
// Profile is the profile access manager interface.
|
||||
type Profile interface {
|
||||
// Config returns the profile access configuration, excluding the
|
||||
// [ProfileConfig.Metrics] property.
|
||||
// Config returns the profile access configuration.
|
||||
Config() (conf *ProfileConfig)
|
||||
|
||||
// IsBlocked returns true if the req should be blocked. req must not be
|
||||
@@ -51,10 +50,6 @@ func (EmptyProfile) IsBlocked(
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
type ProfileConfig struct {
|
||||
// Metrics is used for the collection of the profile access engine
|
||||
// statistics. It must not be nil.
|
||||
Metrics ProfileMetrics
|
||||
|
||||
// AllowedNets is slice of CIDRs to be allowed.
|
||||
AllowedNets []netip.Prefix
|
||||
|
||||
@@ -87,24 +82,35 @@ type DefaultProfile struct {
|
||||
blocklistDomainRules []string
|
||||
}
|
||||
|
||||
// NewDefaultProfile creates a new *DefaultProfile. conf is assumed to be
|
||||
// defaultProfileConfig is the configuration for the default access for
|
||||
// profiles.
|
||||
type defaultProfileConfig struct {
|
||||
// conf is the configuration to use for the access manager. It must not be
|
||||
// nil and must be valid.
|
||||
conf *ProfileConfig
|
||||
|
||||
// metrics is used for the collection of the profile access engine
|
||||
// statistics. It must not be nil.
|
||||
metrics ProfileMetrics
|
||||
}
|
||||
|
||||
// newDefaultProfile creates a new *DefaultProfile. conf is assumed to be
|
||||
// valid. mtrc must not be nil.
|
||||
func NewDefaultProfile(conf *ProfileConfig) (p *DefaultProfile) {
|
||||
func newDefaultProfile(c *defaultProfileConfig) (p *DefaultProfile) {
|
||||
return &DefaultProfile{
|
||||
allowedNets: conf.AllowedNets,
|
||||
blockedNets: conf.BlockedNets,
|
||||
allowedASN: conf.AllowedASN,
|
||||
blockedASN: conf.BlockedASN,
|
||||
blocklistDomainRules: conf.BlocklistDomainRules,
|
||||
blockedHostsEng: newBlockedHostEngine(conf.Metrics, conf.BlocklistDomainRules),
|
||||
allowedNets: c.conf.AllowedNets,
|
||||
blockedNets: c.conf.BlockedNets,
|
||||
allowedASN: c.conf.AllowedASN,
|
||||
blockedASN: c.conf.BlockedASN,
|
||||
blocklistDomainRules: c.conf.BlocklistDomainRules,
|
||||
blockedHostsEng: newBlockedHostEngine(c.metrics, c.conf.BlocklistDomainRules),
|
||||
}
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ Profile = (*DefaultProfile)(nil)
|
||||
|
||||
// Config implements the [Profile] interface for *DefaultProfile. It excludes
|
||||
// the Metrics property.
|
||||
// Config implements the [Profile] interface for *DefaultProfile.
|
||||
func (p *DefaultProfile) Config() (conf *ProfileConfig) {
|
||||
return &ProfileConfig{
|
||||
AllowedNets: slices.Clone(p.allowedNets),
|
||||
@@ -157,3 +163,28 @@ func matchASNs(asns []geoip.ASN, l *geoip.Location) (ok bool) {
|
||||
func (p *DefaultProfile) isBlockedByHostsEng(ctx context.Context, req *dns.Msg) (blocked bool) {
|
||||
return p.blockedHostsEng.isBlocked(ctx, req)
|
||||
}
|
||||
|
||||
// ProfileConstructor creates default access managers for profiles.
|
||||
//
|
||||
// TODO(a.garipov): Add global standard rules for profile access managers here
|
||||
// as well.
|
||||
type ProfileConstructor struct {
|
||||
metrics ProfileMetrics
|
||||
}
|
||||
|
||||
// NewProfileConstructor returns a properly initialized *ProfileConstructor.
|
||||
// mtrc must not be nil.
|
||||
func NewProfileConstructor(mtrc ProfileMetrics) (c *ProfileConstructor) {
|
||||
return &ProfileConstructor{
|
||||
metrics: mtrc,
|
||||
}
|
||||
}
|
||||
|
||||
// New creates a new access manager for a profile based on the configuration.
|
||||
// conf must not be nil and must be valid.
|
||||
func (c *ProfileConstructor) New(conf *ProfileConfig) (p *DefaultProfile) {
|
||||
return newDefaultProfile(&defaultProfileConfig{
|
||||
conf: conf,
|
||||
metrics: c.metrics,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
|
||||
func TestDefaultProfile_Config(t *testing.T) {
|
||||
conf := &access.ProfileConfig{
|
||||
Metrics: testAccessMtrc,
|
||||
AllowedNets: []netip.Prefix{netip.MustParsePrefix("1.1.1.0/24")},
|
||||
BlockedNets: []netip.Prefix{netip.MustParsePrefix("2.2.2.0/24")},
|
||||
AllowedASN: []geoip.ASN{1},
|
||||
@@ -22,7 +21,8 @@ func TestDefaultProfile_Config(t *testing.T) {
|
||||
BlocklistDomainRules: []string{"block.test"},
|
||||
}
|
||||
|
||||
a := access.NewDefaultProfile(conf)
|
||||
cons := access.NewProfileConstructor(testAccessMtrc)
|
||||
a := cons.New(conf)
|
||||
got := a.Config()
|
||||
assert.Equal(t, conf.AllowedNets, got.AllowedNets)
|
||||
assert.Equal(t, conf.BlockedNets, got.BlockedNets)
|
||||
@@ -35,7 +35,6 @@ func TestDefaultProfile_IsBlocked(t *testing.T) {
|
||||
passAddrPort := netip.MustParseAddrPort("3.3.3.3:3333")
|
||||
|
||||
conf := &access.ProfileConfig{
|
||||
Metrics: testAccessMtrc,
|
||||
AllowedNets: []netip.Prefix{netip.MustParsePrefix("1.1.1.1/32")},
|
||||
BlockedNets: []netip.Prefix{netip.MustParsePrefix("1.1.1.0/24")},
|
||||
AllowedASN: []geoip.ASN{1},
|
||||
@@ -49,7 +48,8 @@ func TestDefaultProfile_IsBlocked(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
a := access.NewDefaultProfile(conf)
|
||||
cons := access.NewProfileConstructor(testAccessMtrc)
|
||||
a := cons.New(conf)
|
||||
|
||||
testCases := []struct {
|
||||
loc *geoip.Location
|
||||
@@ -171,7 +171,6 @@ func TestDefaultProfile_IsBlocked(t *testing.T) {
|
||||
|
||||
func TestDefaultProfile_IsBlocked_prefixAllowlist(t *testing.T) {
|
||||
conf := &access.ProfileConfig{
|
||||
Metrics: testAccessMtrc,
|
||||
AllowedNets: []netip.Prefix{
|
||||
netip.MustParsePrefix("2.2.2.0/24"),
|
||||
netip.MustParsePrefix("3.3.0.0/16"),
|
||||
@@ -182,7 +181,8 @@ func TestDefaultProfile_IsBlocked_prefixAllowlist(t *testing.T) {
|
||||
BlocklistDomainRules: nil,
|
||||
}
|
||||
|
||||
a := access.NewDefaultProfile(conf)
|
||||
cons := access.NewProfileConstructor(testAccessMtrc)
|
||||
a := cons.New(conf)
|
||||
|
||||
testCases := []struct {
|
||||
want assert.BoolAssertionFunc
|
||||
@@ -225,7 +225,6 @@ func BenchmarkDefaultProfile_IsBlocked(b *testing.B) {
|
||||
passAddrPort := netip.MustParseAddrPort("3.3.3.3:3333")
|
||||
|
||||
conf := &access.ProfileConfig{
|
||||
Metrics: testAccessMtrc,
|
||||
AllowedNets: []netip.Prefix{netip.MustParsePrefix("1.1.1.1/32")},
|
||||
BlockedNets: []netip.Prefix{netip.MustParsePrefix("1.1.1.0/24")},
|
||||
AllowedASN: []geoip.ASN{1},
|
||||
@@ -239,7 +238,8 @@ func BenchmarkDefaultProfile_IsBlocked(b *testing.B) {
|
||||
},
|
||||
}
|
||||
|
||||
a := access.NewDefaultProfile(conf)
|
||||
cons := access.NewProfileConstructor(testAccessMtrc)
|
||||
a := cons.New(conf)
|
||||
|
||||
ctx := testutil.ContextWithTimeout(b, testTimeout)
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ type CustomDomainStateCurrent struct {
|
||||
|
||||
// CertName is the unique name for fetching the actual certificate data. If
|
||||
// [CustomDomainStateCurrent.Enabled] is true, it must not be empty.
|
||||
//
|
||||
// TODO(a.garipov): Make a newtype.
|
||||
CertName string
|
||||
|
||||
// Enabled shows if this certificate is enabled.
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdrand"
|
||||
"github.com/AdguardTeam/golibs/mathutil/randutil"
|
||||
)
|
||||
|
||||
// RequestIDLen is the length of a [RequestID] in bytes. A RequestID is
|
||||
@@ -19,7 +19,7 @@ type RequestID [RequestIDLen]byte
|
||||
// requestIDRand is used to create [RequestID]s.
|
||||
//
|
||||
// TODO(a.garipov): Consider making a struct instead of using one global source.
|
||||
var requestIDRand = agdrand.NewReader(agdrand.MustNewSeed())
|
||||
var requestIDRand = randutil.NewReader(randutil.MustNewSeed())
|
||||
|
||||
// NewRequestID returns a new pseudorandom RequestID. Prefer this to manual
|
||||
// conversion from other string types.
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
// Package agdrand contains utilities for random numbers.
|
||||
//
|
||||
// TODO(a.garipov): Move to golibs.
|
||||
package agdrand
|
||||
|
||||
import (
|
||||
cryptorand "crypto/rand"
|
||||
"math/rand/v2"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Reader is a ChaCha8-based cryptographically strong random number reader.
|
||||
// It's safe for concurrent use.
|
||||
type Reader struct {
|
||||
// mu protects reader.
|
||||
mu *sync.Mutex
|
||||
|
||||
reader *rand.ChaCha8
|
||||
}
|
||||
|
||||
// NewReader returns a new properly initialized *Reader seeded with the given
|
||||
// seed.
|
||||
func NewReader(seed [32]byte) (r *Reader) {
|
||||
return &Reader{
|
||||
mu: &sync.Mutex{},
|
||||
reader: rand.NewChaCha8(seed),
|
||||
}
|
||||
}
|
||||
|
||||
// Read generates len(p) random bytes and writes them into p. It always returns
|
||||
// len(p) and a nil error. It's safe for concurrent use.
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
return r.reader.Read(p)
|
||||
}
|
||||
|
||||
// LockedSource is an implementation of [rand.Source] that is concurrency-safe.
|
||||
type LockedSource struct {
|
||||
// mu protects src.
|
||||
mu *sync.Mutex
|
||||
|
||||
src rand.Source
|
||||
}
|
||||
|
||||
// NewLockedSource returns new properly initialized *LockedSource.
|
||||
func NewLockedSource(src rand.Source) (s *LockedSource) {
|
||||
return &LockedSource{
|
||||
mu: &sync.Mutex{},
|
||||
src: src,
|
||||
}
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ rand.Source = (*LockedSource)(nil)
|
||||
|
||||
// Uint64 implements the [rand.Source] interface for *LockedSource.
|
||||
func (s *LockedSource) Uint64() (r uint64) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return s.src.Uint64()
|
||||
}
|
||||
|
||||
// MustNewSeed returns new 32 byte seed for pseudorandom generators. Panics on
|
||||
// errors.
|
||||
func MustNewSeed() (seed [32]byte) {
|
||||
_, err := cryptorand.Read(seed[:])
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return seed
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package agdrand_test
|
||||
|
||||
import (
|
||||
"math/rand/v2"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdrand"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// routinesLimit is the number of goroutines for tests.
|
||||
const routinesLimit = 512
|
||||
|
||||
func TestReader_race(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const length = 128
|
||||
|
||||
reader := agdrand.NewReader(agdrand.MustNewSeed())
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(routinesLimit)
|
||||
|
||||
startCh := make(chan struct{})
|
||||
for range routinesLimit {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
<-startCh
|
||||
for range 1_000 {
|
||||
buf := make([]byte, length)
|
||||
_, _ = reader.Read(buf)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
close(startCh)
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestLockedSource_race(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
src := agdrand.NewLockedSource(rand.NewPCG(0, 0))
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(routinesLimit)
|
||||
|
||||
startCh := make(chan struct{})
|
||||
for range routinesLimit {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
<-startCh
|
||||
for range 1_000 {
|
||||
_ = src.Uint64()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
close(startCh)
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// testSeed is a seed for tests.
|
||||
var testSeed = [32]byte{}
|
||||
|
||||
func BenchmarkReader_Read(b *testing.B) {
|
||||
const length = 16
|
||||
|
||||
reader := agdrand.NewReader(testSeed)
|
||||
|
||||
var n int
|
||||
var err error
|
||||
|
||||
b.ReportAllocs()
|
||||
buf := make([]byte, length)
|
||||
for b.Loop() {
|
||||
n, err = reader.Read(buf)
|
||||
}
|
||||
|
||||
require.Equal(b, length, n)
|
||||
require.NoError(b, err)
|
||||
|
||||
// Most recent results:
|
||||
//
|
||||
// goos: darwin
|
||||
// goarch: amd64
|
||||
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/agdrand
|
||||
// cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
|
||||
// BenchmarkReader_Read-12 38364720 28.48 ns/op 0 B/op 0 allocs/op
|
||||
}
|
||||
|
||||
func BenchmarkLockedSource_Uint64(b *testing.B) {
|
||||
src := agdrand.NewLockedSource(rand.NewChaCha8(testSeed))
|
||||
|
||||
b.ReportAllocs()
|
||||
for range b.N {
|
||||
_ = src.Uint64()
|
||||
}
|
||||
|
||||
// Most recent results:
|
||||
//
|
||||
// goos: darwin
|
||||
// goarch: amd64
|
||||
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/agdrand
|
||||
// cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
|
||||
// BenchmarkLockedSource_Uint64-12 59585797 18.13 ns/op 0 B/op 0 allocs/op
|
||||
}
|
||||
47
internal/agdtime/schedule.go
Normal file
47
internal/agdtime/schedule.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package agdtime
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/timeutil"
|
||||
)
|
||||
|
||||
// ExponentialSchedule is a [timeutil.Schedule] that exponentially increases the
|
||||
// time until the next event until it reaches the maximum.
|
||||
//
|
||||
// TODO(a.garipov): Consider moving to golibs.
|
||||
type ExponentialSchedule struct {
|
||||
current time.Duration
|
||||
max time.Duration
|
||||
base uint64
|
||||
}
|
||||
|
||||
// NewExponentialSchedule returns a new properly initialized
|
||||
// *ExponentialSchedule.
|
||||
func NewExponentialSchedule(initial, max time.Duration, base uint64) (s *ExponentialSchedule) {
|
||||
return &ExponentialSchedule{
|
||||
current: initial,
|
||||
max: max,
|
||||
base: base,
|
||||
}
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ timeutil.Schedule = (*ExponentialSchedule)(nil)
|
||||
|
||||
// UntilNext implements the [timeutil.Schedule] interface for
|
||||
// *ExponentialSchedule.
|
||||
func (s *ExponentialSchedule) UntilNext(_ time.Time) (d time.Duration) {
|
||||
d = s.current
|
||||
|
||||
// A negative s.current means that the previous call has overflown
|
||||
// time.Duration, which means it's above max.
|
||||
if d >= s.max || d < 0 {
|
||||
return s.max
|
||||
}
|
||||
|
||||
// #nosec G115 -- The overflow is processed above.
|
||||
s.current = s.current * time.Duration(s.base)
|
||||
|
||||
return d
|
||||
}
|
||||
28
internal/agdtime/schedule_example_test.go
Normal file
28
internal/agdtime/schedule_example_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package agdtime_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
|
||||
)
|
||||
|
||||
func ExampleExponentialSchedule() {
|
||||
s := agdtime.NewExponentialSchedule(1*time.Second, 1*time.Minute, 2)
|
||||
|
||||
for range 10 {
|
||||
fmt.Println(s.UntilNext(time.Time{}))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1s
|
||||
// 2s
|
||||
// 4s
|
||||
// 8s
|
||||
// 16s
|
||||
// 32s
|
||||
// 1m0s
|
||||
// 1m0s
|
||||
// 1m0s
|
||||
// 1m0s
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/access"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/c2h5oh/datasize"
|
||||
@@ -44,6 +45,9 @@ var (
|
||||
TestPendingExpire = time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
)
|
||||
|
||||
// TestRespSzEst is a response-size estimate for tests.
|
||||
const TestRespSzEst datasize.ByteSize = 1 * datasize.KB
|
||||
|
||||
// TestBind includes any IPv4 address.
|
||||
//
|
||||
// TODO(a.garipov): Add to golibs/netutil.
|
||||
@@ -52,5 +56,6 @@ var TestBind = netip.MustParsePrefix("0.0.0.0/0")
|
||||
// TestLogger is the common logger for tests.
|
||||
var TestLogger = slogutil.NewDiscardLogger()
|
||||
|
||||
// TestRespSzEst is a response-size estimate for tests.
|
||||
const TestRespSzEst datasize.ByteSize = 1 * datasize.KB
|
||||
// TestProfileAccessConstructor is the common constructor of profile access
|
||||
// managers for tests
|
||||
var TestProfileAccessConstructor = access.NewProfileConstructor(access.EmptyProfileMetrics{})
|
||||
|
||||
@@ -15,8 +15,6 @@ import (
|
||||
// [tlsconfig.CustomDomainStorage] interface that uses the business-logic
|
||||
// backend as the custom-domain certificate storage. It is safe for concurrent
|
||||
// use.
|
||||
//
|
||||
// TODO(a.garipov): Use.
|
||||
type CustomDomainStorage struct {
|
||||
logger *slog.Logger
|
||||
client CustomDomainServiceClient
|
||||
@@ -100,7 +98,5 @@ func (s *CustomDomainStorage) CertificateData(
|
||||
)
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Consider validating certificate and private-key date.
|
||||
|
||||
return resp.Certificate, resp.PrivateKey, nil
|
||||
}
|
||||
|
||||
@@ -2044,6 +2044,50 @@ func (x *AuthenticationFailedError) GetMessage() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type NotFoundError struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *NotFoundError) Reset() {
|
||||
*x = NotFoundError{}
|
||||
mi := &file_dns_proto_msgTypes[30]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *NotFoundError) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NotFoundError) ProtoMessage() {}
|
||||
|
||||
func (x *NotFoundError) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[30]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use NotFoundError.ProtoReflect.Descriptor instead.
|
||||
func (*NotFoundError) Descriptor() ([]byte, []int) {
|
||||
return file_dns_proto_rawDescGZIP(), []int{30}
|
||||
}
|
||||
|
||||
func (x *NotFoundError) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type RateLimitSettings struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||
@@ -2055,7 +2099,7 @@ type RateLimitSettings struct {
|
||||
|
||||
func (x *RateLimitSettings) Reset() {
|
||||
*x = RateLimitSettings{}
|
||||
mi := &file_dns_proto_msgTypes[30]
|
||||
mi := &file_dns_proto_msgTypes[31]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2067,7 +2111,7 @@ func (x *RateLimitSettings) String() string {
|
||||
func (*RateLimitSettings) ProtoMessage() {}
|
||||
|
||||
func (x *RateLimitSettings) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[30]
|
||||
mi := &file_dns_proto_msgTypes[31]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2080,7 +2124,7 @@ func (x *RateLimitSettings) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RateLimitSettings.ProtoReflect.Descriptor instead.
|
||||
func (*RateLimitSettings) Descriptor() ([]byte, []int) {
|
||||
return file_dns_proto_rawDescGZIP(), []int{30}
|
||||
return file_dns_proto_rawDescGZIP(), []int{31}
|
||||
}
|
||||
|
||||
func (x *RateLimitSettings) GetEnabled() bool {
|
||||
@@ -2113,7 +2157,7 @@ type RemoteKVGetRequest struct {
|
||||
|
||||
func (x *RemoteKVGetRequest) Reset() {
|
||||
*x = RemoteKVGetRequest{}
|
||||
mi := &file_dns_proto_msgTypes[31]
|
||||
mi := &file_dns_proto_msgTypes[32]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2125,7 +2169,7 @@ func (x *RemoteKVGetRequest) String() string {
|
||||
func (*RemoteKVGetRequest) ProtoMessage() {}
|
||||
|
||||
func (x *RemoteKVGetRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[31]
|
||||
mi := &file_dns_proto_msgTypes[32]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2138,7 +2182,7 @@ func (x *RemoteKVGetRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RemoteKVGetRequest.ProtoReflect.Descriptor instead.
|
||||
func (*RemoteKVGetRequest) Descriptor() ([]byte, []int) {
|
||||
return file_dns_proto_rawDescGZIP(), []int{31}
|
||||
return file_dns_proto_rawDescGZIP(), []int{32}
|
||||
}
|
||||
|
||||
func (x *RemoteKVGetRequest) GetKey() string {
|
||||
@@ -2161,7 +2205,7 @@ type RemoteKVGetResponse struct {
|
||||
|
||||
func (x *RemoteKVGetResponse) Reset() {
|
||||
*x = RemoteKVGetResponse{}
|
||||
mi := &file_dns_proto_msgTypes[32]
|
||||
mi := &file_dns_proto_msgTypes[33]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2173,7 +2217,7 @@ func (x *RemoteKVGetResponse) String() string {
|
||||
func (*RemoteKVGetResponse) ProtoMessage() {}
|
||||
|
||||
func (x *RemoteKVGetResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[32]
|
||||
mi := &file_dns_proto_msgTypes[33]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2186,7 +2230,7 @@ func (x *RemoteKVGetResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RemoteKVGetResponse.ProtoReflect.Descriptor instead.
|
||||
func (*RemoteKVGetResponse) Descriptor() ([]byte, []int) {
|
||||
return file_dns_proto_rawDescGZIP(), []int{32}
|
||||
return file_dns_proto_rawDescGZIP(), []int{33}
|
||||
}
|
||||
|
||||
func (x *RemoteKVGetResponse) GetValue() isRemoteKVGetResponse_Value {
|
||||
@@ -2241,7 +2285,7 @@ type RemoteKVSetRequest struct {
|
||||
|
||||
func (x *RemoteKVSetRequest) Reset() {
|
||||
*x = RemoteKVSetRequest{}
|
||||
mi := &file_dns_proto_msgTypes[33]
|
||||
mi := &file_dns_proto_msgTypes[34]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2253,7 +2297,7 @@ func (x *RemoteKVSetRequest) String() string {
|
||||
func (*RemoteKVSetRequest) ProtoMessage() {}
|
||||
|
||||
func (x *RemoteKVSetRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[33]
|
||||
mi := &file_dns_proto_msgTypes[34]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2266,7 +2310,7 @@ func (x *RemoteKVSetRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RemoteKVSetRequest.ProtoReflect.Descriptor instead.
|
||||
func (*RemoteKVSetRequest) Descriptor() ([]byte, []int) {
|
||||
return file_dns_proto_rawDescGZIP(), []int{33}
|
||||
return file_dns_proto_rawDescGZIP(), []int{34}
|
||||
}
|
||||
|
||||
func (x *RemoteKVSetRequest) GetKey() string {
|
||||
@@ -2298,7 +2342,7 @@ type RemoteKVSetResponse struct {
|
||||
|
||||
func (x *RemoteKVSetResponse) Reset() {
|
||||
*x = RemoteKVSetResponse{}
|
||||
mi := &file_dns_proto_msgTypes[34]
|
||||
mi := &file_dns_proto_msgTypes[35]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2310,7 +2354,7 @@ func (x *RemoteKVSetResponse) String() string {
|
||||
func (*RemoteKVSetResponse) ProtoMessage() {}
|
||||
|
||||
func (x *RemoteKVSetResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[34]
|
||||
mi := &file_dns_proto_msgTypes[35]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2323,7 +2367,7 @@ func (x *RemoteKVSetResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RemoteKVSetResponse.ProtoReflect.Descriptor instead.
|
||||
func (*RemoteKVSetResponse) Descriptor() ([]byte, []int) {
|
||||
return file_dns_proto_rawDescGZIP(), []int{34}
|
||||
return file_dns_proto_rawDescGZIP(), []int{35}
|
||||
}
|
||||
|
||||
type CustomDomainCertificateRequest struct {
|
||||
@@ -2335,7 +2379,7 @@ type CustomDomainCertificateRequest struct {
|
||||
|
||||
func (x *CustomDomainCertificateRequest) Reset() {
|
||||
*x = CustomDomainCertificateRequest{}
|
||||
mi := &file_dns_proto_msgTypes[35]
|
||||
mi := &file_dns_proto_msgTypes[36]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2347,7 +2391,7 @@ func (x *CustomDomainCertificateRequest) String() string {
|
||||
func (*CustomDomainCertificateRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CustomDomainCertificateRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[35]
|
||||
mi := &file_dns_proto_msgTypes[36]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2360,7 +2404,7 @@ func (x *CustomDomainCertificateRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use CustomDomainCertificateRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CustomDomainCertificateRequest) Descriptor() ([]byte, []int) {
|
||||
return file_dns_proto_rawDescGZIP(), []int{35}
|
||||
return file_dns_proto_rawDescGZIP(), []int{36}
|
||||
}
|
||||
|
||||
func (x *CustomDomainCertificateRequest) GetCertName() string {
|
||||
@@ -2380,7 +2424,7 @@ type CustomDomainCertificateResponse struct {
|
||||
|
||||
func (x *CustomDomainCertificateResponse) Reset() {
|
||||
*x = CustomDomainCertificateResponse{}
|
||||
mi := &file_dns_proto_msgTypes[36]
|
||||
mi := &file_dns_proto_msgTypes[37]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2392,7 +2436,7 @@ func (x *CustomDomainCertificateResponse) String() string {
|
||||
func (*CustomDomainCertificateResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CustomDomainCertificateResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[36]
|
||||
mi := &file_dns_proto_msgTypes[37]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2405,7 +2449,7 @@ func (x *CustomDomainCertificateResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use CustomDomainCertificateResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CustomDomainCertificateResponse) Descriptor() ([]byte, []int) {
|
||||
return file_dns_proto_rawDescGZIP(), []int{36}
|
||||
return file_dns_proto_rawDescGZIP(), []int{37}
|
||||
}
|
||||
|
||||
func (x *CustomDomainCertificateResponse) GetCertificate() []byte {
|
||||
@@ -2430,7 +2474,7 @@ type SessionTicketRequest struct {
|
||||
|
||||
func (x *SessionTicketRequest) Reset() {
|
||||
*x = SessionTicketRequest{}
|
||||
mi := &file_dns_proto_msgTypes[37]
|
||||
mi := &file_dns_proto_msgTypes[38]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2442,7 +2486,7 @@ func (x *SessionTicketRequest) String() string {
|
||||
func (*SessionTicketRequest) ProtoMessage() {}
|
||||
|
||||
func (x *SessionTicketRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[37]
|
||||
mi := &file_dns_proto_msgTypes[38]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2455,7 +2499,7 @@ func (x *SessionTicketRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use SessionTicketRequest.ProtoReflect.Descriptor instead.
|
||||
func (*SessionTicketRequest) Descriptor() ([]byte, []int) {
|
||||
return file_dns_proto_rawDescGZIP(), []int{37}
|
||||
return file_dns_proto_rawDescGZIP(), []int{38}
|
||||
}
|
||||
|
||||
type SessionTicketResponse struct {
|
||||
@@ -2467,7 +2511,7 @@ type SessionTicketResponse struct {
|
||||
|
||||
func (x *SessionTicketResponse) Reset() {
|
||||
*x = SessionTicketResponse{}
|
||||
mi := &file_dns_proto_msgTypes[38]
|
||||
mi := &file_dns_proto_msgTypes[39]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2479,7 +2523,7 @@ func (x *SessionTicketResponse) String() string {
|
||||
func (*SessionTicketResponse) ProtoMessage() {}
|
||||
|
||||
func (x *SessionTicketResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[38]
|
||||
mi := &file_dns_proto_msgTypes[39]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2492,7 +2536,7 @@ func (x *SessionTicketResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use SessionTicketResponse.ProtoReflect.Descriptor instead.
|
||||
func (*SessionTicketResponse) Descriptor() ([]byte, []int) {
|
||||
return file_dns_proto_rawDescGZIP(), []int{38}
|
||||
return file_dns_proto_rawDescGZIP(), []int{39}
|
||||
}
|
||||
|
||||
func (x *SessionTicketResponse) GetTickets() []*SessionTicket {
|
||||
@@ -2512,7 +2556,7 @@ type SessionTicket struct {
|
||||
|
||||
func (x *SessionTicket) Reset() {
|
||||
*x = SessionTicket{}
|
||||
mi := &file_dns_proto_msgTypes[39]
|
||||
mi := &file_dns_proto_msgTypes[40]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2524,7 +2568,7 @@ func (x *SessionTicket) String() string {
|
||||
func (*SessionTicket) ProtoMessage() {}
|
||||
|
||||
func (x *SessionTicket) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[39]
|
||||
mi := &file_dns_proto_msgTypes[40]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2537,7 +2581,7 @@ func (x *SessionTicket) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use SessionTicket.ProtoReflect.Descriptor instead.
|
||||
func (*SessionTicket) Descriptor() ([]byte, []int) {
|
||||
return file_dns_proto_rawDescGZIP(), []int{39}
|
||||
return file_dns_proto_rawDescGZIP(), []int{40}
|
||||
}
|
||||
|
||||
func (x *SessionTicket) GetName() string {
|
||||
@@ -2563,7 +2607,7 @@ type DeviceSettingsChange_Deleted struct {
|
||||
|
||||
func (x *DeviceSettingsChange_Deleted) Reset() {
|
||||
*x = DeviceSettingsChange_Deleted{}
|
||||
mi := &file_dns_proto_msgTypes[40]
|
||||
mi := &file_dns_proto_msgTypes[41]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2575,7 +2619,7 @@ func (x *DeviceSettingsChange_Deleted) String() string {
|
||||
func (*DeviceSettingsChange_Deleted) ProtoMessage() {}
|
||||
|
||||
func (x *DeviceSettingsChange_Deleted) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[40]
|
||||
mi := &file_dns_proto_msgTypes[41]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2607,7 +2651,7 @@ type DeviceSettingsChange_Upserted struct {
|
||||
|
||||
func (x *DeviceSettingsChange_Upserted) Reset() {
|
||||
*x = DeviceSettingsChange_Upserted{}
|
||||
mi := &file_dns_proto_msgTypes[41]
|
||||
mi := &file_dns_proto_msgTypes[42]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2619,7 +2663,7 @@ func (x *DeviceSettingsChange_Upserted) String() string {
|
||||
func (*DeviceSettingsChange_Upserted) ProtoMessage() {}
|
||||
|
||||
func (x *DeviceSettingsChange_Upserted) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[41]
|
||||
mi := &file_dns_proto_msgTypes[42]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2652,7 +2696,7 @@ type CustomDomain_Pending struct {
|
||||
|
||||
func (x *CustomDomain_Pending) Reset() {
|
||||
*x = CustomDomain_Pending{}
|
||||
mi := &file_dns_proto_msgTypes[42]
|
||||
mi := &file_dns_proto_msgTypes[43]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2664,7 +2708,7 @@ func (x *CustomDomain_Pending) String() string {
|
||||
func (*CustomDomain_Pending) ProtoMessage() {}
|
||||
|
||||
func (x *CustomDomain_Pending) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[42]
|
||||
mi := &file_dns_proto_msgTypes[43]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2706,7 +2750,7 @@ type CustomDomain_Current struct {
|
||||
|
||||
func (x *CustomDomain_Current) Reset() {
|
||||
*x = CustomDomain_Current{}
|
||||
mi := &file_dns_proto_msgTypes[43]
|
||||
mi := &file_dns_proto_msgTypes[44]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -2718,7 +2762,7 @@ func (x *CustomDomain_Current) String() string {
|
||||
func (*CustomDomain_Current) ProtoMessage() {}
|
||||
|
||||
func (x *CustomDomain_Current) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_dns_proto_msgTypes[43]
|
||||
mi := &file_dns_proto_msgTypes[44]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -2916,6 +2960,8 @@ const file_dns_proto_rawDesc = "" +
|
||||
"\x0fBadRequestError\x12\x18\n" +
|
||||
"\amessage\x18\x01 \x01(\tR\amessage\"5\n" +
|
||||
"\x19AuthenticationFailedError\x12\x18\n" +
|
||||
"\amessage\x18\x01 \x01(\tR\amessage\")\n" +
|
||||
"\rNotFoundError\x12\x18\n" +
|
||||
"\amessage\x18\x01 \x01(\tR\amessage\"l\n" +
|
||||
"\x11RateLimitSettings\x12\x18\n" +
|
||||
"\aenabled\x18\x01 \x01(\bR\aenabled\x12\x10\n" +
|
||||
@@ -2989,7 +3035,7 @@ func file_dns_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_dns_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_dns_proto_msgTypes = make([]protoimpl.MessageInfo, 44)
|
||||
var file_dns_proto_msgTypes = make([]protoimpl.MessageInfo, 45)
|
||||
var file_dns_proto_goTypes = []any{
|
||||
(DeviceType)(0), // 0: DeviceType
|
||||
(*RateLimitSettingsRequest)(nil), // 1: RateLimitSettingsRequest
|
||||
@@ -3022,46 +3068,47 @@ var file_dns_proto_goTypes = []any{
|
||||
(*DeviceQuotaExceededError)(nil), // 28: DeviceQuotaExceededError
|
||||
(*BadRequestError)(nil), // 29: BadRequestError
|
||||
(*AuthenticationFailedError)(nil), // 30: AuthenticationFailedError
|
||||
(*RateLimitSettings)(nil), // 31: RateLimitSettings
|
||||
(*RemoteKVGetRequest)(nil), // 32: RemoteKVGetRequest
|
||||
(*RemoteKVGetResponse)(nil), // 33: RemoteKVGetResponse
|
||||
(*RemoteKVSetRequest)(nil), // 34: RemoteKVSetRequest
|
||||
(*RemoteKVSetResponse)(nil), // 35: RemoteKVSetResponse
|
||||
(*CustomDomainCertificateRequest)(nil), // 36: CustomDomainCertificateRequest
|
||||
(*CustomDomainCertificateResponse)(nil), // 37: CustomDomainCertificateResponse
|
||||
(*SessionTicketRequest)(nil), // 38: SessionTicketRequest
|
||||
(*SessionTicketResponse)(nil), // 39: SessionTicketResponse
|
||||
(*SessionTicket)(nil), // 40: SessionTicket
|
||||
(*DeviceSettingsChange_Deleted)(nil), // 41: DeviceSettingsChange.Deleted
|
||||
(*DeviceSettingsChange_Upserted)(nil), // 42: DeviceSettingsChange.Upserted
|
||||
(*CustomDomain_Pending)(nil), // 43: CustomDomain.Pending
|
||||
(*CustomDomain_Current)(nil), // 44: CustomDomain.Current
|
||||
(*timestamppb.Timestamp)(nil), // 45: google.protobuf.Timestamp
|
||||
(*durationpb.Duration)(nil), // 46: google.protobuf.Duration
|
||||
(*emptypb.Empty)(nil), // 47: google.protobuf.Empty
|
||||
(*NotFoundError)(nil), // 31: NotFoundError
|
||||
(*RateLimitSettings)(nil), // 32: RateLimitSettings
|
||||
(*RemoteKVGetRequest)(nil), // 33: RemoteKVGetRequest
|
||||
(*RemoteKVGetResponse)(nil), // 34: RemoteKVGetResponse
|
||||
(*RemoteKVSetRequest)(nil), // 35: RemoteKVSetRequest
|
||||
(*RemoteKVSetResponse)(nil), // 36: RemoteKVSetResponse
|
||||
(*CustomDomainCertificateRequest)(nil), // 37: CustomDomainCertificateRequest
|
||||
(*CustomDomainCertificateResponse)(nil), // 38: CustomDomainCertificateResponse
|
||||
(*SessionTicketRequest)(nil), // 39: SessionTicketRequest
|
||||
(*SessionTicketResponse)(nil), // 40: SessionTicketResponse
|
||||
(*SessionTicket)(nil), // 41: SessionTicket
|
||||
(*DeviceSettingsChange_Deleted)(nil), // 42: DeviceSettingsChange.Deleted
|
||||
(*DeviceSettingsChange_Upserted)(nil), // 43: DeviceSettingsChange.Upserted
|
||||
(*CustomDomain_Pending)(nil), // 44: CustomDomain.Pending
|
||||
(*CustomDomain_Current)(nil), // 45: CustomDomain.Current
|
||||
(*timestamppb.Timestamp)(nil), // 46: google.protobuf.Timestamp
|
||||
(*durationpb.Duration)(nil), // 47: google.protobuf.Duration
|
||||
(*emptypb.Empty)(nil), // 48: google.protobuf.Empty
|
||||
}
|
||||
var file_dns_proto_depIdxs = []int32{
|
||||
23, // 0: RateLimitSettingsResponse.allowed_subnets:type_name -> CidrRange
|
||||
22, // 1: GlobalAccessSettingsResponse.standard:type_name -> AccessSettings
|
||||
45, // 2: DNSProfilesRequest.sync_time:type_name -> google.protobuf.Timestamp
|
||||
46, // 2: DNSProfilesRequest.sync_time:type_name -> google.protobuf.Timestamp
|
||||
10, // 3: DNSProfile.safe_browsing:type_name -> SafeBrowsingSettings
|
||||
12, // 4: DNSProfile.parental:type_name -> ParentalSettings
|
||||
16, // 5: DNSProfile.rule_lists:type_name -> RuleListsSettings
|
||||
11, // 6: DNSProfile.devices:type_name -> DeviceSettings
|
||||
46, // 7: DNSProfile.filtered_response_ttl:type_name -> google.protobuf.Duration
|
||||
47, // 7: DNSProfile.filtered_response_ttl:type_name -> google.protobuf.Duration
|
||||
17, // 8: DNSProfile.blocking_mode_custom_ip:type_name -> BlockingModeCustomIP
|
||||
18, // 9: DNSProfile.blocking_mode_nxdomain:type_name -> BlockingModeNXDOMAIN
|
||||
19, // 10: DNSProfile.blocking_mode_null_ip:type_name -> BlockingModeNullIP
|
||||
20, // 11: DNSProfile.blocking_mode_refused:type_name -> BlockingModeREFUSED
|
||||
22, // 12: DNSProfile.access:type_name -> AccessSettings
|
||||
31, // 13: DNSProfile.rate_limit:type_name -> RateLimitSettings
|
||||
32, // 13: DNSProfile.rate_limit:type_name -> RateLimitSettings
|
||||
8, // 14: DNSProfile.custom_domain:type_name -> CustomDomainSettings
|
||||
7, // 15: DNSProfile.device_changes:type_name -> DeviceSettingsChange
|
||||
41, // 16: DeviceSettingsChange.deleted:type_name -> DeviceSettingsChange.Deleted
|
||||
42, // 17: DeviceSettingsChange.upserted:type_name -> DeviceSettingsChange.Upserted
|
||||
42, // 16: DeviceSettingsChange.deleted:type_name -> DeviceSettingsChange.Deleted
|
||||
43, // 17: DeviceSettingsChange.upserted:type_name -> DeviceSettingsChange.Upserted
|
||||
9, // 18: CustomDomainSettings.domains:type_name -> CustomDomain
|
||||
43, // 19: CustomDomain.pending:type_name -> CustomDomain.Pending
|
||||
44, // 20: CustomDomain.current:type_name -> CustomDomain.Current
|
||||
44, // 19: CustomDomain.pending:type_name -> CustomDomain.Pending
|
||||
45, // 20: CustomDomain.current:type_name -> CustomDomain.Current
|
||||
24, // 21: DeviceSettings.authentication:type_name -> AuthenticationSettings
|
||||
13, // 22: ParentalSettings.schedule:type_name -> ScheduleSettings
|
||||
14, // 23: ScheduleSettings.weeklyRange:type_name -> WeeklyRange
|
||||
@@ -3072,40 +3119,40 @@ var file_dns_proto_depIdxs = []int32{
|
||||
15, // 28: WeeklyRange.fri:type_name -> DayRange
|
||||
15, // 29: WeeklyRange.sat:type_name -> DayRange
|
||||
15, // 30: WeeklyRange.sun:type_name -> DayRange
|
||||
46, // 31: DayRange.start:type_name -> google.protobuf.Duration
|
||||
46, // 32: DayRange.end:type_name -> google.protobuf.Duration
|
||||
45, // 33: DeviceBillingStat.last_activity_time:type_name -> google.protobuf.Timestamp
|
||||
47, // 31: DayRange.start:type_name -> google.protobuf.Duration
|
||||
47, // 32: DayRange.end:type_name -> google.protobuf.Duration
|
||||
46, // 33: DeviceBillingStat.last_activity_time:type_name -> google.protobuf.Timestamp
|
||||
23, // 34: AccessSettings.allowlist_cidr:type_name -> CidrRange
|
||||
23, // 35: AccessSettings.blocklist_cidr:type_name -> CidrRange
|
||||
0, // 36: CreateDeviceRequest.device_type:type_name -> DeviceType
|
||||
11, // 37: CreateDeviceResponse.device:type_name -> DeviceSettings
|
||||
46, // 38: RateLimitedError.retry_delay:type_name -> google.protobuf.Duration
|
||||
47, // 38: RateLimitedError.retry_delay:type_name -> google.protobuf.Duration
|
||||
23, // 39: RateLimitSettings.client_cidr:type_name -> CidrRange
|
||||
47, // 40: RemoteKVGetResponse.empty:type_name -> google.protobuf.Empty
|
||||
46, // 41: RemoteKVSetRequest.ttl:type_name -> google.protobuf.Duration
|
||||
40, // 42: SessionTicketResponse.tickets:type_name -> SessionTicket
|
||||
48, // 40: RemoteKVGetResponse.empty:type_name -> google.protobuf.Empty
|
||||
47, // 41: RemoteKVSetRequest.ttl:type_name -> google.protobuf.Duration
|
||||
41, // 42: SessionTicketResponse.tickets:type_name -> SessionTicket
|
||||
11, // 43: DeviceSettingsChange.Upserted.device:type_name -> DeviceSettings
|
||||
45, // 44: CustomDomain.Pending.expire:type_name -> google.protobuf.Timestamp
|
||||
45, // 45: CustomDomain.Current.not_before:type_name -> google.protobuf.Timestamp
|
||||
45, // 46: CustomDomain.Current.not_after:type_name -> google.protobuf.Timestamp
|
||||
46, // 44: CustomDomain.Pending.expire:type_name -> google.protobuf.Timestamp
|
||||
46, // 45: CustomDomain.Current.not_before:type_name -> google.protobuf.Timestamp
|
||||
46, // 46: CustomDomain.Current.not_after:type_name -> google.protobuf.Timestamp
|
||||
5, // 47: DNSService.getDNSProfiles:input_type -> DNSProfilesRequest
|
||||
21, // 48: DNSService.saveDevicesBillingStat:input_type -> DeviceBillingStat
|
||||
25, // 49: DNSService.createDeviceByHumanId:input_type -> CreateDeviceRequest
|
||||
1, // 50: RateLimitService.getRateLimitSettings:input_type -> RateLimitSettingsRequest
|
||||
3, // 51: RateLimitService.getGlobalAccessSettings:input_type -> GlobalAccessSettingsRequest
|
||||
32, // 52: RemoteKVService.get:input_type -> RemoteKVGetRequest
|
||||
34, // 53: RemoteKVService.set:input_type -> RemoteKVSetRequest
|
||||
36, // 54: CustomDomainService.getCustomDomainCertificate:input_type -> CustomDomainCertificateRequest
|
||||
38, // 55: SessionTicketService.getSessionTickets:input_type -> SessionTicketRequest
|
||||
33, // 52: RemoteKVService.get:input_type -> RemoteKVGetRequest
|
||||
35, // 53: RemoteKVService.set:input_type -> RemoteKVSetRequest
|
||||
37, // 54: CustomDomainService.getCustomDomainCertificate:input_type -> CustomDomainCertificateRequest
|
||||
39, // 55: SessionTicketService.getSessionTickets:input_type -> SessionTicketRequest
|
||||
6, // 56: DNSService.getDNSProfiles:output_type -> DNSProfile
|
||||
47, // 57: DNSService.saveDevicesBillingStat:output_type -> google.protobuf.Empty
|
||||
48, // 57: DNSService.saveDevicesBillingStat:output_type -> google.protobuf.Empty
|
||||
26, // 58: DNSService.createDeviceByHumanId:output_type -> CreateDeviceResponse
|
||||
2, // 59: RateLimitService.getRateLimitSettings:output_type -> RateLimitSettingsResponse
|
||||
4, // 60: RateLimitService.getGlobalAccessSettings:output_type -> GlobalAccessSettingsResponse
|
||||
33, // 61: RemoteKVService.get:output_type -> RemoteKVGetResponse
|
||||
35, // 62: RemoteKVService.set:output_type -> RemoteKVSetResponse
|
||||
37, // 63: CustomDomainService.getCustomDomainCertificate:output_type -> CustomDomainCertificateResponse
|
||||
39, // 64: SessionTicketService.getSessionTickets:output_type -> SessionTicketResponse
|
||||
34, // 61: RemoteKVService.get:output_type -> RemoteKVGetResponse
|
||||
36, // 62: RemoteKVService.set:output_type -> RemoteKVSetResponse
|
||||
38, // 63: CustomDomainService.getCustomDomainCertificate:output_type -> CustomDomainCertificateResponse
|
||||
40, // 64: SessionTicketService.getSessionTickets:output_type -> SessionTicketResponse
|
||||
56, // [56:65] is the sub-list for method output_type
|
||||
47, // [47:56] is the sub-list for method input_type
|
||||
47, // [47:47] is the sub-list for extension type_name
|
||||
@@ -3135,7 +3182,7 @@ func file_dns_proto_init() {
|
||||
file_dns_proto_msgTypes[23].OneofWrappers = []any{
|
||||
(*AuthenticationSettings_PasswordHashBcrypt)(nil),
|
||||
}
|
||||
file_dns_proto_msgTypes[32].OneofWrappers = []any{
|
||||
file_dns_proto_msgTypes[33].OneofWrappers = []any{
|
||||
(*RemoteKVGetResponse_Data)(nil),
|
||||
(*RemoteKVGetResponse_Empty)(nil),
|
||||
}
|
||||
@@ -3145,7 +3192,7 @@ func file_dns_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_dns_proto_rawDesc), len(file_dns_proto_rawDesc)),
|
||||
NumEnums: 1,
|
||||
NumMessages: 44,
|
||||
NumMessages: 45,
|
||||
NumExtensions: 0,
|
||||
NumServices: 5,
|
||||
},
|
||||
|
||||
@@ -85,7 +85,8 @@ service CustomDomainService {
|
||||
|
||||
This method may return the following errors:
|
||||
- AuthenticationFailedError: If the authentication failed.
|
||||
- BadRequestError: If the request is invalid: cert_name is empty or no certificate found.
|
||||
- BadRequestError: If the request is invalid: cert_name is empty.
|
||||
- NotFoundError: If the certificate could not be found.
|
||||
*/
|
||||
rpc getCustomDomainCertificate(CustomDomainCertificateRequest) returns (CustomDomainCertificateResponse);
|
||||
}
|
||||
@@ -341,6 +342,10 @@ message AuthenticationFailedError {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
message NotFoundError {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
message RateLimitSettings {
|
||||
bool enabled = 1;
|
||||
uint32 rps = 2;
|
||||
|
||||
@@ -554,7 +554,8 @@ type CustomDomainServiceClient interface {
|
||||
//
|
||||
// This method may return the following errors:
|
||||
// - AuthenticationFailedError: If the authentication failed.
|
||||
// - BadRequestError: If the request is invalid: cert_name is empty or no certificate found.
|
||||
// - BadRequestError: If the request is invalid: cert_name is empty.
|
||||
// - NotFoundError: If the certificate could not be found.
|
||||
GetCustomDomainCertificate(ctx context.Context, in *CustomDomainCertificateRequest, opts ...grpc.CallOption) (*CustomDomainCertificateResponse, error)
|
||||
}
|
||||
|
||||
@@ -584,7 +585,8 @@ type CustomDomainServiceServer interface {
|
||||
//
|
||||
// This method may return the following errors:
|
||||
// - AuthenticationFailedError: If the authentication failed.
|
||||
// - BadRequestError: If the request is invalid: cert_name is empty or no certificate found.
|
||||
// - BadRequestError: If the request is invalid: cert_name is empty.
|
||||
// - NotFoundError: If the certificate could not be found.
|
||||
GetCustomDomainCertificate(context.Context, *CustomDomainCertificateRequest) (*CustomDomainCertificateResponse, error)
|
||||
mustEmbedUnimplementedCustomDomainServiceServer()
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
@@ -17,6 +18,8 @@ import (
|
||||
// [GRPCMetrics.IncrementErrorCount].
|
||||
//
|
||||
// TODO(e.burkov): Move error types to this package.
|
||||
//
|
||||
// TODO(a.garipov): Separate metrics reporting from error fixing.
|
||||
func fixGRPCError(ctx context.Context, mtrc GRPCMetrics, err error) (res error) {
|
||||
metricsType := GRPCErrOther
|
||||
defer func() { mtrc.IncrementErrorCount(ctx, metricsType) }()
|
||||
@@ -56,6 +59,15 @@ func fixGRPCError(ctx context.Context, mtrc GRPCMetrics, err error) (res error)
|
||||
return &profiledb.DeviceQuotaExceededError{
|
||||
Message: structErr.Message,
|
||||
}
|
||||
case *NotFoundError:
|
||||
metricsType = GRPCErrNotFound
|
||||
|
||||
// This error can currently only be returned from the certificate
|
||||
// API, so return the error that it expects.
|
||||
//
|
||||
// TODO(a.garipov): Fix this and don't assume that this error is
|
||||
// only returned there.
|
||||
return fmt.Errorf("%s: %w", structErr.Message, tlsconfig.ErrCertificateNotFound)
|
||||
case *RateLimitedError:
|
||||
metricsType = GRPCErrRateLimit
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ const (
|
||||
GRPCErrAuthentication GRPCError = "auth"
|
||||
GRPCErrBadRequest GRPCError = "bad_req"
|
||||
GRPCErrDeviceQuota GRPCError = "dev_quota"
|
||||
GRPCErrNotFound GRPCError = "not_found"
|
||||
GRPCErrOther GRPCError = "other"
|
||||
GRPCErrRateLimit GRPCError = "rate_limit"
|
||||
GRPCErrTimeout GRPCError = "timeout"
|
||||
@@ -150,6 +151,9 @@ type TicketStorageMetrics interface {
|
||||
err error,
|
||||
)
|
||||
|
||||
// SetTicketsState sets the state number code of the session tickets.
|
||||
SetTicketsState(ctx context.Context, num float64)
|
||||
|
||||
// ObserveUpdate sets the duration of the session ticket update operation.
|
||||
ObserveUpdate(ctx context.Context, dur time.Duration, err error)
|
||||
}
|
||||
@@ -171,6 +175,10 @@ func (EmptyTicketStorageMetrics) SetTicketStatus(
|
||||
) {
|
||||
}
|
||||
|
||||
// SetTicketsState implements the [TicketStorageMetrics] interface for
|
||||
// EmptyTicketStorageMetrics.
|
||||
func (EmptyTicketStorageMetrics) SetTicketsState(_ context.Context, _ float64) {}
|
||||
|
||||
// ObserveUpdate implements the [TicketStorageMetrics] interface for
|
||||
// EmptyTicketStorageMetrics.
|
||||
func (EmptyTicketStorageMetrics) ObserveUpdate(_ context.Context, _ time.Duration, _ error) {}
|
||||
|
||||
@@ -81,19 +81,19 @@ func (x *SafeBrowsingSettings) toInternal() (c *filter.ConfigSafeBrowsing) {
|
||||
}
|
||||
|
||||
// toInternal converts protobuf access settings to an internal structure. If x
|
||||
// is nil, toInternal returns [access.EmptyProfile].
|
||||
// is nil, toInternal returns [access.EmptyProfile]. all arguments must not be
|
||||
// nil.
|
||||
func (x *AccessSettings) toInternal(
|
||||
ctx context.Context,
|
||||
errColl errcoll.Interface,
|
||||
mtrc access.ProfileMetrics,
|
||||
logger *slog.Logger,
|
||||
errColl errcoll.Interface,
|
||||
cons *access.ProfileConstructor,
|
||||
) (a access.Profile) {
|
||||
if x == nil || !x.Enabled {
|
||||
return access.EmptyProfile{}
|
||||
}
|
||||
|
||||
return access.NewDefaultProfile(&access.ProfileConfig{
|
||||
Metrics: mtrc,
|
||||
return cons.New(&access.ProfileConfig{
|
||||
AllowedNets: cidrRangeToInternal(ctx, errColl, logger, x.AllowlistCidr),
|
||||
BlockedNets: cidrRangeToInternal(ctx, errColl, logger, x.BlocklistCidr),
|
||||
AllowedASN: asnToInternal(x.AllowlistAsn),
|
||||
|
||||
@@ -14,10 +14,10 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter/custom"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/c2h5oh/datasize"
|
||||
"google.golang.org/grpc"
|
||||
@@ -35,6 +35,14 @@ type ProfileStorageConfig struct {
|
||||
// BaseCustomLogger is the base logger used for the custom filters.
|
||||
BaseCustomLogger *slog.Logger
|
||||
|
||||
// Endpoint is the backend API URL. The scheme should be either "grpc" or
|
||||
// "grpcs". It must not be nil.
|
||||
Endpoint *url.URL
|
||||
|
||||
// ProfileAccessConstructor is used to create access managers for profiles.
|
||||
// It must not be nil.
|
||||
ProfileAccessConstructor *access.ProfileConstructor
|
||||
|
||||
// BindSet is the subnet set created from DNS servers listening addresses.
|
||||
// It must not be nil.
|
||||
BindSet netutil.SubnetSet
|
||||
@@ -43,10 +51,6 @@ type ProfileStorageConfig struct {
|
||||
// non-critical errors. It must not be nil.
|
||||
ErrColl errcoll.Interface
|
||||
|
||||
// ProfileMetrics is used for the collection of the profile access engine
|
||||
// statistics. It must not be nil.
|
||||
ProfileMetrics access.ProfileMetrics
|
||||
|
||||
// GRPCMetrics is used for the collection of the protobuf communication
|
||||
// statistics.
|
||||
GRPCMetrics GRPCMetrics
|
||||
@@ -54,10 +58,6 @@ type ProfileStorageConfig struct {
|
||||
// Metrics is used for the collection of the profiles storage statistics.
|
||||
Metrics ProfileDBMetrics
|
||||
|
||||
// Endpoint is the backend API URL. The scheme should be either "grpc" or
|
||||
// "grpcs". It must not be nil.
|
||||
Endpoint *url.URL
|
||||
|
||||
// APIKey is the API key used for authentication, if any. If empty, no
|
||||
// authentication is performed.
|
||||
APIKey string
|
||||
@@ -77,10 +77,10 @@ type ProfileStorageConfig struct {
|
||||
type ProfileStorage struct {
|
||||
logger *slog.Logger
|
||||
baseCustomLogger *slog.Logger
|
||||
profAccessCons *access.ProfileConstructor
|
||||
bindSet netutil.SubnetSet
|
||||
errColl errcoll.Interface
|
||||
client DNSServiceClient
|
||||
profileMetrics access.ProfileMetrics
|
||||
grpcMetrics GRPCMetrics
|
||||
metrics ProfileDBMetrics
|
||||
apiKey string
|
||||
@@ -100,10 +100,10 @@ func NewProfileStorage(c *ProfileStorageConfig) (s *ProfileStorage, err error) {
|
||||
return &ProfileStorage{
|
||||
logger: c.Logger,
|
||||
baseCustomLogger: c.BaseCustomLogger,
|
||||
profAccessCons: c.ProfileAccessConstructor,
|
||||
bindSet: c.BindSet,
|
||||
errColl: c.ErrColl,
|
||||
client: NewDNSServiceClient(client),
|
||||
profileMetrics: c.ProfileMetrics,
|
||||
grpcMetrics: c.GRPCMetrics,
|
||||
metrics: c.Metrics,
|
||||
apiKey: c.APIKey,
|
||||
@@ -313,7 +313,7 @@ func (s *ProfileStorage) newProfile(
|
||||
RuleList: p.RuleLists.toInternal(ctx, s.errColl, s.logger),
|
||||
SafeBrowsing: p.SafeBrowsing.toInternal(),
|
||||
},
|
||||
Access: p.Access.toInternal(ctx, s.errColl, s.profileMetrics, s.logger),
|
||||
Access: p.Access.toInternal(ctx, s.logger, s.errColl, s.profAccessCons),
|
||||
BlockingMode: m,
|
||||
Ratelimiter: p.RateLimit.toInternal(ctx, s.errColl, s.logger, s.respSzEst),
|
||||
AccountID: accID,
|
||||
|
||||
@@ -38,9 +38,9 @@ func TestProfileStorage_NewProfile(t *testing.T) {
|
||||
profileStorage := &ProfileStorage{
|
||||
logger: TestLogger,
|
||||
baseCustomLogger: TestLogger,
|
||||
profAccessCons: TestProfileAccessConstructor,
|
||||
bindSet: TestBind,
|
||||
errColl: agdtest.NewErrorCollector(),
|
||||
profileMetrics: access.EmptyProfileMetrics{},
|
||||
grpcMetrics: EmptyGRPCMetrics{},
|
||||
metrics: EmptyProfileDBMetrics{},
|
||||
respSzEst: TestRespSzEst,
|
||||
@@ -73,9 +73,9 @@ func TestProfileStorage_NewProfile(t *testing.T) {
|
||||
storage := &ProfileStorage{
|
||||
logger: TestLogger,
|
||||
baseCustomLogger: TestLogger,
|
||||
profAccessCons: TestProfileAccessConstructor,
|
||||
bindSet: TestBind,
|
||||
errColl: savingErrColl,
|
||||
profileMetrics: access.EmptyProfileMetrics{},
|
||||
grpcMetrics: EmptyGRPCMetrics{},
|
||||
metrics: EmptyProfileDBMetrics{},
|
||||
respSzEst: TestRespSzEst,
|
||||
@@ -113,9 +113,9 @@ func TestProfileStorage_NewProfile(t *testing.T) {
|
||||
storage := &ProfileStorage{
|
||||
logger: TestLogger,
|
||||
baseCustomLogger: TestLogger,
|
||||
profAccessCons: TestProfileAccessConstructor,
|
||||
bindSet: bindSet,
|
||||
errColl: savingErrColl,
|
||||
profileMetrics: access.EmptyProfileMetrics{},
|
||||
grpcMetrics: EmptyGRPCMetrics{},
|
||||
metrics: EmptyProfileDBMetrics{},
|
||||
respSzEst: TestRespSzEst,
|
||||
@@ -551,8 +551,7 @@ func newProfile(tb testing.TB) (p *agd.Profile) {
|
||||
IPv6: []netip.Addr{netip.MustParseAddr("1234::cdef")},
|
||||
}
|
||||
|
||||
wantAccess := access.NewDefaultProfile(&access.ProfileConfig{
|
||||
Metrics: access.EmptyProfileMetrics{},
|
||||
wantAccess := TestProfileAccessConstructor.New(&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},
|
||||
@@ -722,9 +721,9 @@ func BenchmarkProfileStorage_NewProfile(b *testing.B) {
|
||||
profileStorage := &ProfileStorage{
|
||||
logger: TestLogger,
|
||||
baseCustomLogger: TestLogger,
|
||||
profAccessCons: TestProfileAccessConstructor,
|
||||
bindSet: TestBind,
|
||||
errColl: agdtest.NewErrorCollector(),
|
||||
profileMetrics: access.EmptyProfileMetrics{},
|
||||
grpcMetrics: EmptyGRPCMetrics{},
|
||||
metrics: EmptyProfileDBMetrics{},
|
||||
respSzEst: TestRespSzEst,
|
||||
@@ -743,9 +742,9 @@ func BenchmarkProfileStorage_NewProfile(b *testing.B) {
|
||||
|
||||
// Most recent results:
|
||||
//
|
||||
// goos: darwin
|
||||
// goarch: arm64
|
||||
// goos: linux
|
||||
// goarch: amd64
|
||||
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/backendpb
|
||||
// cpu: Apple M1 Pro
|
||||
// BenchmarkProfileStorage_NewProfile-8 69070 16238 ns/op 3864 B/op 75 allocs/op
|
||||
// cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
|
||||
// BenchmarkProfileStorage_NewProfile-16 98218 18425 ns/op 4008 B/op 76 allocs/op
|
||||
}
|
||||
|
||||
@@ -70,13 +70,14 @@ func TestProfileStorage_CreateAutoDevice(t *testing.T) {
|
||||
endpoint := runLocalGRPCServer(t, grpcSrv)
|
||||
|
||||
s, err := backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
|
||||
BindSet: backendpb.TestBind,
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
Logger: backendpb.TestLogger,
|
||||
BaseCustomLogger: backendpb.TestLogger,
|
||||
GRPCMetrics: backendpb.EmptyGRPCMetrics{},
|
||||
Metrics: backendpb.EmptyProfileDBMetrics{},
|
||||
Endpoint: endpoint,
|
||||
Logger: backendpb.TestLogger,
|
||||
BaseCustomLogger: backendpb.TestLogger,
|
||||
Endpoint: endpoint,
|
||||
ProfileAccessConstructor: backendpb.TestProfileAccessConstructor,
|
||||
BindSet: backendpb.TestBind,
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
GRPCMetrics: backendpb.EmptyGRPCMetrics{},
|
||||
Metrics: backendpb.EmptyProfileDBMetrics{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -140,17 +141,18 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
|
||||
require.NoError(b, err)
|
||||
|
||||
s, err := backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
|
||||
BindSet: netip.MustParsePrefix("0.0.0.0/0"),
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
Logger: backendpb.TestLogger,
|
||||
BaseCustomLogger: backendpb.TestLogger,
|
||||
GRPCMetrics: backendpb.EmptyGRPCMetrics{},
|
||||
Metrics: backendpb.EmptyProfileDBMetrics{},
|
||||
Endpoint: &url.URL{
|
||||
Scheme: "grpc",
|
||||
Host: l.Addr().String(),
|
||||
},
|
||||
MaxProfilesSize: 1 * datasize.MB,
|
||||
ProfileAccessConstructor: backendpb.TestProfileAccessConstructor,
|
||||
BindSet: netip.MustParsePrefix("0.0.0.0/0"),
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
GRPCMetrics: backendpb.EmptyGRPCMetrics{},
|
||||
Metrics: backendpb.EmptyProfileDBMetrics{},
|
||||
MaxProfilesSize: 1 * datasize.MB,
|
||||
})
|
||||
require.NoError(b, err)
|
||||
|
||||
@@ -187,5 +189,5 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
|
||||
// goarch: amd64
|
||||
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/backendpb
|
||||
// cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
|
||||
// BenchmarkProfileStorage_Profiles-16 3982 322718 ns/op 21769 B/op 388 allocs/op
|
||||
// BenchmarkProfileStorage_Profiles-16 6260 177333 ns/op 22001 B/op 388 allocs/op
|
||||
}
|
||||
|
||||
@@ -2,9 +2,13 @@ package backendpb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"maps"
|
||||
"net/url"
|
||||
"slices"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
|
||||
"github.com/AdguardTeam/golibs/timeutil"
|
||||
@@ -91,8 +95,52 @@ func (ts *TicketStorage) Tickets(
|
||||
}
|
||||
|
||||
tickets, err = ts.ticketsToInternal(ctx, resp.GetTickets())
|
||||
|
||||
ts.logger.DebugContext(ctx, "loaded session tickets", "count", len(tickets))
|
||||
if err != nil {
|
||||
return tickets, fmt.Errorf("converting: %w", err)
|
||||
}
|
||||
|
||||
return tickets, err
|
||||
ts.metrics.SetTicketsState(ctx, calcTicketsHash(tickets))
|
||||
|
||||
return tickets, nil
|
||||
}
|
||||
|
||||
// calcTicketsHash calculates a hash of the tickets and returns a part of it as
|
||||
// a float64 number. Returns 0 if there are no tickets.
|
||||
func calcTicketsHash(tickets tlsconfig.NamedTickets) (num float64) {
|
||||
if len(tickets) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Start a new SHA256 hash sum.
|
||||
h := sha256.New()
|
||||
|
||||
// Add each ticket's data to the hash sum. The errors are ignored, because
|
||||
// [hash.Hash] never returns an error.
|
||||
// NOTE: Sorted by name, as strings, so "ticket_10" goes before "ticket_2".
|
||||
for _, name := range slices.Sorted(maps.Keys(tickets)) {
|
||||
// NOTE: Name first, data second, with no separators between them.
|
||||
_, _ = h.Write([]byte(name))
|
||||
|
||||
data := tickets[name]
|
||||
_, _ = h.Write(data[:])
|
||||
}
|
||||
|
||||
hashData := h.Sum(nil)
|
||||
|
||||
// Now, the bytes that will become our uint64 and then float64.
|
||||
//
|
||||
// NOTE: Java will have to use a long signed integer here and below, but
|
||||
// since we only use 48 bits, there should be no signedness issues.
|
||||
intData := make([]byte, 8)
|
||||
|
||||
// Copy the first six bytes to the least significant bytes of the integer
|
||||
// data to prevent signedness issues.
|
||||
copy(intData[2:8], hashData[0:6])
|
||||
|
||||
// Since we only use 48 bits, the integer should fit into a float64 (aka
|
||||
// double in Java) with no issues.
|
||||
num = float64(binary.BigEndian.Uint64(intData))
|
||||
|
||||
return num
|
||||
}
|
||||
|
||||
41
internal/backendpb/ticketstorage_internal_test.go
Normal file
41
internal/backendpb/ticketstorage_internal_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package backendpb
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTicketStorage_CalcTicketsHash(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := []struct {
|
||||
tickets tlsconfig.NamedTickets
|
||||
name string
|
||||
want float64
|
||||
}{{
|
||||
tickets: tlsconfig.NamedTickets{
|
||||
"foo": tlsconfig.SessionTicket{1, 2, 3, 4},
|
||||
"bar": tlsconfig.SessionTicket{5, 6, 7, 8},
|
||||
},
|
||||
name: "data",
|
||||
want: 2.5599110696847e+14,
|
||||
}, {
|
||||
tickets: tlsconfig.NamedTickets{"foo": tlsconfig.SessionTicket{}},
|
||||
name: "no_data",
|
||||
want: 1.76700443131662e+14,
|
||||
}, {
|
||||
tickets: tlsconfig.NamedTickets{},
|
||||
name: "no_tickets",
|
||||
want: 0,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, tc.want, calcTicketsHash(tc.tickets))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ func TestTicketStorage_Tickets(t *testing.T) {
|
||||
const badTicketName tlsconfig.SessionTicketName = "test/ticket"
|
||||
badTicketData := []byte{1, 2, 3, 4}
|
||||
|
||||
const wantErrMsg = `loaded session ticket: ` +
|
||||
const wantErrMsg = `converting: loaded session ticket: ` +
|
||||
`at index 1: str: at index 4: bad rune '/'` + "\n" +
|
||||
`ticket: length: out of range: must be no less than 32, got 4`
|
||||
|
||||
|
||||
41
internal/bindtodevice/bindtodevice_linux_internal_test.go
Normal file
41
internal/bindtodevice/bindtodevice_linux_internal_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
//go:build linux
|
||||
|
||||
package bindtodevice
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// newTestChanListener is a helper for creating a *chanListener for tests.
|
||||
func newTestChanListener(tb testing.TB, conns chan net.Conn) (l *chanListener) {
|
||||
tb.Helper()
|
||||
|
||||
l = newChanListener(EmptyMetrics{}, conns, testSubnetIPv4, testLAddr)
|
||||
require.NotNil(tb, l)
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// newTestChanPacketConn is a helper for creating a *chanPacketConn for tests.
|
||||
func newTestChanPacketConn(
|
||||
tb testing.TB,
|
||||
sessions chan *packetSession,
|
||||
writeReqs chan *packetConnWriteReq,
|
||||
) (c *chanPacketConn) {
|
||||
tb.Helper()
|
||||
|
||||
c = newChanPacketConn(
|
||||
EmptyMetrics{},
|
||||
sessions,
|
||||
testSubnetIPv4,
|
||||
writeReqs,
|
||||
"",
|
||||
testLAddr,
|
||||
)
|
||||
require.NotNil(tb, c)
|
||||
|
||||
return c
|
||||
}
|
||||
@@ -3,12 +3,10 @@
|
||||
package bindtodevice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// chanListener is a [net.Listener] that returns data sent to it through a
|
||||
@@ -18,23 +16,29 @@ import (
|
||||
// module dnsserver to make the bind-to-device logic work in DNS-over-TCP.
|
||||
type chanListener struct {
|
||||
// mu protects conns (against closure) and isClosed.
|
||||
mu *sync.Mutex
|
||||
conns chan net.Conn
|
||||
connsGauge prometheus.Gauge
|
||||
laddr net.Addr
|
||||
subnet netip.Prefix
|
||||
isClosed bool
|
||||
mu *sync.Mutex
|
||||
conns chan net.Conn
|
||||
metrics Metrics
|
||||
laddr net.Addr
|
||||
subnet netip.Prefix
|
||||
isClosed bool
|
||||
}
|
||||
|
||||
// newChanListener returns a new properly initialized *chanListener.
|
||||
func newChanListener(conns chan net.Conn, subnet netip.Prefix, laddr net.Addr) (l *chanListener) {
|
||||
// newChanListener returns a new properly initialized *chanListener. mtrc must
|
||||
// not be nil.
|
||||
func newChanListener(
|
||||
mtrc Metrics,
|
||||
conns chan net.Conn,
|
||||
subnet netip.Prefix,
|
||||
laddr net.Addr,
|
||||
) (l *chanListener) {
|
||||
return &chanListener{
|
||||
mu: &sync.Mutex{},
|
||||
conns: conns,
|
||||
connsGauge: metrics.BindToDeviceTCPConnsChanSize.WithLabelValues(subnet.String()),
|
||||
laddr: laddr,
|
||||
subnet: subnet,
|
||||
isClosed: false,
|
||||
mu: &sync.Mutex{},
|
||||
conns: conns,
|
||||
metrics: mtrc,
|
||||
laddr: laddr,
|
||||
subnet: subnet,
|
||||
isClosed: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +76,7 @@ func (l *chanListener) Close() (err error) {
|
||||
|
||||
// send is a helper method to send a conn to the listener's channel. ok is
|
||||
// false if the listener is closed.
|
||||
func (l *chanListener) send(conn net.Conn) (ok bool) {
|
||||
func (l *chanListener) send(ctx context.Context, conn net.Conn) (ok bool) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
@@ -82,7 +86,7 @@ func (l *chanListener) send(conn net.Conn) (ok bool) {
|
||||
|
||||
l.conns <- conn
|
||||
|
||||
l.connsGauge.Set(float64(len(l.conns)))
|
||||
l.metrics.SetTCPConnsChanSize(ctx, l.subnet, uint(len(l.conns)))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func TestChanListener_Accept(t *testing.T) {
|
||||
conns := make(chan net.Conn, 1)
|
||||
l := newChanListener(conns, testSubnetIPv4, testLAddr)
|
||||
l := newTestChanListener(t, conns)
|
||||
|
||||
// A simple way to have a distinct net.Conn without actually implementing
|
||||
// the entire interface.
|
||||
@@ -32,14 +32,14 @@ func TestChanListener_Accept(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestChanListener_Addr(t *testing.T) {
|
||||
l := newChanListener(nil, testSubnetIPv4, testLAddr)
|
||||
l := newTestChanListener(t, nil)
|
||||
got := l.Addr()
|
||||
assert.Equal(t, testLAddr, got)
|
||||
}
|
||||
|
||||
func TestChanListener_Close(t *testing.T) {
|
||||
conns := make(chan net.Conn)
|
||||
l := newChanListener(conns, testSubnetIPv4, testLAddr)
|
||||
l := newTestChanListener(t, conns)
|
||||
err := l.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package bindtodevice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
@@ -11,8 +12,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/netext"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// chanPacketConn is a [netext.SessionPacketConn] that returns data sent to it
|
||||
@@ -28,25 +27,27 @@ type chanPacketConn struct {
|
||||
|
||||
writeRequests chan *packetConnWriteReq
|
||||
|
||||
sessionsGauge prometheus.Gauge
|
||||
writeRequestsGauge prometheus.Gauge
|
||||
metrics Metrics
|
||||
|
||||
// deadlineMu protects readDeadline and writeDeadline.
|
||||
deadlineMu *sync.RWMutex
|
||||
readDeadline time.Time
|
||||
writeDeadline time.Time
|
||||
|
||||
laddr net.Addr
|
||||
subnet netip.Prefix
|
||||
isClosed bool
|
||||
laddr net.Addr
|
||||
subnet netip.Prefix
|
||||
ifaceName string
|
||||
isClosed bool
|
||||
}
|
||||
|
||||
// newChanPacketConn returns a new properly initialized *chanPacketConn.
|
||||
// newChanPacketConn returns a new properly initialized *chanPacketConn. mtrc
|
||||
// must not be nil.
|
||||
func newChanPacketConn(
|
||||
mtrc Metrics,
|
||||
sessions chan *packetSession,
|
||||
subnet netip.Prefix,
|
||||
writeRequests chan *packetConnWriteReq,
|
||||
writeRequestsGauge prometheus.Gauge,
|
||||
ifaceName string,
|
||||
laddr net.Addr,
|
||||
) (c *chanPacketConn) {
|
||||
return &chanPacketConn{
|
||||
@@ -54,15 +55,14 @@ func newChanPacketConn(
|
||||
sessions: sessions,
|
||||
writeRequests: writeRequests,
|
||||
|
||||
sessionsGauge: metrics.BindToDeviceUDPSessionsChanSize.WithLabelValues(
|
||||
subnet.String(),
|
||||
),
|
||||
writeRequestsGauge: writeRequestsGauge,
|
||||
metrics: mtrc,
|
||||
|
||||
deadlineMu: &sync.RWMutex{},
|
||||
|
||||
laddr: laddr,
|
||||
subnet: subnet,
|
||||
|
||||
ifaceName: ifaceName,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +281,8 @@ func (c *chanPacketConn) writeToSession(
|
||||
return 0, wrapConnError(tnChanPConn, fnName, c.laddr, err)
|
||||
}
|
||||
|
||||
c.writeRequestsGauge.Set(float64(len(c.writeRequests)))
|
||||
// TODO(s.chzhen): Pass context.
|
||||
c.metrics.SetUDPWriteRequestsChanSize(context.TODO(), c.ifaceName, uint(len(c.writeRequests)))
|
||||
|
||||
r, err := receiveWithTimer(resp, timerCh)
|
||||
if err != nil {
|
||||
@@ -325,7 +326,7 @@ func sendWithTimer[T any](ch chan<- T, v T, timerCh <-chan time.Time) (err error
|
||||
|
||||
// send is a helper method to send a session to the packet connection's channel.
|
||||
// ok is false if the listener is closed.
|
||||
func (c *chanPacketConn) send(sess *packetSession) (ok bool) {
|
||||
func (c *chanPacketConn) send(ctx context.Context, sess *packetSession) (ok bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
@@ -335,7 +336,7 @@ func (c *chanPacketConn) send(sess *packetSession) (ok bool) {
|
||||
|
||||
c.sessions <- sess
|
||||
|
||||
c.sessionsGauge.Set(float64(len(c.sessions)))
|
||||
c.metrics.SetUDPSessionsChanSize(ctx, c.subnet, uint(len(c.sessions)))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -8,14 +8,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestChanPacketConn_Close(t *testing.T) {
|
||||
sessions := make(chan *packetSession)
|
||||
c := newChanPacketConn(sessions, testSubnetIPv4, nil, nil, testLAddr)
|
||||
c := newTestChanPacketConn(t, sessions, nil)
|
||||
err := c.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -24,14 +23,14 @@ func TestChanPacketConn_Close(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestChanPacketConn_LocalAddr(t *testing.T) {
|
||||
c := newChanPacketConn(nil, testSubnetIPv4, nil, nil, testLAddr)
|
||||
c := newTestChanPacketConn(t, nil, nil)
|
||||
got := c.LocalAddr()
|
||||
assert.Equal(t, testLAddr, got)
|
||||
}
|
||||
|
||||
func TestChanPacketConn_ReadFromSession(t *testing.T) {
|
||||
sessions := make(chan *packetSession, 1)
|
||||
c := newChanPacketConn(sessions, testSubnetIPv4, nil, nil, testLAddr)
|
||||
c := newTestChanPacketConn(t, sessions, nil)
|
||||
|
||||
body := []byte("hello")
|
||||
bodyLen := len(body)
|
||||
@@ -81,8 +80,7 @@ func TestChanPacketConn_WriteToSession(t *testing.T) {
|
||||
sessions := make(chan *packetSession, 1)
|
||||
writes := make(chan *packetConnWriteReq, 1)
|
||||
|
||||
gauge := prometheus.NewGauge(prometheus.GaugeOpts{})
|
||||
c := newChanPacketConn(sessions, testSubnetIPv4, writes, gauge, testLAddr)
|
||||
c := newTestChanPacketConn(t, sessions, writes)
|
||||
|
||||
body := []byte("hello")
|
||||
bodyLen := len(body)
|
||||
@@ -151,7 +149,7 @@ func checkWriteReqAndRespond(
|
||||
}
|
||||
|
||||
func TestChanPacketConn_deadlines(t *testing.T) {
|
||||
c := newChanPacketConn(nil, testSubnetIPv4, nil, nil, testLAddr)
|
||||
c := newTestChanPacketConn(t, nil, nil)
|
||||
deadline := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
testCases := []struct {
|
||||
|
||||
@@ -10,29 +10,26 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/syncutil"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// interfaceListener contains information about a single interface listener.
|
||||
type interfaceListener struct {
|
||||
logger *slog.Logger
|
||||
conns *connIndex
|
||||
listenConf *net.ListenConfig
|
||||
bodyPool *syncutil.Pool[[]byte]
|
||||
oobPool *syncutil.Pool[[]byte]
|
||||
writeRequests chan *packetConnWriteReq
|
||||
done chan unit
|
||||
errColl errcoll.Interface
|
||||
writeRequestsGauge prometheus.Gauge
|
||||
writeDurationHist prometheus.Observer
|
||||
ifaceName string
|
||||
port uint16
|
||||
logger *slog.Logger
|
||||
conns *connIndex
|
||||
listenConf *net.ListenConfig
|
||||
bodyPool *syncutil.Pool[[]byte]
|
||||
oobPool *syncutil.Pool[[]byte]
|
||||
writeRequests chan *packetConnWriteReq
|
||||
done chan unit
|
||||
errColl errcoll.Interface
|
||||
metrics Metrics
|
||||
ifaceName string
|
||||
port uint16
|
||||
}
|
||||
|
||||
// listenTCP runs the TCP listening loop. It is intended to be used as a
|
||||
@@ -80,14 +77,14 @@ func (l *interfaceListener) processConn(ctx context.Context, logger *slog.Logger
|
||||
laddr := netutil.NetAddrToAddrPort(conn.LocalAddr())
|
||||
raddr := conn.RemoteAddr()
|
||||
if lsnr := l.conns.listener(laddr.Addr()); lsnr != nil {
|
||||
if !lsnr.send(conn) {
|
||||
if !lsnr.send(ctx, conn) {
|
||||
optslog.Debug2(ctx, logger, "channel is closed", "raddr", raddr, "laddr", laddr)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
metrics.BindToDeviceUnknownTCPRequestsTotal.Inc()
|
||||
l.metrics.IncrementUnknownTCPRequests(ctx)
|
||||
|
||||
optslog.Debug2(ctx, logger, "no stream channel", "raddr", raddr, "laddr", laddr)
|
||||
|
||||
@@ -171,14 +168,14 @@ func (l *interfaceListener) readUDP(
|
||||
laddr := sess.laddr.AddrPort().Addr()
|
||||
chanPacketConn := l.conns.packetConn(laddr)
|
||||
if chanPacketConn == nil {
|
||||
metrics.BindToDeviceUnknownUDPRequestsTotal.Inc()
|
||||
l.metrics.IncrementUnknownUDPRequests(ctx)
|
||||
|
||||
optslog.Debug2(ctx, logger, "no packet channel", "raddr", sess.raddr, "laddr", laddr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if !chanPacketConn.send(sess) {
|
||||
if !chanPacketConn.send(ctx, sess) {
|
||||
optslog.Debug1(ctx, logger, "channel is closed", "laddr", laddr)
|
||||
}
|
||||
|
||||
@@ -201,14 +198,14 @@ func (l *interfaceListener) writeUDPResponses(
|
||||
|
||||
return
|
||||
case req := <-l.writeRequests:
|
||||
l.writeUDP(c, req)
|
||||
l.writeUDP(ctx, c, req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// writeUDP handles a single write operation and writes a response to
|
||||
// req.respCh.
|
||||
func (l *interfaceListener) writeUDP(c *net.UDPConn, req *packetConnWriteReq) {
|
||||
func (l *interfaceListener) writeUDP(ctx context.Context, c *net.UDPConn, req *packetConnWriteReq) {
|
||||
resp := &packetConnWriteResp{}
|
||||
resp.err = c.SetWriteDeadline(req.deadline)
|
||||
if resp.err != nil {
|
||||
@@ -217,7 +214,7 @@ func (l *interfaceListener) writeUDP(c *net.UDPConn, req *packetConnWriteReq) {
|
||||
return
|
||||
}
|
||||
|
||||
l.writeToUDPConn(c, req, resp)
|
||||
l.writeToUDPConn(ctx, c, req, resp)
|
||||
|
||||
resetDeadlineErr := c.SetWriteDeadline(time.Time{})
|
||||
resp.err = errors.WithDeferred(resp.err, resetDeadlineErr)
|
||||
@@ -228,12 +225,15 @@ func (l *interfaceListener) writeUDP(c *net.UDPConn, req *packetConnWriteReq) {
|
||||
// writeToUDPConn writes to c, depending on what kind of session req contains,
|
||||
// and sets resp.written and resp.err accordingly.
|
||||
func (l *interfaceListener) writeToUDPConn(
|
||||
ctx context.Context,
|
||||
c *net.UDPConn,
|
||||
req *packetConnWriteReq,
|
||||
resp *packetConnWriteResp,
|
||||
) {
|
||||
start := time.Now()
|
||||
defer func() { l.writeDurationHist.Observe(time.Since(start).Seconds()) }()
|
||||
defer func() {
|
||||
l.metrics.ObserveUDPWriteDuration(ctx, l.ifaceName, time.Since(start))
|
||||
}()
|
||||
|
||||
s := req.session
|
||||
if s == nil {
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
)
|
||||
|
||||
func TestListenConfig(t *testing.T) {
|
||||
pc := newChanPacketConn(nil, testSubnetIPv4, nil, nil, testLAddr)
|
||||
lsnr := newChanListener(nil, testSubnetIPv4, testLAddr)
|
||||
pc := newTestChanPacketConn(t, nil, nil)
|
||||
lsnr := newTestChanListener(t, nil)
|
||||
addr := &agdnet.PrefixNetAddr{
|
||||
Prefix: testSubnetIPv4,
|
||||
Net: "",
|
||||
|
||||
@@ -20,6 +20,9 @@ type ManagerConfig struct {
|
||||
// errors.
|
||||
ErrColl errcoll.Interface
|
||||
|
||||
// Metrics collects bindtodevice-related statistics. It must not be nil.
|
||||
Metrics Metrics
|
||||
|
||||
// ChannelBufferSize is the size of the buffers of the channels used to
|
||||
// dispatch TCP connections and UDP sessions.
|
||||
ChannelBufferSize int
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/netext"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/service"
|
||||
"github.com/AdguardTeam/golibs/syncutil"
|
||||
@@ -29,6 +28,7 @@ type Manager struct {
|
||||
closeOnce *sync.Once
|
||||
ifaceListeners map[ID]*interfaceListener
|
||||
errColl errcoll.Interface
|
||||
metrics Metrics
|
||||
done chan unit
|
||||
chanBufSize int
|
||||
}
|
||||
@@ -41,6 +41,7 @@ func NewManager(c *ManagerConfig) (m *Manager) {
|
||||
closeOnce: &sync.Once{},
|
||||
ifaceListeners: map[ID]*interfaceListener{},
|
||||
errColl: c.ErrColl,
|
||||
metrics: c.Metrics,
|
||||
done: make(chan unit),
|
||||
chanBufSize: c.ChannelBufferSize,
|
||||
}
|
||||
@@ -106,18 +107,17 @@ func (m *Manager) newInterfaceListener(
|
||||
port uint16,
|
||||
) (l *interfaceListener) {
|
||||
return &interfaceListener{
|
||||
logger: m.logger.With("iface", ifaceName, "port", port),
|
||||
conns: &connIndex{},
|
||||
listenConf: newListenConfig(ifaceName, ctrlConf),
|
||||
bodyPool: syncutil.NewSlicePool[byte](bodySize),
|
||||
oobPool: syncutil.NewSlicePool[byte](netext.IPDstOOBSize),
|
||||
writeRequests: make(chan *packetConnWriteReq, m.chanBufSize),
|
||||
done: m.done,
|
||||
errColl: m.errColl,
|
||||
writeRequestsGauge: metrics.BindToDeviceUDPWriteRequestsChanSize.WithLabelValues(ifaceName),
|
||||
writeDurationHist: metrics.BindToDeviceUDPWriteDurationSeconds.WithLabelValues(ifaceName),
|
||||
ifaceName: ifaceName,
|
||||
port: port,
|
||||
logger: m.logger.With("iface", ifaceName, "port", port),
|
||||
conns: &connIndex{},
|
||||
listenConf: newListenConfig(ifaceName, ctrlConf),
|
||||
bodyPool: syncutil.NewSlicePool[byte](bodySize),
|
||||
oobPool: syncutil.NewSlicePool[byte](netext.IPDstOOBSize),
|
||||
writeRequests: make(chan *packetConnWriteReq, m.chanBufSize),
|
||||
done: m.done,
|
||||
errColl: m.errColl,
|
||||
metrics: m.metrics,
|
||||
ifaceName: ifaceName,
|
||||
port: port,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ func (m *Manager) ListenConfig(id ID, subnet netip.Prefix) (c *ListenConfig, err
|
||||
}
|
||||
|
||||
lsnrCh := make(chan net.Conn, m.chanBufSize)
|
||||
lsnr := newChanListener(lsnrCh, subnet, &agdnet.PrefixNetAddr{
|
||||
lsnr := newChanListener(m.metrics, lsnrCh, subnet, &agdnet.PrefixNetAddr{
|
||||
Prefix: subnet,
|
||||
Net: "tcp",
|
||||
Port: l.port,
|
||||
@@ -160,10 +160,11 @@ func (m *Manager) ListenConfig(id ID, subnet netip.Prefix) (c *ListenConfig, err
|
||||
|
||||
sessCh := make(chan *packetSession, m.chanBufSize)
|
||||
pConn := newChanPacketConn(
|
||||
m.metrics,
|
||||
sessCh,
|
||||
subnet,
|
||||
l.writeRequests,
|
||||
l.writeRequestsGauge,
|
||||
l.ifaceName,
|
||||
&agdnet.PrefixNetAddr{
|
||||
Prefix: subnet,
|
||||
Net: "udp",
|
||||
|
||||
@@ -3,15 +3,17 @@
|
||||
package bindtodevice_test
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/bindtodevice"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/AdguardTeam/golibs/testutil/servicetest"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -47,18 +49,36 @@ func (iface *fakeInterface) Subnets() (subnets []netip.Prefix, err error) {
|
||||
return iface.OnSubnets()
|
||||
}
|
||||
|
||||
func TestManager_Add(t *testing.T) {
|
||||
m := bindtodevice.NewManager(&bindtodevice.ManagerConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
InterfaceStorage: &fakeInterfaceStorage{
|
||||
// newTestManager is a helper for creating a [bindtodevice.Manager] for tests.
|
||||
// c may be nil, and all zero-value fields in c are replaced with test defaults.
|
||||
func newTestManager(tb testing.TB, c *bindtodevice.ManagerConfig) (m *bindtodevice.Manager) {
|
||||
tb.Helper()
|
||||
|
||||
c = cmp.Or(c, &bindtodevice.ManagerConfig{})
|
||||
|
||||
c.Logger = cmp.Or(c.Logger, slogutil.NewDiscardLogger())
|
||||
|
||||
c.InterfaceStorage = cmp.Or[bindtodevice.InterfaceStorage](
|
||||
c.InterfaceStorage,
|
||||
&fakeInterfaceStorage{
|
||||
OnInterfaceByName: func(_ string) (iface bindtodevice.NetInterface, err error) {
|
||||
return nil, nil
|
||||
},
|
||||
},
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
ChannelBufferSize: 1,
|
||||
})
|
||||
require.NotNil(t, m)
|
||||
)
|
||||
|
||||
c.ErrColl = cmp.Or[errcoll.Interface](c.ErrColl, agdtest.NewErrorCollector())
|
||||
c.Metrics = cmp.Or[bindtodevice.Metrics](c.Metrics, bindtodevice.EmptyMetrics{})
|
||||
c.ChannelBufferSize = cmp.Or(c.ChannelBufferSize, 1)
|
||||
|
||||
m = bindtodevice.NewManager(c)
|
||||
require.NotNil(tb, m)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func TestManager_Add(t *testing.T) {
|
||||
m := newTestManager(t, nil)
|
||||
|
||||
// Don't use a table, since the results of these subtests depend on each
|
||||
// other.
|
||||
@@ -91,17 +111,13 @@ func TestManager_ListenConfig(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
m := bindtodevice.NewManager(&bindtodevice.ManagerConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
m := newTestManager(t, &bindtodevice.ManagerConfig{
|
||||
InterfaceStorage: &fakeInterfaceStorage{
|
||||
OnInterfaceByName: func(_ string) (iface bindtodevice.NetInterface, err error) {
|
||||
return ifaceWithSubnet, nil
|
||||
},
|
||||
},
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
ChannelBufferSize: 1,
|
||||
})
|
||||
require.NotNil(t, m)
|
||||
|
||||
err := m.Add(testID1, testIfaceName, testPort1, nil)
|
||||
require.NoError(t, err)
|
||||
@@ -140,17 +156,13 @@ func TestManager_ListenConfig(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
noSubnetMgr := bindtodevice.NewManager(&bindtodevice.ManagerConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
noSubnetMgr := newTestManager(t, &bindtodevice.ManagerConfig{
|
||||
InterfaceStorage: &fakeInterfaceStorage{
|
||||
OnInterfaceByName: func(_ string) (iface bindtodevice.NetInterface, err error) {
|
||||
return ifaceWithoutSubnet, nil
|
||||
},
|
||||
},
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
ChannelBufferSize: 1,
|
||||
})
|
||||
require.NotNil(t, noSubnetMgr)
|
||||
|
||||
subTestErr := noSubnetMgr.Add(testID1, testIfaceName, testPort1, nil)
|
||||
require.NoError(t, subTestErr)
|
||||
@@ -169,17 +181,13 @@ func TestManager_ListenConfig(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
narrowSubnetMgr := bindtodevice.NewManager(&bindtodevice.ManagerConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
narrowSubnetMgr := newTestManager(t, &bindtodevice.ManagerConfig{
|
||||
InterfaceStorage: &fakeInterfaceStorage{
|
||||
OnInterfaceByName: func(_ string) (iface bindtodevice.NetInterface, err error) {
|
||||
return ifaceWithNarrowerSubnet, nil
|
||||
},
|
||||
},
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
ChannelBufferSize: 1,
|
||||
})
|
||||
require.NotNil(t, narrowSubnetMgr)
|
||||
|
||||
subTestErr := narrowSubnetMgr.Add(testID1, testIfaceName, testPort1, nil)
|
||||
require.NoError(t, subTestErr)
|
||||
@@ -202,13 +210,7 @@ func TestManager(t *testing.T) {
|
||||
|
||||
ifaceName := iface.Name
|
||||
|
||||
m := bindtodevice.NewManager(&bindtodevice.ManagerConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
InterfaceStorage: bindtodevice.DefaultInterfaceStorage{},
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
ChannelBufferSize: 1,
|
||||
})
|
||||
require.NotNil(t, m)
|
||||
m := newTestManager(t, nil)
|
||||
|
||||
// TODO(a.garipov): Add support for zero port.
|
||||
err := m.Add(testID1, ifaceName, testPort1, nil)
|
||||
@@ -226,11 +228,7 @@ func TestManager(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, lc)
|
||||
|
||||
err = m.Start(testutil.ContextWithTimeout(t, testTimeout))
|
||||
require.NoError(t, err)
|
||||
testutil.CleanupAndRequireSuccess(t, func() (err error) {
|
||||
return m.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
|
||||
})
|
||||
servicetest.RequireRun(t, m, testTimeout)
|
||||
|
||||
t.Run("tcp", func(t *testing.T) {
|
||||
bindtodevice.SubtestListenControlTCP(t, lc, ifaceName, ifaceNet)
|
||||
|
||||
62
internal/bindtodevice/metrics.go
Normal file
62
internal/bindtodevice/metrics.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package bindtodevice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Metrics is an interface for collecting bindtodevice-related statistics.
|
||||
type Metrics interface {
|
||||
// IncrementUnknownTCPRequests increments the counter for TCP requests to
|
||||
// unknown local address.
|
||||
IncrementUnknownTCPRequests(ctx context.Context)
|
||||
|
||||
// IncrementUnknownUDPRequests increments the counter for UDP requests to
|
||||
// unknown local address.
|
||||
IncrementUnknownUDPRequests(ctx context.Context)
|
||||
|
||||
// SetTCPConnsChanSize sets the current number of TCP connections in the
|
||||
// channel by subnet.
|
||||
SetTCPConnsChanSize(ctx context.Context, subnet netip.Prefix, n uint)
|
||||
|
||||
// SetUDPConnsChanSize sets the current number of UDP connections in the
|
||||
// channel by subnet.
|
||||
SetUDPSessionsChanSize(ctx context.Context, subnet netip.Prefix, n uint)
|
||||
|
||||
// SetUDPWriteRequestsChanSize sets the current number of UDP write requests
|
||||
// in the channel by interface name.
|
||||
SetUDPWriteRequestsChanSize(ctx context.Context, name string, n uint)
|
||||
|
||||
// ObserveUDPWriteDuration observes the duration of a UDP write operation by
|
||||
// interface name.
|
||||
ObserveUDPWriteDuration(ctx context.Context, name string, dur time.Duration)
|
||||
}
|
||||
|
||||
// EmptyMetrics is the implementation of the [Metrics] interface that does
|
||||
// nothing.
|
||||
type EmptyMetrics struct{}
|
||||
|
||||
// type check
|
||||
var _ Metrics = EmptyMetrics{}
|
||||
|
||||
// IncrementUnknownTCPRequests implements the [Metrics] interface for
|
||||
// EmptyMetrics.
|
||||
func (EmptyMetrics) IncrementUnknownTCPRequests(_ context.Context) {}
|
||||
|
||||
// IncrementUnknownUDPRequests implements the [Metrics] interface for
|
||||
// EmptyMetrics.
|
||||
func (EmptyMetrics) IncrementUnknownUDPRequests(_ context.Context) {}
|
||||
|
||||
// SetTCPConnsChanSize implements the [Metrics] interface for EmptyMetrics.
|
||||
func (EmptyMetrics) SetTCPConnsChanSize(_ context.Context, _ netip.Prefix, _ uint) {}
|
||||
|
||||
// SetUDPSessionsChanSize implements the [Metrics] interface for EmptyMetrics.
|
||||
func (EmptyMetrics) SetUDPSessionsChanSize(_ context.Context, _ netip.Prefix, _ uint) {}
|
||||
|
||||
// SetUDPWriteRequestsChanSize implements the [Metrics] interface for
|
||||
// EmptyMetrics.
|
||||
func (EmptyMetrics) SetUDPWriteRequestsChanSize(_ context.Context, _ string, _ uint) {}
|
||||
|
||||
// ObserveUDPWriteDuration implements the [Metrics] interface for EmptyMetrics.
|
||||
func (EmptyMetrics) ObserveUDPWriteDuration(_ context.Context, _ string, _ time.Duration) {}
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/access"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdrand"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/billstat"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/bindtodevice"
|
||||
@@ -46,6 +45,7 @@ import (
|
||||
"github.com/AdguardTeam/golibs/contextutil"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/mathutil/randutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||
"github.com/AdguardTeam/golibs/osutil"
|
||||
@@ -57,15 +57,16 @@ import (
|
||||
|
||||
// Constants that define debug identifiers for the debug HTTP service.
|
||||
const (
|
||||
debugIDAllowlist = "allowlist"
|
||||
debugIDBillStat = "billstat"
|
||||
debugIDGeoIP = "geoip"
|
||||
debugIDProfileDB = "profiledb"
|
||||
debugIDProfileDBFull = "profiledb_full"
|
||||
debugIDRuleStat = "rulestat"
|
||||
debugIDTicketRotator = "ticket_rotator"
|
||||
debugIDTLSConfig = "tlsconfig"
|
||||
debugIDWebSvc = "websvc"
|
||||
debugIDAllowlist = "allowlist"
|
||||
debugIDBillStat = "billstat"
|
||||
debugIDCustomDomainDB = "custom_domain_db"
|
||||
debugIDGeoIP = "geoip"
|
||||
debugIDProfileDB = "profiledb"
|
||||
debugIDProfileDBFull = "profiledb_full"
|
||||
debugIDRuleStat = "rulestat"
|
||||
debugIDTLSConfig = "tlsconfig"
|
||||
debugIDTicketRotator = "ticket_rotator"
|
||||
debugIDWebSvc = "websvc"
|
||||
|
||||
// debugIDPrefixPlugin is the prefix for plugin debug identifiers.
|
||||
debugIDPrefixPlugin = "plugin/"
|
||||
@@ -100,38 +101,41 @@ type builder struct {
|
||||
// The fields below are initialized later by calling the builder's methods.
|
||||
// Keep them sorted.
|
||||
|
||||
access *access.Global
|
||||
adultBlocking *hashprefix.Filter
|
||||
adultBlockingHashes *hashprefix.Storage
|
||||
backendGRPCMtrc *metrics.BackendGRPC
|
||||
billStat billstat.Recorder
|
||||
bindSet netutil.SubnetSet
|
||||
btdManager *bindtodevice.Manager
|
||||
cloner *dnsmsg.Cloner
|
||||
connLimit *connlimiter.Limiter
|
||||
controlConf *netext.ControlConfig
|
||||
customDomainDB profiledb.CustomDomainDB
|
||||
dnsCheck dnscheck.Interface
|
||||
dnsDB dnsdb.Interface
|
||||
dnsSvc *dnssvc.Service
|
||||
filterMtrc filter.Metrics
|
||||
filterStorage *filterstorage.Default
|
||||
filteringGroups map[agd.FilteringGroupID]*agd.FilteringGroup
|
||||
fwdHandler *forward.Handler
|
||||
geoIP *geoip.File
|
||||
hashMatcher *hashprefix.Matcher
|
||||
messages *dnsmsg.Constructor
|
||||
newRegDomains *hashprefix.Filter
|
||||
newRegDomainsHashes *hashprefix.Storage
|
||||
profileDB profiledb.Interface
|
||||
queryLog querylog.Interface
|
||||
rateLimit *ratelimit.Backoff
|
||||
ruleStat rulestat.Interface
|
||||
safeBrowsing *hashprefix.Filter
|
||||
safeBrowsingHashes *hashprefix.Storage
|
||||
sdeConf *dnsmsg.StructuredDNSErrorsConfig
|
||||
tlsManager *tlsconfig.DefaultManager
|
||||
webSvc *websvc.Service
|
||||
access *access.Global
|
||||
adultBlocking *hashprefix.Filter
|
||||
adultBlockingHashes *hashprefix.Storage
|
||||
backendGRPCMtrc backendpb.GRPCMetrics
|
||||
billStat billstat.Recorder
|
||||
bindSet netutil.SubnetSet
|
||||
btdManager *bindtodevice.Manager
|
||||
cloner *dnsmsg.Cloner
|
||||
connLimit *connlimiter.Limiter
|
||||
controlConf *netext.ControlConfig
|
||||
customDomainDB *tlsconfig.CustomDomainDB
|
||||
dnsCheck dnscheck.Interface
|
||||
dnsDB dnsdb.Interface
|
||||
dnsSvc *dnssvc.Service
|
||||
dnsSvcCustomDomainDB dnssvc.CustomDomainDB
|
||||
filterMtrc filter.Metrics
|
||||
filterStorage *filterstorage.Default
|
||||
filteringGroups map[agd.FilteringGroupID]*agd.FilteringGroup
|
||||
fwdHandler *forward.Handler
|
||||
geoIP *geoip.File
|
||||
hashMatcher *hashprefix.Matcher
|
||||
messages *dnsmsg.Constructor
|
||||
newRegDomains *hashprefix.Filter
|
||||
newRegDomainsHashes *hashprefix.Storage
|
||||
profDBCustomDomainDB profiledb.CustomDomainDB
|
||||
profileDB profiledb.Interface
|
||||
queryLog querylog.Interface
|
||||
rateLimit *ratelimit.Backoff
|
||||
ruleStat rulestat.Interface
|
||||
safeBrowsing *hashprefix.Filter
|
||||
safeBrowsingHashes *hashprefix.Storage
|
||||
sdeConf *dnsmsg.StructuredDNSErrorsConfig
|
||||
tlsManager *tlsconfig.DefaultManager
|
||||
webSvc *websvc.Service
|
||||
webSvcCertValidator websvc.CertificateValidator
|
||||
|
||||
// The fields below are initialized later, just like with the fields above,
|
||||
// but are placed in this order for alignment optimization.
|
||||
@@ -375,12 +379,15 @@ func (b *builder) initAdultBlocking(
|
||||
Schedule: timeutil.NewConstSchedule(refrIvl),
|
||||
RefreshOnShutdown: false,
|
||||
})
|
||||
err = refr.Start(ctx)
|
||||
|
||||
// TODO(a.garipov, e.burkov): Consider using different context for child
|
||||
// routines.
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting refresher: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(refr)
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
matchers[filter.AdultBlockingTXTSuffix] = b.adultBlockingHashes
|
||||
|
||||
@@ -474,12 +481,12 @@ func (b *builder) initNewRegDomains(
|
||||
Schedule: timeutil.NewConstSchedule(refrIvl),
|
||||
RefreshOnShutdown: false,
|
||||
})
|
||||
err = refr.Start(ctx)
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting refresher: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(refr)
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
b.debugRefrs[prefix] = b.newRegDomains
|
||||
|
||||
@@ -560,12 +567,12 @@ func (b *builder) initSafeBrowsing(
|
||||
Schedule: timeutil.NewConstSchedule(refrIvl),
|
||||
RefreshOnShutdown: false,
|
||||
})
|
||||
err = refr.Start(ctx)
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting refresher: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(refr)
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
matchers[filter.GeneralTXTSuffix] = b.safeBrowsingHashes
|
||||
|
||||
@@ -659,12 +666,12 @@ func (b *builder) initFilterStorage(ctx context.Context) (err error) {
|
||||
Schedule: timeutil.NewConstSchedule(refrIvl),
|
||||
RefreshOnShutdown: false,
|
||||
})
|
||||
err = refr.Start(ctx)
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting default filter storage update: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(refr)
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
b.debugRefrs[filter.StoragePrefix] = b.filterStorage
|
||||
|
||||
@@ -691,7 +698,7 @@ func (b *builder) newSafeSearchConfig(
|
||||
ID: id,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
MaxSize: fltConf.MaxSize,
|
||||
// TODO(a.garipov): Consider making this configurable.
|
||||
// TODO(a.garipov): Consider making configurable.
|
||||
ResultCacheTTL: 1 * time.Hour,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
RefreshTimeout: time.Duration(fltConf.RefreshTimeout),
|
||||
@@ -736,9 +743,14 @@ func (b *builder) initAccess(ctx context.Context) (err error) {
|
||||
func (b *builder) initBindToDevice(ctx context.Context) (err error) {
|
||||
c := b.conf
|
||||
|
||||
mtrc, err := metrics.NewBindToDevice(b.mtrcNamespace, b.promRegisterer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("registering bindtodevice metrics: %w", err)
|
||||
}
|
||||
|
||||
var btdCtrlConf *bindtodevice.ControlConfig
|
||||
btdCtrlConf, b.controlConf = c.Network.toInternal()
|
||||
b.btdManager, err = c.InterfaceListeners.toInternal(b.baseLogger, b.errColl, btdCtrlConf)
|
||||
b.btdManager, err = c.InterfaceListeners.toInternal(b.baseLogger, b.errColl, mtrc, btdCtrlConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("converting interface listeners: %w", err)
|
||||
}
|
||||
@@ -793,7 +805,7 @@ func (b *builder) initQueryLog(ctx context.Context) (err error) {
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "querylog"),
|
||||
Path: b.env.QueryLogPath,
|
||||
Metrics: mtrc,
|
||||
RandSeed: agdrand.MustNewSeed(),
|
||||
RandSeed: randutil.MustNewSeed(),
|
||||
})
|
||||
|
||||
b.logger.DebugContext(ctx, "initialized file-based query log")
|
||||
@@ -854,7 +866,7 @@ func (b *builder) initMsgConstructor(ctx context.Context) (err error) {
|
||||
//
|
||||
// [builder.initGRPCMetrics] must be called before this method.
|
||||
func (b *builder) initTLSManager(ctx context.Context) (err error) {
|
||||
mtrc, err := metrics.NewTLSConfig(b.mtrcNamespace, b.promRegisterer)
|
||||
mtrc, err := metrics.NewTLSConfigManager(b.mtrcNamespace, b.promRegisterer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("registering tls metrics: %w", err)
|
||||
}
|
||||
@@ -941,25 +953,65 @@ func (b *builder) newTicketDB(ctx context.Context) (db tlsconfig.TicketDB, err e
|
||||
// initCustomDomainDB initializes the database for the custom domains.
|
||||
//
|
||||
// [builder.initTLSManager] must be called before this method.
|
||||
func (b *builder) initCustomDomainDB(ctx context.Context) {
|
||||
if !b.profilesEnabled {
|
||||
b.customDomainDB = profiledb.EmptyCustomDomainDB{}
|
||||
func (b *builder) initCustomDomainDB(ctx context.Context) (err error) {
|
||||
if !bool(b.env.CustomDomainsEnabled) || !b.profilesEnabled {
|
||||
b.logger.WarnContext(ctx, "custom domains are disabled")
|
||||
|
||||
return
|
||||
b.dnsSvcCustomDomainDB = dnssvc.EmptyCustomDomainDB{}
|
||||
b.profDBCustomDomainDB = profiledb.EmptyCustomDomainDB{}
|
||||
b.webSvcCertValidator = websvc.RejectCertificateValidator{}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
b.customDomainDB = tlsconfig.NewCustomDomainDB(&tlsconfig.CustomDomainDBConfig{
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "custom_domain_db"),
|
||||
Clock: timeutil.SystemClock{},
|
||||
ErrColl: b.errColl,
|
||||
// TODO(a.garipov): Init and set the gRPC storage.
|
||||
Storage: tlsconfig.EmptyCustomDomainStorage{},
|
||||
// TODO(a.garipov): Set the TLS manager.
|
||||
strgMtrc, err := metrics.NewBackendCustomDomainStorage(b.mtrcNamespace, b.promRegisterer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("registering custom domain storage metrics: %w", err)
|
||||
}
|
||||
|
||||
strg, err := backendpb.NewCustomDomainStorage(&backendpb.CustomDomainStorageConfig{
|
||||
Endpoint: &b.env.CustomDomainsURL.URL,
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "custom_domain_storage"),
|
||||
Clock: timeutil.SystemClock{},
|
||||
GRPCMetrics: b.backendGRPCMtrc,
|
||||
Metrics: strgMtrc,
|
||||
APIKey: b.env.CustomDomainsAPIKey,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("custom domain storage: %w", err)
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Add a refresher and refresh initially.
|
||||
mtrc, err := metrics.NewCustomDomainDB(b.mtrcNamespace, b.promRegisterer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("registering custom domain database metrics: %w", err)
|
||||
}
|
||||
|
||||
b.logger.DebugContext(ctx, "initialized custom domain db")
|
||||
b.customDomainDB, err = tlsconfig.NewCustomDomainDB(&tlsconfig.CustomDomainDBConfig{
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "custom_domain_db"),
|
||||
Clock: timeutil.SystemClock{},
|
||||
ErrColl: b.errColl,
|
||||
Manager: b.tlsManager,
|
||||
Metrics: mtrc,
|
||||
Storage: strg,
|
||||
CacheDirPath: b.env.CustomDomainsCachePath,
|
||||
InitialRetryIvl: time.Duration(b.env.CustomDomainsRefreshIvl),
|
||||
// TODO(a.garipov): Consider making configurable.
|
||||
MaxRetryIvl: 1 * timeutil.Day,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("custom domain db: %w", err)
|
||||
}
|
||||
|
||||
b.dnsSvcCustomDomainDB = b.customDomainDB
|
||||
b.profDBCustomDomainDB = b.customDomainDB
|
||||
b.webSvcCertValidator = b.customDomainDB
|
||||
|
||||
// NOTE: The initial refresh and thus full initialization is done in
|
||||
// [builder.refreshCustomDomainDB].
|
||||
|
||||
b.logger.DebugContext(ctx, "prepared custom domain db")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initServerGroups initializes the server groups.
|
||||
@@ -1010,12 +1062,12 @@ func (b *builder) initTicketRotator(ctx context.Context) (err error) {
|
||||
Schedule: timeutil.NewConstSchedule(time.Duration(b.env.SessionTicketRefreshIvl)),
|
||||
RefreshOnShutdown: false,
|
||||
})
|
||||
err = refr.Start(ctx)
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting ticket rotator refresh: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(refr)
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
b.debugRefrs[debugIDTicketRotator] = tickRot
|
||||
|
||||
@@ -1068,12 +1120,12 @@ func (b *builder) setServerGroupProperties(ctx context.Context) {
|
||||
func (b *builder) startBindToDevice(ctx context.Context) (err error) {
|
||||
// Start the bind-to-device manager here, now that no further calls to
|
||||
// b.btdManager.ListenConfig are required.
|
||||
err = b.btdManager.Start(ctx)
|
||||
err = b.btdManager.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting bindtodevice manager: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(b.btdManager)
|
||||
b.sigHdlr.AddService(b.btdManager)
|
||||
|
||||
b.logger.DebugContext(ctx, "started bindtodevice manager")
|
||||
|
||||
@@ -1086,12 +1138,18 @@ const defaultTimeout = 30 * time.Second
|
||||
|
||||
// initGRPCMetrics initializes the gRPC metrics if necessary.
|
||||
func (b *builder) initGRPCMetrics(ctx context.Context) (err error) {
|
||||
b.backendGRPCMtrc = b.plugins.GRPCMetrics()
|
||||
|
||||
switch {
|
||||
case b.backendGRPCMtrc != nil:
|
||||
b.logger.DebugContext(ctx, "initialized grpc metrics from plugin")
|
||||
|
||||
return nil
|
||||
case
|
||||
b.profilesEnabled,
|
||||
b.env.SessionTicketType == sessionTicketRemote,
|
||||
b.conf.Check.KV.Type == kvModeBackend,
|
||||
b.conf.RateLimit.Allowlist.Type == rlAllowlistTypeBackend:
|
||||
b.env.DNSCheckKVType == kvModeBackend,
|
||||
b.env.RateLimitAllowlistType == rlAllowlistTypeBackend:
|
||||
// Go on.
|
||||
default:
|
||||
// Don't initialize the metrics if no protobuf backend is used.
|
||||
@@ -1147,12 +1205,12 @@ func (b *builder) initBillStat(ctx context.Context) (err error) {
|
||||
Schedule: timeutil.NewConstSchedule(refrIvl),
|
||||
RefreshOnShutdown: true,
|
||||
})
|
||||
err = refr.Start(ctx)
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting billstat recorder refresher: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(refr)
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
b.debugRefrs[debugIDBillStat] = billStat
|
||||
|
||||
@@ -1179,11 +1237,13 @@ func (b *builder) newBillStatUploader() (s billstat.Uploader, err error) {
|
||||
})
|
||||
}
|
||||
|
||||
// initProfileDB initializes the profile database if necessary.
|
||||
//
|
||||
// [builder.initGRPCMetrics] must be called before this method. It also adds
|
||||
// initProfileDB initializes the profile database if necessary. It also adds
|
||||
// the refreshers with ID [debugIDProfileDB], [debugIDProfileDBFull] to the
|
||||
// debug refreshers.
|
||||
//
|
||||
// The following methods must be called before this one:
|
||||
// - [builder.initCustomDomainDB]
|
||||
// - [builder.initGRPCMetrics]
|
||||
func (b *builder) initProfileDB(ctx context.Context) (err error) {
|
||||
if !b.profilesEnabled {
|
||||
b.profileDB = &profiledb.Disabled{}
|
||||
@@ -1202,6 +1262,8 @@ func (b *builder) initProfileDB(ctx context.Context) (err error) {
|
||||
return fmt.Errorf("registering profile access engine metrics: %w", err)
|
||||
}
|
||||
|
||||
profAccessCons := access.NewProfileConstructor(profileMtrc)
|
||||
|
||||
backendProfileDBMtrc, err := metrics.NewBackendProfileDB(b.mtrcNamespace, b.promRegisterer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("registering backend grpc profile metrics: %w", err)
|
||||
@@ -1210,17 +1272,17 @@ func (b *builder) initProfileDB(ctx context.Context) (err error) {
|
||||
respSzEst := b.conf.RateLimit.ResponseSizeEstimate
|
||||
customLogger := b.baseLogger.With(slogutil.KeyPrefix, "filters/"+string(filter.IDCustom))
|
||||
strg, err := backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
|
||||
BindSet: b.bindSet,
|
||||
ErrColl: b.errColl,
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "profilestorage"),
|
||||
BaseCustomLogger: customLogger,
|
||||
ProfileMetrics: profileMtrc,
|
||||
GRPCMetrics: b.backendGRPCMtrc,
|
||||
Metrics: backendProfileDBMtrc,
|
||||
Endpoint: apiURL,
|
||||
APIKey: b.env.ProfilesAPIKey,
|
||||
ResponseSizeEstimate: respSzEst,
|
||||
MaxProfilesSize: b.env.ProfilesMaxRespSize,
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "profilestorage"),
|
||||
BaseCustomLogger: customLogger,
|
||||
Endpoint: apiURL,
|
||||
ProfileAccessConstructor: profAccessCons,
|
||||
BindSet: b.bindSet,
|
||||
ErrColl: b.errColl,
|
||||
GRPCMetrics: b.backendGRPCMtrc,
|
||||
Metrics: backendProfileDBMtrc,
|
||||
APIKey: b.env.ProfilesAPIKey,
|
||||
ResponseSizeEstimate: respSzEst,
|
||||
MaxProfilesSize: b.env.ProfilesMaxRespSize,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating profile storage: %w", err)
|
||||
@@ -1234,18 +1296,19 @@ func (b *builder) initProfileDB(ctx context.Context) (err error) {
|
||||
c := b.conf.Backend
|
||||
timeout := time.Duration(c.Timeout)
|
||||
profDB, err := profiledb.New(&profiledb.Config{
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "profiledb"),
|
||||
BaseCustomLogger: customLogger,
|
||||
Clock: timeutil.SystemClock{},
|
||||
CustomDomainDB: b.customDomainDB,
|
||||
ErrColl: b.errColl,
|
||||
ProfileMetrics: profileMtrc,
|
||||
Metrics: profDBMtrc,
|
||||
Storage: strg,
|
||||
CacheFilePath: b.env.ProfilesCachePath,
|
||||
FullSyncIvl: time.Duration(c.FullRefreshIvl),
|
||||
FullSyncRetryIvl: time.Duration(c.FullRefreshRetryIvl),
|
||||
ResponseSizeEstimate: respSzEst,
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "profiledb"),
|
||||
BaseCustomLogger: customLogger,
|
||||
ProfileAccessConstructor: profAccessCons,
|
||||
Clock: timeutil.SystemClock{},
|
||||
CustomDomainDB: b.profDBCustomDomainDB,
|
||||
ErrColl: b.errColl,
|
||||
ProfileMetrics: profileMtrc,
|
||||
Metrics: profDBMtrc,
|
||||
Storage: strg,
|
||||
CacheFilePath: b.env.ProfilesCachePath,
|
||||
FullSyncIvl: time.Duration(c.FullRefreshIvl),
|
||||
FullSyncRetryIvl: time.Duration(c.FullRefreshRetryIvl),
|
||||
ResponseSizeEstimate: respSzEst,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating default profile database: %w", err)
|
||||
@@ -1274,12 +1337,12 @@ func (b *builder) initProfileDB(ctx context.Context) (err error) {
|
||||
Schedule: sched,
|
||||
RefreshOnShutdown: false,
|
||||
})
|
||||
err = refr.Start(ctx)
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting default profile database refresher: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(refr)
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
b.debugRefrs[debugIDProfileDB] = profDB
|
||||
|
||||
@@ -1291,6 +1354,41 @@ func (b *builder) initProfileDB(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// refreshCustomDomainDB performs the initial refresh of the custom-domain
|
||||
// database.
|
||||
//
|
||||
// [builder.initProfileDB] must be called before this method.
|
||||
func (b *builder) refreshCustomDomainDB(ctx context.Context) (err error) {
|
||||
if !bool(b.env.CustomDomainsEnabled) || !b.profilesEnabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = b.customDomainDB.Refresh(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("custom domain db: initial refresh: %w", err)
|
||||
}
|
||||
|
||||
refr := service.NewRefreshWorker(&service.RefreshWorkerConfig{
|
||||
// TODO(a.garipov): Consider making configurable.
|
||||
ContextConstructor: contextutil.NewTimeoutConstructor(defaultTimeout),
|
||||
Refresher: b.customDomainDB,
|
||||
Schedule: timeutil.NewConstSchedule(time.Duration(b.env.CustomDomainsRefreshIvl)),
|
||||
})
|
||||
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting custom domain db refresher: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
b.debugRefrs[debugIDCustomDomainDB] = b.customDomainDB
|
||||
|
||||
b.logger.DebugContext(ctx, "initialized custom domain db")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initDNSCheck initializes the DNS checker.
|
||||
//
|
||||
// [builder.initGRPCMetrics] and [builder.initMsgConstructor] must be called
|
||||
@@ -1306,6 +1404,7 @@ func (b *builder) initDNSCheck(ctx context.Context) (err error) {
|
||||
c := b.conf.Check
|
||||
|
||||
checkConf, err := c.toInternal(
|
||||
ctx,
|
||||
b.baseLogger,
|
||||
b.env,
|
||||
b.messages,
|
||||
@@ -1365,12 +1464,12 @@ func (b *builder) initRuleStat(ctx context.Context) (err error) {
|
||||
Schedule: timeutil.NewConstSchedule(10 * time.Minute),
|
||||
RefreshOnShutdown: true,
|
||||
})
|
||||
err = refr.Start(ctx)
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting rulestat refresher: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(refr)
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
b.debugRefrs[debugIDRuleStat] = ruleStat
|
||||
|
||||
@@ -1390,7 +1489,7 @@ func (b *builder) initRateLimiter(ctx context.Context) (err error) {
|
||||
allowSubnets := netutil.UnembedPrefixes(c.Allowlist.List)
|
||||
allowlist := ratelimit.NewDynamicAllowlist(allowSubnets, nil)
|
||||
|
||||
typ := b.conf.RateLimit.Allowlist.Type
|
||||
typ := b.env.RateLimitAllowlistType
|
||||
mtrc, err := metrics.NewAllowlist(b.mtrcNamespace, b.promRegisterer, typ)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ratelimit metrics: %w", err)
|
||||
@@ -1434,12 +1533,12 @@ func (b *builder) initRateLimiter(ctx context.Context) (err error) {
|
||||
Schedule: timeutil.NewConstSchedule(time.Duration(c.Allowlist.RefreshIvl)),
|
||||
RefreshOnShutdown: false,
|
||||
})
|
||||
err = refr.Start(ctx)
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting allowlist refresher: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(refr)
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
err = b.initConnLimit(ctx, c.ConnectionLimit)
|
||||
if err != nil {
|
||||
@@ -1472,8 +1571,11 @@ func (b *builder) initConnLimit(ctx context.Context, conf *connLimitConfig) (err
|
||||
}
|
||||
|
||||
// initWeb initializes the web service, starts it, and registers it in the
|
||||
// signal handler. [builder.initDNSCheck] and [builder.initProfileDB] must be
|
||||
// called before this method.
|
||||
// signal handler.
|
||||
//
|
||||
// The following methods must be called before this one:
|
||||
// - [builder.initDNSCheck]
|
||||
// - [builder.initProfileDB]
|
||||
func (b *builder) initWeb(ctx context.Context) (err error) {
|
||||
webSvcMtrc, err := metrics.NewWebSvc(b.mtrcNamespace, b.promRegisterer)
|
||||
if err != nil {
|
||||
@@ -1494,14 +1596,7 @@ func (b *builder) initWeb(ctx context.Context) (err error) {
|
||||
return fmt.Errorf("converting web configuration: %w", err)
|
||||
}
|
||||
|
||||
if b.profilesEnabled {
|
||||
// If profiles are enabled, the custom-domain database must also
|
||||
// implement [websvc.CertificateValidator], as these are parts of the
|
||||
// same feature.
|
||||
webConf.CertificateValidator = b.customDomainDB.(websvc.CertificateValidator)
|
||||
} else {
|
||||
webConf.CertificateValidator = websvc.RejectCertificateValidator{}
|
||||
}
|
||||
webConf.CertificateValidator = b.webSvcCertValidator
|
||||
|
||||
b.webSvc = websvc.New(webConf)
|
||||
|
||||
@@ -1518,18 +1613,18 @@ func (b *builder) initWeb(ctx context.Context) (err error) {
|
||||
Schedule: timeutil.NewConstSchedule(5 * time.Minute),
|
||||
RefreshOnShutdown: false,
|
||||
})
|
||||
err = refr.Start(ctx)
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting websvc refresher: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(refr)
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
// The web service is considered critical, so its Start method panics
|
||||
// instead of returning an error.
|
||||
_ = b.webSvc.Start(ctx)
|
||||
_ = b.webSvc.Start(context.WithoutCancel(ctx))
|
||||
|
||||
b.sigHdlr.Add(b.webSvc)
|
||||
b.sigHdlr.AddService(b.webSvc)
|
||||
|
||||
b.debugRefrs[debugIDWebSvc] = b.webSvc
|
||||
|
||||
@@ -1559,12 +1654,12 @@ func (b *builder) waitGeoIP(ctx context.Context) (err error) {
|
||||
Schedule: timeutil.NewConstSchedule(time.Duration(b.conf.GeoIP.RefreshIvl)),
|
||||
RefreshOnShutdown: false,
|
||||
})
|
||||
err = refr.Start(ctx)
|
||||
err = refr.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("starting geoip refresher: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(refr)
|
||||
b.sigHdlr.AddService(refr)
|
||||
|
||||
b.debugRefrs[debugIDGeoIP] = b.geoIP
|
||||
|
||||
@@ -1577,6 +1672,7 @@ func (b *builder) waitGeoIP(ctx context.Context) (err error) {
|
||||
// - [builder.initAccess]
|
||||
// - [builder.initBillStat]
|
||||
// - [builder.initBindToDevice]
|
||||
// - [builder.initCustomDomainDB]
|
||||
// - [builder.initDNSDB]
|
||||
// - [builder.initFilterStorage]
|
||||
// - [builder.initFilteringGroups]
|
||||
@@ -1601,32 +1697,35 @@ func (b *builder) initDNS(ctx context.Context) (err error) {
|
||||
b.fwdHandler = forward.NewHandler(b.conf.Upstream.toInternal(b.baseLogger, mtrcListener))
|
||||
|
||||
dnsHdlrsConf := &dnssvc.HandlersConfig{
|
||||
BaseLogger: b.baseLogger,
|
||||
Cache: b.conf.Cache.toInternal(),
|
||||
Cloner: b.cloner,
|
||||
HumanIDParser: agd.NewHumanIDParser(),
|
||||
Messages: b.messages,
|
||||
PluginRegistry: b.plugins,
|
||||
StructuredErrors: b.sdeConf,
|
||||
AccessManager: b.access,
|
||||
BillStat: b.billStat,
|
||||
CacheManager: b.cacheManager,
|
||||
DNSCheck: b.dnsCheck,
|
||||
DNSDB: b.dnsDB,
|
||||
ErrColl: b.errColl,
|
||||
FilterStorage: b.filterStorage,
|
||||
GeoIP: b.geoIP,
|
||||
Handler: b.fwdHandler,
|
||||
HashMatcher: b.hashMatcher,
|
||||
ProfileDB: b.profileDB,
|
||||
PrometheusRegisterer: b.promRegisterer,
|
||||
QueryLog: b.queryLog,
|
||||
RateLimit: b.rateLimit,
|
||||
RuleStat: b.ruleStat,
|
||||
MetricsNamespace: b.mtrcNamespace,
|
||||
FilteringGroups: b.filteringGroups,
|
||||
ServerGroups: b.serverGroups,
|
||||
EDEEnabled: b.conf.Filters.EDEEnabled,
|
||||
BaseLogger: b.baseLogger,
|
||||
Cache: b.conf.Cache.toInternal(),
|
||||
Cloner: b.cloner,
|
||||
HumanIDParser: agd.NewHumanIDParser(),
|
||||
MainMiddlewareMetrics: b.plugins.MainMiddlewareMetrics(),
|
||||
Messages: b.messages,
|
||||
PostInitialMiddleware: b.plugins.PostInitialMiddleware(),
|
||||
StructuredErrors: b.sdeConf,
|
||||
AccessManager: b.access,
|
||||
BillStat: b.billStat,
|
||||
CacheManager: b.cacheManager,
|
||||
CustomDomainDB: b.dnsSvcCustomDomainDB,
|
||||
DNSCheck: b.dnsCheck,
|
||||
DNSDB: b.dnsDB,
|
||||
ErrColl: b.errColl,
|
||||
FilterStorage: b.filterStorage,
|
||||
GeoIP: b.geoIP,
|
||||
Handler: b.fwdHandler,
|
||||
HashMatcher: b.hashMatcher,
|
||||
ProfileDB: b.profileDB,
|
||||
PrometheusRegisterer: b.promRegisterer,
|
||||
QueryLog: b.queryLog,
|
||||
RateLimit: b.rateLimit,
|
||||
RuleStat: b.ruleStat,
|
||||
MetricsNamespace: b.mtrcNamespace,
|
||||
NodeName: b.env.NodeName,
|
||||
FilteringGroups: b.filteringGroups,
|
||||
ServerGroups: b.serverGroups,
|
||||
EDEEnabled: b.conf.Filters.EDEEnabled,
|
||||
}
|
||||
|
||||
dnsHdlrs, err := dnssvc.NewHandlers(ctx, dnsHdlrsConf)
|
||||
@@ -1679,12 +1778,12 @@ func (b *builder) performConnCheck(ctx context.Context) (err error) {
|
||||
// [builder.initDNS] must be called before this method.
|
||||
func (b *builder) initHealthCheck(ctx context.Context) (err error) {
|
||||
upd := newUpstreamHealthcheck(b.baseLogger, b.fwdHandler, b.conf.Upstream, b.errColl)
|
||||
err = upd.Start(ctx)
|
||||
err = upd.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("initializing healthcheck: %w", err)
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(upd)
|
||||
b.sigHdlr.AddService(upd)
|
||||
|
||||
b.logger.DebugContext(ctx, "initialized healthcheck")
|
||||
|
||||
@@ -1704,14 +1803,14 @@ func (b *builder) initPluginRefreshers() {
|
||||
func (b *builder) initPluginServices(ctx context.Context) (err error) {
|
||||
var errs []error
|
||||
for id, svc := range b.plugins.Services() {
|
||||
err = svc.Start(ctx)
|
||||
err = svc.Start(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("starting plugin service %q: %w", id, err))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
b.sigHdlr.Add(svc)
|
||||
b.sigHdlr.AddService(svc)
|
||||
}
|
||||
|
||||
return errors.Join(errs...)
|
||||
@@ -1725,9 +1824,9 @@ func (b *builder) initPluginServices(ctx context.Context) (err error) {
|
||||
func (b *builder) mustStartDNS(ctx context.Context) {
|
||||
// The DNS service is considered critical, so its Start method panics
|
||||
// instead of returning an error.
|
||||
_ = b.dnsSvc.Start(ctx)
|
||||
_ = b.dnsSvc.Start(context.WithoutCancel(ctx))
|
||||
|
||||
b.sigHdlr.Add(b.dnsSvc)
|
||||
b.sigHdlr.AddService(b.dnsSvc)
|
||||
|
||||
b.logger.DebugContext(ctx, "started dns")
|
||||
}
|
||||
@@ -1754,9 +1853,9 @@ func (b *builder) mustInitDebugSvc(ctx context.Context) {
|
||||
|
||||
// The debug HTTP service is considered critical, so its Start method panics
|
||||
// instead of returning an error.
|
||||
_ = debugSvc.Start(ctx)
|
||||
_ = debugSvc.Start(context.WithoutCancel(ctx))
|
||||
|
||||
b.sigHdlr.Add(debugSvc)
|
||||
b.sigHdlr.AddService(debugSvc)
|
||||
|
||||
b.logger.DebugContext(
|
||||
ctx,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/netip"
|
||||
@@ -30,18 +31,12 @@ import (
|
||||
|
||||
// checkConfig is the DNS server checking configuration.
|
||||
type checkConfig struct {
|
||||
// KV is remote key-value store configuration for DNS server checking.
|
||||
KV *remoteKVConfig `yaml:"kv"`
|
||||
|
||||
// Domains are the domain names used for DNS server checking.
|
||||
Domains []string `yaml:"domains"`
|
||||
|
||||
// NodeLocation is the location of this server node.
|
||||
NodeLocation string `yaml:"node_location"`
|
||||
|
||||
// NodeName is the name of this server node.
|
||||
NodeName string `yaml:"node_name"`
|
||||
|
||||
// IPv4 is the list of IPv4 addresses to respond with for A queries to
|
||||
// subdomains of Domain.
|
||||
IPv4 []netip.Addr `yaml:"ipv4"`
|
||||
@@ -54,6 +49,7 @@ type checkConfig struct {
|
||||
// toInternal converts c to the DNS server check configuration for the DNS
|
||||
// server. c must be valid.
|
||||
func (c *checkConfig) toInternal(
|
||||
ctx context.Context,
|
||||
baseLogger *slog.Logger,
|
||||
envs *environment,
|
||||
messages *dnsmsg.Constructor,
|
||||
@@ -67,7 +63,7 @@ func (c *checkConfig) toInternal(
|
||||
return nil, fmt.Errorf("dnscheck metrics: %w", err)
|
||||
}
|
||||
|
||||
kv, err := c.KV.newRemoteKV(envs, namespace, reg, grpcMtrc, baseLogger)
|
||||
kv, err := newRemoteKV(ctx, envs, namespace, reg, grpcMtrc, baseLogger)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return nil, err
|
||||
@@ -86,7 +82,7 @@ func (c *checkConfig) toInternal(
|
||||
ErrColl: errColl,
|
||||
Domains: domains,
|
||||
NodeLocation: c.NodeLocation,
|
||||
NodeName: c.NodeName,
|
||||
NodeName: envs.NodeName,
|
||||
IPv4: c.IPv4,
|
||||
IPv6: c.IPv6,
|
||||
}, nil
|
||||
@@ -99,18 +95,22 @@ const maxRespSize = 1 * datasize.MB
|
||||
// [remotekv.KeyNamespace].
|
||||
const keyNamespaceCheck = "check"
|
||||
|
||||
// newRemoteKV returns a new properly initialized remote key-value storage. c
|
||||
// must be valid. grpcMtrc should be registered before calling this method.
|
||||
func (c *remoteKVConfig) newRemoteKV(
|
||||
// newRemoteKV returns a new properly initialized remote key-value storage.
|
||||
// grpcMtrc should be registered before calling this method.
|
||||
func newRemoteKV(
|
||||
ctx context.Context,
|
||||
envs *environment,
|
||||
namespace string,
|
||||
reg prometheus.Registerer,
|
||||
grpcMtrc backendpb.GRPCMetrics,
|
||||
baseLogger *slog.Logger,
|
||||
) (kv remotekv.Interface, err error) {
|
||||
switch c.Type {
|
||||
switch envs.DNSCheckKVType {
|
||||
case kvModeBackend:
|
||||
return newBackendRemoteKV(envs, namespace, reg, grpcMtrc, c.TTL)
|
||||
kv, err = newBackendRemoteKV(envs, namespace, reg, grpcMtrc, envs.DNSCheckKVTTL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing backend dnscheck kv: %w", err)
|
||||
}
|
||||
case kvModeCache:
|
||||
// TODO(e.burkov): The local cache in [dnscheck.RemoteKV] becomes
|
||||
// pointless with this mode.
|
||||
@@ -120,19 +120,26 @@ func (c *remoteKVConfig) newRemoteKV(
|
||||
}),
|
||||
}), nil
|
||||
case kvModeRedis:
|
||||
return newRedisRemoteKV(envs, namespace, reg, baseLogger, c.TTL)
|
||||
kv, err = newRedisRemoteKV(ctx, namespace, reg, baseLogger, envs.DNSCheckKVTTL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing redis dnscheck kv: %w", err)
|
||||
}
|
||||
case kvModeConsul:
|
||||
kv, err = newConsulRemoteKV(envs, c.TTL)
|
||||
kv, err = newConsulRemoteKV(envs, envs.DNSCheckKVTTL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing consul dnscheck kv: %w", err)
|
||||
}
|
||||
default:
|
||||
panic(fmt.Errorf("dnscheck kv type: %w: %q", errors.ErrBadEnumValue, c.Type))
|
||||
panic(fmt.Errorf(
|
||||
"env DNSCHECK_KV_TYPE: %w: %q",
|
||||
errors.ErrBadEnumValue,
|
||||
envs.DNSCheckKVType,
|
||||
))
|
||||
}
|
||||
|
||||
return remotekv.NewKeyNamespace(&remotekv.KeyNamespaceConfig{
|
||||
KV: kv,
|
||||
Prefix: newRemoteKVPrefix(envs, c.Type),
|
||||
Prefix: newRemoteKVPrefix(envs, envs.DNSCheckKVType),
|
||||
}), nil
|
||||
}
|
||||
|
||||
@@ -170,7 +177,7 @@ func newBackendRemoteKV(
|
||||
// newRedisRemoteKV returns a new properly initialized Redis-based remote
|
||||
// key-value storage.
|
||||
func newRedisRemoteKV(
|
||||
envs *environment,
|
||||
ctx context.Context,
|
||||
namespace string,
|
||||
reg prometheus.Registerer,
|
||||
baseLogger *slog.Logger,
|
||||
@@ -181,36 +188,7 @@ func newRedisRemoteKV(
|
||||
return nil, fmt.Errorf("registering redis kv metrics: %w", err)
|
||||
}
|
||||
|
||||
var dialer *redisutil.DefaultDialer
|
||||
dialer, err = redisutil.NewDefaultDialer(&redisutil.DefaultDialerConfig{
|
||||
Addr: &netutil.HostPort{
|
||||
Host: envs.RedisAddr,
|
||||
Port: envs.RedisPort,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing redisutil dialer: %w", err)
|
||||
}
|
||||
|
||||
var connTester *redisutil.RoleChecker
|
||||
connTester, err = redisutil.NewRoleChecker(&redisutil.RoleCheckerConfig{
|
||||
Logger: baseLogger.With(slogutil.KeyPrefix, "redis_role_checker"),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing redisutil role checker: %w", err)
|
||||
}
|
||||
|
||||
var pool *redisutil.DefaultPool
|
||||
pool, err = redisutil.NewDefaultPool(&redisutil.DefaultPoolConfig{
|
||||
Logger: baseLogger.With(slogutil.KeyPrefix, "redis_pool"),
|
||||
ConnectionTester: connTester,
|
||||
Dialer: dialer,
|
||||
Metrics: mtrc,
|
||||
IdleTimeout: time.Duration(envs.RedisIdleTimeout),
|
||||
MaxActive: envs.RedisMaxActive,
|
||||
MaxIdle: envs.RedisMaxIdle,
|
||||
Wait: true,
|
||||
})
|
||||
pool, err := redisutil.NewPoolFromEnvironment(ctx, baseLogger, mtrc)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing redisutil pool: %w", err)
|
||||
}
|
||||
@@ -224,8 +202,11 @@ func newRedisRemoteKV(
|
||||
}
|
||||
|
||||
// newConsulRemoteKV returns a new properly initialized Consul-based remote
|
||||
// key-value storage.
|
||||
func newConsulRemoteKV(envs *environment, ttl timeutil.Duration) (kv remotekv.Interface, err error) {
|
||||
// key-value storage. envs must be valid.
|
||||
func newConsulRemoteKV(
|
||||
envs *environment,
|
||||
ttl timeutil.Duration,
|
||||
) (kv remotekv.Interface, err error) {
|
||||
consulKVURL := envs.ConsulDNSCheckKVURL
|
||||
consulSessionURL := envs.ConsulDNSCheckSessionURL
|
||||
if consulKVURL == nil || consulSessionURL == nil {
|
||||
@@ -274,7 +255,6 @@ func (c *checkConfig) Validate() (err error) {
|
||||
|
||||
errs := []error{
|
||||
validate.NotEmpty("node_location", c.NodeLocation),
|
||||
validate.NotEmpty("node_name", c.NodeName),
|
||||
validate.NotEmptySlice("domains", c.Domains),
|
||||
}
|
||||
|
||||
@@ -290,8 +270,6 @@ func (c *checkConfig) Validate() (err error) {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
errs = validate.Append(errs, "kv", c.KV)
|
||||
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
@@ -332,39 +310,3 @@ const (
|
||||
kvModeConsul = "consul"
|
||||
kvModeRedis = "redis"
|
||||
)
|
||||
|
||||
// remoteKVConfig is remote key-value store configuration for DNS server
|
||||
// checking.
|
||||
type remoteKVConfig struct {
|
||||
// Type defines the type of remote key-value store. Allowed values are
|
||||
// [kvModeBackend], [kvModeCache], [kvModeConsul] and [kvModeRedis].
|
||||
Type string `yaml:"type"`
|
||||
|
||||
// TTL defines, for how long to keep the information about a single client.
|
||||
TTL timeutil.Duration `yaml:"ttl"`
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ validate.Interface = (*remoteKVConfig)(nil)
|
||||
|
||||
// Validate implements the [validate.Interface] interface for *remoteKVConfig.
|
||||
func (c *remoteKVConfig) Validate() (err error) {
|
||||
if c == nil {
|
||||
return errors.ErrNoValue
|
||||
}
|
||||
|
||||
ttl := time.Duration(c.TTL)
|
||||
|
||||
switch c.Type {
|
||||
case kvModeBackend:
|
||||
return validate.Positive("ttl", ttl)
|
||||
case kvModeCache:
|
||||
return nil
|
||||
case kvModeConsul:
|
||||
return validate.InRange("ttl", ttl, consulkv.MinTTL, consulkv.MaxTTL)
|
||||
case kvModeRedis:
|
||||
return validate.NoLessThan("ttl", ttl, rediskv.MinTTL)
|
||||
default:
|
||||
return fmt.Errorf("type: %w: %q", errors.ErrBadEnumValue, c.Type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
@@ -15,12 +16,13 @@ import (
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/sentryutil"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Main is the entry point of application.
|
||||
func Main(plugins *plugin.Registry) {
|
||||
// TODO(a.garipov, e.burkov): Consider adding timeouts for initialization.
|
||||
ctx := context.Background()
|
||||
ctx, stop := signal.NotifyContext(context.Background(), unix.SIGINT, unix.SIGTERM)
|
||||
|
||||
envs := errors.Must(parseEnvironment())
|
||||
errors.Check(envs.Validate())
|
||||
@@ -35,8 +37,6 @@ func Main(plugins *plugin.Registry) {
|
||||
|
||||
sentryutil.SetDefaultLogger(baseLogger, "")
|
||||
|
||||
experiment.Init(baseLogger)
|
||||
|
||||
// TODO(a.garipov): Consider ways of replacing a prefix and stop passing
|
||||
// the main logger everywhere.
|
||||
mainLogger := baseLogger.With(slogutil.KeyPrefix, "main")
|
||||
@@ -71,9 +71,7 @@ func Main(plugins *plugin.Registry) {
|
||||
|
||||
profilesEnabled := c.isProfilesEnabled()
|
||||
|
||||
errors.Check(envs.validateFromValidConfig(c, profilesEnabled))
|
||||
|
||||
metrics.SetAdditionalInfo(c.AdditionalMetricsInfo)
|
||||
errors.Check(envs.validateProfilesConf(profilesEnabled))
|
||||
|
||||
// Building and running the server
|
||||
|
||||
@@ -86,6 +84,10 @@ func Main(plugins *plugin.Registry) {
|
||||
profilesEnabled: profilesEnabled,
|
||||
})
|
||||
|
||||
errors.Check(experiment.Init(baseLogger, b.promRegisterer))
|
||||
|
||||
errors.Check(metrics.SetAdditionalInfo(b.promRegisterer, c.AdditionalMetricsInfo))
|
||||
|
||||
b.startGeoIP(ctx)
|
||||
|
||||
errors.Check(os.MkdirAll(envs.FilterCachePath, agd.DefaultDirPerm))
|
||||
@@ -112,9 +114,7 @@ func Main(plugins *plugin.Registry) {
|
||||
|
||||
errors.Check(b.initTLSManager(ctx))
|
||||
|
||||
// TODO(a.garipov): Check the errors when the methods starts returning
|
||||
// them.
|
||||
b.initCustomDomainDB(ctx)
|
||||
errors.Check(b.initCustomDomainDB(ctx))
|
||||
|
||||
errors.Check(b.initServerGroups(ctx))
|
||||
|
||||
@@ -126,6 +126,8 @@ func Main(plugins *plugin.Registry) {
|
||||
|
||||
errors.Check(b.initProfileDB(ctx))
|
||||
|
||||
errors.Check(b.refreshCustomDomainDB(ctx))
|
||||
|
||||
errors.Check(b.initDNSCheck(ctx))
|
||||
|
||||
errors.Check(b.initRuleStat(ctx))
|
||||
@@ -151,7 +153,18 @@ func Main(plugins *plugin.Registry) {
|
||||
b.mustInitDebugSvc(ctx)
|
||||
|
||||
// Signal that the server is started.
|
||||
metrics.SetUpGauge(buildVersion, commitTime, branch, revision, runtime.Version())
|
||||
errors.Check(metrics.SetUpGauge(
|
||||
b.promRegisterer,
|
||||
buildVersion,
|
||||
branch,
|
||||
commitTime,
|
||||
revision,
|
||||
runtime.Version(),
|
||||
))
|
||||
|
||||
// Unregister the signal behavior for ctx.
|
||||
stop()
|
||||
ctx = context.WithoutCancel(ctx)
|
||||
|
||||
os.Exit(b.handleSignals(ctx))
|
||||
}
|
||||
|
||||
@@ -9,10 +9,13 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/debugsvc"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/remotekv/consulkv"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/remotekv/rediskv"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/version"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
@@ -36,6 +39,7 @@ type environment struct {
|
||||
ConsulAllowlistURL *urlutil.URL `env:"CONSUL_ALLOWLIST_URL"`
|
||||
ConsulDNSCheckKVURL *urlutil.URL `env:"CONSUL_DNSCHECK_KV_URL"`
|
||||
ConsulDNSCheckSessionURL *urlutil.URL `env:"CONSUL_DNSCHECK_SESSION_URL"`
|
||||
CustomDomainsURL *urlutil.URL `env:"CUSTOM_DOMAINS_URL"`
|
||||
DNSCheckRemoteKVURL *urlutil.URL `env:"DNSCHECK_REMOTEKV_URL"`
|
||||
FilterIndexURL *urlutil.URL `env:"FILTER_INDEX_URL,notEmpty"`
|
||||
GeneralSafeSearchURL *urlutil.URL `env:"GENERAL_SAFE_SEARCH_URL"`
|
||||
@@ -50,22 +54,26 @@ type environment struct {
|
||||
BackendRateLimitAPIKey string `env:"BACKEND_RATELIMIT_API_KEY"`
|
||||
BillStatAPIKey string `env:"BILLSTAT_API_KEY"`
|
||||
ConfPath string `env:"CONFIG_PATH" envDefault:"./config.yaml"`
|
||||
CustomDomainsAPIKey string `env:"CUSTOM_DOMAINS_API_KEY"`
|
||||
CustomDomainsCachePath string `env:"CUSTOM_DOMAINS_CACHE_PATH"`
|
||||
DNSCheckKVType string `env:"DNSCHECK_KV_TYPE"`
|
||||
DNSCheckRemoteKVAPIKey string `env:"DNSCHECK_REMOTEKV_API_KEY"`
|
||||
FilterCachePath string `env:"FILTER_CACHE_PATH" envDefault:"./filters/"`
|
||||
GeoIPASNPath string `env:"GEOIP_ASN_PATH" envDefault:"./asn.mmdb"`
|
||||
GeoIPCountryPath string `env:"GEOIP_COUNTRY_PATH" envDefault:"./country.mmdb"`
|
||||
LogFormat string `env:"LOG_FORMAT" envDefault:"text"`
|
||||
NodeName string `env:"NODE_NAME,notEmpty"`
|
||||
ProfilesAPIKey string `env:"PROFILES_API_KEY"`
|
||||
ProfilesCachePath string `env:"PROFILES_CACHE_PATH" envDefault:"./profilecache.pb"`
|
||||
QueryLogPath string `env:"QUERYLOG_PATH" envDefault:"./querylog.jsonl"`
|
||||
RedisAddr string `env:"REDIS_ADDR"`
|
||||
RateLimitAllowlistType string `env:"RATELIMIT_ALLOWLIST_TYPE"`
|
||||
RedisKeyPrefix string `env:"REDIS_KEY_PREFIX" envDefault:"agdns"`
|
||||
SSLKeyLogFile string `env:"SSL_KEY_LOG_FILE"`
|
||||
SentryDSN string `env:"SENTRY_DSN" envDefault:"stderr"`
|
||||
SessionTicketCachePath string `env:"SESSION_TICKET_CACHE_PATH"`
|
||||
SessionTicketType string `env:"SESSION_TICKET_TYPE"`
|
||||
SessionTicketAPIKey string `env:"SESSION_TICKET_API_KEY"`
|
||||
SessionTicketCachePath string `env:"SESSION_TICKET_CACHE_PATH"`
|
||||
SessionTicketIndexName string `env:"SESSION_TICKET_INDEX_NAME"`
|
||||
SessionTicketType string `env:"SESSION_TICKET_TYPE"`
|
||||
|
||||
// TODO(a.garipov): Consider renaming to "WEB_STATIC_PATH" or something
|
||||
// similar.
|
||||
@@ -75,20 +83,19 @@ type environment struct {
|
||||
|
||||
ProfilesMaxRespSize datasize.ByteSize `env:"PROFILES_MAX_RESP_SIZE" envDefault:"64MB"`
|
||||
|
||||
RedisIdleTimeout timeutil.Duration `env:"REDIS_IDLE_TIMEOUT" envDefault:"30s"`
|
||||
CustomDomainsRefreshIvl timeutil.Duration `env:"CUSTOM_DOMAINS_REFRESH_INTERVAL"`
|
||||
DNSCheckKVTTL timeutil.Duration `env:"DNSCHECK_KV_TTL"`
|
||||
SessionTicketRefreshIvl timeutil.Duration `env:"SESSION_TICKET_REFRESH_INTERVAL"`
|
||||
|
||||
// TODO(a.garipov): Rename to DNSCHECK_CACHE_KV_COUNT?
|
||||
DNSCheckCacheKVSize int `env:"DNSCHECK_CACHE_KV_SIZE"`
|
||||
RedisMaxActive int `env:"REDIS_MAX_ACTIVE" envDefault:"10"`
|
||||
RedisMaxIdle int `env:"REDIS_MAX_IDLE" envDefault:"3"`
|
||||
|
||||
ListenPort uint16 `env:"LISTEN_PORT" envDefault:"8181"`
|
||||
RedisPort uint16 `env:"REDIS_PORT" envDefault:"6379"`
|
||||
|
||||
Verbosity uint8 `env:"VERBOSE" envDefault:"0"`
|
||||
|
||||
AdultBlockingEnabled strictBool `env:"ADULT_BLOCKING_ENABLED" envDefault:"1"`
|
||||
CustomDomainsEnabled strictBool `env:"CUSTOM_DOMAINS_ENABLED" envDefault:"1"`
|
||||
LogTimestamp strictBool `env:"LOG_TIMESTAMP" envDefault:"1"`
|
||||
NewRegDomainsEnabled strictBool `env:"NEW_REG_DOMAINS_ENABLED" envDefault:"1"`
|
||||
SafeBrowsingEnabled strictBool `env:"SAFE_BROWSING_ENABLED" envDefault:"1"`
|
||||
@@ -141,7 +148,11 @@ func (envs *environment) Validate() (err error) {
|
||||
errs = append(errs, fmt.Errorf("VERBOSE: %w", err))
|
||||
}
|
||||
|
||||
errs = envs.validateCustomDomains(errs)
|
||||
errs = envs.validateDNSCheck(errs)
|
||||
errs = envs.validateRateLimit(errs)
|
||||
errs = envs.validateSessionTickets(errs)
|
||||
errs = envs.validateRateLimitURLs(errs)
|
||||
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
@@ -245,8 +256,75 @@ func (envs *environment) validateWebStaticDir() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateSessionTickets appends validation errors to the given errs if
|
||||
// environment variables for session tickets contain errors.
|
||||
// validateCustomDomains appends validation errors to errs if the environment
|
||||
// variables for custom domains contain errors.
|
||||
func (envs *environment) validateCustomDomains(errs []error) (res []error) {
|
||||
res = errs
|
||||
|
||||
if !envs.CustomDomainsEnabled {
|
||||
return res
|
||||
}
|
||||
|
||||
res = append(res,
|
||||
validate.NotEmpty("env CUSTOM_DOMAINS_CACHE_PATH", envs.CustomDomainsCachePath),
|
||||
validate.Positive("env CUSTOM_DOMAINS_REFRESH_INTERVAL", envs.CustomDomainsRefreshIvl),
|
||||
)
|
||||
|
||||
if err := validate.NotNil("env CUSTOM_DOMAINS_URL", envs.CustomDomainsURL); err != nil {
|
||||
res = append(res, err)
|
||||
} else if err = urlutil.ValidateGRPCURL(&envs.CustomDomainsURL.URL); err != nil {
|
||||
res = append(res, fmt.Errorf("env CUSTOM_DOMAINS_URL: %w", err))
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// validateDNSCheck appends validation errors to errs if the environment
|
||||
// variables for DNS check contain errors.
|
||||
func (envs *environment) validateDNSCheck(errs []error) (res []error) {
|
||||
res = errs
|
||||
|
||||
ttl := time.Duration(envs.DNSCheckKVTTL)
|
||||
|
||||
var err error
|
||||
switch typ := envs.DNSCheckKVType; typ {
|
||||
case kvModeBackend:
|
||||
res = envs.validateBackendKV(res)
|
||||
err = validate.Positive("env DNSCHECK_KV_TTL", ttl)
|
||||
case kvModeCache:
|
||||
res = envs.validateCache(res)
|
||||
case kvModeConsul:
|
||||
err = validate.InRange("env DNSCHECK_KV_TTL", ttl, consulkv.MinTTL, consulkv.MaxTTL)
|
||||
case kvModeRedis:
|
||||
err = validate.NoLessThan("env DNSCHECK_KV_TTL", ttl, rediskv.MinTTL)
|
||||
default:
|
||||
err = fmt.Errorf("env DNSCHECK_KV_TYPE: %w: %q", errors.ErrBadEnumValue, typ)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// validateDNSCheck appends validation errors to errs if the environment
|
||||
// variables for rate limit contain errors.
|
||||
func (envs *environment) validateRateLimit(errs []error) (res []error) {
|
||||
switch typ := envs.RateLimitAllowlistType; typ {
|
||||
case rlAllowlistTypeBackend, rlAllowlistTypeConsul:
|
||||
// Go on.
|
||||
default:
|
||||
err := fmt.Errorf("env RATELIMIT_ALLOWLIST_TYPE: %w: %q", errors.ErrBadEnumValue, typ)
|
||||
|
||||
return append(errs, err)
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// validateSessionTickets appends validation errors to errs if the environment
|
||||
// variables for session tickets contain errors.
|
||||
func (envs *environment) validateSessionTickets(errs []error) (res []error) {
|
||||
res = errs
|
||||
|
||||
@@ -287,25 +365,11 @@ func (envs *environment) validateSessionTickets(errs []error) (res []error) {
|
||||
return res
|
||||
}
|
||||
|
||||
// validateFromValidConfig returns an error if environment variables that depend
|
||||
// on configuration properties contain errors. conf is expected to be valid.
|
||||
func (envs *environment) validateFromValidConfig(
|
||||
conf *configuration,
|
||||
profilesEnabled bool,
|
||||
) (err error) {
|
||||
// validateProfilesConf returns an error if environment variables for profiles
|
||||
// database configuration contain errors.
|
||||
func (envs *environment) validateProfilesConf(profilesEnabled bool) (err error) {
|
||||
var errs []error
|
||||
|
||||
switch typ := conf.Check.KV.Type; typ {
|
||||
case kvModeBackend:
|
||||
errs = envs.validateBackendKV(errs)
|
||||
case kvModeCache:
|
||||
errs = envs.validateCache(errs)
|
||||
case kvModeRedis:
|
||||
errs = envs.validateRedis(errs)
|
||||
default:
|
||||
// Probably consul.
|
||||
}
|
||||
|
||||
if profilesEnabled {
|
||||
errs = envs.validateProfilesURLs(errs)
|
||||
|
||||
@@ -319,8 +383,6 @@ func (envs *environment) validateFromValidConfig(
|
||||
}
|
||||
}
|
||||
|
||||
errs = envs.validateRateLimitURLs(conf, errs)
|
||||
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
@@ -338,34 +400,6 @@ func (envs *environment) validateCache(errs []error) (res []error) {
|
||||
return res
|
||||
}
|
||||
|
||||
// validateRedis appends validation errors to the given errs if environment
|
||||
// variables for Redis contain errors.
|
||||
func (envs *environment) validateRedis(errs []error) (res []error) {
|
||||
res = errs
|
||||
|
||||
if err := validate.NotEmpty("env REDIS_ADDR", envs.RedisAddr); err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := validate.Positive("env REDIS_IDLE_TIMEOUT", envs.RedisIdleTimeout); err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := validate.NotNegative("env REDIS_MAX_ACTIVE", envs.RedisMaxActive); err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := validate.NotNegative("env REDIS_MAX_IDLE", envs.RedisMaxIdle); err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// validateBackendKV appends validation errors to the given errs if environment
|
||||
// variables for a backend key-value store contain errors.
|
||||
func (envs *environment) validateBackendKV(errs []error) (res []error) {
|
||||
@@ -420,15 +454,12 @@ func (envs *environment) validateProfilesURLs(errs []error) (res []error) {
|
||||
|
||||
// validateRateLimitURLs appends validation errors to the given errs if rate
|
||||
// limit URLs in environment variables are invalid.
|
||||
func (envs *environment) validateRateLimitURLs(
|
||||
conf *configuration,
|
||||
errs []error,
|
||||
) (withURLs []error) {
|
||||
func (envs *environment) validateRateLimitURLs(errs []error) (withURLs []error) {
|
||||
rlURL := envs.BackendRateLimitURL
|
||||
rlEnv := "BACKEND_RATELIMIT_URL"
|
||||
validateFunc := urlutil.ValidateGRPCURL
|
||||
|
||||
if conf.RateLimit.Allowlist.Type == rlAllowlistTypeConsul {
|
||||
if envs.RateLimitAllowlistType == rlAllowlistTypeConsul {
|
||||
rlURL = envs.ConsulAllowlistURL
|
||||
rlEnv = "CONSUL_ALLOWLIST_URL"
|
||||
validateFunc = urlutil.ValidateHTTPURL
|
||||
|
||||
@@ -25,10 +25,12 @@ type interfaceListenersConfig struct {
|
||||
}
|
||||
|
||||
// toInternal converts c to a possibly-nil bindtodevice.Manager. c must be
|
||||
// valid.
|
||||
// valid. logger, errColl, and mtrc must not be nil. If ctrlConf is nil, a
|
||||
// default configuration is used.
|
||||
func (c *interfaceListenersConfig) toInternal(
|
||||
logger *slog.Logger,
|
||||
errColl errcoll.Interface,
|
||||
mtrc bindtodevice.Metrics,
|
||||
ctrlConf *bindtodevice.ControlConfig,
|
||||
) (m *bindtodevice.Manager, err error) {
|
||||
if c == nil {
|
||||
@@ -39,6 +41,7 @@ func (c *interfaceListenersConfig) toInternal(
|
||||
Logger: logger.With(slogutil.KeyPrefix, "bindtodevice"),
|
||||
InterfaceStorage: bindtodevice.DefaultInterfaceStorage{},
|
||||
ErrColl: errColl,
|
||||
Metrics: mtrc,
|
||||
ChannelBufferSize: c.ChannelBufferSize,
|
||||
})
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
|
||||
"github.com/AdguardTeam/golibs/service"
|
||||
)
|
||||
@@ -15,9 +16,12 @@ type Config struct {
|
||||
// DNSCheck is a custom implementation of the DNSCheck service.
|
||||
DNSCheck dnscheck.Interface
|
||||
|
||||
// GRPCMtrc is a custom implementation of the gRPC metrics.
|
||||
GRPCMtrc backendpb.GRPCMetrics
|
||||
|
||||
// MainMwMtrc is a custom implementation of the filtering-middleware
|
||||
// metrics.
|
||||
MainMwMtrc metrics.MainMiddleware
|
||||
MainMwMtrc dnssvc.MainMiddlewareMetrics
|
||||
|
||||
// PostInitMw is a custom implementation of the post-initial middleware.
|
||||
PostInitMw dnsserver.Middleware
|
||||
@@ -39,7 +43,8 @@ type Config struct {
|
||||
// values.
|
||||
type Registry struct {
|
||||
dnscheck dnscheck.Interface
|
||||
mainMwMtrc metrics.MainMiddleware
|
||||
grpcMtrc backendpb.GRPCMetrics
|
||||
mainMwMtrc dnssvc.MainMiddlewareMetrics
|
||||
postInitMw dnsserver.Middleware
|
||||
ruleStat rulestat.Interface
|
||||
refrs map[string]service.Refresher
|
||||
@@ -51,6 +56,7 @@ type Registry struct {
|
||||
func NewRegistry(c *Config) (r *Registry) {
|
||||
return &Registry{
|
||||
dnscheck: c.DNSCheck,
|
||||
grpcMtrc: c.GRPCMtrc,
|
||||
mainMwMtrc: c.MainMwMtrc,
|
||||
postInitMw: c.PostInitMw,
|
||||
ruleStat: c.RuleStat,
|
||||
@@ -68,9 +74,18 @@ func (r *Registry) DNSCheck() (dnsCk dnscheck.Interface) {
|
||||
return r.dnscheck
|
||||
}
|
||||
|
||||
// GRPCMetrics returns a custom implementation of the gRPC metrics, if any.
|
||||
func (r *Registry) GRPCMetrics() (grpcMtrc backendpb.GRPCMetrics) {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return r.grpcMtrc
|
||||
}
|
||||
|
||||
// MainMiddlewareMetrics returns a custom implementation of the
|
||||
// filtering-middleware metrics, if any.
|
||||
func (r *Registry) MainMiddlewareMetrics() (mainMwMtrc metrics.MainMiddleware) {
|
||||
func (r *Registry) MainMiddlewareMetrics() (mainMwMtrc dnssvc.MainMiddlewareMetrics) {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
@@ -135,10 +134,6 @@ func (c *rateLimitConfig) Validate() (err error) {
|
||||
|
||||
// allowListConfig is the consul allow list configuration.
|
||||
type allowListConfig struct {
|
||||
// Type defines where the rate limit settings are received from. Allowed
|
||||
// values are [rlAllowlistTypeBackend] and [rlAllowlistTypeConsul].
|
||||
Type string `yaml:"type"`
|
||||
|
||||
// List contains IPs and CIDRs.
|
||||
List []netutil.Prefix `yaml:"list"`
|
||||
|
||||
@@ -161,20 +156,7 @@ func (c *allowListConfig) Validate() (err error) {
|
||||
return errors.ErrNoValue
|
||||
}
|
||||
|
||||
errs := []error{
|
||||
validate.Positive("refresh_interval", c.RefreshIvl),
|
||||
}
|
||||
|
||||
switch c.Type {
|
||||
case
|
||||
rlAllowlistTypeBackend,
|
||||
rlAllowlistTypeConsul:
|
||||
// Go on.
|
||||
default:
|
||||
errs = append(errs, fmt.Errorf("type: %w: %q", errors.ErrBadEnumValue, c.Type))
|
||||
}
|
||||
|
||||
return errors.Join(errs...)
|
||||
return validate.Positive("refresh_interval", c.RefreshIvl)
|
||||
}
|
||||
|
||||
// connLimitConfig is the configuration structure for the stream-connection
|
||||
|
||||
@@ -126,7 +126,7 @@ type tlsConfigCerts []*tlsConfigCert
|
||||
func (certs tlsConfigCerts) store(ctx context.Context, tlsMgr tlsconfig.Manager) (err error) {
|
||||
var errs []error
|
||||
for i, c := range certs {
|
||||
err = tlsMgr.Add(ctx, c.Certificate, c.Key)
|
||||
err = tlsMgr.Add(ctx, c.Certificate, c.Key, false)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("adding certificate at index %d: %w", i, err))
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
)
|
||||
|
||||
// limitConn is a wrapper for a stream connection that decreases the counter
|
||||
|
||||
@@ -66,7 +66,12 @@ func (EmptyMetrics) DecrementActive(_ context.Context, _ *ConnMetricsData) {}
|
||||
func (EmptyMetrics) ObserveLifeDuration(_ context.Context, _ *ConnMetricsData, _ time.Duration) {}
|
||||
|
||||
// ObserveWaitingDuration implements the [Metrics] interface for EmptyMetrics.
|
||||
func (EmptyMetrics) ObserveWaitingDuration(_ context.Context, _ *ConnMetricsData, _ time.Duration) {}
|
||||
func (EmptyMetrics) ObserveWaitingDuration(
|
||||
_ context.Context,
|
||||
_ *ConnMetricsData,
|
||||
_ time.Duration,
|
||||
) {
|
||||
}
|
||||
|
||||
// SetStopLimit implements the [Metrics] interface for EmptyMetrics.
|
||||
func (EmptyMetrics) SetStopLimit(_ context.Context, _ uint64) {}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/AdguardTeam/golibs/testutil/fakeservice"
|
||||
"github.com/AdguardTeam/golibs/testutil/servicetest"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -79,14 +80,7 @@ func TestService_Start(t *testing.T) {
|
||||
svc := debugsvc.New(c)
|
||||
require.NotNil(t, svc)
|
||||
|
||||
var err error
|
||||
require.NotPanics(t, func() {
|
||||
err = svc.Start(testutil.ContextWithTimeout(t, testTimeout))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
testutil.CleanupAndRequireSuccess(t, func() (err error) {
|
||||
return svc.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
|
||||
})
|
||||
servicetest.RequireRun(t, svc, testTimeout)
|
||||
|
||||
client := agdhttp.NewClient(&agdhttp.ClientConfig{
|
||||
Timeout: testTimeout,
|
||||
@@ -105,10 +99,10 @@ func TestService_Start(t *testing.T) {
|
||||
// yet, check for it in periodically.
|
||||
var resp *http.Response
|
||||
healthCheckURL := srvURL.JoinPath(debugsvc.PathPatternHealthCheck)
|
||||
require.Eventually(t, func() (ok bool) {
|
||||
resp, err = client.Get(ctx, healthCheckURL)
|
||||
|
||||
return err == nil
|
||||
require.EventuallyWithT(t, func(ct *assert.CollectT) {
|
||||
var getErr error
|
||||
resp, getErr = client.Get(ctx, healthCheckURL)
|
||||
assert.NoError(t, getErr)
|
||||
}, testTimeout, testTimeout/10)
|
||||
|
||||
body := readRespBody(t, resp)
|
||||
@@ -116,7 +110,7 @@ func TestService_Start(t *testing.T) {
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// Check pprof service URL.
|
||||
resp, err = client.Get(ctx, srvURL.JoinPath(httputil.PprofBasePath))
|
||||
resp, err := client.Get(ctx, srvURL.JoinPath(httputil.PprofBasePath))
|
||||
require.NoError(t, err)
|
||||
|
||||
body = readRespBody(t, resp)
|
||||
|
||||
@@ -36,6 +36,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/mathutil/randutil"
|
||||
"github.com/AdguardTeam/golibs/service"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@@ -166,7 +167,7 @@ func NewHandler(conf *HandlerConfig) (h *Handler) {
|
||||
src := conf.RandSource
|
||||
if src == nil {
|
||||
// Do not initialize through [cmp.Or], as the default value could panic.
|
||||
src = rand.NewChaCha8(mustNewSeed())
|
||||
src = rand.NewChaCha8(randutil.MustNewSeed())
|
||||
}
|
||||
|
||||
hcConf := conf.Healthcheck
|
||||
@@ -177,10 +178,7 @@ func NewHandler(conf *HandlerConfig) (h *Handler) {
|
||||
h = &Handler{
|
||||
logger: cmp.Or(conf.Logger, slog.Default()),
|
||||
// #nosec G404 -- We don't need a real random, pseudorandom is enough.
|
||||
rand: rand.New(&lockedSource{
|
||||
mu: &sync.Mutex{},
|
||||
src: src,
|
||||
}),
|
||||
rand: rand.New(randutil.NewLockedSource(src)),
|
||||
activeUpstreamsMu: &sync.RWMutex{},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
package forward
|
||||
|
||||
import (
|
||||
cryptorand "crypto/rand"
|
||||
"math/rand/v2"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// mustNewSeed returns new 32 byte seed for pseudorandom generators. Panics on
|
||||
// errors.
|
||||
//
|
||||
// TODO(a.garipov): Remove once agdrand is merged into golibs.
|
||||
func mustNewSeed() (seed [32]byte) {
|
||||
_, err := cryptorand.Read(seed[:])
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return seed
|
||||
}
|
||||
|
||||
// lockedSource is an implementation of [rand.Source] that is concurrency-safe.
|
||||
//
|
||||
// TODO(a.garipov): Remove once agdrand is merged into golibs.
|
||||
type lockedSource struct {
|
||||
// mu protects src.
|
||||
mu *sync.Mutex
|
||||
src rand.Source
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ rand.Source = (*lockedSource)(nil)
|
||||
|
||||
// Uint64 implements the [rand.Source] interface for *lockedSource.
|
||||
func (s *lockedSource) Uint64() (r uint64) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return s.src.Uint64()
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
module github.com/AdguardTeam/AdGuardDNS/internal/dnsserver
|
||||
|
||||
go 1.24.3
|
||||
go 1.24.5
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/golibs v0.32.11
|
||||
github.com/AdguardTeam/golibs v0.32.15
|
||||
github.com/ameshkov/dnscrypt/v2 v2.4.0
|
||||
github.com/ameshkov/dnsstamps v1.0.3
|
||||
github.com/bluele/gcache v0.0.2
|
||||
@@ -14,7 +14,7 @@ require (
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/quic-go/quic-go v0.52.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/net v0.40.0
|
||||
golang.org/x/net v0.41.0
|
||||
golang.org/x/sys v0.33.0
|
||||
)
|
||||
|
||||
@@ -23,7 +23,7 @@ require (
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a // indirect
|
||||
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.23.4 // indirect
|
||||
github.com/onsi/gomega v1.37.0 // indirect
|
||||
@@ -35,12 +35,12 @@ require (
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
go.uber.org/mock v0.5.2 // indirect
|
||||
golang.org/x/crypto v0.38.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
golang.org/x/crypto v0.39.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
github.com/AdguardTeam/golibs v0.32.11 h1:75EquS8SWvzsM3JFJY0359ZBw66jDjAegteHzh9nSw8=
|
||||
github.com/AdguardTeam/golibs v0.32.15 h1:arDRDWiZCH3g5Onr8AqMnOHhaOppNoBpgC3DNhmeDeA=
|
||||
github.com/AdguardTeam/golibs v0.32.15/go.mod h1:G9CzUOzx87J+2u+eClJrrwWD7lMbROvuUnT8uvDUzIA=
|
||||
github.com/ameshkov/dnscrypt/v2 v2.4.0 h1:if6ZG2cuQmcP2TwSY+D0+8+xbPfoatufGlOQTMNkI9o=
|
||||
github.com/ameshkov/dnscrypt/v2 v2.4.0/go.mod h1:WpEFV2uhebXb8Jhes/5/fSdpmhGV8TL22RDaeWwV6hI=
|
||||
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
|
||||
@@ -14,12 +15,13 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4=
|
||||
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
|
||||
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18=
|
||||
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -62,21 +64,22 @@ go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b h1:QoALfVG9rhQ/M7vYDScfPdWjGL9dlsVVM5VGh7aKoAA=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -3,6 +3,7 @@ package prometheus_test
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
@@ -10,6 +11,9 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// testTimeout is the common timeout for tests.
|
||||
const testTimeout = 1 * time.Second
|
||||
|
||||
// testLogger is the common logger for tests.
|
||||
var testLogger = slogutil.NewDiscardLogger()
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
|
||||
dnssvcprom "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/prometheus"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/AdguardTeam/golibs/testutil/servicetest"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -37,13 +37,7 @@ func TestServerMetricsListener_integration_requestLifetime(t *testing.T) {
|
||||
srv := dnsserver.NewServerDNS(conf)
|
||||
|
||||
// Start the server.
|
||||
err = srv.Start(context.Background())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure the server shuts down in the end.
|
||||
testutil.CleanupAndRequireSuccess(t, func() (err error) {
|
||||
return srv.Shutdown(context.Background())
|
||||
})
|
||||
servicetest.RequireRun(t, srv, testTimeout)
|
||||
|
||||
// Create a test message.
|
||||
req := dnsservertest.CreateMessage(testReqDomain, dns.TypeA)
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/billstat"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/cmd/plugin"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/connlimiter"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
|
||||
@@ -17,7 +16,6 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/netext"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/initial"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
|
||||
@@ -110,12 +108,17 @@ type HandlersConfig struct {
|
||||
// profiles enabled.
|
||||
HumanIDParser *agd.HumanIDParser
|
||||
|
||||
// MainMiddlewareMetrics is used to collect metrics for the main middleware,
|
||||
// if needed.
|
||||
MainMiddlewareMetrics MainMiddlewareMetrics
|
||||
|
||||
// Messages is the message constructor used to create blocked and other
|
||||
// messages for this DNS service. It must not be nil.
|
||||
Messages *dnsmsg.Constructor
|
||||
|
||||
// PluginRegistry is used to override configuration parameters.
|
||||
PluginRegistry *plugin.Registry
|
||||
// PostInitialMiddleware is the middleware to run after the initial
|
||||
// middleware, if any.
|
||||
PostInitialMiddleware dnsserver.Middleware
|
||||
|
||||
// StructuredErrors is the configuration for the experimental Structured DNS
|
||||
// Errors feature in the profiles' message constructors. It must not be
|
||||
@@ -131,6 +134,9 @@ type HandlersConfig struct {
|
||||
// CacheManager is the global cache manager. It must not be nil.
|
||||
CacheManager agdcache.Manager
|
||||
|
||||
// CustomDomainDB is used to match custom domains. It must not be nil.
|
||||
CustomDomainDB CustomDomainDB
|
||||
|
||||
// DNSCheck is used by clients to check if they use AdGuard DNS. It must
|
||||
// not be nil.
|
||||
DNSCheck dnscheck.Interface
|
||||
@@ -184,6 +190,9 @@ type HandlersConfig struct {
|
||||
// valid Prometheus metric label.
|
||||
MetricsNamespace string
|
||||
|
||||
// NodeName is the name of this server node.
|
||||
NodeName string
|
||||
|
||||
// FilteringGroups are the DNS filtering groups. Each element must be
|
||||
// non-nil.
|
||||
FilteringGroups map[agd.FilteringGroupID]*agd.FilteringGroup
|
||||
@@ -269,7 +278,3 @@ type ServerGroupConfig struct {
|
||||
|
||||
// ServerGroupName is the name of a server group.
|
||||
type ServerGroupName string
|
||||
|
||||
// DDRConfig is the configuration for the server group's Discovery Of Designated
|
||||
// Resolvers (DDR) handlers.
|
||||
type DDRConfig = initial.DDRConfig
|
||||
|
||||
@@ -48,6 +48,7 @@ func NewHandlers(ctx context.Context, c *HandlersConfig) (handlers Handlers, err
|
||||
QueryLog: c.QueryLog,
|
||||
Metrics: mainMwMtrc,
|
||||
RuleStat: c.RuleStat,
|
||||
NodeName: c.NodeName,
|
||||
})
|
||||
|
||||
handler = mainMw.Wrap(handler)
|
||||
@@ -61,7 +62,7 @@ func NewHandlers(ctx context.Context, c *HandlersConfig) (handlers Handlers, err
|
||||
|
||||
handler = preSvcMw.Wrap(handler)
|
||||
|
||||
postInitMw := c.PluginRegistry.PostInitialMiddleware()
|
||||
postInitMw := c.PostInitialMiddleware
|
||||
if postInitMw != nil {
|
||||
handler = postInitMw.Wrap(handler)
|
||||
}
|
||||
@@ -149,12 +150,12 @@ func wrapPreUpstreamMw(
|
||||
// newMainMiddlewareMetrics returns a filtering-middleware metrics
|
||||
// implementation from the config.
|
||||
func newMainMiddlewareMetrics(c *HandlersConfig) (mainMwMtrc MainMiddlewareMetrics, err error) {
|
||||
mainMwMtrc = c.PluginRegistry.MainMiddlewareMetrics()
|
||||
mainMwMtrc = c.MainMiddlewareMetrics
|
||||
if mainMwMtrc != nil {
|
||||
return mainMwMtrc, nil
|
||||
}
|
||||
|
||||
mainMwMtrc, err = metrics.NewDefaultMainMiddleware(
|
||||
mainMwMtrc, err = metrics.NewMainMiddleware(
|
||||
c.BaseLogger.With(slogutil.KeyPrefix, "mainmw_metrics"),
|
||||
c.MetricsNamespace,
|
||||
c.PrometheusRegisterer,
|
||||
@@ -168,15 +169,27 @@ func newMainMiddlewareMetrics(c *HandlersConfig) (mainMwMtrc MainMiddlewareMetri
|
||||
|
||||
// newHandlersForServers returns a handler map for each server group and each
|
||||
// server.
|
||||
func newHandlersForServers(c *HandlersConfig, handler dnsserver.Handler) (handlers Handlers, err error) {
|
||||
rlMwMtrc, err := metrics.NewDefaultRatelimitMiddleware(
|
||||
c.MetricsNamespace,
|
||||
c.PrometheusRegisterer,
|
||||
)
|
||||
//
|
||||
// TODO(a.garipov): Refactor.
|
||||
func newHandlersForServers(
|
||||
c *HandlersConfig,
|
||||
handler dnsserver.Handler,
|
||||
) (handlers Handlers, err error) {
|
||||
initMwMtrc, err := metrics.NewInitialMiddleware(c.MetricsNamespace, c.PrometheusRegisterer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initial middleware metrics: %w", err)
|
||||
}
|
||||
|
||||
rlMwMtrc, err := metrics.NewRatelimitMiddleware(c.MetricsNamespace, c.PrometheusRegisterer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ratelimit middleware metrics: %w", err)
|
||||
}
|
||||
|
||||
dfMtrc, err := metrics.NewDeviceFinder(c.MetricsNamespace, c.PrometheusRegisterer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("device finder metrics: %w", err)
|
||||
}
|
||||
|
||||
handlers = Handlers{}
|
||||
|
||||
rlMwLogger := c.BaseLogger.With(slogutil.KeyPrefix, "ratelimitmw")
|
||||
@@ -191,8 +204,9 @@ func newHandlersForServers(c *HandlersConfig, handler dnsserver.Handler) (handle
|
||||
}
|
||||
|
||||
initMw := initial.New(&initial.Config{
|
||||
Logger: c.BaseLogger.With(slogutil.KeyPrefix, "initmw"),
|
||||
DDR: srvGrp.DDR,
|
||||
Logger: c.BaseLogger.With(slogutil.KeyPrefix, "initmw"),
|
||||
Metrics: initMwMtrc,
|
||||
DDR: srvGrp.DDR,
|
||||
})
|
||||
|
||||
srvGrpHandler := initMw.Wrap(handler)
|
||||
@@ -213,7 +227,7 @@ func newHandlersForServers(c *HandlersConfig, handler dnsserver.Handler) (handle
|
||||
ServerInfo: srvInfo,
|
||||
StructuredErrors: c.StructuredErrors,
|
||||
AccessManager: c.AccessManager,
|
||||
DeviceFinder: newDeviceFinder(c, srvGrp, srv),
|
||||
DeviceFinder: newDeviceFinder(c, srvGrp, srv, dfMtrc),
|
||||
ErrColl: c.ErrColl,
|
||||
GeoIP: c.GeoIP,
|
||||
Metrics: rlMwMtrc,
|
||||
@@ -236,18 +250,22 @@ func newHandlersForServers(c *HandlersConfig, handler dnsserver.Handler) (handle
|
||||
|
||||
// newDeviceFinder returns a new agd.DeviceFinder for a server based on the
|
||||
// configuration. All arguments must not be nil.
|
||||
func newDeviceFinder(c *HandlersConfig, g *ServerGroupConfig, s *agd.Server) (df agd.DeviceFinder) {
|
||||
func newDeviceFinder(
|
||||
c *HandlersConfig,
|
||||
g *ServerGroupConfig,
|
||||
s *agd.Server,
|
||||
mtrc DeviceFinderMetrics,
|
||||
) (df agd.DeviceFinder) {
|
||||
if !g.ProfilesEnabled {
|
||||
return agd.EmptyDeviceFinder{}
|
||||
}
|
||||
|
||||
return devicefinder.NewDefault(&devicefinder.Config{
|
||||
HumanIDParser: c.HumanIDParser,
|
||||
Logger: c.BaseLogger.With(slogutil.KeyPrefix, "devicefinder"),
|
||||
Server: s,
|
||||
// TODO(a.garipov): Use a real one after implementing the interface in
|
||||
// package tlsconfig.
|
||||
CustomDomainDB: devicefinder.EmptyCustomDomainDB{},
|
||||
HumanIDParser: c.HumanIDParser,
|
||||
Logger: c.BaseLogger.With(slogutil.KeyPrefix, "devicefinder"),
|
||||
Server: s,
|
||||
CustomDomainDB: c.CustomDomainDB,
|
||||
Metrics: mtrc,
|
||||
ProfileDB: c.ProfileDB,
|
||||
DeviceDomains: g.DeviceDomains,
|
||||
})
|
||||
|
||||
@@ -150,17 +150,20 @@ func TestNewHandlers(t *testing.T) {
|
||||
|
||||
ctx := testutil.ContextWithTimeout(t, dnssvctest.Timeout)
|
||||
handlers, err := dnssvc.NewHandlers(ctx, &dnssvc.HandlersConfig{
|
||||
BaseLogger: testLogger,
|
||||
Cloner: agdtest.NewCloner(),
|
||||
Cache: tc.cacheConf,
|
||||
HumanIDParser: agd.NewHumanIDParser(),
|
||||
Messages: agdtest.NewConstructor(t),
|
||||
PluginRegistry: nil,
|
||||
StructuredErrors: agdtest.NewSDEConfig(true),
|
||||
AccessManager: accessMgr,
|
||||
BillStat: billStat,
|
||||
BaseLogger: testLogger,
|
||||
Cloner: agdtest.NewCloner(),
|
||||
Cache: tc.cacheConf,
|
||||
HumanIDParser: agd.NewHumanIDParser(),
|
||||
MainMiddlewareMetrics: nil,
|
||||
Messages: agdtest.NewConstructor(t),
|
||||
PostInitialMiddleware: nil,
|
||||
StructuredErrors: agdtest.NewSDEConfig(true),
|
||||
AccessManager: accessMgr,
|
||||
BillStat: billStat,
|
||||
// TODO(a.garipov): Create a test implementation?
|
||||
CacheManager: agdcache.EmptyManager{},
|
||||
CacheManager: agdcache.EmptyManager{},
|
||||
// TODO(a.garipov): Create a test implementation?
|
||||
CustomDomainDB: dnssvc.EmptyCustomDomainDB{},
|
||||
DNSCheck: dnsCk,
|
||||
DNSDB: dnsDB,
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
@@ -174,6 +177,7 @@ func TestNewHandlers(t *testing.T) {
|
||||
RateLimit: agdtest.NewRateLimit(),
|
||||
RuleStat: ruleStat,
|
||||
MetricsNamespace: path.Base(t.Name()),
|
||||
NodeName: t.Name(),
|
||||
FilteringGroups: fltGrps,
|
||||
ServerGroups: []*dnssvc.ServerGroupConfig{srvGrp},
|
||||
EDEEnabled: true,
|
||||
|
||||
@@ -232,6 +232,7 @@ func newTestService(
|
||||
},
|
||||
},
|
||||
CacheManager: agdcache.EmptyManager{},
|
||||
CustomDomainDB: dnssvc.EmptyCustomDomainDB{},
|
||||
DNSCheck: dnsCk,
|
||||
DNSDB: dnsDB,
|
||||
ErrColl: errColl,
|
||||
@@ -245,6 +246,7 @@ func newTestService(
|
||||
RateLimit: rl,
|
||||
RuleStat: ruleStat,
|
||||
MetricsNamespace: path.Base(t.Name()),
|
||||
NodeName: t.Name(),
|
||||
FilteringGroups: map[agd.FilteringGroupID]*agd.FilteringGroup{
|
||||
dnssvctest.FilteringGroupID: fltGrp,
|
||||
},
|
||||
|
||||
@@ -9,10 +9,14 @@ import (
|
||||
// CustomDomainDB contains information about custom domains and matches domains.
|
||||
type CustomDomainDB interface {
|
||||
// Match returns the domain name or wildcard that matches the client-sent
|
||||
// server name. If there is a match, matchedDomain must be a valid domain
|
||||
// name or wildcard, and profID must not be empty and must be valid.
|
||||
// Otherwise, both matchedDomain and profID must be empty.
|
||||
Match(ctx context.Context, cliSrvName string) (matchedDomain string, profID agd.ProfileID)
|
||||
// server name. cliSrvName must be lowercased.
|
||||
//
|
||||
// If there is a match, matchedDomain must be a valid domain name or
|
||||
// wildcard, and profIDs must not be empty and its items must be valid.
|
||||
// Otherwise, matchedDomain must be empty and profIDs must be nil.
|
||||
//
|
||||
// TODO(a.garipov, e.burkov): Reduce allocations of profIDs.
|
||||
Match(ctx context.Context, cliSrvName string) (matchedDomain string, profIDs []agd.ProfileID)
|
||||
}
|
||||
|
||||
// EmptyCustomDomainDB is an [CustomDomainDB] that does nothing.
|
||||
@@ -26,6 +30,6 @@ var _ CustomDomainDB = EmptyCustomDomainDB{}
|
||||
func (EmptyCustomDomainDB) Match(
|
||||
_ context.Context,
|
||||
_ string,
|
||||
) (matchedDomain string, profID agd.ProfileID) {
|
||||
return "", ""
|
||||
) (matchedDomain string, profIDs []agd.ProfileID) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"slices"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
)
|
||||
|
||||
@@ -118,16 +118,18 @@ func (f *Default) deviceResultByCustomDomain(
|
||||
switch dd := cd.deviceData.(type) {
|
||||
case *deviceDataID:
|
||||
prof, dev, err := f.profileDB.ProfileByDeviceID(ctx, dd.id)
|
||||
if err != nil || (prof != nil && prof.ID == cd.profileID) {
|
||||
if err != nil || (prof != nil && slices.Contains(cd.profileIDs, prof.ID)) {
|
||||
return f.newDeviceResult(ctx, prof, dev, "custom domain and device id", err)
|
||||
}
|
||||
|
||||
f.metrics.IncrementCustomDomainMismatches(ctx, cd.domain)
|
||||
|
||||
optslog.Debug4(
|
||||
ctx,
|
||||
f.logger,
|
||||
"custom-domain device and required profile mismatch",
|
||||
"domain", cd.domain,
|
||||
"required_profile_id", cd.profileID,
|
||||
"required_profile_ids", cd.profileIDs,
|
||||
"dev_id", dev.ID,
|
||||
"dev_prof_id", prof.ID,
|
||||
)
|
||||
@@ -223,10 +225,7 @@ func (f *Default) deviceByAddrs(
|
||||
}
|
||||
|
||||
// deviceByLocalAddr finds the profile and the device by the local address.
|
||||
func (f *Default) deviceByLocalAddr(
|
||||
ctx context.Context,
|
||||
localIP netip.Addr,
|
||||
) (r agd.DeviceResult) {
|
||||
func (f *Default) deviceByLocalAddr(ctx context.Context, localIP netip.Addr) (r agd.DeviceResult) {
|
||||
p, d, err := f.profileDB.ProfileByDedicatedIP(ctx, localIP)
|
||||
if err == nil {
|
||||
optslog.Debug3(
|
||||
@@ -251,6 +250,8 @@ func (f *Default) deviceByLocalAddr(
|
||||
}
|
||||
}
|
||||
|
||||
f.metrics.IncrementUnknownDedicated(ctx)
|
||||
|
||||
optslog.Debug2(
|
||||
ctx,
|
||||
f.logger,
|
||||
@@ -275,7 +276,7 @@ func (f *Default) authenticatedResult(
|
||||
dev := res.Device
|
||||
err := f.authenticate(ctx, srvReqInfo, dev)
|
||||
if err != nil {
|
||||
metrics.DNSSvcDoHAuthFailsTotal.Inc()
|
||||
f.metrics.IncrementDoHAuthenticationFails(ctx)
|
||||
|
||||
optslog.Debug2(
|
||||
ctx,
|
||||
|
||||
@@ -5,15 +5,15 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/validate"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -75,7 +75,7 @@ func (*deviceDataID) isDeviceData() {}
|
||||
type deviceDataCustomDomain struct {
|
||||
// deviceData is the underlying device data, which must be either a
|
||||
// [deviceDataID] or a [deviceDataExtHumanID]. If it's the latter, the
|
||||
// profile IDs must match.
|
||||
// profile IDs must contain the profile ID of the device.
|
||||
deviceData deviceData
|
||||
|
||||
// domain is the domain or wildcard that has matched the request. It must
|
||||
@@ -84,7 +84,7 @@ type deviceDataCustomDomain struct {
|
||||
|
||||
// profileID is the ID of the profile owning the custom domain. It must not
|
||||
// be empty.
|
||||
profileID agd.ProfileID
|
||||
profileIDs []agd.ProfileID
|
||||
}
|
||||
|
||||
// type check
|
||||
@@ -125,11 +125,13 @@ func (f *Default) deviceDataFromEncrypted(
|
||||
ctx context.Context,
|
||||
srvReqInfo *dnsserver.RequestInfo,
|
||||
) (dd deviceData, err error) {
|
||||
cliSrvName := srvReqInfo.TLSServerName
|
||||
var customDomain string
|
||||
var requiredProfileID agd.ProfileID
|
||||
if cliSrvName != "" {
|
||||
customDomain, requiredProfileID = f.customDomainDB.Match(ctx, cliSrvName)
|
||||
var requiredProfileIDs []agd.ProfileID
|
||||
if cliSrvName := strings.ToLower(srvReqInfo.TLSServerName); cliSrvName != "" {
|
||||
customDomain, requiredProfileIDs = f.customDomainDB.Match(ctx, cliSrvName)
|
||||
if customDomain != "" {
|
||||
f.metrics.IncrementCustomDomainRequests(ctx, customDomain)
|
||||
}
|
||||
}
|
||||
|
||||
dd, err = f.deviceDataFromSrvReqInfo(ctx, srvReqInfo, customDomain)
|
||||
@@ -137,7 +139,7 @@ func (f *Default) deviceDataFromEncrypted(
|
||||
return nil, fmt.Errorf("extracting device data: %w", err)
|
||||
}
|
||||
|
||||
dd, err = f.wrapCustomDomain(ctx, dd, customDomain, requiredProfileID)
|
||||
dd, err = f.wrapCustomDomain(ctx, dd, customDomain, requiredProfileIDs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wrapping custom domains: %w", err)
|
||||
}
|
||||
@@ -255,9 +257,9 @@ func (f *Default) wrapCustomDomain(
|
||||
ctx context.Context,
|
||||
dd deviceData,
|
||||
matchedDomain string,
|
||||
requiredProfileID agd.ProfileID,
|
||||
requiredProfileIDs []agd.ProfileID,
|
||||
) (wrapped deviceData, err error) {
|
||||
if requiredProfileID == "" {
|
||||
if requiredProfileIDs == nil {
|
||||
return dd, nil
|
||||
}
|
||||
|
||||
@@ -265,23 +267,25 @@ func (f *Default) wrapCustomDomain(
|
||||
case nil:
|
||||
return nil, nil
|
||||
case *deviceDataExtHumanID:
|
||||
err = validate.Equal("profile id in ext id", dd.profileID, requiredProfileID)
|
||||
if err != nil {
|
||||
const msg = "custom domain profile and ext id mismatch"
|
||||
optslog.Debug2(ctx, f.logger, msg, "got", dd.profileID, "want", requiredProfileID)
|
||||
if !slices.Contains(requiredProfileIDs, dd.profileID) {
|
||||
const msg = "custom domain profiles and ext id mismatch"
|
||||
optslog.Debug2(ctx, f.logger, msg, "got", dd.profileID, "want", requiredProfileIDs)
|
||||
|
||||
const errMsg = "profile id in ext id: %s: not contained by expected values"
|
||||
err = fmt.Errorf(errMsg, dd.profileID)
|
||||
|
||||
return nil, newDeviceDataError(err, "custom domain")
|
||||
}
|
||||
|
||||
return &deviceDataCustomDomain{
|
||||
domain: matchedDomain,
|
||||
profileID: requiredProfileID,
|
||||
profileIDs: requiredProfileIDs,
|
||||
deviceData: dd,
|
||||
}, nil
|
||||
case *deviceDataID:
|
||||
return &deviceDataCustomDomain{
|
||||
domain: matchedDomain,
|
||||
profileID: requiredProfileID,
|
||||
profileIDs: requiredProfileIDs,
|
||||
deviceData: dd,
|
||||
}, nil
|
||||
default:
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"net/url"
|
||||
"path"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
@@ -405,7 +406,7 @@ type testCustomDomainDB struct {
|
||||
onMatch func(
|
||||
ctx context.Context,
|
||||
cliSrvName string,
|
||||
) (matchedDomain string, profID agd.ProfileID)
|
||||
) (matchedDomain string, profIDs []agd.ProfileID)
|
||||
}
|
||||
|
||||
// type check
|
||||
@@ -415,16 +416,16 @@ var _ devicefinder.CustomDomainDB = (*testCustomDomainDB)(nil)
|
||||
func (db *testCustomDomainDB) Match(
|
||||
ctx context.Context,
|
||||
cliSrvName string,
|
||||
) (matchedDomain string, profID agd.ProfileID) {
|
||||
) (matchedDomain string, profIDs []agd.ProfileID) {
|
||||
return db.onMatch(ctx, cliSrvName)
|
||||
}
|
||||
|
||||
// newTestCustomDomainDB returns a *testCustomDomainDB that returns the given
|
||||
// data.
|
||||
func newTestCustomDomainDB(domain string, id agd.ProfileID) (db *testCustomDomainDB) {
|
||||
func newTestCustomDomainDB(domain string, ids []agd.ProfileID) (db *testCustomDomainDB) {
|
||||
return &testCustomDomainDB{
|
||||
onMatch: func(_ context.Context, _ string) (matchedDomain string, profID agd.ProfileID) {
|
||||
return domain, id
|
||||
onMatch: func(_ context.Context, _ string) (matchedDomain string, profIDs []agd.ProfileID) {
|
||||
return domain, slices.Clone(ids)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -435,17 +436,25 @@ func TestDefault_Find_customDomainDoT(t *testing.T) {
|
||||
|
||||
const customDomain = "custom.example"
|
||||
|
||||
var (
|
||||
customDBMatch = newTestCustomDomainDB(customDomain, dnssvctest.ProfileID)
|
||||
customDBMatchWk = newTestCustomDomainDB("*."+customDomain, dnssvctest.ProfileID)
|
||||
customDBNoMatch = newTestCustomDomainDB("", "")
|
||||
)
|
||||
|
||||
const profIDOtherStr = "prof5678"
|
||||
profOther := &agd.Profile{}
|
||||
*profOther = *profNormal
|
||||
profOther.ID = agd.ProfileID(profIDOtherStr)
|
||||
|
||||
var (
|
||||
customDBMatch = newTestCustomDomainDB(customDomain, []agd.ProfileID{
|
||||
dnssvctest.ProfileID,
|
||||
})
|
||||
customDBMatchWkSeveral = newTestCustomDomainDB("*."+customDomain, []agd.ProfileID{
|
||||
dnssvctest.ProfileID,
|
||||
profIDOtherStr,
|
||||
})
|
||||
customDBMatchWk = newTestCustomDomainDB("*."+customDomain, []agd.ProfileID{
|
||||
dnssvctest.ProfileID,
|
||||
})
|
||||
customDBNoMatch = newTestCustomDomainDB("", nil)
|
||||
)
|
||||
|
||||
profDBDefault := agdtest.NewProfileDB()
|
||||
|
||||
profDBFoundDevID := agdtest.NewProfileDB()
|
||||
@@ -473,8 +482,7 @@ func TestDefault_Find_customDomainDoT(t *testing.T) {
|
||||
const cliSrvNameDev = dnssvctest.DeviceIDStr + "." + customDomain
|
||||
|
||||
const errStrMismatch errors.Error = `wrapping custom domains: custom domain device id check: ` +
|
||||
`profile id in ext id: not equal to expected value: ` +
|
||||
`got ` + profIDOtherStr + `, want ` + dnssvctest.ProfileIDStr
|
||||
`profile id in ext id: ` + profIDOtherStr + `: not contained by expected values`
|
||||
|
||||
testCases := []struct {
|
||||
customDB devicefinder.CustomDomainDB
|
||||
@@ -488,6 +496,12 @@ func TestDefault_Find_customDomainDoT(t *testing.T) {
|
||||
wantRes: resNormal,
|
||||
cliSrvName: cliSrvNameDev,
|
||||
name: "custom_device_match",
|
||||
}, {
|
||||
customDB: customDBMatchWkSeveral,
|
||||
profDB: profDBFoundDevID,
|
||||
wantRes: resNormal,
|
||||
cliSrvName: cliSrvNameDev,
|
||||
name: "custom_device_match_several",
|
||||
}, {
|
||||
customDB: customDBNoMatch,
|
||||
profDB: profDBDefault,
|
||||
|
||||
@@ -30,6 +30,10 @@ type Config struct {
|
||||
// CustomDomainDB is used to match custom domains. It must not be nil.
|
||||
CustomDomainDB CustomDomainDB
|
||||
|
||||
// Metrics are used to collect the statistics of the default device finder.
|
||||
// It must not be nil.
|
||||
Metrics Metrics
|
||||
|
||||
// ProfileDB is used to find the profiles. It must not be nil.
|
||||
ProfileDB profiledb.Interface
|
||||
|
||||
@@ -44,6 +48,7 @@ type Default struct {
|
||||
logger *slog.Logger
|
||||
srv *agd.Server
|
||||
customDomainDB CustomDomainDB
|
||||
metrics Metrics
|
||||
profileDB profiledb.Interface
|
||||
deviceDomains []string
|
||||
}
|
||||
@@ -55,6 +60,7 @@ func NewDefault(c *Config) (f *Default) {
|
||||
logger: c.Logger,
|
||||
srv: c.Server,
|
||||
customDomainDB: c.CustomDomainDB,
|
||||
metrics: c.Metrics,
|
||||
profileDB: c.ProfileDB,
|
||||
deviceDomains: c.DeviceDomains,
|
||||
}
|
||||
|
||||
@@ -280,6 +280,7 @@ func newDefault(tb testing.TB, c *devicefinder.Config) (f *devicefinder.Default)
|
||||
c.CustomDomainDB,
|
||||
devicefinder.EmptyCustomDomainDB{},
|
||||
)
|
||||
c.Metrics = cmp.Or[devicefinder.Metrics](c.Metrics, devicefinder.EmptyMetrics{})
|
||||
c.ProfileDB = cmp.Or[profiledb.Interface](c.ProfileDB, agdtest.NewProfileDB())
|
||||
|
||||
return devicefinder.NewDefault(c)
|
||||
|
||||
45
internal/dnssvc/internal/devicefinder/metrics.go
Normal file
45
internal/dnssvc/internal/devicefinder/metrics.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package devicefinder
|
||||
|
||||
import "context"
|
||||
|
||||
// Metrics is an interface for collection of the statistics of the default
|
||||
// device finder.
|
||||
type Metrics interface {
|
||||
// IncrementCustomDomainMismatches is called when a detected device does not
|
||||
// belong to the profile which the custom domain belongs to.
|
||||
IncrementCustomDomainMismatches(ctx context.Context, domain string)
|
||||
|
||||
// IncrementCustomDomainRequests is called when a request is recognized as
|
||||
// being to a custom domain belonging to a profile.
|
||||
IncrementCustomDomainRequests(ctx context.Context, domain string)
|
||||
|
||||
// IncrementDoHAuthenticationFails is called when a request fails DoH
|
||||
// authentication.
|
||||
IncrementDoHAuthenticationFails(ctx context.Context)
|
||||
|
||||
// IncrementUnknownDedicated is called when the DNS request is sent to an
|
||||
// unknown local address.
|
||||
IncrementUnknownDedicated(ctx context.Context)
|
||||
}
|
||||
|
||||
// EmptyMetrics is an empty [Metrics] implementation that does nothing.
|
||||
type EmptyMetrics struct{}
|
||||
|
||||
// type check
|
||||
var _ Metrics = EmptyMetrics{}
|
||||
|
||||
// IncrementCustomDomainRequests implements the [Metrics] interface for
|
||||
// EmptyMetrics.
|
||||
func (EmptyMetrics) IncrementCustomDomainRequests(_ context.Context, _ string) {}
|
||||
|
||||
// IncrementCustomDomainMismatches implements the [Metrics] interface for
|
||||
// EmptyMetrics.
|
||||
func (EmptyMetrics) IncrementCustomDomainMismatches(_ context.Context, _ string) {}
|
||||
|
||||
// IncrementDoHAuthenticationFails implements the [Metrics] interface for
|
||||
// EmptyMetrics.
|
||||
func (EmptyMetrics) IncrementDoHAuthenticationFails(_ context.Context) {}
|
||||
|
||||
// IncrementUnknownDedicated implements the [Metrics] interface for
|
||||
// EmptyMetrics.
|
||||
func (EmptyMetrics) IncrementUnknownDedicated(_ context.Context) {}
|
||||
@@ -15,9 +15,9 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -25,8 +25,9 @@ import (
|
||||
// middleware must be the most outer middleware apart from the ratelimit/access
|
||||
// middleware.
|
||||
type Middleware struct {
|
||||
logger *slog.Logger
|
||||
ddr *DDRConfig
|
||||
logger *slog.Logger
|
||||
metrics Metrics
|
||||
ddr *DDRConfig
|
||||
}
|
||||
|
||||
// Config is the configuration structure for the initial middleware. All fields
|
||||
@@ -35,6 +36,9 @@ type Config struct {
|
||||
// Logger is used to log the operation of the middleware.
|
||||
Logger *slog.Logger
|
||||
|
||||
// Metrics is used to collect the statistics of the middleware.
|
||||
Metrics Metrics
|
||||
|
||||
// DDR is the configuration for the server group's Discovery Of Designated
|
||||
// Resolvers (DDR) handlers. It must not be nil.
|
||||
DDR *DDRConfig
|
||||
@@ -68,8 +72,9 @@ type DDRConfig struct {
|
||||
// must be valid.
|
||||
func New(c *Config) (mw *Middleware) {
|
||||
return &Middleware{
|
||||
logger: c.Logger,
|
||||
ddr: c.DDR,
|
||||
logger: c.Logger,
|
||||
metrics: c.Metrics,
|
||||
ddr: c.DDR,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
51
internal/dnssvc/internal/initial/metrics.go
Normal file
51
internal/dnssvc/internal/initial/metrics.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package initial
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Request kinds for [Metrics].
|
||||
const (
|
||||
// MetricsRequestKindDDR is a label for requests for Discovery of Designated
|
||||
// Resolvers.
|
||||
MetricsRequestKindDDR = "ddr"
|
||||
|
||||
// MetricsRequestKindBadResolverARPA is a label for requests for malformed
|
||||
// resolver.arpa queries.
|
||||
MetricsRequestKindBadResolverARPA = "bad_resolver_arpa"
|
||||
|
||||
// MetricsRequestKindChromePrefetch is a label for requests for the domain
|
||||
// name that Chrome uses to check if it should use its prefetch proxy.
|
||||
MetricsRequestKindChromePrefetch = "chrome_prefetch"
|
||||
|
||||
// MetricsRequestKindFirefox is a label for requests for the domain name
|
||||
// that Firefox uses to check if it should use its own DNS-over-HTTPS
|
||||
// settings.
|
||||
MetricsRequestKindFirefox = "firefox"
|
||||
|
||||
// MetricsRequestKindApplePrivateRelay is a label for requests for the
|
||||
// domain name that Apple devices use to check if Apple Private Relay can be
|
||||
// enabled.
|
||||
MetricsRequestKindApplePrivateRelay = "apple_private_relay"
|
||||
)
|
||||
|
||||
// Metrics is an interface that is used for collection of statistics for DNS
|
||||
// requests for special domain names.
|
||||
type Metrics interface {
|
||||
// IncrementRequestsTotal increments the total number of DNS requests for
|
||||
// special domain names of the specified kind. kind must be one of the
|
||||
// following: [MetricsRequestKindDDR], [MetricsRequestKindBadResolverARPA],
|
||||
// [MetricsRequestKindChromePrefetch], [MetricsRequestKindFirefox] or
|
||||
// [MetricsRequestKindApplePrivateRelay].
|
||||
IncrementRequestsTotal(ctx context.Context, kind string)
|
||||
}
|
||||
|
||||
// EmptyMetrics is the implementation of the [Metrics] interface that does
|
||||
// nothing.
|
||||
type EmptyMetrics struct{}
|
||||
|
||||
// type check
|
||||
var _ Metrics = EmptyMetrics{}
|
||||
|
||||
// IncrementRequestsTotal implements the [Metrics] interface for EmptyMetrics.
|
||||
func (EmptyMetrics) IncrementRequestsTotal(_ context.Context, _ string) {}
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/miekg/dns"
|
||||
@@ -159,7 +158,7 @@ func (mw *Middleware) handleDDR(
|
||||
) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "writing ddr resp for %q: %w", ri.Host) }()
|
||||
|
||||
metrics.DNSSvcDDRRequestsTotal.Inc()
|
||||
mw.metrics.IncrementRequestsTotal(ctx, MetricsRequestKindDDR)
|
||||
|
||||
if mw.ddr.Enabled {
|
||||
return rw.WriteMsg(ctx, req, mw.newRespDDR(req, ri))
|
||||
@@ -178,7 +177,7 @@ func (mw *Middleware) handleDDRNoData(
|
||||
) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "writing ddr resp for %q: %w", ri.Host) }()
|
||||
|
||||
metrics.DNSSvcDDRRequestsTotal.Inc()
|
||||
mw.metrics.IncrementRequestsTotal(ctx, MetricsRequestKindDDR)
|
||||
|
||||
if mw.ddr.Enabled {
|
||||
return rw.WriteMsg(ctx, req, ri.Messages.NewRespRCode(req, dns.RcodeSuccess))
|
||||
@@ -225,7 +224,7 @@ func (mw *Middleware) handleBadResolverARPA(
|
||||
req *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
) (err error) {
|
||||
metrics.DNSSvcBadResolverARPA.Inc()
|
||||
mw.metrics.IncrementRequestsTotal(ctx, MetricsRequestKindBadResolverARPA)
|
||||
|
||||
resp := ri.Messages.NewRespRCode(req, dns.RcodeSuccess)
|
||||
err = rw.WriteMsg(ctx, req, resp)
|
||||
@@ -288,7 +287,7 @@ func (mw *Middleware) handleChromePrefetch(
|
||||
req *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
) (err error) {
|
||||
metrics.DNSSvcChromePrefetchRequestsTotal.Inc()
|
||||
mw.metrics.IncrementRequestsTotal(ctx, MetricsRequestKindChromePrefetch)
|
||||
|
||||
resp := ri.Messages.NewRespRCode(req, dns.RcodeNameError)
|
||||
err = rw.WriteMsg(ctx, req, resp)
|
||||
@@ -314,7 +313,7 @@ func (mw *Middleware) handleFirefoxCanary(
|
||||
req *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
) (err error) {
|
||||
metrics.DNSSvcFirefoxRequestsTotal.Inc()
|
||||
mw.metrics.IncrementRequestsTotal(ctx, MetricsRequestKindFirefox)
|
||||
|
||||
resp := ri.Messages.NewRespRCode(req, dns.RcodeRefused)
|
||||
err = rw.WriteMsg(ctx, req, resp)
|
||||
@@ -340,7 +339,7 @@ func (mw *Middleware) handlePrivateRelay(
|
||||
req *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
) (err error) {
|
||||
metrics.DNSSvcApplePrivateRelayRequestsTotal.Inc()
|
||||
mw.metrics.IncrementRequestsTotal(ctx, MetricsRequestKindApplePrivateRelay)
|
||||
|
||||
resp := ri.Messages.NewRespRCode(req, dns.RcodeNameError)
|
||||
err = rw.WriteMsg(ctx, req, resp)
|
||||
|
||||
@@ -122,7 +122,8 @@ func TestMiddleware_Wrap_specialDomain(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
mw := initial.New(&initial.Config{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Metrics: initial.EmptyMetrics{},
|
||||
DDR: &initial.DDRConfig{
|
||||
Enabled: false,
|
||||
},
|
||||
|
||||
@@ -22,6 +22,7 @@ const (
|
||||
hdrNameCountry = "country"
|
||||
hdrNameDeviceID = "device-id"
|
||||
hdrNameHumanID = "human-id"
|
||||
hdrNameNodeName = "node-name"
|
||||
hdrNameProfileID = "profile-id"
|
||||
hdrNameResType = "res-type"
|
||||
hdrNameRule = "rule"
|
||||
@@ -65,6 +66,12 @@ func (mw *Middleware) writeDebugResponse(
|
||||
return fmt.Errorf("adding %s extra: %w", hdrNameServerIP, err)
|
||||
}
|
||||
|
||||
setQuestionName(debugReq, "", hdrNameNodeName)
|
||||
err = mw.messages.AppendDebugExtra(debugReq, resp, mw.nodeName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("adding %s extra: %w", hdrNameNodeName, err)
|
||||
}
|
||||
|
||||
err = mw.appendDebugExtraFromContext(ctx, debugReq, resp)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
|
||||
@@ -50,20 +50,23 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
mw := &Middleware{
|
||||
messages: msgs,
|
||||
cloner: cloner,
|
||||
errColl: agdtest.NewErrorCollector(),
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Consider moving to dnssvctest and DRY'ing with
|
||||
// mainmw_test.
|
||||
const (
|
||||
allowRule = "||" + dnssvctest.DomainAllowed + "^"
|
||||
blockRule = "||" + dnssvctest.DomainBlocked + "^"
|
||||
rewriteRule = "||" + dnssvctest.DomainRewritten + "^$dnsrewrite=REFUSED"
|
||||
|
||||
nodeName = "test-node"
|
||||
)
|
||||
|
||||
mw := &Middleware{
|
||||
messages: msgs,
|
||||
cloner: cloner,
|
||||
errColl: agdtest.NewErrorCollector(),
|
||||
nodeName: nodeName,
|
||||
}
|
||||
|
||||
clientIPStr := dnssvctest.ClientIP.String()
|
||||
serverIPStr := dnssvctest.ServerAddr.String()
|
||||
|
||||
@@ -87,6 +90,7 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
|
||||
wantExtra: newTXTExtra([][2]string{
|
||||
{"client-ip.adguard-dns.com.", clientIPStr},
|
||||
{"server-ip.adguard-dns.com.", serverIPStr},
|
||||
{"node-name.adguard-dns.com.", nodeName},
|
||||
{"resp.res-type.adguard-dns.com.", "normal"},
|
||||
}),
|
||||
}, {
|
||||
@@ -98,6 +102,7 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
|
||||
wantExtra: newTXTExtra([][2]string{
|
||||
{"client-ip.adguard-dns.com.", clientIPStr},
|
||||
{"server-ip.adguard-dns.com.", serverIPStr},
|
||||
{"node-name.adguard-dns.com.", nodeName},
|
||||
{"req.res-type.adguard-dns.com.", "blocked"},
|
||||
{"req.rule.adguard-dns.com.", blockRule},
|
||||
{"req.rule-list-id.adguard-dns.com.", dnssvctest.FilterListID1Str},
|
||||
@@ -111,6 +116,7 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
|
||||
wantExtra: newTXTExtra([][2]string{
|
||||
{"client-ip.adguard-dns.com.", clientIPStr},
|
||||
{"server-ip.adguard-dns.com.", serverIPStr},
|
||||
{"node-name.adguard-dns.com.", nodeName},
|
||||
{"resp.res-type.adguard-dns.com.", "blocked"},
|
||||
{"resp.rule.adguard-dns.com.", blockRule},
|
||||
{"resp.rule-list-id.adguard-dns.com.", dnssvctest.FilterListID2Str},
|
||||
@@ -126,6 +132,7 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
|
||||
wantExtra: newTXTExtra([][2]string{
|
||||
{"client-ip.adguard-dns.com.", clientIPStr},
|
||||
{"server-ip.adguard-dns.com.", serverIPStr},
|
||||
{"node-name.adguard-dns.com.", nodeName},
|
||||
{"req.res-type.adguard-dns.com.", "allowed"},
|
||||
{"req.rule.adguard-dns.com.", allowRule},
|
||||
{"req.rule-list-id.adguard-dns.com.", ""},
|
||||
@@ -141,6 +148,7 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
|
||||
wantExtra: newTXTExtra([][2]string{
|
||||
{"client-ip.adguard-dns.com.", clientIPStr},
|
||||
{"server-ip.adguard-dns.com.", serverIPStr},
|
||||
{"node-name.adguard-dns.com.", nodeName},
|
||||
{"resp.res-type.adguard-dns.com.", "allowed"},
|
||||
{"resp.rule.adguard-dns.com.", allowRule},
|
||||
{"resp.rule-list-id.adguard-dns.com.", ""},
|
||||
@@ -161,6 +169,7 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
|
||||
wantExtra: newTXTExtra([][2]string{
|
||||
{"client-ip.adguard-dns.com.", clientIPStr},
|
||||
{"server-ip.adguard-dns.com.", serverIPStr},
|
||||
{"node-name.adguard-dns.com.", nodeName},
|
||||
{"req.res-type.adguard-dns.com.", "modified"},
|
||||
{"req.rule.adguard-dns.com.", rewriteRule},
|
||||
{"req.rule-list-id.adguard-dns.com.", ""},
|
||||
@@ -180,6 +189,7 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
|
||||
wantExtra: newTXTExtra([][2]string{
|
||||
{"client-ip.adguard-dns.com.", clientIPStr},
|
||||
{"server-ip.adguard-dns.com.", serverIPStr},
|
||||
{"node-name.adguard-dns.com.", nodeName},
|
||||
{"device-id.adguard-dns.com.", dnssvctest.DeviceIDStr},
|
||||
{"profile-id.adguard-dns.com.", dnssvctest.ProfileIDStr},
|
||||
{"resp.res-type.adguard-dns.com.", "normal"},
|
||||
@@ -196,6 +206,7 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
|
||||
wantExtra: newTXTExtra([][2]string{
|
||||
{"client-ip.adguard-dns.com.", clientIPStr},
|
||||
{"server-ip.adguard-dns.com.", serverIPStr},
|
||||
{"node-name.adguard-dns.com.", nodeName},
|
||||
{"country.adguard-dns.com.", string(geoip.CountryAD)},
|
||||
{"asn.adguard-dns.com.", "0"},
|
||||
{"resp.res-type.adguard-dns.com.", "normal"},
|
||||
@@ -212,6 +223,7 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
|
||||
wantExtra: newTXTExtra([][2]string{
|
||||
{"client-ip.adguard-dns.com.", clientIPStr},
|
||||
{"server-ip.adguard-dns.com.", serverIPStr},
|
||||
{"node-name.adguard-dns.com.", nodeName},
|
||||
{"country.adguard-dns.com.", string(geoip.CountryAD)},
|
||||
{"asn.adguard-dns.com.", "0"},
|
||||
{"subdivision.adguard-dns.com.", "CA"},
|
||||
|
||||
@@ -15,10 +15,10 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/AdguardTeam/golibs/syncutil"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@@ -38,6 +38,7 @@ type Middleware struct {
|
||||
metrics Metrics
|
||||
queryLog querylog.Interface
|
||||
ruleStat rulestat.Interface
|
||||
nodeName string
|
||||
}
|
||||
|
||||
// Config is the configuration structure for the main middleware. All fields
|
||||
@@ -77,6 +78,9 @@ type Config struct {
|
||||
// RuleStat is used to collect statistics about matched filtering rules and
|
||||
// rule lists.
|
||||
RuleStat rulestat.Interface
|
||||
|
||||
// NodeName is the name of this server node.
|
||||
NodeName string
|
||||
}
|
||||
|
||||
// New returns a new main middleware. c must not be nil.
|
||||
@@ -101,6 +105,7 @@ func New(c *Config) (mw *Middleware) {
|
||||
metrics: c.Metrics,
|
||||
queryLog: c.QueryLog,
|
||||
ruleStat: c.RuleStat,
|
||||
nodeName: c.NodeName,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,8 @@ const (
|
||||
"^$dnsrewrite=NOERROR;A;" + testRewriteAddrStr
|
||||
testRuleRewriteCNAME filter.RuleText = "||" + dnssvctest.DomainRewritten +
|
||||
"^$dnsrewrite=NOERROR;CNAME;" + dnssvctest.DomainRewrittenCNAME
|
||||
|
||||
testNodeName = "test-node"
|
||||
)
|
||||
|
||||
// Common variables for tests.
|
||||
@@ -226,6 +228,7 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
Metrics: mainmw.EmptyMetrics{},
|
||||
QueryLog: queryLog,
|
||||
RuleStat: ruleStat,
|
||||
NodeName: testNodeName,
|
||||
}
|
||||
|
||||
mw := mainmw.New(c)
|
||||
@@ -705,6 +708,7 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
|
||||
Metrics: mainmw.EmptyMetrics{},
|
||||
QueryLog: queryLog,
|
||||
RuleStat: ruleStat,
|
||||
NodeName: testNodeName,
|
||||
}
|
||||
|
||||
mw := mainmw.New(c)
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"net/netip"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
|
||||
@@ -27,10 +27,6 @@ type Metrics interface {
|
||||
// IncrementRatelimitedByProfile is called when the DNS request is dropped
|
||||
// by a profile's ratelimit settings.
|
||||
IncrementRatelimitedByProfile(ctx context.Context)
|
||||
|
||||
// IncrementUnknownDedicated is called when the DNS request is sent to an
|
||||
// unknown local address.
|
||||
IncrementUnknownDedicated(ctx context.Context)
|
||||
}
|
||||
|
||||
// EmptyMetrics is an empty [Metrics] implementation that does nothing.
|
||||
@@ -55,10 +51,6 @@ func (EmptyMetrics) IncrementAccessBlockedBySubnet(_ context.Context) {}
|
||||
// *EmptyMetrics.
|
||||
func (EmptyMetrics) IncrementRatelimitedByProfile(_ context.Context) {}
|
||||
|
||||
// IncrementUnknownDedicated implements the [Metrics] interface for
|
||||
// *EmptyMetrics.
|
||||
func (EmptyMetrics) IncrementUnknownDedicated(_ context.Context) {}
|
||||
|
||||
// OnAllowlisted implements the [Metrics] interface for EmptyMetrics.
|
||||
func (EmptyMetrics) OnAllowlisted(_ context.Context, _ *dns.Msg, _ dnsserver.ResponseWriter) {}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/syncutil"
|
||||
@@ -148,7 +148,7 @@ func (mw *Middleware) Wrap(next dnsserver.Handler) (wrapped dnsserver.Handler) {
|
||||
ri := mw.newRequestInfo(ctx, req, rw.LocalAddr(), raddr)
|
||||
defer mw.pool.Put(ri)
|
||||
|
||||
cont, err := mw.handleDeviceResult(ctx, ri.DeviceResult)
|
||||
cont, err := mw.handleDeviceResult(ri.DeviceResult)
|
||||
if !cont {
|
||||
// Don't wrap the error, because this is the main flow, and there is
|
||||
// already [errors.Annotate] here.
|
||||
@@ -196,14 +196,9 @@ func (mw *Middleware) processLocationErr(
|
||||
|
||||
// handleDeviceResult processes the device result and indicates whether the
|
||||
// handler should proceed and the error to return if not.
|
||||
func (mw *Middleware) handleDeviceResult(
|
||||
ctx context.Context,
|
||||
res agd.DeviceResult,
|
||||
) (cont bool, err error) {
|
||||
func (mw *Middleware) handleDeviceResult(res agd.DeviceResult) (cont bool, err error) {
|
||||
switch res := res.(type) {
|
||||
case *agd.DeviceResultUnknownDedicated:
|
||||
mw.metrics.IncrementUnknownDedicated(ctx)
|
||||
|
||||
// The request is dropped by the profile search. Don't write anything
|
||||
// and just return.
|
||||
return false, nil
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -1,16 +1,43 @@
|
||||
package dnssvc
|
||||
|
||||
import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicefinder"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/initial"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/mainmw"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/ratelimitmw"
|
||||
)
|
||||
|
||||
// Re-exports related to configuration.
|
||||
type (
|
||||
// MainMiddlewareMetrics is a re-export of the internal filtering-middleware
|
||||
// metrics interface.
|
||||
// DDRConfig is the configuration for the server group's Discovery Of
|
||||
// Designated Resolvers (DDR) handlers.
|
||||
DDRConfig = initial.DDRConfig
|
||||
)
|
||||
|
||||
// Re-exports related to custom domains.
|
||||
type (
|
||||
// CustomDomainDB contains information about custom domains and matches domains.
|
||||
CustomDomainDB = devicefinder.CustomDomainDB
|
||||
|
||||
// EmptyCustomDomainDB is an [CustomDomainDB] that does nothing.
|
||||
EmptyCustomDomainDB = devicefinder.EmptyCustomDomainDB
|
||||
)
|
||||
|
||||
// Re-exports related to metrics.
|
||||
type (
|
||||
// DeviceFinderMetrics is an interface for collection of the statistics of
|
||||
// the default device finder.
|
||||
DeviceFinderMetrics = devicefinder.Metrics
|
||||
|
||||
// InitialMiddlewareMetrics is an interface for monitoring the initial
|
||||
// middleware state.
|
||||
InitialMiddlewareMetrics = initial.Metrics
|
||||
|
||||
// MainMiddlewareMetrics is an interface for collection of the statistics of
|
||||
// the main filtering middleware.
|
||||
MainMiddlewareMetrics = mainmw.Metrics
|
||||
|
||||
// RatelimitMiddlewareMetrics is a re-export of the metrics interface of the
|
||||
// internal access and ratelimiting middleware.
|
||||
// RatelimitMiddlewareMetrics is an interface for monitoring the ratelimit
|
||||
// middleware state.
|
||||
RatelimitMiddlewareMetrics = ratelimitmw.Metrics
|
||||
)
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/golibs/mathutil"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@@ -83,7 +82,7 @@ func (mw *Middleware) itemFromCache(
|
||||
|
||||
// Check for cache key collisions.
|
||||
if item.host != cr.host {
|
||||
optslog.Warn2(ctx, mw.logger, "cache collision", "item", item, "host", cr.host)
|
||||
mw.logger.WarnContext(ctx, "cache collision", "item", item, "host", cr.host)
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,8 +13,8 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/optslog"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/optslog"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/syncutil"
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
func Init(l *slog.Logger) {
|
||||
func Init(l *slog.Logger, reg prometheus.Registerer) (err error) {
|
||||
expStr := os.Getenv("EXPERIMENTS")
|
||||
if expStr == "" {
|
||||
return
|
||||
@@ -39,16 +39,8 @@ func Init(l *slog.Logger) {
|
||||
}
|
||||
}
|
||||
|
||||
enableMetrics()
|
||||
}
|
||||
|
||||
// enableMetrics sets the labels with enabled experiments and sets the gauge
|
||||
// value to 1.
|
||||
func enableMetrics() {
|
||||
expGauge := metrics.ExperimentGauge(prometheus.Labels{
|
||||
return metrics.SetExperimentGauge(reg, prometheus.Labels{
|
||||
// NOTE: Add experiments here in the following format:
|
||||
// idMyExp: metrics.BoolString(expMyExpEnabled),
|
||||
})
|
||||
|
||||
expGauge.Set(1)
|
||||
}
|
||||
|
||||
@@ -50,7 +50,12 @@ func (s *Default) refresh(ctx context.Context, acceptStale bool) (err error) {
|
||||
fls := resp.toInternal(ctx, s.logger, s.errColl)
|
||||
s.logger.InfoContext(ctx, "validated lists", "num_lists", len(fls))
|
||||
|
||||
newRuleLists := s.refreshRuleLists(ctx, fls, acceptStale)
|
||||
newRuleLists, err := s.refreshRuleLists(ctx, fls, acceptStale)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
s.logger.InfoContext(ctx, "compiled lists", "num_lists", len(newRuleLists))
|
||||
|
||||
err = s.refreshServices(ctx, acceptStale)
|
||||
@@ -111,7 +116,7 @@ func (s *Default) refreshRuleLists(
|
||||
ctx context.Context,
|
||||
filtersData []*indexData,
|
||||
acceptStale bool,
|
||||
) (rls ruleLists) {
|
||||
) (rls ruleLists, err error) {
|
||||
lenFls := len(filtersData)
|
||||
|
||||
resCh := make(chan refrResult, lenFls)
|
||||
@@ -121,23 +126,31 @@ func (s *Default) refreshRuleLists(
|
||||
|
||||
rls = make(ruleLists, lenFls)
|
||||
for range lenFls {
|
||||
res := <-resCh
|
||||
|
||||
fltID := res.id
|
||||
if res.err != nil {
|
||||
err := fmt.Errorf("initializing rulelist %q: %w", fltID, res.err)
|
||||
errcoll.Collect(ctx, s.errColl, s.logger, "rule-list error", err)
|
||||
s.metrics.SetFilterStatus(ctx, string(fltID), s.clock.Now(), 0, err)
|
||||
|
||||
rls[fltID] = s.prevRuleList(fltID)
|
||||
|
||||
continue
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case res := <-resCh:
|
||||
rls[res.id] = s.resultRuleList(ctx, res)
|
||||
}
|
||||
|
||||
rls[fltID] = res.refr
|
||||
}
|
||||
|
||||
return rls
|
||||
return rls, nil
|
||||
}
|
||||
|
||||
// resultRuleList returns a non-nil [rulelist.Refreshable] if res.err is nil.
|
||||
// Otherwise, it returns the previous rule list for the given fltID and logs
|
||||
// the error.
|
||||
func (s *Default) resultRuleList(ctx context.Context, res refrResult) (rl *rulelist.Refreshable) {
|
||||
fltID := res.id
|
||||
if res.err != nil {
|
||||
err := fmt.Errorf("initializing rulelist %q: %w", fltID, res.err)
|
||||
errcoll.Collect(ctx, s.errColl, s.logger, "rule-list error", err)
|
||||
s.metrics.SetFilterStatus(ctx, string(fltID), s.clock.Now(), 0, err)
|
||||
|
||||
return s.prevRuleList(fltID)
|
||||
}
|
||||
|
||||
return res.refr
|
||||
}
|
||||
|
||||
// refreshRuleList creates a [rulelist.Refreshable] from the data loaded with
|
||||
|
||||
@@ -19,6 +19,7 @@ const (
|
||||
GRPCErrAuthentication GRPCError = "auth"
|
||||
GRPCErrBadRequest GRPCError = "bad_req"
|
||||
GRPCErrDeviceQuota GRPCError = "dev_quota"
|
||||
GRPCErrNotFound GRPCError = "not_found"
|
||||
GRPCErrOther GRPCError = "other"
|
||||
GRPCErrRateLimit GRPCError = "rate_limit"
|
||||
GRPCErrTimeout GRPCError = "timeout"
|
||||
@@ -30,6 +31,7 @@ type BackendGRPC struct {
|
||||
errorsTotalAuthentication prometheus.Counter
|
||||
errorsTotalBadRequest prometheus.Counter
|
||||
errorsTotalDeviceQuota prometheus.Counter
|
||||
errorsTotalNotFound prometheus.Counter
|
||||
errorsTotalOther prometheus.Counter
|
||||
errorsTotalRateLimit prometheus.Counter
|
||||
errorsTotalTimeout prometheus.Counter
|
||||
@@ -52,6 +54,7 @@ func NewBackendGRPC(namespace string, reg prometheus.Registerer) (m *BackendGRPC
|
||||
errorsTotalAuthentication: grpcErrorsTotalCounterVec.WithLabelValues(GRPCErrAuthentication),
|
||||
errorsTotalBadRequest: grpcErrorsTotalCounterVec.WithLabelValues(GRPCErrBadRequest),
|
||||
errorsTotalDeviceQuota: grpcErrorsTotalCounterVec.WithLabelValues(GRPCErrDeviceQuota),
|
||||
errorsTotalNotFound: grpcErrorsTotalCounterVec.WithLabelValues(GRPCErrNotFound),
|
||||
errorsTotalOther: grpcErrorsTotalCounterVec.WithLabelValues(GRPCErrOther),
|
||||
errorsTotalRateLimit: grpcErrorsTotalCounterVec.WithLabelValues(GRPCErrRateLimit),
|
||||
errorsTotalTimeout: grpcErrorsTotalCounterVec.WithLabelValues(GRPCErrTimeout),
|
||||
@@ -76,6 +79,8 @@ func (m *BackendGRPC) IncrementErrorCount(_ context.Context, errType GRPCError)
|
||||
ctr = m.errorsTotalBadRequest
|
||||
case GRPCErrDeviceQuota:
|
||||
ctr = m.errorsTotalDeviceQuota
|
||||
case GRPCErrNotFound:
|
||||
ctr = m.errorsTotalNotFound
|
||||
case GRPCErrOther:
|
||||
ctr = m.errorsTotalOther
|
||||
case GRPCErrRateLimit:
|
||||
|
||||
@@ -1,71 +1,162 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
var (
|
||||
bindToDeviceUnknownRequestsTotal = promauto.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "unknown_requests_total",
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemBindToDevice,
|
||||
Help: "The total number of DNS requests to unknown local addresses.",
|
||||
},
|
||||
[]string{"proto"},
|
||||
// BindToDevice is the Prometheus-based implementation of the
|
||||
// [bindtodevice.Metrics] interface.
|
||||
type BindToDevice struct {
|
||||
// unknownTCPRequestsTotal is the total counter of DNS requests over TCP to
|
||||
// unknown local addresses.
|
||||
unknownTCPRequestsTotal prometheus.Counter
|
||||
|
||||
// unknownUDPRequestsTotal is the total counter of DNS requests over UDP to
|
||||
// unknown local addresses.
|
||||
unknownUDPRequestsTotal prometheus.Counter
|
||||
|
||||
// tcpConnsChanSize is a gauge with the current number of TCP connections in
|
||||
// the buffer of the channel by each subnet.
|
||||
tcpConnsChanSize *prometheus.GaugeVec
|
||||
|
||||
// udpSessionsChanSize is a gauge with the current number of UDP sessions in
|
||||
// the buffer of the channel by each subnet.
|
||||
udpSessionsChanSize *prometheus.GaugeVec
|
||||
|
||||
// udpWriteRequestsChanSize is a gauge with the current number of UDP write
|
||||
// requests in the buffer of the channel for each interface listener.
|
||||
udpWriteRequestsChanSize *prometheus.GaugeVec
|
||||
|
||||
// udpWriteDuration is a histogram of durations of UDP write operations.
|
||||
// This histogram includes only the write itself and does not include
|
||||
// deadline setting and resetting.
|
||||
udpWriteDuration *prometheus.HistogramVec
|
||||
}
|
||||
|
||||
// NewBindToDevice registers the bindtodevice-related metrics in reg and returns
|
||||
// a properly initialized *BindToDevice.
|
||||
func NewBindToDevice(namespace string, reg prometheus.Registerer) (m *BindToDevice, err error) {
|
||||
// #nosec G101 -- There are no hardcoded credentials.
|
||||
const (
|
||||
unknownRequestsTotal = "unknown_requests_total"
|
||||
tcpConnsChanSize = "tcp_conns_chan_size"
|
||||
udpSessionsChanSize = "udp_sessions_chan_size"
|
||||
udpWriteRequestsChanSize = "udp_write_requests_chan_size"
|
||||
udpWriteDuration = "udp_write_duration_seconds"
|
||||
)
|
||||
|
||||
// BindToDeviceUnknownTCPRequestsTotal is the total counter of DNS requests
|
||||
// over TCP to unknown local addresses.
|
||||
BindToDeviceUnknownTCPRequestsTotal = bindToDeviceUnknownRequestsTotal.With(prometheus.Labels{
|
||||
"proto": "tcp",
|
||||
})
|
||||
|
||||
// BindToDeviceUnknownUDPRequestsTotal is the total counter of DNS requests
|
||||
// over UDP to unknown local addresses.
|
||||
BindToDeviceUnknownUDPRequestsTotal = bindToDeviceUnknownRequestsTotal.With(prometheus.Labels{
|
||||
"proto": "udp",
|
||||
})
|
||||
)
|
||||
|
||||
var (
|
||||
// BindToDeviceTCPConnsChanSize is a gauge with the current number of TCP
|
||||
// connections in the buffer of the channel by each subnet.
|
||||
BindToDeviceTCPConnsChanSize = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: "tcp_conns_chan_size",
|
||||
unknownRequestsTotalCV := prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: unknownRequestsTotal,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemBindToDevice,
|
||||
Help: "The current number of TCP connections in the channel.",
|
||||
}, []string{"subnet"})
|
||||
Help: "The total number of DNS requests to unknown local addresses.",
|
||||
}, []string{"proto"})
|
||||
|
||||
// BindToDeviceUDPSessionsChanSize is a gauge with the current number of UDP
|
||||
// sessions in the buffer of the channel by each subnet.
|
||||
BindToDeviceUDPSessionsChanSize = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: "udp_sessions_chan_size",
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemBindToDevice,
|
||||
Help: "The current number of UDP sessions in the channel.",
|
||||
}, []string{"subnet"})
|
||||
m = &BindToDevice{
|
||||
unknownTCPRequestsTotal: unknownRequestsTotalCV.WithLabelValues("tcp"),
|
||||
unknownUDPRequestsTotal: unknownRequestsTotalCV.WithLabelValues("udp"),
|
||||
tcpConnsChanSize: prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: tcpConnsChanSize,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemBindToDevice,
|
||||
Help: "The current number of TCP connections in the channel.",
|
||||
}, []string{"subnet"}),
|
||||
udpSessionsChanSize: prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: udpSessionsChanSize,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemBindToDevice,
|
||||
Help: "The current number of UDP sessions in the channel.",
|
||||
}, []string{"subnet"}),
|
||||
udpWriteRequestsChanSize: prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: udpWriteRequestsChanSize,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemBindToDevice,
|
||||
Help: "The current number of UDP write requests in the channel.",
|
||||
}, []string{"name"}),
|
||||
udpWriteDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Name: udpWriteDuration,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemBindToDevice,
|
||||
Help: "The duration of a write to a UDP socket.",
|
||||
Buckets: []float64{0.001, 0.01, 0.1, 1},
|
||||
}, []string{"name"}),
|
||||
}
|
||||
|
||||
// BindToDeviceUDPWriteRequestsChanSize is a gauge with the current number
|
||||
// of UDP write requests in the buffer of the channel for each interface
|
||||
// listener.
|
||||
BindToDeviceUDPWriteRequestsChanSize = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: "udp_write_requests_chan_size",
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemBindToDevice,
|
||||
Help: "The current number of UDP write requests in the channel.",
|
||||
}, []string{"name"})
|
||||
var errs []error
|
||||
collectors := container.KeyValues[string, prometheus.Collector]{{
|
||||
Key: unknownRequestsTotal,
|
||||
Value: unknownRequestsTotalCV,
|
||||
}, {
|
||||
Key: tcpConnsChanSize,
|
||||
Value: m.tcpConnsChanSize,
|
||||
}, {
|
||||
Key: udpSessionsChanSize,
|
||||
Value: m.udpSessionsChanSize,
|
||||
}, {
|
||||
Key: udpWriteRequestsChanSize,
|
||||
Value: m.udpWriteRequestsChanSize,
|
||||
}, {
|
||||
Key: udpWriteDuration,
|
||||
Value: m.udpWriteDuration,
|
||||
}}
|
||||
|
||||
// BindToDeviceUDPWriteDurationSeconds is a histogram of durations of UDP
|
||||
// write operations. This histogram includes only the write itself and does
|
||||
// not include deadline setting and resetting.
|
||||
BindToDeviceUDPWriteDurationSeconds = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Name: "udp_write_duration_seconds",
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemBindToDevice,
|
||||
Help: "The duration of a write to a UDP socket.",
|
||||
Buckets: []float64{0.001, 0.01, 0.1, 1},
|
||||
}, []string{"name"})
|
||||
)
|
||||
for _, c := range collectors {
|
||||
err = reg.Register(c.Value)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("registering metrics %q: %w", c.Key, err))
|
||||
}
|
||||
}
|
||||
|
||||
if err = errors.Join(errs...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// IncrementUnknownTCPRequests implements the [bindtodevice.Metrics] interface
|
||||
// for *BindToDevice.
|
||||
func (m *BindToDevice) IncrementUnknownTCPRequests(context.Context) {
|
||||
m.unknownTCPRequestsTotal.Inc()
|
||||
}
|
||||
|
||||
// IncrementUnknownUDPRequests implements the [bindtodevice.Metrics] interface
|
||||
// for *BindToDevice.
|
||||
func (m *BindToDevice) IncrementUnknownUDPRequests(context.Context) {
|
||||
m.unknownUDPRequestsTotal.Inc()
|
||||
}
|
||||
|
||||
// SetTCPConnsChanSize implements the [bindtodevice.Metrics] interface for
|
||||
// *BindToDevice.
|
||||
func (m *BindToDevice) SetTCPConnsChanSize(_ context.Context, subnet netip.Prefix, n uint) {
|
||||
m.tcpConnsChanSize.WithLabelValues(subnet.String()).Set(float64(n))
|
||||
}
|
||||
|
||||
// SetUDPSessionsChanSize implements the [bindtodevice.Metrics] interface for
|
||||
// *BindToDevice.
|
||||
func (m *BindToDevice) SetUDPSessionsChanSize(_ context.Context, subnet netip.Prefix, n uint) {
|
||||
m.udpSessionsChanSize.WithLabelValues(subnet.String()).Set(float64(n))
|
||||
}
|
||||
|
||||
// SetUDPWriteRequestsChanSize implements the [bindtodevice.Metrics] interface
|
||||
// for *BindToDevice.
|
||||
func (m *BindToDevice) SetUDPWriteRequestsChanSize(_ context.Context, ifaceName string, n uint) {
|
||||
m.udpWriteRequestsChanSize.WithLabelValues(ifaceName).Set(float64(n))
|
||||
}
|
||||
|
||||
// ObserveUDPWriteDuration implements the [bindtodevice.Metrics] interface for
|
||||
// *BindToDevice.
|
||||
func (m *BindToDevice) ObserveUDPWriteDuration(
|
||||
_ context.Context,
|
||||
ifaceName string,
|
||||
dur time.Duration,
|
||||
) {
|
||||
m.udpWriteDuration.WithLabelValues(ifaceName).Observe(float64(dur.Seconds()))
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ import (
|
||||
|
||||
// BackendCustomDomainStorage is the Prometheus-based implementation of the
|
||||
// [backendpb.CustomDomainStorageMetrics] interface.
|
||||
//
|
||||
// TODO(a.garipov): Use.
|
||||
type BackendCustomDomainStorage struct {
|
||||
// errorsTotal is a counter of the total number of errors when requesting
|
||||
// certificate data.
|
||||
@@ -91,7 +89,11 @@ func NewBackendCustomDomainStorage(
|
||||
|
||||
// ObserveRequest implements the [backendpb.CustomDomainStorageMetrics]
|
||||
// interface for *BackendCustomDomainStorage.
|
||||
func (m *BackendCustomDomainStorage) ObserveRequest(_ context.Context, dur time.Duration, err error) {
|
||||
func (m *BackendCustomDomainStorage) ObserveRequest(
|
||||
_ context.Context,
|
||||
dur time.Duration,
|
||||
err error,
|
||||
) {
|
||||
m.requestsTotal.Inc()
|
||||
if err == nil {
|
||||
m.requestDuration.Observe(float64(dur))
|
||||
|
||||
117
internal/metrics/devicefinder.go
Normal file
117
internal/metrics/devicefinder.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// DeviceFinder is the Prometheus-based implementation of the
|
||||
// [dnssvc.DeviceFinderMetrics] interface.
|
||||
type DeviceFinder struct {
|
||||
customDomainMismatchesTotal *prometheus.CounterVec
|
||||
customDomainRequestsTotal *prometheus.CounterVec
|
||||
dohAuthenticationFails prometheus.Counter
|
||||
unknownDedicatedTotal prometheus.Counter
|
||||
}
|
||||
|
||||
// IncrementCustomDomainMismatches implements the [Metrics] interface for
|
||||
// m *DeviceFinder.
|
||||
func (m *DeviceFinder) IncrementCustomDomainMismatches(_ context.Context, domain string) {
|
||||
m.customDomainMismatchesTotal.WithLabelValues(domain).Inc()
|
||||
}
|
||||
|
||||
// IncrementCustomDomainRequests implements the [Metrics] interface for
|
||||
// m *DeviceFinder.
|
||||
func (m *DeviceFinder) IncrementCustomDomainRequests(_ context.Context, domain string) {
|
||||
m.customDomainRequestsTotal.WithLabelValues(domain).Inc()
|
||||
}
|
||||
|
||||
// IncrementDoHAuthenticationFails implements the [Metrics] interface for
|
||||
// m *DeviceFinder.
|
||||
func (m *DeviceFinder) IncrementDoHAuthenticationFails(_ context.Context) {
|
||||
m.dohAuthenticationFails.Inc()
|
||||
}
|
||||
|
||||
// IncrementUnknownDedicated implements the [Metrics] interface for
|
||||
// m *DeviceFinder.
|
||||
func (m *DeviceFinder) IncrementUnknownDedicated(_ context.Context) {
|
||||
m.unknownDedicatedTotal.Inc()
|
||||
}
|
||||
|
||||
// NewDeviceFinder registers the device-finder metrics in reg and returns a
|
||||
// properly initialized *DeviceFinder. All arguments must be set.
|
||||
func NewDeviceFinder(namespace string, reg prometheus.Registerer) (m *DeviceFinder, err error) {
|
||||
const (
|
||||
customDomainMismatchesTotal = "custom_domain_matches_total"
|
||||
customDomainRequestsTotal = "custom_domain_requests_total"
|
||||
dohAuthenticationFails = "doh_authentication_fails"
|
||||
// TODO(a.garipov): Consider renaming to "unknown_dedicated_total".
|
||||
unknownDedicatedTotal = "unknown_dedicated"
|
||||
)
|
||||
|
||||
// TODO(a.garipov): Consider creating a new subsystem.
|
||||
|
||||
m = &DeviceFinder{
|
||||
customDomainMismatchesTotal: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: customDomainMismatchesTotal,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemDNSSvc,
|
||||
Help: "The number of requests from devices that do not belong to the profile " +
|
||||
"which the custom domain belongs to.",
|
||||
}, []string{"domain"}),
|
||||
|
||||
customDomainRequestsTotal: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: customDomainRequestsTotal,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemDNSSvc,
|
||||
Help: "The total number requests recognized as being to a custom domain " +
|
||||
"belonging to a profile.",
|
||||
}, []string{"domain"}),
|
||||
|
||||
dohAuthenticationFails: prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Name: dohAuthenticationFails,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemDNSSvc,
|
||||
Help: "The number of authentication failures for DoH auth.",
|
||||
}),
|
||||
|
||||
unknownDedicatedTotal: prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Name: unknownDedicatedTotal,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemDNSSvc,
|
||||
Help: "The number of dropped queries for unrecognized dedicated addresses.",
|
||||
}),
|
||||
}
|
||||
|
||||
var errs []error
|
||||
collectors := container.KeyValues[string, prometheus.Collector]{{
|
||||
Key: customDomainMismatchesTotal,
|
||||
Value: m.customDomainMismatchesTotal,
|
||||
}, {
|
||||
Key: customDomainRequestsTotal,
|
||||
Value: m.customDomainRequestsTotal,
|
||||
}, {
|
||||
Key: dohAuthenticationFails,
|
||||
Value: m.dohAuthenticationFails,
|
||||
}, {
|
||||
Key: unknownDedicatedTotal,
|
||||
Value: m.unknownDedicatedTotal,
|
||||
}}
|
||||
|
||||
for _, c := range collectors {
|
||||
err = reg.Register(c.Value)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("registering metrics %q: %w", c.Key, err))
|
||||
}
|
||||
}
|
||||
|
||||
if err = errors.Join(errs...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
@@ -1,57 +1,62 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
var (
|
||||
specialRequestsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "special_requests_total",
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemDNSSvc,
|
||||
Help: "The number of DNS requests for special domain names.",
|
||||
}, []string{"kind"})
|
||||
// InitialMiddleware is the Prometheus-based implementation of the
|
||||
// [dnssvc.InitialMiddlewareMetrics] interface.
|
||||
type InitialMiddleware struct {
|
||||
specialRequestsTotal *prometheus.CounterVec
|
||||
}
|
||||
|
||||
// DNSSvcDDRRequestsTotal is a counter with total number of requests for
|
||||
// Discovery of Designated Resolvers.
|
||||
DNSSvcDDRRequestsTotal = specialRequestsTotal.With(prometheus.Labels{
|
||||
"kind": "ddr",
|
||||
})
|
||||
// NewInitialMiddleware registers the filtering-middleware metrics in reg and
|
||||
// returns a properly initialized *InitialMiddleware. All arguments must be
|
||||
// set.
|
||||
func NewInitialMiddleware(
|
||||
namespace string,
|
||||
reg prometheus.Registerer,
|
||||
) (m *InitialMiddleware, err error) {
|
||||
const (
|
||||
specialRequestsTotal = "special_requests_total"
|
||||
)
|
||||
|
||||
// DNSSvcBadResolverARPA is a counter with total number of requests for
|
||||
// malformed resolver.arpa queries.
|
||||
DNSSvcBadResolverARPA = specialRequestsTotal.With(prometheus.Labels{
|
||||
"kind": "bad_resolver_arpa",
|
||||
})
|
||||
m = &InitialMiddleware{
|
||||
specialRequestsTotal: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: specialRequestsTotal,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemDNSSvc,
|
||||
Help: "The number of DNS requests for special domain names.",
|
||||
}, []string{"kind"}),
|
||||
}
|
||||
|
||||
// DNSSvcChromePrefetchRequestsTotal is a counter with total number of
|
||||
// requests for the domain name that Chrome uses to check if it should use
|
||||
// its prefetch proxy.
|
||||
DNSSvcChromePrefetchRequestsTotal = specialRequestsTotal.With(prometheus.Labels{
|
||||
"kind": "chrome_prefetch",
|
||||
})
|
||||
var errs []error
|
||||
collectors := container.KeyValues[string, prometheus.Collector]{{
|
||||
Key: specialRequestsTotal,
|
||||
Value: m.specialRequestsTotal,
|
||||
}}
|
||||
|
||||
// DNSSvcFirefoxRequestsTotal is a counter with total number of requests for
|
||||
// the domain name that Firefox uses to check if it should use its own
|
||||
// DNS-over-HTTPS settings.
|
||||
DNSSvcFirefoxRequestsTotal = specialRequestsTotal.With(prometheus.Labels{
|
||||
"kind": "firefox",
|
||||
})
|
||||
for _, c := range collectors {
|
||||
err = reg.Register(c.Value)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("registering metrics %q: %w", c.Key, err))
|
||||
}
|
||||
}
|
||||
|
||||
// DNSSvcApplePrivateRelayRequestsTotal is a counter with total number of
|
||||
// requests for the domain name that Apple devices use to check if Apple
|
||||
// Private Relay can be enabled.
|
||||
DNSSvcApplePrivateRelayRequestsTotal = specialRequestsTotal.With(prometheus.Labels{
|
||||
"kind": "apple_private_relay",
|
||||
})
|
||||
if err = errors.Join(errs...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// DNSSvcDoHAuthFailsTotal is the counter of DoH basic authentication
|
||||
// failures.
|
||||
DNSSvcDoHAuthFailsTotal = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "doh_authentication_fails",
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemDNSSvc,
|
||||
Help: "The number of authentication failures for DoH auth.",
|
||||
})
|
||||
)
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// IncrementRequestsTotal implements the [Metrics] interface for
|
||||
// *InitialMiddleware.
|
||||
func (m *InitialMiddleware) IncrementRequestsTotal(_ context.Context, kind string) {
|
||||
m.specialRequestsTotal.WithLabelValues(kind).Inc()
|
||||
}
|
||||
|
||||
@@ -13,14 +13,6 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// MainMiddleware is an interface for collection of the statistics of the main
|
||||
// filtering middleware.
|
||||
//
|
||||
// NOTE: Keep in sync with [dnssvc.MainMiddleware].
|
||||
type MainMiddleware interface {
|
||||
OnRequest(ctx context.Context, m *MainMiddlewareRequestMetrics)
|
||||
}
|
||||
|
||||
// MainMiddlewareRequestMetrics is an alias for a structure that contains the
|
||||
// information about a request that has reached the filtering middleware.
|
||||
//
|
||||
@@ -36,9 +28,9 @@ type MainMiddlewareRequestMetrics = struct {
|
||||
IsBlocked bool
|
||||
}
|
||||
|
||||
// DefaultMainMiddleware is the Prometheus-based implementation of the
|
||||
// [MainMiddleware] interface.
|
||||
type DefaultMainMiddleware struct {
|
||||
// MainMiddleware is the Prometheus-based implementation of the
|
||||
// [dnssvc.MainMiddleware] interface.
|
||||
type MainMiddleware struct {
|
||||
// filteringDuration is a histogram with the durations of actually filtering
|
||||
// (e.g. applying filters, safebrowsing, etc) to queries.
|
||||
filteringDuration prometheus.Histogram
|
||||
@@ -63,14 +55,13 @@ type DefaultMainMiddleware struct {
|
||||
userCounter *UserCounter
|
||||
}
|
||||
|
||||
// NewDefaultMainMiddleware registers the filtering-middleware metrics in reg
|
||||
// and returns a properly initialized *DefaultMainMiddleware. All arguments
|
||||
// must be set.
|
||||
func NewDefaultMainMiddleware(
|
||||
// NewMainMiddleware registers the filtering-middleware metrics in reg and
|
||||
// returns a properly initialized *MainMiddleware. All arguments must be set.
|
||||
func NewMainMiddleware(
|
||||
logger *slog.Logger,
|
||||
namespace string,
|
||||
reg prometheus.Registerer,
|
||||
) (m *DefaultMainMiddleware, err error) {
|
||||
) (m *MainMiddleware, err error) {
|
||||
const (
|
||||
filteringDuration = "filtering_duration_seconds"
|
||||
requestPerASNTotal = "request_per_asn_total"
|
||||
@@ -80,7 +71,7 @@ func NewDefaultMainMiddleware(
|
||||
usersLastHourCount = "users_last_hour_count"
|
||||
)
|
||||
|
||||
m = &DefaultMainMiddleware{
|
||||
m = &MainMiddleware{
|
||||
filteringDuration: prometheus.NewHistogram(prometheus.HistogramOpts{
|
||||
Name: "filtering_duration_seconds",
|
||||
Namespace: namespace,
|
||||
@@ -184,8 +175,8 @@ func NewDefaultMainMiddleware(
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// OnRequest implements the [Metrics] interface for *DefaultMainMiddleware.
|
||||
func (m *DefaultMainMiddleware) OnRequest(ctx context.Context, rm *MainMiddlewareRequestMetrics) {
|
||||
// OnRequest implements the [Metrics] interface for *MainMiddleware.
|
||||
func (m *MainMiddleware) OnRequest(ctx context.Context, rm *MainMiddlewareRequestMetrics) {
|
||||
m.filteringDuration.Observe(rm.FilteringDuration.Seconds())
|
||||
|
||||
asnStr := strconv.FormatUint(uint64(rm.ASN), 10)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user