Sync v2.6.0

This commit is contained in:
Andrey Meshkov 2024-03-11 12:21:07 +03:00
parent 150f2d733f
commit b6e37914aa
77 changed files with 3443 additions and 2858 deletions

View File

@ -11,6 +11,49 @@ The format is **not** based on [Keep a Changelog][kec], since the project
## AGDNS-1954 / Build 719
* The objects within `server_groups` array have a new property
`block_page_redirect`:
```yaml
block_page_redirect:
enabled: true
ipv4:
- address: '127.0.0.1'
- address: '127.0.0.2'
ipv6:
- address: '::1'
- address: '::2'
apply:
client:
- address: '192.168.0.0/16'
- address: '1.2.3.4'
skip:
client:
- address: '1.2.0.0/16'
question:
- domain: 'do-not-show-block.site.example'
probability: 0.01
```
For server groups that do not require a block-page redirect, set:
```yaml
block_page_redirect:
enabled: false
```
## AGDNS-1888 / Build 717
* The new environment variable `PROFILES_ENABLED` has been added. With `0`
value it disables user profiles and devices recognition, and billing. Its
default value is `1`. Adjust the value, if necessary.
## AGDNS-1761 / Build 702
* The property `upstream` has been modified. Its property `timeout` has been

View File

@ -8,7 +8,7 @@
# Makefile. Bump this number every time a significant change is made to
# this Makefile.
#
# AdGuard-Project-Version: 2
# AdGuard-Project-Version: 4
# Don't name these macros "GO" etc., because GNU Make apparently makes
# them exported environment variables with the literal value of
@ -23,7 +23,7 @@ VERBOSE.MACRO = $${VERBOSE:-0}
BRANCH = $$( git rev-parse --abbrev-ref HEAD )
GOAMD64 = v1
GOPROXY = https://goproxy.cn|https://proxy.golang.org|direct
GOTOOLCHAIN = go1.21.5
GOTOOLCHAIN = go1.21.8
RACE = 0
REVISION = $$( git rev-parse --short HEAD )
VERSION = 0
@ -59,6 +59,8 @@ go-lint: ; $(ENV) "$(SHELL)" ./scripts/make/go-lint.sh
go-test: ; $(ENV) RACE='1' "$(SHELL)" ./scripts/make/go-test.sh
go-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-tools.sh
go-upd-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-upd-tools.sh
go-check: go-tools go-lint go-test
# A quick check to make sure that all operating systems relevant to the
@ -73,11 +75,4 @@ go-os-check:
txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh
# TODO(a.garipov): Consider adding to scripts/ and the common project
# structure.
go-upd-tools:
cd ./internal/tools/ &&\
"$(GO.MACRO)" get -u &&\
"$(GO.MACRO)" mod tidy
sync-github: ; $(ENV) "$(SHELL)" ./scripts/make/github-sync.sh

View File

@ -274,7 +274,7 @@ filters:
# FILTER_INDEX_URL environment variable.
refresh_interval: 1h
# The timeout for the entire filter update operation. Be aware that each
# individual refresh operation also has its own hardcoded 30s timeout.
# individual refresh operation also has its own hardcoded 3m timeout.
refresh_timeout: 5m
# MaxSize is the maximum size of the downloadable filtering rule-list.
max_size: 256MB
@ -351,15 +351,38 @@ server_groups:
- name: 'adguard_dns_default'
# This filtering_group is used for all anonymous clients.
filtering_group: 'default'
tls:
certificates:
- certificate: './test/cert.crt'
key: './test/cert.key'
session_keys:
- './test/tls_key_1'
- './test/tls_key_2'
device_id_wildcards:
- '*.dns.example.com'
# Settings for redirection to a block page.
block_page_redirect:
# If enabled is false, other fields can be skipped.
enabled: true
# Addresses to use for A queries. If enabled is true, ipv4, ipv6, or
# both must be filled.
ipv4:
- address: '127.0.0.1'
- address: '127.0.0.2'
# Addresses to use for AAAA queries. If enabled is true, ipv4, ipv6, or
# both must be filled.
ipv6:
- address: '::1'
- address: '::2'
# Request parameters based on which the block page is always shown. For
# requests matching these parameters, both skip and probability are
# ignored.
apply:
client:
- address: '192.168.0.0/16'
- address: '1.2.3.4'
# Request parameters based on which the block page is never shown. For
# requests matching these parameters, probability is ignored.
skip:
client:
- address: '1.2.0.0/16'
- address: '5.6.7.8'
question:
- domain: 'do-not-show-block.site.example'
# The probability of responding with the block page IPs based on remote
# address. Must be between 0.0 and 1.0.
probability: 0.01
ddr:
enabled: true
# Device ID domain name suffix to DDR record template mapping. Keep in
@ -386,6 +409,15 @@ server_groups:
- '127.0.0.1'
ipv6_hints:
- '::1'
tls:
certificates:
- certificate: './test/cert.crt'
key: './test/cert.key'
session_keys:
- './test/tls_key_1'
- './test/tls_key_2'
device_id_wildcards:
- '*.dns.example.com'
servers:
- name: 'default_dns'
# See README for the list of protocol values.

View File

@ -28,8 +28,9 @@ configuration file with comments.
* [Filtering groups](#filtering_groups)
* [Network interface listeners](#interface_listeners)
* [Server groups](#server_groups)
* [TLS](#server_groups-*-tls)
* [Block-page redirecting](#server_groups-*-block_page_redirect)
* [DDR](#server_groups-*-ddr)
* [TLS](#server_groups-*-tls)
* [Servers](#server_groups-*-servers-*)
* [Connectivity check](#connectivity-check)
* [Network settings](#network)
@ -108,9 +109,10 @@ Currently, there are the following recommendations for parameters
TCP sockets. That is, if the instance currently has a maximum of 100 000
TCP sockets in use every day, `resume` should be set to about `120000`.
**NOTE:** The number of active stream-connections includes sockets that are
in the process of accepting new connections but have not yet accepted one. That
means that `resume` should be greater than the number of bound addresses.
> [!NOTE]
> The number of active stream-connections includes sockets that are in the
> process of accepting new connections but have not yet accepted one. That
> means that `resume` should be greater than the number of bound addresses.
These recommendations are to be revised based on the metrics.
@ -776,7 +778,7 @@ The `filters` object has the following properties:
* <a href="#filters-refresh_timeout" id="filters-refresh_timeout" name="filters-refresh_timeout">`refresh_timeout`</a>:
The timeout for the *entire* filter update operation, as a human-readable
duration. Be aware that each individual refresh operation also has its own
hardcoded 30s timeout.
hardcoded 3m timeout.
**Example:** `5m`.
@ -890,9 +892,10 @@ The items of the `filtering_groups` array have the following properties:
## <a href="#interface_listeners" id="interface_listeners" name="interface_listeners">Network interface listeners</a>
**NOTE:** The network interface listening works only on Linux with
`SO_BINDTODEVICE` support (2.0.30 and later) and properly setup IP routes. See
the [section on testing `SO_BINDTODEVICE` using Docker][dev-btd].
> [!NOTE]
> The network interface listening works only on Linux with `SO_BINDTODEVICE`
> support (2.0.30 and later) and properly setup IP routes. See the [section
> on testing `SO_BINDTODEVICE` using Docker][dev-btd].
The `interface_listeners` object has the following properties:
@ -936,52 +939,83 @@ The items of the `server_groups` array have the following properties:
**Example:** `default`.
* `tls`: The optional TLS configuration object. See
[below](#server_groups-*-tls).
* `block_page_redirect`: The block-page redirect configuration object. See
[below](#server_groups-*-block_page_redirect).
* `ddr`: The DDR configuration object. See [below](#server_groups-*-ddr).
* `tls`: The TLS configuration object. See [below](#server_groups-*-tls).
> [!NOTE]
> The `tls` object is optional unless the [`servers`
> array](#server_groups-*-servers-*) contains at least one item with an
> encrypted protocol.
* `servers`: Server configuration for this filtering group. See
[below](#server_groups-*-servers-*).
### <a href="#server_groups-*-tls" id="server_groups-*-tls" name="server_groups-*-tls">TLS</a>
### <a href="#server_groups-*-block_page_redirect" id="server_groups-*-block_page_redirect" name="server_groups-*-block_page_redirect">Block-page redirecting</a>
* <a href="#sg-*-tls-certificates" id="sg-*-tls-certificates" name="sg-*-tls-certificates">`certificates`</a>:
The array of objects with paths to the certificate and the private key for
this server group.
The block-page redirect configuration object. If enabled, AdGuard DNS responds
with the configured IP addresses to “redirect” users to an informative block
page.
* <a href="#sg-*-bpr-enabled" id="sg-*-bpr-enabled" name="sg-*-bpr-enabled">`enabled`</a>:
Shows if the block-page redirect is enabled. If `false`, the fields below
can be skipped.
* <a href="#sg-*-bpr-ipv4" id="sg-*-bpr-ipv4" name="sg-*-bpr-ipv4">`ipv4`</a>:
Arrays of IPv4 addresses with which to respond to blocked `A` queries.
If `enabled` is true, `ipv4`, `ipv6`, or both must be filled.
* <a href="#sg-*-bpr-ipv6" id="sg-*-bpr-ipv6" name="sg-*-bpr-ipv6">`ipv6`</a>:
Arrays of IPv6 addresses with which to respond to blocked `AAAA` queries.
If `enabled` is true, `ipv4`, `ipv6`, or both must be filled.
* <a href="#sg-*-bpr-apply" id="sg-*-bpr-apply" name="sg-*-bpr-apply">`apply`</a>:
Request parameters based on which the block-page redirect is always
performed. For requests matching these parameters, both `skip` and
`probability` are
ignored.
**Property example:**
```yaml
'certificates':
- 'certificate': '/etc/dns/cert.crt'
'key': '/etc/dns/cert.key'
apply:
client:
- address: '192.168.0.0/16'
- address: '1.2.3.4'
```
* <a href="#sg-*-tls-session_keys" id="sg-*-tls-session_keys" name="sg-*-tls-session_keys">`session_keys`</a>:
The array of file paths from which the each server's TLS session keys are
updated. Session ticket key files must contain at least 32 bytes.
* <a href="#sg-*-bpr-skip" id="sg-*-bpr-skip" name="sg-*-bpr-skip">`skip`</a>:
Request parameters based on which the block-page redirect is never
performed. For requests matching these parameters, `probability` is
ignored.
**Property example:**
```yaml
'session_keys':
- './private/key_1'
- './private/key_2'
skip:
client:
- address: '1.2.0.0/16'
- address: '5.6.7.8'
question:
- domain: 'do-not-show-block.site.example'
```
* <a href="#sg-*-tls-device_id_wildcards" id="sg-*-tls-device_id_wildcards" name="sg-*-tls-device_id_wildcards">`device_id_wildcards`</a>:
The array of domain name wildcards to use to detect clients' device IDs.
Use this to prevent conflicts when using certificates for subdomains.
* <a href="#sg-*-bpr-probability" id="sg-*-bpr-probability" name="sg-*-bpr-probability">`probability`</a>:
**Property example:**
```yaml
'device_id_wildcards':
- '*.d.dns.example.com'
```
The probability of responding with the block page IPs based on remote
address. Must be between `0.0` and `1.0`.
@ -1062,6 +1096,45 @@ collected the required data was not self-describing and flexible enough.
### <a href="#server_groups-*-tls" id="server_groups-*-tls" name="server_groups-*-tls">TLS</a>
* <a href="#sg-*-tls-certificates" id="sg-*-tls-certificates" name="sg-*-tls-certificates">`certificates`</a>:
The array of objects with paths to the certificate and the private key for
this server group.
**Property example:**
```yaml
'certificates':
- 'certificate': '/etc/dns/cert.crt'
'key': '/etc/dns/cert.key'
```
* <a href="#sg-*-tls-session_keys" id="sg-*-tls-session_keys" name="sg-*-tls-session_keys">`session_keys`</a>:
The array of file paths from which the each server's TLS session keys are
updated. Session ticket key files must contain at least 32 bytes.
**Property example:**
```yaml
'session_keys':
- './private/key_1'
- './private/key_2'
```
* <a href="#sg-*-tls-device_id_wildcards" id="sg-*-tls-device_id_wildcards" name="sg-*-tls-device_id_wildcards">`device_id_wildcards`</a>:
The array of domain name wildcards to use to detect clients' device IDs.
Use this to prevent conflicts when using certificates for subdomains.
**Property example:**
```yaml
'device_id_wildcards':
- '*.d.dns.example.com'
```
### <a href="#server_groups-*-servers-*" id="server_groups-*-servers-*" name="server_groups-*-servers-*">Servers</a>
The items of the `servers` array have the following properties:

View File

@ -27,8 +27,9 @@ The response is sent with the `Transfer-Encoding` set to `chunked` and with an
HTTP trailer named `X-Error` which describes errors that might have occurred
during the database dump.
**NOTE:** For legacy software reasons, despite the endpoint being a `GET` one,
it rotates the database, and so changes the internal state.
> [!NOTE]
> For legacy software reasons, despite the endpoint being a `GET` one, it
> rotates the database, and so changes the internal state.

View File

@ -315,8 +315,8 @@ Open `http://127.0.0.1:8081/metrics` to see the server's metrics.
DNSCrypt is a bit trickier. You need to open `dnscrypt.yml` and use values from
there to generate an SDNS stamp on <https://dnscrypt.info/stamps>.
**NOTE:** The example below is for a test configuration that won't work for
you.
> [!NOTE]
> The example below is for a test configuration that won't work for you.
```sh
dnslookup example.org sdns://AQcAAAAAAAAADjEyNy4wLjAuMTo1NDQzIAbKgP3dmXybr1DaKIFgKjsc8zSFX4rgT_hFgymSq6w1FzIuZG5zY3J5cHQtY2VydC50ZXN0ZG5z

View File

@ -23,6 +23,7 @@ sensitive configuration. All other configuration is stored in the
* [`LOG_TIMESTAMP`](#LOG_TIMESTAMP)
* [`NEW_REG_DOMAINS_URL`](#NEW_REG_DOMAINS_URL)
* [`PROFILES_CACHE_PATH`](#PROFILES_CACHE_PATH)
* [`PROFILES_ENABLED`](#PROFILES_ENABLED)
* [`PROFILES_URL`](#PROFILES_URL)
* [`QUERYLOG_PATH`](#QUERYLOG_PATH)
* [`RESEARCH_LOGS`](#RESEARCH_LOGS)
@ -236,6 +237,14 @@ The profile cache is read on start and is later updated on every
## <a href="#PROFILES_ENABLED" id="PROFILES_ENABLED" name="PROFILES_ENABLED">`PROFILES_ENABLED`</a>
If `0`, disables user profiles and devices recognition and billing.
**Default:** `1`.
## <a href="#PROFILES_URL" id="PROFILES_URL" name="PROFILES_URL">`PROFILES_URL`</a>
The base backend URL for profiles API. Supports GRPC (`grpc://` and`grpcs://`)

View File

@ -30,9 +30,11 @@ document should set the `Server` header in their replies.
This is the service to which the [`BILLSTAT_URL`][env-billstat_url] environment
variable points. Supports `grpc(s)` URLs. The service must correspond to
`./internal/backendpb/backend.proto`.
`./internal/backendpb/backend.proto`. This service can be disabled with the
[`PROFILES_ENABLED`][env-profiles_enabled] environment variable.
[env-billstat_url]: environment.md#BILLSTAT_URL
[env-profiles_enabled]: environment.md#PROFILES_ENABLED
@ -40,7 +42,8 @@ variable points. Supports `grpc(s)` URLs. The service must correspond to
This is the service to which the [`PROFILES_URL`][env-profiles_url] environment
variable points. Supports `grpc(s)` URLs. The service must correspond to
`./internal/backendpb/backend.proto`.
`./internal/backendpb/backend.proto`. This service can be disabled with the
[`PROFILES_ENABLED`][env-profiles_enabled] environment variable.
[env-profiles_url]: environment.md#PROFILES_URL

View File

@ -42,8 +42,9 @@ rules to remember, which property means what. The properties are:
alpha-2][wiki-iso] country code, if any. If none could be detected, this
property is absent. The short name `c` stands for “client country”.
**NOTE:** AdGuard DNS uses the common user-assigned ISO 3166-1 alpha-2 code
`XK` for the partially-recognized state of the Republic of Kosovo.
> [!NOTE]
> AdGuard DNS uses the common user-assigned ISO 3166-1 alpha-2 code `XK`
> for the partially-recognized state of the Republic of Kosovo.
**Example:** `"AU"`
@ -53,8 +54,9 @@ rules to remember, which property means what. The properties are:
could be detected, this property is absent. The short name `d` stands for
“destination”.
**NOTE:** AdGuard DNS uses the common user-assigned ISO 3166-1 alpha-2 code
`XK` for the partially-recognized state of the Republic of Kosovo.
> [!NOTE]
> AdGuard DNS uses the common user-assigned ISO 3166-1 alpha-2 code `XK`
> for the partially-recognized state of the Republic of Kosovo.
**Example:** `"US"`

52
go.mod
View File

@ -1,32 +1,32 @@
module github.com/AdguardTeam/AdGuardDNS
go 1.21.5
go 1.21.8
require (
github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-00010101000000-000000000000
github.com/AdguardTeam/golibs v0.18.1
github.com/AdguardTeam/urlfilter v0.17.2
github.com/AdguardTeam/golibs v0.20.1
github.com/AdguardTeam/urlfilter v0.18.0
github.com/ameshkov/dnscrypt/v2 v2.2.7
github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc
github.com/axiomhq/hyperloglog v0.0.0-20240124082744-24bca3a5b39b
github.com/bluele/gcache v0.0.2
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500
github.com/caarlos0/env/v7 v7.1.0
github.com/getsentry/sentry-go v0.25.0
github.com/getsentry/sentry-go v0.27.0
github.com/google/renameio/v2 v2.0.0
github.com/miekg/dns v1.1.56
github.com/miekg/dns v1.1.58
github.com/oschwald/maxminddb-golang v1.12.0
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
github.com/prometheus/client_golang v1.17.0
github.com/prometheus/client_golang v1.18.0
github.com/prometheus/client_model v0.5.0
github.com/prometheus/common v0.44.0
github.com/quic-go/quic-go v0.39.0
github.com/prometheus/common v0.46.0
github.com/quic-go/quic-go v0.41.0
github.com/stretchr/testify v1.8.4
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
golang.org/x/net v0.17.0
golang.org/x/sys v0.13.0
golang.org/x/time v0.3.0
google.golang.org/grpc v1.58.3
google.golang.org/protobuf v1.31.0
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
golang.org/x/net v0.21.0
golang.org/x/sys v0.17.0
golang.org/x/time v0.5.0
google.golang.org/grpc v1.61.1
google.golang.org/protobuf v1.32.0
gopkg.in/yaml.v2 v2.4.0
)
@ -40,20 +40,18 @@ require (
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/onsi/ginkgo/v2 v2.13.0 // indirect
github.com/panjf2000/ants/v2 v2.8.2 // indirect
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
github.com/panjf2000/ants/v2 v2.9.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.3.4 // indirect
go.uber.org/mock v0.3.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/mod v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/tools v0.14.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

118
go.sum
View File

@ -1,7 +1,7 @@
github.com/AdguardTeam/golibs v0.18.1 h1:6u0fvrIj2qjUsRdbIGJ9AR0g5QRSWdKIo/DYl3tp5aM=
github.com/AdguardTeam/golibs v0.18.1/go.mod h1:DKhCIXHcUYtBhU8ibTLKh1paUL96n5zhQBlx763sj+U=
github.com/AdguardTeam/urlfilter v0.17.2 h1:xTntfr1UWah8m6wwoXJmFgplFk/+kL/hDu204ptrM1U=
github.com/AdguardTeam/urlfilter v0.17.2/go.mod h1:Jru7jFfeH2CoDf150uDs+rRYcZBzHHBz05r9REyDKyE=
github.com/AdguardTeam/golibs v0.20.1 h1:ol8qLjWGZhU9paMMwN+OLWVTUigGsXa29iVTyd62VKY=
github.com/AdguardTeam/golibs v0.20.1/go.mod h1:bgcMgRviCKyU6mkrX+RtT/OsKPFzyppelfRsksMG3KU=
github.com/AdguardTeam/urlfilter v0.18.0 h1:ZZzwODC/ADpjJSODxySrrUnt/fvOCfGFaCW6j+wsGfQ=
github.com/AdguardTeam/urlfilter v0.18.0/go.mod h1:IXxBwedLiZA2viyHkaFxY/8mjub0li2PXRg8a3d9Z1s=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
@ -10,14 +10,14 @@ github.com/ameshkov/dnscrypt/v2 v2.2.7 h1:aEitLIR8HcxVodZ79mgRcCiC0A0I5kZPBuWGFw
github.com/ameshkov/dnscrypt/v2 v2.2.7/go.mod h1:qPWhwz6FdSmuK7W4sMyvogrez4MWdtzosdqlr0Rg3ow=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc h1:Keo7wQ7UODUaHcEi7ltENhbAK2VgZjfat6mLy03tQzo=
github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c=
github.com/axiomhq/hyperloglog v0.0.0-20240124082744-24bca3a5b39b h1:F3yMzKumBUQ6Fn0sYI1YQ16vQRucpZOfBQ9HXWl5+XI=
github.com/axiomhq/hyperloglog v0.0.0-20240124082744-24bca3a5b39b/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdSE0JxlhR2hKnGPcNB35BjQf4RYQDY=
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 h1:6lhrsTEnloDPXyeZBvSYvQf8u86jbKehZPVDDlkgDl4=
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/caarlos0/env/v7 v7.1.0 h1:9lzTF5amyQeWHZzuZeKlCb5FWSUxpG1js43mhbY8ozg=
github.com/caarlos0/env/v7 v7.1.0/go.mod h1:LPPWniDUq4JaO6Q41vtlyikhMknqymCLBw0eX4dcH1E=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
@ -28,25 +28,24 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI=
github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ=
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo=
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -55,18 +54,16 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
github.com/panjf2000/ants/v2 v2.8.2 h1:D1wfANttg8uXhC9149gRt1PDQ+dLVFjNXkCEycMcvQQ=
github.com/panjf2000/ants/v2 v2.8.2/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
github.com/panjf2000/ants/v2 v2.9.0 h1:SztCLkVxBRigbg+vt0S5QvF5vxAbxbKt09/YfAJ0tEo=
github.com/panjf2000/ants/v2 v2.9.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible h1:IWzUvJ72xMjmrjR9q3H1PF+jwdN0uNQiR2t1BLNalyo=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
@ -77,20 +74,18 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y=
github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg=
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.39.0 h1:AgP40iThFMY0bj8jGxROhw3S0FMGa8ryqsmi9tBH3So=
github.com/quic-go/quic-go v0.39.0/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4=
@ -112,37 +107,36 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0=
google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ=
google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk=
google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@ -1,4 +1,4 @@
go 1.21.5
go 1.21.8
use (
.

View File

@ -4,8 +4,11 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
cloud.google.com/go/bigquery v1.8.0 h1:PQcPefKFdaIzjQFbiyOgAqyx8q5djaE7x9Sqe712DPA=
cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk=
cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU=
@ -23,7 +26,9 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999 h1:OR8VhtwhcAI3U48/
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/AdguardTeam/golibs v0.10.7/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw=
github.com/AdguardTeam/golibs v0.17.2/go.mod h1:DKhCIXHcUYtBhU8ibTLKh1paUL96n5zhQBlx763sj+U=
github.com/AdguardTeam/golibs v0.19.0/go.mod h1:3WunclLLfrVAq7fYQRhd6f168FHOEMssnipVXCxDL/w=
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=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@ -46,6 +51,7 @@ github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjK
github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE=
github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU=
github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
@ -64,10 +70,14 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89 h1:aPflPkRFkVwbW6dmcVqfgwp1i+UWGFH6VgR1Jim5Ygc=
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/chromedp/chromedp v0.9.2 h1:dKtNz4kApb06KuSXoTQIyUC2TrA0fhGDwNZf3bcgfKw=
github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@ -86,8 +96,11 @@ github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU=
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk=
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
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=
@ -98,8 +111,10 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E=
github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM=
github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
@ -141,8 +156,11 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
@ -151,7 +169,9 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7 h1:2hRPrmiwPrp3fQX967rNJIhQPtiGXdlQWAxKbKw3VHA=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
@ -180,6 +200,7 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
@ -292,6 +313,7 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/microcosm-cc/bluemonday v1.0.1 h1:SIYunPjnlXcW+gVfvm0IlSeR5U3WZUOLfVmqg85Go44=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg=
@ -336,6 +358,7 @@ github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.38.0/go.mod h1:MPCuRq7KBK2hNcfKj/1iD1BGuN3eAYMeNxp3T42LRUg=
github.com/quic-go/quic-go v0.39.4/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
@ -446,12 +469,14 @@ go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d h1:E2M5QgjZ/Jg+ObCQAudsXxuTsLj7Nl5RV/lZcQZmKSo=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/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=
@ -497,7 +522,9 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq
golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852 h1:xYq6+9AtI+xP3M4r0N1hCkHrInHDBohhquRgx9Kk6gI=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -508,6 +535,7 @@ golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -523,6 +551,9 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
@ -532,7 +563,13 @@ golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
@ -553,6 +590,7 @@ golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
@ -566,6 +604,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@ -576,7 +615,11 @@ google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWof
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8=
google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0=
google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk=
google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU=
google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=

View File

@ -6,6 +6,7 @@ import (
"net/netip"
"strings"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist"
@ -23,26 +24,20 @@ type Interface interface {
// IsBlockedIP returns the status of the IP address blocking as well as the
// rule that blocked it.
IsBlockedIP(ip netip.Addr) (blocked bool, rule string)
IsBlockedIP(ip netip.Addr) (blocked bool)
}
// Global controls IP and client blocking that takes place before all other
// processing. Global is safe for concurrent use.
type Global struct {
blockedIPs map[netip.Addr]string
blockedHostsEng *urlfilter.DNSEngine
blockedNets []netip.Prefix
blockedNets netutil.SubnetSet
}
// NewGlobal create a new Global from provided parameters.
func NewGlobal(blockedDomains, blockedSubnets []string) (g *Global, err error) {
func NewGlobal(blockedDomains []string, blockedSubnets []netip.Prefix) (g *Global, err error) {
g = &Global{
blockedIPs: map[netip.Addr]string{},
}
err = processAccessList(blockedSubnets, g.blockedIPs, &g.blockedNets)
if err != nil {
return nil, fmt.Errorf("adding blocked hosts: %w", err)
blockedNets: netutil.SliceSubnetSet(blockedSubnets),
}
b := &strings.Builder{}
@ -68,24 +63,6 @@ func NewGlobal(blockedDomains, blockedSubnets []string) (g *Global, err error) {
return g, nil
}
// processAccessList is a helper for processing a list of strings, each of them
// could be an IP address or a CIDR.
func processAccessList(strs []string, ips map[netip.Addr]string, nets *[]netip.Prefix) (err error) {
for _, s := range strs {
var ip netip.Addr
var ipnet netip.Prefix
if ip, err = netip.ParseAddr(s); err == nil {
ips[ip] = ip.String()
} else if ipnet, err = netip.ParsePrefix(s); err == nil {
*nets = append(*nets, ipnet)
} else {
return fmt.Errorf("cannot parse subnet or ip address: %q", s)
}
}
return nil
}
// type check
var _ Interface = (*Global)(nil)
@ -104,16 +81,6 @@ func (g *Global) IsBlockedHost(host string, qt uint16) (blocked bool) {
}
// IsBlockedIP implements the [Interface] interface for *Global.
func (g *Global) IsBlockedIP(ip netip.Addr) (blocked bool, rule string) {
if ipStr, ok := g.blockedIPs[ip]; ok {
return true, ipStr
}
for _, ipnet := range g.blockedNets {
if ipnet.Contains(ip) {
return true, ipnet.String()
}
}
return false, ""
func (g *Global) IsBlockedIP(ip netip.Addr) (blocked bool) {
return g.blockedNets.Contains(ip)
}

View File

@ -17,7 +17,7 @@ func TestGlobal_IsBlockedHost(t *testing.T) {
"||block_aaaa.test^$dnstype=AAAA",
"||allowlist.test^",
"@@||allow.allowlist.test^",
}, []string{})
}, nil)
require.NoError(t, err)
testCases := []struct {
@ -76,44 +76,38 @@ func TestGlobal_IsBlockedHost(t *testing.T) {
}
func TestGlobal_IsBlockedIP(t *testing.T) {
global, err := access.NewGlobal([]string{}, []string{
"1.1.1.1",
"2.2.2.0/8",
global, err := access.NewGlobal([]string{}, []netip.Prefix{
netip.MustParsePrefix("1.1.1.1/32"),
netip.MustParsePrefix("2.2.2.0/8"),
})
require.NoError(t, err)
testCases := []struct {
want assert.BoolAssertionFunc
ip netip.Addr
wantRule string
name string
want assert.BoolAssertionFunc
ip netip.Addr
name string
}{{
want: assert.False,
wantRule: "",
name: "pass",
ip: netip.MustParseAddr("1.1.1.0"),
want: assert.False,
name: "pass",
ip: netip.MustParseAddr("1.1.1.0"),
}, {
want: assert.True,
wantRule: "1.1.1.1",
name: "block_ip",
ip: netip.MustParseAddr("1.1.1.1"),
want: assert.True,
name: "block_ip",
ip: netip.MustParseAddr("1.1.1.1"),
}, {
want: assert.False,
wantRule: "",
name: "pass_subnet",
ip: netip.MustParseAddr("1.2.2.2"),
want: assert.False,
name: "pass_subnet",
ip: netip.MustParseAddr("1.2.2.2"),
}, {
want: assert.True,
wantRule: "2.2.2.0/8",
name: "block_subnet",
ip: netip.MustParseAddr("2.2.2.2"),
want: assert.True,
name: "block_subnet",
ip: netip.MustParseAddr("2.2.2.2"),
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
blocked, rule := global.IsBlockedIP(tc.ip)
blocked := global.IsBlockedIP(tc.ip)
tc.want(t, blocked)
assert.Equal(t, tc.wantRule, rule)
})
}
}

View File

@ -29,7 +29,8 @@ func newBlockedHostEngine(rules []string) (e *blockedHostEngine) {
}
}
// isBlocked returns true if the req is blocked by this engine.
// isBlocked returns true if the req is blocked by this engine. req must have
// exactly one question.
func (e *blockedHostEngine) isBlocked(req *dns.Msg) (blocked bool) {
e.initOnce.Do(func() {
start := time.Now()

View File

@ -131,7 +131,7 @@ func matchASNs(asns []geoip.ASN, l *geoip.Location) (ok bool) {
}
// isBlockedByHostsEng returns true if the req is blocked by
// BlocklistDomainRules.
// BlocklistDomainRules. req must have exactly one question.
func (p *DefaultProfile) isBlockedByHostsEng(req *dns.Msg) (blocked bool) {
return p.blockedHostsEng.isBlocked(req)
}

View File

@ -9,76 +9,9 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/netext"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/ameshkov/dnscrypt/v2"
"github.com/miekg/dns"
)
// Servers And Server Groups
// ServerGroup is a group of DNS servers all of which use the same filtering
// settings.
type ServerGroup struct {
// 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
// DDR is the configuration for the server group's Discovery Of Designated
// Resolvers (DDR) handlers. DDR is never nil.
DDR *DDR
// Name is the unique name of the server group.
Name ServerGroupName
// FilteringGroup is the ID of the filtering group for this server.
FilteringGroup FilteringGroupID
// Servers are the settings for servers. Each element must be non-nil.
Servers []*Server
}
// 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
// DeviceIDWildcards are the domain wildcards used to detect device IDs from
// clients' server names.
DeviceIDWildcards []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 {
// DeviceTargets is the set of all domain names, subdomains of which should
// be checked for DDR queries with device IDs.
DeviceTargets *stringutil.Set
// PublicTargets is the set of all public domain names, DDR queries for
// which should be processed.
PublicTargets *stringutil.Set
// DeviceRecordTemplates are used to respond to DDR queries from recognized
// devices.
DeviceRecordTemplates []*dns.SVCB
// PubilcRecordTemplates are used to respond to DDR queries from
// unrecognized devices.
PublicRecordTemplates []*dns.SVCB
// Enabled shows if DDR queries are processed. If it is false, DDR domain
// name queries receive an NXDOMAIN response.
Enabled bool
}
// Server represents a single DNS server. That is, an entity that binds to one
// or more ports and serves DNS over a single protocol.
type Server struct {
@ -192,6 +125,24 @@ func (s *Server) BindsToInterfaces() (ok bool) {
return len(s.bindData) > 0 && s.bindData[0].PrefixAddr != nil
}
// BindDataPrefixes returns a slice of CIDR networks collected from the bind
// data of this server.
func (s *Server) BindDataPrefixes() (ps []netip.Prefix) {
for _, bd := range s.bindData {
var pref netip.Prefix
if bd.PrefixAddr == nil {
addr := bd.AddrPort.Addr()
pref = netip.PrefixFrom(addr, addr.BitLen())
} else {
pref = bd.PrefixAddr.Prefix
}
ps = append(ps, pref)
}
return ps
}
// ServerBindData are the socket binding data for a server. Either AddrPort or
// ListenConfig with PrefixAddr must be set.
//

View File

@ -13,27 +13,31 @@ import (
// Common variables for tests.
var (
addrV4 = netip.MustParseAddr("1.2.3.4")
bindDataAddrPortV4 = &agd.ServerBindData{
AddrPort: netip.MustParseAddrPort("1.2.3.4:53"),
AddrPort: netip.AddrPortFrom(addrV4, 53),
}
addrV6 = netip.MustParseAddr("1234::cdef")
bindDataAddrPortV6 = &agd.ServerBindData{
AddrPort: netip.MustParseAddrPort("[1234::cdef]:53"),
AddrPort: netip.AddrPortFrom(addrV6, 53),
}
prefixV4 = netip.MustParsePrefix("1.2.3.0/24")
bindDataIface = &agd.ServerBindData{
ListenConfig: &agdtest.ListenConfig{},
PrefixAddr: &agdnet.PrefixNetAddr{
Prefix: netip.MustParsePrefix("1.2.3.0/24"),
Prefix: prefixV4,
Net: "",
Port: 53,
},
}
singleIPPrefixV4 = netip.MustParsePrefix("1.2.3.4/32")
bindDataIfaceSingleIP = &agd.ServerBindData{
ListenConfig: &agdtest.ListenConfig{},
PrefixAddr: &agdnet.PrefixNetAddr{
Prefix: netip.MustParsePrefix("1.2.3.4/32"),
Prefix: singleIPPrefixV4,
Net: "",
Port: 53,
},
@ -105,6 +109,41 @@ func TestServer_BindsToInterfaces(t *testing.T) {
assert.True(t, s.BindsToInterfaces())
}
func TestServer_BindDataPrefixes(t *testing.T) {
testCases := []struct {
bindData *agd.ServerBindData
name string
want []netip.Prefix
}{{
bindData: bindDataAddrPortV4,
want: []netip.Prefix{netip.PrefixFrom(addrV4, addrV4.BitLen())},
name: "addr_port_v4",
}, {
bindData: bindDataAddrPortV6,
want: []netip.Prefix{netip.PrefixFrom(addrV6, addrV6.BitLen())},
name: "addr_port_v6",
}, {
bindData: bindDataIface,
want: []netip.Prefix{prefixV4},
name: "prefix",
}, {
bindData: bindDataIfaceSingleIP,
want: []netip.Prefix{singleIPPrefixV4},
name: "prefix_single_ip",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
s := &agd.Server{}
require.NotPanics(t, func() {
s.SetBindData([]*agd.ServerBindData{tc.bindData})
})
assert.Equal(t, tc.want, s.BindDataPrefixes())
})
}
}
func TestServer_HasAddr(t *testing.T) {
testCases := []struct {
bindData *agd.ServerBindData

158
internal/agd/servergroup.go Normal file
View File

@ -0,0 +1,158 @@
package agd
import (
"crypto/tls"
"fmt"
"math"
"net/netip"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/miekg/dns"
)
// ServerGroup is a group of DNS servers all of which use the same filtering
// settings.
type ServerGroup struct {
// BlockPageRedirect is the configuration for the server group's block page.
// BlockPageRedirect is never nil.
//
// TODO(a.garipov): Use.
BlockPageRedirect *BlockPageRedirect
// DDR is the configuration for the server group's Discovery Of Designated
// Resolvers (DDR) handlers. DDR is never nil.
DDR *DDR
// 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
// Name is the unique name of the server group.
Name ServerGroupName
// FilteringGroup is the ID of the filtering group for this server.
FilteringGroup FilteringGroupID
// Servers are the settings for servers. Each element must be non-nil.
Servers []*Server
}
// 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
// DeviceIDWildcards are the domain wildcards used to detect device IDs from
// clients' server names.
DeviceIDWildcards []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 {
// DeviceTargets is the set of all domain names, subdomains of which should
// be checked for DDR queries with device IDs.
DeviceTargets *stringutil.Set
// PublicTargets is the set of all public domain names, DDR queries for
// which should be processed.
PublicTargets *stringutil.Set
// DeviceRecordTemplates are used to respond to DDR queries from recognized
// devices.
DeviceRecordTemplates []*dns.SVCB
// PubilcRecordTemplates are used to respond to DDR queries from
// unrecognized devices.
PublicRecordTemplates []*dns.SVCB
// Enabled shows if DDR queries are processed. If it is false, DDR domain
// name queries receive an NXDOMAIN response.
Enabled bool
}
// BlockPageRedirect is the configuration for a [ServerGroup]'s block page.
type BlockPageRedirect struct {
// Apply defines request parameters based on which the block page is shown
// always. If a request matches Apply, both [BlockPageRedirect.Skip] and
// [BlockPageRedirect.Probability] are ignored.
//
// If [BlockPageRedirect.Enabled] is true, Apply must not be nil.
Apply *BlockPageRedirectApply
// Skip defines request parameters based on which the block page is not
// shown, regardless of [BlockPageRedirect.Probability].
//
// If [BlockPageRedirect.Enabled] is true, Skip must not be nil.
Skip *BlockPageRedirectSkip
// IPv4 are the IPv4 addresses of the block page, used to respond to A
// queries.
//
// If [BlockPageRedirect.Enabled] is true, IPv4, [BlockPageRedirect.IPv6],
// or both must be filled.
IPv4 []netip.Addr
// IPv6 are the IPv6 addresses of the block page, used to respond to AAAA
// queries.
//
// If [BlockPageRedirect.Enabled] is true, [BlockPageRedirect.IPv4], IPv6,
// or both must be filled.
IPv6 []netip.Addr
// Probability defines the probability of responding with the block page IPs
// based on remote address. Probability must be between 0.0 and 1.0.
Probability Probability
// Enabled defines whether the block-page feature is enabled.
Enabled bool
}
// Probability is a type for probabilities ranging from 0.0 to 1.0.
type Probability float64
// NewProbability returns a properly converted Probability or an error.
func NewProbability(f float64) (prob Probability, err error) {
if math.IsNaN(f) || f < 0.0 || f > 1.0 {
return 0, fmt.Errorf("probability must be between 0.0 and 1.0; got %v", f)
}
return Probability(f), nil
}
// MustNewProbability returns a properly converted Probability or panics with an
// error.
func MustNewProbability(f float64) (prob Probability) {
prob, err := NewProbability(f)
if err != nil {
panic(err)
}
return prob
}
// BlockPageRedirectApply defines the conditions for applying the block-page
// logic for a particular request.
type BlockPageRedirectApply struct {
// ClientSubnets are the subnets for which block page is always enabled.
ClientSubnets []netip.Prefix
}
// BlockPageRedirectSkip defines the conditions for skipping the block page
// logic for a particular request.
type BlockPageRedirectSkip struct {
// ClientSubnets are the subnets for which block page is always disabled.
ClientSubnets []netip.Prefix
// QuestionDomains are the domain names for which block page is always
// disabled.
QuestionDomains []string
}

View File

@ -4,8 +4,6 @@
package agdnet
import (
"fmt"
"net/netip"
"strings"
)
@ -48,33 +46,6 @@ func AndroidMetricDomainReplacement(fqdn string) (repl string) {
return ""
}
// ParseSubnets parses IP networks, including single-address ones, from strings.
func ParseSubnets(strs ...string) (subnets []netip.Prefix, err error) {
subnets = make([]netip.Prefix, len(strs))
for i, s := range strs {
// Detect if this is a CIDR or an IP early, so that the path to
// returning an error is shorter.
if strings.Contains(s, "/") {
subnets[i], err = netip.ParsePrefix(s)
if err != nil {
return nil, fmt.Errorf("subnet at idx %d: %w", i, err)
}
continue
}
var ip netip.Addr
ip, err = netip.ParseAddr(s)
if err != nil {
return nil, fmt.Errorf("ip at idx %d: %w", i, err)
}
subnets[i] = netip.PrefixFrom(ip, ip.BitLen())
}
return subnets, nil
}
// NormalizeDomain returns lowercased version of the host without the final dot.
//
// TODO(a.garipov): Move to golibs.

View File

@ -1,38 +1,7 @@
// Package agdservice defines types and interfaces for long-running services.
//
// TODO(a.garipov): Move to golibs.
// TODO(a.garipov): Move more to golibs.
package agdservice
import "context"
// Interface is the interface for long-running services.
//
// TODO(a.garipov): Define whether or not a service should finish starting or
// shutting down before returning from these methods.
type Interface interface {
// Start starts the service. ctx is used for cancelation.
//
// TODO(a.garipov): Use contexts with timeouts everywhere.
Start(ctx context.Context) (err error)
// Shutdown gracefully stops the service. ctx is used to determine
// a timeout before trying to stop the service less gracefully.
//
// TODO(a.garipov): Use contexts with timeouts everywhere.
Shutdown(ctx context.Context) (err error)
}
// type check
var _ Interface = Empty{}
// Empty is an [Interface] implementation that does nothing.
type Empty struct{}
// Start implements the [Interface] interface for Empty.
func (Empty) Start(_ context.Context) (err error) { return nil }
// Shutdown implements the [Interface] interface for Empty.
func (Empty) Shutdown(_ context.Context) (err error) { return nil }
// unit is a convenient alias for struct{}.
type unit = struct{}

View File

@ -7,6 +7,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/service"
"golang.org/x/exp/rand"
)
@ -111,17 +112,17 @@ func NewRefreshWorker(c *RefreshWorkerConfig) (w *RefreshWorker) {
}
// type check
var _ Interface = (*RefreshWorker)(nil)
var _ service.Interface = (*RefreshWorker)(nil)
// Start implements the [Interface] interface for *RefreshWorker. err is always
// nil.
// Start implements the [service.Interface] interface for *RefreshWorker. err
// is always nil.
func (w *RefreshWorker) Start(_ context.Context) (err error) {
go w.refreshInALoop()
return nil
}
// Shutdown implements the [Interface] interface for *RefreshWorker.
// Shutdown implements the [service.Interface] interface for *RefreshWorker.
func (w *RefreshWorker) Shutdown(ctx context.Context) (err error) {
if w.refrOnShutdown {
err = w.refr.Refresh(ctx)

View File

@ -39,7 +39,7 @@ var _ access.Interface = (*AccessManager)(nil)
// AccessManager is a [access.Interface] for tests.
type AccessManager struct {
OnIsBlockedHost func(host string, qt uint16) (blocked bool)
OnIsBlockedIP func(ip netip.Addr) (blocked bool, rule string)
OnIsBlockedIP func(ip netip.Addr) (blocked bool)
}
// IsBlockedHost implements the [access.Interface] interface for *AccessManager.
@ -48,7 +48,7 @@ func (a *AccessManager) IsBlockedHost(host string, qt uint16) (blocked bool) {
}
// IsBlockedIP implements the [access.Interface] interface for *AccessManager.
func (a *AccessManager) IsBlockedIP(ip netip.Addr) (blocked bool, rule string) {
func (a *AccessManager) IsBlockedIP(ip netip.Addr) (blocked bool) {
return a.OnIsBlockedIP(ip)
}

View File

@ -16,8 +16,10 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
@ -27,6 +29,9 @@ import (
// ProfileStorageConfig is the configuration for the business logic backend
// profile storage.
type ProfileStorageConfig struct {
// BindSet is the subnet set created from DNS servers listening addresses.
BindSet netutil.SubnetSet
// ErrColl is the error collector that is used to collect critical and
// non-critical errors.
ErrColl errcoll.Interface
@ -40,6 +45,7 @@ type ProfileStorageConfig struct {
// that retrieves the profile and device information from the business logic
// backend. It is safe for concurrent use.
type ProfileStorage struct {
bindSet netutil.SubnetSet
errColl errcoll.Interface
// client is the current GRPC client.
@ -56,6 +62,7 @@ func NewProfileStorage(c *ProfileStorageConfig) (s *ProfileStorage, err error) {
}
return &ProfileStorage{
bindSet: c.BindSet,
client: client,
errColl: c.ErrColl,
}, nil
@ -97,7 +104,7 @@ func (s *ProfileStorage) Profiles(
stats.endRecv()
stats.startDec()
prof, devices, profErr := profile.toInternal(ctx, time.Now(), s.errColl)
prof, devices, profErr := profile.toInternal(ctx, time.Now(), s.bindSet, s.errColl)
if profErr != nil {
reportf(ctx, s.errColl, "loading profile: %w", profErr)
@ -140,6 +147,7 @@ func fixGRPCError(err error) (wErr error) {
func (x *DNSProfile) toInternal(
ctx context.Context,
updTime time.Time,
bindSet netutil.SubnetSet,
errColl errcoll.Interface,
) (profile *agd.Profile, devices []*agd.Device, err error) {
if x == nil {
@ -156,7 +164,7 @@ func (x *DNSProfile) toInternal(
return nil, nil, fmt.Errorf("blocking mode: %w", err)
}
devices, deviceIds := devicesToInternal(ctx, x.Devices, errColl)
devices, deviceIds := devicesToInternal(ctx, x.Devices, bindSet, errColl)
listsEnabled, listIDs := x.RuleLists.toInternal(ctx, errColl)
profID, err := agd.NewProfileID(x.DnsId)
@ -384,6 +392,7 @@ func blockingModeToInternal(pbm isDNSProfile_BlockingMode) (m dnsmsg.BlockingMod
func devicesToInternal(
ctx context.Context,
ds []*DeviceSettings,
bindSet netutil.SubnetSet,
errColl errcoll.Interface,
) (out []*agd.Device, ids []agd.DeviceID) {
l := len(ds)
@ -393,9 +402,10 @@ func devicesToInternal(
out = make([]*agd.Device, 0, l)
for _, d := range ds {
dev, err := d.toInternal()
dev, err := d.toInternal(bindSet)
if err != nil {
reportf(ctx, errColl, "invalid device settings: %w", err)
metrics.DevicesInvalidTotal.Inc()
continue
}
@ -409,7 +419,7 @@ func devicesToInternal(
// toInternal is a helper that converts device settings from backend protobuf
// response to AdGuard DNS device object.
func (ds *DeviceSettings) toInternal() (dev *agd.Device, err error) {
func (ds *DeviceSettings) toInternal(bindSet netutil.SubnetSet) (dev *agd.Device, err error) {
if ds == nil {
return nil, fmt.Errorf("device is nil")
}
@ -426,6 +436,13 @@ func (ds *DeviceSettings) toInternal() (dev *agd.Device, err error) {
return nil, fmt.Errorf("dedicated ips: %w", err)
}
// TODO(d.kolyshev): Extract business logic validation.
for _, addr := range dedicatedIPs {
if !bindSet.Contains(addr) {
return nil, fmt.Errorf("dedicated ip %q is not in bind data", addr)
}
}
id, err := agd.NewDeviceID(ds.Id)
if err != nil {
return nil, fmt.Errorf("device id: %s: %w", ds.Id, err)

View File

@ -30,6 +30,9 @@ const testProfileID agd.ProfileID = "prof1234"
// TestUpdTime is the common update time for tests.
var TestUpdTime = time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)
// testBind includes any IPv4 address.
var testBind = netip.MustParsePrefix("0.0.0.0/0")
func TestDNSProfile_ToInternal(t *testing.T) {
ctx := context.Background()
@ -40,7 +43,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
}
t.Run("success", func(t *testing.T) {
got, gotDevices, err := NewTestDNSProfile(t).toInternal(ctx, TestUpdTime, errColl)
got, gotDevices, err := NewTestDNSProfile(t).toInternal(ctx, TestUpdTime, testBind, errColl)
require.NoError(t, err)
assert.Equal(t, newProfile(t), got)
@ -57,18 +60,44 @@ func TestDNSProfile_ToInternal(t *testing.T) {
got, gotDevices, err := newDNSProfileWithBadData(t).toInternal(
ctx,
TestUpdTime,
testBind,
savingErrColl,
)
require.NoError(t, err)
require.Error(t, errCollErr)
testutil.AssertErrorMsg(t, "backendpb: invalid device settings:"+
" dedicated ips: ip at index 0: unexpected slice size", errCollErr)
assert.Equal(t, newProfile(t), got)
assert.Equal(t, newDevices(t), gotDevices)
})
t.Run("invalid_device_ded_ip", func(t *testing.T) {
var errCollErr error
savingErrColl := &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, err error) {
errCollErr = err
},
}
bindSet := netip.MustParsePrefix("2.2.2.2/32")
got, gotDevices, err := NewTestDNSProfile(t).toInternal(
ctx,
TestUpdTime,
bindSet,
savingErrColl,
)
require.NoError(t, err)
testutil.AssertErrorMsg(t, "backendpb: invalid device settings:"+
" dedicated ip \"1.1.1.2\" is not in bind data", errCollErr)
assert.NotEqual(t, newProfile(t), got)
assert.NotEqual(t, newDevices(t), gotDevices)
assert.Len(t, gotDevices, 1)
})
t.Run("empty", func(t *testing.T) {
var emptyDNSProfile *DNSProfile
_, _, err := emptyDNSProfile.toInternal(ctx, TestUpdTime, errColl)
_, _, err := emptyDNSProfile.toInternal(ctx, TestUpdTime, testBind, errColl)
testutil.AssertErrorMsg(t, "profile is nil", err)
})
@ -78,7 +107,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
Deleted: true,
}
got, gotDevices, err := dp.toInternal(ctx, TestUpdTime, errColl)
got, gotDevices, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
require.NoError(t, err)
require.NotNil(t, got)
@ -91,7 +120,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
dp := NewTestDNSProfile(t)
dp.Parental.Schedule.Tmz = "invalid"
_, _, err := dp.toInternal(ctx, TestUpdTime, errColl)
_, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
testutil.AssertErrorMsg(t, "parental: schedule: loading timezone: unknown time zone invalid", err)
})
@ -102,7 +131,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
End: nil,
}
_, _, err := dp.toInternal(ctx, TestUpdTime, errColl)
_, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
testutil.AssertErrorMsg(t, "parental: schedule: weekday Sunday: bad day range: end 0 less than start 16", err)
})
@ -111,7 +140,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
bm := dp.BlockingMode.(*DNSProfile_BlockingModeCustomIp)
bm.BlockingModeCustomIp.Ipv4 = []byte("1")
_, _, err := dp.toInternal(ctx, TestUpdTime, errColl)
_, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
testutil.AssertErrorMsg(t, "blocking mode: bad custom ipv4: unexpected slice size", err)
})
@ -120,7 +149,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
bm := dp.BlockingMode.(*DNSProfile_BlockingModeCustomIp)
bm.BlockingModeCustomIp.Ipv6 = []byte("1")
_, _, err := dp.toInternal(ctx, TestUpdTime, errColl)
_, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
testutil.AssertErrorMsg(t, "blocking mode: bad custom ipv6: unexpected slice size", err)
})
@ -128,7 +157,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
dp := NewTestDNSProfile(t)
dp.BlockingMode = nil
got, gotDevices, err := dp.toInternal(ctx, TestUpdTime, errColl)
got, gotDevices, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
require.NoError(t, err)
require.NotNil(t, got)
@ -143,7 +172,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
dp := NewTestDNSProfile(t)
dp.Access = nil
got, _, err := dp.toInternal(ctx, TestUpdTime, errColl)
got, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
require.NoError(t, err)
require.NotNil(t, got)
@ -157,7 +186,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
Enabled: false,
}
got, _, err := dp.toInternal(ctx, TestUpdTime, errColl)
got, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
require.NoError(t, err)
require.NotNil(t, got)
@ -451,7 +480,7 @@ func BenchmarkDNSProfile_ToInternal(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
profSink, _, errSink = dp.toInternal(ctx, TestUpdTime, errColl)
profSink, _, errSink = dp.toInternal(ctx, TestUpdTime, testBind, errColl)
}
require.NotNil(b, profSink)

View File

@ -1,8 +1,9 @@
package backendpb_test
import (
context "context"
"context"
"net"
"net/netip"
"net/url"
"strconv"
"testing"
@ -52,6 +53,7 @@ func BenchmarkProfileStorage_Profiles(b *testing.B) {
require.NoError(b, err)
s, err := backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
BindSet: netip.MustParsePrefix("0.0.0.0/0"),
ErrColl: errColl,
Endpoint: &url.URL{
Scheme: "grpc",

View File

@ -106,6 +106,9 @@ func (c *chanPacketConn) LocalAddr() (addr net.Addr) { return c.laddr }
// *chanPacketConn.
func (c *chanPacketConn) ReadFrom(b []byte) (n int, raddr net.Addr, err error) {
n, sess, err := c.readFromSession(b, "ReadFrom")
if sess == nil {
return 0, nil, err
}
return n, sess.RemoteAddr(), err
}
@ -121,6 +124,13 @@ func (c *chanPacketConn) readFromSession(
b []byte,
fnName string,
) (n int, s netext.PacketSession, err error) {
var sess *packetSession
defer func() {
if sess != nil {
n = copy(b, sess.readBody)
}
}()
var deadline time.Time
func() {
c.deadlineMu.RLock()
@ -137,16 +147,19 @@ func (c *chanPacketConn) readFromSession(
}
defer stopTimer()
sess, err := receiveWithTimer(c.sessions, timerCh)
sess, err = receiveWithTimer(c.sessions, timerCh)
if err != nil {
err = fmt.Errorf("receiving: %w", err)
return 0, nil, wrapConnError(tnChanPConn, fnName, c.laddr, err)
// Prevent netext.PacketSession((*packetSession)(nil)).
if sess != nil {
s = sess
}
return 0, s, wrapConnError(tnChanPConn, fnName, c.laddr, err)
}
n = copy(b, sess.readBody)
return n, sess, nil
return 0, sess, nil
}
// timerFromDeadline converts a deadline value into a timer channel. stopTimer

View File

@ -10,12 +10,12 @@ import (
"sync"
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/netext"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/mapsutil"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/syncutil"
"github.com/miekg/dns"
)
@ -211,12 +211,12 @@ func (m *Manager) validateIfaceSubnet(ifaceName string, subnet netip.Prefix) (er
}
// type check
var _ agdservice.Interface = (*Manager)(nil)
var _ service.Interface = (*Manager)(nil)
// Start implements the [agdservice.Interface] interface for *Manager. If m is
// Start implements the [service.Interface] interface for *Manager. If m is
// nil, Start returns nil, since this feature is optional.
//
// TODO(a.garipov): Consider an interface solution.
// TODO(a.garipov): Consider an interface solution instead of the nil exception.
//
// TODO(a.garipov): Use the context for cancelation.
func (m *Manager) Start(_ context.Context) (err error) {
@ -249,12 +249,15 @@ func (m *Manager) Start(_ context.Context) (err error) {
return nil
}
// Shutdown implements the [agdservice.Interface] interface for *Manager. If m
// is nil, Shutdown returns nil, since this feature is optional.
//
// TODO(a.garipov): Consider an interface solution.
// Shutdown implements the [service.Interface] interface for *Manager. Shutdown
// does not actually wait for all sockets to close. If m is nil, Shutdown
// returns nil, since this feature is optional.
//
// TODO(a.garipov): Consider waiting for all sockets to close.
//
// TODO(a.garipov): Use the context for cancelation.
//
// TODO(a.garipov): Consider an interface solution instead of the nil exception.
func (m *Manager) Shutdown(_ context.Context) (err error) {
if m == nil {
return nil

View File

@ -7,8 +7,8 @@ import (
"fmt"
"net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/service"
)
// Manager creates individual listeners and dispatches connections to them.
@ -43,9 +43,9 @@ func (m *Manager) ListenConfig(id ID, subnet netip.Prefix) (c *ListenConfig, err
}
// type check
var _ agdservice.Interface = (*Manager)(nil)
var _ service.Interface = (*Manager)(nil)
// Start implements the [agdservice.Interface] interface for *Manager. If m is
// Start implements the [service.Interface] interface for *Manager. If m is
// nil, Start returns nil, since this feature is optional.
//
// It is only supported on Linux.
@ -57,8 +57,8 @@ func (m *Manager) Start(_ context.Context) (err error) {
return fmt.Errorf("bindtodevice: starting: %w; only supported on linux", errors.ErrUnsupported)
}
// Shutdown implements the [agdservice.Interface] interface for *Manager. If m
// is nil, Shutdown returns nil, since this feature is optional.
// Shutdown implements the [service.Interface] interface for *Manager. If m is
// nil, Shutdown returns nil, since this feature is optional.
//
// It is only supported on Linux.
func (m *Manager) Shutdown(_ context.Context) (err error) {

View File

@ -1,8 +1,7 @@
package cmd
import (
"fmt"
"net/netip"
"github.com/AdguardTeam/golibs/netutil"
)
// accessConfig is the configuration that controls IP and hosts blocking.
@ -11,7 +10,7 @@ type accessConfig struct {
BlockedQuestionDomains []string `yaml:"blocked_question_domains"`
// BlockedClientSubnets is a list of IP addresses or subnets to block.
BlockedClientSubnets []string `yaml:"blocked_client_subnets"`
BlockedClientSubnets []netutil.Prefix `yaml:"blocked_client_subnets"`
}
// validate returns an error if the access configuration is invalid.
@ -20,21 +19,5 @@ func (a *accessConfig) validate() (err error) {
return errNilConfig
}
for i, s := range a.BlockedClientSubnets {
// TODO(a.garipov): Use [netutil.ParseSubnet] after refactoring it to
// [netip.Addr].
_, parseErr := netip.ParseAddr(s)
if parseErr == nil {
continue
}
_, parseErr = netip.ParsePrefix(s)
if parseErr == nil {
continue
}
return fmt.Errorf("value %q at index %d: bad ip or cidr: %w", s, i, parseErr)
}
return nil
}

View File

@ -3,14 +3,18 @@ package cmd
import (
"context"
"fmt"
"net/netip"
"net/url"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"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/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/timeutil"
)
@ -67,17 +71,22 @@ func (c *backendConfig) validate() (err error) {
// handler.
func setupBackend(
conf *backendConfig,
grps []*agd.ServerGroup,
envs *environments,
sigHdlr signalHandler,
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (profDB *profiledb.Default, rec *billstat.RuntimeRecorder, err error) {
) (profDB profiledb.Interface, rec billstat.Recorder, err error) {
if !envs.ProfilesEnabled {
return &profiledb.Disabled{}, billstat.EmptyRecorder{}, nil
}
rec, err = setupBillStat(conf, envs, sigHdlr, errColl)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return nil, nil, err
}
profDB, err = setupProfDB(conf, envs, sigHdlr, errColl)
profDB, err = setupProfDB(conf, grps, envs, sigHdlr, errColl)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return nil, nil, err
@ -91,7 +100,7 @@ func setupBackend(
func setupBillStat(
conf *backendConfig,
envs *environments,
sigHdlr signalHandler,
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (rec *billstat.RuntimeRecorder, err error) {
apiURL := netutil.CloneURL(&envs.BillStatURL.URL)
@ -124,7 +133,7 @@ func setupBillStat(
return nil, fmt.Errorf("starting bill stat recorder refresher: %w", err)
}
sigHdlr.add(billStatRefr)
sigHdlr.Add(billStatRefr)
return rec, nil
}
@ -133,12 +142,14 @@ func setupBillStat(
// registers its refresher in the signal handler.
func setupProfDB(
conf *backendConfig,
grps []*agd.ServerGroup,
envs *environments,
sigHdlr signalHandler,
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (profDB *profiledb.Default, err error) {
apiURL := netutil.CloneURL(&envs.ProfilesURL.URL)
profStrg, err := setupProfStorage(apiURL, errColl)
bindSet := collectBindSubnetSet(grps)
profStrg, err := setupProfStorage(apiURL, bindSet, errColl)
if err != nil {
return nil, fmt.Errorf("creating profile storage: %w", err)
}
@ -174,11 +185,40 @@ func setupProfDB(
return nil, fmt.Errorf("starting default profile database refresher: %w", err)
}
sigHdlr.add(profDBRefr)
sigHdlr.Add(profDBRefr)
return profDB, nil
}
// collectBindSubnetSet returns a subnet set with IP addresses of servers in the
// provided server groups grps.
func collectBindSubnetSet(grps []*agd.ServerGroup) (s netutil.SubnetSet) {
var serverPrefixes []netip.Prefix
allSingleIP := true
for _, grp := range grps {
for _, srv := range grp.Servers {
for _, p := range srv.BindDataPrefixes() {
allSingleIP = allSingleIP && p.IsSingleIP()
serverPrefixes = append(serverPrefixes, p)
}
}
}
// In cases where an installation only has single-IP prefixes in bind
// interfaces, or no bind interfaces at all, only check the dedicated IPs in
// profiles for validity.
//
// TODO(a.garipov): Do not load profiles on such installations at all, as
// they don't really need them. See AGDNS-1888.
if allSingleIP {
log.Info("warning: all bind ifaces are single-ip; only checking validity of dedicated ips")
return netutil.SubnetSetFunc(netip.Addr.IsValid)
}
return netutil.SliceSubnetSet(serverPrefixes)
}
// Backend API URL schemes.
const (
schemeGRPC = "grpc"
@ -189,11 +229,13 @@ const (
// provided API URL.
func setupProfStorage(
apiURL *url.URL,
bindSet netutil.SubnetSet,
errColl errcoll.Interface,
) (s profiledb.Storage, err error) {
scheme := apiURL.Scheme
if scheme == schemeGRPC || scheme == schemeGRPCS {
return backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
BindSet: bindSet,
Endpoint: apiURL,
ErrColl: errColl,
})

View File

@ -24,6 +24,9 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/AdGuardDNS/internal/websvc"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/timeutil"
)
@ -41,7 +44,8 @@ func Main() {
envs, err := readEnvs()
check(err)
envs.configureLogs()
// TODO(a.garipov): Use slog everywhere.
slogLogger := envs.configureLogs()
// Signal service startup now that we have the logs set up.
log.Info("main: starting adguard dns")
@ -70,7 +74,9 @@ func Main() {
// Signal handler
sigHdlr := newSignalHandler()
sigHdlr := service.NewSignalHandler(&service.SignalHandlerConfig{
Logger: slogLogger.With(slogutil.KeyPrefix, service.SignalHandlerPrefix),
})
// GeoIP database
@ -160,7 +166,7 @@ func Main() {
accessGlobal, err := access.NewGlobal(
c.Access.BlockedQuestionDomains,
c.Access.BlockedClientSubnets,
netutil.UnembedPrefixes(c.Access.BlockedClientSubnets),
)
check(err)
@ -180,12 +186,14 @@ func Main() {
srvGrps, err := c.ServerGroups.toInternal(messages, btdMgr, fltGroups, c.RateLimit, c.DNS)
check(err)
ctx := context.Background()
// Start the bind-to-device manager here, now that no further calls to
// btdMgr.ListenConfig are required.
err = btdMgr.Start(context.Background())
err = btdMgr.Start(ctx)
check(err)
sigHdlr.add(btdMgr)
sigHdlr.Add(btdMgr)
// TLS keys logging
@ -202,7 +210,7 @@ func Main() {
// Profiles database and billing statistics
profDB, billStatRec, err := setupBackend(c.Backend, envs, sigHdlr, errColl)
profDB, billStatRec, err := setupBackend(c.Backend, srvGrps, envs, sigHdlr, errColl)
check(err)
// DNS checker
@ -230,7 +238,7 @@ func Main() {
// Wait for long-running GeoIP initialization.
check(<-geoIPErrCh)
sigHdlr.add(geoIPRefr)
sigHdlr.Add(geoIPRefr)
// Web service
@ -240,9 +248,9 @@ func Main() {
webSvc := websvc.New(webConf)
// The web service is considered critical, so its Start method panics
// instead of returning an error.
_ = webSvc.Start(context.Background())
_ = webSvc.Start(ctx)
sigHdlr.add(webSvc)
sigHdlr.Add(webSvc)
// DNS service
@ -284,6 +292,7 @@ func Main() {
CacheMinTTL: c.Cache.TTLOverride.Min.Duration,
UseCacheTTLOverride: c.Cache.TTLOverride.Enabled,
UseECSCache: c.Cache.Type == cacheTypeECS,
ProfileDBEnabled: bool(envs.ProfilesEnabled),
ResearchMetrics: bool(envs.ResearchMetrics),
ResearchLogs: bool(envs.ResearchLogs),
}
@ -297,16 +306,16 @@ func Main() {
check(err)
upstreamHealthcheckUpd := newUpstreamHealthcheck(handler, c.Upstream, errColl)
err = upstreamHealthcheckUpd.Start(context.Background())
err = upstreamHealthcheckUpd.Start(ctx)
check(err)
sigHdlr.add(upstreamHealthcheckUpd)
sigHdlr.Add(upstreamHealthcheckUpd)
// The DNS service is considered critical, so its Start method panics
// instead of returning an error.
_ = dnsSvc.Start(context.Background())
_ = dnsSvc.Start(ctx)
sigHdlr.add(dnsSvc)
sigHdlr.Add(dnsSvc)
// Debug HTTP-service
@ -314,9 +323,9 @@ func Main() {
// The debug HTTP service is considered critical, so its Start method panics
// instead of returning an error.
_ = debugSvc.Start(context.Background())
_ = debugSvc.Start(ctx)
sigHdlr.add(debugSvc)
sigHdlr.Add(debugSvc)
// Signal that the server is started.
metrics.SetUpGauge(
@ -327,7 +336,7 @@ func Main() {
runtime.Version(),
)
os.Exit(sigHdlr.handle())
os.Exit(sigHdlr.Handle(ctx))
}
// collectPanics reports all panics in Main. It should be called in a defer.

View File

@ -3,6 +3,7 @@ package cmd
import (
"context"
"fmt"
"log/slog"
"net"
"net/http"
"os"
@ -16,8 +17,10 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/service"
"github.com/caarlos0/env/v7"
"github.com/getsentry/sentry-go"
)
@ -56,6 +59,7 @@ type environments struct {
LogTimestamp strictBool `env:"LOG_TIMESTAMP" envDefault:"1"`
LogVerbose strictBool `env:"VERBOSE" envDefault:"0"`
ProfilesEnabled strictBool `env:"PROFILES_ENABLED" envDefault:"1"`
ResearchMetrics strictBool `env:"RESEARCH_METRICS" envDefault:"0"`
ResearchLogs strictBool `env:"RESEARCH_LOGS" envDefault:"0"`
}
@ -71,8 +75,9 @@ func readEnvs() (envs *environments, err error) {
return envs, nil
}
// configureLogs sets the configuration for the plain text logs.
func (envs *environments) configureLogs() {
// configureLogs sets the configuration for the plain text logs. It also
// returns a [slog.Logger] for code that uses it.
func (envs *environments) configureLogs() (slogLogger *slog.Logger) {
var flags int
if envs.LogTimestamp {
flags = log.LstdFlags | log.Lmicroseconds
@ -83,6 +88,13 @@ func (envs *environments) configureLogs() {
if envs.LogVerbose {
log.SetLevel(log.DEBUG)
}
return slogutil.New(&slogutil.Config{
Output: os.Stdout,
Format: slogutil.FormatAdGuardLegacy,
AddTimestamp: bool(envs.LogTimestamp),
Verbose: bool(envs.LogVerbose),
})
}
// buildErrColl builds and returns an error collector from environment.
@ -158,7 +170,7 @@ func (envs *environments) debugConf(dnsDB dnsdb.Interface) (conf *debugsvc.Confi
// buildRuleStat returns a filtering rule statistics collector from environment and
// registers its refresher in sigHdlr, if necessary.
func (envs *environments) buildRuleStat(
sigHdlr signalHandler,
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (r rulestat.Interface, err error) {
if envs.RuleStatURL == nil {
@ -187,7 +199,7 @@ func (envs *environments) buildRuleStat(
return nil, fmt.Errorf("starting rulestat refresher: %w", err)
}
sigHdlr.add(refr)
sigHdlr.Add(refr)
return httpRuleStat, nil
}

View File

@ -12,6 +12,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/timeutil"
"github.com/c2h5oh/datasize"
)
@ -136,7 +137,7 @@ func (c *fltRuleListCache) validate() (err error) {
// registers its refresher in the signal handler.
func setupFilterStorage(
conf *filter.DefaultStorageConfig,
sigHdlr signalHandler,
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
refreshTimeout time.Duration,
) (strg *filter.DefaultStorage, err error) {
@ -162,7 +163,7 @@ func setupFilterStorage(
return nil, fmt.Errorf("starting default filter storage update: %w", err)
}
sigHdlr.add(refr)
sigHdlr.Add(refr)
return strg, nil
}

View File

@ -41,7 +41,6 @@ func (c *interfaceListenersConfig) toInternal(
return errors.Annotate(m.Add(id, l.Interface, l.Port, ctrlConf), "adding listener %q: %w", id)
},
)
if err != nil {
return nil, err
}

View File

@ -5,7 +5,6 @@ import (
"fmt"
"net/url"
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/connlimiter"
"github.com/AdguardTeam/AdGuardDNS/internal/consul"
@ -13,6 +12,8 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/timeutil"
"github.com/c2h5oh/datasize"
)
@ -64,7 +65,7 @@ type rateLimitConfig struct {
// allowListConfig is the consul allow list configuration.
type allowListConfig struct {
// List contains IPs and CIDRs.
List []string `yaml:"list"`
List []netutil.Prefix `yaml:"list"`
// RefreshIvl time between two updates of allow list from the Consul URL.
RefreshIvl timeutil.Duration `yaml:"refresh_interval"`
@ -138,14 +139,10 @@ func (c *rateLimitConfig) validate() (err error) {
func setupRateLimiter(
conf *rateLimitConfig,
consulAllowlist *url.URL,
sigHdlr signalHandler,
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (rateLimiter *ratelimit.Backoff, connLimiter *connlimiter.Limiter, err error) {
allowSubnets, err := agdnet.ParseSubnets(conf.Allowlist.List...)
if err != nil {
return nil, nil, fmt.Errorf("parsing allowlist subnets: %w", err)
}
allowSubnets := netutil.UnembedPrefixes(conf.Allowlist.List)
allowlist := ratelimit.NewDynamicAllowlist(allowSubnets, nil)
refresher, err := consul.NewAllowlistRefresher(allowlist, consulAllowlist)
if err != nil {
@ -168,7 +165,7 @@ func setupRateLimiter(
return nil, nil, fmt.Errorf("starting allowlist refresher: %w", err)
}
sigHdlr.add(refr)
sigHdlr.Add(refr)
return ratelimit.NewBackoff(conf.toInternal(allowlist)), conf.ConnectionLimit.toInternal(), nil
}

View File

@ -14,6 +14,7 @@ import (
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/timeutil"
)
@ -99,7 +100,7 @@ func setupHashPrefixFilter(
url *urlutil.URL,
cachePath string,
maxSize uint64,
sigHdlr signalHandler,
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (strg *hashprefix.Storage, flt *hashprefix.Filter, err error) {
fltConf, err := conf.toInternal(errColl, resolver, cloner, id, url, cachePath, maxSize)
@ -127,7 +128,7 @@ func setupHashPrefixFilter(
return nil, nil, fmt.Errorf("starting refresher for hash prefix filter %s: %w", id, err)
}
sigHdlr.add(refr)
sigHdlr.Add(refr)
return fltConf.Hashes, flt, nil
}

View File

@ -2,11 +2,13 @@ package cmd
import (
"fmt"
"net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/bindtodevice"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/stringutil"
)
@ -39,10 +41,11 @@ func (srvGrps serverGroups) toInternal(
}
svcSrvGrps[i] = &agd.ServerGroup{
TLS: tlsConf,
DDR: g.DDR.toInternal(messages),
Name: agd.ServerGroupName(g.Name),
FilteringGroup: fltGrpID,
BlockPageRedirect: g.BlockPageRedirect.toInternal(),
DDR: g.DDR.toInternal(messages),
TLS: tlsConf,
Name: agd.ServerGroupName(g.Name),
FilteringGroup: fltGrpID,
}
svcSrvGrps[i].Servers, err = g.Servers.toInternal(tlsConf, btdMgr, ratelimitConf, dnsConf)
@ -83,13 +86,16 @@ func (srvGrps serverGroups) validate() (err error) {
// TODO(a.garipov): Think about more consistent naming, since this object is a
// configuration, but it also stores other configurations.
type serverGroup struct {
// TLS are the TLS settings for this server, if any.
TLS *tlsConfig `yaml:"tls"`
// BlockPageRedirect is the configuration for the server group's block page.
BlockPageRedirect *serverGroupBlockPageConfig `yaml:"block_page_redirect"`
// DDR is the Discovery Of Designated Resolvers (DDR) configuration for this
// server group.
DDR *ddrConfig `yaml:"ddr"`
// TLS are the TLS settings for this server, if any.
TLS *tlsConfig `yaml:"tls"`
// Name is the unique name of the server group.
Name string `yaml:"name"`
@ -111,6 +117,11 @@ func (g *serverGroup) validate() (err error) {
return errors.Error("no filtering_group")
}
err = g.BlockPageRedirect.validate()
if err != nil {
return fmt.Errorf("block_page_redirect: %w", err)
}
err = g.DDR.validate()
if err != nil {
return fmt.Errorf("ddr: %w", err)
@ -128,3 +139,255 @@ func (g *serverGroup) validate() (err error) {
return nil
}
// serverGroupBlockPageConfig is the configuration for a [serverGroup]'s block
// page. See [agd.BlockPageRedirect] and the related types for more
// documentation and contracts.
type serverGroupBlockPageConfig struct {
// Apply defines request parameters based on which the block page is always
// shown.
Apply *serverGroupBlockPageApplyConfig `yaml:"apply"`
// Skip defines request parameters based on which the block page is never
// shown, regardless of the probability.
Skip *serverGroupBlockPageSkipConfig `yaml:"skip"`
// IPv4 are the IPv4 records of the block page, used to respond to A
// queries.
IPv4 []*serverGroupBlockPageRecord `yaml:"ipv4"`
// IPv6 are the IPv6 records of the block page, used to respond to AAAA
// queries.
IPv6 []*serverGroupBlockPageRecord `yaml:"ipv6"`
// Probability defines the probability of responding with the block page IPs
// based on remote address.
Probability float64 `yaml:"probability"`
// Enabled defines whether the block-page feature is enabled.
Enabled bool `yaml:"enabled"`
}
// toInternal returns the block-page redirect configuration for a server group.
// c is assumed to be valid.
func (c *serverGroupBlockPageConfig) toInternal() (conf *agd.BlockPageRedirect) {
if !c.Enabled {
return &agd.BlockPageRedirect{}
}
var ipv4 []netip.Addr
for _, r := range c.IPv4 {
ipv4 = append(ipv4, r.Address)
}
var ipv6 []netip.Addr
for _, r := range c.IPv6 {
ipv6 = append(ipv6, r.Address)
}
return &agd.BlockPageRedirect{
Apply: c.Apply.toInternal(),
Skip: c.Skip.toInternal(),
IPv4: ipv4,
IPv6: ipv6,
Probability: agd.MustNewProbability(c.Probability),
Enabled: c.Enabled,
}
}
// validate returns an error if the block-page redirect configuration is
// invalid.
func (c *serverGroupBlockPageConfig) validate() (err error) {
switch {
case c == nil:
return errNilConfig
case !c.Enabled:
return nil
case len(c.IPv4) == 0 && len(c.IPv6) == 0:
return errors.Error("ipv4, ipv6, or both must be set")
}
_, err = agd.NewProbability(c.Probability)
if err != nil {
return fmt.Errorf("probability: %w", err)
}
err = c.validateAddrs()
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
}
err = c.Apply.validate()
if err != nil {
return fmt.Errorf("apply: %w", err)
}
err = c.Skip.validate()
if err != nil {
return fmt.Errorf("skip: %w", err)
}
return nil
}
// validateAddrs returns an error if the block-page redirect if the IP addresses
// in the block-page redirect configuration are invalid.
func (c *serverGroupBlockPageConfig) validateAddrs() (err error) {
for i, r := range c.IPv4 {
err = r.validate()
if err != nil {
return fmt.Errorf("ipv4: at index %d: address: %w", i, err)
} else if !r.Address.Is4() {
return fmt.Errorf("ipv4: at index %d: address: not ipv4: %v", i, r.Address)
}
}
for i, r := range c.IPv6 {
err = r.validate()
if err != nil {
return fmt.Errorf("ipv6: at index %d: %w", i, err)
} else if !r.Address.Is6() {
return fmt.Errorf("ipv6: at index %d: address: not ipv6: %v", i, r.Address)
}
}
return nil
}
// serverGroupBlockPageRecord is a structure for defining answer records in
// [serverGroupBlockPageConfig].
type serverGroupBlockPageRecord struct {
Address netip.Addr `yaml:"address"`
}
// validate returns an error if the record configuration is invalid.
func (c *serverGroupBlockPageRecord) validate() (err error) {
switch {
case c == nil:
return errNilConfig
case !c.Address.IsValid():
return errors.Error("invalid addr")
default:
return nil
}
}
// serverGroupBlockPageApplyConfig defines the conditions for applying the
// block-page logic for a particular request.
type serverGroupBlockPageApplyConfig struct {
// Client are the parameters for clients for which block page is always
// enabled.
Client []*serverGroupBlockPageClientConfig `yaml:"client"`
}
// toInternal returns the block-page redirect applying configuration for a
// server group. c is assumed to be valid.
func (c *serverGroupBlockPageApplyConfig) toInternal() (conf *agd.BlockPageRedirectApply) {
var subnets []netip.Prefix
for _, cli := range c.Client {
subnets = append(subnets, cli.Address.Prefix)
}
return &agd.BlockPageRedirectApply{
ClientSubnets: subnets,
}
}
// validate returns an error if the block-page redirect applying configuration
// is invalid.
func (c *serverGroupBlockPageApplyConfig) validate() (err error) {
if c == nil {
return errNilConfig
}
for i, cli := range c.Client {
err = cli.validate()
if err != nil {
return fmt.Errorf("client: at index %d: %w", i, err)
}
}
return nil
}
// serverGroupBlockPageClientConfig is a common structure for defining clients
// in [serverGroupBlockPageSkipConfig] and [serverGroupBlockPageApplyConfig].
type serverGroupBlockPageClientConfig struct {
Address netutil.Prefix `yaml:"address"`
}
// validate returns an error if the client configuration is invalid.
func (c *serverGroupBlockPageClientConfig) validate() (err error) {
switch {
case c == nil:
return errNilConfig
case !c.Address.IsValid():
return errors.Error("invalid addr")
default:
return nil
}
}
// serverGroupBlockPageSkipConfig defines the conditions for skipping the block
// page logic for a particular request.
type serverGroupBlockPageSkipConfig struct {
// Client are the parameters for clients for which block page is always
// disabled.
Client []*serverGroupBlockPageClientConfig `yaml:"client"`
// QuestionDomains are the parameters for request questions for which block
// page is always disabled.
Question []*serverGroupBlockPageQuestionConfig `yaml:"question"`
}
// toInternal returns the block-page redirect skipping configuration for a
// server group. c is assumed to be valid.
func (c *serverGroupBlockPageSkipConfig) toInternal() (conf *agd.BlockPageRedirectSkip) {
var subnets []netip.Prefix
for _, cli := range c.Client {
subnets = append(subnets, cli.Address.Prefix)
}
var domains []string
for _, q := range c.Question {
domains = append(domains, q.Domain)
}
return &agd.BlockPageRedirectSkip{
ClientSubnets: subnets,
QuestionDomains: domains,
}
}
// validate returns an error if the block-page redirect skipping configuration
// is invalid.
func (c *serverGroupBlockPageSkipConfig) validate() (err error) {
if c == nil {
return errNilConfig
}
for i, cli := range c.Client {
err = cli.validate()
if err != nil {
return fmt.Errorf("client: at index %d: %w", i, err)
}
}
for i, q := range c.Question {
switch {
case q == nil:
return fmt.Errorf("question: at index %d: %w", i, errNilConfig)
case q.Domain == "":
return fmt.Errorf("question: at index %d: %w", i, errors.Error("empty domain"))
}
}
return nil
}
// serverGroupBlockPageQuestionConfig is a structure for defining question
// domains in [serverGroupBlockPageRedirectSkip].
type serverGroupBlockPageQuestionConfig struct {
Domain string `yaml:"domain"`
}

View File

@ -1,85 +0,0 @@
package cmd
import (
"context"
"os"
"os/signal"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/golibs/log"
"golang.org/x/sys/unix"
)
// signalHandler processes incoming signals and shuts services down.
type signalHandler struct {
signal chan os.Signal
// services are the services that are shut down before application
// exiting.
services []agdservice.Interface
}
// newSignalHandler returns a new signalHandler that shuts down services.
func newSignalHandler() (h signalHandler) {
h = signalHandler{
signal: make(chan os.Signal, 1),
}
signal.Notify(h.signal, unix.SIGINT, unix.SIGQUIT, unix.SIGTERM)
return h
}
// add adds a service to the signal handler.
func (h *signalHandler) add(s agdservice.Interface) {
h.services = append(h.services, s)
}
// Exit status constants.
const (
statusSuccess = 0
statusError = 1
)
// handle processes OS signals. status is statusSuccess on success and
// statusError on error.
func (h *signalHandler) handle() (status int) {
defer log.OnPanic("signalHandler.handle")
for sig := range h.signal {
log.Info("sighdlr: received signal %q", sig)
switch sig {
case
unix.SIGINT,
unix.SIGQUIT,
unix.SIGTERM:
return h.shutdown()
}
}
// Shouldn't happen, since h.signal is currently never closed.
return statusError
}
// shutdown gracefully shuts down all services. status is statusSuccess on
// success and statusError on error.
func (h *signalHandler) shutdown() (status int) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
log.Info("sighdlr: shutting down services")
for i := len(h.services) - 1; i >= 0; i-- {
s := h.services[i]
err := s.Shutdown(ctx)
if err != nil {
log.Error("sighdlr: shutting down service at index %d: %s", i, err)
status = statusError
}
}
log.Info("sighdlr: shutting down adguard dns")
return status
}

View File

@ -16,6 +16,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/prometheus/client_golang/prometheus"
)
@ -300,7 +301,7 @@ func enableTLSKeyLogging(grps []*agd.ServerGroup, keyLogFileName string) (err er
// registers its refresher in the signal handler.
func setupTicketRotator(
srvGrps []*agd.ServerGroup,
sigHdlr signalHandler,
sigHdlr *service.SignalHandler,
errColl errcoll.Interface,
) (err error) {
tickRot, err := newTicketRotator(srvGrps)
@ -324,7 +325,7 @@ func setupTicketRotator(
return fmt.Errorf("starting ticket rotator refresh: %w", err)
}
sigHdlr.add(refr)
sigHdlr.Add(refr)
return nil
}

View File

@ -13,11 +13,10 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/prometheus"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/timeutil"
)
// DNS upstream configuration
// upstreamConfig is the upstream module configuration.
type upstreamConfig struct {
// Healthcheck contains the upstream healthcheck configuration.
@ -160,9 +159,9 @@ func newUpstreamHealthcheck(
handler *forward.Handler,
conf *upstreamConfig,
errColl errcoll.Interface,
) (refr agdservice.Interface) {
) (refr service.Interface) {
if !conf.Healthcheck.Enabled {
return agdservice.Empty{}
return service.Empty{}
}
return agdservice.NewRefreshWorker(&agdservice.RefreshWorkerConfig{

View File

@ -7,10 +7,10 @@ import (
"io"
"net/http"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/pprofutil"
"github.com/AdguardTeam/golibs/service"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
@ -69,11 +69,15 @@ func startServer(s *server) {
}
// type check
var _ agdservice.Interface = (*Service)(nil)
var _ service.Interface = (*Service)(nil)
// Start implements the [agdservice.Interface] interface for *Service. It
// starts serving all endpoints. err is always nil, if any endpoint fails to
// start, it panics.
// Start implements the [service.Interface] interface for *Service. It starts
// serving all endpoints but does not wait for them to actually go online. err
// is always nil, if any endpoint fails to start, it panics.
//
// TODO(a.garipov): Wait for the services to go online.
//
// TODO(a.garipov): Use the context for cancelation.
func (svc *Service) Start(_ context.Context) (err error) {
for _, srv := range svc.servers {
go startServer(srv)
@ -82,8 +86,8 @@ func (svc *Service) Start(_ context.Context) (err error) {
return nil
}
// Shutdown implements the [agdservice.Interface] interface for *Service. It
// stops serving all endpoints.
// Shutdown implements the [service.Interface] interface for *Service. It stops
// serving all endpoints.
func (svc *Service) Shutdown(ctx context.Context) (err error) {
srvNum := 0
for _, srv := range svc.servers {

View File

@ -76,6 +76,15 @@ func (kv *httpKV) get(ctx context.Context, key string) (inf *info, err error) {
}
defer func() { err = errors.WithDeferred(err, httpResp.Body.Close()) }()
// Note that, if no key exists at the given path, a 404 is returned instead
// of a normal 200 response.
//
// See https://developer.hashicorp.com/consul/api-docs/kv#read-key.
err = agdhttp.CheckStatus(httpResp, http.StatusOK)
if err != nil {
return nil, fmt.Errorf("response for key %q: %w", key, err)
}
var resp []*consulKVResponse
err = json.NewDecoder(httpResp.Body).Decode(&resp)
if err != nil {
@ -153,6 +162,14 @@ func (kv *httpKV) set(ctx context.Context, key string, inf *info) (err error) {
}
defer func() { err = errors.WithDeferred(err, sessHTTPResp.Body.Close()) }()
// Status 200 is expected.
//
// See https://developer.hashicorp.com/consul/api-docs/session.
err = agdhttp.CheckStatus(sessHTTPResp, http.StatusOK)
if err != nil {
return fmt.Errorf("getting session for key %q: %w", key, err)
}
sessResp := &consulSessionResponse{}
err = json.NewDecoder(sessHTTPResp.Body).Decode(sessResp)
if err != nil {
@ -176,6 +193,14 @@ func (kv *httpKV) set(ctx context.Context, key string, inf *info) (err error) {
}
defer func() { err = errors.WithDeferred(err, resp.Body.Close()) }()
// Status 200 is expected.
//
// See https://github.com/hashicorp/consul/blob/main/api/kv.go#L224.
err = agdhttp.CheckStatus(resp, http.StatusOK)
if err != nil {
return fmt.Errorf("setting key %q: %w", key, err)
}
return nil
}

View File

@ -209,7 +209,75 @@ func TestHTTPKV(t *testing.T) {
dnsCk.ServeHTTP(rw, r)
assert.Equal(t, http.StatusInternalServerError, rw.Code)
assert.Equal(t, wantResp, rw.Body.String())
})
}
// newKVErrorServer returns URLs emulating behavior of Consul KV database
// server returning HTTP errors.
func newKVErrorServer(t *testing.T) (kv, sess *url.URL) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
}))
t.Cleanup(srv.Close)
u, err := url.Parse(srv.URL)
require.NoError(t, err)
return u.JoinPath(kvPath), u.JoinPath(sessPath)
}
func TestHTTPKV_status_error(t *testing.T) {
const (
randomid = "randomid"
localDomain = "example.local"
)
conf := &dnscheck.ConsulConfig{
Messages: &dnsmsg.Constructor{},
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) {},
},
Domains: []string{localDomain},
NodeLocation: "some-node-location",
NodeName: "some-node-name",
TTL: 1 * time.Minute,
}
conf.ConsulKVURL, conf.ConsulSessionURL = newKVErrorServer(t)
dnsCk, err := dnscheck.NewConsul(conf)
require.NoError(t, err)
req := dnsservertest.CreateMessage(randomid+"-"+localDomain, dns.TypeA)
ri := &agd.RequestInfo{
Device: &agd.Device{ID: "some-device-id"},
Profile: &agd.Profile{ID: "some-profile-id"},
ServerGroup: "some-server-group-name",
Server: "some-server-name",
Host: randomid + "-" + localDomain,
RemoteIP: testRemoteIP,
QType: dns.TypeA,
Proto: agd.ProtoDNS,
}
_, err = dnsCk.Check(context.Background(), req, ri)
require.NoError(t, err)
dnscheck.FlushConsulCache(t, dnsCk)
t.Run("fail", func(t *testing.T) {
const wantResp = `getting from consul: response for key "randomid": server "": ` +
`status code error: expected 200, got 500` + "\n"
r := httptest.NewRequest(http.MethodGet, (&url.URL{
Scheme: "http",
Host: randomid + "-" + localDomain,
Path: "/dnscheck/test",
}).String(), strings.NewReader(""))
rw := httptest.NewRecorder()
dnsCk.ServeHTTP(rw, r)
assert.Equal(t, http.StatusInternalServerError, rw.Code)
assert.Equal(t, wantResp, rw.Body.String())
})
}

View File

@ -200,6 +200,7 @@ func (c *Constructor) AppendDebugExtra(req, resp *dns.Msg, str string) (err erro
// positive numbers, but we need a ceiling operation here.
strNum := (strLen + MaxTXTStringLen - 1) / MaxTXTStringLen
// TODO(a.garipov): Use slices.Chunk in Go 1.23.
newStr := make([]string, strNum)
for i := 0; i < strNum; i++ {
start := i * MaxTXTStringLen

View File

@ -1,11 +1,30 @@
package dnsserver_test
import (
"context"
"testing"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/golibs/testutil"
)
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
// testTimeout is a common timeout for tests.
const testTimeout = dnsserver.DefaultReadTimeout
// contextWithTimeout is a helper that creates a new context with timeout and
// registers ctx's cleanup with t.Cleanup.
//
// TODO(a.garipov): Move to golibs and DRY.
func contextWithTimeout(tb testing.TB, timeout time.Duration) (ctx context.Context) {
tb.Helper()
ctx, cancel := context.WithTimeout(context.Background(), timeout)
tb.Cleanup(cancel)
return ctx
}

View File

@ -189,12 +189,12 @@ func RunLocalQUICServer(
tlsConfig *tls.Config,
) (s *dnsserver.ServerQUIC, addr *net.UDPAddr, err error) {
conf := dnsserver.ConfigQUIC{
TLSConfig: tlsConfig,
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
Handler: h,
},
TLSConfig: tlsConfig,
}
s = dnsserver.NewServerQUIC(conf)
@ -209,7 +209,7 @@ func RunLocalQUICServer(
addr, ok := s.LocalUDPAddr().(*net.UDPAddr)
if !ok {
return nil, nil, fmt.Errorf("invalid listen addr: %s", addr)
return nil, nil, fmt.Errorf("invalid listen addr: %T(%[1]v)", s.LocalUDPAddr())
}
return s, addr, nil

View File

@ -1,21 +1,21 @@
module github.com/AdguardTeam/AdGuardDNS/internal/dnsserver
go 1.21.5
go 1.21.8
require (
github.com/AdguardTeam/golibs v0.18.1
github.com/AdguardTeam/golibs v0.20.1
github.com/ameshkov/dnscrypt/v2 v2.2.7
github.com/ameshkov/dnsstamps v1.0.3
github.com/bluele/gcache v0.0.2
github.com/miekg/dns v1.1.56
github.com/panjf2000/ants/v2 v2.8.2
github.com/miekg/dns v1.1.58
github.com/panjf2000/ants/v2 v2.9.0
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
github.com/prometheus/client_golang v1.17.0
github.com/quic-go/quic-go v0.39.0
github.com/prometheus/client_golang v1.18.0
github.com/quic-go/quic-go v0.41.0
github.com/stretchr/testify v1.8.4
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
golang.org/x/net v0.17.0
golang.org/x/sys v0.13.0
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
golang.org/x/net v0.21.0
golang.org/x/sys v0.17.0
)
require (
@ -24,23 +24,21 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/onsi/ginkgo/v2 v2.13.0 // indirect
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/common v0.46.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.3.4 // indirect
go.uber.org/mock v0.3.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/mod v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/tools v0.14.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,4 +1,5 @@
github.com/AdguardTeam/golibs v0.18.1 h1:6u0fvrIj2qjUsRdbIGJ9AR0g5QRSWdKIo/DYl3tp5aM=
github.com/AdguardTeam/golibs v0.20.1 h1:ol8qLjWGZhU9paMMwN+OLWVTUigGsXa29iVTyd62VKY=
github.com/AdguardTeam/golibs v0.20.1/go.mod h1:bgcMgRviCKyU6mkrX+RtT/OsKPFzyppelfRsksMG3KU=
github.com/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=
@ -17,48 +18,44 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ=
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo=
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/panjf2000/ants/v2 v2.8.2 h1:D1wfANttg8uXhC9149gRt1PDQ+dLVFjNXkCEycMcvQQ=
github.com/panjf2000/ants/v2 v2.8.2/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/panjf2000/ants/v2 v2.9.0 h1:SztCLkVxBRigbg+vt0S5QvF5vxAbxbKt09/YfAJ0tEo=
github.com/panjf2000/ants/v2 v2.9.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible h1:IWzUvJ72xMjmrjR9q3H1PF+jwdN0uNQiR2t1BLNalyo=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y=
github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg=
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.39.0 h1:AgP40iThFMY0bj8jGxROhw3S0FMGa8ryqsmi9tBH3So=
github.com/quic-go/quic-go v0.39.0/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
github.com/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=
@ -70,31 +67,27 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@ -474,7 +474,7 @@ func (s *ServerBase) waitShutdown(ctx context.Context) (err error) {
// isStarted returns true if the server is started.
func (s *ServerBase) isStarted() (started bool) {
s.lock.RLock()
started = s.started
s.lock.RUnlock()
return started
defer s.lock.RUnlock()
return s.started
}

View File

@ -313,7 +313,7 @@ func BenchmarkServeQUIC(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
resp := sendQUICMessage(b, sess, req, false)
resp := requireSendQUICMessage(b, sess, req)
require.NotNil(b, resp)
require.True(b, resp.Response)
}

View File

@ -108,6 +108,8 @@ func NewServerDNS(conf ConfigDNS) (s *ServerDNS) {
// server with a TLS layer on top of it.
func newServerDNS(proto Protocol, conf ConfigDNS) (s *ServerDNS) {
// Init default settings first.
//
// TODO(a.garipov): Use cmp.Or in Go 1.22.
if conf.ReadTimeout == 0 {
conf.ReadTimeout = DefaultReadTimeout
}

View File

@ -246,8 +246,16 @@ func (s *ServerHTTPS) shutdown(ctx context.Context) (err error) {
s.started = false
// First step, close the active listener right away.
s.closeListeners()
// First step, close the active TCP listener right away. Don't close the
// UDP one, as if there is one, it is closed by closing the QUIC listener.
//
// TODO(a.garipov): Fix this mess.
if s.tcpListener != nil {
err = s.tcpListener.Close()
if err != nil {
log.Info("[%s]: Failed to close NetworkTCP listener: %v", s.Name(), err)
}
}
// Second, shutdown the HTTP server.
err = s.httpServer.Shutdown(ctx)

View File

@ -597,7 +597,6 @@ func createJSONRequest(
requestURL := fmt.Sprintf("%s://test.local%s?%s", proto, dnsserver.PathJSON, q.Encode())
r, err = http.NewRequest(method, requestURL, nil)
if err != nil {
return nil, err
}

View File

@ -66,11 +66,11 @@ var compatProtoDQ = []string{"doq-i00", "doq-i02", "doq-i03", "dq"}
// ConfigQUIC is a struct that needs to be passed to NewServerQUIC to
// initialize a new ServerQUIC instance.
type ConfigQUIC struct {
ConfigBase
// TLSConfig is the TLS configuration for QUIC.
TLSConfig *tls.Config
ConfigBase
// MaxStreamsPerPeer is the maximum number of concurrent streams that a peer
// is allowed to open.
MaxStreamsPerPeer int
@ -83,8 +83,6 @@ type ConfigQUIC struct {
type ServerQUIC struct {
*ServerBase
conf ConfigQUIC
// pool is a goroutine pool we use to process DNS queries. Complicated
// logic may require growing the goroutine's stack and we experienced it
// in AdGuard DNS. The easiest way to avoid spending extra time on this is
@ -100,6 +98,10 @@ type ServerQUIC struct {
// quicListener is a listener that we use to accept DoQ connections.
quicListener *quic.Listener
// TODO(a.garipov): Remove this and only save the values a server actually
// uses.
conf ConfigQUIC
}
// quicBytePoolSize is the size for the QUIC byte pools.
@ -120,10 +122,10 @@ func NewServerQUIC(conf ConfigQUIC) (s *ServerQUIC) {
s = &ServerQUIC{
ServerBase: newServerBase(ProtoDoQ, conf.ConfigBase),
conf: conf,
pool: newPoolNonblocking(),
reqPool: syncutil.NewSlicePool[byte](quicBytePoolSize),
respPool: syncutil.NewSlicePool[byte](quicBytePoolSize),
conf: conf,
}
return s
@ -207,7 +209,6 @@ func (s *ServerQUIC) shutdown() (err error) {
s.started = false
// Now close all listeners
s.closeListeners()
err = s.quicListener.Close()
if err != nil {
// Log this error but do not return it
@ -242,6 +243,12 @@ func (s *ServerQUIC) serveQUIC(ctx context.Context, l *quic.Listener) (err error
// Wait until all conns are processed before exiting this method
defer wg.Wait()
// Use a context that is canceled once this connection ends to mitigate
// quic-go's mishandling of contexts. See TODO in serveQUICConn.
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
defer cancel()
for s.isStarted() {
err = s.acceptQUICConn(ctx, l, wg)
if err != nil {
@ -251,7 +258,6 @@ func (s *ServerQUIC) serveQUIC(ctx context.Context, l *quic.Listener) (err error
return err
}
}
return nil
@ -294,7 +300,7 @@ func (s *ServerQUIC) acceptQUICConn(
}
// serveQUICConnAsync wraps serveQUICConn call and handles all possible errors
// that might happen there. It also makes sure that the WaitGroup will be
// that might happen there. It also makes sure that the WaitGroup will be
// decremented.
func (s *ServerQUIC) serveQUICConnAsync(
ctx context.Context,
@ -331,6 +337,21 @@ func (s *ServerQUIC) serveQUICConn(ctx context.Context, conn quic.Connection) (e
// bidirectional stream.
var stream quic.Stream
acceptCtx, cancel := context.WithDeadline(ctx, time.Now().Add(maxQUICIdleTimeout))
// For some reason AcceptStream below seems to get stuck even when
// acceptCtx is canceled. As a mitigation, check the context manually
// right before feeding it into AcceptStream.
//
// TODO(a.garipov): Try to reproduce and report.
select {
case <-acceptCtx.Done():
cancel()
return fmt.Errorf("checking accept ctx: %w", acceptCtx.Err())
default:
// Go on.
}
stream, err = conn.AcceptStream(acceptCtx)
// Make sure to call the cancel function to avoid leaks.
cancel()
@ -396,9 +417,7 @@ func (s *ServerQUIC) serveQUICStream(
// that stream.
defer log.OnCloserError(stream, log.DEBUG)
var msg *dns.Msg
var doqDraft bool
msg, doqDraft, err = s.readQUICMsg(ctx, stream)
msg, err := s.readQUICMsg(ctx, stream)
if err != nil {
closeQUICConn(conn, DOQCodeProtocolError)
@ -435,15 +454,7 @@ func (s *ServerQUIC) serveQUICStream(
bufPtr := s.respPool.Get()
defer s.respPool.Put(bufPtr)
// Depending on the DoQ version we either write a 2-bytes prefixed message
// or just write the message (for old draft versions).
var b []byte
if doqDraft {
// TODO(ameshkov): remove draft support in the late 2023.
b, err = resp.PackBuffer(*bufPtr)
} else {
b, err = packWithPrefix(resp, *bufPtr)
}
b, err := packWithPrefix(resp, *bufPtr)
if err != nil {
closeQUICConn(conn, DOQCodeProtocolError)
@ -464,7 +475,7 @@ func (s *ServerQUIC) serveQUICStream(
func (s *ServerQUIC) readQUICMsg(
ctx context.Context,
stream quic.Stream,
) (m *dns.Msg, doqDraft bool, err error) {
) (m *dns.Msg, err error) {
bufPtr := s.reqPool.Get()
defer s.reqPool.Put(bufPtr)
@ -485,35 +496,29 @@ func (s *ServerQUIC) readQUICMsg(
// received.
if n < DNSHeaderSize {
if err != nil {
return nil, false, fmt.Errorf("failed to read QUIC message: %w", err)
return nil, fmt.Errorf("failed to read QUIC message: %w", err)
}
s.metrics.OnInvalidMsg(ctx)
return nil, false, dns.ErrShortRead
return nil, dns.ErrShortRead
}
// Note that we support both the old drafts and the new RFC. In the old
// draft DNS messages were not prefixed with the message length.
// TODO(a.garipov): DRY logic with the TCP one.
m = &dns.Msg{}
// We're checking if the first two bytes contain the length of the message.
// According to the spec, the DNS message ID is 0 so the first two bytes
// will be zero in the case of an old draft implementation so this check
// should be reliable.
packetLen := binary.BigEndian.Uint16(buf[:2])
if packetLen == uint16(n-2) {
wantLen := uint16(n - 2)
if packetLen == wantLen {
err = m.Unpack(buf[2:])
} else {
err = m.Unpack(buf)
doqDraft = true
err = fmt.Errorf("bad buffer size %d, want %d", packetLen, wantLen)
}
if err != nil {
s.metrics.OnInvalidMsg(ctx)
return nil, false, err
return nil, err
}
return m, doqDraft, nil
return m, nil
}
// readAll reads from r until an error or io.EOF into the specified buffer buf.
@ -558,7 +563,10 @@ func (s *ServerQUIC) listenQUIC(ctx context.Context) (err error) {
return err
}
// Save this for s.LocalUDPAddr. Do not close it separately as ql closes
// the underlying connection.
s.udpListener = conn
s.quicListener = ql
return nil

View File

@ -4,6 +4,7 @@ import (
"context"
"crypto/tls"
"encoding/binary"
"fmt"
"io"
"net"
"sync"
@ -30,7 +31,7 @@ func TestServerQUIC_integration_query(t *testing.T) {
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
return srv.Shutdown(context.Background())
return srv.Shutdown(contextWithTimeout(t, testTimeout))
})
// Open a QUIC connection.
@ -41,28 +42,29 @@ func TestServerQUIC_integration_query(t *testing.T) {
return conn.CloseWithError(0, "")
})
// Send multiple queries to the DNS server in parallel
const queriesNum = 100
wg := &sync.WaitGroup{}
wg.Add(queriesNum)
for i := 0; i < 100; i++ {
wg.Add(1)
// Create a test message.
for i := 0; i < queriesNum; i++ {
req := dnsservertest.NewReq("example.org.", dns.TypeA, dns.ClassINET)
req.RecursionDesired = true
// Even requests are sent as if it's an old draft client.
doqDraft := i%2 == 0
go func() {
defer wg.Done()
resp := sendQUICMessage(t, conn, req, doqDraft)
assert.NotNil(t, resp)
resp, reqErr := sendQUICMessage(conn, req)
// Do not use require, as this is a separate goroutine.
if !assert.NoError(t, reqErr) || !assert.NotNil(t, resp) {
return
}
assert.True(t, resp.Response)
// EDNS0 padding is only present when request also has padding opt.
paddingOpt := dnsservertest.FindEDNS0Option[*dns.EDNS0_PADDING](resp)
require.Nil(t, paddingOpt)
assert.Nil(t, paddingOpt)
}()
}
@ -78,7 +80,7 @@ func TestServerQUIC_integration_ENDS0Padding(t *testing.T) {
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
return srv.Shutdown(context.Background())
return srv.Shutdown(contextWithTimeout(t, testTimeout))
})
// Open a QUIC connection.
@ -92,7 +94,7 @@ func TestServerQUIC_integration_ENDS0Padding(t *testing.T) {
req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
req.Extra = []dns.RR{dnsservertest.NewEDNS0Padding(req.Len(), dns.DefaultMsgSize)}
resp := sendQUICMessage(t, conn, req, false)
resp := requireSendQUICMessage(t, conn, req)
require.NotNil(t, resp)
require.Equal(t, dns.RcodeSuccess, resp.Rcode)
require.True(t, resp.Response)
@ -112,7 +114,7 @@ func TestServerQUIC_integration_0RTT(t *testing.T) {
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
return srv.Shutdown(context.Background())
return srv.Shutdown(contextWithTimeout(t, testTimeout))
})
quicTracer := dnsservertest.NewQUICTracer()
@ -150,7 +152,7 @@ func TestServerQUIC_integration_largeQuery(t *testing.T) {
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
return srv.Shutdown(context.Background())
return srv.Shutdown(contextWithTimeout(t, testTimeout))
})
// Open a QUIC connection.
@ -174,7 +176,7 @@ func TestServerQUIC_integration_largeQuery(t *testing.T) {
},
}
resp := sendQUICMessage(t, conn, req, false)
resp := requireSendQUICMessage(t, conn, req)
require.NotNil(t, resp)
require.True(t, resp.Response)
}
@ -202,64 +204,77 @@ func testQUICExchange(
req := dnsservertest.NewReq("example.org.", dns.TypeA, dns.ClassINET)
req.RecursionDesired = true
resp := sendQUICMessage(t, conn, req, false)
resp := requireSendQUICMessage(t, conn, req)
require.NotNil(t, resp)
}
// sendQUICMessage is a test helper that sends a test QUIC message.
func sendQUICMessage(
t testing.TB,
conn quic.Connection,
req *dns.Msg,
doqDraft bool,
) (resp *dns.Msg) {
t.Helper()
) (resp *dns.Msg, err error) {
stream, err := conn.OpenStreamSync(context.Background())
require.NoError(t, err)
defer log.OnCloserError(stream, log.DEBUG)
data, err := req.Pack()
require.NoError(t, err)
var buf []byte
if doqDraft {
buf = data
} else {
buf = make([]byte, 2+len(data))
binary.BigEndian.PutUint16(buf, uint16(len(data)))
copy(buf[2:], data)
if err != nil {
return nil, fmt.Errorf("opening stream: %w", err)
}
defer log.OnCloserError(stream, log.ERROR)
data, err := req.Pack()
if err != nil {
return nil, fmt.Errorf("packing: %w", err)
}
buf := make([]byte, 2+len(data))
binary.BigEndian.PutUint16(buf, uint16(len(data)))
copy(buf[2:], data)
err = writeQUICStream(buf, stream)
require.NoError(t, err)
if err != nil {
return nil, fmt.Errorf("writing: %w", err)
}
// Closes the write-direction of the stream and sends a STREAM FIN packet.
// A DoQ client MUST send a FIN packet to indicate that the query is
// finished.
err = stream.Close()
require.NoError(t, err)
if err != nil {
return nil, fmt.Errorf("closing stream: %w", err)
}
// Now read the response.
respBytes := make([]byte, dns.MaxMsgSize)
n, err := stream.Read(respBytes)
if !errors.Is(err, io.EOF) {
require.NoError(t, err)
if err != nil && !errors.Is(err, io.EOF) {
return nil, fmt.Errorf("reading stream: %w", err)
}
require.GreaterOrEqual(t, n, dnsserver.DNSHeaderSize)
if n < dnsserver.DNSHeaderSize {
return nil, fmt.Errorf("read %d, want %d", n, dnsserver.DNSHeaderSize)
}
// Unpack the response.
reply := &dns.Msg{}
if doqDraft {
err = reply.Unpack(respBytes[:n])
} else {
err = reply.Unpack(respBytes[2:n])
err = reply.Unpack(respBytes[2:n])
if err != nil {
return nil, fmt.Errorf("unpacking: %w", err)
}
return reply, nil
}
// requireSendQUICMessage is a test helper that sends a test QUIC message and
// requires it to succeed. It must not be used in a goroutine with the outer
// test's t.
func requireSendQUICMessage(
t testing.TB,
conn quic.Connection,
req *dns.Msg,
) (resp *dns.Msg) {
t.Helper()
resp, err := sendQUICMessage(conn, req)
require.NoError(t, err)
return reply
return resp
}
// writeQUICStream writes buf to the specified QUIC stream in chunks. This way

View File

@ -12,7 +12,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/billstat"
"github.com/AdguardTeam/AdGuardDNS/internal/connlimiter"
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
@ -34,6 +33,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
"github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/service"
"github.com/miekg/dns"
)
@ -144,6 +144,10 @@ type Config struct {
// used.
UseECSCache bool
// ProfileDBEnabled is true, if user devices and profiles recognition is
// enabled.
ProfileDBEnabled bool
// ResearchMetrics controls whether research metrics are enabled or not.
// This is a set of metrics that we may need temporary, so its collection is
// controlled by a separate setting.
@ -267,10 +271,10 @@ func mustStartListener(
}
// type check
var _ agdservice.Interface = (*Service)(nil)
var _ service.Interface = (*Service)(nil)
// Start implements the [agdservice.Interface] interface for *Service. It
// panics if one of the listeners could not start.
// Start implements the [service.Interface] interface for *Service. It panics
// if one of the listeners could not start.
func (svc *Service) Start(_ context.Context) (err error) {
for _, g := range svc.groups {
for _, s := range g.servers {
@ -298,7 +302,7 @@ func shutdownListeners(ctx context.Context, listeners []*listener) (err error) {
return nil
}
// Shutdown implements the [agdservice.Interface] interface for *Service.
// Shutdown implements the [service.Interface] interface for *Service.
func (svc *Service) Shutdown(ctx context.Context) (err error) {
var errs []error
for _, g := range svc.groups {
@ -512,13 +516,14 @@ func newServers(
})
imw := initial.New(&initial.Config{
Messages: c.Messages,
FilteringGroup: fg,
ServerGroup: srvGrp,
Server: s,
ProfileDB: c.ProfileDB,
GeoIP: c.GeoIP,
ErrColl: c.ErrColl,
Messages: c.Messages,
FilteringGroup: fg,
ServerGroup: srvGrp,
Server: s,
ProfileDB: c.ProfileDB,
GeoIP: c.GeoIP,
ErrColl: c.ErrColl,
ProfileDBEnabled: c.ProfileDBEnabled,
})
h := dnsserver.WithMiddlewares(

View File

@ -101,8 +101,8 @@ func newTestService(
OnIsBlockedHost: func(host string, qt uint16) (blocked bool) {
return false
},
OnIsBlockedIP: func(ip netip.Addr) (blocked bool, rule string) {
return false, ""
OnIsBlockedIP: func(ip netip.Addr) (blocked bool) {
return false
},
}
@ -228,16 +228,18 @@ func newTestService(
},
},
ServerGroups: []*agd.ServerGroup{{
TLS: &agd.TLS{
DeviceIDWildcards: []string{dnssvctest.DeviceIDWildcard},
},
BlockPageRedirect: &agd.BlockPageRedirect{},
DDR: &agd.DDR{
Enabled: true,
},
TLS: &agd.TLS{
DeviceIDWildcards: []string{dnssvctest.DeviceIDWildcard},
},
Name: testSrvGrpName,
FilteringGroup: testFltGrpID,
Servers: []*agd.Server{srv},
}},
ProfileDBEnabled: true,
}
svc, err := dnssvc.New(c)

View File

@ -45,7 +45,7 @@ func (mw *Middleware) Wrap(next dnsserver.Handler) (wrapped dnsserver.Handler) {
defer func() { err = errors.Annotate(err, "access mw: %w") }()
rAddr := netutil.NetAddrToAddrPort(rw.RemoteAddr()).Addr()
if blocked, _ := mw.accessManager.IsBlockedIP(rAddr); blocked {
if blocked := mw.accessManager.IsBlockedIP(rAddr); blocked {
metrics.AccessBlockedForSubnetTotal.Inc()
return nil

View File

@ -25,9 +25,9 @@ func TestMiddleware_Wrap(t *testing.T) {
"block.test",
"UPPERCASE.test",
"||block_aaaa.test^$dnstype=AAAA",
}, []string{
"1.1.1.1",
"2.2.2.0/8",
}, []netip.Prefix{
netip.MustParsePrefix("1.1.1.1/32"),
netip.MustParsePrefix("2.2.2.0/8"),
})
require.NoError(t, accessErr)

View File

@ -55,6 +55,10 @@ type Middleware struct {
// errColl collects and reports the errors considered non-critical.
errColl errcoll.Interface
// profilesEnabled is true, if user devices and profiles recognition is
// enabled.
profilesEnabled bool
}
// Config is the configuration structure for the initial middleware. All fields
@ -80,6 +84,10 @@ type Config struct {
// ErrColl collects and reports the errors considered non-critical.
ErrColl errcoll.Interface
// ProfileDBEnabled is true, if user devices and profiles recognition is
// enabled.
ProfileDBEnabled bool
}
// New returns a new initial middleware. c must not be nil.
@ -92,9 +100,10 @@ func New(c *Config) (mw *Middleware) {
pool: syncutil.NewPool(func() (v *agd.RequestInfo) {
return &agd.RequestInfo{}
}),
db: c.ProfileDB,
geoIP: c.GeoIP,
errColl: c.ErrColl,
db: c.ProfileDB,
geoIP: c.GeoIP,
errColl: c.ErrColl,
profilesEnabled: c.ProfileDBEnabled,
}
}
@ -221,6 +230,10 @@ func (mw *Middleware) newRequestInfo(
return nil, err
}
if !mw.profilesEnabled {
return ri, nil
}
// Add the profile information, if any.
localAddr := netutil.NetAddrToAddrPort(lAddr)
err = mw.addProfile(ctx, ri, req, localAddr)

View File

@ -181,6 +181,7 @@ func TestMiddleware_Wrap(t *testing.T) {
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
ProfileDBEnabled: true,
})
ctx := context.Background()
@ -301,6 +302,7 @@ func TestMiddleware_Wrap_error(t *testing.T) {
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
ProfileDBEnabled: true,
})
ctx := context.Background()
@ -517,6 +519,7 @@ func TestMiddleware_Wrap_access(t *testing.T) {
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
ProfileDBEnabled: true,
})
ctx := context.Background()
@ -565,14 +568,15 @@ func newServers() (srvs map[agd.ServerName]*agd.Server) {
func newServerGroup(srvs []*agd.Server) (srvGrp *agd.ServerGroup) {
srvGrp = &agd.ServerGroup{
TLS: &agd.TLS{
DeviceIDWildcards: []string{"*.d." + resolverName},
},
BlockPageRedirect: &agd.BlockPageRedirect{},
DDR: &agd.DDR{
DeviceTargets: stringutil.NewSet(),
PublicTargets: stringutil.NewSet(),
Enabled: true,
},
TLS: &agd.TLS{
DeviceIDWildcards: []string{"*.d." + resolverName},
},
Name: "test_server_group",
Servers: srvs,
}
@ -605,14 +609,15 @@ var errSink error
func BenchmarkMiddleware_Wrap(b *testing.B) {
const devIDTarget = "dns.example.com"
srvGrp := &agd.ServerGroup{
TLS: &agd.TLS{
DeviceIDWildcards: []string{"*." + devIDTarget},
},
BlockPageRedirect: &agd.BlockPageRedirect{},
DDR: &agd.DDR{
DeviceTargets: stringutil.NewSet(),
PublicTargets: stringutil.NewSet(),
Enabled: true,
},
TLS: &agd.TLS{
DeviceIDWildcards: []string{"*." + devIDTarget},
},
Name: agd.ServerGroupName("test_server_group"),
Servers: []*agd.Server{
dnssvctest.NewServer("test_server_dot", agd.ProtoDoT, &agd.ServerBindData{
@ -708,6 +713,7 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
ProfileDBEnabled: true,
})
h := mw.Wrap(handler)
@ -753,6 +759,7 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
ProfileDBEnabled: true,
})
h := mw.Wrap(handler)
@ -806,6 +813,7 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
ProfileDBEnabled: true,
})
h := mw.Wrap(handler)
@ -864,6 +872,7 @@ func BenchmarkMiddleware_Wrap(b *testing.B) {
ErrColl: &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) { panic("not implemented") },
},
ProfileDBEnabled: true,
})
h := mw.Wrap(handler)

View File

@ -101,8 +101,9 @@ func TestMiddleware_profile(t *testing.T) {
srv.LinkedIPEnabled = tc.linkedIPEnabled
mw := New(&Config{
Server: srv,
ProfileDB: newProfileDB(t, prof, dev, tc.wantByWhat),
Server: srv,
ProfileDB: newProfileDB(t, prof, dev, tc.wantByWhat),
ProfileDBEnabled: true,
})
ctx := context.Background()
@ -196,8 +197,9 @@ func TestMiddleware_profileByAddrs(t *testing.T) {
srv.LinkedIPEnabled = tc.linkedIPEnabled
mw := New(&Config{
Server: srv,
ProfileDB: newProfileDB(t, prof, dev, tc.wantByWhat),
Server: srv,
ProfileDB: newProfileDB(t, prof, dev, tc.wantByWhat),
ProfileDBEnabled: true,
})
ctx := context.Background()

View File

@ -198,9 +198,10 @@ func TestMiddleware_ServeDNS_specialDomain(t *testing.T) {
Protocol: agd.ProtoDNS,
LinkedIPEnabled: true,
},
ProfileDB: db,
GeoIP: geoIP,
ErrColl: errColl,
ProfileDB: db,
GeoIP: geoIP,
ErrColl: errColl,
ProfileDBEnabled: true,
})
h := mw.Wrap(handler)

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,5 @@
// Package internal contains common constants, types, and utilities shared by
// other subpackages of package filter/.
//
// TODO(a.garipov): Move more code to subpackages, see AGDNS-824.
package internal
import (

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,15 @@ var DevicesNewCountGauge = promauto.NewGauge(prometheus.GaugeOpts{
Help: "The number of user devices that were changed or added since the previous sync.",
})
// DevicesInvalidTotal is a gauge with the number of invalid user devices loaded
// from the backend.
var DevicesInvalidTotal = promauto.NewCounter(prometheus.CounterOpts{
Name: "devices_invalid_total",
Subsystem: subsystemBackend,
Namespace: namespace,
Help: "The total number of invalid user devices loaded from the backend.",
})
// ProfilesCountGauge is a gauge with the total number of user profiles loaded
// from the backend.
var ProfilesCountGauge = promauto.NewGauge(prometheus.GaugeOpts{

View File

@ -21,6 +21,9 @@ var DNSSvcRequestByASNTotal = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: namespace,
Subsystem: subsystemDNSSvc,
Help: "The number of processed DNS requests labeled by country and ASN.",
ConstLabels: prometheus.Labels{
dontStoreLabel: dontStoreLabelValue,
},
}, []string{"country", "asn"})
// DNSSvcRequestByFilterTotal is a counter with the total number of queries

View File

@ -35,6 +35,16 @@ const (
subsystemWebSvc = "websvc"
)
const (
// dontStoreLabel is a label that signals that the metric should not be
// stored in the long-term storage.
dontStoreLabel = "do_not_store_metric"
// dontStoreLabelValue is a positive value of the [dontStoreLabel] label to
// avoid calling [BoolString] every time.
dontStoreLabelValue = "1"
)
// SetUpGauge signals that the server has been started. Use a function here to
// avoid circular dependencies.
func SetUpGauge(version, buildtime, branch, revision, goversion string) {

View File

@ -39,6 +39,39 @@ type Interface interface {
ProfileByLinkedIP(ctx context.Context, ip netip.Addr) (p *agd.Profile, d *agd.Device, err error)
}
// type check
var _ Interface = (*Disabled)(nil)
// Disabled is a profile database that panics on any call.
type Disabled struct{}
// profilesDBUnexpectedCall is a panic message template for lookup methods when
// profiles database is disabled.
const profilesDBUnexpectedCall string = "profiles db: unexpected call to %s"
// ProfileByDeviceID implements the [Interface] interface for *Disabled.
func (d *Disabled) ProfileByDeviceID(
_ context.Context,
_ agd.DeviceID,
) (_ *agd.Profile, _ *agd.Device, _ error) {
panic(fmt.Errorf(profilesDBUnexpectedCall, "ProfileByDeviceID"))
}
// ProfileByDedicatedIP implements the [Interface] interface for *Disabled.
func (d *Disabled) ProfileByDedicatedIP(
_ context.Context, _ netip.Addr,
) (_ *agd.Profile, _ *agd.Device, _ error) {
panic(fmt.Errorf(profilesDBUnexpectedCall, "ProfileByDedicatedIP"))
}
// ProfileByLinkedIP implements the [Interface] interface for *Disabled.
func (d *Disabled) ProfileByLinkedIP(
_ context.Context,
_ netip.Addr,
) (_ *agd.Profile, _ *agd.Device, _ error) {
panic(fmt.Errorf(profilesDBUnexpectedCall, "ProfileByLinkedIP"))
}
// Config represents the profile database configuration.
type Config struct {
// Storage returns the data for this profile DB.

View File

@ -1,38 +1,36 @@
module github.com/AdguardTeam/AdGuardDNS/internal/tools
go 1.21.5
go 1.21.8
require (
github.com/fzipp/gocyclo v0.6.0
github.com/golangci/misspell v0.4.1
github.com/gordonklaus/ineffassign v0.1.0
github.com/kisielk/errcheck v1.6.3
github.com/kisielk/errcheck v1.7.0
github.com/kyoh86/looppointer v0.2.1
github.com/securego/gosec/v2 v2.18.2
// TODO(a.garipov): Return to latest once the release is tagged
// correctly. See uudashr/gocognit#31.
github.com/securego/gosec/v2 v2.19.0
github.com/uudashr/gocognit v1.1.2
golang.org/x/tools v0.16.0
golang.org/x/vuln v1.0.1
golang.org/x/tools v0.18.0
golang.org/x/vuln v1.0.4
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
google.golang.org/protobuf v1.31.0
honnef.co/go/tools v0.4.6
mvdan.cc/gofumpt v0.5.0
mvdan.cc/unparam v0.0.0-20230917202934-3ee2d22f45fb
google.golang.org/protobuf v1.32.0
honnef.co/go/tools v0.4.7
mvdan.cc/gofumpt v0.6.0
mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14
)
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/ccojocar/zxcvbn-go v1.0.1 // indirect
github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/kyoh86/nolint v0.0.1 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 // indirect
golang.org/x/exp/typeparams v0.0.0-20231127185646-65229373498e // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.17.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,37 +1,35 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/ccojocar/zxcvbn-go v1.0.1 h1:+sxrANSCj6CdadkcMnvde/GWU1vZiiXRbqYSCalV4/4=
github.com/ccojocar/zxcvbn-go v1.0.1/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg=
github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golangci/misspell v0.4.1 h1:+y73iSicVy2PqyX7kmUefHusENlrP9YwuHZHPLGQj/g=
github.com/golangci/misspell v0.4.1/go.mod h1:9mAN1quEo3DlpbaIKKyEvRxK1pwqR9s/Sea1bJCtlNI=
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s=
github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
github.com/kisielk/errcheck v1.6.3 h1:dEKh+GLHcWm2oN34nMvDzn1sqI0i0WxPvrgiJA5JuM8=
github.com/kisielk/errcheck v1.6.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw=
github.com/kisielk/errcheck v1.7.0 h1:+SbscKmWJ5mOK/bO1zS60F5I9WwZDWOfRsC4RwfwRV0=
github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -40,16 +38,16 @@ github.com/kyoh86/looppointer v0.2.1 h1:Jx9fnkBj/JrIryBLMTYNTj9rvc2SrPS98Dg0w7fx
github.com/kyoh86/looppointer v0.2.1/go.mod h1:q358WcM8cMWU+5vzqukvaZtnJi1kw/MpRHQm3xvTrjw=
github.com/kyoh86/nolint v0.0.1 h1:GjNxDEkVn2wAxKHtP7iNTrRxytRZ1wXxLV5j4XzGfRU=
github.com/kyoh86/nolint v0.0.1/go.mod h1:1ZiZZ7qqrZ9dZegU96phwVcdQOMKIqRzFJL3ewq9gtI=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA=
github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo=
github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/securego/gosec/v2 v2.18.2 h1:DkDt3wCiOtAHf1XkiXZBhQ6m6mK/b9T/wD257R3/c+I=
github.com/securego/gosec/v2 v2.18.2/go.mod h1:xUuqSF6i0So56Y2wwohWAmB07EdBkUN6crbLlHwbyJs=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/securego/gosec/v2 v2.19.0 h1:gl5xMkOI0/E6Hxx0XCY2XujA3V7SNSefA8sC+3f1gnk=
github.com/securego/gosec/v2 v2.19.0/go.mod h1:hOkDcHz9J/XIgIlPDXalxjeVYsHxoWUc5zJSHxcB8YM=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/uudashr/gocognit v1.1.2 h1:l6BAEKJqQH2UpKAPKdMfZf5kE4W/2xk8pfU1OVLvniI=
@ -65,27 +63,26 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp/typeparams v0.0.0-20231127185646-65229373498e h1:Iel2aGgaO80fSb1N54L7SE6XMeVvYy6caKt8u/5LvR8=
golang.org/x/exp/typeparams v0.0.0-20231127185646-65229373498e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225 h1:BzKNaIRXh1bD+1557OcFIHlpYBiVbK4zEyn8zBHi1SE=
golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -96,41 +93,38 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/vuln v1.0.1 h1:KUas02EjQK5LTuIx1OylBQdKKZ9jeugs+HiqO5HormU=
golang.org/x/vuln v1.0.1/go.mod h1:bb2hMwln/tqxg32BNY4CcxHWtHXuYa3SbIBmtsyjxtM=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/vuln v1.0.4 h1:SP0mPeg2PmGCu03V+61EcQiOjmpri2XijexKdzv8Z1I=
golang.org/x/vuln v1.0.4/go.mod h1:NbJdUQhX8jY++FtuhrXs2Eyx0yePo9pF7nPlIjo9aaQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.4.6 h1:oFEHCKeID7to/3autwsWfnuv69j3NsfcXbvJKuIcep8=
honnef.co/go/tools v0.4.6/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0=
mvdan.cc/gofumpt v0.5.0 h1:0EQ+Z56k8tXjj/6TQD25BFNKQXpCvT0rnansIc7Ug5E=
mvdan.cc/gofumpt v0.5.0/go.mod h1:HBeVDtMKRZpXyxFciAirzdKklDlGu8aAy1wEbH5Y9js=
mvdan.cc/unparam v0.0.0-20230917202934-3ee2d22f45fb h1:xiF91GJnDSbyPdiZB5d52N2VpZfGhjM4Ji75cjzuooQ=
mvdan.cc/unparam v0.0.0-20230917202934-3ee2d22f45fb/go.mod h1:ZzZjEpJDOmx8TdVU6umamY3Xy0UAQUI2DHbf05USVbI=
honnef.co/go/tools v0.4.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs=
honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0=
mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo=
mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA=
mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14 h1:zCr3iRRgdk5eIikZNDphGcM6KGVTx3Yu+/Uu9Es254w=
mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14/go.mod h1:ZzZjEpJDOmx8TdVU6umamY3Xy0UAQUI2DHbf05USVbI=

View File

@ -10,10 +10,10 @@ import (
"net/url"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/service"
)
// Config is the AdGuard DNS web service configuration structure.
@ -201,11 +201,16 @@ func blockPageServers(
}
// type check
var _ agdservice.Interface = (*Service)(nil)
var _ service.Interface = (*Service)(nil)
// Start implements the [agdservice.Interface] interface for *Service. svc may
// be nil. It panics if one of the servers could not start.
func (svc *Service) Start(ctx context.Context) (err error) {
// Start implements the [service.Interface] interface for *Service. It starts
// serving all endpoints but does not wait for them to actually go online. svc
// may be nil. err is always nil; if any endpoint fails to start, it panics.
//
// TODO(a.garipov): Wait for the services to go online.
//
// TODO(a.garipov): Use the context for cancelation.
func (svc *Service) Start(_ context.Context) (err error) {
if svc == nil {
return nil
}
@ -261,8 +266,8 @@ func mustStartServer(srv *http.Server) {
}
}
// Shutdown implements the [agdservice.Interface] interface for *Service. svc
// may be nil.
// Shutdown implements the [service.Interface] interface for *Service. svc may
// be nil.
func (svc *Service) Shutdown(ctx context.Context) (err error) {
if svc == nil {
return nil

View File

@ -95,11 +95,11 @@ func mockDNSProfile() (dp *backendpb.DNSProfile) {
}
devices := []*backendpb.DeviceSettings{{
Id: "118ffe93",
Name: "118ffe93-name",
Id: "test",
Name: "test-name",
FilteringEnabled: false,
LinkedIp: []byte{1, 1, 1, 1},
DedicatedIps: [][]byte{{1, 1, 1, 2}},
DedicatedIps: [][]byte{{127, 0, 0, 1}},
}}
return &backendpb.DNSProfile{

View File

@ -0,0 +1,33 @@
#!/bin/sh
# This comment is used to simplify checking local copies of the script. Bump
# this number every time a significant change is made to this script.
#
# AdGuard-Project-Version: 1
verbose="${VERBOSE:-0}"
readonly verbose
if [ "$verbose" -gt '1' ]
then
env
set -x
x_flags='-x=1'
elif [ "$verbose" -gt '0' ]
then
set -x
x_flags='-x=0'
else
set +x
x_flags='-x=0'
fi
readonly x_flags
set -e -f -u
go="${GO:-go}"
readonly go
cd ./internal/tools/
"$go" get -u
"$go" mod tidy