Compare commits

...

27 Commits

Author SHA1 Message Date
Ainar Garipov
dda513fe82 cherry-pick: all: prepare changelog for v0.106.3 release
Merge in DNS/adguard-home from changelog to master

Squashed commit of the following:

commit 126119ecbd9062fcce5dec08a13120c828740e28
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed May 19 14:47:55 2021 +0300

    all: prepare changelog for v0.106.3 release
2021-05-19 15:01:50 +03:00
Ildar Kamalov
13e0124dec cherry-pick: client: fix query log response status error
Closes #3089

Squashed commit of the following:

commit c5f3112298b11a73b77a35ea249f24abed221425
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue May 18 16:08:56 2021 +0300

    client: fix query log response status error
2021-05-19 15:01:46 +03:00
Ainar Garipov
f716b2b3f5 cherry-pick: all: add us to logs
Merge in DNS/adguard-home from imp-logs to master

Squashed commit of the following:

commit b463825196625f59b19977920f828f57e4b87f0d
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue May 18 14:08:24 2021 +0300

    all: add us to logs
2021-05-19 15:00:58 +03:00
Ainar Garipov
031e61305d cherry-pick: all: fix some races
Updates #3087.

Squashed commit of the following:

commit e888ce524f286f3c34e14e0086336b65a95fa020
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon May 17 16:34:10 2021 +0300

    all: fix some races
2021-05-17 17:20:03 +03:00
Eugene Burkov
b1b2f4a233 cherry-pick: improve installation script
Merge in DNS/adguard-home from 2542-2462-imp-script to master

Closes #2462.
Updates #2542.
Updates #2613.

Squashed commit of the following:

commit 4a7472200f2ae07aeccc3511a75a94674b655cdb
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon May 17 15:11:08 2021 +0300

    scripts: imp naming, docs

commit acbb5864a34e81d8c80767dd7ef57dffb189dc64
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon May 17 15:05:57 2021 +0300

    scripts: imp fix

commit 64777015b6d50e7330fbe7546de1f436f4cb707f
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon May 17 14:54:05 2021 +0300

    scripts: fix bsd

commit 3308921f4c253c8670c4be70896c55f7a892ff3e
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon May 17 14:04:04 2021 +0300

    scripts: imp requirements checking

commit 453cf7a4ce676d2eb09d423304e4d5a8962ac4e5
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon May 17 13:54:38 2021 +0300

    scripts: fix docs

commit a2229052f6cf747247c8290cd0de27cc88c14977
Merge: 0852c87b 120ba967
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon May 17 13:50:45 2021 +0300

    Merge branch 'master' into 2542-2462-imp-script

commit 0852c87bf33b833095644e649bbcedbf89ad4f82
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon May 17 13:49:27 2021 +0300

    scripts: add os-specific requirements check

commit 6313d8fd19f70c41b7091511ca8d979859ddb10c
Merge: 1b4092d5 a031cae4
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri May 14 19:46:57 2021 +0300

    Merge branch 'master' into 2542-2462-imp-script

commit 1b4092d5ee1de5b56c6252bf9debe8b90cdf954e
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri May 14 19:46:09 2021 +0300

    scripts: imp install.sh a little

commit 0584b30b4648b88f542fff6f2879c4a7ae042af4
Merge: 22621c86 9d788a29
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri May 14 19:27:47 2021 +0300

    Merge branch 'master' into 2542-2462-imp-script

commit 22621c86a70e61f98850a10f0c5e450c8aeaa90f
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri May 14 19:25:47 2021 +0300

    all: imp code

commit a38f4adc4688995ca515f8d0d8d271427365623c
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri May 14 18:40:37 2021 +0300

    all: fix url variable

commit 238cb859184da4af025137d99216d51d3b481dc0
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri May 14 18:27:13 2021 +0300

    imp code quality

commit 0e36c125369d47612fd97c2841a2a688bed5841d
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri May 14 16:34:49 2021 +0300

    all: fix typos

commit b20f0b72141f5abb5e598324a3f2bd750164e612
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Apr 29 14:02:40 2021 +0300

    all: imp installation script
2021-05-17 15:25:30 +03:00
Ainar Garipov
4921a325e2 cherry-pick: client: upd i18n
Updates #2643.

Squashed commit of the following:

commit 2a3ae4ce7748954ad957fb22b30eacc2b5cc7b6c
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon May 17 13:26:38 2021 +0300

    client: upd i18n
2021-05-17 15:00:10 +03:00
Ainar Garipov
d36f95a2b0 cherry-pick: all: restore netbsd compat
Updates #3147.

Squashed commit of the following:

commit 4e1bcfd1561f9b927755c5024521d5508ef94b1f
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon May 17 13:17:51 2021 +0300

    all: restore netbsd compat
2021-05-17 15:00:03 +03:00
Ainar Garipov
1d61f50fc8 cherry-pick: dhcpd: support decline and release msgs
Updates #3053.

Squashed commit of the following:

commit eb68a21436536d67b6d23873e6b6f291912bf3a1
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri May 14 18:58:15 2021 +0300

    dhcpd: do not panic

commit 423678934e736e842fc90042ee0037d1efa912ee
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri May 14 18:18:49 2021 +0300

    dhcpd: support decline and release msgs
2021-05-17 14:59:59 +03:00
Ainar Garipov
d747ae36ca cherry-pick: dhcpd: refactor validations
Updates #3107.
Updates #3127.

Squashed commit of the following:

commit ad64472566ecd1b0864212cd2644a57439aceb85
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu May 13 14:45:21 2021 +0300

    dhcpd: refactor validations
2021-05-17 14:59:53 +03:00
Ainar Garipov
4e31610d7b cherry-pick: dnsforward: exclude docker dns
Updates #3064.

Squashed commit of the following:

commit 2cfeb830853dffcb26968d0a4d21b623f00da275
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu May 13 14:02:08 2021 +0300

    all: imp code, expose pprof port

commit a22656a3fd24253f7327eff5168ea84391c8d758
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu May 13 13:34:05 2021 +0300

    all: imp code, dockerfile

commit 35e2145fe061d0d803b46578539499ecfe9d3ea4
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu May 13 12:34:09 2021 +0300

    dnsforward: exclude docker dns
2021-05-17 14:59:05 +03:00
Eugene Burkov
3953ca50e6 cherry-pick: 2875 client settings
Merge in DNS/adguard-home from 2875-client-settings to master

Updates #2875.

Squashed commit of the following:

commit 43e5af66acb8ace71a329fe2effae6a78492d73f
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Wed May 12 18:12:03 2021 +0300

    all: fix client settings applying
2021-05-17 14:58:59 +03:00
Eugene Burkov
f7e4e998cf cherri-pick: 3115 domain case
Merge in DNS/adguard-home from 3115-domain-case to master

Updates #3115.

Squashed commit of the following:

commit 02b6d27d862b3e3dc2a17220cec35f0f18e31fb3
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue May 11 19:56:06 2021 +0300

    all: fix typos

commit cdd1de64d5f79605b5fdcad5879204194856b083
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue May 11 19:37:37 2021 +0300

    dnsforward: fix disallowed domains case matching
2021-05-17 14:58:53 +03:00
Ainar Garipov
e301480401 cherry-pick: Fix spelling of lighttpd
Updates #3095.

* commit '23f87dc45e8e58da09df0a8f13f3145554a2f2bb':
  Fix spelling of lighttpd
2021-05-17 14:58:19 +03:00
Ainar Garipov
caa90b0340 cherry-pick: prepare changelog for v0.106.2
Merge in DNS/adguard-home from changelog to master

Squashed commit of the following:

commit 8727a97d052d5d89a4a6ff9a56751c167a36e103
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu May 6 18:06:56 2021 +0300

    prepare changelog for v0.106.2
2021-05-06 18:19:38 +03:00
Ainar Garipov
81a5225622 cherry-pick: client: upd i18n
Updates #2643.

Squashed commit of the following:

commit aae8dd9bd79bdd52d754a2dfd3e725088d34cf33
Merge: 7708a7cb 460aa1a5
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu May 6 16:41:43 2021 +0300

    Merge branch 'master' into 2643-upd-i18n

commit 7708a7cb26a1e70dc920c2e5513e6652e67f77d0
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu May 6 15:46:22 2021 +0300

    client: upd i18n
2021-05-06 18:14:25 +03:00
Ainar Garipov
199e1f6a60 cherry-pick: home: imp client http api, docs
Updates #3075.

Squashed commit of the following:

commit c88fd2e24a19474bce736e5b6af7e094b43be390
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu May 6 16:09:49 2021 +0300

    home: imp code, docs

commit 8ae7d9001927d56394d2177c22fe114d98f01732
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu May 6 15:35:49 2021 +0300

    home: imp client http api, docs
2021-05-06 18:13:43 +03:00
Ainar Garipov
66d47b1462 cherry-pick: dhcpd: imp normalization, validation
Updates #3056.

Squashed commit of the following:

commit 875954fc8d59980a39b03032007cbc15d87801ea
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed May 5 19:54:24 2021 +0300

    all: imp err msgs

commit c6ea471038ce28f608084b59d3447ff64124260f
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed May 5 17:55:12 2021 +0300

    dhcpd: imp normalization, validation
2021-05-06 18:11:43 +03:00
Ainar Garipov
e1ac2590c9 cherry-pick: Disabled autocapitalize on username field in mobile browsers
Updates #3077.

* commit 'b2c48d0d3bcb6f8eb1d95af8516e5531b51e1ea5':
  Disabled autocapitalize on username field in mobile browsers
2021-05-06 18:11:02 +03:00
Ainar Garipov
7696afd03c cherry-pick: bamboo-specs: add missing vars
Merge in DNS/adguard-home from specs-vars to master

Squashed commit of the following:

commit 25f50e4b8c98edf6a3bd161f62bdf5db49202358
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Apr 30 15:12:28 2021 +0300

    bamboo-specs: add missing vars
2021-04-30 15:17:54 +03:00
Ainar Garipov
3d48ec4555 cherry-pick: bamboo-specs: configure release branches
Merge in DNS/adguard-home from specs-branch to master

Squashed commit of the following:

commit 20819ce0d4fc090c3a49d316115b3173300babc4
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Apr 30 14:52:54 2021 +0300

    bamboo-specs: configure release branches
2021-04-30 15:08:57 +03:00
Ainar Garipov
e576a23dd1 cherry-pick: all: prepare changelog for v0.106.1
Merge in DNS/adguard-home from changelog-0.106.1 to master

Squashed commit of the following:

commit f2d1aeba8dc4952bb642e1e223babf6eb1cf3400
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Apr 30 13:53:42 2021 +0300

    all: fix date in changelog

commit 72c1482d37a10fcf2bdfb7f0b513063e8a350bcd
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Apr 30 13:52:42 2021 +0300

    all: prepare changelog for v0.106.1
2021-04-30 14:14:31 +03:00
Ainar Garipov
e0c839f105 cherry-pick: client: upd i18n
Updates #2643.

Squashed commit of the following:

commit 3ffa1870d67de835aa8b473490cbdd482d538ac0
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Apr 30 13:31:27 2021 +0300

    client: upd i18n
2021-04-30 14:14:20 +03:00
Ainar Garipov
49a0b90795 cherry-pick: client: imp private dns resolver docs
Updates #3028.

Squashed commit of the following:

commit a44f1b76a2d659a96b485906c933b239f6d109d9
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Apr 29 17:36:20 2021 +0300

    client: imp private dns resolver docs
2021-04-30 14:14:04 +03:00
Ainar Garipov
ee3b34ecb1 cherry-pick: all: do not check local domains when dhcp srv is off
Updates #3028.

Squashed commit of the following:

commit 49d3ca5c9de0468ccb1792e9de263fd66e30d79c
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Apr 29 15:35:32 2021 +0300

    all: do not check local domains when dhcp srv is off
2021-04-30 14:13:48 +03:00
Ainar Garipov
351d793b96 cherry-pick: dhcpd: normalize hostnames of invalid static leases
Updates #3027.

Squashed commit of the following:

commit 171ebaecb4b96ebeb2d0fa350460c65f244e94ae
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Apr 29 14:45:04 2021 +0300

    all: imp docs

commit 48b13ed5b435042a0622a66b60407116ae5aa288
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Apr 29 14:34:28 2021 +0300

    dhcpd: normalize hostnames of invalid static leases
2021-04-30 14:13:30 +03:00
Ainar Garipov
d59938d254 cherry-pick: aghnet: imp host validation for system resolvers
Updates #3022.

Squashed commit of the following:

commit 2f63b4e1765d9c9bfeadafcfa42c9d8741b628e1
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Apr 28 21:29:28 2021 +0300

    aghnet: fix doc

commit efdc1bb2c8959a9f888d558c32c415e6f3678b0c
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Apr 28 21:19:54 2021 +0300

    all: doc changes

commit 8154797095874771bcf04d109644e6ae33fcb470
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Apr 28 21:15:42 2021 +0300

    aghnet: imp host validation for system resolvers
2021-04-30 14:13:07 +03:00
Ainar Garipov
5b9bbce55d cherry-pick: bamboo-specs: add initial support for release branches
Merge in DNS/adguard-home from release-branches to master

Squashed commit of the following:

commit 1041589d63bb7192c31161ab92f6825ff11063b9
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Apr 28 18:51:36 2021 +0300

    bamboo-specs: add initial support for release branches
2021-04-30 14:12:16 +03:00
60 changed files with 1324 additions and 726 deletions

View File

@@ -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

View File

@@ -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?]”.

View File

@@ -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) |

View File

@@ -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'

View File

@@ -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-адрасам).",

View File

@@ -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",

View File

@@ -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).",

View File

@@ -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.",

View File

@@ -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).",

View File

@@ -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 utiliza para las consultas de recursos servidos localmente. Por ejemplo, este servidor se utiliza 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).",

View File

@@ -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).",

View File

@@ -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",

View File

@@ -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).",

View File

@@ -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).",

View File

@@ -9,7 +9,7 @@
"bootstrap_dns": "ブートストラップDNSサーバ",
"bootstrap_dns_desc": "ブートストラップDNSサーバは、上流として指定したDoHDoTリゾルバの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アドレスをホスト名に逆解決しようとします。",

View File

@@ -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 주소로부터 클라이언트의 호스트명을 역으로 확인하려고 시도합니다.",

View File

@@ -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).",

View File

@@ -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 usa 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).",

View File

@@ -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 usa 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.",

View File

@@ -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-адресом).",

View File

@@ -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).",

View File

@@ -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 地址反向解析成其客户端主机名。",

View File

@@ -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": "新增識別碼",

View File

@@ -9,7 +9,7 @@
"bootstrap_dns": "自我啟動BootstrapDNS 伺服器",
"bootstrap_dns_desc": "自我啟動BootstrapDNS 伺服器被用於解析您明確指定作為上游的 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\",使用反向的 DNSrDNS。如果未被設定AdGuard Home 使用您的作業系統之預設 DNS 解析器。",
"local_ptr_placeholder": "每行輸入一個伺服器位址",
"resolve_clients_title": "啟用用戶端的 IP 位址之反向的解析",
"resolve_clients_desc": "如果被啟用透過傳送指標PTR查詢到對應的解析器私人 DNS 伺服器供區域的用戶端,上游的伺服器供有公共 IP 位址的用戶端AdGuard Home 將試圖反向地解析用戶端的 IP 位址變為它們的主機名稱。",

View File

@@ -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,

View File

@@ -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,

View File

@@ -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({});

View File

@@ -27,6 +27,7 @@ const Form = (props) => {
component={renderInputField}
placeholder={t('username_placeholder')}
autoComplete="username"
autocapitalize="none"
disabled={processing}
validate={[validateRequiredValue]}
/>

6
go.mod
View File

@@ -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
View File

@@ -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=

View File

@@ -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, ".")

View File

@@ -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 {

View File

@@ -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.

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -1,4 +1,4 @@
// +build darwin
// +build darwin netbsd openbsd
package aghos

View File

@@ -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 {

View File

@@ -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()

View File

@@ -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
}

View File

@@ -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: "",
}}

View File

@@ -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{}

View File

@@ -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

View File

@@ -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,
}}

View File

@@ -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]

View File

@@ -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 {

View File

@@ -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{

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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.

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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")
}

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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':

View File

@@ -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"

View File

@@ -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

View File

@@ -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'\