diff --git a/AGHTechDoc.md b/AGHTechDoc.md index 4758a0da..8f69e5bd 100644 --- a/AGHTechDoc.md +++ b/AGHTechDoc.md @@ -1355,6 +1355,19 @@ Internally, all supported services are stored as a map: service name -> list of rules +### API: Get blocked services list of available services + +Request: + + GET /control/blocked_services/services + +Response: + + 200 OK + + [ "name1", ... ] + + ### API: Get blocked services list Request: diff --git a/CHANGELOG.md b/CHANGELOG.md index 12118439..cc192a1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,21 +20,83 @@ and this project adheres to - Weaker cipher suites that use the CBC (cipher block chaining) mode of operation have been disabled ([#2993]). -### Deprecated - -- Go 1.18 support. v0.109.0 will require at least Go 1.19 to build. - [#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 + + + + +## [v0.107.12] - 2022-09-07 See also the [v0.107.12 GitHub milestone][ms-v0.107.12]. -[ms-v0.107.12]: https://github.com/AdguardTeam/AdGuardHome/milestone/47?closed=1 ---> +### Security + +- Go version was updated to prevent the possibility of exploiting the + CVE-2022-27664 and CVE-2022-32190 Go vulnerabilities fixed in + [Go 1.18.6][go-1.18.6]. + +### Added + +- New `bool`, `dur`, `u8`, and `u16` DHCP options to provide more convenience on + options control by setting values in a human-readable format ([#4705]). See + also a [Wiki page][wiki-dhcp-opts]. +- New `del` DHCP option which removes the corresponding option from server's + response ([#4337]). See also a [Wiki page][wiki-dhcp-opts]. + + **NOTE:** This modifier affects all the parameters in the response and not + only the requested ones. +- A new HTTP API, `GET /control/blocked_services/services`, that lists all + available blocked services ([#4535]). + +### Changed + +- The DHCP options handling is now closer to the [RFC 2131][rfc-2131] ([#4705]). +- When the DHCP server is enabled, queries for domain names under + `dhcp.local_domain_name` not pointing to real DHCP client hostnames are now + processed by filters ([#4865]). +- The DHCPREQUEST handling is now closer to the [RFC 2131][rfc-2131] ([#4863]). +- The internal DNS client, used to resolve hostnames of external clients and + also during automatic updates, now respects the upstream mode settings for the + main DNS client ([#4403]). + +### Deprecated + +- Ports 784 and 8853 for DNS-over-QUIC in Docker images. Users who still serve + DoQ on these ports are encouraged to move to the standard port 853. These + ports will be removed from the `EXPOSE` section of our `Dockerfile` in a + future release. +- Go 1.18 support. v0.109.0 will require at least Go 1.19 to build. + +### Fixed + +- The length of the DHCP server's response is now at least 576 bytes as per RFC + 2131 recommendation ([#4337]). +- Dynamic leases created with empty hostnames ([#4745]). +- Unnecessary logging of non-critical statistics errors ([#4850]). + +[#4337]: https://github.com/AdguardTeam/AdGuardHome/issues/4337 +[#4403]: https://github.com/AdguardTeam/AdGuardHome/issues/4403 +[#4535]: https://github.com/AdguardTeam/AdGuardHome/issues/4535 +[#4705]: https://github.com/AdguardTeam/AdGuardHome/issues/4705 +[#4745]: https://github.com/AdguardTeam/AdGuardHome/issues/4745 +[#4850]: https://github.com/AdguardTeam/AdGuardHome/issues/4850 +[#4863]: https://github.com/AdguardTeam/AdGuardHome/issues/4863 +[#4865]: https://github.com/AdguardTeam/AdGuardHome/issues/4865 + +[go-1.18.6]: https://groups.google.com/g/golang-announce/c/x49AQzIVX-s +[ms-v0.107.12]: https://github.com/AdguardTeam/AdGuardHome/milestone/48?closed=1 +[rfc-2131]: https://datatracker.ietf.org/doc/html/rfc2131 +[wiki-dhcp-opts]: https://github.com/adguardTeam/adGuardHome/wiki/DHCP#config-4 @@ -214,9 +276,10 @@ See also the [v0.107.7 GitHub milestone][ms-v0.107.7]. seconds. - Domain-specific private reverse DNS upstream servers are now validated to allow only `*.in-addr.arpa` and `*.ip6.arpa` domains pointing to - locally-served networks ([#3381]). **Note:** If you already have invalid - entries in your configuration, consider removing them manually, since they - essentially had no effect. + locally-served networks ([#3381]). + + **NOTE:** If you already have invalid entries in your configuration, consider + removing them manually, since they essentially had no effect. - Response filtering is now performed using the record types of the answer section of messages as opposed to the type of the question ([#4238]). - Instead of adding the build time information, the build scripts now use the @@ -1139,11 +1202,12 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2]. -[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.11...HEAD +[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.12...HEAD +[v0.107.12]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.11...v0.107.12 [v0.107.11]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.10...v0.107.11 [v0.107.10]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.9...v0.107.10 [v0.107.9]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.8...v0.107.9 diff --git a/README.md b/README.md index cac993d0..43c9db89 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@  

- AdGuard Home + + + AdGuard Home +

Privacy protection center for you and your devices

- Free and open source, powerful network-wide ads & trackers blocking DNS server. + Free and open source, powerful network-wide ads & trackers blocking DNS + server.

@@ -366,6 +370,7 @@ Here's what you can also do to contribute: * [AdGuard Home on GLInet routers](https://forum.gl-inet.com/t/adguardhome-on-gl-routers/10664) by [Gl-Inet](https://gl-inet.com/) * [Cloudron app](https://git.cloudron.io/cloudron/adguard-home-app) by [@gramakri](https://github.com/gramakri) * [Asuswrt-Merlin-AdGuardHome-Installer](https://github.com/jumpsmm7/Asuswrt-Merlin-AdGuardHome-Installer) by [@jumpsmm7](https://github.com/jumpsmm7) aka [@SomeWhereOverTheRainBow](https://www.snbforums.com/members/somewhereovertherainbow.64179/) +* [Node.js library](https://github.com/Andrea055/AdguardHomeAPI) by [@Andrea055](https://github.com/Andrea055/) ## Acknowledgments diff --git a/bamboo-specs/release.yaml b/bamboo-specs/release.yaml index e379dc73..ddd95734 100644 --- a/bamboo-specs/release.yaml +++ b/bamboo-specs/release.yaml @@ -7,7 +7,7 @@ # Make sure to sync any changes with the branch overrides below. 'variables': 'channel': 'edge' - 'dockerGo': 'adguard/golang-ubuntu:5.0' + 'dockerGo': 'adguard/golang-ubuntu:5.1' 'stages': - 'Build frontend': @@ -322,7 +322,7 @@ # need to build a few of these. 'variables': 'channel': 'beta' - 'dockerGo': 'adguard/golang-ubuntu:5.0' + 'dockerGo': 'adguard/golang-ubuntu:5.1' # release-vX.Y.Z branches are the branches from which the actual final release # is built. - '^release-v[0-9]+\.[0-9]+\.[0-9]+': @@ -337,4 +337,4 @@ # are the ones that actually get released. 'variables': 'channel': 'release' - 'dockerGo': 'adguard/golang-ubuntu:5.0' + 'dockerGo': 'adguard/golang-ubuntu:5.1' diff --git a/bamboo-specs/test.yaml b/bamboo-specs/test.yaml index cd799fda..fe26bd10 100644 --- a/bamboo-specs/test.yaml +++ b/bamboo-specs/test.yaml @@ -5,7 +5,7 @@ 'key': 'AHBRTSPECS' 'name': 'AdGuard Home - Build and run tests' 'variables': - 'dockerGo': 'adguard/golang-ubuntu:5.0' + 'dockerGo': 'adguard/golang-ubuntu:5.1' 'stages': - 'Tests': diff --git a/client/src/__locales/ar.json b/client/src/__locales/ar.json index 2384ecaf..54076076 100644 --- a/client/src/__locales/ar.json +++ b/client/src/__locales/ar.json @@ -1,5 +1,5 @@ { - "client_settings": "الإعدادات", + "client_settings": "إعدادات العميل", "example_upstream_reserved": "يمكنك تحديد <0> DNS upstream لنطاق معين (نطاقات) ", "example_upstream_comment": "يمكنك تحديد تعليق", "upstream_parallel": "استخدام الاستعلامات المتوازية لتسريع الحل عن طريق الاستعلام في وقت واحد عن جميع خوادم المنبع", @@ -47,6 +47,7 @@ "form_error_server_name": "اسم الخادم غير صالح", "form_error_subnet": "لا تحتوي الشبكة الفرعية \"{{cidr}}\" على عنوان IP \"{{ip}}\"", "form_error_positive": "يجب أن يكون أكبر من 0", + "form_error_gateway_ip": "لا يمكن الحصول على عنوان IP الخاص بالبوابة", "out_of_range_error": "يجب أن يكون خارج النطاق \"{{start}}\" - \"{{end}}\"", "lower_range_start_error": "يجب أن يكون أقل من نطاق البداية", "greater_range_start_error": "يجب أن يكون أكبر من نطاق البداية", @@ -210,17 +211,20 @@ "example_comment_hash": "# تعليق أيضًا", "example_regex_meaning": "منع الوصول إلى النطاقات المطابقة للتعبير العادي المحدد.", "example_upstream_regular": "regular DNS (over UDP);", + "example_upstream_regular_port": "DNS عادي (عبر UDP ، مع المنفذ) ؛", "example_upstream_udp": "regular DNS (over UDP, hostname);", "example_upstream_dot": "مشفر<0>DNS-over-TLS;", "example_upstream_doh": "مشفر <0>DNS-over-HTTPS;", "example_upstream_doq": "encrypted <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS Stamps for <1>DNSCrypt or <2>DNS-over-HTTPS resolvers;", "example_upstream_tcp": "regular DNS (over TCP);", + "example_upstream_tcp_port": "DNS عادي (عبر TCP ، مع منفذ) ؛", "example_upstream_tcp_hostname": "regular DNS (over TCP, hostname);", "all_lists_up_to_date_toast": "جميع القوائم محدثة بالفعل", "updated_upstream_dns_toast": "تم حفظ خوادم Upstream بنجاح", "dns_test_ok_toast": "تعمل خوادم DNS المحددة بشكل صحيح", "dns_test_not_ok_toast": "خادم \"{{key}}\": لا يمكن استخدامه يرجى التحقق من كتابته بشكل صحيح", + "dns_test_warning_toast": "المنبع \"{{key}}\" لا يستجيب لطلبات الاختبار وقد لا يعمل بشكل صحيح", "unblock": "إلغاء الحظر", "block": "حظر", "disallow_this_client": "منع هذا العميل", @@ -362,6 +366,7 @@ "encryption_config_saved": "تم حفظ اعدادات التشفير", "encryption_server": "اسم الخادم", "encryption_server_enter": "ادخل عنوان النطاق الخاص بك", + "encryption_server_desc": "من أجل استخدام HTTPS ، تحتاج إلى إدخال اسم الخادم الذي يتطابق مع شهادة SSL أو شهادة البدل. إذا لم يتم تعيين الحقل ، فسيقبل اتصالات TLS لأي مجال.", "encryption_redirect": "إعادة التوجيه إلى HTTPS تلقائيًا", "encryption_redirect_desc": "إذا تم تحديده ، فسيقوم AdGuard Home بإعادة توجيهك تلقائيًا من عناوين HTTP إلى عناوين HTTPS.", "encryption_https": "منفذ HTTPS", diff --git a/client/src/__locales/be.json b/client/src/__locales/be.json index 1f21106e..cdefa29a 100644 --- a/client/src/__locales/be.json +++ b/client/src/__locales/be.json @@ -211,12 +211,14 @@ "example_comment_hash": "# І вось так таксама.", "example_regex_meaning": "блакаваць доступ да даменаў, якія адпавядаюць зададзенаму рэгулярнаму выразу.", "example_upstream_regular": "звычайны DNS (наўзверх UDP);", + "example_upstream_regular_port": "звычайны DNS (праз UDP, імя хаста);", "example_upstream_udp": "звычайны DNS (праз UDP, імя хаста);", "example_upstream_dot": "зашыфраваны <0>DNS-over-TLS;", "example_upstream_doh": "зашыфраваны <0>DNS-over-HTTPS;", "example_upstream_doq": "зашыфраваны <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS Stamps для <1>DNSCrypt ці <2>DNS-over-HTTPS рэзалвераў;", "example_upstream_tcp": "звычайны DNS (наўзверх TCP);", + "example_upstream_tcp_port": "звычайны DNS (праз TCP, імя хаста);", "example_upstream_tcp_hostname": "звычайны DNS (праз TCP, імя хаста);", "all_lists_up_to_date_toast": "Усе спісы ўжо абноўлены", "updated_upstream_dns_toast": "Upstream DNS-серверы абноўлены", diff --git a/client/src/__locales/cs.json b/client/src/__locales/cs.json index a01e1c92..4e48bc46 100644 --- a/client/src/__locales/cs.json +++ b/client/src/__locales/cs.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Také komentář.", "example_regex_meaning": "blokuje přístup doménám, které vyhovují regulárnímu výrazu.", "example_upstream_regular": "obvyklý DNS (přes UDP);", + "example_upstream_regular_port": "obvyklý DNS (skrze UDP, s portem);", "example_upstream_udp": "obvyklý DNS (skrze UDP, název hostitele);", "example_upstream_dot": "šifrovaný <0>DNS skrze TLS;", "example_upstream_doh": "šifrovaný <0>DNS skrze HTTPS;", "example_upstream_doq": "šifrovaný <0>DNS skrze QUIC;", "example_upstream_sdns": "<0>DNS razítka pro <1>DNSCrypt nebo <2>DNS skrze HTTPS řešitele;", "example_upstream_tcp": "obvyklý DNS (přes TCP);", + "example_upstream_tcp_port": "obvyklý DNS (skrze TCP, s portem);", "example_upstream_tcp_hostname": "obvyklý DNS (skrze TCP, název hostitele);", "all_lists_up_to_date_toast": "Všechny seznamy jsou již aktuální", "updated_upstream_dns_toast": "Odchozí servery byly úspěšně uloženy", diff --git a/client/src/__locales/da.json b/client/src/__locales/da.json index 32bec1e2..dddf6249 100644 --- a/client/src/__locales/da.json +++ b/client/src/__locales/da.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Også en kommentar.", "example_regex_meaning": "blokér adgang til domæner matchernde det angivne regulære udtryk", "example_upstream_regular": "almindelig DNS (over UDP)", + "example_upstream_regular_port": "almindelig DNS (over UDP, med port);", "example_upstream_udp": "almindelig DNS (over UDP, værtsnavn);", "example_upstream_dot": "krypteret <0>DNS-over-TLS", "example_upstream_doh": "krypteret <0>DNS-over-HTTPS", "example_upstream_doq": "krypteret <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS Stamps til <1>DNSCrypt eller <2>DNS-over-HTTPS-opløsere;", "example_upstream_tcp": "almindelig DNS (over TCP)", + "example_upstream_tcp_port": "almindelig DNS (over TCP, med port);", "example_upstream_tcp_hostname": "almindelig DNS (over TCP, værtsnavn);", "all_lists_up_to_date_toast": "Alle lister er allerede opdaterede", "updated_upstream_dns_toast": "Upstream-servere er gemt", diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index a1e49718..20e2572f 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Auch ein Kommentar.", "example_regex_meaning": "Zugriff auf die Domains sperren, die dem angegebenen regulären Ausdruck entsprechen.", "example_upstream_regular": "reguläres DNS (over UDP);", + "example_upstream_regular_port": "normales DNS (über UDP, mit Port);", "example_upstream_udp": "normales DNS (über UDP, Hostname);", "example_upstream_dot": "verschlüsseltes <0>DNS-over-TLS;", "example_upstream_doh": "verschlüsseltes <0>DNS-over-HTTPS;", "example_upstream_doq": "verschlüsseltes <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS-Stempel für <1>DNSCrypt oder <2>DNS-over-HTTPS Resolver;", "example_upstream_tcp": "reguläres DNS (over TCP);", + "example_upstream_tcp_port": "normales DNS (über TCP, mit Port);", "example_upstream_tcp_hostname": "normales DNS (über TCP, Hostname);", "all_lists_up_to_date_toast": "Alle Listen sind bereits auf dem neuesten Stand", "updated_upstream_dns_toast": "Upstream-Server erfolgreich gespeichert", @@ -445,7 +447,7 @@ "access_disallowed_title": "Nicht zugelassene Clients", "access_disallowed_desc": "Eine Liste von CIDRs, IP-Adressen oder ClientIDs. Wenn diese Liste gefüllt ist, weist AdGuard Home Anfragen von diesen Clients zurück. Dieses Feld wird ignoriert, wenn es Einträge in der Liste „Zugelassene Clients“ gibt.", "access_blocked_title": "Nicht zugelassene Domains", - "access_blocked_desc": "Verwechseln Sie dies nicht mit Filtern. AdGuard Home verwirft DNS-Abfragen, die mit diesen Domänen übereinstimmen, und diese Abfragen erscheinen nicht einmal im Abfrageprotokoll. Hier können Sie die genauen Domain-Namen, Wildcards und URL-Filter-Regeln angeben, z.B. 'beispiel.org', '*.beispiel.org' oder '||beispiel.org^'.", + "access_blocked_desc": "Verwechseln Sie dies nicht mit Filtern. AdGuard Home verwirft DNS-Abfragen, die mit diesen Domänen übereinstimmen, und diese Abfragen erscheinen nicht einmal im Abfrageprotokoll. Hier können Sie die genauen Domain-Namen, Wildcards und URL-Filter-Regeln angeben, z.B. „example.org“, „*.example.org“ oder „||example.org^“.", "access_settings_saved": "Zugriffseinstellungen erfolgreich gespeichert", "updates_checked": "Neue Version von AdGuard Home ist jetzt verfügbar", "updates_version_equal": "AdGuard Home ist aktuell", @@ -625,7 +627,7 @@ "setup_config_to_enable_dhcp_server": "Einrichten der Konfiguration zur Aktivierung des DHCP-Servers", "original_response": "Ursprüngliche Antwort", "click_to_view_queries": "Anklicken, um Abfragen anzuzeigen", - "port_53_faq_link": "Port 53 wird oft von Diensten wie „DNSStubListener“ oder „systemresolved“ belegt. Bitte lesen Sie <0>diese Anweisung, wie dies behoben werden kann.", + "port_53_faq_link": "Port 53 wird oft von Diensten wie „DNSStubListener“ oder „system-resolved“ belegt. Bitte lesen Sie <0>diese Anweisung, wie dies behoben werden kann.", "adg_will_drop_dns_queries": "AdGuard Home wird alle DNS-Abfragen von diesem Client verwerfen.", "filter_allowlist": "Warnhinweis: Durch diese Aktion wird außerdem die Regel „{{disallowed_rule}}“ aus der Liste der zugelassenen Clients ausgeschlossen.", "last_rule_in_allowlist": "Dieser Client kann nicht gesperrt werden, da das Ausschließen der Regel „{{disallowed_rule}}“ die Liste „Zugelassene Clients“ deaktivieren würde.", diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index af748038..ca423562 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Also a comment.", "example_regex_meaning": "block access to domains matching the specified regular expression.", "example_upstream_regular": "regular DNS (over UDP);", + "example_upstream_regular_port": "regular DNS (over UDP, with port);", "example_upstream_udp": "regular DNS (over UDP, hostname);", "example_upstream_dot": "encrypted <0>DNS-over-TLS;", "example_upstream_doh": "encrypted <0>DNS-over-HTTPS;", "example_upstream_doq": "encrypted <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS Stamps for <1>DNSCrypt or <2>DNS-over-HTTPS resolvers;", "example_upstream_tcp": "regular DNS (over TCP);", + "example_upstream_tcp_port": "regular DNS (over TCP, with port);", "example_upstream_tcp_hostname": "regular DNS (over TCP, hostname);", "all_lists_up_to_date_toast": "All lists are already up-to-date", "updated_upstream_dns_toast": "Upstream servers successfully saved", diff --git a/client/src/__locales/es.json b/client/src/__locales/es.json index 895d0c33..3ac31670 100644 --- a/client/src/__locales/es.json +++ b/client/src/__locales/es.json @@ -211,12 +211,14 @@ "example_comment_hash": "# También un comentario.", "example_regex_meaning": "bloquea el acceso a los dominios que coincidan con la expresión regular especificada.", "example_upstream_regular": "DNS regular (mediante UDP).", + "example_upstream_regular_port": "DNS regular (mediante UDP, con puerto).", "example_upstream_udp": "DNS regular (mediante UDP, nombre del host).", "example_upstream_dot": "cifrado <0>DNS mediante TLS.", "example_upstream_doh": "cifrado <0>DNS mediante HTTPS.", "example_upstream_doq": "cifrado <0>DNS mediante QUIC.", "example_upstream_sdns": "<0>DNS Stamps para <1>DNSCrypt o resolutores <2>DNS mediante HTTPS.", "example_upstream_tcp": "DNS regular (mediante TCP).", + "example_upstream_tcp_port": "DNS regular (mediante TCP, con puerto).", "example_upstream_tcp_hostname": "DNS regular (mediante TCP, nombre del host).", "all_lists_up_to_date_toast": "Todas las listas ya están actualizadas", "updated_upstream_dns_toast": "Servidores DNS de subida guardados correctamente", diff --git a/client/src/__locales/fa.json b/client/src/__locales/fa.json index aef9e5d3..719ca49f 100644 --- a/client/src/__locales/fa.json +++ b/client/src/__locales/fa.json @@ -1,11 +1,14 @@ { "client_settings": "تنظیمات کلاینت", "example_upstream_reserved": "میتوانید جریان ارسالی DNS <0> را برای یک دامنه مشخص تعیین کنید ", + "example_upstream_comment": "یک نظر.", "upstream_parallel": "استفاده از جستار موازی برای سرعت دادن به تفکیک با جستار همزمان همه جریان های ارسالی", "parallel_requests": "درخواست های موازی", + "load_balancing": "متعادل کننده بار", "bootstrap_dns": "خودراه انداز سرورهای DNS", "bootstrap_dns_desc": "خودراه انداز سرورهای DNS برای تفکیک آدرس آی پی تفکیک کننده های DoH/DoT که شما بعنوان جریان ارسالی تعیین کردید استفاده میشود.", "local_ptr_title": "سرورهای خصوصی DNS", + "local_ptr_desc": "سرور یا سرور های DNS ای که AdGuard Home برای درخواست های منابع محلی ارائه شده مورد استفاده قرار خواهد داد. برای مثال، این سرور برای تعیین نام های سرویس دهنده برای سرویس گیرنده با آدرس های آی پی خصوصی مورد استفاده قرار خواهد گرفت. اگر تعیین نشود،AdGuard Home به طور خودکار از تعیین کننده ی DNS پیش فرض شما استفاده خواهد کرد.", "local_ptr_default_resolver": "به طور پیش فرض، AdGuard Home از تعیین کننده های DNS معکوس زیر استفاده می کند: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home نتوانست برای این دستگاه تعیین کننده های DNS معکوس محرمانه مناسب را معین کند.", "local_ptr_placeholder": "در هر خط یک آدرس سرور را وارد کنید", @@ -207,6 +210,9 @@ "dns_test_not_ok_toast": "سرور \"{{key}}\": نمیتواند مورد استفاده قرار گیرد،لطفا بررسی کنید آن را بدرستی نوشته اید", "unblock": "رفع انسداد", "block": "مسدود کردن", + "disallow_this_client": "این مشتری را رد کنید", + "allow_this_client": "به این مشتری اجازه دهید", + "block_for_this_client_only": "مسدود کردن فقط برای این مشتری", "time_table_header": "زمان", "date": "تاریخ", "domain_name_table_header": "نام دامنه", @@ -320,6 +326,7 @@ "install_devices_android_list_5": "گروه مقادیر DNS 1 و DNS 2 را به آدرس سرور AdGuard Home خود تغییر دهید.", "install_devices_ios_list_1": "از صفحه خانه،تنظیمات را فشار دهید.", "install_devices_ios_list_2": "وای فای را از منوی چپ انتخاب کنید (پیکربندی DNS دستی برای ارتباط موبایلی غیرممکن است).", + "install_devices_ios_list_3": "روی نام شبکه فعال فعلی کلیک کنید.", "install_devices_ios_list_4": "در فیلد DNS آدرس سرور AdGuard Home را وارد کنید", "get_started": "شروع به کار", "next": "بعدی", @@ -552,6 +559,7 @@ "safe_search": "جستجوی اَمن", "blocklist": "لیست سیاه", "milliseconds_abbreviation": "هـ ثـ", + "cache_size": "اندازه کش", "cache_optimistic": "حالت ویژه پردازش", "cache_optimistic_desc": "AdGuard Home را وادار می کند که از سمت حافظه پنهان پاسخ دهد حتی وقتی که موارد وارد شده منقضی شده باشد و همچنین سعی بر تازه کردن آنها می کند.", "filter_category_general": "General", diff --git a/client/src/__locales/fi.json b/client/src/__locales/fi.json index 197f74d3..6772c20d 100644 --- a/client/src/__locales/fi.json +++ b/client/src/__locales/fi.json @@ -210,13 +210,15 @@ "example_comment_meaning": "vain kommentti;", "example_comment_hash": "# Tämäkin on kommentti.", "example_regex_meaning": "estä pääsy määritettyä säännöllistä lauseketta vastaaviin verkkotunnuksiin.", - "example_upstream_regular": "tavallinen DNS (UDP:n välityksellä);", + "example_upstream_regular": "tavallinen DNS (UDP);", + "example_upstream_regular_port": "tavallinen DNS (UDP, portti);", "example_upstream_udp": "tavallinen DNS (UDP, isäntänimi);", "example_upstream_dot": "salattu <0>DNS-over-TLS;", "example_upstream_doh": "salattu <0>DNS-over-HTTPS;", "example_upstream_doq": "salattu <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS Stamp -merkinnät <1>DNSCrypt tai <2>DNS-over-HTTPS -resolvereille;", - "example_upstream_tcp": "tavallinen DNS (TCP:n välityksellä);", + "example_upstream_tcp": "tavallinen DNS (TCP);", + "example_upstream_tcp_port": "tavallinen DNS (TCP, portti);", "example_upstream_tcp_hostname": "tavallinen DNS (TCP, isäntänimi);", "all_lists_up_to_date_toast": "Kaikki listat ovat ajan tasalla", "updated_upstream_dns_toast": "Ylävirtojen palvelimet tallennettiin", diff --git a/client/src/__locales/fr.json b/client/src/__locales/fr.json index fe891203..21742d64 100644 --- a/client/src/__locales/fr.json +++ b/client/src/__locales/fr.json @@ -71,8 +71,8 @@ "dhcp_error": "AdGuard Home ne peut pas déterminer s'il y a un autre serveur DHCP actif sur le réseau.", "dhcp_static_ip_error": "Pour utiliser un serveur DHCP, une adresse IP statique est requise. AdGuard Home n'a pas réussi à déterminer si cette interface réseau est configurée via une adresse IP statique. Veuillez définir une adresse IP statique manuellement.", "dhcp_dynamic_ip_found": "Votre système utilise une configuration d'adresses IP dynamiques pour l'interface <0>{{interfaceName}}. Pour utiliser un serveur DHCP, une adresse IP statique est requise. Votre adresse IP actuelle est <0>{{ipAddress}}. AdGuard Home va automatiquement définir cette adresse IP comme statique si vous appuyez sur le bouton « Activer le serveur DHCP ».", - "dhcp_lease_added": "« {{key}} » de bail statique ajoutée avec succès", - "dhcp_lease_deleted": "« {{key}} » de bail statique supprimée avec succès", + "dhcp_lease_added": "« {{key}} » de bail statique ajoutée", + "dhcp_lease_deleted": "« {{key}} » de bail statique supprimée", "dhcp_new_static_lease": "Nouveau bail statique", "dhcp_static_leases_not_found": "Aucun bail statique DHCP trouvé", "dhcp_add_static_lease": "Ajoutez un bail statique", @@ -206,23 +206,25 @@ "example_meaning_filter_block": "bloque l’accès au domaine example.org et à tous ses sous-domaines ;", "example_meaning_filter_whitelist": "débloque l’accès au domaine example.org et à tous ses sous-domaines ;", "example_meaning_host_block": "AdGuard Home va retourner l'adresse 127.0.0.1 au domaine example.org (mais pas aux sous-domaines) ;", - "example_comment": "! Voici comment ajouter une déscription.", + "example_comment": "! Voici un commentaire.", "example_comment_meaning": "juste un commentaire ;", "example_comment_hash": "# Aussi un commentaire.", "example_regex_meaning": "bloque l’accès aux domaines correspondants à l'expression régulière spécifiée .", "example_upstream_regular": "DNS classique (au-dessus de UDP) ;", + "example_upstream_regular_port": "DNS normal (sur UDP, avec port) ;", "example_upstream_udp": "DNS normal (sur UDP, nom d’hôte) ;", "example_upstream_dot": "<0>DNS-over-TLS chiffré ;", "example_upstream_doh": "<0>DNS-over-HTTPS chiffré ;", "example_upstream_doq": "<0>DNS-over-QUIC chiffré;", "example_upstream_sdns": "vous pouvez utiliser <0>DNS Stamps pour <1>DNSCrypt ou les résolveurs <2>DNS_over_HTTPS ;", "example_upstream_tcp": "DNS classique (au-dessus de TCP) ;", + "example_upstream_tcp_port": "DNS normal (sur TCP, avec port) ;", "example_upstream_tcp_hostname": "DNS normal (sur TCP, nom d’hôte) ;", "all_lists_up_to_date_toast": "Toutes les listes sont déjà à jour", "updated_upstream_dns_toast": "Serveurs en amont enregistrés", "dns_test_ok_toast": "Les serveurs DNS spécifiés fonctionnent correctement", "dns_test_not_ok_toast": "Impossible d'utiliser le serveur « {{key}} »: veuillez vérifier si le nom saisi est bien correct", - "dns_test_warning_toast": "L'amont « {{key}} » ne répond pas aux demandes de test et peut ne pas fonctionner correctement.", + "dns_test_warning_toast": "L'amont «{{key}}» ne répond pas aux demandes de test et peut ne pas fonctionner correctement", "unblock": "Débloquer", "block": "Bloquer", "disallow_this_client": "Interdire ce client", @@ -338,7 +340,7 @@ "install_devices_router_list_4": "Vous ne pouvez pas définir un serveur DNS personnalisé sur certains types de routeurs. Dans ce cas, la configuration de AdGuard Home en tant que <0>serveur DHCP peut aider. Sinon, vous devez rechercher le manuel sur la façon de personnaliser les serveurs DNS pour votre modèle de routeur particulier.", "install_devices_windows_list_1": "Ouvrez votre Panneau de configuration depuis le menu Démarrer ou la recherche Windows.", "install_devices_windows_list_2": "Allez dans la catégorie Réseau et Internet et ensuite dans le Centre Réseau et Partage.", - "install_devices_windows_list_3": "Dans le panneau de gauche, cliquez sur « Modifier les paramètres de l'adaptateur ».", + "install_devices_windows_list_3": "Cliquez « Modifier les paramètres de l'adaptateur » sur le panneau à gauche.", "install_devices_windows_list_4": "Cliquez avec le bouton droit de la souris sur votre connexion active et sélectionnez Propriétés.", "install_devices_windows_list_5": "Recherchez « Protocole Internet Version 4 (TCP/IPv4) » (soit, pour IPv6, « Protocole Internet Version 6 (TCP/IPv6) ») dans la liste, sélectionnez-la puis cliquez à nouveau sur Propriétés.", "install_devices_windows_list_6": "Sélectionnez « Utiliser l’adresse de serveur DNS suivante » et saisissez votre adresse de serveur AdGuard Home.", @@ -430,11 +432,11 @@ "form_client_name": "Saisissez le nom du client", "name": "Nom", "client_global_settings": "Utiliser les paramètres généraux", - "client_deleted": "Le client « {{key}} » a été supprimé avec succès", + "client_deleted": "Le client « {{key}} » a été supprimé", "client_added": "Le client « {{key}} » a été ajouté", "client_updated": "Le client « {{key}} » a été mis à jour", "clients_not_found": "Aucun client trouvé", - "client_confirm_delete": "Voulez-vous vraiment supprimer le client « {{key}} »?", + "client_confirm_delete": "Voulez-vous vraiment supprimer le client « {{key}} » ?", "list_confirm_delete": "Voulez-vous vraiment supprimer cette liste ?", "auto_clients_title": "Clients d'exécution", "auto_clients_desc": "Appareils ne figurant pas sur la liste des clients persistants qui peuvent encore utiliser AdGuard Home.", @@ -472,7 +474,7 @@ "rewrite_deleted": "Réécriture DNS pour « {{key}} » supprimée", "rewrite_add": "Ajouter une réécriture DNS", "rewrite_not_found": "Aucune réécriture DNS trouvée", - "rewrite_confirm_delete": "Voulez-vous vraiment supprimer la réécriture DNS pour « {{key}} »?", + "rewrite_confirm_delete": "Voulez-vous vraiment supprimer la réécriture DNS pour « {{key}} » ?", "rewrite_desc": "Permet de configurer facilement la réponse DNS personnalisée pour un nom de domaine spécifique.", "rewrite_applied": "Règle de réécriture appliquée", "rewrite_hosts_applied": "Réécrit par la règle du fichier d’hôtes", @@ -553,11 +555,11 @@ "disable_ipv6_desc": "Abandonner toutes les requêtes DNS pour les adresses IPv6 (type AAAA).", "fastest_addr": "Adresse IP la plus rapide", "fastest_addr_desc": "Rechercher tous les serveurs DNS et renvoyer l’adresse IP la plus rapide parmi toutes les réponses. Cela ralentit les requêtes DNS car AdGuard Home doit attendre les réponses de tous les serveurs DNS, mais la connectivité globale s'améliore.", - "autofix_warning_text": "Si vous cliquez sur « Réparer », AdGuardHome configurera votre système pour utiliser le serveur DNS AdGuardHome.", + "autofix_warning_text": "Si vous cliquez sur « Réparer », AdGuard Home configurera votre système pour utiliser le serveur DNS AdGuard Home.", "autofix_warning_list": "Ceci effectuera les tâches suivantes : <0>Désactiver le système DNSStubListener <0>Définir l’adresse du serveur DNS à 127.0.0.1 <0>Remplacer la cible du lien symbolique de /etc/resolv.conf par /run/systemd/resolve/resolv.conf <0>Arrêter DNSStubListener (recharger le service résolu par systemd)", "autofix_warning_result": "Par conséquent, toutes les demandes DNS de votre système seront traitées par AdGuardHome par défaut.", "tags_title": "Mots clés", - "tags_desc": "Vous pouvez sélectionner les mots clés qui correspondent au client. Les mots clés peuvent être inclus dans les règles de filtrage et vous permettent de les appliquer plus précisément. <0>En savoir plus .", + "tags_desc": "Vous pouvez sélectionner les mots clés qui correspondent au client. Les mots clés peuvent être inclus dans les règles de filtrage et vous permettent de les appliquer plus précisément. <0>En savoir plus.", "form_select_tags": "Sélectionner les mots clés du client", "check_title": "Vérification du filtrage", "check_desc": "Vérifier si le nom d’hôte est filtré .", @@ -573,10 +575,10 @@ "check_service": "Nom du service : {{service}}", "service_name": "Nom du service", "check_not_found": "Introuvable dans vos listes de filtres", - "client_confirm_block": "Voulez-vous vraiment bloquer le client « {{ip}} »?", - "client_confirm_unblock": "Voulez-vous vraiment débloquer le client « {{ip}} »?", - "client_blocked": "Client « {{ip}} » bloqué avec succès", - "client_unblocked": "Client « {{ip}} » débloqué avec succès", + "client_confirm_block": "Voulez-vous vraiment bloquer le client « {{ip}} » ?", + "client_confirm_unblock": "Voulez-vous vraiment débloquer le client « {{ip}} » ?", + "client_blocked": "Client « {{ip}} » bloqué", + "client_unblocked": "Client « {{ip}} » débloqué", "static_ip": "Adresse IP statique", "static_ip_desc": "AdGuard Home est un serveur, il a donc besoin d’une adresse IP statique pour fonctionner correctement. Autrement, à un moment donné, votre routeur pourrait attribuer une adresse IP différente à cet appareil.", "set_static_ip": "Définir une adresse IP statique", diff --git a/client/src/__locales/hr.json b/client/src/__locales/hr.json index 7b9d5453..e4c44dff 100644 --- a/client/src/__locales/hr.json +++ b/client/src/__locales/hr.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Također komentar.", "example_regex_meaning": "blokira pristup domenama koje se podudaraju s regularnim izrazom.", "example_upstream_regular": "zadani DNS (putem UDP);", + "example_upstream_regular_port": "obični DNS (preko UDP-a, s portom);", "example_upstream_udp": "obični DNS (preko UDP-a, ime hosta);", "example_upstream_dot": "šifrirano <0>DNS-over-TLS;", "example_upstream_doh": "šifrirano <0>DNS-over-HTTPS;", "example_upstream_doq": "šifrirano <0>DNS-over-QUIC (eksperimentalno);", "example_upstream_sdns": "<0>DNS Stamps za <1>DNSCrypt ili <2>DNS-over-HTTPS rezolvere;", "example_upstream_tcp": "zadani DNS (putem TCP);", + "example_upstream_tcp_port": "obični DNS (preko TCP-a, s portom);", "example_upstream_tcp_hostname": "obični DNS (preko TCP-a, ime hosta);", "all_lists_up_to_date_toast": "Svi popisi su ažurirani", "updated_upstream_dns_toast": "Uzvodni poslužitelji uspješno su spremljeni", diff --git a/client/src/__locales/hu.json b/client/src/__locales/hu.json index ffdbf7ce..ed414ddd 100644 --- a/client/src/__locales/hu.json +++ b/client/src/__locales/hu.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Ez is egy megjegyzés.", "example_regex_meaning": "blokkolja a hozzáférést azokhoz a domainekhez, amik illeszkednek a megadott reguláris kifejezésre.", "example_upstream_regular": "hagyományos DNS (UDP felett);", + "example_upstream_regular_port": "normál DNS (UDP-n keresztül, porttal);", "example_upstream_udp": "normál DNS (UDP felett, hostnév);", "example_upstream_dot": "titkosított <0>DNS-over-TLS;", "example_upstream_doh": "titkosított <0>DNS-over-HTTPS;", "example_upstream_doq": "titkosított <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS Stamps a <1>DNSCrypt vagy <2>DNS-over-HTTPS feloldókhoz;", "example_upstream_tcp": "hagyományos DNS (TCP felett);", + "example_upstream_tcp_port": "normál DNS (TCP-n keresztül, porttal);", "example_upstream_tcp_hostname": "normál DNS (TCP felett, hostnév);", "all_lists_up_to_date_toast": "Már minden lista naprakész", "updated_upstream_dns_toast": "Upstream szerverek sikeresen mentve", diff --git a/client/src/__locales/id.json b/client/src/__locales/id.json index 0b055f31..5246344d 100644 --- a/client/src/__locales/id.json +++ b/client/src/__locales/id.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Juga sebuah komentar.", "example_regex_meaning": "blokir akses ke domain yang cocok dengan ekspresi reguler yang ditentukan.", "example_upstream_regular": "DNS reguler (melalui UDP);", + "example_upstream_regular_port": "DNS biasa (lebih dari UDP, dengan port);", "example_upstream_udp": "DNS biasa (lebih dari UDP, nama host);", "example_upstream_dot": "terenkripsi <0>DNS-over-TLS;", "example_upstream_doh": "terenkripsi <0>DNS-over-HTTPS;", "example_upstream_doq": "terenkripsi <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>Stempel DNS untuk <1>DNSCrypt atau pengarah <2>DNS-over-HTTPS;", "example_upstream_tcp": "DNS reguler (melalui TCP);", + "example_upstream_tcp_port": "DNS biasa (melalui TCP, dengan port);", "example_upstream_tcp_hostname": "DNS biasa (lebih dari TCP, nama host);", "all_lists_up_to_date_toast": "Semua daftar sudah diperbarui", "updated_upstream_dns_toast": "Server upstream berhasil disimpan", diff --git a/client/src/__locales/it.json b/client/src/__locales/it.json index 9a4ed74b..70722dcd 100644 --- a/client/src/__locales/it.json +++ b/client/src/__locales/it.json @@ -23,7 +23,7 @@ "disabled_dhcp": "Server DHCP disattivato", "unavailable_dhcp": "DHCP non disponibile", "unavailable_dhcp_desc": "AdGuard Home non può eseguire un server DHCP sul tuo sistema operativo", - "dhcp_title": "Server DHCP", + "dhcp_title": "Server DHCP (sperimentale!)", "dhcp_description": "Se il tuo router non supporta la configurazione delle impostazioni del DHCP puoi utilizzare il server DHCP incluso in AdGuard.", "dhcp_enable": "Attiva server DHCP", "dhcp_disable": "Disattiva server DHCP", @@ -211,12 +211,14 @@ "example_comment_hash": "# Anche un commento.", "example_regex_meaning": "blocca l'accesso ai domini corrispondenti alla specifica espressione regolare.", "example_upstream_regular": "DNS regolare (over UDP);", + "example_upstream_regular_port": "DNS regolare (su UDP, con porta);", "example_upstream_udp": "DNS regolare (over UDP, nome host);", "example_upstream_dot": "<0>DNS su TLS crittografato;", "example_upstream_doh": "<0>DNS su HTTPS crittografato;", "example_upstream_doq": "<0>DNS su QUIC crittografato;", "example_upstream_sdns": "<0>DNS Stamps per <1>DNSCrypt oppure i risolutori <2>DNS su HTTPS;", "example_upstream_tcp": "DNS regolare (over TCP);", + "example_upstream_tcp_port": "DNS regolare (su TCP, con porta);", "example_upstream_tcp_hostname": "DNS regolare (over TCP, nome host);", "all_lists_up_to_date_toast": "Tutti gli elenchi sono aggiornati", "updated_upstream_dns_toast": "I server upstream sono stati salvati correttamente", @@ -327,7 +329,7 @@ "install_step": "Passo", "install_devices_title": "Configura i tuoi dispositivi", "install_devices_desc": "Affinché AdGuard Home inizi a funzionare, è necessario configurare i dispositivi per utilizzarlo.", - "install_submit_title": "Congratulazioni!", + "install_submit_title": "Felicitazioni!", "install_submit_desc": "La procedura di configurazione è completa e ora sei pronto per iniziare ad utilizzare AdGuard Home.", "install_devices_router": "Router", "install_devices_router_desc": "Questa configurazione copre automaticamente tutti i dispositivi collegati al router di casa, non è necessario configurarli manualmente.", @@ -341,7 +343,7 @@ "install_devices_windows_list_3": "Sul lato sinistro dello schermo, clicca su \"Cambia impostazioni adattatore\".", "install_devices_windows_list_4": "Fai clic destro sulla tua connessione attiva e seleziona Proprietà.", "install_devices_windows_list_5": "Trova \"Protocollo Internet versione 4 (TCP/IPv4)\" (o, per IPv6, \"Protocollo Internet versione 6 (TCP/IPv6)\" nell'elenco, selezionalo e quindi clicca nuovamente su Proprietà.", - "install_devices_windows_list_6": "Scegli \"Utilizza i seguenti indirizzi server DNS\" ed inserisci i tuoi indirizzi server AdGuard Home.", + "install_devices_windows_list_6": "Scegli \"Utilizza i seguenti indirizzi server DNS\" e inserisci i tuoi indirizzi server AdGuard Home.", "install_devices_macos_list_1": "Fai clic sull'icona Apple e dirigiti sulle Preferenze di Sistema.", "install_devices_macos_list_2": "Clicca su Rete.", "install_devices_macos_list_3": "Seleziona la prima connessione nel tuo elenco e clicca su Avanzate.", diff --git a/client/src/__locales/ja.json b/client/src/__locales/ja.json index fed72b6d..2942a504 100644 --- a/client/src/__locales/ja.json +++ b/client/src/__locales/ja.json @@ -23,7 +23,7 @@ "disabled_dhcp": "DHCPサーバを無効にしました", "unavailable_dhcp": "DHCPは利用できません", "unavailable_dhcp_desc": "AdGuard Homeはお使いのOS上でDHCPサーバを実行できません。", - "dhcp_title": "DHCPサーバ(実験的!)", + "dhcp_title": "DHCPサーバ(※実験的)", "dhcp_description": "あなたのルータがDHCPの設定を提供していないのなら、AdGuardに内蔵されているDHCPサーバを利用できます。", "dhcp_enable": "DHCPサーバを有効にする", "dhcp_disable": "DHCPサーバを無効にする", @@ -71,8 +71,8 @@ "dhcp_error": "ネットワーク上に別の稼働中DHCPサーバがあるかどうか、AdGuard Homeは判断できませんでした", "dhcp_static_ip_error": "DHCPサーバーを使用するには、静的IPアドレスを設定する必要があります。このネットワークインターフェースが静的IPアドレスを使用するように設定されているかどうかを、AdGuard Homeは判断できませんでした。手動で静的IPアドレスを設定してください。", "dhcp_dynamic_ip_found": "お使いのシステムは、インターフェース<0>{{interfaceName}}用に動的IPアドレス構成を使用しています。DHCPサーバを使用するには、静的IPアドレスで設定する必要があります。あなたの現在のIPアドレスは<0>{{ipAddress}}です。「DHCPサーバを有効にする」ボタンを押すと、AdGuard Homeは自動的にこのIPアドレスを静的IPアドレスとして設定します。", - "dhcp_lease_added": "静的割り当て \"{{key}}\" の追加に成功しました", - "dhcp_lease_deleted": "静的割り当て \"{{key}}\" の削除に成功しました", + "dhcp_lease_added": "静的リース \"{{key}}\" の追加が完了しました。", + "dhcp_lease_deleted": "静的リース \"{{key}}\" の削除が完了しました。", "dhcp_new_static_lease": "新規静的割り当て", "dhcp_static_leases_not_found": "DHCP静的割り当てはありません", "dhcp_add_static_lease": "静的割り当てを追加する", @@ -211,12 +211,14 @@ "example_comment_hash": "# これもコメントです", "example_regex_meaning": "指定の正規表現に一致するドメインへのアクセスをブロックします。", "example_upstream_regular": "通常のDNS(over UDP)。", + "example_upstream_regular_port": "レギュラーDNS(over UDP、ポート付き)", "example_upstream_udp": "通常のDNS(over UDP, ホスト名)。", "example_upstream_dot": "暗号化されている <0>DNS-over-TLS。", "example_upstream_doh": "暗号化されている <0>DNS-over-HTTPS。", "example_upstream_doq": "暗号化 <0>DNS-over-QUIC。", "example_upstream_sdns": "<1>DNSCrypt または <2>DNS-over-HTTPS リゾルバのための <0>DNS Stamps。", "example_upstream_tcp": "通常のDNS(over TCP)。", + "example_upstream_tcp_port": "レギュラーDNS(over TCP、ポート付き);", "example_upstream_tcp_hostname": "通常のDNS(over TCP, ホスト名)。", "all_lists_up_to_date_toast": "すべてのリストは既に最新です", "updated_upstream_dns_toast": "上流DNSサーバを保存しました。", @@ -468,11 +470,11 @@ "setup_dns_privacy_other_5": "もっと多くの実装を<0>ここや<1>ここで見つけられます。", "setup_dns_privacy_ioc_mac": "iOS と macOS での設定", "setup_dns_notice": "<1>DNS-over-HTTPSまたは<1>DNS-over-TLSを使用するには、AdGuard Home 設定の<0>暗号化設定が必要です。", - "rewrite_added": "\"{{key}}\" のためのDNS書き換え情報を追加完了しました", - "rewrite_deleted": "\"{{key}}\" のためのDNS書き換え情報を削除完了しました", + "rewrite_added": "\"{{key}}\" のDNS書き換え情報を追加完了しました", + "rewrite_deleted": "\"{{key}}\" のDNS書き換え情報を削除完了しました", "rewrite_add": "DNS書き換え情報を追加する", "rewrite_not_found": "DNS書き換え情報はありません", - "rewrite_confirm_delete": "\"{{key}}\" のためのDNS書き換え情報を削除してもよろしいですか?", + "rewrite_confirm_delete": "\"{{key}}\" のDNS書き換え情報を削除してもよろしいですか?", "rewrite_desc": "特定のドメイン名に対するDNS応答を簡単にカスタマイズすることを可能にします。", "rewrite_applied": "書き換えルールを適用済み", "rewrite_hosts_applied": "hostsファイルのルールによって書き換え済み", @@ -553,7 +555,7 @@ "disable_ipv6_desc": "IPv6アドレス(タイプAAAA)に対するすべてのDNSクエリをドロップします。", "fastest_addr": "最速のIPアドレス", "fastest_addr_desc": "すべてのDNSサーバーに処理要求し、全応答の中で最速のIPアドレスを返します。これにより、AdGuard HomeがすべてのDNSサーバーからの応答を待つ必要があるため、DNSクエリが遅くなりますが、全体的な接続性は向上します。", - "autofix_warning_text": "\"改善\"をクリックすると、AdGuardHomeはAdGuardHome DNSサーバを使用するようにシステムを構成します。", + "autofix_warning_text": "「修正」をクリックすると、AdGuardHomeはAdGuardHome DNSサーバを使用するようにシステムを構成します。", "autofix_warning_list": "次のタスクを実行します:<0>システムDNSStubListenerを非アクティブ化します <0>DNSサーバのアドレスを127.0.0.1に設定します <0>/etc/resolv.confのシンボリックリンクの対象を/run/systemd/resolve/resolv.confに置換します <0>DNSStubListenerを停止します(systemd-resolvedサービスをリロードします)", "autofix_warning_result": "その結果、システムからのすべてのDNSリクエストは、デフォルトでAdGuard Homeによって処理されます。", "tags_title": "タグ", @@ -576,7 +578,7 @@ "client_confirm_block": "クライアント\"{{ip}}\"をブロックしてもよろしいですか?", "client_confirm_unblock": "クライアント\"{{ip}}\"のブロックを解除してもよろしいですか?", "client_blocked": "クライアント\"{{ip}}\"のブロックに成功しました", - "client_unblocked": "クライアント\"{{ip}}\"のブロックの解除に成功しました", + "client_unblocked": "クライアント\"{{ip}}\"のブロック解除に成功しました", "static_ip": "静的IPアドレス", "static_ip_desc": "AdGuard Homeはサーバであり、正しく機能させるには静的IPアドレスが必要です。そうしないと、ある時点で、ルータがこのデバイスに異なるIPアドレスを割り当てるかもしれません。", "set_static_ip": "静的IPアドレスを設定する", diff --git a/client/src/__locales/ko.json b/client/src/__locales/ko.json index 62080721..5afd8c61 100644 --- a/client/src/__locales/ko.json +++ b/client/src/__locales/ko.json @@ -45,10 +45,10 @@ "form_error_mac_format": "잘못된 MAC 주소", "form_error_client_id_format": "ClientID는 숫자, 소문자 및 붙임표(-)만 포함해야 합니다", "form_error_server_name": "유효하지 않은 서버 이름", - "form_error_subnet": "서브넷 \"{{cidr}}\"에 \"{{ip}}\" IP 주소가 없습니다", + "form_error_subnet": "서브넷 '{{cidr}}'에 '{{ip}}' IP 주소가 없습니다", "form_error_positive": "0보다 커야 합니다", "form_error_gateway_ip": "임대는 게이트웨이의 IP 주소를 가질 수 없습니다", - "out_of_range_error": "\"{{start}}\"-\"{{end}}\" 범위 밖이어야 합니다", + "out_of_range_error": "'{{start}}'-'{{end}}' 범위 밖이어야 합니다", "lower_range_start_error": "범위 시작보다 작은 값이어야 합니다", "greater_range_start_error": "범위 시작보다 큰 값이어야 합니다", "greater_range_end_error": "범위 종료보다 큰 값이어야 합니다", @@ -71,8 +71,8 @@ "dhcp_error": "AdGuard Home이 네트워크에 다른 활성 DHCP 서버가 있는지 확인할 수 없습니다", "dhcp_static_ip_error": "DHCP 서버를 사용하려면 고정 IP 주소를 설정해야 합니다. AdGuard Home이 이 네트워크 인터페이스가 고정 IP 주소를 사용하는지 확인할 수 없습니다. 고정 IP 주소를 수동으로 설정하십시오.", "dhcp_dynamic_ip_found": "시스템은 <0>{{interfaceName}} 인터페이스에 동적 IP 주소를 사용합니다. DHCP 서버를 사용하려면 고정 IP 주소를 설정해야 합니다. 현재 IP 주소는 <0>{{ipAddress}}입니다. 'DHCP 서버 활성화' 버튼을 누르면 AdGuard Home이 이 IP 주소를 고정 IP 주소로 자동 설정합니다.", - "dhcp_lease_added": "\"{{key}}\" 고정 임대 정상적으로 추가되었습니다", - "dhcp_lease_deleted": "\"{{key}}\" 고정 임대 정상적으로 삭제되었습니다", + "dhcp_lease_added": "'{{key}}' 고정 임대 정상적으로 추가되었습니다", + "dhcp_lease_deleted": "'{{key}}' 고정 임대 정상적으로 삭제되었습니다", "dhcp_new_static_lease": "새 고정 임대", "dhcp_static_leases_not_found": "DHCP 고정 임대를 찾을 수 없음", "dhcp_add_static_lease": "고정 임대 추가", @@ -82,7 +82,7 @@ "dhcp_reset": "정말로 DHCP 설정을 초기화할까요?", "country": "지역", "city": "도시", - "delete_confirm": "\"{{key}}\"을 삭제하시겠습니까?", + "delete_confirm": "'{{key}}'을(를) 삭제하시겠습니까?", "form_enter_hostname": "호스트 이름을 입력해주세요", "error_details": "오류 상세 정보", "response_details": "응답 정보", @@ -211,17 +211,19 @@ "example_comment_hash": "# 이것 또한 댓글입니다.", "example_regex_meaning": "특정 정규 표현식에 맞는 도메인 접근을 차단합니다.", "example_upstream_regular": "일반 DNS (UDP을 통한 접속);", + "example_upstream_regular_port": "일반 DNS (UDP 이용, 포트 포함);", "example_upstream_udp": "일반 DNS (UDP를 통한, 호스트명);", "example_upstream_dot": "암호화된 <0>DNS-over-TLS;", "example_upstream_doh": "암호화된 <0>DNS-over-HTTPS;", "example_upstream_doq": "암호화된 <0>DNS-over-QUIC;", "example_upstream_sdns": "<1>DNSCrypt 또는 <2>DNS-over-HTTPS 리졸버를 위한 <0>DNS 스탬프;", "example_upstream_tcp": "일반 DNS (TCP를 통한 접속);", + "example_upstream_tcp_port": "일반 DNS (TCP 이용, 포트 포함);", "example_upstream_tcp_hostname": "일반 DNS (TCP를 통한, 호스트명);", "all_lists_up_to_date_toast": "모든 리스트가 이미 최신입니다", "updated_upstream_dns_toast": "업스트림 서버가 성공적으로 저장되었습니다", "dns_test_ok_toast": "특정 DNS 서버들은 정상적으로 동작 중입니다", - "dns_test_not_ok_toast": "서버 \"{{key}}\": 사용할 수 없습니다, 제대로 작성했는지 확인하세요.", + "dns_test_not_ok_toast": "서버 '{{key}}': 사용할 수 없습니다, 제대로 작성했는지 확인하세요", "dns_test_warning_toast": "업스트림 '{{key}}'이(가) 테스트 요청에 응답하지 않으며 제대로 작동하지 않을 수 있습니다", "unblock": "차단 해제", "block": "차단", @@ -423,18 +425,18 @@ "ip_address": "IP 주소", "client_identifier_desc": "클라이언트는 IP 주소, CIDR, MAC 주소 또는 ClientID(DoT/DoH/DoQ에 사용 가능)로 식별할 수 있습니다. <0>여기에서 클라이언트를 식별하는 방법에 대한 자세한 내용은 확인하실 수 있습니다.", "form_enter_ip": "IP 입력", - "form_enter_subnet_ip": "서브넷 \"{{cidr}}\" 내의 IP 주소 입력", + "form_enter_subnet_ip": "서브넷 '{{cidr}}' 내의 IP 주소 입력", "form_enter_mac": "MAC 입력", "form_enter_id": "식별자 입력", "form_add_id": "식별자 추가", "form_client_name": "클라이언트 이름 입력", "name": "이름", "client_global_settings": "글로벌 설정 사용", - "client_deleted": "클라이언트 \"{{key}}\"가 정상적으로 삭제되었습니다", - "client_added": "클라이언트 \"{{key}}\"가 정상적으로 추가되었습니다", - "client_updated": "클라이언트 \"{{key}}\"가 정상적으로 업데이트되었습니다", + "client_deleted": "클라이언트 '{{key}}'이(가) 정상적으로 삭제되었습니다", + "client_added": "클라이언트 '{{key}}'이(가) 정상적으로 추가되었습니다", + "client_updated": "클라이언트 '{{key}}'이(가) 정상적으로 업데이트되었습니다", "clients_not_found": "클라이언트 없음", - "client_confirm_delete": "정말 클라이언트 \"{{key}}\" 삭제하시겠습니까?", + "client_confirm_delete": "정말 클라이언트 '{{key}}'을(를) 삭제하시겠습니까?", "list_confirm_delete": "정말로 이 목록을 제거하시겠습니까?", "auto_clients_title": "런타임 클라이언트", "auto_clients_desc": "AdGuard Home을 계속 사용할 수 있는 영구 클라이언트 목록에 없는 디바이스입니다", @@ -468,11 +470,11 @@ "setup_dns_privacy_other_5": "<0>이곳이나 <1>이곳을 클릭하여 더 많은 구현에 대한 정보를 확인하세요.", "setup_dns_privacy_ioc_mac": "iOS 및 macOS 설정", "setup_dns_notice": "<1>DNS-over-HTTPS 또는 <1>DNS-over-TLS를 사용하려면 AdGuard Home 설정에서 <0>암호화를 구성해야 합니다.", - "rewrite_added": "\"{{key}}\"에 대한 DNS 수정 정보를 성공적으로 추가 됩니다.", - "rewrite_deleted": "\"{{key}}\"에 대한 DNS 수정 정보를 성공적으로 삭제 됩니다.", + "rewrite_added": "'{{key}}'에 대한 DNS 수정 정보를 성공적으로 추가 됩니다", + "rewrite_deleted": "'{{key}}'에 대한 DNS 수정 정보를 성공적으로 삭제 됩니다", "rewrite_add": "DNS 변환 정보를 추가합니다", "rewrite_not_found": "DNS 변경 정보를 찾을 수 없습니다", - "rewrite_confirm_delete": "\"{{key}}\"에 대한 DNS 변경 정보를 삭제하시겠습니까?", + "rewrite_confirm_delete": "'{{key}}'에 대한 DNS 변경 정보를 삭제하시겠습니까?", "rewrite_desc": "특정 도메인 이름에 대한 사용자 지정 DNS 응답을 쉽게 구성할 수 있습니다.", "rewrite_applied": "리디렉션 규칙이 적용됩니다", "rewrite_hosts_applied": "호스트 파일 규칙에 따라 재작성", @@ -553,7 +555,7 @@ "disable_ipv6_desc": "IPv6 주소(타입 AAAA)의 모든 DNS 쿼리가 무시됩니다.", "fastest_addr": "가장 빠른 IP 주소", "fastest_addr_desc": "모든 DNS 서버에 쿼리를 수행한 다음 반응이 가장 빠른 IP주소를 반송합니다. AdGuard Home이 모든 DNS 서버의 응답을 기다려야 하기 때문에 DNS 쿼리 속도가 느려지지만 전반적인 연결이 향상됩니다.", - "autofix_warning_text": "\"Fix\"를 클릭한다면 AdGuard Home은 시스템이 AdGuard Home의 DNS 서버를 사용하도록 설정합니다.", + "autofix_warning_text": "'수정'을 클릭하면 AdGuard Home이 AdGuard Home DNS 서버를 사용하도록 시스템을 설정합니다.", "autofix_warning_list": "다음 작업을 진행합니다: <0>DNSStubListener 시스템 비활성화 <0>DNS 서버 주소를 127.0.0.1로 설정 <0>/etc/resolv.conf의 심볼릭 링크 타겟을 /run/systemd/resolve/resolv.conf로 변경 <0>DNSStubListener 중지 (systemd-resolved 서비스 새로고침)", "autofix_warning_result": "결과적으로 시스템의 모든 DNS 요청은 기본적으로 AdGuard Home에 의해 처리됩니다.", "tags_title": "태그", @@ -573,10 +575,10 @@ "check_service": "서비스 이름: {{service}}", "service_name": "서비스 이름", "check_not_found": "필터 목록에서 찾을 수 없음", - "client_confirm_block": "정말로 클라이언트 \"{{ip}}\"을(를) 차단하시겠습니까?", - "client_confirm_unblock": "정말로 클라이언트 \"{{ip}}\"의 차단을 해제하시겠습니까?", - "client_blocked": "클라이언트 \"{{ip}}\"(이)가 성공적으로 차단되었습니다", - "client_unblocked": "클라이언트 \"{{ip}}\"의 차단을 성공적으로 해제했습니다", + "client_confirm_block": "정말로 클라이언트 '{{ip}}'을(를) 차단하시겠습니까?", + "client_confirm_unblock": "정말로 클라이언트 '{{ip}}'의 차단을 해제하시겠습니까?", + "client_blocked": "클라이언트 '{{ip}}'(이)가 성공적으로 차단되었습니다", + "client_unblocked": "클라이언트 '{{ip}}'의 차단을 성공적으로 해제했습니다", "static_ip": "고정 IP 주소", "static_ip_desc": "AdGuard Home는 서버라서 정상적으로 작동하려면 고정 IP 주소가 필요합니다. 그렇지 않다면 라우터가 언젠가 이 기기에 다른 IP 주소를 할당할 수도 있습니다.", "set_static_ip": "고정 IP 주소 설정", @@ -625,7 +627,7 @@ "setup_config_to_enable_dhcp_server": "DHCP 서버를 활성화하기 위한 설정 구성", "original_response": "원래 응답", "click_to_view_queries": "쿼리를 보려면 클릭합니다", - "port_53_faq_link": "53번 포트는 보통 \"DNSStubListener\"나 \"systemd-resolved\" 서비스가 이미 사용하고 있습니다. 이 문제에 대한 해결 방법을 <0>설명에서 찾아보세요.", + "port_53_faq_link": "53번 포트는 보통 'DNSStubListener나 'systemd-resolved' 서비스가 이미 사용하고 있습니다. 이 문제에 대한 해결 방법을 <0>설명에서 찾아보세요.", "adg_will_drop_dns_queries": "AdGuard Home은 이 클라이언트에서 모든 DNS 쿼리를 삭제합니다.", "filter_allowlist": "경고: 이 경우 허용된 클라이언트 목록에서 '{{disallowed_rule}}' 규칙 또한 제외됩니다.", "last_rule_in_allowlist": "'{{disallowed_rule}}' 규칙을 제외하면 '허용된 클라이언트' 목록이 꺼지므로 해당 클라이언트를 제외할 수 없습니다.", diff --git a/client/src/__locales/nl.json b/client/src/__locales/nl.json index 408dc561..06602c96 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -150,9 +150,9 @@ "general_settings": "Algemene instellingen", "dns_settings": "DNS instellingen", "dns_blocklists": "DNS blokkeerlijsten", - "dns_allowlists": "DNS toestemmingslijsten", + "dns_allowlists": "DNS-toelatingslijsten", "dns_blocklists_desc": "AdGuard Home zal domeinen blokkeren die voorkomen in de blokkeerlijsten.", - "dns_allowlists_desc": "Domeinen in de DNS toestemmingslijsten worden toegestaan zelfs al komen ze voor in de blokkeerlijsten.", + "dns_allowlists_desc": "Domeinen van DNS-toelatingslijsten zijn toegestaan, zelfs als ze op een van de blokkeerlijsten staan.", "custom_filtering_rules": "Aangepaste filter regels", "encryption_settings": "Encryptie instellingen", "dhcp_settings": "DHCP instellingen", @@ -182,21 +182,21 @@ "elapsed": "Verstreken", "filters_and_hosts_hint": "AdGuard Home kan overweg met basic adblock regels en hosts bestanden syntaxis.", "no_blocklist_added": "Geen blokkeerlijsten toegevoegd", - "no_whitelist_added": "Geen toestemmingslijsten toegevoegd", + "no_whitelist_added": "Geen toelatingslijsten toegevoegd", "add_blocklist": "Blokkeerlijst toevoegen", - "add_allowlist": "Toestemmingslijst toevoegen", + "add_allowlist": "Toelatingslijst toevoegen", "cancel_btn": "Annuleren", "enter_name_hint": "Voeg naam toe", "enter_url_or_path_hint": "Voer een URL in of het pad van de lijst", "check_updates_btn": "Controleer op updates", "new_blocklist": "Nieuwe blokkeerlijst", - "new_allowlist": "Nieuwe toestemmingslijst", + "new_allowlist": "Nieuwe toelatingslijst", "edit_blocklist": "Blokkeerlijst beheren", - "edit_allowlist": "Toestemmingslijst beheren", + "edit_allowlist": "Toelatingslijst bewerken", "choose_blocklist": "Blokkeringslijsten selecteren", - "choose_allowlist": "Toestemmingslijsten selecteren", + "choose_allowlist": "Toelatingslijsten selecteren", "enter_valid_blocklist": "Voer een geldige URL in voor de blokkeerlijst.", - "enter_valid_allowlist": "Voer een geldige URL in voor de toestemmingslijst.", + "enter_valid_allowlist": "Voer een geldige URL naar de toelatingslijst in.", "form_error_url_format": "Ongeldig URL-opmaak", "form_error_url_or_path_format": "Ongeldig URL of pad van de lijst", "custom_filter_rules": "Aangepaste filterregels", @@ -211,12 +211,14 @@ "example_comment_hash": "# Ook een opmerking.", "example_regex_meaning": "toegang blokkeren tot de domeinen die overeenkomen met de opgegeven reguliere expressie.", "example_upstream_regular": "standaard DNS (over UDP);", + "example_upstream_regular_port": "standaard DNS (via UDP, met poort);", "example_upstream_udp": "standaard DNS (via UDP, hostnaam);", "example_upstream_dot": "versleutelde <0>DNS-via-TLS;", "example_upstream_doh": "versleutelde <0>DNS-via-HTTPS;", "example_upstream_doq": "versleutelde <0>DNS-via-QUIC;", "example_upstream_sdns": "<0>DNS Stamps voor <1>DNSCrypt of <2>DNS-via-HTTPS oplossingen;", "example_upstream_tcp": "standaard DNS (over TCP);", + "example_upstream_tcp_port": "standaard DNS (via TCP, met poort);", "example_upstream_tcp_hostname": "standaard DNS (via TCP, hostnaam);", "all_lists_up_to_date_toast": "Alle lijsten zijn reeds actueel", "updated_upstream_dns_toast": "Upstream-servers succesvol opgeslagen", @@ -566,7 +568,7 @@ "filtered_custom_rules": "Gefilterd door aangepaste filterregels", "choose_from_list": "Uit de lijst selecteren", "add_custom_list": "Aangepaste lijst toevoegen", - "host_whitelisted": "De host staat op de toestemmingslijst", + "host_whitelisted": "De host staat op de toelatingslijst", "check_ip": "IP-adressen: {{ip}}", "check_cname": "CNAME: {{cname}}", "check_reason": "Reden: {{reason}}", @@ -591,7 +593,7 @@ "validated_with_dnssec": "Gevalideerd met DNSSEC", "all_queries": "Alle vragen", "show_blocked_responses": "Geblokkeerd", - "show_whitelisted_responses": "Op toestemmingslijst", + "show_whitelisted_responses": "Op toelatingslijst", "show_processed_responses": "Verwerkt", "blocked_safebrowsing": "Geblokkeerd door Veilig browsen", "blocked_adult_websites": "Geblokkeerd door ouderlijk toezicht", diff --git a/client/src/__locales/pl.json b/client/src/__locales/pl.json index 65be442a..06fb0bd0 100644 --- a/client/src/__locales/pl.json +++ b/client/src/__locales/pl.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Również komentarz.", "example_regex_meaning": "zablokuj dostęp do domen pasujących do określonego wyrażenia regularnego.", "example_upstream_regular": "normalny DNS (przez UDP);", + "example_upstream_regular_port": "zwykły DNS (przez UDP, z portem);", "example_upstream_udp": "zwykły DNS (przez UDP, nazwa hosta);", "example_upstream_dot": "zaszyfrowany <0>DNS-over-TLS;", "example_upstream_doh": "zaszyfrowany <0>DNS-over-HTTPS;", "example_upstream_doq": "zaszyfrowany <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>Stempel DNS dla resolwerów <1>DNSCrypt lub <2>DNS-over-HTTPS;", "example_upstream_tcp": "zwykły DNS (przez TCP);", + "example_upstream_tcp_port": "zwykły DNS (przez TCP, z portem);", "example_upstream_tcp_hostname": "zwykły DNS (przez TCP, nazwa hosta);", "all_lists_up_to_date_toast": "Wszystkie listy są już aktualne", "updated_upstream_dns_toast": "Serwery nadrzędne zostały pomyślnie zapisane", diff --git a/client/src/__locales/pt-br.json b/client/src/__locales/pt-br.json index dce24636..123ad2c0 100644 --- a/client/src/__locales/pt-br.json +++ b/client/src/__locales/pt-br.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Também um comentário.", "example_regex_meaning": "bloqueia o acesso aos domínios que correspondem à expressão regular especificada.", "example_upstream_regular": "dNS regular (através do UDP);", + "example_upstream_regular_port": "DNS normal (através do UDP, com porta);", "example_upstream_udp": "DNS normal (através do UDP, nome do servidor);", "example_upstream_dot": "<0>DNS-sobre-TLS criptografado;", "example_upstream_doh": "<0>DNS-sobre-HTTPS criptografado;", "example_upstream_doq": "<0>DNS-sobre-QUIC criptografado;", "example_upstream_sdns": "<0>DNS Stamps para o <1>DNSCrypt ou usar os resolvedores <2>DNS-sobre-HTTPS;", "example_upstream_tcp": "DNS regular (através do TCP);", + "example_upstream_tcp_port": "dNS normal (através do TCP, com porta);", "example_upstream_tcp_hostname": "DNS normal (através do TCP, nome do servidor);", "all_lists_up_to_date_toast": "Todas as listas já estão atualizadas", "updated_upstream_dns_toast": "Servidores DNS primário salvos com sucesso", diff --git a/client/src/__locales/pt-pt.json b/client/src/__locales/pt-pt.json index 6003952e..88299c5a 100644 --- a/client/src/__locales/pt-pt.json +++ b/client/src/__locales/pt-pt.json @@ -111,7 +111,7 @@ "enabled_protection": "Ativar proteção", "disable_protection": "Desativar proteção", "disabled_protection": "Desativar proteção", - "refresh_statics": "Actualizar estatísticas", + "refresh_statics": "Atualizar estatísticas", "dns_query": "Consultas de DNS", "blocked_by": "<0>Bloqueado por filtros", "stats_malware_phishing": "Malware/phishing bloqueados", @@ -211,12 +211,14 @@ "example_comment_hash": "# Também um comentário.", "example_regex_meaning": "bloquear o acesso aos domínios que correspondam à expressão regular especificada.", "example_upstream_regular": "DNS regular (através do UDP)", + "example_upstream_regular_port": "DNS normal (através do UDP, com porta);", "example_upstream_udp": "DNS normal (através do UDP, nome do servidor);", "example_upstream_dot": "<0>DNS-sobre-TLS criptografado;", "example_upstream_doh": "<0>DNS-sobre-HTTPS criptografado;", "example_upstream_doq": "<0>DNS-sobre-QUIC criptografado;", "example_upstream_sdns": "<0>DNS Stamps para o <1>DNSCrypt ou usar os resolvedores <2>DNS-sobre-HTTPS;", "example_upstream_tcp": "DNS regular (através do TCP);", + "example_upstream_tcp_port": "dNS normal (através do TCP, com porta);", "example_upstream_tcp_hostname": "DNS normal (através do TCP, nome do servidor);", "all_lists_up_to_date_toast": "Todas as listas já estão atualizadas", "updated_upstream_dns_toast": "Servidores DNS primário guardados com sucesso", @@ -254,7 +256,7 @@ "query_log_filtered": "Filtrado por {{filter}}", "query_log_confirm_clear": "Tem a certeza de que deseja limpar todo o registo de consulta?", "query_log_cleared": "O registo de consulta foi limpo com sucesso", - "query_log_updated": "O registro da consulta foi atualizado com sucesso", + "query_log_updated": "O registo da consulta foi atualizado com sucesso", "query_log_clear": "Limpar registos de consulta", "query_log_retention": "Retenção de registos de consulta", "query_log_enable": "Ativar registo", @@ -263,7 +265,7 @@ "query_log_strict_search": "Usar aspas duplas para uma pesquisa rigorosa", "query_log_retention_confirm": "Tem a certeza de que deseja alterar a retenção do registo de consulta? Se diminuir o valor do intervalo, alguns dados serão perdidos", "anonymize_client_ip": "Tornar anónimo o IP do cliente", - "anonymize_client_ip_desc": "Não gurda o endereço de IP completo do cliente em registros ou estatísticas", + "anonymize_client_ip_desc": "Não gurda o endereço de IP completo do cliente em registo ou estatísticas", "dns_config": "Definição do servidor DNS", "dns_cache_config": "Definição de cache DNS", "dns_cache_config_desc": "Aqui você pode configurar o cache do DNS", @@ -289,7 +291,7 @@ "form_enter_rate_limit": "Insira o limite de taxa", "rate_limit": "Limite de taxa", "edns_enable": "Ativar a sub-rede do cliente EDNS", - "edns_cs_desc": "Adicione a opção de sub-rede de cliente EDNS (ECS) às solicitações de servidor DNS primário e registre os valores enviados pelos clientes no registro de consulta.", + "edns_cs_desc": "Adicione a opção de sub-rede de cliente EDNS (ECS) às solicitações de servidor DNS primário e registre os valores enviados pelos clientes no registo de consulta.", "rate_limit_desc": "O número de solicitações por segundo permitido por cliente. Configurando para 0 significa sem limite.", "blocking_ipv4_desc": "Endereço IP a ser devolvido para uma solicitação A bloqueada", "blocking_ipv6_desc": "Endereço IP a ser devolvido para uma solicitação AAAA bloqueada", @@ -410,7 +412,7 @@ "manual_update": "Por favor, siga estes passos para atualizar manualmente.", "processing_update": "Por favor espere, o AdGuard Home está a atualizar-se", "clients_title": "Clientes persistentes", - "clients_desc": "Configure registros de cliente persistentes para dispositivos conectados ao AdGuard Home", + "clients_desc": "Configure registos de cliente persistentes para dispositivos conectados ao AdGuard Home", "settings_global": "Global", "settings_custom": "Personalizar", "table_client": "Cliente", @@ -445,7 +447,7 @@ "access_disallowed_title": "Clientes não permitidos", "access_disallowed_desc": "Uma lista de CIDRs, endereços IP ou IDs de cliente. Se essa lista tiver entradas, o AdGuard Home descartará as solicitações desses clientes. Este campo é ignorado se houver entradas em clientes permitidos.", "access_blocked_title": "Domínios bloqueados", - "access_blocked_desc": "Não deve ser confundido com filtros. O AdGuard Home elimina as consultas DNS que correspondem a esses domínios, e essas consultas nem aparecem no registro de consultas. Você pode especificar nomes de domínio exatos, caracteres curinga ou regras de filtro de URL, por exemplo \"exemplo.org\", \"*.exemplo.org\", ou \"||exemplo.org^\" correspondentemente.", + "access_blocked_desc": "Não deve ser confundido com filtros. O AdGuard Home elimina as consultas DNS que correspondem a esses domínios, e essas consultas nem aparecem no registo de consultas. Você pode especificar nomes de domínio exatos, caracteres curinga ou regras de filtro de URL, por exemplo \"exemplo.org\", \"*.exemplo.org\", ou \"||exemplo.org^\" correspondentemente.", "access_settings_saved": "Definições de acesso foram guardadas com sucesso", "updates_checked": "Uma nova versão do AdGuard Home está disponível\n", "updates_version_equal": "O AdGuard Home está atualizado", @@ -546,9 +548,9 @@ "example_rewrite_domain": "reescrever resposta apenas para este domínio.", "example_rewrite_wildcard": "reescrever resposta para todos <0>example.org sub-domínios.", "rewrite_ip_address": "Endereço IP: use esse IP em uma resposta A ou AAAA", - "rewrite_domain_name": "Nome de domínio: adicione um registro CNAME", - "rewrite_A": "<0>A: valor especial, mantenha <0>A nos registros do upstream", - "rewrite_AAAA": "<0>AAAA: valor especial, mantenha <0>AAAA nos registros do servidor DNS primário", + "rewrite_domain_name": "Nome de domínio: adicione um registo CNAME", + "rewrite_A": "<0>A: valor especial, mantenha <0>A nos registos do upstream", + "rewrite_AAAA": "<0>AAAA: valor especial, mantenha <0>AAAA nos registos do servidor DNS primário", "disable_ipv6": "Desativar resolução de endereços IPv6", "disable_ipv6_desc": "Descarta todas as consultas DNS para endereços IPv6 (tipo AAAA).", "fastest_addr": "Endereço de IP mais rápido", diff --git a/client/src/__locales/ro.json b/client/src/__locales/ro.json index e0bf4fd0..7a723ac0 100644 --- a/client/src/__locales/ro.json +++ b/client/src/__locales/ro.json @@ -211,12 +211,14 @@ "example_comment_hash": "# De asemenea, un comentariu.", "example_regex_meaning": "blochează accesul la domeniile care corespund expresiei regulate specificate.", "example_upstream_regular": "DNS clasic (over UDP);", + "example_upstream_regular_port": "DNS obișnuit (over UDP, cu port);", "example_upstream_udp": "DNS obișnuit (over UDP, nume de gazdă);", "example_upstream_dot": "<0>DNS-over-TLS criptat;", "example_upstream_doh": "<0>DNS-over-HTTPS criptat;", "example_upstream_doq": "criptat <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS Stamps pentru <1>DNSCrypt sau rezolvatori <2>DNS-over-HTTPS;", "example_upstream_tcp": "DNS clasic (over TCP);", + "example_upstream_tcp_port": "DNS obișnuit (over TCP, cu port);", "example_upstream_tcp_hostname": "DNS obișnuit (over TCP, nume de gazdă);", "all_lists_up_to_date_toast": "Toate listele sunt deja la zi", "updated_upstream_dns_toast": "Serverele din amonte au fost salvate cu succes", diff --git a/client/src/__locales/ru.json b/client/src/__locales/ru.json index 6a1b6d66..9ecdbad2 100644 --- a/client/src/__locales/ru.json +++ b/client/src/__locales/ru.json @@ -211,12 +211,14 @@ "example_comment_hash": "# И вот так тоже.", "example_regex_meaning": "блокировать доступ к доменам, соответствующим заданному регулярному выражению.", "example_upstream_regular": "обычный DNS (поверх UDP);", + "example_upstream_regular_port": "обычный DNS (поверх UDP, с портом);", "example_upstream_udp": "обычный DNS (поверх UDP, с именем хоста);", "example_upstream_dot": "зашифрованный <0>DNS-over-TLS;", "example_upstream_doh": "зашифрованный <0>DNS-over-HTTPS;", "example_upstream_doq": "зашифрован <0>DNS-over-QUIC", "example_upstream_sdns": "<0>DNS Stamps для <1>DNSCrypt или <2>DNS-over-HTTPS серверов;", "example_upstream_tcp": "обычный DNS (поверх TCP);", + "example_upstream_tcp_port": "обычный DNS (поверх TCP, с портом);", "example_upstream_tcp_hostname": "обычный DNS (поверх TCP, с именем хоста);", "all_lists_up_to_date_toast": "Все списки уже обновлены", "updated_upstream_dns_toast": "DNS-серверы успешно обновлены", @@ -626,7 +628,7 @@ "original_response": "Первоначальный ответ", "click_to_view_queries": "Нажмите, чтобы просмотреть запросы", "port_53_faq_link": "Порт 53 часто занят службами «DNSStubListener» или «systemd-resolved». Ознакомьтесь с <0>инструкцией о том, как это разрешить.", - "adg_will_drop_dns_queries": "AdGuard Home AdGuard Home сбросит все DNS-запросы от этого клиента.", + "adg_will_drop_dns_queries": "AdGuard Home сбросит все DNS-запросы от этого клиента.", "filter_allowlist": "ВНИМАНИЕ: Это действие также исключит правило «{{disallowed_rule}}» из списка разрешённых клиентов.", "last_rule_in_allowlist": "Нельзя заблокировать этого клиента, так как исключение правила «{{disallowed_rule}}» ОТКЛЮЧИТ режим белого списка.", "use_saved_key": "Использовать сохранённый ранее ключ", diff --git a/client/src/__locales/si-lk.json b/client/src/__locales/si-lk.json index 17802771..8d4c335a 100644 --- a/client/src/__locales/si-lk.json +++ b/client/src/__locales/si-lk.json @@ -315,7 +315,7 @@ "install_devices_router": "මාර්ගකාරකය", "install_devices_router_desc": "මෙම පිහිටුම ඔබගේ නිවසේ මාර්ගකාරකයට සම්බන්ධිත සියළුම උපාංග ස්වයංක්‍රීයව ආවරණය කරන අතර ඔබට ඒ සෑම එකක්ම අතින් වින්‍යාසගත කිරීමට අවශ්‍ය නොවේ.", "install_devices_address": "ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකය පහත ලිපිනයන්ට සවන් දෙමින් පවතී", - "install_devices_router_list_1": "ඔබගේ මාර්ගකාරකය සඳහා වූ මනාපයන් විවෘත කරන්න. සාමාන්‍යයෙන්, එය ඔබගේ අතිරික්සුවෙන් ඒ.ස.නි.(URL) ක් හරහා (http://192.168.0.1/ හෝ http://192.168.1.1/ වැනි) ප්‍රවේශ විය හැකිය. මුරපදය ඇතුල් කිරීමට සිදු විය හැකි නමුත් එය මතක නැතිනම් බොහෝ විට මාර්ගකාරකයේ බොත්තමක් එබීමෙන් මුරපදය නැවත සැකසිය හැකිය. නමුත් මෙම ක්‍රියා පටිපාටිය තෝරා ගන්නේ නම්, බොහෝ විට ඔබගේ මාර්ගකාරකයේ සමස්ථ වින්‍යාසය අහිමි වනු ඇති බව මතක තබා ගන්න.එය පිහිටුවීමට ඔබගේ මාර්ගකාරකයට යෙදුමක් ඇවැසි නම්, කරුණාකර එය ඔබගේ පරිගණකයේ හෝ දුරකථනයේ ස්ථාපනය කර මාර්ගකාරකයේ සැකසුම් වෙත ප්‍රවේශ වීමට භාවිතා කරන්න.", + "install_devices_router_list_1": "ඔබගේ මාර්ගකාරකයෙහි අභිප්‍රේත විවෘත කරන්න. සාමාන්‍යයෙන්, එය ඔබගේ අතිරික්සුවෙන් ඒ.ස.නි.(URL) ක් හරහා (http://192.168.0.1/ හෝ http://192.168.1.1/ වැනි) ප්‍රවේශ විය හැකිය. මුරපදය ඇතුල් කිරීමට සිදු විය හැකි නමුත් එය මතක නැතිනම් බොහෝ විට මාර්ගකාරකයේ බොත්තමක් එබීමෙන් මුරපදය නැවත සැකසීමට හැකිය. නමුත් මෙම ක්‍රියා පටිපාටිය තෝරා ගන්නේ නම්, බොහෝ විට ඔබගේ මාර්ගකාරකයේ සමස්ථ වින්‍යාසය අහිමි වනු ඇති බව මතක තබා ගන්න. මෙය පිහිටුවීමට ඔබගේ මාර්ගකාරකයට යෙදුමක් ඇවැසි නම්, කරුණාකර එය ඔබගේ පරිගණකයේ හෝ දුරකථනයේ ස්ථාපනය කර මාර්ගකාරකයේ සැකසුම් වෙත ප්‍රවේශ වීමට භාවිතා කරන්න.", "install_devices_router_list_2": "ග.ධා.වි.කෙ. (DHCP)/ ව.නා.ප. (DNS) සැකසුම් සොයා ගන්න. අංක කට්ටල දෙකකට හෝ තුනකට ඉඩ දෙන ක්ෂේත්‍රයක් අසල ඇති ව.නා.ප. අකුරු බලන්න, සෑම එකක්ම ඉලක්කම් එකේ සිට තුන දක්වා කාණ්ඩ හතරකට බෙදා ඇත.", "install_devices_router_list_3": "ඔබගේ ඇඩ්ගාර්ඩ් හෝම් සේවාදායක ලිපින එහි ඇතුල් කරන්න.", "install_devices_router_list_4": "සමහර වර්ගයේ මාර්ගකාරක වල අභිරුචි ව.නා.ප. සේවාදායකයක් සැකසීමට නොහැකිය. මෙම අවස්ථාවේදී ඇඩ්ගාර්ඩ් හෝම් <0>ග.ධා.වි.කෙ. සේවාදායකයක් ලෙස පිහිටුවන්නේ නම් එය උපකාර වනු ඇත. එසේ නැතිනම්, ඔබගේ විශේෂිත මාර්ගකාරකය සඳහා වූ ව.නා.ප. සේවාදායක රිසිකරණය කරන්නේ කෙසේද යන්න පිළිබඳ අත්පොත පරීක්‍ෂා කළ යුතුය.", @@ -325,7 +325,7 @@ "install_devices_windows_list_4": "ඔබගේ ක්‍රියාකාරී සම්බන්ධතාවය මත දකුණු-ක්ලික් කර ගුණාංග තෝරන්න.", "install_devices_windows_list_5": "ලැයිස්තුවෙන් \"අන්තර්ජාල කෙටුම්පත් අනුවාදය 4 (TCP/IPv4)\" (හෝ, IPv6 සඳහා, \"අන්තර්ජාල කෙටුම්පත් අනුවාදය 6 (TCP/IPv6)\") සොයාගෙන එය තෝරා ඉන්පසු ගුණාංග මත නැවත ඔබන්න.", "install_devices_windows_list_6": "'පහත සඳහන් ව.නා.ප. සේවාදායක ලිපින භාවිතා කරන්න' යන්න තෝරා ඔබගේ ඇඩ්ගාර්ඩ් හෝම් සේවාදායක ලිපින ඇතුල් කරන්න.", - "install_devices_macos_list_1": "ඇපල් නිරූපකය එබීමෙන් පසු පද්ධතියේ මනාප වෙත යන්න.", + "install_devices_macos_list_1": "ඇපල් නිරූපකය එබීමෙන් පසු පද්ධතියේ අභිප්‍රේත වෙත යන්න.", "install_devices_macos_list_2": "ජාලය මත ඔබන්න.", "install_devices_macos_list_3": "ඔබගේ ලැයිස්තුවේ පළමු සම්බන්ධතාවය තෝරා වැඩිදුර යන්න ඔබන්න.", "install_devices_macos_list_4": "ව.නා.ප. (DNS) තීරුව තෝරා ඔබගේ ඇඩ්ගාර්ඩ් හෝම් සේවාදායක ලිපින ඇතුල් කරන්න.", diff --git a/client/src/__locales/sk.json b/client/src/__locales/sk.json index b4fa2955..e3db6a43 100644 --- a/client/src/__locales/sk.json +++ b/client/src/__locales/sk.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Tiež komentár.", "example_regex_meaning": "zablokovať prístup k doménam zodpovedajúcim zadanému regulárnemu výrazu.", "example_upstream_regular": "obyčajná DNS (cez UDP);", + "example_upstream_regular_port": "bežný DNS (cez UDP, s portom);", "example_upstream_udp": "štandardné DNS (cez UDP, hostname);", "example_upstream_dot": "šifrované <0>DNS-over-TLS;", "example_upstream_doh": "šifrované <0>DNS-over-HTTPS;", "example_upstream_doq": "šifrované <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS pečiatky pre <1>DNSCrypt alebo <2>DNS-over-HTTPS rezolvery;", "example_upstream_tcp": "obyčajná DNS (cez TCP);", + "example_upstream_tcp_port": "bežný DNS (cez TCP, s portom);", "example_upstream_tcp_hostname": "štandardné DNS (cez TCP, hostname);", "all_lists_up_to_date_toast": "Všetky zoznamy sú už aktuálne", "updated_upstream_dns_toast": "Upstream servery boli úspešne uložené", diff --git a/client/src/__locales/sl.json b/client/src/__locales/sl.json index 1e89cc66..7f0ac8ee 100644 --- a/client/src/__locales/sl.json +++ b/client/src/__locales/sl.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Tudi komentar.", "example_regex_meaning": "onemogoča dostop do domen, ki se ujemajo z določenim regularnim izrazom.", "example_upstream_regular": "redni DNS (nad UDP);", + "example_upstream_regular_port": "redni DNS (nad UDP, z vrati);", "example_upstream_udp": "redni DNS (nad UDP, ime gostitelja);", "example_upstream_dot": "šifriran <0>DNS-prek-TLS;", "example_upstream_doh": "šifriran <0>DNS-prek-HTTPS;", "example_upstream_doq": "šifriran <0>DNS-prek-QUIC;", "example_upstream_sdns": "lahko uporabite <0>DNS Žige za reševalce <1>DNSCrypt ali <2>DNS-prek-HTTPS;", "example_upstream_tcp": "redni DNS (nad TCP);", + "example_upstream_tcp_port": "redni DNS (nad TCP, z vrati);", "example_upstream_tcp_hostname": "redni DNS (nad TCP, ime gostitelja);", "all_lists_up_to_date_toast": "Vsi seznami so že posodobljeni", "updated_upstream_dns_toast": "Gorvodni trežniki so uspešno shranjeni", diff --git a/client/src/__locales/sr-cs.json b/client/src/__locales/sr-cs.json index c42b57ad..4dc6978b 100644 --- a/client/src/__locales/sr-cs.json +++ b/client/src/__locales/sr-cs.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Takođe komentar.", "example_regex_meaning": "blokiranje pristupa domenima koji odgovaraju određenom uobičajenom izrazu.", "example_upstream_regular": "uobičajeno DNS (preko UDP);", + "example_upstream_regular_port": "uobičajen DNS (preko UDP, sa portom);", "example_upstream_udp": "uobičajen DNS (preko UDP, imena domaćina);", "example_upstream_dot": "šifrovano <0>DNS-over-TLS;", "example_upstream_doh": "šifrovano <0>DNS-over-HTTPS;", "example_upstream_doq": "šifrovano <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS brojeve za <1>DNSCrypt ili <2>DNS-over-HTTPS razrešivače;", "example_upstream_tcp": "uobičajeni DNS (preko TCP);", + "example_upstream_tcp_port": "uobičajen DNS (preko TCP, sa portom);", "example_upstream_tcp_hostname": "uobičajen DNS (preko TCP, imena domaćina);", "all_lists_up_to_date_toast": "Sve liste su već ažurirane", "updated_upstream_dns_toast": "Upstream serveri su uspešno sačuvani", diff --git a/client/src/__locales/sv.json b/client/src/__locales/sv.json index 5fc3a4cc..c0d78cbe 100644 --- a/client/src/__locales/sv.json +++ b/client/src/__locales/sv.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Också en kommentar", "example_regex_meaning": "blockera åtkomst till domäner som matchar det angivna uttrycket", "example_upstream_regular": "vanlig DNS (över UDP)", + "example_upstream_regular_port": "vanlig DNS (via UDP, med port);", "example_upstream_udp": "vanlig DNS (över UDP, värdnamn);", "example_upstream_dot": "krypterat <0>DNS-over-TLS", "example_upstream_doh": "krypterat <0>DNS-over-HTTPS", "example_upstream_doq": "krypterat <0>DNS-over-QUIC;", "example_upstream_sdns": "Du kan använda <0>DNS-stamps för <1>DNSCrypt eller <2>DNS-over-HTTPS-resolvers", "example_upstream_tcp": "vanlig DNS (över UDP)", + "example_upstream_tcp_port": "vanlig DNS (via TCP, med port);", "example_upstream_tcp_hostname": "vanlig DNS (över TCP, värdnamn);", "all_lists_up_to_date_toast": "Alla listor är redan uppdaterade", "updated_upstream_dns_toast": "Sparade uppströms dns-servrar", diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index e4415e33..cacb857d 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -44,16 +44,16 @@ "form_error_ip_format": "Geçersiz IP adresi", "form_error_mac_format": "Geçersiz MAC adresi", "form_error_client_id_format": "İstemci Kimliği yalnızca sayılar, küçük harfler ve kısa çizgiler içermelidir", - "form_error_server_name": "Geçersiz sunucu adı", + "form_error_server_name": "Sunucu adı geçersiz", "form_error_subnet": "\"{{cidr}}\" alt ağı, \"{{ip}}\" IP adresini içermiyor", "form_error_positive": "0'dan büyük olmalıdır", - "form_error_gateway_ip": "Kiralama, ağ geçidinin IP adresine sahip olamaz", + "form_error_gateway_ip": "Kiralama, ağ geçidinin IP adresiyle aynı olamaz", "out_of_range_error": "\"{{start}}\"-\"{{end}}\" aralığının dışında olmalıdır", "lower_range_start_error": "Başlangıç aralığından daha düşük olmalıdır", "greater_range_start_error": "Başlangıç aralığından daha büyük olmalıdır", "greater_range_end_error": "Bitiş aralığından daha büyük olmalıdır", "subnet_error": "Adresler bir alt ağda olmalıdır", - "gateway_or_subnet_invalid": "Alt ağ maskesi geçersiz.", + "gateway_or_subnet_invalid": "Alt ağ maskesi geçersiz", "dhcp_form_gateway_input": "Ağ geçidi IP", "dhcp_form_subnet_input": "Alt ağ maskesi", "dhcp_form_range_title": "IP adresi aralığı", @@ -108,9 +108,9 @@ "report_an_issue": "Bir sorun bildir", "privacy_policy": "Gizlilik Politikası", "enable_protection": "Korumayı etkinleştir", - "enabled_protection": "Koruma etkileştirildi", + "enabled_protection": "Koruma etkinleştirildi", "disable_protection": "Korumayı devre dışı bırak", - "disabled_protection": "Koruma durduruldu", + "disabled_protection": "Koruma devre dışı bırakıldı", "refresh_statics": "İstatistikleri yenile", "dns_query": "DNS Sorguları", "blocked_by": "<0>Filtreler tarafından engellenen", @@ -180,7 +180,7 @@ "edit_table_action": "Düzenle", "delete_table_action": "Sil", "elapsed": "Geçen süre", - "filters_and_hosts_hint": "AdGuard Home, temel reklam engelleme kurallarını ve ana makine engelleme dosyalarının söz dizimini anlar.", + "filters_and_hosts_hint": "AdGuard Home, temel reklam engelleme kurallarını ve ana makine dosyalarının söz dizimini anlar.", "no_blocklist_added": "Engel listesi eklenmedi", "no_whitelist_added": "İzin listesi eklenmedi", "add_blocklist": "Engel listesi ekle", @@ -211,12 +211,14 @@ "example_comment_hash": "# Ayrıca bir yorum.", "example_regex_meaning": "belirtilen düzenli ifadelerle eşleşen alan adlarına erişimi engelle.", "example_upstream_regular": "normal DNS (UDP üzerinden);", + "example_upstream_regular_port": "normal DNS (UDP üzerinden, bağlantı noktası ile);", "example_upstream_udp": "normal DNS (UDP üzerinden, ana makine adı);", "example_upstream_dot": "şifrelenmiş <0>DNS-over-TLS;", "example_upstream_doh": "şifrelenmiş <0>DNS-over-HTTPS;", "example_upstream_doq": "şifrelenmiş <0>DNS-over-QUIC;", "example_upstream_sdns": "<1>DNSCrypt veya <2>DNS-over-HTTPS çözümleyicileri için <0>DNS Damgaları;", "example_upstream_tcp": "normal DNS (TCP üzerinden);", + "example_upstream_tcp_port": "normal DNS (TCP üzerinden, bağlantı noktası ile);", "example_upstream_tcp_hostname": "normal DNS (TCP üzerinden, ana makine adı);", "all_lists_up_to_date_toast": "Tüm listeler güncel durumda", "updated_upstream_dns_toast": "Üst sunucular başarıyla kaydedildi", @@ -384,8 +386,8 @@ "encryption_enable_desc": "Şifrelemeyi etkinleştirirseniz, AdGuard Home yönetici arayüzü HTTPS üzerinden çalışır ve DNS sunucusu, DNS-over-HTTPS ve DNS-over-TLS üzerinden gelen istekleri dinler.", "encryption_chain_valid": "Sertifika zinciri geçerli", "encryption_chain_invalid": "Sertifika zinciri geçersiz.", - "encryption_key_valid": "Bu geçerli bir {{type}} özel anahtar.", - "encryption_key_invalid": "Bu geçersiz bir {{type}} özel anahtar.", + "encryption_key_valid": "Bu geçerli bir {{type}} özel anahtarıdır", + "encryption_key_invalid": "Bu geçersiz bir {{type}} özel anahtarıdır", "encryption_subject": "Konu", "encryption_issuer": "Sağlayan", "encryption_hostnames": "Ana makine adları", diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json index d89c1da4..e111863d 100644 --- a/client/src/__locales/uk.json +++ b/client/src/__locales/uk.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Також коментар.", "example_regex_meaning": "блокувати доступ до доменів, що відповідають вказаному регулярному виразу.", "example_upstream_regular": "звичайний DNS (через UDP);", + "example_upstream_regular_port": "звичайний DNS (поверх UDP, з портом);", "example_upstream_udp": "звичайний DNS (поверх UDP, з назвою вузла);", "example_upstream_dot": "зашифрований <0>DNS-over-TLS;", "example_upstream_doh": "зашифрований <0>DNS-over-HTTPS;", "example_upstream_doq": "зашифрований <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS Stamps для <1>DNSCrypt- або <2>DNS-over-HTTPS-вирішувачів;", "example_upstream_tcp": "звичайний DNS (через TCP);", + "example_upstream_tcp_port": "звичайний DNS (поверх TCP, з портом);", "example_upstream_tcp_hostname": "звичайний DNS (поверх TCP, з назвою вузла);", "all_lists_up_to_date_toast": "Всі списки вже оновлені", "updated_upstream_dns_toast": "DNS-сервери успішно збережено", diff --git a/client/src/__locales/vi.json b/client/src/__locales/vi.json index 3000a29a..c8109e40 100644 --- a/client/src/__locales/vi.json +++ b/client/src/__locales/vi.json @@ -211,12 +211,14 @@ "example_comment_hash": "# Cũng là một chú thích.", "example_regex_meaning": "chặn quyền truy cập vào các miền khớp với biểu thức chính được quy định.", "example_upstream_regular": "DNS thông thường (dùng UDP);", + "example_upstream_regular_port": "DNS thông thường (qua UDP, với cổng);", "example_upstream_udp": "DNS thông thường (qua UDP, tên máy chủ);", "example_upstream_dot": "được mã hoá <0>DNS-over-TLS;", "example_upstream_doh": "được mã hoá <0>DNS-over-HTTPS;", "example_upstream_doq": "được mã hoá <0>DNS-over-QUIC;", "example_upstream_sdns": "bạn có thể sử dụng <0>DNS Stamps for <1>DNSCrypt hoặc <2>DNS-over-HTTPS ", "example_upstream_tcp": "DNS thông thường(dùng TCP);", + "example_upstream_tcp_port": "DNS thông thường (qua TCP, với cổng);", "example_upstream_tcp_hostname": "DNS thông thường (qua TCP, tên máy chủ);", "all_lists_up_to_date_toast": "Tất cả danh sách đã ở phiên bản mới nhất", "updated_upstream_dns_toast": "Các máy chủ thượng nguồn đã được lưu thành công", diff --git a/client/src/__locales/zh-cn.json b/client/src/__locales/zh-cn.json index 7c777c1d..e8dc8e43 100644 --- a/client/src/__locales/zh-cn.json +++ b/client/src/__locales/zh-cn.json @@ -70,7 +70,7 @@ "dhcp_warning": "如果你想要启用内置的 DHCP 服务器,请确保在当前网络中没有其它起作用的 DHCP 服务器。否则,此操作可能会破坏已连接设备的网络连接!", "dhcp_error": "AdGuard Home 无法确定在当前网络中是否存在其它 DHCP 服务器", "dhcp_static_ip_error": "要使用 DHCP 服务器,则必须设置静态 IP 地址。AdGuard Home 无法确定此网络接口是否已被配置为使用静态 IP 地址。请手动为此网络接口设置静态 IP 地址。", - "dhcp_dynamic_ip_found": "您的系统对网络接口 <0>{{interfaceName}} 使用了动态 IP 地址配置。要使用 DHCP 服务器,则必须对此网络接口使用静态 IP 地址配置。此网络接口当前的 IP 地址为 <0>{{ipAddress}}。如您点击“启用 DHCP 服务器” 按钮,AdGuard Home 将自动修改此网络接口以使用静态 IP 地址。", + "dhcp_dynamic_ip_found": "您的系统对网络接口 <0>{{interfaceName}} 使用了动态 IP 地址配置。要使用 DHCP 服务器,则必须对此网络接口使用静态 IP 地址配置。此网络接口当前的 IP 地址为 <0>{{ipAddress}}。如您点击「启用 DHCP 服务器」按钮,AdGuard Home 将自动修改此网络接口以使用静态 IP 地址。", "dhcp_lease_added": "静态租约 \"{{key}}\" 已成功添加", "dhcp_lease_deleted": "静态租约 \"{{key}}\" 已成功删除", "dhcp_new_static_lease": "新建静态租约", @@ -211,12 +211,14 @@ "example_comment_hash": "# 这也是一行注释。", "example_regex_meaning": "阻止访问与指定的正则表达式匹配的域名。", "example_upstream_regular": "常规 DNS(基于 UDP);", + "example_upstream_regular_port": "常规 DNS(通过 UDP,带端口);", "example_upstream_udp": "常规 DNS(通过 UDP、主机名);", "example_upstream_dot": "加密 <0>DNS-over-TLS;", "example_upstream_doh": "加密 <0>DNS-over-HTTPS;", "example_upstream_doq": "加密 <0>DNS-over-QUIC", "example_upstream_sdns": "<1>DNSCrypt 的 <0>DNS Stamps 或者 <2>DNS-over-HTTPS 解析器;", "example_upstream_tcp": "常规 DNS(基于 TCP );", + "example_upstream_tcp_port": "常规 DNS(通过 TCP,带端口);", "example_upstream_tcp_hostname": "常规 DNS(通过 TCP、主机名);", "all_lists_up_to_date_toast": "所有列表都是最新的", "updated_upstream_dns_toast": "上游服务器保存成功", @@ -341,7 +343,7 @@ "install_devices_windows_list_3": "在窗口的左侧点击「更改适配器设置」。", "install_devices_windows_list_4": "选择您正在连接的网络设备,右击它并选择「属性”」。", "install_devices_windows_list_5": "在列表中找到「Internet 协议版本 4 (TCP/IPv4)」,选择并再次点击「属性」。", - "install_devices_windows_list_6": "选择“使用下面的 DNS 服务器地址”,并输入您的 AdGuard Home 服务器地址。", + "install_devices_windows_list_6": "选择「使用下面的 DNS 服务器地址」,并输入您的 AdGuard Home 服务器地址。", "install_devices_macos_list_1": "点击苹果图标,进入「系统首选项」。", "install_devices_macos_list_2": "点击「网络」。", "install_devices_macos_list_3": "选择在列表中的第一个连接,并点击「高级」。", @@ -397,7 +399,7 @@ "form_error_equal": "不可相同", "form_error_password": "密码不匹配", "reset_settings": "重置设置", - "update_announcement": "AdGuard Home {{version}} 现已发布! <0>点击此处 以获取详细信息。", + "update_announcement": "AdGuard Home {{version}} 现已发布! <0>点击此处以获取详细信息。", "setup_guide": "设置指导", "dns_addresses": "DNS 地址", "dns_start": "正在启动DNS服务", @@ -423,7 +425,7 @@ "ip_address": "IP 地址", "client_identifier_desc": "客户端可通过 IP 、MAC 地址、CIDR 或客户端 ID(可用于 DoT/DoH/DoQ)被识别。<0>这里您可多了解如何识别客户端。", "form_enter_ip": "输入 IP", - "form_enter_subnet_ip": "输入一个 IP 地址,其须位于子网\"{{cidr}}\"", + "form_enter_subnet_ip": "输入一个 IP 地址,其须位于子网 \"{{cidr}}\"", "form_enter_mac": "输入 MAC", "form_enter_id": "输入标识符", "form_add_id": "添加标识符", @@ -473,7 +475,7 @@ "rewrite_add": "添加 DNS 重写", "rewrite_not_found": "未找到 DNS 重写", "rewrite_confirm_delete": "您确定要删除 \"{{key}}\" 的 DNS 重写?", - "rewrite_desc": "可以轻松地配置特定的域名的自定义 DNS 响应。", + "rewrite_desc": "可以轻松地为特定域名配置自定义 DNS 响应。", "rewrite_applied": " 重定向规则已应用", "rewrite_hosts_applied": "根据hosts文件规则已被重写", "dns_rewrites": "DNS 重写", @@ -553,7 +555,7 @@ "disable_ipv6_desc": "丢弃所有 IPv6 地址 (AAAA) 的 DNS 查询。", "fastest_addr": "最快的 IP 地址", "fastest_addr_desc": "查询所有 DNS 服务器并返回所有响应中速度最快的 IP 地址。因 AdGuard Home 必须等待全部 DNS 服务器均有所回应,因而会降低 DNS 查询的速度,但同时,此举将会改善总体的连接。", - "autofix_warning_text": "若您单击“修复”,AdGuardHome将会配置您的系统以使用AdGuardHome的DNS服务器", + "autofix_warning_text": "若您单击「修复」,AdGuardHome 将会配置您的系统以使用 AdGuardHome 的 DNS 服务器。", "autofix_warning_list": "其将会进行如下工作:<0>停用系统DNSStubListener<0>设置DNS服务器地址为127.0.0.1<0>将/etc/resolv.conf的符号链接目标替换为/run/systemd/resolv/resolv.conf<0>停止DNSStubListener(重新加载系统解析服务)", "autofix_warning_result": "因此,默认情况下所有来自系统的DNS请求都将由AdGuardHome处理。", "tags_title": "标签", @@ -573,14 +575,14 @@ "check_service": "服务名称:{{service}}", "service_name": "服务名称", "check_not_found": "未在您的筛选列表中找到", - "client_confirm_block": "您确定要阻止客户端\"{{ip}}\"?", - "client_confirm_unblock": "您确定要解除对客户端\"{{ip}}\"的封锁吗?", - "client_blocked": "客户端 \"{{ip}}\"被成功拦截", - "client_unblocked": "成功解锁客户端\"{{ip}}\"", + "client_confirm_block": "您确定要阻止客户端 \"{{ip}}\"?", + "client_confirm_unblock": "您确定要解除对客户端 \"{{ip}}\" 的封锁吗?", + "client_blocked": "客户端 \"{{ip}}\" 被成功拦截", + "client_unblocked": "成功解锁客户端 \"{{ip}}\"", "static_ip": "静态IP地址", "static_ip_desc": "AdGuard Home 是一个服务器,所以它需要一个静态IP地址才能正常工作。否则,在某些情况下,你的路由器可能会给这个设备分配一个不同的IP地址。", "set_static_ip": "设置一个静态IP", - "install_static_ok": "好消息!静态IP地址已经配置", + "install_static_ok": "好消息!静态 IP 地址已经配置", "install_static_error": "AdGuard Home 无法为这个网络接口自动配置它。请参阅如何手动完成此操作的说明。", "install_static_configure": "AdGuard Home 检测到一个动态 IP 地址 <0>{{ip}} 被使用。您想把它作为您的静态地址吗?", "confirm_static_ip": "AdGuard Home 将把{{ip}} 配置为您的静态IP地址。您想要继续吗?", @@ -625,8 +627,8 @@ "setup_config_to_enable_dhcp_server": "设置配置以启用 DHCP 服务器", "original_response": "原始响应", "click_to_view_queries": "点击查看查询", - "port_53_faq_link": "53端口常被DNSStubListener或systemdn解析的服务占用。请阅读<0>这份关于如何解决这一问题的说明", - "adg_will_drop_dns_queries": "AdGuard Home 会终止所有来自此客户端的DNS查询。", + "port_53_faq_link": "53端口常被 DNSStubListener 或 systemdn 解析的服务占用。请阅读<0>这份关于如何解决这一问题的说明。", + "adg_will_drop_dns_queries": "AdGuard Home 会丢弃所有来自此客户端的 DNS 查询。", "filter_allowlist": "警告:此操作将把规则 \"{{disallowed_rule}}\" 排除在允许客户端的列表之外。", "last_rule_in_allowlist": "无法禁止此客户端,因为排除 “{{disallowed_rule}}” 规则将禁用“允许客户端”的列表。", "use_saved_key": "使用之前保存的密钥", diff --git a/client/src/__locales/zh-tw.json b/client/src/__locales/zh-tw.json index 3f4cdef2..73bd956b 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -211,12 +211,14 @@ "example_comment_hash": "# 也是一個註解。", "example_regex_meaning": "封鎖至與該已明確指定的規則運算式(Regular Expression)相符的網域之存取。", "example_upstream_regular": "常規 DNS(透過 UDP);", + "example_upstream_regular_port": "常規 DNS(透過 UDP,含連接埠);", "example_upstream_udp": "常規 DNS(透過 UDP,主機名稱);", "example_upstream_dot": "加密的 <0>DNS-over-TLS;", "example_upstream_doh": "加密的 <0>DNS-over-HTTPS;", "example_upstream_doq": "加密的 <0>DNS-over-QUIC;", "example_upstream_sdns": "關於 <1>DNSCrypt 或 <2>DNS-over-HTTPS 解析器之 <0>DNS 戳記;", "example_upstream_tcp": "常規 DNS(透過 TCP);", + "example_upstream_tcp_port": "常規 DNS(透過 TCP,含連接埠);", "example_upstream_tcp_hostname": "常規 DNS(透過 TCP,主機名稱);", "all_lists_up_to_date_toast": "所有的清單已是最新的", "updated_upstream_dns_toast": "上游的伺服器被成功地儲存", diff --git a/client/src/actions/services.js b/client/src/actions/services.js index 1c95e3a1..650aa330 100644 --- a/client/src/actions/services.js +++ b/client/src/actions/services.js @@ -2,6 +2,21 @@ import { createAction } from 'redux-actions'; import apiClient from '../api/Api'; import { addErrorToast, addSuccessToast } from './toasts'; +export const getBlockedServicesAvailableServicesRequest = createAction('GET_BLOCKED_SERVICES_AVAILABLE_SERVICES_REQUEST'); +export const getBlockedServicesAvailableServicesFailure = createAction('GET_BLOCKED_SERVICES_AVAILABLE_SERVICES_FAILURE'); +export const getBlockedServicesAvailableServicesSuccess = createAction('GET_BLOCKED_SERVICES_AVAILABLE_SERVICES_SUCCESS'); + +export const getBlockedServicesAvailableServices = () => async (dispatch) => { + dispatch(getBlockedServicesAvailableServicesRequest()); + try { + const data = await apiClient.getBlockedServicesAvailableServices(); + dispatch(getBlockedServicesAvailableServicesSuccess(data)); + } catch (error) { + dispatch(addErrorToast({ error })); + dispatch(getBlockedServicesAvailableServicesFailure()); + } +}; + export const getBlockedServicesRequest = createAction('GET_BLOCKED_SERVICES_REQUEST'); export const getBlockedServicesFailure = createAction('GET_BLOCKED_SERVICES_FAILURE'); export const getBlockedServicesSuccess = createAction('GET_BLOCKED_SERVICES_SUCCESS'); diff --git a/client/src/api/Api.js b/client/src/api/Api.js index 1f6b2832..d5693bfe 100644 --- a/client/src/api/Api.js +++ b/client/src/api/Api.js @@ -481,10 +481,17 @@ class Api { } // Blocked services + BLOCKED_SERVICES_SERVICES = { path: 'blocked_services/services', method: 'GET' }; + BLOCKED_SERVICES_LIST = { path: 'blocked_services/list', method: 'GET' }; BLOCKED_SERVICES_SET = { path: 'blocked_services/set', method: 'POST' }; + getBlockedServicesAvailableServices() { + const { path, method } = this.BLOCKED_SERVICES_SERVICES; + return this.makeRequest(path, method); + } + getBlockedServices() { const { path, method } = this.BLOCKED_SERVICES_LIST; return this.makeRequest(path, method); diff --git a/client/src/components/Settings/Dns/Upstream/Examples.js b/client/src/components/Settings/Dns/Upstream/Examples.js index 81d171d3..c17e9456 100644 --- a/client/src/components/Settings/Dns/Upstream/Examples.js +++ b/client/src/components/Settings/Dns/Upstream/Examples.js @@ -8,133 +8,123 @@ const Examples = (props) => ( examples_title:

  1. - 94.140.14.140: {props.t('example_upstream_regular')} + 94.140.14.140, 2a10:50c0::1:ff: {props.t('example_upstream_regular')} +
  2. +
  3. + 94.140.14.140:53, [2a10:50c0::1:ff]:53: {props.t('example_upstream_regular_port')}
  4. udp://unfiltered.adguard-dns.com: example_upstream_udp
  5. - tcp://94.140.14.140: example_upstream_tcp + tcp://94.140.14.140, tcp://[2a10:50c0::1:ff]: example_upstream_tcp +
  6. +
  7. + tcp://94.140.14.140:53, tcp://[2a10:50c0::1:ff]:53: example_upstream_tcp_port
  8. tcp://unfiltered.adguard-dns.com: example_upstream_tcp_hostname
  9. - tls://unfiltered.adguard-dns.com: - - - DNS-over-TLS - , - ]} - > - example_upstream_dot - - + tls://unfiltered.adguard-dns.com: + DNS-over-TLS + , + ]} + > + example_upstream_dot +
  10. - https://unfiltered.adguard-dns.com/dns-query: - - - DNS-over-HTTPS - , - ]} - > - example_upstream_doh - - + https://unfiltered.adguard-dns.com/dns-query: + DNS-over-HTTPS + , + ]} + > + example_upstream_doh +
  11. - quic://unfiltered.adguard-dns.com:784: - - - DNS-over-QUIC - , - ]} - > - example_upstream_doq - - + quic://unfiltered.adguard-dns.com: + DNS-over-QUIC + , + ]} + > + example_upstream_doq +
  12. - sdns://...: - - - DNS Stamps - , - - DNSCrypt - , - - DNS-over-HTTPS - , - ]} - > - example_upstream_sdns - - + sdns://...: + DNS Stamps + , + + DNSCrypt + , + + DNS-over-HTTPS + , + ]} + > + example_upstream_sdns +
  13. - [/example.local/]94.140.14.140: - - - Link - , - ]} - > - example_upstream_reserved - - + [/example.local/]94.140.14.140: + Link + , + ]} + > + example_upstream_reserved +
  14. - {COMMENT_LINE_DEFAULT_TOKEN} comment: - - example_upstream_comment - + {COMMENT_LINE_DEFAULT_TOKEN} comment: + example_upstream_comment +
diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index a5c1d2ee..935e3655 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -81,7 +81,7 @@ export const STANDARD_DNS_PORT = 53; export const STANDARD_WEB_PORT = 80; export const STANDARD_HTTPS_PORT = 443; export const DNS_OVER_TLS_PORT = 853; -export const DNS_OVER_QUIC_PORT = 784; +export const DNS_OVER_QUIC_PORT = 853; export const MAX_PORT = 65535; export const EMPTY_DATE = '0001-01-01T00:00:00Z'; diff --git a/client2/src/lib/apis/blockedServices.ts b/client2/src/lib/apis/blockedServices.ts index 381a236d..7daa3344 100644 --- a/client2/src/lib/apis/blockedServices.ts +++ b/client2/src/lib/apis/blockedServices.ts @@ -1,6 +1,18 @@ // This file was autogenerated. Please do not change. // All changes will be overwrited on commit. export default class BlockedServicesApi { + static async blockedServicesAvailableServices(): Promise { + return await fetch(`/control/blocked_services/services`, { + method: 'GET', + }).then(async (res) => { + if (res.status === 200) { + return res.json(); + } else { + return new Error(String(res.status)); + } + }) + } + static async blockedServicesList(): Promise { return await fetch(`/control/blocked_services/list`, { method: 'GET', diff --git a/doc/adguard_home_darkmode.svg b/doc/adguard_home_darkmode.svg new file mode 100644 index 00000000..419134c4 --- /dev/null +++ b/doc/adguard_home_darkmode.svg @@ -0,0 +1,56 @@ + + + + + + + + + diff --git a/doc/adguard_home_lightmode.svg b/doc/adguard_home_lightmode.svg new file mode 100644 index 00000000..00965130 --- /dev/null +++ b/doc/adguard_home_lightmode.svg @@ -0,0 +1,55 @@ + + + + + + + + + diff --git a/go.mod b/go.mod index 71ca8050..bc090305 100644 --- a/go.mod +++ b/go.mod @@ -7,30 +7,31 @@ require ( github.com/AdguardTeam/golibs v0.10.9 github.com/AdguardTeam/urlfilter v0.16.0 github.com/NYTimes/gziphandler v1.1.1 - github.com/ameshkov/dnscrypt/v2 v2.2.3 + github.com/ameshkov/dnscrypt/v2 v2.2.5 github.com/digineo/go-ipset/v2 v2.2.1 + github.com/dimfeld/httptreemux/v5 v5.4.0 github.com/fsnotify/fsnotify v1.5.4 github.com/go-ping/ping v1.1.0 github.com/google/go-cmp v0.5.8 github.com/google/gopacket v1.1.19 github.com/google/renameio v1.0.1 github.com/google/uuid v1.3.0 - github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f + github.com/insomniacslk/dhcp v0.0.0-20220822114210-de18a9d48e84 github.com/kardianos/service v1.2.1 - github.com/lucas-clemente/quic-go v0.28.1 + github.com/lucas-clemente/quic-go v0.29.0 github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 github.com/mdlayher/netlink v1.6.0 // TODO(a.garipov): This package is deprecated; find a new one or use // our own code for that. Perhaps, use gopacket. github.com/mdlayher/raw v0.1.0 github.com/miekg/dns v1.1.50 - github.com/stretchr/testify v1.7.1 + github.com/stretchr/testify v1.8.0 github.com/ti-mo/netfilter v0.4.0 go.etcd.io/bbolt v1.3.6 - golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 - 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-20220817070843-5a390386f1f2 + golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 + golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 + golang.org/x/net v0.0.0-20220906165146-f3363e06e74c + golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v3 v3.0.1 howett.net/plist v1.0.0 @@ -42,12 +43,10 @@ require ( github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect github.com/ameshkov/dnsstamps v1.0.3 // indirect github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 // indirect - github.com/cheekybits/genny v1.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect + github.com/golang/mock v1.6.0 // indirect github.com/josharian/native v1.0.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/mdlayher/packet v1.0.0 // indirect @@ -57,10 +56,9 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/objx v0.1.1 // indirect github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // indirect golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9 // indirect - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect + golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.12 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect diff --git a/go.sum b/go.sum index 8d5d67f2..a2a4197c 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,12 @@ -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= -dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= -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/dnsproxy v0.44.0 h1:JzIxEXF4OyJq4wZVHeZkM1af4VfuwcgrUzjgdBGljsE= github.com/AdguardTeam/dnsproxy v0.44.0/go.mod h1:HsxYYW/bC8uo+4eX9pRW21hFD6gWZdrvcfBb1R6/AzU= 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/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= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= @@ -28,96 +17,63 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw= github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us= -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/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 h1:0b2vaepXIfMsG++IsjHiI2p4bxALD1Y2nQKGMR5zDQM= github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0/go.mod h1:6YNgTHLutezwnBvyneBbwvB8C82y3dcoOj5EQJIdGXA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -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/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= -github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -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/digineo/go-ipset/v2 v2.2.1 h1:k6skY+0fMqeUjjeWO/m5OuWPSZUAn7AucHMnQ1MX77g= github.com/digineo/go-ipset/v2 v2.2.1/go.mod h1:wBsNzJlZlABHUITkesrggFnZQtgW5wkqw1uo8Qxe0VU= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dimfeld/httptreemux/v5 v5.4.0 h1:IiHYEjh+A7pYbhWyjmGnj5HZK6gpOOvyBXCJ+BE8/Gs= +github.com/dimfeld/httptreemux/v5 v5.4.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw= github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= -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-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-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw= github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk= 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= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -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.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= 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/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/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 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/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/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/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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= -github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f h1:l1QCwn715k8nYkj4Ql50rzEog3WnMdrd4YYMMwemxEo= -github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= -github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/insomniacslk/dhcp v0.0.0-20220822114210-de18a9d48e84 h1:MJTy6H+EpXLeAn0P5WAWeLk6dJA3V0ik6S3VJfUyQuI= +github.com/insomniacslk/dhcp v0.0.0-20220822114210-de18a9d48e84/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk= github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -125,33 +81,19 @@ github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+ github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kardianos/service v1.2.1 h1:AYndMsehS+ywIS6RB9KOlcXzteWUzxgMgBymJD7+BYk= github.com/kardianos/service v1.2.1/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -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/lucas-clemente/quic-go v0.29.0 h1:Vw0mGTfmWqGzh4jx/kMymsIkFK6rErFVmg+t9RLrnZE= +github.com/lucas-clemente/quic-go v0.29.0/go.mod h1:CTcNfLYJS2UuRNB+zcNlgvkjBhxX6Hm3WUxxAQx2mgE= 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/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 h1:2oDp6OOhLxQ9JBoUuysVz9UZ9uI6oLUbvAZu0x8o+vE= github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og= @@ -173,15 +115,9 @@ github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5A github.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E= github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= -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/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= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -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= @@ -189,16 +125,11 @@ 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/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/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -206,51 +137,20 @@ 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_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -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/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -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 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +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/ti-mo/netfilter v0.2.0/go.mod h1:8GbBGsY/8fxtyIdfwy29JiluNcPK4K7wIT+x42ipqUU= github.com/ti-mo/netfilter v0.4.0 h1:rTN1nBYULDmMfDeBHZpKuNKX/bWEXQUhe02a/10orzg= github.com/ti-mo/netfilter v0.4.0/go.mod h1:V54q75mUx8CNA2JnFl+wv9iZ5+JP9nCcRlaFS5OZSRM= @@ -261,57 +161,34 @@ github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcy github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 h1:hl6sK6aFgTLISijk6xIzeqnPzQcsLqqvL6vEfTPinME= github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= -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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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= -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-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-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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -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/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/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +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/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 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.20220818022119-ed83ed61efb9 h1:VtCrPQXM5Wo9l7XN64SjBMczl48j8mkP+2e3OhYlz+0= golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -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-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-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/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-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -319,34 +196,21 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 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-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/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-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/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/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 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= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-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-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -355,15 +219,11 @@ golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -387,29 +247,19 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/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-20220817070843-5a390386f1f2 h1:fqTvyMIIj+HRzMmnzr9NtpHP6uVpvB5fkHcgPDC4nu8= -golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/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/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.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 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/time v0.0.0-20181108054448-85acf8d2951c/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-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/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-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -420,57 +270,29 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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/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/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/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/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 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.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= -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.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= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= -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/aghalg/aghalg.go b/internal/aghalg/aghalg.go index f0b71a09..b554a917 100644 --- a/internal/aghalg/aghalg.go +++ b/internal/aghalg/aghalg.go @@ -10,9 +10,14 @@ import ( "golang.org/x/exp/slices" ) -// Coalesce returns the first non-zero value. It is named after the function +// Coalesce returns the first non-zero value. It is named after function // COALESCE in SQL. If values or all its elements are empty, it returns a zero // value. +// +// T is comparable, because Go currently doesn't have a comparableWithZeroValue +// constraint. +// +// TODO(a.garipov): Think of ways to merge with [CoalesceSlice]. func Coalesce[T comparable](values ...T) (res T) { var zero T for _, v := range values { @@ -24,6 +29,20 @@ func Coalesce[T comparable](values ...T) (res T) { return zero } +// CoalesceSlice returns the first non-zero value. It is named after function +// COALESCE in SQL. If values or all its elements are empty, it returns nil. +// +// TODO(a.garipov): Think of ways to merge with [Coalesce]. +func CoalesceSlice[E any, S []E](values ...S) (res S) { + for _, v := range values { + if v != nil { + return v + } + } + + return nil +} + // UniqChecker allows validating uniqueness of comparable items. // // TODO(a.garipov): The Ordered constraint is only really necessary in Validate. diff --git a/internal/aghnet/arpdb_bsd.go b/internal/aghnet/arpdb_bsd.go index 26ac7758..317579de 100644 --- a/internal/aghnet/arpdb_bsd.go +++ b/internal/aghnet/arpdb_bsd.go @@ -33,8 +33,7 @@ func newARPDB() (arp *cmdARPDB) { // parseArpA parses the output of the "arp -a -n" command on macOS and FreeBSD. // The expected input format: // -// host.name (192.168.0.1) at ff:ff:ff:ff:ff:ff on en0 ifscope [ethernet] -// +// host.name (192.168.0.1) at ff:ff:ff:ff:ff:ff on en0 ifscope [ethernet] func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { ns = make([]Neighbor, 0, lenHint) for sc.Scan() { diff --git a/internal/aghnet/arpdb_linux.go b/internal/aghnet/arpdb_linux.go index 9cc38906..e8b34a2f 100644 --- a/internal/aghnet/arpdb_linux.go +++ b/internal/aghnet/arpdb_linux.go @@ -117,9 +117,8 @@ func (arp *fsysARPDB) Neighbors() (ns []Neighbor) { // parseArpAWrt parses the output of the "arp -a -n" command on OpenWrt. The // expected input format: // -// IP address HW type Flags HW address Mask Device -// 192.168.11.98 0x1 0x2 5a:92:df:a9:7e:28 * wan -// +// IP address HW type Flags HW address Mask Device +// 192.168.11.98 0x1 0x2 5a:92:df:a9:7e:28 * wan func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { if !sc.Scan() { // Skip the header. @@ -161,8 +160,7 @@ func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { // parseArpA parses the output of the "arp -a -n" command on Linux. The // expected input format: // -// hostname (192.168.1.1) at ab:cd:ef:ab:cd:ef [ether] on enp0s3 -// +// hostname (192.168.1.1) at ab:cd:ef:ab:cd:ef [ether] on enp0s3 func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { ns = make([]Neighbor, 0, lenHint) for sc.Scan() { @@ -208,8 +206,7 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { // parseIPNeigh parses the output of the "ip neigh" command on Linux. The // expected input format: // -// 192.168.1.1 dev enp0s3 lladdr ab:cd:ef:ab:cd:ef REACHABLE -// +// 192.168.1.1 dev enp0s3 lladdr ab:cd:ef:ab:cd:ef REACHABLE func parseIPNeigh(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { ns = make([]Neighbor, 0, lenHint) for sc.Scan() { diff --git a/internal/aghnet/arpdb_openbsd.go b/internal/aghnet/arpdb_openbsd.go index d5ec5fea..e1626c0b 100644 --- a/internal/aghnet/arpdb_openbsd.go +++ b/internal/aghnet/arpdb_openbsd.go @@ -32,9 +32,8 @@ func newARPDB() (arp *cmdARPDB) { // parseArpA parses the output of the "arp -a -n" command on OpenBSD. The // expected input format: // -// Host Ethernet Address Netif Expire Flags -// 192.168.1.1 ab:cd:ef:ab:cd:ef em0 19m59s -// +// Host Ethernet Address Netif Expire Flags +// 192.168.1.1 ab:cd:ef:ab:cd:ef em0 19m59s func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { // Skip the header. if !sc.Scan() { diff --git a/internal/aghnet/arpdb_windows.go b/internal/aghnet/arpdb_windows.go index 8d5431eb..e81f6818 100644 --- a/internal/aghnet/arpdb_windows.go +++ b/internal/aghnet/arpdb_windows.go @@ -25,12 +25,10 @@ func newARPDB() (arp *cmdARPDB) { // parseArpA parses the output of the "arp /a" command on Windows. The expected // input format (the first line is empty): // -// -// Interface: 192.168.56.16 --- 0x7 -// Internet Address Physical Address Type -// 192.168.56.1 0a-00-27-00-00-00 dynamic -// 192.168.56.255 ff-ff-ff-ff-ff-ff static -// +// Interface: 192.168.56.16 --- 0x7 +// Internet Address Physical Address Type +// 192.168.56.1 0a-00-27-00-00-00 dynamic +// 192.168.56.255 ff-ff-ff-ff-ff-ff static func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { ns = make([]Neighbor, 0, lenHint) for sc.Scan() { diff --git a/internal/aghnet/hostgen.go b/internal/aghnet/hostgen.go index 683c8d9f..f19001cd 100644 --- a/internal/aghnet/hostgen.go +++ b/internal/aghnet/hostgen.go @@ -45,11 +45,11 @@ func generateIPv6Hostname(ipv6 net.IP) (hostname string) { // GenerateHostname generates the hostname from ip. In case of using IPv4 the // result should be like: // -// 192-168-10-1 +// 192-168-10-1 // // In case of using IPv6, the result is like: // -// ff80-f076-0000-0000-0000-0000-0000-0010 +// ff80-f076-0000-0000-0000-0000-0000-0010 // // ip must be either an IPv4 or an IPv6. func GenerateHostname(ip net.IP) (hostname string) { diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index ee345905..5d750945 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -70,8 +70,7 @@ func (rm *requestMatcher) MatchRequest( // rule or an empty string if the last doesn't exist. The returned rules are in // a processed format like: // -// ip host1 host2 ... -// +// ip host1 host2 ... func (rm *requestMatcher) Translate(rule string) (hostRule string) { rm.stateLock.RLock() defer rm.stateLock.RUnlock() diff --git a/internal/aghnet/ipset.go b/internal/aghnet/ipset.go index 88a3f2b7..03e8a758 100644 --- a/internal/aghnet/ipset.go +++ b/internal/aghnet/ipset.go @@ -18,7 +18,7 @@ type IpsetManager interface { // // The syntax of the ipsetConf is: // -// DOMAIN[,DOMAIN].../IPSET_NAME[,IPSET_NAME]... +// DOMAIN[,DOMAIN].../IPSET_NAME[,IPSET_NAME]... // // If ipsetConf is empty, msg and err are nil. The error is of type // *aghos.UnsupportedError if the OS is not supported. diff --git a/internal/aghnet/systemresolvers_windows.go b/internal/aghnet/systemresolvers_windows.go index f82d6e7e..2e8ed3df 100644 --- a/internal/aghnet/systemresolvers_windows.go +++ b/internal/aghnet/systemresolvers_windows.go @@ -62,9 +62,8 @@ func writeExit(w io.WriteCloser) { // scanAddrs scans the DNS addresses from nslookup's output. The expected // output of nslookup looks like this: // -// Default Server: 192-168-1-1.qualified.domain.ru -// Address: 192.168.1.1 -// +// Default Server: 192-168-1-1.qualified.domain.ru +// Address: 192.168.1.1 func scanAddrs(s *bufio.Scanner) (addrs []string) { for s.Scan() { line := strings.TrimSpace(s.Text()) diff --git a/internal/aghos/os.go b/internal/aghos/os.go index 3b688749..b39ecbbd 100644 --- a/internal/aghos/os.go +++ b/internal/aghos/os.go @@ -121,13 +121,12 @@ func PIDByCommand(command string, except ...int) (pid int, err error) { } // parsePSOutput scans the output of ps searching the largest PID of the process -// associated with cmdName ignoring PIDs from ignore. A valid line from -// r should look like these: -// -// 123 ./example-cmd -// 1230 some/base/path/example-cmd -// 3210 example-cmd +// associated with cmdName ignoring PIDs from ignore. A valid line from r +// should look like these: // +// 123 ./example-cmd +// 1230 some/base/path/example-cmd +// 3210 example-cmd func parsePSOutput(r io.Reader, cmdName string, ignore []int) (largest, instNum int, err error) { s := bufio.NewScanner(r) for s.Scan() { diff --git a/internal/dhcpd/conn_unix.go b/internal/dhcpd/conn_unix.go index 1ed2105a..01c063d1 100644 --- a/internal/dhcpd/conn_unix.go +++ b/internal/dhcpd/conn_unix.go @@ -83,7 +83,7 @@ func (s *v4Server) newDHCPConn(iface *net.Interface) (c net.PacketConn, err erro // wrapErrs is a helper to wrap the errors from two independent underlying // connections. -func (c *dhcpConn) wrapErrs(action string, udpConnErr, rawConnErr error) (err error) { +func (*dhcpConn) wrapErrs(action string, udpConnErr, rawConnErr error) (err error) { switch { case udpConnErr != nil && rawConnErr != nil: return errors.List(fmt.Sprintf("%s both connections", action), udpConnErr, rawConnErr) @@ -129,7 +129,7 @@ func (c *dhcpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { // connection. return c.udpConn.WriteTo(p, addr) default: - return 0, fmt.Errorf("peer is of unexpected type %T", addr) + return 0, fmt.Errorf("addr has an unexpected type %T", addr) } } @@ -188,32 +188,20 @@ func (c *dhcpConn) SetWriteDeadline(t time.Time) error { ) } -// ipv4DefaultTTL is the default Time to Live value as recommended by -// RFC-1700 (https://datatracker.ietf.org/doc/html/rfc1700) in seconds. +// ipv4DefaultTTL is the default Time to Live value in seconds as recommended by +// RFC-1700. +// +// See https://datatracker.ietf.org/doc/html/rfc1700. const ipv4DefaultTTL = 64 -// errInvalidPktDHCP is returned when the provided payload is not a valid DHCP -// packet. -const errInvalidPktDHCP errors.Error = "packet is not a valid dhcp packet" - -// buildEtherPkt wraps the payload with IPv4, UDP and Ethernet frames. The -// payload is expected to be an encoded DHCP packet. +// buildEtherPkt wraps the payload with IPv4, UDP and Ethernet frames. +// Validation of the payload is a caller's responsibility. func (c *dhcpConn) buildEtherPkt(payload []byte, peer *dhcpUnicastAddr) (pkt []byte, err error) { - dhcpLayer := gopacket.NewPacket(payload, layers.LayerTypeDHCPv4, gopacket.DecodeOptions{ - NoCopy: true, - }).Layer(layers.LayerTypeDHCPv4) - - // Check if the decoding succeeded and the resulting layer doesn't - // contain any errors. It should guarantee panic-safe converting of the - // layer into gopacket.SerializableLayer. - if dhcpLayer == nil || dhcpLayer.LayerType() != layers.LayerTypeDHCPv4 { - return nil, errInvalidPktDHCP - } - udpLayer := &layers.UDP{ SrcPort: dhcpv4.ServerPort, DstPort: dhcpv4.ClientPort, } + ipv4Layer := &layers.IPv4{ Version: uint8(layers.IPProtocolIPv4), Flags: layers.IPv4DontFragment, @@ -226,6 +214,7 @@ func (c *dhcpConn) buildEtherPkt(payload []byte, peer *dhcpUnicastAddr) (pkt []b // Ignore the error since it's only returned for invalid network layer's // type. _ = udpLayer.SetNetworkLayerForChecksum(ipv4Layer) + ethLayer := &layers.Ethernet{ SrcMAC: c.srcMAC, DstMAC: peer.HardwareAddr, @@ -233,10 +222,19 @@ func (c *dhcpConn) buildEtherPkt(payload []byte, peer *dhcpUnicastAddr) (pkt []b } buf := gopacket.NewSerializeBuffer() - err = gopacket.SerializeLayers(buf, gopacket.SerializeOptions{ + setts := gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true, - }, ethLayer, ipv4Layer, udpLayer, dhcpLayer.(gopacket.SerializableLayer)) + } + + err = gopacket.SerializeLayers( + buf, + setts, + ethLayer, + ipv4Layer, + udpLayer, + gopacket.Payload(payload), + ) if err != nil { return nil, fmt.Errorf("serializing layers: %w", err) } diff --git a/internal/dhcpd/conn_unix_test.go b/internal/dhcpd/conn_unix_test.go index 84020acd..0fdbfec0 100644 --- a/internal/dhcpd/conn_unix_test.go +++ b/internal/dhcpd/conn_unix_test.go @@ -47,7 +47,7 @@ func TestDHCPConn_WriteTo_common(t *testing.T) { n, err := conn.WriteTo(nil, &unexpectedAddrType{}) require.Error(t, err) - testutil.AssertErrorMsg(t, "peer is of unexpected type *dhcpd.unexpectedAddrType", err) + testutil.AssertErrorMsg(t, "addr has an unexpected type *dhcpd.unexpectedAddrType", err) assert.Zero(t, n) }) } @@ -91,14 +91,13 @@ func TestBuildEtherPkt(t *testing.T) { } }) - t.Run("non-serializable", func(t *testing.T) { + t.Run("bad_payload", func(t *testing.T) { // Create an invalid DHCP packet. invalidPayload := []byte{1, 2, 3, 4} - pkt, err := conn.buildEtherPkt(invalidPayload, nil) - require.Error(t, err) + pkt, err := conn.buildEtherPkt(invalidPayload, peer) + require.NoError(t, err) - assert.ErrorIs(t, err, errInvalidPktDHCP) - assert.Empty(t, pkt) + assert.NotEmpty(t, pkt) }) t.Run("serializing_error", func(t *testing.T) { diff --git a/internal/dhcpd/options_unix.go b/internal/dhcpd/options_unix.go index 4e15ccce..dc06c429 100644 --- a/internal/dhcpd/options_unix.go +++ b/internal/dhcpd/options_unix.go @@ -9,26 +9,31 @@ import ( "net" "strconv" "strings" + "time" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/netutil" + "github.com/AdguardTeam/golibs/timeutil" "github.com/insomniacslk/dhcp/dhcpv4" ) // The aliases for DHCP option types available for explicit declaration. +// +// TODO(e.burkov): Add an option for classless routes. const ( - hexTyp = "hex" - ipTyp = "ip" - ipsTyp = "ips" - textTyp = "text" + typDel = "del" + typBool = "bool" + typDur = "dur" + typHex = "hex" + typIP = "ip" + typIPs = "ips" + typText = "text" + typU8 = "u8" + typU16 = "u16" ) -// parseDHCPOptionHex parses a DHCP option as a hex-encoded string. For -// example: -// -// 252 hex 736f636b733a2f2f70726f78792e6578616d706c652e6f7267 -// +// parseDHCPOptionHex parses a DHCP option as a hex-encoded string. func parseDHCPOptionHex(s string) (val dhcpv4.OptionValue, err error) { var data []byte data, err = hex.DecodeString(s) @@ -39,15 +44,12 @@ func parseDHCPOptionHex(s string) (val dhcpv4.OptionValue, err error) { return dhcpv4.OptionGeneric{Data: data}, nil } -// parseDHCPOptionIP parses a DHCP option as a single IP address. For example: -// -// 6 ip 192.168.1.1 -// +// parseDHCPOptionIP parses a DHCP option as a single IP address. func parseDHCPOptionIP(s string) (val dhcpv4.OptionValue, err error) { var ip net.IP // All DHCPv4 options require IPv4, so don't put the 16-byte version. - // Otherwise, the clients will receive weird data that looks like four - // IPv4 addresses. + // Otherwise, the clients will receive weird data that looks like four IPv4 + // addresses. // // See https://github.com/AdguardTeam/AdGuardHome/issues/2688. if ip, err = netutil.ParseIPv4(s); err != nil { @@ -58,133 +60,348 @@ func parseDHCPOptionIP(s string) (val dhcpv4.OptionValue, err error) { } // parseDHCPOptionIPs parses a DHCP option as a comma-separates list of IP -// addresses. For example: -// -// 6 ips 192.168.1.1,192.168.1.2 -// +// addresses. func parseDHCPOptionIPs(s string) (val dhcpv4.OptionValue, err error) { var ips dhcpv4.IPs - var ip net.IP + var ip dhcpv4.OptionValue for i, ipStr := range strings.Split(s, ",") { - // See notes in the ipDHCPOptionParserHandler. - if ip, err = netutil.ParseIPv4(ipStr); err != nil { + ip, err = parseDHCPOptionIP(ipStr) + if err != nil { return nil, fmt.Errorf("parsing ip at index %d: %w", i, err) } - ips = append(ips, ip) + ips = append(ips, net.IP(ip.(dhcpv4.IP))) } return ips, nil } -// parseDHCPOptionText parses a DHCP option as a simple UTF-8 encoded -// text. For example: -// -// 252 text http://192.168.1.1/wpad.dat -// -func parseDHCPOptionText(s string) (val dhcpv4.OptionValue) { - return dhcpv4.OptionGeneric{Data: []byte(s)} +// parseDHCPOptionDur parses a DHCP option as a duration in a human-readable +// form. +func parseDHCPOptionDur(s string) (val dhcpv4.OptionValue, err error) { + var v timeutil.Duration + err = v.UnmarshalText([]byte(s)) + if err != nil { + return nil, fmt.Errorf("decoding dur: %w", err) + } + + return dhcpv4.Duration(v.Duration), nil } -// parseDHCPOption parses an option. See the documentation of parseDHCPOption* -// for more info. -func parseDHCPOption(s string) (opt dhcpv4.Option, err error) { +// parseDHCPOptionUint parses a DHCP option as an unsigned integer. bitSize is +// expected to be 8 or 16. +func parseDHCPOptionUint(s string, bitSize int) (val dhcpv4.OptionValue, err error) { + var v uint64 + v, err = strconv.ParseUint(s, 10, bitSize) + if err != nil { + return nil, fmt.Errorf("decoding u%d: %w", bitSize, err) + } + + switch bitSize { + case 8: + return dhcpv4.OptionGeneric{Data: []byte{uint8(v)}}, nil + case 16: + return dhcpv4.Uint16(v), nil + default: + return nil, fmt.Errorf("unsupported size of integer %d", bitSize) + } +} + +// parseDHCPOptionBool parses a DHCP option as a boolean value. See +// [strconv.ParseBool] for available values. +func parseDHCPOptionBool(s string) (val dhcpv4.OptionValue, err error) { + var v bool + v, err = strconv.ParseBool(s) + if err != nil { + return nil, fmt.Errorf("decoding bool: %w", err) + } + + rawVal := [1]byte{} + if v { + rawVal[0] = 1 + } + + return dhcpv4.OptionGeneric{Data: rawVal[:]}, nil +} + +// parseDHCPOptionVal parses a DHCP option value considering typ. +func parseDHCPOptionVal(typ, valStr string) (val dhcpv4.OptionValue, err error) { + switch typ { + case typBool: + val, err = parseDHCPOptionBool(valStr) + case typDel: + val = dhcpv4.OptionGeneric{Data: nil} + case typDur: + val, err = parseDHCPOptionDur(valStr) + case typHex: + val, err = parseDHCPOptionHex(valStr) + case typIP: + val, err = parseDHCPOptionIP(valStr) + case typIPs: + val, err = parseDHCPOptionIPs(valStr) + case typText: + val = dhcpv4.String(valStr) + case typU8: + val, err = parseDHCPOptionUint(valStr, 8) + case typU16: + val, err = parseDHCPOptionUint(valStr, 16) + default: + err = fmt.Errorf("unknown option type %q", typ) + } + + return val, err +} + +// parseDHCPOption parses an option. For the del option value is ignored. The +// examples of possible option strings: +// +// - 1 bool true +// - 2 del +// - 3 dur 2h5s +// - 4 hex 736f636b733a2f2f70726f78792e6578616d706c652e6f7267 +// - 5 ip 192.168.1.1 +// - 6 ips 192.168.1.1,192.168.1.2 +// - 7 text http://192.168.1.1/wpad.dat +// - 8 u8 255 +// - 9 u16 65535 +func parseDHCPOption(s string) (code dhcpv4.OptionCode, val dhcpv4.OptionValue, err error) { defer func() { err = errors.Annotate(err, "invalid option string %q: %w", s) }() s = strings.TrimSpace(s) parts := strings.SplitN(s, " ", 3) - if len(parts) < 3 { - return opt, errors.Error("need at least three fields") + + var valStr string + if pl := len(parts); pl < 3 { + if pl < 2 || parts[1] != typDel { + return nil, nil, errors.Error("bad option format") + } + } else { + valStr = parts[2] } var code64 uint64 code64, err = strconv.ParseUint(parts[0], 10, 8) if err != nil { - return opt, fmt.Errorf("parsing option code: %w", err) - } - - var optVal dhcpv4.OptionValue - switch typ, val := parts[1], parts[2]; typ { - case hexTyp: - optVal, err = parseDHCPOptionHex(val) - case ipTyp: - optVal, err = parseDHCPOptionIP(val) - case ipsTyp: - optVal, err = parseDHCPOptionIPs(val) - case textTyp: - optVal = parseDHCPOptionText(val) - default: - return opt, fmt.Errorf("unknown option type %q", typ) + return nil, nil, fmt.Errorf("parsing option code: %w", err) } + val, err = parseDHCPOptionVal(parts[1], valStr) if err != nil { - return opt, err + // Don't wrap an error since it's informative enough as is and there + // also the deferred annotation. + return nil, nil, err } - return dhcpv4.Option{ - Code: dhcpv4.GenericOptionCode(code64), - Value: optVal, - }, nil + return dhcpv4.GenericOptionCode(code64), val, nil } // prepareOptions builds the set of DHCP options according to host requirements // document and values from conf. -func prepareOptions(conf V4ServerConf) (opts dhcpv4.Options) { - // Set default values for host configuration parameters listed in Appendix - // A of RFC-2131. Those parameters, if requested by client, should be - // returned with values defined by Host Requirements Document. - // - // See https://datatracker.ietf.org/doc/html/rfc2131#appendix-A. - // - // See also https://datatracker.ietf.org/doc/html/rfc1122, - // https://datatracker.ietf.org/doc/html/rfc1123, and - // https://datatracker.ietf.org/doc/html/rfc2132. - opts = dhcpv4.Options{ +func prepareOptions(conf V4ServerConf) (implicit, explicit dhcpv4.Options) { + // Set default values of host configuration parameters listed in Appendix A + // of RFC-2131. + implicit = dhcpv4.OptionsFromList( // IP-Layer Per Host - dhcpv4.OptionNonLocalSourceRouting.Code(): []byte{0}, - // Set the current recommended default time to live for the - // Internet Protocol which is 64, see - // https://datatracker.ietf.org/doc/html/rfc1700. - dhcpv4.OptionDefaultIPTTL.Code(): []byte{64}, + // An Internet host that includes embedded gateway code MUST have a + // configuration switch to disable the gateway function, and this switch + // MUST default to the non-gateway mode. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-3.3.5. + dhcpv4.OptGeneric(dhcpv4.OptionIPForwarding, []byte{0x0}), + + // A host that supports non-local source-routing MUST have a + // configurable switch to disable forwarding, and this switch MUST + // default to disabled. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-3.3.5. + dhcpv4.OptGeneric(dhcpv4.OptionNonLocalSourceRouting, []byte{0x0}), + + // Do not set the Policy Filter Option since it only makes sense when + // the non-local source routing is enabled. + + // The minimum legal value is 576. + // + // See https://datatracker.ietf.org/doc/html/rfc2132#section-4.4. + dhcpv4.Option{ + Code: dhcpv4.OptionMaximumDatagramAssemblySize, + Value: dhcpv4.Uint16(576), + }, + + // Set the current recommended default time to live for the Internet + // Protocol which is 64. + // + // See https://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml#ip-parameters-2. + dhcpv4.OptGeneric(dhcpv4.OptionDefaultIPTTL, []byte{0x40}), + + // For example, after the PTMU estimate is decreased, the timeout should + // be set to 10 minutes; once this timer expires and a larger MTU is + // attempted, the timeout can be set to a much smaller value. + // + // See https://datatracker.ietf.org/doc/html/rfc1191#section-6.6. + dhcpv4.Option{ + Code: dhcpv4.OptionPathMTUAgingTimeout, + Value: dhcpv4.Duration(10 * time.Minute), + }, + + // There is a table describing the MTU values representing all major + // data-link technologies in use in the Internet so that each set of + // similar MTUs is associated with a plateau value equal to the lowest + // MTU in the group. + // + // See https://datatracker.ietf.org/doc/html/rfc1191#section-7. + dhcpv4.OptGeneric(dhcpv4.OptionPathMTUPlateauTable, []byte{ + 0x0, 0x44, + 0x1, 0x28, + 0x1, 0xFC, + 0x3, 0xEE, + 0x5, 0xD4, + 0x7, 0xD2, + 0x11, 0x0, + 0x1F, 0xE6, + 0x45, 0xFA, + }), // IP-Layer Per Interface - dhcpv4.OptionPerformMaskDiscovery.Code(): []byte{0}, - dhcpv4.OptionMaskSupplier.Code(): []byte{0}, - dhcpv4.OptionPerformRouterDiscovery.Code(): []byte{1}, - // The all-routers address is preferred wherever possible, see - // https://datatracker.ietf.org/doc/html/rfc1256#section-5.1. - dhcpv4.OptionRouterSolicitationAddress.Code(): netutil.IPv4allrouter(), - dhcpv4.OptionBroadcastAddress.Code(): netutil.IPv4bcast(), + // Since nearly all networks in the Internet currently support an MTU of + // 576 or greater, we strongly recommend the use of 576 for datagrams + // sent to non-local networks. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-3.3.3. + dhcpv4.Option{ + Code: dhcpv4.OptionInterfaceMTU, + Value: dhcpv4.Uint16(576), + }, + + // Set the All Subnets Are Local Option to false since commonly the + // connected hosts aren't expected to be multihomed. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-3.3.3. + dhcpv4.OptGeneric(dhcpv4.OptionAllSubnetsAreLocal, []byte{0x00}), + + // Set the Perform Mask Discovery Option to false to provide the subnet + // mask by options only. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.2.9. + dhcpv4.OptGeneric(dhcpv4.OptionPerformMaskDiscovery, []byte{0x00}), + + // A system MUST NOT send an Address Mask Reply unless it is an + // authoritative agent for address masks. An authoritative agent may be + // a host or a gateway, but it MUST be explicitly configured as a + // address mask agent. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.2.9. + dhcpv4.OptGeneric(dhcpv4.OptionMaskSupplier, []byte{0x00}), + + // Set the Perform Router Discovery Option to true as per Router + // Discovery Document. + // + // See https://datatracker.ietf.org/doc/html/rfc1256#section-5.1. + dhcpv4.OptGeneric(dhcpv4.OptionPerformRouterDiscovery, []byte{0x01}), + + // The all-routers address is preferred wherever possible. + // + // See https://datatracker.ietf.org/doc/html/rfc1256#section-5.1. + dhcpv4.Option{ + Code: dhcpv4.OptionRouterSolicitationAddress, + Value: dhcpv4.IP(netutil.IPv4allrouter()), + }, + + // Don't set the Static Routes Option since it should be set up by + // system administrator. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-3.3.1.2. + + // A datagram with the destination address of limited broadcast will be + // received by every host on the connected physical network but will not + // be forwarded outside that network. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.1.3. + dhcpv4.OptBroadcastAddress(netutil.IPv4bcast()), // Link-Layer Per Interface - dhcpv4.OptionTrailerEncapsulation.Code(): []byte{0}, - dhcpv4.OptionEthernetEncapsulation.Code(): []byte{0}, + // If the system does not dynamically negotiate use of the trailer + // protocol on a per-destination basis, the default configuration MUST + // disable the protocol. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-2.3.1. + dhcpv4.OptGeneric(dhcpv4.OptionTrailerEncapsulation, []byte{0x00}), + + // For proxy ARP situations, the timeout needs to be on the order of a + // minute. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-2.3.2.1. + dhcpv4.Option{ + Code: dhcpv4.OptionArpCacheTimeout, + Value: dhcpv4.Duration(time.Minute), + }, + + // An Internet host that implements sending both the RFC-894 and the + // RFC-1042 encapsulations MUST provide a configuration switch to select + // which is sent, and this switch MUST default to RFC-894. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-2.3.3. + dhcpv4.OptGeneric(dhcpv4.OptionEthernetEncapsulation, []byte{0x00}), // TCP Per Host - dhcpv4.OptionTCPKeepaliveInterval.Code(): dhcpv4.Duration(0).ToBytes(), - dhcpv4.OptionTCPKeepaliveGarbage.Code(): []byte{0}, + // A fixed value must be at least big enough for the Internet diameter, + // i.e., the longest possible path. A reasonable value is about twice + // the diameter, to allow for continued Internet growth. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.1.7. + dhcpv4.Option{ + Code: dhcpv4.OptionDefaulTCPTTL, + Value: dhcpv4.Duration(60 * time.Second), + }, + + // The interval MUST be configurable and MUST default to no less than + // two hours. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-4.2.3.6. + dhcpv4.Option{ + Code: dhcpv4.OptionTCPKeepaliveInterval, + Value: dhcpv4.Duration(2 * time.Hour), + }, + + // Unfortunately, some misbehaved TCP implementations fail to respond to + // a probe segment unless it contains data. + // + // See https://datatracker.ietf.org/doc/html/rfc1122#section-4.2.3.6. + dhcpv4.OptGeneric(dhcpv4.OptionTCPKeepaliveGarbage, []byte{0x01}), // Values From Configuration - dhcpv4.OptionRouter.Code(): netutil.CloneIP(conf.subnet.IP), - dhcpv4.OptionSubnetMask.Code(): dhcpv4.IPMask(conf.subnet.Mask).ToBytes(), - } + // Set the Router Option to working subnet's IP since it's initialized + // with the address of the gateway. + dhcpv4.OptRouter(conf.subnet.IP), + + dhcpv4.OptSubnetMask(conf.subnet.Mask), + ) // Set values for explicitly configured options. + explicit = dhcpv4.Options{} for i, o := range conf.Options { - opt, err := parseDHCPOption(o) + code, val, err := parseDHCPOption(o) if err != nil { log.Error("dhcpv4: bad option string at index %d: %s", i, err) continue } - opts.Update(opt) + explicit.Update(dhcpv4.Option{Code: code, Value: val}) + // Remove those from the implicit options. + delete(implicit, code.Code()) } - return opts + log.Debug("dhcpv4: implicit options:\n%s", implicit.Summary(nil)) + log.Debug("dhcpv4: explicit options:\n%s", explicit.Summary(nil)) + + if len(explicit) == 0 { + explicit = nil + } + + return implicit, explicit } diff --git a/internal/dhcpd/options_unix_test.go b/internal/dhcpd/options_unix_test.go index 6b229f44..e901284c 100644 --- a/internal/dhcpd/options_unix_test.go +++ b/internal/dhcpd/options_unix_test.go @@ -7,171 +7,260 @@ import ( "fmt" "net" "testing" + "time" + "github.com/AdguardTeam/golibs/netutil" + "github.com/AdguardTeam/golibs/testutil" "github.com/insomniacslk/dhcp/dhcpv4" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestParseOpt(t *testing.T) { testCases := []struct { name string in string + wantCode dhcpv4.OptionCode + wantVal dhcpv4.OptionValue wantErrMsg string - wantOpt dhcpv4.Option }{{ - name: "hex_success", - in: "6 hex c0a80101c0a80102", + name: "hex_success", + in: "6 hex c0a80101c0a80102", + wantCode: dhcpv4.GenericOptionCode(6), + wantVal: dhcpv4.OptionGeneric{Data: []byte{ + 0xC0, 0xA8, 0x01, 0x01, + 0xC0, 0xA8, 0x01, 0x02, + }}, wantErrMsg: "", - wantOpt: dhcpv4.OptDNS( - net.IP{0xC0, 0xA8, 0x01, 0x01}, - net.IP{0xC0, 0xA8, 0x01, 0x02}, - ), }, { name: "ip_success", in: "6 ip 1.2.3.4", + wantCode: dhcpv4.GenericOptionCode(6), + wantVal: dhcpv4.IP(net.IP{0x01, 0x02, 0x03, 0x04}), wantErrMsg: "", - wantOpt: dhcpv4.OptDNS( - net.IP{0x01, 0x02, 0x03, 0x04}, - ), }, { - name: "ip_fail_v6", - in: "6 ip ::1234", - wantErrMsg: "invalid option string \"6 ip ::1234\": bad ipv4 address \"::1234\"", - wantOpt: dhcpv4.Option{}, - }, { - name: "ips_success", - in: "6 ips 192.168.1.1,192.168.1.2", + name: "ips_success", + in: "6 ips 192.168.1.1,192.168.1.2", + wantCode: dhcpv4.GenericOptionCode(6), + wantVal: dhcpv4.IPs([]net.IP{ + {0xC0, 0xA8, 0x01, 0x01}, + {0xC0, 0xA8, 0x01, 0x02}, + }), wantErrMsg: "", - wantOpt: dhcpv4.OptDNS( - net.IP{0xC0, 0xA8, 0x01, 0x01}, - net.IP{0xC0, 0xA8, 0x01, 0x02}, - ), }, { name: "text_success", in: "252 text http://192.168.1.1/", + wantCode: dhcpv4.GenericOptionCode(252), + wantVal: dhcpv4.String("http://192.168.1.1/"), + wantErrMsg: "", + }, { + name: "del_success", + in: "61 del", + wantCode: dhcpv4.GenericOptionCode(dhcpv4.OptionClientIdentifier), + wantVal: dhcpv4.OptionGeneric{Data: nil}, + wantErrMsg: "", + }, { + name: "bool_success", + in: "19 bool true", + wantCode: dhcpv4.GenericOptionCode(dhcpv4.OptionIPForwarding), + wantVal: dhcpv4.OptionGeneric{Data: []byte{0x01}}, + wantErrMsg: "", + }, { + name: "bool_success_false", + in: "19 bool F", + wantCode: dhcpv4.GenericOptionCode(dhcpv4.OptionIPForwarding), + wantVal: dhcpv4.OptionGeneric{Data: []byte{0x00}}, + wantErrMsg: "", + }, { + name: "dur_success", + in: "24 dur 2h5s", + wantCode: dhcpv4.GenericOptionCode(dhcpv4.OptionPathMTUAgingTimeout), + wantVal: dhcpv4.Duration(2*time.Hour + 5*time.Second), + wantErrMsg: "", + }, { + name: "u8_success", + in: "23 u8 64", + wantCode: dhcpv4.GenericOptionCode(dhcpv4.OptionDefaultIPTTL), + wantVal: dhcpv4.OptionGeneric{Data: []byte{0x40}}, + wantErrMsg: "", + }, { + name: "u16_success", + in: "22 u16 1234", + wantCode: dhcpv4.GenericOptionCode(dhcpv4.OptionMaximumDatagramAssemblySize), + wantVal: dhcpv4.Uint16(1234), wantErrMsg: "", - wantOpt: dhcpv4.OptGeneric( - dhcpv4.GenericOptionCode(252), - []byte("http://192.168.1.1/"), - ), }, { name: "bad_parts", in: "6 ip", - wantErrMsg: `invalid option string "6 ip": need at least three fields`, - wantOpt: dhcpv4.Option{}, + wantCode: nil, + wantVal: nil, + wantErrMsg: `invalid option string "6 ip": bad option format`, }, { - name: "bad_code", - in: "256 ip 1.1.1.1", + name: "bad_code", + in: "256 ip 1.1.1.1", + wantCode: nil, + wantVal: nil, wantErrMsg: `invalid option string "256 ip 1.1.1.1": parsing option code: ` + `strconv.ParseUint: parsing "256": value out of range`, - wantOpt: dhcpv4.Option{}, }, { name: "bad_type", in: "6 bad 1.1.1.1", + wantCode: nil, + wantVal: nil, wantErrMsg: `invalid option string "6 bad 1.1.1.1": unknown option type "bad"`, - wantOpt: dhcpv4.Option{}, }, { - name: "hex_error", - in: "6 hex ZZZ", + name: "hex_error", + in: "6 hex ZZZ", + wantCode: nil, + wantVal: nil, wantErrMsg: `invalid option string "6 hex ZZZ": decoding hex: ` + `encoding/hex: invalid byte: U+005A 'Z'`, - wantOpt: dhcpv4.Option{}, }, { name: "ip_error", in: "6 ip 1.2.3.x", + wantCode: nil, + wantVal: nil, wantErrMsg: "invalid option string \"6 ip 1.2.3.x\": bad ipv4 address \"1.2.3.x\"", - wantOpt: dhcpv4.Option{}, }, { - name: "ips_error", - in: "6 ips 192.168.1.1,192.168.1.x", + name: "ip_error_v6", + in: "6 ip ::1234", + wantCode: nil, + wantVal: nil, + wantErrMsg: "invalid option string \"6 ip ::1234\": bad ipv4 address \"::1234\"", + }, { + name: "ips_error", + in: "6 ips 192.168.1.1,192.168.1.x", + wantCode: nil, + wantVal: nil, wantErrMsg: "invalid option string \"6 ips 192.168.1.1,192.168.1.x\": " + "parsing ip at index 1: bad ipv4 address \"192.168.1.x\"", - wantOpt: dhcpv4.Option{}, + }, { + name: "bool_error", + in: "19 bool yes", + wantCode: nil, + wantVal: nil, + wantErrMsg: "invalid option string \"19 bool yes\": decoding bool: " + + "strconv.ParseBool: parsing \"yes\": invalid syntax", + }, { + name: "dur_error", + in: "24 dur 3y", + wantCode: nil, + wantVal: nil, + wantErrMsg: "invalid option string \"24 dur 3y\": decoding dur: " + + "unmarshaling duration: time: unknown unit \"y\" in duration \"3y\"", + }, { + name: "u8_error", + in: "23 u8 256", + wantCode: nil, + wantVal: nil, + wantErrMsg: "invalid option string \"23 u8 256\": decoding u8: " + + "strconv.ParseUint: parsing \"256\": value out of range", + }, { + name: "u16_error", + in: "23 u16 65536", + wantCode: nil, + wantVal: nil, + wantErrMsg: "invalid option string \"23 u16 65536\": decoding u16: " + + "strconv.ParseUint: parsing \"65536\": value out of range", }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - opt, err := parseDHCPOption(tc.in) - if tc.wantErrMsg != "" { - require.Error(t, err) + code, val, err := parseDHCPOption(tc.in) + testutil.AssertErrorMsg(t, tc.wantErrMsg, err) - assert.Equal(t, tc.wantErrMsg, err.Error()) - - return - } - - require.NoError(t, err) - - assert.Equal(t, tc.wantOpt.Code.Code(), opt.Code.Code()) - assert.Equal(t, tc.wantOpt.Value.ToBytes(), opt.Value.ToBytes()) + assert.Equal(t, tc.wantCode, code) + assert.Equal(t, tc.wantVal, val) }) } } func TestPrepareOptions(t *testing.T) { - allDefault := dhcpv4.Options{ - dhcpv4.OptionNonLocalSourceRouting.Code(): []byte{0}, - dhcpv4.OptionDefaultIPTTL.Code(): []byte{64}, - dhcpv4.OptionPerformMaskDiscovery.Code(): []byte{0}, - dhcpv4.OptionMaskSupplier.Code(): []byte{0}, - dhcpv4.OptionPerformRouterDiscovery.Code(): []byte{1}, - dhcpv4.OptionRouterSolicitationAddress.Code(): []byte{224, 0, 0, 2}, - dhcpv4.OptionBroadcastAddress.Code(): []byte{255, 255, 255, 255}, - dhcpv4.OptionTrailerEncapsulation.Code(): []byte{0}, - dhcpv4.OptionEthernetEncapsulation.Code(): []byte{0}, - dhcpv4.OptionTCPKeepaliveInterval.Code(): []byte{0, 0, 0, 0}, - dhcpv4.OptionTCPKeepaliveGarbage.Code(): []byte{0}, - } oneIP, otherIP := net.IP{1, 2, 3, 4}, net.IP{5, 6, 7, 8} testCases := []struct { - name string - opts []string - checks dhcpv4.Options + name string + wantExplicit dhcpv4.Options + opts []string }{{ - name: "all_default", - checks: allDefault, + name: "all_default", + wantExplicit: nil, + opts: nil, }, { name: "configured_ip", + wantExplicit: dhcpv4.OptionsFromList( + dhcpv4.OptBroadcastAddress(oneIP), + ), opts: []string{ fmt.Sprintf("%d ip %s", dhcpv4.OptionBroadcastAddress, oneIP), }, - checks: dhcpv4.Options{ - dhcpv4.OptionBroadcastAddress.Code(): oneIP, - }, }, { name: "configured_ips", + wantExplicit: dhcpv4.OptionsFromList( + dhcpv4.Option{ + Code: dhcpv4.OptionDomainNameServer, + Value: dhcpv4.IPs{oneIP, otherIP}, + }, + ), opts: []string{ fmt.Sprintf("%d ips %s,%s", dhcpv4.OptionDomainNameServer, oneIP, otherIP), }, - checks: dhcpv4.Options{ - dhcpv4.OptionDomainNameServer.Code(): append(oneIP, otherIP...), - }, }, { - name: "configured_bad", + name: "configured_bad", + wantExplicit: nil, opts: []string{ + "19 bool yes", + "24 dur 3y", + "23 u8 256", + "23 u16 65536", "20 hex", "23 hex abc", "32 ips 1,2,3,4", "28 256.256.256.256", }, - checks: allDefault, + }, { + name: "configured_del", + wantExplicit: dhcpv4.OptionsFromList( + dhcpv4.OptBroadcastAddress(nil), + ), + opts: []string{ + "28 del", + }, + }, { + name: "rewritten_del", + wantExplicit: dhcpv4.OptionsFromList( + dhcpv4.OptBroadcastAddress(netutil.IPv4bcast()), + ), + opts: []string{ + "28 del", + "28 ip 255.255.255.255", + }, + }, { + name: "configured_and_del", + wantExplicit: dhcpv4.OptionsFromList( + dhcpv4.Option{ + Code: dhcpv4.OptionGeoConf, + Value: dhcpv4.String("cba"), + }, + ), + opts: []string{ + "123 text abc", + "123 del", + "123 text cba", + }, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - opts := prepareOptions(V4ServerConf{ + implicit, explicit := prepareOptions(V4ServerConf{ // Just to avoid nil pointer dereference. subnet: &net.IPNet{}, Options: tc.opts, }) - for c, v := range tc.checks { - optVal := opts.Get(dhcpv4.GenericOptionCode(c)) - require.NotNil(t, optVal) - assert.Len(t, optVal, len(v)) - assert.Equal(t, v, optVal) + assert.Equal(t, tc.wantExplicit, explicit) + + for c := range explicit { + assert.NotContains(t, implicit, c) } }) } diff --git a/internal/dhcpd/routeradv.go b/internal/dhcpd/routeradv.go index 863ac5e1..9c87ca9f 100644 --- a/internal/dhcpd/routeradv.go +++ b/internal/dhcpd/routeradv.go @@ -65,39 +65,42 @@ func hwAddrToLinkLayerAddr(hwa net.HardwareAddr) (lla []byte, err error) { } // Create an ICMPv6.RouterAdvertisement packet with all necessary options. +// Data scheme: // -// ICMPv6: -// type[1] -// code[1] -// chksum[2] -// body (RouterAdvertisement): -// Cur Hop Limit[1] -// Flags[1]: MO...... -// Router Lifetime[2] -// Reachable Time[4] -// Retrans Timer[4] -// Option=Prefix Information(3): -// Type[1] -// Length * 8bytes[1] -// Prefix Length[1] -// Flags[1]: LA...... -// Valid Lifetime[4] -// Preferred Lifetime[4] -// Reserved[4] -// Prefix[16] -// Option=MTU(5): -// Type[1] -// Length * 8bytes[1] -// Reserved[2] -// MTU[4] -// Option=Source link-layer address(1): -// Link-Layer Address[8/24] -// Option=Recursive DNS Server(25): -// Type[1] -// Length * 8bytes[1] -// Reserved[2] -// Lifetime[4] -// Addresses of IPv6 Recursive DNS Servers[16] +// ICMPv6: +// - type[1] +// - code[1] +// - chksum[2] +// - body (RouterAdvertisement): +// - Cur Hop Limit[1] +// - Flags[1]: MO...... +// - Router Lifetime[2] +// - Reachable Time[4] +// - Retrans Timer[4] +// - Option=Prefix Information(3): +// - Type[1] +// - Length * 8bytes[1] +// - Prefix Length[1] +// - Flags[1]: LA...... +// - Valid Lifetime[4] +// - Preferred Lifetime[4] +// - Reserved[4] +// - Prefix[16] +// - Option=MTU(5): +// - Type[1] +// - Length * 8bytes[1] +// - Reserved[2] +// - MTU[4] +// - Option=Source link-layer address(1): +// - Link-Layer Address[8/24] +// - Option=Recursive DNS Server(25): +// - Type[1] +// - Length * 8bytes[1] +// - Reserved[2] +// - Lifetime[4] +// - Addresses of IPv6 Recursive DNS Servers[16] +// +// TODO(a.garipov): Replace with an existing implementation from a dependency. func createICMPv6RAPacket(params icmpv6RA) (data []byte, err error) { var lla []byte lla, err = hwAddrToLinkLayerAddr(params.sourceLinkLayerAddress) diff --git a/internal/dhcpd/server.go b/internal/dhcpd/server.go index a359e740..be88804b 100644 --- a/internal/dhcpd/server.go +++ b/internal/dhcpd/server.go @@ -71,12 +71,12 @@ type V4ServerConf struct { // gateway. subnet *net.IPNet - // notify is a way to signal to other components that leases have - // change. notify must be called outside of locked sections, since the + // notify is a way to signal to other components that leases have been + // changed. notify must be called outside of locked sections, since the // clients might want to get the new data. // - // TODO(a.garipov): This is utter madness and must be refactored. It - // just begs for deadlock bugs and other nastiness. + // TODO(a.garipov): This is utter madness and must be refactored. It just + // begs for deadlock bugs and other nastiness. notify func(uint32) } diff --git a/internal/dhcpd/v4.go b/internal/dhcpd/v4.go index 17881d2c..4d6c817b 100644 --- a/internal/dhcpd/v4.go +++ b/internal/dhcpd/v4.go @@ -20,6 +20,7 @@ import ( "github.com/go-ping/ping" "github.com/insomniacslk/dhcp/dhcpv4" "github.com/insomniacslk/dhcp/dhcpv4/server4" + "golang.org/x/exp/slices" //lint:ignore SA1019 See the TODO in go.mod. "github.com/mdlayher/raw" @@ -32,6 +33,17 @@ type v4Server struct { conf V4ServerConf srv *server4.Server + // implicitOpts are the options listed in Appendix A of RFC 2131 initialized + // with default values. It must not have intersections with [explicitOpts]. + implicitOpts dhcpv4.Options + + // explicitOpts are the options parsed from the configuration. It must not + // have intersections with [implicitOpts]. + explicitOpts dhcpv4.Options + + // leasesLock protects leases, leaseHosts, and leasedOffsets. + leasesLock sync.Mutex + // leasedOffsets contains offsets from conf.ipRange.start that have been // leased. leasedOffsets *bitSet @@ -41,12 +53,6 @@ type v4Server struct { // leases contains all dynamic and static leases. leases []*Lease - - // leasesLock protects leases, leaseHosts, and leasedOffsets. - leasesLock sync.Mutex - - // options holds predefined DHCP options to return to clients. - options dhcpv4.Options } // WriteDiskConfig4 - write configuration @@ -252,11 +258,11 @@ func (s *v4Server) rmLeaseByIndex(i int) { // Remove a dynamic lease with the same properties // Return error if a static lease is found func (s *v4Server) rmDynamicLease(lease *Lease) (err error) { - for i := 0; i < len(s.leases); i++ { - l := s.leases[i] + for i, l := range s.leases { + isStatic := l.IsStatic() - if bytes.Equal(l.HWAddr, lease.HWAddr) { - if l.IsStatic() { + if bytes.Equal(l.HWAddr, lease.HWAddr) || l.IP.Equal(lease.IP) { + if isStatic { return errors.Error("static lease already exists") } @@ -268,20 +274,7 @@ func (s *v4Server) rmDynamicLease(lease *Lease) (err error) { l = s.leases[i] } - if l.IP.Equal(lease.IP) { - if l.IsStatic() { - return errors.Error("static lease already exists") - } - - s.rmLeaseByIndex(i) - if i == len(s.leases) { - break - } - - l = s.leases[i] - } - - if l.Hostname == lease.Hostname { + if !isStatic && l.Hostname == lease.Hostname { l.Hostname = "" } } @@ -289,6 +282,10 @@ func (s *v4Server) rmDynamicLease(lease *Lease) (err error) { return nil } +// ErrDupHostname is returned by addLease when the added lease has a not empty +// non-unique hostname. +const ErrDupHostname = errors.Error("hostname is not unique") + // addLease adds a dynamic or static lease. func (s *v4Server) addLease(l *Lease) (err error) { r := s.conf.ipRange @@ -304,13 +301,17 @@ func (s *v4Server) addLease(l *Lease) (err error) { return fmt.Errorf("lease %s (%s) out of range, not adding", l.IP, l.HWAddr) } - s.leases = append(s.leases, l) - s.leasedOffsets.set(offset, true) - if l.Hostname != "" { + if s.leaseHosts.Has(l.Hostname) { + return ErrDupHostname + } + s.leaseHosts.Add(l.Hostname) } + s.leases = append(s.leases, l) + s.leasedOffsets.set(offset, true) + return nil } @@ -365,10 +366,11 @@ func (s *v4Server) AddStaticLease(l *Lease) (err error) { return fmt.Errorf("validating hostname: %w", err) } - // Don't check for hostname uniqueness, since we try to emulate - // dnsmasq here, which means that rmDynamicLease below will - // simply empty the hostname of the dynamic lease if there even - // is one. + // Don't check for hostname uniqueness, since we try to emulate dnsmasq + // here, which means that rmDynamicLease below will simply empty the + // hostname of the dynamic lease if there even is one. In case a static + // lease with the same name already exists, addLease will return an + // error and the lease won't be added. l.Hostname = hostname } @@ -421,19 +423,19 @@ func (s *v4Server) RemoveStaticLease(l *Lease) (err error) { return fmt.Errorf("validating lease: %w", err) } + defer func() { + if err != nil { + return + } + + s.conf.notify(LeaseChangedDBStore) + s.conf.notify(LeaseChangedRemovedStatic) + }() + s.leasesLock.Lock() - err = s.rmLease(l) - if err != nil { - s.leasesLock.Unlock() + defer s.leasesLock.Unlock() - return err - } - s.leasesLock.Unlock() - - s.conf.notify(LeaseChangedDBStore) - s.conf.notify(LeaseChangedRemovedStatic) - - return nil + return s.rmLease(l) } // addrAvailable sends an ICP request to the specified IP address. It returns @@ -523,11 +525,7 @@ func (s *v4Server) findExpiredLease() int { // reserveLease reserves a lease for a client by its MAC-address. It returns // nil if it couldn't allocate a new lease. func (s *v4Server) reserveLease(mac net.HardwareAddr) (l *Lease, err error) { - l = &Lease{ - HWAddr: make([]byte, len(mac)), - } - - copy(l.HWAddr, mac) + l = &Lease{HWAddr: slices.Clone(mac)} l.IP = s.nextIP() if l.IP == nil { @@ -549,21 +547,34 @@ func (s *v4Server) reserveLease(mac net.HardwareAddr) (l *Lease, err error) { return l, nil } -func (s *v4Server) commitLease(l *Lease) { - l.Expiry = time.Now().Add(s.conf.leaseTime) +// commitLease refreshes l's values. It takes the desired hostname into account +// when setting it into the lease, but generates a unique one if the provided +// can't be used. +func (s *v4Server) commitLease(l *Lease, hostname string) { + prev := l.Hostname + hostname = s.validHostnameForClient(hostname, l.IP) - func() { - s.leasesLock.Lock() - defer s.leasesLock.Unlock() + if s.leaseHosts.Has(hostname) { + log.Info("dhcpv4: hostname %q already exists", hostname) - s.conf.notify(LeaseChangedDBStore) - - if l.Hostname != "" { - s.leaseHosts.Add(l.Hostname) + if prev == "" { + // The lease is just allocated due to DHCPDISCOVER. + hostname = aghnet.GenerateHostname(l.IP) + } else { + hostname = prev } - }() + } + if l.Hostname != hostname { + l.Hostname = hostname + } - s.conf.notify(LeaseChangedAdded) + l.Expiry = time.Now().Add(s.conf.leaseTime) + if prev != "" && prev != l.Hostname { + s.leaseHosts.Del(prev) + } + if l.Hostname != "" { + s.leaseHosts.Add(l.Hostname) + } } // allocateLease allocates a new lease for the MAC address. If there are no IP @@ -585,8 +596,8 @@ func (s *v4Server) allocateLease(mac net.HardwareAddr) (l *Lease, err error) { } } -// processDiscover is the handler for the DHCP Discover request. -func (s *v4Server) processDiscover(req, resp *dhcpv4.DHCPv4) (l *Lease, err error) { +// handleDiscover is the handler for the DHCP Discover request. +func (s *v4Server) handleDiscover(req, resp *dhcpv4.DHCPv4) (l *Lease, err error) { mac := req.ClientHWAddr defer s.conf.notify(LeaseChangedDBStore) @@ -620,33 +631,25 @@ func (s *v4Server) processDiscover(req, resp *dhcpv4.DHCPv4) (l *Lease, err erro return l, nil } -type optFQDN struct { - name string -} +// OptionFQDN returns a DHCPv4 option for sending the FQDN to the client +// requested another hostname. +// +// See https://datatracker.ietf.org/doc/html/rfc4702. +func OptionFQDN(fqdn string) (opt dhcpv4.Option) { + optData := []byte{ + // Set only S and O DHCP client FQDN option flags. + // + // See https://datatracker.ietf.org/doc/html/rfc4702#section-2.1. + 1<<0 | 1<<1, + // The RCODE fields should be set to 0xFF in the server responses. + // + // See https://datatracker.ietf.org/doc/html/rfc4702#section-2.2. + 0xFF, + 0xFF, + } + optData = append(optData, fqdn...) -func (o *optFQDN) String() string { - return "optFQDN" -} - -// flags[1] -// A-RR[1] -// PTR-RR[1] -// name[] -func (o *optFQDN) ToBytes() []byte { - b := make([]byte, 3+len(o.name)) - i := 0 - - b[i] = 0x03 // f_server_overrides | f_server - i++ - - b[i] = 255 // A-RR - i++ - - b[i] = 255 // PTR-RR - i++ - - copy(b[i:], []byte(o.name)) - return b + return dhcpv4.OptGeneric(dhcpv4.OptionFQDN, optData) } // checkLease checks if the pair of mac and ip is already leased. The mismatch @@ -676,68 +679,177 @@ func (s *v4Server) checkLease(mac net.HardwareAddr, ip net.IP) (lease *Lease, mi return nil, false } -// processRequest is the handler for the DHCP Request request. -func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, needsReply bool) { +// handleSelecting handles the DHCPREQUEST generated during SELECTING state. +func (s *v4Server) handleSelecting( + req *dhcpv4.DHCPv4, + reqIP net.IP, + sid net.IP, +) (l *Lease, needsReply bool) { + // Client inserts the address of the selected server in server identifier, + // ciaddr MUST be zero. mac := req.ClientHWAddr - reqIP := req.RequestedIPAddress() - if reqIP == nil { - reqIP = req.ClientIPAddr - } + if !sid.Equal(s.conf.dnsIPAddrs[0]) { + log.Debug("dhcpv4: bad server identifier in req msg for %s: %s", mac, sid) - sid := req.ServerIdentifier() - if len(sid) != 0 && !sid.Equal(s.conf.dnsIPAddrs[0]) { - log.Debug("dhcpv4: bad OptionServerIdentifier in req msg for %s", mac) + return nil, false + } else if ciaddr := req.ClientIPAddr; ciaddr != nil && !ciaddr.IsUnspecified() { + log.Debug("dhcpv4: non-zero ciaddr in selecting req msg for %s", mac) return nil, false } + // Requested IP address MUST be filled in with the yiaddr value from the + // chosen DHCPOFFER. if ip4 := reqIP.To4(); ip4 == nil { - log.Debug("dhcpv4: bad OptionRequestedIPAddress in req msg for %s", mac) + log.Debug("dhcpv4: bad requested address in req msg for %s: %s", mac, reqIP) return nil, false } var mismatch bool - if lease, mismatch = s.checkLease(mac, reqIP); mismatch { + if l, mismatch = s.checkLease(mac, reqIP); mismatch { return nil, true - } - - if lease == nil { + } else if l == nil { log.Debug("dhcpv4: no reserved lease for %s", mac) + } + + return l, true +} + +// handleInitReboot handles the DHCPREQUEST generated during INIT-REBOOT state. +func (s *v4Server) handleInitReboot(req *dhcpv4.DHCPv4, reqIP net.IP) (l *Lease, needsReply bool) { + mac := req.ClientHWAddr + + if ip4 := reqIP.To4(); ip4 == nil { + log.Debug("dhcpv4: bad requested address in req msg for %s: %s", mac, reqIP) + + return nil, false + } + + // ciaddr MUST be zero. The client is seeking to verify a previously + // allocated, cached configuration. + if ciaddr := req.ClientIPAddr; ciaddr != nil && !ciaddr.IsUnspecified() { + log.Debug("dhcpv4: non-zero ciaddr in init-reboot req msg for %s", mac) + + return nil, false + } + + if !s.conf.subnet.Contains(reqIP) { + // If the DHCP server detects that the client is on the wrong net then + // the server SHOULD send a DHCPNAK message to the client. + log.Debug("dhcpv4: wrong subnet in init-reboot req msg for %s: %s", mac, reqIP) return nil, true } - if !lease.IsStatic() { - cliHostname := req.HostName() - hostname := s.validHostnameForClient(cliHostname, reqIP) - if hostname != lease.Hostname && s.leaseHosts.Has(hostname) { - log.Info("dhcpv4: hostname %q already exists", hostname) - lease.Hostname = "" - } else { - lease.Hostname = hostname - } + var mismatch bool + if l, mismatch = s.checkLease(mac, reqIP); mismatch { + return nil, true + } else if l == nil { + // If the DHCP server has no record of this client, then it MUST remain + // silent, and MAY output a warning to the network administrator. + log.Info("dhcpv4: warning: no existing lease for %s", mac) - s.commitLease(lease) - } else if lease.Hostname != "" { - o := &optFQDN{ - name: lease.Hostname, - } - fqdn := dhcpv4.Option{ - Code: dhcpv4.OptionFQDN, - Value: o, - } + return nil, false + } - resp.UpdateOption(fqdn) + return l, true +} + +// handleRenew handles the DHCPREQUEST generated during RENEWING or REBINDING +// state. +func (s *v4Server) handleRenew(req *dhcpv4.DHCPv4) (l *Lease, needsReply bool) { + mac := req.ClientHWAddr + + // ciaddr MUST be filled in with client's IP address. + ciaddr := req.ClientIPAddr + if ciaddr == nil || ciaddr.IsUnspecified() || ciaddr.To4() == nil { + log.Debug("dhcpv4: bad ciaddr in renew req msg for %s: %s", mac, ciaddr) + + return nil, false + } + + var mismatch bool + if l, mismatch = s.checkLease(mac, ciaddr); mismatch { + return nil, true + } else if l == nil { + // If the DHCP server has no record of this client, then it MUST remain + // silent, and MAY output a warning to the network administrator. + log.Info("dhcpv4: warning: no existing lease for %s", mac) + + return nil, false + } + + return l, true +} + +// handleByRequestType handles the DHCPREQUEST according to the state during +// which it's generated by client. +func (s *v4Server) handleByRequestType(req *dhcpv4.DHCPv4) (lease *Lease, needsReply bool) { + reqIP, sid := req.RequestedIPAddress(), req.ServerIdentifier() + + if sid != nil && !sid.IsUnspecified() { + // If the DHCPREQUEST message contains a server identifier option, the + // message is in response to a DHCPOFFER message. Otherwise, the + // message is a request to verify or extend an existing lease. + return s.handleSelecting(req, reqIP, sid) + } + + if reqIP != nil && !reqIP.IsUnspecified() { + // Requested IP address option MUST be filled in with client's notion of + // its previously assigned address. + return s.handleInitReboot(req, reqIP) + } + + // Server identifier MUST NOT be filled in, requested IP address option MUST + // NOT be filled in. + return s.handleRenew(req) +} + +// handleRequest is the handler for a DHCPREQUEST message. +// +// See https://datatracker.ietf.org/doc/html/rfc2131#section-4.3.2. +func (s *v4Server) handleRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, needsReply bool) { + lease, needsReply = s.handleByRequestType(req) + if lease == nil { + return nil, needsReply } resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeAck)) - return lease, true + hostname := req.HostName() + isRequested := hostname != "" || req.ParameterRequestList().Has(dhcpv4.OptionHostName) + + defer func() { + s.conf.notify(LeaseChangedAdded) + s.conf.notify(LeaseChangedDBStore) + }() + + s.leasesLock.Lock() + defer s.leasesLock.Unlock() + + if lease.IsStatic() { + if lease.Hostname != "" { + // TODO(e.burkov): This option is used to update the server's DNS + // mapping. The option should only be answered when it has been + // requested. + resp.UpdateOption(OptionFQDN(lease.Hostname)) + } + + return lease, needsReply + } + + s.commitLease(lease, hostname) + + if isRequested { + resp.UpdateOption(dhcpv4.OptHostName(lease.Hostname)) + } + + return lease, needsReply } -// processRequest is the handler for the DHCP Decline request. -func (s *v4Server) processDecline(req, resp *dhcpv4.DHCPv4) (err error) { +// handleDecline is the handler for the DHCP Decline request. +func (s *v4Server) handleDecline(req, resp *dhcpv4.DHCPv4) (err error) { s.conf.notify(LeaseChangedDBStore) s.leasesLock.Lock() @@ -799,8 +911,8 @@ func (s *v4Server) processDecline(req, resp *dhcpv4.DHCPv4) (err error) { return nil } -// processRelease is the handler for the DHCP Release request. -func (s *v4Server) processRelease(req, resp *dhcpv4.DHCPv4) (err error) { +// handleRelease is the handler for the DHCP Release request. +func (s *v4Server) handleRelease(req, resp *dhcpv4.DHCPv4) (err error) { mac := req.ClientHWAddr reqIP := req.RequestedIPAddress() if reqIP == nil { @@ -841,7 +953,7 @@ func (s *v4Server) processRelease(req, resp *dhcpv4.DHCPv4) (err error) { // Return 1: OK // Return 0: error; reply with Nak // Return -1: error; don't reply -func (s *v4Server) process(req, resp *dhcpv4.DHCPv4) int { +func (s *v4Server) handle(req, resp *dhcpv4.DHCPv4) int { var err error // Include server's identifier option since any reply should contain it. @@ -851,11 +963,11 @@ func (s *v4Server) process(req, resp *dhcpv4.DHCPv4) int { // TODO(a.garipov): Refactor this into handlers. var l *Lease - switch req.MessageType() { + switch mt := req.MessageType(); mt { case dhcpv4.MessageTypeDiscover: - l, err = s.processDiscover(req, resp) + l, err = s.handleDiscover(req, resp) if err != nil { - log.Error("dhcpv4: processing discover: %s", err) + log.Error("dhcpv4: handling discover: %s", err) return 0 } @@ -865,7 +977,7 @@ func (s *v4Server) process(req, resp *dhcpv4.DHCPv4) int { } case dhcpv4.MessageTypeRequest: var toReply bool - l, toReply = s.processRequest(req, resp) + l, toReply = s.handleRequest(req, resp) if l == nil { if toReply { return 0 @@ -873,16 +985,16 @@ func (s *v4Server) process(req, resp *dhcpv4.DHCPv4) int { return -1 // drop packet } case dhcpv4.MessageTypeDecline: - err = s.processDecline(req, resp) + err = s.handleDecline(req, resp) if err != nil { - log.Error("dhcpv4: processing decline: %s", err) + log.Error("dhcpv4: handling decline: %s", err) return 0 } case dhcpv4.MessageTypeRelease: - err = s.processRelease(req, resp) + err = s.handleRelease(req, resp) if err != nil { - log.Error("dhcpv4: processing release: %s", err) + log.Error("dhcpv4: handling release: %s", err) return 0 } @@ -892,30 +1004,42 @@ func (s *v4Server) process(req, resp *dhcpv4.DHCPv4) int { resp.YourIPAddr = netutil.CloneIP(l.IP) } - // Set IP address lease time for all DHCPOFFER messages and DHCPACK - // messages replied for DHCPREQUEST. + s.updateOptions(req, resp) + + return 1 +} + +// updateOptions updates the options of the response in accordance with the +// request and RFC 2131. +// +// See https://datatracker.ietf.org/doc/html/rfc2131#section-4.3.1. +func (s *v4Server) updateOptions(req, resp *dhcpv4.DHCPv4) { + // Set IP address lease time for all DHCPOFFER messages and DHCPACK messages + // replied for DHCPREQUEST. // // TODO(e.burkov): Inspect why this is always set to configured value. resp.UpdateOption(dhcpv4.OptIPAddressLeaseTime(s.conf.leaseTime)) - // Update values for each explicitly configured parameter requested by - // client. - // - // See https://datatracker.ietf.org/doc/html/rfc2131#section-4.3.1. - requested := req.ParameterRequestList() - for _, code := range requested { - if configured := s.options; configured.Has(code) { - resp.UpdateOption(dhcpv4.OptGeneric(code, configured.Get(code))) + // If the server recognizes the parameter as a parameter defined in the Host + // Requirements Document, the server MUST include the default value for that + // parameter. + for _, code := range req.ParameterRequestList() { + if val := s.implicitOpts.Get(code); val != nil { + resp.UpdateOption(dhcpv4.OptGeneric(code, val)) } } - // Update the value of Domain Name Server option separately from others if - // not assigned yet since its value is set after server's creating. - if requested.Has(dhcpv4.OptionDomainNameServer) && - !resp.Options.Has(dhcpv4.OptionDomainNameServer) { - resp.UpdateOption(dhcpv4.OptDNS(s.conf.dnsIPAddrs...)) - } - return 1 + // If the server has been explicitly configured with a default value for the + // parameter or the parameter has a non-default value on the client's + // subnet, the server MUST include that value in an appropriate option. + for code, val := range s.explicitOpts { + if val != nil { + resp.Options[code] = val + } else { + // Delete options explicitly configured to be removed. + delete(resp.Options, code) + } + } } // client(0.0.0.0:68) -> (Request:ClientMAC,Type=Discover,ClientID,ReqIP,HostName) -> server(255.255.255.255:67) @@ -941,6 +1065,7 @@ func (s *v4Server) packetHandler(conn net.PacketConn, peer net.Addr, req *dhcpv4 resp, err := dhcpv4.NewReplyFromRequest(req) if err != nil { log.Debug("dhcpv4: dhcpv4.New: %s", err) + return } @@ -951,7 +1076,7 @@ func (s *v4Server) packetHandler(conn net.PacketConn, peer net.Addr, req *dhcpv4 return } - r := s.process(req, resp) + r := s.handle(req, resp) if r < 0 { return } else if r == 0 { @@ -961,6 +1086,12 @@ func (s *v4Server) packetHandler(conn net.PacketConn, peer net.Addr, req *dhcpv4 s.send(peer, conn, req, resp) } +// minDHCPMsgSize is the minimum length of the encoded DHCP message in bytes +// according to RFC-2131. +// +// See https://datatracker.ietf.org/doc/html/rfc2131#section-2. +const minDHCPMsgSize = 576 + // send writes resp for peer to conn considering the req's parameters according // to RFC-2131. // @@ -1001,8 +1132,22 @@ func (s *v4Server) send(peer net.Addr, conn net.PacketConn, req, resp *dhcpv4.DH // Go on since peer is already set to broadcast. } - log.Debug("dhcpv4: sending to %s: %s", peer, resp.Summary()) - if _, err := conn.WriteTo(resp.ToBytes(), peer); err != nil { + pktData := resp.ToBytes() + pktLen := len(pktData) + if pktLen < minDHCPMsgSize { + // Expand the packet to match the minimum DHCP message length. Although + // the dhpcv4 package deals with the BOOTP's lower packet length + // constraint, it seems some clients expecting the length being at least + // 576 bytes as per RFC 2131 (and an obsolete RFC 1533). + // + // See https://github.com/AdguardTeam/AdGuardHome/issues/4337. + pktData = append(pktData, make([]byte, minDHCPMsgSize-pktLen)...) + } + + log.Debug("dhcpv4: sending %d bytes to %s: %s", len(pktData), peer, resp.Summary()) + + _, err := conn.WriteTo(pktData, peer) + if err != nil { log.Error("dhcpv4: conn.Write to %s failed: %s", peer, err) } } @@ -1037,6 +1182,14 @@ func (s *v4Server) Start() (err error) { // No available IP addresses which may appear later. return nil } + // Update the value of Domain Name Server option separately from others if + // not assigned yet since its value is available only at server's start. + // + // TODO(e.burkov): Initialize as implicit option with the rest of default + // options when it will be possible to do before the call to Start. + if !s.explicitOpts.Has(dhcpv4.OptionDomainNameServer) { + s.implicitOpts.Update(dhcpv4.OptDNS(dnsIPAddrs...)) + } s.conf.dnsIPAddrs = dnsIPAddrs @@ -1162,7 +1315,7 @@ func v4Create(conf V4ServerConf) (srv DHCPServer, err error) { s.conf.leaseTime = time.Second * time.Duration(conf.LeaseDuration) } - s.options = prepareOptions(s.conf) + s.implicitOpts, s.explicitOpts = prepareOptions(s.conf) return s, nil } diff --git a/internal/dhcpd/v4_test.go b/internal/dhcpd/v4_test.go index 3c241a4a..6d8f513e 100644 --- a/internal/dhcpd/v4_test.go +++ b/internal/dhcpd/v4_test.go @@ -8,7 +8,10 @@ import ( "net" "strings" "testing" + "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghnet" + "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/golibs/testutil" "github.com/insomniacslk/dhcp/dhcpv4" @@ -23,6 +26,7 @@ var ( DefaultRangeStart = net.IP{192, 168, 10, 100} DefaultRangeEnd = net.IP{192, 168, 10, 200} DefaultGatewayIP = net.IP{192, 168, 10, 1} + DefaultSelfIP = net.IP{192, 168, 10, 2} DefaultSubnetMask = net.IP{255, 255, 255, 0} ) @@ -39,6 +43,7 @@ func defaultV4ServerConf() (conf V4ServerConf) { GatewayIP: DefaultGatewayIP, SubnetMask: DefaultSubnetMask, notify: notify4, + dnsIPAddrs: []net.IP{DefaultSelfIP}, } } @@ -54,6 +59,148 @@ func defaultSrv(t *testing.T) (s DHCPServer) { return s } +func TestV4Server_leasing(t *testing.T) { + const ( + staticName = "static-client" + anotherName = "another-client" + ) + + staticIP := net.IP{192, 168, 10, 10} + anotherIP := DefaultRangeStart + staticMAC := net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA} + anotherMAC := net.HardwareAddr{0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB} + + s := defaultSrv(t) + + t.Run("add_static", func(t *testing.T) { + err := s.AddStaticLease(&Lease{ + Expiry: time.Unix(leaseExpireStatic, 0), + Hostname: staticName, + HWAddr: staticMAC, + IP: staticIP, + }) + require.NoError(t, err) + + t.Run("same_name", func(t *testing.T) { + err = s.AddStaticLease(&Lease{ + Expiry: time.Unix(leaseExpireStatic, 0), + Hostname: staticName, + HWAddr: anotherMAC, + IP: anotherIP, + }) + assert.ErrorIs(t, err, ErrDupHostname) + }) + + t.Run("same_mac", func(t *testing.T) { + wantErrMsg := "dhcpv4: adding static lease: removing " + + "dynamic leases for " + anotherIP.String() + + " (" + staticMAC.String() + "): static lease already exists" + + err = s.AddStaticLease(&Lease{ + Expiry: time.Unix(leaseExpireStatic, 0), + Hostname: anotherName, + HWAddr: staticMAC, + IP: anotherIP, + }) + testutil.AssertErrorMsg(t, wantErrMsg, err) + }) + + t.Run("same_ip", func(t *testing.T) { + wantErrMsg := "dhcpv4: adding static lease: removing " + + "dynamic leases for " + staticIP.String() + + " (" + anotherMAC.String() + "): static lease already exists" + + err = s.AddStaticLease(&Lease{ + Expiry: time.Unix(leaseExpireStatic, 0), + Hostname: anotherName, + HWAddr: anotherMAC, + IP: staticIP, + }) + testutil.AssertErrorMsg(t, wantErrMsg, err) + }) + }) + + t.Run("add_dynamic", func(t *testing.T) { + s4, ok := s.(*v4Server) + require.True(t, ok) + + discoverAnOffer := func( + t *testing.T, + name string, + ip net.IP, + mac net.HardwareAddr, + ) (resp *dhcpv4.DHCPv4) { + testutil.CleanupAndRequireSuccess(t, func() (err error) { + return s.ResetLeases(s.GetLeases(LeasesStatic)) + }) + + req, err := dhcpv4.NewDiscovery( + mac, + dhcpv4.WithOption(dhcpv4.OptHostName(name)), + dhcpv4.WithOption(dhcpv4.OptRequestedIPAddress(ip)), + dhcpv4.WithOption(dhcpv4.OptClientIdentifier([]byte{1, 2, 3, 4, 5, 6, 8})), + dhcpv4.WithGatewayIP(DefaultGatewayIP), + ) + require.NoError(t, err) + + resp = &dhcpv4.DHCPv4{} + res := s4.handle(req, resp) + require.Positive(t, res) + require.Equal(t, dhcpv4.MessageTypeOffer, resp.MessageType()) + + resp.ClientHWAddr = mac + + return resp + } + + t.Run("same_name", func(t *testing.T) { + resp := discoverAnOffer(t, staticName, anotherIP, anotherMAC) + + req, err := dhcpv4.NewRequestFromOffer(resp, dhcpv4.WithOption( + dhcpv4.OptHostName(staticName), + )) + require.NoError(t, err) + + res := s4.handle(req, resp) + require.Positive(t, res) + + assert.Equal(t, aghnet.GenerateHostname(resp.YourIPAddr), resp.HostName()) + }) + + t.Run("same_mac", func(t *testing.T) { + resp := discoverAnOffer(t, anotherName, anotherIP, staticMAC) + + req, err := dhcpv4.NewRequestFromOffer(resp, dhcpv4.WithOption( + dhcpv4.OptHostName(anotherName), + )) + require.NoError(t, err) + + res := s4.handle(req, resp) + require.Positive(t, res) + + fqdnOptData := resp.Options.Get(dhcpv4.OptionFQDN) + require.Len(t, fqdnOptData, 3+len(staticName)) + assert.Equal(t, []uint8(staticName), fqdnOptData[3:]) + + assert.Equal(t, staticIP, resp.YourIPAddr) + }) + + t.Run("same_ip", func(t *testing.T) { + resp := discoverAnOffer(t, anotherName, staticIP, anotherMAC) + + req, err := dhcpv4.NewRequestFromOffer(resp, dhcpv4.WithOption( + dhcpv4.OptHostName(anotherName), + )) + require.NoError(t, err) + + res := s4.handle(req, resp) + require.Positive(t, res) + + assert.NotEqual(t, staticIP, resp.YourIPAddr) + }) + }) +} + func TestV4Server_AddRemove_static(t *testing.T) { s := defaultSrv(t) @@ -182,7 +329,7 @@ func TestV4_AddReplace(t *testing.T) { } } -func TestV4Server_Process_optionsPriority(t *testing.T) { +func TestV4Server_handle_optionsPriority(t *testing.T) { defaultIP := net.IP{192, 168, 1, 1} knownIP := net.IP{1, 2, 3, 4} @@ -199,6 +346,8 @@ func TestV4Server_Process_optionsPriority(t *testing.T) { stringutil.WriteToBuilder(b, ",", ip.String()) } conf.Options = []string{b.String()} + } else { + defer func() { s.implicitOpts.Update(dhcpv4.OptDNS(defaultIP)) }() } ss, err := v4Create(conf) @@ -228,7 +377,7 @@ func TestV4Server_Process_optionsPriority(t *testing.T) { resp, err = dhcpv4.NewReplyFromRequest(req) require.NoError(t, err) - res := s.process(req, resp) + res := s.handle(req, resp) require.Equal(t, 1, res) o := resp.GetOneOption(dhcpv4.OptionDomainNameServer) @@ -254,6 +403,111 @@ func TestV4Server_Process_optionsPriority(t *testing.T) { }) } +func TestV4Server_updateOptions(t *testing.T) { + testIP := net.IP{1, 2, 3, 4} + + dontWant := func(c dhcpv4.OptionCode) (opt dhcpv4.Option) { + return dhcpv4.OptGeneric(c, nil) + } + + testCases := []struct { + name string + wantOpts dhcpv4.Options + reqMods []dhcpv4.Modifier + confOpts []string + }{{ + name: "requested_default", + wantOpts: dhcpv4.OptionsFromList( + dhcpv4.OptBroadcastAddress(netutil.IPv4bcast()), + ), + reqMods: []dhcpv4.Modifier{ + dhcpv4.WithRequestedOptions(dhcpv4.OptionBroadcastAddress), + }, + confOpts: nil, + }, { + name: "requested_non-default", + wantOpts: dhcpv4.OptionsFromList( + dhcpv4.OptBroadcastAddress(testIP), + ), + reqMods: []dhcpv4.Modifier{ + dhcpv4.WithRequestedOptions(dhcpv4.OptionBroadcastAddress), + }, + confOpts: []string{ + fmt.Sprintf("%d ip %s", dhcpv4.OptionBroadcastAddress, testIP), + }, + }, { + name: "non-requested_default", + wantOpts: dhcpv4.OptionsFromList( + dontWant(dhcpv4.OptionBroadcastAddress), + ), + reqMods: nil, + confOpts: nil, + }, { + name: "non-requested_non-default", + wantOpts: dhcpv4.OptionsFromList( + dhcpv4.OptBroadcastAddress(testIP), + ), + reqMods: nil, + confOpts: []string{ + fmt.Sprintf("%d ip %s", dhcpv4.OptionBroadcastAddress, testIP), + }, + }, { + name: "requested_deleted", + wantOpts: dhcpv4.OptionsFromList( + dontWant(dhcpv4.OptionBroadcastAddress), + ), + reqMods: []dhcpv4.Modifier{ + dhcpv4.WithRequestedOptions(dhcpv4.OptionBroadcastAddress), + }, + confOpts: []string{ + fmt.Sprintf("%d del", dhcpv4.OptionBroadcastAddress), + }, + }, { + name: "requested_non-default_deleted", + wantOpts: dhcpv4.OptionsFromList( + dontWant(dhcpv4.OptionBroadcastAddress), + ), + reqMods: []dhcpv4.Modifier{ + dhcpv4.WithRequestedOptions(dhcpv4.OptionBroadcastAddress), + }, + confOpts: []string{ + fmt.Sprintf("%d ip %s", dhcpv4.OptionBroadcastAddress, testIP), + fmt.Sprintf("%d del", dhcpv4.OptionBroadcastAddress), + }, + }} + + for _, tc := range testCases { + req, err := dhcpv4.New(tc.reqMods...) + require.NoError(t, err) + + resp, err := dhcpv4.NewReplyFromRequest(req) + require.NoError(t, err) + + conf := defaultV4ServerConf() + conf.Options = tc.confOpts + + s, err := v4Create(conf) + require.NoError(t, err) + + require.IsType(t, (*v4Server)(nil), s) + s4, _ := s.(*v4Server) + + t.Run(tc.name, func(t *testing.T) { + s4.updateOptions(req, resp) + + for c, v := range tc.wantOpts { + if v == nil { + assert.NotContains(t, resp.Options, c) + + continue + } + + assert.Equal(t, v, resp.Options.Get(dhcpv4.GenericOptionCode(c))) + } + }) + } +} + func TestV4StaticLease_Get(t *testing.T) { sIface := defaultSrv(t) @@ -261,6 +515,7 @@ func TestV4StaticLease_Get(t *testing.T) { require.True(t, ok) s.conf.dnsIPAddrs = []net.IP{{192, 168, 10, 1}} + s.implicitOpts.Update(dhcpv4.OptDNS(s.conf.dnsIPAddrs...)) l := &Lease{ Hostname: "static-1.local", @@ -282,7 +537,7 @@ func TestV4StaticLease_Get(t *testing.T) { resp, err = dhcpv4.NewReplyFromRequest(req) require.NoError(t, err) - assert.Equal(t, 1, s.process(req, resp)) + assert.Equal(t, 1, s.handle(req, resp)) }) // Don't continue if we got any errors in the previous subtest. @@ -305,7 +560,7 @@ func TestV4StaticLease_Get(t *testing.T) { resp, err = dhcpv4.NewReplyFromRequest(req) require.NoError(t, err) - assert.Equal(t, 1, s.process(req, resp)) + assert.Equal(t, 1, s.handle(req, resp)) }) require.NoError(t, err) @@ -349,6 +604,7 @@ func TestV4DynamicLease_Get(t *testing.T) { require.True(t, ok) s.conf.dnsIPAddrs = []net.IP{{192, 168, 10, 1}} + s.implicitOpts.Update(dhcpv4.OptDNS(s.conf.dnsIPAddrs...)) var req, resp *dhcpv4.DHCPv4 mac := net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA} @@ -363,7 +619,7 @@ func TestV4DynamicLease_Get(t *testing.T) { resp, err = dhcpv4.NewReplyFromRequest(req) require.NoError(t, err) - assert.Equal(t, 1, s.process(req, resp)) + assert.Equal(t, 1, s.handle(req, resp)) }) // Don't continue if we got any errors in the previous subtest. @@ -397,7 +653,7 @@ func TestV4DynamicLease_Get(t *testing.T) { resp, err = dhcpv4.NewReplyFromRequest(req) require.NoError(t, err) - assert.Equal(t, 1, s.process(req, resp)) + assert.Equal(t, 1, s.handle(req, resp)) }) require.NoError(t, err) diff --git a/internal/dnsforward/config.go b/internal/dnsforward/config.go index 63af9ed1..e579e97a 100644 --- a/internal/dnsforward/config.go +++ b/internal/dnsforward/config.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghalg" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/dnsproxy/proxy" @@ -162,10 +163,10 @@ type TLSConfig struct { // DNSCryptConfig is the DNSCrypt server configuration struct. type DNSCryptConfig struct { + ResolverCert *dnscrypt.Cert + ProviderName string UDPListenAddrs []*net.UDPAddr TCPListenAddrs []*net.TCPAddr - ProviderName string - ResolverCert *dnscrypt.Cert Enabled bool } @@ -213,68 +214,67 @@ var defaultValues = ServerConfig{ FilteringConfig: FilteringConfig{BlockedResponseTTL: 3600}, } -// createProxyConfig creates and validates configuration for the main proxy -func (s *Server) createProxyConfig() (proxy.Config, error) { - proxyConfig := proxy.Config{ - UDPListenAddr: s.conf.UDPListenAddrs, - TCPListenAddr: s.conf.TCPListenAddrs, - Ratelimit: int(s.conf.Ratelimit), - RatelimitWhitelist: s.conf.RatelimitWhitelist, - RefuseAny: s.conf.RefuseAny, - TrustedProxies: s.conf.TrustedProxies, - CacheMinTTL: s.conf.CacheMinTTL, - CacheMaxTTL: s.conf.CacheMaxTTL, - CacheOptimistic: s.conf.CacheOptimistic, - UpstreamConfig: s.conf.UpstreamConfig, +// createProxyConfig creates and validates configuration for the main proxy. +func (s *Server) createProxyConfig() (conf proxy.Config, err error) { + srvConf := s.conf + conf = proxy.Config{ + UDPListenAddr: srvConf.UDPListenAddrs, + TCPListenAddr: srvConf.TCPListenAddrs, + Ratelimit: int(srvConf.Ratelimit), + RatelimitWhitelist: srvConf.RatelimitWhitelist, + RefuseAny: srvConf.RefuseAny, + TrustedProxies: srvConf.TrustedProxies, + CacheMinTTL: srvConf.CacheMinTTL, + CacheMaxTTL: srvConf.CacheMaxTTL, + CacheOptimistic: srvConf.CacheOptimistic, + UpstreamConfig: srvConf.UpstreamConfig, BeforeRequestHandler: s.beforeRequestHandler, RequestHandler: s.handleDNSRequest, - EnableEDNSClientSubnet: s.conf.EnableEDNSClientSubnet, - MaxGoroutines: int(s.conf.MaxGoroutines), + EnableEDNSClientSubnet: srvConf.EnableEDNSClientSubnet, + MaxGoroutines: int(srvConf.MaxGoroutines), } - if s.conf.CacheSize != 0 { - proxyConfig.CacheEnabled = true - proxyConfig.CacheSizeBytes = int(s.conf.CacheSize) + if srvConf.CacheSize != 0 { + conf.CacheEnabled = true + conf.CacheSizeBytes = int(srvConf.CacheSize) } - proxyConfig.UpstreamMode = proxy.UModeLoadBalance - if s.conf.AllServers { - proxyConfig.UpstreamMode = proxy.UModeParallel - } else if s.conf.FastestAddr { - proxyConfig.UpstreamMode = proxy.UModeFastestAddr - proxyConfig.FastestPingTimeout = s.conf.FastestTimeout.Duration - } + setProxyUpstreamMode( + &conf, + srvConf.AllServers, + srvConf.FastestAddr, + srvConf.FastestTimeout.Duration, + ) - for i, s := range s.conf.BogusNXDomain { - subnet, err := netutil.ParseSubnet(s) + for i, s := range srvConf.BogusNXDomain { + var subnet *net.IPNet + subnet, err = netutil.ParseSubnet(s) if err != nil { log.Error("subnet at index %d: %s", i, err) continue } - proxyConfig.BogusNXDomain = append(proxyConfig.BogusNXDomain, subnet) + conf.BogusNXDomain = append(conf.BogusNXDomain, subnet) } - // TLS settings - err := s.prepareTLS(&proxyConfig) + err = s.prepareTLS(&conf) if err != nil { - return proxyConfig, err + return conf, fmt.Errorf("validating tls: %w", err) } - if s.conf.DNSCryptConfig.Enabled { - proxyConfig.DNSCryptUDPListenAddr = s.conf.DNSCryptConfig.UDPListenAddrs - proxyConfig.DNSCryptTCPListenAddr = s.conf.DNSCryptConfig.TCPListenAddrs - proxyConfig.DNSCryptProviderName = s.conf.DNSCryptConfig.ProviderName - proxyConfig.DNSCryptResolverCert = s.conf.DNSCryptConfig.ResolverCert + if c := srvConf.DNSCryptConfig; c.Enabled { + conf.DNSCryptUDPListenAddr = c.UDPListenAddrs + conf.DNSCryptTCPListenAddr = c.TCPListenAddrs + conf.DNSCryptProviderName = c.ProviderName + conf.DNSCryptResolverCert = c.ResolverCert } - // Validate proxy config - if proxyConfig.UpstreamConfig == nil || len(proxyConfig.UpstreamConfig.Upstreams) == 0 { - return proxyConfig, errors.Error("no default upstream servers configured") + if conf.UpstreamConfig == nil || len(conf.UpstreamConfig.Upstreams) == 0 { + return conf, errors.Error("no default upstream servers configured") } - return proxyConfig, nil + return conf, nil } const ( @@ -337,7 +337,7 @@ func (s *Server) prepareUpstreamSettings() error { if s.conf.UpstreamDNSFileName != "" { data, err := os.ReadFile(s.conf.UpstreamDNSFileName) if err != nil { - return err + return fmt.Errorf("reading upstream from file: %w", err) } upstreams = stringutil.SplitTrimmed(string(data), "\n") @@ -356,7 +356,7 @@ func (s *Server) prepareUpstreamSettings() error { }, ) if err != nil { - return fmt.Errorf("dns: proxy.ParseUpstreamsConfig: %w", err) + return fmt.Errorf("parsing upstream config: %w", err) } if len(upstreamConfig.Upstreams) == 0 { @@ -370,8 +370,9 @@ func (s *Server) prepareUpstreamSettings() error { }, ) if err != nil { - return fmt.Errorf("dns: failed to parse default upstreams: %v", err) + return fmt.Errorf("parsing default upstreams: %w", err) } + upstreamConfig.Upstreams = uc.Upstreams } @@ -380,14 +381,21 @@ func (s *Server) prepareUpstreamSettings() error { return nil } -// prepareIntlProxy - initializes DNS proxy that we use for internal DNS queries -func (s *Server) prepareIntlProxy() { - s.internalProxy = &proxy.Proxy{ - Config: proxy.Config{ - CacheEnabled: true, - CacheSizeBytes: 4096, - UpstreamConfig: s.conf.UpstreamConfig, - }, +// setProxyUpstreamMode sets the upstream mode and related settings in conf +// based on provided parameters. +func setProxyUpstreamMode( + conf *proxy.Config, + allServers bool, + fastestAddr bool, + fastestTimeout time.Duration, +) { + if allServers { + conf.UpstreamMode = proxy.UModeParallel + } else if fastestAddr { + conf.UpstreamMode = proxy.UModeFastestAddr + conf.FastestPingTimeout = fastestTimeout + } else { + conf.UpstreamMode = proxy.UModeLoadBalance } } @@ -401,13 +409,15 @@ func (s *Server) prepareTLS(proxyConfig *proxy.Config) error { return nil } - if s.conf.TLSListenAddrs != nil { - proxyConfig.TLSListenAddr = s.conf.TLSListenAddrs - } + proxyConfig.TLSListenAddr = aghalg.CoalesceSlice( + s.conf.TLSListenAddrs, + proxyConfig.TLSListenAddr, + ) - if s.conf.QUICListenAddrs != nil { - proxyConfig.QUICListenAddr = s.conf.QUICListenAddrs - } + proxyConfig.QUICListenAddr = aghalg.CoalesceSlice( + s.conf.QUICListenAddrs, + proxyConfig.QUICListenAddr, + ) var err error s.conf.cert, err = tls.X509KeyPair(s.conf.CertificateChainData, s.conf.PrivateKeyData) diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index f3c98361..3f5642e9 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -81,9 +81,9 @@ const ( const ddrHostFQDN = "_dns.resolver.arpa." // handleDNSRequest filters the incoming DNS requests and writes them to the query log -func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error { - ctx := &dnsContext{ - proxyCtx: d, +func (s *Server) handleDNSRequest(_ *proxy.Proxy, pctx *proxy.DNSContext) error { + dctx := &dnsContext{ + proxyCtx: pctx, result: &filtering.Result{}, startTime: time.Now(), } @@ -111,7 +111,7 @@ func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error { s.processQueryLogsAndStats, } for _, process := range mods { - r := process(ctx) + r := process(dctx) switch r { case resultCodeSuccess: // continue: call the next filter @@ -120,13 +120,15 @@ func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error { return nil case resultCodeError: - return ctx.err + return dctx.err } } - if d.Res != nil { - d.Res.Compress = true // some devices require DNS message compression + if pctx.Res != nil { + // Some devices require DNS message compression. + pctx.Res.Compress = true } + return nil } @@ -149,34 +151,38 @@ func (s *Server) processRecursion(dctx *dnsContext) (rc resultCode) { // needed and enriches the ctx with some client-specific information. // // TODO(e.burkov): Decompose into less general processors. -func (s *Server) processInitial(ctx *dnsContext) (rc resultCode) { - d := ctx.proxyCtx - if s.conf.AAAADisabled && d.Req.Question[0].Qtype == dns.TypeAAAA { - _ = proxy.CheckDisabledAAAARequest(d, true) +func (s *Server) processInitial(dctx *dnsContext) (rc resultCode) { + pctx := dctx.proxyCtx + q := pctx.Req.Question[0] + qt := q.Qtype + if s.conf.AAAADisabled && qt == dns.TypeAAAA { + _ = proxy.CheckDisabledAAAARequest(pctx, true) + return resultCodeFinish } if s.conf.OnDNSRequest != nil { - s.conf.OnDNSRequest(d) + s.conf.OnDNSRequest(pctx) } - // disable Mozilla DoH - // https://support.mozilla.org/en-US/kb/canary-domain-use-application-dnsnet - if (d.Req.Question[0].Qtype == dns.TypeA || d.Req.Question[0].Qtype == dns.TypeAAAA) && - d.Req.Question[0].Name == "use-application-dns.net." { - d.Res = s.genNXDomain(d.Req) + // Disable Mozilla DoH. + // + // See https://support.mozilla.org/en-US/kb/canary-domain-use-application-dnsnet. + if (qt == dns.TypeA || qt == dns.TypeAAAA) && q.Name == "use-application-dns.net." { + pctx.Res = s.genNXDomain(pctx.Req) + return resultCodeFinish } - // Get the client's ID if any. It should be performed before getting - // client-specific filtering settings. + // Get the ClientID, if any, before getting client-specific filtering + // settings. var key [8]byte - binary.BigEndian.PutUint64(key[:], d.RequestID) - ctx.clientID = string(s.clientIDCache.Get(key[:])) + binary.BigEndian.PutUint64(key[:], pctx.RequestID) + dctx.clientID = string(s.clientIDCache.Get(key[:])) // Get the client-specific filtering settings. - ctx.protectionEnabled = s.conf.ProtectionEnabled - ctx.setts = s.getClientRequestFilteringSettings(ctx) + dctx.protectionEnabled = s.conf.ProtectionEnabled + dctx.setts = s.getClientRequestFilteringSettings(dctx) return resultCodeSuccess } @@ -244,28 +250,28 @@ func (s *Server) onDHCPLeaseChanged(flags int) { s.setTableIPToHost(ipToHost) } -// processDDRQuery responds to SVCB query for a special use domain name -// ‘_dns.resolver.arpa’. The result contains different types of encryption -// supported by current user configuration. +// processDDRQuery responds to Discovery of Designated Resolvers (DDR) SVCB +// queries. The response contains different types of encryption supported by +// current user configuration. // -// See https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html. -func (s *Server) processDDRQuery(ctx *dnsContext) (rc resultCode) { - d := ctx.proxyCtx - question := d.Req.Question[0] +// See https://www.ietf.org/archive/id/draft-ietf-add-ddr-10.html. +func (s *Server) processDDRQuery(dctx *dnsContext) (rc resultCode) { + pctx := dctx.proxyCtx + q := pctx.Req.Question[0] if !s.conf.HandleDDR { return resultCodeSuccess } - if question.Name == ddrHostFQDN { + if q.Name == ddrHostFQDN { if s.dnsProxy.TLSListenAddr == nil && s.conf.HTTPSListenAddrs == nil && - s.dnsProxy.QUICListenAddr == nil || question.Qtype != dns.TypeSVCB { - d.Res = s.makeResponse(d.Req) + s.dnsProxy.QUICListenAddr == nil || q.Qtype != dns.TypeSVCB { + pctx.Res = s.makeResponse(pctx.Req) return resultCodeFinish } - d.Res = s.makeDDRResponse(d.Req) + pctx.Res = s.makeDDRResponse(pctx.Req) return resultCodeFinish } @@ -273,11 +279,13 @@ func (s *Server) processDDRQuery(ctx *dnsContext) (rc resultCode) { return resultCodeSuccess } -// makeDDRResponse creates DDR answer according to server configuration. The -// contructed SVCB resource records have the priority of 1 for each entry, -// similar to examples provided by https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html. +// makeDDRResponse creates a DDR answer based on the server configuration. The +// constructed SVCB resource records have the priority of 1 for each entry, +// similar to examples provided by the [draft standard]. // // TODO(a.meshkov): Consider setting the priority values based on the protocol. +// +// [draft standard]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-10.html. func (s *Server) makeDDRResponse(req *dns.Msg) (resp *dns.Msg) { resp = s.makeResponse(req) // TODO(e.burkov): Think about storing the FQDN version of the server's @@ -351,10 +359,10 @@ func (s *Server) processDetermineLocal(dctx *dnsContext) (rc resultCode) { return rc } -// hostToIP tries to get an IP leased by DHCP and returns the copy of address -// since the data inside the internal table may be changed while request +// dhcpHostToIP tries to get an IP leased by DHCP and returns the copy of +// address since the data inside the internal table may be changed while request // processing. It's safe for concurrent use. -func (s *Server) hostToIP(host string) (ip net.IP, ok bool) { +func (s *Server) dhcpHostToIP(host string) (ip net.IP, ok bool) { s.tableHostToIPLock.Lock() defer s.tableHostToIPLock.Unlock() @@ -379,46 +387,32 @@ func (s *Server) hostToIP(host string) (ip net.IP, ok bool) { // // TODO(a.garipov): Adapt to AAAA as well. func (s *Server) processDHCPHosts(dctx *dnsContext) (rc resultCode) { - if !s.dhcpServer.Enabled() { - return resultCodeSuccess - } - - req := dctx.proxyCtx.Req + pctx := dctx.proxyCtx + req := pctx.Req q := req.Question[0] - - // Go on processing the AAAA request despite the fact that we don't support - // it yet. The expected behavior here is to respond with an empty answer - // and not NXDOMAIN. - if q.Qtype != dns.TypeA && q.Qtype != dns.TypeAAAA { + reqHost, ok := s.isDHCPClientHostQ(q) + if !ok { return resultCodeSuccess } - reqHost := strings.ToLower(q.Name[:len(q.Name)-1]) - // TODO(a.garipov): Move everything related to DHCP local domain to the DHCP - // server. - if !strings.HasSuffix(reqHost, s.localDomainSuffix) { - return resultCodeSuccess - } - - d := dctx.proxyCtx if !dctx.isLocalClient { - log.Debug("dns: %q requests for internal host", d.Addr) - d.Res = s.genNXDomain(req) + log.Debug("dns: %q requests for dhcp host %q", pctx.Addr, reqHost) + pctx.Res = s.genNXDomain(req) // Do not even put into query log. return resultCodeFinish } - ip, ok := s.hostToIP(reqHost) + ip, ok := s.dhcpHostToIP(reqHost) if !ok { - // TODO(e.burkov): Inspect special cases when user want to apply some - // rules handled by other processors to the hosts with TLD. - d.Res = s.genNXDomain(req) + // Go on and process them with filters, including dnsrewrite ones, and + // possibly route them to a domain-specific upstream. + log.Debug("dns: no dhcp record for %q", reqHost) - return resultCodeFinish + return resultCodeSuccess } - log.Debug("dns: internal record: %s -> %s", q.Name, ip) + log.Debug("dns: dhcp record for %q is %s", reqHost, ip) resp := s.makeResponse(req) if q.Qtype == dns.TypeA { @@ -435,9 +429,9 @@ func (s *Server) processDHCPHosts(dctx *dnsContext) (rc resultCode) { // processRestrictLocal responds with NXDOMAIN to PTR requests for IP addresses // in locally-served network from external clients. -func (s *Server) processRestrictLocal(ctx *dnsContext) (rc resultCode) { - d := ctx.proxyCtx - req := d.Req +func (s *Server) processRestrictLocal(dctx *dnsContext) (rc resultCode) { + pctx := dctx.proxyCtx + req := pctx.Req q := req.Question[0] if q.Qtype != dns.TypePTR { // No need for restriction. @@ -473,32 +467,32 @@ func (s *Server) processRestrictLocal(ctx *dnsContext) (rc resultCode) { return resultCodeSuccess } - if !ctx.isLocalClient { - log.Debug("dns: %q requests an internal ip", d.Addr) - d.Res = s.genNXDomain(req) + if !dctx.isLocalClient { + log.Debug("dns: %q requests an internal ip", pctx.Addr) + pctx.Res = s.genNXDomain(req) // Do not even put into query log. return resultCodeFinish } // Do not perform unreversing ever again. - ctx.unreversedReqIP = ip + dctx.unreversedReqIP = ip // There is no need to filter request from external addresses since this // code is only executed when the request is for locally-served ARPA // hostname so disable redundant filters. - ctx.setts.ParentalEnabled = false - ctx.setts.SafeBrowsingEnabled = false - ctx.setts.SafeSearchEnabled = false - ctx.setts.ServicesRules = nil + dctx.setts.ParentalEnabled = false + dctx.setts.SafeBrowsingEnabled = false + dctx.setts.SafeSearchEnabled = false + dctx.setts.ServicesRules = nil // Nothing to restrict. return resultCodeSuccess } -// ipToHost tries to get a hostname leased by DHCP. It's safe for concurrent -// use. -func (s *Server) ipToHost(ip net.IP) (host string, ok bool) { +// ipToDHCPHost tries to get a hostname leased by DHCP. It's safe for +// concurrent use. +func (s *Server) ipToDHCPHost(ip net.IP) (host string, ok bool) { s.tableIPToHostLock.Lock() defer s.tableIPToHostLock.Unlock() @@ -521,27 +515,27 @@ func (s *Server) ipToHost(ip net.IP) (host string, ok bool) { return host, true } -// Respond to PTR requests if the target IP is leased by our DHCP server and the -// requestor is inside the local network. -func (s *Server) processDHCPAddrs(ctx *dnsContext) (rc resultCode) { - d := ctx.proxyCtx - if d.Res != nil { +// processDHCPAddrs responds to PTR requests if the target IP is leased by the +// DHCP server. +func (s *Server) processDHCPAddrs(dctx *dnsContext) (rc resultCode) { + pctx := dctx.proxyCtx + if pctx.Res != nil { return resultCodeSuccess } - ip := ctx.unreversedReqIP + ip := dctx.unreversedReqIP if ip == nil { return resultCodeSuccess } - host, ok := s.ipToHost(ip) + host, ok := s.ipToDHCPHost(ip) if !ok { return resultCodeSuccess } - log.Debug("dns: reverse-lookup: %s -> %s", ip, host) + log.Debug("dns: dhcp reverse record for %s is %q", ip, host) - req := d.Req + req := pctx.Req resp := s.makeResponse(req) ptr := &dns.PTR{ Hdr: dns.RR_Header{ @@ -553,20 +547,20 @@ func (s *Server) processDHCPAddrs(ctx *dnsContext) (rc resultCode) { Ptr: dns.Fqdn(host), } resp.Answer = append(resp.Answer, ptr) - d.Res = resp + pctx.Res = resp return resultCodeSuccess } // processLocalPTR responds to PTR requests if the target IP is detected to be // inside the local network and the query was not answered from DHCP. -func (s *Server) processLocalPTR(ctx *dnsContext) (rc resultCode) { - d := ctx.proxyCtx - if d.Res != nil { +func (s *Server) processLocalPTR(dctx *dnsContext) (rc resultCode) { + pctx := dctx.proxyCtx + if pctx.Res != nil { return resultCodeSuccess } - ip := ctx.unreversedReqIP + ip := dctx.unreversedReqIP if ip == nil { return resultCodeSuccess } @@ -579,16 +573,16 @@ func (s *Server) processLocalPTR(ctx *dnsContext) (rc resultCode) { } if s.conf.UsePrivateRDNS { - s.recDetector.add(*d.Req) - if err := s.localResolvers.Resolve(d); err != nil { - ctx.err = err + s.recDetector.add(*pctx.Req) + if err := s.localResolvers.Resolve(pctx); err != nil { + dctx.err = err return resultCodeError } } - if d.Res == nil { - d.Res = s.genNXDomain(d.Req) + if pctx.Res == nil { + pctx.Res = s.genNXDomain(pctx.Req) // Do not even put into query log. return resultCodeFinish @@ -633,24 +627,25 @@ func ipStringFromAddr(addr net.Addr) (ipStr string) { // processUpstream passes request to upstream servers and handles the response. func (s *Server) processUpstream(dctx *dnsContext) (rc resultCode) { pctx := dctx.proxyCtx + req := pctx.Req + q := req.Question[0] if pctx.Res != nil { // The response has already been set. return resultCodeSuccess + } else if reqHost, ok := s.isDHCPClientHostQ(q); ok { + // A DHCP client hostname query that hasn't been handled or filtered. + // Respond with an NXDOMAIN. + // + // TODO(a.garipov): Route such queries to a custom upstream for the + // local domain name if there is one. + log.Debug("dns: dhcp client hostname %q was not filtered", reqHost) + pctx.Res = s.genNXDomain(req) + + return resultCodeFinish } - if pctx.Addr != nil && s.conf.GetCustomUpstreamByClient != nil { - // Use the ClientID first, since it has a higher priority. - id := stringutil.Coalesce(dctx.clientID, ipStringFromAddr(pctx.Addr)) - upsConf, err := s.conf.GetCustomUpstreamByClient(id) - if err != nil { - log.Error("dns: getting custom upstreams for client %s: %s", id, err) - } else if upsConf != nil { - log.Debug("dns: using custom upstreams for client %s", id) - pctx.CustomUpstreamConfig = upsConf - } - } + s.setCustomUpstream(pctx, dctx.clientID) - req := pctx.Req origReqAD := false if s.conf.EnableDNSSEC { if req.AuthenticatedData { @@ -683,52 +678,100 @@ func (s *Server) processUpstream(dctx *dnsContext) (rc resultCode) { return resultCodeSuccess } -// Apply filtering logic after we have received response from upstream servers -func (s *Server) processFilteringAfterResponse(ctx *dnsContext) (rc resultCode) { - d := ctx.proxyCtx +// isDHCPClientHostQ returns true if q is from a request for a DHCP client +// hostname. If ok is true, reqHost contains the requested hostname. +func (s *Server) isDHCPClientHostQ(q dns.Question) (reqHost string, ok bool) { + if !s.dhcpServer.Enabled() { + return "", false + } - switch res := ctx.result; res.Reason { + // Include AAAA here, because despite the fact that we don't support it yet, + // the expected behavior here is to respond with an empty answer and not + // NXDOMAIN. + if qt := q.Qtype; qt != dns.TypeA && qt != dns.TypeAAAA { + return "", false + } + + reqHost = strings.ToLower(q.Name[:len(q.Name)-1]) + if strings.HasSuffix(reqHost, s.localDomainSuffix) { + return reqHost, true + } + + return "", false +} + +// setCustomUpstream sets custom upstream settings in pctx, if necessary. +func (s *Server) setCustomUpstream(pctx *proxy.DNSContext, clientID string) { + customUpsByClient := s.conf.GetCustomUpstreamByClient + if pctx.Addr == nil || customUpsByClient == nil { + return + } + + // Use the ClientID first, since it has a higher priority. + id := stringutil.Coalesce(clientID, ipStringFromAddr(pctx.Addr)) + upsConf, err := customUpsByClient(id) + if err != nil { + log.Error("dns: getting custom upstreams for client %s: %s", id, err) + + return + } + + if upsConf != nil { + log.Debug("dns: using custom upstreams for client %s", id) + } + + pctx.CustomUpstreamConfig = upsConf +} + +// Apply filtering logic after we have received response from upstream servers +func (s *Server) processFilteringAfterResponse(dctx *dnsContext) (rc resultCode) { + pctx := dctx.proxyCtx + switch res := dctx.result; res.Reason { case filtering.NotFilteredAllowList: - // Go on. + return resultCodeSuccess case filtering.Rewritten, filtering.RewrittenRule: - if len(ctx.origQuestion.Name) == 0 { + if dctx.origQuestion.Name == "" { // origQuestion is set in case we get only CNAME without IP from // rewrites table. - break + return resultCodeSuccess } - d.Req.Question[0], d.Res.Question[0] = ctx.origQuestion, ctx.origQuestion - if len(d.Res.Answer) > 0 { - answer := append([]dns.RR{s.genAnswerCNAME(d.Req, res.CanonName)}, d.Res.Answer...) - d.Res.Answer = answer + pctx.Req.Question[0], pctx.Res.Question[0] = dctx.origQuestion, dctx.origQuestion + if len(pctx.Res.Answer) > 0 { + rr := s.genAnswerCNAME(pctx.Req, res.CanonName) + answer := append([]dns.RR{rr}, pctx.Res.Answer...) + pctx.Res.Answer = answer } + + return resultCodeSuccess default: - // Check the response only if it's from an upstream. Don't check the - // response if the protection is disabled since dnsrewrite rules aren't - // applied to it anyway. - if !ctx.protectionEnabled || !ctx.responseFromUpstream || s.dnsFilter == nil { - break - } + return s.filterAfterResponse(dctx, pctx) + } +} - origResp := d.Res - result, err := s.filterDNSResponse(ctx) - if err != nil { - ctx.err = err - - return resultCodeError - } - - if result != nil { - ctx.result = result - ctx.origResp = origResp - } +// filterAfterResponse returns the result of filtering the response that wasn't +// explicitly allowed or rewritten. +func (s *Server) filterAfterResponse(dctx *dnsContext, pctx *proxy.DNSContext) (res resultCode) { + // Check the response only if it's from an upstream. Don't check the + // response if the protection is disabled since dnsrewrite rules aren't + // applied to it anyway. + if !dctx.protectionEnabled || !dctx.responseFromUpstream || s.dnsFilter == nil { + return resultCodeSuccess } - if ctx.result == nil { - ctx.result = &filtering.Result{} + result, err := s.filterDNSResponse(pctx, dctx.setts) + if err != nil { + dctx.err = err + + return resultCodeError + } + + if result != nil { + dctx.result = result + dctx.origResp = pctx.Res } return resultCodeSuccess diff --git a/internal/dnsforward/dns_test.go b/internal/dnsforward/dns_test.go index 25e28afd..218edb1a 100644 --- a/internal/dnsforward/dns_test.go +++ b/internal/dnsforward/dns_test.go @@ -248,7 +248,7 @@ func TestServer_ProcessDHCPHosts_localRestriction(t *testing.T) { name: "local_client_unknown_host", host: "wronghost.lan", wantIP: nil, - wantRes: resultCodeFinish, + wantRes: resultCodeSuccess, isLocalCli: true, }, { name: "external_client_known_host", @@ -358,7 +358,7 @@ func TestServer_ProcessDHCPHosts(t *testing.T) { host: "example-new.lan", suffix: defaultLocalDomainSuffix, wantIP: nil, - wantRes: resultCodeFinish, + wantRes: resultCodeSuccess, qtyp: dns.TypeA, }, { name: "success_internal_aaaa", diff --git a/internal/dnsforward/dnsforward.go b/internal/dnsforward/dnsforward.go index ca479fc4..33be1e83 100644 --- a/internal/dnsforward/dnsforward.go +++ b/internal/dnsforward/dnsforward.go @@ -49,11 +49,12 @@ type hostToIPTable = map[string]net.IP // Server is the main way to start a DNS server. // // Example: -// s := dnsforward.Server{} -// err := s.Start(nil) // will start a DNS server listening on default port 53, in a goroutine -// err := s.Reconfigure(ServerConfig{UDPListenAddr: &net.UDPAddr{Port: 53535}}) // will reconfigure running DNS server to listen on UDP port 53535 -// err := s.Stop() // will stop listening on port 53535 and cancel all goroutines -// err := s.Start(nil) // will start listening again, on port 53535, in a goroutine +// +// s := dnsforward.Server{} +// err := s.Start(nil) // will start a DNS server listening on default port 53, in a goroutine +// err := s.Reconfigure(ServerConfig{UDPListenAddr: &net.UDPAddr{Port: 53535}}) // will reconfigure running DNS server to listen on UDP port 53535 +// err := s.Stop() // will stop listening on port 53535 and cancel all goroutines +// err := s.Start(nil) // will start listening again, on port 53535, in a goroutine // // The zero Server is empty and ready for use. type Server struct { @@ -176,18 +177,6 @@ func NewServer(p DNSCreateParams) (s *Server, err error) { return s, nil } -// NewCustomServer creates a new instance of *Server with custom internal proxy. -func NewCustomServer(internalProxy *proxy.Proxy) *Server { - s := &Server{ - recDetector: newRecursionDetector(0, 1), - } - if internalProxy != nil { - s.internalProxy = internalProxy - } - - return s -} - // Close gracefully closes the server. It is safe for concurrent use. // // TODO(e.burkov): A better approach would be making Stop method waiting for all @@ -445,65 +434,54 @@ func (s *Server) setupResolvers(localAddrs []string) (err error) { return nil } -// Prepare the object -func (s *Server) Prepare(config *ServerConfig) error { - // Initialize the server configuration - // -- - if config != nil { - s.conf = *config - if s.conf.BlockingMode == "custom_ip" { - if s.conf.BlockingIPv4 == nil || s.conf.BlockingIPv6 == nil { - return fmt.Errorf("dns: invalid custom blocking IP address specified") - } - } +// Prepare initializes parameters of s using data from conf. conf must not be +// nil. +func (s *Server) Prepare(conf *ServerConfig) (err error) { + s.conf = *conf + + err = validateBlockingMode(s.conf.BlockingMode, s.conf.BlockingIPv4, s.conf.BlockingIPv6) + if err != nil { + return fmt.Errorf("checking blocking mode: %w", err) } - // Set default values in the case if nothing is configured - // -- s.initDefaultSettings() - // Initialize ipset configuration - // -- - err := s.ipset.init(s.conf.IpsetList) + err = s.ipset.init(s.conf.IpsetList) if err != nil { + // Don't wrap the error, because it's informative enough as is. return err } - log.Debug("inited ipset") - - // Prepare DNS servers settings - // -- err = s.prepareUpstreamSettings() if err != nil { - return err + return fmt.Errorf("preparing upstream settings: %w", err) } - // Create DNS proxy configuration - // -- var proxyConfig proxy.Config proxyConfig, err = s.createProxyConfig() if err != nil { - return err + return fmt.Errorf("preparing proxy: %w", err) } - // Prepare a DNS proxy instance that we use for internal DNS queries - // -- - s.prepareIntlProxy() - - s.access, err = newAccessCtx(s.conf.AllowedClients, s.conf.DisallowedClients, s.conf.BlockedHosts) + err = s.prepareInternalProxy() if err != nil { - return err + return fmt.Errorf("preparing internal proxy: %w", err) + } + + s.access, err = newAccessCtx( + s.conf.AllowedClients, + s.conf.DisallowedClients, + s.conf.BlockedHosts, + ) + if err != nil { + return fmt.Errorf("preparing access: %w", err) } - // Register web handlers if necessary - // -- if !webRegistered && s.conf.HTTPRegister != nil { webRegistered = true s.registerHandlers() } - // Create the main DNS proxy instance - // -- s.dnsProxy = &proxy.Proxy{Config: proxyConfig} err = s.setupResolvers(s.conf.LocalPTRResolvers) @@ -516,6 +494,61 @@ func (s *Server) Prepare(config *ServerConfig) error { return nil } +// validateBlockingMode returns an error if the blocking mode data aren't valid. +func validateBlockingMode(mode BlockingMode, blockingIPv4, blockingIPv6 net.IP) (err error) { + switch mode { + case + BlockingModeDefault, + BlockingModeNXDOMAIN, + BlockingModeREFUSED, + BlockingModeNullIP: + return nil + case BlockingModeCustomIP: + if blockingIPv4 == nil { + return fmt.Errorf("blocking_ipv4 must be set when blocking_mode is custom_ip") + } else if blockingIPv6 == nil { + return fmt.Errorf("blocking_ipv6 must be set when blocking_mode is custom_ip") + } + + return nil + default: + return fmt.Errorf("bad blocking mode %q", mode) + } +} + +// prepareInternalProxy initializes the DNS proxy that is used for internal DNS +// queries, such at client PTR resolving and updater hostname resolving. +func (s *Server) prepareInternalProxy() (err error) { + conf := &proxy.Config{ + CacheEnabled: true, + CacheSizeBytes: 4096, + UpstreamConfig: s.conf.UpstreamConfig, + MaxGoroutines: int(s.conf.MaxGoroutines), + } + + srvConf := s.conf + setProxyUpstreamMode( + conf, + srvConf.AllServers, + srvConf.FastestAddr, + srvConf.FastestTimeout.Duration, + ) + + // TODO(a.garipov): Make a proper constructor for proxy.Proxy. + p := &proxy.Proxy{ + Config: *conf, + } + + err = p.Init() + if err != nil { + return err + } + + s.internalProxy = p + + return nil +} + // Stop stops the DNS server. func (s *Server) Stop() error { s.serverLock.Lock() @@ -561,7 +594,7 @@ func (s *Server) proxy() (p *proxy.Proxy) { } // Reconfigure applies the new configuration to the DNS server. -func (s *Server) Reconfigure(config *ServerConfig) error { +func (s *Server) Reconfigure(conf *ServerConfig) error { s.serverLock.Lock() defer s.serverLock.Unlock() @@ -575,7 +608,12 @@ func (s *Server) Reconfigure(config *ServerConfig) error { // We wait for some time and hope that this fd will be closed. time.Sleep(100 * time.Millisecond) - err = s.Prepare(config) + // TODO(a.garipov): This whole piece of API is weird and needs to be remade. + if conf == nil { + conf = &s.conf + } + + err = s.Prepare(conf) if err != nil { return fmt.Errorf("could not reconfigure the server: %w", err) } diff --git a/internal/dnsforward/dnsforward_test.go b/internal/dnsforward/dnsforward_test.go index 5144680b..a76d5a41 100644 --- a/internal/dnsforward/dnsforward_test.go +++ b/internal/dnsforward/dnsforward_test.go @@ -78,9 +78,11 @@ func createTestServer( }) require.NoError(t, err) - s.conf = forwardConf + if forwardConf.BlockingMode == "" { + forwardConf.BlockingMode = BlockingModeDefault + } - err = s.Prepare(nil) + err = s.Prepare(&forwardConf) require.NoError(t, err) s.serverLock.Lock() @@ -152,7 +154,7 @@ func createTestTLS(t *testing.T, tlsConf TLSConfig) (s *Server, certPem []byte) tlsConf.CertificateChainData, tlsConf.PrivateKeyData = certPem, keyPem s.conf.TLSConfig = tlsConf - err := s.Prepare(nil) + err := s.Prepare(&s.conf) require.NoErrorf(t, err, "failed to prepare server: %s", err) return s, certPem @@ -286,6 +288,9 @@ func TestServer_timeout(t *testing.T) { t.Run("custom", func(t *testing.T) { srvConf := &ServerConfig{ UpstreamTimeout: timeout, + FilteringConfig: FilteringConfig{ + BlockingMode: BlockingModeDefault, + }, } s, err := NewServer(DNSCreateParams{}) @@ -301,7 +306,8 @@ func TestServer_timeout(t *testing.T) { s, err := NewServer(DNSCreateParams{}) require.NoError(t, err) - err = s.Prepare(nil) + s.conf.FilteringConfig.BlockingMode = BlockingModeDefault + err = s.Prepare(&s.conf) require.NoError(t, err) assert.Equal(t, DefaultTimeout, s.conf.UpstreamTimeout) @@ -915,6 +921,7 @@ func TestRewrite(t *testing.T) { TCPListenAddrs: []*net.TCPAddr{{}}, FilteringConfig: FilteringConfig{ ProtectionEnabled: true, + BlockingMode: BlockingModeDefault, UpstreamDNS: []string{"8.8.8.8:53"}, }, })) @@ -1026,9 +1033,10 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) { s.conf.UDPListenAddrs = []*net.UDPAddr{{}} s.conf.TCPListenAddrs = []*net.TCPAddr{{}} s.conf.UpstreamDNS = []string{"127.0.0.1:53"} - s.conf.ProtectionEnabled = true + s.conf.FilteringConfig.ProtectionEnabled = true + s.conf.FilteringConfig.BlockingMode = BlockingModeDefault - err = s.Prepare(nil) + err = s.Prepare(&s.conf) require.NoError(t, err) err = s.Start() @@ -1098,8 +1106,9 @@ func TestPTRResponseFromHosts(t *testing.T) { s.conf.UDPListenAddrs = []*net.UDPAddr{{}} s.conf.TCPListenAddrs = []*net.TCPAddr{{}} s.conf.UpstreamDNS = []string{"127.0.0.1:53"} + s.conf.FilteringConfig.BlockingMode = BlockingModeDefault - err = s.Prepare(nil) + err = s.Prepare(&s.conf) require.NoError(t, err) err = s.Start() @@ -1217,13 +1226,17 @@ func TestServer_Exchange(t *testing.T) { errUpstream := aghtest.NewErrorUpstream() nonPtrUpstream := aghtest.NewBlockUpstream("some-host", true) - srv := NewCustomServer(&proxy.Proxy{ - Config: proxy.Config{ - UpstreamConfig: &proxy.UpstreamConfig{ - Upstreams: []upstream.Upstream{extUpstream}, + srv := &Server{ + recDetector: newRecursionDetector(0, 1), + internalProxy: &proxy.Proxy{ + Config: proxy.Config{ + UpstreamConfig: &proxy.UpstreamConfig{ + Upstreams: []upstream.Upstream{extUpstream}, + }, }, }, - }) + } + srv.conf.ResolveClients = true srv.conf.UsePrivateRDNS = true diff --git a/internal/dnsforward/dnsrewrite.go b/internal/dnsforward/dnsrewrite.go index 2d4cc5a7..9897449d 100644 --- a/internal/dnsforward/dnsrewrite.go +++ b/internal/dnsforward/dnsrewrite.go @@ -12,64 +12,30 @@ import ( "github.com/miekg/dns" ) -// filterDNSRewriteResponse handles a single DNS rewrite response entry. -// It returns the properly constructed answer resource record. -func (s *Server) filterDNSRewriteResponse(req *dns.Msg, rr rules.RRType, v rules.RRValue) (ans dns.RR, err error) { - // TODO(a.garipov): As more types are added, we will probably want to - // use a handler-oriented approach here. So, think of a way to decouple - // the answer generation logic from the Server. - +// filterDNSRewriteResponse handles a single DNS rewrite response entry. It +// returns the properly constructed answer resource record. +func (s *Server) filterDNSRewriteResponse( + req *dns.Msg, + rr rules.RRType, + v rules.RRValue, +) (ans dns.RR, err error) { switch rr { - case dns.TypeA, + case + dns.TypeA, dns.TypeAAAA: - ip, ok := v.(net.IP) - if !ok { - return nil, fmt.Errorf("value for rr type %d has type %T, not net.IP", rr, v) - } - - if rr == dns.TypeA { - return s.genAnswerA(req, ip.To4()), nil - } - - return s.genAnswerAAAA(req, ip), nil - case dns.TypePTR, + return s.ansFromDNSRewriteIP(v, rr, req) + case + dns.TypePTR, dns.TypeTXT: - str, ok := v.(string) - if !ok { - return nil, fmt.Errorf("value for rr type %d has type %T, not string", rr, v) - } - - if rr == dns.TypeTXT { - return s.genAnswerTXT(req, []string{str}), nil - } - - return s.genAnswerPTR(req, str), nil + return s.ansFromDNSRewriteText(v, rr, req) case dns.TypeMX: - mx, ok := v.(*rules.DNSMX) - if !ok { - return nil, fmt.Errorf("value for rr type %d has type %T, not *rules.DNSMX", rr, v) - } - - return s.genAnswerMX(req, mx), nil - case dns.TypeHTTPS, + return s.ansFromDNSRewriteMX(v, rr, req) + case + dns.TypeHTTPS, dns.TypeSVCB: - svcb, ok := v.(*rules.DNSSVCB) - if !ok { - return nil, fmt.Errorf("value for rr type %d has type %T, not *rules.DNSSVCB", rr, v) - } - - if rr == dns.TypeHTTPS { - return s.genAnswerHTTPS(req, svcb), nil - } - - return s.genAnswerSVCB(req, svcb), nil + return s.ansFromDNSRewriteSVCB(v, rr, req) case dns.TypeSRV: - srv, ok := v.(*rules.DNSSRV) - if !ok { - return nil, fmt.Errorf("value for rr type %d has type %T, not *rules.DNSSRV", rr, v) - } - - return s.genAnswerSRV(req, srv), nil + return s.ansFromDNSRewriteSRV(v, rr, req) default: log.Debug("don't know how to handle dns rr type %d, skipping", rr) @@ -77,9 +43,112 @@ func (s *Server) filterDNSRewriteResponse(req *dns.Msg, rr rules.RRType, v rules } } -// filterDNSRewrite handles dnsrewrite filters. It constructs a DNS -// response and sets it into d.Res. -func (s *Server) filterDNSRewrite(req *dns.Msg, res filtering.Result, d *proxy.DNSContext) (err error) { +// ansFromDNSRewriteIP creates a new answer resource record from the A/AAAA +// dnsrewrite rule data. +func (s *Server) ansFromDNSRewriteIP( + v rules.RRValue, + rr rules.RRType, + req *dns.Msg, +) (ans dns.RR, err error) { + ip, ok := v.(net.IP) + if !ok { + return nil, fmt.Errorf("value for rr type %s has type %T, not net.IP", dns.Type(rr), v) + } + + if rr == dns.TypeA { + return s.genAnswerA(req, ip.To4()), nil + } + + return s.genAnswerAAAA(req, ip), nil +} + +// ansFromDNSRewriteText creates a new answer resource record from the TXT/PTR +// dnsrewrite rule data. +func (s *Server) ansFromDNSRewriteText( + v rules.RRValue, + rr rules.RRType, + req *dns.Msg, +) (ans dns.RR, err error) { + str, ok := v.(string) + if !ok { + return nil, fmt.Errorf("value for rr type %s has type %T, not string", dns.Type(rr), v) + } + + if rr == dns.TypeTXT { + return s.genAnswerTXT(req, []string{str}), nil + } + + return s.genAnswerPTR(req, str), nil +} + +// ansFromDNSRewriteMX creates a new answer resource record from the MX +// dnsrewrite rule data. +func (s *Server) ansFromDNSRewriteMX( + v rules.RRValue, + rr rules.RRType, + req *dns.Msg, +) (ans dns.RR, err error) { + mx, ok := v.(*rules.DNSMX) + if !ok { + return nil, fmt.Errorf( + "value for rr type %s has type %T, not *rules.DNSMX", + dns.Type(rr), + v, + ) + } + + return s.genAnswerMX(req, mx), nil +} + +// ansFromDNSRewriteSVCB creates a new answer resource record from the +// SVCB/HTTPS dnsrewrite rule data. +func (s *Server) ansFromDNSRewriteSVCB( + v rules.RRValue, + rr rules.RRType, + req *dns.Msg, +) (ans dns.RR, err error) { + svcb, ok := v.(*rules.DNSSVCB) + if !ok { + return nil, fmt.Errorf( + "value for rr type %s has type %T, not *rules.DNSSVCB", + dns.Type(rr), + v, + ) + } + + if rr == dns.TypeHTTPS { + return s.genAnswerHTTPS(req, svcb), nil + } + + return s.genAnswerSVCB(req, svcb), nil +} + +// ansFromDNSRewriteSRV creates a new answer resource record from the SRV +// dnsrewrite rule data. +func (s *Server) ansFromDNSRewriteSRV( + v rules.RRValue, + rr rules.RRType, + req *dns.Msg, +) (dns.RR, error) { + srv, ok := v.(*rules.DNSSRV) + if !ok { + return nil, fmt.Errorf( + "value for rr type %s has type %T, not *rules.DNSSRV", + dns.Type(rr), + v, + ) + } + + return s.genAnswerSRV(req, srv), nil +} + +// filterDNSRewrite handles dnsrewrite filters. It constructs a DNS response +// and sets it into pctx.Res. All parameters must not be nil. +func (s *Server) filterDNSRewrite( + req *dns.Msg, + res *filtering.Result, + pctx *proxy.DNSContext, +) (err error) { resp := s.makeResponse(req) dnsrr := res.DNSRewriteResult if dnsrr == nil { @@ -88,7 +157,7 @@ func (s *Server) filterDNSRewrite(req *dns.Msg, res filtering.Result, d *proxy.D resp.Rcode = dnsrr.RCode if resp.Rcode != dns.RcodeSuccess { - d.Res = resp + pctx.Res = resp return nil } @@ -109,7 +178,7 @@ func (s *Server) filterDNSRewrite(req *dns.Msg, res filtering.Result, d *proxy.D resp.Answer = append(resp.Answer, ans) } - d.Res = resp + pctx.Res = resp return nil } diff --git a/internal/dnsforward/dnsrewrite_test.go b/internal/dnsforward/dnsrewrite_test.go index 5ba10582..422759a3 100644 --- a/internal/dnsforward/dnsrewrite_test.go +++ b/internal/dnsforward/dnsrewrite_test.go @@ -42,11 +42,11 @@ func TestServer_FilterDNSRewrite(t *testing.T) { }}, } } - makeRes := func(rcode rules.RCode, rr rules.RRType, v rules.RRValue) (res filtering.Result) { + makeRes := func(rcode rules.RCode, rr rules.RRType, v rules.RRValue) (res *filtering.Result) { resp := filtering.DNSRewriteResultResponse{ rr: []rules.RRValue{v}, } - return filtering.Result{ + return &filtering.Result{ DNSRewriteResult: &filtering.DNSRewriteResult{ RCode: rcode, Response: resp, diff --git a/internal/dnsforward/filter.go b/internal/dnsforward/filter.go index 18f12797..7dc8514e 100644 --- a/internal/dnsforward/filter.go +++ b/internal/dnsforward/filter.go @@ -49,69 +49,83 @@ func (s *Server) beforeRequestHandler( } // getClientRequestFilteringSettings looks up client filtering settings using -// the client's IP address and ID, if any, from ctx. -func (s *Server) getClientRequestFilteringSettings(ctx *dnsContext) *filtering.Settings { +// the client's IP address and ID, if any, from dctx. +func (s *Server) getClientRequestFilteringSettings(dctx *dnsContext) *filtering.Settings { setts := s.dnsFilter.GetConfig() - setts.ProtectionEnabled = ctx.protectionEnabled + setts.ProtectionEnabled = dctx.protectionEnabled if s.conf.FilterHandler != nil { - ip, _ := netutil.IPAndPortFromAddr(ctx.proxyCtx.Addr) - s.conf.FilterHandler(ip, ctx.clientID, &setts) + ip, _ := netutil.IPAndPortFromAddr(dctx.proxyCtx.Addr) + s.conf.FilterHandler(ip, dctx.clientID, &setts) } return &setts } -// filterDNSRequest applies the dnsFilter and sets d.Res if the request was -// filtered. -func (s *Server) filterDNSRequest(ctx *dnsContext) (*filtering.Result, error) { - d := ctx.proxyCtx - req := d.Req +// filterDNSRequest applies the dnsFilter and sets dctx.proxyCtx.Res if the +// request was filtered. +func (s *Server) filterDNSRequest(dctx *dnsContext) (res *filtering.Result, err error) { + pctx := dctx.proxyCtx + req := pctx.Req q := req.Question[0] host := strings.TrimSuffix(q.Name, ".") - res, err := s.dnsFilter.CheckHost(host, q.Qtype, ctx.setts) + resVal, err := s.dnsFilter.CheckHost(host, q.Qtype, dctx.setts) + if err != nil { + return nil, fmt.Errorf("checking host %q: %w", host, err) + } + + // TODO(a.garipov): Make CheckHost return a pointer. + res = &resVal switch { - case err != nil: - return nil, fmt.Errorf("failed to check host %q: %w", host, err) case res.IsFiltered: log.Tracef("host %q is filtered, reason %q, rule: %q", host, res.Reason, res.Rules[0].Text) - d.Res = s.genDNSFilterMessage(d, &res) + pctx.Res = s.genDNSFilterMessage(pctx, res) case res.Reason.In(filtering.Rewritten, filtering.RewrittenRule) && res.CanonName != "" && len(res.IPList) == 0: // Resolve the new canonical name, not the original host name. The // original question is readded in processFilteringAfterResponse. - ctx.origQuestion = q + dctx.origQuestion = q req.Question[0].Name = dns.Fqdn(res.CanonName) case res.Reason == filtering.Rewritten: - resp := s.makeResponse(req) - - name := host - if len(res.CanonName) != 0 { - resp.Answer = append(resp.Answer, s.genAnswerCNAME(req, res.CanonName)) - name = res.CanonName - } - - for _, ip := range res.IPList { - switch q.Qtype { - case dns.TypeA: - a := s.genAnswerA(req, ip.To4()) - a.Hdr.Name = dns.Fqdn(name) - resp.Answer = append(resp.Answer, a) - case dns.TypeAAAA: - a := s.genAnswerAAAA(req, ip) - a.Hdr.Name = dns.Fqdn(name) - resp.Answer = append(resp.Answer, a) - } - } - - d.Res = resp + pctx.Res = s.filterRewritten(req, host, res, q.Qtype) case res.Reason.In(filtering.RewrittenRule, filtering.RewrittenAutoHosts): - if err = s.filterDNSRewrite(req, res, d); err != nil { + if err = s.filterDNSRewrite(req, res, pctx); err != nil { return nil, err } } - return &res, err + return res, err +} + +// filterRewritten handles DNS rewrite filters. It returns a DNS response with +// the data from the filtering result. All parameters must not be nil. +func (s *Server) filterRewritten( + req *dns.Msg, + host string, + res *filtering.Result, + qt uint16, +) (resp *dns.Msg) { + resp = s.makeResponse(req) + name := host + if len(res.CanonName) != 0 { + resp.Answer = append(resp.Answer, s.genAnswerCNAME(req, res.CanonName)) + name = res.CanonName + } + + for _, ip := range res.IPList { + switch qt { + case dns.TypeA: + a := s.genAnswerA(req, ip.To4()) + a.Hdr.Name = dns.Fqdn(name) + resp.Answer = append(resp.Answer, a) + case dns.TypeAAAA: + a := s.genAnswerAAAA(req, ip) + a.Hdr.Name = dns.Fqdn(name) + resp.Answer = append(resp.Answer, a) + } + } + + return resp } // checkHostRules checks the host against filters. It is safe for concurrent @@ -137,16 +151,17 @@ func (s *Server) checkHostRules(host string, rrtype uint16, setts *filtering.Set } // filterDNSResponse checks each resource record of the response's answer -// section from ctx and returns a non-nil res if at least one of canonnical +// section from pctx and returns a non-nil res if at least one of canonnical // names or IP addresses in it matches the filtering rules. -func (s *Server) filterDNSResponse(ctx *dnsContext) (res *filtering.Result, err error) { - d := ctx.proxyCtx - setts := ctx.setts +func (s *Server) filterDNSResponse( + pctx *proxy.DNSContext, + setts *filtering.Settings, +) (res *filtering.Result, err error) { if !setts.FilteringEnabled { return nil, nil } - for _, a := range d.Res.Answer { + for _, a := range pctx.Res.Answer { host := "" var rrtype uint16 switch a := a.(type) { @@ -171,8 +186,8 @@ func (s *Server) filterDNSResponse(ctx *dnsContext) (res *filtering.Result, err } else if res == nil { continue } else if res.IsFiltered { - d.Res = s.genDNSFilterMessage(d, res) - log.Debug("DNSFwd: Matched %s by response: %s", d.Req.Question[0].Name, host) + pctx.Res = s.genDNSFilterMessage(pctx, res) + log.Debug("DNSFwd: Matched %s by response: %s", pctx.Req.Question[0].Name, host) return res, nil } diff --git a/internal/dnsforward/filter_test.go b/internal/dnsforward/filter_test.go index 69dcf8f9..e25d4037 100644 --- a/internal/dnsforward/filter_test.go +++ b/internal/dnsforward/filter_test.go @@ -45,8 +45,7 @@ func TestHandleDNSRequest_filterDNSResponse(t *testing.T) { }) require.NoError(t, err) - s.conf = forwardConf - err = s.Prepare(nil) + err = s.Prepare(&forwardConf) require.NoError(t, err) s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ diff --git a/internal/dnsforward/http.go b/internal/dnsforward/http.go index 93121fac..5df74fe8 100644 --- a/internal/dnsforward/http.go +++ b/internal/dnsforward/http.go @@ -20,16 +20,14 @@ import ( "golang.org/x/exp/slices" ) -type dnsConfig struct { - Upstreams *[]string `json:"upstream_dns"` - UpstreamsFile *string `json:"upstream_dns_file"` - Bootstraps *[]string `json:"bootstrap_dns"` - +// jsonDNSConfig is the JSON representation of the DNS server configuration. +type jsonDNSConfig struct { + Upstreams *[]string `json:"upstream_dns"` + UpstreamsFile *string `json:"upstream_dns_file"` + Bootstraps *[]string `json:"bootstrap_dns"` ProtectionEnabled *bool `json:"protection_enabled"` RateLimit *uint32 `json:"ratelimit"` BlockingMode *BlockingMode `json:"blocking_mode"` - BlockingIPv4 net.IP `json:"blocking_ipv4"` - BlockingIPv6 net.IP `json:"blocking_ipv6"` EDNSCSEnabled *bool `json:"edns_cs_enabled"` DNSSECEnabled *bool `json:"dnssec_enabled"` DisableIPv6 *bool `json:"disable_ipv6"` @@ -41,9 +39,11 @@ type dnsConfig struct { ResolveClients *bool `json:"resolve_clients"` UsePrivateRDNS *bool `json:"use_private_ptr_resolvers"` LocalPTRUpstreams *[]string `json:"local_ptr_upstreams"` + BlockingIPv4 net.IP `json:"blocking_ipv4"` + BlockingIPv6 net.IP `json:"blocking_ipv6"` } -func (s *Server) getDNSConfig() (c *dnsConfig) { +func (s *Server) getDNSConfig() (c *jsonDNSConfig) { s.serverLock.RLock() defer s.serverLock.RUnlock() @@ -72,7 +72,7 @@ func (s *Server) getDNSConfig() (c *dnsConfig) { upstreamMode = "parallel" } - return &dnsConfig{ + return &jsonDNSConfig{ Upstreams: &upstreams, UpstreamsFile: &upstreamFile, Bootstraps: &bootstraps, @@ -102,13 +102,13 @@ func (s *Server) handleGetConfig(w http.ResponseWriter, r *http.Request) { } resp := struct { - dnsConfig + jsonDNSConfig // DefautLocalPTRUpstreams is used to pass the addresses from // systemResolvers to the front-end. It's not a pointer to the slice // since there is no need to omit it while decoding from JSON. DefautLocalPTRUpstreams []string `json:"default_local_ptr_upstreams,omitempty"` }{ - dnsConfig: *s.getDNSConfig(), + jsonDNSConfig: *s.getDNSConfig(), DefautLocalPTRUpstreams: defLocalPTRUps, } @@ -121,31 +121,21 @@ func (s *Server) handleGetConfig(w http.ResponseWriter, r *http.Request) { } } -func (req *dnsConfig) checkBlockingMode() bool { +func (req *jsonDNSConfig) checkBlockingMode() (err error) { if req.BlockingMode == nil { - return true + return nil } - switch bm := *req.BlockingMode; bm { - case BlockingModeDefault, - BlockingModeREFUSED, - BlockingModeNXDOMAIN, - BlockingModeNullIP: - return true - case BlockingModeCustomIP: - return req.BlockingIPv4.To4() != nil && req.BlockingIPv6 != nil - default: - return false - } + return validateBlockingMode(*req.BlockingMode, req.BlockingIPv4, req.BlockingIPv6) } -func (req *dnsConfig) checkUpstreamsMode() bool { +func (req *jsonDNSConfig) checkUpstreamsMode() bool { valid := []string{"", "fastest_addr", "parallel"} return req.UpstreamMode == nil || stringutil.InSlice(valid, *req.UpstreamMode) } -func (req *dnsConfig) checkBootstrap() (err error) { +func (req *jsonDNSConfig) checkBootstrap() (err error) { if req.Bootstraps == nil { return nil } @@ -167,7 +157,7 @@ func (req *dnsConfig) checkBootstrap() (err error) { } // validate returns an error if any field of req is invalid. -func (req *dnsConfig) validate(privateNets netutil.SubnetSet) (err error) { +func (req *jsonDNSConfig) validate(privateNets netutil.SubnetSet) (err error) { if req.Upstreams != nil { err = ValidateUpstreams(*req.Upstreams) if err != nil { @@ -187,9 +177,12 @@ func (req *dnsConfig) validate(privateNets netutil.SubnetSet) (err error) { return err } + err = req.checkBlockingMode() + if err != nil { + return err + } + switch { - case !req.checkBlockingMode(): - return errors.Error("blocking_mode: incorrect value") case !req.checkUpstreamsMode(): return errors.Error("upstream_mode: incorrect value") case !req.checkCacheTTL(): @@ -199,7 +192,7 @@ func (req *dnsConfig) validate(privateNets netutil.SubnetSet) (err error) { } } -func (req *dnsConfig) checkCacheTTL() bool { +func (req *jsonDNSConfig) checkCacheTTL() bool { if req.CacheMinTTL == nil && req.CacheMaxTTL == nil { return true } @@ -216,7 +209,7 @@ func (req *dnsConfig) checkCacheTTL() bool { } func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { - req := &dnsConfig{} + req := &jsonDNSConfig{} err := json.NewDecoder(r.Body).Decode(req) if err != nil { aghhttp.Error(r, w, http.StatusBadRequest, "decoding request: %s", err) @@ -242,100 +235,75 @@ func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { } } -func (s *Server) setConfigRestartable(dc *dnsConfig) (restart bool) { - if dc.Upstreams != nil { - s.conf.UpstreamDNS = *dc.Upstreams - restart = true - } - - if dc.LocalPTRUpstreams != nil { - s.conf.LocalPTRResolvers = *dc.LocalPTRUpstreams - restart = true - } - - if dc.UpstreamsFile != nil { - s.conf.UpstreamDNSFileName = *dc.UpstreamsFile - restart = true - } - - if dc.Bootstraps != nil { - s.conf.BootstrapDNS = *dc.Bootstraps - restart = true - } - - if dc.RateLimit != nil && s.conf.Ratelimit != *dc.RateLimit { - s.conf.Ratelimit = *dc.RateLimit - restart = true - } - - if dc.EDNSCSEnabled != nil { - s.conf.EnableEDNSClientSubnet = *dc.EDNSCSEnabled - restart = true - } - - if dc.CacheSize != nil { - s.conf.CacheSize = *dc.CacheSize - restart = true - } - - if dc.CacheMinTTL != nil { - s.conf.CacheMinTTL = *dc.CacheMinTTL - restart = true - } - - if dc.CacheMaxTTL != nil { - s.conf.CacheMaxTTL = *dc.CacheMaxTTL - restart = true - } - - if dc.CacheOptimistic != nil { - s.conf.CacheOptimistic = *dc.CacheOptimistic - restart = true - } - - return restart -} - -func (s *Server) setConfig(dc *dnsConfig) (restart bool) { +// setConfigRestartable sets the server parameters. shouldRestart is true if +// the server should be restarted to apply changes. +func (s *Server) setConfig(dc *jsonDNSConfig) (shouldRestart bool) { s.serverLock.Lock() defer s.serverLock.Unlock() - if dc.ProtectionEnabled != nil { - s.conf.ProtectionEnabled = *dc.ProtectionEnabled - } - if dc.BlockingMode != nil { s.conf.BlockingMode = *dc.BlockingMode - if *dc.BlockingMode == "custom_ip" { + if *dc.BlockingMode == BlockingModeCustomIP { s.conf.BlockingIPv4 = dc.BlockingIPv4.To4() s.conf.BlockingIPv6 = dc.BlockingIPv6.To16() } } - if dc.DNSSECEnabled != nil { - s.conf.EnableDNSSEC = *dc.DNSSECEnabled - } - - if dc.DisableIPv6 != nil { - s.conf.AAAADisabled = *dc.DisableIPv6 - } - if dc.UpstreamMode != nil { s.conf.AllServers = *dc.UpstreamMode == "parallel" s.conf.FastestAddr = *dc.UpstreamMode == "fastest_addr" } - if dc.ResolveClients != nil { - s.conf.ResolveClients = *dc.ResolveClients - } - - if dc.UsePrivateRDNS != nil { - s.conf.UsePrivateRDNS = *dc.UsePrivateRDNS - } + setIfNotNil(&s.conf.ProtectionEnabled, dc.ProtectionEnabled) + setIfNotNil(&s.conf.EnableDNSSEC, dc.DNSSECEnabled) + setIfNotNil(&s.conf.AAAADisabled, dc.DisableIPv6) + setIfNotNil(&s.conf.ResolveClients, dc.ResolveClients) + setIfNotNil(&s.conf.UsePrivateRDNS, dc.UsePrivateRDNS) return s.setConfigRestartable(dc) } +// setIfNotNil sets the value pointed at by currentPtr to the value pointed at +// by newPtr if newPtr is not nil. currentPtr must not be nil. +func setIfNotNil[T any](currentPtr, newPtr *T) (hasSet bool) { + if newPtr == nil { + return false + } + + *currentPtr = *newPtr + + return true +} + +// setConfigRestartable sets the parameters which trigger a restart. +// shouldRestart is true if the server should be restarted to apply changes. +// s.serverLock is expected to be locked. +func (s *Server) setConfigRestartable(dc *jsonDNSConfig) (shouldRestart bool) { + for _, hasSet := range []bool{ + setIfNotNil(&s.conf.UpstreamDNS, dc.Upstreams), + setIfNotNil(&s.conf.LocalPTRResolvers, dc.LocalPTRUpstreams), + setIfNotNil(&s.conf.UpstreamDNSFileName, dc.UpstreamsFile), + setIfNotNil(&s.conf.BootstrapDNS, dc.Bootstraps), + setIfNotNil(&s.conf.EnableEDNSClientSubnet, dc.EDNSCSEnabled), + setIfNotNil(&s.conf.CacheSize, dc.CacheSize), + setIfNotNil(&s.conf.CacheMinTTL, dc.CacheMinTTL), + setIfNotNil(&s.conf.CacheMaxTTL, dc.CacheMaxTTL), + setIfNotNil(&s.conf.CacheOptimistic, dc.CacheOptimistic), + } { + shouldRestart = shouldRestart || hasSet + if shouldRestart { + break + } + } + + if dc.RateLimit != nil && s.conf.Ratelimit != *dc.RateLimit { + s.conf.Ratelimit = *dc.RateLimit + shouldRestart = true + } + + return shouldRestart +} + // upstreamJSON is a request body for handleTestUpstreamDNS endpoint. type upstreamJSON struct { Upstreams []string `json:"upstream_dns"` @@ -711,11 +679,16 @@ func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { } } +// handleDoH is the DNS-over-HTTPs handler. +// // Control flow: -// web -// -> dnsforward.handleDoH -> dnsforward.ServeHTTP -// -> proxy.ServeHTTP -> proxy.handleDNSRequest -// -> dnsforward.handleDNSRequest +// +// HTTP server +// -> dnsforward.handleDoH +// -> dnsforward.ServeHTTP +// -> proxy.ServeHTTP +// -> proxy.handleDNSRequest +// -> dnsforward.handleDNSRequest func (s *Server) handleDoH(w http.ResponseWriter, r *http.Request) { if !s.conf.TLSAllowUnencryptedDoH && r.TLS == nil { aghhttp.Error(r, w, http.StatusNotFound, "Not Found") diff --git a/internal/dnsforward/http_test.go b/internal/dnsforward/http_test.go index 8863c6c6..1ae39455 100644 --- a/internal/dnsforward/http_test.go +++ b/internal/dnsforward/http_test.go @@ -62,6 +62,7 @@ func TestDNSForwardHTTP_handleGetConfig(t *testing.T) { TCPListenAddrs: []*net.TCPAddr{}, FilteringConfig: FilteringConfig{ ProtectionEnabled: true, + BlockingMode: BlockingModeDefault, UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"}, }, ConfigModified: func() {}, @@ -135,6 +136,7 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) { TCPListenAddrs: []*net.TCPAddr{}, FilteringConfig: FilteringConfig{ ProtectionEnabled: true, + BlockingMode: BlockingModeDefault, UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"}, }, ConfigModified: func() {}, @@ -164,7 +166,7 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) { wantSet: "", }, { name: "blocking_mode_bad", - wantSet: "blocking_mode: incorrect value", + wantSet: "blocking_ipv4 must be set when blocking_mode is custom_ip", }, { name: "ratelimit", wantSet: "", diff --git a/internal/dnsforward/msg.go b/internal/dnsforward/msg.go index c5333ba2..e6bd178e 100644 --- a/internal/dnsforward/msg.go +++ b/internal/dnsforward/msg.go @@ -37,66 +37,73 @@ func ipsFromRules(resRules []*filtering.ResultRule) (ips []net.IP) { return ips } -// genDNSFilterMessage generates a DNS message corresponding to the filtering result -func (s *Server) genDNSFilterMessage(d *proxy.DNSContext, result *filtering.Result) *dns.Msg { - m := d.Req - - if m.Question[0].Qtype != dns.TypeA && m.Question[0].Qtype != dns.TypeAAAA { +// genDNSFilterMessage generates a filtered response to req for the filtering +// result res. +func (s *Server) genDNSFilterMessage( + dctx *proxy.DNSContext, + res *filtering.Result, +) (resp *dns.Msg) { + req := dctx.Req + if qt := req.Question[0].Qtype; qt != dns.TypeA && qt != dns.TypeAAAA { if s.conf.BlockingMode == BlockingModeNullIP { - return s.makeResponse(m) + return s.makeResponse(req) } - return s.genNXDomain(m) + + return s.genNXDomain(req) } - ips := ipsFromRules(result.Rules) - switch result.Reason { + switch res.Reason { case filtering.FilteredSafeBrowsing: - return s.genBlockedHost(m, s.conf.SafeBrowsingBlockHost, d) + return s.genBlockedHost(req, s.conf.SafeBrowsingBlockHost, dctx) case filtering.FilteredParental: - return s.genBlockedHost(m, s.conf.ParentalBlockHost, d) + return s.genBlockedHost(req, s.conf.ParentalBlockHost, dctx) default: - // If the query was filtered by "Safe search", filtering also must return - // the IP address that must be used in response. - // In this case regardless of the filtering method, we should return it - if result.Reason == filtering.FilteredSafeSearch && len(ips) > 0 { - return s.genResponseWithIPs(m, ips) + // If the query was filtered by Safe Search, filtering also must return + // the IP addresses that must be used in response. Return them + // regardless of the filtering method. + ips := ipsFromRules(res.Rules) + if res.Reason == filtering.FilteredSafeSearch && len(ips) > 0 { + return s.genResponseWithIPs(req, ips) } - switch s.conf.BlockingMode { - case BlockingModeCustomIP: - switch m.Question[0].Qtype { - case dns.TypeA: - return s.genARecord(m, s.conf.BlockingIPv4) - case dns.TypeAAAA: - return s.genAAAARecord(m, s.conf.BlockingIPv6) - default: - // Generally shouldn't happen, since the types - // are checked above. - log.Error( - "dns: invalid msg type %d for blocking mode %s", - m.Question[0].Qtype, - s.conf.BlockingMode, - ) + return s.genForBlockingMode(req, ips) + } +} - return s.makeResponse(m) - } - case BlockingModeDefault: - if len(ips) > 0 { - return s.genResponseWithIPs(m, ips) - } - - return s.makeResponseNullIP(m) - case BlockingModeNullIP: - return s.makeResponseNullIP(m) - case BlockingModeNXDOMAIN: - return s.genNXDomain(m) - case BlockingModeREFUSED: - return s.makeResponseREFUSED(m) +// genForBlockingMode generates a filtered response to req based on the server's +// blocking mode. +func (s *Server) genForBlockingMode(req *dns.Msg, ips []net.IP) (resp *dns.Msg) { + qt := req.Question[0].Qtype + switch m := s.conf.BlockingMode; m { + case BlockingModeCustomIP: + switch qt { + case dns.TypeA: + return s.genARecord(req, s.conf.BlockingIPv4) + case dns.TypeAAAA: + return s.genAAAARecord(req, s.conf.BlockingIPv6) default: - log.Error("dns: invalid blocking mode %q", s.conf.BlockingMode) + // Generally shouldn't happen, since the types are checked in + // genDNSFilterMessage. + log.Error("dns: invalid msg type %s for blocking mode %s", dns.Type(qt), m) - return s.makeResponse(m) + return s.makeResponse(req) } + case BlockingModeDefault: + if len(ips) > 0 { + return s.genResponseWithIPs(req, ips) + } + + return s.makeResponseNullIP(req) + case BlockingModeNullIP: + return s.makeResponseNullIP(req) + case BlockingModeNXDOMAIN: + return s.genNXDomain(req) + case BlockingModeREFUSED: + return s.makeResponseREFUSED(req) + default: + log.Error("dns: invalid blocking mode %q", s.conf.BlockingMode) + + return s.makeResponse(req) } } diff --git a/internal/dnsforward/svcbmsg.go b/internal/dnsforward/svcbmsg.go index d1e3e3d8..96983dee 100644 --- a/internal/dnsforward/svcbmsg.go +++ b/internal/dnsforward/svcbmsg.go @@ -157,10 +157,10 @@ var svcbKeyHandlers = map[string]svcbKeyHandler{ // Firstly, the parsing of non-contiguous values isn't supported. Secondly, the // parsing of value-lists is not supported either. // -// ipv4hint=127.0.0.1 // Supported. -// ipv4hint="127.0.0.1" // Unsupported. -// ipv4hint=127.0.0.1,127.0.0.2 // Unsupported. -// ipv4hint="127.0.0.1,127.0.0.2" // Unsupported. +// ipv4hint=127.0.0.1 // Supported. +// ipv4hint="127.0.0.1" // Unsupported. +// ipv4hint=127.0.0.1,127.0.0.2 // Unsupported. +// ipv4hint="127.0.0.1,127.0.0.2" // Unsupported. // // TODO(a.garipov): Support all of these. func (s *Server) genAnswerSVCB(req *dns.Msg, svcb *rules.DNSSVCB) (ans *dns.SVCB) { diff --git a/internal/dnsforward/testdata/TestDNSForwardHTTP_handleGetConfig.json b/internal/dnsforward/testdata/TestDNSForwardHTTP_handleGetConfig.json index 538865c5..3ac6f2f5 100644 --- a/internal/dnsforward/testdata/TestDNSForwardHTTP_handleGetConfig.json +++ b/internal/dnsforward/testdata/TestDNSForwardHTTP_handleGetConfig.json @@ -13,7 +13,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -42,7 +42,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -71,7 +71,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -86,4 +86,4 @@ "use_private_ptr_resolvers": false, "local_ptr_upstreams": [] } -} \ No newline at end of file +} diff --git a/internal/dnsforward/testdata/TestDNSForwardHTTP_handleSetConfig.json b/internal/dnsforward/testdata/TestDNSForwardHTTP_handleSetConfig.json index 830bf491..f55359a9 100644 --- a/internal/dnsforward/testdata/TestDNSForwardHTTP_handleSetConfig.json +++ b/internal/dnsforward/testdata/TestDNSForwardHTTP_handleSetConfig.json @@ -20,7 +20,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -53,7 +53,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -121,7 +121,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -155,7 +155,7 @@ ], "protection_enabled": true, "ratelimit": 6, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -189,7 +189,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": true, @@ -223,7 +223,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -257,7 +257,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -291,7 +291,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -325,7 +325,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -361,7 +361,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -397,7 +397,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -432,7 +432,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -466,7 +466,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -502,7 +502,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -541,7 +541,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, @@ -575,7 +575,7 @@ ], "protection_enabled": true, "ratelimit": 0, - "blocking_mode": "", + "blocking_mode": "default", "blocking_ipv4": "", "blocking_ipv6": "", "edns_cs_enabled": false, diff --git a/internal/filtering/blocked.go b/internal/filtering/blocked.go index 665b62d4..08866100 100644 --- a/internal/filtering/blocked.go +++ b/internal/filtering/blocked.go @@ -7,21 +7,24 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/urlfilter/rules" + "golang.org/x/exp/slices" ) -var serviceRules map[string][]*rules.NetworkRule // service name -> filtering rules - +// svc represents a single blocked service. type svc struct { name string rules []string } +// servicesData contains raw blocked service data. +// // Keep in sync with: -// client/src/helpers/constants.js -// client/src/components/ui/Icons.js -var serviceRulesArray = []svc{{ +// - client/src/helpers/constants.js +// - client/src/components/ui/Icons.js +var servicesData = []svc{{ name: "whatsapp", rules: []string{ + "||wa.me^", "||whatsapp.com^", "||whatsapp.net^", }, @@ -34,7 +37,9 @@ var serviceRulesArray = []svc{{ "||accountkit.com^", "||fb.me^", "||fb.com^", + "||fb.gg^", "||fbsbx.com^", + "||fbwat.ch^", "||messenger.com^", "||facebookcorewwwi.onion^", "||fbcdn.com^", @@ -58,6 +63,7 @@ var serviceRulesArray = []svc{{ "||youtube-nocookie.com^", "||youtube.com^", "||youtubei.googleapis.com^", + "||youtubekids.com^", "||ytimg.com^", }, }, { @@ -97,20 +103,36 @@ var serviceRulesArray = []svc{{ "||discordapp.net^", "||discordapp.com^", "||discord.com^", + "||discord.gift", "||discord.media^", }, }, { name: "ok", rules: []string{"||ok.ru^"}, }, { - name: "skype", - rules: []string{"||skype.com^", "||skypeassets.com^"}, + name: "skype", + rules: []string{ + "||edge-skype-com.s-0001.s-msedge.net^", + "||skype-edf.akadns.net^", + "||skype.com^", + "||skypeassets.com^", + "||skypedata.akadns.net^", + }, }, { - name: "vk", - rules: []string{"||vk.com^", "||userapi.com^", "||vk-cdn.net^", "||vkuservideo.net^"}, + name: "vk", + rules: []string{ + "||userapi.com^", + "||vk-cdn.net^", + "||vk.com^", + "||vkuservideo.net^", + }, }, { - name: "origin", - rules: []string{"||origin.com^", "||signin.ea.com^", "||accounts.ea.com^"}, + name: "origin", + rules: []string{ + "||accounts.ea.com^", + "||origin.com^", + "||signin.ea.com^", + }, }, { name: "steam", rules: []string{ @@ -133,20 +155,30 @@ var serviceRulesArray = []svc{{ }, { name: "cloudflare", rules: []string{ - "||cloudflare.com^", - "||cloudflare-dns.com^", - "||cloudflare.net^", - "||cloudflareinsights.com^", - "||cloudflarestream.com^", - "||cloudflareresolve.com^", - "||cloudflareclient.com^", - "||cloudflarebolt.com^", - "||cloudflarestatus.com^", - "||cloudflare.cn^", - "||one.one^", - "||warp.plus^", "||1.1.1.1^", + "||argotunnel.com^", + "||cloudflare-dns.com^", + "||cloudflare-ipfs.com^", + "||cloudflare-quic.com^", + "||cloudflare.cn^", + "||cloudflare.com^", + "||cloudflare.net^", + "||cloudflareaccess.com^", + "||cloudflareapps.com^", + "||cloudflarebolt.com^", + "||cloudflareclient.com^", + "||cloudflareinsights.com^", + "||cloudflareresolve.com^", + "||cloudflarestatus.com^", + "||cloudflarestream.com^", + "||cloudflarewarp.com^", "||dns4torpnlfs2ifuz2s2yf3fc7rdmsbhm6rw75euj35pac6ap25zgqad.onion^", + "||one.one^", + "||pages.dev^", + "||trycloudflare.com^", + "||videodelivery.net^", + "||warp.plus^", + "||workers.dev^", }, }, { name: "amazon", @@ -174,6 +206,7 @@ var serviceRulesArray = []svc{{ "||amazon.com.br^", "||amazon.co.jp^", "||amazon.com.mx^", + "||amazon.com.tr^", "||amazon.co.uk^", "||createspace.com^", "||aws", @@ -210,27 +243,31 @@ var serviceRulesArray = []svc{{ }, { name: "tiktok", rules: []string{ - "||tiktok.com^", - "||tiktokcdn.com^", - "||musical.ly^", - "||snssdk.com^", "||amemv.com^", - "||toutiao.com^", - "||ixigua.com^", - "||pstatp.com^", - "||ixiguavideo.com^", - "||toutiaocloud.com^", - "||toutiaocloud.net^", "||bdurl.com^", "||bytecdn.cn^", - "||byteimg.com^", - "||ixigua.com^", - "||muscdn.com^", "||bytedance.map.fastly.net^", + "||bytedapm.com^", + "||byteimg.com^", + "||byteoversea.com^", "||douyin.com^", - "||tiktokv.com^", - "||toutiaovod.com^", "||douyincdn.com^", + "||douyinpic.com^", + "||douyinstatic.com^", + "||douyinvod.com^", + "||ixigua.com^", + "||ixiguavideo.com^", + "||muscdn.com^", + "||musical.ly^", + "||pstatp.com^", + "||snssdk.com^", + "||tiktok.com^", + "||tiktokcdn.com^", + "||tiktokv.com^", + "||toutiao.com^", + "||toutiaocloud.com^", + "||toutiaocloud.net^", + "||toutiaovod.com^", }, }, { name: "vimeo", @@ -300,9 +337,13 @@ var serviceRulesArray = []svc{{ name: "disneyplus", rules: []string{ "||disney-plus.net^", - "||disneyplus.com^", "||disney.playback.edge.bamgrid.com^", + "||disneynow.com^", + "||disneyplus.com^", + "||hotstar.com^", "||media.dssott.com^", + "||star.playback.edge.bamgrid.com^", + "||starplus.com^", }, }, { name: "hulu", @@ -332,8 +373,11 @@ var serviceRulesArray = []svc{{ }, { name: "bilibili", rules: []string{ + "||b23.tv^", "||biliapi.net^", "||bilibili.com^", + "||bilicdn1.com^", + "||bilicdn2.com^", "||biligame.com^", "||bilivideo.cn^", "||bilivideo.com^", @@ -342,21 +386,38 @@ var serviceRulesArray = []svc{{ }, }} -// convert array to map +// serviceRules maps a service ID to its filtering rules. +var serviceRules map[string][]*rules.NetworkRule + +// serviceIDs contains service IDs sorted alphabetically. +var serviceIDs []string + +// initBlockedServices initializes package-level blocked service data. func initBlockedServices() { - serviceRules = make(map[string][]*rules.NetworkRule) - for _, s := range serviceRulesArray { - netRules := []*rules.NetworkRule{} + l := len(servicesData) + serviceIDs = make([]string, l) + serviceRules = make(map[string][]*rules.NetworkRule, l) + + for i, s := range servicesData { + netRules := make([]*rules.NetworkRule, 0, len(s.rules)) for _, text := range s.rules { rule, err := rules.NewNetworkRule(text, BlockedSvcsListID) if err != nil { - log.Error("rules.NewNetworkRule: %s rule: %s", err, text) + log.Error("parsing blocked service %q rule %q: %s", s.name, text, err) + continue } + netRules = append(netRules, rule) } + + serviceIDs[i] = s.name serviceRules[s.name] = netRules } + + slices.Sort(serviceIDs) + + log.Debug("filtering: initialized %d services", l) } // BlockedSvcKnown - return TRUE if a blocked service name is known @@ -388,6 +449,16 @@ func (d *DNSFilter) ApplyBlockedServices(setts *Settings, list []string, global } } +func (d *DNSFilter) handleBlockedServicesAvailableServices(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + err := json.NewEncoder(w).Encode(serviceIDs) + if err != nil { + aghhttp.Error(r, w, http.StatusInternalServerError, "encoding available services: %s", err) + + return + } +} + func (d *DNSFilter) handleBlockedServicesList(w http.ResponseWriter, r *http.Request) { d.confLock.RLock() list := d.Config.BlockedServices @@ -396,7 +467,7 @@ func (d *DNSFilter) handleBlockedServicesList(w http.ResponseWriter, r *http.Req w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(list) if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "json.Encode: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "encoding services: %s", err) return } @@ -422,6 +493,7 @@ func (d *DNSFilter) handleBlockedServicesSet(w http.ResponseWriter, r *http.Requ // registerBlockedServicesHandlers - register HTTP handlers func (d *DNSFilter) registerBlockedServicesHandlers() { + d.Config.HTTPRegister(http.MethodGet, "/control/blocked_services/services", d.handleBlockedServicesAvailableServices) d.Config.HTTPRegister(http.MethodGet, "/control/blocked_services/list", d.handleBlockedServicesList) d.Config.HTTPRegister(http.MethodPost, "/control/blocked_services/set", d.handleBlockedServicesSet) } diff --git a/internal/filtering/dnsrewrite.go b/internal/filtering/dnsrewrite.go index 5263f252..58a8dd7b 100644 --- a/internal/filtering/dnsrewrite.go +++ b/internal/filtering/dnsrewrite.go @@ -34,8 +34,8 @@ func (d *DNSFilter) processDNSRewrites(dnsr []*rules.NetworkRule) (res Result) { }} return Result{ - Reason: RewrittenRule, Rules: rules, + Reason: RewrittenRule, CanonName: dr.NewCNAME, } } @@ -60,16 +60,16 @@ func (d *DNSFilter) processDNSRewrites(dnsr []*rules.NetworkRule) (res Result) { } return Result{ - Reason: RewrittenRule, - Rules: rules, DNSRewriteResult: dnsrr, + Rules: rules, + Reason: RewrittenRule, } } } return Result{ - Reason: RewrittenRule, - Rules: rules, DNSRewriteResult: dnsrr, + Rules: rules, + Reason: RewrittenRule, } } diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index 4a3e6b28..446ad4ac 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -296,9 +296,11 @@ func cloneRewrites(entries []*LegacyRewrite) (clone []*LegacyRewrite) { return clone } -// SetFilters - set new filters (synchronously or asynchronously) -// When filters are set asynchronously, the old filters continue working until the new filters are ready. -// In this case the caller must ensure that the old filter files are intact. +// SetFilters sets new filters, synchronously or asynchronously. When filters +// are set asynchronously, the old filters continue working until the new +// filters are ready. +// +// In this case the caller must ensure that the old filter files are intact. func (d *DNSFilter) SetFilters(blockFilters, allowFilters []Filter, async bool) error { if async { params := filtersInitializerParams{ @@ -388,18 +390,8 @@ type ResultRule struct { // TODO(a.garipov): Clarify relationships between fields. Perhaps // replace with a sum type or an interface? type Result struct { - // IsFiltered is true if the request is filtered. - IsFiltered bool `json:",omitempty"` - - // Reason is the reason for blocking or unblocking the request. - Reason Reason `json:",omitempty"` - - // Rules are applied rules. If Rules are not empty, each rule is not nil. - Rules []*ResultRule `json:",omitempty"` - - // IPList is the lookup rewrite result. It is empty unless Reason is set to - // Rewritten. - IPList []net.IP `json:",omitempty"` + // DNSRewriteResult is the $dnsrewrite filter rule result. + DNSRewriteResult *DNSRewriteResult `json:",omitempty"` // CanonName is the CNAME value from the lookup rewrite result. It is empty // unless Reason is set to Rewritten or RewrittenRule. @@ -409,8 +401,18 @@ type Result struct { // Reason is set to FilteredBlockedService. ServiceName string `json:",omitempty"` - // DNSRewriteResult is the $dnsrewrite filter rule result. - DNSRewriteResult *DNSRewriteResult `json:",omitempty"` + // IPList is the lookup rewrite result. It is empty unless Reason is set to + // Rewritten. + IPList []net.IP `json:",omitempty"` + + // Rules are applied rules. If Rules are not empty, each rule is not nil. + Rules []*ResultRule `json:",omitempty"` + + // Reason is the reason for blocking or unblocking the request. + Reason Reason `json:",omitempty"` + + // IsFiltered is true if the request is filtered. + IsFiltered bool `json:",omitempty"` } // Matched returns true if any match at all was found regardless of @@ -872,9 +874,9 @@ func makeResult(matchedRules []rules.Rule, reason Reason) (res Result) { } return Result{ - IsFiltered: reason == FilteredBlockList, - Reason: reason, Rules: resRules, + Reason: reason, + IsFiltered: reason == FilteredBlockList, } } diff --git a/internal/filtering/rewrites.go b/internal/filtering/rewrites.go index dab4c034..c1557158 100644 --- a/internal/filtering/rewrites.go +++ b/internal/filtering/rewrites.go @@ -130,10 +130,9 @@ func matchDomainWildcard(host, wildcard string) (ok bool) { // // The sorting priority: // -// A and AAAA > CNAME -// wildcard > exact -// lower level wildcard > higher level wildcard -// +// 1. A and AAAA > CNAME +// 2. wildcard > exact +// 3. lower level wildcard > higher level wildcard type rewritesSorted []*LegacyRewrite // Len implements the sort.Interface interface for legacyRewritesSorted. diff --git a/internal/filtering/safebrowsing.go b/internal/filtering/safebrowsing.go index e49c4070..9d1d0fa4 100644 --- a/internal/filtering/safebrowsing.go +++ b/internal/filtering/safebrowsing.go @@ -325,12 +325,12 @@ func (d *DNSFilter) checkSafeBrowsing( } res = Result{ - IsFiltered: true, - Reason: FilteredSafeBrowsing, Rules: []*ResultRule{{ Text: "adguard-malware-shavar", FilterListID: SafeBrowsingListID, }}, + Reason: FilteredSafeBrowsing, + IsFiltered: true, } return check(sctx, res, d.safeBrowsingUpstream) @@ -359,12 +359,12 @@ func (d *DNSFilter) checkParental( } res = Result{ - IsFiltered: true, - Reason: FilteredParental, Rules: []*ResultRule{{ Text: "parental CATEGORY_BLACKLISTED", FilterListID: ParentalListID, }}, + Reason: FilteredParental, + IsFiltered: true, } return check(sctx, res, d.parentalUpstream) diff --git a/internal/filtering/safesearch.go b/internal/filtering/safesearch.go index 23751cb0..df2d2108 100644 --- a/internal/filtering/safesearch.go +++ b/internal/filtering/safesearch.go @@ -98,11 +98,11 @@ func (d *DNSFilter) checkSafeSearch( } res = Result{ - IsFiltered: true, - Reason: FilteredSafeSearch, Rules: []*ResultRule{{ FilterListID: SafeSearchListID, }}, + Reason: FilteredSafeSearch, + IsFiltered: true, } if ip := net.ParseIP(safeHost); ip != nil { diff --git a/internal/home/clients_test.go b/internal/home/clients_test.go index 629d7c69..8afd5621 100644 --- a/internal/home/clients_test.go +++ b/internal/home/clients_test.go @@ -9,6 +9,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/dhcpd" "github.com/AdguardTeam/golibs/testutil" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/internal/home/config.go b/internal/home/config.go index 5bd9b98b..7ac6470e 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -203,9 +203,9 @@ var config = &configuration{ Port: defaultPortDNS, StatsInterval: 1, FilteringConfig: dnsforward.FilteringConfig{ - ProtectionEnabled: true, // whether or not use any of filtering features - BlockingMode: "default", // mode how to answer filtered requests - BlockedResponseTTL: 10, // in seconds + ProtectionEnabled: true, // whether or not use any of filtering features + BlockingMode: dnsforward.BlockingModeDefault, + BlockedResponseTTL: 10, // in seconds Ratelimit: 20, RefuseAny: true, AllServers: false, diff --git a/internal/home/dns.go b/internal/home/dns.go index 572e22fe..9741d19b 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -281,10 +281,10 @@ func newDNSCrypt(hosts []net.IP, tlsConf tlsConfigSettings) (dnscc dnsforward.DN } return dnsforward.DNSCryptConfig{ - UDPListenAddrs: ipsToUDPAddrs(hosts, tlsConf.PortDNSCrypt), - TCPListenAddrs: ipsToTCPAddrs(hosts, tlsConf.PortDNSCrypt), ResolverCert: cert, ProviderName: rc.ProviderName, + UDPListenAddrs: ipsToUDPAddrs(hosts, tlsConf.PortDNSCrypt), + TCPListenAddrs: ipsToTCPAddrs(hosts, tlsConf.PortDNSCrypt), Enabled: true, }, nil } diff --git a/internal/home/filter.go b/internal/home/filter.go index e7688f3f..78abd76a 100644 --- a/internal/home/filter.go +++ b/internal/home/filter.go @@ -267,7 +267,8 @@ func (f *Filtering) periodicallyRefreshFilters() { // Refresh filters // flags: filterRefresh* // important: -// TRUE: ignore the fact that we're currently updating the filters +// +// TRUE: ignore the fact that we're currently updating the filters func (f *Filtering) refreshFilters(flags int, important bool) (int, error) { set := atomic.CompareAndSwapUint32(&f.refreshStatus, 0, 1) if !important && !set { @@ -363,25 +364,24 @@ const ( filterRefreshBlocklists = 4 // update block-lists ) -// Checks filters updates if necessary -// If force is true, it ignores the filter.LastUpdated field value -// flags: filterRefresh* +// refreshFiltersIfNecessary checks filters and updates them if necessary. If +// force is true, it ignores the filter.LastUpdated field value. // // Algorithm: -// . Get the list of filters to be updated -// . For each filter run the download and checksum check operation -// . Store downloaded data in a temporary file inside data/filters directory -// . For each filter: -// . If filter data hasn't changed, just set new update time on file -// . If filter data has changed: -// . rename the temporary file ( -> 1.txt) -// Note that this method works only on UNIX. -// On Windows we don't pass files to filtering - we pass the whole data. -// . Pass new filters to filtering object - it analyzes new data while the old filters are still active -// . filtering activates new filters // -// Return the number of updated filters -// Return TRUE - there was a network error and nothing could be updated +// 1. Get the list of filters to be updated. For each filter, run the download +// and checksum check operation. Store downloaded data in a temporary file +// inside data/filters directory +// +// 2. For each filter, if filter data hasn't changed, just set new update time +// on file. Otherwise, rename the temporary file ( -> 1.txt). Note +// that this method works only on Unix systems. On Windows, don't pass +// files to filtering, pass the whole data. +// +// refreshFiltersIfNecessary returns the number of updated filters. It also +// returns true if there was a network error and nothing could be updated. +// +// TODO(a.garipov, e.burkov): What the hell? func (f *Filtering) refreshFiltersIfNecessary(flags int) (int, bool) { log.Debug("Filters: updating...") diff --git a/internal/home/home.go b/internal/home/home.go index 9ca53c55..4eb71494 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -741,11 +741,10 @@ func loadOptions() options { // printWebAddrs prints addresses built from proto, addr, and an appropriate // port. At least one address is printed with the value of port. If the value -// of betaPort is 0, the second address is not printed. The output example: -// -// Go to http://127.0.0.1:80 -// Go to http://127.0.0.1:3000 (BETA) +// of betaPort is 0, the second address is not printed. Output example: // +// Go to http://127.0.0.1:80 +// Go to http://127.0.0.1:3000 (BETA) func printWebAddrs(proto, addr string, port, betaPort int) { const ( hostMsg = "Go to %s://%s" diff --git a/internal/home/service.go b/internal/home/service.go index 831a80d0..20367718 100644 --- a/internal/home/service.go +++ b/internal/home/service.go @@ -159,15 +159,16 @@ func sendSigReload() { } // handleServiceControlAction one of the possible control actions: -// install -- installs a service/daemon -// uninstall -- uninstalls it -// status -- prints the service status -// start -- starts the previously installed service -// stop -- stops the previously installed service -// restart - restarts the previously installed service -// run - this is a special command that is not supposed to be used directly -// it is specified when we register a service, and it indicates to the app -// that it is being run as a service/daemon. +// +// - install: Installs a service/daemon. +// - uninstall: Uninstalls it. +// - status: Prints the service status. +// - start: Starts the previously installed service. +// - stop: Stops the previously installed service. +// - restart: Restarts the previously installed service. +// - run: This is a special command that is not supposed to be used directly +// it is specified when we register a service, and it indicates to the app +// that it is being run as a service/daemon. func handleServiceControlAction(opts options, clientBuildFS fs.FS) { // Call chooseSystem explicitly to introduce OpenBSD support for service // package. It's a noop for other GOOS values. @@ -397,12 +398,11 @@ var launchdConfig = ` // the systemdScript constant in file service_systemd_linux.go in module // github.com/kardianos/service. The following changes have been made: // -// 1. The RestartSec setting is set to a lower value of 10 to make sure we +// 1. The RestartSec setting is set to a lower value of 10 to make sure we // always restart quickly. // -// 2. The ExecStartPre setting is added to make sure that the log directory is +// 2. The ExecStartPre setting is added to make sure that the log directory is // always created to prevent the 209/STDOUT errors. -// const systemdScript = `[Unit] Description={{.Description}} ConditionFileIsExecutable={{.Path|cmdEscape}} diff --git a/internal/home/tls.go b/internal/home/tls.go index fbeabbce..a31d3b9d 100644 --- a/internal/home/tls.go +++ b/internal/home/tls.go @@ -569,10 +569,9 @@ func validatePkey(data *tlsConfigStatus, pkey string) error { return nil } -// Process certificate data and its private key. -// All parameters are optional. -// On error, return partially set object -// with 'WarningValidation' field containing error description. +// validateCertificates processes certificate data and its private key. All +// parameters are optional. On error, validateCertificates returns a partially +// set object with field WarningValidation containing error description. func validateCertificates(certChain, pkey, serverName string) tlsConfigStatus { var data tlsConfigStatus diff --git a/internal/home/upgrade.go b/internal/home/upgrade.go index 4426149c..63e17030 100644 --- a/internal/home/upgrade.go +++ b/internal/home/upgrade.go @@ -240,8 +240,9 @@ func upgradeSchema3to4(diskConf yobj) error { // Replace "auth_name", "auth_pass" string settings with an array: // users: -// - name: "..." -// password: "..." +// - name: "..." +// password: "..." +// // ... func upgradeSchema4to5(diskConf yobj) error { log.Printf("%s(): called", funcName()) @@ -288,16 +289,18 @@ func upgradeSchema4to5(diskConf yobj) error { // clients: // ... -// ip: 127.0.0.1 -// mac: ... +// +// ip: 127.0.0.1 +// mac: ... // // -> // // clients: // ... -// ids: -// - 127.0.0.1 -// - ... +// +// ids: +// - 127.0.0.1 +// - ... func upgradeSchema5to6(diskConf yobj) error { log.Printf("%s(): called", funcName()) @@ -355,19 +358,21 @@ func upgradeSchema5to6(diskConf yobj) error { } // dhcp: -// enabled: false -// interface_name: vboxnet0 -// gateway_ip: 192.168.56.1 -// ... +// +// enabled: false +// interface_name: vboxnet0 +// gateway_ip: 192.168.56.1 +// ... // // -> // // dhcp: -// enabled: false -// interface_name: vboxnet0 -// dhcpv4: -// gateway_ip: 192.168.56.1 -// ... +// +// enabled: false +// interface_name: vboxnet0 +// dhcpv4: +// gateway_ip: 192.168.56.1 +// ... func upgradeSchema6to7(diskConf yobj) error { log.Printf("Upgrade yaml: 6 to 7") @@ -443,15 +448,14 @@ func upgradeSchema6to7(diskConf yobj) error { // upgradeSchema7to8 performs the following changes: // -// # BEFORE: -// 'dns': -// 'bind_host': '127.0.0.1' -// -// # AFTER: -// 'dns': -// 'bind_hosts': -// - '127.0.0.1' +// # BEFORE: +// 'dns': +// 'bind_host': '127.0.0.1' // +// # AFTER: +// 'dns': +// 'bind_hosts': +// - '127.0.0.1' func upgradeSchema7to8(diskConf yobj) (err error) { log.Printf("Upgrade yaml: 7 to 8") @@ -481,14 +485,13 @@ func upgradeSchema7to8(diskConf yobj) (err error) { // upgradeSchema8to9 performs the following changes: // -// # BEFORE: -// 'dns': -// 'autohost_tld': 'lan' -// -// # AFTER: -// 'dns': -// 'local_domain_name': 'lan' +// # BEFORE: +// 'dns': +// 'autohost_tld': 'lan' // +// # AFTER: +// 'dns': +// 'local_domain_name': 'lan' func upgradeSchema8to9(diskConf yobj) (err error) { log.Printf("Upgrade yaml: 8 to 9") @@ -564,16 +567,15 @@ func addQUICPort(ups string, port int) (withPort string) { // upgradeSchema9to10 performs the following changes: // -// # BEFORE: -// 'dns': -// 'upstream_dns': -// - 'quic://some-upstream.com' -// -// # AFTER: -// 'dns': -// 'upstream_dns': -// - 'quic://some-upstream.com:784' +// # BEFORE: +// 'dns': +// 'upstream_dns': +// - 'quic://some-upstream.com' // +// # AFTER: +// 'dns': +// 'upstream_dns': +// - 'quic://some-upstream.com:784' func upgradeSchema9to10(diskConf yobj) (err error) { log.Printf("Upgrade yaml: 9 to 10") @@ -623,15 +625,14 @@ func upgradeSchema9to10(diskConf yobj) (err error) { // upgradeSchema10to11 performs the following changes: // -// # BEFORE: -// 'rlimit_nofile': 42 -// -// # AFTER: -// 'os': -// 'group': '' -// 'rlimit_nofile': 42 -// 'user': '' +// # BEFORE: +// 'rlimit_nofile': 42 // +// # AFTER: +// 'os': +// 'group': '' +// 'rlimit_nofile': 42 +// 'user': '' func upgradeSchema10to11(diskConf yobj) (err error) { log.Printf("Upgrade yaml: 10 to 11") @@ -658,12 +659,11 @@ func upgradeSchema10to11(diskConf yobj) (err error) { // upgradeSchema11to12 performs the following changes: // -// # BEFORE: -// 'querylog_interval': 90 -// -// # AFTER: -// 'querylog_interval': '2160h' +// # BEFORE: +// 'querylog_interval': 90 // +// # AFTER: +// 'querylog_interval': '2160h' func upgradeSchema11to12(diskConf yobj) (err error) { log.Printf("Upgrade yaml: 11 to 12") diskConf["schema_version"] = 12 @@ -698,16 +698,15 @@ func upgradeSchema11to12(diskConf yobj) (err error) { // upgradeSchema12to13 performs the following changes: // -// # BEFORE: -// 'dns': -// # … -// 'local_domain_name': 'lan' -// -// # AFTER: -// 'dhcp': -// # … -// 'local_domain_name': 'lan' +// # BEFORE: +// 'dns': +// # … +// 'local_domain_name': 'lan' // +// # AFTER: +// 'dhcp': +// # … +// 'local_domain_name': 'lan' func upgradeSchema12to13(diskConf yobj) (err error) { log.Printf("Upgrade yaml: 12 to 13") diskConf["schema_version"] = 13 @@ -744,23 +743,22 @@ func upgradeSchema12to13(diskConf yobj) (err error) { // upgradeSchema13to14 performs the following changes: // -// # BEFORE: -// 'clients': -// - 'name': 'client-name' -// # … -// -// # AFTER: -// 'clients': -// 'persistent': -// - 'name': 'client-name' -// # … -// 'runtime_sources': -// 'whois': true -// 'arp': true -// 'rdns': true -// 'dhcp': true -// 'hosts': true +// # BEFORE: +// 'clients': +// - 'name': 'client-name' +// # … // +// # AFTER: +// 'clients': +// 'persistent': +// - 'name': 'client-name' +// # … +// 'runtime_sources': +// 'whois': true +// 'arp': true +// 'rdns': true +// 'dhcp': true +// 'hosts': true func upgradeSchema13to14(diskConf yobj) (err error) { log.Printf("Upgrade yaml: 13 to 14") diskConf["schema_version"] = 14 diff --git a/internal/querylog/decode_test.go b/internal/querylog/decode_test.go index c5d45280..aa3de021 100644 --- a/internal/querylog/decode_test.go +++ b/internal/querylog/decode_test.go @@ -63,9 +63,15 @@ func TestDecodeLogEntry(t *testing.T) { Answer: ans, Cached: true, Result: filtering.Result{ - IsFiltered: true, - Reason: filtering.FilteredBlockList, - IPList: []net.IP{net.IPv4(127, 0, 0, 2)}, + DNSRewriteResult: &filtering.DNSRewriteResult{ + RCode: dns.RcodeSuccess, + Response: filtering.DNSRewriteResultResponse{ + dns.TypeA: []rules.RRValue{net.IPv4(127, 0, 0, 2)}, + }, + }, + CanonName: "example.com", + ServiceName: "example.org", + IPList: []net.IP{net.IPv4(127, 0, 0, 2)}, Rules: []*filtering.ResultRule{{ FilterListID: 42, Text: "||an.yandex.ru", @@ -75,14 +81,8 @@ func TestDecodeLogEntry(t *testing.T) { Text: "||an2.yandex.ru", IP: net.IPv4(127, 0, 0, 3), }}, - CanonName: "example.com", - ServiceName: "example.org", - DNSRewriteResult: &filtering.DNSRewriteResult{ - RCode: dns.RcodeSuccess, - Response: filtering.DNSRewriteResultResponse{ - dns.TypeA: []rules.RRValue{net.IPv4(127, 0, 0, 2)}, - }, - }, + Reason: filtering.FilteredBlockList, + IsFiltered: true, }, Upstream: "https://some.upstream", Elapsed: 837429, diff --git a/internal/querylog/qlog_test.go b/internal/querylog/qlog_test.go index 6beed1be..f33401cc 100644 --- a/internal/querylog/qlog_test.go +++ b/internal/querylog/qlog_test.go @@ -271,13 +271,13 @@ func addEntry(l *queryLog, host string, answerStr, client net.IP) { } res := filtering.Result{ - IsFiltered: true, - Reason: filtering.Rewritten, ServiceName: "SomeService", Rules: []*filtering.ResultRule{{ FilterListID: 1, Text: "SomeRule", }}, + Reason: filtering.Rewritten, + IsFiltered: true, } params := &AddParams{ diff --git a/internal/stats/stats.go b/internal/stats/stats.go index e483dbba..e9397907 100644 --- a/internal/stats/stats.go +++ b/internal/stats/stats.go @@ -385,43 +385,47 @@ func (s *StatsCtx) flush() (cont bool, sleepFor time.Duration) { return true, 0 } + isCommitable := true tx, err := db.Begin(true) if err != nil { log.Error("stats: opening transaction: %s", err) return true, 0 } + defer func() { + if err = finishTxn(tx, isCommitable); err != nil { + log.Error("stats: %s", err) + } + }() s.curr = newUnit(id) - isCommitable := true - ferr := ptr.serialize().flushUnitToDB(tx, ptr.id) - if ferr != nil { - log.Error("stats: flushing unit: %s", ferr) + flushErr := ptr.serialize().flushUnitToDB(tx, ptr.id) + if flushErr != nil { + log.Error("stats: flushing unit: %s", flushErr) isCommitable = false } - derr := tx.DeleteBucket(idToUnitName(id - limit)) - if derr != nil { - log.Error("stats: deleting unit: %s", derr) - if !errors.Is(derr, bbolt.ErrBucketNotFound) { + delErr := tx.DeleteBucket(idToUnitName(id - limit)) + if delErr != nil { + // TODO(e.burkov): Improve the algorithm of deleting the oldest bucket + // to avoid the error. + if errors.Is(delErr, bbolt.ErrBucketNotFound) { + log.Debug("stats: warning: deleting unit: %s", delErr) + } else { isCommitable = false + log.Error("stats: deleting unit: %s", delErr) } } - err = finishTxn(tx, isCommitable) - if err != nil { - log.Error("stats: %s", err) - } - return true, 0 } // periodicFlush checks and flushes the unit to the database if the freshly // generated unit ID differs from the current's ID. Flushing process includes: -// - swapping the current unit with the new empty one; -// - writing the current unit to the database; -// - removing the stale unit from the database. +// - swapping the current unit with the new empty one; +// - writing the current unit to the database; +// - removing the stale unit from the database. func (s *StatsCtx) periodicFlush() { for cont, sleepFor := true, time.Duration(0); cont; time.Sleep(sleepFor) { cont, sleepFor = s.flush() diff --git a/internal/stats/stats_internal_test.go b/internal/stats/stats_internal_test.go index 28a556d3..7d5d9fef 100644 --- a/internal/stats/stats_internal_test.go +++ b/internal/stats/stats_internal_test.go @@ -1,8 +1,14 @@ package stats import ( + "fmt" + "path/filepath" + "sync" + "sync/atomic" "testing" + "time" + "github.com/AdguardTeam/golibs/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -24,3 +30,76 @@ func TestStatsCollector(t *testing.T) { } }) } + +func TestStats_races(t *testing.T) { + var r uint32 + idGen := func() (id uint32) { return atomic.LoadUint32(&r) } + conf := Config{ + UnitID: idGen, + Filename: filepath.Join(t.TempDir(), "./stats.db"), + LimitDays: 1, + } + + s, err := New(conf) + require.NoError(t, err) + + s.Start() + startTime := time.Now() + testutil.CleanupAndRequireSuccess(t, s.Close) + + type signal = struct{} + + writeFunc := func(start, fin *sync.WaitGroup, waitCh <-chan unit, i int) { + e := Entry{ + Domain: fmt.Sprintf("example-%d.org", i), + Client: fmt.Sprintf("client_%d", i), + Result: Result(i)%(resultLast-1) + 1, + Time: uint32(time.Since(startTime).Milliseconds()), + } + + start.Done() + defer fin.Done() + + <-waitCh + + s.Update(e) + } + readFunc := func(start, fin *sync.WaitGroup, waitCh <-chan unit) { + start.Done() + defer fin.Done() + + <-waitCh + + _, _ = s.getData(24) + } + + const ( + roundsNum = 3 + + writersNum = 10 + readersNum = 5 + ) + + for round := 0; round < roundsNum; round++ { + atomic.StoreUint32(&r, uint32(round)) + + startWG, finWG := &sync.WaitGroup{}, &sync.WaitGroup{} + waitCh := make(chan unit) + + for i := 0; i < writersNum; i++ { + startWG.Add(1) + finWG.Add(1) + go writeFunc(startWG, finWG, waitCh, i) + } + + for i := 0; i < readersNum; i++ { + startWG.Add(1) + finWG.Add(1) + go readFunc(startWG, finWG, waitCh) + } + + startWG.Wait() + close(waitCh) + finWG.Wait() + } +} diff --git a/internal/stats/unit.go b/internal/stats/unit.go index 28e0b2bc..0e39cfea 100644 --- a/internal/stats/unit.go +++ b/internal/stats/unit.go @@ -353,33 +353,25 @@ func topsCollector(units []*unitDB, max int, pg pairsGetter) []map[string]uint64 return convertTopSlice(a2) } -/* Algorithm: -. Prepare array of N units, where N is the value of "limit" configuration setting - . Load data for the most recent units from file - If a unit with required ID doesn't exist, just add an empty unit - . Get data for the current unit -. Process data from the units and prepare an output map object: - * per time unit counters: - * DNS-queries/time-unit - * blocked/time-unit - * safebrowsing-blocked/time-unit - * parental-blocked/time-unit - If time-unit is an hour, just add values from each unit to an array. - If time-unit is a day, aggregate per-hour data into days. - * top counters: - * queries/domain - * queries/blocked-domain - * queries/client - To get these values we first sum up data for all units into a single map. - Then we get the pairs with the highest numbers (the values are sorted in descending order) - * total counters: - * DNS-queries - * blocked - * safebrowsing-blocked - * safesearch-blocked - * parental-blocked - These values are just the sum of data for all units. -*/ +// getData returns the statistics data using the following algorithm: +// +// 1. Prepare a slice of N units, where N is the value of "limit" configuration +// setting. Load data for the most recent units from the file. If a unit +// with required ID doesn't exist, just add an empty unit. Get data for the +// current unit. +// +// 2. Process data from the units and prepare an output map object, including +// per time unit counters (DNS queries per time-unit, blocked queries per +// time unit, etc.). If the time unit is hour, just add values from each +// unit to the slice; otherwise, the time unit is day, so aggregate per-hour +// data into days. +// +// To get the top counters (queries per domain, queries per blocked domain, +// etc.), first sum up data for all units into a single map. Then, get the +// pairs with the highest numbers. +// +// The total counters (DNS queries, blocked, etc.) are just the sum of data +// for all units. func (s *StatsCtx) getData(limit uint32) (StatsResp, bool) { if limit == 0 { return StatsResp{ diff --git a/internal/tools/go.mod b/internal/tools/go.mod index 74969289..ed3ed977 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -8,11 +8,12 @@ require ( github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 github.com/kisielk/errcheck v1.6.2 github.com/kyoh86/looppointer v0.1.7 - github.com/securego/gosec/v2 v2.12.0 - golang.org/x/tools v0.1.12 + github.com/securego/gosec/v2 v2.13.1 + golang.org/x/tools v0.1.13-0.20220803210227-8b9a1fbdf5c3 + golang.org/x/vuln v0.0.0-20220902211423-27dd78d2ca39 honnef.co/go/tools v0.3.3 mvdan.cc/gofumpt v0.3.1 - mvdan.cc/unparam v0.0.0-20220706161116-678bad134442 + mvdan.cc/unparam v0.0.0-20220831102321-2fc90a84c7ec ) require ( @@ -20,13 +21,14 @@ require ( github.com/client9/misspell v0.3.4 // indirect github.com/google/go-cmp v0.5.8 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/gookit/color v1.5.1 // 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/typeparams v0.0.0-20220722155223-a9213eeb770e // 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-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 // indirect + golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect + golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/internal/tools/go.sum b/internal/tools/go.sum index 144cd0eb..0f43bb9f 100644 --- a/internal/tools/go.sum +++ b/internal/tools/go.sum @@ -1,752 +1,124 @@ -bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= -cloud.google.com/go v0.26.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.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= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.5.0/go.mod h1:ZEwJccE3z93Z2HWvstpri00jOg7oO4UZDtKhwDwqF0w= -cloud.google.com/go/spanner v1.7.0/go.mod h1:sd3K2gZ9Fd0vMPLXzeCrF6fq4i63Q7aTLW/lBIfBkIk= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -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= -contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 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/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -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/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= -github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.36.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -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/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -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/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 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= 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/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -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.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= -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/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -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= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -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/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -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/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= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo= github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= -github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/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-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/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/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw= -github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/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/gookit/color v1.5.1 h1:Vjg2VEcdHpwq+oY63s/ksHrgJYCTo0bwWvmmYWdE9fQ= -github.com/gookit/color v1.5.1/go.mod h1:wZFzea4X8qN6vHOSP2apMb4/+w/orMznEzYsIHPaqKM= -github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= +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/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= -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/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= -github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 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/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -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/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pty v1.1.1/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/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kyoh86/looppointer v0.1.7 h1:q5sZOhFvmvQ6ZoZxvPB/Mjj2croWX7L49BBuI4XQWCM= github.com/kyoh86/looppointer v0.1.7/go.mod h1:l0cRF49N6xDPx8IuBGC/imZo8Yn1BBLJY0vzI+4fepc= github.com/kyoh86/nolint v0.0.0-20200711045849-7a7b0d649b7a/go.mod h1:hPeUNhNOZ22wXzQKMzeYKXVFTBjJ9czxjeIDyI1ueVM= github.com/kyoh86/nolint v0.0.1 h1:GjNxDEkVn2wAxKHtP7iNTrRxytRZ1wXxLV5j4XzGfRU= github.com/kyoh86/nolint v0.0.1/go.mod h1:1ZiZZ7qqrZ9dZegU96phwVcdQOMKIqRzFJL3ewq9gtI= -github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= -github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= -github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= -github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= 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/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= -github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= -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.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= -github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= -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/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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.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_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/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -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/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= -github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= -github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/securego/gosec/v2 v2.12.0 h1:CQWdW7ATFpvLSohMVsajscfyHJ5rsGmEXmsNcsDNmAg= -github.com/securego/gosec/v2 v2.12.0/go.mod h1:iTpT+eKTw59bSgklBHlSnH5O2tNygHMDxfvMubA4i7I= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -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.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +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/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/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -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.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +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/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -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= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k= -go.mozilla.org/mozlog v0.0.0-20170222151521-4bb13139d403/go.mod h1:jHoPAGnDrCy6kaI2tAze5Prf0Nr0w/oNkROt2lw3n3o= -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= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -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= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -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-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp/typeparams v0.0.0-20220722155223-a9213eeb770e h1:7Xs2YCOpMlNqSQSmrrnhlzBXIE/bpMecZplbLePTJvE= -golang.org/x/exp/typeparams v0.0.0-20220722155223-a9213eeb770e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -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-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= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-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= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/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-20191002035440-2ec189313ef0/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= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 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-20201110031124-69a78807bb2b/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-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/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/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= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/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-20201020160332-67f06af15bc9/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-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-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-20181107165924-66b7b1311ac8/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-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/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-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= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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-20190826190057-c7b8b68b1456/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-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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-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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 h1:9vYwv7OjYaky/tlAeD7C4oC9EsPTlaFl1H2jS++V+ME= -golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +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/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= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 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/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-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/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-20181030221726-6c7e314b6563/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= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-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= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200710042808-f1c4188a97a1/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +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/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.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= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -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.2/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-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -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= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -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= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= -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/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -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.3/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.6/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= -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= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 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-20220706161116-678bad134442 h1:seuXWbRB1qPrS3NQnHmFKLJLtskWyueeIzmLXghMGgk= -mvdan.cc/unparam v0.0.0-20220706161116-678bad134442/go.mod h1:F/Cxw/6mVrNKqrR2YjFf5CaW0Bw4RL8RfbEf4GRggJk= -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= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +mvdan.cc/unparam v0.0.0-20220831102321-2fc90a84c7ec h1:uyA9l4gQQUHSm9zPgTzarWmsjIw7s7hAldLwVxLlu1Y= +mvdan.cc/unparam v0.0.0-20220831102321-2fc90a84c7ec/go.mod h1:EAphbHIduKNGVweyBBwWQd24rSnLy4DsjlpxRFYE498= diff --git a/internal/tools/tools.go b/internal/tools/tools.go index e41fba4a..230d6c4b 100644 --- a/internal/tools/tools.go +++ b/internal/tools/tools.go @@ -4,7 +4,6 @@ package tools import ( - // Tools. _ "github.com/fzipp/gocyclo/cmd/gocyclo" _ "github.com/golangci/misspell/cmd/misspell" _ "github.com/gordonklaus/ineffassign" @@ -13,6 +12,7 @@ import ( _ "github.com/securego/gosec/v2/cmd/gosec" _ "golang.org/x/tools/go/analysis/passes/nilness/cmd/nilness" _ "golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow" + _ "golang.org/x/vuln/cmd/govulncheck" _ "honnef.co/go/tools/cmd/staticcheck" _ "mvdan.cc/gofumpt" _ "mvdan.cc/unparam" diff --git a/internal/updater/updater.go b/internal/updater/updater.go index a0672c58..55c1d918 100644 --- a/internal/updater/updater.go +++ b/internal/updater/updater.go @@ -117,7 +117,7 @@ func (u *Updater) Update() (err error) { return err } - err = u.prepare(filepath.Base(execPath)) + err = u.prepare(execPath) if err != nil { return err } @@ -169,7 +169,7 @@ func (u *Updater) VersionCheckURL() (vcu string) { } // prepare fills all necessary fields in Updater object. -func (u *Updater) prepare(exeName string) (err error) { +func (u *Updater) prepare(exePath string) (err error) { u.updateDir = filepath.Join(u.workDir, fmt.Sprintf("agh-update-%s", u.newVersion)) _, pkgNameOnly := filepath.Split(u.packageURL) @@ -185,7 +185,7 @@ func (u *Updater) prepare(exeName string) (err error) { updateExeName = "AdGuardHome.exe" } - u.backupExeName = filepath.Join(u.backupDir, exeName) + u.backupExeName = filepath.Join(u.backupDir, filepath.Base(exePath)) u.updateExeName = filepath.Join(u.updateDir, updateExeName) log.Debug( @@ -195,7 +195,7 @@ func (u *Updater) prepare(exeName string) (err error) { u.packageURL, ) - u.currentExeName = filepath.Join(u.workDir, exeName) + u.currentExeName = exePath _, err = os.Stat(u.currentExeName) if err != nil { return fmt.Errorf("checking %q: %w", u.currentExeName, err) diff --git a/internal/updater/updater_test.go b/internal/updater/updater_test.go index 219dc087..6eed74fd 100644 --- a/internal/updater/updater_test.go +++ b/internal/updater/updater_test.go @@ -103,10 +103,15 @@ func TestUpdateGetVersion(t *testing.T) { func TestUpdate(t *testing.T) { wd := t.TempDir() - require.NoError(t, os.WriteFile(filepath.Join(wd, "AdGuardHome"), []byte("AdGuardHome"), 0o755)) - require.NoError(t, os.WriteFile(filepath.Join(wd, "README.md"), []byte("README.md"), 0o644)) - require.NoError(t, os.WriteFile(filepath.Join(wd, "LICENSE.txt"), []byte("LICENSE.txt"), 0o644)) - require.NoError(t, os.WriteFile(filepath.Join(wd, "AdGuardHome.yaml"), []byte("AdGuardHome.yaml"), 0o644)) + exePath := filepath.Join(wd, "AdGuardHome") + yamlPath := filepath.Join(wd, "AdGuardHome.yaml") + readmePath := filepath.Join(wd, "README.md") + licensePath := filepath.Join(wd, "LICENSE.txt") + + require.NoError(t, os.WriteFile(exePath, []byte("AdGuardHome"), 0o755)) + require.NoError(t, os.WriteFile(yamlPath, []byte("AdGuardHome.yaml"), 0o644)) + require.NoError(t, os.WriteFile(readmePath, []byte("README.md"), 0o644)) + require.NoError(t, os.WriteFile(licensePath, []byte("LICENSE.txt"), 0o644)) // start server for returning package file pkgData, err := os.ReadFile("testdata/AdGuardHome.tar.gz") @@ -127,17 +132,13 @@ func TestUpdate(t *testing.T) { } u.workDir = wd - u.confName = filepath.Join(u.workDir, "AdGuardHome.yaml") + u.confName = yamlPath u.newVersion = "v0.103.1" u.packageURL = fakeURL.String() - require.NoError(t, u.prepare("AdGuardHome")) - - u.currentExeName = filepath.Join(wd, "AdGuardHome") - + require.NoError(t, u.prepare(exePath)) require.NoError(t, u.downloadPackageFile(u.packageURL, u.packageName)) require.NoError(t, u.unpack()) - // require.NoError(t, u.check()) require.NoError(t, u.backup()) require.NoError(t, u.replace()) @@ -156,22 +157,22 @@ func TestUpdate(t *testing.T) { assert.Equal(t, "AdGuardHome", string(d)) // check updated files - d, err = os.ReadFile(filepath.Join(wd, "AdGuardHome")) + d, err = os.ReadFile(exePath) require.NoError(t, err) assert.Equal(t, "1", string(d)) - d, err = os.ReadFile(filepath.Join(wd, "README.md")) + d, err = os.ReadFile(readmePath) require.NoError(t, err) assert.Equal(t, "2", string(d)) - d, err = os.ReadFile(filepath.Join(wd, "LICENSE.txt")) + d, err = os.ReadFile(licensePath) require.NoError(t, err) assert.Equal(t, "3", string(d)) - d, err = os.ReadFile(filepath.Join(wd, "AdGuardHome.yaml")) + d, err = os.ReadFile(yamlPath) require.NoError(t, err) assert.Equal(t, "AdGuardHome.yaml", string(d)) @@ -180,10 +181,15 @@ func TestUpdate(t *testing.T) { func TestUpdateWindows(t *testing.T) { wd := t.TempDir() - require.NoError(t, os.WriteFile(filepath.Join(wd, "AdGuardHome.exe"), []byte("AdGuardHome.exe"), 0o755)) - require.NoError(t, os.WriteFile(filepath.Join(wd, "README.md"), []byte("README.md"), 0o644)) - require.NoError(t, os.WriteFile(filepath.Join(wd, "LICENSE.txt"), []byte("LICENSE.txt"), 0o644)) - require.NoError(t, os.WriteFile(filepath.Join(wd, "AdGuardHome.yaml"), []byte("AdGuardHome.yaml"), 0o644)) + exePath := filepath.Join(wd, "AdGuardHome.exe") + yamlPath := filepath.Join(wd, "AdGuardHome.yaml") + readmePath := filepath.Join(wd, "README.md") + licensePath := filepath.Join(wd, "LICENSE.txt") + + require.NoError(t, os.WriteFile(exePath, []byte("AdGuardHome.exe"), 0o755)) + require.NoError(t, os.WriteFile(yamlPath, []byte("AdGuardHome.yaml"), 0o644)) + require.NoError(t, os.WriteFile(readmePath, []byte("README.md"), 0o644)) + require.NoError(t, os.WriteFile(licensePath, []byte("LICENSE.txt"), 0o644)) // start server for returning package file pkgData, err := os.ReadFile("testdata/AdGuardHome.zip") @@ -205,14 +211,11 @@ func TestUpdateWindows(t *testing.T) { } u.workDir = wd - u.confName = filepath.Join(u.workDir, "AdGuardHome.yaml") + u.confName = yamlPath u.newVersion = "v0.103.1" u.packageURL = fakeURL.String() - require.NoError(t, u.prepare("AdGuardHome.exe")) - - u.currentExeName = filepath.Join(wd, "AdGuardHome.exe") - + require.NoError(t, u.prepare(exePath)) require.NoError(t, u.downloadPackageFile(u.packageURL, u.packageName)) require.NoError(t, u.unpack()) // assert.Nil(t, u.check()) @@ -233,22 +236,22 @@ func TestUpdateWindows(t *testing.T) { assert.Equal(t, "AdGuardHome.exe", string(d)) // check updated files - d, err = os.ReadFile(filepath.Join(wd, "AdGuardHome.exe")) + d, err = os.ReadFile(exePath) require.NoError(t, err) assert.Equal(t, "1", string(d)) - d, err = os.ReadFile(filepath.Join(wd, "README.md")) + d, err = os.ReadFile(readmePath) require.NoError(t, err) assert.Equal(t, "2", string(d)) - d, err = os.ReadFile(filepath.Join(wd, "LICENSE.txt")) + d, err = os.ReadFile(licensePath) require.NoError(t, err) assert.Equal(t, "3", string(d)) - d, err = os.ReadFile(filepath.Join(wd, "AdGuardHome.yaml")) + d, err = os.ReadFile(yamlPath) require.NoError(t, err) assert.Equal(t, "AdGuardHome.yaml", string(d)) diff --git a/internal/version/version.go b/internal/version/version.go index eec8c4d0..2091d859 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -73,8 +73,7 @@ const ( // fmtModule returns formatted information about module. The result looks like: // -// github.com/Username/module@v1.2.3 (sum: someHASHSUM=) -// +// github.com/Username/module@v1.2.3 (sum: someHASHSUM=) func fmtModule(m *debug.Module) (formatted string) { if m == nil { return "" @@ -118,18 +117,18 @@ const ( // Verbose returns formatted build information. Output example: // -// AdGuard Home -// Version: v0.105.3 -// Channel: development -// Go version: go1.15.3 -// Build time: 2021-03-30T16:26:08Z+0300 -// GOOS: darwin -// GOARCH: amd64 -// Race: false -// Main module: -// ... -// Dependencies: -// ... +// AdGuard Home +// Version: v0.105.3 +// Channel: development +// Go version: go1.15.3 +// Build time: 2021-03-30T16:26:08Z+0300 +// GOOS: darwin +// GOARCH: amd64 +// Race: false +// Main module: +// ... +// Dependencies: +// ... // // TODO(e.burkov): Make it write into passed io.Writer. func Verbose() (v string) { diff --git a/scripts/make/Dockerfile b/scripts/make/Dockerfile index b87ee360..a940a155 100644 --- a/scripts/make/Dockerfile +++ b/scripts/make/Dockerfile @@ -48,6 +48,9 @@ RUN setcap 'cap_net_bind_service=+eip' /opt/adguardhome/AdGuardHome # 5443 : TCP, UDP : DNSCrypt (alt) # 6060 : TCP : HTTP (pprof) # 8853 : UDP : DNS-over-QUIC (experimental) +# +# TODO(a.garipov): Remove the old, non-standard 784 and 8853 ports for +# DNS-over-QUIC in a future release. EXPOSE 53/tcp 53/udp 67/udp 68/udp 80/tcp 443/tcp 443/udp 784/udp\ 853/tcp 853/udp 3000/tcp 3000/udp 3001/tcp 3001/udp 5443/tcp\ 5443/udp 6060/tcp 8853/udp diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh index 6f347d2c..17ac9457 100644 --- a/scripts/make/go-lint.sh +++ b/scripts/make/go-lint.sh @@ -218,14 +218,17 @@ exit_on_output gofumpt --extra -e -l . "$GO" vet ./... +govulncheck ./... + # Apply more lax standards to the code we haven't properly refactored yet. -gocyclo --over 17 ./internal/dhcpd/ ./internal/dnsforward/\ - ./internal/filtering/ ./internal/home/ ./internal/querylog/ +gocyclo --over 17 ./internal/querylog/ +gocyclo --over 15 ./internal/home/ ./internal/dhcpd +gocyclo --over 13 ./internal/filtering/ # Apply stricter standards to new or somewhat refactored code. gocyclo --over 10 ./internal/aghio/ ./internal/aghnet/ ./internal/aghos/\ - ./internal/aghtest/ ./internal/stats/ ./internal/tools/\ - ./internal/updater/ ./internal/version/ ./main.go + ./internal/aghtest/ ./internal/dnsforward/ ./internal/stats/\ + ./internal/tools/ ./internal/updater/ ./internal/version/ ./main.go ineffassign ./... diff --git a/scripts/make/go-tools.sh b/scripts/make/go-tools.sh index 1830c552..a66d5c06 100644 --- a/scripts/make/go-tools.sh +++ b/scripts/make/go-tools.sh @@ -32,10 +32,13 @@ readonly go # prevent the "cannot install cross-compiled binaries when GOBIN is set" error. env\ GOARCH=""\ - GOOS=""\ GOBIN="${PWD}/bin"\ - "$go" install --modfile=./internal/tools/go.mod\ - $v_flags $x_flags\ + GOOS=""\ + GOWORK='off'\ + "$go" install\ + --modfile=./internal/tools/go.mod\ + $v_flags\ + $x_flags\ github.com/fzipp/gocyclo/cmd/gocyclo\ github.com/golangci/misspell/cmd/misspell\ github.com/gordonklaus/ineffassign\ @@ -44,6 +47,7 @@ env\ github.com/securego/gosec/v2/cmd/gosec\ golang.org/x/tools/go/analysis/passes/nilness/cmd/nilness\ golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow\ + golang.org/x/vuln/cmd/govulncheck\ honnef.co/go/tools/cmd/staticcheck\ mvdan.cc/gofumpt\ mvdan.cc/unparam\ diff --git a/scripts/translations/download.js b/scripts/translations/download.js index c511b56f..41359bda 100644 --- a/scripts/translations/download.js +++ b/scripts/translations/download.js @@ -1,3 +1,6 @@ +// TODO(a.garipov): Rewrite this in Go; add better concurrency controls; add +// features for easier maintenance. + const fs = require('fs'); const path = require('path'); const requestPromise = require('request-promise'); @@ -107,7 +110,7 @@ const download = async () => { // Don't request the Crowdin API too aggressively to prevent spurious // 400 errors. - await sleep(200); + await sleep(400); } Promise