Compare commits

..

71 Commits

Author SHA1 Message Date
Ildar Kamalov
ef92c2e891 Merge branch 'master' into ADG-9565 2025-01-29 13:42:29 +03:00
Ildar Kamalov
a4364ff7ed ADG-9565 format large numbers in the upstream table and query log 2025-01-29 13:39:14 +03:00
Ainar Garipov
91270d0b61 Pull request 2336: 7600-fix-time-in-enable-protection-timer
Closes #7599.
Updates #7600.

* commit 'a4ea6c22335dff3a0f9cfba1ccf9db65a1e6db71':
  fix: time in `enable_protection_timer` translation
2025-01-28 21:39:16 +03:00
Ainar Garipov
a4ea6c2233 Merge branch 'master' into 7600-fix-time-in-enable-protection-timer 2025-01-28 21:30:43 +03:00
Eugene Burkov
c7b65fa522 Pull request 2335: Update changelog
Merge in DNS/adguard-home from upd-chlog to master

Squashed commit of the following:

commit ea263dbf3e2d409ae9a982b89ee7976de96138b1
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Jan 28 20:53:44 2025 +0300

    all: upd chlog
2025-01-28 21:10:48 +03:00
Jan Pieper
1a95161784 fix: time in enable_protection_timer translation 2025-01-28 09:53:58 +01:00
Stanislav Chzhen
6633ad6304 Pull request 2333: fix-test
Merge in DNS/adguard-home from fix-test to master

Squashed commit of the following:

commit cddaed40273e81677eec33e2ededfd4556c5b99f
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Jan 20 18:33:43 2025 +0300

    filtering: fix test
2025-01-20 18:57:51 +03:00
Eugene Burkov
dfa28af907 Pull request 2331: Update all
Merge in DNS/adguard-home from upd-all to master

Squashed commit of the following:

commit 6610425055168c577adb8fe6ccb0557ed867c059
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Jan 20 12:53:21 2025 +0300

    client: upd i18n

commit a1d669e3ec7cab80c4bc5fff0fbba9ff7dfdd136
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Jan 20 12:46:05 2025 +0300

    client: upd trackers
2025-01-20 13:08:43 +03:00
Eugene Burkov
8f75c6ac9d Pull request 2330: Upd Go
Merge in DNS/adguard-home from upd-go to master

Squashed commit of the following:

commit 58aad666b56d7100c7b5291fb8a100fe635e6d62
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jan 17 19:02:06 2025 +0300

    all: upd go
2025-01-17 19:24:56 +03:00
Ildar Kamalov
446f21a511 Pull request 2328: ADG-9458 fix request count link in the clients table
Updates #7513.

Squashed commit of the following:

commit 2b7f6bd4d0e1d8855faacf08cc0dff3e4e6d2bbd
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu Jan 9 15:28:11 2025 +0300

    fix

commit 86f3f32272975a199a8fb3867f3e776f71704916
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu Jan 9 15:27:34 2025 +0300

    fix

commit 786c56828f95c66275a19d816759bacc137041f8
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu Jan 9 15:26:38 2025 +0300

    ADG-9458 fix request count link in the clients table
2025-01-10 16:21:34 +03:00
Stanislav Chzhen
0b25119c52 Pull request #2327: AGDNS-2622-fix-race
Merge in DNS/adguard-home from AGDNS-2622-fix-race to master

Squashed commit of the following:

commit 28170e67655048d7356d6cfce07e04017a933163
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Dec 23 17:24:28 2024 +0300

    all: upd proxy

commit 3bd9458220e04041c5135fa97d55e6e6e6c29071
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Dec 20 21:19:20 2024 +0300

    all: upd proxy
2024-12-23 19:12:55 +03:00
Ainar Garipov
20e56b7171 Pull request 2326: more-md-lint
Merge in DNS/adguard-home from more-md-lint to master

Squashed commit of the following:

commit 39e7ea3b441ebf48c5b0d5c2b5b85620515bbea3
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Dec 19 17:03:36 2024 +0300

    all: imp docs more

commit 7aa08036b239d7eb19f674a6c4bfaf1325ff4bff
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Dec 19 16:08:13 2024 +0300

    all: add more docs to lint
2024-12-19 17:17:40 +03:00
Eugene Burkov
261c1599a5 Pull request #2325: 7510 Fix openapi spec
Merge in DNS/adguard-home from 7510-fix-openapi to master

Squashed commit of the following:

commit b67d6f964081cf12bea5c3406eba64a432d02e81
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Dec 19 15:28:46 2024 +0300

    openapi: fmt openapi chlog

commit 738becf0af96b3bfc4b549be9ad84cbce0d9cf39
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Dec 19 14:44:36 2024 +0300

    openapi: log changes

commit a398712ed1b5696f944f15404e340e002822c89f
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Dec 19 14:34:11 2024 +0300

    openapi: fix spec
2024-12-19 15:38:18 +03:00
Ainar Garipov
21945c6058 Pull request 2324: 7505-format-values
Closes #7329.
Updates #7505.

* commit '5c15d1bb16044bbaff1ff29e8bbe3ce2ff3bc982':
  all: upd chlog
  Format values in General Statistics
2024-12-17 16:55:02 +03:00
Ainar Garipov
5c15d1bb16 Merge branch 'master' into 7505-format-values 2024-12-17 16:37:01 +03:00
Ainar Garipov
efe2ed1304 all: upd chlog 2024-12-17 16:20:12 +03:00
Stanislav Chzhen
fe07786d2d Pull request #2323: AGDNS-2598-clients-search
Merge in DNS/adguard-home from AGDNS-2598-clients-search to master

Squashed commit of the following:

commit 9df3c19acad16203ccaa7752902bce8bc835c8fb
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Dec 16 19:11:43 2024 +0300

    home: imp code

commit 7bf8f0a516b57fab6c19c24e4a156c87d9c4d03f
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Dec 16 18:34:06 2024 +0300

    all: imp code

commit 2dd1c941232ceeaef4c506717096a8b8e8555e6e
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Dec 13 17:35:11 2024 +0300

    all: clients search
2024-12-17 15:08:31 +03:00
Hermholtz
2b55e56306 Format values in General Statistics 2024-12-14 15:43:12 +01:00
Ainar Garipov
dedbadafc4 Pull request 2321: upd-go-deps
Merge in DNS/adguard-home from upd-go-deps to master

Squashed commit of the following:

commit 2c0b63da2ec8bbf19bc7dbb03c0166f6f9a5d822
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Dec 12 14:42:31 2024 +0300

    all: upd go deps, tools
2024-12-12 16:20:13 +03:00
Ainar Garipov
d3cc2dc930 Pull request 2319: websvc-patch
Merge in DNS/adguard-home from websvc-patch to master

Squashed commit of the following:

commit b2a10faf12b16f13f617b3ed3ef3e81cb0479ff8
Merge: 38f749106 8f53f6505
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Dec 11 17:33:15 2024 +0300

    Merge branch 'master' into websvc-patch

commit 38f7491069d90d4080e7ad98b09bf9ce19138195
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Dec 10 19:57:54 2024 +0300

    next: add json merge patch utils
2024-12-11 17:41:00 +03:00
Ainar Garipov
8f53f6505b Pull request 2320: upd-chlog
Merge in DNS/adguard-home from upd-chlog to master

Squashed commit of the following:

commit 305ae5823fa2f61b5f58759a29330a65599c19ba
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Dec 11 17:19:51 2024 +0300

    all: upd and fmt chlog
2024-12-11 17:32:22 +03:00
Stanislav Chzhen
dab608292a Pull request 2314: AGDNS-2374-slog-home-webapi
Squashed commit of the following:

commit 7c457d92b5a2d931c22388d37ad30f10dc0ecd89
Merge: bcd3d29df 11dfc7a3e
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Dec 5 18:24:08 2024 +0300

    Merge branch 'master' into AGDNS-2374-slog-home-webapi

commit bcd3d29dfde4af7d223e2d2468dd01635f799bb9
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Dec 5 18:24:01 2024 +0300

    all: imp code

commit f3af1bf3dd476733d0286eeea9f6dd5ebbdb4950
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Dec 4 18:33:35 2024 +0300

    home: imp code

commit 035477513f433346c7bf3215083c317466b4b734
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Dec 3 19:01:55 2024 +0300

    home: imp code

commit 5368d8de50d266b438a4909d81b5fec76b5ca65c
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Dec 3 17:25:37 2024 +0300

    home: imp code

commit fce1bf475f33f6fe45252e2276ea8ebf2a82a8b2
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Dec 2 18:20:31 2024 +0300

    home: slog webapi
2024-12-06 16:01:58 +03:00
Ildar Kamalov
11dfc7a3e8 Pull request 2316: AGDNS-2239 fix setup guide list styles
Squashed commit of the following:

commit 52cc651e3b6a5fe7c46ad1fb41865f2dd1f84258
Merge: 324c4e102 c234e5dc3
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Dec 5 15:28:39 2024 +0300

    Merge branch 'master' into AGDNS-2239

commit 324c4e1024e6d1c4fc72eeae2baeee6565512a6c
Author: Ildar Kamalov <ik@adguard.com>
Date:   Wed Dec 4 17:03:46 2024 +0300

    fix mobile styles

commit 739ccfa6f1c99562c81c2ba947b3c91fb82ea572
Author: Ildar Kamalov <ik@adguard.com>
Date:   Wed Dec 4 16:45:48 2024 +0300

    AGDNS-2239 fix guide list padding
2024-12-05 15:36:40 +03:00
Eugene Burkov
c234e5dc31 Pull request 2317: Update all
Squashed commit of the following:

commit 832a5ac0c9d588428c7d030978769e510e011645
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Dec 4 17:38:20 2024 +0300

    client: upd i18n

commit 6fa7591109085b169b79bd771808922a1a53f875
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Dec 4 17:20:30 2024 +0300

    client: upd trackers

commit f4b692d37c1cc4d784b4a76f85198f4a1cfa7f83
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Dec 4 16:55:40 2024 +0300

    all: upd tools, go
2024-12-04 17:57:37 +03:00
Eugene Burkov
3895cfb4f0 Pull request 2312: 7400 Windows permcheck
Updates #7400.

Squashed commit of the following:

commit f50d7c200de545dc6c8ef70b39208f522033fb90
Merge: 47040a14c 37b16bcf7
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Dec 3 18:09:23 2024 +0300

    Merge branch 'master' into 7400-chown-permcheck

commit 47040a14cd50bf50429f44eba0acdcf736412b61
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Dec 3 14:26:43 2024 +0300

    permcheck: fix nil entries

commit e1d21c576d75a903b88db3b7beb82348cdcf60c9
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Dec 2 15:37:58 2024 +0300

    permcheck: fix nil owner

commit b1fc67c4d189293d0aee90c1905f7f387840643b
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Nov 29 18:07:15 2024 +0300

    permcheck: imp doc

commit 0b6a71326e249f0923e389aa1f6f164b02802a24
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Nov 29 17:16:24 2024 +0300

    permcheck: imp code

commit 7dfbeda179d0ddb81db54fa4e0dcff189b400215
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Nov 29 14:28:17 2024 +0300

    permcheck: imp code

commit 3a5b6aced948a2d09fdae823fc986266c9984b3d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Nov 28 19:21:03 2024 +0300

    all: imp code, docs

commit c076c9366934303fa8c5909bd13770e367dca72e
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Nov 28 15:14:06 2024 +0300

    permcheck: imp code, docs

commit 09e4ae1ba12e195454f1db11fa2f5c9e8e170f06
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 27 19:19:11 2024 +0300

    all: implement windows permcheck

commit b75ed7d4d30e289b8a99e68e6a5e94ab74cf49cb
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Nov 25 18:01:47 2024 +0300

    all: revert permissions
2024-12-03 18:26:00 +03:00
Ainar Garipov
37b16bcf79 Pull request 2315: 7479-readme-fix
Closes #7477.

* commit '4d470f94840c46d22f6dc1454a84a8fdc11eda6b':
  Update wiki-start in README.md
2024-12-03 14:22:32 +03:00
Margaret Fero
4d470f9484 Update wiki-start in README.md
When I clicked the link aliased as wiki-start, the article had a banner at the top redirecting readers to a newer version on the wiki. This commit replaces the link to the outdated version with the link it redirects to, to save future visitors a click.
2024-12-02 00:45:18 -08:00
Stanislav Chzhen
a8431297f7 Pull request 2313: 7357-upd-proxy
Updates #7357.

Squashed commit of the following:

commit 599dee0e5dd6d0af0e06ac97207a2677c32b03da
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Nov 29 14:52:16 2024 +0300

    all: upd golibs

commit eb90c49d37bbe59ecb4867075d4b6fde70871fa2
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Nov 29 14:32:57 2024 +0300

    all: upd proxy

commit 12b8e51c8738a4c94b257d9b4640bc63f9fa5d70
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Nov 28 20:04:58 2024 +0300

    all: upd proxy

commit 77fcabcf60f72c092a0a49075d1415ce370cdbb6
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Nov 28 17:13:30 2024 +0300

    all: upd chlog

commit 714f93d612abd705732cf76bee365272d15a11ce
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Nov 28 17:02:34 2024 +0300

    all: upd proxy
2024-11-29 15:57:06 +03:00
Eugene Burkov
9789e5b0fe Pull request 2311: 7465 Fix nil dereference
Squashed commit of the following:

commit e4943c2b064ff0647d0e3bd2e6431bb94f151ba5
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 27 17:05:32 2024 +0300

    home: fix nil dereference
2024-11-27 17:16:45 +03:00
Eugene Burkov
4a49c4db96 Pull request 2307: AGDNS-2556 Custom updater URL
Squashed commit of the following:

commit 73f946138ccb4f89141f192b6cb1a21887604ab4
Merge: c58847bfb d578c713f
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Nov 26 17:42:29 2024 +0300

    Merge branch 'master' into AGDNS-2556-custom-update-url

commit c58847bfb08131263e1cff4813eb4a466f613d91
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Nov 26 17:34:11 2024 +0300

    home: imp logging

commit 0d451621d76fdf2c363d223eb29c4442d8f36dc8
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Nov 26 15:12:04 2024 +0300

    home: rename config field

commit c7f3822929e9199f8f411f1a0ad072c643feb42f
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Nov 26 15:07:09 2024 +0300

    all: enable updater for some cases

commit 872cd3a18c876076ea643624336cfc0a4296a81d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Nov 22 19:09:18 2024 +0300

    updater: imp test

commit c9efb412e7411b769df54b7247fe168047fb9799
Merge: c989eef71 abb738013
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Nov 22 17:51:46 2024 +0300

    Merge branch 'master' into AGDNS-2556-custom-update-url

commit c989eef715ae7edd98d7b2d5df06fd3d04153209
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Nov 22 17:46:34 2024 +0300

    all: imp code

commit 0452d8b356e6d0b73b097d43b97b7027fcca752d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Nov 22 15:37:21 2024 +0300

    all: add custom url to updater
2024-11-26 20:35:16 +03:00
Stanislav Chzhen
d578c713ff Pull request 2310: 6818-fix-goroutine-leak
Updates #6818.

Squashed commit of the following:

commit 3027fc4a615beba9138449d65994f1630b5a6cbf
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Nov 25 16:53:33 2024 +0300

    all: fixed goroutine leak
2024-11-26 13:34:16 +03:00
Stanislav Chzhen
d4ca14806e Pull request 2309: fix-safesearch-test
Squashed commit of the following:

commit a5b6c831d86ee5264c0918bf12ddef7c78f78f38
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Nov 25 13:45:17 2024 +0300

    dnsforward: imp tests

commit 1ca353423ca4dcc7616475fbf12c9b5b9450a5ea
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Nov 22 20:08:28 2024 +0300

    dnsforward: imp tests

commit 82851aa825818159b5b1583e2716d6656d633b03
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Nov 22 19:54:53 2024 +0300

    dnsforward: imp tests

commit efabbe318e7520eba65b595f11e2fb8effaeec13
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Nov 22 19:36:27 2024 +0300

    dnsforward: fix safesearch test
2024-11-25 14:31:21 +03:00
Stanislav Chzhen
abb738013a Pull request 2308: AGDNS-2374-slog-client-storage
Squashed commit of the following:

commit 670ce6f7267ae6447c179ba491fc18c01cffa1ab
Merge: b3029a041 098cbab7e
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Nov 22 17:09:08 2024 +0300

    Merge branch 'master' into AGDNS-2374-slog-client-storage

commit b3029a041aa0f4b536dd899f162fcee2b7d5127b
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Nov 22 16:53:18 2024 +0300

    all: slog client storage
2024-11-22 17:18:47 +03:00
Eugene Burkov
098cbab7e6 Pull request 2305: 7400 Disable permcheck
Updates #7400.

Squashed commit of the following:

commit f6508d395288dfa5ed0b9aa2e714bc1eba72d243
Merge: aa7119648 d96e65cb0
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Nov 22 15:43:27 2024 +0300

    Merge branch 'master' into 7400-disable-perm

commit aa7119648bae3f2ff6af96215c3c8eab70b379ea
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 20 16:51:37 2024 +0300

    next: add flag

commit c16b90918f5a9493876e3d16776fb18f67cbc09b
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 20 16:42:47 2024 +0300

    home: fix help

commit 2e096c0e320599b9472f55a47c1abbc95e1a9f8e
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 20 16:37:30 2024 +0300

    all: imp code, log changes

commit 368598819fc339cc1dbf788d092af9e4c5191f30
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 20 16:12:18 2024 +0300

    home: add permcheck option
2024-11-22 17:03:09 +03:00
Stanislav Chzhen
d96e65cb0c Pull request 2304: AGDNS-2374-slog-querylog
Squashed commit of the following:

commit e98e5efaaf5388551322933321df0707ad7b2a9c
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Nov 21 13:15:51 2024 +0300

    all: imp code

commit fbe728c9aa03a325c2733c214412f9071faba5ed
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Nov 18 20:57:15 2024 +0300

    all: imp code

commit ef715c58cb6621236424f55268390aa3f997f883
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Nov 18 16:39:35 2024 +0300

    all: imp code

commit cbb993f7ae4311b2a73ace7066a5dabf190291be
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Nov 18 14:03:42 2024 +0300

    all: imp code

commit 8d88d799303c7e3d15322fee87780fedb408ea13
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Nov 15 15:57:07 2024 +0300

    all: slog querylog
2024-11-21 20:19:39 +03:00
Ainar Garipov
1d6d85cff4 Pull request 2303: AGDNS-2505-upd-next
Squashed commit of the following:

commit 586b0eb180afc22d06d673756dd916c17a173361
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 12 19:58:56 2024 +0300

    next: upd more

commit d729aa150f7ac367255830cceca40b8880c51015
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 12 16:53:15 2024 +0300

    next/websvc: upd more

commit 0c64e6cfc66b9212f077b2de7450586fd4d02802
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Nov 11 21:08:51 2024 +0300

    next: upd more

commit 05eec75222360708621c99d3eeac7c8d9f2a5080
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 8 19:20:02 2024 +0300

    next: upd code
2024-11-13 15:44:21 +03:00
Ainar Garipov
ac5a96fada Pull request 2302: upd-all
Squashed commit of the following:

commit f920006277f39b74c803139af2a9039aa45effae
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 8 16:14:41 2024 +0300

    all: fix pre-commit; upd dnsproxy

commit 391f79b244348c6075f5ba0fccfb8882791bf3f1
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 7 18:53:28 2024 +0300

    scripts: imp install

commit 35324db80b591831c32b7ea45930eefee82a6320
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 7 18:20:23 2024 +0300

    all: imp docs, scripts

commit d2724cfaefdb8659efbdb5bf181a28721a909f07
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 7 17:26:23 2024 +0300

    all: upd go, deps, tools, scripts
2024-11-08 17:18:16 +03:00
Eugene Burkov
6673bb175a Pull request 2301: Update all
Squashed commit of the following:

commit df783c76335d8733eb385c047c491ed1bb8b0e51
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 6 18:44:55 2024 +0300

    client: upd i18n

commit b72d4564baa8f8bab819d045aec29f9ab977538d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 6 18:06:27 2024 +0300

    client: upd filters and trackers
2024-11-06 19:26:57 +03:00
Eugene Burkov
b1a0f4fa44 Pull request 2299: AG-29637 Sign release
Squashed commit of the following:

commit 265097a29ed8e89933c08cb8094297ac89a8b140
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 6 18:03:19 2024 +0300

    all: fix darwin find, log changes

commit 298b31c4078239ce83fdf7a3a741062e56f35b9d
Merge: 82c487518 d06b18a49
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 6 18:01:28 2024 +0300

    Merge branch 'master' into AG-29637-sign-release

commit 82c487518bd21a995921a7d5265da6884aac9e9f
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 6 17:34:12 2024 +0300

    scripts: imp fmt manually

commit 4e33ec1a77dd239df8b5eeec16843e517797d486
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Nov 6 14:42:09 2024 +0300

    scripts: imp fmt, sign releases
2024-11-06 18:45:21 +03:00
Ainar Garipov
d06b18a493 Pull request 2300: upd-chlog
Squashed commit of the following:

commit 20d68fb4bbb5874c816e4cfc8ff40ab16e7c8c46
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Nov 6 17:40:08 2024 +0300

    all: upd chlog
2024-11-06 17:56:48 +03:00
Eugene Burkov
80ec01dd49 Pull request 2298: 7314 Fix updater
Updates #7314.

Squashed commit of the following:

commit be214937fc391cf8c0c31e52a29b0adbdcd81f08
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Nov 5 18:42:25 2024 +0300

    updater: upd doc

commit bdb9df94eecb8b1845b1e65b39325f163541ee91
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Nov 5 18:41:26 2024 +0300

    all: rename const

commit 7fbabeb939ba37aba11852af3c4095363e4ce304
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Nov 5 18:34:37 2024 +0300

    all: add binary const

commit c9f1a9f747c9ec440a9ea5754eed6974eff4169d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Nov 5 18:20:44 2024 +0300

    updater: fix binary perm
2024-11-05 19:21:29 +03:00
Ainar Garipov
47dfa44cf6 Pull request 2297: AG-20945-filter-storage
Squashed commit of the following:

commit 2611fd57815910c035621879094ab954389f31b4
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 1 16:29:06 2024 +0300

    dnsforward: imp test

commit 5efcfda937da2ce229ae1a3c57d7a4de35ee7caf
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 1 15:54:18 2024 +0300

    rulelist: imp docs, tests

commit 7a759c46997ed69e931a0a7c4f25820c52660a3f
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 1 14:36:08 2024 +0300

    all: add filtering storage; upd golibs
2024-11-05 12:25:39 +03:00
Ainar Garipov
1d2026bf7e Pull request 2295: upd-all
Squashed commit of the following:

commit c1f3375abc42809928ff80bede77f4099d2e7c1c
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Oct 29 14:34:14 2024 +0300

    all: upd deps, lists, tools
2024-10-29 14:49:25 +03:00
Eugene Burkov
e77de2e67d Pull request 2294: AGDNS-2455 Windows permissions
Closes #7314.

Squashed commit of the following:

commit f8b6ffeec2f0f96c947cf896c75d05efaca77caf
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Oct 29 14:14:41 2024 +0300

    all: fix chlog

commit 9417b7dc510296c096f234e2f340dad5a6faf627
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Oct 28 19:41:30 2024 +0300

    aghos: imp doc

commit b91f0e72a70a8e1392bd07b50714d8b83cc4e33e
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Oct 28 19:26:15 2024 +0300

    all: rm bin

commit 9008ee93b181794c5082894bfa5ce4c76153f93d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Oct 28 18:23:54 2024 +0300

    all: revert permcheck

commit bcc85d50f5f39269713979c6509a9acd220570b8
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Oct 28 17:48:55 2024 +0300

    all: use aghos more

commit 993e351712fbf004a6f96e06061ba2321c1c46e1
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Oct 28 16:24:56 2024 +0300

    all: fix more bugs

commit a22b0d265eb0fa747e136363558b97de54e593b8
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 18:30:52 2024 +0300

    all: fix bugs

commit a2309f812ad3fd83d26c373b67756ea3074f4854
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 17:05:08 2024 +0300

    all: fix chlog, imp api

commit 42c3f8e91c49998068bc208166de20efe49c3dcb
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 16:04:47 2024 +0300

    scripts: fix docs

commit 9e781ff18db58ed9be35e259ecf3c669a4d41e02
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 16:03:19 2024 +0300

    scripts: imp docs

commit 1dbc7849828cc4933bb5edc3257f158ac292d48e
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 15:55:16 2024 +0300

    all: use new functions, add tests

commit dcbabaf4e37149a73969c52c9bfac2b9d9127a67
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 13:23:50 2024 +0300

    aghos: add stat

commit 72d7c0f881835725e65db63ac2dd1c5f7a409036
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Oct 24 17:10:30 2024 +0300

    aghos: add windows functions
2024-10-29 14:28:59 +03:00
Stanislav Chzhen
e529d29e8a Pull request 2291: AGDNS-2374-slog-client
Squashed commit of the following:

commit e8e6dba18b8f44392bd88999e481723a00aa3042
Merge: 929283702 41cce6259
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Oct 22 13:46:26 2024 +0300

    Merge branch 'master' into AGDNS-2374-slog-client

commit 929283702a6a82163906e624f965b934e3b8074e
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Oct 15 14:30:00 2024 +0300

    client: imp tests

commit f29d8edb89e3f05e0bd9c3b0eccc0587882a3ed3
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Oct 14 15:03:08 2024 +0300

    client: imp docs

commit 0b4311ac26c704bbfa0edfc51767c9fc74f959a2
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Oct 11 19:12:50 2024 +0300

    all: imp code

commit 1ad99ee3cb915bb19eff8b893deae1dd4d64b190
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Oct 10 20:59:46 2024 +0300

    all: slog client
2024-10-22 13:57:54 +03:00
Stanislav Chzhen
41cce62597 Pull request 2292: 7338-stats-log-msg
Updates #7338.

Squashed commit of the following:

commit a3ff2af22113d5d31f29f6626fb5b1897ca0d7b3
Merge: 9558de14e 5b45f6d50
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Oct 14 17:48:26 2024 +0300

    Merge branch 'master' into 7338-stats-log-msg

commit 9558de14ef7786cd37481fd13975b3c469c98083
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Oct 14 14:11:13 2024 +0300

    all: imp stats log msg
2024-10-14 18:14:09 +03:00
Stanislav Chzhen
5b45f6d508 Pull request 2293: fix-snap-build
Squashed commit of the following:

commit 44e617662007cf9dac5d11f67d8ea091564f6c2c
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Oct 14 17:15:51 2024 +0300

    all: fix typo

commit ed26f49be92161fcd7e6ffd3cf2c12c560ad2ab7
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Oct 14 17:14:05 2024 +0300

    all: fix snap build

commit 97d186d513c3ea600a8634cd5521b163bfd83394
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Oct 14 16:47:11 2024 +0300

    all: fix snap build
2024-10-14 17:47:47 +03:00
Stanislav Chzhen
73ff401b0f Pull request 2290: 7250-custom-client-cache
Updates #7250.

Squashed commit of the following:

commit 062660f17e164b92a3254c5b79543080c6884dd5
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Oct 9 17:42:17 2024 +0300

    all: upd chlog

commit 66fa039ede456454f26b3bfedefabfe71beda3ab
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Oct 9 17:30:58 2024 +0300

    home: custom client cache
2024-10-10 16:33:03 +03:00
Stanislav Chzhen
6363f8a2e7 Pull request 2286: AGDNS-2374-slog-safesearch
Squashed commit of the following:

commit 1909dfed99b8815c1215c709efcae77a70b52ea3
Merge: 3856fda5f 2c64ab5a5
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Oct 9 16:21:38 2024 +0300

    Merge branch 'master' into AGDNS-2374-slog-safesearch

commit 3856fda5f38a89d2df86bd8701e79d7f3fc02bb7
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Oct 8 20:04:34 2024 +0300

    home: imp code

commit de774009aa82bf45022fd9c359296e7ab45bf93d
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Oct 7 16:41:58 2024 +0300

    all: imp code

commit 038bae59d51497de1db7153e00e779db30f79721
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Oct 3 20:24:48 2024 +0300

    all: imp code

commit 792975e248bb04bce5a8ec767441fcf253c6d00f
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Oct 3 15:46:40 2024 +0300

    all: slog safesearch
2024-10-09 16:31:03 +03:00
Stanislav Chzhen
2c64ab5a51 Pull request 2289: upd-urlfilter
Updates #6818.

Squashed commit of the following:

commit d03b518457ef14d1c565a46c1dbfce1a47bf301d
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Oct 4 18:58:10 2024 +0300

    all: upd chlog

commit 80ee9146998d622c173a9559b8d6af139b750d23
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Fri Oct 4 18:50:24 2024 +0300

    all: upd urlfilter
2024-10-04 19:10:32 +03:00
Stanislav Chzhen
df097341c3 Pull request 2287: 7315-fix-client-storage-panic
Closes #7315.

Squashed commit of the following:

commit 94c8473a14d98b45b5086de432bc68dd55eb654b
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Oct 3 19:09:23 2024 +0300

    all: upd chlog

commit 82b772b1dde19277832d44f9b22c47d22f90bf7e
Merge: e7f34cc43 4919630cc
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Oct 3 19:00:53 2024 +0300

    Merge branch 'master' into 7315-fix-client-storage-panic

commit e7f34cc435f53b80aca328a62e27c6aaa8fe6462
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Oct 3 17:55:39 2024 +0300

    home: fix client storage panic
2024-10-04 18:10:56 +03:00
Stanislav Chzhen
4919630ccc Pull request 2288: upd-chlog
Squashed commit of the following:

commit f064da09e4fa644c085b4e21f18bb27c65549b92
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Oct 3 18:33:58 2024 +0300

    all: imp chlog more

commit 662ba0f56995e9f955446b134f7c71e9d4d59ccd
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Oct 3 18:25:09 2024 +0300

    all: upd chlog
2024-10-03 18:47:28 +03:00
Ainar Garipov
b32b8f9c7e Pull request 2285: fix-test
Squashed commit of the following:

commit 006391c9c089a2d9fe7ad7157e609898be2ee225
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Oct 3 14:15:10 2024 +0300

    dnsforward: imp test more

commit ce743a35eff5271cb13a892373536ae815a74ebb
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Oct 2 21:13:02 2024 +0300

    dnsforward: fix test
2024-10-03 14:56:07 +03:00
Ainar Garipov
355cec1d7b Pull request 2284: AG-32257-file-permission-mitigation
Squashed commit of the following:

commit 6e0e61ec2e95a563b04a622f46c6bbe2b2e12711
Merge: e3cccc01a 5b5b39713
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Oct 2 20:51:29 2024 +0300

    Merge branch 'master' into AG-32257-file-permission-mitigation

commit e3cccc01a9cbd382cec0fcd7f3685e43acb48424
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Oct 2 19:57:32 2024 +0300

    dnsforward: imp test

commit 16ecebbc2fd2f4afe2bf475774af1786fa7a02c0
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Oct 2 19:22:10 2024 +0300

    configmigrate: imp tests

commit da8777c3a7c81e17c0d08cfff4e3a9c8d2bbd649
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Oct 2 18:58:46 2024 +0300

    all: imp types, tests

commit 58822a0ef8aa2d944a667d1ba77fe23ff52af424
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Oct 2 18:28:37 2024 +0300

    all: imp chlog

commit 8ce81f918cc5cf43972e2045532a48c829257a2f
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Oct 2 18:09:57 2024 +0300

    all: improve permissions, add safe_fs_patterns
2024-10-02 21:00:15 +03:00
Stanislav Chzhen
5b5b397132 Pull request 2283: AG-27492-fix-safesearch-cache
Squashed commit of the following:

commit c93ee78c05fae78c99796acfdfcfb4755469e37f
Merge: 8019871a9 557898788
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Oct 2 20:41:52 2024 +0300

    Merge branch 'master' into AG-27492-fix-safesearch-cache

commit 8019871a93b1326cdc3475f49198bc28f194a097
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Oct 2 15:31:37 2024 +0300

    home: fix safesearch cache
2024-10-02 20:48:58 +03:00
Ainar Garipov
5578987884 Pull request 2282: all: upd go, tools, deps
Squashed commit of the following:

commit 760afd59cba826bdc1686506ca7a9243dcb35ab7
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Oct 2 14:52:29 2024 +0300

    all: upd go, tools, deps
2024-10-02 15:16:32 +03:00
Ainar Garipov
54a975f584 Pull request 2280: upd-all
Squashed commit of the following:

commit 8d93f660087f5a08c3775f69a79978da6176e41a
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Sep 30 19:49:47 2024 +0300

    all: imp chlog

commit 858765e7a5e5e668db43cc4e4753a71d022c3034
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Sep 30 19:36:39 2024 +0300

    all: upd i18n, lists, tools
2024-09-30 20:03:10 +03:00
Stanislav Chzhen
d40de33316 Pull request 2273: AG-27492-client-storage-runtime-sources
Squashed commit of the following:

commit 3191224d6de3d679ed7c3a35a383ebed27d3c181
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Sep 26 18:20:04 2024 +0300

    client: imp tests

commit 6cc4ed53a206657c5626a5894190a6851ebb3b01
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Sep 26 18:04:36 2024 +0300

    client: imp code

commit 79272b299ad16534ba4919e1f0616a875d7a15cb
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Sep 26 16:10:06 2024 +0300

    all: imp code

commit 0a001fffbe4dece198f9343b998d606e85f94703
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Sep 24 20:05:47 2024 +0300

    all: imp tests

commit 80f7e98d302f78332a4e297f243ad1c4a958cadd
Merge: df7492e9d e338214ad
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Sep 24 19:10:13 2024 +0300

    Merge branch 'master' into AG-27492-client-storage-runtime-sources

commit df7492e9de063e3c1b582e9f014554bc6cba7e90
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Sep 24 19:06:37 2024 +0300

    all: imp code

commit 23896ae5a6ee3f2d3a54dc15536d1c9349ba46b5
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Sep 19 21:04:34 2024 +0300

    client: fix typo

commit ba0ba2478ccd50d764d1a6a2d5c4b4b35b9b2a1c
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Sep 19 21:02:13 2024 +0300

    all: imp code

commit f7315be742422dda8d0adede6666b119761e67f4
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Sep 12 14:35:38 2024 +0300

    home: imp code

commit f63d0e80fb34f0d2799be7d51138ad1200449fc5
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Sep 12 14:15:49 2024 +0300

    all: imp code

commit 9feda414b6e469d911c9428d9ce1c5043d27cc93
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Sep 10 17:53:42 2024 +0300

    all: imp code

commit fafd7cbb52d36bea260c9d922b7c4204f73e7a66
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Sep 9 21:13:05 2024 +0300

    all: imp code

commit 2d2b8e02163e1bd03bf46d46ef7dbb6a50c4e844
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Sep 5 20:55:10 2024 +0300

    client: add tests

commit 4d394e6f2162f797c409073cb52e1e0de93a9d5e
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Aug 29 20:40:38 2024 +0300

    all: client storage runtime sources
2024-09-30 14:17:42 +03:00
Stanislav Chzhen
e338214ad5 Pull request 2279: AG-27492-clients-runtime-sources-dhcp
Squashed commit of the following:

commit 51fb3e3d07752a33310b05d99726b248d3897335
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Sep 19 17:01:03 2024 +0300

    all: upd chlog

commit 3ab945bb442c921ffbfa14c1dd2825f8ed307999
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Sep 19 16:49:00 2024 +0300

    home: clients runtime sources dhcp
2024-09-19 20:01:16 +03:00
Eugene Burkov
a74c32f742 Pull request 2277: AG-29637 Sign Windows
Squashed commit of the following:

commit d22a4cb262c984241863d8dec1e498d83733ac6f
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Sep 11 15:19:01 2024 +0300

    all: resolve tmp todos

commit 4574b050bae921ec9ebed5f90f96f571ca7800cd
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Sep 11 14:55:44 2024 +0300

    bamboo: checkout later

commit 3036a46566c78350f1335cdd9f17f28c837b679f
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Sep 11 14:35:36 2024 +0300

    bamboo: list files

commit eb675abfc0415907e41e08c8c2bc565162697478
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Sep 11 14:28:14 2024 +0300

    bamboo: work with vcs properly

commit 0c34b4dcfd836f0f1c01cbde50cfc505eb46a5ff
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Sep 11 14:15:06 2024 +0300

    bamboo: add repo name var

commit 15da8e294f6ee43643787264492facd881bf7713
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Sep 11 14:06:26 2024 +0300

    bamboo: upd api key

commit b1d353dbc3b1b29596f15fa2c6fcb1d7d5f57d72
Merge: 3309f0703 cbae07e8e
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Sep 10 19:29:29 2024 +0300

    Merge branch 'master' into AG-29637-sign-windows

commit 3309f07031331d6f72170a7bb91c35e0a2e50c46
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Sep 10 19:09:44 2024 +0300

    all: only sign beta

commit f61af53a70b3abd15717f341f07b58091eb4a988
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Sep 10 15:32:31 2024 +0300

    all: sign windows
2024-09-11 19:39:54 +03:00
Eugene Burkov
cbae07e8e6 Pull request 2278: AG-29637 Checkout publisher
Squashed commit of the following:

commit fec1efed4680076b33141a72e36904c27a04677d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Sep 10 19:14:59 2024 +0300

    bamboo: add publisher
2024-09-10 19:25:31 +03:00
Eugene Burkov
6fe4b9440d Pull request 2276: Update Go & tools
Squashed commit of the following:

commit 74629880756659d22989a69bd7631a246207d3b7
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Sep 10 14:35:51 2024 +0300

    all: fix docs

commit 238ff1d418f1aef2b0056be96ce83484341c3fea
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Sep 10 14:28:27 2024 +0300

    all: upd go & tools
2024-09-10 15:14:48 +03:00
Stanislav Chzhen
b443cf35c4 Pull request 2275: AGDNS-2374-slog-stats
Squashed commit of the following:

commit 45b2fc6a05a4f7775d2b6fa056c81d53d4f402d7
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Sep 5 18:07:06 2024 +0300

    all: imp code

commit 022c90496a46b0a0423dd2cb1c02a3473ba5d224
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Sep 4 19:32:35 2024 +0300

    stats: imp code

commit bb3c0c8002c34bec7440cd93b7833f7022eef0d8
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Sep 4 19:10:36 2024 +0300

    all: imp code

commit 363a16f6bb2faa1d9b890b4967684129208af62e
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Sep 4 17:45:31 2024 +0300

    all: imp code

commit a3c96e3d211cc5e11ba09e334748f65a44b8960a
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Sep 2 20:44:11 2024 +0300

    stats: imp code

commit 2c0ffd91fddd286254b53be790146a2931b7b55b
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Sep 2 19:47:11 2024 +0300

    all: slog stats
2024-09-09 13:31:54 +03:00
Stanislav Chzhen
76344f9785 Pull request 2274: AGDNS-2374-slog-scripts
Squashed commit of the following:

commit 257bd542f78d6e06a6b4783a050b573240a2b5ca
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Sep 2 17:33:12 2024 +0300

    scripts: slog
2024-09-02 18:03:37 +03:00
Stanislav Chzhen
aab6769fa2 Pull request 2272: AGDNS-2374-slog-rdns-whois
Squashed commit of the following:

commit 695db57ec872ac8fa1b3a3b2c095bbe4c5c782cc
Merge: 6b3fda0a3 0b8bf1345
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Aug 29 16:08:39 2024 +0300

    Merge branch 'master' into AGDNS-2374-slog-rdns-whois

commit 6b3fda0a37dfb309cc0909cd86dcb86e6b22afef
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Aug 27 20:40:01 2024 +0300

    all: imp code

commit 0b1f022094e268f51391825c9d5ff9ff1ea27af0
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Aug 26 20:35:06 2024 +0300

    all: slog rdns whois
2024-08-29 16:20:05 +03:00
Stanislav Chzhen
0b8bf13453 Pull request 2271: AGDNS-2374-slog-arpdb
Squashed commit of the following:

commit 355136e6e2f3e77b483d97fbc01fbef562c319eb
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Aug 27 18:09:51 2024 +0300

    arpdb: imp docs

commit 27383833033216ab938b0896dbc39e5af8d4dde9
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Aug 26 19:11:10 2024 +0300

    all: slog arpdb
2024-08-27 20:42:10 +03:00
Stanislav Chzhen
738958d90a Pull request 2270: AGDNS-2374-slog-ipset
Squashed commit of the following:

commit 51ff7d8c49d174d057b4f508f3e113e1ca86bd1a
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Aug 22 13:50:10 2024 +0300

    dnsforward: imp code

commit a1c0011273fc83ec1b509a9d930bca5e278e1e2c
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Aug 21 21:53:01 2024 +0300

    dnsforward: imp code

commit a64fd6b3f037712927a583d04296fcaf821f6442
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Aug 21 21:28:48 2024 +0300

    dnsforward: imp code

commit 37ccae4e923a7e688e79a135b0e49a746e9b2a06
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Aug 21 20:23:58 2024 +0300

    all: imp code

commit 03c69ab2729eb424d768def986cba83731ad3e3b
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Aug 21 19:08:30 2024 +0300

    all: imp code

commit 72adfb101fcdb42635702c1f1c4e13ddcc95bfdc
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Aug 21 16:42:44 2024 +0300

    all: slog ipset
2024-08-26 13:30:00 +03:00
Stanislav Chzhen
30c0bbe5cc Pull request 2265: AG-27492-client-runtime-storage
Squashed commit of the following:

commit a164bace2e0333cf95622f34df7b0e79eac69f41
Merge: 6567cd330 184f476bd
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Aug 21 16:14:55 2024 +0300

    Merge branch 'master' into AG-27492-client-runtime-storage

commit 6567cd330ce76d4744f5eb990c09efdb5481aea9
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Aug 20 16:45:43 2024 +0300

    all: imp code

commit 243123a404bb5279a27de18391fa58a9d3e6149b
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Aug 15 19:15:54 2024 +0300

    all: add tests

commit 6489996878ab6bf2ec93c359599ae29e58e938a0
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Aug 5 15:12:05 2024 +0300

    all: client runtime storage
2024-08-21 16:27:28 +03:00
Eugene Burkov
184f476bdc Pull request 2269: ADG-8932 Upd all
Squashed commit of the following:

commit 00fc45877776ed7d1c59be26330f6f16d784ead2
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Aug 20 16:21:25 2024 +0300

    all: imp lint

commit b04d9cd334a92faf21787e7e1ebf20d5e5fd0bee
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Aug 20 14:40:18 2024 +0300

    all: upd all

commit f151f8c3139a0d8ac8cc5cf4926710b8d3f98846
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Aug 16 13:12:36 2024 +0300

    all: upd proxy
2024-08-20 18:38:04 +03:00
Dimitry Kolyshev
cdf970fcbf Pull request: 5704-riscv
Updates #5704.

Squashed commit of the following:

commit f111e2033afff7e25bbd87df67b83f709446c6cd
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Aug 8 11:27:41 2024 +0300

    docs: chlog

commit 0d56423056075844cef2035481d759dbb1b50b35
Merge: 866239a49 1a6ec30bd
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Aug 8 11:26:14 2024 +0300

    Merge remote-tracking branch 'origin/master' into 5704-riscv

commit 866239a490eb90b058e41e83ca45242534d61ba1
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 6 16:00:05 2024 +0500

    home: riscv arch

commit 60693828579a3ed4949234fc77bbf973981c8db2
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 6 15:56:23 2024 +0500

    scripts: riscv arch

commit ea7cb3a0bdbf25dfce1521de590d92e3b2c89252
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 6 14:35:14 2024 +0500

    scripts: riscv arch
2024-08-08 13:38:26 +03:00
Dimitry Kolyshev
1a6ec30bd7 Pull request: AGDNS-2342-upd-golibs
Squashed commit of the following:

commit 82140ab77775b32ea10d7cd011f2bdc2410f9b92
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 6 11:25:13 2024 +0500

    all: upd golibs
2024-08-07 15:49:32 +03:00
255 changed files with 34504 additions and 31965 deletions

View File

@@ -1,7 +1,7 @@
'name': 'build'
'env':
'GO_VERSION': '1.22.5'
'GO_VERSION': '1.23.5'
'NODE_VERSION': '16'
'on':
@@ -95,7 +95,7 @@
'key': "${{ runner.os }}-node-${{ hashFiles('client/package-lock.json') }}"
'restore-keys': '${{ runner.os }}-node-'
- 'name': 'Set up Snapcraft'
'run': 'sudo apt-get -yq --no-install-suggests --no-install-recommends install snapcraft'
'run': 'sudo snap install snapcraft --classic'
- 'name': 'Set up QEMU'
'uses': 'docker/setup-qemu-action@v1'
- 'name': 'Set up Docker Buildx'

View File

@@ -1,7 +1,7 @@
'name': 'lint'
'env':
'GO_VERSION': '1.22.5'
'GO_VERSION': '1.23.5'
'on':
'push':

7
.gitignore vendored
View File

@@ -1,3 +1,8 @@
# This comment is used to simplify checking local copies of the file. Bump
# this number every time a significant change is made to this file.
#
# AdGuard-Project-Version: 1
# Please, DO NOT put your text editors' temporary files here. The more are
# added, the harder it gets to maintain and manage projects' gitignores. Put
# them into your global gitignore file instead.
@@ -8,6 +13,7 @@
# bottom to make sure they take effect.
*.db
*.log
*.out
*.snap
*.test
/agh-backup/
@@ -21,6 +27,7 @@
/launchpad_credentials
/querylog.json*
/snapcraft_login
/test-reports/
AdGuardHome
AdGuardHome.exe
AdGuardHome.yaml*

25
.markdownlint.json Normal file
View File

@@ -0,0 +1,25 @@
{
"ul-indent": {
"indent": 4
},
"ul-style": {
"style": "dash"
},
"emphasis-style": {
"style": "asterisk"
},
"no-duplicate-heading": {
"siblings_only": true
},
"no-inline-html": {
"allowed_elements": [
"a"
]
},
"no-trailing-spaces": {
"br_spaces": 0
},
"line-length": false,
"no-bare-urls": false,
"link-fragments": false
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
# Keep the Makefile POSIX-compliant. We currently allow hyphens in
# target names, but that may change in the future.
#
# See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html.
# See https://pubs.opengroup.org/onlinepubs/9799919799/utilities/make.html.
.POSIX:
# This comment is used to simplify checking local copies of the
# Makefile. Bump this number every time a significant change is made to
# this Makefile.
#
# AdGuard-Project-Version: 4
# AdGuard-Project-Version: 9
# Don't name these macros "GO" etc., because GNU Make apparently makes
# them exported environment variables with the literal value of
@@ -22,12 +22,12 @@ VERBOSE.MACRO = $${VERBOSE:-0}
CHANNEL = development
CLIENT_DIR = client
COMMIT = $$( git rev-parse --short HEAD )
DEPLOY_SCRIPT_PATH = not/a/real/path
DIST_DIR = dist
GOAMD64 = v1
GOPROXY = https://goproxy.cn|https://proxy.golang.org|direct
GOSUMDB = sum.golang.google.cn
GOTOOLCHAIN = go1.22.5
GOPROXY = https://proxy.golang.org|direct
GOTELEMETRY = off
GOTOOLCHAIN = go1.23.5
GPG_KEY = devteam@adguard.com
GPG_KEY_PASSPHRASE = not-a-real-password
NPM = npm
@@ -35,7 +35,9 @@ NPM_FLAGS = --prefix $(CLIENT_DIR)
NPM_INSTALL_FLAGS = $(NPM_FLAGS) --quiet --no-progress --ignore-engines\
--ignore-optional --ignore-platform --ignore-scripts
RACE = 0
REVISION = $${REVISION:-$$(git rev-parse --short HEAD)}
SIGN = 1
SIGNER_API_KEY = not-a-real-key
VERSION = v0.0.0
YARN = yarn
@@ -58,21 +60,29 @@ BUILD_RELEASE_DEPS_1 = go-deps
ENV = env\
CHANNEL='$(CHANNEL)'\
COMMIT='$(COMMIT)'\
DEPLOY_SCRIPT_PATH='$(DEPLOY_SCRIPT_PATH)' \
DIST_DIR='$(DIST_DIR)'\
GO="$(GO.MACRO)"\
GOAMD64="$(GOAMD64)"\
GOAMD64='$(GOAMD64)'\
GOPROXY='$(GOPROXY)'\
GOSUMDB='$(GOSUMDB)'\
GOTELEMETRY='$(GOTELEMETRY)'\
GOTOOLCHAIN='$(GOTOOLCHAIN)'\
GPG_KEY='$(GPG_KEY)'\
GPG_KEY_PASSPHRASE='$(GPG_KEY_PASSPHRASE)'\
NEXTAPI='$(NEXTAPI)'\
PATH="$${PWD}/bin:$$( "$(GO.MACRO)" env GOPATH )/bin:$${PATH}"\
RACE='$(RACE)'\
REVISION='$(REVISION)'\
SIGN='$(SIGN)'\
NEXTAPI='$(NEXTAPI)'\
SIGNER_API_KEY='$(SIGNER_API_KEY)' \
VERBOSE="$(VERBOSE.MACRO)"\
VERSION="$(VERSION)"\
# Keep the line above blank.
ENV_MISC = env\
PATH="$${PWD}/bin:$$("$(GO.MACRO)" env GOPATH)/bin:$${PATH}"\
VERBOSE="$(VERBOSE.MACRO)"\
VERSION='$(VERSION)'\
# Keep the line above blank.
@@ -80,6 +90,8 @@ ENV = env\
# full build.
build: deps quick-build
init: ; git config core.hooksPath ./scripts/hooks
quick-build: js-build go-build
deps: js-deps go-deps
@@ -93,39 +105,38 @@ build-docker: ; $(ENV) "$(SHELL)" ./scripts/make/build-docker.sh
build-release: $(BUILD_RELEASE_DEPS_$(FRONTEND_PREBUILT))
$(ENV) "$(SHELL)" ./scripts/make/build-release.sh
clean: ; $(ENV) "$(SHELL)" ./scripts/make/clean.sh
init: ; git config core.hooksPath ./scripts/hooks
js-build: ; $(NPM) $(NPM_FLAGS) run build-prod
js-deps: ; $(NPM) $(NPM_INSTALL_FLAGS) ci
js-lint: ; $(NPM) $(NPM_FLAGS) run lint
js-test: ; $(NPM) $(NPM_FLAGS) run test
go-bench: ; $(ENV) "$(SHELL)" ./scripts/make/go-bench.sh
go-build: ; $(ENV) "$(SHELL)" ./scripts/make/go-build.sh
go-deps: ; $(ENV) "$(SHELL)" ./scripts/make/go-deps.sh
go-fuzz: ; $(ENV) "$(SHELL)" ./scripts/make/go-fuzz.sh
go-lint: ; $(ENV) "$(SHELL)" ./scripts/make/go-lint.sh
go-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-tools.sh
go-bench: ; $(ENV) "$(SHELL)" ./scripts/make/go-bench.sh
go-build: ; $(ENV) "$(SHELL)" ./scripts/make/go-build.sh
go-deps: ; $(ENV) "$(SHELL)" ./scripts/make/go-deps.sh
go-env: ; $(ENV) "$(GO.MACRO)" env
go-fuzz: ; $(ENV) "$(SHELL)" ./scripts/make/go-fuzz.sh
go-lint: ; $(ENV) "$(SHELL)" ./scripts/make/go-lint.sh
# TODO(a.garipov): Think about making RACE='1' the default for all
# targets.
go-test: ; $(ENV) RACE='1' "$(SHELL)" ./scripts/make/go-test.sh
go-upd-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-upd-tools.sh
go-test: ; $(ENV) RACE='1' "$(SHELL)" ./scripts/make/go-test.sh
go-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-tools.sh
go-upd-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-upd-tools.sh
go-check: go-tools go-lint go-test
# A quick check to make sure that all supported operating systems can be
# typechecked and built successfully.
# A quick check to make sure that all operating systems relevant to the
# development of the project can be typechecked and built successfully.
go-os-check:
env GOOS='darwin' "$(GO.MACRO)" vet ./internal/...
env GOOS='freebsd' "$(GO.MACRO)" vet ./internal/...
env GOOS='openbsd' "$(GO.MACRO)" vet ./internal/...
env GOOS='linux' "$(GO.MACRO)" vet ./internal/...
env GOOS='windows' "$(GO.MACRO)" vet ./internal/...
$(ENV) GOOS='darwin' "$(GO.MACRO)" vet ./internal/...
$(ENV) GOOS='freebsd' "$(GO.MACRO)" vet ./internal/...
$(ENV) GOOS='openbsd' "$(GO.MACRO)" vet ./internal/...
$(ENV) GOOS='linux' "$(GO.MACRO)" vet ./internal/...
$(ENV) GOOS='windows' "$(GO.MACRO)" vet ./internal/...
txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh
md-lint: ; $(ENV_MISC) "$(SHELL)" ./scripts/make/md-lint.sh
sh-lint: ; $(ENV_MISC) "$(SHELL)" ./scripts/make/sh-lint.sh
openapi-lint: ; cd ./openapi/ && $(YARN) test
openapi-show: ; cd ./openapi/ && $(YARN) start
txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh

View File

@@ -114,7 +114,7 @@ If you're running **Linux,** there's a secure and easy way to install AdGuard Ho
[Docker Hub]: https://hub.docker.com/r/adguard/adguardhome
[Snap Store]: https://snapcraft.io/adguard-home
[wiki-start]: https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started
[wiki-start]: https://adguard-dns.io/kb/adguard-home/getting-started/
### <a href="#guides" id="guides" name="guides">Guides</a>
@@ -205,7 +205,7 @@ Run `make init` to prepare the development environment.
You will need this to build AdGuard Home:
- [Go](https://golang.org/dl/) v1.22 or later;
- [Go](https://golang.org/dl/) v1.23 or later;
- [Node.js](https://nodejs.org/en/download/) v18.18 or later;
- [npm](https://www.npmjs.com/) v8 or later;

View File

@@ -8,7 +8,7 @@
'variables':
'channel': 'edge'
'dockerFrontend': 'adguard/home-js-builder:2.0'
'dockerGo': 'adguard/go-builder:1.22.5--1'
'dockerGo': 'adguard/go-builder:1.23.5--1'
'stages':
- 'Build frontend':
@@ -91,6 +91,11 @@
'tasks':
- 'checkout':
'force-clean-build': true
- 'checkout':
'repository': 'bamboo-deploy-publisher'
# The paths are always relative to the working directory.
'path': 'bamboo-deploy-publisher'
'force-clean-build': true
- 'script':
'interpreter': 'SHELL'
'scripts':
@@ -99,6 +104,9 @@
set -e -f -u -x
# Explicitly checkout the revision that we need.
git checkout "${bamboo.repository.revision.number}"
# Run the build with the specified channel.
echo "${bamboo.gpgSecretKeyPart1}${bamboo.gpgSecretKeyPart2}"\
| awk '{ gsub(/\\n/, "\n"); print; }'\
@@ -107,6 +115,8 @@
make\
CHANNEL=${bamboo.channel}\
GPG_KEY_PASSPHRASE=${bamboo.gpgPassword}\
DEPLOY_SCRIPT_PATH="./bamboo-deploy-publisher/deploy.sh"\
SIGNER_API_KEY="${bamboo.adguardHomeWinSignerSecretApiKey}"\
FRONTEND_PREBUILT=1\
PARALLELISM=1\
VERBOSE=2\
@@ -132,13 +142,15 @@
# Install Qemu, create builder.
docker version -f '{{ .Server.Experimental }}'
docker buildx rm buildx-builder || :
docker buildx create --name buildx-builder --driver docker-container\
--use
docker buildx create \
--name buildx-builder \
--driver docker-container \
--use
docker buildx inspect --bootstrap
# Login to DockerHub.
docker login -u="${bamboo.dockerHubUsername}"\
-p="${bamboo.dockerHubPassword}"
docker login -u="${bamboo.dockerHubUsername}" \
-p="${bamboo.dockerHubPassword}"
# Boot the builder.
docker buildx inspect --bootstrap
@@ -147,14 +159,14 @@
docker info
# Prepare and push the build.
env\
CHANNEL="${bamboo.channel}"\
COMMIT="${bamboo.repository.revision.number}"\
DIST_DIR='dist'\
DOCKER_IMAGE_NAME='adguard/adguardhome'\
DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true"\
VERBOSE='1'\
sh ./scripts/make/build-docker.sh
env \
CHANNEL="${bamboo.channel}" \
REVISION="${bamboo.repository.revision.number}" \
DIST_DIR='dist' \
DOCKER_IMAGE_NAME='adguard/adguardhome' \
DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true" \
VERBOSE='1' \
sh ./scripts/make/build-docker.sh
'environment':
DOCKER_CLI_EXPERIMENTAL=enabled
'final-tasks':
@@ -266,7 +278,7 @@
'variables':
'channel': 'beta'
'dockerFrontend': 'adguard/home-js-builder:2.0'
'dockerGo': 'adguard/go-builder:1.22.5--1'
'dockerGo': 'adguard/go-builder:1.23.5--1'
# release-vX.Y.Z branches are the branches from which the actual final
# release is built.
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
@@ -282,4 +294,4 @@
'variables':
'channel': 'release'
'dockerFrontend': 'adguard/home-js-builder:2.0'
'dockerGo': 'adguard/go-builder:1.22.5--1'
'dockerGo': 'adguard/go-builder:1.23.5--1'

View File

@@ -6,7 +6,7 @@
'name': 'AdGuard Home - Build and run tests'
'variables':
'dockerFrontend': 'adguard/home-js-builder:2.0'
'dockerGo': 'adguard/go-builder:1.22.5--1'
'dockerGo': 'adguard/go-builder:1.23.5--1'
'channel': 'development'
'stages':
@@ -54,6 +54,7 @@
'requirements':
- 'adg-docker': 'true'
# TODO(e.burkov): Add the linting stage for markdown docs and shell scripts.
'Test backend':
'docker':
'image': '${bamboo.dockerGo}'
@@ -195,5 +196,5 @@
# may need to build a few of these.
'variables':
'dockerFrontend': 'adguard/home-js-builder:2.0'
'dockerGo': 'adguard/go-builder:1.22.5--1'
'dockerGo': 'adguard/go-builder:1.23.5--1'
'channel': 'candidate'

View File

@@ -6,18 +6,21 @@
"upstream_parallel": "استخدم الاستعلامات المتوازية لتسريع عملية الحل عن طريق الاستعلام عن جميع الخوادم المنبع في وقت واحد.",
"parallel_requests": "الطلبات الموازية",
"load_balancing": "موازنة الأحمال",
"load_balancing_desc": "الاستعلام عن خادم واحد في كل مرة سيستخدم AdGuard الرئيسية الخوارزمية العشوائية الموزونة لاختيار الخادم بحيث يتم استخدام أسرع خادم في كثير من الأحيان",
"bootstrap_dns": "خوادم Bootstrap DNS",
"bootstrap_dns_desc": "عناوين IP لخوادم DNS المستخدمة لحل عناوين IP الخاصة بمحللات DoH/DoT التي تحددها كمصدرين رئيسيين. التعليقات غير مسموح بها.",
"fallback_dns_title": "خوادم DNS الاحتياطية",
"fallback_dns_desc": "قائمة الخوادم الاحتياطية المستخدمة في حالة عدم الاستجابة من خوادم DNS الرئيسية. تمتلك تلك الخوادم والخوادم الرئيسية نفس الأوامر.",
"fallback_dns_placeholder": "أدخل خادم DNS احتياطي واحد لكل سطر",
"local_ptr_title": "خوادم DNS العكسية الخاصة",
"local_ptr_desc": "خوادم DNS التي يستخدمها AdGuard Home لاستعلامات PTR المحلية. تُستخدم هذه الخوادم لحل أسماء المضيفين للعملاء بعناوين IP خاصة ، على سبيل المثال \"192.168.12.34\" ، باستخدام DNS العكسي. في حالة عدم التعيين ، يستخدم AdGuard Home عناوين محللات DNS الافتراضية لنظام التشغيل الخاص بك باستثناء عناوين AdGuard Home نفسها.",
"local_ptr_default_resolver": "بشكل افتراضي ، يستخدم AdGuard Home محللات DNS العكسية التالية: {{ip}}.",
"local_ptr_no_default_resolver": "لم يتمكن AdGuard Home من تحديد محللات DNS العكسية المناسبة لهذا النظام.",
"local_ptr_placeholder": "أدخل عنوان IP واحد لكل سطر",
"resolve_clients_title": "تفعيل التحليل العكسي لعناوين IP للعملاء",
"resolve_clients_desc": "حل عكسيًا لعناوين IP للعملاء في أسماء مضيفيهم عن طريق إرسال استعلامات PTR إلى أدوات الحل المقابلة (خوادم DNS الخاصة للعملاء المحليين ، والخوادم الأولية للعملاء الذين لديهم عناوين IP عامة).",
"use_private_ptr_resolvers_title": "استخدم محللات DNS العكسية الخاصة",
"use_private_ptr_resolvers_desc": "قم بإجراء عمليات بحث DNS عكسية عن العناوين التي يتم تقديمها محليًا باستخدام هذه الخوادم الأولية. في حالة التعطيل ، يستجيب AdGuard Home مع NXDOMAIN لجميع طلبات PTR هذه باستثناء العملاء المعروفين من DHCP و / etc / hosts وما إلى ذلك.",
"check_dhcp_servers": "تحقق من خوادم DHCP",
"save_config": "حفظ الإعدادات",
"enabled_dhcp": "خادم DHCP مفعل",
@@ -151,6 +154,7 @@
"use_adguard_parental": "استخدام خدمة AdGuard للرقابة الأبوية على الويب",
"use_adguard_parental_hint": "سيتحقق AdGuard Home مما إذا كان النطاق يحتوي على محتوى للبالغين. إنه يستخدم نفس واجهة برمجة التطبيقات الصديقة للخصوصية مثل خدمة الويب الأمنية للتصفح.",
"enforce_safe_search": "استخدم البحث الآمن",
"enforce_save_search_hint": "سيفرض AdGuard Home البحث الآمن في محركات البحث التالية: Google وYouTube وBing وDuckDuckGo وYandex وPixabay.",
"no_servers_specified": "لم يتم تحديد خوادم",
"general_settings": "الإعدادات العامة",
"dns_settings": "إعدادات الـ DNS",
@@ -287,7 +291,7 @@
"custom_ip": "عنوان IP مخصص",
"blocking_ipv4": "حجب عنوان IPv4",
"blocking_ipv6": "حجب عنوان IPv6",
"blocked_response_ttl": "زمن حظر الاستجابة",
"blocked_response_ttl": "حظر استجابة TTL",
"blocked_response_ttl_desc": "تحديد عدد الثواني التي يجب على العملاء تخزين الاستجابة التي تمت تصفيتها مؤقتًا",
"form_enter_blocked_response_ttl": "أدخل وقت الاستجابة المحظورة TTL (بالثواني)",
"dnscrypt": "DNSCrypt",
@@ -730,10 +734,10 @@
"thursday": "الخميس",
"friday": "الجمعة",
"saturday": "السبت",
"sunday_short": "الاحد",
"sunday_short": "الأحد",
"monday_short": "الإثنين",
"tuesday_short": "الثلاثاء",
"wednesday_short": "الاربعاء",
"wednesday_short": "الأربعاء",
"thursday_short": "الخميس",
"friday_short": "الجمعة",
"saturday_short": "السبت",

View File

@@ -6,18 +6,21 @@
"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-серверы не адказваюць. Сінтаксіс такі ж, як і ў галоўным полі ўверх.",
"fallback_dns_placeholder": "Увядзіце па адным рэзервовым серверы 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-адрасам).",
"use_private_ptr_resolvers_title": "Ужываць прыватныя адваротныя DNS-рэзолверы",
"use_private_ptr_resolvers_desc": "Пасылаць адваротныя DNS-запыты для лакальна абслугоўных адрасоў на паказаныя серверы. Калі адключана, AdGuard Home будзе адказваць NXDOMAIN на ўсе падобныя PTR-запыты, апроч запытаў пра кліентаў, ужо вядомых па DHCP, /etc/hosts і гэтак далей.",
"check_dhcp_servers": "Праверыць DHCP-серверы",
"save_config": "Захаваць канфігурацыю",
"enabled_dhcp": "DHCP-сервер улучаны",
@@ -151,6 +154,7 @@
"use_adguard_parental": "Ужывайце модуль Бацькоўскага кантролю AdGuard ",
"use_adguard_parental_hint": "AdGuard Home праверыць, ці ўтрымвае дамен матэрыялы 18+. Ён выкарыстоўвае той жа API для забеспячэння прыватнасці, што і ўэб-служба бяспекі браўзара.",
"enforce_safe_search": "Узмацніць бяспечны пошук",
"enforce_save_search_hint": "AdGuard Home можа забяспечыць бяспечны пошук у наступных пошукавых сістэмах: Google, Youtube, Bing, DuckDuckGo, Yandex і Pixabay.",
"no_servers_specified": "Не паказаных сервераў",
"general_settings": "Асноўныя налады",
"dns_settings": "Налады DNS",
@@ -671,6 +675,7 @@
"use_saved_key": "Скарыстаць захаваны раней ключ",
"parental_control": "Бацькоўскі кантроль",
"safe_browsing": "Бяспечны інтэрнэт",
"served_from_cache": "{{value}} <i>(атрымана з кэша)</i>",
"form_error_password_length": "Пароль павінен утрымліваць ад {{min}} да {{max}} сімвалаў",
"anonymizer_notification": "<0>Заўвага:</0> Ананімізацыя IP уключана. Вы можаце адключыць яе ў <1>Агульных наладах</1>.",
"confirm_dns_cache_clear": "Вы ўпэўнены, што хочаце ачысціць кэш DNS?",

View File

@@ -65,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": "Сума на блокирани сайтове за възрастни",
@@ -85,6 +87,7 @@
"use_adguard_parental": "Включи AdGuard Родителски Надзор",
"use_adguard_parental_hint": "Модул XXX в AdGuard Home ще провери дали страницата има материали за възвъстни. Използва се същия API за анонимност като при модула за Сигурност.",
"enforce_safe_search": "Включи Безопасно Търсене",
"enforce_save_search_hint": "AdGuard Home прилага Безопасно Търсене в следните търсачки и сайтове: Google, Youtube, Bing, и Yandex.",
"no_servers_specified": "Няма избрани услуги",
"general_settings": "Общи настройки",
"custom_filtering_rules": "Местни правила за филтриране",
@@ -156,6 +159,8 @@
"dns_over_https": "DNS-пред-HTTPS",
"dns_over_quic": "DNS-over-QUIC",
"plain_dns": "Обикновен DNS",
"theme_light": "Светла тема",
"theme_dark": "Тъмна тема",
"source_label": "Източник",
"found_in_known_domain_db": "Намерен в списъците с домейни.",
"category_label": "Категория",
@@ -206,6 +211,7 @@
"install_devices_android_list_5": "Променете стойностите на DNS 1 и DNS 2 да използват AdGuard Home сървъра.",
"install_devices_ios_list_1": "От начален екран, цъкнете на Settings.",
"install_devices_ios_list_2": "Изберете Wi-Fi от лявото меню (там няма възможност за въвеждане на DNS настройки).",
"install_devices_ios_list_3": "Клинете на името на активната мрежа към която сте свързани.",
"install_devices_ios_list_4": "В полето за DNS изберете ръчно и въведете адреса на AdGuard Home сървъра.",
"get_started": "Да започваме",
"next": "Следващ",
@@ -216,6 +222,7 @@
"encryption_config_saved": "Конфигурацията е успешно записана",
"encryption_server": "Име на сървъра",
"encryption_server_enter": "Въведете име на домейна",
"encryption_server_desc": "За да използвате HTTPS, трябва името на сървъра да съвпада с това на SSL сертификата.",
"encryption_redirect": "Автоматично пренасочване към HTTPS",
"encryption_redirect_desc": "Служи за автоматично пренасочване от HTTP към HTTPS на страницата за Администрация в AdGuard Home.",
"encryption_https": "HTTPS порт",
@@ -278,5 +285,12 @@
"filter_category_general": "General",
"filter_category_security": "Сигурност",
"port_53_faq_link": "Порт 53 често е зает от \"DNSStubListener\" или \"systemd-resolved\" услуги. Моля, прочетете <0>тази инструкция</0> как да решите това.",
"parental_control": "Родителски контрол"
"parental_control": "Родителски контрол",
"sunday_short": "Нд",
"monday_short": "Пон",
"tuesday_short": "Вт",
"wednesday_short": "Ср",
"thursday_short": "Чт",
"friday_short": "Пт",
"saturday_short": "Съб"
}

View File

@@ -641,7 +641,7 @@
"show_processed_responses": "Verarbeitet",
"blocked_safebrowsing": "Gesperrt durch Internetsicherheit",
"blocked_adult_websites": "Gesperrt durch Kindersicherung",
"blocked_threats": "Bedrohungen blockiert",
"blocked_threats": "Gesperrte Bedrohungen",
"allowed": "Zugelassen",
"filtered": "Gefiltert",
"rewritten": "Umgeschrieben",

View File

@@ -5,17 +5,21 @@
"upstream_parallel": "استفاده از جستار موازی برای سرعت دادن به تفکیک با جستار همزمان همه جریان های ارسالی",
"parallel_requests": "درخواست های موازی",
"load_balancing": "متعادل کننده بار",
"load_balancing_desc": "یک سرور بالادستی را در یک زمان پرس و جو کنید. AdGuard Home از الگوریتم تصادفی وزنی خود برای انتخاب سرور استفاده می کند تا سریع ترین سرور بیشتر مورد استفاده قرار گیرد.",
"bootstrap_dns": "خودراه انداز سرورهای DNS",
"bootstrap_dns_desc": "آدرس‌های IP سرورهای DNS که برای حل کردن آدرس‌های IP حل‌کننده‌های DoH/DoT که به‌عنوان upstream مشخص می‌کنید، استفاده می‌شوند. اظهار نظر مجاز نیست.",
"fallback_dns_title": "سرورهای DNS بازگشتی",
"fallback_dns_desc": "لیست سرورهای DNS بازگشتی که در زمانی که سرورهای DNS بالادستی پاسخ نمی‌دهند استفاده می‌شوند. نحو مانند فیلد بالادستی اصلی بالا است.",
"fallback_dns_placeholder": "یک سرور DNS بازگشتی در هر خط وارد کنید",
"local_ptr_title": "سرورهای خصوصی DNS",
"local_ptr_desc": "سرور یا سرور های DNS ای که AdGuard Home برای درخواست های منابع محلی ارائه شده مورد استفاده قرار خواهد داد. برای مثال، این سرور برای تعیین نام های سرویس دهنده برای سرویس گیرنده با آدرس های آی پی خصوصی مورد استفاده قرار خواهد گرفت. اگر تعیین نشود،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 برای سرویس گیرندگان محلی،سرور مادر برای سرویس گیرندگان با آی پی عمومی).",
"use_private_ptr_resolvers_title": "از تعیین کننده های rDNS محرمانه استفاده کنید",
"use_private_ptr_resolvers_desc": "داده گیری های دی ان اس معکوس را برای آدرس های اینترنتی خدمات منظقه ای با استفاده از سرور های مادر اجرا کنید. چنانچه غیر فعال باشد،AdGuard Home با NXDOMAIN به همه چنین درخواست های PTR پاسخ می دهد به استثناء خدمات گیرنده های شناخته شده از طرف DHCP،/و غیره/هوست ها، و سایر.",
"check_dhcp_servers": "بررسی برای سرورهای DHCP",
"save_config": "ذخیره پیکربندی",
"enabled_dhcp": "سرور DHCP فعال شده است",
@@ -113,6 +117,7 @@
"stats_malware_phishing": "بدافزار/فیشینگ مسدود شده است",
"stats_adult": "وبسایت غیراخلاقی مسدود شده است",
"stats_query_domain": "دامنه جستار بالا",
"for_last_24_hours": "برای 24 ساعت گذشته",
"for_last_days": "برای {{count}} روز آخر",
"for_last_days_plural": "برای {{count}} روز گذشته",
"stats_disabled": "آمار غیرفعال شده است. شما می توانید از قسمت <0>صفحه تنظیمات</0> آن را روشن نمایید.",
@@ -127,6 +132,7 @@
"no_upstreams_data_found": "هیچ اطلاعاتی در مورد سرورهای بالادست یافت نشد",
"number_of_dns_query_days": "تعداد جستار DNS پردازش شده در {{count}} روز آخر",
"number_of_dns_query_days_plural": "تعداد جستار DNS پردازش شده در {{count}} روز گذشته",
"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": "تعداد وبسایت های غیر اخلاقی مسدود شده",
@@ -141,6 +147,7 @@
"use_adguard_parental": "از سرویس وب نظارت والدین AdGuard استفاده کن",
"use_adguard_parental_hint": "AdGuard Home بررسی می کند اگر دامنه حاوی موارد غیر اخلاقی است.آن از همان اِی پی آی دارای حریم خصوصی سرویس وب امنیت وب گردی استفاده می کند.",
"enforce_safe_search": "اجبار جستجوی اَمن",
"enforce_save_search_hint": "AdGuard Home میتواند جستجوی اَمن را در موتور جستجوهای زیر اعمال کند:گوگل،یوتوب،بینگ و یاندکس",
"no_servers_specified": "سروری تعیین نشده است",
"general_settings": "تنظیمات عمومی",
"dns_settings": "تنظیمات DNS",
@@ -423,6 +430,7 @@
"client_confirm_delete": "آیا واقعا میخواهید \"{{key}}\" کلاینت را حذف کنید؟",
"list_confirm_delete": "آیا واقعا میخواهید این لیست را حذف کنید؟",
"auto_clients_title": "کلاینت ها (زمان اِجرا)",
"auto_clients_desc": "داده در کلاینت ها که از AdGuard Home استفاده می کند،اما در پیکربندی ذخیره نمی شود",
"access_title": "تنظیمات دسترسی",
"access_desc": "در اینجا میتوانید دستورات دسترسی را برای DNS سرور AdGuard Home وارد کنید.",
"access_allowed_title": "کلاینت های مجاز",
@@ -586,6 +594,7 @@
"use_saved_key": "از کلید ذخیره شده قبلی استفاده کنید",
"parental_control": "نظارت والدین",
"safe_browsing": "وب گردی اَمن",
"form_error_password_length": "رمزعبور باید حداقل {{value}} کاراکتر باشد.",
"protection_section_label": "حفاظت",
"log_and_stats_section_label": "گزارش پرس و جو و آمار",
"ignore_query_log": "این مشتری را در گزارش پرس و جو نادیده بگیرید",

View File

@@ -6,6 +6,7 @@
"upstream_parallel": "Käytä rinnakkaisia pyyntöjä ja nopeuta selvitystä käyttämällä kaikkia ylävirtapalvelimia samanaikaisesti.",
"parallel_requests": "Rinnakkaiset pyynnöt",
"load_balancing": "Kuormantasaus",
"load_balancing_desc": "Lähetä kysely kerrallaan yhdelle ylävirtapalvelimelle. AdGuard Home valitsee painotetun satunnaisalgoritmin avulla palvelimet, joilla on vähiten epäonnistuneita hakuja ja keskimääräisesti lyhin hakuaika.",
"bootstrap_dns": "Bootstrap DNS-palvelimet",
"bootstrap_dns_desc": "Ylävirroiksi määrittämiesi DoH/DoT-resolverien IP-osoitteiden selvitykseen käytettävien DNS-palvelimien IP-osoitteet. Kommentteja ei sallita.",
"fallback_dns_title": "DNS-varapalvelimet",
@@ -153,6 +154,7 @@
"use_adguard_parental": "Käytä AdGuardin lapsilukko-palvelua",
"use_adguard_parental_hint": "AdGuard Home tarkistaa, sisältääkö verkkotunnus aikuisille tarkoitettua sisältöä. Se käyttää samaa tietosuojapainotteista rajapintaa, kuin turvallisen selauksen palvelu.",
"enforce_safe_search": "Käytä turvallista hakua",
"enforce_save_search_hint": "AdGuard Home pakottaa turvallisen haun käyttöön seuraavissa hakukoneissa: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex ja Pixabay.",
"no_servers_specified": "Palvelimia ei ole määritetty",
"general_settings": "Yleiset asetukset",
"dns_settings": "DNS-asetukset",
@@ -540,7 +542,7 @@
"stats_params": "Tilastoinnin määritys",
"config_successfully_saved": "Asetukset tallennettiin",
"interval_6_hour": "6 tuntia",
"interval_24_hour": "24 tuntia",
"interval_24_hour": "24 tunnilta",
"interval_days": "{{count}} päivä",
"interval_days_plural": "{{count}} päivää",
"domain": "Verkkotunnus",

View File

@@ -6,6 +6,7 @@
"upstream_parallel": "Koristi paralelne upite kako bi ubrzali rješavanje istovremenim ispitavanjem svih upstream poslužitelja.",
"parallel_requests": "Paralelni zahtjevi",
"load_balancing": "Load-balancing",
"load_balancing_desc": "Pitajte jedan po jedan uzvodni poslužitelj. AdGuard Home koristi svoj ponderirani slučajni algoritam za odabir poslužitelja tako da se najbrži poslužitelj koristi češće.",
"bootstrap_dns": "Bootstrap DNS poslužitelji",
"bootstrap_dns_desc": "IP adrese DNS poslužitelja koji se koriste za rješavanje IP adresa DoH/DoT razrjeđivača koje navedete kao uzvodne. Komentari nisu dopušteni.",
"fallback_dns_title": "Rezervni DNS poslužitelji",
@@ -153,6 +154,7 @@
"use_adguard_parental": "Koristi web uslugu AdGuard roditeljske zaštite",
"use_adguard_parental_hint": "AdGuard Home provjeriti će sadrži li domena sadržaj za odrasle. Koristi isti API za zaštitu privatnosti kao i naša usluga zaštite pregledavanja.",
"enforce_safe_search": "Koristi sigurno pretraživanje",
"enforce_save_search_hint": "AdGuard Home provodit će sigurno pretraživanje u sljedećim tražilicama: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
"no_servers_specified": "Nije odabran nijedan poslužitelj",
"general_settings": "Opće postavke",
"dns_settings": "DNS postavke",

View File

@@ -6,18 +6,21 @@
"upstream_parallel": "Használjon párhuzamos lekéréseket a domainek feloldásának felgyorsításához az összes upstream kiszolgálóra való egyidejű lekérdezéssel.",
"parallel_requests": "Párhuzamos lekérések",
"load_balancing": "Terheléselosztás",
"load_balancing_desc": "Egyszerre csak egy szerverről történjen lekérdezés. Az AdGuard Home egy súlyozott, véletlenszerű algoritmust fog használni a megfelelő szerver kiválasztására, így a leggyorsabb szervert fogja a leggyakrabban használni.",
"bootstrap_dns": "Bootstrap DNS kiszolgálók",
"bootstrap_dns_desc": "A DNS-kiszolgálók IP-címei, amelyek a DoH/DoT-feloldók IP-címeinek feloldására szolgálnak, amelyeket upstreamként megadott. Megjegyzések nem megengedettek.",
"fallback_dns_title": "Tartalék DNS-szerverek",
"fallback_dns_desc": "Azoknak a tartalék DNS-szervereknek a listája, amelyeket akkor használnak, ha a felsőbbrendű DNS-szerverek nem válaszolnak. A szintaxis ugyanaz, mint a fő felsőbbrendű mezőben.",
"fallback_dns_placeholder": "Adjon meg egy alternatív DNS szervert soronként",
"local_ptr_title": "Privát DNS szerverek",
"local_ptr_desc": "Azok a DNS szerverek, amiket az AdGuard Home a helyi PTR kérésekhez használ. ",
"local_ptr_default_resolver": "Alapesetben az AdGuard Home a következő reverse DNS feloldókat használja: {{ip}}.",
"local_ptr_no_default_resolver": "Az AdGuard Home nem tudta meghatározni a privát reverse DNS feloldókat ehhez a rendszerhez.",
"local_ptr_placeholder": "Adjon meg egy IP-címet soronként",
"resolve_clients_title": "Kliensek IP címeinek fordított feloldása",
"resolve_clients_desc": "Fordítva oldja fel a kliensek IP címeit a hosztneveikre azáltal, hogy PTR lekérdezéseket küld a megfelelő feloldóknak (privát DNS szerverek a helyi kliensek számára, upstream szerverek a nyilvános IP címmel rendelkező kliensek számára).",
"use_private_ptr_resolvers_title": "Privát reverse DNS feloldók használata",
"use_private_ptr_resolvers_desc": "Reverse DNS keresések végzése a helyileg kiszolgált címekre ezeknek a szervereknek a használatával. Ha le van tiltva, az AdGuard Home az NXDOMAIN használatával válaszol minden ilyen PTR kérésre, kivéve azokat a klienseket, amelyeket már ismer a DHCP, /etc/hosts, stb. által.",
"check_dhcp_servers": "DHCP szerverek keresése",
"save_config": "Konfiguráció mentése",
"enabled_dhcp": "DHCP szerver engedélyezve",
@@ -151,6 +154,7 @@
"use_adguard_parental": "Használja az AdGuard szülői felügyelet webszolgáltatását",
"use_adguard_parental_hint": "Az AdGuard Home ellenőrzi, hogy a domain tartalmaz-e felnőtteknek szóló anyagokat. Ugyanazokat az adatvédelmi API-kat használja, mint a böngésző biztonsági webszolgáltatás.",
"enforce_safe_search": "Biztonságos keresés használata",
"enforce_save_search_hint": "Az AdGuard Home a következő keresőmotorokban biztosíthatja a biztonságos keresést: Google, Youtube, Bing, DuckDuckGo, Yandex és Pixabay.",
"no_servers_specified": "Nincsenek megadott kiszolgálók",
"general_settings": "Általános beállítások",
"dns_settings": "DNS beállítások",
@@ -671,6 +675,7 @@
"use_saved_key": "Előzőleg mentett kulcs használata",
"parental_control": "Szülői felügyelet",
"safe_browsing": "Biztonságos böngészés",
"served_from_cache": "{{value}} <i>(gyorsítótárból kiszolgálva)</i>",
"form_error_password_length": "A jelszó legyen {{min}} és {{max}} karakter között",
"anonymizer_notification": "<0>Megjegyzés:</0> Az IP anonimizálás engedélyezve van. Az <1>Általános beállításoknál letilthatja</1> .",
"confirm_dns_cache_clear": "Biztos benne, hogy törölni szeretné a DNS-gyorsítótárat?",

View File

@@ -6,18 +6,21 @@
"upstream_parallel": "Gunakan kueri paralel untuk mempercepat resoluasi dengan menanyakan semua server upstream secara bersamaan",
"parallel_requests": "Permintaan paralel",
"load_balancing": "Penyeimbang beban",
"load_balancing_desc": "Permintaan satu server pada satu waktu. AdGuard Home akan menggunakan algoritma acak tertimbang untuk memilih server sehingga server tercepat akan lebih sering digunakan.",
"bootstrap_dns": "Server DNS bootstrap",
"bootstrap_dns_desc": "Alamat IP server DNS yang digunakan untuk menyelesaikan alamat IP resolver DoH/DoT yang Anda tentukan sebagai upstream. Komentar tidak diizinkan.",
"fallback_dns_title": "Server DNS cadangan",
"fallback_dns_desc": "Daftar server DNS cadangan yang digunakan ketika server hulu DNS tidak merespons. Sintaksnya sama dengan kolom hulu utama di atas.",
"fallback_dns_placeholder": "Masukkan satu server DNS cadangan per baris",
"local_ptr_title": "Server pembalik DNS pribadi",
"local_ptr_desc": "Server DNS yang digunakan AdGuard Home untuk kueri PTR lokal. Server ini digunakan untuk menyelesaikan nama host klien dengan alamat IP pribadi, misalnya \"192.168.12.34\", menggunakan DNS terbalik. Jika tidak disetel, AdGuard Home menggunakan alamat resolver DNS default OS Anda kecuali untuk alamat AdGuard Home itu sendiri.",
"local_ptr_default_resolver": "Secara bawaan, AdGuard Home menggunakan pemecah DNS terbalik: {{ip}}.",
"local_ptr_no_default_resolver": "AdGuard Home tidak dapat menentukan pemecah DNS terbalik yang sesuai untuk sistem ini.",
"local_ptr_placeholder": "Masukkan satu alamat IP per baris",
"resolve_clients_title": "Aktifkan resolusi hostname klien",
"resolve_clients_desc": "Menyelesaikan alamat IP klien secara terbalik ke nama host mereka dengan mengirimkan kueri PTR ke resolver yang sesuai (server DNS pribadi untuk klien lokal, server upstream untuk klien dengan alamat IP publik).",
"use_private_ptr_resolvers_title": "Gunakan server pembalik DNS pribadi",
"use_private_ptr_resolvers_desc": "Lakukan pencarian DNS terbalik untuk alamat yang disajikan secara lokal menggunakan server hulu ini. Jika dinonaktifkan, Adguard Home merespons dengan NXDOMAIN untuk semua permintaan PTR tersebut kecuali untuk klien yang diketahui dari DHCP, /etc/hosts, dan seterusnya.",
"check_dhcp_servers": "Cek untuk server DHCP",
"save_config": "Simpan pengaturan",
"enabled_dhcp": "Server DHCP diaktifkan",
@@ -69,11 +72,13 @@
"dhcp_error": "AdGuard Home tidak dapat menentukan apakah ada server DHCP aktif lain pada jaringan",
"dhcp_static_ip_error": "Jika ingin menggunakan server DHCP, alamat IP statis harus diatur. AdGuard Home gagal menentukan jika antarmuka jaringan ini dikonfigurasi menggunakan alamat IP statis. Silakan atur alamat IP statis secara manual.",
"dhcp_dynamic_ip_found": "Sistem Anda menggunakan konfigurasi alamat IP dinamis untuk antarmuka <0>{{interfaceName}}</0>. Untuk menggunakan server DHCP, alamat IP statis harus ditetapkan. Alamat IP Anda saat ini adalah <0>{{ipAddress}}</0>. AdGuard Home akan secara otomatis menetapkan alamat IP ini sebagai statis jika Anda menekan tombol Aktifkan DHCP.",
"dhcp_lease_added": "Static lease \"{{key}}\" berhasil ditambahkan",
"dhcp_lease_deleted": "Static lease \"{{key}}\" berhasil dihapus",
"dhcp_lease_updated": "Static lease \"{{key}}\" berhasil diperbarui",
"dhcp_new_static_lease": "Static lease baru",
"dhcp_edit_static_lease": "Mengedit static lease",
"dhcp_static_leases_not_found": "DHCP static lease tidak ditemukan",
"dhcp_add_static_lease": "Tambah static lease",
"dhcp_reset_leases": "Atur ulang semua kontrak",
"dhcp_reset_leases_confirm": "Apakah Anda yakin ingin mengatur ulang kontrak Anda?",
"dhcp_reset_leases_success": "Kontrak DHCP berhasil diatur ulang",
@@ -149,6 +154,7 @@
"use_adguard_parental": "Gunakan layanan web kontrol orang tua AdGuard",
"use_adguard_parental_hint": "AdGuard Home akan mengecek jika domain mengandung materi dewasa. Akan menggunakan API yang ramah privasi yang sama sebagai layanan web keamanan penjelajahan.",
"enforce_safe_search": "Pakai pencarian aman",
"enforce_save_search_hint": "AdGuard Home dapat memaksa penelusuran aman pada mesin pencari berikut: Google, Youtube, Bing, DuckDuckGo, Yandex, dan Pixabay.",
"no_servers_specified": "Sever tidak disebutkan",
"general_settings": "Pengaturan umum",
"dns_settings": "Pengaturan DNS",
@@ -672,6 +678,7 @@
"use_saved_key": "Gunakan kunci yang disimpan sebelumnya",
"parental_control": "Pengawasan Orang Tua",
"safe_browsing": "Penjelajahan Aman",
"served_from_cache": "{{value}} <i>(disajikan dari cache)</i>",
"form_error_password_length": "Kata sandi harus terdiri dari {{min}} hingga {{max}}",
"anonymizer_notification": "<0>Catatan:</0> Anonimisasi IP diaktifkan. Anda dapat menonaktifkannya di <1>Pengaturan umum</1> .",
"confirm_dns_cache_clear": "Apakah Anda yakin ingin menghapus cache DNS?",

View File

@@ -166,7 +166,7 @@
"encryption_settings": "Encryptie instellingen",
"dhcp_settings": "DHCP instellingen",
"upstream_dns": "Upstream DNS-servers",
"upstream_dns_help": "Een server-adres per regel invoeren. <a>Meer weten</a> over het configureren van upstream DNS-servers.",
"upstream_dns_help": "Een server-adres per regel invoeren. <a>Meer informatie</a> over het configureren van upstream DNS-servers.",
"upstream_dns_configured_in_file": "Geconfigureerd in {{path}}",
"test_upstream_btn": "Test upstream",
"upstreams": "Upstreams",
@@ -676,7 +676,7 @@
"filter_allowlist": "WAARSCHUWING: Deze actie zal ook de regel \"{{disallowed_rule}}\" uitsluiten van de lijst met toegestane clients.",
"last_rule_in_allowlist": "Kan deze client niet weigeren omdat het uitsluiten van de regel \"{{disallowed_rule}}\" de lijst \"Toegestane clients\" zal UITSCHAKELEN.",
"use_saved_key": "De eerder opgeslagen sleutel gebruiken",
"parental_control": "Ouderlijk Toezicht ",
"parental_control": "Ouderlijk toezicht",
"safe_browsing": "Veilig browsen",
"served_from_cache_label": "Geleverd vanuit cache",
"form_error_password_length": "Wachtwoord moet {{min}} tot {{max}} tekens lang zijn",

View File

@@ -5,14 +5,17 @@
"upstream_parallel": "Bruk parallele forespørsler for å få oppfarten på behandlinger, ved å forespørre til alle oppstrømstjenerne samtidig",
"parallel_requests": "Parallelle forespørsler",
"load_balancing": "Pågangstrykk-utjevning",
"load_balancing_desc": "Forespør én tjener om gangen. AdGuard Home vil bruke en 'vektlagt tilfeldig valg'-algoritme for å velge tjener, slik at den raskeste tjeneren blir brukt oftere.",
"bootstrap_dns": "Bootstrap-DNS-tjenere",
"bootstrap_dns_desc": "IP-adresser til DNS-servere som brukes til å løse IP-adresser til DoH/DoT-løsere du spesifiserer som oppstrøms. Kommentarer er ikke tillatt.",
"fallback_dns_title": "Reserve DNS-servere",
"fallback_dns_desc": "Liste over reserve-DNS-servere som brukes når oppstrøms DNS-servere ikke svarer. Syntaksen er den samme som i hovedoppstrømsfeltet ovenfor.",
"fallback_dns_placeholder": "Angi én reserve-DNS-server per linje",
"local_ptr_title": "Private DNS-tjenere",
"local_ptr_desc": "DNS-tjenerne som AdGuard Home bruker for lokale PTR-spørringer. Disse tjenerne brukes til å løse vertsnavnene til klienter med private IP-adresser, for eksempel \"192.168.12.34\", ved bruk av omvendt DNS. Hvis det ikke er angitt, bruker AdGuard Home adressene til standard-DNS-løserne til operativsystemet ditt, bortsett fra adressene til selve AdGuard Home.",
"local_ptr_default_resolver": "Som standard, bruker AdGuard Home følgende revers-DNS-oppletere: {{ip}}.",
"local_ptr_no_default_resolver": "AdGuard Home klarte ikke å finne egnede private revers-DNS-oppletere for dette systemet.",
"local_ptr_placeholder": "Skriv inn én tjeneradresse per linje",
"resolve_clients_title": "Skru på revers-oppleting av klienters IP-adresser",
"use_private_ptr_resolvers_title": "Bruk private omvendte DNS-løsere",
"check_dhcp_servers": "Se etter DHCP-tjenere",
@@ -103,6 +106,7 @@
"stats_malware_phishing": "Blokkert skadevare/phishing",
"stats_adult": "Blokkerte voksennettsteder",
"stats_query_domain": "Mest forespurte domener",
"for_last_24_hours": "de siste 24 timene",
"for_last_days": "for den siste {{count}} dagen",
"for_last_days_plural": "de siste {{count}} dagene",
"stats_disabled": "Statistikkene har blitt skrudd av. Du kan skru den på fra <0>innstillingssiden</0>.",
@@ -117,6 +121,7 @@
"no_upstreams_data_found": "Ingen oppstrøms servere data funnet",
"number_of_dns_query_days": "Antall DNS-spørringer behandlet for de siste {{count}} dagene",
"number_of_dns_query_days_plural": "Antall DNS-forespørsler som ble behandlet de siste {{count}} dagene",
"number_of_dns_query_24_hours": "Antall DNS-forespørsler som ble behandlet de siste 24 timene",
"number_of_dns_query_blocked_24_hours": "Antall DNS-forespørsler som ble blokkert av adblock-filtre, hosts-lister, og domene-lister",
"number_of_dns_query_blocked_24_hours_by_sec": "Antall DNS-forespørsler som ble blokkert av AdGuard sin nettlesersikkerhetsmodul",
"number_of_dns_query_blocked_24_hours_adult": "Antall voksennettsteder som ble blokkert",
@@ -132,6 +137,7 @@
"use_adguard_parental": "Benytt AdGuard sin foreldrekontroll-nettjeneste",
"use_adguard_parental_hint": "AdGuard Home vil sjekke om domenet inneholder erotisk materiale. Den benytter den samme privatlivsvennlige API-en som nettlesersikkerhetstjenesten.",
"enforce_safe_search": "Påtving barnevennlige søk",
"enforce_save_search_hint": "AdGuard Home kan fremtvinge \"Safe Search\" i de følgende søkemotorene: Google, YouTube, Bing, DuckDuckGo, Yandex, og Pixabay.",
"no_servers_specified": "Ingen tjenere er spesifisert",
"general_settings": "Generelle innstillinger",
"dns_settings": "DNS-innstillinger",
@@ -621,6 +627,7 @@
"use_saved_key": "Bruk den tidligere lagrede nøkkelen",
"parental_control": "Foreldrekontroll",
"safe_browsing": "Sikker surfing",
"served_from_cache": "{{value}} <i>(formidlet fra mellomlageret)</i>",
"theme_dark_desc": "Mørkt tema",
"theme_light_desc": "Lyst tema",
"disable_notify_until_tomorrow": "Deaktiver beskyttelsen til i morgen",

View File

@@ -6,6 +6,7 @@
"upstream_parallel": "Użyj zapytań równoległych, aby przyspieszyć rozwiązywanie przez jednoczesne wysyłanie zapytań do wszystkich serwerów nadrzędnych.",
"parallel_requests": "Równoległe żądania",
"load_balancing": "Równoważenie obciążenia",
"load_balancing_desc": "Zapytaj jeden serwer nadrzędny na raz. AdGuard Home używa ważonego, losowego algorytmu do wybierania serwerów z najmniejszą liczbą nieudanych wyszukiwań i najniższym uśrednionym czasem wyszukiwania.",
"bootstrap_dns": "Serwery DNS Bootstrap",
"bootstrap_dns_desc": "Adresy IP serwerów DNS używanych do rozpoznawania adresów IP programów rozpoznawania nazw DoH/DoT określonych jako nadrzędne. Komentarze są niedozwolone.",
"fallback_dns_title": "Rezerwowe serwery DNS",
@@ -121,7 +122,7 @@
"stats_query_domain": "Najczęściej wyszukiwane domeny",
"for_last_hours": "w ciągu ostatniej {{count}} godziny",
"for_last_hours_plural": "w ciągu ostatnich {{count}} godzin",
"for_last_days": "za ostatni dzień {{count}}",
"for_last_days": "za ostatni {{count}} dzień",
"for_last_days_plural": "z ostatnich {{count}} dni",
"stats_disabled": "Statystyki zostały wyłączone. Można je włączyć na <0>stronie ustawień</0>.",
"stats_disabled_short": "Statystyki zostały wyłączone",
@@ -129,7 +130,7 @@
"requests_count": "Licznik żądań",
"top_blocked_domains": "Najpopularniejsze zablokowane domeny",
"top_clients": "Główni klienci",
"no_clients_found": "Nie znaleziono klienta",
"no_clients_found": "Nie znaleziono klientów",
"general_statistics": "Ogólne statystyki",
"top_upstreams": "Często żądane serwery nadrzędne",
"no_upstreams_data_found": "Brak danych dotyczących serwerów nadrzędnych",
@@ -153,6 +154,7 @@
"use_adguard_parental": "Użyj usługi Kontrola Rodzicielska AdGuard",
"use_adguard_parental_hint": "AdGuard Home sprawdzi, czy domena zawiera materiały dla dorosłych. Używa tego samego interfejsu API przyjaznego prywatności, co usługa sieciowa Bezpieczne Przeglądanie. ",
"enforce_safe_search": "Użyj bezpiecznego wyszukiwania",
"enforce_save_search_hint": "AdGuard Home wymusza bezpieczne wyszukiwanie w następujących wyszukiwarkach: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
"no_servers_specified": "Nie określono serwerów",
"general_settings": "Ustawienia główne",
"dns_settings": "Ustawienia DNS",

View File

@@ -6,18 +6,21 @@
"upstream_parallel": "Folosiți interogări paralele pentru a accelera rezolvarea, interogând simultan toate serverele în amonte.",
"parallel_requests": "Solicitări paralele",
"load_balancing": "Echilibrare-sarcini",
"load_balancing_desc": "Interoghează câte un server în amonte la un moment dat. AdGuard Home utilizează un algoritm de randomizare ponderat pentru a alege serverul, astfel încât cel mai rapid server să fie utilizat mai des.",
"bootstrap_dns": "Serverele DNS Bootstrap",
"bootstrap_dns_desc": "Adresele IP ale serverelor DNS utilizate pentru a rezolva adresele IP ale soluțiilor DoH/DoT pe care le specificați ca fiind în amonte. Comentariile nu sunt permise.",
"fallback_dns_title": "Servere DNS de rezervă",
"fallback_dns_desc": "Lista serverelor DNS de rezervă utilizate atunci când serverele DNS din amonte nu răspund. Sintaxa este aceeași ca în câmpul principal din amonte de mai sus.",
"fallback_dns_placeholder": "Introduceți un server DNS de rezervă pe linie",
"local_ptr_title": "Servere DNS inverse private",
"local_ptr_desc": "Serverele DNS pe care AdGuard Home le utilizează pentru interogările PTR locale. Aceste servere sunt utilizate pentru a rezolva solicitările PTR pentru adrese din intervale IP private, de exemplu „192.168.12.34”, utilizând DNS invers. Dacă nu este configurat, AdGuard Home utilizează adresele rezolvatorilor DNS impliciți ai sistemului dvs. de operare, cu excepția adreselor AdGuard Home în sine.",
"local_ptr_default_resolver": "În mod implicit, AdGuard Home utilizează următorii rezolvatori DNS inverși: {{ip}}.",
"local_ptr_no_default_resolver": "AdGuard Home nu a putut determina rezolvatorii DNS privați adecvați pentru acest sistem.",
"local_ptr_placeholder": "Introduceți o adresă IP per linie",
"resolve_clients_title": "Permiteți rezolvarea inversa a adreselor IP ale clienților",
"resolve_clients_desc": "Rezolvă invers adresele IP ale clienților în numele lor de gazde prin trimiterea interogărilor PTR la rezolvatorii corespunzători (servere DNS private pentru clienți locali, servere în amonte pentru clienți cu adrese IP publice).",
"use_private_ptr_resolvers_title": "Utilizați rezolvatori DNS inverși privați",
"use_private_ptr_resolvers_desc": "Efectuează examinări DNS inverse pentru adresele deservite local folosind aceste servere în amonte. Dacă este dezactivată, AdGuard Home răspunde cu NXDOMAIN la toate aceste cereri PTR, cu excepția clienților cunoscuți din DHCP, /etc/hosts și așa mai departe.",
"check_dhcp_servers": "Căutați servere DHCP",
"save_config": "Salvare configurare",
"enabled_dhcp": "Server DHCP activat",
@@ -151,6 +154,7 @@
"use_adguard_parental": "Utilizați Controlul Parental AdGuard",
"use_adguard_parental_hint": "AdGuard Home va verifica pentru conținut adult pe domeniu. Utilizează același API discret ca cel utilizat de serviciul de securitate de navigare.",
"enforce_safe_search": "Folosiți Căutarea Sigură",
"enforce_save_search_hint": "AdGuard Home va impune Căutarea Sigură în următoarele motoare de căutare: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
"no_servers_specified": "Nu sunt specificate servere",
"general_settings": "Setări Generale",
"dns_settings": "Setări DNS",
@@ -671,6 +675,7 @@
"use_saved_key": "Folosiți cheia salvată anterior",
"parental_control": "Control Parental",
"safe_browsing": "Navigare în siguranță",
"served_from_cache": "{{value}} <i>(furnizat din cache)</i>",
"form_error_password_length": "Parola trebuie să aibă între {{min}} și {{max}} caractere",
"anonymizer_notification": "<0>Nota:</0> Anonimizarea IP este activată. Puteți să o dezactivați în <1>Setări generale</1>.",
"confirm_dns_cache_clear": "Sunteți sigur că doriți să ștergeți memoria cache DNS?",

View File

@@ -4,8 +4,10 @@
"parallel_requests": "සමාන්තර ඉල්ලීම්",
"load_balancing": "ධාරිතාව තුලනය",
"local_ptr_title": "පෞද්ගලික ප්‍රතිවර්ත ව.නා.ප. සේවාදායක",
"local_ptr_desc": "ස්ථානීය PTR විමසුම් සඳහා ඇඩ්ගාර්ඩ් හෝම් භාවිතා කරන ව.නා.ප. සේවාදායක. මෙම සේවාදායක පුද්ගලික අ.ජා.කෙ. ලිපින පරාසවල PTR විමසුම් විසඳීමට භාවිතා කරයි, උදාහරණයක් ලෙස ප්‍රතිවර්ත ව.නා.ප. භාවිතයෙන් \"192.168.12.34\". මෙය සකසා නැති නම්, ඇඩ්ගාර්ඩ් හෝම් හි ලිපින සඳහා හැරුනු විට ඔබගේ මෙහෙයුම් පද්ධතියේ පෙරනිමි ව.නා.ප. විසදුම්වල ලිපින භාවිතා කරයි.",
"local_ptr_default_resolver": "පෙරනිමි පරිදි, ඇඩ්ගාර්ඩ් හෝම් පහත ප්‍රතිවර්ත ව.නා.ප. පිළිවිසඳු භාවිතා කරයි: {{ip}}.",
"local_ptr_no_default_resolver": "ඇඩ්ගාර්ඩ් හෝම් හට මෙම පද්ධතිය සඳහා සුදුසු පුද්ගලික ප්‍රතිවර්ත ව.නා.ප. පිළිවිසඳු නිශ්චය කරගත නොහැකි විය.",
"local_ptr_placeholder": "පේළියකට අ.ජා.කෙ. ලිපිනය බැගින් ලියන්න",
"resolve_clients_title": "අනුග්‍රාහකවල අ.ජා.කෙ. ලිපින ප්‍රතිවර්ත විසඳීම සබල කරන්න",
"use_private_ptr_resolvers_title": "පෞද්. ප්‍රතිවර්ත ව.නා.ප. පිළිවිසඳු භාවිතය",
"check_dhcp_servers": "ග.ධා.වි.කෙ. සේවාදායක පරීක්‍ෂා කරන්න",
@@ -112,12 +114,15 @@
"general_statistics": "පොදු සංඛ්‍යාලේඛන",
"number_of_dns_query_days": "පසුගිය දවස් {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
"number_of_dns_query_days_plural": "පසුගිය දවස් {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
"number_of_dns_query_hours": "පසුගිය පැය {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
"number_of_dns_query_hours_plural": "පසුගිය පැය {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
"number_of_dns_query_blocked_24_hours": "දැන්වීම් වාරණ පෙරහන් සහ සත්කාරක වාරණ ලැයිස්තු මගින් අවහිර කළ ව.නා.ප. ඉල්ලීම් ගණන",
"number_of_dns_query_blocked_24_hours_by_sec": "ඇඩ්ගාර්ඩ් පිරික්සුම් ආරක්‍ෂණ ඒකකය මගින් අවහිර කළ ව.නා.ප. ඉල්ලීම් ගණන",
"number_of_dns_query_blocked_24_hours_adult": "අවහිර කළ වැඩිහිටි වියමන අඩවි ගණන",
"enforced_save_search": "ආරක්‍ෂිත සෙවීම බලාත්මක කළ",
"number_of_dns_query_to_safe_search": "ආරක්‍ෂිත සෙවීම බලාත්මක කළ සෙවුම් යන්ත්‍ර සඳහා ව.නා.ප. ඉල්ලීම් ගණන",
"average_processing_time": "සාමාන්‍ය සැකසුම් කාලය",
"response_time": "ප්‍රතිචාර කාලය",
"average_processing_time_hint": "ව.නා.ප. ඉල්ලීමක් සැකසීමේ සාමාන්‍ය කාලය මිලි තත්පර වලින්",
"block_domain_use_filters_and_hosts": "පෙරහන් හා සත්කාරක ගොනු භාවිතයෙන් වසම් අවහිර කරන්න",
"filters_block_toggle_hint": "ඔබට අවහිර කිරීමේ නීති <a>පෙරහන්</a> තුළ පිහිටුවිය හැකිය.",
@@ -126,6 +131,7 @@
"use_adguard_parental": "ඇඩ්ගාර්ඩ් දෙමාපිය පාලන වියමන සේවාව භාවිතා කරන්න",
"use_adguard_parental_hint": "වසමේ වැඩිහිටියන්ට අදාල කරුණු අඩංගු දැයි ඇඩ්ගාර්ඩ් හෝම් විසින් පරීක්‍ෂා කරනු ඇත. එය පිරික්සුම් ආරක්‍ෂණ වියමන සේවාව මෙන් රහස්‍යතා හිතකාමී යෙ.ක්‍ර. අ.මු. (API) භාවිතා කරයි.",
"enforce_safe_search": "ආරක්‍ෂිත සෙවුම භාවිතා කරන්න",
"enforce_save_search_hint": "ඇඩ්ගාර්ඩ් හෝම් පහත සෙවුම් යන්ත්‍ර තුළ ආරක්‍ෂිත සෙවුම බලාත්මක කරනු ඇත: ගූගල්, යූටියුබ්, බින්ග්, ඩක්ඩක්ගෝ, එකොසියා, යාන්ඩෙක්ස් සහ පික්සාබේ.",
"no_servers_specified": "සේවාදායක කිසිවක් නිශ්චිතව දක්වා නැත",
"general_settings": "පොදු සැකසුම්",
"dns_settings": "ව.නා.ප. සැකසුම්",
@@ -191,12 +197,14 @@
"example_comment_hash": "# එසේම අදහස් දැක්වීමක්.",
"example_regex_meaning": "නිශ්චිතව දක්වා ඇති නිත්‍ය වාක්‍යවිධියට ගැළපෙන වසම් වෙත ප්‍රවේශය අවහිර කරයි.",
"example_upstream_regular": "සාමාන්‍ය ව.නා.ප. (UDP හරහා);",
"example_upstream_regular_port": "සාමාන්‍ය ව.නා.ප. (UDP හරහා, තොට සමඟ);",
"example_upstream_udp": "සාමාන්‍ය ව.නා.ප. (UDP, සත්කාරක-නම හරහා);",
"example_upstream_dot": "සංකේතිත <0>TLS-මගින්-ව.නා.ප.</0>;",
"example_upstream_doh": "සංකේතිත <0>HTTPS-මගින්-ව.නා.ප.</0>;",
"example_upstream_doq": "සංකේතිත <0>QUIC-මගින්-ව.නා.ප.</0>;",
"example_upstream_sdns": "<1>DNSCrypt</1> හෝ <2>HTTPS-මගින්-ව.නා.ප.</2> පිළිවිසඳු සඳහා <0>ව.නා.ප. මුද්දර</0>;",
"example_upstream_tcp": "සාමාන්‍ය ව.නා.ප. (TCP/ස.පා.කෙ. හරහා);",
"example_upstream_tcp_port": "සාමාන්‍ය ව.නා.ප. (TCP හරහා, තොට සමඟ);",
"example_upstream_tcp_hostname": "සාමාන්‍ය ව.නා.ප. (ස.පා.කෙ., සත්කාරක-නම හරහා);",
"all_lists_up_to_date_toast": "සියළුම ලැයිස්තු දැනටමත් යාවත්කාලීනයි",
"dns_test_ok_toast": "සඳහන් කළ ව.නා.ප. සේවාදායක නිවැරදිව ක්‍රියා කරයි",
@@ -270,6 +278,7 @@
"edns_use_custom_ip": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. යොදාගන්න",
"edns_use_custom_ip_desc": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. භාවිතයට ඉඩදෙන්න",
"rate_limit_desc": "එක් අනුග්‍රාහකයකට ඉඩ දී ඇති තත්පරයට ඉල්ලීම් ගණන. එය 0 ලෙස සැකසීම යනුවෙන් අදහස් කරන්නේ සීමාවක් නැති බවයි.",
"rate_limit_whitelist_placeholder": "පේළියකට අ.ජා.කෙ. ලිපිනය බැගින් ලියන්න",
"blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
"blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
"blocking_mode_default": "පොදු: දැන්වීම් අවහිර කරන ආකාරයේ නීතියක් මගින් අවහිර කළ විට REFUSED සමඟ ප්‍රතිචාර දක්වයි; /etc/host-style ආකාරයේ නීතියක් මගින් අවහිර කළ විට නීතියේ දක්වා ඇති අ.ජා.කෙ. ලිපිනය සමඟ ප්‍රතිචාර දක්වයි",
@@ -500,6 +509,8 @@
"statistics_enable": "සංඛ්‍යාලේඛන සබල කරන්න",
"ignore_domains": "නොසලකන වසම් (පේළියකට එක බැගින්)",
"ignore_domains_title": "නොසලකන වසම්",
"ignore_domains_desc_stats": "මෙම නීති වලට ගැළපෙන විමසුම් සංඛ්‍යාලේඛනයට නොලියැවෙයි",
"ignore_domains_desc_query": "විමසුම් සටහනට මෙම නීති වලට ගැළපෙන විමසුම් නොලියැවෙයි",
"interval_hours": "පැය {{count}}",
"interval_hours_plural": "පැය {{count}}",
"filters_configuration": "පෙරහන් වින්‍යාසය",
@@ -608,6 +619,8 @@
"use_saved_key": "පෙර සුරැකි යතුර භාවිතා කරන්න",
"parental_control": "දෙමාපිය පාලනය",
"safe_browsing": "ආරක්‍ෂිත පිරික්සුම",
"served_from_cache_label": "නිහිතයෙන් සැපයිණි",
"form_error_password_length": "මුරපදය අකුරු {{min}} සහ {{value}} ක් අතර විය යුතුය",
"anonymizer_notification": "<0>සටහන:</0> අ.ජා.කෙ. නිර්නාමිකකරණය සබලයි. ඔබට එය <1>පොදු සැකසුම්</1> හරහා අබල කිරීමට හැකිය .",
"confirm_dns_cache_clear": "ඔබට ව.නා.ප. නිහිතය හිස් කිරීමට වුවමනාද?",
"cache_cleared": "ව.නා.ප. නිහිතය හිස් කෙරිණි",
@@ -637,6 +650,7 @@
"log_and_stats_section_label": "විමසුම් සටහන හා සංඛ්‍යාලේඛන",
"ignore_query_log": "විමසුම් සටහනට මෙම අනුග්‍රාහකය යොදන්න එපා",
"ignore_statistics": "සංඛ්‍යාලේඛනයට මෙම අනුග්‍රාහකය යොදන්න එපා",
"schedule_services": "සේවා අවහිර විරාමය",
"schedule_invalid_select": "ආරම්භක වේලාව අවසන් වේලාවට කලින් විය යුතුය",
"schedule_select_days": "දවස් තෝරන්න",
"schedule_timezone": "වේලා කලාපයක් තෝරන්න",

View File

@@ -484,7 +484,7 @@
"access_disallowed_title": "Nepovolení klienti",
"access_disallowed_desc": "Zoznam CIDR, IP adries alebo <a>ClientID</a>. Ak tento zoznam obsahuje položky, AdGuard Home zruší dopyty od týchto klientov. Toto pole sa ignoruje, ak sú v poli Povolení klienti položky.",
"access_blocked_title": "Nepovolené domény",
"access_blocked_desc": "Nesmie byť zamieňaná s filtrami. AdGuard Home zruší DNS dopyty, ktoré sa zhodujú s týmito doménami, a tieto dopyty sa nezobrazia ani v denníku dopytov. Môžete určiť presné názvy domén, zástupné znaky alebo pravidlá filtrovania URL adries, napr. \"example.org\", \"*.example.org\" alebo ||example.org^\" zodpovedajúcim spôsobom.",
"access_blocked_desc": "Nesmie byť zamieňaná s filtrami. AdGuard Home zruší DNS dopyty, ktoré sa zhodujú s týmito doménami, a tieto dopyty sa nezobrazia ani v denníku dopytov. Môžete určiť presné názvy domén, zástupné znaky alebo pravidlá filtrácie URL adries, napr. \"example.org\", \"*.example.org\" alebo ||example.org^\" zodpovedajúcim spôsobom.",
"access_settings_saved": "Nastavenia prístupu úspešne uložené",
"updates_checked": "K dispozícii je nová verzia aplikácie AdGuard Home\n",
"updates_version_equal": "AdGuard Home je aktuálny",

View File

@@ -6,18 +6,21 @@
"upstream_parallel": "Uporabite vzporedne zahteve za pospešitev reševanja s hkratnim poizvedovanjem vseh gorvodnih strežnikov.",
"parallel_requests": "Vzporedne zahteve",
"load_balancing": "Uravnavanje obremenitve",
"load_balancing_desc": "Poizvedujte po enem strežniku navzgor. AdGuard Home s pomočjo tehtanega naključnega algoritma izbere strežnik, tako da se najpogosteje uporablja najhitrejši strežnik.",
"bootstrap_dns": "Zagonski DNS strežniki",
"bootstrap_dns_desc": "Naslovi IP strežnikov DNS, ki se uporabljajo za razreševanje naslovov IP razreševalcev DoH/DoT, ki jih določite kot navzgor. Komentarji niso dovoljeni.",
"fallback_dns_title": "Rezervni strežniki DNS",
"fallback_dns_desc": "Seznam rezervnih strežnikov DNS, ki se uporabljajo, ko se gorvodni strežniki DNS ne odzivajo. Sintaksa je enaka kot v zgornjem gorvodnem polju.",
"fallback_dns_placeholder": "Vnesite en rezervni strežnik DNS na vrstico",
"local_ptr_title": "Zasebni povratni strežniki DNS",
"local_ptr_desc": "Strežniki DNS, ki jih AdGuard Home uporablja za lokalne PTR poizvedbe. Ti strežniki se uporabljajo za reševanje zahtev PTR za naslove v zasebnih obsegih IP, na primer \"192.168.12.34\", z uporabo obratnega DNS. Če ni nastavljen, AdGuard Home uporablja naslove privzetih razreševalnikov DNS vašega OS, razen naslovov samega AdGuard Home.",
"local_ptr_default_resolver": "AdGuard Home privzeto uporablja te povratne razreševalnike DNS: {{ip}}.",
"local_ptr_no_default_resolver": "AdGuard Home ni mogel določiti ustreznih zasebnih povratnih reševalcev DNS za ta sistem.",
"local_ptr_placeholder": "Vnesite en naslov IP na vrstico",
"resolve_clients_title": "Omogoči obratno reševanje naslovov IP gostiteljev",
"resolve_clients_desc": "Povratno razrešite naslove IP odjemalcev v njihova gostiteljska imena, tako da pošljete poizvedbe PTR ustreznim razreševalcem (zasebni strežniki DNS za lokalne odjemalce, gorvodni strežniki za odjemalce z javnimi naslovi IP).",
"use_private_ptr_resolvers_title": "Uporabi zasebne povratne razreševalnike rDNS",
"use_private_ptr_resolvers_desc": "Opravi povratne preglede DNS za lokalno vročene naslove s pomočjo teh strežnikov. Če je AdGuard onemogočen, se z NXDOMAIN odzove na vse takšne zahteve PTR, razen za odjemalce, znane iz DHCP/etc/hosts itd.",
"check_dhcp_servers": "Preveri strežnike DHCP",
"save_config": "Shrani nastavitve",
"enabled_dhcp": "Strežnik DHCP je omogočen",
@@ -151,6 +154,7 @@
"use_adguard_parental": "Uporabi AdGuardovo spletno storitev 'Starševski nadzor'",
"use_adguard_parental_hint": "AdGuard Home bo preveril, če domena vsebuje vsebine za odrasle. Uporablja enako, za zasebnost prijazen API, kot spletno storitev za varnost brskanja.",
"enforce_safe_search": "Uporabi Varno iskanje",
"enforce_save_search_hint": "AdGuard Home bo vsilil varno iskanje v naslednjih iskalnikih: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
"no_servers_specified": "Ni določenih strežnikov",
"general_settings": "Splošne nastavitve",
"dns_settings": "Nastavitve DNS",

View File

@@ -6,18 +6,21 @@
"upstream_parallel": "Koristite paralelne upite da biste ubrzali rešavanje tako što ćete istovremeno ispitati sve uzvodne servere.",
"parallel_requests": "Paralelni zahtevi",
"load_balancing": "Load-balancing",
"load_balancing_desc": "Koristi jedan upstream server. AdGuard Home koristi najnoviji nasumični algoritam da izabere server tako da se najbrži server češće koristi.",
"bootstrap_dns": "Bootstrap DNS serveri",
"bootstrap_dns_desc": "IP adrese DNS servera koje se koriste za rešavanje IP adresa DoH/DoT razrešivača koje navodite kao uzvodne. Komentari nisu dozvoljeni.",
"fallback_dns_title": "Odstupajući DNS serveri",
"fallback_dns_desc": "Lista povratnih DNS servera koji se koriste kada se uzvodni DNS serveri ne odaziva. Sintaksa je ista kao u glavnom uzvodnom polju iznad.",
"fallback_dns_placeholder": "Unesite jedan povratni DNS server po liniji",
"local_ptr_title": "Private reverse DNS serveri",
"local_ptr_desc": "DNS serveri koje AdGuard Home koristi za lokalne PTR upite. Ovi serveri se koriste za rešavanje imena domaćina klijenata sa privatnim IP adresama, na primer \"192.168.12.34\", koristeći obrnuti DNS. Ako nije podešen, AdGuard Home koristi adrese podrazumevanih DNS razrešivača vašeg OS-a osim adresa samog AdGuard Home-a.",
"local_ptr_default_resolver": "Podrazumevano, AdGuard Home koristi sledeće obrnute DNS razrešivače: {{ip}}.",
"local_ptr_no_default_resolver": "AdGuard Home ne može da odredi pogodne privatne obrnute DNS razrešivače za ovaj sistem.",
"local_ptr_placeholder": "Unesite jednu IP adresu servera po redu",
"resolve_clients_title": "Uključi obrnuto razrešavanje klijentskih IP adresa",
"resolve_clients_desc": "Obrnuto razrešite IP adrese klijenata u njihova imena domaćina slanjem PTR upita odgovarajućim razrešivačima (privatni DNS serveri za lokalne klijente, uzvodni serveri za klijente sa javnim IP adresama).",
"use_private_ptr_resolvers_title": "Koristi privatne obrnute razrešivače",
"use_private_ptr_resolvers_desc": "Izvršavanje obrnutih DNS izgleda za lokalno servirane adrese pomoću ovih uzvodnih servera. Ako je onemogućen, AdGuard Home odgovara sa NXDOMAIN na sve takve PTR zahteve osim klijenata poznatih iz DHCP- a, /etc/hosts itd.",
"check_dhcp_servers": "Proveri DHCP servere",
"save_config": "Sačuvaj konfiguraciju",
"enabled_dhcp": "DHCP server uključen",
@@ -151,6 +154,7 @@
"use_adguard_parental": "Koristi AdGuard-ovu uslugu roditeljske kontrole",
"use_adguard_parental_hint": "AdGuard Home će proveriti da li domen sadrži sadržaj za odrasle. Koristi se isti privatni prijateljski API kao i kod usluge bezbednog pregledanja.",
"enforce_safe_search": "Nametni sigurno pretraživanje",
"enforce_save_search_hint": "AdGuard Home može nametnuti sigurno pretraživanje u sledećim pretraživačima: Google, Youtube, Bing, DuckDuckGo i Yandex.",
"no_servers_specified": "Serveri nisu određeni",
"general_settings": "Opšte postavke",
"dns_settings": "DNS postavke",
@@ -671,6 +675,7 @@
"use_saved_key": "Koristi prethodno sačuvan ključ",
"parental_control": "Roditeljska kontrola",
"safe_browsing": "Sigurno pregledanje",
"served_from_cache": "{{value}} <i>(posluženo iz predmemorije)</i>",
"form_error_password_length": "Lozinka mora imati od {{min}} do {{max}} znakova",
"anonymizer_notification": "<0>Nota:</0> IP prepoznavanje je omogućeno. Možete ga onemogućiti u opštim <1>postavkama</1>.",
"confirm_dns_cache_clear": "Želite li zaista da obrišite DNS keš?",

View File

@@ -6,18 +6,21 @@
"upstream_parallel": "Använd parallella förfrågningar för att snabba upp dessa genom att fråga alla uppströmsservrar samtidigt.",
"parallel_requests": "Parallella förfrågningar",
"load_balancing": "Lastbalansering",
"load_balancing_desc": "Fråga en uppströmsserver åt gången. AdGuard Home använder sin viktade slumpmässiga algoritm för att välja server så att den snabbaste servern används oftare.",
"bootstrap_dns": "Bootstrap-DNS-servrar",
"bootstrap_dns_desc": "IP-adresser för DNS-servrar som används för att lösa IP-adresser för de DoH/DoT-resolvers som du anger som uppströms. Kommentarer är inte tillåtna.",
"fallback_dns_title": "Reserv DNS-servrar",
"fallback_dns_desc": "Lista över reserv-DNS-servrar som används när uppströms DNS-servrar inte svarar. Syntaxen är densamma som i huvuduppströmsfältet ovan.",
"fallback_dns_placeholder": "Ange en reserv-DNS-server per rad",
"local_ptr_title": "Privata omvända DNS-servrar",
"local_ptr_desc": "DNS servrarna som AdGuard Home använder för lokala PTR frågor. Dessa servrar används för att lösa värdnamnen på klienter med privata IP-adresser, till exempel \"192.168.12.34\", genom omvänd DNS. Om inga servrar angetts använder AdGuard Home adresserna till standard DNS servrar för ditt operativsystem förutom adresserna till AdGuard Home själv.",
"local_ptr_default_resolver": "Som standard använder AdGuard Home följande omvända DNS upplösare: {{ip}}.",
"local_ptr_no_default_resolver": "AdGuard Home kunde inte fastställa lämpliga privata omvända DNS upplösare för detta system.",
"local_ptr_placeholder": "Ange en IP-adress per rad",
"resolve_clients_title": "Aktivera omvänd upplösning av klienters IP-adresser",
"resolve_clients_desc": "Lös upp klienternas värdnamn med omvänt uppslag av klienternas IP-adresser genom att skicka PTR-frågor till motsvarande upplösare (privata DNS-servrar för lokala klienter, uppströmsservrar för klienter med offentliga IP-adresser).",
"use_private_ptr_resolvers_title": "Använd privata omvända DNS upplösare",
"use_private_ptr_resolvers_desc": "Utför omvända DNS-sökningar för lokalt betjänade adresser med dessa uppströmsservrar. Om det är inaktiverat svarar AdGuard Home med NXDOMAIN på alla sådana PTR-förfrågningar förutom klienter kända från DHCP, /etc/hosts, och så vidare.",
"check_dhcp_servers": "Letar efter DHCP-servrar",
"save_config": "Spara konfiguration",
"enabled_dhcp": "DHCP-server aktiverad",
@@ -151,6 +154,7 @@
"use_adguard_parental": "Använda AdGuards webbservice för föräldrakontroll",
"use_adguard_parental_hint": "AdGuard Home kommer att kontrollera domäner för innehåll av vuxenmaterial . Samma integritetsvänliga metod för API-lookup som tillämpas i webbservicens surfsäkerhet används.",
"enforce_safe_search": "Använd SafeSearch",
"enforce_save_search_hint": "AdGuard Home kommer tvinga säker surf på följande sökmotorer: Google, Youtube, Bing, DuckDuckGo, Yandex, Pixabay.",
"no_servers_specified": "Inga servrar angivna",
"general_settings": "Allmänna inställningar",
"dns_settings": "DNS-inställningar",
@@ -457,7 +461,7 @@
"form_enter_mac": "Skriv in MAC",
"form_enter_id": "Ange identifierare",
"form_add_id": "Lägg till identifierare",
"form_client_name": "Skriv in klientnamn",
"form_client_name": "Ange klientnamn",
"name": "Namn",
"client_name": "Klient {{id}}",
"client_global_settings": "Använda globala inställningar",

View File

@@ -1,6 +1,7 @@
{
"client_settings": "การตั้งค่าไคลเอนต์",
"bootstrap_dns": "Bootstrap เซิร์ฟเวอร์ DNS",
"bootstrap_dns_desc": "เซิร์ฟเวอร์ Bootstrap DNS ใช้เพื่อแก้ไขที่อยู่ IP ของตัวแก้ไข DoH / DoT ที่คุณระบุว่าเป็น upstreams",
"check_dhcp_servers": "ตรวจสอบ DHCP servers",
"enabled_dhcp": "เปิดการใช้งาน DHCP server แล้ว",
"disabled_dhcp": "ปิดการใช้งาน DHCP server แล้ว",
@@ -12,6 +13,13 @@
"dhcp_leases": "สัญญาเช่า DHCP",
"dhcp_static_leases": "DHCP แบบกำหนด",
"dhcp_leases_not_found": "ไม่พบสัญญาเช่า DHCP",
"form_error_required": "ช่องที่ต้องกรอก",
"form_error_ip4_format": "รูปแบบ IPv4 ไม่ถูกต้อง",
"form_error_ip6_format": "รูปแบบ IPv6 ไม่ถูกต้อง",
"form_error_ip_format": "รูปแบบ IP ไม่ถูกต้อง",
"form_error_mac_format": "รูปแบบ MAC ไม่ถูกต้อง",
"form_error_client_id_format": "รูปแบบ ID ลูกค้าไม่ถูกต้อง",
"form_error_positive": "ต้องมากกว่า 0",
"dhcp_form_gateway_input": "IP ของเกตเวย์",
"dhcp_form_subnet_input": "ซับเน็ตมาสก์",
"dhcp_form_range_title": "ช่วงของที่อยู่ IP",
@@ -38,6 +46,7 @@
"settings": "การตั้งค่า",
"filters": "ตัวกรอง",
"query_log": "บันทึกการสืบค้น",
"nothing_found": "ไม่พบอะไร",
"faq": "คำถามที่พบบ่อย",
"version": "รุ่น",
"address": "ที่อยู่",
@@ -46,6 +55,7 @@
"copyright": "ลิขสิทธิ์",
"homepage": "หน้าหลัก",
"report_an_issue": "รายงานปัญหา",
"privacy_policy": "นโยบายความเป็นส่วนตัว",
"enable_protection": "เปิดใช้งานการป้องกัน",
"enabled_protection": "เปิดใช้งานการป้องกันแล้ว",
"disable_protection": "ปิดใช้งานการป้องกัน",
@@ -56,6 +66,7 @@
"stats_malware_phishing": "ปิดกั้นมัลแวร์/ฟิชชิ่ง แล้ว",
"stats_adult": "ปิดกั้นเว็บไซต์สำหรับผู้ใหญ่แล้ว",
"stats_query_domain": "โดเมนที่เข้าบ่อยสุด",
"for_last_24_hours": "ในช่วง 24 ชั่วโมงที่ผ่านมา",
"for_last_days": "สำหรับ {{count}} วันสุดท้าย",
"for_last_days_plural": "สำหรับ {{count}} วันล่าสุด",
"no_domains_found": "ไม่พบโดเมน",
@@ -70,8 +81,10 @@
"block_domain_use_filters_and_hosts": "ปิดกั้นโดเมนโดยใช้ตัวกรองและไฟล์โฮสต์",
"filters_block_toggle_hint": "คุณสามารถตั้งค่ากฎการปิดกั้นในการตั้งค่า<a>ตัวกรอง</a>",
"use_adguard_browsing_sec": "ใช้บริการเว็บการรักษาความปลอดภัยการเรียกดู AdGuard",
"use_adguard_browsing_sec_hint": "AdGuard Home จะตรวจสอบว่าโดเมนอยู่ในรายการที่ไม่อนุญาตโดยเว็บเซอร์วิสความปลอดภัยการสืบค้นหรือไม่ จะใช้ API การค้นหาที่เป็นมิตรกับข้อมูลส่วนบุคคลเพื่อทำการตรวจสอบ: มีการส่งคำนำหน้าสั้น ๆ ของชื่อโดเมน SHA256 แฮชไปยังเซิร์ฟเวอร์",
"use_adguard_parental": "ใช้บริการเว็บการควบคุมโดยผู้ปกครองของ AdGuard",
"use_adguard_parental_hint": "AdGuard Home จะตรวจสอบว่าโดเมนมีเนื้อหาสำหรับผู้ใหญ่หรือไม่ มันใช้ API ความเป็นส่วนตัวเช่นเดียวกับบริการเว็บการรักษาความปลอดภัยการท่องเว็บ",
"enforce_safe_search": "บังคับใช้การค้นหาที่ปลอดภัย",
"no_servers_specified": "ไม่ได้ระบุเซิร์ฟเวอร์",
"general_settings": "การตั้งค่าทั่วไป",
"dns_settings": "การตั้งค่า DNS",
@@ -84,6 +97,12 @@
"apply_btn": "นำไปใช้",
"disabled_filtering_toast": "ปิดใช้งานการกรอง",
"enabled_filtering_toast": "เปิดใช้งานการกรอง",
"disabled_safe_browsing_toast": "ปิดใช้งานการเรียกดูอย่างปลอดภัย",
"enabled_safe_browsing_toast": "เปิดการใช้งาน safebrowsing",
"disabled_parental_toast": "ปิดใช้งานการควบคุมโดยผู้ปกครอง",
"enabled_parental_toast": "เปิดการใช้งานเข้าเว็บไม่พึงประสงค์",
"disabled_safe_search_toast": "ปิดใช้งานการค้นหาที่ปลอดภัย",
"enabled_save_search_toast": "เปิดใช้งานการค้นหาที่ปลอดภัย",
"enabled_table_header": "เปิดใช้งาน",
"name_table_header": "ชื่อ",
"rules_count_table_header": "กฎการนับ",
@@ -98,6 +117,18 @@
"custom_filter_rules": "กฎการกรองที่กำหนดเอง",
"custom_filter_rules_hint": "ป้อนหนึ่งกฎในหนึ่งบรรทัด คุณสามารถใช้กฎปิดกั้นโฆษณาหรือโฮสต์ไฟล์ไวยากรณ์",
"examples_title": "ตัวอย่าง",
"example_meaning_filter_block": "ปิดกั้นการเข้าถึงโดเมน example.org และโดเมนย่อยทั้งหมด",
"example_meaning_filter_whitelist": "เลิกปิดกั้นการเข้าถึงโดเมน example.org และโดเมนย่อยทั้งหมด",
"example_meaning_host_block": "ตอนนี้ AdGuard Home จะส่งคืนที่อยู่ 127.0.0.1 สำหรับโดเมน example.org (แต่ไม่ใช่โดเมนย่อย)",
"example_comment": "! นี่ความคิดเห็น",
"example_comment_meaning": "เพียงความคิดเห็น",
"example_comment_hash": "# นอกจากนี้ยังมีความคิดเห็น",
"example_regex_meaning": "ปิดกั้นการเข้าถึงโดเมนที่ตรงกับนิพจน์ทั่วไปที่ระบุ",
"example_upstream_regular": "DNS ปกติ (มากกว่า UDP)",
"example_upstream_dot": "encrypted <0>DNS-over-TLS</0> แล้ว",
"example_upstream_doh": "เข้ารหัส <0>DNS-over-HTTPS</0> แล้ว",
"example_upstream_sdns": "คุณสามรถใช้ <0>DNS Stamps</0> กับ <1>DNSCrypt</1> หรือ <2>DNS-over-HTTPS</2> ตัวแก้ปัญหา",
"example_upstream_tcp": "dNS ปกติ (ผ่าน TCP)",
"dns_test_ok_toast": "เซิร์ฟเวอร์ DNS ที่ระบุทำงานอย่างถูกต้อง",
"dns_test_not_ok_toast": "เซิร์ฟเวอร์ \"{{key}}\": ไม่สามารถใช้งานได้ โปรดตรวจสอบว่าคุณเขียนถูกต้อง",
"unblock": "เลิกปิดกั้น",
@@ -117,6 +148,7 @@
"loading_table_status": "กำลังโหลด...",
"page_table_footer_text": "หน้า",
"rows_table_footer_text": "ตาราง",
"updated_custom_filtering_toast": "อัปเดตกฎการกรองที่กำหนดเอง",
"rule_removed_from_custom_filtering_toast": "ลบกฎออกจากกฎการกรองที่กำหนดเองแล้ว {{rule}}",
"rule_added_to_custom_filtering_toast": "เพิ่มกฎในกฎการกรองที่กำหนดเองแล้ว {{rule}}",
"query_log_response_status": "สถานะ: {{value}}",
@@ -124,10 +156,12 @@
"query_log_confirm_clear": "คุณแน่ใจหรือไม่ว่าต้องการลบบันทึกการใช้งานทั้งหมด?",
"query_log_cleared": "บันทึกการใช้งานได้รับการล้างเรียบร้อยแล้ว",
"query_log_clear": "ล้างบันทึกการสืบค้น",
"query_log_retention": "แบบสอบถามบันทึกการเก็บรักษา",
"query_log_enable": "เปิดใช้งานบันทึก",
"query_log_configuration": "บันทึกการกำหนดค่า",
"query_log_disabled": "บันทึกแบบสอบถามถูกปิดใช้งานและสามารถกำหนดค่าใน <0>การตั้งค่า</0>",
"query_log_strict_search": "ใช้เครื่องหมายคำพูดคู่เพื่อการค้นหาที่จำกัด",
"query_log_retention_confirm": "คุณแน่ใจหรือไม่ว่าต้องการเปลี่ยนการเก็บข้อมูลบันทึกแบบสอบถาม? หากคุณลดค่าช่วงเวลา ข้อมูลบางอย่างจะหายไป",
"dns_config": "การกำหนดค่าเซิร์ฟเวอร์ DNS",
"blocking_mode": "โหมดการปิดกั้น",
"default": "ค่าเริ่มต้น",
@@ -142,6 +176,8 @@
"dns_over_quic": "DNS-over-QUIC",
"form_enter_rate_limit": "ป้อนขีดจำกัดอัตรา",
"rate_limit": "จำกัดอัตรา",
"edns_enable": "เปิดใช้งานซับเน็ตไคลเอ็นต์ EDNS",
"edns_cs_desc": "หากเปิดใช้งาน AdGuard Home จะส่งซับเน็ตของไคลเอนต์ไปยังเซิร์ฟเวอร์ DNS",
"blocking_ipv4_desc": "ที่อยู่ IP ที่จะส่งคืนสำหรับคำขอที่ถูกปิดกั้น",
"blocking_ipv6_desc": "ที่อยู่ IP ที่จะส่งคืนสำหรับคำขอ AAAA ที่ถูกปิดกั้น",
"blocking_mode_nxdomain": "NXDOMAIN: ตอบสนองด้วยรหัส NXDOMAIN",
@@ -162,6 +198,7 @@
"install_settings_dns_desc": "คุณจะต้องกำหนดค่าอุปกรณ์หรือเราเตอร์ของคุณเพื่อใช้เซิร์ฟเวอร์ DNS ตามที่อยู่ต่อไปนี้:",
"install_settings_all_interfaces": "อินเทอร์เฟซทั้งหมด",
"install_auth_title": "การตรวจสอบสิทธิ์",
"install_auth_desc": "ขอแนะนำอย่างยิ่งให้กำหนดค่าการตรวจสอบรหัสผ่านให้กับส่วนต่อประสานเว็บผู้ดูแลระบบ AdGuard Home ของคุณ แม้ว่ามันจะสามารถเข้าถึงได้เฉพาะในเครือข่ายท้องถิ่นของคุณก็ยังคงเป็นสิ่งสำคัญที่จะปกป้องมันจากการเข้าถึงที่ไม่จำกัด",
"install_auth_username": "ชื่อผู้ใช้",
"install_auth_password": "รหัสผ่าน",
"install_auth_confirm": "ยืนยันรหัสผ่าน",
@@ -171,26 +208,37 @@
"install_devices_title": "กำหนดค่าอุปกรณ์ของคุณ",
"install_devices_desc": "ในการเริ่มใช้งาน AdGuard Home คุณต้องกำหนดค่าอุปกรณ์ของคุณเพื่อใช้งาน",
"install_submit_title": "ยินดีด้วย!",
"install_submit_desc": "ขั้นตอนการตั้งค่าเสร็จสิ้นและคุณพร้อมที่จะเริ่มใช้งาน AdGuard Home",
"install_devices_router": "เราเตอร์",
"install_devices_router_desc": "การตั้งค่านี้จะครอบคลุมอุปกรณ์ทั้งหมดที่เชื่อมต่อกับเราเตอร์ที่บ้านของคุณโดยอัตโนมัติและคุณไม่จำเป็นต้องกำหนดค่าแต่ละอุปกรณ์ด้วยตนเอง",
"install_devices_address": "เซิร์ฟเวอร์ DNS ของ AdGuard Home กำลังรับฟังตามที่อยู่ต่อไปนี้",
"install_devices_router_list_2": "ค้นหาการตั้งค่า DHCP/DNS ค้นหาตัวอักษร DNS ที่อยู่ถัดจากช่องที่อนุญาตให้มีตัวเลขสองหรือสามชุดโดยแต่ละกลุ่มแบ่งออกเป็นสี่กลุ่มหนึ่งถึงสามหลัก",
"install_devices_router_list_3": "ป้อนที่อยู่เซิร์ฟเวอร์ AdGuard Home ของคุณที่นั่น",
"install_devices_windows_list_1": "เปิด Control Panel โดยใช้ Start menu หรือ Windows search",
"install_devices_windows_list_2": "ไปที่หมวด Network and Internet แล้วเลือก Network and Sharing Center",
"install_devices_windows_list_3": "ทางด้านซ้ายจะมีคำว่า Change adapter settings ให้กดเข้าไป",
"install_devices_windows_list_4": "เลือกการเชื่อมต่อที่ใช้งานอยู่ คลิกขวาแล้วเลือก Properties",
"install_devices_windows_list_5": "ค้นหา Internet Protocol Version 4 (TCP/IP) แล้วคลิก Properties อีกครั้ง",
"install_devices_windows_list_6": "ค้นหา DNS server addresses ให้ทำการกรอกหมายเลข AdGuard Home ลงไปในช่อง",
"install_devices_macos_list_1": "คลิกโลโก้แอปเปิ้ลแล้วกด System Preferences",
"install_devices_macos_list_2": "คลิก Network",
"install_devices_macos_list_3": "เลือกการเชื่อมต่อแล้วคลิก Advanced",
"install_devices_macos_list_4": "ค้นหาแท็บ DNS แล้วกรอกหมาเลย AdGuard Home",
"install_devices_android_list_1": "เข้าหน้าเมนู(บางรุ่นจะมีตรงแท็บการแจ้งเตือน) เลือกการตั้งค่า",
"install_devices_android_list_2": "เลือกเมนู Wi-Fi แล้วค้นหา Wi-Fi ที่จะเชื่อมต่อ (ไม่สารถตั้งค่ากับเน็ตมือถือได้)",
"install_devices_android_list_3": "แตะชื่อWi-Fi ที่จะเชื่อมต่อค้างไว้(บางรุ่นให้เลื่อนจอลงไปล่างสุด) เลือกการตั้งค่าเพิ่มเติม",
"install_devices_android_list_4": "ในอุปกรณ์บางอย่างคุณอาจต้องทำเครื่องหมายในช่องสำหรับขั้นสูงเพื่อดูการตั้งค่าเพิ่มเติม หากต้องการปรับการตั้งค่า Android DNS ของคุณคุณจะต้องเปลี่ยนการตั้งค่า IP จาก DHCP เป็นแบบคงที่",
"install_devices_android_list_5": "เปลี่ยนการตั้งค่า DNS ที่ 1 และค่า DNS 2 ถึงที่อยู่เซิร์ฟเวอร์ AdGuard Home ของคุณ",
"install_devices_ios_list_1": "เลือกการตั้งค่า",
"install_devices_ios_list_2": "เลือก Wi-Fi ด้านซ้าย (ไม่สามรถใช้งานได้กับดาต้ามือถือ)",
"install_devices_ios_list_3": "เลือกชื่อที่จะเชื่อมต่อ",
"install_devices_ios_list_4": "กรอก DNS AdGuard Home Server ลงไปในช่อง",
"get_started": "เริ่มต้นการใช้งาน",
"next": "ถัดไป",
"open_dashboard": "เปิดหน้าควบคุม",
"install_saved": "บันทึกเรียบร้อยแล้ว",
"encryption_title": "การเข้ารหัส",
"encryption_desc": "การดข้ารหัส (HTTPS/TLS) รองรับทั้ง DNS และหน้าเว็บแอดมิน",
"encryption_server": "ชื่อเซิร์ฟเวอร์",
"encryption_server_enter": "ป้อนชื่อโดเมน",
"encryption_redirect": "ไปเส้นทาง HTTPS อัตโนมัติ",
@@ -208,6 +256,10 @@
"encryption_key_input": "คัดลอก/วาง PEM-encoded private key ของคุณตรงนี้",
"encryption_enable": "เปิดการเข้ารหัส (HTTPS, 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}} ที่ถูกต้อง",
"encryption_key_invalid": "นี่เป็นคีย์ส่วนตัว {{type}} ที่ไม่ถูกต้อง",
"encryption_subject": "เรื่อง:",
"encryption_issuer": "ผู้ออกใบรับรอง:",
"encryption_hostnames": "ชื่อโฮส",
@@ -215,16 +267,21 @@
"encryption_warning": "คำเตือน",
"topline_expiring_certificate": "ใบรับรอง SSL ของคุณกำลังจะหมดอายุ กรุณาอัปเดท <0>การตั้งค่าเข้ารหัส</0>.",
"topline_expired_certificate": "ใบรับรอง SSL ของคุณหมดอายุแล้ว กรุณาอัปเดท <0>การตั้งค่าเข้ารหัส</0>.",
"form_error_port_unsafe": "เป็นพอร์ทที่ไม่ปลอดภัย",
"form_error_password": "รหัสผ่านไม่ตรงกัน",
"reset_settings": "รีเซ็ตการตั้งค่า",
"update_announcement": "AdGuard Home {{version}} พร้อมแล้ว <0>กดตรงนี้</0> สำหรับข้อมูลเพิ่มเติม",
"dns_addresses": "ที่อยู่ DNS",
"dns_start": "เซิร์ฟเวอร์ DNS เริ่มทำงาน",
"dns_status_error": "เกิดข้อผิดพลาดในการตรวจสอบสถานะเซิร์ฟเวอร์ DNS",
"down": "ดับ",
"fix": "ซ่อม",
"dns_providers": "นี่คือรายการ <0>ของผู้ให้บริการ DNS ที่เป็นที่รู้จัก</0> ให้เลือก",
"update_now": "อัปเดตตอนนี้",
"update_failed": "อัปเดทล้มเหลว กรุณา <a> ทำตามขั้นตอน </a> เพื่ออัพเดทด้วยตนเอง",
"processing_update": "รอซักครู่ AdGuard Home กำลังอัปเดท",
"clients_title": "เครื่องลูกข่าย",
"clients_desc": "ตั้งค่าอุปกรณ์เพื่อเชื่อมต่อ AdGuard Home",
"settings_global": "ทั่วโลก",
"settings_custom": "กำหนดเอง",
"table_client": "เครื่องลูกข่าย",
@@ -246,9 +303,14 @@
"client_updated": "อัปเดตเครื่อง \"{{key}}\" สำเร็จแล้ว",
"clients_not_found": "ไม่มีเครื่องลูกข่าย",
"client_confirm_delete": "คุณแน่ใจนะว่าจะลบเครื่อง \"{{key}}\"?",
"auto_clients_title": "เครื่อง (runtime)",
"auto_clients_desc": "ข้อมูลเกี่ยวกับไคลเอนต์ที่ใช้ AdGuard Home แต่ไม่ได้เก็บไว้ในการกำหนดค่า",
"access_title": "เข้าถึงการตั้งค่า",
"access_desc": "ที่นี่คุณสามารถกำหนดค่ากฎการเข้าถึงสำหรับเซิร์ฟเวอร์ AdGuard Home DNS",
"access_allowed_title": "ลูกค้าที่ได้รับอนุญาต",
"access_allowed_desc": "รายการ CIDR หรือที่อยู่ IP หากกำหนดค่า AdGuard Home จะยอมรับคำขอจากที่อยู่ IP เหล่านี้เท่านั้น",
"access_disallowed_title": "ลูกค้าไม่ได้รับอนุญาต",
"access_disallowed_desc": "รายการ CIDR หรือที่อยู่ IP หากกำหนดค่าไว้ AdGuard Home จะส่งคำขอจากที่อยู่ IP เหล่านี้",
"access_blocked_title": "โดเมนที่ถูกปิดกั้น",
"check_updates_now": "ตรวจสอบการปรับปรุง",
"setup_dns_privacy_other_title": "การใช้งานอื่น ๆ",
@@ -257,6 +319,8 @@
"rewrite_add": "เพิ่ม DNS rewrite",
"form_domain": "ป้อนชื่อโดเมน",
"form_answer": "ป้อนชื่อโดเมนหรือ IP",
"form_error_domain_format": "รูปแบบ Domain ไม่ถูกต้อง",
"form_error_answer_format": "รูปแบบคำตอบไม่ถูกต้อง",
"configure": "กำหนดค่า",
"main_settings": "ตั้งค่าหลัก",
"block_services": "ปิดกั้นบริการเฉพาะ",
@@ -285,6 +349,8 @@
"filter_updated": "อัปเดตตัวกรองสำเร็จแล้ว",
"statistics_configuration": "การกำหนดค่าสถิติ",
"statistics_retention": "การเก็บรักษาสถิติ",
"statistics_retention_desc": "หากคุณลดค่าช่วงเวลาข้อมูลบางอย่างจะหายไป",
"statistics_clear": "ล้างสถิติ",
"statistics_clear_confirm": "คุณแน่ใจหรือไม่ว่าต้องการล้างสถิติ?",
"statistics_retention_confirm": "คุณแน่ใจหรือไม่ว่าต้องการเปลี่ยนการเก็บรักษาสถิติ? หากคุณลดค่าช่วงเวลา ข้อมูลบางอย่างจะหายไป",
"statistics_cleared": "สถิติได้ถูกล้างเรียบร้อยแล้ว",
@@ -292,6 +358,7 @@
"interval_hours_plural": "{{count}} ชั่วโมง",
"filters_configuration": "การกำหนดค่าตัวกรอง",
"filters_enable": "เปิดใช้งานตัวกรอง",
"filters_interval": "ตัวกรองช่วงเวลาการอัปเดต",
"disabled": "ปิดใช้งาน",
"username_label": "ชื่อผู้ใช้",
"username_placeholder": "ป้อนชื่อผู้ใช้",
@@ -306,21 +373,33 @@
"netname": "ชื่อเครือข่าย",
"network": "เครือข่าย",
"descr": "คำอธิบาย",
"whois": "Whois",
"filtering_rules_learn_more": "<0>เรียนรู้เพิ่มเติม</0> เกี่ยวกับการสร้างรายการปิดกั้นโฮสต์ของคุณเอง",
"blocked_by_response": "ปิดกั้นโดย CNAME หรือ IP ในการตอบกลับ",
"try_again": "ลองอีกครั้ง",
"domain_desc": "ป้อนชื่อโดเมนหรือไวด์การ์ดที่คุณต้องการเขียนใหม่",
"example_rewrite_domain": "เขียนคำตอบซ้ำสำหรับชื่อโดเมนนี้เท่านั้น",
"example_rewrite_wildcard": "เขียนคำตอบใหม่ทั้งหมดสำหรับ <0>example.org</0> โดเมนย่อย",
"disable_ipv6": "ปิดใช้งาน IPv6",
"disable_ipv6_desc": "หากเปิดใช้งานคุณสมบัตินี้การสืบค้น DNS ทั้งหมดสำหรับที่อยู่ IPv6 (ประเภท AAAA) จะถูกทิ้ง",
"autofix_warning_text": "หากคุณคลิก \"แก้ไข\" AdGuardHome จะกำหนดค่าระบบของคุณเพื่อใช้เซิร์ฟเวอร์ AdGuardHome",
"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": "ดังนั้น AdGuardHome จะประมวลผลคำขอ DNS ทั้งหมดจากระบบของคุณตามค่าเริ่มต้น",
"tags_title": "แท็ก",
"tags_desc": "คุณสามารถเลือกแท็กที่สอดคล้องกับลูกค้า แท็กสามารถรวมอยู่ในกฎการกรองและอนุญาตให้คุณใช้งานได้อย่างถูกต้องมากขึ้น <0>เรียนรู้เพิ่มเติม</0>",
"form_select_tags": "เลือกแท็กเครื่อง",
"check_title": "ตรวจสอบการกรอง",
"check_desc": "ตรวจสอบว่าชื่อโฮสต์ถูกกรอง",
"form_enter_host": "ป้อนชื่อโฮสต์",
"show_blocked_responses": "ปิดกั้นแล้ว",
"show_whitelisted_responses": "รายการที่อนุญาต",
"show_processed_responses": "ประมวลผลแล้ว",
"blocked_adult_websites": "ถูกปิดกั้นโดยการควบคุมของผู้ปกครอง",
"safe_search": "ค้นหาอย่างปลอดภัย",
"blocklist": "บัญชีดำ",
"allowed": "รายการที่อนุญาต",
"filter_category_other": "อื่น ๆ",
"parental_control": "ควบคุมโดยผู้ปกครอง",
"sunday_short": "อาทิตย์",
"monday_short": "จันทร์",
"tuesday_short": "อังคาร",

View File

@@ -6,18 +6,21 @@
"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-серверів, які використовуються, коли upstream DNS-сервери не відповідають. Синтаксис такий самий, як і в полі upstream сервера вище.",
"fallback_dns_placeholder": "Вводьте один резервний DNS-сервер на рядок",
"local_ptr_title": "Приватні сервери для зворотного DNS",
"local_ptr_desc": "DNS-сервери, які AdGuard Home використовує для локальних PTR-запитів. Ці сервери використовуються для вирішення PTR-запитів для адрес у приватних мережах, наприклад, «192.168.12.34». Якщо список порожній, 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": "Увімкнути зворотне вирішення IP-адрес клієнтів",
"resolve_clients_desc": "Визначати доменні імена клієнтів за допомогою PTR-запитів до відповідних серверів — приватних DNS-серверів для локальних клієнтів та upstream-серверів для клієнтів з публічними IP-адресами.",
"use_private_ptr_resolvers_title": "Використовувати приватні зворотні DNS-резолвери",
"use_private_ptr_resolvers_desc": "Розвʼязувати запити PTR, SOA та NS для доменів ARPA, що містять приватні IP-адреси, через приватні вихідні сервери, DHCP, /etc/hosts тощо. Якщо вимкнено, AdGuard Home відповідатиме на всі такі запити з NXDOMAIN.",
"check_dhcp_servers": "Перевірити DHCP-сервери",
"save_config": "Зберегти конфігурацію",
"enabled_dhcp": "DHCP-сервер увімкнено",
@@ -151,6 +154,7 @@
"use_adguard_parental": "Використовувати вебслужбу «Батьківський контроль» AdGuard",
"use_adguard_parental_hint": "AdGuard Home перевірить, чи містить домен матеріали для дорослих. Буде використано той же безпечний API, що й для «Безпеки перегляду» AdGuard.",
"enforce_safe_search": "Використовувати Безпечний пошук",
"enforce_save_search_hint": "AdGuard Home може примусово застосовувати безпечний пошук в таких пошукових системах: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
"no_servers_specified": "Сервери не вказано",
"general_settings": "Загальні налаштування",
"dns_settings": "Налаштування DNS",
@@ -339,10 +343,10 @@
"known_tracker": "Відомі трекери",
"install_welcome_title": "Вітаємо в AdGuard Home!",
"install_welcome_desc": "AdGuard Home — це мережевий DNS-сервер, що блокує рекламу та відстеження. Його мета — надати вам контроль над усією мережею та всіма пристроями в ній без потреби використання програми на стороні клієнта.",
"install_settings_title": "Веб-інтерфейс адміністратора",
"install_settings_title": "Вебінтерфейс адміністратора",
"install_settings_listen": "Мережевий інтерфейс",
"install_settings_port": "Порт",
"install_settings_interface_link": "Веб-інтерфейс адміністратора AdGuard Home буде доступний за такими адресами:",
"install_settings_interface_link": "Вебінтерфейс адміністратора AdGuard Home буде доступний за такими адресами:",
"form_error_port": "Уведіть правильне значення порту",
"install_settings_dns": "DNS-сервер",
"install_settings_dns_desc": "Вам потрібно буде налаштувати свої пристрої або маршрутизатор для використання DNS-сервера за такими адресами:",

View File

@@ -6,18 +6,21 @@
"upstream_parallel": "Sử dụng truy vấn song song để tăng tốc độ giải quyết bằng cách truy vấn đồng thời tất cả các máy chủ ngược tuyến",
"parallel_requests": "Yêu cầu song song",
"load_balancing": "Cân bằng tải",
"load_balancing_desc": "Truy vấn một máy chủ thượng nguồn tại một thời điểm. AdGuard Home sử dụng thuật toán ngẫu nhiên có trọng số để chọn máy chủ có số lần tìm kiếm không thành công thấp nhất và thời gian tìm kiếm trung bình thấp nhất.",
"bootstrap_dns": "Máy chủ DNS Bootstrap",
"bootstrap_dns_desc": "Địa chỉ IP của máy chủ DNS được sử dụng để phân giải địa chỉ IP của trình phân giải DoH/DoT mà bạn chỉ định làm thượng nguồn. Bình luận không được phép.",
"fallback_dns_title": "Máy chủ DNS dự phòng",
"fallback_dns_desc": "Danh sách máy chủ DNS dự phòng được sử dụng khi máy chủ DNS ngược tuyến không phản hồi. Cú pháp tương tự như trong trường ngược dòng chính ở trên.",
"fallback_dns_placeholder": "Nhập một máy chủ DNS dự phòng trên mỗi dòng",
"local_ptr_title": "Máy chủ DNS riêng tư",
"local_ptr_desc": "Máy chủ DNS được AdGuard Home sử dụng cho các yêu cầu PTR, SOA và NS riêng tư. Một yêu cầu được coi là riêng tư nếu nó yêu cầu một miền ARPA chứa một mạng con trong phạm vi IP riêng tư (chẳng hạn như \"192.168.12.34\") và đến từ một máy khách có địa chỉ IP riêng tư. Nếu không được thiết lập, các trình phân giải DNS mặc định của hệ điều hành của bạn sẽ được sử dụng, ngoại trừ các địa chỉ IP của AdGuard Home.",
"local_ptr_default_resolver": "Theo mặc định, AdGuard Home sử dụng các hệ thống phân giải tên miền ngược sau: {{ip}}.",
"local_ptr_no_default_resolver": "AdGuard Home không thể xác định hệ thống phân giải tên miền ngược riêng phù hợp cho hệ thống này.",
"local_ptr_placeholder": "Nhập một địa chỉ IP trên mỗi dòng",
"resolve_clients_title": "Kích hoạt cho phép phân giải ngược về địa chỉ IP của máy khách",
"resolve_clients_desc": "Nếu được bật, AdGuard Home sẽ cố gắng phân giải ngược lại địa chỉ IP của khách hàng thành tên máy chủ của họ bằng cách gửi các truy vấn PTR tới trình phân giải tương ứng (máy chủ DNS riêng cho máy khách cục bộ, máy chủ ngược dòng cho máy khách có địa chỉ IP công cộng).",
"use_private_ptr_resolvers_title": "Sử dụng trình rDNS riêng tư",
"use_private_ptr_resolvers_desc": "Giải quyết các yêu cầu PTR, SOA và NS cho các miền ARPA chứa địa chỉ IP riêng thông qua máy chủ thượng nguồn riêng, DHCP, /etc/hosts, v. v. Nếu bị vô hiệu hóa, AdGuard Home sẽ phản hồi tất cả các yêu cầu đó bằng NXDOMAIN.",
"check_dhcp_servers": "Kiểm tra máy chủ DHCP",
"save_config": "Lưu thiết lập",
"enabled_dhcp": "Máy chủ DHCP đã kích hoạt",
@@ -151,6 +154,7 @@
"use_adguard_parental": "Sử dụng dịch vụ quản lý của phụ huynh AdGuard",
"use_adguard_parental_hint": "AdGuard Home sẽ kiểm tra nếu tên miền chứa từ khoá người lớn. Tính năng sử dụng API thân thiện với quyền riêng tư tương tự với dịch vụ bảo vệ duyệt web",
"enforce_safe_search": "Bắt buộc tìm kiếm an toàn",
"enforce_save_search_hint": "AdGuard Home sẽ thực thi tìm kiếm an toàn trong các công cụ tìm kiếm sau: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
"no_servers_specified": "Không có máy chủ nào được liệt kê",
"general_settings": "Cài đặt chung",
"dns_settings": "Cài đặt DNS",
@@ -421,6 +425,9 @@
"encryption_hostnames": "Tên máy chủ",
"encryption_reset": "Bạn có chắc chắn muốn đặt lại cài đặt mã hóa?",
"encryption_warning": "Cảnh báo",
"encryption_plain_dns_enable": "Kích hoạt DNS đơn giản",
"encryption_plain_dns_desc": "DNS đơn giản được bật theo mặc định. Bạn có thể vô hiệu hóa nó để buộc tất cả các thiết bị sử dụng DNS được mã hóa. Để thực hiện việc này, bạn phải kích hoạt ít nhất một giao thức DNS được mã hóa",
"encryption_plain_dns_error": "Để tắt DNS đơn giản, hãy bật ít nhất một giao thức DNS được mã hóa",
"topline_expiring_certificate": "Chứng chỉ SSL của bạn sắp hết hạn. Cập nhật <0>Cài đặt mã hóa</0>.",
"topline_expired_certificate": "Chứng chỉ SSL của bạn đã hết hạn. Cập nhật <0>Cài đặt mã hóa</0>.",
"form_error_port_range": "Nhập giá trị cổng trong phạm vi 80-65535",
@@ -671,6 +678,7 @@
"use_saved_key": "Sử dụng khóa đã lưu trước đó",
"parental_control": "Quản lý của phụ huynh",
"safe_browsing": "Duyệt web an toàn",
"served_from_cache_label": "Được phục vụ từ bộ nhớ đệm",
"form_error_password_length": "Mật khẩu phải dài từ {{min}} đến {{max}} ký tự",
"anonymizer_notification": "<0> Lưu ý:</0> Tính năng ẩn danh IP được bật. Bạn có thể tắt nó trong <1> Cài đặt chung</1>.",
"confirm_dns_cache_clear": "Bạn có chắc chắn muốn xóa bộ đệm ẩn DNS không?",

View File

@@ -6,18 +6,21 @@
"upstream_parallel": "使用平行查詢,同時查詢所有上游伺服器來加速解析結果",
"parallel_requests": "平行處理",
"load_balancing": "負載平衡",
"load_balancing_desc": "一次只查詢一個伺服器。AdGuard Home 會使用加權隨機取樣來選擇使用的查詢結果,以確保速度最快的伺服器能被充分運用。",
"bootstrap_dns": "引導Boostrap DNS 伺服器",
"bootstrap_dns_desc": "Bootstrap DNS 伺服器用於解析您所設定的上游 DoH/DoT 解析器的 IP 地址",
"fallback_dns_title": "備用 DNS 伺服器",
"fallback_dns_desc": "備用 DNS 伺服器列表:於主要 DNS 伺服器沒有回應時使用。語法與主要 DNS 伺服器設定欄位相同。",
"fallback_dns_placeholder": "每行輸入一個備用 DNS 伺服器",
"local_ptr_title": "私人 DNS 伺服器",
"local_ptr_desc": "AdGuard Home 用於區域 PTR 查詢的 DNS 伺服器。這些伺服器將用於解析具有私人 IP 位址的用戶端的主機名稱,例如 \"192.168.12.34\",使用 rDNS。如果沒有設定AdGuard Home 將自動使用您的系統預設 DNS 解析。",
"local_ptr_default_resolver": "AdGuard Home 預設使用以下作為 DNS 反解器:{{ip}}",
"local_ptr_no_default_resolver": "AdGuard Home 無法為此系統確定適合私有反解析器。",
"local_ptr_placeholder": "每行輸入一個伺服器位址",
"resolve_clients_title": "啟用用戶端的 IP 位址的反向解析",
"resolve_clients_desc": "透過相應的伺服器傳送 PTR 查詢(本機用戶端使用私人 DNS 伺服器,公共 IP 使用上游伺服器),將客戶端的 IP 反解為主機名稱。",
"use_private_ptr_resolvers_title": "使用私人 DNS 反解器",
"use_private_ptr_resolvers_desc": "使用這些上游為本機提供反解 DNS 查詢。如果禁用 AdGuard Home 將會對相關 PTR 請求回應 NXDOMAIN但 DHCP、/etc/hosts 等已知的用戶端除外。",
"check_dhcp_servers": "檢查 DHCP 伺服器",
"save_config": "儲存設定",
"enabled_dhcp": "DHCP 伺服器已啟動",
@@ -151,6 +154,7 @@
"use_adguard_parental": "使用 AdGuard 家長監護功能",
"use_adguard_parental_hint": "AdGuard Home 將比對查詢網域是否含有成人內容。它使用與 AdGuard 瀏覽安全一樣的尊重個人隱私的 API 來進行檢查。",
"enforce_safe_search": "強制使用安全搜尋",
"enforce_save_search_hint": "AdGuard Home 可在下列搜尋引擎使用強制安全搜尋Google、YouTube、Bing、DuckDuckGo, Yandex 和 Pixabay。",
"no_servers_specified": "沒有指定的伺服器",
"general_settings": "一般設定",
"dns_settings": "DNS 設定",

View File

@@ -20,7 +20,7 @@
"resolve_clients_title": "啟用用戶端的 IP 位址之反向的解析",
"resolve_clients_desc": "透過傳送指標PTR查詢到對應的解析器私人 DNS 伺服器供區域的用戶端,上游的伺服器供有公共 IP 位址的用戶端),反向地解析用戶端的 IP 位址變為它們的主機名稱。",
"use_private_ptr_resolvers_title": "使用私人反向的 DNS 解析器",
"use_private_ptr_resolvers_desc": "使用私人上游伺服器、DHCP、/etc/hosts 等方式解析包含私人 IP 位址的 ARPA 網域 PTR、SOA 和 NS 請求。如果禁用AdGuard Home 將對所有此類請求以 NXDOMAIN 回。",
"use_private_ptr_resolvers_desc": "通過私人上游伺服器、DHCP、/etc/hosts 等等,對包含私人 IP 位址的 ARPA 網域解析 PTR、SOA 和 NS 請求。如果禁用AdGuard Home 將對所有此類請求以 NXDOMAIN 回。",
"check_dhcp_servers": "檢查動態主機設定協定DHCP伺服器",
"save_config": "儲存配置",
"enabled_dhcp": "動態主機設定協定DHCP伺服器被啟用",

View File

@@ -46,7 +46,7 @@ export const getStats = () => async (dispatch: any) => {
const normalizedTopClients = normalizeTopStats(stats.top_clients);
const clientsParams = getParamsForClientsSearch(normalizedTopClients, 'name');
const clients = await apiClient.findClients(clientsParams);
const clients = await apiClient.searchClients(clientsParams);
const topClientsWithInfo = addClientInfo(normalizedTopClients, clients, 'name');
const normalizedStats = {

View File

@@ -415,7 +415,7 @@ class Api {
// Per-client settings
GET_CLIENTS = { path: 'clients', method: 'GET' };
FIND_CLIENTS = { path: 'clients/find', method: 'GET' };
SEARCH_CLIENTS = { path: 'clients/search', method: 'POST' };
ADD_CLIENT = { path: 'clients/add', method: 'POST' };
@@ -453,11 +453,12 @@ class Api {
return this.makeRequest(path, method, parameters);
}
findClients(params: any) {
const { path, method } = this.FIND_CLIENTS;
const url = getPathWithQueryString(path, params);
return this.makeRequest(url, method);
searchClients(config: any) {
const { path, method } = this.SEARCH_CLIENTS;
const parameters = {
data: config,
};
return this.makeRequest(path, method, parameters);
}
// DNS access settings

View File

@@ -23,7 +23,7 @@ interface RowProps {
const Row = ({ label, count, response_status, tooltipTitle, translationComponents }: RowProps) => {
const content = response_status ? (
<LogsSearchLink response_status={response_status}>{formatNumber(count)}</LogsSearchLink>
<LogsSearchLink response_status={response_status}>{count}</LogsSearchLink>
) : (
count
);
@@ -77,16 +77,16 @@ const Counters = ({ refreshButton, subtitle }: CountersProps) => {
? t('number_of_dns_query_hours', { count: msToHours(interval) })
: t('number_of_dns_query_days', { count: msToDays(interval) });
const rows = [
const rows: RowProps[] = [
{
label: 'dns_query',
count: numDnsQueries.toString(),
count: formatNumber(numDnsQueries),
tooltipTitle: dnsQueryTooltip,
response_status: RESPONSE_FILTER.ALL.QUERY,
},
{
label: 'blocked_by',
count: numBlockedFiltering.toString(),
count: formatNumber(numBlockedFiltering),
tooltipTitle: 'number_of_dns_query_blocked_24_hours',
response_status: RESPONSE_FILTER.BLOCKED.QUERY,
@@ -98,19 +98,19 @@ const Counters = ({ refreshButton, subtitle }: CountersProps) => {
},
{
label: 'stats_malware_phishing',
count: numReplacedSafebrowsing.toString(),
count: formatNumber(numReplacedSafebrowsing),
tooltipTitle: 'number_of_dns_query_blocked_24_hours_by_sec',
response_status: RESPONSE_FILTER.BLOCKED_THREATS.QUERY,
},
{
label: 'stats_adult',
count: numReplacedParental.toString(),
count: formatNumber(numReplacedParental),
tooltipTitle: 'number_of_dns_query_blocked_24_hours_adult',
response_status: RESPONSE_FILTER.BLOCKED_ADULT_WEBSITES.QUERY,
},
{
label: 'enforced_save_search',
count: numReplacedSafesearch.toString(),
count: formatNumber(numReplacedSafesearch),
tooltipTitle: 'number_of_dns_query_to_safe_search',
response_status: RESPONSE_FILTER.SAFE_SEARCH.QUERY,
},

View File

@@ -10,6 +10,7 @@ import Card from '../ui/Card';
import DomainCell from './DomainCell';
import { DASHBOARD_TABLES_DEFAULT_PAGE_SIZE, TABLES_MIN_ROWS } from '../../helpers/constants';
import { formatNumber } from '../../helpers/helpers';
interface TimeCellProps {
value?: string | number;
@@ -20,7 +21,7 @@ const TimeCell = ({ value }: TimeCellProps) => {
return '';
}
const valueInMilliseconds = round(Number(value) * 1000);
const valueInMilliseconds = formatNumber(round(Number(value) * 1000));
return (
<div className="logs__row o-hidden">

View File

@@ -154,7 +154,7 @@ const Dashboard = ({
}}
disabled={processingProtection}>
{protectionDisabledDuration
? `${t('enable_protection_timer')} ${getRemaningTimeText(protectionDisabledDuration)}`
? `${t('enable_protection_timer', { time: getRemaningTimeText(protectionDisabledDuration) })}`
: getProtectionBtnText(protectionEnabled)}
</button>

View File

@@ -306,7 +306,7 @@ const ClientsTable = ({
return content;
}
return <LogsSearchLink search={row.original.ids[0]}>{content}</LogsSearchLink>;
return <LogsSearchLink search={row.original.name}>{content}</LogsSearchLink>;
},
},
{

View File

@@ -14,6 +14,17 @@
font-size: 15px;
}
.guide__list {
margin-top: 16px;
padding-left: 0;
}
@media screen and (min-width: 768px) {
.guide__list {
padding-left: 24px;
}
}
.guide__address {
display: block;
margin-bottom: 7px;

View File

@@ -33,13 +33,13 @@ const SetupGuide = ({
<Trans>install_devices_address</Trans>:
</div>
<div className="mt-3">
<ul className="guide__list">
{dnsAddresses.map((ip: any) => (
<li key={ip} className="guide__address">
{ip}
</li>
))}
</div>
</ul>
</div>
<Guide dnsAddresses={dnsAddresses} />

View File

@@ -238,6 +238,12 @@ export default {
"homepage": "https://github.com/hagezi/dns-blocklists",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_51.txt"
},
"hagezi_samsung_tracker_blocklist": {
"name": "HaGeZi's Samsung Tracker Blocklist",
"categoryId": "other",
"homepage": "https://github.com/hagezi/dns-blocklists",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_61.txt"
},
"hagezi_the_worlds_most_abused_tlds": {
"name": "HaGeZi's The World's Most Abused TLDs",
"categoryId": "security",
@@ -256,6 +262,18 @@ export default {
"homepage": "https://github.com/hagezi/dns-blocklists",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_49.txt"
},
"hagezi_windows_office_tracker_blocklist": {
"name": "HaGeZi's Windows/Office Tracker Blocklist",
"categoryId": "other",
"homepage": "https://github.com/hagezi/dns-blocklists",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_63.txt"
},
"hagezi_xiaomi_tracking_blocklist": {
"name": "HaGeZi's Xiaomi Tracker Blocklist",
"categoryId": "other",
"homepage": "https://github.com/hagezi/dns-blocklists",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_60.txt"
},
"no_google": {
"name": "No Google",
"categoryId": "other",
@@ -340,17 +358,17 @@ export default {
"homepage": "https://github.com/uBlockOrigin/uAssets",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_50.txt"
},
"ukrainian_security_filter": {
"name": "Ukrainian Security Filter",
"categoryId": "other",
"homepage": "https://github.com/braveinnovators/ukrainian-security-filter",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_62.txt"
},
"urlhaus_filter_online": {
"name": "Malicious URL Blocklist (URLHaus)",
"categoryId": "security",
"homepage": "https://urlhaus.abuse.ch/",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_11.txt"
},
"windowsspyblocker_hosts_spy_rules": {
"name": "WindowsSpyBlocker - Hosts spy rules",
"categoryId": "other",
"homepage": "https://github.com/crazy-max/WindowsSpyBlocker",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_23.txt"
}
}
}

View File

@@ -451,13 +451,10 @@ export const getParamsForClientsSearch = (data: any, param: any, additionalParam
clients.add(e[additionalParam]);
}
});
const params = {};
const ids = Array.from(clients.values());
ids.forEach((id, i) => {
params[`ip${i}`] = id;
});
return params;
return {
clients: Array.from(clients).map((id) => ({ id })),
};
};
/**
@@ -524,7 +521,7 @@ export const getObjDiff = (initialValues: any, values: any) =>
* @param num {number} to format
* @returns {string} Returns a string with a language-sensitive representation of this number
*/
export const formatNumber = (num: any) => {
export const formatNumber = (num: number): string => {
const currentLanguage = i18n.languages[0] || DEFAULT_LANGUAGE;
return num.toLocaleString(currentLanguage);
};
@@ -673,9 +670,16 @@ export const countClientsStatistics = (ids: any, autoClients: any) => {
* @param {function} t translate
* @returns {string}
*/
export const formatElapsedMs = (elapsedMs: any, t: any) => {
const formattedElapsedMs = parseInt(elapsedMs, 10) || parseFloat(elapsedMs).toFixed(2);
return `${formattedElapsedMs} ${t('milliseconds_abbreviation')}`;
export const formatElapsedMs = (elapsedMs: string, t: (key: string) => string) => {
const parsedElapsedMs = parseInt(elapsedMs, 10);
if (Number.isNaN(parsedElapsedMs)) {
return elapsedMs;
}
const formattedMs = formatNumber(parsedElapsedMs);
return `${formattedMs} ${t('milliseconds_abbreviation')}`;
};
/**
@@ -757,12 +761,9 @@ type NestedObject = {
order: number;
};
export const getObjectKeysSorted = <
T extends Record<string, NestedObject>,
K extends keyof NestedObject
>(
export const getObjectKeysSorted = <T extends Record<string, NestedObject>, K extends keyof NestedObject>(
object: T,
sortKey: K
sortKey: K,
): string[] => {
return Object.entries(object)
.sort(([, a], [, b]) => (a[sortKey] as number) - (b[sortKey] as number))

File diff suppressed because it is too large Load Diff

51
go.mod
View File

@@ -1,24 +1,25 @@
module github.com/AdguardTeam/AdGuardHome
go 1.22.5
go 1.23.5
require (
github.com/AdguardTeam/dnsproxy v0.72.2
github.com/AdguardTeam/golibs v0.25.1
github.com/AdguardTeam/urlfilter v0.19.0
github.com/AdguardTeam/dnsproxy v0.73.5
github.com/AdguardTeam/golibs v0.31.0
github.com/AdguardTeam/urlfilter v0.20.0
github.com/NYTimes/gziphandler v1.1.1
github.com/ameshkov/dnscrypt/v2 v2.3.0
github.com/bluele/gcache v0.0.2
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500
github.com/digineo/go-ipset/v2 v2.2.1
github.com/dimfeld/httptreemux/v5 v5.5.0
github.com/fsnotify/fsnotify v1.7.0
github.com/go-ping/ping v1.1.0
github.com/fsnotify/fsnotify v1.8.0
// TODO(e.burkov): This package is deprecated; find a new one or use our
// own code for that. Perhaps, use gopacket.
github.com/go-ping/ping v1.2.0
github.com/google/go-cmp v0.6.0
github.com/google/gopacket v1.1.19
github.com/google/renameio/v2 v2.0.0
github.com/google/uuid v1.6.0
github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49
github.com/insomniacslk/dhcp v0.0.0-20241203100832-a481575ed0ef
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86
github.com/kardianos/service v1.2.2
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
@@ -27,15 +28,15 @@ require (
// TODO(a.garipov): This package is deprecated; find a new one or use our
// own code for that. Perhaps, use gopacket.
github.com/mdlayher/raw v0.1.0
github.com/miekg/dns v1.1.61
github.com/quic-go/quic-go v0.44.0
github.com/stretchr/testify v1.9.0
github.com/miekg/dns v1.1.62
github.com/quic-go/quic-go v0.48.2
github.com/stretchr/testify v1.10.0
github.com/ti-mo/netfilter v0.5.2
go.etcd.io/bbolt v1.3.10
golang.org/x/crypto v0.25.0
golang.org/x/exp v0.0.0-20240707233637-46b078467d37
golang.org/x/net v0.27.0
golang.org/x/sys v0.22.0
go.etcd.io/bbolt v1.3.11
golang.org/x/crypto v0.31.0
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67
golang.org/x/net v0.33.0
golang.org/x/sys v0.28.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
howett.net/plist v1.0.1
@@ -48,19 +49,19 @@ require (
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/google/pprof v0.0.0-20240521024322-9665fa269a30 // indirect
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/mdlayher/socket v0.5.1 // indirect
github.com/onsi/ginkgo/v2 v2.17.3 // indirect
github.com/onsi/ginkgo/v2 v2.22.1 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/tools v0.23.0 // indirect
gonum.org/v1/gonum v0.15.0 // indirect
go.uber.org/mock v0.5.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/tools v0.28.0 // indirect
gonum.org/v1/gonum v0.15.1 // indirect
)

106
go.sum
View File

@@ -1,9 +1,9 @@
github.com/AdguardTeam/dnsproxy v0.72.2 h1:0uItzXnUIuC9r+ZvPbNquGaAHvdWnWLbhSDdxsZk5og=
github.com/AdguardTeam/dnsproxy v0.72.2/go.mod h1:PA1UiTtTHMbXPv9NjHat+zrsgK8S7p/RJ+j/3tNqtUE=
github.com/AdguardTeam/golibs v0.25.1 h1:po5dBbFCoZAySsbsMN/ZRB0WTLYDA1d8BxPgvriu/EA=
github.com/AdguardTeam/golibs v0.25.1/go.mod h1:HaTyS2wCbxFudjht9N/+/Qf1b5cMad2BAYSwe7DPCXI=
github.com/AdguardTeam/urlfilter v0.19.0 h1:q7eH13+yNETlpD/VD3u5rLQOripcUdEktqZFy+KiQLk=
github.com/AdguardTeam/urlfilter v0.19.0/go.mod h1:+N54ZvxqXYLnXuvpaUhK2exDQW+djZBRSb6F6j0rkBY=
github.com/AdguardTeam/dnsproxy v0.73.5 h1:3EiVaTfmuW6PcJGbqloR6ZdHACsrYkm9z0eH8ZQTZnQ=
github.com/AdguardTeam/dnsproxy v0.73.5/go.mod h1:Oqw+k7LyjDObfYzXYCkpgtirbzbUrmotr92jrb3N09I=
github.com/AdguardTeam/golibs v0.31.0 h1:Z0oPfLTLw6iZmpE58dePy2Bel0MaX+lnDwtFEE5EmIo=
github.com/AdguardTeam/golibs v0.31.0/go.mod h1:wIkZ9o2UnppeW6/YD7yJB71dYbMhiuC1Fh/I2ElW7GQ=
github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs=
github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
@@ -25,16 +25,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/digineo/go-ipset/v2 v2.2.1 h1:k6skY+0fMqeUjjeWO/m5OuWPSZUAn7AucHMnQ1MX77g=
github.com/digineo/go-ipset/v2 v2.2.1/go.mod h1:wBsNzJlZlABHUITkesrggFnZQtgW5wkqw1uo8Qxe0VU=
github.com/dimfeld/httptreemux/v5 v5.5.0 h1:p8jkiMrCuZ0CmhwYLcbNbl7DDo21fozhKHQ2PccwOFQ=
github.com/dimfeld/httptreemux/v5 v5.5.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
github.com/go-ping/ping v1.2.0 h1:vsJ8slZBZAXNCK4dPcI2PEE9eM9n9RbXbGouVQ/Y4yQ=
github.com/go-ping/ping v1.2.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -44,8 +42,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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-20240521024322-9665fa269a30 h1:r6YdmbD41tGHeCWDyHF691LWtL7D1iSTyJaKejTWwVU=
github.com/google/pprof v0.0.0-20240521024322-9665fa269a30/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -53,8 +51,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49 h1:/OuvSMGT9+xnyZ+7MZQ1zdngaCCAdPoSw8B/uurZ7pg=
github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic=
github.com/insomniacslk/dhcp v0.0.0-20241203100832-a481575ed0ef h1:NzQKDfd5ZOPnuZYf9MnRee8x2qecsVqzsnaLjEZiBko=
github.com/insomniacslk/dhcp v0.0.0-20241203100832-a481575ed0ef/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk=
@@ -78,14 +76,14 @@ github.com/mdlayher/raw v0.1.0/go.mod h1:yXnxvs6c0XoF/aK52/H5PjsVHmWBCFfZUfoh/Y5
github.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E=
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU=
github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE=
github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
github.com/onsi/ginkgo/v2 v2.22.1 h1:QW7tbJAUDyVDVOM5dFa7qaybo+CRfR7bemlQUN6Z8aM=
github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM=
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
@@ -97,10 +95,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
@@ -109,8 +107,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/ti-mo/netfilter v0.2.0/go.mod h1:8GbBGsY/8fxtyIdfwy29JiluNcPK4K7wIT+x42ipqUU=
github.com/ti-mo/netfilter v0.5.2 h1:CTjOwFuNNeZ9QPdRXt1MZFLFUf84cKtiQutNauHWd40=
github.com/ti-mo/netfilter v0.5.2/go.mod h1:Btx3AtFiOVdHReTDmP9AE+hlkOcvIy403u7BXXbWZKo=
@@ -122,32 +120,32 @@ github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/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.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
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.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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=
@@ -158,25 +156,25 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w
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.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ=
gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0=
gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -1,94 +0,0 @@
package aghalg
// RingBuffer is the implementation of ring buffer data structure.
type RingBuffer[T any] struct {
buf []T
cur uint
full bool
}
// NewRingBuffer initializes the new instance of ring buffer. size must be
// greater or equal to zero.
func NewRingBuffer[T any](size uint) (rb *RingBuffer[T]) {
return &RingBuffer[T]{
buf: make([]T, size),
}
}
// Append appends an element to the buffer.
func (rb *RingBuffer[T]) Append(e T) {
if len(rb.buf) == 0 {
return
}
rb.buf[rb.cur] = e
rb.cur = (rb.cur + 1) % uint(cap(rb.buf))
if rb.cur == 0 {
rb.full = true
}
}
// Range calls cb for each element of the buffer. If cb returns false it stops.
func (rb *RingBuffer[T]) Range(cb func(T) (cont bool)) {
before, after := rb.splitCur()
for _, e := range before {
if !cb(e) {
return
}
}
for _, e := range after {
if !cb(e) {
return
}
}
}
// ReverseRange calls cb for each element of the buffer in reverse order. If
// cb returns false it stops.
func (rb *RingBuffer[T]) ReverseRange(cb func(T) (cont bool)) {
before, after := rb.splitCur()
for i := len(after) - 1; i >= 0; i-- {
if !cb(after[i]) {
return
}
}
for i := len(before) - 1; i >= 0; i-- {
if !cb(before[i]) {
return
}
}
}
// splitCur splits the buffer in two, before and after current position in
// chronological order. If buffer is not full, after is nil.
func (rb *RingBuffer[T]) splitCur() (before, after []T) {
if len(rb.buf) == 0 {
return nil, nil
}
cur := rb.cur
if !rb.full {
return rb.buf[:cur], nil
}
return rb.buf[cur:], rb.buf[:cur]
}
// Len returns a length of the buffer.
func (rb *RingBuffer[T]) Len() (l uint) {
if !rb.full {
return rb.cur
}
return uint(cap(rb.buf))
}
// Clear clears the buffer.
func (rb *RingBuffer[T]) Clear() {
rb.full = false
rb.cur = 0
}

View File

@@ -1,169 +0,0 @@
package aghalg_test
import (
"slices"
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/stretchr/testify/assert"
)
// elements is a helper function that returns n elements of the buffer.
func elements(b *aghalg.RingBuffer[int], n uint, reverse bool) (es []int) {
fn := b.Range
if reverse {
fn = b.ReverseRange
}
var i uint
fn(func(e int) (cont bool) {
if i >= n {
return false
}
es = append(es, e)
i++
return true
})
return es
}
func TestNewRingBuffer(t *testing.T) {
t.Run("success_and_clear", func(t *testing.T) {
b := aghalg.NewRingBuffer[int](5)
for i := range 10 {
b.Append(i)
}
assert.Equal(t, []int{5, 6, 7, 8, 9}, elements(b, b.Len(), false))
b.Clear()
assert.Zero(t, b.Len())
})
t.Run("zero", func(t *testing.T) {
b := aghalg.NewRingBuffer[int](0)
for i := range 10 {
b.Append(i)
bufLen := b.Len()
assert.EqualValues(t, 0, bufLen)
assert.Empty(t, elements(b, bufLen, false))
assert.Empty(t, elements(b, bufLen, true))
}
})
t.Run("single", func(t *testing.T) {
b := aghalg.NewRingBuffer[int](1)
for i := range 10 {
b.Append(i)
bufLen := b.Len()
assert.EqualValues(t, 1, bufLen)
assert.Equal(t, []int{i}, elements(b, bufLen, false))
assert.Equal(t, []int{i}, elements(b, bufLen, true))
}
})
}
func TestRingBuffer_Range(t *testing.T) {
const size = 5
b := aghalg.NewRingBuffer[int](size)
testCases := []struct {
name string
want []int
count int
length uint
}{{
name: "three",
count: 3,
length: 3,
want: []int{0, 1, 2},
}, {
name: "ten",
count: 10,
length: size,
want: []int{5, 6, 7, 8, 9},
}, {
name: "hundred",
count: 100,
length: size,
want: []int{95, 96, 97, 98, 99},
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
for i := range tc.count {
b.Append(i)
}
bufLen := b.Len()
assert.Equal(t, tc.length, bufLen)
want := tc.want
assert.Equal(t, want, elements(b, bufLen, false))
assert.Equal(t, want[:len(want)-1], elements(b, bufLen-1, false))
assert.Equal(t, want[:len(want)/2], elements(b, bufLen/2, false))
want = want[:cap(want)]
slices.Reverse(want)
assert.Equal(t, want, elements(b, bufLen, true))
assert.Equal(t, want[:len(want)-1], elements(b, bufLen-1, true))
assert.Equal(t, want[:len(want)/2], elements(b, bufLen/2, true))
})
}
}
func TestRingBuffer_Range_increment(t *testing.T) {
const size = 5
b := aghalg.NewRingBuffer[int](size)
testCases := []struct {
name string
want []int
}{{
name: "one",
want: []int{0},
}, {
name: "two",
want: []int{0, 1},
}, {
name: "three",
want: []int{0, 1, 2},
}, {
name: "four",
want: []int{0, 1, 2, 3},
}, {
name: "five",
want: []int{0, 1, 2, 3, 4},
}, {
name: "six",
want: []int{1, 2, 3, 4, 5},
}, {
name: "seven",
want: []int{2, 3, 4, 5, 6},
}, {
name: "eight",
want: []int{3, 4, 5, 6, 7},
}, {
name: "nine",
want: []int{4, 5, 6, 7, 8},
}, {
name: "ten",
want: []int{5, 6, 7, 8, 9},
}}
for i, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
b.Append(i)
bufLen := b.Len()
assert.Equal(t, tc.want, elements(b, bufLen, false))
slices.Reverse(tc.want)
assert.Equal(t, tc.want, elements(b, bufLen, true))
})
}
}

View File

@@ -2,19 +2,16 @@
package aghhttp
import (
"context"
"fmt"
"io"
"log/slog"
"net/http"
"github.com/AdguardTeam/AdGuardHome/internal/version"
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/log"
)
// HTTP scheme constants.
const (
SchemeHTTP = "http"
SchemeHTTPS = "https"
"github.com/AdguardTeam/golibs/logutil/slogutil"
)
// RegisterFunc is the function that sets the handler to handle the URL for the
@@ -31,12 +28,39 @@ func OK(w http.ResponseWriter) {
}
// Error writes formatted message to w and also logs it.
//
// TODO(s.chzhen): Remove it.
func Error(r *http.Request, w http.ResponseWriter, code int, format string, args ...any) {
text := fmt.Sprintf(format, args...)
log.Error("%s %s %s: %s", r.Method, r.Host, r.URL, text)
http.Error(w, text, code)
}
// ErrorAndLog writes formatted message to w and also logs it with the specified
// logging level.
func ErrorAndLog(
ctx context.Context,
l *slog.Logger,
r *http.Request,
w http.ResponseWriter,
code int,
format string,
args ...any,
) {
text := fmt.Sprintf(format, args...)
l.ErrorContext(
ctx,
"http error",
"host", r.Host,
"method", r.Method,
"raddr", r.RemoteAddr,
"request_uri", r.RequestURI,
slogutil.KeyError, text,
)
http.Error(w, text, code)
}
// UserAgent returns the ID of the service as a User-Agent string. It can also
// be used as the value of the Server HTTP header.
func UserAgent() (ua string) {

View File

@@ -7,6 +7,7 @@ import (
"bufio"
"fmt"
"io"
"io/fs"
"os"
"os/exec"
"path"
@@ -19,6 +20,13 @@ import (
"github.com/AdguardTeam/golibs/log"
)
// Default file, binary, and directory permissions.
const (
DefaultPermDir fs.FileMode = 0o700
DefaultPermExe fs.FileMode = 0o700
DefaultPermFile fs.FileMode = 0o600
)
// Unsupported is a helper that returns a wrapped [errors.ErrUnsupported].
func Unsupported(op string) (err error) {
return fmt.Errorf("%s: not supported on %s: %w", op, runtime.GOOS, errors.ErrUnsupported)
@@ -138,16 +146,6 @@ func IsOpenWrt() (ok bool) {
return isOpenWrt()
}
// NotifyReconfigureSignal notifies c on receiving reconfigure signals.
func NotifyReconfigureSignal(c chan<- os.Signal) {
notifyReconfigureSignal(c)
}
// IsReconfigureSignal returns true if sig is a reconfigure signal.
func IsReconfigureSignal(sig os.Signal) (ok bool) {
return isReconfigureSignal(sig)
}
// SendShutdownSignal sends the shutdown signal to the channel.
func SendShutdownSignal(c chan<- os.Signal) {
sendShutdownSignal(c)

View File

@@ -1,22 +1,11 @@
//go:build darwin || freebsd || linux || openbsd
//go:build unix
package aghos
import (
"os"
"os/signal"
"golang.org/x/sys/unix"
)
func notifyReconfigureSignal(c chan<- os.Signal) {
signal.Notify(c, unix.SIGHUP)
}
func isReconfigureSignal(sig os.Signal) (ok bool) {
return sig == unix.SIGHUP
}
func sendShutdownSignal(_ chan<- os.Signal) {
// On Unix we are already notified by the system.
}

View File

@@ -4,12 +4,11 @@ package aghos
import (
"os"
"os/signal"
"golang.org/x/sys/windows"
)
func setRlimit(val uint64) (err error) {
func setRlimit(_ uint64) (err error) {
return Unsupported("setrlimit")
}
@@ -38,14 +37,6 @@ func isOpenWrt() (ok bool) {
return false
}
func notifyReconfigureSignal(c chan<- os.Signal) {
signal.Notify(c, windows.SIGHUP)
}
func isReconfigureSignal(sig os.Signal) (ok bool) {
return sig == windows.SIGHUP
}
func sendShutdownSignal(c chan<- os.Signal) {
c <- os.Interrupt
}

View File

@@ -62,7 +62,9 @@ func newPendingFile(filePath string, mode fs.FileMode) (f PendingFile, err error
return nil, fmt.Errorf("opening pending file: %w", err)
}
err = file.Chmod(mode)
// TODO(e.burkov): The [os.Chmod] implementation is useless on Windows,
// investigate if it can be removed.
err = os.Chmod(file.Name(), mode)
if err != nil {
return nil, fmt.Errorf("preparing pending file: %w", err)
}

View File

@@ -58,7 +58,7 @@ func (w *FSWatcher) Add(name string) (err error) {
// ServiceWithConfig is a fake [agh.ServiceWithConfig] implementation for tests.
type ServiceWithConfig[ConfigType any] struct {
OnStart func() (err error)
OnStart func(ctx context.Context) (err error)
OnShutdown func(ctx context.Context) (err error)
OnConfig func() (c ConfigType)
}
@@ -68,8 +68,8 @@ var _ agh.ServiceWithConfig[struct{}] = (*ServiceWithConfig[struct{}])(nil)
// Start implements the [agh.ServiceWithConfig] interface for
// *ServiceWithConfig.
func (s *ServiceWithConfig[_]) Start() (err error) {
return s.OnStart()
func (s *ServiceWithConfig[_]) Start(ctx context.Context) (err error) {
return s.OnStart(ctx)
}
// Shutdown implements the [agh.ServiceWithConfig] interface for
@@ -89,14 +89,14 @@ func (s *ServiceWithConfig[ConfigType]) Config() (c ConfigType) {
// AddressProcessor is a fake [client.AddressProcessor] implementation for
// tests.
type AddressProcessor struct {
OnProcess func(ip netip.Addr)
OnProcess func(ctx context.Context, ip netip.Addr)
OnClose func() (err error)
}
// Process implements the [client.AddressProcessor] interface for
// *AddressProcessor.
func (p *AddressProcessor) Process(ip netip.Addr) {
p.OnProcess(ip)
func (p *AddressProcessor) Process(ctx context.Context, ip netip.Addr) {
p.OnProcess(ctx, ip)
}
// Close implements the [client.AddressProcessor] interface for
@@ -107,13 +107,18 @@ func (p *AddressProcessor) Close() (err error) {
// AddressUpdater is a fake [client.AddressUpdater] implementation for tests.
type AddressUpdater struct {
OnUpdateAddress func(ip netip.Addr, host string, info *whois.Info)
OnUpdateAddress func(ctx context.Context, ip netip.Addr, host string, info *whois.Info)
}
// UpdateAddress implements the [client.AddressUpdater] interface for
// *AddressUpdater.
func (p *AddressUpdater) UpdateAddress(ip netip.Addr, host string, info *whois.Info) {
p.OnUpdateAddress(ip, host, info)
func (p *AddressUpdater) UpdateAddress(
ctx context.Context,
ip netip.Addr,
host string,
info *whois.Info,
) {
p.OnUpdateAddress(ctx, ip, host, info)
}
// Package dnsforward

View File

@@ -5,6 +5,7 @@ import (
"bufio"
"bytes"
"fmt"
"log/slog"
"net"
"net/netip"
"slices"
@@ -12,7 +13,7 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/osutil"
)
@@ -38,8 +39,8 @@ type Interface interface {
}
// New returns the [Interface] properly initialized for the OS.
func New() (arp Interface) {
return newARPDB()
func New(logger *slog.Logger) (arp Interface) {
return newARPDB(logger)
}
// Empty is the [Interface] implementation that does nothing.
@@ -69,6 +70,30 @@ type Neighbor struct {
MAC net.HardwareAddr
}
// newNeighbor returns the new initialized [Neighbor] by parsing string
// representations of IP and MAC addresses.
func newNeighbor(host, ipStr, macStr string) (n *Neighbor, err error) {
defer func() { err = errors.Annotate(err, "getting arp neighbor: %w") }()
ip, err := netip.ParseAddr(ipStr)
if err != nil {
// Don't wrap the error, as it will get annotated.
return nil, err
}
mac, err := net.ParseMAC(macStr)
if err != nil {
// Don't wrap the error, as it will get annotated.
return nil, err
}
return &Neighbor{
Name: host,
IP: ip,
MAC: mac,
}, nil
}
// Clone returns the deep copy of n.
func (n Neighbor) Clone() (clone Neighbor) {
return Neighbor{
@@ -80,10 +105,10 @@ func (n Neighbor) Clone() (clone Neighbor) {
// validatedHostname returns h if it's a valid hostname, or an empty string
// otherwise, logging the validation error.
func validatedHostname(h string) (host string) {
func validatedHostname(logger *slog.Logger, h string) (host string) {
err := netutil.ValidateHostname(h)
if err != nil {
log.Debug("arpdb: parsing arp output: host: %s", err)
logger.Debug("parsing host of arp output", slogutil.KeyError, err)
return ""
}
@@ -132,15 +157,18 @@ func (ns *neighs) reset(with []Neighbor) {
// parseNeighsFunc parses the text from sc as if it'd be an output of some
// ARP-related command. lenHint is a hint for the size of the allocated slice
// of Neighbors.
type parseNeighsFunc func(sc *bufio.Scanner, lenHint int) (ns []Neighbor)
//
// TODO(s.chzhen): Return []*Neighbor instead.
type parseNeighsFunc func(logger *slog.Logger, sc *bufio.Scanner, lenHint int) (ns []Neighbor)
// cmdARPDB is the implementation of the [Interface] that uses command line to
// retrieve data.
type cmdARPDB struct {
parse parseNeighsFunc
ns *neighs
cmd string
args []string
logger *slog.Logger
parse parseNeighsFunc
ns *neighs
cmd string
args []string
}
// type check
@@ -158,7 +186,7 @@ func (arp *cmdARPDB) Refresh() (err error) {
}
sc := bufio.NewScanner(bytes.NewReader(out))
ns := arp.parse(sc, arp.ns.len())
ns := arp.parse(arp.logger, sc, arp.ns.len())
if err = sc.Err(); err != nil {
// TODO(e.burkov): This error seems unreachable. Investigate.
return fmt.Errorf("scanning the output: %w", err)

View File

@@ -4,17 +4,17 @@ package arpdb
import (
"bufio"
"net"
"net/netip"
"log/slog"
"strings"
"sync"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
)
func newARPDB() (arp *cmdARPDB) {
func newARPDB(logger *slog.Logger) (arp *cmdARPDB) {
return &cmdARPDB{
parse: parseArpA,
logger: logger,
parse: parseArpA,
ns: &neighs{
mu: &sync.RWMutex{},
ns: make([]Neighbor, 0),
@@ -33,7 +33,7 @@ func newARPDB() (arp *cmdARPDB) {
// The expected input format:
//
// host.name (192.168.0.1) at ff:ff:ff:ff:ff:ff on en0 ifscope [ethernet]
func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
func parseArpA(logger *slog.Logger, sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
ns = make([]Neighbor, 0, lenHint)
for sc.Scan() {
ln := sc.Text()
@@ -48,26 +48,15 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
continue
}
ip, err := netip.ParseAddr(ipStr[1 : len(ipStr)-1])
host := validatedHostname(logger, fields[0])
n, err := newNeighbor(host, ipStr[1:len(ipStr)-1], fields[3])
if err != nil {
log.Debug("arpdb: parsing arp output: ip: %s", err)
logger.Debug("parsing arp output", "line", ln, slogutil.KeyError, err)
continue
}
hwStr := fields[3]
mac, err := net.ParseMAC(hwStr)
if err != nil {
log.Debug("arpdb: parsing arp output: mac: %s", err)
continue
}
ns = append(ns, Neighbor{
IP: ip,
MAC: mac,
Name: validatedHostname(fields[0]),
})
ns = append(ns, *n)
}
return ns

View File

@@ -11,6 +11,7 @@ import (
"testing"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -61,7 +62,7 @@ func (s mapShell) RunCmd(cmd string, args ...string) (code int, out []byte, err
func Test_New(t *testing.T) {
var a Interface
require.NotPanics(t, func() { a = New() })
require.NotPanics(t, func() { a = New(slogutil.NewDiscardLogger()) })
assert.NotNil(t, a)
}
@@ -201,8 +202,9 @@ func Test_NewARPDBs(t *testing.T) {
func TestCmdARPDB_arpa(t *testing.T) {
a := &cmdARPDB{
cmd: "cmd",
parse: parseArpA,
logger: slogutil.NewDiscardLogger(),
cmd: "cmd",
parse: parseArpA,
ns: &neighs{
mu: &sync.RWMutex{},
ns: make([]Neighbor, 0),

View File

@@ -6,17 +6,18 @@ import (
"bufio"
"fmt"
"io/fs"
"log/slog"
"net"
"net/netip"
"strings"
"sync"
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/stringutil"
)
func newARPDB() (arp *arpdbs) {
func newARPDB(logger *slog.Logger) (arp *arpdbs) {
// Use the common storage among the implementations.
ns := &neighs{
mu: &sync.RWMutex{},
@@ -39,9 +40,10 @@ func newARPDB() (arp *arpdbs) {
},
// Then, try "arp -a -n".
&cmdARPDB{
parse: parseF,
ns: ns,
cmd: "arp",
logger: logger,
parse: parseF,
ns: ns,
cmd: "arp",
// Use -n flag to avoid resolving the hostnames of the neighbors.
// By default ARP attempts to resolve the hostnames via DNS. See
// man 8 arp.
@@ -51,10 +53,11 @@ func newARPDB() (arp *arpdbs) {
},
// Finally, try "ip neigh".
&cmdARPDB{
parse: parseIPNeigh,
ns: ns,
cmd: "ip",
args: []string{"neigh"},
logger: logger,
parse: parseIPNeigh,
ns: ns,
cmd: "ip",
args: []string{"neigh"},
},
)
}
@@ -131,7 +134,7 @@ func (arp *fsysARPDB) Neighbors() (ns []Neighbor) {
//
// IP address HW type Flags HW address Mask Device
// 192.168.11.98 0x1 0x2 5a:92:df:a9:7e:28 * wan
func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
func parseArpAWrt(logger *slog.Logger, sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
if !sc.Scan() {
// Skip the header.
return
@@ -146,25 +149,14 @@ func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
continue
}
ip, err := netip.ParseAddr(fields[0])
n, err := newNeighbor("", fields[0], fields[3])
if err != nil {
log.Debug("arpdb: parsing arp output: ip: %s", err)
logger.Debug("parsing arp output", "line", ln, slogutil.KeyError, err)
continue
}
hwStr := fields[3]
mac, err := net.ParseMAC(hwStr)
if err != nil {
log.Debug("arpdb: parsing arp output: mac: %s", err)
continue
}
ns = append(ns, Neighbor{
IP: ip,
MAC: mac,
})
ns = append(ns, *n)
}
return ns
@@ -174,7 +166,7 @@ func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
// expected input format:
//
// hostname (192.168.1.1) at ab:cd:ef:ab:cd:ef [ether] on enp0s3
func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
func parseArpA(logger *slog.Logger, sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
ns = make([]Neighbor, 0, lenHint)
for sc.Scan() {
ln := sc.Text()
@@ -189,26 +181,15 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
continue
}
ip, err := netip.ParseAddr(ipStr[1 : len(ipStr)-1])
host := validatedHostname(logger, fields[0])
n, err := newNeighbor(host, ipStr[1:len(ipStr)-1], fields[3])
if err != nil {
log.Debug("arpdb: parsing arp output: ip: %s", err)
logger.Debug("parsing arp output", "line", ln, slogutil.KeyError, err)
continue
}
hwStr := fields[3]
mac, err := net.ParseMAC(hwStr)
if err != nil {
log.Debug("arpdb: parsing arp output: mac: %s", err)
continue
}
ns = append(ns, Neighbor{
IP: ip,
MAC: mac,
Name: validatedHostname(fields[0]),
})
ns = append(ns, *n)
}
return ns
@@ -218,7 +199,7 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
// expected input format:
//
// 192.168.1.1 dev enp0s3 lladdr ab:cd:ef:ab:cd:ef REACHABLE
func parseIPNeigh(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
func parseIPNeigh(logger *slog.Logger, sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
ns = make([]Neighbor, 0, lenHint)
for sc.Scan() {
ln := sc.Text()
@@ -228,27 +209,14 @@ func parseIPNeigh(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
continue
}
n := Neighbor{}
ip, err := netip.ParseAddr(fields[0])
n, err := newNeighbor("", fields[0], fields[4])
if err != nil {
log.Debug("arpdb: parsing arp output: ip: %s", err)
logger.Debug("parsing arp output", "line", ln, slogutil.KeyError, err)
continue
} else {
n.IP = ip
}
mac, err := net.ParseMAC(fields[4])
if err != nil {
log.Debug("arpdb: parsing arp output: mac: %s", err)
continue
} else {
n.MAC = mac
}
ns = append(ns, n)
ns = append(ns, *n)
}
return ns

View File

@@ -9,6 +9,7 @@ import (
"testing"
"testing/fstest"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -69,9 +70,10 @@ func TestCmdARPDB_linux(t *testing.T) {
t.Run("wrt", func(t *testing.T) {
a := &cmdARPDB{
parse: parseArpAWrt,
cmd: "arp",
args: []string{"-a"},
logger: slogutil.NewDiscardLogger(),
parse: parseArpAWrt,
cmd: "arp",
args: []string{"-a"},
ns: &neighs{
mu: &sync.RWMutex{},
ns: make([]Neighbor, 0),
@@ -86,9 +88,10 @@ func TestCmdARPDB_linux(t *testing.T) {
t.Run("ip_neigh", func(t *testing.T) {
a := &cmdARPDB{
parse: parseIPNeigh,
cmd: "ip",
args: []string{"neigh"},
logger: slogutil.NewDiscardLogger(),
parse: parseIPNeigh,
cmd: "ip",
args: []string{"neigh"},
ns: &neighs{
mu: &sync.RWMutex{},
ns: make([]Neighbor, 0),

View File

@@ -4,17 +4,17 @@ package arpdb
import (
"bufio"
"net"
"net/netip"
"log/slog"
"strings"
"sync"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
)
func newARPDB() (arp *cmdARPDB) {
func newARPDB(logger *slog.Logger) (arp *cmdARPDB) {
return &cmdARPDB{
parse: parseArpA,
logger: logger,
parse: parseArpA,
ns: &neighs{
mu: &sync.RWMutex{},
ns: make([]Neighbor, 0),
@@ -34,7 +34,7 @@ func newARPDB() (arp *cmdARPDB) {
//
// Host Ethernet Address Netif Expire Flags
// 192.168.1.1 ab:cd:ef:ab:cd:ef em0 19m59s
func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
func parseArpA(logger *slog.Logger, sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
// Skip the header.
if !sc.Scan() {
return nil
@@ -49,27 +49,14 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
continue
}
n := Neighbor{}
ip, err := netip.ParseAddr(fields[0])
n, err := newNeighbor("", fields[0], fields[1])
if err != nil {
log.Debug("arpdb: parsing arp output: ip: %s", err)
logger.Debug("parsing arp output", "line", ln, slogutil.KeyError, err)
continue
} else {
n.IP = ip
}
mac, err := net.ParseMAC(fields[1])
if err != nil {
log.Debug("arpdb: parsing arp output: mac: %s", err)
continue
} else {
n.MAC = mac
}
ns = append(ns, n)
ns = append(ns, *n)
}
return ns

View File

@@ -4,17 +4,17 @@ package arpdb
import (
"bufio"
"net"
"net/netip"
"log/slog"
"strings"
"sync"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
)
func newARPDB() (arp *cmdARPDB) {
func newARPDB(logger *slog.Logger) (arp *cmdARPDB) {
return &cmdARPDB{
parse: parseArpA,
logger: logger,
parse: parseArpA,
ns: &neighs{
mu: &sync.RWMutex{},
ns: make([]Neighbor, 0),
@@ -31,7 +31,7 @@ func newARPDB() (arp *cmdARPDB) {
// Internet Address Physical Address Type
// 192.168.56.1 0a-00-27-00-00-00 dynamic
// 192.168.56.255 ff-ff-ff-ff-ff-ff static
func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
func parseArpA(logger *slog.Logger, sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
ns = make([]Neighbor, 0, lenHint)
for sc.Scan() {
ln := sc.Text()
@@ -44,24 +44,14 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
continue
}
ip, err := netip.ParseAddr(fields[0])
n, err := newNeighbor("", fields[0], fields[1])
if err != nil {
log.Debug("arpdb: parsing arp output: ip: %s", err)
logger.Debug("parsing arp output", "line", ln, slogutil.KeyError, err)
continue
}
mac, err := net.ParseMAC(fields[1])
if err != nil {
log.Debug("arpdb: parsing arp output: mac: %s", err)
continue
}
ns = append(ns, Neighbor{
IP: ip,
MAC: mac,
})
ns = append(ns, *n)
}
return ns

View File

@@ -2,6 +2,7 @@ package client
import (
"context"
"log/slog"
"net/netip"
"sync"
"time"
@@ -10,7 +11,7 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/rdns"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
)
@@ -20,7 +21,7 @@ const ErrClosed errors.Error = "use of closed address processor"
// AddressProcessor is the interface for types that can process clients.
type AddressProcessor interface {
Process(ip netip.Addr)
Process(ctx context.Context, ip netip.Addr)
Close() (err error)
}
@@ -31,13 +32,17 @@ type EmptyAddrProc struct{}
var _ AddressProcessor = EmptyAddrProc{}
// Process implements the [AddressProcessor] interface for EmptyAddrProc.
func (EmptyAddrProc) Process(_ netip.Addr) {}
func (EmptyAddrProc) Process(_ context.Context, _ netip.Addr) {}
// Close implements the [AddressProcessor] interface for EmptyAddrProc.
func (EmptyAddrProc) Close() (_ error) { return nil }
// DefaultAddrProcConfig is the configuration structure for address processors.
type DefaultAddrProcConfig struct {
// BaseLogger is used to create loggers with custom prefixes for sources of
// information about runtime clients. It must not be nil.
BaseLogger *slog.Logger
// DialContext is used to create TCP connections to WHOIS servers.
// DialContext must not be nil if [DefaultAddrProcConfig.UseWHOIS] is true.
DialContext aghnet.DialContextFunc
@@ -84,12 +89,15 @@ type DefaultAddrProcConfig struct {
type AddressUpdater interface {
// UpdateAddress updates information about an IP address, setting host (if
// not empty) and WHOIS information (if not nil).
UpdateAddress(ip netip.Addr, host string, info *whois.Info)
UpdateAddress(ctx context.Context, ip netip.Addr, host string, info *whois.Info)
}
// DefaultAddrProc processes incoming client addresses with rDNS and WHOIS, if
// configured, and updates that information in a client storage.
type DefaultAddrProc struct {
// logger is used to log the operation of address processor.
logger *slog.Logger
// clientIPsMu serializes closure of clientIPs and access to isClosed.
clientIPsMu *sync.Mutex
@@ -136,6 +144,7 @@ const (
// not be nil.
func NewDefaultAddrProc(c *DefaultAddrProcConfig) (p *DefaultAddrProc) {
p = &DefaultAddrProc{
logger: c.BaseLogger.With(slogutil.KeyPrefix, "addrproc"),
clientIPsMu: &sync.Mutex{},
clientIPs: make(chan netip.Addr, defaultQueueSize),
rdns: &rdns.Empty{},
@@ -147,6 +156,7 @@ func NewDefaultAddrProc(c *DefaultAddrProcConfig) (p *DefaultAddrProc) {
if c.UseRDNS {
p.rdns = rdns.New(&rdns.Config{
Logger: c.BaseLogger.With(slogutil.KeyPrefix, "rdns"),
Exchanger: c.Exchanger,
CacheSize: defaultCacheSize,
CacheTTL: defaultIPTTL,
@@ -154,13 +164,16 @@ func NewDefaultAddrProc(c *DefaultAddrProcConfig) (p *DefaultAddrProc) {
}
if c.UseWHOIS {
p.whois = newWHOIS(c.DialContext)
p.whois = newWHOIS(c.BaseLogger.With(slogutil.KeyPrefix, "whois"), c.DialContext)
}
go p.process(c.CatchPanics)
// TODO(s.chzhen): Pass context.
ctx := context.TODO()
go p.process(ctx, c.CatchPanics)
for _, ip := range c.InitialAddresses {
p.Process(ip)
p.Process(ctx, ip)
}
return p
@@ -168,7 +181,7 @@ func NewDefaultAddrProc(c *DefaultAddrProcConfig) (p *DefaultAddrProc) {
// newWHOIS returns a whois.Interface instance using the given function for
// dialing.
func newWHOIS(dialFunc aghnet.DialContextFunc) (w whois.Interface) {
func newWHOIS(logger *slog.Logger, dialFunc aghnet.DialContextFunc) (w whois.Interface) {
// TODO(s.chzhen): Consider making configurable.
const (
// defaultTimeout is the timeout for WHOIS requests.
@@ -186,6 +199,7 @@ func newWHOIS(dialFunc aghnet.DialContextFunc) (w whois.Interface) {
)
return whois.New(&whois.Config{
Logger: logger,
DialContext: dialFunc,
ServerAddr: whois.DefaultServer,
Port: whois.DefaultPort,
@@ -202,7 +216,7 @@ func newWHOIS(dialFunc aghnet.DialContextFunc) (w whois.Interface) {
var _ AddressProcessor = (*DefaultAddrProc)(nil)
// Process implements the [AddressProcessor] interface for *DefaultAddrProc.
func (p *DefaultAddrProc) Process(ip netip.Addr) {
func (p *DefaultAddrProc) Process(ctx context.Context, ip netip.Addr) {
p.clientIPsMu.Lock()
defer p.clientIPsMu.Unlock()
@@ -214,36 +228,42 @@ func (p *DefaultAddrProc) Process(ip netip.Addr) {
case p.clientIPs <- ip:
// Go on.
default:
log.Debug("clients: ip channel is full; len: %d", len(p.clientIPs))
p.logger.DebugContext(ctx, "ip channel is full", "len", len(p.clientIPs))
}
}
// process processes the incoming client IP-address information. It is intended
// to be used as a goroutine. Once clientIPs is closed, process exits.
func (p *DefaultAddrProc) process(catchPanics bool) {
func (p *DefaultAddrProc) process(ctx context.Context, catchPanics bool) {
if catchPanics {
defer log.OnPanic("addrProcessor.process")
defer slogutil.RecoverAndLog(ctx, p.logger)
}
log.Info("clients: processing addresses")
p.logger.InfoContext(ctx, "processing addresses")
for ip := range p.clientIPs {
host := p.processRDNS(ip)
info := p.processWHOIS(ip)
host := p.processRDNS(ctx, ip)
info := p.processWHOIS(ctx, ip)
p.addrUpdater.UpdateAddress(ip, host, info)
p.addrUpdater.UpdateAddress(ctx, ip, host, info)
}
log.Info("clients: finished processing addresses")
p.logger.InfoContext(ctx, "finished processing addresses")
}
// processRDNS resolves the clients' IP addresses using reverse DNS. host is
// empty if there were errors or if the information hasn't changed.
func (p *DefaultAddrProc) processRDNS(ip netip.Addr) (host string) {
func (p *DefaultAddrProc) processRDNS(ctx context.Context, ip netip.Addr) (host string) {
start := time.Now()
log.Debug("clients: processing %s with rdns", ip)
p.logger.DebugContext(ctx, "processing rdns", "ip", ip)
defer func() {
log.Debug("clients: finished processing %s with rdns in %s", ip, time.Since(start))
p.logger.DebugContext(
ctx,
"finished processing rdns",
"ip", ip,
"host", host,
"elapsed", time.Since(start),
)
}()
ok := p.shouldResolve(ip)
@@ -251,7 +271,7 @@ func (p *DefaultAddrProc) processRDNS(ip netip.Addr) (host string) {
return
}
host, changed := p.rdns.Process(ip)
host, changed := p.rdns.Process(ctx, ip)
if !changed {
host = ""
}
@@ -268,16 +288,22 @@ func (p *DefaultAddrProc) shouldResolve(ip netip.Addr) (ok bool) {
// processWHOIS looks up the information about clients' IP addresses in the
// WHOIS databases. info is nil if there were errors or if the information
// hasn't changed.
func (p *DefaultAddrProc) processWHOIS(ip netip.Addr) (info *whois.Info) {
func (p *DefaultAddrProc) processWHOIS(ctx context.Context, ip netip.Addr) (info *whois.Info) {
start := time.Now()
log.Debug("clients: processing %s with whois", ip)
p.logger.DebugContext(ctx, "processing whois", "ip", ip)
defer func() {
log.Debug("clients: finished processing %s with whois in %s", ip, time.Since(start))
p.logger.DebugContext(
ctx,
"finished processing whois",
"ip", ip,
"whois", info,
"elapsed", time.Since(start),
)
}()
// TODO(s.chzhen): Move the timeout logic from WHOIS configuration to the
// context.
info, changed := p.whois.Process(context.Background(), ip)
info, changed := p.whois.Process(ctx, ip)
if !changed {
info = nil
}

View File

@@ -13,6 +13,7 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/AdguardTeam/golibs/testutil/fakenet"
@@ -25,7 +26,8 @@ func TestEmptyAddrProc(t *testing.T) {
p := client.EmptyAddrProc{}
assert.NotPanics(t, func() {
p.Process(testIP)
ctx := testutil.ContextWithTimeout(t, testTimeout)
p.Process(ctx, testIP)
})
assert.NotPanics(t, func() {
@@ -99,6 +101,7 @@ func TestDefaultAddrProc_Process_rDNS(t *testing.T) {
updInfoCh := make(chan *whois.Info, 1)
p := client.NewDefaultAddrProc(&client.DefaultAddrProcConfig{
BaseLogger: slogutil.NewDiscardLogger(),
DialContext: func(_ context.Context, _, _ string) (conn net.Conn, err error) {
panic("not implemented")
},
@@ -118,7 +121,8 @@ func TestDefaultAddrProc_Process_rDNS(t *testing.T) {
})
testutil.CleanupAndRequireSuccess(t, p.Close)
p.Process(tc.ip)
ctx := testutil.ContextWithTimeout(t, testTimeout)
p.Process(ctx, tc.ip)
if !tc.wantUpd {
return
@@ -144,8 +148,8 @@ func newOnUpdateAddress(
ips chan<- netip.Addr,
hosts chan<- string,
infos chan<- *whois.Info,
) (f func(ip netip.Addr, host string, info *whois.Info)) {
return func(ip netip.Addr, host string, info *whois.Info) {
) (f func(ctx context.Context, ip netip.Addr, host string, info *whois.Info)) {
return func(ctx context.Context, ip netip.Addr, host string, info *whois.Info) {
if !want && (host != "" || info != nil) {
panic(fmt.Errorf("got unexpected update for %v with %q and %v", ip, host, info))
}
@@ -208,6 +212,7 @@ func TestDefaultAddrProc_Process_WHOIS(t *testing.T) {
updInfoCh := make(chan *whois.Info, 1)
p := client.NewDefaultAddrProc(&client.DefaultAddrProcConfig{
BaseLogger: slogutil.NewDiscardLogger(),
DialContext: func(_ context.Context, _, _ string) (conn net.Conn, err error) {
return whoisConn, nil
},
@@ -227,7 +232,8 @@ func TestDefaultAddrProc_Process_WHOIS(t *testing.T) {
})
testutil.CleanupAndRequireSuccess(t, p.Close)
p.Process(testIP)
ctx := testutil.ContextWithTimeout(t, testTimeout)
p.Process(ctx, testIP)
if !tc.wantUpd {
return
@@ -248,7 +254,9 @@ func TestDefaultAddrProc_Process_WHOIS(t *testing.T) {
func TestDefaultAddrProc_Close(t *testing.T) {
t.Parallel()
p := client.NewDefaultAddrProc(&client.DefaultAddrProcConfig{})
p := client.NewDefaultAddrProc(&client.DefaultAddrProcConfig{
BaseLogger: slogutil.NewDiscardLogger(),
})
err := p.Close()
assert.NoError(t, err)

View File

@@ -8,6 +8,7 @@ import (
"encoding"
"fmt"
"net/netip"
"slices"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
)
@@ -118,8 +119,9 @@ func (r *Runtime) Info() (cs Source, host string) {
return cs, info[0]
}
// SetInfo sets a host as a client information from the cs.
func (r *Runtime) SetInfo(cs Source, hosts []string) {
// setInfo sets a host as a client information from the cs.
func (r *Runtime) setInfo(cs Source, hosts []string) {
// TODO(s.chzhen): Use contract where hosts must contain non-empty host.
if len(hosts) == 1 && hosts[0] == "" {
hosts = []string{}
}
@@ -136,13 +138,13 @@ func (r *Runtime) SetInfo(cs Source, hosts []string) {
}
}
// WHOIS returns a WHOIS client information.
// WHOIS returns a copy of WHOIS client information.
func (r *Runtime) WHOIS() (info *whois.Info) {
return r.whois
return r.whois.Clone()
}
// SetWHOIS sets a WHOIS client information. info must be non-nil.
func (r *Runtime) SetWHOIS(info *whois.Info) {
// setWHOIS sets a WHOIS client information. info must be non-nil.
func (r *Runtime) setWHOIS(info *whois.Info) {
r.whois = info
}
@@ -175,3 +177,15 @@ func (r *Runtime) isEmpty() (ok bool) {
func (r *Runtime) Addr() (ip netip.Addr) {
return r.ip
}
// clone returns a deep copy of the runtime client.
func (r *Runtime) clone() (c *Runtime) {
return &Runtime{
ip: r.ip,
whois: r.whois.Clone(),
arp: slices.Clone(r.arp),
rdns: slices.Clone(r.rdns),
dhcp: slices.Clone(r.dhcp),
hostsFile: slices.Clone(r.hostsFile),
}
}

View File

@@ -2,6 +2,7 @@ package client
import (
"fmt"
"maps"
"net"
"net/netip"
"slices"
@@ -9,7 +10,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/golibs/errors"
"golang.org/x/exp/maps"
)
// macKey contains MAC as byte array of 6, 8, or 20 bytes.
@@ -330,12 +330,14 @@ func (ci *index) size() (n int) {
// rangeByName is like [Index.Range] but sorts the persistent clients by name
// before iterating ensuring a predictable order.
func (ci *index) rangeByName(f func(c *Persistent) (cont bool)) {
cs := maps.Values(ci.uidToClient)
slices.SortFunc(cs, func(a, b *Persistent) (n int) {
return strings.Compare(a.Name, b.Name)
})
clients := slices.SortedStableFunc(
maps.Values(ci.uidToClient),
func(a, b *Persistent) (res int) {
return strings.Compare(a.Name, b.Name)
},
)
for _, c := range cs {
for _, c := range clients {
if !f(c) {
break
}

View File

@@ -1,21 +1,20 @@
package client
import (
"context"
"encoding"
"fmt"
"log/slog"
"net"
"net/netip"
"slices"
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/AdGuardHome/internal/filtering/safesearch"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/google/uuid"
)
@@ -136,7 +135,8 @@ type Persistent struct {
}
// validate returns an error if persistent client information contains errors.
func (c *Persistent) validate(allTags *container.MapSet[string]) (err error) {
// allTags must be sorted.
func (c *Persistent) validate(ctx context.Context, l *slog.Logger, allTags []string) (err error) {
switch {
case c.Name == "":
return errors.Error("empty name")
@@ -153,11 +153,12 @@ func (c *Persistent) validate(allTags *container.MapSet[string]) (err error) {
err = conf.Close()
if err != nil {
log.Error("client: closing upstream config: %s", err)
l.ErrorContext(ctx, "client: closing upstream config", slogutil.KeyError, err)
}
for _, t := range c.Tags {
if !allTags.Has(t) {
_, ok := slices.BinarySearch(allTags, t)
if !ok {
return fmt.Errorf("invalid tag: %q", t)
}
}
@@ -322,20 +323,3 @@ func (c *Persistent) CloseUpstreams() (err error) {
return nil
}
// SetSafeSearch initializes and sets the safe search filter for this client.
func (c *Persistent) SetSafeSearch(
conf filtering.SafeSearchConfig,
cacheSize uint,
cacheTTL time.Duration,
) (err error) {
ss, err := safesearch.NewDefault(conf, fmt.Sprintf("client %q", c.Name), cacheSize, cacheTTL)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
}
c.SafeSearch = ss
return nil
}

View File

@@ -1,11 +1,8 @@
package client
import (
"net/netip"
"testing"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -125,69 +122,3 @@ func TestPersistent_EqualIDs(t *testing.T) {
})
}
}
func TestPersistent_Validate(t *testing.T) {
const (
allowedTag = "allowed_tag"
notAllowedTag = "not_allowed_tag"
)
allowedTags := container.NewMapSet(allowedTag)
testCases := []struct {
name string
cli *Persistent
wantErrMsg string
}{{
name: "success",
cli: &Persistent{
Name: "basic",
IPs: []netip.Addr{
netip.MustParseAddr("1.2.3.4"),
},
UID: MustNewUID(),
},
wantErrMsg: "",
}, {
name: "empty_name",
cli: &Persistent{
Name: "",
},
wantErrMsg: "empty name",
}, {
name: "no_id",
cli: &Persistent{
Name: "no_id",
},
wantErrMsg: "id required",
}, {
name: "no_uid",
cli: &Persistent{
Name: "no_uid",
IPs: []netip.Addr{
netip.MustParseAddr("1.2.3.4"),
},
},
wantErrMsg: "uid required",
}, {
name: "not_allowed_tag",
cli: &Persistent{
Name: "basic",
IPs: []netip.Addr{
netip.MustParseAddr("1.2.3.4"),
},
UID: MustNewUID(),
Tags: []string{
notAllowedTag,
},
},
wantErrMsg: `invalid tag: "` + notAllowedTag + `"`,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := tc.cli.validate(allowedTags)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
})
}
}

View File

@@ -2,39 +2,34 @@ package client
import "net/netip"
// RuntimeIndex stores information about runtime clients.
type RuntimeIndex struct {
// runtimeIndex stores information about runtime clients.
type runtimeIndex struct {
// index maps IP address to runtime client.
index map[netip.Addr]*Runtime
}
// NewRuntimeIndex returns initialized runtime index.
func NewRuntimeIndex() (ri *RuntimeIndex) {
return &RuntimeIndex{
// newRuntimeIndex returns initialized runtime index.
func newRuntimeIndex() (ri *runtimeIndex) {
return &runtimeIndex{
index: map[netip.Addr]*Runtime{},
}
}
// Client returns the saved runtime client by ip. If no such client exists,
// client returns the saved runtime client by ip. If no such client exists,
// returns nil.
func (ri *RuntimeIndex) Client(ip netip.Addr) (rc *Runtime) {
func (ri *runtimeIndex) client(ip netip.Addr) (rc *Runtime) {
return ri.index[ip]
}
// Add saves the runtime client in the index. IP address of a client must be
// add saves the runtime client in the index. IP address of a client must be
// unique. See [Runtime.Client]. rc must not be nil.
func (ri *RuntimeIndex) Add(rc *Runtime) {
func (ri *runtimeIndex) add(rc *Runtime) {
ip := rc.Addr()
ri.index[ip] = rc
}
// Size returns the number of the runtime clients.
func (ri *RuntimeIndex) Size() (n int) {
return len(ri.index)
}
// Range calls f for each runtime client in an undefined order.
func (ri *RuntimeIndex) Range(f func(rc *Runtime) (cont bool)) {
// rangeClients calls f for each runtime client in an undefined order.
func (ri *runtimeIndex) rangeClients(f func(rc *Runtime) (cont bool)) {
for _, rc := range ri.index {
if !f(rc) {
return
@@ -42,17 +37,31 @@ func (ri *RuntimeIndex) Range(f func(rc *Runtime) (cont bool)) {
}
}
// Delete removes the runtime client by ip.
func (ri *RuntimeIndex) Delete(ip netip.Addr) {
delete(ri.index, ip)
// setInfo sets the client information from cs for runtime client stored by ip.
// If no such client exists, it creates one.
func (ri *runtimeIndex) setInfo(ip netip.Addr, cs Source, hosts []string) (rc *Runtime) {
rc = ri.index[ip]
if rc == nil {
rc = NewRuntime(ip)
ri.add(rc)
}
rc.setInfo(cs, hosts)
return rc
}
// DeleteBySource removes all runtime clients that have information only from
// the specified source and returns the number of removed clients.
func (ri *RuntimeIndex) DeleteBySource(src Source) (n int) {
for ip, rc := range ri.index {
// clearSource removes information from the specified source from all clients.
func (ri *runtimeIndex) clearSource(src Source) {
for _, rc := range ri.index {
rc.unset(src)
}
}
// removeEmpty removes empty runtime clients and returns the number of removed
// clients.
func (ri *runtimeIndex) removeEmpty() (n int) {
for ip, rc := range ri.index {
if rc.isEmpty() {
delete(ri.index, ip)
n++

View File

@@ -1,85 +0,0 @@
package client_test
import (
"net/netip"
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/stretchr/testify/assert"
)
func TestRuntimeIndex(t *testing.T) {
const cliSrc = client.SourceARP
var (
ip1 = netip.MustParseAddr("1.1.1.1")
ip2 = netip.MustParseAddr("2.2.2.2")
ip3 = netip.MustParseAddr("3.3.3.3")
)
ri := client.NewRuntimeIndex()
currentSize := 0
testCases := []struct {
ip netip.Addr
name string
hosts []string
src client.Source
}{{
src: cliSrc,
ip: ip1,
name: "1",
hosts: []string{"host1"},
}, {
src: cliSrc,
ip: ip2,
name: "2",
hosts: []string{"host2"},
}, {
src: cliSrc,
ip: ip3,
name: "3",
hosts: []string{"host3"},
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
rc := client.NewRuntime(tc.ip)
rc.SetInfo(tc.src, tc.hosts)
ri.Add(rc)
currentSize++
got := ri.Client(tc.ip)
assert.Equal(t, rc, got)
})
}
t.Run("size", func(t *testing.T) {
assert.Equal(t, currentSize, ri.Size())
})
t.Run("range", func(t *testing.T) {
s := 0
ri.Range(func(rc *client.Runtime) (cont bool) {
s++
return true
})
assert.Equal(t, currentSize, s)
})
t.Run("delete", func(t *testing.T) {
ri.Delete(ip1)
currentSize--
assert.Equal(t, currentSize, ri.Size())
})
t.Run("delete_by_src", func(t *testing.T) {
assert.Equal(t, currentSize, ri.DeleteBySource(cliSrc))
assert.Equal(t, 0, ri.Size())
})
}

View File

@@ -1,28 +1,121 @@
package client
import (
"context"
"fmt"
"log/slog"
"net"
"net/netip"
"slices"
"sync"
"time"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/AdGuardHome/internal/arpdb"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/hostsfile"
"github.com/AdguardTeam/golibs/logutil/slogutil"
)
// Config is the client storage configuration structure.
//
// TODO(s.chzhen): Expand.
type Config struct {
// AllowedTags is a list of all allowed client tags.
AllowedTags []string
// allowedTags is the list of available client tags.
var allowedTags = []string{
"device_audio",
"device_camera",
"device_gameconsole",
"device_laptop",
"device_nas", // Network-attached Storage
"device_other",
"device_pc",
"device_phone",
"device_printer",
"device_securityalarm",
"device_tablet",
"device_tv",
"os_android",
"os_ios",
"os_linux",
"os_macos",
"os_other",
"os_windows",
"user_admin",
"user_child",
"user_regular",
}
// DHCP is an interface for accessing DHCP lease data the [Storage] needs.
type DHCP interface {
// Leases returns all the DHCP leases.
Leases() (leases []*dhcpsvc.Lease)
// HostByIP returns the hostname of the DHCP client with the given IP
// address. host will be empty if there is no such client, due to an
// assumption that a DHCP client must always have a hostname.
HostByIP(ip netip.Addr) (host string)
// MACByIP returns the MAC address for the given IP address leased. It
// returns nil if there is no such client, due to an assumption that a DHCP
// client must always have a MAC address.
MACByIP(ip netip.Addr) (mac net.HardwareAddr)
}
// EmptyDHCP is the empty [DHCP] implementation that does nothing.
type EmptyDHCP struct{}
// type check
var _ DHCP = EmptyDHCP{}
// Leases implements the [DHCP] interface for emptyDHCP.
func (EmptyDHCP) Leases() (leases []*dhcpsvc.Lease) { return nil }
// HostByIP implements the [DHCP] interface for emptyDHCP.
func (EmptyDHCP) HostByIP(_ netip.Addr) (host string) { return "" }
// MACByIP implements the [DHCP] interface for emptyDHCP.
func (EmptyDHCP) MACByIP(_ netip.Addr) (mac net.HardwareAddr) { return nil }
// HostsContainer is an interface for receiving updates to the system hosts
// file.
type HostsContainer interface {
Upd() (updates <-chan *hostsfile.DefaultStorage)
}
// StorageConfig is the client storage configuration structure.
type StorageConfig struct {
// Logger is used for logging the operation of the client storage. It must
// not be nil.
Logger *slog.Logger
// DHCP is used to match IPs against MACs of persistent clients and update
// [SourceDHCP] runtime client information. It must not be nil.
DHCP DHCP
// EtcHosts is used to update [SourceHostsFile] runtime client information.
EtcHosts HostsContainer
// ARPDB is used to update [SourceARP] runtime client information.
ARPDB arpdb.Interface
// InitialClients is a list of persistent clients parsed from the
// configuration file. Each client must not be nil.
InitialClients []*Persistent
// ARPClientsUpdatePeriod defines how often [SourceARP] runtime client
// information is updated.
ARPClientsUpdatePeriod time.Duration
// RuntimeSourceDHCP specifies whether to update [SourceDHCP] information
// of runtime clients.
RuntimeSourceDHCP bool
}
// Storage contains information about persistent and runtime clients.
type Storage struct {
// allowedTags is a set of all allowed tags.
allowedTags *container.MapSet[string]
// logger is used for logging the operation of the client storage. It must
// not be nil.
logger *slog.Logger
// mu protects indexes of persistent and runtime clients.
mu *sync.Mutex
@@ -31,28 +124,277 @@ type Storage struct {
index *index
// runtimeIndex contains information about runtime clients.
runtimeIndex *runtimeIndex
// dhcp is used to update [SourceDHCP] runtime client information.
dhcp DHCP
// etcHosts is used to update [SourceHostsFile] runtime client information.
etcHosts HostsContainer
// arpDB is used to update [SourceARP] runtime client information.
arpDB arpdb.Interface
// done is the shutdown signaling channel.
done chan struct{}
// allowedTags is a sorted list of all allowed tags. It must not be
// modified after initialization.
//
// TODO(s.chzhen): Use it.
runtimeIndex *RuntimeIndex
// TODO(s.chzhen): Use custom type.
allowedTags []string
// arpClientsUpdatePeriod defines how often [SourceARP] runtime client
// information is updated. It must be greater than zero.
arpClientsUpdatePeriod time.Duration
// runtimeSourceDHCP specifies whether to update [SourceDHCP] information
// of runtime clients.
runtimeSourceDHCP bool
}
// NewStorage returns initialized client storage. conf must not be nil.
func NewStorage(conf *Config) (s *Storage) {
allowedTags := container.NewMapSet(conf.AllowedTags...)
func NewStorage(ctx context.Context, conf *StorageConfig) (s *Storage, err error) {
tags := slices.Clone(allowedTags)
slices.Sort(tags)
return &Storage{
allowedTags: allowedTags,
mu: &sync.Mutex{},
index: newIndex(),
runtimeIndex: NewRuntimeIndex(),
s = &Storage{
logger: conf.Logger,
mu: &sync.Mutex{},
index: newIndex(),
runtimeIndex: newRuntimeIndex(),
dhcp: conf.DHCP,
etcHosts: conf.EtcHosts,
arpDB: conf.ARPDB,
done: make(chan struct{}),
allowedTags: tags,
arpClientsUpdatePeriod: conf.ARPClientsUpdatePeriod,
runtimeSourceDHCP: conf.RuntimeSourceDHCP,
}
for i, p := range conf.InitialClients {
err = s.Add(ctx, p)
if err != nil {
return nil, fmt.Errorf("adding client %q at index %d: %w", p.Name, i, err)
}
}
s.ReloadARP(ctx)
return s, nil
}
// Start starts the goroutines for updating the runtime client information.
//
// TODO(s.chzhen): Pass context.
func (s *Storage) Start(ctx context.Context) (err error) {
go s.periodicARPUpdate(ctx)
go s.handleHostsUpdates(ctx)
return nil
}
// Shutdown gracefully stops the client storage.
//
// TODO(s.chzhen): Pass context.
func (s *Storage) Shutdown(_ context.Context) (err error) {
close(s.done)
return s.closeUpstreams()
}
// periodicARPUpdate periodically reloads runtime clients from ARP. It is
// intended to be used as a goroutine.
func (s *Storage) periodicARPUpdate(ctx context.Context) {
defer slogutil.RecoverAndLog(ctx, s.logger)
t := time.NewTicker(s.arpClientsUpdatePeriod)
for {
select {
case <-t.C:
s.ReloadARP(ctx)
case <-s.done:
return
}
}
}
// ReloadARP reloads runtime clients from ARP, if configured.
func (s *Storage) ReloadARP(ctx context.Context) {
if s.arpDB != nil {
s.addFromSystemARP(ctx)
}
}
// addFromSystemARP adds the IP-hostname pairings from the output of the arp -a
// command.
func (s *Storage) addFromSystemARP(ctx context.Context) {
s.mu.Lock()
defer s.mu.Unlock()
if err := s.arpDB.Refresh(); err != nil {
s.arpDB = arpdb.Empty{}
s.logger.ErrorContext(ctx, "refreshing arp container", slogutil.KeyError, err)
return
}
ns := s.arpDB.Neighbors()
if len(ns) == 0 {
s.logger.DebugContext(ctx, "refreshing arp container: the update is empty")
return
}
src := SourceARP
s.runtimeIndex.clearSource(src)
for _, n := range ns {
s.runtimeIndex.setInfo(n.IP, src, []string{n.Name})
}
removed := s.runtimeIndex.removeEmpty()
s.logger.DebugContext(
ctx,
"updating client aliases from arp neighborhood",
"added", len(ns),
"removed", removed,
)
}
// handleHostsUpdates receives the updates from the hosts container and adds
// them to the clients storage. It is intended to be used as a goroutine.
func (s *Storage) handleHostsUpdates(ctx context.Context) {
if s.etcHosts == nil {
return
}
defer slogutil.RecoverAndLog(ctx, s.logger)
for {
select {
case upd, ok := <-s.etcHosts.Upd():
if !ok {
return
}
s.addFromHostsFile(ctx, upd)
case <-s.done:
return
}
}
}
// addFromHostsFile fills the client-hostname pairing index from the system's
// hosts files.
func (s *Storage) addFromHostsFile(ctx context.Context, hosts *hostsfile.DefaultStorage) {
s.mu.Lock()
defer s.mu.Unlock()
src := SourceHostsFile
s.runtimeIndex.clearSource(src)
added := 0
hosts.RangeNames(func(addr netip.Addr, names []string) (cont bool) {
// Only the first name of the first record is considered a canonical
// hostname for the IP address.
//
// TODO(e.burkov): Consider using all the names from all the records.
s.runtimeIndex.setInfo(addr, src, []string{names[0]})
added++
return true
})
removed := s.runtimeIndex.removeEmpty()
s.logger.DebugContext(
ctx,
"updating client aliases from system hosts file",
"added", added,
"removed", removed,
)
}
// type check
var _ AddressUpdater = (*Storage)(nil)
// UpdateAddress implements the [AddressUpdater] interface for *Storage
func (s *Storage) UpdateAddress(ctx context.Context, ip netip.Addr, host string, info *whois.Info) {
// Common fast path optimization.
if host == "" && info == nil {
return
}
s.mu.Lock()
defer s.mu.Unlock()
if host != "" {
s.runtimeIndex.setInfo(ip, SourceRDNS, []string{host})
}
if info != nil {
s.setWHOISInfo(ctx, ip, info)
}
}
// UpdateDHCP updates [SourceDHCP] runtime client information.
func (s *Storage) UpdateDHCP(ctx context.Context) {
if s.dhcp == nil || !s.runtimeSourceDHCP {
return
}
s.mu.Lock()
defer s.mu.Unlock()
src := SourceDHCP
s.runtimeIndex.clearSource(src)
added := 0
for _, l := range s.dhcp.Leases() {
s.runtimeIndex.setInfo(l.IP, src, []string{l.Hostname})
added++
}
removed := s.runtimeIndex.removeEmpty()
s.logger.DebugContext(
ctx,
"updating client aliases from dhcp",
"added", added,
"removed", removed,
)
}
// setWHOISInfo sets the WHOIS information for a runtime client.
func (s *Storage) setWHOISInfo(ctx context.Context, ip netip.Addr, wi *whois.Info) {
_, ok := s.index.findByIP(ip)
if ok {
s.logger.DebugContext(
ctx,
"persistent client is already created, ignore whois info",
"ip", ip,
)
return
}
rc := s.runtimeIndex.client(ip)
if rc == nil {
rc = NewRuntime(ip)
s.runtimeIndex.add(rc)
}
rc.setWHOIS(wi)
s.logger.DebugContext(ctx, "set whois info for runtime client", "ip", ip, "whois", wi)
}
// Add stores persistent client information or returns an error.
func (s *Storage) Add(p *Persistent) (err error) {
func (s *Storage) Add(ctx context.Context, p *Persistent) (err error) {
defer func() { err = errors.Annotate(err, "adding client: %w") }()
err = p.validate(s.allowedTags)
err = p.validate(ctx, s.logger, s.allowedTags)
if err != nil {
// Don't wrap the error since there is already an annotation deferred.
return err
@@ -75,7 +417,13 @@ func (s *Storage) Add(p *Persistent) (err error) {
s.index.add(p)
log.Debug("client storage: added %q: IDs: %q [%d]", p.Name, p.IDs(), s.index.size())
s.logger.DebugContext(
ctx,
"client added",
"name", p.Name,
"ids", p.IDs(),
"clients_count", s.index.size(),
)
return nil
}
@@ -95,6 +443,9 @@ func (s *Storage) FindByName(name string) (p *Persistent, ok bool) {
// Find finds persistent client by string representation of the client ID, 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()
@@ -104,6 +455,16 @@ func (s *Storage) Find(id string) (p *Persistent, ok bool) {
return p.ShallowClone(), ok
}
ip, err := netip.ParseAddr(id)
if err != nil {
return nil, false
}
foundMAC := s.dhcp.MACByIP(ip)
if foundMAC != nil {
return s.FindByMAC(foundMAC)
}
return nil, false
}
@@ -131,11 +492,9 @@ 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.
// 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) {
s.mu.Lock()
defer s.mu.Unlock()
p, ok = s.index.findByMAC(mac)
if ok {
return p.ShallowClone(), ok
@@ -146,7 +505,7 @@ func (s *Storage) FindByMAC(mac net.HardwareAddr) (p *Persistent, ok bool) {
// RemoveByName removes persistent client information. ok is false if no such
// client exists by that name.
func (s *Storage) RemoveByName(name string) (ok bool) {
func (s *Storage) RemoveByName(ctx context.Context, name string) (ok bool) {
s.mu.Lock()
defer s.mu.Unlock()
@@ -156,7 +515,7 @@ func (s *Storage) RemoveByName(name string) (ok bool) {
}
if err := p.CloseUpstreams(); err != nil {
log.Error("client storage: removing client %q: %s", p.Name, err)
s.logger.ErrorContext(ctx, "removing client", "name", p.Name, slogutil.KeyError, err)
}
s.index.remove(p)
@@ -166,10 +525,10 @@ func (s *Storage) RemoveByName(name string) (ok bool) {
// Update finds the stored persistent client by its name and updates its
// information from p.
func (s *Storage) Update(name string, p *Persistent) (err error) {
func (s *Storage) Update(ctx context.Context, name string, p *Persistent) (err error) {
defer func() { err = errors.Annotate(err, "updating client: %w") }()
err = p.validate(s.allowedTags)
err = p.validate(ctx, s.logger, s.allowedTags)
if err != nil {
// Don't wrap the error since there is already an annotation deferred.
return err
@@ -217,8 +576,8 @@ func (s *Storage) Size() (n int) {
return s.index.size()
}
// CloseUpstreams closes upstream configurations of persistent clients.
func (s *Storage) CloseUpstreams() (err error) {
// closeUpstreams closes upstream configurations of persistent clients.
func (s *Storage) closeUpstreams() (err error) {
s.mu.Lock()
defer s.mu.Unlock()
@@ -227,63 +586,39 @@ func (s *Storage) CloseUpstreams() (err error) {
// ClientRuntime returns a copy of the saved runtime client by ip. If no such
// client exists, returns nil.
//
// TODO(s.chzhen): Use it.
func (s *Storage) ClientRuntime(ip netip.Addr) (rc *Runtime) {
s.mu.Lock()
defer s.mu.Unlock()
return s.runtimeIndex.Client(ip)
}
rc = s.runtimeIndex.client(ip)
if rc != nil {
return rc.clone()
}
// AddRuntime saves the runtime client information in the storage. IP address
// of a client must be unique. rc must not be nil.
//
// TODO(s.chzhen): Use it.
func (s *Storage) AddRuntime(rc *Runtime) {
s.mu.Lock()
defer s.mu.Unlock()
if !s.runtimeSourceDHCP {
return nil
}
s.runtimeIndex.Add(rc)
}
host := s.dhcp.HostByIP(ip)
if host == "" {
return nil
}
// SizeRuntime returns the number of the runtime clients.
//
// TODO(s.chzhen): Use it.
func (s *Storage) SizeRuntime() (n int) {
s.mu.Lock()
defer s.mu.Unlock()
rc = s.runtimeIndex.setInfo(ip, SourceDHCP, []string{host})
return s.runtimeIndex.Size()
return rc.clone()
}
// RangeRuntime calls f for each runtime client in an undefined order.
//
// TODO(s.chzhen): Use it.
func (s *Storage) RangeRuntime(f func(rc *Runtime) (cont bool)) {
s.mu.Lock()
defer s.mu.Unlock()
s.runtimeIndex.Range(f)
s.runtimeIndex.rangeClients(f)
}
// DeleteRuntime removes the runtime client by ip.
//
// TODO(s.chzhen): Use it.
func (s *Storage) DeleteRuntime(ip netip.Addr) {
s.mu.Lock()
defer s.mu.Unlock()
s.runtimeIndex.Delete(ip)
}
// DeleteBySource removes all runtime clients that have information only from
// the specified source and returns the number of removed clients.
//
// TODO(s.chzhen): Use it.
func (s *Storage) DeleteBySource(src Source) (n int) {
s.mu.Lock()
defer s.mu.Unlock()
return s.runtimeIndex.DeleteBySource(src)
// AllowedTags returns the list of available client tags. tags must not be
// modified.
func (s *Storage) AllowedTags() (tags []string) {
return s.allowedTags
}

View File

@@ -3,28 +3,549 @@ package client_test
import (
"net"
"net/netip"
"runtime"
"slices"
"sync"
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/arpdb"
"github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/AdguardTeam/golibs/hostsfile"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// newTestStorage is a helper function that returns initialized storage.
func newTestStorage(tb testing.TB) (s *client.Storage) {
tb.Helper()
ctx := testutil.ContextWithTimeout(tb, testTimeout)
s, err := client.NewStorage(ctx, &client.StorageConfig{
Logger: slogutil.NewDiscardLogger(),
})
require.NoError(tb, err)
return s
}
// testHostsContainer is a mock implementation of the [client.HostsContainer]
// interface.
type testHostsContainer struct {
onUpd func() (updates <-chan *hostsfile.DefaultStorage)
}
// type check
var _ client.HostsContainer = (*testHostsContainer)(nil)
// Upd implements the [client.HostsContainer] interface for *testHostsContainer.
func (c *testHostsContainer) Upd() (updates <-chan *hostsfile.DefaultStorage) {
return c.onUpd()
}
// Interface stores and refreshes the network neighborhood reported by ARP
// (Address Resolution Protocol).
type Interface interface {
// Refresh updates the stored data. It must be safe for concurrent use.
Refresh() (err error)
// Neighbors returnes the last set of data reported by ARP. Both the method
// and it's result must be safe for concurrent use.
Neighbors() (ns []arpdb.Neighbor)
}
// testARPDB is a mock implementation of the [arpdb.Interface].
type testARPDB struct {
onRefresh func() (err error)
onNeighbors func() (ns []arpdb.Neighbor)
}
// type check
var _ arpdb.Interface = (*testARPDB)(nil)
// Refresh implements the [arpdb.Interface] interface for *testARP.
func (c *testARPDB) Refresh() (err error) {
return c.onRefresh()
}
// Neighbors implements the [arpdb.Interface] interface for *testARP.
func (c *testARPDB) Neighbors() (ns []arpdb.Neighbor) {
return c.onNeighbors()
}
// testDHCP is a mock implementation of the [client.DHCP].
type testDHCP struct {
OnLeases func() (leases []*dhcpsvc.Lease)
OnHostBy func(ip netip.Addr) (host string)
OnMACBy func(ip netip.Addr) (mac net.HardwareAddr)
}
// type check
var _ client.DHCP = (*testDHCP)(nil)
// Lease implements the [client.DHCP] interface for *testDHCP.
func (t *testDHCP) Leases() (leases []*dhcpsvc.Lease) { return t.OnLeases() }
// HostByIP implements the [client.DHCP] interface for *testDHCP.
func (t *testDHCP) HostByIP(ip netip.Addr) (host string) { return t.OnHostBy(ip) }
// MACByIP implements the [client.DHCP] interface for *testDHCP.
func (t *testDHCP) MACByIP(ip netip.Addr) (mac net.HardwareAddr) { return t.OnMACBy(ip) }
// compareRuntimeInfo is a helper function that returns true if the runtime
// client has provided info.
func compareRuntimeInfo(rc *client.Runtime, src client.Source, host string) (ok bool) {
s, h := rc.Info()
if s != src {
return false
} else if h != host {
return false
}
return true
}
func TestStorage_Add_hostsfile(t *testing.T) {
var (
cliIP1 = netip.MustParseAddr("1.1.1.1")
cliName1 = "client_one"
cliIP2 = netip.MustParseAddr("2.2.2.2")
cliName2 = "client_two"
)
hostCh := make(chan *hostsfile.DefaultStorage)
h := &testHostsContainer{
onUpd: func() (updates <-chan *hostsfile.DefaultStorage) { return hostCh },
}
ctx := testutil.ContextWithTimeout(t, testTimeout)
storage, err := client.NewStorage(ctx, &client.StorageConfig{
Logger: slogutil.NewDiscardLogger(),
DHCP: client.EmptyDHCP{},
EtcHosts: h,
ARPClientsUpdatePeriod: testTimeout / 10,
})
require.NoError(t, err)
err = storage.Start(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
return storage.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
})
t.Run("add_hosts", func(t *testing.T) {
var s *hostsfile.DefaultStorage
s, err = hostsfile.NewDefaultStorage()
require.NoError(t, err)
s.Add(&hostsfile.Record{
Addr: cliIP1,
Names: []string{cliName1},
})
testutil.RequireSend(t, hostCh, s, testTimeout)
require.Eventually(t, func() (ok bool) {
cli1 := storage.ClientRuntime(cliIP1)
if cli1 == nil {
return false
}
assert.True(t, compareRuntimeInfo(cli1, client.SourceHostsFile, cliName1))
return true
}, testTimeout, testTimeout/10)
})
t.Run("update_hosts", func(t *testing.T) {
var s *hostsfile.DefaultStorage
s, err = hostsfile.NewDefaultStorage()
require.NoError(t, err)
s.Add(&hostsfile.Record{
Addr: cliIP2,
Names: []string{cliName2},
})
testutil.RequireSend(t, hostCh, s, testTimeout)
require.Eventually(t, func() (ok bool) {
cli2 := storage.ClientRuntime(cliIP2)
if cli2 == nil {
return false
}
assert.True(t, compareRuntimeInfo(cli2, client.SourceHostsFile, cliName2))
cli1 := storage.ClientRuntime(cliIP1)
require.Nil(t, cli1)
return true
}, testTimeout, testTimeout/10)
})
}
func TestStorage_Add_arp(t *testing.T) {
var (
mu sync.Mutex
neighbors []arpdb.Neighbor
cliIP1 = netip.MustParseAddr("1.1.1.1")
cliName1 = "client_one"
cliIP2 = netip.MustParseAddr("2.2.2.2")
cliName2 = "client_two"
)
a := &testARPDB{
onRefresh: func() (err error) { return nil },
onNeighbors: func() (ns []arpdb.Neighbor) {
mu.Lock()
defer mu.Unlock()
return neighbors
},
}
ctx := testutil.ContextWithTimeout(t, testTimeout)
storage, err := client.NewStorage(ctx, &client.StorageConfig{
Logger: slogutil.NewDiscardLogger(),
DHCP: client.EmptyDHCP{},
ARPDB: a,
ARPClientsUpdatePeriod: testTimeout / 10,
})
require.NoError(t, err)
err = storage.Start(testutil.ContextWithTimeout(t, testTimeout))
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
return storage.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
})
t.Run("add_hosts", func(t *testing.T) {
func() {
mu.Lock()
defer mu.Unlock()
neighbors = []arpdb.Neighbor{{
Name: cliName1,
IP: cliIP1,
}}
}()
require.Eventually(t, func() (ok bool) {
cli1 := storage.ClientRuntime(cliIP1)
if cli1 == nil {
return false
}
assert.True(t, compareRuntimeInfo(cli1, client.SourceARP, cliName1))
return true
}, testTimeout, testTimeout/10)
})
t.Run("update_hosts", func(t *testing.T) {
func() {
mu.Lock()
defer mu.Unlock()
neighbors = []arpdb.Neighbor{{
Name: cliName2,
IP: cliIP2,
}}
}()
require.Eventually(t, func() (ok bool) {
cli2 := storage.ClientRuntime(cliIP2)
if cli2 == nil {
return false
}
assert.True(t, compareRuntimeInfo(cli2, client.SourceARP, cliName2))
cli1 := storage.ClientRuntime(cliIP1)
require.Nil(t, cli1)
return true
}, testTimeout, testTimeout/10)
})
}
func TestStorage_Add_whois(t *testing.T) {
var (
cliIP1 = netip.MustParseAddr("1.1.1.1")
cliIP2 = netip.MustParseAddr("2.2.2.2")
cliName2 = "client_two"
cliIP3 = netip.MustParseAddr("3.3.3.3")
cliName3 = "client_three"
)
ctx := testutil.ContextWithTimeout(t, testTimeout)
storage, err := client.NewStorage(ctx, &client.StorageConfig{
Logger: slogutil.NewDiscardLogger(),
DHCP: client.EmptyDHCP{},
})
require.NoError(t, err)
whois := &whois.Info{
Country: "AU",
Orgname: "Example Org",
}
t.Run("new_client", func(t *testing.T) {
storage.UpdateAddress(ctx, cliIP1, "", whois)
cli1 := storage.ClientRuntime(cliIP1)
require.NotNil(t, cli1)
assert.Equal(t, whois, cli1.WHOIS())
})
t.Run("existing_runtime_client", func(t *testing.T) {
storage.UpdateAddress(ctx, cliIP2, cliName2, nil)
storage.UpdateAddress(ctx, cliIP2, "", whois)
cli2 := storage.ClientRuntime(cliIP2)
require.NotNil(t, cli2)
assert.True(t, compareRuntimeInfo(cli2, client.SourceRDNS, cliName2))
assert.Equal(t, whois, cli2.WHOIS())
})
t.Run("can't_set_persistent_client", func(t *testing.T) {
err = storage.Add(ctx, &client.Persistent{
Name: cliName3,
UID: client.MustNewUID(),
IPs: []netip.Addr{cliIP3},
})
require.NoError(t, err)
storage.UpdateAddress(ctx, cliIP3, "", whois)
rc := storage.ClientRuntime(cliIP3)
require.Nil(t, rc)
})
}
func TestClientsDHCP(t *testing.T) {
var (
cliIP1 = netip.MustParseAddr("1.1.1.1")
cliName1 = "one.dhcp"
cliIP2 = netip.MustParseAddr("2.2.2.2")
cliMAC2 = mustParseMAC("22:22:22:22:22:22")
cliName2 = "two.dhcp"
cliIP3 = netip.MustParseAddr("3.3.3.3")
cliMAC3 = mustParseMAC("33:33:33:33:33:33")
cliName3 = "three.dhcp"
prsCliIP = netip.MustParseAddr("4.3.2.1")
prsCliMAC = mustParseMAC("AA:AA:AA:AA:AA:AA")
prsCliName = "persistent.dhcp"
)
ipToHost := map[netip.Addr]string{
cliIP1: cliName1,
}
ipToMAC := map[netip.Addr]net.HardwareAddr{
prsCliIP: prsCliMAC,
}
leases := []*dhcpsvc.Lease{{
IP: cliIP2,
Hostname: cliName2,
HWAddr: cliMAC2,
}, {
IP: cliIP3,
Hostname: cliName3,
HWAddr: cliMAC3,
}}
d := &testDHCP{
OnLeases: func() (ls []*dhcpsvc.Lease) {
return leases
},
OnHostBy: func(ip netip.Addr) (host string) {
return ipToHost[ip]
},
OnMACBy: func(ip netip.Addr) (mac net.HardwareAddr) {
return ipToMAC[ip]
},
}
ctx := testutil.ContextWithTimeout(t, testTimeout)
storage, err := client.NewStorage(ctx, &client.StorageConfig{
Logger: slogutil.NewDiscardLogger(),
DHCP: d,
RuntimeSourceDHCP: true,
})
require.NoError(t, err)
t.Run("find_runtime", func(t *testing.T) {
cli1 := storage.ClientRuntime(cliIP1)
require.NotNil(t, cli1)
assert.True(t, compareRuntimeInfo(cli1, client.SourceDHCP, cliName1))
})
t.Run("find_persistent", func(t *testing.T) {
err = storage.Add(ctx, &client.Persistent{
Name: prsCliName,
UID: client.MustNewUID(),
MACs: []net.HardwareAddr{prsCliMAC},
})
require.NoError(t, err)
prsCli, ok := storage.Find(prsCliIP.String())
require.True(t, ok)
assert.Equal(t, prsCliName, prsCli.Name)
})
t.Run("leases", func(t *testing.T) {
delete(ipToHost, cliIP1)
storage.UpdateDHCP(ctx)
cli1 := storage.ClientRuntime(cliIP1)
require.Nil(t, cli1)
for i, l := range leases {
cli := storage.ClientRuntime(l.IP)
require.NotNil(t, cli)
src, host := cli.Info()
assert.Equal(t, client.SourceDHCP, src)
assert.Equal(t, leases[i].Hostname, host)
}
})
t.Run("range", func(t *testing.T) {
s := 0
storage.RangeRuntime(func(rc *client.Runtime) (cont bool) {
s++
return true
})
assert.Equal(t, len(leases), s)
})
}
func TestClientsAddExisting(t *testing.T) {
ctx := testutil.ContextWithTimeout(t, testTimeout)
t.Run("simple", func(t *testing.T) {
storage, err := client.NewStorage(ctx, &client.StorageConfig{
Logger: slogutil.NewDiscardLogger(),
DHCP: client.EmptyDHCP{},
})
require.NoError(t, err)
ip := netip.MustParseAddr("1.1.1.1")
// Add a client.
err = storage.Add(ctx, &client.Persistent{
Name: "client1",
UID: client.MustNewUID(),
IPs: []netip.Addr{ip, netip.MustParseAddr("1:2:3::4")},
Subnets: []netip.Prefix{netip.MustParsePrefix("2.2.2.0/24")},
MACs: []net.HardwareAddr{{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}},
})
require.NoError(t, err)
// Now add an auto-client with the same IP.
storage.UpdateAddress(ctx, ip, "test", nil)
rc := storage.ClientRuntime(ip)
assert.True(t, compareRuntimeInfo(rc, client.SourceRDNS, "test"))
})
t.Run("complicated", func(t *testing.T) {
// TODO(a.garipov): Properly decouple the DHCP server from the client
// storage.
if runtime.GOOS == "windows" {
t.Skip("skipping dhcp test on windows")
}
// First, init a DHCP server with a single static lease.
config := &dhcpd.ServerConfig{
Enabled: true,
DataDir: t.TempDir(),
Conf4: dhcpd.V4ServerConf{
Enabled: true,
GatewayIP: netip.MustParseAddr("1.2.3.1"),
SubnetMask: netip.MustParseAddr("255.255.255.0"),
RangeStart: netip.MustParseAddr("1.2.3.2"),
RangeEnd: netip.MustParseAddr("1.2.3.10"),
},
}
dhcpServer, err := dhcpd.Create(config)
require.NoError(t, err)
storage, err := client.NewStorage(ctx, &client.StorageConfig{
Logger: slogutil.NewDiscardLogger(),
DHCP: dhcpServer,
})
require.NoError(t, err)
ip := netip.MustParseAddr("1.2.3.4")
err = dhcpServer.AddStaticLease(&dhcpsvc.Lease{
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
IP: ip,
Hostname: "testhost",
Expiry: time.Now().Add(time.Hour),
})
require.NoError(t, err)
// Add a new client with the same IP as for a client with MAC.
err = storage.Add(ctx, &client.Persistent{
Name: "client2",
UID: client.MustNewUID(),
IPs: []netip.Addr{ip},
})
require.NoError(t, err)
// Add a new client with the IP from the first client's IP range.
err = storage.Add(ctx, &client.Persistent{
Name: "client3",
UID: client.MustNewUID(),
IPs: []netip.Addr{netip.MustParseAddr("2.2.2.2")},
})
require.NoError(t, err)
})
}
// newStorage is a helper function that returns a client storage filled with
// persistent clients from the m. It also generates a UID for each client.
func newStorage(tb testing.TB, m []*client.Persistent) (s *client.Storage) {
tb.Helper()
s = client.NewStorage(&client.Config{
AllowedTags: nil,
ctx := testutil.ContextWithTimeout(tb, testTimeout)
s, err := client.NewStorage(ctx, &client.StorageConfig{
Logger: slogutil.NewDiscardLogger(),
DHCP: client.EmptyDHCP{},
})
require.NoError(tb, err)
for _, c := range m {
c.UID = client.MustNewUID()
require.NoError(tb, s.Add(c))
require.NoError(tb, s.Add(ctx, c))
}
require.Equal(tb, len(m), s.Size())
return s
}
@@ -43,6 +564,9 @@ func TestStorage_Add(t *testing.T) {
const (
existingName = "existing_name"
existingClientID = "existing_client_id"
allowedTag = "user_admin"
notAllowedTag = "not_allowed_tag"
)
var (
@@ -59,10 +583,19 @@ func TestStorage_Add(t *testing.T) {
UID: existingClientUID,
}
s := client.NewStorage(&client.Config{
AllowedTags: nil,
})
err := s.Add(existingClient)
ctx := testutil.ContextWithTimeout(t, testTimeout)
s := newTestStorage(t)
tags := s.AllowedTags()
require.NotZero(t, len(tags))
require.True(t, slices.IsSorted(tags))
_, ok := slices.BinarySearch(tags, allowedTag)
require.True(t, ok)
_, ok = slices.BinarySearch(tags, notAllowedTag)
require.False(t, ok)
err := s.Add(ctx, existingClient)
require.NoError(t, err)
testCases := []struct {
@@ -119,11 +652,51 @@ func TestStorage_Add(t *testing.T) {
},
wantErrMsg: `adding client: another client "existing_name" ` +
`uses the same ClientID "existing_client_id"`,
}, {
name: "not_allowed_tag",
cli: &client.Persistent{
Name: "not_allowed_tag",
Tags: []string{notAllowedTag},
IPs: []netip.Addr{netip.MustParseAddr("4.4.4.4")},
UID: client.MustNewUID(),
},
wantErrMsg: `adding client: invalid tag: "not_allowed_tag"`,
}, {
name: "allowed_tag",
cli: &client.Persistent{
Name: "allowed_tag",
Tags: []string{allowedTag},
IPs: []netip.Addr{netip.MustParseAddr("5.5.5.5")},
UID: client.MustNewUID(),
},
wantErrMsg: "",
}, {
name: "",
cli: &client.Persistent{
Name: "",
IPs: []netip.Addr{netip.MustParseAddr("6.6.6.6")},
UID: client.MustNewUID(),
},
wantErrMsg: "adding client: empty name",
}, {
name: "no_id",
cli: &client.Persistent{
Name: "no_id",
UID: client.MustNewUID(),
},
wantErrMsg: "adding client: id required",
}, {
name: "no_uid",
cli: &client.Persistent{
Name: "no_uid",
IPs: []netip.Addr{netip.MustParseAddr("7.7.7.7")},
},
wantErrMsg: "adding client: uid required",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err = s.Add(tc.cli)
err = s.Add(ctx, tc.cli)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
})
@@ -141,10 +714,9 @@ func TestStorage_RemoveByName(t *testing.T) {
UID: client.MustNewUID(),
}
s := client.NewStorage(&client.Config{
AllowedTags: nil,
})
err := s.Add(existingClient)
ctx := testutil.ContextWithTimeout(t, testTimeout)
s := newTestStorage(t)
err := s.Add(ctx, existingClient)
require.NoError(t, err)
testCases := []struct {
@@ -163,19 +735,17 @@ func TestStorage_RemoveByName(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
tc.want(t, s.RemoveByName(tc.cliName))
tc.want(t, s.RemoveByName(ctx, tc.cliName))
})
}
t.Run("duplicate_remove", func(t *testing.T) {
s = client.NewStorage(&client.Config{
AllowedTags: nil,
})
err = s.Add(existingClient)
s = newTestStorage(t)
err = s.Add(ctx, existingClient)
require.NoError(t, err)
assert.True(t, s.RemoveByName(existingName))
assert.False(t, s.RemoveByName(existingName))
assert.True(t, s.RemoveByName(ctx, existingName))
assert.False(t, s.RemoveByName(ctx, existingName))
})
}
@@ -341,6 +911,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"
@@ -413,6 +1104,7 @@ func TestStorage_Update(t *testing.T) {
`uses the same ClientID "obstructing_client_id"`,
}}
ctx := testutil.ContextWithTimeout(t, testTimeout)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
s := newStorage(
@@ -423,7 +1115,7 @@ func TestStorage_Update(t *testing.T) {
},
)
err := s.Update(clientName, tc.cli)
err := s.Update(ctx, clientName, tc.cli)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
})
}

View File

@@ -2,4 +2,4 @@
package configmigrate
// LastSchemaVersion is the most recent schema version.
const LastSchemaVersion uint = 28
const LastSchemaVersion uint = 29

View File

@@ -19,6 +19,7 @@ func TestUpgradeSchema1to2(t *testing.T) {
m := New(&Config{
WorkingDir: "",
DataDir: "",
})
err := m.migrateTo2(diskConf)
@@ -520,7 +521,7 @@ func TestUpgradeSchema11to12(t *testing.T) {
name string
}{{
ivl: 1,
want: timeutil.Duration{Duration: timeutil.Day},
want: timeutil.Duration(timeutil.Day),
wantErr: "",
name: "success",
}, {
@@ -603,7 +604,7 @@ func TestUpgradeSchema11to12(t *testing.T) {
ivlVal, ok = ivl.(timeutil.Duration)
require.True(t, ok)
assert.Equal(t, 90*24*time.Hour, ivlVal.Duration)
assert.Equal(t, 90*24*time.Hour, time.Duration(ivlVal))
})
}
@@ -1054,12 +1055,12 @@ func TestUpgradeSchema19to20(t *testing.T) {
name string
}{{
ivl: 1,
want: timeutil.Duration{Duration: timeutil.Day},
want: timeutil.Duration(timeutil.Day),
wantErr: "",
name: "success",
}, {
ivl: 0,
want: timeutil.Duration{Duration: timeutil.Day},
want: timeutil.Duration(timeutil.Day),
wantErr: "",
name: "success",
}, {
@@ -1142,7 +1143,7 @@ func TestUpgradeSchema19to20(t *testing.T) {
ivlVal, ok = ivl.(timeutil.Duration)
require.True(t, ok)
assert.Equal(t, 24*time.Hour, ivlVal.Duration)
assert.Equal(t, 24*time.Hour, time.Duration(ivlVal))
})
}

View File

@@ -10,20 +10,24 @@ import (
// Config is a the configuration for initializing a [Migrator].
type Config struct {
// WorkingDir is an absolute path to the working directory of AdGuardHome.
// WorkingDir is the absolute path to the working directory of AdGuardHome.
WorkingDir string
// DataDir is the absolute path to the data directory of AdGuardHome.
DataDir string
}
// Migrator performs the YAML configuration file migrations.
type Migrator struct {
// workingDir is an absolute path to the working directory of AdGuardHome.
workingDir string
dataDir string
}
// New creates a new Migrator.
func New(cfg *Config) (m *Migrator) {
func New(c *Config) (m *Migrator) {
return &Migrator{
workingDir: cfg.WorkingDir,
workingDir: c.WorkingDir,
dataDir: c.DataDir,
}
}
@@ -120,6 +124,7 @@ func (m *Migrator) upgradeConfigSchema(current, target uint, diskConf yobj) (err
25: migrateTo26,
26: migrateTo27,
27: migrateTo28,
28: m.migrateTo29,
}
for i, migrate := range upgrades[current:target] {

View File

@@ -1,9 +1,12 @@
package configmigrate_test
import (
"bytes"
"io/fs"
"os"
"path"
"path/filepath"
"runtime"
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/configmigrate"
@@ -202,6 +205,7 @@ func TestMigrateConfig_Migrate(t *testing.T) {
migrator := configmigrate.New(&configmigrate.Config{
WorkingDir: t.Name(),
DataDir: filepath.Join(t.Name(), "data"),
})
newBody, upgraded, err := migrator.Migrate(body, tc.targetVersion)
require.NoError(t, err)
@@ -211,3 +215,43 @@ func TestMigrateConfig_Migrate(t *testing.T) {
})
}
}
// TODO(a.garipov): Consider ways of merging into the previous one.
func TestMigrateConfig_Migrate_v29(t *testing.T) {
const (
pathUnix = `/path/to/file.txt`
userDirPatUnix = `TestMigrateConfig_Migrate/v29/data/userfilters/*`
pathWindows = `C:\path\to\file.txt`
userDirPatWindows = `TestMigrateConfig_Migrate\v29\data\userfilters\*`
)
pathToReplace := pathUnix
patternToReplace := userDirPatUnix
if runtime.GOOS == "windows" {
pathToReplace = pathWindows
patternToReplace = userDirPatWindows
}
body, err := fs.ReadFile(testdata, "TestMigrateConfig_Migrate/v29/input.yml")
require.NoError(t, err)
body = bytes.ReplaceAll(body, []byte("FILEPATH"), []byte(pathToReplace))
wantBody, err := fs.ReadFile(testdata, "TestMigrateConfig_Migrate/v29/output.yml")
require.NoError(t, err)
wantBody = bytes.ReplaceAll(wantBody, []byte("FILEPATH"), []byte(pathToReplace))
wantBody = bytes.ReplaceAll(wantBody, []byte("USERFILTERSPATH"), []byte(patternToReplace))
migrator := configmigrate.New(&configmigrate.Config{
WorkingDir: t.Name(),
DataDir: "TestMigrateConfig_Migrate/v29/data",
})
newBody, upgraded, err := migrator.Migrate(body, 29)
require.NoError(t, err)
require.True(t, upgraded)
require.YAMLEq(t, string(wantBody), string(newBody))
}

View File

@@ -0,0 +1,117 @@
http:
address: 127.0.0.1:3000
session_ttl: 3h
pprof:
enabled: true
port: 6060
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
parental_sensitivity: 0
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filtering:
filtering_enabled: true
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
protection_enabled: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
blocked_response_ttl: 10
filters:
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: FILEPATH
name: Local Filter
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 28
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored:
- '|.^'
statistics:
enabled: true
interval: 240h
ignored:
- '|.^'
os:
group: ''
rlimit_nofile: 123
user: ''
log:
file: ""
max_backups: 0
max_size: 100
max_age: 3
compress: true
local_time: false
verbose: true

View File

@@ -0,0 +1,120 @@
http:
address: 127.0.0.1:3000
session_ttl: 3h
pprof:
enabled: true
port: 6060
users:
- name: testuser
password: testpassword
dns:
bind_hosts:
- 127.0.0.1
port: 53
parental_sensitivity: 0
upstream_dns:
- tls://1.1.1.1
- tls://1.0.0.1
- quic://8.8.8.8:784
bootstrap_dns:
- 8.8.8.8:53
edns_client_subnet:
enabled: true
use_custom: false
custom_ip: ""
filtering:
filtering_enabled: true
parental_enabled: false
safebrowsing_enabled: false
safe_fs_patterns:
- USERFILTERSPATH
- FILEPATH
safe_search:
enabled: false
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
protection_enabled: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
blocked_response_ttl: 10
filters:
- url: https://adaway.org/hosts.txt
name: AdAway
enabled: false
- url: FILEPATH
name: Local Filter
enabled: false
clients:
persistent:
- name: localhost
ids:
- 127.0.0.1
- aa:aa:aa:aa:aa:aa
use_global_settings: true
use_global_blocked_services: true
filtering_enabled: false
parental_enabled: false
safebrowsing_enabled: false
safe_search:
enabled: true
bing: true
duckduckgo: true
google: true
pixabay: true
yandex: true
youtube: true
blocked_services:
schedule:
time_zone: Local
ids:
- 500px
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
dhcp:
enabled: false
interface_name: vboxnet0
local_domain_name: local
dhcpv4:
gateway_ip: 192.168.0.1
subnet_mask: 255.255.255.0
range_start: 192.168.0.10
range_end: 192.168.0.250
lease_duration: 1234
icmp_timeout_msec: 10
schema_version: 29
user_rules: []
querylog:
enabled: true
file_enabled: true
interval: 720h
size_memory: 1000
ignored:
- '|.^'
statistics:
enabled: true
interval: 240h
ignored:
- '|.^'
os:
group: ''
rlimit_nofile: 123
user: ''
log:
file: ""
max_backups: 0
max_size: 100
max_age: 3
compress: true
local_time: false
verbose: true

View File

@@ -37,7 +37,7 @@ func migrateTo12(diskConf yobj) (err error) {
qlogIvl = 90
}
dns[field] = timeutil.Duration{Duration: time.Duration(qlogIvl) * timeutil.Day}
dns[field] = timeutil.Duration(time.Duration(qlogIvl) * timeutil.Day)
return nil
}

View File

@@ -38,7 +38,7 @@ func migrateTo20(diskConf yobj) (err error) {
ivl = 1
}
stats[field] = timeutil.Duration{Duration: time.Duration(ivl) * timeutil.Day}
stats[field] = timeutil.Duration(time.Duration(ivl) * timeutil.Day)
return nil
}

View File

@@ -48,7 +48,7 @@ func migrateTo23(diskConf yobj) (err error) {
diskConf["http"] = yobj{
"address": netip.AddrPortFrom(bindHostAddr, uint16(bindPort)).String(),
"session_ttl": timeutil.Duration{Duration: time.Duration(sessionTTL) * time.Hour}.String(),
"session_ttl": timeutil.Duration(time.Duration(sessionTTL) * time.Hour).String(),
}
delete(diskConf, "bind_host")

View File

@@ -0,0 +1,63 @@
package configmigrate
import (
"fmt"
"path/filepath"
)
// migrateTo29 performs the following changes:
//
// # BEFORE:
// 'filters':
// - 'enabled': true
// 'url': /path/to/file.txt
// 'name': My FS Filter
// 'id': 1234
//
// # AFTER:
// 'filters':
// - 'enabled': true
// 'url': /path/to/file.txt
// 'name': My FS Filter
// 'id': 1234
// # …
// 'filtering':
// 'safe_fs_patterns':
// - '/opt/AdGuardHome/data/userfilters/*'
// - '/path/to/file.txt'
// # …
func (m Migrator) migrateTo29(diskConf yobj) (err error) {
diskConf["schema_version"] = 29
filterVals, ok, err := fieldVal[[]any](diskConf, "filters")
if !ok {
return err
}
paths := []string{
filepath.Join(m.dataDir, "userfilters", "*"),
}
for i, v := range filterVals {
var f yobj
f, ok = v.(yobj)
if !ok {
return fmt.Errorf("filters: at index %d: expected object, got %T", i, v)
}
var u string
u, ok, _ = fieldVal[string](f, "url")
if ok && filepath.IsAbs(u) {
paths = append(paths, u)
}
}
fltConf, ok, err := fieldVal[yobj](diskConf, "filtering")
if !ok {
return err
}
fltConf["safe_fs_patterns"] = paths
return nil
}

View File

@@ -1,61 +1,50 @@
# Testing DHCP Server
# Testing DHCP Server
Contents:
* [Test setup with Virtual Box](#vbox)
* [Quick test with DHCPTest](#dhcptest)
## <a href="#vbox" id="vbox" name="vbox">Test setup with Virtual Box</a>
- [Test setup with Virtual Box](#vbox)
- [Quick test with DHCPTest](#dhcptest)
### Prerequisites
## <a href="#vbox" id="vbox" name="vbox">Test setup with Virtual Box</a>
### Prerequisites
To set up a test environment for DHCP server you will need:
* Linux AG Home host machine (Virtual).
* Virtual Box.
* Virtual machine (guest OS doesn't matter).
- Linux AG Home host machine (Virtual)
- Virtual Box
- Virtual machine (guest OS doesn't matter)
### Configure Virtual Box
### Configure Virtual Box
1. Install Virtual Box and run the following command to create a Host-Only
network:
1. Install Virtual Box and run the following command to create a Host-Only network:
```sh
$ VBoxManage hostonlyif create
```
```sh
VBoxManage hostonlyif create
```
You can check its status by `ip a` command.
You can check its status by `ip a` command.
You can also set up Host-Only network using Virtual Box menu:
You can also set up Host-Only network using Virtual Box menu in *File → Host Network Manager.*
```
File -> Host Network Manager...
```
2. Create your virtual machine and set up its network in *VM Settings → Network → Host-only Adapter.*
2. Create your virtual machine and set up its network:
3. Start your VM, install an OS. Configure your network interface to use DHCP and the OS should ask for a IP address from our DHCP server.
```
VM Settings -> Network -> Host-only Adapter
```
4. To see the current IP addresses on client OS you can use `ip a` command on Linux or `ipconfig` on Windows.
3. Start your VM, install an OS. Configure your network interface to use
DHCP and the OS should ask for a IP address from our DHCP server.
5. To force the client OS to request an IP from DHCP server again, you can use `dhclient` on Linux or `ipconfig /release` on Windows.
4. To see the current IP addresses on client OS you can use `ip a` command on
Linux or `ipconfig` on Windows.
### Configure server
5. To force the client OS to request an IP from DHCP server again, you can
use `dhclient` on Linux or `ipconfig /release` on Windows.
1. Edit server configuration file `AdGuardHome.yaml`, for example:
### Configure server
1. Edit server configuration file `AdGuardHome.yaml`, for example:
```yaml
dhcp:
enabled: true
interface_name: vboxnet0
local_domain_name: lan
dhcpv4:
```yaml
dhcp:
enabled: true
interface_name: vboxnet0
local_domain_name: lan
dhcpv4:
gateway_ip: 192.168.56.1
subnet_mask: 255.255.255.0
range_start: 192.168.56.2
@@ -63,34 +52,33 @@ To set up a test environment for DHCP server you will need:
lease_duration: 86400
icmp_timeout_msec: 1000
options: []
dhcpv6:
dhcpv6:
range_start: 2001::1
lease_duration: 86400
ra_slaac_only: false
ra_allow_slaac: false
```
```
2. Start the server
2. Start the server:
```sh
./AdGuardHome -v
```
```sh
./AdGuardHome -v
```
There should be a message in log which shows that DHCP server is ready:
There should be a message in log which shows that DHCP server is ready:
```
[info] DHCP: listening on 0.0.0.0:67
```
```none
[info] dhcpv4: listening
```
## <a href="#dhcptest" id="dhcptest" name="dhcptest">Quick test with DHCPTest utility</a>
## <a href="#dhcptest" id="dhcptest" name="dhcptest">Quick test with DHCPTest utility</a>
### Prerequisites
### Prerequisites
* [DHCP test utility][dhcptest-gh].
- [DHCP test utility][dhcptest-gh].
### Quick test
### Quick test
The DHCP server could be tested for DISCOVER-OFFER packets with in
interactive mode.
The DHCP server could be tested for DISCOVER-OFFER packets with in interactive mode.
[dhcptest-gh]: https://github.com/CyberShadow/dhcptest

View File

@@ -12,6 +12,7 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
@@ -185,7 +186,7 @@ func writeDB(path string, leases []*dbLease) (err error) {
return err
}
err = maybe.WriteFile(path, buf, 0o644)
err = maybe.WriteFile(path, buf, aghos.DefaultPermFile)
if err != nil {
// Don't wrap the error since it's informative enough as is.
return err

View File

@@ -84,7 +84,7 @@ func parseDHCPOptionDur(s string) (val dhcpv4.OptionValue, err error) {
return nil, fmt.Errorf("decoding dur: %w", err)
}
return dhcpv4.Duration(v.Duration), nil
return dhcpv4.Duration(v), nil
}
// parseDHCPOptionUint parses a DHCP option as an unsigned integer. bitSize is

View File

@@ -144,8 +144,8 @@ func TestParseOpt(t *testing.T) {
in: "24 dur 3y",
wantCode: nil,
wantVal: nil,
wantErrMsg: "invalid option string \"24 dur 3y\": decoding dur: " +
"unmarshaling duration: time: unknown unit \"y\" in duration \"3y\"",
wantErrMsg: `invalid option string "24 dur 3y": decoding dur: time: ` +
`unknown unit "y" in duration "3y"`,
}, {
name: "u8_error",
in: "23 u8 256",

View File

@@ -18,9 +18,11 @@ import (
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/timeutil"
"github.com/go-ping/ping"
"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/dhcpv4/server4"
//lint:ignore SA1019 See the TODO in go.mod.
"github.com/go-ping/ping"
)
// v4Server is a DHCPv4 server.

View File

@@ -3,11 +3,12 @@ package dhcpsvc
import (
"fmt"
"log/slog"
"maps"
"os"
"slices"
"time"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/mapsutil"
"github.com/AdguardTeam/golibs/netutil"
)
@@ -78,14 +79,13 @@ func (conf *Config) Validate() (err error) {
return errors.Join(errs...)
}
mapsutil.SortedRange(conf.Interfaces, func(iface string, ic *InterfaceConfig) (ok bool) {
for _, iface := range slices.Sorted(maps.Keys(conf.Interfaces)) {
ic := conf.Interfaces[iface]
err = ic.validate()
if err != nil {
errs = append(errs, fmt.Errorf("interface %q: %w", iface, err))
}
return true
})
}
return errors.Join(errs...)
}

View File

@@ -82,7 +82,7 @@ type Empty struct{}
var _ agh.ServiceWithConfig[*Config] = Empty{}
// Start implements the [Service] interface for Empty.
func (Empty) Start() (err error) { return nil }
func (Empty) Start(_ context.Context) (err error) { return nil }
// Shutdown implements the [Service] interface for Empty.
func (Empty) Shutdown(_ context.Context) (err error) { return nil }

View File

@@ -4,14 +4,15 @@ import (
"context"
"fmt"
"log/slog"
"maps"
"net"
"net/netip"
"slices"
"sync"
"sync/atomic"
"time"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/mapsutil"
)
// DHCPServer is a DHCP server for both IPv4 and IPv6 address families.
@@ -107,7 +108,8 @@ func newInterfaces(
v6 = make(dhcpInterfacesV6, 0, len(ifaces))
var errs []error
mapsutil.SortedRange(ifaces, func(name string, iface *InterfaceConfig) (cont bool) {
for _, name := range slices.Sorted(maps.Keys(ifaces)) {
iface := ifaces[name]
var i4 *dhcpInterfaceV4
i4, err = newDHCPInterfaceV4(ctx, l, name, iface.IPv4)
if err != nil {
@@ -120,9 +122,8 @@ func newInterfaces(
if i6 != nil {
v6 = append(v6, i6)
}
}
return true
})
if err = errors.Join(errs...); err != nil {
return nil, nil, err
}

View File

@@ -81,7 +81,7 @@ func (s *Server) clientIDFromDNSContext(pctx *proxy.DNSContext) (clientID string
cliSrvName, err := clientServerName(pctx, proto)
if err != nil {
return "", err
return "", fmt.Errorf("getting client server-name: %w", err)
}
clientID, err = clientIDFromClientServerName(

View File

@@ -3,6 +3,7 @@ package dnsforward
import (
"crypto/tls"
"fmt"
"net/http"
"path"
"strings"
@@ -118,17 +119,13 @@ func clientServerName(pctx *proxy.DNSContext, proto proxy.Proto) (srvName string
switch proto {
case proxy.ProtoHTTPS:
r := pctx.HTTPRequest
if connState := r.TLS; connState != nil {
srvName = connState.ServerName
} else if r.Host != "" {
var host string
host, err = netutil.SplitHost(r.Host)
if err != nil {
return "", fmt.Errorf("parsing host: %w", err)
}
var fromHost bool
srvName, fromHost, err = clientServerNameFromHTTP(pctx.HTTPRequest)
if err != nil {
return "", fmt.Errorf("from http: %w", err)
}
srvName = host
if fromHost {
from = "host header"
}
case proxy.ProtoQUIC:
@@ -153,3 +150,23 @@ func clientServerName(pctx *proxy.DNSContext, proto proxy.Proto) (srvName string
return srvName, nil
}
// clientServerNameFromHTTP returns the TLS server name or the value of the host
// header depending on the protocol. fromHost is true if srvName comes from the
// "Host" HTTP header.
func clientServerNameFromHTTP(r *http.Request) (srvName string, fromHost bool, err error) {
if connState := r.TLS; connState != nil {
return connState.ServerName, false, nil
}
if r.Host == "" {
return "", false, nil
}
srvName, err = netutil.SplitHost(r.Host)
if err != nil {
return "", false, fmt.Errorf("parsing host: %w", err)
}
return srvName, true, nil
}

View File

@@ -218,8 +218,8 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
}
srv := &Server{
conf: ServerConfig{TLSConfig: tlsConf},
logger: slogutil.NewDiscardLogger(),
conf: ServerConfig{TLSConfig: tlsConf},
baseLogger: slogutil.NewDiscardLogger(),
}
var (

View File

@@ -159,7 +159,7 @@ type Config struct {
// IpsetList is the ipset configuration that allows AdGuard Home to add IP
// addresses of the specified domain names to an ipset list. Syntax:
//
// DOMAIN[,DOMAIN].../IPSET_NAME
// DOMAIN[,DOMAIN].../IPSET_NAME[,IPSET_NAME]...
//
// This field is ignored if [IpsetListFileName] is set.
IpsetList []string `yaml:"ipset"`
@@ -318,6 +318,7 @@ func (s *Server) newProxyConfig() (conf *proxy.Config, err error) {
trustedPrefixes := netutil.UnembedPrefixes(srvConf.TrustedProxies)
conf = &proxy.Config{
Logger: s.baseLogger.With(slogutil.KeyPrefix, "dnsproxy"),
HTTP3: srvConf.ServeHTTP3,
Ratelimit: int(srvConf.Ratelimit),
RatelimitSubnetLenIPv4: srvConf.RatelimitSubnetLenIPv4,
@@ -342,16 +343,12 @@ func (s *Server) newProxyConfig() (conf *proxy.Config, err error) {
MessageConstructor: s,
}
if s.logger != nil {
conf.Logger = s.logger.With(slogutil.KeyPrefix, "dnsproxy")
}
if srvConf.EDNSClientSubnet.UseCustom {
// TODO(s.chzhen): Use netip.Addr instead of net.IP inside dnsproxy.
conf.EDNSAddr = net.IP(srvConf.EDNSClientSubnet.CustomIP.AsSlice())
}
err = setProxyUpstreamMode(conf, srvConf.UpstreamMode, srvConf.FastestTimeout.Duration)
err = setProxyUpstreamMode(conf, srvConf.UpstreamMode, time.Duration(srvConf.FastestTimeout))
if err != nil {
return nil, fmt.Errorf("upstream mode: %w", err)
}
@@ -427,8 +424,6 @@ func parseBogusNXDOMAIN(confBogusNXDOMAIN []string) (subnets []netip.Prefix, err
return subnets, nil
}
const defaultBlockedResponseTTL = 3600
// initDefaultSettings initializes default settings if nothing
// is configured
func (s *Server) initDefaultSettings() {
@@ -459,24 +454,24 @@ func (s *Server) initDefaultSettings() {
// prepareIpsetListSettings reads and prepares the ipset configuration either
// from a file or from the data in the configuration file.
func (s *Server) prepareIpsetListSettings() (err error) {
func (s *Server) prepareIpsetListSettings() (ipsets []string, err error) {
fn := s.conf.IpsetListFileName
if fn == "" {
return s.ipset.init(s.conf.IpsetList)
return s.conf.IpsetList, nil
}
// #nosec G304 -- Trust the path explicitly given by the user.
data, err := os.ReadFile(fn)
if err != nil {
return err
return nil, err
}
ipsets := stringutil.SplitTrimmed(string(data), "\n")
ipsets = stringutil.FilterOut(ipsets, IsCommentOrEmpty)
ipsets = stringutil.SplitTrimmed(string(data), "\n")
ipsets = slices.DeleteFunc(ipsets, IsCommentOrEmpty)
log.Debug("dns: using %d ipset rules from file %q", len(ipsets), fn)
return s.ipset.init(ipsets)
return ipsets, nil
}
// loadUpstreams parses upstream DNS servers from the configured file or from

View File

@@ -123,18 +123,17 @@ type Server struct {
// access drops disallowed clients.
access *accessManager
// logger is used for logging during server routines.
//
// TODO(d.kolyshev): Make it never nil.
// TODO(d.kolyshev): Use this logger.
logger *slog.Logger
// baseLogger is used to create loggers for other entities. It should not
// have a prefix and must not be nil.
baseLogger *slog.Logger
// 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.
ipset ipsetCtx
// ipset processes DNS requests using ipset data. It must not be nil after
// initialization. See [newIpsetHandler].
ipset *ipsetHandler
// privateNets is the configured set of IP networks considered private.
privateNets netutil.SubnetSet
@@ -245,7 +244,7 @@ func NewServer(p DNSCreateParams) (s *Server, err error) {
stats: p.Stats,
queryLog: p.QueryLog,
privateNets: p.PrivateNets,
logger: p.Logger.With(slogutil.KeyPrefix, "dnsforward"),
baseLogger: p.Logger,
// TODO(e.burkov): Use some case-insensitive string comparison.
localDomainSuffix: strings.ToLower(localDomainSuffix),
etcHosts: etcHosts,
@@ -609,11 +608,18 @@ func (s *Server) prepareLocalResolvers() (uc *proxy.UpstreamConfig, err error) {
// the primary DNS proxy instance. It assumes s.serverLock is locked or the
// Server not running.
func (s *Server) prepareInternalDNS() (err error) {
err = s.prepareIpsetListSettings()
ipsetList, err := s.prepareIpsetListSettings()
if err != nil {
return fmt.Errorf("preparing ipset settings: %w", err)
}
ipsetLogger := s.baseLogger.With(slogutil.KeyPrefix, "ipset")
s.ipset, err = newIpsetHandler(context.TODO(), ipsetLogger, ipsetList)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
}
bootOpts := &upstream.Options{
Timeout: DefaultTimeout,
HTTPVersions: UpstreamHTTPVersions(s.conf.UseHTTP3Upstreams),
@@ -677,6 +683,7 @@ func (s *Server) setupAddrProc() {
s.addrProc = client.EmptyAddrProc{}
} else {
c := s.conf.AddrProcConf
c.BaseLogger = s.baseLogger
c.DialContext = s.DialContext
c.PrivateSubnets = s.privateNets
c.UsePrivateRDNS = s.conf.UsePrivateRDNS
@@ -720,6 +727,7 @@ func validateBlockingMode(
func (s *Server) prepareInternalProxy() (err error) {
srvConf := s.conf
conf := &proxy.Config{
Logger: s.baseLogger.With(slogutil.KeyPrefix, "dnsproxy"),
CacheEnabled: true,
CacheSizeBytes: 4096,
PrivateRDNSUpstreamConfig: srvConf.PrivateRDNSUpstreamConfig,
@@ -732,11 +740,7 @@ func (s *Server) prepareInternalProxy() (err error) {
MessageConstructor: s,
}
if s.logger != nil {
conf.Logger = s.logger.With(slogutil.KeyPrefix, "dnsproxy")
}
err = setProxyUpstreamMode(conf, srvConf.UpstreamMode, srvConf.FastestTimeout.Duration)
err = setProxyUpstreamMode(conf, srvConf.UpstreamMode, time.Duration(srvConf.FastestTimeout))
if err != nil {
return fmt.Errorf("invalid upstream mode: %w", err)
}
@@ -814,6 +818,8 @@ func (s *Server) proxy() (p *proxy.Proxy) {
}
// Reconfigure applies the new configuration to the DNS server.
//
// TODO(a.garipov): This whole piece of API is weird and needs to be remade.
func (s *Server) Reconfigure(conf *ServerConfig) error {
s.serverLock.Lock()
defer s.serverLock.Unlock()
@@ -827,14 +833,15 @@ func (s *Server) Reconfigure(conf *ServerConfig) error {
// We wait for some time and hope that this fd will be closed.
time.Sleep(100 * time.Millisecond)
// TODO(a.garipov): This whole piece of API is weird and needs to be remade.
if s.addrProc != nil {
err := s.addrProc.Close()
if err != nil {
log.Error("dnsforward: closing address processor: %s", err)
}
}
if conf == nil {
conf = &s.conf
} else {
closeErr := s.addrProc.Close()
if closeErr != nil {
log.Error("dnsforward: closing address processor: %s", closeErr)
}
}
// TODO(e.burkov): It seems an error here brings the server down, which is

View File

@@ -500,6 +500,10 @@ func TestServerRace(t *testing.T) {
}
func TestSafeSearch(t *testing.T) {
const (
googleSafeSearch = "forcesafesearch.google.com."
)
safeSearchConf := filtering.SafeSearchConfig{
Enabled: true,
Google: true,
@@ -513,12 +517,14 @@ func TestSafeSearch(t *testing.T) {
SafeSearchCacheSize: 1000,
CacheTime: 30,
}
safeSearch, err := safesearch.NewDefault(
safeSearchConf,
"",
filterConf.SafeSearchCacheSize,
time.Minute*time.Duration(filterConf.CacheTime),
)
ctx := testutil.ContextWithTimeout(t, testTimeout)
safeSearch, err := safesearch.NewDefault(ctx, &safesearch.DefaultConfig{
Logger: slogutil.NewDiscardLogger(),
ServicesConfig: safeSearchConf,
CacheSize: filterConf.SafeSearchCacheSize,
CacheTTL: time.Minute * time.Duration(filterConf.CacheTime),
})
require.NoError(t, err)
filterConf.SafeSearch = safeSearch
@@ -534,10 +540,17 @@ func TestSafeSearch(t *testing.T) {
ServePlainDNS: true,
}
s := createTestServer(t, filterConf, forwardConf)
startDeferStop(t, s)
ups := aghtest.NewUpstreamMock(func(req *dns.Msg) (resp *dns.Msg, err error) {
pt := testutil.PanicT{}
assert.Equal(pt, googleSafeSearch, req.Question[0].Name)
return aghtest.MatchedResponse(req, dns.TypeA, googleSafeSearch, "1.2.3.4"), nil
})
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ups}
startDeferStop(t, s)
addr := s.dnsProxy.Addr(proxy.ProtoUDP).String()
client := &dns.Client{}
yandexIP := netip.AddrFrom4([4]byte{213, 180, 193, 56})
@@ -584,8 +597,8 @@ func TestSafeSearch(t *testing.T) {
req := createTestMessage(tc.host)
var reply *dns.Msg
reply, _, err = client.Exchange(req, addr)
require.NoErrorf(t, err, "couldn't talk to server %s: %s", addr, err)
reply, err = dns.Exchange(req, addr)
require.NoError(t, err)
if tc.wantCNAME != "" {
require.Len(t, reply.Answer, 2)

View File

@@ -228,7 +228,7 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
}, {
name: "upstream_dns_bad",
wantSet: `validating dns config: upstream servers: parsing error at index 0: ` +
`cannot prepare the upstream: invalid address !!!: bad hostname "!!!": ` +
`cannot prepare the upstream: invalid address !!!: bad domain name "!!!": ` +
`bad top-level domain name label "!!!": bad top-level domain name label rune '!'`,
}, {
name: "bootstraps_bad",

View File

@@ -1,28 +1,43 @@
package dnsforward
import (
"context"
"fmt"
"log/slog"
"net"
"os"
"strings"
"github.com/AdguardTeam/AdGuardHome/internal/ipset"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/miekg/dns"
)
// ipsetCtx is the ipset context. ipsetMgr can be nil.
type ipsetCtx struct {
// ipsetHandler is the ipset context. ipsetMgr can be nil.
type ipsetHandler struct {
ipsetMgr ipset.Manager
logger *slog.Logger
}
// init initializes the ipset context. It is not safe for concurrent use.
//
// TODO(a.garipov): Rewrite into a simple constructor?
func (c *ipsetCtx) init(ipsetConf []string) (err error) {
c.ipsetMgr, err = ipset.NewManager(ipsetConf)
if errors.Is(err, os.ErrInvalid) || errors.Is(err, os.ErrPermission) {
// newIpsetHandler returns a new initialized [ipsetHandler]. It is not safe for
// concurrent use.
func newIpsetHandler(
ctx context.Context,
logger *slog.Logger,
ipsetList []string,
) (h *ipsetHandler, err error) {
h = &ipsetHandler{
logger: logger,
}
conf := &ipset.Config{
Logger: logger,
Lines: ipsetList,
}
h.ipsetMgr, err = ipset.NewManager(ctx, conf)
if errors.Is(err, os.ErrInvalid) ||
errors.Is(err, os.ErrPermission) ||
errors.Is(err, errors.ErrUnsupported) {
// ipset cannot currently be initialized if the server was installed
// from Snap or when the user or the binary doesn't have the required
// permissions, or when the kernel doesn't support netfilter.
@@ -31,30 +46,28 @@ func (c *ipsetCtx) init(ipsetConf []string) (err error) {
//
// TODO(a.garipov): The Snap problem can probably be solved if we add
// the netlink-connector interface plug.
log.Info("ipset: warning: cannot initialize: %s", err)
logger.WarnContext(ctx, "cannot initialize", slogutil.KeyError, err)
return nil
} else if errors.Is(err, errors.ErrUnsupported) {
log.Info("ipset: warning: %s", err)
return nil
return h, nil
} else if err != nil {
return fmt.Errorf("initializing ipset: %w", err)
return nil, fmt.Errorf("initializing ipset: %w", err)
}
return h, nil
}
// close closes the Linux Netfilter connections. close can be called on a nil
// handler.
func (h *ipsetHandler) close() (err error) {
if h != nil && h.ipsetMgr != nil {
return h.ipsetMgr.Close()
}
return nil
}
// close closes the Linux Netfilter connections.
func (c *ipsetCtx) close() (err error) {
if c.ipsetMgr != nil {
return c.ipsetMgr.Close()
}
return nil
}
func (c *ipsetCtx) dctxIsfilled(dctx *dnsContext) (ok bool) {
// dctxIsFilled returns true if dctx has enough information to process.
func dctxIsFilled(dctx *dnsContext) (ok bool) {
return dctx != nil &&
dctx.responseFromUpstream &&
dctx.proxyCtx != nil &&
@@ -65,8 +78,8 @@ func (c *ipsetCtx) dctxIsfilled(dctx *dnsContext) (ok bool) {
// skipIpsetProcessing returns true when the ipset processing can be skipped for
// this request.
func (c *ipsetCtx) skipIpsetProcessing(dctx *dnsContext) (ok bool) {
if c == nil || c.ipsetMgr == nil || !c.dctxIsfilled(dctx) {
func (h *ipsetHandler) skipIpsetProcessing(dctx *dnsContext) (ok bool) {
if h == nil || h.ipsetMgr == nil || !dctxIsFilled(dctx) {
return true
}
@@ -108,31 +121,31 @@ func ipsFromAnswer(ans []dns.RR) (ip4s, ip6s []net.IP) {
}
// process adds the resolved IP addresses to the domain's ipsets, if any.
func (c *ipsetCtx) process(dctx *dnsContext) (rc resultCode) {
log.Debug("dnsforward: ipset: started processing")
defer log.Debug("dnsforward: ipset: finished processing")
func (h *ipsetHandler) process(dctx *dnsContext) (rc resultCode) {
// TODO(s.chzhen): Use passed context.
ctx := context.TODO()
h.logger.DebugContext(ctx, "started processing")
defer h.logger.DebugContext(ctx, "finished processing")
if c.skipIpsetProcessing(dctx) {
if h.skipIpsetProcessing(dctx) {
return resultCodeSuccess
}
log.Debug("ipset: starting processing")
req := dctx.proxyCtx.Req
host := req.Question[0].Name
host = strings.TrimSuffix(host, ".")
host = strings.ToLower(host)
ip4s, ip6s := ipsFromAnswer(dctx.proxyCtx.Res.Answer)
n, err := c.ipsetMgr.Add(host, ip4s, ip6s)
n, err := h.ipsetMgr.Add(ctx, host, ip4s, ip6s)
if err != nil {
// Consider ipset errors non-critical to the request.
log.Error("dnsforward: ipset: adding host ips: %s", err)
h.logger.ErrorContext(ctx, "adding host ips", slogutil.KeyError, err)
return resultCodeSuccess
}
log.Debug("dnsforward: ipset: added %d new ipset entries", n)
h.logger.DebugContext(ctx, "added new ipset entries", "num", n)
return resultCodeSuccess
}

View File

@@ -1,10 +1,12 @@
package dnsforward
import (
"context"
"net"
"testing"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
)
@@ -16,7 +18,7 @@ type fakeIpsetMgr struct {
}
// Add implements the aghnet.IpsetManager interface for *fakeIpsetMgr.
func (m *fakeIpsetMgr) Add(host string, ip4s, ip6s []net.IP) (n int, err error) {
func (m *fakeIpsetMgr) Add(_ context.Context, host string, ip4s, ip6s []net.IP) (n int, err error) {
m.ip4s = append(m.ip4s, ip4s...)
m.ip6s = append(m.ip6s, ip6s...)
@@ -58,7 +60,9 @@ func TestIpsetCtx_process(t *testing.T) {
responseFromUpstream: true,
}
ictx := &ipsetCtx{}
ictx := &ipsetHandler{
logger: slogutil.NewDiscardLogger(),
}
rc := ictx.process(dctx)
assert.Equal(t, resultCodeSuccess, rc)
@@ -77,8 +81,9 @@ func TestIpsetCtx_process(t *testing.T) {
}
m := &fakeIpsetMgr{}
ictx := &ipsetCtx{
ictx := &ipsetHandler{
ipsetMgr: m,
logger: slogutil.NewDiscardLogger(),
}
rc := ictx.process(dctx)
@@ -101,8 +106,9 @@ func TestIpsetCtx_process(t *testing.T) {
}
m := &fakeIpsetMgr{}
ictx := &ipsetCtx{
ictx := &ipsetHandler{
ipsetMgr: m,
logger: slogutil.NewDiscardLogger(),
}
rc := ictx.process(dctx)
@@ -124,8 +130,9 @@ func TestIpsetCtx_SkipIpsetProcessing(t *testing.T) {
}
m := &fakeIpsetMgr{}
ictx := &ipsetCtx{
ictx := &ipsetHandler{
ipsetMgr: m,
logger: slogutil.NewDiscardLogger(),
}
testCases := []struct {

View File

@@ -58,7 +58,7 @@ func (s *Server) genDNSFilterMessage(
return s.replyCompressed(req)
}
return s.newMsgNODATA(req)
return s.NewMsgNODATA(req)
}
switch res.Reason {
@@ -344,51 +344,6 @@ func (s *Server) makeResponseREFUSED(req *dns.Msg) *dns.Msg {
return s.reply(req, dns.RcodeRefused)
}
// newMsgNODATA returns a properly initialized NODATA response.
//
// See https://www.rfc-editor.org/rfc/rfc2308#section-2.2.
func (s *Server) newMsgNODATA(req *dns.Msg) (resp *dns.Msg) {
resp = s.reply(req, dns.RcodeSuccess)
resp.Ns = s.genSOA(req)
return resp
}
func (s *Server) genSOA(request *dns.Msg) []dns.RR {
zone := ""
if len(request.Question) > 0 {
zone = request.Question[0].Name
}
soa := dns.SOA{
// values copied from verisign's nonexistent .com domain
// their exact values are not important in our use case because they are used for domain transfers between primary/secondary DNS servers
Refresh: 1800,
Retry: 900,
Expire: 604800,
Minttl: 86400,
// copied from AdGuard DNS
Ns: "fake-for-negative-caching.adguard.com.",
Serial: 100500,
// rest is request-specific
Hdr: dns.RR_Header{
Name: zone,
Rrtype: dns.TypeSOA,
Ttl: s.dnsFilter.BlockedResponseTTL(),
Class: dns.ClassINET,
},
Mbox: "hostmaster.", // zone will be appended later if it's not empty or "."
}
if soa.Hdr.Ttl == 0 {
soa.Hdr.Ttl = defaultBlockedResponseTTL
}
if len(zone) > 0 && zone[0] != '.' {
soa.Mbox += zone
}
return []dns.RR{&soa}
}
// type check
var _ proxy.MessageConstructor = (*Server)(nil)
@@ -425,3 +380,52 @@ func (s *Server) NewMsgNOTIMPLEMENTED(req *dns.Msg) (resp *dns.Msg) {
return resp
}
// NewMsgNODATA implements the [proxy.MessageConstructor] interface for *Server.
func (s *Server) NewMsgNODATA(req *dns.Msg) (resp *dns.Msg) {
resp = s.reply(req, dns.RcodeSuccess)
resp.Ns = s.genSOA(req)
return resp
}
func (s *Server) genSOA(req *dns.Msg) []dns.RR {
zone := ""
if len(req.Question) > 0 {
zone = req.Question[0].Name
}
const defaultBlockedResponseTTL = 3600
soa := dns.SOA{
// Values copied from verisign's nonexistent.com domain.
//
// Their exact values are not important in our use case because they are
// used for domain transfers between primary/secondary DNS servers.
Refresh: 1800,
Retry: 900,
Expire: 604800,
Minttl: 86400,
// copied from AdGuard DNS
Ns: "fake-for-negative-caching.adguard.com.",
Serial: 100500,
// rest is request-specific
Hdr: dns.RR_Header{
Name: zone,
Rrtype: dns.TypeSOA,
Ttl: s.dnsFilter.BlockedResponseTTL(),
Class: dns.ClassINET,
},
// zone will be appended later if it's not ".".
Mbox: "hostmaster.",
}
if soa.Hdr.Ttl == 0 {
soa.Hdr.Ttl = defaultBlockedResponseTTL
}
if zone != "." {
soa.Mbox += zone
}
return []dns.RR{&soa}
}

View File

@@ -2,6 +2,7 @@ package dnsforward
import (
"cmp"
"context"
"encoding/binary"
"net"
"net/netip"
@@ -159,7 +160,7 @@ func (s *Server) processInitial(dctx *dnsContext) (rc resultCode) {
q := pctx.Req.Question[0]
qt := q.Qtype
if s.conf.AAAADisabled && qt == dns.TypeAAAA {
pctx.Res = s.newMsgNODATA(pctx.Req)
pctx.Res = s.NewMsgNODATA(pctx.Req)
return resultCodeFinish
}
@@ -203,7 +204,8 @@ func (s *Server) processClientIP(addr netip.Addr) {
s.serverLock.RLock()
defer s.serverLock.RUnlock()
s.addrProc.Process(addr)
// TODO(s.chzhen): Pass context.
s.addrProc.Process(context.TODO(), addr)
}
// processDDRQuery responds to Discovery of Designated Resolvers (DDR) SVCB

View File

@@ -2,6 +2,7 @@ package dnsforward
import (
"cmp"
"context"
"net"
"net/netip"
"testing"
@@ -90,7 +91,7 @@ func TestServer_ProcessInitial(t *testing.T) {
var gotAddr netip.Addr
s.addrProc = &aghtest.AddressProcessor{
OnProcess: func(ip netip.Addr) { gotAddr = ip },
OnProcess: func(ctx context.Context, ip netip.Addr) { gotAddr = ip },
OnClose: func() (err error) { panic("not implemented") },
}
@@ -431,7 +432,7 @@ func TestServer_ProcessDHCPHosts_localRestriction(t *testing.T) {
dnsFilter: createTestDNSFilter(t),
dhcpServer: dhcp,
localDomainSuffix: localDomainSuffix,
logger: slogutil.NewDiscardLogger(),
baseLogger: slogutil.NewDiscardLogger(),
}
req := &dns.Msg{
@@ -567,7 +568,7 @@ func TestServer_ProcessDHCPHosts(t *testing.T) {
dnsFilter: createTestDNSFilter(t),
dhcpServer: testDHCP,
localDomainSuffix: tc.suffix,
logger: slogutil.NewDiscardLogger(),
baseLogger: slogutil.NewDiscardLogger(),
}
req := &dns.Msg{

Some files were not shown because too many files have changed in this diff Show More