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.