diff --git a/.github/stale.yml b/.github/stale.yml index d242832f..6ed9a7df 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -8,6 +8,7 @@ - 'documentation' - 'enhancement' - 'feature request' +- 'help wanted' - 'localization' - 'needs investigation' - 'recurrent' diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d82fb57..84f45312 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,10 @@ and this project adheres to ### Added +- Support for Discovery of Designated Resolvers (DDR) according to the + [RFC draft][ddr-draft-06] ([#4463]). +- The ability to control each source of runtime clients separately via + `clients.runtime_sources` configuration object ([#3020]). - The ability to customize the set of networks that are considered private through the new `dns.private_networks` property in the configuration file ([#3142]). @@ -63,8 +67,36 @@ and this project adheres to #### Configuration Changes -In this release, the schema version has changed from 12 to 13. +In this release, the schema version has changed from 12 to 14. +- Object `clients`, which in schema versions 13 and earlier was an array of + actual persistent clients, is now consist of `persistent` and + `runtime_sources` properties: + + ```yaml + # BEFORE: + 'clients': + - name: client-name + # … + + # AFTER: + 'clients': + 'persistent': + - name: client-name + # … + 'runtime_sources': + whois: true + arp: true + rdns: true + dhcp: true + hosts: true + ``` + + The value for `clients.runtime_sources.rdns` field is taken from + `dns.resolve_clients` property. To rollback this change, remove the + `runtime_sources` property, move the contents of `persistent` into the + `clients` itself, the value of `clients.runtime_sources.rdns` into the + `dns.resolve_clietns`, and change the `schema_version` back to `13`. - Property `local_domain_name`, which in schema versions 12 and earlier used to be a part of the `dns` object, is now a part of the `dhcp` object: @@ -85,14 +117,19 @@ In this release, the schema version has changed from 12 to 13. ### Deprecated +- The `--no-etc-hosts` option. Its' functionality is now controlled by + `clients.runtime_sources.hosts` configuration property. v0.109.0 will remove + the flag completely. - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. ### Fixed +- Slow version update queries making other HTTP APIs unresponsible ([#4499]). - ARP tables refreshing process causing excessive PTR requests ([#3157]). [#1730]: https://github.com/AdguardTeam/AdGuardHome/issues/1730 [#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 +[#3020]: https://github.com/AdguardTeam/AdGuardHome/issues/3020 [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#3142]: https://github.com/AdguardTeam/AdGuardHome/issues/3142 [#3157]: https://github.com/AdguardTeam/AdGuardHome/issues/3157 @@ -106,9 +143,11 @@ In this release, the schema version has changed from 12 to 13. [#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 +[#4499]: https://github.com/AdguardTeam/AdGuardHome/issues/4499 -[repr]: https://reproducible-builds.org/docs/source-date-epoch/ +[ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html [doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 +[repr]: https://reproducible-builds.org/docs/source-date-epoch/ diff --git a/Makefile b/Makefile index 5d9e7a7c..7c8f205f 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,8 @@ YARN_INSTALL_FLAGS = $(YARN_FLAGS) --network-timeout 120000 --silent\ --ignore-engines --ignore-optional --ignore-platform\ --ignore-scripts +V1API = 0 + # Macros for the build-release target. If FRONTEND_PREBUILT is 0, the # default, the macro $(BUILD_RELEASE_DEPS_$(FRONTEND_PREBUILT)) expands # into BUILD_RELEASE_DEPS_0, and so both frontend and backend @@ -61,6 +63,7 @@ ENV = env\ PATH="$${PWD}/bin:$$( "$(GO.MACRO)" env GOPATH )/bin:$${PATH}"\ RACE='$(RACE)'\ SIGN='$(SIGN)'\ + V1API='$(V1API)'\ VERBOSE='$(VERBOSE)'\ VERSION='$(VERSION)'\ diff --git a/client/src/__locales/cs.json b/client/src/__locales/cs.json index 26759394..8331dd50 100644 --- a/client/src/__locales/cs.json +++ b/client/src/__locales/cs.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Bootstrap DNS servery", "bootstrap_dns_desc": "Servery Bootstrap DNS se používají k řešení IP adres DoH/DoT, které zadáváte jako upstreamy.", "local_ptr_title": "Soukromé reverzní DNS servery", - "local_ptr_desc": "Servery DNS, které AdGuard Home používá pro lokální dotazy PTR. Tyto servery se používají k rozlišení názvů hostitelů klientů se soukromými adresami IP, například \"192.168.12.34\" pomocí rDNS. Pokud není nastaveno, AdGuard Home automaticky použije výchozí řešitele vašeho OS s výjimkou adres samotného AdGuard Home.", + "local_ptr_desc": "Servery DNS, které AdGuard Home používá pro lokální dotazy PTR. Tyto servery se používají k řešení požadavků PTR na adresy v soukromých rozmezích IP, například \"192.168.12.34\", pomocí reverzního DNS. Pokud není nastaveno, AdGuard Home automaticky použije výchozí řešitele vašeho OS s výjimkou adres samotného AdGuard Home.", "local_ptr_default_resolver": "Ve výchozím nastavení používá AdGuard Home následující reverzní DNS řešitele: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home nemohl určit vhodné soukromé reverzní DNS řešitele pro tento systém.", "local_ptr_placeholder": "Zadejte jednu adresu serveru na řádek", @@ -283,7 +283,7 @@ "download_mobileconfig_doh": "Stáhnout .mobileconfig pro DNS skrze HTTPS", "download_mobileconfig_dot": "Stáhnout .mobileconfig pro DNS skrze TLS", "download_mobileconfig": "Stáhnout konfigurační soubor", - "plain_dns": "Čisté DNS", + "plain_dns": "Běžný DNS", "form_enter_rate_limit": "Zadejte rychlostní limit", "rate_limit": "Rychlostní limit", "edns_enable": "Povolit klientskou podsíť EDNS", diff --git a/client/src/__locales/da.json b/client/src/__locales/da.json index 1b12ad06..4b077cf8 100644 --- a/client/src/__locales/da.json +++ b/client/src/__locales/da.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Bootstrap DNS-servere", "bootstrap_dns_desc": "Bootstrap DNS-servere bruges til at fortolke IP-adresser for de DoH-/DoT-resolvere, du angiver som upstream.", "local_ptr_title": "Private reverse DNS-servere", - "local_ptr_desc": "De DNS-servere, som AdGuard Home bruger til lokale PTR-forespørgsler. Disse servere bruges til at opløse klientværtsnavne med private IP-adresser, f.eks. \"192.168.12.34\", vha. rDNS. Hvis ikke indstillet, bruger AdGuard Home dit operativsystems standard DNS-opløsere undtagen for sine egne adresser.", + "local_ptr_desc": "DNS-servere brugt af AdGuard Home til lokale PTR-forespørgsler. Disse servere bruges til at opløse PTR-forespørgsler fra private IP-adresseområder, f.eks. \"192.168.12.34\", vha. reverse DNS. Hvis ikke opsat, bruger AdGuard Home operativsystems standard DNS-opløsere undtagen for sine egne adresser.", "local_ptr_default_resolver": "AdGuard Home bruger som standard flg. reverse DNS-opløsere: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home kunne ikke fastslå egnede private reverse DNS-opløsere for dette system.", "local_ptr_placeholder": "Indtast en serveradresse pr. Linje", @@ -351,7 +351,7 @@ "install_devices_android_list_5": "Skift de aktuelle DNS 1- og DNS 2-værdier til dine AdGuard Home-serveradresser.", "install_devices_ios_list_1": "Tryk på Indstillinger på Hjem-skærmen.", "install_devices_ios_list_2": "Vælg Wi-Fi i menuen til venstre (det er umuligt at opsætte DNS for mobilnetværker).", - "install_devices_ios_list_3": "Tryk på navnet på det aktuelt aktive netværk.", + "install_devices_ios_list_3": "Tryk på navnet for det aktuelt aktive netværk.", "install_devices_ios_list_4": "Angiv dine AdGuard Home-serveradresser i DNS-feltet.", "get_started": "Komme I Gang", "next": "Næste", diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index be5666a8..0fe6345d 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -149,9 +149,9 @@ "general_settings": "Allgemeine Einstellungen", "dns_settings": "DNS-Einstellungen", "dns_blocklists": "DNS-Sperrliste", - "dns_allowlists": "DNS-Freigabelisten", + "dns_allowlists": "DNS-Positivlisten", "dns_blocklists_desc": "AdGuard Home sperrt Domains, die in den Sperrlisten enthalten sind.", - "dns_allowlists_desc": "Domains aus DNS-Freigabelisten werden auch dann zugelassen, wenn sie in einer der Sperrlisten enthalten sind.", + "dns_allowlists_desc": "Domains aus DNS-Positivlisten werden auch dann zugelassen, wenn sie in einer der Sperrlisten enthalten sind.", "custom_filtering_rules": "Benutzerdefinierte Filterregeln", "encryption_settings": "Verschlüsselungseinstellungen", "dhcp_settings": "DHCP-Einstellungen", @@ -181,21 +181,21 @@ "elapsed": "Verstrichen", "filters_and_hosts_hint": "AdGuard Home versteht grundlegende Werbefilterregeln und Host-Datei-Syntax.", "no_blocklist_added": "Keine Sperrliste hinzugefügt", - "no_whitelist_added": "Keine Freigabeliste hinzugefügt", + "no_whitelist_added": "Keine Positivliste hinzugefügt", "add_blocklist": "Sperrliste hinzufügen", - "add_allowlist": "Freigabeliste hinzufügen", + "add_allowlist": "Positivliste hinzufügen", "cancel_btn": "Abbrechen", "enter_name_hint": "Name eingeben", "enter_url_or_path_hint": "URL oder absoluten Pfad der Liste eingeben", "check_updates_btn": "Nach Aktualisierungen suchen", "new_blocklist": "Neue Sperrliste", - "new_allowlist": "Neue Freigabeliste", + "new_allowlist": "Neue Positivliste", "edit_blocklist": "Sperrliste bearbeiten", - "edit_allowlist": "Freigabeliste bearbeiten", + "edit_allowlist": "Positivliste bearbeiten", "choose_blocklist": "Sperrliste wählen", - "choose_allowlist": "Freigabeliste wählen", + "choose_allowlist": "Positivliste wählen", "enter_valid_blocklist": "Gültige Webadresse zur Sperrliste eingeben.", - "enter_valid_allowlist": "Gültige Webadresse zur Freigabeliste eingeben.", + "enter_valid_allowlist": "Gültige Webadresse zur Positivliste eingeben.", "form_error_url_format": "Ungültiges URL-Format", "form_error_url_or_path_format": "Ungültige URL oder absoluter Pfad der Liste", "custom_filter_rules": "Benutzerdefinierte Filterregeln", diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 706ddf55..f39d2f51 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Bootstrap DNS servers", "bootstrap_dns_desc": "Bootstrap DNS servers are used to resolve IP addresses of the DoH/DoT resolvers you specify as upstreams.", "local_ptr_title": "Private reverse DNS servers", - "local_ptr_desc": "The DNS servers that AdGuard Home uses for local PTR queries. These servers are used to resolve the hostnames of clients with private IP addresses, for example \"192.168.12.34\", using reverse DNS. If not set, AdGuard Home uses the addresses of the default DNS resolvers of your OS except for the addresses of AdGuard Home itself.", + "local_ptr_desc": "The DNS servers that AdGuard Home uses for local PTR queries. These servers are used to resolve PTR requests for addresses in private IP ranges, for example \"192.168.12.34\", using reverse DNS. If not set, AdGuard Home uses the addresses of the default DNS resolvers of your OS except for the addresses of AdGuard Home itself.", "local_ptr_default_resolver": "By default, AdGuard Home uses the following reverse DNS resolvers: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home could not determine suitable private reverse DNS resolvers for this system.", "local_ptr_placeholder": "Enter one server address per line", diff --git a/client/src/__locales/es.json b/client/src/__locales/es.json index a83527ed..e495c81d 100644 --- a/client/src/__locales/es.json +++ b/client/src/__locales/es.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Servidores DNS de arranque", "bootstrap_dns_desc": "Los servidores DNS de arranque se utilizan para resolver las direcciones IP de los resolutores DoH/DoT que especifiques como DNS de subida.", "local_ptr_title": "Servidores DNS inversos y privados", - "local_ptr_desc": "Los servidores DNS que AdGuard Home utiliza para las consultas PTR locales. Estos servidores se utilizan para resolver los nombres de hosts de los clientes a direcciones IP privadas, por ejemplo \"192.168.12.34\", utilizando DNS inverso. Si no está establecido, AdGuard Home utilizará los resolutores DNS predeterminados de tu sistema operativo, excepto las direcciones del propio AdGuard Home.", + "local_ptr_desc": "Los servidores DNS que AdGuard Home utiliza para las consultas PTR locales. Estos servidores se utilizan para resolver las peticiones PTR de direcciones en rangos de IP privadas, por ejemplo \"192.168.12.34\", utilizando DNS inverso. Si no está establecido, AdGuard Home utilizará los resolutores DNS predeterminados de tu sistema operativo, excepto las direcciones del propio AdGuard Home.", "local_ptr_default_resolver": "Por defecto, AdGuard Home utiliza los siguientes resolutores DNS inversos: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home no pudo determinar los resolutores DNS inversos y privados adecuados para este sistema.", "local_ptr_placeholder": "Ingresa una dirección de servidor por línea", @@ -351,7 +351,7 @@ "install_devices_android_list_5": "Cambia los valores de DNS 1 y DNS 2 a las direcciones de tu servidor AdGuard Home.", "install_devices_ios_list_1": "En la pantalla de inicio, pulsa en Configuración.", "install_devices_ios_list_2": "Elige Wi-Fi en el menú de la izquierda (es imposible configurar DNS para redes móviles).", - "install_devices_ios_list_3": "Pulsa sobre el nombre de la red activa en ese momento.", + "install_devices_ios_list_3": "Pulsa sobre el nombre de la red actualmente activa.", "install_devices_ios_list_4": "En el campo DNS ingresa las direcciones de tu servidor AdGuard Home.", "get_started": "Comenzar", "next": "Siguiente", diff --git a/client/src/__locales/fi.json b/client/src/__locales/fi.json index 5e6c8089..3141b12a 100644 --- a/client/src/__locales/fi.json +++ b/client/src/__locales/fi.json @@ -338,7 +338,7 @@ "install_devices_windows_list_2": "Avaa \"Verkko ja Internet\" -ryhmä ja sitten \"Verkko ja jakamiskeskus\".", "install_devices_windows_list_3": "Paina ikkunan vasemmasta laidasta \"Muuta sovittimen asetuksia\".", "install_devices_windows_list_4": "Paina aktiivista yhteyttäsi hiiren kakkospainikkeella ja valitse \"Ominaisuudet\".", - "install_devices_windows_list_5": "Etsi listasta \"Internet protokolla versio 4 (TCP/IP)\", valitse se ja paina jälleen \"Ominaisuudet\".", + "install_devices_windows_list_5": "Etsi listasta \"Internet Protocol Version 4 (TCP/IPv4)\" (tai IPv6:lle \"Internet Protocol Version 6 (TCP/IPv6)\"), valitse se ja paina jälleen \"Ominaisuudet\".", "install_devices_windows_list_6": "Valitse \"Käytä seuraavia DNS-palvelinten osoitteita\" ja syötä AdGuard Home -palvelimesi osoitteet.", "install_devices_macos_list_1": "Paina Omena-kuvaketta ja valitse \"Järjestelmäasetukset\".", "install_devices_macos_list_2": "Paina \"Verkko\".", diff --git a/client/src/__locales/nl.json b/client/src/__locales/nl.json index 7fc19d73..83278ee3 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Bootstrap DNS-servers", "bootstrap_dns_desc": "Bootstrap DNS-servers worden gebruikt om IP-adressen op te lossen van de DoH / DoT-resolvers die u opgeeft als upstreams.", "local_ptr_title": "Private omgekeerde DNS-servers", - "local_ptr_desc": "De DNS-servers die AdGuard Home zal gebruiken voor lokale PTR zoekopdrachten. Deze server wordt gebruikt om de hostnamen van de clients met private IP-adressen, bijvoorbeeld \"192.168.12.34\", dmv. rDNS. Indien niet ingesteld, gebruikt AdGuard Home automatisch je standaard DNS-resolver.", + "local_ptr_desc": "De DNS-servers die AdGuard Home gebruikt voor lokale PTR-zoekopdrachten. Deze servers worden gebruikt om PTR-verzoeken voor adressen in privé-IP-bereiken op te lossen, bijvoorbeeld \"192.168.12.34\", met behulp van reverse DNS. Indien niet ingesteld, gebruikt AdGuard Home de adressen van de standaard DNS-resolvers van uw besturingssysteem, behalve de adressen van AdGuard Home zelf.", "local_ptr_default_resolver": "Standaard gebruikt AdGuard Home de volgende omgekeerde DNS-resolvers: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home kon voor dit systeem geen geschikte private omgekeerde DNS-resolvers bepalen.", "local_ptr_placeholder": "Voer één serveradres per regel in", diff --git a/client/src/__locales/ro.json b/client/src/__locales/ro.json index b19b8576..097dba59 100644 --- a/client/src/__locales/ro.json +++ b/client/src/__locales/ro.json @@ -7,15 +7,15 @@ "load_balancing": "Echilibrare-sarcini", "load_balancing_desc": "Interoghează câte un server în amonte la un moment dat. AdGuard Home utilizează un algoritm de randomizare ponderat pentru a alege serverul, astfel încât cel mai rapid server să fie utilizat mai des.", "bootstrap_dns": "Serverele DNS Bootstrap", - "bootstrap_dns_desc": "Serverele DNS Bootstrap sunt folosite pentru a rezolva adresele IP ale resolverelor DoH/DoT indicate ca upstreams.", + "bootstrap_dns_desc": "Serverele DNS Bootstrap sunt folosite pentru a rezolva adresele IP ale rezolvatorilor DoH/DoT indicați ca upstreams.", "local_ptr_title": "Servere DNS inverse private", - "local_ptr_desc": "Servere DNS pe care AdGuard Home le utilizează pentru interogări PTR locale. Aceste servere sunt folosite pentru a rezolva numele gazdelor de clienți cu adrese IP private, cum ar fi \"192.168.12.34\", folosind DNS inversat. Dacă nu este setat, AdGuard Home utilizează adresele resolverelor DNS implicite ale SO al dvs., cu excepția adreselor AdGuard Home înseși.", - "local_ptr_default_resolver": "În mod implicit, AdGuard Home utilizează următoarele resolvere DNS inverse: {{ip}}.", - "local_ptr_no_default_resolver": "AdGuard Home nu a putut determina resolvere DNS private adecvate pentru acest sistem.", + "local_ptr_desc": "Serverele DNS pe care AdGuard Home le utilizează pentru interogările PTR locale. Aceste servere sunt utilizate pentru a rezolva solicitările PTR pentru adrese din intervale IP private, de exemplu „192.168.12.34”, utilizând DNS invers. Dacă nu este configurat, AdGuard Home utilizează adresele rezolvatorilor DNS impliciți ai sistemului dvs. de operare, cu excepția adreselor AdGuard Home în sine.", + "local_ptr_default_resolver": "În mod implicit, AdGuard Home utilizează următorii rezolvatori DNS inverși: {{ip}}.", + "local_ptr_no_default_resolver": "AdGuard Home nu a putut determina rezolvatorii DNS privați adecvați pentru acest sistem.", "local_ptr_placeholder": "Introduceți o adresă de server per linie", "resolve_clients_title": "Permiteți rezolvarea inversa a adreselor IP ale clienților", - "resolve_clients_desc": "Rezolvă invers adresele IP ale clienților în numele lor de gazde prin trimiterea interogărilor PTR la resolverele corespunzătoare (servere DNS private pentru clienți locali, servere în amonte pentru clienți cu adrese IP publice).", - "use_private_ptr_resolvers_title": "Utilizați resolvere DNS inverse private", + "resolve_clients_desc": "Rezolvă invers adresele IP ale clienților în numele lor de gazde prin trimiterea interogărilor PTR la rezolvatorii corespunzători (servere DNS private pentru clienți locali, servere în amonte pentru clienți cu adrese IP publice).", + "use_private_ptr_resolvers_title": "Utilizați rezolvatori DNS inverși privați", "use_private_ptr_resolvers_desc": "Efectuează examinări DNS inverse pentru adresele deservite local folosind aceste servere în amonte. Dacă este dezactivată, AdGuard Home răspunde cu NXDOMAIN la toate aceste cereri PTR, cu excepția clienților cunoscuți din DHCP, /etc/hosts și așa mai departe.", "check_dhcp_servers": "Căutați servere DHCP", "save_config": "Salvare configurare", @@ -214,7 +214,7 @@ "example_upstream_dot": "<0>DNS-over-TLS criptat;", "example_upstream_doh": "<0>DNS-over-HTTPS criptat;", "example_upstream_doq": "<0>DNS-over-QUIC criptat (experimental);", - "example_upstream_sdns": "<0>DNS Stamps pentru <1>DNSCrypt sau rezolvere <2>DNS-over-HTTPS;", + "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_hostname": "DNS obișnuit (over TCP, nume de gazdă);", "all_lists_up_to_date_toast": "Toate listele sunt deja la zi", @@ -351,7 +351,7 @@ "install_devices_android_list_5": "Schimbați valorile DNS 1 și DNS 2 la adresele serverului dvs. AdGuard Home.", "install_devices_ios_list_1": "Din ecranul de start, tapați Setări.", "install_devices_ios_list_2": "Alegeți Wi-Fi în meniul din stânga (este imposibil să configurați DNS pentru rețelele mobile).", - "install_devices_ios_list_3": "Tapați numele rețelei active curente.", + "install_devices_ios_list_3": "Apăsați pe numele rețelei active în prezent.", "install_devices_ios_list_4": "În câmpul DNS, introduceți adresele serverului dvs. AdGuard Home.", "get_started": "Să începem", "next": "Următor", @@ -585,7 +585,7 @@ "list_updated": "{{count}} listă actualizată", "list_updated_plural": "{{count}} liste actualizate", "dnssec_enable": "Activați DNSSEC", - "dnssec_enable_desc": "Activați semnalul DNSSEC în interogările DNS de ieșire și verificați rezultatul (este necesar un resolver compatibil DNSSEC).", + "dnssec_enable_desc": "Activați semnalul DNSSEC în interogările DNS de ieșire și verificați rezultatul (este necesar un rezolvator compatibil DNSSEC).", "validated_with_dnssec": "Validat cu DNSSEC", "all_queries": "Toate interogările", "show_blocked_responses": "Blocat", diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index 74dedd8b..f26e0011 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -9,7 +9,7 @@ "bootstrap_dns": "DNS Önyükleme sunucuları", "bootstrap_dns_desc": "DNS Önyükleme sunucuları, belirttiğiniz üst sunucuların DoH/DoT çözümleyicilerine ait IP adreslerinin çözümlemek için kullanılır.", "local_ptr_title": "Özel ters DNS sunucuları", - "local_ptr_desc": "AdGuard Home'un yerel PTR sorguları için kullandığı DNS sunucuları. Bu sunucular, rDNS kullanarak \"192.168.12.34\" gibi özel IP adreslerine sahip istemcilerin ana makine adlarını çözmek için kullanılır. Ayarlanmadığı durumda AdGuard Home, işletim sisteminizin varsayılan DNS çözümleme adreslerini kullanır.", + "local_ptr_desc": "AdGuard Home'un yerel PTR sorguları için kullandığı DNS sunucuları. Bu sunucular, rDNS kullanarak, örneğin \"192.168.12.34\" gibi özel IP aralıklarındaki adresler için PTR isteklerini çözmek için kullanılır. Ayarlanmadığı durumda AdGuard Home, işletim sisteminizin varsayılan DNS çözümleme adreslerini kullanır.", "local_ptr_default_resolver": "AdGuard Home, varsayılan olarak aşağıdaki ters DNS çözümleyicilerini kullanır: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home, bu sistem için uygun olan özel ters DNS çözümleyicilerini belirleyemedi.", "local_ptr_placeholder": "Her satıra bir sunucu adresi girin", @@ -115,7 +115,7 @@ "blocked_by": "<0>Filtreler tarafından engellenen", "stats_malware_phishing": "Engellenen kötü amaçlı yazılım ve kimlik avı", "stats_adult": "Engellenen yetişkin içerikli siteler", - "stats_query_domain": "En fazla sorgulanan alan adları", + "stats_query_domain": "Başlıca sorgulanan alan adları", "for_last_24_hours": "son 24 saat içindekiler", "for_last_days": "son {{count}} gün boyunca", "for_last_days_plural": "son {{count}} gün boyunca", @@ -123,8 +123,8 @@ "stats_disabled_short": "İstatistikler devre dışı bırakıldı", "no_domains_found": "Alan adı bulunamadı", "requests_count": "İstek sayısı", - "top_blocked_domains": "En fazla engellenen alan adları", - "top_clients": "En aktif istemciler", + "top_blocked_domains": "Başlıca engellenen alan adları", + "top_clients": "Başlıca istemciler", "no_clients_found": "İstemci bulunamadı", "general_statistics": "Genel istatistikler", "number_of_dns_query_days": "Son {{count}} gün boyunca işlenen DNS sorgularının sayısı", @@ -351,7 +351,7 @@ "install_devices_android_list_5": "DNS 1 ve DNS 2 değerlerini AdGuard Home sunucunuzun adresleriyle değiştirin.", "install_devices_ios_list_1": "Ana ekrandan Ayarlar'a dokunun.", "install_devices_ios_list_2": "Sol menüde bulunan Wi-Fi bölümüne girin (mobil ağlar için özel DNS sunucusu ayarlanamaz).", - "install_devices_ios_list_3": "Bağlı olduğunuz ağın ismine dokunun.", + "install_devices_ios_list_3": "O anda aktif olan ağın adına dokunun.", "install_devices_ios_list_4": "DNS alanına AdGuard Home sunucunuzun adreslerini girin.", "get_started": "Başlayın", "next": "Sonraki", @@ -602,14 +602,14 @@ "milliseconds_abbreviation": "ms", "cache_size": "Önbellek boyutu", "cache_size_desc": "DNS önbellek boyutu (bayt cinsinden).", - "cache_ttl_min_override": "Minimum TTL'i değiştir", - "cache_ttl_max_override": "Maksimum TTL'i değiştir", + "cache_ttl_min_override": "Minimum kullanım süresini geçersiz kıl", + "cache_ttl_max_override": "Maksimum kullanım süresini geçersiz kıl", "enter_cache_size": "Önbellek boyutunu girin (bayt)", - "enter_cache_ttl_min_override": "Minimum TTL değerini girin (saniye olarak)", - "enter_cache_ttl_max_override": "Maksimum TTL değerini girin (saniye olarak)", + "enter_cache_ttl_min_override": "Minimum kullanım süresi girin (saniye olarak)", + "enter_cache_ttl_max_override": "Maksimum kullanım süresi girin (saniye olarak)", "cache_ttl_min_override_desc": "DNS yanıtlarını önbelleğe alırken üst sunucudan alınan kullanım süresi değerini uzatın (saniye olarak).", "cache_ttl_max_override_desc": "DNS önbelleğindeki girişler için maksimum kullanım süresi değerini ayarlayın (saniye olarak).", - "ttl_cache_validation": "Minimum önbellek TTL geçersiz kılma, maksimuma eşit veya bundan küçük olmalıdır", + "ttl_cache_validation": "Minimum önbellek kullanım süresi geçersiz kılma, maksimum değerden küçük veya ona eşit olmalıdır", "cache_optimistic": "İyimser önbelleğe alma", "cache_optimistic_desc": "Girişlerin süresi dolduğunda bile AdGuard Home'un önbellekten yanıt vermesini sağlayın ve bunları yenilemeye çalışın.", "filter_category_general": "Genel", diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json index 5d349618..9fcbd460 100644 --- a/client/src/__locales/uk.json +++ b/client/src/__locales/uk.json @@ -65,7 +65,7 @@ "dhcp_ip_addresses": "IP-адреси", "ip": "IP", "dhcp_table_hostname": "Назва вузла", - "dhcp_table_expires": "Термін дії", + "dhcp_table_expires": "Закінчується", "dhcp_warning": "Якщо ви однаково хочете увімкнути DHCP-сервер, переконайтеся, що у вашій мережі немає інших активних DHCP-серверів. Інакше, це може порушити роботу інтернету на під'єднаних пристроях!", "dhcp_error": "AdGuard Home не зміг визначити, чи є в мережі інший DHCP-сервер", "dhcp_static_ip_error": "Для використання DHCP-сервера необхідно встановити статичну IP-адресу. Нам не вдалося визначити, чи цей мережевий інтерфейс налаштовано для використання статичної IP-адреси. Встановіть статичну IP-адресу вручну.", @@ -137,15 +137,15 @@ "number_of_dns_query_to_safe_search": "Кількість DNS-запитів до пошукових систем, для яких примусово застосований безпечний пошук", "average_processing_time": "Середній час обробки", "average_processing_time_hint": "Середній час обробки DNS запиту в мілісекундах", - "block_domain_use_filters_and_hosts": "Блокувати домени з використанням фільтрів та hosts-файлів", + "block_domain_use_filters_and_hosts": "Блокування доменів за допомогою фільтрів та hosts-файлів", "filters_block_toggle_hint": "Ви можете налаштувати правила блокування в розділі Фільтри.", - "use_adguard_browsing_sec": "Використовувати веб-службу безпечного перегляду AdGuard", + "use_adguard_browsing_sec": "Використовувати Безпечну навігацію AdGuard", "use_adguard_browsing_sec_hint": "AdGuard Home перевірятиме, чи додано домен до списку веб-служби безпечного перегляду браузера. Він використовуватиме API для перевірки — на сервер надсилається лише короткий префікс хешу SHA256 доменного імені.", "use_adguard_parental": "Використовувати вебсервіс Батьківського контролю AdGuard", - "use_adguard_parental_hint": "AdGuard Home перевірятиме, чи домен містить матеріали для дорослих. Він використовує той самий орієнтований на приватність API, що й веб-служба безпечного перегляду.", - "enforce_safe_search": "Використовувати безпечний пошук", + "use_adguard_parental_hint": "AdGuard Home перевірить, чи містить домен матеріали для дорослих. Він використовує то же API, що й Безпечна навігація AdGuard.", + "enforce_safe_search": "Використовувати Безпечний пошук", "enforce_save_search_hint": "AdGuard Home може примусово застосовувати безпечний пошук в таких пошукових системах: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.", - "no_servers_specified": "Не вказано сервери", + "no_servers_specified": "Сервери не вказано", "general_settings": "Загальні налаштування", "dns_settings": "Налаштування DNS", "dns_blocklists": "Список блокування DNS", @@ -158,7 +158,7 @@ "upstream_dns": "Upstream DNS-сервери", "upstream_dns_help": "Введіть адреси серверів по одній на рядок. Докладніше про налаштування DNS-серверів.", "upstream_dns_configured_in_file": "Налаштовано в {{path}}", - "test_upstream_btn": "Тест upstream серверів", + "test_upstream_btn": "Перевірити сервери", "upstreams": "Upstreams", "apply_btn": "Застосувати", "disabled_filtering_toast": "Фільтрування вимкнено", @@ -266,7 +266,7 @@ "dns_cache_config": "Конфігурація кешу DNS", "dns_cache_config_desc": "Тут ви можете налаштувати DNS-кеш", "blocking_mode": "Режим блокування", - "default": "Типовий", + "default": "Усталено", "nxdomain": "NXDOMAIN", "refused": "REFUSED", "null_ip": "Нульовий IP", @@ -316,7 +316,7 @@ "install_settings_dns_desc": "Вам потрібно буде налаштувати свої пристрої або маршрутизатор для використання DNS-сервера за такими адресами:", "install_settings_all_interfaces": "Усі інтерфейси", "install_auth_title": "Авторизація", - "install_auth_desc": "Необходно налаштувати автентифікацію паролем для вебінтерфейсу AdGuard Home. Навіть якщо він доступний лише у вашій локальній мережі, важливо захистити його від необмеженого доступу.\n\nДолжна быть настроена аутентификация паролем для веб-интерфейса AdGuard Home. Даже если он доступен только в вашей локальной сети, важно защитить его от неограниченного доступа.", + "install_auth_desc": "Необхідно налаштувати автентифікацію паролем для вебінтерфейсу AdGuard Home. Навіть якщо він доступний лише у вашій локальній мережі, важливо захистити його від необмеженого доступу.", "install_auth_username": "Ім'я користувача", "install_auth_password": "Пароль", "install_auth_confirm": "Підтвердьте пароль", @@ -336,7 +336,7 @@ "install_devices_router_list_4": "Ви не можете встановити власний DNS-сервер на деяких типах маршрутизаторів. У цьому разі вам може допомогти налаштування AdGuard Home в якості <0>DHCP-сервера. В іншому разі вам потрібно знайти інструкцію щодо налаштування DNS-сервера для вашої конкретної моделі маршрутизатора.", "install_devices_windows_list_1": "Відкрийте Панель керування через меню «Пуск» або пошук Windows.", "install_devices_windows_list_2": "Перейдіть до категорії Мережа й Інтернет, а потім до Центру мереж і спільного доступу.", - "install_devices_windows_list_3": "Зліва на екрані натисніть на «Змінити настройки адаптера».", + "install_devices_windows_list_3": "Зліва на екрані натисніть на «Змінити налаштування адаптера».", "install_devices_windows_list_4": "Клацніть на активному з'єднанні правою кнопкою миші та виберіть «Властивості».", "install_devices_windows_list_5": "Знайдіть у списку пункт «Internet Protocol Version 4 (TCP/IPv4)» або «Internet Protocol Version 6 (TCP/IPv6)», виберіть його та натисніть кнопку Властивості ще раз.", "install_devices_windows_list_6": "Виберіть «Використовувати наступні адреси DNS-серверів» та введіть адреси вашого сервера AdGuard Home.", @@ -375,7 +375,7 @@ "encryption_certificates_desc": "Для використання шифрування потрібно надати дійсний ланцюжок сертифікатів SSL для вашого домену. Ви можете отримати безкоштовний сертифікат на <0>{{link}} або придбати його в одному з надійних Центрів Сертифікації.", "encryption_certificates_input": "Скопіюйте/вставте сюди свої кодовані PEM сертифікати.", "encryption_status": "Статус", - "encryption_expire": "Закічнується", + "encryption_expire": "Закінчується", "encryption_key": "Приватний ключ", "encryption_key_input": "Скопіюйте/вставте сюди свій приватний ключ кодований PEM для вашого сертифіката.", "encryption_enable": "Увімкнути шифрування (HTTPS, DNS-over-HTTPS і DNS-over-TLS)", diff --git a/client/src/__locales/zh-cn.json b/client/src/__locales/zh-cn.json index 69d5b8b0..4640432f 100644 --- a/client/src/__locales/zh-cn.json +++ b/client/src/__locales/zh-cn.json @@ -148,8 +148,8 @@ "no_servers_specified": "未找到指定的服务器", "general_settings": "常规设置", "dns_settings": "DNS 设置", - "dns_blocklists": "DNS封锁清单", - "dns_allowlists": "DNS允许清单", + "dns_blocklists": "DNS 拦截列表", + "dns_allowlists": "DNS 允许列表", "dns_blocklists_desc": "AdGuard Home将阻止匹配DNS拦截清单的域名", "dns_allowlists_desc": "来自DNS允许列表的域将被允许,即使它们位于任意阻止列表中也是如此", "custom_filtering_rules": "自定义过滤规则", @@ -335,23 +335,22 @@ "install_devices_router_list_3": "请在此处输入您的 AdGuard Home 服务器地址。", "install_devices_router_list_4": "在某些类型的路由器上无法设置自定义 DNS 服务器。在此情况下将 AdGuard Home 设置为 <0>DHCP 服务器,可能会有所帮助。否则您应该查找如何根据特定路由器型号设置 DNS 服务器的使用手册。", "install_devices_windows_list_1": "通过开始菜单或 Windows 搜索功能打开控制面板。", - "install_devices_windows_list_2": "点击进入 ”网络和 Internet“ 后,再次点击进入 “网络和共享中心”", + "install_devices_windows_list_2": "点击进入「网络和 Internet」后,再次点击进入「网络和共享中心」", "install_devices_windows_list_3": "在窗口的左侧点击「更改适配器设置」。", "install_devices_windows_list_4": "选择您正在连接的网络设备,右击它并选择「属性”」。", - "install_devices_windows_list_5": "在列表中找到 ”Internet 协议版本 4 (TCP/IPv4)“ ,选择并再次点击 ”属性“ 。", + "install_devices_windows_list_5": "在列表中找到「Internet 协议版本 4 (TCP/IPv4)」,选择并再次点击「属性」。", "install_devices_windows_list_6": "选择“使用下面的 DNS 服务器地址”,并输入您的 AdGuard Home 服务器地址。", "install_devices_macos_list_1": "点击苹果图标,进入「系统首选项」。", "install_devices_macos_list_2": "点击「网络」。", - "install_devices_macos_list_3": "选择在列表中的第一个连接,并点击 ”高级“ 。", - "install_devices_macos_list_4": "选择 ”DNS“ 选项卡,并输入您的 AdGuard Home 服务器地址。", + "install_devices_macos_list_3": "选择在列表中的第一个连接,并点击「高级」。", + "install_devices_macos_list_4": "选择「DNS」选项卡,并输入您的 AdGuard Home 服务器地址。", "install_devices_android_list_1": "在安卓主屏幕菜单中点击设置。", - "install_devices_android_list_2": "点击菜单上的 ”无线局域网“ 选项。在屏幕上将列出所有可用的网络(蜂窝移动网络不支持修改 DNS )。", - "install_devices_android_list_3": "长按当前已连接的网络,然后点击 ”修改网络设置“ 。", - "install_devices_android_list_4": "在某些设备上,您可能需要选中 ”高级“ 复选框以查看进一步的设置。您可能需要调整您安卓设备的 DNS 设置,或是需要将 IP 设置从 DHCP 切换到静态。", + "install_devices_android_list_2": "点击菜单上的「无线局域网」选项。在屏幕上将列出所有可用的网络(蜂窝移动网络不支持修改 DNS )。", + "install_devices_android_list_3": "长按当前已连接的网络,然后点击「修改网络设置」。", + "install_devices_android_list_4": "在某些设备上,您可能需要选中「高级」复选框以查看进一步的设置。您可能需要调整您安卓设备的 DNS 设置,或是需要将 IP 设置从 DHCP 切换到静态。", "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_1": "从主屏幕中点击「设置」。", + "install_devices_ios_list_2": "从左侧目录中选择「无线局域网」(移动数据网络环境下不支持修改 DNS )。", "install_devices_ios_list_4": "在 DNS 字段中输入您的 AdGuard Home 服务器地址。", "get_started": "开始配置", "next": "下一步", diff --git a/client/src/__locales/zh-tw.json b/client/src/__locales/zh-tw.json index 666ddcc3..435d6b01 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -9,7 +9,7 @@ "bootstrap_dns": "自我啟動(Bootstrap)DNS 伺服器", "bootstrap_dns_desc": "自我啟動(Bootstrap)DNS 伺服器被用於解析您明確指定作為上游的 DoH/DoT 解析器之 IP 位址。", "local_ptr_title": "私人反向的 DNS 伺服器", - "local_ptr_desc": "AdGuard Home 用於區域指標(PTR)查詢之 DNS 伺服器。這些伺服器被用於解析含私人 IP 位址的用戶端之主機名稱,例如,\"192.168.12.34\",使用反向的 DNS。如果未被設定,除 AdGuard Home 它本身的位址之外,AdGuard Home 使用您的作業系統之預設 DNS 解析器的位址。", + "local_ptr_desc": "AdGuard Home 用於區域指標(PTR)查詢之 DNS 伺服器。這些伺服器被用於解析有關在私人 IP 範圍的位址之區域指標查詢,例如,\"192.168.12.34\",使用反向的 DNS。如果未被設定,AdGuard Home 使用您的作業系統之預設 DNS 解析器的位址。", "local_ptr_default_resolver": "預設下,AdGuard Home 使用以下反向的 DNS 解析器:{{ip}}。", "local_ptr_no_default_resolver": "AdGuard Home 無法為此系統決定合適的私人反向的 DNS 解析器。", "local_ptr_placeholder": "每行輸入一個伺服器位址", diff --git a/client/src/components/Logs/InfiniteTable.js b/client/src/components/Logs/InfiniteTable.js index d419ac3d..36f411c8 100644 --- a/client/src/components/Logs/InfiniteTable.js +++ b/client/src/components/Logs/InfiniteTable.js @@ -43,7 +43,7 @@ const InfiniteTable = ({ useEffect(() => { listener(); - }, [items.length < QUERY_LOGS_PAGE_LIMIT]); + }, [items.length < QUERY_LOGS_PAGE_LIMIT, isEntireLog]); useEffect(() => { const THROTTLE_TIME = 100; @@ -66,15 +66,24 @@ const InfiniteTable = ({ const isNothingFound = items.length === 0 && !processingGetLogs; - return
- {loading && } -
- {isNothingFound - ? - : <>{items.map(renderRow)} - {!isEntireLog &&
{t('loading_table_status')}
} - } -
; + return ( +
+ {loading && } +
+ {isNothingFound ? ( + + ) : ( + <> + {items.map(renderRow)} + {!isEntireLog && ( +
+ {t('loading_table_status')} +
+ )} + + )} +
+ ); }; InfiniteTable.propTypes = { diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js index 5fb42c05..a7bf9485 100644 --- a/client/src/helpers/helpers.js +++ b/client/src/helpers/helpers.js @@ -693,8 +693,8 @@ export const replaceZeroWithEmptyString = (value) => (parseInt(value, 10) === 0 * @returns {string} */ export const getLogsUrlParams = (search, response_status) => `?${queryString.stringify({ - search, - response_status, + search: search || undefined, + response_status: response_status || undefined, })}`; export const processContent = ( diff --git a/go.mod b/go.mod index 30d8b377..3b64e7db 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,13 @@ module github.com/AdguardTeam/AdGuardHome go 1.17 require ( - github.com/AdguardTeam/dnsproxy v0.42.1 + github.com/AdguardTeam/dnsproxy v0.42.2 github.com/AdguardTeam/golibs v0.10.8 github.com/AdguardTeam/urlfilter v0.16.0 github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.2.3 github.com/digineo/go-ipset/v2 v2.2.1 - github.com/fsnotify/fsnotify v1.5.1 + github.com/fsnotify/fsnotify v1.5.4 github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 github.com/google/go-cmp v0.5.7 github.com/google/gopacket v1.1.19 @@ -28,8 +28,8 @@ require ( github.com/ti-mo/netfilter v0.4.0 go.etcd.io/bbolt v1.3.6 golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 - golang.org/x/net v0.0.0-20220412020605-290c469a71a5 - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad + golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 + golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.4.0 howett.net/plist v1.0.0 @@ -57,10 +57,10 @@ require ( 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.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a // indirect + golang.org/x/tools v0.1.11-0.20220426200323-dcaea06afc12 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect diff --git a/go.sum b/go.sum index e75df993..06ae9b96 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr 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.42.1 h1:RZAtW75cvMX1d9Mibg0CA343V7VWV5PLrXsLhBZfdYc= -github.com/AdguardTeam/dnsproxy v0.42.1/go.mod h1:thHuk3599mgmucsv5J9HR9lBVQHnf4YleE08EbxNrN0= +github.com/AdguardTeam/dnsproxy v0.42.2 h1:aBhbuvqg/rZN8Rab5ILSfPFJDkiTviWXXcceJgajnNs= +github.com/AdguardTeam/dnsproxy v0.42.2/go.mod h1:thHuk3599mgmucsv5J9HR9lBVQHnf4YleE08EbxNrN0= 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= @@ -58,8 +58,9 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI 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.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +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= @@ -292,8 +293,9 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI 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.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= 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= @@ -329,8 +331,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 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= @@ -390,8 +392,9 @@ 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-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/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= @@ -416,8 +419,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a h1:ofrrl6c6NG5/IOSx/R1cyiQxxjqlur0h/TvbUhkH0II= -golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11-0.20220426200323-dcaea06afc12 h1:pODAJF0uBqx6zFa1MYaiTobVo5FzCbnTVUXeO8o71fE= +golang.org/x/tools v0.1.11-0.20220426200323-dcaea06afc12/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= 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= diff --git a/internal/aghnet/net_nolinux.go b/internal/aghnet/net_bsd.go similarity index 69% rename from internal/aghnet/net_nolinux.go rename to internal/aghnet/net_bsd.go index f429c6fa..bd705e92 100644 --- a/internal/aghnet/net_nolinux.go +++ b/internal/aghnet/net_bsd.go @@ -1,5 +1,5 @@ -//go:build !linux -// +build !linux +//go:build darwin || freebsd || openbsd +// +build darwin freebsd openbsd package aghnet diff --git a/internal/aghnet/net_windows.go b/internal/aghnet/net_windows.go index 0cea8fe7..17499cce 100644 --- a/internal/aghnet/net_windows.go +++ b/internal/aghnet/net_windows.go @@ -1,5 +1,5 @@ -//go:build !(linux || darwin || freebsd || openbsd) -// +build !linux,!darwin,!freebsd,!openbsd +//go:build windows +// +build windows package aghnet @@ -13,6 +13,10 @@ import ( "golang.org/x/sys/windows" ) +func canBindPrivilegedPorts() (can bool, err error) { + return true, nil +} + func ifaceHasStaticIP(string) (ok bool, err error) { return false, aghos.Unsupported("checking static ip") } diff --git a/internal/aghos/os.go b/internal/aghos/os.go index 018a3e89..3b688749 100644 --- a/internal/aghos/os.go +++ b/internal/aghos/os.go @@ -175,3 +175,13 @@ func RootDirFS() (fsys fs.FS) { // behavior is undocumented but it currently works. return os.DirFS("") } + +// NotifyShutdownSignal notifies c on receiving shutdown signals. +func NotifyShutdownSignal(c chan<- os.Signal) { + notifyShutdownSignal(c) +} + +// IsShutdownSignal returns true if sig is a shutdown signal. +func IsShutdownSignal(sig os.Signal) (ok bool) { + return isShutdownSignal(sig) +} diff --git a/internal/aghos/os_unix.go b/internal/aghos/os_unix.go new file mode 100644 index 00000000..9a3cc308 --- /dev/null +++ b/internal/aghos/os_unix.go @@ -0,0 +1,27 @@ +//go:build darwin || freebsd || linux || openbsd +// +build darwin freebsd linux openbsd + +package aghos + +import ( + "os" + "os/signal" + + "golang.org/x/sys/unix" +) + +func notifyShutdownSignal(c chan<- os.Signal) { + signal.Notify(c, unix.SIGINT, unix.SIGQUIT, unix.SIGTERM) +} + +func isShutdownSignal(sig os.Signal) (ok bool) { + switch sig { + case + unix.SIGINT, + unix.SIGQUIT, + unix.SIGTERM: + return true + default: + return false + } +} diff --git a/internal/aghos/os_windows.go b/internal/aghos/os_windows.go index bff5a3f0..31fca3ef 100644 --- a/internal/aghos/os_windows.go +++ b/internal/aghos/os_windows.go @@ -4,6 +4,10 @@ package aghos import ( + "os" + "os/signal" + "syscall" + "golang.org/x/sys/windows" ) @@ -35,3 +39,20 @@ func haveAdminRights() (bool, error) { func isOpenWrt() (ok bool) { return false } + +func notifyShutdownSignal(c chan<- os.Signal) { + // syscall.SIGTERM is processed automatically. See go doc os/signal, + // section Windows. + signal.Notify(c, os.Interrupt) +} + +func isShutdownSignal(sig os.Signal) (ok bool) { + switch sig { + case + os.Interrupt, + syscall.SIGTERM: + return true + default: + return false + } +} diff --git a/internal/dnsforward/config.go b/internal/dnsforward/config.go index 9a050f52..16a6325e 100644 --- a/internal/dnsforward/config.go +++ b/internal/dnsforward/config.go @@ -122,6 +122,7 @@ type FilteringConfig struct { EnableDNSSEC bool `yaml:"enable_dnssec"` // Set AD flag in outcoming DNS request EnableEDNSClientSubnet bool `yaml:"edns_client_subnet"` // Enable EDNS Client Subnet option MaxGoroutines uint32 `yaml:"max_goroutines"` // Max. number of parallel goroutines for processing incoming requests + HandleDDR bool `yaml:"handle_ddr"` // Handle DDR requests // IpsetList is the ipset configuration that allows AdGuard Home to add // IP addresses of the specified domain names to an ipset list. Syntax: @@ -151,7 +152,7 @@ type TLSConfig struct { PrivateKeyData []byte `yaml:"-" json:"-"` // ServerName is the hostname of the server. Currently, it is only being - // used for ClientID checking. + // used for ClientID checking and Discovery of Designated Resolvers (DDR). ServerName string `yaml:"-" json:"-"` cert tls.Certificate diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index d423482a..19d54d91 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -76,6 +76,10 @@ const ( resultCodeError ) +// ddrHostFQDN is the FQDN used in Discovery of Designated Resolvers (DDR) requests. +// See https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html. +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{ @@ -94,6 +98,7 @@ func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error { mods := []modProcessFunc{ s.processRecursion, s.processInitial, + s.processDDRQuery, s.processDetermineLocal, s.processInternalHosts, s.processRestrictLocal, @@ -241,6 +246,77 @@ 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. +// +// 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] + + if !s.conf.HandleDDR { + return resultCodeSuccess + } + + if question.Name == ddrHostFQDN { + // TODO(a.garipov): Check DoQ support in next RFC drafts. + if s.dnsProxy.TLSListenAddr == nil && s.dnsProxy.HTTPSListenAddr == nil || + question.Qtype != dns.TypeSVCB { + d.Res = s.makeResponse(d.Req) + + return resultCodeFinish + } + + d.Res = s.makeDDRResponse(d.Req) + + return resultCodeFinish + } + + return resultCodeSuccess +} + +// makeDDRResponse creates DDR answer according to server configuration. +func (s *Server) makeDDRResponse(req *dns.Msg) (resp *dns.Msg) { + resp = s.makeResponse(req) + domainName := s.conf.ServerName + + for _, addr := range s.dnsProxy.HTTPSListenAddr { + values := []dns.SVCBKeyValue{ + &dns.SVCBAlpn{Alpn: []string{"h2"}}, + &dns.SVCBPort{Port: uint16(addr.Port)}, + &dns.SVCBDoHPath{Template: "/dns-query?dns"}, + } + + ans := &dns.SVCB{ + Hdr: s.hdr(req, dns.TypeSVCB), + Priority: 1, + Target: domainName, + Value: values, + } + + resp.Answer = append(resp.Answer, ans) + } + + for _, addr := range s.dnsProxy.TLSListenAddr { + values := []dns.SVCBKeyValue{ + &dns.SVCBAlpn{Alpn: []string{"dot"}}, + &dns.SVCBPort{Port: uint16(addr.Port)}, + } + + ans := &dns.SVCB{ + Hdr: s.hdr(req, dns.TypeSVCB), + Priority: 2, + Target: domainName, + Value: values, + } + + resp.Answer = append(resp.Answer, ans) + } + + return resp +} + // processDetermineLocal determines if the client's IP address is from // locally-served network and saves the result into the context. func (s *Server) processDetermineLocal(dctx *dnsContext) (rc resultCode) { diff --git a/internal/dnsforward/dns_test.go b/internal/dnsforward/dns_test.go index 54104268..8ab7501c 100644 --- a/internal/dnsforward/dns_test.go +++ b/internal/dnsforward/dns_test.go @@ -14,6 +14,152 @@ import ( "github.com/stretchr/testify/require" ) +const ddrTestDomainName = "dns.example.net" + +func TestServer_ProcessDDRQuery(t *testing.T) { + dohSVCB := &dns.SVCB{ + Priority: 1, + Target: ddrTestDomainName, + Value: []dns.SVCBKeyValue{ + &dns.SVCBAlpn{Alpn: []string{"h2"}}, + &dns.SVCBPort{Port: 8044}, + &dns.SVCBDoHPath{Template: "/dns-query?dns"}, + }, + } + + dotSVCB := &dns.SVCB{ + Priority: 2, + Target: ddrTestDomainName, + Value: []dns.SVCBKeyValue{ + &dns.SVCBAlpn{Alpn: []string{"dot"}}, + &dns.SVCBPort{Port: 8043}, + }, + } + + testCases := []struct { + name string + host string + want []*dns.SVCB + wantRes resultCode + portDoH int + portDoT int + qtype uint16 + ddrEnabled bool + }{{ + name: "pass_host", + wantRes: resultCodeSuccess, + host: "example.net.", + qtype: dns.TypeSVCB, + ddrEnabled: true, + portDoH: 8043, + }, { + name: "pass_qtype", + wantRes: resultCodeFinish, + host: ddrHostFQDN, + qtype: dns.TypeA, + ddrEnabled: true, + portDoH: 8043, + }, { + name: "pass_disabled_tls", + wantRes: resultCodeFinish, + host: ddrHostFQDN, + qtype: dns.TypeSVCB, + ddrEnabled: true, + }, { + name: "pass_disabled_ddr", + wantRes: resultCodeSuccess, + host: ddrHostFQDN, + qtype: dns.TypeSVCB, + ddrEnabled: false, + portDoH: 8043, + }, { + name: "dot", + wantRes: resultCodeFinish, + want: []*dns.SVCB{dotSVCB}, + host: ddrHostFQDN, + qtype: dns.TypeSVCB, + ddrEnabled: true, + portDoT: 8043, + }, { + name: "doh", + wantRes: resultCodeFinish, + want: []*dns.SVCB{dohSVCB}, + host: ddrHostFQDN, + qtype: dns.TypeSVCB, + ddrEnabled: true, + portDoH: 8044, + }, { + name: "dot_doh", + wantRes: resultCodeFinish, + want: []*dns.SVCB{dotSVCB, dohSVCB}, + host: ddrHostFQDN, + qtype: dns.TypeSVCB, + ddrEnabled: true, + portDoT: 8043, + portDoH: 8044, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + s := prepareTestServer(t, tc.portDoH, tc.portDoT, tc.ddrEnabled) + + req := createTestMessageWithType(tc.host, tc.qtype) + + dctx := &dnsContext{ + proxyCtx: &proxy.DNSContext{ + Req: req, + }, + } + + res := s.processDDRQuery(dctx) + require.Equal(t, tc.wantRes, res) + + if tc.wantRes != resultCodeFinish { + return + } + + msg := dctx.proxyCtx.Res + require.NotNil(t, msg) + + for _, v := range tc.want { + v.Hdr = s.hdr(req, dns.TypeSVCB) + } + + assert.ElementsMatch(t, tc.want, msg.Answer) + }) + } +} + +func prepareTestServer(t *testing.T, portDoH, portDoT int, ddrEnabled bool) (s *Server) { + t.Helper() + + proxyConf := proxy.Config{} + + if portDoH > 0 { + proxyConf.HTTPSListenAddr = []*net.TCPAddr{{Port: portDoH}} + } + + if portDoT > 0 { + proxyConf.TLSListenAddr = []*net.TCPAddr{{Port: portDoT}} + } + + s = &Server{ + dnsProxy: &proxy.Proxy{ + Config: proxyConf, + }, + conf: ServerConfig{ + FilteringConfig: FilteringConfig{ + HandleDDR: ddrEnabled, + }, + TLSConfig: TLSConfig{ + ServerName: ddrTestDomainName, + }, + }, + } + + return s +} + func TestServer_ProcessDetermineLocal(t *testing.T) { s := &Server{ privateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed), diff --git a/internal/home/clients.go b/internal/home/clients.go index fe15e514..d4d6b959 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -59,6 +59,16 @@ const ( ClientSourceHostsFile ) +// clientSourceConf is used to configure where the runtime clients will be +// obtained from. +type clientSourcesConf struct { + WHOIS bool `yaml:"whois"` + ARP bool `yaml:"arp"` + RDNS bool `yaml:"rdns"` + DHCP bool `yaml:"dhcp"` + HostsFile bool `yaml:"hosts"` +} + // RuntimeClient information type RuntimeClient struct { WHOISInfo *RuntimeClientWHOISInfo @@ -134,14 +144,14 @@ func (clients *clientsContainer) Init( clients.dhcpServer.SetOnLeaseChanged(clients.onDHCPLeaseChanged) } - go clients.handleHostsUpdates() + if clients.etcHosts != nil { + go clients.handleHostsUpdates() + } } func (clients *clientsContainer) handleHostsUpdates() { - if clients.etcHosts != nil { - for upd := range clients.etcHosts.Upd() { - clients.addFromHostsFile(upd) - } + for upd := range clients.etcHosts.Upd() { + clients.addFromHostsFile(upd) } } @@ -158,7 +168,9 @@ func (clients *clientsContainer) Start() { // Reload reloads runtime clients. func (clients *clientsContainer) Reload() { - clients.addFromSystemARP() + if clients.arpdb != nil { + clients.addFromSystemARP() + } } type clientObject struct { @@ -843,7 +855,7 @@ func (clients *clientsContainer) addFromSystemARP() { // updateFromDHCP adds the clients that have a non-empty hostname from the DHCP // server. func (clients *clientsContainer) updateFromDHCP(add bool) { - if clients.dhcpServer == nil { + if clients.dhcpServer == nil || !config.Clients.Sources.DHCP { return } diff --git a/internal/home/config.go b/internal/home/config.go index aa8450be..14f5781e 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -51,6 +51,13 @@ type osConfig struct { RlimitNoFile uint64 `yaml:"rlimit_nofile"` } +type clientsConfig struct { + // Sources defines the set of sources to fetch the runtime clients from. + Sources *clientSourcesConf `yaml:"runtime_sources"` + // Persistent are the configured clients. + Persistent []*clientObject `yaml:"persistent"` +} + // configuration is loaded from YAML // field ordering is important -- yaml fields will mirror ordering from here type configuration struct { @@ -88,7 +95,7 @@ type configuration struct { // Clients contains the YAML representations of the persistent clients. // This field is only used for reading and writing persistent client data. // Keep this field sorted to ensure consistent ordering. - Clients []*clientObject `yaml:"clients"` + Clients *clientsConfig `yaml:"clients"` logSettings `yaml:",inline"` @@ -123,9 +130,6 @@ type dnsConfig struct { // UpstreamTimeout is the timeout for querying upstream servers. UpstreamTimeout timeutil.Duration `yaml:"upstream_timeout"` - // ResolveClients enables and disables resolving clients with RDNS. - ResolveClients bool `yaml:"resolve_clients"` - // PrivateNets is the set of IP networks for which the private reverse DNS // resolver should be used. PrivateNets []string `yaml:"private_networks"` @@ -183,6 +187,7 @@ var config = &configuration{ Ratelimit: 20, RefuseAny: true, AllServers: false, + HandleDDR: true, FastestTimeout: timeutil.Duration{ Duration: fastip.DefaultPingWaitTimeout, }, @@ -198,7 +203,6 @@ var config = &configuration{ FilteringEnabled: true, // whether or not use filter lists FiltersUpdateIntervalHours: 24, UpstreamTimeout: timeutil.Duration{Duration: dnsforward.DefaultTimeout}, - ResolveClients: true, UsePrivateRDNS: true, }, TLS: tlsConfigSettings{ @@ -209,6 +213,15 @@ var config = &configuration{ DHCP: &dhcpd.ServerConfig{ LocalDomainName: "lan", }, + Clients: &clientsConfig{ + Sources: &clientSourcesConf{ + WHOIS: true, + ARP: true, + RDNS: true, + DHCP: true, + HostsFile: true, + }, + }, logSettings: logSettings{ LogCompress: false, LogLocalTime: false, @@ -404,9 +417,7 @@ func (c *configuration) write() error { s.WriteDiskConfig(&c) dns := &config.DNS dns.FilteringConfig = c - dns.LocalPTRResolvers, - dns.ResolveClients, - dns.UsePrivateRDNS = s.RDNSSettings() + dns.LocalPTRResolvers, config.Clients.Sources.RDNS, dns.UsePrivateRDNS = s.RDNSSettings() } if Context.dhcpServer != nil { @@ -415,7 +426,7 @@ func (c *configuration) write() error { config.DHCP = c } - config.Clients = Context.clients.forConfig() + config.Clients.Persistent = Context.clients.forConfig() configFile := config.getConfigFilename() log.Debug("Writing YAML file: %s", configFile) diff --git a/internal/home/controlupdate.go b/internal/home/controlupdate.go index 79b9f37e..ae469598 100644 --- a/internal/home/controlupdate.go +++ b/internal/home/controlupdate.go @@ -3,6 +3,7 @@ package home import ( "context" "encoding/json" + "fmt" "net/http" "os" "os/exec" @@ -27,12 +28,16 @@ type temporaryError interface { // Get the latest available version from the Internet func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + resp := &versionResponse{} if Context.disableUpdate { - // w.Header().Set("Content-Type", "application/json") resp.Disabled = true - _ = json.NewEncoder(w).Encode(resp) - // TODO(e.burkov): Add error handling and deal with headers. + err := json.NewEncoder(w).Encode(resp) + if err != nil { + aghhttp.Error(r, w, http.StatusInternalServerError, "writing body: %s", err) + } + return } @@ -44,30 +49,48 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { if r.ContentLength != 0 { err = json.NewDecoder(r.Body).Decode(req) if err != nil { - aghhttp.Error(r, w, http.StatusBadRequest, "JSON parse: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "parsing request: %s", err) return } } + err = requestVersionInfo(resp, req.Recheck) + if err != nil { + // Don't wrap the error, because it's informative enough as is. + aghhttp.Error(r, w, http.StatusBadGateway, "%s", err) + + return + } + + err = resp.setAllowedToAutoUpdate() + if err != nil { + // Don't wrap the error, because it's informative enough as is. + aghhttp.Error(r, w, http.StatusInternalServerError, "%s", err) + + return + } + + err = json.NewEncoder(w).Encode(resp) + if err != nil { + aghhttp.Error(r, w, http.StatusInternalServerError, "writing body: %s", err) + } +} + +// requestVersionInfo sets the VersionInfo field of resp if it can reach the +// update server. +func requestVersionInfo(resp *versionResponse, recheck bool) (err error) { for i := 0; i != 3; i++ { - func() { - Context.controlLock.Lock() - defer Context.controlLock.Unlock() - - resp.VersionInfo, err = Context.updater.VersionInfo(req.Recheck) - }() - + resp.VersionInfo, err = Context.updater.VersionInfo(recheck) if err != nil { var terr temporaryError if errors.As(err, &terr) && terr.Temporary() { - // Temporary network error. This case may happen while - // we're restarting our DNS server. Log and sleep for - // some time. + // Temporary network error. This case may happen while we're + // restarting our DNS server. Log and sleep for some time. // // See https://github.com/AdguardTeam/AdGuardHome/issues/934. d := time.Duration(i) * time.Second - log.Info("temp net error: %q; sleeping for %s and retrying", err, d) + log.Info("update: temp net error: %q; sleeping for %s and retrying", err, d) time.Sleep(d) continue @@ -76,29 +99,14 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { break } + if err != nil { vcu := Context.updater.VersionCheckURL() - // TODO(a.garipov): Figure out the purpose of %T verb. - aghhttp.Error( - r, - w, - http.StatusBadGateway, - "Couldn't get version check json from %s: %T %s\n", - vcu, - err, - err, - ) - return + return fmt.Errorf("getting version info from %s: %s", vcu, err) } - resp.confirmAutoUpdate() - - w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(resp) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't write body: %s", err) - } + return nil } // handleUpdate performs an update to the latest available version procedure. @@ -132,31 +140,37 @@ func handleUpdate(w http.ResponseWriter, r *http.Request) { // versionResponse is the response for /control/version.json endpoint. type versionResponse struct { - Disabled bool `json:"disabled"` updater.VersionInfo + Disabled bool `json:"disabled"` } -// confirmAutoUpdate checks the real possibility of auto update. -func (vr *versionResponse) confirmAutoUpdate() { - if vr.CanAutoUpdate != nil && *vr.CanAutoUpdate { - canUpdate := true - - var tlsConf *tlsConfigSettings - if runtime.GOOS != "windows" { - tlsConf = &tlsConfigSettings{} - Context.tls.WriteDiskConfig(tlsConf) - } - - if tlsConf != nil && - ((tlsConf.Enabled && (tlsConf.PortHTTPS < 1024 || - tlsConf.PortDNSOverTLS < 1024 || - tlsConf.PortDNSOverQUIC < 1024)) || - config.BindPort < 1024 || - config.DNS.Port < 1024) { - canUpdate, _ = aghnet.CanBindPrivilegedPorts() - } - vr.CanAutoUpdate = &canUpdate +// setAllowedToAutoUpdate sets CanAutoUpdate to true if AdGuard Home is actually +// allowed to perform an automatic update by the OS. +func (vr *versionResponse) setAllowedToAutoUpdate() (err error) { + if vr.CanAutoUpdate == nil || !*vr.CanAutoUpdate { + return } + + tlsConf := &tlsConfigSettings{} + Context.tls.WriteDiskConfig(tlsConf) + + canUpdate := true + if tlsConfUsesPrivilegedPorts(tlsConf) || config.BindPort < 1024 || config.DNS.Port < 1024 { + canUpdate, err = aghnet.CanBindPrivilegedPorts() + if err != nil { + return fmt.Errorf("checking ability to bind privileged ports: %w", err) + } + } + + vr.CanAutoUpdate = &canUpdate + + return nil +} + +// tlsConfUsesPrivilegedPorts returns true if the provided TLS configuration +// indicates that privileged ports are used. +func tlsConfUsesPrivilegedPorts(c *tlsConfigSettings) (ok bool) { + return c.Enabled && (c.PortHTTPS < 1024 || c.PortDNSOverTLS < 1024 || c.PortDNSOverQUIC < 1024) } // finishUpdate completes an update procedure. diff --git a/internal/home/dns.go b/internal/home/dns.go index c30e12ec..1c04c6c3 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -135,8 +135,13 @@ func initDNSServer() (err error) { return fmt.Errorf("dnsServer.Prepare: %w", err) } - Context.rdns = NewRDNS(Context.dnsServer, &Context.clients, config.DNS.UsePrivateRDNS) - Context.whois = initWHOIS(&Context.clients) + if config.Clients.Sources.RDNS { + Context.rdns = NewRDNS(Context.dnsServer, &Context.clients, config.DNS.UsePrivateRDNS) + } + + if config.Clients.Sources.WHOIS { + Context.whois = initWHOIS(&Context.clients) + } Context.filters.Init() return nil @@ -153,10 +158,11 @@ func onDNSRequest(pctx *proxy.DNSContext) { return } - if config.DNS.ResolveClients && !ip.IsLoopback() { + srcs := config.Clients.Sources + if srcs.RDNS && !ip.IsLoopback() { Context.rdns.Begin(ip) } - if !netutil.IsSpecialPurpose(ip) { + if srcs.WHOIS && !netutil.IsSpecialPurpose(ip) { Context.whois.Begin(ip) } } @@ -239,7 +245,7 @@ func generateServerConfig() (newConf dnsforward.ServerConfig, err error) { newConf.FilterHandler = applyAdditionalFiltering newConf.GetCustomUpstreamByClient = Context.clients.findUpstreams - newConf.ResolveClients = dnsConf.ResolveClients + newConf.ResolveClients = config.Clients.Sources.RDNS newConf.UsePrivateRDNS = dnsConf.UsePrivateRDNS newConf.LocalPTRResolvers = dnsConf.LocalPTRResolvers newConf.UpstreamTimeout = dnsConf.UpstreamTimeout.Duration @@ -324,24 +330,28 @@ func getDNSEncryption() (de dnsEncryption) { // applyAdditionalFiltering adds additional client information and settings if // the client has them. -func applyAdditionalFiltering(clientAddr net.IP, clientID string, setts *filtering.Settings) { +func applyAdditionalFiltering(clientIP net.IP, clientID string, setts *filtering.Settings) { Context.dnsFilter.ApplyBlockedServices(setts, nil, true) - if clientAddr == nil { + log.Debug("looking up settings for client with ip %s and clientid %q", clientIP, clientID) + + if clientIP == nil { return } - setts.ClientIP = clientAddr + setts.ClientIP = clientIP c, ok := Context.clients.Find(clientID) if !ok { - c, ok = Context.clients.Find(clientAddr.String()) + c, ok = Context.clients.Find(clientIP.String()) if !ok { + log.Debug("client with ip %s and clientid %q not found", clientIP, clientID) + return } } - log.Debug("using settings for client %s with ip %s and clientid %q", c.Name, clientAddr, clientID) + log.Debug("using settings for client %q with ip %s and clientid %q", c.Name, clientIP, clientID) if c.UseOwnBlockedServices { Context.dnsFilter.ApplyBlockedServices(setts, c.BlockedServices, false) @@ -387,10 +397,11 @@ func startDNSServer() error { continue } - if config.DNS.ResolveClients && !ip.IsLoopback() { + srcs := config.Clients.Sources + if srcs.RDNS && !ip.IsLoopback() { Context.rdns.Begin(ip) } - if !netutil.IsSpecialPurpose(ip) { + if srcs.WHOIS && !netutil.IsSpecialPurpose(ip) { Context.whois.Begin(ip) } } diff --git a/internal/home/home.go b/internal/home/home.go index 420e67d8..539552d1 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -173,6 +173,11 @@ func setupContext(args options) { os.Exit(0) } + + if !args.noEtcHosts && config.Clients.Sources.HostsFile { + err = setupHostsContainer() + fatalOnError(err) + } } Context.mux = http.NewServeMux() @@ -285,14 +290,12 @@ func setupConfig(args options) (err error) { ConfName: config.getConfigFilename(), }) - if !args.noEtcHosts { - if err = setupHostsContainer(); err != nil { - return err - } + var arpdb aghnet.ARPDB + if config.Clients.Sources.ARP { + arpdb = aghnet.NewARPDB() } - arpdb := aghnet.NewARPDB() - Context.clients.Init(config.Clients, Context.dhcpServer, Context.etcHosts, arpdb) + Context.clients.Init(config.Clients.Persistent, Context.dhcpServer, Context.etcHosts, arpdb) if args.bindPort != 0 { uc := aghalg.UniqChecker{} diff --git a/internal/home/options.go b/internal/home/options.go index dc11ca35..6f5a4d8d 100644 --- a/internal/home/options.go +++ b/internal/home/options.go @@ -230,13 +230,19 @@ var helpArg = arg{ } var noEtcHostsArg = arg{ - description: "Do not use the OS-provided hosts.", + description: "Deprecated. Do not use the OS-provided hosts.", longName: "no-etc-hosts", shortName: "", updateWithValue: nil, updateNoValue: func(o options) (options, error) { o.noEtcHosts = true; return o, nil }, - effect: nil, - serialize: func(o options) []string { return boolSliceOrNil(o.noEtcHosts) }, + effect: func(_ options, _ string) (f effect, err error) { + log.Info( + "warning: --no-etc-hosts flag is deprecated and will be removed in the future versions", + ) + + return nil, nil + }, + serialize: func(o options) []string { return boolSliceOrNil(o.noEtcHosts) }, } var localFrontendArg = arg{ diff --git a/internal/home/upgrade.go b/internal/home/upgrade.go index 34297470..d9611dc9 100644 --- a/internal/home/upgrade.go +++ b/internal/home/upgrade.go @@ -21,9 +21,11 @@ import ( ) // currentSchemaVersion is the current schema version. -const currentSchemaVersion = 13 +const currentSchemaVersion = 14 // These aliases are provided for convenience. +// +// TODO(e.burkov): Remove any after updating to Go 1.18. type ( any = interface{} yarr = []any @@ -86,6 +88,7 @@ func upgradeConfigSchema(oldVersion int, diskConf yobj) (err error) { upgradeSchema10to11, upgradeSchema11to12, upgradeSchema12to13, + upgradeSchema13to14, } n := 0 @@ -726,7 +729,7 @@ func upgradeSchema12to13(diskConf yobj) (err error) { var dhcp yobj dhcp, ok = dhcpVal.(yobj) if !ok { - return fmt.Errorf("unexpected type of dhcp: %T", dnsVal) + return fmt.Errorf("unexpected type of dhcp: %T", dhcpVal) } const field = "local_domain_name" @@ -737,6 +740,68 @@ func upgradeSchema12to13(diskConf yobj) (err error) { return nil } +// 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 +// +func upgradeSchema13to14(diskConf yobj) (err error) { + log.Printf("Upgrade yaml: 13 to 14") + diskConf["schema_version"] = 14 + + clientsVal, ok := diskConf["clients"] + if !ok { + clientsVal = yarr{} + } + + var rdnsSrc bool + if dnsVal, dok := diskConf["dns"]; dok { + var dnsSettings yobj + dnsSettings, ok = dnsVal.(yobj) + if !ok { + return fmt.Errorf("unexpected type of dns: %T", dnsVal) + } + + var rdnsSrcVal any + rdnsSrcVal, ok = dnsSettings["resolve_clients"] + if ok { + rdnsSrc, ok = rdnsSrcVal.(bool) + if !ok { + return fmt.Errorf("unexpected type of resolve_clients: %T", rdnsSrcVal) + } + + delete(dnsSettings, "resolve_clients") + } + } + + diskConf["clients"] = yobj{ + "persistent": clientsVal, + "runtime_sources": &clientSourcesConf{ + WHOIS: true, + ARP: true, + RDNS: rdnsSrc, + DHCP: true, + HostsFile: true, + }, + } + + return nil +} + // TODO(a.garipov): Replace with log.Output when we port it to our logging // package. func funcName() string { diff --git a/internal/home/upgrade_test.go b/internal/home/upgrade_test.go index c63bc443..4c25cba3 100644 --- a/internal/home/upgrade_test.go +++ b/internal/home/upgrade_test.go @@ -513,46 +513,129 @@ func TestUpgradeSchema11to12(t *testing.T) { } func TestUpgradeSchema12to13(t *testing.T) { - t.Run("no_dns", func(t *testing.T) { - conf := yobj{} + const newSchemaVer = 13 - err := upgradeSchema12to13(conf) - require.NoError(t, err) - - assert.Equal(t, conf["schema_version"], 13) - }) - - t.Run("no_dhcp", func(t *testing.T) { - conf := yobj{ - "dns": yobj{}, - } - - err := upgradeSchema12to13(conf) - require.NoError(t, err) - - assert.Equal(t, conf["schema_version"], 13) - }) - - t.Run("good", func(t *testing.T) { - conf := yobj{ + testCases := []struct { + in yobj + want yobj + name string + }{{ + in: yobj{}, + want: yobj{"schema_version": newSchemaVer}, + name: "no_dns", + }, { + in: yobj{"dns": yobj{}}, + want: yobj{ + "dns": yobj{}, + "schema_version": newSchemaVer, + }, + name: "no_dhcp", + }, { + in: yobj{ "dns": yobj{ "local_domain_name": "lan", }, "dhcp": yobj{}, - "schema_version": 12, - } - - wantConf := yobj{ + "schema_version": newSchemaVer - 1, + }, + want: yobj{ "dns": yobj{}, "dhcp": yobj{ "local_domain_name": "lan", }, - "schema_version": 13, - } + "schema_version": newSchemaVer, + }, + name: "good", + }} - err := upgradeSchema12to13(conf) - require.NoError(t, err) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := upgradeSchema12to13(tc.in) + require.NoError(t, err) - assert.Equal(t, wantConf, conf) - }) + assert.Equal(t, tc.want, tc.in) + }) + } +} + +func TestUpgradeSchema13to14(t *testing.T) { + const newSchemaVer = 14 + + testClient := &clientObject{ + Name: "agh-client", + IDs: []string{"id1"}, + UseGlobalSettings: true, + } + + testCases := []struct { + in yobj + want yobj + name string + }{{ + in: yobj{}, + want: yobj{ + "schema_version": newSchemaVer, + // The clients field will be added anyway. + "clients": yobj{ + "persistent": yarr{}, + "runtime_sources": &clientSourcesConf{ + WHOIS: true, + ARP: true, + RDNS: false, + DHCP: true, + HostsFile: true, + }, + }, + }, + name: "no_clients", + }, { + in: yobj{ + "clients": []*clientObject{testClient}, + }, + want: yobj{ + "schema_version": newSchemaVer, + "clients": yobj{ + "persistent": []*clientObject{testClient}, + "runtime_sources": &clientSourcesConf{ + WHOIS: true, + ARP: true, + RDNS: false, + DHCP: true, + HostsFile: true, + }, + }, + }, + name: "no_dns", + }, { + in: yobj{ + "clients": []*clientObject{testClient}, + "dns": yobj{ + "resolve_clients": true, + }, + }, + want: yobj{ + "schema_version": newSchemaVer, + "clients": yobj{ + "persistent": []*clientObject{testClient}, + "runtime_sources": &clientSourcesConf{ + WHOIS: true, + ARP: true, + RDNS: true, + DHCP: true, + HostsFile: true, + }, + }, + "dns": yobj{}, + }, + name: "good", + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := upgradeSchema13to14(tc.in) + require.NoError(t, err) + + assert.Equal(t, tc.want, tc.in) + }) + } } diff --git a/internal/tools/go.mod b/internal/tools/go.mod index 2ad6ce16..bb587070 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -11,7 +11,7 @@ require ( github.com/securego/gosec/v2 v2.11.0 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a - honnef.co/go/tools v0.3.0 + honnef.co/go/tools v0.3.1 mvdan.cc/gofumpt v0.3.1 mvdan.cc/unparam v0.0.0-20220316160445-06cc5682983b ) @@ -19,16 +19,16 @@ require ( require ( github.com/BurntSushi/toml v1.1.0 // indirect github.com/client9/misspell v0.3.4 // indirect - github.com/google/go-cmp v0.5.7 // indirect + github.com/google/go-cmp v0.5.8 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gookit/color v1.5.0 // 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-20220407100705-7b9b53b0aca4 // indirect + golang.org/x/exp/typeparams v0.0.0-20220426173459-3bcf042a4bf5 // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/internal/tools/go.sum b/internal/tools/go.sum index 7dbf5491..2f04e4a6 100644 --- a/internal/tools/go.sum +++ b/internal/tools/go.sum @@ -157,8 +157,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= 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/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= @@ -420,8 +421,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 h1:FR+oGxGfbQu1d+jglI3rCkjAjUnhRSZcUxr+DqlDLNo= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20220407100705-7b9b53b0aca4 h1:P5yukcpQfG1ZDKR0pGdaZCVwaNPntMxLFKYg81li58M= -golang.org/x/exp/typeparams v0.0.0-20220407100705-7b9b53b0aca4/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20220426173459-3bcf042a4bf5 h1:pKfHvPtBtqS0+V/V9Y0cZQa2h8HJV/qSRJiGgYu+LQA= +golang.org/x/exp/typeparams v0.0.0-20220426173459-3bcf042a4bf5/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= @@ -559,8 +560,8 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/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-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -751,8 +752,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh 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.0 h1:2LdYUZ7CIxnYgskbUZfY7FPggmqnh6shBqfWa8Tn3XU= -honnef.co/go/tools v0.3.0/go.mod h1:vlRD9XErLMGT+mDuofSr0mMMquscM/1nQqtRSsh6m70= +honnef.co/go/tools v0.3.1 h1:1kJlrWJLkaGXgcaeosRXViwviqjI7nkBvU2+sZW0AYc= +honnef.co/go/tools v0.3.1/go.mod h1:vlRD9XErLMGT+mDuofSr0mMMquscM/1nQqtRSsh6m70= 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-20220316160445-06cc5682983b h1:C8Pi6noat8BcrL9WnSRYeQ63fpkJk3hKVHtF5731kIw= diff --git a/internal/updater/check.go b/internal/updater/check.go index edf046af..ec7176b2 100644 --- a/internal/updater/check.go +++ b/internal/updater/check.go @@ -17,11 +17,11 @@ const versionCheckPeriod = 8 * time.Hour // VersionInfo contains information about a new version. type VersionInfo struct { + CanAutoUpdate *bool `json:"can_autoupdate,omitempty"` NewVersion string `json:"new_version,omitempty"` Announcement string `json:"announcement,omitempty"` AnnouncementURL string `json:"announcement_url,omitempty"` SelfUpdateMinVersion string `json:"-"` - CanAutoUpdate *bool `json:"can_autoupdate,omitempty"` } // MaxResponseSize is responses on server's requests maximum length in bytes. diff --git a/internal/v1/agh/agh.go b/internal/v1/agh/agh.go new file mode 100644 index 00000000..212da4d6 --- /dev/null +++ b/internal/v1/agh/agh.go @@ -0,0 +1,33 @@ +// Package agh contains common entities and interfaces of AdGuard Home. +// +// TODO(a.garipov): Move to the upper-level internal/. +package agh + +import "context" + +// Service is the interface for API servers. +// +// TODO(a.garipov): Consider adding a context to Start. +// +// TODO(a.garipov): Consider adding a Wait method or making an extension +// interface for that. +type Service interface { + // Start starts the service. It does not block. + Start() (err error) + + // Shutdown gracefully stops the service. ctx is used to determine + // a timeout before trying to stop the service less gracefully. + Shutdown(ctx context.Context) (err error) +} + +// type check +var _ Service = EmptyService{} + +// EmptyService is a Service that does nothing. +type EmptyService struct{} + +// Start implements the Service interface for EmptyService. +func (EmptyService) Start() (err error) { return nil } + +// Shutdown implements the Service interface for EmptyService. +func (EmptyService) Shutdown(_ context.Context) (err error) { return nil } diff --git a/internal/v1/cmd/cmd.go b/internal/v1/cmd/cmd.go new file mode 100644 index 00000000..4c4e252f --- /dev/null +++ b/internal/v1/cmd/cmd.go @@ -0,0 +1,69 @@ +// Package cmd is the AdGuard Home entry point. It contains the on-disk +// configuration file utilities, signal processing logic, and so on. +// +// TODO(a.garipov): Move to the upper-level internal/. +package cmd + +import ( + "context" + "io/fs" + "math/rand" + "net" + "time" + + "github.com/AdguardTeam/AdGuardHome/internal/v1/websvc" + "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/netutil" +) + +// Main is the entry point of application. +func Main(clientBuildFS fs.FS) { + // # Initial Configuration + + rand.Seed(time.Now().UnixNano()) + + // TODO(a.garipov): Set up logging. + + // # Web Service + + // TODO(a.garipov): Use in the Web service. + _ = clientBuildFS + + // TODO(a.garipov): Make configurable. + web := websvc.New(&websvc.Config{ + Addresses: []*netutil.IPPort{{ + IP: net.IP{127, 0, 0, 1}, + Port: 3001, + }}, + Timeout: 60 * time.Second, + }) + + err := web.Start() + fatalOnError(err) + + sigHdlr := newSignalHandler( + web, + ) + + go sigHdlr.handle() + + select {} +} + +// defaultTimeout is the timeout used for some operations where another timeout +// hasn't been defined yet. +const defaultTimeout = 15 * time.Second + +// ctxWithDefaultTimeout is a helper function that returns a context with +// timeout set to defaultTimeout. +func ctxWithDefaultTimeout() (ctx context.Context, cancel context.CancelFunc) { + return context.WithTimeout(context.Background(), defaultTimeout) +} + +// fatalOnError is a helper that exits the program with an error code if err is +// not nil. It must only be used within Main. +func fatalOnError(err error) { + if err != nil { + log.Fatal(err) + } +} diff --git a/internal/v1/cmd/signal.go b/internal/v1/cmd/signal.go new file mode 100644 index 00000000..b9f09673 --- /dev/null +++ b/internal/v1/cmd/signal.go @@ -0,0 +1,70 @@ +package cmd + +import ( + "os" + + "github.com/AdguardTeam/AdGuardHome/internal/aghos" + "github.com/AdguardTeam/AdGuardHome/internal/v1/agh" + "github.com/AdguardTeam/golibs/log" +) + +// signalHandler processes incoming signals and shuts services down. +type signalHandler struct { + signal chan os.Signal + + // services are the services that are shut down before application + // exiting. + services []agh.Service +} + +// handle processes OS signals. +func (h *signalHandler) handle() { + defer log.OnPanic("signalProcessor.handle") + + for sig := range h.signal { + log.Info("sigproc: received signal %q", sig) + + if aghos.IsShutdownSignal(sig) { + h.shutdown() + } + } +} + +// Exit status constants. +const ( + statusSuccess = 0 + statusError = 1 +) + +// shutdown gracefully shuts down all services. +func (h *signalHandler) shutdown() { + ctx, cancel := ctxWithDefaultTimeout() + defer cancel() + + status := statusSuccess + + log.Info("sigproc: shutting down services") + for i, service := range h.services { + err := service.Shutdown(ctx) + if err != nil { + log.Error("sigproc: shutting down service at index %d: %s", i, err) + status = statusError + } + } + + log.Info("sigproc: shutting down adguard home") + + os.Exit(status) +} + +// newSignalHandler returns a new signalHandler that shuts down svcs. +func newSignalHandler(svcs ...agh.Service) (h *signalHandler) { + h = &signalHandler{ + signal: make(chan os.Signal, 1), + services: svcs, + } + + aghos.NotifyShutdownSignal(h.signal) + + return h +} diff --git a/internal/v1/websvc/websvc.go b/internal/v1/websvc/websvc.go new file mode 100644 index 00000000..e741ff3d --- /dev/null +++ b/internal/v1/websvc/websvc.go @@ -0,0 +1,185 @@ +// Package websvc contains the AdGuard Home web service. +// +// TODO(a.garipov): Add tests. +package websvc + +import ( + "context" + "crypto/tls" + "fmt" + "io" + "net" + "net/http" + "sync" + "time" + + "github.com/AdguardTeam/AdGuardHome/internal/v1/agh" + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/netutil" +) + +// Config is the AdGuard Home web service configuration structure. +type Config struct { + // TLS is the optional TLS configuration. If TLS is not nil, + // SecureAddresses must not be empty. + TLS *tls.Config + + // Addresses are the addresses on which to serve the plain HTTP API. + Addresses []*netutil.IPPort + + // SecureAddresses are the addresses on which to serve the HTTPS API. If + // SecureAddresses is not empty, TLS must not be nil. + SecureAddresses []*netutil.IPPort + + // Timeout is the timeout for all server operations. + Timeout time.Duration +} + +// Service is the AdGuard Home web service. A nil *Service is a valid service +// that does nothing. +type Service struct { + tls *tls.Config + servers []*http.Server + timeout time.Duration +} + +// New returns a new properly initialized *Service. If c is nil, svc is a nil +// *Service that does nothing. +func New(c *Config) (svc *Service) { + if c == nil { + return nil + } + + svc = &Service{ + tls: c.TLS, + timeout: c.Timeout, + } + + mux := http.NewServeMux() + mux.HandleFunc("/health-check", svc.handleGetHealthCheck) + + for _, a := range c.Addresses { + addr := a.String() + errLog := log.StdLog("websvc: http: "+addr, log.ERROR) + svc.servers = append(svc.servers, &http.Server{ + Addr: addr, + Handler: mux, + ErrorLog: errLog, + ReadTimeout: c.Timeout, + WriteTimeout: c.Timeout, + IdleTimeout: c.Timeout, + ReadHeaderTimeout: c.Timeout, + }) + } + + for _, a := range c.SecureAddresses { + addr := a.String() + errLog := log.StdLog("websvc: https: "+addr, log.ERROR) + svc.servers = append(svc.servers, &http.Server{ + Addr: addr, + Handler: mux, + TLSConfig: c.TLS, + ErrorLog: errLog, + ReadTimeout: c.Timeout, + WriteTimeout: c.Timeout, + IdleTimeout: c.Timeout, + ReadHeaderTimeout: c.Timeout, + }) + } + + return svc +} + +// Addrs returns all addresses on which this server serves the HTTP API. Addrs +// must not be called until Start returns. +func (svc *Service) Addrs() (addrs []string) { + addrs = make([]string, 0, len(svc.servers)) + for _, srv := range svc.servers { + addrs = append(addrs, srv.Addr) + } + + return addrs +} + +// handleGetHealthCheck is the handler for the GET /health-check HTTP API. +func (svc *Service) handleGetHealthCheck(w http.ResponseWriter, _ *http.Request) { + _, _ = io.WriteString(w, "OK") +} + +// unit is a convenient alias for struct{}. +type unit = struct{} + +// type check +var _ agh.Service = (*Service)(nil) + +// Start implements the agh.Service interface for *Service. svc may be nil. +// After Start exits, all HTTP servers have tried to start, possibly failing and +// writing error messages to the log. +func (svc *Service) Start() (err error) { + if svc == nil { + return nil + } + + srvs := svc.servers + + wg := &sync.WaitGroup{} + wg.Add(len(srvs)) + for _, srv := range srvs { + go serve(srv, wg) + } + + wg.Wait() + + return nil +} + +// serve starts and runs srv and writes all errors into its log. +func serve(srv *http.Server, wg *sync.WaitGroup) { + addr := srv.Addr + defer log.OnPanic(addr) + + var l net.Listener + var err error + if srv.TLSConfig == nil { + l, err = net.Listen("tcp", addr) + } else { + l, err = tls.Listen("tcp", addr, srv.TLSConfig) + } + if err != nil { + srv.ErrorLog.Printf("starting srv %s: binding: %s", addr, err) + } + + // Update the server's address in case the address had the port zero, which + // would mean that a random available port was automatically chosen. + srv.Addr = l.Addr().String() + + log.Info("websvc: starting srv http://%s", srv.Addr) + wg.Done() + + err = srv.Serve(l) + if err != nil && !errors.Is(err, http.ErrServerClosed) { + srv.ErrorLog.Printf("starting srv %s: %s", addr, err) + } +} + +// Shutdown implements the agh.Service interface for *Service. svc may be nil. +func (svc *Service) Shutdown(ctx context.Context) (err error) { + if svc == nil { + return nil + } + + var errs []error + for _, srv := range svc.servers { + serr := srv.Shutdown(ctx) + if serr != nil { + errs = append(errs, fmt.Errorf("shutting down srv %s: %w", srv.Addr, serr)) + } + } + + if len(errs) > 0 { + return errors.List("shutting down") + } + + return nil +} diff --git a/internal/v1/websvc/websvc_test.go b/internal/v1/websvc/websvc_test.go new file mode 100644 index 00000000..01b892cd --- /dev/null +++ b/internal/v1/websvc/websvc_test.go @@ -0,0 +1,69 @@ +package websvc_test + +import ( + "context" + "io" + "net" + "net/http" + "net/url" + "testing" + "time" + + "github.com/AdguardTeam/AdGuardHome/internal/v1/websvc" + "github.com/AdguardTeam/golibs/netutil" + "github.com/AdguardTeam/golibs/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const testTimeout = 1 * time.Second + +func TestService_Start_getHealthCheck(t *testing.T) { + c := &websvc.Config{ + TLS: nil, + Addresses: []*netutil.IPPort{{ + IP: net.IP{127, 0, 0, 1}, + Port: 0, + }}, + SecureAddresses: nil, + Timeout: testTimeout, + } + + svc := websvc.New(c) + + err := svc.Start() + require.NoError(t, err) + t.Cleanup(func() { + ctx, cancel := context.WithTimeout(context.Background(), testTimeout) + t.Cleanup(cancel) + + err = svc.Shutdown(ctx) + require.NoError(t, err) + }) + + addrs := svc.Addrs() + require.Len(t, addrs, 1) + + u := &url.URL{ + Scheme: "http", + Host: addrs[0], + Path: "/health-check", + } + req, err := http.NewRequest(http.MethodGet, u.String(), nil) + require.NoError(t, err) + + httpCli := &http.Client{ + Timeout: testTimeout, + } + resp, err := httpCli.Do(req) + require.NoError(t, err) + + testutil.CleanupAndRequireSuccess(t, resp.Body.Close) + + assert.Equal(t, http.StatusOK, resp.StatusCode) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + assert.Equal(t, []byte("OK"), body) +} diff --git a/main.go b/main.go index 505eb3e5..03ad2f03 100644 --- a/main.go +++ b/main.go @@ -1,3 +1,6 @@ +//go:build !v1 +// +build !v1 + package main import ( diff --git a/main_v1.go b/main_v1.go new file mode 100644 index 00000000..6b5f3dea --- /dev/null +++ b/main_v1.go @@ -0,0 +1,21 @@ +//go:build v1 +// +build v1 + +package main + +import ( + "embed" + + "github.com/AdguardTeam/AdGuardHome/internal/v1/cmd" +) + +// Embed the prebuilt client here since we strive to keep .go files inside the +// internal directory and the embed package is unable to embed files located +// outside of the same or underlying directory. + +//go:embed build2 +var clientBuildFS embed.FS + +func main() { + cmd.Main(clientBuildFS) +} diff --git a/openapi/v1.yaml b/openapi/v1.yaml new file mode 100644 index 00000000..30c318bc --- /dev/null +++ b/openapi/v1.yaml @@ -0,0 +1,4913 @@ +'openapi': '3.0.3' +'info': + 'contact': + 'email': 'devteam@adguard.com' + 'name': 'AdGuard Home' + 'url': 'https://github.com/AdguardTeam/AdGuardHome' + 'description': | + **!! WARNING! API IS AT THE DRAFT STAGE! THINGS WILL BREAK! !!** + + AdGuard Home REST API, V1 **DRAFT**. Our administration web interface is + built on top of this REST API. + + This API is currently a **DRAFT** and is not covered by any stability + guarantees. Once this API reaches maturity, the old `/control/` API will + mostly be removed. + + ## Information For API Users + + * Empty arrays are always sent by the backend, unless documented + otherwise. If the backend doesn't, it's a backend error. + + * `PATCH` requests with JSON bodies use RFC 7396 JSON Merge Patch unless + documented otherwise. + + * The property `x-error-class` on plain text error responses suggests, + which class of error should be used if the API user wants to wrap it + into an object. The property `x-error-code` suggest the error code for + the error object. The code usually goes into the `code` property, and + the content, into `msg`. + + * The property `x-skip-web-api` on operations suggests API clients for + web, like our frontend, to skip this operation in their generated code. + + * The header `Server` will be set to `AdGuardHome/<>`. For + example: `AdGuardHome/v0.107.0-a.42+abcd1234`. + + ## Conventions For API Authors + + ### Naming + + * `CapitalCamelCase` for entities. + + * Initialisms are spelled like `DhcpSettings` and not `DHCPSettings`. + + * `lower_snake_case` for path and query parameters. + + * No unit suffices. + + * Path parameters's names start with `Path`; query, with `Query`. + + * Requests end with `Req`; responses, with `Resp`. + + ### Structure + + * Add `400` and `422` responses to requests that accept data. + + * Add `401` responses, unless the method can work without authorization. + + * Add `500` responses. + + * Descriptions are always on their own lines. + + * Don't add a description if there is already one a level above. + + * Five levels of indentation max, except for descriptions and array + items. + + * Keep things in alphabetical order. + + * Mark required things as such. Document possibly-absent fields **both** + in `required` **and** in `description`, if there is one. + + * Prefer flat objects. Example: `resp.top_user`, not `resp.top.user.val`. + + * Prefer to make it easier for the frontend where possible. + + * Provide examples for requests and responses. If examples are provided + elsewhere, document that. + + * Summaries and descriptions with dots. + + * Top-level value in a JSON request or response must be an object. + + ### Types + + * Add `'maximum': 65535` for 16-bit unsigned integers (for example, port + numbers). + + * Add `'minimum': 0` for unsigned integers. + + * Duration in milliseconds. Time in milliseconds in the Unix epoch. Both + of type `double`, because that is easier for the JS frontend. + + * Integers are always `int64`, numbers are always `double. + + 'license': + 'name': 'GNU General Public License v3.0' + 'url': 'https://www.gnu.org/licenses/gpl-3.0.txt' + 'title': 'AdGuard Home V1 DRAFT API' + 'version': '0.108' + +'servers': +- 'description': > + The V1 HTTP API namespace. + 'url': '/api/v1' + +'security': +- 'basicAuth': [] + +'tags': +- 'description': > + Authorization and account management. + 'name': 'accounts' +- 'description': > + Configuration and settings for Apple products. + 'name': 'apple' +- 'description': > + Runtime and persistent client information. + 'name': 'clients' +- 'description': > + DHCP server methods. + 'name': 'dhcp' +- 'description': > + First-time install configuration handlers. Will not be available once the + installation is done. + 'name': 'install' +- 'description': > + Query logs. + 'name': 'log' +- 'description': > + Filter lists, blocked services, and custom filtering rules. + 'name': 'protection' +- 'description': > + Settings management. + 'name': 'settings' +- 'description': > + Query, filtering, system, and other statistics. + 'name': 'stats' +- 'description': > + Information about the AdGuard Home server and the host system. + 'name': 'system' + +'paths': + '/health-check': + 'get': + 'operationId': 'HealthCheck' + 'servers': + - 'url': '/' + 'summary': 'Check if the server is up.' + 'tags': + - 'system' + + '/accounts/profile': + 'get': + 'operationId': 'GetV1AccountsProfile' + 'responses': + '200': + '$ref': '#/components/responses/GetV1AccountsProfileResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get the profile of the current user.' + 'tags': + - 'accounts' + 'patch': + 'operationId': 'PatchV1AccountsProfile' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1AccountsProfileReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1AccountsProfileResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update the profile of the current user.' + 'tags': + - 'accounts' + + '/accounts/session': + 'delete': + 'operationId': 'DeleteV1AccountsSession' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Log out of the system.' + 'tags': + - 'accounts' + 'post': + 'operationId': 'PostV1AccountsSession' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1AccountsSessionReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Log into the system.' + 'tags': + - 'accounts' + + '/apple/doh.mobileconfig': + 'get': + 'operationId': 'GetV1AppleDohMobileconfig' + 'parameters': + - '$ref': '#/components/parameters/QueryClientId' + - '$ref': '#/components/parameters/QueryHost' + 'responses': + '200': + '$ref': '#/components/responses/GetV1AppleDohMobileconfigResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get a DNS-over-HTTPS .mobileconfig.' + 'tags': + - 'apple' + 'x-skip-web-api': true + + '/apple/dot.mobileconfig': + 'get': + 'operationId': 'GetV1AppleDotMobileconfig' + 'parameters': + - '$ref': '#/components/parameters/QueryHost' + - '$ref': '#/components/parameters/QueryClientId' + 'responses': + '200': + '$ref': '#/components/responses/GetV1AppleDotMobileconfigResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get a DNS-over-HTTPS .mobileconfig.' + 'tags': + - 'apple' + 'x-skip-web-api': true + + '/clients/persistent': + 'get': + 'operationId': 'GetV1ClientsPersistent' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ClientsPersistentResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all persistent clients.' + 'tags': + - 'clients' + 'post': + 'operationId': 'PostV1ClientsPersistent' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ClientsPersistentReq' + 'responses': + '201': + '$ref': '#/components/responses/PostV1ClientsPersistentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Create a new persistent client.' + 'tags': + - 'clients' + + '/clients/persistent/{client_uid}': + 'delete': + 'operationId': 'DeleteV1ClientPersistent' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Delete a persistent client.' + 'tags': + - 'clients' + 'parameters': + - '$ref': '#/components/parameters/PathClientUid' + 'patch': + 'operationId': 'PatchV1ClientPersistent' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1ClientPersistentReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1ClientPersistentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update a persistent client.' + 'tags': + - 'clients' + + '/clients/runtime': + 'get': + 'operationId': 'GetV1ClientsRuntime' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ClientsRuntimeResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all runtime clients.' + 'tags': + - 'clients' + + '/dhcp/leases': + 'get': + 'operationId': 'GetV1DhcpLeases' + 'responses': + '200': + '$ref': '#/components/responses/GetV1DhcpLeasesResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all dynamic and static DHCP leases.' + 'tags': + - 'dhcp' + 'post': + 'operationId': 'PostV1DhcpLeases' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1DhcpLeasesReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1DhcpLeasesResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Create a new static DHCP lease.' + 'tags': + - 'dhcp' + + '/dhcp/leases/{lease_uid}': + 'delete': + 'operationId': 'DeleteV1DhcpLease' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Delete a static DHCP lease.' + 'tags': + - 'dhcp' + 'parameters': + - '$ref': '#/components/parameters/PathLeaseUid' + 'patch': + 'operationId': 'PatchV1DhcpLease' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1DhcpLeaseReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1DhcpLeaseResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update a static DHCP lease.' + 'tags': + - 'dhcp' + + '/dhcp/status': + 'get': + 'operationId': 'GetV1DhcpStatus' + 'responses': + '200': + '$ref': '#/components/responses/GetV1DhcpStatusResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get DHCP server status.' + 'tags': + - 'dhcp' + + '/install/check': + 'post': + 'operationId': 'PostV1InstallCheck' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1InstallCheckReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1InstallCheckResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Check initial configuration.' + 'tags': + - 'install' + + '/install/configure': + 'post': + 'operationId': 'PostV1InstallConfigure' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1InstallConfigureReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Apply initial configuration.' + 'tags': + - 'install' + + '/install/info': + 'get': + 'operationId': 'GetV1InstallInfo' + 'responses': + '200': + '$ref': '#/components/responses/GetV1InstallInfoResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get initial configuration information.' + 'tags': + - 'install' + + '/log/clear': + 'post': + 'operationId': 'PostV1LogClear' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1LogClearReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Clear the whole query log.' + 'tags': + - 'log' + + '/log/search': + 'get': + 'operationId': 'GetV1LogSearch' + 'parameters': + - '$ref': '#/components/parameters/QueryBefore' + - '$ref': '#/components/parameters/QueryLimit' + - '$ref': '#/components/parameters/QueryReason' + - '$ref': '#/components/parameters/QueryTerm' + 'responses': + '200': + '$ref': '#/components/responses/GetV1LogSearchResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Search query logs.' + 'tags': + - 'log' + + '/protection/blocked_services': + 'get': + 'operationId': 'GetV1ProtectionBlockedServices' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ProtectionBlockedServicesResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get blocked services.' + 'tags': + - 'protection' + 'put': + 'operationId': 'PutV1ProtectionBlockedServices' + 'requestBody': + '$ref': '#/components/requestBodies/PutV1ProtectionBlockedServicesReq' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ProtectionBlockedServicesResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Replace blocked services.' + 'tags': + - 'protection' + + '/protection/check_custom_rules': + 'post': + 'operationId': 'PostV1ProtectionCheckCustomRules' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ProtectionCheckCustomRulesReq' + 'responses': + '201': + '$ref': '#/components/responses/PostV1ProtectionCheckCustomRulesResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Check custom filtering rules.' + 'tags': + - 'protection' + + '/protection/custom_rules': + 'get': + 'operationId': 'GetV1ProtectionCustomRules' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ProtectionCustomRulesResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get custom rules.' + 'tags': + - 'protection' + 'put': + 'operationId': 'PutV1ProtectionCustomRules' + 'requestBody': + '$ref': '#/components/requestBodies/PutV1ProtectionCustomRulesReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Replace custom rules.' + 'tags': + - 'protection' + + '/protection/dns_rewrites': + 'get': + 'operationId': 'GetV1ProtectionDnsRewrites' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ProtectionDnsRewritesResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all classic DNS rewrites.' + 'tags': + - 'protection' + 'post': + 'operationId': 'PostV1ProtectionDnsRewrites' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ProtectionDnsRewritesReq' + 'responses': + '201': + '$ref': '#/components/responses/PostV1ProtectionDnsRewritesResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Add a new classic DNS rewrite.' + 'tags': + - 'protection' + + '/protection/dns_rewrites/{dns_rewrite_uid}': + 'delete': + 'operationId': 'DeleteV1ProtectionDnsRewrite' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Delete a classic DNS rewrite.' + 'tags': + - 'protection' + 'parameters': + - '$ref': '#/components/parameters/PathDnsRewriteUid' + + '/protection/filters': + 'get': + 'operationId': 'GetV1ProtectionFilters' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ProtectionFiltersResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all filters.' + 'tags': + - 'protection' + 'post': + 'operationId': 'PostV1ProtectionFilters' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ProtectionFiltersReq' + 'responses': + '201': + '$ref': '#/components/responses/PostV1ProtectionFiltersResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Add a new filter.' + 'tags': + - 'protection' + + '/protection/filters/{filter_uid}': + 'delete': + 'operationId': 'DeleteV1ProtectionFilter' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Delete a filter.' + 'tags': + - 'protection' + 'parameters': + - '$ref': '#/components/parameters/PathFilterUid' + 'patch': + 'operationId': 'PatchV1ProtectionFilter' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1ProtectionFilterReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1ProtectionFilterResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': > + Update a filter's settings. + 'tags': + - 'protection' + + '/protection/refresh_filters': + 'post': + 'operationId': 'PostV1ProtectionRefreshFilters' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ProtectionRefreshFiltersReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1ProtectionRefreshFiltersResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': > + Refresh all filters. + 'tags': + - 'protection' + + '/protection/refresh_filters/{filter_uid}': + 'parameters': + - '$ref': '#/components/parameters/PathFilterUid' + 'post': + 'operationId': 'PostV1ProtectionRefreshFilter' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ProtectionRefreshFilterReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1ProtectionRefreshFilterResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': > + Refresh a filter. + 'tags': + - 'protection' + + '/settings/all': + 'get': + 'operationId': 'GetV1SettingsAll' + 'responses': + '200': + '$ref': '#/components/responses/GetV1SettingsAllResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all settings.' + 'tags': + - 'settings' + + '/settings/dhcp': + 'patch': + 'operationId': 'PatchV1SettingsDhcp' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsDhcpReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsDhcpResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update DHCP server settings.' + 'tags': + - 'settings' + + '/settings/dns': + 'patch': + 'operationId': 'PatchV1SettingsDns' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsDnsReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsDnsResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update DNS server settings.' + 'tags': + - 'settings' + + '/settings/dns/access': + 'get': + 'description': > + Get DNS access settings. This is a separate API, because these lists + can become quite big. + 'operationId': 'GetV1SettingsDnsAccess' + 'responses': + '200': + '$ref': '#/components/responses/GetV1SettingsDnsAccessResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get DNS access settings.' + 'tags': + - 'settings' + 'put': + 'description': > + Update DNS access settings. This is a separate API, because these lists + can become quite big. + 'operationId': 'PutV1SettingsDnsAccess' + 'requestBody': + '$ref': '#/components/requestBodies/PutV1SettingsDnsAccessReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update DNS access settings.' + 'tags': + - 'settings' + + '/settings/dns/check': + 'post': + 'operationId': 'PostV1SettingsDnsCheck' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1SettingsDnsCheckReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1SettingsDnsCheckResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Check DNS upstream settings.' + 'tags': + - 'settings' + + '/settings/log': + 'patch': + 'operationId': 'PatchV1SettingsLog' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsLogReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsLogResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update query logging settings.' + 'tags': + - 'settings' + + '/settings/protection': + 'patch': + 'operationId': 'PatchV1SettingsProtection' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsProtectionReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsProtectionResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update protection settings.' + 'tags': + - 'settings' + + '/settings/stats': + 'patch': + 'operationId': 'PatchV1SettingsStats' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsStatsReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsStatsResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update statistics settings.' + 'tags': + - 'settings' + + '/settings/tls': + 'patch': + 'operationId': 'PatchV1SettingsTls' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsTlsReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsTlsResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update TLS and encryption settings.' + 'tags': + - 'settings' + + '/settings/tls/check': + 'post': + 'operationId': 'PostV1SettingsTlsCheck' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1SettingsTlsCheckReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1SettingsTlsCheckResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Check TLS and encryption settings.' + 'tags': + - 'settings' + + '/stats/all': + 'get': + 'operationId': 'GetV1StatsAll' + 'responses': + '200': + '$ref': '#/components/responses/GetV1StatsAllResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all statistics.' + 'tags': + - 'stats' + + '/stats/clear': + 'post': + 'operationId': 'PostV1StatsClear' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1StatsClearReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Clear all statistics.' + 'tags': + - 'stats' + + '/system/info': + 'get': + 'operationId': 'GetV1SystemInfo' + 'responses': + '200': + '$ref': '#/components/responses/GetV1SystemInfoResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get server information.' + 'tags': + - 'system' + + '/system/reset': + 'post': + 'operationId': 'PostV1SystemReset' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1SystemResetReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1SystemResetResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Reset all settings to defaults.' + 'tags': + - 'system' + + '/system/update': + 'post': + 'operationId': 'PostV1SystemUpdate' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1SystemUpdateReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1SystemUpdateResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update AdGuard Home.' + 'tags': + - 'system' + +'components': + 'parameters': + 'PathDnsRewriteUid': + 'description': > + DNS rewrite ID. + 'example': 'abcd1234' + 'in': 'path' + 'name': 'dns_rewrite_uid' + 'required': true + 'schema': + '$ref': '#/components/schemas/Uid' + + 'PathClientUid': + 'description': > + The unique ID of a client. + 'example': 'abcd1234' + 'in': 'path' + 'name': 'client_uid' + 'required': true + 'schema': + '$ref': '#/components/schemas/Uid' + + 'PathFilterUid': + 'description': > + The ID of a filter. + 'example': 'abcd1234' + 'in': 'path' + 'name': 'filter_uid' + 'required': true + 'schema': + '$ref': '#/components/schemas/Uid' + + 'PathLeaseUid': + 'description': > + The ID of a static lease. + 'example': 'abcd1234' + 'in': 'path' + 'name': 'lease_uid' + 'required': true + 'schema': + '$ref': '#/components/schemas/Uid' + + 'QueryBefore': + 'description': > + Unix time, before which to show the search results, in milliseconds. + 'example': 1614345496000 + 'in': 'query' + 'name': 'before' + 'required': false + 'schema': + 'format': 'double' + 'type': 'number' + + 'QueryClientId': + 'description': > + ClientID, **not** its UID. + 'example': 'client-1' + 'in': 'query' + 'name': 'client_id' + 'required': false + 'schema': + '$ref': '#/components/schemas/ClientId' + + 'QueryHost': + 'description': > + The host for which the Configuration is generated. + 'example': 'example.org' + 'in': 'query' + 'name': 'host' + 'required': true + 'schema': + 'type': 'string' + + 'QueryLimit': + 'description': > + Maximum amount of records to return. + 'example': 100 + 'in': 'query' + 'name': 'limit' + 'required': false + 'schema': + 'format': 'int64' + 'type': 'integer' + + 'QueryReason': + 'description': > + Filter query log results by filtering reason. + 'example': 'not_filtered_notfound' + 'in': 'query' + 'name': 'reason' + 'required': false + 'schema': + '$ref': '#/components/schemas/FilteringReason' + + 'QueryTerm': + 'description': > + Search term. + 'example': '127.0.0.1' + 'in': 'query' + 'name': 'term' + 'required': false + 'schema': + 'type': 'string' + + 'requestBodies': + 'PatchV1AccountsProfileReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1AccountsProfileReq' + 'required': true + + 'PatchV1ClientPersistentReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1ClientPersistentReq' + 'required': true + + 'PatchV1DhcpLeaseReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1DhcpLeaseReq' + 'required': true + + 'PatchV1ProtectionFilterReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1ProtectionFilterReq' + 'required': true + + 'PatchV1SettingsDhcpReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsDhcpReq' + 'required': true + + 'PatchV1SettingsDnsReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsDnsReq' + 'required': true + + 'PatchV1SettingsLogReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsLogReq' + 'required': true + + 'PatchV1SettingsProtectionReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsProtectionReq' + 'required': true + + 'PatchV1SettingsStatsReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsStatsReq' + 'required': true + + 'PatchV1SettingsTlsReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsTlsReq' + 'required': true + + 'PostV1AccountsSessionReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1AccountsSessionReq' + 'required': true + + 'PostV1ClientsPersistentReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ClientsPersistentReq' + 'required': true + + 'PostV1DhcpLeasesReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1DhcpLeasesReq' + 'required': true + + 'PostV1InstallCheckReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1InstallCheckReq' + 'required': true + + 'PostV1InstallConfigureReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1InstallConfigureReq' + 'required': true + + 'PostV1LogClearReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1LogClearReq' + 'required': true + + 'PostV1ProtectionCheckCustomRulesReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionCheckCustomRulesReq' + 'required': true + + 'PostV1ProtectionDnsRewritesReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionDnsRewritesReq' + 'required': true + + 'PostV1ProtectionFiltersReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionFiltersReq' + 'required': true + + 'PostV1ProtectionRefreshFilterReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionRefreshFilterReq' + 'required': true + + 'PostV1ProtectionRefreshFiltersReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionRefreshFiltersReq' + 'required': true + + 'PostV1SettingsDnsCheckReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SettingsDnsCheckReq' + 'required': true + + 'PostV1SettingsTlsCheckReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SettingsTlsCheckReq' + 'required': true + + 'PostV1StatsClearReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1StatsClearReq' + 'required': true + + 'PostV1SystemResetReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SystemResetReq' + 'required': true + + 'PostV1SystemUpdateReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SystemUpdateReq' + 'required': true + + 'PutV1ProtectionBlockedServicesReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PutV1ProtectionBlockedServicesReq' + 'required': true + + 'PutV1ProtectionCustomRulesReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PutV1ProtectionCustomRulesReq' + 'required': true + + 'PutV1SettingsDnsAccessReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PutV1SettingsDnsAccessReq' + 'required': true + + 'responses': + 'BadRequestResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/BadRequestResp' + 'text/plain': + 'example': >- + invalid character '{' looking for beginning of object key string + 'x-error-class': '#/components/schemas/BadRequestResp' + 'x-error-code': 'TXT400' + 'description': > + Generic bad request response. Sent when the request data is malformed + (for example, invalid JSON). + + 'GetV1AccountsProfileResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1AccountsProfileResp' + 'description': > + A successful response to a `GET /api/v1/accounts/profile` request. + + 'GetV1AppleDohMobileconfigResp': + 'content': + 'application/xml': + 'schema': + '$ref': '#/components/schemas/GetV1AppleDohMobileconfigResp' + 'description': > + A successful response to a `GET /api/v1/apple/doh.mobileconfig` request. + + 'GetV1AppleDotMobileconfigResp': + 'content': + 'application/xml': + 'schema': + '$ref': '#/components/schemas/GetV1AppleDotMobileconfigResp' + 'description': > + A successful response to a `GET /api/v1/apple/dot.mobileconfig` request. + + 'GetV1ClientsPersistentResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ClientsPersistentResp' + 'description': > + A successful response to a `GET /api/v1/clients/persistent` request. + + 'GetV1ClientsRuntimeResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ClientsRuntimeResp' + 'description': > + A successful response to a `GET /api/v1/clients/runtime` request. + + 'GetV1DhcpLeasesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1DhcpLeasesResp' + 'description': > + A successful response to a `GET /api/v1/dhcp/leases` request. + + 'GetV1DhcpStatusResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1DhcpStatusResp' + 'description': > + A successful response to a `GET /api/v1/dhcp/status` request. + + 'GetV1InstallInfoResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1InstallInfoResp' + 'description': > + A successful response to a `GET /api/v1/install/info` request. + + 'GetV1LogSearchResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1LogSearchResp' + 'description': > + A successful response to a `GET /api/v1/log/search` request. + + 'GetV1ProtectionBlockedServicesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ProtectionBlockedServicesResp' + 'description': > + A successful response to a `GET /api/v1/protection/blocked_services` + or a `PUT /api/v1/protection/blocked_services` request. + + 'GetV1ProtectionCustomRulesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ProtectionCustomRulesResp' + 'description': > + A successful response to a `GET /api/v1/protection/custom_rules` + request. + + 'GetV1ProtectionDnsRewritesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ProtectionDnsRewritesResp' + 'description': > + A successful response to a `GET /api/v1/protection/dns_rewrites` + request. + + 'GetV1ProtectionFiltersResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ProtectionFiltersResp' + 'description': > + A successful response to a `GET /api/v1/protection/filters` request. + + 'GetV1SettingsAllResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1SettingsAllResp' + 'description': > + A successful response to a `GET /api/v1/settings/all` request. + + 'GetV1SettingsDnsAccessResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1SettingsDnsAccessResp' + 'description': > + A successful response to a `GET /api/v1/settings/dns/access` request. + + 'GetV1StatsAllResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1StatsAllResp' + 'description': > + A successful response to a `GET /api/v1/stats/all` request. + + 'GetV1SystemInfoResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1SystemInfoResp' + 'description': > + A successful response to a `GET /api/v1/server/info` request. + + 'InternalServerErrorResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/InternalServerErrorResp' + 'text/plain': + 'example': >- + runtime error: invalid memory address or nil pointer dereference + 'x-error-class': '#/components/schemas/InternalServerErrorResp' + 'x-error-code': 'TXT500' + 'description': > + Generic internal server error. + + 'NoContentResp': + 'description': > + Generic no-error no-content response. + + 'NotFoundResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/NotFoundResp' + 'text/plain': + 'example': >- + Not found. + 'x-error-class': '#/components/schemas/NotFoundResp' + 'x-error-code': 'TXT404' + 'description': > + Generic not found response. + + 'PatchV1AccountsProfileResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1AccountsProfileResp' + 'description': > + A successful response to a `PATCH /api/v1/accounts/profile` request. + + 'PatchV1ClientPersistentResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1ClientPersistentResp' + 'description': > + A successful response to + a `PATCH /api/v1/clients/persistent/{client_uid}` request. + + 'PatchV1DhcpLeaseResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1DhcpLeaseResp' + 'description': > + A successful response to a `PATCH /api/v1/dhcp/leases/{lease_uid}` + request. + + 'PatchV1ProtectionFilterResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1ProtectionFilterResp' + 'description': > + A successful response to a `PATCH /api/v1/filters/{filter_uid}` request. + + 'PatchV1SettingsDhcpResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsDhcpResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/dhcp` request. + + 'PatchV1SettingsDnsResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsDnsResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/dns` request. + + 'PatchV1SettingsLogResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsLogResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/log` request. + + 'PatchV1SettingsProtectionResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsProtectionResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/protection` request. + + 'PatchV1SettingsStatsResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsStatsResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/stats` request. + + 'PatchV1SettingsTlsResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsTlsResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/tls` request. + + 'PostV1ClientsPersistentResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ClientsPersistentResp' + 'description': > + A successful response to a `POST /api/v1/clients/persistent` request. + + 'PostV1DhcpLeasesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1DhcpLeasesResp' + 'description': > + A successful response to a `POST /api/v1/dhcp/leases` request. + + 'PostV1InstallCheckResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1InstallCheckResp' + 'description': > + A successful response to a `POST /api/v1/install/check` request. + + 'PostV1ProtectionCheckCustomRulesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionCheckCustomRulesResp' + 'description': > + A successful response to a `POST /api/v1/protection/check_custom_rules` + request. + + 'PostV1ProtectionDnsRewritesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionDnsRewritesResp' + 'description': > + A successful response to a `POST /api/v1/protection/dns_rewrites` + request. + + 'PostV1ProtectionFiltersResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionFiltersResp' + 'description': > + A successful response to a `POST /api/v1/protection/filters` request. + + 'PostV1ProtectionRefreshFilterResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionRefreshFilterResp' + 'description': > + A successful response to + a `POST /api/v1/protection/refresh_filters/{filter_uid}` request. + + 'PostV1ProtectionRefreshFiltersResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionRefreshFiltersResp' + 'description': > + A successful response to a `POST /api/v1/protection/refresh_filters` + request. + + 'PostV1SettingsDnsCheckResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SettingsDnsCheckResp' + 'description': > + A successful response to a `POST /api/v1/settings/dns/check` request. + + 'PostV1SettingsTlsCheckResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SettingsTlsCheckResp' + 'description': > + A successful response to a `POST /api/v1/settings/tls/check` request. + + 'PostV1SystemResetResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SystemResetResp' + 'description': > + A successful response to a `POST /api/v1/system/reset` request. + + 'PostV1SystemUpdateResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SystemUpdateResp' + 'description': > + A successful response to a `POST /api/v1/system/update` request. + + 'UnauthorizedResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/UnauthorizedResp' + 'text/plain': + 'example': 'no or bad authorization provided' + 'x-error-class': '#/components/schemas/UnauthorizedResp' + 'x-error-code': 'TXT401' + 'description': > + This API requires authorization. + 'headers': + 'WWW-Authenticate': + 'description': > + The required WWW-Authenticate header. + 'example': 'Basic realm="AdGuard Home", charset="UTF-8"' + 'required': true + 'schema': + 'type': 'string' + + 'UnprocessableEntityResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/UnprocessableEntityResp' + 'description': > + Generic bad request data response. Sent when the request data is + well-formed but is invalid for this request. + + 'schemas': + 'BadRequestResp': + 'example': + 'code': 'JSN000' + 'msg': >- + invalid character '{' looking for beginning of object key string + 'properties': + 'code': + '$ref': '#/components/schemas/ErrorCode' + 'msg': + 'description': > + Error message string. + 'type': 'string' + 'required': + - 'code' + - 'msg' + 'type': 'object' + + 'BlockedServiceId': + 'description': > + ID of a blocked service. + 'enum': + - '9gag' + - 'amazon' + - 'cloudflare' + - 'dailymotion' + - 'discord' + - 'disneyplus' + - 'ebay' + - 'epic_games' + - 'facebook' + - 'hulu' + - 'imgur' + - 'instagram' + - 'mail_ru' + - 'netflix' + - 'ok' + - 'origin' + - 'pinterest' + - 'qq' + - 'reddit' + - 'skype' + - 'snapchat' + - 'spotify' + - 'steam' + - 'telegram' + - 'tiktok' + - 'tinder' + - 'twitch' + - 'twitter' + - 'viber' + - 'vimeo' + - 'vk' + - 'wechat' + - 'weibo' + - 'whatsapp' + - 'youtube' + 'type': 'string' + + 'BlockedServices': + 'description': > + Blocked services. + 'example': + 'services': + - '9gag' + - 'dailymotion' + 'properties': + 'services': + 'description': > + All blocked services. + 'items': + '$ref': '#/components/schemas/BlockedServiceId' + 'type': 'array' + 'required': + - 'services' + 'type': 'object' + + 'Channel': + 'description': > + AdGuard Home release channel. + 'enum': + - 'beta' + - 'development' + - 'edge' + - 'release' + 'type': 'string' + + 'ClientId': + 'pattern': '[0-9a-z-]{1,64}' + 'type': 'string' + + 'ClientInfo': + 'description': > + A shorter information about a client. If the `uid` field is present, + this is a persistent client. Otherwise, this is a runtime client. + 'properties': + 'blocked': + 'description': > + If `true`, client is blocked. + 'type': 'boolean' + 'ids': + 'description': | + Client identifiers. That includes ClientIDs set by users as well as + IP addresses. There must be at least one identifier. + + Not to be confused with the `uid` field. + 'example': + - '1.2.3.4' + - 'user-1' + 'items': + 'type': 'string' + 'minItems': 1 + 'type': 'array' + 'name': + 'description': > + The name of the client, if any. If there are none, this field is + absent. + 'example': 'User 1' + 'type': 'string' + 'num': + 'description': > + Total number of requests for this client. + 'example': 1000 + 'format': 'int64' + 'type': 'integer' + 'num_blocked': + 'description': > + Total number of blocked requests for this client. + 'example': 1000 + 'format': 'int64' + 'type': 'integer' + 'uid': + '$ref': '#/components/schemas/Uid' + 'whois': + '$ref': '#/components/schemas/Whois' + 'required': + - 'blocked' + - 'ids' + - 'num' + - 'num_blocked' + 'type': 'object' + + 'CustomRules': + 'description': > + Custom filtering rules. + 'example': + 'rules': + - '||example.com' + - '# Some comment' + 'properties': + 'rules': + 'description': > + All custom filtering rules + 'items': + 'type': 'string' + 'type': 'array' + 'required': + - 'rules' + 'type': 'object' + + 'DhcpLease': + 'allOf': + - '$ref': '#/components/schemas/DhcpLeasePost' + - 'description': > + A dynamic or static DHCP lease. If the `uid` field is present, this is + a static lease. Otherwise, this is a dynamic lease. + 'example': + 'expires': 1614345496000 + 'hostname': 'my-mobile' + 'ip': '192.168.1.2' + 'mac': '01:23:45:67:89:ab' + 'uid': 'abcd1234' + 'properties': + 'uid': + '$ref': '#/components/schemas/Uid' + + 'DhcpLeasePatch': + 'description': > + A static DHCP lease update object. + 'example': + 'expires': 1614345496000 + 'properties': + 'expires': + 'description': > + The Unix time of the lease's expiry time, in milliseconds. + 'format': 'double' + 'type': 'number' + 'hostname': + 'description': > + Client's hostname. + 'type': 'string' + 'ip': + 'description': > + IP address leased to the client. + 'type': 'string' + 'mac': + 'description': > + Hardware address of the lease client. + 'type': 'string' + 'type': 'object' + + 'DhcpLeasePost': + 'allOf': + - '$ref': '#/components/schemas/DhcpLeasePatch' + - 'description': > + A static DHCP lease create object. + 'example': + 'expires': 1614345496000 + 'hostname': 'my-mobile' + 'ip': '192.168.1.2' + 'mac': '01:23:45:67:89:ab' + 'required': + - 'expires' + - 'hostname' + - 'ip' + - 'mac' + + 'DhcpSettings': + 'allOf': + - '$ref': '#/components/schemas/DhcpSettingsPatch' + - 'description': > + DHCP server settings. + 'example': + 'enabled': true + 'interface_name': 'wlan0' + 'ipv4_gateway_ip': '192.168.1.1' + 'ipv4_lease_duration': 86400000 + 'ipv4_range_end': '192.168.1.101' + 'ipv4_range_start': '192.168.1.2' + 'ipv4_subnet_mask': '255.255.255.0' + 'ipv6_range_start': '2001:db8::1' + 'ipv6_lease_duration': 86400000 + 'required': + - 'enabled' + + 'DhcpSettingsPatch': + 'description': > + DHCP server settings update object. + 'example': + 'enabled': true + 'interface_name': 'wlan0' + 'ipv4_gateway_ip': '192.168.1.1' + 'ipv4_lease_duration': 86400000 + 'ipv4_range_end': '192.168.1.101' + 'ipv4_range_start': '192.168.1.2' + 'ipv4_subnet_mask': '255.255.255.0' + 'properties': + 'enabled': + 'description': > + If `true`, the DHCP server is enabled. + 'type': 'boolean' + 'interface_name': + 'description': > + The name of network interface to serve on. + 'type': 'string' + 'ipv4_gateway_ip': + 'description': > + The IP address of the gateway. + 'type': 'string' + 'ipv4_lease_duration': + 'description': > + The duration of the IPv4 lease, in milliseconds. + 'type': 'number' + 'ipv4_range_end': + 'description': > + The end of the IPv4 addresses to serve to clients. + 'type': 'string' + 'ipv4_range_start': + 'description': > + The start of the IPv4 addresses to serve to clients. + 'type': 'string' + 'ipv4_subnet_mask': + 'description': > + The IP subnet mask. + 'type': 'string' + 'ipv6_lease_duration': + 'description': > + The duration of the IPv6 lease, in milliseconds. + 'type': 'number' + 'ipv6_range_start': + 'description': > + The start of the IPv6 addresses to serve to clients. + 'type': 'string' + 'type': 'object' + + 'DnsAccessSettings': + 'description': > + DNS server access settings. + 'example': + 'allowed_clients': [] + 'blocked_clients': + - '1.2.3.4' + - '5.6.7.8/16' + 'blocked_domain_rules': + - 'id.server' + - '*.example.org' + - '||example.com^' + 'properties': + 'allowed_clients': + 'description': > + CIDR or IP addresses of clients in the allowlist. If non-empty, + AdGuard Home will accept requests from these IP addresses only. + 'items': + 'type': 'string' + 'type': 'array' + 'blocked_clients': + 'description': > + CIDR or IP addresses of clients in the blocklist. If non-empty, + AdGuard Home will drop requests from these IP addresses. + 'items': + 'type': 'string' + 'type': 'array' + 'blocked_domain_rules': + 'description': > + AdGuard Home will drop DNS queries, if the domains in their queries + match these rules. Here you can specify the exact domain + names, wildcards, and `urlfilter` rules. Examples: + + * `example.org` + + * `*.example.org` + + * `||example.org^` + 'items': + 'type': 'string' + 'type': 'array' + 'required': + - 'allowed_clients' + - 'blocked_clients' + - 'blocked_domain_rules' + 'type': 'object' + + 'DnsBlockingMode': + 'description': | + DNS blocking mode. + + * `custom_ip`: Respond with a custom IP address. If this mode is + selected, both `blocking_ipv4` and `blocking_ipv6` parameters must + be set. + + * `default`: Same as `null_ip` for Adblock-style rules, but respond + with the IP address specified in the rule when blocked by an + `/etc/hosts`-style rule. + + * `null_ip`: Respond with a zero IP address: `0.0.0.0` for `A` + requests and `::` for `AAAA` ones. + + * `nxdomain`: Respond with the `NXDOMAIN` code. + + * `refused`: Respond with the `REFUSET` code. + + 'enum': + - 'custom_ip' + - 'default' + - 'null_ip' + - 'nxdomain' + - 'refused' + 'type': 'string' + + 'DnsClass': + 'description': > + DNS resource record class, aka `CLASS`. + 'enum': + - 'any' + - 'ch' + - 'cs' + - 'hs' + - 'in' + 'type': 'string' + + 'DnsProto': + 'description': > + DNS protocol. + 'enum': + - 'dot' + - 'doh' + - 'doq' + - 'dnscrypt' + - 'udp' + 'type': 'string' + + 'DnsResponseCode': + 'description': > + DNS response code, aka `RCODE`. + 'enum': + - 'badalg' + - 'badcookie' + - 'badkey' + - 'badmode' + - 'badname' + - 'badsig' + - 'badtime' + - 'badtrunc' + - 'badvers' + - 'formerr' + - 'noerror' + - 'notauth' + - 'notimp' + - 'notzone' + - 'nxdomain' + - 'nxrrset' + - 'refused' + - 'servfail' + - 'yxdomain' + - 'yxrrset' + 'type': 'string' + + 'DnsRewrite': + 'allOf': + - '$ref': '#/components/schemas/DnsRewritePost' + - 'description': > + A classic DNS rewrite. + 'example': + 'answer': 'A' + 'domain': 'example.com' + 'id': 'abcd1234' + 'properties': + 'id': + '$ref': '#/components/schemas/Uid' + 'required': + - 'answer' + - 'domain' + - 'id' + 'type': 'object' + + 'DnsRewritePost': + 'description': > + A classic DNS rewrite create object. + 'example': + 'answer': 'A' + 'domain': 'example.com' + 'properties': + 'answer': + 'description': > + The value of an `A`, `AAAA`, or `CNAME` DNS record in the response. + Acceptable formats: + + * Domain name: add a `CNAME` record with this domain name. + + * IPv4 address: use this IP in an `A` response. + + * IPv6 address: use this IP in an `AAAA` response. + + * The literal `A`: keep only `A` records from the upstream + response. + + * The literal `AAAA`: keep only `AAAA` records from the upstream + response. + 'type': 'string' + 'domain': + 'description': > + Domain name or wildcard. + 'type': 'string' + 'required': + - 'answer' + - 'domain' + 'type': 'object' + + 'DnsSettings': + 'allOf': + - '$ref': '#/components/schemas/DnsSettingsPatch' + - 'description': > + DNS server settings. + 'example': + 'blocking_mode': 'default' + 'bootstrap_servers': + - '9.9.9.10' + - '149.112.112.10' + 'cache_size': 4194304 + 'cache_ttl_max': 0 + 'cache_ttl_min': 0 + 'dnssec': false + 'edns_client_subnet': false + 'ipv6': true + 'rate_limit': 20 + 'upstream_mode': 'load_balancing' + 'upstream_servers': + - '1.1.1.1' + - '8.8.8.8' + 'required': + - 'blocking_mode' + - 'bootstrap_servers' + - 'cache_size' + - 'cache_ttl_max' + - 'cache_ttl_min' + - 'dnssec' + - 'edns_client_subnet' + - 'ipv6' + - 'rate_limit' + - 'upstream_mode' + - 'upstream_servers' + + 'DnsSettingsPatch': + 'description': > + DNS server settings update object. + 'example': + 'cache_size': 4194304 + 'upstream_servers': + - '1.1.1.1' + 'properties': + 'blocking_ipv4': + 'description': > + IPv4 address to respond with when `blocking_mode` is `custom_ip`. + See the documentation for the `DnsBlockingMode` schema. If + `blocking_mode` is different from `custom_ip`, this property is not + included. + 'type': 'string' + 'blocking_ipv6': + 'description': > + IPv6 address to respond with when `blocking_mode` is `custom_ip`. + See the documentation for the `DnsBlockingMode` schema. If + `blocking_mode` is different from `custom_ip`, this property is not + included. + 'type': 'string' + 'blocking_mode': + '$ref': '#/components/schemas/DnsBlockingMode' + 'bootstrap_servers': + 'description': | + Bootstrap DNS servers' IP addresses to resolve the hostnames of the + encrypted DNS server providers. + 'items': + 'type': 'string' + 'type': 'array' + 'cache_size': + 'description': > + DNS cache size in bytes. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'cache_ttl_max': + 'description': > + Set a maximum time-to-live value for entries in the DNS cache. `0` + means no override. The value is in **seconds**, like in DNS record + headers. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'cache_ttl_min': + 'description': > + Extend short time-to-live values received from the upstream server + when caching DNS responses. `0` means no override. TThe value is + in **seconds**, like in DNS record headers. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'dnssec': + 'description': > + If `true`, set DNSSEC flag in outcoming DNS queries and check the + result. A DNSSEC-enabled resolver is required. + 'type': 'boolean' + 'edns_client_subnet': + 'description': > + If `true`, enable EDNS Client Subnet support and send clients' + subnets to DNS servers. + 'type': 'boolean' + 'ipv6': + 'description': > + If `true`, accept `AAAA` DNS queries. If `false`, respond to them + with an empty answer. + 'type': 'boolean' + 'rate_limit': + 'description': > + The number of requests per second that a single client is allowed to + make. `0` means no limit. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'upstream_mode': + '$ref': '#/components/schemas/DnsUpstreamMode' + 'upstream_servers': + 'description': > + Upstream DNS servers. + 'items': + '$ref': '#/components/schemas/UpstreamServerAddr' + 'type': 'array' + 'type': 'object' + + 'DnsType': + 'description': > + DNS resource record type, aka `TYPE`. + 'enum': + - 'a' + - 'aaaa' + - 'afsdb' + - 'any' + - 'apl' + - 'atma' + - 'avc' + - 'axfr' + - 'caa' + - 'cdnskey' + - 'cds' + - 'cert' + - 'cname' + - 'csync' + - 'dhcid' + - 'dlv' + - 'dname' + - 'dnskey' + - 'ds' + - 'eid' + - 'eui48' + - 'eui64' + - 'gid' + - 'gpos' + - 'hinfo' + - 'hip' + - 'https' + - 'isdn' + - 'ixfr' + - 'key' + - 'kx' + - 'l32' + - 'l64' + - 'loc' + - 'lp' + - 'maila' + - 'mailb' + - 'mb' + - 'md' + - 'mf' + - 'mg' + - 'minfo' + - 'mr' + - 'mx' + - 'naptr' + - 'nid' + - 'nimloc' + - 'ninfo' + - 'ns' + - 'nsap-ptr' + - 'nsec' + - 'nsec3' + - 'nsec3param' + - 'null' + - 'nxt' + - 'openpgpkey' + - 'opt' + - 'ptr' + - 'px' + - 'rkey' + - 'rp' + - 'rrsig' + - 'rt' + - 'sig' + - 'smimea' + - 'soa' + - 'spf' + - 'srv' + - 'sshfp' + - 'svcb' + - 'ta' + - 'talink' + - 'tkey' + - 'tlsa' + - 'tsig' + - 'txt' + - 'uid' + - 'uinfo' + - 'unspec' + - 'uri' + - 'x25' + 'type': 'string' + + 'DnsUpstreamMode': + 'description': | + Upstream request mode. + + * `fastest`: Query all DNS servers and return the IP address that was + returned by the fastest response. Slows down DNS responses, since + it waits for responses from all upstreams, but improves the overall + connectivity. + + * `load_balancing`: Query one server at a time using a weighted random + algorithm picking the server so that the fastest server is used + more often. + + * `parallel`: Use parallel requests to speed up resolving by + simultaneously querying all upstream servers. + 'enum': + - 'fastest' + - 'load_balancing' + - 'parallel' + 'type': 'string' + + 'ErrorCode': + 'description': | + An error code. + + * `AUT000`: No or bad authorization credentials provided. + + * `ENT404`: Entity not found; as opposed to path not found. + + * `JSN000`: A JSON syntax error. + + * `JSN001`: A JSON type error. + + * `OSS000`: The server's operating system doesn't support the + requested functionality. + + * `PTH404`: Path not found; as opposed to entity not found. + + * `RNT000`: A server runtime error. + + * `TXT400`: A plaintext bad request error. Used when a plaintext + error is wrapped. + + * `TXT401`: A plaintext unauthorized error. Used when a plaintext + error is wrapped. + + * `TXT404`: A plaintext not found error. Used when a plaintext error + is wrapped. + + * `TXT500`: A plaintext internal server error. Used when a plaintext + error is wrapped. + + TODO(a.garipov): Expand with TLS validation errors, DHCP errors, filter + URL reaching errors, OS and I/O errors, and so on. + 'enum': + - 'AUT000' + - 'ENT404' + - 'JSN000' + - 'JSN001' + - 'OSS000' + - 'PTH404' + - 'RNT000' + - 'TXT400' + - 'TXT401' + - 'TXT404' + - 'TXT500' + 'type': 'string' + + 'Filter': + 'allOf': + - '$ref': '#/components/schemas/FilterPatch' + - 'description': > + A single filter list of rules. + 'example': + 'allowlist': false + 'enabled': true + 'name': 'AdMaster 5000 Super List v2.0 Final' + 'num_rules': 36766 + 'refreshed': 1614345496000 + 'uid': 'abcd1234' + 'url': 'https://admaster.example.com/list.txt' + 'properties': + 'num_rules': + 'description': > + Number of rules in this filter. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'refreshed': + 'description': > + Unix time of last refresh for this filter, in milliseconds. + 'format': 'double' + 'type': 'number' + 'uid': + '$ref': '#/components/schemas/Uid' + 'required': + - 'allowlist' + - 'enabled' + - 'name' + - 'num_rules' + - 'refreshed' + - 'uid' + - 'url' + + 'FilterPatch': + 'description': > + A filter update object. + 'example': + 'enabled': true + 'properties': + 'allowlist': + 'description': > + If `true`, this filter works as an allowlist filters. + 'type': 'boolean' + 'enabled': + 'description': > + If `true`, this filter is applied. + 'type': 'boolean' + 'name': + 'description': > + The name of this filter. + 'type': 'string' + 'url': + 'description': | + A URL of the file containing filtering rules. + + Examples of allowed schemes: + + * `file:///home/user/ads/rules.txt`: A local file. + + * `http://example.com/ads/rules.txt`: Remote list, fetched over + plain HTTP. + + * `https://example.com/ads/rules.txt`: Remote list, fetched over + HTTPS. + 'type': 'string' + 'type': 'object' + + 'FilterPost': + 'allOf': + - '$ref': '#/components/schemas/FilterPatch' + - 'description': > + A filter create object. + 'example': + 'allowlist': false + 'enabled': true + 'name': 'AdMaster 5000 Super List v2.0 Final' + 'url': 'https://admaster.example.com/list.txt' + 'required': + - 'allowlist' + - 'enabled' + - 'name' + - 'url' + + 'FilteringReason': + 'description': > + Request filtering status. + 'enum': + - 'filtered_blocked_service' + - 'filtered_blocklist' + - 'filtered_invalid' + - 'filtered_parental' + - 'filtered_safe_browsing' + - 'filtered_safe_search' + - 'not_filtered_allowlist' + - 'not_filtered_error' + - 'not_filtered_notfound' + - 'rewrite' + - 'rewrite_etc_hosts' + - 'rewrite_rule' + 'type': 'string' + + 'FilteringResultRule': + 'description': > + Applied filtering rule. + 'properties': + 'filter_list_uid': + '$ref': '#/components/schemas/Uid' + 'text': + 'description': > + The text of the filtering rule applied to the request, if any. + 'type': 'string' + 'required': + - 'filter_list_uid' + - 'text' + 'type': 'object' + + 'GetV1AccountsProfileResp': + '$ref': '#/components/schemas/Profile' + + # TODO(a.garipov): Find a way to describe such XML documents using OpenAPI. + # If that is even possible. + 'GetV1AppleDohMobileconfigResp': + 'example': | + + + + + PayloadContent + + + DNSSettings + + DNSProtocol + HTTPS + ServerName + example.com + ServerURL + https://example.com/dns-query/123 + + Name + myexample.local DoH + PayloadDescription + Configures device to use AdGuard Home + PayloadDisplayName + myexample.local DoH + PayloadIdentifier + com.apple.dnsSettings.managed.b6928468-ae3a-4368-a70d-cb7122275013 + PayloadType + com.apple.dnsSettings.managed + PayloadUUID + 18526b8c-6065-4b96-b635-9cde769ac0f2 + PayloadVersion + 1 + + + PayloadDescription + Adds AdGuard Home to Big Sur and iOS 14 or newer systems + PayloadDisplayName + myexample.local DoH + PayloadIdentifier + 9a37b659-7541-4f9e-8b4d-6e2a59a123c8 + PayloadRemovalDisallowed + + PayloadType + Configuration + PayloadUUID + 255dbaf7-0c52-4855-9b22-ad8209690197 + PayloadVersion + 1 + + + 'type': 'object' + + # TODO(a.garipov): See the comment on GetV1AppleDohMobileconfigResp. + 'GetV1AppleDotMobileconfigResp': + 'example': | + + + + + PayloadContent + + + DNSSettings + + DNSProtocol + TLS + ServerName + 123.example.com + + Name + example.com DoT + PayloadDescription + Configures device to use AdGuard Home + PayloadDisplayName + example.com DoT + PayloadIdentifier + com.apple.dnsSettings.managed.7807cb66-c6ec-4c78-be29-d8ffcb3321ee + PayloadType + com.apple.dnsSettings.managed + PayloadUUID + b0fb9137-e27a-4f95-abc3-556103ad9ac1 + PayloadVersion + 1 + + + PayloadDescription + Adds AdGuard Home to Big Sur and iOS 14 or newer systems + PayloadDisplayName + myexample.local DoT + PayloadIdentifier + f1095036-406e-4243-8210-cf0ffa52b3f6 + PayloadRemovalDisallowed + + PayloadType + Configuration + PayloadUUID + 21cd3597-0769-486a-86d0-7b5e32d24305 + PayloadVersion + 1 + + + 'type': 'object' + + 'GetV1ClientsPersistentResp': + 'description': > + Persistent clients. + 'example': + 'clients': + - 'blocked': false + 'blocked_services': [] + 'filtering': false + 'ids': ['client-1'] + 'name': 'Client 1' + 'parental': false + 'safe_browsing': false + 'safe_search': false + 'tags': ['user_admin'] + 'use_global_blocked_services': true + 'use_global_settings': true + 'uid': 'abcd1234' + 'upstream_servers': [] + - 'blocked': false + 'blocked_services': [] + 'filtering': true + 'ids': ['client-2'] + 'name': 'Client 2' + 'parental': true + 'safe_browsing': true + 'safe_search': true + 'tags': ['user_child'] + 'use_global_blocked_services': false + 'use_global_settings': false + 'uid': 'efgh5678' + 'upstream_servers': [] + 'properties': + 'clients': + 'description': > + All persistent clients. + 'items': + '$ref': '#/components/schemas/PersistentClient' + 'type': 'array' + 'required': + - 'clients' + 'type': 'object' + + 'GetV1ClientsRuntimeResp': + 'description': > + Runtime clients. + 'example': + 'clients': + - 'host': 'my-box' + 'ip': '1.2.3.4' + 'num_blocked_requests': 0 + 'num_requests': 100 + 'sources': + - 'arp' + - 'ip': '5.6.7.8' + 'num_blocked_requests': 100 + 'num_requests': 100 + 'sources': + - 'whois' + 'whois': + 'city': 'Minsk' + 'country': 'BY' + 'properties': + 'clients': + 'description': > + All runtime clients. + 'items': + '$ref': '#/components/schemas/RuntimeClient' + 'type': 'array' + 'required': + - 'clients' + 'type': 'object' + + 'GetV1DhcpLeasesResp': + 'description': > + All dynamic and static DHCP leases. + 'example': + 'leases': + - 'expires': 1614345496000 + 'hostname': 'my-mobile' + 'ip': '192.168.1.2' + 'mac': '01:23:45:67:89:ab' + 'uid': 'abcd1234' + - 'expires': 1614345497000 + 'hostname': '' + 'ip': '192.168.1.3' + 'mac': '01:23:45:67:89:cd' + 'properties': + 'leases': + 'description': > + Dynamic and static DHCP leases. + 'items': + '$ref': '#/components/schemas/DhcpLease' + 'type': 'array' + 'required': + - 'leases' + 'type': 'object' + + 'GetV1DhcpStatusResp': + 'description': > + Current DHCP server status and data for enabling it. + 'example': + 'interfaces': + - 'ips': + - '192.168.1.1' + 'mac': '01:23:45:67:89:ab' + 'mtu': 1500 + 'name': 'lan0' + 'up': true + 'ipv4_other_servers': + 'ips': + - '192.169.1.1' + 'ipv4_static_ip': + 'ip': '192.168.1.1' + 'static': true + 'supported': true + 'ipv6_other_servers': + 'ips': [] + 'error': 'permission denied' + 'ipv6_static_ip': + 'ip': '200f::1' + 'static': true + 'supported': true + 'properties': + 'interfaces': + 'description': > + Available network interfaces. + 'items': + '$ref': '#/components/schemas/NetworkInterface' + 'type': 'array' + 'ipv4_other_servers': + '$ref': '#/components/schemas/GetV1DhcpStatusRespOtherServer' + 'ipv4_static_ip': + '$ref': '#/components/schemas/StaticIpCheckResult' + 'ipv6_other_servers': + '$ref': '#/components/schemas/GetV1DhcpStatusRespOtherServer' + 'ipv6_static_ip': + '$ref': '#/components/schemas/StaticIpCheckResult' + 'required': + - 'interfaces' + - 'ipv4_other_servers' + - 'ipv4_static_ip' + - 'ipv6_other_servers' + - 'ipv6_static_ip' + 'type': 'object' + + 'GetV1DhcpStatusRespOtherServer': + 'properties': + 'error': + 'description': > + Error, if any. If there is no error, this field is absent. + 'type': 'string' + 'ips': + 'description': > + IP addresses of other DHCP servers, if found. + 'required': + - 'ips' + 'type': 'object' + + 'GetV1InstallInfoResp': + 'description': > + AdGuard Home addresses configuration. + 'example': + 'dns_port': 53 + 'interfaces': + - 'ips': + - '192.168.1.1' + 'mac': '01:23:45:67:89:ab' + 'mtu': 1500 + 'name': 'lan0' + 'up': true + 'web_port': 80 + 'properties': + 'dns_port': + 'description': > + Recommended DNS port. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'interfaces': + 'description': > + Available network interfaces. + 'items': + '$ref': '#/components/schemas/NetworkInterface' + 'type': 'array' + 'web_port': + 'description': > + Recommended web interface port. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'required': + - 'dns_port' + - 'interfaces' + - 'web_port' + 'type': 'object' + + 'GetV1LogSearchResp': + 'description': > + Query log search results. + 'example': + 'results': + - 'answer': + - 'ttl': 60 + 'type': 'a' + 'value': '5.6.7.8' + 'answer_dnssec': false + 'client': + 'blocked': false + 'ids': + - '1.2.3.4' + - 'user-1' + 'name': 'User 1' + 'num': 100 + 'num_blocked': 50 + 'uid': 'abcd1234' + 'whois': + 'city': 'Minsk' + 'country': 'BY' + 'elapsed': 3.2 + 'proto': 'udp' + 'question': + 'class': 'in' + 'host': 'example.com' + 'type': 'a' + 'rcode': 'noerror' + 'reason': 'not_filtered_notfound' + 'rules': [] + 'start': 1614345496000 + 'upstream': '8.8.8.8' + 'properties': + 'results': + 'description': > + The query log. + 'items': + '$ref': '#/components/schemas/LogRecord' + 'type': 'array' + 'required': + - 'results' + 'type': 'object' + + 'GetV1ProtectionBlockedServicesResp': + '$ref': '#/components/schemas/BlockedServices' + + 'GetV1ProtectionCustomRulesResp': + '$ref': '#/components/schemas/CustomRules' + + 'GetV1ProtectionDnsRewritesResp': + 'description': > + Classic DNS rewrites. + 'example': + 'rules': + - 'answer': 'A' + 'domain': 'example.com' + 'id': 'abcd1234' + - 'answer': '0.0.0.0' + 'domain': '*.example.org' + 'id': 'efgh5678' + - 'answer': 'my.example.net' + 'domain': 'example.net' + 'id': 'ijkl9012' + 'properties': + 'rules': + 'description': > + All classic DNS rewrites. + 'items': + '$ref': '#/components/schemas/DnsRewrite' + 'type': 'array' + 'required': + - 'rules' + 'type': 'object' + + 'GetV1ProtectionFiltersResp': + 'description': > + Filters. + 'example': + 'filters': + - 'allowlist': false + 'enabled': true + 'name': 'AdMaster 5000 Super List v2.0 Final' + 'num_rules': 36766 + 'refreshed': 1614345496000 + 'uid': 'abcd1234' + 'url': 'https://admaster.example.com/list.txt' + - 'allowlist': false + 'enabled': true + 'name': 'My personal list' + 'num_rules': 0 + 'refreshed': 1614345497000 + 'uid': 'efgh5678' + 'url': 'file:///home/user/Documents/ad_list.txt' + 'properties': + 'filters': + 'description': > + All current filters. + 'items': + '$ref': '#/components/schemas/Filter' + 'type': 'array' + 'required': + - 'filters' + 'type': 'object' + + # Perhaps a lot of these belong in separate APIs, but our colleagues asked + # to pack as much data into every request as reasonably possible. + 'GetV1SettingsAllResp': + 'description': > + Most settings. + # Don't add examples, as are provided by the subclasses. + 'properties': + 'dhcp': + '$ref': '#/components/schemas/DhcpSettings' + 'dns': + '$ref': '#/components/schemas/DnsSettings' + 'log': + '$ref': '#/components/schemas/LogSettings' + 'protection': + '$ref': '#/components/schemas/ProtectionSettings' + 'stats': + '$ref': '#/components/schemas/StatsSettings' + 'tls': + '$ref': '#/components/schemas/TlsSettings' + 'required': + - 'dhcp' + - 'dns' + - 'log' + - 'protection' + - 'stats' + - 'tls' + 'type': 'object' + + 'GetV1SettingsDnsAccessResp': + '$ref': '#/components/schemas/DnsAccessSettings' + + # See the comment on the GetV1SettingsAllResp schema. + 'GetV1StatsAllResp': + 'description': > + All statistics. + 'example': + 'dns_cache_hit_rate': 56.7 + 'dns_cache_records': 123 + 'graph_avg_processing': + - 3.0 + - 0.4 + 'graph_blocked_ad_queries': + - 10 + - 20 + 'graph_blocked_custom_rule_queries': + - 10 + - 20 + 'graph_blocked_domains': + - 10 + - 20 + 'graph_blocked_parental_control_queries': + - 10 + - 20 + 'graph_blocked_safe_browsing_queries': + - 10 + - 20 + 'graph_blocked_safe_search_queries': + - 10 + - 20 + 'graph_blocked_service_queries': + - 10 + - 20 + 'graph_blocked_tracker_queries': + - 10 + - 20 + 'graph_cpu_percent': + - 50 + - 75 + 'graph_domains': + - 20 + - 30 + 'graph_queries': + - 1000 + - 2002 + 'graph_ram_resident': + - 1048576 + - 2097152 + 'time_unit': 'hour' + 'top_blocked_domains': + - 'name': 'example.net' + 'num': 100 + 'top_clients': + - 'blocked': false + 'ids': + - '1.2.3.4' + - 'user-1' + 'name': 'User 1' + 'num': 100 + 'num_blocked': 50 + 'uid': 'abcd1234' + 'whois': + 'city': 'Minsk' + 'country': 'BY' + - 'blocked': true + 'ids': + - '5.6.7.8' + 'num': 100 + 'num_blocked': 100 + 'top_domains': + - 'name': 'example.com' + 'num': 1000 + - 'name': 'example.net' + 'num': 100 + 'total_blocked_ad_queries': 100 + 'total_blocked_custom_rule_queries': 10 + 'total_blocked_domains': 500 + 'total_blocked_parental_control_queries': 10 + 'total_blocked_safe_browsing_queries': 10 + 'total_blocked_safe_search_queries': 10 + 'total_blocked_service_queries': 10 + 'total_blocked_tracker_queries': 10 + 'total_domains': 1000 + 'total_queries': 10000 + 'properties': + 'dns_cache_hit_rate': + 'description': > + DNS cache hit rate, in percent. + 'maximum': 100.0 + 'minimum': 0.0 + 'format': 'double' + 'type': 'number' + 'dns_cache_records': + 'description': > + Number of DNS responses currently in cache. + 'minimum': 0 + 'format': 'int64' + 'type': 'integer' + 'graph_avg_processing': + 'description': > + Average DNS query processing duration graph information. Each item + is one `time_unit` long. The duration is in milliseconds. Sorted + by time in descending order. + 'items': + 'format': 'double' + 'type': 'number' + 'type': 'array' + 'graph_blocked_ad_queries': + 'description': > + Number of queries blocked by advertising filters graph information. + Each item is one `time_unit` long. Sorted by time in descending + order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_custom_rule_queries': + 'description': > + Number of queries blocked by custom filtering rules graph + information. Each item is one `time_unit` long. Sorted by time in + descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_domains': + 'description': > + Blocked queried domains graph information. Each item is one + `time_unit` long. Sorted by time in descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_parental_control_queries': + 'description': > + Number of queries blocked by parental control services graph + information. Each item is one `time_unit` long. Sorted by time in + descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_safe_browsing_queries': + 'description': > + Number of queries blocked by safe browsing services graph + information. Each item is one `time_unit` long. Sorted by time in + descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_safe_search_queries': + 'description': > + Number of queries blocked by safe search services graph information. + Each item is one `time_unit` long. Sorted by time in descending + order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_service_queries': + 'description': > + Number of queries blocked by blocked service settings graph + information. Each item is one `time_unit` long. Sorted by time in + descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_tracker_queries': + 'description': > + Number of queries blocked by tracker filters graph information. + Each item is one `time_unit` long. Sorted by time in descending + order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_cpu_percent': + 'description': > + CPU usage percentage graph information. Each item is one + `time_unit` long. Sorted by time in descending order. + 'items': + 'format': 'double' + 'type': 'number' + 'type': 'array' + 'graph_domains': + 'description': > + Queried domains graph information. Each item is one `time_unit` + long. Sorted by time in descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_queries': + 'description': > + Number of served DNS queries graph information. Each item is one + `time_unit` long. Sorted by time in descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_ram_resident': + 'description': > + AdGuard Home's resident memory usage graph information. The size is + in bytes. Each item is one `time_unit` long. Sorted by time in + descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'time_unit': + '$ref': '#/components/schemas/TimeUnit' + 'top_blocked_domains': + 'description': > + Top blocked queried domains. Sorted by number in descending order. + 'items': + '$ref': '#/components/schemas/GetV1StatsAllRespTopsItem' + 'type': 'array' + 'top_clients': + 'description': > + Top clients. Sorted by number in descending order. + 'items': + '$ref': '#/components/schemas/ClientInfo' + 'type': 'array' + 'top_domains': + 'description': > + Top queried domains. Sorted by number in descending order. + 'items': + '$ref': '#/components/schemas/GetV1StatsAllRespTopsItem' + 'type': 'array' + 'total_blocked_ad_queries': + 'description': > + Total number of queries blocked by advertising filters. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_custom_rule_queries': + 'description': > + Total number of queries blocked by custom filtering rules. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_domains': + 'description': > + Total number of blocked queried domains. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_parental_control_queries': + 'description': > + Total number of queries blocked by parental control services. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_safe_browsing_queries': + 'description': > + Total number of queries blocked by safe browsing services. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_safe_search_queries': + 'description': > + Total number of queries blocked by safe search services. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_service_queries': + 'description': > + Total number of queries blocked by blocked service settings. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_tracker_queries': + 'description': > + Total number of queries blocked by tracker filters. + 'format': 'int64' + 'type': 'integer' + 'total_domains': + 'description': > + Total number of queried domains. + 'format': 'int64' + 'type': 'integer' + 'total_queries': + 'description': > + Total number of served DNS queries. + 'format': 'int64' + 'type': 'integer' + 'required': + - 'dns_cache_hit_rate' + - 'dns_cache_records' + - 'graph_avg_processing' + - 'graph_blocked_ad_queries' + - 'graph_blocked_custom_rule_queries' + - 'graph_blocked_domains' + - 'graph_blocked_parental_control_queries' + - 'graph_blocked_safe_browsing_queries' + - 'graph_blocked_safe_search_queries' + - 'graph_blocked_service_queries' + - 'graph_blocked_tracker_queries' + - 'graph_cpu_percent' + - 'graph_domains' + - 'graph_queries' + - 'graph_ram_resident' + - 'time_unit' + - 'top_blocked_domains' + - 'top_clients' + - 'top_domains' + - 'total_blocked_ad_queries' + - 'total_blocked_custom_rule_queries' + - 'total_blocked_domains' + - 'total_blocked_parental_control_queries' + - 'total_blocked_safe_browsing_queries' + - 'total_blocked_safe_search_queries' + - 'total_blocked_service_queries' + - 'total_blocked_tracker_queries' + - 'total_domains' + - 'total_queries' + 'type': 'object' + + 'GetV1StatsAllRespTopsItem': + 'description': > + A top array item. + 'properties': + 'name': + 'description': > + The name of the entity. Mostly domain names. + 'example': 'example.com' + 'type': 'string' + 'num': + 'description': > + The value of the statistic. + 'example': 1000 + 'format': 'int64' + 'type': 'integer' + 'required': + - 'name' + - 'num' + 'type': 'object' + + 'GetV1SystemInfoResp': + 'description': > + Information about the AdGuard Home server. + 'example': + 'channel': 'release' + 'new_version': 'v0.106.1' + 'start': 1614345496000 + 'version': 'v0.106.0' + 'properties': + 'channel': + '$ref': '#/components/schemas/Channel' + 'new_version': + 'description': > + New available version of AdGuard Home to which the server can be + updated, if any. If there are none, this field is absent. + 'type': 'string' + 'start': + 'description': > + Unix time at which AdGuard Home started working, in milliseconds. + 'format': 'double' + 'type': 'number' + 'version': + 'description': > + Current AdGuard Home version. + 'type': 'string' + 'required': + - 'channel' + - 'start' + - 'version' + 'type': 'object' + + 'InternalServerErrorResp': + 'example': + 'code': 'RNT000' + 'msg': >- + runtime error: invalid memory address or nil pointer dereference + 'properties': + 'code': + '$ref': '#/components/schemas/ErrorCode' + 'msg': + 'description': > + Error message string. + 'type': 'string' + 'required': + - 'code' + - 'msg' + 'type': 'object' + + 'Lang': + 'description': > + Language code. + # Hold the enum in sync with .twosky.json. + 'enum': + - 'be' + - 'bg' + - 'cs' + - 'da' + - 'de' + - 'en' + - 'es' + - 'fa' + - 'fr' + - 'hr' + - 'hu' + - 'id' + - 'it' + - 'ja' + - 'ko' + - 'nl' + - 'no' + - 'pl' + - 'pt-br' + - 'pt-pt' + - 'ro' + - 'ru' + - 'si-lk' + - 'sk' + - 'sl' + - 'sr-cs' + - 'sv' + - 'th' + - 'tr' + - 'vi' + - 'zh-cn' + - 'zh-hk' + - 'zh-tw' + 'type': 'string' + + 'LogRecord': + 'description': > + Query log record. + 'properties': + 'answer': + 'description': > + The answer given to the user. + 'items': + '$ref': '#/components/schemas/LogRecordDnsAnswer' + 'type': 'array' + 'answer_dnssec': + 'description': > + If `true`, DNSSEC was used. + 'type': 'boolean' + 'blocked_service': + 'description': > + Set if `reason` is `filtered_blocked_service`. Otherwise, this + field is absent. + 'type': 'string' + 'client': + '$ref': '#/components/schemas/ClientInfo' + 'elapsed': + 'description': > + Time it took to process the request, in milliseconds. + 'format': 'double' + 'type': 'number' + 'original_answer': + 'description': > + Original answer from the upstream server, if the answer was + rewritten. + 'items': + '$ref': '#/components/schemas/LogRecordDnsAnswer' + 'type': 'array' + 'proto': + '$ref': '#/components/schemas/DnsProto' + 'question': + '$ref': '#/components/schemas/LogRecordDnsQuestion' + 'rcode': + '$ref': '#/components/schemas/DnsResponseCode' + 'reason': + '$ref': '#/components/schemas/FilteringReason' + 'rules': + 'description': > + Applied rules. + 'items': + '$ref': '#/components/schemas/FilteringResultRule' + 'type': 'array' + 'start': + 'description': > + Request processing start Unix time, in milliseconds. + 'format': 'double' + 'type': 'number' + 'upstream': + '$ref': '#/components/schemas/UpstreamServerAddr' + 'required': + - 'answer' + - 'answer_dnssec' + - 'client' + - 'elapsed' + - 'proto' + - 'question' + - 'rcode' + - 'reason' + - 'rules' + - 'start' + - 'upstream' + 'type': 'object' + + 'LogRecordDnsAnswer': + 'description': > + DNS answer section. + 'properties': + 'ttl': + 'description': > + TTL of a record. This value is in **seconds**, like in DNS record + headers. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'type': + '$ref': '#/components/schemas/DnsType' + 'value': + 'description': > + An opaque string describing the result value. + 'type': 'string' + 'required': + - 'ttl' + - 'type' + - 'value' + 'type': 'object' + + 'LogRecordDnsQuestion': + 'description': > + DNS question section. + 'properties': + 'class': + '$ref': '#/components/schemas/DnsClass' + 'host': + 'description': > + Host from the query. + 'type': 'string' + 'type': + '$ref': '#/components/schemas/DnsType' + 'required': + - 'class' + - 'host' + - 'type' + 'type': 'object' + + 'LogSettings': + 'allOf': + - '$ref': '#/components/schemas/LogSettingsPatch' + - 'description': > + Query logging settings. + 'example': + 'anonymize': true + 'enabled': true + 'rotation': 604800000 + 'required': + - 'anonymize' + - 'enabled' + - 'rotation' + + 'LogSettingsPatch': + 'description': > + Query logging settings update object. + 'properties': + 'anonymize': + 'description': > + If `true`, client IP address anonymization is enabled. + 'type': 'boolean' + 'enabled': + 'description': > + If `true`, query logging is enabled. + 'type': 'boolean' + 'rotation': + 'description': > + Log rotation interval, in milliseconds. After that time, the log + file will be replaced by a new one, while the old one gets renamed. + 'format': 'double' + 'minimum': 86400000 + 'maximum': 7776000000 + 'type': 'number' + 'type': 'object' + + 'NetworkInterface': + 'properties': + 'ips': + 'description': > + The IP addresses of the interface, if any. + 'items': + 'type': 'string' + 'type': 'array' + 'mac': + 'description': > + The MAC address of the interface. + 'type': 'string' + 'mtu': + 'description': > + The interface's MTU, the maximum transmission unit. + 'format': 'int64' + 'type': 'integer' + 'name': + 'description': > + The name of the interface. + 'type': 'string' + 'up': + 'description': > + If `true`, the interface is up. + 'type': 'boolean' + 'required': + - 'ips' + - 'mac' + - 'mtu' + - 'name' + - 'up' + 'type': 'object' + + 'NotFoundResp': + 'example': + 'code': 'ENT404' + 'msg': >- + entity not found + 'properties': + 'code': + '$ref': '#/components/schemas/ErrorCode' + 'msg': + 'description': > + Error message string. + 'type': 'string' + 'required': + - 'code' + - 'msg' + 'type': 'object' + + 'PatchV1AccountsProfileReq': + 'example': + 'lang': 'ru' + 'properties': + 'lang': + '$ref': '#/components/schemas/Lang' + 'type': 'object' + + 'PatchV1AccountsProfileResp': + '$ref': '#/components/schemas/Profile' + + 'PatchV1ClientPersistentReq': + '$ref': '#/components/schemas/PersistentClientPatch' + + 'PatchV1ClientPersistentResp': + '$ref': '#/components/schemas/PersistentClient' + + 'PatchV1DhcpLeaseReq': + '$ref': '#/components/schemas/DhcpLeasePatch' + + 'PatchV1DhcpLeaseResp': + '$ref': '#/components/schemas/DhcpLease' + + 'PatchV1ProtectionFilterReq': + '$ref': '#/components/schemas/FilterPatch' + + 'PatchV1ProtectionFilterResp': + '$ref': '#/components/schemas/Filter' + + 'PatchV1SettingsDhcpReq': + '$ref': '#/components/schemas/DhcpSettingsPatch' + + 'PatchV1SettingsDhcpResp': + '$ref': '#/components/schemas/DhcpSettings' + + 'PatchV1SettingsDnsReq': + '$ref': '#/components/schemas/DnsSettingsPatch' + + 'PatchV1SettingsDnsResp': + '$ref': '#/components/schemas/DnsSettings' + + 'PatchV1SettingsLogReq': + '$ref': '#/components/schemas/LogSettingsPatch' + + 'PatchV1SettingsLogResp': + '$ref': '#/components/schemas/LogSettings' + + 'PatchV1SettingsProtectionReq': + '$ref': '#/components/schemas/ProtectionSettingsPatch' + + 'PatchV1SettingsProtectionResp': + '$ref': '#/components/schemas/ProtectionSettings' + + 'PatchV1SettingsStatsReq': + '$ref': '#/components/schemas/StatsSettingsPatch' + + 'PatchV1SettingsStatsResp': + '$ref': '#/components/schemas/StatsSettings' + + 'PatchV1SettingsTlsReq': + '$ref': '#/components/schemas/TlsSettingsPatch' + + 'PatchV1SettingsTlsResp': + '$ref': '#/components/schemas/TlsSettings' + + 'PersistentClient': + 'allOf': + - '$ref': '#/components/schemas/PersistentClientPatch' + - 'description': > + Persistent client. + 'example': + 'blocked': false + 'blocked_services': [] + 'filtering': false + 'ids': ['client-1'] + 'name': 'Client 1' + 'num_blocked_requests': 50 + 'num_requests': 100 + 'parental': false + 'safe_browsing': false + 'safe_search': false + 'tags': ['user_admin'] + 'use_global_blocked_services': true + 'use_global_settings': true + 'uid': 'abcd1234' + 'upstream_servers': [] + 'properties': + 'num_blocked_requests': + 'description': > + Total number of blocked requests for this runtime client. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'num_requests': + 'description': > + Total number of requests for this runtime client. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'uid': + '$ref': '#/components/schemas/Uid' + 'required': + - 'blocked' + - 'blocked_services' + - 'filtering' + - 'ids' + - 'name' + - 'parental' + - 'safe_browsing' + - 'safe_search' + - 'tags' + - 'uid' + - 'upstream_servers' + - 'use_global_blocked_services' + - 'use_global_settings' + + 'PersistentClientPatch': + 'description': > + Persistent client update object. + 'example': + 'filtering': false + 'parental': false + 'safe_browsing': false + 'safe_search': false + 'tags': ['user_admin'] + 'properties': + 'blocked': + 'description': > + If `true`, the client is blocked. + 'type': 'boolean' + 'blocked_services': + 'description': > + Custom blocked services for this client. + 'items': + '$ref': '#/components/schemas/BlockedServiceId' + 'type': 'array' + 'filtering': + 'description': > + If `true`, filtering based on filter rule lists is enabled for this + client. + 'type': 'boolean' + 'ids': + 'description': > + IP, CIDR, MAC, or ClientID (not to be confused with the `uid` field) + for client identification. + 'items': + 'type': 'string' + 'type': 'array' + 'name': + 'description': > + The name of this client. + 'type': 'string' + 'parental': + 'description': > + If `true`, parental protection is enabled for this client. + 'type': 'boolean' + 'safe_browsing': + 'description': > + If `true`, safe browsing protection is enabled for this client. + 'type': 'boolean' + 'safe_search': + 'description': > + If `true`, safe search protection is enabled for this client. + 'type': 'boolean' + 'tags': + 'description': > + Client tags. + 'items': + '$ref': '#/components/schemas/PersistentClientTag' + 'type': 'array' + 'use_global_blocked_services': + 'description': > + If `true`, use global blocked services for this client instead of + the custom ones. + 'type': 'boolean' + 'use_global_settings': + 'description': > + If `true`, use global protection settings for this client instead of + the custom ones. + 'type': 'boolean' + 'upstream_servers': + 'description': > + Custom upstream DNS servers for this client. + 'items': + '$ref': '#/components/schemas/UpstreamServerAddr' + 'type': 'array' + 'type': 'object' + + 'PersistentClientPost': + 'allOf': + - '$ref': '#/components/schemas/PersistentClientPatch' + - 'description': > + Persistent client create object. + 'example': + 'blocked': false + 'blocked_services': [] + 'filtering': false + 'ids': ['client-1'] + 'name': 'Client 1' + 'parental': false + 'safe_browsing': false + 'safe_search': false + 'tags': ['user_admin'] + 'use_global_blocked_services': true + 'use_global_settings': true + 'upstream_servers': [] + 'required': + - 'blocked' + - 'blocked_services' + - 'filtering' + - 'ids' + - 'name' + - 'parental' + - 'safe_browsing' + - 'safe_search' + - 'tags' + - 'upstream_servers' + - 'use_global_blocked_services' + - 'use_global_settings' + + 'PersistentClientTag': + 'description': > + Tags can be included in filtering rules to allow you to apply them more + accurately. + 'enum': + - 'device_audio' + - 'device_camera' + - 'device_gameconsole' + - 'device_laptop' + - 'device_nas' + - 'device_other' + - 'device_pc' + - 'device_phone' + - 'device_printer' + - 'device_securityalarm' + - 'device_tablet' + - 'device_tv' + - 'os_android' + - 'os_ios' + - 'os_linux' + - 'os_macos' + - 'os_other' + - 'os_windows' + - 'user_admin' + - 'user_child' + - 'user_regular' + 'type': 'string' + + 'PostV1AccountsSessionReq': + 'example': + 'password': 'G00dp455word!' + 'username': 'admin' + 'properties': + 'password': + 'description': > + Password. + 'format': 'password' + 'type': 'string' + 'username': + 'description': > + Username. + 'type': 'string' + 'required': + - 'password' + - 'username' + 'type': 'object' + + 'PostV1ClientsPersistentReq': + '$ref': '#/components/schemas/PersistentClientPost' + + 'PostV1ClientsPersistentResp': + '$ref': '#/components/schemas/PersistentClient' + + 'PostV1DhcpLeasesReq': + '$ref': '#/components/schemas/DhcpLeasePost' + + 'PostV1DhcpLeasesResp': + '$ref': '#/components/schemas/DhcpLease' + + 'PostV1InstallCheckReq': + 'description': > + Configuration for checking. + 'example': + 'dns': + 'ip': + - '0.0.0.0' + 'port': 53 + 'static_ip': false + 'web': + 'ip': + - '0.0.0.0' + 'port': 80 + 'properties': + 'dns': + '$ref': '#/components/schemas/PostV1InstallCheckReqServer' + 'static_ip': + 'description': > + If `true`, check if a static IP is set or can be set. + 'type': 'boolean' + 'web': + '$ref': '#/components/schemas/PostV1InstallCheckReqServer' + 'required': + - 'dns' + - 'static_ip' + - 'web' + 'type': 'object' + + 'PostV1InstallCheckReqServer': + 'description': > + A configuration for a server check. + 'properties': + 'ip': + 'description': > + IP addresses to check for availability. + 'items': + 'type': 'string' + 'minItems': 1 + 'type': 'array' + 'port': + 'description': > + Port to check for availability. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'required': + - 'ip' + - 'port' + 'type': 'object' + + 'PostV1InstallCheckResp': + 'description': > + Configuration checking response. + 'example': + 'dns': + 'error': 'permission denied' + 'static_ip': + 'ip': '192.168.1.1' + 'static': true + 'supported': true + 'web': {} + 'properties': + 'dns': + '$ref': '#/components/schemas/PostV1InstallCheckRespNetwork' + 'static_ip': + '$ref': '#/components/schemas/StaticIpCheckResult' + 'web': + '$ref': '#/components/schemas/PostV1InstallCheckRespNetwork' + 'required': + - 'dns' + - 'static_ip' + - 'web' + 'type': 'object' + + 'PostV1InstallCheckRespNetwork': + 'properties': + 'error': + 'description': > + Error, if any. If there is no error, this field is absent. + 'type': 'string' + 'type': 'object' + + 'PostV1InstallConfigureReq': + 'description': > + AdGuard Home initial configuration. + 'example': + 'dns_ip': '0.0.0.0' + 'dns_port': 53 + 'password': 'G00dp455word!' + 'username': 'admin' + 'set_static_ip': true + 'web_ip': '0.0.0.0' + 'web_port': 80 + 'properties': + 'dns_ip': + 'description': > + The IP address to serve DNS queries on. + 'type': 'string' + 'dns_port': + 'description': > + The port to serve DNS queries on. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'password': + 'description': > + Password. + 'type': 'string' + 'username': + 'description': > + Username. + 'type': 'string' + 'set_static_ip': + 'description': > + If `true`, set the server's IP address to static. + 'type': 'boolean' + 'web_ip': + 'description': > + The IP address to serve the web interface on. + 'type': 'string' + 'web_port': + 'description': > + The port to serve the web interface on. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'required': + - 'dns_ip' + - 'dns_port' + - 'password' + - 'username' + - 'set_static_ip' + - 'web_ip' + - 'web_port' + 'type': 'object' + + 'PostV1LogClearReq': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1ProtectionCheckCustomRulesReq': + 'description': > + Data to check using custom filtering rules. + 'example': + 'host': 'example.com' + 'properties': + 'host': + 'description': > + The hostname to check. + 'type': 'string' + 'required': + - 'host' + 'type': 'object' + + 'PostV1ProtectionCheckCustomRulesResp': + 'description': > + Custom filtering rules check results. + 'example': + 'reason': 'filtered_blocklist' + 'rules': + - 'filter_list_uid': 'abcd1234' + 'text': '||example.com^' + 'properties': + 'cname': + 'description': > + Set if `reason` is `Rewrite`. Otherwise, this field is absent. + 'type': 'string' + 'ip_addrs': + 'description': > + Set if `reason` is `Rewrite`. Otherwise, this field is absent. + 'items': + 'type': 'string' + 'type': 'array' + 'reason': + '$ref': '#/components/schemas/FilteringReason' + 'rules': + 'description': > + Applied rules. + 'items': + '$ref': '#/components/schemas/FilteringResultRule' + 'type': 'array' + 'service_name': + 'description': > + Set if `reason` is `FilteredBlockedService`. Otherwise, this field + is absent. + 'type': 'string' + 'required': + - 'reason' + - 'rules' + 'type': 'object' + + 'PostV1ProtectionDnsRewritesReq': + '$ref': '#/components/schemas/DnsRewritePost' + + 'PostV1ProtectionDnsRewritesResp': + '$ref': '#/components/schemas/DnsRewrite' + + 'PostV1ProtectionFiltersReq': + '$ref': '#/components/schemas/FilterPost' + + 'PostV1ProtectionFiltersResp': + '$ref': '#/components/schemas/Filter' + + 'PostV1ProtectionRefreshFilterReq': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1ProtectionRefreshFilterResp': + '$ref': '#/components/schemas/Filter' + + 'PostV1ProtectionRefreshFiltersReq': + 'description': > + Filters refresh parameters. + 'example': + 'allowlist': false + 'blocklist': true + 'properties': + 'allowlist': + 'description': > + If `true`, refresh all allowlist filters. + 'type': 'boolean' + 'blocklist': + 'description': > + If `true`, refresh all blocklist filters. + 'type': 'boolean' + 'required': + - 'allowlist' + - 'blocklist' + 'type': 'object' + + 'PostV1ProtectionRefreshFiltersResp': + 'description': > + Refresh results. + 'example': + 'errors': + - 'msg': 'context deadline exceeded' + 'uid': 'efgh5678' + 'refreshed': + - 'allowlist': false + 'enabled': true + 'name': 'AdMaster 5000 Super List v2.0 Final' + 'num_rules': 36766 + 'refreshed': 1614345496000 + 'uid': 'abcd1234' + 'url': 'https://admaster.example.com/list.txt' + 'properties': + 'errors': + 'description': > + All encountered errors. + 'items': + '$ref': '#/components/schemas/RefreshFilterError' + 'type': 'array' + 'refreshed': + 'description': > + Refreshed filters. + 'items': + '$ref': '#/components/schemas/Filter' + 'type': 'array' + 'required': + - 'errors' + - 'refreshed' + 'type': 'object' + + 'PostV1SettingsDnsCheckReq': + 'description': > + Validatable DNS settings. + 'example': + 'bootstrap_servers': + - '9.9.9.10' + - '149.112.112.10' + 'upstream_servers': + - '1.1.1.1' + - '8.8.8.8' + 'properties': + 'bootstrap_servers': + 'description': | + Bootstrap DNS servers' IP addresses to check. + 'items': + 'type': 'string' + 'type': 'array' + 'upstream_servers': + 'description': > + Upstream DNS servers to check. + 'items': + '$ref': '#/components/schemas/UpstreamServerAddr' + 'type': 'array' + 'required': + - 'bootstrap_servers' + - 'upstream_servers' + 'type': 'object' + + 'PostV1SettingsDnsCheckResp': + 'description': > + DNS settings validation results. + 'example': + 'bootstrap_servers': + '9.9.9.10': 'network is unreachable' + 'upstream_servers': + '8.8.8.8': 'network is unreachable' + 'properties': + 'bootstrap_servers': + 'additionalProperties': + 'minLength': 1 + 'type': 'string' + 'description': > + An IP-address-to-error mapping. If an address is not in this + object, the check for that address is successful. If there were no + errors, this field is absent. + 'upstream_servers': + 'additionalProperties': + 'type': 'string' + 'description': > + An upstream-address-to-error mapping. If an address is not in this + object, the check for that address is successful. If there were no + errors, this field is absent. + 'type': 'object' + + 'PostV1SettingsTlsCheckReq': + 'description': > + Validatable TLS settings. + 'example': + 'certificate_path': '/etc/ssl/example.com.cert' + 'port_dns_over_quic': 784 + 'port_dns_over_tls': 853 + 'port_https': 443 + 'private_key_path': '/etc/ssl/example.com.key' + 'server_name': 'dns.example.com' + 'properties': + 'certificate': + 'description': | + Base64-encoded string with PEM-encoded certificate chain. + + Should not be sent if `certificate_path` is sent. Otherwise, must + be sent. + 'format': 'byte' + 'type': 'string' + 'certificate_path': + 'description': | + Path to the certificate file. + + Should not be sent if `certificate` is sent. Otherwise, must be + sent. + 'type': 'string' + 'port_dns_over_quic': + 'default': 784 + 'description': > + The DNS-over-QUIC port. If `0`, DNS-over-QUIC is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'port_dns_over_tls': + 'default': 853 + 'description': > + The DNS-over-TLS port. If `0`, DNS-over-TLS is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'port_https': + 'default': 443 + 'description': > + The HTTPS port. If `0`, HTTPS is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'private_key': + 'description': | + Base64-encoded string with PEM-encoded private key. + + Should not be sent if `private_key_path` is sent. Otherwise, must + be sent. + 'format': 'byte' + 'type': 'string' + 'private_key_path': + 'description': | + Path to the private key file. + + Should not be sent if `private_key` is sent. Otherwise, must be + sent. + 'type': 'string' + 'server_name': + 'description': > + The name of the server. Used to validate the certificates as well + as to check ClientIDs in DNS-over-HTTP and DNS-over-TLS. + 'type': 'string' + 'required': + - 'port_dns_over_quic' + - 'port_dns_over_tls' + - 'port_https' + - 'server_name' + 'type': 'object' + + 'PostV1SettingsTlsCheckResp': + 'description': > + TLS settings validation results. + 'example': + 'dns_names': + - '*.example.com' + - 'example.com' + 'issuer': 'CN=Example CA,OU=Development,O=Example CA,L=Canberra,ST=Canberra,C=AU' + 'key_type': 'RSA' + 'not_after': 1614345497000 + 'not_before': 1614345496000 + 'port_https_error': 'address already in use' + 'subject': 'CN=Example CA,OU=Development,O=Example CA,L=Canberra,ST=Canberra,C=AU' + 'warnings': [] + 'properties': + 'cert_error': + 'description': > + Certificate validation error, if any. If the certificate is valid, + this field is absent. + 'type': 'string' + 'chain_error': + 'description': > + Certificate chain validation error, if any. If the certificate + chain is valid, this field is absent. + 'type': 'string' + 'dns_names': + 'description': > + The value of the `SubjectAltNames` field of the first certificate in + the chain. + 'items': + 'type': 'string' + 'type': 'array' + 'issuer': + 'description': > + The issuer of the first certificate in the chain. + 'type': 'string' + 'key_error': + 'description': > + Private key pair error, if any. If the key is valid, this field is + absent. + 'type': 'string' + 'key_type': + '$ref': '#/components/schemas/TlsKeyType' + 'not_after': + 'description': > + The value of the `NotAfter` field of the first certificate in the + chain, as a Unix time, in milliseconds. + 'format': 'double' + 'type': 'number' + 'not_before': + 'description': > + The value of the `NotBefore` field of the first certificate in the + chain, as a Unix time, in milliseconds. + 'format': 'double' + 'type': 'number' + 'port_dns_over_quic_error': + 'description': > + DNS-over-QUIC port checking error, if any. If the port is + available, this field is absent. + 'type': 'string' + 'port_dns_over_tls_error': + 'description': > + DNS-over-TLS port checking error, if any. If the port is available, + this field is absent. + 'type': 'string' + 'port_https_error': + 'description': > + DNS-over-HTTPS port checking error, if any. If the port is + available, this field is absent. + 'type': 'string' + 'pair_error': + 'description': > + Certificate and key pair error, if any. If the pair is valid, this + field is absent. + 'type': 'string' + 'subject': + 'description': > + The subject of the first certificate in the chain. + 'type': 'string' + 'warnings': + 'description': > + Validation warnings, if any. + 'items': + 'type': 'string' + 'type': 'array' + 'required': + - 'dns_names' + - 'issuer' + - 'key_type' + - 'not_after' + - 'not_before' + - 'subject' + - 'warnings' + 'type': 'object' + + 'PostV1StatsClearReq': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1SystemResetReq': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1SystemResetResp': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1SystemUpdateReq': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1SystemUpdateResp': + 'example': + 'reload': 10000 + 'properties': + 'reload': + 'description': > + Time, after which the frontend must reload the page, in + milliseconds. + 'format': 'double' + 'type': 'number' + 'type': 'object' + + 'Profile': + 'description': > + Current user's profile. + 'example': + 'lang': 'en' + 'username': 'admin' + 'properties': + 'lang': + '$ref': '#/components/schemas/Lang' + 'username': + 'description': > + Current user's name. + 'type': 'string' + 'required': + - 'lang' + - 'username' + 'type': 'object' + + 'ProtectionSettings': + 'allOf': + - '$ref': '#/components/schemas/ProtectionSettingsPatch' + - 'description': > + Protection settings. + 'example': + 'autoupdate': 86400000 + 'filtering': true + 'parental': true + 'safe_browsing': false + 'safe_search': false + 'required': + - 'autoupdate' + - 'filtering' + - 'parental' + - 'safe_browsing' + - 'safe_search' + + 'ProtectionSettingsPatch': + 'description': > + Protection settings update object. + 'example': + 'autoupdate': 0 + 'properties': + 'autoupdate': + 'description': > + Filter automatic update interval, in milliseconds. Set to `0` to + disable automatic updates. + 'format': 'double' + 'minimum': 0 + 'maximum': 604800000 + 'type': 'number' + 'filtering': + 'description': > + If `true`, filtering based on filter rule lists is enabled. + 'type': 'boolean' + 'parental': + 'description': > + If `true`, parental protection is enabled. + 'type': 'boolean' + 'pause_end': + 'description': | + If `state` is `paused`, `pause_end` will show the Unix time until + which the protection is disabled in milliseconds. Otherwise, the + property won't be set. + + When updating, if `state` is set to `paused`, `pause_end` must be + set to a timestamp in the future. + 'format': 'double' + 'type': 'number' + 'safe_browsing': + 'description': > + If `true`, safe browsing protection is enabled. + 'type': 'boolean' + 'safe_search': + 'description': > + If `true`, safe search protection is enabled. + 'type': 'boolean' + 'state': + '$ref': '#/components/schemas/ProtectionSettingsState' + 'type': 'object' + + 'ProtectionSettingsState': + 'description': | + State of protection. + + * `off`: Protection is disabled. + + * `on`: Protection is enabled. + + * `paused`: Protection is paused. See the `pause_end` property to get + or set the end of the pause. + 'enum': + - 'off' + - 'on' + - 'paused' + 'type': 'string' + + 'PutV1ProtectionBlockedServicesReq': + '$ref': '#/components/schemas/BlockedServices' + + 'PutV1ProtectionCustomRulesReq': + '$ref': '#/components/schemas/CustomRules' + + 'PutV1SettingsDnsAccessReq': + '$ref': '#/components/schemas/DnsAccessSettings' + + 'RefreshFilterError': + 'description': > + Filter refresh error. + 'properties': + 'msg': + 'description': > + Error message. + 'type': 'string' + 'uid': + '$ref': '#/components/schemas/Uid' + 'required': + - 'msg' + - 'uid' + 'type': 'object' + + 'RuntimeClient': + 'description': > + A runtime client's information. + 'properties': + 'host': + 'description': > + The RDNS host of the runtime, if any. If there is none, this field + is absent. + 'type': 'string' + 'ip': + 'description': > + The IP-address of the runtime client. + 'type': 'string' + 'sources': + 'description': > + The sources from which the information about this runtime client was + collected. + 'items': + '$ref': '#/components/schemas/RuntimeClientSource' + 'minItems': 1 + 'type': 'array' + 'num_blocked_requests': + 'description': > + Total number of blocked requests for this runtime client. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'num_requests': + 'description': > + Total number of requests for this runtime client. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'whois': + '$ref': '#/components/schemas/Whois' + 'required': + - 'ip' + - 'num_blocked_requests' + - 'num_requests' + - 'sources' + 'type': 'object' + + 'RuntimeClientSource': + 'description': > + The source from which the information about this runtime client was + collected. + + * `arp`: The information was collected from the `arp -a` output. + + * `dhcp`: The information was collected from our DHCP server. + + * `hosts_file`: The information was collected from the `/etc/hosts` + file. + + * `rdns`: The information was collected by performing a reverse DNS + lookup. + + * `whois`: The information was collected by performing a WHOIS lookup. + 'enum': + - 'arp' + - 'dhcp' + - 'hosts_file' + - 'rdns' + - 'whois' + 'type': 'string' + + 'StaticIpCheckResult': + 'properties': + 'error': + 'description': > + Error, if any. If there is no error, this field is absent. + 'type': 'string' + 'ip': + 'description': > + The IP address. + 'type': 'string' + 'static': + 'description': > + If `true`, the interface has a static IP address. + 'type': 'boolean' + 'supported': + 'description': > + If `true`, setting a static IP on this system is supported. + 'type': 'boolean' + 'required': + - 'ip' + - 'static' + - 'supported' + 'type': 'object' + + 'StatsSettings': + 'allOf': + - '$ref': '#/components/schemas/StatsSettingsPatch' + - 'description': > + Statistics settings. + 'required': + - 'autorefresh' + - 'retention' + + 'StatsSettingsPatch': + 'description': > + Statistics settings update object. + 'properties': + 'autorefresh': + 'description': > + Statistics UI autorefresh time in milliseconds. `0` means + autorefresh is disabled. + 'format': 'double' + 'type': 'number' + 'retention': + 'description': > + Statistics retention interval, in milliseconds. + 'format': 'double' + 'type': 'number' + 'type': 'object' + + 'TimeUnit': + 'description': > + Time units used for statistics. See the documentation for the + `GET /api/v1/stats/all` request. + 'enum': + - 'hour' + - 'day' + 'type': 'string' + + 'TlsKeyType': + 'description': > + TLS key type. + 'enum': + - 'ECDSA' + - 'RSA' + 'type': 'string' + + 'TlsSettings': + 'allOf': + - '$ref': '#/components/schemas/TlsSettingsPatch' + - 'description': > + TLS and encryption settings. + 'example': + 'certificate_path': '/etc/ssl/example.com.cert' + 'enabled': true + 'force_https': true + 'port_dns_over_quic': 784 + 'port_dns_over_tls': 853 + 'port_https': 443 + 'private_key_path': '/etc/ssl/example.com.key' + 'server_name': 'dns.example.com' + 'required': + - 'enabled' + - 'force_https' + - 'port_dns_over_quic' + - 'port_dns_over_tls' + - 'port_https' + - 'server_name' + + 'TlsSettingsPatch': + 'description': > + TLS and encryption settings update object. + 'example': + 'certificate': 'Base64KeyDatAA==' + 'enabled': true + 'private_key': 'Base64CertDatA==' + 'properties': + 'certificate': + 'description': | + Base64-encoded string with PEM-encoded certificate chain. + + Should not be sent if `certificate_path` is sent. Otherwise, must + be sent. + 'format': 'byte' + 'type': 'string' + 'certificate_path': + 'description': | + Path to the certificate file. + + Should not be sent if `certificate` is sent. Otherwise, must be + sent. + 'type': 'string' + 'enabled': + 'description': > + If `true`, AdGuard Home the administration interface will be served + over HTTPS, and the DNS server will listen requests over + DNS-over-TLS and other protocols. + 'type': 'boolean' + 'force_https': + 'description': > + If `true`, enabled the HTTP-to-HTTPS redirect. + 'type': 'boolean' + 'port_dns_over_quic': + 'default': 784 + 'description': > + The DNS-over-QUIC port. If `0`, DNS-over-QUIC is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'port_dns_over_tls': + 'default': 853 + 'description': > + The DNS-over-TLS port. If `0`, DNS-over-TLS is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'port_https': + 'default': 443 + 'description': > + The HTTPS port. If `0`, HTTPS is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'private_key': + 'description': | + Base64-encoded string with PEM-encoded private key. + + Should not be sent if `private_key_path` is sent. Otherwise, must + be sent. + 'format': 'byte' + 'type': 'string' + 'private_key_path': + 'description': | + Path to the private key file. + + Should not be sent if `private_key` is sent. Otherwise, must be + sent. + 'type': 'string' + 'server_name': + 'description': > + The name of the server. Used to validate the certificates as well + as to check ClientIDs in DNS-over-HTTP and DNS-over-TLS. + 'type': 'string' + 'type': 'object' + + 'Uid': + 'description': > + A unique ID of an entity, an opaque string. + 'pattern': '[0-9a-zA-Z_-]{1,64}' + 'type': 'string' + + 'UnauthorizedResp': + 'example': + 'code': 'AUT000' + 'msg': 'no or bad authorization provided' + 'properties': + 'code': + '$ref': '#/components/schemas/ErrorCode' + 'msg': + 'description': > + Error message string. + 'type': 'string' + 'required': + - 'code' + - 'msg' + 'type': 'object' + + 'UnprocessableEntityResp': + 'example': + 'code': 'JSN001' + 'msg': >- + json: cannot unmarshal string into Go struct field T.A of type int + 'properties': + 'code': + '$ref': '#/components/schemas/ErrorCode' + 'msg': + 'description': > + Error message string. + 'type': 'string' + 'required': + - 'code' + - 'msg' + 'type': 'object' + + 'UpstreamServerAddr': + 'description': | + Upstream DNS server address. Supported item formats: + + * `94.140.14.140`: plain DNS-over-UDP. + + * `tls://dns-unfiltered.adguard.com`: encrypted DNS-over-TLS. + + * `https://dns-unfiltered.adguard.com/dns-query`: encrypted + DNS-over-HTTPS. + + * `quic://dns-unfiltered.adguard.com:784`: encrypted DNS-over-QUIC + (experimental). + + * `tcp://94.140.14.140`: plain DNS-over-TCP. + + * `sdns://...`: DNS Stamps for DNSCrypt or DNS-over-HTTPS + resolvers. + + * `[/example.local/]94.140.14.140`: DNS upstream for specific + domain(s). + + * `# comment`: A comment. + 'type': 'string' + + 'Whois': + 'additionalProperties': + 'type': 'string' + 'description': > + WHOIS information, if any. If there are none, this field is usually + absent. + 'minProperties': 1 + 'type': 'object' + + # TODO(a.garipov): Find a way to specify a cookie authorization. + 'securitySchemes': + 'basicAuth': + 'description': > + Basic HTTP authorization. + 'scheme': 'basic' + 'type': 'http' diff --git a/scripts/make/go-build.sh b/scripts/make/go-build.sh index 7854166c..c998a611 100644 --- a/scripts/make/go-build.sh +++ b/scripts/make/go-build.sh @@ -123,4 +123,14 @@ CGO_ENABLED="$cgo_enabled" GO111MODULE='on' export CGO_ENABLED GO111MODULE -"$go" build --ldflags "$ldflags" "$race_flags" --trimpath "$o_flags" "$v_flags" "$x_flags" +# Build the new binary if requested. +if [ "${V1API:-0}" -eq '0' ] +then + tags_flags='--tags=' +else + tags_flags='--tags=v1' +fi +readonly tags_flags + +"$go" build --ldflags "$ldflags" "$race_flags" "$tags_flags" --trimpath "$o_flags" "$v_flags"\ + "$x_flags" diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh index 32d99480..df2f297a 100644 --- a/scripts/make/go-lint.sh +++ b/scripts/make/go-lint.sh @@ -136,11 +136,11 @@ underscores() { -e '_freebsd.go'\ -e '_linux.go'\ -e '_little.go'\ - -e '_nolinux.go'\ -e '_openbsd.go'\ -e '_others.go'\ -e '_test.go'\ -e '_unix.go'\ + -e '_v1.go'\ -e '_windows.go' \ -v\ | sed -e 's/./\t\0/' @@ -223,7 +223,7 @@ gocyclo --over 17 ./internal/dhcpd/ ./internal/dnsforward/\ # 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/updater/ ./internal/v1/ ./internal/version/ ./main.go\ ineffassign ./...