Compare commits
16 Commits
v0.107.0-b
...
fix-stats-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02834e6b7b | ||
|
|
b45162a0f2 | ||
|
|
ce0df255be | ||
|
|
b735c8167c | ||
|
|
2ac2ad0609 | ||
|
|
37a3666a2a | ||
|
|
5aed8db5cf | ||
|
|
e1e064db59 | ||
|
|
b1242ee93f | ||
|
|
5f3131c799 | ||
|
|
1714a986e3 | ||
|
|
6ac28ee8ee | ||
|
|
bf1263628a | ||
|
|
176a344aee | ||
|
|
48b0cefb29 | ||
|
|
857f876486 |
@@ -19,7 +19,7 @@
|
|||||||
"it": "Italiano",
|
"it": "Italiano",
|
||||||
"ja": "日本語",
|
"ja": "日本語",
|
||||||
"ko": "한국어",
|
"ko": "한국어",
|
||||||
"nl": "Dutch",
|
"nl": "Nederlands",
|
||||||
"no": "Norsk",
|
"no": "Norsk",
|
||||||
"pl": "Polski",
|
"pl": "Polski",
|
||||||
"pt-br": "Português (BR)",
|
"pt-br": "Português (BR)",
|
||||||
|
|||||||
21
CHANGELOG.md
21
CHANGELOG.md
@@ -10,12 +10,13 @@ and this project adheres to
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
## [v0.107.0] - 2021-09-14 (APPROX.)
|
## [v0.107.0] - 2021-09-28 (APPROX.)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Bootstrap DNS server IPs to the `mobileconfig` API responses ([#3568]).
|
- DNS server IP addresses to the `mobileconfig` API responses ([#3568],
|
||||||
|
[#3607]).
|
||||||
- Setting the timeout for IP address pinging in the "Fastest IP address" mode
|
- Setting the timeout for IP address pinging in the "Fastest IP address" mode
|
||||||
through the new `fastest_timeout` field in the configuration file ([#1992]).
|
through the new `fastest_timeout` field in the configuration file ([#1992]).
|
||||||
- Static IP address detection on FreeBSD ([#3289]).
|
- Static IP address detection on FreeBSD ([#3289]).
|
||||||
@@ -49,10 +50,10 @@ and this project adheres to
|
|||||||
|
|
||||||
- The `systemd` service script will now create the `/var/log` directory when it
|
- The `systemd` service script will now create the `/var/log` directory when it
|
||||||
doesn't exist ([#3579]).
|
doesn't exist ([#3579]).
|
||||||
- Items in allowed clients, disallowed clients, and blocked hosts lists must
|
- Items in allowed clients, disallowed clients, and blocked hosts lists are now
|
||||||
be unique ([#3419]).
|
required to be unique ([#3419]).
|
||||||
- The TLS private key previously saved as a string isn't shown in API responses
|
- The TLS private key previously saved as a string isn't shown in API responses
|
||||||
any more ([#1898]).
|
anymore ([#1898]).
|
||||||
- Better OpenWrt detection ([#3435]).
|
- Better OpenWrt detection ([#3435]).
|
||||||
- DNS-over-HTTPS queries that come from HTTP proxies in the `trusted_proxies`
|
- DNS-over-HTTPS queries that come from HTTP proxies in the `trusted_proxies`
|
||||||
list now use the real IP address of the client instead of the address of the
|
list now use the real IP address of the client instead of the address of the
|
||||||
@@ -115,7 +116,10 @@ In this release, the schema version has changed from 10 to 12.
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Panic when upstream server responds with empty question section ([#3551]).
|
- Adding an IP into only one of the matching ipsets on Linux ([#3638]).
|
||||||
|
- Removal of temporary filter files ([#3567]).
|
||||||
|
- Panic when an upstream server responds with an empty question section
|
||||||
|
([#3551]).
|
||||||
- 9GAG blocking ([#3564]).
|
- 9GAG blocking ([#3564]).
|
||||||
- DHCP now follows RFCs more closely when it comes to response sending and
|
- DHCP now follows RFCs more closely when it comes to response sending and
|
||||||
option selection ([#3443], [#3538]).
|
option selection ([#3443], [#3538]).
|
||||||
@@ -194,8 +198,11 @@ In this release, the schema version has changed from 10 to 12.
|
|||||||
[#3538]: https://github.com/AdguardTeam/AdGuardHome/issues/3538
|
[#3538]: https://github.com/AdguardTeam/AdGuardHome/issues/3538
|
||||||
[#3551]: https://github.com/AdguardTeam/AdGuardHome/issues/3551
|
[#3551]: https://github.com/AdguardTeam/AdGuardHome/issues/3551
|
||||||
[#3564]: https://github.com/AdguardTeam/AdGuardHome/issues/3564
|
[#3564]: https://github.com/AdguardTeam/AdGuardHome/issues/3564
|
||||||
|
[#3567]: https://github.com/AdguardTeam/AdGuardHome/issues/3567
|
||||||
[#3568]: https://github.com/AdguardTeam/AdGuardHome/issues/3568
|
[#3568]: https://github.com/AdguardTeam/AdGuardHome/issues/3568
|
||||||
[#3579]: https://github.com/AdguardTeam/AdGuardHome/issues/3579
|
[#3579]: https://github.com/AdguardTeam/AdGuardHome/issues/3579
|
||||||
|
[#3607]: https://github.com/AdguardTeam/AdGuardHome/issues/3607
|
||||||
|
[#3638]: https://github.com/AdguardTeam/AdGuardHome/issues/3638
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -399,7 +406,7 @@ In this release, the schema version has changed from 10 to 12.
|
|||||||
- The field `"range_start"` in the `GET /control/dhcp/status` HTTP API response
|
- The field `"range_start"` in the `GET /control/dhcp/status` HTTP API response
|
||||||
is now correctly named again ([#2678]).
|
is now correctly named again ([#2678]).
|
||||||
- DHCPv6 server's `ra_slaac_only` and `ra_allow_slaac` settings aren't reset to
|
- DHCPv6 server's `ra_slaac_only` and `ra_allow_slaac` settings aren't reset to
|
||||||
`false` on update any more ([#2653]).
|
`false` on update anymore ([#2653]).
|
||||||
- The `Vary` header is now added along with `Access-Control-Allow-Origin` to
|
- The `Vary` header is now added along with `Access-Control-Allow-Origin` to
|
||||||
prevent cache-related and other issues in browsers ([#2658]).
|
prevent cache-related and other issues in browsers ([#2658]).
|
||||||
- The request body size limit is now set for HTTPS requests as well.
|
- The request body size limit is now set for HTTPS requests as well.
|
||||||
|
|||||||
@@ -218,6 +218,7 @@
|
|||||||
"reset_settings": "Изтрий всички настройки",
|
"reset_settings": "Изтрий всички настройки",
|
||||||
"update_announcement": "Има нова AdGuard Home {{version}}! <0>Цъкни тук</0> за повече информация.",
|
"update_announcement": "Има нова AdGuard Home {{version}}! <0>Цъкни тук</0> за повече информация.",
|
||||||
"disable_ipv6": "Изключете IPv6 протокола",
|
"disable_ipv6": "Изключете IPv6 протокола",
|
||||||
|
"check_updates_now": "Провери за актуализации",
|
||||||
"show_blocked_responses": "Блокирано",
|
"show_blocked_responses": "Блокирано",
|
||||||
"port_53_faq_link": "Порт 53 често е зает от \"DNSStubListener\" или \"systemd-resolved\" услуги. Моля, прочетете <0>тази инструкция</0> как да решите това."
|
"port_53_faq_link": "Порт 53 често е зает от \"DNSStubListener\" или \"systemd-resolved\" услуги. Моля, прочетете <0>тази инструкция</0> как да решите това."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Budete muset nakonfigurovat Vaše zařízení nebo router, aby používali DNS server na následujících adresách:",
|
"install_settings_dns_desc": "Budete muset nakonfigurovat Vaše zařízení nebo router, aby používali DNS server na následujících adresách:",
|
||||||
"install_settings_all_interfaces": "Všechna rozhraní",
|
"install_settings_all_interfaces": "Všechna rozhraní",
|
||||||
"install_auth_title": "Ověřování",
|
"install_auth_title": "Ověřování",
|
||||||
"install_auth_desc": "Doporučujeme Vám nakonfigurovat v administrátorském webovém rozhraní AdGuard Home ověření Vaší identity heslem. I když je přístupné pouze ve Vaší lokální síti, je stále důležité chránit jej před neomezeným přístupem.",
|
"install_auth_desc": "V administrátorském webovém rozhraní AdGuard Home musí být nastaveno ověřovací heslo. I když je AdGuard Home přístupný pouze v místní síti, je důležité jej chránit před neomezeným přístupem.",
|
||||||
"install_auth_username": "Uživatelské jméno",
|
"install_auth_username": "Uživatelské jméno",
|
||||||
"install_auth_password": "Heslo",
|
"install_auth_password": "Heslo",
|
||||||
"install_auth_confirm": "Potvrďte heslo",
|
"install_auth_confirm": "Potvrďte heslo",
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Du skal opsætte dine enheder eller router til at bruge DNS-serveren på flg. adresser:",
|
"install_settings_dns_desc": "Du skal opsætte dine enheder eller router til at bruge DNS-serveren på flg. adresser:",
|
||||||
"install_settings_all_interfaces": "Alle grænseflader",
|
"install_settings_all_interfaces": "Alle grænseflader",
|
||||||
"install_auth_title": "Godkendelse",
|
"install_auth_title": "Godkendelse",
|
||||||
"install_auth_desc": "Det anbefales stærkt at opsætte adgangskodegodkendelse på din AdGuard Home admin webgrænseflade. Selvom den kun er tilgængelig på dit lokalnetværk, er det stadig vigtigt at få den beskyttet mod ubegrænset adgang.",
|
"install_auth_desc": "Adgangskodegodkendelse på din AdGuard Home admin-webflade skal opsættes. Selv hvis AdGuard Home kun er tilgængelig på lokalnetværket, er beskyttelse mod uautoriseret og ubegrænset adgang stadig vigtig.",
|
||||||
"install_auth_username": "Brugernavn",
|
"install_auth_username": "Brugernavn",
|
||||||
"install_auth_password": "Adgangskode",
|
"install_auth_password": "Adgangskode",
|
||||||
"install_auth_confirm": "Bekræft adgangskode",
|
"install_auth_confirm": "Bekræft adgangskode",
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Sie müssen Ihre Geräte oder Ihren Router so konfigurieren, dass er den DNS-Server unter den folgenden Adressen verwendet:",
|
"install_settings_dns_desc": "Sie müssen Ihre Geräte oder Ihren Router so konfigurieren, dass er den DNS-Server unter den folgenden Adressen verwendet:",
|
||||||
"install_settings_all_interfaces": "Alle Schnittstellen",
|
"install_settings_all_interfaces": "Alle Schnittstellen",
|
||||||
"install_auth_title": "Authentifizierung",
|
"install_auth_title": "Authentifizierung",
|
||||||
"install_auth_desc": "Es wird dringend empfohlen, die Passwortauthentifizierung für Ihre AdGuard Home Administrator-Weboberfläche zu konfigurieren. Auch wenn es nur in Ihrem lokalen Netzwerk zugänglich ist, ist es dennoch wichtig, es vor unbefugtem Zugriff zu schützen.",
|
"install_auth_desc": "Die Passwortauthentifizierung für Ihre AdGuard Home Administrator-Weboberfläche muss konfiguriert sein. Auch wenn AdGuard Home nur in Ihrem lokalen Netzwerk zugänglich ist, ist es dennoch wichtig, es vor unbefugtem Zugriff zu schützen.",
|
||||||
"install_auth_username": "Benutzername",
|
"install_auth_username": "Benutzername",
|
||||||
"install_auth_password": "Passwort",
|
"install_auth_password": "Passwort",
|
||||||
"install_auth_confirm": "Passwort bestätigen",
|
"install_auth_confirm": "Passwort bestätigen",
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "You will need to configure your devices or router to use the DNS server on the following addresses:",
|
"install_settings_dns_desc": "You will need to configure your devices or router to use the DNS server on the following addresses:",
|
||||||
"install_settings_all_interfaces": "All interfaces",
|
"install_settings_all_interfaces": "All interfaces",
|
||||||
"install_auth_title": "Authentication",
|
"install_auth_title": "Authentication",
|
||||||
"install_auth_desc": "It is highly recommended to configure password authentication to your AdGuard Home admin web interface. Even if it is accessible only in your local network, it is still important to protect it from unrestricted access.",
|
"install_auth_desc": "Password authentication to your AdGuard Home admin web interface must be configured. Even if AdGuard Home is accessible only in your local network, it is still important to protect it from unrestricted access.",
|
||||||
"install_auth_username": "Username",
|
"install_auth_username": "Username",
|
||||||
"install_auth_password": "Password",
|
"install_auth_password": "Password",
|
||||||
"install_auth_confirm": "Confirm password",
|
"install_auth_confirm": "Confirm password",
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Deberás configurar tus dispositivos o router para usar el servidor DNS en las siguientes direcciones:",
|
"install_settings_dns_desc": "Deberás configurar tus dispositivos o router para usar el servidor DNS en las siguientes direcciones:",
|
||||||
"install_settings_all_interfaces": "Todas las interfaces",
|
"install_settings_all_interfaces": "Todas las interfaces",
|
||||||
"install_auth_title": "Autenticación",
|
"install_auth_title": "Autenticación",
|
||||||
"install_auth_desc": "Se recomienda encarecidamente configurar la autenticación por contraseña para la interfaz web de administración de AdGuard Home. Incluso si solo es accesible en tu red local, es importante que estés protegido contra el acceso no autorizado.",
|
"install_auth_desc": "Debe configurarse la autenticación por contraseña para la interfaz web de administración de AdGuard Home. Incluso si AdGuard Home es accesible solo en tu red local, es importante protegerlo del acceso no autorizado.",
|
||||||
"install_auth_username": "Usuario",
|
"install_auth_username": "Usuario",
|
||||||
"install_auth_password": "Contraseña",
|
"install_auth_password": "Contraseña",
|
||||||
"install_auth_confirm": "Confirmar contraseña",
|
"install_auth_confirm": "Confirmar contraseña",
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Vous devrez configurer vos appareils et votre routeur pour utiliser le serveur DNS sur les adresses suivantes :",
|
"install_settings_dns_desc": "Vous devrez configurer vos appareils et votre routeur pour utiliser le serveur DNS sur les adresses suivantes :",
|
||||||
"install_settings_all_interfaces": "Toutes les interfaces",
|
"install_settings_all_interfaces": "Toutes les interfaces",
|
||||||
"install_auth_title": "Authentification",
|
"install_auth_title": "Authentification",
|
||||||
"install_auth_desc": "Il est fortement recommandé de configurer un mot de passe pour accéder à l'interface web administrateur AdGuard Home. Même si elle est disponible que dans votre réseau local, cela reste important de se protéger contre des accès non désirés.",
|
"install_auth_desc": "C'est nécessaire de configurer l'authentification par aide de mot de passe pour accéder à l'interface web administrateur de votre AdGuard Home. Même si AdGuard Home n'est accessible que dans votre réseau local, c'est important d'y restreindre accès aux tiers.",
|
||||||
"install_auth_username": "Nom d'utilisateur",
|
"install_auth_username": "Nom d'utilisateur",
|
||||||
"install_auth_password": "Mot de passe",
|
"install_auth_password": "Mot de passe",
|
||||||
"install_auth_confirm": "Confirmer le mot de passe",
|
"install_auth_confirm": "Confirmer le mot de passe",
|
||||||
@@ -613,7 +613,7 @@
|
|||||||
"click_to_view_queries": "Cliquez pour voir les requêtes",
|
"click_to_view_queries": "Cliquez pour voir les requêtes",
|
||||||
"port_53_faq_link": "Le port 53 est souvent occupé par les services « DNSStubListener » ou « systemd-resolved ». Veuillez lire <0>cette instruction</0> pour savoir comment résoudre ce problème.",
|
"port_53_faq_link": "Le port 53 est souvent occupé par les services « DNSStubListener » ou « systemd-resolved ». Veuillez lire <0>cette instruction</0> pour savoir comment résoudre ce problème.",
|
||||||
"adg_will_drop_dns_queries": "AdGuard Home ignorera toutes les requêtes DNS de ce client.",
|
"adg_will_drop_dns_queries": "AdGuard Home ignorera toutes les requêtes DNS de ce client.",
|
||||||
"filter_allowlist": "AVERTISSEMENT : Cette action exclura également la règle « {{disallowed_rule}} » de la liste des clients autorisés.",
|
"filter_allowlist": "ATTENTION : Cette action exclura également la règle « {{disallowed_rule}} » de la liste des clients autorisés.",
|
||||||
"last_rule_in_allowlist": "Impossible d’interdire ce client, car l’exclusion de la règle « {{disallowed_rule}} » DÉSACTIVERA la liste des « clients autorisés ».",
|
"last_rule_in_allowlist": "Impossible d’interdire ce client, car l’exclusion de la règle « {{disallowed_rule}} » DÉSACTIVERA la liste des « clients autorisés ».",
|
||||||
"experimental": "Expérimental",
|
"experimental": "Expérimental",
|
||||||
"use_saved_key": "Utiliser la clef précédemment enregistrée"
|
"use_saved_key": "Utiliser la clef précédemment enregistrée"
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Sarà necessario configurare i dispositivi o il router per utilizzare il server DNS nei seguenti indirizzi:",
|
"install_settings_dns_desc": "Sarà necessario configurare i dispositivi o il router per utilizzare il server DNS nei seguenti indirizzi:",
|
||||||
"install_settings_all_interfaces": "Tutte le interfacce",
|
"install_settings_all_interfaces": "Tutte le interfacce",
|
||||||
"install_auth_title": "Autenticazione",
|
"install_auth_title": "Autenticazione",
|
||||||
"install_auth_desc": "Si consiglia vivamente di configurare l'autenticazione della password per l'interfaccia web di amministrazione di AdGuard Home. Anche se è accessibile solo nella rete locale, è comunque importante proteggerlo da accessi illimitati.",
|
"install_auth_desc": "L\\'autenticazione con password sulla tua interfaccia web da amministratore di AdGuard Home dev\\'esser configurata. Anche se AdGuard Home è accessibile solo dalla tua rete locale, è comunque importante proteggerlo da accessi non limitati.",
|
||||||
"install_auth_username": "Nome utente",
|
"install_auth_username": "Nome utente",
|
||||||
"install_auth_password": "Password",
|
"install_auth_password": "Password",
|
||||||
"install_auth_confirm": "Conferma password",
|
"install_auth_confirm": "Conferma password",
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "次のアドレスでDNSサーバを使用するようにあなたのデバイスまたはルータを設定する必要があります:",
|
"install_settings_dns_desc": "次のアドレスでDNSサーバを使用するようにあなたのデバイスまたはルータを設定する必要があります:",
|
||||||
"install_settings_all_interfaces": "すべてのインターフェイス",
|
"install_settings_all_interfaces": "すべてのインターフェイス",
|
||||||
"install_auth_title": "認証",
|
"install_auth_title": "認証",
|
||||||
"install_auth_desc": "AdGuard Homeの管理ウェブインターフェースにパスワード認証を設定することを強くお勧めします。ローカルネットワークでのみアクセス可能であっても、制限のないアクセスから保護することは重要です。",
|
"install_auth_desc": "AdGuard Homeの管理ウェブインターフェースにパスワード認証を設定する必要があります。AdGuard Homeがローカルネットワークでのみアクセス可能であっても、制限のないアクセスから保護することは重要です。",
|
||||||
"install_auth_username": "ユーザ名",
|
"install_auth_username": "ユーザ名",
|
||||||
"install_auth_password": "パスワード",
|
"install_auth_password": "パスワード",
|
||||||
"install_auth_confirm": "パスワード(確認用)",
|
"install_auth_confirm": "パスワード(確認用)",
|
||||||
@@ -503,6 +503,7 @@
|
|||||||
"statistics_clear_confirm": "統計を消去してもよろしいですか?",
|
"statistics_clear_confirm": "統計を消去してもよろしいですか?",
|
||||||
"statistics_retention_confirm": "統計の保持を変更してもよろしいですか? 期間を短くすると、一部のデータが失われます",
|
"statistics_retention_confirm": "統計の保持を変更してもよろしいですか? 期間を短くすると、一部のデータが失われます",
|
||||||
"statistics_cleared": "統計の消去に成功しました",
|
"statistics_cleared": "統計の消去に成功しました",
|
||||||
|
"statistics_enable": "統計を有効にする",
|
||||||
"interval_hours": "{{count}}時間",
|
"interval_hours": "{{count}}時間",
|
||||||
"interval_hours_plural": "{{count}}時間",
|
"interval_hours_plural": "{{count}}時間",
|
||||||
"filters_configuration": "フィルタ設定",
|
"filters_configuration": "フィルタ設定",
|
||||||
@@ -612,7 +613,8 @@
|
|||||||
"click_to_view_queries": "クエリを表示するにはクリックしてください",
|
"click_to_view_queries": "クエリを表示するにはクリックしてください",
|
||||||
"port_53_faq_link": "多くの場合、ポート53は \"DNSStubListener\" または \"systemd-resolved\" サービスによって利用されています。これを解決する方法については、<0>この手順</0>をお読みください。",
|
"port_53_faq_link": "多くの場合、ポート53は \"DNSStubListener\" または \"systemd-resolved\" サービスによって利用されています。これを解決する方法については、<0>この手順</0>をお読みください。",
|
||||||
"adg_will_drop_dns_queries": "AdGuard Homeは、このクライアントからすべてのDNSクエリを落とします。",
|
"adg_will_drop_dns_queries": "AdGuard Homeは、このクライアントからすべてのDNSクエリを落とします。",
|
||||||
"client_not_in_allowed_clients": "「許可されたクライアント」リストにないため、このクライアントは許可されていません。",
|
"filter_allowlist": "【注意】このアクションは、許可されたクライアントのリストから「{{disallowed_rule}}」というルールも除外します。",
|
||||||
|
"last_rule_in_allowlist": "ルール「{{disallowed_rule}}」を除外すると「許可されたクライアント」リストが無効になるため、このクライアントを拒否することはできません。",
|
||||||
"experimental": "実験用",
|
"experimental": "実験用",
|
||||||
"use_saved_key": "以前に保存したキーを使用する"
|
"use_saved_key": "以前に保存したキーを使用する"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Je moet jouw apparaten of router configureren om de DNS-server te gebruiken op de volgende adressen:",
|
"install_settings_dns_desc": "Je moet jouw apparaten of router configureren om de DNS-server te gebruiken op de volgende adressen:",
|
||||||
"install_settings_all_interfaces": "Alle interfaces",
|
"install_settings_all_interfaces": "Alle interfaces",
|
||||||
"install_auth_title": "Authenticatie",
|
"install_auth_title": "Authenticatie",
|
||||||
"install_auth_desc": "Het wordt ten zeerste aanbevolen om wachtwoordverificatie te configureren voor de AdGuard Home admin webinterface. Zelfs als het alleen toegankelijk is in uw lokale netwerk, is het nog steeds belangrijk om het te beschermen tegen onbeperkte toegang.",
|
"install_auth_desc": "Wachtwoordverificatie voor je AdGuard Home-beheerderswebinterface moet worden geconfigureerd. Zelfs als AdGuard Home alleen toegankelijk is in je lokale netwerk, is het nog steeds belangrijk om het te beschermen tegen onbeperkte toegang.",
|
||||||
"install_auth_username": "Gebruikersnaam",
|
"install_auth_username": "Gebruikersnaam",
|
||||||
"install_auth_password": "Wachtwoord",
|
"install_auth_password": "Wachtwoord",
|
||||||
"install_auth_confirm": "Bevestig wachtwoord",
|
"install_auth_confirm": "Bevestig wachtwoord",
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Konieczne będzie skonfigurowanie urządzenia lub routera do korzystania z serwera DNS pod następującymi adresami:",
|
"install_settings_dns_desc": "Konieczne będzie skonfigurowanie urządzenia lub routera do korzystania z serwera DNS pod następującymi adresami:",
|
||||||
"install_settings_all_interfaces": "Wszystkie interfejsy",
|
"install_settings_all_interfaces": "Wszystkie interfejsy",
|
||||||
"install_auth_title": "Uwierzytelnianie",
|
"install_auth_title": "Uwierzytelnianie",
|
||||||
"install_auth_desc": "Zalecamy skonfigurowanie strony AdGuard Home Admin, aby zweryfikować swoją tożsamość za pomocą hasła. Chociaż jest dostępny tylko w sieci lokalnej, nadal ważne jest, aby chronić go przed nieograniczonym dostępem.",
|
"install_auth_desc": "Należy skonfigurować uwierzytelnianie hasłem do interfejsu internetowego administratora AdGuard Home. Nawet jeśli AdGuard Home jest dostępny tylko w sieci lokalnej, nadal ważne jest, aby chronić go przed nieograniczonym dostępem.",
|
||||||
"install_auth_username": "Nazwa użytkownika",
|
"install_auth_username": "Nazwa użytkownika",
|
||||||
"install_auth_password": "Hasło",
|
"install_auth_password": "Hasło",
|
||||||
"install_auth_confirm": "Potwierdź hasło",
|
"install_auth_confirm": "Potwierdź hasło",
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Você precisa configurar seu dispositivo ou roteador para usar o servidor DNS nos seguintes endereços:",
|
"install_settings_dns_desc": "Você precisa configurar seu dispositivo ou roteador para usar o servidor DNS nos seguintes endereços:",
|
||||||
"install_settings_all_interfaces": "Todas interfaces",
|
"install_settings_all_interfaces": "Todas interfaces",
|
||||||
"install_auth_title": "Autenticação",
|
"install_auth_title": "Autenticação",
|
||||||
"install_auth_desc": "É altamente recomendável configurar a autenticação por senha na interface web de administração do AdGuard Home. Mesmo que ela seja acessível somente em sua rede local, ainda assim é importante protegê-la contra acesso irrestrito.",
|
"install_auth_desc": "A autenticação de senha para a interface da web de administrador do AdGuard Home deve ser configurada. Mesmo que o AdGuard Home esteja acessível apenas em sua rede local, ainda é importante protegê-la de acesso irrestrito.",
|
||||||
"install_auth_username": "Nome de usuário",
|
"install_auth_username": "Nome de usuário",
|
||||||
"install_auth_password": "Senha",
|
"install_auth_password": "Senha",
|
||||||
"install_auth_confirm": "Confirmar senha",
|
"install_auth_confirm": "Confirmar senha",
|
||||||
|
|||||||
@@ -99,10 +99,10 @@
|
|||||||
"homepage": "Página inicial",
|
"homepage": "Página inicial",
|
||||||
"report_an_issue": "Comunicar um problema",
|
"report_an_issue": "Comunicar um problema",
|
||||||
"privacy_policy": "Política de privacidade",
|
"privacy_policy": "Política de privacidade",
|
||||||
"enable_protection": "Ativar protecção",
|
"enable_protection": "Ativar proteção",
|
||||||
"enabled_protection": "Ativar protecção",
|
"enabled_protection": "Ativar proteção",
|
||||||
"disable_protection": "Desativar protecção",
|
"disable_protection": "Desativar proteção",
|
||||||
"disabled_protection": "Desativar protecção",
|
"disabled_protection": "Desativar proteção",
|
||||||
"refresh_statics": "Repor estatísticas",
|
"refresh_statics": "Repor estatísticas",
|
||||||
"dns_query": "Consultas de DNS",
|
"dns_query": "Consultas de DNS",
|
||||||
"blocked_by": "<0>Bloqueado por filtros</0>",
|
"blocked_by": "<0>Bloqueado por filtros</0>",
|
||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Precisa de configurar o seu dispositivo ou router para usar o servidor DNS nos seguintes endereços:",
|
"install_settings_dns_desc": "Precisa de configurar o seu dispositivo ou router para usar o servidor DNS nos seguintes endereços:",
|
||||||
"install_settings_all_interfaces": "Todas as interfaces",
|
"install_settings_all_interfaces": "Todas as interfaces",
|
||||||
"install_auth_title": "Autenticação",
|
"install_auth_title": "Autenticação",
|
||||||
"install_auth_desc": "É altamente recomendável configurar a autenticação por palavra-passe para a sua interface web de administrador do AdGuard Home. Mesmo que seja acessível apenas na sua rede local, ainda assim é importante protegê-lo contra o acesso irrestrito.",
|
"install_auth_desc": "A autenticação de palavra-passe para a interface da web de administrador do AdGuard Home deve ser configurada. Mesmo que o AdGuard Home esteja acessível apenas em sua rede local, ainda é importante protegê-la de acesso irrestrito.",
|
||||||
"install_auth_username": "Nome do utilizador",
|
"install_auth_username": "Nome do utilizador",
|
||||||
"install_auth_password": "Palavra-passe",
|
"install_auth_password": "Palavra-passe",
|
||||||
"install_auth_confirm": "Confirmar palavra-passe",
|
"install_auth_confirm": "Confirmar palavra-passe",
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Вам будет нужно настроить свои устройства или роутер на использование DNS-сервера на одном из следующих адресов:",
|
"install_settings_dns_desc": "Вам будет нужно настроить свои устройства или роутер на использование DNS-сервера на одном из следующих адресов:",
|
||||||
"install_settings_all_interfaces": "Все интерфейсы",
|
"install_settings_all_interfaces": "Все интерфейсы",
|
||||||
"install_auth_title": "Авторизация",
|
"install_auth_title": "Авторизация",
|
||||||
"install_auth_desc": "Настоятельно рекомендуется настроить аутентификацию паролем для веб-интерфейса AdGuard Home. Даже если он доступен только в вашей локальной сети, важно защитить его от неограниченного доступа.",
|
"install_auth_desc": "Должна быть настроена аутентификация паролем для веб-интерфейса AdGuard Home. Даже если он доступен только в вашей локальной сети, важно защитить его от неограниченного доступа.",
|
||||||
"install_auth_username": "Имя пользователя",
|
"install_auth_username": "Имя пользователя",
|
||||||
"install_auth_password": "Пароль",
|
"install_auth_password": "Пароль",
|
||||||
"install_auth_confirm": "Подтвердить пароль",
|
"install_auth_confirm": "Подтвердить пароль",
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
"dhcp_enable": "ග.ධා.වි.කෙ. සේවාදායකය සබල කරන්න",
|
"dhcp_enable": "ග.ධා.වි.කෙ. සේවාදායකය සබල කරන්න",
|
||||||
"dhcp_disable": "ග.ධා.වි.කෙ. සේවාදායකය අබල කරන්න",
|
"dhcp_disable": "ග.ධා.වි.කෙ. සේවාදායකය අබල කරන්න",
|
||||||
"dhcp_config_saved": "ග.ධා.වි.කෙ. වින්යාසය සාර්ථකව සුරකින ලදි",
|
"dhcp_config_saved": "ග.ධා.වි.කෙ. වින්යාසය සාර්ථකව සුරකින ලදි",
|
||||||
"dhcp_ipv4_settings": "ග.ධා.වි.කෙ. අයිපීවී 4 සැකසුම්",
|
"dhcp_ipv4_settings": "ග.ධා.වි.කෙ. අ.ජා.කෙ. 4 සැකසුම්",
|
||||||
"dhcp_ipv6_settings": "ග.ධා.වි.කෙ. අයිපීවී 6 සැකසුම්",
|
"dhcp_ipv6_settings": "ග.ධා.වි.කෙ. අ.ජා.කෙ. 6 සැකසුම්",
|
||||||
"form_error_required": "අවශ්ය ක්ෂේත්රයකි",
|
"form_error_required": "අවශ්ය ක්ෂේත්රයකි",
|
||||||
"form_error_ip4_format": "වලංගු නොවන IPv4 ආකෘතියකි",
|
"form_error_ip4_format": "වලංගු නොවන IPv4 ආකෘතියකි",
|
||||||
"form_error_ip6_format": "වලංගු නොවන IPv6 ආකෘතියකි",
|
"form_error_ip6_format": "වලංගු නොවන IPv6 ආකෘතියකි",
|
||||||
@@ -221,8 +221,8 @@
|
|||||||
"refused": "REFUSED",
|
"refused": "REFUSED",
|
||||||
"null_ip": "අභිශූන්යය අ.ජා. කෙ.",
|
"null_ip": "අභිශූන්යය අ.ජා. කෙ.",
|
||||||
"custom_ip": "අභිරුචි අ.ජා. කෙ.",
|
"custom_ip": "අභිරුචි අ.ජා. කෙ.",
|
||||||
"blocking_ipv4": "අයි.පී.වී.4 අවහිර කිරීම\n",
|
"blocking_ipv4": "අ.ජා.කෙ.4 අවහිර කිරීම",
|
||||||
"blocking_ipv6": "අයි.පී.වී.6 අවහිර කිරීම",
|
"blocking_ipv6": "අ.ජා.කෙ.6 අවහිර කිරීම",
|
||||||
"client_id": "අනුග්රාහකයේ හැඳුනුම",
|
"client_id": "අනුග්රාහකයේ හැඳුනුම",
|
||||||
"client_id_placeholder": "අනුග්රාහකයේ හැඳුනුම යොදන්න",
|
"client_id_placeholder": "අනුග්රාහකයේ හැඳුනුම යොදන්න",
|
||||||
"download_mobileconfig": "වින්යාසගත ගොනුව බාගන්න",
|
"download_mobileconfig": "වින්යාසගත ගොනුව බාගන්න",
|
||||||
@@ -230,8 +230,8 @@
|
|||||||
"form_enter_rate_limit": "අනුපාත සීමාව ඇතුල් කරන්න",
|
"form_enter_rate_limit": "අනුපාත සීමාව ඇතුල් කරන්න",
|
||||||
"rate_limit": "අනුපාත සීමාව",
|
"rate_limit": "අනුපාත සීමාව",
|
||||||
"rate_limit_desc": "එක් අනුග්රාහකයකට ඉඩ දී ඇති තත්පරයට ඉල්ලීම් ගණන. එය 0 ලෙස සැකසීම යනුවෙන් අදහස් කරන්නේ සීමාවක් නැති බවයි.",
|
"rate_limit_desc": "එක් අනුග්රාහකයකට ඉඩ දී ඇති තත්පරයට ඉල්ලීම් ගණන. එය 0 ලෙස සැකසීම යනුවෙන් අදහස් කරන්නේ සීමාවක් නැති බවයි.",
|
||||||
"blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා. කෙ. (IP) ලිපිනය",
|
"blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
||||||
"blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා. කෙ. (IP) ලිපිනය",
|
"blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
||||||
"blocking_mode_default": "පොදු: දැන්වීම් අවහිර කරන ආකාරයේ නීතියක් මගින් අවහිර කළ විට REFUSED සමඟ ප්රතිචාර දක්වයි; /etc/host-style ආකාරයේ නීතියක් මගින් අවහිර කළ විට නීතියේ දක්වා ඇති අ.ජා. කෙ. ලිපිනය සමඟ ප්රතිචාර දක්වයි",
|
"blocking_mode_default": "පොදු: දැන්වීම් අවහිර කරන ආකාරයේ නීතියක් මගින් අවහිර කළ විට REFUSED සමඟ ප්රතිචාර දක්වයි; /etc/host-style ආකාරයේ නීතියක් මගින් අවහිර කළ විට නීතියේ දක්වා ඇති අ.ජා. කෙ. ලිපිනය සමඟ ප්රතිචාර දක්වයි",
|
||||||
"blocking_mode_refused": "REFUSED: REFUSED කේතය සමඟ ප්රතිචාර දක්වයි",
|
"blocking_mode_refused": "REFUSED: REFUSED කේතය සමඟ ප්රතිචාර දක්වයි",
|
||||||
"blocking_mode_nxdomain": "නොපවතින වසම (NXDOMAIN): NXDOMAIN කේතය සමඟ ප්රතිචාර දක්වයි",
|
"blocking_mode_nxdomain": "නොපවතින වසම (NXDOMAIN): NXDOMAIN කේතය සමඟ ප්රතිචාර දක්වයි",
|
||||||
@@ -465,7 +465,7 @@
|
|||||||
"rewrite_ip_address": "අ.ජා. කෙ. ලිපිනය: මෙම අ.ජා. කෙටුම්පත A හෝ AAAA ප්රතිචාරයකට භාවිතා කරන්න",
|
"rewrite_ip_address": "අ.ජා. කෙ. ලිපිනය: මෙම අ.ජා. කෙටුම්පත A හෝ AAAA ප්රතිචාරයකට භාවිතා කරන්න",
|
||||||
"rewrite_domain_name": "වසම් නාමය: අන්. නා. (CNAME) වාර්තාවක් එක් කරන්න",
|
"rewrite_domain_name": "වසම් නාමය: අන්. නා. (CNAME) වාර්තාවක් එක් කරන්න",
|
||||||
"disable_ipv6": "IPv6 ලිපින විසඳීම අබල කරන්න",
|
"disable_ipv6": "IPv6 ලිපින විසඳීම අබල කරන්න",
|
||||||
"disable_ipv6_desc": "අ.ජා. කෙ. අනු. 6 ලිපින (AAAA වර්ගය) සඳහා වන සියලුම ව.නා.ප. විමසුම් අතහැර දමනු ලැබේ.",
|
"disable_ipv6_desc": "අ.ජා.කෙ. අනු. 6 ලිපින (AAAA වර්ගය) සඳහා වන සියලුම ව.නා.ප. විමසුම් අතහැර දමනු ලැබේ.",
|
||||||
"fastest_addr": "වේගවත්ම අන්තර්ජාල කෙටුම්පත් (IP) ලිපිනය",
|
"fastest_addr": "වේගවත්ම අන්තර්ජාල කෙටුම්පත් (IP) ලිපිනය",
|
||||||
"fastest_addr_desc": "සියලුම ව.නා.ප. සේවාදායකයන්ගෙන් විමසා සියලු ප්රතිචාර අතරින් වේගවත්ම අ.ජා. කෙ. ලිපිනය ලබා දෙයි. සියලුම ව.නා.ප. සේවාදායකයන්ගේ ප්රතිචාර සඳහා ඇඩ්ගාර්ඩ් හෝම් රැඳී සිටිය යුතු බැවින් මෙය ව.නා.ප. විමසුම් මන්දගාමී කරන නමුත් සමස්ත සම්බන්ධතාවය වැඩි දියුණු කරයි.",
|
"fastest_addr_desc": "සියලුම ව.නා.ප. සේවාදායකයන්ගෙන් විමසා සියලු ප්රතිචාර අතරින් වේගවත්ම අ.ජා. කෙ. ලිපිනය ලබා දෙයි. සියලුම ව.නා.ප. සේවාදායකයන්ගේ ප්රතිචාර සඳහා ඇඩ්ගාර්ඩ් හෝම් රැඳී සිටිය යුතු බැවින් මෙය ව.නා.ප. විමසුම් මන්දගාමී කරන නමුත් සමස්ත සම්බන්ධතාවය වැඩි දියුණු කරයි.",
|
||||||
"autofix_warning_text": "ඔබ \"නිරාකරණය කරන්න\" බොත්තම එබුවහොත්, ඔබගේ පද්ධතිය ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකය භාවිතා කිරීමට වින්යාසගත කරනු ඇත.",
|
"autofix_warning_text": "ඔබ \"නිරාකරණය කරන්න\" බොත්තම එබුවහොත්, ඔබගේ පද්ධතිය ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකය භාවිතා කිරීමට වින්යාසගත කරනු ඇත.",
|
||||||
|
|||||||
@@ -208,7 +208,7 @@
|
|||||||
"example_upstream_sdns": "môžete použiť <0>DNS pečiatky</0> pre <1>DNSCrypt</1> alebo <2>DNS-over-HTTPS</2>",
|
"example_upstream_sdns": "môžete použiť <0>DNS pečiatky</0> pre <1>DNSCrypt</1> alebo <2>DNS-over-HTTPS</2>",
|
||||||
"example_upstream_tcp": "radová DNS (cez TCP)",
|
"example_upstream_tcp": "radová DNS (cez TCP)",
|
||||||
"all_lists_up_to_date_toast": "Všetky zoznamy sú už aktuálne",
|
"all_lists_up_to_date_toast": "Všetky zoznamy sú už aktuálne",
|
||||||
"updated_upstream_dns_toast": "Aktualizované upstream DNS servery",
|
"updated_upstream_dns_toast": "Upstream servery boli úspešne uložené",
|
||||||
"dns_test_ok_toast": "Špecifikované DNS servery pracujú korektne",
|
"dns_test_ok_toast": "Špecifikované DNS servery pracujú korektne",
|
||||||
"dns_test_not_ok_toast": "Server \"{{key}}\": nemohol byť použitý, skontrolujte, či ste ho správne napísali",
|
"dns_test_not_ok_toast": "Server \"{{key}}\": nemohol byť použitý, skontrolujte, či ste ho správne napísali",
|
||||||
"unblock": "Odblokovať",
|
"unblock": "Odblokovať",
|
||||||
@@ -235,7 +235,7 @@
|
|||||||
"loading_table_status": "Načítavam...",
|
"loading_table_status": "Načítavam...",
|
||||||
"page_table_footer_text": "Stránka",
|
"page_table_footer_text": "Stránka",
|
||||||
"rows_table_footer_text": "riadky",
|
"rows_table_footer_text": "riadky",
|
||||||
"updated_custom_filtering_toast": "Aktualizované vlastné filtračné pravidlá",
|
"updated_custom_filtering_toast": "Vlastné pravidlá boli úspešne uložené",
|
||||||
"rule_removed_from_custom_filtering_toast": "Pravidlo odstránené z vlastných filtračných pravidiel: {{rule}}",
|
"rule_removed_from_custom_filtering_toast": "Pravidlo odstránené z vlastných filtračných pravidiel: {{rule}}",
|
||||||
"rule_added_to_custom_filtering_toast": "Pravidlo pridané do vlastných filtračných pravidiel: {{rule}}",
|
"rule_added_to_custom_filtering_toast": "Pravidlo pridané do vlastných filtračných pravidiel: {{rule}}",
|
||||||
"query_log_response_status": "Stav: {{value}}",
|
"query_log_response_status": "Stav: {{value}}",
|
||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Budete musieť konfigurovať Vaše zariadenia alebo smerovač, aby používali DNS server na nasledujúcich adresách:",
|
"install_settings_dns_desc": "Budete musieť konfigurovať Vaše zariadenia alebo smerovač, aby používali DNS server na nasledujúcich adresách:",
|
||||||
"install_settings_all_interfaces": "Všetky rozhrania",
|
"install_settings_all_interfaces": "Všetky rozhrania",
|
||||||
"install_auth_title": "Overenie identity",
|
"install_auth_title": "Overenie identity",
|
||||||
"install_auth_desc": "Odporúčame Vám nakonfigurovať na administrátorskom webovom rozhraní AdGuard Home overenie Vašej identity heslom. Aj keď je prístupné iba vo Vašej lokálnej sieti, je stále dôležité chrániť ho pred neobmedzeným prístupom.",
|
"install_auth_desc": "Je potrebné nakonfigurovať autentifikáciu heslom do administrátorského webového rozhrania AdGuard Home. Aj keď je AdGuard Home prístupný iba vo Vašej lokálnej sieti, je stále dôležité chrániť ho pred neobmedzeným prístupom.",
|
||||||
"install_auth_username": "Meno používateľa",
|
"install_auth_username": "Meno používateľa",
|
||||||
"install_auth_password": "Heslo",
|
"install_auth_password": "Heslo",
|
||||||
"install_auth_confirm": "Potvrdenie hesla",
|
"install_auth_confirm": "Potvrdenie hesla",
|
||||||
|
|||||||
@@ -208,7 +208,7 @@
|
|||||||
"example_upstream_sdns": "lahko uporabite <0>DNS Žige</0> za reševalce <1>DNSCrypt</1> ali <2>DNS-prek-HTTPS</2>",
|
"example_upstream_sdns": "lahko uporabite <0>DNS Žige</0> za reševalce <1>DNSCrypt</1> ali <2>DNS-prek-HTTPS</2>",
|
||||||
"example_upstream_tcp": "redni DNS (nad TCP)",
|
"example_upstream_tcp": "redni DNS (nad TCP)",
|
||||||
"all_lists_up_to_date_toast": "Vsi seznami so že posodobljeni",
|
"all_lists_up_to_date_toast": "Vsi seznami so že posodobljeni",
|
||||||
"updated_upstream_dns_toast": "Posodobljeni Zagonske strežnike DNS",
|
"updated_upstream_dns_toast": "Gorvodni trežniki so uspešno shranjeni",
|
||||||
"dns_test_ok_toast": "Navedeni strežniki DNS delujejo pravilno",
|
"dns_test_ok_toast": "Navedeni strežniki DNS delujejo pravilno",
|
||||||
"dns_test_not_ok_toast": "Ni mogoče uporabiti: strežnika \"{{key}}\". Preverite, ali ste ga pravilno napisali",
|
"dns_test_not_ok_toast": "Ni mogoče uporabiti: strežnika \"{{key}}\". Preverite, ali ste ga pravilno napisali",
|
||||||
"unblock": "Omogoči",
|
"unblock": "Omogoči",
|
||||||
@@ -235,7 +235,7 @@
|
|||||||
"loading_table_status": "Nalaganje...",
|
"loading_table_status": "Nalaganje...",
|
||||||
"page_table_footer_text": "Stran",
|
"page_table_footer_text": "Stran",
|
||||||
"rows_table_footer_text": "vrstic",
|
"rows_table_footer_text": "vrstic",
|
||||||
"updated_custom_filtering_toast": "Posodobljena pravila filtriranja po meri",
|
"updated_custom_filtering_toast": "Pravila po meri so uspešno shranjena",
|
||||||
"rule_removed_from_custom_filtering_toast": "Pravilo je odstranjeno iz pravil filtriranja po meri: {{rule}}",
|
"rule_removed_from_custom_filtering_toast": "Pravilo je odstranjeno iz pravil filtriranja po meri: {{rule}}",
|
||||||
"rule_added_to_custom_filtering_toast": "Pravilo je dodano pravilom filtriranja po meri: {{rule}}",
|
"rule_added_to_custom_filtering_toast": "Pravilo je dodano pravilom filtriranja po meri: {{rule}}",
|
||||||
"query_log_response_status": "Stanje: {{value}}",
|
"query_log_response_status": "Stanje: {{value}}",
|
||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Vaše naprave ali usmerjevalnik boste morali konfigurirati za uporabo strežnika DNS na naslednjih naslovih:",
|
"install_settings_dns_desc": "Vaše naprave ali usmerjevalnik boste morali konfigurirati za uporabo strežnika DNS na naslednjih naslovih:",
|
||||||
"install_settings_all_interfaces": "Vsi vmesniki",
|
"install_settings_all_interfaces": "Vsi vmesniki",
|
||||||
"install_auth_title": "Preverjanje pristnosti",
|
"install_auth_title": "Preverjanje pristnosti",
|
||||||
"install_auth_desc": "Zelo priporočljivo je, da konfigurirate overovitev pristnosti gesla za vaš skrbniški spletni vmesnik AdGuard Home. Tudi če je dostopen v vašem lokalnem omrežju, je še vedno pomembno, da ga zaščitite pred neomejenim dostopom.",
|
"install_auth_desc": "Nastavljeno mora biti preverjanje pristnosti gesla za skrbniški spletni vmesnik AdGuard Home. Tudi če je AdGuard Home dostopen samo v vašem lokalnem omrežju, je še vedno pomembno, da ga zaščitite pred neomejenim dostopom.",
|
||||||
"install_auth_username": "Uporabniško ime",
|
"install_auth_username": "Uporabniško ime",
|
||||||
"install_auth_password": "Geslo",
|
"install_auth_password": "Geslo",
|
||||||
"install_auth_confirm": "Potrdite geslo",
|
"install_auth_confirm": "Potrdite geslo",
|
||||||
@@ -503,6 +503,7 @@
|
|||||||
"statistics_clear_confirm": "Ali ste prepričani, da želite počistiti statistiko?",
|
"statistics_clear_confirm": "Ali ste prepričani, da želite počistiti statistiko?",
|
||||||
"statistics_retention_confirm": "Ali ste prepričani, da želite spremeniti zadrževanje statistike? Če zmanjšate vrednost intervala, bodo nekateri podatki izgubljeni",
|
"statistics_retention_confirm": "Ali ste prepričani, da želite spremeniti zadrževanje statistike? Če zmanjšate vrednost intervala, bodo nekateri podatki izgubljeni",
|
||||||
"statistics_cleared": "Statistika je bila uspešno počiščena",
|
"statistics_cleared": "Statistika je bila uspešno počiščena",
|
||||||
|
"statistics_enable": "Omogoči statistiko",
|
||||||
"interval_hours": "{{count}} ur",
|
"interval_hours": "{{count}} ur",
|
||||||
"interval_hours_plural": "{{count}} ur",
|
"interval_hours_plural": "{{count}} ur",
|
||||||
"filters_configuration": "Nastavitve filtrov",
|
"filters_configuration": "Nastavitve filtrov",
|
||||||
@@ -612,7 +613,8 @@
|
|||||||
"click_to_view_queries": "Kliknite za prikaz poizvedb",
|
"click_to_view_queries": "Kliknite za prikaz poizvedb",
|
||||||
"port_53_faq_link": "Vrata 53 pogosto zasedajo storitve 'DNSStubListener' ali 'Sistemsko razrešene storitve'. Preberite <0>to navodilo</0> o tem, kako to rešiti.",
|
"port_53_faq_link": "Vrata 53 pogosto zasedajo storitve 'DNSStubListener' ali 'Sistemsko razrešene storitve'. Preberite <0>to navodilo</0> o tem, kako to rešiti.",
|
||||||
"adg_will_drop_dns_queries": "AdGuard Home bo izpustil vse poizvedbe DNS iz tega odjemalca.",
|
"adg_will_drop_dns_queries": "AdGuard Home bo izpustil vse poizvedbe DNS iz tega odjemalca.",
|
||||||
"client_not_in_allowed_clients": "Odjemalec ni dovoljen, ker ga ni na seznamu \"Dovoljeni odjemalci\".",
|
"filter_allowlist": "OPOZORILO: S to akcijo bo pravilo \"{{disallowed_rule}}\" izključeno s seznama dovoljenih odjemalcev.",
|
||||||
|
"last_rule_in_allowlist": "Tega odjemalca ni mogoče onemogočiti, ker izključitev pravila \"{{disallowed_rule}}\" bo ONEMOGOČILO seznam 'Dovoljeni odjemalci'.",
|
||||||
"experimental": "Eksperimentalno",
|
"experimental": "Eksperimentalno",
|
||||||
"use_saved_key": "Uporabi prej shranjeni ključ"
|
"use_saved_key": "Uporabi prej shranjeni ključ"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "Cihazlarınızı veya yönlendiricinizi şu adresteki DNS sunucusunu kullanması için ayarlamanız gerekecek:",
|
"install_settings_dns_desc": "Cihazlarınızı veya yönlendiricinizi şu adresteki DNS sunucusunu kullanması için ayarlamanız gerekecek:",
|
||||||
"install_settings_all_interfaces": "Tüm arayüzler",
|
"install_settings_all_interfaces": "Tüm arayüzler",
|
||||||
"install_auth_title": "Kimlik Doğrulama",
|
"install_auth_title": "Kimlik Doğrulama",
|
||||||
"install_auth_desc": "AdGuard Home yönetici web arayüzüne erişim için kullanıcı adı ve şifre yapılandırmanız önemle tavsiye edilir. Yalnızca yerel ağınızdan erişilebilir olsa bile izinsiz erişimden korumak yine de önemlidir.",
|
"install_auth_desc": "AdGuard Home yönetim web arayüzü için şifre doğrulaması yapılandırılmalıdır. AdGuard Home'a yalnızca yerel ağınızdan erişilebilir olsa bile, onu sınırsız erişimden korumak yine de önemlidir.",
|
||||||
"install_auth_username": "Kullanıcı adı",
|
"install_auth_username": "Kullanıcı adı",
|
||||||
"install_auth_password": "Parola",
|
"install_auth_password": "Parola",
|
||||||
"install_auth_confirm": "Parolayı onayla",
|
"install_auth_confirm": "Parolayı onayla",
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "您将需要使用以下地址来设置您的设备或路由器的 DNS 服务器:",
|
"install_settings_dns_desc": "您将需要使用以下地址来设置您的设备或路由器的 DNS 服务器:",
|
||||||
"install_settings_all_interfaces": "所有接口",
|
"install_settings_all_interfaces": "所有接口",
|
||||||
"install_auth_title": "身份认证",
|
"install_auth_title": "身份认证",
|
||||||
"install_auth_desc": "我们强烈建议您为 AdGuard Home 的网页管理界面配置密码。即使该页面只能通过您的本地网络访问,但避免它被不加限制地访问仍十分重要。",
|
"install_auth_desc": "您需要对 AdGuard Home 的网页管理界面配置密码认证。即使该 AdGuard Home 只能通过您的本地网络访问,避免 AdGuard Home 被不受限制地访问依旧十分重要。",
|
||||||
"install_auth_username": "用户名",
|
"install_auth_username": "用户名",
|
||||||
"install_auth_password": "密码",
|
"install_auth_password": "密码",
|
||||||
"install_auth_confirm": "确认密码",
|
"install_auth_confirm": "确认密码",
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
"install_settings_dns_desc": "您將需要配置您的裝置或路由器以使用於下列的位址上之 DNS 伺服器:",
|
"install_settings_dns_desc": "您將需要配置您的裝置或路由器以使用於下列的位址上之 DNS 伺服器:",
|
||||||
"install_settings_all_interfaces": "所有的介面",
|
"install_settings_all_interfaces": "所有的介面",
|
||||||
"install_auth_title": "驗證",
|
"install_auth_title": "驗證",
|
||||||
"install_auth_desc": "配置屬於您的 AdGuard Home 管理員網路介面之密碼驗證是被非常建議的。即使它僅在您的區域網路中為可存取的,保護它免於不受限制的存取為仍然重要的。",
|
"install_auth_desc": "往您的 AdGuard Home 管理員網路介面之密碼驗證必須被配置。即使 AdGuard Home 僅在您的區域網路中為可存取的,保護它免於不受限制的存取為仍然重要的。",
|
||||||
"install_auth_username": "使用者名稱",
|
"install_auth_username": "使用者名稱",
|
||||||
"install_auth_password": "密碼",
|
"install_auth_password": "密碼",
|
||||||
"install_auth_confirm": "確認密碼",
|
"install_auth_confirm": "確認密碼",
|
||||||
|
|||||||
@@ -16,18 +16,31 @@ const Row = ({
|
|||||||
? <LogsSearchLink response_status={response_status}>{formatNumber(count)}</LogsSearchLink>
|
? <LogsSearchLink response_status={response_status}>{formatNumber(count)}</LogsSearchLink>
|
||||||
: count;
|
: count;
|
||||||
|
|
||||||
return <tr key={label}>
|
return (
|
||||||
<td>
|
<div className="counters__row" key={label}>
|
||||||
<Trans components={translationComponents}>{label}</Trans>
|
<div className="counters__column">
|
||||||
<Tooltip content={tooltipTitle} placement="top"
|
<span className="counters__title">
|
||||||
className="tooltip-container tooltip-custom--narrow text-center">
|
<Trans components={translationComponents}>
|
||||||
<svg className="icons icon--20 icon--lightgray ml-2">
|
{label}
|
||||||
<use xlinkHref="#question" />
|
</Trans>
|
||||||
</svg>
|
</span>
|
||||||
</Tooltip>
|
<span className="counters__tooltip">
|
||||||
</td>
|
<Tooltip
|
||||||
<td className="text-right"><strong>{content}</strong></td>
|
content={tooltipTitle}
|
||||||
</tr>;
|
placement="top"
|
||||||
|
className="tooltip-container tooltip-custom--narrow text-center"
|
||||||
|
>
|
||||||
|
<svg className="icons icon--20 icon--lightgray ml-2">
|
||||||
|
<use xlinkHref="#question" />
|
||||||
|
</svg>
|
||||||
|
</Tooltip>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="counters__column counters__column--value">
|
||||||
|
<strong>{content}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Counters = ({ refreshButton, subtitle }) => {
|
const Counters = ({ refreshButton, subtitle }) => {
|
||||||
@@ -88,9 +101,9 @@ const Counters = ({ refreshButton, subtitle }) => {
|
|||||||
bodyType="card-table"
|
bodyType="card-table"
|
||||||
refresh={refreshButton}
|
refresh={refreshButton}
|
||||||
>
|
>
|
||||||
<table className="table card-table">
|
<div className="counters">
|
||||||
<tbody>{rows.map(Row)}</tbody>
|
{rows.map(Row)}
|
||||||
</table>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -49,3 +49,39 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.counters__row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.counters__column--value {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: 1.5rem;
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 768px) {
|
||||||
|
.counters__column {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.counters__title {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.counters__tooltip {
|
||||||
|
display: block;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -3,8 +3,8 @@ module github.com/AdguardTeam/AdGuardHome
|
|||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AdguardTeam/dnsproxy v0.39.5
|
github.com/AdguardTeam/dnsproxy v0.39.8
|
||||||
github.com/AdguardTeam/golibs v0.9.2
|
github.com/AdguardTeam/golibs v0.9.3
|
||||||
github.com/AdguardTeam/urlfilter v0.14.6
|
github.com/AdguardTeam/urlfilter v0.14.6
|
||||||
github.com/NYTimes/gziphandler v1.1.1
|
github.com/NYTimes/gziphandler v1.1.1
|
||||||
github.com/ameshkov/dnscrypt/v2 v2.2.2
|
github.com/ameshkov/dnscrypt/v2 v2.2.2
|
||||||
|
|||||||
7
go.sum
7
go.sum
@@ -9,12 +9,13 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D
|
|||||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||||
github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf h1:gc042VRSIRSUzZ+Px6xQCRWNJZTaPkomisDfUZmoFNk=
|
github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf h1:gc042VRSIRSUzZ+Px6xQCRWNJZTaPkomisDfUZmoFNk=
|
||||||
github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI=
|
github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI=
|
||||||
github.com/AdguardTeam/dnsproxy v0.39.5 h1:SQorhRLR1241t6hy9CiAGZUjRULhsDJlPJTl0UGX8uw=
|
github.com/AdguardTeam/dnsproxy v0.39.8 h1:miRhkZBx/19Rs1o10r3QC0D0Zc2J2Id/cqXwfvLOyM0=
|
||||||
github.com/AdguardTeam/dnsproxy v0.39.5/go.mod h1:eDpJKAdkHORRwAedjuERv+7SWlcz4cn+5uwrbUAWHRY=
|
github.com/AdguardTeam/dnsproxy v0.39.8/go.mod h1:eDpJKAdkHORRwAedjuERv+7SWlcz4cn+5uwrbUAWHRY=
|
||||||
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
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.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||||
github.com/AdguardTeam/golibs v0.9.2 h1:H3BDFkaosxvb+UgFlNVyN66GZ+JglcZULnJ7z7PukyQ=
|
|
||||||
github.com/AdguardTeam/golibs v0.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY=
|
github.com/AdguardTeam/golibs v0.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY=
|
||||||
|
github.com/AdguardTeam/golibs v0.9.3 h1:noeKHJEzrSwxzX0Zi3USM3cXf1qQV99SO772jet/uEY=
|
||||||
|
github.com/AdguardTeam/golibs v0.9.3/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY=
|
||||||
github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
|
github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
|
||||||
github.com/AdguardTeam/urlfilter v0.14.6 h1:emqoKZElooHACYehRBYENeKVN1a/rspxiqTIMYLuoIo=
|
github.com/AdguardTeam/urlfilter v0.14.6 h1:emqoKZElooHACYehRBYENeKVN1a/rspxiqTIMYLuoIo=
|
||||||
github.com/AdguardTeam/urlfilter v0.14.6/go.mod h1:klx4JbOfc4EaNb5lWLqOwfg+pVcyRukmoJRvO55lL5U=
|
github.com/AdguardTeam/urlfilter v0.14.6/go.mod h1:klx4JbOfc4EaNb5lWLqOwfg+pVcyRukmoJRvO55lL5U=
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/digineo/go-ipset/v2"
|
"github.com/digineo/go-ipset/v2"
|
||||||
"github.com/mdlayher/netlink"
|
"github.com/mdlayher/netlink"
|
||||||
"github.com/ti-mo/netfilter"
|
"github.com/ti-mo/netfilter"
|
||||||
@@ -67,6 +68,15 @@ type ipsetProps struct {
|
|||||||
// unit is a convenient alias for struct{}.
|
// unit is a convenient alias for struct{}.
|
||||||
type unit = struct{}
|
type unit = struct{}
|
||||||
|
|
||||||
|
// ipsInIpset is the type of a set of IP-address-to-ipset mappings.
|
||||||
|
type ipsInIpset map[ipInIpsetEntry]unit
|
||||||
|
|
||||||
|
// ipInIpsetEntry is the type for entries in an ipsInIpset set.
|
||||||
|
type ipInIpsetEntry struct {
|
||||||
|
ipsetName string
|
||||||
|
ipArr [net.IPv6len]byte
|
||||||
|
}
|
||||||
|
|
||||||
// ipsetMgr is the Linux Netfilter ipset manager.
|
// ipsetMgr is the Linux Netfilter ipset manager.
|
||||||
type ipsetMgr struct {
|
type ipsetMgr struct {
|
||||||
nameToIpset map[string]ipsetProps
|
nameToIpset map[string]ipsetProps
|
||||||
@@ -82,7 +92,7 @@ type ipsetMgr struct {
|
|||||||
// are either added to all corresponding ipsets or not. When that stops
|
// are either added to all corresponding ipsets or not. When that stops
|
||||||
// being the case, for example if we add dynamic reconfiguration of
|
// being the case, for example if we add dynamic reconfiguration of
|
||||||
// ipsets, this map will need to become a per-ipset-name one.
|
// ipsets, this map will need to become a per-ipset-name one.
|
||||||
addedIPs map[[16]byte]unit
|
addedIPs ipsInIpset
|
||||||
|
|
||||||
ipv4Conn ipsetConn
|
ipv4Conn ipsetConn
|
||||||
ipv6Conn ipsetConn
|
ipv6Conn ipsetConn
|
||||||
@@ -199,7 +209,7 @@ func newIpsetMgrWithDialer(ipsetConf []string, dial ipsetDialer) (mgr IpsetManag
|
|||||||
|
|
||||||
dial: dial,
|
dial: dial,
|
||||||
|
|
||||||
addedIPs: make(map[[16]byte]unit),
|
addedIPs: make(ipsInIpset),
|
||||||
}
|
}
|
||||||
|
|
||||||
err = m.dialNetfilter(&netlink.Config{})
|
err = m.dialNetfilter(&netlink.Config{})
|
||||||
@@ -265,16 +275,19 @@ func (m *ipsetMgr) addIPs(host string, set ipsetProps, ips []net.IP) (n int, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
var entries []*ipset.Entry
|
var entries []*ipset.Entry
|
||||||
var newAddedIPs [][16]byte
|
var newAddedEntries []ipInIpsetEntry
|
||||||
for _, ip := range ips {
|
for _, ip := range ips {
|
||||||
var iparr [16]byte
|
e := ipInIpsetEntry{
|
||||||
copy(iparr[:], ip.To16())
|
ipsetName: set.name,
|
||||||
if _, added := m.addedIPs[iparr]; added {
|
}
|
||||||
|
copy(e.ipArr[:], ip.To16())
|
||||||
|
|
||||||
|
if _, added := m.addedIPs[e]; added {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
entries = append(entries, ipset.NewEntry(ipset.EntryIP(ip)))
|
entries = append(entries, ipset.NewEntry(ipset.EntryIP(ip)))
|
||||||
newAddedIPs = append(newAddedIPs, iparr)
|
newAddedEntries = append(newAddedEntries, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
n = len(entries)
|
n = len(entries)
|
||||||
@@ -299,8 +312,8 @@ func (m *ipsetMgr) addIPs(host string, set ipsetProps, ips []net.IP) (n int, err
|
|||||||
|
|
||||||
// Only add these to the cache once we're sure that all of them were
|
// Only add these to the cache once we're sure that all of them were
|
||||||
// actually sent to the ipset.
|
// actually sent to the ipset.
|
||||||
for _, iparr := range newAddedIPs {
|
for _, e := range newAddedEntries {
|
||||||
m.addedIPs[iparr] = unit{}
|
m.addedIPs[e] = unit{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return n, nil
|
return n, nil
|
||||||
@@ -330,6 +343,8 @@ func (m *ipsetMgr) addToSets(
|
|||||||
return n, fmt.Errorf("unexpected family %s for ipset %q", set.family, set.name)
|
return n, fmt.Errorf("unexpected family %s for ipset %q", set.family, set.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debug("ipset: added %d ips to set %s", nn, set.name)
|
||||||
|
|
||||||
n += nn
|
n += nn
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,6 +361,8 @@ func (m *ipsetMgr) Add(host string, ip4s, ip6s []net.IP) (n int, err error) {
|
|||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debug("ipset: found %d sets", len(sets))
|
||||||
|
|
||||||
return m.addToSets(host, ip4s, ip6s, sets)
|
return m.addToSets(host, ip4s, ip6s, sets)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ func (c *ipsetCtx) process(dctx *dnsContext) (rc resultCode) {
|
|||||||
return resultCodeSuccess
|
return resultCodeSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("ipset: added %d new ips", n)
|
log.Debug("ipset: added %d new ipset entries", n)
|
||||||
|
|
||||||
return resultCodeSuccess
|
return resultCodeSuccess
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ type fakeIpsetMgr struct {
|
|||||||
ip6s []net.IP
|
ip6s []net.IP
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add implements the aghnet.IpsetManager inteface for *fakeIpsetMgr.
|
// Add implements the aghnet.IpsetManager interface for *fakeIpsetMgr.
|
||||||
func (m *fakeIpsetMgr) Add(host string, ip4s, ip6s []net.IP) (n int, err error) {
|
func (m *fakeIpsetMgr) Add(host string, ip4s, ip6s []net.IP) (n int, err error) {
|
||||||
m.ip4s = append(m.ip4s, ip4s...)
|
m.ip4s = append(m.ip4s, ip4s...)
|
||||||
m.ip6s = append(m.ip6s, ip6s...)
|
m.ip6s = append(m.ip6s, ip6s...)
|
||||||
|
|||||||
@@ -255,10 +255,14 @@ func (d *DNSFilter) GetConfig() (s Settings) {
|
|||||||
// WriteDiskConfig - write configuration
|
// WriteDiskConfig - write configuration
|
||||||
func (d *DNSFilter) WriteDiskConfig(c *Config) {
|
func (d *DNSFilter) WriteDiskConfig(c *Config) {
|
||||||
d.confLock.Lock()
|
d.confLock.Lock()
|
||||||
|
defer d.confLock.Unlock()
|
||||||
|
|
||||||
*c = d.Config
|
*c = d.Config
|
||||||
c.Rewrites = rewriteArrayDup(d.Config.Rewrites)
|
c.Rewrites = cloneRewrites(c.Rewrites)
|
||||||
// BlockedServices
|
}
|
||||||
d.confLock.Unlock()
|
|
||||||
|
func cloneRewrites(entries []RewriteEntry) (clone []RewriteEntry) {
|
||||||
|
return append([]RewriteEntry(nil), entries...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFilters - set new filters (synchronously or asynchronously)
|
// SetFilters - set new filters (synchronously or asynchronously)
|
||||||
|
|||||||
@@ -27,8 +27,66 @@ type RewriteEntry struct {
|
|||||||
Type uint16 `yaml:"-"`
|
Type uint16 `yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RewriteEntry) equals(b RewriteEntry) bool {
|
// equal returns true if the entry is considered equal to the other.
|
||||||
return r.Domain == b.Domain && r.Answer == b.Answer
|
func (e *RewriteEntry) equal(other RewriteEntry) (ok bool) {
|
||||||
|
return e.Domain == other.Domain && e.Answer == other.Answer
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchesQType returns true if the entry matched qtype.
|
||||||
|
func (e *RewriteEntry) matchesQType(qtype uint16) (ok bool) {
|
||||||
|
// Add CNAMEs, since they match for all types requests.
|
||||||
|
if e.Type == dns.TypeCNAME {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject types other than A and AAAA.
|
||||||
|
if qtype != dns.TypeA && qtype != dns.TypeAAAA {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the types match or the entry is set to allow only the other type,
|
||||||
|
// include them.
|
||||||
|
return e.Type == qtype || e.IP == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize makes sure that the a new or decoded entry is normalized with
|
||||||
|
// regards to domain name case, IP length, and so on.
|
||||||
|
func (e *RewriteEntry) normalize() {
|
||||||
|
// TODO(a.garipov): Write a case-agnostic version of strings.HasSuffix
|
||||||
|
// and use it in matchDomainWildcard instead of using strings.ToLower
|
||||||
|
// everywhere.
|
||||||
|
e.Domain = strings.ToLower(e.Domain)
|
||||||
|
|
||||||
|
switch e.Answer {
|
||||||
|
case "AAAA":
|
||||||
|
e.IP = nil
|
||||||
|
e.Type = dns.TypeAAAA
|
||||||
|
|
||||||
|
return
|
||||||
|
case "A":
|
||||||
|
e.IP = nil
|
||||||
|
e.Type = dns.TypeA
|
||||||
|
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
// Go on.
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := net.ParseIP(e.Answer)
|
||||||
|
if ip == nil {
|
||||||
|
e.Type = dns.TypeCNAME
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ip4 := ip.To4()
|
||||||
|
if ip4 != nil {
|
||||||
|
e.IP = ip4
|
||||||
|
e.Type = dns.TypeA
|
||||||
|
} else {
|
||||||
|
e.IP = ip
|
||||||
|
e.Type = dns.TypeAAAA
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isWildcard(host string) bool {
|
func isWildcard(host string) bool {
|
||||||
@@ -78,48 +136,9 @@ func (a rewritesSorted) Less(i, j int) bool {
|
|||||||
return len(a[i].Domain) > len(a[j].Domain)
|
return len(a[i].Domain) > len(a[j].Domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare prepares the a new or decoded entry.
|
|
||||||
func (r *RewriteEntry) prepare() {
|
|
||||||
// TODO(a.garipov): Write a case-agnostic version of strings.HasSuffix
|
|
||||||
// and use it in matchDomainWildcard instead of using strings.ToLower
|
|
||||||
// everywhere.
|
|
||||||
r.Domain = strings.ToLower(r.Domain)
|
|
||||||
|
|
||||||
switch r.Answer {
|
|
||||||
case "AAAA":
|
|
||||||
r.IP = nil
|
|
||||||
r.Type = dns.TypeAAAA
|
|
||||||
|
|
||||||
return
|
|
||||||
case "A":
|
|
||||||
r.IP = nil
|
|
||||||
r.Type = dns.TypeA
|
|
||||||
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
// Go on.
|
|
||||||
}
|
|
||||||
|
|
||||||
ip := net.ParseIP(r.Answer)
|
|
||||||
if ip == nil {
|
|
||||||
r.Type = dns.TypeCNAME
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ip4 := ip.To4()
|
|
||||||
if ip4 != nil {
|
|
||||||
r.IP = ip4
|
|
||||||
r.Type = dns.TypeA
|
|
||||||
} else {
|
|
||||||
r.IP = ip
|
|
||||||
r.Type = dns.TypeAAAA
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNSFilter) prepareRewrites() {
|
func (d *DNSFilter) prepareRewrites() {
|
||||||
for i := range d.Rewrites {
|
for i := range d.Rewrites {
|
||||||
d.Rewrites[i].prepare()
|
d.Rewrites[i].normalize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,18 +146,15 @@ func (d *DNSFilter) prepareRewrites() {
|
|||||||
// CNAME, then A and AAAA; exact, then wildcard. If the host is matched
|
// CNAME, then A and AAAA; exact, then wildcard. If the host is matched
|
||||||
// exactly, wildcard entries aren't returned. If the host matched by wildcards,
|
// exactly, wildcard entries aren't returned. If the host matched by wildcards,
|
||||||
// return the most specific for the question type.
|
// return the most specific for the question type.
|
||||||
func findRewrites(a []RewriteEntry, host string, qtype uint16) []RewriteEntry {
|
func findRewrites(entries []RewriteEntry, host string, qtype uint16) (matched []RewriteEntry) {
|
||||||
rr := rewritesSorted{}
|
rr := rewritesSorted{}
|
||||||
for _, r := range a {
|
for _, e := range entries {
|
||||||
if r.Domain != host && !matchDomainWildcard(host, r.Domain) {
|
if e.Domain != host && !matchDomainWildcard(host, e.Domain) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return CNAMEs for all types requests, but only the
|
if e.matchesQType(qtype) {
|
||||||
// appropriate ones for A and AAAA.
|
rr = append(rr, e)
|
||||||
if r.Type == dns.TypeCNAME ||
|
|
||||||
(r.Type == qtype && (qtype == dns.TypeA || qtype == dns.TypeAAAA)) {
|
|
||||||
rr = append(rr, r)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,12 +185,6 @@ func max(a, b int) int {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func rewriteArrayDup(a []RewriteEntry) []RewriteEntry {
|
|
||||||
a2 := make([]RewriteEntry, len(a))
|
|
||||||
copy(a2, a)
|
|
||||||
return a2
|
|
||||||
}
|
|
||||||
|
|
||||||
type rewriteEntryJSON struct {
|
type rewriteEntryJSON struct {
|
||||||
Domain string `json:"domain"`
|
Domain string `json:"domain"`
|
||||||
Answer string `json:"answer"`
|
Answer string `json:"answer"`
|
||||||
@@ -213,7 +223,7 @@ func (d *DNSFilter) handleRewriteAdd(w http.ResponseWriter, r *http.Request) {
|
|||||||
Domain: jsent.Domain,
|
Domain: jsent.Domain,
|
||||||
Answer: jsent.Answer,
|
Answer: jsent.Answer,
|
||||||
}
|
}
|
||||||
ent.prepare()
|
ent.normalize()
|
||||||
d.confLock.Lock()
|
d.confLock.Lock()
|
||||||
d.Config.Rewrites = append(d.Config.Rewrites, ent)
|
d.Config.Rewrites = append(d.Config.Rewrites, ent)
|
||||||
d.confLock.Unlock()
|
d.confLock.Unlock()
|
||||||
@@ -238,7 +248,7 @@ func (d *DNSFilter) handleRewriteDelete(w http.ResponseWriter, r *http.Request)
|
|||||||
arr := []RewriteEntry{}
|
arr := []RewriteEntry{}
|
||||||
d.confLock.Lock()
|
d.confLock.Lock()
|
||||||
for _, ent := range d.Config.Rewrites {
|
for _, ent := range d.Config.Rewrites {
|
||||||
if ent.equals(entDel) {
|
if ent.equal(entDel) {
|
||||||
log.Debug("Rewrites: removed element: %s -> %s", ent.Domain, ent.Answer)
|
log.Debug("Rewrites: removed element: %s -> %s", ent.Domain, ent.Answer)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ func TestRewritesExceptionIP(t *testing.T) {
|
|||||||
}, {
|
}, {
|
||||||
name: "match_AAAA_host3.com",
|
name: "match_AAAA_host3.com",
|
||||||
host: "host3.com",
|
host: "host3.com",
|
||||||
want: nil,
|
want: []net.IP{},
|
||||||
dtyp: dns.TypeAAAA,
|
dtyp: dns.TypeAAAA,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ var config = &configuration{
|
|||||||
AuthBlockMin: 15,
|
AuthBlockMin: 15,
|
||||||
DNS: dnsConfig{
|
DNS: dnsConfig{
|
||||||
BindHosts: []net.IP{{0, 0, 0, 0}},
|
BindHosts: []net.IP{{0, 0, 0, 0}},
|
||||||
Port: 53,
|
Port: defaultPortDNS,
|
||||||
StatsInterval: 1,
|
StatsInterval: 1,
|
||||||
FilteringConfig: dnsforward.FilteringConfig{
|
FilteringConfig: dnsforward.FilteringConfig{
|
||||||
ProtectionEnabled: true, // whether or not use any of filtering features
|
ProtectionEnabled: true, // whether or not use any of filtering features
|
||||||
@@ -202,9 +202,9 @@ var config = &configuration{
|
|||||||
UsePrivateRDNS: true,
|
UsePrivateRDNS: true,
|
||||||
},
|
},
|
||||||
TLS: tlsConfigSettings{
|
TLS: tlsConfigSettings{
|
||||||
PortHTTPS: 443,
|
PortHTTPS: defaultPortHTTPS,
|
||||||
PortDNSOverTLS: 853, // needs to be passed through to dnsproxy
|
PortDNSOverTLS: defaultPortTLS, // needs to be passed through to dnsproxy
|
||||||
PortDNSOverQUIC: 784,
|
PortDNSOverQUIC: defaultPortQUIC,
|
||||||
},
|
},
|
||||||
logSettings: logSettings{
|
logSettings: logSettings{
|
||||||
LogCompress: false,
|
LogCompress: false,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func httpError(w http.ResponseWriter, code int, format string, args ...interface
|
|||||||
func appendDNSAddrs(dst []string, addrs ...net.IP) (res []string) {
|
func appendDNSAddrs(dst []string, addrs ...net.IP) (res []string) {
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
var hostport string
|
var hostport string
|
||||||
if config.DNS.Port != 53 {
|
if config.DNS.Port != defaultPortDNS {
|
||||||
hostport = netutil.JoinHostPort(addr.String(), config.DNS.Port)
|
hostport = netutil.JoinHostPort(addr.String(), config.DNS.Port)
|
||||||
} else {
|
} else {
|
||||||
hostport = addr.String()
|
hostport = addr.String()
|
||||||
@@ -285,8 +285,6 @@ func preInstallHandler(handler http.Handler) http.Handler {
|
|||||||
return &preInstallHandlerStruct{handler}
|
return &preInstallHandlerStruct{handler}
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultHTTPSPort = 443
|
|
||||||
|
|
||||||
// handleHTTPSRedirect redirects the request to HTTPS, if needed. If ok is
|
// handleHTTPSRedirect redirects the request to HTTPS, if needed. If ok is
|
||||||
// true, the middleware must continue handling the request.
|
// true, the middleware must continue handling the request.
|
||||||
func handleHTTPSRedirect(w http.ResponseWriter, r *http.Request) (ok bool) {
|
func handleHTTPSRedirect(w http.ResponseWriter, r *http.Request) (ok bool) {
|
||||||
@@ -304,7 +302,7 @@ func handleHTTPSRedirect(w http.ResponseWriter, r *http.Request) (ok bool) {
|
|||||||
|
|
||||||
if r.TLS == nil && web.forceHTTPS {
|
if r.TLS == nil && web.forceHTTPS {
|
||||||
hostPort := host
|
hostPort := host
|
||||||
if port := web.conf.PortHTTPS; port != defaultHTTPSPort {
|
if port := web.conf.PortHTTPS; port != defaultPortHTTPS {
|
||||||
hostPort = netutil.JoinHostPort(host, port)
|
hostPort = netutil.JoinHostPort(host, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -254,13 +254,21 @@ func (f *Filtering) handleFilteringRefresh(w http.ResponseWriter, r *http.Reques
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.controlLock.Unlock()
|
|
||||||
flags := filterRefreshBlocklists
|
flags := filterRefreshBlocklists
|
||||||
if req.White {
|
if req.White {
|
||||||
flags = filterRefreshAllowlists
|
flags = filterRefreshAllowlists
|
||||||
}
|
}
|
||||||
resp.Updated, err = f.refreshFilters(flags|filterRefreshForce, false)
|
func() {
|
||||||
Context.controlLock.Lock()
|
// Temporarily unlock the Context.controlLock because the
|
||||||
|
// f.refreshFilters waits for it to be unlocked but it's
|
||||||
|
// actually locked in ensure wrapper.
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): Reconsider this messy syncing process.
|
||||||
|
Context.controlLock.Unlock()
|
||||||
|
defer Context.controlLock.Lock()
|
||||||
|
|
||||||
|
resp.Updated, err = f.refreshFilters(flags|filterRefreshForce, false)
|
||||||
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpError(w, http.StatusInternalServerError, "%s", err)
|
httpError(w, http.StatusInternalServerError, "%s", err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ type getAddrsResponse struct {
|
|||||||
// handleInstallGetAddresses is the handler for /install/get_addresses endpoint.
|
// handleInstallGetAddresses is the handler for /install/get_addresses endpoint.
|
||||||
func (web *Web) handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) {
|
func (web *Web) handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) {
|
||||||
data := getAddrsResponse{}
|
data := getAddrsResponse{}
|
||||||
data.WebPort = 80
|
data.WebPort = defaultPortHTTP
|
||||||
data.DNSPort = 53
|
data.DNSPort = defaultPortDNS
|
||||||
|
|
||||||
ifaces, err := aghnet.GetValidNetInterfacesForWeb()
|
ifaces, err := aghnet.GetValidNetInterfacesForWeb()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -257,7 +257,8 @@ type applyConfigReq struct {
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy installation parameters between two configuration objects
|
// copyInstallSettings copies the installation parameters between two
|
||||||
|
// configuration structures.
|
||||||
func copyInstallSettings(dst, src *configuration) {
|
func copyInstallSettings(dst, src *configuration) {
|
||||||
dst.BindHost = src.BindHost
|
dst.BindHost = src.BindHost
|
||||||
dst.BindPort = src.BindPort
|
dst.BindPort = src.BindPort
|
||||||
@@ -307,7 +308,7 @@ func (web *Web) handleInstallConfigure(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var curConfig *configuration
|
curConfig := &configuration{}
|
||||||
copyInstallSettings(curConfig, config)
|
copyInstallSettings(curConfig, config)
|
||||||
|
|
||||||
Context.firstRun = false
|
Context.firstRun = false
|
||||||
@@ -552,8 +553,8 @@ type getAddrsResponseBeta struct {
|
|||||||
// functionality will appear in default handleInstallGetAddresses.
|
// functionality will appear in default handleInstallGetAddresses.
|
||||||
func (web *Web) handleInstallGetAddressesBeta(w http.ResponseWriter, r *http.Request) {
|
func (web *Web) handleInstallGetAddressesBeta(w http.ResponseWriter, r *http.Request) {
|
||||||
data := getAddrsResponseBeta{}
|
data := getAddrsResponseBeta{}
|
||||||
data.WebPort = 80
|
data.WebPort = defaultPortHTTP
|
||||||
data.DNSPort = 53
|
data.DNSPort = defaultPortDNS
|
||||||
|
|
||||||
ifaces, err := aghnet.GetValidNetInterfacesForWeb()
|
ifaces, err := aghnet.GetValidNetInterfacesForWeb()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -19,6 +19,15 @@ import (
|
|||||||
yaml "gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Default ports.
|
||||||
|
const (
|
||||||
|
defaultPortDNS = 53
|
||||||
|
defaultPortHTTP = 80
|
||||||
|
defaultPortHTTPS = 443
|
||||||
|
defaultPortQUIC = 784
|
||||||
|
defaultPortTLS = 853
|
||||||
|
)
|
||||||
|
|
||||||
// Called by other modules when configuration is changed
|
// Called by other modules when configuration is changed
|
||||||
func onConfigModified() {
|
func onConfigModified() {
|
||||||
_ = config.write()
|
_ = config.write()
|
||||||
@@ -253,7 +262,7 @@ func getDNSEncryption() (de dnsEncryption) {
|
|||||||
hostname := tlsConf.ServerName
|
hostname := tlsConf.ServerName
|
||||||
if tlsConf.PortHTTPS != 0 {
|
if tlsConf.PortHTTPS != 0 {
|
||||||
addr := hostname
|
addr := hostname
|
||||||
if tlsConf.PortHTTPS != 443 {
|
if tlsConf.PortHTTPS != defaultPortHTTPS {
|
||||||
addr = netutil.JoinHostPort(addr, tlsConf.PortHTTPS)
|
addr = netutil.JoinHostPort(addr, tlsConf.PortHTTPS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
"github.com/AdguardTeam/golibs/stringutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var nextFilterID = time.Now().Unix() // semi-stable way to generate an unique ID
|
var nextFilterID = time.Now().Unix() // semi-stable way to generate an unique ID
|
||||||
@@ -535,26 +536,85 @@ func (f *Filtering) read(reader io.Reader, tmpFile *os.File, filter *filter) (in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateIntl returns true if filter update performed successfully.
|
// finalizeUpdate closes and gets rid of temporary file f with filter's content
|
||||||
func (f *Filtering) updateIntl(filter *filter) (updated bool, err error) {
|
// according to updated. It also saves new values of flt's name, rules number
|
||||||
updated = false
|
// and checksum if sucсeeded.
|
||||||
log.Tracef("Downloading update for filter %d from %s", filter.ID, filter.URL)
|
func finalizeUpdate(
|
||||||
|
f *os.File,
|
||||||
|
flt *filter,
|
||||||
|
updated bool,
|
||||||
|
name string,
|
||||||
|
rnum int,
|
||||||
|
cs uint32,
|
||||||
|
) (err error) {
|
||||||
|
tmpFileName := f.Name()
|
||||||
|
|
||||||
tmpFile, err := os.CreateTemp(filepath.Join(Context.getDataDir(), filterDir), "")
|
// Close the file before renaming it because it's required on Windows.
|
||||||
|
//
|
||||||
|
// See https://github.com/adguardTeam/adGuardHome/issues/1553.
|
||||||
|
if err = f.Close(); err != nil {
|
||||||
|
return fmt.Errorf("closing temporary file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !updated {
|
||||||
|
log.Tracef("filter #%d from %s has no changes, skip", flt.ID, flt.URL)
|
||||||
|
|
||||||
|
return os.Remove(tmpFileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("saving filter %d contents to: %s", flt.ID, flt.Path())
|
||||||
|
|
||||||
|
if err = os.Rename(tmpFileName, flt.Path()); err != nil {
|
||||||
|
return errors.WithDeferred(err, os.Remove(tmpFileName))
|
||||||
|
}
|
||||||
|
|
||||||
|
flt.Name = stringutil.Coalesce(flt.Name, name)
|
||||||
|
flt.checksum = cs
|
||||||
|
flt.RulesCount = rnum
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// processUpdate copies filter's content from src to dst and returns the name,
|
||||||
|
// rules number, and checksum for it. It also returns the number of bytes read
|
||||||
|
// from src.
|
||||||
|
func (f *Filtering) processUpdate(
|
||||||
|
src io.Reader,
|
||||||
|
dst *os.File,
|
||||||
|
flt *filter,
|
||||||
|
) (name string, rnum int, cs uint32, n int, err error) {
|
||||||
|
if n, err = f.read(src, dst, flt); err != nil {
|
||||||
|
return "", 0, 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = dst.Seek(0, io.SeekStart); err != nil {
|
||||||
|
return "", 0, 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rnum, cs, name = f.parseFilterContents(dst)
|
||||||
|
|
||||||
|
return name, rnum, cs, n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateIntl updates the flt rewriting it's actual file. It returns true if
|
||||||
|
// the actual update has been performed.
|
||||||
|
func (f *Filtering) updateIntl(flt *filter) (ok bool, err error) {
|
||||||
|
log.Tracef("downloading update for filter %d from %s", flt.ID, flt.URL)
|
||||||
|
|
||||||
|
var name string
|
||||||
|
var rnum, n int
|
||||||
|
var cs uint32
|
||||||
|
|
||||||
|
var tmpFile *os.File
|
||||||
|
tmpFile, err = os.CreateTemp(filepath.Join(Context.getDataDir(), filterDir), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updated, err
|
return false, err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
var derr error
|
err = errors.WithDeferred(err, finalizeUpdate(tmpFile, flt, ok, name, rnum, cs))
|
||||||
if tmpFile != nil {
|
ok = ok && err == nil
|
||||||
if derr = tmpFile.Close(); derr != nil {
|
if ok {
|
||||||
log.Printf("Couldn't close temporary file: %s", derr)
|
log.Printf("updated filter %d: %d bytes, %d rules", flt.ID, n, rnum)
|
||||||
}
|
|
||||||
|
|
||||||
tmpFileName := tmpFile.Name()
|
|
||||||
if derr = os.Remove(tmpFileName); derr != nil {
|
|
||||||
log.Printf("Couldn't delete temporary file %s: %s", tmpFileName, derr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -562,72 +622,42 @@ func (f *Filtering) updateIntl(filter *filter) (updated bool, err error) {
|
|||||||
// end users.
|
// end users.
|
||||||
//
|
//
|
||||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/3198.
|
// See https://github.com/AdguardTeam/AdGuardHome/issues/3198.
|
||||||
err = tmpFile.Chmod(0o644)
|
if err = tmpFile.Chmod(0o644); err != nil {
|
||||||
if err != nil {
|
return false, fmt.Errorf("changing file mode: %w", err)
|
||||||
return updated, fmt.Errorf("changing file mode: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var reader io.Reader
|
var r io.Reader
|
||||||
if filepath.IsAbs(filter.URL) {
|
if filepath.IsAbs(flt.URL) {
|
||||||
var f io.ReadCloser
|
var file io.ReadCloser
|
||||||
f, err = os.Open(filter.URL)
|
file, err = os.Open(flt.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updated, fmt.Errorf("open file: %w", err)
|
return false, fmt.Errorf("open file: %w", err)
|
||||||
}
|
}
|
||||||
defer func() { err = errors.WithDeferred(err, f.Close()) }()
|
defer func() { err = errors.WithDeferred(err, file.Close()) }()
|
||||||
|
|
||||||
reader = f
|
r = file
|
||||||
} else {
|
} else {
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
resp, err = Context.client.Get(filter.URL)
|
resp, err = Context.client.Get(flt.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Couldn't request filter from URL %s, skipping: %s", filter.URL, err)
|
log.Printf("requesting filter from %s, skip: %s", flt.URL, err)
|
||||||
|
|
||||||
return updated, err
|
return false, err
|
||||||
}
|
}
|
||||||
defer func() { err = errors.WithDeferred(err, resp.Body.Close()) }()
|
defer func() { err = errors.WithDeferred(err, resp.Body.Close()) }()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
log.Printf("Got status code %d from URL %s, skipping", resp.StatusCode, filter.URL)
|
log.Printf("got status code %d from %s, skip", resp.StatusCode, flt.URL)
|
||||||
return updated, fmt.Errorf("got status code != 200: %d", resp.StatusCode)
|
|
||||||
|
return false, fmt.Errorf("got status code != 200: %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
reader = resp.Body
|
|
||||||
|
r = resp.Body
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err := f.read(reader, tmpFile, filter)
|
name, rnum, cs, n, err = f.processUpdate(r, tmpFile, flt)
|
||||||
if err != nil {
|
|
||||||
return updated, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract filter name and count number of rules
|
return cs != flt.checksum, err
|
||||||
_, _ = tmpFile.Seek(0, io.SeekStart)
|
|
||||||
rulesCount, checksum, filterName := f.parseFilterContents(tmpFile)
|
|
||||||
// Check if the filter has been really changed
|
|
||||||
if filter.checksum == checksum {
|
|
||||||
log.Tracef("Filter #%d at URL %s hasn't changed, not updating it", filter.ID, filter.URL)
|
|
||||||
return updated, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Filter %d has been updated: %d bytes, %d rules",
|
|
||||||
filter.ID, total, rulesCount)
|
|
||||||
if len(filter.Name) == 0 {
|
|
||||||
filter.Name = filterName
|
|
||||||
}
|
|
||||||
filter.RulesCount = rulesCount
|
|
||||||
filter.checksum = checksum
|
|
||||||
filterFilePath := filter.Path()
|
|
||||||
log.Printf("Saving filter %d contents to: %s", filter.ID, filterFilePath)
|
|
||||||
|
|
||||||
// Closing the file before renaming it is necessary on Windows
|
|
||||||
_ = tmpFile.Close()
|
|
||||||
err = os.Rename(tmpFile.Name(), filterFilePath)
|
|
||||||
if err != nil {
|
|
||||||
return updated, err
|
|
||||||
}
|
|
||||||
tmpFile = nil
|
|
||||||
updated = true
|
|
||||||
|
|
||||||
return updated, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// loads filter contents from the file in dataDir
|
// loads filter contents from the file in dataDir
|
||||||
|
|||||||
@@ -1,76 +1,118 @@
|
|||||||
package home
|
package home
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"io/fs"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testStartFilterListener(t *testing.T) net.Listener {
|
const testFltsFileName = "1.txt"
|
||||||
|
|
||||||
|
func testStartFilterListener(t *testing.T, fltContent *[]byte) (l net.Listener) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
n, werr := w.Write(*fltContent)
|
||||||
|
require.NoError(t, werr)
|
||||||
|
require.Equal(t, len(*fltContent), n)
|
||||||
|
})
|
||||||
|
|
||||||
|
var err error
|
||||||
|
l, err = net.Listen("tcp", ":0")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
_ = http.Serve(l, h)
|
||||||
|
}()
|
||||||
|
t.Cleanup(func() {
|
||||||
|
require.NoError(t, l.Close())
|
||||||
|
})
|
||||||
|
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilters(t *testing.T) {
|
||||||
const content = `||example.org^$third-party
|
const content = `||example.org^$third-party
|
||||||
# Inline comment example
|
# Inline comment example
|
||||||
||example.com^$third-party
|
||example.com^$third-party
|
||||||
0.0.0.0 example.com
|
0.0.0.0 example.com
|
||||||
`
|
`
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
fltContent := []byte(content)
|
||||||
mux.HandleFunc("/filters/1.txt", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
_, werr := w.Write([]byte(content))
|
|
||||||
assert.Nil(t, werr)
|
|
||||||
})
|
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", ":0")
|
l := testStartFilterListener(t, &fltContent)
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
_ = http.Serve(listener, mux)
|
|
||||||
}()
|
|
||||||
|
|
||||||
t.Cleanup(func() {
|
|
||||||
assert.Nil(t, listener.Close())
|
|
||||||
})
|
|
||||||
|
|
||||||
return listener
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFilters(t *testing.T) {
|
|
||||||
l := testStartFilterListener(t)
|
|
||||||
dir := t.TempDir()
|
|
||||||
|
|
||||||
Context = homeContext{
|
Context = homeContext{
|
||||||
workDir: dir,
|
workDir: t.TempDir(),
|
||||||
client: &http.Client{
|
client: &http.Client{
|
||||||
Timeout: 5 * time.Second,
|
Timeout: 5 * time.Second,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Context.filters.Init()
|
Context.filters.Init()
|
||||||
|
|
||||||
f := filter{
|
f := &filter{
|
||||||
URL: fmt.Sprintf("http://127.0.0.1:%d/filters/1.txt", l.Addr().(*net.TCPAddr).Port),
|
URL: (&url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: (&netutil.IPPort{
|
||||||
|
IP: net.IP{127, 0, 0, 1},
|
||||||
|
Port: l.Addr().(*net.TCPAddr).Port,
|
||||||
|
}).String(),
|
||||||
|
Path: path.Join(filterDir, testFltsFileName),
|
||||||
|
}).String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download.
|
updateAndAssert := func(t *testing.T, want require.BoolAssertionFunc, wantRulesCount int) {
|
||||||
ok, err := Context.filters.update(&f)
|
ok, err := Context.filters.update(f)
|
||||||
require.Nil(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, ok)
|
want(t, ok)
|
||||||
assert.Equal(t, 3, f.RulesCount)
|
|
||||||
|
|
||||||
// Refresh.
|
assert.Equal(t, wantRulesCount, f.RulesCount)
|
||||||
ok, err = Context.filters.update(&f)
|
|
||||||
require.Nil(t, err)
|
|
||||||
require.False(t, ok)
|
|
||||||
|
|
||||||
err = Context.filters.load(&f)
|
var dir []fs.DirEntry
|
||||||
require.Nil(t, err)
|
dir, err = os.ReadDir(filepath.Join(Context.getDataDir(), filterDir))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
f.unload()
|
assert.Len(t, dir, 1)
|
||||||
require.Nil(t, os.Remove(f.Path()))
|
|
||||||
|
require.FileExists(t, f.Path())
|
||||||
|
|
||||||
|
err = Context.filters.load(f)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("download", func(t *testing.T) {
|
||||||
|
updateAndAssert(t, require.True, 3)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("refresh_idle", func(t *testing.T) {
|
||||||
|
updateAndAssert(t, require.False, 3)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("refresh_actually", func(t *testing.T) {
|
||||||
|
fltContent = []byte(`||example.com^`)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
fltContent = []byte(content)
|
||||||
|
})
|
||||||
|
|
||||||
|
updateAndAssert(t, require.True, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("load_unload", func(t *testing.T) {
|
||||||
|
err := Context.filters.load(f)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
f.unload()
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, os.Remove(f.Path()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ type homeContext struct {
|
|||||||
|
|
||||||
configFilename string // Config filename (can be overridden via the command line arguments)
|
configFilename string // Config filename (can be overridden via the command line arguments)
|
||||||
workDir string // Location of our directory, used to protect against CWD being somewhere else
|
workDir string // Location of our directory, used to protect against CWD being somewhere else
|
||||||
firstRun bool // if set to true, don't run any services except HTTP web inteface, and serve only first-run html
|
firstRun bool // if set to true, don't run any services except HTTP web interface, and serve only first-run html
|
||||||
pidFileName string // PID file name. Empty if no PID file was created.
|
pidFileName string // PID file name. Empty if no PID file was created.
|
||||||
disableUpdate bool // If set, don't check for updates
|
disableUpdate bool // If set, don't check for updates
|
||||||
controlLock sync.Mutex
|
controlLock sync.Mutex
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package home
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
@@ -10,7 +11,6 @@ import (
|
|||||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/stringutil"
|
|
||||||
uuid "github.com/satori/go.uuid"
|
uuid "github.com/satori/go.uuid"
|
||||||
"howett.net/plist"
|
"howett.net/plist"
|
||||||
)
|
)
|
||||||
@@ -31,9 +31,8 @@ type dnsSettings struct {
|
|||||||
// DNSProtocol is not "TLS".
|
// DNSProtocol is not "TLS".
|
||||||
ServerName string `plist:",omitempty"`
|
ServerName string `plist:",omitempty"`
|
||||||
|
|
||||||
// ServerAddresses is a list of plain DNS server IP addresses used to
|
// ServerAddresses is a list IP addresses of the server.
|
||||||
// resolve the hostname in ServerURL or ServerName.
|
ServerAddresses []net.IP `plist:",omitempty"`
|
||||||
ServerAddresses []string `plist:",omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// payloadContent is a Device Management Profile payload.
|
// payloadContent is a Device Management Profile payload.
|
||||||
@@ -158,10 +157,19 @@ func handleMobileConfig(w http.ResponseWriter, r *http.Request, dnsp string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dnsIPs, err := collectDNSIPs()
|
||||||
|
if err != nil {
|
||||||
|
// Don't add a lot of formatting, since the error is already
|
||||||
|
// wrapped by collectDNSIPs.
|
||||||
|
respondJSONError(w, http.StatusInternalServerError, err.Error())
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
d := &dnsSettings{
|
d := &dnsSettings{
|
||||||
DNSProtocol: dnsp,
|
DNSProtocol: dnsp,
|
||||||
ServerName: host,
|
ServerName: host,
|
||||||
ServerAddresses: cloneBootstrap(),
|
ServerAddresses: dnsIPs,
|
||||||
}
|
}
|
||||||
|
|
||||||
mobileconfig, err := encodeMobileConfig(d, clientID)
|
mobileconfig, err := encodeMobileConfig(d, clientID)
|
||||||
@@ -188,14 +196,6 @@ func handleMobileConfig(w http.ResponseWriter, r *http.Request, dnsp string) {
|
|||||||
_, _ = w.Write(mobileconfig)
|
_, _ = w.Write(mobileconfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// cloneBootstrap returns a clone of the current bootstrap DNS servers.
|
|
||||||
func cloneBootstrap() (bootstrap []string) {
|
|
||||||
config.RLock()
|
|
||||||
defer config.RUnlock()
|
|
||||||
|
|
||||||
return stringutil.CloneSlice(config.DNS.BootstrapDNS)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMobileConfigDoH(w http.ResponseWriter, r *http.Request) {
|
func handleMobileConfigDoH(w http.ResponseWriter, r *http.Request) {
|
||||||
handleMobileConfig(w, r, dnsProtoHTTPS)
|
handleMobileConfig(w, r, dnsProtoHTTPS)
|
||||||
}
|
}
|
||||||
@@ -203,3 +203,25 @@ func handleMobileConfigDoH(w http.ResponseWriter, r *http.Request) {
|
|||||||
func handleMobileConfigDoT(w http.ResponseWriter, r *http.Request) {
|
func handleMobileConfigDoT(w http.ResponseWriter, r *http.Request) {
|
||||||
handleMobileConfig(w, r, dnsProtoTLS)
|
handleMobileConfig(w, r, dnsProtoTLS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// collectDNSIPs returns a slice of IP addresses the server is listening
|
||||||
|
// on, including the addresses on all interfaces in cases of unspecified IPs but
|
||||||
|
// excluding loopback addresses.
|
||||||
|
func collectDNSIPs() (ips []net.IP, err error) {
|
||||||
|
// TODO(a.garipov): This really shouldn't be a function that parses
|
||||||
|
// a list of strings. Instead, we need a function that returns this
|
||||||
|
// data as []net.IP or []*netutil.IPPort. Maybe someday.
|
||||||
|
addrs, err := collectDNSAddresses()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ip := net.ParseIP(addr)
|
||||||
|
if ip != nil && !ip.IsLoopback() {
|
||||||
|
ips = append(ips, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ips, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,42 +3,41 @@ package home
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"howett.net/plist"
|
"howett.net/plist"
|
||||||
)
|
)
|
||||||
|
|
||||||
// testBootstrapDNS are the bootstrap plain DNS server addresses for tests.
|
// setupDNSIPs is a helper that sets up the server IP address configuration for
|
||||||
var testBootstrapDNS = []string{
|
// tests and also tears it down in a cleanup function.
|
||||||
"94.140.14.14",
|
func setupDNSIPs(t testing.TB) {
|
||||||
"94.140.15.15",
|
|
||||||
}
|
|
||||||
|
|
||||||
// setupBootstraps is a helper that sets up the bootstrap plain DNS server
|
|
||||||
// configuration for tests and also tears it down in a cleanup function.
|
|
||||||
func setupBootstraps(t testing.TB) {
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
prevConfig := config
|
prevConfig := config
|
||||||
|
prevTLS := Context.tls
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
config = prevConfig
|
config = prevConfig
|
||||||
|
Context.tls = prevTLS
|
||||||
})
|
})
|
||||||
|
|
||||||
config = &configuration{
|
config = &configuration{
|
||||||
DNS: dnsConfig{
|
DNS: dnsConfig{
|
||||||
FilteringConfig: dnsforward.FilteringConfig{
|
BindHosts: []net.IP{netutil.IPv4Zero()},
|
||||||
BootstrapDNS: testBootstrapDNS,
|
Port: defaultPortDNS,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Context.tls = &TLSMod{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandleMobileConfigDoH(t *testing.T) {
|
func TestHandleMobileConfigDoH(t *testing.T) {
|
||||||
setupBootstraps(t)
|
setupDNSIPs(t)
|
||||||
|
|
||||||
t.Run("success", func(t *testing.T) {
|
t.Run("success", func(t *testing.T) {
|
||||||
r, err := http.NewRequest(http.MethodGet, "https://example.com:12345/apple/doh.mobileconfig?host=example.org", nil)
|
r, err := http.NewRequest(http.MethodGet, "https://example.com:12345/apple/doh.mobileconfig?host=example.org", nil)
|
||||||
@@ -59,7 +58,7 @@ func TestHandleMobileConfigDoH(t *testing.T) {
|
|||||||
s := mc.PayloadContent[0].DNSSettings
|
s := mc.PayloadContent[0].DNSSettings
|
||||||
require.NotNil(t, s)
|
require.NotNil(t, s)
|
||||||
|
|
||||||
assert.Equal(t, testBootstrapDNS, s.ServerAddresses)
|
assert.NotEmpty(t, s.ServerAddresses)
|
||||||
assert.Empty(t, s.ServerName)
|
assert.Empty(t, s.ServerName)
|
||||||
assert.Equal(t, "https://example.org/dns-query", s.ServerURL)
|
assert.Equal(t, "https://example.org/dns-query", s.ServerURL)
|
||||||
})
|
})
|
||||||
@@ -105,14 +104,14 @@ func TestHandleMobileConfigDoH(t *testing.T) {
|
|||||||
s := mc.PayloadContent[0].DNSSettings
|
s := mc.PayloadContent[0].DNSSettings
|
||||||
require.NotNil(t, s)
|
require.NotNil(t, s)
|
||||||
|
|
||||||
assert.Equal(t, testBootstrapDNS, s.ServerAddresses)
|
assert.NotEmpty(t, s.ServerAddresses)
|
||||||
assert.Empty(t, s.ServerName)
|
assert.Empty(t, s.ServerName)
|
||||||
assert.Equal(t, "https://example.org/dns-query/cli42", s.ServerURL)
|
assert.Equal(t, "https://example.org/dns-query/cli42", s.ServerURL)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandleMobileConfigDoT(t *testing.T) {
|
func TestHandleMobileConfigDoT(t *testing.T) {
|
||||||
setupBootstraps(t)
|
setupDNSIPs(t)
|
||||||
|
|
||||||
t.Run("success", func(t *testing.T) {
|
t.Run("success", func(t *testing.T) {
|
||||||
r, err := http.NewRequest(http.MethodGet, "https://example.com:12345/apple/dot.mobileconfig?host=example.org", nil)
|
r, err := http.NewRequest(http.MethodGet, "https://example.com:12345/apple/dot.mobileconfig?host=example.org", nil)
|
||||||
@@ -133,7 +132,7 @@ func TestHandleMobileConfigDoT(t *testing.T) {
|
|||||||
s := mc.PayloadContent[0].DNSSettings
|
s := mc.PayloadContent[0].DNSSettings
|
||||||
require.NotNil(t, s)
|
require.NotNil(t, s)
|
||||||
|
|
||||||
assert.Equal(t, testBootstrapDNS, s.ServerAddresses)
|
assert.NotEmpty(t, s.ServerAddresses)
|
||||||
assert.Equal(t, "example.org", s.ServerName)
|
assert.Equal(t, "example.org", s.ServerName)
|
||||||
assert.Empty(t, s.ServerURL)
|
assert.Empty(t, s.ServerURL)
|
||||||
})
|
})
|
||||||
@@ -180,7 +179,7 @@ func TestHandleMobileConfigDoT(t *testing.T) {
|
|||||||
s := mc.PayloadContent[0].DNSSettings
|
s := mc.PayloadContent[0].DNSSettings
|
||||||
require.NotNil(t, s)
|
require.NotNil(t, s)
|
||||||
|
|
||||||
assert.Equal(t, testBootstrapDNS, s.ServerAddresses)
|
assert.NotEmpty(t, s.ServerAddresses)
|
||||||
assert.Equal(t, "cli42.example.org", s.ServerName)
|
assert.Equal(t, "cli42.example.org", s.ServerName)
|
||||||
assert.Empty(t, s.ServerURL)
|
assert.Empty(t, s.ServerURL)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import (
|
|||||||
"github.com/kardianos/service"
|
"github.com/kardianos/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(a.garipov): Move shell templates into actual files. Either during the
|
// TODO(a.garipov): Consider moving the shell templates into actual files and
|
||||||
// v0.106.0 cycle using packr or during the following cycle using go:embed.
|
// using go:embed instead of using large string constants.
|
||||||
|
|
||||||
const (
|
const (
|
||||||
launchdStdoutPath = "/var/log/AdGuardHome.stdout.log"
|
launchdStdoutPath = "/var/log/AdGuardHome.stdout.log"
|
||||||
@@ -313,18 +313,21 @@ func configureService(c *service.Config) {
|
|||||||
// POSIX / systemd
|
// POSIX / systemd
|
||||||
|
|
||||||
// Redirect stderr and stdout to files. Make sure we always restart.
|
// Redirect stderr and stdout to files. Make sure we always restart.
|
||||||
// Start only once network is up on Linux/systemd.
|
|
||||||
c.Option["LogOutput"] = true
|
c.Option["LogOutput"] = true
|
||||||
c.Option["Restart"] = "always"
|
c.Option["Restart"] = "always"
|
||||||
c.Dependencies = []string{
|
|
||||||
"After=syslog.target network-online.target",
|
// Start only once network is up on Linux/systemd.
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
c.Dependencies = []string{
|
||||||
|
"After=syslog.target network-online.target",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use modified service file templates.
|
// Use the modified service file templates.
|
||||||
c.Option["SystemdScript"] = systemdScript
|
c.Option["SystemdScript"] = systemdScript
|
||||||
c.Option["SysvScript"] = sysvScript
|
c.Option["SysvScript"] = sysvScript
|
||||||
|
|
||||||
// On OpenWrt we're using a different type of sysvScript.
|
// Use different scripts on OpenWrt and FreeBSD.
|
||||||
if aghos.IsOpenWrt() {
|
if aghos.IsOpenWrt() {
|
||||||
c.Option["SysvScript"] = openWrtScript
|
c.Option["SysvScript"] = openWrtScript
|
||||||
} else if runtime.GOOS == "freebsd" {
|
} else if runtime.GOOS == "freebsd" {
|
||||||
@@ -392,7 +395,7 @@ ConditionFileIsExecutable={{.Path|cmdEscape}}
|
|||||||
[Service]
|
[Service]
|
||||||
StartLimitInterval=5
|
StartLimitInterval=5
|
||||||
StartLimitBurst=10
|
StartLimitBurst=10
|
||||||
ExecStartPre=mkdir -p /var/log/
|
ExecStartPre=/bin/mkdir -p /var/log/
|
||||||
ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}}
|
ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}}
|
||||||
{{if .ChRoot}}RootDirectory={{.ChRoot|cmd}}{{end}}
|
{{if .ChRoot}}RootDirectory={{.ChRoot|cmd}}{{end}}
|
||||||
{{if .WorkingDirectory}}WorkingDirectory={{.WorkingDirectory|cmdEscape}}{{end}}
|
{{if .WorkingDirectory}}WorkingDirectory={{.WorkingDirectory|cmdEscape}}{{end}}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ is_little_endian() {
|
|||||||
# machine. The required software:
|
# machine. The required software:
|
||||||
#
|
#
|
||||||
# curl
|
# curl
|
||||||
# unzip (macOS) / tar (other unices)
|
# unzip (macOS) / tar (other unixes)
|
||||||
#
|
#
|
||||||
check_required() {
|
check_required() {
|
||||||
required_darwin="unzip"
|
required_darwin="unzip"
|
||||||
@@ -426,6 +426,8 @@ download() {
|
|||||||
then
|
then
|
||||||
error_exit "cannot download the package from $url into $pkg_name"
|
error_exit "cannot download the package from $url into $pkg_name"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
log "successfully downloaded $pkg_name"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function unpack unpacks the passed archive depending on it's extension.
|
# Function unpack unpacks the passed archive depending on it's extension.
|
||||||
@@ -433,7 +435,7 @@ unpack() {
|
|||||||
log "unpacking package from $pkg_name into $out_dir"
|
log "unpacking package from $pkg_name into $out_dir"
|
||||||
if ! mkdir -p "$out_dir"
|
if ! mkdir -p "$out_dir"
|
||||||
then
|
then
|
||||||
error_exit "cannot create directory at the $out_dir"
|
error_exit "cannot create directory $out_dir"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case "$pkg_ext"
|
case "$pkg_ext"
|
||||||
@@ -449,6 +451,8 @@ unpack() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
log "successfully unpacked, contents: $( echo; ls -l -A "$agh_dir" )"
|
||||||
|
|
||||||
rm "$pkg_name"
|
rm "$pkg_name"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,6 +511,8 @@ install_service() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
log "installation failed, removing $agh_dir"
|
||||||
|
|
||||||
rm -r "$agh_dir"
|
rm -r "$agh_dir"
|
||||||
|
|
||||||
# Some devices detected to have armv7 CPU face the compatibility
|
# Some devices detected to have armv7 CPU face the compatibility
|
||||||
|
|||||||
Reference in New Issue
Block a user