Compare commits

..

276 Commits

Author SHA1 Message Date
Ainar Garipov
39e22ada96 all: upd base docker 2025-04-10 20:35:55 +03:00
Eugene Burkov
5aee57e297 all: sync with master 2025-04-08 19:57:40 +03:00
Eugene Burkov
6ab44f059c all: fix chlog date 2025-03-21 13:28:43 +03:00
Eugene Burkov
ef7d71dd67 all: sync with master 2025-03-20 18:30:28 +03:00
Eugene Burkov
bd16eee509 all: fix chlog date 2025-03-19 17:40:40 +03:00
Eugene Burkov
729c56de20 client: resync with master 2025-03-19 16:44:03 +03:00
Eugene Burkov
e6b31bab77 all: fix chagelog 2025-03-18 17:14:58 +03:00
Eugene Burkov
d8f855ebfc all: resync with master 2025-03-18 14:15:50 +03:00
Eugene Burkov
a829adad10 all: resync with master 2025-03-17 20:56:05 +03:00
Eugene Burkov
2fc1e258ed all: fix chlog 2025-03-11 18:19:44 +03:00
Eugene Burkov
bbf1ceb870 all: rm deleted 2025-03-11 15:14:20 +03:00
Eugene Burkov
8de3734e2c all: rm files 2025-03-11 14:01:32 +03:00
Eugene Burkov
474cba52f0 all: sync with master, upd chlog 2025-03-11 13:36:04 +03:00
Ainar Garipov
805de59805 all: fix chlog 2025-02-20 17:43:18 +03:00
Ainar Garipov
effc822b85 all: sync with master 2025-02-18 19:50:19 +03:00
Eugene Burkov
aef00413d5 all: fix release date 2025-01-23 16:24:34 +03:00
Eugene Burkov
49bd72c27f all: fix chlog 2025-01-20 15:21:56 +03:00
Eugene Burkov
2e52a2c8a0 all: sync with master 2025-01-20 15:03:33 +03:00
Ainar Garipov
ceb178fcd5 all: imp chlog 2024-12-11 16:09:24 +03:00
Ainar Garipov
0d202cb544 all: upd chlog 2024-12-11 14:33:55 +03:00
Eugene Burkov
6ce6c2c04d all: move release date 2024-12-05 17:07:56 +03:00
Eugene Burkov
3f95db98d3 all: sync with master 2024-12-05 16:00:18 +03:00
Eugene Burkov
54f3a5f990 all: sync hotfix 2024-11-05 19:32:44 +03:00
Eugene Burkov
44cebc06ec all: upd release date 2024-11-05 13:46:19 +03:00
Eugene Burkov
6affa96490 all: sync with master 2024-10-29 18:53:56 +03:00
Ainar Garipov
2aaf8ab3c1 all: upd chlog 2024-10-03 15:34:48 +03:00
Ainar Garipov
ee1eb80786 all: resync fix 2024-10-02 20:25:07 +03:00
Ainar Garipov
e8fd4b1872 all: add permcheck, client fix; imp chlog 2024-10-02 18:24:07 +03:00
Ainar Garipov
8cb5781770 all: resync with master 2024-09-30 20:17:20 +03:00
Ainar Garipov
c7d8b9ede1 client: import querylog fix 2024-07-04 17:06:16 +03:00
Ainar Garipov
5c6bb33e3a all: resync with master 2024-07-03 15:53:40 +03:00
Ainar Garipov
158d4f0249 all: sync with master 2024-07-03 15:38:37 +03:00
Ainar Garipov
f73717ec08 all: upd chlog 2024-06-06 17:31:01 +03:00
Ainar Garipov
1807198a9b all: sync with master 2024-06-05 19:00:28 +03:00
Eugene Burkov
1ccf8fe116 all: upd chlog 2024-05-23 15:32:15 +03:00
Eugene Burkov
d22f0eefe2 all: sync with master; upd chlog 2024-05-22 18:32:21 +03:00
Ainar Garipov
344c66f7ab all: fix release date in chlog 2024-05-21 17:10:16 +03:00
Ainar Garipov
83be002b41 all: upd chlog 2024-05-15 17:24:12 +03:00
Ainar Garipov
9945cd3991 all: upd chlog; sync with master 2024-05-15 16:30:36 +03:00
Ainar Garipov
667263a3a8 all: sync with master 2024-05-15 13:34:12 +03:00
Ainar Garipov
6318fc424b all: import hotfix; upd chlog 2024-04-05 14:58:11 +03:00
Ainar Garipov
e32a37a747 all: upd chlog, x/net 2024-04-04 16:29:15 +03:00
Ainar Garipov
7805a71332 all: sync more; upd chlog 2024-04-03 21:30:46 +03:00
Ainar Garipov
6fb2aee210 all: sync with master; upd chlog 2024-04-02 20:22:19 +03:00
Ainar Garipov
ce9bb588ed all: sync with master 2024-03-19 16:20:32 +03:00
Ainar Garipov
55fb914537 all: sync rc fix with master 2024-03-13 16:25:51 +03:00
Ainar Garipov
6f7bfd6c9c all: sync with master 2024-03-12 18:15:58 +03:00
Ainar Garipov
fbc0d981ba all: partially sync with master; upd chlog 2024-03-06 18:33:53 +03:00
Ainar Garipov
48d1c673a9 all: fix chlog 2024-02-06 15:21:25 +03:00
Ainar Garipov
889a0eb8b3 all: upd chlog, i18n; fix os resolv 2024-02-01 15:20:53 +03:00
Ainar Garipov
b01c10b73e all: sync with master 2024-01-30 18:44:31 +03:00
Eugene Burkov
f6ad64bf69 all: fix chlog link 2023-12-11 15:36:34 +03:00
Eugene Burkov
a5e8443735 all: fix chlog link 2023-12-11 15:26:48 +03:00
Eugene Burkov
2860929a47 all: sync with master; upd chlog 2023-12-11 14:26:01 +03:00
Ainar Garipov
ecdac56616 all: fix chlog link 2023-12-07 17:44:22 +03:00
Ainar Garipov
25918e56fa Pull request 2100: v0.107.42-rc
Squashed commit of the following:

commit 284190f748345c7556e60b67f051ec5f6f080948
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Dec 6 19:36:00 2023 +0300

    all: sync with master; upd chlog
2023-12-07 17:23:00 +03:00
Ainar Garipov
df91f016f2 all: fix chlog 2023-11-13 18:34:42 +03:00
Ainar Garipov
f7d259f653 all: fix chlog 2023-11-13 18:00:38 +03:00
Ainar Garipov
82ab4328d4 all: sync with master; upd chlog 2023-11-13 17:39:48 +03:00
Ainar Garipov
b21e19a223 all: sync with master; upd chlog 2023-10-18 17:04:44 +03:00
Ainar Garipov
c6aed4eb57 cherry-pick: 6180 revert 2023-10-11 18:35:46 +03:00
Ainar Garipov
760d466b38 all: sync with master; upd chlog 2023-10-11 17:31:41 +03:00
Ainar Garipov
258eecc55b all: sync with master; upd chlog 2023-09-11 17:51:50 +03:00
Ainar Garipov
7b93f5d7cf all: sync with master; upd chlog 2023-09-07 17:13:48 +03:00
Ainar Garipov
3be7676970 all: sync with master; upd chlog 2023-08-02 16:26:34 +03:00
Ainar Garipov
48ee2f8a42 all: sync with master; upd chlog 2023-07-26 13:18:44 +03:00
Ainar Garipov
ec83d0eb86 all: sync with master; upd chlog 2023-07-12 15:13:31 +03:00
Ainar Garipov
19347d263a cherry-pick: 5959-fix-error-days
Updates #5959.

* commit '4b9264531be50e81fe610050a12827b71bc3a9cd':
  clients: use constant a day in milliseconds
  clients: fix lint
  fix error days
2023-07-03 14:38:16 +03:00
Ainar Garipov
b22b16d98c all: sync with master; upd chlog 2023-07-03 14:10:40 +03:00
Ainar Garipov
cadb765b7d all: sync with master; upd chlog 2023-06-13 17:04:47 +03:00
Ainar Garipov
1116da8b83 all: sync with master; upd chlog 2023-06-08 19:48:01 +03:00
Ainar Garipov
c65700923a all: sync with master; upd chlog 2023-06-07 20:04:01 +03:00
Ainar Garipov
7030c7c24c all: imp chlog 2023-04-18 16:56:12 +03:00
Ainar Garipov
09718a2170 all: sync with master; upd chlog 2023-04-18 16:07:11 +03:00
Ainar Garipov
77cda2c2c5 all: imp chlog 2023-04-12 16:18:02 +03:00
Ainar Garipov
d9c57cdd9a all: sync with master; upd chlog 2023-04-12 14:48:42 +03:00
Ainar Garipov
0dad53b5f7 all: fix chlog 2023-04-05 16:38:18 +03:00
Ainar Garipov
9a7315dbea all: upd go, tools, ui; fix panics 2023-04-05 16:35:27 +03:00
Ainar Garipov
a21558f418 all: sync with master; upd chlog 2023-03-09 15:39:35 +03:00
Ainar Garipov
4f928be393 bamboo-specs: do not require make where not needed 2023-02-21 15:12:18 +03:00
Ainar Garipov
f543b47261 dnsforward: fix panic; take Host into account 2023-02-21 14:55:10 +03:00
Ainar Garipov
66b831072c all: sync with master; upd chlog 2023-02-15 16:53:29 +03:00
Ainar Garipov
80eb339896 all: sync with master; upd chlog 2023-02-01 15:41:34 +03:00
Ainar Garipov
c69639c013 all: imp chlog 2023-01-19 15:29:10 +03:00
Ainar Garipov
5f6fbe8e08 all: sync with master; upd chlog 2023-01-19 15:04:46 +03:00
Ainar Garipov
b40bbf0260 all: upd chlog 2023-01-19 15:00:14 +03:00
Ainar Garipov
a11c8e91ab all: sync with master 2022-12-15 17:50:08 +03:00
Ainar Garipov
618d0e596c all: fix chlog 2022-12-07 16:49:19 +03:00
Ainar Garipov
fde9ea5cb1 all: sync with master 2022-12-07 16:46:59 +03:00
Ainar Garipov
03d9803238 all: upd chlog 2022-11-23 17:00:27 +03:00
Ainar Garipov
bd64b8b014 all: sync with master 2022-11-23 16:52:05 +03:00
Ainar Garipov
67fe064fcf all: sync with master 2022-11-08 17:53:30 +03:00
Ainar Garipov
471668d19a all: fix chlog 2022-11-02 18:29:57 +03:00
Ainar Garipov
42762dfe54 all: upd chlog 2022-11-02 16:25:08 +03:00
Ainar Garipov
c9314610d4 all: sync with master 2022-11-02 16:18:02 +03:00
Ainar Garipov
16755c37d8 all: upd go 2022-10-07 15:57:26 +03:00
Ainar Garipov
73fcbd6ea2 all: sync with master 2022-10-03 18:52:20 +03:00
Ainar Garipov
30244f361f all: sync with master 2022-09-29 19:10:03 +03:00
Ainar Garipov
083991fb21 home: sync with master 2022-09-29 18:54:54 +03:00
Ainar Garipov
e3200d5046 all: upd chlog 2022-09-29 17:43:04 +03:00
Ainar Garipov
21f6ed36fe all: sync with master 2022-09-29 17:36:01 +03:00
Ainar Garipov
77d04d44eb all: sync with master 2022-09-14 16:36:29 +03:00
Ainar Garipov
b34d119255 all: imp chlog 2022-09-07 18:38:03 +03:00
Ainar Garipov
63bd71a10c all: imp chlog 2022-09-07 18:07:52 +03:00
Ainar Garipov
faf2b32389 all: sync with master 2022-09-07 18:03:18 +03:00
Ainar Garipov
d23da1b757 all: sync with master 2022-08-19 15:45:54 +03:00
Ainar Garipov
beb8e36eee cherry-pick: 4557-asuswrt-readme
Updates #4557.

* commit 'e3624ec5880361b8afccd0ddac9dc31fd7ce4a07':
  all: fix abbreviation
  Update README.md
2022-08-19 15:21:21 +03:00
Ainar Garipov
fe70161c01 cherry-pick: upd-dnsproxy
Merge in DNS/adguard-home from upd-dnsproxy to master

Squashed commit of the following:

commit 3c5b683e96191b9cf0abf35229c3c665370d782e
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Aug 18 18:04:13 2022 +0300

    all: upd dnsproxy
2022-08-19 15:20:59 +03:00
Ainar Garipov
39fa4b1f8e cherry-pick: 4846-migration-fix
Updates #4846.

Squashed commit of the following:

commit 22e2e89e5390c7b1486fb69064c55da40fc5c7e7
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Aug 18 16:25:07 2022 +0300

    home: fix yaml object type
2022-08-19 15:19:11 +03:00
Ainar Garipov
c7a8883201 cherry-pick: 4795-bilibili
Updates #4795.

* commit 'e6ebb8efef4430c48b06469ba566349bba3d9856':
  filtering: fmt
  filtering: add Bilibili and Weibo domains
  filtering: add Bilibili service
2022-08-19 15:18:14 +03:00
Ainar Garipov
3fd467413c cherry-pick: 4446-readme-fix
Updates #4446.

* commit 'ea5d165a703dd37ef40254f3f775e049b6cebf93':
  all: imp readme
  Enable code block syntax hightlight in README.md
2022-08-19 15:17:57 +03:00
Ainar Garipov
9728dd856f cherry-pick: 4387-fix-openapi-schema
Updates #4387.

* commit 'f54a2dc1da5dfd578f156cf1e0f53f32516eb844':
  home: imp filtering handling
  correct openapi schema
2022-08-19 15:17:43 +03:00
Ainar Garipov
ecadf78d60 all: upd chlog 2022-08-19 15:02:37 +03:00
Ainar Garipov
eba4612d72 all: fix chlog 2022-08-17 18:55:20 +03:00
Ainar Garipov
9200163f85 all: sync with master 2022-08-17 18:23:30 +03:00
Ainar Garipov
3c17853344 cherry-pick: 4844-snap-core22
Closes #4843.
Updates #4844.

* commit '385a873b0f006f26832e73744845fdbc2864aad0':
  all: chlog
  Update Snap to Ubuntu Core 22 #4843
2022-08-17 18:16:57 +03:00
Eugene Burkov
993a3fc42c cherry-pick: 4358 stats races
Merge in DNS/adguard-home from 4358-stats-races to master

Updates #4358

Squashed commit of the following:

commit 162d17b04d95adad21fb9b3c5a6fb64df2e037ec
Merge: 17732cfa d4c3a43b
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Aug 17 14:04:20 2022 +0300

    Merge branch 'master' into 4358-stats-races

commit 17732cfa0f3b2589bf2c252697eee1d6b358a66c
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Aug 17 13:53:42 2022 +0300

    stats: imp docs, locking

commit 4ee090869af0fa2b777c12027c3b77d5acd6e4de
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Aug 16 20:26:19 2022 +0300

    stats: revert const

commit a7681a1b882cef04511fcd5d569f5abe2f955239
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Aug 16 20:23:00 2022 +0300

    stats: imp concurrency

commit a6c6c1a0572e4201cd24644fd3f86f51fc27f633
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Aug 16 19:51:30 2022 +0300

    stats: imp code, tests, docs

commit 954196b49f5ad91d91f445ff656e63c318e4124c
Merge: 281e00da 6e63757f
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Aug 16 13:07:32 2022 +0300

    Merge branch 'master' into 4358-stats-races

commit 281e00daf781d045269584ce0158eed1d77918df
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Aug 12 16:22:18 2022 +0300

    stats: imp closing

commit ed036d9aa7e25498869edfb866b6e923538970eb
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Aug 12 16:11:12 2022 +0300

    stats: imp tests more

commit f848a12487ecd2afc8416e800510090cc1be7330
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Aug 12 13:54:19 2022 +0300

    stats: imp tests, code

commit 60e11f042d51ec68850143129e61c701c5e4f3a4
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Aug 11 16:36:07 2022 +0300

    stats: fix test

commit 6d97f1db093b5ce0d37984ff96a9ef6f4e02dba1
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Aug 11 14:53:21 2022 +0300

    stats: imp code, docs

commit 20c70c2847b0de6c7f9271a8d9a831175ed0c499
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Aug 10 20:53:36 2022 +0300

    stats: imp shared memory safety

commit 8b3945670a190bab070171e6b4976edab1e3e2a2
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Aug 10 17:22:55 2022 +0300

    stats: imp code
2022-08-17 18:15:41 +03:00
Ainar Garipov
7bb9b2416b cherry-pick: upd-specs
Merge in DNS/adguard-home from upd-specs to master

Squashed commit of the following:

commit d7ac1dc1ef305098ff741d557c13db8a60ffe1f9
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Aug 15 19:16:51 2022 +0300

    bamboo-specs: allow larger keys
2022-08-17 18:15:16 +03:00
Eugene Burkov
2de321ce24 cherry-pick: Fix frontend CI build
Merge in DNS/adguard-home from fix-bamboo-specs to master

Squashed commit of the following:

commit e59b75ab9528bbe8fbf5e15054d848abffbae312
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Aug 15 18:52:10 2022 +0300

    all: fix ci frontend build
2022-08-17 18:14:59 +03:00
Eugene Burkov
30b2b85ff1 cherry-pick: Separate front- and back- end builds
Merge in DNS/adguard-home from imp-bamboo-specs to master

Squashed commit of the following:

commit 3415b650e48aefef3ad16030be3d797de4015403
Merge: e37c0a2b f58265ec
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Aug 15 18:42:42 2022 +0300

    Merge branch 'master' into imp-bamboo-specs

commit e37c0a2bb52fab98e133332e8f54d500d0f96b06
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Aug 15 18:30:33 2022 +0300

    scripts: replace find with loop

commit 826a02f6a11000cce4b3205229d6bbb050c8dd73
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Aug 15 18:00:41 2022 +0300

    all: ...again

commit 54aebf5d4aeba35e3dc320436236759f4d1ccdad
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Aug 15 17:59:24 2022 +0300

    all: fix spec yaml

commit 87b92b30504f2427c40303265354afba4855e0bb
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Aug 15 17:48:19 2022 +0300

    all: separate front- and back-end builds
2022-08-17 18:14:44 +03:00
Ainar Garipov
6ea4788f56 cherry-pick: 4836-revert-dhcp-upd
Updates #4836.

Squashed commit of the following:

commit 6fe1721d44be1c23e524d477e28b5f7cc5dd2dc6
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Aug 15 17:48:41 2022 +0300

    dhcpd: reverd mod upd
2022-08-17 18:13:27 +03:00
Ainar Garipov
3c52a021b9 cherry-pick: add-ar-i18n
Merge in DNS/adguard-home from add-ar-i18n to master

Squashed commit of the following:

commit 6ef7c70bceb6f6ebabd81011154022a75fc91bd3
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Aug 10 20:55:39 2022 +0300

    client: add ar locale
2022-08-17 18:12:15 +03:00
Ainar Garipov
0ceea9af5f cherry-pick: upd-yaml
Merge in DNS/adguard-home from upd-yaml to master

Squashed commit of the following:

commit f0c3a1896e7eba73b1c8a02533637cdabc89909b
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Aug 8 15:28:02 2022 +0300

    home: restore indent lvl

commit b52c124d2e786e8575c58e75efa7d2cd2b70b67f
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Aug 8 15:06:41 2022 +0300

    all: upd tools, yaml mod
2022-08-17 18:10:49 +03:00
Eugene Burkov
39b404be19 cherry-pick: 4358 fix stats
Merge in DNS/adguard-home from 4358-fix-stats to master

Updates #4358.
Updates #4342.

Squashed commit of the following:

commit 5683cb304688ea639e5ba7f219a7bf12370211a4
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Aug 4 18:20:54 2022 +0300

    stats: rm races test

commit 63dd67650ed64eaf9685b955a4fdf3c0067a7f8c
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Aug 4 17:13:36 2022 +0300

    stats: try to imp test

commit 59a0f249fc00566872db62e362c87bc0c201b333
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Aug 4 16:38:57 2022 +0300

    stats: fix nil ptr deref

commit 7fc3ff18a34a1d0e0fec3ca83a33f499ac752572
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Apr 7 16:02:51 2022 +0300

    stats: fix races finally, imp tests

commit c63f5f4e7929819fe79b3a1e392f6b91cd630846
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Aug 4 00:56:49 2022 +0300

    aghhttp: add register func

commit 61adc7f0e95279c1b7f4a0c0af5ab387ee461411
Merge: edbdb2d4 9b3adac1
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Aug 4 00:36:01 2022 +0300

    Merge branch 'master' into 4358-fix-stats

commit edbdb2d4c6a06dcbf8107a28c4c3a61ba394e907
Merge: a91e4d7a a481ff4c
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Aug 3 21:00:42 2022 +0300

    Merge branch 'master' into 4358-fix-stats

commit a91e4d7af13591eeef45cb7980d1ebc1650a5cb7
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Aug 3 18:46:19 2022 +0300

    stats: imp code, docs

commit c5f3814c5c1a734ca8ff6726cc9ffc1177a055cf
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Aug 3 18:16:13 2022 +0300

    all: log changes

commit 5e6caafc771dddc4c6be07c34658de359106fbe5
Merge: 091ba756 eb8e8166
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Aug 3 18:09:10 2022 +0300

    Merge branch 'master' into 4358-fix-stats

commit 091ba75618d3689b9c04f05431283417c8cc52f9
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Aug 3 18:07:39 2022 +0300

    stats: imp docs, code

commit f2b2de77ce5f0448d6df9232a614a3710f1e2e8a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Aug 2 17:09:30 2022 +0300

    all: refactor stats & add mutexes

commit b3f11c455ceaa3738ec20eefc46f866ff36ed046
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Apr 27 15:30:09 2022 +0300

    WIP
2022-08-17 18:10:16 +03:00
Ainar Garipov
56dc3eab02 cherry-pick: 4801-hassio-link
Updates #4801.

* commit '73f935f3f370ad7e1dfb2495fe71d1dc5e415672':
  Update Hass.io AdGuard Home integration link
2022-08-17 18:07:06 +03:00
Ainar Garipov
554a38eeb1 cherry-pick: 4800-upd-link
Updates #4800.

* commit 'bbccd616148f63240afee6ccf643179ff322c6f4':
  Update RFC 9250 link
2022-08-17 18:06:29 +03:00
Ainar Garipov
c8d3afe869 cherry-pick: 4670-invalid-arg-cap-check
Updates #4670.

Squashed commit of the following:

commit 9c32739eb92ef57c78a4dc3ec3c0f280aebf7182
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Aug 3 20:04:54 2022 +0300

    aghnet: imp port check for older linuxes
2022-08-17 18:05:28 +03:00
Ainar Garipov
44222c604c all: upd chlog 2022-08-17 18:05:16 +03:00
Ainar Garipov
cbf221585e all: upd chlog 2022-08-03 16:22:44 +03:00
Ainar Garipov
48322f6d0d all: upd chlog 2022-08-03 16:21:12 +03:00
Ainar Garipov
d5a213c639 cherry-pick: upd-i18n
Merge in DNS/adguard-home from upd-i18n to master

Squashed commit of the following:

commit 366600a32ecbb163ab43b43145898bbadcfbc2e9
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Aug 3 15:09:16 2022 +0300

    client: fix si-lk

commit 2a55ee3846251e53529f4ef6562e5f4939381eae
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Aug 3 15:03:45 2022 +0300

    client: upd i18n
2022-08-03 16:01:22 +03:00
Ainar Garipov
8166c4bc33 cherry-pick: upd-go
Merge in DNS/adguard-home from upd-go to master

Squashed commit of the following:

commit 8edfb5cc3466c1e4ee2eacae5157bd93c135a284
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Aug 3 14:25:45 2022 +0300

    all: imp docs; fmt

commit 080b8a85c02afbdaa079c0da47cb7b6311d50fbe
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Aug 2 20:51:20 2022 +0300

    all: upd go, imp generic code
2022-08-03 16:01:02 +03:00
Ildar Kamalov
133cd9ef6b cherry-pick: 4776 add word break for query log domains
Updates #4776

Squashed commit of the following:

commit 6f1778fbd11da529ae934ee33c8f1ad227cdfa66
Merge: 753bd44c 053bb72a
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Aug 2 11:52:07 2022 +0300

    Merge branch 'master' into 4776-domains

commit 753bd44cbb592903ed996713a79e4dbf073d780b
Author: Ildar Kamalov <ik@adguard.com>
Date:   Mon Aug 1 16:58:07 2022 +0300

    client: add word break for query log domains
2022-08-03 15:59:23 +03:00
Ildar Kamalov
11146f73ed cherry-pick: 4775 fix query log issue on tablet devices
Updates #4775

Squashed commit of the following:

commit 9ad85d2306b68227e11c7b1dd792e3fe6389939d
Merge: 95aa29d6 41f081d8
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Aug 2 11:44:04 2022 +0300

    Merge branch 'master' into 4775-popup

commit 95aa29d68bdf5e9c4e7aa59f42d04328b1872115
Author: Ildar Kamalov <ik@adguard.com>
Date:   Mon Aug 1 16:21:23 2022 +0300

    client: fix query log issue on tablet devices
2022-08-03 15:57:05 +03:00
Eugene Burkov
1beb18db47 cherry-pick: 4517 warning wording
Merge in DNS/adguard-home from 4517-warning-label to master

Updates #4517.

Squashed commit of the following:

commit 4987f63937253da2954cf20c7b99a3b8a0adf112
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Aug 1 13:59:28 2022 +0300

    client: imp wording
2022-08-03 15:56:45 +03:00
Eugene Burkov
f7bc2273a7 cherry-pick: 4517 domain specific test
Merge in DNS/adguard-home from 4517-domain-specific-test to master

Updates #4517.

Squashed commit of the following:

commit 03a803f831749a060923ec966592696f99591786
Merge: 8ea24170 f5959a0d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jul 29 19:17:28 2022 +0300

    Merge branch 'master' into 4517-domain-specific-test

commit 8ea2417036547996bb2d39b75b0ff31de4fe9b21
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jul 29 18:44:26 2022 +0300

    all: log changes, imp docs

commit aa74c8be64f2796a2dfa7166f0155fff5bb395b6
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jul 29 18:07:12 2022 +0300

    dnsforward: imp logging

commit 02dccca4e7d766bbfbe0826933e8be70fcd93f58
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jul 29 17:24:08 2022 +0300

    all: imp code, docs

commit 3b21067d07b208baf574a34fb06ec808b37c4ee3
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jul 29 13:34:55 2022 +0300

    client: add warning toast

commit ea2272dc77f87e34dc6aff0af99c7a51a04e3770
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jul 28 20:11:55 2022 +0300

    dnsforward: imp err msg, docs

commit fd9ee82afef9d93961c30ebafcc7a11d984247b5
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jul 28 19:24:58 2022 +0300

    dnsforward: test doain specific upstreams

commit 9a83ebfa7a73bf4e03eaf1ff4a33f79771159fc7
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jul 28 18:22:49 2022 +0300

    dnsforward: merge some logic
2022-08-03 15:56:25 +03:00
Ainar Garipov
d1e735a003 cherry-pick: upd-links-etc
Merge in DNS/adguard-home from upd-links-etc to master

Squashed commit of the following:

commit 49856df394f1a2123a27afdb35047d3b1a49860f
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Aug 2 20:43:10 2022 +0300

    all: revert cdn link revert

commit 59bbe4bbd300f48674c1a6224a91f9a567d6c79c
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Aug 2 20:40:50 2022 +0300

    all: revert static link revert

commit fe2acc4a0d6d5ee31cb8dbb0d0e0984c3cd723db
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Aug 2 18:24:02 2022 +0300

    all: revert links up in README; imp tools
2022-08-03 15:54:47 +03:00
Ainar Garipov
af4ff5c748 cherry-pick: upd-domains-and-links
Merge in DNS/adguard-home from upd-domains-and-links to master

Squashed commit of the following:

commit 5e5ff2fec358104995877da689da24749ac470ce
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Jul 28 19:53:19 2022 +0300

    all: upd urls

    Update domains and URLs to make them more resistant to state blocking.
2022-08-03 15:54:23 +03:00
Ainar Garipov
fc951c1226 cherry-pick: 4755-youtube-domain
Updates #4755.

Squashed commit of the following:

commit cb0ab8b26f6f277ef76ee3492c99870cbfc24666
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Jul 28 17:21:02 2022 +0300

    filtering: add another youtube domain
2022-08-03 15:52:00 +03:00
Ainar Garipov
f81fd42472 cherry-pick: imp-issue-tmpl
Merge in DNS/adguard-home from imp-issue-tmpl to master

Squashed commit of the following:

commit 3941dd135911d850f3ec9b01f55bc45269a7b91c
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Jul 28 15:24:26 2022 +0300

    all: fix links in issue tmpls

commit 438375a4666f951fc24ab47e4b0de5a61714973b
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Jul 28 15:23:00 2022 +0300

    all: imp issue tmpls
2022-08-03 15:51:37 +03:00
Ainar Garipov
1029ea5966 cherry-pick: issue-templates
Merge in DNS/adguard-home from issue-templates to master

Squashed commit of the following:

commit 989253530047a463804e81c8fda82ac268f39adc
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Jul 27 16:56:35 2022 +0300

    all: fix issue tmpl schema

commit e69df09ab4b4f713d124dc6eeb1ed34e0f4aaa70
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Jul 27 16:41:14 2022 +0300

    all: rename tmpl files

commit 542306da1ea1bdc09ca328856367c64139a8ec60
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Jul 27 16:37:02 2022 +0300

    all: imp github issue templates
2022-08-03 15:51:23 +03:00
Ainar Garipov
c0abdb4bc7 cherry-pick: 4782-server-name-label
Updates #4782.

Squashed commit of the following:

commit d350b3853bf722c0f2a8d1fc4a1c28dc384c5ca0
Author: Natalia Sokolova <n.sokolova@adguard.com>
Date:   Tue Jul 26 18:39:38 2022 +0300

    client: imp wording

commit d0785311bfe38fb10477bf8971a46d6c61aecfda
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Jul 26 17:16:41 2022 +0300

    client: imp tls server name label
2022-08-03 15:50:48 +03:00
Ainar Garipov
6681178ad3 all: upd chlog 2022-08-03 15:43:45 +03:00
Ainar Garipov
e73605c4c5 all: add ms link 2022-07-13 15:24:17 +03:00
Ainar Garipov
c7017d49aa all: upd chlog 2022-07-13 15:22:20 +03:00
Ainar Garipov
191d3bde49 cherry-pick: home: fix exe path finding
Closes #4735.

Squashed commit of the following:

commit 8228e5f82c9d8056d5567a7f1b13b1365346c4d4
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Jul 11 17:41:19 2022 +0300

    home: fix exe path finding
2022-07-13 15:15:10 +03:00
Ainar Garipov
18876a8e5c cherry-pick: aghalg: impl json.Marshaler for NullBool
Updates #4735.

Squashed commit of the following:

commit 93a0b1dc6b668f7d9fd89d06b8f0f24dcd345356
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Jul 11 17:02:36 2022 +0300

    aghalg: impl json.Marshaler for NullBool
2022-07-13 15:14:54 +03:00
Eugene Burkov
aa4a0d9880 cherry-pick: 4698 Gateway IP in DHCP Lease
Closes #4698.

Squashed commit of the following:

commit 6be0caee58926f8cea1e10650fbde0c8d97d0dac
Author: Ildar Kamalov <ik@adguard.com>
Date:   Fri Jul 8 13:41:50 2022 +0300

    update translation

commit e0370656d05e8463d73ea73568cae81187c6b2e3
Author: Ildar Kamalov <ik@adguard.com>
Date:   Fri Jul 8 13:40:54 2022 +0300

    client: validate static lease ip

commit 7f4d00f9f3a54dc93ce5d5c45e9c21745f6e39d1
Merge: 2ee79626 77e5e27d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jul 8 13:20:15 2022 +0300

    Merge branch 'master' into 4698-lease-with-gateway

commit 2ee79626a1b0c7b113dbd22ba4ef6e85ea9913ec
Merge: 471b96b8 3505ce87
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jul 7 19:34:33 2022 +0300

    Merge branch 'master' into 4698-lease-with-gateway

commit 471b96b81da8920c1e71b7110050154f912677d2
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jul 7 16:07:23 2022 +0300

    dhcpd: imp docs

commit 67dd6c76f7d2df4712a57281e0f40f2ee1a1efa2
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jul 7 15:48:47 2022 +0300

    dhcpd: restrict gateway ip for lease
2022-07-13 15:14:32 +03:00
Dimitry Kolyshev
d03d731d65 cherry-pick: all: updater exe name
Merge in DNS/adguard-home from 4219-updater to master

Squashed commit of the following:

commit f569a5f232330b83c234838a5bff8ae5277f152f
Merge: a90b4fa7 3505ce87
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jul 7 22:14:50 2022 +0530

    Merge remote-tracking branch 'origin/master' into 4219-updater

    # Conflicts:
    #	CHANGELOG.md

commit a90b4fa7782c5ec4531d8e305c0d448e84898239
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jul 7 21:56:17 2022 +0530

    home: imp code

commit da0f96b976e430fffc531072ef3e2384bc8b1f09
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jul 7 21:48:40 2022 +0530

    updater: exe name

commit 246dc9ca3b133cbc93ea59edd272674b87ff8de3
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jul 7 19:18:02 2022 +0530

    all: imp docs

commit 042382d170c4d68ff67fe5544a75371337529623
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jul 7 18:02:25 2022 +0530

    all: updater exe name

commit a180c4673ead66788969865784348634af1a739e
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jul 7 17:47:46 2022 +0530

    docs: updater exe name

commit 1a98a6eadbd96add0a488fb8f89fb7d8b0ffb3d0
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jul 7 17:40:44 2022 +0530

    all: updater exe name

commit 1b13f5d85550dc71b08fd8e5b4258f8414a38759
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jul 7 17:14:57 2022 +0530

    all: updater exe name
2022-07-13 15:14:06 +03:00
Ainar Garipov
33b58a42fe cherry-pick: all: use canonical names for hosts file runtime clients
Updates #4683.

Squashed commit of the following:

commit daa8fdaee574d4ac2171f6b13c5ce3f3fedd9801
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Jul 7 19:13:29 2022 +0300

    all: use canonical names for hosts file runtime clients
2022-07-13 15:13:06 +03:00
Eugene Burkov
2e9e708647 cherry-pick: 4699 dhcp ptr
Merge in DNS/adguard-home from 4699-dhcp-ptr to master

Closes #4699.

Squashed commit of the following:

commit 0a8e2b3e22b7fad28a53db65031cc39d8755ecf4
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jun 28 18:40:53 2022 +0300

    dnsforward: imp naming again

commit 0b0884a8305f18f7f69560b86be8837933e220e9
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jun 28 18:26:58 2022 +0300

    dnsforward: imp naming

commit e193f53d9a1dd76d41396c06e2ec5a1e7d176557
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jun 28 17:26:00 2022 +0300

    all: imp chlog

commit 8ac9f84f086d9cb0b0f9da72bfc51f9b70a3dab7
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jun 28 17:18:48 2022 +0300

    all: log changes

commit 7cdc175d02b6eacfcb6ba62a5424d11e2561a879
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jun 28 17:03:52 2022 +0300

    dnsforward: add tld to dhcp leased hostnames
2022-07-13 15:11:37 +03:00
Eugene Burkov
8ad22841ab cherry-pick: 4677 openwrt service
Merge in DNS/adguard-home from 4677-openwrt-service to master

Updates #4677.

Squashed commit of the following:

commit 6aed4036d3338a601a7ec5ef1ca74a407ae4c0e2
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Jun 20 14:49:33 2022 +0300

    home: imp docs

commit 54e32fa47ed11e50c6405ced90a400e4e69f021d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Jun 20 14:30:08 2022 +0300

    home: fix wrt svc
2022-07-13 15:06:04 +03:00
Ainar Garipov
32cf02264c cherry-pick: 4326 improve dockerfile
Updates #4326.

* commit 'f987c2559825923b22e910d01c2d42fb06231acc':
  scripts: imp docs; upd alpine
  Simplify Dockerfile Alpine Linux apk usage
2022-07-13 15:04:26 +03:00
Ildar Kamalov
0e8445b38f cherry-pick: 4659 fix url value in filter table actions
Updates #4659

Squashed commit of the following:

commit e1bcda9566bd9f1cca965f4308c337a9adf2ce04
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Jun 14 17:40:09 2022 +0300

    client: fix url value in filter table actions
2022-07-13 15:03:54 +03:00
Eugene Burkov
cb27ecd6c0 cherry-pick: more sysv
Merge in DNS/adguard-home from 4480-sysv-again to master

Updates #4480.

Squashed commit of the following:

commit 263fa05ab19de95b18fb07f6c89e4b9a1b24657b
Merge: 360a6468 d3f39b0a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jun 14 13:36:15 2022 +0300

    Merge branch 'master' into 4480-sysv-again

commit 360a646833ca9e0e01cb6d085e70b898a30dc2d0
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jun 9 18:15:41 2022 +0300

    home: rename linux file

commit c3032533b7e00136c25d15a4ad771bb8a9c13e31
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jun 9 18:06:25 2022 +0300

    home: imp code

commit 2381c4a6ab4f6dca88123ff7b0a92f2cf9a420a8
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jun 9 17:48:22 2022 +0300

    home: wrap sysv service
2022-07-13 15:03:38 +03:00
Ildar Kamalov
535220b3df cherry-pick: 4637 fix blocked services icons and actions highlight
Updates #4637

Squashed commit of the following:

commit d69887586d15582406fab642e576a46f8984107b
Merge: 65453371 e738508d
Author: Ildar Kamalov <ik@adguard.com>
Date:   Fri Jun 10 12:07:29 2022 +0300

    Merge branch 'master' into 4637-table

commit 65453371fc7309e772a12fb9f522247e1392a64a
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu Jun 9 18:43:44 2022 +0300

    client: fix blocked services icons and actions highlight
2022-07-13 15:03:18 +03:00
Ainar Garipov
7b9cfa94f8 cherry-pick: all: imp updater
Merge in DNS/adguard-home from imp-updater to master

Squashed commit of the following:

commit 6ed487359e56a35b36f13dcbf2efbf2a7a2d8734
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Jun 9 16:29:35 2022 +0300

    all: imp logs, err handling

commit e930044cb619a43e5a44c230dadbe2228e9a93f5
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Jun 9 15:53:35 2022 +0300

    all: imp updater
2022-07-13 15:02:51 +03:00
Ildar Kamalov
b3f2e88e9c cherry-pick: 4642 update dns addresses on encryption update
Updates #4642

Squashed commit of the following:

commit 75729120d3532dc2bd12b6c9e724a691043a1870
Merge: 5b681867 1c1ca1c6
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu Jun 9 11:58:13 2022 +0300

    Merge branch 'master' into 4642-dns-privacy

commit 5b68186705c3a9287a44e33c8cf7ab79060f35a4
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Jun 7 18:39:02 2022 +0300

    fix

commit 46a9346154d33206e829a97021f3ef47ac2a5611
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Jun 7 18:18:18 2022 +0300

    client: update dns addresses on encryption update
2022-07-13 15:02:25 +03:00
Ildar Kamalov
aa7a8d45e4 cherry-pick: 4641 fix button clickable area
Updates #4641

Squashed commit of the following:

commit f9f018388a198d7712e5caabba94035e42e393c4
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Jun 7 16:21:37 2022 +0300

    client: fix button clickable area
2022-07-13 15:02:01 +03:00
Ainar Garipov
49cdef3d6a all: upd chlog, go 2022-07-13 14:46:30 +03:00
Ainar Garipov
fecd146552 client: upd i18n 2022-07-13 13:43:21 +03:00
Ainar Garipov
b01efd8c98 all: upd chlog 2022-06-06 18:10:40 +03:00
Ainar Garipov
bd4dfb261c cherry-pick: all: fix quic reply id
Merge in DNS/adguard-home from upd-dnsproxy-quic-fix to master

Squashed commit of the following:

commit a6ffa24769259c73e397e02d087dc155ed58a3e2
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Jun 6 15:06:00 2022 +0300

    all: fix quic reply id
2022-06-06 16:46:20 +03:00
Ainar Garipov
e754e4d2f6 cherry-pick: client: upd i18n
Merge in DNS/adguard-home from upd-i18n to master

Squashed commit of the following:

commit 3feadfe31609ef52726b582ad6ba18bfa435a081
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Jun 3 16:34:36 2022 +0300

    client: upd i18n
2022-06-03 16:40:11 +03:00
Ainar Garipov
b220e35c99 cherry-pick: all: replace uuid pkg; upd deps
Merge in DNS/adguard-home from 4622-upd-deps to master

Squashed commit of the following:

commit 36f407d8ab103da0f7eacdf91c153c23a5b7c3f2
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Jun 3 15:22:47 2022 +0300

    home: imp mobileconfig uuid gen

commit dddd162461a4830f7c0636338430cd6e77199214
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Jun 3 13:54:29 2022 +0300

    all: replace uuid pkg; upd deps
2022-06-03 16:31:56 +03:00
Ainar Garipov
4f5131f423 all: sync more 2022-06-02 17:55:48 +03:00
Ainar Garipov
dcb043df5f all: sync with master more 2022-06-02 17:28:16 +03:00
Ainar Garipov
86e5756262 client: sync with master 2022-06-02 17:23:58 +03:00
Eugene Burkov
ba0cf5739b cherry-pick: 3142 swap arp and rdns priority
Merge in DNS/adguard-home from 3142-fix-clients to master

Updates #3142.
Updates #3597.

Squashed commit of the following:

commit 4dcabedbfb1a4e4a0aaba588f708e4625442fce8
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Mar 22 15:13:15 2022 +0300

    all: imp log of changes

commit 481088d05eecac1109daf378e0b4d5f6b2cf099b
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Mar 22 14:36:44 2022 +0300

    all: swap arp and rdns priority
2022-06-02 17:11:09 +03:00
Eugene Burkov
c4a13b92d2 cherry-pick: 3157 excessive ptrs
Merge in DNS/adguard-home from 3157-excessive-ptrs to master

Updates #3157.

Squashed commit of the following:

commit 6803988240dca2f147bb80a5b3f78d7749d2fa14
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Apr 19 14:50:01 2022 +0300

    aghnet: and again

commit 1a7f4d1dbc8fd4d3ae620349917526a75fa71b47
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Apr 19 14:49:20 2022 +0300

    aghnet: docs again

commit d88da1fc7135f3cd03aff10b02d9957c8ffdfd30
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Apr 19 14:47:36 2022 +0300

    aghnet: imp docs

commit c45dbc7800e882c6c4110aab640c32b03046f89a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Apr 19 14:41:19 2022 +0300

    aghnet: keep alphabetical order

commit b61781785d096ef43f60fb4f1905a4ed3cdf7c68
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Apr 19 13:50:56 2022 +0300

    aghnet: imp code quality

commit 578dbd71ed2f2089c69343d7d4bf8bbc29150ace
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Apr 12 17:02:38 2022 +0300

    aghnet: imp arp container
2022-06-02 17:05:18 +03:00
Dimitry Kolyshev
723279121a cherry-pick: whotracksme tracker links
Merge in DNS/adguard-home from 4416-ui-tracker-href to master

Squashed commit of the following:

commit 979ea82a3b4d2c2a895b81aacd613fb7e5bec586
Merge: 4fe6328b 12ee287d
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Apr 19 15:03:13 2022 +0200

    Merge remote-tracking branch 'origin/master' into 4416-ui-tracker-href

commit 4fe6328b276e697a2aa351c6543d2efe6d2dc2e1
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Apr 19 14:08:10 2022 +0200

    whotracksme tracker links
2022-06-02 16:53:32 +03:00
Ainar Garipov
3ad7649f7d cherry-pick: all: do not mark help-wanted issues as stale
Merge in DNS/adguard-home from help-wanted-stale to master

Squashed commit of the following:

commit 1c5ffcdd0153dd7d9d9bcc1e35dee4a0b3113f59
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Apr 22 20:04:01 2022 +0300

    all: do not mark help-wanted issues as stale
2022-06-02 16:53:13 +03:00
Ainar Garipov
2898a49d86 cherry-pick: home: rm unnecessary locking in update; refactor
Merge in DNS/adguard-home from 4499-rm-unnecessary-locking to master

Squashed commit of the following:

commit 6d70472506dd0fd69225454c73d9f7f6a208b76b
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Apr 25 17:26:54 2022 +0300

    home: rm unnecessary locking in update; refactor
2022-06-02 16:51:50 +03:00
Ildar Kamalov
1547f9d35e cherry-pick: client: fix constant loading for blocked requests
Updates #4420

Squashed commit of the following:

commit 461a59e1541626020bf0bcfaf34ba7d2f4509dc7
Merge: 5c5e7b5d 2a1ad532
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Apr 25 18:46:02 2022 +0300

    Merge branch 'master' into 4420-loading-log

commit 5c5e7b5d1a69d30e40e71f49f46dea89fa8c40a2
Author: Ildar Kamalov <ik@adguard.com>
Date:   Sun Apr 24 22:18:22 2022 +0300

    client: fix constant loading for blocked requests
2022-06-02 16:45:06 +03:00
Eugene Burkov
adadd55c42 cherry-pick: 4525 fix panic
Merge in DNS/adguard-home from 3020-fix-panic to master

Closes #4525.

Squashed commit of the following:

commit f8d9e25eccb485269aa2f0275d4e08da767f9d05
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Apr 26 15:09:11 2022 +0300

    home: imp code

commit 8fe02c8f057c05b9e8ce1de056a92e7cd69ae4c6
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Apr 26 14:44:33 2022 +0300

    home: fix panic
2022-06-02 16:44:48 +03:00
Ainar Garipov
33b0225aa4 cherry-pick: home: imp client finding logging
Updates #4526.

Squashed commit of the following:

commit 970476ea238cbab797912e1c50eca35e3f74a52f
Merge: 3e2dde81 c4ff80fd
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Apr 27 14:01:17 2022 +0300

    Merge branch 'master' into 4526-add-client-logs

commit 3e2dde81d7325b75c257f333e2c4e417f4ae203d
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Apr 27 13:59:19 2022 +0300

    home: imp logs

commit 094bfe34770b4bdc504b5ae97dd2d3842b2f73cf
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Apr 26 21:11:18 2022 +0300

    home: imp client finding logging
2022-06-02 16:43:14 +03:00
Ainar Garipov
97d4058d80 cherry-pick: home: imp openbsd init script
Closes #4533.

Squashed commit of the following:

commit 48ca9e100619e714eab565273daeb4ee9adb5b74
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Apr 28 20:25:15 2022 +0300

    home: imp openbsd init script
2022-06-02 16:42:57 +03:00
Eugene Burkov
86207e719d cherry-pick: 4542 clientid case
Merge in DNS/adguard-home from 4542-clientid-case to master

Updates #4542.

Squashed commit of the following:

commit 2a3111ebcef09460b407cd1c870cad2391cd5650
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed May 4 20:44:18 2022 +0300

    all: fix changelog link

commit 3732def83e2a36eeff2d682149dc4dcef4e92a7d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed May 4 20:43:37 2022 +0300

    all: log changes

commit 9fe1001cf586669ae238c9c4818070cf94e23ce8
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed May 4 19:37:33 2022 +0300

    dnsforward: lowercase clientid
2022-06-02 16:42:15 +03:00
Eugene Burkov
113f94ff46 cherry-pick: all: log changes
Updates #4273.

Squashed commit of the following:

commit ebae1a4d0944fa348b7dcb7e73e59d083c7a5e97
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed May 18 14:48:16 2022 +0300

    all: log changes
2022-06-02 16:40:13 +03:00
Dimitry Kolyshev
5673deb391 cherry-pick: all: upd dnsproxy
Merge in DNS/adguard-home from 4503-upstream-conf to master

Squashed commit of the following:

commit c6cb1babd4cbf9aacafe902e3d54ce17e8d2cc81
Merge: 75d85ed1 79d85a24
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon May 23 13:06:00 2022 +0200

    Merge remote-tracking branch 'origin/master' into 4503-upstream-conf

commit 75d85ed1f4d8d5060800b2f8a4cde662db02ae30
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Fri May 20 13:14:16 2022 +0200

    all: upd dnsproxy

commit 781768d639388a60fc90631f819cfc5dd90b9eba
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon May 16 16:27:25 2022 +0200

    all: docs

commit 0dafb5b3fe11b1952d9a04294bcaaa8091b9c2a7
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon May 16 16:17:35 2022 +0200

    all: docs

commit 0d5463e4157132b0e6be78fd97eaf5a5cb8d1edc
Merge: e2c86909 f289f4b1
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon May 16 16:01:40 2022 +0200

    Merge remote-tracking branch 'origin/master' into 4503-upstream-conf

    # Conflicts:
    #	go.mod
    #	go.sum

commit e2c869091b1386065076f44dbf9498a31c9d5451
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon May 16 15:29:17 2022 +0200

    all: upd dnsrpoxy
2022-06-02 16:39:29 +03:00
Eugene Burkov
3548a393ed cherry-pick: 4480 fix sysv service script
Merge in DNS/adguard-home from 4480-sysv-boot to master

Updates #4480.

Squashed commit of the following:

commit c9645b1f3bd22a249c666e4485818bab6769f32d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue May 24 14:25:09 2022 +0300

    home: imp sysv script

commit cc323364ba6cce0284cbc6be9133a50a51b71f56
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon May 23 21:13:06 2022 +0300

    home: fix sysv service script
2022-06-02 16:35:58 +03:00
Ainar Garipov
254515f274 cherry-pick: all: upd dnsproxy, supp rfc 9250
Updates #4592.

Squashed commit of the following:

commit 1a80875d6aa7811d7d1d978f6fa8d558dec1ca87
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue May 24 19:28:27 2022 +0300

    all: upd dnsproxy, supp rfc 9250
2022-06-02 16:34:36 +03:00
Dimitry Kolyshev
bccbecc6ea cherry-pick: all: filters json
Merge in DNS/adguard-home from 4581-filters-json to master

Squashed commit of the following:

commit da0b86983432ac1791645da328df5848daac5ea6
Merge: 62fa4fc6 a82ec09a
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed May 25 12:58:25 2022 +0200

    Merge remote-tracking branch 'origin/master' into 4581-filters-json

commit 62fa4fc6ff150ebb8dbd8888a58819fb644d43ad
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed May 25 11:55:52 2022 +0200

    all: filters json

commit 96486ffbb41947b5e748f6e35eb96ee73867eba1
Merge: 9956f0af c0ac82be
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue May 24 15:57:52 2022 +0200

    Merge branch 'master' into 4581-filters-json

commit 9956f0aff1b7029f336d22013a62f2871a964322
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue May 24 15:53:43 2022 +0200

    all: filters json
2022-06-02 16:33:33 +03:00
Ainar Garipov
66f53803af cherry-pick: querylog: fix oldest calc
Updates #4591.

Squashed commit of the following:

commit 70b70c78c85311363535536c7ea12336b21accf8
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed May 25 17:35:54 2022 +0300

    querylog: fix oldest calc
2022-06-02 16:32:45 +03:00
Ildar Kamalov
faef005ce7 cherry-pick: client: reset filtered logs on url params clear
Merge in DNS/adguard-home from fix-querylog-link to master

Squashed commit of the following:

commit fc4043258eb1e427a76ee44d2a4a525a6d659ab9
Merge: 25b91504 549b20bd
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu May 26 12:42:02 2022 +0300

    Merge branch 'master' into fix-querylog-link

commit 25b91504e8949bd381e6774148e4a7ecbb81610e
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu May 26 12:21:57 2022 +0300

    fix

commit f567b9b1e4eeb6499c79b05e4d837e905850a6b9
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu May 26 12:20:48 2022 +0300

    client: reset filtered logs on url params clear
2022-06-02 16:32:18 +03:00
Eugene Burkov
941cd2a562 cherry-pick: 4166 udp upstream
Merge in DNS/adguard-home from 4166-udp-upstream to master

Closes #4166.

Squashed commit of the following:

commit b8b6d1c7ac1e11e83c0c68e46e7f66fdc6043839
Merge: e5f01273 ea6e033d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Mar 1 20:36:40 2022 +0300

    Merge branch 'master' into 4166-udp-upstream

commit e5f0127384d84c4395da5b79a1fd4a47acbe122c
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Mar 1 19:41:33 2022 +0300

    client: upd upstream examples

commit bd974f22231f11f4c57e19d6d13bc45dbfdf2fdf
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Mar 1 18:36:10 2022 +0300

    all: upd proxy

commit badf1325090ecd1dc86e42e7406dfb6653e07bf1
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Feb 4 14:36:50 2022 +0300

    WIP
2022-06-02 16:31:11 +03:00
Eugene Burkov
6a4a9a0239 cherry-pick: 3978 Query Log ECS
Merge in DNS/adguard-home from 3978-ecs-ip to master

Updates #3978.

Squashed commit of the following:

commit 915b94afa4b6d90169f73d4fa171bc81bcc267a7
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Mar 3 17:46:40 2022 +0300

    all: rm dot

commit 2dd2ed081b199de7e5d8269dae5d08d53b5eea6d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Mar 3 17:42:45 2022 +0300

    client: imp txt

commit 8d5a23df739f0b650f9f3870141fd83e8fa0c1e0
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Mar 3 14:36:04 2022 +0300

    client: imp text

commit 69c856749a20144822ef3f1f67c5f3e3c24f5374
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Mar 3 14:24:56 2022 +0300

    client: imp description

commit cd0150128ad29d1874492735a5d621c0803ad0bd
Merge: 28181fbc e0b557ed
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Mar 2 21:02:16 2022 +0300

    Merge branch 'master' into 3978-ecs-ip

commit 28181fbc79eb22e7fd13cbd1d5a3c040af9fa2a4
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Mar 2 20:45:50 2022 +0300

    client: show ecs

commit cdc5e7f8c4155b798426d815eed0da547ef6efb7
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Feb 17 20:15:56 2022 +0300

    openapi: fix milestone

commit 404d6d822fa1ba4ed4cd41d92d4c1b805342fe55
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Feb 17 20:08:21 2022 +0300

    all: fix deps, docs

commit 8fb80526f1e251d3b7b193c53a4a6dee0e22c145
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Feb 17 19:39:34 2022 +0300

    all: add querylog ecs backend
2022-06-02 16:29:22 +03:00
Eugene Burkov
b9dbe6f1b6 cherry-pick: 4213 add bsd syslog
Merge in DNS/adguard-home from 4213-bsd-syslog to master

Updates #4046.
Closes #4213.

Squashed commit of the following:

commit 1e57c75c4184e83b09cfd27456340ca9447791be
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Feb 28 16:20:32 2022 +0300

    home: imp error msg

commit 63059d031153ff9b6dc9aecd9522d2ad4f8448da
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Feb 28 15:36:37 2022 +0300

    all: imp log of changes

commit 682c3c9e8986b6bdf2d0c665c9cad4a71fd2cc83
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Feb 28 15:29:29 2022 +0300

    home: imp code

commit 86c311a71d07823c18521890bea7c898c117466b
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Feb 28 15:03:02 2022 +0300

    home: add bsd syslog
2022-06-02 16:26:25 +03:00
Ainar Garipov
7fec111ef8 cherry-pick: home: imp openbsd init script
Closes #4533.

Squashed commit of the following:

commit 48ca9e100619e714eab565273daeb4ee9adb5b74
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Apr 28 20:25:15 2022 +0300

    home: imp openbsd init script
2022-06-02 16:25:01 +03:00
Eugene Burkov
5e1bd99718 cherry-pick: 4276 upd quic port
Merge in DNS/adguard-home from 4276-doq-port to master

Closes #4276.

Squashed commit of the following:

commit cbdde622b54d0d5d11d1b4809f95a41ace990a1b
Merge: d32c13e9 2c33ab6a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Mar 23 15:47:43 2022 +0300

    Merge branch 'master' into 4276-doq-port

commit d32c13e98f0fed2c863160e4e2de02ae3038e3df
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Mar 21 21:55:09 2022 +0300

    all: fix link

commit 0afd702f5192d727927df2f8d95b9317811a1be0
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Mar 21 21:47:38 2022 +0300

    all: imp docs, log changes

commit 9a77fc3daf78d32c577f1bc49aa1f8bc352d44e3
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Mar 21 21:41:30 2022 +0300

    home: upd quic port
2022-06-02 16:23:15 +03:00
Eugene Burkov
9d75f72ceb cherry-pick: 1730 bogus cidr
Merge in DNS/adguard-home from 1730-bogus-cidr to master

Closes #1730.

Squashed commit of the following:

commit 0be54259ca4edb8752e9f7e5ea5104a2b51ed440
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jan 25 18:50:01 2022 +0300

    all: imp log of changes

commit 59fb7a8c469216823ff54621ec40a4d084836132
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jan 25 18:46:34 2022 +0300

    all: log changes

commit 9206b13dd715fdf1180d1d572d1b80024b9e6592
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jan 25 18:41:26 2022 +0300

    all: upd dnsproxy
2022-06-02 16:20:41 +03:00
Ainar Garipov
d98d96db1a all: upd chlog 2022-06-02 16:09:50 +03:00
Ainar Garipov
6a0ef2df15 all: upd chlog, go 2022-04-13 14:30:17 +03:00
Dimitry Kolyshev
75c2eb4c8a cherry-pick: svcb dohpath support
Merge in DNS/adguard-home from 4463-ddr-support to master

Squashed commit of the following:

commit 99a149e9024354ad0341739c3c9b08cefbd74468
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Apr 12 14:13:17 2022 +0200

    imp docs

commit 26150be8df8b35e47c108f6e3319c57b39fb8e38
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Apr 11 20:36:18 2022 +0200

    imp code docs

commit 5a4607f71abba83a9ac8753abd74c9fb97e4a545
Merge: 00f0abf5 9f0fdc5e
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Apr 11 16:14:49 2022 +0200

    Merge remote-tracking branch 'origin/master' into 4463-ddr-support

    # Conflicts:
    #	internal/dnsforward/svcbmsg.go

commit 00f0abf5eea07aeeebc2a856a958215021a51ab7
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Apr 11 16:06:42 2022 +0200

    svcb dohpath support

commit ace81ce1ea2fb96c4434c6c1fded4a79427cf17e
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Apr 7 14:31:32 2022 +0200

    svcb dohpath support

commit a1b5df4fb2e87dab265d6ca55928610a6acc1c00
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Apr 6 16:53:17 2022 +0200

    svcb dohpath support
2022-04-12 21:09:28 +03:00
Dimitry Kolyshev
d021a67d66 cherry-pick: upd bamboo-specs snapcraft
Merge in DNS/adguard-home from upd-bamboo-spec to master

Squashed commit of the following:

commit c26c70f97cbce98afd5c7d4241188d6949869c2a
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Fri Apr 8 13:51:23 2022 +0200

    upd bamboo-specs snapcraft

commit afe40c03b70d2b2dff9c7c25044d7924bdd3c765
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Fri Apr 8 13:10:38 2022 +0200

    upd bamboo-specs snapcraft
2022-04-12 21:09:04 +03:00
Ainar Garipov
4ed97cab12 cherry-pick: dnsforward: upd svcp param ech name
Merge in DNS/adguard-home from upd-ech-dnsrewrite to master

Squashed commit of the following:

commit b5d9e8643fcb0d7fe7bc44c6d8fc8a9d3f2c9595
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Apr 7 18:01:18 2022 +0300

    all: imp chlog

commit 447c5ea6bc2031d4af46578bdb8d724bff001ca0
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Apr 7 15:40:18 2022 +0300

    dnsforward: upd svcp param ech name
2022-04-12 21:08:40 +03:00
Eugene Burkov
a38742eed7 cherry-pick: 4437 imp help output
Merge in DNS/adguard-home from imp-help to master

Updates #4437.

Squashed commit of the following:

commit 941338b93e19021c5b211e9e644387e4326533ce
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Apr 7 13:59:55 2022 +0300

    home: imp help output
2022-04-12 21:08:24 +03:00
Eugene Burkov
5efa95ed26 cherry-pick: 4437 depr memory opt
Merge in DNS/adguard-home from 4437-rm-mem-opt to master

Updates #4437.
Updates #2044.

Squashed commit of the following:

commit d1e5520213f6b68570d18a8d831d4923112901ba
Merge: 73a6b494 8bb95469
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Apr 6 19:37:09 2022 +0300

    Merge branch 'master' into 4437-rm-mem-opt

commit 73a6b4948cb32f1cb79a54b244018b29382fad76
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Apr 6 18:33:23 2022 +0300

    all: imp log of changes

commit a62efcdcd44de300726c906c7f6198c0a02d4ccf
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Apr 6 18:27:42 2022 +0300

    home: depr memory opt
2022-04-12 21:07:46 +03:00
Ildar Kamalov
04db7db607 cherry-pick: 700 validate only enabled encryption form
Merge in DNS/adguard-home from 700-validate to master

Updates #700.

Squashed commit of the following:

commit 9cd9ff2d23352e00c7782cf68195809111c832e5
Author: Ildar Kamalov <ik@adguard.com>
Date:   Wed Apr 6 18:50:11 2022 +0300

    client: validate only enabled encryption form
2022-04-12 21:07:26 +03:00
Ainar Garipov
d17c6c6bb3 all: upd go, chlog, tools 2022-04-06 18:27:21 +03:00
Ildar Kamalov
b2052f2ef1 cherry-pick: fix down flag
Squashed commit of the following:

commit ea446e844a21e7e7e0271d4d133c581014facda1
Merge: bb8cabfa 5e71f5df
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu Mar 31 10:49:20 2022 +0300

    Merge branch 'master' into client-down-flag

commit bb8cabfae8e2e3eaa09f48ffe7d2fb3b308d31fb
Author: Ildar Kamalov <ik@adguard.com>
Date:   Wed Mar 30 19:27:30 2022 +0300

    client: fix down flag
2022-04-06 17:50:54 +03:00
Eugene Burkov
cddcf852c2 cherry-pick: aghnet: fix catching timeout errors
Merge in DNS/adguard-home from fix-is-timeout to master

Squashed commit of the following:

commit b0fefd01f27a835a34e44beb2eb2c34027960a51
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Mar 29 15:57:06 2022 +0300

    aghnet: fix catching timeout errors
2022-04-06 17:50:27 +03:00
Eugene Burkov
1def426b45 cherry-pick: add go sumdb env
Merge in DNS/adguard-home from cn-sumdb to master

Squashed commit of the following:

commit 439973292f473efa72fb6a733a32be45e634274e
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Mar 28 16:51:28 2022 +0300

    Makefile: add go sumdb env
2022-04-06 17:50:08 +03:00
Ainar Garipov
b114fd5279 cherry-pick: home: fix types
Updates #4424.

Squashed commit of the following:

commit 784b4940d46ce74edbfbbde6e5b24f95dcb4bc70
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Mar 24 17:07:41 2022 +0300

    home: fix types
2022-04-06 17:49:44 +03:00
Eugene Burkov
d27c3284f6 cherry-pick: 4276 upd quic port
Merge in DNS/adguard-home from 4276-doq-port to master

Closes #4276.

Squashed commit of the following:

commit cbdde622b54d0d5d11d1b4809f95a41ace990a1b
Merge: d32c13e9 2c33ab6a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Mar 23 15:47:43 2022 +0300

    Merge branch 'master' into 4276-doq-port

commit d32c13e98f0fed2c863160e4e2de02ae3038e3df
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Mar 21 21:55:09 2022 +0300

    all: fix link

commit 0afd702f5192d727927df2f8d95b9317811a1be0
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Mar 21 21:47:38 2022 +0300

    all: imp docs, log changes

commit 9a77fc3daf78d32c577f1bc49aa1f8bc352d44e3
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Mar 21 21:41:30 2022 +0300

    home: upd quic port
2022-04-06 17:49:12 +03:00
Ildar Kamalov
ba24a26b53 cherry-pick: 4409 fix icons height
Updates #4409

Squashed commit of the following:

commit 132073ccf00ba6eb6ddacfc82c8d2e01f3d4b011
Author: Ildar Kamalov <ik@adguard.com>
Date:   Mon Mar 21 15:22:33 2022 +0300

    client: remove height

commit 29970f33e7af26e406c442510d626fc0cfdae0ce
Merge: 96b3abcf 77858586
Author: Ildar Kamalov <ik@adguard.com>
Date:   Mon Mar 21 15:10:49 2022 +0300

    Merge branch 'master' into 4409-icon

commit 96b3abcfa4561da466cc53331b8f751d55f59351
Author: Ildar Kamalov <ik@adguard.com>
Date:   Mon Mar 21 10:22:55 2022 +0300

    client: fix icons height
2022-04-06 17:44:11 +03:00
Eugene Burkov
3e6678b6b4 cherry-pick: filtering: fix qq regex legacy
Merge in DNS/adguard-home from qq-rule to master

Updates #3717.

Squashed commit of the following:

commit 1e2d50077067e5f95da645091686349ce9c8a6bc
Merge: 7290a1c4 b16b1d1d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Mar 23 14:14:10 2022 +0300

    Merge branch 'master' into qq-rule

commit 7290a1c456a7f47e91cc9485f5e112b92cb595ba
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Mar 18 20:36:17 2022 +0300

    filtering: fix qq regex legacy
2022-04-06 17:43:05 +03:00
Ainar Garipov
83fd6f9782 cherry-pick: Fix unsupported regex for QQ blocked rules
Updates #3717.

* commit 'ded9842cd7fbbae0c3a55cd1f468ade22cab0d97':
  Fix unsupported regex for QQ blocked rules
2022-04-06 17:42:49 +03:00
Ainar Garipov
52bc1b3f10 all: upd go, chlog 2022-03-04 15:38:59 +03:00
Ainar Garipov
dd2153b7ac cherry-pick: scripts: imp snap building
Closes #4239.

Squashed commit of the following:

commit 942c03bd88b81d813a12136a135ca6dc003fedf3
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Feb 9 20:38:36 2022 +0300

    scripts: imp snap building
2022-03-01 15:44:43 +03:00
Ainar Garipov
dd96a34861 all: upd chlog 2022-03-01 15:15:59 +03:00
Ainar Garipov
daf26ee25a all: upd chlog 2022-03-01 15:12:34 +03:00
Ainar Garipov
7e140eaaac cherry-pick: client: upd i18n
Merge in DNS/adguard-home from 2643-upd-i18n to master

Squashed commit of the following:

commit 1f36b960877ee2c30319e26132db892fb8a2ef71
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Mar 1 15:05:24 2022 +0300

    client: upd i18n
2022-03-01 15:11:21 +03:00
Ainar Garipov
d07a712988 all: upd chlog 2022-02-28 19:15:59 +03:00
Ainar Garipov
95863288bf cherry-pick: client: fix link in client form
Updates #4244.

Squashed commit of the following:

commit 20d558e9e6935555a13e1aebc7d364e6f1910e9e
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Feb 28 19:01:32 2022 +0300

    client: fix link in client form
2022-02-28 19:14:46 +03:00
Ainar Garipov
ea12be658b all: upd chlog 2022-02-21 17:10:19 +03:00
Ainar Garipov
faa7c9aae5 cherry-pick: client: upd i18n
Updates #2643.

Squashed commit of the following:

commit 048c245ab682f0799c2f7a7f0435a1898a482392
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Feb 21 16:58:10 2022 +0300

    client: upd i18n
2022-02-21 17:08:25 +03:00
Ainar Garipov
e3653e8c25 all: upd chlog 2022-02-18 21:01:24 +03:00
Ainar Garipov
b40cb24822 all: upd chlog 2022-02-14 17:14:37 +03:00
Ainar Garipov
74004c1aa0 cherry-pick: client: use strict search by client
Updates #4271.

Squashed commit of the following:

commit 10a113126306fce51b4dd10a696b8c7d3213a445
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Feb 11 18:37:18 2022 +0300

    client: more strict search

commit 7aa24129195c0eba442bfe43564469fdb2a5b138
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Feb 11 18:22:18 2022 +0300

    client: use strict search by client
2022-02-14 17:06:16 +03:00
Ainar Garipov
3e240741f1 cherry-pick: scripts: imp mips compat
Updates #4269.

Squashed commit of the following:

commit f633e875f4f0ab767a0537d9bfe95734823f8a51
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Feb 11 17:33:53 2022 +0300

    scripts: imp mips compat
2022-02-14 17:06:06 +03:00
Ainar Garipov
6cfdbef1a5 cherry-pick: client: imp validation texts
Merge in DNS/adguard-home from imp-i18n to master

Squashed commit of the following:

commit c58c00383824a88ea8e22a845e422ba2ff7d225e
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Feb 10 20:21:00 2022 +0300

    client: imp validation texts
2022-02-14 17:05:33 +03:00
Ainar Garipov
d9bde6425b cherry-pick: all: use "ClientID" consistently
Closes #4242.
Updates #4244.

Squashed commit of the following:

commit 3a2296a7a70006cf6777e54ce1e2fc3559aec5be
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Feb 9 21:23:43 2022 +0300

    client: imp more

commit 3aacc8696ac694ff459fd33ba7beeeabd2569a55
Merge: b28a120f 2a5b5f19
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Feb 9 21:21:59 2022 +0300

    Merge branch 'master' into 4244-imp-i18n

commit b28a120fe9aa68507b173717059b7b259097d6a4
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Feb 9 14:49:49 2022 +0300

    client: imp texts more

commit c1fa6ca336f2d5bdcc67836f348be4843a0a8f79
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Feb 8 21:12:15 2022 +0300

    all: use "ClientID" consistently
2022-02-14 17:04:33 +03:00
Ainar Garipov
e2ae9e1591 cherry-pick: client: upd i18n
Merge in DNS/adguard-home from upd-i18n to master

Squashed commit of the following:

commit e2f9e9f52a424b7c13beebfc2f8fea3814d3b2f4
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Feb 8 13:48:17 2022 +0300

    client: upd i18n
2022-02-14 17:04:18 +03:00
Ainar Garipov
5ebcbfa9ad all: upd go 2022-02-11 16:27:53 +03:00
Ainar Garipov
e276bd7a31 all: upd chlog, minimize diff to master 2022-02-07 20:35:33 +03:00
Eugene Burkov
659b2529bf cherry-pick: upd changelog
Merge in DNS/adguard-home from changelog-right-now to master

Squashed commit of the following:

commit b391a1f8ac666de67ad6d00c9cbf6e90614f16c7
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Feb 7 20:18:25 2022 +0300

    fix changelog

commit 39878b75c9ecc91668be759d4cc033961c91c2c5
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Feb 7 20:15:43 2022 +0300

    all: log changes
2022-02-07 20:26:43 +03:00
Eugene Burkov
97b3ed43ab cherry-pick: 4254 fix optimistic
Merge in DNS/adguard-home from 4254-fix-optimistic to master

Updates #4254.

Squashed commit of the following:

commit 652e2c2ab9405b9a6ed5d153b6b508e3b87ce66e
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Feb 7 18:55:34 2022 +0300

    all: upd proxy
2022-02-07 20:23:51 +03:00
Ainar Garipov
767d6d3f28 cherry-pick: all: add gh milestone links to chlog
Merge in DNS/adguard-home from chlog-ms-links to master

Squashed commit of the following:

commit 97156f1452a7713e5e8d66a9b5eeac25fb97ab04
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Feb 4 17:56:58 2022 +0300

    all: add gh milestone links to chlog
2022-02-07 20:12:54 +03:00
Ainar Garipov
31fc9bfc52 cherry-pick: scripts: add link to platforms page
Closes #4209.

Squashed commit of the following:

commit 12d99e7454ff01e00f29e51d002147a04a77a2b3
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Feb 1 19:55:31 2022 +0300

    scripts: imp docs

commit 12c4dabea2bac04601202a05d0c820ff2e32c93e
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Feb 1 19:49:16 2022 +0300

    scripts: add link to platforms page
2022-02-07 20:10:11 +03:00
Ainar Garipov
3f06b02409 cherry-pick: all: imp ann url
Updates #4209.

Squashed commit of the following:

commit 0c31a59c5bf6bcc27a4779adf226d9a1ac9eece1
Merge: 803f32db 8455940b
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Feb 1 19:33:55 2022 +0300

    Merge branch 'master' into 4209-ann-url

commit 803f32dbc7276077a4374ed0f5e0a1fa36f91c9b
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Feb 1 14:46:47 2022 +0300

    client: add manual update link to update topline

commit ca375b52fa53503a3987b9723eb9a1d74878e890
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Jan 31 20:49:42 2022 +0300

    all: imp ann url
2022-02-07 20:09:54 +03:00
Ildar Kamalov
5bf958ec6b cherry-pick: 4212 fix query log search results
Closes #4212.

Squashed commit of the following:

commit cd854e5bf71953c753c690c28b5571f2c8b1ea0f
Merge: 8532ca80 bf9b35b9
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Jan 31 20:10:17 2022 +0300

    Merge branch 'master' into 4212-logs

commit 8532ca80d135e4c306ac4d0c999475d77ba51a02
Author: Ildar Kamalov <ik@adguard.com>
Date:   Mon Jan 31 19:22:52 2022 +0300

    fix lint

commit 1a85074180d95d7a7aad854c75a7a811aee719e9
Author: Ildar Kamalov <ik@adguard.com>
Date:   Mon Jan 31 19:14:54 2022 +0300

    client: fix query log search results
2022-02-07 20:09:27 +03:00
Ainar Garipov
959d9ff9a0 cherry-pick: client: upd manual upd link
Closes #4208.

Squashed commit of the following:

commit 4ae27b5f7cd6b0f4ec0c9041d92c4d1ac00dd622
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Jan 31 18:34:18 2022 +0300

    client: upd manual upd link
2022-02-07 20:09:09 +03:00
Ainar Garipov
4813b4de25 all: upd chlog, minimize diff to master 2022-01-28 17:44:10 +03:00
Eugene Burkov
119100924c cherry-pick: 4216 simpl hosts
Merge in DNS/adguard-home from 4216-hosts-explode to master

Updates #4216.

Squashed commit of the following:

commit a6ed131923496d9bbd1d80c652d4584951528c4a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jan 27 19:11:23 2022 +0300

    aghnet: imp docs

commit 25cca065c3c6dc227288cdd0803dc3ff8f9c3ca4
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jan 27 18:53:16 2022 +0300

    aghnet: simpl hosts container
2022-01-28 16:31:04 +03:00
Ainar Garipov
bd584de4ee cherry-pick: 4162 fix theme color
Updates #4162.

* commit '2263adbbe0c14cb914451d131d94ab6fd236852c':
  Update login.html
  Update install.html
  Update index.html
2022-01-28 16:30:35 +03:00
Ainar Garipov
ede85ab2f2 all: upd chlog 2022-01-25 14:12:12 +03:00
Ainar Garipov
12c20288e4 cherry-pick: client: upd i18n
Updates #2643.

Squashed commit of the following:

commit bd6bc0aeaa1bd928ae39642691b913befbc0f396
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Jan 25 14:04:10 2022 +0300

    client: upd i18n
2022-01-25 14:11:12 +03:00
Ainar Garipov
5bbbf89c10 cherry-pick: all: upd dnsproxy
Merge in DNS/adguard-home from imp-logs to master

Squashed commit of the following:

commit bff4c3757b61db63320af72e1af56649f6f70a50
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Jan 24 17:25:34 2022 +0300

    all: upd dnsproxy
2022-01-24 17:44:54 +03:00
Eugene Burkov
d55393ecd5 cherry-pick: client: upd i18n
Merge in DNS/adguard-home from upd-i18n to master

Squashed commit of the following:

commit e3dfb6cd66813d45591f74c9cdddab8b61143db3
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Jan 24 14:52:19 2022 +0300

    client: upd i18n
2022-01-24 17:41:04 +03:00
Eugene Burkov
2b5927306f cherry-pick: 2846 cover aghnet vol.1
Merge in DNS/adguard-home from 2846-cover-aghnet-vol.1 to master

Updates #2846.

Squashed commit of the following:

commit 368e75b0bacb290f9929b8a5a682b06f2d75df6a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jan 21 19:11:59 2022 +0300

    aghnet: imp tests

commit 8bb3e2a1680fd30294f7c82693891ffb19474c6a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jan 21 18:27:06 2022 +0300

    aghnet: rm unused test

commit 28d8e64880f845810d0af629e5d1f06b9bde5b28
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jan 21 18:18:22 2022 +0300

    aghnet: cover with tests
2022-01-21 19:24:38 +03:00
Ainar Garipov
4f016b6ed7 all: upd chlog 2022-01-21 17:11:27 +03:00
Ildar Kamalov
3a2a6d10ec cherry-pick: 3971 fix client id error message
Updates #3971

Squashed commit of the following:

commit f6b855a16daaec7bfca1e1653b4b9c4180c2d80e
Merge: 0cb31dbb 5ec4a4da
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu Jan 20 18:19:20 2022 +0300

    Merge branch 'master' into 3971-client-id

commit 0cb31dbbea785fb5ba11a8efe2b6653aece7cd97
Author: Natalia Sokolova <n.sokolova@adguard.com>
Date:   Thu Jan 20 11:41:06 2022 +0300

    client/src/__locales/en.json edited online with Bitbucket

commit 7999f260d83adcb2fc8d5d5e40cb1934e0333873
Author: Ildar Kamalov <ik@adguard.com>
Date:   Wed Jan 19 15:58:18 2022 +0300

    client: fix client id error message
2022-01-21 17:08:07 +03:00
Eugene Burkov
2491426b09 cherry-pick: 4142 stats panic
Merge in DNS/adguard-home from 4142-stats-panic to master

Updates #4142.

Squashed commit of the following:

commit bf168f50ac86bdfdab73bf7285705f09f87b6c72
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jan 20 17:13:41 2022 +0300

    stats: imp more

commit bb638211da7d0c51959ded2dacb72faea00befb4
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jan 20 17:09:31 2022 +0300

    stats: imp code quality

commit 27ac52f15e4e0f4112ce7a6b47b03f963463393e
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jan 20 17:00:09 2022 +0300

    stats: recover panic on init

commit 1ffcebbb9062438170b010e1c7bad3c6cef4cfc1
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jan 20 14:19:01 2022 +0300

    all: fix some typos
2022-01-21 17:08:07 +03:00
Ildar Kamalov
5ebdd1390e cherry-pick: 4143 sort client ids
Merge in DNS/adguard-home from 4143-clients-sort to master

Updates #4143.

Squashed commit of the following:

commit a4b547eb46a54bdfdc7d342fab5f8ecfa54f5d06
Merge: d369c11c d82b2902
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu Jan 20 11:58:42 2022 +0300

    Merge branch 'master' into 4143-clients-sort

commit d369c11c69665510043f63e0283e1ca1b2974289
Author: Ildar Kamalov <ik@adguard.com>
Date:   Wed Jan 19 16:53:39 2022 +0300

    client: fix sort ip method

commit d767a1199c37ad9df7f3bc2d362d840b0226d836
Author: Ildar Kamalov <ik@adguard.com>
Date:   Wed Jan 19 16:23:23 2022 +0300

    client: sort client ids
2022-01-21 17:08:07 +03:00
Eugene Burkov
b7f0247575 cherry-pick: 4095 fix duplicating port
Merge in DNS/adguard-home from 4095-port-3000 to master

Updates #4095.

Squashed commit of the following:

commit 968cc806264898523d29c4ec20b3ce6a69abb09c
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Jan 19 20:26:33 2022 +0300

    home: fix typo

commit 03c6798db6a4ca726a7b5a683e475a8a74f79fe1
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Jan 19 20:20:34 2022 +0300

    all: more naming imps

commit d3d417fcb24a1859f53a743b3533faa81b6bef19
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Jan 19 20:10:14 2022 +0300

    aghalgo: rename into aghalg

commit 6e106006d07a747ff4ddf1271532106c3a3e2b20
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Jan 19 20:05:43 2022 +0300

    all: imp names, docs

commit 12c8d9fde0d0cc5b953da30b042171ba7c53da5d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Jan 19 19:57:21 2022 +0300

    all: fix log of changes

commit 49c7a705b9b1ad8f2ef68fa807f9b6b8c447b421
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Jan 19 19:51:00 2022 +0300

    home: fix duplicating port 3000
2022-01-21 17:08:07 +03:00
Ainar Garipov
e28186a28a cherry-pick: scripts: imp sh lint 2022-01-21 17:08:03 +03:00
Eugene Burkov
de1a7ce48f cherry-pick: 4133 empty rewrite
Merge in DNS/adguard-home from 4133-empty-rewrite to master

Closes #4133.

Squashed commit of the following:

commit 4d2313c211c3955922d340c006b323c65e5e5ba4
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jan 18 21:36:21 2022 +0300

    all: log changes

commit 5b8e392a2225c215fc117223d3f6553f8bdf21cd
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jan 18 21:32:57 2022 +0300

    all: upd urlfilter
2022-01-21 17:02:42 +03:00
Ainar Garipov
48480fb33b cherry-pick: home: show version in install api
Closes #4026.

Squashed commit of the following:

commit bcd1315a10e819daee3aee323427d90a27860b4a
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Jan 18 14:57:49 2022 +0300

    openapi: fix example

commit b56e27c5ac1fc7c3f595057d77607479d72ec50a
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Jan 18 14:55:51 2022 +0300

    client: show version on install page

commit 95dfbfaa1235deef7b55e51457d11c677f6ef6b5
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Jan 18 14:29:08 2022 +0300

    home: show version in install api
2022-01-21 16:59:57 +03:00
Eugene Burkov
f41332fe6b cherry-pick: 4120 service domain validation
Merge in DNS/adguard-home from 4120-fix-services to master

Closes #4120.

Squashed commit of the following:

commit ca2e5faf64f567cc6647a300181712236158e69d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jan 18 14:14:54 2022 +0300

    dnsforward: imp docs

commit 9ed5f536e691dcdee5b7c94e161c738d31ff8588
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jan 18 13:50:33 2022 +0300

    dnsforward: fix reverse domain validation
2022-01-21 16:59:39 +03:00
Ainar Garipov
1f8b340b8f cherry-pick: all: upd dnsproxy
Updates #4065.

Squashed commit of the following:

commit d65d2e3a783910b9cb95c5bcfbcf1af11da666d5
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Jan 17 18:47:17 2022 +0300

    all: upd dnsproxy
2022-01-21 16:57:39 +03:00
Eugene Burkov
fdaf1d09d3 cherry-pick: 4074 fix upstream test
Merge in DNS/adguard-home from 4074-upstream-test to master

Updates #4074.

Squashed commit of the following:

commit 0de155b1e175a892b259791ff6d6e6f351bcfcf2
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Jan 12 19:20:01 2022 +0500

    dnsforward: fix upstream test
2022-01-21 16:50:46 +03:00
Eugene Burkov
b9682c4f10 cherry-pick: 4079 fix hosts container aliases
Merge in DNS/adguard-home from 4079-hosts-again to master

Updates #4079.

Squashed commit of the following:

commit 6aa8cbf32e8e47ba46bf5fba7681a10b68b4bc01
Merge: 19dba371 34c95f99
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Jan 12 14:05:30 2022 +0500

    Merge branch 'master' into 4079-hosts-again

commit 19dba371cc30ab8b75b0116833f4ecf0ef0f182f
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Jan 12 14:05:20 2022 +0500

    aghnet: imp docs

commit 9f341eb8ee4ba8468240bc3eeeb4951a3f7f5e6d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Jan 10 18:44:17 2022 +0500

    aghnet: fix races

commit fd66191c7637c8584711e5bb8186494327ce0f87
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Jan 6 17:21:14 2022 +0500

    aghnet: fix hosts container aliases
2022-01-21 16:48:17 +03:00
Eugene Burkov
69dcb4effd cherry-pick: 4046 darwin service message
Merge in DNS/adguard-home from 4046-log-dir to master

Closes #4046.

Squashed commit of the following:

commit 05140550b14f477f52487c575f56428ce9e6fa10
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Jan 5 17:54:11 2022 +0500

    all: add macOS service msg
2022-01-21 16:47:34 +03:00
Ainar Garipov
d50fd0ba91 all: upd chlog 2021-12-29 22:39:11 +03:00
Ainar Garipov
c2c7b4c731 cherry-pick: all: upd dnsproxy
Updates #4042.

Squashed commit of the following:

commit 7531b974a6142fafee825ce9ca2ea202619b95af
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Dec 29 22:01:54 2021 +0300

    all: upd dnsproxy
2021-12-29 22:38:22 +03:00
Ainar Garipov
952d5f3a3d all: fix release script 2021-12-29 19:20:26 +03:00
Ainar Garipov
3f126c9ec9 all: prepare chlog 2021-12-29 16:22:14 +03:00
Ainar Garipov
0be58ef918 all: imp chlog 2021-12-29 16:16:40 +03:00
Ainar Garipov
8f9053e2fc all: backport, prepare release 2021-12-29 16:09:01 +03:00
Ainar Garipov
68452e5330 cherry-pick: client: upd i18n
Updates #2643.

Squashed commit of the following:

commit bc3de579e00762bc2c4b62fb1f7ba73837c10bff
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Dec 29 15:37:29 2021 +0300

    client: upd si-lk i18n again

commit 2cd5436b6e8c1918855aff58dd0958fe47b47e90
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Dec 29 15:08:21 2021 +0300

    client: upd i18n
2021-12-29 16:03:34 +03:00
Ainar Garipov
2eacc46eaa cherry-pick: all: opt log levels more
Updates #3929.

Squashed commit of the following:

commit 0d4aadeff1c4de1440795faf83eb072c46392ff3
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Dec 28 16:34:44 2021 +0300

    all: opt log levels more
2021-12-29 16:03:23 +03:00
Ainar Garipov
74dcc91ea7 cherry-pick: all: imp uniq validation err msgs
Updates #3975.

Squashed commit of the following:

commit f8578c2afb1bb5786e7b855a1715e0757bc08510
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Dec 28 16:39:13 2021 +0300

    aghalgo: imp docs

commit d9fc625f7c4ede2cf4b0683ad5efd0ddf9b966b1
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Dec 28 16:21:24 2021 +0300

    all: imp uniq validation err msgs
2021-12-29 16:03:03 +03:00
Ainar Garipov
dd7bf61323 cherry-pick: aghnet: fix ipset init errors
Updates #4027.

Squashed commit of the following:

commit 9ac0cc27ca94e630cc321c90b60b271499af4d9b
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Dec 27 20:26:22 2021 +0300

    aghnet: fix ipset init errors
2021-12-29 16:02:50 +03:00
Ainar Garipov
2819d6cace cherry-pick: filtering: fix rw to subdomain
Updates #4016.

Squashed commit of the following:

commit 83bb15c5a5098103cd17e76b49f456fb4fa73408
Merge: 81905503 313555b1
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Dec 27 19:36:44 2021 +0300

    Merge branch 'master' into 4016-rw-subdomain

commit 81905503c977c004d7ddca1d4e7537bf76443a6e
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Dec 27 19:35:51 2021 +0300

    filtering: fix self reqs

commit b706f481f00232d28dade0bd747a7496753c7deb
Merge: 29cf83de 661f4ece
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Dec 27 19:13:08 2021 +0300

    Merge branch 'master' into 4016-rw-subdomain

commit 29cf83de8e3ff60ea1c471c2a161055b1377392d
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Dec 27 19:07:08 2021 +0300

    all: fix docs

commit 9213fd8ec2b81e65b1198ab241400065f14684b1
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Dec 27 18:44:06 2021 +0300

    filtering: fix rw to subdomain
2021-12-29 16:02:04 +03:00
Eugene Burkov
75355a6883 cherry-pick: 3868 log freebsd reload fix
Merge in DNS/adguard-home from 3868-changelog to master

Squashed commit of the following:

commit 92ccf7422c4c1342c160e4806cbf9fb17c22749b
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Dec 27 19:22:47 2021 +0300

    all: log more changes
2021-12-29 16:01:31 +03:00
Eugene Burkov
e9c007d56b cherry-pick: 3868 imp service uninstall
Merge in DNS/adguard-home from 3868-imp-uninstall to master

Closes #3868.
Updates #3457.

Squashed commit of the following:

commit 6f50713407980c27e5b14bef4dc8839e134ec5c8
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Dec 27 19:06:13 2021 +0300

    all: imp openwrt

commit 59f058f8ec7f5ac8cb795bf837c396601652a6ff
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Dec 27 17:26:32 2021 +0300

    all: imp code && docs

commit bab95366b0ffa40d96de5bb8116ec14606e310ed
Merge: 92ebc210 52f36f20
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Dec 27 17:06:25 2021 +0300

    Merge branch 'master' into 3868-imp-uninstall

commit 92ebc210f04d5e02c3eef726017a0d5687f4bc4c
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Dec 27 13:18:58 2021 +0300

    home: imp freebsd script & log changes

commit 583ffc256e9f87cf19da2eca8bbefc9e00ea86cc
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Dec 16 14:08:46 2021 +0300

    all: imp service uninstall
2021-12-29 16:01:09 +03:00
Ainar Garipov
84c9085516 cherry-pick: filtering: restore rewrite behavior with other question types
Updates #4008.

Squashed commit of the following:

commit babbc29331cfc2603c0c3b0987f5ba926690ec3e
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Dec 24 18:46:20 2021 +0300

    filtering: restore rewrite behavior with other question types
2021-12-24 22:41:10 +03:00
Ainar Garipov
9f36e57c1e cherry-pick: all: opt log levels
Updates #3929.

Squashed commit of the following:

commit bfb2361d81a0667c36193484ca125d08e5638b21
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Dec 24 17:23:39 2021 +0300

    all: opt log levels
2021-12-24 22:41:10 +03:00
Eugene Burkov
7528699fc2 cherry-pick: 3987 Fix nil pointer dereference
Merge in DNS/adguard-home from 3987-fix-nil-deref to master

Updates #3987.
Updates #2846.

Squashed commit of the following:

commit d653e09ce88a8b10b2a17fea1563c419895c714c
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Dec 23 20:08:51 2021 +0300

    all: log changes

commit c47a4eeacf76fa7df2d01af166dee9d52528ac58
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Dec 23 19:22:39 2021 +0300

    aghnet: fix windows tests

commit 9c91f14ccfe967ada3c00ddb86d673238e52c12d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Dec 23 19:09:49 2021 +0300

    aghnet: imp code readability, docs

commit d3df15d1892e4ebfe7f8ea7144e39a0c712fce52
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Dec 23 18:47:28 2021 +0300

    aghnet: fix nil pointer dereference
2021-12-24 22:41:10 +03:00
Eugene Burkov
d280151c18 cherry-pick: 3998 Make hosts rules match exactly
Merge in DNS/adguard-home from 3998-fix-hosts-gen to master

Closes #3998

Squashed commit of the following:

commit b565d51afb6c292dd16accd45b7d37ed386714e8
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Dec 23 16:25:02 2021 +0300

    aghnet: make hosts rules match exactly
2021-12-24 22:41:10 +03:00
Ainar Garipov
b44c755d25 cherry-pick: all: upd dnsproxy
Updates #3977.

Squashed commit of the following:

commit 3aaaacac102cdea04ae46b36d2dd3a3be7d50147
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Dec 23 16:15:11 2021 +0300

    all: upd dnsproxy
2021-12-24 22:41:05 +03:00
Ainar Garipov
e4078e87a1 cherry-pick: 3945 log success
Updates #3945.

* commit 'ebe86ce00ebca3431a96a44c3616af3ac42250ab':
  home: imp auth
  Log successful login attempts in addition to failed ones
2021-12-24 22:23:22 +03:00
Eugene Burkov
be36204756 cherry-pick: Update miekg/dns
Merge in DNS/adguard-home from upd-dns-lib to master

Updates #2275.

Squashed commit of the following:

commit 54d0485157ac4f08830ad7d8ca9be49eef87d678
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Dec 23 13:31:34 2021 +0300

    all: upd dns lib
2021-12-24 22:22:47 +03:00
Ainar Garipov
b5409d6d00 cherry-pick: client: imp en i18n
Merge in DNS/adguard-home from en-i18n-safe-browsing to master

Squashed commit of the following:

commit dd32a58c3761818a10386b4a1d9e6871da59c71e
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Dec 22 17:31:35 2021 +0300

    client: imp en i18n
2021-12-24 22:19:07 +03:00
Ainar Garipov
f3d6bce03e cherry-pick: scripts: add network-control plug
Updates #3976.

Squashed commit of the following:

commit 49d8a3a2d333c7896530c8a44c5ef06c396b5ae0
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Dec 22 16:20:45 2021 +0300

    scripts: add network-control plug
2021-12-24 22:18:19 +03:00
87 changed files with 1482 additions and 3280 deletions

View File

@@ -9,46 +9,18 @@ The format is based on [*Keep a Changelog*](https://keepachangelog.com/en/1.0.0/
<!--
## [v0.108.0] TBA
## [v0.107.62] - 2025-04-30 (APPROX.)
See also the [v0.107.62 GitHub milestone][ms-v0.107.62].
[ms-v0.107.62]: https://github.com/AdguardTeam/AdGuardHome/milestone/97?closed=1
NOTE: Add new changes BELOW THIS COMMENT.
-->
### Fixed
- Command line option `--update` when the `dns.serve_plain_dns` configuration property was disabled ([7801]).
- DNS cache not working for custom upstream configurations.
- Validation process for the DNS-over-TLS, DNS-over-QUIC, and HTTPS ports on the *Encryption Settings* page.
[#7801]: https://github.com/AdguardTeam/AdGuardHome/issues/7801
<!--
NOTE: Add new changes ABOVE THIS COMMENT.
-->
## [v0.107.61] - 2025-04-22
## [v0.107.61] - 2025-04-22 (APPROX.)
See also the [v0.107.61 GitHub milestone][ms-v0.107.61].
### Security
- Any simultaneous requests that are considered duplicates will now only result in a single request to upstreams, reducing the chance of a cache poisoning attack succeeding. This is controlled by the new configuration object `pending_requests`, which has a single `enabled` property, set to `true` by default.
**NOTE:** We thank [Xiang Li][mr-xiang-li] for reporting this security issue. It's strongly recommended to leave it enabled, otherwise AdGuard Home will be vulnerable to untrusted clients.
### Fixed
- Searching for persistent clients using an exact match for CIDR in the `POST /clients/search HTTP API`.
[mr-xiang-li]: https://lixiang521.com/
[ms-v0.107.61]: https://github.com/AdguardTeam/AdGuardHome/milestone/96?closed=1
NOTE: Add new changes BELOW THIS COMMENT.
-->
<!--
NOTE: Add new changes ABOVE THIS COMMENT.
-->
## [v0.107.60] - 2025-04-14
See also the [v0.107.60 GitHub milestone][ms-v0.107.60].
@@ -83,13 +55,15 @@ See also the [v0.107.60 GitHub milestone][ms-v0.107.60].
[#7729]: https://github.com/AdguardTeam/AdGuardHome/issues/7729
[#7734]: https://github.com/AdguardTeam/AdGuardHome/issues/7734
[go-1.24.2]: https://groups.google.com/g/golang-announce/c/Y2uBTVKjBQk
[go-1.24.2]: https://groups.google.com/g/golang-announce/c/Y2uBTVKjBQk
[ms-v0.107.60]: https://github.com/AdguardTeam/AdGuardHome/milestone/95?closed=1
## [v0.107.59] - 2025-03-21
See also the [v0.107.59 GitHub milestone][ms-v0.107.59].
### Fixed
- Rules with the `client` modifier not working ([#7708]).
- The search form not working in the query log ([#7704]).
@@ -3130,12 +3104,11 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
[ms-v0.104.2]: https://github.com/AdguardTeam/AdGuardHome/milestone/28?closed=1
<!--
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.62...HEAD
[v0.107.62]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.61...v0.107.62
-->
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.61...HEAD
[v0.107.61]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.60...v0.107.61
-->
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.60...HEAD
[v0.107.60]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.59...v0.107.60
[v0.107.59]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.58...v0.107.59
[v0.107.58]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.57...v0.107.58

View File

@@ -7,7 +7,7 @@
# Make sure to sync any changes with the branch overrides below.
'variables':
'channel': 'edge'
'dockerFrontend': 'adguard/home-js-builder:3.1'
'dockerFrontend': 'adguard/home-js-builder:3.0'
'dockerGo': 'adguard/go-builder:1.24.2--1'
'stages':
@@ -278,7 +278,7 @@
# need to build a few of these.
'variables':
'channel': 'beta'
'dockerFrontend': 'adguard/home-js-builder:3.1'
'dockerFrontend': 'adguard/home-js-builder:3.0'
'dockerGo': 'adguard/go-builder:1.24.2--1'
# release-vX.Y.Z branches are the branches from which the actual final
# release is built.
@@ -294,5 +294,5 @@
# are the ones that actually get released.
'variables':
'channel': 'release'
'dockerFrontend': 'adguard/home-js-builder:3.1'
'dockerFrontend': 'adguard/home-js-builder:3.0'
'dockerGo': 'adguard/go-builder:1.24.2--1'

View File

@@ -5,7 +5,7 @@
'key': 'AHBRTSPECS'
'name': 'AdGuard Home - Build and run tests'
'variables':
'dockerFrontend': 'adguard/home-js-builder:3.1'
'dockerFrontend': 'adguard/home-js-builder:3.0'
'dockerGo': 'adguard/go-builder:1.24.2--1'
'channel': 'development'
@@ -233,6 +233,6 @@
# Set the default release channel on the release branch to beta, as we
# may need to build a few of these.
'variables':
'dockerFrontend': 'adguard/home-js-builder:3.1'
'dockerFrontend': 'adguard/home-js-builder:3.0'
'dockerGo': 'adguard/go-builder:1.24.2--1'
'channel': 'candidate'

1207
client/package-lock.json generated vendored

File diff suppressed because it is too large Load Diff

4
client/package.json vendored
View File

@@ -66,7 +66,7 @@
"@babel/preset-react": "^7.24.1",
"@playwright/test": "1.50.1",
"@types/lodash": "^4.17.4",
"@types/node": "^22.13.10",
"@types/node": "^22.10.2",
"@types/react": "^17.0.80",
"@types/react-dom": "^18.3.0",
"@types/react-redux": "^7.1.33",
@@ -99,7 +99,7 @@
"stylelint": "^16.5.0",
"ts-loader": "^9.5.1",
"url-loader": "^4.1.1",
"vitest": "^3.1.1",
"vitest": "^3.0.4",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4",

View File

@@ -1,24 +1,24 @@
{
"client_settings": "Налады кліентаў",
"example_upstream_reserved": "upstream <0>для канкрэтных даменаў</0>;",
"example_multiple_upstreams_reserved": "некалькі сервер DNSаў <0>для канкрэтных даменаў</0>;",
"example_multiple_upstreams_reserved": "некалькі DNS-сервераў <0>для канкрэтных даменаў</0>;",
"example_upstream_comment": "каментар.",
"upstream_parallel": "Ужыць адначасныя запыты да ўсіх сервераў для паскарэння апрацоўкі запыту",
"parallel_requests": "Паралельныя запыты",
"load_balancing": "Размеркаванне нагрузкі",
"load_balancing_desc": "Запытвайце па адным серверы за раз. AdGuard Home будзе выкарыстоўваць выпадковы алгарытм для выбару сервера, так што самы хуткі сервер будзе выкарыстоўвацца часцей.",
"bootstrap_dns": "Bootstrap сервер DNSы",
"bootstrap_dns_desc": "IP-адрасы сервер DNSаў, якія выкарыстоўваюцца для вырашэння IP-адрасоў распознавальнікаў DoH/DoT, якія вы ўказваеце ў якасці перадачы. Каментары не дапускаюцца.",
"fallback_dns_title": "Рэзервовыя сервер DNSы",
"fallback_dns_desc": "Спіс рэзервовых сервер DNSаў, якія выкарыстоўваюцца, калі вышэйшыя сервер DNSы не адказваюць. Сінтаксіс такі ж, як і ў галоўным полі ўверх.",
"bootstrap_dns": "Bootstrap DNS-серверы",
"bootstrap_dns_desc": "IP-адрасы DNS-сервераў, якія выкарыстоўваюцца для вырашэння IP-адрасоў распознавальнікаў DoH/DoT, якія вы ўказваеце ў якасці перадачы. Каментары не дапускаюцца.",
"fallback_dns_title": "Рэзервовыя DNS-серверы",
"fallback_dns_desc": "Спіс рэзервовых DNS-сервераў, якія выкарыстоўваюцца, калі вышэйшыя DNS-серверы не адказваюць. Сінтаксіс такі ж, як і ў галоўным полі ўверх.",
"fallback_dns_placeholder": "Увядзіце па адным рэзервовым серверы DNS у радку",
"local_ptr_title": "Прыватныя сервер DNSы",
"local_ptr_title": "Прыватныя DNS-серверы",
"local_ptr_desc": "DNS-серверы, якія AdGuard Home выкарыстоўвае для лакальных PTR-запытаў. Гэтыя серверы выкарыстоўваюцца, каб атрымаць даменавыя імёны кліентаў з прыватнымі IP-адрасамі, напрыклад «192.168.12.34», з дапамогай rDNS. Калі спіс пусты, AdGuard Home выкарыстоўвае прадвызначаныя DNS-серверы вашай АС.",
"local_ptr_default_resolver": "Па змаўчанні AdGuard Home выкарыстоўвае наступныя зваротныя DNS-рэзолверы: {{ip}}.",
"local_ptr_no_default_resolver": "AdGuard Home не змог вызначыць прыдатныя прыватныя адваротныя DNS-рэзолверы для гэтай сістэмы.",
"local_ptr_placeholder": "Увядзіце па адным адрасе на радок",
"resolve_clients_title": "Уключыць запытванне даменавых імёнаў для кліентаў",
"resolve_clients_desc": "AdGuard Home будзе спрабаваць аўтаматычна вызначыць даменавыя імёны кліентаў праз PTR-запыты да адпаведных сервераў (прыватны сервер DNS для лакальных кліентаў, upstream-серверы для кліентаў з публічным IP-адрасам).",
"resolve_clients_desc": "AdGuard Home будзе спрабаваць аўтаматычна вызначыць даменавыя імёны кліентаў праз PTR-запыты да адпаведных сервераў (прыватны DNS-сервер для лакальных кліентаў, upstream-серверы для кліентаў з публічным IP-адрасам).",
"use_private_ptr_resolvers_title": "Ужываць прыватныя адваротныя DNS-рэзолверы",
"use_private_ptr_resolvers_desc": "Пасылаць адваротныя DNS-запыты для лакальна абслугоўных адрасоў на паказаныя серверы. Калі адключана, AdGuard Home будзе адказваць NXDOMAIN на ўсе падобныя PTR-запыты, апроч запытаў пра кліентаў, ужо вядомых па DHCP, /etc/hosts і гэтак далей.",
"check_dhcp_servers": "Праверыць DHCP-серверы",
@@ -101,13 +101,13 @@
"compact": "Компактный",
"nothing_found": "Нічога не знойдзена",
"faq": "FAQ",
"version": "Версія",
"version": "версія",
"address": "Адрас",
"protocol": "Пратакол",
"on": "УКЛ",
"off": "Выкл",
"copyright": "Усе правы захаваныя",
"homepage": "Хатняя старонка",
"homepage": "Галоўная",
"report_an_issue": "Паведаміць пра праблему",
"privacy_policy": "Палітыка прыватнасці",
"enable_protection": "Уключыць абарону",
@@ -165,8 +165,8 @@
"custom_filtering_rules": "Карыстальніцкія правілы фільтрацыі",
"encryption_settings": "Налады шыфравання",
"dhcp_settings": "Налады DHCP",
"upstream_dns": "Upstream сервер DNSы",
"upstream_dns_help": "Увядзіце адрасы сервераў па адным у радку. <a>Даведацца больш </a> пра наладжванне сервер DNSаў.",
"upstream_dns": "Upstream DNS-серверы",
"upstream_dns_help": "Увядзіце адрасы сервераў па адным у радку. <a>Даведацца больш </a> пра наладжванне DNS-сервераў.",
"upstream_dns_configured_in_file": "Наладжаны ў {{path}}",
"test_upstream_btn": "Тэст upstream сервераў",
"upstreams": "Upstreams",
@@ -182,7 +182,7 @@
"enabled_save_search_toast": "Уключаны бяспечны пошук",
"updated_save_search_toast": "Налады бяспечнага пошуку абноўлены",
"enabled_table_header": "УКЛ.",
"name_table_header": "Назва",
"name_table_header": "Імя",
"list_url_table_header": "URL-адрас спіса",
"rules_count_table_header": "Колькасць правілаў:",
"last_time_updated_table_header": "Апошняе абнаўленне",
@@ -196,7 +196,7 @@
"no_whitelist_added": "Белыя спісы не дададзены",
"add_blocklist": "Дадаць чорны спіс",
"add_allowlist": "Дадаць белы спіс",
"cancel_btn": "Скасаваць",
"cancel_btn": "Адмена",
"enter_name_hint": "Увядзіце імя",
"enter_url_or_path_hint": "Увядзіце URL-адрас ці абсалютны шлях да спіса",
"check_updates_btn": "Праверыць абнаўленні",
@@ -219,7 +219,7 @@
"example_meaning_host_block": "адказаць 127.0.0.1 для example.org (але не для яго паддаменаў);",
"example_comment": "! Так можна дадаваць апісанне.",
"example_comment_meaning": "каментар;",
"example_comment_hash": "# Таксама каментарый.",
"example_comment_hash": "# І вось так таксама.",
"example_regex_meaning": "блакаваць доступ да даменаў, якія адпавядаюць зададзенаму рэгулярнаму выразу.",
"example_upstream_regular": "звычайны DNS (наўзверх UDP);",
"example_upstream_regular_port": "звычайны DNS (праз UDP, імя хаста);",
@@ -233,13 +233,13 @@
"example_upstream_tcp_port": "звычайны DNS (праз TCP, імя хаста);",
"example_upstream_tcp_hostname": "звычайны DNS (праз TCP, імя хаста);",
"all_lists_up_to_date_toast": "Усе спісы ўжо абноўлены",
"updated_upstream_dns_toast": "Upstream сервер DNSы абноўлены",
"updated_upstream_dns_toast": "Upstream DNS-серверы абноўлены",
"dns_test_ok_toast": "Паказаныя серверы DNS працуюць карэктна",
"dns_test_not_ok_toast": "Сервер «{{key}}»: немагчыма выкарыстоўваць, праверце слушнасць напісання",
"dns_test_parsing_error_toast": "Раздзел {{section}}: радок {{line}}: немагчыма выкарыстоўваць, праверце слушнасць напісання",
"dns_test_warning_toast": "Upstream «{{key}}» не адказвае на тэставыя запыты і можа не працаваць належным чынам",
"unblock": "Адблакаваць",
"block": "Заблакіраваць",
"block": "Заблакаваць",
"disallow_this_client": "Забараніць доступ гэтаму кліенту",
"allow_this_client": "Дазволіць доступ гэтаму кліенту",
"block_for_this_client_only": "Заблакаваць толькі для гэтага кліента",
@@ -259,7 +259,7 @@
"no_logs_found": "Логі не знойдзены",
"refresh_btn": "Абнавіць",
"previous_btn": "Назад",
"next_btn": "Далей",
"next_btn": "Наперад",
"loading_table_status": "Загрузка...",
"page_table_footer_text": "Старонка",
"rows_table_footer_text": "радкоў",
@@ -280,7 +280,7 @@
"query_log_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання запытаў? Пры памяншэнні інтэрвалу, некаторыя даныя могуць быць страчаны",
"anonymize_client_ip": "Ананімізацыя IP-адрасы кліента",
"anonymize_client_ip_desc": "Не захоўвайце поўныя IP-адрасы гэтых удзельнікаў у часопісах або статыстыцы",
"dns_config": "Налады сервер DNSа",
"dns_config": "Налады DNS-сервера",
"dns_cache_config": "Налада кэша DNS",
"dns_cache_config_desc": "Тут можна наладзіць кэш DNS",
"blocking_mode": "Рэжым блакавання",
@@ -342,14 +342,14 @@
"unknown_filter": "Невядомы фільтр {{filterId}}",
"known_tracker": "Вядомы трэкер",
"install_welcome_title": "Сардэчна запрашаем у AdGuard Home!",
"install_welcome_desc": "AdGuard Home гэта сервер DNS, што блакуе рэкламу і трэкінг. Яго мэта даць вам магчымасць кантраляваць усю ваша сеціва і ўсе падлучаныя прылады. Ён не патрабуе ўсталёўкі кліенцкіх праграм.",
"install_welcome_desc": "AdGuard Home гэта DNS-сервер, што блакуе рэкламу і трэкінг. Яго мэта даць вам магчымасць кантраляваць усю ваша сеціва і ўсе падлучаныя прылады. Ён не патрабуе ўсталёўкі кліенцкіх праграм.",
"install_settings_title": "Ўэб-інтэрфейс адміністравання",
"install_settings_listen": "Інтэрфейс сеціва",
"install_settings_port": "Порт",
"install_settings_interface_link": "Ваш ўэб-інтэрфейс адміністравання AdGuard Home будзе даступны па наступных адрасах:",
"form_error_port": "Увядзіце карэктны нумар порта",
"install_settings_dns": "DNS-сервер",
"install_settings_dns_desc": "Вам будзе трэба наладзіць свае прылады ці роўтар на выкарыстанне сервер DNSа на адным з наступных адрасоў:",
"install_settings_dns_desc": "Вам будзе трэба наладзіць свае прылады ці роўтар на выкарыстанне DNS-сервера на адным з наступных адрасоў:",
"install_settings_all_interfaces": "Усе інтэрфейсы",
"install_auth_title": "Аўтарызацыя",
"install_auth_desc": "Настойліва рэкамендуецца наладзіць аўтэнтыфікацыю паролем для ўэб-інтэрфейсу AdGuard Home. Нават калі ён даступны толькі ў вашай лакальнай сетцы, важна абараніць яго ад неабмежаванага доступу.",
@@ -365,17 +365,17 @@
"install_submit_desc": "Працэдура налады завершана і вы гатовы пачаць выкарыстанне AdGuard Home.",
"install_devices_router": "Роўтар",
"install_devices_router_desc": "Такая наладка аўтаматычна пакрые ўсе прылады, што выкарыстоўваюць ваш хатні роўтар, і вам не трэба будзе наладжваць кожнае з іх у асобнасці.",
"install_devices_address": "сервер DNS AdGuard Home даступны па наступных адрасах",
"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_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аў для вашай пэўнай мадэлі маршрутызатара.",
"install_devices_router_list_4": "Вы не можаце ўсталяваць уласны DNS-сервер на некаторых тыпах маршрутызатараў. У гэтым выпадку можа дапамагчы налада AdGuard Home у якасці <a href='#dhcp'>DHCP-сервера</a>. У адваротным выпадку вам трэба звярнуцца да кіраўніцтва па наладзе DNS-сервераў для вашай пэўнай мадэлі маршрутызатара.",
"install_devices_windows_list_1": "Адкрыйце Панэль кіравання праз меню «Пуск» ці праз пошук Windows.",
"install_devices_windows_list_2": "Перайдзіце ў «Сеціва і інтэрнэт», а потым у «Цэнтр кіравання сеціва і агульным доступам».",
"install_devices_windows_list_3": "У левым боку экрана клікніце «Змена параметраў адаптара».",
"install_devices_windows_list_4": "Пстрыкніце правай кнопкай мышы ваша актыўнае злучэнне і абярыце Уласцівасці.",
"install_devices_windows_list_5": "Знайдзіце ў спісе пункт «IP версіі 4 (TCP/IPv4)», вылучыце яго і потым ізноў націсніце «Уласцівасці».",
"install_devices_windows_list_6": "Абярыце «Выкарыстаць наступныя адрасы сервер DNSаў» і ўвядзіце адрас AdGuard Home.",
"install_devices_windows_list_6": "Абярыце «Выкарыстаць наступныя адрасы DNS-сервераў» і ўвядзіце адрас AdGuard Home.",
"install_devices_macos_list_1": "Клікніце па абразку Apple і перайдзіце ў Сістэмныя налады.",
"install_devices_macos_list_2": "Клікніце па іконцы Сеціва.",
"install_devices_macos_list_3": "Абярыце першае падлучэнне ў спісе і націсніце кнопку «Дадаткова».",
@@ -415,7 +415,7 @@
"encryption_key": "Прыватны ключ",
"encryption_key_input": "Скапіюйце сюды прыватны ключ у PEM-кадоўцы.",
"encryption_enable": "Уключыць шыфраванне (HTTPS, DNS-over-HTTPS і DNS-over-TLS)",
"encryption_enable_desc": "Калі шыфраванне ўлучана, ўэб-інтэрфейс AdGuard Home будзе працаваць па HTTPS, а сервер DNS будзе таксама працаваць па DNS-over-HTTPS і DNS-over-TLS.",
"encryption_enable_desc": "Калі шыфраванне ўлучана, ўэб-інтэрфейс AdGuard Home будзе працаваць па HTTPS, а DNS-сервер будзе таксама працаваць па DNS-over-HTTPS і DNS-over-TLS.",
"encryption_chain_valid": "Ланцужок сертыфікатаў валідны",
"encryption_chain_invalid": "Ланцужок сертыфікатаў не валідны",
"encryption_key_valid": "Валідны {{type}} прыватны ключ",
@@ -435,8 +435,8 @@
"update_announcement": "AdGuard Home {{version}} ужо даступная! <0>Націсніце сюды</0>, каб даведацца больш.",
"setup_guide": "Інструкцыя па наладзе",
"dns_addresses": "Адрасы DNS",
"dns_start": "сервер DNS запускаецца",
"dns_status_error": "Памылка праверкі стану сервер DNSа",
"dns_start": "DNS-сервер запускаецца",
"dns_status_error": "Памылка праверкі стану DNS-сервера",
"down": "Уніз",
"fix": "Выправіць",
"dns_providers": "<0>Спіс вядомых DNS-правайдараў</0> на выбар.",
@@ -449,7 +449,7 @@
"settings_global": "Глабальныя",
"settings_custom": "Свае",
"table_client": "Кліент",
"table_name": "Назва",
"table_name": "Імя",
"save_btn": "Захаваць",
"client_add": "Дадаць кліента",
"client_new": "Новы кліент",
@@ -475,7 +475,7 @@
"auto_clients_title": "Кліенты (runtime)",
"auto_clients_desc": "Інфармацыя аб IP-адрасах прылад, якія выкарыстоўваюць або могуць выкарыстоўваць AdGuard Home. Гэтая інфармацыя збіраецца з некалькіх крыніц, уключаючы файлы хостаў, зваротны DNS і г.д.",
"access_title": "Налады доступу",
"access_desc": "Тут вы можаце наладзіць правілы доступу да сервер DNSу AdGuard Home",
"access_desc": "Тут вы можаце наладзіць правілы доступу да DNS-серверу AdGuard Home",
"access_allowed_title": "Дазволеныя кліенты",
"access_allowed_desc": "Спіс CIDR, IP-адрасоў або <a>ClientID</a>. Калі ў гэтым спісе ёсць запісы, AdGuard Home будзе прымаць запыты толькі ад гэтых кліентаў.",
"access_disallowed_title": "Забароненыя кліенты",
@@ -596,7 +596,7 @@
"disable_ipv6_desc": "Ігнараваць усе запыты DNS для адрасоў IPv6 (тып AAAA) і выдаленне дадзеных IPv6 з адказаў тыпу HTTPS.",
"fastest_addr": "Найхуткі IP-адрас",
"fastest_addr_desc": "Апытайце ўсе DNS-серверы і вярніце самы хуткі IP-адрас сярод усіх адказаў. Гэта замарудзіць выкананне DNS-запытаў, бо нам давядзецца чакаць адказаў ад усіх DNS-сервераў, але палепшыць агульную ўзаемасувязь.",
"autofix_warning_text": "Пры націску «Выправіць» AdGuard Home наладзіць вашу сістэму на выкарыстанне сервер DNSа AdGuard Home.",
"autofix_warning_text": "Пры націску «Выправіць» AdGuard Home наладзіць вашу сістэму на выкарыстанне DNS-сервера AdGuard Home.",
"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 (перазагрузіць сістэмную службу)</0>.",
"autofix_warning_result": "У выніку ўсе DNS-запыты ад вашай сістэмы будуць па змаўчанні апрацоўвацца AdGuard Home.\n",
"tags_title": "Тэгі",
@@ -634,12 +634,12 @@
"validated_with_dnssec": "Проверено с помощью DNSSEC",
"all_queries": "Усе запыты",
"show_blocked_responses": "Заблакавана",
"show_whitelisted_responses": "У белым спісе",
"show_whitelisted_responses": "Белы спіс",
"show_processed_responses": "Апрацавана",
"blocked_safebrowsing": "Заблакіравана згодна з базай даных Safe Browsing",
"blocked_adult_websites": "Заблакавана Бацькоўскім кантролем",
"blocked_threats": "Заблакавана пагроз",
"allowed": "У белым спісе",
"allowed": "Дазволены",
"filtered": "Адфільтраваныя",
"rewritten": "Перапісаныя",
"safe_search": "Бяспечны пошук",
@@ -738,7 +738,7 @@
"thursday_short": "Чц.",
"friday_short": "Пт.",
"saturday_short": "Сб.",
"upstream_dns_cache_configuration": "Канфігурацыя кэша upstream сервер DNSаў",
"upstream_dns_cache_configuration": "Канфігурацыя кэша upstream DNS-сервераў",
"enable_upstream_dns_cache": "Ўключыць кэшаванне для карыстацкай канфігурацыі upstream-сервераў гэтага кліента",
"dns_cache_size": "Памер кэша DNS, у байтах"
}

View File

@@ -45,7 +45,6 @@
"filter": "Филтър",
"query_log": "История на заявките",
"compact": "Compact",
"nothing_found": "Нищо не е намерено",
"faq": "ЧЗВ",
"version": "версия",
"address": "Адрес",
@@ -66,12 +65,14 @@
"stats_malware_phishing": "вируси/атаки",
"stats_adult": "сайтове за възрастни",
"stats_query_domain": "Най-отваряни страници",
"for_last_24_hours": "за последните 24 часа",
"no_domains_found": "Няма намерени резултати",
"requests_count": "Сума на заявките",
"top_blocked_domains": "Най-блокирани страници",
"top_clients": "Най-активни IP адреси",
"no_clients_found": "Нямa намерени адреси",
"general_statistics": "Обща статисика",
"number_of_dns_query_24_hours": "Сума на DNS заявки за последните 24 часа",
"number_of_dns_query_blocked_24_hours": "Сума на блокирани DNS заявки от филтрите за реклама и местни",
"number_of_dns_query_blocked_24_hours_by_sec": "Сума на блокирани DNS заявки от AdGuard свързани със сигурността",
"number_of_dns_query_blocked_24_hours_adult": "Сума на блокирани сайтове за възрастни",
@@ -155,7 +156,6 @@
"rule_added_to_custom_filtering_toast": "Добавено до местни правила за филтриране: {{rule}}",
"default": "По подразбиране",
"custom_ip": "Персонализиран IP",
"dnscrypt": "DNSCrypt",
"dns_over_https": "DNS-пред-HTTPS",
"dns_over_quic": "DNS-over-QUIC",
"plain_dns": "Обикновен DNS",

View File

@@ -656,7 +656,7 @@
"blocklist": "Zakázaný",
"milliseconds_abbreviation": "ms",
"cache_size": "Velikost mezipaměti",
"cache_size_desc": "Velikost mezipaměti DNS (v bajtech). Chcete-li ukládání do mezipaměti zakázat, nastavte 0.",
"cache_size_desc": "Velikost mezipaměti DNS (v bajtech). Chcete-li ukládání do mezipaměti zakázat, ponechte prázdné.",
"cache_ttl_min_override": "Přepsat minimální hodnotu TTL",
"cache_ttl_max_override": "Přepsat maximální hodnotu TTL",
"enter_cache_size": "Zadejte velikost mezipaměti (v bajtech)",

View File

@@ -656,7 +656,7 @@
"blocklist": "Sortliste",
"milliseconds_abbreviation": "ms",
"cache_size": "Cache-størrelse",
"cache_size_desc": "DNS cache-størrelse (i bytes). Sæt til 0 for at deaktivere cache.",
"cache_size_desc": "DNS cache-størrelse (i bytes). Lad stå tomt for at deaktivere cache.",
"cache_ttl_min_override": "Tilsidesæt minimum TTL",
"cache_ttl_max_override": "Tilsidesæt maksimal TTL",
"enter_cache_size": "Angiv cache-størrelse (bytes)",

View File

@@ -656,7 +656,7 @@
"blocklist": "Sperrliste",
"milliseconds_abbreviation": "ms",
"cache_size": "Größe des Cache",
"cache_size_desc": "Größe des DNS-Cache (in Bytes). Um das Caching zu deaktivieren, setzen Sie den Wert auf 0.",
"cache_size_desc": "Größe des DNS-Zwischenspeichers (in Bytes)",
"cache_ttl_min_override": "TTL-Minimalwert überschreiben",
"cache_ttl_max_override": "TTL-Höchstwert überschreiben",
"enter_cache_size": "Größe des Cache (Bytes) eingeben",

View File

@@ -656,7 +656,7 @@
"blocklist": "Blocklist",
"milliseconds_abbreviation": "ms",
"cache_size": "Cache size",
"cache_size_desc": "DNS cache size (in bytes). To disable caching, set to 0.",
"cache_size_desc": "DNS cache size (in bytes). To disable caching, leave empty.",
"cache_ttl_min_override": "Override minimum TTL",
"cache_ttl_max_override": "Override maximum TTL",
"enter_cache_size": "Enter cache size (bytes)",

View File

@@ -656,7 +656,7 @@
"blocklist": "Lista de bloqueo",
"milliseconds_abbreviation": "ms",
"cache_size": "Tamaño de la caché",
"cache_size_desc": "Tamaño de la caché DNS (en bytes). Para desactivar el almacenamiento en caché, configúralo en 0.",
"cache_size_desc": "Tamaño de la caché DNS (en bytes). Para deshabilitar el almacenamiento en caché, déjalo vacío.",
"cache_ttl_min_override": "Anular TTL mínimo",
"cache_ttl_max_override": "Anular TTL máximo",
"enter_cache_size": "Ingresa el tamaño de la caché (bytes)",

View File

@@ -656,7 +656,7 @@
"blocklist": "Liste de blocage",
"milliseconds_abbreviation": "ms",
"cache_size": "Taille du cache",
"cache_size_desc": "Taille du cache DNS (en octets). Pour désactiver la mise en cache, mettez la valeur sur 0.",
"cache_size_desc": "Taille du cache DNS (en octets). Pour désactiver la mise en cache, laissez vide.",
"cache_ttl_min_override": "Remplacer le TTL minimum",
"cache_ttl_max_override": "Remplacer le TTL maximum",
"enter_cache_size": "Entrer la taille du cache (octets)",

View File

@@ -656,7 +656,7 @@
"blocklist": "Lista nera",
"milliseconds_abbreviation": "ms",
"cache_size": "Dimensioni cache",
"cache_size_desc": "Dimensione della cache DNS (in byte). Per disabilitare la cache, impostare su 0.",
"cache_size_desc": "Dimensione della cache DNS (in byte). Per disabilitare la memorizzazione nella cache, lascia vuoto.",
"cache_ttl_min_override": "Sovrascrivi TTL minimo",
"cache_ttl_max_override": "Sovrascrivi TTL massimo",
"enter_cache_size": "Immetti dimensioni cache (in byte)",

View File

@@ -656,7 +656,7 @@
"blocklist": "ブロックリスト",
"milliseconds_abbreviation": "ms",
"cache_size": "キャッシュサイズ",
"cache_size_desc": "DNSキャッシュサイズバイト単位※キャッシュを無効化するには、「0」ゼロしてください。",
"cache_size_desc": "DNSキャッシュサイズバイト単位※キャッシュを無効化するには、この欄を空してください。",
"cache_ttl_min_override": "最小TTLの上書き秒単位",
"cache_ttl_max_override": "最大TTLの上書き秒単位",
"enter_cache_size": "キャッシュサイズ(バイト単位)を入力してください",

View File

@@ -656,7 +656,7 @@
"blocklist": "차단 목록",
"milliseconds_abbreviation": "ms",
"cache_size": "캐시 크기",
"cache_size_desc": "DNS 캐시 크기(바이트). 캐싱을 사용하지 않으려면 0으로 설정합니다.",
"cache_size_desc": "DNS 캐시 크기(바이트). 캐싱을 비활성화하려면 비워 둡니다.",
"cache_ttl_min_override": "최소 TTL (초) 무시",
"cache_ttl_max_override": "최대 TTL (초) 무시",
"enter_cache_size": "캐시 크기를 입력하세요",

View File

@@ -110,9 +110,9 @@
"homepage": "Startpagina",
"report_an_issue": "Rapporteer een probleem",
"privacy_policy": "Privacybeleid",
"enable_protection": "Bescherming inschakelen",
"enable_protection": "Schakel bescherming in",
"enabled_protection": "Bescherming ingeschakeld",
"disable_protection": "Bescherming uitschakelen",
"disable_protection": "Schakel bescherming uit",
"disabled_protection": "Bescherming uitgeschakeld",
"refresh_statics": "Ververs statistieken",
"dns_query": "DNS-queries",
@@ -656,7 +656,7 @@
"blocklist": "Blokkeerlijst",
"milliseconds_abbreviation": "ms",
"cache_size": "Cache grootte",
"cache_size_desc": "DNS-cachegrootte (in bytes). Om caching uit te schakelen, stel deze in op 0.",
"cache_size_desc": "DNS-cachegrootte (in bytes). Leeg laten om caching uit te schakelen.",
"cache_ttl_min_override": "Minimale TTL overschrijven",
"cache_ttl_max_override": "Maximale TTL overschrijven",
"enter_cache_size": "Cache grootte invoeren (bytes)",
@@ -702,13 +702,13 @@
"disable_for_hours": "Voor {{count}} uur",
"disable_for_hours_plural": "Voor {{count}} uren",
"disable_until_tomorrow": "Tot morgen",
"disable_notify_for_seconds": "Bescherming uitschakelen voor {{count}} seconde",
"disable_notify_for_seconds_plural": "Bescherming uitschakelen voor {{count}} seconden",
"disable_notify_for_minutes": "Bescherming uitschakelen voor {{count}} minuut",
"disable_notify_for_minutes_plural": "Bescherming uitschakelen voor {{count}} minuten",
"disable_notify_for_hours": "Bescherming uitschakelen voor {{count}} uur",
"disable_notify_for_hours_plural": "Bescherming uitschakelen voor {{count}} uren",
"disable_notify_until_tomorrow": "Bescherming uitschakelen tot morgen",
"disable_notify_for_seconds": "Beveiliging uitschakelen voor {{count}} seconde",
"disable_notify_for_seconds_plural": "Beveiliging uitschakelen voor {{count}} seconden",
"disable_notify_for_minutes": "Beveiliging uitschakelen voor {{count}} minuut",
"disable_notify_for_minutes_plural": "Beveiliging uitschakelen voor {{count}} minuten",
"disable_notify_for_hours": "Beveiliging uitschakelen voor {{count}} uur",
"disable_notify_for_hours_plural": "Beveiliging uitschakelen voor {{count}} uren",
"disable_notify_until_tomorrow": "Beveiliging uitschakelen tot morgen",
"enable_protection_timer": "Bescherming wordt ingeschakeld over {{time}}",
"custom_retention_input": "Voer retentie in uren in",
"custom_rotation_input": "Voer rotatie in uren in",

View File

@@ -264,7 +264,7 @@
"custom_ip": "Tilpasset IP",
"blocking_ipv4": "IPv4-blokkering",
"blocking_ipv6": "IPv6-blokkering",
"blocked_response_ttl": "Blokkerte svars TTL",
"blocked_response_ttl": "Blokkert svar TTL",
"dnscrypt": "DNSCrypt",
"dns_over_https": "DNS-over-HTTPS",
"dns_over_tls": "DNS-over-TLS",

View File

@@ -656,7 +656,7 @@
"blocklist": "Lista de bloqueio",
"milliseconds_abbreviation": "ms",
"cache_size": "Tamanho do cache",
"cache_size_desc": "Tamanho do cache do DNS (em bytes). Para desativar o cache, defina como 0.",
"cache_size_desc": "Tamanho do cache do DNS (em bytes). Para desativar o cache, deixe em branco.",
"cache_ttl_min_override": "Sobrepor o TTL mínimo",
"cache_ttl_max_override": "Sobrepor o TTL máximo",
"enter_cache_size": "Digite o tamanho do cache (bytes)",

View File

@@ -656,7 +656,7 @@
"blocklist": "Lista de bloqueio",
"milliseconds_abbreviation": "ms",
"cache_size": "Tamanho do cache",
"cache_size_desc": "Tamanho do cache DNS (em bytes). Para desativar o cache, defina como 0.",
"cache_size_desc": "Tamanho do cache DNS (em bytes). Para desativar o cache, deixar o campo vazio.",
"cache_ttl_min_override": "Sobrepor o TTL mínimo",
"cache_ttl_max_override": "Sobrepor o TTL máximo",
"enter_cache_size": "Digite o tamanho do cache (bytes)",

View File

@@ -656,7 +656,7 @@
"blocklist": "Чёрный список",
"milliseconds_abbreviation": "мс",
"cache_size": "Размер кеша",
"cache_size_desc": "Размер кеша DNS (в байтах). Чтобы отключить кеширование, установите значение 0.",
"cache_size_desc": "Размера кеша DNS (в байтах). Чтобы отключить кэширование, оставьте поле пустым.",
"cache_ttl_min_override": "Переопределить минимальный TTL",
"cache_ttl_max_override": "Переопределить максимальный TTL",
"enter_cache_size": "Введите размер кеша (в байтах)",

View File

@@ -656,7 +656,7 @@
"blocklist": "Zoznam blokovaní",
"milliseconds_abbreviation": "ms",
"cache_size": "Veľkosť cache",
"cache_size_desc": "Veľkosť vyrovnávacej pamäte DNS (v bajtoch). Ak chcete vypnúť ukladanie do vyrovnávacej pamäte, nastavte hodnotu 0.",
"cache_size_desc": "Veľkosť vyrovnávacej pamäte DNS (v bajtoch). Ak chcete zakázať ukladanie do vyrovnávacej pamäte, ponechajte pole prázdne.",
"cache_ttl_min_override": "Prepísať minimálne TTL",
"cache_ttl_max_override": "Prepísať maximálne TTL",
"enter_cache_size": "Zadať veľkosť cache (v bajtoch)",

View File

@@ -656,7 +656,7 @@
"blocklist": "Engel listesi",
"milliseconds_abbreviation": "ms",
"cache_size": "Önbellek boyutu",
"cache_size_desc": "DNS önbellek boyutu (bayt cinsinden). Önbelleği devre dışı bırakmak için 0 olarak ayarlayın.",
"cache_size_desc": "DNS önbellek boyutu (bayt cinsinden). Önbelleğe almayı devre dışı bırakmak için boş bırakın.",
"cache_ttl_min_override": "Minimum kullanım süresini geçersiz kıl",
"cache_ttl_max_override": "Maksimum kullanım süresini geçersiz kıl",
"enter_cache_size": "Önbellek boyutunu girin (bayt)",

View File

@@ -656,7 +656,7 @@
"blocklist": "黑名单",
"milliseconds_abbreviation": "毫秒",
"cache_size": "缓存大小",
"cache_size_desc": "DNS 缓存大小(单位:字节)。若要禁用缓存,请设置为 0。",
"cache_size_desc": "DNS 缓存大小(单位:字节)。若要关闭缓存,请留空。",
"cache_ttl_min_override": "覆盖最小 TTL 值",
"cache_ttl_max_override": "覆盖最大 TTL 值",
"enter_cache_size": "输入缓存大小(字节)",

View File

@@ -656,7 +656,7 @@
"blocklist": "封鎖清單",
"milliseconds_abbreviation": "ms",
"cache_size": "快取大小",
"cache_size_desc": "DNS 快取大小位元組。若要停用快取,請設為 0。",
"cache_size_desc": "DNS 快取大小 (位元組)。若要停用快取,請留空。",
"cache_ttl_min_override": "覆寫最小的存活時間TTL",
"cache_ttl_max_override": "覆寫最大的存活時間TTL",
"enter_cache_size": "輸入快取大小(位元組)",

View File

@@ -78,7 +78,6 @@ class CustomRules extends Component<CustomRulesProps> {
<form onSubmit={this.handleSubmit}>
<div className="text-edit-container mb-4">
<textarea
data-testid="custom_rule_textarea"
className="form-control font-monospace text-input"
value={userRules}
onChange={this.handleChange}
@@ -92,7 +91,6 @@ class CustomRules extends Component<CustomRulesProps> {
<div className="card-actions">
<button
data-testid="apply_custom_rule"
className="btn btn-success btn-standard btn-large"
type="submit"
onClick={this.handleSubmit}>

View File

@@ -59,7 +59,7 @@ const Header = () => {
<div className="header__column">
<div className="header__right">
{!processingProfile && name && (
<a href="control/logout" className="btn btn-sm btn-outline-secondary" data-testid="sign_out">
<a href="control/logout" className="btn btn-sm btn-outline-secondary">
{t('sign_out')}
</a>
)}

View File

@@ -288,7 +288,7 @@ const Row = memo(
);
return (
<div style={style} className={className} onClick={onClick} role="row" data-testid="querylog_cell">
<div style={style} className={className} onClick={onClick} role="row">
<DateCell {...rowProps} />
<DomainCell {...rowProps} />

View File

@@ -84,7 +84,6 @@ export const Form = ({ className, setIsLoading }: Props) => {
}}>
<div className="field__search">
<SearchField
data-testid="querylog_search"
value={searchValue}
handleChange={(val) => setValue('search', val)}
onKeyDown={onEnterPress}

View File

@@ -27,14 +27,12 @@ const SETTINGS = {
enabled: false,
title: i18next.t('use_adguard_browsing_sec'),
subtitle: i18next.t('use_adguard_browsing_sec_hint'),
testId: 'safebrowsing',
[ORDER_KEY]: 0,
},
parental: {
enabled: false,
title: i18next.t('use_adguard_parental'),
subtitle: i18next.t('use_adguard_parental_hint'),
testId: 'parental',
[ORDER_KEY]: 1,
},
};
@@ -92,12 +90,11 @@ class Settings extends Component<SettingsProps> {
renderSettings = (settings: any) =>
getObjectKeysSorted(SETTINGS, ORDER_KEY).map((key: any) => {
const setting = settings[key];
const { enabled, title, subtitle, testId } = setting;
const { enabled, title, subtitle } = setting;
return (
<div key={key} className="form__group form__group--checkbox">
<Checkbox
data-testid={testId}
value={enabled}
title={title}
subtitle={subtitle}
@@ -121,7 +118,6 @@ class Settings extends Component<SettingsProps> {
<>
<div className="form__group form__group--checkbox">
<Checkbox
data-testid="safesearch"
value={enabled}
title={i18next.t('enforce_safe_search')}
subtitle={i18next.t('enforce_save_search_hint')}

View File

@@ -94,17 +94,14 @@ const Footer = () => {
auto: {
desc: t('theme_auto_desc'),
icon: '#auto',
testId: 'theme_auto',
},
dark: {
desc: t('theme_dark_desc'),
icon: '#dark',
testId: 'theme_dark',
},
light: {
desc: t('theme_light_desc'),
icon: '#light',
testId: 'theme_light',
},
};
@@ -116,9 +113,7 @@ const Footer = () => {
type="button"
className="btn btn-sm btn-secondary footer__theme-button"
onClick={() => onThemeChange(theme)}
title={content[theme].desc}
data-testid={content[theme].testId}
>
title={content[theme].desc}>
<svg className={cn('footer__theme-icon', { 'footer__theme-icon--active': currentValue === theme })}>
<use xlinkHref={content[theme].icon} />
</svg>

View File

@@ -28,12 +28,6 @@ export default {
"homepage": "https://badmojr.github.io/1Hosts/",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_24.txt"
},
"1hosts_pro": {
"name": "1Hosts (Pro)",
"categoryId": "general",
"homepage": "https://badmojr.github.io/1Hosts/",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_64.txt"
},
"CHN_adrules": {
"name": "CHN: AdRules DNS List",
"categoryId": "regional",

View File

@@ -1,34 +0,0 @@
import { test, expect } from '@playwright/test';
import { ADMIN_USERNAME, ADMIN_PASSWORD } from '../constants';
test.describe('Control Panel', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login.html');
await page.getByTestId('username').click();
await page.getByTestId('username').fill(ADMIN_USERNAME);
await page.getByTestId('password').click();
await page.getByTestId('password').fill(ADMIN_PASSWORD);
await page.keyboard.press('Tab');
await page.getByTestId('sign_in').click();
await page.waitForURL((url) => !url.href.endsWith('/login.html'));
});
test('should sign out successfully', async ({ page }) => {
await page.getByTestId('sign_out').click();
await page.waitForURL((url) => url.href.endsWith('/login.html'));
await expect(page.getByTestId('sign_in')).toBeVisible();
});
test('should change theme to dark and then light', async ({ page }) => {
await page.getByTestId('theme_dark').click();
await expect(page.locator('body[data-theme="dark"]')).toBeVisible();
await page.getByTestId('theme_light').click();
await expect(page.locator('body:not([data-theme="dark"])')).toBeVisible();
});
});

View File

@@ -1,52 +0,0 @@
import { test, expect, type Page } from '@playwright/test';
import { ADMIN_USERNAME, ADMIN_PASSWORD } from '../constants';
test.describe('DNS Settings', () => {
test.beforeEach(async ({ page }) => {
// Login before each test
await page.goto('/login.html');
await page.getByTestId('username').click();
await page.getByTestId('username').fill(ADMIN_USERNAME);
await page.getByTestId('password').click();
await page.getByTestId('password').fill(ADMIN_PASSWORD);
await page.keyboard.press('Tab');
await page.getByTestId('sign_in').click();
await page.waitForURL((url) => !url.href.endsWith('/login.html'));
});
const runDNSSettingsTest = async (page: Page, address: string) => {
await page.goto('/#dns');
const currentDns = await page.getByTestId('upstream_dns').inputValue();
await page.getByTestId('upstream_dns').fill(address);
await page.getByTestId('dns_upstream_test').click();
await page.waitForTimeout(2000);
await expect(page.getByTestId('upstream_dns')).toHaveValue(address);
await page.getByTestId('upstream_dns').fill(currentDns);
await page.getByTestId('dns_upstream_save').click({ force: true });
};
test('test for Default DNS', async ({ page }) => {
await runDNSSettingsTest(page, 'https://dns10.quad9.net/dns-query');
});
test('test for Plain DNS', async ({ page }) => {
await runDNSSettingsTest(page, '94.140.14.140');
});
test('test for DNS-over-HTTPS', async ({ page }) => {
await runDNSSettingsTest(page, 'https://unfiltered.adguard-dns.com/dns-query');
});
test('test for DNS-over-TLS', async ({ page }) => {
await runDNSSettingsTest(page, 'tls://unfiltered.adguard-dns.com');
});
test('test for DNS-over-QUIC', async ({ page }) => {
await runDNSSettingsTest(page, 'quic://unfiltered.adguard-dns.com');
});
});

View File

@@ -1,73 +0,0 @@
import { test, expect, type Page } from '@playwright/test';
import { execSync } from 'child_process';
import { ADMIN_USERNAME, ADMIN_PASSWORD } from '../constants';
test.describe('Filtering', () => {
test.beforeEach(async ({ page }) => {
// Login before each test
await page.goto('/login.html');
await page.getByTestId('username').click();
await page.getByTestId('username').fill(ADMIN_USERNAME);
await page.getByTestId('password').click();
await page.getByTestId('password').fill(ADMIN_PASSWORD);
await page.keyboard.press('Tab');
await page.getByTestId('sign_in').click();
await page.waitForURL((url) => !url.href.endsWith('/login.html'));
});
const runTerminalCommand = (command: string) => {
try {
console.info(`Executing command: ${command}`);
const output = execSync(command, { encoding: 'utf-8', stdio: 'pipe' }).trim();
console.info('Command executed successfully.');
console.debug(`Command output:\n${output}`);
return output;
} catch (error: any) {
console.error(`Command execution failed with error:\n${error.message}`);
throw new Error(`Failed to execute command: ${command}\nError: ${error.message}`);
}
}
const runCustomRuleTest = async (page: Page, domain_to_block: string) => {
await page.goto('/#custom_rules');
await page.getByTestId('custom_rule_textarea').fill(domain_to_block);
await page.getByTestId('apply_custom_rule').click();
const nslookupBlockedResult = await runTerminalCommand(`nslookup ${domain_to_block} 127.0.0.1`).toString();
console.info(`nslookup blocked CNAME result: '${nslookupBlockedResult}'`);
const currentRules = await page.getByTestId('custom_rule_textarea').inputValue();
console.debug(`Current rules before removal:\n${currentRules}`);
if (currentRules.includes(domain_to_block)) {
const updatedRules = currentRules
.split('\n')
.filter((line) => line.trim() !== domain_to_block.trim())
.join('\n');
await page.getByTestId('custom_rule_textarea').fill(updatedRules);
console.info(`Rule '${domain_to_block}' removed successfully.`);
console.info('Applying the updated filtering rules after removal.');
await page.getByTestId('apply_custom_rule').click();
await page.waitForLoadState('domcontentloaded');
console.info(`Filtering rules successfully updated after removing '${domain_to_block}'.`);
} else {
console.warn(`Rule '${domain_to_block}' not found. No changes were made.`);
}
const nslookupUnblockedResult = await runTerminalCommand(`nslookup ${domain_to_block} 127.0.0.1`).toString();
console.info(`nslookup unblocked CNAME result: '${nslookupUnblockedResult}'`);
};
test('Test blocking rule for apple.com', async ({ page }) => {
await runCustomRuleTest(page, 'apple.com');
});
});

View File

@@ -1,89 +0,0 @@
import { test, expect } from '@playwright/test';
import { execSync } from 'child_process';
import { ADMIN_USERNAME, ADMIN_PASSWORD } from '../constants';
test.describe('General Settings', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login.html');
await page.getByTestId('username').click();
await page.getByTestId('username').fill(ADMIN_USERNAME);
await page.getByTestId('password').click();
await page.getByTestId('password').fill(ADMIN_PASSWORD);
await page.keyboard.press('Tab');
await page.getByTestId('sign_in').click();
await page.waitForURL((url) => !url.href.endsWith('/login.html'));
});
test('should toggle browsing security feature and verify DNS changes', async ({ page }) => {
await page.goto('/#settings');
const browsingSecurity = await page.getByTestId('safebrowsing');
const browsingSecurityLabel = await browsingSecurity.locator('xpath=following-sibling::*[1]');
const initialState = await browsingSecurity.isChecked();
if (!initialState) {
await browsingSecurityLabel.click();
await expect(browsingSecurity).toBeChecked();
}
const resultEnabled = execSync('nslookup totalvirus.com 127.0.0.1').toString();
await browsingSecurityLabel.click();
await expect(browsingSecurity).not.toBeChecked();
const resultDisabled = execSync('nslookup totalvirus.com 127.0.0.1').toString();
expect(resultEnabled).not.toEqual(resultDisabled);
if (initialState) {
await browsingSecurityLabel.click();
await expect(browsingSecurity).toBeChecked();
}
});
test('should toggle parental control feature and verify DNS changes', async ({ page }) => {
await page.goto('/#settings');
const parentalControl = page.getByTestId('parental');
const parentalControlLabel = await parentalControl.locator('xpath=following-sibling::*[1]');
const initialState = await parentalControl.isChecked();
if (!initialState) {
await parentalControlLabel.click();
await expect(parentalControl).toBeChecked();
}
const resultEnabled = execSync('nslookup pornhub.com 127.0.0.1').toString();
await parentalControlLabel.click();
await expect(parentalControl).not.toBeChecked();
const resultDisabled = execSync('nslookup pornhub.com 127.0.0.1').toString();
expect(resultEnabled).not.toEqual(resultDisabled);
if (initialState) {
await parentalControlLabel.click();
await expect(parentalControl).toBeChecked();
}
});
test('should toggle safe search feature', async ({ page }) => {
await page.goto('/#settings');
const safeSearch = page.getByTestId('safesearch');
const safeSearchLabel = await safeSearch.locator('xpath=following-sibling::*[1]');
const initialState = await safeSearch.isChecked();
await safeSearchLabel.click();
await expect(safeSearch).not.toBeChecked({ checked: initialState });
await safeSearchLabel.click();
await expect(safeSearch).toBeChecked({ checked: initialState });
});
});

View File

@@ -1,124 +0,0 @@
import { test, expect } from '@playwright/test';
import { ADMIN_USERNAME, ADMIN_PASSWORD } from '../constants';
test.describe('QueryLog', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login.html');
await page.getByTestId('username').click();
await page.getByTestId('username').fill(ADMIN_USERNAME);
await page.getByTestId('password').click();
await page.getByTestId('password').fill(ADMIN_PASSWORD);
await page.keyboard.press('Tab');
await page.getByTestId('sign_in').click();
await page.waitForURL((url) => !url.href.endsWith('/login.html'));
});
test('Search of queryLog should work correctly', async ({ page }) => {
await page.route('/control/querylog', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(
{
"data": [
{
"answer": [
{
"type": "A",
"value": "77.88.44.242",
"ttl": 294
},
{
"type": "A",
"value": "5.255.255.242",
"ttl": 294
},
{
"type": "A",
"value": "77.88.55.242",
"ttl": 294
}
],
"answer_dnssec": false,
"cached": false,
"client": "127.0.0.1",
"client_info": {
"whois": {},
"name": "localhost",
"disallowed_rule": "127.0.0.1",
"disallowed": false
},
"client_proto": "",
"elapsedMs": "78.163167",
"question": {
"class": "IN",
"name": "ya.ru",
"type": "A"
},
"reason": "NotFilteredNotFound",
"rules": [],
"status": "NOERROR",
"time": "2024-07-17T16:02:37.500662+02:00",
"upstream": "https://dns10.quad9.net:443/dns-query"
},
{
"answer": [
{
"type": "A",
"value": "77.88.55.242",
"ttl": 351
},
{
"type": "A",
"value": "77.88.44.242",
"ttl": 351
},
{
"type": "A",
"value": "5.255.255.242",
"ttl": 351
}
],
"answer_dnssec": false,
"cached": false,
"client": "127.0.0.1",
"client_info": {
"whois": {},
"name": "localhost",
"disallowed_rule": "127.0.0.1",
"disallowed": false
},
"client_proto": "",
"elapsedMs": "5051.070708",
"question": {
"class": "IN",
"name": "ya.ru",
"type": "A"
},
"reason": "NotFilteredNotFound",
"rules": [],
"status": "NOERROR",
"time": "2024-07-17T16:02:37.4983+02:00",
"upstream": "https://dns10.quad9.net:443/dns-query"
}
],
"oldest": "2024-07-17T16:02:37.4983+02:00"
}
),
});
});
await page.goto('/#logs');
await page.getByTestId('querylog_search').fill('127.0.0.1');
const [request] = await Promise.all([
page.waitForRequest((req) => req.url().includes('/control/querylog')),
]);
if (request) {
expect(request.url()).toContain('search=127.0.0.1');
expect(await page.getByTestId('querylog_cell').first().isVisible()).toBe(true);
}
});
});

34
go.mod
View File

@@ -3,8 +3,8 @@ module github.com/AdguardTeam/AdGuardHome
go 1.24.2
require (
github.com/AdguardTeam/dnsproxy v0.75.5
github.com/AdguardTeam/golibs v0.32.9
github.com/AdguardTeam/dnsproxy v0.75.2
github.com/AdguardTeam/golibs v0.32.7
github.com/AdguardTeam/urlfilter v0.20.0
github.com/NYTimes/gziphandler v1.1.1
github.com/ameshkov/dnscrypt/v2 v2.4.0
@@ -34,21 +34,21 @@ require (
github.com/ti-mo/netfilter v0.5.2
go.etcd.io/bbolt v1.4.0
golang.org/x/crypto v0.37.0
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
golang.org/x/net v0.39.0
golang.org/x/sys v0.33.0
golang.org/x/sys v0.32.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
howett.net/plist v1.0.1
)
require (
cloud.google.com/go v0.120.1 // indirect
cloud.google.com/go/ai v0.10.2 // indirect
cloud.google.com/go/auth v0.16.0 // indirect
cloud.google.com/go v0.120.0 // indirect
cloud.google.com/go/ai v0.10.1 // indirect
cloud.google.com/go/auth v0.15.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/longrunning v0.6.7 // indirect
cloud.google.com/go/longrunning v0.6.6 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/ameshkov/dnsstamps v1.0.3 // indirect
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 // indirect
@@ -61,7 +61,7 @@ require (
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/golangci/misspell v0.6.0 // indirect
github.com/google/generative-ai-go v0.19.0 // indirect
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a // indirect
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
@@ -89,26 +89,26 @@ require (
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/mock v0.5.2 // indirect
golang.org/x/exp/typeparams v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
go.uber.org/mock v0.5.1 // indirect
golang.org/x/exp/typeparams v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/oauth2 v0.29.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/telemetry v0.0.0-20250417124945-06ef541f3fa3 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/telemetry v0.0.0-20250406004356-f593adaf3fc1 // indirect
golang.org/x/term v0.31.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/tools v0.32.0 // indirect
golang.org/x/vuln v1.1.4 // indirect
gonum.org/v1/gonum v0.16.0 // indirect
google.golang.org/api v0.229.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect
google.golang.org/api v0.228.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250407143221-ac9807e6c755 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250407143221-ac9807e6c755 // indirect
google.golang.org/grpc v1.71.1 // indirect
google.golang.org/protobuf v1.36.6 // indirect
honnef.co/go/tools v0.6.1 // indirect
mvdan.cc/editorconfig v0.3.0 // indirect
mvdan.cc/gofumpt v0.8.0 // indirect
mvdan.cc/gofumpt v0.7.0 // indirect
mvdan.cc/sh/v3 v3.11.0 // indirect
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 // indirect
)

68
go.sum
View File

@@ -1,19 +1,19 @@
cloud.google.com/go v0.120.1 h1:Z+5V7yd383+9617XDCyszmK5E4wJRJL+tquMfDj9hLM=
cloud.google.com/go v0.120.1/go.mod h1:56Vs7sf/i2jYM6ZL9NYlC82r04PThNcPS5YgFmb0rp8=
cloud.google.com/go/ai v0.10.2 h1:5NHzmZlRs+3kvlsVdjT0cTnLrjQdROJ/8VOljVfs+8o=
cloud.google.com/go/ai v0.10.2/go.mod h1:xZuZuE9d3RgsR132meCnPadiU9XV0qXjpLr+P4J46eE=
cloud.google.com/go/auth v0.16.0 h1:Pd8P1s9WkcrBE2n/PhAwKsdrR35V3Sg2II9B+ndM3CU=
cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA=
cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q=
cloud.google.com/go/ai v0.10.1 h1:EU93KqYmMeOKgaBXAz2DshH2C/BzAT1P+iJORksLIic=
cloud.google.com/go/ai v0.10.1/go.mod h1:sWWHZvmJ83BjuxAQtYEiA0SFTpijtbH+SXWFO14ri5A=
cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps=
cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
github.com/AdguardTeam/dnsproxy v0.75.5 h1:/P7+Ku4bjl+sVC/FW3PbT7pabgCjKTcrAOHqsZe2e60=
github.com/AdguardTeam/dnsproxy v0.75.5/go.mod h1:fdwtHhrDkTueDagDCasYKZbXdppkkBXW7RGPBNH+pis=
github.com/AdguardTeam/golibs v0.32.9 h1:/6luT0aMOn05/s9eh1yA4lbcHgl0d1iEEvEBbIMMUk0=
github.com/AdguardTeam/golibs v0.32.9/go.mod h1:McV1QFFlKLElKa306V4OL/T2kr7564PhsayfvTWYBVs=
cloud.google.com/go/longrunning v0.6.6 h1:XJNDo5MUfMM05xK3ewpbSdmt7R2Zw+aQEMbdQR65Rbw=
cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw=
github.com/AdguardTeam/dnsproxy v0.75.2 h1:bciOkzQh/GG8vcZGdFn6+rS3pu+2Npt9tbA4bNA/rsc=
github.com/AdguardTeam/dnsproxy v0.75.2/go.mod h1:U/ouLftmXMIrkTAf8JepqbPuoQzsbXJo0Vxxn+LAdgA=
github.com/AdguardTeam/golibs v0.32.7 h1:3dmGlAVgmvquCCwHsvEl58KKcRAK3z1UnjMnwSIeDH4=
github.com/AdguardTeam/golibs v0.32.7/go.mod h1:bE8KV1zqTzgZjmjFyBJ9f9O5DEKO717r7e57j1HclJA=
github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs=
github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
@@ -72,8 +72,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4=
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
@@ -199,16 +199,16 @@ go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs=
go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
golang.org/x/exp/typeparams v0.0.0-20250408133849-7e4ce0ab07d0 h1:oMe07YcizemJ09rs2kRkFYAp0pt4e1lYLwPWiEGMpXE=
golang.org/x/exp/typeparams v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
golang.org/x/exp/typeparams v0.0.0-20250305212735-054e65f0b394 h1:VI4qDpTkfFaCXEPrbojidLgVQhj2x4nzTccG0hjaLlU=
golang.org/x/exp/typeparams v0.0.0-20250305212735-054e65f0b394/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -227,8 +227,8 @@ golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -241,10 +241,10 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20250417124945-06ef541f3fa3 h1:RXY2+rSHXvxO2Y+gKrPjYVaEoGOqh3VEXFhnWAt1Irg=
golang.org/x/telemetry v0.0.0-20250417124945-06ef541f3fa3/go.mod h1:RoaXAWDwS90j6FxVKwJdBV+0HCU+llrKUGgJaxiKl6M=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20250406004356-f593adaf3fc1 h1:LxyDqgHX2VuimV2UQSNFpQxz+NRUUsh8ulNcP3WvNG0=
golang.org/x/telemetry v0.0.0-20250406004356-f593adaf3fc1/go.mod h1:RoaXAWDwS90j6FxVKwJdBV+0HCU+llrKUGgJaxiKl6M=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
@@ -268,12 +268,12 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/api v0.229.0 h1:p98ymMtqeJ5i3lIBMj5MpR9kzIIgzpHHh8vQ+vgAzx8=
google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0=
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e h1:UdXH7Kzbj+Vzastr5nVfccbmFsmYNygVLSPk1pEfDoY=
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e/go.mod h1:085qFyf2+XaZlRdCgKNCIZ3afY2p4HHZdoIRpId8F4A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/api v0.228.0 h1:X2DJ/uoWGnY5obVjewbp8icSL5U4FzuCfy9OjbLSnLs=
google.golang.org/api v0.228.0/go.mod h1:wNvRS1Pbe8r4+IfBIniV8fwCpGwTrYa+kMUDiC5z5a4=
google.golang.org/genproto/googleapis/api v0.0.0-20250407143221-ac9807e6c755 h1:AMLTAunltONNuzWgVPZXrjLWtXpsG6A3yLLPEoJ/IjU=
google.golang.org/genproto/googleapis/api v0.0.0-20250407143221-ac9807e6c755/go.mod h1:2R6XrVC8Oc08GlNh8ujEpc7HkLiEZ16QeY7FxIs20ac=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250407143221-ac9807e6c755 h1:TwXJCGVREgQ/cl18iY0Z4wJCTL/GmW+Um2oSwZiZPnc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250407143221-ac9807e6c755/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
@@ -292,8 +292,8 @@ howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
mvdan.cc/editorconfig v0.3.0 h1:D1D2wLYEYGpawWT5SpM5pRivgEgXjtEXwC9MWhEY0gQ=
mvdan.cc/editorconfig v0.3.0/go.mod h1:NcJHuDtNOTEJ6251indKiWuzK6+VcrMuLzGMLKBFupQ=
mvdan.cc/gofumpt v0.8.0 h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k=
mvdan.cc/gofumpt v0.8.0/go.mod h1:vEYnSzyGPmjvFkqJWtXkh79UwPWP9/HMxQdGEXZHjpg=
mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU=
mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo=
mvdan.cc/sh/v3 v3.11.0 h1:q5h+XMDRfUGUedCqFFsjoFjrhwf2Mvtt1rkMvVz0blw=
mvdan.cc/sh/v3 v3.11.0/go.mod h1:LRM+1NjoYCzuq/WZ6y44x14YNAI0NK7FLPeQSaFagGg=
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 h1:WjUu4yQoT5BHT1w8Zu56SP8367OuBV5jvo+4Ulppyf8=

View File

@@ -10,8 +10,7 @@ import (
// Login is the type for web user logins.
type Login string
// NewLogin returns a web user login. The length of s must not be greater than
// [math.MaxUint16].
// NewLogin returns a web user login.
//
// TODO(s.chzhen): Add more constraints as needed.
func NewLogin(s string) (l Login, err error) {

View File

@@ -1,35 +0,0 @@
package aghuser
import (
"crypto/rand"
"time"
)
// SessionToken is the type for the web user session token.
type SessionToken [16]byte
// NewSessionToken returns a cryptographically secure randomly generated web
// user session token. If an error occurs during random generation, it will
// cause the program to crash.
func NewSessionToken() (t SessionToken) {
_, _ = rand.Read(t[:])
return t
}
// Session represents a web user session.
type Session struct {
// Expire indicates when the session will expire.
Expire time.Time
// UserLogin is the login of the web user associated with the session.
//
// TODO(s.chzhen): Remove this field and associate the user by UserID.
UserLogin Login
// Token is the session token.
Token SessionToken
// UserID is the identifier of the web user associated with the session.
UserID UserID
}

View File

@@ -1,449 +0,0 @@
package aghuser
import (
"context"
"encoding/binary"
"fmt"
"log/slog"
"sync"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/timeutil"
"go.etcd.io/bbolt"
berrors "go.etcd.io/bbolt/errors"
)
// SessionStorage is an interface that defines methods for handling web user
// sessions. All methods must be safe for concurrent use.
//
// TODO(s.chzhen): Add DeleteAll method.
type SessionStorage interface {
// New creates a new session for the web user.
New(ctx context.Context, u *User) (s *Session, err error)
// FindByToken returns the stored session for the web user based on the session
// token.
//
// TODO(s.chzhen): Consider function signature change to reflect the
// in-memory implementation, as it currently always returns nil for error.
FindByToken(ctx context.Context, t SessionToken) (s *Session, err error)
// DeleteByToken removes a stored web user session by the provided token.
DeleteByToken(ctx context.Context, t SessionToken) (err error)
// Close releases the web user sessions database resources.
Close() (err error)
}
// DefaultSessionStorageConfig represents the web user session storage
// configuration structure.
type DefaultSessionStorageConfig struct {
// Logger is used for logging the operation of the session storage. It must
// not be nil.
Logger *slog.Logger
// Clock is used to get the current time. It must not be nil.
Clock timeutil.Clock
// UserDB contains the web user information such as ID, login, and password.
// It must not be nil.
UserDB DB
// DBPath is the path to the database file where session data is stored. It
// must not be empty.
DBPath string
// SessionTTL is the default Time-To-Live duration for web user sessions.
// It specifies how long a session should last and is a required field.
SessionTTL time.Duration
}
// DefaultSessionStorage is the default bbolt database implementation of the
// [SessionStorage] interface.
type DefaultSessionStorage struct {
// db is an instance of the bbolt database where web user sessions are
// stored by [SessionToken] in the [bucketNameSessions] bucket.
db *bbolt.DB
// logger is used for logging the operation of the session storage.
logger *slog.Logger
// mu protects sessions.
mu *sync.Mutex
// clock is used to get the current time.
clock timeutil.Clock
// userDB contains the web user information such as ID, login, and password.
userDB DB
// sessions maps a session token to a web user session.
sessions map[SessionToken]*Session
// sessionTTL is the default Time-To-Live value for web user sessions.
sessionTTL time.Duration
}
// NewDefaultSessionStorage returns the new properly initialized
// *DefaultSessionStorage.
func NewDefaultSessionStorage(
ctx context.Context,
conf *DefaultSessionStorageConfig,
) (ds *DefaultSessionStorage, err error) {
ds = &DefaultSessionStorage{
clock: conf.Clock,
userDB: conf.UserDB,
logger: conf.Logger,
mu: &sync.Mutex{},
sessions: map[SessionToken]*Session{},
sessionTTL: conf.SessionTTL,
}
dbFilename := conf.DBPath
// TODO(s.chzhen): Pass logger with options.
ds.db, err = bbolt.Open(dbFilename, aghos.DefaultPermFile, nil)
if err != nil {
ds.logger.ErrorContext(ctx, "opening db %q: %w", dbFilename, err)
if errors.Is(err, berrors.ErrInvalid) {
const s = "AdGuard Home cannot be initialized due to an incompatible file system.\n" +
"Please read the explanation here: https://adguard-dns.io/kb/adguard-home/getting-started/#limitations"
slogutil.PrintLines(ctx, ds.logger, slog.LevelError, "", s)
}
return nil, err
}
err = ds.loadSessions(ctx)
if err != nil {
return nil, fmt.Errorf("loading sessions: %w", err)
}
return ds, nil
}
// loadSessions loads web user sessions from the bbolt database.
func (ds *DefaultSessionStorage) loadSessions(ctx context.Context) (err error) {
tx, err := ds.db.Begin(true)
if err != nil {
return fmt.Errorf("starting transaction: %w", err)
}
needRollback := true
defer func() {
if needRollback {
err = errors.WithDeferred(err, tx.Rollback())
}
}()
bkt := tx.Bucket([]byte(bboltBucketSessions))
if bkt == nil {
return nil
}
removed, err := ds.processSessions(ctx, bkt)
if err != nil {
return fmt.Errorf("processing sessions: %w", err)
}
if removed == 0 {
ds.logger.DebugContext(ctx, "loading sessions from db", "stored", len(ds.sessions))
return nil
}
needRollback = false
err = tx.Commit()
if err != nil {
return fmt.Errorf("committing transaction: %w", err)
}
ds.logger.DebugContext(
ctx,
"loading sessions from db",
"stored", len(ds.sessions),
"removed", removed,
)
return nil
}
// processSessions iterates over the sessions bucket and loads or removes
// sessions as needed.
func (ds *DefaultSessionStorage) processSessions(
ctx context.Context,
bkt *bbolt.Bucket,
) (removed int, err error) {
invalidSessions := [][]byte{}
err = bkt.ForEach(ds.bboltSessionHandler(ctx, &invalidSessions))
if err != nil {
return 0, fmt.Errorf("iterating over sessions: %w", err)
}
var errs []error
for _, s := range invalidSessions {
if err = bkt.Delete(s); err != nil {
errs = append(errs, err)
}
}
if err = errors.Join(errs...); err != nil {
return 0, fmt.Errorf("deleting sessions: %w", err)
}
return len(invalidSessions), nil
}
// bboltSessionHandler returns a function for [bbolt.Bucket.ForEach] that
// iterates over stored sessions, deserializes them, and logs any errors
// encountered. The returned error is always nil, as these errors are
// considered non-critical to stop the iteration process.
func (ds *DefaultSessionStorage) bboltSessionHandler(
ctx context.Context,
invalidSessions *[][]byte,
) (fn func(k, v []byte) (err error)) {
now := ds.clock.Now()
return func(k, v []byte) (err error) {
s, err := bboltDecode(v)
if err != nil {
*invalidSessions = append(*invalidSessions, k)
ds.logger.DebugContext(ctx, "deserializing session", slogutil.KeyError, err)
return nil
}
if now.After(s.Expire) {
*invalidSessions = append(*invalidSessions, k)
return nil
}
u, err := ds.userDB.ByLogin(ctx, s.UserLogin)
if err != nil {
// Should not happen, as it currently always returns nil for error.
panic(err)
}
if u == nil {
*invalidSessions = append(*invalidSessions, k)
ds.logger.DebugContext(ctx, "no saved user by name", "name", s.UserLogin)
return nil
}
t := SessionToken(k)
s.Token = t
s.UserID = u.ID
ds.sessions[t] = s
return nil
}
}
// bboltBucketSessions is the name of the bucket storing web user sessions in
// the bbolt database.
const bboltBucketSessions = "sessions-2"
const (
// bboltSessionExpireLen is the length of the expire field in the binary
// entry stored in bbolt.
bboltSessionExpireLen = 4
// bboltSessionNameLen is the length of the name field in the binary entry
// stored in bbolt.
bboltSessionNameLen = 2
)
// bboltDecode deserializes decodes a binary data into a session.
func bboltDecode(data []byte) (s *Session, err error) {
if len(data) < bboltSessionExpireLen+bboltSessionNameLen {
return nil, fmt.Errorf("length of the data is less than expected: got %d", len(data))
}
expireData := data[:bboltSessionExpireLen]
nameLenData := data[bboltSessionExpireLen : bboltSessionExpireLen+bboltSessionNameLen]
nameData := data[bboltSessionExpireLen+bboltSessionNameLen:]
nameLen := binary.BigEndian.Uint16(nameLenData)
if len(nameData) != int(nameLen) {
return nil, fmt.Errorf("login: expected length %d, got %d", nameLen, len(nameData))
}
expire := binary.BigEndian.Uint32(expireData)
return &Session{
Expire: time.Unix(int64(expire), 0),
UserLogin: Login(nameData),
}, nil
}
// bboltEncode serializes a session properties into a binary data.
func bboltEncode(s *Session) (data []byte) {
data = make([]byte, bboltSessionExpireLen+bboltSessionNameLen+len(s.UserLogin))
expireData := data[:bboltSessionExpireLen]
nameLenData := data[bboltSessionExpireLen : bboltSessionExpireLen+bboltSessionNameLen]
nameData := data[bboltSessionExpireLen+bboltSessionNameLen:]
expire := uint32(s.Expire.Unix())
binary.BigEndian.PutUint32(expireData, expire)
binary.BigEndian.PutUint16(nameLenData, uint16(len(s.UserLogin)))
copy(nameData, []byte(s.UserLogin))
return data
}
// type check
var _ SessionStorage = (*DefaultSessionStorage)(nil)
// New implements the [SessionStorage] interface for *DefaultSessionStorage.
func (ds *DefaultSessionStorage) New(ctx context.Context, u *User) (s *Session, err error) {
s = &Session{
Token: NewSessionToken(),
UserID: u.ID,
UserLogin: u.Login,
Expire: ds.clock.Now().Add(ds.sessionTTL),
}
err = ds.store(s)
if err != nil {
return nil, fmt.Errorf("storing session: %w", err)
}
ds.mu.Lock()
defer ds.mu.Unlock()
ds.sessions[s.Token] = s
return s, nil
}
// store saves a web user session in the bbolt database.
func (ds *DefaultSessionStorage) store(s *Session) (err error) {
tx, err := ds.db.Begin(true)
if err != nil {
return fmt.Errorf("starting transaction: %w", err)
}
needRollback := true
defer func() {
if needRollback {
err = errors.WithDeferred(err, tx.Rollback())
}
}()
bkt, err := tx.CreateBucketIfNotExists([]byte(bboltBucketSessions))
if err != nil {
return fmt.Errorf("creating bucket: %w", err)
}
err = bkt.Put(s.Token[:], bboltEncode(s))
if err != nil {
return fmt.Errorf("putting data: %w", err)
}
needRollback = false
err = tx.Commit()
if err != nil {
return fmt.Errorf("committing transaction: %w", err)
}
return nil
}
// FindByToken implements the [SessionStorage] interface for *DefaultSessionStorage.
func (ds *DefaultSessionStorage) FindByToken(ctx context.Context, t SessionToken) (s *Session, err error) {
ds.mu.Lock()
defer ds.mu.Unlock()
s, ok := ds.sessions[t]
if !ok {
return nil, nil
}
now := ds.clock.Now()
if now.After(s.Expire) {
err = ds.deleteByToken(ctx, t)
if err != nil {
return nil, fmt.Errorf("expired session: %w", err)
}
return nil, nil
}
return s, nil
}
// DeleteByToken implements the [SessionStorage] interface for
// *DefaultSessionStorage.
func (ds *DefaultSessionStorage) DeleteByToken(ctx context.Context, t SessionToken) (err error) {
ds.mu.Lock()
defer ds.mu.Unlock()
// Don't wrap the error because it's informative enough as is.
return ds.deleteByToken(ctx, t)
}
// deleteByToken removes stored session by token. ds.mu is expected to be
// locked.
func (ds *DefaultSessionStorage) deleteByToken(ctx context.Context, t SessionToken) (err error) {
err = ds.remove(ctx, t)
if err != nil {
ds.logger.ErrorContext(ctx, "deleting session", slogutil.KeyError, err)
return err
}
delete(ds.sessions, t)
return nil
}
// remove deletes a web user session from the bbolt database.
func (ds *DefaultSessionStorage) remove(ctx context.Context, t SessionToken) (err error) {
tx, err := ds.db.Begin(true)
if err != nil {
return fmt.Errorf("starting transaction: %w", err)
}
needRollback := true
defer func() {
if needRollback {
err = errors.WithDeferred(err, tx.Rollback())
}
}()
bkt := tx.Bucket([]byte(bboltBucketSessions))
if bkt == nil {
return errors.Error("no bucket")
}
err = bkt.Delete(t[:])
if err != nil {
return fmt.Errorf("removing data: %w", err)
}
needRollback = false
err = tx.Commit()
if err != nil {
return fmt.Errorf("committing transaction: %w", err)
}
ds.logger.DebugContext(ctx, "removed session from db")
return err
}
// Close implements the [SessionStorage] interface for *DefaultSessionStorage.
func (ds *DefaultSessionStorage) Close() (err error) {
err = ds.db.Close()
if err != nil {
return fmt.Errorf("closing db: %w", err)
}
return nil
}

View File

@@ -1,162 +0,0 @@
package aghuser_test
import (
"context"
"os"
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghuser"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/AdguardTeam/golibs/testutil/faketime"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// addSession is a helper function that saves and returns a session for a newly
// generated [aghuser.User] by login.
func addSession(
tb testing.TB,
ctx context.Context,
ds aghuser.SessionStorage,
login aghuser.Login,
) (s *aghuser.Session) {
tb.Helper()
s, err := ds.New(ctx, &aghuser.User{
ID: aghuser.MustNewUserID(),
Login: login,
})
require.NoError(tb, err)
require.NotNil(tb, s)
var got *aghuser.Session
got, err = ds.FindByToken(ctx, s.Token)
require.NoError(tb, err)
require.NotNil(tb, got)
assert.Equal(tb, login, got.UserLogin)
return s
}
func TestDefaultSessionStorage(t *testing.T) {
const (
userLoginFirst aghuser.Login = "user_one"
userLoginSecond aghuser.Login = "user_two"
)
var (
ctx = testutil.ContextWithTimeout(t, testTimeout)
logger = slogutil.NewDiscardLogger()
)
const (
sessionTTL = time.Minute
timeStep = time.Second
)
// Set up a mock clock to test expired sessions. Each call to [clock.Now]
// will return the [date] incremented by [timeStep].
date := time.Now()
clock := &faketime.Clock{
OnNow: func() (now time.Time) {
date = date.Add(timeStep)
return date
},
}
dbFile, err := os.CreateTemp(t.TempDir(), "sessions.db")
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, dbFile.Close)
userDB := aghuser.NewDefaultDB()
err = userDB.Create(ctx, &aghuser.User{
Login: userLoginFirst,
ID: aghuser.MustNewUserID(),
})
require.NoError(t, err)
err = userDB.Create(ctx, &aghuser.User{
Login: userLoginSecond,
ID: aghuser.MustNewUserID(),
})
require.NoError(t, err)
var (
ds *aghuser.DefaultSessionStorage
sessionFirst *aghuser.Session
sessionSecond *aghuser.Session
)
require.True(t, t.Run("prepare_session_storage", func(t *testing.T) {
ds, err = aghuser.NewDefaultSessionStorage(ctx, &aghuser.DefaultSessionStorageConfig{
Clock: clock,
UserDB: userDB,
Logger: logger,
DBPath: dbFile.Name(),
SessionTTL: sessionTTL,
})
require.NoError(t, err)
sessionFirst = addSession(t, ctx, ds, userLoginFirst)
// Advance time to ensure the first session expires before creating the
// second session.
date = date.Add(time.Hour)
sessionSecond = addSession(t, ctx, ds, userLoginSecond)
err = ds.Close()
require.NoError(t, err)
}))
require.True(t, t.Run("load_sessions", func(t *testing.T) {
ds, err = aghuser.NewDefaultSessionStorage(ctx, &aghuser.DefaultSessionStorageConfig{
Clock: clock,
UserDB: userDB,
Logger: logger,
DBPath: dbFile.Name(),
SessionTTL: sessionTTL,
})
require.NoError(t, err)
var got *aghuser.Session
got, err = ds.FindByToken(ctx, sessionFirst.Token)
require.NoError(t, err)
assert.Nil(t, got)
got, err = ds.FindByToken(ctx, sessionSecond.Token)
require.NoError(t, err)
require.NotNil(t, got)
assert.Equal(t, userLoginSecond, got.UserLogin)
err = ds.DeleteByToken(ctx, sessionSecond.Token)
require.NoError(t, err)
got, err = ds.FindByToken(ctx, sessionSecond.Token)
require.NoError(t, err)
assert.Nil(t, got)
}))
require.True(t, t.Run("expired_session", func(t *testing.T) {
testutil.CleanupAndRequireSuccess(t, ds.Close)
sessionFirst = addSession(t, ctx, ds, userLoginFirst)
date = date.Add(time.Hour)
var got *aghuser.Session
got, err = ds.FindByToken(ctx, sessionFirst.Token)
require.NoError(t, err)
assert.Nil(t, got)
}))
}

View File

@@ -32,13 +32,13 @@ func MustNewUserID() (uid UserID) {
// User represents a web user.
type User struct {
// Password stores the password information for the web user. It must not
// be nil.
Password Password
// ID is the unique identifier for the web user. It must not be empty.
ID UserID
// Login is the login name of the web user. It must not be empty.
Login Login
// ID is the unique identifier for the web user. It must not be empty.
ID UserID
// Password stores the password information for the web user. It must not
// be nil.
Password Password
}

View File

@@ -11,34 +11,8 @@ import (
"slices"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
)
// ClientID is a unique identifier for a persistent client used in
// DNS-over-HTTPS, DNS-over-TLS, and DNS-over-QUIC queries.
//
// TODO(s.chzhen): Use everywhere.
type ClientID string
// ValidateClientID returns an error if id is not a valid ClientID.
//
// TODO(s.chzhen): Consider implementing [validate.Interface] for ClientID.
func ValidateClientID(id string) (err error) {
err = netutil.ValidateHostnameLabel(id)
if err != nil {
// Replace the domain name label wrapper with our own.
return fmt.Errorf("invalid clientid %q: %w", id, errors.Unwrap(err))
}
return nil
}
// isValidClientID returns false if id is not a valid ClientID.
func isValidClientID(id string) (ok bool) {
return netutil.IsValidHostnameLabel(id)
}
// Source represents the source from which the information about the client has
// been obtained.
type Source uint8

View File

@@ -35,7 +35,7 @@ type index struct {
nameToUID map[string]UID
// clientIDToUID maps ClientID to UID.
clientIDToUID map[ClientID]UID
clientIDToUID map[string]UID
// ipToUID maps IP address to UID.
ipToUID map[netip.Addr]UID
@@ -54,7 +54,7 @@ type index struct {
func newIndex() (ci *index) {
return &index{
nameToUID: map[string]UID{},
clientIDToUID: map[ClientID]UID{},
clientIDToUID: map[string]UID{},
ipToUID: map[netip.Addr]UID{},
subnetToUID: aghalg.NewSortedMap[netip.Prefix, UID](subnetCompare),
macToUID: map[macKey]UID{},
@@ -207,7 +207,7 @@ func (ci *index) clashesMAC(c *Persistent) (p *Persistent, mac net.HardwareAddr)
// find finds persistent client by string representation of the ClientID, IP
// address, or MAC.
func (ci *index) find(id string) (c *Persistent, ok bool) {
c, ok = ci.findByClientID(ClientID(id))
c, ok = ci.findByClientID(id)
if ok {
return c, true
}
@@ -230,7 +230,7 @@ func (ci *index) find(id string) (c *Persistent, ok bool) {
}
// findByClientID finds persistent client by ClientID.
func (ci *index) findByClientID(clientID ClientID) (c *Persistent, ok bool) {
func (ci *index) findByClientID(clientID string) (c *Persistent, ok bool) {
uid, ok := ci.clientIDToUID[clientID]
if ok {
return ci.uidToClient[uid], true
@@ -275,26 +275,6 @@ func (ci *index) findByIP(ip netip.Addr) (c *Persistent, found bool) {
return nil, false
}
// findByCIDR searches for a persistent client with the provided subnet as an
// identifier. Note that this function looks for an exact match of subnets,
// rather than checking if one subnet contains another.
func (ci *index) findByCIDR(subnet netip.Prefix) (c *Persistent, ok bool) {
var uid UID
for pref, id := range ci.subnetToUID.Range {
if subnet == pref {
uid, ok = id, true
break
}
}
if ok {
return ci.uidToClient[uid], true
}
return nil, false
}
// findByMAC finds persistent client by MAC.
func (ci *index) findByMAC(mac net.HardwareAddr) (c *Persistent, found bool) {
k := macToKey(mac)

View File

@@ -5,7 +5,6 @@ import (
"net/netip"
"testing"
"github.com/AdguardTeam/golibs/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -59,12 +58,12 @@ func TestClientIndex_Find(t *testing.T) {
clientWithMAC = &Persistent{
Name: "client_with_mac",
MACs: []net.HardwareAddr{errors.Must(net.ParseMAC(cliMAC))},
MACs: []net.HardwareAddr{mustParseMAC(cliMAC)},
}
clientWithID = &Persistent{
Name: "client_with_id",
ClientIDs: []ClientID{cliID},
ClientIDs: []string{cliID},
}
clientLinkLocal = &Persistent{
@@ -142,10 +141,10 @@ func TestClientIndex_Clashes(t *testing.T) {
Subnets: []netip.Prefix{netip.MustParsePrefix(cliSubnet)},
}, {
Name: "client_with_mac",
MACs: []net.HardwareAddr{errors.Must(net.ParseMAC(cliMAC))},
MACs: []net.HardwareAddr{mustParseMAC(cliMAC)},
}, {
Name: "client_with_id",
ClientIDs: []ClientID{cliID},
ClientIDs: []string{cliID},
}}
ci := newIDIndex(clients)
@@ -182,6 +181,17 @@ func TestClientIndex_Clashes(t *testing.T) {
}
}
// mustParseMAC is wrapper around [net.ParseMAC] that panics if there is an
// error.
func mustParseMAC(s string) (mac net.HardwareAddr) {
mac, err := net.ParseMAC(s)
if err != nil {
panic(err)
}
return mac
}
func TestMACToKey(t *testing.T) {
testCases := []struct {
want any
@@ -190,44 +200,44 @@ func TestMACToKey(t *testing.T) {
}{{
name: "column6",
in: "00:00:5e:00:53:01",
want: [6]byte(errors.Must(net.ParseMAC("00:00:5e:00:53:01"))),
want: [6]byte(mustParseMAC("00:00:5e:00:53:01")),
}, {
name: "column8",
in: "02:00:5e:10:00:00:00:01",
want: [8]byte(errors.Must(net.ParseMAC("02:00:5e:10:00:00:00:01"))),
want: [8]byte(mustParseMAC("02:00:5e:10:00:00:00:01")),
}, {
name: "column20",
in: "00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01",
want: [20]byte(errors.Must(net.ParseMAC("00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01"))),
want: [20]byte(mustParseMAC("00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01")),
}, {
name: "hyphen6",
in: "00-00-5e-00-53-01",
want: [6]byte(errors.Must(net.ParseMAC("00-00-5e-00-53-01"))),
want: [6]byte(mustParseMAC("00-00-5e-00-53-01")),
}, {
name: "hyphen8",
in: "02-00-5e-10-00-00-00-01",
want: [8]byte(errors.Must(net.ParseMAC("02-00-5e-10-00-00-00-01"))),
want: [8]byte(mustParseMAC("02-00-5e-10-00-00-00-01")),
}, {
name: "hyphen20",
in: "00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01",
want: [20]byte(errors.Must(net.ParseMAC("00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01"))),
want: [20]byte(mustParseMAC("00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01")),
}, {
name: "dot6",
in: "0000.5e00.5301",
want: [6]byte(errors.Must(net.ParseMAC("0000.5e00.5301"))),
want: [6]byte(mustParseMAC("0000.5e00.5301")),
}, {
name: "dot8",
in: "0200.5e10.0000.0001",
want: [8]byte(errors.Must(net.ParseMAC("0200.5e10.0000.0001"))),
want: [8]byte(mustParseMAC("0200.5e10.0000.0001")),
}, {
name: "dot20",
in: "0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001",
want: [20]byte(errors.Must(net.ParseMAC("0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001"))),
want: [20]byte(mustParseMAC("0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001")),
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mac := errors.Must(net.ParseMAC(tc.in))
mac := mustParseMAC(tc.in)
key := macToKey(mac)
assert.Equal(t, tc.want, key)
@@ -292,19 +302,19 @@ func TestIndex_FindByIPWithoutZone(t *testing.T) {
func TestClientIndex_RangeByName(t *testing.T) {
sortedClients := []*Persistent{{
Name: "clientA",
ClientIDs: []ClientID{"A"},
ClientIDs: []string{"A"},
}, {
Name: "clientB",
ClientIDs: []ClientID{"B"},
ClientIDs: []string{"B"},
}, {
Name: "clientC",
ClientIDs: []ClientID{"C"},
ClientIDs: []string{"C"},
}, {
Name: "clientD",
ClientIDs: []ClientID{"D"},
ClientIDs: []string{"D"},
}, {
Name: "clientE",
ClientIDs: []ClientID{"E"},
ClientIDs: []string{"E"},
}}
testCases := []struct {
@@ -339,115 +349,3 @@ func TestClientIndex_RangeByName(t *testing.T) {
})
}
}
func TestIndex_FindByName(t *testing.T) {
const (
clientExistingName = "client_existing"
clientAnotherExistingName = "client_another_existing"
nonExistingClientName = "client_non_existing"
)
var (
clientExisting = &Persistent{
Name: clientExistingName,
IPs: []netip.Addr{netip.MustParseAddr("192.0.2.1")},
}
clientAnotherExisting = &Persistent{
Name: clientAnotherExistingName,
IPs: []netip.Addr{netip.MustParseAddr("192.0.2.2")},
}
)
clients := []*Persistent{
clientExisting,
clientAnotherExisting,
}
ci := newIDIndex(clients)
testCases := []struct {
want *Persistent
found assert.BoolAssertionFunc
name string
clientName string
}{{
want: clientExisting,
found: assert.True,
name: "existing",
clientName: clientExistingName,
}, {
want: clientAnotherExisting,
found: assert.True,
name: "another_existing",
clientName: clientAnotherExistingName,
}, {
want: nil,
found: assert.False,
name: "non_existing",
clientName: nonExistingClientName,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
c, ok := ci.findByName(tc.clientName)
assert.Equal(t, tc.want, c)
tc.found(t, ok)
})
}
}
func TestIndex_FindByMAC(t *testing.T) {
var (
cliMAC = errors.Must(net.ParseMAC("11:11:11:11:11:11"))
cliAnotherMAC = errors.Must(net.ParseMAC("22:22:22:22:22:22"))
nonExistingClientMAC = errors.Must(net.ParseMAC("33:33:33:33:33:33"))
)
var (
clientExisting = &Persistent{
Name: "client",
MACs: []net.HardwareAddr{cliMAC},
}
clientAnotherExisting = &Persistent{
Name: "another_client",
MACs: []net.HardwareAddr{cliAnotherMAC},
}
)
clients := []*Persistent{
clientExisting,
clientAnotherExisting,
}
ci := newIDIndex(clients)
testCases := []struct {
want *Persistent
found assert.BoolAssertionFunc
name string
clientMAC net.HardwareAddr
}{{
want: clientExisting,
found: assert.True,
name: "existing",
clientMAC: cliMAC,
}, {
want: clientAnotherExisting,
found: assert.True,
name: "another_existing",
clientMAC: cliAnotherMAC,
}, {
want: nil,
found: assert.False,
name: "non_existing",
clientMAC: nonExistingClientMAC,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
c, ok := ci.findByMAC(tc.clientMAC)
assert.Equal(t, tc.want, c)
tc.found(t, ok)
})
}
}

View File

@@ -15,6 +15,7 @@ import (
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/google/uuid"
)
@@ -70,9 +71,7 @@ type Persistent struct {
// Tags is a list of client tags that categorize the client.
Tags []string
// Upstreams is a list of custom upstream DNS servers for the client. If
// it's empty, the custom upstream cache is disabled, regardless of the
// value of UpstreamsCacheEnabled.
// Upstreams is a list of custom upstream DNS servers for the client.
Upstreams []string
// IPs is a list of IP addresses that identify the client. The client must
@@ -91,16 +90,15 @@ type Persistent struct {
// ClientIDs identifying the client. The client must have at least one ID
// (IP, subnet, MAC, or ClientID).
ClientIDs []ClientID
ClientIDs []string
// UID is the unique identifier of the persistent client.
UID UID
// UpstreamsCacheSize defines the size of the custom upstream cache.
// UpstreamsCacheSize is the cache size for custom upstreams.
UpstreamsCacheSize uint32
// UpstreamsCacheEnabled specifies whether the custom upstream cache is
// used. If true, the list of Upstreams should not be empty.
// UpstreamsCacheEnabled specifies whether custom upstreams are used.
UpstreamsCacheEnabled bool
// UseOwnSettings specifies whether custom filtering settings are used.
@@ -136,7 +134,7 @@ func (c *Persistent) validate(ctx context.Context, l *slog.Logger, allTags []str
switch {
case c.Name == "":
return errors.Error("empty name")
case c.idendifiersLen() == 0:
case c.IDsLen() == 0:
return errors.Error("id required")
case c.UID == UID{}:
return errors.Error("uid required")
@@ -239,15 +237,28 @@ func (c *Persistent) setID(id string) (err error) {
return err
}
c.ClientIDs = append(c.ClientIDs, ClientID(strings.ToLower(id)))
c.ClientIDs = append(c.ClientIDs, strings.ToLower(id))
return nil
}
// Identifiers returns a list of client identifiers containing at least one
// element.
func (c *Persistent) Identifiers() (ids []string) {
ids = make([]string, 0, c.idendifiersLen())
// ValidateClientID returns an error if id is not a valid ClientID.
//
// TODO(s.chzhen): It's an exact copy of the [dnsforward.ValidateClientID] to
// avoid the import cycle. Remove it.
func ValidateClientID(id string) (err error) {
err = netutil.ValidateHostnameLabel(id)
if err != nil {
// Replace the domain name label wrapper with our own.
return fmt.Errorf("invalid clientid %q: %w", id, errors.Unwrap(err))
}
return nil
}
// IDs returns a list of ClientIDs containing at least one element.
func (c *Persistent) IDs() (ids []string) {
ids = make([]string, 0, c.IDsLen())
for _, ip := range c.IPs {
ids = append(ids, ip.String())
@@ -261,15 +272,11 @@ func (c *Persistent) Identifiers() (ids []string) {
ids = append(ids, mac.String())
}
for _, cid := range c.ClientIDs {
ids = append(ids, string(cid))
}
return ids
return append(ids, c.ClientIDs...)
}
// identifiersLen returns the number of client identifiers.
func (c *Persistent) idendifiersLen() (n int) {
// IDsLen returns a length of ClientIDs.
func (c *Persistent) IDsLen() (n int) {
return len(c.IPs) + len(c.Subnets) + len(c.MACs) + len(c.ClientIDs)
}

View File

@@ -18,7 +18,6 @@ import (
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/hostsfile"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/timeutil"
)
@@ -434,138 +433,48 @@ func (s *Storage) Add(ctx context.Context, p *Persistent) (err error) {
ctx,
"client added",
"name", p.Name,
"ids", p.Identifiers(),
"ids", p.IDs(),
"clients_count", s.index.size(),
)
return nil
}
// FindParams represents the parameters for searching a client. At least one
// field must be non-empty.
type FindParams struct {
// ClientID is a unique identifier for the client used in DoH, DoT, and DoQ
// DNS queries.
ClientID ClientID
// RemoteIP is the IP address used as a client search parameter.
RemoteIP netip.Addr
// Subnet is the CIDR used as a client search parameter.
Subnet netip.Prefix
// MAC is the physical hardware address used as a client search parameter.
MAC net.HardwareAddr
// UID is the unique ID of persistent client used as a search parameter.
//
// TODO(s.chzhen): Use this.
UID UID
}
// ErrBadIdentifier is returned by [FindParams.Set] when it cannot parse the
// provided client identifier.
const ErrBadIdentifier errors.Error = "bad client identifier"
// Set clears the stored search parameters and parses the string representation
// of the search parameter into typed parameter, storing it. In some cases, it
// may result in storing both an IP address and a MAC address because they might
// have identical string representations. It returns [ErrBadIdentifier] if id
// cannot be parsed.
//
// TODO(s.chzhen): Add support for UID.
func (p *FindParams) Set(id string) (err error) {
*p = FindParams{}
isFound := false
if netutil.IsValidIPString(id) {
// It is safe to use [netip.MustParseAddr] because it has already been
// validated that id contains the string representation of the IP
// address.
p.RemoteIP = netip.MustParseAddr(id)
// Even if id can be parsed as an IP address, it may be a MAC address.
// So do not return prematurely, continue parsing.
isFound = true
}
if netutil.IsValidMACString(id) {
p.MAC, err = net.ParseMAC(id)
if err != nil {
panic(fmt.Errorf("parsing mac from %q: %w", id, err))
}
isFound = true
}
if isFound {
return nil
}
if netutil.IsValidIPPrefixString(id) {
// It is safe to use [netip.MustParsePrefix] because it has already been
// validated that id contains the string representation of IP prefix.
p.Subnet = netip.MustParsePrefix(id)
return nil
}
if !isValidClientID(id) {
return ErrBadIdentifier
}
p.ClientID = ClientID(id)
return nil
}
// Find represents the parameters for searching a client. params must not be
// nil and must have at least one non-empty field.
func (s *Storage) Find(params *FindParams) (p *Persistent, ok bool) {
// FindByName finds persistent client by name. And returns its shallow copy.
func (s *Storage) FindByName(name string) (p *Persistent, ok bool) {
s.mu.Lock()
defer s.mu.Unlock()
isClientID := params.ClientID != ""
isRemoteIP := params.RemoteIP != (netip.Addr{})
isSubnet := params.Subnet != (netip.Prefix{})
isMAC := params.MAC != nil
for {
switch {
case isClientID:
isClientID = false
p, ok = s.index.findByClientID(params.ClientID)
case isRemoteIP:
isRemoteIP = false
p, ok = s.findByIP(params.RemoteIP)
case isSubnet:
isSubnet = false
p, ok = s.index.findByCIDR(params.Subnet)
case isMAC:
isMAC = false
p, ok = s.index.findByMAC(params.MAC)
default:
return nil, false
}
if ok {
return p.ShallowClone(), true
}
p, ok = s.index.findByName(name)
if ok {
return p.ShallowClone(), ok
}
return nil, false
}
// findByIP finds persistent client by IP address. s.mu is expected to be
// locked.
func (s *Storage) findByIP(addr netip.Addr) (p *Persistent, ok bool) {
p, ok = s.index.findByIP(addr)
// Find finds persistent client by string representation of the ClientID, IP
// address, or MAC. And returns its shallow copy.
//
// TODO(s.chzhen): Accept ClientIDData structure instead, which will contain
// the parsed IP address, if any.
func (s *Storage) Find(id string) (p *Persistent, ok bool) {
s.mu.Lock()
defer s.mu.Unlock()
p, ok = s.index.find(id)
if ok {
return p, true
return p.ShallowClone(), ok
}
foundMAC := s.dhcp.MACByIP(addr)
ip, err := netip.ParseAddr(id)
if err != nil {
return nil, false
}
foundMAC := s.dhcp.MACByIP(ip)
if foundMAC != nil {
return s.index.findByMAC(foundMAC)
return s.FindByMAC(foundMAC)
}
return nil, false
@@ -578,8 +487,6 @@ func (s *Storage) findByIP(addr netip.Addr) (p *Persistent, ok bool) {
//
// Note that multiple clients can have the same IP address with different zones.
// Therefore, the result of this method is indeterminate.
//
// TODO(s.chzhen): Consider accepting [FindParams].
func (s *Storage) FindLoose(ip netip.Addr, id string) (p *Persistent, ok bool) {
s.mu.Lock()
defer s.mu.Unlock()
@@ -591,7 +498,7 @@ func (s *Storage) FindLoose(ip netip.Addr, id string) (p *Persistent, ok bool) {
foundMAC := s.dhcp.MACByIP(ip)
if foundMAC != nil {
return s.index.findByMAC(foundMAC)
return s.FindByMAC(foundMAC)
}
p = s.index.findByIPWithoutZone(ip)
@@ -602,6 +509,17 @@ func (s *Storage) FindLoose(ip netip.Addr, id string) (p *Persistent, ok bool) {
return nil, false
}
// FindByMAC finds persistent client by MAC and returns its shallow copy. s.mu
// is expected to be locked.
func (s *Storage) FindByMAC(mac net.HardwareAddr) (p *Persistent, ok bool) {
p, ok = s.index.findByMAC(mac)
if ok {
return p.ShallowClone(), ok
}
return nil, false
}
// RemoveByName removes persistent client information. ok is false if no such
// client exists by that name.
func (s *Storage) RemoveByName(ctx context.Context, name string) (ok bool) {
@@ -730,9 +648,9 @@ func (s *Storage) CustomUpstreamConfig(
s.mu.Lock()
defer s.mu.Unlock()
c, ok := s.index.findByClientID(ClientID(id))
c, ok := s.index.findByClientID(id)
if !ok {
c, ok = s.findByIP(addr)
c, ok = s.index.findByIP(addr)
}
if !ok {
@@ -764,7 +682,7 @@ func (s *Storage) ClearUpstreamCache() {
// ClientID or client IP address, and applies it to the filtering settings.
// setts must not be nil.
func (s *Storage) ApplyClientFiltering(id string, addr netip.Addr, setts *filtering.Settings) {
c, ok := s.index.findByClientID(ClientID(id))
c, ok := s.index.findByClientID(id)
if !ok {
c, ok = s.index.findByIP(addr)
}
@@ -772,7 +690,7 @@ func (s *Storage) ApplyClientFiltering(id string, addr netip.Addr, setts *filter
if !ok {
foundMAC := s.dhcp.MACByIP(addr)
if foundMAC != nil {
c, ok = s.index.findByMAC(foundMAC)
c, ok = s.FindByMAC(foundMAC)
}
}

View File

@@ -15,7 +15,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/hostsfile"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
@@ -351,15 +350,15 @@ func TestClientsDHCP(t *testing.T) {
cliName1 = "one.dhcp"
cliIP2 = netip.MustParseAddr("2.2.2.2")
cliMAC2 = errors.Must(net.ParseMAC("22:22:22:22:22:22"))
cliMAC2 = mustParseMAC("22:22:22:22:22:22")
cliName2 = "two.dhcp"
cliIP3 = netip.MustParseAddr("3.3.3.3")
cliMAC3 = errors.Must(net.ParseMAC("33:33:33:33:33:33"))
cliMAC3 = mustParseMAC("33:33:33:33:33:33")
cliName3 = "three.dhcp"
prsCliIP = netip.MustParseAddr("4.3.2.1")
prsCliMAC = errors.Must(net.ParseMAC("AA:AA:AA:AA:AA:AA"))
prsCliMAC = mustParseMAC("AA:AA:AA:AA:AA:AA")
prsCliName = "persistent.dhcp"
otherARPCliName = "other.arp"
@@ -520,11 +519,7 @@ func TestClientsDHCP(t *testing.T) {
})
require.NoError(t, err)
params := &client.FindParams{}
err = params.Set(prsCliIP.String())
require.NoError(t, err)
prsCli, ok := storage.Find(params)
prsCli, ok := storage.Find(prsCliIP.String())
require.True(t, ok)
assert.Equal(t, prsCliName, prsCli.Name)
@@ -668,6 +663,17 @@ func newStorage(tb testing.TB, m []*client.Persistent) (s *client.Storage) {
return s
}
// mustParseMAC is wrapper around [net.ParseMAC] that panics if there is an
// error.
func mustParseMAC(s string) (mac net.HardwareAddr) {
mac, err := net.ParseMAC(s)
if err != nil {
panic(err)
}
return mac
}
func TestStorage_Add(t *testing.T) {
const (
existingName = "existing_name"
@@ -687,7 +693,7 @@ func TestStorage_Add(t *testing.T) {
Name: existingName,
IPs: []netip.Addr{existingIP},
Subnets: []netip.Prefix{existingSubnet},
ClientIDs: []client.ClientID{existingClientID},
ClientIDs: []string{existingClientID},
UID: existingClientUID,
}
@@ -755,7 +761,7 @@ func TestStorage_Add(t *testing.T) {
name: "duplicate_client_id",
cli: &client.Persistent{
Name: "duplicate_client_id",
ClientIDs: []client.ClientID{existingClientID},
ClientIDs: []string{existingClientID},
UID: client.MustNewUID(),
},
wantErrMsg: `adding client: another client "existing_name" ` +
@@ -892,12 +898,12 @@ func TestStorage_Find(t *testing.T) {
clientWithMAC = &client.Persistent{
Name: "client_with_mac",
MACs: []net.HardwareAddr{errors.Must(net.ParseMAC(cliMAC))},
MACs: []net.HardwareAddr{mustParseMAC(cliMAC)},
}
clientWithID = &client.Persistent{
Name: "client_with_id",
ClientIDs: []client.ClientID{cliID},
ClientIDs: []string{cliID},
}
clientLinkLocal = &client.Persistent{
@@ -944,11 +950,7 @@ func TestStorage_Find(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
for _, id := range tc.ids {
params := &client.FindParams{}
err := params.Set(id)
require.NoError(t, err)
c, ok := s.Find(params)
c, ok := s.Find(id)
require.True(t, ok)
assert.Equal(t, tc.want, c)
@@ -957,11 +959,7 @@ func TestStorage_Find(t *testing.T) {
}
t.Run("not_found", func(t *testing.T) {
params := &client.FindParams{}
err := params.Set(cliIPNone)
require.NoError(t, err)
_, ok := s.Find(params)
_, ok := s.Find(cliIPNone)
assert.False(t, ok)
})
}
@@ -1027,6 +1025,127 @@ func TestStorage_FindLoose(t *testing.T) {
}
}
func TestStorage_FindByName(t *testing.T) {
const (
cliIP1 = "1.1.1.1"
cliIP2 = "2.2.2.2"
)
const (
clientExistingName = "client_existing"
clientAnotherExistingName = "client_another_existing"
nonExistingClientName = "client_non_existing"
)
var (
clientExisting = &client.Persistent{
Name: clientExistingName,
IPs: []netip.Addr{netip.MustParseAddr(cliIP1)},
}
clientAnotherExisting = &client.Persistent{
Name: clientAnotherExistingName,
IPs: []netip.Addr{netip.MustParseAddr(cliIP2)},
}
)
clients := []*client.Persistent{
clientExisting,
clientAnotherExisting,
}
s := newStorage(t, clients)
testCases := []struct {
want *client.Persistent
name string
clientName string
}{{
name: "existing",
clientName: clientExistingName,
want: clientExisting,
}, {
name: "another_existing",
clientName: clientAnotherExistingName,
want: clientAnotherExisting,
}, {
name: "non_existing",
clientName: nonExistingClientName,
want: nil,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
c, ok := s.FindByName(tc.clientName)
if tc.want == nil {
assert.False(t, ok)
return
}
assert.True(t, ok)
assert.Equal(t, tc.want, c)
})
}
}
func TestStorage_FindByMAC(t *testing.T) {
var (
cliMAC = mustParseMAC("11:11:11:11:11:11")
cliAnotherMAC = mustParseMAC("22:22:22:22:22:22")
nonExistingClientMAC = mustParseMAC("33:33:33:33:33:33")
)
var (
clientExisting = &client.Persistent{
Name: "client",
MACs: []net.HardwareAddr{cliMAC},
}
clientAnotherExisting = &client.Persistent{
Name: "another_client",
MACs: []net.HardwareAddr{cliAnotherMAC},
}
)
clients := []*client.Persistent{
clientExisting,
clientAnotherExisting,
}
s := newStorage(t, clients)
testCases := []struct {
want *client.Persistent
name string
clientMAC net.HardwareAddr
}{{
name: "existing",
clientMAC: cliMAC,
want: clientExisting,
}, {
name: "another_existing",
clientMAC: cliAnotherMAC,
want: clientAnotherExisting,
}, {
name: "non_existing",
clientMAC: nonExistingClientMAC,
want: nil,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
c, ok := s.FindByMAC(tc.clientMAC)
if tc.want == nil {
assert.False(t, ok)
return
}
assert.True(t, ok)
assert.Equal(t, tc.want, c)
})
}
}
func TestStorage_Update(t *testing.T) {
const (
clientName = "client_name"
@@ -1043,7 +1162,7 @@ func TestStorage_Update(t *testing.T) {
Name: obstructingName,
IPs: []netip.Addr{obstructingIP},
Subnets: []netip.Prefix{obstructingSubnet},
ClientIDs: []client.ClientID{obstructingClientID},
ClientIDs: []string{obstructingClientID},
}
clientToUpdate := &client.Persistent{
@@ -1092,7 +1211,7 @@ func TestStorage_Update(t *testing.T) {
name: "duplicate_client_id",
cli: &client.Persistent{
Name: "duplicate_client_id",
ClientIDs: []client.ClientID{obstructingClientID},
ClientIDs: []string{obstructingClientID},
UID: client.MustNewUID(),
},
wantErrMsg: `updating client: another client "obstructing_name" ` +
@@ -1119,19 +1238,19 @@ func TestStorage_Update(t *testing.T) {
func TestStorage_RangeByName(t *testing.T) {
sortedClients := []*client.Persistent{{
Name: "clientA",
ClientIDs: []client.ClientID{"A"},
ClientIDs: []string{"A"},
}, {
Name: "clientB",
ClientIDs: []client.ClientID{"B"},
ClientIDs: []string{"B"},
}, {
Name: "clientC",
ClientIDs: []client.ClientID{"C"},
ClientIDs: []string{"C"},
}, {
Name: "clientD",
ClientIDs: []client.ClientID{"D"},
ClientIDs: []string{"D"},
}, {
Name: "clientE",
ClientIDs: []client.ClientID{"E"},
ClientIDs: []string{"E"},
}}
testCases := []struct {
@@ -1169,20 +1288,29 @@ func TestStorage_RangeByName(t *testing.T) {
func TestStorage_CustomUpstreamConfig(t *testing.T) {
const (
existingClientID = "existing_client_id"
existingName = "existing_name"
existingClientID = "existing_client_id"
nonExistingClientID = "non_existing_client_id"
)
var (
existingIP = netip.MustParseAddr("192.0.2.1")
nonExistingIP = netip.MustParseAddr("192.0.2.255")
existingClientUID = client.MustNewUID()
existingIP = netip.MustParseAddr("192.0.2.1")
dhcpCliIP = netip.MustParseAddr("192.0.2.2")
dhcpCliMAC = errors.Must(net.ParseMAC("02:00:00:00:00:00"))
nonExistingIP = netip.MustParseAddr("192.0.2.255")
testUpstreamTimeout = time.Second
)
existingClient := &client.Persistent{
Name: existingName,
IPs: []netip.Addr{existingIP},
ClientIDs: []string{existingClientID},
UID: existingClientUID,
Upstreams: []string{"192.0.2.0"},
}
date := time.Now()
clock := &faketime.Clock{
OnNow: func() (now time.Time) {
@@ -1192,30 +1320,7 @@ func TestStorage_CustomUpstreamConfig(t *testing.T) {
},
}
ipToMAC := map[netip.Addr]net.HardwareAddr{
dhcpCliIP: dhcpCliMAC,
}
dhcp := &testDHCP{
OnLeases: func() (ls []*dhcpsvc.Lease) {
panic("not implemented")
},
OnHostBy: func(ip netip.Addr) (host string) {
panic("not implemented")
},
OnMACBy: func(ip netip.Addr) (mac net.HardwareAddr) {
return ipToMAC[ip]
},
}
ctx := testutil.ContextWithTimeout(t, testTimeout)
s, err := client.NewStorage(ctx, &client.StorageConfig{
Logger: slogutil.NewDiscardLogger(),
Clock: clock,
DHCP: dhcp,
})
require.NoError(t, err)
s := newTestStorage(t, clock)
s.UpdateCommonUpstreamConfig(&client.CommonUpstreamConfig{
UpstreamTimeout: testUpstreamTimeout,
})
@@ -1224,21 +1329,8 @@ func TestStorage_CustomUpstreamConfig(t *testing.T) {
return s.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
})
err = s.Add(ctx, &client.Persistent{
Name: "client_first",
IPs: []netip.Addr{existingIP},
ClientIDs: []client.ClientID{existingClientID},
UID: client.MustNewUID(),
Upstreams: []string{"192.0.2.0"},
})
require.NoError(t, err)
err = s.Add(ctx, &client.Persistent{
Name: "client_second",
MACs: []net.HardwareAddr{dhcpCliMAC},
UID: client.MustNewUID(),
Upstreams: []string{"192.0.2.0"},
})
ctx := testutil.ContextWithTimeout(t, testTimeout)
err := s.Add(ctx, existingClient)
require.NoError(t, err)
testCases := []struct {
@@ -1256,11 +1348,6 @@ func TestStorage_CustomUpstreamConfig(t *testing.T) {
cliID: "",
cliAddr: existingIP,
wantNilConf: assert.NotNil,
}, {
name: "client_dhcp",
cliID: "",
cliAddr: dhcpCliIP,
wantNilConf: assert.NotNil,
}, {
name: "non_existing_client_id",
cliID: nonExistingClientID,
@@ -1293,193 +1380,4 @@ func TestStorage_CustomUpstreamConfig(t *testing.T) {
assert.NotEqual(t, conf, updConf)
})
t.Run("same_custom_config", func(t *testing.T) {
firstConf := s.CustomUpstreamConfig(existingClientID, existingIP)
require.NotNil(t, firstConf)
secondConf := s.CustomUpstreamConfig(existingClientID, existingIP)
require.NotNil(t, secondConf)
assert.Same(t, firstConf, secondConf)
})
}
func BenchmarkFindParams_Set(b *testing.B) {
const (
testIPStr = "192.0.2.1"
testCIDRStr = "192.0.2.0/24"
testMACStr = "02:00:00:00:00:00"
testClientID = "clientid"
)
benchCases := []struct {
wantErr error
params *client.FindParams
name string
id string
}{{
wantErr: nil,
params: &client.FindParams{
ClientID: testClientID,
},
name: "client_id",
id: testClientID,
}, {
wantErr: nil,
params: &client.FindParams{
RemoteIP: netip.MustParseAddr(testIPStr),
},
name: "ip_address",
id: testIPStr,
}, {
wantErr: nil,
params: &client.FindParams{
Subnet: netip.MustParsePrefix(testCIDRStr),
},
name: "subnet",
id: testCIDRStr,
}, {
wantErr: nil,
params: &client.FindParams{
MAC: errors.Must(net.ParseMAC(testMACStr)),
},
name: "mac_address",
id: testMACStr,
}, {
wantErr: client.ErrBadIdentifier,
params: &client.FindParams{},
name: "bad_id",
id: "!@#$%^&*()_+",
}}
for _, bc := range benchCases {
b.Run(bc.name, func(b *testing.B) {
params := &client.FindParams{}
var err error
b.ReportAllocs()
for b.Loop() {
err = params.Set(bc.id)
}
assert.ErrorIs(b, err, bc.wantErr)
assert.Equal(b, bc.params, params)
})
}
// Most recent results:
//
// goos: linux
// goarch: amd64
// pkg: github.com/AdguardTeam/AdGuardHome/internal/client
// cpu: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz
// BenchmarkFindParams_Set/client_id-8 49463488 24.27 ns/op 0 B/op 0 allocs/op
// BenchmarkFindParams_Set/ip_address-8 18740977 62.22 ns/op 0 B/op 0 allocs/op
// BenchmarkFindParams_Set/subnet-8 10848192 110.0 ns/op 0 B/op 0 allocs/op
// BenchmarkFindParams_Set/mac_address-8 8148494 133.2 ns/op 8 B/op 1 allocs/op
// BenchmarkFindParams_Set/bad_id-8 73894278 16.29 ns/op 0 B/op 0 allocs/op
}
func BenchmarkStorage_Find(b *testing.B) {
const (
cliID = "cid"
cliMAC = "02:00:00:00:00:00"
)
const (
cliNameWithID = "client_with_id"
cliNameWithIP = "client_with_ip"
cliNameWithCIDR = "client_with_cidr"
cliNameWithMAC = "client_with_mac"
)
var (
cliIP = netip.MustParseAddr("192.0.2.1")
cliCIDR = netip.MustParsePrefix("192.0.2.0/24")
)
var (
clientWithID = &client.Persistent{
Name: cliNameWithID,
ClientIDs: []client.ClientID{cliID},
}
clientWithIP = &client.Persistent{
Name: cliNameWithIP,
IPs: []netip.Addr{cliIP},
}
clientWithCIDR = &client.Persistent{
Name: cliNameWithCIDR,
Subnets: []netip.Prefix{cliCIDR},
}
clientWithMAC = &client.Persistent{
Name: cliNameWithMAC,
MACs: []net.HardwareAddr{errors.Must(net.ParseMAC(cliMAC))},
}
)
clients := []*client.Persistent{
clientWithID,
clientWithIP,
clientWithCIDR,
clientWithMAC,
}
s := newStorage(b, clients)
benchCases := []struct {
params *client.FindParams
name string
wantName string
}{{
params: &client.FindParams{
ClientID: cliID,
},
name: "client_id",
wantName: cliNameWithID,
}, {
params: &client.FindParams{
RemoteIP: cliIP,
},
name: "ip_address",
wantName: cliNameWithIP,
}, {
params: &client.FindParams{
Subnet: cliCIDR,
},
name: "subnet",
wantName: cliNameWithCIDR,
}, {
params: &client.FindParams{
MAC: errors.Must(net.ParseMAC(cliMAC)),
},
name: "mac_address",
wantName: cliNameWithMAC,
}}
for _, bc := range benchCases {
b.Run(bc.name, func(b *testing.B) {
var p *client.Persistent
var ok bool
b.ReportAllocs()
for b.Loop() {
p, ok = s.Find(bc.params)
}
assert.True(b, ok)
assert.NotNil(b, p)
assert.Equal(b, bc.wantName, p.Name)
})
}
// Most recent results:
//
// goos: linux
// goarch: amd64
// pkg: github.com/AdguardTeam/AdGuardHome/internal/client
// cpu: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz
// BenchmarkStorage_Find/client_id-8 7070107 154.4 ns/op 240 B/op 2 allocs/op
// BenchmarkStorage_Find/ip_address-8 6831823 168.6 ns/op 248 B/op 2 allocs/op
// BenchmarkStorage_Find/subnet-8 7209050 167.5 ns/op 256 B/op 2 allocs/op
// BenchmarkStorage_Find/mac_address-8 5776131 199.7 ns/op 256 B/op 3 allocs/op
}

View File

@@ -138,7 +138,6 @@ func (m *upstreamManager) customUpstreamConfig(uid UID) (proxyConf *proxy.Custom
proxyConf = newCustomUpstreamConfig(cliConf, m.commonConf)
cliConf.proxyConf = proxyConf
cliConf.commonConfUpdate = m.confUpdate
cliConf.isChanged = false
return proxyConf

View File

@@ -1,11 +1,13 @@
package dhcpsvc_test
import (
"net"
"net/netip"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/stretchr/testify/require"
)
// testLocalTLD is a common local TLD for tests.
@@ -54,3 +56,11 @@ var testInterfaceConf = map[string]*dhcpsvc.InterfaceConfig{
},
},
}
// mustParseMAC parses a hardware address from s and requires no errors.
func mustParseMAC(t require.TestingT, s string) (mac net.HardwareAddr) {
mac, err := net.ParseMAC(s)
require.NoError(t, err)
return mac
}

View File

@@ -2,7 +2,6 @@ package dhcpsvc_test
import (
"io/fs"
"net"
"net/netip"
"os"
"path"
@@ -12,7 +11,6 @@ import (
"time"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -178,9 +176,9 @@ func TestDHCPServer_AddLease(t *testing.T) {
newIP = netip.MustParseAddr("192.168.0.3")
newIPv6 = netip.MustParseAddr("2001:db8::2")
existMAC = errors.Must(net.ParseMAC("01:02:03:04:05:06"))
newMAC = errors.Must(net.ParseMAC("06:05:04:03:02:01"))
ipv6MAC = errors.Must(net.ParseMAC("02:03:04:05:06:07"))
existMAC = mustParseMAC(t, "01:02:03:04:05:06")
newMAC = mustParseMAC(t, "06:05:04:03:02:01")
ipv6MAC = mustParseMAC(t, "02:03:04:05:06:07")
)
require.NoError(t, srv.AddLease(ctx, &dhcpsvc.Lease{
@@ -293,9 +291,9 @@ func TestDHCPServer_index(t *testing.T) {
ip3 = netip.MustParseAddr("172.16.0.3")
ip4 = netip.MustParseAddr("172.16.0.4")
mac1 = errors.Must(net.ParseMAC("01:02:03:04:05:06"))
mac2 = errors.Must(net.ParseMAC("06:05:04:03:02:01"))
mac3 = errors.Must(net.ParseMAC("02:03:04:05:06:07"))
mac1 = mustParseMAC(t, "01:02:03:04:05:06")
mac2 = mustParseMAC(t, "06:05:04:03:02:01")
mac3 = mustParseMAC(t, "02:03:04:05:06:07")
)
t.Run("ip_idx", func(t *testing.T) {
@@ -351,9 +349,9 @@ func TestDHCPServer_UpdateStaticLease(t *testing.T) {
ip3 = netip.MustParseAddr("192.168.0.4")
ip4 = netip.MustParseAddr("2001:db8::3")
mac1 = errors.Must(net.ParseMAC("01:02:03:04:05:06"))
mac2 = errors.Must(net.ParseMAC("06:05:04:03:02:01"))
mac3 = errors.Must(net.ParseMAC("06:05:04:03:02:02"))
mac1 = mustParseMAC(t, "01:02:03:04:05:06")
mac2 = mustParseMAC(t, "06:05:04:03:02:01")
mac3 = mustParseMAC(t, "06:05:04:03:02:02")
)
testCases := []struct {
@@ -454,9 +452,9 @@ func TestDHCPServer_RemoveLease(t *testing.T) {
newIP = netip.MustParseAddr("192.168.0.3")
newIPv6 = netip.MustParseAddr("2001:db8::2")
existMAC = errors.Must(net.ParseMAC("01:02:03:04:05:06"))
newMAC = errors.Must(net.ParseMAC("02:03:04:05:06:07"))
ipv6MAC = errors.Must(net.ParseMAC("06:05:04:03:02:01"))
existMAC = mustParseMAC(t, "01:02:03:04:05:06")
newMAC = mustParseMAC(t, "02:03:04:05:06:07")
ipv6MAC = mustParseMAC(t, "06:05:04:03:02:01")
)
testCases := []struct {
@@ -561,13 +559,13 @@ func TestServer_Leases(t *testing.T) {
Expiry: expiry,
IP: netip.MustParseAddr("192.168.0.3"),
Hostname: "example.host",
HWAddr: errors.Must(net.ParseMAC("AA:AA:AA:AA:AA:AA")),
HWAddr: mustParseMAC(t, "AA:AA:AA:AA:AA:AA"),
IsStatic: false,
}, {
Expiry: time.Time{},
IP: netip.MustParseAddr("192.168.0.4"),
Hostname: "example.static.host",
HWAddr: errors.Must(net.ParseMAC("BB:BB:BB:BB:BB:BB")),
HWAddr: mustParseMAC(t, "BB:BB:BB:BB:BB:BB"),
IsStatic: true,
}}
assert.ElementsMatch(t, wantLeases, srv.Leases())

View File

@@ -10,7 +10,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
@@ -52,7 +51,7 @@ func processAccessClients(
} else if ipnet, err = netip.ParsePrefix(s); err == nil {
*nets = append(*nets, ipnet)
} else {
err = client.ValidateClientID(s)
err = ValidateClientID(s)
if err != nil {
return fmt.Errorf("value %q at index %d: bad ip, cidr, or clientid", s, i)
}

View File

@@ -74,7 +74,7 @@ func (s *Server) clientIDFromDNSContext(pctx *proxy.DNSContext) (clientID string
return "", nil
}
hostSrvName := s.conf.TLSConf.ServerName
hostSrvName := s.conf.ServerName
if hostSrvName == "" {
return "", nil
}
@@ -87,7 +87,7 @@ func (s *Server) clientIDFromDNSContext(pctx *proxy.DNSContext) (clientID string
clientID, err = clientIDFromClientServerName(
hostSrvName,
cliSrvName,
s.conf.TLSConf.StrictSNICheck,
s.conf.StrictSNICheck,
)
if err != nil {
return "", fmt.Errorf("clientid check: %w", err)

View File

@@ -121,7 +121,7 @@ func TestServer_HandleBefore_tls(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
s, _ := createTestTLS(t, &TLSConfig{
s, _ := createTestTLS(t, TLSConfig{
TLSListenAddrs: []*net.TCPAddr{{}},
ServerName: tlsServerName,
})
@@ -259,7 +259,6 @@ func TestServer_HandleBefore_udp(t *testing.T) {
}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
AllowedClients: tc.allowedClients,
DisallowedClients: tc.disallowedClients,

View File

@@ -7,13 +7,26 @@ import (
"path"
"strings"
"github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/quic-go/quic-go"
)
// ValidateClientID returns an error if id is not a valid ClientID.
//
// Keep in sync with [client.ValidateClientID].
func ValidateClientID(id string) (err error) {
err = netutil.ValidateHostnameLabel(id)
if err != nil {
// Replace the domain name label wrapper with our own.
return fmt.Errorf("invalid clientid %q: %w", id, errors.Unwrap(err))
}
return nil
}
// clientIDFromClientServerName extracts and validates a ClientID. hostSrvName
// is the server name of the host. cliSrvName is the server name as sent by the
// client. When strict is true, and client and host server name don't match,
@@ -40,7 +53,7 @@ func clientIDFromClientServerName(
}
clientID = cliSrvName[:len(cliSrvName)-len(hostSrvName)-1]
err = client.ValidateClientID(clientID)
err = ValidateClientID(clientID)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return "", err
@@ -80,7 +93,7 @@ func clientIDFromDNSContextHTTPS(pctx *proxy.DNSContext) (clientID string, err e
return "", fmt.Errorf("clientid check: invalid path %q: extra parts", origPath)
}
err = client.ValidateClientID(clientID)
err = ValidateClientID(clientID)
if err != nil {
return "", fmt.Errorf("clientid check: %w", err)
}

View File

@@ -212,13 +212,13 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
tlsConf := &TLSConfig{
tlsConf := TLSConfig{
ServerName: tc.confSrvName,
StrictSNICheck: tc.strictSNI,
}
srv := &Server{
conf: ServerConfig{TLSConf: tlsConf},
conf: ServerConfig{TLSConfig: tlsConf},
baseLogger: slogutil.NewDiscardLogger(),
}

View File

@@ -11,6 +11,7 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghtls"
@@ -167,34 +168,43 @@ type EDNSClientSubnet struct {
UseCustom bool `yaml:"use_custom"`
}
// TLSConfig contains the TLS configuration settings for DNS-over-HTTPS (DoH),
// DNS-over-TLS (DoT), DNS-over-QUIC (DoQ), and Discovery of Designated
// Resolvers (DDR).
// TLSConfig is the TLS configuration for HTTPS, DNS-over-HTTPS, and DNS-over-TLS
type TLSConfig struct {
// Cert is the TLS certificate used for TLS connections. It is nil if
// encryption is disabled.
Cert *tls.Certificate
cert tls.Certificate
// TLSListenAddrs are the addresses to listen on for DoT connections. Each
// item in the list must be non-nil if Cert is not nil.
TLSListenAddrs []*net.TCPAddr
TLSListenAddrs []*net.TCPAddr `yaml:"-" json:"-"`
QUICListenAddrs []*net.UDPAddr `yaml:"-" json:"-"`
HTTPSListenAddrs []*net.TCPAddr `yaml:"-" json:"-"`
// QUICListenAddrs are the addresses to listen on for DoQ connections. Each
// item in the list must be non-nil if Cert is not nil.
QUICListenAddrs []*net.UDPAddr
// PEM-encoded certificates chain
CertificateChain string `yaml:"certificate_chain" json:"certificate_chain"`
// PEM-encoded private key
PrivateKey string `yaml:"private_key" json:"private_key"`
// HTTPSListenAddrs should be the addresses AdGuard Home is listening on for
// DoH connections. These addresses are announced with DDR. Each item in
// the list must be non-nil.
HTTPSListenAddrs []*net.TCPAddr
CertificatePath string `yaml:"certificate_path" json:"certificate_path"`
PrivateKeyPath string `yaml:"private_key_path" json:"private_key_path"`
CertificateChainData []byte `yaml:"-" json:"-"`
PrivateKeyData []byte `yaml:"-" json:"-"`
// ServerName is the hostname of the server. Currently, it is only being
// used for ClientID checking and Discovery of Designated Resolvers (DDR).
ServerName string
ServerName string `yaml:"-" json:"-"`
// DNS names from certificate (SAN) or CN value from Subject
dnsNames []string
// OverrideTLSCiphers, when set, contains the names of the cipher suites to
// use. If the slice is empty, the default safe suites are used.
OverrideTLSCiphers []string `yaml:"override_tls_ciphers,omitempty" json:"-"`
// StrictSNICheck controls if the connections with SNI mismatching the
// certificate's ones should be rejected.
StrictSNICheck bool
StrictSNICheck bool `yaml:"strict_sni_check" json:"-"`
// hasIPAddrs is set during the certificate parsing and is true if the
// configured certificate contains at least a single IP address.
hasIPAddrs bool
}
// DNSCryptConfig is the DNSCrypt server configuration struct.
@@ -229,11 +239,8 @@ type ServerConfig struct {
// Remove that.
AddrProcConf *client.DefaultAddrProcConfig
// TLSConf is the TLS configuration for DNS-over-TLS, DNS-over-QUIC, and
// HTTPS. It must not be nil.
TLSConf *TLSConfig
Config
TLSConfig
DNSCryptConfig
TLSAllowUnencryptedDoH bool
@@ -274,10 +281,6 @@ type ServerConfig struct {
// ServePlainDNS defines if plain DNS is allowed for incoming requests.
ServePlainDNS bool
// PendingRequestsEnabled defines if duplicate requests should be forwarded
// to upstreams along with the original one.
PendingRequestsEnabled bool
}
// UpstreamMode is a enumeration of upstream mode representations. See
@@ -321,9 +324,6 @@ func (s *Server) newProxyConfig() (conf *proxy.Config, err error) {
UsePrivateRDNS: srvConf.UsePrivateRDNS,
PrivateSubnets: s.privateNets,
MessageConstructor: s,
PendingRequests: &proxy.PendingRequestsConfig{
Enabled: srvConf.PendingRequestsEnabled,
},
}
if srvConf.EDNSClientSubnet.UseCustom {
@@ -608,33 +608,45 @@ func (conf *ServerConfig) ourAddrsSet() (m addrPortSet, err error) {
}
}
// prepareTLS sets up the TLS configuration for the DNS proxy.
// prepareTLS - prepares TLS configuration for the DNS proxy
func (s *Server) prepareTLS(proxyConfig *proxy.Config) (err error) {
if s.conf.TLSConf.Cert == nil {
return
}
if s.conf.TLSConf.TLSListenAddrs == nil && s.conf.TLSConf.QUICListenAddrs == nil {
if len(s.conf.CertificateChainData) == 0 || len(s.conf.PrivateKeyData) == 0 {
return nil
}
proxyConfig.TLSListenAddr = s.conf.TLSConf.TLSListenAddrs
proxyConfig.QUICListenAddr = s.conf.TLSConf.QUICListenAddrs
if s.conf.TLSListenAddrs == nil && s.conf.QUICListenAddrs == nil {
return nil
}
cert, err := x509.ParseCertificate(s.conf.TLSConf.Cert.Certificate[0])
proxyConfig.TLSListenAddr = aghalg.CoalesceSlice(
s.conf.TLSListenAddrs,
proxyConfig.TLSListenAddr,
)
proxyConfig.QUICListenAddr = aghalg.CoalesceSlice(
s.conf.QUICListenAddrs,
proxyConfig.QUICListenAddr,
)
s.conf.cert, err = tls.X509KeyPair(s.conf.CertificateChainData, s.conf.PrivateKeyData)
if err != nil {
return fmt.Errorf("failed to parse TLS keypair: %w", err)
}
cert, err := x509.ParseCertificate(s.conf.cert.Certificate[0])
if err != nil {
return fmt.Errorf("x509.ParseCertificate(): %w", err)
}
s.hasIPAddrs = aghtls.CertificateHasIP(cert)
s.conf.hasIPAddrs = aghtls.CertificateHasIP(cert)
if s.conf.TLSConf.StrictSNICheck {
if s.conf.StrictSNICheck {
if len(cert.DNSNames) != 0 {
s.dnsNames = cert.DNSNames
s.conf.dnsNames = cert.DNSNames
log.Debug("dns: using certificate's SAN as DNS names: %v", cert.DNSNames)
slices.Sort(s.dnsNames)
slices.Sort(s.conf.dnsNames)
} else {
s.dnsNames = []string{cert.Subject.CommonName}
s.conf.dnsNames = append(s.conf.dnsNames, cert.Subject.CommonName)
log.Debug("dns: using certificate's CN as DNS name: %s", cert.Subject.CommonName)
}
}
@@ -683,11 +695,11 @@ func anyNameMatches(dnsNames []string, sni string) (ok bool) {
// Called by 'tls' package when Client Hello is received
// If the server name (from SNI) supplied by client is incorrect - we terminate the ongoing TLS handshake.
func (s *Server) onGetCertificate(ch *tls.ClientHelloInfo) (*tls.Certificate, error) {
if s.conf.TLSConf.StrictSNICheck && !anyNameMatches(s.dnsNames, ch.ServerName) {
if s.conf.StrictSNICheck && !anyNameMatches(s.conf.dnsNames, ch.ServerName) {
log.Info("dns: tls: unknown SNI in Client Hello: %s", ch.ServerName)
return nil, fmt.Errorf("invalid SNI")
}
return s.conf.TLSConf.Cert, nil
return &s.conf.cert, nil
}
// preparePlain prepares the plain-DNS configuration for the DNS proxy.

View File

@@ -296,7 +296,6 @@ func TestServer_HandleDNSRequest_dns64(t *testing.T) {
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
UseDNS64: true,
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
@@ -336,7 +335,6 @@ func TestServer_dns64WithDisabledRDNS(t *testing.T) {
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
UseDNS64: true,
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},

View File

@@ -103,26 +103,16 @@ type SystemResolvers interface {
//
// The zero Server is empty and ready for use.
type Server struct {
// addrProc, if not nil, is used to process clients' IP addresses with rDNS,
// WHOIS, etc.
addrProc client.AddressProcessor
// dnsProxy is the DNS proxy for forwarding client's DNS requests.
dnsProxy *proxy.Proxy
// bootstrap is the resolver for upstreams' hostnames.
bootstrap upstream.Resolver
// clientIDCache is a temporary storage for ClientIDs that were extracted
// during the BeforeRequestHandler stage.
clientIDCache cache.Cache
// dnsFilter is the DNS filter for filtering client's DNS requests and
// responses.
dnsFilter *filtering.DNSFilter
// dhcpServer is the DHCP server for accessing lease data.
dhcpServer DHCP
// etcHosts contains the current data from the system's hosts files.
etcHosts upstream.Resolver
// privateNets is the configured set of IP networks considered private.
privateNets netutil.SubnetSet
// queryLog is the query log for client's DNS requests, responses and
// filtering results.
queryLog querylog.QueryLog
@@ -130,43 +120,37 @@ type Server struct {
// stats is the statistics collector for client's DNS usage data.
stats stats.Interface
// sysResolvers used to fetch system resolvers to use by default for private
// PTR resolving.
sysResolvers SystemResolvers
// access drops disallowed clients.
access *accessManager
// anonymizer masks the client's IP addresses if needed.
anonymizer *aghnet.IPMut
// baseLogger is used to create loggers for other entities. It should not
// have a prefix and must not be nil.
baseLogger *slog.Logger
// dnsFilter is the DNS filter for filtering client's DNS requests and
// responses.
dnsFilter *filtering.DNSFilter
// dnsProxy is the DNS proxy for forwarding client's DNS requests.
dnsProxy *proxy.Proxy
// internalProxy resolves internal requests from the application itself. It
// isn't started and so no listen ports are required.
internalProxy *proxy.Proxy
// localDomainSuffix is the suffix used to detect internal hosts. It
// must be a valid domain name plus dots on each side.
localDomainSuffix string
// ipset processes DNS requests using ipset data. It must not be nil after
// initialization. See [newIpsetHandler].
ipset *ipsetHandler
// dns64Pref is the NAT64 prefix used for DNS64 response mapping. The major
// part of DNS64 happens inside the [proxy] package, but there still are
// some places where response mapping is needed (e.g. DHCP).
dns64Pref netip.Prefix
// privateNets is the configured set of IP networks considered private.
privateNets netutil.SubnetSet
// localDomainSuffix is the suffix used to detect internal hosts. It
// must be a valid domain name plus dots on each side.
localDomainSuffix string
// addrProc, if not nil, is used to process clients' IP addresses with rDNS,
// WHOIS, etc.
addrProc client.AddressProcessor
// sysResolvers used to fetch system resolvers to use by default for private
// PTR resolving.
sysResolvers SystemResolvers
// etcHosts contains the current data from the system's hosts files.
etcHosts upstream.Resolver
// bootstrap is the resolver for upstreams' hostnames.
bootstrap upstream.Resolver
// bootResolvers are the resolvers that should be used for
// bootstrapping along with [etcHosts].
@@ -175,26 +159,34 @@ type Server struct {
// [upstream.Resolver] interface.
bootResolvers []*upstream.UpstreamResolver
// dnsNames are the DNS names from certificate (SAN) or CN value from
// Subject.
dnsNames []string
// dns64Pref is the NAT64 prefix used for DNS64 response mapping. The major
// part of DNS64 happens inside the [proxy] package, but there still are
// some places where response mapping is needed (e.g. DHCP).
dns64Pref netip.Prefix
// anonymizer masks the client's IP addresses if needed.
anonymizer *aghnet.IPMut
// clientIDCache is a temporary storage for ClientIDs that were extracted
// during the BeforeRequestHandler stage.
clientIDCache cache.Cache
// internalProxy resolves internal requests from the application itself. It
// isn't started and so no listen ports are required.
internalProxy *proxy.Proxy
// isRunning is true if the DNS server is running.
isRunning bool
// protectionUpdateInProgress is used to make sure that only one goroutine
// updating the protection configuration after a pause is running at a time.
protectionUpdateInProgress atomic.Bool
// conf is the current configuration of the server.
conf ServerConfig
// serverLock protects Server.
serverLock sync.RWMutex
// protectionUpdateInProgress is used to make sure that only one goroutine
// updating the protection configuration after a pause is running at a time.
protectionUpdateInProgress atomic.Bool
// isRunning is true if the DNS server is running.
isRunning bool
// hasIPAddrs is set during the certificate parsing and is true if the
// configured certificate contains at least a single IP address.
hasIPAddrs bool
}
// defaultLocalDomainSuffix is the default suffix used to detect internal hosts

View File

@@ -213,23 +213,17 @@ func createServerTLSConfig(t *testing.T) (*tls.Config, []byte, []byte) {
}, certPem, keyPem
}
func createTestTLS(t *testing.T, tlsConf *TLSConfig) (s *Server, certPem []byte) {
func createTestTLS(t *testing.T, tlsConf TLSConfig) (s *Server, certPem []byte) {
t.Helper()
var keyPem []byte
_, certPem, keyPem = createServerTLSConfig(t)
cert, err := tls.X509KeyPair(certPem, keyPem)
require.NoError(t, err)
tlsConf.Cert = &cert
s = createTestServer(t, &filtering.Config{
BlockingMode: filtering.BlockingModeDefault,
}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: tlsConf,
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
@@ -238,7 +232,10 @@ func createTestTLS(t *testing.T, tlsConf *TLSConfig) (s *Server, certPem []byte)
ServePlainDNS: true,
})
err = s.Prepare(&s.conf)
tlsConf.CertificateChainData, tlsConf.PrivateKeyData = certPem, keyPem
s.conf.TLSConfig = tlsConf
err := s.Prepare(&s.conf)
require.NoErrorf(t, err, "failed to prepare server: %s", err)
return s, certPem
@@ -357,7 +354,6 @@ func TestServer(t *testing.T) {
}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
@@ -399,7 +395,6 @@ func TestServer_timeout(t *testing.T) {
t.Run("custom", func(t *testing.T) {
srvConf := &ServerConfig{
UpstreamTimeout: testTimeout,
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
@@ -427,7 +422,6 @@ func TestServer_timeout(t *testing.T) {
})
require.NoError(t, err)
s.conf.TLSConf = &TLSConfig{}
s.conf.Config.UpstreamMode = UpstreamModeLoadBalance
s.conf.Config.EDNSClientSubnet = &EDNSClientSubnet{
Enabled: false,
@@ -442,7 +436,6 @@ func TestServer_timeout(t *testing.T) {
func TestServer_Prepare_fallbacks(t *testing.T) {
srvConf := &ServerConfig{
TLSConf: &TLSConfig{},
Config: Config{
FallbackDNS: []string{
"#tls://1.1.1.1",
@@ -473,7 +466,6 @@ func TestServerWithProtectionDisabled(t *testing.T) {
}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
@@ -495,7 +487,7 @@ func TestServerWithProtectionDisabled(t *testing.T) {
}
func TestDoTServer(t *testing.T) {
s, certPem := createTestTLS(t, &TLSConfig{
s, certPem := createTestTLS(t, TLSConfig{
TLSListenAddrs: []*net.TCPAddr{{}},
})
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()}
@@ -519,7 +511,7 @@ func TestDoTServer(t *testing.T) {
}
func TestDoQServer(t *testing.T) {
s, _ := createTestTLS(t, &TLSConfig{
s, _ := createTestTLS(t, TLSConfig{
QUICListenAddrs: []*net.UDPAddr{{IP: net.IP{127, 0, 0, 1}}},
})
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()}
@@ -604,7 +596,6 @@ func TestSafeSearch(t *testing.T) {
forwardConf := ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{
@@ -699,7 +690,6 @@ func TestInvalidRequest(t *testing.T) {
}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{
@@ -731,7 +721,6 @@ func TestBlockedRequest(t *testing.T) {
forwardConf := ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{
@@ -769,7 +758,6 @@ func TestServerCustomClientUpstream(t *testing.T) {
forwardConf := ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
CacheSize: defaultCacheSize,
UpstreamMode: UpstreamModeLoadBalance,
@@ -850,7 +838,6 @@ func TestBlockCNAMEProtectionEnabled(t *testing.T) {
}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{
@@ -886,7 +873,6 @@ func TestBlockCNAME(t *testing.T) {
forwardConf := ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{
@@ -961,7 +947,6 @@ func TestClientRulesForCNAMEMatching(t *testing.T) {
forwardConf := ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{
@@ -1009,7 +994,6 @@ func TestNullBlockedRequest(t *testing.T) {
forwardConf := ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{
@@ -1080,7 +1064,6 @@ func TestBlockedCustomIP(t *testing.T) {
conf := &ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
UpstreamMode: UpstreamModeLoadBalance,
@@ -1136,7 +1119,6 @@ func TestBlockedByHosts(t *testing.T) {
forwardConf := ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{
@@ -1190,7 +1172,6 @@ func TestBlockedBySafeBrowsing(t *testing.T) {
forwardConf := ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{
@@ -1254,7 +1235,6 @@ func TestRewrite(t *testing.T) {
assert.NoError(t, s.Prepare(&ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamDNS: []string{"8.8.8.8:53"},
UpstreamMode: UpstreamModeLoadBalance,
@@ -1389,7 +1369,6 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) {
s.conf.UDPListenAddrs = []*net.UDPAddr{{}}
s.conf.TCPListenAddrs = []*net.TCPAddr{{}}
s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
s.conf.TLSConf = &TLSConfig{}
s.conf.Config.EDNSClientSubnet = &EDNSClientSubnet{Enabled: false}
s.conf.Config.ClientsContainer = EmptyClientsContainer{}
s.conf.Config.UpstreamMode = UpstreamModeLoadBalance
@@ -1478,7 +1457,6 @@ func TestPTRResponseFromHosts(t *testing.T) {
s.conf.UDPListenAddrs = []*net.UDPAddr{{}}
s.conf.TCPListenAddrs = []*net.TCPAddr{{}}
s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
s.conf.TLSConf = &TLSConfig{}
s.conf.Config.EDNSClientSubnet = &EDNSClientSubnet{Enabled: false}
s.conf.Config.ClientsContainer = EmptyClientsContainer{}
s.conf.Config.UpstreamMode = UpstreamModeLoadBalance
@@ -1745,7 +1723,6 @@ func TestServer_Exchange(t *testing.T) {
srv := createTestServer(t, &filtering.Config{
BlockingMode: filtering.BlockingModeDefault,
}, ServerConfig{
TLSConf: &TLSConfig{},
Config: Config{
UpstreamDNS: []string{upsAddr},
UpstreamMode: UpstreamModeLoadBalance,
@@ -1769,7 +1746,6 @@ func TestServer_Exchange(t *testing.T) {
srv := createTestServer(t, &filtering.Config{
BlockingMode: filtering.BlockingModeDefault,
}, ServerConfig{
TLSConf: &TLSConfig{},
Config: Config{
UpstreamDNS: []string{upsAddr},
UpstreamMode: UpstreamModeLoadBalance,

View File

@@ -37,7 +37,6 @@ func TestServer_FilterDNSRewrite(t *testing.T) {
srv := createTestServer(t, &filtering.Config{
BlockingMode: filtering.BlockingModeDefault,
}, ServerConfig{
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},

View File

@@ -31,7 +31,6 @@ func TestHandleDNSRequest_handleDNSRequest(t *testing.T) {
forwardConf := ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{

View File

@@ -76,7 +76,6 @@ func TestDNSForwardHTTP_handleGetConfig(t *testing.T) {
forwardConf := ServerConfig{
UDPListenAddrs: []*net.UDPAddr{},
TCPListenAddrs: []*net.TCPAddr{},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
FallbackDNS: []string{"9.9.9.10"},
@@ -160,7 +159,6 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
forwardConf := ServerConfig{
UDPListenAddrs: []*net.UDPAddr{},
TCPListenAddrs: []*net.TCPAddr{},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
RatelimitSubnetLenIPv4: 24,
@@ -371,7 +369,6 @@ func TestServer_HandleTestUpstreamDNS(t *testing.T) {
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
UpstreamTimeout: upsTimeout,
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},

View File

@@ -246,9 +246,9 @@ func (s *Server) makeDDRResponse(req *dns.Msg) (resp *dns.Msg) {
// TODO(e.burkov): Think about storing the FQDN version of the server's
// name somewhere.
domainName := dns.Fqdn(s.conf.TLSConf.ServerName)
domainName := dns.Fqdn(s.conf.ServerName)
for _, addr := range s.conf.TLSConf.HTTPSListenAddrs {
for _, addr := range s.conf.HTTPSListenAddrs {
values := []dns.SVCBKeyValue{
&dns.SVCBAlpn{Alpn: []string{"h2"}},
&dns.SVCBPort{Port: uint16(addr.Port)},
@@ -265,7 +265,7 @@ func (s *Server) makeDDRResponse(req *dns.Msg) (resp *dns.Msg) {
resp.Answer = append(resp.Answer, ans)
}
if s.hasIPAddrs {
if s.conf.hasIPAddrs {
// Only add DNS-over-TLS resolvers in case the certificate contains IP
// addresses.
//

View File

@@ -3,7 +3,6 @@ package dnsforward
import (
"cmp"
"context"
"crypto/tls"
"net"
"net/netip"
"testing"
@@ -78,7 +77,6 @@ func TestServer_ProcessInitial(t *testing.T) {
t.Parallel()
c := ServerConfig{
TLSConf: &TLSConfig{},
Config: Config{
AAAADisabled: tc.aaaaDisabled,
UpstreamMode: UpstreamModeLoadBalance,
@@ -179,7 +177,6 @@ func TestServer_ProcessFilteringAfterResponse(t *testing.T) {
t.Parallel()
c := ServerConfig{
TLSConf: &TLSConfig{},
Config: Config{
AAAADisabled: tc.aaaaDisabled,
UpstreamMode: UpstreamModeLoadBalance,
@@ -319,8 +316,6 @@ func TestServer_ProcessDDRQuery(t *testing.T) {
}}
_, certPem, keyPem := createServerTLSConfig(t)
cert, err := tls.X509KeyPair(certPem, keyPem)
require.NoError(t, err)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@@ -333,18 +328,19 @@ func TestServer_ProcessDDRQuery(t *testing.T) {
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
ClientsContainer: EmptyClientsContainer{},
},
TLSConf: &TLSConfig{
ServerName: ddrTestDomainName,
Cert: &cert,
TLSListenAddrs: tc.addrsDoT,
HTTPSListenAddrs: tc.addrsDoH,
QUICListenAddrs: tc.addrsDoQ,
TLSConfig: TLSConfig{
ServerName: ddrTestDomainName,
CertificateChainData: certPem,
PrivateKeyData: keyPem,
TLSListenAddrs: tc.addrsDoT,
HTTPSListenAddrs: tc.addrsDoH,
QUICListenAddrs: tc.addrsDoQ,
},
ServePlainDNS: true,
})
// TODO(e.burkov): Generate a certificate actually containing the
// IP addresses.
s.hasIPAddrs = true
s.conf.hasIPAddrs = true
req := createTestMessageWithType(tc.host, tc.qtype)
@@ -661,7 +657,6 @@ func TestServer_HandleDNSRequest_restrictLocal(t *testing.T) {
}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
// TODO(s.chzhen): Add tests where EDNSClientSubnet.Enabled is true.
// Improve Config declaration for tests.
Config: Config{
@@ -794,7 +789,6 @@ func TestServer_ProcessUpstream_localPTR(t *testing.T) {
ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
@@ -824,7 +818,6 @@ func TestServer_ProcessUpstream_localPTR(t *testing.T) {
ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},

View File

@@ -16,7 +16,6 @@ func TestGenAnswerHTTPS_andSVCB(t *testing.T) {
s := createTestServer(t, &filtering.Config{
BlockingMode: filtering.BlockingModeDefault,
}, ServerConfig{
TLSConf: &TLSConfig{},
Config: Config{
UpstreamMode: UpstreamModeLoadBalance,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},

View File

@@ -28,10 +28,6 @@ type clientsContainer struct {
// filter. It must not be nil.
baseLogger *slog.Logger
// logger is used for logging the operation of the client container. It
// must not be nil.
logger *slog.Logger
// storage stores information about persistent clients.
storage *client.Storage
@@ -62,7 +58,6 @@ type clientsContainer struct {
// BlockedClientChecker checks if a client is blocked by the current access
// settings.
type BlockedClientChecker interface {
// TODO(s.chzhen): Accept [client.FindParams].
IsBlockedClient(ip netip.Addr, clientID string) (blocked bool, rule string)
}
@@ -85,7 +80,6 @@ func (clients *clientsContainer) Init(
}
clients.baseLogger = baseLogger
clients.logger = baseLogger.With(slogutil.KeyPrefix, "client_container")
clients.safeSearchCacheSize = filteringConf.SafeSearchCacheSize
clients.safeSearchCacheTTL = time.Minute * time.Duration(filteringConf.CacheTime)
@@ -275,7 +269,7 @@ func (clients *clientsContainer) forConfig() (objs []*clientObject) {
BlockedServices: cli.BlockedServices.Clone(),
IDs: cli.Identifiers(),
IDs: cli.IDs(),
Tags: slices.Clone(cli.Tags),
Upstreams: slices.Clone(cli.Upstreams),
@@ -362,27 +356,15 @@ func (clients *clientsContainer) clientOrArtificial(
}, true
}
// shouldCountClient is a wrapper around [client.Storage.Find] to make it a
// shouldCountClient is a wrapper around [clientsContainer.find] to make it a
// valid client information finder for the statistics. If no information about
// the client is found, it returns true. Values of ids must be either a valid
// ClientID or a valid IP address.
//
// TODO(s.chzhen): Accept [client.FindParams].
// the client is found, it returns true.
func (clients *clientsContainer) shouldCountClient(ids []string) (y bool) {
clients.lock.Lock()
defer clients.lock.Unlock()
params := &client.FindParams{}
for _, id := range ids {
err := params.Set(id)
if err != nil {
// Should not happen.
clients.logger.Warn("parsing find params", slogutil.KeyError, err)
continue
}
client, ok := clients.storage.Find(params)
client, ok := clients.storage.Find(id)
if ok {
return !client.IgnoreStatistics
}

View File

@@ -300,7 +300,7 @@ func clientToJSON(c *client.Persistent) (cj *clientJSON) {
return &clientJSON{
Name: c.Name,
IDs: c.Identifiers(),
IDs: c.IDs(),
Tags: c.Tags,
UseGlobalSettings: !c.UseOwnSettings,
FilteringEnabled: c.FilteringEnabled,
@@ -428,53 +428,32 @@ func (clients *clientsContainer) handleUpdateClient(w http.ResponseWriter, r *ht
// Deprecated: Remove it when migration to the new API is over.
func (clients *clientsContainer) handleFindClient(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
data := make([]map[string]*clientJSON, 0, len(q))
params := &client.FindParams{}
var err error
data := []map[string]*clientJSON{}
for i := range len(q) {
idStr := q.Get(fmt.Sprintf("ip%d", i))
if idStr == "" {
break
}
err = params.Set(idStr)
if err != nil {
clients.logger.DebugContext(
r.Context(),
"finding client",
"id", idStr,
slogutil.KeyError, err,
)
continue
}
data = append(data, map[string]*clientJSON{
idStr: clients.findClient(idStr, params),
idStr: clients.findClient(idStr),
})
}
aghhttp.WriteJSONResponseOK(w, r, data)
}
// findClient returns available information about a client by params from the
// client's storage or access settings. idStr is the string representation of
// typed params. params must not be nil. cj is guaranteed to be non-nil.
func (clients *clientsContainer) findClient(
idStr string,
params *client.FindParams,
) (cj *clientJSON) {
c, ok := clients.storage.Find(params)
// findClient returns available information about a client by idStr from the
// client's storage or access settings. cj is guaranteed to be non-nil.
func (clients *clientsContainer) findClient(idStr string) (cj *clientJSON) {
ip, _ := netip.ParseAddr(idStr)
c, ok := clients.storage.Find(idStr)
if !ok {
return clients.findRuntime(idStr, params)
return clients.findRuntime(ip, idStr)
}
cj = clientToJSON(c)
disallowed, rule := clients.clientChecker.IsBlockedClient(
params.RemoteIP,
string(params.ClientID),
)
disallowed, rule := clients.clientChecker.IsBlockedClient(ip, idStr)
cj.Disallowed, cj.DisallowedRule = &disallowed, &rule
return cj
@@ -493,8 +472,7 @@ type searchClientJSON struct {
ID string `json:"id"`
}
// handleSearchClient is the handler for the POST /control/clients/search HTTP
// API.
// handleSearchClient is the handler for the POST /control/clients/search HTTP API.
func (clients *clientsContainer) handleSearchClient(w http.ResponseWriter, r *http.Request) {
q := searchQueryJSON{}
err := json.NewDecoder(r.Body).Decode(&q)
@@ -504,25 +482,11 @@ func (clients *clientsContainer) handleSearchClient(w http.ResponseWriter, r *ht
return
}
data := make([]map[string]*clientJSON, 0, len(q.Clients))
params := &client.FindParams{}
data := []map[string]*clientJSON{}
for _, c := range q.Clients {
idStr := c.ID
err = params.Set(idStr)
if err != nil {
clients.logger.DebugContext(
r.Context(),
"searching client",
"id", idStr,
slogutil.KeyError, err,
)
continue
}
data = append(data, map[string]*clientJSON{
idStr: clients.findClient(idStr, params),
idStr: clients.findClient(idStr),
})
}
@@ -530,37 +494,38 @@ func (clients *clientsContainer) handleSearchClient(w http.ResponseWriter, r *ht
}
// findRuntime looks up the IP in runtime and temporary storages, like
// /etc/hosts tables, DHCP leases, or blocklists. params must not be nil. cj
// is guaranteed to be non-nil.
func (clients *clientsContainer) findRuntime(
idStr string,
params *client.FindParams,
) (cj *clientJSON) {
var host string
whois := &whois.Info{}
ip := params.RemoteIP
// /etc/hosts tables, DHCP leases, or blocklists. cj is guaranteed to be
// non-nil.
func (clients *clientsContainer) findRuntime(ip netip.Addr, idStr string) (cj *clientJSON) {
rc := clients.storage.ClientRuntime(ip)
if rc != nil {
_, host = rc.Info()
whois = whoisOrEmpty(rc)
if rc == nil {
// It is still possible that the IP used to be in the runtime clients
// list, but then the server was reloaded. So, check the DNS server's
// blocked IP list.
//
// See https://github.com/AdguardTeam/AdGuardHome/issues/2428.
disallowed, rule := clients.clientChecker.IsBlockedClient(ip, idStr)
cj = &clientJSON{
IDs: []string{idStr},
Disallowed: &disallowed,
DisallowedRule: &rule,
WHOIS: &whois.Info{},
}
return cj
}
// Check the DNS server's blocked IP list regardless of whether a runtime
// client was found or not. This is because it's still possible that the
// runtime client associated with the IP address was stored previously, but
// then the server was reloaded.
//
// See https://github.com/AdguardTeam/AdGuardHome/issues/2428.
disallowed, rule := clients.clientChecker.IsBlockedClient(ip, string(params.ClientID))
return &clientJSON{
Name: host,
IDs: []string{idStr},
WHOIS: whois,
Disallowed: &disallowed,
DisallowedRule: &rule,
_, host := rc.Info()
cj = &clientJSON{
Name: host,
IDs: []string{idStr},
WHOIS: whoisOrEmpty(rc),
}
disallowed, rule := clients.clientChecker.IsBlockedClient(ip, idStr)
cj.Disallowed, cj.DisallowedRule = &disallowed, &rule
return cj
}
// RegisterClientsHandlers registers HTTP handlers

View File

@@ -153,7 +153,7 @@ func TestClientsContainer_HandleAddClient(t *testing.T) {
clientTwo := newPersistentClientWithIDs(t, "client2", []string{testClientIP2})
clientEmptyID := newPersistentClient("empty_client_id")
clientEmptyID.ClientIDs = []client.ClientID{""}
clientEmptyID.ClientIDs = []string{""}
testCases := []struct {
name string
@@ -278,7 +278,7 @@ func TestClientsContainer_HandleUpdateClient(t *testing.T) {
clientModified := newPersistentClientWithIDs(t, "client2", []string{testClientIP2})
clientEmptyID := newPersistentClient("empty_client_id")
clientEmptyID.ClientIDs = []client.ClientID{""}
clientEmptyID.ClientIDs = []string{""}
testCases := []struct {
name string

View File

@@ -6,7 +6,6 @@ import (
"net/netip"
"os"
"path/filepath"
"slices"
"sync"
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
@@ -24,7 +23,6 @@ import (
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/timeutil"
"github.com/google/go-cmp/cmp"
"github.com/google/renameio/v2/maybe"
yaml "gopkg.in/yaml.v3"
)
@@ -263,128 +261,30 @@ type dnsConfig struct {
// HostsFileEnabled defines whether to use information from the system hosts
// file to resolve queries.
HostsFileEnabled bool `yaml:"hostsfile_enabled"`
// PendingRequests configures duplicate requests policy.
PendingRequests *pendingRequests `yaml:"pending_requests"`
}
// pendingRequests is a block with pending requests configuration.
type pendingRequests struct {
// Enabled controls if duplicate requests should be sent to the upstreams
// along with the original one.
Enabled bool `yaml:"enabled"`
}
// tlsConfigSettings is the TLS configuration for DNS-over-TLS, DNS-over-QUIC,
// and HTTPS. When adding new properties, update the [tlsConfigSettings.clone]
// and [tlsConfigSettings.setPrivateFieldsAndCompare] methods as necessary.
type tlsConfigSettings struct {
// Enabled indicates whether encryption (DoT/DoH/HTTPS) is enabled.
Enabled bool `yaml:"enabled" json:"enabled"`
Enabled bool `yaml:"enabled" json:"enabled"` // Enabled is the encryption (DoT/DoH/HTTPS) status
ServerName string `yaml:"server_name" json:"server_name,omitempty"` // ServerName is the hostname of your HTTPS/TLS server
ForceHTTPS bool `yaml:"force_https" json:"force_https"` // ForceHTTPS: if true, forces HTTP->HTTPS redirect
PortHTTPS uint16 `yaml:"port_https" json:"port_https,omitempty"` // HTTPS port. If 0, HTTPS will be disabled
PortDNSOverTLS uint16 `yaml:"port_dns_over_tls" json:"port_dns_over_tls,omitempty"` // DNS-over-TLS port. If 0, DoT will be disabled
PortDNSOverQUIC uint16 `yaml:"port_dns_over_quic" json:"port_dns_over_quic,omitempty"` // DNS-over-QUIC port. If 0, DoQ will be disabled
// ServerName is the hostname of the HTTPS/TLS server.
ServerName string `yaml:"server_name" json:"server_name,omitempty"`
// ForceHTTPS, if true, forces an HTTP to HTTPS redirect.
ForceHTTPS bool `yaml:"force_https" json:"force_https"`
// PortHTTPS is the HTTPS port. If 0, HTTPS will be disabled.
PortHTTPS uint16 `yaml:"port_https" json:"port_https,omitempty"`
// PortDNSOverTLS is the DNS-over-TLS port. If 0, DoT will be disabled.
PortDNSOverTLS uint16 `yaml:"port_dns_over_tls" json:"port_dns_over_tls,omitempty"`
// PortDNSOverQUIC is the DNS-over-QUIC port. If 0, DoQ will be disabled.
PortDNSOverQUIC uint16 `yaml:"port_dns_over_quic" json:"port_dns_over_quic,omitempty"`
// PortDNSCrypt is the port for DNSCrypt requests. If it's zero, DNSCrypt
// is disabled.
// PortDNSCrypt is the port for DNSCrypt requests. If it's zero,
// DNSCrypt is disabled.
PortDNSCrypt uint16 `yaml:"port_dnscrypt" json:"port_dnscrypt"`
// DNSCryptConfigFile is the path to the DNSCrypt config file. Must be set
// if PortDNSCrypt is not zero.
// DNSCryptConfigFile is the path to the DNSCrypt config file. Must be
// set if PortDNSCrypt is not zero.
//
// See https://github.com/AdguardTeam/dnsproxy and
// https://github.com/ameshkov/dnscrypt.
DNSCryptConfigFile string `yaml:"dnscrypt_config_file" json:"dnscrypt_config_file"`
// AllowUnencryptedDoH allows DoH queries via unencrypted HTTP (e.g. for
// reverse proxying).
//
// TODO(s.chzhen): Add this option into the Web UI.
// Allow DoH queries via unencrypted HTTP (e.g. for reverse proxying)
AllowUnencryptedDoH bool `yaml:"allow_unencrypted_doh" json:"allow_unencrypted_doh"`
// CertificateChain is the PEM-encoded certificate chain. Must be empty if
// [tlsConfigSettings.CertificatePath] is provided.
CertificateChain string `yaml:"certificate_chain" json:"certificate_chain"`
// PrivateKey is the PEM-encoded private key. Must be empty if
// [tlsConfigSettings.PrivateKeyPath] is provided.
PrivateKey string `yaml:"private_key" json:"private_key"`
// CertificatePath is the path to the certificate file. Must be empty if
// [tlsConfigSettings.CertificateChain] is provided.
CertificatePath string `yaml:"certificate_path" json:"certificate_path"`
// PrivateKeyPath is the path to the private key file. Must be empty if
// [tlsConfigSettings.PrivateKey] is provided.
PrivateKeyPath string `yaml:"private_key_path" json:"private_key_path"`
// OverrideTLSCiphers, when set, contains the names of the cipher suites to
// use. If the slice is empty, the default safe suites are used.
OverrideTLSCiphers []string `yaml:"override_tls_ciphers,omitempty" json:"-"`
// CertificateChainData is the PEM-encoded byte data for the certificate
// chain.
CertificateChainData []byte `yaml:"-" json:"-"`
// PrivateKeyData is the PEM-encoded byte data for the private key.
PrivateKeyData []byte `yaml:"-" json:"-"`
// StrictSNICheck controls if the connections with SNI mismatching the
// certificate's ones should be rejected.
StrictSNICheck bool `yaml:"strict_sni_check" json:"-"`
}
// clone returns a deep copy of c.
func (c *tlsConfigSettings) clone() (clone *tlsConfigSettings) {
clone = &tlsConfigSettings{}
*clone = *c
clone.OverrideTLSCiphers = slices.Clone(c.OverrideTLSCiphers)
clone.CertificateChainData = slices.Clone(c.CertificateChainData)
clone.PrivateKeyData = slices.Clone(c.PrivateKeyData)
return clone
}
// setPrivateFieldsAndCompare sets any missing properties in conf to match those
// in c and returns true if TLS configurations are equal. conf must not be be
// nil.
// It sets the following properties because these are not accepted from the
// frontend:
//
// [tlsConfigSettings.AllowUnencryptedDoH]
// [tlsConfigSettings.DNSCryptConfigFile]
// [tlsConfigSettings.OverrideTLSCiphers]
// [tlsConfigSettings.PortDNSCrypt]
//
// The following properties are skipped as they are set by
// [tlsManager.loadTLSConfig]:
//
// [tlsConfigSettings.CertificateChainData]
// [tlsConfigSettings.PrivateKeyData]
func (c *tlsConfigSettings) setPrivateFieldsAndCompare(conf *tlsConfigSettings) (equal bool) {
conf.OverrideTLSCiphers = slices.Clone(c.OverrideTLSCiphers)
// TODO(s.chzhen): Remove this once the frontend supports it.
conf.AllowUnencryptedDoH = c.AllowUnencryptedDoH
conf.DNSCryptConfigFile = c.DNSCryptConfigFile
conf.PortDNSCrypt = c.PortDNSCrypt
// TODO(a.garipov): Define a custom comparer.
return cmp.Equal(c, conf)
dnsforward.TLSConfig `yaml:",inline" json:",inline"`
}
type queryLogConfig struct {
@@ -480,9 +380,6 @@ var config = &configuration{
UsePrivateRDNS: true,
ServePlainDNS: true,
HostsFileEnabled: true,
PendingRequests: &pendingRequests{
Enabled: true,
},
},
TLS: tlsConfigSettings{
PortHTTPS: defaultPortHTTPS,
@@ -752,8 +649,9 @@ func (c *configuration) write(tlsMgr *tlsManager) (err error) {
}
if tlsMgr != nil {
tlsConf := tlsMgr.config()
config.TLS = *tlsConf
tlsConf := tlsConfigSettings{}
tlsMgr.WriteDiskConfig(&tlsConf)
config.TLS = tlsConf
}
if globalContext.stats != nil {

View File

@@ -82,7 +82,7 @@ func (web *webAPI) requestVersionInfo(
) (err error) {
updater := web.conf.updater
for range 3 {
resp.VersionInfo, err = updater.VersionInfo(ctx, recheck)
resp.VersionInfo, err = updater.VersionInfo(recheck)
if err == nil {
return nil
}
@@ -133,7 +133,7 @@ func (web *webAPI) handleUpdate(w http.ResponseWriter, r *http.Request) {
return
}
err = updater.Update(r.Context(), false)
err = updater.Update(false)
if err != nil {
aghhttp.Error(r, w, http.StatusInternalServerError, "%s", err)
@@ -164,8 +164,11 @@ func (vr *versionResponse) setAllowedToAutoUpdate(tlsMgr *tlsManager) (err error
return nil
}
tlsConf := &tlsConfigSettings{}
tlsMgr.WriteDiskConfig(tlsConf)
canUpdate := true
if tlsConfUsesPrivilegedPorts(tlsMgr.config()) ||
if tlsConfUsesPrivilegedPorts(tlsConf) ||
config.HTTPConfig.Address.Port() < 1024 ||
config.DNS.Port < 1024 {
canUpdate, err = aghnet.CanBindPrivilegedPorts()

View File

@@ -2,7 +2,6 @@ package home
import (
"context"
"crypto/tls"
"fmt"
"log/slog"
"net"
@@ -112,6 +111,9 @@ func initDNS(
return err
}
tlsConf := &tlsConfigSettings{}
tlsMgr.WriteDiskConfig(tlsConf)
return initDNSServer(
globalContext.filters,
globalContext.stats,
@@ -119,15 +121,16 @@ func initDNS(
globalContext.dhcpServer,
anonymizer,
httpRegister,
tlsConf,
tlsMgr,
baseLogger,
)
}
// initDNSServer initializes the [context.dnsServer]. To only use the internal
// proxy, none of the arguments are required, but tlsMgr and l still must not be
// nil, in other cases all the arguments also must not be nil. It also must not
// be called unless [config] and [globalContext] are initialized.
// proxy, none of the arguments are required, but tlsConf, tlsMgr and l still
// must not be nil, in other cases all the arguments also must not be nil. It
// also must not be called unless [config] and [globalContext] are initialized.
//
// TODO(e.burkov): Use [dnsforward.DNSCreateParams] as a parameter.
func initDNSServer(
@@ -137,6 +140,7 @@ func initDNSServer(
dhcpSrv dnsforward.DHCP,
anonymizer *aghnet.IPMut,
httpReg aghhttp.RegisterFunc,
tlsConf *tlsConfigSettings,
tlsMgr *tlsManager,
l *slog.Logger,
) (err error) {
@@ -165,7 +169,7 @@ func initDNSServer(
dnsConf, err := newServerConfig(
&config.DNS,
config.Clients.Sources,
tlsMgr.config(),
tlsConf,
tlsMgr,
httpReg,
globalContext.clients.storage,
@@ -251,16 +255,11 @@ func newServerConfig(
fwdConf := dnsConf.Config
fwdConf.ClientsContainer = clientsContainer
intTLSConf, err := newDNSTLSConfig(tlsConf, hosts)
if err != nil {
return nil, fmt.Errorf("constructing tls config: %w", err)
}
newConf = &dnsforward.ServerConfig{
UDPListenAddrs: ipsToUDPAddrs(hosts, dnsConf.Port),
TCPListenAddrs: ipsToTCPAddrs(hosts, dnsConf.Port),
Config: fwdConf,
TLSConf: intTLSConf,
TLSConfig: newDNSTLSConfig(tlsConf, hosts),
TLSAllowUnencryptedDoH: tlsConf.AllowUnencryptedDoH,
UpstreamTimeout: time.Duration(dnsConf.UpstreamTimeout),
TLSv12Roots: tlsMgr.rootCerts,
@@ -273,7 +272,6 @@ func newServerConfig(
ServeHTTP3: dnsConf.ServeHTTP3,
UseHTTP3Upstreams: dnsConf.UseHTTP3Upstreams,
ServePlainDNS: dnsConf.ServePlainDNS,
PendingRequestsEnabled: dnsConf.PendingRequests.Enabled,
}
var initialAddresses []netip.Addr
@@ -306,19 +304,14 @@ func newServerConfig(
}
// newDNSTLSConfig converts values from the configuration file into the internal
// TLS settings for the DNS server. conf must not be nil.
func newDNSTLSConfig(
conf *tlsConfigSettings,
addrs []netip.Addr,
) (dnsConf *dnsforward.TLSConfig, err error) {
// TLS settings for the DNS server. tlsConf must not be nil.
func newDNSTLSConfig(conf *tlsConfigSettings, addrs []netip.Addr) (dnsConf dnsforward.TLSConfig) {
if !conf.Enabled {
return &dnsforward.TLSConfig{}, nil
return dnsforward.TLSConfig{}
}
dnsConf = &dnsforward.TLSConfig{
ServerName: conf.ServerName,
StrictSNICheck: conf.StrictSNICheck,
}
dnsConf = conf.TLSConfig
dnsConf.ServerName = conf.ServerName
if conf.PortHTTPS != 0 {
dnsConf.HTTPSListenAddrs = ipsToTCPAddrs(addrs, conf.PortHTTPS)
@@ -332,22 +325,7 @@ func newDNSTLSConfig(
dnsConf.QUICListenAddrs = ipsToUDPAddrs(addrs, conf.PortDNSOverQUIC)
}
cert, err := tls.X509KeyPair(conf.CertificateChainData, conf.PrivateKeyData)
if err != nil {
const format = "parsing tls key pair: %w"
if conf.AllowUnencryptedDoH {
// TODO(s.chzhen): Use [slog.Logger].
log.Info("warning: %s: %s", format, err)
return dnsConf, nil
}
return nil, fmt.Errorf(format, err)
}
dnsConf.Cert = &cert
return dnsConf, nil
return dnsConf
}
// newDNSCryptConfig converts values from the configuration file into the
@@ -400,7 +378,8 @@ type dnsEncryption struct {
// getDNSEncryption returns the TLS encryption addresses that AdGuard Home
// listens on. tlsMgr must not be nil.
func getDNSEncryption(tlsMgr *tlsManager) (de dnsEncryption) {
tlsConf := tlsMgr.config()
tlsConf := tlsConfigSettings{}
tlsMgr.WriteDiskConfig(&tlsConf)
if !tlsConf.Enabled || len(tlsConf.ServerName) == 0 {
return dnsEncryption{}

View File

@@ -487,14 +487,9 @@ func checkPorts() (err error) {
}
// isUpdateEnabled returns true if the update is enabled for current
// configuration. It also logs the decision. isCustomURL should be true if the
// configuration. It also logs the decision. customURL should be true if the
// updater is using a custom URL.
func isUpdateEnabled(
ctx context.Context,
l *slog.Logger,
opts *options,
isCustomURL bool,
) (ok bool) {
func isUpdateEnabled(ctx context.Context, l *slog.Logger, opts *options, customURL bool) (ok bool) {
if opts.disableUpdate {
l.DebugContext(ctx, "updates are disabled by command-line option")
@@ -505,13 +500,13 @@ func isUpdateEnabled(
case
version.ChannelDevelopment,
version.ChannelCandidate:
if isCustomURL {
if customURL {
l.DebugContext(ctx, "updates are enabled because custom url is used")
} else {
l.DebugContext(ctx, "updates are disabled for development and candidate builds")
}
return isCustomURL
return customURL
default:
l.DebugContext(ctx, "updates are enabled")
@@ -519,7 +514,7 @@ func isUpdateEnabled(
}
}
// initWeb initializes the web module. upd, baseLogger, and tlsMgr must not be
// initWeb initializes the web module. upd, baseLogger, and tlsMgr must not be
// nil.
func initWeb(
ctx context.Context,
@@ -528,7 +523,7 @@ func initWeb(
upd *updater.Updater,
baseLogger *slog.Logger,
tlsMgr *tlsManager,
isCustomUpdURL bool,
customURL bool,
) (web *webAPI, err error) {
logger := baseLogger.With(slogutil.KeyPrefix, "webapi")
@@ -544,7 +539,7 @@ func initWeb(
}
}
disableUpdate := !isUpdateEnabled(ctx, baseLogger, &opts, isCustomUpdURL)
disableUpdate := !isUpdateEnabled(ctx, baseLogger, &opts, customURL)
webConf := &webConfig{
updater: upd,
@@ -650,12 +645,11 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}, sigHdlr *signalH
confPath := configFilePath()
updLogger := slogLogger.With(slogutil.KeyPrefix, "updater")
upd, isCustomURL := newUpdater(ctx, updLogger, config, globalContext.workDir, confPath, execPath)
upd, customURL := newUpdater(ctx, slogLogger, globalContext.workDir, confPath, execPath, config)
// TODO(e.burkov): This could be made earlier, probably as the option's
// effect.
cmdlineUpdate(ctx, updLogger, opts, upd, tlsMgr)
cmdlineUpdate(ctx, slogLogger, opts, upd, tlsMgr)
if !globalContext.firstRun {
// Save the updated config.
@@ -677,7 +671,7 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}, sigHdlr *signalH
globalContext.auth, err = initUsers()
fatalOnError(err)
web, err := initWeb(ctx, opts, clientBuildFS, upd, slogLogger, tlsMgr, isCustomURL)
web, err := initWeb(ctx, opts, clientBuildFS, upd, slogLogger, tlsMgr, customURL)
fatalOnError(err)
globalContext.web = web
@@ -720,17 +714,16 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}, sigHdlr *signalH
<-done
}
// newUpdater creates a new AdGuard Home updater. l and conf must not be nil.
// workDir, confPath, and execPath must not be empty. isCustomURL is true if
// the user has specified a custom version announcement URL.
// newUpdater creates a new AdGuard Home updater. customURL is true if the user
// has specified a custom version announcement URL.
func newUpdater(
ctx context.Context,
l *slog.Logger,
conf *configuration,
workDir string,
confPath string,
execPath string,
) (upd *updater.Updater, isCustomURL bool) {
config *configuration,
) (upd *updater.Updater, customURL bool) {
// envName is the name of the environment variable that can be used to
// override the default version check URL.
const envName = "ADGUARD_HOME_TEST_UPDATE_VERSION_URL"
@@ -742,14 +735,14 @@ func newUpdater(
case version.Channel() == version.ChannelRelease:
// Only enable custom version URL for development builds.
l.DebugContext(ctx, "custom version url is disabled for release builds")
case !conf.UnsafeUseCustomUpdateIndexURL:
case !config.UnsafeUseCustomUpdateIndexURL:
l.DebugContext(ctx, "custom version url is disabled in config")
default:
versionURL, _ = url.Parse(customURLStr)
}
err := urlutil.ValidateHTTPURL(versionURL)
if isCustomURL = err == nil; !isCustomURL {
if customURL = err == nil; !customURL {
l.DebugContext(ctx, "parsing custom version url", slogutil.KeyError, err)
versionURL = updater.DefaultVersionURL()
@@ -758,8 +751,7 @@ func newUpdater(
l.DebugContext(ctx, "creating updater", "config_path", confPath)
return updater.NewUpdater(&updater.Config{
Client: conf.Filtering.HTTPClient,
Logger: l,
Client: config.Filtering.HTTPClient,
Version: version.Version(),
Channel: version.Channel(),
GOARCH: runtime.GOARCH,
@@ -770,7 +762,7 @@ func newUpdater(
ConfName: confPath,
ExecPath: execPath,
VersionCheckURL: versionURL,
}), isCustomURL
}), customURL
}
// checkPermissions checks and migrates permissions of the files and directories
@@ -999,9 +991,9 @@ func printWebAddrs(proto, addr string, port uint16) {
//
// TODO(s.chzhen): Implement separate functions for HTTP and HTTPS.
func printHTTPAddresses(proto string, tlsMgr *tlsManager) {
var tlsConf *tlsConfigSettings
tlsConf := tlsConfigSettings{}
if tlsMgr != nil {
tlsConf = tlsMgr.config()
tlsMgr.WriteDiskConfig(&tlsConf)
}
port := config.HTTPConfig.Address.Port()
@@ -1086,12 +1078,12 @@ func cmdlineUpdate(
//
// TODO(e.burkov): We could probably initialize the internal resolver
// separately.
err := initDNSServer(nil, nil, nil, nil, nil, nil, tlsMgr, l)
err := initDNSServer(nil, nil, nil, nil, nil, nil, &tlsConfigSettings{}, tlsMgr, l)
fatalOnError(err)
l.InfoContext(ctx, "performing update via cli")
info, err := upd.VersionInfo(ctx, true)
info, err := upd.VersionInfo(true)
if err != nil {
l.ErrorContext(ctx, "getting version info", slogutil.KeyError, err)
@@ -1104,7 +1096,7 @@ func cmdlineUpdate(
os.Exit(osutil.ExitCodeSuccess)
}
err = upd.Update(ctx, globalContext.firstRun)
err = upd.Update(globalContext.firstRun)
fatalOnError(err)
err = restartService()

View File

@@ -8,7 +8,7 @@ import (
"net/url"
"path"
"github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/log"
@@ -151,7 +151,7 @@ func handleMobileConfig(w http.ResponseWriter, r *http.Request, dnsp string) {
clientID := q.Get("client_id")
if clientID != "" {
err = client.ValidateClientID(clientID)
err = dnsforward.ValidateClientID(clientID)
if err != nil {
respondJSONError(w, http.StatusBadRequest, err.Error())

View File

@@ -24,9 +24,11 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghtls"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/c2h5oh/datasize"
"github.com/google/go-cmp/cmp"
)
// tlsManager contains the current configuration and state of AdGuard Home TLS
@@ -35,9 +37,6 @@ type tlsManager struct {
// logger is used for logging the operation of the TLS Manager.
logger *slog.Logger
// mu protects status, certLastMod, conf, and servePlainDNS.
mu *sync.Mutex
// status is the current status of the configuration. It is never nil.
status *tlsConfigStatus
@@ -53,9 +52,6 @@ type tlsManager struct {
// Resolve it.
web *webAPI
// conf contains the TLS configuration settings. It must not be nil.
conf *tlsConfigSettings
// configModified is called when the TLS configuration is changed via an
// HTTP request.
configModified func()
@@ -63,6 +59,9 @@ type tlsManager struct {
// customCipherIDs are the ID of the cipher suites that AdGuard Home must use.
customCipherIDs []uint16
confLock sync.Mutex
conf tlsConfigSettings
// servePlainDNS defines if plain DNS is allowed for incoming requests.
servePlainDNS bool
}
@@ -92,10 +91,9 @@ type tlsManagerConfig struct {
func newTLSManager(ctx context.Context, conf *tlsManagerConfig) (m *tlsManager, err error) {
m = &tlsManager{
logger: conf.logger,
mu: &sync.Mutex{},
configModified: conf.configModified,
status: &tlsConfigStatus{},
conf: &conf.tlsSettings,
conf: conf.tlsSettings,
servePlainDNS: conf.servePlainDNS,
}
@@ -114,22 +112,17 @@ func newTLSManager(ctx context.Context, conf *tlsManagerConfig) (m *tlsManager,
m.logger.InfoContext(ctx, "using default ciphers")
}
m.mu.Lock()
defer m.mu.Unlock()
if m.conf.Enabled {
err = m.load(ctx)
if err != nil {
m.conf.Enabled = false
if !m.conf.Enabled {
return m, nil
return m, err
}
m.setCertFileTime(ctx)
}
err = m.load(ctx)
if err != nil {
m.conf.Enabled = false
return m, err
}
m.setCertFileTime(ctx)
return m, nil
}
@@ -143,9 +136,8 @@ func (m *tlsManager) setWebAPI(webAPI *webAPI) {
}
// load reloads the TLS configuration from files or data from the config file.
// m.mu is expected to be locked.
func (m *tlsManager) load(ctx context.Context) (err error) {
err = m.loadTLSConfig(ctx, m.conf, m.status)
err = m.loadTLSConf(ctx, &m.conf, m.status)
if err != nil {
return fmt.Errorf("loading config: %w", err)
}
@@ -153,16 +145,15 @@ func (m *tlsManager) load(ctx context.Context) (err error) {
return nil
}
// config returns a deep copy of the stored TLS configuration.
func (m *tlsManager) config() (conf *tlsConfigSettings) {
m.mu.Lock()
defer m.mu.Unlock()
return m.conf.clone()
// WriteDiskConfig - write config
func (m *tlsManager) WriteDiskConfig(conf *tlsConfigSettings) {
m.confLock.Lock()
*conf = m.conf
m.confLock.Unlock()
}
// setCertFileTime sets [tlsManager.certLastMod] from the certificate. If there
// are errors, setCertFileTime logs them. m.mu is expected to be locked.
// are errors, setCertFileTime logs them.
func (m *tlsManager) setCertFileTime(ctx context.Context) {
if len(m.conf.CertificatePath) == 0 {
return
@@ -184,24 +175,21 @@ func (m *tlsManager) setCertFileTime(ctx context.Context) {
func (m *tlsManager) start(_ context.Context) {
m.registerWebHandlers()
m.mu.Lock()
defer m.mu.Unlock()
m.confLock.Lock()
tlsConf := m.conf
m.confLock.Unlock()
// The background context is used because the TLSConfigChanged wraps context
// with timeout on its own and shuts down the server, which handles current
// request.
m.web.tlsConfigChanged(context.Background(), m.conf)
m.web.tlsConfigChanged(context.Background(), tlsConf)
}
// reload updates the configuration and restarts the TLS manager. It logs any
// encountered errors.
//
// TODO(s.chzhen): Consider returning an error.
// reload updates the configuration and restarts the TLS manager.
func (m *tlsManager) reload(ctx context.Context) {
m.mu.Lock()
defer m.mu.Unlock()
m.confLock.Lock()
tlsConf := m.conf
m.confLock.Unlock()
if !tlsConf.Enabled || len(tlsConf.CertificatePath) == 0 {
return
@@ -223,7 +211,9 @@ func (m *tlsManager) reload(ctx context.Context) {
m.logger.InfoContext(ctx, "certificate file is modified")
m.confLock.Lock()
err = m.load(ctx)
m.confLock.Unlock()
if err != nil {
m.logger.ErrorContext(ctx, "reloading", slogutil.KeyError, err)
@@ -237,6 +227,10 @@ func (m *tlsManager) reload(ctx context.Context) {
m.logger.ErrorContext(ctx, "reconfiguring dns server", slogutil.KeyError, err)
}
m.confLock.Lock()
tlsConf = m.conf
m.confLock.Unlock()
// The background context is used because the TLSConfigChanged wraps context
// with timeout on its own and shuts down the server, which handles current
// request.
@@ -244,12 +238,15 @@ func (m *tlsManager) reload(ctx context.Context) {
}
// reconfigureDNSServer updates the DNS server configuration using the stored
// TLS settings. m.mu is expected to be locked.
// TLS settings.
func (m *tlsManager) reconfigureDNSServer() (err error) {
tlsConf := &tlsConfigSettings{}
m.WriteDiskConfig(tlsConf)
newConf, err := newServerConfig(
&config.DNS,
config.Clients.Sources,
m.conf,
tlsConf,
m,
httpRegister,
globalContext.clients.storage,
@@ -266,11 +263,9 @@ func (m *tlsManager) reconfigureDNSServer() (err error) {
return nil
}
// loadTLSConfig loads and validates the TLS configuration. It also sets
// [tlsConfigSettings.CertificateChainData] and
// [tlsConfigSettings.PrivateKeyData] properties. The returned error is also
// set in status.WarningValidation.
func (m *tlsManager) loadTLSConfig(
// loadTLSConf loads and validates the TLS configuration. The returned error is
// also set in status.WarningValidation.
func (m *tlsManager) loadTLSConf(
ctx context.Context,
tlsConf *tlsConfigSettings,
status *tlsConfigStatus,
@@ -362,10 +357,10 @@ type tlsConfigStatus struct {
KeyType string `json:"key_type,omitempty"`
// NotBefore is the NotBefore field of the first certificate in the chain.
NotBefore time.Time `json:"not_before"`
NotBefore time.Time `json:"not_before,omitempty"`
// NotAfter is the NotAfter field of the first certificate in the chain.
NotAfter time.Time `json:"not_after"`
NotAfter time.Time `json:"not_after,omitempty"`
// WarningValidation is a validation warning message with the issue
// description.
@@ -415,23 +410,15 @@ type tlsConfigSettingsExt struct {
// handleTLSStatus is the handler for the GET /control/tls/status HTTP API.
func (m *tlsManager) handleTLSStatus(w http.ResponseWriter, r *http.Request) {
var tlsConf *tlsConfigSettings
var servePlainDNS bool
func() {
m.mu.Lock()
defer m.mu.Unlock()
tlsConf = m.conf.clone()
servePlainDNS = m.servePlainDNS
}()
m.confLock.Lock()
data := tlsConfig{
tlsConfigSettingsExt: tlsConfigSettingsExt{
tlsConfigSettings: *tlsConf,
ServePlainDNS: aghalg.BoolToNullBool(servePlainDNS),
tlsConfigSettings: m.conf,
ServePlainDNS: aghalg.BoolToNullBool(m.servePlainDNS),
},
tlsConfigStatus: m.status,
}
m.confLock.Unlock()
marshalTLS(w, r, data)
}
@@ -447,9 +434,6 @@ func (m *tlsManager) handleTLSValidate(w http.ResponseWriter, r *http.Request) {
return
}
m.mu.Lock()
defer m.mu.Unlock()
if setts.PrivateKeySaved {
setts.PrivateKey = m.conf.PrivateKey
}
@@ -465,7 +449,7 @@ func (m *tlsManager) handleTLSValidate(w http.ResponseWriter, r *http.Request) {
// Skip the error check, since we are only interested in the value of
// status.WarningValidation.
status := &tlsConfigStatus{}
_ = m.loadTLSConfig(ctx, &setts.tlsConfigSettings, status)
_ = m.loadTLSConf(ctx, &setts.tlsConfigSettings, status)
resp := tlsConfig{
tlsConfigSettingsExt: setts,
tlsConfigStatus: status,
@@ -474,23 +458,42 @@ func (m *tlsManager) handleTLSValidate(w http.ResponseWriter, r *http.Request) {
marshalTLS(w, r, resp)
}
// setConfig updates manager TLS configuration with the given one. m.mu is
// expected to be locked.
// setConfig updates manager conf with the given one.
func (m *tlsManager) setConfig(
ctx context.Context,
newConf tlsConfigSettings,
status *tlsConfigStatus,
servePlain aghalg.NullBool,
) (restartHTTPS bool) {
if !m.conf.setPrivateFieldsAndCompare(&newConf) {
m.confLock.Lock()
defer m.confLock.Unlock()
// Reset the DNSCrypt data before comparing, since we currently do not
// accept these from the frontend.
//
// TODO(a.garipov): Define a custom comparer for dnsforward.TLSConfig.
newConf.DNSCryptConfigFile = m.conf.DNSCryptConfigFile
newConf.PortDNSCrypt = m.conf.PortDNSCrypt
if !cmp.Equal(m.conf, newConf, cmp.AllowUnexported(dnsforward.TLSConfig{})) {
m.logger.InfoContext(ctx, "config has changed, restarting https server")
restartHTTPS = true
} else {
m.logger.InfoContext(ctx, "config has not changed")
}
m.conf = &newConf
// Note: don't do just `t.conf = data` because we must preserve all other members of t.conf
m.conf.Enabled = newConf.Enabled
m.conf.ServerName = newConf.ServerName
m.conf.ForceHTTPS = newConf.ForceHTTPS
m.conf.PortHTTPS = newConf.PortHTTPS
m.conf.PortDNSOverTLS = newConf.PortDNSOverTLS
m.conf.PortDNSOverQUIC = newConf.PortDNSOverQUIC
m.conf.CertificateChain = newConf.CertificateChain
m.conf.CertificatePath = newConf.CertificatePath
m.conf.CertificateChainData = newConf.CertificateChainData
m.conf.PrivateKey = newConf.PrivateKey
m.conf.PrivateKeyPath = newConf.PrivateKeyPath
m.conf.PrivateKeyData = newConf.PrivateKeyData
m.status = status
if servePlain != aghalg.NBNull {
@@ -512,16 +515,6 @@ func (m *tlsManager) handleTLSConfigure(w http.ResponseWriter, r *http.Request)
return
}
var restartHTTPS bool
defer func() {
if restartHTTPS {
m.configModified()
}
}()
m.mu.Lock()
defer m.mu.Unlock()
if req.PrivateKeySaved {
req.PrivateKey = m.conf.PrivateKey
}
@@ -533,7 +526,7 @@ func (m *tlsManager) handleTLSConfigure(w http.ResponseWriter, r *http.Request)
}
status := &tlsConfigStatus{}
err = m.loadTLSConfig(ctx, &req.tlsConfigSettings, status)
err = m.loadTLSConf(ctx, &req.tlsConfigSettings, status)
if err != nil {
resp := tlsConfig{
tlsConfigSettingsExt: req,
@@ -545,18 +538,20 @@ func (m *tlsManager) handleTLSConfigure(w http.ResponseWriter, r *http.Request)
return
}
restartHTTPS = m.setConfig(ctx, req.tlsConfigSettings, status, req.ServePlainDNS)
restartHTTPS := m.setConfig(ctx, req.tlsConfigSettings, status, req.ServePlainDNS)
m.setCertFileTime(ctx)
if req.ServePlainDNS != aghalg.NBNull {
func() {
config.Lock()
defer config.Unlock()
m.confLock.Lock()
defer m.confLock.Unlock()
config.DNS.ServePlainDNS = req.ServePlainDNS == aghalg.NBTrue
}()
}
m.configModified()
err = m.reconfigureDNSServer()
if err != nil {
m.logger.ErrorContext(ctx, "reconfiguring dns server", slogutil.KeyError, err)
@@ -572,18 +567,18 @@ func (m *tlsManager) handleTLSConfigure(w http.ResponseWriter, r *http.Request)
}
marshalTLS(w, r, resp)
rc := http.NewResponseController(w)
err = rc.Flush()
if err != nil {
m.logger.ErrorContext(ctx, "flushing response", slogutil.KeyError, err)
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
// The background context is used because the TLSConfigChanged wraps context
// with timeout on its own and shuts down the server, which handles current
// request. It is also should be done in a separate goroutine due to the
// request. It is also should be done in a separate goroutine due to the
// same reason.
if restartHTTPS {
go m.web.tlsConfigChanged(context.Background(), &req.tlsConfigSettings)
go func() {
m.web.tlsConfigChanged(context.Background(), req.tlsConfigSettings)
}()
}
}

View File

@@ -204,8 +204,6 @@ func assertCertSerialNumber(tb testing.TB, conf *tlsConfigSettings, wantSN int64
func TestTLSManager_Reload(t *testing.T) {
storeGlobals(t)
config.DNS.Port = 0
var (
logger = slogutil.NewDiscardLogger()
ctx = testutil.ContextWithTimeout(t, testTimeout)
@@ -241,9 +239,11 @@ func TestTLSManager_Reload(t *testing.T) {
logger: logger,
configModified: func() {},
tlsSettings: tlsConfigSettings{
Enabled: true,
CertificatePath: certPath,
PrivateKeyPath: keyPath,
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificatePath: certPath,
PrivateKeyPath: keyPath,
},
},
servePlainDNS: false,
})
@@ -254,7 +254,8 @@ func TestTLSManager_Reload(t *testing.T) {
m.setWebAPI(web)
conf := m.config()
conf := &tlsConfigSettings{}
m.WriteDiskConfig(conf)
assertCertSerialNumber(t, conf, snBefore)
certDER, key = newCertAndKey(t, snAfter)
@@ -262,11 +263,7 @@ func TestTLSManager_Reload(t *testing.T) {
m.reload(ctx)
// The [tlsManager.reload] method will start the DNS server and it should be
// stopped after the test ends.
testutil.CleanupAndRequireSuccess(t, globalContext.dnsServer.Stop)
conf = m.config()
m.WriteDiskConfig(conf)
assertCertSerialNumber(t, conf, snAfter)
}
@@ -281,9 +278,11 @@ func TestTLSManager_HandleTLSStatus(t *testing.T) {
logger: logger,
configModified: func() {},
tlsSettings: tlsConfigSettings{
Enabled: true,
CertificateChain: string(testCertChainData),
PrivateKey: string(testPrivateKeyData),
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificateChain: string(testCertChainData),
PrivateKey: string(testPrivateKeyData),
},
},
servePlainDNS: false,
})
@@ -343,49 +342,47 @@ func TestValidateTLSSettings(t *testing.T) {
busyUDPPort := udpAddr.Port
testCases := []struct {
setts tlsConfigSettingsExt
name string
wantErr string
setts tlsConfigSettingsExt
}{{
name: "basic",
wantErr: "",
setts: tlsConfigSettingsExt{},
wantErr: "",
}, {
name: "disabled_all",
wantErr: "plain DNS is required in case encryption protocols are disabled",
setts: tlsConfigSettingsExt{
ServePlainDNS: aghalg.NBFalse,
},
name: "disabled_all",
wantErr: "plain DNS is required in case encryption protocols are disabled",
}, {
name: "busy_https_port",
wantErr: fmt.Sprintf("port %d for HTTPS is not available", busyTCPPort),
setts: tlsConfigSettingsExt{
tlsConfigSettings: tlsConfigSettings{
Enabled: true,
PortHTTPS: uint16(busyTCPPort),
},
},
name: "busy_https_port",
wantErr: fmt.Sprintf("port %d for HTTPS is not available", busyTCPPort),
}, {
name: "busy_dot_port",
wantErr: fmt.Sprintf("port %d for DNS-over-TLS is not available", busyTCPPort),
setts: tlsConfigSettingsExt{
tlsConfigSettings: tlsConfigSettings{
Enabled: true,
PortDNSOverTLS: uint16(busyTCPPort),
},
},
name: "busy_dot_port",
wantErr: fmt.Sprintf("port %d for DNS-over-TLS is not available", busyTCPPort),
}, {
name: "busy_doq_port",
wantErr: fmt.Sprintf("port %d for DNS-over-QUIC is not available", busyUDPPort),
setts: tlsConfigSettingsExt{
tlsConfigSettings: tlsConfigSettings{
Enabled: true,
PortDNSOverQUIC: uint16(busyUDPPort),
},
},
name: "busy_doq_port",
wantErr: fmt.Sprintf("port %d for DNS-over-QUIC is not available", busyUDPPort),
}, {
name: "duplicate_port",
wantErr: "validating tcp ports: duplicated values: [4433]",
setts: tlsConfigSettingsExt{
tlsConfigSettings: tlsConfigSettings{
Enabled: true,
@@ -393,6 +390,8 @@ func TestValidateTLSSettings(t *testing.T) {
PortDNSOverTLS: 4433,
},
},
name: "duplicate_port",
wantErr: "validating tcp ports: duplicated values: [4433]",
}}
for _, tc := range testCases {
@@ -418,9 +417,11 @@ func TestTLSManager_HandleTLSValidate(t *testing.T) {
logger: logger,
configModified: func() {},
tlsSettings: tlsConfigSettings{
Enabled: true,
CertificateChain: string(testCertChainData),
PrivateKey: string(testPrivateKeyData),
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificateChain: string(testCertChainData),
PrivateKey: string(testPrivateKeyData),
},
},
servePlainDNS: false,
})
@@ -433,9 +434,11 @@ func TestTLSManager_HandleTLSValidate(t *testing.T) {
setts := &tlsConfigSettingsExt{
tlsConfigSettings: tlsConfigSettings{
Enabled: true,
CertificateChain: base64.StdEncoding.EncodeToString(testCertChainData),
PrivateKey: base64.StdEncoding.EncodeToString(testPrivateKeyData),
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificateChain: base64.StdEncoding.EncodeToString(testCertChainData),
PrivateKey: base64.StdEncoding.EncodeToString(testPrivateKeyData),
},
},
}
@@ -473,7 +476,6 @@ func TestTLSManager_HandleTLSConfigure(t *testing.T) {
require.NoError(t, err)
err = globalContext.dnsServer.Prepare(&dnsforward.ServerConfig{
TLSConf: &dnsforward.TLSConfig{},
Config: dnsforward.Config{
UpstreamMode: dnsforward.UpstreamModeLoadBalance,
EDNSClientSubnet: &dnsforward.EDNSClientSubnet{Enabled: false},
@@ -509,9 +511,11 @@ func TestTLSManager_HandleTLSConfigure(t *testing.T) {
logger: logger,
configModified: func() {},
tlsSettings: tlsConfigSettings{
Enabled: true,
CertificatePath: certPath,
PrivateKeyPath: keyPath,
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificatePath: certPath,
PrivateKeyPath: keyPath,
},
},
servePlainDNS: true,
})
@@ -522,16 +526,19 @@ func TestTLSManager_HandleTLSConfigure(t *testing.T) {
m.setWebAPI(web)
conf := m.config()
conf := &tlsConfigSettings{}
m.WriteDiskConfig(conf)
assertCertSerialNumber(t, conf, wantSerialNumber)
// Prepare a request with the new TLS configuration.
setts := &tlsConfigSettingsExt{
tlsConfigSettings: tlsConfigSettings{
Enabled: true,
PortHTTPS: 4433,
CertificateChain: base64.StdEncoding.EncodeToString(testCertChainData),
PrivateKey: base64.StdEncoding.EncodeToString(testPrivateKeyData),
Enabled: true,
PortHTTPS: 4433,
TLSConfig: dnsforward.TLSConfig{
CertificateChain: base64.StdEncoding.EncodeToString(testCertChainData),
PrivateKey: base64.StdEncoding.EncodeToString(testPrivateKeyData),
},
},
}

View File

@@ -157,8 +157,8 @@ func newWebAPI(ctx context.Context, conf *webConfig) (w *webAPI) {
}
// tlsConfigChanged updates the TLS configuration and restarts the HTTPS server
// if necessary. tlsConf must not be nil.
func (web *webAPI) tlsConfigChanged(ctx context.Context, tlsConf *tlsConfigSettings) {
// if necessary.
func (web *webAPI) tlsConfigChanged(ctx context.Context, tlsConf tlsConfigSettings) {
defer slogutil.RecoverAndExit(ctx, web.logger, osutil.ExitCodeFailure)
web.logger.DebugContext(ctx, "applying new tls configuration")

View File

@@ -64,7 +64,7 @@ type Entry struct {
Domain string
// UpstreamStats contains the DNS query statistics for both the upstream and
// fallback DNS servers. Don't modify items in the slice.
// fallback DNS servers.
UpstreamStats []*proxy.UpstreamStatistics
// Result is the result of processing the request.

View File

@@ -1,7 +1,6 @@
package updater
import (
"context"
"encoding/json"
"fmt"
"io"
@@ -13,6 +12,7 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/ioutil"
"github.com/AdguardTeam/golibs/log"
"github.com/c2h5oh/datasize"
)
@@ -35,7 +35,7 @@ const maxVersionRespSize datasize.ByteSize = 64 * datasize.KB
// VersionInfo downloads the latest version information. If forceRecheck is
// false and there are cached results, those results are returned.
func (u *Updater) VersionInfo(ctx context.Context, forceRecheck bool) (vi VersionInfo, err error) {
func (u *Updater) VersionInfo(forceRecheck bool) (vi VersionInfo, err error) {
u.mu.Lock()
defer u.mu.Unlock()
@@ -45,17 +45,11 @@ func (u *Updater) VersionInfo(ctx context.Context, forceRecheck bool) (vi Versio
return u.prevCheckResult, u.prevCheckError
}
var resp *http.Response
vcu := u.versionCheckURL
req, err := http.NewRequestWithContext(ctx, http.MethodGet, vcu, nil)
resp, err = u.client.Get(vcu)
if err != nil {
return VersionInfo{}, fmt.Errorf("constructing request to %s: %w", vcu, err)
}
u.logger.DebugContext(ctx, "requesting version data", "url", vcu)
resp, err := u.client.Do(req)
if err != nil {
return VersionInfo{}, fmt.Errorf("requesting %s: %w", vcu, err)
return VersionInfo{}, fmt.Errorf("updater: HTTP GET %s: %w", vcu, err)
}
defer func() { err = errors.WithDeferred(err, resp.Body.Close()) }()
@@ -65,16 +59,16 @@ func (u *Updater) VersionInfo(ctx context.Context, forceRecheck bool) (vi Versio
// ReadCloser.
body, err := io.ReadAll(r)
if err != nil {
return VersionInfo{}, fmt.Errorf("reading response from %s: %w", vcu, err)
return VersionInfo{}, fmt.Errorf("updater: HTTP GET %s: %w", vcu, err)
}
u.prevCheckTime = now
u.prevCheckResult, u.prevCheckError = u.parseVersionResponse(ctx, body)
u.prevCheckResult, u.prevCheckError = u.parseVersionResponse(body)
return u.prevCheckResult, u.prevCheckError
}
func (u *Updater) parseVersionResponse(ctx context.Context, data []byte) (VersionInfo, error) {
func (u *Updater) parseVersionResponse(data []byte) (VersionInfo, error) {
info := VersionInfo{
CanAutoUpdate: aghalg.NBFalse,
}
@@ -98,7 +92,7 @@ func (u *Updater) parseVersionResponse(ctx context.Context, data []byte) (Versio
info.Announcement = versionJSON["announcement"]
info.AnnouncementURL = versionJSON["announcement_url"]
packageURL, key, found := u.downloadURL(ctx, versionJSON)
packageURL, key, found := u.downloadURL(versionJSON)
if !found {
return info, fmt.Errorf("version.json: no package URL: key %q not found in object", key)
}
@@ -114,10 +108,7 @@ func (u *Updater) parseVersionResponse(ctx context.Context, data []byte) (Versio
// downloadURL returns the download URL for current build as well as its key in
// versionObj. If the key is not found, it additionally prints an informative
// log message.
func (u *Updater) downloadURL(
ctx context.Context,
versionObj map[string]string,
) (dlURL, key string, ok bool) {
func (u *Updater) downloadURL(versionObj map[string]string) (dlURL, key string, ok bool) {
if u.goarch == "arm" && u.goarm != "" {
key = fmt.Sprintf("download_%s_%sv%s", u.goos, u.goarch, u.goarm)
} else if isMIPS(u.goarch) && u.gomips != "" {
@@ -133,7 +124,7 @@ func (u *Updater) downloadURL(
keys := slices.Sorted(maps.Keys(versionObj))
u.logger.ErrorContext(ctx, "key not found", "missing", key, "got", keys)
log.Error("updater: key %q not found; got keys %q", key, keys)
return "", key, false
}

View File

@@ -10,7 +10,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
"github.com/AdguardTeam/AdGuardHome/internal/updater"
"github.com/AdguardTeam/AdGuardHome/internal/version"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -59,7 +58,6 @@ func TestUpdater_VersionInfo(t *testing.T) {
u := updater.NewUpdater(&updater.Config{
Client: srv.Client(),
Logger: testLogger,
Version: "v0.103.0-beta.1",
Channel: version.ChannelBeta,
GOARCH: "arm",
@@ -67,8 +65,7 @@ func TestUpdater_VersionInfo(t *testing.T) {
VersionCheckURL: fakeURL,
})
ctx := testutil.ContextWithTimeout(t, testTimeout)
info, err := u.VersionInfo(ctx, false)
info, err := u.VersionInfo(false)
require.NoError(t, err)
assert.Equal(t, counter, 1)
@@ -78,14 +75,14 @@ func TestUpdater_VersionInfo(t *testing.T) {
assert.Equal(t, aghalg.NBTrue, info.CanAutoUpdate)
t.Run("cache_check", func(t *testing.T) {
_, err = u.VersionInfo(testutil.ContextWithTimeout(t, testTimeout), false)
_, err = u.VersionInfo(false)
require.NoError(t, err)
assert.Equal(t, counter, 1)
})
t.Run("force_check", func(t *testing.T) {
_, err = u.VersionInfo(testutil.ContextWithTimeout(t, testTimeout), true)
_, err = u.VersionInfo(true)
require.NoError(t, err)
assert.Equal(t, counter, 2)
@@ -94,7 +91,7 @@ func TestUpdater_VersionInfo(t *testing.T) {
t.Run("api_fail", func(t *testing.T) {
srv.Close()
_, err = u.VersionInfo(testutil.ContextWithTimeout(t, testTimeout), true)
_, err = u.VersionInfo(true)
var urlErr *url.Error
assert.ErrorAs(t, err, &urlErr)
})
@@ -133,7 +130,6 @@ func TestUpdater_VersionInfo_others(t *testing.T) {
for _, tc := range testCases {
u := updater.NewUpdater(&updater.Config{
Client: fakeClient,
Logger: testLogger,
Version: "v0.103.0-beta.1",
Channel: version.ChannelBeta,
GOOS: "linux",
@@ -143,8 +139,7 @@ func TestUpdater_VersionInfo_others(t *testing.T) {
VersionCheckURL: fakeURL,
})
ctx := testutil.ContextWithTimeout(t, testTimeout)
info, err := u.VersionInfo(ctx, false)
info, err := u.VersionInfo(false)
require.NoError(t, err)
assert.Equal(t, "v0.103.0-beta.2", info.NewVersion)

View File

@@ -5,11 +5,9 @@ import (
"archive/tar"
"archive/zip"
"compress/gzip"
"context"
"fmt"
"io"
"io/fs"
"log/slog"
"net/http"
"net/url"
"os"
@@ -24,14 +22,13 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/version"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/ioutil"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil/urlutil"
)
// Updater is the AdGuard Home updater.
type Updater struct {
client *http.Client
logger *slog.Logger
version string
channel string
@@ -78,48 +75,27 @@ func DefaultVersionURL() *url.URL {
// Config is the AdGuard Home updater configuration.
type Config struct {
// Client is used to perform HTTP requests. It must not be nil.
Client *http.Client
// Logger is used for logging the update process. It must not be nil.
Logger *slog.Logger
// VersionCheckURL is URL to the latest version announcement. It must not
// be nil, see [DefaultVersionURL].
VersionCheckURL *url.URL
// Version is the current AdGuard Home version. It must not be empty.
Version string
// Channel is the current AdGuard Home update channel. It must be a valid
// channel, see [version.ChannelBeta] and the related constants.
Channel string
GOARCH string
GOOS string
GOARM string
GOMIPS string
// GOARCH is the current CPU architecture. It must not be empty and must be
// one of the supported architectures.
GOARCH string
// GOOS is the current operating system. It must not be empty and must be
// one of the supported OSs.
GOOS string
// GOARM is the current ARM variant, if any. It must either be empty or be
// a valid and supported GOARM value.
GOARM string
// GOMIPS is the current MIPS variant, if any. It must either be empty or
// be a valid and supported GOMIPS value.
GOMIPS string
// ConfName is the name of the current configuration file. It must not be
// empty.
// ConfName is the name of the current configuration file. Typically,
// "AdGuardHome.yaml".
ConfName string
// WorkDir is the working directory that is used for temporary files. It
// must not be empty.
// WorkDir is the working directory that is used for temporary files.
WorkDir string
// ExecPath is path to the executable file. It must not be empty.
// ExecPath is path to the executable file.
ExecPath string
}
@@ -127,7 +103,6 @@ type Config struct {
func NewUpdater(conf *Config) *Updater {
return &Updater{
client: conf.Client,
logger: conf.Logger,
version: conf.Version,
channel: conf.Channel,
@@ -147,49 +122,49 @@ func NewUpdater(conf *Config) *Updater {
// Update performs the auto-update. It returns an error if the update failed.
// If firstRun is true, it assumes the configuration file doesn't exist.
func (u *Updater) Update(ctx context.Context, firstRun bool) (err error) {
func (u *Updater) Update(firstRun bool) (err error) {
u.mu.Lock()
defer u.mu.Unlock()
u.logger.InfoContext(ctx, "staring update", "first_run", firstRun)
log.Info("updater: updating")
defer func() {
if err != nil {
u.logger.ErrorContext(ctx, "update failed", slogutil.KeyError, err)
log.Info("updater: failed")
} else {
u.logger.InfoContext(ctx, "update finished")
log.Info("updater: finished successfully")
}
}()
err = u.prepare(ctx)
err = u.prepare()
if err != nil {
return fmt.Errorf("preparing: %w", err)
}
defer u.clean(ctx)
defer u.clean()
err = u.downloadPackageFile(ctx)
err = u.downloadPackageFile()
if err != nil {
return fmt.Errorf("downloading package file: %w", err)
}
err = u.unpack(ctx)
err = u.unpack()
if err != nil {
return fmt.Errorf("unpacking: %w", err)
}
if !firstRun {
err = u.check(ctx)
err = u.check()
if err != nil {
return fmt.Errorf("checking config: %w", err)
}
}
err = u.backup(ctx, firstRun)
err = u.backup(firstRun)
if err != nil {
return fmt.Errorf("making backup: %w", err)
}
err = u.replace(ctx)
err = u.replace()
if err != nil {
return fmt.Errorf("replacing: %w", err)
}
@@ -206,7 +181,7 @@ func (u *Updater) NewVersion() (nv string) {
}
// prepare fills all necessary fields in Updater object.
func (u *Updater) prepare(ctx context.Context) (err error) {
func (u *Updater) prepare() (err error) {
u.updateDir = filepath.Join(u.workDir, fmt.Sprintf("agh-update-%s", u.newVersion))
_, pkgNameOnly := filepath.Split(u.packageURL)
@@ -225,12 +200,11 @@ func (u *Updater) prepare(ctx context.Context) (err error) {
u.backupExeName = filepath.Join(u.backupDir, filepath.Base(u.execPath))
u.updateExeName = filepath.Join(u.updateDir, updateExeName)
u.logger.InfoContext(
ctx,
"updating",
"from", version.Version(),
"to", u.newVersion,
"package_url", u.packageURL,
log.Debug(
"updater: updating from %s to %s using url: %s",
version.Version(),
u.newVersion,
u.packageURL,
)
u.currentExeName = u.execPath
@@ -243,20 +217,23 @@ func (u *Updater) prepare(ctx context.Context) (err error) {
}
// unpack extracts the files from the downloaded archive.
func (u *Updater) unpack(ctx context.Context) (err error) {
func (u *Updater) unpack() error {
var err error
_, pkgNameOnly := filepath.Split(u.packageURL)
u.logger.InfoContext(ctx, "unpacking package", "package_name", pkgNameOnly)
log.Debug("updater: unpacking package")
if strings.HasSuffix(pkgNameOnly, ".zip") {
u.unpackedFiles, err = u.unpackZip(ctx, u.packageName, u.updateDir)
u.unpackedFiles, err = zipFileUnpack(u.packageName, u.updateDir)
if err != nil {
return fmt.Errorf(".zip unpack failed: %w", err)
}
} else if strings.HasSuffix(pkgNameOnly, ".tar.gz") {
u.unpackedFiles, err = u.unpackTarGz(ctx, u.packageName, u.updateDir)
u.unpackedFiles, err = tarGzFileUnpack(u.packageName, u.updateDir)
if err != nil {
return fmt.Errorf(".tar.gz unpack failed: %w", err)
}
} else {
return fmt.Errorf("unknown package extension")
}
@@ -266,8 +243,8 @@ func (u *Updater) unpack(ctx context.Context) (err error) {
// check returns an error if the configuration file couldn't be used with the
// version of AdGuard Home just downloaded.
func (u *Updater) check(ctx context.Context) (err error) {
u.logger.InfoContext(ctx, "checking configuration")
func (u *Updater) check() (err error) {
log.Debug("updater: checking configuration")
err = copyFile(u.confName, filepath.Join(u.updateDir, "AdGuardHome.yaml"), aghos.DefaultPermFile)
if err != nil {
@@ -291,9 +268,8 @@ func (u *Updater) check(ctx context.Context) (err error) {
// backup makes a backup of the current configuration and supporting files. It
// ignores the configuration file if firstRun is true.
func (u *Updater) backup(ctx context.Context, firstRun bool) (err error) {
u.logger.InfoContext(ctx, "backing up current configuration")
func (u *Updater) backup(firstRun bool) (err error) {
log.Debug("updater: backing up current configuration")
_ = os.Mkdir(u.backupDir, aghos.DefaultPermDir)
if !firstRun {
err = copyFile(u.confName, filepath.Join(u.backupDir, "AdGuardHome.yaml"), aghos.DefaultPermFile)
@@ -303,7 +279,7 @@ func (u *Updater) backup(ctx context.Context, firstRun bool) (err error) {
}
wd := u.workDir
err = u.copySupportingFiles(ctx, u.unpackedFiles, wd, u.backupDir)
err = copySupportingFiles(u.unpackedFiles, wd, u.backupDir)
if err != nil {
return fmt.Errorf("copySupportingFiles(%s, %s) failed: %w", wd, u.backupDir, err)
}
@@ -313,18 +289,13 @@ func (u *Updater) backup(ctx context.Context, firstRun bool) (err error) {
// replace moves the current executable with the updated one and also copies the
// supporting files.
func (u *Updater) replace(ctx context.Context) (err error) {
err = u.copySupportingFiles(ctx, u.unpackedFiles, u.updateDir, u.workDir)
func (u *Updater) replace() error {
err := copySupportingFiles(u.unpackedFiles, u.updateDir, u.workDir)
if err != nil {
return fmt.Errorf("copySupportingFiles(%s, %s) failed: %w", u.updateDir, u.workDir, err)
}
u.logger.InfoContext(
ctx,
"backing up current executable",
"from", u.currentExeName,
"to", u.backupExeName,
)
log.Debug("updater: renaming: %s to %s", u.currentExeName, u.backupExeName)
err = os.Rename(u.currentExeName, u.backupExeName)
if err != nil {
return err
@@ -340,22 +311,14 @@ func (u *Updater) replace(ctx context.Context) (err error) {
return err
}
u.logger.InfoContext(
ctx,
"replacing current executable",
"from", u.updateExeName,
"to", u.currentExeName,
)
log.Debug("updater: renamed: %s to %s", u.updateExeName, u.currentExeName)
return nil
}
// clean removes the temporary directory itself and all it's contents.
func (u *Updater) clean(ctx context.Context) {
err := os.RemoveAll(u.updateDir)
if err != nil {
u.logger.WarnContext(ctx, "removing update dir", slogutil.KeyError, err)
}
func (u *Updater) clean() {
_ = os.RemoveAll(u.updateDir)
}
// MaxPackageFileSize is a maximum package file length in bytes. The largest
@@ -364,52 +327,34 @@ func (u *Updater) clean(ctx context.Context) {
const MaxPackageFileSize = 32 * 1024 * 1024
// Download package file and save it to disk
func (u *Updater) downloadPackageFile(ctx context.Context) (err error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.packageURL, nil)
func (u *Updater) downloadPackageFile() (err error) {
var resp *http.Response
resp, err = u.client.Get(u.packageURL)
if err != nil {
return fmt.Errorf("constructing package request: %w", err)
}
resp, err := u.client.Do(req)
if err != nil {
return fmt.Errorf("requesting package: %w", err)
return fmt.Errorf("http request failed: %w", err)
}
defer func() { err = errors.WithDeferred(err, resp.Body.Close()) }()
r := ioutil.LimitReader(resp.Body, MaxPackageFileSize)
u.logger.InfoContext(ctx, "reading http body")
log.Debug("updater: reading http body")
// This use of ReadAll is now safe, because we limited body's Reader.
body, err := io.ReadAll(r)
if err != nil {
return fmt.Errorf("io.ReadAll() failed: %w", err)
}
err = os.Mkdir(u.updateDir, aghos.DefaultPermDir)
if err != nil {
// TODO(a.garipov): Consider returning this error.
u.logger.WarnContext(ctx, "creating update dir", slogutil.KeyError, err)
}
u.logger.InfoContext(ctx, "saving package", "to", u.packageName)
_ = os.Mkdir(u.updateDir, aghos.DefaultPermDir)
log.Debug("updater: saving package to file")
err = os.WriteFile(u.packageName, body, aghos.DefaultPermFile)
if err != nil {
return fmt.Errorf("writing package file: %w", err)
}
return nil
}
// unpackTarGzFile unpacks one file from a .tar.gz archive into outDir. All
// arguments must not be empty.
func (u *Updater) unpackTarGzFile(
ctx context.Context,
outDir string,
tr *tar.Reader,
hdr *tar.Header,
) (name string, err error) {
func tarGzFileUnpackOne(outDir string, tr *tar.Reader, hdr *tar.Header) (name string, err error) {
name = filepath.Base(hdr.Name)
if name == "" {
return "", nil
@@ -432,18 +377,13 @@ func (u *Updater) unpackTarGzFile(
return "", fmt.Errorf("creating directory %q: %w", outName, err)
}
u.logger.InfoContext(ctx, "created directory", "name", outName)
log.Debug("updater: created directory %q", outName)
return "", nil
}
if hdr.Typeflag != tar.TypeReg {
u.logger.WarnContext(
ctx,
"unknown file type; skipping",
"file_name", name,
"type", hdr.Typeflag,
)
log.Info("updater: %s: unknown file type %d, skipping", name, hdr.Typeflag)
return "", nil
}
@@ -460,19 +400,16 @@ func (u *Updater) unpackTarGzFile(
return "", fmt.Errorf("io.Copy(): %w", err)
}
u.logger.InfoContext(ctx, "created file", "name", outName)
log.Debug("updater: created file %q", outName)
return name, nil
}
// unpackTarGz unpack all files from a .tar.gz archive to outDir. Existing
// files are overwritten. All files are created inside outDir. files are the
// list of created files.
func (u *Updater) unpackTarGz(
ctx context.Context,
tarfile string,
outDir string,
) (files []string, err error) {
// Unpack all files from .tar.gz file to the specified directory
// Existing files are overwritten
// All files are created inside outDir, subdirectories are not created
// Return the list of files (not directories) written
func tarGzFileUnpack(tarfile, outDir string) (files []string, err error) {
f, err := os.Open(tarfile)
if err != nil {
return nil, fmt.Errorf("os.Open(): %w", err)
@@ -500,7 +437,7 @@ func (u *Updater) unpackTarGz(
}
var name string
name, err = u.unpackTarGzFile(ctx, outDir, tarReader, hdr)
name, err = tarGzFileUnpackOne(outDir, tarReader, hdr)
if name != "" {
files = append(files, name)
@@ -510,13 +447,7 @@ func (u *Updater) unpackTarGz(
return files, err
}
// unpackZipFile unpacks one file from a .zip archive into outDir. All
// arguments must not be empty.
func (u *Updater) unpackZipFile(
ctx context.Context,
outDir string,
zf *zip.File,
) (name string, err error) {
func zipFileUnpackOne(outDir string, zf *zip.File) (name string, err error) {
var rc io.ReadCloser
rc, err = zf.Open()
if err != nil {
@@ -535,8 +466,7 @@ func (u *Updater) unpackZipFile(
if name == "AdGuardHome" {
// Top-level AdGuardHome/. Skip it.
//
// TODO(a.garipov): See the similar TODO in
// [Updater.unpackTarGzFile].
// TODO(a.garipov): See the similar todo in tarGzFileUnpack.
return "", nil
}
@@ -545,7 +475,7 @@ func (u *Updater) unpackZipFile(
return "", fmt.Errorf("creating directory %q: %w", outputName, err)
}
u.logger.InfoContext(ctx, "created directory", "name", outputName)
log.Debug("updater: created directory %q", outputName)
return "", nil
}
@@ -562,19 +492,16 @@ func (u *Updater) unpackZipFile(
return "", fmt.Errorf("io.Copy(): %w", err)
}
u.logger.InfoContext(ctx, "created file", "name", outputName)
log.Debug("updater: created file %q", outputName)
return name, nil
}
// unpackZip unpack all files from a .zip archive to outDir. Existing files are
// overwritten. All files are created inside outDir. files are the list of
// created files.
func (u *Updater) unpackZip(
ctx context.Context,
zipfile string,
outDir string,
) (files []string, err error) {
// Unpack all files from .zip file to the specified directory
// Existing files are overwritten
// All files are created inside 'outDir', subdirectories are not created
// Return the list of files (not directories) written
func zipFileUnpack(zipfile, outDir string) (files []string, err error) {
zrc, err := zip.OpenReader(zipfile)
if err != nil {
return nil, fmt.Errorf("zip.OpenReader(): %w", err)
@@ -583,7 +510,7 @@ func (u *Updater) unpackZip(
for _, zf := range zrc.File {
var name string
name, err = u.unpackZipFile(ctx, outDir, zf)
name, err = zipFileUnpackOne(outDir, zf)
if err != nil {
break
}
@@ -616,12 +543,7 @@ func copyFile(src, dst string, perm fs.FileMode) (err error) {
// copySupportingFiles copies each file specified in files from srcdir to
// dstdir. If a file specified as a path, only the name of the file is used.
// It skips AdGuardHome, AdGuardHome.exe, and AdGuardHome.yaml.
func (u *Updater) copySupportingFiles(
ctx context.Context,
files []string,
srcdir string,
dstdir string,
) (err error) {
func copySupportingFiles(files []string, srcdir, dstdir string) error {
for _, f := range files {
_, name := filepath.Split(f)
if name == "AdGuardHome" || name == "AdGuardHome.exe" || name == "AdGuardHome.yaml" {
@@ -631,12 +553,12 @@ func (u *Updater) copySupportingFiles(
src := filepath.Join(srcdir, name)
dst := filepath.Join(dstdir, name)
err = copyFile(src, dst, aghos.DefaultPermFile)
err := copyFile(src, dst, aghos.DefaultPermFile)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}
u.logger.InfoContext(ctx, "copied", "from", src, "to", dst)
log.Debug("updater: copied: %q to %q", src, dst)
}
return nil

View File

@@ -1,16 +1,12 @@
package updater
import (
"context"
"net/url"
"os"
"path/filepath"
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -59,7 +55,6 @@ func TestUpdater_internal(t *testing.T) {
u := NewUpdater(&Config{
Client: fakeClient,
Logger: slogutil.NewDiscardLogger(),
GOOS: tc.os,
Version: "v0.103.0",
ExecPath: exePath,
@@ -73,13 +68,13 @@ func TestUpdater_internal(t *testing.T) {
u.newVersion = "v0.103.1"
u.packageURL = fakeURL.String()
require.NoError(t, u.prepare(newCtx(t)))
require.NoError(t, u.downloadPackageFile(newCtx(t)))
require.NoError(t, u.unpack(newCtx(t)))
require.NoError(t, u.backup(newCtx(t), false))
require.NoError(t, u.replace(newCtx(t)))
require.NoError(t, u.prepare())
require.NoError(t, u.downloadPackageFile())
require.NoError(t, u.unpack())
require.NoError(t, u.backup(false))
require.NoError(t, u.replace())
u.clean(newCtx(t))
u.clean()
require.True(t, t.Run("backup", func(t *testing.T) {
var d []byte
@@ -118,8 +113,3 @@ func TestUpdater_internal(t *testing.T) {
}))
}
}
// newCtx is a helper that returns a new context with a timeout.
func newCtx(tb testing.TB) (ctx context.Context) {
return testutil.ContextWithTimeout(tb, 1*time.Second)
}

View File

@@ -10,21 +10,17 @@ import (
"path/filepath"
"runtime"
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/updater"
"github.com/AdguardTeam/AdGuardHome/internal/version"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// testTimeout is the common timeout for tests.
const testTimeout = 1 * time.Second
// testLogger is the common logger for tests.
var testLogger = slogutil.NewDiscardLogger()
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
func TestUpdater_Update(t *testing.T) {
const jsonData = `{
@@ -77,7 +73,6 @@ func TestUpdater_Update(t *testing.T) {
u := updater.NewUpdater(&updater.Config{
Client: srv.Client(),
Logger: testLogger,
GOARCH: "amd64",
GOOS: "linux",
Version: "v0.103.0",
@@ -87,12 +82,10 @@ func TestUpdater_Update(t *testing.T) {
VersionCheckURL: versionCheckURL,
})
ctx := testutil.ContextWithTimeout(t, testTimeout)
_, err = u.VersionInfo(ctx, false)
_, err = u.VersionInfo(false)
require.NoError(t, err)
ctx = testutil.ContextWithTimeout(t, testTimeout)
err = u.Update(ctx, true)
err = u.Update(true)
require.NoError(t, err)
// check backup files
@@ -131,15 +124,14 @@ func TestUpdater_Update(t *testing.T) {
t.Skip("skipping config check test on windows")
}
err = u.Update(testutil.ContextWithTimeout(t, testTimeout), false)
err = u.Update(false)
assert.NoError(t, err)
})
t.Run("api_fail", func(t *testing.T) {
srv.Close()
err = u.Update(testutil.ContextWithTimeout(t, testTimeout), true)
err = u.Update(true)
var urlErr *url.Error
assert.ErrorAs(t, err, &urlErr)
})

View File

@@ -980,8 +980,7 @@
- 'clients'
'operationId': 'clientsSearch'
'summary': >
Retrieve information about clients by performing an exact match search
using IP addresses, CIDRs, MAC addresses, or ClientIDs.
Get information about clients by their IP addresses, CIDRs, MAC addresses, or ClientIDs.
'requestBody':
'content':
'application/json':

View File

@@ -199,7 +199,6 @@ run_linter gocognit --over='10' \
./internal/aghhttp/ \
./internal/aghrenameio/ \
./internal/aghtest/ \
./internal/aghuser/ \
./internal/arpdb/ \
./internal/client/ \
./internal/configmigrate/ \
@@ -251,7 +250,6 @@ run_linter fieldalignment \
./internal/aghrenameio/ \
./internal/aghtest/ \
./internal/aghtls/ \
./internal/aghuser/ \
./internal/arpdb/ \
./internal/client/ \
./internal/configmigrate/ \
@@ -282,7 +280,6 @@ run_linter gosec --exclude G115 --quiet \
./internal/aghos/ \
./internal/aghrenameio/ \
./internal/aghtest/ \
./internal/aghuser/ \
./internal/arpdb/ \
./internal/client/ \
./internal/configmigrate/ \