Compare commits
27 Commits
fix-templa
...
beta-v0.10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dda513fe82 | ||
|
|
13e0124dec | ||
|
|
f716b2b3f5 | ||
|
|
031e61305d | ||
|
|
b1b2f4a233 | ||
|
|
4921a325e2 | ||
|
|
d36f95a2b0 | ||
|
|
1d61f50fc8 | ||
|
|
d747ae36ca | ||
|
|
4e31610d7b | ||
|
|
3953ca50e6 | ||
|
|
f7e4e998cf | ||
|
|
e301480401 | ||
|
|
caa90b0340 | ||
|
|
81a5225622 | ||
|
|
199e1f6a60 | ||
|
|
66d47b1462 | ||
|
|
e1ac2590c9 | ||
|
|
7696afd03c | ||
|
|
3d48ec4555 | ||
|
|
e576a23dd1 | ||
|
|
e0c839f105 | ||
|
|
49a0b90795 | ||
|
|
ee3b34ecb1 | ||
|
|
351d793b96 | ||
|
|
d59938d254 | ||
|
|
5b9bbce55d |
71
CHANGELOG.md
71
CHANGELOG.md
@@ -10,12 +10,65 @@ and this project adheres to
|
||||
## [Unreleased]
|
||||
|
||||
<!--
|
||||
## [v0.107.0] - 2021-06-21 (APPROX.)
|
||||
## [v0.107.0] - 2021-06-28 (APPROX.)
|
||||
-->
|
||||
|
||||
<!--
|
||||
## [v0.106.1] - 2021-05-17 (APPROX.)
|
||||
-->
|
||||
## [v0.106.3] - 2021-05-19
|
||||
|
||||
### Added
|
||||
|
||||
- Support for reinstall (`-r`) and uninstall (`-u`) flags in the installation
|
||||
script ([#2462]).
|
||||
- Support for DHCP `DECLINE` and `RELEASE` message types ([#3053]).
|
||||
|
||||
### Changed
|
||||
|
||||
- Add microseconds to log output.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Intermittent "Warning: ID mismatch" errors ([#3087]).
|
||||
- Error when using installation script on some ARMv7 devices ([#2542]).
|
||||
- DHCP leases validation ([#3107], [#3127]).
|
||||
- Local PTR request recursion in Docker containers ([#3064]).
|
||||
- Ignoring client-specific filtering settings when filtering is disabled in
|
||||
general settings ([#2875]).
|
||||
- Disallowed domains are now case-insensitive ([#3115]).
|
||||
|
||||
[#2462]: https://github.com/AdguardTeam/AdGuardHome/issues/2462
|
||||
[#2542]: https://github.com/AdguardTeam/AdGuardHome/issues/2542
|
||||
[#2875]: https://github.com/AdguardTeam/AdGuardHome/issues/2875
|
||||
[#3053]: https://github.com/AdguardTeam/AdGuardHome/issues/3053
|
||||
[#3064]: https://github.com/AdguardTeam/AdGuardHome/issues/3064
|
||||
[#3107]: https://github.com/AdguardTeam/AdGuardHome/issues/3107
|
||||
[#3115]: https://github.com/AdguardTeam/AdGuardHome/issues/3115
|
||||
[#3127]: https://github.com/AdguardTeam/AdGuardHome/issues/3127
|
||||
|
||||
|
||||
|
||||
## [v0.106.2] - 2021-05-06
|
||||
|
||||
### Fixed
|
||||
|
||||
- Uniqueness validation for dynamic DHCP leases ([#3056]).
|
||||
|
||||
[#3056]: https://github.com/AdguardTeam/AdGuardHome/issues/3056
|
||||
|
||||
|
||||
|
||||
## [v0.106.1] - 2021-04-30
|
||||
|
||||
### Fixed
|
||||
|
||||
- Local domain name handling when the DHCP server is disabled ([#3028]).
|
||||
- Normalization of perviously-saved invalid static DHCP leases ([#3027]).
|
||||
- Validation of IPv6 addresses with zones in system resolvers ([#3022]).
|
||||
|
||||
[#3022]: https://github.com/AdguardTeam/AdGuardHome/issues/3022
|
||||
[#3027]: https://github.com/AdguardTeam/AdGuardHome/issues/3027
|
||||
[#3028]: https://github.com/AdguardTeam/AdGuardHome/issues/3028
|
||||
|
||||
|
||||
|
||||
## [v0.106.0] - 2021-04-28
|
||||
|
||||
@@ -320,12 +373,14 @@ and this project adheres to
|
||||
|
||||
|
||||
<!--
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.1...HEAD
|
||||
[v0.107.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.1...v0.107.0
|
||||
[v0.106.1]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.0...v0.106.1
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.0...HEAD
|
||||
[v0.107.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.3...v0.107.0
|
||||
-->
|
||||
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.0...HEAD
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.3...HEAD
|
||||
[v0.106.3]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.2...v0.106.3
|
||||
[v0.106.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.1...v0.106.2
|
||||
[v0.106.1]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.0...v0.106.1
|
||||
[v0.106.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.2...v0.106.0
|
||||
[v0.105.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.1...v0.105.2
|
||||
[v0.105.1]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.0...v0.105.1
|
||||
|
||||
@@ -309,6 +309,8 @@ on GitHub and most other Markdown renderers. -->
|
||||
|
||||
* Avoid bashisms and GNUisms, prefer POSIX features only.
|
||||
|
||||
* Avoid spaces between patterns of the same `case` condition.
|
||||
|
||||
* Prefer `'raw strings'` to `"double quoted strings"` whenever possible.
|
||||
|
||||
* Put spaces within `$( cmd )`, `$(( expr ))`, and `{ cmd; }`.
|
||||
@@ -324,10 +326,10 @@ on GitHub and most other Markdown renderers. -->
|
||||
* UPPERCASE names for external exported variables, lowercase for local,
|
||||
unexported ones.
|
||||
|
||||
* Use `set -e -f -u` and also `set -x` in verbose mode.
|
||||
|
||||
* Use `readonly` liberally.
|
||||
|
||||
* Use `set -e -f -u` and also `set -x` in verbose mode.
|
||||
|
||||
* Use the `"$var"` form instead of the `$var` form, unless word splitting is
|
||||
required.
|
||||
|
||||
@@ -352,6 +354,7 @@ on GitHub and most other Markdown renderers. -->
|
||||
* When using `test` (aka `[`), spell compound conditions with `&&`, `||`, and
|
||||
`!` **outside** of `test` instead of `-a`, `-o`, and `!` inside of `test`
|
||||
correspondingly. The latter ones are pretty much deprecated in POSIX.
|
||||
Also, prefer `!= ''` form instead of `-n` to check if string is empty.
|
||||
|
||||
See also: “[Problems With the `test` Builtin: What Does `-a` Mean?]”.
|
||||
|
||||
|
||||
12
README.md
12
README.md
@@ -68,9 +68,17 @@ It operates as a DNS server that re-routes tracking domains to a "black hole", t
|
||||
### Automated install (Linux and Mac)
|
||||
Run the following command in your terminal:
|
||||
```
|
||||
curl -sSL https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh
|
||||
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
|
||||
```
|
||||
|
||||
The script also accepts some options:
|
||||
* `-c <channel>` to use specified channel.
|
||||
* `-r` to reinstall AdGuard Home;
|
||||
* `-u` to uninstall AdGuard Home;
|
||||
* `-v` for verbose output;
|
||||
|
||||
Note that options `-r` and `-u` are mutually exclusive.
|
||||
|
||||
### Alternative methods
|
||||
|
||||
#### Manual installation
|
||||
@@ -137,7 +145,7 @@ AdGuard Home provides a lot of features out-of-the-box with no need to install a
|
||||
| Blocking ads and trackers | ✅ | ✅ |
|
||||
| Customizing blocklists | ✅ | ✅ |
|
||||
| Built-in DHCP server | ✅ | ✅ |
|
||||
| HTTPS for the Admin interface | ✅ | Kind of, but you'll need to manually configure lighthttpd |
|
||||
| HTTPS for the Admin interface | ✅ | Kind of, but you'll need to manually configure lighttpd |
|
||||
| Encrypted DNS upstream servers (DNS-over-HTTPS, DNS-over-TLS, DNSCrypt) | ✅ | ❌ (requires additional software) |
|
||||
| Cross-platform | ✅ | ❌ (not natively, only via Docker) |
|
||||
| Running as a DNS-over-HTTPS or DNS-over-TLS server | ✅ | ❌ (requires additional software) |
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
'project-key': 'AGH'
|
||||
'key': 'AGHBSNAPSPECS'
|
||||
'name': 'AdGuard Home - Build and publish release'
|
||||
# Make sure to sync any changes with the branch overrides below.
|
||||
'variables':
|
||||
'channel': 'edge'
|
||||
'dockerGo': 'adguard/golang-ubuntu:2.0'
|
||||
@@ -228,7 +229,9 @@
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'triggers':
|
||||
- 'cron': '0 30 14 ? * MON-FRI *'
|
||||
# Don't use minute values that end with a zero or a five as these are often used
|
||||
# in CI and so resources during these minutes can be quite busy.
|
||||
- 'cron': '0 42 13 ? * MON-FRI *'
|
||||
'branches':
|
||||
'create': 'manually'
|
||||
'delete':
|
||||
@@ -250,3 +253,25 @@
|
||||
'labels': []
|
||||
'other':
|
||||
'concurrent-build-plugin': 'system-default'
|
||||
|
||||
'branch-overrides':
|
||||
# beta-vX.Y branches are the branches into which the commits that are needed to
|
||||
# release a new patch version are initially cherry-picked.
|
||||
- '^beta-v[0-9]+\.[0-9]+':
|
||||
# Build betas on release branches manually.
|
||||
'triggers': []
|
||||
# Set the default release channel on the release branch to beta, as we may
|
||||
# need to build a few of these.
|
||||
'variables':
|
||||
'channel': 'beta'
|
||||
'dockerGo': 'adguard/golang-ubuntu:2.0'
|
||||
# release-vX.Y.Z branches are the branches from which the actual final release
|
||||
# is built.
|
||||
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
||||
# Build final releases on release branches manually.
|
||||
'triggers': []
|
||||
# Set the default release channel on the final branch to release, as these
|
||||
# are the ones that actually get released.
|
||||
'variables':
|
||||
'channel': 'release'
|
||||
'dockerGo': 'adguard/golang-ubuntu:2.0'
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Bootstrap DNS-серверы",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS-серверы выкарыстоўваюцца для пошуку IP-адрасоў DoH/DoT сервераў, якія вы паказалі.",
|
||||
"local_ptr_title": "Прыватныя DNS-серверы",
|
||||
"local_ptr_desc": "DNS-сервер ці серверы, якія AdGuard Home будзе выкарыстоўваць для запытаў на лакальныя рэсурсы. Напрыклад, гэтыя серверы будуць выкарыстоўвацца, каб атрымаць даменавыя імёны кліентаў у прыватных сетках. Калі спіс пусты, AdGuard Home будзе выкарыстоўваць сістэмны DNS-сервер па змаўчанні.",
|
||||
"local_ptr_desc": "DNS-серверы, якія AdGuard Home выкарыстоўвае для лакальных PTR-запытаў. Гэтыя серверы выкарыстоўваюцца, каб атрымаць даменавыя імёны кліентаў з прыватнымі IP-адрасамі, напрыклад «192.168.12.34», з дапамогай rDNS. Калі спіс пусты, AdGuard Home выкарыстоўвае прадвызначаныя DNS-серверы вашай АС.",
|
||||
"local_ptr_placeholder": "Увядзіце па адным адрасе на радок",
|
||||
"resolve_clients_title": "Уключыць запытванне даменавых імёнаў для кліентаў",
|
||||
"resolve_clients_desc": "AdGuard Home будзе спрабаваць аўтаматычна вызначыць даменавыя імёны кліентаў праз PTR-запыты да адпаведных сервераў (прыватны DNS-сервер для лакальных кліентаў, upstream-серверы для кліентаў з публічным IP-адрасам).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Bootstrap DNS servery",
|
||||
"bootstrap_dns_desc": "Servery Bootstrap DNS se používají k řešení IP adres DoH/DoT, které zadáváte jako upstreamy.",
|
||||
"local_ptr_title": "Soukromé DNS servery",
|
||||
"local_ptr_desc": "Servery DNS, které AdGuard Home použije pro dotazy na lokálně poskytované zdroje. Tento server bude například používán k řešení názvů hostitelů pro klienty se soukromými IP adresami. Pokud není nastaveno, AdGuard Home automaticky použije váš výchozí překladač DNS.",
|
||||
"local_ptr_desc": "Servery DNS, které AdGuard Home používá pro lokální dotazy PTR. Tyto servery se používají k rozlišení názvů hostitelů klientů se soukromými adresami IP, například \"192.168.12.34\" pomocí rDNS. Pokud není nastaveno, AdGuard Home automaticky použije výchozí řešitele vašeho OS.",
|
||||
"local_ptr_placeholder": "Zadejte jednu adresu serveru na řádek",
|
||||
"resolve_clients_title": "Povolit zpětné řešení IP adres klientů",
|
||||
"resolve_clients_desc": "Pokud je povoleno, AdGuard Home se pokusí obráceně vyřešit IP adresy klientů na jejich názvy hostitelů zasláním dotazů PTR příslušným řešitelům (soukromé DNS servery pro místní klienty, odchozí server pro klienty s veřejnou IP adresou).",
|
||||
@@ -193,10 +193,10 @@
|
||||
"example_comment_hash": "# Také komentář",
|
||||
"example_regex_meaning": "blokuje přístup doménám, které vyhovují regulárnímu výrazu",
|
||||
"example_upstream_regular": "obyčejný DNS (přes UDP)",
|
||||
"example_upstream_dot": "šifrovaný <0>DNS přes TLS</0>",
|
||||
"example_upstream_doh": "šifrovaný <0>DNS přes HTTPS</0>",
|
||||
"example_upstream_doq": "šifrovaný <0>DNS přes QUIC</0>",
|
||||
"example_upstream_sdns": "můžete použít <0>DNS razítka</0> pro <1>DNSCrypt</1> nebo <2>DNS přes HTTPS</2> řešitele",
|
||||
"example_upstream_dot": "šifrovaný <0>DNS skrze TLS</0>",
|
||||
"example_upstream_doh": "šifrovaný <0>DNS skrze HTTPS</0>",
|
||||
"example_upstream_doq": "šifrovaný <0>DNS skrze QUIC</0>",
|
||||
"example_upstream_sdns": "můžete použít <0>DNS razítka</0> pro <1>DNSCrypt</1> nebo <2>DNS skrze HTTPS</2> řešitele",
|
||||
"example_upstream_tcp": "obyčejný DNS (přes TCP)",
|
||||
"all_lists_up_to_date_toast": "Všechny seznamy jsou již aktuální",
|
||||
"updated_upstream_dns_toast": "Aktualizované upstream DNS servery",
|
||||
@@ -255,8 +255,8 @@
|
||||
"blocking_ipv4": "Blokování IPv4",
|
||||
"blocking_ipv6": "Blokování IPv6",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS přes HTTPS",
|
||||
"dns_over_tls": "DNS přes TLS",
|
||||
"dns_over_https": "DNS skrze HTTPS",
|
||||
"dns_over_tls": "DNS skrze TLS",
|
||||
"dns_over_quic": "DNS skrze QUIC",
|
||||
"client_id": "ID klienta",
|
||||
"client_id_placeholder": "Zadejte ID klienta",
|
||||
@@ -347,11 +347,11 @@
|
||||
"encryption_redirect": "Automaticky přesměrovat na HTTPS",
|
||||
"encryption_redirect_desc": "Pokud je zaškrtnuto, AdGuard Home vás automaticky přesměruje z adres HTTP na HTTPS.",
|
||||
"encryption_https": "HTTPS port",
|
||||
"encryption_https_desc": "Pokud je nakonfigurován port HTTPS, AdGuard Home administrátorské rozhraní bude přístupné přes HTTPS a bude také poskytovat DNS přes HTTPS na '/dns-query'.",
|
||||
"encryption_dot": "DNS přes TLS port",
|
||||
"encryption_dot_desc": "Pokud je tento port nakonfigurován, AdGuard Home bude na tomto portu spouštět DNS přes TLS server.",
|
||||
"encryption_doq": "DNS přes QUIC port",
|
||||
"encryption_doq_desc": "Pokud je tento port nakonfigurován, AdGuard Home spustí na tomto portu server DNS přes QUIC. Je to experimentální a nemusí být spolehlivé. V současnosti také není příliš mnoho klientů, kteří to podporují.",
|
||||
"encryption_https_desc": "Pokud je nakonfigurován port HTTPS, AdGuard Home administrátorské rozhraní bude přístupné přes HTTPS a bude také poskytovat DNS skrze HTTPS na '/dns-query'.",
|
||||
"encryption_dot": "DNS skrze TLS port",
|
||||
"encryption_dot_desc": "Pokud je tento port nakonfigurován, AdGuard Home bude na tomto portu spouštět DNS skrze TLS server.",
|
||||
"encryption_doq": "DNS skrze QUIC port",
|
||||
"encryption_doq_desc": "Pokud je tento port nakonfigurován, AdGuard Home spustí na tomto portu server DNS skrze QUIC. Je to experimentální a nemusí být spolehlivé. V současnosti také není příliš mnoho klientů, kteří to podporují.",
|
||||
"encryption_certificates": "Certifikáty",
|
||||
"encryption_certificates_desc": "Chcete-li používat šifrování, musíte pro svou doménu poskytnout platný řetězec certifikátů SSL. Certifikát můžete získat bezplatně na adrese <0>{{link}}</ 0>, nebo jej můžete zakoupit od jednoho z důvěryhodných certifikačních úřadů.",
|
||||
"encryption_certificates_input": "Zde můžete nakopírovat/vložit certifikáty PEM.",
|
||||
@@ -359,8 +359,8 @@
|
||||
"encryption_expire": "Vyprší",
|
||||
"encryption_key": "Osobní kód",
|
||||
"encryption_key_input": "Zde můžete nakopírovat/vložit soukromý klíč k certifikátu PEM.",
|
||||
"encryption_enable": "Povolit šifrování (HTTPS, DNS přes HTTPS a DNS přes TLS)",
|
||||
"encryption_enable_desc": "Pokud je šifrování zapnuto, administrátorské rozhraní AdGuard Home bude pracovat přes HTTPS a DNS server bude naslouchat požadavky přes DNS přes HTTPS a DNS přes TLS.",
|
||||
"encryption_enable": "Povolit šifrování (HTTPS, DNS skrze HTTPS a DNS skrze TLS)",
|
||||
"encryption_enable_desc": "Pokud je šifrování zapnuto, administrátorské rozhraní AdGuard Home bude pracovat skrze HTTPS a DNS server bude naslouchat požadavky přes DNS skrze HTTPS a DNS skrze TLS.",
|
||||
"encryption_chain_valid": "Certifikační řetězec je platný",
|
||||
"encryption_chain_invalid": "Certifikační řetězec je neplatný",
|
||||
"encryption_key_valid": "Toto je platný {{type}} osobní klíč",
|
||||
@@ -429,23 +429,23 @@
|
||||
"updates_version_equal": "AdGuard Home je aktuální",
|
||||
"check_updates_now": "Zkontrolovat aktualizace nyní",
|
||||
"dns_privacy": "Soukromí DNS",
|
||||
"setup_dns_privacy_1": "<0>DNS-přes-TLS:</0> Použít <1>{{address}}</1> řetězec.",
|
||||
"setup_dns_privacy_2": "<0>DNS-přes-HTTPS:</0> Použít <1>{{address}}</1> řetězec.",
|
||||
"setup_dns_privacy_1": "<0>DNS skrze TLS:</0> Použít <1>{{address}}</1> řetězec.",
|
||||
"setup_dns_privacy_2": "<0>DNS skrze HTTPS:</0> Použít <1>{{address}}</1> řetězec.",
|
||||
"setup_dns_privacy_3": "<0>Zde je seznam softwaru, který můžete použít.</0>",
|
||||
"setup_dns_privacy_4": "Na zařízení se systémem iOS 14 nebo macOS Big Sur si můžete stáhnout speciální soubor '.mobileconfig', který do nastavení DNS přidává servery <highlight>DNS skrze HTTPS</highlight> nebo <highlight> DNS skrze TLS</highlight>.",
|
||||
"setup_dns_privacy_android_1": "Android 9 podporuje DNS-přes-TLS nativně. Pokud ho chcete konfigurovat, přejděte na Nastavení → Síť & internet → Pokročilé → Soukromé DNS a tam zadejte název vaší domény.",
|
||||
"setup_dns_privacy_android_2": "<0>AdGuard pro Android</0> podporuje <1>DNS-přes-HTTPS</1> a <1>DNS-přes-TLS</1>.",
|
||||
"setup_dns_privacy_android_3": "<0>Intra</0> přidává podporu <1>DNS-přes-HTTPS</1> pro Android.",
|
||||
"setup_dns_privacy_ios_1": "<0>DNSCloak</0> podporuje funkci <1>DNS-přes-HTTPS</1>, ale abyste ji mohli nakonfigurovat pro používání vlastního serveru, musíte vygenerovat značku <2>DNS Stamp</2>.",
|
||||
"setup_dns_privacy_ios_2": "<0>AdGuard pro iOS</0> podporuje nastavení <1>DNS-přes-HTTPS</1> a <1>DNS-přes-TLS</1>.",
|
||||
"setup_dns_privacy_android_1": "Android 9 podporuje DNS skrze TLS nativně. Pokud ho chcete konfigurovat, přejděte na Nastavení → Síť & internet → Pokročilé → Soukromé DNS a tam zadejte název vaší domény.",
|
||||
"setup_dns_privacy_android_2": "<0>AdGuard pro Android</0> podporuje <1>DNS skrze HTTPS</1> a <1>DNS skrze LS</1>.",
|
||||
"setup_dns_privacy_android_3": "<0>Intra</0> přidává podporu <1>DNS skrze HTTPS</1> pro Android.",
|
||||
"setup_dns_privacy_ios_1": "<0>DNSCloak</0> podporuje funkci <1>DNS skrze HTTPS</1>, ale abyste ji mohli nakonfigurovat pro používání vlastního serveru, musíte vygenerovat značku <2>DNS Stamp</2>.",
|
||||
"setup_dns_privacy_ios_2": "<0>AdGuard pro iOS</0> podporuje nastavení <1>DNS skrze HTTPS</1> a <1>DNS skrze TLS</1>.",
|
||||
"setup_dns_privacy_other_title": "Další implementace",
|
||||
"setup_dns_privacy_other_1": "Samotný AdGuard Home může být bezpečným klientem DNS na jakékoli platformě.",
|
||||
"setup_dns_privacy_other_2": "<0>dnsproxy</0> podporuje všechny známé bezpečné DNS protokoly.",
|
||||
"setup_dns_privacy_other_3": "<0>dnscrypt-proxy</0> podporuje <1>DNS-přes-HTTPS</1>.",
|
||||
"setup_dns_privacy_other_4": "<0>Mozilla Firefox</0> podporuje <1>DNS-přes-HTTPS</1>.",
|
||||
"setup_dns_privacy_other_3": "<0>dnscrypt-proxy</0> podporuje <1>DNS skrze HTTPS</1>.",
|
||||
"setup_dns_privacy_other_4": "<0>Mozilla Firefox</0> podporuje <1>DNS skrze HTTPS</1>.",
|
||||
"setup_dns_privacy_other_5": "Další implementace naleznete <0>zde</0> a <1>zde</1>.",
|
||||
"setup_dns_privacy_ioc_mac": "Konfigurace pro iOS a macOS",
|
||||
"setup_dns_notice": "Pro použití <1>DNS-přes-HTTPS</1> nebo <1>DNS-přes-TLS</1> potřebujete v nastaveních AdGuard Home <0>nakonfigurovat šifrování</0>.",
|
||||
"setup_dns_notice": "Pro použití <1>DNS skrze HTTPS</1> nebo <1>DNS skrze TLS</1> potřebujete v nastaveních AdGuard Home <0>nakonfigurovat šifrování</0>.",
|
||||
"rewrite_added": "Přesměrování DNS pro „{{key}}“ úspěšně přidáno",
|
||||
"rewrite_deleted": "Přesměrování DNS pro „{{key}}“ úspěšně smazáno",
|
||||
"rewrite_add": "Přidat přesměrování DNS",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Bootstrap DNS-servere",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS-servere bruges til at fortolke IP-adresser for de DoH-/DoT-resolvere, du angiver som upstream.",
|
||||
"local_ptr_title": "Private DNS-servere",
|
||||
"local_ptr_desc": "De DNS-servere som AdGuard Home vil bruge til forespørgsler efter lokalt leverede ressourcer. For eksempel vil denne server blive brugt til at løse klienters værtsnavne for klienter med private IP-adresser. Hvis ikke indstillet, bruger AdGuard Home automatisk din standard DNS-resolver.",
|
||||
"local_ptr_desc": "De DNS-servere, som AdGuard Home bruger til lokale PTR-forespørgsler. Disse servere bruges til at opløse klientværtsnavne med private IP-adresser, f.eks. \"192.168.12.34\", vha. rDNS. Hvis ikke indstillet, bruger AdGuard Home dit operativsystems standard DNS-opløsere.",
|
||||
"local_ptr_placeholder": "Indtast en serveradresse pr. Linje",
|
||||
"resolve_clients_title": "Aktivér omvendt løsning af klienters IP-adresser",
|
||||
"resolve_clients_desc": "Hvis aktiveret, forsøger AdGuard Home automatisk at løse klienters værtsnavne fra deres IP-adresser ved at sende en PTR-forespørgsel til en tilsvarende resolver (privat DNS-server til lokale klienter, upstream-server til klienter med offentlig IP-adresse).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Bootstrap DNS-Server starten",
|
||||
"bootstrap_dns_desc": "Bootstrap-DNS-Server werden verwendet, um IP-Adressen der DoH/DoT-Resolver aufzulösen, die Sie als Upstreams angeben.",
|
||||
"local_ptr_title": "Eigene DNS-Server",
|
||||
"local_ptr_desc": "DNS-Server, die AdGuard Home für Abfragen nach lokal bereitgestellten Ressourcen verwenden wird. Diese Server werden z. B. für die Auflösung der Hostnamen der Clients für die Clients mit privaten IP-Adressen verwendet. Wenn nicht festgelegt, verwendet AdGuard Home automatisch Ihre Standard-DNS-Auflösung.",
|
||||
"local_ptr_desc": "Die DNS-Server, die AdGuard Home für lokale PTR-Abfragen verwendet. Diese Server werden verwendet, um die Hostnamen von Clients mit privaten IP-Adressen, z. B. „192.168.12.34“, mithilfe von rDNS aufzulösen. Wenn nicht festgelegt, verwendet AdGuard Home die Standard-DNS-Resolver Ihres Betriebssystems.",
|
||||
"local_ptr_placeholder": "Eine Serveradresse pro Zeile eingeben",
|
||||
"resolve_clients_title": "Hostnamenauflösung der Clients aktivieren",
|
||||
"resolve_clients_desc": "Wenn aktiviert, versucht AdGuard Home, die Hostnamen der Clients automatisch aus deren IP-Adressen aufzulösen, indem er eine PTR-Abfrage an einen entsprechenden Auflösungsdienst (privater DNS-Server für lokale Clients, Upstream-Server für Clients mit öffentlicher IP) sendet.",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Bootstrap DNS servers",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS servers are used to resolve IP addresses of the DoH/DoT resolvers you specify as upstreams.",
|
||||
"local_ptr_title": "Private DNS servers",
|
||||
"local_ptr_desc": "The DNS servers that AdGuard Home will use for queries for locally served resources. For instance, this server will be used for resolving clients' hostnames for the clients with private IP addresses. If not set, AdGuard Home will automatically use your default DNS resolver.",
|
||||
"local_ptr_desc": "The DNS servers that AdGuard Home uses for local PTR queries. These servers are used to resolve the hostnames of clients with private IP addresses, for example \"192.168.12.34\", using rDNS. If not set, AdGuard Home uses the default DNS resolvers of your OS.",
|
||||
"local_ptr_placeholder": "Enter one server address per line",
|
||||
"resolve_clients_title": "Enable reverse resolving of clients' IP addresses",
|
||||
"resolve_clients_desc": "If enabled, AdGuard Home will attempt to reversely resolve clients' IP addresses into their hostnames by sending PTR queries to corresponding resolvers (private DNS servers for local clients, upstream server for clients with public IP addresses).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Servidores DNS de arranque",
|
||||
"bootstrap_dns_desc": "Los servidores DNS de arranque se utilizan para resolver las direcciones IP de los resolutores DoH/DoT que especifiques como DNS de subida.",
|
||||
"local_ptr_title": "Servidores DNS privados",
|
||||
"local_ptr_desc": "Los servidores DNS que AdGuard Home utilizará para las consultas de recursos servidos localmente. Por ejemplo, este servidor se utilizará para resolver los nombres de hosts de los clientes con direcciones IP privadas. Si no está establecido, AdGuard Home utilizará automáticamente tu resolutor DNS predeterminado.",
|
||||
"local_ptr_desc": "Los servidores DNS que AdGuard Home utiliza para las consultas PTR locales. Estos servidores se utilizan para resolver los nombres de hosts de los clientes a direcciones IP privadas, por ejemplo \"192.168.12.34\", utilizando rDNS. Si no está establecido, AdGuard Home utilizará los resolutores DNS predeterminados de tu sistema operativo.",
|
||||
"local_ptr_placeholder": "Ingresa una dirección de servidor por línea",
|
||||
"resolve_clients_title": "Habilitar la resolución inversa de las direcciones IP de clientes",
|
||||
"resolve_clients_desc": "Si está habilitado, AdGuard Home intentará resolver de manera inversa las direcciones IP de los clientes a sus nombres de hosts enviando consultas PTR a los resolutores correspondientes (servidores DNS privados para clientes locales, servidor DNS de subida para clientes con direcciones IP públicas).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Serveurs DNS d'amorçage",
|
||||
"bootstrap_dns_desc": "Les serveurs DNS d'amorçage sont utilisés pour résoudre les adresses IP des résolveurs DoH/DoT que vous spécifiez comme upstream.",
|
||||
"local_ptr_title": "Serveurs DNS privés",
|
||||
"local_ptr_desc": "Le serveur ou serveurs DNS qui seront utilisés par AdGuard Home pour les requêtes de ressources servies localement. Ce serveur pourra être utilisé, par exemple, pour résoudre les noms d'hôtes des clients pour les clients avec des adresses IP privées. S'il n'est pas défini, AdGuard Home utilisera votre résolveur DNS par défaut automatiquement.",
|
||||
"local_ptr_desc": "Les serveurs DNS utilisés par AdGuard Home pour les requêtes PTR servies localement. Ces serveurs sont utilisés pour résoudre les noms d'hôtes des clients pour les clients avec des adresses IP privées, par exemple \"192.168.12.34\", en utilisant rDNS. S'il n'est pas défini, AdGuard Home utilisera le résolveur DNS de votre OS par défaut automatiquement.",
|
||||
"local_ptr_placeholder": "Saisissez une adresse de serveur par ligne",
|
||||
"resolve_clients_title": "Activer la résolution inverse des adresses IP des clients",
|
||||
"resolve_clients_desc": "Lorsque activé, AdGuard Home tentera de résoudre de manière inverse les adresses IP des clients en leurs noms d'hôtes en envoyant des requêtes PTR aux résolveurs correspondants (serveurs DNS privés pour les clients locaux, serveur en amont pour les clients ayant des adresses IP publiques).",
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
"bootstrap_dns": "Bootstrap DNS kiszolgálók",
|
||||
"bootstrap_dns_desc": "A Bootstrap DNS szerverek a DoH/DoT feloldók IP-címeinek feloldására szolgálnak.",
|
||||
"local_ptr_title": "Privát DNS szerverek",
|
||||
"local_ptr_desc": "Azok a DNS szerverek, amiket az AdGuard Home a helyi PTR kérésekhez használ. Ezeket a szervereket arra használjuk, hogy az rDNS segítségével fel lehessen oldani a kliensek hosztneveit. Ha nincs beállítva ilyen, akkor az AdGuard Home alapértelmezés szerint az OS nevét fogja feloldani.",
|
||||
"local_ptr_placeholder": "Adjon meg soronként egy kiszolgáló címet",
|
||||
"resolve_clients_title": "Kliensek IP címeinek fordított feloldása",
|
||||
"resolve_clients_desc": "Ha engedélyezve van, az AdGuard Home megpróbálja átfordítani a kliensek IP címeit hosztnevekre, PTR lekérdezéseket küldve a megfelelő feloldóknak (privát DNS szerverek a helyi kliensek számára, upstream szerverek a nyilvános IP címmel rendelkező ügyfelek számára).",
|
||||
"check_dhcp_servers": "DHCP szerverek keresése",
|
||||
"save_config": "Konfiguráció mentése",
|
||||
"enabled_dhcp": "DHCP szerver engedélyezve",
|
||||
@@ -35,6 +38,7 @@
|
||||
"form_error_mac_format": "Érvénytelen MAC formátum",
|
||||
"form_error_client_id_format": "Érvénytelen kliens ID formátum",
|
||||
"form_error_server_name": "Érvénytelen szervernév",
|
||||
"form_error_subnet": "A(z) \"{{cidr}}\" alhálózat nem tartalmazza a(z) \"{{ip}}\" IP címet",
|
||||
"form_error_positive": "0-nál nagyobbnak kell lennie",
|
||||
"form_error_negative": "Legalább 0-nak kell lennie",
|
||||
"range_end_error": "Nagyobbnak kell lennie, mint a tartomány kezdete",
|
||||
@@ -307,6 +311,7 @@
|
||||
"install_devices_router": "Router",
|
||||
"install_devices_router_desc": "Ez a beállítás lefed minden eszközt, amik az Ön routeréhez csatlakoznak, így azokat nem kell külön, kézzel beállítania.",
|
||||
"install_devices_address": "Az AdGuard DNS szerver a következő címeket figyeli",
|
||||
"install_devices_router_list_1": "Nyissa meg a router beállításait. Ez általában a böngészőn keresztül történik egy URL megadásával (pl. http://192.168.0.1/ vagy http://192.168.1.1/). Ez az oldal valószínűleg felhasználónevet és jelszót fog kérni. Ha nem tudja a belépési adatokat, ellenőrizze a router dobozát, a router alján levő fehér címkét vagy a technikai dokumentációt az interneten. Végső esetben visszaállíthatja a routert, azonban ne feledje, hogyha ezt az eljárást választja, akkor valószínűleg elveszíti annak összes beállítását. Ha a router beállításához alkalmazásra van szükség, telepítse az alkalmazást a telefonjára vagy a számítógépére, és használja azt az útválasztó beállításainak eléréséhez.",
|
||||
"install_devices_router_list_2": "Keresse meg a DHCP/DNS beállításokat. Keresse a DNS szót egy olyan mező mellett, amely egy 4 csoportból álló, 1-3 számjegyű számsort vár.",
|
||||
"install_devices_router_list_3": "Adja meg az AdGuard Home szerver címét itt.",
|
||||
"install_devices_router_list_4": "Bizonyos típusú routereknél nem állíthat be egyéni DNS-kiszolgálót. Ebben az esetben segíthet, ha az AdGuard Home-t DHCP-szerverként állítja be. Ellenkező esetben keresse meg az adott router kézikönyvében a DNS-kiszolgálók testreszabását.",
|
||||
@@ -396,6 +401,7 @@
|
||||
"ip_address": "IP cím",
|
||||
"client_identifier_desc": "A klienseket az IP-cím, a CIDR, a MAC-cím vagy egy speciális kliens azonosító alapján lehet azonosítani (ez használható DoT/DoH /DoQ esetén). <0>Itt</0> többet is megtudhat a kliensek azonosításáról.",
|
||||
"form_enter_ip": "IP-cím megadása",
|
||||
"form_enter_subnet_ip": "Adjon meg egy IP címet az alhálózatban \"{{cidr}}\"",
|
||||
"form_enter_mac": "MAC-cím megadása",
|
||||
"form_enter_id": "Azonosító megadása",
|
||||
"form_add_id": "Azonosító hozzáadása",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Server DNS bootstrap",
|
||||
"bootstrap_dns_desc": "Server Bootstrap DNS dapat digunakan untuk meresolve alamat IP pada DoH/DoT resolvers yang Anda tentukan sebagai upstreams.",
|
||||
"local_ptr_title": "Server DNS pribadi",
|
||||
"local_ptr_desc": "Server atau server DNS yang akan digunakan AdGuard Home untuk kueri sumber daya disajikan secara lokal. Misalnya, server ini akan digunakan untuk menyelesaikan hostname klien untuk klien dengan alamat IP pribadi. Jika tidak disetel, AdGuard Home akan secara otomatis menggunakan resolver DNS default Anda.",
|
||||
"local_ptr_desc": "Server DNS yang digunakan AdGuard Home untuk kueri PTR lokal. Server ini digunakan untuk menetapkan nama host klien bersama alamat IP pribadi, sebagai contoh \"192.168.12.34\", menggunakan rDNS. Jika tidka diatur, AdGuard Home akan menggunakan resolver DNS bawaan/default OS Anda.",
|
||||
"local_ptr_placeholder": "Masukkan satu alamat server per baris",
|
||||
"resolve_clients_title": "Aktifkan resolusi hostname klien",
|
||||
"resolve_clients_desc": "Jika diaktifkan, AdGuard Home akan mencoba menyelesaikan hostname klien secara otomatis dari alamat IP mereka dengan mengirimkan kueri PTR ke penyelesai yang sesuai (server DNS pribadi untuk klien lokal, server upstream untuk klien dengan IP publik).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Server DNS bootstrap",
|
||||
"bootstrap_dns_desc": "I server DNS di bootstrap sono utilizzati per risolvere gli indirizzi IP dei risolutori DoH/DoT specificati come upstream.",
|
||||
"local_ptr_title": "Server DNS privati",
|
||||
"local_ptr_desc": "I server DNS che AdGuard Home utilizzerà per richiedere le risorse disponibili localmente. Ad esempio, questo server verrà utilizzato per risolvere i nomi host dei client con indirizzi IP privati. Se non impostato, AdGuard Home utilizzerà automaticamente il risolutore DNS predefinito.",
|
||||
"local_ptr_desc": "I server DNS che AdGuard Home utilizzerà per richiedere le risorse PTR disponibili localmente. Ad esempio, questo server verrà utilizzato per risolvere i nomi host dei client con indirizzi IP privati, comò \"192.168.12.34\", utilizzando rDNS. Se non impostato, AdGuard Home utilizzerà automaticamente il risolutore DNS predefinito del tuo sistema operativo.",
|
||||
"local_ptr_placeholder": "Inserisci un indirizzo server per riga",
|
||||
"resolve_clients_title": "Attiva la risoluzione inversa degli indirizzi IP dei client",
|
||||
"resolve_clients_desc": "Se attivo, AdGuard Home tenterà di risolvere inversamente gli indirizzi IP dei client nei relativi nomi host inviando una richiesta PTR a un risolutore corrispondente (server DNS privato per client locali, server upstream per client con IP pubblico).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "ブートストラップDNSサーバ",
|
||||
"bootstrap_dns_desc": "ブートストラップDNSサーバは、上流として指定したDoH/DoTリゾルバのIPアドレスを解決するために使用されます。",
|
||||
"local_ptr_title": "プライベートDNSサーバー",
|
||||
"local_ptr_desc": "AdGuard Homeがローカルに提供されるリソースのクエリに使用するDNSサーバーです。例えば、このサーバーは、プライベートIPアドレスを持つクライアントのホスト名を解決するために使用されます。設定されていない場合、AdGuard Homeはお使いのデフォルトDNSリゾルバーを自動的に使用します。",
|
||||
"local_ptr_desc": "AdGuard HomeがローカルPTRクエリに使用するDNSサーバーです。これらのサーバーは、rDNSを使ってプライベートIPアドレス(例えば\"192.168.12.34\")を持つクライアントのホスト名を解決するために使用されます。設定されていない場合、AdGuard HomeはOSのデフォルトDNSリゾルバーを自動的に使用します。",
|
||||
"local_ptr_placeholder": "1行に1つのサーバを入力してください。",
|
||||
"resolve_clients_title": "クライアントのIPアドレスの逆解決を有効にする",
|
||||
"resolve_clients_desc": "有効にすると、AdGuard Homeは、対応するリゾルバー(ローカルクライアントの場合はプライベートDNSサーバ、パブリックIPを持つクライアントの場合は上流サーバ)にPTRクエリを送信することにより、クライアントのIPアドレスをホスト名に逆解決しようとします。",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "부트스트랩 DNS 서버",
|
||||
"bootstrap_dns_desc": "부트스트랩 DNS 서버는 업스트림으로 지정한 DoH/DoT 서버의 IP 주소를 확인하는 데 사용합니다.",
|
||||
"local_ptr_title": "프라이빗 DNS 서버",
|
||||
"local_ptr_desc": "AdGuard Home이 로컬 리소스에 대한 쿼리에 사용할 DNS 서버입니다. 예를 들어, 사설 IP 주소가 있는 클라이언트의 호스트명을 확인할 때 사용합니다. 설정하지 않으면 기본으로 설정된 DNS 서버를 사용합니다.",
|
||||
"local_ptr_desc": "AdGuard Home이 로컬 PTR 쿼리에 사용하는 DNS 서버입니다. 이러한 서버는 rDNS를 사용하여 개인 IP 주소(예: '192.168.12.34')가 있는 클라이언트의 호스트 이름을 확인하는 데 사용됩니다. 설정되지 않은 경우, AdGuard Home은 OS의 기본 DNS 리졸버를 사용합니다.",
|
||||
"local_ptr_placeholder": "한 줄에 하나씩 서버 주소 입력",
|
||||
"resolve_clients_title": "클라이언트 IP 주소에 대한 호스트명 확인 활성화",
|
||||
"resolve_clients_desc": "활성화된 경우 AdGuard Home은 PTR 쿼리를 해당 서버(로컬 클라이언트의 경우 프라이빗 DNS 서버, 공용 IP 주소가 있는 클라이언트의 경우 업스트림 서버)로 전송하여 IP 주소로부터 클라이언트의 호스트명을 역으로 확인하려고 시도합니다.",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Serwery DNS Bootstrap",
|
||||
"bootstrap_dns_desc": "Serwery DNS Bootstrap są używane do ustalenia adresu IP serwerów DoH/DoT, które oznaczysz jako główne serwery DNS.",
|
||||
"local_ptr_title": "Prywatne serwery DNS",
|
||||
"local_ptr_desc": "Serwery DNS, z których AdGuard Home będzie korzystał przy zapytaniach o lokalnie obsługiwane zasoby. Na przykład, ten serwer będzie używany do rozwiązywania nazw hostów klientów z prywatnymi adresami IP. Jeśli nie jest ustawiony, AdGuard Home będzie automatycznie korzystał z domyślnego resolvera DNS.",
|
||||
"local_ptr_desc": "Serwery DNS, których AdGuard Home używa do lokalnych zapytań PTR. Serwery te są używane do rozwiązywania nazw hostów klientów z prywatnymi adresami IP, na przykład \"192.168.12.34\", przy użyciu rDNS. Jeśli nie jest ustawiony, AdGuard Home używa domyślnych resolwerów DNS systemu operacyjnego.",
|
||||
"local_ptr_placeholder": "Wprowadź po jednym adresie serwera w każdym wierszu",
|
||||
"resolve_clients_title": "Włącz odwrotne rozpoznawanie adresów IP klientów",
|
||||
"resolve_clients_desc": "Jeśli jest włączona, AdGuard Home spróbuje odwrócić adresy IP klientów do ich nazw hostów, wysyłając zapytania PTR do odpowiednich resolverów (prywatne serwery DNS dla klientów lokalnych, serwer nadrzędny dla klientów z publicznymi adresami IP).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Servidores DNS de inicialização",
|
||||
"bootstrap_dns_desc": "Servidores DNS de inicialização são usados para resolver endereços IP dos resolvedores DoH/DoT que você especifica como upstreams.",
|
||||
"local_ptr_title": "Servidores DNS privados",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usará para consultas de recursos servidos localmente. Por exemplo, este servidor será usado para resolver nomes de host de clientes para clientes com endereços IP privados. Se não for definido, o AdGuard Home usará automaticamente seu resolvedor DNS padrão.",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver os nomes de host de clientes com endereços IP privados, por exemplo \"192.168.12.34\", usando rDNS. Se não for definido, o AdGuard Home usa os resolvedores DNS padrão do seu sistema operacional.",
|
||||
"local_ptr_placeholder": "Insira um endereço de servidor por linha",
|
||||
"resolve_clients_title": "Ativar resolução reversa de endereços IP de clientes",
|
||||
"resolve_clients_desc": "Se ativado, o AdGuard Home tentará resolver de forma reversa os endereços IP dos clientes em seus nomes de host, enviando consultas PTR aos resolvedores correspondentes (servidores DNS privados para clientes locais, servidor DNS primário para clientes com endereços IP públicos).",
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"bootstrap_dns": "Servidores DNS de arranque",
|
||||
"bootstrap_dns_desc": "Servidores DNS de inicialização são usados para resolver endereços IP dos resolvedores DoH/DoT que especifica como upstreams.",
|
||||
"local_ptr_title": "Servidores DNS privados",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usará para consultas de recursos servidos localmente. Por exemplo, este servidor será usado para resolver nomes de host de clientes para clientes com endereços IP privados. Se não for definido, o AdGuard Home usará automaticamente seu resolvedor DNS padrão.",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver os nomes de host de clientes com endereços IP privados, por exemplo \"192.168.12.34\", usando rDNS. Se não for definido, o AdGuard Home usa os resolvedores DNS padrão do seu sistema operacional.",
|
||||
"local_ptr_placeholder": "Insira um endereço de servidor por linha",
|
||||
"resolve_clients_title": "Activar resolução reversa de endereços IP de clientes",
|
||||
"resolve_clients_title": "Ativar resolução reversa de endereços IP de clientes",
|
||||
"resolve_clients_desc": "Se activado, o AdGuard Home tentará resolver de forma reversa os endereços IP dos clientes em seus nomes de host, enviando consultas PTR aos resolvedores correspondentes (servidores DNS privados para clientes locais, servidor DNS primário para clientes com endereços IP públicos).",
|
||||
"check_dhcp_servers": "Verificar por servidores DHCP",
|
||||
"save_config": "Guardar definição",
|
||||
@@ -21,10 +21,10 @@
|
||||
"unavailable_dhcp_desc": "O AdGuard Home não pode executar um servidor DHCP em seu sistema operacional",
|
||||
"dhcp_title": "Servidor DHCP (experimental)",
|
||||
"dhcp_description": "Se o seu router não fornecer configurações de DHCP, poderá usar o servidor DHCP integrado do AdGuard.",
|
||||
"dhcp_enable": "Activar servidor DHCP",
|
||||
"dhcp_disable": "Desactivar servidor DHCP",
|
||||
"dhcp_not_found": "É seguro activar o servidor DHCP integrado porque o AdGuard Home não encontrou nenhum servidor DHCP ativo na rede. No entanto, você deve verificar isso manualmente, pois a verificação automática atualmente não oferece 100% de garantia.",
|
||||
"dhcp_found": "Um servidor DHCP activo foi encontrado na rede. Não é seguro activar o servidor DHCP incorporado.",
|
||||
"dhcp_enable": "Ativar servidor DHCP",
|
||||
"dhcp_disable": "Desativar servidor DHCP",
|
||||
"dhcp_not_found": "É seguro ativar o servidor DHCP integrado porque o AdGuard Home não encontrou nenhum servidor DHCP ativo na rede. No entanto, você deve verificar isso manualmente, pois a verificação automática atualmente não oferece 100% de garantia.",
|
||||
"dhcp_found": "Um servidor DHCP ativo foi encontrado na rede. Não é seguro ativar o servidor DHCP incorporado.",
|
||||
"dhcp_leases": "Concessões DHCP",
|
||||
"dhcp_static_leases": "Concessões de DHCP estático",
|
||||
"dhcp_leases_not_found": "Nenhuma concessão DHCP encontrada",
|
||||
@@ -55,10 +55,10 @@
|
||||
"ip": "IP",
|
||||
"dhcp_table_hostname": "Nome do servidor",
|
||||
"dhcp_table_expires": "Expira",
|
||||
"dhcp_warning": "Se tu quiser activar o servidor DHCP de qualquer maneira, certifique-se de que não haja outro servidor DHCP activo em tua rede, pois isso pode quebrar a conectividade com a Internet para dispositivos na rede!",
|
||||
"dhcp_warning": "Se tu quiser ativar o servidor DHCP de qualquer maneira, certifique-se de que não haja outro servidor DHCP ativo em tua rede, pois isso pode quebrar a conectividade com a Internet para dispositivos na rede!",
|
||||
"dhcp_error": "O AdGuard Home não conseguiu determinar se há noutro servidor DHCP ativo na rede.",
|
||||
"dhcp_static_ip_error": "Para usar o servidor DHCP, deve definir um endereço IP estático. AdGuard Home não conseguiu determinar se essa interface de rede está configurada usando o endereço de IP estático. Por favor, defina um endereço IP estático manualmente.",
|
||||
"dhcp_dynamic_ip_found": "O seu sistema usa a configuração de endereço IP dinâmico para a interface <0>{{interfaceName}}</0>. Para usar o servidor DHCP, deve definir um endereço de IP estático. O seu endereço IP actual é <0> {{ipAddress}} </ 0>. AdGuard Home irá definir automaticamente este endereço IP como estático se pressionar o botão \"Activar servidor DHCP\".",
|
||||
"dhcp_dynamic_ip_found": "O seu sistema usa a configuração de endereço IP dinâmico para a interface <0>{{interfaceName}}</0>. Para usar o servidor DHCP, deve definir um endereço de IP estático. O seu endereço IP actual é <0> {{ipAddress}} </ 0>. AdGuard Home irá definir automaticamente este endereço IP como estático se pressionar o botão \"Ativar servidor DHCP\".",
|
||||
"dhcp_lease_added": "Concessão estática \"{{key}}\" adicionada com sucesso",
|
||||
"dhcp_lease_deleted": "Concessão estática \"{{key}}\" excluída com sucesso",
|
||||
"dhcp_new_static_lease": "Nova concessão estática",
|
||||
@@ -92,10 +92,10 @@
|
||||
"homepage": "Página inicial",
|
||||
"report_an_issue": "Comunicar um problema",
|
||||
"privacy_policy": "Política de Privacidade",
|
||||
"enable_protection": "Activar protecção",
|
||||
"enabled_protection": "Activar protecção",
|
||||
"disable_protection": "Desactivar protecção",
|
||||
"disabled_protection": "Desactivar protecção",
|
||||
"enable_protection": "Ativar protecção",
|
||||
"enabled_protection": "Ativar protecção",
|
||||
"disable_protection": "Desativar protecção",
|
||||
"disabled_protection": "Desativar protecção",
|
||||
"refresh_statics": "Repor estatísticas",
|
||||
"dns_query": "Consultas de DNS",
|
||||
"blocked_by": "<0>Bloqueado por filtros</0>",
|
||||
@@ -236,7 +236,7 @@
|
||||
"query_log_updated": "O registro da consulta foi actualizado com sucesso",
|
||||
"query_log_clear": "Limpar registos de consulta",
|
||||
"query_log_retention": "Retenção de registos de consulta",
|
||||
"query_log_enable": "Activar registo",
|
||||
"query_log_enable": "Ativar registo",
|
||||
"query_log_configuration": "Definições do registo",
|
||||
"query_log_disabled": "O registo de consulta está desactivado e pode ser configurado em <0>definições</0>",
|
||||
"query_log_strict_search": "Usar aspas duplas para uma pesquisa rigorosa",
|
||||
@@ -267,7 +267,7 @@
|
||||
"plain_dns": "DNS simples",
|
||||
"form_enter_rate_limit": "Insira o limite de taxa",
|
||||
"rate_limit": "Limite de taxa",
|
||||
"edns_enable": "Activar sub-rede do cliente EDNS",
|
||||
"edns_enable": "Ativar sub-rede do cliente EDNS",
|
||||
"edns_cs_desc": "Se activado, o AdGuard Home enviará sub-redes dos clientes para os servidores DNS.",
|
||||
"rate_limit_desc": "O número de solicitações por segundo permitido por cliente. Configurando para 0 significa sem limite.",
|
||||
"blocking_ipv4_desc": "Endereço IP a ser devolvido para uma solicitação A bloqueada",
|
||||
@@ -359,7 +359,7 @@
|
||||
"encryption_expire": "Expira",
|
||||
"encryption_key": "Chave privada",
|
||||
"encryption_key_input": "Copie/cole aqui a chave privada codificada em PEM para o seu certificado.",
|
||||
"encryption_enable": "Activar criptografia (HTTPS, DNS-sobre-HTTPS e DNS-sobre-TLS)",
|
||||
"encryption_enable": "Ativar criptografia (HTTPS, DNS-sobre-HTTPS e DNS-sobre-TLS)",
|
||||
"encryption_enable_desc": "Se a criptografia estiver activada, a interface administrativa do AdGuard Home funcionará em HTTPS, o servidor DNS irá capturar as solicitações por meio do DNS-sobre-HTTPS e DNS-sobre-TLS.",
|
||||
"encryption_chain_valid": "Cadeia de certificado válida",
|
||||
"encryption_chain_invalid": "A cadeia de certificado é inválida",
|
||||
@@ -495,7 +495,7 @@
|
||||
"interval_hours": "{{count}} hora",
|
||||
"interval_hours_plural": "{{count}} horas",
|
||||
"filters_configuration": "Definição dos filtros",
|
||||
"filters_enable": "Activar filtros",
|
||||
"filters_enable": "Ativar filtros",
|
||||
"filters_interval": "Intervalo de actualização de filtros",
|
||||
"disabled": "Desactivado",
|
||||
"username_label": "Nome do utilizador",
|
||||
@@ -523,12 +523,12 @@
|
||||
"rewrite_domain_name": "Nome de domínio: adicione um registro CNAME",
|
||||
"rewrite_A": "<0>A</0>: valor especial, mantenha <0>A</0> nos registros do upstream",
|
||||
"rewrite_AAAA": "<0>AAAA</0>: valor especial, mantenha <0>AAAA</0> nos registros do servidor DNS primário",
|
||||
"disable_ipv6": "Desactivar IPv6",
|
||||
"disable_ipv6": "Desativar IPv6",
|
||||
"disable_ipv6_desc": "Se este recurso estiver ativado, todas as consultas de DNS para endereços IPv6 (tipo AAAA) serão ignoradas.",
|
||||
"fastest_addr": "Endereço de IP mais rápido",
|
||||
"fastest_addr_desc": "Consulta todos os servidores DNS e retorna o endereço IP mais rápido entre todas as respostas. Isso torna as consultas DNS mais lentas, pois o AdGuard Home tem que esperar pelas respostas de todos os servidores DNS, mas melhora a conectividade geral.",
|
||||
"autofix_warning_text": "Se clicar em \"Corrigir\", o AdGuardHome irá configurar o seu sistema para utilizar o servidor DNS do AdGuardHome.",
|
||||
"autofix_warning_list": "Ele irá realizar estas tarefas: <0>Desactivar sistema DNSStubListener</0> <0>Definir endereço do servidor DNS para 127.0.0.1</0> <0>Substituir o alvo simbólico do link /etc/resolv.conf para /run/systemd/resolv.conf</0> <0>Parar DNSStubListener (recarregar serviço resolvido pelo sistema)</0>",
|
||||
"autofix_warning_list": "Irá realizar estas tarefas: <0>Desativar sistema DNSStubListener</0> <0>Definir endereço do servidor DNS para 127.0.0.1</0> <0>Substituir o alvo simbólico do link /etc/resolv.conf para /run/systemd/resolv.conf</0> <0>Parar DNSStubListener (recarregar serviço resolvido pelo sistema)</0>",
|
||||
"autofix_warning_result": "Como resultado, todos as solicitações DNS do seu sistema serão processadas pelo AdGuard Home por predefinição.",
|
||||
"tags_title": "Etiquetas",
|
||||
"tags_desc": "Tu podes seleccionar as etiquetas que correspondem ao cliente. As etiquetas podem ser incluídas nas regras de filtragem e permitir que tu as aplique com mais precisão. <0>Saiba mais</0>",
|
||||
@@ -560,7 +560,7 @@
|
||||
"confirm_static_ip": "O AdGuard Home irá configurar {{ip}} para ser seu endereço IP estático. Deseja continuar?",
|
||||
"list_updated": "{{count}} lista actualizada",
|
||||
"list_updated_plural": "{{count}} listas actualizadas",
|
||||
"dnssec_enable": "Activar DNSSEC",
|
||||
"dnssec_enable": "Ativar DNSSEC",
|
||||
"dnssec_enable_desc": "Definir a flag DNSSEC nas consultas de DNS em andamento e verificar o resultado (é necessário um resolvedor DNSSEC ativado)",
|
||||
"validated_with_dnssec": "Validado com DNSSEC",
|
||||
"all_queries": "Todas as consultas",
|
||||
@@ -594,7 +594,7 @@
|
||||
"filter_category_security_desc": "Listas especializadas em bloquear domínios de malware, phishing ou fraude",
|
||||
"filter_category_regional_desc": "Listas focadas em anúncios regionais e servidores de monitorização",
|
||||
"filter_category_other_desc": "Outras listas de bloqueio",
|
||||
"setup_config_to_enable_dhcp_server": "Defina a definição para activar o servidor DHCP",
|
||||
"setup_config_to_enable_dhcp_server": "Defina a configuração para ativar o servidor DHCP",
|
||||
"original_response": "Resposta original",
|
||||
"click_to_view_queries": "Clique para ver as consultas",
|
||||
"port_53_faq_link": "A porta 53 é frequentemente ocupada por serviços \"DNSStubListener\" ou \"systemd-resolved\". Por favor leia <0>essa instrução</0> para resolver isso.",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Bootstrap DNS-серверы",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS-серверы используются для поиска IP-адресов DoH/DoT серверов, которые вы указали.",
|
||||
"local_ptr_title": "Приватные DNS-серверы",
|
||||
"local_ptr_desc": "DNS-серверы, которые AdGuard Home будет использовать для запросов на локальные ресурсы. Например, эти серверы будут использоваться, чтобы получить доменные имена клиентов в приватных сетях. Если список пуст, AdGuard Home будет использовать системный DNS-сервер по умолчанию.",
|
||||
"local_ptr_desc": "DNS-серверы, которые AdGuard Home использует для локальных PTR-запросов. Эти серверы используются, чтобы получить доменные имена клиентов с приватными IP-адресами, например «192.168.12.34», с помощью rDNS. Если список пуст, AdGuard Home использует DNS-серверы по умолчанию вашей ОС.",
|
||||
"local_ptr_placeholder": "Введите по одному адресу на строчку",
|
||||
"resolve_clients_title": "Включить запрашивание доменных имён для IP-адресов клиентов",
|
||||
"resolve_clients_desc": "AdGuard Home будет пытаться определить доменные имена клиентов через PTR-запросы к соответствующим серверам (приватные DNS-серверы для локальных клиентов, upstream-сервер для клиентов с публичным IP-адресом).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Zagonski DNS strežniki",
|
||||
"bootstrap_dns_desc": "Zagonski DNS strežniki se uporabljajo za razreševanje IP naslovov DoH/DoT reševalcev, ki jih določite kot navzgornje.",
|
||||
"local_ptr_title": "Zasebni strežniki DNS",
|
||||
"local_ptr_desc": "Strežniki DNS, ki jih bo AdGuard Home uporabil za poizvedbe o lokalno oskrbovanih virih. Ta strežnik bo na primer uporabljen za razreševanje imen gostiteljev odjemalcev z zasebnimi naslovi IP. Če ni nastavljen, bo AdGuard Home samodejno uporabil vaš privzeti razreševalnik DNS.",
|
||||
"local_ptr_desc": "Strežniki DNS, ki jih AdGuard Home uporablja za lokalne poizvedbe PTR. Ti strežniki se uporabljajo za razreševanje imen gostiteljev z zasebnimi naslovi IP, na primer \"192.168.12.34\" uporablja rDNS. Če ni nastavljen, AdGuard Home uporablja privzete rešitve DNS vašega OS.",
|
||||
"local_ptr_placeholder": "V vrstico vnesite en naslov strežnika",
|
||||
"resolve_clients_title": "Omogoči obratno reševanje naslovov IP gostiteljev",
|
||||
"resolve_clients_desc": "Če je omogočeno, bo AdGuard Home poskušal samodejno razrešiti gostiteljska imena odjemalcev iz njihovih naslovov IP tako, da pošlje poizvedbo PTR ustreznemu razreševalniku (zasebni strežniki DNS za lokalne odjemalce, gorvodni strežnik za odjemalce z javnimi naslovi IP).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Bootstrap DNS 服务器",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS 服务器用于解析您指定为上游的 DoH / DoT 解析器的 IP 地址。",
|
||||
"local_ptr_title": "私人 DNS 服务器",
|
||||
"local_ptr_desc": "AdGuard Home 用于查询本地服务资源的 DNS 服务器。例如,该服务器将被用作具有私人 IP 地址的客户机解析客户机的主机名。如果没有设置,AdGuard Home 将自动使用您的默认 DNS 解析器",
|
||||
"local_ptr_desc": "AdGuard Home 用于本地 PTR 查询的 DNS 服务器。例如,该服务器将被用于解析具有私人 IP 地址的客户机的主机名,比如 \"192.168.12.34\",使用 rDNS 。如果没有设置,AdGuard Home 将自动使用您的默认 DNS 解析器。",
|
||||
"local_ptr_placeholder": "每行输入一个服务器地址",
|
||||
"resolve_clients_title": "启用客户端的 IP 地址的反向解析",
|
||||
"resolve_clients_desc": "如果启用,AdGuard Home 将尝试通过发送 PTR 查询到对应的解析器 (本地客户端的私人 DNS 服务器,公有 IP 客户端的上游服务器) 将 IP 地址反向解析成其客户端主机名。",
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
"load_balancing_desc": "一次只查詢一個伺服器。AdGuard Home 會使用加權隨機取樣來選擇使用的查詢結果,以確保速度最快的伺服器能被充分運用。",
|
||||
"bootstrap_dns": "引導(Boostrap) DNS 伺服器",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS 伺服器用於解析您所設定的上游 DoH/DoT 解析器的 IP 地址",
|
||||
"local_ptr_title": "私人 DNS 伺服器",
|
||||
"local_ptr_desc": "AdGuard Home 用於區域 PTR 查詢的 DNS 伺服器。該伺服器將被用於解析具有私人 IP 位址的用戶端的主機名稱,比如 \"192.168.12.34\",使用 rDNS。如果沒有設定,AdGuard Home 將自動使用您的預設 DNS 解析器。",
|
||||
"local_ptr_placeholder": "每行輸入一個伺服器位址",
|
||||
"resolve_clients_title": "啟用用戶端的 IP 位址的反向解析",
|
||||
"resolve_clients_desc": "如果啟用,AdGuard Home 將嘗試透過傳送 PTR 查詢到對應的解析器 (本機用戶端的私人 DNS 伺服器,公有 IP 用戶端的上遊伺服器) ,將 IP 位址反向解析成其用戶端的主機名稱。",
|
||||
"check_dhcp_servers": "檢查 DHCP 伺服器",
|
||||
"save_config": "儲存設定",
|
||||
"enabled_dhcp": "DHCP 伺服器已啟動",
|
||||
@@ -33,6 +38,7 @@
|
||||
"form_error_mac_format": "無效的 「MAC 位址」格式",
|
||||
"form_error_client_id_format": "無效的「客戶端 ID」格式",
|
||||
"form_error_server_name": "無效伺服器名稱",
|
||||
"form_error_subnet": "子網路 \"{{cidr}}\" 不包含 IP 位址 \"{{ip}}\"",
|
||||
"form_error_positive": "數值必須大於 0",
|
||||
"form_error_negative": "數值必須大於等於 0",
|
||||
"range_end_error": "必須大於起始值",
|
||||
@@ -395,6 +401,7 @@
|
||||
"ip_address": "IP 位址",
|
||||
"client_identifier_desc": "可通過 IP 地址、CIDR、MAC 地址來辨識使用者裝置。注意:必須使用 AdGuard Home 內建 <0>DHCP 伺服器</0> 才能偵測 MAC 地址。",
|
||||
"form_enter_ip": "輸入 IP",
|
||||
"form_enter_subnet_ip": "在子網路 \"{{cidr}}\" 中輸入一個 IP 位址",
|
||||
"form_enter_mac": "輸入 MAC 地址",
|
||||
"form_enter_id": "輸入識別碼",
|
||||
"form_add_id": "新增識別碼",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "自我啟動(Bootstrap)DNS 伺服器",
|
||||
"bootstrap_dns_desc": "自我啟動(Bootstrap)DNS 伺服器被用於解析您明確指定作為上游的 DoH/DoT 解析器之 IP 位址。",
|
||||
"local_ptr_title": "私人 DNS 伺服器",
|
||||
"local_ptr_desc": "AdGuard Home 將用於供在本地服務的資源的查詢之 DNS 伺服器。例如,此伺服器將被用於對於有私人 IP 位址的用戶端解析其主機名稱。如果未被設定,AdGuard Home 將自動地使用您的預設 DNS 解析器。",
|
||||
"local_ptr_desc": "AdGuard Home 用於區域指標(PTR)查詢之 DNS 伺服器。這些伺服器被用於解析含私人 IP 位址的用戶端之主機名稱,例如,\"192.168.12.34\",使用反向的 DNS(rDNS)。如果未被設定,AdGuard Home 使用您的作業系統之預設 DNS 解析器。",
|
||||
"local_ptr_placeholder": "每行輸入一個伺服器位址",
|
||||
"resolve_clients_title": "啟用用戶端的 IP 位址之反向的解析",
|
||||
"resolve_clients_desc": "如果被啟用,透過傳送指標(PTR)查詢到對應的解析器(私人 DNS 伺服器供區域的用戶端,上游的伺服器供有公共 IP 位址的用戶端),AdGuard Home 將試圖反向地解析用戶端的 IP 位址變為它們的主機名稱。",
|
||||
|
||||
@@ -209,7 +209,6 @@ ClientCell.propTypes = {
|
||||
client: propTypes.string.isRequired,
|
||||
client_id: propTypes.string,
|
||||
client_info: propTypes.shape({
|
||||
ids: propTypes.arrayOf(propTypes.string).isRequired,
|
||||
name: propTypes.string.isRequired,
|
||||
whois: propTypes.shape({
|
||||
country: propTypes.string,
|
||||
|
||||
@@ -231,7 +231,6 @@ Row.propTypes = {
|
||||
client_proto: propTypes.string.isRequired,
|
||||
client_id: propTypes.string,
|
||||
client_info: propTypes.shape({
|
||||
ids: propTypes.arrayOf(propTypes.string).isRequired,
|
||||
name: propTypes.string.isRequired,
|
||||
whois: propTypes.shape({
|
||||
country: propTypes.string,
|
||||
|
||||
@@ -63,8 +63,8 @@ const Logs = () => {
|
||||
const history = useHistory();
|
||||
|
||||
const {
|
||||
response_status: response_status_url_param = '',
|
||||
search: search_url_param = '',
|
||||
response_status: response_status_url_param,
|
||||
search: search_url_param,
|
||||
} = queryString.parse(history.location.search);
|
||||
|
||||
const {
|
||||
@@ -76,8 +76,8 @@ const Logs = () => {
|
||||
const filter = useSelector((state) => state.queryLogs.filter, shallowEqual);
|
||||
const logs = useSelector((state) => state.queryLogs.logs, shallowEqual);
|
||||
|
||||
const search = filter?.search || search_url_param;
|
||||
const response_status = filter?.response_status || response_status_url_param;
|
||||
const search = filter?.search || search_url_param || '';
|
||||
const response_status = filter?.response_status || response_status_url_param || '';
|
||||
|
||||
const [isSmallScreen, setIsSmallScreen] = useState(window.innerWidth < SMALL_SCREEN_SIZE);
|
||||
const [detailedDataCurrent, setDetailedDataCurrent] = useState({});
|
||||
|
||||
@@ -27,6 +27,7 @@ const Form = (props) => {
|
||||
component={renderInputField}
|
||||
placeholder={t('username_placeholder')}
|
||||
autoComplete="username"
|
||||
autocapitalize="none"
|
||||
disabled={processing}
|
||||
validate={[validateRequiredValue]}
|
||||
/>
|
||||
|
||||
6
go.mod
6
go.mod
@@ -3,8 +3,8 @@ module github.com/AdguardTeam/AdGuardHome
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/dnsproxy v0.37.2
|
||||
github.com/AdguardTeam/golibs v0.4.5
|
||||
github.com/AdguardTeam/dnsproxy v0.37.4
|
||||
github.com/AdguardTeam/golibs v0.5.0
|
||||
github.com/AdguardTeam/urlfilter v0.14.5
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/ameshkov/dnscrypt/v2 v2.1.3
|
||||
@@ -40,4 +40,4 @@ require (
|
||||
howett.net/plist v0.0.0-20201203080718-1454fab16a06
|
||||
)
|
||||
|
||||
replace github.com/insomniacslk/dhcp => github.com/AdguardTeam/dhcp v0.0.0-20210420175708-50b0efd52063
|
||||
replace github.com/insomniacslk/dhcp => github.com/AdguardTeam/dhcp v0.0.0-20210517101438-550ef4cd8c6e
|
||||
|
||||
12
go.sum
12
go.sum
@@ -18,15 +18,15 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/AdguardTeam/dhcp v0.0.0-20210420175708-50b0efd52063 h1:RBsQppxEJEqHApY6WDBkM2H0UG5wt57RcT0El2WGdp8=
|
||||
github.com/AdguardTeam/dhcp v0.0.0-20210420175708-50b0efd52063/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI=
|
||||
github.com/AdguardTeam/dnsproxy v0.37.2 h1:3lgizD+lZI6uqxFiQykd1/hV7Ji4vSJBMejl1rbFAXU=
|
||||
github.com/AdguardTeam/dnsproxy v0.37.2/go.mod h1:xkJWEuTr550gPDmB9azsciKZzSXjf9wMn+Ji54PQ4gE=
|
||||
github.com/AdguardTeam/dhcp v0.0.0-20210517101438-550ef4cd8c6e h1:M6YnFP12o0/SjBEPt6b2r8ZkIy/wsV14TK8X9Tb6DEE=
|
||||
github.com/AdguardTeam/dhcp v0.0.0-20210517101438-550ef4cd8c6e/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI=
|
||||
github.com/AdguardTeam/dnsproxy v0.37.4 h1:YIoJkIp828LKmmmgxXvZHUKfGLsqTQAK8g+4DXbDbyU=
|
||||
github.com/AdguardTeam/dnsproxy v0.37.4/go.mod h1:xkJWEuTr550gPDmB9azsciKZzSXjf9wMn+Ji54PQ4gE=
|
||||
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.4/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||
github.com/AdguardTeam/golibs v0.4.5 h1:RRA9ZsmbJEN4OllAx0BcfvSbRBxxpWluJijBYmtp13U=
|
||||
github.com/AdguardTeam/golibs v0.4.5/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||
github.com/AdguardTeam/golibs v0.5.0 h1:qwhEKjDrT0UcwDnHrNU2Yg/DLR9b/GsUncnXYW6VzAU=
|
||||
github.com/AdguardTeam/golibs v0.5.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||
github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
|
||||
github.com/AdguardTeam/urlfilter v0.14.5 h1:WyF0hg0MwKevsqNPkoaZFH8f5WRi/yuy/7qePtYt5Ts=
|
||||
github.com/AdguardTeam/urlfilter v0.14.5/go.mod h1:klx4JbOfc4EaNb5lWLqOwfg+pVcyRukmoJRvO55lL5U=
|
||||
|
||||
@@ -48,32 +48,32 @@ const maxDomainLabelLen = 63
|
||||
// See https://stackoverflow.com/a/32294443/1892060.
|
||||
const maxDomainNameLen = 253
|
||||
|
||||
const invalidCharMsg = "invalid char %q at index %d in %q"
|
||||
|
||||
// ValidateDomainNameLabel returns an error if label is not a valid label of
|
||||
// a domain name.
|
||||
func ValidateDomainNameLabel(label string) (err error) {
|
||||
defer agherr.Annotate("validating label %q: %w", &err, label)
|
||||
|
||||
l := len(label)
|
||||
if l > maxDomainLabelLen {
|
||||
return fmt.Errorf("%q is too long, max: %d", label, maxDomainLabelLen)
|
||||
return fmt.Errorf("label is too long, max: %d", maxDomainLabelLen)
|
||||
} else if l == 0 {
|
||||
return agherr.Error("label is empty")
|
||||
}
|
||||
|
||||
if r := label[0]; !IsValidHostOuterRune(rune(r)) {
|
||||
return fmt.Errorf(invalidCharMsg, r, 0, label)
|
||||
return fmt.Errorf("invalid char %q at index %d", r, 0)
|
||||
} else if l == 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i, r := range label[1 : l-1] {
|
||||
if !isValidHostRune(r) {
|
||||
return fmt.Errorf(invalidCharMsg, r, i+1, label)
|
||||
return fmt.Errorf("invalid char %q at index %d", r, i+1)
|
||||
}
|
||||
}
|
||||
|
||||
if r := label[l-1]; !IsValidHostOuterRune(rune(r)) {
|
||||
return fmt.Errorf(invalidCharMsg, r, l-1, label)
|
||||
return fmt.Errorf("invalid char %q at index %d", r, l-1)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -87,6 +87,8 @@ func ValidateDomainNameLabel(label string) (err error) {
|
||||
// TODO(a.garipov): After making sure that this works correctly, port this into
|
||||
// module golibs.
|
||||
func ValidateDomainName(name string) (err error) {
|
||||
defer agherr.Annotate("validating domain name %q: %w", &err, name)
|
||||
|
||||
name, err = idna.ToASCII(name)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -96,7 +98,7 @@ func ValidateDomainName(name string) (err error) {
|
||||
if l == 0 {
|
||||
return agherr.Error("domain name is empty")
|
||||
} else if l > maxDomainNameLen {
|
||||
return fmt.Errorf("%q is too long, max: %d", name, maxDomainNameLen)
|
||||
return fmt.Errorf("too long, max: %d", maxDomainNameLen)
|
||||
}
|
||||
|
||||
labels := strings.Split(name, ".")
|
||||
|
||||
@@ -95,40 +95,46 @@ func TestValidateDomainName(t *testing.T) {
|
||||
}, {
|
||||
name: "empty",
|
||||
in: "",
|
||||
wantErrMsg: `domain name is empty`,
|
||||
wantErrMsg: `validating domain name "": domain name is empty`,
|
||||
}, {
|
||||
name: "bad_symbol",
|
||||
in: "!!!",
|
||||
wantErrMsg: `invalid domain name label at index 0: ` +
|
||||
`invalid char '!' at index 0 in "!!!"`,
|
||||
wantErrMsg: `validating domain name "!!!": invalid domain name label at index 0: ` +
|
||||
`validating label "!!!": invalid char '!' at index 0`,
|
||||
}, {
|
||||
name: "bad_length",
|
||||
in: longDomainName,
|
||||
wantErrMsg: `"` + longDomainName + `" is too long, max: 253`,
|
||||
wantErrMsg: `validating domain name "` + longDomainName + `": too long, max: 253`,
|
||||
}, {
|
||||
name: "bad_label_length",
|
||||
in: longLabelDomainName,
|
||||
wantErrMsg: `invalid domain name label at index 0: "` + longLabel +
|
||||
`" is too long, max: 63`,
|
||||
wantErrMsg: `validating domain name "` + longLabelDomainName + `": ` +
|
||||
`invalid domain name label at index 0: validating label "` + longLabel +
|
||||
`": label is too long, max: 63`,
|
||||
}, {
|
||||
name: "bad_label_empty",
|
||||
in: "example..com",
|
||||
wantErrMsg: `invalid domain name label at index 1: label is empty`,
|
||||
name: "bad_label_empty",
|
||||
in: "example..com",
|
||||
wantErrMsg: `validating domain name "example..com": ` +
|
||||
`invalid domain name label at index 1: ` +
|
||||
`validating label "": label is empty`,
|
||||
}, {
|
||||
name: "bad_label_first_symbol",
|
||||
in: "example.-aa.com",
|
||||
wantErrMsg: `invalid domain name label at index 1:` +
|
||||
` invalid char '-' at index 0 in "-aa"`,
|
||||
wantErrMsg: `validating domain name "example.-aa.com": ` +
|
||||
`invalid domain name label at index 1: ` +
|
||||
`validating label "-aa": invalid char '-' at index 0`,
|
||||
}, {
|
||||
name: "bad_label_last_symbol",
|
||||
in: "example-.aa.com",
|
||||
wantErrMsg: `invalid domain name label at index 0:` +
|
||||
` invalid char '-' at index 7 in "example-"`,
|
||||
wantErrMsg: `validating domain name "example-.aa.com": ` +
|
||||
`invalid domain name label at index 0: ` +
|
||||
`validating label "example-": invalid char '-' at index 7`,
|
||||
}, {
|
||||
name: "bad_label_symbol",
|
||||
in: "example.a!!!.com",
|
||||
wantErrMsg: `invalid domain name label at index 1:` +
|
||||
` invalid char '!' at index 1 in "a!!!"`,
|
||||
wantErrMsg: `validating domain name "example.a!!!.com": ` +
|
||||
`invalid domain name label at index 1: ` +
|
||||
`validating label "a!!!": invalid char '!' at index 1`,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
||||
@@ -26,11 +26,15 @@ type SystemResolvers interface {
|
||||
}
|
||||
|
||||
const (
|
||||
// fakeDialErr is an error which dialFunc is expected to return.
|
||||
fakeDialErr agherr.Error = "this error signals the successful dialFunc work"
|
||||
// errBadAddrPassed is returned when dialFunc can't parse an IP address.
|
||||
errBadAddrPassed agherr.Error = "the passed string is not a valid IP address"
|
||||
|
||||
// badAddrPassedErr is returned when dialFunc can't parse an IP address.
|
||||
badAddrPassedErr agherr.Error = "the passed string is not a valid IP address"
|
||||
// errFakeDial is an error which dialFunc is expected to return.
|
||||
errFakeDial agherr.Error = "this error signals the successful dialFunc work"
|
||||
|
||||
// errUnexpectedHostFormat is returned by validateDialedHost when the host has
|
||||
// more than one percent sign.
|
||||
errUnexpectedHostFormat agherr.Error = "unexpected host format"
|
||||
)
|
||||
|
||||
// refreshWithTicker refreshes the cache of sr after each tick form tickCh.
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -35,7 +36,7 @@ func (sr *systemResolvers) refresh() (err error) {
|
||||
|
||||
_, err = sr.resolver.LookupHost(context.Background(), sr.hostGenFunc())
|
||||
dnserr := &net.DNSError{}
|
||||
if errors.As(err, &dnserr) && dnserr.Err == fakeDialErr.Error() {
|
||||
if errors.As(err, &dnserr) && dnserr.Err == errFakeDial.Error() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -58,19 +59,60 @@ func newSystemResolvers(refreshIvl time.Duration, hostGenFunc HostGenFunc) (sr S
|
||||
return s
|
||||
}
|
||||
|
||||
// validateDialedHost validated the host used by resolvers in dialFunc.
|
||||
func validateDialedHost(host string) (err error) {
|
||||
defer agherr.Annotate("parsing %q: %w", &err, host)
|
||||
|
||||
var ipStr string
|
||||
parts := strings.Split(host, "%")
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
ipStr = host
|
||||
case 2:
|
||||
// Remove the zone and check the IP address part.
|
||||
ipStr = parts[0]
|
||||
default:
|
||||
return errUnexpectedHostFormat
|
||||
}
|
||||
|
||||
if net.ParseIP(ipStr) == nil {
|
||||
return errBadAddrPassed
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// dockerEmbeddedDNS is the address of Docker's embedded DNS server.
|
||||
//
|
||||
// See
|
||||
// https://github.com/moby/moby/blob/v1.12.0/docs/userguide/networking/dockernetworks.md.
|
||||
const dockerEmbeddedDNS = "127.0.0.11"
|
||||
|
||||
// dialFunc gets the resolver's address and puts it into internal cache.
|
||||
func (sr *systemResolvers) dialFunc(_ context.Context, _, address string) (_ net.Conn, err error) {
|
||||
// Just validate the passed address is a valid IP.
|
||||
var host string
|
||||
host, err = SplitHost(address)
|
||||
if err != nil {
|
||||
// TODO(e.burkov): Maybe use a structured badAddrPassedErr to
|
||||
// TODO(e.burkov): Maybe use a structured errBadAddrPassed to
|
||||
// allow unwrapping of the real error.
|
||||
return nil, fmt.Errorf("%s: %w", err, badAddrPassedErr)
|
||||
return nil, fmt.Errorf("%s: %w", err, errBadAddrPassed)
|
||||
}
|
||||
|
||||
if net.ParseIP(host) == nil {
|
||||
return nil, fmt.Errorf("parsing %q: %w", host, badAddrPassedErr)
|
||||
// Exclude Docker's embedded DNS server, as it may cause recursion if
|
||||
// the container is set as the host system's default DNS server.
|
||||
//
|
||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/3064.
|
||||
//
|
||||
// TODO(a.garipov): Perhaps only do this when we are in the container?
|
||||
// Maybe use an environment variable?
|
||||
if host == dockerEmbeddedDNS {
|
||||
return nil, errFakeDial
|
||||
}
|
||||
|
||||
err = validateDialedHost(host)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("validating dialed host: %w", err)
|
||||
}
|
||||
|
||||
sr.addrsLock.Lock()
|
||||
@@ -78,7 +120,7 @@ func (sr *systemResolvers) dialFunc(_ context.Context, _, address string) (_ net
|
||||
|
||||
sr.addrs.Add(host)
|
||||
|
||||
return nil, fakeDialErr
|
||||
return nil, errFakeDial
|
||||
}
|
||||
|
||||
func (sr *systemResolvers) Get() (rs []string) {
|
||||
|
||||
@@ -46,21 +46,33 @@ func TestSystemResolvers_DialFunc(t *testing.T) {
|
||||
imp := createTestSystemResolversImp(t, 0, nil)
|
||||
|
||||
testCases := []struct {
|
||||
want error
|
||||
name string
|
||||
address string
|
||||
want error
|
||||
}{{
|
||||
want: errFakeDial,
|
||||
name: "valid",
|
||||
address: "127.0.0.1",
|
||||
want: fakeDialErr,
|
||||
}, {
|
||||
want: errFakeDial,
|
||||
name: "valid_ipv6_port",
|
||||
address: "[::1]:53",
|
||||
}, {
|
||||
want: errFakeDial,
|
||||
name: "valid_ipv6_zone_port",
|
||||
address: "[::1%lo0]:53",
|
||||
}, {
|
||||
want: errBadAddrPassed,
|
||||
name: "invalid_split_host",
|
||||
address: "127.0.0.1::123",
|
||||
want: badAddrPassedErr,
|
||||
}, {
|
||||
want: errUnexpectedHostFormat,
|
||||
name: "invalid_ipv6_zone_port",
|
||||
address: "[::1%%lo0]:53",
|
||||
}, {
|
||||
want: errBadAddrPassed,
|
||||
name: "invalid_parse_ip",
|
||||
address: "not-ip",
|
||||
want: badAddrPassedErr,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build darwin
|
||||
// +build darwin netbsd openbsd
|
||||
|
||||
package aghos
|
||||
|
||||
@@ -27,13 +27,13 @@ var webHandlersRegistered = false
|
||||
|
||||
// Lease contains the necessary information about a DHCP lease
|
||||
type Lease struct {
|
||||
// Expiry is the expiration time of the lease. The unix timestamp value
|
||||
// of 1 means that this is a static lease.
|
||||
Expiry time.Time `json:"expires"`
|
||||
|
||||
Hostname string `json:"hostname"`
|
||||
HWAddr net.HardwareAddr `json:"mac"`
|
||||
IP net.IP `json:"ip"`
|
||||
Hostname string `json:"hostname"`
|
||||
|
||||
// Lease expiration time
|
||||
// 1: static lease
|
||||
Expiry time.Time `json:"expires"`
|
||||
}
|
||||
|
||||
// IsStatic returns true if the lease is static.
|
||||
@@ -133,6 +133,7 @@ type Server struct {
|
||||
|
||||
// ServerInterface is an interface for servers.
|
||||
type ServerInterface interface {
|
||||
Enabled() (ok bool)
|
||||
Leases(flags int) []Lease
|
||||
SetOnLeaseChanged(onLeaseChanged OnLeaseChangedT)
|
||||
}
|
||||
@@ -207,6 +208,11 @@ func Create(conf ServerConfig) *Server {
|
||||
return s
|
||||
}
|
||||
|
||||
// Enabled returns true when the server is enabled.
|
||||
func (s *Server) Enabled() (ok bool) {
|
||||
return s.conf.Enabled
|
||||
}
|
||||
|
||||
// server calls this function after DB is updated
|
||||
func (s *Server) onNotify(flags uint32) {
|
||||
if flags == LeaseChangedDBStore {
|
||||
|
||||
@@ -37,30 +37,34 @@ func TestDB(t *testing.T) {
|
||||
SubnetMask: net.IP{255, 255, 255, 0},
|
||||
notify: testNotify,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
s.srv6, err = v6Create(V6ServerConf{})
|
||||
require.Nil(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
leases := []Lease{{
|
||||
IP: net.IP{192, 168, 10, 100},
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Expiry: time.Now().Add(time.Hour),
|
||||
Expiry: time.Now().Add(time.Hour),
|
||||
Hostname: "static-1.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 100},
|
||||
}, {
|
||||
IP: net.IP{192, 168, 10, 101},
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xBB},
|
||||
Hostname: "static-2.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xBB},
|
||||
IP: net.IP{192, 168, 10, 101},
|
||||
}}
|
||||
|
||||
srv4, ok := s.srv4.(*v4Server)
|
||||
require.True(t, ok)
|
||||
|
||||
err = srv4.addLease(&leases[0])
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, s.srv4.AddStaticLease(leases[1]))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.srv4.AddStaticLease(leases[1])
|
||||
require.NoError(t, err)
|
||||
|
||||
s.dbStore()
|
||||
t.Cleanup(func() {
|
||||
assert.Nil(t, os.Remove(dbFilename))
|
||||
assert.NoError(t, os.Remove(dbFilename))
|
||||
})
|
||||
s.srv4.ResetLeases(nil)
|
||||
s.dbLoad()
|
||||
|
||||
@@ -36,7 +36,7 @@ type v4Server struct {
|
||||
// leases contains all dynamic and static leases.
|
||||
leases []*Lease
|
||||
|
||||
// leasesLock protects leases and leasedOffsets.
|
||||
// leasesLock protects leases, leaseHosts, and leasedOffsets.
|
||||
leasesLock sync.Mutex
|
||||
}
|
||||
|
||||
@@ -49,8 +49,56 @@ func (s *v4Server) WriteDiskConfig4(c *V4ServerConf) {
|
||||
func (s *v4Server) WriteDiskConfig6(c *V6ServerConf) {
|
||||
}
|
||||
|
||||
// normalizeHostname normalizes a hostname sent by the client. If err is not
|
||||
// nil, norm is an empty string.
|
||||
func normalizeHostname(hostname string) (norm string, err error) {
|
||||
defer agherr.Annotate("normalizing %q: %w", &err, hostname)
|
||||
|
||||
if hostname == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
norm = strings.ToLower(hostname)
|
||||
parts := strings.FieldsFunc(norm, func(c rune) (ok bool) {
|
||||
return c != '.' && !aghnet.IsValidHostOuterRune(c)
|
||||
})
|
||||
|
||||
if len(parts) == 0 {
|
||||
return "", fmt.Errorf("no valid parts")
|
||||
}
|
||||
|
||||
norm = strings.Join(parts, "-")
|
||||
norm = strings.TrimSuffix(norm, "-")
|
||||
|
||||
return norm, nil
|
||||
}
|
||||
|
||||
// validHostnameForClient accepts the hostname sent by the client and its IP and
|
||||
// returns either a normalized version of that hostname, or a new hostname
|
||||
// generated from the IP address, or an empty string.
|
||||
func (s *v4Server) validHostnameForClient(cliHostname string, ip net.IP) (hostname string) {
|
||||
hostname, err := normalizeHostname(cliHostname)
|
||||
if err != nil {
|
||||
log.Info("dhcpv4: %s", err)
|
||||
}
|
||||
|
||||
if hostname == "" {
|
||||
hostname = aghnet.GenerateHostname(ip)
|
||||
}
|
||||
|
||||
err = aghnet.ValidateDomainName(hostname)
|
||||
if err != nil {
|
||||
log.Info("dhcpv4: %s", err)
|
||||
hostname = ""
|
||||
}
|
||||
|
||||
return hostname
|
||||
}
|
||||
|
||||
// ResetLeases - reset leases
|
||||
func (s *v4Server) ResetLeases(leases []*Lease) {
|
||||
var err error
|
||||
|
||||
if !s.conf.Enabled {
|
||||
return
|
||||
}
|
||||
@@ -60,9 +108,10 @@ func (s *v4Server) ResetLeases(leases []*Lease) {
|
||||
s.leases = nil
|
||||
|
||||
for _, l := range leases {
|
||||
err := s.addLease(l)
|
||||
l.Hostname = s.validHostnameForClient(l.Hostname, l.IP)
|
||||
err = s.addLease(l)
|
||||
if err != nil {
|
||||
// TODO(a.garipov): Better error handling.
|
||||
// TODO(a.garipov): Wrap and bubble up the error.
|
||||
log.Error(
|
||||
"dhcpv4: reset: re-adding a lease for %s (%s): %s",
|
||||
l.IP,
|
||||
@@ -197,7 +246,7 @@ func (s *v4Server) rmDynamicLease(lease *Lease) (err error) {
|
||||
|
||||
if bytes.Equal(l.HWAddr, lease.HWAddr) {
|
||||
if l.IsStatic() {
|
||||
return fmt.Errorf("static lease already exists")
|
||||
return agherr.Error("static lease already exists")
|
||||
}
|
||||
|
||||
s.rmLeaseByIndex(i)
|
||||
@@ -208,66 +257,52 @@ func (s *v4Server) rmDynamicLease(lease *Lease) (err error) {
|
||||
l = s.leases[i]
|
||||
}
|
||||
|
||||
if net.IP.Equal(l.IP, lease.IP) {
|
||||
if l.IP.Equal(lease.IP) {
|
||||
if l.IsStatic() {
|
||||
return fmt.Errorf("static lease already exists")
|
||||
return agherr.Error("static lease already exists")
|
||||
}
|
||||
|
||||
s.rmLeaseByIndex(i)
|
||||
if i == len(s.leases) {
|
||||
break
|
||||
}
|
||||
|
||||
l = s.leases[i]
|
||||
}
|
||||
|
||||
if l.Hostname == lease.Hostname {
|
||||
l.Hostname = ""
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *v4Server) addStaticLease(l *Lease) (err error) {
|
||||
if sn := s.conf.subnet; !sn.Contains(l.IP) {
|
||||
return fmt.Errorf("subnet %s does not contain the ip %q", sn, l.IP)
|
||||
}
|
||||
|
||||
s.leases = append(s.leases, l)
|
||||
|
||||
// addLease adds a dynamic or static lease.
|
||||
func (s *v4Server) addLease(l *Lease) (err error) {
|
||||
r := s.conf.ipRange
|
||||
offset, ok := r.offset(l.IP)
|
||||
if ok {
|
||||
s.leasedOffsets.set(offset, true)
|
||||
}
|
||||
offset, inOffset := r.offset(l.IP)
|
||||
|
||||
s.leaseHosts.Add(l.Hostname)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *v4Server) addDynamicLease(l *Lease) (err error) {
|
||||
r := s.conf.ipRange
|
||||
offset, ok := r.offset(l.IP)
|
||||
if !ok {
|
||||
if l.IsStatic() {
|
||||
if sn := s.conf.subnet; !sn.Contains(l.IP) {
|
||||
return fmt.Errorf("subnet %s does not contain the ip %q", sn, l.IP)
|
||||
}
|
||||
} else if !inOffset {
|
||||
return fmt.Errorf("lease %s (%s) out of range, not adding", l.IP, l.HWAddr)
|
||||
}
|
||||
|
||||
s.leases = append(s.leases, l)
|
||||
s.leaseHosts.Add(l.Hostname)
|
||||
s.leasedOffsets.set(offset, true)
|
||||
|
||||
if l.Hostname != "" {
|
||||
s.leaseHosts.Add(l.Hostname)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// addLease adds a dynamic or static lease.
|
||||
func (s *v4Server) addLease(l *Lease) (err error) {
|
||||
err = s.validateLease(l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if l.IsStatic() {
|
||||
return s.addStaticLease(l)
|
||||
}
|
||||
|
||||
return s.addDynamicLease(l)
|
||||
}
|
||||
|
||||
// Remove a lease with the same properties
|
||||
func (s *v4Server) rmLease(lease Lease) error {
|
||||
// rmLease removes a lease with the same properties.
|
||||
func (s *v4Server) rmLease(lease Lease) (err error) {
|
||||
if len(s.leases) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -289,7 +324,7 @@ func (s *v4Server) rmLease(lease Lease) error {
|
||||
|
||||
// AddStaticLease adds a static lease. It is safe for concurrent use.
|
||||
func (s *v4Server) AddStaticLease(l Lease) (err error) {
|
||||
defer agherr.Annotate("dhcpv4: %w", &err)
|
||||
defer agherr.Annotate("dhcpv4: adding static lease: %w", &err)
|
||||
|
||||
if ip4 := l.IP.To4(); ip4 == nil {
|
||||
return fmt.Errorf("invalid ip %q, only ipv4 is supported", l.IP)
|
||||
@@ -297,11 +332,31 @@ func (s *v4Server) AddStaticLease(l Lease) (err error) {
|
||||
|
||||
l.Expiry = time.Unix(leaseExpireStatic, 0)
|
||||
|
||||
l.Hostname, err = normalizeHostname(l.Hostname)
|
||||
err = aghnet.ValidateHardwareAddress(l.HWAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if l.Hostname != "" {
|
||||
var hostname string
|
||||
hostname, err = normalizeHostname(l.Hostname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = aghnet.ValidateDomainName(hostname)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validating hostname: %w", err)
|
||||
}
|
||||
|
||||
// Don't check for hostname uniqueness, since we try to emulate
|
||||
// dnsmasq here, which means that rmDynamicLease below will
|
||||
// simply empty the hostname of the dynamic lease if there even
|
||||
// is one.
|
||||
|
||||
l.Hostname = hostname
|
||||
}
|
||||
|
||||
// Perform the following actions in an anonymous function to make sure
|
||||
// that the lock gets unlocked before the notification step.
|
||||
func() {
|
||||
@@ -365,16 +420,19 @@ func (s *v4Server) RemoveStaticLease(l Lease) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Send ICMP to the specified machine
|
||||
// Return TRUE if it doesn't reply, which probably means that the IP is available
|
||||
func (s *v4Server) addrAvailable(target net.IP) bool {
|
||||
// addrAvailable sends an ICP request to the specified IP address. It returns
|
||||
// true if the remote host doesn't reply, which probably means that the IP
|
||||
// address is available.
|
||||
//
|
||||
// TODO(a.garipov): I'm not sure that this is the best way to do this.
|
||||
func (s *v4Server) addrAvailable(target net.IP) (avail bool) {
|
||||
if s.conf.ICMPTimeout == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
pinger, err := ping.NewPinger(target.String())
|
||||
if err != nil {
|
||||
log.Error("ping.NewPinger(): %v", err)
|
||||
log.Error("dhcpv4: ping.NewPinger(): %s", err)
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -386,20 +444,24 @@ func (s *v4Server) addrAvailable(target net.IP) bool {
|
||||
pinger.OnRecv = func(_ *ping.Packet) {
|
||||
reply = true
|
||||
}
|
||||
log.Debug("dhcpv4: Sending ICMP Echo to %v", target)
|
||||
|
||||
log.Debug("dhcpv4: sending icmp echo to %s", target)
|
||||
|
||||
err = pinger.Run()
|
||||
if err != nil {
|
||||
log.Error("pinger.Run(): %v", err)
|
||||
log.Error("dhcpv4: pinger.Run(): %s", err)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if reply {
|
||||
log.Info("dhcpv4: IP conflict: %v is already used by another device", target)
|
||||
log.Info("dhcpv4: ip conflict: %s is already used by another device", target)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
log.Debug("dhcpv4: ICMP procedure is complete: %v", target)
|
||||
log.Debug("dhcpv4: icmp procedure is complete: %q", target)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -474,58 +536,67 @@ func (s *v4Server) reserveLease(mac net.HardwareAddr) (l *Lease, err error) {
|
||||
func (s *v4Server) commitLease(l *Lease) {
|
||||
l.Expiry = time.Now().Add(s.conf.leaseTime)
|
||||
|
||||
s.leasesLock.Lock()
|
||||
s.conf.notify(LeaseChangedDBStore)
|
||||
s.leasesLock.Unlock()
|
||||
func() {
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
s.conf.notify(LeaseChangedDBStore)
|
||||
|
||||
if l.Hostname != "" {
|
||||
s.leaseHosts.Add(l.Hostname)
|
||||
}
|
||||
}()
|
||||
|
||||
s.conf.notify(LeaseChangedAdded)
|
||||
}
|
||||
|
||||
// Process Discover request and return lease
|
||||
// allocateLease allocates a new lease for the MAC address. If there are no IP
|
||||
// addresses left, both l and err are nil.
|
||||
func (s *v4Server) allocateLease(mac net.HardwareAddr) (l *Lease, err error) {
|
||||
for {
|
||||
l, err = s.reserveLease(mac)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reserving a lease: %w", err)
|
||||
} else if l == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if s.addrAvailable(l.IP) {
|
||||
return l, nil
|
||||
}
|
||||
|
||||
s.blocklistLease(l)
|
||||
}
|
||||
}
|
||||
|
||||
// processDiscover is the handler for the DHCP Discover request.
|
||||
func (s *v4Server) processDiscover(req, resp *dhcpv4.DHCPv4) (l *Lease, err error) {
|
||||
mac := req.ClientHWAddr
|
||||
|
||||
defer s.conf.notify(LeaseChangedDBStore)
|
||||
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
// TODO(a.garipov): Refactor this mess.
|
||||
l = s.findLease(mac)
|
||||
if l == nil {
|
||||
toStore := false
|
||||
for l == nil {
|
||||
l, err = s.reserveLease(mac)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reserving a lease: %w", err)
|
||||
}
|
||||
|
||||
if l == nil {
|
||||
log.Debug("dhcpv4: no more ip addresses")
|
||||
if toStore {
|
||||
s.conf.notify(LeaseChangedDBStore)
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Return a special error?
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
toStore = true
|
||||
|
||||
if !s.addrAvailable(l.IP) {
|
||||
s.blocklistLease(l)
|
||||
l = nil
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
s.conf.notify(LeaseChangedDBStore)
|
||||
} else {
|
||||
if l != nil {
|
||||
reqIP := req.RequestedIPAddress()
|
||||
if len(reqIP) != 0 && !reqIP.Equal(l.IP) {
|
||||
log.Debug("dhcpv4: different RequestedIP: %s != %s", reqIP, l.IP)
|
||||
}
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeOffer))
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
l, err = s.allocateLease(mac)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if l == nil {
|
||||
log.Debug("dhcpv4: no more ip addresses")
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeOffer))
|
||||
@@ -562,82 +633,8 @@ func (o *optFQDN) ToBytes() []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
// normalizeHostname normalizes a hostname sent by the client.
|
||||
func normalizeHostname(name string) (norm string, err error) {
|
||||
if name == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
norm = strings.ToLower(name)
|
||||
parts := strings.FieldsFunc(norm, func(c rune) (ok bool) {
|
||||
return c != '.' && !aghnet.IsValidHostOuterRune(c)
|
||||
})
|
||||
|
||||
if len(parts) == 0 {
|
||||
return "", fmt.Errorf("normalizing hostname %q: no valid parts", name)
|
||||
}
|
||||
|
||||
norm = strings.Join(parts, "-")
|
||||
norm = strings.TrimSuffix(norm, "-")
|
||||
|
||||
return norm, nil
|
||||
}
|
||||
|
||||
// validateHostname validates a hostname sent by the client.
|
||||
func (s *v4Server) validateHostname(name string) (err error) {
|
||||
defer agherr.Annotate("validating hostname: %s", &err)
|
||||
|
||||
if name == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = aghnet.ValidateDomainName(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.leaseHosts.Has(name) {
|
||||
return agherr.Error("hostname exists")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateLease returns an error if the lease is invalid.
|
||||
func (s *v4Server) validateLease(l *Lease) (err error) {
|
||||
defer agherr.Annotate("validating lease: %s", &err)
|
||||
|
||||
if l == nil {
|
||||
return agherr.Error("lease is nil")
|
||||
}
|
||||
|
||||
err = aghnet.ValidateHardwareAddress(l.HWAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.validateHostname(l.Hostname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sn := s.conf.subnet; !sn.Contains(l.IP) {
|
||||
return fmt.Errorf("subnet %s does not contain the ip %q", sn, l.IP)
|
||||
}
|
||||
|
||||
r := s.conf.ipRange
|
||||
if !l.IsStatic() && !r.contains(l.IP) {
|
||||
return fmt.Errorf("dynamic lease range %s does not contain the ip %q", r, l.IP)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Process Request request and return lease
|
||||
// Return false if we don't need to reply
|
||||
func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, ok bool) {
|
||||
var err error
|
||||
|
||||
// processRequest is the handler for the DHCP Request request.
|
||||
func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, needsReply bool) {
|
||||
mac := req.ClientHWAddr
|
||||
reqIP := req.RequestedIPAddress()
|
||||
if reqIP == nil {
|
||||
@@ -646,81 +643,65 @@ func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, ok bo
|
||||
|
||||
sid := req.ServerIdentifier()
|
||||
if len(sid) != 0 && !sid.Equal(s.conf.dnsIPAddrs[0]) {
|
||||
log.Debug("dhcpv4: bad OptionServerIdentifier in request message for %s", mac)
|
||||
log.Debug("dhcpv4: bad OptionServerIdentifier in req msg for %s", mac)
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if ip4 := reqIP.To4(); ip4 == nil {
|
||||
log.Debug("dhcpv4: bad OptionRequestedIPAddress in request message for %s", mac)
|
||||
log.Debug("dhcpv4: bad OptionRequestedIPAddress in req msg for %s", mac)
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
s.leasesLock.Lock()
|
||||
for _, l := range s.leases {
|
||||
if bytes.Equal(l.HWAddr, mac) {
|
||||
if !l.IP.Equal(reqIP) {
|
||||
s.leasesLock.Unlock()
|
||||
log.Debug("dhcpv4: mismatched OptionRequestedIPAddress in request message for %s", mac)
|
||||
mismatch := false
|
||||
func() {
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
return nil, true
|
||||
for _, l := range s.leases {
|
||||
if !bytes.Equal(l.HWAddr, mac) {
|
||||
continue
|
||||
}
|
||||
|
||||
lease = l
|
||||
if l.IP.Equal(reqIP) {
|
||||
lease = l
|
||||
|
||||
break
|
||||
return
|
||||
}
|
||||
|
||||
log.Debug(
|
||||
`dhcpv4: mismatched OptionRequestedIPAddress in req msg for %s`,
|
||||
mac,
|
||||
)
|
||||
|
||||
mismatch = true
|
||||
|
||||
return
|
||||
}
|
||||
}()
|
||||
if mismatch {
|
||||
return nil, true
|
||||
}
|
||||
s.leasesLock.Unlock()
|
||||
|
||||
if lease == nil {
|
||||
log.Debug("dhcpv4: no lease for %s", mac)
|
||||
log.Debug("dhcpv4: no reserved lease for %s", mac)
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
if !lease.IsStatic() {
|
||||
cliHostname := req.HostName()
|
||||
|
||||
var hostname string
|
||||
hostname, err = normalizeHostname(cliHostname)
|
||||
if err != nil {
|
||||
log.Error("dhcpv4: cannot normalize hostname for %s: %s", mac, err)
|
||||
|
||||
// Go on and assign a hostname made from the IP.
|
||||
hostname := s.validHostnameForClient(cliHostname, reqIP)
|
||||
if hostname != lease.Hostname && s.leaseHosts.Has(hostname) {
|
||||
log.Info("dhcpv4: hostname %q already exists", hostname)
|
||||
lease.Hostname = ""
|
||||
} else {
|
||||
lease.Hostname = hostname
|
||||
}
|
||||
|
||||
if hostname != "" {
|
||||
if cliHostname != hostname {
|
||||
log.Debug(
|
||||
"dhcpv4: normalized hostname %q into %q",
|
||||
cliHostname,
|
||||
hostname,
|
||||
)
|
||||
}
|
||||
|
||||
if lease.Hostname != hostname {
|
||||
// Either a new lease or an old lease with a new
|
||||
// hostname, so validate.
|
||||
err = s.validateHostname(hostname)
|
||||
if err != nil {
|
||||
log.Error("dhcpv4: validating %s: %s", mac, err)
|
||||
|
||||
// Go on and assign a hostname made from
|
||||
// the IP below.
|
||||
hostname = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hostname == "" {
|
||||
hostname = aghnet.GenerateHostname(reqIP)
|
||||
}
|
||||
|
||||
lease.Hostname = hostname
|
||||
s.commitLease(lease)
|
||||
} else if len(lease.Hostname) != 0 {
|
||||
} else if lease.Hostname != "" {
|
||||
o := &optFQDN{
|
||||
name: lease.Hostname,
|
||||
}
|
||||
@@ -737,6 +718,107 @@ func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, ok bo
|
||||
return lease, true
|
||||
}
|
||||
|
||||
// processRequest is the handler for the DHCP Decline request.
|
||||
func (s *v4Server) processDecline(req, resp *dhcpv4.DHCPv4) (err error) {
|
||||
s.conf.notify(LeaseChangedDBStore)
|
||||
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
mac := req.ClientHWAddr
|
||||
reqIP := req.RequestedIPAddress()
|
||||
if reqIP == nil {
|
||||
reqIP = req.ClientIPAddr
|
||||
}
|
||||
|
||||
var oldLease *Lease
|
||||
for _, l := range s.leases {
|
||||
if bytes.Equal(l.HWAddr, mac) && l.IP.Equal(reqIP) {
|
||||
oldLease = l
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if oldLease == nil {
|
||||
log.Info("dhcpv4: lease with ip %s for %s not found", reqIP, mac)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
err = s.rmDynamicLease(oldLease)
|
||||
if err != nil {
|
||||
return fmt.Errorf("removing old lease for %s: %w", mac, err)
|
||||
}
|
||||
|
||||
newLease, err := s.allocateLease(mac)
|
||||
if err != nil {
|
||||
return fmt.Errorf("allocating new lease for %s: %w", mac, err)
|
||||
} else if newLease == nil {
|
||||
log.Info("dhcpv4: allocating new lease for %s: no more ip addresses", mac)
|
||||
|
||||
resp.YourIPAddr = make([]byte, 4)
|
||||
resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeAck))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
newLease.Hostname = oldLease.Hostname
|
||||
newLease.Expiry = time.Now().Add(s.conf.leaseTime)
|
||||
|
||||
err = s.addLease(newLease)
|
||||
if err != nil {
|
||||
return fmt.Errorf("adding new lease for %s: %w", mac, err)
|
||||
}
|
||||
|
||||
log.Info("dhcpv4: changed ip from %s to %s for %s", reqIP, newLease.IP, mac)
|
||||
|
||||
resp.YourIPAddr = make([]byte, 4)
|
||||
copy(resp.YourIPAddr, newLease.IP)
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeAck))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// processRelease is the handler for the DHCP Release request.
|
||||
func (s *v4Server) processRelease(req, resp *dhcpv4.DHCPv4) (err error) {
|
||||
mac := req.ClientHWAddr
|
||||
reqIP := req.RequestedIPAddress()
|
||||
if reqIP == nil {
|
||||
reqIP = req.ClientIPAddr
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Add a separate notification type for dynamic lease
|
||||
// removal?
|
||||
defer s.conf.notify(LeaseChangedDBStore)
|
||||
|
||||
n := 0
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
for _, l := range s.leases {
|
||||
if !bytes.Equal(l.HWAddr, mac) || !l.IP.Equal(reqIP) {
|
||||
continue
|
||||
}
|
||||
|
||||
err = s.rmDynamicLease(l)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("removing dynamic lease for %s: %w", mac, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
n++
|
||||
}
|
||||
|
||||
log.Info("dhcpv4: released %d dynamic leases for %s", n, mac)
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeAck))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Find a lease associated with MAC and prepare response
|
||||
// Return 1: OK
|
||||
// Return 0: error; reply with Nak
|
||||
@@ -746,6 +828,7 @@ func (s *v4Server) process(req, resp *dhcpv4.DHCPv4) int {
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptServerIdentifier(s.conf.dnsIPAddrs[0]))
|
||||
|
||||
// TODO(a.garipov): Refactor this into handlers.
|
||||
var l *Lease
|
||||
switch req.MessageType() {
|
||||
case dhcpv4.MessageTypeDiscover:
|
||||
@@ -768,10 +851,26 @@ func (s *v4Server) process(req, resp *dhcpv4.DHCPv4) int {
|
||||
}
|
||||
return -1 // drop packet
|
||||
}
|
||||
case dhcpv4.MessageTypeDecline:
|
||||
err = s.processDecline(req, resp)
|
||||
if err != nil {
|
||||
log.Error("dhcpv4: processing decline: %s", err)
|
||||
|
||||
return 0
|
||||
}
|
||||
case dhcpv4.MessageTypeRelease:
|
||||
err = s.processRelease(req, resp)
|
||||
if err != nil {
|
||||
log.Error("dhcpv4: processing release: %s", err)
|
||||
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
resp.YourIPAddr = make([]byte, 4)
|
||||
copy(resp.YourIPAddr, l.IP)
|
||||
if l != nil {
|
||||
resp.YourIPAddr = make([]byte, 4)
|
||||
copy(resp.YourIPAddr, l.IP)
|
||||
}
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptIPAddressLeaseTime(s.conf.leaseTime))
|
||||
resp.UpdateOption(dhcpv4.OptRouter(s.conf.subnet.IP))
|
||||
@@ -794,11 +893,13 @@ func (s *v4Server) packetHandler(conn net.PacketConn, peer net.Addr, req *dhcpv4
|
||||
|
||||
switch req.MessageType() {
|
||||
case dhcpv4.MessageTypeDiscover,
|
||||
dhcpv4.MessageTypeRequest:
|
||||
//
|
||||
|
||||
dhcpv4.MessageTypeRequest,
|
||||
dhcpv4.MessageTypeDecline,
|
||||
dhcpv4.MessageTypeRelease:
|
||||
// Go on.
|
||||
default:
|
||||
log.Debug("dhcpv4: unsupported message type %d", req.MessageType())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,9 @@ func TestV4_AddRemove_static(t *testing.T) {
|
||||
|
||||
// Add static lease.
|
||||
l := Lease{
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "static-1.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
}
|
||||
|
||||
err = s.AddStaticLease(l)
|
||||
@@ -76,11 +77,13 @@ func TestV4_AddReplace(t *testing.T) {
|
||||
require.True(t, ok)
|
||||
|
||||
dynLeases := []Lease{{
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
HWAddr: net.HardwareAddr{0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "dynamic-1.local",
|
||||
HWAddr: net.HardwareAddr{0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
}, {
|
||||
IP: net.IP{192, 168, 10, 151},
|
||||
HWAddr: net.HardwareAddr{0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "dynamic-2.local",
|
||||
HWAddr: net.HardwareAddr{0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 151},
|
||||
}}
|
||||
|
||||
for i := range dynLeases {
|
||||
@@ -89,11 +92,13 @@ func TestV4_AddReplace(t *testing.T) {
|
||||
}
|
||||
|
||||
stLeases := []Lease{{
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
HWAddr: net.HardwareAddr{0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "static-1.local",
|
||||
HWAddr: net.HardwareAddr{0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
}, {
|
||||
IP: net.IP{192, 168, 10, 152},
|
||||
HWAddr: net.HardwareAddr{0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "static-2.local",
|
||||
HWAddr: net.HardwareAddr{0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 152},
|
||||
}}
|
||||
|
||||
for _, l := range stLeases {
|
||||
@@ -129,8 +134,9 @@ func TestV4StaticLease_Get(t *testing.T) {
|
||||
s.conf.dnsIPAddrs = []net.IP{{192, 168, 10, 1}}
|
||||
|
||||
l := Lease{
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "static-1.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
}
|
||||
err = s.AddStaticLease(l)
|
||||
require.NoError(t, err)
|
||||
@@ -269,7 +275,12 @@ func TestV4DynamicLease_Get(t *testing.T) {
|
||||
assert.Equal(t, dhcpv4.MessageTypeAck, resp.MessageType())
|
||||
assert.Equal(t, mac, resp.ClientHWAddr)
|
||||
assert.True(t, s.conf.RangeStart.Equal(resp.YourIPAddr))
|
||||
assert.True(t, s.conf.GatewayIP.Equal(resp.Router()[0]))
|
||||
|
||||
router := resp.Router()
|
||||
require.Len(t, router, 1)
|
||||
|
||||
assert.Equal(t, s.conf.GatewayIP, router[0])
|
||||
|
||||
assert.True(t, s.conf.GatewayIP.Equal(resp.ServerIdentifier()))
|
||||
assert.Equal(t, s.conf.subnet.Mask, resp.SubnetMask())
|
||||
assert.Equal(t, s.conf.leaseTime.Seconds(), resp.IPAddressLeaseTime(-1).Seconds())
|
||||
@@ -329,12 +340,12 @@ func TestNormalizeHostname(t *testing.T) {
|
||||
}, {
|
||||
name: "error",
|
||||
hostname: "!!!",
|
||||
wantErrMsg: `normalizing hostname "!!!": no valid parts`,
|
||||
wantErrMsg: `normalizing "!!!": no valid parts`,
|
||||
want: "",
|
||||
}, {
|
||||
name: "error_spaces",
|
||||
hostname: "! ! !",
|
||||
wantErrMsg: `normalizing hostname "! ! !": no valid parts`,
|
||||
wantErrMsg: `normalizing "! ! !": no valid parts`,
|
||||
want: "",
|
||||
}}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ func newAccessCtx(allowedClients, disallowedClients, blockedHosts []string) (a *
|
||||
|
||||
b := &strings.Builder{}
|
||||
for _, s := range blockedHosts {
|
||||
aghstrings.WriteToBuilder(b, s, "\n")
|
||||
aghstrings.WriteToBuilder(b, strings.ToLower(s), "\n")
|
||||
}
|
||||
|
||||
listArray := []filterlist.RuleList{}
|
||||
|
||||
@@ -2,6 +2,7 @@ package dnsforward
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
@@ -15,7 +16,8 @@ import (
|
||||
func ValidateClientID(clientID string) (err error) {
|
||||
err = aghnet.ValidateDomainNameLabel(clientID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid client id: %w", err)
|
||||
// Replace the domain name label wrapper with our own.
|
||||
return fmt.Errorf("invalid client id %q: %w", clientID, errors.Unwrap(err))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -117,8 +117,8 @@ func TestProcessClientID(t *testing.T) {
|
||||
hostSrvName: "example.com",
|
||||
cliSrvName: "!!!.example.com",
|
||||
wantClientID: "",
|
||||
wantErrMsg: `client id check: invalid client id: invalid char '!' ` +
|
||||
`at index 0 in "!!!"`,
|
||||
wantErrMsg: `client id check: invalid client id "!!!": ` +
|
||||
`invalid char '!' at index 0`,
|
||||
wantRes: resultCodeError,
|
||||
strictSNI: true,
|
||||
}, {
|
||||
@@ -128,9 +128,9 @@ func TestProcessClientID(t *testing.T) {
|
||||
cliSrvName: `abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmno` +
|
||||
`pqrstuvwxyz0123456789.example.com`,
|
||||
wantClientID: "",
|
||||
wantErrMsg: `client id check: invalid client id: "abcdefghijklmno` +
|
||||
`pqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789" ` +
|
||||
`is too long, max: 63`,
|
||||
wantErrMsg: `client id check: invalid client id "abcdefghijklmno` +
|
||||
`pqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789": ` +
|
||||
`label is too long, max: 63`,
|
||||
wantRes: resultCodeError,
|
||||
strictSNI: true,
|
||||
}, {
|
||||
@@ -238,8 +238,8 @@ func TestProcessClientID_https(t *testing.T) {
|
||||
name: "invalid_client_id",
|
||||
path: "/dns-query/!!!",
|
||||
wantClientID: "",
|
||||
wantErrMsg: `client id check: invalid client id: invalid char '!' ` +
|
||||
`at index 0 in "!!!"`,
|
||||
wantErrMsg: `client id check: invalid client id "!!!": ` +
|
||||
`invalid char '!' at index 0`,
|
||||
wantRes: resultCodeError,
|
||||
}}
|
||||
|
||||
|
||||
@@ -249,6 +249,10 @@ func (s *Server) hostToIP(host string) (ip net.IP, ok bool) {
|
||||
//
|
||||
// TODO(a.garipov): Adapt to AAAA as well.
|
||||
func (s *Server) processInternalHosts(dctx *dnsContext) (rc resultCode) {
|
||||
if !s.dhcpServer.Enabled() {
|
||||
return resultCodeSuccess
|
||||
}
|
||||
|
||||
req := dctx.proxyCtx.Req
|
||||
q := req.Question[0]
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ func TestServer_ProcessInternalHosts_localRestriction(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s := &Server{
|
||||
dhcpServer: &testDHCP{},
|
||||
localDomainSuffix: defaultLocalDomainSuffix,
|
||||
tableHostToIP: hostToIPTable{
|
||||
"example": knownIP,
|
||||
@@ -201,6 +202,7 @@ func TestServer_ProcessInternalHosts(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s := &Server{
|
||||
dhcpServer: &testDHCP{},
|
||||
localDomainSuffix: tc.suffix,
|
||||
tableHostToIP: hostToIPTable{
|
||||
"example": knownIP,
|
||||
@@ -318,7 +320,7 @@ func TestLocalRestriction(t *testing.T) {
|
||||
}
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err = s.handleDNSRequest(nil, pctx)
|
||||
require.Nil(t, err)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, pctx.Res)
|
||||
require.Len(t, pctx.Res.Answer, tc.wantLen)
|
||||
if tc.wantLen > 0 {
|
||||
|
||||
@@ -370,9 +370,7 @@ func (s *Server) setupResolvers(localAddrs []string) (err error) {
|
||||
// really applicable here since in case of listening on all network
|
||||
// interfaces we should check the whole interface's network to cut off
|
||||
// all the loopback addresses as well.
|
||||
localAddrs = aghstrings.FilterOut(localAddrs, func(s string) (ok bool) {
|
||||
return ourAddrsSet.Has(s)
|
||||
})
|
||||
localAddrs = aghstrings.FilterOut(localAddrs, ourAddrsSet.Has)
|
||||
|
||||
var upsConfig proxy.UpstreamConfig
|
||||
upsConfig, err = proxy.ParseUpstreamsConfig(localAddrs, upstream.Options{
|
||||
|
||||
@@ -75,6 +75,7 @@ func createTestServer(
|
||||
require.NotNil(t, snd)
|
||||
|
||||
s, err = NewServer(DNSCreateParams{
|
||||
DHCPServer: &testDHCP{},
|
||||
DNSFilter: f,
|
||||
SubnetDetector: snd,
|
||||
})
|
||||
@@ -736,6 +737,7 @@ func TestBlockedCustomIP(t *testing.T) {
|
||||
|
||||
var s *Server
|
||||
s, err = NewServer(DNSCreateParams{
|
||||
DHCPServer: &testDHCP{},
|
||||
DNSFilter: dnsfilter.New(&dnsfilter.Config{}, filters),
|
||||
SubnetDetector: snd,
|
||||
})
|
||||
@@ -873,6 +875,7 @@ func TestRewrite(t *testing.T) {
|
||||
|
||||
var s *Server
|
||||
s, err = NewServer(DNSCreateParams{
|
||||
DHCPServer: &testDHCP{},
|
||||
DNSFilter: f,
|
||||
SubnetDetector: snd,
|
||||
})
|
||||
@@ -1016,11 +1019,13 @@ func TestMatchDNSName(t *testing.T) {
|
||||
|
||||
type testDHCP struct{}
|
||||
|
||||
func (d *testDHCP) Enabled() (ok bool) { return true }
|
||||
|
||||
func (d *testDHCP) Leases(flags int) []dhcpd.Lease {
|
||||
l := dhcpd.Lease{
|
||||
IP: net.IP{127, 0, 0, 1},
|
||||
IP: net.IP{192, 168, 12, 34},
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "localhost",
|
||||
Hostname: "myhost",
|
||||
}
|
||||
|
||||
return []dhcpd.Lease{l}
|
||||
@@ -1056,7 +1061,7 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) {
|
||||
})
|
||||
|
||||
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
||||
req := createTestMessageWithType("1.0.0.127.in-addr.arpa.", dns.TypePTR)
|
||||
req := createTestMessageWithType("34.12.168.192.in-addr.arpa.", dns.TypePTR)
|
||||
|
||||
resp, err := dns.Exchange(req, addr.String())
|
||||
require.NoError(t, err)
|
||||
@@ -1064,11 +1069,11 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) {
|
||||
require.Len(t, resp.Answer, 1)
|
||||
|
||||
assert.Equal(t, dns.TypePTR, resp.Answer[0].Header().Rrtype)
|
||||
assert.Equal(t, "1.0.0.127.in-addr.arpa.", resp.Answer[0].Header().Name)
|
||||
assert.Equal(t, "34.12.168.192.in-addr.arpa.", resp.Answer[0].Header().Name)
|
||||
|
||||
ptr, ok := resp.Answer[0].(*dns.PTR)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "localhost.", ptr.Ptr)
|
||||
assert.Equal(t, "myhost.", ptr.Ptr)
|
||||
}
|
||||
|
||||
func TestPTRResponseFromHosts(t *testing.T) {
|
||||
@@ -1098,6 +1103,7 @@ func TestPTRResponseFromHosts(t *testing.T) {
|
||||
|
||||
var s *Server
|
||||
s, err = NewServer(DNSCreateParams{
|
||||
DHCPServer: &testDHCP{},
|
||||
DNSFilter: dnsfilter.New(&c, nil),
|
||||
SubnetDetector: snd,
|
||||
})
|
||||
@@ -1160,8 +1166,9 @@ func TestNewServer(t *testing.T) {
|
||||
in: DNSCreateParams{
|
||||
LocalDomain: "!!!",
|
||||
},
|
||||
wantErrMsg: `local domain: invalid domain name label at index 0: ` +
|
||||
`invalid char '!' at index 0 in "!!!"`,
|
||||
wantErrMsg: `local domain: validating domain name "!!!": ` +
|
||||
`invalid domain name label at index 0: ` +
|
||||
`validating label "!!!": invalid char '!' at index 0`,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
||||
@@ -20,7 +20,11 @@ func (s *Server) beforeRequestHandler(_ *proxy.Proxy, d *proxy.DNSContext) (bool
|
||||
}
|
||||
|
||||
if len(d.Req.Question) == 1 {
|
||||
host := strings.TrimSuffix(d.Req.Question[0].Name, ".")
|
||||
// It's lowercased here since this handler is called before any
|
||||
// other one.
|
||||
name := strings.ToLower(d.Req.Question[0].Name)
|
||||
d.Req.Question[0].Name = name
|
||||
host := strings.TrimSuffix(name, ".")
|
||||
if s.access.IsBlockedDomain(host) {
|
||||
log.Tracef("Domain %s is blocked by settings", host)
|
||||
return false, nil
|
||||
@@ -46,8 +50,6 @@ func (s *Server) getClientRequestFilteringSettings(ctx *dnsContext) *dnsfilter.F
|
||||
// filtered.
|
||||
func (s *Server) filterDNSRequest(ctx *dnsContext) (*dnsfilter.Result, error) {
|
||||
d := ctx.proxyCtx
|
||||
// TODO(e.burkov): Consistently use req instead of d.Req since it is
|
||||
// declared.
|
||||
req := d.Req
|
||||
host := strings.TrimSuffix(req.Question[0].Name, ".")
|
||||
res, err := s.dnsFilter.CheckHost(host, req.Question[0].Qtype, ctx.setts)
|
||||
|
||||
@@ -29,25 +29,25 @@ var webHandlersRegistered = false
|
||||
|
||||
// Client contains information about persistent clients.
|
||||
type Client struct {
|
||||
IDs []string
|
||||
Tags []string
|
||||
Name string
|
||||
UseOwnSettings bool // false: use global settings
|
||||
FilteringEnabled bool
|
||||
SafeSearchEnabled bool
|
||||
SafeBrowsingEnabled bool
|
||||
ParentalEnabled bool
|
||||
|
||||
UseOwnBlockedServices bool // false: use global settings
|
||||
BlockedServices []string
|
||||
|
||||
Upstreams []string // list of upstream servers to be used for the client's requests
|
||||
|
||||
// Custom upstream config for this client
|
||||
// nil: not yet initialized
|
||||
// not nil, but empty: initialized, no good upstreams
|
||||
// not nil, not empty: Upstreams ready to be used
|
||||
// upstreamConfig is the custom upstream config for this client. If
|
||||
// it's nil, it has not been initialized yet. If it's non-nil and
|
||||
// empty, there are no valid upstreams. If it's non-nil and non-empty,
|
||||
// these upstream must be used.
|
||||
upstreamConfig *proxy.UpstreamConfig
|
||||
|
||||
Name string
|
||||
|
||||
IDs []string
|
||||
Tags []string
|
||||
BlockedServices []string
|
||||
Upstreams []string
|
||||
|
||||
UseOwnSettings bool
|
||||
FilteringEnabled bool
|
||||
SafeSearchEnabled bool
|
||||
SafeBrowsingEnabled bool
|
||||
ParentalEnabled bool
|
||||
UseOwnBlockedServices bool
|
||||
}
|
||||
|
||||
type clientSource uint
|
||||
@@ -63,9 +63,9 @@ const (
|
||||
|
||||
// RuntimeClient information
|
||||
type RuntimeClient struct {
|
||||
WhoisInfo *RuntimeClientWhoisInfo
|
||||
Host string
|
||||
Source clientSource
|
||||
WhoisInfo *RuntimeClientWhoisInfo
|
||||
}
|
||||
|
||||
// RuntimeClientWhoisInfo is the filtered WHOIS data for a runtime client.
|
||||
|
||||
@@ -7,31 +7,38 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// clientJSON is a common structure used by several handlers to deal with
|
||||
// clients. Some of the fields are only necessary in one or two handlers and
|
||||
// are thus made pointers with an omitempty tag.
|
||||
//
|
||||
// TODO(a.garipov): Consider using nullbool and an optional string here? Or
|
||||
// split into several structs?
|
||||
type clientJSON struct {
|
||||
IDs []string `json:"ids"`
|
||||
Tags []string `json:"tags"`
|
||||
Name string `json:"name"`
|
||||
UseGlobalSettings bool `json:"use_global_settings"`
|
||||
FilteringEnabled bool `json:"filtering_enabled"`
|
||||
ParentalEnabled bool `json:"parental_enabled"`
|
||||
SafeSearchEnabled bool `json:"safesearch_enabled"`
|
||||
SafeBrowsingEnabled bool `json:"safebrowsing_enabled"`
|
||||
// Disallowed, if non-nil and false, means that the client's IP is
|
||||
// allowed. Otherwise, the IP is blocked.
|
||||
Disallowed *bool `json:"disallowed,omitempty"`
|
||||
|
||||
UseGlobalBlockedServices bool `json:"use_global_blocked_services"`
|
||||
BlockedServices []string `json:"blocked_services"`
|
||||
// DisallowedRule is the rule due to which the client is disallowed.
|
||||
// If Disallowed is true and this string is empty, the client IP is
|
||||
// disallowed by the "allowed IP list", that is it is not included in
|
||||
// the allowlist.
|
||||
DisallowedRule *string `json:"disallowed_rule,omitempty"`
|
||||
|
||||
Upstreams []string `json:"upstreams"`
|
||||
WhoisInfo *RuntimeClientWhoisInfo `json:"whois_info,omitempty"`
|
||||
|
||||
WhoisInfo *RuntimeClientWhoisInfo `json:"whois_info"`
|
||||
Name string `json:"name"`
|
||||
|
||||
// Disallowed - if true -- client's IP is not disallowed
|
||||
// Otherwise, it is blocked.
|
||||
Disallowed bool `json:"disallowed"`
|
||||
BlockedServices []string `json:"blocked_services"`
|
||||
IDs []string `json:"ids"`
|
||||
Tags []string `json:"tags"`
|
||||
Upstreams []string `json:"upstreams"`
|
||||
|
||||
// DisallowedRule - the rule due to which the client is disallowed
|
||||
// If Disallowed is true, and this string is empty - it means that the client IP
|
||||
// is disallowed by the "allowed IP list", i.e. it is not included in allowed.
|
||||
DisallowedRule string `json:"disallowed_rule"`
|
||||
FilteringEnabled bool `json:"filtering_enabled"`
|
||||
ParentalEnabled bool `json:"parental_enabled"`
|
||||
SafeBrowsingEnabled bool `json:"safebrowsing_enabled"`
|
||||
SafeSearchEnabled bool `json:"safesearch_enabled"`
|
||||
UseGlobalBlockedServices bool `json:"use_global_blocked_services"`
|
||||
UseGlobalSettings bool `json:"use_global_settings"`
|
||||
}
|
||||
|
||||
type runtimeClientJSON struct {
|
||||
@@ -126,8 +133,6 @@ func clientToJSON(c *Client) clientJSON {
|
||||
BlockedServices: c.BlockedServices,
|
||||
|
||||
Upstreams: c.Upstreams,
|
||||
|
||||
WhoisInfo: &RuntimeClientWhoisInfo{},
|
||||
}
|
||||
|
||||
return cj
|
||||
@@ -243,7 +248,8 @@ func (clients *clientsContainer) handleFindClient(w http.ResponseWriter, r *http
|
||||
}
|
||||
} else {
|
||||
cj = clientToJSON(c)
|
||||
cj.Disallowed, cj.DisallowedRule = clients.dnsServer.IsBlockedIP(ip)
|
||||
disallowed, rule := clients.dnsServer.IsBlockedIP(ip)
|
||||
cj.Disallowed, cj.DisallowedRule = &disallowed, &rule
|
||||
}
|
||||
|
||||
data = append(data, map[string]clientJSON{
|
||||
@@ -279,8 +285,8 @@ func (clients *clientsContainer) findRuntime(ip net.IP, idStr string) (cj client
|
||||
|
||||
cj = clientJSON{
|
||||
IDs: []string{idStr},
|
||||
Disallowed: disallowed,
|
||||
DisallowedRule: rule,
|
||||
Disallowed: &disallowed,
|
||||
DisallowedRule: &rule,
|
||||
WhoisInfo: &RuntimeClientWhoisInfo{},
|
||||
}
|
||||
|
||||
@@ -288,7 +294,8 @@ func (clients *clientsContainer) findRuntime(ip net.IP, idStr string) (cj client
|
||||
}
|
||||
|
||||
cj = runtimeClientToJSON(idStr, rc)
|
||||
cj.Disallowed, cj.DisallowedRule = clients.dnsServer.IsBlockedIP(ip)
|
||||
disallowed, rule := clients.dnsServer.IsBlockedIP(ip)
|
||||
cj.Disallowed, cj.DisallowedRule = &disallowed, &rule
|
||||
|
||||
return cj, true
|
||||
}
|
||||
|
||||
@@ -133,14 +133,21 @@ func handleStatus(w http.ResponseWriter, _ *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
resp := statusResponse{
|
||||
DNSAddrs: dnsAddrs,
|
||||
DNSPort: config.DNS.Port,
|
||||
HTTPPort: config.BindPort,
|
||||
IsRunning: isRunning(),
|
||||
Version: version.Version(),
|
||||
Language: config.Language,
|
||||
}
|
||||
var resp statusResponse
|
||||
|
||||
func() {
|
||||
config.RLock()
|
||||
defer config.RUnlock()
|
||||
|
||||
resp = statusResponse{
|
||||
DNSAddrs: dnsAddrs,
|
||||
DNSPort: config.DNS.Port,
|
||||
HTTPPort: config.BindPort,
|
||||
IsRunning: isRunning(),
|
||||
Version: version.Version(),
|
||||
Language: config.Language,
|
||||
}
|
||||
}()
|
||||
|
||||
var c *dnsforward.FilteringConfig
|
||||
if Context.dnsServer != nil {
|
||||
|
||||
@@ -319,6 +319,9 @@ func applyAdditionalFiltering(clientAddr net.IP, clientID string, setts *dnsfilt
|
||||
}
|
||||
|
||||
func startDNSServer() error {
|
||||
config.Lock()
|
||||
defer config.Unlock()
|
||||
|
||||
if isRunning() {
|
||||
return fmt.Errorf("unable to start forwarding DNS server: Already running")
|
||||
}
|
||||
|
||||
@@ -76,16 +76,6 @@ type filter struct {
|
||||
dnsfilter.Filter `yaml:",inline"`
|
||||
}
|
||||
|
||||
// Creates a helper object for working with the user rules
|
||||
func userFilter() filter {
|
||||
f := filter{
|
||||
// User filter always has constant ID=0
|
||||
Enabled: true,
|
||||
}
|
||||
f.Filter.Data = []byte(strings.Join(config.UserRules, "\n"))
|
||||
return f
|
||||
}
|
||||
|
||||
const (
|
||||
statusFound = 1
|
||||
statusEnabledChanged = 2
|
||||
@@ -689,41 +679,33 @@ func (filter *filter) LastTimeUpdated() time.Time {
|
||||
}
|
||||
|
||||
func enableFilters(async bool) {
|
||||
var filters []dnsfilter.Filter
|
||||
var whiteFilters []dnsfilter.Filter
|
||||
if config.DNS.FilteringEnabled {
|
||||
// convert array of filters
|
||||
filters := []dnsfilter.Filter{{
|
||||
Data: []byte(strings.Join(config.UserRules, "\n")),
|
||||
}}
|
||||
|
||||
userFilter := userFilter()
|
||||
f := dnsfilter.Filter{
|
||||
ID: userFilter.ID,
|
||||
Data: userFilter.Data,
|
||||
for _, filter := range config.Filters {
|
||||
if !filter.Enabled {
|
||||
continue
|
||||
}
|
||||
filters = append(filters, f)
|
||||
|
||||
for _, filter := range config.Filters {
|
||||
if !filter.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
f = dnsfilter.Filter{
|
||||
ID: filter.ID,
|
||||
FilePath: filter.Path(),
|
||||
}
|
||||
filters = append(filters, f)
|
||||
filters = append(filters, dnsfilter.Filter{
|
||||
ID: filter.ID,
|
||||
FilePath: filter.Path(),
|
||||
})
|
||||
}
|
||||
for _, filter := range config.WhitelistFilters {
|
||||
if !filter.Enabled {
|
||||
continue
|
||||
}
|
||||
for _, filter := range config.WhitelistFilters {
|
||||
if !filter.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
f = dnsfilter.Filter{
|
||||
ID: filter.ID,
|
||||
FilePath: filter.Path(),
|
||||
}
|
||||
whiteFilters = append(whiteFilters, f)
|
||||
}
|
||||
whiteFilters = append(whiteFilters, dnsfilter.Filter{
|
||||
ID: filter.ID,
|
||||
FilePath: filter.Path(),
|
||||
})
|
||||
}
|
||||
|
||||
_ = Context.dnsFilter.SetFilters(filters, whiteFilters, async)
|
||||
if err := Context.dnsFilter.SetFilters(filters, whiteFilters, async); err != nil {
|
||||
log.Debug("enabling filters: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,6 +184,10 @@ func setupConfig(args options) {
|
||||
|
||||
Context.dhcpServer = dhcpd.Create(config.DHCP)
|
||||
if Context.dhcpServer == nil {
|
||||
// TODO(a.garipov): There are a lot of places in the code right
|
||||
// now which assume that the DHCP server can be nil despite this
|
||||
// condition. Inspect them and perhaps rewrite them to use
|
||||
// Enabled() instead.
|
||||
log.Fatalf("can't initialize dhcp module")
|
||||
}
|
||||
|
||||
@@ -489,6 +493,10 @@ func configureLogger(args options) {
|
||||
log.SetLevel(log.DEBUG)
|
||||
}
|
||||
|
||||
// Make sure that we see the microseconds in logs, as networking stuff
|
||||
// can happen pretty quickly.
|
||||
log.SetFlags(log.LstdFlags | log.Lmicroseconds)
|
||||
|
||||
if args.runningAsService && ls.LogFile == "" && runtime.GOOS == "windows" {
|
||||
// When running as a Windows service, use eventlog by default if nothing else is configured
|
||||
// Otherwise, we'll simply loose the log output
|
||||
|
||||
@@ -86,7 +86,13 @@ func handleI18nChangeLanguage(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
config.Language = language
|
||||
func() {
|
||||
config.Lock()
|
||||
defer config.Unlock()
|
||||
|
||||
config.Language = language
|
||||
}()
|
||||
|
||||
onConfigModified()
|
||||
returnOK(w)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,15 @@
|
||||
|
||||
## v0.106: API changes
|
||||
|
||||
### The field `"supported_tags"` in `GET /control/clients`
|
||||
|
||||
* Prefiously undocumented field `"supported_tags"` in the response is now
|
||||
documented.
|
||||
|
||||
### The field `"whois_info"` in `GET /control/clients`
|
||||
|
||||
* Objects in the `"auto_clients"` array now have the `"whois_info"` field.
|
||||
|
||||
### New response code in `POST /control/login`
|
||||
|
||||
* `429` is returned when user is out of login attempts. It adds the
|
||||
|
||||
@@ -2234,6 +2234,10 @@
|
||||
'type': 'array'
|
||||
'items':
|
||||
'type': 'string'
|
||||
'tags':
|
||||
'items':
|
||||
'type': 'string'
|
||||
'type': 'array'
|
||||
'ClientAuto':
|
||||
'type': 'object'
|
||||
'description': 'Auto-Client information'
|
||||
@@ -2250,6 +2254,8 @@
|
||||
'type': 'string'
|
||||
'description': 'The source of this information'
|
||||
'example': 'etc/hosts'
|
||||
'whois_info':
|
||||
'$ref': '#/components/schemas/WhoisInfo'
|
||||
'ClientUpdate':
|
||||
'type': 'object'
|
||||
'description': 'Client update request'
|
||||
@@ -2384,6 +2390,10 @@
|
||||
'$ref': '#/components/schemas/ClientsArray'
|
||||
'auto_clients':
|
||||
'$ref': '#/components/schemas/ClientsAutoArray'
|
||||
'supported_tags':
|
||||
'items':
|
||||
'type': 'string'
|
||||
'type': 'array'
|
||||
'ClientsArray':
|
||||
'type': 'array'
|
||||
'items':
|
||||
|
||||
@@ -1,249 +1,507 @@
|
||||
#!/bin/sh
|
||||
|
||||
# AdGuard Home Installation Script
|
||||
#
|
||||
# 1. Download the package
|
||||
# 2. Unpack it
|
||||
# 3. Install as a service
|
||||
#
|
||||
# Requirements:
|
||||
# . bash
|
||||
# . which
|
||||
# . printf
|
||||
# . uname
|
||||
# . id
|
||||
# . head, tail
|
||||
# . curl
|
||||
# . tar or unzip
|
||||
# . rm
|
||||
|
||||
set -e
|
||||
|
||||
log_info()
|
||||
{
|
||||
printf "[info] %s\\n" "$1"
|
||||
}
|
||||
|
||||
log_error()
|
||||
{
|
||||
printf "[error] %s\\n" "$1"
|
||||
}
|
||||
|
||||
# Get OS
|
||||
# Return: darwin, linux, freebsd
|
||||
detect_os()
|
||||
{
|
||||
UNAME_S="$(uname -s)"
|
||||
OS=
|
||||
case "$UNAME_S" in
|
||||
Linux)
|
||||
OS=linux
|
||||
;;
|
||||
|
||||
FreeBSD)
|
||||
OS=freebsd
|
||||
;;
|
||||
|
||||
Darwin)
|
||||
OS=darwin
|
||||
;;
|
||||
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
echo $OS
|
||||
}
|
||||
|
||||
# Get CPU endianness
|
||||
# Return: le, ""
|
||||
cpu_little_endian()
|
||||
{
|
||||
ENDIAN_FLAG="$(head -c 6 /bin/bash | tail -c 1)"
|
||||
if [ "$ENDIAN_FLAG" = "$(printf '\001')" ]; then
|
||||
echo 'le'
|
||||
return 0
|
||||
# Function log is an echo wrapper that writes to stderr if the caller
|
||||
# requested verbosity level greater than 0. Otherwise, it does nothing.
|
||||
log() {
|
||||
if [ "$verbose" -gt '0' ]
|
||||
then
|
||||
echo "$1" 1>&2
|
||||
fi
|
||||
}
|
||||
|
||||
# Get CPU
|
||||
# Return: amd64, 386, armv5, armv6, armv7, arm64, mips_softfloat, mipsle_softfloat, mips64_softfloat, mips64le_softfloat
|
||||
detect_cpu()
|
||||
{
|
||||
UNAME_M="$(uname -m)"
|
||||
CPU=
|
||||
# Function error_exit is an echo wrapper that writes to stderr and stops the
|
||||
# script execution with code 1.
|
||||
error_exit() {
|
||||
echo "$1" 1>&2
|
||||
|
||||
case "$UNAME_M" in
|
||||
|
||||
x86_64 | x86-64 | x64 | amd64)
|
||||
CPU=amd64
|
||||
;;
|
||||
|
||||
i386 | i486 | i686 | i786 | x86)
|
||||
CPU=386
|
||||
;;
|
||||
|
||||
armv5l)
|
||||
CPU=armv5
|
||||
;;
|
||||
|
||||
armv6l)
|
||||
CPU=armv6
|
||||
;;
|
||||
|
||||
armv7l | armv8l)
|
||||
CPU=armv7
|
||||
;;
|
||||
|
||||
aarch64 | arm64)
|
||||
CPU=arm64
|
||||
;;
|
||||
|
||||
mips)
|
||||
LE=$(cpu_little_endian)
|
||||
CPU=mips${LE}_softfloat
|
||||
;;
|
||||
|
||||
mips64)
|
||||
LE=$(cpu_little_endian)
|
||||
CPU=mips64${LE}_softfloat
|
||||
;;
|
||||
|
||||
*)
|
||||
return 1
|
||||
|
||||
esac
|
||||
|
||||
echo "${CPU}"
|
||||
}
|
||||
|
||||
# Get package file name extension
|
||||
# Return: tar.gz, zip
|
||||
package_extension()
|
||||
{
|
||||
if [ "$OS" = "darwin" ]; then
|
||||
echo "zip"
|
||||
return 0
|
||||
fi
|
||||
echo "tar.gz"
|
||||
}
|
||||
|
||||
# Download data to a file
|
||||
# Use: download URL OUTPUT
|
||||
download()
|
||||
{
|
||||
log_info "Downloading package from $1 -> $2"
|
||||
if is_command curl ; then
|
||||
curl -s "$1" --output "$2" || error_exit "Failed to download $1"
|
||||
else
|
||||
error_exit "curl is necessary to install AdGuard Home"
|
||||
fi
|
||||
}
|
||||
|
||||
# Unpack package to a directory
|
||||
# Use: unpack INPUT OUTPUT_DIR PKG_EXT
|
||||
unpack()
|
||||
{
|
||||
log_info "Unpacking package from $1 -> $2"
|
||||
mkdir -p "$2"
|
||||
if [ "$3" = "zip" ]; then
|
||||
unzip -qq "$1" -d "$2" || return 1
|
||||
elif [ "$3" = "tar.gz" ]; then
|
||||
tar xzf "$1" -C "$2" || return 1
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Print error message and exit
|
||||
# Use: error_exit MESSAGE
|
||||
error_exit()
|
||||
{
|
||||
log_error "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if command exists
|
||||
# Use: is_command COMMAND
|
||||
# Function usage prints the note about how to use the script.
|
||||
#
|
||||
# TODO(e.burkov): Document each option.
|
||||
usage() {
|
||||
echo 'install.sh: usage: [-c channel] [-C cpu_type] [-h] [-O os] [-o output_dir]'\
|
||||
'[-r|-R] [-u|-U] [-v|-V]' 1>&2
|
||||
|
||||
exit 2
|
||||
}
|
||||
|
||||
# Function is_command checks if the command exists on the machine.
|
||||
is_command() {
|
||||
check_command="$1"
|
||||
command -v "${check_command}" >/dev/null 2>&1
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Entry point
|
||||
main() {
|
||||
log_info "Starting AdGuard Home installation script"
|
||||
|
||||
CHANNEL=${1}
|
||||
if [ "${CHANNEL}" != "beta" ] && [ "${CHANNEL}" != "edge" ]; then
|
||||
CHANNEL=release
|
||||
fi
|
||||
log_info "Channel ${CHANNEL}"
|
||||
|
||||
OS=$(detect_os) || error_exit "Cannot detect your OS"
|
||||
CPU=$(detect_cpu) || error_exit "Cannot detect your CPU"
|
||||
|
||||
# TODO: Remove when Mac M1 native support is added
|
||||
if [ "${OS}" = "darwin" ] && [ "${CPU}" = "arm64" ]; then
|
||||
CPU="amd64"
|
||||
log_info "Use ${CPU} build on Mac M1 until the native ARM support is added"
|
||||
fi
|
||||
|
||||
PKG_EXT=$(package_extension)
|
||||
PKG_NAME=AdGuardHome_${OS}_${CPU}.${PKG_EXT}
|
||||
|
||||
SCRIPT_URL="https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh"
|
||||
URL="https://static.adguard.com/adguardhome/${CHANNEL}/${PKG_NAME}"
|
||||
OUT_DIR="/opt"
|
||||
if [ "${OS}" = "darwin" ]; then
|
||||
# It may be important to install AdGuard Home to /Applications on MacOS
|
||||
# Otherwise, it may not grant enough privileges to it
|
||||
OUT_DIR="/Applications"
|
||||
fi
|
||||
|
||||
AGH_DIR="${OUT_DIR}/AdGuardHome"
|
||||
|
||||
# Root check
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
log_info "Script called with root privileges"
|
||||
else
|
||||
if is_command sudo ; then
|
||||
log_info "Please note, that AdGuard Home requires root privileges to install using this script."
|
||||
log_info "Restarting with root privileges"
|
||||
|
||||
exec curl -sSL ${SCRIPT_URL} | sudo sh -s "$@"
|
||||
exit $?
|
||||
else
|
||||
log_info "Root privileges are required to install AdGuard Home using this installer."
|
||||
log_info "Please, re-run this script as root."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "AdGuard Home will be installed to ${AGH_DIR}"
|
||||
|
||||
[ -d "${AGH_DIR}" ] && [ -n "$(ls -1 -A -q ${AGH_DIR})" ] && error_exit "Directory ${AGH_DIR} is not empty, abort installation"
|
||||
|
||||
download "${URL}" "${PKG_NAME}" || error_exit "Cannot download the package"
|
||||
|
||||
if [ "${OS}" = "darwin" ]; then
|
||||
# TODO: remove this after v0.106.0 release
|
||||
mkdir "${AGH_DIR}"
|
||||
unpack "${PKG_NAME}" "${AGH_DIR}" "${PKG_EXT}" || error_exit "Cannot unpack the package"
|
||||
else
|
||||
unpack "${PKG_NAME}" "${OUT_DIR}" "${PKG_EXT}" || error_exit "Cannot unpack the package"
|
||||
fi
|
||||
|
||||
# Install AdGuard Home service and run it.
|
||||
( cd "${AGH_DIR}" && ./AdGuardHome -s install || error_exit "Cannot install AdGuardHome as a service" )
|
||||
|
||||
rm "${PKG_NAME}"
|
||||
|
||||
log_info "AdGuard Home is now installed and running."
|
||||
log_info "You can control the service status with the following commands:"
|
||||
log_info " sudo ${AGH_DIR}/AdGuardHome -s start|stop|restart|status|install|uninstall"
|
||||
# Function is_little_endian checks if the CPU is little-endian.
|
||||
is_little_endian() {
|
||||
[ "$( head -c 6 /bin/sh | tail -c 1 )" = "$( printf '\001' )" ]
|
||||
}
|
||||
|
||||
main "$@"
|
||||
# Function check_required checks if the required software is available on the
|
||||
# machine. The required software:
|
||||
#
|
||||
# curl
|
||||
# unzip (macOS) / tar (other unices)
|
||||
#
|
||||
check_required() {
|
||||
readonly required_darwin="unzip"
|
||||
readonly required_unix="tar"
|
||||
|
||||
# Split with space.
|
||||
required="curl"
|
||||
if [ "$os" = 'linux' ] || [ "$os" = 'freebsd' ]
|
||||
then
|
||||
required="$required $required_unix"
|
||||
elif [ "$os" = 'darwin' ]
|
||||
then
|
||||
required="$required $required_darwin"
|
||||
fi
|
||||
|
||||
# Don't use quotes to get word splitting.
|
||||
for cmd in ${required}
|
||||
do
|
||||
echo "checking $cmd"
|
||||
if ! is_command "$cmd"
|
||||
then
|
||||
log "the full list of required software: [$required]"
|
||||
|
||||
error_exit "$cmd is required to install AdGuard Home via this script"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Function check_out_dir requires the output directory to be set and exist.
|
||||
check_out_dir() {
|
||||
if [ "$out_dir" = '' ]
|
||||
then
|
||||
error_exit 'output directory should be presented'
|
||||
fi
|
||||
|
||||
if ! [ -d "$out_dir" ]
|
||||
then
|
||||
log "$out_dir directory will be created"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function parse_opts parses the options list and validates it's combinations.
|
||||
parse_opts() {
|
||||
while getopts "C:c:hO:o:rRuUvV" opt $*
|
||||
do
|
||||
case "$opt"
|
||||
in
|
||||
(C)
|
||||
cpu="$OPTARG"
|
||||
;;
|
||||
(c)
|
||||
channel="$OPTARG"
|
||||
;;
|
||||
(h)
|
||||
usage
|
||||
;;
|
||||
(O)
|
||||
os="$OPTARG"
|
||||
;;
|
||||
(o)
|
||||
out_dir="$OPTARG"
|
||||
;;
|
||||
(R)
|
||||
reinstall='0'
|
||||
;;
|
||||
(U)
|
||||
uninstall='0'
|
||||
;;
|
||||
(r)
|
||||
reinstall='1'
|
||||
;;
|
||||
(u)
|
||||
uninstall='1'
|
||||
;;
|
||||
(V)
|
||||
verbose='0'
|
||||
;;
|
||||
(v)
|
||||
verbose='1'
|
||||
;;
|
||||
(*)
|
||||
log "bad option $OPTARG"
|
||||
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$uninstall" = '1' ] && [ "$reinstall" = '1' ]
|
||||
then
|
||||
error_exit 'the -r and -u options are mutually exclusive'
|
||||
fi
|
||||
}
|
||||
|
||||
# Function set_channel sets the channel if needed and validates the value.
|
||||
set_channel() {
|
||||
# Validate.
|
||||
case "$channel"
|
||||
in
|
||||
('development'|'edge'|'beta'|'release')
|
||||
# All is well, go on.
|
||||
;;
|
||||
(*)
|
||||
error_exit \
|
||||
"invalid channel '$channel'
|
||||
supported values are 'development', 'edge', 'beta', and 'release'"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Log.
|
||||
log "channel: $channel"
|
||||
}
|
||||
|
||||
# Function set_os sets the os if needed and validates the value.
|
||||
set_os() {
|
||||
# Set if needed.
|
||||
if [ "$os" = '' ]
|
||||
then
|
||||
os="$( uname -s )"
|
||||
case "$os"
|
||||
in
|
||||
('Linux')
|
||||
os='linux'
|
||||
;;
|
||||
('FreeBSD')
|
||||
os='freebsd'
|
||||
;;
|
||||
('Darwin')
|
||||
os='darwin'
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Validate.
|
||||
case "$os"
|
||||
in
|
||||
('linux'|'freebsd'|'darwin')
|
||||
# All right, go on.
|
||||
;;
|
||||
(*)
|
||||
error_exit "unsupported operating system: $os"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Log.
|
||||
log "operating system: $os"
|
||||
}
|
||||
|
||||
# Function set_cpu sets the cpu if needed and validates the value.
|
||||
set_cpu() {
|
||||
# Set if needed.
|
||||
if [ "$cpu" = '' ]
|
||||
then
|
||||
cpu="$( uname -m )"
|
||||
case "$cpu"
|
||||
in
|
||||
('x86_64'|'x86-64'|'x64'|'amd64')
|
||||
cpu='amd64'
|
||||
;;
|
||||
('i386'|'i486'|'i686'|'i786'|'x86')
|
||||
cpu='386'
|
||||
;;
|
||||
('armv5l')
|
||||
cpu='armv5'
|
||||
;;
|
||||
('armv6l')
|
||||
cpu='armv6'
|
||||
;;
|
||||
('armv7l' | 'armv8l')
|
||||
cpu='armv7'
|
||||
;;
|
||||
('aarch64'|'arm64')
|
||||
cpu='arm64'
|
||||
;;
|
||||
('mips'|'mips64')
|
||||
if is_little_endian
|
||||
then
|
||||
cpu="${cpu}le"
|
||||
fi
|
||||
cpu="${cpu}_softfloat"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Validate.
|
||||
case "$cpu"
|
||||
in
|
||||
('amd64'|'386'|'armv5'|'armv6'|'armv7'|'arm64')
|
||||
# All right, go on.
|
||||
;;
|
||||
('mips64le_softfloat'|'mips64_softfloat'|'mipsle_softfloat'|'mips_softfloat')
|
||||
# That's right too.
|
||||
;;
|
||||
(*)
|
||||
error_exit "unsupported cpu type: $cpu"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Log.
|
||||
log "cpu type: $cpu"
|
||||
}
|
||||
|
||||
# Function fix_darwin performs some configuration changes for macOS if
|
||||
# needed.
|
||||
fix_darwin() {
|
||||
if ! [ "$os" = 'darwin' ]
|
||||
then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# TODO: Remove when Mac M1 native support is added.
|
||||
if [ "$cpu" = 'arm64' ]
|
||||
then
|
||||
cpu='amd64'
|
||||
log "use $cpu build on Mac M1 until the native ARM support is added."
|
||||
fi
|
||||
|
||||
# Set the package extension.
|
||||
pkg_ext='zip'
|
||||
|
||||
# It is important to install AdGuard Home into the /Applications
|
||||
# directory on MacOS. Otherwise, it may not grant enough privileges to
|
||||
# the AdGuard Home.
|
||||
out_dir='/Applications'
|
||||
}
|
||||
|
||||
# Function fix_freebsd performs some fixes to make it work on FreeBSD.
|
||||
fix_freebsd() {
|
||||
if ! [ "$os" = 'freebsd' ]
|
||||
then
|
||||
return 0
|
||||
fi
|
||||
|
||||
readonly rcd='/usr/local/etc/rc.d'
|
||||
if ! [ -d "$rcd" ]
|
||||
then
|
||||
mkdir "$rcd"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function configure sets the script's configuration.
|
||||
configure() {
|
||||
set_channel
|
||||
set_os
|
||||
set_cpu
|
||||
fix_darwin
|
||||
check_out_dir
|
||||
|
||||
readonly pkg_name="AdGuardHome_${os}_${cpu}.${pkg_ext}"
|
||||
readonly url="https://static.adguard.com/adguardhome/${channel}/${pkg_name}"
|
||||
readonly agh_dir="${out_dir}/AdGuardHome"
|
||||
|
||||
log "AdGuard Home will be installed into $agh_dir"
|
||||
}
|
||||
|
||||
# Function is_root checks for root privileges to be granted.
|
||||
is_root() {
|
||||
if [ "$( id -u )" = '0' ]
|
||||
then
|
||||
log 'script is executed with root privileges'
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
if is_command sudo
|
||||
then
|
||||
log 'note that AdGuard Home requires root privileges to install using this script'
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
error_exit \
|
||||
'root privileges are required to install AdGuard Home using this script
|
||||
please, restart it with root privileges'
|
||||
}
|
||||
|
||||
# Function rerun_with_root downloads the script and tries to run it with root
|
||||
# privileges. It also uses the configuration that already set.
|
||||
#
|
||||
# TODO(e.burkov): Try to avoid restarting.
|
||||
rerun_with_root() {
|
||||
readonly script_url=\
|
||||
'https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh'
|
||||
|
||||
flags=''
|
||||
if [ "$reinstall" = '1' ]
|
||||
then
|
||||
flags="${flags} -r"
|
||||
fi
|
||||
if [ "$uninstall" = '1' ]
|
||||
then
|
||||
flags="${flags} -u"
|
||||
fi
|
||||
if [ "$verbose" = '1' ]
|
||||
then
|
||||
flags="${flags} -v"
|
||||
fi
|
||||
|
||||
readonly opts="-c $channel -C $cpu -O $os -o $out_dir $flags"
|
||||
|
||||
log 'restarting with root privileges'
|
||||
|
||||
curl -L -S -s "$script_url" | sudo sh -s -- $opts
|
||||
exit $?
|
||||
}
|
||||
|
||||
# Function download downloads the file from the URL and saves it to the
|
||||
# specified filepath.
|
||||
download() {
|
||||
log "downloading package from $url -> $pkg_name"
|
||||
|
||||
if ! curl -s "$url" --output "$pkg_name"
|
||||
then
|
||||
error_exit "cannot download the package from $url into $pkg_name"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function unpack unpacks the passed archive depending on it's extension.
|
||||
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"
|
||||
fi
|
||||
|
||||
case "$pkg_ext"
|
||||
in
|
||||
('zip')
|
||||
unzip "$pkg_name" -d "$out_dir"
|
||||
;;
|
||||
('tar.gz')
|
||||
tar -C "$out_dir" -f "$pkg_name" -x -z
|
||||
;;
|
||||
(*)
|
||||
error_exit "unexpected package extension: '$pkg_ext'"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$?" != '0' ]
|
||||
then
|
||||
error_exit "cannot unpack the package into $out_dir"
|
||||
fi
|
||||
|
||||
rm "$pkg_name"
|
||||
}
|
||||
|
||||
# Function handle_existing detects the existing AGH installation and takes care
|
||||
# of removing it if needed.
|
||||
handle_existing() {
|
||||
if ! [ -d "$agh_dir" ]
|
||||
then
|
||||
log 'no need to uninstall'
|
||||
|
||||
if [ "$uninstall" = '1' ]
|
||||
then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$( ls -1 -A -q $agh_dir )" != '' ]
|
||||
then
|
||||
log 'the existing AdGuard Home installation is detected'
|
||||
|
||||
if [ "$reinstall" != '1' ] && [ "$uninstall" != '1' ]
|
||||
then
|
||||
error_exit \
|
||||
"to reinstall/uninstall the AdGuard Home using\this script specify one of the '-r' or '-u' flags"
|
||||
fi
|
||||
|
||||
if ( cd "$agh_dir" && ! ./AdGuardHome -s uninstall )
|
||||
then
|
||||
# It doesn't terminate the script since it is possible
|
||||
# that AGH just not installed as service but appearing
|
||||
# in the directory.
|
||||
log "cannot uninstall AdGuard Home from $agh_dir"
|
||||
fi
|
||||
|
||||
rm -r "$agh_dir"
|
||||
|
||||
log 'AdGuard Home was successfully uninstalled'
|
||||
fi
|
||||
|
||||
if [ "$uninstall" = '1' ]
|
||||
then
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Function install_service tries to install AGH as service.
|
||||
install_service() {
|
||||
# TODO(e.burkov): Think about AGH's output suppressing with no verbose
|
||||
# flag.
|
||||
if ( cd "$agh_dir" && ./AdGuardHome -s install )
|
||||
then
|
||||
return 0
|
||||
fi
|
||||
|
||||
rm -r "$agh_dir"
|
||||
|
||||
# Some devices detected to have armv7 CPU face the compatibility
|
||||
# issues with actual armv7 builds. We should try to install the
|
||||
# armv5 binary instead.
|
||||
#
|
||||
# See https://github.com/AdguardTeam/AdGuardHome/issues/2542.
|
||||
if [ "$cpu" = 'armv7' ]
|
||||
then
|
||||
cpu='armv5'
|
||||
reinstall='1'
|
||||
|
||||
log "trying to use $cpu cpu"
|
||||
|
||||
rerun_with_root
|
||||
fi
|
||||
|
||||
error_exit 'cannot install AdGuardHome as a service'
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Entrypoint
|
||||
|
||||
# Exit the script if a pipeline fails (-e), prevent accidental filename
|
||||
# expansion (-f), and consider undefined variables as errors (-u).
|
||||
set -e -f -u
|
||||
|
||||
# Set default values of configuration variables.
|
||||
channel='release'
|
||||
reinstall='0'
|
||||
uninstall='0'
|
||||
verbose='0'
|
||||
cpu=''
|
||||
os=''
|
||||
out_dir='/opt'
|
||||
pkg_ext='tar.gz'
|
||||
parse_opts $*
|
||||
|
||||
echo 'starting AdGuard Home installation script'
|
||||
|
||||
configure
|
||||
check_required
|
||||
|
||||
if ! is_root
|
||||
then
|
||||
rerun_with_root
|
||||
fi
|
||||
# Needs rights.
|
||||
fix_freebsd
|
||||
|
||||
handle_existing
|
||||
|
||||
download
|
||||
unpack
|
||||
|
||||
install_service
|
||||
|
||||
echo "\
|
||||
AdGuard Home is now installed and running
|
||||
you can control the service status with the following commands:
|
||||
sudo ${agh_dir}/AdGuardHome -s start|stop|restart|status|install|uninstall"
|
||||
|
||||
@@ -37,13 +37,14 @@ RUN setcap 'cap_net_bind_service=+eip' /opt/adguardhome/AdGuardHome
|
||||
# 67, 68 : DHCP
|
||||
# 80 : HTTP
|
||||
# 443 : HTTPS, DNS-over-HTTPS, DNSCrypt
|
||||
# 784 : DNS-over-QUIC
|
||||
# 853 : DNS-over-TLS
|
||||
# 3000 : HTTP alt
|
||||
# 3001 : HTTP beta
|
||||
# 5443 : DNSCrypt alt
|
||||
EXPOSE 53/tcp 53/udp 67/udp 68/udp 80/tcp 443/tcp 443/udp 784/udp\
|
||||
853/tcp 3000/tcp 3001/tcp 5443/tcp 5443/udp
|
||||
# 6060 : HTTP pprof
|
||||
# 8853 : DNS-over-QUIC
|
||||
EXPOSE 53/tcp 53/udp 67/udp 68/udp 80/tcp 443/tcp 443/udp 853/tcp\
|
||||
3000/tcp 3001/tcp 5443/tcp 5443/udp 6060/tcp 8853/udp
|
||||
|
||||
WORKDIR /opt/adguardhome/work
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ underscores() {
|
||||
git ls-files '*_*.go' | {
|
||||
grep -F\
|
||||
-e '_big.go'\
|
||||
-e '_bsd.go'\
|
||||
-e '_darwin.go'\
|
||||
-e '_freebsd.go'\
|
||||
-e '_linux.go'\
|
||||
|
||||
Reference in New Issue
Block a user