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 ## AGDNS-1761 / Build 702
* The property `upstream` has been modified. Its property `timeout` has been * 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 # Makefile. Bump this number every time a significant change is made to
# this Makefile. # this Makefile.
# #
# AdGuard-Project-Version: 2 # AdGuard-Project-Version: 4
# Don't name these macros "GO" etc., because GNU Make apparently makes # Don't name these macros "GO" etc., because GNU Make apparently makes
# them exported environment variables with the literal value of # them exported environment variables with the literal value of
@ -23,7 +23,7 @@ VERBOSE.MACRO = $${VERBOSE:-0}
BRANCH = $$( git rev-parse --abbrev-ref HEAD ) BRANCH = $$( git rev-parse --abbrev-ref HEAD )
GOAMD64 = v1 GOAMD64 = v1
GOPROXY = https://goproxy.cn|https://proxy.golang.org|direct GOPROXY = https://goproxy.cn|https://proxy.golang.org|direct
GOTOOLCHAIN = go1.21.5 GOTOOLCHAIN = go1.21.8
RACE = 0 RACE = 0
REVISION = $$( git rev-parse --short HEAD ) REVISION = $$( git rev-parse --short HEAD )
VERSION = 0 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-test: ; $(ENV) RACE='1' "$(SHELL)" ./scripts/make/go-test.sh
go-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-tools.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 go-check: go-tools go-lint go-test
# A quick check to make sure that all operating systems relevant to the # 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 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 sync-github: ; $(ENV) "$(SHELL)" ./scripts/make/github-sync.sh

View File

@ -274,7 +274,7 @@ filters:
# FILTER_INDEX_URL environment variable. # FILTER_INDEX_URL environment variable.
refresh_interval: 1h refresh_interval: 1h
# The timeout for the entire filter update operation. Be aware that each # 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 refresh_timeout: 5m
# MaxSize is the maximum size of the downloadable filtering rule-list. # MaxSize is the maximum size of the downloadable filtering rule-list.
max_size: 256MB max_size: 256MB
@ -351,15 +351,38 @@ server_groups:
- name: 'adguard_dns_default' - name: 'adguard_dns_default'
# This filtering_group is used for all anonymous clients. # This filtering_group is used for all anonymous clients.
filtering_group: 'default' filtering_group: 'default'
tls: # Settings for redirection to a block page.
certificates: block_page_redirect:
- certificate: './test/cert.crt' # If enabled is false, other fields can be skipped.
key: './test/cert.key' enabled: true
session_keys: # Addresses to use for A queries. If enabled is true, ipv4, ipv6, or
- './test/tls_key_1' # both must be filled.
- './test/tls_key_2' ipv4:
device_id_wildcards: - address: '127.0.0.1'
- '*.dns.example.com' - 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: ddr:
enabled: true enabled: true
# Device ID domain name suffix to DDR record template mapping. Keep in # Device ID domain name suffix to DDR record template mapping. Keep in
@ -386,6 +409,15 @@ server_groups:
- '127.0.0.1' - '127.0.0.1'
ipv6_hints: ipv6_hints:
- '::1' - '::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: servers:
- name: 'default_dns' - name: 'default_dns'
# See README for the list of protocol values. # See README for the list of protocol values.

View File

@ -28,8 +28,9 @@ configuration file with comments.
* [Filtering groups](#filtering_groups) * [Filtering groups](#filtering_groups)
* [Network interface listeners](#interface_listeners) * [Network interface listeners](#interface_listeners)
* [Server groups](#server_groups) * [Server groups](#server_groups)
* [TLS](#server_groups-*-tls) * [Block-page redirecting](#server_groups-*-block_page_redirect)
* [DDR](#server_groups-*-ddr) * [DDR](#server_groups-*-ddr)
* [TLS](#server_groups-*-tls)
* [Servers](#server_groups-*-servers-*) * [Servers](#server_groups-*-servers-*)
* [Connectivity check](#connectivity-check) * [Connectivity check](#connectivity-check)
* [Network settings](#network) * [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. 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`. TCP sockets in use every day, `resume` should be set to about `120000`.
**NOTE:** The number of active stream-connections includes sockets that are > [!NOTE]
in the process of accepting new connections but have not yet accepted one. That > The number of active stream-connections includes sockets that are in the
means that `resume` should be greater than the number of bound addresses. > 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. 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>: * <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 The timeout for the *entire* filter update operation, as a human-readable
duration. Be aware that each individual refresh operation also has its own duration. Be aware that each individual refresh operation also has its own
hardcoded 30s timeout. hardcoded 3m timeout.
**Example:** `5m`. **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> ## <a href="#interface_listeners" id="interface_listeners" name="interface_listeners">Network interface listeners</a>
**NOTE:** The network interface listening works only on Linux with > [!NOTE]
`SO_BINDTODEVICE` support (2.0.30 and later) and properly setup IP routes. See > The network interface listening works only on Linux with `SO_BINDTODEVICE`
the [section on testing `SO_BINDTODEVICE` using Docker][dev-btd]. > 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: 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`. **Example:** `default`.
* `tls`: The optional TLS configuration object. See * `block_page_redirect`: The block-page redirect configuration object. See
[below](#server_groups-*-tls). [below](#server_groups-*-block_page_redirect).
* `ddr`: The DDR configuration object. See [below](#server_groups-*-ddr). * `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 * `servers`: Server configuration for this filtering group. See
[below](#server_groups-*-servers-*). [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 block-page redirect configuration object. If enabled, AdGuard DNS responds
The array of objects with paths to the certificate and the private key for with the configured IP addresses to “redirect” users to an informative block
this server group. 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:** **Property example:**
```yaml ```yaml
'certificates': apply:
- 'certificate': '/etc/dns/cert.crt' client:
'key': '/etc/dns/cert.key' - 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>: * <a href="#sg-*-bpr-skip" id="sg-*-bpr-skip" name="sg-*-bpr-skip">`skip`</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. Request parameters based on which the block-page redirect is never
performed. For requests matching these parameters, `probability` is
ignored.
**Property example:** **Property example:**
```yaml ```yaml
'session_keys': skip:
- './private/key_1' client:
- './private/key_2' - 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>: * <a href="#sg-*-bpr-probability" id="sg-*-bpr-probability" name="sg-*-bpr-probability">`probability`</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:** The probability of responding with the block page IPs based on remote
address. Must be between `0.0` and `1.0`.
```yaml
'device_id_wildcards':
- '*.d.dns.example.com'
```
@ -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> ### <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: 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 HTTP trailer named `X-Error` which describes errors that might have occurred
during the database dump. during the database dump.
**NOTE:** For legacy software reasons, despite the endpoint being a `GET` one, > [!NOTE]
it rotates the database, and so changes the internal state. > 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 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>. 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 > [!NOTE]
you. > The example below is for a test configuration that won't work for you.
```sh ```sh
dnslookup example.org sdns://AQcAAAAAAAAADjEyNy4wLjAuMTo1NDQzIAbKgP3dmXybr1DaKIFgKjsc8zSFX4rgT_hFgymSq6w1FzIuZG5zY3J5cHQtY2VydC50ZXN0ZG5z 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) * [`LOG_TIMESTAMP`](#LOG_TIMESTAMP)
* [`NEW_REG_DOMAINS_URL`](#NEW_REG_DOMAINS_URL) * [`NEW_REG_DOMAINS_URL`](#NEW_REG_DOMAINS_URL)
* [`PROFILES_CACHE_PATH`](#PROFILES_CACHE_PATH) * [`PROFILES_CACHE_PATH`](#PROFILES_CACHE_PATH)
* [`PROFILES_ENABLED`](#PROFILES_ENABLED)
* [`PROFILES_URL`](#PROFILES_URL) * [`PROFILES_URL`](#PROFILES_URL)
* [`QUERYLOG_PATH`](#QUERYLOG_PATH) * [`QUERYLOG_PATH`](#QUERYLOG_PATH)
* [`RESEARCH_LOGS`](#RESEARCH_LOGS) * [`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> ## <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://`) 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 This is the service to which the [`BILLSTAT_URL`][env-billstat_url] environment
variable points. Supports `grpc(s)` URLs. The service must correspond to 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-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 This is the service to which the [`PROFILES_URL`][env-profiles_url] environment
variable points. Supports `grpc(s)` URLs. The service must correspond to 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 [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 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”. 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 > [!NOTE]
`XK` for the partially-recognized state of the Republic of Kosovo. > 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"` **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 could be detected, this property is absent. The short name `d` stands for
“destination”. “destination”.
**NOTE:** AdGuard DNS uses the common user-assigned ISO 3166-1 alpha-2 code > [!NOTE]
`XK` for the partially-recognized state of the Republic of Kosovo. > 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"` **Example:** `"US"`

52
go.mod
View File

@ -1,32 +1,32 @@
module github.com/AdguardTeam/AdGuardDNS module github.com/AdguardTeam/AdGuardDNS
go 1.21.5 go 1.21.8
require ( require (
github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-00010101000000-000000000000 github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-00010101000000-000000000000
github.com/AdguardTeam/golibs v0.18.1 github.com/AdguardTeam/golibs v0.20.1
github.com/AdguardTeam/urlfilter v0.17.2 github.com/AdguardTeam/urlfilter v0.18.0
github.com/ameshkov/dnscrypt/v2 v2.2.7 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/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/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/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/oschwald/maxminddb-golang v1.12.0
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible 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/client_model v0.5.0
github.com/prometheus/common v0.44.0 github.com/prometheus/common v0.46.0
github.com/quic-go/quic-go v0.39.0 github.com/quic-go/quic-go v0.41.0
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
golang.org/x/net v0.17.0 golang.org/x/net v0.21.0
golang.org/x/sys v0.13.0 golang.org/x/sys v0.17.0
golang.org/x/time v0.3.0 golang.org/x/time v0.5.0
google.golang.org/grpc v1.58.3 google.golang.org/grpc v1.61.1
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.32.0
gopkg.in/yaml.v2 v2.4.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/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/protobuf v1.5.3 // 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/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/onsi/ginkgo/v2 v2.15.0 // indirect
github.com/onsi/ginkgo/v2 v2.13.0 // indirect github.com/panjf2000/ants/v2 v2.9.0 // indirect
github.com/panjf2000/ants/v2 v2.8.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect
github.com/quic-go/qpack v0.4.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.4.0 // indirect
go.uber.org/mock v0.3.0 // indirect golang.org/x/crypto v0.19.0 // indirect
golang.org/x/crypto v0.14.0 // indirect golang.org/x/mod v0.15.0 // indirect
golang.org/x/mod v0.13.0 // indirect golang.org/x/text v0.14.0 // indirect
golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.18.0 // indirect
golang.org/x/tools v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect
gopkg.in/yaml.v3 v3.0.1 // 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.20.1 h1:ol8qLjWGZhU9paMMwN+OLWVTUigGsXa29iVTyd62VKY=
github.com/AdguardTeam/golibs v0.18.1/go.mod h1:DKhCIXHcUYtBhU8ibTLKh1paUL96n5zhQBlx763sj+U= github.com/AdguardTeam/golibs v0.20.1/go.mod h1:bgcMgRviCKyU6mkrX+RtT/OsKPFzyppelfRsksMG3KU=
github.com/AdguardTeam/urlfilter v0.17.2 h1:xTntfr1UWah8m6wwoXJmFgplFk/+kL/hDu204ptrM1U= github.com/AdguardTeam/urlfilter v0.18.0 h1:ZZzwODC/ADpjJSODxySrrUnt/fvOCfGFaCW6j+wsGfQ=
github.com/AdguardTeam/urlfilter v0.17.2/go.mod h1:Jru7jFfeH2CoDf150uDs+rRYcZBzHHBz05r9REyDKyE= 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 h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw= github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 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/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 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A= 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-20240124082744-24bca3a5b39b h1:F3yMzKumBUQ6Fn0sYI1YQ16vQRucpZOfBQ9HXWl5+XI=
github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c= 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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 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 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= 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-20231215233829-aa82cc1e6500 h1:6lhrsTEnloDPXyeZBvSYvQf8u86jbKehZPVDDlkgDl4=
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= 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 h1:9lzTF5amyQeWHZzuZeKlCb5FWSUxpG1js43mhbY8ozg=
github.com/caarlos0/env/v7 v7.1.0/go.mod h1:LPPWniDUq4JaO6Q41vtlyikhMknqymCLBw0eX4dcH1E= github.com/caarlos0/env/v7 v7.1.0/go.mod h1:LPPWniDUq4JaO6Q41vtlyikhMknqymCLBw0eX4dcH1E=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= 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-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 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= 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.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= 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 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= 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.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 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 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 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 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= 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.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 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/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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo=
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= 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 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 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/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 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 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/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= 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/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.9.0 h1:SztCLkVxBRigbg+vt0S5QvF5vxAbxbKt09/YfAJ0tEo=
github.com/panjf2000/ants/v2 v2.8.2/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I= 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 h1:IWzUvJ72xMjmrjR9q3H1PF+jwdN0uNQiR2t1BLNalyo=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= 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= 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/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 h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= 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.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= 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 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= 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.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= 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 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= 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 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= 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/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
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.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= 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/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4= github.com/shirou/gopsutil/v3 v3.23.7 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/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 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 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.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= 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-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk=
google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= 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-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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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 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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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 ( 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.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8= cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
cloud.google.com/go/bigquery v1.8.0 h1:PQcPefKFdaIzjQFbiyOgAqyx8q5djaE7x9Sqe712DPA= 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.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.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/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ= cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU= 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= 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.10.7/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw=
github.com/AdguardTeam/golibs v0.17.2/go.mod h1:DKhCIXHcUYtBhU8ibTLKh1paUL96n5zhQBlx763sj+U= 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.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/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 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 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.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 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU=
github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= 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/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-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= 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 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= github.com/census-instrumentation/opencensus-proto v0.2.1 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/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash 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/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/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/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 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 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 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f 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/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-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 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= 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= 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 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= 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.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/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 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/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 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= 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 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-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/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/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/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 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 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-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 h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 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.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/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 h1:2hRPrmiwPrp3fQX967rNJIhQPtiGXdlQWAxKbKw3VHA=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= 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/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 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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 h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.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 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 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 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 h1:SIYunPjnlXcW+gVfvm0IlSeR5U3WZUOLfVmqg85Go44=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= 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= 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/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/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.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.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2 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 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/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-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-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-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-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.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.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.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-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-20221019170559-20944726eadf/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= 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.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 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= 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.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 h1:xYq6+9AtI+xP3M4r0N1hCkHrInHDBohhquRgx9Kk6gI=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-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-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-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-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-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-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.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.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.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= golang.org/x/term v0.3.0 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.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.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= 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.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.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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.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.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.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-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= 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.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= 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.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-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-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/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-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 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0=
google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= 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-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.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=

View File

@ -6,6 +6,7 @@ import (
"net/netip" "net/netip"
"strings" "strings"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/urlfilter" "github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist" "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 // IsBlockedIP returns the status of the IP address blocking as well as the
// rule that blocked it. // 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 // Global controls IP and client blocking that takes place before all other
// processing. Global is safe for concurrent use. // processing. Global is safe for concurrent use.
type Global struct { type Global struct {
blockedIPs map[netip.Addr]string
blockedHostsEng *urlfilter.DNSEngine blockedHostsEng *urlfilter.DNSEngine
blockedNets []netip.Prefix blockedNets netutil.SubnetSet
} }
// NewGlobal create a new Global from provided parameters. // 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{ g = &Global{
blockedIPs: map[netip.Addr]string{}, blockedNets: netutil.SliceSubnetSet(blockedSubnets),
}
err = processAccessList(blockedSubnets, g.blockedIPs, &g.blockedNets)
if err != nil {
return nil, fmt.Errorf("adding blocked hosts: %w", err)
} }
b := &strings.Builder{} b := &strings.Builder{}
@ -68,24 +63,6 @@ func NewGlobal(blockedDomains, blockedSubnets []string) (g *Global, err error) {
return g, nil 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 // type check
var _ Interface = (*Global)(nil) 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. // IsBlockedIP implements the [Interface] interface for *Global.
func (g *Global) IsBlockedIP(ip netip.Addr) (blocked bool, rule string) { func (g *Global) IsBlockedIP(ip netip.Addr) (blocked bool) {
if ipStr, ok := g.blockedIPs[ip]; ok { return g.blockedNets.Contains(ip)
return true, ipStr
}
for _, ipnet := range g.blockedNets {
if ipnet.Contains(ip) {
return true, ipnet.String()
}
}
return false, ""
} }

View File

@ -17,7 +17,7 @@ func TestGlobal_IsBlockedHost(t *testing.T) {
"||block_aaaa.test^$dnstype=AAAA", "||block_aaaa.test^$dnstype=AAAA",
"||allowlist.test^", "||allowlist.test^",
"@@||allow.allowlist.test^", "@@||allow.allowlist.test^",
}, []string{}) }, nil)
require.NoError(t, err) require.NoError(t, err)
testCases := []struct { testCases := []struct {
@ -76,44 +76,38 @@ func TestGlobal_IsBlockedHost(t *testing.T) {
} }
func TestGlobal_IsBlockedIP(t *testing.T) { func TestGlobal_IsBlockedIP(t *testing.T) {
global, err := access.NewGlobal([]string{}, []string{ global, err := access.NewGlobal([]string{}, []netip.Prefix{
"1.1.1.1", netip.MustParsePrefix("1.1.1.1/32"),
"2.2.2.0/8", netip.MustParsePrefix("2.2.2.0/8"),
}) })
require.NoError(t, err) require.NoError(t, err)
testCases := []struct { testCases := []struct {
want assert.BoolAssertionFunc want assert.BoolAssertionFunc
ip netip.Addr ip netip.Addr
wantRule string name string
name string
}{{ }{{
want: assert.False, want: assert.False,
wantRule: "", name: "pass",
name: "pass", ip: netip.MustParseAddr("1.1.1.0"),
ip: netip.MustParseAddr("1.1.1.0"),
}, { }, {
want: assert.True, want: assert.True,
wantRule: "1.1.1.1", name: "block_ip",
name: "block_ip", ip: netip.MustParseAddr("1.1.1.1"),
ip: netip.MustParseAddr("1.1.1.1"),
}, { }, {
want: assert.False, want: assert.False,
wantRule: "", name: "pass_subnet",
name: "pass_subnet", ip: netip.MustParseAddr("1.2.2.2"),
ip: netip.MustParseAddr("1.2.2.2"),
}, { }, {
want: assert.True, want: assert.True,
wantRule: "2.2.2.0/8", name: "block_subnet",
name: "block_subnet", ip: netip.MustParseAddr("2.2.2.2"),
ip: netip.MustParseAddr("2.2.2.2"),
}} }}
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
blocked, rule := global.IsBlockedIP(tc.ip) blocked := global.IsBlockedIP(tc.ip)
tc.want(t, blocked) 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) { func (e *blockedHostEngine) isBlocked(req *dns.Msg) (blocked bool) {
e.initOnce.Do(func() { e.initOnce.Do(func() {
start := time.Now() 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 // 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) { func (p *DefaultProfile) isBlockedByHostsEng(req *dns.Msg) (blocked bool) {
return p.blockedHostsEng.isBlocked(req) return p.blockedHostsEng.isBlocked(req)
} }

View File

@ -9,76 +9,9 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet" "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/netext" "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/netext"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/ameshkov/dnscrypt/v2" "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 // Server represents a single DNS server. That is, an entity that binds to one
// or more ports and serves DNS over a single protocol. // or more ports and serves DNS over a single protocol.
type Server struct { type Server struct {
@ -192,6 +125,24 @@ func (s *Server) BindsToInterfaces() (ok bool) {
return len(s.bindData) > 0 && s.bindData[0].PrefixAddr != nil 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 // ServerBindData are the socket binding data for a server. Either AddrPort or
// ListenConfig with PrefixAddr must be set. // ListenConfig with PrefixAddr must be set.
// //

View File

@ -13,27 +13,31 @@ import (
// Common variables for tests. // Common variables for tests.
var ( var (
addrV4 = netip.MustParseAddr("1.2.3.4")
bindDataAddrPortV4 = &agd.ServerBindData{ bindDataAddrPortV4 = &agd.ServerBindData{
AddrPort: netip.MustParseAddrPort("1.2.3.4:53"), AddrPort: netip.AddrPortFrom(addrV4, 53),
} }
addrV6 = netip.MustParseAddr("1234::cdef")
bindDataAddrPortV6 = &agd.ServerBindData{ 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{ bindDataIface = &agd.ServerBindData{
ListenConfig: &agdtest.ListenConfig{}, ListenConfig: &agdtest.ListenConfig{},
PrefixAddr: &agdnet.PrefixNetAddr{ PrefixAddr: &agdnet.PrefixNetAddr{
Prefix: netip.MustParsePrefix("1.2.3.0/24"), Prefix: prefixV4,
Net: "", Net: "",
Port: 53, Port: 53,
}, },
} }
singleIPPrefixV4 = netip.MustParsePrefix("1.2.3.4/32")
bindDataIfaceSingleIP = &agd.ServerBindData{ bindDataIfaceSingleIP = &agd.ServerBindData{
ListenConfig: &agdtest.ListenConfig{}, ListenConfig: &agdtest.ListenConfig{},
PrefixAddr: &agdnet.PrefixNetAddr{ PrefixAddr: &agdnet.PrefixNetAddr{
Prefix: netip.MustParsePrefix("1.2.3.4/32"), Prefix: singleIPPrefixV4,
Net: "", Net: "",
Port: 53, Port: 53,
}, },
@ -105,6 +109,41 @@ func TestServer_BindsToInterfaces(t *testing.T) {
assert.True(t, s.BindsToInterfaces()) 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) { func TestServer_HasAddr(t *testing.T) {
testCases := []struct { testCases := []struct {
bindData *agd.ServerBindData 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 package agdnet
import ( import (
"fmt"
"net/netip"
"strings" "strings"
) )
@ -48,33 +46,6 @@ func AndroidMetricDomainReplacement(fqdn string) (repl string) {
return "" 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. // NormalizeDomain returns lowercased version of the host without the final dot.
// //
// TODO(a.garipov): Move to golibs. // TODO(a.garipov): Move to golibs.

View File

@ -1,38 +1,7 @@
// Package agdservice defines types and interfaces for long-running services. // 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 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{}. // unit is a convenient alias for struct{}.
type unit = struct{} type unit = struct{}

View File

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

View File

@ -39,7 +39,7 @@ var _ access.Interface = (*AccessManager)(nil)
// AccessManager is a [access.Interface] for tests. // AccessManager is a [access.Interface] for tests.
type AccessManager struct { type AccessManager struct {
OnIsBlockedHost func(host string, qt uint16) (blocked bool) 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. // 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. // 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) return a.OnIsBlockedIP(ip)
} }

View File

@ -16,8 +16,10 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg" "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll" "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip" "github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb" "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
@ -27,6 +29,9 @@ import (
// ProfileStorageConfig is the configuration for the business logic backend // ProfileStorageConfig is the configuration for the business logic backend
// profile storage. // profile storage.
type ProfileStorageConfig struct { 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 // ErrColl is the error collector that is used to collect critical and
// non-critical errors. // non-critical errors.
ErrColl errcoll.Interface ErrColl errcoll.Interface
@ -40,6 +45,7 @@ type ProfileStorageConfig struct {
// that retrieves the profile and device information from the business logic // that retrieves the profile and device information from the business logic
// backend. It is safe for concurrent use. // backend. It is safe for concurrent use.
type ProfileStorage struct { type ProfileStorage struct {
bindSet netutil.SubnetSet
errColl errcoll.Interface errColl errcoll.Interface
// client is the current GRPC client. // client is the current GRPC client.
@ -56,6 +62,7 @@ func NewProfileStorage(c *ProfileStorageConfig) (s *ProfileStorage, err error) {
} }
return &ProfileStorage{ return &ProfileStorage{
bindSet: c.BindSet,
client: client, client: client,
errColl: c.ErrColl, errColl: c.ErrColl,
}, nil }, nil
@ -97,7 +104,7 @@ func (s *ProfileStorage) Profiles(
stats.endRecv() stats.endRecv()
stats.startDec() 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 { if profErr != nil {
reportf(ctx, s.errColl, "loading profile: %w", profErr) reportf(ctx, s.errColl, "loading profile: %w", profErr)
@ -140,6 +147,7 @@ func fixGRPCError(err error) (wErr error) {
func (x *DNSProfile) toInternal( func (x *DNSProfile) toInternal(
ctx context.Context, ctx context.Context,
updTime time.Time, updTime time.Time,
bindSet netutil.SubnetSet,
errColl errcoll.Interface, errColl errcoll.Interface,
) (profile *agd.Profile, devices []*agd.Device, err error) { ) (profile *agd.Profile, devices []*agd.Device, err error) {
if x == nil { if x == nil {
@ -156,7 +164,7 @@ func (x *DNSProfile) toInternal(
return nil, nil, fmt.Errorf("blocking mode: %w", err) 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) listsEnabled, listIDs := x.RuleLists.toInternal(ctx, errColl)
profID, err := agd.NewProfileID(x.DnsId) profID, err := agd.NewProfileID(x.DnsId)
@ -384,6 +392,7 @@ func blockingModeToInternal(pbm isDNSProfile_BlockingMode) (m dnsmsg.BlockingMod
func devicesToInternal( func devicesToInternal(
ctx context.Context, ctx context.Context,
ds []*DeviceSettings, ds []*DeviceSettings,
bindSet netutil.SubnetSet,
errColl errcoll.Interface, errColl errcoll.Interface,
) (out []*agd.Device, ids []agd.DeviceID) { ) (out []*agd.Device, ids []agd.DeviceID) {
l := len(ds) l := len(ds)
@ -393,9 +402,10 @@ func devicesToInternal(
out = make([]*agd.Device, 0, l) out = make([]*agd.Device, 0, l)
for _, d := range ds { for _, d := range ds {
dev, err := d.toInternal() dev, err := d.toInternal(bindSet)
if err != nil { if err != nil {
reportf(ctx, errColl, "invalid device settings: %w", err) reportf(ctx, errColl, "invalid device settings: %w", err)
metrics.DevicesInvalidTotal.Inc()
continue continue
} }
@ -409,7 +419,7 @@ func devicesToInternal(
// toInternal is a helper that converts device settings from backend protobuf // toInternal is a helper that converts device settings from backend protobuf
// response to AdGuard DNS device object. // 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 { if ds == nil {
return nil, fmt.Errorf("device is 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) 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) id, err := agd.NewDeviceID(ds.Id)
if err != nil { if err != nil {
return nil, fmt.Errorf("device id: %s: %w", ds.Id, err) 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. // TestUpdTime is the common update time for tests.
var TestUpdTime = time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC) 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) { func TestDNSProfile_ToInternal(t *testing.T) {
ctx := context.Background() ctx := context.Background()
@ -40,7 +43,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
} }
t.Run("success", func(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) require.NoError(t, err)
assert.Equal(t, newProfile(t), got) assert.Equal(t, newProfile(t), got)
@ -57,18 +60,44 @@ func TestDNSProfile_ToInternal(t *testing.T) {
got, gotDevices, err := newDNSProfileWithBadData(t).toInternal( got, gotDevices, err := newDNSProfileWithBadData(t).toInternal(
ctx, ctx,
TestUpdTime, TestUpdTime,
testBind,
savingErrColl, savingErrColl,
) )
require.NoError(t, err) 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, newProfile(t), got)
assert.Equal(t, newDevices(t), gotDevices) 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) { t.Run("empty", func(t *testing.T) {
var emptyDNSProfile *DNSProfile var emptyDNSProfile *DNSProfile
_, _, err := emptyDNSProfile.toInternal(ctx, TestUpdTime, errColl) _, _, err := emptyDNSProfile.toInternal(ctx, TestUpdTime, testBind, errColl)
testutil.AssertErrorMsg(t, "profile is nil", err) testutil.AssertErrorMsg(t, "profile is nil", err)
}) })
@ -78,7 +107,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
Deleted: true, Deleted: true,
} }
got, gotDevices, err := dp.toInternal(ctx, TestUpdTime, errColl) got, gotDevices, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, got) require.NotNil(t, got)
@ -91,7 +120,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
dp := NewTestDNSProfile(t) dp := NewTestDNSProfile(t)
dp.Parental.Schedule.Tmz = "invalid" 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) testutil.AssertErrorMsg(t, "parental: schedule: loading timezone: unknown time zone invalid", err)
}) })
@ -102,7 +131,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
End: nil, 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) 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 := dp.BlockingMode.(*DNSProfile_BlockingModeCustomIp)
bm.BlockingModeCustomIp.Ipv4 = []byte("1") 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) 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 := dp.BlockingMode.(*DNSProfile_BlockingModeCustomIp)
bm.BlockingModeCustomIp.Ipv6 = []byte("1") 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) 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 := NewTestDNSProfile(t)
dp.BlockingMode = nil 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.NoError(t, err)
require.NotNil(t, got) require.NotNil(t, got)
@ -143,7 +172,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
dp := NewTestDNSProfile(t) dp := NewTestDNSProfile(t)
dp.Access = nil dp.Access = nil
got, _, err := dp.toInternal(ctx, TestUpdTime, errColl) got, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, got) require.NotNil(t, got)
@ -157,7 +186,7 @@ func TestDNSProfile_ToInternal(t *testing.T) {
Enabled: false, Enabled: false,
} }
got, _, err := dp.toInternal(ctx, TestUpdTime, errColl) got, _, err := dp.toInternal(ctx, TestUpdTime, testBind, errColl)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, got) require.NotNil(t, got)
@ -451,7 +480,7 @@ func BenchmarkDNSProfile_ToInternal(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { 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) require.NotNil(b, profSink)

View File

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

View File

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

View File

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

View File

@ -7,8 +7,8 @@ import (
"fmt" "fmt"
"net/netip" "net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/service"
) )
// Manager creates individual listeners and dispatches connections to them. // 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 // 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. // nil, Start returns nil, since this feature is optional.
// //
// It is only supported on Linux. // 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) return fmt.Errorf("bindtodevice: starting: %w; only supported on linux", errors.ErrUnsupported)
} }
// Shutdown implements the [agdservice.Interface] interface for *Manager. If m // Shutdown implements the [service.Interface] interface for *Manager. If m is
// is nil, Shutdown returns nil, since this feature is optional. // nil, Shutdown returns nil, since this feature is optional.
// //
// It is only supported on Linux. // It is only supported on Linux.
func (m *Manager) Shutdown(_ context.Context) (err error) { func (m *Manager) Shutdown(_ context.Context) (err error) {

View File

@ -1,8 +1,7 @@
package cmd package cmd
import ( import (
"fmt" "github.com/AdguardTeam/golibs/netutil"
"net/netip"
) )
// accessConfig is the configuration that controls IP and hosts blocking. // accessConfig is the configuration that controls IP and hosts blocking.
@ -11,7 +10,7 @@ type accessConfig struct {
BlockedQuestionDomains []string `yaml:"blocked_question_domains"` BlockedQuestionDomains []string `yaml:"blocked_question_domains"`
// BlockedClientSubnets is a list of IP addresses or subnets to block. // 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. // validate returns an error if the access configuration is invalid.
@ -20,21 +19,5 @@ func (a *accessConfig) validate() (err error) {
return errNilConfig 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 return nil
} }

View File

@ -3,14 +3,18 @@ package cmd
import ( import (
"context" "context"
"fmt" "fmt"
"net/netip"
"net/url" "net/url"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice" "github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/backendpb" "github.com/AdguardTeam/AdGuardDNS/internal/backendpb"
"github.com/AdguardTeam/AdGuardDNS/internal/billstat" "github.com/AdguardTeam/AdGuardDNS/internal/billstat"
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll" "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb" "github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/timeutil" "github.com/AdguardTeam/golibs/timeutil"
) )
@ -67,17 +71,22 @@ func (c *backendConfig) validate() (err error) {
// handler. // handler.
func setupBackend( func setupBackend(
conf *backendConfig, conf *backendConfig,
grps []*agd.ServerGroup,
envs *environments, envs *environments,
sigHdlr signalHandler, sigHdlr *service.SignalHandler,
errColl errcoll.Interface, 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) rec, err = setupBillStat(conf, envs, sigHdlr, errColl)
if err != nil { if err != nil {
// Don't wrap the error, because it's informative enough as is. // Don't wrap the error, because it's informative enough as is.
return nil, nil, err return nil, nil, err
} }
profDB, err = setupProfDB(conf, envs, sigHdlr, errColl) profDB, err = setupProfDB(conf, grps, envs, sigHdlr, errColl)
if err != nil { if err != nil {
// Don't wrap the error, because it's informative enough as is. // Don't wrap the error, because it's informative enough as is.
return nil, nil, err return nil, nil, err
@ -91,7 +100,7 @@ func setupBackend(
func setupBillStat( func setupBillStat(
conf *backendConfig, conf *backendConfig,
envs *environments, envs *environments,
sigHdlr signalHandler, sigHdlr *service.SignalHandler,
errColl errcoll.Interface, errColl errcoll.Interface,
) (rec *billstat.RuntimeRecorder, err error) { ) (rec *billstat.RuntimeRecorder, err error) {
apiURL := netutil.CloneURL(&envs.BillStatURL.URL) apiURL := netutil.CloneURL(&envs.BillStatURL.URL)
@ -124,7 +133,7 @@ func setupBillStat(
return nil, fmt.Errorf("starting bill stat recorder refresher: %w", err) return nil, fmt.Errorf("starting bill stat recorder refresher: %w", err)
} }
sigHdlr.add(billStatRefr) sigHdlr.Add(billStatRefr)
return rec, nil return rec, nil
} }
@ -133,12 +142,14 @@ func setupBillStat(
// registers its refresher in the signal handler. // registers its refresher in the signal handler.
func setupProfDB( func setupProfDB(
conf *backendConfig, conf *backendConfig,
grps []*agd.ServerGroup,
envs *environments, envs *environments,
sigHdlr signalHandler, sigHdlr *service.SignalHandler,
errColl errcoll.Interface, errColl errcoll.Interface,
) (profDB *profiledb.Default, err error) { ) (profDB *profiledb.Default, err error) {
apiURL := netutil.CloneURL(&envs.ProfilesURL.URL) apiURL := netutil.CloneURL(&envs.ProfilesURL.URL)
profStrg, err := setupProfStorage(apiURL, errColl) bindSet := collectBindSubnetSet(grps)
profStrg, err := setupProfStorage(apiURL, bindSet, errColl)
if err != nil { if err != nil {
return nil, fmt.Errorf("creating profile storage: %w", err) 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) return nil, fmt.Errorf("starting default profile database refresher: %w", err)
} }
sigHdlr.add(profDBRefr) sigHdlr.Add(profDBRefr)
return profDB, nil 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. // Backend API URL schemes.
const ( const (
schemeGRPC = "grpc" schemeGRPC = "grpc"
@ -189,11 +229,13 @@ const (
// provided API URL. // provided API URL.
func setupProfStorage( func setupProfStorage(
apiURL *url.URL, apiURL *url.URL,
bindSet netutil.SubnetSet,
errColl errcoll.Interface, errColl errcoll.Interface,
) (s profiledb.Storage, err error) { ) (s profiledb.Storage, err error) {
scheme := apiURL.Scheme scheme := apiURL.Scheme
if scheme == schemeGRPC || scheme == schemeGRPCS { if scheme == schemeGRPC || scheme == schemeGRPCS {
return backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{ return backendpb.NewProfileStorage(&backendpb.ProfileStorageConfig{
BindSet: bindSet,
Endpoint: apiURL, Endpoint: apiURL,
ErrColl: errColl, ErrColl: errColl,
}) })

View File

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

View File

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

View File

@ -12,6 +12,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/filter" "github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix" "github.com/AdguardTeam/AdGuardDNS/internal/filter/hashprefix"
"github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/timeutil" "github.com/AdguardTeam/golibs/timeutil"
"github.com/c2h5oh/datasize" "github.com/c2h5oh/datasize"
) )
@ -136,7 +137,7 @@ func (c *fltRuleListCache) validate() (err error) {
// registers its refresher in the signal handler. // registers its refresher in the signal handler.
func setupFilterStorage( func setupFilterStorage(
conf *filter.DefaultStorageConfig, conf *filter.DefaultStorageConfig,
sigHdlr signalHandler, sigHdlr *service.SignalHandler,
errColl errcoll.Interface, errColl errcoll.Interface,
refreshTimeout time.Duration, refreshTimeout time.Duration,
) (strg *filter.DefaultStorage, err error) { ) (strg *filter.DefaultStorage, err error) {
@ -162,7 +163,7 @@ func setupFilterStorage(
return nil, fmt.Errorf("starting default filter storage update: %w", err) return nil, fmt.Errorf("starting default filter storage update: %w", err)
} }
sigHdlr.add(refr) sigHdlr.Add(refr)
return strg, nil 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) return errors.Annotate(m.Add(id, l.Interface, l.Port, ctrlConf), "adding listener %q: %w", id)
}, },
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice" "github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/connlimiter" "github.com/AdguardTeam/AdGuardDNS/internal/connlimiter"
"github.com/AdguardTeam/AdGuardDNS/internal/consul" "github.com/AdguardTeam/AdGuardDNS/internal/consul"
@ -13,6 +12,8 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/errcoll" "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics" "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/timeutil" "github.com/AdguardTeam/golibs/timeutil"
"github.com/c2h5oh/datasize" "github.com/c2h5oh/datasize"
) )
@ -64,7 +65,7 @@ type rateLimitConfig struct {
// allowListConfig is the consul allow list configuration. // allowListConfig is the consul allow list configuration.
type allowListConfig struct { type allowListConfig struct {
// List contains IPs and CIDRs. // 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 time between two updates of allow list from the Consul URL.
RefreshIvl timeutil.Duration `yaml:"refresh_interval"` RefreshIvl timeutil.Duration `yaml:"refresh_interval"`
@ -138,14 +139,10 @@ func (c *rateLimitConfig) validate() (err error) {
func setupRateLimiter( func setupRateLimiter(
conf *rateLimitConfig, conf *rateLimitConfig,
consulAllowlist *url.URL, consulAllowlist *url.URL,
sigHdlr signalHandler, sigHdlr *service.SignalHandler,
errColl errcoll.Interface, errColl errcoll.Interface,
) (rateLimiter *ratelimit.Backoff, connLimiter *connlimiter.Limiter, err error) { ) (rateLimiter *ratelimit.Backoff, connLimiter *connlimiter.Limiter, err error) {
allowSubnets, err := agdnet.ParseSubnets(conf.Allowlist.List...) allowSubnets := netutil.UnembedPrefixes(conf.Allowlist.List)
if err != nil {
return nil, nil, fmt.Errorf("parsing allowlist subnets: %w", err)
}
allowlist := ratelimit.NewDynamicAllowlist(allowSubnets, nil) allowlist := ratelimit.NewDynamicAllowlist(allowSubnets, nil)
refresher, err := consul.NewAllowlistRefresher(allowlist, consulAllowlist) refresher, err := consul.NewAllowlistRefresher(allowlist, consulAllowlist)
if err != nil { if err != nil {
@ -168,7 +165,7 @@ func setupRateLimiter(
return nil, nil, fmt.Errorf("starting allowlist refresher: %w", err) 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 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/errors"
"github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/netutil/urlutil" "github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/timeutil" "github.com/AdguardTeam/golibs/timeutil"
) )
@ -99,7 +100,7 @@ func setupHashPrefixFilter(
url *urlutil.URL, url *urlutil.URL,
cachePath string, cachePath string,
maxSize uint64, maxSize uint64,
sigHdlr signalHandler, sigHdlr *service.SignalHandler,
errColl errcoll.Interface, errColl errcoll.Interface,
) (strg *hashprefix.Storage, flt *hashprefix.Filter, err error) { ) (strg *hashprefix.Storage, flt *hashprefix.Filter, err error) {
fltConf, err := conf.toInternal(errColl, resolver, cloner, id, url, cachePath, maxSize) 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) 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 return fltConf.Hashes, flt, nil
} }

View File

@ -2,11 +2,13 @@ package cmd
import ( import (
"fmt" "fmt"
"net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/agd" "github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/bindtodevice" "github.com/AdguardTeam/AdGuardDNS/internal/bindtodevice"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg" "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/golibs/stringutil"
) )
@ -39,10 +41,11 @@ func (srvGrps serverGroups) toInternal(
} }
svcSrvGrps[i] = &agd.ServerGroup{ svcSrvGrps[i] = &agd.ServerGroup{
TLS: tlsConf, BlockPageRedirect: g.BlockPageRedirect.toInternal(),
DDR: g.DDR.toInternal(messages), DDR: g.DDR.toInternal(messages),
Name: agd.ServerGroupName(g.Name), TLS: tlsConf,
FilteringGroup: fltGrpID, Name: agd.ServerGroupName(g.Name),
FilteringGroup: fltGrpID,
} }
svcSrvGrps[i].Servers, err = g.Servers.toInternal(tlsConf, btdMgr, ratelimitConf, dnsConf) 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 // TODO(a.garipov): Think about more consistent naming, since this object is a
// configuration, but it also stores other configurations. // configuration, but it also stores other configurations.
type serverGroup struct { type serverGroup struct {
// TLS are the TLS settings for this server, if any. // BlockPageRedirect is the configuration for the server group's block page.
TLS *tlsConfig `yaml:"tls"` BlockPageRedirect *serverGroupBlockPageConfig `yaml:"block_page_redirect"`
// DDR is the Discovery Of Designated Resolvers (DDR) configuration for this // DDR is the Discovery Of Designated Resolvers (DDR) configuration for this
// server group. // server group.
DDR *ddrConfig `yaml:"ddr"` 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 is the unique name of the server group.
Name string `yaml:"name"` Name string `yaml:"name"`
@ -111,6 +117,11 @@ func (g *serverGroup) validate() (err error) {
return errors.Error("no filtering_group") 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() err = g.DDR.validate()
if err != nil { if err != nil {
return fmt.Errorf("ddr: %w", err) return fmt.Errorf("ddr: %w", err)
@ -128,3 +139,255 @@ func (g *serverGroup) validate() (err error) {
return nil 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/errcoll"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics" "github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/service"
"github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/golibs/stringutil"
"github.com/prometheus/client_golang/prometheus" "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. // registers its refresher in the signal handler.
func setupTicketRotator( func setupTicketRotator(
srvGrps []*agd.ServerGroup, srvGrps []*agd.ServerGroup,
sigHdlr signalHandler, sigHdlr *service.SignalHandler,
errColl errcoll.Interface, errColl errcoll.Interface,
) (err error) { ) (err error) {
tickRot, err := newTicketRotator(srvGrps) tickRot, err := newTicketRotator(srvGrps)
@ -324,7 +325,7 @@ func setupTicketRotator(
return fmt.Errorf("starting ticket rotator refresh: %w", err) return fmt.Errorf("starting ticket rotator refresh: %w", err)
} }
sigHdlr.add(refr) sigHdlr.Add(refr)
return nil return nil
} }

View File

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

View File

@ -7,10 +7,10 @@ import (
"io" "io"
"net/http" "net/http"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/pprofutil" "github.com/AdguardTeam/golibs/pprofutil"
"github.com/AdguardTeam/golibs/service"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
) )
@ -69,11 +69,15 @@ func startServer(s *server) {
} }
// type check // type check
var _ agdservice.Interface = (*Service)(nil) var _ service.Interface = (*Service)(nil)
// Start implements the [agdservice.Interface] interface for *Service. It // Start implements the [service.Interface] interface for *Service. It starts
// starts serving all endpoints. err is always nil, if any endpoint fails to // serving all endpoints but does not wait for them to actually go online. err
// start, it panics. // 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) { func (svc *Service) Start(_ context.Context) (err error) {
for _, srv := range svc.servers { for _, srv := range svc.servers {
go startServer(srv) go startServer(srv)
@ -82,8 +86,8 @@ func (svc *Service) Start(_ context.Context) (err error) {
return nil return nil
} }
// Shutdown implements the [agdservice.Interface] interface for *Service. It // Shutdown implements the [service.Interface] interface for *Service. It stops
// stops serving all endpoints. // serving all endpoints.
func (svc *Service) Shutdown(ctx context.Context) (err error) { func (svc *Service) Shutdown(ctx context.Context) (err error) {
srvNum := 0 srvNum := 0
for _, srv := range svc.servers { 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()) }() 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 var resp []*consulKVResponse
err = json.NewDecoder(httpResp.Body).Decode(&resp) err = json.NewDecoder(httpResp.Body).Decode(&resp)
if err != nil { 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()) }() 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{} sessResp := &consulSessionResponse{}
err = json.NewDecoder(sessHTTPResp.Body).Decode(sessResp) err = json.NewDecoder(sessHTTPResp.Body).Decode(sessResp)
if err != nil { 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()) }() 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 return nil
} }

View File

@ -209,7 +209,75 @@ func TestHTTPKV(t *testing.T) {
dnsCk.ServeHTTP(rw, r) dnsCk.ServeHTTP(rw, r)
assert.Equal(t, http.StatusInternalServerError, rw.Code) 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()) 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. // positive numbers, but we need a ceiling operation here.
strNum := (strLen + MaxTXTStringLen - 1) / MaxTXTStringLen strNum := (strLen + MaxTXTStringLen - 1) / MaxTXTStringLen
// TODO(a.garipov): Use slices.Chunk in Go 1.23.
newStr := make([]string, strNum) newStr := make([]string, strNum)
for i := 0; i < strNum; i++ { for i := 0; i < strNum; i++ {
start := i * MaxTXTStringLen start := i * MaxTXTStringLen

View File

@ -1,11 +1,30 @@
package dnsserver_test package dnsserver_test
import ( import (
"context"
"testing" "testing"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/golibs/testutil" "github.com/AdguardTeam/golibs/testutil"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
testutil.DiscardLogOutput(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, tlsConfig *tls.Config,
) (s *dnsserver.ServerQUIC, addr *net.UDPAddr, err error) { ) (s *dnsserver.ServerQUIC, addr *net.UDPAddr, err error) {
conf := dnsserver.ConfigQUIC{ conf := dnsserver.ConfigQUIC{
TLSConfig: tlsConfig,
ConfigBase: dnsserver.ConfigBase{ ConfigBase: dnsserver.ConfigBase{
Name: "test", Name: "test",
Addr: "127.0.0.1:0", Addr: "127.0.0.1:0",
Handler: h, Handler: h,
}, },
TLSConfig: tlsConfig,
} }
s = dnsserver.NewServerQUIC(conf) s = dnsserver.NewServerQUIC(conf)
@ -209,7 +209,7 @@ func RunLocalQUICServer(
addr, ok := s.LocalUDPAddr().(*net.UDPAddr) addr, ok := s.LocalUDPAddr().(*net.UDPAddr)
if !ok { 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 return s, addr, nil

View File

@ -1,21 +1,21 @@
module github.com/AdguardTeam/AdGuardDNS/internal/dnsserver module github.com/AdguardTeam/AdGuardDNS/internal/dnsserver
go 1.21.5 go 1.21.8
require ( 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/dnscrypt/v2 v2.2.7
github.com/ameshkov/dnsstamps v1.0.3 github.com/ameshkov/dnsstamps v1.0.3
github.com/bluele/gcache v0.0.2 github.com/bluele/gcache v0.0.2
github.com/miekg/dns v1.1.56 github.com/miekg/dns v1.1.58
github.com/panjf2000/ants/v2 v2.8.2 github.com/panjf2000/ants/v2 v2.9.0
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible 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/quic-go/quic-go v0.39.0 github.com/quic-go/quic-go v0.41.0
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
golang.org/x/net v0.17.0 golang.org/x/net v0.21.0
golang.org/x/sys v0.13.0 golang.org/x/sys v0.17.0
) )
require ( require (
@ -24,23 +24,21 @@ require (
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // 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/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-20240207164012-fb44976bdcd5 // indirect
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
github.com/kr/text v0.2.0 // 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.15.0 // indirect
github.com/onsi/ginkgo/v2 v2.13.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.5.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/prometheus/procfs v0.12.0 // indirect
github.com/quic-go/qpack v0.4.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.4.0 // indirect
go.uber.org/mock v0.3.0 // indirect golang.org/x/crypto v0.19.0 // indirect
golang.org/x/crypto v0.14.0 // indirect golang.org/x/mod v0.15.0 // indirect
golang.org/x/mod v0.13.0 // indirect golang.org/x/text v0.14.0 // indirect
golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.18.0 // indirect
golang.org/x/tools v0.14.0 // indirect google.golang.org/protobuf v1.32.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // 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 h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw= github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 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 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= 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 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9/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-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/panjf2000/ants/v2 v2.9.0 h1:SztCLkVxBRigbg+vt0S5QvF5vxAbxbKt09/YfAJ0tEo=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/panjf2000/ants/v2 v2.9.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
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/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 h1:IWzUvJ72xMjmrjR9q3H1PF+jwdN0uNQiR2t1BLNalyo=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
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 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 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= 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/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
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.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= 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/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.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.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 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/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.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
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=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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. // isStarted returns true if the server is started.
func (s *ServerBase) isStarted() (started bool) { func (s *ServerBase) isStarted() (started bool) {
s.lock.RLock() s.lock.RLock()
started = s.started defer s.lock.RUnlock()
s.lock.RUnlock()
return started return s.started
} }

View File

@ -313,7 +313,7 @@ func BenchmarkServeQUIC(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
resp := sendQUICMessage(b, sess, req, false) resp := requireSendQUICMessage(b, sess, req)
require.NotNil(b, resp) require.NotNil(b, resp)
require.True(b, resp.Response) 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. // server with a TLS layer on top of it.
func newServerDNS(proto Protocol, conf ConfigDNS) (s *ServerDNS) { func newServerDNS(proto Protocol, conf ConfigDNS) (s *ServerDNS) {
// Init default settings first. // Init default settings first.
//
// TODO(a.garipov): Use cmp.Or in Go 1.22.
if conf.ReadTimeout == 0 { if conf.ReadTimeout == 0 {
conf.ReadTimeout = DefaultReadTimeout conf.ReadTimeout = DefaultReadTimeout
} }

View File

@ -246,8 +246,16 @@ func (s *ServerHTTPS) shutdown(ctx context.Context) (err error) {
s.started = false s.started = false
// First step, close the active listener right away. // First step, close the active TCP listener right away. Don't close the
s.closeListeners() // 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. // Second, shutdown the HTTP server.
err = s.httpServer.Shutdown(ctx) 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()) requestURL := fmt.Sprintf("%s://test.local%s?%s", proto, dnsserver.PathJSON, q.Encode())
r, err = http.NewRequest(method, requestURL, nil) r, err = http.NewRequest(method, requestURL, nil)
if err != nil { if err != nil {
return nil, err 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 // ConfigQUIC is a struct that needs to be passed to NewServerQUIC to
// initialize a new ServerQUIC instance. // initialize a new ServerQUIC instance.
type ConfigQUIC struct { type ConfigQUIC struct {
ConfigBase
// TLSConfig is the TLS configuration for QUIC. // TLSConfig is the TLS configuration for QUIC.
TLSConfig *tls.Config TLSConfig *tls.Config
ConfigBase
// MaxStreamsPerPeer is the maximum number of concurrent streams that a peer // MaxStreamsPerPeer is the maximum number of concurrent streams that a peer
// is allowed to open. // is allowed to open.
MaxStreamsPerPeer int MaxStreamsPerPeer int
@ -83,8 +83,6 @@ type ConfigQUIC struct {
type ServerQUIC struct { type ServerQUIC struct {
*ServerBase *ServerBase
conf ConfigQUIC
// pool is a goroutine pool we use to process DNS queries. Complicated // pool is a goroutine pool we use to process DNS queries. Complicated
// logic may require growing the goroutine's stack and we experienced it // 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 // 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 is a listener that we use to accept DoQ connections.
quicListener *quic.Listener 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. // quicBytePoolSize is the size for the QUIC byte pools.
@ -120,10 +122,10 @@ func NewServerQUIC(conf ConfigQUIC) (s *ServerQUIC) {
s = &ServerQUIC{ s = &ServerQUIC{
ServerBase: newServerBase(ProtoDoQ, conf.ConfigBase), ServerBase: newServerBase(ProtoDoQ, conf.ConfigBase),
conf: conf,
pool: newPoolNonblocking(), pool: newPoolNonblocking(),
reqPool: syncutil.NewSlicePool[byte](quicBytePoolSize), reqPool: syncutil.NewSlicePool[byte](quicBytePoolSize),
respPool: syncutil.NewSlicePool[byte](quicBytePoolSize), respPool: syncutil.NewSlicePool[byte](quicBytePoolSize),
conf: conf,
} }
return s return s
@ -207,7 +209,6 @@ func (s *ServerQUIC) shutdown() (err error) {
s.started = false s.started = false
// Now close all listeners // Now close all listeners
s.closeListeners()
err = s.quicListener.Close() err = s.quicListener.Close()
if err != nil { if err != nil {
// Log this error but do not return it // 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 // Wait until all conns are processed before exiting this method
defer wg.Wait() 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() { for s.isStarted() {
err = s.acceptQUICConn(ctx, l, wg) err = s.acceptQUICConn(ctx, l, wg)
if err != nil { if err != nil {
@ -251,7 +258,6 @@ func (s *ServerQUIC) serveQUIC(ctx context.Context, l *quic.Listener) (err error
return err return err
} }
} }
return nil return nil
@ -294,7 +300,7 @@ func (s *ServerQUIC) acceptQUICConn(
} }
// serveQUICConnAsync wraps serveQUICConn call and handles all possible errors // 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. // decremented.
func (s *ServerQUIC) serveQUICConnAsync( func (s *ServerQUIC) serveQUICConnAsync(
ctx context.Context, ctx context.Context,
@ -331,6 +337,21 @@ func (s *ServerQUIC) serveQUICConn(ctx context.Context, conn quic.Connection) (e
// bidirectional stream. // bidirectional stream.
var stream quic.Stream var stream quic.Stream
acceptCtx, cancel := context.WithDeadline(ctx, time.Now().Add(maxQUICIdleTimeout)) 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) stream, err = conn.AcceptStream(acceptCtx)
// Make sure to call the cancel function to avoid leaks. // Make sure to call the cancel function to avoid leaks.
cancel() cancel()
@ -396,9 +417,7 @@ func (s *ServerQUIC) serveQUICStream(
// that stream. // that stream.
defer log.OnCloserError(stream, log.DEBUG) defer log.OnCloserError(stream, log.DEBUG)
var msg *dns.Msg msg, err := s.readQUICMsg(ctx, stream)
var doqDraft bool
msg, doqDraft, err = s.readQUICMsg(ctx, stream)
if err != nil { if err != nil {
closeQUICConn(conn, DOQCodeProtocolError) closeQUICConn(conn, DOQCodeProtocolError)
@ -435,15 +454,7 @@ func (s *ServerQUIC) serveQUICStream(
bufPtr := s.respPool.Get() bufPtr := s.respPool.Get()
defer s.respPool.Put(bufPtr) defer s.respPool.Put(bufPtr)
// Depending on the DoQ version we either write a 2-bytes prefixed message b, err := packWithPrefix(resp, *bufPtr)
// 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)
}
if err != nil { if err != nil {
closeQUICConn(conn, DOQCodeProtocolError) closeQUICConn(conn, DOQCodeProtocolError)
@ -464,7 +475,7 @@ func (s *ServerQUIC) serveQUICStream(
func (s *ServerQUIC) readQUICMsg( func (s *ServerQUIC) readQUICMsg(
ctx context.Context, ctx context.Context,
stream quic.Stream, stream quic.Stream,
) (m *dns.Msg, doqDraft bool, err error) { ) (m *dns.Msg, err error) {
bufPtr := s.reqPool.Get() bufPtr := s.reqPool.Get()
defer s.reqPool.Put(bufPtr) defer s.reqPool.Put(bufPtr)
@ -485,35 +496,29 @@ func (s *ServerQUIC) readQUICMsg(
// received. // received.
if n < DNSHeaderSize { if n < DNSHeaderSize {
if err != nil { 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) 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 // TODO(a.garipov): DRY logic with the TCP one.
// draft DNS messages were not prefixed with the message length.
m = &dns.Msg{} 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]) packetLen := binary.BigEndian.Uint16(buf[:2])
if packetLen == uint16(n-2) { wantLen := uint16(n - 2)
if packetLen == wantLen {
err = m.Unpack(buf[2:]) err = m.Unpack(buf[2:])
} else { } else {
err = m.Unpack(buf) err = fmt.Errorf("bad buffer size %d, want %d", packetLen, wantLen)
doqDraft = true
} }
if err != nil { if err != nil {
s.metrics.OnInvalidMsg(ctx) 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. // 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 return err
} }
// Save this for s.LocalUDPAddr. Do not close it separately as ql closes
// the underlying connection.
s.udpListener = conn s.udpListener = conn
s.quicListener = ql s.quicListener = ql
return nil return nil

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"encoding/binary" "encoding/binary"
"fmt"
"io" "io"
"net" "net"
"sync" "sync"
@ -30,7 +31,7 @@ func TestServerQUIC_integration_query(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) { testutil.CleanupAndRequireSuccess(t, func() (err error) {
return srv.Shutdown(context.Background()) return srv.Shutdown(contextWithTimeout(t, testTimeout))
}) })
// Open a QUIC connection. // Open a QUIC connection.
@ -41,28 +42,29 @@ func TestServerQUIC_integration_query(t *testing.T) {
return conn.CloseWithError(0, "") return conn.CloseWithError(0, "")
}) })
// Send multiple queries to the DNS server in parallel const queriesNum = 100
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(queriesNum)
for i := 0; i < 100; i++ { for i := 0; i < queriesNum; i++ {
wg.Add(1)
// Create a test message.
req := dnsservertest.NewReq("example.org.", dns.TypeA, dns.ClassINET) req := dnsservertest.NewReq("example.org.", dns.TypeA, dns.ClassINET)
req.RecursionDesired = true req.RecursionDesired = true
// Even requests are sent as if it's an old draft client.
doqDraft := i%2 == 0
go func() { go func() {
defer wg.Done() defer wg.Done()
resp := sendQUICMessage(t, conn, req, doqDraft) resp, reqErr := sendQUICMessage(conn, req)
assert.NotNil(t, resp) // 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) assert.True(t, resp.Response)
// EDNS0 padding is only present when request also has padding opt. // EDNS0 padding is only present when request also has padding opt.
paddingOpt := dnsservertest.FindEDNS0Option[*dns.EDNS0_PADDING](resp) 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) require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) { testutil.CleanupAndRequireSuccess(t, func() (err error) {
return srv.Shutdown(context.Background()) return srv.Shutdown(contextWithTimeout(t, testTimeout))
}) })
// Open a QUIC connection. // Open a QUIC connection.
@ -92,7 +94,7 @@ func TestServerQUIC_integration_ENDS0Padding(t *testing.T) {
req := dnsservertest.CreateMessage("example.org.", dns.TypeA) req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
req.Extra = []dns.RR{dnsservertest.NewEDNS0Padding(req.Len(), dns.DefaultMsgSize)} 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.NotNil(t, resp)
require.Equal(t, dns.RcodeSuccess, resp.Rcode) require.Equal(t, dns.RcodeSuccess, resp.Rcode)
require.True(t, resp.Response) require.True(t, resp.Response)
@ -112,7 +114,7 @@ func TestServerQUIC_integration_0RTT(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) { testutil.CleanupAndRequireSuccess(t, func() (err error) {
return srv.Shutdown(context.Background()) return srv.Shutdown(contextWithTimeout(t, testTimeout))
}) })
quicTracer := dnsservertest.NewQUICTracer() quicTracer := dnsservertest.NewQUICTracer()
@ -150,7 +152,7 @@ func TestServerQUIC_integration_largeQuery(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) { testutil.CleanupAndRequireSuccess(t, func() (err error) {
return srv.Shutdown(context.Background()) return srv.Shutdown(contextWithTimeout(t, testTimeout))
}) })
// Open a QUIC connection. // 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.NotNil(t, resp)
require.True(t, resp.Response) require.True(t, resp.Response)
} }
@ -202,64 +204,77 @@ func testQUICExchange(
req := dnsservertest.NewReq("example.org.", dns.TypeA, dns.ClassINET) req := dnsservertest.NewReq("example.org.", dns.TypeA, dns.ClassINET)
req.RecursionDesired = true req.RecursionDesired = true
resp := sendQUICMessage(t, conn, req, false) resp := requireSendQUICMessage(t, conn, req)
require.NotNil(t, resp) require.NotNil(t, resp)
} }
// sendQUICMessage is a test helper that sends a test QUIC message. // sendQUICMessage is a test helper that sends a test QUIC message.
func sendQUICMessage( func sendQUICMessage(
t testing.TB,
conn quic.Connection, conn quic.Connection,
req *dns.Msg, req *dns.Msg,
doqDraft bool, ) (resp *dns.Msg, err error) {
) (resp *dns.Msg) {
t.Helper()
stream, err := conn.OpenStreamSync(context.Background()) stream, err := conn.OpenStreamSync(context.Background())
require.NoError(t, err) if err != nil {
return nil, fmt.Errorf("opening stream: %w", 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)
} }
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) 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. // 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 // A DoQ client MUST send a FIN packet to indicate that the query is
// finished. // finished.
err = stream.Close() 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) respBytes := make([]byte, dns.MaxMsgSize)
n, err := stream.Read(respBytes) n, err := stream.Read(respBytes)
if !errors.Is(err, io.EOF) { if err != nil && !errors.Is(err, io.EOF) {
require.NoError(t, err) 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{} reply := &dns.Msg{}
if doqDraft { err = reply.Unpack(respBytes[2:n])
err = reply.Unpack(respBytes[:n]) if err != nil {
} else { return nil, fmt.Errorf("unpacking: %w", err)
err = reply.Unpack(respBytes[2:n])
} }
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) require.NoError(t, err)
return reply return resp
} }
// writeQUICStream writes buf to the specified QUIC stream in chunks. This way // 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/access"
"github.com/AdguardTeam/AdGuardDNS/internal/agd" "github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdservice"
"github.com/AdguardTeam/AdGuardDNS/internal/billstat" "github.com/AdguardTeam/AdGuardDNS/internal/billstat"
"github.com/AdguardTeam/AdGuardDNS/internal/connlimiter" "github.com/AdguardTeam/AdGuardDNS/internal/connlimiter"
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck" "github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
@ -34,6 +33,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/querylog" "github.com/AdguardTeam/AdGuardDNS/internal/querylog"
"github.com/AdguardTeam/AdGuardDNS/internal/rulestat" "github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/service"
"github.com/miekg/dns" "github.com/miekg/dns"
) )
@ -144,6 +144,10 @@ type Config struct {
// used. // used.
UseECSCache bool UseECSCache bool
// ProfileDBEnabled is true, if user devices and profiles recognition is
// enabled.
ProfileDBEnabled bool
// ResearchMetrics controls whether research metrics are enabled or not. // ResearchMetrics controls whether research metrics are enabled or not.
// This is a set of metrics that we may need temporary, so its collection is // This is a set of metrics that we may need temporary, so its collection is
// controlled by a separate setting. // controlled by a separate setting.
@ -267,10 +271,10 @@ func mustStartListener(
} }
// type check // type check
var _ agdservice.Interface = (*Service)(nil) var _ service.Interface = (*Service)(nil)
// Start implements the [agdservice.Interface] interface for *Service. It // Start implements the [service.Interface] interface for *Service. It panics
// panics if one of the listeners could not start. // if one of the listeners could not start.
func (svc *Service) Start(_ context.Context) (err error) { func (svc *Service) Start(_ context.Context) (err error) {
for _, g := range svc.groups { for _, g := range svc.groups {
for _, s := range g.servers { for _, s := range g.servers {
@ -298,7 +302,7 @@ func shutdownListeners(ctx context.Context, listeners []*listener) (err error) {
return nil 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) { func (svc *Service) Shutdown(ctx context.Context) (err error) {
var errs []error var errs []error
for _, g := range svc.groups { for _, g := range svc.groups {
@ -512,13 +516,14 @@ func newServers(
}) })
imw := initial.New(&initial.Config{ imw := initial.New(&initial.Config{
Messages: c.Messages, Messages: c.Messages,
FilteringGroup: fg, FilteringGroup: fg,
ServerGroup: srvGrp, ServerGroup: srvGrp,
Server: s, Server: s,
ProfileDB: c.ProfileDB, ProfileDB: c.ProfileDB,
GeoIP: c.GeoIP, GeoIP: c.GeoIP,
ErrColl: c.ErrColl, ErrColl: c.ErrColl,
ProfileDBEnabled: c.ProfileDBEnabled,
}) })
h := dnsserver.WithMiddlewares( h := dnsserver.WithMiddlewares(

View File

@ -101,8 +101,8 @@ func newTestService(
OnIsBlockedHost: func(host string, qt uint16) (blocked bool) { OnIsBlockedHost: func(host string, qt uint16) (blocked bool) {
return false return false
}, },
OnIsBlockedIP: func(ip netip.Addr) (blocked bool, rule string) { OnIsBlockedIP: func(ip netip.Addr) (blocked bool) {
return false, "" return false
}, },
} }
@ -228,16 +228,18 @@ func newTestService(
}, },
}, },
ServerGroups: []*agd.ServerGroup{{ ServerGroups: []*agd.ServerGroup{{
TLS: &agd.TLS{ BlockPageRedirect: &agd.BlockPageRedirect{},
DeviceIDWildcards: []string{dnssvctest.DeviceIDWildcard},
},
DDR: &agd.DDR{ DDR: &agd.DDR{
Enabled: true, Enabled: true,
}, },
TLS: &agd.TLS{
DeviceIDWildcards: []string{dnssvctest.DeviceIDWildcard},
},
Name: testSrvGrpName, Name: testSrvGrpName,
FilteringGroup: testFltGrpID, FilteringGroup: testFltGrpID,
Servers: []*agd.Server{srv}, Servers: []*agd.Server{srv},
}}, }},
ProfileDBEnabled: true,
} }
svc, err := dnssvc.New(c) 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") }() defer func() { err = errors.Annotate(err, "access mw: %w") }()
rAddr := netutil.NetAddrToAddrPort(rw.RemoteAddr()).Addr() rAddr := netutil.NetAddrToAddrPort(rw.RemoteAddr()).Addr()
if blocked, _ := mw.accessManager.IsBlockedIP(rAddr); blocked { if blocked := mw.accessManager.IsBlockedIP(rAddr); blocked {
metrics.AccessBlockedForSubnetTotal.Inc() metrics.AccessBlockedForSubnetTotal.Inc()
return nil return nil

View File

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

View File

@ -55,6 +55,10 @@ type Middleware struct {
// errColl collects and reports the errors considered non-critical. // errColl collects and reports the errors considered non-critical.
errColl errcoll.Interface 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 // 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 collects and reports the errors considered non-critical.
ErrColl errcoll.Interface 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. // 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) { pool: syncutil.NewPool(func() (v *agd.RequestInfo) {
return &agd.RequestInfo{} return &agd.RequestInfo{}
}), }),
db: c.ProfileDB, db: c.ProfileDB,
geoIP: c.GeoIP, geoIP: c.GeoIP,
errColl: c.ErrColl, errColl: c.ErrColl,
profilesEnabled: c.ProfileDBEnabled,
} }
} }
@ -221,6 +230,10 @@ func (mw *Middleware) newRequestInfo(
return nil, err return nil, err
} }
if !mw.profilesEnabled {
return ri, nil
}
// Add the profile information, if any. // Add the profile information, if any.
localAddr := netutil.NetAddrToAddrPort(lAddr) localAddr := netutil.NetAddrToAddrPort(lAddr)
err = mw.addProfile(ctx, ri, req, localAddr) err = mw.addProfile(ctx, ri, req, localAddr)

View File

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

View File

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

View File

@ -198,9 +198,10 @@ func TestMiddleware_ServeDNS_specialDomain(t *testing.T) {
Protocol: agd.ProtoDNS, Protocol: agd.ProtoDNS,
LinkedIPEnabled: true, LinkedIPEnabled: true,
}, },
ProfileDB: db, ProfileDB: db,
GeoIP: geoIP, GeoIP: geoIP,
ErrColl: errColl, ErrColl: errColl,
ProfileDBEnabled: true,
}) })
h := mw.Wrap(handler) 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 // Package internal contains common constants, types, and utilities shared by
// other subpackages of package filter/. // other subpackages of package filter/.
//
// TODO(a.garipov): Move more code to subpackages, see AGDNS-824.
package internal package internal
import ( 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.", 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 // ProfilesCountGauge is a gauge with the total number of user profiles loaded
// from the backend. // from the backend.
var ProfilesCountGauge = promauto.NewGauge(prometheus.GaugeOpts{ var ProfilesCountGauge = promauto.NewGauge(prometheus.GaugeOpts{

View File

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

View File

@ -35,6 +35,16 @@ const (
subsystemWebSvc = "websvc" 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 // SetUpGauge signals that the server has been started. Use a function here to
// avoid circular dependencies. // avoid circular dependencies.
func SetUpGauge(version, buildtime, branch, revision, goversion string) { 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) 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. // Config represents the profile database configuration.
type Config struct { type Config struct {
// Storage returns the data for this profile DB. // Storage returns the data for this profile DB.

View File

@ -1,38 +1,36 @@
module github.com/AdguardTeam/AdGuardDNS/internal/tools module github.com/AdguardTeam/AdGuardDNS/internal/tools
go 1.21.5 go 1.21.8
require ( require (
github.com/fzipp/gocyclo v0.6.0 github.com/fzipp/gocyclo v0.6.0
github.com/golangci/misspell v0.4.1 github.com/golangci/misspell v0.4.1
github.com/gordonklaus/ineffassign v0.1.0 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/kyoh86/looppointer v0.2.1
github.com/securego/gosec/v2 v2.18.2 github.com/securego/gosec/v2 v2.19.0
// TODO(a.garipov): Return to latest once the release is tagged
// correctly. See uudashr/gocognit#31.
github.com/uudashr/gocognit v1.1.2 github.com/uudashr/gocognit v1.1.2
golang.org/x/tools v0.16.0 golang.org/x/tools v0.18.0
golang.org/x/vuln v1.0.1 golang.org/x/vuln v1.0.4
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.32.0
honnef.co/go/tools v0.4.6 honnef.co/go/tools v0.4.7
mvdan.cc/gofumpt v0.5.0 mvdan.cc/gofumpt v0.6.0
mvdan.cc/unparam v0.0.0-20230917202934-3ee2d22f45fb mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14
) )
require ( require (
github.com/BurntSushi/toml v1.3.2 // indirect 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/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/gookit/color v1.5.4 // indirect
github.com/kyoh86/nolint v0.0.1 // indirect github.com/kyoh86/nolint v0.0.1 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // 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 v0.0.0-20230307190834-24139beb5833 // indirect
golang.org/x/exp/typeparams v0.0.0-20231127185646-65229373498e // indirect golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/mod v0.14.0 // indirect golang.org/x/mod v0.15.0 // indirect
golang.org/x/sync v0.5.0 // indirect golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.15.0 // indirect golang.org/x/sys v0.17.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // 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 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 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.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg=
github.com/ccojocar/zxcvbn-go v1.0.1/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 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 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= 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.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 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 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= 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 h1:+y73iSicVy2PqyX7kmUefHusENlrP9YwuHZHPLGQj/g=
github.com/golangci/misspell v0.4.1/go.mod h1:9mAN1quEo3DlpbaIKKyEvRxK1pwqR9s/Sea1bJCtlNI= 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 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-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 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 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 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 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.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= 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 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s=
github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= 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.7.0 h1:+SbscKmWJ5mOK/bO1zS60F5I9WwZDWOfRsC4RwfwRV0=
github.com/kisielk/errcheck v1.6.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= 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 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 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 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/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 h1:GjNxDEkVn2wAxKHtP7iNTrRxytRZ1wXxLV5j4XzGfRU=
github.com/kyoh86/nolint v0.0.1/go.mod h1:1ZiZZ7qqrZ9dZegU96phwVcdQOMKIqRzFJL3ewq9gtI= 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.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA= github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo=
github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/securego/gosec/v2 v2.18.2 h1:DkDt3wCiOtAHf1XkiXZBhQ6m6mK/b9T/wD257R3/c+I= github.com/securego/gosec/v2 v2.19.0 h1:gl5xMkOI0/E6Hxx0XCY2XujA3V7SNSefA8sC+3f1gnk=
github.com/securego/gosec/v2 v2.18.2/go.mod h1:xUuqSF6i0So56Y2wwohWAmB07EdBkUN6crbLlHwbyJs= 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 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/uudashr/gocognit v1.1.2 h1:l6BAEKJqQH2UpKAPKdMfZf5kE4W/2xk8pfU1OVLvniI= 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/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 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= 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-20240222234643-814bf88cf225 h1:BzKNaIRXh1bD+1557OcFIHlpYBiVbK4zEyn8zBHi1SE=
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/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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.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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-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-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-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-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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 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.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= 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-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-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.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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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-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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-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-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.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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/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.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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/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.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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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-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-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.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.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.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/vuln v1.0.1 h1:KUas02EjQK5LTuIx1OylBQdKKZ9jeugs+HiqO5HormU= golang.org/x/vuln v1.0.4 h1:SP0mPeg2PmGCu03V+61EcQiOjmpri2XijexKdzv8Z1I=
golang.org/x/vuln v1.0.1/go.mod h1:bb2hMwln/tqxg32BNY4CcxHWtHXuYa3SbIBmtsyjxtM= 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-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-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= 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 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= 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.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 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/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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs=
honnef.co/go/tools v0.4.6/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0= honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0=
mvdan.cc/gofumpt v0.5.0 h1:0EQ+Z56k8tXjj/6TQD25BFNKQXpCvT0rnansIc7Ug5E= mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo=
mvdan.cc/gofumpt v0.5.0/go.mod h1:HBeVDtMKRZpXyxFciAirzdKklDlGu8aAy1wEbH5Y9js= mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA=
mvdan.cc/unparam v0.0.0-20230917202934-3ee2d22f45fb h1:xiF91GJnDSbyPdiZB5d52N2VpZfGhjM4Ji75cjzuooQ= mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14 h1:zCr3iRRgdk5eIikZNDphGcM6KGVTx3Yu+/Uu9Es254w=
mvdan.cc/unparam v0.0.0-20230917202934-3ee2d22f45fb/go.mod h1:ZzZjEpJDOmx8TdVU6umamY3Xy0UAQUI2DHbf05USVbI= mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14/go.mod h1:ZzZjEpJDOmx8TdVU6umamY3Xy0UAQUI2DHbf05USVbI=

View File

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

View File

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