mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-11-24 22:15:45 +03:00
all: sync with master; upd chlog
This commit is contained in:
parent
80eb339896
commit
66b831072c
55 changed files with 24817 additions and 798 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -1,7 +1,7 @@
|
||||||
'name': 'build'
|
'name': 'build'
|
||||||
|
|
||||||
'env':
|
'env':
|
||||||
'GO_VERSION': '1.18.9'
|
'GO_VERSION': '1.19.6'
|
||||||
'NODE_VERSION': '14'
|
'NODE_VERSION': '14'
|
||||||
|
|
||||||
'on':
|
'on':
|
||||||
|
|
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
|
@ -1,7 +1,7 @@
|
||||||
'name': 'lint'
|
'name': 'lint'
|
||||||
|
|
||||||
'env':
|
'env':
|
||||||
'GO_VERSION': '1.18.9'
|
'GO_VERSION': '1.19.6'
|
||||||
|
|
||||||
'on':
|
'on':
|
||||||
'push':
|
'push':
|
||||||
|
|
106
CHANGELOG.md
106
CHANGELOG.md
|
@ -14,11 +14,11 @@ and this project adheres to
|
||||||
<!--
|
<!--
|
||||||
## [v0.108.0] - TBA
|
## [v0.108.0] - TBA
|
||||||
|
|
||||||
## [v0.107.24] - 2023-02-22 (APPROX.)
|
## [v0.107.25] - 2023-03-09 (APPROX.)
|
||||||
|
|
||||||
See also the [v0.107.24 GitHub milestone][ms-v0.107.24].
|
See also the [v0.107.25 GitHub milestone][ms-v0.107.25].
|
||||||
|
|
||||||
[ms-v0.107.24]: https://github.com/AdguardTeam/AdGuardHome/milestone/60?closed=1
|
[ms-v0.107.25]: https://github.com/AdguardTeam/AdGuardHome/milestone/61?closed=1
|
||||||
|
|
||||||
NOTE: Add new changes BELOW THIS COMMENT.
|
NOTE: Add new changes BELOW THIS COMMENT.
|
||||||
-->
|
-->
|
||||||
|
@ -29,6 +29,98 @@ NOTE: Add new changes ABOVE THIS COMMENT.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [v0.107.24] - 2023-02-15
|
||||||
|
|
||||||
|
See also the [v0.107.24 GitHub milestone][ms-v0.107.24].
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Go version has been updated, both because Go 1.18 has reached end of life an
|
||||||
|
to prevent the possibility of exploiting the Go vulnerabilities fixed in [Go
|
||||||
|
1.19.6][go-1.19.6].
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- The ability to disable statistics by using the new `statistics.enabled`
|
||||||
|
field. Previously it was necessary to set the `statistics_interval` to 0,
|
||||||
|
losing the previous value ([#1717], [#4299]).
|
||||||
|
- The ability to exclude domain names from the query log or statistics by using
|
||||||
|
the new `querylog.ignored` or `statistics.ignored` fields ([#1717], [#4299]).
|
||||||
|
The UI changes are coming in the upcoming releases.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
#### Configuration Changes
|
||||||
|
|
||||||
|
In this release, the schema version has changed from 14 to 16.
|
||||||
|
|
||||||
|
- Property `statistics_interval`, which in schema versions 15 and earlier used
|
||||||
|
to be a part of the `dns` object, is now a part of the `statistics` object:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# BEFORE:
|
||||||
|
'dns':
|
||||||
|
# …
|
||||||
|
'statistics_interval': 1
|
||||||
|
|
||||||
|
# AFTER:
|
||||||
|
'statistics':
|
||||||
|
# …
|
||||||
|
'interval': 1
|
||||||
|
```
|
||||||
|
|
||||||
|
To rollback this change, move the property back into the `dns` object and
|
||||||
|
change the `schema_version` back to `15`.
|
||||||
|
- The fields `dns.querylog_enabled`, `dns.querylog_file_enabled`,
|
||||||
|
`dns.querylog_interval`, and `dns.querylog_size_memory` have been moved to the
|
||||||
|
new `querylog` object.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# BEFORE:
|
||||||
|
'dns':
|
||||||
|
'querylog_enabled': true
|
||||||
|
'querylog_file_enabled': true
|
||||||
|
'querylog_interval': '2160h'
|
||||||
|
'querylog_size_memory': 1000
|
||||||
|
|
||||||
|
# AFTER:
|
||||||
|
'querylog':
|
||||||
|
'enabled': true
|
||||||
|
'file_enabled': true
|
||||||
|
'interval': '2160h'
|
||||||
|
'size_memory': 1000
|
||||||
|
```
|
||||||
|
|
||||||
|
To rollback this change, rename and move properties back into the `dns`
|
||||||
|
object, remove `querylog` object and `querylog.ignored` property, and change
|
||||||
|
the `schema_version` back to `14`.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- Go 1.19 support. Future versions will require at least Go 1.20 to build.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Setting the AD (Authenticated Data) flag on responses that have the DO (DNSSEC
|
||||||
|
OK) flag set but not the AD flag ([#5479]).
|
||||||
|
- Client names resolved via reverse DNS not being updated ([#4939]).
|
||||||
|
- The icon for League Of Legends on the Blocked services page ([#5433]).
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Go 1.18 support, as it has reached end of life.
|
||||||
|
|
||||||
|
[#1717]: https://github.com/AdguardTeam/AdGuardHome/issues/1717
|
||||||
|
[#4299]: https://github.com/AdguardTeam/AdGuardHome/issues/4299
|
||||||
|
[#4939]: https://github.com/AdguardTeam/AdGuardHome/issues/4939
|
||||||
|
[#5433]: https://github.com/AdguardTeam/AdGuardHome/issues/5433
|
||||||
|
[#5479]: https://github.com/AdguardTeam/AdGuardHome/issues/5479
|
||||||
|
|
||||||
|
[go-1.19.6]: https://groups.google.com/g/golang-announce/c/V0aBFqaFs_E
|
||||||
|
[ms-v0.107.24]: https://github.com/AdguardTeam/AdGuardHome/milestone/60?closed=1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [v0.107.23] - 2023-02-01
|
## [v0.107.23] - 2023-02-01
|
||||||
|
|
||||||
See also the [v0.107.23 GitHub milestone][ms-v0.107.23].
|
See also the [v0.107.23 GitHub milestone][ms-v0.107.23].
|
||||||
|
@ -1031,7 +1123,6 @@ In this release, the schema version has changed from 10 to 12.
|
||||||
|
|
||||||
To rollback this change, convert the property back into days and change the
|
To rollback this change, convert the property back into days and change the
|
||||||
`schema_version` back to `11`.
|
`schema_version` back to `11`.
|
||||||
|
|
||||||
- Property `rlimit_nofile`, which in schema versions 10 and earlier used to be
|
- Property `rlimit_nofile`, which in schema versions 10 and earlier used to be
|
||||||
on the top level, is now moved to the new `os` object:
|
on the top level, is now moved to the new `os` object:
|
||||||
|
|
||||||
|
@ -1578,11 +1669,12 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.24...HEAD
|
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.25...HEAD
|
||||||
[v0.107.24]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.23...v0.107.24
|
[v0.107.25]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.24...v0.107.25
|
||||||
-->
|
-->
|
||||||
|
|
||||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.23...HEAD
|
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.24...HEAD
|
||||||
|
[v0.107.24]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.23...v0.107.24
|
||||||
[v0.107.23]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.22...v0.107.23
|
[v0.107.23]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.22...v0.107.23
|
||||||
[v0.107.22]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.21...v0.107.22
|
[v0.107.22]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.21...v0.107.22
|
||||||
[v0.107.21]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.20...v0.107.21
|
[v0.107.21]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.20...v0.107.21
|
||||||
|
|
16
README.md
16
README.md
|
@ -81,12 +81,24 @@ code.
|
||||||
|
|
||||||
### <a href="#automated-install-linux-and-mac" id="automated-install-linux-and-mac" name="automated-install-linux-and-mac">Automated install (Unix)</a>
|
### <a href="#automated-install-linux-and-mac" id="automated-install-linux-and-mac" name="automated-install-linux-and-mac">Automated install (Unix)</a>
|
||||||
|
|
||||||
Run the following command in your terminal:
|
To install with `curl` run the following command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
|
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To install with `wget` run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
wget --no-verbose -O - https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
|
||||||
|
```
|
||||||
|
|
||||||
|
To install with `fetch` run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fetch -o - https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
|
||||||
|
```
|
||||||
|
|
||||||
The script also accepts some options:
|
The script also accepts some options:
|
||||||
|
|
||||||
* `-c <channel>` to use specified channel;
|
* `-c <channel>` to use specified channel;
|
||||||
|
@ -249,7 +261,7 @@ Run `make init` to prepare the development environment.
|
||||||
|
|
||||||
You will need this to build AdGuard Home:
|
You will need this to build AdGuard Home:
|
||||||
|
|
||||||
* [Go](https://golang.org/dl/) v1.18 or later;
|
* [Go](https://golang.org/dl/) v1.19 or later;
|
||||||
* [Node.js](https://nodejs.org/en/download/) v10.16.2 or later;
|
* [Node.js](https://nodejs.org/en/download/) v10.16.2 or later;
|
||||||
* [npm](https://www.npmjs.com/) v6.14 or later;
|
* [npm](https://www.npmjs.com/) v6.14 or later;
|
||||||
* [yarn](https://yarnpkg.com/) v1.22.5 or later.
|
* [yarn](https://yarnpkg.com/) v1.22.5 or later.
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
# Make sure to sync any changes with the branch overrides below.
|
# Make sure to sync any changes with the branch overrides below.
|
||||||
'variables':
|
'variables':
|
||||||
'channel': 'edge'
|
'channel': 'edge'
|
||||||
'dockerGo': 'adguard/golang-ubuntu:5.4'
|
'dockerGo': 'adguard/golang-ubuntu:6.1'
|
||||||
|
|
||||||
'stages':
|
'stages':
|
||||||
- 'Build frontend':
|
- 'Build frontend':
|
||||||
|
@ -223,6 +223,7 @@
|
||||||
|
|
||||||
channel="${bamboo.channel}"
|
channel="${bamboo.channel}"
|
||||||
readonly channel
|
readonly channel
|
||||||
|
|
||||||
case "$channel"
|
case "$channel"
|
||||||
in
|
in
|
||||||
('release')
|
('release')
|
||||||
|
@ -269,8 +270,10 @@
|
||||||
|
|
||||||
set -e -f -u -x
|
set -e -f -u -x
|
||||||
|
|
||||||
export CHANNEL="${bamboo.channel}"
|
channel="${bamboo.channel}"
|
||||||
if [ "$CHANNEL" != 'release' ] && [ "${CHANNEL}" != 'beta' ]
|
readonly channel
|
||||||
|
|
||||||
|
if [ "$channel" != 'release' ] && [ "${channel}" != 'beta' ]
|
||||||
then
|
then
|
||||||
echo "don't publish to GitHub Releases for this channel"
|
echo "don't publish to GitHub Releases for this channel"
|
||||||
|
|
||||||
|
@ -323,7 +326,7 @@
|
||||||
# need to build a few of these.
|
# need to build a few of these.
|
||||||
'variables':
|
'variables':
|
||||||
'channel': 'beta'
|
'channel': 'beta'
|
||||||
'dockerGo': 'adguard/golang-ubuntu:5.4'
|
'dockerGo': 'adguard/golang-ubuntu:6.1'
|
||||||
# release-vX.Y.Z branches are the branches from which the actual final release
|
# release-vX.Y.Z branches are the branches from which the actual final release
|
||||||
# is built.
|
# is built.
|
||||||
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
||||||
|
@ -338,4 +341,4 @@
|
||||||
# are the ones that actually get released.
|
# are the ones that actually get released.
|
||||||
'variables':
|
'variables':
|
||||||
'channel': 'release'
|
'channel': 'release'
|
||||||
'dockerGo': 'adguard/golang-ubuntu:5.4'
|
'dockerGo': 'adguard/golang-ubuntu:6.1'
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
'key': 'AHBRTSPECS'
|
'key': 'AHBRTSPECS'
|
||||||
'name': 'AdGuard Home - Build and run tests'
|
'name': 'AdGuard Home - Build and run tests'
|
||||||
'variables':
|
'variables':
|
||||||
'dockerGo': 'adguard/golang-ubuntu:5.4'
|
'dockerGo': 'adguard/golang-ubuntu:6.1'
|
||||||
|
|
||||||
'stages':
|
'stages':
|
||||||
- 'Tests':
|
- 'Tests':
|
||||||
|
|
|
@ -261,7 +261,7 @@
|
||||||
"query_log_configuration": "Налада часопіса",
|
"query_log_configuration": "Налада часопіса",
|
||||||
"query_log_disabled": "Часопіс запытаў выключаны, яго можна ўключыць у <0>наладах</0>",
|
"query_log_disabled": "Часопіс запытаў выключаны, яго можна ўключыць у <0>наладах</0>",
|
||||||
"query_log_strict_search": "Ужывайце падвойныя двукоссі для строгага пошуку",
|
"query_log_strict_search": "Ужывайце падвойныя двукоссі для строгага пошуку",
|
||||||
"query_log_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання запытаў? Пры скарачэнні інтэрвалу дадзеныя могуць быць згублены",
|
"query_log_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання запытаў? Пры памяншэнні інтэрвалу, некаторыя даныя могуць быць страчаны",
|
||||||
"anonymize_client_ip": "Ананімізацыя IP-адрасы кліента",
|
"anonymize_client_ip": "Ананімізацыя IP-адрасы кліента",
|
||||||
"anonymize_client_ip_desc": "Не захоўвайце поўныя IP-адрасы гэтых удзельнікаў у часопісах або статыстыцы",
|
"anonymize_client_ip_desc": "Не захоўвайце поўныя IP-адрасы гэтых удзельнікаў у часопісах або статыстыцы",
|
||||||
"dns_config": "Налады DNS-сервера",
|
"dns_config": "Налады DNS-сервера",
|
||||||
|
@ -356,7 +356,7 @@
|
||||||
"install_devices_android_list_5": "Зараз можна змяніць палі «DNS 1» і «DNS 2». Увядзіце ў іх адрасы AdGuard Home.",
|
"install_devices_android_list_5": "Зараз можна змяніць палі «DNS 1» і «DNS 2». Увядзіце ў іх адрасы AdGuard Home.",
|
||||||
"install_devices_ios_list_1": "Увайдзіце ў меню налад прылады.",
|
"install_devices_ios_list_1": "Увайдзіце ў меню налад прылады.",
|
||||||
"install_devices_ios_list_2": "Абярыце пункт «Wi-Fi» (для мабільных сетак ручная наладка DNS немагчыма).",
|
"install_devices_ios_list_2": "Абярыце пункт «Wi-Fi» (для мабільных сетак ручная наладка DNS немагчыма).",
|
||||||
"install_devices_ios_list_3": "Націсніце на назву сетцы, да якой прылада падлучана ў дадзены момант.",
|
"install_devices_ios_list_3": "Націсніце на назву актыўнай у дадзены момант сеткі.",
|
||||||
"install_devices_ios_list_4": "У поле «DNS» увядзіце ўвядзіце адрасы AdGuard Home.",
|
"install_devices_ios_list_4": "У поле «DNS» увядзіце ўвядзіце адрасы AdGuard Home.",
|
||||||
"get_started": "Паехалі",
|
"get_started": "Паехалі",
|
||||||
"next": "Далей",
|
"next": "Далей",
|
||||||
|
@ -517,10 +517,10 @@
|
||||||
"filter_updated": "Спіс паспяхова абноўлены",
|
"filter_updated": "Спіс паспяхова абноўлены",
|
||||||
"statistics_configuration": "Канфігурацыя статыстыкі",
|
"statistics_configuration": "Канфігурацыя статыстыкі",
|
||||||
"statistics_retention": "Захаванне статыстыкі",
|
"statistics_retention": "Захаванне статыстыкі",
|
||||||
"statistics_retention_desc": "Калі вы зменшыце значэнне інтэрвалу, некаторыя дадзеныя могуць быць згублены",
|
"statistics_retention_desc": "Калі вы паменшыце значэнне інтэрвалу, некаторыя даныя могуць быць страчаны",
|
||||||
"statistics_clear": "Ачысціць статыстыку",
|
"statistics_clear": "Ачысціць статыстыку",
|
||||||
"statistics_clear_confirm": "Вы ўпэўнены, што хочаце ачысціць статыстыку?",
|
"statistics_clear_confirm": "Вы ўпэўнены, што хочаце ачысціць статыстыку?",
|
||||||
"statistics_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання статыстыкі? Пры скарачэнні інтэрвалу дадзеныя могуць быць згублены",
|
"statistics_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання статыстыкі? Пры памяншэнні інтэрвалу, некаторыя даныя могуць быць страчаны",
|
||||||
"statistics_cleared": "Статыстыка паспяхова вычышчана",
|
"statistics_cleared": "Статыстыка паспяхова вычышчана",
|
||||||
"statistics_enable": "Уключыць статыстыку",
|
"statistics_enable": "Уключыць статыстыку",
|
||||||
"interval_hours": "{{count}} гадзіна",
|
"interval_hours": "{{count}} гадзіна",
|
||||||
|
@ -598,7 +598,7 @@
|
||||||
"show_blocked_responses": "Заблакавана",
|
"show_blocked_responses": "Заблакавана",
|
||||||
"show_whitelisted_responses": "Белы спіс",
|
"show_whitelisted_responses": "Белы спіс",
|
||||||
"show_processed_responses": "Апрацавана",
|
"show_processed_responses": "Апрацавана",
|
||||||
"blocked_safebrowsing": "Заблакавана згодна базе дадзеных Safe Browsing",
|
"blocked_safebrowsing": "Заблакіравана згодна з базай даных Safe Browsing",
|
||||||
"blocked_adult_websites": "Заблакавана Бацькоўскім кантролем",
|
"blocked_adult_websites": "Заблакавана Бацькоўскім кантролем",
|
||||||
"blocked_threats": "Заблакавана пагроз",
|
"blocked_threats": "Заблакавана пагроз",
|
||||||
"allowed": "Дазволены",
|
"allowed": "Дазволены",
|
||||||
|
@ -639,7 +639,7 @@
|
||||||
"safe_browsing": "Бяспечны інтэрнэт",
|
"safe_browsing": "Бяспечны інтэрнэт",
|
||||||
"served_from_cache": "{{value}} <i>(атрымана з кэша)</i>",
|
"served_from_cache": "{{value}} <i>(атрымана з кэша)</i>",
|
||||||
"form_error_password_length": "Пароль павінен быць не менш за {{value}} сімвалаў",
|
"form_error_password_length": "Пароль павінен быць не менш за {{value}} сімвалаў",
|
||||||
"anonymizer_notification": "<0>Заўвага:</0> Ананімізацыя IP уключана. Вы можаце адключыць яго ў <1>Агульных наладах</1> .",
|
"anonymizer_notification": "<0>Заўвага:</0> Ананімізацыя IP уключана. Вы можаце адключыць яе ў <1>Агульных наладах</1>.",
|
||||||
"confirm_dns_cache_clear": "Вы ўпэўнены, што хочаце ачысціць кэш DNS?",
|
"confirm_dns_cache_clear": "Вы ўпэўнены, што хочаце ачысціць кэш DNS?",
|
||||||
"cache_cleared": "Кэш DNS паспяхова ачышчаны",
|
"cache_cleared": "Кэш DNS паспяхова ачышчаны",
|
||||||
"clear_cache": "Ачысціць кэш"
|
"clear_cache": "Ачысціць кэш"
|
||||||
|
|
|
@ -454,7 +454,7 @@
|
||||||
"updates_checked": "La nueva versión de AdGuard Home está disponible",
|
"updates_checked": "La nueva versión de AdGuard Home está disponible",
|
||||||
"updates_version_equal": "AdGuard Home está actualizado",
|
"updates_version_equal": "AdGuard Home está actualizado",
|
||||||
"check_updates_now": "Buscar actualizaciones ahora",
|
"check_updates_now": "Buscar actualizaciones ahora",
|
||||||
"version_request_error": "La búsqueda de actualizaciones falló. Por favor revisa tu conexión a Internet.",
|
"version_request_error": "Error buscar la actualización. Comprueba tu conexión a Internet.",
|
||||||
"dns_privacy": "DNS cifrado",
|
"dns_privacy": "DNS cifrado",
|
||||||
"setup_dns_privacy_1": "<0>DNS mediante TLS:</0> Utiliza la cadena <1>{{address}}</1>.",
|
"setup_dns_privacy_1": "<0>DNS mediante TLS:</0> Utiliza la cadena <1>{{address}}</1>.",
|
||||||
"setup_dns_privacy_2": "<0>DNS mediante HTTPS:</0> Utiliza la cadena <1>{{address}}</1>.",
|
"setup_dns_privacy_2": "<0>DNS mediante HTTPS:</0> Utiliza la cadena <1>{{address}}</1>.",
|
||||||
|
@ -640,7 +640,7 @@
|
||||||
"served_from_cache": "{{value}} <i>(servido desde la caché)</i>",
|
"served_from_cache": "{{value}} <i>(servido desde la caché)</i>",
|
||||||
"form_error_password_length": "La contraseña debe tener al menos {{value}} caracteres",
|
"form_error_password_length": "La contraseña debe tener al menos {{value}} caracteres",
|
||||||
"anonymizer_notification": "<0>Nota:</0> La anonimización de IP está habilitada. Puedes deshabilitarla en <1>Configuración general</1>.",
|
"anonymizer_notification": "<0>Nota:</0> La anonimización de IP está habilitada. Puedes deshabilitarla en <1>Configuración general</1>.",
|
||||||
"confirm_dns_cache_clear": "¿Estás seguro de que deseas borrar la caché de DNS?",
|
"confirm_dns_cache_clear": "¿Estás seguro de que deseas borrar la caché DNS?",
|
||||||
"cache_cleared": "Caché DNS borrado con éxito",
|
"cache_cleared": "Caché DNS borrado correctamente",
|
||||||
"clear_cache": "Borrar caché"
|
"clear_cache": "Borrar caché"
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
"unavailable_dhcp": "DHCP ei ole käytettävissä",
|
"unavailable_dhcp": "DHCP ei ole käytettävissä",
|
||||||
"unavailable_dhcp_desc": "AdGuard Home ei voi suorittaa DHCP-palvelinta käyttöjärjestelmässäsi",
|
"unavailable_dhcp_desc": "AdGuard Home ei voi suorittaa DHCP-palvelinta käyttöjärjestelmässäsi",
|
||||||
"dhcp_title": "DHCP-palvelin (kokeellinen!)",
|
"dhcp_title": "DHCP-palvelin (kokeellinen!)",
|
||||||
"dhcp_description": "Jos reitittimessäsi ei ole DHCP-asetuksia, voit käyttää AdGuard Homen omaa sisäänrakennettua DHCP-palvelinta.",
|
"dhcp_description": "Jollei reitittimesi tarjoa DHCP-asetuksia, voit käyttää AdGuard Homen omaa sisäänrakennettua DHCP-palvelinta.",
|
||||||
"dhcp_enable": "Ota DHCP-palvelin käyttöön",
|
"dhcp_enable": "Ota DHCP-palvelin käyttöön",
|
||||||
"dhcp_disable": "Poista DHCP-palvelin käytöstä",
|
"dhcp_disable": "Poista DHCP-palvelin käytöstä",
|
||||||
"dhcp_not_found": "On turvallista ottaa sisäänrakennettu DHCP-palvelin käyttöön, koska AdGuard Home ei havainnut verkossa muita aktiivisia DHCP-palvelimia. Suosittelemme, että varmistat tämän vielä itse, koska automaattinen tunnistus ei ole 100% varma.",
|
"dhcp_not_found": "On turvallista ottaa sisäänrakennettu DHCP-palvelin käyttöön, koska AdGuard Home ei havainnut verkossa muita aktiivisia DHCP-palvelimia. Suosittelemme, että varmistat tämän vielä itse, koska automaattinen tunnistus ei ole 100% varma.",
|
||||||
|
|
|
@ -128,7 +128,7 @@
|
||||||
"number_of_dns_query_days": "过去 {{count}} 天内处理的 DNS 查询总数",
|
"number_of_dns_query_days": "过去 {{count}} 天内处理的 DNS 查询总数",
|
||||||
"number_of_dns_query_days_plural": "在过去的 {{count}} 天内处理了多少个 DNS 查询",
|
"number_of_dns_query_days_plural": "在过去的 {{count}} 天内处理了多少个 DNS 查询",
|
||||||
"number_of_dns_query_24_hours": "过去 24 小时内处理的 DNS 请求总数",
|
"number_of_dns_query_24_hours": "过去 24 小时内处理的 DNS 请求总数",
|
||||||
"number_of_dns_query_blocked_24_hours": "被广告过滤器和 Hosts 拦截清单阻止的 DNS 请求总数",
|
"number_of_dns_query_blocked_24_hours": "被广告过滤器和 Hosts 黑名单阻止的 DNS 请求总数",
|
||||||
"number_of_dns_query_blocked_24_hours_by_sec": "被 AdGuard 安全浏览模块阻止的 DNS 请求总数",
|
"number_of_dns_query_blocked_24_hours_by_sec": "被 AdGuard 安全浏览模块阻止的 DNS 请求总数",
|
||||||
"number_of_dns_query_blocked_24_hours_adult": "被阻止的成人网站总数",
|
"number_of_dns_query_blocked_24_hours_adult": "被阻止的成人网站总数",
|
||||||
"enforced_save_search": "强制安全搜索",
|
"enforced_save_search": "强制安全搜索",
|
||||||
|
@ -146,10 +146,10 @@
|
||||||
"no_servers_specified": "未找到指定的服务器",
|
"no_servers_specified": "未找到指定的服务器",
|
||||||
"general_settings": "常规设置",
|
"general_settings": "常规设置",
|
||||||
"dns_settings": "DNS 设置",
|
"dns_settings": "DNS 设置",
|
||||||
"dns_blocklists": "DNS 拦截列表",
|
"dns_blocklists": "DNS 黑名单",
|
||||||
"dns_allowlists": "DNS 允许列表",
|
"dns_allowlists": "DNS 白名单",
|
||||||
"dns_blocklists_desc": "AdGuard Home将阻止匹配DNS拦截清单的域名",
|
"dns_blocklists_desc": "AdGuard Home将阻止匹配DNS拦截清单的域名",
|
||||||
"dns_allowlists_desc": "来自DNS允许列表的域将被允许,即使它们位于任意阻止列表中也是如此",
|
"dns_allowlists_desc": "来自 DNS 白名单的域名将被允许,即使它们位于任意黑名单中也是如此。",
|
||||||
"custom_filtering_rules": "自定义过滤规则",
|
"custom_filtering_rules": "自定义过滤规则",
|
||||||
"encryption_settings": "加密设置",
|
"encryption_settings": "加密设置",
|
||||||
"dhcp_settings": "DHCP 设置",
|
"dhcp_settings": "DHCP 设置",
|
||||||
|
@ -178,22 +178,22 @@
|
||||||
"delete_table_action": "删除",
|
"delete_table_action": "删除",
|
||||||
"elapsed": "耗时",
|
"elapsed": "耗时",
|
||||||
"filters_and_hosts_hint": "AdGuard Home 可以解析基础的 adblock 规则和 Hosts 语法。",
|
"filters_and_hosts_hint": "AdGuard Home 可以解析基础的 adblock 规则和 Hosts 语法。",
|
||||||
"no_blocklist_added": "未添加阻止列表",
|
"no_blocklist_added": "未添加黑名单",
|
||||||
"no_whitelist_added": "未添加允许列表",
|
"no_whitelist_added": "未添加白名单",
|
||||||
"add_blocklist": "添加阻止列表",
|
"add_blocklist": "添加黑名单",
|
||||||
"add_allowlist": "添加允许列表",
|
"add_allowlist": "添加白名单",
|
||||||
"cancel_btn": "取消",
|
"cancel_btn": "取消",
|
||||||
"enter_name_hint": "输入名称",
|
"enter_name_hint": "输入名称",
|
||||||
"enter_url_or_path_hint": "请输入URL或列表的绝对路径",
|
"enter_url_or_path_hint": "请输入URL或列表的绝对路径",
|
||||||
"check_updates_btn": "检查更新",
|
"check_updates_btn": "检查更新",
|
||||||
"new_blocklist": "新封锁清单",
|
"new_blocklist": "新封锁清单",
|
||||||
"new_allowlist": "新的允许清单",
|
"new_allowlist": "新增白名单",
|
||||||
"edit_blocklist": "编辑阻止列表",
|
"edit_blocklist": "编辑黑名单",
|
||||||
"edit_allowlist": "编辑允许列表",
|
"edit_allowlist": "编辑白名单",
|
||||||
"choose_blocklist": "选择拦截列表",
|
"choose_blocklist": "选择黑名单",
|
||||||
"choose_allowlist": "选择允许列表",
|
"choose_allowlist": "选择白名单",
|
||||||
"enter_valid_blocklist": "输入有效的阻止列表URL",
|
"enter_valid_blocklist": "输入有效的黑名单 URL",
|
||||||
"enter_valid_allowlist": "输入有效的允许列表URL",
|
"enter_valid_allowlist": "输入有效的白名单 URL",
|
||||||
"form_error_url_format": "无效的 URL 格式",
|
"form_error_url_format": "无效的 URL 格式",
|
||||||
"form_error_url_or_path_format": "无效的 URL 或列表的绝对路径",
|
"form_error_url_or_path_format": "无效的 URL 或列表的绝对路径",
|
||||||
"custom_filter_rules": "自定义过滤器规则",
|
"custom_filter_rules": "自定义过滤器规则",
|
||||||
|
@ -269,9 +269,9 @@
|
||||||
"dns_cache_config_desc": "您可以在此处配置 DNS 缓存",
|
"dns_cache_config_desc": "您可以在此处配置 DNS 缓存",
|
||||||
"blocking_mode": "拦截模式",
|
"blocking_mode": "拦截模式",
|
||||||
"default": "默认",
|
"default": "默认",
|
||||||
"nxdomain": "无效域名",
|
"nxdomain": "NXDOMAIN",
|
||||||
"refused": "REFUSED",
|
"refused": "REFUSED",
|
||||||
"null_ip": "无效 IP",
|
"null_ip": "空 IP",
|
||||||
"custom_ip": "自定义 IP",
|
"custom_ip": "自定义 IP",
|
||||||
"blocking_ipv4": "拦截 IPv4",
|
"blocking_ipv4": "拦截 IPv4",
|
||||||
"blocking_ipv6": "拦截 IPv6",
|
"blocking_ipv6": "拦截 IPv6",
|
||||||
|
@ -296,7 +296,7 @@
|
||||||
"blocking_mode_default": "默认:被 Adblock 规则拦截时反应为零 IP 地址(A记录:0.0.0.0;AAAA记录:::);被/etc/hosts 规则拦截时反应为规则中指定 IP 地址",
|
"blocking_mode_default": "默认:被 Adblock 规则拦截时反应为零 IP 地址(A记录:0.0.0.0;AAAA记录:::);被/etc/hosts 规则拦截时反应为规则中指定 IP 地址",
|
||||||
"blocking_mode_refused": "REFUSED:以 REFUSED 码响应请求",
|
"blocking_mode_refused": "REFUSED:以 REFUSED 码响应请求",
|
||||||
"blocking_mode_nxdomain": "NXDOMAIN:以NXDOMAIN码响应",
|
"blocking_mode_nxdomain": "NXDOMAIN:以NXDOMAIN码响应",
|
||||||
"blocking_mode_null_ip": "空IP:以零IP地址响应(A记录 0.0.0.0;AAAA记录 ::)",
|
"blocking_mode_null_ip": "空 IP:以零 IP 地址响应(A 记录 0.0.0.0;AAAA 记录 ::)",
|
||||||
"blocking_mode_custom_ip": "自定IP:以手动设置的IP地址响应",
|
"blocking_mode_custom_ip": "自定IP:以手动设置的IP地址响应",
|
||||||
"theme_auto": "自动",
|
"theme_auto": "自动",
|
||||||
"theme_light": "浅色主题",
|
"theme_light": "浅色主题",
|
||||||
|
@ -605,7 +605,7 @@
|
||||||
"filtered": "已过滤",
|
"filtered": "已过滤",
|
||||||
"rewritten": "重写项",
|
"rewritten": "重写项",
|
||||||
"safe_search": "安全搜索",
|
"safe_search": "安全搜索",
|
||||||
"blocklist": "拦截列表",
|
"blocklist": "黑名单",
|
||||||
"milliseconds_abbreviation": "毫秒",
|
"milliseconds_abbreviation": "毫秒",
|
||||||
"cache_size": "缓存大小",
|
"cache_size": "缓存大小",
|
||||||
"cache_size_desc": "DNS 缓存大小(单位:字节)。要关闭缓存,请留空。",
|
"cache_size_desc": "DNS 缓存大小(单位:字节)。要关闭缓存,请留空。",
|
||||||
|
@ -626,7 +626,7 @@
|
||||||
"filter_category_general_desc": "在大多数设备上阻止跟踪和广告的列表",
|
"filter_category_general_desc": "在大多数设备上阻止跟踪和广告的列表",
|
||||||
"filter_category_security_desc": "专用于拦截恶意软件、钓鱼或欺诈域名的列表",
|
"filter_category_security_desc": "专用于拦截恶意软件、钓鱼或欺诈域名的列表",
|
||||||
"filter_category_regional_desc": "专注于区域广告和跟踪服务器的列表",
|
"filter_category_regional_desc": "专注于区域广告和跟踪服务器的列表",
|
||||||
"filter_category_other_desc": "其他阻止列表",
|
"filter_category_other_desc": "其他黑名单",
|
||||||
"setup_config_to_enable_dhcp_server": "设置配置以启用 DHCP 服务器",
|
"setup_config_to_enable_dhcp_server": "设置配置以启用 DHCP 服务器",
|
||||||
"original_response": "原始响应",
|
"original_response": "原始响应",
|
||||||
"click_to_view_queries": "点击查看查询",
|
"click_to_view_queries": "点击查看查询",
|
||||||
|
|
|
@ -53,7 +53,7 @@ export const STATUS_COLORS = {
|
||||||
export const REPOSITORY = {
|
export const REPOSITORY = {
|
||||||
URL: 'https://github.com/AdguardTeam/AdGuardHome',
|
URL: 'https://github.com/AdguardTeam/AdGuardHome',
|
||||||
TRACKERS_DB:
|
TRACKERS_DB:
|
||||||
'https://github.com/AdguardTeam/AdGuardHome/tree/master/client/src/helpers/trackers/adguard.json',
|
'https://github.com/AdguardTeam/AdGuardHome/tree/master/client/src/helpers/trackers/trackers.json',
|
||||||
ISSUES: 'https://github.com/AdguardTeam/AdGuardHome/issues/new/choose',
|
ISSUES: 'https://github.com/AdguardTeam/AdGuardHome/issues/new/choose',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -160,12 +160,6 @@ export default {
|
||||||
"homepage": "https://github.com/DandelionSprout/adfilt",
|
"homepage": "https://github.com/DandelionSprout/adfilt",
|
||||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_6.txt"
|
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_6.txt"
|
||||||
},
|
},
|
||||||
"energized_spark": {
|
|
||||||
"name": "Energized Spark",
|
|
||||||
"categoryId": "general",
|
|
||||||
"homepage": "https://energized.pro/",
|
|
||||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_28.txt"
|
|
||||||
},
|
|
||||||
"hagezi_personal": {
|
"hagezi_personal": {
|
||||||
"name": "HaGeZi Personal Black \u0026 White",
|
"name": "HaGeZi Personal Black \u0026 White",
|
||||||
"categoryId": "general",
|
"categoryId": "general",
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import whotracksmeDb from './whotracksme.json';
|
|
||||||
import whotracksmeWebsites from './whotracksme_web.json';
|
import whotracksmeWebsites from './whotracksme_web.json';
|
||||||
import adguardDb from './adguard.json';
|
import trackersDb from './trackers.json';
|
||||||
import { REPOSITORY } from '../constants';
|
import { REPOSITORY } from '../constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,6 +38,7 @@ const getWhotracksmeUrl = (trackerId) => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the source metadata for the specified tracker
|
* Gets the source metadata for the specified tracker
|
||||||
|
*
|
||||||
* @param {TrackerData} trackerData tracker data
|
* @param {TrackerData} trackerData tracker data
|
||||||
* @returns {source} source metadata or null if no matching tracker found
|
* @returns {source} source metadata or null if no matching tracker found
|
||||||
*/
|
*/
|
||||||
|
@ -64,14 +64,26 @@ export const getSourceData = (trackerData) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets tracker data in the specified database
|
* Converts the JSON string source into numeric source for AdGuard Home
|
||||||
|
*
|
||||||
|
* @param {TrackerData} trackerData tracker data
|
||||||
|
* @returns {number} source number
|
||||||
|
*/
|
||||||
|
const convertSource = (sourceStr) => {
|
||||||
|
if (!sourceStr || sourceStr !== 'AdGuard') {
|
||||||
|
return sources.WHOTRACKSME;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sources.ADGUARD;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets tracker data from the trackers database
|
||||||
*
|
*
|
||||||
* @param {String} domainName domain name to check
|
* @param {String} domainName domain name to check
|
||||||
* @param {*} trackersDb trackers database
|
|
||||||
* @param {number} source source ID
|
|
||||||
* @returns {TrackerData} tracker data or null if no matching tracker found
|
* @returns {TrackerData} tracker data or null if no matching tracker found
|
||||||
*/
|
*/
|
||||||
const getTrackerDataFromDb = (domainName, trackersDb, source) => {
|
export const getTrackerData = (domainName) => {
|
||||||
if (!domainName) {
|
if (!domainName) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +100,7 @@ const getTrackerDataFromDb = (domainName, trackersDb, source) => {
|
||||||
if (trackerId) {
|
if (trackerId) {
|
||||||
const trackerData = trackersDb.trackers[trackerId];
|
const trackerData = trackersDb.trackers[trackerId];
|
||||||
const categoryName = trackersDb.categories[trackerData.categoryId];
|
const categoryName = trackersDb.categories[trackerData.categoryId];
|
||||||
trackerData.source = source;
|
const source = convertSource(trackerData.source);
|
||||||
const sourceData = getSourceData(trackerData);
|
const sourceData = getSourceData(trackerData);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -105,22 +117,3 @@ const getTrackerDataFromDb = (domainName, trackersDb, source) => {
|
||||||
// No tracker found for the specified domain
|
// No tracker found for the specified domain
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets tracker data from the trackers database
|
|
||||||
*
|
|
||||||
* @param {String} domainName domain name to check
|
|
||||||
* @returns {TrackerData} tracker data or null if no matching tracker found
|
|
||||||
*/
|
|
||||||
export const getTrackerData = (domainName) => {
|
|
||||||
if (!domainName) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = getTrackerDataFromDb(domainName, adguardDb, sources.ADGUARD);
|
|
||||||
if (!data) {
|
|
||||||
data = getTrackerDataFromDb(domainName, whotracksmeDb, sources.WHOTRACKSME);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
23750
client/src/helpers/trackers/trackers.json
Normal file
23750
client/src/helpers/trackers/trackers.json
Normal file
File diff suppressed because it is too large
Load diff
39
go.mod
39
go.mod
|
@ -1,10 +1,10 @@
|
||||||
module github.com/AdguardTeam/AdGuardHome
|
module github.com/AdguardTeam/AdGuardHome
|
||||||
|
|
||||||
go 1.18
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
// TODO(a.garipov): Return to a tagged version once DNS64 is in.
|
// TODO(a.garipov): Use v0.48.0 when it's released.
|
||||||
github.com/AdguardTeam/dnsproxy v0.46.6-0.20230125113741-98cb8a899e49
|
github.com/AdguardTeam/dnsproxy v0.47.1-0.20230207130636-533058b17239
|
||||||
github.com/AdguardTeam/golibs v0.11.4
|
github.com/AdguardTeam/golibs v0.11.4
|
||||||
github.com/AdguardTeam/urlfilter v0.16.1
|
github.com/AdguardTeam/urlfilter v0.16.1
|
||||||
github.com/NYTimes/gziphandler v1.1.1
|
github.com/NYTimes/gziphandler v1.1.1
|
||||||
|
@ -19,27 +19,26 @@ require (
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8
|
github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8
|
||||||
github.com/kardianos/service v1.2.2
|
github.com/kardianos/service v1.2.2
|
||||||
github.com/lucas-clemente/quic-go v0.31.1
|
|
||||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
|
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
|
||||||
github.com/mdlayher/netlink v1.7.1
|
github.com/mdlayher/netlink v1.7.1
|
||||||
// TODO(a.garipov): This package is deprecated; find a new one or use
|
// TODO(a.garipov): This package is deprecated; find a new one or use
|
||||||
// our own code for that. Perhaps, use gopacket.
|
// our own code for that. Perhaps, use gopacket.
|
||||||
github.com/mdlayher/raw v0.1.0
|
github.com/mdlayher/raw v0.1.0
|
||||||
github.com/miekg/dns v1.1.50
|
github.com/miekg/dns v1.1.50
|
||||||
|
github.com/quic-go/quic-go v0.32.0
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.1
|
||||||
github.com/ti-mo/netfilter v0.5.0
|
github.com/ti-mo/netfilter v0.5.0
|
||||||
go.etcd.io/bbolt v1.3.7
|
go.etcd.io/bbolt v1.3.7
|
||||||
golang.org/x/crypto v0.5.0
|
golang.org/x/crypto v0.6.0
|
||||||
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201
|
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb
|
||||||
golang.org/x/net v0.5.0
|
golang.org/x/net v0.7.0
|
||||||
golang.org/x/sys v0.4.0
|
golang.org/x/sys v0.5.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
howett.net/plist v1.0.0
|
howett.net/plist v1.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.1.0 // indirect
|
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||||
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
|
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
|
||||||
github.com/ameshkov/dnsstamps v1.0.3 // indirect
|
github.com/ameshkov/dnsstamps v1.0.3 // indirect
|
||||||
|
@ -48,20 +47,22 @@ require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||||
github.com/golang/mock v1.6.0 // indirect
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
github.com/google/pprof v0.0.0-20230131232505-5a9e8f65f08f // indirect
|
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
|
||||||
github.com/josharian/native v1.1.0 // indirect
|
github.com/josharian/native v1.1.0 // indirect
|
||||||
github.com/marten-seemann/qpack v0.3.0 // indirect
|
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.4 // indirect
|
|
||||||
github.com/marten-seemann/qtls-go1-19 v0.1.2 // indirect
|
|
||||||
github.com/mdlayher/packet v1.1.1 // indirect
|
github.com/mdlayher/packet v1.1.1 // indirect
|
||||||
github.com/mdlayher/socket v0.4.0 // indirect
|
github.com/mdlayher/socket v0.4.0 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.8.0 // indirect
|
github.com/onsi/ginkgo/v2 v2.8.1 // indirect
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect
|
github.com/quic-go/qpack v0.4.0 // indirect
|
||||||
golang.org/x/mod v0.7.0 // indirect
|
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect
|
||||||
|
github.com/quic-go/qtls-go1-19 v0.2.0 // indirect
|
||||||
|
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
|
||||||
|
github.com/u-root/uio v0.0.0-20230215032506-9aa6f7e2d72c // indirect
|
||||||
|
golang.org/x/mod v0.8.0 // indirect
|
||||||
golang.org/x/sync v0.1.0 // indirect
|
golang.org/x/sync v0.1.0 // indirect
|
||||||
golang.org/x/text v0.6.0 // indirect
|
golang.org/x/text v0.7.0 // indirect
|
||||||
golang.org/x/tools v0.5.0 // indirect
|
golang.org/x/tools v0.6.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
73
go.sum
73
go.sum
|
@ -1,5 +1,5 @@
|
||||||
github.com/AdguardTeam/dnsproxy v0.46.6-0.20230125113741-98cb8a899e49 h1:TDZsKB8BrKA2na6p5l20BvEu3MmgOWhIfTANz5laFuE=
|
github.com/AdguardTeam/dnsproxy v0.47.1-0.20230207130636-533058b17239 h1:n1oOiywOvdeqWLto809bK1rK1EPDkpaSfT/r1OiCVaQ=
|
||||||
github.com/AdguardTeam/dnsproxy v0.46.6-0.20230125113741-98cb8a899e49/go.mod h1:ZEkTmTJ2XInT3aVy0mHtEnSWSclpHHj/9hfNXDuAk5k=
|
github.com/AdguardTeam/dnsproxy v0.47.1-0.20230207130636-533058b17239/go.mod h1:+Sdi5ISrjDFbeCsKNqzcC1Ag7pJ5Hh9y+UBNb3dfqJ4=
|
||||||
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||||
github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw=
|
github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw=
|
||||||
github.com/AdguardTeam/golibs v0.11.4 h1:IltyvxwCTN+xxJF5sh6VadF8Zfbf8elgCm9dgijSVzM=
|
github.com/AdguardTeam/golibs v0.11.4 h1:IltyvxwCTN+xxJF5sh6VadF8Zfbf8elgCm9dgijSVzM=
|
||||||
|
@ -7,8 +7,6 @@ github.com/AdguardTeam/golibs v0.11.4/go.mod h1:87bN2x4VsTritptE3XZg9l8T6gznWsIx
|
||||||
github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
|
github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
|
||||||
github.com/AdguardTeam/urlfilter v0.16.1 h1:ZPi0rjqo8cQf2FVdzo6cqumNoHZx2KPXj2yZa1A5BBw=
|
github.com/AdguardTeam/urlfilter v0.16.1 h1:ZPi0rjqo8cQf2FVdzo6cqumNoHZx2KPXj2yZa1A5BBw=
|
||||||
github.com/AdguardTeam/urlfilter v0.16.1/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI=
|
github.com/AdguardTeam/urlfilter v0.16.1/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI=
|
||||||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
|
||||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
|
||||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||||
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
|
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
|
||||||
|
@ -57,8 +55,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
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/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||||
github.com/google/pprof v0.0.0-20230131232505-5a9e8f65f08f h1:gl1DCiSk+mrXXBGPm6CEeS2MkJuMVzAOrXg34oVj1QI=
|
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U=
|
||||||
github.com/google/pprof v0.0.0-20230131232505-5a9e8f65f08f/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
|
||||||
github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU=
|
github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU=
|
||||||
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
||||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
@ -85,14 +83,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/lucas-clemente/quic-go v0.31.1 h1:O8Od7hfioqq0PMYHDyBkxU2aA7iZ2W9pjbrWuja2YR4=
|
|
||||||
github.com/lucas-clemente/quic-go v0.31.1/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g=
|
|
||||||
github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE=
|
|
||||||
github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g=
|
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.4 h1:ogomB+lWV3Vmwiu6RTwDVTMGx+9j7SEi98e8QB35Its=
|
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.4/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
|
||||||
github.com/marten-seemann/qtls-go1-19 v0.1.2 h1:ZevAEqKXH0bZmoOBPiqX2h5rhQ7cbZi+X+rlq2JUbCE=
|
|
||||||
github.com/marten-seemann/qtls-go1-19 v0.1.2/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
|
||||||
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
||||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 h1:2oDp6OOhLxQ9JBoUuysVz9UZ9uI6oLUbvAZu0x8o+vE=
|
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 h1:2oDp6OOhLxQ9JBoUuysVz9UZ9uI6oLUbvAZu0x8o+vE=
|
||||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og=
|
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og=
|
||||||
|
@ -118,16 +108,29 @@ github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI=
|
github.com/onsi/ginkgo/v2 v2.8.1 h1:xFTEVwOFa1D/Ty24Ws1npBWkDYEV9BqZrsDxVrVkrrU=
|
||||||
github.com/onsi/ginkgo/v2 v2.8.0/go.mod h1:6JsQiECmxCa3V5st74AL/AmsV482EDdVrGaVW6z3oYU=
|
github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc=
|
||||||
github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
|
github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
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/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
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/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U=
|
||||||
|
github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc=
|
||||||
|
github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk=
|
||||||
|
github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||||
|
github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI=
|
||||||
|
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||||
|
github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA=
|
||||||
|
github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo=
|
||||||
github.com/shirou/gopsutil/v3 v3.21.8 h1:nKct+uP0TV8DjjNiHanKf8SAuub+GNsbrOtM9Nl9biA=
|
github.com/shirou/gopsutil/v3 v3.21.8 h1:nKct+uP0TV8DjjNiHanKf8SAuub+GNsbrOtM9Nl9biA=
|
||||||
github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ=
|
github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
@ -151,23 +154,24 @@ github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev
|
||||||
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
|
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
|
||||||
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
|
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
|
||||||
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
|
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
|
||||||
github.com/u-root/uio v0.0.0-20221213070652-c3537552635f h1:dpx1PHxYqAnXzbryJrWP1NQLzEjwcVgFLhkknuFQ7ww=
|
|
||||||
github.com/u-root/uio v0.0.0-20221213070652-c3537552635f/go.mod h1:IogEAUBXDEwX7oR/BMmCctShYs80ql4hF0ySdzGxf7E=
|
github.com/u-root/uio v0.0.0-20221213070652-c3537552635f/go.mod h1:IogEAUBXDEwX7oR/BMmCctShYs80ql4hF0ySdzGxf7E=
|
||||||
|
github.com/u-root/uio v0.0.0-20230215032506-9aa6f7e2d72c h1:PHoGTnweZP+KIg/8Zc6+iOesrIF5yHkpb4GBDxHm7yE=
|
||||||
|
github.com/u-root/uio v0.0.0-20230215032506-9aa6f7e2d72c/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||||
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
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.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||||
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 h1:BEABXpNXLEz0WxtA+6CQIz2xkg80e+1zrhWyMcq8VzE=
|
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w=
|
||||||
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
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.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
@ -184,8 +188,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
|
@ -218,24 +222,24 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4=
|
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||||
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -244,12 +248,11 @@ google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscL
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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 h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
"github.com/lucas-clemente/quic-go"
|
"github.com/quic-go/quic-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateClientID returns an error if id is not a valid ClientID.
|
// ValidateClientID returns an error if id is not a valid ClientID.
|
||||||
|
@ -151,25 +151,7 @@ func (s *Server) clientIDFromDNSContext(pctx *proxy.DNSContext) (clientID string
|
||||||
func clientServerName(pctx *proxy.DNSContext, proto proxy.Proto) (srvName string, err error) {
|
func clientServerName(pctx *proxy.DNSContext, proto proxy.Proto) (srvName string, err error) {
|
||||||
switch proto {
|
switch proto {
|
||||||
case proxy.ProtoHTTPS:
|
case proxy.ProtoHTTPS:
|
||||||
// github.com/lucas-clemente/quic-go seems to not populate the TLS
|
srvName = pctx.HTTPRequest.TLS.ServerName
|
||||||
// field. So, if the request comes over HTTP/3, use the Host header
|
|
||||||
// value as the server name.
|
|
||||||
//
|
|
||||||
// See https://github.com/lucas-clemente/quic-go/issues/2879.
|
|
||||||
//
|
|
||||||
// TODO(a.garipov): Remove this crutch once they fix it.
|
|
||||||
r := pctx.HTTPRequest
|
|
||||||
if r.ProtoAtLeast(3, 0) {
|
|
||||||
var host string
|
|
||||||
host, err = netutil.SplitHost(r.Host)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("parsing host: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
srvName = host
|
|
||||||
} else if connState := r.TLS; connState != nil {
|
|
||||||
srvName = r.TLS.ServerName
|
|
||||||
}
|
|
||||||
case proxy.ProtoQUIC:
|
case proxy.ProtoQUIC:
|
||||||
qConn := pctx.QUICConnection
|
qConn := pctx.QUICConnection
|
||||||
conn, ok := qConn.(quicConnection)
|
conn, ok := qConn.(quicConnection)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/lucas-clemente/quic-go"
|
"github.com/quic-go/quic-go"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -55,7 +55,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantClientID string
|
wantClientID string
|
||||||
wantErrMsg string
|
wantErrMsg string
|
||||||
strictSNI bool
|
strictSNI bool
|
||||||
useHTTP3 bool
|
|
||||||
}{{
|
}{{
|
||||||
name: "udp",
|
name: "udp",
|
||||||
proto: proxy.ProtoUDP,
|
proto: proxy.ProtoUDP,
|
||||||
|
@ -64,7 +63,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantClientID: "",
|
wantClientID: "",
|
||||||
wantErrMsg: "",
|
wantErrMsg: "",
|
||||||
strictSNI: false,
|
strictSNI: false,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "tls_no_clientid",
|
name: "tls_no_clientid",
|
||||||
proto: proxy.ProtoTLS,
|
proto: proxy.ProtoTLS,
|
||||||
|
@ -73,7 +71,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantClientID: "",
|
wantClientID: "",
|
||||||
wantErrMsg: "",
|
wantErrMsg: "",
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "tls_no_client_server_name",
|
name: "tls_no_client_server_name",
|
||||||
proto: proxy.ProtoTLS,
|
proto: proxy.ProtoTLS,
|
||||||
|
@ -83,7 +80,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantErrMsg: `clientid check: client server name "" ` +
|
wantErrMsg: `clientid check: client server name "" ` +
|
||||||
`doesn't match host server name "example.com"`,
|
`doesn't match host server name "example.com"`,
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "tls_no_client_server_name_no_strict",
|
name: "tls_no_client_server_name_no_strict",
|
||||||
proto: proxy.ProtoTLS,
|
proto: proxy.ProtoTLS,
|
||||||
|
@ -92,7 +88,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantClientID: "",
|
wantClientID: "",
|
||||||
wantErrMsg: "",
|
wantErrMsg: "",
|
||||||
strictSNI: false,
|
strictSNI: false,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "tls_clientid",
|
name: "tls_clientid",
|
||||||
proto: proxy.ProtoTLS,
|
proto: proxy.ProtoTLS,
|
||||||
|
@ -101,7 +96,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantClientID: "cli",
|
wantClientID: "cli",
|
||||||
wantErrMsg: "",
|
wantErrMsg: "",
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "tls_clientid_hostname_error",
|
name: "tls_clientid_hostname_error",
|
||||||
proto: proxy.ProtoTLS,
|
proto: proxy.ProtoTLS,
|
||||||
|
@ -111,7 +105,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantErrMsg: `clientid check: client server name "cli.example.net" ` +
|
wantErrMsg: `clientid check: client server name "cli.example.net" ` +
|
||||||
`doesn't match host server name "example.com"`,
|
`doesn't match host server name "example.com"`,
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "tls_invalid_clientid",
|
name: "tls_invalid_clientid",
|
||||||
proto: proxy.ProtoTLS,
|
proto: proxy.ProtoTLS,
|
||||||
|
@ -121,7 +114,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantErrMsg: `clientid check: invalid clientid "!!!": ` +
|
wantErrMsg: `clientid check: invalid clientid "!!!": ` +
|
||||||
`bad domain name label rune '!'`,
|
`bad domain name label rune '!'`,
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "tls_clientid_too_long",
|
name: "tls_clientid_too_long",
|
||||||
proto: proxy.ProtoTLS,
|
proto: proxy.ProtoTLS,
|
||||||
|
@ -133,7 +125,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
`pqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789": ` +
|
`pqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789": ` +
|
||||||
`domain name label is too long: got 72, max 63`,
|
`domain name label is too long: got 72, max 63`,
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "quic_clientid",
|
name: "quic_clientid",
|
||||||
proto: proxy.ProtoQUIC,
|
proto: proxy.ProtoQUIC,
|
||||||
|
@ -142,7 +133,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantClientID: "cli",
|
wantClientID: "cli",
|
||||||
wantErrMsg: "",
|
wantErrMsg: "",
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "tls_clientid_issue3437",
|
name: "tls_clientid_issue3437",
|
||||||
proto: proxy.ProtoTLS,
|
proto: proxy.ProtoTLS,
|
||||||
|
@ -152,7 +142,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantErrMsg: `clientid check: client server name "cli.myexample.com" ` +
|
wantErrMsg: `clientid check: client server name "cli.myexample.com" ` +
|
||||||
`doesn't match host server name "example.com"`,
|
`doesn't match host server name "example.com"`,
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "tls_case",
|
name: "tls_case",
|
||||||
proto: proxy.ProtoTLS,
|
proto: proxy.ProtoTLS,
|
||||||
|
@ -161,7 +150,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantClientID: "insensitive",
|
wantClientID: "insensitive",
|
||||||
wantErrMsg: ``,
|
wantErrMsg: ``,
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "quic_case",
|
name: "quic_case",
|
||||||
proto: proxy.ProtoQUIC,
|
proto: proxy.ProtoQUIC,
|
||||||
|
@ -170,7 +158,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantClientID: "insensitive",
|
wantClientID: "insensitive",
|
||||||
wantErrMsg: ``,
|
wantErrMsg: ``,
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "https_no_clientid",
|
name: "https_no_clientid",
|
||||||
proto: proxy.ProtoHTTPS,
|
proto: proxy.ProtoHTTPS,
|
||||||
|
@ -179,7 +166,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantClientID: "",
|
wantClientID: "",
|
||||||
wantErrMsg: "",
|
wantErrMsg: "",
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
}, {
|
||||||
name: "https_clientid",
|
name: "https_clientid",
|
||||||
proto: proxy.ProtoHTTPS,
|
proto: proxy.ProtoHTTPS,
|
||||||
|
@ -188,16 +174,6 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
wantClientID: "cli",
|
wantClientID: "cli",
|
||||||
wantErrMsg: "",
|
wantErrMsg: "",
|
||||||
strictSNI: true,
|
strictSNI: true,
|
||||||
useHTTP3: false,
|
|
||||||
}, {
|
|
||||||
name: "https_clientid_quic",
|
|
||||||
proto: proxy.ProtoHTTPS,
|
|
||||||
hostSrvName: "example.com",
|
|
||||||
cliSrvName: "cli.example.com",
|
|
||||||
wantClientID: "cli",
|
|
||||||
wantErrMsg: "",
|
|
||||||
strictSNI: true,
|
|
||||||
useHTTP3: true,
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
@ -219,7 +195,7 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
|
|
||||||
switch tc.proto {
|
switch tc.proto {
|
||||||
case proxy.ProtoHTTPS:
|
case proxy.ProtoHTTPS:
|
||||||
httpReq = newHTTPReq(tc.cliSrvName, tc.useHTTP3)
|
httpReq = newHTTPReq(tc.cliSrvName)
|
||||||
case proxy.ProtoQUIC:
|
case proxy.ProtoQUIC:
|
||||||
qconn = testQUICConnection{
|
qconn = testQUICConnection{
|
||||||
serverName: tc.cliSrvName,
|
serverName: tc.cliSrvName,
|
||||||
|
@ -246,21 +222,11 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// newHTTPReq is a helper to create HTTP requests for tests.
|
// newHTTPReq is a helper to create HTTP requests for tests.
|
||||||
func newHTTPReq(cliSrvName string, useHTTP3 bool) (r *http.Request) {
|
func newHTTPReq(cliSrvName string) (r *http.Request) {
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
Path: "/dns-query",
|
Path: "/dns-query",
|
||||||
}
|
}
|
||||||
|
|
||||||
if useHTTP3 {
|
|
||||||
return &http.Request{
|
|
||||||
ProtoMajor: 3,
|
|
||||||
ProtoMinor: 0,
|
|
||||||
URL: u,
|
|
||||||
Host: cliSrvName,
|
|
||||||
TLS: &tls.ConnectionState{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &http.Request{
|
return &http.Request{
|
||||||
ProtoMajor: 1,
|
ProtoMajor: 1,
|
||||||
ProtoMinor: 1,
|
ProtoMinor: 1,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -225,7 +226,7 @@ type ServerConfig struct {
|
||||||
LocalPTRResolvers []string
|
LocalPTRResolvers []string
|
||||||
|
|
||||||
// DNS64Prefixes is a slice of NAT64 prefixes to be used for DNS64.
|
// DNS64Prefixes is a slice of NAT64 prefixes to be used for DNS64.
|
||||||
DNS64Prefixes []string
|
DNS64Prefixes []netip.Prefix
|
||||||
|
|
||||||
// ResolveClients signals if the RDNS should resolve clients' addresses.
|
// ResolveClients signals if the RDNS should resolve clients' addresses.
|
||||||
ResolveClients bool
|
ResolveClients bool
|
||||||
|
@ -271,6 +272,8 @@ func (s *Server) createProxyConfig() (conf proxy.Config, err error) {
|
||||||
RequestHandler: s.handleDNSRequest,
|
RequestHandler: s.handleDNSRequest,
|
||||||
EnableEDNSClientSubnet: srvConf.EnableEDNSClientSubnet,
|
EnableEDNSClientSubnet: srvConf.EnableEDNSClientSubnet,
|
||||||
MaxGoroutines: int(srvConf.MaxGoroutines),
|
MaxGoroutines: int(srvConf.MaxGoroutines),
|
||||||
|
UseDNS64: srvConf.UseDNS64,
|
||||||
|
DNS64Prefs: srvConf.DNS64Prefixes,
|
||||||
}
|
}
|
||||||
|
|
||||||
if srvConf.CacheSize != 0 {
|
if srvConf.CacheSize != 0 {
|
||||||
|
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||||
|
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||||
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
"github.com/AdguardTeam/golibs/stringutil"
|
"github.com/AdguardTeam/golibs/stringutil"
|
||||||
|
@ -17,6 +19,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// To transfer information between modules
|
// To transfer information between modules
|
||||||
|
//
|
||||||
|
// TODO(s.chzhen): Add lowercased, non-FQDN version of the hostname from the
|
||||||
|
// question of the request.
|
||||||
type dnsContext struct {
|
type dnsContext struct {
|
||||||
proxyCtx *proxy.DNSContext
|
proxyCtx *proxy.DNSContext
|
||||||
|
|
||||||
|
@ -419,7 +424,7 @@ func (s *Server) processDHCPHosts(dctx *dnsContext) (rc resultCode) {
|
||||||
}
|
}
|
||||||
resp.Answer = append(resp.Answer, a)
|
resp.Answer = append(resp.Answer, a)
|
||||||
case dns.TypeAAAA:
|
case dns.TypeAAAA:
|
||||||
if len(s.dns64Prefs) > 0 {
|
if s.dns64Pref != (netip.Prefix{}) {
|
||||||
// Respond with DNS64-mapped address for IPv4 host if DNS64 is
|
// Respond with DNS64-mapped address for IPv4 host if DNS64 is
|
||||||
// enabled.
|
// enabled.
|
||||||
aaaa := &dns.AAAA{
|
aaaa := &dns.AAAA{
|
||||||
|
@ -468,15 +473,6 @@ func (s *Server) processRestrictLocal(dctx *dnsContext) (rc resultCode) {
|
||||||
return resultCodeSuccess
|
return resultCodeSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.shouldStripDNS64(ip) {
|
|
||||||
// Strip the prefix from the address to get the original IPv4.
|
|
||||||
ip = ip[nat64PrefixLen:]
|
|
||||||
|
|
||||||
// Treat a DNS64-prefixed address as a locally served one since those
|
|
||||||
// queries should never be sent to the global DNS.
|
|
||||||
dctx.unreversedReqIP = ip
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restrict an access to local addresses for external clients. We also
|
// Restrict an access to local addresses for external clients. We also
|
||||||
// assume that all the DHCP leases we give are locally served or at least
|
// assume that all the DHCP leases we give are locally served or at least
|
||||||
// shouldn't be accessible externally.
|
// shouldn't be accessible externally.
|
||||||
|
@ -655,13 +651,7 @@ func (s *Server) processUpstream(dctx *dnsContext) (rc resultCode) {
|
||||||
|
|
||||||
s.setCustomUpstream(pctx, dctx.clientID)
|
s.setCustomUpstream(pctx, dctx.clientID)
|
||||||
|
|
||||||
origReqAD := false
|
reqWantsDNSSEC := s.setReqAD(req)
|
||||||
if s.conf.EnableDNSSEC {
|
|
||||||
origReqAD = req.AuthenticatedData
|
|
||||||
if !req.AuthenticatedData {
|
|
||||||
req.AuthenticatedData = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the request further since it wasn't filtered.
|
// Process the request further since it wasn't filtered.
|
||||||
prx := s.proxy()
|
prx := s.proxy()
|
||||||
|
@ -671,23 +661,73 @@ func (s *Server) processUpstream(dctx *dnsContext) (rc resultCode) {
|
||||||
return resultCodeError
|
return resultCodeError
|
||||||
}
|
}
|
||||||
|
|
||||||
if dctx.err = prx.Resolve(pctx); dctx.err != nil {
|
if err := prx.Resolve(pctx); err != nil {
|
||||||
return resultCodeError
|
if errors.Is(err, upstream.ErrNoUpstreams) {
|
||||||
|
// Do not even put into querylog. Currently this happens either
|
||||||
|
// when the private resolvers enabled and the request is DNS64 PTR,
|
||||||
|
// or when the client isn't considered local by prx.
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): Make proxy detect local client the same way as
|
||||||
|
// AGH does.
|
||||||
|
pctx.Res = s.genNXDomain(req)
|
||||||
|
|
||||||
|
return resultCodeFinish
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.performDNS64(prx, dctx) == resultCodeError {
|
dctx.err = err
|
||||||
|
|
||||||
return resultCodeError
|
return resultCodeError
|
||||||
}
|
}
|
||||||
|
|
||||||
dctx.responseFromUpstream = true
|
dctx.responseFromUpstream = true
|
||||||
dctx.responseAD = pctx.Res.AuthenticatedData
|
dctx.responseAD = pctx.Res.AuthenticatedData
|
||||||
|
|
||||||
if s.conf.EnableDNSSEC && !origReqAD {
|
s.setRespAD(pctx, reqWantsDNSSEC)
|
||||||
|
|
||||||
|
return resultCodeSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
// setReqAD changes the request based on the server settings. wantsDNSSEC is
|
||||||
|
// false if the response should be cleared of the AD bit.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov, e.burkov): This should probably be done in module dnsproxy.
|
||||||
|
func (s *Server) setReqAD(req *dns.Msg) (wantsDNSSEC bool) {
|
||||||
|
if !s.conf.EnableDNSSEC {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
origReqAD := req.AuthenticatedData
|
||||||
|
req.AuthenticatedData = true
|
||||||
|
|
||||||
|
// Per [RFC 6840] says, validating resolvers should only set the AD bit when
|
||||||
|
// the response has the AD bit set and the request contained either a set DO
|
||||||
|
// bit or a set AD bit. So, if neither of these is true, clear the AD bits
|
||||||
|
// in [Server.setRespAD].
|
||||||
|
//
|
||||||
|
// [RFC 6840]: https://datatracker.ietf.org/doc/html/rfc6840#section-5.8
|
||||||
|
return origReqAD || hasDO(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasDO returns true if msg has EDNS(0) options and the DNSSEC OK flag is set
|
||||||
|
// in there.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Move to golibs/dnsmsg when it's there.
|
||||||
|
func hasDO(msg *dns.Msg) (do bool) {
|
||||||
|
o := msg.IsEdns0()
|
||||||
|
if o == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.Do()
|
||||||
|
}
|
||||||
|
|
||||||
|
// setRespAD changes the request and response based on the server settings and
|
||||||
|
// the original request data.
|
||||||
|
func (s *Server) setRespAD(pctx *proxy.DNSContext, reqWantsDNSSEC bool) {
|
||||||
|
if s.conf.EnableDNSSEC && !reqWantsDNSSEC {
|
||||||
pctx.Req.AuthenticatedData = false
|
pctx.Req.AuthenticatedData = false
|
||||||
pctx.Res.AuthenticatedData = false
|
pctx.Res.AuthenticatedData = false
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultCodeSuccess
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// isDHCPClientHostQ returns true if q is from a request for a DHCP client
|
// isDHCPClientHostQ returns true if q is from a request for a DHCP client
|
||||||
|
|
|
@ -1,34 +1,10 @@
|
||||||
package dnsforward
|
package dnsforward
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
|
||||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
|
||||||
"github.com/AdguardTeam/golibs/mathutil"
|
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
|
||||||
"github.com/miekg/dns"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// maxNAT64PrefixBitLen is the maximum length of a NAT64 prefix in bits.
|
|
||||||
// See https://datatracker.ietf.org/doc/html/rfc6147#section-5.2.
|
|
||||||
maxNAT64PrefixBitLen = 96
|
|
||||||
|
|
||||||
// nat64PrefixLen is the length of a NAT64 prefix in bytes.
|
|
||||||
nat64PrefixLen = net.IPv6len - net.IPv4len
|
|
||||||
|
|
||||||
// maxDNS64SynTTL is the maximum TTL for synthesized DNS64 responses with no
|
|
||||||
// SOA records in seconds.
|
|
||||||
//
|
|
||||||
// If the SOA RR was not delivered with the negative response to the AAAA
|
|
||||||
// query, then the DNS64 SHOULD use the TTL of the original A RR or 600
|
|
||||||
// seconds, whichever is shorter.
|
|
||||||
//
|
|
||||||
// See https://datatracker.ietf.org/doc/html/rfc6147#section-5.1.7.
|
|
||||||
maxDNS64SynTTL uint32 = 600
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// setupDNS64 initializes DNS64 settings, the NAT64 prefixes in particular. If
|
// setupDNS64 initializes DNS64 settings, the NAT64 prefixes in particular. If
|
||||||
|
@ -38,227 +14,22 @@ const (
|
||||||
// is specified explicitly. Each prefix also validated to be a valid IPv6
|
// is specified explicitly. Each prefix also validated to be a valid IPv6
|
||||||
// CIDR with a maximum length of 96 bits. The first specified prefix is then
|
// CIDR with a maximum length of 96 bits. The first specified prefix is then
|
||||||
// used to synthesize AAAA records.
|
// used to synthesize AAAA records.
|
||||||
func (s *Server) setupDNS64() (err error) {
|
func (s *Server) setupDNS64() {
|
||||||
if !s.conf.UseDNS64 {
|
if !s.conf.UseDNS64 {
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
l := len(s.conf.DNS64Prefixes)
|
if len(s.conf.DNS64Prefixes) == 0 {
|
||||||
if l == 0 {
|
// dns64WellKnownPref is the default prefix to use in an algorithmic
|
||||||
s.dns64Prefs = []netip.Prefix{dns64WellKnownPref}
|
// mapping for DNS64.
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
prefs := make([]netip.Prefix, 0, l)
|
|
||||||
for i, pref := range s.conf.DNS64Prefixes {
|
|
||||||
var p netip.Prefix
|
|
||||||
p, err = netip.ParsePrefix(pref)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("prefix at index %d: %w", i, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
addr := p.Addr()
|
|
||||||
if !addr.Is6() {
|
|
||||||
return fmt.Errorf("prefix at index %d: %q is not an IPv6 prefix", i, pref)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.Bits() > maxNAT64PrefixBitLen {
|
|
||||||
return fmt.Errorf("prefix at index %d: %q is too long for DNS64", i, pref)
|
|
||||||
}
|
|
||||||
|
|
||||||
prefs = append(prefs, p.Masked())
|
|
||||||
}
|
|
||||||
|
|
||||||
s.dns64Prefs = prefs
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkDNS64 checks if DNS64 should be performed. It returns a DNS64 request
|
|
||||||
// to resolve or nil if DNS64 is not desired. It also filters resp to not
|
|
||||||
// contain any NAT64 excluded addresses in the answer section, if needed. Both
|
|
||||||
// req and resp must not be nil.
|
|
||||||
//
|
//
|
||||||
// See https://datatracker.ietf.org/doc/html/rfc6147.
|
// See https://datatracker.ietf.org/doc/html/rfc6052#section-2.1.
|
||||||
func (s *Server) checkDNS64(req, resp *dns.Msg) (dns64Req *dns.Msg) {
|
dns64WellKnownPref := netip.MustParsePrefix("64:ff9b::/96")
|
||||||
if len(s.dns64Prefs) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
q := req.Question[0]
|
s.dns64Pref = dns64WellKnownPref
|
||||||
if q.Qtype != dns.TypeAAAA || q.Qclass != dns.ClassINET {
|
} else {
|
||||||
// DNS64 operation for classes other than IN is undefined, and a DNS64
|
s.dns64Pref = s.conf.DNS64Prefixes[0]
|
||||||
// MUST behave as though no DNS64 function is configured.
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rcode := resp.Rcode
|
|
||||||
if rcode == dns.RcodeNameError {
|
|
||||||
// A result with RCODE=3 (Name Error) is handled according to normal DNS
|
|
||||||
// operation (which is normally to return the error to the client).
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if rcode == dns.RcodeSuccess {
|
|
||||||
// If resolver receives an answer with at least one AAAA record
|
|
||||||
// containing an address outside any of the excluded range(s), then it
|
|
||||||
// by default SHOULD build an answer section for a response including
|
|
||||||
// only the AAAA record(s) that do not contain any of the addresses
|
|
||||||
// inside the excluded ranges.
|
|
||||||
var hasAnswers bool
|
|
||||||
if resp.Answer, hasAnswers = s.filterNAT64Answers(resp.Answer); hasAnswers {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any other RCODE is treated as though the RCODE were 0 and the answer
|
|
||||||
// section were empty.
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dns.Msg{
|
|
||||||
MsgHdr: dns.MsgHdr{
|
|
||||||
Id: dns.Id(),
|
|
||||||
RecursionDesired: req.RecursionDesired,
|
|
||||||
AuthenticatedData: req.AuthenticatedData,
|
|
||||||
CheckingDisabled: req.CheckingDisabled,
|
|
||||||
},
|
|
||||||
Question: []dns.Question{{
|
|
||||||
Name: req.Question[0].Name,
|
|
||||||
Qtype: dns.TypeA,
|
|
||||||
Qclass: dns.ClassINET,
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// filterNAT64Answers filters out AAAA records that are within one of NAT64
|
|
||||||
// exclusion prefixes. hasAnswers is true if the filtered slice contains at
|
|
||||||
// least a single AAAA answer not within the prefixes or a CNAME.
|
|
||||||
func (s *Server) filterNAT64Answers(rrs []dns.RR) (filtered []dns.RR, hasAnswers bool) {
|
|
||||||
filtered = make([]dns.RR, 0, len(rrs))
|
|
||||||
for _, ans := range rrs {
|
|
||||||
switch ans := ans.(type) {
|
|
||||||
case *dns.AAAA:
|
|
||||||
addr, err := netutil.IPToAddrNoMapped(ans.AAAA)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("dnsforward: bad AAAA record: %s", err)
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.withinDNS64(addr) {
|
|
||||||
// Filter the record.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
filtered, hasAnswers = append(filtered, ans), true
|
|
||||||
case *dns.CNAME, *dns.DNAME:
|
|
||||||
// If the response contains a CNAME or a DNAME, then the CNAME or
|
|
||||||
// DNAME chain is followed until the first terminating A or AAAA
|
|
||||||
// record is reached.
|
|
||||||
//
|
|
||||||
// Just treat CNAME and DNAME responses as passable answers since
|
|
||||||
// AdGuard Home doesn't follow any of these chains except the
|
|
||||||
// dnsrewrite-defined ones.
|
|
||||||
filtered, hasAnswers = append(filtered, ans), true
|
|
||||||
default:
|
|
||||||
filtered = append(filtered, ans)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filtered, hasAnswers
|
|
||||||
}
|
|
||||||
|
|
||||||
// synthDNS64 synthesizes a DNS64 response using the original response as a
|
|
||||||
// basis and modifying it with data from resp. It returns true if the response
|
|
||||||
// was actually modified.
|
|
||||||
func (s *Server) synthDNS64(origReq, origResp, resp *dns.Msg) (ok bool) {
|
|
||||||
if len(resp.Answer) == 0 {
|
|
||||||
// If there is an empty answer, then the DNS64 responds to the original
|
|
||||||
// querying client with the answer the DNS64 received to the original
|
|
||||||
// (initiator's) query.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Time to Live (TTL) field is set to the minimum of the TTL of the
|
|
||||||
// original A RR and the SOA RR for the queried domain. If the original
|
|
||||||
// response contains no SOA records, the minimum of the TTL of the original
|
|
||||||
// A RR and [maxDNS64SynTTL] should be used. See [maxDNS64SynTTL].
|
|
||||||
soaTTL := maxDNS64SynTTL
|
|
||||||
for _, rr := range origResp.Ns {
|
|
||||||
if hdr := rr.Header(); hdr.Rrtype == dns.TypeSOA && hdr.Name == origReq.Question[0].Name {
|
|
||||||
soaTTL = hdr.Ttl
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newAns := make([]dns.RR, 0, len(resp.Answer))
|
|
||||||
for _, ans := range resp.Answer {
|
|
||||||
rr := s.synthRR(ans, soaTTL)
|
|
||||||
if rr == nil {
|
|
||||||
// The error should have already been logged.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
newAns = append(newAns, rr)
|
|
||||||
}
|
|
||||||
|
|
||||||
origResp.Answer = newAns
|
|
||||||
origResp.Ns = resp.Ns
|
|
||||||
origResp.Extra = resp.Extra
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// dns64WellKnownPref is the default prefix to use in an algorithmic mapping for
|
|
||||||
// DNS64. See https://datatracker.ietf.org/doc/html/rfc6052#section-2.1.
|
|
||||||
var dns64WellKnownPref = netip.MustParsePrefix("64:ff9b::/96")
|
|
||||||
|
|
||||||
// withinDNS64 checks if ip is within one of the configured DNS64 prefixes.
|
|
||||||
//
|
|
||||||
// TODO(e.burkov): We actually using bytes of only the first prefix from the
|
|
||||||
// set to construct the answer, so consider using some implementation of a
|
|
||||||
// prefix set for the rest.
|
|
||||||
func (s *Server) withinDNS64(ip netip.Addr) (ok bool) {
|
|
||||||
for _, n := range s.dns64Prefs {
|
|
||||||
if n.Contains(ip) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// shouldStripDNS64 returns true if DNS64 is enabled and ip has either one of
|
|
||||||
// custom DNS64 prefixes or the Well-Known one. This is intended to be used
|
|
||||||
// with PTR requests.
|
|
||||||
//
|
|
||||||
// The requirement is to match any Pref64::/n used at the site, and not merely
|
|
||||||
// the locally configured Pref64::/n. This is because end clients could ask for
|
|
||||||
// a PTR record matching an address received through a different (site-provided)
|
|
||||||
// DNS64.
|
|
||||||
//
|
|
||||||
// See https://datatracker.ietf.org/doc/html/rfc6147#section-5.3.1.
|
|
||||||
func (s *Server) shouldStripDNS64(ip net.IP) (ok bool) {
|
|
||||||
if len(s.dns64Prefs) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
addr, err := netutil.IPToAddr(ip, netutil.AddrFamilyIPv6)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case s.withinDNS64(addr):
|
|
||||||
log.Debug("dnsforward: %s is within DNS64 custom prefix set", ip)
|
|
||||||
case dns64WellKnownPref.Contains(addr):
|
|
||||||
log.Debug("dnsforward: %s is within DNS64 well-known prefix", ip)
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mapDNS64 maps ip to IPv6 address using configured DNS64 prefix. ip must be a
|
// mapDNS64 maps ip to IPv6 address using configured DNS64 prefix. ip must be a
|
||||||
|
@ -267,79 +38,12 @@ func (s *Server) shouldStripDNS64(ip net.IP) (ok bool) {
|
||||||
func (s *Server) mapDNS64(ip netip.Addr) (mapped net.IP) {
|
func (s *Server) mapDNS64(ip netip.Addr) (mapped net.IP) {
|
||||||
// Don't mask the address here since it should have already been masked on
|
// Don't mask the address here since it should have already been masked on
|
||||||
// initialization stage.
|
// initialization stage.
|
||||||
pref := s.dns64Prefs[0].Addr().As16()
|
pref := s.dns64Pref.Masked().Addr().As16()
|
||||||
ipData := ip.As4()
|
ipData := ip.As4()
|
||||||
|
|
||||||
mapped = make(net.IP, net.IPv6len)
|
mapped = make(net.IP, net.IPv6len)
|
||||||
copy(mapped[:nat64PrefixLen], pref[:])
|
copy(mapped[:proxy.NAT64PrefixLength], pref[:])
|
||||||
copy(mapped[nat64PrefixLen:], ipData[:])
|
copy(mapped[proxy.NAT64PrefixLength:], ipData[:])
|
||||||
|
|
||||||
return mapped
|
return mapped
|
||||||
}
|
}
|
||||||
|
|
||||||
// performDNS64 processes the current state of dctx assuming that it has already
|
|
||||||
// been tried to resolve, checks if it contains any acceptable response, and if
|
|
||||||
// it doesn't, performs DNS64 request and the following synthesis. It returns
|
|
||||||
// the [resultCodeError] if there was an error set to dctx.
|
|
||||||
func (s *Server) performDNS64(prx *proxy.Proxy, dctx *dnsContext) (rc resultCode) {
|
|
||||||
pctx := dctx.proxyCtx
|
|
||||||
req := pctx.Req
|
|
||||||
|
|
||||||
dns64Req := s.checkDNS64(req, pctx.Res)
|
|
||||||
if dns64Req == nil {
|
|
||||||
return resultCodeSuccess
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug("dnsforward: received an empty AAAA response, checking DNS64")
|
|
||||||
|
|
||||||
origReq := pctx.Req
|
|
||||||
origResp := pctx.Res
|
|
||||||
origUps := pctx.Upstream
|
|
||||||
|
|
||||||
pctx.Req = dns64Req
|
|
||||||
defer func() { pctx.Req = origReq }()
|
|
||||||
|
|
||||||
if dctx.err = prx.Resolve(pctx); dctx.err != nil {
|
|
||||||
return resultCodeError
|
|
||||||
}
|
|
||||||
|
|
||||||
dns64Resp := pctx.Res
|
|
||||||
pctx.Res = origResp
|
|
||||||
if dns64Resp != nil && s.synthDNS64(origReq, pctx.Res, dns64Resp) {
|
|
||||||
log.Debug("dnsforward: synthesized AAAA response for %q", origReq.Question[0].Name)
|
|
||||||
} else {
|
|
||||||
pctx.Upstream = origUps
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultCodeSuccess
|
|
||||||
}
|
|
||||||
|
|
||||||
// synthRR synthesizes a DNS64 resource record in compliance with RFC 6147. If
|
|
||||||
// rr is not an A record, it's returned as is. A records are modified to become
|
|
||||||
// a DNS64-synthesized AAAA records, and the TTL is set according to the
|
|
||||||
// original TTL of a record and soaTTL. It returns nil on invalid A records.
|
|
||||||
func (s *Server) synthRR(rr dns.RR, soaTTL uint32) (result dns.RR) {
|
|
||||||
aResp, ok := rr.(*dns.A)
|
|
||||||
if !ok {
|
|
||||||
return rr
|
|
||||||
}
|
|
||||||
|
|
||||||
addr, err := netutil.IPToAddr(aResp.A, netutil.AddrFamilyIPv4)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("dnsforward: bad A record: %s", err)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
aaaa := &dns.AAAA{
|
|
||||||
Hdr: dns.RR_Header{
|
|
||||||
Name: aResp.Hdr.Name,
|
|
||||||
Rrtype: dns.TypeAAAA,
|
|
||||||
Class: aResp.Hdr.Class,
|
|
||||||
Ttl: mathutil.Min(aResp.Hdr.Ttl, soaTTL),
|
|
||||||
},
|
|
||||||
AAAA: s.mapDNS64(addr),
|
|
||||||
}
|
|
||||||
|
|
||||||
return aaaa
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,6 +15,16 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// maxDNS64SynTTL is the maximum TTL for synthesized DNS64 responses with no SOA
|
||||||
|
// records in seconds.
|
||||||
|
//
|
||||||
|
// If the SOA RR was not delivered with the negative response to the AAAA query,
|
||||||
|
// then the DNS64 SHOULD use the TTL of the original A RR or 600 seconds,
|
||||||
|
// whichever is shorter.
|
||||||
|
//
|
||||||
|
// See https://datatracker.ietf.org/doc/html/rfc6147#section-5.1.7.
|
||||||
|
const maxDNS64SynTTL uint32 = 600
|
||||||
|
|
||||||
// newRR is a helper that creates a new dns.RR with the given name, qtype, ttl
|
// newRR is a helper that creates a new dns.RR with the given name, qtype, ttl
|
||||||
// and value. It fails the test if the qtype is not supported or the type of
|
// and value. It fails the test if the qtype is not supported or the type of
|
||||||
// value doesn't match the qtype.
|
// value doesn't match the qtype.
|
||||||
|
|
|
@ -80,10 +80,17 @@ type Server struct {
|
||||||
privateNets netutil.SubnetSet
|
privateNets netutil.SubnetSet
|
||||||
localResolvers *proxy.Proxy
|
localResolvers *proxy.Proxy
|
||||||
sysResolvers aghnet.SystemResolvers
|
sysResolvers aghnet.SystemResolvers
|
||||||
|
|
||||||
|
// recDetector is a cache for recursive requests. It is used to detect
|
||||||
|
// and prevent recursive requests only for private upstreams.
|
||||||
|
//
|
||||||
|
// See https://github.com/adguardTeam/adGuardHome/issues/3185#issuecomment-851048135.
|
||||||
recDetector *recursionDetector
|
recDetector *recursionDetector
|
||||||
|
|
||||||
// dns64Prefix is the set of NAT64 prefixes used for DNS64 handling.
|
// dns64Pref is the NAT64 prefix used for DNS64 response mapping. The major
|
||||||
dns64Prefs []netip.Prefix
|
// part of DNS64 happens inside the [proxy] package, but there still are
|
||||||
|
// some places where response mapping is needed (e.g. DHCP).
|
||||||
|
dns64Pref netip.Prefix
|
||||||
|
|
||||||
// anonymizer masks the client's IP addresses if needed.
|
// anonymizer masks the client's IP addresses if needed.
|
||||||
anonymizer *aghnet.IPMut
|
anonymizer *aghnet.IPMut
|
||||||
|
@ -246,8 +253,8 @@ func (s *Server) Resolve(host string) ([]net.IPAddr, error) {
|
||||||
|
|
||||||
// RDNSExchanger is a resolver for clients' addresses.
|
// RDNSExchanger is a resolver for clients' addresses.
|
||||||
type RDNSExchanger interface {
|
type RDNSExchanger interface {
|
||||||
// Exchange tries to resolve the ip in a suitable way, e.g. either as
|
// Exchange tries to resolve the ip in a suitable way, i.e. either as local
|
||||||
// local or as external.
|
// or as external.
|
||||||
Exchange(ip net.IP) (host string, err error)
|
Exchange(ip net.IP) (host string, err error)
|
||||||
|
|
||||||
// ResolvesPrivatePTR returns true if the RDNSExchanger is able to
|
// ResolvesPrivatePTR returns true if the RDNSExchanger is able to
|
||||||
|
@ -256,13 +263,13 @@ type RDNSExchanger interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// rDNSEmptyAnswerErr is returned by Exchange method when the answer
|
// ErrRDNSNoData is returned by [RDNSExchanger.Exchange] when the answer
|
||||||
// section of respond is empty.
|
// section of response is either NODATA or has no PTR records.
|
||||||
rDNSEmptyAnswerErr errors.Error = "the answer section is empty"
|
ErrRDNSNoData errors.Error = "no ptr data in response"
|
||||||
|
|
||||||
// rDNSNotPTRErr is returned by Exchange method when the response is not
|
// ErrRDNSFailed is returned by [RDNSExchanger.Exchange] if the received
|
||||||
// of PTR type.
|
// response is not a NOERROR or NXDOMAIN.
|
||||||
rDNSNotPTRErr errors.Error = "the response is not a ptr"
|
ErrRDNSFailed errors.Error = "failed to resolve ptr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// type check
|
// type check
|
||||||
|
@ -317,18 +324,25 @@ func (s *Server) Exchange(ip net.IP) (host string, err error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Distinguish between NODATA response and a failed request.
|
||||||
resp := ctx.Res
|
resp := ctx.Res
|
||||||
if len(resp.Answer) == 0 {
|
if resp.Rcode != dns.RcodeSuccess && resp.Rcode != dns.RcodeNameError {
|
||||||
return "", fmt.Errorf("lookup for %q: %w", arpa, rDNSEmptyAnswerErr)
|
return "", fmt.Errorf(
|
||||||
}
|
"received %s response: %w",
|
||||||
|
dns.RcodeToString[resp.Rcode],
|
||||||
ptr, ok := resp.Answer[0].(*dns.PTR)
|
ErrRDNSFailed,
|
||||||
if !ok {
|
)
|
||||||
return "", fmt.Errorf("type checking: %w", rDNSNotPTRErr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, ans := range resp.Answer {
|
||||||
|
ptr, ok := ans.(*dns.PTR)
|
||||||
|
if ok {
|
||||||
return strings.TrimSuffix(ptr.Ptr, "."), nil
|
return strings.TrimSuffix(ptr.Ptr, "."), nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", ErrRDNSNoData
|
||||||
|
}
|
||||||
|
|
||||||
// ResolvesPrivatePTR implements the RDNSExchanger interface for *Server.
|
// ResolvesPrivatePTR implements the RDNSExchanger interface for *Server.
|
||||||
func (s *Server) ResolvesPrivatePTR() (ok bool) {
|
func (s *Server) ResolvesPrivatePTR() (ok bool) {
|
||||||
|
@ -477,6 +491,8 @@ func (s *Server) Prepare(conf *ServerConfig) (err error) {
|
||||||
return fmt.Errorf("preparing proxy: %w", err)
|
return fmt.Errorf("preparing proxy: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.setupDNS64()
|
||||||
|
|
||||||
err = s.prepareInternalProxy()
|
err = s.prepareInternalProxy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("preparing internal proxy: %w", err)
|
return fmt.Errorf("preparing internal proxy: %w", err)
|
||||||
|
@ -493,18 +509,18 @@ func (s *Server) Prepare(conf *ServerConfig) (err error) {
|
||||||
|
|
||||||
s.registerHandlers()
|
s.registerHandlers()
|
||||||
|
|
||||||
err = s.setupDNS64()
|
// TODO(e.burkov): Remove once the local resolvers logic moved to dnsproxy.
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("preparing DNS64: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.dnsProxy = &proxy.Proxy{Config: proxyConfig}
|
|
||||||
|
|
||||||
err = s.setupResolvers(s.conf.LocalPTRResolvers)
|
err = s.setupResolvers(s.conf.LocalPTRResolvers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("setting up resolvers: %w", err)
|
return fmt.Errorf("setting up resolvers: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.conf.UsePrivateRDNS {
|
||||||
|
proxyConfig.PrivateRDNSUpstreamConfig = s.localResolvers.UpstreamConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
s.dnsProxy = &proxy.Proxy{Config: proxyConfig}
|
||||||
|
|
||||||
s.recDetector.clear()
|
s.recDetector.clear()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -89,9 +89,14 @@ func createTestServer(
|
||||||
s.serverLock.Lock()
|
s.serverLock.Lock()
|
||||||
defer s.serverLock.Unlock()
|
defer s.serverLock.Unlock()
|
||||||
|
|
||||||
|
// TODO(e.burkov): Try to move it higher.
|
||||||
if localUps != nil {
|
if localUps != nil {
|
||||||
s.localResolvers.UpstreamConfig.Upstreams = []upstream.Upstream{localUps}
|
ups := []upstream.Upstream{localUps}
|
||||||
|
s.localResolvers.UpstreamConfig.Upstreams = ups
|
||||||
s.conf.UsePrivateRDNS = true
|
s.conf.UsePrivateRDNS = true
|
||||||
|
s.dnsProxy.PrivateRDNSUpstreamConfig = &proxy.UpstreamConfig{
|
||||||
|
Upstreams: ups,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
@ -1216,6 +1221,9 @@ func TestServer_Exchange(t *testing.T) {
|
||||||
|
|
||||||
errUpstream := aghtest.NewErrorUpstream()
|
errUpstream := aghtest.NewErrorUpstream()
|
||||||
nonPtrUpstream := aghtest.NewBlockUpstream("some-host", true)
|
nonPtrUpstream := aghtest.NewBlockUpstream("some-host", true)
|
||||||
|
refusingUpstream := aghtest.NewUpstreamMock(func(req *dns.Msg) (resp *dns.Msg, err error) {
|
||||||
|
return new(dns.Msg).SetRcode(req, dns.RcodeRefused), nil
|
||||||
|
})
|
||||||
|
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
recDetector: newRecursionDetector(0, 1),
|
recDetector: newRecursionDetector(0, 1),
|
||||||
|
@ -1260,15 +1268,21 @@ func TestServer_Exchange(t *testing.T) {
|
||||||
}, {
|
}, {
|
||||||
name: "empty_answer_error",
|
name: "empty_answer_error",
|
||||||
want: "",
|
want: "",
|
||||||
wantErr: rDNSEmptyAnswerErr,
|
wantErr: ErrRDNSNoData,
|
||||||
locUpstream: locUpstream,
|
locUpstream: locUpstream,
|
||||||
req: net.IP{192, 168, 1, 2},
|
req: net.IP{192, 168, 1, 2},
|
||||||
}, {
|
}, {
|
||||||
name: "not_ptr_error",
|
name: "invalid_answer",
|
||||||
want: "",
|
want: "",
|
||||||
wantErr: rDNSNotPTRErr,
|
wantErr: ErrRDNSNoData,
|
||||||
locUpstream: nonPtrUpstream,
|
locUpstream: nonPtrUpstream,
|
||||||
req: localIP,
|
req: localIP,
|
||||||
|
}, {
|
||||||
|
name: "refused",
|
||||||
|
want: "",
|
||||||
|
wantErr: ErrRDNSFailed,
|
||||||
|
locUpstream: refusingUpstream,
|
||||||
|
req: localIP,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|
|
@ -22,9 +22,11 @@ func (s *Server) processQueryLogsAndStats(dctx *dnsContext) (rc resultCode) {
|
||||||
|
|
||||||
shouldLog := true
|
shouldLog := true
|
||||||
msg := pctx.Req
|
msg := pctx.Req
|
||||||
|
q := msg.Question[0]
|
||||||
|
host := strings.ToLower(strings.TrimSuffix(q.Name, "."))
|
||||||
|
|
||||||
// don't log ANY request if refuseAny is enabled
|
// don't log ANY request if refuseAny is enabled
|
||||||
if len(msg.Question) >= 1 && msg.Question[0].Qtype == dns.TypeANY && s.conf.RefuseAny {
|
if q.Qtype == dns.TypeANY && s.conf.RefuseAny {
|
||||||
shouldLog = false
|
shouldLog = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,11 +43,20 @@ func (s *Server) processQueryLogsAndStats(dctx *dnsContext) (rc resultCode) {
|
||||||
// Synchronize access to s.queryLog and s.stats so they won't be suddenly
|
// Synchronize access to s.queryLog and s.stats so they won't be suddenly
|
||||||
// uninitialized while in use. This can happen after proxy server has been
|
// uninitialized while in use. This can happen after proxy server has been
|
||||||
// stopped, but its workers haven't yet exited.
|
// stopped, but its workers haven't yet exited.
|
||||||
if shouldLog && s.queryLog != nil {
|
if shouldLog &&
|
||||||
|
s.queryLog != nil &&
|
||||||
|
s.queryLog.ShouldLog(host, q.Qtype, q.Qclass) {
|
||||||
s.logQuery(dctx, pctx, elapsed, ip)
|
s.logQuery(dctx, pctx, elapsed, ip)
|
||||||
|
} else {
|
||||||
|
log.Debug(
|
||||||
|
"dnsforward: request %s %s from %s ignored; not logging",
|
||||||
|
dns.Type(q.Qtype),
|
||||||
|
host,
|
||||||
|
ip,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.stats != nil {
|
if s.stats != nil && s.stats.ShouldCount(host, q.Qtype, q.Qclass) {
|
||||||
s.updateStats(dctx, elapsed, *dctx.result, ip)
|
s.updateStats(dctx, elapsed, *dctx.result, ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,34 +16,44 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// testQueryLog is a simple querylog.QueryLog implementation for tests.
|
// testQueryLog is a simple [querylog.QueryLog] implementation for tests.
|
||||||
type testQueryLog struct {
|
type testQueryLog struct {
|
||||||
// QueryLog is embedded here simply to make testQueryLog
|
// QueryLog is embedded here simply to make testQueryLog
|
||||||
// a querylog.QueryLog without actually implementing all methods.
|
// a [querylog.QueryLog] without actually implementing all methods.
|
||||||
querylog.QueryLog
|
querylog.QueryLog
|
||||||
|
|
||||||
lastParams *querylog.AddParams
|
lastParams *querylog.AddParams
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add implements the querylog.QueryLog interface for *testQueryLog.
|
// Add implements the [querylog.QueryLog] interface for *testQueryLog.
|
||||||
func (l *testQueryLog) Add(p *querylog.AddParams) {
|
func (l *testQueryLog) Add(p *querylog.AddParams) {
|
||||||
l.lastParams = p
|
l.lastParams = p
|
||||||
}
|
}
|
||||||
|
|
||||||
// testStats is a simple stats.Stats implementation for tests.
|
// ShouldLog implements the [querylog.QueryLog] interface for *testQueryLog.
|
||||||
|
func (l *testQueryLog) ShouldLog(string, uint16, uint16) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// testStats is a simple [stats.Interface] implementation for tests.
|
||||||
type testStats struct {
|
type testStats struct {
|
||||||
// Stats is embedded here simply to make testStats a stats.Stats without
|
// Stats is embedded here simply to make testStats a [stats.Interface]
|
||||||
// actually implementing all methods.
|
// without actually implementing all methods.
|
||||||
stats.Interface
|
stats.Interface
|
||||||
|
|
||||||
lastEntry stats.Entry
|
lastEntry stats.Entry
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update implements the stats.Stats interface for *testStats.
|
// Update implements the [stats.Interface] interface for *testStats.
|
||||||
func (l *testStats) Update(e stats.Entry) {
|
func (l *testStats) Update(e stats.Entry) {
|
||||||
l.lastEntry = e
|
l.lastEntry = e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShouldCount implements the [stats.Interface] interface for *testStats.
|
||||||
|
func (l *testStats) ShouldCount(string, uint16, uint16) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func TestProcessQueryLogsAndStats(t *testing.T) {
|
func TestProcessQueryLogsAndStats(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
@ -1283,7 +1283,7 @@ var blockedServices = []blockedService{{
|
||||||
}, {
|
}, {
|
||||||
ID: "leagueoflegends",
|
ID: "leagueoflegends",
|
||||||
Name: "League of Legends",
|
Name: "League of Legends",
|
||||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 30 30\" width=\"60px\" height=\"60px\"><path d=\"M 7 4 L 9 7.25 L 9 22.75 L 6.875 26 L 21.957031 26 L 25 22 L 14 22 L 14 4 L 7 4 z M 16 4.0507812 L 16 6.0585938 C 20.493 6.5575937 24 10.375 24 15 C 24 16.849 23.438516 18.569 22.478516 20 L 24.785156 20 C 25.556156 18.498 26 16.801 26 15 C 26 9.272 21.598 4.5577812 16 4.0507812 z M 6.8730469 7.6113281 C 5.0940469 9.5663281 4 12.155 4 15 C 4 17.837 5.0884219 20.418094 6.8574219 22.371094 L 7 22.154297 L 7 19.105469 C 6.365 17.872469 6 16.479 6 15 C 6 13.521 6.365 12.127531 7 10.894531 L 7 7.8164062 L 6.8730469 7.6113281 z\"/></svg>"),
|
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 30 30\"><path d=\"M 7 4 L 9 7.25 L 9 22.75 L 6.875 26 L 21.957031 26 L 25 22 L 14 22 L 14 4 L 7 4 z M 16 4.0507812 L 16 6.0585938 C 20.493 6.5575937 24 10.375 24 15 C 24 16.849 23.438516 18.569 22.478516 20 L 24.785156 20 C 25.556156 18.498 26 16.801 26 15 C 26 9.272 21.598 4.5577812 16 4.0507812 z M 6.8730469 7.6113281 C 5.0940469 9.5663281 4 12.155 4 15 C 4 17.837 5.0884219 20.418094 6.8574219 22.371094 L 7 22.154297 L 7 19.105469 C 6.365 17.872469 6 16.479 6 15 C 6 13.521 6.365 12.127531 7 10.894531 L 7 7.8164062 L 6.8730469 7.6113281 z\"/></svg>"),
|
||||||
Rules: []string{
|
Rules: []string{
|
||||||
"||leagueoflegends.co.kr^",
|
"||leagueoflegends.co.kr^",
|
||||||
"||leagueoflegends.com^",
|
"||leagueoflegends.com^",
|
||||||
|
@ -1307,9 +1307,7 @@ var blockedServices = []blockedService{{
|
||||||
Rules: []string{
|
Rules: []string{
|
||||||
"||aus.social^",
|
"||aus.social^",
|
||||||
"||awscommunity.social^",
|
"||awscommunity.social^",
|
||||||
"||cupoftea.social^",
|
|
||||||
"||cyberplace.social^",
|
"||cyberplace.social^",
|
||||||
"||defcon.social^",
|
|
||||||
"||det.social^",
|
"||det.social^",
|
||||||
"||fosstodon.org^",
|
"||fosstodon.org^",
|
||||||
"||glasgow.social^",
|
"||glasgow.social^",
|
||||||
|
@ -1335,7 +1333,6 @@ var blockedServices = []blockedService{{
|
||||||
"||mastodon.au^",
|
"||mastodon.au^",
|
||||||
"||mastodon.bida.im^",
|
"||mastodon.bida.im^",
|
||||||
"||mastodon.com.tr^",
|
"||mastodon.com.tr^",
|
||||||
"||mastodon.eus^",
|
|
||||||
"||mastodon.green^",
|
"||mastodon.green^",
|
||||||
"||mastodon.ie^",
|
"||mastodon.ie^",
|
||||||
"||mastodon.iriseden.eu^",
|
"||mastodon.iriseden.eu^",
|
||||||
|
@ -1343,13 +1340,15 @@ var blockedServices = []blockedService{{
|
||||||
"||mastodon.nu^",
|
"||mastodon.nu^",
|
||||||
"||mastodon.nz^",
|
"||mastodon.nz^",
|
||||||
"||mastodon.online^",
|
"||mastodon.online^",
|
||||||
|
"||mastodon.online^",
|
||||||
"||mastodon.scot^",
|
"||mastodon.scot^",
|
||||||
"||mastodon.sdf.org^",
|
"||mastodon.sdf.org^",
|
||||||
"||mastodon.social^",
|
"||mastodon.social^",
|
||||||
|
"||mastodon.social^",
|
||||||
"||mastodon.top^",
|
"||mastodon.top^",
|
||||||
"||mastodon.uno^",
|
"||mastodon.uno^",
|
||||||
"||mastodon.world^",
|
"||mastodon.world^",
|
||||||
"||mastodon.zaclys.com^",
|
"||mastodon.xyz^",
|
||||||
"||mastodonapp.uk^",
|
"||mastodonapp.uk^",
|
||||||
"||mastodonners.nl^",
|
"||mastodonners.nl^",
|
||||||
"||mastodont.cat^",
|
"||mastodont.cat^",
|
||||||
|
@ -1361,9 +1360,10 @@ var blockedServices = []blockedService{{
|
||||||
"||mindly.social^",
|
"||mindly.social^",
|
||||||
"||mstdn.ca^",
|
"||mstdn.ca^",
|
||||||
"||mstdn.jp^",
|
"||mstdn.jp^",
|
||||||
|
"||mstdn.party^",
|
||||||
"||mstdn.social^",
|
"||mstdn.social^",
|
||||||
"||muenchen.social^",
|
"||muenchen.social^",
|
||||||
"||muenster.im^",
|
"||nerdculture.de^",
|
||||||
"||newsie.social^",
|
"||newsie.social^",
|
||||||
"||noc.social^",
|
"||noc.social^",
|
||||||
"||norden.social^",
|
"||norden.social^",
|
||||||
|
|
|
@ -67,15 +67,18 @@ func (c *Client) closeUpstreams() (err error) {
|
||||||
|
|
||||||
type clientSource uint
|
type clientSource uint
|
||||||
|
|
||||||
// Client sources. The order determines the priority.
|
// Clients information sources. The order determines the priority.
|
||||||
const (
|
const (
|
||||||
ClientSourceWHOIS clientSource = iota
|
ClientSourceNone clientSource = iota
|
||||||
|
ClientSourceWHOIS
|
||||||
ClientSourceARP
|
ClientSourceARP
|
||||||
ClientSourceRDNS
|
ClientSourceRDNS
|
||||||
ClientSourceDHCP
|
ClientSourceDHCP
|
||||||
ClientSourceHostsFile
|
ClientSourceHostsFile
|
||||||
|
ClientSourcePersistent
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// type check
|
||||||
var _ fmt.Stringer = clientSource(0)
|
var _ fmt.Stringer = clientSource(0)
|
||||||
|
|
||||||
// String returns a human-readable name of cs.
|
// String returns a human-readable name of cs.
|
||||||
|
@ -96,6 +99,7 @@ func (cs clientSource) String() (s string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
var _ encoding.TextMarshaler = clientSource(0)
|
var _ encoding.TextMarshaler = clientSource(0)
|
||||||
|
|
||||||
// MarshalText implements encoding.TextMarshaler for the clientSource.
|
// MarshalText implements encoding.TextMarshaler for the clientSource.
|
||||||
|
@ -332,23 +336,24 @@ func (clients *clientsContainer) onDHCPLeaseChanged(flags int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// exists checks if client with this IP address already exists.
|
// clientSource checks if client with this IP address already exists and returns
|
||||||
func (clients *clientsContainer) exists(ip netip.Addr, source clientSource) (ok bool) {
|
// the source which updated it last. It returns [ClientSourceNone] if the
|
||||||
|
// client doesn't exist.
|
||||||
|
func (clients *clientsContainer) clientSource(ip netip.Addr) (src clientSource) {
|
||||||
clients.lock.Lock()
|
clients.lock.Lock()
|
||||||
defer clients.lock.Unlock()
|
defer clients.lock.Unlock()
|
||||||
|
|
||||||
_, ok = clients.findLocked(ip.String())
|
_, ok := clients.findLocked(ip.String())
|
||||||
if ok {
|
if ok {
|
||||||
return true
|
return ClientSourcePersistent
|
||||||
}
|
}
|
||||||
|
|
||||||
rc, ok := clients.ipToRC[ip]
|
rc, ok := clients.ipToRC[ip]
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return ClientSourceNone
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return false if the new source has higher priority.
|
return rc.Source
|
||||||
return source <= rc.Source
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func toQueryLogWHOIS(wi *RuntimeClientWHOISInfo) (cw *querylog.ClientWHOIS) {
|
func toQueryLogWHOIS(wi *RuntimeClientWHOISInfo) (cw *querylog.ClientWHOIS) {
|
||||||
|
|
|
@ -67,9 +67,9 @@ func TestClients(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(t, "client2", c.Name)
|
assert.Equal(t, "client2", c.Name)
|
||||||
|
|
||||||
assert.False(t, clients.exists(cliNoneIP, ClientSourceHostsFile))
|
assert.Equal(t, clients.clientSource(cliNoneIP), ClientSourceNone)
|
||||||
assert.True(t, clients.exists(cli1IP, ClientSourceHostsFile))
|
assert.Equal(t, clients.clientSource(cli1IP), ClientSourcePersistent)
|
||||||
assert.True(t, clients.exists(cli2IP, ClientSourceHostsFile))
|
assert.Equal(t, clients.clientSource(cli2IP), ClientSourcePersistent)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("add_fail_name", func(t *testing.T) {
|
t.Run("add_fail_name", func(t *testing.T) {
|
||||||
|
@ -127,8 +127,8 @@ func TestClients(t *testing.T) {
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.False(t, clients.exists(cliOldIP, ClientSourceHostsFile))
|
assert.Equal(t, clients.clientSource(cliOldIP), ClientSourceNone)
|
||||||
assert.True(t, clients.exists(cliNewIP, ClientSourceHostsFile))
|
assert.Equal(t, clients.clientSource(cliNewIP), ClientSourcePersistent)
|
||||||
|
|
||||||
err = clients.Update("client1", &Client{
|
err = clients.Update("client1", &Client{
|
||||||
IDs: []string{cliNew},
|
IDs: []string{cliNew},
|
||||||
|
@ -157,7 +157,7 @@ func TestClients(t *testing.T) {
|
||||||
ok := clients.Del("client1-renamed")
|
ok := clients.Del("client1-renamed")
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
assert.False(t, clients.exists(netip.MustParseAddr("1.1.1.2"), ClientSourceHostsFile))
|
assert.Equal(t, clients.clientSource(netip.MustParseAddr("1.1.1.2")), ClientSourceNone)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("del_fail", func(t *testing.T) {
|
t.Run("del_fail", func(t *testing.T) {
|
||||||
|
@ -176,18 +176,18 @@ func TestClients(t *testing.T) {
|
||||||
ok = clients.AddHost(ip, "host3", ClientSourceHostsFile)
|
ok = clients.AddHost(ip, "host3", ClientSourceHostsFile)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
|
|
||||||
assert.True(t, clients.exists(ip, ClientSourceHostsFile))
|
assert.Equal(t, clients.clientSource(ip), ClientSourceHostsFile)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("dhcp_replaces_arp", func(t *testing.T) {
|
t.Run("dhcp_replaces_arp", func(t *testing.T) {
|
||||||
ip := netip.MustParseAddr("1.2.3.4")
|
ip := netip.MustParseAddr("1.2.3.4")
|
||||||
ok := clients.AddHost(ip, "from_arp", ClientSourceARP)
|
ok := clients.AddHost(ip, "from_arp", ClientSourceARP)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.True(t, clients.exists(ip, ClientSourceARP))
|
assert.Equal(t, clients.clientSource(ip), ClientSourceARP)
|
||||||
|
|
||||||
ok = clients.AddHost(ip, "from_dhcp", ClientSourceDHCP)
|
ok = clients.AddHost(ip, "from_dhcp", ClientSourceDHCP)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.True(t, clients.exists(ip, ClientSourceDHCP))
|
assert.Equal(t, clients.clientSource(ip), ClientSourceDHCP)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("addhost_fail", func(t *testing.T) {
|
t.Run("addhost_fail", func(t *testing.T) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||||
|
@ -114,6 +115,8 @@ type configuration struct {
|
||||||
|
|
||||||
DNS dnsConfig `yaml:"dns"`
|
DNS dnsConfig `yaml:"dns"`
|
||||||
TLS tlsConfigSettings `yaml:"tls"`
|
TLS tlsConfigSettings `yaml:"tls"`
|
||||||
|
QueryLog queryLogConfig `yaml:"querylog"`
|
||||||
|
Stats statsConfig `yaml:"statistics"`
|
||||||
|
|
||||||
// Filters reflects the filters from [filtering.Config]. It's cloned to the
|
// Filters reflects the filters from [filtering.Config]. It's cloned to the
|
||||||
// config used in the filtering module at the startup. Afterwards it's
|
// config used in the filtering module at the startup. Afterwards it's
|
||||||
|
@ -147,20 +150,6 @@ type dnsConfig struct {
|
||||||
BindHosts []netip.Addr `yaml:"bind_hosts"`
|
BindHosts []netip.Addr `yaml:"bind_hosts"`
|
||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
|
|
||||||
// StatsInterval is the time interval for flushing statistics to the disk in
|
|
||||||
// days.
|
|
||||||
StatsInterval uint32 `yaml:"statistics_interval"`
|
|
||||||
|
|
||||||
// QueryLogEnabled defines if the query log is enabled.
|
|
||||||
QueryLogEnabled bool `yaml:"querylog_enabled"`
|
|
||||||
// QueryLogFileEnabled defines, if the query log is written to the file.
|
|
||||||
QueryLogFileEnabled bool `yaml:"querylog_file_enabled"`
|
|
||||||
// QueryLogInterval is the interval for query log's files rotation.
|
|
||||||
QueryLogInterval timeutil.Duration `yaml:"querylog_interval"`
|
|
||||||
// QueryLogMemSize is the number of entries kept in memory before they are
|
|
||||||
// flushed to disk.
|
|
||||||
QueryLogMemSize uint32 `yaml:"querylog_size_memory"`
|
|
||||||
|
|
||||||
// AnonymizeClientIP defines if clients' IP addresses should be anonymized
|
// AnonymizeClientIP defines if clients' IP addresses should be anonymized
|
||||||
// in query log and statistics.
|
// in query log and statistics.
|
||||||
AnonymizeClientIP bool `yaml:"anonymize_client_ip"`
|
AnonymizeClientIP bool `yaml:"anonymize_client_ip"`
|
||||||
|
@ -188,7 +177,7 @@ type dnsConfig struct {
|
||||||
UseDNS64 bool `yaml:"use_dns64"`
|
UseDNS64 bool `yaml:"use_dns64"`
|
||||||
|
|
||||||
// DNS64Prefixes is the list of NAT64 prefixes to be used for DNS64.
|
// DNS64Prefixes is the list of NAT64 prefixes to be used for DNS64.
|
||||||
DNS64Prefixes []string `yaml:"dns64_prefixes"`
|
DNS64Prefixes []netip.Prefix `yaml:"dns64_prefixes"`
|
||||||
|
|
||||||
// ServeHTTP3 defines if HTTP/3 is be allowed for incoming requests.
|
// ServeHTTP3 defines if HTTP/3 is be allowed for incoming requests.
|
||||||
//
|
//
|
||||||
|
@ -228,6 +217,37 @@ type tlsConfigSettings struct {
|
||||||
dnsforward.TLSConfig `yaml:",inline" json:",inline"`
|
dnsforward.TLSConfig `yaml:",inline" json:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type queryLogConfig struct {
|
||||||
|
// Enabled defines if the query log is enabled.
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
|
||||||
|
// FileEnabled defines, if the query log is written to the file.
|
||||||
|
FileEnabled bool `yaml:"file_enabled"`
|
||||||
|
|
||||||
|
// Interval is the interval for query log's files rotation.
|
||||||
|
Interval timeutil.Duration `yaml:"interval"`
|
||||||
|
|
||||||
|
// MemSize is the number of entries kept in memory before they are
|
||||||
|
// flushed to disk.
|
||||||
|
MemSize uint32 `yaml:"size_memory"`
|
||||||
|
|
||||||
|
// Ignored is the list of host names, which should not be written to
|
||||||
|
// log.
|
||||||
|
Ignored []string `yaml:"ignored"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type statsConfig struct {
|
||||||
|
// Enabled defines if the statistics are enabled.
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
|
||||||
|
// Interval is the time interval for flushing statistics to the disk in
|
||||||
|
// days.
|
||||||
|
Interval uint32 `yaml:"interval"`
|
||||||
|
|
||||||
|
// Ignored is the list of host names, which should not be counted.
|
||||||
|
Ignored []string `yaml:"ignored"`
|
||||||
|
}
|
||||||
|
|
||||||
// config is the global configuration structure.
|
// config is the global configuration structure.
|
||||||
//
|
//
|
||||||
// TODO(a.garipov, e.burkov): This global is awful and must be removed.
|
// TODO(a.garipov, e.burkov): This global is awful and must be removed.
|
||||||
|
@ -240,11 +260,6 @@ var config = &configuration{
|
||||||
DNS: dnsConfig{
|
DNS: dnsConfig{
|
||||||
BindHosts: []netip.Addr{netip.IPv4Unspecified()},
|
BindHosts: []netip.Addr{netip.IPv4Unspecified()},
|
||||||
Port: defaultPortDNS,
|
Port: defaultPortDNS,
|
||||||
StatsInterval: 1,
|
|
||||||
QueryLogEnabled: true,
|
|
||||||
QueryLogFileEnabled: true,
|
|
||||||
QueryLogInterval: timeutil.Duration{Duration: 90 * timeutil.Day},
|
|
||||||
QueryLogMemSize: 1000,
|
|
||||||
FilteringConfig: dnsforward.FilteringConfig{
|
FilteringConfig: dnsforward.FilteringConfig{
|
||||||
ProtectionEnabled: true, // whether or not use any of filtering features
|
ProtectionEnabled: true, // whether or not use any of filtering features
|
||||||
BlockingMode: dnsforward.BlockingModeDefault,
|
BlockingMode: dnsforward.BlockingModeDefault,
|
||||||
|
@ -282,6 +297,18 @@ var config = &configuration{
|
||||||
PortDNSOverTLS: defaultPortTLS, // needs to be passed through to dnsproxy
|
PortDNSOverTLS: defaultPortTLS, // needs to be passed through to dnsproxy
|
||||||
PortDNSOverQUIC: defaultPortQUIC,
|
PortDNSOverQUIC: defaultPortQUIC,
|
||||||
},
|
},
|
||||||
|
QueryLog: queryLogConfig{
|
||||||
|
Enabled: true,
|
||||||
|
FileEnabled: true,
|
||||||
|
Interval: timeutil.Duration{Duration: 90 * timeutil.Day},
|
||||||
|
MemSize: 1000,
|
||||||
|
Ignored: []string{},
|
||||||
|
},
|
||||||
|
Stats: statsConfig{
|
||||||
|
Enabled: true,
|
||||||
|
Interval: 1,
|
||||||
|
Ignored: []string{},
|
||||||
|
},
|
||||||
// NOTE: Keep these parameters in sync with the one put into
|
// NOTE: Keep these parameters in sync with the one put into
|
||||||
// client/src/helpers/filters/filters.js by scripts/vetted-filters.
|
// client/src/helpers/filters/filters.js by scripts/vetted-filters.
|
||||||
//
|
//
|
||||||
|
@ -458,19 +485,24 @@ func (c *configuration) write() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if Context.stats != nil {
|
if Context.stats != nil {
|
||||||
sdc := stats.DiskConfig{}
|
statsConf := stats.Config{}
|
||||||
Context.stats.WriteDiskConfig(&sdc)
|
Context.stats.WriteDiskConfig(&statsConf)
|
||||||
config.DNS.StatsInterval = sdc.Interval
|
config.Stats.Interval = statsConf.LimitDays
|
||||||
|
config.Stats.Enabled = statsConf.Enabled
|
||||||
|
config.Stats.Ignored = statsConf.Ignored.Values()
|
||||||
|
sort.Strings(config.Stats.Ignored)
|
||||||
}
|
}
|
||||||
|
|
||||||
if Context.queryLog != nil {
|
if Context.queryLog != nil {
|
||||||
dc := querylog.Config{}
|
dc := querylog.Config{}
|
||||||
Context.queryLog.WriteDiskConfig(&dc)
|
Context.queryLog.WriteDiskConfig(&dc)
|
||||||
config.DNS.QueryLogEnabled = dc.Enabled
|
|
||||||
config.DNS.QueryLogFileEnabled = dc.FileEnabled
|
|
||||||
config.DNS.QueryLogInterval = timeutil.Duration{Duration: dc.RotationIvl}
|
|
||||||
config.DNS.QueryLogMemSize = dc.MemSize
|
|
||||||
config.DNS.AnonymizeClientIP = dc.AnonymizeClientIP
|
config.DNS.AnonymizeClientIP = dc.AnonymizeClientIP
|
||||||
|
config.QueryLog.Enabled = dc.Enabled
|
||||||
|
config.QueryLog.FileEnabled = dc.FileEnabled
|
||||||
|
config.QueryLog.Interval = timeutil.Duration{Duration: dc.RotationIvl}
|
||||||
|
config.QueryLog.MemSize = dc.MemSize
|
||||||
|
config.QueryLog.Ignored = dc.Ignored.Values()
|
||||||
|
sort.Strings(config.QueryLog.Ignored)
|
||||||
}
|
}
|
||||||
|
|
||||||
if Context.filters != nil {
|
if Context.filters != nil {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/lucas-clemente/quic-go/http3"
|
"github.com/quic-go/quic-go/http3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getAddrsResponse is the response for /install/get_addresses endpoint.
|
// getAddrsResponse is the response for /install/get_addresses endpoint.
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||||
|
@ -20,6 +21,7 @@ import (
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
"github.com/AdguardTeam/golibs/stringutil"
|
||||||
"github.com/ameshkov/dnscrypt/v2"
|
"github.com/ameshkov/dnscrypt/v2"
|
||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
@ -51,10 +53,18 @@ func initDNS() (err error) {
|
||||||
|
|
||||||
statsConf := stats.Config{
|
statsConf := stats.Config{
|
||||||
Filename: filepath.Join(baseDir, "stats.db"),
|
Filename: filepath.Join(baseDir, "stats.db"),
|
||||||
LimitDays: config.DNS.StatsInterval,
|
LimitDays: config.Stats.Interval,
|
||||||
ConfigModified: onConfigModified,
|
ConfigModified: onConfigModified,
|
||||||
HTTPRegister: httpRegister,
|
HTTPRegister: httpRegister,
|
||||||
|
Enabled: config.Stats.Enabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set, err := nonDupEmptyHostNames(config.Stats.Ignored)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("statistics: ignored list: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
statsConf.Ignored = set
|
||||||
Context.stats, err = stats.New(statsConf)
|
Context.stats, err = stats.New(statsConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("init stats: %w", err)
|
return fmt.Errorf("init stats: %w", err)
|
||||||
|
@ -66,12 +76,19 @@ func initDNS() (err error) {
|
||||||
HTTPRegister: httpRegister,
|
HTTPRegister: httpRegister,
|
||||||
FindClient: Context.clients.findMultiple,
|
FindClient: Context.clients.findMultiple,
|
||||||
BaseDir: baseDir,
|
BaseDir: baseDir,
|
||||||
RotationIvl: config.DNS.QueryLogInterval.Duration,
|
|
||||||
MemSize: config.DNS.QueryLogMemSize,
|
|
||||||
Enabled: config.DNS.QueryLogEnabled,
|
|
||||||
FileEnabled: config.DNS.QueryLogFileEnabled,
|
|
||||||
AnonymizeClientIP: config.DNS.AnonymizeClientIP,
|
AnonymizeClientIP: config.DNS.AnonymizeClientIP,
|
||||||
|
RotationIvl: config.QueryLog.Interval.Duration,
|
||||||
|
MemSize: config.QueryLog.MemSize,
|
||||||
|
Enabled: config.QueryLog.Enabled,
|
||||||
|
FileEnabled: config.QueryLog.FileEnabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set, err = nonDupEmptyHostNames(config.QueryLog.Ignored)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("querylog: ignored list: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.Ignored = set
|
||||||
Context.queryLog = querylog.New(conf)
|
Context.queryLog = querylog.New(conf)
|
||||||
|
|
||||||
Context.filters, err = filtering.New(config.DNS.DnsfilterConf, nil)
|
Context.filters, err = filtering.New(config.DNS.DnsfilterConf, nil)
|
||||||
|
@ -515,3 +532,27 @@ func closeDNSServer() {
|
||||||
|
|
||||||
log.Debug("all dns modules are closed")
|
log.Debug("all dns modules are closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nonDupEmptyHostNames returns nil and error, if list has duplicate or empty
|
||||||
|
// host name. Otherwise returns a set, which contains lowercase host names
|
||||||
|
// without dot at the end, and nil error.
|
||||||
|
func nonDupEmptyHostNames(list []string) (set *stringutil.Set, err error) {
|
||||||
|
set = stringutil.NewSet()
|
||||||
|
|
||||||
|
for _, v := range list {
|
||||||
|
host := strings.ToLower(strings.TrimSuffix(v, "."))
|
||||||
|
// TODO(a.garipov): Think about ignoring empty (".") names in
|
||||||
|
// the future.
|
||||||
|
if host == "" {
|
||||||
|
return nil, errors.Error("host name is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if set.Has(host) {
|
||||||
|
return nil, fmt.Errorf("duplicate host name %q", host)
|
||||||
|
}
|
||||||
|
|
||||||
|
set.Add(host)
|
||||||
|
}
|
||||||
|
|
||||||
|
return set, nil
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
||||||
"github.com/AdguardTeam/golibs/cache"
|
"github.com/AdguardTeam/golibs/cache"
|
||||||
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,10 +17,6 @@ type RDNS struct {
|
||||||
exchanger dnsforward.RDNSExchanger
|
exchanger dnsforward.RDNSExchanger
|
||||||
clients *clientsContainer
|
clients *clientsContainer
|
||||||
|
|
||||||
// usePrivate is used to store the state of current private RDNS resolving
|
|
||||||
// settings and to react to it's changes.
|
|
||||||
usePrivate uint32
|
|
||||||
|
|
||||||
// ipCh used to pass client's IP to rDNS workerLoop.
|
// ipCh used to pass client's IP to rDNS workerLoop.
|
||||||
ipCh chan netip.Addr
|
ipCh chan netip.Addr
|
||||||
|
|
||||||
|
@ -28,13 +25,21 @@ type RDNS struct {
|
||||||
// address will be resolved once again. If the address couldn't be
|
// address will be resolved once again. If the address couldn't be
|
||||||
// resolved, cache prevents further attempts to resolve it for some time.
|
// resolved, cache prevents further attempts to resolve it for some time.
|
||||||
ipCache cache.Cache
|
ipCache cache.Cache
|
||||||
|
|
||||||
|
// usePrivate stores the state of current private reverse-DNS resolving
|
||||||
|
// settings.
|
||||||
|
usePrivate atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default rDNS values.
|
// Default AdGuard Home reverse DNS values.
|
||||||
const (
|
const (
|
||||||
defaultRDNSCacheSize = 10000
|
revDNSCacheSize = 10000
|
||||||
defaultRDNSCacheTTL = 1 * 60 * 60
|
|
||||||
defaultRDNSIPChSize = 256
|
// TODO(e.burkov): Make these values configurable.
|
||||||
|
revDNSCacheTTL = 24 * 60 * 60
|
||||||
|
revDNSFailureCacheTTL = 1 * 60 * 60
|
||||||
|
|
||||||
|
revDNSQueueSize = 256
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRDNS creates and returns initialized RDNS.
|
// NewRDNS creates and returns initialized RDNS.
|
||||||
|
@ -48,14 +53,13 @@ func NewRDNS(
|
||||||
clients: clients,
|
clients: clients,
|
||||||
ipCache: cache.New(cache.Config{
|
ipCache: cache.New(cache.Config{
|
||||||
EnableLRU: true,
|
EnableLRU: true,
|
||||||
MaxCount: defaultRDNSCacheSize,
|
MaxCount: revDNSCacheSize,
|
||||||
}),
|
}),
|
||||||
ipCh: make(chan netip.Addr, defaultRDNSIPChSize),
|
ipCh: make(chan netip.Addr, revDNSQueueSize),
|
||||||
}
|
|
||||||
if usePrivate {
|
|
||||||
rDNS.usePrivate = 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rDNS.usePrivate.Store(usePrivate)
|
||||||
|
|
||||||
go rDNS.workerLoop()
|
go rDNS.workerLoop()
|
||||||
|
|
||||||
return rDNS
|
return rDNS
|
||||||
|
@ -68,12 +72,8 @@ func NewRDNS(
|
||||||
// approach since only unresolved locally-served addresses should be removed.
|
// approach since only unresolved locally-served addresses should be removed.
|
||||||
// Implement when improving the cache.
|
// Implement when improving the cache.
|
||||||
func (r *RDNS) ensurePrivateCache() {
|
func (r *RDNS) ensurePrivateCache() {
|
||||||
var usePrivate uint32
|
usePrivate := r.exchanger.ResolvesPrivatePTR()
|
||||||
if r.exchanger.ResolvesPrivatePTR() {
|
if r.usePrivate.CompareAndSwap(!usePrivate, usePrivate) {
|
||||||
usePrivate = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if atomic.CompareAndSwapUint32(&r.usePrivate, 1-usePrivate, usePrivate) {
|
|
||||||
r.ipCache.Clear()
|
r.ipCache.Clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,25 +84,28 @@ func (r *RDNS) isCached(ip netip.Addr) (ok bool) {
|
||||||
ipBytes := ip.AsSlice()
|
ipBytes := ip.AsSlice()
|
||||||
now := uint64(time.Now().Unix())
|
now := uint64(time.Now().Unix())
|
||||||
if expire := r.ipCache.Get(ipBytes); len(expire) != 0 {
|
if expire := r.ipCache.Get(ipBytes); len(expire) != 0 {
|
||||||
if binary.BigEndian.Uint64(expire) > now {
|
return binary.BigEndian.Uint64(expire) > now
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// The cache entry either expired or doesn't exist.
|
|
||||||
ttl := make([]byte, 8)
|
|
||||||
binary.BigEndian.PutUint64(ttl, now+defaultRDNSCacheTTL)
|
|
||||||
r.ipCache.Set(ipBytes, ttl)
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cache caches the ip address for ttl seconds.
|
||||||
|
func (r *RDNS) cache(ip netip.Addr, ttl uint64) {
|
||||||
|
ipData := ip.AsSlice()
|
||||||
|
|
||||||
|
ttlData := [8]byte{}
|
||||||
|
binary.BigEndian.PutUint64(ttlData[:], uint64(time.Now().Unix())+ttl)
|
||||||
|
|
||||||
|
r.ipCache.Set(ipData, ttlData[:])
|
||||||
|
}
|
||||||
|
|
||||||
// Begin adds the ip to the resolving queue if it is not cached or already
|
// Begin adds the ip to the resolving queue if it is not cached or already
|
||||||
// resolved.
|
// resolved.
|
||||||
func (r *RDNS) Begin(ip netip.Addr) {
|
func (r *RDNS) Begin(ip netip.Addr) {
|
||||||
r.ensurePrivateCache()
|
r.ensurePrivateCache()
|
||||||
|
|
||||||
if r.isCached(ip) || r.clients.exists(ip, ClientSourceRDNS) {
|
if r.isCached(ip) || r.clients.clientSource(ip) > ClientSourceRDNS {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,15 +123,21 @@ func (r *RDNS) workerLoop() {
|
||||||
defer log.OnPanic("rdns")
|
defer log.OnPanic("rdns")
|
||||||
|
|
||||||
for ip := range r.ipCh {
|
for ip := range r.ipCh {
|
||||||
|
ttl := uint64(revDNSCacheTTL)
|
||||||
|
|
||||||
host, err := r.exchanger.Exchange(ip.AsSlice())
|
host, err := r.exchanger.Exchange(ip.AsSlice())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("rdns: resolving %q: %s", ip, err)
|
log.Debug("rdns: resolving %q: %s", ip, err)
|
||||||
|
if errors.Is(err, dnsforward.ErrRDNSFailed) {
|
||||||
continue
|
// Cache failure for a less time.
|
||||||
} else if host == "" {
|
ttl = revDNSFailureCacheTTL
|
||||||
continue
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.cache(ip, ttl)
|
||||||
|
|
||||||
|
if host != "" {
|
||||||
_ = r.clients.AddHost(ip, host, ClientSourceRDNS)
|
_ = r.clients.AddHost(ip, host, ClientSourceRDNS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ func TestRDNS_Begin(t *testing.T) {
|
||||||
|
|
||||||
ipCache := cache.New(cache.Config{
|
ipCache := cache.New(cache.Config{
|
||||||
EnableLRU: true,
|
EnableLRU: true,
|
||||||
MaxCount: defaultRDNSCacheSize,
|
MaxCount: revDNSCacheSize,
|
||||||
})
|
})
|
||||||
ttl := make([]byte, binary.Size(uint64(0)))
|
ttl := make([]byte, binary.Size(uint64(0)))
|
||||||
binary.BigEndian.PutUint64(ttl, uint64(time.Now().Add(100*time.Hour).Unix()))
|
binary.BigEndian.PutUint64(ttl, uint64(time.Now().Add(100*time.Hour).Unix()))
|
||||||
|
@ -153,7 +153,7 @@ func TestRDNS_ensurePrivateCache(t *testing.T) {
|
||||||
|
|
||||||
ipCache := cache.New(cache.Config{
|
ipCache := cache.New(cache.Config{
|
||||||
EnableLRU: true,
|
EnableLRU: true,
|
||||||
MaxCount: defaultRDNSCacheSize,
|
MaxCount: revDNSCacheSize,
|
||||||
})
|
})
|
||||||
|
|
||||||
ex := &rDNSExchanger{
|
ex := &rDNSExchanger{
|
||||||
|
@ -204,21 +204,25 @@ func TestRDNS_WorkerLoop(t *testing.T) {
|
||||||
cliIP netip.Addr
|
cliIP netip.Addr
|
||||||
wantLog string
|
wantLog string
|
||||||
name string
|
name string
|
||||||
|
wantClientSource clientSource
|
||||||
}{{
|
}{{
|
||||||
ups: locUpstream,
|
ups: locUpstream,
|
||||||
cliIP: localIP,
|
cliIP: localIP,
|
||||||
wantLog: "",
|
wantLog: "",
|
||||||
name: "all_good",
|
name: "all_good",
|
||||||
|
wantClientSource: ClientSourceRDNS,
|
||||||
}, {
|
}, {
|
||||||
ups: errUpstream,
|
ups: errUpstream,
|
||||||
cliIP: netip.MustParseAddr("192.168.1.2"),
|
cliIP: netip.MustParseAddr("192.168.1.2"),
|
||||||
wantLog: `rdns: resolving "192.168.1.2": test upstream error`,
|
wantLog: `rdns: resolving "192.168.1.2": test upstream error`,
|
||||||
name: "resolve_error",
|
name: "resolve_error",
|
||||||
|
wantClientSource: ClientSourceNone,
|
||||||
}, {
|
}, {
|
||||||
ups: locUpstream,
|
ups: locUpstream,
|
||||||
cliIP: netip.MustParseAddr("2a00:1450:400c:c06::93"),
|
cliIP: netip.MustParseAddr("2a00:1450:400c:c06::93"),
|
||||||
wantLog: "",
|
wantLog: "",
|
||||||
name: "ipv6_good",
|
name: "ipv6_good",
|
||||||
|
wantClientSource: ClientSourceRDNS,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
@ -237,6 +241,10 @@ func TestRDNS_WorkerLoop(t *testing.T) {
|
||||||
},
|
},
|
||||||
clients: cc,
|
clients: cc,
|
||||||
ipCh: ch,
|
ipCh: ch,
|
||||||
|
ipCache: cache.New(cache.Config{
|
||||||
|
EnableLRU: true,
|
||||||
|
MaxCount: revDNSCacheSize,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
@ -253,11 +261,9 @@ func TestRDNS_WorkerLoop(t *testing.T) {
|
||||||
|
|
||||||
if tc.wantLog != "" {
|
if tc.wantLog != "" {
|
||||||
assert.Contains(t, w.String(), tc.wantLog)
|
assert.Contains(t, w.String(), tc.wantLog)
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.True(t, cc.exists(tc.cliIP, ClientSourceRDNS))
|
assert.Equal(t, tc.wantClientSource, cc.clientSource(tc.cliIP))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// currentSchemaVersion is the current schema version.
|
// currentSchemaVersion is the current schema version.
|
||||||
const currentSchemaVersion = 14
|
const currentSchemaVersion = 16
|
||||||
|
|
||||||
// These aliases are provided for convenience.
|
// These aliases are provided for convenience.
|
||||||
type (
|
type (
|
||||||
|
@ -87,6 +87,8 @@ func upgradeConfigSchema(oldVersion int, diskConf yobj) (err error) {
|
||||||
upgradeSchema11to12,
|
upgradeSchema11to12,
|
||||||
upgradeSchema12to13,
|
upgradeSchema12to13,
|
||||||
upgradeSchema13to14,
|
upgradeSchema13to14,
|
||||||
|
upgradeSchema14to15,
|
||||||
|
upgradeSchema15to16,
|
||||||
}
|
}
|
||||||
|
|
||||||
n := 0
|
n := 0
|
||||||
|
@ -802,6 +804,107 @@ func upgradeSchema13to14(diskConf yobj) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// upgradeSchema14to15 performs the following changes:
|
||||||
|
//
|
||||||
|
// # BEFORE:
|
||||||
|
// 'dns':
|
||||||
|
// 'querylog_enabled': true
|
||||||
|
// 'querylog_file_enabled': true
|
||||||
|
// 'querylog_interval': '2160h'
|
||||||
|
// 'querylog_size_memory': 1000
|
||||||
|
//
|
||||||
|
// # AFTER:
|
||||||
|
// 'querylog':
|
||||||
|
// 'enabled': true
|
||||||
|
// 'file_enabled': true
|
||||||
|
// 'interval': '2160h'
|
||||||
|
// 'size_memory': 1000
|
||||||
|
// 'ignored': []
|
||||||
|
func upgradeSchema14to15(diskConf yobj) (err error) {
|
||||||
|
log.Printf("Upgrade yaml: 14 to 15")
|
||||||
|
diskConf["schema_version"] = 15
|
||||||
|
|
||||||
|
dnsVal, ok := diskConf["dns"]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dns, ok := dnsVal.(yobj)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type of dns: %T", dnsVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
type temp struct {
|
||||||
|
from string
|
||||||
|
to string
|
||||||
|
val any
|
||||||
|
}
|
||||||
|
replaces := []temp{
|
||||||
|
{from: "querylog_enabled", to: "enabled", val: true},
|
||||||
|
{from: "querylog_file_enabled", to: "file_enabled", val: true},
|
||||||
|
{from: "querylog_interval", to: "interval", val: "2160h"},
|
||||||
|
{from: "querylog_size_memory", to: "size_memory", val: 1000},
|
||||||
|
}
|
||||||
|
qlog := map[string]any{
|
||||||
|
"ignored": []any{},
|
||||||
|
}
|
||||||
|
for _, r := range replaces {
|
||||||
|
v, has := dns[r.from]
|
||||||
|
if !has {
|
||||||
|
v = r.val
|
||||||
|
}
|
||||||
|
delete(dns, r.from)
|
||||||
|
qlog[r.to] = v
|
||||||
|
}
|
||||||
|
diskConf["querylog"] = qlog
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// upgradeSchema15to16 performs the following changes:
|
||||||
|
//
|
||||||
|
// # BEFORE:
|
||||||
|
// 'dns':
|
||||||
|
// 'statistics_interval': 1
|
||||||
|
//
|
||||||
|
// # AFTER:
|
||||||
|
// 'statistics':
|
||||||
|
// 'enabled': true
|
||||||
|
// 'interval': 1
|
||||||
|
// 'ignored': []
|
||||||
|
func upgradeSchema15to16(diskConf yobj) (err error) {
|
||||||
|
log.Printf("Upgrade yaml: 15 to 16")
|
||||||
|
diskConf["schema_version"] = 16
|
||||||
|
|
||||||
|
dnsVal, ok := diskConf["dns"]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dns, ok := dnsVal.(yobj)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type of dns: %T", dnsVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
stats := map[string]any{
|
||||||
|
"enabled": true,
|
||||||
|
"interval": 1,
|
||||||
|
"ignored": []any{},
|
||||||
|
}
|
||||||
|
|
||||||
|
k := "statistics_interval"
|
||||||
|
v, has := dns[k]
|
||||||
|
if has {
|
||||||
|
stats["enabled"] = v != 0
|
||||||
|
stats["interval"] = v
|
||||||
|
}
|
||||||
|
delete(dns, k)
|
||||||
|
|
||||||
|
diskConf["statistics"] = stats
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(a.garipov): Replace with log.Output when we port it to our logging
|
// TODO(a.garipov): Replace with log.Output when we port it to our logging
|
||||||
// package.
|
// package.
|
||||||
func funcName() string {
|
func funcName() string {
|
||||||
|
|
|
@ -640,3 +640,110 @@ func TestUpgradeSchema13to14(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpgradeSchema14to15(t *testing.T) {
|
||||||
|
const newSchemaVer = 15
|
||||||
|
|
||||||
|
defaultWantObj := yobj{
|
||||||
|
"querylog": map[string]any{
|
||||||
|
"enabled": true,
|
||||||
|
"file_enabled": true,
|
||||||
|
"interval": "2160h",
|
||||||
|
"size_memory": 1000,
|
||||||
|
"ignored": []any{},
|
||||||
|
},
|
||||||
|
"dns": map[string]any{},
|
||||||
|
"schema_version": newSchemaVer,
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
in yobj
|
||||||
|
want yobj
|
||||||
|
name string
|
||||||
|
}{{
|
||||||
|
in: yobj{
|
||||||
|
"dns": map[string]any{
|
||||||
|
"querylog_enabled": true,
|
||||||
|
"querylog_file_enabled": true,
|
||||||
|
"querylog_interval": "2160h",
|
||||||
|
"querylog_size_memory": 1000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: defaultWantObj,
|
||||||
|
name: "basic",
|
||||||
|
}, {
|
||||||
|
in: yobj{
|
||||||
|
"dns": map[string]any{},
|
||||||
|
},
|
||||||
|
want: defaultWantObj,
|
||||||
|
name: "default_values",
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
err := upgradeSchema14to15(tc.in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.want, tc.in)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpgradeSchema15to16(t *testing.T) {
|
||||||
|
const newSchemaVer = 16
|
||||||
|
|
||||||
|
defaultWantObj := yobj{
|
||||||
|
"statistics": map[string]any{
|
||||||
|
"enabled": true,
|
||||||
|
"interval": 1,
|
||||||
|
"ignored": []any{},
|
||||||
|
},
|
||||||
|
"dns": map[string]any{},
|
||||||
|
"schema_version": newSchemaVer,
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
in yobj
|
||||||
|
want yobj
|
||||||
|
name string
|
||||||
|
}{{
|
||||||
|
in: yobj{
|
||||||
|
"dns": map[string]any{
|
||||||
|
"statistics_interval": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: defaultWantObj,
|
||||||
|
name: "basic",
|
||||||
|
}, {
|
||||||
|
in: yobj{
|
||||||
|
"dns": map[string]any{},
|
||||||
|
},
|
||||||
|
want: defaultWantObj,
|
||||||
|
name: "default_values",
|
||||||
|
}, {
|
||||||
|
in: yobj{
|
||||||
|
"dns": map[string]any{
|
||||||
|
"statistics_interval": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: yobj{
|
||||||
|
"statistics": map[string]any{
|
||||||
|
"enabled": false,
|
||||||
|
"interval": 0,
|
||||||
|
"ignored": []any{},
|
||||||
|
},
|
||||||
|
"dns": map[string]any{},
|
||||||
|
"schema_version": newSchemaVer,
|
||||||
|
},
|
||||||
|
name: "stats_disabled",
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
err := upgradeSchema15to16(tc.in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.want, tc.in)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,8 +15,8 @@ import (
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
"github.com/NYTimes/gziphandler"
|
"github.com/NYTimes/gziphandler"
|
||||||
"github.com/lucas-clemente/quic-go"
|
"github.com/quic-go/quic-go"
|
||||||
"github.com/lucas-clemente/quic-go/http3"
|
"github.com/quic-go/quic-go/http3"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
"golang.org/x/net/http2/h2c"
|
"golang.org/x/net/http2/h2c"
|
||||||
)
|
)
|
||||||
|
|
|
@ -44,6 +44,9 @@ func (l *queryLog) initWeb() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *queryLog) handleQueryLog(w http.ResponseWriter, r *http.Request) {
|
func (l *queryLog) handleQueryLog(w http.ResponseWriter, r *http.Request) {
|
||||||
|
l.lock.Lock()
|
||||||
|
defer l.lock.Unlock()
|
||||||
|
|
||||||
params, err := l.parseSearchParams(r)
|
params, err := l.parseSearchParams(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
aghhttp.Error(r, w, http.StatusBadRequest, "failed to parse params: %s", err)
|
aghhttp.Error(r, w, http.StatusBadRequest, "failed to parse params: %s", err)
|
||||||
|
|
|
@ -247,3 +247,13 @@ func (l *queryLog) Add(params *AddParams) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShouldLog returns true if request for the host should be logged.
|
||||||
|
func (l *queryLog) ShouldLog(host string, _, _ uint16) bool {
|
||||||
|
return !l.isIgnored(host)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isIgnored returns true if the host is in the Ignored list.
|
||||||
|
func (l *queryLog) isIgnored(host string) bool {
|
||||||
|
return l.conf.Ignored.Has(host)
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||||
"github.com/AdguardTeam/dnsproxy/proxyutil"
|
"github.com/AdguardTeam/dnsproxy/proxyutil"
|
||||||
|
"github.com/AdguardTeam/golibs/stringutil"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/AdguardTeam/golibs/timeutil"
|
"github.com/AdguardTeam/golibs/timeutil"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
@ -249,6 +250,48 @@ func TestQueryLogFileDisabled(t *testing.T) {
|
||||||
assert.Equal(t, "example2.org", ll[1].QHost)
|
assert.Equal(t, "example2.org", ll[1].QHost)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestQueryLogShouldLog(t *testing.T) {
|
||||||
|
const (
|
||||||
|
ignored1 = "ignor.ed"
|
||||||
|
ignored2 = "ignored.to"
|
||||||
|
)
|
||||||
|
set := stringutil.NewSet(ignored1, ignored2)
|
||||||
|
|
||||||
|
l := newQueryLog(Config{
|
||||||
|
Enabled: true,
|
||||||
|
RotationIvl: timeutil.Day,
|
||||||
|
MemSize: 100,
|
||||||
|
BaseDir: t.TempDir(),
|
||||||
|
Ignored: set,
|
||||||
|
})
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
host string
|
||||||
|
wantLog bool
|
||||||
|
}{{
|
||||||
|
name: "log",
|
||||||
|
host: "example.com",
|
||||||
|
wantLog: true,
|
||||||
|
}, {
|
||||||
|
name: "no_log_ignored_1",
|
||||||
|
host: ignored1,
|
||||||
|
wantLog: false,
|
||||||
|
}, {
|
||||||
|
name: "no_log_ignored_2",
|
||||||
|
host: ignored2,
|
||||||
|
wantLog: false,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
res := l.ShouldLog(tc.host, dns.TypeA, dns.ClassINET)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.wantLog, res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func addEntry(l *queryLog, host string, answerStr, client net.IP) {
|
func addEntry(l *queryLog, host string, answerStr, client net.IP) {
|
||||||
q := dns.Msg{
|
q := dns.Msg{
|
||||||
Question: []dns.Question{{
|
Question: []dns.Question{{
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
"github.com/AdguardTeam/golibs/stringutil"
|
||||||
"github.com/AdguardTeam/golibs/timeutil"
|
"github.com/AdguardTeam/golibs/timeutil"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
@ -26,6 +27,9 @@ type QueryLog interface {
|
||||||
|
|
||||||
// WriteDiskConfig - write configuration
|
// WriteDiskConfig - write configuration
|
||||||
WriteDiskConfig(c *Config)
|
WriteDiskConfig(c *Config)
|
||||||
|
|
||||||
|
// ShouldLog returns true if request for the host should be logged.
|
||||||
|
ShouldLog(host string, qType, qClass uint16) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config is the query log configuration structure.
|
// Config is the query log configuration structure.
|
||||||
|
@ -71,6 +75,10 @@ type Config struct {
|
||||||
// AnonymizeClientIP tells if the query log should anonymize clients' IP
|
// AnonymizeClientIP tells if the query log should anonymize clients' IP
|
||||||
// addresses.
|
// addresses.
|
||||||
AnonymizeClientIP bool
|
AnonymizeClientIP bool
|
||||||
|
|
||||||
|
// Ignored is the list of host names, which should not be written to
|
||||||
|
// log.
|
||||||
|
Ignored *stringutil.Set
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddParams is the parameters for adding an entry.
|
// AddParams is the parameters for adding an entry.
|
||||||
|
|
|
@ -155,6 +155,9 @@ func (l *queryLog) periodicRotate() {
|
||||||
// checkAndRotate rotates log files if those are older than the specified
|
// checkAndRotate rotates log files if those are older than the specified
|
||||||
// rotation interval.
|
// rotation interval.
|
||||||
func (l *queryLog) checkAndRotate() {
|
func (l *queryLog) checkAndRotate() {
|
||||||
|
l.lock.Lock()
|
||||||
|
defer l.lock.Unlock()
|
||||||
|
|
||||||
oldest, err := l.readFileFirstTimeValue()
|
oldest, err := l.readFileFirstTimeValue()
|
||||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
log.Error("querylog: reading oldest record for rotation: %s", err)
|
log.Error("querylog: reading oldest record for rotation: %s", err)
|
||||||
|
|
|
@ -263,6 +263,10 @@ func (l *queryLog) readNextEntry(
|
||||||
e = &logEntry{}
|
e = &logEntry{}
|
||||||
decodeLogEntry(e, line)
|
decodeLogEntry(e, line)
|
||||||
|
|
||||||
|
if l.isIgnored(e.QHost) {
|
||||||
|
return nil, ts, nil
|
||||||
|
}
|
||||||
|
|
||||||
e.client, err = l.client(e.ClientID, e.IP.String(), cache)
|
e.client, err = l.client(e.ClientID, e.IP.String(), cache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(
|
log.Error(
|
||||||
|
|
|
@ -5,7 +5,6 @@ package stats
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||||
|
@ -41,10 +40,11 @@ type StatsResp struct {
|
||||||
|
|
||||||
// handleStats handles requests to the GET /control/stats endpoint.
|
// handleStats handles requests to the GET /control/stats endpoint.
|
||||||
func (s *StatsCtx) handleStats(w http.ResponseWriter, r *http.Request) {
|
func (s *StatsCtx) handleStats(w http.ResponseWriter, r *http.Request) {
|
||||||
limit := atomic.LoadUint32(&s.limitHours)
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
resp, ok := s.getData(limit)
|
resp, ok := s.getData(s.limitHours)
|
||||||
log.Debug("stats: prepared data in %v", time.Since(start))
|
log.Debug("stats: prepared data in %v", time.Since(start))
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -65,7 +65,13 @@ type configResp struct {
|
||||||
|
|
||||||
// handleStatsInfo handles requests to the GET /control/stats_info endpoint.
|
// handleStatsInfo handles requests to the GET /control/stats_info endpoint.
|
||||||
func (s *StatsCtx) handleStatsInfo(w http.ResponseWriter, r *http.Request) {
|
func (s *StatsCtx) handleStatsInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
resp := configResp{IntervalDays: atomic.LoadUint32(&s.limitHours) / 24}
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
resp := configResp{IntervalDays: s.limitHours / 24}
|
||||||
|
if !s.enabled {
|
||||||
|
resp.IntervalDays = 0
|
||||||
|
}
|
||||||
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,16 +15,10 @@ import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
"github.com/AdguardTeam/golibs/stringutil"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DiskConfig is the configuration structure that is stored in file.
|
|
||||||
type DiskConfig struct {
|
|
||||||
// Interval is the number of days for which the statistics are collected
|
|
||||||
// before flushing to the database.
|
|
||||||
Interval uint32 `yaml:"statistics_interval"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkInterval returns true if days is valid to be used as statistics
|
// checkInterval returns true if days is valid to be used as statistics
|
||||||
// retention interval. The valid values are 0, 1, 7, 30 and 90.
|
// retention interval. The valid values are 0, 1, 7, 30 and 90.
|
||||||
func checkInterval(days uint32) (ok bool) {
|
func checkInterval(days uint32) (ok bool) {
|
||||||
|
@ -51,6 +45,12 @@ type Config struct {
|
||||||
// LimitDays is the maximum number of days to collect statistics into the
|
// LimitDays is the maximum number of days to collect statistics into the
|
||||||
// current unit.
|
// current unit.
|
||||||
LimitDays uint32
|
LimitDays uint32
|
||||||
|
|
||||||
|
// Enabled tells if the statistics are enabled.
|
||||||
|
Enabled bool
|
||||||
|
|
||||||
|
// Ignored is the list of host names, which should not be counted.
|
||||||
|
Ignored *stringutil.Set
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface is the statistics interface to be used by other packages.
|
// Interface is the statistics interface to be used by other packages.
|
||||||
|
@ -68,30 +68,22 @@ type Interface interface {
|
||||||
TopClientsIP(limit uint) []netip.Addr
|
TopClientsIP(limit uint) []netip.Addr
|
||||||
|
|
||||||
// WriteDiskConfig puts the Interface's configuration to the dc.
|
// WriteDiskConfig puts the Interface's configuration to the dc.
|
||||||
WriteDiskConfig(dc *DiskConfig)
|
WriteDiskConfig(dc *Config)
|
||||||
|
|
||||||
|
// ShouldCount returns true if request for the host should be counted.
|
||||||
|
ShouldCount(host string, qType, qClass uint16) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatsCtx collects the statistics and flushes it to the database. Its default
|
// StatsCtx collects the statistics and flushes it to the database. Its default
|
||||||
// flushing interval is one hour.
|
// flushing interval is one hour.
|
||||||
//
|
|
||||||
// TODO(e.burkov): Use atomic.Pointer for accessing db in go1.19.
|
|
||||||
type StatsCtx struct {
|
type StatsCtx struct {
|
||||||
// limitHours is the maximum number of hours to collect statistics into the
|
|
||||||
// current unit.
|
|
||||||
//
|
|
||||||
// It is of type uint32 to be accessed by atomic. It's arranged at the
|
|
||||||
// beginning of the structure to keep 64-bit alignment.
|
|
||||||
limitHours uint32
|
|
||||||
|
|
||||||
// currMu protects curr.
|
// currMu protects curr.
|
||||||
currMu *sync.RWMutex
|
currMu *sync.RWMutex
|
||||||
// curr is the actual statistics collection result.
|
// curr is the actual statistics collection result.
|
||||||
curr *unit
|
curr *unit
|
||||||
|
|
||||||
// dbMu protects db.
|
|
||||||
dbMu *sync.Mutex
|
|
||||||
// db is the opened statistics database, if any.
|
// db is the opened statistics database, if any.
|
||||||
db *bbolt.DB
|
db atomic.Pointer[bbolt.DB]
|
||||||
|
|
||||||
// unitIDGen is the function that generates an identifier for the current
|
// unitIDGen is the function that generates an identifier for the current
|
||||||
// unit. It's here for only testing purposes.
|
// unit. It's here for only testing purposes.
|
||||||
|
@ -106,6 +98,21 @@ type StatsCtx struct {
|
||||||
|
|
||||||
// filename is the name of database file.
|
// filename is the name of database file.
|
||||||
filename string
|
filename string
|
||||||
|
|
||||||
|
// lock protects all the fields below.
|
||||||
|
lock sync.Mutex
|
||||||
|
|
||||||
|
// enabled tells if the statistics are enabled.
|
||||||
|
enabled bool
|
||||||
|
|
||||||
|
// limitHours is the maximum number of hours to collect statistics into the
|
||||||
|
// current unit.
|
||||||
|
//
|
||||||
|
// TODO(s.chzhen): Rewrite to use time.Duration.
|
||||||
|
limitHours uint32
|
||||||
|
|
||||||
|
// ignored is the list of host names, which should not be counted.
|
||||||
|
ignored *stringutil.Set
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates s from conf and properly initializes it. Don't use s before
|
// New creates s from conf and properly initializes it. Don't use s before
|
||||||
|
@ -114,11 +121,12 @@ func New(conf Config) (s *StatsCtx, err error) {
|
||||||
defer withRecovered(&err)
|
defer withRecovered(&err)
|
||||||
|
|
||||||
s = &StatsCtx{
|
s = &StatsCtx{
|
||||||
|
enabled: conf.Enabled,
|
||||||
currMu: &sync.RWMutex{},
|
currMu: &sync.RWMutex{},
|
||||||
dbMu: &sync.Mutex{},
|
|
||||||
filename: conf.Filename,
|
filename: conf.Filename,
|
||||||
configModified: conf.ConfigModified,
|
configModified: conf.ConfigModified,
|
||||||
httpRegister: conf.HTTPRegister,
|
httpRegister: conf.HTTPRegister,
|
||||||
|
ignored: conf.Ignored,
|
||||||
}
|
}
|
||||||
if s.limitHours = conf.LimitDays * 24; !checkInterval(conf.LimitDays) {
|
if s.limitHours = conf.LimitDays * 24; !checkInterval(conf.LimitDays) {
|
||||||
s.limitHours = 24
|
s.limitHours = 24
|
||||||
|
@ -137,7 +145,7 @@ func New(conf Config) (s *StatsCtx, err error) {
|
||||||
var udb *unitDB
|
var udb *unitDB
|
||||||
id := s.unitIDGen()
|
id := s.unitIDGen()
|
||||||
|
|
||||||
tx, err := s.db.Begin(true)
|
tx, err := s.db.Load().Begin(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("stats: opening a transaction: %w", err)
|
return nil, fmt.Errorf("stats: opening a transaction: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -191,7 +199,7 @@ func (s *StatsCtx) Start() {
|
||||||
func (s *StatsCtx) Close() (err error) {
|
func (s *StatsCtx) Close() (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "stats: closing: %w") }()
|
defer func() { err = errors.Annotate(err, "stats: closing: %w") }()
|
||||||
|
|
||||||
db := s.swapDatabase(nil)
|
db := s.db.Swap(nil)
|
||||||
if db == nil {
|
if db == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -220,7 +228,10 @@ func (s *StatsCtx) Close() (err error) {
|
||||||
|
|
||||||
// Update implements the Interface interface for *StatsCtx.
|
// Update implements the Interface interface for *StatsCtx.
|
||||||
func (s *StatsCtx) Update(e Entry) {
|
func (s *StatsCtx) Update(e Entry) {
|
||||||
if atomic.LoadUint32(&s.limitHours) == 0 {
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
if !s.enabled || s.limitHours == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,14 +259,22 @@ func (s *StatsCtx) Update(e Entry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteDiskConfig implements the Interface interface for *StatsCtx.
|
// WriteDiskConfig implements the Interface interface for *StatsCtx.
|
||||||
func (s *StatsCtx) WriteDiskConfig(dc *DiskConfig) {
|
func (s *StatsCtx) WriteDiskConfig(dc *Config) {
|
||||||
dc.Interval = atomic.LoadUint32(&s.limitHours) / 24
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
dc.LimitDays = s.limitHours / 24
|
||||||
|
dc.Enabled = s.enabled
|
||||||
|
dc.Ignored = s.ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
// TopClientsIP implements the [Interface] interface for *StatsCtx.
|
// TopClientsIP implements the [Interface] interface for *StatsCtx.
|
||||||
func (s *StatsCtx) TopClientsIP(maxCount uint) (ips []netip.Addr) {
|
func (s *StatsCtx) TopClientsIP(maxCount uint) (ips []netip.Addr) {
|
||||||
limit := atomic.LoadUint32(&s.limitHours)
|
s.lock.Lock()
|
||||||
if limit == 0 {
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
limit := s.limitHours
|
||||||
|
if !s.enabled || limit == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,25 +303,6 @@ func (s *StatsCtx) TopClientsIP(maxCount uint) (ips []netip.Addr) {
|
||||||
return ips
|
return ips
|
||||||
}
|
}
|
||||||
|
|
||||||
// database returns the database if it's opened. It's safe for concurrent use.
|
|
||||||
func (s *StatsCtx) database() (db *bbolt.DB) {
|
|
||||||
s.dbMu.Lock()
|
|
||||||
defer s.dbMu.Unlock()
|
|
||||||
|
|
||||||
return s.db
|
|
||||||
}
|
|
||||||
|
|
||||||
// swapDatabase swaps the database with another one and returns it. It's safe
|
|
||||||
// for concurrent use.
|
|
||||||
func (s *StatsCtx) swapDatabase(with *bbolt.DB) (old *bbolt.DB) {
|
|
||||||
s.dbMu.Lock()
|
|
||||||
defer s.dbMu.Unlock()
|
|
||||||
|
|
||||||
old, s.db = s.db, with
|
|
||||||
|
|
||||||
return old
|
|
||||||
}
|
|
||||||
|
|
||||||
// deleteOldUnits walks the buckets available to tx and deletes old units. It
|
// deleteOldUnits walks the buckets available to tx and deletes old units. It
|
||||||
// returns the number of deletions performed.
|
// returns the number of deletions performed.
|
||||||
func deleteOldUnits(tx *bbolt.Tx, firstID uint32) (deleted int) {
|
func deleteOldUnits(tx *bbolt.Tx, firstID uint32) (deleted int) {
|
||||||
|
@ -358,10 +358,7 @@ func (s *StatsCtx) openDB() (err error) {
|
||||||
// Use defer to unlock the mutex as soon as possible.
|
// Use defer to unlock the mutex as soon as possible.
|
||||||
defer log.Debug("stats: database opened")
|
defer log.Debug("stats: database opened")
|
||||||
|
|
||||||
s.dbMu.Lock()
|
s.db.Store(db)
|
||||||
defer s.dbMu.Unlock()
|
|
||||||
|
|
||||||
s.db = db
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -369,6 +366,9 @@ func (s *StatsCtx) openDB() (err error) {
|
||||||
func (s *StatsCtx) flush() (cont bool, sleepFor time.Duration) {
|
func (s *StatsCtx) flush() (cont bool, sleepFor time.Duration) {
|
||||||
id := s.unitIDGen()
|
id := s.unitIDGen()
|
||||||
|
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
s.currMu.Lock()
|
s.currMu.Lock()
|
||||||
defer s.currMu.Unlock()
|
defer s.currMu.Unlock()
|
||||||
|
|
||||||
|
@ -377,12 +377,12 @@ func (s *StatsCtx) flush() (cont bool, sleepFor time.Duration) {
|
||||||
return false, 0
|
return false, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
limit := atomic.LoadUint32(&s.limitHours)
|
limit := s.limitHours
|
||||||
if limit == 0 || ptr.id == id {
|
if limit == 0 || ptr.id == id {
|
||||||
return true, time.Second
|
return true, time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
db := s.database()
|
db := s.db.Load()
|
||||||
if db == nil {
|
if db == nil {
|
||||||
return true, 0
|
return true, 0
|
||||||
}
|
}
|
||||||
|
@ -437,21 +437,30 @@ func (s *StatsCtx) periodicFlush() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StatsCtx) setLimit(limitDays int) {
|
func (s *StatsCtx) setLimit(limitDays int) {
|
||||||
atomic.StoreUint32(&s.limitHours, uint32(24*limitDays))
|
s.lock.Lock()
|
||||||
if limitDays == 0 {
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
if limitDays != 0 {
|
||||||
|
s.enabled = true
|
||||||
|
s.limitHours = uint32(24 * limitDays)
|
||||||
|
log.Debug("stats: set limit: %d days", limitDays)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.enabled = false
|
||||||
|
log.Debug("stats: disabled")
|
||||||
|
|
||||||
if err := s.clear(); err != nil {
|
if err := s.clear(); err != nil {
|
||||||
log.Error("stats: %s", err)
|
log.Error("stats: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("stats: set limit: %d days", limitDays)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset counters and clear database
|
// Reset counters and clear database
|
||||||
func (s *StatsCtx) clear() (err error) {
|
func (s *StatsCtx) clear() (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "clearing: %w") }()
|
defer func() { err = errors.Annotate(err, "clearing: %w") }()
|
||||||
|
|
||||||
db := s.swapDatabase(nil)
|
db := s.db.Swap(nil)
|
||||||
if db != nil {
|
if db != nil {
|
||||||
var tx *bbolt.Tx
|
var tx *bbolt.Tx
|
||||||
tx, err = db.Begin(true)
|
tx, err = db.Begin(true)
|
||||||
|
@ -495,7 +504,7 @@ func (s *StatsCtx) clear() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StatsCtx) loadUnits(limit uint32) (units []*unitDB, firstID uint32) {
|
func (s *StatsCtx) loadUnits(limit uint32) (units []*unitDB, firstID uint32) {
|
||||||
db := s.database()
|
db := s.db.Load()
|
||||||
if db == nil {
|
if db == nil {
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
|
@ -547,3 +556,13 @@ func (s *StatsCtx) loadUnits(limit uint32) (units []*unitDB, firstID uint32) {
|
||||||
|
|
||||||
return units, firstID
|
return units, firstID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShouldCount returns true if request for the host should be counted.
|
||||||
|
func (s *StatsCtx) ShouldCount(host string, _, _ uint16) bool {
|
||||||
|
return !s.isIgnored(host)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isIgnored returns true if the host is in the Ignored list.
|
||||||
|
func (s *StatsCtx) isIgnored(host string) bool {
|
||||||
|
return s.ignored.Has(host)
|
||||||
|
}
|
||||||
|
|
|
@ -47,8 +47,6 @@ func TestStats_races(t *testing.T) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
testutil.CleanupAndRequireSuccess(t, s.Close)
|
testutil.CleanupAndRequireSuccess(t, s.Close)
|
||||||
|
|
||||||
type signal = struct{}
|
|
||||||
|
|
||||||
writeFunc := func(start, fin *sync.WaitGroup, waitCh <-chan unit, i int) {
|
writeFunc := func(start, fin *sync.WaitGroup, waitCh <-chan unit, i int) {
|
||||||
e := Entry{
|
e := Entry{
|
||||||
Domain: fmt.Sprintf("example-%d.org", i),
|
Domain: fmt.Sprintf("example-%d.org", i),
|
||||||
|
|
|
@ -53,6 +53,7 @@ func TestStats(t *testing.T) {
|
||||||
conf := stats.Config{
|
conf := stats.Config{
|
||||||
Filename: filepath.Join(t.TempDir(), "stats.db"),
|
Filename: filepath.Join(t.TempDir(), "stats.db"),
|
||||||
LimitDays: 1,
|
LimitDays: 1,
|
||||||
|
Enabled: true,
|
||||||
UnitID: constUnitID,
|
UnitID: constUnitID,
|
||||||
HTTPRegister: func(_, url string, handler http.HandlerFunc) {
|
HTTPRegister: func(_, url string, handler http.HandlerFunc) {
|
||||||
handlers[url] = handler
|
handlers[url] = handler
|
||||||
|
@ -158,6 +159,7 @@ func TestLargeNumbers(t *testing.T) {
|
||||||
conf := stats.Config{
|
conf := stats.Config{
|
||||||
Filename: filepath.Join(t.TempDir(), "stats.db"),
|
Filename: filepath.Join(t.TempDir(), "stats.db"),
|
||||||
LimitDays: 1,
|
LimitDays: 1,
|
||||||
|
Enabled: true,
|
||||||
UnitID: func() (id uint32) { return atomic.LoadUint32(&curHour) },
|
UnitID: func() (id uint32) { return atomic.LoadUint32(&curHour) },
|
||||||
HTTPRegister: func(_, url string, handler http.HandlerFunc) { handlers[url] = handler },
|
HTTPRegister: func(_, url string, handler http.HandlerFunc) { handlers[url] = handler },
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
"github.com/AdguardTeam/golibs/stringutil"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -341,13 +342,15 @@ type pairsGetter func(u *unitDB) (pairs []countPair)
|
||||||
|
|
||||||
// topsCollector collects statistics about highest values from the given *unitDB
|
// topsCollector collects statistics about highest values from the given *unitDB
|
||||||
// slice using pg to retrieve data.
|
// slice using pg to retrieve data.
|
||||||
func topsCollector(units []*unitDB, max int, pg pairsGetter) []map[string]uint64 {
|
func topsCollector(units []*unitDB, max int, ignored *stringutil.Set, pg pairsGetter) []map[string]uint64 {
|
||||||
m := map[string]uint64{}
|
m := map[string]uint64{}
|
||||||
for _, u := range units {
|
for _, u := range units {
|
||||||
for _, cp := range pg(u) {
|
for _, cp := range pg(u) {
|
||||||
|
if !ignored.Has(cp.Name) {
|
||||||
m[cp.Name] += cp.Count
|
m[cp.Name] += cp.Count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
a2 := convertMapToSlice(m, max)
|
a2 := convertMapToSlice(m, max)
|
||||||
|
|
||||||
return convertTopSlice(a2)
|
return convertTopSlice(a2)
|
||||||
|
@ -408,9 +411,9 @@ func (s *StatsCtx) getData(limit uint32) (StatsResp, bool) {
|
||||||
BlockedFiltering: statsCollector(units, firstID, timeUnit, func(u *unitDB) (num uint64) { return u.NResult[RFiltered] }),
|
BlockedFiltering: statsCollector(units, firstID, timeUnit, func(u *unitDB) (num uint64) { return u.NResult[RFiltered] }),
|
||||||
ReplacedSafebrowsing: statsCollector(units, firstID, timeUnit, func(u *unitDB) (num uint64) { return u.NResult[RSafeBrowsing] }),
|
ReplacedSafebrowsing: statsCollector(units, firstID, timeUnit, func(u *unitDB) (num uint64) { return u.NResult[RSafeBrowsing] }),
|
||||||
ReplacedParental: statsCollector(units, firstID, timeUnit, func(u *unitDB) (num uint64) { return u.NResult[RParental] }),
|
ReplacedParental: statsCollector(units, firstID, timeUnit, func(u *unitDB) (num uint64) { return u.NResult[RParental] }),
|
||||||
TopQueried: topsCollector(units, maxDomains, func(u *unitDB) (pairs []countPair) { return u.Domains }),
|
TopQueried: topsCollector(units, maxDomains, s.ignored, func(u *unitDB) (pairs []countPair) { return u.Domains }),
|
||||||
TopBlocked: topsCollector(units, maxDomains, func(u *unitDB) (pairs []countPair) { return u.BlockedDomains }),
|
TopBlocked: topsCollector(units, maxDomains, s.ignored, func(u *unitDB) (pairs []countPair) { return u.BlockedDomains }),
|
||||||
TopClients: topsCollector(units, maxClients, func(u *unitDB) (pairs []countPair) { return u.Clients }),
|
TopClients: topsCollector(units, maxClients, nil, func(u *unitDB) (pairs []countPair) { return u.Clients }),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Total counters:
|
// Total counters:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module github.com/AdguardTeam/AdGuardHome/internal/tools
|
module github.com/AdguardTeam/AdGuardHome/internal/tools
|
||||||
|
|
||||||
go 1.18
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fzipp/gocyclo v0.6.0
|
github.com/fzipp/gocyclo v0.6.0
|
||||||
|
@ -8,10 +8,10 @@ require (
|
||||||
github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28
|
github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28
|
||||||
github.com/kisielk/errcheck v1.6.3
|
github.com/kisielk/errcheck v1.6.3
|
||||||
github.com/kyoh86/looppointer v0.2.1
|
github.com/kyoh86/looppointer v0.2.1
|
||||||
github.com/securego/gosec/v2 v2.14.0
|
github.com/securego/gosec/v2 v2.15.0
|
||||||
golang.org/x/tools v0.5.1-0.20230117180257-8aba49bb5ea2
|
golang.org/x/tools v0.6.0
|
||||||
golang.org/x/vuln v0.0.0-20230130175424-dd534eeddf33
|
golang.org/x/vuln v0.0.0-20230213165600-1a019b0c7f30
|
||||||
honnef.co/go/tools v0.3.3
|
honnef.co/go/tools v0.4.1
|
||||||
mvdan.cc/gofumpt v0.4.0
|
mvdan.cc/gofumpt v0.4.0
|
||||||
mvdan.cc/unparam v0.0.0-20230125043941-70a0ce6e7b95
|
mvdan.cc/unparam v0.0.0-20230125043941-70a0ce6e7b95
|
||||||
)
|
)
|
||||||
|
@ -24,10 +24,10 @@ require (
|
||||||
github.com/kyoh86/nolint v0.0.1 // indirect
|
github.com/kyoh86/nolint v0.0.1 // indirect
|
||||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
|
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 // indirect
|
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb // indirect
|
||||||
golang.org/x/exp/typeparams v0.0.0-20230131160201-f062dba9d201 // indirect
|
golang.org/x/exp/typeparams v0.0.0-20230213192124-5e25df0256eb // indirect
|
||||||
golang.org/x/mod v0.7.0 // indirect
|
golang.org/x/mod v0.8.0 // indirect
|
||||||
golang.org/x/sync v0.1.0 // indirect
|
golang.org/x/sync v0.1.0 // indirect
|
||||||
golang.org/x/sys v0.4.0 // indirect
|
golang.org/x/sys v0.5.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,6 +7,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||||
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
|
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
|
||||||
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
|
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
|
||||||
|
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||||
github.com/golangci/misspell v0.4.0 h1:KtVB/hTK4bbL/S6bs64rYyk8adjmh1BygbBiaAiX+a0=
|
github.com/golangci/misspell v0.4.0 h1:KtVB/hTK4bbL/S6bs64rYyk8adjmh1BygbBiaAiX+a0=
|
||||||
github.com/golangci/misspell v0.4.0/go.mod h1:W6O/bwV6lGDxUCChm2ykw9NQdd5bYd1Xkjo88UcWyJc=
|
github.com/golangci/misspell v0.4.0/go.mod h1:W6O/bwV6lGDxUCChm2ykw9NQdd5bYd1Xkjo88UcWyJc=
|
||||||
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=
|
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=
|
||||||
|
@ -29,14 +30,14 @@ github.com/kyoh86/nolint v0.0.1 h1:GjNxDEkVn2wAxKHtP7iNTrRxytRZ1wXxLV5j4XzGfRU=
|
||||||
github.com/kyoh86/nolint v0.0.1/go.mod h1:1ZiZZ7qqrZ9dZegU96phwVcdQOMKIqRzFJL3ewq9gtI=
|
github.com/kyoh86/nolint v0.0.1/go.mod h1:1ZiZZ7qqrZ9dZegU96phwVcdQOMKIqRzFJL3ewq9gtI=
|
||||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA=
|
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA=
|
||||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8=
|
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8=
|
||||||
github.com/onsi/ginkgo/v2 v2.3.1 h1:8SbseP7qM32WcvE6VaN6vfXxv698izmsJ1UQX9ve7T8=
|
github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI=
|
||||||
github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI=
|
github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
github.com/securego/gosec/v2 v2.14.0 h1:U1hfs0oBackChXA72plCYVA4cOlQ4gO+209dHiSNZbI=
|
github.com/securego/gosec/v2 v2.15.0 h1:v4Ym7FF58/jlykYmmhZ7mTm7FQvN/setNm++0fgIAtw=
|
||||||
github.com/securego/gosec/v2 v2.14.0/go.mod h1:Ff03zEi5NwSOfXj9nFpBfhbWTtROCkg9N+9goggrYn4=
|
github.com/securego/gosec/v2 v2.15.0/go.mod h1:VOjTrZOkUtSDt2QLSJmQBMWnvwiQPEjg0l+5juIqGk8=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
@ -53,22 +54,22 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 h1:BEABXpNXLEz0WxtA+6CQIz2xkg80e+1zrhWyMcq8VzE=
|
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w=
|
||||||
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||||
golang.org/x/exp/typeparams v0.0.0-20230131160201-f062dba9d201 h1:O1QcdQUR9htWjzzsXVFPX+RJ3n1P/u/5bsQR8dbs5BY=
|
golang.org/x/exp/typeparams v0.0.0-20230213192124-5e25df0256eb h1:WGs/bGIWYyAY5PVgGGMXqGGCxSJz4fpoUExb/vgqNCU=
|
||||||
golang.org/x/exp/typeparams v0.0.0-20230131160201-f062dba9d201/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
golang.org/x/exp/typeparams v0.0.0-20230213192124-5e25df0256eb/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -83,35 +84,33 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
|
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||||
golang.org/x/tools v0.5.1-0.20230117180257-8aba49bb5ea2 h1:v0FhRDmSCNH/0EurAT6T8KRY4aNuUhz6/WwBMxG+gvQ=
|
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||||
golang.org/x/tools v0.5.1-0.20230117180257-8aba49bb5ea2/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/vuln v0.0.0-20230130175424-dd534eeddf33 h1:je2aB5nnlseeGvJy5clg6EyC3jjbbCNsRDroC3qQJsA=
|
golang.org/x/vuln v0.0.0-20230213165600-1a019b0c7f30 h1:Q4B8LhSjZGto/+P5REBb4N51ec2H4efRqjBIeJ6nv/Y=
|
||||||
golang.org/x/vuln v0.0.0-20230130175424-dd534eeddf33/go.mod h1:cBP4HMKv0X+x96j8IJWCKk0eqpakBmmHjKGSSC0NaYE=
|
golang.org/x/vuln v0.0.0-20230213165600-1a019b0c7f30/go.mod h1:cBP4HMKv0X+x96j8IJWCKk0eqpakBmmHjKGSSC0NaYE=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=
|
honnef.co/go/tools v0.4.1 h1:HPeloSr0mLOEMOkhT9Au5aeki44kvP6ka3v1xIsM6Zo=
|
||||||
honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=
|
honnef.co/go/tools v0.4.1/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA=
|
||||||
mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
|
mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
|
||||||
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
|
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
|
||||||
mvdan.cc/unparam v0.0.0-20230125043941-70a0ce6e7b95 h1:n/xhncJPSt0YzfOhnyn41XxUdrWQNgmLBG72FE27Fqw=
|
mvdan.cc/unparam v0.0.0-20230125043941-70a0ce6e7b95 h1:n/xhncJPSt0YzfOhnyn41XxUdrWQNgmLBG72FE27Fqw=
|
||||||
|
|
|
@ -205,7 +205,7 @@ code from [the repo][companiesrepo].
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
( cd scripts/companiesdb && sh ./download.sh )
|
sh ./scripts/companiesdb/download.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
[companiesrepo]: https://github.com/AdguardTeam/companiesdb
|
[companiesrepo]: https://github.com/AdguardTeam/companiesdb
|
||||||
|
|
|
@ -4,11 +4,9 @@ set -e -f -u -x
|
||||||
|
|
||||||
# This script syncs companies DB that we bundle with AdGuard Home. The source
|
# This script syncs companies DB that we bundle with AdGuard Home. The source
|
||||||
# for this database is https://github.com/AdguardTeam/companiesdb.
|
# for this database is https://github.com/AdguardTeam/companiesdb.
|
||||||
|
#
|
||||||
|
trackers_url='https://raw.githubusercontent.com/AdguardTeam/companiesdb/main/dist/trackers.json'
|
||||||
|
output='./client/src/helpers/trackers/trackers.json'
|
||||||
|
readonly trackers_url output
|
||||||
|
|
||||||
whotracksme='https://raw.githubusercontent.com/AdguardTeam/companiesdb/main/dist/whotracksme.json'
|
curl -o "$output" -v "$trackers_url"
|
||||||
adguard='https://raw.githubusercontent.com/AdguardTeam/companiesdb/main/dist/adguard.json'
|
|
||||||
base_path='../../client/src/helpers/trackers'
|
|
||||||
readonly whotracksme adguard base_path
|
|
||||||
|
|
||||||
curl -o "${base_path}/whotracksme.json" -v "$whotracksme"
|
|
||||||
curl -o "${base_path}/adguard.json" -v "$adguard"
|
|
||||||
|
|
|
@ -338,6 +338,18 @@ download_wget() {
|
||||||
wget --no-verbose -O "$wget_output" "$1"
|
wget --no-verbose -O "$wget_output" "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# download_fetch uses fetch(1) to download a file. The first argument is the
|
||||||
|
# URL. The second argument is optional and is the output file.
|
||||||
|
download_fetch() {
|
||||||
|
fetch_output="${2:-}"
|
||||||
|
if [ "$fetch_output" = '' ]
|
||||||
|
then
|
||||||
|
fetch -o '-' "$1"
|
||||||
|
else
|
||||||
|
fetch -o "$fetch_output" "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Function set_download_func sets the appropriate function for downloading
|
# Function set_download_func sets the appropriate function for downloading
|
||||||
# files.
|
# files.
|
||||||
set_download_func() {
|
set_download_func() {
|
||||||
|
@ -348,6 +360,9 @@ set_download_func() {
|
||||||
elif is_command 'wget'
|
elif is_command 'wget'
|
||||||
then
|
then
|
||||||
download_func='download_wget'
|
download_func='download_wget'
|
||||||
|
elif is_command 'fetch'
|
||||||
|
then
|
||||||
|
download_func='download_fetch'
|
||||||
else
|
else
|
||||||
error_exit "either curl or wget is required to install AdGuard Home via this script"
|
error_exit "either curl or wget is required to install AdGuard Home via this script"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -227,8 +227,9 @@ gocyclo --over 13 ./internal/dhcpd ./internal/filtering/ ./internal/home/
|
||||||
# Apply stricter standards to new or somewhat refactored code.
|
# Apply stricter standards to new or somewhat refactored code.
|
||||||
gocyclo --over 10 ./internal/aghio/ ./internal/aghnet/ ./internal/aghos/\
|
gocyclo --over 10 ./internal/aghio/ ./internal/aghnet/ ./internal/aghos/\
|
||||||
./internal/aghtest/ ./internal/dnsforward/ ./internal/filtering/rewrite/\
|
./internal/aghtest/ ./internal/dnsforward/ ./internal/filtering/rewrite/\
|
||||||
./internal/stats/ ./internal/tools/ ./internal/updater/ ./internal/version/\
|
./internal/stats/ ./internal/tools/ ./internal/updater/\
|
||||||
./scripts/vetted-filters/ ./main.go
|
./internal/version/ ./scripts/blocked-services/ ./scripts/vetted-filters/\
|
||||||
|
./main.go
|
||||||
|
|
||||||
ineffassign ./...
|
ineffassign ./...
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ readonly go
|
||||||
count_flags='--count=1'
|
count_flags='--count=1'
|
||||||
cover_flags='--coverprofile=./coverage.txt'
|
cover_flags='--coverprofile=./coverage.txt'
|
||||||
shuffle_flags='--shuffle=on'
|
shuffle_flags='--shuffle=on'
|
||||||
timeout_flags="${TIMEOUT_FLAGS:---timeout=30s}"
|
timeout_flags="${TIMEOUT_FLAGS:---timeout=90s}"
|
||||||
readonly count_flags cover_flags shuffle_flags timeout_flags
|
readonly count_flags cover_flags shuffle_flags timeout_flags
|
||||||
|
|
||||||
"$go" test "$count_flags" "$cover_flags" "$race_flags" "$shuffle_flags" "$timeout_flags"\
|
"$go" test "$count_flags" "$cover_flags" "$race_flags" "$shuffle_flags" "$timeout_flags"\
|
||||||
|
|
Loading…
Reference in a new issue