Compare commits

...

16 Commits

Author SHA1 Message Date
Ildar Kamalov
02834e6b7b client: nowrap 2021-09-29 16:47:14 +03:00
Ildar Kamalov
b45162a0f2 fix: stats table layout 2021-09-29 16:28:05 +03:00
Ainar Garipov
ce0df255be Pull request: all: upd dnsproxy
Merge in DNS/adguard-home from upd-dnsproxy to master

Squashed commit of the following:

commit 83fe60a9312e8146e12dd2a93f9b443d113c1a32
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Sep 29 14:27:04 2021 +0300

    all: upd dnsproxy
2021-09-29 14:37:23 +03:00
Ainar Garipov
b735c8167c Pull request: client: upd i18n
Merge in DNS/adguard-home from upd-i18n to master

Squashed commit of the following:

commit d286164e32eb793de7bff441cc4513ecdb4fe458
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Sep 29 13:57:41 2021 +0300

    client: upd i18n
2021-09-29 14:11:05 +03:00
Eugene Burkov
2ac2ad0609 Pull request: rename dutch to nederlands
Merge in DNS/adguard-home from 3642-fix-locale-name to master

* commit '37a3666a2adcf7a820672f1b9642e7b9740bec26':
  Renamed Dutch to Nederlands in language selector
2021-09-23 13:14:05 +03:00
Franklin
37a3666a2a Renamed Dutch to Nederlands in language selector 2021-09-22 23:30:06 +02:00
Ainar Garipov
5aed8db5cf Pull request: all: imp install script logs, systemd unit file
Updates #3579.

Squashed commit of the following:

commit 9a25fe15c999b351639d4baaa556c0b6e52c3102
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Sep 22 18:09:25 2021 +0300

    all: imp install script logs, systemd unit file
2021-09-22 18:18:23 +03:00
Ainar Garipov
e1e064db59 Pull request: aghnet: fix adding entry into multiple ipsets
Updates #3638.

Squashed commit of the following:

commit f9c52176806051c2e3d5e34a440a919ca022c319
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Sep 22 14:31:46 2021 +0300

    aghnet: fix docs

commit 1167806d73ba14d0145a2d1e11cece5dbb7958aa
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Sep 22 14:26:28 2021 +0300

    all: imp docs, names

commit ba08f5c759fe4d83a4709f619fa65dffe3e9e164
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Sep 22 14:14:05 2021 +0300

    aghnet: fix adding entry into multiple ipsets
2021-09-22 14:37:40 +03:00
Ainar Garipov
b1242ee93f Pull request: client: fix wording abt auth
Updates #3619.

Squashed commit of the following:

commit 9eecd4ef235b8dce747dab3feec325b1f84f8f3d
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Sep 21 16:52:27 2021 +0300

    client: fix wording abt auth
2021-09-21 17:01:42 +03:00
Ainar Garipov
5f3131c799 Pull request: all: imp install script logs
Updates #3579.

Squashed commit of the following:

commit 0fe83fba34dc633281144ae1a8c3e7782f6995aa
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Sep 21 14:36:04 2021 +0300

    all: imp install script logs
2021-09-21 14:45:59 +03:00
Ainar Garipov
1714a986e3 Pull request: home: provide correct server addrs in mobileconfig
Updates #3607.
Updates #3568.

Squashed commit of the following:

commit a02f9788f88b3a9339a0900baa02881a77f1fb9b
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Sep 17 18:18:31 2021 +0300

    home: provide correct server addrs in mobileconfig
2021-09-17 18:31:07 +03:00
Ainar Garipov
6ac28ee8ee Pull request: home: do not add linux deps on non-linux systems
Updates #3609.

Squashed commit of the following:

commit 8f890d2806938db1aee05833d1b2ae8ff1bc9fd4
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Sep 17 16:10:09 2021 +0300

    home: do not add linux deps on non-linux systems
2021-09-17 16:24:44 +03:00
Ainar Garipov
bf1263628a Pull request: filtering: fix special values in legacy rewrites
Updates #3616.

Squashed commit of the following:

commit 06a65c3fe754f8f849f5e1648cc3d94d564bfa16
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Sep 17 14:31:06 2021 +0300

    filtering: imp docs

commit 9b6788453622ee19b0b383833e734d25e03a4d55
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Sep 17 14:22:56 2021 +0300

    filtering: fix special values in legacy rewrites
2021-09-17 14:37:55 +03:00
Eugene Burkov
176a344aee Pull request: 3567 filters update
Merge in DNS/adguard-home from 3567-old-filters to master

Updates #3567.

Squashed commit of the following:

commit d5cc419f1b01f89b2cbf40ff98b562d3498c15c2
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Sep 15 19:22:49 2021 +0300

    home: lock doc

commit 54edba6b3bd87a5e6a46c626db8eca9f4cd50858
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Sep 15 14:16:20 2021 +0300

    home: imp code, docs

commit e6dde1d3b3e3e0b196361806e77708bb797f5d29
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Sep 15 13:53:50 2021 +0300

    home: imp code, logic

commit b258b62948504e62d0e6366605dbd288f4584ada
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Sep 14 19:35:14 2021 +0300

    all: imp log of changes

commit 9b66cde852ae1741d10e54fcb1d13d9676b42436
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Sep 14 18:56:52 2021 +0300

    home: imp filter upd
2021-09-15 20:09:32 +03:00
Ainar Garipov
48b0cefb29 Pull request: home: fix install panic
Closes #3596.

Squashed commit of the following:

commit e14f8795859cf775b360d4fe2f5c1d0eebb87ba6
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Sep 14 17:49:48 2021 +0300

    home: fix install panic
2021-09-14 18:03:14 +03:00
Ainar Garipov
857f876486 Pull request: all: fix chlog typos
Merge in DNS/adguard-home from fix-chlog to master

Squashed commit of the following:

commit ccbb2bd6c1112fba4d39d0dac4e262887f94d8e6
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Sep 14 16:50:01 2021 +0300

    all: fix chlog typos
2021-09-14 16:55:15 +03:00
44 changed files with 514 additions and 303 deletions

View File

@@ -19,7 +19,7 @@
"it": "Italiano",
"ja": "日本語",
"ko": "한국어",
"nl": "Dutch",
"nl": "Nederlands",
"no": "Norsk",
"pl": "Polski",
"pt-br": "Português (BR)",

View File

@@ -10,12 +10,13 @@ and this project adheres to
## [Unreleased]
<!--
## [v0.107.0] - 2021-09-14 (APPROX.)
## [v0.107.0] - 2021-09-28 (APPROX.)
-->
### 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
through the new `fastest_timeout` field in the configuration file ([#1992]).
- 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
doesn't exist ([#3579]).
- Items in allowed clients, disallowed clients, and blocked hosts lists must
be unique ([#3419]).
- Items in allowed clients, disallowed clients, and blocked hosts lists are now
required to be unique ([#3419]).
- The TLS private key previously saved as a string isn't shown in API responses
any more ([#1898]).
anymore ([#1898]).
- Better OpenWrt detection ([#3435]).
- 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
@@ -115,7 +116,10 @@ In this release, the schema version has changed from 10 to 12.
### 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]).
- DHCP now follows RFCs more closely when it comes to response sending and
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
[#3551]: https://github.com/AdguardTeam/AdGuardHome/issues/3551
[#3564]: https://github.com/AdguardTeam/AdGuardHome/issues/3564
[#3567]: https://github.com/AdguardTeam/AdGuardHome/issues/3567
[#3568]: https://github.com/AdguardTeam/AdGuardHome/issues/3568
[#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
is now correctly named again ([#2678]).
- 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
prevent cache-related and other issues in browsers ([#2658]).
- The request body size limit is now set for HTTPS requests as well.

View File

@@ -218,6 +218,7 @@
"reset_settings": "Изтрий всички настройки",
"update_announcement": "Има нова AdGuard Home {{version}}! <0>Цъкни тук</0> за повече информация.",
"disable_ipv6": "Изключете IPv6 протокола",
"check_updates_now": "Провери за актуализации",
"show_blocked_responses": "Блокирано",
"port_53_faq_link": "Порт 53 често е зает от \"DNSStubListener\" или \"systemd-resolved\" услуги. Моля, прочетете <0>тази инструкция</0> как да решите това."
}

View File

@@ -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_all_interfaces": "Všechna rozhraní",
"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_password": "Heslo",
"install_auth_confirm": "Potvrďte heslo",

View File

@@ -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_all_interfaces": "Alle grænseflader",
"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_password": "Adgangskode",
"install_auth_confirm": "Bekræft adgangskode",

View File

@@ -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_all_interfaces": "Alle Schnittstellen",
"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_password": "Passwort",
"install_auth_confirm": "Passwort bestätigen",

View File

@@ -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_all_interfaces": "All interfaces",
"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_password": "Password",
"install_auth_confirm": "Confirm password",

View File

@@ -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_all_interfaces": "Todas las interfaces",
"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_password": "Contraseña",
"install_auth_confirm": "Confirmar contraseña",

View File

@@ -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_all_interfaces": "Toutes les interfaces",
"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_password": "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",
"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.",
"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 dinterdire ce client, car lexclusion de la règle « {{disallowed_rule}} » DÉSACTIVERA la liste des « clients autorisés ».",
"experimental": "Expérimental",
"use_saved_key": "Utiliser la clef précédemment enregistrée"

View File

@@ -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_all_interfaces": "Tutte le interfacce",
"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_password": "Password",
"install_auth_confirm": "Conferma password",

View File

@@ -306,7 +306,7 @@
"install_settings_dns_desc": "次のアドレスでDNSサーバを使用するようにあなたのデバイスまたはルータを設定する必要があります:",
"install_settings_all_interfaces": "すべてのインターフェイス",
"install_auth_title": "認証",
"install_auth_desc": "AdGuard Homeの管理ウェブインターフェースにパスワード認証を設定することを強くお勧めします。ローカルネットワークでのみアクセス可能であっても、制限のないアクセスから保護することは重要です。",
"install_auth_desc": "AdGuard Homeの管理ウェブインターフェースにパスワード認証を設定する必要があります。AdGuard Homeがローカルネットワークでのみアクセス可能であっても、制限のないアクセスから保護することは重要です。",
"install_auth_username": "ユーザ名",
"install_auth_password": "パスワード",
"install_auth_confirm": "パスワード(確認用)",
@@ -503,6 +503,7 @@
"statistics_clear_confirm": "統計を消去してもよろしいですか?",
"statistics_retention_confirm": "統計の保持を変更してもよろしいですか? 期間を短くすると、一部のデータが失われます",
"statistics_cleared": "統計の消去に成功しました",
"statistics_enable": "統計を有効にする",
"interval_hours": "{{count}}時間",
"interval_hours_plural": "{{count}}時間",
"filters_configuration": "フィルタ設定",
@@ -612,7 +613,8 @@
"click_to_view_queries": "クエリを表示するにはクリックしてください",
"port_53_faq_link": "多くの場合、ポート53は \"DNSStubListener\" または \"systemd-resolved\" サービスによって利用されています。これを解決する方法については、<0>この手順</0>をお読みください。",
"adg_will_drop_dns_queries": "AdGuard Homeは、このクライアントからすべてのDNSクエリを落とします。",
"client_not_in_allowed_clients": "「許可されたクライアントリストにないため、このクライアントは許可されていません。",
"filter_allowlist": "【注意】このアクションは、許可されたクライアントリストから「{{disallowed_rule}}」というルールも除外します。",
"last_rule_in_allowlist": "ルール「{{disallowed_rule}}」を除外すると「許可されたクライアント」リストが無効になるため、このクライアントを拒否することはできません。",
"experimental": "実験用",
"use_saved_key": "以前に保存したキーを使用する"
}

View File

@@ -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_all_interfaces": "Alle interfaces",
"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_password": "Wachtwoord",
"install_auth_confirm": "Bevestig wachtwoord",

View File

@@ -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_all_interfaces": "Wszystkie interfejsy",
"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_password": "Hasło",
"install_auth_confirm": "Potwierdź hasło",

View File

@@ -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_all_interfaces": "Todas interfaces",
"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_password": "Senha",
"install_auth_confirm": "Confirmar senha",

View File

@@ -99,10 +99,10 @@
"homepage": "Página inicial",
"report_an_issue": "Comunicar um problema",
"privacy_policy": "Política de privacidade",
"enable_protection": "Ativar protecção",
"enabled_protection": "Ativar protecção",
"disable_protection": "Desativar protecção",
"disabled_protection": "Desativar protecção",
"enable_protection": "Ativar proteção",
"enabled_protection": "Ativar proteção",
"disable_protection": "Desativar proteção",
"disabled_protection": "Desativar proteção",
"refresh_statics": "Repor estatísticas",
"dns_query": "Consultas de DNS",
"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_all_interfaces": "Todas as interfaces",
"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_password": "Palavra-passe",
"install_auth_confirm": "Confirmar palavra-passe",

View File

@@ -306,7 +306,7 @@
"install_settings_dns_desc": "Вам будет нужно настроить свои устройства или роутер на использование DNS-сервера на одном из следующих адресов:",
"install_settings_all_interfaces": "Все интерфейсы",
"install_auth_title": "Авторизация",
"install_auth_desc": "Настоятельно рекомендуется настроить аутентификацию паролем для веб-интерфейса AdGuard Home. Даже если он доступен только в вашей локальной сети, важно защитить его от неограниченного доступа.",
"install_auth_desc": "Должна быть настроена аутентификация паролем для веб-интерфейса AdGuard Home. Даже если он доступен только в вашей локальной сети, важно защитить его от неограниченного доступа.",
"install_auth_username": "Имя пользователя",
"install_auth_password": "Пароль",
"install_auth_confirm": "Подтвердить пароль",

View File

@@ -16,8 +16,8 @@
"dhcp_enable": "ග.ධා.වි.කෙ. සේවාදායකය සබල කරන්න",
"dhcp_disable": "ග.ධා.වි.කෙ. සේවාදායකය අබල කරන්න",
"dhcp_config_saved": "ග.ධා.වි.කෙ. වින්‍යාසය සාර්ථකව සුරකින ලදි",
"dhcp_ipv4_settings": "ග.ධා.වි.කෙ. අයිපීවී 4 සැකසුම්",
"dhcp_ipv6_settings": "ග.ධා.වි.කෙ. අයිපීවී 6 සැකසුම්",
"dhcp_ipv4_settings": "ග.ධා.වි.කෙ. අ.ජා.කෙ. 4 සැකසුම්",
"dhcp_ipv6_settings": "ග.ධා.වි.කෙ. අ.ජා.කෙ. 6 සැකසුම්",
"form_error_required": "අවශ්‍ය ක්ෂේත්‍රයකි",
"form_error_ip4_format": "වලංගු නොවන IPv4 ආකෘතියකි",
"form_error_ip6_format": "වලංගු නොවන IPv6 ආකෘතියකි",
@@ -221,8 +221,8 @@
"refused": "REFUSED",
"null_ip": "අභිශූන්‍යය අ.ජා. කෙ.",
"custom_ip": "අභිරුචි අ.ජා. කෙ.",
"blocking_ipv4": "අයි.පී.වී.4 අවහිර කිරීම\n",
"blocking_ipv6": "අයි.පී.වී.6 අවහිර කිරීම",
"blocking_ipv4": "අ.ජා.කෙ.4 අවහිර කිරීම",
"blocking_ipv6": "අ.ජා.කෙ.6 අවහිර කිරීම",
"client_id": "අනුග්‍රාහකයේ හැඳුනුම",
"client_id_placeholder": "අනුග්‍රාහකයේ හැඳුනුම යොදන්න",
"download_mobileconfig": "වින්‍යාසගත ගොනුව බාගන්න",
@@ -230,8 +230,8 @@
"form_enter_rate_limit": "අනුපාත සීමාව ඇතුල් කරන්න",
"rate_limit": "අනුපාත සීමාව",
"rate_limit_desc": "එක් අනුග්‍රාහකයකට ඉඩ දී ඇති තත්පරයට ඉල්ලීම් ගණන. එය 0 ලෙස සැකසීම යනුවෙන් අදහස් කරන්නේ සීමාවක් නැති බවයි.",
"blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා. කෙ. (IP) ලිපිනය",
"blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා. කෙ. (IP) ලිපිනය",
"blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
"blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
"blocking_mode_default": "පොදු: දැන්වීම් අවහිර කරන ආකාරයේ නීතියක් මගින් අවහිර කළ විට REFUSED සමඟ ප්‍රතිචාර දක්වයි; /etc/host-style ආකාරයේ නීතියක් මගින් අවහිර කළ විට නීතියේ දක්වා ඇති අ.ජා. කෙ. ලිපිනය සමඟ ප්‍රතිචාර දක්වයි",
"blocking_mode_refused": "REFUSED: REFUSED කේතය සමඟ ප්‍රතිචාර දක්වයි",
"blocking_mode_nxdomain": "නොපවතින වසම (NXDOMAIN): NXDOMAIN කේතය සමඟ ප්‍රතිචාර දක්වයි",
@@ -465,7 +465,7 @@
"rewrite_ip_address": "අ.ජා. කෙ. ලිපිනය: මෙම අ.ජා. කෙටුම්පත A හෝ AAAA ප්‍රතිචාරයකට භාවිතා කරන්න",
"rewrite_domain_name": "වසම් නාමය: අන්. නා. (CNAME) වාර්තාවක් එක් කරන්න",
"disable_ipv6": "IPv6 ලිපින විසඳීම අබල කරන්න",
"disable_ipv6_desc": "අ.ජා. කෙ. අනු. 6 ලිපින (AAAA වර්ගය) සඳහා වන සියලුම ව.නා.ප. විමසුම් අතහැර දමනු ලැබේ.",
"disable_ipv6_desc": "අ.ජා.කෙ. අනු. 6 ලිපින (AAAA වර්ගය) සඳහා වන සියලුම ව.නා.ප. විමසුම් අතහැර දමනු ලැබේ.",
"fastest_addr": "වේගවත්ම අන්තර්ජාල කෙටුම්පත් (IP) ලිපිනය",
"fastest_addr_desc": "සියලුම ව.නා.ප. සේවාදායකයන්ගෙන් විමසා සියලු ප්‍රතිචාර අතරින් වේගවත්ම අ.ජා. කෙ. ලිපිනය ලබා දෙයි. සියලුම ව.නා.ප. සේවාදායකයන්ගේ ප්‍රතිචාර සඳහා ඇඩ්ගාර්ඩ් හෝම් රැඳී සිටිය යුතු බැවින් මෙය ව.නා.ප. විමසුම් මන්දගාමී කරන නමුත් සමස්ත සම්බන්ධතාවය වැඩි දියුණු කරයි.",
"autofix_warning_text": "ඔබ \"නිරාකරණය කරන්න\" බොත්තම එබුවහොත්, ඔබගේ පද්ධතිය ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකය භාවිතා කිරීමට වින්‍යාසගත කරනු ඇත.",

View File

@@ -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_tcp": "radová DNS (cez TCP)",
"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_not_ok_toast": "Server \"{{key}}\": nemohol byť použitý, skontrolujte, či ste ho správne napísali",
"unblock": "Odblokovať",
@@ -235,7 +235,7 @@
"loading_table_status": "Načítavam...",
"page_table_footer_text": "Stránka",
"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_added_to_custom_filtering_toast": "Pravidlo pridané do vlastných filtračných pravidiel: {{rule}}",
"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_all_interfaces": "Všetky rozhrania",
"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_password": "Heslo",
"install_auth_confirm": "Potvrdenie hesla",

View File

@@ -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_tcp": "redni DNS (nad TCP)",
"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_not_ok_toast": "Ni mogoče uporabiti: strežnika \"{{key}}\". Preverite, ali ste ga pravilno napisali",
"unblock": "Omogoči",
@@ -235,7 +235,7 @@
"loading_table_status": "Nalaganje...",
"page_table_footer_text": "Stran",
"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_added_to_custom_filtering_toast": "Pravilo je dodano pravilom filtriranja po meri: {{rule}}",
"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_all_interfaces": "Vsi vmesniki",
"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_password": "Geslo",
"install_auth_confirm": "Potrdite geslo",
@@ -503,6 +503,7 @@
"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_cleared": "Statistika je bila uspešno počiščena",
"statistics_enable": "Omogoči statistiko",
"interval_hours": "{{count}} ur",
"interval_hours_plural": "{{count}} ur",
"filters_configuration": "Nastavitve filtrov",
@@ -612,7 +613,8 @@
"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.",
"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",
"use_saved_key": "Uporabi prej shranjeni ključ"
}

View File

@@ -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_all_interfaces": "Tüm arayüzler",
"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_password": "Parola",
"install_auth_confirm": "Parolayı onayla",

View File

@@ -306,7 +306,7 @@
"install_settings_dns_desc": "您将需要使用以下地址来设置您的设备或路由器的 DNS 服务器:",
"install_settings_all_interfaces": "所有接口",
"install_auth_title": "身份认证",
"install_auth_desc": "我们强烈建议您为 AdGuard Home 的网页管理界面配置密码。即使该页面只能通过您的本地网络访问,避免被不限制地访问十分重要。",
"install_auth_desc": "您需要对 AdGuard Home 的网页管理界面配置密码认证。即使该 AdGuard Home 只能通过您的本地网络访问,避免 AdGuard Home 被不限制地访问依旧十分重要。",
"install_auth_username": "用户名",
"install_auth_password": "密码",
"install_auth_confirm": "确认密码",

View File

@@ -306,7 +306,7 @@
"install_settings_dns_desc": "您將需要配置您的裝置或路由器以使用於下列的位址上之 DNS 伺服器:",
"install_settings_all_interfaces": "所有的介面",
"install_auth_title": "驗證",
"install_auth_desc": "配置屬於您的 AdGuard Home 管理員網路介面之密碼驗證是被非常建議的。即使它僅在您的區域網路中為可存取的,保護它免於不受限制的存取為仍然重要的。",
"install_auth_desc": "您的 AdGuard Home 管理員網路介面之密碼驗證必須被配置。即使 AdGuard Home 僅在您的區域網路中為可存取的,保護它免於不受限制的存取為仍然重要的。",
"install_auth_username": "使用者名稱",
"install_auth_password": "密碼",
"install_auth_confirm": "確認密碼",

View File

@@ -16,18 +16,31 @@ const Row = ({
? <LogsSearchLink response_status={response_status}>{formatNumber(count)}</LogsSearchLink>
: count;
return <tr key={label}>
<td>
<Trans components={translationComponents}>{label}</Trans>
<Tooltip content={tooltipTitle} placement="top"
className="tooltip-container tooltip-custom--narrow text-center">
<svg className="icons icon--20 icon--lightgray ml-2">
<use xlinkHref="#question" />
</svg>
</Tooltip>
</td>
<td className="text-right"><strong>{content}</strong></td>
</tr>;
return (
<div className="counters__row" key={label}>
<div className="counters__column">
<span className="counters__title">
<Trans components={translationComponents}>
{label}
</Trans>
</span>
<span className="counters__tooltip">
<Tooltip
content={tooltipTitle}
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 }) => {
@@ -88,9 +101,9 @@ const Counters = ({ refreshButton, subtitle }) => {
bodyType="card-table"
refresh={refreshButton}
>
<table className="table card-table">
<tbody>{rows.map(Row)}</tbody>
</table>
<div className="counters">
{rows.map(Row)}
</div>
</Card>
);
};

View File

@@ -49,3 +49,39 @@
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
View File

@@ -3,8 +3,8 @@ module github.com/AdguardTeam/AdGuardHome
go 1.16
require (
github.com/AdguardTeam/dnsproxy v0.39.5
github.com/AdguardTeam/golibs v0.9.2
github.com/AdguardTeam/dnsproxy v0.39.8
github.com/AdguardTeam/golibs v0.9.3
github.com/AdguardTeam/urlfilter v0.14.6
github.com/NYTimes/gziphandler v1.1.1
github.com/ameshkov/dnscrypt/v2 v2.2.2

7
go.sum
View File

@@ -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=
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/dnsproxy v0.39.5 h1:SQorhRLR1241t6hy9CiAGZUjRULhsDJlPJTl0UGX8uw=
github.com/AdguardTeam/dnsproxy v0.39.5/go.mod h1:eDpJKAdkHORRwAedjuERv+7SWlcz4cn+5uwrbUAWHRY=
github.com/AdguardTeam/dnsproxy v0.39.8 h1:miRhkZBx/19Rs1o10r3QC0D0Zc2J2Id/cqXwfvLOyM0=
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.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.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/urlfilter v0.14.6 h1:emqoKZElooHACYehRBYENeKVN1a/rspxiqTIMYLuoIo=
github.com/AdguardTeam/urlfilter v0.14.6/go.mod h1:klx4JbOfc4EaNb5lWLqOwfg+pVcyRukmoJRvO55lL5U=

View File

@@ -10,6 +10,7 @@ import (
"sync"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/digineo/go-ipset/v2"
"github.com/mdlayher/netlink"
"github.com/ti-mo/netfilter"
@@ -67,6 +68,15 @@ type ipsetProps struct {
// unit is a convenient alias for 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.
type ipsetMgr struct {
nameToIpset map[string]ipsetProps
@@ -82,7 +92,7 @@ type ipsetMgr struct {
// are either added to all corresponding ipsets or not. When that stops
// being the case, for example if we add dynamic reconfiguration of
// ipsets, this map will need to become a per-ipset-name one.
addedIPs map[[16]byte]unit
addedIPs ipsInIpset
ipv4Conn ipsetConn
ipv6Conn ipsetConn
@@ -199,7 +209,7 @@ func newIpsetMgrWithDialer(ipsetConf []string, dial ipsetDialer) (mgr IpsetManag
dial: dial,
addedIPs: make(map[[16]byte]unit),
addedIPs: make(ipsInIpset),
}
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 newAddedIPs [][16]byte
var newAddedEntries []ipInIpsetEntry
for _, ip := range ips {
var iparr [16]byte
copy(iparr[:], ip.To16())
if _, added := m.addedIPs[iparr]; added {
e := ipInIpsetEntry{
ipsetName: set.name,
}
copy(e.ipArr[:], ip.To16())
if _, added := m.addedIPs[e]; added {
continue
}
entries = append(entries, ipset.NewEntry(ipset.EntryIP(ip)))
newAddedIPs = append(newAddedIPs, iparr)
newAddedEntries = append(newAddedEntries, e)
}
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
// actually sent to the ipset.
for _, iparr := range newAddedIPs {
m.addedIPs[iparr] = unit{}
for _, e := range newAddedEntries {
m.addedIPs[e] = unit{}
}
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)
}
log.Debug("ipset: added %d ips to set %s", nn, set.name)
n += nn
}
@@ -346,6 +361,8 @@ func (m *ipsetMgr) Add(host string, ip4s, ip6s []net.IP) (n int, err error) {
return 0, nil
}
log.Debug("ipset: found %d sets", len(sets))
return m.addToSets(host, ip4s, ip6s, sets)
}

View File

@@ -131,7 +131,7 @@ func (c *ipsetCtx) process(dctx *dnsContext) (rc resultCode) {
return resultCodeSuccess
}
log.Debug("ipset: added %d new ips", n)
log.Debug("ipset: added %d new ipset entries", n)
return resultCodeSuccess
}

View File

@@ -15,7 +15,7 @@ type fakeIpsetMgr struct {
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) {
m.ip4s = append(m.ip4s, ip4s...)
m.ip6s = append(m.ip6s, ip6s...)

View File

@@ -255,10 +255,14 @@ func (d *DNSFilter) GetConfig() (s Settings) {
// WriteDiskConfig - write configuration
func (d *DNSFilter) WriteDiskConfig(c *Config) {
d.confLock.Lock()
defer d.confLock.Unlock()
*c = d.Config
c.Rewrites = rewriteArrayDup(d.Config.Rewrites)
// BlockedServices
d.confLock.Unlock()
c.Rewrites = cloneRewrites(c.Rewrites)
}
func cloneRewrites(entries []RewriteEntry) (clone []RewriteEntry) {
return append([]RewriteEntry(nil), entries...)
}
// SetFilters - set new filters (synchronously or asynchronously)

View File

@@ -27,8 +27,66 @@ type RewriteEntry struct {
Type uint16 `yaml:"-"`
}
func (r *RewriteEntry) equals(b RewriteEntry) bool {
return r.Domain == b.Domain && r.Answer == b.Answer
// equal returns true if the entry is considered equal to the other.
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 {
@@ -78,48 +136,9 @@ func (a rewritesSorted) Less(i, j int) bool {
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() {
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
// exactly, wildcard entries aren't returned. If the host matched by wildcards,
// 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{}
for _, r := range a {
if r.Domain != host && !matchDomainWildcard(host, r.Domain) {
for _, e := range entries {
if e.Domain != host && !matchDomainWildcard(host, e.Domain) {
continue
}
// Return CNAMEs for all types requests, but only the
// appropriate ones for A and AAAA.
if r.Type == dns.TypeCNAME ||
(r.Type == qtype && (qtype == dns.TypeA || qtype == dns.TypeAAAA)) {
rr = append(rr, r)
if e.matchesQType(qtype) {
rr = append(rr, e)
}
}
@@ -169,12 +185,6 @@ func max(a, b int) int {
return b
}
func rewriteArrayDup(a []RewriteEntry) []RewriteEntry {
a2 := make([]RewriteEntry, len(a))
copy(a2, a)
return a2
}
type rewriteEntryJSON struct {
Domain string `json:"domain"`
Answer string `json:"answer"`
@@ -213,7 +223,7 @@ func (d *DNSFilter) handleRewriteAdd(w http.ResponseWriter, r *http.Request) {
Domain: jsent.Domain,
Answer: jsent.Answer,
}
ent.prepare()
ent.normalize()
d.confLock.Lock()
d.Config.Rewrites = append(d.Config.Rewrites, ent)
d.confLock.Unlock()
@@ -238,7 +248,7 @@ func (d *DNSFilter) handleRewriteDelete(w http.ResponseWriter, r *http.Request)
arr := []RewriteEntry{}
d.confLock.Lock()
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)
continue
}

View File

@@ -316,7 +316,7 @@ func TestRewritesExceptionIP(t *testing.T) {
}, {
name: "match_AAAA_host3.com",
host: "host3.com",
want: nil,
want: []net.IP{},
dtyp: dns.TypeAAAA,
}}

View File

@@ -173,7 +173,7 @@ var config = &configuration{
AuthBlockMin: 15,
DNS: dnsConfig{
BindHosts: []net.IP{{0, 0, 0, 0}},
Port: 53,
Port: defaultPortDNS,
StatsInterval: 1,
FilteringConfig: dnsforward.FilteringConfig{
ProtectionEnabled: true, // whether or not use any of filtering features
@@ -202,9 +202,9 @@ var config = &configuration{
UsePrivateRDNS: true,
},
TLS: tlsConfigSettings{
PortHTTPS: 443,
PortDNSOverTLS: 853, // needs to be passed through to dnsproxy
PortDNSOverQUIC: 784,
PortHTTPS: defaultPortHTTPS,
PortDNSOverTLS: defaultPortTLS, // needs to be passed through to dnsproxy
PortDNSOverQUIC: defaultPortQUIC,
},
logSettings: logSettings{
LogCompress: false,

View File

@@ -39,7 +39,7 @@ func httpError(w http.ResponseWriter, code int, format string, args ...interface
func appendDNSAddrs(dst []string, addrs ...net.IP) (res []string) {
for _, addr := range addrs {
var hostport string
if config.DNS.Port != 53 {
if config.DNS.Port != defaultPortDNS {
hostport = netutil.JoinHostPort(addr.String(), config.DNS.Port)
} else {
hostport = addr.String()
@@ -285,8 +285,6 @@ func preInstallHandler(handler http.Handler) http.Handler {
return &preInstallHandlerStruct{handler}
}
const defaultHTTPSPort = 443
// handleHTTPSRedirect redirects the request to HTTPS, if needed. If ok is
// true, the middleware must continue handling the request.
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 {
hostPort := host
if port := web.conf.PortHTTPS; port != defaultHTTPSPort {
if port := web.conf.PortHTTPS; port != defaultPortHTTPS {
hostPort = netutil.JoinHostPort(host, port)
}

View File

@@ -254,13 +254,21 @@ func (f *Filtering) handleFilteringRefresh(w http.ResponseWriter, r *http.Reques
return
}
Context.controlLock.Unlock()
flags := filterRefreshBlocklists
if req.White {
flags = filterRefreshAllowlists
}
resp.Updated, err = f.refreshFilters(flags|filterRefreshForce, false)
Context.controlLock.Lock()
func() {
// 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 {
httpError(w, http.StatusInternalServerError, "%s", err)
return

View File

@@ -29,8 +29,8 @@ type getAddrsResponse struct {
// handleInstallGetAddresses is the handler for /install/get_addresses endpoint.
func (web *Web) handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) {
data := getAddrsResponse{}
data.WebPort = 80
data.DNSPort = 53
data.WebPort = defaultPortHTTP
data.DNSPort = defaultPortDNS
ifaces, err := aghnet.GetValidNetInterfacesForWeb()
if err != nil {
@@ -257,7 +257,8 @@ type applyConfigReq struct {
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) {
dst.BindHost = src.BindHost
dst.BindPort = src.BindPort
@@ -307,7 +308,7 @@ func (web *Web) handleInstallConfigure(w http.ResponseWriter, r *http.Request) {
return
}
var curConfig *configuration
curConfig := &configuration{}
copyInstallSettings(curConfig, config)
Context.firstRun = false
@@ -552,8 +553,8 @@ type getAddrsResponseBeta struct {
// functionality will appear in default handleInstallGetAddresses.
func (web *Web) handleInstallGetAddressesBeta(w http.ResponseWriter, r *http.Request) {
data := getAddrsResponseBeta{}
data.WebPort = 80
data.DNSPort = 53
data.WebPort = defaultPortHTTP
data.DNSPort = defaultPortDNS
ifaces, err := aghnet.GetValidNetInterfacesForWeb()
if err != nil {

View File

@@ -19,6 +19,15 @@ import (
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
func onConfigModified() {
_ = config.write()
@@ -253,7 +262,7 @@ func getDNSEncryption() (de dnsEncryption) {
hostname := tlsConf.ServerName
if tlsConf.PortHTTPS != 0 {
addr := hostname
if tlsConf.PortHTTPS != 443 {
if tlsConf.PortHTTPS != defaultPortHTTPS {
addr = netutil.JoinHostPort(addr, tlsConf.PortHTTPS)
}

View File

@@ -18,6 +18,7 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
)
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.
func (f *Filtering) updateIntl(filter *filter) (updated bool, err error) {
updated = false
log.Tracef("Downloading update for filter %d from %s", filter.ID, filter.URL)
// finalizeUpdate closes and gets rid of temporary file f with filter's content
// according to updated. It also saves new values of flt's name, rules number
// and checksum if sucсeeded.
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 {
return updated, err
return false, err
}
defer func() {
var derr error
if tmpFile != nil {
if derr = tmpFile.Close(); derr != nil {
log.Printf("Couldn't close temporary file: %s", derr)
}
tmpFileName := tmpFile.Name()
if derr = os.Remove(tmpFileName); derr != nil {
log.Printf("Couldn't delete temporary file %s: %s", tmpFileName, derr)
}
err = errors.WithDeferred(err, finalizeUpdate(tmpFile, flt, ok, name, rnum, cs))
ok = ok && err == nil
if ok {
log.Printf("updated filter %d: %d bytes, %d rules", flt.ID, n, rnum)
}
}()
@@ -562,72 +622,42 @@ func (f *Filtering) updateIntl(filter *filter) (updated bool, err error) {
// end users.
//
// See https://github.com/AdguardTeam/AdGuardHome/issues/3198.
err = tmpFile.Chmod(0o644)
if err != nil {
return updated, fmt.Errorf("changing file mode: %w", err)
if err = tmpFile.Chmod(0o644); err != nil {
return false, fmt.Errorf("changing file mode: %w", err)
}
var reader io.Reader
if filepath.IsAbs(filter.URL) {
var f io.ReadCloser
f, err = os.Open(filter.URL)
var r io.Reader
if filepath.IsAbs(flt.URL) {
var file io.ReadCloser
file, err = os.Open(flt.URL)
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 {
var resp *http.Response
resp, err = Context.client.Get(filter.URL)
resp, err = Context.client.Get(flt.URL)
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()) }()
if resp.StatusCode != http.StatusOK {
log.Printf("Got status code %d from URL %s, skipping", resp.StatusCode, filter.URL)
return updated, fmt.Errorf("got status code != 200: %d", resp.StatusCode)
log.Printf("got status code %d from %s, skip", resp.StatusCode, flt.URL)
return false, fmt.Errorf("got status code != 200: %d", resp.StatusCode)
}
reader = resp.Body
r = resp.Body
}
total, err := f.read(reader, tmpFile, filter)
if err != nil {
return updated, err
}
name, rnum, cs, n, err = f.processUpdate(r, tmpFile, flt)
// Extract filter name and count number of rules
_, _ = 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
return cs != flt.checksum, err
}
// loads filter contents from the file in dataDir

View File

@@ -1,76 +1,118 @@
package home
import (
"fmt"
"io/fs"
"net"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"testing"
"time"
"github.com/AdguardTeam/golibs/netutil"
"github.com/stretchr/testify/assert"
"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()
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
# Inline comment example
||example.com^$third-party
0.0.0.0 example.com
`
mux := http.NewServeMux()
mux.HandleFunc("/filters/1.txt", func(w http.ResponseWriter, r *http.Request) {
_, werr := w.Write([]byte(content))
assert.Nil(t, werr)
})
fltContent := []byte(content)
listener, err := net.Listen("tcp", ":0")
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()
l := testStartFilterListener(t, &fltContent)
Context = homeContext{
workDir: dir,
workDir: t.TempDir(),
client: &http.Client{
Timeout: 5 * time.Second,
},
}
Context.filters.Init()
f := filter{
URL: fmt.Sprintf("http://127.0.0.1:%d/filters/1.txt", l.Addr().(*net.TCPAddr).Port),
f := &filter{
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.
ok, err := Context.filters.update(&f)
require.Nil(t, err)
require.True(t, ok)
assert.Equal(t, 3, f.RulesCount)
updateAndAssert := func(t *testing.T, want require.BoolAssertionFunc, wantRulesCount int) {
ok, err := Context.filters.update(f)
require.NoError(t, err)
want(t, ok)
// Refresh.
ok, err = Context.filters.update(&f)
require.Nil(t, err)
require.False(t, ok)
assert.Equal(t, wantRulesCount, f.RulesCount)
err = Context.filters.load(&f)
require.Nil(t, err)
var dir []fs.DirEntry
dir, err = os.ReadDir(filepath.Join(Context.getDataDir(), filterDir))
require.NoError(t, err)
f.unload()
require.Nil(t, os.Remove(f.Path()))
assert.Len(t, dir, 1)
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()))
}

View File

@@ -69,7 +69,7 @@ type homeContext struct {
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
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.
disableUpdate bool // If set, don't check for updates
controlLock sync.Mutex

View File

@@ -3,6 +3,7 @@ package home
import (
"encoding/json"
"fmt"
"net"
"net/http"
"net/url"
"path"
@@ -10,7 +11,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
uuid "github.com/satori/go.uuid"
"howett.net/plist"
)
@@ -31,9 +31,8 @@ type dnsSettings struct {
// DNSProtocol is not "TLS".
ServerName string `plist:",omitempty"`
// ServerAddresses is a list of plain DNS server IP addresses used to
// resolve the hostname in ServerURL or ServerName.
ServerAddresses []string `plist:",omitempty"`
// ServerAddresses is a list IP addresses of the server.
ServerAddresses []net.IP `plist:",omitempty"`
}
// 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{
DNSProtocol: dnsp,
ServerName: host,
ServerAddresses: cloneBootstrap(),
ServerAddresses: dnsIPs,
}
mobileconfig, err := encodeMobileConfig(d, clientID)
@@ -188,14 +196,6 @@ func handleMobileConfig(w http.ResponseWriter, r *http.Request, dnsp string) {
_, _ = 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) {
handleMobileConfig(w, r, dnsProtoHTTPS)
}
@@ -203,3 +203,25 @@ func handleMobileConfigDoH(w http.ResponseWriter, r *http.Request) {
func handleMobileConfigDoT(w http.ResponseWriter, r *http.Request) {
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
}

View File

@@ -3,42 +3,41 @@ package home
import (
"bytes"
"encoding/json"
"net"
"net/http"
"net/http/httptest"
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/golibs/netutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"howett.net/plist"
)
// testBootstrapDNS are the bootstrap plain DNS server addresses for tests.
var testBootstrapDNS = []string{
"94.140.14.14",
"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) {
// setupDNSIPs is a helper that sets up the server IP address configuration for
// tests and also tears it down in a cleanup function.
func setupDNSIPs(t testing.TB) {
t.Helper()
prevConfig := config
prevTLS := Context.tls
t.Cleanup(func() {
config = prevConfig
Context.tls = prevTLS
})
config = &configuration{
DNS: dnsConfig{
FilteringConfig: dnsforward.FilteringConfig{
BootstrapDNS: testBootstrapDNS,
},
BindHosts: []net.IP{netutil.IPv4Zero()},
Port: defaultPortDNS,
},
}
Context.tls = &TLSMod{}
}
func TestHandleMobileConfigDoH(t *testing.T) {
setupBootstraps(t)
setupDNSIPs(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)
@@ -59,7 +58,7 @@ func TestHandleMobileConfigDoH(t *testing.T) {
s := mc.PayloadContent[0].DNSSettings
require.NotNil(t, s)
assert.Equal(t, testBootstrapDNS, s.ServerAddresses)
assert.NotEmpty(t, s.ServerAddresses)
assert.Empty(t, s.ServerName)
assert.Equal(t, "https://example.org/dns-query", s.ServerURL)
})
@@ -105,14 +104,14 @@ func TestHandleMobileConfigDoH(t *testing.T) {
s := mc.PayloadContent[0].DNSSettings
require.NotNil(t, s)
assert.Equal(t, testBootstrapDNS, s.ServerAddresses)
assert.NotEmpty(t, s.ServerAddresses)
assert.Empty(t, s.ServerName)
assert.Equal(t, "https://example.org/dns-query/cli42", s.ServerURL)
})
}
func TestHandleMobileConfigDoT(t *testing.T) {
setupBootstraps(t)
setupDNSIPs(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)
@@ -133,7 +132,7 @@ func TestHandleMobileConfigDoT(t *testing.T) {
s := mc.PayloadContent[0].DNSSettings
require.NotNil(t, s)
assert.Equal(t, testBootstrapDNS, s.ServerAddresses)
assert.NotEmpty(t, s.ServerAddresses)
assert.Equal(t, "example.org", s.ServerName)
assert.Empty(t, s.ServerURL)
})
@@ -180,7 +179,7 @@ func TestHandleMobileConfigDoT(t *testing.T) {
s := mc.PayloadContent[0].DNSSettings
require.NotNil(t, s)
assert.Equal(t, testBootstrapDNS, s.ServerAddresses)
assert.NotEmpty(t, s.ServerAddresses)
assert.Equal(t, "cli42.example.org", s.ServerName)
assert.Empty(t, s.ServerURL)
})

View File

@@ -17,8 +17,8 @@ import (
"github.com/kardianos/service"
)
// TODO(a.garipov): Move shell templates into actual files. Either during the
// v0.106.0 cycle using packr or during the following cycle using go:embed.
// TODO(a.garipov): Consider moving the shell templates into actual files and
// using go:embed instead of using large string constants.
const (
launchdStdoutPath = "/var/log/AdGuardHome.stdout.log"
@@ -313,18 +313,21 @@ func configureService(c *service.Config) {
// POSIX / systemd
// 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["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["SysvScript"] = sysvScript
// On OpenWrt we're using a different type of sysvScript.
// Use different scripts on OpenWrt and FreeBSD.
if aghos.IsOpenWrt() {
c.Option["SysvScript"] = openWrtScript
} else if runtime.GOOS == "freebsd" {
@@ -392,7 +395,7 @@ ConditionFileIsExecutable={{.Path|cmdEscape}}
[Service]
StartLimitInterval=5
StartLimitBurst=10
ExecStartPre=mkdir -p /var/log/
ExecStartPre=/bin/mkdir -p /var/log/
ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}}
{{if .ChRoot}}RootDirectory={{.ChRoot|cmd}}{{end}}
{{if .WorkingDirectory}}WorkingDirectory={{.WorkingDirectory|cmdEscape}}{{end}}

View File

@@ -47,7 +47,7 @@ is_little_endian() {
# machine. The required software:
#
# curl
# unzip (macOS) / tar (other unices)
# unzip (macOS) / tar (other unixes)
#
check_required() {
required_darwin="unzip"
@@ -426,6 +426,8 @@ download() {
then
error_exit "cannot download the package from $url into $pkg_name"
fi
log "successfully downloaded $pkg_name"
}
# 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"
if ! mkdir -p "$out_dir"
then
error_exit "cannot create directory at the $out_dir"
error_exit "cannot create directory $out_dir"
fi
case "$pkg_ext"
@@ -449,6 +451,8 @@ unpack() {
;;
esac
log "successfully unpacked, contents: $( echo; ls -l -A "$agh_dir" )"
rm "$pkg_name"
}
@@ -507,6 +511,8 @@ install_service() {
return 0
fi
log "installation failed, removing $agh_dir"
rm -r "$agh_dir"
# Some devices detected to have armv7 CPU face the compatibility