diff --git a/.gitignore b/.gitignore
index 6ced4cd..a52cf5c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@ config.yml
country.mmdb
dnsdb.bolt
querylog.jsonl
+profilecache.json
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 50e1511..eb22dbd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,26 +11,64 @@ The format is **not** based on [Keep a Changelog][kec], since the project
+## AGDNS-1174 / Build 397
+
+ * DNS Server Check now responds with NODATA message to all non-A neither non-AAAA requests.
+
+
+
+## AGDNS-911 / Build 375
+
+ * Added support for running a DoH3 server. No configuration changes are
+ required to run it. If there was a DoH server configured, it will start
+ listening for HTTP/3 connections on the same port where it listens for
+ HTTP/2. Make sure that udp/443 is allowed in the iptables configuration on
+ the server.
+
+
+
+## AGDNS-842 / Build 372
+
+ * The new environment variable `PROFILES_CACHE_PATH` has been added. Its
+ default value is `./profilecache.json`. Adjust the value, if necessary.
+
+
+
+## AGDNS-891 / Build 371
+
+ * The property `server` of `upstream` object has been changed. Now it
+ is a URL optionally starting with `tcp://` or `udp://`, and then an address
+ in `ip:port` format.
+
+ ```yaml
+ upstream:
+ server: 'tcp://8.8.8.8:53'
+ ```
+
+ Adjust the value, if necessary.
+
+
+
## AGDNS-1032 / Build 363
-* The new optional field `static_content.*.allow_origin` has been added:
+ * The new optional field `static_content.*.allow_origin` has been added:
- ```yaml
+ ```yaml
static_content:
'/favicon.ico':
allow_origin: '*'
- ```
+ ```
## AGDNS-898 / Build 359
-* The new optional object `additional_metrics_info` has been added:
+ * The new optional object `additional_metrics_info` has been added:
- ```yaml
- additional_metrics_info:
- test_key: 'test_value'
- ```
+ ```yaml
+ additional_metrics_info:
+ test_key: 'test_value'
+ ```
diff --git a/config.dist.yml b/config.dist.yml
index f6b7c1c..1b6b0ee 100644
--- a/config.dist.yml
+++ b/config.dist.yml
@@ -48,7 +48,7 @@ cache:
# DNS upstream configuration.
upstream:
- server: '127.0.0.9:53'
+ server: '8.8.8.8:53'
timeout: 2s
fallback:
- 1.1.1.1:53
diff --git a/doc/configuration.md b/doc/configuration.md
index ebaffa9..e003421 100644
--- a/doc/configuration.md
+++ b/doc/configuration.md
@@ -139,9 +139,13 @@ The `cache` object has the following properties:
The `upstream` object has the following properties:
* `server`:
- The address of the main upstream server, in the `ip:port` format.
+ The URL of the main upstream server, in the `[scheme://]ip:port` format.
- **Example:** `8.8.8.8:53` or `[2001:4860:4860::8844]:53`.
+ **Examples:**
+
+ - `8.8.8.8:53`: regular DNS (over UDP with TCP fallback).
+ - `tcp://1.1.1.1:53`: regular DNS (over TCP).
+ - `udp://1.1.1.1:53`: regular DNS (over UDP).
* `timeout`:
Timeout for all outgoing DNS requests, as a human-readable duration.
@@ -223,8 +227,9 @@ The `backend` object has the following properties:
**Example:** `1m`.
* `full_refresh_interval`:
- How often AdGuard DNS performs full synchronization, as a human-readable
- duration.
+ How often AdGuard DNS performs a full profile refresh, as a human-readable
+ duration. If [`PROFILES_CACHE_PATH`][env-profiles_cache_path] is set, the
+ profile cache is also saved after a full refresh.
**Example:** `24h`.
@@ -234,6 +239,8 @@ The `backend` object has the following properties:
**Example:** `1m`.
+[env-profiles_cache_path]: environment.md#PROFILES_CACHE_PATH
+
## Query Log
@@ -825,7 +832,7 @@ The `connectivity_check` object has the following properties:
The `additional_metrics_info` object is a map of strings with extra information
which is exposed by `dns_app_additional_info` metric.
-Map keys must match reqular expression `^[a-zA-Z_][a-zA-Z0-9_]*$`. See
+Map keys must match regular expression `^[a-zA-Z_][a-zA-Z0-9_]*$`. See
[Prometheus documentation on valid labels][prom-label].
**Property example:**
diff --git a/doc/development.md b/doc/development.md
index 318dc31..fca97e6 100644
--- a/doc/development.md
+++ b/doc/development.md
@@ -206,6 +206,8 @@ Examples below are for the configuration with the following changes:
* DoH: `443` → `8443`
* DoQ: `853` → `8853`
+You may also need to remove `probe_ipv6` if your network does not support IPv6.
+
```sh
env \
BACKEND_ENDPOINT='PUT BACKEND URL HERE' \
@@ -215,6 +217,7 @@ env \
DNSDB_PATH='./test/cache/dnsdb.bolt' \
FILTER_INDEX_URL='https://atropnikov.github.io/HostlistsRegistry/assets/filters.json' \
FILTER_CACHE_PATH='./test/cache' \
+ PROFILES_CACHE_PATH='./test/profilecache.json' \
GENERAL_SAFE_SEARCH_URL='https://adguardteam.github.io/HostlistsRegistry/assets/engines_safe_search.txt' \
GEOIP_ASN_PATH='./test/GeoLite2-ASN-Test.mmdb' \
GEOIP_COUNTRY_PATH='./test/GeoIP2-Country-Test.mmdb' \
diff --git a/doc/environment.md b/doc/environment.md
index 4ed2bc1..48e2b6b 100644
--- a/doc/environment.md
+++ b/doc/environment.md
@@ -15,6 +15,7 @@ sensitive configuration. All other configuration is stored in the
* [`DNSDB_PATH`](#DNSDB_PATH)
* [`FILTER_INDEX_URL`](#FILTER_INDEX_URL)
* [`FILTER_CACHE_PATH`](#FILTER_CACHE_PATH)
+ * [`PROFILES_CACHE_PATH`](#PROFILES_CACHE_PATH)
* [`GENERAL_SAFE_SEARCH_URL`](#GENERAL_SAFE_SEARCH_URL)
* [`GEOIP_ASN_PATH` and `GEOIP_COUNTRY_PATH`](#GEOIP_ASN_PATH)
* [`LISTEN_ADDR`](#LISTEN_ADDR)
@@ -118,6 +119,17 @@ The path to the directory with the filter lists cache.
+## `PROFILES_CACHE_PATH`
+
+The path to the profile cache file. The profile cache is read on start and is
+later updated on every [full refresh][conf-backend-full_refresh_interval].
+
+**Default:** `./profilecache.json`.
+
+[conf-backend-full_refresh_interval]: configuration.md#backend-full_refresh_interval
+
+
+
## `FILTER_INDEX_URL`
The URL of the filtering rule index file server. See the [external HTTP API
diff --git a/doc/http.md b/doc/http.md
index 4ff9030..f3565b7 100644
--- a/doc/http.md
+++ b/doc/http.md
@@ -42,6 +42,10 @@ with a random ID prepended to one of the [check domains][conf-check-domains]
with a hyphen. The random ID must have from 4 to 63 characters and only include
the alphanumeric characters and a hyphen.
+
+
Example of the request:
```sh
@@ -67,28 +71,16 @@ The `protocol` field can have one of the following values:
-
-
"dns-tcp"
+ "dns"
-
- Plain DNS over TCP.
+ Plain DNS.
-
-
"dns-udp"
+ "dnscrypt"
-
- Plain DNS over UDP.
-
- -
-
"dnscrypt-tcp"
-
- -
- DNSCrypt over TCP.
-
- -
-
"dnscrypt-udp"
-
- -
- DNSCrypt over UDP.
+ DNSCrypt.
-
"doh"
diff --git a/doc/querylog.md b/doc/querylog.md
index cf7677e..385fd57 100644
--- a/doc/querylog.md
+++ b/doc/querylog.md
@@ -5,8 +5,8 @@ entries are designed to be concise and easily compressable. An example of the
log output:
```jsonl
-{"u":"ABCD","b":"prof1234","i":"dev1234","c":"RU","d":"US","n":"example.com.","l":"cdef5678","m":"||example.com^","t":1628590394000,"a":1234,"e":5,"q":1,"f":2,"s":0,"p":2,"r":0}
-{"u":"DEFG","b":"prof1234","i":"dev1234","c":"RU","d":"JP","n":"example.org.","l":"hijk9012","m":"||example.org^","t":1628590394100,"a":6789,"e":6,"q":1,"f":2,"s":0,"p":2,"r":0}
+{"u":"ABCD","b":"prof1234","i":"dev1234","c":"RU","d":"US","n":"example.com.","l":"cdef5678","m":"||example.com^","t":1628590394000,"a":1234,"e":5,"q":1,"f":2,"s":0,"p":8,"r":0}
+{"u":"DEFG","b":"prof1234","i":"dev1234","c":"RU","d":"JP","n":"example.org.","l":"hijk9012","m":"||example.org^","t":1628590394100,"a":6789,"e":6,"q":1,"f":2,"s":0,"p":8,"r":0}
```
AdGuard DNS opens and closes the log file on each write to prevent issues with
@@ -207,23 +207,11 @@ rules to remember, which property means what. The properties are:
-
Invalid or unknown protocol. Typically, this value is never used.
- -
-
1
-
- -
- Plain DNS over TCP.
-
- -
-
2
-
- -
- Plain DNS over UDP.
-
-
3
-
- DNS-over-HTTP.
+ DNS-over-HTTPS.
-
4
@@ -238,20 +226,20 @@ rules to remember, which property means what. The properties are:
DNS-over-TLS.
-
-
6
+ 8
-
- DNSCrypt over TCP.
+ Plain DNS.
-
-
7
+ 9
-
- DNSCrypt over UDP.
+ DNSCrypt.
- **Example:** `2`
+ **Example:** `3`
* `r`:
The response code (aka `RCODE`) sent to the client. The short name `r`
diff --git a/go.mod b/go.mod
index a52341e..60376eb 100644
--- a/go.mod
+++ b/go.mod
@@ -4,26 +4,26 @@ go 1.19
require (
github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.100.0
- github.com/AdguardTeam/golibs v0.10.9
+ github.com/AdguardTeam/golibs v0.11.3
github.com/AdguardTeam/urlfilter v0.16.0
- github.com/ameshkov/dnscrypt/v2 v2.2.3
+ github.com/ameshkov/dnscrypt/v2 v2.2.5
github.com/bluele/gcache v0.0.2
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b
- github.com/caarlos0/env/v6 v6.9.3
- github.com/getsentry/raven-go v0.2.0
+ github.com/caarlos0/env/v6 v6.10.1
+ github.com/getsentry/sentry-go v0.14.0
github.com/google/renameio v1.0.1
github.com/miekg/dns v1.1.50
github.com/oschwald/maxminddb-golang v1.10.0
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
- github.com/prometheus/client_golang v1.13.0
- github.com/prometheus/client_model v0.2.0
+ github.com/prometheus/client_golang v1.13.1
+ github.com/prometheus/client_model v0.3.0
github.com/prometheus/common v0.37.0
github.com/stretchr/testify v1.8.0
go.etcd.io/bbolt v1.3.6
- golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
- golang.org/x/net v0.0.0-20220812174116-3211cb980234
- golang.org/x/sys v0.0.0-20220818161305-2296e01440c6
- golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
+ golang.org/x/exp v0.0.0-20221031165847-c99f073a8326
+ golang.org/x/net v0.1.0
+ golang.org/x/sys v0.1.0
+ golang.org/x/time v0.1.0
gopkg.in/yaml.v2 v2.4.0
)
@@ -32,28 +32,26 @@ require (
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
github.com/ameshkov/dnsstamps v1.0.3 // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
- github.com/cheekybits/genny v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
+ github.com/go-logr/logr v1.2.3 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
+ github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
- github.com/lucas-clemente/quic-go v0.28.1 // indirect
- github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
- github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
- github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
- github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
+ github.com/lucas-clemente/quic-go v0.29.2 // indirect
+ github.com/marten-seemann/qpack v0.3.0 // indirect
+ github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
+ github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
- github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
- golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 // indirect
- golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
- golang.org/x/text v0.3.7 // indirect
- golang.org/x/tools v0.1.12 // indirect
+ golang.org/x/crypto v0.1.0 // indirect
+ golang.org/x/mod v0.6.0 // indirect
+ golang.org/x/text v0.4.0 // indirect
+ golang.org/x/tools v0.2.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/go.sum b/go.sum
index d0e8dee..403d014 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,5 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
@@ -32,17 +30,11 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
-dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
-dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
-git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
-github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw=
-github.com/AdguardTeam/golibs v0.10.9 h1:F9oP2da0dQ9RQDM1lGR7LxUTfUWu8hEFOs4icwAkKM0=
-github.com/AdguardTeam/golibs v0.10.9/go.mod h1:W+5rznZa1cSNSFt+gPS7f4Wytnr9fOrd5ZYqwadPw14=
+github.com/AdguardTeam/golibs v0.11.3 h1:Oif+REq2WLycQ2Xm3ZPmJdfftptss0HbGWbxdFaC310=
+github.com/AdguardTeam/golibs v0.11.3/go.mod h1:87bN2x4VsTritptE3XZg9l8T6gznWsIxHBcQ1DeRIXA=
github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
github.com/AdguardTeam/urlfilter v0.16.0 h1:IO29m+ZyQuuOnPLTzHuXj35V1DZOp1Dcryl576P2syg=
github.com/AdguardTeam/urlfilter v0.16.0/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI=
@@ -59,58 +51,44 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/ameshkov/dnscrypt/v2 v2.2.3 h1:X9UP5AHtwp46Ji+sGFfF/1Is6OPI/SjxLqhKpx0P5UI=
-github.com/ameshkov/dnscrypt/v2 v2.2.3/go.mod h1:xJB9cE1/GF+NB6EEQqRlkoa4bjcV2w7VYn1G+zVq7Bs=
-github.com/ameshkov/dnsstamps v1.0.1/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
+github.com/ameshkov/dnscrypt/v2 v2.2.5 h1:Ju1gQeez+6XLtk/b/k3RoJ2t+Ls+BSItLTZjZeedneY=
+github.com/ameshkov/dnscrypt/v2 v2.2.5/go.mod h1:Cu5GgMvCR10BeXgACiGDwXyOpfMktsSIidml1XBp6uM=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
-github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
-github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdSE0JxlhR2hKnGPcNB35BjQf4RYQDY=
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
-github.com/caarlos0/env/v6 v6.9.3 h1:Tyg69hoVXDnpO5Qvpsu8EoquarbPyQb+YwExWHP8wWU=
-github.com/caarlos0/env/v6 v6.9.3/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
+github.com/caarlos0/env/v6 v6.10.1 h1:t1mPSxNpei6M5yAeu1qtRdPAK29Nbcf/n3G7x+b3/II=
+github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s=
-github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
-github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
-github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
-github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
-github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
-github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/getsentry/sentry-go v0.14.0 h1:rlOBkuFZRKKdUnKO+0U3JclRDQKlRu5vVQtkWSQvC70=
+github.com/getsentry/sentry-go v0.14.0/go.mod h1:RZPJKSw+adu8PBNygiri/A98FqVr2HtRckJk9XVxJ9I=
+github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -122,6 +100,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
+github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -132,7 +112,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@@ -170,9 +149,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
-github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -186,18 +163,12 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU=
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
-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.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -214,28 +185,20 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU=
-github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
-github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
-github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
-github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
-github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
-github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ=
-github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
-github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
-github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
-github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
-github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU=
-github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
-github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/lucas-clemente/quic-go v0.29.2 h1:O8Mt0O6LpvEW+wfC40vZdcw0DngwYzoxq5xULZNzSI8=
+github.com/lucas-clemente/quic-go v0.29.2/go.mod h1:g6/h9YMmLuU54tL1gW25uIi3VlBp3uv+sBihplIuskE=
+github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE=
+github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g=
+github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI=
+github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
+github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE=
+github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
-github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
+github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
+github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
@@ -246,8 +209,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
-github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@@ -255,47 +216,42 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
-github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
-github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
-github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
-github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
+github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI=
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible h1:IWzUvJ72xMjmrjR9q3H1PF+jwdN0uNQiR2t1BLNalyo=
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
+github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
-github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
-github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
+github.com/prometheus/client_golang v1.13.1 h1:3gMjIY2+/hzmqhtUC/aQNYldJA6DtH3CgQvwS+02K1c=
+github.com/prometheus/client_golang v1.13.1/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
+github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
-github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
@@ -304,37 +260,11 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil/v3 v3.21.8 h1:nKct+uP0TV8DjjNiHanKf8SAuub+GNsbrOtM9Nl9biA=
github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ=
-github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
-github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
-github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
-github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
-github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
-github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
-github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
-github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
-github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
-github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
-github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
-github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
-github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
-github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
-github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
-github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
-github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
-github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
-github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
-github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
-github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
-github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
-github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -342,18 +272,14 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
-github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
-github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -361,26 +287,19 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
-go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
-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-20180904163835-0709b304e793/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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUHW7cJMmx3TGZOrnyYaNQ6c=
-golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -391,11 +310,10 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
-golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
+golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
+golang.org/x/exp v0.0.0-20221031165847-c99f073a8326/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -415,18 +333,15 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.2.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.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -435,7 +350,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -454,25 +368,20 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
-golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
-golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -488,11 +397,9 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+v
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20181116152217-5ac8a444bdc5/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -502,7 +409,6 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -520,7 +426,6 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -542,9 +447,8 @@ golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5gHoGSL4QbDz3S9s6j4U=
-golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -553,17 +457,15 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
-golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
+golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@@ -583,7 +485,6 @@ golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -607,15 +508,12 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
+golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -633,18 +531,12 @@ google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
-google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -673,9 +565,6 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -710,7 +599,6 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -724,8 +612,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -736,5 +622,3 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
-sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
diff --git a/go.work.sum b/go.work.sum
index db964da..396542b 100644
--- a/go.work.sum
+++ b/go.work.sum
@@ -10,6 +10,8 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412 h1:GvWw74
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c h1:ivON6cwHK1OH26MZyWDCnbTRZZf0IhNsENoNAKFS1g4=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999 h1:OR8VhtwhcAI3U48/rzBsVOuHi0zDPzYI1xASVcdSgR8=
github.com/AdguardTeam/golibs v0.10.7/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw=
+github.com/AdguardTeam/golibs v0.11.2 h1:JbQB1Dg2JWStXgHh1QqBbOLWnP4t9oDjppoBH6TVXSE=
+github.com/AdguardTeam/golibs v0.11.2/go.mod h1:87bN2x4VsTritptE3XZg9l8T6gznWsIxHBcQ1DeRIXA=
github.com/AdguardTeam/gomitmproxy v0.2.0 h1:rvCOf17pd1/CnMyMQW891zrEiIQBpQ8cIGjKN9pinUU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
@@ -31,6 +33,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrp
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
+github.com/getsentry/sentry-go v0.13.0 h1:20dgTiUSfxRB/EhMPtxcL9ZEbM1ZdR+W/7f7NWD+xWo=
+github.com/getsentry/sentry-go v0.13.0/go.mod h1:EOsfu5ZdvKPfeHYV6pTVQnsjfp30+XA7//UooKNumH0=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/gliderlabs/ssh v0.1.1 h1:j3L6gSLQalDETeEg/Jg0mGY0/y/N6zI2xX1978P0Uqw=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
@@ -45,7 +49,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekf
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/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
-github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
@@ -75,7 +78,6 @@ github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T
github.com/lucas-clemente/quic-go v0.27.1/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w=
-github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs=
github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
@@ -90,6 +92,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86 h1:D6paGObi5Wud7xg83MaEFyjxQB1W5bz5d0IFppr+ymk=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab h1:eFXv9Nu1lGbrNbj619aWwZfVF5HBrm9Plte8aNptuTI=
+github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
+github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
github.com/openzipkin/zipkin-go v0.1.1 h1:A/ADD6HaPnAKj3yS7HjGHRK77qi41Hi0DirOOIQAeIw=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
@@ -124,7 +128,6 @@ github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUY
github.com/viant/assertly v0.4.8 h1:5x1GzBaRteIwTr5RAGFVG14uNeRFxVNbXPWrK2qAgpc=
github.com/viant/toolbox v0.24.0 h1:6TteTDQ68CjgcCe8wH3D3ZhUQQOJXMTbj/D9rkk2a1k=
github.com/yuin/goldmark v1.4.1 h1:/vn0k+RBvwlxEmP5E7SZMqNxPhfMVFEJiykr15/0XKM=
-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
go4.org v0.0.0-20180809161055-417644f6feb5 h1:+hE86LblG4AyDgwMCLTE6FOlM9+qjHSYS+rKqxUVdsM=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d h1:E2M5QgjZ/Jg+ObCQAudsXxuTsLj7Nl5RV/lZcQZmKSo=
@@ -137,13 +140,14 @@ golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220516155154-20f960328961/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852 h1:xYq6+9AtI+xP3M4r0N1hCkHrInHDBohhquRgx9Kk6gI=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
+golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/internal/agd/agd_test.go b/internal/agd/agd_test.go
index 768b4c5..960e071 100644
--- a/internal/agd/agd_test.go
+++ b/internal/agd/agd_test.go
@@ -6,13 +6,13 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/golibs/testutil"
)
// Common Constants And Utilities
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
// testTimeout is the timeout for common test operations.
diff --git a/internal/agd/dns.go b/internal/agd/dns.go
index 8165dc9..39fa7cd 100644
--- a/internal/agd/dns.go
+++ b/internal/agd/dns.go
@@ -20,14 +20,12 @@ const (
// packages and modules may depend on the numerical values. These numerical
// values are a part of the API.
- ProtoInvalid = dnsserver.ProtoInvalid
- ProtoDNSTCP = dnsserver.ProtoDNSTCP
- ProtoDNSUDP = dnsserver.ProtoDNSUDP
- ProtoDoH = dnsserver.ProtoDoH
- ProtoDoQ = dnsserver.ProtoDoQ
- ProtoDoT = dnsserver.ProtoDoT
- ProtoDNSCryptTCP = dnsserver.ProtoDNSCryptTCP
- ProtoDNSCryptUDP = dnsserver.ProtoDNSCryptUDP
+ ProtoInvalid = dnsserver.ProtoInvalid
+ ProtoDNS = dnsserver.ProtoDNS
+ ProtoDoH = dnsserver.ProtoDoH
+ ProtoDoQ = dnsserver.ProtoDoQ
+ ProtoDoT = dnsserver.ProtoDoT
+ ProtoDNSCrypt = dnsserver.ProtoDNSCrypt
)
// Resolver is the DNS resolver interface.
diff --git a/internal/agd/profile.go b/internal/agd/profile.go
index ac7f5b8..58d8e42 100644
--- a/internal/agd/profile.go
+++ b/internal/agd/profile.go
@@ -14,6 +14,8 @@ import (
// the infrastructure, a profile is also called a “DNS server”. We call it
// profile, because it's less confusing.
//
+// NOTE: Increment defaultProfileDBCacheVersion on any change of this structure.
+//
// TODO(a.garipov): Consider making it closer to the config file and the backend
// response by grouping parental, rule list, and safe browsing settings into
// separate structs.
diff --git a/internal/agd/profiledb.go b/internal/agd/profiledb.go
index f54a702..41899ae 100644
--- a/internal/agd/profiledb.go
+++ b/internal/agd/profiledb.go
@@ -2,8 +2,10 @@ package agd
import (
"context"
+ "encoding/json"
"fmt"
"net/netip"
+ "os"
"sync"
"time"
@@ -53,6 +55,9 @@ type DefaultProfileDB struct {
// syncTimeFull is the time of the last full synchronization.
syncTimeFull time.Time
+ // cacheFilePath is the path to profiles cache file.
+ cacheFilePath string
+
// fullSyncIvl is the interval between two full synchronizations with the
// storage
fullSyncIvl time.Duration
@@ -64,6 +69,7 @@ type DefaultProfileDB struct {
func NewDefaultProfileDB(
ds ProfileStorage,
fullRefreshIvl time.Duration,
+ cacheFilePath string,
) (db *DefaultProfileDB, err error) {
db = &DefaultProfileDB{
mapsMu: &sync.RWMutex{},
@@ -75,6 +81,12 @@ func NewDefaultProfileDB(
deviceIDToIP: make(map[DeviceID]netip.Addr),
ipToDeviceID: make(map[netip.Addr]DeviceID),
fullSyncIvl: fullRefreshIvl,
+ cacheFilePath: cacheFilePath,
+ }
+
+ err = db.loadProfileCache()
+ if err != nil {
+ log.Error("profiledb: cache: loading: %s", err)
}
// initialTimeout defines the maximum duration of the first attempt to load
@@ -94,7 +106,7 @@ func NewDefaultProfileDB(
return db, nil
}
- return nil, fmt.Errorf("profiledb: initial refresh: %w", err)
+ return nil, fmt.Errorf("initial refresh: %w", err)
}
log.Info("profiledb: initial refresh succeeded")
@@ -146,11 +158,105 @@ func (db *DefaultProfileDB) Refresh(ctx context.Context) (err error) {
db.syncTime = resp.SyncTime
if isFullSync {
db.syncTimeFull = time.Now()
+
+ err = db.saveProfileCache(ctx)
+ if err != nil {
+ return fmt.Errorf("saving cache: %w", err)
+ }
}
return nil
}
+// profileCache is the structure for profiles db cache.
+type profileCache struct {
+ SyncTime time.Time `json:"sync_time"`
+ Profiles []*Profile `json:"profiles"`
+ Version int `json:"version"`
+}
+
+// saveStorageCache saves profiles data to cache file.
+func (db *DefaultProfileDB) saveProfileCache(ctx context.Context) (err error) {
+ var resp *PSProfilesResponse
+ resp, err = db.storage.Profiles(ctx, &PSProfilesRequest{
+ SyncTime: time.Time{},
+ })
+
+ if err != nil {
+ return err
+ }
+
+ data := &profileCache{
+ Profiles: resp.Profiles,
+ Version: defaultProfileDBCacheVersion,
+ SyncTime: time.Now(),
+ }
+
+ cache, err := json.Marshal(data)
+ if err != nil {
+ return fmt.Errorf("encoding json: %w", err)
+ }
+
+ err = os.WriteFile(db.cacheFilePath, cache, 0o600)
+ if err != nil {
+ // Don't wrap the error, because it's informative enough as is.
+ return err
+ }
+
+ log.Debug("profiledb: cache: saved %d profiles to %q", len(resp.Profiles), db.cacheFilePath)
+
+ return nil
+}
+
+// defaultProfileDBCacheVersion is the version of cached data structure. It's
+// manually incremented on every change in [profileCache] structure.
+const defaultProfileDBCacheVersion = 1
+
+// loadProfileCache loads profiles data from cache file.
+func (db *DefaultProfileDB) loadProfileCache() (err error) {
+ data, err := db.loadStorageCache()
+ if err != nil {
+ return fmt.Errorf("loading cache: %w", err)
+ }
+
+ if data == nil {
+ return nil
+ }
+
+ if data.Version == defaultProfileDBCacheVersion {
+ profiles := data.Profiles
+ devNum := db.setProfiles(profiles)
+ log.Debug("profiledb: cache: got %d profiles with %d devices", len(profiles), devNum)
+
+ db.syncTime = data.SyncTime
+ db.syncTimeFull = data.SyncTime
+ }
+
+ return nil
+}
+
+// loadStorageCache loads data from cache file.
+func (db *DefaultProfileDB) loadStorageCache() (data *profileCache, err error) {
+ file, err := os.Open(db.cacheFilePath)
+ if err != nil {
+ if errors.Is(err, os.ErrNotExist) {
+ // File could be deleted or not yet created, go on.
+ return nil, nil
+ }
+
+ return nil, err
+ }
+ defer func() { err = errors.WithDeferred(err, file.Close()) }()
+
+ data = &profileCache{}
+ err = json.NewDecoder(file).Decode(data)
+ if err != nil {
+ return nil, fmt.Errorf("decoding json: %w", err)
+ }
+
+ return data, nil
+}
+
// setProfiles adds or updates the data for all profiles.
func (db *DefaultProfileDB) setProfiles(profiles []*Profile) (devNum int) {
db.mapsMu.Lock()
diff --git a/internal/agd/profiledb_test.go b/internal/agd/profiledb_test.go
index cd432e3..1b6cef6 100644
--- a/internal/agd/profiledb_test.go
+++ b/internal/agd/profiledb_test.go
@@ -3,6 +3,7 @@ package agd_test
import (
"context"
"net/netip"
+ "path/filepath"
"testing"
"time"
@@ -32,7 +33,8 @@ func newDefaultProfileDB(tb testing.TB, dev *agd.Device) (db *agd.DefaultProfile
OnProfiles: onProfiles,
}
- db, err := agd.NewDefaultProfileDB(ds, 1*time.Minute)
+ cacheFilePath := filepath.Join(tb.TempDir(), "profiles.json")
+ db, err := agd.NewDefaultProfileDB(ds, 1*time.Minute, cacheFilePath)
require.NoError(tb, err)
return db
diff --git a/internal/agd/refresh_test.go b/internal/agd/refresh_test.go
index 89e7f61..c3e1d8d 100644
--- a/internal/agd/refresh_test.go
+++ b/internal/agd/refresh_test.go
@@ -13,73 +13,77 @@ import (
"github.com/stretchr/testify/require"
)
-func TestRefreshWorker(t *testing.T) {
- // Test Constants
+// sig is a convenient alias for struct{} when it's used as a signal for
+// synchronization.
+type sig = struct{}
- const (
- testIvl = 5 * time.Millisecond
- testIvlLong = 1 * time.Hour
- name = "test refresher"
- testError errors.Error = "test error"
- )
+const (
+ testIvl = 5 * time.Millisecond
+ testIvlLong = 1 * time.Hour
+ name = "test refresher"
+ testError errors.Error = "test error"
+)
- // Test Mocks
+// newTestRefresher is a helper that returns refr and linked syncCh channel.
+func newTestRefresher(t *testing.T, respErr error) (refr *agdtest.Refresher, syncCh chan sig) {
+ t.Helper()
pt := testutil.PanicT{}
- refreshSync := make(chan agdtest.Signal, 1)
- refr := &agdtest.Refresher{
+ syncCh = make(chan sig, 1)
+ refr = &agdtest.Refresher{
OnRefresh: func(_ context.Context) (err error) {
- agdtest.RequireSend(pt, refreshSync, testTimeout)
+ testutil.RequireSend(pt, syncCh, sig{}, testTimeout)
- return nil
+ return respErr
},
}
- errRefr := &agdtest.Refresher{
- OnRefresh: func(_ context.Context) (err error) {
- agdtest.RequireSend(pt, refreshSync, testTimeout)
+ return refr, syncCh
+}
- return testError
- },
- }
+// newRefrConf returns worker configuration.
+func newRefrConf(
+ t *testing.T,
+ refr agd.Refresher,
+ ivl time.Duration,
+ refrOnShutDown bool,
+ errCh chan sig,
+) (conf *agd.RefreshWorkerConfig) {
+ t.Helper()
+
+ pt := testutil.PanicT{}
- errCh := make(chan agdtest.Signal, 1)
errColl := &agdtest.ErrorCollector{
OnCollect: func(_ context.Context, _ error) {
- agdtest.RequireSend(pt, errCh, testTimeout)
+ testutil.RequireSend(pt, errCh, sig{}, testTimeout)
},
}
- // Test Helpers
-
- refrConf := func(
- refr agd.Refresher,
- ivl time.Duration,
- refrOnShutDown bool,
- ) (conf *agd.RefreshWorkerConfig) {
- return &agd.RefreshWorkerConfig{
- Context: func() (ctx context.Context, cancel context.CancelFunc) {
- return context.WithTimeout(context.Background(), testTimeout)
- },
- Refresher: refr,
- ErrColl: errColl,
- Name: name,
- Interval: ivl,
- RefreshOnShutdown: refrOnShutDown,
- RoutineLogsAreDebug: false,
- }
+ return &agd.RefreshWorkerConfig{
+ Context: func() (ctx context.Context, cancel context.CancelFunc) {
+ return context.WithTimeout(context.Background(), testTimeout)
+ },
+ Refresher: refr,
+ ErrColl: errColl,
+ Name: name,
+ Interval: ivl,
+ RefreshOnShutdown: refrOnShutDown,
+ RoutineLogsAreDebug: false,
}
+}
- // Tests
-
+func TestRefreshWorker(t *testing.T) {
t.Run("success", func(t *testing.T) {
- w := agd.NewRefreshWorker(refrConf(refr, testIvl, false))
+ refr, syncCh := newTestRefresher(t, nil)
+ errCh := make(chan sig, 1)
+
+ w := agd.NewRefreshWorker(newRefrConf(t, refr, testIvl, false, errCh))
err := w.Start()
require.NoError(t, err)
- agdtest.RequireReceive(pt, refreshSync, testTimeout)
+ testutil.RequireReceive(t, syncCh, testTimeout)
require.Empty(t, errCh)
shutdown, cancel := context.WithTimeout(context.Background(), testTimeout)
@@ -90,7 +94,10 @@ func TestRefreshWorker(t *testing.T) {
})
t.Run("success_on_shutdown", func(t *testing.T) {
- w := agd.NewRefreshWorker(refrConf(refr, testIvlLong, true))
+ refr, syncCh := newTestRefresher(t, nil)
+ errCh := make(chan sig, 1)
+
+ w := agd.NewRefreshWorker(newRefrConf(t, refr, testIvlLong, true, errCh))
err := w.Start()
require.NoError(t, err)
@@ -101,18 +108,21 @@ func TestRefreshWorker(t *testing.T) {
err = w.Shutdown(shutdown)
require.NoError(t, err)
- agdtest.RequireReceive(pt, refreshSync, testTimeout)
+ testutil.RequireReceive(t, syncCh, testTimeout)
require.Empty(t, errCh)
})
t.Run("error", func(t *testing.T) {
- w := agd.NewRefreshWorker(refrConf(errRefr, testIvl, false))
+ errRefr, syncCh := newTestRefresher(t, testError)
+ errCh := make(chan sig, 1)
+
+ w := agd.NewRefreshWorker(newRefrConf(t, errRefr, testIvl, false, errCh))
err := w.Start()
require.NoError(t, err)
- agdtest.RequireReceive(pt, refreshSync, testTimeout)
- agdtest.RequireReceive(pt, errCh, testTimeout)
+ testutil.RequireReceive(t, syncCh, testTimeout)
+ testutil.RequireReceive(t, errCh, testTimeout)
shutdown, cancel := context.WithTimeout(context.Background(), testTimeout)
defer cancel()
@@ -122,7 +132,10 @@ func TestRefreshWorker(t *testing.T) {
})
t.Run("error_on_shutdown", func(t *testing.T) {
- w := agd.NewRefreshWorker(refrConf(errRefr, testIvlLong, true))
+ errRefr, syncCh := newTestRefresher(t, testError)
+ errCh := make(chan sig, 1)
+
+ w := agd.NewRefreshWorker(newRefrConf(t, errRefr, testIvlLong, true, errCh))
err := w.Start()
require.NoError(t, err)
@@ -133,7 +146,7 @@ func TestRefreshWorker(t *testing.T) {
err = w.Shutdown(shutdown)
assert.ErrorIs(t, err, testError)
- agdtest.RequireReceive(pt, refreshSync, testTimeout)
+ testutil.RequireReceive(t, syncCh, testTimeout)
require.Empty(t, errCh)
})
}
diff --git a/internal/agd/upstream.go b/internal/agd/upstream.go
index 7c92f66..77952be 100644
--- a/internal/agd/upstream.go
+++ b/internal/agd/upstream.go
@@ -3,6 +3,8 @@ package agd
import (
"net/netip"
"time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/forward"
)
// Upstream
@@ -12,6 +14,9 @@ type Upstream struct {
// Server is the upstream server we're using to forward DNS queries.
Server netip.AddrPort
+ // Network is the Server network protocol.
+ Network forward.Network
+
// FallbackServers is a list of the DNS servers we're using to fallback to
// when the upstream server fails to respond.
FallbackServers []netip.AddrPort
diff --git a/internal/agdnet/agdnet.go b/internal/agdnet/agdnet.go
index b113dc5..2781eb7 100644
--- a/internal/agdnet/agdnet.go
+++ b/internal/agdnet/agdnet.go
@@ -5,37 +5,10 @@ package agdnet
import (
"fmt"
- "net"
"net/netip"
"strings"
)
-// AddrFamily is an IANA address family number.
-type AddrFamily uint16
-
-// IANA address family numbers.
-//
-// See https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml.
-const (
- AddrFamilyNone AddrFamily = 0
- AddrFamilyIPv4 AddrFamily = 1
- AddrFamilyIPv6 AddrFamily = 2
-)
-
-// String implements the fmt.Stringer interface for AddrFamily.
-func (f AddrFamily) String() (s string) {
- switch f {
- case AddrFamilyNone:
- return "none"
- case AddrFamilyIPv4:
- return "ipv4"
- case AddrFamilyIPv6:
- return "ipv6"
- default:
- return fmt.Sprintf("!bad_addr_fam_%d", f)
- }
-}
-
// androidMetricFQDNSuffix is the suffix of the FQDN in DNS queries for
// metrics that the DNS resolver of the Android operating system seems to
// send a lot and because of that we apply special rules to these queries.
@@ -67,102 +40,6 @@ func IsImmediateSubdomain(domain, top string) (ok bool) {
strings.Count(domain, ".") == strings.Count(top, ".")+1
}
-// ZeroSubnet returns an IP subnet with prefix 0 and all bytes of the IP address
-// set to 0. fam must be either AddrFamilyIPv4 or AddrFamilyIPv6.
-//
-// TODO(a.garipov): Move to netutil.
-func ZeroSubnet(fam AddrFamily) (n netip.Prefix) {
- switch fam {
- case AddrFamilyIPv4:
- return netip.PrefixFrom(netip.IPv4Unspecified(), 0)
- case AddrFamilyIPv6:
- return netip.PrefixFrom(netip.IPv6Unspecified(), 0)
- default:
- panic(fmt.Errorf("agdnet: unsupported addr fam %s", fam))
- }
-}
-
-// IPNetToPrefix is a helper that converts a *net.IPNet into a netip.Prefix. If
-// subnet is nil, it returns netip.Prefix{}. fam must be either AddrFamilyIPv4
-// or AddrFamilyIPv6.
-func IPNetToPrefix(subnet *net.IPNet, fam AddrFamily) (p netip.Prefix, err error) {
- if subnet == nil {
- return netip.Prefix{}, nil
- }
-
- addr, err := IPToAddr(subnet.IP, fam)
- if err != nil {
- return netip.Prefix{}, fmt.Errorf("bad ip for subnet %v: %w", subnet, err)
- }
-
- ones, _ := subnet.Mask.Size()
- p = netip.PrefixFrom(addr, ones)
- if !p.IsValid() {
- return netip.Prefix{}, fmt.Errorf("bad subnet %v", subnet)
- }
-
- return p, nil
-}
-
-// IPNetToPrefixNoMapped is like IPNetToPrefix but it detects the address family
-// automatically by assuming that every IPv6-mapped IPv4 address is actually an
-// IPv4 address. Do not use IPNetToPrefixNoMapped where this assumption isn't
-// safe.
-func IPNetToPrefixNoMapped(subnet *net.IPNet) (p netip.Prefix, err error) {
- if subnet == nil {
- return netip.Prefix{}, nil
- }
-
- if ip4 := subnet.IP.To4(); ip4 != nil {
- subnet.IP = ip4
-
- return IPNetToPrefix(subnet, AddrFamilyIPv4)
- }
-
- return IPNetToPrefix(subnet, AddrFamilyIPv6)
-}
-
-// IPToAddr converts a net.IP into a netip.Addr of the given family and returns
-// a meaningful error. fam must be either AddrFamilyIPv4 or AddrFamilyIPv6.
-func IPToAddr(ip net.IP, fam AddrFamily) (addr netip.Addr, err error) {
- switch fam {
- case AddrFamilyIPv4:
- // Make sure that we use the IPv4 form of the address to make sure that
- // netip.Addr doesn't turn out to be an IPv6 one when it really should
- // be an IPv4 one.
- ip4 := ip.To4()
- if ip4 == nil {
- return netip.Addr{}, fmt.Errorf("bad ipv4 net.IP %v", ip)
- }
-
- ip = ip4
- case AddrFamilyIPv6:
- // Again, make sure that we use the correct form according to the
- // address family.
- ip = ip.To16()
- default:
- panic(fmt.Errorf("agdnet: unsupported addr fam %s", fam))
- }
-
- addr, ok := netip.AddrFromSlice(ip)
- if !ok {
- return netip.Addr{}, fmt.Errorf("bad net.IP value %v", ip)
- }
-
- return addr, nil
-}
-
-// IPToAddrNoMapped is like IPToAddr but it detects the address family
-// automatically by assuming that every IPv6-mapped IPv4 address is actually an
-// IPv4 address. Do not use IPToAddrNoMapped where this assumption isn't safe.
-func IPToAddrNoMapped(ip net.IP) (addr netip.Addr, err error) {
- if ip4 := ip.To4(); ip4 != nil {
- return IPToAddr(ip4, AddrFamilyIPv4)
- }
-
- return IPToAddr(ip, AddrFamilyIPv6)
-}
-
// 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))
diff --git a/internal/agdnet/agdnet_example_test.go b/internal/agdnet/agdnet_example_test.go
index 99cc9d2..27716e1 100644
--- a/internal/agdnet/agdnet_example_test.go
+++ b/internal/agdnet/agdnet_example_test.go
@@ -2,10 +2,8 @@ package agdnet_test
import (
"fmt"
- "net"
"github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
- "github.com/AdguardTeam/golibs/netutil"
)
func ExampleIsAndroidTLSMetricDomain() {
@@ -67,109 +65,3 @@ func ExampleIsImmediateSubdomain() {
// similar 1 : false
// similar 2 : false
}
-
-func ExampleZeroSubnet() {
- fmt.Printf("%-5s: %9s\n", "ipv4", agdnet.ZeroSubnet(agdnet.AddrFamilyIPv4))
- fmt.Printf("%-5s: %9s\n", "ipv6", agdnet.ZeroSubnet(agdnet.AddrFamilyIPv6))
-
- func() {
- defer func() { fmt.Println(recover()) }()
-
- _ = agdnet.ZeroSubnet(42)
- }()
-
- // Output:
- // ipv4 : 0.0.0.0/0
- // ipv6 : ::/0
- // agdnet: unsupported addr fam !bad_addr_fam_42
-}
-
-func ExampleIPToAddr() {
- ip := net.IP{1, 2, 3, 4}
- addr, err := agdnet.IPToAddr(ip, agdnet.AddrFamilyIPv4)
- fmt.Println(addr, err)
-
- addr, err = agdnet.IPToAddr(ip, agdnet.AddrFamilyIPv6)
- fmt.Println(addr, err)
-
- addr, err = agdnet.IPToAddr(nil, agdnet.AddrFamilyIPv4)
- fmt.Println(addr, err)
-
- // Output:
- // 1.2.3.4
- // ::ffff:1.2.3.4
- // invalid IP bad ipv4 net.IP
-}
-
-func ExampleIPToAddrNoMapped() {
- addr, err := agdnet.IPToAddrNoMapped(net.IP{1, 2, 3, 4})
- fmt.Println(addr, err)
-
- addrMapped, err := agdnet.IPToAddrNoMapped(net.IPv4(1, 2, 3, 4))
- fmt.Println(addr, err)
- fmt.Printf("%s == %s is %t\n", addr, addrMapped, addr == addrMapped)
-
- addr, err = agdnet.IPToAddrNoMapped(net.ParseIP("1234::cdef"))
- fmt.Println(addr, err)
-
- // Output:
- // 1.2.3.4
- // 1.2.3.4
- // 1.2.3.4 == 1.2.3.4 is true
- // 1234::cdef
-}
-
-func ExampleIPNetToPrefix() {
- prefix, err := agdnet.IPNetToPrefix(nil, agdnet.AddrFamilyIPv4)
- fmt.Println(prefix, err)
-
- prefix, err = agdnet.IPNetToPrefix(&net.IPNet{
- IP: nil,
- }, agdnet.AddrFamilyIPv4)
- fmt.Println(prefix, err)
-
- prefix, err = agdnet.IPNetToPrefix(&net.IPNet{
- IP: net.IP{1, 2, 3, 0},
- Mask: net.CIDRMask(64, netutil.IPv6BitLen),
- }, agdnet.AddrFamilyIPv4)
- fmt.Println(prefix, err)
-
- prefix, err = agdnet.IPNetToPrefix(&net.IPNet{
- IP: net.IP{1, 2, 3, 0},
- Mask: net.CIDRMask(24, netutil.IPv4BitLen),
- }, agdnet.AddrFamilyIPv4)
- fmt.Println(prefix, err)
-
- // Output:
- // invalid Prefix
- // invalid Prefix bad ip for subnet : bad ipv4 net.IP
- // invalid Prefix bad subnet 1.2.3.0/0
- // 1.2.3.0/24
-}
-
-func ExampleIPNetToPrefixNoMapped() {
- prefix, err := agdnet.IPNetToPrefixNoMapped(&net.IPNet{
- IP: net.IP{1, 2, 3, 0},
- Mask: net.CIDRMask(24, netutil.IPv4BitLen),
- })
- fmt.Println(prefix, err)
-
- prefixMapped, err := agdnet.IPNetToPrefixNoMapped(&net.IPNet{
- IP: net.IPv4(1, 2, 3, 0),
- Mask: net.CIDRMask(24, netutil.IPv4BitLen),
- })
- fmt.Println(prefix, err)
- fmt.Printf("%s == %s is %t\n", prefix, prefixMapped, prefix == prefixMapped)
-
- prefix, err = agdnet.IPNetToPrefixNoMapped(&net.IPNet{
- IP: net.ParseIP("1234::cdef"),
- Mask: net.CIDRMask(64, netutil.IPv6BitLen),
- })
- fmt.Println(prefix, err)
-
- // Output:
- // 1.2.3.0/24
- // 1.2.3.0/24
- // 1.2.3.0/24 == 1.2.3.0/24 is true
- // 1234::cdef/64
-}
diff --git a/internal/agdnet/resolver.go b/internal/agdnet/resolver.go
new file mode 100644
index 0000000..8bc7af7
--- /dev/null
+++ b/internal/agdnet/resolver.go
@@ -0,0 +1,193 @@
+package agdnet
+
+import (
+ "context"
+ "fmt"
+ "math"
+ "net"
+ "sync"
+ "time"
+
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/log"
+ "github.com/AdguardTeam/golibs/netutil"
+)
+
+// Resolvers
+
+// Resolver is the DNS resolver interface.
+//
+// See go doc net.Resolver.
+type Resolver interface {
+ LookupIP(ctx context.Context, fam netutil.AddrFamily, host string) (ips []net.IP, err error)
+}
+
+// DefaultResolver uses [net.DefaultResolver] to resolve addresses.
+type DefaultResolver struct{}
+
+// type check
+var _ Resolver = DefaultResolver{}
+
+// LookupIP implements the [Resolver] interface for DefaultResolver.
+func (DefaultResolver) LookupIP(
+ ctx context.Context,
+ fam netutil.AddrFamily,
+ host string,
+) (ips []net.IP, err error) {
+ switch fam {
+ case netutil.AddrFamilyIPv4:
+ return net.DefaultResolver.LookupIP(ctx, "ip4", host)
+ case netutil.AddrFamilyIPv6:
+ return net.DefaultResolver.LookupIP(ctx, "ip6", host)
+ default:
+ return nil, net.UnknownNetworkError(fam.String())
+ }
+}
+
+// resolveCache is a simple address resolving cache.
+type resolveCache map[string]*resolveCacheItem
+
+// resolveCacheItem is an item of [resolveCache].
+type resolveCacheItem struct {
+ refrTime time.Time
+ ips []net.IP
+}
+
+// CachingResolver caches resolved results for hosts for a certain time,
+// regardless of the actual TTLs of the records. It is used for caching the
+// results of lookups of hostnames that don't change their IP addresses often.
+type CachingResolver struct {
+ resolver Resolver
+
+ // mu protects ip4 and ip6.
+ mu *sync.Mutex
+ ipv4 resolveCache
+ ipv6 resolveCache
+
+ ttl time.Duration
+}
+
+// NewCachingResolver returns a new caching resolver.
+func NewCachingResolver(resolver Resolver, ttl time.Duration) (c *CachingResolver) {
+ return &CachingResolver{
+ resolver: resolver,
+
+ mu: &sync.Mutex{},
+ ipv4: resolveCache{},
+ ipv6: resolveCache{},
+
+ ttl: ttl,
+ }
+}
+
+// type check
+var _ Resolver = (*CachingResolver)(nil)
+
+// LookupIP implements the [Resolver] interface for *CachingResolver. host
+// should be normalized. Slice ips and its elements must not be mutated.
+func (c *CachingResolver) LookupIP(
+ ctx context.Context,
+ fam netutil.AddrFamily,
+ host string,
+) (ips []net.IP, err error) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ var item *resolveCacheItem
+ switch fam {
+ case netutil.AddrFamilyIPv4:
+ item = c.ipv4[host]
+ case netutil.AddrFamilyIPv6:
+ item = c.ipv6[host]
+ default:
+ return nil, net.UnknownNetworkError(fam.String())
+ }
+
+ if item == nil || time.Since(item.refrTime) > c.ttl {
+ item, err = c.resolve(ctx, fam, host)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return item.ips, nil
+}
+
+// resolve looks up the IP addresses for host and puts them into the cache.
+func (c *CachingResolver) resolve(
+ ctx context.Context,
+ fam netutil.AddrFamily,
+ host string,
+) (item *resolveCacheItem, err error) {
+ var ips []net.IP
+
+ refrTime := time.Now()
+
+ // Don't resolve IP addresses.
+ ip := net.ParseIP(host)
+ if ip != nil {
+ ip4 := ip.To4()
+ if fam == netutil.AddrFamilyIPv4 && ip4 != nil {
+ ips = []net.IP{ip4}
+ } else if fam == netutil.AddrFamilyIPv6 && ip4 == nil {
+ ips = []net.IP{ip}
+ } else {
+ // Not the right kind of IP address. Cache absence of IP addresses
+ // for this network forever.
+ ips = []net.IP{}
+ }
+
+ // Set the refresh time to the maximum date that time.Duration allows to
+ // prevent this item from refreshing.
+ refrTime = time.Unix(0, math.MaxInt64)
+ } else {
+ ips, err = c.resolver.LookupIP(ctx, fam, host)
+ if err != nil {
+ if !isExpectedLookupError(fam, err) {
+ return nil, fmt.Errorf("resolving %s addr for %q: %w", fam, host, err)
+ }
+
+ log.Debug("caching resolver: warning: %s", err)
+ }
+ }
+
+ var cache resolveCache
+ if fam == netutil.AddrFamilyIPv4 {
+ cache = c.ipv4
+ } else {
+ cache = c.ipv6
+ }
+
+ item = &resolveCacheItem{
+ refrTime: refrTime,
+ ips: ips,
+ }
+
+ cache[host] = item
+
+ return item, nil
+}
+
+// isExpectedLookupError returns true if the error is an expected lookup error.
+func isExpectedLookupError(fam netutil.AddrFamily, err error) (ok bool) {
+ var dnsErr *net.DNSError
+ if fam == netutil.AddrFamilyIPv6 && errors.As(err, &dnsErr) {
+ // It's expected that Go default DNS resolver returns a DNS error in
+ // some cases when it receives an empty response. It's unclear what
+ // exactly triggers this error, though.
+ //
+ // TODO(ameshkov): Consider researching this in detail.
+ return true
+ }
+
+ var addrErr *net.AddrError
+ if !errors.As(err, &addrErr) {
+ return false
+ }
+
+ // Expect the error about no suitable addresses. For example, no IPv6
+ // addresses for a host that does have IPv4 ones.
+ //
+ // See function filterAddrList in ${GOROOT}/src/net/ipsock.go.
+ return addrErr.Err == "no suitable address found"
+}
diff --git a/internal/agdnet/resolver_test.go b/internal/agdnet/resolver_test.go
new file mode 100644
index 0000000..d23102f
--- /dev/null
+++ b/internal/agdnet/resolver_test.go
@@ -0,0 +1,88 @@
+package agdnet_test
+
+import (
+ "context"
+ "net"
+ "testing"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/timeutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestCachingResolver_Resolve(t *testing.T) {
+ const testHost = "addr.example"
+
+ var numLookups uint64
+ wantIPv4 := []net.IP{{1, 2, 3, 4}}
+ wantIPv6 := []net.IP{net.ParseIP("1234::5678")}
+ r := &agdtest.Resolver{
+ OnLookupIP: func(
+ _ context.Context,
+ fam netutil.AddrFamily,
+ _ string,
+ ) (ips []net.IP, err error) {
+ numLookups++
+
+ if fam == netutil.AddrFamilyIPv4 {
+ return wantIPv4, nil
+ }
+
+ return nil, nil
+ },
+ }
+
+ cached := agdnet.NewCachingResolver(r, 1*timeutil.Day)
+
+ testCases := []struct {
+ name string
+ host string
+ wantIPs []net.IP
+ wantNum uint64
+ fam netutil.AddrFamily
+ }{{
+ name: "initial",
+ host: testHost,
+ wantIPs: wantIPv4,
+ wantNum: 1,
+ fam: netutil.AddrFamilyIPv4,
+ }, {
+ name: "cached",
+ host: testHost,
+ wantIPs: wantIPv4,
+ wantNum: 1,
+ fam: netutil.AddrFamilyIPv4,
+ }, {
+ name: "other_network",
+ host: testHost,
+ wantIPs: nil,
+ wantNum: 2,
+ fam: netutil.AddrFamilyIPv6,
+ }, {
+ name: "ipv4",
+ host: wantIPv4[0].String(),
+ wantIPs: wantIPv4,
+ wantNum: 2,
+ fam: netutil.AddrFamilyIPv4,
+ }, {
+ name: "ipv6",
+ host: wantIPv6[0].String(),
+ wantIPs: wantIPv6,
+ wantNum: 2,
+ fam: netutil.AddrFamilyIPv6,
+ }}
+
+ ctx := context.Background()
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ got, err := cached.LookupIP(ctx, tc.fam, tc.host)
+ require.NoError(t, err)
+
+ assert.Equal(t, tc.wantNum, numLookups)
+ assert.Equal(t, tc.wantIPs, got)
+ })
+ }
+}
diff --git a/internal/agdtest/agdtest.go b/internal/agdtest/agdtest.go
index 5b22545..fb83fe6 100644
--- a/internal/agdtest/agdtest.go
+++ b/internal/agdtest/agdtest.go
@@ -1,18 +1,3 @@
// Package agdtest contains simple mocks for common interfaces and other test
// utilities.
package agdtest
-
-import (
- "io"
- "os"
- "testing"
-
- "github.com/AdguardTeam/golibs/log"
-)
-
-// DiscardLogOutput runs tests with discarded logger's output.
-func DiscardLogOutput(m *testing.M) {
- log.SetOutput(io.Discard)
-
- os.Exit(m.Run())
-}
diff --git a/internal/agdtest/interface.go b/internal/agdtest/interface.go
index 7e34e83..43b0eb2 100644
--- a/internal/agdtest/interface.go
+++ b/internal/agdtest/interface.go
@@ -16,6 +16,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
"github.com/AdguardTeam/AdGuardDNS/internal/rulestat"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
)
@@ -23,8 +24,6 @@ import (
//
// Keep entities in this file in alphabetic order.
-// agd.ErrorCollector
-
// type check
var _ agd.ErrorCollector = (*ErrorCollector)(nil)
@@ -40,8 +39,6 @@ func (c *ErrorCollector) Collect(ctx context.Context, err error) {
c.OnCollect(ctx, err)
}
-// agd.ProfileDB
-
// type check
var _ agd.ProfileDB = (*ProfileDB)(nil)
@@ -73,8 +70,6 @@ func (db *ProfileDB) ProfileByIP(
return db.OnProfileByIP(ctx, ip)
}
-// agd.ProfileStorage
-
// type check
var _ agd.ProfileStorage = (*ProfileStorage)(nil)
@@ -94,8 +89,6 @@ func (ds *ProfileStorage) Profiles(
return ds.OnProfiles(ctx, req)
}
-// agd.Refresher
-
// type check
var _ agd.Refresher = (*Refresher)(nil)
@@ -109,28 +102,30 @@ func (r *Refresher) Refresh(ctx context.Context) (err error) {
return r.OnRefresh(ctx)
}
-// agd.Resolver
+// Package agdnet
// type check
-var _ agd.Resolver = (*Resolver)(nil)
+var _ agdnet.Resolver = (*Resolver)(nil)
// Resolver is an agd.Resolver for tests.
type Resolver struct {
- OnLookupIP func(ctx context.Context, network, addr string) (ips []net.IP, err error)
+ OnLookupIP func(
+ ctx context.Context,
+ fam netutil.AddrFamily,
+ host string,
+ ) (ips []net.IP, err error)
}
// LookupIP implements the agd.Resolver interface for *Resolver.
func (r *Resolver) LookupIP(
ctx context.Context,
- network string,
- addr string,
+ fam netutil.AddrFamily,
+ host string,
) (ips []net.IP, err error) {
- return r.OnLookupIP(ctx, network, addr)
+ return r.OnLookupIP(ctx, fam, host)
}
-// Package BillStat
-
-// billstat.Recorder
+// Package billstat
// type check
var _ billstat.Recorder = (*BillStatRecorder)(nil)
@@ -159,8 +154,6 @@ func (r *BillStatRecorder) Record(
r.OnRecord(ctx, id, ctry, asn, start, proto)
}
-// billstat.Uploader
-
// type check
var _ billstat.Uploader = (*BillStatUploader)(nil)
@@ -174,9 +167,7 @@ func (b *BillStatUploader) Upload(ctx context.Context, records billstat.Records)
return b.OnUpload(ctx, records)
}
-// Package DNSCheck
-
-// dnscheck.Interface
+// Package dnscheck
// type check
var _ dnscheck.Interface = (*DNSCheck)(nil)
@@ -195,9 +186,7 @@ func (db *DNSCheck) Check(
return db.OnCheck(ctx, req, ri)
}
-// Package DNSDB
-
-// dnsdb.Interface
+// Package dnsdb
// type check
var _ dnsdb.Interface = (*DNSDB)(nil)
@@ -212,9 +201,7 @@ func (db *DNSDB) Record(ctx context.Context, resp *dns.Msg, ri *agd.RequestInfo)
db.OnRecord(ctx, resp, ri)
}
-// Package Filter
-
-// filter.Interface
+// Package filter
// type check
var _ filter.Interface = (*Filter)(nil)
@@ -257,8 +244,6 @@ func (f *Filter) Close() (err error) {
return f.OnClose()
}
-// filter.Storage
-
// type check
var _ filter.Storage = (*FilterStorage)(nil)
@@ -281,9 +266,7 @@ func (s *FilterStorage) HasListID(id agd.FilterListID) (ok bool) {
return s.OnHasListID(id)
}
-// Package GeoIP
-
-// geoip.Interface
+// Package geoip
// type check
var _ geoip.Interface = (*GeoIP)(nil)
@@ -293,7 +276,7 @@ type GeoIP struct {
OnSubnetByLocation func(
c agd.Country,
a agd.ASN,
- fam agdnet.AddrFamily,
+ fam netutil.AddrFamily,
) (n netip.Prefix, err error)
OnData func(host string, ip netip.Addr) (l *agd.Location, err error)
}
@@ -302,7 +285,7 @@ type GeoIP struct {
func (g *GeoIP) SubnetByLocation(
c agd.Country,
a agd.ASN,
- fam agdnet.AddrFamily,
+ fam netutil.AddrFamily,
) (n netip.Prefix, err error) {
return g.OnSubnetByLocation(c, a, fam)
}
@@ -312,9 +295,7 @@ func (g *GeoIP) Data(host string, ip netip.Addr) (l *agd.Location, err error) {
return g.OnData(host, ip)
}
-// Package Querylog
-
-// querylog.Interface
+// Package querylog
// type check
var _ querylog.Interface = (*QueryLog)(nil)
@@ -329,9 +310,7 @@ func (ql *QueryLog) Write(ctx context.Context, e *querylog.Entry) (err error) {
return ql.OnWrite(ctx, e)
}
-// Package RuleStat
-
-// rulestat.Interface
+// Package rulestat
// type check
var _ rulestat.Interface = (*RuleStat)(nil)
@@ -346,11 +325,9 @@ func (s *RuleStat) Collect(ctx context.Context, id agd.FilterListID, text agd.Fi
s.OnCollect(ctx, id, text)
}
-// Module DNSServer
+// Module dnsserver
-// Package RateLimit
-
-// ratelimit.RateLimit
+// Package ratelimit
// type check
var _ ratelimit.Interface = (*RateLimit)(nil)
diff --git a/internal/agdtest/sync.go b/internal/agdtest/sync.go
deleted file mode 100644
index 15830e1..0000000
--- a/internal/agdtest/sync.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package agdtest
-
-import (
- "time"
-
- "github.com/stretchr/testify/require"
-)
-
-// Synchronization Utilities
-//
-// TODO(a.garipov): Add generic versions when we can.
-//
-// TODO(a.garipov): Add to golibs once the API is stabilized.
-
-// Signal is a simple signal type alias for tests.
-type Signal = struct{}
-
-// RequireSend waits until a signal is sent to ch or until the timeout is
-// reached. If the timeout is reached, the test is failed.
-func RequireSend(t require.TestingT, ch chan<- Signal, timeout time.Duration) {
- if h, ok := t.(interface{ Helper() }); ok {
- h.Helper()
- }
-
- timer := time.NewTimer(timeout)
- defer timer.Stop()
-
- select {
- case ch <- Signal{}:
- // Go on.
- case <-timer.C:
- t.Errorf("did not send after %s", timeout)
- t.FailNow()
- }
-}
-
-// RequireReceive waits until a signal is received from ch or until the timeout
-// is reached. If the timeout is reached, the test is failed.
-func RequireReceive(t require.TestingT, ch <-chan Signal, timeout time.Duration) {
- if h, ok := t.(interface{ Helper() }); ok {
- h.Helper()
- }
-
- timer := time.NewTimer(timeout)
- defer timer.Stop()
-
- select {
- case <-ch:
- // Go on.
- case <-timer.C:
- t.Errorf("did not receive after %s", timeout)
- t.FailNow()
- }
-}
diff --git a/internal/backend/backend_test.go b/internal/backend/backend_test.go
index 0f30955..47bc563 100644
--- a/internal/backend/backend_test.go
+++ b/internal/backend/backend_test.go
@@ -3,9 +3,9 @@ package backend_test
import (
"testing"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/golibs/testutil"
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
diff --git a/internal/backend/profiledb.go b/internal/backend/profiledb.go
index 5807910..c0dde37 100644
--- a/internal/backend/profiledb.go
+++ b/internal/backend/profiledb.go
@@ -82,9 +82,7 @@ func (s *ProfileStorage) Profiles(
return nil, fmt.Errorf("loading from url %s: %w", redURL, err)
}
- updTime := s.now()
-
- return settResp.toInternal(ctx, updTime, s.errColl), nil
+ return settResp.toInternal(ctx, s.now(), s.errColl), nil
}
// loadSettingsResponse fetches, decodes, and returns the settings response.
diff --git a/internal/backend/profiledb_test.go b/internal/backend/profiledb_test.go
index 8dd829e..268de3a 100644
--- a/internal/backend/profiledb_test.go
+++ b/internal/backend/profiledb_test.go
@@ -2,6 +2,7 @@ package backend_test
import (
"context"
+ "fmt"
"net/http"
"net/http/httptest"
"net/netip"
@@ -18,6 +19,12 @@ import (
"github.com/stretchr/testify/require"
)
+// Common test constants.
+var (
+ syncTime = time.Unix(0, 1_624_443_079_309_000_000)
+ updTime = time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)
+)
+
func TestProfileStorage_Profiles(t *testing.T) {
reqURLStr := ""
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -40,7 +47,6 @@ func TestProfileStorage_Profiles(t *testing.T) {
u, err := url.Parse(srv.URL)
require.NoError(t, err)
- updTime := time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)
c := &backend.ProfileStorageConfig{
BaseEndpoint: u,
Now: func() (t time.Time) { return updTime },
@@ -50,7 +56,6 @@ func TestProfileStorage_Profiles(t *testing.T) {
require.NotNil(t, ds)
ctx := context.Background()
- syncTime := time.Unix(0, 1_624_443_079_309_000_000)
req := &agd.PSProfilesRequest{
SyncTime: syncTime,
}
@@ -61,10 +66,19 @@ func TestProfileStorage_Profiles(t *testing.T) {
// Compare against a relative URL since the URL inside an HTTP handler
// seems to always be relative.
- wantURLStr := backend.PathDNSAPIV1Settings + "?sync_time=1624443079309"
+ wantURLStr := fmt.Sprintf("%s?sync_time=%d", backend.PathDNSAPIV1Settings, syncTime.UnixMilli())
assert.Equal(t, wantURLStr, reqURLStr)
- // Keep in sync with the testdata one.
+ want := testProfileResp(t)
+ assert.Equal(t, want, resp)
+}
+
+// testProfileResp returns profile resp corresponding with testdata.
+//
+// Keep in sync with the testdata one.
+func testProfileResp(t *testing.T) *agd.PSProfilesResponse {
+ t.Helper()
+
wantLoc, err := time.LoadLocation("GMT")
require.NoError(t, err)
@@ -151,5 +165,5 @@ func TestProfileStorage_Profiles(t *testing.T) {
}},
}
- assert.Equal(t, want, resp)
+ return want
}
diff --git a/internal/billstat/billstat_test.go b/internal/billstat/billstat_test.go
index 852fd1f..746e5ee 100644
--- a/internal/billstat/billstat_test.go
+++ b/internal/billstat/billstat_test.go
@@ -4,13 +4,13 @@ import (
"testing"
"time"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/golibs/testutil"
)
// Common Constants And Utilities
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
// testTimeout is the timeout for common test operations.
diff --git a/internal/billstat/runtime_test.go b/internal/billstat/runtime_test.go
index 6f78f4e..3c90fc5 100644
--- a/internal/billstat/runtime_test.go
+++ b/internal/billstat/runtime_test.go
@@ -14,6 +14,10 @@ import (
"github.com/stretchr/testify/require"
)
+// sig is a convenient alias for struct{} when it's used as a signal for
+// synchronization.
+type sig = struct{}
+
// Common constants for tests.
const (
devID = "dev1234"
@@ -62,7 +66,7 @@ func TestRuntimeRecorder_fail(t *testing.T) {
const testError errors.Error = "test error"
var emulateFail bool
var gotRecord *billstat.Record
- uploadSync := make(chan agdtest.Signal)
+ uploadSync := make(chan sig)
onUpload := func(_ context.Context, records billstat.Records) (err error) {
if emulateFail {
pt := testutil.PanicT{}
@@ -70,11 +74,11 @@ func TestRuntimeRecorder_fail(t *testing.T) {
// Give the goroutine a signal that it can now record another query
// to emulate a situation where a query gets recorded while an
// upload is in progress.
- agdtest.RequireSend(pt, uploadSync, testTimeout)
+ testutil.RequireSend(pt, uploadSync, sig{}, testTimeout)
// Wait for the other query in the goroutine to be recorded and
// proceed to returning an error after that.
- agdtest.RequireReceive(pt, uploadSync, testTimeout)
+ testutil.RequireReceive(pt, uploadSync, testTimeout)
return testError
}
@@ -104,11 +108,11 @@ func TestRuntimeRecorder_fail(t *testing.T) {
go func() {
pt := testutil.PanicT{}
- agdtest.RequireReceive(pt, uploadSync, testTimeout)
+ testutil.RequireReceive(pt, uploadSync, testTimeout)
r.Record(ctx, devID, clientCtry, clientASN, start, proto)
- agdtest.RequireSend(pt, uploadSync, testTimeout)
+ testutil.RequireSend(pt, uploadSync, sig{}, testTimeout)
}()
err := r.Refresh(context.Background())
diff --git a/internal/cmd/backend.go b/internal/cmd/backend.go
index 980aa19..c67ce89 100644
--- a/internal/cmd/backend.go
+++ b/internal/cmd/backend.go
@@ -1,11 +1,11 @@
package cmd
import (
- "net/url"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/backend"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/timeutil"
)
@@ -33,15 +33,17 @@ type backendConfig struct {
// toInternal converts c to the data storage configuration for the DNS server.
// c is assumed to be valid.
func (c *backendConfig) toInternal(
- backendEndpoint *url.URL,
+ envs *environments,
errColl agd.ErrorCollector,
) (profStrg *backend.ProfileStorageConfig, billStat *backend.BillStatConfig) {
+ backendEndpoint := &envs.BackendEndpoint.URL
+
return &backend.ProfileStorageConfig{
- BaseEndpoint: backendEndpoint,
+ BaseEndpoint: netutil.CloneURL(backendEndpoint),
Now: time.Now,
ErrColl: errColl,
}, &backend.BillStatConfig{
- BaseEndpoint: backendEndpoint,
+ BaseEndpoint: netutil.CloneURL(backendEndpoint),
}
}
diff --git a/internal/cmd/check.go b/internal/cmd/check.go
index 8adb200..d907f3e 100644
--- a/internal/cmd/check.go
+++ b/internal/cmd/check.go
@@ -8,7 +8,6 @@ import (
"strings"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/dnscheck"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/golibs/errors"
@@ -115,13 +114,13 @@ func (c *checkConfig) validate() (err error) {
return errors.Error("no domains")
}
- err = validateNonNilIPs(c.IPv4, agdnet.AddrFamilyIPv4)
+ err = validateNonNilIPs(c.IPv4, netutil.AddrFamilyIPv4)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
}
- err = validateNonNilIPs(c.IPv6, agdnet.AddrFamilyIPv6)
+ err = validateNonNilIPs(c.IPv6, netutil.AddrFamilyIPv6)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
@@ -134,7 +133,9 @@ func (c *checkConfig) validate() (err error) {
return nil
}
-func validateNonNilIPs(ips []netip.Addr, fam agdnet.AddrFamily) (err error) {
+// validateNonNilIPs returns an error if ips is empty or had IP addresses of
+// incorrect protocol version.
+func validateNonNilIPs(ips []netip.Addr, fam netutil.AddrFamily) (err error) {
if len(ips) == 0 {
return fmt.Errorf("no %s", fam)
}
@@ -143,9 +144,9 @@ func validateNonNilIPs(ips []netip.Addr, fam agdnet.AddrFamily) (err error) {
var checkProto func(ip netip.Addr) (ok bool)
switch fam {
- case agdnet.AddrFamilyIPv4:
+ case netutil.AddrFamilyIPv4:
checkProto = netip.Addr.Is4
- case agdnet.AddrFamilyIPv6:
+ case netutil.AddrFamilyIPv6:
checkProto = netip.Addr.Is6
default:
panic(fmt.Errorf("agdnet: unsupported addr fam %s", fam))
diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go
index 3f717f2..475b7cc 100644
--- a/internal/cmd/cmd.go
+++ b/internal/cmd/cmd.go
@@ -192,7 +192,7 @@ func Main() {
// Profiles Database
- profStrgConf, billStatConf := c.Backend.toInternal(&envs.BackendEndpoint.URL, errColl)
+ profStrgConf, billStatConf := c.Backend.toInternal(envs, errColl)
profStrg := backend.NewProfileStorage(profStrgConf)
// Billing Statistics
@@ -213,7 +213,11 @@ func Main() {
err = billStatRecUpd.Start()
fatalOnError(err)
- profDB, err := agd.NewDefaultProfileDB(profStrg, c.Backend.FullRefreshIvl.Duration)
+ profDB, err := agd.NewDefaultProfileDB(
+ profStrg,
+ c.Backend.FullRefreshIvl.Duration,
+ envs.ProfilesCachePath,
+ )
fatalOnError(err)
profDBUpd := agd.NewRefreshWorker(&agd.RefreshWorkerConfig{
@@ -308,8 +312,12 @@ func Main() {
metricsListener := prometheus.NewForwardMetricsListener(len(c.Upstream.FallbackServers) + 1)
+ upstream, err := c.Upstream.toInternal()
+ fatalOnError(err)
+
handler := forward.NewHandler(&forward.HandlerConfig{
- Address: c.Upstream.Server,
+ Address: upstream.Server,
+ Network: upstream.Network,
MetricsListener: metricsListener,
HealthcheckDomainTmpl: c.Upstream.Healthcheck.DomainTmpl,
FallbackAddresses: c.Upstream.FallbackServers,
@@ -331,7 +339,7 @@ func Main() {
Handler: handler,
QueryLog: queryLog,
RuleStat: ruleStat,
- Upstream: c.Upstream.toInternal(),
+ Upstream: upstream,
RateLimit: rateLimiter,
FilteringGroups: fltGroups,
ServerGroups: srvGrps,
diff --git a/internal/cmd/env.go b/internal/cmd/env.go
index 655eadb..fe0f94c 100644
--- a/internal/cmd/env.go
+++ b/internal/cmd/env.go
@@ -17,7 +17,7 @@ import (
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
env "github.com/caarlos0/env/v6"
- "github.com/getsentry/raven-go"
+ "github.com/getsentry/sentry-go"
)
// Environment Configuration
@@ -34,14 +34,15 @@ type environments struct {
YoutubeSafeSearchURL *agdhttp.URL `env:"YOUTUBE_SAFE_SEARCH_URL,notEmpty"`
RuleStatURL *agdhttp.URL `env:"RULESTAT_URL"`
- ConfPath string `env:"CONFIG_PATH" envDefault:"./config.yml"`
- DNSDBPath string `env:"DNSDB_PATH" envDefault:"./dnsdb.bolt"`
- FilterCachePath string `env:"FILTER_CACHE_PATH" envDefault:"./filters/"`
- GeoIPASNPath string `env:"GEOIP_ASN_PATH" envDefault:"./asn.mmdb"`
- GeoIPCountryPath string `env:"GEOIP_COUNTRY_PATH" envDefault:"./country.mmdb"`
- QueryLogPath string `env:"QUERYLOG_PATH" envDefault:"./querylog.jsonl"`
- SentryDSN string `env:"SENTRY_DSN" envDefault:"stderr"`
- SSLKeyLogFile string `env:"SSL_KEY_LOG_FILE"`
+ ConfPath string `env:"CONFIG_PATH" envDefault:"./config.yml"`
+ DNSDBPath string `env:"DNSDB_PATH" envDefault:"./dnsdb.bolt"`
+ FilterCachePath string `env:"FILTER_CACHE_PATH" envDefault:"./filters/"`
+ ProfilesCachePath string `env:"PROFILES_CACHE_PATH" envDefault:"./profilecache.json"`
+ GeoIPASNPath string `env:"GEOIP_ASN_PATH" envDefault:"./asn.mmdb"`
+ GeoIPCountryPath string `env:"GEOIP_COUNTRY_PATH" envDefault:"./country.mmdb"`
+ QueryLogPath string `env:"QUERYLOG_PATH" envDefault:"./querylog.jsonl"`
+ SentryDSN string `env:"SENTRY_DSN" envDefault:"stderr"`
+ SSLKeyLogFile string `env:"SSL_KEY_LOG_FILE"`
ListenAddr net.IP `env:"LISTEN_ADDR" envDefault:"127.0.0.1"`
@@ -83,12 +84,16 @@ func (envs *environments) buildErrColl() (errColl agd.ErrorCollector, err error)
return errcoll.NewWriterErrorCollector(os.Stderr), nil
}
- rc, err := raven.New(dsn)
+ cli, err := sentry.NewClient(sentry.ClientOptions{
+ Dsn: dsn,
+ AttachStacktrace: true,
+ Release: agd.Version(),
+ })
if err != nil {
return nil, err
}
- return errcoll.NewRavenErrorCollector(rc), nil
+ return errcoll.NewSentryErrorCollector(cli), nil
}
// buildDNSDB builds and returns an anonymous statistics collector and its
diff --git a/internal/cmd/filter.go b/internal/cmd/filter.go
index 8698867..00f34bd 100644
--- a/internal/cmd/filter.go
+++ b/internal/cmd/filter.go
@@ -1,10 +1,10 @@
package cmd
import (
- "net"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/timeutil"
@@ -46,7 +46,7 @@ func (c *filtersConfig) toInternal(
YoutubeSafeSearchRulesURL: netutil.CloneURL(&envs.YoutubeSafeSearchURL.URL),
Now: time.Now,
ErrColl: errColl,
- Resolver: net.DefaultResolver,
+ Resolver: agdnet.DefaultResolver{},
CacheDir: envs.FilterCachePath,
CustomFilterCacheSize: c.CustomFilterCacheSize,
// TODO(a.garipov): Consider making this configurable.
diff --git a/internal/cmd/server.go b/internal/cmd/server.go
index e5975f3..76b8666 100644
--- a/internal/cmd/server.go
+++ b/internal/cmd/server.go
@@ -24,12 +24,7 @@ func (srvs servers) toInternal(tlsConfig *agd.TLS) (dnsSrvs []*agd.Server, err e
dnsSrvs = append(dnsSrvs, &agd.Server{
Name: name,
BindAddresses: slices.Clone(srv.BindAddresses),
- Protocol: agd.ProtoDNSTCP,
- LinkedIPEnabled: srv.LinkedIPEnabled,
- }, &agd.Server{
- Name: name,
- BindAddresses: slices.Clone(srv.BindAddresses),
- Protocol: agd.ProtoDNSUDP,
+ Protocol: agd.ProtoDNS,
LinkedIPEnabled: srv.LinkedIPEnabled,
})
case srvProtoDNSCrypt:
@@ -43,13 +38,7 @@ func (srvs servers) toInternal(tlsConfig *agd.TLS) (dnsSrvs []*agd.Server, err e
DNSCrypt: dcConf,
Name: name,
BindAddresses: slices.Clone(srv.BindAddresses),
- Protocol: agd.ProtoDNSCryptTCP,
- LinkedIPEnabled: srv.LinkedIPEnabled,
- }, &agd.Server{
- DNSCrypt: dcConf,
- Name: name,
- BindAddresses: slices.Clone(srv.BindAddresses),
- Protocol: agd.ProtoDNSCryptUDP,
+ Protocol: agd.ProtoDNSCrypt,
LinkedIPEnabled: srv.LinkedIPEnabled,
})
default:
diff --git a/internal/cmd/upstream.go b/internal/cmd/upstream.go
index 19d37f9..7715a16 100644
--- a/internal/cmd/upstream.go
+++ b/internal/cmd/upstream.go
@@ -4,6 +4,8 @@ import (
"context"
"fmt"
"net/netip"
+ "net/url"
+ "strings"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/forward"
@@ -18,8 +20,9 @@ type upstreamConfig struct {
// Healthcheck contains the upstream healthcheck configuration.
Healthcheck *upstreamHealthcheckConfig `yaml:"healthcheck"`
- // Server is the upstream server we're using to forward DNS queries.
- Server netip.AddrPort `yaml:"server"`
+ // Server is the upstream url of the server we're using to forward DNS
+ // queries. It starts with tcp://, udp://, or with an IP address.
+ Server string `yaml:"server"`
// FallbackServers is a list of the DNS servers we're using to fallback to
// when the upstream server fails to respond
@@ -30,13 +33,18 @@ type upstreamConfig struct {
}
// toInternal converts c to the data storage configuration for the DNS server.
-// c is assumed to be valid.
-func (c *upstreamConfig) toInternal() (conf *agd.Upstream) {
+func (c *upstreamConfig) toInternal() (conf *agd.Upstream, err error) {
+ net, addrPort, err := splitUpstreamURL(c.Server)
+ if err != nil {
+ return nil, err
+ }
+
return &agd.Upstream{
- Server: c.Server,
+ Server: addrPort,
+ Network: net,
FallbackServers: c.FallbackServers,
Timeout: c.Timeout.Duration,
- }
+ }, nil
}
// validate returns an error if the upstream configuration is invalid.
@@ -44,7 +52,7 @@ func (c *upstreamConfig) validate() (err error) {
switch {
case c == nil:
return errNilConfig
- case c.Server == netip.AddrPort{}:
+ case c.Server == "":
return errors.Error("no server")
case len(c.FallbackServers) == 0:
return errors.Error("no fallback")
@@ -61,6 +69,37 @@ func (c *upstreamConfig) validate() (err error) {
return errors.Annotate(c.Healthcheck.validate(), "healthcheck: %w")
}
+// splitUpstreamURL separates server url to net protocol and port address.
+func splitUpstreamURL(raw string) (upsNet forward.Network, addrPort netip.AddrPort, err error) {
+ addr := raw
+ upsNet = forward.NetworkAny
+
+ if strings.Contains(raw, "://") {
+ var u *url.URL
+ u, err = url.Parse(raw)
+ if err != nil {
+ return upsNet, addrPort, fmt.Errorf("bad server url: %q: %w", raw, err)
+ }
+
+ addr = u.Host
+ upsNet = forward.Network(u.Scheme)
+
+ switch upsNet {
+ case forward.NetworkTCP, forward.NetworkUDP:
+ // Go on.
+ break
+ default:
+ return upsNet, addrPort, fmt.Errorf("bad server protocol: %q", u.Scheme)
+ }
+ }
+
+ if addrPort, err = netip.ParseAddrPort(addr); err != nil {
+ return upsNet, addrPort, fmt.Errorf("bad server address: %q", addr)
+ }
+
+ return upsNet, addrPort, nil
+}
+
// upstreamHealthcheckConfig is the configuration for the upstream healthcheck
// feature.
type upstreamHealthcheckConfig struct {
diff --git a/internal/consul/allowlist_test.go b/internal/consul/allowlist_test.go
index 1afc9be..6a5e69c 100644
--- a/internal/consul/allowlist_test.go
+++ b/internal/consul/allowlist_test.go
@@ -9,7 +9,6 @@ import (
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/consul"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
"github.com/AdguardTeam/golibs/testutil"
@@ -18,7 +17,7 @@ import (
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
// handleWithURL starts the test server with h, finishes it on cleanup, and
diff --git a/internal/debugsvc/debugsvc_test.go b/internal/debugsvc/debugsvc_test.go
index 8e4e112..6f1ac89 100644
--- a/internal/debugsvc/debugsvc_test.go
+++ b/internal/debugsvc/debugsvc_test.go
@@ -8,7 +8,6 @@ import (
"testing"
"time"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/debugsvc"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
@@ -16,7 +15,7 @@ import (
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
func TestService_Start(t *testing.T) {
diff --git a/internal/dnscheck/consul.go b/internal/dnscheck/consul.go
index 44c8148..9ed2a41 100644
--- a/internal/dnscheck/consul.go
+++ b/internal/dnscheck/consul.go
@@ -160,7 +160,7 @@ func (cc *Consul) Check(
qt := ri.QType
if qt != dns.TypeA && qt != dns.TypeAAAA {
- return nil, nil
+ return ri.Messages.NewMsgNODATA(req), nil
}
var randomID string
diff --git a/internal/dnscheck/consul_test.go b/internal/dnscheck/consul_test.go
index 54b6d38..8118083 100644
--- a/internal/dnscheck/consul_test.go
+++ b/internal/dnscheck/consul_test.go
@@ -87,7 +87,7 @@ func TestConsul_ServeHTTP(t *testing.T) {
"profile_id": "some-profile-id",
"server_group_name": "some-server-group-name",
"server_name": "some-server-name",
- "protocol": agd.ProtoDNSUDP.String(),
+ "protocol": agd.ProtoDNS.String(),
"node_location": "some-node-location",
"node_name": "some-node-name",
"client_ip": "1.2.3.4",
@@ -109,7 +109,7 @@ func TestConsul_ServeHTTP(t *testing.T) {
ctx := context.Background()
ctx = dnsserver.ContextWithServerInfo(ctx, dnsserver.ServerInfo{
Name: theOnlyVal["server_name"].(string),
- Proto: agd.ProtoDNSUDP,
+ Proto: agd.ProtoDNS,
})
var resp *dns.Msg
diff --git a/internal/dnscheck/dnscheck_test.go b/internal/dnscheck/dnscheck_test.go
index 1aee197..f32cf9a 100644
--- a/internal/dnscheck/dnscheck_test.go
+++ b/internal/dnscheck/dnscheck_test.go
@@ -4,11 +4,11 @@ import (
"net/netip"
"testing"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/golibs/testutil"
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
// Test data.
diff --git a/internal/dnscheck/httpkv_test.go b/internal/dnscheck/httpkv_test.go
index 2a83095..82923f8 100644
--- a/internal/dnscheck/httpkv_test.go
+++ b/internal/dnscheck/httpkv_test.go
@@ -71,6 +71,8 @@ func (db *testKV) get(rw http.ResponseWriter, r *http.Request) {
return
}
+ // TODO(a.garipov): Consider making testutil.RequireTypeAssert accept
+ // testutil.PanicT.
require.IsType(pt, ([]byte)(nil), v)
val := v.([]byte)
@@ -152,7 +154,7 @@ func TestHTTPKV(t *testing.T) {
ctx := context.Background()
ctx = dnsserver.ContextWithServerInfo(ctx, dnsserver.ServerInfo{
- Proto: agd.ProtoDNSUDP,
+ Proto: agd.ProtoDNS,
})
req := dnsservertest.CreateMessage(randomid+"-"+localDomain, dns.TypeA)
@@ -176,7 +178,7 @@ func TestHTTPKV(t *testing.T) {
"profile_id": "some-profile-id",
"server_group_name": "some-server-group-name",
"server_name": "some-server-name",
- "protocol": agd.ProtoDNSUDP.String(),
+ "protocol": agd.ProtoDNS.String(),
"node_location": "some-node-location",
"node_name": "some-node-name",
"client_ip": "1.2.3.4",
diff --git a/internal/dnsdb/dnsdb_test.go b/internal/dnsdb/dnsdb_test.go
index 5d12d51..5f4d60b 100644
--- a/internal/dnsdb/dnsdb_test.go
+++ b/internal/dnsdb/dnsdb_test.go
@@ -3,9 +3,9 @@ package dnsdb_test
import (
"testing"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/golibs/testutil"
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
diff --git a/internal/dnsmsg/constructor.go b/internal/dnsmsg/constructor.go
index dcf0bdd..2a53d6b 100644
--- a/internal/dnsmsg/constructor.go
+++ b/internal/dnsmsg/constructor.go
@@ -72,6 +72,13 @@ func (c *Constructor) NewMsgSERVFAIL(req *dns.Msg) (resp *dns.Msg) {
return c.newMsgRCode(req, dns.RcodeServerFailure)
}
+// NewMsgNODATA returns a properly initialized NODATA response.
+//
+// See https://www.rfc-editor.org/rfc/rfc2308#section-2.2.
+func (c *Constructor) NewMsgNODATA(req *dns.Msg) (resp *dns.Msg) {
+ return c.newMsgRCode(req, dns.RcodeSuccess)
+}
+
// newMsgRCode returns a properly initialized response with the given RCode.
func (c *Constructor) newMsgRCode(req *dns.Msg, rc RCode) (resp *dns.Msg) {
resp = (&dns.Msg{}).SetRcode(req, int(rc))
diff --git a/internal/dnsmsg/constructor_test.go b/internal/dnsmsg/constructor_test.go
index 0d24a5b..c6e378b 100644
--- a/internal/dnsmsg/constructor_test.go
+++ b/internal/dnsmsg/constructor_test.go
@@ -102,6 +102,10 @@ func TestConstructor_noAnswerMethods(t *testing.T) {
method: mc.NewMsgSERVFAIL,
name: "servfail",
want: dns.RcodeServerFailure,
+ }, {
+ method: mc.NewMsgNODATA,
+ name: "nodata",
+ want: dns.RcodeSuccess,
}}
for _, tc := range testCases {
diff --git a/internal/dnsmsg/dnsmsg.go b/internal/dnsmsg/dnsmsg.go
index 690939f..aa85424 100644
--- a/internal/dnsmsg/dnsmsg.go
+++ b/internal/dnsmsg/dnsmsg.go
@@ -8,7 +8,7 @@ import (
"fmt"
"net/netip"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
)
@@ -107,12 +107,12 @@ func ECSFromMsg(msg *dns.Msg) (subnet netip.Prefix, scope uint8, err error) {
// option. It returns an error if esn does not contain valid, RFC-compliant
// EDNS Client Subnet information or the address family is unsupported.
func ecsData(esn *dns.EDNS0_SUBNET) (subnet netip.Prefix, scope uint8, err error) {
- fam := agdnet.AddrFamily(esn.Family)
- if fam != agdnet.AddrFamilyIPv4 && fam != agdnet.AddrFamilyIPv6 {
+ fam := netutil.AddrFamily(esn.Family)
+ if fam != netutil.AddrFamilyIPv4 && fam != netutil.AddrFamilyIPv6 {
return netip.Prefix{}, 0, fmt.Errorf("unsupported addr family number %d", fam)
}
- ip, err := agdnet.IPToAddr(esn.Address, fam)
+ ip, err := netutil.IPToAddr(esn.Address, fam)
if err != nil {
return netip.Prefix{}, 0, fmt.Errorf("bad ecs ip addr: %w", err)
}
diff --git a/internal/dnsmsg/dnsmsg_test.go b/internal/dnsmsg/dnsmsg_test.go
index 934cc08..06be934 100644
--- a/internal/dnsmsg/dnsmsg_test.go
+++ b/internal/dnsmsg/dnsmsg_test.go
@@ -7,17 +7,16 @@ import (
"testing"
"time"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
// testFltRespTTL is the common filtered response TTL.
@@ -32,12 +31,12 @@ const (
)
// newECSExtraMsg is a helper constructor for ECS messages.
-func newECSExtraMsg(ip netip.Addr, ecsFam agdnet.AddrFamily, mask uint8) (msg *dns.Msg) {
+func newECSExtraMsg(ip netip.Addr, ecsFam netutil.AddrFamily, mask uint8) (msg *dns.Msg) {
var scope uint8
switch ecsFam {
- case agdnet.AddrFamilyIPv4:
+ case netutil.AddrFamilyIPv4:
scope = ipv4Scope
- case agdnet.AddrFamilyIPv6:
+ case netutil.AddrFamilyIPv6:
scope = ipv6Scope
default:
panic(fmt.Errorf("unsupported ecs addr fam %s", ecsFam))
@@ -108,49 +107,49 @@ func TestECSFromMsg(t *testing.T) {
wantErrMsg: "",
wantScope: 0,
}, {
- msg: newECSExtraMsg(ipv4Net.Addr(), agdnet.AddrFamilyIPv4, ipv4MaskBits),
+ msg: newECSExtraMsg(ipv4Net.Addr(), netutil.AddrFamilyIPv4, ipv4MaskBits),
wantECS: ipv4Net,
name: "ecs_ipv4",
wantErrMsg: "",
wantScope: ipv4Scope,
}, {
- msg: newECSExtraMsg(ipv4Net.Addr(), agdnet.AddrFamilyIPv4, 0),
+ msg: newECSExtraMsg(ipv4Net.Addr(), netutil.AddrFamilyIPv4, 0),
wantECS: netip.Prefix{},
name: "ecs_ipv4_zero_mask_addr",
wantErrMsg: "bad ecs: ip 1.2.3.0 has non-zero bits beyond prefix 0",
wantScope: 0,
}, {
- msg: newECSExtraMsg(netip.IPv4Unspecified(), agdnet.AddrFamilyIPv4, 0),
+ msg: newECSExtraMsg(netip.IPv4Unspecified(), netutil.AddrFamilyIPv4, 0),
wantECS: netip.PrefixFrom(netip.IPv4Unspecified(), 0),
name: "ecs_ipv4_zero",
wantErrMsg: "",
wantScope: ipv4Scope,
}, {
- msg: newECSExtraMsg(ipv4Net.Addr(), agdnet.AddrFamilyIPv4, 1),
+ msg: newECSExtraMsg(ipv4Net.Addr(), netutil.AddrFamilyIPv4, 1),
wantECS: netip.Prefix{},
name: "ecs_ipv4_bad_ones",
wantErrMsg: "bad ecs: ip 1.2.3.0 has non-zero bits beyond prefix 1",
wantScope: 0,
}, {
- msg: newECSExtraMsg(ipv4Net.Addr(), agdnet.AddrFamilyIPv4, math.MaxUint8),
+ msg: newECSExtraMsg(ipv4Net.Addr(), netutil.AddrFamilyIPv4, math.MaxUint8),
wantECS: netip.Prefix{},
name: "ecs_ipv4_bad_too_much",
wantErrMsg: "bad ecs: bad src netmask 255 for addr family ipv4",
wantScope: 0,
}, {
- msg: newECSExtraMsg(ipv6Net.Addr(), agdnet.AddrFamilyIPv6, ipv6MaskBits),
+ msg: newECSExtraMsg(ipv6Net.Addr(), netutil.AddrFamilyIPv6, ipv6MaskBits),
wantECS: ipv6Net,
name: "ecs_ipv6",
wantErrMsg: "",
wantScope: ipv6Scope,
}, {
- msg: newECSExtraMsg(ipv6Net.Addr(), agdnet.AddrFamilyIPv6, 1),
+ msg: newECSExtraMsg(ipv6Net.Addr(), netutil.AddrFamilyIPv6, 1),
wantECS: netip.Prefix{},
name: "ecs_ipv6_bad_ones",
wantErrMsg: "bad ecs: ip 2001:0:102:304:: has non-zero bits beyond prefix 1",
wantScope: 0,
}, {
- msg: newECSExtraMsg(ipv6Net.Addr(), agdnet.AddrFamilyIPv6, math.MaxUint8),
+ msg: newECSExtraMsg(ipv6Net.Addr(), netutil.AddrFamilyIPv6, math.MaxUint8),
wantECS: netip.Prefix{},
name: "ecs_ipv6_bad_too_much",
wantErrMsg: "bad ecs: bad src netmask 255 for addr family ipv6",
diff --git a/internal/dnsmsg/svcbmsg_test.go b/internal/dnsmsg/svcbmsg_test.go
index 1f7598d..b99237f 100644
--- a/internal/dnsmsg/svcbmsg_test.go
+++ b/internal/dnsmsg/svcbmsg_test.go
@@ -254,10 +254,8 @@ func TestConstructor_NewDDR(t *testing.T) {
}
for _, unsupProto := range []dnsserver.Protocol{
- dnsserver.ProtoDNSTCP,
- dnsserver.ProtoDNSUDP,
- dnsserver.ProtoDNSCryptTCP,
- dnsserver.ProtoDNSCryptUDP,
+ dnsserver.ProtoDNS,
+ dnsserver.ProtoDNSCrypt,
} {
t.Run(unsupProto.String(), func(t *testing.T) {
assert.Panics(t, func() {
diff --git a/internal/dnsserver/context.go b/internal/dnsserver/context.go
index c3fd244..b935638 100644
--- a/internal/dnsserver/context.go
+++ b/internal/dnsserver/context.go
@@ -13,8 +13,7 @@ type ctxKey int
const (
ctxKeyServerInfo ctxKey = iota
ctxKeyStartTime
- ctxKeyRequestSize
- ctxKeyResponseSize
+ ctxKeyRequestInfo
ctxKeyClientInfo
)
@@ -76,27 +75,38 @@ func MustStartTimeFromContext(ctx context.Context) (t time.Time) {
return st
}
-// ContextWithRequestSize attaches request's size to the specified context.
-func ContextWithRequestSize(parent context.Context, size int) (ctx context.Context) {
- return context.WithValue(parent, ctxKeyRequestSize, size)
+// RequestInfo is a structure that contains basic request information. It is
+// attached to every context.Context linked to processing a DNS request.
+type RequestInfo struct {
+ // RequestSize is the size of a DNS request in bytes.
+ RequestSize int
+
+ // ResponseSize is the size of a DNS response in bytes. May be 0 if no
+ // response was sent.
+ ResponseSize int
}
-// RequestSizeFromContext gets request's size from the context.
-func RequestSizeFromContext(ctx context.Context) (size int, found bool) {
- size, found = ctx.Value(ctxKeyRequestSize).(int)
-
- return size, found
+// ContextWithRequestInfo attaches RequestInfo to the specified context.
+func ContextWithRequestInfo(parent context.Context, ri RequestInfo) (ctx context.Context) {
+ return context.WithValue(parent, ctxKeyRequestInfo, ri)
}
-// ContextWithResponseSize attaches response's size to the specified context.
-func ContextWithResponseSize(parent context.Context, size int) (ctx context.Context) {
- return context.WithValue(parent, ctxKeyResponseSize, size)
+// RequestInfoFromContext gets RequestInfo from the specified context.
+func RequestInfoFromContext(ctx context.Context) (ri RequestInfo, found bool) {
+ ri, found = ctx.Value(ctxKeyRequestInfo).(RequestInfo)
+
+ return ri, found
}
-// ResponseSizeFromContext gets response's size from the context.
-func ResponseSizeFromContext(ctx context.Context) (size int, found bool) {
- size, found = ctx.Value(ctxKeyResponseSize).(int)
- return size, found
+// MustRequestInfoFromContext gets RequestInfo attached to the context and
+// panics if it is not found.
+func MustRequestInfoFromContext(ctx context.Context) (ri RequestInfo) {
+ ri, found := RequestInfoFromContext(ctx)
+ if !found {
+ panic("request info not found in the context")
+ }
+
+ return ri
}
// ClientInfo is a structure that contains basic information about the client.
@@ -105,9 +115,12 @@ type ClientInfo struct {
// URL is the request URL. It is set only if the protocol of the
// server is DoH.
URL *url.URL
+
// TLSServerName is the server name field of the client's TLS hello
// request. It is set only if the protocol of the server is either DoQ
- // or DoT. Note, that the original SNI is transformed to lower-case.
+ // or DoT or DoH. Note, that the original SNI is transformed to lower-case.
+ //
+ // TODO(ameshkov): use r.TLS with DoH3 (see httpContextWithClientInfo).
TLSServerName string
}
diff --git a/internal/dnsserver/context_test.go b/internal/dnsserver/context_test.go
index 6f5a979..981cbc3 100644
--- a/internal/dnsserver/context_test.go
+++ b/internal/dnsserver/context_test.go
@@ -17,7 +17,7 @@ func TestServerInfoFromContext(t *testing.T) {
serverInfo := dnsserver.ServerInfo{
Name: "test",
Addr: "127.0.0.1",
- Proto: dnsserver.ProtoDNSUDP,
+ Proto: dnsserver.ProtoDNS,
}
ctx = dnsserver.ContextWithServerInfo(ctx, serverInfo)
diff --git a/internal/dnsserver/dnsserver.go b/internal/dnsserver/dnsserver.go
index c71835f..5ef5883 100644
--- a/internal/dnsserver/dnsserver.go
+++ b/internal/dnsserver/dnsserver.go
@@ -20,17 +20,18 @@ type Handler interface {
// specified ResponseWriter.
//
// It accepts context.Context argument which has some additional info
- // attached to it. This context always contains ServerInfo which can be
+ // attached to it. This context always contains ServerInfo which can be
// retrieved using ServerInfoFromContext or MustServerInfoFromContext.
// Also, it always contains request's start time that can be retrieved
- // using StartTimeFromContext.
- ServeDNS(context.Context, ResponseWriter, *dns.Msg) error
+ // using StartTimeFromContext. Finally, it also must contain ClientInfo
+ // that can be retrieved using MustClientInfoFromContext.
+ ServeDNS(context.Context, ResponseWriter, *dns.Msg) (err error)
}
// The HandlerFunc type is an adapter to allow the use of ordinary functions
// as DNS handlers. If f is a function with the appropriate signature,
// HandlerFunc(f) is a Handler that calls f.
-type HandlerFunc func(context.Context, ResponseWriter, *dns.Msg) error
+type HandlerFunc func(context.Context, ResponseWriter, *dns.Msg) (err error)
// ServeDNS implements the Handler interface for HandlerFunc.
func (f HandlerFunc) ServeDNS(ctx context.Context, rw ResponseWriter, req *dns.Msg) (err error) {
@@ -50,15 +51,34 @@ var notImplementedHandlerFunc HandlerFunc = func(
}
// Server represents a DNS server.
+//
+// TODO(ameshkov): move validation to ctors (for all structs that inherit this).
+//
+// TODO(ameshkov): consider Proto()/Network()/Addr() -> single Info() func.
type Server interface {
+ // Name returns the server name.
+ Name() (name string)
+ // Proto returns the protocol of the server.
+ Proto() (proto Protocol)
+ // Network is a network (tcp, udp or empty) this server listens to. If it
+ // is empty, the server listens to all networks that are supposed to be
+ // used by its protocol.
+ Network() (network Network)
+ // Addr returns the address the server was configured to listen to.
+ Addr() (addr string)
// Start starts the server, exits immediately if it failed to start
// listening. Start returns once all servers are considered up.
Start(ctx context.Context) (err error)
// Shutdown stops the server and waits for all active connections to close.
Shutdown(ctx context.Context) (err error)
- // LocalAddr returns the address the server listens to at the moment. It
- // must be safe for concurrent use.
- LocalAddr() (lAddr net.Addr)
+ // LocalTCPAddr returns the TCP address the server listens to at the moment
+ // or nil if it does not listen to TCP. Depending on the server protocol
+ // it may correspond to DNS-over-TCP, DNS-over-TLS, HTTP2, DNSCrypt (TCP).
+ LocalTCPAddr() (addr net.Addr)
+ // LocalUDPAddr returns the UDP address the server listens to at the moment or
+ // nil if it does not listen to UDP. Depending on the server protocol
+ // it may correspond to DNS-over-UDP, HTTP3, QUIC, DNSCrypt (UDP).
+ LocalUDPAddr() (addr net.Addr)
}
// A ResponseWriter interface is used by a DNS handler to construct a DNS
diff --git a/internal/dnsserver/dnsserver_test.go b/internal/dnsserver/dnsserver_test.go
index 60f5db1..99698d2 100644
--- a/internal/dnsserver/dnsserver_test.go
+++ b/internal/dnsserver/dnsserver_test.go
@@ -3,9 +3,9 @@ package dnsserver_test
import (
"testing"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
+ "github.com/AdguardTeam/golibs/testutil"
)
func TestMain(m *testing.M) {
- dnsservertest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
diff --git a/internal/dnsserver/dnsservertest/dnsservertest.go b/internal/dnsserver/dnsservertest/dnsservertest.go
index 8282a3a..1a77b8b 100644
--- a/internal/dnsserver/dnsservertest/dnsservertest.go
+++ b/internal/dnsserver/dnsservertest/dnsservertest.go
@@ -1,18 +1,3 @@
// Package dnsservertest provides convenient helper functions for unit-tests
// in packages related to dnsserver.
package dnsservertest
-
-import (
- "io"
- "os"
- "testing"
-
- "github.com/AdguardTeam/golibs/log"
-)
-
-// DiscardLogOutput runs tests with discarded logger's output.
-func DiscardLogOutput(m *testing.M) {
- log.SetOutput(io.Discard)
-
- os.Exit(m.Run())
-}
diff --git a/internal/dnsserver/dnsservertest/error_unix.go b/internal/dnsserver/dnsservertest/error_unix.go
new file mode 100644
index 0000000..89b83c2
--- /dev/null
+++ b/internal/dnsserver/dnsservertest/error_unix.go
@@ -0,0 +1,13 @@
+//go:build unix
+
+package dnsservertest
+
+import (
+ "github.com/AdguardTeam/golibs/errors"
+ "golang.org/x/sys/unix"
+)
+
+// errorIsAddrInUse returns true if err is an address already in use error.
+func errorIsAddrInUse(err error) (ok bool) {
+ return errors.Is(err, unix.EADDRINUSE)
+}
diff --git a/internal/dnsserver/dnsservertest/error_windows.go b/internal/dnsserver/dnsservertest/error_windows.go
new file mode 100644
index 0000000..9a65456
--- /dev/null
+++ b/internal/dnsserver/dnsservertest/error_windows.go
@@ -0,0 +1,13 @@
+//go:build windows
+
+package dnsservertest
+
+import (
+ "github.com/AdguardTeam/golibs/errors"
+ "golang.org/x/sys/windows"
+)
+
+// errorIsAddrInUse returns true if err is an address already in use error.
+func errorIsAddrInUse(err error) (ok bool) {
+ return errors.Is(err, windows.WSAEADDRINUSE)
+}
diff --git a/internal/dnsserver/dnsservertest/handler.go b/internal/dnsserver/dnsservertest/handler.go
index 6d2e300..3f5a67f 100644
--- a/internal/dnsserver/dnsservertest/handler.go
+++ b/internal/dnsserver/dnsservertest/handler.go
@@ -5,12 +5,21 @@ import (
"net"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/miekg/dns"
)
-// CreateTestHandler creates a dnsserver.Handler with the specified parameters.
+// CreateTestHandler creates a [dnsserver.Handler] with the specified parameters.
func CreateTestHandler(recordsCount int) (h dnsserver.Handler) {
f := func(ctx context.Context, rw dnsserver.ResponseWriter, req *dns.Msg) (err error) {
+ // Check that necessary context keys are set.
+ si := dnsserver.MustServerInfoFromContext(ctx)
+ _ = dnsserver.MustStartTimeFromContext(ctx)
+ ci := dnsserver.MustClientInfoFromContext(ctx)
+ if si.Proto.IsStdEncrypted() && ci.TLSServerName == "" {
+ return errors.Error("client info does not contain server name")
+ }
+
hostname := req.Question[0].Name
resp := &dns.Msg{
diff --git a/internal/dnsserver/dnsservertest/server.go b/internal/dnsserver/dnsservertest/server.go
index 6a0a7e0..38af5b1 100644
--- a/internal/dnsserver/dnsservertest/server.go
+++ b/internal/dnsserver/dnsservertest/server.go
@@ -7,128 +7,78 @@ import (
"fmt"
"net"
"net/http"
+ "testing"
+ "time"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/ameshkov/dnscrypt/v2"
+ "github.com/stretchr/testify/require"
)
-// RunLocalDNSServer runs a simple test server with the specified handler. addr
-// is the address that can be used to reach that server.
-func RunLocalDNSServer(
- h dnsserver.Handler,
- proto dnsserver.Protocol,
-) (s *dnsserver.ServerDNS, addr string, err error) {
+// RunDNSServer runs a simple test server with the specified handler for the
+// duration of the test. It also registers a cleanup function that stops the
+// server. addr is the address that can be used to reach that server.
+//
+// TODO(a.garipov): s seems to only be used for LocalUDPAddr. Perhaps, only
+// return it?
+func RunDNSServer(t testing.TB, h dnsserver.Handler) (s *dnsserver.ServerDNS, addr string) {
+ t.Helper()
+
conf := dnsserver.ConfigDNS{
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Proto: proto,
Handler: h,
},
}
s = dnsserver.NewServerDNS(conf)
+ require.Equal(t, dnsserver.ProtoDNS, s.Proto())
- err = s.Start(context.Background())
- if err != nil {
- return nil, "", err
+ err := runWithRetry(func() error { return s.Start(context.Background()) })
+ require.NoError(t, err)
+
+ testutil.CleanupAndRequireSuccess(t, func() (err error) {
+ return s.Shutdown(context.Background())
+ })
+
+ localAddr := s.LocalTCPAddr()
+ if localAddr == nil {
+ localAddr = s.LocalUDPAddr()
}
- return s, s.LocalAddr().String(), nil
+ return s, localAddr.String()
}
-// DNSServer represents a plain DNS server that listens to both TCP and UDP.
-type DNSServer struct {
- Addr string
- SrvTCP *dnsserver.ServerDNS
- SrvUDP *dnsserver.ServerDNS
-}
+// RunTLSServer runs a simple test server with the specified handler for the
+// duration of the test. It also registers a cleanup function that stops the
+// server. addr is the address that can be used to reach that server.
+func RunTLSServer(t testing.TB, h dnsserver.Handler, tlsConfig *tls.Config) (addr *net.TCPAddr) {
+ t.Helper()
-// Shutdown stops both servers
-func (s *DNSServer) Shutdown(ctx context.Context) (err error) {
- err = s.SrvUDP.Shutdown(ctx)
- if err != nil {
- return err
- }
- return s.SrvTCP.Shutdown(ctx)
-}
-
-// RunDNSServer runs a test DNS server with the specified handler. Actually, it
-// runs two DNS servers, one with dnsserver.ProtoDNSUDP and the other one with
-// dnsserver.ProtoDNSTCP, both of which use the same port.
-func RunDNSServer(h dnsserver.Handler) (s *DNSServer, err error) {
- s = &DNSServer{}
-
- // First let's run the TCP server
- conf := dnsserver.ConfigDNS{
- ConfigBase: dnsserver.ConfigBase{
- Name: "test_tcp",
- Addr: "127.0.0.1:0",
- Proto: dnsserver.ProtoDNSTCP,
- Handler: h,
- },
- }
- s.SrvTCP = dnsserver.NewServerDNS(conf)
- err = s.SrvTCP.Start(context.Background())
- if err != nil {
- return nil, err
- }
-
- // Now let's get the port that it uses
- port := s.SrvTCP.LocalAddr().(*net.TCPAddr).Port
- s.Addr = fmt.Sprintf("127.0.0.1:%d", port)
-
- // Now we can run the UDP server
- conf = dnsserver.ConfigDNS{
- ConfigBase: dnsserver.ConfigBase{
- Name: "test_udp",
- Addr: s.Addr,
- Proto: dnsserver.ProtoDNSUDP,
- Handler: h,
- },
- }
- s.SrvUDP = dnsserver.NewServerDNS(conf)
- err = s.SrvUDP.Start(context.Background())
- if err != nil {
- return nil, err
- }
-
- return s, nil
-}
-
-// RunLocalTLSServer runs a simple test server with the specified handler
-// returns the address that can be used to reach that server
-func RunLocalTLSServer(
- h dnsserver.Handler,
- tlsConfig *tls.Config,
-) (s *dnsserver.ServerTLS, addr *net.TCPAddr, err error) {
conf := dnsserver.ConfigTLS{
ConfigDNS: dnsserver.ConfigDNS{
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Proto: dnsserver.ProtoDoT,
Handler: h,
},
},
TLSConfig: tlsConfig,
}
- s = dnsserver.NewServerTLS(conf)
- if s.Proto() != dnsserver.ProtoDoT {
- return nil, nil, errors.Error("invalid protocol")
- }
- err = s.Start(context.Background())
- if err != nil {
- return nil, nil, err
- }
+ s := dnsserver.NewServerTLS(conf)
+ require.Equal(t, dnsserver.ProtoDoT, s.Proto())
- addr, ok := s.LocalAddr().(*net.TCPAddr)
- if !ok {
- return nil, nil, fmt.Errorf("invalid listen addr: %s", addr)
- }
+ err := runWithRetry(func() error { return s.Start(context.Background()) })
+ require.NoError(t, err)
- return s, addr, nil
+ testutil.CleanupAndRequireSuccess(t, func() (err error) {
+ return s.Shutdown(context.Background())
+ })
+
+ return testutil.RequireTypeAssert[*net.TCPAddr](t, s.LocalTCPAddr())
}
// TestDNSCryptServer is a structure that contains the initialized DNSCrypt
@@ -136,98 +86,82 @@ func RunLocalTLSServer(
type TestDNSCryptServer struct {
Srv *dnsserver.ServerDNSCrypt
ProviderName string
- ResolverPk ed25519.PublicKey
ServerAddr string
+ ResolverPk ed25519.PublicKey
}
-// RunLocalDNSCryptServer runs a simple test DNSCrypt server with the specified
-// handler. Returns the address that can be used to reach that server.
-func RunLocalDNSCryptServer(
- h dnsserver.Handler,
- network dnsserver.Network,
-) (s *TestDNSCryptServer, err error) {
+// RunDNSCryptServer runs a simple test DNSCrypt server with the specified
+// handler for the duration of the test. It also registers a cleanup function
+// that stops the server.
+func RunDNSCryptServer(t testing.TB, h dnsserver.Handler) (s *TestDNSCryptServer) {
+ t.Helper()
+
s = &TestDNSCryptServer{
ProviderName: "example.org",
}
// Generate DNSCrypt configuration for the server
- var rc dnscrypt.ResolverConfig
- rc, err = dnscrypt.GenerateResolverConfig(s.ProviderName, nil)
- if err != nil {
- return nil, err
- }
- var cert *dnscrypt.Cert
- cert, err = rc.CreateCert()
- if err != nil {
- return nil, err
- }
+ rc, err := dnscrypt.GenerateResolverConfig(s.ProviderName, nil)
+ require.NoError(t, err)
+
+ cert, err := rc.CreateCert()
+ require.NoError(t, err)
// Extract the public key (we'll use it for the dnscrypt.Client)
var privateKey []byte
privateKey, err = dnscrypt.HexDecodeKey(rc.PrivateKey)
- if err != nil {
- return nil, err
- }
- resolverPk, ok := ed25519.PrivateKey(privateKey).Public().(ed25519.PublicKey)
- if !ok {
- return nil, errors.Error("could not create a private key")
- }
- s.ResolverPk = resolverPk
+ require.NoError(t, err)
- proto := dnsserver.ProtoDNSCryptUDP
- if network != dnsserver.NetworkUDP {
- proto = dnsserver.ProtoDNSCryptTCP
- }
+ pk := ed25519.PrivateKey(privateKey).Public()
+
+ s.ResolverPk = testutil.RequireTypeAssert[ed25519.PublicKey](t, pk)
conf := dnsserver.ConfigDNSCrypt{
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Proto: proto,
Handler: h,
},
DNSCryptProviderName: s.ProviderName,
DNSCryptResolverCert: cert,
}
- // Create a new ServerDNSCrypt and run it
+ // Create a new ServerDNSCrypt and run it.
s.Srv = dnsserver.NewServerDNSCrypt(conf)
- err = s.Srv.Start(context.Background())
- if err != nil {
- return nil, err
- }
+ require.Equal(t, dnsserver.ProtoDNSCrypt, s.Srv.Proto())
- // Get the address it listens to
- addr := s.Srv.LocalAddr()
- if addr == nil {
- return nil, errors.Error("wrong address")
- }
+ err = runWithRetry(func() error { return s.Srv.Start(context.Background()) })
+ require.NoError(t, err)
- switch v := addr.(type) {
- case *net.UDPAddr:
- s.ServerAddr = fmt.Sprintf("127.0.0.1:%d", v.Port)
- case *net.TCPAddr:
- s.ServerAddr = fmt.Sprintf("127.0.0.1:%d", v.Port)
- default:
- return nil, fmt.Errorf("wrong address %v", addr)
- }
+ testutil.CleanupAndRequireSuccess(t, func() (err error) {
+ return s.Srv.Shutdown(context.Background())
+ })
- return s, nil
+ // Get the address it listens to. It does not matter which one will be
+ // used (UDP or TCP) since we need it in the string format.
+ s.ServerAddr = s.Srv.LocalUDPAddr().String()
+
+ return s
}
-// RunLocalHTTPSServer runs a simple test HTTP server with the specified handler.
-// addr is the address that can be used to reach that server.
+// RunLocalHTTPSServer runs a simple test HTTP server with the specified
+// handler. addr is the address that can be used to reach that server.
func RunLocalHTTPSServer(
h dnsserver.Handler,
tlsConfig *tls.Config,
nonDNSHandler http.Handler,
-) (s *dnsserver.ServerHTTPS, addr *net.TCPAddr, err error) {
+) (s *dnsserver.ServerHTTPS, err error) {
+ network := dnsserver.NetworkAny
+ if tlsConfig == nil {
+ network = dnsserver.NetworkTCP
+ }
+
conf := dnsserver.ConfigHTTPS{
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Proto: dnsserver.ProtoDoH,
Handler: h,
+ Network: network,
},
TLSConfig: tlsConfig,
NonDNSHandler: nonDNSHandler,
@@ -235,21 +169,15 @@ func RunLocalHTTPSServer(
s = dnsserver.NewServerHTTPS(conf)
if s.Proto() != dnsserver.ProtoDoH {
- return nil, nil, errors.Error("invalid protocol")
+ return nil, errors.Error("invalid protocol")
}
err = s.Start(context.Background())
if err != nil {
- return nil, nil, err
+ return nil, err
}
- var ok bool
- addr, ok = s.LocalAddr().(*net.TCPAddr)
- if !ok {
- return nil, nil, fmt.Errorf("invalid listen addr: %s", addr)
- }
-
- return s, addr, nil
+ return s, nil
}
// RunLocalQUICServer runs a simple test HTTP server with the specified handler.
@@ -262,7 +190,6 @@ func RunLocalQUICServer(
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Proto: dnsserver.ProtoDoQ,
Handler: h,
},
TLSConfig: tlsConfig,
@@ -278,10 +205,29 @@ func RunLocalQUICServer(
return nil, nil, err
}
- addr, ok := s.LocalAddr().(*net.UDPAddr)
+ addr, ok := s.LocalUDPAddr().(*net.UDPAddr)
if !ok {
return nil, nil, fmt.Errorf("invalid listen addr: %s", addr)
}
return s, addr, nil
}
+
+// runWithRetry runs exec func and retries in case of address already in use
+// error.
+func runWithRetry(exec func() error) (err error) {
+ err = exec()
+ if err != nil {
+ if errorIsAddrInUse(err) {
+ // Give system time to release sockets.
+ time.Sleep(200 * time.Millisecond)
+
+ err = exec()
+ if err != nil {
+ err = fmt.Errorf("after one retry: %w", err)
+ }
+ }
+ }
+
+ return err
+}
diff --git a/internal/dnsserver/doc.go b/internal/dnsserver/doc.go
index 330bbfb..e9070a4 100644
--- a/internal/dnsserver/doc.go
+++ b/internal/dnsserver/doc.go
@@ -44,8 +44,9 @@ Alternatively, you can use forward.NewHandler to create a DNS forwarding handler
# Plain DNS
-Plain DNS server may use either TCP or UDP protocols. Here's how to create a
-simple plain DNS server:
+By default, plain DNS server will listen to both TCP and UDP unless Network
+is specified in the configuration. Here's how to create a simple plain
+DNS server:
conf := dnsserver.ConfigDNS{
ConfigBase: dnsserver.ConfigBase{
@@ -53,8 +54,6 @@ simple plain DNS server:
Name: "test",
// listen address
Addr: "127.0.0.1:0",
- // protocol (ProtoDNSUDP or ProtoDNSTCP)
- Proto: dnsserver.ProtoDNSUDP,
// handler that will process incoming DNS queries
Handler: handler,
},
@@ -75,7 +74,6 @@ certificate and its private key.
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Proto: dnsserver.ProtoDoT,
Handler: h,
},
},
@@ -86,12 +84,14 @@ certificate and its private key.
# DNS-over-HTTPS
-DoH server uses an [*http.Server] internally. There are a couple of things to
-note:
+DoH server uses an [*http.Server] and/or [*http3.Server] internally. There are
+a couple of things to note:
- 1. tls.Config is optional. If you don't pass it, the server works simply as a
- plain HTTP server. This might be useful if you're running a reverse proxy
- like nginx in front of your DoH server.
+ 1. tls.Config can be omitted, but you must set [ConfigBase.Network] to
+ NetworkTCP. In this case the server will work simply as a plain HTTP
+ server. This might be useful if you're running a reverse proxy like Nginx
+ in front of your DoH server. If you do specify it, the server will listen
+ to both DoH2 and DoH3 by default.
2. In the constructor you can specify an optional [http.HandlerFunc] that
processes non-DNS requests, e.g. requests to paths different from
@@ -103,7 +103,6 @@ Example:
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Proto: dnsserver.ProtoDoH,
Handler: h,
},
TLSConfig: tlsConfig,
@@ -121,7 +120,6 @@ DoQ server uses the [quic-go module]. Just like DoH and DoT, it requires a
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Proto: dnsserver.ProtoDoQ,
Handler: h,
},
TLSConfig: tlsConfig,
@@ -139,7 +137,6 @@ documentation] about how to initialize it.
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Proto: dnsserver.ProtoDNSCryptUDP,
Handler: h,
},
DNSCryptProviderName: s.ProviderName,
@@ -148,9 +145,6 @@ documentation] about how to initialize it.
s := dnsserver.NewServerDNSCrypt(conf)
err := s.Start(context.Background())
-Normally, you would like to run two servers on the same address. One would
-listen to TCP, and the other one would listen to UDP.
-
# Middlewares
Package dnsserver supports customizing server behavior using middlewares. All
diff --git a/internal/dnsserver/example_test.go b/internal/dnsserver/example_test.go
index a42f2ec..71ed64f 100644
--- a/internal/dnsserver/example_test.go
+++ b/internal/dnsserver/example_test.go
@@ -34,8 +34,6 @@ func ExampleNewServerDNS() {
Name: "test",
// listen address
Addr: "127.0.0.1:0",
- // protocol (ProtoDNSUDP or ProtoDNSTCP)
- Proto: dnsserver.ProtoDNSUDP,
// handler that will process incoming DNS queries
Handler: handler,
},
@@ -60,6 +58,7 @@ func ExampleWithMiddlewares() {
// Init a handler func function with middlewares.
forwarder := forward.NewHandler(&forward.HandlerConfig{
Address: netip.MustParseAddrPort("94.140.14.140:53"),
+ Network: forward.NetworkAny,
}, true)
middleware := querylog.NewLogMiddleware(os.Stdout)
@@ -70,7 +69,6 @@ func ExampleWithMiddlewares() {
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Proto: dnsserver.ProtoDNSUDP,
Handler: handler,
},
}
diff --git a/internal/dnsserver/forward/example_test.go b/internal/dnsserver/forward/example_test.go
index 7190951..897a283 100644
--- a/internal/dnsserver/forward/example_test.go
+++ b/internal/dnsserver/forward/example_test.go
@@ -12,11 +12,11 @@ import (
func ExampleNewHandler() {
conf := dnsserver.ConfigDNS{
ConfigBase: dnsserver.ConfigBase{
- Name: "srv",
- Addr: "127.0.0.1:0",
- Proto: dnsserver.ProtoDNSUDP,
+ Name: "srv",
+ Addr: "127.0.0.1:0",
Handler: forward.NewHandler(&forward.HandlerConfig{
Address: netip.MustParseAddrPort("8.8.8.8:53"),
+ Network: forward.NetworkAny,
FallbackAddresses: []netip.AddrPort{
netip.MustParseAddrPort("1.1.1.1:53"),
},
diff --git a/internal/dnsserver/forward/forward.go b/internal/dnsserver/forward/forward.go
index b901f9a..575848e 100644
--- a/internal/dnsserver/forward/forward.go
+++ b/internal/dnsserver/forward/forward.go
@@ -84,6 +84,9 @@ type HandlerConfig struct {
// all DNS queries.
Address netip.AddrPort
+ // Network is the network protocol for the main upstream address.
+ Network Network
+
// MetricsListener is the optional listener for the handler events. Set it
// if you want to keep track of what the handler does and record performance
// metrics. If not set, EmptyMetricsListener is used.
@@ -117,7 +120,7 @@ type HandlerConfig struct {
// support plain DNS upstreams. c must not be nil.
func NewHandler(c *HandlerConfig, initialHealthcheck bool) (h *Handler) {
h = &Handler{
- upstream: NewUpstreamPlain(c.Address, NetworkAny),
+ upstream: NewUpstreamPlain(c.Address, c.Network),
hcDomainTmpl: c.HealthcheckDomainTmpl,
timeout: c.Timeout,
hcBackoff: c.HealthcheckBackoffDuration,
diff --git a/internal/dnsserver/forward/forward_test.go b/internal/dnsserver/forward/forward_test.go
index 2487c35..52fbe5a 100644
--- a/internal/dnsserver/forward/forward_test.go
+++ b/internal/dnsserver/forward/forward_test.go
@@ -14,28 +14,23 @@ import (
)
func TestMain(m *testing.M) {
- dnsservertest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
func TestHandler_ServeDNS(t *testing.T) {
- srv, err := dnsservertest.RunDNSServer(dnsservertest.DefaultHandler())
- require.NoError(t, err)
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ srv, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
// No-fallbacks handler.
handler := forward.NewHandler(&forward.HandlerConfig{
- Address: netip.MustParseAddrPort(srv.Addr),
+ Address: netip.MustParseAddrPort(addr),
+ Network: forward.NetworkAny,
}, true)
req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
- addr := srv.SrvTCP.LocalAddr()
- rw := dnsserver.NewNonWriterResponseWriter(addr, addr)
+ rw := dnsserver.NewNonWriterResponseWriter(srv.LocalUDPAddr(), srv.LocalUDPAddr())
// Check the handler's ServeDNS method
- err = handler.ServeDNS(context.Background(), rw, req)
+ err := handler.ServeDNS(context.Background(), rw, req)
require.NoError(t, err)
res := rw.Msg()
@@ -44,26 +39,20 @@ func TestHandler_ServeDNS(t *testing.T) {
}
func TestHandler_ServeDNS_fallbackNetError(t *testing.T) {
- srv, err := dnsservertest.RunDNSServer(dnsservertest.DefaultHandler())
- require.NoError(t, err)
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
-
+ srv, _ := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
handler := forward.NewHandler(&forward.HandlerConfig{
Address: netip.MustParseAddrPort("127.0.0.1:0"),
+ Network: forward.NetworkAny,
FallbackAddresses: []netip.AddrPort{
- netip.MustParseAddrPort(srv.Addr),
+ netip.MustParseAddrPort(srv.LocalUDPAddr().String()),
},
}, true)
req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
- addr := srv.SrvTCP.LocalAddr()
- rw := dnsserver.NewNonWriterResponseWriter(addr, addr)
+ rw := dnsserver.NewNonWriterResponseWriter(srv.LocalUDPAddr(), srv.LocalUDPAddr())
// Check the handler's ServeDNS method
- err = handler.ServeDNS(context.Background(), rw, req)
+ err := handler.ServeDNS(context.Background(), rw, req)
require.NoError(t, err)
res := rw.Msg()
diff --git a/internal/dnsserver/forward/healthcheck_test.go b/internal/dnsserver/forward/healthcheck_test.go
index e90a40e..8a3e2aa 100644
--- a/internal/dnsserver/forward/healthcheck_test.go
+++ b/internal/dnsserver/forward/healthcheck_test.go
@@ -9,7 +9,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/forward"
- "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -41,25 +40,14 @@ func TestHandler_Refresh(t *testing.T) {
return rw.WriteMsg(ctx, req, nrw.Msg())
})
- upstream, err := dnsservertest.RunDNSServer(handlerFunc)
- require.NoError(t, err)
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return upstream.Shutdown(context.Background())
- })
-
- fallback, err := dnsservertest.RunDNSServer(dnsservertest.DefaultHandler())
- require.NoError(t, err)
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return fallback.Shutdown(context.Background())
- })
-
+ upstream, _ := dnsservertest.RunDNSServer(t, handlerFunc)
+ fallback, _ := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
handler := forward.NewHandler(&forward.HandlerConfig{
- Address: netip.MustParseAddrPort(upstream.Addr),
+ Address: netip.MustParseAddrPort(upstream.LocalUDPAddr().String()),
+ Network: forward.NetworkAny,
HealthcheckDomainTmpl: "${RANDOM}.upstream-check.example",
FallbackAddresses: []netip.AddrPort{
- netip.MustParseAddrPort(fallback.Addr),
+ netip.MustParseAddrPort(fallback.LocalUDPAddr().String()),
},
// Make sure that the handler routs queries back to the main upstream
// immediately.
@@ -67,10 +55,9 @@ func TestHandler_Refresh(t *testing.T) {
}, false)
req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
- addr := fallback.SrvTCP.LocalAddr()
- rw := dnsserver.NewNonWriterResponseWriter(addr, addr)
+ rw := dnsserver.NewNonWriterResponseWriter(fallback.LocalUDPAddr(), fallback.LocalUDPAddr())
- err = handler.ServeDNS(context.Background(), rw, req)
+ err := handler.ServeDNS(context.Background(), rw, req)
require.Error(t, err)
assert.Equal(t, uint64(1), atomic.LoadUint64(&upstreamRequestsCount))
diff --git a/internal/dnsserver/forward/upstreamplain_test.go b/internal/dnsserver/forward/upstreamplain_test.go
index 50b67fa..1d1b049 100644
--- a/internal/dnsserver/forward/upstreamplain_test.go
+++ b/internal/dnsserver/forward/upstreamplain_test.go
@@ -9,7 +9,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/forward"
"github.com/AdguardTeam/golibs/log"
- "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/require"
)
@@ -31,14 +30,8 @@ func TestUpstreamPlain_Exchange(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- srv, err := dnsservertest.RunDNSServer(dnsservertest.DefaultHandler())
- require.NoError(t, err)
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
-
- u := forward.NewUpstreamPlain(netip.MustParseAddrPort(srv.Addr), tc.network)
+ _, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
+ u := forward.NewUpstreamPlain(netip.MustParseAddrPort(addr), tc.network)
defer log.OnCloserError(u, log.DEBUG)
req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
@@ -68,8 +61,9 @@ func TestUpstreamPlain_Exchange_truncated(t *testing.T) {
}
res := nrw.Msg()
- si := dnsserver.MustServerInfoFromContext(ctx)
- if si.Proto == dnsserver.ProtoDNSUDP {
+ network := dnsserver.NetworkFromAddr(rw.LocalAddr())
+
+ if network == dnsserver.NetworkUDP {
res.Truncated = true
res.Answer = nil
}
@@ -77,19 +71,14 @@ func TestUpstreamPlain_Exchange_truncated(t *testing.T) {
return rw.WriteMsg(ctx, req, res)
})
- srv, err := dnsservertest.RunDNSServer(handlerFunc)
- require.NoError(t, err)
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ _, addr := dnsservertest.RunDNSServer(t, handlerFunc)
// Create a test message.
req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
// First, check that we receive truncated response over UDP.
- addr := netip.MustParseAddrPort(srv.Addr)
- uUDP := forward.NewUpstreamPlain(addr, forward.NetworkUDP)
+ uAddr := netip.MustParseAddrPort(addr)
+ uUDP := forward.NewUpstreamPlain(uAddr, forward.NetworkUDP)
defer log.OnCloserError(uUDP, log.DEBUG)
res, err := uUDP.Exchange(context.Background(), req)
@@ -97,7 +86,7 @@ func TestUpstreamPlain_Exchange_truncated(t *testing.T) {
dnsservertest.RequireResponse(t, req, res, 0, dns.RcodeSuccess, true)
// Second, check that nothing is truncated over TCP.
- uTCP := forward.NewUpstreamPlain(addr, forward.NetworkTCP)
+ uTCP := forward.NewUpstreamPlain(uAddr, forward.NetworkTCP)
defer log.OnCloserError(uTCP, log.DEBUG)
res, err = uTCP.Exchange(context.Background(), req)
@@ -106,7 +95,7 @@ func TestUpstreamPlain_Exchange_truncated(t *testing.T) {
// Now with NetworkANY response is also not truncated since the upstream
// fallbacks to TCP.
- uAny := forward.NewUpstreamPlain(addr, forward.NetworkAny)
+ uAny := forward.NewUpstreamPlain(uAddr, forward.NetworkAny)
defer log.OnCloserError(uAny, log.DEBUG)
res, err = uAny.Exchange(context.Background(), req)
diff --git a/internal/dnsserver/go.mod b/internal/dnsserver/go.mod
index 7f437c5..00e2627 100644
--- a/internal/dnsserver/go.mod
+++ b/internal/dnsserver/go.mod
@@ -3,18 +3,18 @@ module github.com/AdguardTeam/AdGuardDNS/internal/dnsserver
go 1.19
require (
- github.com/AdguardTeam/golibs v0.10.9
- github.com/ameshkov/dnscrypt/v2 v2.2.3
+ github.com/AdguardTeam/golibs v0.11.3
+ github.com/ameshkov/dnscrypt/v2 v2.2.5
github.com/ameshkov/dnsstamps v1.0.3
github.com/bluele/gcache v0.0.2
- github.com/lucas-clemente/quic-go v0.28.1
+ github.com/lucas-clemente/quic-go v0.29.2
github.com/miekg/dns v1.1.50
github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible
- github.com/prometheus/client_golang v1.13.0
+ github.com/prometheus/client_golang v1.13.1
github.com/stretchr/testify v1.8.0
- golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
- golang.org/x/net v0.0.0-20220812174116-3211cb980234
- golang.org/x/sys v0.0.0-20220818161305-2296e01440c6
+ golang.org/x/exp v0.0.0-20221031165847-c99f073a8326
+ golang.org/x/net v0.1.0
+ golang.org/x/sys v0.1.0
)
require (
@@ -22,28 +22,31 @@ require (
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
- github.com/cheekybits/genny v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
+ github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
+ github.com/google/go-cmp v0.5.9 // indirect
github.com/kr/text v0.2.0 // indirect
- github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
- github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
- github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
- github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
+ github.com/marten-seemann/qpack v0.3.0 // indirect
+ github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
+ github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
+ github.com/onsi/ginkgo/v2 v2.4.0 // indirect
+ github.com/onsi/gomega v1.22.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/client_model v0.2.0 // indirect
+ github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
- golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 // indirect
- golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
- golang.org/x/text v0.3.7 // indirect
- golang.org/x/tools v0.1.12 // indirect
+ golang.org/x/crypto v0.1.0 // indirect
+ golang.org/x/mod v0.6.0 // indirect
+ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
+ golang.org/x/text v0.4.0 // indirect
+ golang.org/x/tools v0.2.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
diff --git a/internal/dnsserver/go.sum b/internal/dnsserver/go.sum
index 2186e53..b339817 100644
--- a/internal/dnsserver/go.sum
+++ b/internal/dnsserver/go.sum
@@ -1,7 +1,5 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
@@ -32,15 +30,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
-dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
-dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
-git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
-github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
-github.com/AdguardTeam/golibs v0.10.9 h1:F9oP2da0dQ9RQDM1lGR7LxUTfUWu8hEFOs4icwAkKM0=
-github.com/AdguardTeam/golibs v0.10.9/go.mod h1:W+5rznZa1cSNSFt+gPS7f4Wytnr9fOrd5ZYqwadPw14=
+github.com/AdguardTeam/golibs v0.11.3 h1:Oif+REq2WLycQ2Xm3ZPmJdfftptss0HbGWbxdFaC310=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
@@ -52,50 +43,36 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/ameshkov/dnscrypt/v2 v2.2.3 h1:X9UP5AHtwp46Ji+sGFfF/1Is6OPI/SjxLqhKpx0P5UI=
-github.com/ameshkov/dnscrypt/v2 v2.2.3/go.mod h1:xJB9cE1/GF+NB6EEQqRlkoa4bjcV2w7VYn1G+zVq7Bs=
-github.com/ameshkov/dnsstamps v1.0.1/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
+github.com/ameshkov/dnscrypt/v2 v2.2.5 h1:Ju1gQeez+6XLtk/b/k3RoJ2t+Ls+BSItLTZjZeedneY=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
-github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
-github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
-github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
-github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
-github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -107,6 +84,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
@@ -115,7 +93,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@@ -153,9 +130,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
-github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -167,19 +143,12 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-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.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
-github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -195,28 +164,18 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU=
-github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
-github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
-github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
-github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
-github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
-github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ=
-github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
-github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
-github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
-github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
-github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU=
-github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
-github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/lucas-clemente/quic-go v0.29.2 h1:O8Mt0O6LpvEW+wfC40vZdcw0DngwYzoxq5xULZNzSI8=
+github.com/lucas-clemente/quic-go v0.29.2/go.mod h1:g6/h9YMmLuU54tL1gW25uIi3VlBp3uv+sBihplIuskE=
+github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE=
+github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI=
+github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
+github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE=
+github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
-github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
+github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -226,8 +185,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
-github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@@ -235,16 +192,12 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
-github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
-github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
-github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
-github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
+github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI=
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/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -252,27 +205,23 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
-github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
-github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
+github.com/prometheus/client_golang v1.13.1 h1:3gMjIY2+/hzmqhtUC/aQNYldJA6DtH3CgQvwS+02K1c=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
-github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
@@ -281,35 +230,9 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
-github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
-github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
-github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
-github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
-github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
-github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
-github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
-github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
-github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
-github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
-github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
-github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
-github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
-github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
-github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
-github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
-github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
-github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
-github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
-github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
-github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
-github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -317,38 +240,26 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
-github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
-github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
-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-20180904163835-0709b304e793/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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUHW7cJMmx3TGZOrnyYaNQ6c=
-golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -359,11 +270,9 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
-golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
+golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -383,18 +292,14 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.2.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.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -403,7 +308,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -421,24 +325,18 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
-golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
-golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -454,11 +352,9 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+v
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20181116152217-5ac8a444bdc5/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -467,7 +363,6 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -485,7 +380,6 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -503,9 +397,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5gHoGSL4QbDz3S9s6j4U=
-golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -514,15 +406,12 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@@ -542,7 +431,6 @@ golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -566,15 +454,11 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -592,18 +476,12 @@ google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
-google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -632,9 +510,6 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -669,22 +544,17 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -695,5 +565,3 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
-sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
diff --git a/internal/dnsserver/listen_noreuseport.go b/internal/dnsserver/listen_noreuseport.go
index 09c8c75..8cf56e6 100644
--- a/internal/dnsserver/listen_noreuseport.go
+++ b/internal/dnsserver/listen_noreuseport.go
@@ -4,12 +4,30 @@ package dnsserver
import (
"context"
+ "fmt"
"net"
+
+ "github.com/AdguardTeam/golibs/errors"
)
// listenUDP listens to the specified address on UDP.
-func listenUDP(_ context.Context, addr string) (conn net.PacketConn, err error) {
- return net.ListenPacket("udp", addr)
+func listenUDP(_ context.Context, addr string, _ bool) (conn *net.UDPConn, err error) {
+ defer func() { err = errors.Annotate(err, "opening packet listener: %w") }()
+
+ c, err := net.ListenPacket("udp", addr)
+ if err != nil {
+ return nil, err
+ }
+
+ conn, ok := c.(*net.UDPConn)
+ if !ok {
+ // TODO(ameshkov): should not happen, consider panic here.
+ err = fmt.Errorf("expected conn of type %T, got %T", conn, c)
+
+ return nil, err
+ }
+
+ return conn, nil
}
// listenTCP listens to the specified address on TCP.
diff --git a/internal/dnsserver/listen_reuseport.go b/internal/dnsserver/listen_reuseport.go
index 1ac4e6e..552782f 100644
--- a/internal/dnsserver/listen_reuseport.go
+++ b/internal/dnsserver/listen_reuseport.go
@@ -4,9 +4,11 @@ package dnsserver
import (
"context"
+ "fmt"
"net"
"syscall"
+ "github.com/AdguardTeam/golibs/errors"
"golang.org/x/sys/unix"
)
@@ -22,11 +24,35 @@ func reuseportControl(_, _ string, c syscall.RawConn) (err error) {
return opErr
}
-// listenUDP listens to the specified address on UDP.
-func listenUDP(ctx context.Context, addr string) (conn net.PacketConn, err error) {
+// listenUDP listens to the specified address on UDP. If oob flag is set to
+// true this method also enables OOB for the listen socket that enables using of
+// ReadMsgUDP/WriteMsgUDP. Doing it this way is necessary to correctly discover
+// the source address when it listens to 0.0.0.0.
+func listenUDP(ctx context.Context, addr string, oob bool) (conn *net.UDPConn, err error) {
+ defer func() { err = errors.Annotate(err, "opening packet listener: %w") }()
+
var lc net.ListenConfig
lc.Control = reuseportControl
- return lc.ListenPacket(ctx, "udp", addr)
+ c, err := lc.ListenPacket(ctx, "udp", addr)
+ if err != nil {
+ return nil, err
+ }
+
+ conn, ok := c.(*net.UDPConn)
+ if !ok {
+ // TODO(ameshkov): should not happen, consider panic here.
+ err = fmt.Errorf("expected conn of type %T, got %T", conn, c)
+
+ return nil, err
+ }
+
+ if oob {
+ if err = setUDPSocketOptions(conn); err != nil {
+ return nil, fmt.Errorf("failed to set socket options: %w", err)
+ }
+ }
+
+ return conn, err
}
// listenTCP listens to the specified address on TCP.
diff --git a/internal/dnsserver/metrics.go b/internal/dnsserver/metrics.go
index c49febd..2e90363 100644
--- a/internal/dnsserver/metrics.go
+++ b/internal/dnsserver/metrics.go
@@ -15,20 +15,18 @@ import (
// ServerInfoFromContext or MustServerInfoFromContext.
// N.B. The implementation must be thread-safe.
type MetricsListener interface {
- // OnRequest called when we finished processing a request and we know what
+ // OnRequest called when we finished processing a request, and we know what
// response has been written.
//
- // ctx is the context of the DNS request. Besides the server info it also must
- // contain request's start time (can be retrieved by StartTimeFromContext or
- // MustStartTimeFromContext) and request and response sizes
- // (RequestSizeFromContext and ResponseSizeFromContext). Response size will
- // only be attached if there was any response written by the server.
+ // ctx is the context of the DNS request. Besides the server info, it also
+ // must contain request's start time (retrieved by MustStartTimeFromContext)
+ // and request info (MustRequestInfoFromContext).
//
- // req is a DNS request. Note, that
- // if the request was discarded (BadFormat or NotImplemented) this method
- // will still be called so the request message may be incorrect (i.e. no
- // Question section or whatever). res is a DNS response, will always be
- // present. rw is the ResponseWriter that was used to write the response.
+ // req is a DNS request. Note, that if the request was discarded (BadFormat
+ // or NotImplemented) this method will still be called so the request
+ // message may be incorrect (i.e. no Question section or whatever). res is
+ // a DNS response, will always be present. rw is the ResponseWriter that was
+ // used to write the response.
OnRequest(ctx context.Context, req, resp *dns.Msg, rw ResponseWriter)
// OnInvalidMsg called when the server encounters an invalid DNS message.
@@ -45,6 +43,12 @@ type MetricsListener interface {
// OnPanic called when a panic happened in a goroutine. ctx is the context
// of the DNS request. v is the object returned by the recover() method.
OnPanic(ctx context.Context, v any)
+
+ // OnQUICAddressValidation called when a QUIC connection needs to determine
+ // whether it's required or not to send the retry packet. This metric
+ // allows to keep an eye on how the addresses cache performs.
+ // TODO(ameshkov): find a way to attach this info to ctx and remove this.
+ OnQUICAddressValidation(hit bool)
}
// EmptyMetricsListener implements MetricsListener with empty functions.
@@ -70,3 +74,8 @@ func (e *EmptyMetricsListener) OnError(_ context.Context, _ error) {
// OnPanic implements the MetricsListener interface for *EmptyMetricsListener.
func (e *EmptyMetricsListener) OnPanic(_ context.Context, _ any) {
}
+
+// OnQUICAddressValidation implements the MetricsListener interface for
+// *EmptyMetricsListener.
+func (e *EmptyMetricsListener) OnQUICAddressValidation(_ bool) {
+}
diff --git a/internal/dnsserver/prometheus/cache_test.go b/internal/dnsserver/prometheus/cache_test.go
index 5f92838..83d7b85 100644
--- a/internal/dnsserver/prometheus/cache_test.go
+++ b/internal/dnsserver/prometheus/cache_test.go
@@ -4,6 +4,7 @@ import (
"context"
"net"
"testing"
+ "time"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/cache"
@@ -33,7 +34,15 @@ func TestCacheMetricsListener_integration_cache(t *testing.T) {
req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
addr := &net.UDPAddr{IP: net.IP{1, 2, 3, 4}, Port: 53}
nrw := dnsserver.NewNonWriterResponseWriter(addr, addr)
- err := handlerWithMiddleware.ServeDNS(context.Background(), nrw, req)
+ ctx := dnsserver.ContextWithServerInfo(context.Background(), dnsserver.ServerInfo{
+ Name: "test_server",
+ Addr: "127.0.0.1:0",
+ Proto: dnsserver.ProtoDNS,
+ })
+ ctx = dnsserver.ContextWithStartTime(ctx, time.Now())
+ ctx = dnsserver.ContextWithClientInfo(ctx, dnsserver.ClientInfo{})
+
+ err := handlerWithMiddleware.ServeDNS(ctx, nrw, req)
require.NoError(t, err)
dnsservertest.RequireResponse(t, req, nrw.Msg(), 1, dns.RcodeSuccess, false)
}
diff --git a/internal/dnsserver/prometheus/forward_test.go b/internal/dnsserver/prometheus/forward_test.go
index 97bd447..d2ee285 100644
--- a/internal/dnsserver/prometheus/forward_test.go
+++ b/internal/dnsserver/prometheus/forward_test.go
@@ -9,7 +9,6 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/forward"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/prometheus"
- "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/require"
)
@@ -18,16 +17,12 @@ import (
// normal unit test, we create a forward handler, emulate a query and then
// check if prom metrics were incremented.
func TestForwardMetricsListener_integration_request(t *testing.T) {
- srv, err := dnsservertest.RunDNSServer(dnsservertest.DefaultHandler())
- require.NoError(t, err)
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ srv, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
// Initialize a new forward.Handler and set the metrics listener.
handler := forward.NewHandler(&forward.HandlerConfig{
- Address: netip.MustParseAddrPort(srv.Addr),
+ Address: netip.MustParseAddrPort(addr),
+ Network: forward.NetworkAny,
MetricsListener: prometheus.NewForwardMetricsListener(0),
}, true)
@@ -35,10 +30,9 @@ func TestForwardMetricsListener_integration_request(t *testing.T) {
// It will then call the metrics listener and prom metrics should be
// incremented.
req := dnsservertest.CreateMessage("example.org.", dns.TypeA)
- addr := srv.SrvTCP.LocalAddr()
- rw := dnsserver.NewNonWriterResponseWriter(addr, addr)
+ rw := dnsserver.NewNonWriterResponseWriter(srv.LocalUDPAddr(), srv.LocalUDPAddr())
- err = handler.ServeDNS(context.Background(), rw, req)
+ err := handler.ServeDNS(context.Background(), rw, req)
require.NoError(t, err)
// Now make sure that prometheus metrics were incremented properly.
diff --git a/internal/dnsserver/prometheus/helper.go b/internal/dnsserver/prometheus/helper.go
index 88def9d..8de9f79 100644
--- a/internal/dnsserver/prometheus/helper.go
+++ b/internal/dnsserver/prometheus/helper.go
@@ -15,13 +15,16 @@ func requestLabels(
req *dns.Msg,
rw dnsserver.ResponseWriter,
) prometheus.Labels {
- // base labels
+ // Base labels with general server information (name, addr, proto).
labels := baseLabels(ctx)
- // DNS query type
+ // DNS query type (only use those we're interested in).
labels["type"] = typeToString(req)
- // Address family
+ // Network type (tcp or udp).
+ labels["network"] = string(dnsserver.NetworkFromAddr(rw.LocalAddr()))
+
+ // Address family.
ip, _ := netutil.IPAndPortFromAddr(rw.RemoteAddr())
if ip == nil {
labels["family"] = "0"
diff --git a/internal/dnsserver/prometheus/prometheus.go b/internal/dnsserver/prometheus/prometheus.go
index 829d743..6de7893 100644
--- a/internal/dnsserver/prometheus/prometheus.go
+++ b/internal/dnsserver/prometheus/prometheus.go
@@ -14,22 +14,25 @@ like using "github.com/prometheus/client_golang/prometheus/promhttp" package.
dnsserver.MetricsListener metrics:
- - "dns_server_request_total" is the number of processed DNS requests. Labels
- include the common labels: server name, address and protocol, and also
- include request-specific labels: "type" is a DNS query type (string);
- "family" is the Addr family. 1 for IPv4, 2 for IPv6, 0 for unknown.
+ - "dns_server_request_total" is the number of processed DNS requests. Labels
+ include the common labels: server name, address, network and protocol, and
+ also include request-specific labels: "type" is a DNS query type (string);
+ "family" is the Addr family. 1 for IPv4, 2 for IPv6, 0 for unknown,
+ "network" is "tcp" or "udp".
- "dns_server_request_duration_seconds" is a histogram with request durations.
- "dns_server_request_size_bytes" is a histogram with request sizes.
- "dns_server_response_size_bytes" is a histogram with response sizes.
- "dns_server_response_rcode_total" is the number of received DNS responses.
- Besides basic labels it also includes "rcode" label. "rcode" is either a
+ Besides basic labels, it also includes "rcode" label. "rcode" is either a
response code string representation or "DROPPED" if there actually was no
response at all.
- "dns_server_error_total" is the number of errors occurred in the DNS server.
- "dns_server_panic_total" is the number of panics occurred in the DNS server.
- "dns_server_invalid_msg_total" is the number of invalid messages received by
- the DNS server. It may be just crap bytes, but it also may be incorrect DNS
+ the DNS server. It may be just crap bytes, but it also may be incorrect DNS
messages (i.e. no Question records, unsupported Opcode, etc).
+ - "dns_server_quic_addr_validation_lookups" is the number of quic address
+ validation cache lookups. hit=1 means that a cached item was found.
forward.MetricsListener metrics:
diff --git a/internal/dnsserver/prometheus/prometheus_test.go b/internal/dnsserver/prometheus/prometheus_test.go
index f55fd70..eacb45e 100644
--- a/internal/dnsserver/prometheus/prometheus_test.go
+++ b/internal/dnsserver/prometheus/prometheus_test.go
@@ -3,14 +3,13 @@ package prometheus_test
import (
"testing"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/require"
-
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
)
func TestMain(m *testing.M) {
- dnsservertest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
// requireMetrics accepts a list of metrics names and checks that
diff --git a/internal/dnsserver/prometheus/ratelimit.go b/internal/dnsserver/prometheus/ratelimit.go
index 66bfd6c..8b6a277 100644
--- a/internal/dnsserver/prometheus/ratelimit.go
+++ b/internal/dnsserver/prometheus/ratelimit.go
@@ -46,12 +46,12 @@ var (
Namespace: namespace,
Subsystem: subsystemRateLimit,
Help: "The total number of rate-limited DNS queries.",
- }, []string{"name", "proto", "addr", "type", "family"})
+ }, []string{"name", "proto", "network", "addr", "type", "family"})
allowlistedTotal = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "allowlisted_total",
Namespace: namespace,
Subsystem: subsystemRateLimit,
Help: "The total number of allowlisted DNS queries.",
- }, []string{"name", "proto", "addr", "type", "family"})
+ }, []string{"name", "proto", "network", "addr", "type", "family"})
)
diff --git a/internal/dnsserver/prometheus/ratelimit_test.go b/internal/dnsserver/prometheus/ratelimit_test.go
index 759f511..15d634f 100644
--- a/internal/dnsserver/prometheus/ratelimit_test.go
+++ b/internal/dnsserver/prometheus/ratelimit_test.go
@@ -47,8 +47,10 @@ func TestRateLimiterMetricsListener_integration_cache(t *testing.T) {
ctx := dnsserver.ContextWithServerInfo(context.Background(), dnsserver.ServerInfo{
Name: "test",
Addr: "127.0.0.1",
- Proto: dnsserver.ProtoDNSUDP,
+ Proto: dnsserver.ProtoDNS,
})
+ ctx = dnsserver.ContextWithStartTime(ctx, time.Now())
+ ctx = dnsserver.ContextWithClientInfo(ctx, dnsserver.ClientInfo{})
err = handlerWithMiddleware.ServeDNS(ctx, nrw, req)
require.NoError(t, err)
diff --git a/internal/dnsserver/prometheus/server.go b/internal/dnsserver/prometheus/server.go
index 2603901..b71c5e7 100644
--- a/internal/dnsserver/prometheus/server.go
+++ b/internal/dnsserver/prometheus/server.go
@@ -5,21 +5,20 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
- "github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
-// ServerMetricsListener implements the dnsserver.MetricsListener interface
+// ServerMetricsListener implements the [dnsserver.MetricsListener] interface
// and increments prom counters.
type ServerMetricsListener struct{}
// type check
var _ dnsserver.MetricsListener = (*ServerMetricsListener)(nil)
-// OnRequest implements the dnsserver.MetricsListener interface for
-// *ServerMetricsListener.
+// OnRequest implements the [dnsserver.MetricsListener] interface for
+// [*ServerMetricsListener].
func (l *ServerMetricsListener) OnRequest(
ctx context.Context,
req, resp *dns.Msg,
@@ -37,19 +36,12 @@ func (l *ServerMetricsListener) OnRequest(
requestDuration.With(srvLabels).Observe(elapsed)
// Increment request size.
- size, found := dnsserver.RequestSizeFromContext(ctx)
- if !found {
- log.Error("request size is not attached to the context")
- }
- requestSize.With(srvLabels).Observe(float64(size))
+ ri := dnsserver.MustRequestInfoFromContext(ctx)
+ requestSize.With(srvLabels).Observe(float64(ri.RequestSize))
// If resp is not nil, increment response-related metrics
if resp != nil {
- size, found = dnsserver.ResponseSizeFromContext(ctx)
- if !found {
- log.Error("response size is not attached to the context")
- }
- responseSize.With(srvLabels).Observe(float64(size))
+ responseSize.With(srvLabels).Observe(float64(ri.ResponseSize))
resLabels := baseLabels(ctx)
resLabels["rcode"] = rCodeToString(resp.Rcode)
@@ -63,35 +55,45 @@ func (l *ServerMetricsListener) OnRequest(
}
}
-// OnInvalidMsg implements the dnsserver.MetricsListener interface for
-// *ServerMetricsListener.
+// OnInvalidMsg implements the [dnsserver.MetricsListener] interface for
+// [*ServerMetricsListener].
func (l *ServerMetricsListener) OnInvalidMsg(ctx context.Context) {
labels := baseLabels(ctx)
invalidMsgTotal.With(labels).Inc()
}
-// OnError implements the dnsserver.MetricsListener interface for
-// *ServerMetricsListener.
+// OnError implements the [dnsserver.MetricsListener] interface for
+// [*ServerMetricsListener].
func (l *ServerMetricsListener) OnError(ctx context.Context, _ error) {
labels := baseLabels(ctx)
errorTotal.With(labels).Inc()
}
-// OnPanic implements the dnsserver.MetricsListener interface for
-// *ServerMetricsListener.
+// OnPanic implements the [dnsserver.MetricsListener] interface for
+// [*ServerMetricsListener].
func (l *ServerMetricsListener) OnPanic(ctx context.Context, _ any) {
labels := baseLabels(ctx)
panicTotal.With(labels).Inc()
}
-// This block contains prometheus metrics declarations for dnsserver.Server
+// OnQUICAddressValidation implements the [dnsserver.MetricsListener] interface
+// for [*ServerMetricsListener].
+func (l *ServerMetricsListener) OnQUICAddressValidation(hit bool) {
+ if hit {
+ quicAddrValidationCacheLookupsHits.Inc()
+ } else {
+ quicAddrValidationCacheLookupsMisses.Inc()
+ }
+}
+
+// This block contains prometheus metrics declarations for [dnsserver.Server]
var (
requestTotal = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "request_total",
Namespace: namespace,
Subsystem: subsystemServer,
Help: "The number of processed DNS requests.",
- }, []string{"name", "proto", "addr", "type", "family"})
+ }, []string{"name", "proto", "network", "addr", "type", "family"})
requestDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
Name: "request_duration_seconds",
@@ -148,3 +150,16 @@ var (
Help: "The number of invalid DNS messages processed by the DNS server.",
}, []string{"name", "proto", "addr"})
)
+
+var (
+ quicAddrValidationCacheLookups = promauto.NewCounterVec(prometheus.CounterOpts{
+ Name: "quic_addr_validation_lookups",
+ Namespace: namespace,
+ Subsystem: subsystemServer,
+ Help: "The number of QUIC address validation lookups." +
+ "hit=1 means that a cached item was found.",
+ }, []string{"hit"})
+
+ quicAddrValidationCacheLookupsHits = quicAddrValidationCacheLookups.WithLabelValues("1")
+ quicAddrValidationCacheLookupsMisses = quicAddrValidationCacheLookups.WithLabelValues("0")
+)
diff --git a/internal/dnsserver/prometheus/server_test.go b/internal/dnsserver/prometheus/server_test.go
index a819b3c..6a11c1f 100644
--- a/internal/dnsserver/prometheus/server_test.go
+++ b/internal/dnsserver/prometheus/server_test.go
@@ -23,29 +23,28 @@ func TestServerMetricsListener_integration_requestLifetime(t *testing.T) {
ConfigBase: dnsserver.ConfigBase{
Name: "test",
Addr: "127.0.0.1:0",
- Proto: dnsserver.ProtoDNSTCP,
Handler: dnsservertest.DefaultHandler(),
Metrics: &prom.ServerMetricsListener{},
},
}
srv := dnsserver.NewServerDNS(conf)
- // Start the server
+ // Start the server.
err := srv.Start(context.Background())
require.NoError(t, err)
- // Make sure the server shuts down in the end
+ // Make sure the server shuts down in the end.
testutil.CleanupAndRequireSuccess(t, func() (err error) {
return srv.Shutdown(context.Background())
})
- // Create a test message
+ // Create a test message.
req := dnsservertest.CreateMessage("example.org", dns.TypeA)
c := &dns.Client{Net: "tcp"}
- // Send a test DNS query
- addr := srv.LocalAddr().String()
+ // Send a test DNS query.
+ addr := srv.LocalUDPAddr().String()
// Pass 10 requests to make the test less flaky.
for i := 0; i < 10; i++ {
@@ -55,7 +54,7 @@ func TestServerMetricsListener_integration_requestLifetime(t *testing.T) {
require.Equal(t, dns.RcodeSuccess, res.Rcode)
}
- // Now make sure that prometheus metrics were incremented properly
+ // Now make sure that prometheus metrics were incremented properly.
requireMetrics(
t,
"dns_server_request_total",
diff --git a/internal/dnsserver/protocol.go b/internal/dnsserver/protocol.go
index 828910c..f12ceb1 100644
--- a/internal/dnsserver/protocol.go
+++ b/internal/dnsserver/protocol.go
@@ -2,6 +2,7 @@ package dnsserver
import (
"fmt"
+ "net"
"golang.org/x/exp/slices"
)
@@ -18,11 +19,8 @@ const (
// ProtoInvalid is the invalid default value.
ProtoInvalid Protocol = 0
- // ProtoDNSTCP is plain DNS over TCP.
- ProtoDNSTCP Protocol = 1
-
- // ProtoDNSUDP is plain DNS over UDP.
- ProtoDNSUDP Protocol = 2
+ // ProtoDNS is plain DNS.
+ ProtoDNS Protocol = 8
// ProtoDoH is DNS-over-HTTPS.
ProtoDoH Protocol = 3
@@ -33,30 +31,23 @@ const (
// ProtoDoT is DNS-over-TLS.
ProtoDoT Protocol = 5
- // ProtoDNSCryptTCP is DNSCrypt over TCP.
- ProtoDNSCryptTCP Protocol = 6
-
- // ProtoDNSCryptUDP is DNSCrypt over UDP.
- ProtoDNSCryptUDP Protocol = 7
+ // ProtoDNSCrypt is DNSCrypt.
+ ProtoDNSCrypt Protocol = 9
)
// String implements the fmt.Stringer interface for Protocol.
func (p Protocol) String() (s string) {
switch p {
- case ProtoDNSTCP:
- return "dns-tcp"
- case ProtoDNSUDP:
- return "dns-udp"
+ case ProtoDNS:
+ return "dns"
case ProtoDoH:
return "doh"
case ProtoDoQ:
return "doq"
case ProtoDoT:
return "dot"
- case ProtoDNSCryptTCP:
- return "dnscrypt-tcp"
- case ProtoDNSCryptUDP:
- return "dnscrypt-udp"
+ case ProtoDNSCrypt:
+ return "dnscrypt"
default:
return fmt.Sprintf("!bad_protocol_%d", p)
}
@@ -71,17 +62,12 @@ func (p Protocol) ALPN() (alpn []string) {
case ProtoDoQ:
return []string{nextProtoDoQ}
case ProtoDoH:
- return slices.Clone(nextProtoDoH)
+ return slices.Clone(nextProtoDoH3)
default:
return nil
}
}
-// IsPlain returns true if the protocol is a plain DNS over TCP or UDP.
-func (p Protocol) IsPlain() (ok bool) {
- return p == ProtoDNSTCP || p == ProtoDNSUDP
-}
-
// IsStdEncrypted returns true if the protocol is one of the standard encrypted
// DNS protocol as defined by an RFC.
func (p Protocol) IsStdEncrypted() (ok bool) {
@@ -97,8 +83,31 @@ type Network string
const (
NetworkTCP Network = "tcp"
NetworkUDP Network = "udp"
+ NetworkAny Network = ""
)
+// CanTCP returns true if this Network supports TCP.
+func (n Network) CanTCP() (ok bool) {
+ return n == NetworkAny || n == NetworkTCP
+}
+
+// CanUDP returns true if this Network supports UDP.
+func (n Network) CanUDP() (ok bool) {
+ return n == NetworkAny || n == NetworkUDP
+}
+
+// NetworkFromAddr returns NetworkTCP or NetworkUDP depending on the address.
+func NetworkFromAddr(addr net.Addr) (network Network) {
+ switch addr.Network() {
+ case "udp":
+ return NetworkUDP
+ case "tcp":
+ return NetworkTCP
+ default:
+ panic(fmt.Sprintf("unexpected network type %s", addr.Network()))
+ }
+}
+
const (
// DNSHeaderSize is the DNS query header size.
DNSHeaderSize = 12
diff --git a/internal/dnsserver/querylog/querylog.go b/internal/dnsserver/querylog/querylog.go
index 472a919..7997931 100644
--- a/internal/dnsserver/querylog/querylog.go
+++ b/internal/dnsserver/querylog/querylog.go
@@ -41,8 +41,10 @@ func (l *LogMiddleware) Wrap(h dnsserver.Handler) (wrapped dnsserver.Handler) {
// [{name} {proto}://{addr}] {id} {type} {name} {size} {rcode} {rsize} {duration}
sb := strings.Builder{}
- // Server info: [{name} {proto}://{addr}]
serverInfo := dnsserver.MustServerInfoFromContext(ctx)
+ requestInfo := dnsserver.MustRequestInfoFromContext(ctx)
+
+ // [{name} {proto}://{addr}]
sb.WriteString(
fmt.Sprintf("[%s %s://%s] ",
serverInfo.Name,
@@ -56,7 +58,6 @@ func (l *LogMiddleware) Wrap(h dnsserver.Handler) (wrapped dnsserver.Handler) {
if len(req.Question) > 0 {
hostname = req.Question[0].Name
}
- reqSize, _ := dnsserver.RequestSizeFromContext(ctx)
var qType uint16
if len(req.Question) == 1 {
qType = req.Question[0].Qtype
@@ -70,7 +71,7 @@ func (l *LogMiddleware) Wrap(h dnsserver.Handler) (wrapped dnsserver.Handler) {
req.Id,
qTypeStr,
hostname,
- reqSize,
+ requestInfo.RequestSize,
),
)
@@ -79,7 +80,7 @@ func (l *LogMiddleware) Wrap(h dnsserver.Handler) (wrapped dnsserver.Handler) {
rsize := 0
if recW.Resp != nil {
rcode = recW.Resp.Rcode
- rsize, _ = dnsserver.ResponseSizeFromContext(ctx)
+ rsize = requestInfo.ResponseSize
}
sb.WriteString(fmt.Sprintf("%d %d ", rcode, rsize))
diff --git a/internal/dnsserver/querylog/querylog_test.go b/internal/dnsserver/querylog/querylog_test.go
index b0cf019..88748ce 100644
--- a/internal/dnsserver/querylog/querylog_test.go
+++ b/internal/dnsserver/querylog/querylog_test.go
@@ -49,11 +49,13 @@ func TestLogMiddleware_Wrap(t *testing.T) {
dnsserver.ServerInfo{
Name: "test",
Addr: "0.0.0.0:53",
- Proto: dnsserver.ProtoDNSUDP,
+ Proto: dnsserver.ProtoDNS,
})
ctx = dnsserver.ContextWithStartTime(ctx, time.Now().Add(-time.Second))
- ctx = dnsserver.ContextWithRequestSize(ctx, req.Len())
- ctx = dnsserver.ContextWithResponseSize(ctx, req.Len())
+ ctx = dnsserver.ContextWithRequestInfo(ctx, dnsserver.RequestInfo{
+ RequestSize: req.Len(),
+ ResponseSize: req.Len(),
+ })
// Init response writer with test data
localAddr := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 53}
@@ -68,7 +70,7 @@ func TestLogMiddleware_Wrap(t *testing.T) {
require.True(t,
strings.HasPrefix(
w.String(),
- "[test dns-udp://0.0.0.0:53] 1 A example.org. 29 0 29",
+ "[test dns://0.0.0.0:53] 1 A example.org. 29 0 29",
),
"invalid message: %s",
w.String(),
diff --git a/internal/dnsserver/ratelimit/ratelimit.go b/internal/dnsserver/ratelimit/ratelimit.go
index e3f44a6..0ee65fc 100644
--- a/internal/dnsserver/ratelimit/ratelimit.go
+++ b/internal/dnsserver/ratelimit/ratelimit.go
@@ -29,7 +29,7 @@ type Middleware struct {
Metrics MetricsListener
// rateLimit is defines whether the query should be dropped or not. The
- // default implementation of it is *BackOff.
+ // default implementation of it is [*BackOff].
rateLimit Interface
// protos is a list of protocols this middleware applies rate-limiting logic
@@ -40,7 +40,8 @@ type Middleware struct {
// type check
var _ dnsserver.Middleware = (*Middleware)(nil)
-// NewMiddleware returns a properly initialized *Middleware.
+// NewMiddleware returns a properly initialized [*Middleware]. protos is a list
+// of [dnsserver.Protocol] the rate limit will be used for.
func NewMiddleware(rl Interface, protos []dnsserver.Protocol) (m *Middleware, err error) {
return &Middleware{
Metrics: &EmptyMetricsListener{},
@@ -49,7 +50,7 @@ func NewMiddleware(rl Interface, protos []dnsserver.Protocol) (m *Middleware, er
}, nil
}
-// Wrap implements the dnsserver.Middleware interface for *Middleware.
+// Wrap implements the [dnsserver.Middleware] interface for [*Middleware].
func (m *Middleware) Wrap(handler dnsserver.Handler) (wrapped dnsserver.Handler) {
f := func(ctx context.Context, rw dnsserver.ResponseWriter, req *dns.Msg) (err error) {
if !m.isEnabledForProto(ctx) {
@@ -101,9 +102,9 @@ func (m *Middleware) Wrap(handler dnsserver.Handler) (wrapped dnsserver.Handler)
}
// addrPortFromNetAddr returns the IP address and port from addr. If one cannot
-// be obtained from addr, it returns netip.AddrPort{}.
+// be obtained from addr, it returns a zero value of [netip.AddrPort].
//
-// NOTE: Keep in sync with dnssvc.ipFromNetAddr.
+// NOTE: Keep in sync with [dnssvc.ipFromNetAddr].
//
// TODO(a.garipov): Perhaps this normalization should be done in package
// dnsserver.
@@ -133,6 +134,7 @@ func (m *Middleware) isEnabledForProto(ctx context.Context) (enabled bool) {
}
si := dnsserver.MustServerInfoFromContext(ctx)
+
for _, proto := range m.protos {
if proto == si.Proto {
return true
diff --git a/internal/dnsserver/ratelimit/ratelimit_test.go b/internal/dnsserver/ratelimit/ratelimit_test.go
index f8de102..8be231d 100644
--- a/internal/dnsserver/ratelimit/ratelimit_test.go
+++ b/internal/dnsserver/ratelimit/ratelimit_test.go
@@ -10,13 +10,14 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/ratelimit"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMain(m *testing.M) {
- dnsservertest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
func TestRatelimitMiddleware(t *testing.T) {
@@ -103,7 +104,7 @@ func TestRatelimitMiddleware(t *testing.T) {
RefuseANY: true,
})
rlMw, err := ratelimit.NewMiddleware(rl, []dnsserver.Protocol{
- dnsserver.ProtoDNSUDP,
+ dnsserver.ProtoDNS,
})
require.NoError(t, err)
@@ -115,12 +116,17 @@ func TestRatelimitMiddleware(t *testing.T) {
ctx := dnsserver.ContextWithServerInfo(context.Background(), dnsserver.ServerInfo{
Name: "test",
Addr: "127.0.0.1",
- Proto: dnsserver.ProtoDNSUDP,
+ Proto: dnsserver.ProtoDNS,
})
+ ctx = dnsserver.ContextWithStartTime(ctx, time.Now())
+ ctx = dnsserver.ContextWithClientInfo(ctx, dnsserver.ClientInfo{})
n := 0
for i := 0; i < tc.reqsNum; i++ {
- nrw := dnsserver.NewNonWriterResponseWriter(nil, tc.remoteAddr)
+ nrw := dnsserver.NewNonWriterResponseWriter(
+ &net.UDPAddr{IP: []byte{1, 2, 3, 4}},
+ tc.remoteAddr,
+ )
err = withMw.ServeDNS(ctx, nrw, tc.req)
require.NoError(t, err)
diff --git a/internal/dnsserver/serverbase.go b/internal/dnsserver/serverbase.go
index 2a6099d..fbc6392 100644
--- a/internal/dnsserver/serverbase.go
+++ b/internal/dnsserver/serverbase.go
@@ -17,18 +17,27 @@ import (
type ConfigBase struct {
// Name is used for logging, and it may be used for perf counters reporting.
Name string
+
// Addr is the address the server listens to. See go doc net.Dial for
// the documentation on the address format.
Addr string
- // Proto is the server protocol.
- Proto Protocol
+
+ // Network is the network this server listens to. If empty, the server will
+ // listen to all networks that are supposed to be used by the server's
+ // protocol. Note, that it only makes sense for [ServerDNS],
+ // [ServerDNSCrypt], and [ServerHTTPS].
+ Network Network
+
// Handler is a handler that processes incoming DNS messages.
// If not set, we'll use the default handler that returns error response
// to any query.
+
Handler Handler
// Metrics is the object we use for collecting performance metrics.
// This field is optional.
+
Metrics MetricsListener
+
// BaseContext is a function that should return the base context. If not
// set, we'll be using context.Background().
BaseContext func() (ctx context.Context)
@@ -42,6 +51,9 @@ type ServerBase struct {
addr string
// proto is the server protocol.
proto Protocol
+ // network is the network to listen to. It only makes sense for the
+ // following protocols: ProtoDNS, ProtoDNSCrypt, ProtoDoH.
+ network Network
// handler is a handler that processes incoming DNS messages.
handler Handler
// baseContext is a function that should return the base context.
@@ -68,13 +80,17 @@ type ServerBase struct {
wg sync.WaitGroup
}
+// type check
+var _ Server = (*ServerBase)(nil)
+
// newServerBase creates a new instance of ServerBase and initializes
// some of its internal properties.
-func newServerBase(conf ConfigBase) (s *ServerBase) {
+func newServerBase(proto Protocol, conf ConfigBase) (s *ServerBase) {
s = &ServerBase{
name: conf.Name,
addr: conf.Addr,
- proto: conf.Proto,
+ proto: proto,
+ network: conf.Network,
handler: conf.Handler,
metrics: conf.Metrics,
baseContext: conf.BaseContext,
@@ -95,22 +111,38 @@ func newServerBase(conf ConfigBase) (s *ServerBase) {
return s
}
-// Name returns the server name. It is safe for concurrent use.
+// Name implements the [dnsserver.Server] interface for *ServerBase.
func (s *ServerBase) Name() (name string) {
return s.name
}
-// Addr returns the address the server was configured to listen to. It is safe
-// for concurrent use.
+// Proto implements the [dnsserver.Server] interface for *ServerBase.
+func (s *ServerBase) Proto() (proto Protocol) {
+ return s.proto
+}
+
+// Network implements the [dnsserver.Server] interface for *ServerBase.
+func (s *ServerBase) Network() (network Network) {
+ return s.network
+}
+
+// Addr implements the [dnsserver.Server] interface for *ServerBase.
func (s *ServerBase) Addr() (addr string) {
return s.addr
}
-// LocalAddr returns the address the server listens to at the moment.
-func (s *ServerBase) LocalAddr() (addr net.Addr) {
- if s.udpListener != nil {
- return s.udpListener.LocalAddr()
- }
+// Start implements the [dnsserver.Server] interface for *ServerBase.
+func (s *ServerBase) Start(_ context.Context) (err error) {
+ panic("*ServerBase must not be used directly")
+}
+
+// Shutdown implements the [dnsserver.Server] interface for *ServerBase.
+func (s *ServerBase) Shutdown(_ context.Context) (err error) {
+ panic("*ServerBase must not be used directly")
+}
+
+// LocalTCPAddr implements the [dnsserver.Server] interface for *ServerBase.
+func (s *ServerBase) LocalTCPAddr() (addr net.Addr) {
if s.tcpListener != nil {
return s.tcpListener.Addr()
}
@@ -118,9 +150,13 @@ func (s *ServerBase) LocalAddr() (addr net.Addr) {
return nil
}
-// Proto returns the protocol of the server. It is safe for concurrent use.
-func (s *ServerBase) Proto() (proto Protocol) {
- return s.proto
+// LocalUDPAddr implements the [dnsserver.Server] interface for *ServerBase.
+func (s *ServerBase) LocalUDPAddr() (addr net.Addr) {
+ if s.udpListener != nil {
+ return s.udpListener.LocalAddr()
+ }
+
+ return nil
}
// requestContext returns a context for one request. It adds the start time and
@@ -162,16 +198,17 @@ func (s *ServerBase) serveDNSMsg(
hostname, qType := questionData(req)
log.Debug("[%d] processing \"%s %s\"", req.Id, qType, hostname)
- ctx = ContextWithRequestSize(ctx, req.Len())
recW := NewRecorderResponseWriter(rw)
s.serveDNSMsgInternal(ctx, req, recW)
+ ri := RequestInfo{RequestSize: req.Len()}
resp := recW.Resp
written = resp != nil
if written {
- ctx = ContextWithResponseSize(ctx, resp.Len())
+ ri.ResponseSize = resp.Len()
}
+ ctx = ContextWithRequestInfo(ctx, ri)
s.metrics.OnRequest(ctx, req, resp, rw)
log.Debug("[%d]: finished processing \"%s %s\"", req.Id, qType, hostname)
@@ -303,6 +340,49 @@ func (s *ServerBase) handlePanicAndRecover(ctx context.Context) {
}
}
+// listenUDP creates a UDP listener for the ServerBase.addr. This function will
+// initialize and start ServerBase.udpListener or return an error. If the TCP
+// listener is already running, its address is used instead. The point of this
+// is to properly handle the case when port 0 is used as both listeners should
+// use the same port, and we only learn it after the first one was started.
+func (s *ServerBase) listenUDP(ctx context.Context) (err error) {
+ addr := s.addr
+ if s.tcpListener != nil {
+ addr = s.tcpListener.Addr().String()
+ }
+
+ conn, err := listenUDP(ctx, addr, true)
+ if err != nil {
+ return err
+ }
+
+ s.udpListener = conn
+
+ return nil
+}
+
+// listenTCP creates a TCP listener for the ServerBase.addr. This function will
+// initialize and start ServerBase.tcpListener or return an error. If the UDP
+// listener is already running, its address is used instead. The point of this
+// is to properly handle the case when port 0 is used as both listeners should
+// use the same port, and we only learn it after the first one was started.
+func (s *ServerBase) listenTCP(ctx context.Context) (err error) {
+ addr := s.addr
+ if s.udpListener != nil {
+ addr = s.udpListener.LocalAddr().String()
+ }
+
+ var l net.Listener
+ l, err = listenTCP(ctx, addr)
+ if err != nil {
+ return err
+ }
+
+ s.tcpListener = l
+
+ return nil
+}
+
// closeListeners stops UDP and TCP listeners.
func (s *ServerBase) closeListeners() {
if s.udpListener != nil {
diff --git a/internal/dnsserver/serverbench_test.go b/internal/dnsserver/serverbench_test.go
index 24432b3..eabb225 100644
--- a/internal/dnsserver/serverbench_test.go
+++ b/internal/dnsserver/serverbench_test.go
@@ -12,6 +12,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/testutil"
"github.com/ameshkov/dnscrypt/v2"
"github.com/ameshkov/dnsstamps"
@@ -20,101 +21,90 @@ import (
"github.com/stretchr/testify/require"
)
-func BenchmarkServeUDP(b *testing.B) {
- srv, _, err := dnsservertest.RunLocalDNSServer(
- dnsservertest.DefaultHandler(),
- dnsserver.ProtoDNSUDP,
- )
- require.NoError(b, err)
+func BenchmarkServeDNS(b *testing.B) {
+ testCases := []struct {
+ name string
+ network dnsserver.Network
+ }{{
+ name: "udp",
+ network: dnsserver.NetworkUDP,
+ }, {
+ name: "tcp",
+ network: dnsserver.NetworkTCP,
+ }}
- testutil.CleanupAndRequireSuccess(b, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ for _, tc := range testCases {
+ b.Run(tc.name, func(b *testing.B) {
+ _, addr := dnsservertest.RunDNSServer(b, dnsservertest.DefaultHandler())
- // Prepare a test message
- m := new(dns.Msg)
- m.SetQuestion("example.org.", dns.TypeA)
- msg, _ := m.Pack()
+ // Prepare a test message.
+ m := new(dns.Msg)
+ m.SetQuestion("example.org.", dns.TypeA)
+ var msg []byte
+ msgPacket, _ := m.Pack()
+ if tc.network == dnsserver.NetworkTCP {
+ msg = make([]byte, 2+len(msgPacket))
+ binary.BigEndian.PutUint16(msg, uint16(len(msgPacket)))
+ copy(msg[2:], msgPacket)
+ } else {
+ msg, _ = m.Pack()
+ }
- // Open a UDP connection (using one to avoid client-side allocations)
- conn, err := net.DialUDP("udp", nil, srv.LocalAddr().(*net.UDPAddr))
- require.NoError(b, err)
+ // Open connection (using one to avoid client-side allocations).
+ conn, err := net.Dial(string(tc.network), addr)
+ require.NoError(b, err)
- // Prepare a buffer to read responses
- resBuf := make([]byte, 512)
+ // Prepare a buffer to read responses.
+ resBuf := make([]byte, 512)
- b.ReportAllocs()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- _, err = conn.Write(msg)
- require.NoError(b, err)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err = conn.Write(msg)
+ require.NoError(b, err)
- var n int
- n, err = conn.Read(resBuf)
- require.NoError(b, err)
- require.GreaterOrEqual(b, n, dnsserver.DNSHeaderSize)
+ err = readMsg(resBuf, tc.network, conn)
+ require.NoError(b, err)
+ }
+ b.StopTimer()
+ })
}
- b.StopTimer()
}
-func BenchmarkServeTCP(b *testing.B) {
- srv, _, err := dnsservertest.RunLocalDNSServer(
- dnsservertest.DefaultHandler(),
- dnsserver.ProtoDNSTCP)
- require.NoError(b, err)
+// readMsg is a helper function for reading DNS responses from a plain DNS
+// connection.
+func readMsg(resBuf []byte, network dnsserver.Network, conn net.Conn) (err error) {
+ defer func() { err = errors.Annotate(err, "failed to read DNS msg: %w", err) }()
- testutil.CleanupAndRequireSuccess(b, func() (err error) {
- return srv.Shutdown(context.Background())
- })
-
- // Prepare a test message
- m := new(dns.Msg)
- m.SetQuestion("example.org.", dns.TypeA)
- data, _ := m.Pack()
- msg := make([]byte, 2+len(data))
- binary.BigEndian.PutUint16(msg, uint16(len(data)))
- copy(msg[2:], data)
-
- // Open a TCP connection (using one to avoid client-side allocations)
- conn, err := net.DialTCP("tcp", nil, srv.LocalAddr().(*net.TCPAddr))
- require.NoError(b, err)
-
- // Prepare a buffer to read responses
- resBuf := make([]byte, 512)
-
- b.ReportAllocs()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- _, err = conn.Write(msg)
- require.NoError(b, err)
+ var n int
+ if network == dnsserver.NetworkTCP {
var length uint16
if err = binary.Read(conn, binary.BigEndian, &length); err != nil {
- b.Fatalf("failed to read the DNS query response: %v", err)
+ return err
}
- var n int
n, err = io.ReadFull(conn, resBuf[:length])
if err != nil {
- b.Fatalf("failed to read the DNS query response: %v", err)
+ return err
+ }
+ } else {
+ n, err = conn.Read(resBuf)
+ if err != nil {
+ return err
}
-
- require.GreaterOrEqual(b, n, dnsserver.DNSHeaderSize)
}
- b.StopTimer()
+
+ if n < dnsserver.DNSHeaderSize {
+ return dns.ErrShortRead
+ }
+
+ return nil
}
func BenchmarkServeTLS(b *testing.B) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
- srv, addr, err := dnsservertest.RunLocalTLSServer(
- dnsservertest.DefaultHandler(),
- tlsConfig,
- )
- require.NoError(b, err)
-
- testutil.CleanupAndRequireSuccess(b, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ addr := dnsservertest.RunTLSServer(b, dnsservertest.DefaultHandler(), tlsConfig)
// Prepare a test message
m := new(dns.Msg)
@@ -158,103 +148,142 @@ func BenchmarkServeTLS(b *testing.B) {
b.StopTimer()
}
-func BenchmarkServeHTTPS(b *testing.B) {
- proto := "https"
- tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
- srv, addr, err := dnsservertest.RunLocalHTTPSServer(
- dnsservertest.DefaultHandler(),
- tlsConfig,
- nil,
- )
- require.NoError(b, err)
+func BenchmarkServeDoH(b *testing.B) {
+ testCases := []struct {
+ name string
+ https bool
+ http3Enabled bool
+ }{{
+ name: "doh2",
+ https: true,
+ http3Enabled: false,
+ }, {
+ name: "doh3",
+ https: true,
+ http3Enabled: true,
+ }, {
+ name: "plain_http",
+ https: true,
+ http3Enabled: true,
+ }}
- testutil.CleanupAndRequireSuccess(b, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ for _, tc := range testCases {
+ b.Run(tc.name, func(b *testing.B) {
+ proto := "https"
+ if !tc.https {
+ proto = "http"
+ }
- // Prepare a test message
- m := new(dns.Msg)
- m.SetQuestion("example.org.", dns.TypeA)
- data, _ := m.Pack()
- msg := make([]byte, 2+len(data))
- binary.BigEndian.PutUint16(msg, uint16(len(data)))
- copy(msg[2:], data)
+ var tlsConfig *tls.Config
+ if tc.https {
+ tlsConfig = dnsservertest.CreateServerTLSConfig("example.org")
+ }
+ srv, err := dnsservertest.RunLocalHTTPSServer(
+ dnsservertest.DefaultHandler(),
+ tlsConfig,
+ nil,
+ )
+ require.NoError(b, err)
- // Prepare client
- client, err := createDoHClient(addr, tlsConfig)
- require.NoError(b, err)
+ testutil.CleanupAndRequireSuccess(b, func() (err error) {
+ return srv.Shutdown(context.Background())
+ })
- // Prepare http.Request
- req, err := createDoHRequest(proto, http.MethodPost, m)
- require.NoError(b, err)
+ // Prepare a test message.
+ m := new(dns.Msg)
+ m.SetQuestion("example.org.", dns.TypeA)
+ data, _ := m.Pack()
+ msg := make([]byte, 2+len(data))
+ binary.BigEndian.PutUint16(msg, uint16(len(data)))
+ copy(msg[2:], data)
- b.ReportAllocs()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- var res *http.Response
- res, err = client.Do(req)
- require.NoError(b, err)
+ // Prepare client.
+ addr := srv.LocalTCPAddr()
+ if tc.http3Enabled {
+ addr = srv.LocalUDPAddr()
+ }
- var buf []byte
- buf, err = io.ReadAll(res.Body)
- _ = res.Body.Close()
- require.NoError(b, err)
- require.GreaterOrEqual(b, len(buf), dnsserver.DNSHeaderSize)
+ client, err := createDoHClient(addr, tlsConfig)
+ require.NoError(b, err)
+
+ // Prepare http.Request.
+ req, err := createDoHRequest(proto, http.MethodPost, m)
+ require.NoError(b, err)
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ var res *http.Response
+ res, err = client.Do(req)
+ require.NoError(b, err)
+
+ var buf []byte
+ buf, err = io.ReadAll(res.Body)
+ _ = res.Body.Close()
+ require.NoError(b, err)
+ require.GreaterOrEqual(b, len(buf), dnsserver.DNSHeaderSize)
+ }
+ b.StopTimer()
+ })
}
- b.StopTimer()
}
-func BenchmarkServePlainHTTP(b *testing.B) {
- proto := "http"
- srv, addr, err := dnsservertest.RunLocalHTTPSServer(
- dnsservertest.DefaultHandler(),
- nil,
- nil,
- )
- require.NoError(b, err)
+func BenchmarkServeDNSCrypt(b *testing.B) {
+ testCases := []struct {
+ name string
+ network dnsserver.Network
+ }{{
+ name: "udp",
+ network: dnsserver.NetworkUDP,
+ }, {
+ name: "tcp",
+ network: dnsserver.NetworkTCP,
+ }}
- testutil.CleanupAndRequireSuccess(b, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ for _, tc := range testCases {
+ b.Run(tc.name, func(b *testing.B) {
+ // Create a test message
+ req := new(dns.Msg)
+ req.Id = dns.Id()
+ req.RecursionDesired = true
+ name := "example.org."
+ req.Question = []dns.Question{
+ {Name: name, Qtype: dns.TypeA, Qclass: dns.ClassINET},
+ }
- // Prepare a test message
- m := new(dns.Msg)
- m.SetQuestion("example.org.", dns.TypeA)
- data, _ := m.Pack()
- msg := make([]byte, 2+len(data))
- binary.BigEndian.PutUint16(msg, uint16(len(data)))
- copy(msg[2:], data)
+ client := &dnscrypt.Client{
+ Timeout: 1 * time.Second,
+ Net: string(tc.network),
+ }
- // Prepare client
- client, err := createDoHClient(addr, nil)
- require.NoError(b, err)
+ s := dnsservertest.RunDNSCryptServer(b, dnsservertest.DefaultHandler())
+ stamp := dnsstamps.ServerStamp{
+ ServerAddrStr: s.ServerAddr,
+ ServerPk: s.ResolverPk,
+ ProviderName: s.ProviderName,
+ Proto: dnsstamps.StampProtoTypeDNSCrypt,
+ }
- // Prepare http.Request
- req, err := createDoHRequest(proto, http.MethodPost, m)
- require.NoError(b, err)
+ // Load server info
+ ri, err := client.DialStamp(stamp)
+ require.NoError(b, err)
+ require.NotNil(b, ri)
- b.ReportAllocs()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- var res *http.Response
- res, err = client.Do(req)
- require.NoError(b, err)
+ // Open a single connection
+ conn, err := net.Dial(string(tc.network), stamp.ServerAddrStr)
+ require.NoError(b, err)
- var buf []byte
- buf, err = io.ReadAll(res.Body)
- _ = res.Body.Close()
- require.NoError(b, err)
- require.GreaterOrEqual(b, len(buf), dnsserver.DNSHeaderSize)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ var resp *dns.Msg
+ resp, err = client.ExchangeConn(conn, req, ri)
+ require.NoError(b, err)
+ require.True(b, resp.Response)
+ }
+ b.StopTimer()
+ })
}
- b.StopTimer()
-}
-
-func BenchmarkServeDNSCryptUDP(b *testing.B) {
- benchmarkServeDNSCrypt(b, dnsserver.NetworkUDP)
-}
-
-func BenchmarkServeDNSCryptTCP(b *testing.B) {
- benchmarkServeDNSCrypt(b, dnsserver.NetworkTCP)
}
func BenchmarkServeQUIC(b *testing.B) {
@@ -296,55 +325,3 @@ func BenchmarkServeQUIC(b *testing.B) {
}
b.StopTimer()
}
-
-func benchmarkServeDNSCrypt(b *testing.B, network dnsserver.Network) {
- s, err := dnsservertest.RunLocalDNSCryptServer(
- dnsservertest.DefaultHandler(),
- network,
- )
- require.NoError(b, err)
- b.Cleanup(func() {
- err = s.Srv.Shutdown(context.Background())
- require.NoError(b, err)
- })
-
- // Create a test message
- req := new(dns.Msg)
- req.Id = dns.Id()
- req.RecursionDesired = true
- name := "example.org."
- req.Question = []dns.Question{
- {Name: name, Qtype: dns.TypeA, Qclass: dns.ClassINET},
- }
-
- client := &dnscrypt.Client{
- Timeout: 1 * time.Second,
- Net: string(network),
- }
-
- stamp := dnsstamps.ServerStamp{
- ServerAddrStr: s.ServerAddr,
- ServerPk: s.ResolverPk,
- ProviderName: s.ProviderName,
- Proto: dnsstamps.StampProtoTypeDNSCrypt,
- }
-
- // Load server info
- ri, err := client.DialStamp(stamp)
- require.NoError(b, err)
- require.NotNil(b, ri)
-
- // Open a single connection
- conn, err := net.Dial(string(network), stamp.ServerAddrStr)
- require.NoError(b, err)
-
- b.ReportAllocs()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- var resp *dns.Msg
- resp, err = client.ExchangeConn(conn, req, ri)
- require.NoError(b, err)
- require.True(b, resp.Response)
- }
- b.StopTimer()
-}
diff --git a/internal/dnsserver/serverdns.go b/internal/dnsserver/serverdns.go
index 4e422c9..e65115b 100644
--- a/internal/dnsserver/serverdns.go
+++ b/internal/dnsserver/serverdns.go
@@ -2,11 +2,11 @@ package dnsserver
import (
"context"
- "fmt"
"net"
"sync"
"time"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
)
@@ -77,18 +77,16 @@ type ServerDNS struct {
// type check
var _ Server = (*ServerDNS)(nil)
-// NewServerDNS creates a new ServerDNS instance. conf.Proto must be either
-// [ProtoDNSTCP] or [ProtoDNSUDP].
+// NewServerDNS creates a new ServerDNS instance.
func NewServerDNS(conf ConfigDNS) (s *ServerDNS) {
- if !conf.Proto.IsPlain() {
- panic(fmt.Errorf("invalid proto %s in NewServerDNS", conf.Proto))
- }
-
- return newServerDNS(conf)
+ return newServerDNS(ProtoDNS, conf)
}
-func newServerDNS(conf ConfigDNS) (s *ServerDNS) {
- // Init default settings first
+// newServerDNS initializes a new ServerDNS instance with the specified proto.
+// This function is reused in ServerTLS as it is basically a plain DNS-over-TCP
+// server with a TLS layer on top of it.
+func newServerDNS(proto Protocol, conf ConfigDNS) (s *ServerDNS) {
+ // Init default settings first.
if conf.ReadTimeout == 0 {
conf.ReadTimeout = DefaultReadTimeout
}
@@ -108,7 +106,7 @@ func newServerDNS(conf ConfigDNS) (s *ServerDNS) {
}
s = &ServerDNS{
- ServerBase: newServerBase(conf.ConfigBase),
+ ServerBase: newServerBase(proto, conf.ConfigBase),
conf: conf,
}
@@ -120,8 +118,10 @@ func newServerDNS(conf ConfigDNS) (s *ServerDNS) {
return s
}
-// Start starts all listeners and starts processing queries.
+// Start implements the dnsserver.Server interface for *ServerDNS.
func (s *ServerDNS) Start(ctx context.Context) (err error) {
+ defer func() { err = errors.Annotate(err, "starting dns server: %w", err) }()
+
s.lock.Lock()
defer s.lock.Unlock()
@@ -138,9 +138,12 @@ func (s *ServerDNS) Start(ctx context.Context) (err error) {
Proto: s.proto,
})
- // Start listening to UDP on the specified addrs.
- switch s.proto {
- case ProtoDNSUDP:
+ if s.proto != ProtoDNS {
+ return ErrInvalidArgument
+ }
+
+ // Start listening to UDP on the specified address.
+ if s.network.CanUDP() {
err = s.listenUDP(ctx)
if err != nil {
return err
@@ -148,7 +151,10 @@ func (s *ServerDNS) Start(ctx context.Context) (err error) {
s.wg.Add(1)
go s.startServeUDP(ctx)
- case ProtoDNSTCP:
+ }
+
+ // Start listening to TCP on the specified address.
+ if s.network.CanTCP() {
err = s.listenTCP(ctx)
if err != nil {
return err
@@ -156,8 +162,6 @@ func (s *ServerDNS) Start(ctx context.Context) (err error) {
s.wg.Add(1)
go s.startServeTCP(ctx)
- default:
- return ErrInvalidArgument
}
log.Info("[%s]: Server has been started", s.Name())
@@ -165,8 +169,10 @@ func (s *ServerDNS) Start(ctx context.Context) (err error) {
return nil
}
-// Shutdown closes active connections and listeners (if they're not closed already).
+// Shutdown implements the dnsserver.Server interface for *ServerDNS.
func (s *ServerDNS) Shutdown(ctx context.Context) (err error) {
+ defer func() { err = errors.Annotate(err, "shutting down dns server: %w", err) }()
+
err = s.shutdown()
if err != nil {
log.Info("[%s]: Failed to shutdown: %v", s.Name(), err)
diff --git a/internal/dnsserver/serverdns_test.go b/internal/dnsserver/serverdns_test.go
index 64b8f79..1080986 100644
--- a/internal/dnsserver/serverdns_test.go
+++ b/internal/dnsserver/serverdns_test.go
@@ -12,29 +12,19 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
- "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/require"
)
func TestServerDNS_StartShutdown(t *testing.T) {
- srv, _, err := dnsservertest.RunLocalDNSServer(
- dnsservertest.DefaultHandler(),
- dnsserver.ProtoDNSUDP,
- )
- require.NoError(t, err)
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
- require.NoError(t, err)
+ _, _ = dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
}
func TestServerDNS_integration_query(t *testing.T) {
testCases := []struct {
- name string
- proto dnsserver.Protocol
- req *dns.Msg
+ name string
+ network dnsserver.Network
+ req *dns.Msg
// if nil, use defaultTestHandler
handler dnsserver.Handler
expectedRecordsCount int
@@ -43,7 +33,7 @@ func TestServerDNS_integration_query(t *testing.T) {
expectedMsg func(t *testing.T, m *dns.Msg)
}{{
name: "valid_udp_msg",
- proto: dnsserver.ProtoDNSUDP,
+ network: dnsserver.NetworkUDP,
expectedRecordsCount: 1,
expectedRCode: dns.RcodeSuccess,
req: &dns.Msg{
@@ -54,7 +44,7 @@ func TestServerDNS_integration_query(t *testing.T) {
},
}, {
name: "valid_tcp_msg",
- proto: dnsserver.ProtoDNSTCP,
+ network: dnsserver.NetworkTCP,
expectedRecordsCount: 1,
expectedRCode: dns.RcodeSuccess,
req: &dns.Msg{
@@ -67,7 +57,7 @@ func TestServerDNS_integration_query(t *testing.T) {
// This test checks that we remove unsupported EDNS0 options from
// the response.
name: "udp_edns0_supported_options",
- proto: dnsserver.ProtoDNSUDP,
+ network: dnsserver.NetworkUDP,
expectedRecordsCount: 1,
expectedRCode: dns.RcodeSuccess,
expectedMsg: func(t *testing.T, m *dns.Msg) {
@@ -107,7 +97,7 @@ func TestServerDNS_integration_query(t *testing.T) {
}, {
// Check that we reject invalid DNS messages (like having two questions)
name: "reject_msg",
- proto: dnsserver.ProtoDNSUDP,
+ network: dnsserver.NetworkUDP,
expectedRecordsCount: 0,
expectedRCode: dns.RcodeFormatError,
req: &dns.Msg{
@@ -120,7 +110,7 @@ func TestServerDNS_integration_query(t *testing.T) {
}, {
// Checks that we handle mixed case domain names
name: "udp_mixed_case",
- proto: dnsserver.ProtoDNSUDP,
+ network: dnsserver.NetworkUDP,
expectedRecordsCount: 1,
expectedRCode: dns.RcodeSuccess,
req: &dns.Msg{
@@ -133,7 +123,7 @@ func TestServerDNS_integration_query(t *testing.T) {
// Checks that we respond with NotImplemented to requests with OpcodeStatus
// also checks that Opcode is unchanged in the response
name: "not_implemented_msg",
- proto: dnsserver.ProtoDNSUDP,
+ network: dnsserver.NetworkUDP,
expectedRecordsCount: 0,
expectedRCode: dns.RcodeNotImplemented,
req: &dns.Msg{
@@ -146,7 +136,7 @@ func TestServerDNS_integration_query(t *testing.T) {
// Checks that we respond with SERVFAIL in case if the handler
// returns an error
name: "handler_failure",
- proto: dnsserver.ProtoDNSUDP,
+ network: dnsserver.NetworkUDP,
expectedRecordsCount: 0,
expectedRCode: dns.RcodeServerFailure,
handler: dnsserver.HandlerFunc(func(
@@ -166,7 +156,7 @@ func TestServerDNS_integration_query(t *testing.T) {
// Checks that Z flag is set to zero even when the query has it
// See https://github.com/miekg/dns/issues/975
name: "msg_with_zflag",
- proto: dnsserver.ProtoDNSUDP,
+ network: dnsserver.NetworkUDP,
expectedRecordsCount: 1,
expectedRCode: dns.RcodeSuccess,
req: &dns.Msg{
@@ -178,8 +168,8 @@ func TestServerDNS_integration_query(t *testing.T) {
}, {
// Checks that large responses are getting truncated when
// sent over UDP
- name: "udp_truncate_response",
- proto: dnsserver.ProtoDNSUDP,
+ name: "udp_truncate_response",
+ network: dnsserver.NetworkUDP,
// Set a handler that generates a large response
handler: dnsservertest.CreateTestHandler(64),
expectedRecordsCount: 0,
@@ -194,8 +184,8 @@ func TestServerDNS_integration_query(t *testing.T) {
}, {
// Checks that if UDP size is large enough there would be no
// truncated responses
- name: "udp_edns0_no_truncate",
- proto: dnsserver.ProtoDNSUDP,
+ name: "udp_edns0_no_truncate",
+ network: dnsserver.NetworkUDP,
// Set a handler that generates a large response
handler: dnsservertest.CreateTestHandler(64),
expectedRecordsCount: 64,
@@ -219,8 +209,8 @@ func TestServerDNS_integration_query(t *testing.T) {
}, {
// Checks that large responses are NOT truncated when
// sent over UDP
- name: "tcp_no_truncate_response",
- proto: dnsserver.ProtoDNSTCP,
+ name: "tcp_no_truncate_response",
+ network: dnsserver.NetworkTCP,
// Set a handler that generates a large response
handler: dnsservertest.CreateTestHandler(64),
// No truncate
@@ -241,21 +231,12 @@ func TestServerDNS_integration_query(t *testing.T) {
if tc.handler != nil {
handler = tc.handler
}
- srv, addr, err := dnsservertest.RunLocalDNSServer(handler, tc.proto)
- require.NoError(t, err)
- require.Equal(t, tc.proto, srv.Proto())
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ _, addr := dnsservertest.RunDNSServer(t, handler)
// Send this test message to our server over UDP
c := new(dns.Client)
- c.Net = "udp"
+ c.Net = string(tc.network)
c.UDPSize = 7000 // need to be set to read large responses
- if tc.proto == dnsserver.ProtoDNSTCP {
- c.Net = "tcp"
- }
res, _, err := c.Exchange(tc.req, addr)
require.NoError(t, err)
@@ -270,19 +251,10 @@ func TestServerDNS_integration_query(t *testing.T) {
}
func TestServerDNS_integration_tcpQueriesPipelining(t *testing.T) {
- // As per RFC 7766 we should support queries pipelining for TCP,
- // i.e. we should be able to process incoming queries in parallel and
- // write responses out of order.
- srv, addr, err := dnsservertest.RunLocalDNSServer(
- dnsservertest.DefaultHandler(),
- dnsserver.ProtoDNSTCP,
- )
- require.NoError(t, err)
- require.Equal(t, dnsserver.ProtoDNSTCP, srv.Proto())
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ // As per RFC 7766 we should support queries pipelining for TCP, that is we
+ // should be able to process incoming queries in parallel and write
+ // responses out of order.
+ _, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
// First - establish a connection
conn, err := net.Dial("tcp", addr)
@@ -348,17 +320,7 @@ func TestServerDNS_integration_tcpQueriesPipelining(t *testing.T) {
}
func TestServerDNS_integration_udpMsgIgnore(t *testing.T) {
- srv, addr, err := dnsservertest.RunLocalDNSServer(
- dnsservertest.DefaultHandler(),
- dnsserver.ProtoDNSUDP,
- )
- require.NoError(t, err)
- require.Equal(t, dnsserver.ProtoDNSUDP, srv.Proto())
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
-
+ _, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
conn, err := net.Dial("udp", addr)
require.Nil(t, err)
@@ -449,17 +411,7 @@ func TestServerDNS_integration_tcpMsgIgnore(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- srv, addr, err := dnsservertest.RunLocalDNSServer(
- dnsservertest.DefaultHandler(),
- dnsserver.ProtoDNSTCP,
- )
- require.NoError(t, err)
- require.Equal(t, dnsserver.ProtoDNSTCP, srv.Proto())
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
-
+ _, addr := dnsservertest.RunDNSServer(t, dnsservertest.DefaultHandler())
conn, err := net.Dial("tcp", addr)
require.Nil(t, err)
diff --git a/internal/dnsserver/serverdnscrypt.go b/internal/dnsserver/serverdnscrypt.go
index b3a1123..33be7d0 100644
--- a/internal/dnsserver/serverdnscrypt.go
+++ b/internal/dnsserver/serverdnscrypt.go
@@ -2,7 +2,6 @@ package dnsserver
import (
"context"
- "net"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
@@ -40,16 +39,23 @@ var _ Server = (*ServerDNSCrypt)(nil)
// NewServerDNSCrypt creates a new instance of ServerDNSCrypt.
func NewServerDNSCrypt(conf ConfigDNSCrypt) (s *ServerDNSCrypt) {
return &ServerDNSCrypt{
- ServerBase: newServerBase(conf.ConfigBase),
+ ServerBase: newServerBase(ProtoDNSCrypt, conf.ConfigBase),
conf: conf,
}
}
-// Start starts the server and starts processing queries.
+// Start implements the dnsserver.Server interface for *ServerDNSCrypt.
func (s *ServerDNSCrypt) Start(ctx context.Context) (err error) {
+ defer func() { err = errors.Annotate(err, "starting dnscrypt server: %w", err) }()
+
s.lock.Lock()
defer s.lock.Unlock()
+ // First, validate the protocol.
+ if s.proto != ProtoDNSCrypt {
+ return ErrInvalidArgument
+ }
+
if s.started {
return ErrServerAlreadyStarted
}
@@ -72,23 +78,9 @@ func (s *ServerDNSCrypt) Start(ctx context.Context) (err error) {
},
}
- switch s.proto {
- case ProtoDNSCryptUDP:
- err = s.listenUDP(ctx)
- if err != nil {
- return err
- }
-
- go s.startServeUDP(ctx)
- case ProtoDNSCryptTCP:
- err = s.listenTCP(ctx)
- if err != nil {
- return err
- }
-
- go s.startServeTCP(ctx)
- default:
- return ErrInvalidArgument
+ err = s.startServe(ctx)
+ if err != nil {
+ return err
}
log.Info("[%s]: Server has been started", s.Name())
@@ -96,8 +88,10 @@ func (s *ServerDNSCrypt) Start(ctx context.Context) (err error) {
return nil
}
-// Shutdown closes active connections and listeners (if they're not closed already).
+// Shutdown implements the dnsserver.Server interface for *ServerDNSCrypt.
func (s *ServerDNSCrypt) Shutdown(ctx context.Context) (err error) {
+ defer func() { err = errors.Annotate(err, "shutting down dnscrypt server: %w", err) }()
+
log.Info("[%s]: Stopping the server", s.Name())
err = s.shutdown()
if err != nil {
@@ -112,6 +106,29 @@ func (s *ServerDNSCrypt) Shutdown(ctx context.Context) (err error) {
return err
}
+// startServe creates listeners and starts serving DNSCrypt.
+func (s *ServerDNSCrypt) startServe(ctx context.Context) (err error) {
+ if s.network.CanUDP() {
+ err = s.listenUDP(ctx)
+ if err != nil {
+ return err
+ }
+
+ go s.startServeUDP(ctx)
+ }
+
+ if s.network.CanTCP() {
+ err = s.listenTCP(ctx)
+ if err != nil {
+ return err
+ }
+
+ go s.startServeTCP(ctx)
+ }
+
+ return nil
+}
+
// startServeUDP starts the UDP listener loop.
func (s *ServerDNSCrypt) startServeUDP(ctx context.Context) {
// We do not recover from panics here since if this go routine panics
@@ -186,48 +203,9 @@ func (h *dnsCryptHandler) ServeDNS(rw dnscrypt.ResponseWriter, r *dns.Msg) (err
return rw.WriteMsg(genErrorResponse(r, dns.RcodeServerFailure))
}
- network := NetworkUDP
- if h.srv.proto == ProtoDNSCryptTCP {
- network = NetworkTCP
- }
-
+ network := NetworkFromAddr(rw.LocalAddr())
msg := nrw.Msg()
normalize(network, r, msg)
return rw.WriteMsg(msg)
}
-
-// listenUDP creates the UDP listener for the ServerDNSCrypt.addr.
-func (s *ServerDNSCrypt) listenUDP(ctx context.Context) (err error) {
- var l net.PacketConn
- l, err = listenUDP(ctx, s.addr)
- if err != nil {
- return err
- }
-
- u, ok := l.(*net.UDPConn)
- if !ok {
- return ErrInvalidArgument
- }
-
- if err = setUDPSocketOptions(u); err != nil {
- return err
- }
-
- s.udpListener = u
-
- return nil
-}
-
-// listenTCP creates the TCP listener for the ServerDNSCrypt.addr.
-func (s *ServerDNSCrypt) listenTCP(ctx context.Context) (err error) {
- var l net.Listener
- l, err = listenTCP(ctx, s.addr)
- if err != nil {
- return err
- }
-
- s.tcpListener = l
-
- return nil
-}
diff --git a/internal/dnsserver/serverdnscrypt_test.go b/internal/dnsserver/serverdnscrypt_test.go
index 9f5c907..c77205a 100644
--- a/internal/dnsserver/serverdnscrypt_test.go
+++ b/internal/dnsserver/serverdnscrypt_test.go
@@ -1,7 +1,6 @@
package dnsserver_test
import (
- "context"
"testing"
"time"
@@ -15,9 +14,9 @@ import (
func TestServerDNSCrypt_integration_query(t *testing.T) {
testCases := []struct {
- name string
- proto dnsserver.Protocol
- req *dns.Msg
+ name string
+ network dnsserver.Network
+ req *dns.Msg
// if nil, use DefaultTestHandler
handler dnsserver.Handler
expectedRecordsCount int
@@ -25,7 +24,7 @@ func TestServerDNSCrypt_integration_query(t *testing.T) {
expectedTruncated bool
}{{
name: "udp_valid_msg",
- proto: dnsserver.ProtoDNSCryptUDP,
+ network: dnsserver.NetworkUDP,
expectedRecordsCount: 1,
expectedRCode: dns.RcodeSuccess,
req: &dns.Msg{
@@ -36,7 +35,7 @@ func TestServerDNSCrypt_integration_query(t *testing.T) {
},
}, {
name: "tcp_valid_msg",
- proto: dnsserver.ProtoDNSCryptTCP,
+ network: dnsserver.NetworkTCP,
expectedRecordsCount: 1,
expectedRCode: dns.RcodeSuccess,
req: &dns.Msg{
@@ -48,8 +47,8 @@ func TestServerDNSCrypt_integration_query(t *testing.T) {
}, {
// Checks that large responses are getting truncated when
// sent over UDP
- name: "udp_truncate_response",
- proto: dnsserver.ProtoDNSCryptUDP,
+ name: "udp_truncate_response",
+ network: dnsserver.NetworkUDP,
// Set a handler that generates a large response
handler: dnsservertest.CreateTestHandler(64),
// DNSCrypt server removes all records from a truncated response
@@ -65,8 +64,8 @@ func TestServerDNSCrypt_integration_query(t *testing.T) {
}, {
// Checks that if UDP size is large enough there would be no
// truncated responses
- name: "udp_edns0_no_truncate",
- proto: dnsserver.ProtoDNSCryptUDP,
+ name: "udp_edns0_no_truncate",
+ network: dnsserver.NetworkUDP,
// Set a handler that generates a large response
handler: dnsservertest.CreateTestHandler(64),
expectedRecordsCount: 64,
@@ -89,26 +88,15 @@ func TestServerDNSCrypt_integration_query(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- network := dnsserver.NetworkUDP
- if tc.proto == dnsserver.ProtoDNSCryptTCP {
- network = dnsserver.NetworkTCP
- }
handler := tc.handler
if tc.handler == nil {
handler = dnsservertest.DefaultHandler()
}
- s, err := dnsservertest.RunLocalDNSCryptServer(handler, network)
- require.NoError(t, err)
- require.Equal(t, tc.proto, s.Srv.Proto())
-
- defer func() {
- err = s.Srv.Shutdown(context.Background())
- require.NoError(t, err)
- }()
+ s := dnsservertest.RunDNSCryptServer(t, handler)
client := &dnscrypt.Client{
Timeout: 1 * time.Second,
- Net: string(network),
+ Net: string(tc.network),
UDPSize: 7000, // Make sure that we can read any response
}
diff --git a/internal/dnsserver/serverdnstcp.go b/internal/dnsserver/serverdnstcp.go
index 06421e9..65d8f6a 100644
--- a/internal/dnsserver/serverdnstcp.go
+++ b/internal/dnsserver/serverdnstcp.go
@@ -16,19 +16,6 @@ import (
"github.com/miekg/dns"
)
-// listenTCP creates a TCP listener for the ServerDNS.addr.
-func (s *ServerDNS) listenTCP(ctx context.Context) (err error) {
- var l net.Listener
- l, err = listenTCP(ctx, s.addr)
- if err != nil {
- return err
- }
-
- s.tcpListener = l
-
- return nil
-}
-
// serveTCP runs the TCP serving loop.
func (s *ServerDNS) serveTCP(ctx context.Context, l net.Listener) (err error) {
defer log.OnCloserError(l, log.DEBUG)
@@ -108,7 +95,7 @@ func (s *ServerDNS) serveTCPConn(ctx context.Context, conn net.Conn) {
reqCtx := s.requestContext()
ci := ClientInfo{}
- if cs, ok := conn.(tlsConnecionStater); ok {
+ if cs, ok := conn.(tlsConnectionStater); ok {
ci.TLSServerName = strings.ToLower(cs.ConnectionState().ServerName)
}
reqCtx = ContextWithClientInfo(reqCtx, ci)
@@ -120,9 +107,9 @@ func (s *ServerDNS) serveTCPConn(ctx context.Context, conn net.Conn) {
}
}
-// tlsConnecionStater is a common interface for connections that can return
+// tlsConnectionStater is a common interface for connections that can return
// a TLS connection state.
-type tlsConnecionStater interface {
+type tlsConnectionStater interface {
ConnectionState() tls.ConnectionState
}
diff --git a/internal/dnsserver/serverdnsudp.go b/internal/dnsserver/serverdnsudp.go
index 98fa7c9..09302bc 100644
--- a/internal/dnsserver/serverdnsudp.go
+++ b/internal/dnsserver/serverdnsudp.go
@@ -14,27 +14,6 @@ import (
"golang.org/x/net/ipv6"
)
-// listenUDP creates a UDP listener for the ServerDNS.addr.
-func (s *ServerDNS) listenUDP(ctx context.Context) (err error) {
- l, err := listenUDP(ctx, s.addr)
- if err != nil {
- return err
- }
-
- u, ok := l.(*net.UDPConn)
- if !ok {
- return ErrInvalidArgument
- }
-
- if err = setUDPSocketOptions(u); err != nil {
- return err
- }
-
- s.udpListener = u
-
- return nil
-}
-
// serveUDP runs the UDP serving loop.
func (s *ServerDNS) serveUDP(ctx context.Context, conn *net.UDPConn) (err error) {
defer log.OnCloserError(conn, log.DEBUG)
diff --git a/internal/dnsserver/serverhttps.go b/internal/dnsserver/serverhttps.go
index 31ba690..0036e20 100644
--- a/internal/dnsserver/serverhttps.go
+++ b/internal/dnsserver/serverhttps.go
@@ -14,8 +14,11 @@ import (
"strings"
"time"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
+ "github.com/lucas-clemente/quic-go"
+ "github.com/lucas-clemente/quic-go/http3"
"github.com/miekg/dns"
"golang.org/x/net/http2"
)
@@ -37,18 +40,27 @@ const (
httpIdleTimeout = 120 * time.Second
)
-// nextProtoDoH is a list of ALPN that we would add by default to the server
+// nextProtoDoH is a list of ALPN that we would add by default to the server's
// *tls.Config if no NextProto is specified there. Note, that with this order,
// we prioritize HTTP/2 over HTTP/1.1.
var nextProtoDoH = []string{http2.NextProtoTLS, "http/1.1"}
+// nextProtoDoH3 is a list of ALPN that we should add by default to the server's
+// *tls.Config if no NextProto is specified there and DoH3 is supposed to be
+// used.
+var nextProtoDoH3 = []string{"h3", http2.NextProtoTLS, "http/1.1"}
+
// ConfigHTTPS is a struct that needs to be passed to NewServerHTTPS to
-// initialize a new ServerHTTPS instance.
+// initialize a new ServerHTTPS instance. You can choose whether HTTP/3 is
+// enabled or not by specifying [ConfigBase.Network]. By default, the server
+// will listen to both HTTP/2 and HTTP/3, but if you set it to NetworkTCP, the
+// server will only use HTTP/2 and NetworkUDP will mean HTTP/3 only.
type ConfigHTTPS struct {
ConfigBase
- // TLSConfig is the TLS configuration for HTTPS.
- // if not set, we'll run a plain HTTP server.
+ // TLSConfig is the TLS configuration for HTTPS. If not set and
+ // [ConfigBase.Network] is set to NetworkTCP the server will listen to
+ // plain HTTP.
TLSConfig *tls.Config
// NonDNSHandler handles requests with the path not equal to /dns-query.
@@ -63,8 +75,17 @@ type ConfigHTTPS struct {
type ServerHTTPS struct {
*ServerBase
+ // httpServer is an instance of an *http.Server that is responsible for
+ // handling HTTP/1.1 and HTTP/2 requests.
httpServer *http.Server
+ // h3Server is an instance of an *http.Server that is responsible for
+ // handling HTTP/3 requests.
+ h3Server *http3.Server
+
+ // quicListener is a listener that we use to serve DoH3 requests.
+ quicListener quic.EarlyListener
+
conf ConfigHTTPS
}
@@ -73,21 +94,18 @@ var _ Server = (*ServerHTTPS)(nil)
// NewServerHTTPS creates a new ServerHTTPS instance.
func NewServerHTTPS(conf ConfigHTTPS) (s *ServerHTTPS) {
- tlsConfig := conf.TLSConfig
- if tlsConfig != nil && len(tlsConfig.NextProtos) == 0 {
- tlsConfig.NextProtos = nextProtoDoH
- }
-
s = &ServerHTTPS{
- ServerBase: newServerBase(conf.ConfigBase),
+ ServerBase: newServerBase(ProtoDoH, conf.ConfigBase),
conf: conf,
}
return s
}
-// Start starts the ServerHTTPS.
+// Start implements the dnsserver.Server interface for *ServerHTTPS.
func (s *ServerHTTPS) Start(ctx context.Context) (err error) {
+ defer func() { err = errors.Annotate(err, "starting doh server: %w", err) }()
+
s.lock.Lock()
defer s.lock.Unlock()
@@ -104,37 +122,33 @@ func (s *ServerHTTPS) Start(ctx context.Context) (err error) {
Proto: s.proto,
})
- // Start the TLS or TCP listener
- err = s.listenTLS(ctx)
- if err != nil {
- return err
+ if s.proto != ProtoDoH {
+ return ErrInvalidArgument
}
- // Prepare and run the HTTP server
- handler := &httpHandler{
- srv: s,
- listener: s.tcpListener,
+ if s.network.CanTCP() {
+ err = s.startHTTPSServer(ctx)
+ if err != nil {
+ return err
+ }
}
- s.httpServer = &http.Server{
- Handler: handler,
- ReadTimeout: httpReadTimeout,
- ReadHeaderTimeout: httpReadTimeout,
- WriteTimeout: httpWriteTimeout,
- IdleTimeout: httpIdleTimeout,
- ErrorLog: log.StdLog("dnsserver/serverhttps: "+s.name, log.DEBUG),
+ if s.network.CanUDP() {
+ err = s.startH3Server(ctx)
+ if err != nil {
+ return err
+ }
}
- // Start the server thread
- s.wg.Add(1)
- go s.serveHTTPS(ctx, s.httpServer, s.tcpListener)
log.Info("[%s]: Server has been started", s.Name())
return nil
}
-// Shutdown stops the ServerHTTPS.
+// Shutdown implements the dnsserver.Server interface for *ServerHTTPS.
func (s *ServerHTTPS) Shutdown(ctx context.Context) (err error) {
+ defer func() { err = errors.Annotate(err, "shutting down doh server: %w", err) }()
+
log.Info("[%s]: Stopping the server", s.Name())
err = s.shutdown(ctx)
if err != nil {
@@ -149,6 +163,63 @@ func (s *ServerHTTPS) Shutdown(ctx context.Context) (err error) {
return err
}
+// startHTTPSServer starts the HTTPS server that will handle HTTP/1.1 and HTTP2.
+func (s *ServerHTTPS) startHTTPSServer(ctx context.Context) (err error) {
+ // Start the TLS or TCP listener.
+ err = s.listenTLS(ctx)
+ if err != nil {
+ return err
+ }
+
+ // Prepare and run the HTTP server.
+ handler := &httpHandler{
+ srv: s,
+ localAddr: s.tcpListener.Addr(),
+ }
+
+ // Create an instance of the HTTP server.
+ s.httpServer = &http.Server{
+ Handler: handler,
+ ReadTimeout: httpReadTimeout,
+ ReadHeaderTimeout: httpReadTimeout,
+ WriteTimeout: httpWriteTimeout,
+ IdleTimeout: httpIdleTimeout,
+ ErrorLog: log.StdLog("dnsserver/serverhttps: "+s.name, log.DEBUG),
+ }
+
+ // Start the server worker goroutine.
+ s.wg.Add(1)
+ go s.serveHTTPS(ctx, s.httpServer, s.tcpListener)
+
+ return nil
+}
+
+// startH3Server starts the HTTP/3 server.
+func (s *ServerHTTPS) startH3Server(ctx context.Context) (err error) {
+ // Start the QUIC listener.
+ err = s.listenQUIC(ctx)
+ if err != nil {
+ return err
+ }
+
+ // Prepare and run the HTTP/3 server.
+ handler := &httpHandler{
+ srv: s,
+ localAddr: s.quicListener.Addr(),
+ }
+
+ // Create an instance of the HTTP/3 server.
+ s.h3Server = &http3.Server{
+ Handler: handler,
+ }
+
+ // Start the server worker goroutine.
+ s.wg.Add(1)
+ go s.serveH3(ctx, s.h3Server, s.quicListener)
+
+ return nil
+}
+
// shutdown marks the server as stopped and closes active listeners.
func (s *ServerHTTPS) shutdown(ctx context.Context) (err error) {
s.lock.Lock()
@@ -159,19 +230,33 @@ func (s *ServerHTTPS) shutdown(ctx context.Context) (err error) {
s.started = false
- // First step, close the active listener right away
+ // First step, close the active listener right away.
s.closeListeners()
- // Second, shutdown the HTTP server
+ // Second, shutdown the HTTP server.
err = s.httpServer.Shutdown(ctx)
if err != nil {
log.Debug("[%s]: http server shutdown: %v", s.Name(), err)
}
+ // Finally, shutdown the HTTP/3 server.
+ if s.h3Server != nil {
+ err = s.quicListener.Close()
+ if err != nil {
+ log.Debug("[%s]: quic listener shutdown: %v", s.Name(), err)
+ }
+
+ err = s.h3Server.Close()
+ if err != nil {
+ log.Debug("[%s]: http/3 server shutdown: %v", s.Name(), err)
+ }
+ }
+
return nil
}
-// serveHTTPS is a worker goroutine that serves HTTP.
+// serveHTTPS is launched in a worker goroutine and serves HTTP/1.1 and HTTP/2
+// requests.
func (s *ServerHTTPS) serveHTTPS(ctx context.Context, hs *http.Server, l net.Listener) {
defer s.wg.Done()
@@ -196,16 +281,62 @@ func (s *ServerHTTPS) serveHTTPS(ctx context.Context, hs *http.Server, l net.Lis
}
}
+// serveH3 is launched in a worker goroutine and serves HTTP/3 requests.
+func (s *ServerHTTPS) serveH3(ctx context.Context, hs *http3.Server, ql quic.EarlyListener) {
+ defer s.wg.Done()
+
+ // Do not recover from panics here since if this goroutine panics, the
+ // application won't be able to continue listening to DoH.
+ defer s.handlePanicAndExit(ctx)
+
+ u := &url.URL{
+ Scheme: "h3",
+ Host: s.addr,
+ }
+ log.Info("[%s]: Start listening to %s", s.name, u)
+
+ err := hs.ServeListener(ql)
+ if err != nil {
+ log.Info("[%s]: Finished listening to %s due to %v", s.name, u, err)
+ }
+}
+
// httpHandler is a helper structure that implements http.Handler
// and holds pointers to ServerHTTPS, net.Listener.
type httpHandler struct {
- srv *ServerHTTPS
- listener net.Listener
+ srv *ServerHTTPS
+ localAddr net.Addr
}
// type check
var _ http.Handler = (*httpHandler)(nil)
+// remoteAddr gets HTTP request's remote address.
+//
+// TODO(a.garipov): Add trusted proxies and real IP extraction logic. Perhaps
+// just copy from module dnsproxy if that one fits. Also, perhaps make that
+// logic pluggable and put it into a new package in module golibs.
+func (h *httpHandler) remoteAddr(r *http.Request) (addr net.Addr) {
+ // Consider that the http.Request.RemoteAddr documentation is correct and
+ // that it is always a valid ip:port value. Panic if it isn't so.
+ ipStr, port, err := netutil.SplitHostPort(r.RemoteAddr)
+ if err != nil {
+ panic(fmt.Sprintf("failed to split host:port %s: %v", r.RemoteAddr, err))
+ }
+
+ ip, err := netutil.ParseIP(ipStr)
+ if err != nil {
+ panic(fmt.Sprintf("failed to parse IP %s: %v", ipStr, err))
+ }
+
+ if NetworkFromAddr(h.localAddr) == NetworkUDP {
+ // This means that we're extracting remoteAddr from an HTTP/3 request.
+ return &net.UDPAddr{IP: ip, Port: port}
+ }
+
+ return &net.TCPAddr{IP: ip, Port: port}
+}
+
// ServeHTTP implements the http.Handler interface for *httpHandler. It reads
// the DNS data from the request, resolves it, and sends a response.
//
@@ -250,17 +381,18 @@ func (h *httpHandler) serveDoH(ctx context.Context, w http.ResponseWriter, r *ht
return
}
- rAddr := remoteAddr(r)
- lAddr := h.listener.Addr()
+ rAddr := h.remoteAddr(r)
+ lAddr := h.localAddr
rw := NewNonWriterResponseWriter(lAddr, rAddr)
- ci := ClientInfo{
- URL: netutil.CloneURL(r.URL),
+ ctx, err = httpContextWithClientInfo(ctx, r)
+ if err != nil {
+ log.Debug("Failed to enrich DoH context: %v", err)
+ h.srv.metrics.OnInvalidMsg(ctx)
+ http.Error(w, err.Error(), http.StatusBadRequest)
+
+ return
}
- if r.TLS != nil {
- ci.TLSServerName = strings.ToLower(r.TLS.ServerName)
- }
- ctx = ContextWithClientInfo(ctx, ci)
// Serve the query
written := h.srv.serveDNS(ctx, m, rw)
@@ -335,22 +467,83 @@ func (h *httpHandler) writeResponse(
return err
}
-// listenTCP starts the TCP/TLS listener.
+// listenTCP starts the TCP/TLS listener. Note that if there's no TLS config,
+// a plain TCP listener will be started instead.
func (s *ServerHTTPS) listenTLS(ctx context.Context) (err error) {
- l, err := listenTCP(ctx, s.addr)
+ err = s.listenTCP(ctx)
if err != nil {
return err
}
- if s.conf.TLSConfig != nil {
- l = tls.NewListener(l, s.conf.TLSConfig)
+ // Prepare the TLS configuration of the server.
+ tlsConf := s.conf.TLSConfig
+ if tlsConf == nil {
+ return nil
+ } else if len(tlsConf.NextProtos) == 0 {
+ tlsConf = tlsConf.Clone()
+ tlsConf.NextProtos = nextProtoDoH
}
- s.tcpListener = l
+ s.tcpListener = tls.NewListener(s.tcpListener, tlsConf)
return nil
}
+// listenQUIC starts a QUIC listener that will be used to serve HTTP/3 requests.
+func (s *ServerHTTPS) listenQUIC(ctx context.Context) (err error) {
+ // Prepare the TLS configuration of the server.
+ tlsConf := s.conf.TLSConfig
+ if tlsConf != nil && len(tlsConf.NextProtos) == 0 {
+ tlsConf = tlsConf.Clone()
+ tlsConf.NextProtos = nextProtoDoH3
+ }
+
+ // Do not enable OOB here as quic-go will do that on its own.
+ conn, err := listenUDP(ctx, s.addr, false)
+ if err != nil {
+ return err
+ }
+
+ qConf := newServerQUICConfig(s.metrics)
+ ql, err := quic.ListenEarly(conn, tlsConf, qConf)
+ if err != nil {
+ return err
+ }
+
+ s.udpListener = conn
+ s.quicListener = ql
+
+ return nil
+}
+
+// httpContextWithClientInfo adds client info to the context.
+func httpContextWithClientInfo(
+ parent context.Context,
+ r *http.Request,
+) (ctx context.Context, err error) {
+ ci := ClientInfo{
+ URL: netutil.CloneURL(r.URL),
+ }
+
+ // Due to the quic-go bug we should use Host instead of r.TLS:
+ // https://github.com/lucas-clemente/quic-go/issues/3596
+ //
+ // TODO(ameshkov): remove this when the bug is fixed in quic-go.
+ if r.ProtoAtLeast(3, 0) {
+ var host string
+ host, err = netutil.SplitHost(r.Host)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse Host: %w", err)
+ }
+
+ ci.TLSServerName = host
+ } else if r.TLS != nil {
+ ci.TLSServerName = strings.ToLower(r.TLS.ServerName)
+ }
+
+ return ContextWithClientInfo(parent, ci), nil
+}
+
// httpRequestToMsg reads the DNS message from http.Request.
func httpRequestToMsg(req *http.Request) (b []byte, err error) {
_, isJSON, _ := isDoH(req)
@@ -389,28 +582,6 @@ func httpRequestToMsgGet(req *http.Request) (b []byte, err error) {
return base64.RawURLEncoding.DecodeString(b64[0])
}
-// remoteAddr gets HTTP request's remote address.
-//
-// TODO(a.garipov): Add trusted proxies and real IP extraction logic. Perhaps
-// just copy from module dnsproxy if that one fits. Also, perhaps make that
-// logic pluggable and put it into a new package in module golibs.
-func remoteAddr(r *http.Request) (addr *net.TCPAddr) {
- // Consider that the http.Request.RemoteAddr documentation is correct and
- // that it is always a valid ip:port value. Panic if it isn't so.
- ipStr, port, err := netutil.SplitHostPort(r.RemoteAddr)
- if err != nil {
- panic(err)
- }
-
- ip, err := netutil.ParseIP(ipStr)
- if err != nil {
- panic(err)
- }
-
- // TODO(a.garipov): Return a *net.UDPAddr when we're HTTP/3-ready.
- return &net.TCPAddr{IP: ip, Port: port}
-}
-
// isDoH returns true if r.URL.Path contains DNS-over-HTTP paths, and also what
// content type is desired by the user. isJSON is true if the user uses the
// JSON API. ct can be either MimeTypeDoH or MimeTypeJSON.
diff --git a/internal/dnsserver/serverhttps_test.go b/internal/dnsserver/serverhttps_test.go
index 95d6252..dff806f 100644
--- a/internal/dnsserver/serverhttps_test.go
+++ b/internal/dnsserver/serverhttps_test.go
@@ -19,6 +19,8 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/testutil"
+ "github.com/lucas-clemente/quic-go"
+ "github.com/lucas-clemente/quic-go/http3"
"github.com/miekg/dns"
"github.com/stretchr/testify/require"
"golang.org/x/net/http2"
@@ -26,11 +28,12 @@ import (
func TestServerHTTPS_integration_serveRequests(t *testing.T) {
testCases := []struct {
- name string
- method string
- tls bool
- json bool
- requestWireformat bool
+ name string
+ method string
+ tls bool
+ json bool
+ reqWireFormat bool
+ http3Enabled bool
}{{
name: "doh_get_wireformat",
method: http.MethodGet,
@@ -72,27 +75,35 @@ func TestServerHTTPS_integration_serveRequests(t *testing.T) {
tls: false,
json: true,
}, {
- name: "doh_get_json_wireformat",
- method: http.MethodGet,
- tls: true,
- json: true,
- requestWireformat: true,
+ name: "doh_get_json_wireformat",
+ method: http.MethodGet,
+ tls: true,
+ json: true,
+ reqWireFormat: true,
}, {
- name: "doh_post_json_wireformat",
- method: http.MethodPost,
- tls: true,
- json: true,
- requestWireformat: true,
+ name: "doh_post_json_wireformat",
+ method: http.MethodPost,
+ tls: true,
+ json: true,
+ reqWireFormat: true,
+ }, {
+ name: "doh3_get_wireformat",
+ method: http.MethodGet,
+ tls: true,
+ json: false,
+ http3Enabled: true,
+ }, {
+ name: "doh3_post_wireformat",
+ method: http.MethodPost,
+ tls: true,
+ json: false,
+ http3Enabled: true,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- var tlsConfig *tls.Config
- if tc.tls {
- tlsConfig = dnsservertest.CreateServerTLSConfig("example.org")
- }
-
- srv, addr, err := dnsservertest.RunLocalHTTPSServer(
+ tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
+ srv, err := dnsservertest.RunLocalHTTPSServer(
dnsservertest.DefaultHandler(),
tlsConfig,
nil,
@@ -113,16 +124,12 @@ func TestServerHTTPS_integration_serveRequests(t *testing.T) {
}
var resp *dns.Msg
- resp, err = sendDoHRequest(
- addr,
- tlsConfig,
- tc.method,
- tc.json,
- tc.requestWireformat,
- req,
- )
- require.NoError(t, err)
- require.NotNil(t, resp)
+ addr := srv.LocalTCPAddr()
+ if tc.http3Enabled {
+ addr = srv.LocalUDPAddr()
+ }
+
+ resp = mustDoHReq(t, addr, tlsConfig, tc.method, tc.json, tc.reqWireFormat, req)
require.True(t, resp.Response)
})
}
@@ -134,7 +141,7 @@ func TestServerHTTPS_integration_nonDNSHandler(t *testing.T) {
_, _ = w.Write([]byte("OK"))
})
- srv, addr, err := dnsservertest.RunLocalHTTPSServer(
+ srv, err := dnsservertest.RunLocalHTTPSServer(
dnsservertest.DefaultHandler(),
nil,
testHandler,
@@ -146,7 +153,7 @@ func TestServerHTTPS_integration_nonDNSHandler(t *testing.T) {
})
var resp *http.Response
- resp, err = http.Get(fmt.Sprintf("http://%s/test", addr))
+ resp, err = http.Get(fmt.Sprintf("http://%s/test", srv.LocalTCPAddr()))
defer log.OnCloserError(resp.Body, log.DEBUG)
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
@@ -307,59 +314,69 @@ func TestDNSMsgToJSONMsg(t *testing.T) {
}}, jsonMsg.Extra)
}
-func sendDoHRequest(
+func mustDoHReq(
+ t testing.TB,
httpsAddr net.Addr,
tlsConfig *tls.Config,
method string,
json bool,
requestWireformat bool,
- msg *dns.Msg,
-) (resp *dns.Msg, err error) {
- var client *http.Client
- client, err = createDoHClient(httpsAddr, tlsConfig)
- if err != nil {
- return nil, err
- }
+ req *dns.Msg,
+) (resp *dns.Msg) {
+ t.Helper()
+
+ client, err := createDoHClient(httpsAddr, tlsConfig)
+ require.NoError(t, err)
proto := "https"
if tlsConfig == nil {
proto = "http"
}
- var req *http.Request
+ var httpReq *http.Request
if json {
- req, err = createJSONRequest(proto, method, requestWireformat, msg)
+ httpReq, err = createJSONRequest(proto, method, requestWireformat, req)
} else {
- req, err = createDoHRequest(proto, method, msg)
+ httpReq, err = createDoHRequest(proto, method, req)
}
+ require.NoError(t, err)
- if err != nil {
- return nil, err
- }
-
- var httpResp *http.Response
- httpResp, err = client.Do(req)
- if err != nil {
- return nil, err
- }
+ httpResp, err := client.Do(httpReq)
+ require.NoError(t, err)
defer log.OnCloserError(httpResp.Body, log.DEBUG)
- var body []byte
- body, err = io.ReadAll(httpResp.Body)
- if err != nil {
- return nil, err
+ if tlsConfig != nil && !httpResp.ProtoAtLeast(2, 0) {
+ t.Fatal(fmt.Errorf("protocol is too old: %s", httpResp.Proto))
}
+ body, err := io.ReadAll(httpResp.Body)
+ require.NoError(t, err)
+
if json && !requestWireformat {
resp, err = unpackJSONMsg(body)
} else {
resp, err = unpackDoHMsg(body)
}
+ require.NoError(t, err)
+ require.NotNil(t, resp)
- return resp, err
+ return resp
}
-func createDoHClient(httpsAddr net.Addr, tlsConfig *tls.Config) (*http.Client, error) {
+func createDoHClient(httpsAddr net.Addr, tlsConfig *tls.Config) (client *http.Client, err error) {
+ if dnsserver.NetworkFromAddr(httpsAddr) == dnsserver.NetworkUDP {
+ return createDoH3Client(httpsAddr, tlsConfig)
+ }
+
+ return createDoH2Client(httpsAddr, tlsConfig)
+}
+
+func createDoH2Client(httpsAddr net.Addr, tlsConfig *tls.Config) (client *http.Client, err error) {
+ if tlsConfig != nil {
+ tlsConfig = tlsConfig.Clone()
+ tlsConfig.NextProtos = []string{"h2", "http/1.1"}
+ }
+
dialer := &net.Dialer{
Timeout: 5 * time.Second,
}
@@ -371,9 +388,10 @@ func createDoHClient(httpsAddr net.Addr, tlsConfig *tls.Config) (*http.Client, e
TLSClientConfig: tlsConfig,
DisableCompression: true,
DialContext: dialContext,
+ ForceAttemptHTTP2: true,
}
if tlsConfig != nil {
- err := http2.ConfigureTransport(transport)
+ err = http2.ConfigureTransport(transport)
if err != nil {
return nil, err
}
@@ -384,6 +402,29 @@ func createDoHClient(httpsAddr net.Addr, tlsConfig *tls.Config) (*http.Client, e
}, nil
}
+func createDoH3Client(httpsAddr net.Addr, tlsConfig *tls.Config) (client *http.Client, err error) {
+ tlsConfig = tlsConfig.Clone()
+ tlsConfig.NextProtos = []string{"h3"}
+
+ transport := &http3.RoundTripper{
+ DisableCompression: true,
+ Dial: func(
+ ctx context.Context,
+ _ string,
+ tlsCfg *tls.Config,
+ cfg *quic.Config,
+ ) (c quic.EarlyConnection, e error) {
+ return quic.DialAddrEarlyContext(ctx, httpsAddr.String(), tlsCfg, cfg)
+ },
+ TLSClientConfig: tlsConfig,
+ }
+
+ return &http.Client{
+ Transport: transport,
+ Timeout: 5 * time.Second,
+ }, nil
+}
+
func createDoHRequest(proto, method string, msg *dns.Msg) (r *http.Request, err error) {
// Prepare message
var buf []byte
diff --git a/internal/dnsserver/serverquic.go b/internal/dnsserver/serverquic.go
index f166ecd..260f227 100644
--- a/internal/dnsserver/serverquic.go
+++ b/internal/dnsserver/serverquic.go
@@ -6,6 +6,7 @@ import (
"encoding/binary"
"fmt"
"io"
+ "math"
"net"
"strings"
"sync"
@@ -13,6 +14,7 @@ import (
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
+ "github.com/bluele/gcache"
"github.com/lucas-clemente/quic-go"
"github.com/miekg/dns"
)
@@ -27,6 +29,20 @@ const (
// value in quic-go is 30, but our internal tests show that a higher
// value works better for clients written with ngtcp2.
maxQUICIdleTimeout = 5 * time.Minute
+
+ // quicAddrValidatorCacheSize is the size of the cache that we use in the QUIC
+ // address validator. The value is chosen arbitrarily and we should consider
+ // making it configurable.
+ //
+ // TODO(ameshkov): make it configurable after we analyze stats.
+ quicAddrValidatorCacheSize = 10000
+
+ // quicAddrValidatorCacheTTL is time-to-live for cache items in the QUIC address
+ // validator. The value is chosen arbitrarily and we should consider making it
+ // configurable.
+ //
+ // TODO(ameshkov): make it configurable after we analyze stats.
+ quicAddrValidatorCacheTTL = 30 * time.Minute
)
const (
@@ -76,19 +92,24 @@ func NewServerQUIC(conf ConfigQUIC) (s *ServerQUIC) {
}
s = &ServerQUIC{
- ServerBase: newServerBase(conf.ConfigBase),
+ ServerBase: newServerBase(ProtoDoQ, conf.ConfigBase),
conf: conf,
}
return s
}
-// Start starts the ServerQUIC server, exits immediately if it failed to
-// start listening.
+// Start implements the dnsserver.Server interface for *ServerQUIC.
func (s *ServerQUIC) Start(ctx context.Context) (err error) {
+ defer func() { err = errors.Annotate(err, "starting doq server: %w", err) }()
+
s.lock.Lock()
defer s.lock.Unlock()
+ if s.conf.TLSConfig == nil {
+ return errors.Error("tls config is required")
+ }
+
if s.started {
return ErrServerAlreadyStarted
}
@@ -120,8 +141,10 @@ func (s *ServerQUIC) Start(ctx context.Context) (err error) {
return nil
}
-// Shutdown stops the server and waits for all active connections to close.
+// Shutdown implements the dnsserver.Server interface for *ServerQUIC.
func (s *ServerQUIC) Shutdown(ctx context.Context) (err error) {
+ defer func() { err = errors.Annotate(err, "shutting down doq server: %w", err) }()
+
log.Info("[%s]: Stopping the server", s.Name())
err = s.shutdown()
@@ -164,13 +187,13 @@ func (s *ServerQUIC) startServeQUIC(ctx context.Context) {
defer s.handlePanicAndExit(ctx)
defer s.wg.Done()
- log.Info("[%s]: Start listening to quic://%s", s.Name(), s.LocalAddr())
+ log.Info("[%s]: Start listening to quic://%s", s.Name(), s.LocalUDPAddr())
err := s.serveQUIC(ctx, s.quicListener)
if err != nil {
log.Info(
"[%s]: Finished listening to quic://%s due to %v",
s.Name(),
- s.LocalAddr(),
+ s.LocalUDPAddr(),
err,
)
}
@@ -418,27 +441,24 @@ func (s *ServerQUIC) readQUICMsg(
return m, doqDraft, nil
}
-// listenQUIC creates the UDP listener for the ServerQUIC.addr
-// and also starts the QUIC listener.
+// listenQUIC creates the UDP listener for the ServerQUIC.addr and also starts
+// the QUIC listener.
func (s *ServerQUIC) listenQUIC(ctx context.Context) (err error) {
- var l net.PacketConn
- l, err = listenUDP(ctx, s.addr)
+ // Do not enable OOB here as quic-go will do that on its own.
+ conn, err := listenUDP(ctx, s.addr, false)
if err != nil {
return err
}
- udpConn, ok := l.(*net.UDPConn)
- if !ok {
- return ErrInvalidArgument
- }
+ qConf := newServerQUICConfig(s.metrics)
- qConf := &quic.Config{MaxIdleTimeout: maxQUICIdleTimeout}
- ql, err := quic.Listen(l, s.conf.TLSConfig, qConf)
+ // Do not change to quic.ListenEarly, see quicNotEarlyListener to know why.
+ ql, err := quic.Listen(conn, s.conf.TLSConfig, qConf)
if err != nil {
return err
}
- s.udpListener = udpConn
+ s.udpListener = conn
s.quicListener = ql
return nil
@@ -470,16 +490,10 @@ func isExpectedQUICErr(err error) (ok bool) {
return true
}
- // We have to use error string since quic-go keeps it's error structs in the
- // internal package
- str := err.Error()
-
// Expected to be returned by all streams and connection methods calls when
// the server is closed. Unfortunately, this error is not exported from
// quic-go.
- //
- // TODO(ameshkov): Make a pull request to quic-go about this.
- if strings.Contains(str, "server closed") {
+ if errors.Is(err, quic.ErrServerClosed) {
return true
}
@@ -571,3 +585,74 @@ func closeQUICConn(conn quic.Connection, code quic.ApplicationErrorCode) {
log.Debug("failed to close the QUIC connection: %v", err)
}
}
+
+// newServerQUICConfig creates *quic.Config populated with the default settings.
+// This function is supposed to be used for both DoQ and DoH3 server.
+func newServerQUICConfig(metrics MetricsListener) (conf *quic.Config) {
+ v := newQUICAddrValidator(quicAddrValidatorCacheSize, quicAddrValidatorCacheTTL, metrics)
+
+ return &quic.Config{
+ MaxIdleTimeout: maxQUICIdleTimeout,
+ RequireAddressValidation: v.requiresValidation,
+ MaxIncomingStreams: math.MaxUint16,
+ MaxIncomingUniStreams: math.MaxUint16,
+ }
+}
+
+// quicAddrValidator is a helper struct that holds a small LRU cache of
+// addresses for which we do not require address validation.
+type quicAddrValidator struct {
+ cache gcache.Cache
+ ttl time.Duration
+ metrics MetricsListener
+}
+
+// newQUICAddrValidator initializes a new instance of *quicAddrValidator.
+func newQUICAddrValidator(
+ cacheSize int,
+ ttl time.Duration,
+ metrics MetricsListener,
+) (v *quicAddrValidator) {
+ return &quicAddrValidator{
+ cache: gcache.New(cacheSize).LRU().Build(),
+ ttl: ttl,
+ metrics: metrics,
+ }
+}
+
+// requiresValidation determines if a QUIC Retry packet should be sent by the
+// client. This allows the server to verify the client's address but increases
+// the latency.
+//
+// TODO(ameshkov): consider caddy-like implementation here.
+func (v *quicAddrValidator) requiresValidation(addr net.Addr) (ok bool) {
+ udpAddr, ok := addr.(*net.UDPAddr)
+ if !ok {
+ // Report this as an error as this is not the expected behavior here.
+ v.metrics.OnError(
+ context.Background(),
+ fmt.Errorf("not a udp address: %v", addr),
+ )
+
+ return false
+ }
+
+ key := udpAddr.IP.String()
+ if v.cache.Has(key) {
+ v.metrics.OnQUICAddressValidation(true)
+
+ return false
+ }
+
+ v.metrics.OnQUICAddressValidation(false)
+
+ err := v.cache.SetWithExpire(key, true, v.ttl)
+ if err != nil {
+ // Shouldn't happen, since we don't set a serialization function.
+ panic(fmt.Errorf("quic validator: setting cache item: %w", err))
+ }
+
+ // Address not found in the cache so return true to make sure the server
+ // will require address validation.
+ return true
+}
diff --git a/internal/dnsserver/servertls.go b/internal/dnsserver/servertls.go
index ccddceb..8e92f5d 100644
--- a/internal/dnsserver/servertls.go
+++ b/internal/dnsserver/servertls.go
@@ -5,6 +5,7 @@ import (
"crypto/tls"
"net"
+ "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
)
@@ -30,7 +31,7 @@ var _ Server = (*ServerTLS)(nil)
// NewServerTLS creates a new ServerTLS instance.
func NewServerTLS(conf ConfigTLS) (s *ServerTLS) {
- srv := newServerDNS(conf.ConfigDNS)
+ srv := newServerDNS(ProtoDoT, conf.ConfigDNS)
s = &ServerTLS{
ServerDNS: srv,
conf: conf,
@@ -39,11 +40,17 @@ func NewServerTLS(conf ConfigTLS) (s *ServerTLS) {
return s
}
-// Start starts the TLS listener and starts processing queries.
+// Start implements the dnsserver.Server interface for *ServerTLS.
func (s *ServerTLS) Start(ctx context.Context) (err error) {
+ defer func() { err = errors.Annotate(err, "starting dot server: %w", err) }()
+
s.lock.Lock()
defer s.lock.Unlock()
+ if s.conf.TLSConfig == nil {
+ return errors.Error("tls config is required")
+ }
+
// TODO(ameshkov): Consider only setting s.started to true once the
// listeners are up.
if s.started {
@@ -75,6 +82,13 @@ func (s *ServerTLS) Start(ctx context.Context) (err error) {
return nil
}
+// Shutdown implements the dnsserver.Server interface for *ServerTLS.
+func (s *ServerTLS) Shutdown(ctx context.Context) (err error) {
+ defer func() { err = errors.Annotate(err, "shutting down dot server: %w", err) }()
+
+ return s.ServerDNS.Shutdown(ctx)
+}
+
// startServeTCP starts the TCP listen loop and handles errors if any.
func (s *ServerTLS) startServeTCP(ctx context.Context) {
// We do not recover from panics here since if this go routine panics
diff --git a/internal/dnsserver/servertls_test.go b/internal/dnsserver/servertls_test.go
index a416adb..d4cc173 100644
--- a/internal/dnsserver/servertls_test.go
+++ b/internal/dnsserver/servertls_test.go
@@ -1,7 +1,6 @@
package dnsserver_test
import (
- "context"
"crypto/tls"
"encoding/binary"
"io"
@@ -12,23 +11,13 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/golibs/log"
- "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/require"
)
func TestServerTLS_integration_queryTLS(t *testing.T) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
- srv, addr, err := dnsservertest.RunLocalTLSServer(
- dnsservertest.DefaultHandler(),
- tlsConfig,
- )
- require.NoError(t, err)
- require.Equal(t, dnsserver.ProtoDoT, srv.Proto())
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ addr := dnsservertest.RunTLSServer(t, dnsservertest.DefaultHandler(), tlsConfig)
// Create a test message
req := new(dns.Msg)
@@ -97,16 +86,8 @@ func TestServerTLS_integration_msgIgnore(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
- srv, addr, err := dnsservertest.RunLocalTLSServer(
- dnsservertest.DefaultHandler(),
- tlsConfig,
- )
- require.NoError(t, err)
- require.Equal(t, dnsserver.ProtoDoT, srv.Proto())
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ h := dnsservertest.DefaultHandler()
+ addr := dnsservertest.RunTLSServer(t, h, tlsConfig)
conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
require.Nil(t, err)
@@ -134,12 +115,7 @@ func TestServerTLS_integration_noTruncateQuery(t *testing.T) {
handler := dnsservertest.CreateTestHandler(64)
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
- srv, addr, err := dnsservertest.RunLocalTLSServer(handler, tlsConfig)
- require.NoError(t, err)
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ addr := dnsservertest.RunTLSServer(t, handler, tlsConfig)
// Create a test message
req := new(dns.Msg)
@@ -167,16 +143,7 @@ func TestServerTLS_integration_queriesPipelining(t *testing.T) {
// i.e. we should be able to process incoming queries in parallel and
// write responses out of order.
tlsConfig := dnsservertest.CreateServerTLSConfig("example.org")
- srv, addr, err := dnsservertest.RunLocalTLSServer(
- dnsservertest.DefaultHandler(),
- tlsConfig,
- )
- require.NoError(t, err)
- require.Equal(t, dnsserver.ProtoDoT, srv.Proto())
-
- testutil.CleanupAndRequireSuccess(t, func() (err error) {
- return srv.Shutdown(context.Background())
- })
+ addr := dnsservertest.RunTLSServer(t, dnsservertest.DefaultHandler(), tlsConfig)
// First - establish a connection
conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
diff --git a/internal/dnssvc/deviceid.go b/internal/dnssvc/deviceid.go
index bc4862d..429b1dc 100644
--- a/internal/dnssvc/deviceid.go
+++ b/internal/dnssvc/deviceid.go
@@ -114,11 +114,11 @@ var _ errors.Wrapper = (*deviceIDError)(nil)
func (err *deviceIDError) Unwrap() (unwrapped error) { return err.err }
// type check
-var _ errcoll.RavenReportableError = (*deviceIDError)(nil)
+var _ errcoll.SentryReportableError = (*deviceIDError)(nil)
-// IsRavenReportable implements the errcoll.RavenReportableError interface for
+// IsSentryReportable implements the errcoll.SentryReportableError interface for
// *deviceIDError.
-func (err *deviceIDError) IsRavenReportable() (ok bool) { return false }
+func (err *deviceIDError) IsSentryReportable() (ok bool) { return false }
// deviceIDFromContext extracts the device from the server name of the TLS
// client's DoH, DoT, or DoQ request, using the provided domain name wildcards,
diff --git a/internal/dnssvc/deviceid_internal_test.go b/internal/dnssvc/deviceid_internal_test.go
index 7ccfb21..30f7b50 100644
--- a/internal/dnssvc/deviceid_internal_test.go
+++ b/internal/dnssvc/deviceid_internal_test.go
@@ -24,12 +24,12 @@ func TestService_Wrap_deviceID(t *testing.T) {
wildcards []string
proto agd.Protocol
}{{
- name: "udp",
+ name: "dns",
cliSrvName: "",
wantDeviceID: "",
wantErrMsg: "",
wildcards: nil,
- proto: agd.ProtoDNSUDP,
+ proto: agd.ProtoDNS,
}, {
name: "tls_no_device_id",
cliSrvName: "dns.example.com",
diff --git a/internal/dnssvc/dnssvc.go b/internal/dnssvc/dnssvc.go
index 333c532..d7f8b43 100644
--- a/internal/dnssvc/dnssvc.go
+++ b/internal/dnssvc/dnssvc.go
@@ -345,14 +345,7 @@ type listener struct {
// listenerName returns a standard name for a listener.
func listenerName(srvName agd.ServerName, addr netip.AddrPort, p agd.Protocol) (name string) {
- switch p {
- case agd.ProtoDNSTCP, agd.ProtoDNSCryptTCP:
- return fmt.Sprintf("%s/tcp/%s", srvName, addr)
- case agd.ProtoDNSUDP, agd.ProtoDNSCryptUDP:
- return fmt.Sprintf("%s/udp/%s", srvName, addr)
- default:
- return fmt.Sprintf("%s/%s", srvName, addr)
- }
+ return fmt.Sprintf("%s/%s/%s", srvName, p, addr)
}
// NewListener returns a new Listener. It is the default DNS listener
@@ -378,16 +371,15 @@ func NewListener(
confBase := dnsserver.ConfigBase{
Name: name,
Addr: addrStr,
- Proto: s.Protocol,
Handler: h,
BaseContext: ctxWithReqID,
Metrics: metricsListener,
}
switch p := s.Protocol; p {
- case agd.ProtoDNSTCP, agd.ProtoDNSUDP:
+ case agd.ProtoDNS:
l = dnsserver.NewServerDNS(dnsserver.ConfigDNS{ConfigBase: confBase})
- case agd.ProtoDNSCryptTCP, agd.ProtoDNSCryptUDP:
+ case agd.ProtoDNSCrypt:
l = dnsserver.NewServerDNSCrypt(dnsserver.ConfigDNSCrypt{
ConfigBase: confBase,
DNSCryptProviderName: dcConf.ProviderName,
@@ -443,8 +435,8 @@ func newServers(
// validate fg.
fg := c.FilteringGroups[srvGrp.FilteringGroup]
- // Only apply rate-limiting logic to plain DNS over UDP.
- rlProtos := []agd.Protocol{agd.ProtoDNSUDP}
+ // Only apply rate-limiting logic to plain DNS.
+ rlProtos := []agd.Protocol{agd.ProtoDNS}
var rlm *ratelimit.Middleware
rlm, err = ratelimit.NewMiddleware(c.RateLimit, rlProtos)
diff --git a/internal/dnssvc/dnssvc_test.go b/internal/dnssvc/dnssvc_test.go
index 3c4ce25..3335e09 100644
--- a/internal/dnssvc/dnssvc_test.go
+++ b/internal/dnssvc/dnssvc_test.go
@@ -10,18 +10,18 @@ import (
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/forward"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
// type check
@@ -32,35 +32,70 @@ var _ agd.Refresher = (*forward.Handler)(nil)
// type check
var _ dnssvc.Listener = (*testListener)(nil)
-// testListener is a dnssvc.Listener for tests.
+// testListener is a [dnssvc.Listener] for tests.
type testListener struct {
- onStart func(ctx context.Context) (err error)
- onShutdown func(ctx context.Context) (err error)
- onLocalAddr func() (addr net.Addr)
+ onStart func(ctx context.Context) (err error)
+ onShutdown func(ctx context.Context) (err error)
+ onName func() (name string)
+ onProto func() (proto dnsserver.Protocol)
+ onNetwork func() (network dnsserver.Network)
+ onAddr func() (addr string)
+ onLocalTCPAddr func() (addr net.Addr)
+ onLocalUDPAddr func() (addr net.Addr)
}
-// Start implements the dnsserver.Server interface for *testListener.
+// Name implements the [dnsserver.Server] interface for *testListener.
+func (l *testListener) Name() (name string) {
+ return l.onName()
+}
+
+// Proto implements the [dnsserver.Server] interface for *testListener.
+func (l *testListener) Proto() (proto dnsserver.Protocol) {
+ return l.onProto()
+}
+
+// Network implements the [dnsserver.Server] interface for *testListener.
+func (l *testListener) Network() (network dnsserver.Network) {
+ return l.onNetwork()
+}
+
+// Addr implements the [dnsserver.Server] interface for *testListener.
+func (l *testListener) Addr() (addr string) {
+ return l.onAddr()
+}
+
+// Start implements the [dnsserver.Server] interface for *testListener.
func (l *testListener) Start(ctx context.Context) (err error) {
return l.onStart(ctx)
}
-// Shutdown implements the dnsserver.Server interface for *testListener.
+// Shutdown implements the [dnsserver.Server] interface for *testListener.
func (l *testListener) Shutdown(ctx context.Context) (err error) {
return l.onShutdown(ctx)
}
-// LocalAddr implements the dnsserver.Server interface for *testListener.
-func (l *testListener) LocalAddr() (addr net.Addr) {
- return l.onLocalAddr()
+// LocalTCPAddr implements the [dnsserver.Server] interface for *testListener.
+func (l *testListener) LocalTCPAddr() (addr net.Addr) {
+ return l.onLocalTCPAddr()
+}
+
+// LocalUDPAddr implements the [dnsserver.Server] interface for *testListener.
+func (l *testListener) LocalUDPAddr() (addr net.Addr) {
+ return l.onLocalUDPAddr()
}
// newTestListener returns a *testListener all of methods of which panic with
// a "not implemented" message.
func newTestListener() (tl *testListener) {
return &testListener{
- onStart: func(_ context.Context) (err error) { panic("not implemented") },
- onShutdown: func(_ context.Context) (err error) { panic("not implemented") },
- onLocalAddr: func() (addr net.Addr) { panic("not implemented") },
+ onName: func() (_ string) { panic("not implemented") },
+ onProto: func() (_ dnsserver.Protocol) { panic("not implemented") },
+ onNetwork: func() (_ dnsserver.Network) { panic("not implemented") },
+ onAddr: func() (_ string) { panic("not implemented") },
+ onStart: func(_ context.Context) (err error) { panic("not implemented") },
+ onShutdown: func(_ context.Context) (err error) { panic("not implemented") },
+ onLocalUDPAddr: func() (_ net.Addr) { panic("not implemented") },
+ onLocalTCPAddr: func() (_ net.Addr) { panic("not implemented") },
}
}
@@ -123,7 +158,7 @@ func TestService_Start(t *testing.T) {
srv := &agd.Server{
Name: "test_server",
- Protocol: agd.ProtoDNSUDP,
+ Protocol: agd.ProtoDNS,
BindAddresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:53")},
}
@@ -162,26 +197,14 @@ func TestNew(t *testing.T) {
srvs := []*agd.Server{{
DNSCrypt: nil,
TLS: nil,
- Name: "test_server_dns_tcp",
- Protocol: agd.ProtoDNSTCP,
- BindAddresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:53")},
- }, {
- DNSCrypt: nil,
- TLS: nil,
- Name: "test_server_dns_udp",
- Protocol: agd.ProtoDNSUDP,
+ Name: "test_server_dns",
+ Protocol: agd.ProtoDNS,
BindAddresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:53")},
}, {
DNSCrypt: &agd.DNSCryptConfig{},
TLS: nil,
Name: "test_server_dnscrypt_tcp",
- Protocol: agd.ProtoDNSCryptTCP,
- BindAddresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:8853")},
- }, {
- DNSCrypt: &agd.DNSCryptConfig{},
- TLS: nil,
- Name: "test_server_dnscrypt_udp",
- Protocol: agd.ProtoDNSCryptUDP,
+ Protocol: agd.ProtoDNSCrypt,
BindAddresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:8853")},
}, {
DNSCrypt: nil,
diff --git a/internal/dnssvc/errcoll.go b/internal/dnssvc/errcoll.go
index 4acac69..25df6df 100644
--- a/internal/dnssvc/errcoll.go
+++ b/internal/dnssvc/errcoll.go
@@ -36,6 +36,12 @@ func (s *errCollMetricsListener) OnInvalidMsg(ctx context.Context) {
s.baseListener.OnInvalidMsg(ctx)
}
+// OnQUICAddressValidation implements the dnsserver.MetricsListener interface
+// for *errCollMetricsListener.
+func (s *errCollMetricsListener) OnQUICAddressValidation(hit bool) {
+ s.baseListener.OnQUICAddressValidation(hit)
+}
+
// OnPanic implements the dnsserver.MetricsListener interface for
// *errCollMetricsListener.
func (s *errCollMetricsListener) OnPanic(ctx context.Context, v any) {
diff --git a/internal/dnssvc/initmw.go b/internal/dnssvc/initmw.go
index bf6dbd2..9876015 100644
--- a/internal/dnssvc/initmw.go
+++ b/internal/dnssvc/initmw.go
@@ -253,7 +253,7 @@ func (mw *initMw) addProfile(ctx context.Context, ri *agd.RequestInfo, req *dns.
// Assume that mw.srvGrp.TLS is non-nil if p.IsStdEncrypted() is true.
wildcards := mw.srvGrp.TLS.DeviceIDWildcards
id, err = deviceIDFromContext(ctx, mw.srv.Protocol, wildcards)
- } else if p.IsPlain() {
+ } else if p == agd.ProtoDNS {
id, err = deviceIDFromEDNS(req)
} else {
// No DeviceID for DNSCrypt yet.
@@ -308,7 +308,7 @@ func (mw *initMw) profile(
optlog.Debug1("init mw: not matching by ip for server %s", mw.srv.Name)
return nil, nil, "", agd.ProfileNotFoundError{}
- } else if !p.IsPlain() {
+ } else if p != agd.ProtoDNS {
optlog.Debug1("init mw: not matching by ip for proto %v", p)
return nil, nil, "", agd.ProfileNotFoundError{}
diff --git a/internal/dnssvc/initmw_internal_test.go b/internal/dnssvc/initmw_internal_test.go
index 888a7fb..ab05594 100644
--- a/internal/dnssvc/initmw_internal_test.go
+++ b/internal/dnssvc/initmw_internal_test.go
@@ -9,12 +9,13 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/stringutil"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -53,14 +54,14 @@ func TestInitMw_ServeDNS_ddr(t *testing.T) {
BindAddresses: []netip.AddrPort{netip.MustParseAddrPort("5.6.7.8:54321")},
Protocol: agd.ProtoDoH,
},
- "tcp": {
+ "dns": {
BindAddresses: []netip.AddrPort{netip.MustParseAddrPort("2.4.6.8:53")},
- Protocol: agd.ProtoDNSTCP,
+ Protocol: agd.ProtoDNS,
LinkedIPEnabled: true,
},
- "tcp_nolink": {
+ "dns_nolink": {
BindAddresses: []netip.AddrPort{netip.MustParseAddrPort("2.4.6.8:53")},
- Protocol: agd.ProtoDNSTCP,
+ Protocol: agd.ProtoDNS,
},
}
@@ -109,7 +110,7 @@ func TestInitMw_ServeDNS_ddr(t *testing.T) {
OnSubnetByLocation: func(
_ agd.Country,
_ agd.ASN,
- _ agdnet.AddrFamily,
+ _ netutil.AddrFamily,
) (_ netip.Prefix, _ error) {
panic("not implemented")
},
@@ -181,7 +182,7 @@ func TestInitMw_ServeDNS_ddr(t *testing.T) {
}, {
device: testDevice,
name: "linked_ip",
- srv: srvs["tcp"],
+ srv: srvs["dns"],
host: ddrFQDN,
wantTarget: targetWithID,
wantNum: len(pubSVCBTmpls),
@@ -189,7 +190,7 @@ func TestInitMw_ServeDNS_ddr(t *testing.T) {
}, {
device: testDevice,
name: "no_linked_ip",
- srv: srvs["tcp_nolink"],
+ srv: srvs["dns_nolink"],
host: ddrFQDN,
wantTarget: resolverFQDN,
wantNum: len(pubSVCBTmpls),
@@ -267,9 +268,8 @@ func TestInitMw_ServeDNS_ddr(t *testing.T) {
assert.Len(t, resp.Answer, tc.wantNum)
for _, rr := range resp.Answer {
- require.IsType(t, (*dns.SVCB)(nil), rr)
+ svcb := testutil.RequireTypeAssert[*dns.SVCB](t, rr)
- svcb := rr.(*dns.SVCB)
assert.Equal(t, tc.wantTarget, svcb.Target)
assert.Equal(t, tc.host, svcb.Hdr.Name)
}
@@ -386,7 +386,7 @@ func TestInitMw_ServeDNS_privateRelay(t *testing.T) {
OnSubnetByLocation: func(
_ agd.Country,
_ agd.ASN,
- _ agdnet.AddrFamily,
+ _ netutil.AddrFamily,
) (n netip.Prefix, err error) {
panic("not implemented")
},
@@ -410,7 +410,7 @@ func TestInitMw_ServeDNS_privateRelay(t *testing.T) {
},
srvGrp: &agd.ServerGroup{},
srv: &agd.Server{
- Protocol: agd.ProtoDNSTCP,
+ Protocol: agd.ProtoDNS,
LinkedIPEnabled: true,
},
db: db,
@@ -487,7 +487,7 @@ func BenchmarkInitMw_Wrap(b *testing.B) {
OnSubnetByLocation: func(
_ agd.Country,
_ agd.ASN,
- _ agdnet.AddrFamily,
+ _ netutil.AddrFamily,
) (n netip.Prefix, err error) {
panic("not implemented")
},
diff --git a/internal/dnssvc/middleware_test.go b/internal/dnssvc/middleware_test.go
index e0034c2..a93f251 100644
--- a/internal/dnssvc/middleware_test.go
+++ b/internal/dnssvc/middleware_test.go
@@ -9,13 +9,13 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnssvc"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
@@ -93,7 +93,7 @@ func TestService_Wrap_withClient(t *testing.T) {
OnSubnetByLocation: func(
_ agd.Country,
_ agd.ASN,
- _ agdnet.AddrFamily,
+ _ netutil.AddrFamily,
) (n netip.Prefix, err error) {
panic("not implemented")
},
diff --git a/internal/dnssvc/record.go b/internal/dnssvc/record.go
index fd6f10d..84fb062 100644
--- a/internal/dnssvc/record.go
+++ b/internal/dnssvc/record.go
@@ -8,7 +8,6 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
@@ -31,6 +30,9 @@ func (svc *Service) recordQueryInfo(
reqRes filter.Result,
respRes filter.Result,
) {
+ id, text, blocked := filteringData(reqRes, respRes)
+ svc.ruleStat.Collect(ctx, id, text)
+
prof := ri.Profile
if prof == nil {
return
@@ -47,9 +49,6 @@ func (svc *Service) recordQueryInfo(
reqCtry, reqASN = g.Country, g.ASN
}
- id, text, blocked := filteringData(reqRes, respRes)
- svc.ruleStat.Collect(ctx, id, text)
-
proto := dnsserver.MustServerInfoFromContext(ctx).Proto
start := dnsserver.MustStartTimeFromContext(ctx)
svc.billStat.Record(ctx, devID, reqCtry, reqASN, start, proto)
@@ -155,17 +154,17 @@ func (svc *Service) responseData(
}
var rrType dns.Type
- var fam agdnet.AddrFamily
+ var fam netutil.AddrFamily
var netIP net.IP
dnssec = resp.AuthenticatedData
rcode = dnsmsg.RCode(resp.Rcode)
for _, rr := range resp.Answer {
switch v := rr.(type) {
case *dns.A:
- fam = agdnet.AddrFamilyIPv4
+ fam = netutil.AddrFamilyIPv4
rrType, netIP = dns.Type(v.Hdr.Rrtype), v.A
case *dns.AAAA:
- fam = agdnet.AddrFamilyIPv6
+ fam = netutil.AddrFamilyIPv6
rrType, netIP = dns.Type(v.Hdr.Rrtype), v.AAAA
default:
continue
@@ -184,7 +183,7 @@ func (svc *Service) responseData(
svc.reportf(ctx, "reading %s resp data: %w", rrType, err)
}
- ip, err = agdnet.IPToAddr(netIP, fam)
+ ip, err = netutil.IPToAddr(netIP, fam)
if err != nil {
svc.reportf(ctx, "converting %s resp data: %w", rrType, err)
}
diff --git a/internal/dnssvc/resp_internal_test.go b/internal/dnssvc/resp_internal_test.go
index b38d454..44b80b9 100644
--- a/internal/dnssvc/resp_internal_test.go
+++ b/internal/dnssvc/resp_internal_test.go
@@ -12,6 +12,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -107,9 +108,9 @@ func TestWriteFilteredResp(t *testing.T) {
ans := written.Answer[0]
assert.Equal(t, tc.wantTTL, ans.Header().Ttl)
- require.IsType(t, (*dns.A)(nil), ans)
+ a := testutil.RequireTypeAssert[*dns.A](t, ans)
- assert.Equal(t, tc.wantIP, ans.(*dns.A).A)
+ assert.Equal(t, tc.wantIP, a.A)
})
}
}
diff --git a/internal/ecscache/ecscache.go b/internal/ecscache/ecscache.go
index 3e86a5b..297878f 100644
--- a/internal/ecscache/ecscache.go
+++ b/internal/ecscache/ecscache.go
@@ -8,13 +8,13 @@ import (
"net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/AdGuardDNS/internal/optlog"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/bluele/gcache"
"github.com/miekg/dns"
)
@@ -127,7 +127,7 @@ func writeCachedResponse(
req *dns.Msg,
resp *dns.Msg,
ecs *agd.ECS,
- ecsFam agdnet.AddrFamily,
+ ecsFam netutil.AddrFamily,
hostHasECS bool,
) (err error) {
// Increment the hits metrics here, since we already know if the domain name
@@ -163,15 +163,15 @@ func writeCachedResponse(
// ecsFamFromReq returns the address family to use for the outgoing request from
// the request information using either the contents of the EDNS Client Subnet
// option or the real remote IP address.
-func ecsFamFromReq(ri *agd.RequestInfo) (ecsFam agdnet.AddrFamily) {
+func ecsFamFromReq(ri *agd.RequestInfo) (ecsFam netutil.AddrFamily) {
if ecs := ri.ECS; ecs != nil {
if ecs.Subnet.Addr().Is4() {
- return agdnet.AddrFamilyIPv4
+ return netutil.AddrFamilyIPv4
}
// Assume that families other than IPv4 and IPv6 have been filtered out
// by dnsmsg.ECSFromMsg.
- return agdnet.AddrFamilyIPv6
+ return netutil.AddrFamilyIPv6
}
// Set the address family parameter to the one of the client's address as
@@ -179,10 +179,10 @@ func ecsFamFromReq(ri *agd.RequestInfo) (ecsFam agdnet.AddrFamily) {
//
// See https://datatracker.ietf.org/doc/html/rfc7871#section-7.1.1.
if ri.RemoteIP.Is4() {
- return agdnet.AddrFamilyIPv4
+ return netutil.AddrFamilyIPv4
}
- return agdnet.AddrFamilyIPv6
+ return netutil.AddrFamilyIPv6
}
// locFromReq returns the country and ASN from the request information using
@@ -211,7 +211,7 @@ func (m *Middleware) writeUpstreamResponse(
resp *dns.Msg,
ri *agd.RequestInfo,
locSubnet netip.Prefix,
- ecsFam agdnet.AddrFamily,
+ ecsFam netutil.AddrFamily,
reqDO bool,
) (err error) {
subnet, scope, err := dnsmsg.ECSFromMsg(resp)
@@ -233,8 +233,8 @@ func (m *Middleware) writeUpstreamResponse(
metrics.ECSCacheLookupNoSupportMisses.Inc()
metrics.ECSNoSupportCacheSize.Set(float64(m.cache.Len(false)))
- locSubnet = agdnet.ZeroSubnet(ecsFam)
- ecsFam = agdnet.AddrFamilyNone
+ locSubnet = netutil.ZeroPrefix(ecsFam)
+ ecsFam = netutil.AddrFamilyNone
}
m.set(resp, ri.Host, locSubnet, hostHasECS, reqDO)
diff --git a/internal/ecscache/ecscache_test.go b/internal/ecscache/ecscache_test.go
index 02243d4..4a192e1 100644
--- a/internal/ecscache/ecscache_test.go
+++ b/internal/ecscache/ecscache_test.go
@@ -7,19 +7,20 @@ import (
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/ecscache"
+ "github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
// Common test domain names.
@@ -148,7 +149,7 @@ func TestMiddleware_Wrap_noECS(t *testing.T) {
t,
handler,
agd.CountryNone,
- agdnet.ZeroSubnet(agdnet.AddrFamilyIPv4),
+ netutil.ZeroPrefix(netutil.AddrFamilyIPv4),
)
ctx := agd.ContextWithRequestInfo(context.Background(), &agd.RequestInfo{
Host: tc.req.Question[0].Name,
@@ -190,7 +191,7 @@ func TestMiddleware_Wrap_ecs(t *testing.T) {
subnet := netip.PrefixFrom(netip.AddrFrom4(*(*[4]byte)(ip)), prefixLen)
opt.Option = append(opt.Option, &dns.EDNS0_SUBNET{
Code: dns.EDNS0SUBNET,
- Family: uint16(agdnet.AddrFamilyIPv4),
+ Family: uint16(netutil.AddrFamilyIPv4),
SourceNetmask: prefixLen,
SourceScope: 0,
Address: ip,
@@ -198,7 +199,7 @@ func TestMiddleware_Wrap_ecs(t *testing.T) {
const ctry = agd.CountryAD
defaultCtrySubnet := netip.MustParsePrefix("1.2.0.0/16")
- ecsExtra := dnsservertest.NewECSExtra(net.IP{1, 2, 0, 0}, uint16(agdnet.AddrFamilyIPv4), 20, 20)
+ ecsExtra := dnsservertest.NewECSExtra(net.IP{1, 2, 0, 0}, uint16(netutil.AddrFamilyIPv4), 20, 20)
testCases := []struct {
req *dns.Msg
@@ -255,7 +256,7 @@ func TestMiddleware_Wrap_ecs(t *testing.T) {
Scope: 0,
},
name: "no_country",
- ctrySubnet: agdnet.ZeroSubnet(agdnet.AddrFamilyIPv4),
+ ctrySubnet: netutil.ZeroPrefix(netutil.AddrFamilyIPv4),
wantNumReq: 1,
wantTTL: defaultTTL,
}, {
@@ -351,10 +352,8 @@ func TestMiddleware_Wrap_ecs(t *testing.T) {
require.NotNil(t, respOpt)
require.Len(t, respOpt.Option, 1)
- o := respOpt.Option[0]
- require.IsType(t, (*dns.EDNS0_SUBNET)(nil), o)
+ subnetOpt := testutil.RequireTypeAssert[*dns.EDNS0_SUBNET](t, respOpt.Option[0])
- subnetOpt := o.(*dns.EDNS0_SUBNET)
assert.Equal(t, ip, subnetOpt.Address)
assert.Equal(t, uint8(prefixLen), subnetOpt.SourceNetmask)
assert.Equal(t, uint8(prefixLen), subnetOpt.SourceScope)
@@ -376,7 +375,7 @@ func newWithCache(
OnSubnetByLocation: func(
ctry agd.Country,
_ agd.ASN,
- _ agdnet.AddrFamily,
+ _ netutil.AddrFamily,
) (n netip.Prefix, err error) {
t.Helper()
diff --git a/internal/ecscache/msg.go b/internal/ecscache/msg.go
index 6fe0197..1730302 100644
--- a/internal/ecscache/msg.go
+++ b/internal/ecscache/msg.go
@@ -7,8 +7,8 @@ import (
"net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
)
@@ -78,13 +78,13 @@ func setRespAD(resp *dns.Msg, reqAD, reqDO bool) {
}
// setECS sets the EDNS Client Subnet option using data from ecs. Both msg and
-// ecs must not be nil. ecsFam should be either agdnet.AddrFamilyIPv4 or
-// agdnet.AddrFamilyIPv6. ecs should contain an IP address of the same family
-// as ecsFam.
+// ecs must not be nil. ecsFam should be either [netutil.AddrFamilyIPv4] or
+// [netutil.AddrFamilyIPv6]. ecs should contain an IP address of the same
+// family as ecsFam.
func setECS(
msg *dns.Msg,
ecs *agd.ECS,
- ecsFam agdnet.AddrFamily,
+ ecsFam netutil.AddrFamily,
isResp bool,
) (err error) {
ip, err := addrToNetIP(ecs.Subnet.Addr(), ecsFam)
@@ -129,10 +129,10 @@ func setECS(
}
// addrToNetIP returns ip as a net.IP with the correct number of bytes for fam.
-// fam must be either agdnet.AddrFamilyIPv4 or agdnet.AddrFamilyIPv6.
-func addrToNetIP(ip netip.Addr, fam agdnet.AddrFamily) (res net.IP, err error) {
+// fam must be either [netutil.AddrFamilyIPv4] or [netutil.AddrFamilyIPv6].
+func addrToNetIP(ip netip.Addr, fam netutil.AddrFamily) (res net.IP, err error) {
switch fam {
- case agdnet.AddrFamilyIPv4:
+ case netutil.AddrFamilyIPv4:
if ip.Is6() {
return nil, fmt.Errorf("cannot convert %s to ipv4", ip)
}
@@ -142,7 +142,7 @@ func addrToNetIP(ip netip.Addr, fam agdnet.AddrFamily) (res net.IP, err error) {
ip4 := ip.As4()
return ip4[:], nil
- case agdnet.AddrFamilyIPv6:
+ case netutil.AddrFamilyIPv6:
if ip.Is4() {
return nil, fmt.Errorf("bad ipv4 addr %s for ipv6 addr fam", ip)
}
diff --git a/internal/errcoll/raven_test.go b/internal/errcoll/raven_test.go
deleted file mode 100644
index 97bde0c..0000000
--- a/internal/errcoll/raven_test.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package errcoll_test
-
-import (
- "context"
- "fmt"
- "testing"
- "time"
-
- "github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
- "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
- "github.com/AdguardTeam/golibs/errors"
- "github.com/getsentry/raven-go"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-// testRavenTransport is a raven.Transport for tests.
-type testRavenTransport struct {
- onSend func(url, authHeader string, packet *raven.Packet) (err error)
-}
-
-// Send implements the raven.Transport interface for *testRavenTransport.
-func (t *testRavenTransport) Send(url, authHeader string, packet *raven.Packet) (err error) {
- return t.onSend(url, authHeader, packet)
-}
-
-func TestRavenErrorCollector(t *testing.T) {
- gotPacketCh := make(chan *raven.Packet, 1)
- rt := &testRavenTransport{
- onSend: func(_, _ string, packet *raven.Packet) (err error) {
- gotPacketCh <- packet
-
- return nil
- },
- }
-
- rc, err := raven.New("https://user:password@does.not.exist/test")
- require.NoError(t, err)
-
- rc.Transport = rt
- c := errcoll.NewRavenErrorCollector(rc)
-
- const devID = "dev1234"
- const fgID = "fg1234"
- const profID = "prof1234"
- const reqID = "req5678"
-
- ctx := context.Background()
- ctx = agd.ContextWithRequestInfo(ctx, &agd.RequestInfo{
- Device: &agd.Device{ID: devID},
- Profile: &agd.Profile{ID: profID},
- FilteringGroup: &agd.FilteringGroup{ID: fgID},
- Messages: &dnsmsg.Constructor{
- FilteredResponseTTL: 10 * time.Second,
- },
- ID: reqID,
- })
-
- err = fmt.Errorf("wrapped: %w", errors.Error("test error"))
- c.Collect(ctx, err)
-
- gotPacket := <-gotPacketCh
- assert.Equal(t, err.Error(), gotPacket.Message)
-
- type ravenTags = map[string]string
- tags := make(ravenTags, len(gotPacket.Tags))
- for _, tag := range gotPacket.Tags {
- tags[tag.Key] = tag.Value
- }
-
- position := tags["position"]
- delete(tags, "position")
- delete(tags, "version")
- delete(tags, "git_revision")
-
- wantRx := `.*errcoll/raven_test.go:[0-9]+.*`
- assert.Regexp(t, wantRx, position)
-
- wantTags := ravenTags{
- "device_id": devID,
- "filtering_group_id": fgID,
- "profile_id": profID,
- "request_id": reqID,
- "unwrapped_type": "errors.Error",
- }
- assert.Equal(t, wantTags, tags)
-}
diff --git a/internal/errcoll/raven.go b/internal/errcoll/sentry.go
similarity index 76%
rename from internal/errcoll/raven.go
rename to internal/errcoll/sentry.go
index c9bd498..26f7fdf 100644
--- a/internal/errcoll/raven.go
+++ b/internal/errcoll/sentry.go
@@ -2,7 +2,6 @@ package errcoll
import (
"context"
- "fmt"
"io"
"net"
"os"
@@ -14,50 +13,53 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/forward"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
- "github.com/getsentry/raven-go"
+ "github.com/getsentry/sentry-go"
"golang.org/x/sys/unix"
)
-// Raven API Error Collector
+// Sentry API Error Collector
-// RavenErrorCollector is an agd.ErrorCollector that sends errors to
-// a Raven-like HTTP API.
-type RavenErrorCollector struct {
- raven *raven.Client
+// SentryErrorCollector is an [agd.ErrorCollector] that sends errors to a
+// Sentry-like HTTP API.
+type SentryErrorCollector struct {
+ sentry *sentry.Client
}
-// NewRavenErrorCollector returns a new RavenErrorCollector. rc must be
+// NewSentryErrorCollector returns a new SentryErrorCollector. cli must be
// non-nil.
-func NewRavenErrorCollector(rc *raven.Client) (c *RavenErrorCollector) {
- return &RavenErrorCollector{
- raven: rc,
+func NewSentryErrorCollector(cli *sentry.Client) (c *SentryErrorCollector) {
+ return &SentryErrorCollector{
+ sentry: cli,
}
}
// type check
-var _ agd.ErrorCollector = (*RavenErrorCollector)(nil)
+var _ agd.ErrorCollector = (*SentryErrorCollector)(nil)
-// Collect implements the agd.ErrorCollector interface for
-// *RavenErrorCollector.
-func (c *RavenErrorCollector) Collect(ctx context.Context, err error) {
+// Collect implements the [agd.ErrorCollector] interface for
+// *SentryErrorCollector.
+func (c *SentryErrorCollector) Collect(ctx context.Context, err error) {
if !isReportable(err) {
- log.Debug("errcoll: raven: non-reportable error: %s", err)
+ log.Debug("errcoll: sentry: non-reportable error: %s", err)
return
}
+ scope := sentry.NewScope()
tags := tagsFromCtx(ctx)
- tags["unwrapped_type"] = fmt.Sprintf("%T", errors.Unwrap(err))
+ scope.SetTags(tags)
- _ = c.raven.CaptureError(err, tags)
+ _ = c.sentry.CaptureException(err, &sentry.EventHint{
+ Context: ctx,
+ }, scope)
}
-// RavenReportableError is the interface for errors and wrapper that can tell
+// SentryReportableError is the interface for errors and wrapper that can tell
// whether they should be reported or not.
-type RavenReportableError interface {
+type SentryReportableError interface {
error
- IsRavenReportable() (ok bool)
+ IsSentryReportable() (ok bool)
}
// isReportable returns true if the error is worth reporting.
@@ -65,13 +67,13 @@ type RavenReportableError interface {
// TODO(a.garipov): Make sure that we use this approach everywhere.
func isReportable(err error) (ok bool) {
var (
- ravErr RavenReportableError
+ ravErr SentryReportableError
fwdErr *forward.Error
dnsWErr *dnsserver.WriteError
)
if errors.As(err, &ravErr) {
- return ravErr.IsRavenReportable()
+ return ravErr.IsSentryReportable()
} else if errors.As(err, &fwdErr) {
return isReportableNetwork(fwdErr.Err)
} else if errors.As(err, &dnsWErr) {
@@ -151,14 +153,13 @@ func isConnectionBreak(err error) (ok bool) {
}
}
-// ravenTags is a convenient alias for map[string]string.
-type ravenTags = map[string]string
+// sentryTags is a convenient alias for map[string]string.
+type sentryTags = map[string]string
-func tagsFromCtx(ctx context.Context) (tags ravenTags) {
- tags = ravenTags{
+// tagsFromCtx returns Sentry tags based on the information from ctx.
+func tagsFromCtx(ctx context.Context) (tags sentryTags) {
+ tags = sentryTags{
"git_revision": agd.Revision(),
- "position": caller(3),
- "version": agd.Version(),
}
var reqID agd.RequestID
diff --git a/internal/errcoll/sentry_test.go b/internal/errcoll/sentry_test.go
new file mode 100644
index 0000000..675b162
--- /dev/null
+++ b/internal/errcoll/sentry_test.go
@@ -0,0 +1,111 @@
+package errcoll_test
+
+import (
+ "context"
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
+ "github.com/AdguardTeam/AdGuardDNS/internal/errcoll"
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/getsentry/sentry-go"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "golang.org/x/exp/maps"
+)
+
+// testSentryTransport is a sentry.Transport for tests.
+type testSentryTransport struct {
+ onConfigure func(opts sentry.ClientOptions)
+ onFlush func(timeout time.Duration) (ok bool)
+ onSend func(e *sentry.Event)
+}
+
+// type check
+var _ sentry.Transport = (*testSentryTransport)(nil)
+
+// Configure implements the sentry.Transport interface for *testSentryTransport.
+func (t *testSentryTransport) Configure(ops sentry.ClientOptions) {
+ t.onConfigure(ops)
+}
+
+// Flush implements the sentry.Transport interface for *testSentryTransport.
+func (t *testSentryTransport) Flush(timeout time.Duration) (ok bool) {
+ return t.onFlush(timeout)
+}
+
+// Send implements the sentry.Transport interface for *testSentryTransport.
+func (t *testSentryTransport) SendEvent(e *sentry.Event) {
+ t.onSend(e)
+}
+
+func TestSentryErrorCollector(t *testing.T) {
+ gotEventCh := make(chan *sentry.Event, 1)
+ tr := &testSentryTransport{
+ onConfigure: func(_ sentry.ClientOptions) {
+ // Do nothing.
+ },
+ onFlush: func(_ time.Duration) (ok bool) {
+ return true
+ },
+ onSend: func(e *sentry.Event) {
+ gotEventCh <- e
+ },
+ }
+
+ sentryClient, err := sentry.NewClient(sentry.ClientOptions{
+ Dsn: "https://user:password@does.not.exist/test",
+ Transport: tr,
+ Release: agd.Version(),
+ })
+ require.NoError(t, err)
+
+ c := errcoll.NewSentryErrorCollector(sentryClient)
+
+ const devID = "dev1234"
+ const fltGrpID = "fg1234"
+ const profID = "prof1234"
+ const reqID = "req5678"
+
+ ctx := context.Background()
+ ctx = agd.ContextWithRequestInfo(ctx, &agd.RequestInfo{
+ Device: &agd.Device{ID: devID},
+ Profile: &agd.Profile{ID: profID},
+ FilteringGroup: &agd.FilteringGroup{ID: fltGrpID},
+ Messages: &dnsmsg.Constructor{
+ FilteredResponseTTL: 10 * time.Second,
+ },
+ ID: reqID,
+ })
+
+ origErr := errors.Error("test error")
+ err = fmt.Errorf("wrapped: %w", origErr)
+ c.Collect(ctx, err)
+
+ gotEvent := <-gotEventCh
+ require.NotNil(t, gotEvent)
+
+ // TODO(a.garipov): Use a transport that is closer to the real one and check
+ // other fields of gotEvent such as Version.
+
+ gotExceptions := gotEvent.Exception
+ require.NotEmpty(t, gotExceptions)
+
+ assert.Equal(t, origErr.Error(), gotExceptions[0].Value)
+
+ gotExc := gotExceptions[len(gotExceptions)-1]
+ assert.Equal(t, err.Error(), gotExc.Value)
+
+ gotTags := maps.Clone(gotEvent.Tags)
+ delete(gotTags, "git_revision")
+
+ wantTags := map[string]string{
+ "device_id": devID,
+ "filtering_group_id": fltGrpID,
+ "profile_id": profID,
+ "request_id": reqID,
+ }
+ assert.Equal(t, wantTags, gotTags)
+}
diff --git a/internal/filter/filter.go b/internal/filter/filter.go
index 431fcc2..e3e8944 100644
--- a/internal/filter/filter.go
+++ b/internal/filter/filter.go
@@ -8,7 +8,6 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/c2h5oh/datasize"
"github.com/miekg/dns"
)
@@ -23,6 +22,12 @@ const maxFilterSize = 128 * int64(datasize.MB)
// TODO(a.garipov): Consider making timeouts where they are used configurable.
const defaultTimeout = 30 * time.Second
+// defaultResolveTimeout is the default timeout for resolving hosts for safe
+// search and safe browsing filters.
+//
+// TODO(ameshkov): Consider making configurable.
+const defaultResolveTimeout = 1 * time.Second
+
// Interface is the DNS request and response filter interface.
type Interface interface {
// FilterRequest filters the DNS request for the provided client. All
@@ -38,22 +43,3 @@ type Interface interface {
// Close closes the filter and frees resources associated with it.
Close() (err error)
}
-
-// Network constants.
-const (
- netIP4 = "ip4"
- netIP6 = "ip6"
-)
-
-// dnsTypeToNetwork converts a DNS RR type to a network type. If rr is neither
-// A nor AAAA, network is an empty string.
-func dnsTypeToNetwork(qt dnsmsg.RRType) (network string) {
- switch qt {
- case dns.TypeA:
- return netIP4
- case dns.TypeAAAA:
- return netIP6
- default:
- return ""
- }
-}
diff --git a/internal/filter/filter_test.go b/internal/filter/filter_test.go
index 4387ddc..dfaca17 100644
--- a/internal/filter/filter_test.go
+++ b/internal/filter/filter_test.go
@@ -14,14 +14,13 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/require"
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
// testFilterID is the standard ID of the filter for tests.
diff --git a/internal/filter/hashprefix.go b/internal/filter/hashprefix.go
index 8f9d3ac..22bda0c 100644
--- a/internal/filter/hashprefix.go
+++ b/internal/filter/hashprefix.go
@@ -7,6 +7,7 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
@@ -40,18 +41,18 @@ type HashPrefixConfig struct {
// hashPrefixFilter is a filter that matches hosts by their hashes based on
// a hash prefix table.
type hashPrefixFilter struct {
- hashes *HashStorage
- resCache *resultCache
- rslvCache *resolveCache
- errColl agd.ErrorCollector
- repHost string
- id agd.FilterListID
+ hashes *HashStorage
+ resCache *resultCache
+ resolver agdnet.Resolver
+ errColl agd.ErrorCollector
+ repHost string
+ id agd.FilterListID
}
// newHashPrefixFilter returns a new hash prefix filter. c must not be nil.
func newHashPrefixFilter(
c *HashPrefixConfig,
- rslvCache *resolveCache,
+ resolver agdnet.Resolver,
errColl agd.ErrorCollector,
id agd.FilterListID,
) (f *hashPrefixFilter) {
@@ -60,12 +61,12 @@ func newHashPrefixFilter(
}
return &hashPrefixFilter{
- hashes: c.Hashes,
- resCache: cache,
- rslvCache: rslvCache,
- errColl: errColl,
- repHost: c.ReplacementHost,
- id: id,
+ hashes: c.Hashes,
+ resCache: cache,
+ resolver: resolver,
+ errColl: errColl,
+ repHost: c.ReplacementHost,
+ id: id,
}
}
@@ -87,8 +88,8 @@ func (f *hashPrefixFilter) filterReq(
return r.(*ResultModified).CloneForReq(req), nil
}
- network := dnsTypeToNetwork(qt)
- if network == "" {
+ fam := netutil.AddrFamilyFromRRType(qt)
+ if fam == netutil.AddrFamilyNone {
return nil, nil
}
@@ -106,8 +107,11 @@ func (f *hashPrefixFilter) filterReq(
return nil, nil
}
+ ctx, cancel := context.WithTimeout(ctx, defaultResolveTimeout)
+ defer cancel()
+
var result *dns.Msg
- ips, err := f.rslvCache.resolve(network, f.repHost)
+ ips, err := f.resolver.LookupIP(ctx, fam, f.repHost)
if err != nil {
agd.Collectf(ctx, f.errColl, "filter %s: resolving: %w", f.id, err)
diff --git a/internal/filter/hashprefix_test.go b/internal/filter/hashprefix_test.go
index d2385e1..6b0c1b7 100644
--- a/internal/filter/hashprefix_test.go
+++ b/internal/filter/hashprefix_test.go
@@ -11,6 +11,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
@@ -48,7 +49,11 @@ func TestStorage_FilterFromContext_safeBrowsing(t *testing.T) {
// Fake Data
- onLookupIP := func(_ context.Context, network, _ string) (ips []net.IP, err error) {
+ onLookupIP := func(
+ _ context.Context,
+ _ netutil.AddrFamily,
+ _ string,
+ ) (ips []net.IP, err error) {
return []net.IP{safeBrowsingSafeIP4}, nil
}
@@ -105,9 +110,9 @@ func TestStorage_FilterFromContext_safeBrowsing(t *testing.T) {
var r filter.Result
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultModified)(nil), r)
- rm, _ := r.(*filter.ResultModified)
+ rm := testutil.RequireTypeAssert[*filter.ResultModified](t, r)
+
assert.Equal(t, rm.Rule, agd.FilterRuleText(safeBrowsingHost))
assert.Equal(t, rm.List, agd.FilterListIDSafeBrowsing)
}
diff --git a/internal/filter/resolvecache.go b/internal/filter/resolvecache.go
deleted file mode 100644
index badbb02..0000000
--- a/internal/filter/resolvecache.go
+++ /dev/null
@@ -1,141 +0,0 @@
-package filter
-
-import (
- "context"
- "fmt"
- "math"
- "net"
- "sync"
- "time"
-
- "github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/golibs/errors"
- "github.com/AdguardTeam/golibs/log"
- "github.com/AdguardTeam/golibs/timeutil"
-)
-
-// Resolve Cache
-
-// resolveCache caches resolved results for hosts for 24 hours. Use it when you
-// need to cache results of lookups of hostnames that don't change IP addresses
-// that often.
-type resolveCache struct {
- resolver agd.Resolver
-
- // mu protects ip4 and ip6.
- mu *sync.RWMutex
- ip4 map[string]*resolveCacheItem
- ip6 map[string]*resolveCacheItem
-}
-
-// resolveCacheItem is an item of the resolved IP cache.
-type resolveCacheItem struct {
- refr time.Time
- ips []net.IP
-}
-
-// newResolveCache returns a new resolved IP cache.
-func newResolveCache(resolver agd.Resolver) (c *resolveCache) {
- return &resolveCache{
- resolver: resolver,
-
- mu: &sync.RWMutex{},
- ip4: map[string]*resolveCacheItem{},
- ip6: map[string]*resolveCacheItem{},
- }
-}
-
-// resolve returns the cached IPs. network must be either "ip4" or "ip6".
-func (c *resolveCache) resolve(network, addr string) (ips []net.IP, err error) {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- var item *resolveCacheItem
- if network == netIP4 {
- item = c.ip4[addr]
- } else {
- item = c.ip6[addr]
- }
-
- // TODO(ameshkov): Consider making configurable.
- if item == nil || time.Since(item.refr) > 1*timeutil.Day {
- item, err = c.refresh(network, addr)
- if err != nil {
- return nil, err
- }
- }
-
- return item.ips, nil
-}
-
-// refresh refreshes the IP addresses.
-func (c *resolveCache) refresh(network, addr string) (item *resolveCacheItem, err error) {
- var ips []net.IP
-
- refr := time.Now()
-
- // Don't resolve IP addresses.
- ip := net.ParseIP(addr)
- if ip != nil {
- ip4 := ip.To4()
- if (network == netIP4 && ip4 != nil) || (network == netIP6 && ip4 == nil) {
- ips = []net.IP{ip}
- } else {
- // Not the right kind of IP address. Cache absence of IP addresses
- // for this network forever.
- ips = []net.IP{}
- }
-
- // Set the refresh time to the maximum date that time.Duration allows to
- // prevent this item from refreshing.
- refr = time.Unix(0, math.MaxInt64)
- } else {
- ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
- defer cancel()
-
- ips, err = c.resolver.LookupIP(ctx, network, addr)
- if err != nil {
- if !isExpectedLookupError(network, err) {
- return nil, fmt.Errorf("resolving %s addr for %q: %w", network, addr, err)
- }
-
- log.Debug("resolve cache: warning: %s", err)
- }
- }
-
- item = &resolveCacheItem{
- refr: refr,
- ips: ips,
- }
- if network == netIP4 {
- c.ip4[addr] = item
- } else {
- c.ip6[addr] = item
- }
-
- return item, nil
-}
-
-// isExpectedLookupError returns true if the error is an expected lookup error.
-func isExpectedLookupError(network string, err error) (ok bool) {
- var dnsErr *net.DNSError
- if network == netIP6 && errors.As(err, &dnsErr) {
- // It's expected that Go default DNS resolver returns a DNS error in
- // some cases when it receives an empty response. It's unclear what
- // exactly triggers this error, though.
- //
- // TODO(ameshkov): Consider researching this in detail.
- return true
- }
-
- var addrErr *net.AddrError
- if !errors.As(err, &addrErr) {
- return false
- }
-
- // Expect the error about no suitable addresses. For example, no IPv6
- // addresses for a host that does have IPv4 ones.
- //
- // See function filterAddrList in ${GOROOT}/src/net/ipsock.go.
- return addrErr.Err == "no suitable address found"
-}
diff --git a/internal/filter/rulelist_test.go b/internal/filter/rulelist_test.go
index d3492f7..d33addc 100644
--- a/internal/filter/rulelist_test.go
+++ b/internal/filter/rulelist_test.go
@@ -71,9 +71,9 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
var r filter.Result
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultBlocked)(nil), r)
- rb, _ := r.(*filter.ResultBlocked)
+ rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
+
assert.Contains(t, rb.Rule, blockedHost)
assert.Equal(t, rb.List, testFilterID)
})
@@ -97,9 +97,9 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
var r filter.Result
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultAllowed)(nil), r)
- ra, _ := r.(*filter.ResultAllowed)
+ ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
+
assert.Contains(t, ra.Rule, allowedHost)
assert.Equal(t, ra.List, testFilterID)
})
@@ -123,9 +123,9 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
var r filter.Result
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultBlocked)(nil), r)
- rb, _ := r.(*filter.ResultBlocked)
+ rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
+
assert.Contains(t, rb.Rule, blockedClientHost)
assert.Equal(t, rb.List, testFilterID)
})
@@ -149,9 +149,9 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
var r filter.Result
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultAllowed)(nil), r)
- ra, _ := r.(*filter.ResultAllowed)
+ ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
+
assert.Contains(t, ra.Rule, allowedClientHost)
assert.Equal(t, ra.List, testFilterID)
})
@@ -175,9 +175,9 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
var r filter.Result
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultBlocked)(nil), r)
- rb, _ := r.(*filter.ResultBlocked)
+ rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
+
assert.Contains(t, rb.Rule, blockedDeviceHost)
assert.Equal(t, rb.List, testFilterID)
})
@@ -201,9 +201,9 @@ func TestStorage_FilterFromContext_ruleList_request(t *testing.T) {
var r filter.Result
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultAllowed)(nil), r)
- ra, _ := r.(*filter.ResultAllowed)
+ ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
+
assert.Contains(t, ra.Rule, allowedDeviceHost)
assert.Equal(t, ra.List, testFilterID)
})
@@ -286,9 +286,9 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
var r filter.Result
r, err = f.FilterResponse(ctx, resp, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultBlocked)(nil), r)
- rb, _ := r.(*filter.ResultBlocked)
+ rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
+
assert.Contains(t, rb.Rule, blockedIP4.String())
assert.Equal(t, rb.List, testFilterID)
})
@@ -304,9 +304,9 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
var r filter.Result
r, err = f.FilterResponse(ctx, resp, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultAllowed)(nil), r)
- ra, _ := r.(*filter.ResultAllowed)
+ ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
+
assert.Contains(t, ra.Rule, allowedIP4.String())
assert.Equal(t, ra.List, testFilterID)
})
@@ -322,9 +322,9 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
var r filter.Result
r, err = f.FilterResponse(ctx, resp, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultBlocked)(nil), r)
- rb, _ := r.(*filter.ResultBlocked)
+ rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
+
assert.Contains(t, rb.Rule, blockedHost)
assert.Equal(t, rb.List, testFilterID)
})
@@ -340,9 +340,9 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
var r filter.Result
r, err = f.FilterResponse(ctx, resp, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultAllowed)(nil), r)
- ra, _ := r.(*filter.ResultAllowed)
+ ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
+
assert.Contains(t, ra.Rule, allowedHost)
assert.Equal(t, ra.List, testFilterID)
})
@@ -358,9 +358,9 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
var r filter.Result
r, err = f.FilterResponse(ctx, resp, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultBlocked)(nil), r)
- rb, _ := r.(*filter.ResultBlocked)
+ rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
+
assert.Contains(t, rb.Rule, blockedClientHost)
assert.Equal(t, rb.List, testFilterID)
})
@@ -376,9 +376,9 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
var r filter.Result
r, err = f.FilterResponse(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultAllowed)(nil), r)
- ra, _ := r.(*filter.ResultAllowed)
+ ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
+
assert.Contains(t, ra.Rule, allowedClientHost)
assert.Equal(t, ra.List, testFilterID)
})
@@ -409,9 +409,9 @@ func TestStorage_FilterFromContext_ruleList_response(t *testing.T) {
var r filter.Result
r, err = f.FilterResponse(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultBlocked)(nil), r)
- rb, _ := r.(*filter.ResultBlocked)
+ rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
+
assert.Contains(t, rb.Rule, "cname.blocked")
assert.Equal(t, rb.List, testFilterID)
})
diff --git a/internal/filter/safesearch.go b/internal/filter/safesearch.go
index 093ed66..bf1a3a2 100644
--- a/internal/filter/safesearch.go
+++ b/internal/filter/safesearch.go
@@ -7,8 +7,10 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg"
"github.com/AdguardTeam/golibs/log"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/urlfilter"
"github.com/miekg/dns"
"github.com/patrickmn/go-cache"
@@ -21,27 +23,23 @@ type safeSearch struct {
// resultCache contains cached results.
resultCache *resultCache
- // rslvCache contains resolved IPs.
- rslvCache *resolveCache
-
// flt is used to filter requests.
flt *ruleListFilter
+ // resolver resolves IP addresses.
+ resolver agdnet.Resolver
+
// errColl is used to report rare errors.
errColl agd.ErrorCollector
}
// safeSearchConfig contains configuration for the safe search filter.
type safeSearchConfig struct {
- rslvCache *resolveCache
-
- errColl agd.ErrorCollector
-
- list *agd.FilterList
-
+ list *agd.FilterList
+ resolver agdnet.Resolver
+ errColl agd.ErrorCollector
cacheDir string
-
- ttl time.Duration
+ ttl time.Duration
//lint:ignore U1000 TODO(a.garipov): Currently unused. See AGDNS-398.
cacheSize int
@@ -55,9 +53,9 @@ func newSafeSearch(c *safeSearchConfig) (f *safeSearch) {
}
return &safeSearch{
- rslvCache: c.rslvCache,
resultCache: resCache,
flt: newRuleListFilter(c.list, c.cacheDir),
+ resolver: c.resolver,
errColl: c.errColl,
}
}
@@ -73,8 +71,8 @@ func (f *safeSearch) filterReq(
req *dns.Msg,
) (r Result, err error) {
qt := ri.QType
- network := dnsTypeToNetwork(qt)
- if network == "" {
+ fam := netutil.AddrFamilyFromRRType(qt)
+ if fam == netutil.AddrFamilyNone {
return nil, nil
}
@@ -93,8 +91,11 @@ func (f *safeSearch) filterReq(
return r.(*ResultModified).CloneForReq(req), nil
}
+ ctx, cancel := context.WithTimeout(ctx, defaultResolveTimeout)
+ defer cancel()
+
var result *dns.Msg
- ips, err := f.rslvCache.resolve(network, repHost)
+ ips, err := f.resolver.LookupIP(ctx, fam, repHost)
if err != nil {
agd.Collectf(ctx, f.errColl, "filter %s: resolving: %w", f.flt.id(), err)
diff --git a/internal/filter/safesearch_test.go b/internal/filter/safesearch_test.go
index 3237a4f..881810c 100644
--- a/internal/filter/safesearch_test.go
+++ b/internal/filter/safesearch_test.go
@@ -11,6 +11,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
@@ -23,10 +24,14 @@ func TestStorage_FilterFromContext_safeSearch(t *testing.T) {
}
numLookupIP := 0
- onLookupIP := func(_ context.Context, network, _ string) (ips []net.IP, err error) {
+ onLookupIP := func(
+ _ context.Context,
+ fam netutil.AddrFamily,
+ _ string,
+ ) (ips []net.IP, err error) {
numLookupIP++
- if network == "ip4" {
+ if fam == netutil.AddrFamilyIPv4 {
return []net.IP{safeSearchIPRespIP4}, nil
}
diff --git a/internal/filter/storage.go b/internal/filter/storage.go
index e324b54..a490be0 100644
--- a/internal/filter/storage.go
+++ b/internal/filter/storage.go
@@ -11,9 +11,11 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
+ "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
+ "github.com/AdguardTeam/golibs/timeutil"
"github.com/bluele/gcache"
"github.com/prometheus/client_golang/prometheus"
)
@@ -115,7 +117,7 @@ type DefaultStorageConfig struct {
ErrColl agd.ErrorCollector
// Resolver is used to resolve hosts in safe search.
- Resolver agd.Resolver
+ Resolver agdnet.Resolver
// CacheDir is the path to the directory where the cached filter files are
// put. The directory must exist.
@@ -136,25 +138,26 @@ type DefaultStorageConfig struct {
// NewDefaultStorage returns a new filter storage. c must not be nil.
func NewDefaultStorage(c *DefaultStorageConfig) (s *DefaultStorage, err error) {
- rslvCache := newResolveCache(c.Resolver)
+ // TODO(ameshkov): Consider making configurable.
+ resolver := agdnet.NewCachingResolver(c.Resolver, 1*timeutil.Day)
safeBrowsing := newHashPrefixFilter(
c.SafeBrowsing,
- rslvCache,
+ resolver,
c.ErrColl,
agd.FilterListIDSafeBrowsing,
)
adultBlocking := newHashPrefixFilter(
c.AdultBlocking,
- rslvCache,
+ resolver,
c.ErrColl,
agd.FilterListIDAdultBlocking,
)
genSafeSearch := newSafeSearch(&safeSearchConfig{
- rslvCache: rslvCache,
- errColl: c.ErrColl,
+ resolver: resolver,
+ errColl: c.ErrColl,
list: &agd.FilterList{
URL: c.GeneralSafeSearchRulesURL,
ID: agd.FilterListIDGeneralSafeSearch,
@@ -165,8 +168,8 @@ func NewDefaultStorage(c *DefaultStorageConfig) (s *DefaultStorage, err error) {
})
ytSafeSearch := newSafeSearch(&safeSearchConfig{
- rslvCache: rslvCache,
- errColl: c.ErrColl,
+ resolver: resolver,
+ errColl: c.ErrColl,
list: &agd.FilterList{
URL: c.YoutubeSafeSearchRulesURL,
ID: agd.FilterListIDYoutubeSafeSearch,
diff --git a/internal/filter/storage_test.go b/internal/filter/storage_test.go
index fa7da7a..3891d80 100644
--- a/internal/filter/storage_test.go
+++ b/internal/filter/storage_test.go
@@ -11,6 +11,7 @@ import (
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
@@ -78,9 +79,9 @@ func TestStorage_FilterFromContext(t *testing.T) {
var r filter.Result
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultBlocked)(nil), r)
- rb, _ := r.(*filter.ResultBlocked)
+ rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
+
assert.Contains(t, rb.Rule, blockedHost)
assert.Equal(t, rb.List, testFilterID)
})
@@ -104,9 +105,9 @@ func TestStorage_FilterFromContext(t *testing.T) {
var r filter.Result
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultBlocked)(nil), r)
- rb, _ := r.(*filter.ResultBlocked)
+ rb := testutil.RequireTypeAssert[*filter.ResultBlocked](t, r)
+
assert.Contains(t, rb.Rule, customHost)
assert.Equal(t, rb.List, agd.FilterListIDCustom)
})
@@ -141,7 +142,11 @@ func TestStorage_FilterFromContext_customAllow(t *testing.T) {
}
resolver := &agdtest.Resolver{
- OnLookupIP: func(_ context.Context, network, _ string) (ips []net.IP, err error) {
+ OnLookupIP: func(
+ _ context.Context,
+ _ netutil.AddrFamily,
+ _ string,
+ ) (ips []net.IP, err error) {
return []net.IP{safeBrowsingSafeIP4}, nil
},
}
@@ -219,9 +224,9 @@ func TestStorage_FilterFromContext_customAllow(t *testing.T) {
r, err := f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultAllowed)(nil), r)
- ra, _ := r.(*filter.ResultAllowed)
+ ra := testutil.RequireTypeAssert[*filter.ResultAllowed](t, r)
+
assert.Equal(t, ra.Rule, agd.FilterRuleText(safeBrowsingAllowRule))
assert.Equal(t, ra.List, agd.FilterListIDCustom)
}
@@ -232,7 +237,11 @@ func TestStorage_FilterFromContext_schedule(t *testing.T) {
}
resolver := &agdtest.Resolver{
- OnLookupIP: func(_ context.Context, network, _ string) (ips []net.IP, err error) {
+ OnLookupIP: func(
+ _ context.Context,
+ _ netutil.AddrFamily,
+ _ string,
+ ) (ips []net.IP, err error) {
return []net.IP{safeBrowsingSafeIP4}, nil
},
}
@@ -351,9 +360,9 @@ func TestStorage_FilterFromContext_schedule(t *testing.T) {
r, err = f.FilterRequest(ctx, req, ri)
require.NoError(t, err)
- require.IsType(t, (*filter.ResultModified)(nil), r)
- rm, _ := r.(*filter.ResultModified)
+ rm := testutil.RequireTypeAssert[*filter.ResultModified](t, r)
+
assert.Equal(t, rm.Rule, agd.FilterRuleText(safeBrowsingHost))
assert.Equal(t, rm.List, agd.FilterListIDAdultBlocking)
}
diff --git a/internal/geoip/asntops.go b/internal/geoip/asntops.go
index 36c41ac..8e0b690 100644
--- a/internal/geoip/asntops.go
+++ b/internal/geoip/asntops.go
@@ -17,8 +17,9 @@ var allTopASNs = map[agd.ASN]struct{}{
1267: {},
1547: {},
1680: {},
- 1901: {},
- 2110: {},
+ 1955: {},
+ 2107: {},
+ 2108: {},
2116: {},
2119: {},
2516: {},
@@ -65,6 +66,8 @@ var allTopASNs = map[agd.ASN]struct{}{
4775: {},
4788: {},
4804: {},
+ 4808: {},
+ 4812: {},
4817: {},
4818: {},
4837: {},
@@ -75,16 +78,13 @@ var allTopASNs = map[agd.ASN]struct{}{
5410: {},
5416: {},
5432: {},
- 5466: {},
5483: {},
- 5484: {},
5578: {},
5603: {},
5607: {},
5610: {},
5617: {},
5639: {},
- 5645: {},
5769: {},
6057: {},
6147: {},
@@ -92,7 +92,6 @@ var allTopASNs = map[agd.ASN]struct{}{
6306: {},
6327: {},
6400: {},
- 6535: {},
6568: {},
6639: {},
6661: {},
@@ -109,7 +108,6 @@ var allTopASNs = map[agd.ASN]struct{}{
6821: {},
6830: {},
6848: {},
- 6849: {},
6855: {},
6866: {},
6871: {},
@@ -134,31 +132,28 @@ var allTopASNs = map[agd.ASN]struct{}{
8359: {},
8374: {},
8376: {},
- 8386: {},
8400: {},
8402: {},
8412: {},
8447: {},
- 8449: {},
8452: {},
8473: {},
8544: {},
8551: {},
8585: {},
- 8661: {},
8680: {},
8681: {},
8697: {},
8708: {},
- 8728: {},
8764: {},
8781: {},
8818: {},
+ 8847: {},
8866: {},
8881: {},
8926: {},
8953: {},
- 8966: {},
+ 8978: {},
9009: {},
9038: {},
9051: {},
@@ -194,6 +189,7 @@ var allTopASNs = map[agd.ASN]struct{}{
10101: {},
10131: {},
10139: {},
+ 10143: {},
10219: {},
10226: {},
10269: {},
@@ -203,6 +199,7 @@ var allTopASNs = map[agd.ASN]struct{}{
11081: {},
11139: {},
11315: {},
+ 11427: {},
11556: {},
11594: {},
11664: {},
@@ -213,9 +210,7 @@ var allTopASNs = map[agd.ASN]struct{}{
12297: {},
12302: {},
12322: {},
- 12338: {},
12353: {},
- 12361: {},
12389: {},
12392: {},
12400: {},
@@ -227,7 +222,6 @@ var allTopASNs = map[agd.ASN]struct{}{
12709: {},
12716: {},
12735: {},
- 12741: {},
12764: {},
12793: {},
12810: {},
@@ -242,6 +236,7 @@ var allTopASNs = map[agd.ASN]struct{}{
12997: {},
13036: {},
13046: {},
+ 13092: {},
13122: {},
13124: {},
13194: {},
@@ -274,7 +269,6 @@ var allTopASNs = map[agd.ASN]struct{}{
15704: {},
15706: {},
15735: {},
- 15751: {},
15796: {},
15802: {},
15805: {},
@@ -291,14 +285,13 @@ var allTopASNs = map[agd.ASN]struct{}{
16135: {},
16232: {},
16276: {},
- 16322: {},
16345: {},
- 16413: {},
16509: {},
16637: {},
16705: {},
17072: {},
17079: {},
+ 17411: {},
17421: {},
17458: {},
17470: {},
@@ -313,6 +306,7 @@ var allTopASNs = map[agd.ASN]struct{}{
17858: {},
17882: {},
17893: {},
+ 17924: {},
17976: {},
17993: {},
18001: {},
@@ -326,14 +320,11 @@ var allTopASNs = map[agd.ASN]struct{}{
19429: {},
19711: {},
19863: {},
- 20001: {},
20057: {},
20115: {},
20294: {},
- 20299: {},
20473: {},
20634: {},
- 20661: {},
20776: {},
20845: {},
20875: {},
@@ -353,6 +344,7 @@ var allTopASNs = map[agd.ASN]struct{}{
21450: {},
21497: {},
21575: {},
+ 21744: {},
21826: {},
21928: {},
21996: {},
@@ -360,6 +352,7 @@ var allTopASNs = map[agd.ASN]struct{}{
22069: {},
22085: {},
22351: {},
+ 22363: {},
22724: {},
22773: {},
22927: {},
@@ -370,10 +363,10 @@ var allTopASNs = map[agd.ASN]struct{}{
23655: {},
23657: {},
23674: {},
- 23688: {},
23693: {},
23752: {},
23889: {},
+ 23917: {},
23955: {},
23969: {},
24158: {},
@@ -389,6 +382,7 @@ var allTopASNs = map[agd.ASN]struct{}{
24757: {},
24835: {},
24921: {},
+ 24940: {},
25019: {},
25106: {},
25135: {},
@@ -401,7 +395,6 @@ var allTopASNs = map[agd.ASN]struct{}{
25472: {},
25513: {},
25543: {},
- 26130: {},
26599: {},
26611: {},
26615: {},
@@ -426,20 +419,20 @@ var allTopASNs = map[agd.ASN]struct{}{
27884: {},
27895: {},
27901: {},
- 27903: {},
27924: {},
27947: {},
27995: {},
28005: {},
28006: {},
28036: {},
- 28094: {},
28104: {},
28118: {},
28126: {},
28403: {},
+ 28469: {},
28548: {},
28573: {},
+ 28698: {},
28787: {},
28884: {},
28885: {},
@@ -452,12 +445,10 @@ var allTopASNs = map[agd.ASN]struct{}{
29247: {},
29256: {},
29310: {},
- 29314: {},
29355: {},
29357: {},
29447: {},
29465: {},
- 29497: {},
29518: {},
29544: {},
29555: {},
@@ -477,8 +468,8 @@ var allTopASNs = map[agd.ASN]struct{}{
30992: {},
30999: {},
31012: {},
+ 31037: {},
31042: {},
- 31122: {},
31126: {},
31133: {},
31163: {},
@@ -488,7 +479,6 @@ var allTopASNs = map[agd.ASN]struct{}{
31252: {},
31404: {},
31452: {},
- 31549: {},
31615: {},
31721: {},
32020: {},
@@ -502,7 +492,6 @@ var allTopASNs = map[agd.ASN]struct{}{
33779: {},
33874: {},
33915: {},
- 33983: {},
34058: {},
34170: {},
34557: {},
@@ -515,6 +504,7 @@ var allTopASNs = map[agd.ASN]struct{}{
35228: {},
35432: {},
35444: {},
+ 35725: {},
35805: {},
35819: {},
35900: {},
@@ -524,7 +514,6 @@ var allTopASNs = map[agd.ASN]struct{}{
36873: {},
36884: {},
36890: {},
- 36892: {},
36902: {},
36903: {},
36907: {},
@@ -533,7 +522,6 @@ var allTopASNs = map[agd.ASN]struct{}{
36924: {},
36925: {},
36926: {},
- 36930: {},
36935: {},
36939: {},
36945: {},
@@ -552,11 +540,11 @@ var allTopASNs = map[agd.ASN]struct{}{
37006: {},
37009: {},
37020: {},
- 37030: {},
37035: {},
37037: {},
37054: {},
37057: {},
+ 37069: {},
37075: {},
37081: {},
37094: {},
@@ -565,7 +553,6 @@ var allTopASNs = map[agd.ASN]struct{}{
37119: {},
37133: {},
37136: {},
- 37148: {},
37154: {},
37164: {},
37168: {},
@@ -590,11 +577,9 @@ var allTopASNs = map[agd.ASN]struct{}{
37371: {},
37376: {},
37385: {},
- 37406: {},
37410: {},
37424: {},
37425: {},
- 37429: {},
37440: {},
37447: {},
37451: {},
@@ -612,7 +597,6 @@ var allTopASNs = map[agd.ASN]struct{}{
37531: {},
37541: {},
37550: {},
- 37552: {},
37559: {},
37563: {},
37575: {},
@@ -624,24 +608,26 @@ var allTopASNs = map[agd.ASN]struct{}{
37645: {},
37649: {},
37671: {},
- 37680: {},
+ 37678: {},
37693: {},
37705: {},
38009: {},
38077: {},
38195: {},
38201: {},
+ 38322: {},
38442: {},
38466: {},
+ 38565: {},
38623: {},
38742: {},
38800: {},
38819: {},
+ 38901: {},
38999: {},
39010: {},
39232: {},
39603: {},
- 39611: {},
39642: {},
39891: {},
40945: {},
@@ -650,7 +636,6 @@ var allTopASNs = map[agd.ASN]struct{}{
41329: {},
41330: {},
41557: {},
- 41653: {},
41697: {},
41738: {},
41750: {},
@@ -658,24 +643,23 @@ var allTopASNs = map[agd.ASN]struct{}{
41937: {},
42003: {},
42082: {},
- 42237: {},
+ 42162: {},
42298: {},
42313: {},
42437: {},
42560: {},
+ 42610: {},
42772: {},
42779: {},
42863: {},
- 42912: {},
42961: {},
- 43019: {},
43197: {},
+ 43242: {},
43447: {},
43557: {},
43571: {},
43612: {},
43733: {},
- 43754: {},
43766: {},
43824: {},
43925: {},
@@ -684,23 +668,16 @@ var allTopASNs = map[agd.ASN]struct{}{
44087: {},
44143: {},
44244: {},
- 44395: {},
- 44489: {},
44558: {},
44869: {},
- 45011: {},
- 45102: {},
45143: {},
- 45168: {},
45177: {},
45178: {},
- 45193: {},
45245: {},
45345: {},
45355: {},
45356: {},
45498: {},
- 45558: {},
45609: {},
45629: {},
45650: {},
@@ -710,7 +687,7 @@ var allTopASNs = map[agd.ASN]struct{}{
45879: {},
45891: {},
45899: {},
- 45925: {},
+ 45960: {},
46408: {},
46650: {},
47139: {},
@@ -730,6 +707,7 @@ var allTopASNs = map[agd.ASN]struct{}{
48728: {},
48832: {},
48887: {},
+ 48953: {},
49273: {},
49734: {},
49800: {},
@@ -741,15 +719,13 @@ var allTopASNs = map[agd.ASN]struct{}{
50266: {},
50616: {},
50710: {},
- 50810: {},
50973: {},
51207: {},
- 51346: {},
51375: {},
51407: {},
51495: {},
+ 51684: {},
51765: {},
- 51896: {},
52228: {},
52233: {},
52253: {},
@@ -761,25 +737,23 @@ var allTopASNs = map[agd.ASN]struct{}{
52362: {},
52398: {},
52468: {},
- 53667: {},
55330: {},
+ 55424: {},
55430: {},
- 55722: {},
- 55792: {},
+ 55769: {},
55805: {},
55836: {},
55850: {},
- 55885: {},
55943: {},
55944: {},
56055: {},
56089: {},
56167: {},
56300: {},
+ 56653: {},
56665: {},
56696: {},
56902: {},
- 57218: {},
57269: {},
57293: {},
57388: {},
@@ -787,19 +761,16 @@ var allTopASNs = map[agd.ASN]struct{}{
57704: {},
58224: {},
58460: {},
- 58689: {},
58731: {},
58952: {},
59257: {},
- 59381: {},
+ 59588: {},
+ 59625: {},
59989: {},
60068: {},
60258: {},
- 60471: {},
- 60781: {},
61143: {},
61461: {},
- 63526: {},
63949: {},
64466: {},
131178: {},
@@ -809,11 +780,12 @@ var allTopASNs = map[agd.ASN]struct{}{
131445: {},
132045: {},
132061: {},
- 132148: {},
132165: {},
132167: {},
132199: {},
+ 132429: {},
132471: {},
+ 132618: {},
132831: {},
133076: {},
133384: {},
@@ -822,47 +794,42 @@ var allTopASNs = map[agd.ASN]struct{}{
133579: {},
133612: {},
134783: {},
- 134840: {},
135300: {},
- 135409: {},
136255: {},
- 136480: {},
+ 136442: {},
+ 136969: {},
137412: {},
- 137824: {},
138179: {},
- 139020: {},
139759: {},
139831: {},
139898: {},
141995: {},
+ 142541: {},
196838: {},
196874: {},
- 197207: {},
- 197288: {},
- 197540: {},
197830: {},
198279: {},
+ 198288: {},
198484: {},
198605: {},
199140: {},
+ 199155: {},
199276: {},
199731: {},
+ 200134: {},
+ 200313: {},
200651: {},
- 200740: {},
201019: {},
201167: {},
201767: {},
201986: {},
202087: {},
202254: {},
- 202391: {},
+ 203214: {},
203953: {},
203995: {},
- 204151: {},
204170: {},
204342: {},
- 204649: {},
- 205110: {},
205368: {},
205714: {},
206026: {},
@@ -870,59 +837,61 @@ var allTopASNs = map[agd.ASN]struct{}{
206206: {},
206262: {},
207569: {},
+ 207651: {},
207810: {},
- 207876: {},
- 210542: {},
+ 209240: {},
+ 210315: {},
213155: {},
- 262181: {},
+ 213373: {},
262186: {},
262197: {},
262202: {},
262210: {},
262239: {},
- 263238: {},
263725: {},
263783: {},
263824: {},
264628: {},
264645: {},
- 264663: {},
264668: {},
264731: {},
+ 265727: {},
+ 269729: {},
271773: {},
327697: {},
+ 327707: {},
327712: {},
327738: {},
327756: {},
327765: {},
327769: {},
- 327776: {},
327786: {},
327799: {},
327802: {},
327885: {},
+ 327903: {},
327931: {},
327934: {},
328061: {},
+ 328079: {},
328088: {},
- 328136: {},
+ 328118: {},
328169: {},
328191: {},
328200: {},
+ 328207: {},
328228: {},
328250: {},
328286: {},
328297: {},
- 328309: {},
- 328411: {},
328453: {},
328469: {},
328471: {},
328605: {},
- 328614: {},
- 329078: {},
+ 328727: {},
+ 328755: {},
+ 328943: {},
394311: {},
- 394648: {},
395561: {},
396304: {},
396357: {},
@@ -934,11 +903,11 @@ var allTopASNs = map[agd.ASN]struct{}{
var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountryAD: 6752,
agd.CountryAE: 5384,
- agd.CountryAF: 131284,
+ agd.CountryAF: 45178,
agd.CountryAG: 11594,
- agd.CountryAI: 11139,
+ agd.CountryAI: 396304,
agd.CountryAL: 42313,
- agd.CountryAM: 44395,
+ agd.CountryAM: 12297,
agd.CountryAO: 37119,
agd.CountryAR: 7303,
agd.CountryAS: 9751,
@@ -946,10 +915,10 @@ var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountryAU: 1221,
agd.CountryAW: 11816,
agd.CountryAX: 3238,
- agd.CountryAZ: 34170,
+ agd.CountryAZ: 31721,
agd.CountryBA: 9146,
agd.CountryBB: 14813,
- agd.CountryBD: 24389,
+ agd.CountryBD: 24432,
agd.CountryBE: 5432,
agd.CountryBF: 37577,
agd.CountryBG: 8866,
@@ -957,7 +926,7 @@ var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountryBI: 327799,
agd.CountryBJ: 37424,
agd.CountryBL: 3215,
- agd.CountryBM: 32020,
+ agd.CountryBM: 3855,
agd.CountryBN: 10094,
agd.CountryBO: 6568,
agd.CountryBQ: 27745,
@@ -968,20 +937,20 @@ var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountryBY: 25106,
agd.CountryBZ: 10269,
agd.CountryCA: 812,
- agd.CountryCD: 37447,
+ agd.CountryCD: 37020,
agd.CountryCF: 37460,
agd.CountryCG: 37451,
agd.CountryCH: 3303,
agd.CountryCI: 29571,
agd.CountryCK: 10131,
- agd.CountryCL: 7418,
+ agd.CountryCL: 27651,
agd.CountryCM: 36912,
agd.CountryCN: 4134,
agd.CountryCO: 26611,
agd.CountryCR: 11830,
agd.CountryCU: 27725,
agd.CountryCV: 37517,
- agd.CountryCW: 52233,
+ agd.CountryCW: 11081,
agd.CountryCY: 6866,
agd.CountryCZ: 5610,
agd.CountryDE: 3320,
@@ -999,7 +968,7 @@ var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountryET: 24757,
agd.CountryFI: 51765,
agd.CountryFJ: 38442,
- agd.CountryFK: 204649,
+ agd.CountryFK: 198605,
agd.CountryFM: 139759,
agd.CountryFO: 15389,
agd.CountryFR: 3215,
@@ -1007,33 +976,33 @@ var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountryGB: 9009,
agd.CountryGD: 46650,
agd.CountryGE: 16010,
- agd.CountryGF: 48252,
+ agd.CountryGF: 16028,
agd.CountryGG: 8680,
agd.CountryGH: 30986,
agd.CountryGI: 8301,
agd.CountryGL: 8818,
- agd.CountryGM: 25250,
+ agd.CountryGM: 37309,
agd.CountryGN: 37461,
agd.CountryGP: 3215,
agd.CountryGQ: 37337,
agd.CountryGR: 6799,
agd.CountryGT: 14754,
- agd.CountryGU: 9246,
+ agd.CountryGU: 3605,
agd.CountryGW: 327769,
agd.CountryGY: 19863,
- agd.CountryHK: 9269,
+ agd.CountryHK: 4760,
agd.CountryHN: 14754,
agd.CountryHR: 5391,
agd.CountryHT: 27653,
agd.CountryHU: 5483,
agd.CountryID: 7713,
- agd.CountryIE: 15502,
+ agd.CountryIE: 16509,
agd.CountryIL: 12400,
agd.CountryIM: 13122,
agd.CountryIN: 55836,
agd.CountryIO: 17458,
- agd.CountryIQ: 50710,
- agd.CountryIR: 202391,
+ agd.CountryIQ: 203214,
+ agd.CountryIR: 44244,
agd.CountryIS: 43571,
agd.CountryIT: 1267,
agd.CountryJE: 8680,
@@ -1044,16 +1013,16 @@ var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountryKG: 50223,
agd.CountryKH: 38623,
agd.CountryKI: 134783,
- agd.CountryKM: 328061,
- agd.CountryKN: 36290,
+ agd.CountryKM: 36939,
+ agd.CountryKN: 11139,
agd.CountryKR: 4766,
agd.CountryKW: 29357,
agd.CountryKY: 6639,
agd.CountryKZ: 206026,
agd.CountryLA: 9873,
- agd.CountryLB: 42003,
+ agd.CountryLB: 38999,
agd.CountryLC: 15344,
- agd.CountryLI: 20634,
+ agd.CountryLI: 22363,
agd.CountryLK: 18001,
agd.CountryLR: 37094,
agd.CountryLS: 33567,
@@ -1065,7 +1034,7 @@ var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountryMC: 6758,
agd.CountryMD: 8926,
agd.CountryME: 43940,
- agd.CountryMF: 21351,
+ agd.CountryMF: 33392,
agd.CountryMG: 37054,
agd.CountryMH: 24439,
agd.CountryMK: 6821,
@@ -1086,28 +1055,28 @@ var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountryMZ: 37342,
agd.CountryNA: 36996,
agd.CountryNC: 18200,
- agd.CountryNE: 37531,
- agd.CountryNF: 45168,
+ agd.CountryNE: 37233,
agd.CountryNG: 29465,
agd.CountryNI: 14754,
agd.CountryNL: 1136,
agd.CountryNO: 2119,
agd.CountryNP: 17501,
agd.CountryNR: 45355,
- agd.CountryNU: 55885,
+ agd.CountryNU: 198605,
agd.CountryNZ: 4771,
agd.CountryOM: 28885,
- agd.CountryPA: 18809,
+ agd.CountryPA: 11556,
agd.CountryPE: 12252,
agd.CountryPF: 9471,
- agd.CountryPG: 38009,
+ agd.CountryPG: 58460,
agd.CountryPH: 9299,
agd.CountryPK: 17557,
agd.CountryPL: 43447,
agd.CountryPM: 3695,
+ agd.CountryPN: 198605,
agd.CountryPR: 14638,
agd.CountryPS: 12975,
- agd.CountryPT: 3243,
+ agd.CountryPT: 12353,
agd.CountryPW: 17893,
agd.CountryPY: 23201,
agd.CountryQA: 42298,
@@ -1123,30 +1092,31 @@ var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountrySE: 1257,
agd.CountrySG: 4773,
agd.CountrySI: 5603,
+ agd.CountrySJ: 198605,
agd.CountrySK: 6855,
agd.CountrySL: 37164,
- agd.CountrySM: 15433,
+ agd.CountrySM: 196874,
agd.CountrySN: 8346,
agd.CountrySO: 37371,
agd.CountrySR: 27775,
- agd.CountrySS: 37594,
+ agd.CountrySS: 37376,
agd.CountryST: 328191,
agd.CountrySV: 14754,
agd.CountrySX: 27781,
agd.CountrySY: 29256,
- agd.CountrySZ: 328169,
+ agd.CountrySZ: 19711,
agd.CountryTC: 394311,
- agd.CountryTD: 327756,
- agd.CountryTG: 24691,
+ agd.CountryTD: 327802,
+ agd.CountryTG: 36924,
agd.CountryTH: 131445,
agd.CountryTJ: 43197,
agd.CountryTL: 58731,
agd.CountryTM: 51495,
agd.CountryTN: 37705,
- agd.CountryTO: 38201,
- agd.CountryTR: 9121,
+ agd.CountryTO: 45355,
+ agd.CountryTR: 16135,
agd.CountryTT: 27800,
- agd.CountryTV: 135409,
+ agd.CountryTV: 198605,
agd.CountryTW: 3462,
agd.CountryTZ: 36908,
agd.CountryUA: 15895,
@@ -1154,9 +1124,10 @@ var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountryUS: 21928,
agd.CountryUY: 6057,
agd.CountryUZ: 8193,
+ agd.CountryVA: 8978,
agd.CountryVC: 46408,
agd.CountryVE: 8048,
- agd.CountryVG: 396357,
+ agd.CountryVG: 14813,
agd.CountryVI: 14434,
agd.CountryVN: 7552,
agd.CountryVU: 9249,
@@ -1167,5 +1138,5 @@ var countryTopASNs = map[agd.Country]agd.ASN{
agd.CountryYT: 3215,
agd.CountryZA: 37457,
agd.CountryZM: 37287,
- agd.CountryZW: 37204,
+ agd.CountryZW: 30969,
}
diff --git a/internal/geoip/file.go b/internal/geoip/file.go
index e428274..e7845b8 100644
--- a/internal/geoip/file.go
+++ b/internal/geoip/file.go
@@ -9,9 +9,9 @@ import (
"sync"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/bluele/gcache"
"github.com/oschwald/maxminddb-golang"
)
@@ -122,7 +122,7 @@ func ipToCacheKey(ip netip.Addr) (k any) {
var _ Interface = (*File)(nil)
// SubnetByLocation implements the Interface interface for *File. fam must be
-// either agdnet.AddrFamilyIPv4 or agdnet.AddrFamilyIPv6.
+// either [netutil.AddrFamilyIPv4] or [netutil.AddrFamilyIPv6].
//
// The process of the subnet selection is as follows:
//
@@ -142,7 +142,7 @@ var _ Interface = (*File)(nil)
func (f *File) SubnetByLocation(
c agd.Country,
asn agd.ASN,
- fam agdnet.AddrFamily,
+ fam netutil.AddrFamily,
) (n netip.Prefix, err error) {
// TODO(a.garipov): Thoroughly cover with tests.
@@ -153,10 +153,10 @@ func (f *File) SubnetByLocation(
defer f.mu.RUnlock()
switch fam {
- case agdnet.AddrFamilyIPv4:
+ case netutil.AddrFamilyIPv4:
topASNSubnets = f.ipv4TopASNSubnets
ctrySubnets = f.ipv4CountrySubnets
- case agdnet.AddrFamilyIPv6:
+ case netutil.AddrFamilyIPv6:
topASNSubnets = f.ipv6TopASNSubnets
ctrySubnets = f.ipv6CountrySubnets
default:
@@ -178,7 +178,7 @@ func (f *File) SubnetByLocation(
return n, nil
}
- return agdnet.ZeroSubnet(fam), nil
+ return netutil.ZeroPrefix(fam), nil
}
// Data implements the Interface interface for *File. If ip is netip.Addr{},
diff --git a/internal/geoip/file_test.go b/internal/geoip/file_test.go
index bfd7c96..3288b99 100644
--- a/internal/geoip/file_test.go
+++ b/internal/geoip/file_test.go
@@ -6,9 +6,9 @@ import (
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/geoip"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -90,12 +90,12 @@ func TestFile_SubnetByLocation(t *testing.T) {
require.NoError(t, err)
// TODO(a.garipov): Actually test ASN queries once we have the data.
- gotIPv4Subnet, err := g.SubnetByLocation(testIPv4SubnetCtry, 0, agdnet.AddrFamilyIPv4)
+ gotIPv4Subnet, err := g.SubnetByLocation(testIPv4SubnetCtry, 0, netutil.AddrFamilyIPv4)
require.NoError(t, err)
assert.Equal(t, testIPv4CountrySubnet, gotIPv4Subnet)
- gotIPv6Subnet, err := g.SubnetByLocation(testIPv6SubnetCtry, 0, agdnet.AddrFamilyIPv6)
+ gotIPv6Subnet, err := g.SubnetByLocation(testIPv6SubnetCtry, 0, netutil.AddrFamilyIPv6)
require.NoError(t, err)
assert.Equal(t, testIPv6CountrySubnet, gotIPv6Subnet)
diff --git a/internal/geoip/filescanner.go b/internal/geoip/filescanner.go
index 299a1d7..1c884fe 100644
--- a/internal/geoip/filescanner.go
+++ b/internal/geoip/filescanner.go
@@ -5,8 +5,8 @@ import (
"net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
"github.com/AdguardTeam/golibs/log"
+ "github.com/AdguardTeam/golibs/netutil"
"github.com/oschwald/maxminddb-golang"
)
@@ -73,8 +73,8 @@ func resetTopASNSubnets(r *maxminddb.Reader) (ipv4, ipv6 asnSubnets, err error)
return nil, nil, fmt.Errorf("reading: %w", err)
}
- applyTopASNSubnetHacks(ipv4, agdnet.AddrFamilyIPv4)
- applyTopASNSubnetHacks(ipv6, agdnet.AddrFamilyIPv6)
+ applyTopASNSubnetHacks(ipv4, netutil.AddrFamilyIPv4)
+ applyTopASNSubnetHacks(ipv6, netutil.AddrFamilyIPv6)
log.Debug("geoip: got ipv4 top asn subnets %v", ipv4)
log.Debug("geoip: got ipv6 top asn subnets %v", ipv6)
@@ -93,7 +93,7 @@ func subnetASNData(nets *maxminddb.Networks) (asn agd.ASN, subnet netip.Prefix,
// Assume that there are no actual IPv6-mapped IPv4 addresses in the GeoIP
// database.
- subnet, err = agdnet.IPNetToPrefixNoMapped(n)
+ subnet, err = netutil.IPNetToPrefixNoMapped(n)
if err != nil {
return 0, netip.Prefix{}, fmt.Errorf("converting subnet: %w", err)
}
@@ -143,11 +143,11 @@ func dist(a, b int) (d int) {
// applyTopASNSubnetHacks modifies the data in subnets based on the previous
// experience and user reports. It also make sure that all items in subnets
// have the desired length for their protocol. subnets must not be nil. fam
-// must be either agdnet.AddrFamilyIPv4 or agdnet.AddrFamilyIPv6.
-func applyTopASNSubnetHacks(subnets asnSubnets, fam agdnet.AddrFamily) {
+// must be either [netutil.AddrFamilyIPv4] or [netutil.AddrFamilyIPv6].
+func applyTopASNSubnetHacks(subnets asnSubnets, fam netutil.AddrFamily) {
var desiredLength int
switch fam {
- case agdnet.AddrFamilyIPv4:
+ case netutil.AddrFamilyIPv4:
// We've got complaints from Moscow Megafon users that they cannot use
// the YouTube app on Android and iOS when we use a different subnet.
// It appears that the IPs for domain "youtubei.googleapis.com" are
@@ -155,7 +155,7 @@ func applyTopASNSubnetHacks(subnets asnSubnets, fam agdnet.AddrFamily) {
// the ECS option.
subnets[25159] = netip.MustParsePrefix("178.176.72.0/24")
desiredLength = desiredIPv4SubnetLength
- case agdnet.AddrFamilyIPv6:
+ case netutil.AddrFamilyIPv6:
// TODO(a.garipov): Add more if we find them.
desiredLength = desiredIPv6SubnetLength
@@ -206,8 +206,8 @@ func resetCountrySubnets(r *maxminddb.Reader) (ipv4, ipv6 countrySubnets, err er
return nil, nil, fmt.Errorf("reading: %w", err)
}
- applyCountrySubnetHacks(ipv4, agdnet.AddrFamilyIPv4)
- applyCountrySubnetHacks(ipv6, agdnet.AddrFamilyIPv6)
+ applyCountrySubnetHacks(ipv4, netutil.AddrFamilyIPv4)
+ applyCountrySubnetHacks(ipv6, netutil.AddrFamilyIPv6)
log.Debug("geoip: got ipv4 country subnets %v", ipv4)
log.Debug("geoip: got ipv6 country subnets %v", ipv6)
@@ -218,15 +218,15 @@ func resetCountrySubnets(r *maxminddb.Reader) (ipv4, ipv6 countrySubnets, err er
// applyCountrySubnetHacks modifies the data in subnets based on the previous
// experience and user reports. It also make sure that all items in subnets
// have the desired length for their protocol. subnets must not be nil. fam
-// must be either agdnet.AddrFamilyIPv4 or agdnet.AddrFamilyIPv6.
-func applyCountrySubnetHacks(subnets countrySubnets, fam agdnet.AddrFamily) {
+// must be either [netutil.AddrFamilyIPv4] or [netutil.AddrFamilyIPv6].
+func applyCountrySubnetHacks(subnets countrySubnets, fam netutil.AddrFamily) {
var desiredLength int
switch fam {
- case agdnet.AddrFamilyIPv4:
+ case netutil.AddrFamilyIPv4:
// TODO(a.garipov): Add more if we find them.
desiredLength = desiredIPv4SubnetLength
- case agdnet.AddrFamilyIPv6:
+ case netutil.AddrFamilyIPv6:
// TODO(a.garipov): Add more if we find them.
desiredLength = desiredIPv6SubnetLength
@@ -252,7 +252,7 @@ func subnetCountryData(nets *maxminddb.Networks) (c agd.Country, subnet netip.Pr
// Assume that there are no actual IPv6-mapped IPv4 addresses in the GeoIP
// database.
- subnet, err = agdnet.IPNetToPrefixNoMapped(n)
+ subnet, err = netutil.IPNetToPrefixNoMapped(n)
if err != nil {
return agd.CountryNone, netip.Prefix{}, fmt.Errorf("converting subnet: %w", err)
}
diff --git a/internal/geoip/geoip.go b/internal/geoip/geoip.go
index 35ee990..764d04f 100644
--- a/internal/geoip/geoip.go
+++ b/internal/geoip/geoip.go
@@ -5,7 +5,7 @@ import (
"net/netip"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdnet"
+ "github.com/AdguardTeam/golibs/netutil"
)
// Interface is the interface for the GeoIP database that stores the geographic
@@ -13,8 +13,8 @@ import (
type Interface interface {
// SubnetByLocation returns the default subnet for country c and ASN a, if
// there is one. If there isn't, n is an unspecified subnet. fam must be
- // either agdnet.AddrFamilyIPv4 or agdnet.AddrFamilyIPv6.
- SubnetByLocation(c agd.Country, a agd.ASN, fam agdnet.AddrFamily) (n netip.Prefix, err error)
+ // either [netutil.AddrFamilyIPv4] or [netutil.AddrFamilyIPv6].
+ SubnetByLocation(c agd.Country, a agd.ASN, fam netutil.AddrFamily) (n netip.Prefix, err error)
// Data returns the GeoIP data for ip. It may use host to get cached GeoIP
// data if ip is netip.Addr{}.
diff --git a/internal/geoip/geoip_test.go b/internal/geoip/geoip_test.go
index 4166734..cbaa87a 100644
--- a/internal/geoip/geoip_test.go
+++ b/internal/geoip/geoip_test.go
@@ -5,11 +5,11 @@ import (
"testing"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/golibs/testutil"
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
// Paths to test data.
diff --git a/internal/querylog/fs_test.go b/internal/querylog/fs_test.go
index bcc152f..02a9e6a 100644
--- a/internal/querylog/fs_test.go
+++ b/internal/querylog/fs_test.go
@@ -51,11 +51,11 @@ func TestFileSystem_Write(t *testing.T) {
"q":1,
"f":2,
"s":1,
- "p":2,
+ "p":8,
"r":0
}`) + "\n"
- assert.Equal(t, []byte(want), b)
+ assert.Equal(t, want, string(b))
t.Run("nxdomain", func(t *testing.T) {
e = testEntry()
@@ -83,11 +83,11 @@ func TestFileSystem_Write(t *testing.T) {
"q":1,
"f":1,
"s":1,
- "p":2,
+ "p":8,
"r":3
}`) + "\n"
- assert.Equal(t, []byte(want), b)
+ assert.Equal(t, want, string(b))
})
}
diff --git a/internal/querylog/querylog_test.go b/internal/querylog/querylog_test.go
index 442a180..4586af7 100644
--- a/internal/querylog/querylog_test.go
+++ b/internal/querylog/querylog_test.go
@@ -5,14 +5,14 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/filter"
"github.com/AdguardTeam/AdGuardDNS/internal/querylog"
+ "github.com/AdguardTeam/golibs/testutil"
"github.com/miekg/dns"
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
// Helpers
@@ -32,7 +32,7 @@ func testEntry() (e *querylog.Entry) {
ClientCountry: agd.CountryRU,
ResponseCountry: agd.CountryUS,
DomainFQDN: "example.com.",
- Protocol: agd.ProtoDNSUDP,
+ Protocol: agd.ProtoDNS,
ClientASN: 1234,
Elapsed: 5,
RequestType: dns.TypeA,
diff --git a/internal/rulestat/rulestat_test.go b/internal/rulestat/rulestat_test.go
index 6f207ec..490814f 100644
--- a/internal/rulestat/rulestat_test.go
+++ b/internal/rulestat/rulestat_test.go
@@ -3,9 +3,9 @@ package rulestat_test
import (
"testing"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
+ "github.com/AdguardTeam/golibs/testutil"
)
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
diff --git a/internal/tools/go.mod b/internal/tools/go.mod
index 955f271..8bd2554 100644
--- a/internal/tools/go.mod
+++ b/internal/tools/go.mod
@@ -4,32 +4,30 @@ go 1.19
require (
github.com/fzipp/gocyclo v0.6.0
- github.com/golangci/misspell v0.3.5
- github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8
+ github.com/golangci/misspell v0.4.0
+ github.com/gordonklaus/ineffassign v0.0.0-20220928193011-d2c82e48359b
github.com/kisielk/errcheck v1.6.2
- github.com/kyoh86/looppointer v0.1.8-0.20220224024524-f953a93c424a
- github.com/securego/gosec/v2 v2.13.1
- golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
- golang.org/x/tools v0.1.13-0.20220803210227-8b9a1fbdf5c3
- golang.org/x/vuln v0.0.0-20220902211423-27dd78d2ca39
+ github.com/kyoh86/looppointer v0.1.9
+ github.com/securego/gosec/v2 v2.14.0
+ golang.org/x/tools v0.2.0
+ golang.org/x/vuln v0.0.0-20221025230227-995372c58a16
honnef.co/go/tools v0.3.3
- mvdan.cc/gofumpt v0.3.1
- mvdan.cc/unparam v0.0.0-20220831102321-2fc90a84c7ec
+ mvdan.cc/gofumpt v0.4.0
+ mvdan.cc/unparam v0.0.0-20220926085101-66de63301820
)
require (
- github.com/BurntSushi/toml v1.2.0 // indirect
- github.com/client9/misspell v0.3.4 // indirect
- github.com/google/go-cmp v0.5.8 // indirect
+ github.com/BurntSushi/toml v1.2.1 // indirect
+ github.com/google/go-cmp v0.5.9 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gookit/color v1.5.2 // indirect
github.com/kyoh86/nolint v0.0.1 // indirect
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
- github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
- golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 // indirect
- golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 // indirect
- golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
- golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect
- golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77 // indirect
+ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
+ golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 // indirect
+ golang.org/x/exp/typeparams v0.0.0-20221031165847-c99f073a8326 // indirect
+ golang.org/x/mod v0.6.0 // indirect
+ golang.org/x/sync v0.1.0 // indirect
+ golang.org/x/sys v0.1.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
diff --git a/internal/tools/go.sum b/internal/tools/go.sum
index 72e5309..3e4f57e 100644
--- a/internal/tools/go.sum
+++ b/internal/tools/go.sum
@@ -1,51 +1,51 @@
-github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
-github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
+github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns=
+github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
-github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo=
-github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
-github.com/google/go-cmdtest v0.4.0 h1:ToXh6W5spLp3npJV92tk6d5hIpUPYEzHLkD+rncbyhI=
-github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
-github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/golangci/misspell v0.4.0 h1:KtVB/hTK4bbL/S6bs64rYyk8adjmh1BygbBiaAiX+a0=
+github.com/golangci/misspell v0.4.0/go.mod h1:W6O/bwV6lGDxUCChm2ykw9NQdd5bYd1Xkjo88UcWyJc=
+github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
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/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
-github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 h1:PVRE9d4AQKmbelZ7emNig1+NT27DUmKZn5qXxfio54U=
-github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
+github.com/gordonklaus/ineffassign v0.0.0-20220928193011-d2c82e48359b h1:TYNAU9lu7ggdAereRq0dzCIDzHu9mNyGLj/hd5PXq8I=
+github.com/gordonklaus/ineffassign v0.0.0-20220928193011-d2c82e48359b/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
github.com/kisielk/errcheck v1.6.2 h1:uGQ9xI8/pgc9iOoCe7kWQgRE6SBTrCGmTSf0LrEtY7c=
github.com/kisielk/errcheck v1.6.2/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kyoh86/looppointer v0.1.8-0.20220224024524-f953a93c424a h1:da9XVPg3Ev0xFoUs5nbJhOmyNvfcyhZEFfRn+aiw+E8=
-github.com/kyoh86/looppointer v0.1.8-0.20220224024524-f953a93c424a/go.mod h1:3Cmdc4LzTl3XqEEsZl91PidV/cqgZaoM4vXOG6akEE0=
+github.com/kyoh86/looppointer v0.1.9 h1:siTt2dqv+pW3y5gvykZXhlVcTnUVMDf11bGlB9GL5PI=
+github.com/kyoh86/looppointer v0.1.9/go.mod h1:q358WcM8cMWU+5vzqukvaZtnJi1kw/MpRHQm3xvTrjw=
github.com/kyoh86/nolint v0.0.1 h1:GjNxDEkVn2wAxKHtP7iNTrRxytRZ1wXxLV5j4XzGfRU=
github.com/kyoh86/nolint v0.0.1/go.mod h1:1ZiZZ7qqrZ9dZegU96phwVcdQOMKIqRzFJL3ewq9gtI=
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA=
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8=
-github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
-github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q=
+github.com/onsi/ginkgo/v2 v2.3.1 h1:8SbseP7qM32WcvE6VaN6vfXxv698izmsJ1UQX9ve7T8=
+github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
-github.com/securego/gosec/v2 v2.13.1 h1:7mU32qn2dyC81MH9L2kefnQyRMUarfDER3iQyMHcjYM=
-github.com/securego/gosec/v2 v2.13.1/go.mod h1:EO1sImBMBWFjOTFzMWfTRrZW6M15gm60ljzrmy/wtHo=
+github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/securego/gosec/v2 v2.14.0 h1:U1hfs0oBackChXA72plCYVA4cOlQ4gO+209dHiSNZbI=
+github.com/securego/gosec/v2 v2.14.0/go.mod h1:Ff03zEi5NwSOfXj9nFpBfhbWTtROCkg9N+9goggrYn4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -53,31 +53,27 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
-golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
-golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 h1:Ic/qN6TEifvObMGQy72k0n1LlJr7DjWWEi+MOsDOiSk=
-golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
+golang.org/x/exp v0.0.0-20221031165847-c99f073a8326/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp/typeparams v0.0.0-20221031165847-c99f073a8326 h1:fl8k2zg28yA23264d82M4dp+YlJ3ngDcpuB1bewkQi4=
+golang.org/x/exp/typeparams v0.0.0-20221031165847-c99f073a8326/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
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 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
+golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc=
-golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -87,32 +83,28 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/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-20220224003255-dbe011f71a99/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77 h1:C1tElbkWrsSkn3IRl1GCW/gETw1TywWIPgwZtXTZbYg=
-golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
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-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
-golang.org/x/tools v0.1.13-0.20220803210227-8b9a1fbdf5c3 h1:aE4T3aJwdCNz+s35ScSQYUzeGu7BOLDHZ1bBHVurqqY=
-golang.org/x/tools v0.1.13-0.20220803210227-8b9a1fbdf5c3/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/vuln v0.0.0-20220902211423-27dd78d2ca39 h1:501+NfNjDh4IT4HOzdeezTOFD7njtY49aXJN1oY3E1s=
-golang.org/x/vuln v0.0.0-20220902211423-27dd78d2ca39/go.mod h1:7tDfEDtOLlzHQRi4Yzfg5seVBSvouUIjyPzBx4q5CxQ=
+golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
+golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
+golang.org/x/vuln v0.0.0-20221025230227-995372c58a16 h1:/H6ddBUaKrFDOBFz0Y3l1/Ppbx19f/rK11jABxiqKFw=
+golang.org/x/vuln v0.0.0-20221025230227-995372c58a16/go.mod h1:F12iebNzxRMpJsm4W7ape+r/KdnXiSy3VC94WsyCG68=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+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 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
-gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -120,7 +112,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=
honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=
-mvdan.cc/gofumpt v0.3.1 h1:avhhrOmv0IuvQVK7fvwV91oFSGAk5/6Po8GXTzICeu8=
-mvdan.cc/gofumpt v0.3.1/go.mod h1:w3ymliuxvzVx8DAutBnVyDqYb1Niy/yCJt/lk821YCE=
-mvdan.cc/unparam v0.0.0-20220831102321-2fc90a84c7ec h1:uyA9l4gQQUHSm9zPgTzarWmsjIw7s7hAldLwVxLlu1Y=
-mvdan.cc/unparam v0.0.0-20220831102321-2fc90a84c7ec/go.mod h1:EAphbHIduKNGVweyBBwWQd24rSnLy4DsjlpxRFYE498=
+mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
+mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
+mvdan.cc/unparam v0.0.0-20220926085101-66de63301820 h1:fggBTMFbBz7CMny3mWZphe0B/6D8ILBunvvB1cNNHi8=
+mvdan.cc/unparam v0.0.0-20220926085101-66de63301820/go.mod h1:7fKhD/gH+APJ9Y27S2PYO7+oVWtb3XPrw9W5ayxVq2A=
diff --git a/internal/websvc/handler.go b/internal/websvc/handler.go
index 92798f8..55c20d9 100644
--- a/internal/websvc/handler.go
+++ b/internal/websvc/handler.go
@@ -141,7 +141,7 @@ func (sc StaticContent) serveHTTP(w http.ResponseWriter, r *http.Request) (serve
}
if f.AllowOrigin != "" {
- w.Header().Set(agdhttp.HdrNameAccessControlAllowOrigin, f.ContentType)
+ w.Header().Set(agdhttp.HdrNameAccessControlAllowOrigin, f.AllowOrigin)
}
w.Header().Set(agdhttp.HdrNameContentType, f.ContentType)
w.WriteHeader(http.StatusOK)
diff --git a/internal/websvc/websvc_test.go b/internal/websvc/websvc_test.go
index e2e8535..8b663ef 100644
--- a/internal/websvc/websvc_test.go
+++ b/internal/websvc/websvc_test.go
@@ -10,7 +10,6 @@ import (
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
- "github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
"github.com/AdguardTeam/AdGuardDNS/internal/websvc"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
@@ -20,7 +19,7 @@ import (
const testTimeout = 1 * time.Second
func TestMain(m *testing.M) {
- agdtest.DiscardLogOutput(m)
+ testutil.DiscardLogOutput(m)
}
func TestNew(t *testing.T) {
diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh
index c1a0424..941c89b 100644
--- a/scripts/make/go-lint.sh
+++ b/scripts/make/go-lint.sh
@@ -50,7 +50,7 @@ trap not_found EXIT
go_version="$( "${GO:-go}" version )"
readonly go_version
-go_min_version='go1.19'
+go_min_version='go1.19.3'
go_version_msg="
warning: your go version (${go_version}) is different from the recommended minimal one (${go_min_version}).
if you have the version installed, please set the GO environment variable.
@@ -135,6 +135,8 @@ underscores() {
-e '_noreuseport.go'\
-e '_reuseport.go'\
-e '_test.go'\
+ -e '_unix.go'\
+ -e '_windows.go'\
-v\
| sed -e 's/./\t\0/'
)"
diff --git a/scripts/make/go-test.sh b/scripts/make/go-test.sh
index bcb51be..4fb2aa6 100644
--- a/scripts/make/go-test.sh
+++ b/scripts/make/go-test.sh
@@ -38,7 +38,8 @@ go="${GO:-go}"
count_flags='--count=1'
shuffle_flags='--shuffle=on'
-timeout_flags="${TIMEOUT_FLAGS:---timeout=30s}"
+# TODO(ameshkov): Find out, why QUIC tests are so slow, and return to 30s.
+timeout_flags="${TIMEOUT_FLAGS:---timeout=60s}"
readonly go count_flags shuffle_flags timeout_flags
# TODO(a.garipov): Remove the dnsserver stuff once it is separated.