mirror of
https://github.com/AdguardTeam/AdGuardDNS.git
synced 2025-02-20 11:23:36 +08:00
Sync v2.11.0
This commit is contained in:
parent
87137bddcf
commit
f1791135af
41
CHANGELOG.md
41
CHANGELOG.md
@ -7,6 +7,47 @@ 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-2507 / Build 926
|
||||
|
||||
- Profile's file cache version was incremented. The file cache structure has been optimized, so messages like the following are to be expected:
|
||||
|
||||
```none
|
||||
profiledb: warning: error loading fs cache err="decoding protobuf: proto: cannot parse invalid wire-format data"
|
||||
```
|
||||
|
||||
## AGDNS-2327 / Build 916
|
||||
|
||||
- Profile's file cache version was incremented. The new field `BlockChromePrefetch` has been added to profile's object.
|
||||
|
||||
- The objects within the `filtering_groups` have a new property, `block_chrome_prefetch`. So replace this:
|
||||
|
||||
```yaml
|
||||
filtering_groups:
|
||||
-
|
||||
id: default
|
||||
# …
|
||||
block_firefox_canary: true
|
||||
block_private_relay: true
|
||||
```
|
||||
|
||||
with this:
|
||||
|
||||
```yaml
|
||||
filtering_groups:
|
||||
-
|
||||
id: default
|
||||
# …
|
||||
block_chrome_prefetch: true
|
||||
block_firefox_canary: true
|
||||
block_private_relay: true
|
||||
```
|
||||
|
||||
## AGDNS-2514 / Build 908
|
||||
|
||||
- The environment variable `DNSCHECK_CACHE_KV_SIZE` has been added.
|
||||
|
||||
- The property `kv.type` within the `check` object now supports the `cache` value.
|
||||
|
||||
## AGDNS-2484/ Build 886
|
||||
|
||||
- Property `type` of the `ratelimit` object has been moved to the underlying `allowlist` object. So replace this:
|
||||
|
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.23.2
|
||||
GOTOOLCHAIN = go1.23.4
|
||||
RACE = 0
|
||||
REVISION = $${REVISION:-$$(git rev-parse --short HEAD)}
|
||||
VERSION = 0
|
||||
|
@ -175,8 +175,8 @@ check:
|
||||
# Domains to use for DNS checking.
|
||||
kv:
|
||||
# Defines the type of remote key-value storage. Allowed values are
|
||||
# "backend", "consul", and "redis".
|
||||
type: 'consul'
|
||||
# "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.
|
||||
@ -341,8 +341,9 @@ filtering_groups:
|
||||
enabled: true
|
||||
block_dangerous_domains: true
|
||||
block_newly_registered_domains: false
|
||||
block_private_relay: false
|
||||
block_chrome_prefetch: true
|
||||
block_firefox_canary: true
|
||||
block_private_relay: false
|
||||
- id: 'family'
|
||||
parental:
|
||||
enabled: true
|
||||
@ -357,8 +358,9 @@ filtering_groups:
|
||||
enabled: true
|
||||
block_dangerous_domains: true
|
||||
block_newly_registered_domains: false
|
||||
block_private_relay: false
|
||||
block_chrome_prefetch: true
|
||||
block_firefox_canary: true
|
||||
block_private_relay: false
|
||||
- id: 'non_filtering'
|
||||
rule_lists:
|
||||
enabled: false
|
||||
@ -368,8 +370,9 @@ filtering_groups:
|
||||
enabled: false
|
||||
block_dangerous_domains: true
|
||||
block_newly_registered_domains: false
|
||||
block_private_relay: false
|
||||
block_chrome_prefetch: false
|
||||
block_firefox_canary: true
|
||||
block_private_relay: false
|
||||
|
||||
# The configuration for the device-listening feature. Works only on Linux with
|
||||
# SO_BINDTODEVICE support.
|
||||
|
@ -378,7 +378,7 @@ 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`, `consul`, and `redis`.
|
||||
- <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`.
|
||||
|
||||
@ -386,6 +386,8 @@ The `check` object has the following properties:
|
||||
|
||||
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`.
|
||||
@ -662,14 +664,18 @@ The items of the `filtering_groups` array have the following properties:
|
||||
|
||||
**Example:** `true`.
|
||||
|
||||
- <a href="#fg-*-block_private_relay" id="fg-*-block_private_relay" name="fg-*-block_private_relay">`private_relay`</a>: If true, Apple Private Relay queries are blocked for requests using this filtering group.
|
||||
- <a href="#fg-*-block_chrome_prefetch" id="fg-*-block_chrome_prefetch" name="fg-*-block_chrome_prefetch">`block_chrome_prefetch`</a>: If true, Chrome prefetch domain queries are blocked for requests using this filtering group, forcing the preferch proxy into preflight mode.
|
||||
|
||||
**Example:** `false`.
|
||||
**Example:** `true`.
|
||||
|
||||
- <a href="#fg-*-block_firefox_canary" id="fg-*-block_firefox_canary" name="fg-*-block_firefox_canary">`block_firefox_canary`</a>: If true, Firefox canary domain queries are blocked for requests using this filtering group.
|
||||
|
||||
**Example:** `true`.
|
||||
|
||||
- <a href="#fg-*-block_private_relay" id="fg-*-block_private_relay" name="fg-*-block_private_relay">`private_relay`</a>: If true, Apple Private Relay queries are blocked for requests using this filtering group.
|
||||
|
||||
**Example:** `false`.
|
||||
|
||||
## <a href="#interface_listeners" id="interface_listeners" name="interface_listeners">Network interface listeners</a>
|
||||
|
||||
> [!NOTE]
|
||||
|
@ -112,6 +112,7 @@ Supported IDs:
|
||||
- `profiledb`
|
||||
- `rulestat`
|
||||
- `ticket_rotator`
|
||||
- `tlsconfig`
|
||||
|
||||
The special ID `*`, when used alone, causes all available refresh tasks to be performed. Use with caution.
|
||||
|
||||
|
@ -16,6 +16,7 @@ AdGuard DNS uses [environment variables][wiki-env] to store some of the more sen
|
||||
- [`CONSUL_ALLOWLIST_URL`](#CONSUL_ALLOWLIST_URL)
|
||||
- [`CONSUL_DNSCHECK_KV_URL`](#CONSUL_DNSCHECK_KV_URL)
|
||||
- [`CONSUL_DNSCHECK_SESSION_URL`](#CONSUL_DNSCHECK_SESSION_URL)
|
||||
- [`DNSCHECK_CACHE_KV_SIZE`](#DNSCHECK_CACHE_KV_SIZE)
|
||||
- [`DNSCHECK_REMOTEKV_API_KEY`](#DNSCHECK_REMOTEKV_API_KEY)
|
||||
- [`DNSCHECK_REMOTEKV_URL`](#DNSCHECK_REMOTEKV_URL)
|
||||
- [`FILTER_CACHE_PATH`](#FILTER_CACHE_PATH)
|
||||
@ -142,6 +143,16 @@ The HTTP(S) URL of the session API of the Consul instance used as a key-value da
|
||||
|
||||
**Example:** `http://localhost:8500/v1/session/create`
|
||||
|
||||
## <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`.
|
||||
|
||||
**Example:** `1000`
|
||||
|
||||
[conf-dnscheck-type]: configuration.md#check-kv-type
|
||||
|
||||
## <a href="#DNSCHECK_REMOTEKV_API_KEY" id="DNSCHECK_REMOTEKV_API_KEY" name="DNSCHECK_REMOTEKV_API_KEY">`DNSCHECK_REMOTEKV_API_KEY`</a>
|
||||
|
||||
The API key to use when authenticating queries to the backend key-value database API, if any. The API key should be valid as defined by [RFC 6750].
|
||||
|
34
go.mod
34
go.mod
@ -1,10 +1,10 @@
|
||||
module github.com/AdguardTeam/AdGuardDNS
|
||||
|
||||
go 1.23.2
|
||||
go 1.23.4
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-20240607112746-5690301129fe
|
||||
github.com/AdguardTeam/golibs v0.30.1
|
||||
github.com/AdguardTeam/golibs v0.30.4
|
||||
github.com/AdguardTeam/urlfilter v0.20.0
|
||||
github.com/ameshkov/dnscrypt/v2 v2.3.0
|
||||
github.com/axiomhq/hyperloglog v0.2.0
|
||||
@ -19,15 +19,15 @@ require (
|
||||
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/prometheus/client_model v0.6.1
|
||||
github.com/prometheus/common v0.60.0
|
||||
github.com/quic-go/quic-go v0.48.1
|
||||
github.com/prometheus/common v0.60.1
|
||||
github.com/quic-go/quic-go v0.48.2
|
||||
github.com/stretchr/testify v1.9.0
|
||||
golang.org/x/crypto v0.28.0
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
|
||||
golang.org/x/net v0.30.0
|
||||
golang.org/x/sys v0.26.0
|
||||
golang.org/x/time v0.7.0
|
||||
google.golang.org/grpc v1.67.1
|
||||
golang.org/x/crypto v0.30.0
|
||||
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d
|
||||
golang.org/x/net v0.32.0
|
||||
golang.org/x/sys v0.28.0
|
||||
golang.org/x/time v0.8.0
|
||||
google.golang.org/grpc v1.68.0
|
||||
google.golang.org/protobuf v1.35.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
@ -41,20 +41,20 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20241023014458-598669927662 // indirect
|
||||
github.com/google/pprof v0.0.0-20241203143554-1e3fdc7de467 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.22.0 // indirect
|
||||
github.com/panjf2000/ants/v2 v2.10.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/tools v0.26.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/tools v0.28.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
|
70
go.sum
70
go.sum
@ -1,5 +1,5 @@
|
||||
github.com/AdguardTeam/golibs v0.30.1 h1:/yv7dq2h7WXw/jTDxkE3FP9zHerRT+i03PZRHJX4fPU=
|
||||
github.com/AdguardTeam/golibs v0.30.1/go.mod h1:FkwcNQEJoGsgDGXcalrVa/4gWbE68KsmE2guXWtBQUE=
|
||||
github.com/AdguardTeam/golibs v0.30.4 h1:zfFX1v4hkOCz6BifkneiBW2PCwSK523kYNr+VwaFrIw=
|
||||
github.com/AdguardTeam/golibs v0.30.4/go.mod h1:Ir9dlHfb8nRQsG3Qgo1zoGL+k1qMbcBtb8tcnsvzdAE=
|
||||
github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs=
|
||||
github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||
@ -37,12 +37,14 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s=
|
||||
github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20241023014458-598669927662 h1:SKMkD83p7FwUqKmBsPdLHF5dNyxq3jOWwu9w9UyH5vA=
|
||||
github.com/google/pprof v0.0.0-20241023014458-598669927662/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241203143554-1e3fdc7de467 h1:keEZFtbLJugfE0qHn+Ge1JCE71spzkchQobDf3mzS/4=
|
||||
github.com/google/pprof v0.0.0-20241203143554-1e3fdc7de467/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
|
||||
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
@ -59,10 +61,10 @@ github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
||||
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
|
||||
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||
github.com/panjf2000/ants/v2 v2.10.0 h1:zhRg1pQUtkyRiOFo2Sbqwjp0GfBNo9cUY2/Grpx1p+8=
|
||||
@ -81,14 +83,14 @@ github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA=
|
||||
github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
|
||||
github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
|
||||
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.48.1 h1:y/8xmfWI9qmGTc+lBr4jKRUWLGSlSigv847ULJ4hYXA=
|
||||
github.com/quic-go/quic-go v0.48.1/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
|
||||
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
|
||||
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||
@ -111,29 +113,29 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
|
||||
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0=
|
||||
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
||||
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
|
||||
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 h1:XVhgTWWV3kGQlwJHR3upFWZeTsei6Oks1apkZSeonIE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
|
||||
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
37
go.work.sum
37
go.work.sum
@ -1,6 +1,7 @@
|
||||
cel.dev/expr v0.15.0 h1:O1jzfJCQBfL5BFoYktaxwIhuttaQPsVWerH9/EEKx0w=
|
||||
cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
|
||||
cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
|
||||
cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
@ -161,6 +162,7 @@ github.com/AdguardTeam/golibs v0.25.3/go.mod h1:HaTyS2wCbxFudjht9N/+/Qf1b5cMad2B
|
||||
github.com/AdguardTeam/golibs v0.30.0/go.mod h1:vjw1OVZG6BYyoqGRY88U4LCJLOMfhBFhU0UJBdaSAuQ=
|
||||
github.com/AdguardTeam/golibs v0.30.1 h1:/yv7dq2h7WXw/jTDxkE3FP9zHerRT+i03PZRHJX4fPU=
|
||||
github.com/AdguardTeam/golibs v0.30.1/go.mod h1:FkwcNQEJoGsgDGXcalrVa/4gWbE68KsmE2guXWtBQUE=
|
||||
github.com/AdguardTeam/golibs v0.30.3/go.mod h1:Ir9dlHfb8nRQsG3Qgo1zoGL+k1qMbcBtb8tcnsvzdAE=
|
||||
github.com/AdguardTeam/gomitmproxy v0.2.0 h1:rvCOf17pd1/CnMyMQW891zrEiIQBpQ8cIGjKN9pinUU=
|
||||
github.com/AdguardTeam/gomitmproxy v0.2.1 h1:p9gr8Er1TYvf+7ic81Ax1sZ62UNCsMTZNbm7tC59S9o=
|
||||
github.com/AdguardTeam/gomitmproxy v0.2.1/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
|
||||
@ -251,6 +253,7 @@ github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido6
|
||||
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
|
||||
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d h1:t5Wuyh53qYyg9eqn4BbnlIT+vmhyww0TatL+zT3uWgI=
|
||||
@ -367,8 +370,6 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
@ -401,6 +402,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
@ -488,6 +491,7 @@ github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw
|
||||
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
|
||||
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
@ -572,6 +576,8 @@ github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3Ro
|
||||
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
||||
github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
|
||||
github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
|
||||
github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||
@ -589,12 +595,14 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
@ -739,6 +747,7 @@ go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8p
|
||||
go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc=
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5 h1:+hE86LblG4AyDgwMCLTE6FOlM9+qjHSYS+rKqxUVdsM=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d h1:E2M5QgjZ/Jg+ObCQAudsXxuTsLj7Nl5RV/lZcQZmKSo=
|
||||
@ -758,6 +767,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20221019170559-20944726eadf/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
@ -769,6 +780,8 @@ golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQ
|
||||
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@ -784,6 +797,7 @@ golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -820,6 +834,9 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@ -852,6 +869,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -889,6 +908,9 @@ golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808 h1:+Kc94D8UVEVxJnLXp/+FMfqQARZtWHfVrcRtcG8aT3g=
|
||||
golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY=
|
||||
@ -925,6 +947,8 @@ golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
|
||||
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
|
||||
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
|
||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
@ -938,6 +962,9 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
@ -963,7 +990,11 @@ golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc
|
||||
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
||||
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -1014,6 +1045,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
|
||||
google.golang.org/genproto/googleapis/bytestream v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:vh/N7795ftP0AkN1w8XKqN4w1OdUKXW5Eummda+ofv8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
||||
@ -1044,6 +1076,7 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
|
||||
|
@ -2,17 +2,13 @@ package agd_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testutil.DiscardLogOutput(m)
|
||||
}
|
||||
|
||||
// Common long strings for tests.
|
||||
//
|
||||
// TODO(a.garipov): Move to a new validation package.
|
||||
var (
|
||||
testLongStr = strings.Repeat("a", 200)
|
||||
testLongStrUnicode = strings.Repeat("ы", 200)
|
||||
|
@ -34,7 +34,8 @@ func TestNewDeviceName(t *testing.T) {
|
||||
}, {
|
||||
name: "too_long_unicode",
|
||||
in: testLongStrUnicode,
|
||||
wantErrMsg: `bad device name "` + testLongStrUnicode + `": too long: got 200 runes, max 128`,
|
||||
wantErrMsg: `bad device name "` + testLongStrUnicode +
|
||||
`": too long: got 200 runes, max 128`,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
28
internal/agd/filteringgroup.go
Normal file
28
internal/agd/filteringgroup.go
Normal file
@ -0,0 +1,28 @@
|
||||
package agd
|
||||
|
||||
import "github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
|
||||
// FilteringGroup represents a set of filtering settings.
|
||||
type FilteringGroup struct {
|
||||
// FilterConfig is the configuration of the filters used for this filtering
|
||||
// group. It must not be nil.
|
||||
FilterConfig *filter.ConfigGroup
|
||||
|
||||
// ID is the unique ID of this filtering group. It must be set.
|
||||
ID FilteringGroupID
|
||||
|
||||
// BlockChromePrefetch shows if the Chrome prefetch proxy feature should be
|
||||
// disabled for requests using this filtering group.
|
||||
BlockChromePrefetch bool
|
||||
|
||||
// BlockFirefoxCanary shows if Firefox canary domain is blocked for
|
||||
// requests using this filtering group.
|
||||
BlockFirefoxCanary bool
|
||||
|
||||
// BlockPrivateRelay shows if Apple Private Relay is blocked for requests
|
||||
// using this filtering group.
|
||||
BlockPrivateRelay bool
|
||||
}
|
||||
|
||||
// FilteringGroupID is the ID of a filter group. It is an opaque string.
|
||||
type FilteringGroupID string
|
@ -1,173 +0,0 @@
|
||||
package agd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
)
|
||||
|
||||
// FilterListID is the ID of a filter list. It is an opaque string.
|
||||
type FilterListID string
|
||||
|
||||
// Special FilterListID values shared across the AdGuard DNS system.
|
||||
//
|
||||
// DO NOT change these as other parts of the system depend on these values.
|
||||
const (
|
||||
// FilterListIDNone means that no filter were applied at all.
|
||||
FilterListIDNone FilterListID = ""
|
||||
|
||||
// FilterListIDBlockedService is the shared filter-list ID used when a
|
||||
// request was blocked by the service blocker.
|
||||
FilterListIDBlockedService FilterListID = "blocked_service"
|
||||
|
||||
// FilterListIDCustom is the special shared filter-list ID used when
|
||||
// a request was filtered by a custom profile rule.
|
||||
FilterListIDCustom FilterListID = "custom"
|
||||
|
||||
// FilterListIDAdultBlocking is the special shared filter-list ID used when
|
||||
// a request was filtered by the adult content blocking filter.
|
||||
FilterListIDAdultBlocking FilterListID = "adult_blocking"
|
||||
|
||||
// FilterListIDSafeBrowsing is the special shared filter-list ID used when
|
||||
// a request was filtered by the safe browsing filter.
|
||||
FilterListIDSafeBrowsing FilterListID = "safe_browsing"
|
||||
|
||||
// FilterListIDNewRegDomains is the special shared filter-list ID used when
|
||||
// a request was filtered by the newly registered domains filter.
|
||||
FilterListIDNewRegDomains FilterListID = "newly_registered_domains"
|
||||
|
||||
// FilterListIDGeneralSafeSearch is the shared filter-list ID used when
|
||||
// a request was modified by the general safe search filter.
|
||||
FilterListIDGeneralSafeSearch FilterListID = "general_safe_search"
|
||||
|
||||
// FilterListIDYoutubeSafeSearch is the special shared filter-list ID used
|
||||
// when a request was modified by the YouTube safe search filter.
|
||||
FilterListIDYoutubeSafeSearch FilterListID = "youtube_safe_search"
|
||||
|
||||
// FilterListIDAdGuardDNS is the special filter-list ID of the main AdGuard
|
||||
// DNS filtering-rule list. For this list, rule statistics are collected.
|
||||
FilterListIDAdGuardDNS FilterListID = "adguard_dns_filter"
|
||||
|
||||
// FilterListIDAdGuardPopup is the special filter-list ID of the AdGuard DNS
|
||||
// list of popup domains.
|
||||
FilterListIDAdGuardPopup FilterListID = "adguard_popup_filter"
|
||||
)
|
||||
|
||||
// The maximum and minimum lengths of a filter list ID.
|
||||
const (
|
||||
MaxFilterListIDLen = 128
|
||||
MinFilterListIDLen = 1
|
||||
)
|
||||
|
||||
// NewFilterListID converts a simple string into a FilterListID and makes sure
|
||||
// that it's valid. This should be preferred to a simple type conversion.
|
||||
func NewFilterListID(s string) (id FilterListID, err error) {
|
||||
defer func() { err = errors.Annotate(err, "bad filter list id %q: %w", s) }()
|
||||
|
||||
err = ValidateInclusion(len(s), MaxFilterListIDLen, MinFilterListIDLen, UnitByte)
|
||||
if err != nil {
|
||||
return FilterListIDNone, err
|
||||
}
|
||||
|
||||
// Allow only the printable, non-whitespace ASCII characters. Technically
|
||||
// we only need to exclude carriage return, line feed, and slash characters,
|
||||
// but let's be more strict just in case.
|
||||
if i, r := firstNonIDRune(s, true); i != -1 {
|
||||
return FilterListIDNone, fmt.Errorf("bad rune %q at index %d", r, i)
|
||||
}
|
||||
|
||||
return FilterListID(s), nil
|
||||
}
|
||||
|
||||
// SupportsDNSRewrite returns true if the $dnsrewrite rules in filtering-rule
|
||||
// lists with this ID should be processed.
|
||||
func (id FilterListID) SupportsDNSRewrite() (ok bool) {
|
||||
switch id {
|
||||
case
|
||||
FilterListIDAdGuardPopup,
|
||||
FilterListIDCustom,
|
||||
FilterListIDGeneralSafeSearch,
|
||||
FilterListIDYoutubeSafeSearch:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// FilterRuleText is the text of a single rule within a filter.
|
||||
type FilterRuleText string
|
||||
|
||||
// MaxFilterRuleTextRuneLen is the maximum length of a filter rule in runes.
|
||||
const MaxFilterRuleTextRuneLen = 1024
|
||||
|
||||
// NewFilterRuleText converts a simple string into a FilterRuleText and makes
|
||||
// sure that it's valid. This should be preferred to a simple type conversion.
|
||||
func NewFilterRuleText(s string) (t FilterRuleText, err error) {
|
||||
defer func() { err = errors.Annotate(err, "bad filter rule text %q: %w", s) }()
|
||||
|
||||
err = ValidateInclusion(utf8.RuneCountInString(s), MaxFilterRuleTextRuneLen, 0, UnitRune)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return FilterRuleText(s), nil
|
||||
}
|
||||
|
||||
// FilteringGroup represents a set of filtering settings.
|
||||
//
|
||||
// TODO(a.garipov): Consider making it closer to the config file and the backend
|
||||
// response by grouping parental, rule list, and safe browsing settings into
|
||||
// separate structs.
|
||||
type FilteringGroup struct {
|
||||
// ID is the unique ID of this filtering group.
|
||||
ID FilteringGroupID
|
||||
|
||||
// RuleListIDs are the filtering rule list IDs used for this filtering
|
||||
// group. They are ignored if RuleListsEnabled is false.
|
||||
RuleListIDs []FilterListID
|
||||
|
||||
// RuleListsEnabled shows whether the rule-list based filtering is enabled.
|
||||
// This must be true in order for all parameters below to work.
|
||||
RuleListsEnabled bool
|
||||
|
||||
// ParentalEnabled shows whether the parental protection functionality is
|
||||
// enabled. This must be true in order for all parameters below to
|
||||
// work.
|
||||
ParentalEnabled bool
|
||||
|
||||
// BlockAdult shows whether the adult content blocking safe browsing
|
||||
// filtering should be enforced.
|
||||
BlockAdult bool
|
||||
|
||||
// SafeBrowsingEnabled shows whether the general safe browsing filtering
|
||||
// should be enforced.
|
||||
SafeBrowsingEnabled bool
|
||||
|
||||
// BlockDangerousDomains shows whether the dangerous domains safe browsing
|
||||
// filtering should be enforced.
|
||||
BlockDangerousDomains bool
|
||||
|
||||
// BlockNewlyRegisteredDomains shows whether the newly registered domains
|
||||
// safe browsing filtering should be enforced.
|
||||
BlockNewlyRegisteredDomains bool
|
||||
|
||||
// GeneralSafeSearch shows whether the general safe search filtering should
|
||||
// be enforced.
|
||||
GeneralSafeSearch bool
|
||||
|
||||
// YoutubeSafeSearch shows whether the YouTube safe search filtering should
|
||||
// be enforced.
|
||||
YoutubeSafeSearch bool
|
||||
|
||||
// BlockPrivateRelay shows if Apple Private Relay is blocked for requests
|
||||
// using this filtering group.
|
||||
BlockPrivateRelay bool
|
||||
|
||||
// BlockFirefoxCanary shows if Firefox canary domain is blocked for
|
||||
// requests using this filtering group.
|
||||
BlockFirefoxCanary bool
|
||||
}
|
||||
|
||||
// FilteringGroupID is the ID of a filter group. It is an opaque string.
|
||||
type FilteringGroupID string
|
@ -2,13 +2,11 @@ package agd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/access"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
)
|
||||
|
||||
// Profile contains information about an AdGuard DNS profile. In other parts of
|
||||
@ -17,141 +15,62 @@ import (
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
//
|
||||
// TODO(a.garipov): Consider making it closer to the config file and the backend
|
||||
// response by grouping parental, rule list, and safe browsing settings into
|
||||
// separate structs.
|
||||
type Profile struct {
|
||||
// Parental are the parental settings for this profile. They are ignored if
|
||||
// FilteringEnabled is set to false.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
Parental *ParentalProtectionSettings
|
||||
|
||||
// Ratelimiter is the custom ratelimiter for this profile. It must not be
|
||||
// FilterConfig is the configuration of the filters used for this profile
|
||||
// and all its devices that don't have filtering disabled. It must not be
|
||||
// nil.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
Ratelimiter Ratelimiter
|
||||
|
||||
// SafeBrowsing are the safe browsing settings for this profile. They are
|
||||
// ignored if FilteringEnabled is set to false.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
SafeBrowsing *SafeBrowsingSettings
|
||||
FilterConfig *filter.ConfigClient
|
||||
|
||||
// Access is the access manager for this profile. It must not be nil.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
Access access.Profile
|
||||
|
||||
// BlockingMode defines the way blocked responses are constructed. It must
|
||||
// not be nil.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
BlockingMode dnsmsg.BlockingMode
|
||||
|
||||
// Ratelimiter is the custom ratelimiter for this profile. It must not be
|
||||
// nil.
|
||||
Ratelimiter Ratelimiter
|
||||
|
||||
// ID is the unique ID of this profile. It must not be empty.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
ID ProfileID
|
||||
|
||||
// UpdateTime shows the last time this profile was updated from the backend.
|
||||
// This is NOT the time of update in the backend's database, since the
|
||||
// backend doesn't send this information.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
UpdateTime time.Time
|
||||
|
||||
// DeviceIDs are the IDs of devices attached to this profile.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
DeviceIDs []DeviceID
|
||||
|
||||
// RuleListIDs are the IDs of the filtering rule lists enabled for this
|
||||
// profile. They are ignored if FilteringEnabled or RuleListsEnabled are
|
||||
// set to false.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
RuleListIDs []FilterListID
|
||||
|
||||
// CustomRules are the custom filtering rules for this profile. They are
|
||||
// ignored if RuleListsEnabled is set to false.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
CustomRules []FilterRuleText
|
||||
|
||||
// FilteredResponseTTL is the time-to-live value used for responses sent to
|
||||
// the devices of this profile.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
FilteredResponseTTL time.Duration
|
||||
|
||||
// FilteringEnabled defines whether queries from devices of this profile
|
||||
// should be filtered in any way at all.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
FilteringEnabled bool
|
||||
|
||||
// RuleListsEnabled defines whether queries from devices of this profile
|
||||
// should be filtered using the filtering rule lists in RuleListIDs.
|
||||
// Requires FilteringEnabled to be set to true.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
RuleListsEnabled bool
|
||||
|
||||
// QueryLogEnabled defines whether query logs should be saved for the
|
||||
// devices of this profile.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
QueryLogEnabled bool
|
||||
|
||||
// Deleted shows if this profile is deleted.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
Deleted bool
|
||||
|
||||
// BlockPrivateRelay shows if Apple Private Relay queries are blocked for
|
||||
// requests from all devices in this profile.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
BlockPrivateRelay bool
|
||||
|
||||
// BlockFirefoxCanary shows if Firefox canary domain is blocked for
|
||||
// requests from all devices in this profile.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
BlockFirefoxCanary bool
|
||||
|
||||
// IPLogEnabled shows if client IP addresses are logged.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
IPLogEnabled bool
|
||||
|
||||
// AutoDevicesEnabled shows if the automatic creation of devices using
|
||||
// HumanIDs should be enabled for this profile.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
AutoDevicesEnabled bool
|
||||
|
||||
// BlockChromePrefetch shows if the Chrome prefetch proxy feature should be
|
||||
// forced into preflight mode for all devices in this profile.
|
||||
BlockChromePrefetch bool
|
||||
|
||||
// BlockFirefoxCanary shows if Firefox canary domain is blocked for
|
||||
// requests from all devices in this profile.
|
||||
BlockFirefoxCanary bool
|
||||
|
||||
// BlockPrivateRelay shows if Apple Private Relay queries are blocked for
|
||||
// requests from all devices in this profile.
|
||||
BlockPrivateRelay bool
|
||||
|
||||
// Deleted shows if this profile is deleted.
|
||||
Deleted bool
|
||||
|
||||
// FilteringEnabled defines whether queries from devices of this profile
|
||||
// should be filtered in any way at all.
|
||||
FilteringEnabled bool
|
||||
|
||||
// IPLogEnabled shows if client IP addresses are logged.
|
||||
IPLogEnabled bool
|
||||
|
||||
// QueryLogEnabled defines whether query logs should be saved for the
|
||||
// devices of this profile.
|
||||
QueryLogEnabled bool
|
||||
}
|
||||
|
||||
// ProfileID is the ID of a profile. It is an opaque string.
|
||||
@ -179,165 +98,3 @@ func NewProfileID(s string) (id ProfileID, err error) {
|
||||
|
||||
return ProfileID(s), nil
|
||||
}
|
||||
|
||||
// DayRange is a range within a single day. Start and End are minutes from the
|
||||
// start of day, with 0 being 00:00:00.(0) and 1439, 23:59:59.(9).
|
||||
//
|
||||
// Additionally, if both Start and End are set to [math.MaxUint16], the range is
|
||||
// a special zero-length range. This is needed, because when both Start and End
|
||||
// are zero, such DayRange indicates one minute after midnight; as well as to
|
||||
// reduce the amount of pointers and thus GC time.
|
||||
//
|
||||
// TODO(a.garipov): Refactor. See AGDNS-1516.
|
||||
type DayRange struct {
|
||||
Start uint16
|
||||
End uint16
|
||||
}
|
||||
|
||||
// MaxDayRangeMinutes is the maximum value for DayRange.Start and DayRange.End
|
||||
// fields, excluding the zero-length range ones.
|
||||
const MaxDayRangeMinutes = 24*60 - 1
|
||||
|
||||
// ZeroLengthDayRange returns a new zero-length day range.
|
||||
func ZeroLengthDayRange() (r DayRange) {
|
||||
return DayRange{
|
||||
Start: math.MaxUint16,
|
||||
End: math.MaxUint16,
|
||||
}
|
||||
}
|
||||
|
||||
// IsZeroLength returns true if r is a zero-length range.
|
||||
func (r DayRange) IsZeroLength() (ok bool) {
|
||||
return r.Start == math.MaxUint16 && r.End == math.MaxUint16
|
||||
}
|
||||
|
||||
// Validate returns the day range validation errors, if any.
|
||||
func (r DayRange) Validate() (err error) {
|
||||
defer func() { err = errors.Annotate(err, "bad day range: %w") }()
|
||||
|
||||
switch {
|
||||
case r.IsZeroLength():
|
||||
return nil
|
||||
case r.End < r.Start:
|
||||
return fmt.Errorf("end %d less than start %d", r.End, r.Start)
|
||||
case r.Start > MaxDayRangeMinutes:
|
||||
return fmt.Errorf("start %d greater than %d", r.Start, MaxDayRangeMinutes)
|
||||
case r.End > MaxDayRangeMinutes:
|
||||
return fmt.Errorf("end %d greater than %d", r.End, MaxDayRangeMinutes)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WeeklySchedule is a schedule for one week. The index is the same as
|
||||
// time.Weekday values. That is, 0 is Sunday, 1 is Monday, etc. An empty
|
||||
// DayRange means that there is no schedule for this day.
|
||||
type WeeklySchedule [7]DayRange
|
||||
|
||||
// ParentalProtectionSchedule is the schedule of a client's parental protection.
|
||||
// All fields must not be nil.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
type ParentalProtectionSchedule struct {
|
||||
// Week is the parental protection schedule for every day of the week.
|
||||
Week *WeeklySchedule
|
||||
|
||||
// TimeZone is the profile's time zone.
|
||||
TimeZone *agdtime.Location
|
||||
}
|
||||
|
||||
// Contains returns true if t is within the allowed schedule.
|
||||
func (s *ParentalProtectionSchedule) Contains(t time.Time) (ok bool) {
|
||||
t = t.In(&s.TimeZone.Location)
|
||||
r := s.Week[int(t.Weekday())]
|
||||
if r.IsZeroLength() {
|
||||
return false
|
||||
}
|
||||
|
||||
day := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, &s.TimeZone.Location)
|
||||
start := day.Add(time.Duration(r.Start) * time.Minute)
|
||||
end := day.Add(time.Duration(r.End+1)*time.Minute - 1*time.Nanosecond)
|
||||
|
||||
return !t.Before(start) && !t.After(end)
|
||||
}
|
||||
|
||||
// ParentalProtectionSettings are the parental protection settings of a profile.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
type ParentalProtectionSettings struct {
|
||||
Schedule *ParentalProtectionSchedule
|
||||
|
||||
// BlockedServices are the IDs of the services blocked for this profile.
|
||||
BlockedServices []BlockedServiceID
|
||||
|
||||
// Enabled tells whether the parental protection should be enabled at all.
|
||||
// This must be true in order for all parameters below to work.
|
||||
Enabled bool
|
||||
|
||||
// BlockAdult tells if AdGuard DNS should enforce blocking of adult content
|
||||
// using the safe browsing filter.
|
||||
BlockAdult bool
|
||||
|
||||
// GeneralSafeSearch tells if AdGuard DNS should enforce general safe search
|
||||
// in most search engines.
|
||||
GeneralSafeSearch bool
|
||||
|
||||
// YoutubeSafeSearch tells if AdGuard DNS should enforce safe search on
|
||||
// YouTube.
|
||||
YoutubeSafeSearch bool
|
||||
}
|
||||
|
||||
// SafeBrowsingSettings are the safe browsing settings of a profile.
|
||||
//
|
||||
// NOTE: Do not change fields of this structure without incrementing
|
||||
// [internal/profiledb/internal.FileCacheVersion].
|
||||
type SafeBrowsingSettings struct {
|
||||
// Enabled defines whether queries from devices of this profile should be
|
||||
// filtered using the safe browsing filter. This must be true in order for
|
||||
// all parameters below to work.
|
||||
Enabled bool
|
||||
|
||||
// BlockDangerousDomains shows whether the dangerous domains safe browsing
|
||||
// filtering should be enforced.
|
||||
BlockDangerousDomains bool
|
||||
|
||||
// BlockNewlyRegisteredDomains shows whether the newly registered domains
|
||||
// safe browsing filtering should be enforced.
|
||||
BlockNewlyRegisteredDomains bool
|
||||
}
|
||||
|
||||
// BlockedServiceID is the ID of a blocked service. While these are usually
|
||||
// human-readable, clients should treat them as opaque strings.
|
||||
//
|
||||
// When a request is blocked by the service blocker, this ID is used as the
|
||||
// text of the blocking rule.
|
||||
type BlockedServiceID string
|
||||
|
||||
// The maximum and minimum lengths of a blocked service ID.
|
||||
const (
|
||||
MaxBlockedServiceIDLen = 64
|
||||
MinBlockedServiceIDLen = 1
|
||||
)
|
||||
|
||||
// NewBlockedServiceID converts a simple string into a BlockedServiceID and
|
||||
// makes sure that it's valid. This should be preferred to a simple type
|
||||
// conversion.
|
||||
func NewBlockedServiceID(s string) (id BlockedServiceID, err error) {
|
||||
defer func() { err = errors.Annotate(err, "bad blocked service id %q: %w", s) }()
|
||||
|
||||
err = ValidateInclusion(len(s), MaxBlockedServiceIDLen, MinBlockedServiceIDLen, UnitByte)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Allow only the printable, non-whitespace ASCII characters. Technically
|
||||
// we only need to exclude carriage return, line feed, and slash characters,
|
||||
// but let's be more strict just in case.
|
||||
if i, r := firstNonIDRune(s, true); i != -1 {
|
||||
return "", fmt.Errorf("bad char %q at index %d", r, i)
|
||||
}
|
||||
|
||||
return BlockedServiceID(s), nil
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ func (GlobalRatelimiter) Config() (_ *RatelimitConfig) { return &RatelimitConfig
|
||||
// CountResponses implements the [Ratelimiter] interface for GlobalRatelimiter.
|
||||
func (GlobalRatelimiter) CountResponses(_ context.Context, _ *dns.Msg, _ netip.Addr) {}
|
||||
|
||||
// DefaultRatelimiter is the default [Ratelimiter] impelentation.
|
||||
// DefaultRatelimiter is the default [Ratelimiter] implementation.
|
||||
//
|
||||
// TODO(a.garipov): Add tests.
|
||||
type DefaultRatelimiter struct {
|
||||
|
@ -19,7 +19,7 @@ type Server struct {
|
||||
DNSCrypt *DNSCryptConfig
|
||||
|
||||
// TLS is the TLS configuration for this server, if any.
|
||||
TLS *tls.Config
|
||||
TLS *TLSConfig
|
||||
|
||||
// QUICConf is the QUIC configuration for this server.
|
||||
QUICConf *QUICConfig
|
||||
@ -200,3 +200,13 @@ type QUICConfig struct {
|
||||
// QUICLimitsEnabled, if true, enables QUIC limiting.
|
||||
QUICLimitsEnabled bool
|
||||
}
|
||||
|
||||
// TLSConfig is the TLS configuration of a DNS server. Metrics and ALPs must be
|
||||
// set for saved configurations.
|
||||
type TLSConfig struct {
|
||||
// Default is the defult TLS configuration. It must not be nil.
|
||||
Default *tls.Config
|
||||
|
||||
// H3 is the TLS configuration for DoH3.
|
||||
H3 *tls.Config
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
package agd
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@ -14,10 +12,11 @@ type ServerGroup struct {
|
||||
// Resolvers (DDR) handlers. DDR must not be nil.
|
||||
DDR *DDR
|
||||
|
||||
// TLS are the TLS settings for this server group. If Servers contains at
|
||||
// least one server with a non-plain protocol (see [Protocol.IsPlain]), TLS
|
||||
// must not be nil.
|
||||
TLS *TLS
|
||||
// DeviceDomains is the list of domain names used to detect device IDs from
|
||||
// clients' server names.
|
||||
//
|
||||
// TODO(s.chzhen): Consider using a custom type.
|
||||
DeviceDomains []string
|
||||
|
||||
// Name is the unique name of the server group.
|
||||
Name ServerGroupName
|
||||
@ -36,20 +35,6 @@ type ServerGroup struct {
|
||||
// ServerGroupName is the name of a server group.
|
||||
type ServerGroupName string
|
||||
|
||||
// TLS is the TLS configuration of a DNS server group.
|
||||
type TLS struct {
|
||||
// Conf is the server's TLS configuration.
|
||||
Conf *tls.Config
|
||||
|
||||
// DeviceDomains are the domain names used to detect device IDs from
|
||||
// clients' server names.
|
||||
DeviceDomains []string
|
||||
|
||||
// SessionKeys are paths to files containing the TLS session keys for this
|
||||
// server.
|
||||
SessionKeys []string
|
||||
}
|
||||
|
||||
// DDR is the configuration for the server group's Discovery Of Designated
|
||||
// Resolvers (DDR) handlers.
|
||||
type DDR struct {
|
||||
|
@ -10,7 +10,11 @@ import (
|
||||
|
||||
// LRUConfig is a configuration structure of a cache.
|
||||
type LRUConfig struct {
|
||||
Size int
|
||||
// Count is the maximum number of elements to keep in the cache. It must be
|
||||
// positive.
|
||||
//
|
||||
// TODO(a.garipov): Make uint64.
|
||||
Count int
|
||||
}
|
||||
|
||||
// LRU is an [Interface] implementation.
|
||||
@ -21,7 +25,7 @@ type LRU[K, T any] struct {
|
||||
// NewLRU returns a new initialized LRU cache.
|
||||
func NewLRU[K, T any](conf *LRUConfig) (c *LRU[K, T]) {
|
||||
return &LRU[K, T]{
|
||||
cache: gcache.New(conf.Size).LRU().Build(),
|
||||
cache: gcache.New(conf.Count).LRU().Build(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ func TestLRU(t *testing.T) {
|
||||
)
|
||||
|
||||
cache := agdcache.NewLRU[string, int](&agdcache.LRUConfig{
|
||||
Size: 10,
|
||||
Count: 10,
|
||||
})
|
||||
|
||||
cache.Set(key, val)
|
||||
|
@ -5,16 +5,11 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testutil.DiscardLogOutput(m)
|
||||
}
|
||||
|
||||
func TestPasswordHashBcrypt_Authenticate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -22,6 +22,18 @@ type Refresher interface {
|
||||
Refresh(ctx context.Context) (err error)
|
||||
}
|
||||
|
||||
// RefresherFunc is an adapter to allow the use of ordinary functions as
|
||||
// [Refresher].
|
||||
type RefresherFunc func(ctx context.Context) (err error)
|
||||
|
||||
// type check
|
||||
var _ Refresher = RefresherFunc(nil)
|
||||
|
||||
// Refresh implements the [Refresher] interface for RefresherFunc.
|
||||
func (f RefresherFunc) Refresh(ctx context.Context) (err error) {
|
||||
return f(ctx)
|
||||
}
|
||||
|
||||
// RefreshWorker is an [Interface] implementation that updates its [Refresher]
|
||||
// every tick of the provided ticker.
|
||||
type RefreshWorker struct {
|
||||
|
@ -96,9 +96,9 @@ func TestRefreshWorker(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("error", func(t *testing.T) {
|
||||
errRefr, syncCh := newTestRefresher(t, testError)
|
||||
refrWithError, syncCh := newTestRefresher(t, testError)
|
||||
|
||||
w := agdservice.NewRefreshWorker(newRefrConfig(t, errRefr, testIvl, false))
|
||||
w := agdservice.NewRefreshWorker(newRefrConfig(t, refrWithError, testIvl, false))
|
||||
|
||||
err := w.Start(testutil.ContextWithTimeout(t, testTimeout))
|
||||
require.NoError(t, err)
|
||||
@ -110,9 +110,9 @@ func TestRefreshWorker(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("error_on_shutdown", func(t *testing.T) {
|
||||
errRefr, syncCh := newTestRefresher(t, testError)
|
||||
refrWithError, syncCh := newTestRefresher(t, testError)
|
||||
|
||||
w := agdservice.NewRefreshWorker(newRefrConfig(t, errRefr, testIvlLong, true))
|
||||
w := agdservice.NewRefreshWorker(newRefrConfig(t, refrWithError, testIvlLong, true))
|
||||
|
||||
err := w.Start(testutil.ContextWithTimeout(t, testTimeout))
|
||||
require.NoError(t, err)
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/billstat"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
|
||||
@ -111,6 +112,21 @@ func (r *Refresher) Refresh(ctx context.Context) (err error) {
|
||||
return r.OnRefresh(ctx)
|
||||
}
|
||||
|
||||
// Package agdtime
|
||||
|
||||
// type check
|
||||
var _ agdtime.Clock = (*Clock)(nil)
|
||||
|
||||
// Clock is a [agdtime.Clock] for tests.
|
||||
type Clock struct {
|
||||
OnNow func() (now time.Time)
|
||||
}
|
||||
|
||||
// Now implements the [agdtime.Clock] interface for *Clock.
|
||||
func (c *Clock) Now() (now time.Time) {
|
||||
return c.OnNow()
|
||||
}
|
||||
|
||||
// Package billstat
|
||||
|
||||
// type check
|
||||
@ -220,34 +236,24 @@ var _ filter.Interface = (*Filter)(nil)
|
||||
|
||||
// Filter is a [filter.Interface] for tests.
|
||||
type Filter struct {
|
||||
OnFilterRequest func(
|
||||
ctx context.Context,
|
||||
req *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
) (r filter.Result, err error)
|
||||
OnFilterResponse func(
|
||||
ctx context.Context,
|
||||
resp *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
) (r filter.Result, err error)
|
||||
OnFilterRequest func(ctx context.Context, req *filter.Request) (r filter.Result, err error)
|
||||
OnFilterResponse func(ctx context.Context, resp *filter.Response) (r filter.Result, err error)
|
||||
}
|
||||
|
||||
// FilterRequest implements the [filter.Interface] interface for *Filter.
|
||||
func (f *Filter) FilterRequest(
|
||||
ctx context.Context,
|
||||
req *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
req *filter.Request,
|
||||
) (r filter.Result, err error) {
|
||||
return f.OnFilterRequest(ctx, req, ri)
|
||||
return f.OnFilterRequest(ctx, req)
|
||||
}
|
||||
|
||||
// FilterResponse implements the [filter.Interface] interface for *Filter.
|
||||
func (f *Filter) FilterResponse(
|
||||
ctx context.Context,
|
||||
resp *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
resp *filter.Response,
|
||||
) (r filter.Result, err error) {
|
||||
return f.OnFilterResponse(ctx, resp, ri)
|
||||
return f.OnFilterResponse(ctx, resp)
|
||||
}
|
||||
|
||||
// type check
|
||||
@ -274,21 +280,18 @@ var _ filter.Storage = (*FilterStorage)(nil)
|
||||
|
||||
// FilterStorage is a [filter.Storage] for tests.
|
||||
type FilterStorage struct {
|
||||
OnFilterFromContext func(ctx context.Context, ri *agd.RequestInfo) (f filter.Interface)
|
||||
OnHasListID func(id agd.FilterListID) (ok bool)
|
||||
OnForConfig func(ctx context.Context, c filter.Config) (f filter.Interface)
|
||||
OnHasListID func(id filter.ID) (ok bool)
|
||||
}
|
||||
|
||||
// FilterFromContext implements the [filter.Storage] interface for
|
||||
// ForConfig implements the [filter.Storage] interface for
|
||||
// *FilterStorage.
|
||||
func (s *FilterStorage) FilterFromContext(
|
||||
ctx context.Context,
|
||||
ri *agd.RequestInfo,
|
||||
) (f filter.Interface) {
|
||||
return s.OnFilterFromContext(ctx, ri)
|
||||
func (s *FilterStorage) ForConfig(ctx context.Context, c filter.Config) (f filter.Interface) {
|
||||
return s.OnForConfig(ctx, c)
|
||||
}
|
||||
|
||||
// HasListID implements the [filter.Storage] interface for *FilterStorage.
|
||||
func (s *FilterStorage) HasListID(id agd.FilterListID) (ok bool) {
|
||||
func (s *FilterStorage) HasListID(id filter.ID) (ok bool) {
|
||||
return s.OnHasListID(id)
|
||||
}
|
||||
|
||||
@ -522,11 +525,11 @@ var _ rulestat.Interface = (*RuleStat)(nil)
|
||||
|
||||
// RuleStat is a [rulestat.Interface] for tests.
|
||||
type RuleStat struct {
|
||||
OnCollect func(ctx context.Context, id agd.FilterListID, text agd.FilterRuleText)
|
||||
OnCollect func(ctx context.Context, id filter.ID, text filter.RuleText)
|
||||
}
|
||||
|
||||
// Collect implements the [rulestat.Interface] interface for *RuleStat.
|
||||
func (s *RuleStat) Collect(ctx context.Context, id agd.FilterListID, text agd.FilterRuleText) {
|
||||
func (s *RuleStat) Collect(ctx context.Context, id filter.ID, text filter.RuleText) {
|
||||
s.OnCollect(ctx, id, text)
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,24 @@ import (
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
)
|
||||
|
||||
// Clock is an interface for time-related operations.
|
||||
//
|
||||
// TODO(a.garipov): Expand with operations like After or Tick.
|
||||
//
|
||||
// TODO(a.garipov): Move to golibs/timeutil.
|
||||
type Clock interface {
|
||||
Now() (now time.Time)
|
||||
}
|
||||
|
||||
// SystemClock is a [Clock] that uses the functions from package time.
|
||||
type SystemClock struct{}
|
||||
|
||||
// type check
|
||||
var _ Clock = SystemClock{}
|
||||
|
||||
// Now implements the [Clock] interface for SystemClock.
|
||||
func (SystemClock) Now() (now time.Time) { return time.Now() }
|
||||
|
||||
// Location is a wrapper around time.Location that can de/serialize itself from
|
||||
// and to JSON.
|
||||
//
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/golibs/httphdr"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
@ -41,11 +40,6 @@ func newClient(apiURL *url.URL) (client *grpc.ClientConn, err error) {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// reportf is a helper method for reporting non-critical errors.
|
||||
func reportf(ctx context.Context, errColl errcoll.Interface, format string, args ...any) {
|
||||
errcoll.Collectf(ctx, errColl, "backendpb: "+format, args...)
|
||||
}
|
||||
|
||||
// ctxWithAuthentication adds the API key authentication header to the outgoing
|
||||
// request context if apiKey is not empty. If it is empty, ctx is parent.
|
||||
func ctxWithAuthentication(parent context.Context, apiKey string) (ctx context.Context) {
|
||||
|
@ -2,18 +2,13 @@ package backendpb
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/c2h5oh/datasize"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testutil.DiscardLogOutput(m)
|
||||
}
|
||||
|
||||
// Common IDs for tests and their string forms.
|
||||
//
|
||||
// TODO(a.garipov): Move all or most tests into external and unexport these.
|
||||
@ -37,5 +32,8 @@ var TestUpdTime = time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
// TODO(a.garipov): Add to golibs/netutil.
|
||||
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
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
@ -16,13 +17,18 @@ import (
|
||||
// BillStatConfig is the configuration structure for the business logic backend
|
||||
// billing statistics uploader.
|
||||
type BillStatConfig struct {
|
||||
// Logger is used for logging the operation of the billing statistics
|
||||
// uploader. It must not be nil.
|
||||
Logger *slog.Logger
|
||||
|
||||
// GRPCMetrics is used for the collection of the protobuf communication
|
||||
// statistics.
|
||||
GRPCMetrics GRPCMetrics
|
||||
|
||||
// ErrColl is the error collector that is used to collect critical and
|
||||
// non-critical errors.
|
||||
ErrColl errcoll.Interface
|
||||
|
||||
// Metrics is used for the collection of the protobuf errors.
|
||||
Metrics Metrics
|
||||
|
||||
// Endpoint is the backend API URL. The scheme should be either "grpc" or
|
||||
// "grpcs".
|
||||
Endpoint *url.URL
|
||||
@ -31,6 +37,20 @@ type BillStatConfig struct {
|
||||
APIKey string
|
||||
}
|
||||
|
||||
// BillStat is the implementation of the [billstat.Uploader] interface that
|
||||
// uploads the billing statistics to the business logic backend. It is safe for
|
||||
// concurrent use.
|
||||
//
|
||||
// TODO(a.garipov): Consider uniting with [ProfileStorage] into a single
|
||||
// backendpb.Client.
|
||||
type BillStat struct {
|
||||
logger *slog.Logger
|
||||
errColl errcoll.Interface
|
||||
grpcMetrics GRPCMetrics
|
||||
client DNSServiceClient
|
||||
apiKey string
|
||||
}
|
||||
|
||||
// NewBillStat creates a new billing statistics uploader. c must not be nil.
|
||||
func NewBillStat(c *BillStatConfig) (b *BillStat, err error) {
|
||||
client, err := newClient(c.Endpoint)
|
||||
@ -40,26 +60,14 @@ func NewBillStat(c *BillStatConfig) (b *BillStat, err error) {
|
||||
}
|
||||
|
||||
return &BillStat{
|
||||
logger: c.Logger,
|
||||
errColl: c.ErrColl,
|
||||
metrics: c.Metrics,
|
||||
grpcMetrics: c.GRPCMetrics,
|
||||
client: NewDNSServiceClient(client),
|
||||
apiKey: c.APIKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BillStat is the implementation of the [billstat.Uploader] interface that
|
||||
// uploads the billing statistics to the business logic backend. It is safe for
|
||||
// concurrent use.
|
||||
//
|
||||
// TODO(a.garipov): Consider uniting with [ProfileStorage] into a single
|
||||
// backendpb.Client.
|
||||
type BillStat struct {
|
||||
errColl errcoll.Interface
|
||||
metrics Metrics
|
||||
client DNSServiceClient
|
||||
apiKey string
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ billstat.Uploader = (*BillStat)(nil)
|
||||
|
||||
@ -72,12 +80,13 @@ func (b *BillStat) Upload(ctx context.Context, records billstat.Records) (err er
|
||||
ctx = ctxWithAuthentication(ctx, b.apiKey)
|
||||
stream, err := b.client.SaveDevicesBillingStat(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("opening stream: %w", fixGRPCError(ctx, b.metrics, err))
|
||||
return fmt.Errorf("opening stream: %w", fixGRPCError(ctx, b.grpcMetrics, err))
|
||||
}
|
||||
|
||||
for deviceID, record := range records {
|
||||
if record == nil {
|
||||
reportf(ctx, b.errColl, "device %q: null record", deviceID)
|
||||
err = fmt.Errorf("device %q: null record", deviceID)
|
||||
errcoll.Collect(ctx, b.errColl, b.logger, "uploading records", err)
|
||||
|
||||
continue
|
||||
}
|
||||
@ -87,7 +96,7 @@ func (b *BillStat) Upload(ctx context.Context, records billstat.Records) (err er
|
||||
return fmt.Errorf(
|
||||
"uploading device %q record: %w",
|
||||
deviceID,
|
||||
fixGRPCError(ctx, b.metrics, sendErr),
|
||||
fixGRPCError(ctx, b.grpcMetrics, sendErr),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -101,13 +101,14 @@ func TestBillStat_Upload(t *testing.T) {
|
||||
|
||||
errColl := &agdtest.ErrorCollector{
|
||||
OnCollect: func(_ context.Context, err error) {
|
||||
testutil.AssertErrorMsg(t, `backendpb: device "invalid": null record`, err)
|
||||
testutil.AssertErrorMsg(t, `uploading records: device "invalid": null record`, err)
|
||||
},
|
||||
}
|
||||
|
||||
b, err := backendpb.NewBillStat(&backendpb.BillStatConfig{
|
||||
Logger: backendpb.TestLogger,
|
||||
ErrColl: errColl,
|
||||
Metrics: backendpb.EmptyMetrics{},
|
||||
GRPCMetrics: backendpb.EmptyGRPCMetrics{},
|
||||
Endpoint: &url.URL{
|
||||
Scheme: "grpc",
|
||||
Host: l.Addr().String(),
|
||||
|
@ -3,6 +3,7 @@ package backendpb
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/netip"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
@ -19,7 +20,8 @@ func devicesToInternal(
|
||||
ds []*DeviceSettings,
|
||||
bindSet netutil.SubnetSet,
|
||||
errColl errcoll.Interface,
|
||||
mtrc Metrics,
|
||||
logger *slog.Logger,
|
||||
mtrc ProfileDBMetrics,
|
||||
) (out []*agd.Device, ids []agd.DeviceID) {
|
||||
l := len(ds)
|
||||
if l == 0 {
|
||||
@ -35,7 +37,8 @@ func devicesToInternal(
|
||||
id = d.Id
|
||||
}
|
||||
|
||||
reportf(ctx, errColl, "bad device settings for device with id %q: %w", id, err)
|
||||
err = fmt.Errorf("bad settings for device with id %q: %w", id, err)
|
||||
errcoll.Collect(ctx, errColl, logger, "converting device", err)
|
||||
|
||||
// TODO(s.chzhen): Add a return result structure and move the
|
||||
// metrics collection to the layer above.
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.35.1
|
||||
// protoc-gen-go v1.35.2
|
||||
// protoc v5.28.3
|
||||
// source: dns.proto
|
||||
|
||||
@ -247,6 +247,7 @@ type DNSProfile struct {
|
||||
Access *AccessSettings `protobuf:"bytes,18,opt,name=access,proto3" json:"access,omitempty"`
|
||||
AutoDevicesEnabled bool `protobuf:"varint,19,opt,name=auto_devices_enabled,json=autoDevicesEnabled,proto3" json:"auto_devices_enabled,omitempty"`
|
||||
RateLimit *RateLimitSettings `protobuf:"bytes,20,opt,name=rate_limit,json=rateLimit,proto3" json:"rate_limit,omitempty"`
|
||||
BlockChromePrefetch bool `protobuf:"varint,21,opt,name=block_chrome_prefetch,json=blockChromePrefetch,proto3" json:"block_chrome_prefetch,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DNSProfile) Reset() {
|
||||
@ -426,6 +427,13 @@ func (x *DNSProfile) GetRateLimit() *RateLimitSettings {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *DNSProfile) GetBlockChromePrefetch() bool {
|
||||
if x != nil {
|
||||
return x.BlockChromePrefetch
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type isDNSProfile_BlockingMode interface {
|
||||
isDNSProfile_BlockingMode()
|
||||
}
|
||||
@ -2001,7 +2009,7 @@ var file_dns_proto_rawDesc = []byte{
|
||||
0x09, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x73, 0x79,
|
||||
0x6e, 0x63, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xad, 0x08, 0x0a, 0x0a, 0x44, 0x4e, 0x53, 0x50, 0x72,
|
||||
0x6e, 0x63, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xe1, 0x08, 0x0a, 0x0a, 0x44, 0x4e, 0x53, 0x50, 0x72,
|
||||
0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x6e, 0x73, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x6e, 0x73, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11,
|
||||
0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
|
||||
@ -2067,223 +2075,226 @@ var file_dns_proto_rawDesc = []byte{
|
||||
0x65, 0x64, 0x12, 0x31, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74,
|
||||
0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d,
|
||||
0x69, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x09, 0x72, 0x61, 0x74, 0x65,
|
||||
0x4c, 0x69, 0x6d, 0x69, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e,
|
||||
0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x14, 0x53, 0x61, 0x66, 0x65, 0x42,
|
||||
0x72, 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
|
||||
0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x17, 0x62, 0x6c, 0x6f,
|
||||
0x63, 0x6b, 0x5f, 0x64, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x6f, 0x75, 0x73, 0x5f, 0x64, 0x6f, 0x6d,
|
||||
0x61, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x62, 0x6c, 0x6f, 0x63,
|
||||
0x6b, 0x44, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x6f, 0x75, 0x73, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x73, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x72, 0x64, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x72, 0x64, 0x22, 0x8a,
|
||||
0x02, 0x0a, 0x0e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
|
||||
0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
|
||||
0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69,
|
||||
0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x10, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x5f, 0x69, 0x70, 0x18,
|
||||
0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x49, 0x70, 0x12,
|
||||
0x23, 0x0a, 0x0d, 0x64, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x69, 0x70, 0x73,
|
||||
0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65,
|
||||
0x64, 0x49, 0x70, 0x73, 0x12, 0x3f, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x41,
|
||||
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x5f, 0x69,
|
||||
0x64, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x68,
|
||||
0x75, 0x6d, 0x61, 0x6e, 0x49, 0x64, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x22, 0x87, 0x02, 0x0a, 0x10,
|
||||
0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x5f, 0x61, 0x64, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x75, 0x6c, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x67,
|
||||
0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x73, 0x65, 0x61, 0x72,
|
||||
0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
|
||||
0x6c, 0x53, 0x61, 0x66, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x2e, 0x0a, 0x13, 0x79,
|
||||
0x6f, 0x75, 0x74, 0x75, 0x62, 0x65, 0x5f, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x73, 0x65, 0x61, 0x72,
|
||||
0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x79, 0x6f, 0x75, 0x74, 0x75, 0x62,
|
||||
0x65, 0x53, 0x61, 0x66, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x29, 0x0a, 0x10, 0x62,
|
||||
0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18,
|
||||
0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75,
|
||||
0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64,
|
||||
0x75, 0x6c, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x63, 0x68,
|
||||
0x65, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x54, 0x0a, 0x10, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
|
||||
0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x6d, 0x7a,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x6d, 0x7a, 0x12, 0x2e, 0x0a, 0x0b, 0x77,
|
||||
0x65, 0x65, 0x6b, 0x6c, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x0c, 0x2e, 0x57, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0b,
|
||||
0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0xd8, 0x01, 0x0a, 0x0b,
|
||||
0x57, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x03, 0x6d,
|
||||
0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61,
|
||||
0x6e, 0x67, 0x65, 0x52, 0x03, 0x6d, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x03, 0x74, 0x75, 0x65, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65,
|
||||
0x52, 0x03, 0x74, 0x75, 0x65, 0x12, 0x1b, 0x0a, 0x03, 0x77, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x77,
|
||||
0x65, 0x64, 0x12, 0x1b, 0x0a, 0x03, 0x74, 0x68, 0x75, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x74, 0x68, 0x75, 0x12,
|
||||
0x1b, 0x0a, 0x03, 0x66, 0x72, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44,
|
||||
0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x66, 0x72, 0x69, 0x12, 0x1b, 0x0a, 0x03,
|
||||
0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52,
|
||||
0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x73, 0x61, 0x74, 0x12, 0x1b, 0x0a, 0x03, 0x73, 0x75, 0x6e,
|
||||
0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67,
|
||||
0x65, 0x52, 0x03, 0x73, 0x75, 0x6e, 0x22, 0x68, 0x0a, 0x08, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e,
|
||||
0x67, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x73, 0x74,
|
||||
0x61, 0x72, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x65, 0x6e, 0x64,
|
||||
0x22, 0x3f, 0x0a, 0x11, 0x52, 0x75, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x53, 0x65, 0x74,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,
|
||||
0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x64,
|
||||
0x73, 0x22, 0x3e, 0x0a, 0x14, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64,
|
||||
0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x49, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76,
|
||||
0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x69, 0x70, 0x76, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76,
|
||||
0x36, 0x22, 0x16, 0x0a, 0x14, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64,
|
||||
0x65, 0x4e, 0x58, 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x22, 0x14, 0x0a, 0x12, 0x42, 0x6c, 0x6f,
|
||||
0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x75, 0x6c, 0x6c, 0x49, 0x50, 0x22,
|
||||
0x15, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52,
|
||||
0x45, 0x46, 0x55, 0x53, 0x45, 0x44, 0x22, 0xe3, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x76, 0x69, 0x63,
|
||||
0x65, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x12, 0x48, 0x0a, 0x12,
|
||||
0x6c, 0x61, 0x73, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x69,
|
||||
0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
|
||||
0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69,
|
||||
0x74, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63,
|
||||
0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x69,
|
||||
0x65, 0x6e, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x61,
|
||||
0x73, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x0d, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0x90, 0x02, 0x0a,
|
||||
0x0e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
|
||||
0x31, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64,
|
||||
0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61,
|
||||
0x6e, 0x67, 0x65, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x69,
|
||||
0x64, 0x72, 0x12, 0x31, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f,
|
||||
0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x69, 0x64,
|
||||
0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73,
|
||||
0x74, 0x43, 0x69, 0x64, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69,
|
||||
0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x61, 0x6c,
|
||||
0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28,
|
||||
0x0d, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12,
|
||||
0x34, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x64, 0x6f, 0x6d,
|
||||
0x61, 0x69, 0x6e, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||
0x14, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
|
||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22,
|
||||
0x3d, 0x0a, 0x09, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61,
|
||||
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x85,
|
||||
0x01, 0x0a, 0x16, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x64, 0x6f, 0x68,
|
||||
0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x0b, 0x64, 0x6f, 0x68, 0x41, 0x75, 0x74, 0x68, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x32, 0x0a,
|
||||
0x14, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x62,
|
||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x12, 0x70,
|
||||
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x48, 0x61, 0x73, 0x68, 0x42, 0x63, 0x72, 0x79, 0x70,
|
||||
0x74, 0x42, 0x13, 0x0a, 0x11, 0x64, 0x6f, 0x68, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
|
||||
0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x22, 0x75, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a,
|
||||
0x06, 0x64, 0x6e, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64,
|
||||
0x6e, 0x73, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x49, 0x64, 0x12,
|
||||
0x2c, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70,
|
||||
0x65, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3f, 0x0a,
|
||||
0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65,
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x68,
|
||||
0x0a, 0x10, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x45, 0x72, 0x72,
|
||||
0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x0b,
|
||||
0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x72, 0x65,
|
||||
0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x22, 0x34, 0x0a, 0x18, 0x44, 0x65, 0x76, 0x69,
|
||||
0x63, 0x65, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x45,
|
||||
0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2b,
|
||||
0x0a, 0x0f, 0x42, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f,
|
||||
0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x35, 0x0a, 0x19, 0x41,
|
||||
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x61, 0x69,
|
||||
0x6c, 0x65, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73,
|
||||
0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x32, 0x0a, 0x15, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x63,
|
||||
0x68, 0x72, 0x6f, 0x6d, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x74, 0x63, 0x68, 0x18, 0x15,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x68, 0x72, 0x6f, 0x6d,
|
||||
0x65, 0x50, 0x72, 0x65, 0x66, 0x65, 0x74, 0x63, 0x68, 0x42, 0x0f, 0x0a, 0x0d, 0x62, 0x6c, 0x6f,
|
||||
0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x14, 0x53,
|
||||
0x61, 0x66, 0x65, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x36, 0x0a,
|
||||
0x17, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x64, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x6f, 0x75, 0x73,
|
||||
0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15,
|
||||
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x6f, 0x75, 0x73, 0x44, 0x6f,
|
||||
0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e,
|
||||
0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e,
|
||||
0x72, 0x64, 0x22, 0x8a, 0x02, 0x0a, 0x0e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x74,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x66, 0x69, 0x6c,
|
||||
0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x45,
|
||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64,
|
||||
0x5f, 0x69, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x65,
|
||||
0x64, 0x49, 0x70, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64,
|
||||
0x5f, 0x69, 0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x64, 0x69,
|
||||
0x63, 0x61, 0x74, 0x65, 0x64, 0x49, 0x70, 0x73, 0x12, 0x3f, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x17, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x68, 0x75, 0x6d,
|
||||
0x61, 0x6e, 0x5f, 0x69, 0x64, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0c, 0x68, 0x75, 0x6d, 0x61, 0x6e, 0x49, 0x64, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x22,
|
||||
0x87, 0x02, 0x0a, 0x10, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x53, 0x65, 0x74, 0x74,
|
||||
0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1f,
|
||||
0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x61, 0x64, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x75, 0x6c, 0x74, 0x12,
|
||||
0x2e, 0x0a, 0x13, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x73, 0x61, 0x66, 0x65, 0x5f,
|
||||
0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x67, 0x65,
|
||||
0x6e, 0x65, 0x72, 0x61, 0x6c, 0x53, 0x61, 0x66, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12,
|
||||
0x2e, 0x0a, 0x13, 0x79, 0x6f, 0x75, 0x74, 0x75, 0x62, 0x65, 0x5f, 0x73, 0x61, 0x66, 0x65, 0x5f,
|
||||
0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x79, 0x6f,
|
||||
0x75, 0x74, 0x75, 0x62, 0x65, 0x53, 0x61, 0x66, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12,
|
||||
0x29, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x73, 0x63,
|
||||
0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x53,
|
||||
0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52,
|
||||
0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x54, 0x0a, 0x10, 0x53, 0x63, 0x68,
|
||||
0x65, 0x64, 0x75, 0x6c, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x10, 0x0a,
|
||||
0x03, 0x74, 0x6d, 0x7a, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x6d, 0x7a, 0x12,
|
||||
0x2e, 0x0a, 0x0b, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x57, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x52, 0x61, 0x6e,
|
||||
0x67, 0x65, 0x52, 0x0b, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22,
|
||||
0xd8, 0x01, 0x0a, 0x0b, 0x57, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12,
|
||||
0x1b, 0x0a, 0x03, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44,
|
||||
0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x6d, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x03,
|
||||
0x74, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52,
|
||||
0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x74, 0x75, 0x65, 0x12, 0x1b, 0x0a, 0x03, 0x77, 0x65, 0x64,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67,
|
||||
0x65, 0x52, 0x03, 0x77, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x03, 0x74, 0x68, 0x75, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03,
|
||||
0x74, 0x68, 0x75, 0x12, 0x1b, 0x0a, 0x03, 0x66, 0x72, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x09, 0x2e, 0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x66, 0x72, 0x69,
|
||||
0x12, 0x1b, 0x0a, 0x03, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e,
|
||||
0x44, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x73, 0x61, 0x74, 0x12, 0x1b, 0x0a,
|
||||
0x03, 0x73, 0x75, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x44, 0x61, 0x79,
|
||||
0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x03, 0x73, 0x75, 0x6e, 0x22, 0x68, 0x0a, 0x08, 0x44, 0x61,
|
||||
0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
|
||||
0x03, 0x65, 0x6e, 0x64, 0x22, 0x3f, 0x0a, 0x11, 0x52, 0x75, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62,
|
||||
0x6c, 0x65, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
|
||||
0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x3e, 0x0a, 0x14, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e,
|
||||
0x67, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x49, 0x50, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x70, 0x76,
|
||||
0x34, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
0x04, 0x69, 0x70, 0x76, 0x36, 0x22, 0x16, 0x0a, 0x14, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e,
|
||||
0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x58, 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x22, 0x14, 0x0a,
|
||||
0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x75, 0x6c,
|
||||
0x6c, 0x49, 0x50, 0x22, 0x15, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d,
|
||||
0x6f, 0x64, 0x65, 0x52, 0x45, 0x46, 0x55, 0x53, 0x45, 0x44, 0x22, 0xe3, 0x01, 0x0a, 0x11, 0x44,
|
||||
0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74,
|
||||
0x12, 0x48, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74,
|
||||
0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
|
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x41, 0x63,
|
||||
0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65,
|
||||
0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64,
|
||||
0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||
0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x14,
|
||||
0x0a, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28,
|
||||
0x0d, 0x52, 0x03, 0x61, 0x73, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65,
|
||||
0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73,
|
||||
0x22, 0x90, 0x02, 0x0a, 0x0e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x12, 0x31, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74,
|
||||
0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x69,
|
||||
0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69,
|
||||
0x73, 0x74, 0x43, 0x69, 0x64, 0x72, 0x12, 0x31, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c,
|
||||
0x69, 0x73, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a,
|
||||
0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63,
|
||||
0x6b, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x69, 0x64, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6c, 0x6c,
|
||||
0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d,
|
||||
0x52, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x6e, 0x12, 0x23,
|
||||
0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x6e, 0x18,
|
||||
0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74,
|
||||
0x41, 0x73, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74,
|
||||
0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x14, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x44, 0x6f,
|
||||
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62,
|
||||
0x6c, 0x65, 0x64, 0x22, 0x3d, 0x0a, 0x09, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72,
|
||||
0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66,
|
||||
0x69, 0x78, 0x22, 0x85, 0x01, 0x0a, 0x16, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x22, 0x0a,
|
||||
0x0d, 0x64, 0x6f, 0x68, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x64, 0x6f, 0x68, 0x41, 0x75, 0x74, 0x68, 0x4f, 0x6e, 0x6c,
|
||||
0x79, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61,
|
||||
0x73, 0x68, 0x5f, 0x62, 0x63, 0x72, 0x79, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48,
|
||||
0x00, 0x52, 0x12, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x48, 0x61, 0x73, 0x68, 0x42,
|
||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x64, 0x6f, 0x68, 0x5f, 0x70, 0x61, 0x73,
|
||||
0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x22, 0x75, 0x0a, 0x13, 0x43, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x6e, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x05, 0x64, 0x6e, 0x73, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x75, 0x6d, 0x61,
|
||||
0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x75, 0x6d, 0x61,
|
||||
0x6e, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79,
|
||||
0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63,
|
||||
0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70,
|
||||
0x65, 0x22, 0x3f, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63,
|
||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x64, 0x65, 0x76,
|
||||
0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x44, 0x65, 0x76, 0x69,
|
||||
0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69,
|
||||
0x63, 0x65, 0x22, 0x68, 0x0a, 0x10, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65,
|
||||
0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x12, 0x3a, 0x0a, 0x0b, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x0a, 0x72, 0x65, 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x22, 0x34, 0x0a, 0x18,
|
||||
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x45, 0x78, 0x63, 0x65, 0x65,
|
||||
0x64, 0x65, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x22, 0x6c, 0x0a, 0x11, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53,
|
||||
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
|
||||
0x64, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x70, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03,
|
||||
0x72, 0x70, 0x73, 0x12, 0x2b, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x69,
|
||||
0x64, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52,
|
||||
0x61, 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x69, 0x64, 0x72,
|
||||
0x22, 0x26, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x47, 0x65, 0x74, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x64, 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f,
|
||||
0x74, 0x65, 0x4b, 0x56, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x14, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52,
|
||||
0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x05, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x48, 0x00, 0x52, 0x05,
|
||||
0x65, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x67,
|
||||
0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x03, 0x74, 0x74,
|
||||
0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x22, 0x15, 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x74,
|
||||
0x65, 0x4b, 0x56, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x87,
|
||||
0x01, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a,
|
||||
0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x49,
|
||||
0x4e, 0x44, 0x4f, 0x57, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4e, 0x44, 0x52, 0x4f,
|
||||
0x49, 0x44, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x41, 0x43, 0x10, 0x03, 0x12, 0x07, 0x0a,
|
||||
0x03, 0x49, 0x4f, 0x53, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x10,
|
||||
0x05, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x52, 0x10, 0x06, 0x12, 0x0c, 0x0a,
|
||||
0x08, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x5f, 0x54, 0x56, 0x10, 0x07, 0x12, 0x10, 0x0a, 0x0c, 0x47,
|
||||
0x41, 0x4d, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, 0x45, 0x10, 0x08, 0x12, 0x09, 0x0a,
|
||||
0x05, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x09, 0x32, 0xd0, 0x01, 0x0a, 0x0a, 0x44, 0x4e, 0x53,
|
||||
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x0e, 0x67, 0x65, 0x74, 0x44, 0x4e,
|
||||
0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x13, 0x2e, 0x44, 0x4e, 0x53, 0x50,
|
||||
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b,
|
||||
0x2e, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x30, 0x01, 0x12, 0x46, 0x0a,
|
||||
0x16, 0x73, 0x61, 0x76, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x69, 0x6c, 0x6c,
|
||||
0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x12, 0x12, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
|
||||
0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
|
||||
0x70, 0x74, 0x79, 0x28, 0x01, 0x12, 0x44, 0x0a, 0x15, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44,
|
||||
0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x79, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x14,
|
||||
0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76,
|
||||
0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x61, 0x0a, 0x10, 0x52,
|
||||
0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x4d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53,
|
||||
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69,
|
||||
0x6d, 0x69, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x65,
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x75,
|
||||
0x0a, 0x0f, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x12, 0x30, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x12, 0x13, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74,
|
||||
0x65, 0x4b, 0x56, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e,
|
||||
0x67, 0x65, 0x22, 0x2b, 0x0a, 0x0f, 0x42, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22,
|
||||
0x35, 0x0a, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x6c, 0x0a, 0x11, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69,
|
||||
0x6d, 0x69, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65,
|
||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x70, 0x73, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x0d, 0x52, 0x03, 0x72, 0x70, 0x73, 0x12, 0x2b, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||
0x74, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43,
|
||||
0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||
0x43, 0x69, 0x64, 0x72, 0x22, 0x26, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56,
|
||||
0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
|
||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x64, 0x0a, 0x13,
|
||||
0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x03, 0x73, 0x65, 0x74, 0x12, 0x13, 0x2e, 0x52, 0x65, 0x6d,
|
||||
0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x14, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3d, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x64, 0x67,
|
||||
0x75, 0x61, 0x72, 0x64, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x64, 0x6e, 0x73,
|
||||
0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x42, 0x10, 0x44, 0x4e, 0x53, 0x50,
|
||||
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0xa2, 0x02,
|
||||
0x03, 0x44, 0x4e, 0x53, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x48, 0x00, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x05, 0x65, 0x6d, 0x70,
|
||||
0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
|
||||
0x48, 0x00, 0x52, 0x05, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x22, 0x67, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65,
|
||||
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61,
|
||||
0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2b,
|
||||
0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75,
|
||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x22, 0x15, 0x0a, 0x13, 0x52,
|
||||
0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x2a, 0x87, 0x01, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70,
|
||||
0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0b,
|
||||
0x0a, 0x07, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x41,
|
||||
0x4e, 0x44, 0x52, 0x4f, 0x49, 0x44, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x41, 0x43, 0x10,
|
||||
0x03, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4f, 0x53, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x49,
|
||||
0x4e, 0x55, 0x58, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x52, 0x10,
|
||||
0x06, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x5f, 0x54, 0x56, 0x10, 0x07, 0x12,
|
||||
0x10, 0x0a, 0x0c, 0x47, 0x41, 0x4d, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, 0x45, 0x10,
|
||||
0x08, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x09, 0x32, 0xd0, 0x01, 0x0a,
|
||||
0x0a, 0x44, 0x4e, 0x53, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x0e, 0x67,
|
||||
0x65, 0x74, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x13, 0x2e,
|
||||
0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x30,
|
||||
0x01, 0x12, 0x46, 0x0a, 0x16, 0x73, 0x61, 0x76, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73,
|
||||
0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x12, 0x12, 0x2e, 0x44, 0x65,
|
||||
0x76, 0x69, 0x63, 0x65, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x1a,
|
||||
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x12, 0x44, 0x0a, 0x15, 0x63, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x79, 0x48, 0x75, 0x6d, 0x61, 0x6e,
|
||||
0x49, 0x64, 0x12, 0x14, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32,
|
||||
0x61, 0x0a, 0x10, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x12, 0x4d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69,
|
||||
0x6d, 0x69, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x2e, 0x52, 0x61,
|
||||
0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d,
|
||||
0x69, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x32, 0x75, 0x0a, 0x0f, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x30, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x12, 0x13, 0x2e, 0x52,
|
||||
0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x14, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x47, 0x65, 0x74, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x03, 0x73, 0x65, 0x74, 0x12, 0x13,
|
||||
0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x56, 0x53, 0x65,
|
||||
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3d, 0x0a, 0x21, 0x63, 0x6f, 0x6d,
|
||||
0x2e, 0x61, 0x64, 0x67, 0x75, 0x61, 0x72, 0x64, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64,
|
||||
0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x42, 0x10,
|
||||
0x44, 0x4e, 0x53, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x50, 0x01, 0xa2, 0x02, 0x03, 0x44, 0x4e, 0x53, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -108,6 +108,7 @@ message DNSProfile {
|
||||
AccessSettings access = 18;
|
||||
bool auto_devices_enabled = 19;
|
||||
RateLimitSettings rate_limit = 20;
|
||||
bool block_chrome_prefetch = 21;
|
||||
}
|
||||
|
||||
message SafeBrowsingSettings {
|
||||
|
@ -9,30 +9,15 @@ import (
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// GRPCError is a type alias for string that contains the gRPC error type.
|
||||
//
|
||||
// TODO(s.chzhen): Rewrite as soon as the import cycle is resolved.
|
||||
type GRPCError = string
|
||||
|
||||
// gRPC errors of [GRPCError] type.
|
||||
const (
|
||||
GRPCErrAuthentication GRPCError = "auth"
|
||||
GRPCErrBadRequest GRPCError = "bad_req"
|
||||
GRPCErrDeviceQuota GRPCError = "dev_quota"
|
||||
GRPCErrOther GRPCError = "other"
|
||||
GRPCErrRateLimit GRPCError = "rate_limit"
|
||||
GRPCErrTimeout GRPCError = "timeout"
|
||||
)
|
||||
|
||||
// fixGRPCError converts a gRPC error into an application error, if necessary.
|
||||
// That includes gRPC deadlines, which do not match [context.DeadlineExceeded]
|
||||
// correctly.
|
||||
//
|
||||
// It also updates the backend gRPC metrics depending on the type, see
|
||||
// [Metrics.IncrementGRPCErrorCount].
|
||||
func fixGRPCError(ctx context.Context, mtrc Metrics, err error) (res error) {
|
||||
// [GRPCMetrics.IncrementErrorCount].
|
||||
func fixGRPCError(ctx context.Context, mtrc GRPCMetrics, err error) (res error) {
|
||||
metricsType := GRPCErrOther
|
||||
defer func() { mtrc.IncrementGRPCErrorCount(ctx, metricsType) }()
|
||||
defer func() { mtrc.IncrementErrorCount(ctx, metricsType) }()
|
||||
|
||||
s, ok := status.FromError(err)
|
||||
if !ok {
|
||||
|
@ -5,13 +5,47 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Metrics is an interface that is used for the collection of the protobuf
|
||||
// errors statistics.
|
||||
type Metrics interface {
|
||||
// IncrementGRPCErrorCount increments the gRPC error count of errType.
|
||||
// errType must be one of GRPCError values.
|
||||
IncrementGRPCErrorCount(ctx context.Context, errType GRPCError)
|
||||
// GRPCError is a type alias for string that contains the gRPC error type.
|
||||
//
|
||||
// See [GRPCMetrics.IncrementErrorCount].
|
||||
//
|
||||
// TODO(s.chzhen): Rewrite as soon as the import cycle is resolved.
|
||||
type GRPCError = string
|
||||
|
||||
// gRPC errors of [GRPCError] type.
|
||||
//
|
||||
// NOTE: Keep in sync with [metrics.GRPCError].
|
||||
const (
|
||||
GRPCErrAuthentication GRPCError = "auth"
|
||||
GRPCErrBadRequest GRPCError = "bad_req"
|
||||
GRPCErrDeviceQuota GRPCError = "dev_quota"
|
||||
GRPCErrOther GRPCError = "other"
|
||||
GRPCErrRateLimit GRPCError = "rate_limit"
|
||||
GRPCErrTimeout GRPCError = "timeout"
|
||||
)
|
||||
|
||||
// GRPCMetrics is an interface that is used for the collection of the protobuf
|
||||
// communication statistics.
|
||||
type GRPCMetrics interface {
|
||||
// IncrementErrorCount increments the gRPC error count of errType. errType
|
||||
// must be one of [GRPCError] values.
|
||||
IncrementErrorCount(ctx context.Context, errType GRPCError)
|
||||
}
|
||||
|
||||
// EmptyGRPCMetrics is the implementation of the [GRPCMetrics] interface that
|
||||
// does nothing.
|
||||
type EmptyGRPCMetrics struct{}
|
||||
|
||||
// type check
|
||||
var _ GRPCMetrics = EmptyGRPCMetrics{}
|
||||
|
||||
// IncrementErrorCount implements the [GRPCMetrics] interface for
|
||||
// EmptyGRPCMetrics.
|
||||
func (EmptyGRPCMetrics) IncrementErrorCount(_ context.Context, _ GRPCError) {}
|
||||
|
||||
// ProfileDBMetrics is an interface that is used for the collection of the
|
||||
// profile database statistics.
|
||||
type ProfileDBMetrics interface {
|
||||
// IncrementInvalidDevicesCount increments the number of invalid devices.
|
||||
IncrementInvalidDevicesCount(ctx context.Context)
|
||||
|
||||
@ -19,18 +53,61 @@ type Metrics interface {
|
||||
UpdateStats(ctx context.Context, avgRecv, avgDec time.Duration)
|
||||
}
|
||||
|
||||
// EmptyMetrics is the implementation of the [Metrics] interface that does
|
||||
// nothing.
|
||||
type EmptyMetrics struct{}
|
||||
// EmptyProfileDBMetrics is the implementation of the [ProfileDBMetrics]
|
||||
// interface that does nothing.
|
||||
type EmptyProfileDBMetrics struct{}
|
||||
|
||||
// type check
|
||||
var _ Metrics = EmptyMetrics{}
|
||||
var _ ProfileDBMetrics = EmptyProfileDBMetrics{}
|
||||
|
||||
// IncrementGRPCErrorCount implements the [Metrics] interface for EmptyMetrics.
|
||||
func (EmptyMetrics) IncrementGRPCErrorCount(_ context.Context, errType GRPCError) {}
|
||||
// IncrementInvalidDevicesCount implements the [ProfileDBMetrics] interface for
|
||||
// EmptyProfileDBMetrics.
|
||||
func (EmptyProfileDBMetrics) IncrementInvalidDevicesCount(_ context.Context) {}
|
||||
|
||||
// IncrementInvalidDevicesCount implements the [Metrics] interface for EmptyMetrics.
|
||||
func (EmptyMetrics) IncrementInvalidDevicesCount(_ context.Context) {}
|
||||
// UpdateStats implements the [ProfileDBMetrics] interface for
|
||||
// EmptyProfileDBMetrics.
|
||||
func (EmptyProfileDBMetrics) UpdateStats(_ context.Context, _, _ time.Duration) {}
|
||||
|
||||
// UpdateStats implements the [Metrics] interface for EmptyMetrics.
|
||||
func (EmptyMetrics) UpdateStats(_ context.Context, _, _ time.Duration) {}
|
||||
// RemoteKVOp is the type alias for string that contains remote key-value
|
||||
// storage operation name.
|
||||
//
|
||||
// See [RemoteKVMetrics.ObserveOperation].
|
||||
type RemoteKVOp = string
|
||||
|
||||
// Remote key-value storage operation names for [RemoteKVOp].
|
||||
//
|
||||
// NOTE: Keep in sync with [metrics.RemoteKVOp].
|
||||
const (
|
||||
RemoteKVOpGet RemoteKVOp = "get"
|
||||
RemoteKVOpSet RemoteKVOp = "set"
|
||||
)
|
||||
|
||||
// RemoteKVMetrics is an interface that is used for the collection of the remote
|
||||
// key-value storage statistics.
|
||||
//
|
||||
// TODO(e.burkov): It may actually describe metrics for any remote key-value
|
||||
// storage implementation, consider declaring it in the [remotekv] package.
|
||||
type RemoteKVMetrics interface {
|
||||
// ObserveOperation updates the remote key-value storage statistics. op
|
||||
// must be one of [RemoteKVOp] values.
|
||||
ObserveOperation(ctx context.Context, op string, dur time.Duration)
|
||||
|
||||
// IncrementLookups increments the number of lookups. hit is true if the
|
||||
// lookup returned a value.
|
||||
IncrementLookups(ctx context.Context, hit bool)
|
||||
}
|
||||
|
||||
// EmptyRemoteKVMetrics is the implementation of the [RemoteKVMetrics] interface
|
||||
// that does nothing.
|
||||
type EmptyRemoteKVMetrics struct{}
|
||||
|
||||
// type check
|
||||
var _ RemoteKVMetrics = EmptyRemoteKVMetrics{}
|
||||
|
||||
// ObserveOperation implements the [RemoteKVMetrics] interface for
|
||||
// EmptyRemoteKVMetrics.
|
||||
func (EmptyRemoteKVMetrics) ObserveOperation(_ context.Context, _ string, _ time.Duration) {}
|
||||
|
||||
// IncrementLookups implements the [RemoteKVMetrics] interface for
|
||||
// EmptyRemoteKVMetrics.
|
||||
func (EmptyRemoteKVMetrics) IncrementLookups(_ context.Context, _ bool) {}
|
||||
|
@ -3,6 +3,7 @@ package backendpb
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
@ -11,6 +12,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
@ -20,20 +22,21 @@ import (
|
||||
// toInternal converts the protobuf-encoded data into a profile structure and
|
||||
// its device structures.
|
||||
//
|
||||
// TODO(a.garipov): Refactor into a method of [*ProfileStorage]?
|
||||
// TODO(a.garipov): Refactor into methods of [*ProfileStorage].
|
||||
func (x *DNSProfile) toInternal(
|
||||
ctx context.Context,
|
||||
updTime time.Time,
|
||||
bindSet netutil.SubnetSet,
|
||||
errColl errcoll.Interface,
|
||||
mtrc Metrics,
|
||||
logger *slog.Logger,
|
||||
mtrc ProfileDBMetrics,
|
||||
respSzEst datasize.ByteSize,
|
||||
) (profile *agd.Profile, devices []*agd.Device, err error) {
|
||||
if x == nil {
|
||||
return nil, nil, fmt.Errorf("profile is nil")
|
||||
}
|
||||
|
||||
parental, err := x.Parental.toInternal(ctx, errColl)
|
||||
parental, err := x.Parental.toInternal(ctx, errColl, logger)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("parental: %w", err)
|
||||
}
|
||||
@ -43,8 +46,7 @@ func (x *DNSProfile) toInternal(
|
||||
return nil, nil, fmt.Errorf("blocking mode: %w", err)
|
||||
}
|
||||
|
||||
devices, deviceIds := devicesToInternal(ctx, x.Devices, bindSet, errColl, mtrc)
|
||||
listsEnabled, listIDs := x.RuleLists.toInternal(ctx, errColl)
|
||||
devices, deviceIds := devicesToInternal(ctx, x.Devices, bindSet, errColl, logger, mtrc)
|
||||
|
||||
profID, err := agd.NewProfileID(x.DnsId)
|
||||
if err != nil {
|
||||
@ -56,52 +58,63 @@ func (x *DNSProfile) toInternal(
|
||||
fltRespTTL = respTTL.AsDuration()
|
||||
}
|
||||
|
||||
return &agd.Profile{
|
||||
Parental: parental,
|
||||
BlockingMode: m,
|
||||
ID: profID,
|
||||
customRules := rulesToInternal(ctx, x.CustomRules, errColl, logger)
|
||||
custom := &filter.ConfigCustom{
|
||||
ID: string(x.DnsId),
|
||||
UpdateTime: updTime,
|
||||
DeviceIDs: deviceIds,
|
||||
RuleListIDs: listIDs,
|
||||
CustomRules: rulesToInternal(ctx, x.CustomRules, errColl),
|
||||
FilteredResponseTTL: fltRespTTL,
|
||||
FilteringEnabled: x.FilteringEnabled,
|
||||
Ratelimiter: x.RateLimit.toInternal(ctx, errColl, respSzEst),
|
||||
Rules: customRules,
|
||||
// TODO(a.garipov): Consider adding an explicit flag to the protocol.
|
||||
Enabled: len(customRules) > 0,
|
||||
}
|
||||
|
||||
return &agd.Profile{
|
||||
FilterConfig: &filter.ConfigClient{
|
||||
Custom: custom,
|
||||
Parental: parental,
|
||||
RuleList: x.RuleLists.toInternal(ctx, errColl, logger),
|
||||
SafeBrowsing: x.SafeBrowsing.toInternal(),
|
||||
Access: x.Access.toInternal(ctx, errColl),
|
||||
RuleListsEnabled: listsEnabled,
|
||||
QueryLogEnabled: x.QueryLogEnabled,
|
||||
Deleted: x.Deleted,
|
||||
BlockPrivateRelay: x.BlockPrivateRelay,
|
||||
BlockFirefoxCanary: x.BlockFirefoxCanary,
|
||||
IPLogEnabled: x.IpLogEnabled,
|
||||
},
|
||||
Access: x.Access.toInternal(ctx, errColl, logger),
|
||||
BlockingMode: m,
|
||||
Ratelimiter: x.RateLimit.toInternal(ctx, errColl, logger, respSzEst),
|
||||
ID: profID,
|
||||
DeviceIDs: deviceIds,
|
||||
FilteredResponseTTL: fltRespTTL,
|
||||
AutoDevicesEnabled: x.AutoDevicesEnabled,
|
||||
BlockChromePrefetch: x.BlockChromePrefetch,
|
||||
BlockFirefoxCanary: x.BlockFirefoxCanary,
|
||||
BlockPrivateRelay: x.BlockPrivateRelay,
|
||||
Deleted: x.Deleted,
|
||||
FilteringEnabled: x.FilteringEnabled,
|
||||
IPLogEnabled: x.IpLogEnabled,
|
||||
QueryLogEnabled: x.QueryLogEnabled,
|
||||
}, devices, nil
|
||||
}
|
||||
|
||||
// toInternal converts a protobuf parental-settings structure to an internal
|
||||
// one. If x is nil, toInternal returns nil.
|
||||
// toInternal converts a protobuf parental-protection settings structure to an
|
||||
// internal one. If x is nil, toInternal returns a disabled configuration.
|
||||
func (x *ParentalSettings) toInternal(
|
||||
ctx context.Context,
|
||||
errColl errcoll.Interface,
|
||||
) (s *agd.ParentalProtectionSettings, err error) {
|
||||
logger *slog.Logger,
|
||||
) (c *filter.ConfigParental, err error) {
|
||||
c = &filter.ConfigParental{}
|
||||
if x == nil {
|
||||
return nil, nil
|
||||
return c, nil
|
||||
}
|
||||
|
||||
schedule, err := x.Schedule.toInternal()
|
||||
c.AdultBlockingEnabled = x.BlockAdult
|
||||
c.BlockedServices = blockedSvcsToInternal(ctx, errColl, logger, x.BlockedServices)
|
||||
c.Enabled = x.Enabled
|
||||
c.SafeSearchGeneralEnabled = x.GeneralSafeSearch
|
||||
c.SafeSearchYouTubeEnabled = x.YoutubeSafeSearch
|
||||
|
||||
c.PauseSchedule, err = x.Schedule.toInternal()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("schedule: %w", err)
|
||||
return nil, fmt.Errorf("pause schedule: %w", err)
|
||||
}
|
||||
|
||||
return &agd.ParentalProtectionSettings{
|
||||
Schedule: schedule,
|
||||
BlockedServices: blockedSvcsToInternal(ctx, errColl, x.BlockedServices),
|
||||
Enabled: x.Enabled,
|
||||
BlockAdult: x.BlockAdult,
|
||||
GeneralSafeSearch: x.GeneralSafeSearch,
|
||||
YoutubeSafeSearch: x.YoutubeSafeSearch,
|
||||
}, nil
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// toInternal converts protobuf rate-limiting settings to an internal structure.
|
||||
@ -109,6 +122,7 @@ func (x *ParentalSettings) toInternal(
|
||||
func (x *RateLimitSettings) toInternal(
|
||||
ctx context.Context,
|
||||
errColl errcoll.Interface,
|
||||
logger *slog.Logger,
|
||||
respSzEst datasize.ByteSize,
|
||||
) (r agd.Ratelimiter) {
|
||||
if x == nil || !x.Enabled {
|
||||
@ -116,24 +130,26 @@ func (x *RateLimitSettings) toInternal(
|
||||
}
|
||||
|
||||
return agd.NewDefaultRatelimiter(&agd.RatelimitConfig{
|
||||
ClientSubnets: cidrRangeToInternal(ctx, errColl, x.ClientCidr),
|
||||
ClientSubnets: cidrRangeToInternal(ctx, errColl, logger, x.ClientCidr),
|
||||
RPS: x.Rps,
|
||||
Enabled: x.Enabled,
|
||||
}, respSzEst)
|
||||
}
|
||||
|
||||
// toInternal converts protobuf safe-browsing settings to an internal structure.
|
||||
// If x is nil, toInternal returns nil.
|
||||
func (x *SafeBrowsingSettings) toInternal() (sb *agd.SafeBrowsingSettings) {
|
||||
// toInternal converts protobuf safe-browsing settings to an internal
|
||||
// safe-browsing configuration. If x is nil, toInternal returns a disabled
|
||||
// configuration.
|
||||
func (x *SafeBrowsingSettings) toInternal() (c *filter.ConfigSafeBrowsing) {
|
||||
c = &filter.ConfigSafeBrowsing{}
|
||||
if x == nil {
|
||||
return nil
|
||||
return c
|
||||
}
|
||||
|
||||
return &agd.SafeBrowsingSettings{
|
||||
Enabled: x.Enabled,
|
||||
BlockDangerousDomains: x.BlockDangerousDomains,
|
||||
BlockNewlyRegisteredDomains: x.BlockNrd,
|
||||
}
|
||||
c.Enabled = x.Enabled
|
||||
c.DangerousDomainsEnabled = x.BlockDangerousDomains
|
||||
c.NewlyRegisteredDomainsEnabled = x.BlockNrd
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// toInternal converts protobuf access settings to an internal structure. If x
|
||||
@ -141,14 +157,15 @@ func (x *SafeBrowsingSettings) toInternal() (sb *agd.SafeBrowsingSettings) {
|
||||
func (x *AccessSettings) toInternal(
|
||||
ctx context.Context,
|
||||
errColl errcoll.Interface,
|
||||
logger *slog.Logger,
|
||||
) (a access.Profile) {
|
||||
if x == nil || !x.Enabled {
|
||||
return access.EmptyProfile{}
|
||||
}
|
||||
|
||||
return access.NewDefaultProfile(&access.ProfileConfig{
|
||||
AllowedNets: cidrRangeToInternal(ctx, errColl, x.AllowlistCidr),
|
||||
BlockedNets: cidrRangeToInternal(ctx, errColl, x.BlocklistCidr),
|
||||
AllowedNets: cidrRangeToInternal(ctx, errColl, logger, x.AllowlistCidr),
|
||||
BlockedNets: cidrRangeToInternal(ctx, errColl, logger, x.BlocklistCidr),
|
||||
AllowedASN: asnToInternal(x.AllowlistAsn),
|
||||
BlockedASN: asnToInternal(x.BlocklistAsn),
|
||||
BlocklistDomainRules: x.BlocklistDomainRules,
|
||||
@ -160,12 +177,14 @@ func (x *AccessSettings) toInternal(
|
||||
func cidrRangeToInternal(
|
||||
ctx context.Context,
|
||||
errColl errcoll.Interface,
|
||||
logger *slog.Logger,
|
||||
cidrs []*CidrRange,
|
||||
) (out []netip.Prefix) {
|
||||
for i, c := range cidrs {
|
||||
addr, ok := netip.AddrFromSlice(c.Address)
|
||||
if !ok {
|
||||
reportf(ctx, errColl, "bad cidr at index %d: %v", i, c.Address)
|
||||
err := fmt.Errorf("bad cidr at index %d: %v", i, c.Address)
|
||||
errcoll.Collect(ctx, errColl, logger, "converting cidrs", err)
|
||||
|
||||
continue
|
||||
}
|
||||
@ -187,71 +206,71 @@ func asnToInternal(asns []uint32) (out []geoip.ASN) {
|
||||
}
|
||||
|
||||
// blockedSvcsToInternal is a helper that converts the blocked service IDs from
|
||||
// the backend response to AdGuard DNS blocked service IDs.
|
||||
// the backend response to AdGuard DNS blocked-service IDs.
|
||||
func blockedSvcsToInternal(
|
||||
ctx context.Context,
|
||||
errColl errcoll.Interface,
|
||||
logger *slog.Logger,
|
||||
respSvcs []string,
|
||||
) (svcs []agd.BlockedServiceID) {
|
||||
) (ids []filter.BlockedServiceID) {
|
||||
l := len(respSvcs)
|
||||
if l == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
svcs = make([]agd.BlockedServiceID, 0, l)
|
||||
for i, s := range respSvcs {
|
||||
id, err := agd.NewBlockedServiceID(s)
|
||||
ids = make([]filter.BlockedServiceID, 0, l)
|
||||
for i, idStr := range respSvcs {
|
||||
id, err := filter.NewBlockedServiceID(idStr)
|
||||
if err != nil {
|
||||
reportf(ctx, errColl, "blocked service at index %d: %w", i, err)
|
||||
err = fmt.Errorf("at index %d: %w", i, err)
|
||||
errcoll.Collect(ctx, errColl, logger, "converting blocked services", err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
svcs = append(svcs, id)
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
return svcs
|
||||
return ids
|
||||
}
|
||||
|
||||
// toInternal converts a protobuf protection-schedule structure to an internal
|
||||
// one. If x is nil, toInternal returns nil.
|
||||
func (x *ScheduleSettings) toInternal() (sch *agd.ParentalProtectionSchedule, err error) {
|
||||
func (x *ScheduleSettings) toInternal() (c *filter.ConfigSchedule, err error) {
|
||||
if x == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sch = &agd.ParentalProtectionSchedule{}
|
||||
c = &filter.ConfigSchedule{
|
||||
Week: &filter.WeeklySchedule{},
|
||||
}
|
||||
|
||||
sch.TimeZone, err = agdtime.LoadLocation(x.Tmz)
|
||||
c.TimeZone, err = agdtime.LoadLocation(x.Tmz)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading timezone: %w", err)
|
||||
}
|
||||
|
||||
sch.Week = &agd.WeeklySchedule{}
|
||||
|
||||
w := x.WeeklyRange
|
||||
days := []*DayRange{w.Sun, w.Mon, w.Tue, w.Wed, w.Thu, w.Fri, w.Sat}
|
||||
for i, d := range days {
|
||||
if d == nil {
|
||||
sch.Week[i] = agd.ZeroLengthDayRange()
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
sch.Week[i] = agd.DayRange{
|
||||
ivl := &filter.DayInterval{
|
||||
Start: uint16(d.Start.AsDuration().Minutes()),
|
||||
End: uint16(d.End.AsDuration().Minutes()),
|
||||
}
|
||||
End: uint16(d.End.AsDuration().Minutes() + 1),
|
||||
}
|
||||
|
||||
for i, r := range sch.Week {
|
||||
err = r.Validate()
|
||||
err = ivl.Validate()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("weekday %s: %w", time.Weekday(i), err)
|
||||
}
|
||||
|
||||
c.Week[i] = ivl
|
||||
}
|
||||
|
||||
return sch, nil
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// toInternal converts a protobuf custom blocking-mode to an internal one.
|
||||
@ -312,17 +331,19 @@ func rulesToInternal(
|
||||
ctx context.Context,
|
||||
respRules []string,
|
||||
errColl errcoll.Interface,
|
||||
) (rules []agd.FilterRuleText) {
|
||||
logger *slog.Logger,
|
||||
) (rules []filter.RuleText) {
|
||||
l := len(respRules)
|
||||
if l == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
rules = make([]agd.FilterRuleText, 0, l)
|
||||
rules = make([]filter.RuleText, 0, l)
|
||||
for i, r := range respRules {
|
||||
text, err := agd.NewFilterRuleText(r)
|
||||
text, err := filter.NewRuleText(r)
|
||||
if err != nil {
|
||||
reportf(ctx, errColl, "rule at index %d: %w", i, err)
|
||||
err = fmt.Errorf("at index %d: %w", i, err)
|
||||
errcoll.Collect(ctx, errColl, logger, "converting rules", err)
|
||||
|
||||
continue
|
||||
}
|
||||
@ -334,32 +355,32 @@ func rulesToInternal(
|
||||
}
|
||||
|
||||
// toInternal is a helper that converts the filter lists from the backend
|
||||
// response to AdGuard DNS filter list ids. If x is nil, toInternal returns
|
||||
// false and nil.
|
||||
// response to AdGuard DNS rule-list configuration. If x is nil, toInternal
|
||||
// returns a disabled configuration.
|
||||
func (x *RuleListsSettings) toInternal(
|
||||
ctx context.Context,
|
||||
errColl errcoll.Interface,
|
||||
) (enabled bool, filterLists []agd.FilterListID) {
|
||||
logger *slog.Logger,
|
||||
) (c *filter.ConfigRuleList) {
|
||||
c = &filter.ConfigRuleList{}
|
||||
if x == nil {
|
||||
return false, nil
|
||||
return c
|
||||
}
|
||||
|
||||
l := len(x.Ids)
|
||||
if l == 0 {
|
||||
return x.Enabled, nil
|
||||
}
|
||||
c.Enabled = x.Enabled
|
||||
c.IDs = make([]filter.ID, 0, len(x.Ids))
|
||||
|
||||
filterLists = make([]agd.FilterListID, 0, l)
|
||||
for i, f := range x.Ids {
|
||||
id, err := agd.NewFilterListID(f)
|
||||
for i, idStr := range x.Ids {
|
||||
id, err := filter.NewID(idStr)
|
||||
if err != nil {
|
||||
reportf(ctx, errColl, "filter id: at index %d: %w", i, err)
|
||||
err = fmt.Errorf("at index %d: %w", i, err)
|
||||
errcoll.Collect(ctx, errColl, logger, "converting filter id", err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
filterLists = append(filterLists, id)
|
||||
c.IDs = append(c.IDs, id)
|
||||
}
|
||||
|
||||
return x.Enabled, filterLists
|
||||
return c
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/c2h5oh/datasize"
|
||||
@ -35,7 +36,8 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@ -58,14 +60,15 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
savingErrColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
testutil.AssertErrorMsg(
|
||||
t,
|
||||
`backendpb: bad device settings for device with id "inv-d-ip":`+
|
||||
" dedicated ips: ip at index 0: unexpected slice size",
|
||||
`converting device: bad settings for device with id "inv-d-ip":`+
|
||||
` dedicated ips: ip at index 0: unexpected slice size`,
|
||||
errCollErr,
|
||||
)
|
||||
|
||||
@ -89,13 +92,14 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
bindSet,
|
||||
savingErrColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
testutil.AssertErrorMsg(
|
||||
t,
|
||||
`backendpb: bad device settings for device with id "`+TestDeviceIDStr+`":`+
|
||||
`converting device: bad settings for device with id "`+TestDeviceIDStr+`":`+
|
||||
" dedicated ips: at index 0: \"1.1.1.2\" is not in bind data",
|
||||
errCollErr,
|
||||
)
|
||||
@ -114,7 +118,8 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
testutil.AssertErrorMsg(t, "profile is nil", err)
|
||||
@ -133,7 +138,8 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@ -155,12 +161,13 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
testutil.AssertErrorMsg(
|
||||
t,
|
||||
"parental: schedule: loading timezone: unknown time zone invalid",
|
||||
"parental: pause schedule: loading timezone: unknown time zone invalid",
|
||||
err,
|
||||
)
|
||||
})
|
||||
@ -179,12 +186,13 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
testutil.AssertErrorMsg(
|
||||
t,
|
||||
"parental: schedule: weekday Sunday: bad day range: end 0 less than start 16",
|
||||
"parental: pause schedule: weekday Sunday: end: out of range: 1 is less than start 16",
|
||||
err,
|
||||
)
|
||||
})
|
||||
@ -201,7 +209,8 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
testutil.AssertErrorMsg(t, "blocking mode: bad custom ipv4: unexpected slice size", err)
|
||||
@ -219,7 +228,8 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
testutil.AssertErrorMsg(t, "blocking mode: bad custom ipv6: unexpected slice size", err)
|
||||
@ -238,7 +248,8 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
testutil.AssertErrorMsg(t, "blocking mode: no valid custom ips found", err)
|
||||
@ -255,7 +266,8 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@ -279,7 +291,8 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@ -302,7 +315,8 @@ func TestDNSProfile_ToInternal(t *testing.T) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@ -464,6 +478,7 @@ func NewTestDNSProfile(tb testing.TB) (dp *DNSProfile) {
|
||||
Prefix: 24,
|
||||
}},
|
||||
},
|
||||
BlockChromePrefetch: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -484,35 +499,37 @@ func newProfile(tb testing.TB) (p *agd.Profile) {
|
||||
wantLoc, err := agdtime.LoadLocation("GMT")
|
||||
require.NoError(tb, err)
|
||||
|
||||
dayRange := agd.DayRange{
|
||||
dayIvl := &filter.DayInterval{
|
||||
Start: 0,
|
||||
End: 59,
|
||||
End: 60,
|
||||
}
|
||||
|
||||
wantParental := &agd.ParentalProtectionSettings{
|
||||
Schedule: &agd.ParentalProtectionSchedule{
|
||||
Week: &agd.WeeklySchedule{
|
||||
agd.ZeroLengthDayRange(),
|
||||
dayRange,
|
||||
dayRange,
|
||||
dayRange,
|
||||
dayRange,
|
||||
dayRange,
|
||||
agd.ZeroLengthDayRange(),
|
||||
wantParental := &filter.ConfigParental{
|
||||
PauseSchedule: &filter.ConfigSchedule{
|
||||
Week: &filter.WeeklySchedule{
|
||||
nil,
|
||||
dayIvl,
|
||||
dayIvl,
|
||||
dayIvl,
|
||||
dayIvl,
|
||||
dayIvl,
|
||||
nil,
|
||||
},
|
||||
TimeZone: wantLoc,
|
||||
},
|
||||
BlockedServices: []agd.BlockedServiceID{"youtube"},
|
||||
BlockedServices: []filter.BlockedServiceID{
|
||||
"youtube",
|
||||
},
|
||||
Enabled: false,
|
||||
BlockAdult: false,
|
||||
GeneralSafeSearch: false,
|
||||
YoutubeSafeSearch: false,
|
||||
AdultBlockingEnabled: false,
|
||||
SafeSearchGeneralEnabled: false,
|
||||
SafeSearchYouTubeEnabled: false,
|
||||
}
|
||||
|
||||
wantSafeBrowsing := &agd.SafeBrowsingSettings{
|
||||
wantSafeBrowsing := &filter.ConfigSafeBrowsing{
|
||||
Enabled: true,
|
||||
BlockDangerousDomains: true,
|
||||
BlockNewlyRegisteredDomains: false,
|
||||
DangerousDomainsEnabled: true,
|
||||
NewlyRegisteredDomainsEnabled: false,
|
||||
}
|
||||
|
||||
wantBlockingMode := &dnsmsg.BlockingModeCustomIP{
|
||||
@ -535,30 +552,39 @@ func newProfile(tb testing.TB) (p *agd.Profile) {
|
||||
}, 1*datasize.KB)
|
||||
|
||||
return &agd.Profile{
|
||||
Parental: wantParental,
|
||||
BlockingMode: wantBlockingMode,
|
||||
ID: TestProfileID,
|
||||
FilterConfig: &filter.ConfigClient{
|
||||
Custom: &filter.ConfigCustom{
|
||||
ID: TestProfileIDStr,
|
||||
UpdateTime: TestUpdTime,
|
||||
Rules: []filter.RuleText{"||example.org^"},
|
||||
Enabled: true,
|
||||
},
|
||||
Parental: wantParental,
|
||||
RuleList: &filter.ConfigRuleList{
|
||||
IDs: []filter.ID{"1"},
|
||||
Enabled: true,
|
||||
},
|
||||
SafeBrowsing: wantSafeBrowsing,
|
||||
},
|
||||
Access: wantAccess,
|
||||
BlockingMode: wantBlockingMode,
|
||||
Ratelimiter: wantRateLimiter,
|
||||
ID: TestProfileID,
|
||||
DeviceIDs: []agd.DeviceID{
|
||||
TestDeviceID,
|
||||
"2222bbbb",
|
||||
"3333cccc",
|
||||
"4444dddd",
|
||||
},
|
||||
RuleListIDs: []agd.FilterListID{"1"},
|
||||
CustomRules: []agd.FilterRuleText{"||example.org^"},
|
||||
FilteredResponseTTL: 10 * time.Second,
|
||||
Ratelimiter: wantRateLimiter,
|
||||
SafeBrowsing: wantSafeBrowsing,
|
||||
Access: wantAccess,
|
||||
RuleListsEnabled: true,
|
||||
FilteringEnabled: true,
|
||||
QueryLogEnabled: true,
|
||||
Deleted: false,
|
||||
BlockPrivateRelay: true,
|
||||
BlockFirefoxCanary: true,
|
||||
IPLogEnabled: true,
|
||||
AutoDevicesEnabled: true,
|
||||
BlockChromePrefetch: true,
|
||||
BlockFirefoxCanary: true,
|
||||
BlockPrivateRelay: true,
|
||||
Deleted: false,
|
||||
FilteringEnabled: true,
|
||||
IPLogEnabled: true,
|
||||
QueryLogEnabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,7 +657,8 @@ func BenchmarkDNSProfile_ToInternal(b *testing.B) {
|
||||
TestUpdTime,
|
||||
TestBind,
|
||||
errColl,
|
||||
EmptyMetrics{},
|
||||
TestLogger,
|
||||
EmptyProfileDBMetrics{},
|
||||
TestRespSzEst,
|
||||
)
|
||||
}
|
||||
@ -639,10 +666,10 @@ func BenchmarkDNSProfile_ToInternal(b *testing.B) {
|
||||
require.NotNil(b, profSink)
|
||||
require.NoError(b, errSink)
|
||||
|
||||
// Most recent result, on a ThinkPad X13:
|
||||
// Most recent results:
|
||||
// goos: linux
|
||||
// goarch: amd64
|
||||
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/backendpb
|
||||
// cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
|
||||
// BenchmarkDNSProfile_ToInternal-16 67160 22130 ns/op 3048 B/op 51 allocs/op
|
||||
// BenchmarkDNSProfile_ToInternal-16 79732 14686 ns/op 3160 B/op 59 allocs/op
|
||||
}
|
||||
|
@ -31,12 +31,16 @@ type ProfileStorageConfig struct {
|
||||
// non-critical errors. It must not be nil.
|
||||
ErrColl errcoll.Interface
|
||||
|
||||
// Logger is used as the base logger for the profile storage. It must not
|
||||
// be nil.
|
||||
// Logger is used for logging the operation of the profile storage. It must
|
||||
// not be nil.
|
||||
Logger *slog.Logger
|
||||
|
||||
// Metrics is used for the collection of the protobuf errors.
|
||||
Metrics Metrics
|
||||
// GRPCMetrics is used for the collection of the protobuf communication
|
||||
// statistics.
|
||||
GRPCMetrics GRPCMetrics
|
||||
|
||||
// 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.
|
||||
@ -63,7 +67,8 @@ type ProfileStorage struct {
|
||||
errColl errcoll.Interface
|
||||
client DNSServiceClient
|
||||
logger *slog.Logger
|
||||
metrics Metrics
|
||||
grpcMetrics GRPCMetrics
|
||||
metrics ProfileDBMetrics
|
||||
apiKey string
|
||||
respSzEst datasize.ByteSize
|
||||
maxProfSize datasize.ByteSize
|
||||
@ -83,6 +88,7 @@ func NewProfileStorage(c *ProfileStorageConfig) (s *ProfileStorage, err error) {
|
||||
errColl: c.ErrColl,
|
||||
client: NewDNSServiceClient(client),
|
||||
logger: c.Logger,
|
||||
grpcMetrics: c.GRPCMetrics,
|
||||
metrics: c.Metrics,
|
||||
apiKey: c.APIKey,
|
||||
respSzEst: c.ResponseSizeEstimate,
|
||||
@ -115,7 +121,7 @@ func (s *ProfileStorage) CreateAutoDevice(
|
||||
DeviceType: DeviceType(req.DeviceType),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("calling backend: %w", fixGRPCError(ctx, s.metrics, err))
|
||||
return nil, fmt.Errorf("calling backend: %w", fixGRPCError(ctx, s.grpcMetrics, err))
|
||||
}
|
||||
|
||||
d, err := backendResp.Device.toInternal(s.bindSet)
|
||||
@ -140,7 +146,7 @@ func (s *ProfileStorage) Profiles(
|
||||
respSzOpt := grpc.MaxCallRecvMsgSize(int(s.maxProfSize.Bytes()))
|
||||
stream, err := s.client.GetDNSProfiles(ctx, toProtobuf(req), respSzOpt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading profiles: %w", fixGRPCError(ctx, s.metrics, err))
|
||||
return nil, fmt.Errorf("loading profiles: %w", fixGRPCError(ctx, s.grpcMetrics, err))
|
||||
}
|
||||
defer func() { err = errors.WithDeferred(err, stream.CloseSend()) }()
|
||||
|
||||
@ -165,7 +171,7 @@ func (s *ProfileStorage) Profiles(
|
||||
return nil, fmt.Errorf(
|
||||
"receiving profile #%d: %w",
|
||||
n,
|
||||
fixGRPCError(ctx, s.metrics, profErr),
|
||||
fixGRPCError(ctx, s.grpcMetrics, profErr),
|
||||
)
|
||||
}
|
||||
stats.endRecv()
|
||||
@ -176,11 +182,12 @@ func (s *ProfileStorage) Profiles(
|
||||
time.Now(),
|
||||
s.bindSet,
|
||||
s.errColl,
|
||||
s.logger,
|
||||
s.metrics,
|
||||
s.respSzEst,
|
||||
)
|
||||
if profErr != nil {
|
||||
reportf(ctx, s.errColl, "loading profile: %w", profErr)
|
||||
errcoll.Collect(ctx, s.errColl, s.logger, "loading profile", profErr)
|
||||
|
||||
continue
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/c2h5oh/datasize"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -69,8 +68,9 @@ func TestProfileStorage_CreateAutoDevice(t *testing.T) {
|
||||
s, err := backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
|
||||
BindSet: backendpb.TestBind,
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Metrics: backendpb.EmptyMetrics{},
|
||||
Logger: backendpb.TestLogger,
|
||||
GRPCMetrics: backendpb.EmptyGRPCMetrics{},
|
||||
Metrics: backendpb.EmptyProfileDBMetrics{},
|
||||
Endpoint: &url.URL{
|
||||
Scheme: "grpc",
|
||||
Host: l.Addr().String(),
|
||||
@ -159,8 +159,9 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
|
||||
s, err := backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
|
||||
BindSet: netip.MustParsePrefix("0.0.0.0/0"),
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Metrics: backendpb.EmptyMetrics{},
|
||||
Logger: backendpb.TestLogger,
|
||||
GRPCMetrics: backendpb.EmptyGRPCMetrics{},
|
||||
Metrics: backendpb.EmptyProfileDBMetrics{},
|
||||
Endpoint: &url.URL{
|
||||
Scheme: "grpc",
|
||||
Host: l.Addr().String(),
|
||||
@ -195,8 +196,10 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
|
||||
require.NoError(b, errSink)
|
||||
require.NotNil(b, respSink)
|
||||
|
||||
// goos: darwin
|
||||
// goarch: arm64
|
||||
// Most recent results:
|
||||
// goos: linux
|
||||
// goarch: amd64
|
||||
// pkg: github.com/AdguardTeam/AdGuardDNS/internal/backendpb
|
||||
// BenchmarkProfileStorage_Profiles-8 11599 104725 ns/op 18281 B/op 328 allocs/op
|
||||
// cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
|
||||
// BenchmarkProfileStorage_Profiles-16 4501 258657 ns/op 20020 B/op 350 allocs/op
|
||||
}
|
||||
|
@ -19,8 +19,9 @@ type RateLimiterConfig struct {
|
||||
// not be nil.
|
||||
Logger *slog.Logger
|
||||
|
||||
// GRPCMetrics is used for the collection of the protobuf errors.
|
||||
GRPCMetrics Metrics
|
||||
// GRPCMetrics is used for the collection of the protobuf communication
|
||||
// statistics.
|
||||
GRPCMetrics GRPCMetrics
|
||||
|
||||
// Metrics is used to collect allowlist statistics.
|
||||
Metrics consul.Metrics
|
||||
@ -44,7 +45,7 @@ type RateLimiterConfig struct {
|
||||
// that retrieves the rate limit settings from the business logic backend.
|
||||
type RateLimiter struct {
|
||||
logger *slog.Logger
|
||||
grpcMetrics Metrics
|
||||
grpcMetrics GRPCMetrics
|
||||
metrics consul.Metrics
|
||||
allowlist *ratelimit.DynamicAllowlist
|
||||
errColl errcoll.Interface
|
||||
@ -92,7 +93,7 @@ func (l *RateLimiter) Refresh(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
allowedSubnets := backendResp.AllowedSubnets
|
||||
prefixes := cidrRangeToInternal(ctx, l.errColl, allowedSubnets)
|
||||
prefixes := cidrRangeToInternal(ctx, l.errColl, l.logger, allowedSubnets)
|
||||
l.allowlist.Update(prefixes)
|
||||
|
||||
l.logger.InfoContext(ctx, "refresh successful", "num_records", len(prefixes))
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/consul"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -83,9 +82,9 @@ func TestRateLimiter_Refresh(t *testing.T) {
|
||||
|
||||
allowlist := ratelimit.NewDynamicAllowlist(nil, nil)
|
||||
l, err := backendpb.NewRateLimiter(&backendpb.RateLimiterConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Logger: backendpb.TestLogger,
|
||||
Metrics: consul.EmptyMetrics{},
|
||||
GRPCMetrics: backendpb.EmptyMetrics{},
|
||||
GRPCMetrics: backendpb.EmptyGRPCMetrics{},
|
||||
Allowlist: allowlist,
|
||||
Endpoint: &url.URL{
|
||||
Scheme: "grpc",
|
||||
|
@ -7,18 +7,20 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/remotekv"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
)
|
||||
|
||||
// RemoteKVConfig is the configuration for the business logic backend key-value
|
||||
// storage.
|
||||
type RemoteKVConfig struct {
|
||||
// Metrics is used for the collection of the remote key-value storage
|
||||
// Metrics is used for the collection of the backend remote key-value
|
||||
// storage statistics.
|
||||
Metrics RemoteKVMetrics
|
||||
|
||||
// GRPCMetrics is used for the collection of the protobuf communication
|
||||
// statistics.
|
||||
//
|
||||
// TODO(e.burkov): Perhaps, it worths of a separate metrics interface,
|
||||
// since it's only used for the collection of the protobuf errors.
|
||||
Metrics Metrics
|
||||
GRPCMetrics GRPCMetrics
|
||||
|
||||
// Endpoint is the backend API URL. The scheme should be either "grpc" or
|
||||
// "grpcs".
|
||||
@ -35,7 +37,8 @@ type RemoteKVConfig struct {
|
||||
// uses the business logic backend as the key-value storage. It is safe for
|
||||
// concurrent use.
|
||||
type RemoteKV struct {
|
||||
metrics Metrics
|
||||
grpcMetrics GRPCMetrics
|
||||
metrics RemoteKVMetrics
|
||||
client RemoteKVServiceClient
|
||||
apiKey string
|
||||
ttl time.Duration
|
||||
@ -51,6 +54,7 @@ func NewRemoteKV(c *RemoteKVConfig) (kv *RemoteKV, err error) {
|
||||
}
|
||||
|
||||
return &RemoteKV{
|
||||
grpcMetrics: c.GRPCMetrics,
|
||||
metrics: c.Metrics,
|
||||
client: NewRemoteKVServiceClient(client),
|
||||
apiKey: c.APIKey,
|
||||
@ -68,14 +72,34 @@ func (kv *RemoteKV) Get(ctx context.Context, key string) (val []byte, ok bool, e
|
||||
}
|
||||
|
||||
ctx = ctxWithAuthentication(ctx, kv.apiKey)
|
||||
|
||||
start := time.Now()
|
||||
resp, err := kv.client.Get(ctx, req)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("getting %q key: %w", key, fixGRPCError(ctx, kv.metrics, err))
|
||||
err = fmt.Errorf("getting %q key: %w", key, fixGRPCError(ctx, kv.grpcMetrics, err))
|
||||
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
val = resp.GetData()
|
||||
kv.metrics.ObserveOperation(ctx, RemoteKVOpGet, time.Since(start))
|
||||
|
||||
return val, val != nil, nil
|
||||
defer func() { kv.metrics.IncrementLookups(ctx, ok) }()
|
||||
|
||||
received := resp.GetValue()
|
||||
|
||||
switch received := received.(type) {
|
||||
case *RemoteKVGetResponse_Data:
|
||||
return received.Data, true, nil
|
||||
case *RemoteKVGetResponse_Empty:
|
||||
return nil, false, nil
|
||||
default:
|
||||
return nil, false, fmt.Errorf(
|
||||
"getting %q key: response type: %w: %T(%[3]v)",
|
||||
key,
|
||||
errors.ErrBadEnumValue,
|
||||
received,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Set implements the [remotekv.Interface] interface for *RemoteKV.
|
||||
@ -87,10 +111,14 @@ func (kv *RemoteKV) Set(ctx context.Context, key string, val []byte) (err error)
|
||||
}
|
||||
|
||||
ctx = ctxWithAuthentication(ctx, kv.apiKey)
|
||||
|
||||
start := time.Now()
|
||||
_, err = kv.client.Set(ctx, req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting %q key: %w", key, fixGRPCError(ctx, kv.metrics, err))
|
||||
return fmt.Errorf("setting %q key: %w", key, fixGRPCError(ctx, kv.grpcMetrics, err))
|
||||
}
|
||||
|
||||
kv.metrics.ObserveOperation(ctx, RemoteKVOpSet, time.Since(start))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -65,7 +65,8 @@ func TestRemoteKV_Get(t *testing.T) {
|
||||
t.Cleanup(grpcSrv.GracefulStop)
|
||||
|
||||
kv, err := backendpb.NewRemoteKV(&backendpb.RemoteKVConfig{
|
||||
Metrics: backendpb.EmptyMetrics{},
|
||||
GRPCMetrics: backendpb.EmptyGRPCMetrics{},
|
||||
Metrics: backendpb.EmptyRemoteKVMetrics{},
|
||||
Endpoint: &url.URL{
|
||||
Scheme: "grpc",
|
||||
Host: l.Addr().String(),
|
||||
|
@ -54,7 +54,7 @@ func (s *profilesCallStats) endDec() {
|
||||
}
|
||||
|
||||
// report writes the statistics to the log and the metrics.
|
||||
func (s *profilesCallStats) report(ctx context.Context, mtrc Metrics) {
|
||||
func (s *profilesCallStats) report(ctx context.Context, mtrc ProfileDBMetrics) {
|
||||
lvl := slog.LevelDebug
|
||||
if s.isFullSync {
|
||||
lvl = slog.LevelInfo
|
||||
|
@ -54,7 +54,9 @@ func newChanPacketConn(
|
||||
sessions: sessions,
|
||||
writeRequests: writeRequests,
|
||||
|
||||
sessionsGauge: metrics.BindToDeviceUDPSessionsChanSize.WithLabelValues(subnet.String()),
|
||||
sessionsGauge: metrics.BindToDeviceUDPSessionsChanSize.WithLabelValues(
|
||||
subnet.String(),
|
||||
),
|
||||
writeRequestsGauge: writeRequestsGauge,
|
||||
|
||||
deadlineMu: &sync.RWMutex{},
|
||||
|
@ -70,7 +70,12 @@ func listenControlWithSO(
|
||||
opts,
|
||||
newIntSetSockOptFunc("IP_RECVORIGDSTADDR", unix.IPPROTO_IP, unix.IP_RECVORIGDSTADDR, 1),
|
||||
newIntSetSockOptFunc("IP_FREEBIND", unix.IPPROTO_IP, unix.IP_FREEBIND, 1),
|
||||
newIntSetSockOptFunc("IPV6_RECVORIGDSTADDR", unix.IPPROTO_IPV6, unix.IPV6_RECVORIGDSTADDR, 1),
|
||||
newIntSetSockOptFunc(
|
||||
"IPV6_RECVORIGDSTADDR",
|
||||
unix.IPPROTO_IPV6,
|
||||
unix.IPV6_RECVORIGDSTADDR,
|
||||
1,
|
||||
),
|
||||
newIntSetSockOptFunc("IPV6_FREEBIND", unix.IPPROTO_IPV6, unix.IPV6_FREEBIND, 1),
|
||||
)
|
||||
default:
|
||||
|
@ -6,14 +6,9 @@ import (
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/billstat"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||
"github.com/AdguardTeam/golibs/timeutil"
|
||||
)
|
||||
|
||||
@ -91,24 +86,3 @@ func initProfDB(
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// newBillStatUploader creates and returns a billstat uploader depending on the
|
||||
// provided API URL.
|
||||
func newBillStatUploader(
|
||||
envs *environment,
|
||||
errColl errcoll.Interface,
|
||||
mtrc backendpb.Metrics,
|
||||
) (s billstat.Uploader, err error) {
|
||||
apiURL := netutil.CloneURL(&envs.BillStatURL.URL)
|
||||
err = urlutil.ValidateGRPCURL(apiURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("billstat api url: %w", err)
|
||||
}
|
||||
|
||||
return backendpb.NewBillStat(&backendpb.BillStatConfig{
|
||||
ErrColl: errColl,
|
||||
Metrics: mtrc,
|
||||
Endpoint: apiURL,
|
||||
APIKey: envs.BillStatAPIKey,
|
||||
})
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdtime"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/billstat"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/bindtodevice"
|
||||
@ -32,6 +33,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter/filterstorage"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
|
||||
@ -57,6 +59,7 @@ const (
|
||||
debugIDProfileDB = "profiledb"
|
||||
debugIDRuleStat = "rulestat"
|
||||
debugIDTicketRotator = "ticket_rotator"
|
||||
debugIDTLSConfig = "tlsconfig"
|
||||
debugIDWebSvc = "websvc"
|
||||
)
|
||||
|
||||
@ -76,6 +79,7 @@ type builder struct {
|
||||
cacheManager *agdcache.DefaultManager
|
||||
cloner *dnsmsg.Cloner
|
||||
conf *configuration
|
||||
debugRefrs debugsvc.Refreshers
|
||||
env *environment
|
||||
errColl errcoll.Interface
|
||||
geoIPError chan error
|
||||
@ -91,7 +95,7 @@ type builder struct {
|
||||
access *access.Global
|
||||
adultBlocking *hashprefix.Filter
|
||||
adultBlockingHashes *hashprefix.Storage
|
||||
backendGRPCMtrc *metrics.BackendPB
|
||||
backendGRPCMtrc *metrics.BackendGRPC
|
||||
billStat billstat.Recorder
|
||||
bindSet netutil.SubnetSet
|
||||
btdManager *bindtodevice.Manager
|
||||
@ -100,7 +104,8 @@ type builder struct {
|
||||
dnsCheck dnscheck.Interface
|
||||
dnsDB dnsdb.Interface
|
||||
dnsSvc *dnssvc.Service
|
||||
filterStorage *filter.DefaultStorage
|
||||
filterMtrc filter.Metrics
|
||||
filterStorage *filterstorage.Default
|
||||
filteringGroups map[agd.FilteringGroupID]*agd.FilteringGroup
|
||||
fwdHandler *forward.Handler
|
||||
geoIP *geoip.File
|
||||
@ -110,12 +115,11 @@ type builder struct {
|
||||
newRegDomainsHashes *hashprefix.Storage
|
||||
profileDB profiledb.Interface
|
||||
rateLimit *ratelimit.Backoff
|
||||
debugRefrs debugsvc.Refreshers
|
||||
ruleStat rulestat.Interface
|
||||
safeBrowsing *hashprefix.Filter
|
||||
safeBrowsingHashes *hashprefix.Storage
|
||||
sdeConf *dnsmsg.StructuredDNSErrorsConfig
|
||||
tlsMtrc tlsconfig.Metrics
|
||||
tlsManager *tlsconfig.DefaultManager
|
||||
webSvc *websvc.Service
|
||||
|
||||
// The fields below are initialized later, just like with the fields above,
|
||||
@ -201,8 +205,8 @@ func (b *builder) initGeoIP(ctx context.Context) {
|
||||
CacheManager: b.cacheManager,
|
||||
ASNPath: asn,
|
||||
CountryPath: ctry,
|
||||
HostCacheSize: c.HostCacheSize,
|
||||
IPCacheSize: c.IPCacheSize,
|
||||
HostCacheCount: c.HostCacheSize,
|
||||
IPCacheCount: c.IPCacheSize,
|
||||
AllTopASNs: geoip.DefaultTopASNs,
|
||||
CountryTopASNs: geoip.DefaultCountryTopASNs,
|
||||
})
|
||||
@ -225,6 +229,11 @@ func (b *builder) initHashPrefixFilters(ctx context.Context) (err error) {
|
||||
|
||||
matchers := map[string]*hashprefix.Storage{}
|
||||
|
||||
b.filterMtrc, err = metrics.NewFilter(b.mtrcNamespace, b.promRegisterer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("registering filter metrics: %w", err)
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Merge the three functions below together.
|
||||
|
||||
err = b.initAdultBlocking(ctx, matchers, maxSize, cacheDir)
|
||||
@ -251,8 +260,7 @@ func (b *builder) initHashPrefixFilters(ctx context.Context) (err error) {
|
||||
|
||||
// initAdultBlocking initializes the adult-blocking filter and hash storage. It
|
||||
// also adds the refresher with ID
|
||||
// [hashprefix.IDPrefix]/[agd.FilterListIDAdultBlocking] to the debug
|
||||
// refreshers.
|
||||
// [hashprefix.IDPrefix]/[filter.IDAdultBlocking] to the debug refreshers.
|
||||
//
|
||||
// It must be called from [builder.initHashPrefixFilters].
|
||||
func (b *builder) initAdultBlocking(
|
||||
@ -272,7 +280,7 @@ func (b *builder) initAdultBlocking(
|
||||
}
|
||||
|
||||
c := b.conf.AdultBlocking
|
||||
id := agd.FilterListIDAdultBlocking
|
||||
id := filter.IDAdultBlocking
|
||||
prefix := path.Join(hashprefix.IDPrefix, string(id))
|
||||
b.adultBlocking, err = hashprefix.NewFilter(&hashprefix.FilterConfig{
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, prefix),
|
||||
@ -281,6 +289,7 @@ func (b *builder) initAdultBlocking(
|
||||
Hashes: b.adultBlockingHashes,
|
||||
URL: &b.env.AdultBlockingURL.URL,
|
||||
ErrColl: b.errColl,
|
||||
Metrics: b.filterMtrc,
|
||||
ID: id,
|
||||
CachePath: filepath.Join(cacheDir, string(id)),
|
||||
ReplacementHost: c.BlockHost,
|
||||
@ -289,7 +298,7 @@ func (b *builder) initAdultBlocking(
|
||||
CacheTTL: c.CacheTTL.Duration,
|
||||
// TODO(a.garipov): Make all sizes [datasize.ByteSize] and rename cache
|
||||
// entity counts to fooCount.
|
||||
CacheSize: c.CacheSize,
|
||||
CacheCount: c.CacheSize,
|
||||
MaxSize: maxSize,
|
||||
})
|
||||
if err != nil {
|
||||
@ -327,8 +336,7 @@ func (b *builder) initAdultBlocking(
|
||||
|
||||
// initNewRegDomains initializes the newly-registered domain filter and hash
|
||||
// storage. It also adds the refresher with ID
|
||||
// [hashprefix.IDPrefix]/[agd.FilterListIDNewRegDomains] to the debug
|
||||
// refreshers.
|
||||
// [hashprefix.IDPrefix]/[filter.IDNewRegDomains] to the debug refreshers.
|
||||
//
|
||||
// It must be called from [builder.initHashPrefixFilters].
|
||||
func (b *builder) initNewRegDomains(
|
||||
@ -349,7 +357,7 @@ func (b *builder) initNewRegDomains(
|
||||
// Reuse the general safe-browsing filter configuration with a new URL and
|
||||
// ID.
|
||||
c := b.conf.SafeBrowsing
|
||||
id := agd.FilterListIDNewRegDomains
|
||||
id := filter.IDNewRegDomains
|
||||
prefix := path.Join(hashprefix.IDPrefix, string(id))
|
||||
b.newRegDomains, err = hashprefix.NewFilter(&hashprefix.FilterConfig{
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, prefix),
|
||||
@ -358,13 +366,14 @@ func (b *builder) initNewRegDomains(
|
||||
Hashes: b.newRegDomainsHashes,
|
||||
URL: &b.env.NewRegDomainsURL.URL,
|
||||
ErrColl: b.errColl,
|
||||
Metrics: b.filterMtrc,
|
||||
ID: id,
|
||||
CachePath: filepath.Join(cacheDir, string(id)),
|
||||
ReplacementHost: c.BlockHost,
|
||||
Staleness: c.RefreshIvl.Duration,
|
||||
RefreshTimeout: c.RefreshTimeout.Duration,
|
||||
CacheTTL: c.CacheTTL.Duration,
|
||||
CacheSize: c.CacheSize,
|
||||
CacheCount: c.CacheSize,
|
||||
MaxSize: maxSize,
|
||||
})
|
||||
if err != nil {
|
||||
@ -399,8 +408,8 @@ func (b *builder) initNewRegDomains(
|
||||
}
|
||||
|
||||
// initSafeBrowsing initializes the safe-browsing filter and hash storage. It
|
||||
// also adds the refresher with ID
|
||||
// [hashprefix.IDPrefix]/[agd.FilterListIDSafeBrowsing] to the debug refreshers.
|
||||
// also adds the refresher with ID [hashprefix.IDPrefix]/[filter.IDSafeBrowsing]
|
||||
// to the debug refreshers.
|
||||
//
|
||||
// It must be called from [builder.initHashPrefixFilters].
|
||||
func (b *builder) initSafeBrowsing(
|
||||
@ -420,7 +429,7 @@ func (b *builder) initSafeBrowsing(
|
||||
}
|
||||
|
||||
c := b.conf.SafeBrowsing
|
||||
id := agd.FilterListIDSafeBrowsing
|
||||
id := filter.IDSafeBrowsing
|
||||
prefix := path.Join(hashprefix.IDPrefix, string(id))
|
||||
b.safeBrowsing, err = hashprefix.NewFilter(&hashprefix.FilterConfig{
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, prefix),
|
||||
@ -429,13 +438,14 @@ func (b *builder) initSafeBrowsing(
|
||||
Hashes: b.safeBrowsingHashes,
|
||||
URL: &b.env.SafeBrowsingURL.URL,
|
||||
ErrColl: b.errColl,
|
||||
Metrics: b.filterMtrc,
|
||||
ID: id,
|
||||
CachePath: filepath.Join(cacheDir, string(id)),
|
||||
ReplacementHost: c.BlockHost,
|
||||
Staleness: c.RefreshIvl.Duration,
|
||||
RefreshTimeout: c.RefreshTimeout.Duration,
|
||||
CacheTTL: c.CacheTTL.Duration,
|
||||
CacheSize: c.CacheSize,
|
||||
CacheCount: c.CacheSize,
|
||||
MaxSize: maxSize,
|
||||
})
|
||||
if err != nil {
|
||||
@ -477,26 +487,78 @@ func (b *builder) initSafeBrowsing(
|
||||
// [builder.initHashPrefixFilters] must be called before this method.
|
||||
func (b *builder) initFilterStorage(ctx context.Context) (err error) {
|
||||
c := b.conf.Filters
|
||||
b.filterStorage = filter.NewDefaultStorage(c.toInternal(
|
||||
b.baseLogger,
|
||||
b.errColl,
|
||||
b.cacheManager,
|
||||
b.env,
|
||||
b.safeBrowsing,
|
||||
b.adultBlocking,
|
||||
b.newRegDomains,
|
||||
))
|
||||
refrIvl := c.RefreshIvl.Duration
|
||||
refrTimeout := c.RefreshTimeout.Duration
|
||||
|
||||
err = b.filterStorage.RefreshInitial(ctx)
|
||||
b.filterStorage, err = filterstorage.New(&filterstorage.Config{
|
||||
BaseLogger: b.baseLogger,
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, filter.StoragePrefix),
|
||||
BlockedServices: &filterstorage.ConfigBlockedServices{
|
||||
IndexURL: &b.env.BlockedServiceIndexURL.URL,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
IndexMaxSize: c.MaxSize,
|
||||
// TODO(a.garipov): Consider making configurable.
|
||||
IndexRefreshTimeout: 3 * time.Minute,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
IndexStaleness: refrIvl,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
ResultCacheCount: c.RuleListCache.Size,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
ResultCacheEnabled: c.RuleListCache.Enabled,
|
||||
Enabled: bool(b.env.BlockedServiceEnabled),
|
||||
},
|
||||
Custom: &filterstorage.ConfigCustom{
|
||||
CacheCount: c.CustomFilterCacheSize,
|
||||
},
|
||||
HashPrefix: &filterstorage.ConfigHashPrefix{
|
||||
Adult: b.adultBlocking,
|
||||
Dangerous: b.safeBrowsing,
|
||||
NewlyRegistered: b.newRegDomains,
|
||||
},
|
||||
RuleLists: &filterstorage.ConfigRuleLists{
|
||||
IndexURL: &b.env.FilterIndexURL.URL,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
IndexMaxSize: c.MaxSize,
|
||||
MaxSize: c.MaxSize,
|
||||
IndexRefreshTimeout: c.IndexRefreshTimeout.Duration,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
IndexStaleness: refrIvl,
|
||||
RefreshTimeout: refrTimeout,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
Staleness: refrIvl,
|
||||
ResultCacheCount: c.RuleListCache.Size,
|
||||
ResultCacheEnabled: c.RuleListCache.Enabled,
|
||||
},
|
||||
SafeSearchGeneral: b.newSafeSearchConfig(
|
||||
b.env.GeneralSafeSearchURL,
|
||||
filter.IDGeneralSafeSearch,
|
||||
bool(b.env.GeneralSafeSearchEnabled),
|
||||
),
|
||||
SafeSearchYouTube: b.newSafeSearchConfig(
|
||||
b.env.YoutubeSafeSearchURL,
|
||||
filter.IDYoutubeSafeSearch,
|
||||
bool(b.env.YoutubeSafeSearchEnabled),
|
||||
),
|
||||
CacheManager: b.cacheManager,
|
||||
Clock: agdtime.SystemClock{},
|
||||
ErrColl: b.errColl,
|
||||
Metrics: b.filterMtrc,
|
||||
CacheDir: b.env.FilterCachePath,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating default filter storage: %w", err)
|
||||
}
|
||||
|
||||
err = b.filterStorage.RefreshInitial(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("refreshing default filter storage: %w", err)
|
||||
}
|
||||
|
||||
refr := agdservice.NewRefreshWorker(&agdservice.RefreshWorkerConfig{
|
||||
Context: newCtxWithTimeoutCons(c.RefreshIvl.Duration),
|
||||
Context: newCtxWithTimeoutCons(refrTimeout),
|
||||
Refresher: b.filterStorage,
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "filters/storage_refresh"),
|
||||
Interval: c.RefreshIvl.Duration,
|
||||
Interval: refrIvl,
|
||||
RefreshOnShutdown: false,
|
||||
RandomizeStart: false,
|
||||
})
|
||||
@ -514,6 +576,35 @@ func (b *builder) initFilterStorage(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// newSafeSearchConfig returns a new safe-search configuration for the given URL
|
||||
// and ID if enabled; otherwise, it returns an empty configuration.
|
||||
func (b *builder) newSafeSearchConfig(
|
||||
u *urlutil.URL,
|
||||
id filter.ID,
|
||||
enabled bool,
|
||||
) (c *filterstorage.ConfigSafeSearch) {
|
||||
if !enabled {
|
||||
return &filterstorage.ConfigSafeSearch{}
|
||||
}
|
||||
|
||||
fltConf := b.conf.Filters
|
||||
|
||||
return &filterstorage.ConfigSafeSearch{
|
||||
URL: &u.URL,
|
||||
ID: id,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
MaxSize: fltConf.MaxSize,
|
||||
// TODO(a.garipov): Consider making this configurable.
|
||||
ResultCacheTTL: 1 * time.Hour,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
RefreshTimeout: fltConf.RefreshTimeout.Duration,
|
||||
// TODO(a.garipov): Consider adding a separate parameter here.
|
||||
Staleness: fltConf.RefreshIvl.Duration,
|
||||
ResultCacheCount: fltConf.SafeSearchCacheSize,
|
||||
Enabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
// initFilteringGroups initializes the filtering groups.
|
||||
//
|
||||
// [builder.initFilterStorage] must be called before this method.
|
||||
@ -606,26 +697,54 @@ func (b *builder) initMsgConstructor(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// initTLSManager initializes the TLS manager and the TLS-related metrics. It
|
||||
// also adds the refresher with ID [debugIDTLSConfig] to the debug refreshers.
|
||||
func (b *builder) initTLSManager(ctx context.Context) (err error) {
|
||||
mtrc, err := metrics.NewTLSConfig(b.mtrcNamespace, b.promRegisterer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("registering tls metrics: %w", err)
|
||||
}
|
||||
|
||||
logFile := b.env.SSLKeyLogFile
|
||||
if logFile != "" {
|
||||
b.logger.WarnContext(ctx, "tls key logging is enabled", "file", logFile)
|
||||
}
|
||||
|
||||
ticketPaths := b.conf.ServerGroups.collectSessTicketPaths()
|
||||
|
||||
mgr, err := tlsconfig.NewDefaultManager(&tlsconfig.DefaultManagerConfig{
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "tlsconfig"),
|
||||
ErrColl: b.errColl,
|
||||
Metrics: mtrc,
|
||||
KeyLogFilename: logFile,
|
||||
SessionTicketPaths: ticketPaths,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("initializing tls manager: %w", err)
|
||||
}
|
||||
|
||||
b.tlsManager = mgr
|
||||
b.debugRefrs[debugIDTLSConfig] = mgr
|
||||
|
||||
b.logger.DebugContext(ctx, "initialized tls manager")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initServerGroups initializes the server groups.
|
||||
//
|
||||
// The following methods must be called before this one:
|
||||
// - [builder.initBindToDevice]
|
||||
// - [builder.initFilteringGroups]
|
||||
// - [builder.initMsgConstructor]
|
||||
// - [builder.initTLSManager]
|
||||
func (b *builder) initServerGroups(ctx context.Context) (err error) {
|
||||
mtrc, err := metrics.NewTLSConfig(b.mtrcNamespace, b.promRegisterer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("registering tls metrics: %w", err)
|
||||
}
|
||||
|
||||
b.tlsMtrc = mtrc
|
||||
|
||||
c := b.conf
|
||||
b.serverGroups, err = c.ServerGroups.toInternal(
|
||||
ctx,
|
||||
mtrc,
|
||||
b.messages,
|
||||
b.btdManager,
|
||||
b.tlsManager,
|
||||
b.filteringGroups,
|
||||
c.RateLimit,
|
||||
c.DNS,
|
||||
@ -699,22 +818,12 @@ func (b *builder) startBindToDevice(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// initTLS initializes the optional TLS key logging and session-ticket rotation.
|
||||
// It also adds the refresher with ID [debugIDTicketRotator] to the debug
|
||||
// refreshers.
|
||||
// initTicketRotator initializes the TLS session ticket rotator. It also adds
|
||||
// the refresher with ID [debugIDTicketRotator] to the debug refreshers.
|
||||
//
|
||||
// [builder.initServerGroups] must be called before this method.
|
||||
func (b *builder) initTLS(ctx context.Context) (err error) {
|
||||
if f := b.env.SSLKeyLogFile; f != "" {
|
||||
b.logger.WarnContext(ctx, "IMPORTANT: TLS KEY LOGGING IS ENABLED", "ssl_key_log_file", f)
|
||||
|
||||
err = enableTLSKeyLogging(b.serverGroups, f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("enabling tls key logging: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
tickRot := newTicketRotator(b.baseLogger, b.errColl, b.tlsMtrc, b.serverGroups)
|
||||
// [builder.initTLSManager] must be called before this method.
|
||||
func (b *builder) initTicketRotator(ctx context.Context) (err error) {
|
||||
tickRot := agdservice.RefresherFunc(b.tlsManager.RotateTickets)
|
||||
err = tickRot.Refresh(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("initial session ticket refresh: %w", err)
|
||||
@ -744,6 +853,7 @@ func (b *builder) initTLS(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
// initGRPCMetrics initializes the gRPC metrics if necessary.
|
||||
// [builder.initServerGroups] must be called before this method.
|
||||
func (b *builder) initGRPCMetrics(ctx context.Context) (err error) {
|
||||
switch {
|
||||
case
|
||||
@ -756,18 +866,19 @@ func (b *builder) initGRPCMetrics(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.backendGRPCMtrc, err = metrics.NewBackendPB(b.mtrcNamespace, b.promRegisterer)
|
||||
b.backendGRPCMtrc, err = metrics.NewBackendGRPC(b.mtrcNamespace, b.promRegisterer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("registering backendbp metrics: %w", err)
|
||||
return fmt.Errorf("registering backend grpc metrics: %w", err)
|
||||
}
|
||||
|
||||
b.logger.DebugContext(ctx, "initialized grpc metrics")
|
||||
b.logger.DebugContext(ctx, "initialized backend grpc metrics")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initBillStat initializes the billing-statistics recorder if necessary. It
|
||||
// also adds the refresher with ID [debugIDBillStat] to the debug refreshers.
|
||||
// [builder.initGRPCMetrics] must be called before this method.
|
||||
func (b *builder) initBillStat(ctx context.Context) (err error) {
|
||||
if !b.profilesEnabled {
|
||||
b.billStat = billstat.EmptyRecorder{}
|
||||
@ -775,7 +886,7 @@ func (b *builder) initBillStat(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
upl, err := newBillStatUploader(b.env, b.errColl, b.backendGRPCMtrc)
|
||||
upl, err := b.newBillStatUploader()
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating billstat uploader: %w", err)
|
||||
}
|
||||
@ -819,11 +930,28 @@ func (b *builder) initBillStat(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// newBillStatUploader creates and returns a billstat uploader depending on the
|
||||
// provided API URL.
|
||||
func (b *builder) newBillStatUploader() (s billstat.Uploader, err error) {
|
||||
apiURL := netutil.CloneURL(&b.env.BillStatURL.URL)
|
||||
err = urlutil.ValidateGRPCURL(apiURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("billstat api url: %w", err)
|
||||
}
|
||||
|
||||
return backendpb.NewBillStat(&backendpb.BillStatConfig{
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "billstat_uploader"),
|
||||
ErrColl: b.errColl,
|
||||
GRPCMetrics: b.backendGRPCMtrc,
|
||||
Endpoint: apiURL,
|
||||
APIKey: b.env.BillStatAPIKey,
|
||||
})
|
||||
}
|
||||
|
||||
// initProfileDB initializes the profile database if necessary.
|
||||
//
|
||||
// [builder.initGRPCMetrics] and [builder.initServerGroups] must be called
|
||||
// before this method. It also adds the refresher with ID [debugIDProfileDB] to
|
||||
// the debug refreshers.
|
||||
// [builder.initGRPCMetrics] must be called before this method. It also adds
|
||||
// the refresher with ID [debugIDProfileDB] to the debug refreshers.
|
||||
func (b *builder) initProfileDB(ctx context.Context) (err error) {
|
||||
if !b.profilesEnabled {
|
||||
b.profileDB = &profiledb.Disabled{}
|
||||
@ -837,12 +965,18 @@ func (b *builder) initProfileDB(ctx context.Context) (err error) {
|
||||
return fmt.Errorf("profile api url: %w", err)
|
||||
}
|
||||
|
||||
backendProfileDBMtrc, err := metrics.NewBackendProfileDB(b.mtrcNamespace, b.promRegisterer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("registering backend grpc profile metrics: %w", err)
|
||||
}
|
||||
|
||||
respSzEst := b.conf.RateLimit.ResponseSizeEstimate
|
||||
strg, err := backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
|
||||
BindSet: b.bindSet,
|
||||
ErrColl: b.errColl,
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "backendpb"),
|
||||
Metrics: b.backendGRPCMtrc,
|
||||
Logger: b.baseLogger.With(slogutil.KeyPrefix, "profilestorage"),
|
||||
GRPCMetrics: b.backendGRPCMtrc,
|
||||
Metrics: backendProfileDBMtrc,
|
||||
Endpoint: apiURL,
|
||||
APIKey: b.env.ProfilesAPIKey,
|
||||
ResponseSizeEstimate: respSzEst,
|
||||
@ -917,6 +1051,7 @@ func (b *builder) initDNSCheck(ctx context.Context) (err error) {
|
||||
c := b.conf.Check
|
||||
|
||||
checkConf, err := c.toInternal(
|
||||
b.baseLogger,
|
||||
b.env,
|
||||
b.messages,
|
||||
b.errColl,
|
||||
@ -1051,12 +1186,10 @@ func (b *builder) initRateLimiter(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
// initWeb initializes the web service, starts it, and registers it in the
|
||||
// signal handler.
|
||||
//
|
||||
// [builder.initServerGroups] must be called before this method.
|
||||
// signal handler. [builder.initDNSCheck] must be call before this method.
|
||||
func (b *builder) initWeb(ctx context.Context) (err error) {
|
||||
c := b.conf.Web
|
||||
webConf, err := c.toInternal(ctx, b.env, b.dnsCheck, b.errColl, b.tlsMtrc)
|
||||
webConf, err := c.toInternal(ctx, b.env, b.dnsCheck, b.errColl, b.tlsManager)
|
||||
if err != nil {
|
||||
return fmt.Errorf("converting web configuration: %w", err)
|
||||
}
|
||||
@ -1142,7 +1275,6 @@ func (b *builder) waitGeoIP(ctx context.Context) (err error) {
|
||||
// - [builder.initAccess]
|
||||
// - [builder.initBillStat]
|
||||
// - [builder.initBindToDevice]
|
||||
// - [builder.initDNSCheck]
|
||||
// - [builder.initFilterStorage]
|
||||
// - [builder.initFilteringGroups]
|
||||
// - [builder.initMsgConstructor]
|
||||
@ -1153,7 +1285,7 @@ func (b *builder) waitGeoIP(ctx context.Context) (err error) {
|
||||
// - [builder.waitGeoIP]
|
||||
func (b *builder) initDNS(ctx context.Context) (err error) {
|
||||
b.fwdHandler = forward.NewHandler(b.conf.Upstream.toInternal(b.baseLogger))
|
||||
b.dnsDB = b.conf.DNSDB.toInternal(b.errColl)
|
||||
b.dnsDB = b.conf.DNSDB.toInternal(b.baseLogger, b.errColl)
|
||||
|
||||
dnsHdlrsConf := &dnssvc.HandlersConfig{
|
||||
BaseLogger: b.baseLogger,
|
||||
|
@ -2,10 +2,12 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
|
||||
@ -17,6 +19,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/remotekv/rediskv"
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/timeutil"
|
||||
"github.com/c2h5oh/datasize"
|
||||
@ -50,14 +53,15 @@ type checkConfig struct {
|
||||
// toInternal converts c to the DNS server check configuration for the DNS
|
||||
// server. c must be valid.
|
||||
func (c *checkConfig) toInternal(
|
||||
baseLogger *slog.Logger,
|
||||
envs *environment,
|
||||
messages *dnsmsg.Constructor,
|
||||
errColl errcoll.Interface,
|
||||
namespace string,
|
||||
reg prometheus.Registerer,
|
||||
backendMtrc backendpb.Metrics,
|
||||
grpcMtrc backendpb.GRPCMetrics,
|
||||
) (conf *dnscheck.RemoteKVConfig, err error) {
|
||||
kv, err := newRemoteKV(c.RemoteKV, envs, namespace, reg, backendMtrc)
|
||||
kv, err := c.RemoteKV.newRemoteKV(envs, namespace, reg, grpcMtrc)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return nil, err
|
||||
@ -69,6 +73,7 @@ func (c *checkConfig) toInternal(
|
||||
}
|
||||
|
||||
return &dnscheck.RemoteKVConfig{
|
||||
Logger: baseLogger.With(slogutil.KeyPrefix, "dnscheck"),
|
||||
Messages: messages,
|
||||
RemoteKV: kv,
|
||||
ErrColl: errColl,
|
||||
@ -87,33 +92,42 @@ const maxRespSize = 1 * datasize.MB
|
||||
// [remotekv.KeyNamespace].
|
||||
const keyNamespaceCheck = "check"
|
||||
|
||||
// newRemoteKV returns a new properly initialized remote key-value storage.
|
||||
func newRemoteKV(
|
||||
c *remoteKVConfig,
|
||||
// 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(
|
||||
envs *environment,
|
||||
namespace string,
|
||||
reg prometheus.Registerer,
|
||||
backendMtrc backendpb.Metrics,
|
||||
grpcMtrc backendpb.GRPCMetrics,
|
||||
) (kv remotekv.Interface, err error) {
|
||||
switch c.Type {
|
||||
case kvModeBackend:
|
||||
kv, err = backendpb.NewRemoteKV(&backendpb.RemoteKVConfig{
|
||||
Metrics: backendMtrc,
|
||||
Endpoint: &envs.DNSCheckRemoteKVURL.URL,
|
||||
APIKey: envs.DNSCheckRemoteKVAPIKey,
|
||||
TTL: c.TTL.Duration,
|
||||
})
|
||||
var backendKVMtrc *metrics.BackendRemoteKV
|
||||
backendKVMtrc, err = metrics.NewBackendRemoteKV(namespace, reg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("registering backend kv metrics: %w", err)
|
||||
}
|
||||
|
||||
kv, err = c.newBackendRemoteKV(envs, backendKVMtrc, grpcMtrc)
|
||||
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.
|
||||
return remotekv.NewCache(&remotekv.CacheConfig{
|
||||
Cache: agdcache.NewLRU[string, []byte](&agdcache.LRUConfig{
|
||||
Count: envs.DNSCheckCacheKVSize,
|
||||
}),
|
||||
}), nil
|
||||
case kvModeRedis:
|
||||
var redisKVMtrc rediskv.Metrics
|
||||
var redisKVMtrc *metrics.RedisKV
|
||||
redisKVMtrc, err = metrics.NewRedisKV(namespace, reg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("registering redis kv metrics: %w", err)
|
||||
}
|
||||
|
||||
redisKV := rediskv.NewRedisKV(&rediskv.RedisKVConfig{
|
||||
kv = rediskv.NewRedisKV(&rediskv.RedisKVConfig{
|
||||
Metrics: redisKVMtrc,
|
||||
Addr: &netutil.HostPort{
|
||||
Host: envs.RedisAddr,
|
||||
@ -124,12 +138,59 @@ func newRemoteKV(
|
||||
IdleTimeout: envs.RedisIdleTimeout.Duration,
|
||||
TTL: c.TTL.Duration,
|
||||
})
|
||||
|
||||
kv = remotekv.NewKeyNamespace(&remotekv.KeyNamespaceConfig{
|
||||
KV: redisKV,
|
||||
Prefix: fmt.Sprintf("%s:%s:", envs.RedisKeyPrefix, keyNamespaceCheck),
|
||||
})
|
||||
case kvModeConsul:
|
||||
kv, err = c.newConsulRemoteKV(envs)
|
||||
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))
|
||||
}
|
||||
|
||||
return remotekv.NewKeyNamespace(&remotekv.KeyNamespaceConfig{
|
||||
KV: kv,
|
||||
Prefix: newRemoveKVPrefix(envs, c.Type),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// newBackendRemoteKV returns a new properly initialized backend remote
|
||||
// key-value storage. c must be valid.
|
||||
//
|
||||
// TODO(e.burkov): Add key namespace.
|
||||
func (c *remoteKVConfig) newBackendRemoteKV(
|
||||
envs *environment,
|
||||
backendKVMtrc *metrics.BackendRemoteKV,
|
||||
grpcMtrc backendpb.GRPCMetrics,
|
||||
) (kv *backendpb.RemoteKV, err error) {
|
||||
kv, err = backendpb.NewRemoteKV(&backendpb.RemoteKVConfig{
|
||||
GRPCMetrics: grpcMtrc,
|
||||
Metrics: backendKVMtrc,
|
||||
Endpoint: &envs.DNSCheckRemoteKVURL.URL,
|
||||
APIKey: envs.DNSCheckRemoteKVAPIKey,
|
||||
TTL: c.TTL.Duration,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing backend dnscheck kv: %w", err)
|
||||
}
|
||||
|
||||
return kv, nil
|
||||
}
|
||||
|
||||
// newRemoveKVPrefix returns a remote KV custom prefix for the keys.
|
||||
func newRemoveKVPrefix(envs *environment, kvType string) (pref string) {
|
||||
switch kvType {
|
||||
case kvModeBackend, kvModeCache, kvModeConsul:
|
||||
return fmt.Sprintf("%s:%s:", kvType, keyNamespaceCheck)
|
||||
case kvModeRedis:
|
||||
return fmt.Sprintf("%s:%s:", envs.RedisKeyPrefix, keyNamespaceCheck)
|
||||
default:
|
||||
panic(fmt.Errorf("dnscheck kv type: %w: %q", errors.ErrBadEnumValue, kvType))
|
||||
}
|
||||
}
|
||||
|
||||
// newConsulRemoteKV returns a new properly initialized Consul-based remote
|
||||
// key-value storage. c must be valid.
|
||||
func (c *remoteKVConfig) newConsulRemoteKV(envs *environment) (kv remotekv.Interface, err error) {
|
||||
consulKVURL := envs.ConsulDNSCheckKVURL
|
||||
consulSessionURL := envs.ConsulDNSCheckSessionURL
|
||||
if consulKVURL == nil || consulSessionURL == nil {
|
||||
@ -151,9 +212,6 @@ func newRemoteKV(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing consul dnscheck kv: %w", err)
|
||||
}
|
||||
default:
|
||||
return remotekv.Empty{}, nil
|
||||
}
|
||||
|
||||
return kv, nil
|
||||
}
|
||||
@ -238,6 +296,7 @@ func validateNonNilIPs(ips []netip.Addr, fam netutil.AddrFamily) (err error) {
|
||||
// DNSCheck key-value database modes.
|
||||
const (
|
||||
kvModeBackend = "backend"
|
||||
kvModeCache = "cache"
|
||||
kvModeConsul = "consul"
|
||||
kvModeRedis = "redis"
|
||||
)
|
||||
@ -246,7 +305,7 @@ const (
|
||||
// checking.
|
||||
type remoteKVConfig struct {
|
||||
// Type defines the type of remote key-value store. Allowed values are
|
||||
// [kvModeBackend], [kvModeConsul] and [kvModeRedis].
|
||||
// [kvModeBackend], [kvModeCache], [kvModeConsul] and [kvModeRedis].
|
||||
Type string `yaml:"type"`
|
||||
|
||||
// TTL defines, for how long to keep the information about a single client.
|
||||
@ -269,6 +328,8 @@ func (c *remoteKVConfig) validate() (err error) {
|
||||
if ttl.Duration <= 0 {
|
||||
return newNotPositiveError("ttl", ttl)
|
||||
}
|
||||
case kvModeCache:
|
||||
// Go on.
|
||||
case kvModeConsul:
|
||||
if ttl.Duration < consulkv.MinTTL || ttl.Duration > consulkv.MaxTTL {
|
||||
return fmt.Errorf(
|
||||
@ -288,8 +349,6 @@ func (c *remoteKVConfig) validate() (err error) {
|
||||
ttl,
|
||||
)
|
||||
}
|
||||
case "":
|
||||
return fmt.Errorf("type: %w", errors.ErrEmptyValue)
|
||||
default:
|
||||
return fmt.Errorf("type: %w: %q", errors.ErrBadEnumValue, c.Type)
|
||||
}
|
||||
|
@ -94,11 +94,13 @@ func Main(plugins *plugin.Registry) {
|
||||
|
||||
errors.Check(b.initMsgConstructor(ctx))
|
||||
|
||||
errors.Check(b.initTLSManager(ctx))
|
||||
|
||||
errors.Check(b.initServerGroups(ctx))
|
||||
|
||||
errors.Check(b.startBindToDevice(ctx))
|
||||
|
||||
errors.Check(b.initTLS(ctx))
|
||||
errors.Check(b.initTicketRotator(ctx))
|
||||
|
||||
errors.Check(b.initGRPCMetrics(ctx))
|
||||
|
||||
|
@ -48,8 +48,8 @@ func connectivityCheck(srvGrps []*agd.ServerGroup, connCheck *connCheckConfig) (
|
||||
}
|
||||
|
||||
defer func() {
|
||||
errClose := errors.Annotate(conn4.Close(), "connectivity check: closing ipv4: %w")
|
||||
err = errors.WithDeferred(err, errClose)
|
||||
closeErr := errors.Annotate(conn4.Close(), "connectivity check: closing ipv4: %w")
|
||||
err = errors.WithDeferred(err, closeErr)
|
||||
}()
|
||||
|
||||
if !requireIPv6ConnCheck(srvGrps) {
|
||||
@ -69,8 +69,8 @@ func connectivityCheck(srvGrps []*agd.ServerGroup, connCheck *connCheckConfig) (
|
||||
}
|
||||
|
||||
defer func() {
|
||||
errClose := errors.Annotate(conn6.Close(), "connectivity check: closing ipv6: %w")
|
||||
err = errors.WithDeferred(err, errClose)
|
||||
closeErr := errors.Annotate(conn6.Close(), "connectivity check: closing ipv6: %w")
|
||||
err = errors.WithDeferred(err, closeErr)
|
||||
}()
|
||||
|
||||
return nil
|
||||
|
@ -1,9 +1,12 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
)
|
||||
|
||||
// dnsDBConfig is the configuration of the DNSDB module.
|
||||
@ -34,12 +37,16 @@ func (c *dnsDBConfig) validate() (err error) {
|
||||
|
||||
// toInternal builds and returns an anonymous statistics collector. c must be
|
||||
// valid.
|
||||
func (c *dnsDBConfig) toInternal(errColl errcoll.Interface) (d dnsdb.Interface) {
|
||||
func (c *dnsDBConfig) toInternal(
|
||||
baseLogger *slog.Logger,
|
||||
errColl errcoll.Interface,
|
||||
) (d dnsdb.Interface) {
|
||||
if !c.Enabled {
|
||||
return dnsdb.Empty{}
|
||||
}
|
||||
|
||||
db := dnsdb.New(&dnsdb.DefaultConfig{
|
||||
Logger: baseLogger.With(slogutil.KeyPrefix, "dnsdb"),
|
||||
ErrColl: errColl,
|
||||
MaxSize: c.MaxSize,
|
||||
})
|
||||
|
@ -68,6 +68,8 @@ type environment struct {
|
||||
|
||||
RedisIdleTimeout timeutil.Duration `env:"REDIS_IDLE_TIMEOUT" envDefault:"30s"`
|
||||
|
||||
// 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"`
|
||||
|
||||
@ -233,10 +235,12 @@ func (envs *environment) validateFromValidConfig(conf *configuration) (err error
|
||||
var errs []error
|
||||
|
||||
switch typ := conf.Check.RemoteKV.Type; typ {
|
||||
case kvModeRedis:
|
||||
errs = envs.validateRedis(errs)
|
||||
case kvModeBackend:
|
||||
errs = envs.validateBackendKV(errs)
|
||||
case kvModeCache:
|
||||
errs = envs.validateCache(errs)
|
||||
case kvModeRedis:
|
||||
errs = envs.validateRedis(errs)
|
||||
default:
|
||||
// Probably consul.
|
||||
}
|
||||
@ -259,38 +263,51 @@ func (envs *environment) validateFromValidConfig(conf *configuration) (err error
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
// validateCache appends validation errors to the given errs if environment
|
||||
// variables for KV Cache contain errors.
|
||||
func (envs *environment) validateCache(errs []error) (res []error) {
|
||||
res = errs
|
||||
|
||||
if envs.DNSCheckCacheKVSize <= 0 {
|
||||
err := newNotPositiveError("DNSCHECK_CACHE_KV_SIZE", envs.DNSCheckCacheKVSize)
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// validateRedis appends validation errors to the given errs if environment
|
||||
// variables for Redis contain errors.
|
||||
func (envs *environment) validateRedis(errs []error) (withRedis []error) {
|
||||
withRedis = errs
|
||||
func (envs *environment) validateRedis(errs []error) (res []error) {
|
||||
res = errs
|
||||
|
||||
if envs.RedisAddr == "" {
|
||||
err := fmt.Errorf("REDIS_ADDR: %q", errors.ErrEmptyValue)
|
||||
withRedis = append(withRedis, err)
|
||||
err := fmt.Errorf("REDIS_ADDR: %w", errors.ErrEmptyValue)
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if envs.RedisIdleTimeout.Duration <= 0 {
|
||||
err := newNotPositiveError("REDIS_IDLE_TIMEOUT", envs.RedisIdleTimeout)
|
||||
withRedis = append(withRedis, err)
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if envs.RedisMaxActive < 0 {
|
||||
err := newNegativeError("REDIS_MAX_ACTIVE", envs.RedisMaxActive)
|
||||
withRedis = append(withRedis, err)
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if envs.RedisMaxIdle < 0 {
|
||||
err := newNegativeError("REDIS_MAX_IDLE", envs.RedisMaxIdle)
|
||||
withRedis = append(withRedis, err)
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
return withRedis
|
||||
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) (withKV []error) {
|
||||
withKV = errs
|
||||
func (envs *environment) validateBackendKV(errs []error) (res []error) {
|
||||
res = errs
|
||||
|
||||
var u *url.URL
|
||||
if envs.DNSCheckRemoteKVURL != nil {
|
||||
@ -299,16 +316,16 @@ func (envs *environment) validateBackendKV(errs []error) (withKV []error) {
|
||||
|
||||
err := urlutil.ValidateGRPCURL(u)
|
||||
if err != nil {
|
||||
withKV = append(withKV, fmt.Errorf("env DNSCHECK_REMOTEKV_URL: %w", err))
|
||||
res = append(res, fmt.Errorf("env DNSCHECK_REMOTEKV_URL: %w", err))
|
||||
}
|
||||
|
||||
return withKV
|
||||
return res
|
||||
}
|
||||
|
||||
// validateProfilesURLs appends validation errors to the given errs if profiles
|
||||
// URLs in environment variables are invalid.
|
||||
func (envs *environment) validateProfilesURLs(errs []error) (withURLs []error) {
|
||||
withURLs = errs
|
||||
func (envs *environment) validateProfilesURLs(errs []error) (res []error) {
|
||||
res = errs
|
||||
|
||||
grpcOnlyURLs := []*urlEnvData{{
|
||||
url: envs.BillStatURL,
|
||||
@ -332,11 +349,11 @@ func (envs *environment) validateProfilesURLs(errs []error) (withURLs []error) {
|
||||
|
||||
err := urlutil.ValidateGRPCURL(u)
|
||||
if err != nil {
|
||||
withURLs = append(withURLs, fmt.Errorf("env %s: %w", urlData.name, err))
|
||||
res = append(res, fmt.Errorf("env %s: %w", urlData.name, err))
|
||||
}
|
||||
}
|
||||
|
||||
return withURLs
|
||||
return res
|
||||
}
|
||||
|
||||
// validateRateLimitURLs appends validation errors to the given errs if rate
|
||||
|
@ -2,16 +2,8 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/timeutil"
|
||||
"github.com/c2h5oh/datasize"
|
||||
)
|
||||
@ -27,9 +19,13 @@ type filtersConfig struct {
|
||||
|
||||
// CustomFilterCacheSize is the size of the LRU cache of compiled filtering
|
||||
// engines for profiles with custom filtering rules.
|
||||
//
|
||||
// TODO(a.garipov): Rename to "custom_filter_cache_count"?
|
||||
CustomFilterCacheSize int `yaml:"custom_filter_cache_size"`
|
||||
|
||||
// SafeSearchCacheSize is the size of the LRU cache of safe-search results.
|
||||
//
|
||||
// TODO(a.garipov): Rename to "safe_search_cache_count"?
|
||||
SafeSearchCacheSize int `yaml:"safe_search_cache_size"`
|
||||
|
||||
// ResponseTTL is the TTL to set for DNS responses to requests for filtered
|
||||
@ -66,58 +62,6 @@ type filtersConfig struct {
|
||||
SDEEnabled bool `yaml:"sde_enabled"`
|
||||
}
|
||||
|
||||
// toInternal converts c to the filter storage configuration for the DNS server.
|
||||
// cacheDir must exist. c must be valid.
|
||||
func (c *filtersConfig) toInternal(
|
||||
logger *slog.Logger,
|
||||
errColl errcoll.Interface,
|
||||
cacheManager agdcache.Manager,
|
||||
envs *environment,
|
||||
safeBrowsing *hashprefix.Filter,
|
||||
adultBlocking *hashprefix.Filter,
|
||||
newRegDomains *hashprefix.Filter,
|
||||
) (conf *filter.DefaultStorageConfig) {
|
||||
var blockedServiceIndexURL *url.URL
|
||||
if envs.BlockedServiceEnabled {
|
||||
blockedServiceIndexURL = netutil.CloneURL(&envs.BlockedServiceIndexURL.URL)
|
||||
}
|
||||
|
||||
var generalSafeSearchRulesURL *url.URL
|
||||
if envs.GeneralSafeSearchEnabled {
|
||||
generalSafeSearchRulesURL = netutil.CloneURL(&envs.GeneralSafeSearchURL.URL)
|
||||
}
|
||||
|
||||
var youtubeSafeSearchRulesURL *url.URL
|
||||
if envs.YoutubeSafeSearchEnabled {
|
||||
youtubeSafeSearchRulesURL = netutil.CloneURL(&envs.YoutubeSafeSearchURL.URL)
|
||||
}
|
||||
|
||||
return &filter.DefaultStorageConfig{
|
||||
BaseLogger: logger,
|
||||
FilterIndexURL: netutil.CloneURL(&envs.FilterIndexURL.URL),
|
||||
BlockedServiceIndexURL: blockedServiceIndexURL,
|
||||
GeneralSafeSearchRulesURL: generalSafeSearchRulesURL,
|
||||
YoutubeSafeSearchRulesURL: youtubeSafeSearchRulesURL,
|
||||
SafeBrowsing: safeBrowsing,
|
||||
AdultBlocking: adultBlocking,
|
||||
NewRegDomains: newRegDomains,
|
||||
Now: time.Now,
|
||||
ErrColl: errColl,
|
||||
CacheManager: cacheManager,
|
||||
CacheDir: envs.FilterCachePath,
|
||||
CustomFilterCacheSize: c.CustomFilterCacheSize,
|
||||
SafeSearchCacheSize: c.SafeSearchCacheSize,
|
||||
// TODO(a.garipov): Consider making this configurable.
|
||||
SafeSearchCacheTTL: 1 * time.Hour,
|
||||
RuleListCacheSize: c.RuleListCache.Size,
|
||||
RefreshIvl: c.RefreshIvl.Duration,
|
||||
IndexRefreshTimeout: c.IndexRefreshTimeout.Duration,
|
||||
RuleListRefreshTimeout: c.RuleListRefreshTimeout.Duration,
|
||||
UseRuleListCache: c.RuleListCache.Enabled,
|
||||
MaxRuleListSize: c.MaxSize,
|
||||
}
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ validator = (*filtersConfig)(nil)
|
||||
|
||||
@ -153,6 +97,8 @@ func (c *filtersConfig) validate() (err error) {
|
||||
// fltRuleListCache contains filtering rule-list cache configuration.
|
||||
type fltRuleListCache struct {
|
||||
// Size defines the size of the LRU cache of rule-list filtering results.
|
||||
//
|
||||
// TODO(a.garipov): Rename to "count"?
|
||||
Size int `yaml:"size"`
|
||||
|
||||
// Enabled shows if the rule-list cache is enabled. If it is false, the
|
||||
|
@ -24,13 +24,17 @@ type filteringGroup struct {
|
||||
// ID is a filtering group ID. Must be unique.
|
||||
ID string `yaml:"id"`
|
||||
|
||||
// BlockPrivateRelay shows if Apple Private Relay queries are blocked for
|
||||
// requests using this filtering group.
|
||||
BlockPrivateRelay bool `yaml:"block_private_relay"`
|
||||
// BlockChromePrefetch shows if the Chrome prefetch proxy feature should be
|
||||
// disabled for requests using this filtering group.
|
||||
BlockChromePrefetch bool `yaml:"block_chrome_prefetch"`
|
||||
|
||||
// BlockFirefoxCanary shows if Firefox canary domain is blocked for
|
||||
// requests using this filtering group.
|
||||
BlockFirefoxCanary bool `yaml:"block_firefox_canary"`
|
||||
|
||||
// BlockPrivateRelay shows if Apple Private Relay queries are blocked for
|
||||
// requests using this filtering group.
|
||||
BlockPrivateRelay bool `yaml:"block_private_relay"`
|
||||
}
|
||||
|
||||
// fltGrpRuleLists contains filter rule lists configuration for a filtering
|
||||
@ -44,6 +48,15 @@ type fltGrpRuleLists struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
}
|
||||
|
||||
// toInternal converts c to the rule-list configuration for the filtering group.
|
||||
// c must be valid.
|
||||
func (c *fltGrpRuleLists) toInternal(ids []filter.ID) (fltConf *filter.ConfigRuleList) {
|
||||
return &filter.ConfigRuleList{
|
||||
IDs: ids,
|
||||
Enabled: c.Enabled,
|
||||
}
|
||||
}
|
||||
|
||||
// fltGrpParental contains parental protection configuration for a filtering
|
||||
// group.
|
||||
type fltGrpParental struct {
|
||||
@ -64,6 +77,19 @@ type fltGrpParental struct {
|
||||
YoutubeSafeSearch bool `yaml:"youtube_safe_search"`
|
||||
}
|
||||
|
||||
// toInternal converts c to the parental-control configuration for the filtering
|
||||
// group. c must be valid.
|
||||
func (c *fltGrpParental) toInternal() (fltConf *filter.ConfigParental) {
|
||||
return &filter.ConfigParental{
|
||||
PauseSchedule: nil,
|
||||
BlockedServices: nil,
|
||||
Enabled: c.Enabled,
|
||||
AdultBlockingEnabled: c.BlockAdult,
|
||||
SafeSearchGeneralEnabled: c.GeneralSafeSearch,
|
||||
SafeSearchYouTubeEnabled: c.YoutubeSafeSearch,
|
||||
}
|
||||
}
|
||||
|
||||
// fltGrpSafeBrowsing contains general safe browsing configuration for
|
||||
// a filtering group.
|
||||
type fltGrpSafeBrowsing struct {
|
||||
@ -79,6 +105,16 @@ type fltGrpSafeBrowsing struct {
|
||||
BlockNewlyRegisteredDomains bool `yaml:"block_newly_registered_domains"`
|
||||
}
|
||||
|
||||
// toInternal converts c to the safe-browsing configuration for the filtering
|
||||
// group. c must be valid.
|
||||
func (c *fltGrpSafeBrowsing) toInternal() (fltConf *filter.ConfigSafeBrowsing) {
|
||||
return &filter.ConfigSafeBrowsing{
|
||||
Enabled: c.Enabled,
|
||||
DangerousDomainsEnabled: c.BlockDangerousDomains,
|
||||
NewlyRegisteredDomainsEnabled: c.BlockNewlyRegisteredDomains,
|
||||
}
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ validator = (*filteringGroup)(nil)
|
||||
|
||||
@ -87,21 +123,23 @@ func (g *filteringGroup) validate() (err error) {
|
||||
switch {
|
||||
case g == nil:
|
||||
return errors.ErrNoValue
|
||||
case g.RuleLists == nil:
|
||||
return fmt.Errorf("rule_lists: %w", errors.ErrNoValue)
|
||||
case g.ID == "":
|
||||
return fmt.Errorf("id: %w", errors.ErrEmptyValue)
|
||||
case g.Parental == nil:
|
||||
return fmt.Errorf("parental: %w", errors.ErrNoValue)
|
||||
case g.RuleLists == nil:
|
||||
return fmt.Errorf("rule_lists: %w", errors.ErrNoValue)
|
||||
case g.SafeBrowsing == nil:
|
||||
return fmt.Errorf("safe_browsing: %w", errors.ErrNoValue)
|
||||
case g.ID == "":
|
||||
return fmt.Errorf("id: %w", errors.ErrEmptyValue)
|
||||
}
|
||||
|
||||
fltIDs := container.NewMapSet[string]()
|
||||
for i, fltID := range g.RuleLists.IDs {
|
||||
if fltIDs.Has(fltID) {
|
||||
return fmt.Errorf("rule_lists: at index %d: duplicate id %q", i, fltID)
|
||||
return fmt.Errorf("rule_lists: at index %d: id: %w: %q", i, errors.ErrDuplicated, fltID)
|
||||
}
|
||||
|
||||
_, err = agd.NewFilterListID(fltID)
|
||||
_, err = filter.NewID(fltID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("rule_lists: at index %d: %w", i, err)
|
||||
}
|
||||
@ -123,32 +161,29 @@ func (groups filteringGroups) toInternal(
|
||||
) (fltGrps map[agd.FilteringGroupID]*agd.FilteringGroup, err error) {
|
||||
fltGrps = make(map[agd.FilteringGroupID]*agd.FilteringGroup, len(groups))
|
||||
for _, g := range groups {
|
||||
filterIDs := make([]agd.FilterListID, len(g.RuleLists.IDs))
|
||||
filterIDs := make([]filter.ID, len(g.RuleLists.IDs))
|
||||
for i, fltID := range g.RuleLists.IDs {
|
||||
// Assume that these have already been validated in
|
||||
// [filteringGroup.validate].
|
||||
id := agd.FilterListID(fltID)
|
||||
id := filter.ID(fltID)
|
||||
if !s.HasListID(id) {
|
||||
return nil, fmt.Errorf("filter list id %q is not in the index", id)
|
||||
}
|
||||
|
||||
filterIDs[i] = agd.FilterListID(fltID)
|
||||
filterIDs[i] = filter.ID(fltID)
|
||||
}
|
||||
|
||||
id := agd.FilteringGroupID(g.ID)
|
||||
fltGrps[id] = &agd.FilteringGroup{
|
||||
FilterConfig: &filter.ConfigGroup{
|
||||
Parental: g.Parental.toInternal(),
|
||||
RuleList: g.RuleLists.toInternal(filterIDs),
|
||||
SafeBrowsing: g.SafeBrowsing.toInternal(),
|
||||
},
|
||||
ID: id,
|
||||
RuleListsEnabled: g.RuleLists.Enabled,
|
||||
RuleListIDs: filterIDs,
|
||||
ParentalEnabled: g.Parental.Enabled,
|
||||
BlockAdult: g.Parental.BlockAdult,
|
||||
SafeBrowsingEnabled: g.SafeBrowsing.Enabled,
|
||||
BlockDangerousDomains: g.SafeBrowsing.BlockDangerousDomains,
|
||||
BlockNewlyRegisteredDomains: g.SafeBrowsing.BlockNewlyRegisteredDomains,
|
||||
GeneralSafeSearch: g.Parental.GeneralSafeSearch,
|
||||
YoutubeSafeSearch: g.Parental.YoutubeSafeSearch,
|
||||
BlockPrivateRelay: g.BlockPrivateRelay,
|
||||
BlockChromePrefetch: g.BlockChromePrefetch,
|
||||
BlockFirefoxCanary: g.BlockFirefoxCanary,
|
||||
BlockPrivateRelay: g.BlockPrivateRelay,
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,7 +207,7 @@ func (groups filteringGroups) validate() (err error) {
|
||||
}
|
||||
|
||||
if ids.Has(string(g.ID)) {
|
||||
return fmt.Errorf("at index %d: duplicate id %q", i, g.ID)
|
||||
return fmt.Errorf("at index %d: id: %w: %q", i, errors.ErrDuplicated, g.ID)
|
||||
}
|
||||
|
||||
ids.Add(g.ID)
|
||||
|
@ -8,9 +8,13 @@ import (
|
||||
// geoIPConfig is the GeoIP database configuration.
|
||||
type geoIPConfig struct {
|
||||
// HostCacheSize is the size of the hostname lookup cache, in entries.
|
||||
//
|
||||
// TODO(a.garipov): Rename to "host_cache_count"?
|
||||
HostCacheSize int `yaml:"host_cache_size"`
|
||||
|
||||
// IPCacheSize is the size of the IP lookup cache, in entries.
|
||||
//
|
||||
// TODO(a.garipov): Rename to "ip_cache_count"?
|
||||
IPCacheSize int `yaml:"ip_cache_size"`
|
||||
|
||||
// RefreshIvl defines how often AdGuard DNS reopens the GeoIP database
|
||||
|
@ -1,11 +1,14 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"slices"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/bindtodevice"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
@ -14,11 +17,11 @@ import (
|
||||
// toInternal returns the configuration of DNS servers for a single server
|
||||
// group. srvs and other parts of the configuration must be valid.
|
||||
func (srvs servers) toInternal(
|
||||
mtrc tlsconfig.Metrics,
|
||||
tlsConfig *agd.TLS,
|
||||
btdMgr *bindtodevice.Manager,
|
||||
tlsMgr tlsconfig.Manager,
|
||||
ratelimitConf *rateLimitConfig,
|
||||
dnsConf *dnsConfig,
|
||||
deviceDomains []string,
|
||||
) (dnsSrvs []*agd.Server, err error) {
|
||||
dnsSrvs = make([]*agd.Server, 0, len(srvs))
|
||||
for _, srv := range srvs {
|
||||
@ -66,18 +69,7 @@ func (srvs servers) toInternal(
|
||||
QUICLimitsEnabled: ratelimitConf.QUIC.Enabled,
|
||||
}
|
||||
|
||||
tlsConf := tlsConfig.Conf.Clone()
|
||||
|
||||
// Attach the functions that will count TLS handshake metrics.
|
||||
tlsConf.GetConfigForClient = mtrc.BeforeHandshake(string(srv.Protocol))
|
||||
tlsConf.VerifyConnection = mtrc.AfterHandshake(
|
||||
string(srv.Protocol),
|
||||
srv.Name,
|
||||
tlsConfig.DeviceDomains,
|
||||
tlsConf.Certificates,
|
||||
)
|
||||
|
||||
dnsSrv.TLS = tlsConf
|
||||
dnsSrv.TLS = newTLSConfig(dnsSrv, tlsMgr, deviceDomains, srv)
|
||||
}
|
||||
|
||||
dnsSrv.SetBindData(bindData)
|
||||
@ -88,6 +80,35 @@ func (srvs servers) toInternal(
|
||||
return dnsSrvs, nil
|
||||
}
|
||||
|
||||
// newTLSConfig returns the TLS configuration with metrics and ALPs set.
|
||||
//
|
||||
// TODO(s.chzhen): Consider moving to agd package as soon as the import cycle
|
||||
// is resolved.
|
||||
func newTLSConfig(
|
||||
dnsSrv *agd.Server,
|
||||
tlsMgr tlsconfig.Manager,
|
||||
deviceDomains []string,
|
||||
srv *server,
|
||||
) (c *agd.TLSConfig) {
|
||||
tlsConf := tlsMgr.CloneWithMetrics(string(srv.Protocol), srv.Name, deviceDomains)
|
||||
|
||||
var tlsConfH3 *tls.Config
|
||||
switch dnsSrv.Protocol {
|
||||
case agd.ProtoDoH:
|
||||
tlsConfH3 = tlsMgr.CloneWithMetrics(string(srv.Protocol), srv.Name, deviceDomains)
|
||||
|
||||
tlsConf.NextProtos = slices.Clone(dnsserver.NextProtoDoH)
|
||||
tlsConfH3.NextProtos = slices.Clone(dnsserver.NextProtoDoH3)
|
||||
case agd.ProtoDoQ:
|
||||
tlsConf.NextProtos = slices.Clone(dnsserver.NextProtoDoQ)
|
||||
}
|
||||
|
||||
return &agd.TLSConfig{
|
||||
Default: tlsConf,
|
||||
H3: tlsConfH3,
|
||||
}
|
||||
}
|
||||
|
||||
// servers is a slice of server settings. A valid instance of servers has no
|
||||
// nil items.
|
||||
type servers []*server
|
||||
@ -110,7 +131,7 @@ func (srvs servers) validate() (needsTLS bool, err error) {
|
||||
}
|
||||
|
||||
if names.Has(s.Name) {
|
||||
return false, fmt.Errorf("at index %d: duplicate name %q", i, s.Name)
|
||||
return false, fmt.Errorf("at index %d: name: %w: %q", i, errors.ErrDuplicated, s.Name)
|
||||
}
|
||||
|
||||
names.Add(s.Name)
|
||||
@ -337,11 +358,11 @@ func (c *serverBindInterface) validate() (err error) {
|
||||
set := container.NewMapSet[netip.Prefix]()
|
||||
for i, subnet := range c.Subnets {
|
||||
if !subnet.IsValid() {
|
||||
return fmt.Errorf("bad subnet at index %d", i)
|
||||
return fmt.Errorf("subnets: at index %d: bad subnet", i)
|
||||
}
|
||||
|
||||
if set.Has(subnet) {
|
||||
return fmt.Errorf("duplicate subnet %s at index %d", subnet, i)
|
||||
return fmt.Errorf("subnets: at index %d: %w: %s", i, errors.ErrDuplicated, subnet)
|
||||
}
|
||||
|
||||
set.Add(subnet)
|
||||
|
@ -20,9 +20,9 @@ type serverGroups []*serverGroup
|
||||
// service. srvGrps and other parts of the configuration must be valid.
|
||||
func (srvGrps serverGroups) toInternal(
|
||||
ctx context.Context,
|
||||
mtrc tlsconfig.Metrics,
|
||||
messages *dnsmsg.Constructor,
|
||||
btdMgr *bindtodevice.Manager,
|
||||
tlsMgr tlsconfig.Manager,
|
||||
fltGrps map[agd.FilteringGroupID]*agd.FilteringGroup,
|
||||
ratelimitConf *rateLimitConfig,
|
||||
dnsConf *dnsConfig,
|
||||
@ -35,26 +35,26 @@ func (srvGrps serverGroups) toInternal(
|
||||
return nil, fmt.Errorf("server group %q: unknown filtering group %q", g.Name, fltGrpID)
|
||||
}
|
||||
|
||||
var tlsConf *agd.TLS
|
||||
tlsConf, err = g.TLS.toInternal(ctx, mtrc)
|
||||
var deviceDomains []string
|
||||
deviceDomains, err = g.TLS.toInternal(ctx, tlsMgr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tls: %w", err)
|
||||
return nil, fmt.Errorf("tls %q: %w", g.Name, err)
|
||||
}
|
||||
|
||||
svcSrvGrps[i] = &agd.ServerGroup{
|
||||
DDR: g.DDR.toInternal(messages),
|
||||
TLS: tlsConf,
|
||||
DeviceDomains: deviceDomains,
|
||||
Name: agd.ServerGroupName(g.Name),
|
||||
FilteringGroup: fltGrpID,
|
||||
ProfilesEnabled: g.ProfilesEnabled,
|
||||
}
|
||||
|
||||
svcSrvGrps[i].Servers, err = g.Servers.toInternal(
|
||||
mtrc,
|
||||
tlsConf,
|
||||
btdMgr,
|
||||
tlsMgr,
|
||||
ratelimitConf,
|
||||
dnsConf,
|
||||
deviceDomains,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("server group %q: %w", g.Name, err)
|
||||
@ -81,7 +81,7 @@ func (srvGrps serverGroups) validate() (err error) {
|
||||
}
|
||||
|
||||
if names.Has(g.Name) {
|
||||
return fmt.Errorf("at index %d: duplicate name %q", i, g.Name)
|
||||
return fmt.Errorf("at index %d: name: %w: %q", i, errors.ErrDuplicated, g.Name)
|
||||
}
|
||||
|
||||
names.Add(g.Name)
|
||||
@ -148,3 +148,16 @@ func (g *serverGroup) validate() (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// collectSessTicketPaths returns the list of unique session ticket file paths
|
||||
// for all server groups.
|
||||
func (srvGrps serverGroups) collectSessTicketPaths() (paths []string) {
|
||||
set := container.NewSortedSliceSet[string]()
|
||||
for _, g := range srvGrps {
|
||||
for _, k := range g.TLS.SessionKeys {
|
||||
set.Add(k)
|
||||
}
|
||||
}
|
||||
|
||||
return set.Values()
|
||||
}
|
||||
|
@ -1,121 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
)
|
||||
|
||||
// ticketRotator is a refresh worker that rereads and resets TLS session
|
||||
// tickets. It should be initially refreshed before use.
|
||||
type ticketRotator struct {
|
||||
logger *slog.Logger
|
||||
errColl errcoll.Interface
|
||||
mtrc tlsconfig.Metrics
|
||||
confs map[*tls.Config][]string
|
||||
}
|
||||
|
||||
// newTicketRotator creates a new TLS session ticket rotator that rotates
|
||||
// tickets for the TLS configurations of all servers in grps.
|
||||
//
|
||||
// grps must be valid.
|
||||
func newTicketRotator(
|
||||
logger *slog.Logger,
|
||||
errColl errcoll.Interface,
|
||||
mtrc tlsconfig.Metrics,
|
||||
grps []*agd.ServerGroup,
|
||||
) (tr *ticketRotator) {
|
||||
confs := map[*tls.Config][]string{}
|
||||
|
||||
for _, g := range grps {
|
||||
t := g.TLS
|
||||
if t == nil || len(t.SessionKeys) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, srv := range g.Servers {
|
||||
if srv.TLS != nil {
|
||||
confs[srv.TLS] = t.SessionKeys
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &ticketRotator{
|
||||
logger: logger.With(slogutil.KeyPrefix, "tickrot"),
|
||||
errColl: errColl,
|
||||
mtrc: mtrc,
|
||||
confs: confs,
|
||||
}
|
||||
}
|
||||
|
||||
// sessTickLen is the length of a single TLS session ticket key in bytes.
|
||||
//
|
||||
// NOTE: Unlike Nginx, Go's crypto/tls doesn't use the random bytes from the
|
||||
// session ticket keys as-is, but instead hashes these bytes and uses the first
|
||||
// 48 bytes of the hashed data as the key name, the AES key, and the HMAC key.
|
||||
const sessTickLen = 32
|
||||
|
||||
// type check
|
||||
var _ agdservice.Refresher = (*ticketRotator)(nil)
|
||||
|
||||
// Refresh implements the [agdservice.Refresher] interface for *ticketRotator.
|
||||
func (r *ticketRotator) Refresh(ctx context.Context) (err error) {
|
||||
r.logger.DebugContext(ctx, "refresh started")
|
||||
defer r.logger.DebugContext(ctx, "refresh finished")
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
errcoll.Collect(ctx, r.errColl, r.logger, "ticket rotation failed", err)
|
||||
}
|
||||
}()
|
||||
|
||||
for conf, files := range r.confs {
|
||||
keys := make([][sessTickLen]byte, 0, len(files))
|
||||
|
||||
for _, fileName := range files {
|
||||
var key [sessTickLen]byte
|
||||
key, err = readSessionTicketKey(fileName)
|
||||
if err != nil {
|
||||
r.mtrc.SetSessionTicketRotationStatus(ctx, false)
|
||||
|
||||
return fmt.Errorf("session ticket for srv %s: %w", conf.ServerName, err)
|
||||
}
|
||||
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
if len(keys) == 0 {
|
||||
return fmt.Errorf("no session tickets for srv %s in %q", conf.ServerName, files)
|
||||
}
|
||||
|
||||
conf.SetSessionTicketKeys(keys)
|
||||
}
|
||||
|
||||
r.mtrc.SetSessionTicketRotationStatus(ctx, true)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// readSessionTicketKey reads a single TLS session ticket key from a file.
|
||||
func readSessionTicketKey(fn string) (key [sessTickLen]byte, err error) {
|
||||
// #nosec G304 -- Trust the file paths that are given to us in the
|
||||
// configuration file.
|
||||
b, err := os.ReadFile(fn)
|
||||
if err != nil {
|
||||
return key, fmt.Errorf("reading session ticket: %w", err)
|
||||
}
|
||||
|
||||
if len(b) < sessTickLen {
|
||||
return key, fmt.Errorf("session ticket in %s: bad len %d, want %d", fn, len(b), sessTickLen)
|
||||
}
|
||||
|
||||
return [sessTickLen]byte(b), nil
|
||||
}
|
@ -3,13 +3,9 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/tlsconfig"
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
@ -39,27 +35,22 @@ type tlsConfig struct {
|
||||
// valid.
|
||||
func (c *tlsConfig) toInternal(
|
||||
ctx context.Context,
|
||||
mtrc tlsconfig.Metrics,
|
||||
) (conf *agd.TLS, err error) {
|
||||
tlsMgr tlsconfig.Manager,
|
||||
) (deviceDomains []string, err error) {
|
||||
if c == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
tlsConf, err := c.Certificates.toInternal(ctx, mtrc)
|
||||
err = c.Certificates.store(ctx, tlsMgr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("certificates: %w", err)
|
||||
}
|
||||
|
||||
var deviceDomains []string
|
||||
for _, w := range c.DeviceIDWildcards {
|
||||
deviceDomains = append(deviceDomains, strings.TrimPrefix(w, "*."))
|
||||
}
|
||||
|
||||
return &agd.TLS{
|
||||
Conf: tlsConf,
|
||||
DeviceDomains: deviceDomains,
|
||||
SessionKeys: c.SessionKeys,
|
||||
}, nil
|
||||
return deviceDomains, nil
|
||||
}
|
||||
|
||||
// validate returns an error if the TLS configuration is invalid for the given
|
||||
@ -101,9 +92,9 @@ func validateDeviceIDWildcards(wildcards []string) (err error) {
|
||||
for i, w := range wildcards {
|
||||
// TODO(e.burkov): Consider removing this requirement.
|
||||
if !strings.HasPrefix(w, "*.") {
|
||||
return fmt.Errorf("at index %d: not a wildcard", i)
|
||||
return fmt.Errorf("at index %d: not a wildcard: %q", i, w)
|
||||
} else if s.Has(w) {
|
||||
return fmt.Errorf("at index %d: duplicated wildcard", i)
|
||||
return fmt.Errorf("at index %d: wildcard: %w: %q", i, errors.ErrDuplicated, w)
|
||||
}
|
||||
|
||||
s.Add(w)
|
||||
@ -125,42 +116,40 @@ type tlsConfigCert struct {
|
||||
// no nil items.
|
||||
type tlsConfigCerts []*tlsConfigCert
|
||||
|
||||
// toInternal converts certs to a TLS configuration. certs must be valid.
|
||||
// store stores the TLS certificates in the TLS manager. certs must be valid.
|
||||
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)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("adding certificate at index %d: %w", i, err))
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) != 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// toInternal is like [tlsConfigCerts.store] but it also returns the TLS
|
||||
// configuration. certs must be valid.
|
||||
func (certs tlsConfigCerts) toInternal(
|
||||
ctx context.Context,
|
||||
mtrc tlsconfig.Metrics,
|
||||
tlsMgr tlsconfig.Manager,
|
||||
) (conf *tls.Config, err error) {
|
||||
if len(certs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
tlsCerts := make([]tls.Certificate, len(certs))
|
||||
for i, c := range certs {
|
||||
var cert tls.Certificate
|
||||
cert, err = tls.LoadX509KeyPair(c.Certificate, c.Key)
|
||||
err = certs.store(ctx, tlsMgr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("certificate at index %d: %w", i, err)
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var leaf *x509.Certificate
|
||||
leaf, err = x509.ParseCertificate(cert.Certificate[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid leaf, certificate at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
cert.Leaf = leaf
|
||||
tlsCerts[i] = cert
|
||||
|
||||
authAlgo, subj := leaf.PublicKeyAlgorithm.String(), leaf.Subject.String()
|
||||
|
||||
mtrc.SetCertificateInfo(ctx, authAlgo, subj, leaf.NotAfter)
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
Certificates: tlsCerts,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
MaxVersion: tls.VersionTLS13,
|
||||
}, nil
|
||||
return tlsMgr.Clone(), nil
|
||||
}
|
||||
|
||||
// type check
|
||||
@ -181,24 +170,3 @@ func (certs tlsConfigCerts) validate() (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// enableTLSKeyLogging enables TLS key logging (use for debug purposes only).
|
||||
func enableTLSKeyLogging(grps []*agd.ServerGroup, keyLogFileName string) (err error) {
|
||||
path := filepath.Clean(keyLogFileName)
|
||||
|
||||
// TODO(a.garipov): Consider closing the file when we add SIGHUP support.
|
||||
kl, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("opening SSL_KEY_LOG_FILE: %w", err)
|
||||
}
|
||||
|
||||
for _, g := range grps {
|
||||
for _, s := range g.Servers {
|
||||
if s.TLS != nil {
|
||||
s.TLS.KeyLogWriter = kl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -41,7 +41,10 @@ func (c *upstreamConfig) toInternal(logger *slog.Logger) (fwdConf *forward.Handl
|
||||
|
||||
upsConfs := toUpstreamConfigs(upstreams)
|
||||
fallbackConfs := toUpstreamConfigs(fallbacks)
|
||||
metricsListener := prometheus.NewForwardMetricsListener(metrics.Namespace(), len(upstreams)+len(fallbacks))
|
||||
metricsListener := prometheus.NewForwardMetricsListener(
|
||||
metrics.Namespace(),
|
||||
len(upstreams)+len(fallbacks),
|
||||
)
|
||||
|
||||
var hcInit time.Duration
|
||||
if c.Healthcheck.Enabled {
|
||||
|
@ -68,7 +68,7 @@ func (c *webConfig) toInternal(
|
||||
envs *environment,
|
||||
dnsCk dnscheck.Interface,
|
||||
errColl errcoll.Interface,
|
||||
mtrc tlsconfig.Metrics,
|
||||
tlsMgr tlsconfig.Manager,
|
||||
) (conf *websvc.Config, err error) {
|
||||
if c == nil {
|
||||
return nil, nil
|
||||
@ -87,7 +87,7 @@ func (c *webConfig) toInternal(
|
||||
conf.RootRedirectURL = netutil.CloneURL(&c.RootRedirectURL.URL)
|
||||
}
|
||||
|
||||
conf.LinkedIP, err = c.LinkedIP.toInternal(ctx, mtrc, envs.LinkedIPTargetURL)
|
||||
conf.LinkedIP, err = c.LinkedIP.toInternal(ctx, tlsMgr, envs.LinkedIPTargetURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting linked_ip: %w", err)
|
||||
}
|
||||
@ -111,7 +111,7 @@ func (c *webConfig) toInternal(
|
||||
}}
|
||||
|
||||
for _, bp := range blockPages {
|
||||
*bp.webConfPtr, err = bp.conf.toInternal(ctx, mtrc)
|
||||
*bp.webConfPtr, err = bp.conf.toInternal(ctx, tlsMgr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", bp.name, err)
|
||||
}
|
||||
@ -123,7 +123,7 @@ func (c *webConfig) toInternal(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conf.NonDoHBind, err = c.NonDoHBind.toInternal(ctx, mtrc)
|
||||
conf.NonDoHBind, err = c.NonDoHBind.toInternal(ctx, tlsMgr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting non_doh_bind: %w", err)
|
||||
}
|
||||
@ -230,7 +230,7 @@ type linkedIPServer struct {
|
||||
// toInternal converts s to a linkedIP server configuration. s must be valid.
|
||||
func (s *linkedIPServer) toInternal(
|
||||
ctx context.Context,
|
||||
mtrc tlsconfig.Metrics,
|
||||
tlsMgr tlsconfig.Manager,
|
||||
targetURL *urlutil.URL,
|
||||
) (srv *websvc.LinkedIPServer, err error) {
|
||||
if s == nil {
|
||||
@ -238,7 +238,7 @@ func (s *linkedIPServer) toInternal(
|
||||
}
|
||||
|
||||
srv = &websvc.LinkedIPServer{}
|
||||
srv.Bind, err = s.Bind.toInternal(ctx, mtrc)
|
||||
srv.Bind, err = s.Bind.toInternal(ctx, tlsMgr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting bind: %w", err)
|
||||
}
|
||||
@ -288,7 +288,7 @@ type blockPageServer struct {
|
||||
// toInternal converts s to a block page server configuration. s must be valid.
|
||||
func (s *blockPageServer) toInternal(
|
||||
ctx context.Context,
|
||||
mtrc tlsconfig.Metrics,
|
||||
tlsMgr tlsconfig.Manager,
|
||||
) (conf *websvc.BlockPageServerConfig, err error) {
|
||||
if s == nil {
|
||||
return nil, nil
|
||||
@ -298,7 +298,7 @@ func (s *blockPageServer) toInternal(
|
||||
ContentFilePath: s.BlockPage,
|
||||
}
|
||||
|
||||
conf.Bind, err = s.Bind.toInternal(ctx, mtrc)
|
||||
conf.Bind, err = s.Bind.toInternal(ctx, tlsMgr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting bind: %w", err)
|
||||
}
|
||||
@ -337,12 +337,12 @@ type bindData []*bindItem
|
||||
// be valid.
|
||||
func (bd bindData) toInternal(
|
||||
ctx context.Context,
|
||||
mtrc tlsconfig.Metrics,
|
||||
tlsMgr tlsconfig.Manager,
|
||||
) (data []*websvc.BindData, err error) {
|
||||
data = make([]*websvc.BindData, len(bd))
|
||||
|
||||
for i, d := range bd {
|
||||
data[i], err = d.toInternal(ctx, mtrc)
|
||||
data[i], err = d.toInternal(ctx, tlsMgr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("bind data at index %d: %w", i, err)
|
||||
}
|
||||
@ -383,9 +383,9 @@ type bindItem struct {
|
||||
// be valid.
|
||||
func (i *bindItem) toInternal(
|
||||
ctx context.Context,
|
||||
mtrc tlsconfig.Metrics,
|
||||
tlsMgr tlsconfig.Manager,
|
||||
) (data *websvc.BindData, err error) {
|
||||
tlsConf, err := i.Certificates.toInternal(ctx, mtrc)
|
||||
tlsConf, err := i.Certificates.toInternal(ctx, tlsMgr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("certificates: %w", err)
|
||||
}
|
||||
|
@ -17,27 +17,27 @@ import (
|
||||
|
||||
func TestListenConfig(t *testing.T) {
|
||||
pc := &fakenet.PacketConn{
|
||||
OnClose: func() (err error) { panic("not implemented") },
|
||||
OnLocalAddr: func() (laddr net.Addr) { panic("not implemented") },
|
||||
OnReadFrom: func(b []byte) (n int, addr net.Addr, err error) { panic("not implemented") },
|
||||
OnSetDeadline: func(t time.Time) (err error) { panic("not implemented") },
|
||||
OnSetReadDeadline: func(t time.Time) (err error) { panic("not implemented") },
|
||||
OnSetWriteDeadline: func(t time.Time) (err error) { panic("not implemented") },
|
||||
OnWriteTo: func(b []byte, addr net.Addr) (n int, err error) { panic("not implemented") },
|
||||
OnClose: func() (_ error) { panic("not implemented") },
|
||||
OnLocalAddr: func() (_ net.Addr) { panic("not implemented") },
|
||||
OnReadFrom: func(_ []byte) (_ int, _ net.Addr, _ error) {
|
||||
panic("not implemented")
|
||||
},
|
||||
OnSetDeadline: func(_ time.Time) (_ error) { panic("not implemented") },
|
||||
OnSetReadDeadline: func(_ time.Time) (_ error) { panic("not implemented") },
|
||||
OnSetWriteDeadline: func(_ time.Time) (_ error) { panic("not implemented") },
|
||||
OnWriteTo: func(_ []byte, _ net.Addr) (_ int, _ error) {
|
||||
panic("not implemented")
|
||||
},
|
||||
}
|
||||
|
||||
lsnr := &fakenet.Listener{
|
||||
OnAccept: func() (c net.Conn, err error) { panic("not implemented") },
|
||||
OnAddr: func() (addr net.Addr) { panic("not implemented") },
|
||||
OnClose: func() (err error) { return nil },
|
||||
OnAccept: func() (_ net.Conn, _ error) { panic("not implemented") },
|
||||
OnAddr: func() (_ net.Addr) { panic("not implemented") },
|
||||
OnClose: func() (_ error) { return nil },
|
||||
}
|
||||
|
||||
c := &agdtest.ListenConfig{
|
||||
OnListen: func(
|
||||
ctx context.Context,
|
||||
network string,
|
||||
address string,
|
||||
) (l net.Listener, err error) {
|
||||
OnListen: func(ctx context.Context, network, address string) (l net.Listener, err error) {
|
||||
return lsnr, nil
|
||||
},
|
||||
OnListenPacket: func(
|
||||
|
@ -162,7 +162,7 @@ func TestService_Start(t *testing.T) {
|
||||
resp, err = client.Post(ctx, refreshURL, agdhttp.HdrValApplicationJSON, reqBody)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, refreshed, 0)
|
||||
assert.Empty(t, refreshed)
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
respBody = readRespBody(t, resp)
|
||||
|
@ -2,15 +2,8 @@ package dnscheck_test
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testutil.DiscardLogOutput(m)
|
||||
}
|
||||
|
||||
// Test data.
|
||||
var (
|
||||
testRemoteIP = netip.MustParseAddr("1.2.3.4")
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"slices"
|
||||
@ -19,7 +20,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/remotekv/consulkv"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/httphdr"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/miekg/dns"
|
||||
cache "github.com/patrickmn/go-cache"
|
||||
@ -28,8 +29,10 @@ import (
|
||||
|
||||
// RemoteKV is the RemoteKV KV based DNS checker.
|
||||
type RemoteKV struct {
|
||||
// mu protects cache. Don't use an RWMutex here, since the ratio of read
|
||||
// and write access is expected to be approximately equal.
|
||||
logger *slog.Logger
|
||||
|
||||
// mu protects cache. Don't use an RWMutex here, since it is expected that
|
||||
// there are about as many reads as there are writes.
|
||||
mu *sync.Mutex
|
||||
cache *cache.Cache
|
||||
|
||||
@ -49,6 +52,9 @@ type RemoteKV struct {
|
||||
// RemoteKVConfig is the configuration structure for remote KV based DNS
|
||||
// checker. All fields must be non-empty.
|
||||
type RemoteKVConfig struct {
|
||||
// Logger is used to log the operation of the DNS checker.
|
||||
Logger *slog.Logger
|
||||
|
||||
// Messages is the message constructor used to create DNS responses with
|
||||
// IPv4 and IPv6 IPs.
|
||||
Messages *dnsmsg.Constructor
|
||||
@ -85,8 +91,9 @@ const (
|
||||
)
|
||||
|
||||
// NewRemoteKV creates a new remote KV based DNS checker. c must be non-nil.
|
||||
func NewRemoteKV(c *RemoteKVConfig) (cc *RemoteKV) {
|
||||
func NewRemoteKV(c *RemoteKVConfig) (dc *RemoteKV) {
|
||||
return &RemoteKV{
|
||||
logger: c.Logger,
|
||||
mu: &sync.Mutex{},
|
||||
cache: cache.New(defaultCacheExp, defaultCacheGC),
|
||||
kv: c.RemoteKV,
|
||||
@ -104,7 +111,7 @@ func NewRemoteKV(c *RemoteKVConfig) (cc *RemoteKV) {
|
||||
var _ Interface = (*RemoteKV)(nil)
|
||||
|
||||
// Check implements the Interface interface for *RemoteKV.
|
||||
func (cc *RemoteKV) Check(
|
||||
func (dc *RemoteKV) Check(
|
||||
ctx context.Context,
|
||||
req *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
@ -124,7 +131,7 @@ func (cc *RemoteKV) Check(
|
||||
}()
|
||||
|
||||
var randomID string
|
||||
randomID, matched, err = randomIDFromDomain(ri.Host, cc.domains)
|
||||
randomID, matched, err = randomIDFromDomain(ri.Host, dc.domains)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return nil, err
|
||||
@ -132,32 +139,32 @@ func (cc *RemoteKV) Check(
|
||||
// Not a dnscheck domain, just ignore the request.
|
||||
return nil, nil
|
||||
} else if randomID == "" {
|
||||
return cc.resp(ri, req)
|
||||
return dc.resp(ri, req)
|
||||
}
|
||||
|
||||
inf := cc.newInfo(ri)
|
||||
inf := dc.newInfo(ri)
|
||||
b, err := json.Marshal(inf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("encoding value for key %q for remote kv: %w", randomID, err)
|
||||
}
|
||||
|
||||
cc.addToCache(randomID, b)
|
||||
dc.addToCache(randomID, b)
|
||||
|
||||
err = cc.kv.Set(ctx, randomID, b)
|
||||
err = dc.kv.Set(ctx, randomID, b)
|
||||
if err != nil {
|
||||
errcoll.Collectf(ctx, cc.errColl, "dnscheck: remote kv setting: %w", err)
|
||||
errcoll.Collect(ctx, dc.errColl, dc.logger, "remote kv setting", err)
|
||||
}
|
||||
|
||||
return cc.resp(ri, req)
|
||||
return dc.resp(ri, req)
|
||||
}
|
||||
|
||||
// addToCache adds inf into cache using randomID as key. It's safe for
|
||||
// concurrent use.
|
||||
func (cc *RemoteKV) addToCache(randomID string, inf []byte) {
|
||||
cc.mu.Lock()
|
||||
defer cc.mu.Unlock()
|
||||
func (dc *RemoteKV) addToCache(randomID string, inf []byte) {
|
||||
dc.mu.Lock()
|
||||
defer dc.mu.Unlock()
|
||||
|
||||
cc.cache.SetDefault(randomID, inf)
|
||||
dc.cache.SetDefault(randomID, inf)
|
||||
}
|
||||
|
||||
// serverType is a type for the enum of server types in the DNS checker HTTP
|
||||
@ -172,7 +179,7 @@ const (
|
||||
|
||||
// newInfo returns an information record with all available data about the
|
||||
// server and the request. ri must not be nil.
|
||||
func (cc *RemoteKV) newInfo(ri *agd.RequestInfo) (inf *info) {
|
||||
func (dc *RemoteKV) newInfo(ri *agd.RequestInfo) (inf *info) {
|
||||
g := ri.ServerGroup
|
||||
|
||||
srvType := serverTypePublic
|
||||
@ -186,8 +193,8 @@ func (cc *RemoteKV) newInfo(ri *agd.RequestInfo) (inf *info) {
|
||||
ServerType: srvType,
|
||||
|
||||
Protocol: ri.Proto.String(),
|
||||
NodeLocation: cc.nodeLocation,
|
||||
NodeName: cc.nodeName,
|
||||
NodeLocation: dc.nodeLocation,
|
||||
NodeName: dc.nodeName,
|
||||
|
||||
ClientIP: ri.RemoteIP,
|
||||
}
|
||||
@ -204,7 +211,7 @@ func (cc *RemoteKV) newInfo(ri *agd.RequestInfo) (inf *info) {
|
||||
//
|
||||
// TODO(e.burkov): Inspect the reason for using different message constructors
|
||||
// for different DNS types, and consider using only one of them.
|
||||
func (cc *RemoteKV) resp(ri *agd.RequestInfo, req *dns.Msg) (resp *dns.Msg, err error) {
|
||||
func (dc *RemoteKV) resp(ri *agd.RequestInfo, req *dns.Msg) (resp *dns.Msg, err error) {
|
||||
qt := ri.QType
|
||||
|
||||
if qt != dns.TypeA && qt != dns.TypeAAAA {
|
||||
@ -212,24 +219,23 @@ func (cc *RemoteKV) resp(ri *agd.RequestInfo, req *dns.Msg) (resp *dns.Msg, err
|
||||
}
|
||||
|
||||
if qt == dns.TypeA {
|
||||
return cc.messages.NewRespIP(req, cc.ipv4...)
|
||||
return dc.messages.NewRespIP(req, dc.ipv4...)
|
||||
}
|
||||
|
||||
return cc.messages.NewRespIP(req, cc.ipv6...)
|
||||
return dc.messages.NewRespIP(req, dc.ipv6...)
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ http.Handler = (*RemoteKV)(nil)
|
||||
|
||||
// ServeHTTP implements the http.Handler interface for *RemoteKV.
|
||||
func (cc *RemoteKV) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
m, p, raddr := r.Method, r.URL.Path, r.RemoteAddr
|
||||
log.Debug("dnscheck: http req %s %s from %s", m, p, raddr)
|
||||
defer log.Debug("dnscheck: finished http req %s %s from %s", m, p, raddr)
|
||||
|
||||
//
|
||||
// TODO(a.garipov): Consider using the websvc logger once it switches to
|
||||
// log/slog.
|
||||
func (dc *RemoteKV) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO(a.garipov): Put this into constant here and in package dnssvc.
|
||||
if r.URL.Path == "/dnscheck/test" {
|
||||
cc.serveCheckTest(r.Context(), w, r)
|
||||
dc.serveCheckTest(r.Context(), w, r)
|
||||
|
||||
return
|
||||
}
|
||||
@ -241,48 +247,48 @@ func (cc *RemoteKV) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
//
|
||||
// TODO(a.garipov): Refactor this and other HTTP handlers to return wrapped
|
||||
// errors and centralize the error handling.
|
||||
func (cc *RemoteKV) serveCheckTest(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
raddr := r.RemoteAddr
|
||||
func (dc *RemoteKV) serveCheckTest(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
l := dc.logger.With("raddr", r.RemoteAddr)
|
||||
|
||||
name, err := netutil.SplitHost(r.Host)
|
||||
host, err := netutil.SplitHost(r.Host)
|
||||
if err != nil {
|
||||
log.Debug("dnscheck: http req from %s: bad host %q: %s", raddr, r.Host, err)
|
||||
l.DebugContext(ctx, "bad host", "hostport", r.Host, slogutil.KeyError, err)
|
||||
|
||||
http.NotFound(w, r)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
randomID, matched, err := randomIDFromDomain(name, cc.domains)
|
||||
randomID, matched, err := randomIDFromDomain(host, dc.domains)
|
||||
if err != nil {
|
||||
log.Debug("dnscheck: http req from %s: id: %s", raddr, err)
|
||||
l.DebugContext(ctx, "bad request", "host", host, slogutil.KeyError, err)
|
||||
|
||||
http.NotFound(w, r)
|
||||
|
||||
return
|
||||
} else if !matched || randomID == "" {
|
||||
// We expect dnscheck requests to have a unique ID in the domain name.
|
||||
log.Debug("dnscheck: http req from %s: bad domain %q", raddr, name)
|
||||
l.DebugContext(ctx, "bad domain", "host", host, slogutil.KeyError, err)
|
||||
|
||||
http.NotFound(w, r)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
inf, ok, err := cc.info(ctx, randomID)
|
||||
inf, ok, err := dc.info(ctx, randomID)
|
||||
// TODO(s.chzhen): Use error interface instead of error value.
|
||||
if errors.Is(err, consulkv.ErrRateLimited) {
|
||||
http.Error(w, err.Error(), http.StatusTooManyRequests)
|
||||
|
||||
return
|
||||
} else if err != nil {
|
||||
log.Debug("dnscheck: http req from %s: getting info: %s", raddr, err)
|
||||
l.DebugContext(ctx, "getting info", "random_id", randomID, slogutil.KeyError, err)
|
||||
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
} else if !ok {
|
||||
log.Debug("dnscheck: http req from %s: no info for %q", raddr, randomID)
|
||||
l.DebugContext(ctx, "no info", "random_id", randomID, slogutil.KeyError, err)
|
||||
|
||||
http.NotFound(w, r)
|
||||
|
||||
@ -295,12 +301,12 @@ func (cc *RemoteKV) serveCheckTest(ctx context.Context, w http.ResponseWriter, r
|
||||
|
||||
_, err = w.Write(inf)
|
||||
if err != nil {
|
||||
errcoll.Collectf(ctx, cc.errColl, "dnscheck: http resp write error: %w", err)
|
||||
errcoll.Collect(ctx, dc.errColl, dc.logger, "http resp write", err)
|
||||
}
|
||||
}
|
||||
|
||||
// info returns an information record by the random request ID.
|
||||
func (cc *RemoteKV) info(ctx context.Context, randomID string) (inf []byte, ok bool, err error) {
|
||||
func (dc *RemoteKV) info(ctx context.Context, randomID string) (inf []byte, ok bool, err error) {
|
||||
defer func() {
|
||||
metrics.DNSCheckRequestTotal.With(prometheus.Labels{
|
||||
"type": "http",
|
||||
@ -312,17 +318,17 @@ func (cc *RemoteKV) info(ctx context.Context, randomID string) (inf []byte, ok b
|
||||
|
||||
defer func() { err = errors.Annotate(err, "getting from remote kv: %w") }()
|
||||
|
||||
cc.mu.Lock()
|
||||
defer cc.mu.Unlock()
|
||||
dc.mu.Lock()
|
||||
defer dc.mu.Unlock()
|
||||
|
||||
infoVal, ok := cc.cache.Get(randomID)
|
||||
infoVal, ok := dc.cache.Get(randomID)
|
||||
if ok {
|
||||
return infoVal.([]byte), true, nil
|
||||
}
|
||||
|
||||
inf, ok, err = cc.kv.Get(ctx, randomID)
|
||||
inf, ok, err = dc.kv.Get(ctx, randomID)
|
||||
if err != nil {
|
||||
errcoll.Collectf(ctx, cc.errColl, "dnscheck: remote kv getting: %w", err)
|
||||
errcoll.Collect(ctx, dc.errColl, dc.logger, "remote kv getting", err)
|
||||
|
||||
// Don't wrap the error, as it will get annotated.
|
||||
return nil, false, err
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/remotekv"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -46,6 +47,7 @@ func TestConsul_ServeHTTP(t *testing.T) {
|
||||
}
|
||||
|
||||
conf := &dnscheck.RemoteKVConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Messages: &dnsmsg.Constructor{},
|
||||
RemoteKV: remotekv.Empty{},
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
@ -171,6 +173,7 @@ func TestConsul_Check(t *testing.T) {
|
||||
msgs := agdtest.NewConstructorWithTTL(t, ttl*time.Second)
|
||||
|
||||
conf := &dnscheck.RemoteKVConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Messages: msgs,
|
||||
RemoteKV: remotekv.Empty{},
|
||||
Domains: []string{checkDomain},
|
||||
|
@ -6,6 +6,7 @@ package dnsdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@ -35,6 +36,7 @@ func (Empty) Record(_ context.Context, _ *dns.Msg, _ *agd.RequestInfo) {}
|
||||
|
||||
// Default is the default DNSDB implementation.
|
||||
type Default struct {
|
||||
logger *slog.Logger
|
||||
buffer *atomic.Pointer[buffer]
|
||||
errColl errcoll.Interface
|
||||
maxSize int
|
||||
@ -42,6 +44,9 @@ type Default struct {
|
||||
|
||||
// DefaultConfig is the default DNS database configuration structure.
|
||||
type DefaultConfig struct {
|
||||
// Logger is used to log the operation of the DNS database.
|
||||
Logger *slog.Logger
|
||||
|
||||
// ErrColl is used to collect HTTP errors.
|
||||
ErrColl errcoll.Interface
|
||||
|
||||
@ -52,6 +57,7 @@ type DefaultConfig struct {
|
||||
// New creates a new default DNS database. c must not be nil.
|
||||
func New(c *DefaultConfig) (db *Default) {
|
||||
db = &Default{
|
||||
logger: c.Logger,
|
||||
buffer: &atomic.Pointer[buffer]{},
|
||||
errColl: c.ErrColl,
|
||||
maxSize: c.MaxSize,
|
||||
|
@ -1,11 +0,0 @@
|
||||
package dnsdb_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testutil.DiscardLogOutput(m)
|
||||
}
|
@ -31,7 +31,7 @@ func (db *Default) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
h.Set(httphdr.XError, err.Error())
|
||||
errcoll.Collectf(ctx, db.errColl, "dnsdb: http handler error: %w", err)
|
||||
errcoll.Collect(ctx, db.errColl, db.logger, "handling http", err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsdb"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
|
||||
"github.com/AdguardTeam/golibs/httphdr"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -120,6 +121,7 @@ func TestDefault_ServeHTTP(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
db := dnsdb.New(&dnsdb.DefaultConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
ErrColl: agdtest.NewErrorCollector(),
|
||||
MaxSize: 100,
|
||||
})
|
||||
|
8
internal/dnsserver/cache/cache.go
vendored
8
internal/dnsserver/cache/cache.go
vendored
@ -42,9 +42,9 @@ type MiddlewareConfig struct {
|
||||
// performance metrics. If not set, EmptyMetricsListener is used.
|
||||
MetricsListener MetricsListener
|
||||
|
||||
// Size is the number of entities to hold in the cache. It must be greater
|
||||
// than zero.
|
||||
Size int
|
||||
// Count is the number of entities to hold in the cache. It must be
|
||||
// positive.
|
||||
Count int
|
||||
|
||||
// MinTTL is the minimum supported TTL for cache items.
|
||||
MinTTL time.Duration
|
||||
@ -64,7 +64,7 @@ func NewMiddleware(c *MiddlewareConfig) (m *Middleware) {
|
||||
|
||||
return &Middleware{
|
||||
metrics: metrics,
|
||||
cache: gcache.New(c.Size).LRU().Build(),
|
||||
cache: gcache.New(c.Count).LRU().Build(),
|
||||
cacheMinTTL: c.MinTTL,
|
||||
overrideTTL: c.OverrideTTL,
|
||||
}
|
||||
|
30
internal/dnsserver/cache/cache_test.go
vendored
30
internal/dnsserver/cache/cache_test.go
vendored
@ -19,8 +19,8 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
const (
|
||||
servFailMaxCacheTTL = 30
|
||||
|
||||
reqHostname = "example.com"
|
||||
reqCname = "cname.example.com"
|
||||
reqHost = "example.com"
|
||||
reqCNAME = "cname.example.com"
|
||||
reqNs1 = "ns1.example.com"
|
||||
reqNs2 = "ns2.example.com"
|
||||
|
||||
@ -30,10 +30,10 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
reqAddr := netip.MustParseAddr("1.2.3.4")
|
||||
testTTL := 60 * time.Second
|
||||
|
||||
aReq := dnsservertest.NewReq(reqHostname, dns.TypeA, dns.ClassINET)
|
||||
cnameReq := dnsservertest.NewReq(reqHostname, dns.TypeCNAME, dns.ClassINET)
|
||||
cnameAns := dnsservertest.SectionAnswer{dnsservertest.NewCNAME(reqHostname, defaultTTL, reqCname)}
|
||||
soaNs := dnsservertest.SectionNs{dnsservertest.NewSOA(reqHostname, defaultTTL, reqNs1, reqNs2)}
|
||||
aReq := dnsservertest.NewReq(reqHost, dns.TypeA, dns.ClassINET)
|
||||
cnameReq := dnsservertest.NewReq(reqHost, dns.TypeCNAME, dns.ClassINET)
|
||||
cnameAns := dnsservertest.SectionAnswer{dnsservertest.NewCNAME(reqHost, defaultTTL, reqCNAME)}
|
||||
soaNs := dnsservertest.SectionNs{dnsservertest.NewSOA(reqHost, defaultTTL, reqNs1, reqNs2)}
|
||||
|
||||
const N = 5
|
||||
testCases := []struct {
|
||||
@ -46,7 +46,7 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
}{{
|
||||
req: aReq,
|
||||
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
|
||||
dnsservertest.NewA(reqHostname, defaultTTL, reqAddr),
|
||||
dnsservertest.NewA(reqHost, defaultTTL, reqAddr),
|
||||
}),
|
||||
name: "simple_a",
|
||||
wantNumReq: 1,
|
||||
@ -83,7 +83,7 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
}, {
|
||||
req: aReq,
|
||||
resp: dnsservertest.NewResp(dns.RcodeNameError, aReq, dnsservertest.SectionNs{
|
||||
dnsservertest.NewNS(reqHostname, defaultTTL, reqNs1),
|
||||
dnsservertest.NewNS(reqHost, defaultTTL, reqNs1),
|
||||
}),
|
||||
name: "non_authoritative_nxdomain",
|
||||
// TODO(ameshkov): Consider https://datatracker.ietf.org/doc/html/rfc2308#section-3.
|
||||
@ -107,7 +107,7 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
}, {
|
||||
req: cnameReq,
|
||||
resp: dnsservertest.NewResp(dns.RcodeSuccess, cnameReq, dnsservertest.SectionAnswer{
|
||||
dnsservertest.NewCNAME(reqHostname, defaultTTL, reqCname),
|
||||
dnsservertest.NewCNAME(reqHost, defaultTTL, reqCNAME),
|
||||
}),
|
||||
name: "simple_cname_ans",
|
||||
wantNumReq: 1,
|
||||
@ -116,7 +116,7 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
}, {
|
||||
req: aReq,
|
||||
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
|
||||
dnsservertest.NewA(reqHostname, 0, reqAddr),
|
||||
dnsservertest.NewA(reqHost, 0, reqAddr),
|
||||
}),
|
||||
name: "expired_one",
|
||||
wantNumReq: N,
|
||||
@ -125,7 +125,7 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
}, {
|
||||
req: aReq,
|
||||
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
|
||||
dnsservertest.NewA(reqHostname, 10, reqAddr),
|
||||
dnsservertest.NewA(reqHost, 10, reqAddr),
|
||||
}),
|
||||
name: "override_ttl_ok",
|
||||
wantNumReq: 1,
|
||||
@ -134,7 +134,7 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
}, {
|
||||
req: aReq,
|
||||
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
|
||||
dnsservertest.NewA(reqHostname, 1000, reqAddr),
|
||||
dnsservertest.NewA(reqHost, 1000, reqAddr),
|
||||
}),
|
||||
name: "override_ttl_max",
|
||||
wantNumReq: 1,
|
||||
@ -143,7 +143,7 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
}, {
|
||||
req: aReq,
|
||||
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
|
||||
dnsservertest.NewA(reqHostname, 0, reqAddr),
|
||||
dnsservertest.NewA(reqHost, 0, reqAddr),
|
||||
}),
|
||||
name: "override_ttl_zero",
|
||||
wantNumReq: N,
|
||||
@ -152,7 +152,7 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
}, {
|
||||
req: aReq,
|
||||
resp: dnsservertest.NewResp(dns.RcodeServerFailure, aReq, dnsservertest.SectionAnswer{
|
||||
dnsservertest.NewA(reqHostname, servFailMaxCacheTTL, reqAddr),
|
||||
dnsservertest.NewA(reqHost, servFailMaxCacheTTL, reqAddr),
|
||||
}),
|
||||
name: "override_ttl_servfail",
|
||||
wantNumReq: 1,
|
||||
@ -186,7 +186,7 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
withCache := dnsserver.WithMiddlewares(
|
||||
handler,
|
||||
cache.NewMiddleware(&cache.MiddlewareConfig{
|
||||
Size: 100,
|
||||
Count: 100,
|
||||
MinTTL: minTTL,
|
||||
OverrideTTL: tc.minTTL != nil,
|
||||
}),
|
||||
|
@ -158,6 +158,14 @@ func RunLocalHTTPSServer(
|
||||
network = dnsserver.NetworkTCP
|
||||
}
|
||||
|
||||
var tlsConfigH3 *tls.Config
|
||||
if tlsConfig != nil {
|
||||
tlsConfigH3 = tlsConfig.Clone()
|
||||
|
||||
tlsConfig.NextProtos = dnsserver.NextProtoDoH
|
||||
tlsConfigH3.NextProtos = dnsserver.NextProtoDoH3
|
||||
}
|
||||
|
||||
conf := dnsserver.ConfigHTTPS{
|
||||
ConfigBase: dnsserver.ConfigBase{
|
||||
Name: "test",
|
||||
@ -165,7 +173,8 @@ func RunLocalHTTPSServer(
|
||||
Handler: h,
|
||||
Network: network,
|
||||
},
|
||||
TLSConfig: tlsConfig,
|
||||
TLSConfDefault: tlsConfig,
|
||||
TLSConfH3: tlsConfigH3,
|
||||
NonDNSHandler: nonDNSHandler,
|
||||
}
|
||||
|
||||
|
@ -38,20 +38,30 @@ func CreateServerTLSConfig(tlsServerName string) (tlsConfig *tls.Config) {
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature |
|
||||
x509.KeyUsageCertSign,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
template.DNSNames = append(template.DNSNames, tlsServerName)
|
||||
|
||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(privateKey), privateKey)
|
||||
derBytes, err := x509.CreateCertificate(
|
||||
rand.Reader,
|
||||
&template,
|
||||
&template,
|
||||
publicKey(privateKey),
|
||||
privateKey,
|
||||
)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to create certificate: %v", err))
|
||||
}
|
||||
|
||||
certPem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||
keyPem := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)})
|
||||
keyPem := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
|
||||
})
|
||||
|
||||
cert, err := tls.X509KeyPair(certPem, keyPem)
|
||||
if err != nil {
|
||||
|
@ -1,9 +1,9 @@
|
||||
module github.com/AdguardTeam/AdGuardDNS/internal/dnsserver
|
||||
|
||||
go 1.23.2
|
||||
go 1.23.4
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/golibs v0.30.1
|
||||
github.com/AdguardTeam/golibs v0.30.4
|
||||
github.com/ameshkov/dnscrypt/v2 v2.3.0
|
||||
github.com/ameshkov/dnsstamps v1.0.3
|
||||
github.com/bluele/gcache v0.0.2
|
||||
@ -12,11 +12,11 @@ require (
|
||||
github.com/panjf2000/ants/v2 v2.10.0
|
||||
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/quic-go/quic-go v0.48.1
|
||||
github.com/quic-go/quic-go v0.48.2
|
||||
github.com/stretchr/testify v1.9.0
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
|
||||
golang.org/x/net v0.30.0
|
||||
golang.org/x/sys v0.26.0
|
||||
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d
|
||||
golang.org/x/net v0.32.0
|
||||
golang.org/x/sys v0.28.0
|
||||
)
|
||||
|
||||
require (
|
||||
@ -26,23 +26,23 @@ require (
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20241023014458-598669927662 // indirect
|
||||
github.com/google/pprof v0.0.0-20241203143554-1e3fdc7de467 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.22.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.60.0 // indirect
|
||||
github.com/prometheus/common v0.60.1 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/crypto v0.28.0 // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/tools v0.26.0 // indirect
|
||||
golang.org/x/crypto v0.30.0 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.8.0 // indirect
|
||||
golang.org/x/tools v0.28.0 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
@ -1,5 +1,4 @@
|
||||
github.com/AdguardTeam/golibs v0.30.1 h1:/yv7dq2h7WXw/jTDxkE3FP9zHerRT+i03PZRHJX4fPU=
|
||||
github.com/AdguardTeam/golibs v0.30.1/go.mod h1:FkwcNQEJoGsgDGXcalrVa/4gWbE68KsmE2guXWtBQUE=
|
||||
github.com/AdguardTeam/golibs v0.30.4 h1:zfFX1v4hkOCz6BifkneiBW2PCwSK523kYNr+VwaFrIw=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
|
||||
@ -26,8 +25,7 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20241023014458-598669927662 h1:SKMkD83p7FwUqKmBsPdLHF5dNyxq3jOWwu9w9UyH5vA=
|
||||
github.com/google/pprof v0.0.0-20241023014458-598669927662/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241203143554-1e3fdc7de467 h1:keEZFtbLJugfE0qHn+Ge1JCE71spzkchQobDf3mzS/4=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
@ -38,10 +36,8 @@ github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
||||
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
|
||||
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
|
||||
github.com/panjf2000/ants/v2 v2.10.0 h1:zhRg1pQUtkyRiOFo2Sbqwjp0GfBNo9cUY2/Grpx1p+8=
|
||||
github.com/panjf2000/ants/v2 v2.10.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
|
||||
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible h1:IWzUvJ72xMjmrjR9q3H1PF+jwdN0uNQiR2t1BLNalyo=
|
||||
@ -52,14 +48,12 @@ github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA=
|
||||
github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
|
||||
github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.48.1 h1:y/8xmfWI9qmGTc+lBr4jKRUWLGSlSigv847ULJ4hYXA=
|
||||
github.com/quic-go/quic-go v0.48.1/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
|
||||
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@ -72,25 +66,16 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
|
||||
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
func TestCacheMetricsListener_integration_cache(t *testing.T) {
|
||||
cacheMiddleware := cache.NewMiddleware(&cache.MiddlewareConfig{
|
||||
MetricsListener: prometheus.NewCacheMetricsListener(testNamespace),
|
||||
Size: 100,
|
||||
Count: 100,
|
||||
})
|
||||
|
||||
handlerWithMiddleware := dnsserver.WithMiddlewares(
|
||||
|
@ -61,7 +61,7 @@ func (p Protocol) ALPN() (alpn []string) {
|
||||
case ProtoDoQ:
|
||||
return []string{nextProtoDoQ}
|
||||
case ProtoDoH:
|
||||
return slices.Clone(nextProtoDoH3)
|
||||
return slices.Clone(NextProtoDoH3)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
@ -43,15 +43,15 @@ const (
|
||||
httpIdleTimeout = 120 * time.Second
|
||||
)
|
||||
|
||||
// nextProtoDoH is a list of ALPN that we would add by default to the server's
|
||||
// *tls.Config if no NextProto is specified there. Note, that with this order,
|
||||
// we prioritize HTTP/2 over HTTP/1.1.
|
||||
var nextProtoDoH = []string{http2.NextProtoTLS, "http/1.1"}
|
||||
// NextProtoDoH is a list of ALPN protocols added by default to the server's
|
||||
// *tls.Config if no NextProto is specified there. Note that with this order,
|
||||
// HTTP/2 is prioritized over HTTP/1.1.
|
||||
var NextProtoDoH = []string{http2.NextProtoTLS, "http/1.1"}
|
||||
|
||||
// nextProtoDoH3 is a list of ALPN that we should add by default to the server's
|
||||
// NextProtoDoH3 is a list of ALPN protocols added by default to the server's
|
||||
// *tls.Config if no NextProto is specified there and DoH3 is supposed to be
|
||||
// used.
|
||||
var nextProtoDoH3 = []string{http3.NextProtoH3, http2.NextProtoTLS, "http/1.1"}
|
||||
// used. Note that with this order, HTTP/2 is prioritized over HTTP/1.1.
|
||||
var NextProtoDoH3 = []string{http3.NextProtoH3, http2.NextProtoTLS, "http/1.1"}
|
||||
|
||||
// ConfigHTTPS is a struct that needs to be passed to NewServerHTTPS to
|
||||
// initialize a new ServerHTTPS instance. You can choose whether HTTP/3 is
|
||||
@ -59,10 +59,14 @@ var nextProtoDoH3 = []string{http3.NextProtoH3, http2.NextProtoTLS, "http/1.1"}
|
||||
// will listen to both HTTP/2 and HTTP/3, but if you set it to NetworkTCP, the
|
||||
// server will only use HTTP/2 and NetworkUDP will mean HTTP/3 only.
|
||||
type ConfigHTTPS struct {
|
||||
// TLSConfig is the TLS configuration for HTTPS. If not set and
|
||||
// [ConfigBase.Network] is set to NetworkTCP the server will listen to
|
||||
// plain HTTP.
|
||||
TLSConfig *tls.Config
|
||||
// TLSConfDefault is the TLS configuration for HTTPS. If not set and
|
||||
// [ConfigBase.Network] is set to NetworkTCP the server will listen to plain
|
||||
// HTTP. If it is not nil, it must be set to [NextProtoDoH].
|
||||
TLSConfDefault *tls.Config
|
||||
|
||||
// TLSConfH3 is the TLS configuration for DoH3. If it is not nil, it must
|
||||
// be set to [NextProtoDoH3].
|
||||
TLSConfH3 *tls.Config
|
||||
|
||||
// NonDNSHandler handles requests with the path not equal to /dns-query.
|
||||
// If it is empty, the server will return 404 for requests like that.
|
||||
@ -306,7 +310,7 @@ func (s *ServerHTTPS) serveHTTPS(ctx context.Context, hs *http.Server, l net.Lis
|
||||
defer s.handlePanicAndExit(ctx)
|
||||
|
||||
scheme := urlutil.SchemeHTTPS
|
||||
if s.conf.TLSConfig == nil {
|
||||
if s.conf.TLSConfDefault == nil {
|
||||
scheme = urlutil.SchemeHTTP
|
||||
}
|
||||
|
||||
@ -516,12 +520,9 @@ func (s *ServerHTTPS) listenTLS(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
// Prepare the TLS configuration of the server.
|
||||
tlsConf := s.conf.TLSConfig
|
||||
tlsConf := s.conf.TLSConfDefault
|
||||
if tlsConf == nil {
|
||||
return nil
|
||||
} else if len(tlsConf.NextProtos) == 0 {
|
||||
tlsConf = tlsConf.Clone()
|
||||
tlsConf.NextProtos = nextProtoDoH
|
||||
}
|
||||
|
||||
s.tcpListener = tls.NewListener(s.tcpListener, tlsConf)
|
||||
@ -532,11 +533,7 @@ func (s *ServerHTTPS) listenTLS(ctx context.Context) (err error) {
|
||||
// listenQUIC starts a QUIC listener that will be used to serve HTTP/3 requests.
|
||||
func (s *ServerHTTPS) listenQUIC(ctx context.Context) (err error) {
|
||||
// Prepare the TLS configuration of the server.
|
||||
tlsConf := s.conf.TLSConfig
|
||||
if tlsConf != nil && len(tlsConf.NextProtos) == 0 {
|
||||
tlsConf = tlsConf.Clone()
|
||||
tlsConf.NextProtos = nextProtoDoH3
|
||||
}
|
||||
tlsConf := s.conf.TLSConfH3
|
||||
|
||||
conn, err := s.listenConfig.ListenPacket(ctx, "udp", s.addr)
|
||||
if err != nil {
|
||||
|
@ -307,7 +307,8 @@ func TestDNSMsgToJSONMsg(t *testing.T) {
|
||||
Type: dns.TypeHTTPS,
|
||||
Class: dns.ClassINET,
|
||||
TTL: 100,
|
||||
Data: `0 example.com alpn="h2,h3" ech="AQI=" ipv4hint="127.0.0.1,127.0.0.2" ipv6hint="2000::,2001::"`,
|
||||
Data: `0 example.com alpn="h2,h3" ech="AQI=" ipv4hint="127.0.0.1,127.0.0.2" ` +
|
||||
`ipv6hint="2000::,2001::"`,
|
||||
}}, jsonMsg.Answer)
|
||||
require.Equal(t, []dnsserver.JSONAnswer{{
|
||||
Name: "example.org",
|
||||
|
@ -62,10 +62,16 @@ const (
|
||||
// compatProtoDQ are ALPNs for backwards compatibility.
|
||||
var compatProtoDQ = []string{"doq-i00", "doq-i02", "doq-i03", "dq"}
|
||||
|
||||
// NextProtoDoQ is a list of ALPN protocols added by default to the server's
|
||||
// *tls.Config if no NextProto is specified there and DoQ is supposed to be
|
||||
// used.
|
||||
var NextProtoDoQ = append([]string{nextProtoDoQ}, compatProtoDQ...)
|
||||
|
||||
// ConfigQUIC is a struct that needs to be passed to NewServerQUIC to
|
||||
// initialize a new ServerQUIC instance.
|
||||
type ConfigQUIC struct {
|
||||
// TLSConfig is the TLS configuration for QUIC.
|
||||
// TLSConfig is the TLS configuration for QUIC. If it is not nil, it must
|
||||
// be set to [NextProtoDoQ].
|
||||
TLSConfig *tls.Config
|
||||
|
||||
ConfigBase
|
||||
@ -111,12 +117,6 @@ const quicBytePoolSize = dns.MaxMsgSize
|
||||
|
||||
// NewServerQUIC creates a new ServerQUIC instance.
|
||||
func NewServerQUIC(conf ConfigQUIC) (s *ServerQUIC) {
|
||||
// Make sure DOQ ALPNs are enabled in the TLS config.
|
||||
tlsConfig := conf.TLSConfig
|
||||
if len(tlsConfig.NextProtos) == 0 {
|
||||
tlsConfig.NextProtos = append([]string{nextProtoDoQ}, compatProtoDQ...)
|
||||
}
|
||||
|
||||
if conf.ListenConfig == nil {
|
||||
// Do not enable OOB here as quic-go will do that on its own.
|
||||
conf.ListenConfig = netext.DefaultListenConfig(nil)
|
||||
|
@ -107,6 +107,7 @@ func TestServerQUIC_integration_ENDS0Padding(t *testing.T) {
|
||||
|
||||
func TestServerQUIC_integration_0RTT(t *testing.T) {
|
||||
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
|
||||
tlsConfig.NextProtos = dnsserver.NextProtoDoQ
|
||||
srv, addr, err := dnsservertest.RunLocalQUICServer(
|
||||
dnsservertest.NewDefaultHandler(),
|
||||
tlsConfig,
|
||||
|
@ -347,14 +347,15 @@ func NewListener(
|
||||
case agd.ProtoDoH:
|
||||
l = dnsserver.NewServerHTTPS(dnsserver.ConfigHTTPS{
|
||||
ConfigBase: baseConf,
|
||||
TLSConfig: s.TLS,
|
||||
TLSConfDefault: s.TLS.Default,
|
||||
TLSConfH3: s.TLS.H3,
|
||||
NonDNSHandler: nonDNS,
|
||||
MaxStreamsPerPeer: quicConf.MaxStreamsPerPeer,
|
||||
QUICLimitsEnabled: quicConf.QUICLimitsEnabled,
|
||||
})
|
||||
case agd.ProtoDoQ:
|
||||
l = dnsserver.NewServerQUIC(dnsserver.ConfigQUIC{
|
||||
TLSConfig: s.TLS,
|
||||
TLSConfig: s.TLS.Default,
|
||||
ConfigBase: baseConf,
|
||||
MaxStreamsPerPeer: quicConf.MaxStreamsPerPeer,
|
||||
QUICLimitsEnabled: quicConf.QUICLimitsEnabled,
|
||||
@ -369,7 +370,7 @@ func NewListener(
|
||||
MaxPipelineCount: tcpConf.MaxPipelineCount,
|
||||
TCPIdleTimeout: tcpConf.IdleTimeout,
|
||||
},
|
||||
TLSConfig: s.TLS,
|
||||
TLSConfig: s.TLS.Default,
|
||||
})
|
||||
default:
|
||||
return nil, fmt.Errorf("protocol: %w: %d", errors.ErrBadEnumValue, p)
|
||||
|
@ -88,7 +88,7 @@ func wrapPreUpstreamMw(ctx context.Context, c *HandlersConfig) (wrapped dnsserve
|
||||
cacheMw := cache.NewMiddleware(&cache.MiddlewareConfig{
|
||||
// TODO(a.garipov): Do not use promauto and refactor.
|
||||
MetricsListener: dnssrvprom.NewCacheMetricsListener(metrics.Namespace()),
|
||||
Size: conf.NoECSCount,
|
||||
Count: conf.NoECSCount,
|
||||
MinTTL: conf.MinTTL,
|
||||
OverrideTTL: conf.OverrideCacheTTL,
|
||||
})
|
||||
@ -146,7 +146,10 @@ func newMainMiddlewareMetrics(c *HandlersConfig) (mainMwMtrc MainMiddlewareMetri
|
||||
// newHandlersForServers returns a handler map for each server group and each
|
||||
// server.
|
||||
func newHandlersForServers(c *HandlersConfig, h dnsserver.Handler) (handlers Handlers, err error) {
|
||||
rlMwMtrc, err := metrics.NewDefaultRatelimitMiddleware(c.MetricsNamespace, c.PrometheusRegisterer)
|
||||
rlMwMtrc, err := metrics.NewDefaultRatelimitMiddleware(
|
||||
c.MetricsNamespace,
|
||||
c.PrometheusRegisterer,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ratelimit middleware metrics: %w", err)
|
||||
}
|
||||
@ -206,6 +209,6 @@ func newDeviceFinder(c *HandlersConfig, g *agd.ServerGroup, s *agd.Server) (df a
|
||||
ProfileDB: c.ProfileDB,
|
||||
HumanIDParser: c.HumanIDParser,
|
||||
Server: s,
|
||||
DeviceDomains: g.TLS.DeviceDomains,
|
||||
DeviceDomains: g.DeviceDomains,
|
||||
})
|
||||
}
|
||||
|
@ -60,19 +60,27 @@ func TestNewHandlers(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
fltGrps := map[agd.FilteringGroupID]*agd.FilteringGroup{
|
||||
dnssvctest.FilteringGroupID: {
|
||||
ID: dnssvctest.FilteringGroupID,
|
||||
RuleListIDs: []agd.FilterListID{dnssvctest.FilterListID1},
|
||||
RuleListsEnabled: true,
|
||||
fltGrp := &agd.FilteringGroup{
|
||||
FilterConfig: &filter.ConfigGroup{
|
||||
Parental: &filter.ConfigParental{},
|
||||
RuleList: &filter.ConfigRuleList{
|
||||
IDs: []filter.ID{dnssvctest.FilterListID1},
|
||||
Enabled: true,
|
||||
},
|
||||
SafeBrowsing: &filter.ConfigSafeBrowsing{},
|
||||
},
|
||||
ID: dnssvctest.FilteringGroupID,
|
||||
}
|
||||
|
||||
fltGrps := map[agd.FilteringGroupID]*agd.FilteringGroup{
|
||||
dnssvctest.FilteringGroupID: fltGrp,
|
||||
}
|
||||
|
||||
fltStrg := &agdtest.FilterStorage{
|
||||
OnFilterFromContext: func(_ context.Context, _ *agd.RequestInfo) (f filter.Interface) {
|
||||
OnForConfig: func(_ context.Context, _ filter.Config) (f filter.Interface) {
|
||||
panic("not implemented")
|
||||
},
|
||||
OnHasListID: func(_ agd.FilterListID) (ok bool) { panic("not implemented") },
|
||||
OnHasListID: func(_ filter.ID) (ok bool) { panic("not implemented") },
|
||||
}
|
||||
|
||||
hashMatcher := &agdtest.HashMatcher{
|
||||
@ -91,7 +99,7 @@ func TestNewHandlers(t *testing.T) {
|
||||
}
|
||||
|
||||
ruleStat := &agdtest.RuleStat{
|
||||
OnCollect: func(_ context.Context, _ agd.FilterListID, _ agd.FilterRuleText) {
|
||||
OnCollect: func(_ context.Context, _ filter.ID, _ filter.RuleText) {
|
||||
panic("not implemented")
|
||||
},
|
||||
}
|
||||
@ -104,7 +112,6 @@ func TestNewHandlers(t *testing.T) {
|
||||
DDR: &agd.DDR{
|
||||
Enabled: true,
|
||||
},
|
||||
TLS: &agd.TLS{},
|
||||
Name: dnssvctest.ServerGroupName,
|
||||
FilteringGroup: dnssvctest.FilteringGroupID,
|
||||
Servers: []*agd.Server{srv},
|
||||
|
@ -57,7 +57,7 @@ func newTestService(
|
||||
querylogCh chan<- *querylog.Entry,
|
||||
geoIPCh chan<- string,
|
||||
dnsDBCh chan<- *agd.RequestInfo,
|
||||
ruleStatCh chan<- agd.FilterRuleText,
|
||||
ruleStatCh chan<- filter.RuleText,
|
||||
) (svc *dnssvc.Service, srvAddr netip.AddrPort) {
|
||||
t.Helper()
|
||||
|
||||
@ -73,11 +73,19 @@ func newTestService(
|
||||
}
|
||||
|
||||
prof := &agd.Profile{
|
||||
FilterConfig: &filter.ConfigClient{
|
||||
Custom: &filter.ConfigCustom{},
|
||||
Parental: &filter.ConfigParental{},
|
||||
RuleList: &filter.ConfigRuleList{
|
||||
IDs: []filter.ID{dnssvctest.FilterListID1},
|
||||
Enabled: true,
|
||||
},
|
||||
SafeBrowsing: &filter.ConfigSafeBrowsing{},
|
||||
},
|
||||
Access: access.EmptyProfile{},
|
||||
BlockingMode: &dnsmsg.BlockingModeNullIP{},
|
||||
ID: dnssvctest.ProfileID,
|
||||
DeviceIDs: []agd.DeviceID{dnssvctest.DeviceID},
|
||||
RuleListIDs: []agd.FilterListID{dnssvctest.FilterListID1},
|
||||
FilteredResponseTTL: agdtest.FilteredResponseTTL,
|
||||
FilteringEnabled: true,
|
||||
QueryLogEnabled: true,
|
||||
@ -124,10 +132,10 @@ func newTestService(
|
||||
}
|
||||
|
||||
fltStrg := &agdtest.FilterStorage{
|
||||
OnFilterFromContext: func(_ context.Context, _ *agd.RequestInfo) (f filter.Interface) {
|
||||
OnForConfig: func(_ context.Context, _ filter.Config) (f filter.Interface) {
|
||||
return flt
|
||||
},
|
||||
OnHasListID: func(_ agd.FilterListID) (ok bool) { panic("not implemented") },
|
||||
OnHasListID: func(_ filter.ID) (ok bool) { panic("not implemented") },
|
||||
}
|
||||
|
||||
var ql querylog.Interface = &agdtest.QueryLog{
|
||||
@ -164,7 +172,7 @@ func newTestService(
|
||||
}
|
||||
|
||||
ruleStat := &agdtest.RuleStat{
|
||||
OnCollect: func(_ context.Context, _ agd.FilterListID, text agd.FilterRuleText) {
|
||||
OnCollect: func(_ context.Context, _ filter.ID, text filter.RuleText) {
|
||||
testutil.RequireSend(pt, ruleStatCh, text, dnssvctest.Timeout)
|
||||
},
|
||||
}
|
||||
@ -182,15 +190,25 @@ func newTestService(
|
||||
DDR: &agd.DDR{
|
||||
Enabled: true,
|
||||
},
|
||||
TLS: &agd.TLS{
|
||||
DeviceDomains: []string{dnssvctest.DomainForDevices},
|
||||
},
|
||||
Name: dnssvctest.ServerGroupName,
|
||||
FilteringGroup: dnssvctest.FilteringGroupID,
|
||||
Servers: []*agd.Server{srv},
|
||||
ProfilesEnabled: true,
|
||||
}}
|
||||
|
||||
fltGrp := &agd.FilteringGroup{
|
||||
FilterConfig: &filter.ConfigGroup{
|
||||
Parental: &filter.ConfigParental{},
|
||||
RuleList: &filter.ConfigRuleList{
|
||||
IDs: []filter.ID{dnssvctest.FilterListID1},
|
||||
Enabled: true,
|
||||
},
|
||||
SafeBrowsing: &filter.ConfigSafeBrowsing{},
|
||||
},
|
||||
ID: dnssvctest.FilteringGroupID,
|
||||
}
|
||||
|
||||
hdlrConf := &dnssvc.HandlersConfig{
|
||||
BaseLogger: slogutil.NewDiscardLogger(),
|
||||
Cache: &dnssvc.CacheConfig{
|
||||
@ -227,11 +245,7 @@ func newTestService(
|
||||
RuleStat: ruleStat,
|
||||
MetricsNamespace: path.Base(t.Name()),
|
||||
FilteringGroups: map[agd.FilteringGroupID]*agd.FilteringGroup{
|
||||
dnssvctest.FilteringGroupID: {
|
||||
ID: dnssvctest.FilteringGroupID,
|
||||
RuleListIDs: []agd.FilterListID{dnssvctest.FilterListID1},
|
||||
RuleListsEnabled: true,
|
||||
},
|
||||
dnssvctest.FilteringGroupID: fltGrp,
|
||||
},
|
||||
ServerGroups: srvGrps,
|
||||
EDEEnabled: true,
|
||||
@ -271,7 +285,7 @@ func TestService_Wrap(t *testing.T) {
|
||||
querylogCh := make(chan *querylog.Entry, 1)
|
||||
geoIPCh := make(chan string, 2)
|
||||
dnsDBCh := make(chan *agd.RequestInfo, 1)
|
||||
ruleStatCh := make(chan agd.FilterRuleText, 1)
|
||||
ruleStatCh := make(chan filter.RuleText, 1)
|
||||
|
||||
errCollCh := make(chan error, 1)
|
||||
go func() {
|
||||
@ -291,21 +305,27 @@ func TestService_Wrap(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("simple_success", func(t *testing.T) {
|
||||
noMatch := func(
|
||||
flt := &agdtest.Filter{
|
||||
OnFilterRequest: func(
|
||||
_ context.Context,
|
||||
m *dns.Msg,
|
||||
_ *agd.RequestInfo,
|
||||
fltReq *filter.Request,
|
||||
) (r filter.Result, err error) {
|
||||
pt := testutil.PanicT{}
|
||||
require.NotEmpty(pt, m.Question)
|
||||
require.Equal(pt, dnssvctest.DomainFQDN, m.Question[0].Name)
|
||||
require.NotEmpty(pt, fltReq.DNS.Question)
|
||||
require.Equal(pt, dnssvctest.DomainFQDN, fltReq.DNS.Question[0].Name)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
},
|
||||
OnFilterResponse: func(
|
||||
_ context.Context,
|
||||
fltResp *filter.Response,
|
||||
) (r filter.Result, err error) {
|
||||
pt := testutil.PanicT{}
|
||||
require.NotEmpty(pt, fltResp.DNS.Question)
|
||||
require.Equal(pt, dnssvctest.DomainFQDN, fltResp.DNS.Question[0].Name)
|
||||
|
||||
flt := &agdtest.Filter{
|
||||
OnFilterRequest: noMatch,
|
||||
OnFilterResponse: noMatch,
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
|
||||
svc, srvAddr := newTestService(
|
||||
@ -346,13 +366,13 @@ func TestService_Wrap(t *testing.T) {
|
||||
|
||||
dnsDBReqInfo := <-dnsDBCh
|
||||
assert.NotNil(t, dnsDBReqInfo)
|
||||
assert.Equal(t, agd.FilterRuleText(""), <-ruleStatCh)
|
||||
assert.Equal(t, filter.RuleText(""), <-ruleStatCh)
|
||||
})
|
||||
|
||||
t.Run("request_cname", func(t *testing.T) {
|
||||
const (
|
||||
cname = "cname.example.org"
|
||||
cnameRule agd.FilterRuleText = "||" + dnssvctest.Domain + "^$dnsrewrite=" + cname
|
||||
cnameRule filter.RuleText = "||" + dnssvctest.Domain + "^$dnsrewrite=" + cname
|
||||
)
|
||||
|
||||
cnameFQDN := dns.Fqdn(cname)
|
||||
@ -360,11 +380,10 @@ func TestService_Wrap(t *testing.T) {
|
||||
flt := &agdtest.Filter{
|
||||
OnFilterRequest: func(
|
||||
_ context.Context,
|
||||
m *dns.Msg,
|
||||
_ *agd.RequestInfo,
|
||||
fltReq *filter.Request,
|
||||
) (r filter.Result, err error) {
|
||||
// Pretend a CNAME rewrite matched the request.
|
||||
mod := dnsmsg.Clone(m)
|
||||
mod := dnsmsg.Clone(fltReq.DNS)
|
||||
mod.Question[0].Name = cnameFQDN
|
||||
|
||||
return &filter.ResultModifiedRequest{
|
||||
@ -373,11 +392,7 @@ func TestService_Wrap(t *testing.T) {
|
||||
Rule: cnameRule,
|
||||
}, nil
|
||||
},
|
||||
OnFilterResponse: func(
|
||||
_ context.Context,
|
||||
_ *dns.Msg,
|
||||
_ *agd.RequestInfo,
|
||||
) (filter.Result, error) {
|
||||
OnFilterResponse: func(_ context.Context, _ *filter.Response) (filter.Result, error) {
|
||||
panic("not implemented")
|
||||
},
|
||||
}
|
||||
|
@ -199,7 +199,8 @@ func TestDefault_Find_byHumanID(t *testing.T) {
|
||||
|
||||
// Use uppercase versions to make sure that the device finder recognizes the
|
||||
// device-type and profile data regardless of the case.
|
||||
extIDStr := "OTR-" + strings.ToUpper(dnssvctest.ProfileIDStr) + "-" + dnssvctest.HumanIDStr + "-!!!"
|
||||
extIDStr := "OTR-" + strings.ToUpper(dnssvctest.ProfileIDStr) + "-" +
|
||||
dnssvctest.HumanIDStr + "-!!!"
|
||||
|
||||
profDB := agdtest.NewProfileDB()
|
||||
profDB.OnCreateAutoDevice = func(
|
||||
|
@ -408,7 +408,12 @@ func BenchmarkDefault(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
sinkDevResult = df.Find(ctx, bc.req, dnssvctest.ClientAddrPort, dnssvctest.ServerAddrPort)
|
||||
sinkDevResult = df.Find(
|
||||
ctx,
|
||||
bc.req,
|
||||
dnssvctest.ClientAddrPort,
|
||||
dnssvctest.ServerAddrPort,
|
||||
)
|
||||
}
|
||||
|
||||
_ = testutil.RequireTypeAssert[*agd.DeviceResultOK](b, sinkDevResult)
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@ -36,8 +37,8 @@ const (
|
||||
|
||||
// Common filtering-rule list ID for tests.
|
||||
const (
|
||||
FilterListID1 agd.FilterListID = FilterListID1Str
|
||||
FilterListID2 agd.FilterListID = FilterListID2Str
|
||||
FilterListID1 filter.ID = FilterListID1Str
|
||||
FilterListID2 filter.ID = FilterListID2Str
|
||||
)
|
||||
|
||||
// Common domains and FQDNs for tests.
|
||||
@ -144,7 +145,9 @@ func NewServer(
|
||||
|
||||
if proto.IsStdEncrypted() {
|
||||
// #nosec G402 -- This is a test helper.
|
||||
srv.TLS = &tls.Config{}
|
||||
srv.TLS = &agd.TLSConfig{
|
||||
Default: &tls.Config{},
|
||||
}
|
||||
}
|
||||
|
||||
switch proto {
|
||||
|
@ -29,6 +29,12 @@ const (
|
||||
// Resolvers for querying the resolver with unknown or absent name.
|
||||
DDRDomain = DDRLabel + "." + ResolverARPADomain
|
||||
|
||||
// ChromePrefetchHost is the hostname that Chrome uses to check if it should
|
||||
// use the Chrome Private Prefetch Proxy feature.
|
||||
//
|
||||
// See https://developer.chrome.com/docs/privacy-security/private-prefetch-proxy-for-network-admins.
|
||||
ChromePrefetchHost = "dns-tunnel-check.googlezip.net"
|
||||
|
||||
// FirefoxCanaryHost is the hostname that Firefox uses to check if it should
|
||||
// use its own DNS-over-HTTPS settings.
|
||||
//
|
||||
@ -251,6 +257,10 @@ func (mw *Middleware) specialDomainHandler(
|
||||
if shouldBlockPrivateRelay(ri, prof) {
|
||||
return mw.handlePrivateRelay, "apple_private_relay"
|
||||
}
|
||||
case ChromePrefetchHost:
|
||||
if shouldBlockChromePrefetch(ri, prof) {
|
||||
return mw.handleChromePrefetch, "chrome_prefetch"
|
||||
}
|
||||
case FirefoxCanaryHost:
|
||||
if shouldBlockFirefoxCanary(ri, prof) {
|
||||
return mw.handleFirefoxCanary, "firefox"
|
||||
@ -262,36 +272,34 @@ func (mw *Middleware) specialDomainHandler(
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
// shouldBlockPrivateRelay returns true if the query is for an Apple Private
|
||||
// Relay check domain and the request information or profile indicates that
|
||||
// Apple Private Relay should be blocked.
|
||||
func shouldBlockPrivateRelay(ri *agd.RequestInfo, prof *agd.Profile) (ok bool) {
|
||||
// shouldBlockChromePrefetch returns true request information or profile
|
||||
// indicate that the Chrome prefetch domain should be blocked.
|
||||
func shouldBlockChromePrefetch(ri *agd.RequestInfo, prof *agd.Profile) (ok bool) {
|
||||
if prof != nil {
|
||||
return prof.BlockPrivateRelay
|
||||
return prof.BlockChromePrefetch
|
||||
}
|
||||
|
||||
return ri.FilteringGroup.BlockPrivateRelay
|
||||
return ri.FilteringGroup.BlockChromePrefetch
|
||||
}
|
||||
|
||||
// handlePrivateRelay responds to Apple Private Relay queries with an NXDOMAIN
|
||||
// response.
|
||||
func (mw *Middleware) handlePrivateRelay(
|
||||
// handleChromePrefetch responds to Chrome prefetch domain queries with an
|
||||
// NXDOMAIN response.
|
||||
func (mw *Middleware) handleChromePrefetch(
|
||||
ctx context.Context,
|
||||
rw dnsserver.ResponseWriter,
|
||||
req *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
) (err error) {
|
||||
metrics.DNSSvcApplePrivateRelayRequestsTotal.Inc()
|
||||
metrics.DNSSvcChromePrefetchRequestsTotal.Inc()
|
||||
|
||||
resp := ri.Messages.NewRespRCode(req, dns.RcodeNameError)
|
||||
err = rw.WriteMsg(ctx, req, resp)
|
||||
|
||||
return errors.Annotate(err, "writing private relay resp: %w")
|
||||
return errors.Annotate(err, "writing chrome prefetch resp: %w")
|
||||
}
|
||||
|
||||
// shouldBlockFirefoxCanary returns true if the query is for a Firefox canary
|
||||
// domain and the request information or profile indicates that Firefox canary
|
||||
// domain should be blocked.
|
||||
// shouldBlockFirefoxCanary returns true request information or profile indicate
|
||||
// that the Firefox canary domain should be blocked.
|
||||
func shouldBlockFirefoxCanary(ri *agd.RequestInfo, prof *agd.Profile) (ok bool) {
|
||||
if prof != nil {
|
||||
return prof.BlockFirefoxCanary
|
||||
@ -315,3 +323,29 @@ func (mw *Middleware) handleFirefoxCanary(
|
||||
|
||||
return errors.Annotate(err, "writing firefox canary resp: %w")
|
||||
}
|
||||
|
||||
// shouldBlockPrivateRelay returns true request information or profile indicate
|
||||
// that the Apple Private Relay domain should be blocked.
|
||||
func shouldBlockPrivateRelay(ri *agd.RequestInfo, prof *agd.Profile) (ok bool) {
|
||||
if prof != nil {
|
||||
return prof.BlockPrivateRelay
|
||||
}
|
||||
|
||||
return ri.FilteringGroup.BlockPrivateRelay
|
||||
}
|
||||
|
||||
// handlePrivateRelay responds to Apple Private Relay queries with an NXDOMAIN
|
||||
// response.
|
||||
func (mw *Middleware) handlePrivateRelay(
|
||||
ctx context.Context,
|
||||
rw dnsserver.ResponseWriter,
|
||||
req *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
) (err error) {
|
||||
metrics.DNSSvcApplePrivateRelayRequestsTotal.Inc()
|
||||
|
||||
resp := ri.Messages.NewRespRCode(req, dns.RcodeNameError)
|
||||
err = rw.WriteMsg(ctx, req, resp)
|
||||
|
||||
return errors.Annotate(err, "writing private relay resp: %w")
|
||||
}
|
||||
|
@ -24,31 +24,36 @@ func TestMiddleware_Wrap_specialDomain(t *testing.T) {
|
||||
var (
|
||||
profAllowed = &agd.Profile{
|
||||
Access: access.EmptyProfile{},
|
||||
BlockPrivateRelay: false,
|
||||
BlockChromePrefetch: false,
|
||||
BlockFirefoxCanary: false,
|
||||
BlockPrivateRelay: false,
|
||||
}
|
||||
|
||||
profBlocked = &agd.Profile{
|
||||
Access: access.EmptyProfile{},
|
||||
BlockPrivateRelay: true,
|
||||
BlockChromePrefetch: true,
|
||||
BlockFirefoxCanary: true,
|
||||
BlockPrivateRelay: true,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
fltGrpAllowed = &agd.FilteringGroup{
|
||||
BlockPrivateRelay: false,
|
||||
BlockChromePrefetch: false,
|
||||
BlockFirefoxCanary: false,
|
||||
BlockPrivateRelay: false,
|
||||
}
|
||||
|
||||
fltGrpBlocked = &agd.FilteringGroup{
|
||||
BlockPrivateRelay: true,
|
||||
BlockChromePrefetch: true,
|
||||
BlockFirefoxCanary: true,
|
||||
BlockPrivateRelay: true,
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
appleHost = initial.ApplePrivateRelayMaskHost
|
||||
chromeHost = initial.ChromePrefetchHost
|
||||
firefoxHost = initial.FirefoxCanaryHost
|
||||
)
|
||||
|
||||
@ -100,29 +105,27 @@ func TestMiddleware_Wrap_specialDomain(t *testing.T) {
|
||||
reqInfo: newSpecDomReqInfo(t, nil, fltGrpBlocked, firefoxHost, dns.TypeA),
|
||||
name: "firefox_canary_blocked_by_fltgrp",
|
||||
wantRCode: dns.RcodeRefused,
|
||||
}, {
|
||||
reqInfo: newSpecDomReqInfo(t, profAllowed, fltGrpAllowed, chromeHost, dns.TypeA),
|
||||
name: "chrome_prefetch_allowed_by_both",
|
||||
wantRCode: dns.RcodeSuccess,
|
||||
}, {
|
||||
reqInfo: newSpecDomReqInfo(t, profBlocked, fltGrpAllowed, chromeHost, dns.TypeA),
|
||||
name: "chrome_prefetch_blocked_by_prof",
|
||||
wantRCode: dns.RcodeNameError,
|
||||
}, {
|
||||
reqInfo: newSpecDomReqInfo(t, nil, fltGrpBlocked, chromeHost, dns.TypeA),
|
||||
name: "chrome_prefetch_blocked_by_fltgrp",
|
||||
wantRCode: dns.RcodeNameError,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var handler dnsserver.Handler = dnsserver.HandlerFunc(func(
|
||||
ctx context.Context,
|
||||
rw dnsserver.ResponseWriter,
|
||||
req *dns.Msg,
|
||||
) (err error) {
|
||||
if tc.wantRCode != dns.RcodeSuccess {
|
||||
return errors.Error("unexpectedly reached handler")
|
||||
}
|
||||
|
||||
resp := (&dns.Msg{}).SetReply(req)
|
||||
|
||||
return rw.WriteMsg(ctx, req, resp)
|
||||
})
|
||||
|
||||
mw := initial.New(&initial.Config{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
|
||||
h := mw.Wrap(handler)
|
||||
h := mw.Wrap(newSpecDomHandler(tc.wantRCode == dns.RcodeSuccess))
|
||||
|
||||
ctx := testutil.ContextWithTimeout(t, dnssvctest.Timeout)
|
||||
ctx = agd.ContextWithRequestInfo(ctx, tc.reqInfo)
|
||||
@ -185,3 +188,21 @@ func newSpecDomReqInfo(
|
||||
|
||||
return ri
|
||||
}
|
||||
|
||||
// newSpecDomHandler is a helper that creates a DNS handler for the
|
||||
// special-domain tests. The handler returns an error if wantReach is false.
|
||||
func newSpecDomHandler(wantReach bool) (h dnsserver.Handler) {
|
||||
return dnsserver.HandlerFunc(func(
|
||||
ctx context.Context,
|
||||
rw dnsserver.ResponseWriter,
|
||||
req *dns.Msg,
|
||||
) (err error) {
|
||||
if !wantReach {
|
||||
return errors.Error("unexpectedly reached handler")
|
||||
}
|
||||
|
||||
resp := (&dns.Msg{}).SetReply(req)
|
||||
|
||||
return rw.WriteMsg(ctx, req, resp)
|
||||
})
|
||||
}
|
||||
|
@ -221,7 +221,10 @@ func TestMiddleware_writeDebugResponse(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
rw := dnsserver.NewNonWriterResponseWriter(dnssvctest.ServerTCPAddr, dnssvctest.ClientTCPAddr)
|
||||
rw := dnsserver.NewNonWriterResponseWriter(
|
||||
dnssvctest.ServerTCPAddr,
|
||||
dnssvctest.ClientTCPAddr,
|
||||
)
|
||||
|
||||
ctx := agd.ContextWithRequestInfo(context.Background(), tc.reqInfo)
|
||||
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@ -57,9 +58,12 @@ func (mw *Middleware) filterRequest(
|
||||
) {
|
||||
start := time.Now()
|
||||
|
||||
reqRes, err := f.FilterRequest(ctx, fctx.originalRequest, ri)
|
||||
fltReq := mw.reqInfoToFltReq(fctx.originalRequest, ri)
|
||||
defer mw.putFltReq(fltReq)
|
||||
|
||||
reqRes, err := f.FilterRequest(ctx, fltReq)
|
||||
if err != nil {
|
||||
mw.reportf(ctx, "filtering request: %w", err)
|
||||
errcoll.Collect(ctx, mw.errColl, mw.logger, "filtering request", err)
|
||||
}
|
||||
|
||||
if mod, ok := reqRes.(*filter.ResultModifiedRequest); ok {
|
||||
@ -70,6 +74,38 @@ func (mw *Middleware) filterRequest(
|
||||
fctx.elapsed += time.Since(start)
|
||||
}
|
||||
|
||||
// reqInfoToFltReq converts data from a DNS request and request info into a
|
||||
// *filter.Request. The returned request data should be put back into the pool
|
||||
// by using [Middleware.putFltReq].
|
||||
func (mw *Middleware) reqInfoToFltReq(req *dns.Msg, ri *agd.RequestInfo) (fltReq *filter.Request) {
|
||||
fltReq = mw.fltReqPool.Get()
|
||||
|
||||
// NOTE: Fill all fields of fltReq since it is reused from the pool.
|
||||
fltReq.DNS = req
|
||||
fltReq.Messages = ri.Messages
|
||||
fltReq.RemoteIP = ri.RemoteIP
|
||||
|
||||
if _, d := ri.DeviceData(); d != nil {
|
||||
fltReq.ClientName = string(d.Name)
|
||||
} else {
|
||||
fltReq.ClientName = ""
|
||||
}
|
||||
|
||||
fltReq.Host = ri.Host
|
||||
fltReq.QType = ri.QType
|
||||
fltReq.QClass = ri.QClass
|
||||
|
||||
return fltReq
|
||||
}
|
||||
|
||||
// putFltReq sets req.DNS to nil, to prevent the message being contained in the
|
||||
// pool, which can lead to conflicts with the cloner of the middleware, and puts
|
||||
// req back into the pool.
|
||||
func (mw *Middleware) putFltReq(req *filter.Request) {
|
||||
req.DNS = nil
|
||||
mw.fltReqPool.Put(req)
|
||||
}
|
||||
|
||||
// filterResponse applies f to resp and sets the result of filtering in fctx.
|
||||
// If origReq has a different question name than resp, the request assumed being
|
||||
// CNAME-rewritten and no filtering performed on resp, the CNAME is prepended to
|
||||
@ -95,9 +131,12 @@ func (mw *Middleware) filterResponse(
|
||||
var rr dns.RR = ri.Messages.NewAnswerCNAME(origReq, modReq.Question[0].Name)
|
||||
origResp.Answer = slices.Insert(origResp.Answer, 0, rr)
|
||||
} else {
|
||||
respRes, err := f.FilterResponse(ctx, fctx.originalResponse, ri)
|
||||
fltResp := mw.reqInfoToFltResp(fctx.originalResponse, ri)
|
||||
defer mw.putFltResp(fltResp)
|
||||
|
||||
respRes, err := f.FilterResponse(ctx, fltResp)
|
||||
if err != nil {
|
||||
mw.reportf(ctx, "filtering response: %w", err)
|
||||
errcoll.Collect(ctx, mw.errColl, mw.logger, "filtering response", err)
|
||||
}
|
||||
|
||||
fctx.responseResult = respRes
|
||||
@ -106,11 +145,41 @@ func (mw *Middleware) filterResponse(
|
||||
fctx.elapsed += time.Since(start)
|
||||
}
|
||||
|
||||
// reqInfoToFltResp converts data from a DNS response and request info into a
|
||||
// *filter.Response. The returned response data should be put back into
|
||||
// the pool by using [Middleware.putFltResp].
|
||||
func (mw *Middleware) reqInfoToFltResp(
|
||||
resp *dns.Msg,
|
||||
ri *agd.RequestInfo,
|
||||
) (fltResp *filter.Response) {
|
||||
fltResp = mw.fltRespPool.Get()
|
||||
|
||||
// NOTE: Fill all fields of fltResp since it is reused from the pool.
|
||||
fltResp.DNS = resp
|
||||
fltResp.RemoteIP = ri.RemoteIP
|
||||
|
||||
if _, d := ri.DeviceData(); d != nil {
|
||||
fltResp.ClientName = string(d.Name)
|
||||
} else {
|
||||
fltResp.ClientName = ""
|
||||
}
|
||||
|
||||
return fltResp
|
||||
}
|
||||
|
||||
// putFltResp sets resp.DNS to nil, to prevent the message being contained in
|
||||
// the pool, which can lead to conflicts with the cloner of the middleware, and
|
||||
// puts resp back into the pool.
|
||||
func (mw *Middleware) putFltResp(resp *filter.Response) {
|
||||
resp.DNS = nil
|
||||
mw.fltRespPool.Put(resp)
|
||||
}
|
||||
|
||||
// filteringData returns the data necessary for request information recording
|
||||
// from the filtering context.
|
||||
func filteringData(
|
||||
fctx *filteringContext,
|
||||
) (id agd.FilterListID, text agd.FilterRuleText, blocked bool) {
|
||||
) (id filter.ID, text filter.RuleText, blocked bool) {
|
||||
if fctx.requestResult != nil {
|
||||
return resultData(fctx.requestResult, "reqRes")
|
||||
}
|
||||
@ -123,9 +192,9 @@ func filteringData(
|
||||
func resultData(
|
||||
res filter.Result,
|
||||
argName string,
|
||||
) (id agd.FilterListID, text agd.FilterRuleText, blocked bool) {
|
||||
) (id filter.ID, text filter.RuleText, blocked bool) {
|
||||
if res == nil {
|
||||
return agd.FilterListIDNone, "", false
|
||||
return filter.IDNone, "", false
|
||||
}
|
||||
|
||||
id, text = res.MatchedRule()
|
||||
@ -164,7 +233,13 @@ func (mw *Middleware) setFilteredResponse(
|
||||
var err error
|
||||
fctx.filteredResponse, err = ri.Messages.NewBlockedResp(fctx.originalRequest)
|
||||
if err != nil {
|
||||
mw.reportf(ctx, "creating blocked resp for filtered req: %w", err)
|
||||
errcoll.Collect(
|
||||
ctx,
|
||||
mw.errColl,
|
||||
mw.logger,
|
||||
"creating blocked resp for filtered req",
|
||||
err,
|
||||
)
|
||||
fctx.filteredResponse = fctx.originalResponse
|
||||
}
|
||||
case *filter.ResultAllowed, *filter.ResultModifiedRequest:
|
||||
@ -201,7 +276,13 @@ func (mw *Middleware) setFilteredResponseNoReq(
|
||||
var err error
|
||||
fctx.filteredResponse, err = ri.Messages.NewBlockedResp(fctx.originalRequest)
|
||||
if err != nil {
|
||||
mw.reportf(ctx, "creating blocked resp for filtered resp: %w", err)
|
||||
errcoll.Collect(
|
||||
ctx,
|
||||
mw.errColl,
|
||||
mw.logger,
|
||||
"creating blocked resp for filtered resp",
|
||||
err,
|
||||
)
|
||||
fctx.filteredResponse = fctx.originalResponse
|
||||
}
|
||||
default:
|
||||
|
@ -27,6 +27,8 @@ import (
|
||||
type Middleware struct {
|
||||
cloner *dnsmsg.Cloner
|
||||
fltCtxPool *syncutil.Pool[filteringContext]
|
||||
fltReqPool *syncutil.Pool[filter.Request]
|
||||
fltRespPool *syncutil.Pool[filter.Response]
|
||||
logger *slog.Logger
|
||||
messages *dnsmsg.Constructor
|
||||
billStat billstat.Recorder
|
||||
@ -84,6 +86,12 @@ func New(c *Config) (mw *Middleware) {
|
||||
fltCtxPool: syncutil.NewPool(func() (v *filteringContext) {
|
||||
return &filteringContext{}
|
||||
}),
|
||||
fltReqPool: syncutil.NewPool(func() (v *filter.Request) {
|
||||
return &filter.Request{}
|
||||
}),
|
||||
fltRespPool: syncutil.NewPool(func() (v *filter.Response) {
|
||||
return &filter.Response{}
|
||||
}),
|
||||
logger: c.Logger,
|
||||
messages: c.Messages,
|
||||
billStat: c.BillStat,
|
||||
@ -125,7 +133,7 @@ func (mw *Middleware) Wrap(next dnsserver.Handler) (wrapped dnsserver.Handler) {
|
||||
"remote_ip", ri.RemoteIP,
|
||||
)
|
||||
|
||||
flt := mw.fltStrg.FilterFromContext(ctx, ri)
|
||||
flt := mw.filter(ctx, ri)
|
||||
mw.filterRequest(ctx, fctx, flt, ri)
|
||||
|
||||
// Check the context error here, since the context could have already
|
||||
@ -171,6 +179,20 @@ func (mw *Middleware) Wrap(next dnsserver.Handler) (wrapped dnsserver.Handler) {
|
||||
return dnsserver.HandlerFunc(f)
|
||||
}
|
||||
|
||||
// filter returns a filter based on the request information.
|
||||
func (mw *Middleware) filter(ctx context.Context, ri *agd.RequestInfo) (f filter.Interface) {
|
||||
p, d := ri.DeviceData()
|
||||
if p == nil {
|
||||
return mw.fltStrg.ForConfig(ctx, ri.FilteringGroup.FilterConfig)
|
||||
}
|
||||
|
||||
if p.FilteringEnabled && d.FilteringEnabled {
|
||||
return mw.fltStrg.ForConfig(ctx, p.FilterConfig)
|
||||
}
|
||||
|
||||
return mw.fltStrg.ForConfig(ctx, nil)
|
||||
}
|
||||
|
||||
// nextParams is a helper that returns the parameters to call the next handler
|
||||
// with taking the filtering context into account.
|
||||
func (mw *Middleware) nextParams(
|
||||
@ -239,8 +261,3 @@ func (mw *Middleware) reportMetrics(
|
||||
IsBlocked: isBlocked,
|
||||
})
|
||||
}
|
||||
|
||||
// reportf is a helper method for reporting non-critical errors.
|
||||
func (mw *Middleware) reportf(ctx context.Context, format string, args ...any) {
|
||||
errcoll.Collectf(ctx, mw.errColl, "mainmw: "+format, args...)
|
||||
}
|
||||
|
@ -34,12 +34,12 @@ const (
|
||||
testRespAddr4Str = "3.4.5.6"
|
||||
testRewriteAddrStr = "7.8.9.0"
|
||||
|
||||
testRuleAllow agd.FilterRuleText = "@@||" + dnssvctest.DomainAllowed + "^"
|
||||
testRuleBlockReq agd.FilterRuleText = "||" + dnssvctest.DomainBlocked + "^"
|
||||
testRuleBlockResp agd.FilterRuleText = "||" + testRespAddr4Str + "^"
|
||||
testRuleRewrite agd.FilterRuleText = "||" + dnssvctest.DomainRewritten +
|
||||
testRuleAllow filter.RuleText = "@@||" + dnssvctest.DomainAllowed + "^"
|
||||
testRuleBlockReq filter.RuleText = "||" + dnssvctest.DomainBlocked + "^"
|
||||
testRuleBlockResp filter.RuleText = "||" + testRespAddr4Str + "^"
|
||||
testRuleRewrite filter.RuleText = "||" + dnssvctest.DomainRewritten +
|
||||
"^$dnsrewrite=NOERROR;A;" + testRewriteAddrStr
|
||||
testRuleRewriteCNAME agd.FilterRuleText = "||" + dnssvctest.DomainRewritten +
|
||||
testRuleRewriteCNAME filter.RuleText = "||" + dnssvctest.DomainRewritten +
|
||||
"^$dnsrewrite=NOERROR;CNAME;" + dnssvctest.DomainRewrittenCNAME
|
||||
)
|
||||
|
||||
@ -96,25 +96,23 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
flt := &agdtest.Filter{
|
||||
OnFilterRequest: func(
|
||||
_ context.Context,
|
||||
_ *dns.Msg,
|
||||
_ *agd.RequestInfo,
|
||||
_ *filter.Request,
|
||||
) (r filter.Result, err error) {
|
||||
return nil, nil
|
||||
},
|
||||
OnFilterResponse: func(
|
||||
_ context.Context,
|
||||
_ *dns.Msg,
|
||||
_ *agd.RequestInfo,
|
||||
_ *filter.Response,
|
||||
) (r filter.Result, err error) {
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
|
||||
fltStrg := &agdtest.FilterStorage{
|
||||
OnFilterFromContext: func(_ context.Context, _ *agd.RequestInfo) (f filter.Interface) {
|
||||
OnForConfig: func(_ context.Context, _ filter.Config) (f filter.Interface) {
|
||||
return flt
|
||||
},
|
||||
OnHasListID: func(_ agd.FilterListID) (ok bool) { panic("not implemented") },
|
||||
OnHasListID: func(_ filter.ID) (ok bool) { panic("not implemented") },
|
||||
}
|
||||
|
||||
geoIP := agdtest.NewGeoIP()
|
||||
@ -131,10 +129,10 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
}
|
||||
|
||||
ruleStat := &agdtest.RuleStat{
|
||||
OnCollect: func(_ context.Context, id agd.FilterListID, text agd.FilterRuleText) {
|
||||
OnCollect: func(_ context.Context, id filter.ID, text filter.RuleText) {
|
||||
pt := testutil.PanicT{}
|
||||
require.Equal(pt, agd.FilterListID(""), id)
|
||||
require.Equal(pt, agd.FilterRuleText(""), text)
|
||||
require.Equal(pt, filter.ID(""), id)
|
||||
require.Equal(pt, filter.RuleText(""), text)
|
||||
},
|
||||
}
|
||||
|
||||
@ -238,7 +236,10 @@ func TestMiddleware_Wrap(t *testing.T) {
|
||||
h := mw.Wrap(newSimpleHandler(t, tc.req, wantResp))
|
||||
|
||||
ctx := newContext(t, tc.device, tc.profile, reqHost, reqQType, reqStart)
|
||||
rw := dnsserver.NewNonWriterResponseWriter(dnssvctest.ServerTCPAddr, dnssvctest.ClientTCPAddr)
|
||||
rw := dnsserver.NewNonWriterResponseWriter(
|
||||
dnssvctest.ServerTCPAddr,
|
||||
dnssvctest.ClientTCPAddr,
|
||||
)
|
||||
|
||||
serveErr := h.ServeDNS(ctx, rw, tc.req)
|
||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, serveErr)
|
||||
@ -332,6 +333,19 @@ func newContext(
|
||||
ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{
|
||||
StartTime: start,
|
||||
})
|
||||
|
||||
fltConf := &filter.ConfigGroup{
|
||||
Parental: &filter.ConfigParental{},
|
||||
RuleList: &filter.ConfigRuleList{
|
||||
IDs: []filter.ID{
|
||||
dnssvctest.FilterListID1,
|
||||
dnssvctest.FilterListID2,
|
||||
},
|
||||
Enabled: true,
|
||||
},
|
||||
SafeBrowsing: &filter.ConfigSafeBrowsing{},
|
||||
}
|
||||
|
||||
ctx = agd.ContextWithRequestInfo(ctx, &agd.RequestInfo{
|
||||
DeviceResult: &agd.DeviceResultOK{
|
||||
Device: d,
|
||||
@ -342,11 +356,7 @@ func newContext(
|
||||
ASN: testASN,
|
||||
},
|
||||
FilteringGroup: &agd.FilteringGroup{
|
||||
RuleListIDs: []agd.FilterListID{
|
||||
dnssvctest.FilterListID1,
|
||||
dnssvctest.FilterListID2,
|
||||
},
|
||||
RuleListsEnabled: true,
|
||||
FilterConfig: fltConf,
|
||||
},
|
||||
Messages: agdtest.NewConstructor(tb),
|
||||
RemoteIP: dnssvctest.ClientAddr,
|
||||
@ -540,7 +550,7 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
|
||||
respRes filter.Result
|
||||
name string
|
||||
wantErrMsg string
|
||||
wantRule agd.FilterRuleText
|
||||
wantRule filter.RuleText
|
||||
}{{
|
||||
req: reqAllow,
|
||||
device: nil,
|
||||
@ -641,28 +651,23 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
|
||||
flt := &agdtest.Filter{
|
||||
OnFilterRequest: func(
|
||||
_ context.Context,
|
||||
_ *dns.Msg,
|
||||
_ *agd.RequestInfo,
|
||||
_ *filter.Request,
|
||||
) (r filter.Result, err error) {
|
||||
return tc.reqRes, nil
|
||||
},
|
||||
OnFilterResponse: func(
|
||||
_ context.Context,
|
||||
_ *dns.Msg,
|
||||
_ *agd.RequestInfo,
|
||||
_ *filter.Response,
|
||||
) (r filter.Result, err error) {
|
||||
return tc.respRes, nil
|
||||
},
|
||||
}
|
||||
|
||||
fltStrg := &agdtest.FilterStorage{
|
||||
OnFilterFromContext: func(
|
||||
_ context.Context,
|
||||
_ *agd.RequestInfo,
|
||||
) (f filter.Interface) {
|
||||
OnForConfig: func(_ context.Context, _ filter.Config) (f filter.Interface) {
|
||||
return flt
|
||||
},
|
||||
OnHasListID: func(_ agd.FilterListID) (ok bool) { panic("not implemented") },
|
||||
OnHasListID: func(_ filter.ID) (ok bool) { panic("not implemented") },
|
||||
}
|
||||
|
||||
q := tc.req.Question[0]
|
||||
@ -680,7 +685,7 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
|
||||
}
|
||||
|
||||
ruleStat := &agdtest.RuleStat{
|
||||
OnCollect: func(_ context.Context, id agd.FilterListID, text agd.FilterRuleText) {
|
||||
OnCollect: func(_ context.Context, id filter.ID, text filter.RuleText) {
|
||||
pt := testutil.PanicT{}
|
||||
require.Equal(pt, dnssvctest.FilterListID1, id)
|
||||
require.Equal(pt, tc.wantRule, text)
|
||||
@ -705,7 +710,10 @@ func TestMiddleware_Wrap_filtering(t *testing.T) {
|
||||
h := mw.Wrap(newSimpleHandler(t, tc.wantUpsReq, tc.upsResp))
|
||||
|
||||
ctx := newContext(t, tc.device, tc.profile, reqHost, reqQType, reqStart)
|
||||
rw := dnsserver.NewNonWriterResponseWriter(dnssvctest.ServerTCPAddr, dnssvctest.ClientTCPAddr)
|
||||
rw := dnsserver.NewNonWriterResponseWriter(
|
||||
dnssvctest.ServerTCPAddr,
|
||||
dnssvctest.ClientTCPAddr,
|
||||
)
|
||||
|
||||
serveErr := h.ServeDNS(ctx, rw, tc.req)
|
||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, serveErr)
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
|
||||
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
|
||||
"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"
|
||||
@ -87,7 +88,7 @@ func (mw *Middleware) recordQueryInfo(
|
||||
err := mw.queryLog.Write(ctx, e)
|
||||
if err != nil {
|
||||
// Consider query logging errors non-critical.
|
||||
mw.reportf(ctx, "writing query log: %w", err)
|
||||
errcoll.Collect(ctx, mw.errColl, mw.logger, "writing query log", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +139,7 @@ func (mw *Middleware) responseData(
|
||||
|
||||
ip, err := ipFromAnswer(resp.Answer)
|
||||
if err != nil {
|
||||
mw.reportf(ctx, "getting response data: %w", err)
|
||||
errcoll.Collect(ctx, mw.errColl, mw.logger, "getting response data", err)
|
||||
}
|
||||
|
||||
return rcode, ip, dnssec
|
||||
@ -228,7 +229,7 @@ func (mw *Middleware) country(ctx context.Context, host string, ip netip.Addr) (
|
||||
l, err := mw.geoIP.Data(host, ip)
|
||||
if err != nil {
|
||||
// Consider GeoIP errors non-critical.
|
||||
mw.reportf(ctx, "getting geoip data: %w", err)
|
||||
errcoll.Collect(ctx, mw.errColl, mw.logger, "getting geoip data", err)
|
||||
}
|
||||
|
||||
if l != nil {
|
||||
|
@ -42,7 +42,7 @@ func TestMiddleware_Wrap_access(t *testing.T) {
|
||||
blockedClient2Prefix = netip.MustParsePrefix("2001:db8::/120")
|
||||
)
|
||||
|
||||
accessMgr, errAccess := access.NewGlobal(
|
||||
accessMgr, accessErr := access.NewGlobal(
|
||||
[]string{
|
||||
domainBlockedNormal,
|
||||
domainBlockedUppercase,
|
||||
@ -53,7 +53,7 @@ func TestMiddleware_Wrap_access(t *testing.T) {
|
||||
blockedClient2Prefix,
|
||||
},
|
||||
)
|
||||
require.NoError(t, errAccess)
|
||||
require.NoError(t, accessErr)
|
||||
|
||||
geoIP := agdtest.NewGeoIP()
|
||||
geoIP.OnData = func(_ string, _ netip.Addr) (l *geoip.Location, err error) {
|
||||
@ -154,9 +154,11 @@ func TestMiddleware_Wrap_access(t *testing.T) {
|
||||
qtype: dns.TypeAAAA,
|
||||
}}
|
||||
|
||||
handler := dnsserver.HandlerFunc(func(ctx context.Context, rw dnsserver.ResponseWriter, req *dns.Msg) (_ error) {
|
||||
handler := dnsserver.HandlerFunc(
|
||||
func(ctx context.Context, rw dnsserver.ResponseWriter, req *dns.Msg) (err error) {
|
||||
return rw.WriteMsg(ctx, req, dnsservertest.NewResp(dns.RcodeSuccess, req))
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
@ -15,10 +15,10 @@ var msgSink *dns.Msg
|
||||
func BenchmarkMiddleware_Get(b *testing.B) {
|
||||
mw := &Middleware{
|
||||
cache: agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
|
||||
Size: 10,
|
||||
Count: 10,
|
||||
}),
|
||||
ecsCache: agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
|
||||
Size: 10,
|
||||
Count: 10,
|
||||
}),
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -91,10 +91,10 @@ type MiddlewareConfig struct {
|
||||
// manager. c must not be nil.
|
||||
func NewMiddleware(c *MiddlewareConfig) (m *Middleware) {
|
||||
cache := agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
|
||||
Size: c.NoECSCount,
|
||||
Count: c.NoECSCount,
|
||||
})
|
||||
ecsCache := agdcache.NewLRU[uint64, *cacheItem](&agdcache.LRUConfig{
|
||||
Size: c.ECSCount,
|
||||
Count: c.ECSCount,
|
||||
})
|
||||
|
||||
c.CacheManager.Add(cacheIDNoECS, cache)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user