Compare commits

..

37 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
Ainar Garipov
fd3b244a8a Pull request: all: prepare changelog for v0.106.0
Merge in DNS/adguard-home from changelog to master

Squashed commit of the following:

commit 736b462fd1e2603b6b4ae443cc14f4958490887a
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Apr 28 15:18:09 2021 +0300

    all: prepare changelog for v0.106.0
2021-04-28 16:25:06 +03:00
Ainar Garipov
bc33868676 Pull request: client: upd i18n
Updates #2643.

Squashed commit of the following:

commit 7b221535d6a403e5194aaa270790fa6b4a1404c8
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Apr 28 15:50:03 2021 +0300

    client: upd i18n
2021-04-28 16:14:04 +03:00
Eugene Burkov
f603c21b55 Pull request: 2826 auth block
Merge in DNS/adguard-home from 2826-auth-block to master

Updates #2826.

Squashed commit of the following:

commit ae87360379270012869ad2bc4e528e07eb9af91e
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Apr 27 15:35:49 2021 +0300

    home: fix mistake

commit dfa2ab05e9a8e70ac1bec36c4eb8ef3b02283b92
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Apr 27 15:31:53 2021 +0300

    home: imp code

commit ff4220d3c3d92ae604e92a0c5c274d9527350d99
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Apr 27 15:14:20 2021 +0300

    home: imp authratelimiter

commit c73a407d8652d64957e35046dbae7168aa45202f
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Apr 27 14:20:17 2021 +0300

    home: fix authratelimiter

commit 724db4380928b055f9995006cf421cbe9c5363e7
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Apr 23 12:15:48 2021 +0300

    home: introduce auth blocker
2021-04-27 18:56:32 +03:00
Eugene Burkov
3f1b71fdf3 Pull request: 2981 fix double answers
Merge in DNS/adguard-home from 2981-fix-dnsrewrite to master

Closes #2981.
Updates #2923.

Squashed commit of the following:

commit 578754d194a9a9dd0d47e5af7b6c2f315eaa1d1d
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Apr 23 17:07:24 2021 +0300

    all: upd urlfilter
2021-04-26 17:18:42 +03:00
Ainar Garipov
45840948f5 Pull request #1136: dnsforward: lower log level of non-crit err
Updates #3008.

Squashed commit of the following:

commit d02f9befef8db1f1e7f21fb98b59b47c0c275887
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Apr 26 16:30:44 2021 +0300

    dnsforward: lower log level of non-crit err
2021-04-26 16:41:50 +03:00
Ainar Garipov
51372d5c34 Pull request: all: upd dnsproxy, fix root reqs with custom upstreams for domains
Updates #2994.

Squashed commit of the following:

commit e255f1c3af9d5c760a61533b12726b49eb26442a
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Apr 23 15:38:37 2021 +0300

    all: upd dnsproxy, fix root reqs with custom upstreams for domains
2021-04-23 16:26:37 +03:00
Ainar Garipov
cb01eaa7f7 Pull request: all: imp go version setting and detection
Merge in DNS/adguard-home from imp-make to master

Squashed commit of the following:

commit 9ecb3422a55f5d010000bf4253a2766fefa67173
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Apr 22 19:59:36 2021 +0300

    all: fix spelling

commit c136f6562af80a67e627b472621ac68763f85fde
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Apr 22 19:50:07 2021 +0300

    all: imp go version setting and detection
2021-04-22 20:06:34 +03:00
Ainar Garipov
138dfaa85b Pull request: home: rm unnecessary func
Merge in DNS/adguard-home from imp-test to master

Squashed commit of the following:

commit 0ef7812e32b74647b43bb1d69b569e9b102e92b3
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Apr 22 14:12:00 2021 +0300

    home: rm unnecessary func
2021-04-22 14:18:20 +03:00
Eugene Burkov
4165e0ef3a Pull request: 2574 external tests vol.4
Merge in DNS/adguard-home from 2574-external-tests-4 to master

Close #2574.

Squashed commit of the following:

commit 0d06fce604750f76f4a319b2539105e936a248ce
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Apr 22 13:26:25 2021 +0300

    home: imp tests, docs

commit fc7b7f13f19bb8f183522a13d5726253eaae83d0
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Apr 22 12:20:15 2021 +0300

    home: fix whois test
2021-04-22 13:38:24 +03:00
Eugene Burkov
2d87a0458e Pull request: 2829 rm util
Merge in DNS/adguard-home from 2829-finally to master

Closes #2829.

Squashed commit of the following:

commit 22b287d5c2cbeced1b48747a1c4b6431c1052f12
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Wed Apr 21 18:39:54 2021 +0300

    util: rm
2021-04-21 18:50:33 +03:00
73 changed files with 2100 additions and 946 deletions

View File

@@ -10,11 +10,73 @@ and this project adheres to
## [Unreleased]
<!--
## [v0.106.0] - 2021-05-01
## [v0.107.0] - 2021-06-28 (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
### Added
- The ability to block user for login after configurable number of unsuccessful
attempts for configurable time ([#2826]).
- `$denyallow` modifier for filters ([#2923]).
- Hostname uniqueness validation in the DHCP server ([#2952]).
- Hostname generating for DHCP clients which don't provide their own ([#2723]).
- New flag `--no-etc-hosts` to disable client domain name lookups in the
@@ -52,6 +114,9 @@ and this project adheres to
### Fixed
- Multiple answers for `$dnsrewrite` rule matching requests with repeating
patterns in it ([#2981]).
- Root server resolving when custom upstreams for hosts are specified ([#2994]).
- Inconsistent resolving of DHCP clients when the DHCP server is disabled
([#2934]).
- Comment handling in clients' custom upstreams ([#2947]).
@@ -77,11 +142,13 @@ and this project adheres to
[#2704]: https://github.com/AdguardTeam/AdGuardHome/issues/2704
[#2723]: https://github.com/AdguardTeam/AdGuardHome/issues/2723
[#2824]: https://github.com/AdguardTeam/AdGuardHome/issues/2824
[#2826]: https://github.com/AdguardTeam/AdGuardHome/issues/2826
[#2828]: https://github.com/AdguardTeam/AdGuardHome/issues/2828
[#2835]: https://github.com/AdguardTeam/AdGuardHome/issues/2835
[#2838]: https://github.com/AdguardTeam/AdGuardHome/issues/2838
[#2843]: https://github.com/AdguardTeam/AdGuardHome/issues/2843
[#2889]: https://github.com/AdguardTeam/AdGuardHome/issues/2889
[#2923]: https://github.com/AdguardTeam/AdGuardHome/issues/2923
[#2927]: https://github.com/AdguardTeam/AdGuardHome/issues/2927
[#2934]: https://github.com/AdguardTeam/AdGuardHome/issues/2934
[#2945]: https://github.com/AdguardTeam/AdGuardHome/issues/2945
@@ -89,6 +156,8 @@ and this project adheres to
[#2952]: https://github.com/AdguardTeam/AdGuardHome/issues/2952
[#2954]: https://github.com/AdguardTeam/AdGuardHome/issues/2954
[#2961]: https://github.com/AdguardTeam/AdGuardHome/issues/2961
[#2981]: https://github.com/AdguardTeam/AdGuardHome/issues/2981
[#2994]: https://github.com/AdguardTeam/AdGuardHome/issues/2994
[doq-draft-02]: https://tools.ietf.org/html/draft-ietf-dprive-dnsoquic-02
@@ -304,11 +373,15 @@ and this project adheres to
<!--
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.0...HEAD
[v0.106.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.2...v0.106.0
[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.105.2...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
[v0.105.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.104.3...v0.105.0

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

@@ -7,13 +7,15 @@
CHANNEL = development
CLIENT_BETA_DIR = client2
CLIENT_DIR = client
COMMIT = $$(git rev-parse --short HEAD)
COMMIT = $$( git rev-parse --short HEAD )
DIST_DIR = dist
# TODO(a.garipov): Find out a way to make this work in GNU Make.
# Don't name this macro "GO", because GNU Make apparenly makes it an
# exported environment variable with the literal value of "${GO:-go}",
# which is not what we need. Use a dot in the name to make sure that
# users don't have an environment variable with the same name.
#
# GO = $${GO:-go}
#
GO = go
# See https://unix.stackexchange.com/q/646255/105635.
GO.MACRO = $${GO:-go}
GOPROXY = https://goproxy.cn|https://proxy.golang.org|direct
GPG_KEY = devteam@adguard.com
GPG_KEY_PASSPHRASE = not-a-real-password
@@ -37,9 +39,9 @@ ENV = env\
GPG_KEY='$(GPG_KEY)'\
GPG_KEY_PASSPHRASE='$(GPG_KEY_PASSPHRASE)'\
DIST_DIR='$(DIST_DIR)'\
GO='$(GO)'\
GO="$(GO.MACRO)"\
GOPROXY='$(GOPROXY)'\
PATH="$${PWD}/bin:$$($(GO) env GOPATH)/bin:$${PATH}"\
PATH="$${PWD}/bin:$$( "$(GO.MACRO)" env GOPATH )/bin:$${PATH}"\
RACE='$(RACE)'\
SIGN='$(SIGN)'\
VERBOSE='$(VERBOSE)'\
@@ -97,10 +99,10 @@ go-check: go-tools go-lint go-test
# A quick check to make sure that all supported operating systems can be
# typechecked and built successfully.
go-os-check:
env GOOS='darwin' $(GO) vet ./internal/...
env GOOS='freebsd' $(GO) vet ./internal/...
env GOOS='linux' $(GO) vet ./internal/...
env GOOS='windows' $(GO) vet ./internal/...
env GOOS='darwin' "$(GO.MACRO)" vet ./internal/...
env GOOS='freebsd' "$(GO.MACRO)" vet ./internal/...
env GOOS='linux' "$(GO.MACRO)" vet ./internal/...
env GOOS='windows' "$(GO.MACRO)" vet ./internal/...
openapi-lint: ; cd ./openapi/ && $(YARN) test
openapi-show: ; cd ./openapi/ && $(YARN) start

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-адрасам).",
@@ -38,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": "Павінен перавышаць пачатак дыяпазону",
@@ -310,7 +311,7 @@
"install_devices_router": "Роўтар",
"install_devices_router_desc": "Такая наладка аўтаматычна пакрые ўсе прылады, што выкарыстоўваюць ваш хатні роўтар, і вам не трэба будзе наладжваць кожнае з іх у асобнасці.",
"install_devices_address": "DNS-сервер AdGuard Home даступны па наступных адрасах",
"install_devices_router_list_1": "Адкрыйце налады вашага рутара. Звычайна вы можаце адкрыць іх у вашым браўзары (напрыклад, http://192.168.0.1/ ці http://192.168.1.1/). Вас могуць папрасіць увесці пароль. Калі вы не помніце яго, пароль часта можна скінуць, націснуўшы на кнопку на самым роўтары. Некаторыя роўтары патрабуюць адмысловага дадатку, які ў гэтым выпадку павінен быць ужо ўсталявана на ваш кампутар ці тэлефон.",
"install_devices_router_list_1": "Адкрыйце налады вашага роўтара. Звычайна вы можаце адкрыць іх у вашым браўзары, напрыклад, http://192.168.0.1/ ці http://192.168.1.1/. Вас могуць папрасіць увесці пароль. Калі вы не помніце яго, пароль часта можна скінуць, націснуўшы на кнопку на самым роўтары. Некаторыя роўтары патрабуюць адмысловага дадатку, які ў гэтым выпадку павінен быць ужо ўсталявана на ваш кампутар ці тэлефон.",
"install_devices_router_list_2": "Знайдзіце налады DHCP ці DNS. Знайдзіце літары \"DNS\" поруч з тэкставым полем, у якое можна ўвесці два ці тры шэрагі лічбаў, падзеленых на 4 групы ад адной до трох лічбаў.",
"install_devices_router_list_3": "Увядзіце туды адрас вашага AdGuard Home.",
"install_devices_router_list_4": "Вы не можаце ўсталяваць уласны DNS-сервер на некаторых тыпах маршрутызатараў. У гэтым выпадку можа дапамагчы налада AdGuard Home у якасці <a href='#dhcp'>DHCP-сервера</a>. У адваротным выпадку вам трэба звярнуцца да кіраўніцтва па наладзе DNS-сервераў для вашай пэўнай мадэлі маршрутызатара.",
@@ -400,6 +401,7 @@
"ip_address": "IP-адрас",
"client_identifier_desc": "Кліенты могуць быць ідэнтыфікаваны па IP-адрасе, CIDR ці MAC-адрасу. Звярніце ўвагу, што выкарыстанне MAC як ідэнтыфікатара магчыма, толькі калі AdGuard Home таксама з'яўляецца і <0>DHCP-серверам</0>",
"form_enter_ip": "Увядзіце IP",
"form_enter_subnet_ip": "Увядзіце IP-адрас у падсеткі «{{cidr}}»",
"form_enter_mac": "Увядзіце MAC",
"form_enter_id": "Увядзіце ідэнтыфікатар",
"form_add_id": "Дадаць ідэнтыфікатар",

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).",
@@ -38,7 +38,7 @@
"form_error_mac_format": "Format MAC invalide",
"form_error_client_id_format": "Format d'ID client non valide",
"form_error_server_name": "Nom de serveur invalide",
"form_error_subnet": "Le sous-réseau \"{{cidr}}\" ne contient pas l'adresse IP \"{{ip}}\"",
"form_error_subnet": "Le sous-réseau « {{cidr}} » ne contient pas l'adresse IP « {{ip}} »",
"form_error_positive": "Doit être supérieur à 0",
"form_error_negative": "Doit être égal à 0 ou supérieur",
"range_end_error": "Doit être supérieur au début de la gamme",
@@ -58,16 +58,16 @@
"dhcp_warning": "Si vous souhaitez tout de même activer le serveur DHCP, assurez-vous qu'il n'y a pas d'autre serveur DHCP actif sur votre réseau. Sinon, cela peut perturber la connexion Internet sur tous les appareils connectés au réseau !",
"dhcp_error": "AdGuard Home ne peut pas déterminer s'il y a un autre serveur DHCP actif sur le réseau.",
"dhcp_static_ip_error": "Pour utiliser un serveur DHCP, une adresse IP statique est requise. AdGuard Home n'a pas réussi à déterminer si cette interface réseau est configurée via une adresse IP statique. Veuillez définir une adresse IP statique manuellement.",
"dhcp_dynamic_ip_found": "Votre système utilise une configuration d'adresses IP dynamiques pour l'interface <0>{{interfaceName}}</0>. Pour utiliser un serveur DHCP, une adresse IP statique est requise. Votre adresse IP actuelle est <0>{{ipAddress}}</0>. AdGuard Home va automatiquement définir cette adresse IP comme statique si vous appuyez sur le bouton \"Activer le serveur DHCP\".",
"dhcp_lease_added": "\"{{key}}\" de bail statique ajoutée avec succès",
"dhcp_lease_deleted": "\"{{key}}\" de bail statique supprimée avec succès",
"dhcp_dynamic_ip_found": "Votre système utilise une configuration d'adresses IP dynamiques pour l'interface <0>{{interfaceName}}</0>. Pour utiliser un serveur DHCP, une adresse IP statique est requise. Votre adresse IP actuelle est <0>{{ipAddress}}</0>. AdGuard Home va automatiquement définir cette adresse IP comme statique si vous appuyez sur le bouton « Activer le serveur DHCP ».",
"dhcp_lease_added": "« {{key}} » de bail statique ajoutée avec succès",
"dhcp_lease_deleted": "« {{key}} » de bail statique supprimée avec succès",
"dhcp_new_static_lease": "Nouveau bail statique",
"dhcp_static_leases_not_found": "Aucun bail statique DHCP trouvé",
"dhcp_add_static_lease": "Ajoutez un bail statique",
"dhcp_reset": "Voulez-vous vraiment réinitialiser votre configuration DHCP ?",
"country": "Pays",
"city": "Ville",
"delete_confirm": "Voulez-vous vraiment supprimer \"{{key}}\" ?",
"delete_confirm": "Voulez-vous vraiment supprimer « {{key}} »?",
"form_enter_hostname": "Saisissez un nom d'hôte",
"error_details": "Détails des erreurs",
"response_details": "Détails de la réponse",
@@ -201,7 +201,7 @@
"all_lists_up_to_date_toast": "Toutes les listes sont déjà à jour",
"updated_upstream_dns_toast": "Les serveurs DNS upstream sont mis à jour",
"dns_test_ok_toast": "Les serveurs DNS spécifiés fonctionnent correctement",
"dns_test_not_ok_toast": "Impossible d'utiliser le serveur \"{{key}}\": veuillez vérifier si le nom saisi est bien correct",
"dns_test_not_ok_toast": "Impossible d'utiliser le serveur « {{key}} »: veuillez vérifier si le nom saisi est bien correct",
"unblock": "Débloquer",
"block": "Bloquer",
"disallow_this_client": "Interdire ce client",
@@ -227,8 +227,8 @@
"page_table_footer_text": "Page",
"rows_table_footer_text": "lignes",
"updated_custom_filtering_toast": "Règles de filtrage d'utilisateur mises à jour",
"rule_removed_from_custom_filtering_toast": "Règle retirée des règles d'utilisateur: {{rule}}",
"rule_added_to_custom_filtering_toast": "Règle ajoutée aux règles d'utilisateur: {{rule}}",
"rule_removed_from_custom_filtering_toast": "Règle retirée des règles d'utilisateur : {{rule}}",
"rule_added_to_custom_filtering_toast": "Règle ajoutée aux règles d'utilisateur : {{rule}}",
"query_log_response_status": "Statut : {{value}}",
"query_log_filtered": "Filtré par {{filter}}",
"query_log_confirm_clear": "Êtes-vous sûr de vouloir effacer tout le journal des requêtes ?",
@@ -272,10 +272,10 @@
"rate_limit_desc": "Le nombre de requêtes par seconde quun seul client est autorisé à faire. Le réglage 0 fait illimité.",
"blocking_ipv4_desc": "Adresse IP à renvoyer pour une demande A bloquée",
"blocking_ipv6_desc": "Adresse IP à renvoyer pour une demande AAAA bloquée",
"blocking_mode_default": "Par défaut : Répondre avec adresse IP zéro (0.0.0.0 pour A; :: pour AAAA) lorsque bloqué par la règle de style Adblock; répondre avec ladresse IP spécifiée dans la règle lorsque bloquée par la règle du style /etc/hosts",
"blocking_mode_refused": "REFUSED: Répondre avec le code REFUSED",
"blocking_mode_default": "Par défaut : Répondre avec adresse IP zéro (0.0.0.0 pour A ; :: pour AAAA) lorsque bloqué par la règle de style Adblock ; répondre avec ladresse IP spécifiée dans la règle lorsque bloquée par la règle du style /etc/hosts",
"blocking_mode_refused": "REFUSED : Répondre avec le code REFUSED",
"blocking_mode_nxdomain": "NXDOMAIN : Répondre avec le code NXDOMAIN",
"blocking_mode_null_ip": "IP nulle : Répondre avec une adresse IP nulle (0.0.0.0 pour A; :: pour AAAA)",
"blocking_mode_null_ip": "IP nulle : Répondre avec une adresse IP nulle (0.0.0.0 pour A ; :: pour AAAA)",
"blocking_mode_custom_ip": "IP personnalisée : Répondre avec une adresse IP définie manuellement",
"upstream_dns_client_desc": "Si vous laissez ce champ vide, AdGuard Home utilisera les serveurs configurés dans les <0>paramètres DNS</0>.",
"tracker_source": "Source du traceur",
@@ -401,18 +401,18 @@
"ip_address": "Adresse IP",
"client_identifier_desc": "Les clients peuvent être identifiés par les adresses IP, CIDR, MAC ou un ID client spécial (qui peut être utilisé pour DoT/DoH/DoQ). Vous trouverez plus d'information sur l'identification des clients <0>ici</0> .",
"form_enter_ip": "Saisissez l'IP",
"form_enter_subnet_ip": "Saisissez une adresse IP dans le sous-réseau \"{{cidr}}\"",
"form_enter_subnet_ip": "Saisissez une adresse IP dans le sous-réseau « {{cidr}} »",
"form_enter_mac": "Saisissez MAC",
"form_enter_id": "Entrer identifiant",
"form_add_id": "Ajouter identifiant",
"form_client_name": "Saisissez le nom du client",
"name": "Nom",
"client_global_settings": "Utiliser les paramètres généraux",
"client_deleted": "Le client \"{{key}}\" a été supprimé avec succès",
"client_added": "Le client \"{{key}}\" a été ajouté",
"client_updated": "Le client \"{{key}}\" a été mis à jour",
"client_deleted": "Le client « {{key}} » a été supprimé avec succès",
"client_added": "Le client « {{key}} » a été ajouté",
"client_updated": "Le client « {{key}} » a été mis à jour",
"clients_not_found": "Aucun client trouvé",
"client_confirm_delete": "Voulez-vous vraiment supprimer le client \"{{key}}\" ?",
"client_confirm_delete": "Voulez-vous vraiment supprimer le client « {{key}} »?",
"list_confirm_delete": "Voulez-vous vraiment supprimer cette liste ?",
"auto_clients_title": "Clients (exécution)",
"auto_clients_desc": "Les données des clients qu'utilisent AdGuard Home, mais non stockées dans la configuration",
@@ -446,11 +446,11 @@
"setup_dns_privacy_other_5": "Vous trouverez plus d'implémentations <0>ici</0> et <1>ici</1>.",
"setup_dns_privacy_ioc_mac": "Configuration sur iOS et macOS",
"setup_dns_notice": "Pour utiliser le <1>DNS-over-HTTPS</1> ou le <1>DNS-over-TLS</1>, vous devez <0>configurer le Chiffrement</0> dans les paramètres de AdGuard Home.",
"rewrite_added": "Réécriture DNS pour \"{{key}}\" ajoutée",
"rewrite_deleted": "Réécriture DNS pour \"{{key}}\" supprimée",
"rewrite_added": "Réécriture DNS pour « {{key}} » ajoutée",
"rewrite_deleted": "Réécriture DNS pour « {{key}} » supprimée",
"rewrite_add": "Ajouter une réécriture DNS",
"rewrite_not_found": "Aucune réécriture DNS trouvée",
"rewrite_confirm_delete": "Voulez-vous vraiment supprimer la réécriture DNS pour \"{{key}}\" ?",
"rewrite_confirm_delete": "Voulez-vous vraiment supprimer la réécriture DNS pour « {{key}} »?",
"rewrite_desc": "Permet de configurer facilement la réponse DNS personnalisée pour un nom de domaine spécifique.",
"rewrite_applied": "Règle de réécriture appliquée",
"rewrite_hosts_applied": "Réécrit par la règle du fichier dhôtes",
@@ -527,7 +527,7 @@
"disable_ipv6_desc": "Si cette fonctionnalité est activée, toutes les requêtes DNS visant des adresses IPv6 (type AAAA) seront annulées.",
"fastest_addr": "Adresse IP la plus rapide",
"fastest_addr_desc": "Rechercher tous les serveurs DNS et renvoyer ladresse IP la plus rapide parmi toutes les réponses. Cela ralentit les requêtes DNS car AdGuard Home doit attendre les réponses de tous les serveurs DNS, mais la connectivité globale s'améliore.",
"autofix_warning_text": "Si vous cliquez sur \"Réparer\", AdGuardHome configurera votre système pour utiliser le serveur DNS AdGuardHome.",
"autofix_warning_text": "Si vous cliquez sur « Réparer », AdGuardHome configurera votre système pour utiliser le serveur DNS AdGuardHome.",
"autofix_warning_list": "Ceci effectuera les tâches suivantes : <0>Désactiver le système DNSStubListener</0> <0>Définir ladresse du serveur DNS à 127.0.0.1 </0> <0>Remplacer la cible du lien symbolique de /etc/resolv.conf par /run/systemd/resolve/resolv.conf</0> <0>Arrêter DNSStubListener (recharger le service résolu par systemd)</0>",
"autofix_warning_result": "Par conséquent, toutes les demandes DNS de votre système seront traitées par AdGuardHome par défaut.",
"tags_title": "Mots clés",
@@ -554,10 +554,10 @@
"static_ip": "Adresse IP statique",
"static_ip_desc": "AdGuard Home est un serveur, il a donc besoin dune adresse IP statique pour fonctionner correctement. Autrement, à un moment donné, votre routeur pourrait attribuer une adresse IP différente à cet appareil.",
"set_static_ip": "Définir une adresse IP statique",
"install_static_ok": "Bonne nouvelle! Ladresse IP statique est déjà configurée",
"install_static_ok": "Bonne nouvelle ! Ladresse IP statique est déjà configurée",
"install_static_error": "AdGuard Home ne peut pas le configurer automatiquement pour cette interface réseau. Veuillez rechercher une instruction sur la façon de procéder manuellement.",
"install_static_configure": "AdGuard Home a détecté quune adresse IP dynamique est utilisée — <0>{{ip}}</0>. Souhaitez-vous lutiliser comme votre adresse statique ?",
"confirm_static_ip": "AdGuard Home configurera {{ip}} pour être votre adresse IP statique. Voulez-vous poursuivre?",
"confirm_static_ip": "AdGuard Home configurera {{ip}} pour être votre adresse IP statique. Voulez-vous poursuivre ?",
"list_updated": "{{count}} liste mise à jour",
"list_updated_plural": "{{count}} listes mises à jour",
"dnssec_enable": "Activer DNSSEC",

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",
@@ -53,11 +57,14 @@
"dhcp_table_expires": "Lejár",
"dhcp_warning": "Ha engedélyezni szeretné a DHCP-kiszolgálót, ellenőrizze, hogy nincs-e más aktív DHCP-kiszolgáló a hálózaton, mert ez megszakíthatja a hálózati eszközök internetkapcsolatát.",
"dhcp_error": "Az AdGuard Home nem tudta megállapítani, hogy van-e másik aktív DHCP-szerver a hálózaton.",
"dhcp_static_ip_error": "A DHCP szerver használatához statikus IP-címet kell beállítani. Nem sikerült meghatározni, hogy ez a hálózati interfész statikus IP-cím használatával van-e beállítva. Állítson be kézzel egy statikus IP-címet.",
"dhcp_dynamic_ip_found": "A rendszer dinamikus IP-cím konfigurációt használ az <0>{{interfaceName}}</0> interfészhez. A DHCP szerver használatához statikus IP-címet kell beállítani. Jelenlegi IP-címe: <0>{{ipAddress}}</0>. Automatikusan beállítjuk ezt az IP címet statikusnak, ha rányom a DHCP engedélyezése gombra.",
"dhcp_lease_added": "Statikus bérlet \"{{key}}\" sikeresen hozzáadva",
"dhcp_lease_deleted": "Statikus bérlet \"{{key}}\" sikeresen törölve",
"dhcp_new_static_lease": "Új statikus bérlet",
"dhcp_static_leases_not_found": "Nem találhatóak statikus DHCP bérletek",
"dhcp_add_static_lease": "Statikus bérlet hozzáadása",
"dhcp_reset": "Biztosan visszaállítja a DHCP beállításokat?",
"country": "Ország",
"city": "Város",
"delete_confirm": "Biztosan törli a \"{{key}}\" -t?",
@@ -104,7 +111,14 @@
"top_clients": "Legaktívabb kliensek",
"no_clients_found": "Nem található kliens",
"general_statistics": "Általános statisztikák",
"number_of_dns_query_days": "Lekérdezések száma az utolsó {{count}} napban",
"number_of_dns_query_days_plural": "Feldolgozott DNS lekérdezések száma az utolsó {{count}} napban",
"number_of_dns_query_24_hours": "Az elmúlt 24 órában feldolgozott DNS lekérdezések száma",
"number_of_dns_query_blocked_24_hours": "A hirdetésblokkoló szűrők és a hosztfájlok által letiltott DNS kérések száma",
"number_of_dns_query_blocked_24_hours_by_sec": "Az AdGuard böngészési biztonság modulja által letiltott DNS kérések száma",
"number_of_dns_query_blocked_24_hours_adult": "Blokkolt felnőtt tartalmak száma",
"enforced_save_search": "Kényszerített biztonságos keresés",
"number_of_dns_query_to_safe_search": "A biztonságos keresésre kényszerített DNS lekérdezések száma",
"average_processing_time": "Átlagos feldolgozási idő",
"average_processing_time_hint": "A DNS lekérdezések feldolgozásához szükséges átlagos idő milliszekundumban",
"block_domain_use_filters_and_hosts": "Domainek blokkolása szűrők és hosztfájlok használatával",
@@ -114,6 +128,7 @@
"use_adguard_parental": "Használja az AdGuard szülői felügyelet webszolgáltatását",
"use_adguard_parental_hint": "Az AdGuard Home ellenőrzi, hogy a domain tartalmaz-e felnőtteknek szóló anyagokat. Ugyanazokat az adatvédelmi API-kat használja, mint a böngésző biztonsági webszolgáltatás.",
"enforce_safe_search": "Biztonságos keresés kényszerítése",
"enforce_save_search_hint": "Az AdGuard Home a következő keresőmotorokban biztosíthatja a biztonságos keresést: Google, Youtube, Bing, DuckDuckGo, Yandex és Pixabay.",
"no_servers_specified": "Nincsenek megadott kiszolgálók",
"general_settings": "Általános beállítások",
"dns_settings": "DNS beállítások",
@@ -125,6 +140,7 @@
"encryption_settings": "Titkosítási beállítások",
"dhcp_settings": "DHCP beállítások",
"upstream_dns": "Upstream DNS-kiszolgálók",
"upstream_dns_help": "Adja meg a szerverek címeit soronként. <a>Tudjon meg többet</a> a DNS szerverek bekonfigurálásáról.",
"upstream_dns_configured_in_file": "Beállítva itt: {{path}}",
"test_upstream_btn": "Upstreamek tesztelése",
"upstreams": "Upstream-ek",
@@ -253,6 +269,7 @@
"rate_limit": "Kérések korlátozása",
"edns_enable": "EDNS kliens alhálózat engedélyezése",
"edns_cs_desc": "Ha engedélyezve van, az AdGuard Home a kliensek alhálózatait küldi el a DNS-kiszolgálóknak.",
"rate_limit_desc": "Maximálisan hány kérést küldhet egy kliens másodpercenkén. Ha 0-ra állítja, akkor nincs korlátozás.",
"blocking_ipv4_desc": "A blokkolt A kéréshez visszaadandó IP-cím",
"blocking_ipv6_desc": "A blokkolt AAAA kéréshez visszaadandó IP-cím",
"blocking_mode_default": "Alapértelmezés: Válaszoljon nulla IP-címmel (vagyis 0.0.0.0 az A-hoz, :: pedig az AAAA-hoz), amikor a blokkolás egy adblock-stílusú szabállyal történik; illetve válaszoljon egy, a szabály által meghatározott IP címmel, amikor a blokkolás egy /etc/hosts stílusú szabállyal történik",
@@ -275,6 +292,7 @@
"install_settings_listen": "Figyelő felület",
"install_settings_port": "Port",
"install_settings_interface_link": "Az AdGuard Home webes admin felülete elérhető a következő címe(ke)n:",
"form_error_port": "Írja be az érvényes portszámot",
"install_settings_dns": "DNS szerver",
"install_settings_dns_desc": "Be kell állítania az eszközeit vagy a routerét, hogy használni tudja a DNS szervert a következő címeken:",
"install_settings_all_interfaces": "Minden felület",
@@ -293,8 +311,10 @@
"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.",
"install_devices_windows_list_1": "Nyissa meg a Vezérlőpultot a Start menün vagy a Windows keresőn keresztül.",
"install_devices_windows_list_2": "Válassza a Hálózat és internet kategóriát, majd pedig a Hálózati és megosztási központot.",
"install_devices_windows_list_3": "A képernyő bal oldalán keresse meg az Adapterbeállítások módosítása lehetőséget és kattintson rá.",
@@ -320,6 +340,7 @@
"install_saved": "Sikeres mentés",
"encryption_title": "Titkosítás",
"encryption_desc": "Titkosítás (HTTPS/TLS) támogatása mind a DNS, mind pedig a webes admin felület számára",
"encryption_config_saved": "Titkosítási beállítások mentve",
"encryption_server": "Szerver neve",
"encryption_server_enter": "Adja meg az Ön domain címét",
"encryption_server_desc": "A HTTPS használatához meg kell adnia a szerver nevét, amely megegyezik az SSL tanúsítvánnyal vagy a helyettesítő tanúsítvánnyal. Ha a mező nincs beállítva, akkor bármely tartományhoz elfogadja a TLS kapcsolatokat.",
@@ -350,10 +371,13 @@
"encryption_reset": "Biztosan visszaállítja a titkosítási beállításokat?",
"topline_expiring_certificate": "Az SSL-tanúsítványa hamarosan lejár. Frissítse a <0>Titkosítási beállításokat</0>.",
"topline_expired_certificate": "Az SSL-tanúsítványa lejárt. Frissítse a <0>Titkosítási beállításokat</0>.",
"form_error_port_range": "A port értékét a 80-65535 tartományban adja meg",
"form_error_port_unsafe": "Ez a port nem biztonságos",
"form_error_equal": "Nem egyezhetnek",
"form_error_password": "A jelszavak nem egyeznek",
"reset_settings": "Beállítások visszaállítása",
"update_announcement": "Az AdGuard Home {{version}} verziója elérhető! <0>Kattintson ide</0> további információkért.",
"setup_guide": "Beállítási útmutató",
"dns_addresses": "DNS címek",
"dns_start": "A DNS szerver indul",
"dns_status_error": "Hiba történt a DNS szerver állapotának ellenőrzésekor",
@@ -377,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",
@@ -398,6 +423,7 @@
"access_disallowed_title": "Nem engedélyezett kliensek",
"access_disallowed_desc": "A CIDR vagy IP címek listája. Ha konfigurálva van, az AdGuard Home eldobja a lekérdezéseket ezekről az IP-címekről.",
"access_blocked_title": "Nem engedélyezett domainek",
"access_blocked_desc": "Ne keverje össze ezt a szűrőkkel. Az AdGuard Home az összes DNS kérést el fogja dobni, ami ezekkel a domainekkel kapcsolatos. Itt megadhatja a pontos domainneveket, a helyettesítő karaktereket és az urlfilter-szabályokat, pl. 'example.org', '*.example.org' vagy '||example.org^'.",
"access_settings_saved": "A hozzáférési beállítások sikeresen mentésre kerültek",
"updates_checked": "A frissítések sikeresen ellenőrizve lettek",
"updates_version_equal": "Az AdGuard Home naprakész",
@@ -500,6 +526,7 @@
"disable_ipv6": "IPv6 letiltása",
"disable_ipv6_desc": "Ha ez a szolgáltatás engedélyezve van, akkor az összes IPv6-cím (AAAA típus) DNS-lekérdezése elveszik.",
"fastest_addr": "Leggyorsabb IP-cím",
"fastest_addr_desc": "Kérdezze le az összes DNS-kiszolgálót, és adja vissza a leggyorsabb IP-címet a válaszok közül. Ez lelassítja a DNS-lekérdezéseket, mivel az összes DNS-kiszolgáló esetében meg kell várnunk a válaszokat, de javítja az összeköttetést.",
"autofix_warning_text": "Ha a \"Javítás\" lehetőségre kattint, az AdGuard Home megpróbálja beállítani a rendszerét, hogy használja az AdGuard Home DNS szervert.",
"autofix_warning_list": "A következő feladatokat hajtja végre: <0>A DNSStubListener rendszer kikapcsolása</0><0>Beállítja a DNS-kiszolgáló címét 127.0.0.1-re.</0><0>Lecseréli az /etc/resolv.conf szimbolikus útvonalat erre: /run/systemd/resolve/resolv.conf</0><0>A DNSStubListener leállítása (a rendszer által feloldott szolgáltatás újratöltése)</0>",
"autofix_warning_result": "Mindennek eredményeként az Ön rendszeréből származó összes DNS-kérést alapértelmezés szerint az AdGuard Home dolgozza fel.",
@@ -529,6 +556,7 @@
"set_static_ip": "Statikus IP-cím beállítása",
"install_static_ok": "Jó hír! A statikus IP-cím már be van állítva",
"install_static_error": "Az AdGuard Home nem tudja automatikusan konfigurálni ezt a hálózati felületet. Kérjük, nézzen utána, hogyan kell ezt manuálisan elvégezni.",
"install_static_configure": "Úgy észleltük, hogy dinamikus IP-cím van használatban — <0>{{ip}}</0>. Szeretné ezt statikus IP-címként használni?",
"confirm_static_ip": "Az AdGuard Home beállítja az {{ip}} IP-címet az Ön statikus IP-címének. Biztosan folytatni kívánja?",
"list_updated": "{{count}} lista frissítve lett",
"list_updated_plural": "{{count}} lista frissítve lett",
@@ -566,6 +594,7 @@
"filter_category_security_desc": "Olyan listák, amelyek a kártékony, adathalász vagy átverős oldalak tiltására vannak kifejlesztve",
"filter_category_regional_desc": "Olyan listák, amelyek a regionális hirdetések, valamint a nyomkövető szerverek ellen vannak kifejlesztve",
"filter_category_other_desc": "További tiltólisták",
"setup_config_to_enable_dhcp_server": "Konfiguráció beállítása a DHCP-kiszolgáló engedélyezéséhez",
"original_response": "Eredeti válasz",
"click_to_view_queries": "Kattintson a lekérésekért",
"port_53_faq_link": "Az 53-as portot gyakran a \"DNSStubListener\" vagy a \"systemd-resolved\" (rendszer által feloldott) szolgáltatások használják. Kérjük, olvassa el <0>ezt az útmutatót</0> a probléma megoldásához.",

View File

@@ -1,10 +1,20 @@
{
"client_settings": "Pengaturan klien",
"example_upstream_reserved": "Anda dapat menetapkan DNS upstream <0>untuk domain spesifik</0>",
"example_upstream_comment": "Anda dapat menentukan komentar",
"upstream_parallel": "Gunakan kueri paralel untuk mempercepat resoluasi dengan menanyakan semua server upstream secara bersamaan",
"parallel_requests": "Permintaan paralel",
"load_balancing": "Penyeimbang beban",
"load_balancing_desc": "Permintaan satu server pada satu waktu. AdGuard Home akan menggunakan algoritma acak tertimbang untuk memilih server sehingga server tercepat akan lebih sering digunakan.",
"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 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).",
"check_dhcp_servers": "Cek untuk server DHCP",
"save_config": "Simpan pengaturan",
"enabled_dhcp": "Server DHCP diaktifkan",
"disabled_dhcp": "Server DHCP dinonaktifkan",
"unavailable_dhcp": "DHCP tidak tersedia",
@@ -13,10 +23,12 @@
"dhcp_description": "Jika router Anda tidak mendukung pengaturan DHCP, Anda dapat menggunakan server DHCP bawaan AdGuard.",
"dhcp_enable": "Aktifkan server DHCP",
"dhcp_disable": "Nonaktifkan server DHCP",
"dhcp_not_found": "Aman untuk mengaktifkan server DHCP yang dibangun karena rumah AdGuard tidak menemukan server DHCP yang aktif pada jaringan. Namun, Anda harus memeriksa ulang secara manual sebagai penyelidikan otomatis tidak memberikan jaminan 100%.",
"dhcp_found": "Ditemukan beberapa server DHCP aktif di dalam jaringan. Tidak aman untuk menyalakan server DHCP bawaan.",
"dhcp_leases": "DHCP leases",
"dhcp_static_leases": "DHCP static leases",
"dhcp_leases_not_found": "DHCP lease tidak ditemukan",
"dhcp_config_saved": "Pengaturan server DHCP tersimpan",
"dhcp_ipv4_settings": "Pengaturan DHCP IPv4",
"dhcp_ipv6_settings": "Pengaturan DHCP IPv6",
"form_error_required": "Kolom yang harus diisi",
@@ -25,6 +37,8 @@
"form_error_ip_format": "Format IPv4 tidak valid",
"form_error_mac_format": "Format MAC tidak valid",
"form_error_client_id_format": "Format client ID tidak valid",
"form_error_server_name": "Nama server tidak valid",
"form_error_subnet": "Subnet \"{{cidr}}\" tidak berisi alamat IP \"{{ip}}\"",
"form_error_positive": "Harus lebih dari 0",
"form_error_negative": "Harus berjumlah 0 atau lebih besar dari 0",
"range_end_error": "Harus lebih besar dari rentang awal",
@@ -41,11 +55,16 @@
"ip": "IP",
"dhcp_table_hostname": "Nama host",
"dhcp_table_expires": "Kadaluwarsa",
"dhcp_warning": "Jika anda ingin mengaktifkan server DHCP bawaan, pastikan tidak ada server DHCP lain yang aktif. Jika tidak, akan memutus koneksi internet pada perangkat yang telah terhubung!",
"dhcp_error": "AdGuard Home tidak dapat menentukan apakah ada server DHCP aktif lain pada jaringan.",
"dhcp_static_ip_error": "Jika ingin menggunakan server DHCP, alamat IP statis harus diatur. AdGuard Home gagal menentukan jika antarmuka jaringan ini dikonfigurasi menggunakan alamat IP statis. Silakan atur alamat IP statis secara manual.",
"dhcp_dynamic_ip_found": "Sistem Anda menggunakan konfigurasi alamat IP dinamis untuk antarmuka <0>{{interfaceName}}</0>. Untuk menggunakan server DHCP, alamat IP statis harus ditetapkan. Alamat IP Anda saat ini adalah <0>{{ipAddress}}</0>. AdGuard Home akan secara otomatis menetapkan alamat IP ini sebagai statis jika Anda menekan tombol Aktifkan DHCP.",
"dhcp_lease_added": "Static lease \"{{key}}\" berhasil ditambahkan",
"dhcp_lease_deleted": "Static lease \"{{key}}\" berhasil dihapus",
"dhcp_new_static_lease": "Static lease baru",
"dhcp_static_leases_not_found": "DHCP static lease tidak ditemukan",
"dhcp_add_static_lease": "Tambah static lease",
"dhcp_reset": "Apakah anda yakin ingin mengatur ulang konfigurasi DHCP anda?",
"country": "Negara",
"city": "Kota",
"delete_confirm": "Apakah anda yakin ingin menghapus \"{{key}}\"?",
@@ -92,7 +111,14 @@
"top_clients": "Klien teratas",
"no_clients_found": "Tidak ditemukan klien",
"general_statistics": "Statistik umum",
"number_of_dns_query_days": "Jumlah kueri DNS diproses selama {{value}} hari terakhir",
"number_of_dns_query_days_plural": "Jumlah kueri DNS yang diproses selama {{count}} hari terakhir",
"number_of_dns_query_24_hours": "Jumlah kueri DNS diproses selama 24 jam terakhir",
"number_of_dns_query_blocked_24_hours": "Julah DNS diblokir oleh penyaring adblock dan daftar blokir hosts",
"number_of_dns_query_blocked_24_hours_by_sec": "Jumlah perminataan DNS diblokir oleh modul Kemanan Penjelajahan AdGuard",
"number_of_dns_query_blocked_24_hours_adult": "Jumlah website dewasa diblokir",
"enforced_save_search": "Paksa pencarian aman",
"number_of_dns_query_to_safe_search": "Jumlah perminataan DNS ke mesin pencari yang dipaksa Pencarian Aman",
"average_processing_time": "Rata-rata waktu pemrosesan",
"average_processing_time_hint": "Rata-rata waktu dalam milidetik untuk pemrosesan sebuah permintaan DNS",
"block_domain_use_filters_and_hosts": "Blokir domain menggunakan filter dan file hosts",
@@ -102,6 +128,7 @@
"use_adguard_parental": "Gunakan layanan web kontrol orang tua AdGuard",
"use_adguard_parental_hint": "AdGuard Home akan mengecek jika domain mengandung materi dewasa. Akan menggunakan API yang ramah privasi yang sama sebagai layanan web keamanan penjelajahan.",
"enforce_safe_search": "Paksa penelusuran aman",
"enforce_save_search_hint": "AdGuard Home dapat memaksa penelusuran aman pada mesin pencari berikut: Google, Youtube, Bing, DuckDuckGo, Yandex, dan Pixabay.",
"no_servers_specified": "Sever tidak disebutkan",
"general_settings": "Pengaturan umum",
"dns_settings": "Pengaturan DNS",
@@ -113,6 +140,7 @@
"encryption_settings": "Pengaturan enkripsi",
"dhcp_settings": "Pengaturan DHCP",
"upstream_dns": "Server DNS hulu",
"upstream_dns_help": "Masukkan alamat server per baris. <a>Pelajari lebih</a> mengenai konfigurasi upstream server DNS.",
"upstream_dns_configured_in_file": "Diatur dalam {{path}}",
"test_upstream_btn": "Uji hulu",
"upstreams": "Upstream",
@@ -226,15 +254,22 @@
"custom_ip": "Custom IP",
"blocking_ipv4": "Blokiran IPv4",
"blocking_ipv6": "Blokiran IPv6",
"dnscrypt": "DNSCrypt",
"dns_over_https": "DNS-over-HTTPS",
"dns_over_tls": "DNS-over-TLS",
"dns_over_quic": "DNS-over-QUIC",
"client_id": "ID Klien",
"client_id_placeholder": "Masukkan ID klien",
"client_id_desc": "Klien yang berbeda dapat diidentifikasi dengan ID klien khusus. <a>Di sini</a> Anda dapat mempelajari lebih lanjut tentang cara mengidentifikasi klien.",
"download_mobileconfig_doh": "Unduh .mobileconfig untuk DNS-over-HTTPS",
"download_mobileconfig_dot": "Unduh .mobileconfig untuk DNS-over-TLS",
"download_mobileconfig": "Unduh berkas konfigurasi",
"plain_dns": "Plain DNS",
"form_enter_rate_limit": "Masukkan batas nilai",
"rate_limit": "Batas nilai",
"edns_enable": "Aktifkan EDNS Klien Subnet",
"edns_cs_desc": "Apabila dinyalakan, AdGuard Home akan mengirim subnet klien ke server-server DNS.",
"rate_limit_desc": "Jumlah permintaan per detik yang diperbolehkan untuk satu klien. Atur ke 0 untuk tidak terbatas.",
"blocking_ipv4_desc": "Alamat IP akan dikembalikan untuk permintaan A yang diblokir",
"blocking_ipv6_desc": "Alamat IP akan dipulihkan untuk permintaan AAAA yang diblokir",
"blocking_mode_default": "Default: Tanggapi dengan alamat IP nol (0.0.0.0 untuk A; :: untuk AAAA) saat diblokir oleh aturan gaya Adblock; tanggapi dengan alamat IP yang ditentukan dalam aturan ketika diblokir oleh aturan gaya host /etc/",
@@ -276,8 +311,10 @@
"install_devices_router": "Router",
"install_devices_router_desc": "Pengaturan ini akan secara otomatis mencakup semua perangkat yang terhubung ke router rumah anda dan anda tak perlu mengkonfigurasikan secara manual.",
"install_devices_address": "Server DNS AdGuard Home akan menggunakan alamat berikut",
"install_devices_router_list_1": "Buka preferensi untuk router Anda. Biasanya, Anda dapat mengaksesnya dari browser Anda melalui URL, seperti http://192.168.0.1/ atau http://192.168.1.1/. Anda mungkin diminta untuk memasukkan kata sandi. Jika Anda tidak mengingatnya, Anda sering kali dapat mengatur ulang kata sandi dengan menekan tombol pada perute itu sendiri, tetapi perlu diketahui bahwa jika prosedur ini dipilih, Anda mungkin akan kehilangan seluruh konfigurasi perute. Jika router Anda memerlukan aplikasi untuk menyiapkannya, instal aplikasi tersebut di ponsel atau PC Anda dan gunakan untuk mengakses pengaturan router.",
"install_devices_router_list_2": "Temukan pengaturan DHCP / DNS. Cari huruf DNS di sebelah bidang yang memungkinkan dua atau tiga set angka, masing-masing dipecah menjadi empat grup dengan satu hingga tiga digit.",
"install_devices_router_list_3": "Masukkan alamat server AdGuard Home disana",
"install_devices_router_list_4": "Anda tidak dapat menyetel server DNS kustom pada beberapa tipe router. Dalam hal ini mungkin membantu jika Anda mengatur AdGuard Home sebagai <0>server DHCP</0>. Jika tidak, Anda harus mencari petunjuk tentang cara mengkustomisasi server DNS untuk model router khusus Anda.",
"install_devices_windows_list_1": "Buka Panel Kontrol melalui menu Start atau pencarian Windows.",
"install_devices_windows_list_2": "Masuk ke kategori Jaringan dan Internet (Network and Internet) dan kemudian ke Pusat Jaringan dan Berbagi (Network and Sharing Center).",
"install_devices_windows_list_3": "Di sisi kiri layar temukan Ubah pengaturan adaptor dan klik.",
@@ -303,8 +340,10 @@
"install_saved": "Berhasil disimpan",
"encryption_title": "Enkripsi",
"encryption_desc": "Enkripsi (HTTPS / TLS) untuk DNS dan antarmuka admin",
"encryption_config_saved": "Pengaturan enkripsi telah tersimpan",
"encryption_server": "Nama server",
"encryption_server_enter": "Masukkan nama domain anda",
"encryption_server_desc": "Untuk menggunakan HTTPS, Anda harus memasukkan nama server yang cocok dengan sertifikat SSL Anda. Bila ruas tak ditata, akan menerima koneksi TLS bagi domain manapun.",
"encryption_redirect": "Alihkan ke HTTPS secara otomatis",
"encryption_redirect_desc": "Jika dicentang, AdGuard Home akan secara otomatis mengarahkan anda dari HTTP ke alamat HTTPS.",
"encryption_https": "Port HTTPS",
@@ -332,10 +371,13 @@
"encryption_reset": "Anda yakin ingin mengatur ulang pengaturan enkripsi?",
"topline_expiring_certificate": "Sertifikat SSL Anda hampir kedaluwarsa. Perbarui <0>Pengaturan enkripsi</0>.",
"topline_expired_certificate": "Sertifikat SSL Anda kedaluwarsa. Perbarui <0>Pengaturan enkripsi</0>.",
"form_error_port_range": "Masukkan nomor port di kisaran 80-65535",
"form_error_port_unsafe": "Ini adalah port yang tidak aman",
"form_error_equal": "Seharusnya tidak sama",
"form_error_password": "Kata sandi tidak cocok",
"reset_settings": "Setel ulang pengaturan",
"update_announcement": "AdGuard Home {{version}} sekarang tersedia! <0>Klik di sini</0> untuk info lebih lanjut.",
"setup_guide": "Panduan Penyiapan",
"dns_addresses": "Alamat DNS",
"dns_start": "Server DNS sedang dinyalakan",
"dns_status_error": "Kesalahan dalam mendapatkan status server DNS",
@@ -357,7 +399,9 @@
"client_edit": "Ubah Klien",
"client_identifier": "Identifikasi",
"ip_address": "Alamat IP",
"client_identifier_desc": "Klien dapat diidentifikasi oleh alamat IP, CIDR, alamat MAC atau ID klien khusus (dapat digunakan untuk DoT/DoH/DoQ). <0>Di sini</0> Anda dapat mempelajari lebih lanjut tentang bagaimana mengidentifikasi klien.",
"form_enter_ip": "Masukkan IP",
"form_enter_subnet_ip": "Masukkan alamat IP di subnet \"{{cidr}}\"",
"form_enter_mac": "Masukkan MAC",
"form_enter_id": "Masukkan pengenal",
"form_add_id": "Tambah pengenal",
@@ -379,6 +423,7 @@
"access_disallowed_title": "Klien yang tidak diizinkan",
"access_disallowed_desc": "Daftar CIDR atau alamat IP. Jika dikonfigurasi, AdGuard Home akan membatalkan permintaan dari alamat IP ini.",
"access_blocked_title": "Domain yang diblokir",
"access_blocked_desc": "Jangan bingung antara ini dengan filter. AdGuard Home akan membatalkan kueri DNS dengan domain ini dalam pertanyaan kueri. Di sini Anda dapat menentukan nama domain yang tepat, karakter pengganti, dan aturan filter URL, mis. \"example.org\", \"*.example.org\" atau \"||example.org^\".",
"access_settings_saved": "Pengaturan akses berhasil disimpan",
"updates_checked": "Pembaruan berhasil dicek",
"updates_version_equal": "AdGuard Home sudah tebaru",
@@ -481,6 +526,7 @@
"disable_ipv6": "Matikan IPv6",
"disable_ipv6_desc": "Apabila fitur ini dinyalakan, semua permintaan DNS untuk alamat-alamat IPv6 (tipe AAAA) akan diputus.",
"fastest_addr": "Alamat IP tercepat",
"fastest_addr_desc": "Kuiri semua server DNS dan kembalikan alamat IP tercepat diantara semua tanggapan. Ini memperlambat pencarian DNS Sebagai Rumah AdGuard harus menunggu tanggapan dari semua server DNS, tapi meningkatkan konektivitas keseluruhan.",
"autofix_warning_text": "Apabila anda menekan \"Perbaiki\", AdGuardHome akan mengatur sistem anda untuk menggunakan server DNS AdGuardHome.",
"autofix_warning_list": "Ini akan melakukan tugas berikut: <0>Nonaktifkan sistem DNSStubListener</0> <0> Atur alamat server DNS ke 127.0.0.1</0> <0>Ganti target tautan simbolis /etc/resolv.conf pakai /run/systemd/resolve/resolv.conf</0> <0>Hentikan DNSStubListener (muat ulang layanan sistemd-resolve service)</0>",
"autofix_warning_result": "Hasilnya, semua permintaan DNS dari sistem anda akan diproses oleh AdGuardHome secara standar.",
@@ -510,6 +556,7 @@
"set_static_ip": "Atur alamat IP statik",
"install_static_ok": "Kabar baik! Alamat IP statis sudah dikonfigurasi",
"install_static_error": "AdGuard Home tidak dapat mengonfigurasinya secara otomatis untuk antarmuka jaringan ini. Silakan cari instruksi tentang cara melakukan ini secara manual.",
"install_static_configure": "AdGuard Home mendeteksi alamat IP dinamis <0>{{ip}}</0> digunakan. Anda ingin menggunakannya sebagai alamat statis Anda?",
"confirm_static_ip": "AdGuard Home akan mengonfigurasi {{ip}} menjadi alamat IP statis Anda. Anda ingin melanjutkan?",
"list_updated": "{{count}} daftar terbarui",
"list_updated_plural": "{{count}} daftar terbarui",
@@ -547,6 +594,7 @@
"filter_category_security_desc": "Daftar yang khusus pada pemblokiran malware, phishing, atau domain penipuan",
"filter_category_regional_desc": "Daftar yang berfokus pada iklan regional dan server pelacakan",
"filter_category_other_desc": "Daftar hitam lain",
"setup_config_to_enable_dhcp_server": "Setel konfigurasi untuk aktifkan server DHCP",
"original_response": "Respon asli",
"click_to_view_queries": "Klik untuk lihat permintaan",
"port_53_faq_link": "Port 53 sering ditempati oleh layanan \"DNSStubListener\" atau \"systemd-resolved\". Silakan baca <0>instruksi ini</0> tentang cara menyelesaikan ini.",

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 주소로부터 클라이언트의 호스트명을 역으로 확인하려고 시도합니다.",
@@ -23,7 +23,7 @@
"dhcp_description": "라우터가 DHCP 설정을 제공하지 않으면 AdGuard의 자체 기본 제공 DHCP 서버를 사용할 수 있습니다.",
"dhcp_enable": "DHCP 서버 활성화",
"dhcp_disable": "DHCP 서버 비활성화",
"dhcp_not_found": "AdGuard Home이 네트워크에서 활성 DHCP 서버를 찾지 못했기 때문에 DHCP 서버를 활성화하는 것이 안전합니다. 하지만 자동 검색이 100% 보장을 제공하지 않으므로 수동으로 다시 확인해 보세요.",
"dhcp_not_found": "AdGuard Home이 네트워크에서 활성화된 DHCP 서버를 찾지 못했기 때문에 DHCP 서버를 활성화하는 것이 안전합니다. 하지만 자동 검색이 완전히 안전하지 않기 때문에 수동으로 다시 확인하는 걸 권장합니다.",
"dhcp_found": "네트워크에 활성 DHCP 서버가 있습니다. 기본 제공 DHCP 서버를 활성화하는 것은 안전하지 않습니다.",
"dhcp_leases": "DHCP 임대",
"dhcp_static_leases": "DHCP 고정 임대",
@@ -311,7 +311,7 @@
"install_devices_router": "라우터",
"install_devices_router_desc": "이 설정은 이제 자동으로 당신의 집의 라우터에 연결된 모든 기기에 적용될 것이기에 수동으로 각각의 기기를 설정해줄 필요가 없습니다.",
"install_devices_address": "AdGuard Home DNS 서버는 다음의 주소를 받고 있습니다.",
"install_devices_router_list_1": "라우터의 환경 설정을 여세요. 환경 설정은 다음의 주소(http://192.168.0.1/ 혹은 http://192.168.1.1/)를 통해 브라우저로 접근 가능합니다. 비밀번호를 입력해야할 수 있습니다. 비밀번호를 잊었다면 라우터 기기에 있는 버튼을 눌러 비밀번호를 초기화할 수 있지만 라우터 구성이 손실될 수 있습니다. 라우터 설정에 앱이 필요한 경우, 휴대폰이나 컴퓨터에 앱을 설치하고 이를 사용하여 라우터 설정에 액세스하세요.",
"install_devices_router_list_1": "라우터의 환경 설정을 여세요. 환경 설정은 다음의 주소(http://192.168.0.1/ 혹은 http://192.168.1.1/)를 통해 브라우저로 접근 가능합니다. 비밀번호를 입력해야 할 수 있습니다. 비밀번호를 잊었다면 라우터 기기에 있는 버튼을 눌러 비밀번호를 초기화할 수 있지만 라우터 설정이 손실될 수 있습니다. 라우터 설정에 앱이 필요한 경우, 휴대폰이나 컴퓨터에 앱을 설치하고 이를 사용하여 라우터 설정에 액세스하세요.",
"install_devices_router_list_2": "각각 1~3자리 숫자의 네 그룹으로 분할된 두 세트의 숫자를 허용하는 필드 옆에 있는 DNS 문자를 찾으세요.",
"install_devices_router_list_3": "AdGuard Home 서버 주소를 입력하세요",
"install_devices_router_list_4": "일부 라우터 유형에서는 사용자 정의 DNS 서버를 설정할 수 없습니다. 이 경우에는 AdGuard Home을 <0>DHCP 서버</0>로 설정할 수 있습니다. 그렇지 않으면 특정 라우터 모델에 맞게 DNS 서버를 설정하는 방법을 찾아야 합니다.",
@@ -526,7 +526,7 @@
"disable_ipv6": "IPv6 비활성화",
"disable_ipv6_desc": "이 기능이 활성화되면 IPv6 (타입 AAAA) 의 모든 DNS 쿼리가 드랍됩니다.",
"fastest_addr": "가장 빠른 IP 주소",
"fastest_addr_desc": "반응이 가장 빠른 IP주소를 가진 DNS서버에 쿼리를 수행합니다. AdGuard Home이 모든 DNS 서버의 응답을 기다려야하기 때문에 DNS 쿼리 속도가 느려지지만 전반적인 연결이 향상됩니다.",
"fastest_addr_desc": "모든 DNS 서버에 쿼리를 수행한 다음 반응이 가장 빠른 IP주소를 반송합니다. AdGuard Home이 모든 DNS 서버의 응답을 기다려야 하기 때문에 DNS 쿼리 속도가 느려지지만 전반적인 연결이 향상됩니다.",
"autofix_warning_text": "\"Fix\"를 클릭한다면 AdGuard Home은 시스템이 AdGuard Home의 DNS 서버를 사용하도록 설정합니다.",
"autofix_warning_list": "다음 작업을 진행합니다: <0>DNSStubListener 시스템 비활성화</0> <0>DNS 서버 주소를 127.0.0.1로 설정</0> <0>/etc/resolv.conf의 심볼릭 링크 타겟을 /run/systemd/resolve/resolv.conf로 변경</0> <0>DNSStubListener 중지 (systemd-resolved 서비스 새로고침)</0>",
"autofix_warning_result": "결과적으로 시스템의 모든 DNS 요청은 기본적으로 AdGuard Home에 의해 처리됩니다.",

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).",
@@ -311,6 +311,7 @@
"install_devices_router": "Roteador",
"install_devices_router_desc": "Esta configuração cobrirá automaticamente todos os dispositivos conectados ao seu roteador doméstico e você não irá precisar configurar cada um deles manualmente.",
"install_devices_address": "O servidor de DNS do AdGuard Home está capturando os seguintes endereços",
"install_devices_router_list_1": "Abra as preferências do seu roteador. Normalmente, você pode acessá-lo de seu navegador por meio de um URL, como http://192.168.0.1/ ou http://192.168.1.1/. Você pode ser solicitado a inserir uma senha. Se você não se lembrar, muitas vezes você pode redefinir a senha pressionando um botão no próprio roteador, mas esteja ciente de que se esse procedimento for escolhido, você provavelmente perderá toda a configuração do roteador. Se o seu roteador requer um aplicativo para configurá-lo, instale o aplicativo no seu telefone ou PC e use-o para acessar as configurações do roteador.",
"install_devices_router_list_2": "Encontre as Configurações de DNS. Procure as letras DNS ao lado de um campo que permite dois ou três conjuntos de números, cada um dividido em quatro grupos de um a três números.",
"install_devices_router_list_3": "Digite aqui seu servidor do AdGuard Home.",
"install_devices_router_list_4": "Em alguns tipos de roteador, um servidor DNS personalizado não pode ser configurado. Nesse caso, configurar o AdGuard Home como um <0>Servidor DHCP</0> pode ajudar. Caso contrário, você deve verificar o manual do roteador sobre como personalizar os servidores DNS em seu modelo de roteador específico.",

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",
@@ -311,6 +311,7 @@
"install_devices_router": "Router",
"install_devices_router_desc": "Esta definição cobrirá automaticamente todos os dispositivos ligados ao seu router doméstico e não irá precisar de configurar cada um deles manualmente.",
"install_devices_address": "O servidor de DNS do AdGuard Home está a capturar os seguintes endereços",
"install_devices_router_list_1": "Abra as preferências do seu roteador. Normalmente, tu podes acessá-lo de teu navegador por meio de um URL, como http://192.168.0.1/ ou http://192.168.1.1/. Tu podes ser solicitado a inserir uma palavra-passe. Se tu não se lembrar, muitas vezes tu podes repor a palavra-passe pressionando um botão no próprio roteador, mas esteja ciente de que se esse procedimento for escolhido, tu provavelmente perderás toda a definição do roteador. Se o teu roteador requer uma aplicação para configurá-lo, instale a aplicação no seu telefone ou PC e use-o para acessar as definições do roteador.",
"install_devices_router_list_2": "Encontre as configurações de DNS. Procure as letras DNS ao lado de um campo que permite dois ou três conjuntos de números, cada um dividido em quatro grupos de um a três números.",
"install_devices_router_list_3": "Insira aqui seu servidor do AdGuard Home.",
"install_devices_router_list_4": "Em alguns tipos de roteador, um servidor DNS personalizado não pode ser configurado. Nesse caso, configurar o AdGuard Home como um <0>Servidor DHCP</0> pode ajudar. Caso contrário, tu deve verificar o manual do router sobre como personalizar os servidores DNS em seu modelo de router específico.",
@@ -358,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",
@@ -494,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",
@@ -522,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>",
@@ -559,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",
@@ -593,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

@@ -1,10 +1,20 @@
{
"client_settings": "用戶端設定",
"example_upstream_reserved": "您可以<0>指定網域</0>使用特定 DNS 查詢",
"example_upstream_comment": "您可以指定註解",
"upstream_parallel": "使用平行查詢,同時查詢所有上游伺服器來加速解析結果",
"parallel_requests": "平行處理",
"load_balancing": "負載平衡",
"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 伺服器已啟動",
"disabled_dhcp": "DHCP 伺服器已關閉",
"unavailable_dhcp": "DHCP 無法使用",
@@ -13,10 +23,12 @@
"dhcp_description": "如果你的路由器沒有提供 DHCP 設定,您可以使用 AdGuard 內建的 DHCP 伺服器。",
"dhcp_enable": "開啟 DHCP 伺服器",
"dhcp_disable": "關閉 DHCP 伺服器",
"dhcp_not_found": "您可以安全地啟用內建 DHCP 伺服器 - 在目前網路中沒有找到任何有效的 DHCP 伺服器。但我們依舊建議您手動再次檢查,因為目前我們的自動檢測並不能確定 100% 準確",
"dhcp_found": "在目前網段中有正在運作的 DHCP 伺服器,開啟內建 DHCP 伺服器是不安全的。",
"dhcp_leases": "DHCP 租用",
"dhcp_static_leases": "DHCP 靜態租用",
"dhcp_leases_not_found": "找不到 DHCP 租約",
"dhcp_config_saved": "DHCP 設定已儲存",
"dhcp_ipv4_settings": "DHCP IPv4 設定",
"dhcp_ipv6_settings": "DHCP IPv6 設定",
"form_error_required": "必要欄位",
@@ -26,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": "必須大於起始值",
@@ -42,11 +55,16 @@
"ip": "IP",
"dhcp_table_hostname": "主機名稱",
"dhcp_table_expires": "到期",
"dhcp_warning": "如果無論如何您都想要啟動 AdGuard 內建 DHCP 伺服器,請先確保同一網路下沒有正在運作的 DHCP 伺服器,否則很有可能會破壞其他已連線至網際網路的裝置。",
"dhcp_error": "無法偵測到同一網路下使否有其他 DHCP 伺服器。",
"dhcp_static_ip_error": "使用 DHCP 伺服器必須先指定靜態 IP 位置給 AdGuard。無法偵測到有效的靜態 IP 設定,請先手動設定。",
"dhcp_dynamic_ip_found": "您的網路介面 <0>{{interfaceName}}</0> 正在使用動態 IP要使用 DHCP 伺服器必須指定靜態 IP 給 AdGuard。\n目前您的 IP 位址 <0>{{ipAddress}}</0>,啟用 DHCP 後此 IP 將自動設定為靜態 IP 位址。",
"dhcp_lease_added": "靜態租用 \"{{key}}\" 已新增成功",
"dhcp_lease_deleted": "靜態租用 \"{{key}}\" 已刪除成功",
"dhcp_new_static_lease": "新增靜態租用",
"dhcp_static_leases_not_found": "找不到 DHCP 靜態租用",
"dhcp_add_static_lease": "新增靜態租用",
"dhcp_reset": "您確定要重設 DHCP 設定嗎?",
"country": "國家",
"city": "城市",
"delete_confirm": "您確定要刪除「{{key}}」嗎?",
@@ -93,7 +111,14 @@
"top_clients": "熱門用戶端排行",
"no_clients_found": "找不到用戶端",
"general_statistics": "一般統計資料",
"number_of_dns_query_days": "過去 {{count}} 天內 DNS 查詢總數",
"number_of_dns_query_days_plural": "過去 {{count}} 天內 DNS 查詢總數",
"number_of_dns_query_24_hours": "過去 24小時內 DNS 查詢總數",
"number_of_dns_query_blocked_24_hours": "已被廣告過濾器與主機黑名單封鎖 DNS 查詢總數",
"number_of_dns_query_blocked_24_hours_by_sec": "已被 AdGuard 瀏覽安全模組封鎖的 DNS 查詢總數",
"number_of_dns_query_blocked_24_hours_adult": "已封鎖成人網站總數",
"enforced_save_search": "強制使用安全搜尋",
"number_of_dns_query_to_safe_search": "已強制使用安全搜尋總數",
"average_processing_time": "平均的處理時間",
"average_processing_time_hint": "處理 DNS 請求的平均時間(毫秒)",
"block_domain_use_filters_and_hosts": "使用過濾器與 hosts 檔案阻擋網域查詢",
@@ -103,6 +128,7 @@
"use_adguard_parental": "使用 AdGuard 家長監護功能",
"use_adguard_parental_hint": "AdGuard Home 將比對查詢網域是否含有成人內容。它使用與 AdGuard 瀏覽安全一樣的尊重個人隱私的 API 來進行檢查。",
"enforce_safe_search": "強制使用安全搜尋",
"enforce_save_search_hint": "AdGuard Home 可在下列搜尋引擎使用強制安全搜尋Google、YouTube、Bing、DuckDuckGo 和 Yandex。",
"no_servers_specified": "沒有指定的伺服器",
"general_settings": "一般設定",
"dns_settings": "DNS 設定",
@@ -114,6 +140,7 @@
"encryption_settings": "加密設定",
"dhcp_settings": "DHCP 設定",
"upstream_dns": "上游 DNS 伺服器",
"upstream_dns_help": "每行輸入一個伺服器位址。<a>了解更多</a>有關設定上游 DNS 伺服器的內容",
"upstream_dns_configured_in_file": "設定在 {{path}}",
"test_upstream_btn": "測試上游 DNS",
"upstreams": "上游",
@@ -242,6 +269,7 @@
"rate_limit": "速率限制",
"edns_enable": "啟用 EDNS Client Subnet",
"edns_cs_desc": "開啟後 AdGuard Home 將會傳送用戶端的子網路給 DNS 伺服器。",
"rate_limit_desc": "限制單一裝置每秒發出的查詢次數(設定為 0 即表示無限制)",
"blocking_ipv4_desc": "回覆指定 IPv4 位址給被封鎖的網域的 A 紀錄查詢",
"blocking_ipv6_desc": "回覆指定 IPv6 位址給被封鎖的網域的 AAAA 紀錄查詢",
"blocking_mode_default": "預設:被 Adblock 規則封鎖時回應零值的 IP 位址A 紀錄回應 0.0.0.0 AAAA 紀錄回應 ::);被 /etc/hosts 規則封鎖時回應規則中指定 IP 位址",
@@ -254,6 +282,7 @@
"source_label": "來源",
"found_in_known_domain_db": "在已知網域資料庫中找到。",
"category_label": "類別",
"rule_label": "規則",
"list_label": "清單",
"unknown_filter": "未知過濾器 {{filterId}}",
"known_tracker": "已知追蹤器",
@@ -263,6 +292,7 @@
"install_settings_listen": "監聽介面",
"install_settings_port": "連接埠",
"install_settings_interface_link": "您可以從以下 IP 位址來訪問 AdGuard Home 管理介面:",
"form_error_port": "輸入有效的連接埠",
"install_settings_dns": "DNS 伺服器",
"install_settings_dns_desc": "您需要將您的裝置或路由器設定以下的 IP 位址為 DNS 伺服器:",
"install_settings_all_interfaces": "所有介面",
@@ -281,8 +311,10 @@
"install_devices_router": "路由器",
"install_devices_router_desc": "使用此設定後,所有連接家中路由器的裝置都會自動套用,無須在每台裝置上個別設定。",
"install_devices_address": "AdGuard Home DNS 伺服器正在監聽以下位址",
"install_devices_router_list_1": "開啟您的路由器設定。通常可透過瀏覽器開啟http://192.168.0.1/ 或 http://192.168.1.1)。接著您可能會被要求驗證登入,如果忘記密碼可以按壓路由器的 REST 重設按鈕來重設。部分路由器可能需要安裝特定應用程式,在這種情況下應該已經安裝在您的電腦或手機上。",
"install_devices_router_list_2": "找到 DHCP/DNS 設定。允許兩到三組數字的欄位旁邊尋找 DNS 字串,每組數字分為四組,每組一到三位數。",
"install_devices_router_list_3": "請在那邊輸入您的 AdGuard Home 伺服器位址。",
"install_devices_router_list_4": "您無法於某些類型的路由器上設定自訂的 DNS 伺服器。在這種情況下,如果您設置 AdGuard Home 作為 <0>DHCP</0> 伺服器,其可能有所幫助。否則,您應搜尋有關如何為您的特定路由器型號自訂 DNS 伺服器之用法說明。",
"install_devices_windows_list_1": "在「開始列」或「Windows 搜尋」開啟控制台。",
"install_devices_windows_list_2": "點擊「網路和網際網路」,接著點選「網路和共用中心」。",
"install_devices_windows_list_3": "在畫面左側點擊「變更介面卡設定」。",
@@ -308,8 +340,10 @@
"install_saved": "成功儲存",
"encryption_title": "加密",
"encryption_desc": "加密HTTPS/TLS提供給 DNS 和「管理介面網頁介面」兩者",
"encryption_config_saved": "加密設定已儲存",
"encryption_server": "伺服器名稱",
"encryption_server_enter": "輸入您的網域名稱",
"encryption_server_desc": "要使用 HTTPS您必須輸入與您 SSL 憑證相符的伺服器名稱。",
"encryption_redirect": "自動重新導向到 HTTPS",
"encryption_redirect_desc": "如果啟用AdGuard Home 將會自動導向 HTTP 到 HTTPS。",
"encryption_https": "HTTPS 連接埠",
@@ -337,10 +371,13 @@
"encryption_reset": "您確定要重設加密設定嗎?",
"topline_expiring_certificate": "您的 SSL 憑證即將到期。請前往<0>加密設定</0>更新。",
"topline_expired_certificate": "您的 SSL 憑證已到期。請前往<0>加密設定</0>更新。",
"form_error_port_range": "輸入範圍 80-65535 中的值",
"form_error_port_unsafe": "這個連接埠不安全",
"form_error_equal": "不可相同",
"form_error_password": "密碼不相符",
"reset_settings": "重設設定",
"update_announcement": "有新版的 AdGuard Home {{version}} 可供更新!詳細資訊請<0>點擊這裡</0>。",
"setup_guide": "安裝導覽",
"dns_addresses": "DNS 位址",
"dns_start": "DNS 伺服器正在啟動",
"dns_status_error": "檢查 DNS 伺服器狀態錯誤",
@@ -362,7 +399,9 @@
"client_edit": "編輯用戶端",
"client_identifier": "識別碼",
"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": "新增識別碼",
@@ -384,6 +423,7 @@
"access_disallowed_title": "用戶端黑名單",
"access_disallowed_desc": "輸入 CIDR 或 IP 位址格式的清單,設定後 AdGuard Home 將拒絕設定的 IP 位址查詢請求。",
"access_blocked_title": "網域黑名單",
"access_blocked_desc": "請不要與過濾器搞混AdGuard Home 將對這些網域執行過濾檢查後丟棄 DNS 請求。您可以輸入特定網域名稱來使用設定或使用萬用字元例如「example.org」、「*.example.org」或「||example.org^」。",
"access_settings_saved": "存取設定已儲存",
"updates_checked": "檢查更新成功",
"updates_version_equal": "AdGuard Home 是最新的版本",
@@ -486,6 +526,7 @@
"disable_ipv6": "停用 IPv6",
"disable_ipv6_desc": "開啟此功能後,將捨棄所有對 IPv6 位址AAAA的查詢。",
"fastest_addr": "Fastest IP 位址",
"fastest_addr_desc": "從所有 DNS 伺服器查詢中回應最快的 IP 位址。但這操作會等待所有 DNS 查詢結果後才能回應,導致速度有所降低,不過同時卻也改善了整體連線品質。",
"autofix_warning_text": "如果您點擊「修復」AdGuard Home 將更改您的系統 DNS 設定更改為 AdGuard Home DNS 伺服器",
"autofix_warning_list": "它將執行這些任務:<0>停用系統 DNSStubListener</0> <0>將 DNS 設定為 127.0.0.1</0> <0>更換軟連結將 /etc/resolv.conf 為 /run/systemd/resolve/resolv.conf</0> <0>停止 DNSStubListener重新載入 systemd-resolved</0>",
"autofix_warning_result": "就結論來說 DNS 請求預設由本機的 AdGuard Home 處理。",
@@ -515,6 +556,7 @@
"set_static_ip": "設定一組靜態 IP 位址",
"install_static_ok": "好消息!靜態 IP 位址設定完成了",
"install_static_error": "AdGuard Home 無法在這個網路介面上執行自動設定。請尋找有關如何手動更改設定的說明。",
"install_static_configure": "我們偵測到 <0>{{ip}}</0> 動態 IP 已被使用。您想要將它當作靜態 IP 使用嗎?",
"confirm_static_ip": "AdGuard Home 將使用 {{ip}} 作為靜態 IP。要繼續處理",
"list_updated": "已更新 {{count}} 個清單",
"list_updated_plural": "已更新 {{count}} 個清單",
@@ -552,6 +594,7 @@
"filter_category_security_desc": "針對惡意軟體、網路釣魚或詐騙網域的封鎖清單",
"filter_category_regional_desc": "針對地區性廣告與追蹤器伺服器的封鎖清單",
"filter_category_other_desc": "其他封鎖清單",
"setup_config_to_enable_dhcp_server": "建立設定檔來使用 DHCP 伺服器",
"original_response": "原始回應",
"click_to_view_queries": "按一下以檢視查詢結果",
"port_53_faq_link": "連接埠 53 經常被「DNSStubListener」或「systemd-resolved」服務佔用。請閱讀下列有關解決<0>這個問題</0>的說明",

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]}
/>

8
go.mod
View File

@@ -3,9 +3,9 @@ module github.com/AdguardTeam/AdGuardHome
go 1.15
require (
github.com/AdguardTeam/dnsproxy v0.37.1
github.com/AdguardTeam/golibs v0.4.5
github.com/AdguardTeam/urlfilter v0.14.4
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
github.com/digineo/go-ipset/v2 v2.2.1
@@ -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

16
go.sum
View File

@@ -18,18 +18,18 @@ 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.1 h1:vULyF1+xSI7vV99m8GD2hmOuCQrpu87awyeSe5qtFbA=
github.com/AdguardTeam/dnsproxy v0.37.1/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.4 h1:lrS7lrfxVCFh4TFB6nwPp5UE4n1XNvv3zUetduD9mZw=
github.com/AdguardTeam/urlfilter v0.14.4/go.mod h1:klx4JbOfc4EaNb5lWLqOwfg+pVcyRukmoJRvO55lL5U=
github.com/AdguardTeam/urlfilter v0.14.5 h1:WyF0hg0MwKevsqNPkoaZFH8f5WRi/yuy/7qePtYt5Ts=
github.com/AdguardTeam/urlfilter v0.14.5/go.mod h1:klx4JbOfc4EaNb5lWLqOwfg+pVcyRukmoJRvO55lL5U=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=

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{
@@ -427,7 +425,7 @@ func (s *Server) Prepare(config *ServerConfig) error {
//
// TODO(a.garipov): The Snap problem can probably be solved if
// we add the netlink-connector interface plug.
log.Error("cannot initialize ipset: %s", err)
log.Info("warning: cannot initialize ipset: %s", err)
}
// Prepare DNS servers settings

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

@@ -8,6 +8,7 @@ import (
"fmt"
"net"
"net/http"
"strconv"
"strings"
"sync"
"time"
@@ -62,6 +63,7 @@ func (s *session) deserialize(data []byte) bool {
// Auth - global object
type Auth struct {
db *bbolt.DB
blocker *authRateLimiter
sessions map[string]*session
users []User
lock sync.Mutex
@@ -75,12 +77,15 @@ type User struct {
}
// InitAuth - create a global object
func InitAuth(dbFilename string, users []User, sessionTTL uint32) *Auth {
func InitAuth(dbFilename string, users []User, sessionTTL uint32, blocker *authRateLimiter) *Auth {
log.Info("Initializing auth module: %s", dbFilename)
a := Auth{}
a.sessionTTL = sessionTTL
a.sessions = make(map[string]*session)
a := &Auth{
sessionTTL: sessionTTL,
blocker: blocker,
sessions: make(map[string]*session),
users: users,
}
var err error
a.db, err = bbolt.Open(dbFilename, 0o644, nil)
if err != nil {
@@ -92,10 +97,9 @@ func InitAuth(dbFilename string, users []User, sessionTTL uint32) *Auth {
return nil
}
a.loadSessions()
a.users = users
log.Info("auth: initialized. users:%d sessions:%d", len(a.users), len(a.sessions))
return &a
return a
}
// Close - close module
@@ -330,13 +334,23 @@ func cookieExpiryFormat(exp time.Time) (formatted string) {
return exp.Format(cookieTimeFormat)
}
func (a *Auth) httpCookie(req loginJSON) (string, error) {
func (a *Auth) httpCookie(req loginJSON, addr string) (cookie string, err error) {
blocker := a.blocker
u := a.UserFind(req.Name, req.Password)
if len(u.Name) == 0 {
return "", nil
if blocker != nil {
blocker.inc(addr)
}
return "", err
}
sess, err := newSessionToken()
if blocker != nil {
blocker.remove(addr)
}
var sess []byte
sess, err = newSessionToken()
if err != nil {
return "", err
}
@@ -404,10 +418,38 @@ func handleLogin(w http.ResponseWriter, r *http.Request) {
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
httpError(w, http.StatusBadRequest, "json decode: %s", err)
return
}
cookie, err := Context.auth.httpCookie(req)
var remoteAddr string
// The realIP couldn't be used here due to security issues.
//
// See https://github.com/AdguardTeam/AdGuardHome/issues/2799.
//
// TODO(e.burkov): Use realIP when the issue will be fixed.
if remoteAddr, err = aghnet.SplitHost(r.RemoteAddr); err != nil {
httpError(w, http.StatusBadRequest, "auth: getting remote address: %s", err)
return
}
if blocker := Context.auth.blocker; blocker != nil {
if left := blocker.check(remoteAddr); left > 0 {
w.Header().Set("Retry-After", strconv.Itoa(int(left.Seconds())))
httpError(
w,
http.StatusTooManyRequests,
"auth: blocked for %s",
left,
)
return
}
}
var cookie string
cookie, err = Context.auth.httpCookie(req, remoteAddr)
if err != nil {
httpError(w, http.StatusBadRequest, "crypto rand reader: %s", err)
@@ -425,7 +467,6 @@ func handleLogin(w http.ResponseWriter, r *http.Request) {
} else {
log.Info("auth: failed to login user %q from ip %q", req.Name, ip)
}
time.Sleep(1 * time.Second)
http.Error(w, "invalid username or password", http.StatusBadRequest)

View File

@@ -8,7 +8,6 @@ import (
"net/http"
"net/textproto"
"net/url"
"os"
"path/filepath"
"testing"
"time"
@@ -22,21 +21,6 @@ func TestMain(m *testing.M) {
aghtest.DiscardLogOutput(m)
}
func prepareTestDir(t *testing.T) string {
t.Helper()
const dir = "./agh-test"
require.Nil(t, os.RemoveAll(dir))
// TODO(e.burkov): Replace with testing.TempDir after updating Go
// version to 1.16.
require.Nil(t, os.MkdirAll(dir, 0o755))
t.Cleanup(func() { require.Nil(t, os.RemoveAll(dir)) })
return dir
}
func TestNewSessionToken(t *testing.T) {
// Successful case.
token, err := newSessionToken()
@@ -57,14 +41,14 @@ func TestNewSessionToken(t *testing.T) {
}
func TestAuth(t *testing.T) {
dir := prepareTestDir(t)
dir := t.TempDir()
fn := filepath.Join(dir, "sessions.db")
users := []User{{
Name: "name",
PasswordHash: "$2y$05$..vyzAECIhJPfaQiOK17IukcQnqEgKJHy0iETyYqxn3YXJl8yZuo2",
}}
a := InitAuth(fn, nil, 60)
a := InitAuth(fn, nil, 60, nil)
s := session{}
user := User{Name: "name"}
@@ -92,7 +76,7 @@ func TestAuth(t *testing.T) {
a.Close()
// load saved session
a = InitAuth(fn, users, 60)
a = InitAuth(fn, users, 60, nil)
// the session is still alive
assert.Equal(t, checkSessionOK, a.checkSession(sessStr))
@@ -107,7 +91,7 @@ func TestAuth(t *testing.T) {
time.Sleep(3 * time.Second)
// load and remove expired sessions
a = InitAuth(fn, users, 60)
a = InitAuth(fn, users, 60, nil)
assert.Equal(t, checkSessionNotFound, a.checkSession(sessStr))
a.Close()
@@ -132,13 +116,13 @@ func (w *testResponseWriter) WriteHeader(statusCode int) {
}
func TestAuthHTTP(t *testing.T) {
dir := prepareTestDir(t)
dir := t.TempDir()
fn := filepath.Join(dir, "sessions.db")
users := []User{
{Name: "name", PasswordHash: "$2y$05$..vyzAECIhJPfaQiOK17IukcQnqEgKJHy0iETyYqxn3YXJl8yZuo2"},
}
Context.auth = InitAuth(fn, users, 60)
Context.auth = InitAuth(fn, users, 60, nil)
handlerCalled := false
handler := func(_ http.ResponseWriter, _ *http.Request) {
@@ -167,7 +151,7 @@ func TestAuthHTTP(t *testing.T) {
assert.True(t, handlerCalled)
// perform login
cookie, err := Context.auth.httpCookie(loginJSON{Name: "name", Password: "password"})
cookie, err := Context.auth.httpCookie(loginJSON{Name: "name", Password: "password"}, "")
assert.Nil(t, err)
assert.NotEmpty(t, cookie)

View File

@@ -12,7 +12,7 @@ import (
)
func TestAuthGL(t *testing.T) {
dir := prepareTestDir(t)
dir := t.TempDir()
GLMode = true
t.Cleanup(func() {

View File

@@ -0,0 +1,109 @@
package home
import (
"sync"
"time"
)
// failedAuthTTL is the period of time for which the failed attempt will stay in
// cache.
const failedAuthTTL = 1 * time.Minute
// failedAuth is an entry of authRateLimiter's cache.
type failedAuth struct {
until time.Time
num uint
}
// authRateLimiter used to cache failed authentication attempts.
type authRateLimiter struct {
failedAuths map[string]failedAuth
// failedAuthsLock protects failedAuths.
failedAuthsLock sync.Mutex
blockDur time.Duration
maxAttempts uint
}
// newAuthRateLimiter returns properly initialized *authRateLimiter.
func newAuthRateLimiter(blockDur time.Duration, maxAttempts uint) (ab *authRateLimiter) {
return &authRateLimiter{
failedAuths: make(map[string]failedAuth),
blockDur: blockDur,
maxAttempts: maxAttempts,
}
}
// cleanupLocked checks each blocked users removing ones with expired TTL. For
// internal use only.
func (ab *authRateLimiter) cleanupLocked(now time.Time) {
for k, v := range ab.failedAuths {
if now.After(v.until) {
delete(ab.failedAuths, k)
}
}
}
// checkLocked checks the attempter for it's state. For internal use only.
func (ab *authRateLimiter) checkLocked(usrID string, now time.Time) (left time.Duration) {
a, ok := ab.failedAuths[usrID]
if !ok {
return 0
}
if a.num < ab.maxAttempts {
return 0
}
return a.until.Sub(now)
}
// check returns the time left until unblocking. The nonpositive result should
// be interpreted as not blocked attempter.
func (ab *authRateLimiter) check(usrID string) (left time.Duration) {
now := time.Now()
ab.failedAuthsLock.Lock()
defer ab.failedAuthsLock.Unlock()
ab.cleanupLocked(now)
return ab.checkLocked(usrID, now)
}
// incLocked increments the number of unsuccessful attempts for attempter with
// ip and updates it's blocking moment if needed. For internal use only.
func (ab *authRateLimiter) incLocked(usrID string, now time.Time) {
var until time.Time = now.Add(failedAuthTTL)
var attNum uint = 1
a, ok := ab.failedAuths[usrID]
if ok {
until = a.until
attNum = a.num + 1
}
if attNum >= ab.maxAttempts {
until = now.Add(ab.blockDur)
}
ab.failedAuths[usrID] = failedAuth{
num: attNum,
until: until,
}
}
// inc updates the failed attempt in cache.
func (ab *authRateLimiter) inc(usrID string) {
now := time.Now()
ab.failedAuthsLock.Lock()
defer ab.failedAuthsLock.Unlock()
ab.incLocked(usrID, now)
}
// remove stops any tracking and any blocking of the user.
func (ab *authRateLimiter) remove(usrID string) {
ab.failedAuthsLock.Lock()
defer ab.failedAuthsLock.Unlock()
delete(ab.failedAuths, usrID)
}

View File

@@ -0,0 +1,207 @@
package home
import (
"net"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAuthRateLimiter_Cleanup(t *testing.T) {
const key = "some-key"
now := time.Now()
testCases := []struct {
name string
att failedAuth
wantExp bool
}{{
name: "expired",
att: failedAuth{
until: now.Add(-100 * time.Hour),
},
wantExp: true,
}, {
name: "nope_yet",
att: failedAuth{
until: now.Add(failedAuthTTL / 2),
},
wantExp: false,
}, {
name: "blocked",
att: failedAuth{
until: now.Add(100 * time.Hour),
},
wantExp: false,
}}
for _, tc := range testCases {
ab := &authRateLimiter{
failedAuths: map[string]failedAuth{
key: tc.att,
},
}
t.Run(tc.name, func(t *testing.T) {
ab.cleanupLocked(now)
if tc.wantExp {
assert.Empty(t, ab.failedAuths)
return
}
require.Len(t, ab.failedAuths, 1)
_, ok := ab.failedAuths[key]
require.True(t, ok)
})
}
}
func TestAuthRateLimiter_Check(t *testing.T) {
key := string(net.IP{127, 0, 0, 1})
const maxAtt = 1
now := time.Now()
testCases := []struct {
until time.Time
name string
num uint
wantExp bool
}{{
until: now.Add(-100 * time.Hour),
name: "expired",
num: 0,
wantExp: true,
}, {
until: now.Add(failedAuthTTL),
name: "not_blocked_but_tracked",
num: 0,
wantExp: true,
}, {
until: now,
name: "expired_but_stayed",
num: 2,
wantExp: true,
}, {
until: now.Add(100 * time.Hour),
name: "blocked",
num: 2,
wantExp: false,
}}
for _, tc := range testCases {
failedAuths := map[string]failedAuth{
key: {
num: tc.num,
until: tc.until,
},
}
ab := &authRateLimiter{
maxAttempts: maxAtt,
failedAuths: failedAuths,
}
t.Run(tc.name, func(t *testing.T) {
until := ab.check(key)
if tc.wantExp {
assert.LessOrEqual(t, until, time.Duration(0))
} else {
assert.Greater(t, until, time.Duration(0))
}
})
}
t.Run("non-existent", func(t *testing.T) {
ab := &authRateLimiter{
failedAuths: map[string]failedAuth{
key + "smthng": {},
},
}
until := ab.check(key)
assert.Zero(t, until)
})
}
func TestAuthRateLimiter_Inc(t *testing.T) {
ip := net.IP{127, 0, 0, 1}
key := string(ip)
now := time.Now()
const maxAtt = 2
const blockDur = 15 * time.Minute
testCases := []struct {
until time.Time
wantUntil time.Time
name string
num uint
wantNum uint
}{{
name: "only_inc",
until: now,
wantUntil: now,
num: maxAtt - 1,
wantNum: maxAtt,
}, {
name: "inc_and_block",
until: now,
wantUntil: now.Add(failedAuthTTL),
num: maxAtt,
wantNum: maxAtt + 1,
}}
for _, tc := range testCases {
failedAuths := map[string]failedAuth{
key: {
num: tc.num,
until: tc.until,
},
}
ab := &authRateLimiter{
blockDur: blockDur,
maxAttempts: maxAtt,
failedAuths: failedAuths,
}
t.Run(tc.name, func(t *testing.T) {
ab.inc(key)
a, ok := ab.failedAuths[key]
require.True(t, ok)
assert.Equal(t, tc.wantNum, a.num)
assert.LessOrEqual(t, tc.wantUntil.Unix(), a.until.Unix())
})
}
t.Run("non-existent", func(t *testing.T) {
ab := &authRateLimiter{
blockDur: blockDur,
maxAttempts: maxAtt,
failedAuths: map[string]failedAuth{},
}
ab.inc(key)
a, ok := ab.failedAuths[key]
require.True(t, ok)
assert.EqualValues(t, 1, a.num)
})
}
func TestAuthRateLimiter_Remove(t *testing.T) {
const key = "some-key"
failedAuths := map[string]failedAuth{
key: {},
}
ab := &authRateLimiter{
failedAuths: failedAuths,
}
ab.remove(key)
assert.Empty(t, ab.failedAuths)
}

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

@@ -47,10 +47,16 @@ type configuration struct {
BindPort int `yaml:"bind_port"` // BindPort is the port the HTTP server
BetaBindPort int `yaml:"beta_bind_port"` // BetaBindPort is the port for new client
Users []User `yaml:"users"` // Users that can access HTTP server
ProxyURL string `yaml:"http_proxy"` // Proxy address for our HTTP client
Language string `yaml:"language"` // two-letter ISO 639-1 language code
RlimitNoFile uint `yaml:"rlimit_nofile"` // Maximum number of opened fd's per process (0: default)
DebugPProf bool `yaml:"debug_pprof"` // Enable pprof HTTP server on port 6060
// AuthAttempts is the maximum number of failed login attempts a user
// can do before being blocked.
AuthAttempts uint `yaml:"auth_attempts"`
// AuthBlockMin is the duration, in minutes, of the block of new login
// attempts after AuthAttempts unsuccessful login attempts.
AuthBlockMin uint `yaml:"block_auth_min"`
ProxyURL string `yaml:"http_proxy"` // Proxy address for our HTTP client
Language string `yaml:"language"` // two-letter ISO 639-1 language code
RlimitNoFile uint `yaml:"rlimit_nofile"` // Maximum number of opened fd's per process (0: default)
DebugPProf bool `yaml:"debug_pprof"` // Enable pprof HTTP server on port 6060
// TTL for a web session (in hours)
// An active session is automatically refreshed once a day.
@@ -137,6 +143,8 @@ var config = configuration{
BindPort: 3000,
BetaBindPort: 0,
BindHost: net.IP{0, 0, 0, 0},
AuthAttempts: 5,
AuthBlockMin: 15,
DNS: dnsConfig{
BindHosts: []net.IP{{0, 0, 0, 0}},
Port: 53,

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

@@ -43,7 +43,7 @@ func testStartFilterListener(t *testing.T) net.Listener {
func TestFilters(t *testing.T) {
l := testStartFilterListener(t)
dir := prepareTestDir(t)
dir := t.TempDir()
Context = homeContext{
workDir: dir,

View File

@@ -30,7 +30,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
"github.com/AdguardTeam/AdGuardHome/internal/stats"
"github.com/AdguardTeam/AdGuardHome/internal/updater"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/AdGuardHome/internal/version"
"github.com/AdguardTeam/golibs/log"
"gopkg.in/natefinch/lumberjack.v2"
@@ -139,8 +138,8 @@ func setupContext(args options) {
initConfig()
Context.tlsRoots = util.LoadSystemRootCAs()
Context.tlsCiphers = util.InitTLSCiphers()
Context.tlsRoots = LoadSystemRootCAs()
Context.tlsCiphers = InitTLSCiphers()
Context.transport = &http.Transport{
DialContext: customDialContext,
Proxy: getHTTPProxy,
@@ -185,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")
}
@@ -283,7 +286,21 @@ func run(args options) {
sessFilename := filepath.Join(Context.getDataDir(), "sessions.db")
GLMode = args.glinetMode
Context.auth = InitAuth(sessFilename, config.Users, config.WebSessionTTLHours*60*60)
var arl *authRateLimiter
if config.AuthAttempts > 0 && config.AuthBlockMin > 0 {
arl = newAuthRateLimiter(
time.Duration(config.AuthBlockMin)*time.Minute,
config.AuthAttempts,
)
} else {
log.Info("authratelimiter is disabled")
}
Context.auth = InitAuth(
sessFilename,
config.Users,
config.WebSessionTTLHours*60*60,
arl,
)
if Context.auth == nil {
log.Fatalf("Couldn't initialize Auth module")
}
@@ -476,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
@@ -641,7 +662,9 @@ func detectFirstRun() bool {
return errors.Is(err, os.ErrNotExist)
}
// Connect to a remote server resolving hostname using our own DNS server
// Connect to a remote server resolving hostname using our own DNS server.
//
// TODO(e.burkov): This messy logic should be decomposed and clarified.
func customDialContext(ctx context.Context, network, addr string) (conn net.Conn, err error) {
log.Tracef("network:%v addr:%v", network, addr)

View File

@@ -114,7 +114,7 @@ func TestHome(t *testing.T) {
// Init new context
Context = homeContext{}
dir := prepareTestDir(t)
dir := t.TempDir()
fn := filepath.Join(dir, "AdGuardHome.yaml")
// Prepare the test config

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

@@ -15,12 +15,15 @@ import (
"io/ioutil"
"net/http"
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"sync"
"time"
"github.com/AdguardTeam/golibs/log"
"golang.org/x/sys/cpu"
)
var tlsWebHandlersRegistered = false
@@ -551,3 +554,96 @@ func (t *TLSMod) registerWebHandlers() {
httpRegister(http.MethodPost, "/control/tls/configure", t.handleTLSConfigure)
httpRegister(http.MethodPost, "/control/tls/validate", t.handleTLSValidate)
}
// LoadSystemRootCAs tries to load root certificates from the operating system.
// It returns nil in case nothing is found so that that Go.crypto will use it's
// default algorithm to find system root CA list.
//
// See https://github.com/AdguardTeam/AdGuardHome/internal/issues/1311.
func LoadSystemRootCAs() (roots *x509.CertPool) {
// TODO(e.burkov): Use build tags instead.
if runtime.GOOS != "linux" {
return nil
}
// Directories with the system root certificates, which aren't supported
// by Go.crypto.
dirs := []string{
// Entware.
"/opt/etc/ssl/certs",
}
roots = x509.NewCertPool()
for _, dir := range dirs {
fis, err := ioutil.ReadDir(dir)
if errors.Is(err, os.ErrNotExist) {
continue
}
if err != nil {
log.Error("opening directory: %q: %s", dir, err)
}
var rootsAdded bool
for _, fi := range fis {
var certData []byte
certData, err = ioutil.ReadFile(filepath.Join(dir, fi.Name()))
if err == nil && roots.AppendCertsFromPEM(certData) {
rootsAdded = true
}
}
if rootsAdded {
return roots
}
}
return nil
}
// InitTLSCiphers performs the same work as initDefaultCipherSuites() from
// crypto/tls/common.go but don't uses lots of other default ciphers.
func InitTLSCiphers() (ciphers []uint16) {
// Check the cpu flags for each platform that has optimized GCM
// implementations. The worst case is when all these variables are
// false.
var (
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
// Keep in sync with crypto/aes/cipher_s390x.go.
hasGCMAsmS390X = cpu.S390X.HasAES &&
cpu.S390X.HasAESCBC &&
cpu.S390X.HasAESCTR &&
(cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
hasGCMAsm = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X
)
if hasGCMAsm {
// If AES-GCM hardware is provided then prioritize AES-GCM
// cipher suites.
ciphers = []uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
}
} else {
// Without AES-GCM hardware, we put the ChaCha20-Poly1305 cipher
// suites first.
ciphers = []uint16{
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
}
}
return append(
ciphers,
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
)
}

View File

@@ -27,6 +27,10 @@ type Whois struct {
clients *clientsContainer
ipChan chan net.IP
// dialContext specifies the dial function for creating unencrypted TCP
// connections.
dialContext func(ctx context.Context, network, addr string) (conn net.Conn, err error)
// Contains IP addresses of clients
// An active IP address is resolved once again after it expires.
// If IP address couldn't be resolved, it stays here for some time to prevent further attempts to resolve the same IP.
@@ -45,7 +49,8 @@ func initWhois(clients *clientsContainer) *Whois {
EnableLRU: true,
MaxCount: 10000,
}),
ipChan: make(chan net.IP, 255),
dialContext: customDialContext,
ipChan: make(chan net.IP, 255),
}
go w.workerLoop()
@@ -124,7 +129,7 @@ func (w *Whois) query(ctx context.Context, target, serverAddr string) (string, e
if addr == "whois.arin.net" {
target = "n + " + target
}
conn, err := customDialContext(ctx, "tcp", serverAddr)
conn, err := w.dialContext(ctx, "tcp", serverAddr)
if err != nil {
return "", err
}

View File

@@ -2,44 +2,77 @@ package home
import (
"context"
"io"
"net"
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func prepareTestDNSServer(t *testing.T) {
t.Helper()
config.DNS.Port = 1234
var err error
Context.dnsServer, err = dnsforward.NewServer(dnsforward.DNSCreateParams{})
require.NoError(t, err)
conf := &dnsforward.ServerConfig{}
conf.UpstreamDNS = []string{"8.8.8.8"}
err = Context.dnsServer.Prepare(conf)
require.NoError(t, err)
// fakeConn is a mock implementation of net.Conn to simplify testing.
//
// TODO(e.burkov): Search for other places in code where it may be used. Move
// into aghtest then.
type fakeConn struct {
// Conn is embedded here simply to make *fakeConn a net.Conn without
// actually implementing all methods.
net.Conn
data []byte
}
// TODO(e.burkov): It's kind of complicated to get rid of network access in this
// test. The thing is that *Whois creates new *net.Dialer each time it requests
// the server, so it becomes hard to simulate handling of request from test even
// with substituted upstream. However, it must be done.
func TestWhois(t *testing.T) {
prepareTestDNSServer(t)
// Write implements net.Conn interface for *fakeConn. It always returns 0 and a
// nil error without mutating the slice.
func (c *fakeConn) Write(_ []byte) (n int, err error) {
return 0, nil
}
w := Whois{timeoutMsec: 5000}
resp, err := w.queryAll(context.Background(), "8.8.8.8")
// Read implements net.Conn interface for *fakeConn. It puts the content of
// c.data field into b up to the b's capacity.
func (c *fakeConn) Read(b []byte) (n int, err error) {
return copy(b, c.data), io.EOF
}
// Close implements net.Conn interface for *fakeConn. It always returns nil.
func (c *fakeConn) Close() (err error) {
return nil
}
// SetReadDeadline implements net.Conn interface for *fakeConn. It always
// returns nil.
func (c *fakeConn) SetReadDeadline(_ time.Time) (err error) {
return nil
}
// fakeDial is a mock implementation of customDialContext to simplify testing.
func (c *fakeConn) fakeDial(ctx context.Context, network, addr string) (conn net.Conn, err error) {
return c, nil
}
func TestWhois(t *testing.T) {
const (
nl = "\n"
data = `OrgName: FakeOrg LLC` + nl +
`City: Nonreal` + nl +
`Country: Imagiland` + nl
)
fc := &fakeConn{
data: []byte(data),
}
w := Whois{
timeoutMsec: 5000,
dialContext: fc.fakeDial,
}
resp, err := w.queryAll(context.Background(), "1.2.3.4")
assert.NoError(t, err)
m := whoisParse(resp)
require.NotEmpty(t, m)
assert.Equal(t, "Google LLC", m["orgname"])
assert.Equal(t, "US", m["country"])
assert.Equal(t, "Mountain View", m["city"])
assert.Equal(t, "FakeOrg LLC", m["orgname"])
assert.Equal(t, "Imagiland", m["country"])
assert.Equal(t, "Nonreal", m["city"])
}

View File

@@ -1,107 +0,0 @@
// Package util contains various utilities.
//
// TODO(a.garipov): Such packages are widely considered an antipattern. Remove
// this when we refactor our project structure.
package util
import (
"crypto/tls"
"crypto/x509"
"errors"
"io/ioutil"
"os"
"runtime"
"github.com/AdguardTeam/golibs/log"
"golang.org/x/sys/cpu"
)
// LoadSystemRootCAs - load root CAs from the system
// Return the x509 certificate pool object
// Return nil if nothing has been found.
// This means that Go.crypto will use its default algorithm to find system root CA list.
// https://github.com/AdguardTeam/AdGuardHome/internal/issues/1311
func LoadSystemRootCAs() *x509.CertPool {
if runtime.GOOS != "linux" {
return nil
}
// Directories with the system root certificates, that aren't supported by Go.crypto
dirs := []string{
"/opt/etc/ssl/certs", // Entware
}
roots := x509.NewCertPool()
for _, dir := range dirs {
fis, err := ioutil.ReadDir(dir)
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
log.Error("opening directory: %q: %s", dir, err)
}
continue
}
rootsAdded := false
for _, fi := range fis {
var certData []byte
certData, err = ioutil.ReadFile(dir + "/" + fi.Name())
if err == nil && roots.AppendCertsFromPEM(certData) {
rootsAdded = true
}
}
if rootsAdded {
return roots
}
}
return nil
}
// InitTLSCiphers - the same as initDefaultCipherSuites() from src/crypto/tls/common.go
// but with the difference that we don't use so many other default ciphers.
func InitTLSCiphers() []uint16 {
var ciphers []uint16
// Check the cpu flags for each platform that has optimized GCM implementations.
// Worst case, these variables will just all be false.
var (
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
// Keep in sync with crypto/aes/cipher_s390x.go.
hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
hasGCMAsm = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X
)
if hasGCMAsm {
// If AES-GCM hardware is provided then prioritise AES-GCM
// cipher suites.
ciphers = []uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
}
} else {
// Without AES-GCM hardware, we put the ChaCha20-Poly1305
// cipher suites first.
ciphers = []uint16{
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
}
}
otherCiphers := []uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
}
ciphers = append(ciphers, otherCiphers...)
return ciphers
}

View File

@@ -4,7 +4,21 @@
## v0.106: API changes
## New `"private_upstream"` field in `POST /test_upstream_dns`
### 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
`Retry-After` header with the number of seconds of block left in it.
### New `"private_upstream"` field in `POST /test_upstream_dns`
* The new optional field `"private_upstream"` of `UpstreamConfig` contains the
upstream servers for resolving locally-served ip addresses to be checked.

View File

@@ -1078,6 +1078,12 @@
'responses':
'200':
'description': 'OK.'
'400':
'description': >
Invalid username or password.
'429':
'description': >
Out of login attempts.
'/logout':
'get':
'tags':
@@ -2228,6 +2234,10 @@
'type': 'array'
'items':
'type': 'string'
'tags':
'items':
'type': 'string'
'type': 'array'
'ClientAuto':
'type': 'object'
'description': 'Auto-Client information'
@@ -2244,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'
@@ -2378,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

@@ -27,7 +27,7 @@ set -f -u
# Deferred Helpers
not_found_msg='
readonly not_found_msg='
looks like a binary not found error.
make sure you have installed the linter binaries using:
@@ -49,6 +49,29 @@ trap not_found EXIT
# Warnings
readonly go_min_version='go1.15'
readonly go_min_version_prefix="go version ${go_min_version}"
readonly go_version_msg="
warning: your go version is different from the recommended minimal one (${go_min_version}).
if you have the version installed, please set the GO environment variable.
for example:
export GO='${go_min_version}'
"
case "$( "$GO" version )"
in
("$go_min_version_prefix"*)
# Go on.
;;
(*)
echo "$go_version_msg" 1>&2
;;
esac
# Simple Analyzers
# blocklist_imports is a simple check against unwanted packages.
@@ -69,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'\
@@ -99,7 +123,7 @@ exit_on_output() (
cmd="$1"
shift
output="$("$cmd" "$@" 2>&1)"
output="$( "$cmd" "$@" 2>&1 )"
exitcode="$?"
if [ "$exitcode" != '0' ]
then