Compare commits
24 Commits
v0.108.0-b
...
v0.108.0-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65a33a1215 | ||
|
|
1a49d2f0c9 | ||
|
|
549b20bdea | ||
|
|
75f01d51f7 | ||
|
|
a82ec09afd | ||
|
|
c0ac82be6a | ||
|
|
24d7dc8e8a | ||
|
|
79d85a24e9 | ||
|
|
f289f4b1b6 | ||
|
|
58515fce43 | ||
|
|
21905d9869 | ||
|
|
a580149ad6 | ||
|
|
6dc9e73ce4 | ||
|
|
5d52e68d26 | ||
|
|
c4ff80fd3a | ||
|
|
ed449c6186 | ||
|
|
1c89394aef | ||
|
|
235316e050 | ||
|
|
0a1ff65b4a | ||
|
|
2a1ad532f4 | ||
|
|
9d144ecb0a | ||
|
|
9b7fe74086 | ||
|
|
82af43039c | ||
|
|
12ee287d0b |
1
.github/stale.yml
vendored
1
.github/stale.yml
vendored
@@ -8,6 +8,7 @@
|
||||
- 'documentation'
|
||||
- 'enhancement'
|
||||
- 'feature request'
|
||||
- 'help wanted'
|
||||
- 'localization'
|
||||
- 'needs investigation'
|
||||
- 'recurrent'
|
||||
|
||||
66
CHANGELOG.md
66
CHANGELOG.md
@@ -23,6 +23,12 @@ and this project adheres to
|
||||
|
||||
### Added
|
||||
|
||||
- Support for the final DNS-over-QUIC standard, [RFC 9250][rfc-9250] ([#4592]).
|
||||
- Support upstreams for subdomains of a domain only ([#4503]).
|
||||
- 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]).
|
||||
@@ -36,8 +42,11 @@ and this project adheres to
|
||||
|
||||
### Changed
|
||||
|
||||
- On OpenBSD, the daemon script now uses the recommended `/bin/ksh` shell
|
||||
instead of the `/bin/sh` one ([#4533]). To apply this change, backup your
|
||||
data and run `AdGuardHome -s uninstall && AdGuardHome -s install`.
|
||||
- The default DNS-over-QUIC port number is now `853` instead of `754` in
|
||||
accordance with the latest [RFC draft][doq-draft-10] ([#4276]).
|
||||
accordance with [RFC 9250][rfc-9250] ([#4276]).
|
||||
- Reverse DNS now has a greater priority as the source of runtime clients'
|
||||
information than ARP neighborhood.
|
||||
- Improved detection of runtime clients through more resilient ARP processing
|
||||
@@ -63,8 +72,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_clients`, 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,12 +122,26 @@ 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
|
||||
|
||||
- Query log occasionally going into an infinite loop ([#4591]).
|
||||
- Service startup on boot on systems using SysV-init ([#4480]).
|
||||
- Detection of the stopped service status on macOS and Linux ([#4273]).
|
||||
- Case-sensitive ClientID ([#4542]).
|
||||
- Slow version update queries making other HTTP APIs unresponsive ([#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
|
||||
[#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367
|
||||
[#3381]: https://github.com/AdguardTeam/AdGuardHome/issues/3381
|
||||
[#3503]: https://github.com/AdguardTeam/AdGuardHome/issues/3503
|
||||
@@ -100,10 +151,19 @@ In this release, the schema version has changed from 12 to 13.
|
||||
[#4213]: https://github.com/AdguardTeam/AdGuardHome/issues/4213
|
||||
[#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221
|
||||
[#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238
|
||||
[#4273]: https://github.com/AdguardTeam/AdGuardHome/issues/4273
|
||||
[#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276
|
||||
[#4480]: https://github.com/AdguardTeam/AdGuardHome/issues/4480
|
||||
[#4499]: https://github.com/AdguardTeam/AdGuardHome/issues/4499
|
||||
[#4503]: https://github.com/AdguardTeam/AdGuardHome/issues/4503
|
||||
[#4533]: https://github.com/AdguardTeam/AdGuardHome/issues/4533
|
||||
[#4542]: https://github.com/AdguardTeam/AdGuardHome/issues/4542
|
||||
[#4591]: https://github.com/AdguardTeam/AdGuardHome/issues/4591
|
||||
[#4592]: https://github.com/AdguardTeam/AdGuardHome/issues/4592
|
||||
|
||||
[rfc-9250]: https://datatracker.ietf.org/doc/html/rfc9250
|
||||
[ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html
|
||||
[repr]: https://reproducible-builds.org/docs/source-date-epoch/
|
||||
[doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2
|
||||
|
||||
|
||||
|
||||
|
||||
3
Makefile
3
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)'\
|
||||
|
||||
|
||||
@@ -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",
|
||||
@@ -85,7 +85,7 @@
|
||||
"form_enter_hostname": "Zadejte název hostitele",
|
||||
"error_details": "Podrobnosti chyby",
|
||||
"response_details": "Detail odpovědi",
|
||||
"request_details": "Detail požadavku",
|
||||
"request_details": "Detaily požadavku",
|
||||
"client_details": "Detaily klienta",
|
||||
"details": "Detaily",
|
||||
"back": "Zpět",
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Bootstrap DNS-palvelimet",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS-palvelimia käytetään ylävirroiksi määritettyjen DoH/DoT-resolvereiden IP-osoitteiden selvitykseen.",
|
||||
"local_ptr_title": "Yksityiset käänteiset DNS-palvelimet",
|
||||
"local_ptr_desc": "DNS-palvelimet, joita AdGuard Home käyttää paikallisille PTR-pyynnöille. Näitä palvelimia käytetään yksityistä IP-osoitetta käyttävien päätelaitteiden osoitteiden, kuten \"192.168.12.34\", selvitykseen käänteisen DNS:n avulla. Jos ei käytössä, käyttää AdGuard Home käyttöjärjestelmän oletusarvoisia DNS-resolvereita, poislukien AdGuard Homen omat osoitteet.",
|
||||
"local_ptr_desc": "DNS-palvelimet, joita AdGuard Home käyttää paikallisille PTR-kyselyille. Näitä palvelimia käytetään yksityistä IP-osoitetta käyttävien PTR-kyselyiden osoitteiden, kuten \"192.168.12.34\", selvitykseen käänteisen DNS:n avulla. Jos ei käytössä, AdGuard Home käyttää käyttöjärjestelmän oletusarvoisia DNS-resolvereita, poislukien AdGuard Homen omat osoitteet.",
|
||||
"local_ptr_default_resolver": "Oletusarvoisesti AdGuard Home käyttää seuraavia käänteisiä DNS-resolvereita: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home ei voinut määrittää tälle järjestelmälle sopivaa yksityistä käänteistä DNS-resolveria.",
|
||||
"local_ptr_placeholder": "Syötä yksi palvelimen osoite per rivi",
|
||||
@@ -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\".",
|
||||
@@ -351,7 +351,7 @@
|
||||
"install_devices_android_list_5": "Syötä \"DNS 1\" ja \"DNS 2\" -kenttiin AdGuard Home -palvelimesi osoitteet.",
|
||||
"install_devices_ios_list_1": "Napauta aloitusnäytöstä \"Asetukset\".",
|
||||
"install_devices_ios_list_2": "Valitse vasemmalta \"Wi-Fi\" (mobiiliverkolle ei ole mahdollista määrittää omaa DNS-palvelinta).",
|
||||
"install_devices_ios_list_3": "Valitse yhdistetty verkko.",
|
||||
"install_devices_ios_list_3": "Valitse tällä hetkellä aktiivinen verkko.",
|
||||
"install_devices_ios_list_4": "Syötä \"DNS\" -kenttään AdGuard Home -palvelimesi osoitteet.",
|
||||
"get_started": "Aloita",
|
||||
"next": "Seuraava",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Servidores DNS de inicialização",
|
||||
"bootstrap_dns_desc": "Servidores DNS de inicialização são usados para resolver endereços IP dos resolvedores DoH/DoT que você especifica como upstreams.",
|
||||
"local_ptr_title": "Servidores DNS reversos privados",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver os nomes de host de clientes com endereços IP privados, por exemplo \"192.168.12.34\", usando DNS reverso. Se não for definido, o AdGuard Home usa os endereços dos resolvedores DNS padrão do seu sistema operacional, exceto os endereços do AdGuard Home.",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver solicitações de PTR para endereços em intervalos de IP privados, por exemplo \"192.168.12.34\", usando DNS reverso. Se não estiver definido, o AdGuard Home usa os endereços dos resolvedores de DNS padrão do seu sistema operacional, exceto os endereços do próprio AdGuard Home.",
|
||||
"local_ptr_default_resolver": "Por padrão, o AdGuard Home usa os seguintes resolvedores de DNS reverso: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "A página inicial do AdGuard não conseguiu determinar resolvedores DNS reversos privados adequados para este sistema.",
|
||||
"local_ptr_placeholder": "Insira um endereço de servidor por linha",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Servidores DNS de arranque",
|
||||
"bootstrap_dns_desc": "Servidores DNS de inicialização são usados para resolver endereços IP dos resolvedores DoH/DoT que especifica como upstreams.",
|
||||
"local_ptr_title": "Servidores DNS reversos privados",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver os nomes de host de clientes com endereços IP privados, por exemplo \"192.168.12.34\", usando DNS reverso. Se não for definido, o AdGuard Home usa os endereços dos resolvedores DNS padrão do seu sistema operacional, exceto os endereços do AdGuard Home.",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver solicitações de PTR para endereços em intervalos de IP privados, por exemplo \"192.168.12.34\", usando DNS reverso. Se não estiver definido, o AdGuard Home usa os endereços dos resolvedores de DNS padrão do seu sistema operacional, exceto os endereços do próprio AdGuard Home.",
|
||||
"local_ptr_default_resolver": "Por predefinição, o AdGuard Home usa os seguintes resolvedores de DNS reverso: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "A página inicial do AdGuard não conseguiu determinar resolvedores DNS reversos privados adequados para este sistema.",
|
||||
"local_ptr_placeholder": "Insira um endereço de servidor por linha",
|
||||
|
||||
@@ -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</0> criptat;",
|
||||
"example_upstream_doh": "<0>DNS-over-HTTPS</0> criptat;",
|
||||
"example_upstream_doq": "<0>DNS-over-QUIC</0> criptat (experimental);",
|
||||
"example_upstream_sdns": "<0>DNS Stamps</0> pentru <1>DNSCrypt</1> sau rezolvere <2>DNS-over-HTTPS</2>;",
|
||||
"example_upstream_sdns": "<0>DNS Stamps</0> pentru <1>DNSCrypt</1> sau rezolvatori <2>DNS-over-HTTPS</2>;",
|
||||
"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",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Zagonski DNS strežniki",
|
||||
"bootstrap_dns_desc": "Zagonski DNS strežniki se uporabljajo za razreševanje IP naslovov DoH/DoT reševalcev, ki jih določite kot navzgornje.",
|
||||
"local_ptr_title": "Zasebni povratni strežniki DNS",
|
||||
"local_ptr_desc": "Strežniki DNS, ki jih AdGuard Home uporablja za lokalne poizvedbe PTR. Ti strežniki se uporabljajo za razreševanje imen gostiteljev z zasebnimi naslovi IP, na primer \"192.168.12.34\" uporablja DNS. Če ni nastavljen, uporablja naslove privzetih razreševalnikov DNS vašega OS, razen naslovov samega AdGuard Home.",
|
||||
"local_ptr_desc": "Strežniki DNS, ki jih AdGuard Home uporablja za lokalne PTR poizvedbe. Ti strežniki se uporabljajo za reševanje zahtev PTR za naslove v zasebnih obsegih IP, na primer \"192.168.12.34\", z uporabo obratnega DNS. Če ni nastavljen, AdGuard Home uporablja naslove privzetih razreševalnikov DNS vašega OS, razen naslovov samega AdGuard Home.",
|
||||
"local_ptr_default_resolver": "AdGuard Home privzeto uporablja te povratne razreševalnike DNS: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home ni mogel določiti ustreznih zasebnih povratnih reševalcev DNS za ta sistem.",
|
||||
"local_ptr_placeholder": "V vrstico vnesite en naslov strežnika",
|
||||
@@ -351,7 +351,7 @@
|
||||
"install_devices_android_list_5": "Spremeni nastavitev vrednosti DNS 1 in DNS 2 na naslove strežnikov AdGuard Home.",
|
||||
"install_devices_ios_list_1": "Na začetnem zaslonu izberite Nastavitve.",
|
||||
"install_devices_ios_list_2": "V levem meniju izberite Wi-Fi (nemogoče je konfigurirati DNS za mobilna omrežja).",
|
||||
"install_devices_ios_list_3": "Dotaknite se imena trenutno aktivnega omrežja.",
|
||||
"install_devices_ios_list_3": "Tapnite na ime trenutno aktivnega omrežja.",
|
||||
"install_devices_ios_list_4": "V polje DNS vnesite vaše naslove AdGuard Home strežnika.",
|
||||
"get_started": "Začnimo",
|
||||
"next": "Naprej",
|
||||
|
||||
@@ -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</0>",
|
||||
"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ı",
|
||||
@@ -336,22 +336,22 @@
|
||||
"install_devices_router_list_4": "Bazı yönlendirici türlerinde özel bir DNS sunucusu ayarlanamaz. Bu durumda, AdGuard Home'u <0>DHCP sunucusu</0> olarak ayarlamak yardımcı olabilir. Aksi takdirde, yönlendirici modeliniz için DNS sunucularını nasıl ayarlayacağınız konusunda yönlendirici kılavuzuna bakmalısınız.",
|
||||
"install_devices_windows_list_1": "Başlat menüsünden veya Windows araması aracılığıyla Denetim Masası'nı açın.",
|
||||
"install_devices_windows_list_2": "Ağ ve İnternet kategorisine girin ve ardından Ağ ve Paylaşım Merkezi'ne girin.",
|
||||
"install_devices_windows_list_3": "Sol panelde \"Bağdaştırıcı ayarlarını değiştirin'e\" tıklayın.",
|
||||
"install_devices_windows_list_3": "Sol panelde \"Bağdaştırıcı ayarlarını değiştirin\" öğesine tıklayın.",
|
||||
"install_devices_windows_list_4": "Kullandığınız aktif bağlantının üzerine sağ tıklayın ve Özellikler öğesine tıklayın.",
|
||||
"install_devices_windows_list_5": "Listede \"İnternet Protokolü Sürüm 4 (TCP/IPv4)\" (veya IPv6 için \"İnternet Protokolü Sürüm 6 (TCP/IPv6)\") öğesini bulun, seçin ve ardından tekrar Özellikler'e tıklayın.",
|
||||
"install_devices_windows_list_5": "Listede \"İnternet Protokolü Sürüm 4 (TCP/IPv4)\" (veya IPv6 için \"İnternet Protokolü Sürüm 6 (TCP/IPv6)\") öğesini bulun, seçin ve ardından tekrar Özellikler öğesine tıklayın.",
|
||||
"install_devices_windows_list_6": "\"Aşağıdaki DNS sunucu adreslerini kullan\"ı seçin ve AdGuard Home sunucu adreslerinizi girin.",
|
||||
"install_devices_macos_list_1": "Apple simgesine tıklayın ve Sistem Tercihleri'ne gidin.",
|
||||
"install_devices_macos_list_2": "Ağ'a tıklayın.",
|
||||
"install_devices_macos_list_1": "Apple simgesine tıklayın ve Sistem Tercihleri öğesine gidin.",
|
||||
"install_devices_macos_list_2": "Ağ öğesine tıklayın.",
|
||||
"install_devices_macos_list_3": "Listedeki ilk bağlantıyı seçin ve Gelişmiş öğesine tıklayın.",
|
||||
"install_devices_macos_list_4": "DNS sekmesini seçin ve AdGuard Home sunucunuzun adreslerini girin.",
|
||||
"install_devices_android_list_1": "Android Menüsü ana ekranından Ayarlar'a dokunun.",
|
||||
"install_devices_android_list_2": "Menüde bulunan Wi-Fi seçeneğine dokunun. Mevcut tüm ağlar listelenecektir (mobil ağlar için özel DNS sunucusu ayarlanamaz).",
|
||||
"install_devices_android_list_2": "Menüde bulunan Wi-Fi öğesine dokunun. Mevcut tüm ağlar listelenecektir (mobil ağlar için özel DNS sunucusu ayarlanamaz).",
|
||||
"install_devices_android_list_3": "Bağlı olduğunuz ağın üzerine basılı tutun ve Ağı Değiştir'e dokunun.",
|
||||
"install_devices_android_list_4": "Bazı cihazlarda, diğer ayarları görmek için \"Gelişmiş\" seçeneğini seçmeniz gerekebilir. Android DNS ayarlarınızı yapmak için IP ayarlarını DHCP modundan Statik moda almanız gerekecektir.",
|
||||
"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",
|
||||
@@ -453,7 +453,7 @@
|
||||
"setup_dns_privacy_2": "<0>DNS-over-HTTPS:</0> <1>{{address}}</1> dizesini kullan.",
|
||||
"setup_dns_privacy_3": "<0>İşte, kullanabileceğiniz yazılımların bir listesi.</0>",
|
||||
"setup_dns_privacy_4": "Bir iOS 14 veya macOS Big Sur cihazında, DNS ayarlarına <highlight>DNS-over-HTTPS</highlight> veya <highlight>DNS-over-TLS</highlight> sunucuları ekleyen özel '.mobileconfig' dosyasını indirebilirsiniz.",
|
||||
"setup_dns_privacy_android_1": "Android 9, yerel olarak DNS-over-TLS protokolünü destekler. Yapılandırmak için Ayarlar → Ağ ve İnternet → Gelişmiş → Özel DNS seçeneğine gidin ve alan adınızı girin.",
|
||||
"setup_dns_privacy_android_1": "Android 9, yerel olarak DNS-over-TLS protokolünü destekler. Yapılandırmak için Ayarlar → Ağ ve İnternet → Gelişmiş → Özel DNS öğesine gidin ve alan adınızı girin.",
|
||||
"setup_dns_privacy_android_2": "<0>Android için AdGuard</0>, <1>DNS-over-HTTPS</1> ve <1>DNS-over-TLS</1> protokolünü destekler.",
|
||||
"setup_dns_privacy_android_3": "<0>Intra</0> Android'e <1>DNS-over-HTTPS</1> protokol desteğini ekler.",
|
||||
"setup_dns_privacy_ios_1": "<0>DNSCloak</0>, <1>DNS-over-HTTPS</1> protokolünü destekler, ancak kendi sunucunuzu kullanacak şekilde yapılandırmak için bir <2>DNS Damgası</2> oluşturmanız gerekir.",
|
||||
@@ -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",
|
||||
|
||||
@@ -7,16 +7,16 @@
|
||||
"load_balancing": "Балансування навантаження",
|
||||
"load_balancing_desc": "Запитувати один сервер за раз. AdGuard Home використовуватиме зважений випадковий алгоритм для вибору сервера, щоб найшвидший сервер використовувався частіше.",
|
||||
"bootstrap_dns": "Bootstrap DNS-сервери",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS-сервери використовуються для пошуку IP-адреси DoH/DoT серверів, які ви встановили.",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS-сервери використовуються для вирішення IP-адрес встановлених серверів DoH/DoT.",
|
||||
"local_ptr_title": "Приватні сервери для зворотного DNS",
|
||||
"local_ptr_desc": "DNS-сервери, які AdGuard Home використовує для локальних PTR-запитів. Ці сервери, використовуючи rDNS, використовуються для отримання доменних імен клієнтів у приватних мережах, наприклад, «192.168.12.34». Якщо список порожній, буде використовуватись системний DNS-сервер.",
|
||||
"local_ptr_default_resolver": "AdGuard Home усталено використовує такі зворотні DNS-резолвери: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home не зміг визначити приватні реверсивні DNS-резолвери, що були б придатними для цієї системи.",
|
||||
"local_ptr_desc": "DNS-сервери, які AdGuard Home використовує для локальних PTR-запитів. Ці сервери використовуються для вирішення PTR-запитів для адрес у приватних мережах, наприклад, «192.168.12.34». Якщо список порожній, AdGuard Home буде усталено використовувати системний DNS-сервер.",
|
||||
"local_ptr_default_resolver": "Стандартно AdGuard Home користується такими зворотними DNS-вирішувачами: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home не зміг визначити приватні зворотні DNS-вирішувачі, які підійшли б для цієї системи.",
|
||||
"local_ptr_placeholder": "Вводьте одну адресу на рядок",
|
||||
"resolve_clients_title": "Увімкнути запитування доменних імен для IP-адрес клієнтів",
|
||||
"resolve_clients_title": "Увімкнути зворотне вирішення IP-адрес клієнтів",
|
||||
"resolve_clients_desc": "Визначати доменні імена клієнтів за допомогою PTR-запитів до відповідних серверів — приватних DNS-серверів для локальних клієнтів та upstream-серверів для клієнтів з публічними IP-адресами.",
|
||||
"use_private_ptr_resolvers_title": "Використовувати приватні зворотні DNS-резолвери",
|
||||
"use_private_ptr_resolvers_desc": "Надсилати зворотні DNS-запити до вказаних серверів для клієнтів, що обслуговуються локально. Якщо вимкнено, AdGuard Home буде відповідати NXDOMAIN на всі такі PTR-запити, окрім запитів про клієнтів, що уже відомі по DHCP, /etc/hosts тощо.",
|
||||
"use_private_ptr_resolvers_desc": "Надсилати зворотні DNS-запити до вказаних серверів для клієнтів, що обслуговуються локально. Якщо вимкнено, AdGuard Home буде відповідати NXDOMAIN на всі такі PTR-запити, окрім запитів про клієнтів, що уже відомі завдяки DHCP, /etc/hosts тощо.",
|
||||
"check_dhcp_servers": "Перевірити DHCP-сервери",
|
||||
"save_config": "Зберегти конфігурацію",
|
||||
"enabled_dhcp": "DHCP-сервер увімкнено",
|
||||
@@ -60,12 +60,12 @@
|
||||
"dhcp_form_range_end": "Кінець діапазону",
|
||||
"dhcp_form_lease_title": "Час оренди DHCP (в секундах)",
|
||||
"dhcp_form_lease_input": "Тривалість оренди",
|
||||
"dhcp_interface_select": "Оберіть інтерфейс DHCP",
|
||||
"dhcp_interface_select": "Вибрати DHCP-інтерфейс",
|
||||
"dhcp_hardware_address": "Апаратна адреса",
|
||||
"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-адресу вручну.",
|
||||
@@ -117,11 +117,11 @@
|
||||
"stats_adult": "Заблоковано вебсайтів для дорослих",
|
||||
"stats_query_domain": "Найчастіші запити доменів",
|
||||
"for_last_24_hours": "за останні 24 години",
|
||||
"for_last_days": "за останній день",
|
||||
"for_last_days": "за останній {{count}} день",
|
||||
"for_last_days_plural": "за останні {{count}} днів",
|
||||
"stats_disabled": "Статистику вимкнено. Ви можете увімкнути її на <0>сторінці налаштувань</0>.",
|
||||
"stats_disabled_short": "Статистику вимкнено",
|
||||
"no_domains_found": "Доменів не знайдено",
|
||||
"no_domains_found": "Не знайдено жодного домену",
|
||||
"requests_count": "Кількість запитів",
|
||||
"top_blocked_domains": "Найчастіше блоковані домени",
|
||||
"top_clients": "Найактивніші клієнти",
|
||||
@@ -131,21 +131,21 @@
|
||||
"number_of_dns_query_days_plural": "Кількість DNS-запитів, оброблених за останні {{count}} днів",
|
||||
"number_of_dns_query_24_hours": "Кількість DNS-запитів, оброблених за останні 24 години",
|
||||
"number_of_dns_query_blocked_24_hours": "Кількість DNS-запитів, заблокованих фільтрами і списками блокування hosts",
|
||||
"number_of_dns_query_blocked_24_hours_by_sec": "Кількість DNS-запитів, заблокованих модулем безпеки перегляду AdGuard",
|
||||
"number_of_dns_query_blocked_24_hours_by_sec": "Кількість DNS-запитів, заблокованих модулем «Безпека перегляду» AdGuard",
|
||||
"number_of_dns_query_blocked_24_hours_adult": "Кількість заблокованих вебсайтів для дорослих",
|
||||
"enforced_save_search": "Примусовий безпечний пошук",
|
||||
"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": "Ви можете налаштувати правила блокування в розділі <a>Фільтри</a>.",
|
||||
"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_browsing_sec": "Використовувати вебслужбу «Безпека перегляду» AdGuard",
|
||||
"use_adguard_browsing_sec_hint": "AdGuard Home перевірятиме, чи підлягає домен блокуванню завдяки вебслужбі «Безпека перегляду». Для перевірки буде використано безпечний API — на сервер надсилається лише короткий префікс хешу SHA256 доменного імені.",
|
||||
"use_adguard_parental": "Використовувати вебслужбу «Батьківський контроль» AdGuard",
|
||||
"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,15 +158,15 @@
|
||||
"upstream_dns": "Upstream DNS-сервери",
|
||||
"upstream_dns_help": "Введіть адреси серверів по одній на рядок. <a>Докладніше</a> про налаштування DNS-серверів.",
|
||||
"upstream_dns_configured_in_file": "Налаштовано в {{path}}",
|
||||
"test_upstream_btn": "Тест upstream серверів",
|
||||
"test_upstream_btn": "Перевірити сервери",
|
||||
"upstreams": "Upstreams",
|
||||
"apply_btn": "Застосувати",
|
||||
"disabled_filtering_toast": "Фільтрування вимкнено",
|
||||
"enabled_filtering_toast": "Фільтрування увімкнено",
|
||||
"disabled_safe_browsing_toast": "Безпечний перегляд вимкнено",
|
||||
"enabled_safe_browsing_toast": "Безпечний перегляд увімкнено",
|
||||
"disabled_parental_toast": "Батьківський контроль вимкнено",
|
||||
"enabled_parental_toast": "Батьківський контроль увімкнено",
|
||||
"disabled_parental_toast": "«Батьківський контроль» вимкнено",
|
||||
"enabled_parental_toast": "«Батьківський контроль» увімкнено",
|
||||
"disabled_safe_search_toast": "Безпечний пошук вимкнено",
|
||||
"enabled_save_search_toast": "Безпечний пошук увімкнено",
|
||||
"enabled_table_header": "Увімкнено",
|
||||
@@ -193,7 +193,7 @@
|
||||
"edit_blocklist": "Змінити список блокування",
|
||||
"edit_allowlist": "Змінити список дозволів",
|
||||
"choose_blocklist": "Виберіть списки блокування",
|
||||
"choose_allowlist": "Обрати списки дозволених сайтів",
|
||||
"choose_allowlist": "Виберіть списки дозволів",
|
||||
"enter_valid_blocklist": "Введіть дійсну URL-адресу в список блокування.",
|
||||
"enter_valid_allowlist": "Введіть дійсну URL-адресу в список дозволів.",
|
||||
"form_error_url_format": "Неправильний формат URL",
|
||||
@@ -214,7 +214,7 @@
|
||||
"example_upstream_dot": "зашифрований <0>DNS-over-TLS</0>;",
|
||||
"example_upstream_doh": "зашифрований <0>DNS-over-HTTPS</0>;",
|
||||
"example_upstream_doq": "зашифрований <0>DNS-over-QUIC</0> (експериментальний);",
|
||||
"example_upstream_sdns": "<0>DNS Stamps</0> для <1>DNSCrypt</1> або <2>DNS-over-HTTPS</2> серверів;",
|
||||
"example_upstream_sdns": "<0>DNS Stamps</0> для <1>DNSCrypt-</1> або <2>DNS-over-HTTPS-</2>вирішувачів;",
|
||||
"example_upstream_tcp": "звичайний DNS (через TCP);",
|
||||
"example_upstream_tcp_hostname": "звичайний DNS (поверх TCP, з назвою вузла);",
|
||||
"all_lists_up_to_date_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-сервера</0>. В іншому разі вам потрібно знайти інструкцію щодо налаштування 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.",
|
||||
@@ -351,7 +351,7 @@
|
||||
"install_devices_android_list_5": "Змініть встановлені значення DNS 1 і DNS 2 на адреси вашого домашнього сервера AdGuard.",
|
||||
"install_devices_ios_list_1": "На головному екрані торкніться Налаштування.",
|
||||
"install_devices_ios_list_2": "Виберіть Wi-Fi у меню ліворуч (неможливо налаштувати DNS для мобільних мереж).",
|
||||
"install_devices_ios_list_3": "Натисніть на назву поточно активної мережі.",
|
||||
"install_devices_ios_list_3": "Натисніть на назву поточної активної мережі.",
|
||||
"install_devices_ios_list_4": "У полі DNS введіть адреси вашого сервера AdGuard Home.",
|
||||
"get_started": "Розпочати",
|
||||
"next": "Наступні",
|
||||
@@ -372,10 +372,10 @@
|
||||
"encryption_doq": "Порт DNS-over-QUIC (експериментальний)",
|
||||
"encryption_doq_desc": "Якщо цей порт налаштовано, AdGuard Home запустить на цьому порту сервер DNS-over-QUIC. Це експериментально і може бути ненадійним. Крім того, зараз не так багато клієнтів, які це підтримують.",
|
||||
"encryption_certificates": "Сертифікати",
|
||||
"encryption_certificates_desc": "Для використання шифрування потрібно надати дійсний ланцюжок сертифікатів SSL для вашого домену. Ви можете отримати безкоштовний сертифікат на <0>{{link}}</0> або придбати його в одному з надійних Центрів Сертифікації.",
|
||||
"encryption_certificates_desc": "Для використання шифрування потрібно надати дійсний ланцюжок сертифікатів SSL для вашого домену. Ви можете отримати безплатний сертифікат на <0>{{link}}</0> або придбати його в одному з надійних Центрів Сертифікації.",
|
||||
"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)",
|
||||
@@ -552,16 +552,16 @@
|
||||
"fastest_addr": "Найшвидша IP-адреса",
|
||||
"fastest_addr_desc": "Опитати всі DNS-сервери й повернути найшвидшу IP-адресу серед усіх наданих. Це сповільнить швидкість DNS-запитів, оскільки AdGuard Home повинен буде чекати відповіді усіх DNS-серверів, але водночас може покращити якість з'єднання.",
|
||||
"autofix_warning_text": "Якщо ви натиснете «Виправити», AdGuard Home налаштує вашу систему на використання DNS-сервера AdGuard Home.",
|
||||
"autofix_warning_list": "Це виконає наступні завдання: <0>Деактивує систему DNSStubListener</0> <0>Змінить адресу DNS сервера на 127.0.0.1</0> <0>Замінить символічне посилання /etc/resolv.conf на /run/systemd/resolve/resolv.conf</0> <0>Зупинить DNSStubListener (перезапустить сервіс systemd-resolved)</0>",
|
||||
"autofix_warning_list": "Будуть виконані такі дії: <0>Деактивація системи DNSStubListener</0> <0>Зміна адреси DNS-сервера на «127.0.0.1»</0> <0>Заміна символічного посилання «/etc/resolv.conf» на «/run/systemd/resolve/resolv.conf»</0> <0>Зупинка DNSStubListener (перезапуск системної служби systemd-resolved)</0>",
|
||||
"autofix_warning_result": "В результаті буде усталено, що усі DNS-запити вашої системи будуть опрацьовані AdGuard Home.",
|
||||
"tags_title": "Теги",
|
||||
"tags_desc": "Ви можете вибрати теги, які відповідають клієнту. Теги можна використати в правилах фільтрування, щоб точніше застосовувати їх. <0>Докладніше</0>.",
|
||||
"form_select_tags": "Виберіть теги клієнта",
|
||||
"check_title": "Перевірте фільтрування",
|
||||
"check_title": "Перевірити фільтрування",
|
||||
"check_desc": "Перевірити чи фільтрується назва вузла.",
|
||||
"check": "Перевірити",
|
||||
"form_enter_host": "Введіть назву вузла",
|
||||
"filtered_custom_rules": "Відфільтровано за власними правилами фільтрування",
|
||||
"filtered_custom_rules": "Відфільтровано завдяки власним правилам фільтрування",
|
||||
"choose_from_list": "Виберіть зі списку",
|
||||
"add_custom_list": "Додати власний список",
|
||||
"host_whitelisted": "Вузол додано до списку дозволів",
|
||||
@@ -585,14 +585,14 @@
|
||||
"list_updated": "{{count}} список оновлено",
|
||||
"list_updated_plural": "{{count}} списки оновлено",
|
||||
"dnssec_enable": "Увімкнути DNSSEC",
|
||||
"dnssec_enable_desc": "Встановити прапорець DNSSEC для вихідних DNS запитів та перевірити результат (потрібен розпізнавач з підтримкою DNSSEC).",
|
||||
"dnssec_enable_desc": "Увімкнути DNSSEC для вихідних DNS-запитів та перевірити результат (потрібен вирішувач з підтримкою DNSSEC).",
|
||||
"validated_with_dnssec": "Засвідчено DNSSEC",
|
||||
"all_queries": "Усі запити",
|
||||
"show_blocked_responses": "Заблоковані",
|
||||
"show_whitelisted_responses": "Дозволені",
|
||||
"show_processed_responses": "Оброблені",
|
||||
"blocked_safebrowsing": "Заблоковано Безпечним переглядом",
|
||||
"blocked_adult_websites": "Заблоковано Батьківським контролем",
|
||||
"blocked_adult_websites": "Заблоковано «Батьківським контролем»",
|
||||
"blocked_threats": "Заблоковано загроз",
|
||||
"allowed": "Дозволено",
|
||||
"filtered": "Відфільтровано",
|
||||
|
||||
@@ -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,22 +335,22 @@
|
||||
"install_devices_router_list_3": "请在此处输入您的 AdGuard Home 服务器地址。",
|
||||
"install_devices_router_list_4": "在某些类型的路由器上无法设置自定义 DNS 服务器。在此情况下将 AdGuard Home 设置为 <0>DHCP 服务器</0>,可能会有所帮助。否则您应该查找如何根据特定路由器型号设置 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_1": "从主屏幕中点击「设置」。",
|
||||
"install_devices_ios_list_2": "从左侧目录中选择「无线局域网」(移动数据网络环境下不支持修改 DNS )。",
|
||||
"install_devices_ios_list_3": "点击当前已连接网络的名称。",
|
||||
"install_devices_ios_list_4": "在 DNS 字段中输入您的 AdGuard Home 服务器地址。",
|
||||
"get_started": "开始配置",
|
||||
|
||||
@@ -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": "每行輸入一個伺服器位址",
|
||||
|
||||
@@ -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 <div className='logs__table' role='grid'>
|
||||
{loading && <Loading />}
|
||||
<Header />
|
||||
{isNothingFound
|
||||
? <label className="logs__no-data">{t('nothing_found')}</label>
|
||||
: <>{items.map(renderRow)}
|
||||
{!isEntireLog && <div ref={loader} className="logs__loading text-center">{t('loading_table_status')}</div>}
|
||||
</>}
|
||||
</div>;
|
||||
return (
|
||||
<div className="logs__table" role="grid">
|
||||
{loading && <Loading />}
|
||||
<Header />
|
||||
{isNothingFound ? (
|
||||
<label className="logs__no-data">{t('nothing_found')}</label>
|
||||
) : (
|
||||
<>
|
||||
{items.map(renderRow)}
|
||||
{!isEntireLog && (
|
||||
<div ref={loader} className="logs__loading text-center">
|
||||
{t('loading_table_status')}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
InfiniteTable.propTypes = {
|
||||
|
||||
@@ -152,6 +152,16 @@ const Logs = () => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!history.location.search) {
|
||||
(async () => {
|
||||
setIsLoading(true);
|
||||
await dispatch(setFilteredLogs());
|
||||
setIsLoading(false);
|
||||
})();
|
||||
}
|
||||
}, [history.location.search]);
|
||||
|
||||
const renderPage = () => <>
|
||||
<Filters
|
||||
filter={{
|
||||
|
||||
@@ -81,8 +81,8 @@
|
||||
"urlhaus-filter-online": {
|
||||
"name": "Online Malicious URL Blocklist",
|
||||
"categoryId": "security",
|
||||
"homepage": "https://gitlab.com/curben/urlhaus-filter",
|
||||
"source": "https://curben.gitlab.io/malware-filter/urlhaus-filter-agh-online.txt"
|
||||
"homepage": "https://gitlab.com/malware-filter/urlhaus-filter",
|
||||
"source": "https://malware-filter.gitlab.io/malware-filter/urlhaus-filter-agh-online.txt"
|
||||
},
|
||||
"dandelion-sprouts-anti-malware-list": {
|
||||
"name": "Dandelion Sprout's Anti-Malware List",
|
||||
|
||||
@@ -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 = (
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import whotracksmeDb from './whotracksme.json';
|
||||
import whotracksmeWebsites from './whotracksme_web.json';
|
||||
import adguardDb from './adguard.json';
|
||||
import { REPOSITORY } from '../constants';
|
||||
|
||||
@@ -20,6 +21,22 @@ export const sources = {
|
||||
ADGUARD: 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets link to tracker page on whotracks.me.
|
||||
*
|
||||
* @param trackerId
|
||||
* @return {string}
|
||||
*/
|
||||
const getWhotracksmeUrl = (trackerId) => {
|
||||
const websiteId = whotracksmeWebsites.websites[trackerId];
|
||||
if (websiteId) {
|
||||
// Overrides links to websites.
|
||||
return `https://whotracks.me/websites/${websiteId}.html`;
|
||||
}
|
||||
|
||||
return `https://whotracks.me/trackers/${trackerId}.html`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the source metadata for the specified tracker
|
||||
* @param {TrackerData} trackerData tracker data
|
||||
@@ -33,7 +50,7 @@ export const getSourceData = (trackerData) => {
|
||||
if (trackerData.source === sources.WHOTRACKSME) {
|
||||
return {
|
||||
name: 'Whotracks.me',
|
||||
url: `https://whotracks.me/trackers/${trackerData.id}.html`,
|
||||
url: getWhotracksmeUrl(trackerData.id),
|
||||
};
|
||||
}
|
||||
if (trackerData.source === sources.ADGUARD) {
|
||||
|
||||
6
client/src/helpers/trackers/whotracksme_web.json
Normal file
6
client/src/helpers/trackers/whotracksme_web.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"timeUpdated": "2021-12-19T13:50:00.512Z",
|
||||
"websites": {
|
||||
"netflix": "netflix.com"
|
||||
}
|
||||
}
|
||||
15
go.mod
15
go.mod
@@ -3,20 +3,21 @@ module github.com/AdguardTeam/AdGuardHome
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/dnsproxy v0.42.1
|
||||
github.com/AdguardTeam/dnsproxy v0.43.0
|
||||
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/dimfeld/httptreemux/v5 v5.4.0
|
||||
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
|
||||
github.com/google/renameio v1.0.1
|
||||
github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41
|
||||
github.com/kardianos/service v1.2.1
|
||||
github.com/lucas-clemente/quic-go v0.26.0
|
||||
github.com/lucas-clemente/quic-go v0.27.1
|
||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
|
||||
github.com/mdlayher/netlink v1.6.0
|
||||
// TODO(a.garipov): This package is deprecated; find a new one or use
|
||||
@@ -28,8 +29,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 +58,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
|
||||
|
||||
33
go.sum
33
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.43.0 h1:K082nx37DaNqSyT3kDtAfgBACNWc+ZDI1Yr/kGppu1k=
|
||||
github.com/AdguardTeam/dnsproxy v0.43.0/go.mod h1:JUGTm5dmlll47JltztsT0N//pVJjdg6zu0SNeUeaA7g=
|
||||
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=
|
||||
@@ -52,14 +52,17 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/digineo/go-ipset/v2 v2.2.1 h1:k6skY+0fMqeUjjeWO/m5OuWPSZUAn7AucHMnQ1MX77g=
|
||||
github.com/digineo/go-ipset/v2 v2.2.1/go.mod h1:wBsNzJlZlABHUITkesrggFnZQtgW5wkqw1uo8Qxe0VU=
|
||||
github.com/dimfeld/httptreemux/v5 v5.4.0 h1:IiHYEjh+A7pYbhWyjmGnj5HZK6gpOOvyBXCJ+BE8/Gs=
|
||||
github.com/dimfeld/httptreemux/v5 v5.4.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.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=
|
||||
@@ -140,21 +143,15 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg=
|
||||
github.com/lucas-clemente/quic-go v0.26.0 h1:ALBQXr9UJ8A1LyzvceX4jd9QFsHvlI0RR6BkV16o00A=
|
||||
github.com/lucas-clemente/quic-go v0.26.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
|
||||
github.com/lucas-clemente/quic-go v0.27.1 h1:sOw+4kFSVrdWOYmUjufQ9GBVPqZ+tu+jMtXxXNmRJyk=
|
||||
github.com/lucas-clemente/quic-go v0.27.1/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWChPSI4+hgW7jc=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.0/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
@@ -292,8 +289,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 +327,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 +388,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 +415,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=
|
||||
|
||||
@@ -13,19 +13,24 @@ import (
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
)
|
||||
|
||||
func newARPDB() *cmdARPDB {
|
||||
func newARPDB() (arp *cmdARPDB) {
|
||||
return &cmdARPDB{
|
||||
parse: parseArpA,
|
||||
ns: &neighs{
|
||||
mu: &sync.RWMutex{},
|
||||
ns: make([]Neighbor, 0),
|
||||
},
|
||||
cmd: "arp",
|
||||
args: []string{"-a"},
|
||||
cmd: "arp",
|
||||
// Use -n flag to avoid resolving the hostnames of the neighbors. By
|
||||
// default ARP attempts to resolve the hostnames via DNS. See man 8
|
||||
// arp.
|
||||
//
|
||||
// See also https://github.com/AdguardTeam/AdGuardHome/issues/3157.
|
||||
args: []string{"-a", "-n"},
|
||||
}
|
||||
}
|
||||
|
||||
// parseArpA parses the output of the "arp -a" command on macOS and FreeBSD.
|
||||
// parseArpA parses the output of the "arp -a -n" command on macOS and FreeBSD.
|
||||
// The expected input format:
|
||||
//
|
||||
// host.name (192.168.0.1) at ff:ff:ff:ff:ff:ff on en0 ifscope [ethernet]
|
||||
|
||||
@@ -38,12 +38,17 @@ func newARPDB() (arp *arpdbs) {
|
||||
fsys: rootDirFS,
|
||||
filename: "proc/net/arp",
|
||||
},
|
||||
// Then, try "arp -a".
|
||||
// Then, try "arp -a -n".
|
||||
&cmdARPDB{
|
||||
parse: parseF,
|
||||
ns: ns,
|
||||
cmd: "arp",
|
||||
args: []string{"-a"},
|
||||
// Use -n flag to avoid resolving the hostnames of the neighbors.
|
||||
// By default ARP attempts to resolve the hostnames via DNS. See
|
||||
// man 8 arp.
|
||||
//
|
||||
// See also https://github.com/AdguardTeam/AdGuardHome/issues/3157.
|
||||
args: []string{"-a", "-n"},
|
||||
},
|
||||
// Finally, try "ip neigh".
|
||||
&cmdARPDB{
|
||||
@@ -109,11 +114,11 @@ func (arp *fsysARPDB) Neighbors() (ns []Neighbor) {
|
||||
return arp.ns.clone()
|
||||
}
|
||||
|
||||
// parseArpAWrt parses the output of the "arp -a" command on OpenWrt. The
|
||||
// parseArpAWrt parses the output of the "arp -a -n" command on OpenWrt. The
|
||||
// expected input format:
|
||||
//
|
||||
// IP address HW type Flags HW address Mask Device
|
||||
// 192.168.11.98 0x1 0x2 5a:92:df:a9:7e:28 * wan
|
||||
// IP address HW type Flags HW address Mask Device
|
||||
// 192.168.11.98 0x1 0x2 5a:92:df:a9:7e:28 * wan
|
||||
//
|
||||
func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
|
||||
if !sc.Scan() {
|
||||
@@ -153,8 +158,8 @@ func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
|
||||
return ns
|
||||
}
|
||||
|
||||
// parseArpA parses the output of the "arp -a" command on Linux. The expected
|
||||
// input format:
|
||||
// parseArpA parses the output of the "arp -a -n" command on Linux. The
|
||||
// expected input format:
|
||||
//
|
||||
// hostname (192.168.1.1) at ab:cd:ef:ab:cd:ef [ether] on enp0s3
|
||||
//
|
||||
|
||||
@@ -12,20 +12,25 @@ import (
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
|
||||
func newARPDB() *cmdARPDB {
|
||||
func newARPDB() (arp *cmdARPDB) {
|
||||
return &cmdARPDB{
|
||||
parse: parseArpA,
|
||||
ns: &neighs{
|
||||
mu: &sync.RWMutex{},
|
||||
ns: make([]Neighbor, 0),
|
||||
},
|
||||
cmd: "arp",
|
||||
args: []string{"-a"},
|
||||
cmd: "arp",
|
||||
// Use -n flag to avoid resolving the hostnames of the neighbors. By
|
||||
// default ARP attempts to resolve the hostnames via DNS. See man 8
|
||||
// arp.
|
||||
//
|
||||
// See also https://github.com/AdguardTeam/AdGuardHome/issues/3157.
|
||||
args: []string{"-a", "-n"},
|
||||
}
|
||||
}
|
||||
|
||||
// parseArpA parses the output of the "arp -a" command on OpenBSD. The expected
|
||||
// input format:
|
||||
// parseArpA parses the output of the "arp -a -n" command on OpenBSD. The
|
||||
// expected input format:
|
||||
//
|
||||
// Host Ethernet Address Netif Expire Flags
|
||||
// 192.168.1.1 ab:cd:ef:ab:cd:ef em0 19m59s
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
func newARPDB() *cmdARPDB {
|
||||
func newARPDB() (arp *cmdARPDB) {
|
||||
return &cmdARPDB{
|
||||
parse: parseArpA,
|
||||
ns: &neighs{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
//go:build darwin || freebsd || openbsd
|
||||
// +build darwin freebsd openbsd
|
||||
|
||||
package aghnet
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
27
internal/aghos/os_unix.go
Normal file
27
internal/aghos/os_unix.go
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func clientIDFromClientServerName(
|
||||
return "", err
|
||||
}
|
||||
|
||||
return clientID, nil
|
||||
return strings.ToLower(clientID), nil
|
||||
}
|
||||
|
||||
// clientIDFromDNSContextHTTPS extracts the client's ID from the path of the
|
||||
@@ -104,7 +104,7 @@ func clientIDFromDNSContextHTTPS(pctx *proxy.DNSContext) (clientID string, err e
|
||||
return "", fmt.Errorf("clientid check: %w", err)
|
||||
}
|
||||
|
||||
return clientID, nil
|
||||
return strings.ToLower(clientID), nil
|
||||
}
|
||||
|
||||
// tlsConn is a narrow interface for *tls.Conn to simplify testing.
|
||||
@@ -112,8 +112,8 @@ type tlsConn interface {
|
||||
ConnectionState() (cs tls.ConnectionState)
|
||||
}
|
||||
|
||||
// quicSession is a narrow interface for quic.Session to simplify testing.
|
||||
type quicSession interface {
|
||||
// quicConnection is a narrow interface for quic.Connection to simplify testing.
|
||||
type quicConnection interface {
|
||||
ConnectionState() (cs quic.ConnectionState)
|
||||
}
|
||||
|
||||
@@ -148,16 +148,16 @@ func (s *Server) clientIDFromDNSContext(pctx *proxy.DNSContext) (clientID string
|
||||
|
||||
cliSrvName = tc.ConnectionState().ServerName
|
||||
case proxy.ProtoQUIC:
|
||||
qs, ok := pctx.QUICSession.(quicSession)
|
||||
conn, ok := pctx.QUICConnection.(quicConnection)
|
||||
if !ok {
|
||||
return "", fmt.Errorf(
|
||||
"proxy ctx quic session of proto %s is %T, want quic.Session",
|
||||
"proxy ctx quic conn of proto %s is %T, want quic.Connection",
|
||||
proto,
|
||||
pctx.QUICSession,
|
||||
pctx.QUICConnection,
|
||||
)
|
||||
}
|
||||
|
||||
cliSrvName = qs.ConnectionState().TLS.ServerName
|
||||
cliSrvName = conn.ConnectionState().TLS.ServerName
|
||||
}
|
||||
|
||||
clientID, err = clientIDFromClientServerName(
|
||||
|
||||
@@ -29,17 +29,18 @@ func (c testTLSConn) ConnectionState() (cs tls.ConnectionState) {
|
||||
return cs
|
||||
}
|
||||
|
||||
// testQUICSession is a quicSession for tests.
|
||||
type testQUICSession struct {
|
||||
// Session is embedded here simply to make testQUICSession a quic.Session
|
||||
// without actually implementing all methods.
|
||||
quic.Session
|
||||
// testQUICConnection is a quicConnection for tests.
|
||||
type testQUICConnection struct {
|
||||
// Connection is embedded here simply to make testQUICConnection a
|
||||
// quic.Connection without actually implementing all methods.
|
||||
quic.Connection
|
||||
|
||||
serverName string
|
||||
}
|
||||
|
||||
// ConnectionState implements the quicSession interface for testQUICSession.
|
||||
func (c testQUICSession) ConnectionState() (cs quic.ConnectionState) {
|
||||
// ConnectionState implements the quicConnection interface for
|
||||
// testQUICConnection.
|
||||
func (c testQUICConnection) ConnectionState() (cs quic.ConnectionState) {
|
||||
cs.TLS.ServerName = c.serverName
|
||||
|
||||
return cs
|
||||
@@ -143,6 +144,22 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||
wantErrMsg: `clientid check: client server name "cli.myexample.com" ` +
|
||||
`doesn't match host server name "example.com"`,
|
||||
strictSNI: true,
|
||||
}, {
|
||||
name: "tls_case",
|
||||
proto: proxy.ProtoTLS,
|
||||
hostSrvName: "example.com",
|
||||
cliSrvName: "InSeNsItIvE.example.com",
|
||||
wantClientID: "insensitive",
|
||||
wantErrMsg: ``,
|
||||
strictSNI: true,
|
||||
}, {
|
||||
name: "quic_case",
|
||||
proto: proxy.ProtoQUIC,
|
||||
hostSrvName: "example.com",
|
||||
cliSrvName: "InSeNsItIvE.example.com",
|
||||
wantClientID: "insensitive",
|
||||
wantErrMsg: ``,
|
||||
strictSNI: true,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@@ -163,17 +180,17 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
var qs quic.Session
|
||||
var qconn quic.Connection
|
||||
if tc.proto == proxy.ProtoQUIC {
|
||||
qs = testQUICSession{
|
||||
qconn = testQUICConnection{
|
||||
serverName: tc.cliSrvName,
|
||||
}
|
||||
}
|
||||
|
||||
pctx := &proxy.DNSContext{
|
||||
Proto: tc.proto,
|
||||
Conn: conn,
|
||||
QUICSession: qs,
|
||||
Proto: tc.proto,
|
||||
Conn: conn,
|
||||
QUICConnection: qconn,
|
||||
}
|
||||
|
||||
clientID, err := srv.clientIDFromDNSContext(pctx)
|
||||
@@ -210,6 +227,11 @@ func TestClientIDFromDNSContextHTTPS(t *testing.T) {
|
||||
path: "/dns-query/cli/",
|
||||
wantClientID: "cli",
|
||||
wantErrMsg: "",
|
||||
}, {
|
||||
name: "clientid_case",
|
||||
path: "/dns-query/InSeNsItIvE",
|
||||
wantClientID: "insensitive",
|
||||
wantErrMsg: ``,
|
||||
}, {
|
||||
name: "bad_url",
|
||||
path: "/foo",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
@@ -135,7 +140,6 @@ func (s *Server) processRecursion(dctx *dnsContext) (rc resultCode) {
|
||||
pctx.Res = s.genNXDomain(pctx.Req)
|
||||
|
||||
return resultCodeFinish
|
||||
|
||||
}
|
||||
|
||||
return resultCodeSuccess
|
||||
@@ -242,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) {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -510,6 +510,7 @@ func separateUpstream(upstreamStr string) (upstream string, isDomainSpec bool, e
|
||||
continue
|
||||
}
|
||||
|
||||
host = strings.TrimPrefix(host, "*.")
|
||||
err = netutil.ValidateDomainName(host)
|
||||
if err != nil {
|
||||
return "", true, fmt.Errorf("domain at index %d: %w", i, err)
|
||||
|
||||
@@ -83,7 +83,7 @@ func TestRecursionDetector_Suspect(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
msg dns.Msg
|
||||
want bool
|
||||
want int
|
||||
}{{
|
||||
name: "simple",
|
||||
msg: dns.Msg{
|
||||
@@ -95,24 +95,18 @@ func TestRecursionDetector_Suspect(t *testing.T) {
|
||||
Qtype: dns.TypeA,
|
||||
}},
|
||||
},
|
||||
want: true,
|
||||
want: 1,
|
||||
}, {
|
||||
name: "unencumbered",
|
||||
msg: dns.Msg{},
|
||||
want: false,
|
||||
want: 0,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Cleanup(rd.clear)
|
||||
|
||||
rd.add(tc.msg)
|
||||
|
||||
if tc.want {
|
||||
assert.Equal(t, 1, rd.recentRequests.Stats().Count)
|
||||
} else {
|
||||
assert.Zero(t, rd.recentRequests.Stats().Count)
|
||||
}
|
||||
assert.Equal(t, tc.want, rd.recentRequests.Stats().Count)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,9 +64,9 @@ func (s *Server) logQuery(
|
||||
Answer: pctx.Res,
|
||||
OrigAnswer: dctx.origResp,
|
||||
Result: dctx.result,
|
||||
Elapsed: elapsed,
|
||||
ClientID: dctx.clientID,
|
||||
ClientIP: ip,
|
||||
Elapsed: elapsed,
|
||||
AuthenticatedData: dctx.responseAD,
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -59,6 +60,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 +145,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 +169,9 @@ func (clients *clientsContainer) Start() {
|
||||
|
||||
// Reload reloads runtime clients.
|
||||
func (clients *clientsContainer) Reload() {
|
||||
clients.addFromSystemARP()
|
||||
if clients.arpdb != nil {
|
||||
clients.addFromSystemARP()
|
||||
}
|
||||
}
|
||||
|
||||
type clientObject struct {
|
||||
@@ -534,7 +547,7 @@ func (clients *clientsContainer) check(c *Client) (err error) {
|
||||
} else if mac, err = net.ParseMAC(id); err == nil {
|
||||
c.IDs[i] = mac.String()
|
||||
} else if err = dnsforward.ValidateClientID(id); err == nil {
|
||||
c.IDs[i] = id
|
||||
c.IDs[i] = strings.ToLower(id)
|
||||
} else {
|
||||
return fmt.Errorf("invalid clientid at index %d: %q", i, id)
|
||||
}
|
||||
@@ -843,7 +856,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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -58,6 +58,7 @@ func initDNSServer() (err error) {
|
||||
}
|
||||
|
||||
conf := querylog.Config{
|
||||
Anonymizer: anonymizer,
|
||||
ConfigModified: onConfigModified,
|
||||
HTTPRegister: httpRegister,
|
||||
FindClient: Context.clients.findMultiple,
|
||||
@@ -67,7 +68,6 @@ func initDNSServer() (err error) {
|
||||
Enabled: config.DNS.QueryLogEnabled,
|
||||
FileEnabled: config.DNS.QueryLogFileEnabled,
|
||||
AnonymizeClientIP: config.DNS.AnonymizeClientIP,
|
||||
Anonymizer: anonymizer,
|
||||
}
|
||||
Context.queryLog = querylog.New(conf)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -16,18 +16,17 @@ type RDNS struct {
|
||||
exchanger dnsforward.RDNSExchanger
|
||||
clients *clientsContainer
|
||||
|
||||
// usePrivate is used to store the state of current private RDNS
|
||||
// resolving settings and to react to it's changes.
|
||||
// usePrivate is used to store the state of current private RDNS resolving
|
||||
// settings and to react to it's changes.
|
||||
usePrivate uint32
|
||||
|
||||
// ipCh used to pass client's IP to rDNS workerLoop.
|
||||
ipCh chan net.IP
|
||||
|
||||
// ipCache caches the IP addresses to be resolved by rDNS. The resolved
|
||||
// address stays here while it's inside clients. After leaving clients
|
||||
// the address will be resolved once again. If the address couldn't be
|
||||
// resolved, cache prevents further attempts to resolve it for some
|
||||
// time.
|
||||
// address stays here while it's inside clients. After leaving clients the
|
||||
// address will be resolved once again. If the address couldn't be
|
||||
// resolved, cache prevents further attempts to resolve it for some time.
|
||||
ipCache cache.Cache
|
||||
}
|
||||
|
||||
|
||||
@@ -433,8 +433,11 @@ EnvironmentFile=-/etc/sysconfig/{{.Name}}
|
||||
WantedBy=multi-user.target
|
||||
`
|
||||
|
||||
// Note: we should keep it in sync with the template from service_sysv_linux.go file
|
||||
// Use "ps | grep -v grep | grep $(get_pid)" because "ps PID" may not work on OpenWrt
|
||||
// sysvScript is the source of the daemon script for SysV-based Linux systems.
|
||||
// Keep as close as possible to the https://github.com/kardianos/service/blob/29f8c79c511bc18422bb99992779f96e6bc33921/service_sysv_linux.go#L187.
|
||||
//
|
||||
// Use ps command instead of reading the procfs since it's a more
|
||||
// implementation-independent approach.
|
||||
const sysvScript = `#!/bin/sh
|
||||
# For RedHat and cousins:
|
||||
# chkconfig: - 99 01
|
||||
@@ -465,7 +468,7 @@ get_pid() {
|
||||
}
|
||||
|
||||
is_running() {
|
||||
[ -f "$pid_file" ] && ps | grep -v grep | grep $(get_pid) > /dev/null 2>&1
|
||||
[ -f "$pid_file" ] && ps -p "$(get_pid)" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
@@ -609,7 +612,7 @@ command_args="-P ${pidfile} -p ${pidfile_child} -T ${name} -r {{.WorkingDirector
|
||||
run_rc_command "$1"
|
||||
`
|
||||
|
||||
const openBSDScript = `#!/bin/sh
|
||||
const openBSDScript = `#!/bin/ksh
|
||||
#
|
||||
# $OpenBSD: {{ .SvcInfo }}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ import (
|
||||
)
|
||||
|
||||
type qlogConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
// Use float64 here to support fractional numbers and not mess the API
|
||||
// users by changing the units.
|
||||
Interval float64 `json:"interval"`
|
||||
Enabled bool `json:"enabled"`
|
||||
AnonymizeClientIP bool `json:"anonymize_client_ip"`
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ func (l *queryLog) clear() {
|
||||
log.Error("removing log file %q: %s", l.logFile, err)
|
||||
}
|
||||
|
||||
log.Debug("Query log: cleared")
|
||||
log.Debug("querylog: cleared")
|
||||
}
|
||||
|
||||
func (l *queryLog) Add(params *AddParams) {
|
||||
|
||||
@@ -285,8 +285,8 @@ func addEntry(l *queryLog, host string, answerStr, client net.IP) {
|
||||
Answer: &a,
|
||||
OrigAnswer: &a,
|
||||
Result: &res,
|
||||
ClientIP: client,
|
||||
Upstream: "upstream",
|
||||
ClientIP: client,
|
||||
}
|
||||
|
||||
l.Add(params)
|
||||
|
||||
@@ -28,8 +28,11 @@ type QueryLog interface {
|
||||
WriteDiskConfig(c *Config)
|
||||
}
|
||||
|
||||
// Config - configuration object
|
||||
// Config is the query log configuration structure.
|
||||
type Config struct {
|
||||
// Anonymizer processes the IP addresses to anonymize those if needed.
|
||||
Anonymizer *aghnet.IPMut
|
||||
|
||||
// ConfigModified is called when the configuration is changed, for
|
||||
// example by HTTP requests.
|
||||
ConfigModified func()
|
||||
@@ -68,9 +71,6 @@ type Config struct {
|
||||
// AnonymizeClientIP tells if the query log should anonymize clients' IP
|
||||
// addresses.
|
||||
AnonymizeClientIP bool
|
||||
|
||||
// Anonymizer processes the IP addresses to anonymize those if needed.
|
||||
Anonymizer *aghnet.IPMut
|
||||
}
|
||||
|
||||
// AddParams is the parameters for adding an entry.
|
||||
@@ -91,18 +91,18 @@ type AddParams struct {
|
||||
// Result is the filtering result (optional).
|
||||
Result *filtering.Result
|
||||
|
||||
// Elapsed is the time spent for processing the request.
|
||||
Elapsed time.Duration
|
||||
|
||||
ClientID string
|
||||
|
||||
ClientIP net.IP
|
||||
|
||||
// Upstream is the URL of the upstream DNS server.
|
||||
Upstream string
|
||||
|
||||
ClientProto ClientProto
|
||||
|
||||
ClientIP net.IP
|
||||
|
||||
// Elapsed is the time spent for processing the request.
|
||||
Elapsed time.Duration
|
||||
|
||||
// Cached indicates if the response is served from cache.
|
||||
Cached bool
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ func (l *queryLog) searchMemory(params *searchParams, cache clientCache) (entrie
|
||||
|
||||
// search - searches log entries in the query log using specified parameters
|
||||
// returns the list of entries found + time of the oldest entry
|
||||
func (l *queryLog) search(params *searchParams) ([]*logEntry, time.Time) {
|
||||
func (l *queryLog) search(params *searchParams) (entries []*logEntry, oldest time.Time) {
|
||||
now := time.Now()
|
||||
|
||||
if params.limit == 0 {
|
||||
@@ -88,7 +88,7 @@ func (l *queryLog) search(params *searchParams) ([]*logEntry, time.Time) {
|
||||
totalLimit := params.offset + params.limit
|
||||
|
||||
// now let's get a unified collection
|
||||
entries := append(memoryEntries, fileEntries...)
|
||||
entries = append(memoryEntries, fileEntries...)
|
||||
if len(entries) > totalLimit {
|
||||
// remove extra records
|
||||
entries = entries[:totalLimit]
|
||||
@@ -111,13 +111,18 @@ func (l *queryLog) search(params *searchParams) ([]*logEntry, time.Time) {
|
||||
}
|
||||
}
|
||||
|
||||
if len(entries) > 0 && len(entries) <= totalLimit {
|
||||
if len(entries) > 0 {
|
||||
// Update oldest after merging in the memory buffer.
|
||||
oldest = entries[len(entries)-1].Time
|
||||
}
|
||||
|
||||
log.Debug("QueryLog: prepared data (%d/%d) older than %s in %s",
|
||||
len(entries), total, params.olderThan, time.Since(now))
|
||||
log.Debug(
|
||||
"querylog: prepared data (%d/%d) older than %s in %s",
|
||||
len(entries),
|
||||
total,
|
||||
params.olderThan,
|
||||
time.Since(now),
|
||||
)
|
||||
|
||||
return entries, oldest
|
||||
}
|
||||
@@ -180,6 +185,8 @@ func (l *queryLog) searchFiles(
|
||||
e, ts, err = l.readNextEntry(r, params, cache)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
oldestNano = 0
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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.
|
||||
|
||||
33
internal/v1/agh/agh.go
Normal file
33
internal/v1/agh/agh.go
Normal file
@@ -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 }
|
||||
71
internal/v1/cmd/cmd.go
Normal file
71
internal/v1/cmd/cmd.go
Normal file
@@ -0,0 +1,71 @@
|
||||
// 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
|
||||
|
||||
start := time.Now()
|
||||
rand.Seed(start.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,
|
||||
}},
|
||||
Start: start,
|
||||
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)
|
||||
}
|
||||
}
|
||||
70
internal/v1/cmd/signal.go
Normal file
70
internal/v1/cmd/signal.go
Normal file
@@ -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("signalHandler.handle")
|
||||
|
||||
for sig := range h.signal {
|
||||
log.Info("sighdlr: 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("sighdlr: shutting down services")
|
||||
for i, service := range h.services {
|
||||
err := service.Shutdown(ctx)
|
||||
if err != nil {
|
||||
log.Error("sighdlr: shutting down service at index %d: %s", i, err)
|
||||
status = statusError
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("sighdlr: shutting down adguard 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
|
||||
}
|
||||
61
internal/v1/websvc/json.go
Normal file
61
internal/v1/websvc/json.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package websvc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
|
||||
// JSON Utilities
|
||||
|
||||
// jsonTime is a time.Time that can be decoded from JSON and encoded into JSON
|
||||
// according to our API conventions.
|
||||
type jsonTime time.Time
|
||||
|
||||
// type check
|
||||
var _ json.Marshaler = jsonTime{}
|
||||
|
||||
// nsecPerMsec is the number of nanoseconds in a millisecond.
|
||||
const nsecPerMsec = float64(time.Millisecond / time.Nanosecond)
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface for jsonTime. err is
|
||||
// always nil.
|
||||
func (t jsonTime) MarshalJSON() (b []byte, err error) {
|
||||
msec := float64(time.Time(t).UnixNano()) / nsecPerMsec
|
||||
b = strconv.AppendFloat(nil, msec, 'f', 3, 64)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ json.Unmarshaler = (*jsonTime)(nil)
|
||||
|
||||
// UnmarshalJSON implements the json.Marshaler interface for *jsonTime.
|
||||
func (t *jsonTime) UnmarshalJSON(b []byte) (err error) {
|
||||
if t == nil {
|
||||
return fmt.Errorf("json time is nil")
|
||||
}
|
||||
|
||||
msec, err := strconv.ParseFloat(string(b), 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing json time: %w", err)
|
||||
}
|
||||
|
||||
*t = jsonTime(time.Unix(0, int64(msec*nsecPerMsec)).UTC())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeJSONResponse encodes v into w and logs any errors it encounters. r is
|
||||
// used to get additional information from the request.
|
||||
func writeJSONResponse(w io.Writer, r *http.Request, v interface{}) {
|
||||
err := json.NewEncoder(w).Encode(v)
|
||||
if err != nil {
|
||||
log.Error("websvc: writing resp to %s %s: %s", r.Method, r.URL.Path, err)
|
||||
}
|
||||
}
|
||||
16
internal/v1/websvc/middleware.go
Normal file
16
internal/v1/websvc/middleware.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package websvc
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Middlewares
|
||||
|
||||
// jsonMw sets the content type of the response to application/json.
|
||||
func jsonMw(h http.Handler) (wrapped http.HandlerFunc) {
|
||||
f := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
return http.HandlerFunc(f)
|
||||
}
|
||||
8
internal/v1/websvc/path.go
Normal file
8
internal/v1/websvc/path.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package websvc
|
||||
|
||||
// Path constants
|
||||
const (
|
||||
PathHealthCheck = "/health-check"
|
||||
|
||||
PathV1SystemInfo = "/api/v1/system/info"
|
||||
)
|
||||
35
internal/v1/websvc/system.go
Normal file
35
internal/v1/websvc/system.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package websvc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"runtime"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
||||
)
|
||||
|
||||
// System Handlers
|
||||
|
||||
// RespGetV1SystemInfo describes the response of the GET /api/v1/system/info
|
||||
// HTTP API.
|
||||
type RespGetV1SystemInfo struct {
|
||||
Arch string `json:"arch"`
|
||||
Channel string `json:"channel"`
|
||||
OS string `json:"os"`
|
||||
NewVersion string `json:"new_version,omitempty"`
|
||||
Start jsonTime `json:"start"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// handleGetV1SystemInfo is the handler for the GET /api/v1/system/info HTTP
|
||||
// API.
|
||||
func (svc *Service) handleGetV1SystemInfo(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSONResponse(w, r, &RespGetV1SystemInfo{
|
||||
Arch: runtime.GOARCH,
|
||||
Channel: version.Channel(),
|
||||
OS: runtime.GOOS,
|
||||
// TODO(a.garipov): Fill this when we have an updater.
|
||||
NewVersion: "",
|
||||
Start: jsonTime(svc.start),
|
||||
Version: version.Version(),
|
||||
})
|
||||
}
|
||||
36
internal/v1/websvc/system_test.go
Normal file
36
internal/v1/websvc/system_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package websvc_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/v1/websvc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestService_handleGetV1SystemInfo(t *testing.T) {
|
||||
_, addr := newTestServer(t)
|
||||
u := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: addr,
|
||||
Path: websvc.PathV1SystemInfo,
|
||||
}
|
||||
|
||||
body := httpGet(t, u, http.StatusOK)
|
||||
resp := &websvc.RespGetV1SystemInfo{}
|
||||
err := json.Unmarshal(body, resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
// TODO(a.garipov): Consider making version.Channel and version.Version
|
||||
// testable and test these better.
|
||||
assert.NotEmpty(t, resp.Channel)
|
||||
|
||||
assert.Equal(t, resp.Arch, runtime.GOARCH)
|
||||
assert.Equal(t, resp.OS, runtime.GOOS)
|
||||
assert.Equal(t, testStart, time.Time(resp.Start))
|
||||
}
|
||||
227
internal/v1/websvc/websvc.go
Normal file
227
internal/v1/websvc/websvc.go
Normal file
@@ -0,0 +1,227 @@
|
||||
// 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"
|
||||
httptreemux "github.com/dimfeld/httptreemux/v5"
|
||||
)
|
||||
|
||||
// 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
|
||||
|
||||
// Start is the time of start of AdGuard Home.
|
||||
Start time.Time
|
||||
|
||||
// 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
|
||||
start time.Time
|
||||
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,
|
||||
start: c.Start,
|
||||
timeout: c.Timeout,
|
||||
}
|
||||
|
||||
mux := newMux(svc)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// newMux returns a new HTTP request multiplexor for the AdGuard Home web
|
||||
// service.
|
||||
func newMux(svc *Service) (mux *httptreemux.ContextMux) {
|
||||
mux = httptreemux.NewContextMux()
|
||||
|
||||
routes := []struct {
|
||||
handler http.HandlerFunc
|
||||
method string
|
||||
path string
|
||||
isJSON bool
|
||||
}{{
|
||||
handler: svc.handleGetHealthCheck,
|
||||
method: http.MethodGet,
|
||||
path: PathHealthCheck,
|
||||
isJSON: false,
|
||||
}, {
|
||||
handler: svc.handleGetV1SystemInfo,
|
||||
method: http.MethodGet,
|
||||
path: PathV1SystemInfo,
|
||||
isJSON: true,
|
||||
}}
|
||||
|
||||
for _, r := range routes {
|
||||
var h http.HandlerFunc
|
||||
if r.isJSON {
|
||||
// TODO(a.garipov): Consider using httptreemux's MiddlewareFunc.
|
||||
h = jsonMw(r.handler)
|
||||
} else {
|
||||
h = r.handler
|
||||
}
|
||||
|
||||
mux.Handle(r.method, r.path, h)
|
||||
}
|
||||
|
||||
return mux
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
97
internal/v1/websvc/websvc_test.go
Normal file
97
internal/v1/websvc/websvc_test.go
Normal file
@@ -0,0 +1,97 @@
|
||||
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
|
||||
|
||||
// testStart is the server start value for tests.
|
||||
var testStart = time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
// newTestServer creates and starts a new web service instance as well as its
|
||||
// sole address. It also registers a cleanup procedure, which shuts the
|
||||
// instance down.
|
||||
//
|
||||
// TODO(a.garipov): Use svc or remove it.
|
||||
func newTestServer(t testing.TB) (svc *websvc.Service, addr string) {
|
||||
t.Helper()
|
||||
|
||||
c := &websvc.Config{
|
||||
TLS: nil,
|
||||
Addresses: []*netutil.IPPort{{
|
||||
IP: net.IP{127, 0, 0, 1},
|
||||
Port: 0,
|
||||
}},
|
||||
SecureAddresses: nil,
|
||||
Timeout: testTimeout,
|
||||
Start: testStart,
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
return svc, addrs[0]
|
||||
}
|
||||
|
||||
// httpGet is a helper that performs an HTTP GET request and returns the body of
|
||||
// the response as well as checks that the status code is correct.
|
||||
//
|
||||
// TODO(a.garipov): Add helpers for other methods.
|
||||
func httpGet(t testing.TB, u *url.URL, wantCode int) (body []byte) {
|
||||
t.Helper()
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
||||
require.NoErrorf(t, err, "creating req")
|
||||
|
||||
httpCli := &http.Client{
|
||||
Timeout: testTimeout,
|
||||
}
|
||||
resp, err := httpCli.Do(req)
|
||||
require.NoErrorf(t, err, "performing req")
|
||||
require.Equal(t, wantCode, resp.StatusCode)
|
||||
|
||||
testutil.CleanupAndRequireSuccess(t, resp.Body.Close)
|
||||
|
||||
body, err = io.ReadAll(resp.Body)
|
||||
require.NoErrorf(t, err, "reading body")
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func TestService_Start_getHealthCheck(t *testing.T) {
|
||||
_, addr := newTestServer(t)
|
||||
u := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: addr,
|
||||
Path: websvc.PathHealthCheck,
|
||||
}
|
||||
|
||||
body := httpGet(t, u, http.StatusOK)
|
||||
|
||||
assert.Equal(t, []byte("OK"), body)
|
||||
}
|
||||
21
main_v1.go
Normal file
21
main_v1.go
Normal file
@@ -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)
|
||||
}
|
||||
4925
openapi/v1.yaml
Normal file
4925
openapi/v1.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
|
||||
@@ -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 ./...
|
||||
|
||||
|
||||
Reference in New Issue
Block a user