Compare commits

..

3 Commits

Author SHA1 Message Date
Eugene Burkov
3918789ca7 aghnet: imp permissions logic 2023-02-06 16:11:55 +03:00
Eugene Burkov
da1b53a3b4 Merge branch 'master' into 4728-cap-check 2023-02-06 15:45:10 +03:00
yscialom
b82c67405f Fix #4714: correctly check thread can bind to privileged ports 2022-07-09 17:21:56 +02:00
86 changed files with 1448 additions and 1942 deletions

View File

@@ -1,7 +1,7 @@
'name': 'build' 'name': 'build'
'env': 'env':
'GO_VERSION': '1.19.6' 'GO_VERSION': '1.18.9'
'NODE_VERSION': '14' 'NODE_VERSION': '14'
'on': 'on':

View File

@@ -1,7 +1,7 @@
'name': 'lint' 'name': 'lint'
'env': 'env':
'GO_VERSION': '1.19.6' 'GO_VERSION': '1.18.9'
'on': 'on':
'push': 'push':

View File

@@ -14,25 +14,20 @@ and this project adheres to
<!-- <!--
## [v0.108.0] - TBA ## [v0.108.0] - TBA
## [v0.107.26] - 2023-03-09 (APPROX.) ## [v0.107.24] - 2023-02-22 (APPROX.)
See also the [v0.107.26 GitHub milestone][ms-v0.107.26]. See also the [v0.107.24 GitHub milestone][ms-v0.107.24].
[ms-v0.107.26]: https://github.com/AdguardTeam/AdGuardHome/milestone/62?closed=1 [ms-v0.107.24]: https://github.com/AdguardTeam/AdGuardHome/milestone/60?closed=1
NOTE: Add new changes BELOW THIS COMMENT. NOTE: Add new changes BELOW THIS COMMENT.
--> -->
### Fixed ### Fixed
- Requirements to domain names in domain-specific upstream configurations have - The icon for League Of Legends on the Blocked services page ([#5433]).
been relaxed to meet those from [RFC 3696][rfc3696] ([#4884]).
- Failing service installation via script on FreeBSD ([#5431]).
[#4884]: https://github.com/AdguardTeam/AdGuardHome/issues/4884 [#5433]: https://github.com/AdguardTeam/AdGuardHome/issues/5433
[#5431]: https://github.com/AdguardTeam/AdGuardHome/issues/5431
[rfc3696]: https://datatracker.ietf.org/doc/html/rfc3696
<!-- <!--
NOTE: Add new changes ABOVE THIS COMMENT. NOTE: Add new changes ABOVE THIS COMMENT.
@@ -40,112 +35,6 @@ NOTE: Add new changes ABOVE THIS COMMENT.
## [v0.107.25] - 2023-02-21
See also the [v0.107.25 GitHub milestone][ms-v0.107.25].
### Fixed
- Panic when using unencrypted DNS-over-HTTPS ([#5518]).
[#5518]: https://github.com/AdguardTeam/AdGuardHome/issues/5518
[ms-v0.107.25]: https://github.com/AdguardTeam/AdGuardHome/milestone/61?closed=1
## [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].
@@ -1148,6 +1037,7 @@ 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:
@@ -1694,13 +1584,11 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
<!-- <!--
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.26...HEAD [Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.24...HEAD
[v0.107.26]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.25...v0.107.26 [v0.107.24]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.23...v0.107.24
--> -->
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.25...HEAD [Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.23...HEAD
[v0.107.25]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.24...v0.107.25
[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

View File

@@ -4,26 +4,17 @@
# See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html. # See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html.
.POSIX: .POSIX:
# This comment is used to simplify checking local copies of the
# Makefile. Bump this number every time a significant change is made to
# this Makefile.
#
# AdGuard-Project-Version: 2
# Don't name these macros "GO" etc., because GNU Make apparently makes
# them exported environment variables with the literal value of
# "${GO:-go}" and so on, which is not what we need. Use a dot in the
# name to make sure that users don't have an environment variable with
# the same name.
#
# See https://unix.stackexchange.com/q/646255/105635.
GO.MACRO = $${GO:-go}
VERBOSE.MACRO = $${VERBOSE:-0}
CHANNEL = development CHANNEL = development
CLIENT_DIR = client CLIENT_DIR = client
COMMIT = $$( git rev-parse --short HEAD ) COMMIT = $$( git rev-parse --short HEAD )
DIST_DIR = dist DIST_DIR = dist
# Don't name this macro "GO", because GNU Make apparenly makes it an
# exported environment variable with the literal value of "${GO:-go}",
# which is not what we need. Use a dot in the name to make sure that
# users don't have an environment variable with the same name.
#
# See https://unix.stackexchange.com/q/646255/105635.
GO.MACRO = $${GO:-go}
GOPROXY = https://goproxy.cn|https://proxy.golang.org|direct GOPROXY = https://goproxy.cn|https://proxy.golang.org|direct
GOSUMDB = sum.golang.google.cn GOSUMDB = sum.golang.google.cn
GPG_KEY = devteam@adguard.com GPG_KEY = devteam@adguard.com
@@ -34,6 +25,7 @@ NPM_INSTALL_FLAGS = $(NPM_FLAGS) --quiet --no-progress --ignore-engines\
--ignore-optional --ignore-platform --ignore-scripts --ignore-optional --ignore-platform --ignore-scripts
RACE = 0 RACE = 0
SIGN = 1 SIGN = 1
VERBOSE = 0
VERSION = v0.0.0 VERSION = v0.0.0
YARN = yarn YARN = yarn
@@ -67,13 +59,13 @@ ENV = env\
RACE='$(RACE)'\ RACE='$(RACE)'\
SIGN='$(SIGN)'\ SIGN='$(SIGN)'\
NEXTAPI='$(NEXTAPI)'\ NEXTAPI='$(NEXTAPI)'\
VERBOSE="$(VERBOSE.MACRO)"\ VERBOSE='$(VERBOSE)'\
VERSION='$(VERSION)'\ VERSION='$(VERSION)'\
# Keep the line above blank. # Keep the line above blank.
# Keep this target first, so that a naked make invocation triggers a # Keep this target first, so that a naked make invocation triggers
# full build. # a full build.
build: deps quick-build build: deps quick-build
quick-build: js-build go-build quick-build: js-build go-build
@@ -127,4 +119,4 @@ go-os-check:
openapi-lint: ; cd ./openapi/ && $(YARN) test openapi-lint: ; cd ./openapi/ && $(YARN) test
openapi-show: ; cd ./openapi/ && $(YARN) start openapi-show: ; cd ./openapi/ && $(YARN) start
txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh

View File

@@ -81,24 +81,12 @@ 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>
To install with `curl` run the following command: Run the following command in your terminal:
```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;
@@ -261,7 +249,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.19 or later; * [Go](https://golang.org/dl/) v1.18 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.

View File

@@ -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:6.1' 'dockerGo': 'adguard/golang-ubuntu:5.4'
'stages': 'stages':
- 'Build frontend': - 'Build frontend':
@@ -136,12 +136,8 @@
set -e -f -u -x set -e -f -u -x
COMMIT="${bamboo.repository.revision.number}"
export COMMIT
readonly COMMIT
# Explicitly checkout the revision that we need. # Explicitly checkout the revision that we need.
git checkout "$COMMIT" git checkout "${bamboo.repository.revision.number}"
# Install Qemu, create builder. # Install Qemu, create builder.
docker version -f '{{ .Server.Experimental }}' docker version -f '{{ .Server.Experimental }}'
@@ -161,13 +157,12 @@
docker info docker info
# Prepare and push the build. # Prepare and push the build.
env\ make\
CHANNEL="${bamboo.channel}"\ CHANNEL="${bamboo.channel}"\
DIST_DIR='dist'\
DOCKER_IMAGE_NAME='adguard/adguardhome'\ DOCKER_IMAGE_NAME='adguard/adguardhome'\
DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true"\ DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true"\
VERBOSE='1'\ VERBOSE='1'\
sh ./scripts/make/build-docker.sh build-docker
'environment': 'environment':
DOCKER_CLI_EXPERIMENTAL=enabled DOCKER_CLI_EXPERIMENTAL=enabled
'final-tasks': 'final-tasks':
@@ -228,7 +223,6 @@
channel="${bamboo.channel}" channel="${bamboo.channel}"
readonly channel readonly channel
case "$channel" case "$channel"
in in
('release') ('release')
@@ -275,10 +269,8 @@
set -e -f -u -x set -e -f -u -x
channel="${bamboo.channel}" export CHANNEL="${bamboo.channel}"
readonly channel if [ "$CHANNEL" != 'release' ] && [ "${CHANNEL}" != 'beta' ]
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"
@@ -331,7 +323,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:6.1' 'dockerGo': 'adguard/golang-ubuntu:5.4'
# 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]+':
@@ -346,4 +338,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:6.1' 'dockerGo': 'adguard/golang-ubuntu:5.4'

View File

@@ -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:6.1' 'dockerGo': 'adguard/golang-ubuntu:5.4'
'stages': 'stages':
- 'Tests': - 'Tests':

View File

@@ -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": "Ачысціць кэш"

View File

@@ -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": "Error buscar la actualización. Comprueba tu conexión a Internet.", "version_request_error": "La búsqueda de actualizaciones falló. Por favor revisa 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é DNS?", "confirm_dns_cache_clear": "¿Estás seguro de que deseas borrar la caché de DNS?",
"cache_cleared": "Caché DNS borrado correctamente", "cache_cleared": "Caché DNS borrado con éxito",
"clear_cache": "Borrar caché" "clear_cache": "Borrar caché"
} }

View File

@@ -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": "Jollei reitittimesi tarjoa DHCP-asetuksia, voit käyttää AdGuard Homen omaa sisäänrakennettua DHCP-palvelinta.", "dhcp_description": "Jos reitittimessäsi ei ole 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.",

View File

@@ -449,7 +449,7 @@
"access_disallowed_title": "İzin verilmeyen istemciler", "access_disallowed_title": "İzin verilmeyen istemciler",
"access_disallowed_desc": "CIDR'lerin, IP adreslerinin veya <a>İstemci Kimliklerin</a> listesi. Bu listede girişler varsa, AdGuard Home bu istemcilerden gelen istekleri keser. İzin verilen istemcilerde girişler varsa, bu alan yok sayılır.", "access_disallowed_desc": "CIDR'lerin, IP adreslerinin veya <a>İstemci Kimliklerin</a> listesi. Bu listede girişler varsa, AdGuard Home bu istemcilerden gelen istekleri keser. İzin verilen istemcilerde girişler varsa, bu alan yok sayılır.",
"access_blocked_title": "İzin verilmeyen alan adları", "access_blocked_title": "İzin verilmeyen alan adları",
"access_blocked_desc": "Bu işlem filtrelerle ilgili değildir. AdGuard Home, bu alan adlarından gelen DNS sorgularını yanıtsız bırakır ve bu sorgular sorgu günlüğünde görünmez. Tam alan adlarını, joker karakterleri veya URL filtre kurallarını belirtebilirsiniz, örn. \"example.org\", \"*.example.org\" veya \"||example.org^\".", "access_blocked_desc": "Bu işlem filtrelerle ilgili değildir. AdGuard Home, bu alan adlarından gelen DNS sorgularını yanıtsız bırakır ve bu sorgular sorgu günlüğünde görünmez. Tam alan adlarını, joker karakterleri veya URL filtre kurallarını belirtebilirsiniz, ör. \"example.org\", \"*.example.org\" veya \"||example.org^\".",
"access_settings_saved": "Erişim ayarları başarıyla kaydedildi!", "access_settings_saved": "Erişim ayarları başarıyla kaydedildi!",
"updates_checked": "AdGuard Home'un yeni bir sürümü mevcut", "updates_checked": "AdGuard Home'un yeni bir sürümü mevcut",
"updates_version_equal": "AdGuard Home yazılımı güncel durumda", "updates_version_equal": "AdGuard Home yazılımı güncel durumda",

View File

@@ -16,7 +16,7 @@
"resolve_clients_title": "启用客户端的 IP 地址的反向解析", "resolve_clients_title": "启用客户端的 IP 地址的反向解析",
"resolve_clients_desc": "通过发送 PTR 查询到对应的解析器 (本地客户端的私人 DNS 服务器,公共 IP 客户端的上游服务器) 将 IP 地址反向解析成其客户端主机名。", "resolve_clients_desc": "通过发送 PTR 查询到对应的解析器 (本地客户端的私人 DNS 服务器,公共 IP 客户端的上游服务器) 将 IP 地址反向解析成其客户端主机名。",
"use_private_ptr_resolvers_title": "使用私人反向 DNS 解析器", "use_private_ptr_resolvers_title": "使用私人反向 DNS 解析器",
"use_private_ptr_resolvers_desc": "使用这些上游服务器对本地服务的地址执行反向 DNS 查找。 如果禁用,则 AdGuard Home 会以 NXDOMAIN 响应所有此类 PTR 请求,从 DHCP、/etc/hosts 等获知的客户端除外。", "use_private_ptr_resolvers_desc": "使用这些上游服务器对本地服务的地址执行反向 DNS 查找。 如果禁用,则 AdGuard Home会以 NXDOMAIN 响应所有此类PTR请求从 DHCP、/ etc / hosts 等获知的客户端除外。",
"check_dhcp_servers": "检查 DHCP 服务器", "check_dhcp_servers": "检查 DHCP 服务器",
"save_config": "保存配置", "save_config": "保存配置",
"enabled_dhcp": "DHCP 服务器已启用", "enabled_dhcp": "DHCP 服务器已启用",
@@ -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 设置",
@@ -172,28 +172,28 @@
"list_url_table_header": "清单网址", "list_url_table_header": "清单网址",
"rules_count_table_header": "规则数", "rules_count_table_header": "规则数",
"last_time_updated_table_header": "上次更新时间", "last_time_updated_table_header": "上次更新时间",
"actions_table_header": "操作", "actions_table_header": "活跃状态",
"request_table_header": "请求", "request_table_header": "请求",
"edit_table_action": "编辑", "edit_table_action": "编辑",
"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.0AAAA记录::);被/etc/hosts 规则拦截时反应为规则中指定 IP 地址", "blocking_mode_default": "默认:被 Adblock 规则拦截时反应为零 IP 地址A记录0.0.0.0AAAA记录::);被/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.0AAAA 记录 ::", "blocking_mode_null_ip": "空IP以零IP地址响应(A记录 0.0.0.0AAAA记录 ::)",
"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": "点击查看查询",

View File

@@ -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/trackers.json', 'https://github.com/AdguardTeam/AdGuardHome/tree/master/client/src/helpers/trackers/adguard.json',
ISSUES: 'https://github.com/AdguardTeam/AdGuardHome/issues/new/choose', ISSUES: 'https://github.com/AdguardTeam/AdGuardHome/issues/new/choose',
}; };

View File

@@ -101,7 +101,7 @@ export default {
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_13.txt" "source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_13.txt"
}, },
"POL_polish_filters_for_pi_hole": { "POL_polish_filters_for_pi_hole": {
"name": "POL: Polish filters for Pi-hole", "name": "POL: Polish filters for Pi hole",
"categoryId": "regional", "categoryId": "regional",
"homepage": "https://www.certyficate.it/", "homepage": "https://www.certyficate.it/",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_14.txt" "source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_14.txt"
@@ -160,6 +160,12 @@ 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",

View File

@@ -0,0 +1,175 @@
{
"timeUpdated": "2021-12-15",
"categories": {
"0": "audio_video_player",
"1": "comments",
"2": "customer_interaction",
"3": "pornvertising",
"4": "advertising",
"5": "essential",
"6": "site_analytics",
"7": "social_media",
"8": "misc",
"9": "cdn",
"10": "hosting",
"11": "unknown",
"12": "extensions",
"13": "email",
"14": "consent",
"15": "telemetry",
"101": "mobile_analytics"
},
"trackers": {
"akamai_technologies": {
"name": "Akamai Technologies",
"categoryId": 9,
"url": "https://www.akamai.com/",
"companyId": "akamai"
},
"apple": {
"name": "Apple",
"categoryId": 8,
"url": "https://www.apple.com/",
"companyId": "apple"
},
"apple_ads": {
"name": "Apple Search Ads",
"categoryId": 4,
"url": "https://searchads.apple.com/",
"companyId": "apple"
},
"facebook_audience": {
"name": "Facebook Audience Network",
"categoryId": 4,
"url": "https://www.facebook.com/business/products/audience-network",
"companyId": "facebook"
},
"crashlytics": {
"name": "Crashlytics",
"categoryId": 101,
"url": "https://crashlytics.com/",
"companyId": null
},
"flurry": {
"name": "Flurry",
"categoryId": 101,
"url": "http://www.flurry.com/",
"companyId": "verizon"
},
"hockeyapp": {
"name": "HockeyApp",
"categoryId": 101,
"url": "https://hockeyapp.net/",
"companyId": null
},
"firebase": {
"name": "Firebase",
"categoryId": 101,
"url": "https://firebase.google.com/",
"companyId": "google"
},
"appsflyer": {
"name": "AppsFlyer",
"categoryId": 101,
"url": "https://www.appsflyer.com/",
"companyId": "appsflyer"
},
"yandex_appmetrica": {
"name": "Yandex AppMetrica",
"categoryId": 101,
"url": "https://appmetrica.yandex.com/",
"companyId": "yandex"
},
"adjust": {
"name": "Adjust",
"categoryId": 101,
"url": "https://www.adjust.com/",
"companyId": "adjust"
},
"branch": {
"name": "Branch.io",
"categoryId": 101,
"url": "https://branch.io/",
"companyId": "branch_metrics_inc"
},
"markmonitor": {
"name": "MarkMonitor",
"categoryId": 4,
"url": "https://www.markmonitor.com/",
"companyId": "markmonitor"
},
"appcenter": {
"name": "Microsoft App Center",
"categoryId": 5,
"url": "https://appcenter.ms/",
"companyId": null
},
"unity_ads": {
"name": "Unity Ads",
"categoryId": 4,
"url": "https://unity.com/solutions/mobile-business/monetize-your-game",
"companyId": null
},
"azure": {
"name": "Microsoft Azure",
"categoryId": 10,
"url": "https://azure.microsoft.com/",
"companyId": "microsoft"
},
"button": {
"name": "Button",
"categoryId": 4,
"url": "https://www.usebutton.com/",
"companyId": null
},
"netflix": {
"name": "Netflix",
"categoryId": 8,
"url": "https://www.netflix.com/",
"companyId": null
},
"mail.ru_banner": {
"name": "Mail.Ru Banner Network",
"categoryId": 4,
"url": "http://mail.ru/",
"companyId": "vk"
},
"mail.ru_counter": {
"name": "Mail.Ru Counter",
"categoryId": 2,
"url": "http://mail.ru/",
"companyId": "vk"
},
"mail.ru_group": {
"name": "Mail.Ru Group",
"categoryId": 7,
"url": "http://mail.ru/",
"companyId": "vk"
}
},
"trackerDomains": {
"akadns.net": "akamai_technologies",
"akamaiedge.net": "akamai_technologies",
"apple.com": "apple",
"apple.news": "apple",
"apple-dns.net": "apple",
"aaplimg.com": "apple",
"icloud.com": "apple",
"mzstatic.com": "apple",
"iadsdk.apple.com": "apple_ads",
"graph.facebook.com": "facebook_audience",
"crashlytics.com": "crashlytics",
"flurry.com": "flurry",
"hockeyapp.net": "hockeyapp",
"app-measurement.com": "firebase",
"appsflyer.com": "appsflyer",
"appmetrica.yandex.com": "yandex_appmetrica",
"adjust.com": "adjust",
"mobileapptracking.com": "branch",
"edgecastcdn.net": "markmonitor",
"appcenter.ms": "appcenter",
"unityads.unity3d.com": "unity_ads",
"azure.com": "azure",
"bttn.io": "button"
}
}

View File

@@ -1,5 +1,6 @@
import whotracksmeDb from './whotracksme.json';
import whotracksmeWebsites from './whotracksme_web.json'; import whotracksmeWebsites from './whotracksme_web.json';
import trackersDb from './trackers.json'; import adguardDb from './adguard.json';
import { REPOSITORY } from '../constants'; import { REPOSITORY } from '../constants';
/** /**
@@ -38,7 +39,6 @@ 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,26 +64,14 @@ export const getSourceData = (trackerData) => {
}; };
/** /**
* Converts the JSON string source into numeric source for AdGuard Home * Gets tracker data in the specified database
*
* @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
*/ */
export const getTrackerData = (domainName) => { const getTrackerDataFromDb = (domainName, trackersDb, source) => {
if (!domainName) { if (!domainName) {
return null; return null;
} }
@@ -100,7 +88,7 @@ export const getTrackerData = (domainName) => {
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];
const source = convertSource(trackerData.source); trackerData.source = source;
const sourceData = getSourceData(trackerData); const sourceData = getSourceData(trackerData);
return { return {
@@ -117,3 +105,22 @@ export const getTrackerData = (domainName) => {
// 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;
};

View File

@@ -1,5 +1,5 @@
{ {
"timeUpdated": "2023-02-21T12:46:33.324Z", "timeUpdated": "2022-10-15T00:14:03.765Z",
"categories": { "categories": {
"0": "audio_video_player", "0": "audio_video_player",
"1": "comments", "1": "comments",
@@ -16,8 +16,7 @@
"12": "extensions", "12": "extensions",
"13": "email", "13": "email",
"14": "consent", "14": "consent",
"15": "telemetry", "15": "telemetry"
"101": "mobile_analytics"
}, },
"trackers": { "trackers": {
"163": { "163": {
@@ -873,11 +872,10 @@
"companyId": "adgoto" "companyId": "adgoto"
}, },
"adguard": { "adguard": {
"name": "AdGuard", "name": "Adguard",
"categoryId": 8, "categoryId": 12,
"url": "https://adguard.com/", "url": "https://adguard.com/",
"companyId": "adguard", "companyId": null
"source": "AdGuard"
}, },
"adhands": { "adhands": {
"name": "AdHands", "name": "AdHands",
@@ -953,10 +951,9 @@
}, },
"adjust": { "adjust": {
"name": "Adjust", "name": "Adjust",
"categoryId": 101, "categoryId": 6,
"url": "https://www.adjust.com/", "url": "https://www.adjust.com/",
"companyId": "adjust", "companyId": "adjust"
"source": "AdGuard"
}, },
"adk2": { "adk2": {
"name": "adk2", "name": "adk2",
@@ -2144,8 +2141,7 @@
"name": "Akamai Technologies", "name": "Akamai Technologies",
"categoryId": 9, "categoryId": 9,
"url": "https://www.akamai.com/", "url": "https://www.akamai.com/",
"companyId": "akamai", "companyId": "akamai"
"source": "AdGuard"
}, },
"akamoihd.net": { "akamoihd.net": {
"name": "akamoihd.net", "name": "akamoihd.net",
@@ -2545,10 +2541,9 @@
}, },
"appsflyer": { "appsflyer": {
"name": "AppsFlyer", "name": "AppsFlyer",
"categoryId": 101, "categoryId": 6,
"url": "https://www.appsflyer.com/", "url": "https://www.appsflyer.com/",
"companyId": "appsflyer", "companyId": "appsflyer"
"source": "AdGuard"
}, },
"apptv": { "apptv": {
"name": "appTV", "name": "appTV",
@@ -6772,64 +6767,55 @@
"name": "Facebook", "name": "Facebook",
"categoryId": 4, "categoryId": 4,
"url": "https://www.facebook.com", "url": "https://www.facebook.com",
"companyId": "meta", "companyId": "facebook"
"source": "AdGuard"
}, },
"facebook_beacon": { "facebook_beacon": {
"name": "Facebook Beacon", "name": "Facebook Beacon",
"categoryId": 7, "categoryId": 7,
"url": "http://www.facebook.com/beacon/faq.php", "url": "http://www.facebook.com/beacon/faq.php",
"companyId": "meta", "companyId": "facebook"
"source": "AdGuard"
}, },
"facebook_cdn": { "facebook_cdn": {
"name": "Facebook CDN", "name": "Facebook CDN",
"categoryId": 9, "categoryId": 9,
"url": "https://www.facebook.com", "url": "https://www.facebook.com",
"companyId": "meta", "companyId": "facebook"
"source": "AdGuard"
}, },
"facebook_connect": { "facebook_connect": {
"name": "Facebook Connect", "name": "Facebook Connect",
"categoryId": 6, "categoryId": 6,
"url": "https://developers.facebook.com/connect.php", "url": "https://developers.facebook.com/connect.php",
"companyId": "meta", "companyId": "facebook"
"source": "AdGuard"
}, },
"facebook_conversion_tracking": { "facebook_conversion_tracking": {
"name": "Facebook Conversion Tracking", "name": "Facebook Conversion Tracking",
"categoryId": 4, "categoryId": 4,
"url": "http://www.facebook.com/", "url": "http://www.facebook.com/",
"companyId": "meta", "companyId": "facebook"
"source": "AdGuard"
}, },
"facebook_custom_audience": { "facebook_custom_audience": {
"name": "Facebook Custom Audience", "name": "Facebook Custom Audience",
"categoryId": 4, "categoryId": 4,
"url": "https://www.facebook.com", "url": "https://www.facebook.com",
"companyId": "meta", "companyId": "facebook"
"source": "AdGuard"
}, },
"facebook_graph": { "facebook_graph": {
"name": "Facebook Social Graph", "name": "Facebook Social Graph",
"categoryId": 7, "categoryId": 7,
"url": "https://developers.facebook.com/docs/reference/api/", "url": "https://developers.facebook.com/docs/reference/api/",
"companyId": "meta", "companyId": "facebook"
"source": "AdGuard"
}, },
"facebook_impressions": { "facebook_impressions": {
"name": "Facebook Impressions", "name": "Facebook Impressions",
"categoryId": 4, "categoryId": 4,
"url": "https://www.facebook.com/", "url": "https://www.facebook.com/",
"companyId": "meta", "companyId": "facebook"
"source": "AdGuard"
}, },
"facebook_social_plugins": { "facebook_social_plugins": {
"name": "Facebook Social Plugins", "name": "Facebook Social Plugins",
"categoryId": 7, "categoryId": 7,
"url": "https://developers.facebook.com/plugins", "url": "https://developers.facebook.com/plugins",
"companyId": "meta", "companyId": "facebook"
"source": "AdGuard"
}, },
"facetz.dca": { "facetz.dca": {
"name": "Facetz.DCA", "name": "Facetz.DCA",
@@ -7109,10 +7095,9 @@
}, },
"flurry": { "flurry": {
"name": "Flurry", "name": "Flurry",
"categoryId": 101, "categoryId": 6,
"url": "http://www.flurry.com/", "url": "http://www.flurry.com/",
"companyId": "verizon", "companyId": "verizon"
"source": "AdGuard"
}, },
"flxone": { "flxone": {
"name": "FLXONE", "name": "FLXONE",
@@ -8918,8 +8903,7 @@
"name": "Instagram", "name": "Instagram",
"categoryId": 8, "categoryId": 8,
"url": "https://www.facebook.com/", "url": "https://www.facebook.com/",
"companyId": "meta", "companyId": "facebook"
"source": "AdGuard"
}, },
"instant_check_mate": { "instant_check_mate": {
"name": "Instant Check Mate", "name": "Instant Check Mate",
@@ -10509,22 +10493,19 @@
"name": "Mail.Ru Banner Network", "name": "Mail.Ru Banner Network",
"categoryId": 4, "categoryId": 4,
"url": "http://mail.ru/", "url": "http://mail.ru/",
"companyId": "vk", "companyId": "megafon"
"source": "AdGuard"
}, },
"mail.ru_counter": { "mail.ru_counter": {
"name": "Mail.Ru Counter", "name": "Mail.Ru Counter",
"categoryId": 2, "categoryId": 2,
"url": "http://mail.ru/", "url": "https://corp.megafon.com/",
"companyId": "vk", "companyId": "megafon"
"source": "AdGuard"
}, },
"mail.ru_group": { "mail.ru_group": {
"name": "Mail.Ru Group", "name": "Mail.Ru Group",
"categoryId": 7, "categoryId": 7,
"url": "http://mail.ru/", "url": "http://mail.ru/",
"companyId": "vk", "companyId": "megafon"
"source": "AdGuard"
}, },
"mailchimp_tracking": { "mailchimp_tracking": {
"name": "MailChimp Tracking", "name": "MailChimp Tracking",
@@ -10650,8 +10631,7 @@
"name": "MarkMonitor", "name": "MarkMonitor",
"categoryId": 4, "categoryId": 4,
"url": "https://www.markmonitor.com/", "url": "https://www.markmonitor.com/",
"companyId": "markmonitor", "companyId": "markmonitor"
"source": "AdGuard"
}, },
"marktest": { "marktest": {
"name": "Marktest", "name": "Marktest",
@@ -11711,10 +11691,9 @@
}, },
"netflix": { "netflix": {
"name": "Netflix", "name": "Netflix",
"categoryId": 0, "categoryId": 8,
"url": "https://www.netflix.com/", "url": null,
"companyId": "netflix", "companyId": null
"source": "AdGuard"
}, },
"netletix": { "netletix": {
"name": "Netletix", "name": "Netletix",
@@ -17990,22 +17969,19 @@
"name": "Vk.com", "name": "Vk.com",
"categoryId": 7, "categoryId": 7,
"url": "https://vk.com/", "url": "https://vk.com/",
"companyId": "vk", "companyId": "megafon"
"source": "AdGuard"
}, },
"vkontakte": { "vkontakte": {
"name": "VKontakte", "name": "VKontakte",
"categoryId": 7, "categoryId": 7,
"url": "https://vk.com/", "url": "https://vk.com/",
"companyId": "vk", "companyId": "megafon"
"source": "AdGuard"
}, },
"vkontakte_widgets": { "vkontakte_widgets": {
"name": "VKontakte Widgets", "name": "VKontakte Widgets",
"categoryId": 7, "categoryId": 7,
"url": "https://dev.vk.com/", "url": "http://vk.com/developers.php",
"companyId": "vk", "companyId": "megafon"
"source": "AdGuard"
}, },
"vntsm.com": { "vntsm.com": {
"name": "Venatus Media", "name": "Venatus Media",
@@ -19224,237 +19200,6 @@
"categoryId": 4, "categoryId": 4,
"url": "http://www.zypmedia.com/", "url": "http://www.zypmedia.com/",
"companyId": "zypmedia" "companyId": "zypmedia"
},
"slack": {
"name": "Slack",
"categoryId": 8,
"url": "https://www.slack.com/",
"companyId": "salesforce",
"source": "AdGuard"
},
"apple": {
"name": "Apple",
"categoryId": 8,
"url": "https://www.apple.com/",
"companyId": "apple",
"source": "AdGuard"
},
"apple_ads": {
"name": "Apple Search Ads",
"categoryId": 4,
"url": "https://searchads.apple.com/",
"companyId": "apple",
"source": "AdGuard"
},
"facebook_audience": {
"name": "Facebook Audience Network",
"categoryId": 4,
"url": "https://www.facebook.com/business/products/audience-network",
"companyId": "meta",
"source": "AdGuard"
},
"crashlytics": {
"name": "Crashlytics",
"categoryId": 101,
"url": "https://crashlytics.com/",
"companyId": null,
"source": "AdGuard"
},
"showrss": {
"name": "showRSS",
"categoryId": 8,
"url": "https://showrss.info/",
"companyId": "showrss",
"source": "AdGuard"
},
"hockeyapp": {
"name": "HockeyApp",
"categoryId": 101,
"url": "https://hockeyapp.net/",
"companyId": null,
"source": "AdGuard"
},
"gmail": {
"name": "Gmail",
"categoryId": 13,
"url": "https://mail.google.com/",
"companyId": "google",
"source": "AdGuard"
},
"google_trust_services": {
"name": "Google Trust Services",
"categoryId": 5,
"url": "https://pki.goog/",
"companyId": "google",
"source": "AdGuard"
},
"firebase": {
"name": "Firebase",
"categoryId": 101,
"url": "https://firebase.google.com/",
"companyId": "google",
"source": "AdGuard"
},
"yandex_appmetrica": {
"name": "Yandex AppMetrica",
"categoryId": 101,
"url": "https://appmetrica.yandex.com/",
"companyId": "yandex",
"source": "AdGuard"
},
"branch": {
"name": "Branch.io",
"categoryId": 101,
"url": "https://branch.io/",
"companyId": "branch_metrics_inc",
"source": "AdGuard"
},
"telstra": {
"name": "Telstra",
"categoryId": 8,
"url": "https://www.telstra.com.au/",
"companyId": "telstra",
"source": "AdGuard"
},
"medialab": {
"name": "MediaLab.AI Inc.",
"categoryId": 8,
"url": "https://medialab.la/",
"companyId": "medialab",
"source": "AdGuard"
},
"qualcomm": {
"name": "Qualcomm",
"categoryId": 8,
"url": "https://www.qualcomm.com/",
"companyId": "qualcomm",
"source": "AdGuard"
},
"solaredge": {
"name": "SolarEdge Technologies, Inc.",
"categoryId": 8,
"url": "https://www.solaredge.com/",
"companyId": "solaredge",
"source": "AdGuard"
},
"sectigo": {
"name": "Sectigo Limited",
"categoryId": 5,
"url": "https://www.solaredge.com/",
"companyId": "sectigo",
"source": "AdGuard"
},
"element": {
"name": "Element",
"categoryId": 7,
"url": "https://element.io/",
"companyId": "element",
"source": "AdGuard"
},
"oztam": {
"name": "OzTAM",
"categoryId": 8,
"url": "https://oztam.com.au/",
"companyId": "oztam",
"source": "AdGuard"
},
"oppo": {
"name": "OPPO",
"categoryId": 101,
"url": "https://www.oppo.com/",
"companyId": "oppo",
"source": "AdGuard"
},
"outlook": {
"name": "Microsoft Outlook",
"categoryId": 13,
"url": "https://outlook.live.com/",
"companyId": "microsoft",
"source": "AdGuard"
},
"appcenter": {
"name": "Microsoft App Center",
"categoryId": 5,
"url": "https://appcenter.ms/",
"companyId": null,
"source": "AdGuard"
},
"unity_ads": {
"name": "Unity Ads",
"categoryId": 4,
"url": "https://unity.com/solutions/mobile-business/monetize-your-game",
"companyId": null,
"source": "AdGuard"
},
"azure": {
"name": "Microsoft Azure",
"categoryId": 10,
"url": "https://azure.microsoft.com/",
"companyId": "microsoft",
"source": "AdGuard"
},
"button": {
"name": "Button",
"categoryId": 4,
"url": "https://www.usebutton.com/",
"companyId": null,
"source": "AdGuard"
},
"lets_encrypt": {
"name": "Let's Encrypt",
"categoryId": 5,
"url": "https://letsencrypt.org/",
"companyId": "lets_encrypt",
"source": "AdGuard"
},
"kik": {
"name": "Kik",
"categoryId": 7,
"url": "https://kik.com/",
"companyId": "kik",
"source": "AdGuard"
},
"plex": {
"name": "Plex",
"categoryId": 0,
"url": "https://www.plex.tv/",
"companyId": "plex",
"source": "AdGuard"
},
"matrix": {
"name": "Matrix",
"categoryId": 5,
"url": "https://matrix.org/",
"companyId": "matrix",
"source": "AdGuard"
},
"ntppool": {
"name": "Network Time Protocol",
"categoryId": 5,
"url": "https://ntp.org/",
"companyId": "ntppool",
"source": "AdGuard"
},
"whatsapp": {
"name": "WhatsApp",
"categoryId": 8,
"url": "https://www.whatsapp.com/",
"companyId": "meta",
"source": "AdGuard"
},
"vscode": {
"name": "Visual Studio Code",
"categoryId": 8,
"url": "https://code.visualstudio.com/",
"companyId": "microsoft",
"source": "AdGuard"
},
"msedge": {
"name": "Microsoft Edge",
"categoryId": 8,
"url": "https://www.microsoft.com/en-us/edge",
"companyId": "microsoft",
"source": "AdGuard"
} }
}, },
"trackerDomains": { "trackerDomains": {
@@ -20995,7 +20740,7 @@
"facebook.net": "facebook", "facebook.net": "facebook",
"fbcdn.net": "facebook_cdn", "fbcdn.net": "facebook_cdn",
"fbsbx.com": "facebook_cdn", "fbsbx.com": "facebook_cdn",
"graph.facebook.com": "facebook_audience", "graph.facebook.com": "facebook_graph",
"facetz.net": "facetz.dca", "facetz.net": "facetz.dca",
"adsfac.eu": "facilitate_digital", "adsfac.eu": "facilitate_digital",
"adsfac.net": "facilitate_digital", "adsfac.net": "facilitate_digital",
@@ -21528,7 +21273,7 @@
"isocket.com": "isocket", "isocket.com": "isocket",
"ispot.tv": "ispot.tv", "ispot.tv": "ispot.tv",
"itineraire.info": "itineraire.info", "itineraire.info": "itineraire.info",
"apple.com": "apple", "apple.com": "itunes_link_maker",
"autolinkmaker.itunes.apple.com": "itunes_link_maker", "autolinkmaker.itunes.apple.com": "itunes_link_maker",
"ity.im": "ity.im", "ity.im": "ity.im",
"iubenda.com": "iubenda.com", "iubenda.com": "iubenda.com",
@@ -21982,7 +21727,7 @@
"azurewebsites.net": "microsoft", "azurewebsites.net": "microsoft",
"cloudapp.net": "microsoft", "cloudapp.net": "microsoft",
"gfx.ms": "microsoft", "gfx.ms": "microsoft",
"live.com": "outlook", "live.com": "microsoft",
"microsoft.com": "microsoft", "microsoft.com": "microsoft",
"microsoftonline-p.com": "microsoft", "microsoftonline-p.com": "microsoft",
"microsoftonline.com": "microsoft", "microsoftonline.com": "microsoft",
@@ -23784,107 +23529,6 @@
"zukxd6fkxqn.com": "zukxd6fkxqn.com", "zukxd6fkxqn.com": "zukxd6fkxqn.com",
"zwaar.net": "zwaar", "zwaar.net": "zwaar",
"zwaar.org": "zwaar", "zwaar.org": "zwaar",
"extend.tv": "zypmedia", "extend.tv": "zypmedia"
"whatsapp.net": "whatsapp",
"whatsapp.com": "whatsapp",
"telstra.com.au": "telstra",
"telstra.com": "telstra",
"slack.com": "slack",
"slackb.com": "slack",
"slack-edge.com": "slack",
"slack-imgs.com": "slack",
"addlive.io": "snap",
"feelinsonice.com": "snap",
"sc-cdn.net": "snap",
"sc-corp.net": "snap",
"sc-gw.com": "snap",
"sc-jpl.com": "snap",
"sc-prod.net": "snap",
"snap-dev.net": "snap",
"snapads.com": "snap",
"snapkit.com": "snap",
"adguard.app": "adguard",
"adguard.io": "adguard",
"adguard.org": "adguard",
"adguard-dns.com": "adguard",
"adguard-dns.io": "adguard",
"adguard-vpn.com": "adguard",
"adguardvpn.com": "adguard",
"adguard-vpn.online": "adguard",
"oppomobile.com": "oppo",
"heytapmobi.com": "oppo",
"heytapmobile.com": "oppo",
"heytapdl.com": "oppo",
"allawnos.com": "oppo",
"allawntech.com": "oppo",
"nflximg.com": "netflix",
"element.io": "element",
"riot.im": "element",
"gvt1.com": "google_servers",
"gvt2.com": "google_servers",
"gvt3.com": "google_servers",
"akadns.net": "akamai_technologies",
"akamaiedge.net": "akamai_technologies",
"akaquill.net": "akamai_technologies",
"me.com": "apple",
"apple.news": "apple",
"apple-dns.net": "apple",
"aaplimg.com": "apple",
"icloud.com": "apple",
"itunes.com": "apple",
"icloud-content.com": "apple",
"kik.com": "kik",
"apikik.com": "kik",
"kik-live.com": "kik",
"mzstatic.com": "apple",
"cdn-apple.com": "apple",
"apple-mapkit.com": "apple",
"icons.axm-usercontent-apple.com": "apple",
"apple-cloudkit.com": "apple",
"apzones.com": "apple",
"apple-livephotoskit.com": "apple",
"safebrowsing.apple": "apple",
"safebrowsing.g.applimg.com": "apple",
"matrix.org": "matrix",
"medialab.la": "medialab",
"media-lab.ai": "medialab",
"phicdn.net": "digicert_trust_seal",
"e-msedge.net": "msedge",
"l-msedge.net": "msedge",
"exp-tas.com": "vscode",
"vscode-unpkg.net": "vscode",
"v0cdn.net": "vscode",
"vscode-cdn.net": "vscode",
"iadsdk.apple.com": "apple_ads",
"showrss.info": "showrss",
"sectigo.com": "sectigo",
"solaredge.com": "solaredge",
"crashlytics.com": "crashlytics",
"cloudflare-dns.com": "cloudflare",
"flurry.com": "flurry",
"hockeyapp.net": "hockeyapp",
"app-measurement.com": "firebase",
"appmetrica.yandex.com": "yandex_appmetrica",
"letsencrypt.org": "lets_encrypt",
"lencr.org": "lets_encrypt",
"oztam.com.au": "oztam",
"mobileapptracking.com": "branch",
"ntp.org": "ntppool",
"ntppool.org": "ntppool",
"plex.tv": "plex",
"plex.direct": "plex",
"edgecastcdn.net": "markmonitor",
"appcenter.ms": "appcenter",
"unityads.unity3d.com": "unity_ads",
"usertrust.com": "trustlogo",
"azure.com": "azure",
"trafficmanager.net": "azure",
"hotmail.com": "outlook",
"outlook.com": "outlook",
"bttn.io": "button",
"pki.goog": "google_trust_services",
"xtracloud.net": "qualcomm",
"qualcomm.com": "qualcomm",
"gmail.com": "gmail"
} }
} }

41
go.mod
View File

@@ -1,11 +1,11 @@
module github.com/AdguardTeam/AdGuardHome module github.com/AdguardTeam/AdGuardHome
go 1.19 go 1.18
require ( require (
// TODO(a.garipov): Use v0.48.0 when it's released. // TODO(a.garipov): Return to a tagged version once DNS64 is in.
github.com/AdguardTeam/dnsproxy v0.48.0 github.com/AdguardTeam/dnsproxy v0.46.6-0.20230125113741-98cb8a899e49
github.com/AdguardTeam/golibs v0.12.0 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
github.com/ameshkov/dnscrypt/v2 v2.2.5 github.com/ameshkov/dnscrypt/v2 v2.2.5
@@ -19,26 +19,27 @@ 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.6.0 golang.org/x/crypto v0.5.0
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb golang.org/x/exp v0.0.0-20230131160201-f062dba9d201
golang.org/x/net v0.7.0 golang.org/x/net v0.5.0
golang.org/x/sys v0.5.0 golang.org/x/sys v0.4.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.0.0
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
@@ -47,22 +48,20 @@ 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-20230207041349-798e818bf904 // indirect github.com/google/pprof v0.0.0-20230131232505-5a9e8f65f08f // 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.3 // indirect github.com/onsi/ginkgo/v2 v2.8.0 // 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/quic-go/qpack v0.4.0 // indirect github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect golang.org/x/mod v0.7.0 // indirect
github.com/quic-go/qtls-go1-19 v0.2.1 // indirect
github.com/quic-go/qtls-go1-20 v0.1.1 // indirect
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // 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.7.0 // indirect golang.org/x/text v0.6.0 // indirect
golang.org/x/tools v0.6.0 // indirect golang.org/x/tools v0.5.0 // indirect
) )

77
go.sum
View File

@@ -1,12 +1,14 @@
github.com/AdguardTeam/dnsproxy v0.48.0 h1:sGViYy2pV0cEp2zCsxPjFd9rlgD0+yELpIeLkBxHAoI= github.com/AdguardTeam/dnsproxy v0.46.6-0.20230125113741-98cb8a899e49 h1:TDZsKB8BrKA2na6p5l20BvEu3MmgOWhIfTANz5laFuE=
github.com/AdguardTeam/dnsproxy v0.48.0/go.mod h1:9OHoeaVod+moWwrLjHF95RQnFWGi/6B1tfKsxWc/yGE= github.com/AdguardTeam/dnsproxy v0.46.6-0.20230125113741-98cb8a899e49/go.mod h1:ZEkTmTJ2XInT3aVy0mHtEnSWSclpHHj/9hfNXDuAk5k=
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.12.0 h1:z4Q3Mz0pHJ2Zag4B0RBaIXEUue1TPOKkbRiYkwC4r7I= github.com/AdguardTeam/golibs v0.11.4 h1:IltyvxwCTN+xxJF5sh6VadF8Zfbf8elgCm9dgijSVzM=
github.com/AdguardTeam/golibs v0.12.0/go.mod h1:87bN2x4VsTritptE3XZg9l8T6gznWsIxHBcQ1DeRIXA= github.com/AdguardTeam/golibs v0.11.4/go.mod h1:87bN2x4VsTritptE3XZg9l8T6gznWsIxHBcQ1DeRIXA=
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=
@@ -55,8 +57,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-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= github.com/google/pprof v0.0.0-20230131232505-5a9e8f65f08f h1:gl1DCiSk+mrXXBGPm6CEeS2MkJuMVzAOrXg34oVj1QI=
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= github.com/google/pprof v0.0.0-20230131232505-5a9e8f65f08f/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
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=
@@ -83,6 +85,14 @@ 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=
@@ -108,29 +118,16 @@ 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.3 h1:RpbK1G8nWPNaCVFBWsOGnEQQGgASi6b8fxcWBvDYjxQ= github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI=
github.com/onsi/ginkgo/v2 v2.8.3/go.mod h1:6OaUA8BCi0aZfmzYT/q9AacwTzDpNbxILUT+TlBq6MY= github.com/onsi/ginkgo/v2 v2.8.0/go.mod h1:6JsQiECmxCa3V5st74AL/AmsV482EDdVrGaVW6z3oYU=
github.com/onsi/gomega v1.27.0 h1:QLidEla4bXUuZVFa4KX6JHCsuGgbi85LC/pCHrt/O08= github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
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.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
github.com/quic-go/qtls-go1-20 v0.1.1/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=
@@ -154,24 +151,23 @@ 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-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA=
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/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.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w= golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 h1:BEABXpNXLEz0WxtA+6CQIz2xkg80e+1zrhWyMcq8VzE=
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/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.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.7.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=
@@ -188,8 +184,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.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
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=
@@ -222,24 +218,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.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.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.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.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.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
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=
@@ -248,11 +244,12 @@ 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.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
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=

View File

@@ -67,7 +67,7 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
} }
host := fields[0] host := fields[0]
err = netutil.ValidateHostname(host) err = netutil.ValidateDomainName(host)
if err != nil { if err != nil {
log.Debug("arpdb: parsing arp output: host: %s", err) log.Debug("arpdb: parsing arp output: host: %s", err)
} else { } else {

View File

@@ -198,7 +198,7 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) {
} }
host := fields[0] host := fields[0]
if verr := netutil.ValidateHostname(host); verr != nil { if verr := netutil.ValidateDomainName(host); verr != nil {
log.Debug("arpdb: parsing arp output: host: %s", verr) log.Debug("arpdb: parsing arp output: host: %s", verr)
} else { } else {
n.Name = host n.Name = host

View File

@@ -343,7 +343,7 @@ func (hp *hostsParser) parseLine(line string) (ip netip.Addr, hosts []string) {
// See https://github.com/AdguardTeam/AdGuardHome/issues/3946. // See https://github.com/AdguardTeam/AdGuardHome/issues/3946.
// //
// TODO(e.burkov): Investigate if hosts may contain DNS-SD domains. // TODO(e.burkov): Investigate if hosts may contain DNS-SD domains.
err = netutil.ValidateHostname(f) err = netutil.ValidateDomainName(f)
if err != nil { if err != nil {
log.Error("%s: host %q is invalid, ignoring", hostsContainerPref, f) log.Error("%s: host %q is invalid, ignoring", hostsContainerPref, f)

View File

@@ -80,6 +80,11 @@ func CanBindPrivilegedPorts() (can bool, err error) {
return canBindPrivilegedPorts() return canBindPrivilegedPorts()
} }
// AcquirePermissions tries to acquire permissions to bind to privileged ports.
func AcquirePermissions() (err error) {
return acquirePermissions()
}
// NetInterface represents an entry of network interfaces map. // NetInterface represents an entry of network interfaces map.
type NetInterface struct { type NetInterface struct {
// Addresses are the network interface addresses. // Addresses are the network interface addresses.

View File

@@ -7,3 +7,7 @@ import "github.com/AdguardTeam/AdGuardHome/internal/aghos"
func canBindPrivilegedPorts() (can bool, err error) { func canBindPrivilegedPorts() (can bool, err error) {
return aghos.HaveAdminRights() return aghos.HaveAdminRights()
} }
func acquirePermissions() (err error) {
return nil
}

View File

@@ -23,17 +23,17 @@ const dhcpcdConf = "etc/dhcpcd.conf"
func canBindPrivilegedPorts() (can bool, err error) { func canBindPrivilegedPorts() (can bool, err error) {
res, err := unix.PrctlRetInt( res, err := unix.PrctlRetInt(
unix.PR_CAP_AMBIENT, unix.PR_CAPBSET_READ,
unix.PR_CAP_AMBIENT_IS_SET,
unix.CAP_NET_BIND_SERVICE, unix.CAP_NET_BIND_SERVICE,
0, 0,
0, 0,
0,
) )
if err != nil { if err != nil {
if errors.Is(err, unix.EINVAL) { if errors.Is(err, unix.EINVAL) {
// Older versions of Linux kernel do not support this. Print a // Older versions of Linux kernel do not support this. Print a
// warning and check admin rights. // warning and check admin rights.
log.Info("warning: cannot check capability cap_net_bind_service: %s", err) log.Info("warning: cannot check cap_net_bind_service: %s", err)
} else { } else {
return false, err return false, err
} }
@@ -45,6 +45,21 @@ func canBindPrivilegedPorts() (can bool, err error) {
return res == 1 || adm, nil return res == 1 || adm, nil
} }
func acquirePermissions() (err error) {
_, err = unix.PrctlRetInt(
unix.PR_CAP_AMBIENT,
unix.PR_CAP_AMBIENT_RAISE,
unix.CAP_NET_BIND_SERVICE,
0,
0,
)
if err != nil {
return fmt.Errorf("raising cap_net_bind_service: %w", err)
}
return nil
}
// dhcpcdStaticConfig checks if interface is configured by /etc/dhcpcd.conf to // dhcpcdStaticConfig checks if interface is configured by /etc/dhcpcd.conf to
// have a static IP. // have a static IP.
func (n interfaceName) dhcpcdStaticConfig(r io.Reader) (subsources []string, cont bool, err error) { func (n interfaceName) dhcpcdStaticConfig(r io.Reader) (subsources []string, cont bool, err error) {

View File

@@ -43,3 +43,7 @@ func closePortChecker(c io.Closer) (err error) {
func isAddrInUse(err syscall.Errno) (ok bool) { func isAddrInUse(err syscall.Errno) (ok bool) {
return errors.Is(err, windows.WSAEADDRINUSE) return errors.Is(err, windows.WSAEADDRINUSE)
} }
func acquirePermissions() (err error) {
return nil
}

View File

@@ -108,7 +108,7 @@ func (s *v4Server) validHostnameForClient(cliHostname string, ip net.IP) (hostna
hostname = aghnet.GenerateHostname(ip) hostname = aghnet.GenerateHostname(ip)
} }
err = netutil.ValidateHostname(hostname) err = netutil.ValidateDomainName(hostname)
if err != nil { if err != nil {
log.Info("dhcpv4: %s", err) log.Info("dhcpv4: %s", err)
hostname = "" hostname = ""
@@ -372,7 +372,7 @@ func (s *v4Server) AddStaticLease(l *Lease) (err error) {
return err return err
} }
err = netutil.ValidateHostname(hostname) err = netutil.ValidateDomainName(hostname)
if err != nil { if err != nil {
return fmt.Errorf("validating hostname: %w", err) return fmt.Errorf("validating hostname: %w", err)
} }

View File

@@ -251,8 +251,8 @@ func TestV4Server_AddRemove_static(t *testing.T) {
}, },
name: "bad_hostname", name: "bad_hostname",
wantErrMsg: `dhcpv4: adding static lease: validating hostname: ` + wantErrMsg: `dhcpv4: adding static lease: validating hostname: ` +
`bad hostname "bad-lbl-.local": ` + `bad domain name "bad-lbl-.local": ` +
`bad hostname label "bad-lbl-": bad hostname label rune '-'`, `bad domain name label "bad-lbl-": bad domain name label rune '-'`,
}} }}
for _, tc := range testCases { for _, tc := range testCases {

View File

@@ -9,12 +9,12 @@ 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/quic-go/quic-go" "github.com/lucas-clemente/quic-go"
) )
// ValidateClientID returns an error if id is not a valid ClientID. // ValidateClientID returns an error if id is not a valid ClientID.
func ValidateClientID(id string) (err error) { func ValidateClientID(id string) (err error) {
err = netutil.ValidateHostnameLabel(id) err = netutil.ValidateDomainNameLabel(id)
if err != nil { if err != nil {
// Replace the domain name label wrapper with our own. // Replace the domain name label wrapper with our own.
return fmt.Errorf("invalid clientid %q: %w", id, errors.Unwrap(err)) return fmt.Errorf("invalid clientid %q: %w", id, errors.Unwrap(err))
@@ -147,16 +147,19 @@ func (s *Server) clientIDFromDNSContext(pctx *proxy.DNSContext) (clientID string
return clientID, nil return clientID, nil
} }
// clientServerName returns the TLS server name based on the protocol. For // clientServerName returns the TLS server name based on the protocol.
// DNS-over-HTTPS requests, it will return the hostname part of the Host header
// if there is one.
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
// 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 r := pctx.HTTPRequest
if connState := r.TLS; connState != nil { if r.ProtoAtLeast(3, 0) {
srvName = connState.ServerName
} else if r.Host != "" {
var host string var host string
host, err = netutil.SplitHost(r.Host) host, err = netutil.SplitHost(r.Host)
if err != nil { if err != nil {
@@ -164,6 +167,8 @@ func clientServerName(pctx *proxy.DNSContext, proto proxy.Proto) (srvName string
} }
srvName = host 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

View File

@@ -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/quic-go/quic-go" "github.com/lucas-clemente/quic-go"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -50,169 +50,160 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string
proto proxy.Proto proto proxy.Proto
confSrvName string hostSrvName string
cliSrvName string cliSrvName string
wantClientID string wantClientID string
wantErrMsg string wantErrMsg string
inclHTTPTLS bool
strictSNI bool strictSNI bool
useHTTP3 bool
}{{ }{{
name: "udp", name: "udp",
proto: proxy.ProtoUDP, proto: proxy.ProtoUDP,
confSrvName: "", hostSrvName: "",
cliSrvName: "", cliSrvName: "",
wantClientID: "", wantClientID: "",
wantErrMsg: "", wantErrMsg: "",
inclHTTPTLS: false,
strictSNI: false, strictSNI: false,
useHTTP3: false,
}, { }, {
name: "tls_no_clientid", name: "tls_no_clientid",
proto: proxy.ProtoTLS, proto: proxy.ProtoTLS,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "example.com", cliSrvName: "example.com",
wantClientID: "", wantClientID: "",
wantErrMsg: "", wantErrMsg: "",
inclHTTPTLS: false,
strictSNI: true, strictSNI: true,
useHTTP3: false,
}, { }, {
name: "tls_no_client_server_name", name: "tls_no_client_server_name",
proto: proxy.ProtoTLS, proto: proxy.ProtoTLS,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "", cliSrvName: "",
wantClientID: "", wantClientID: "",
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"`,
inclHTTPTLS: false, 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,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "", cliSrvName: "",
wantClientID: "", wantClientID: "",
wantErrMsg: "", wantErrMsg: "",
inclHTTPTLS: false,
strictSNI: false, strictSNI: false,
useHTTP3: false,
}, { }, {
name: "tls_clientid", name: "tls_clientid",
proto: proxy.ProtoTLS, proto: proxy.ProtoTLS,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "cli.example.com", cliSrvName: "cli.example.com",
wantClientID: "cli", wantClientID: "cli",
wantErrMsg: "", wantErrMsg: "",
inclHTTPTLS: false,
strictSNI: true, strictSNI: true,
useHTTP3: false,
}, { }, {
name: "tls_clientid_hostname_error", name: "tls_clientid_hostname_error",
proto: proxy.ProtoTLS, proto: proxy.ProtoTLS,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "cli.example.net", cliSrvName: "cli.example.net",
wantClientID: "", wantClientID: "",
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"`,
inclHTTPTLS: false, strictSNI: true,
strictSNI: true, useHTTP3: false,
}, { }, {
name: "tls_invalid_clientid", name: "tls_invalid_clientid",
proto: proxy.ProtoTLS, proto: proxy.ProtoTLS,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "!!!.example.com", cliSrvName: "!!!.example.com",
wantClientID: "", wantClientID: "",
wantErrMsg: `clientid check: invalid clientid "!!!": ` + wantErrMsg: `clientid check: invalid clientid "!!!": ` +
`bad hostname label rune '!'`, `bad domain name label rune '!'`,
inclHTTPTLS: false, strictSNI: true,
strictSNI: true, useHTTP3: false,
}, { }, {
name: "tls_clientid_too_long", name: "tls_clientid_too_long",
proto: proxy.ProtoTLS, proto: proxy.ProtoTLS,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: `abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmno` + cliSrvName: `abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmno` +
`pqrstuvwxyz0123456789.example.com`, `pqrstuvwxyz0123456789.example.com`,
wantClientID: "", wantClientID: "",
wantErrMsg: `clientid check: invalid clientid "abcdefghijklmno` + wantErrMsg: `clientid check: invalid clientid "abcdefghijklmno` +
`pqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789": ` + `pqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789": ` +
`hostname label is too long: got 72, max 63`, `domain name label is too long: got 72, max 63`,
inclHTTPTLS: false, strictSNI: true,
strictSNI: true, useHTTP3: false,
}, { }, {
name: "quic_clientid", name: "quic_clientid",
proto: proxy.ProtoQUIC, proto: proxy.ProtoQUIC,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "cli.example.com", cliSrvName: "cli.example.com",
wantClientID: "cli", wantClientID: "cli",
wantErrMsg: "", wantErrMsg: "",
inclHTTPTLS: false,
strictSNI: true, strictSNI: true,
useHTTP3: false,
}, { }, {
name: "tls_clientid_issue3437", name: "tls_clientid_issue3437",
proto: proxy.ProtoTLS, proto: proxy.ProtoTLS,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "cli.myexample.com", cliSrvName: "cli.myexample.com",
wantClientID: "", wantClientID: "",
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"`,
inclHTTPTLS: false, strictSNI: true,
strictSNI: true, useHTTP3: false,
}, { }, {
name: "tls_case", name: "tls_case",
proto: proxy.ProtoTLS, proto: proxy.ProtoTLS,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "InSeNsItIvE.example.com", cliSrvName: "InSeNsItIvE.example.com",
wantClientID: "insensitive", wantClientID: "insensitive",
wantErrMsg: ``, wantErrMsg: ``,
inclHTTPTLS: false,
strictSNI: true, strictSNI: true,
useHTTP3: false,
}, { }, {
name: "quic_case", name: "quic_case",
proto: proxy.ProtoQUIC, proto: proxy.ProtoQUIC,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "InSeNsItIvE.example.com", cliSrvName: "InSeNsItIvE.example.com",
wantClientID: "insensitive", wantClientID: "insensitive",
wantErrMsg: ``, wantErrMsg: ``,
inclHTTPTLS: false,
strictSNI: true, strictSNI: true,
useHTTP3: false,
}, { }, {
name: "https_no_clientid", name: "https_no_clientid",
proto: proxy.ProtoHTTPS, proto: proxy.ProtoHTTPS,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "example.com", cliSrvName: "example.com",
wantClientID: "", wantClientID: "",
wantErrMsg: "", wantErrMsg: "",
inclHTTPTLS: true,
strictSNI: true, strictSNI: true,
useHTTP3: false,
}, { }, {
name: "https_clientid", name: "https_clientid",
proto: proxy.ProtoHTTPS, proto: proxy.ProtoHTTPS,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "cli.example.com", cliSrvName: "cli.example.com",
wantClientID: "cli", wantClientID: "cli",
wantErrMsg: "", wantErrMsg: "",
inclHTTPTLS: true,
strictSNI: true, strictSNI: true,
useHTTP3: false,
}, { }, {
name: "https_issue5518", name: "https_clientid_quic",
proto: proxy.ProtoHTTPS, proto: proxy.ProtoHTTPS,
confSrvName: "example.com", hostSrvName: "example.com",
cliSrvName: "cli.example.com", cliSrvName: "cli.example.com",
wantClientID: "cli", wantClientID: "cli",
wantErrMsg: "", wantErrMsg: "",
inclHTTPTLS: false,
strictSNI: true,
}, {
name: "https_no_host",
proto: proxy.ProtoHTTPS,
confSrvName: "example.com",
cliSrvName: "example.com",
wantClientID: "",
wantErrMsg: "",
inclHTTPTLS: false,
strictSNI: true, strictSNI: true,
useHTTP3: true,
}} }}
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
tlsConf := TLSConfig{ tlsConf := TLSConfig{
ServerName: tc.confSrvName, ServerName: tc.hostSrvName,
StrictSNICheck: tc.strictSNI, StrictSNICheck: tc.strictSNI,
} }
@@ -228,7 +219,7 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
switch tc.proto { switch tc.proto {
case proxy.ProtoHTTPS: case proxy.ProtoHTTPS:
httpReq = newHTTPReq(tc.cliSrvName, tc.inclHTTPTLS) httpReq = newHTTPReq(tc.cliSrvName, tc.useHTTP3)
case proxy.ProtoQUIC: case proxy.ProtoQUIC:
qconn = testQUICConnection{ qconn = testQUICConnection{
serverName: tc.cliSrvName, serverName: tc.cliSrvName,
@@ -255,25 +246,30 @@ 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, inclTLS bool) (r *http.Request) { func newHTTPReq(cliSrvName string, useHTTP3 bool) (r *http.Request) {
u := &url.URL{ u := &url.URL{
Path: "/dns-query", Path: "/dns-query",
} }
r = &http.Request{ if useHTTP3 {
return &http.Request{
ProtoMajor: 3,
ProtoMinor: 0,
URL: u,
Host: cliSrvName,
TLS: &tls.ConnectionState{},
}
}
return &http.Request{
ProtoMajor: 1, ProtoMajor: 1,
ProtoMinor: 1, ProtoMinor: 1,
URL: u, URL: u,
Host: cliSrvName, Host: cliSrvName,
} TLS: &tls.ConnectionState{
if inclTLS {
r.TLS = &tls.ConnectionState{
ServerName: cliSrvName, ServerName: cliSrvName,
} },
} }
return r
} }
func TestClientIDFromDNSContextHTTPS(t *testing.T) { func TestClientIDFromDNSContextHTTPS(t *testing.T) {
@@ -330,7 +326,7 @@ func TestClientIDFromDNSContextHTTPS(t *testing.T) {
path: "/dns-query/!!!", path: "/dns-query/!!!",
cliSrvName: "example.com", cliSrvName: "example.com",
wantClientID: "", wantClientID: "",
wantErrMsg: `clientid check: invalid clientid "!!!": bad hostname label rune '!'`, wantErrMsg: `clientid check: invalid clientid "!!!": bad domain name label rune '!'`,
}, { }, {
name: "both_ids", name: "both_ids",
path: "/dns-query/right", path: "/dns-query/right",

View File

@@ -5,8 +5,8 @@ import (
"crypto/x509" "crypto/x509"
"fmt" "fmt"
"net" "net"
"net/netip"
"os" "os"
"sort"
"strings" "strings"
"time" "time"
@@ -22,7 +22,6 @@ import (
"github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/golibs/timeutil" "github.com/AdguardTeam/golibs/timeutil"
"github.com/ameshkov/dnscrypt/v2" "github.com/ameshkov/dnscrypt/v2"
"golang.org/x/exp/slices"
) )
// BlockingMode is an enum of all allowed blocking modes. // BlockingMode is an enum of all allowed blocking modes.
@@ -226,7 +225,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 []netip.Prefix DNS64Prefixes []string
// ResolveClients signals if the RDNS should resolve clients' addresses. // ResolveClients signals if the RDNS should resolve clients' addresses.
ResolveClients bool ResolveClients bool
@@ -272,8 +271,6 @@ 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 {
@@ -510,7 +507,7 @@ func (s *Server) prepareTLS(proxyConfig *proxy.Config) (err error) {
if len(cert.DNSNames) != 0 { if len(cert.DNSNames) != 0 {
s.conf.dnsNames = cert.DNSNames s.conf.dnsNames = cert.DNSNames
log.Debug("dnsforward: using certificate's SAN as DNS names: %v", cert.DNSNames) log.Debug("dnsforward: using certificate's SAN as DNS names: %v", cert.DNSNames)
slices.Sort(s.conf.dnsNames) sort.Strings(s.conf.dnsNames)
} else { } else {
s.conf.dnsNames = append(s.conf.dnsNames, cert.Subject.CommonName) s.conf.dnsNames = append(s.conf.dnsNames, cert.Subject.CommonName)
log.Debug("dnsforward: using certificate's CN as DNS name: %s", cert.Subject.CommonName) log.Debug("dnsforward: using certificate's CN as DNS name: %s", cert.Subject.CommonName)
@@ -526,6 +523,16 @@ func (s *Server) prepareTLS(proxyConfig *proxy.Config) (err error) {
return nil return nil
} }
// isInSorted returns true if s is in the sorted slice strs.
func isInSorted(strs []string, s string) (ok bool) {
i := sort.SearchStrings(strs, s)
if i == len(strs) || strs[i] != s {
return false
}
return true
}
// isWildcard returns true if host is a wildcard hostname. // isWildcard returns true if host is a wildcard hostname.
func isWildcard(host string) (ok bool) { func isWildcard(host string) (ok bool) {
return len(host) >= 2 && host[0] == '*' && host[1] == '.' return len(host) >= 2 && host[0] == '*' && host[1] == '.'
@@ -540,12 +547,11 @@ func matchesDomainWildcard(host, pat string) (ok bool) {
// anyNameMatches returns true if sni, the client's SNI value, matches any of // anyNameMatches returns true if sni, the client's SNI value, matches any of
// the DNS names and patterns from certificate. dnsNames must be sorted. // the DNS names and patterns from certificate. dnsNames must be sorted.
func anyNameMatches(dnsNames []string, sni string) (ok bool) { func anyNameMatches(dnsNames []string, sni string) (ok bool) {
// Check sni is either a valid hostname or a valid IP address. if netutil.ValidateDomainName(sni) != nil {
if netutil.ValidateHostname(sni) != nil && net.ParseIP(sni) == nil {
return false return false
} }
if _, ok = slices.BinarySearch(dnsNames, sni); ok { if isInSorted(dnsNames, sni) {
return true return true
} }

View File

@@ -1,15 +1,15 @@
package dnsforward package dnsforward
import ( import (
"sort"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.org/x/exp/slices"
) )
func TestAnyNameMatches(t *testing.T) { func TestAnyNameMatches(t *testing.T) {
dnsNames := []string{"host1", "*.host2", "1.2.3.4"} dnsNames := []string{"host1", "*.host2", "1.2.3.4"}
slices.Sort(dnsNames) sort.Strings(dnsNames)
testCases := []struct { testCases := []struct {
name string name string
@@ -31,10 +31,6 @@ func TestAnyNameMatches(t *testing.T) {
name: "match", name: "match",
dnsName: "1.2.3.4", dnsName: "1.2.3.4",
want: true, want: true,
}, {
name: "mismatch_bad_ip",
dnsName: "1.2.3.256",
want: false,
}, { }, {
name: "mismatch", name: "mismatch",
dnsName: "host2", dnsName: "host2",

View File

@@ -10,8 +10,6 @@ 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"
@@ -19,9 +17,6 @@ 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
@@ -230,7 +225,7 @@ func (s *Server) onDHCPLeaseChanged(flags int) {
for _, l := range ll { for _, l := range ll {
// TODO(a.garipov): Remove this after we're finished with the client // TODO(a.garipov): Remove this after we're finished with the client
// hostname validations in the DHCP server code. // hostname validations in the DHCP server code.
err := netutil.ValidateHostname(l.Hostname) err := netutil.ValidateDomainName(l.Hostname)
if err != nil { if err != nil {
log.Debug("dnsforward: skipping invalid hostname %q from dhcp: %s", l.Hostname, err) log.Debug("dnsforward: skipping invalid hostname %q from dhcp: %s", l.Hostname, err)
@@ -424,7 +419,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 s.dns64Pref != (netip.Prefix{}) { if len(s.dns64Prefs) > 0 {
// 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,11 +463,20 @@ func (s *Server) processRestrictLocal(dctx *dnsContext) (rc resultCode) {
return resultCodeError return resultCodeError
} }
log.Debug("dnsforward: request is not for arpa domain") log.Debug("dnsforward: request is for a service domain")
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.
@@ -651,7 +655,13 @@ func (s *Server) processUpstream(dctx *dnsContext) (rc resultCode) {
s.setCustomUpstream(pctx, dctx.clientID) s.setCustomUpstream(pctx, dctx.clientID)
reqWantsDNSSEC := s.setReqAD(req) origReqAD := false
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()
@@ -661,73 +671,23 @@ func (s *Server) processUpstream(dctx *dnsContext) (rc resultCode) {
return resultCodeError return resultCodeError
} }
if err := prx.Resolve(pctx); err != nil { if dctx.err = prx.Resolve(pctx); dctx.err != nil {
if errors.Is(err, upstream.ErrNoUpstreams) { return resultCodeError
// 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
}
dctx.err = err
if s.performDNS64(prx, dctx) == resultCodeError {
return resultCodeError return resultCodeError
} }
dctx.responseFromUpstream = true dctx.responseFromUpstream = true
dctx.responseAD = pctx.Res.AuthenticatedData dctx.responseAD = pctx.Res.AuthenticatedData
s.setRespAD(pctx, reqWantsDNSSEC) if s.conf.EnableDNSSEC && !origReqAD {
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

View File

@@ -1,10 +1,34 @@
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
@@ -14,22 +38,227 @@ import (
// 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() { func (s *Server) setupDNS64() (err error) {
if !s.conf.UseDNS64 { if !s.conf.UseDNS64 {
return return nil
} }
if len(s.conf.DNS64Prefixes) == 0 { l := len(s.conf.DNS64Prefixes)
// dns64WellKnownPref is the default prefix to use in an algorithmic if l == 0 {
// mapping for DNS64. s.dns64Prefs = []netip.Prefix{dns64WellKnownPref}
//
// See https://datatracker.ietf.org/doc/html/rfc6052#section-2.1.
dns64WellKnownPref := netip.MustParsePrefix("64:ff9b::/96")
s.dns64Pref = dns64WellKnownPref return nil
} else {
s.dns64Pref = s.conf.DNS64Prefixes[0]
} }
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.
func (s *Server) checkDNS64(req, resp *dns.Msg) (dns64Req *dns.Msg) {
if len(s.dns64Prefs) == 0 {
return nil
}
q := req.Question[0]
if q.Qtype != dns.TypeAAAA || q.Qclass != dns.ClassINET {
// DNS64 operation for classes other than IN is undefined, and a DNS64
// 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
@@ -38,12 +267,79 @@ func (s *Server) setupDNS64() {
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.dns64Pref.Masked().Addr().As16() pref := s.dns64Prefs[0].Addr().As16()
ipData := ip.As4() ipData := ip.As4()
mapped = make(net.IP, net.IPv6len) mapped = make(net.IP, net.IPv6len)
copy(mapped[:proxy.NAT64PrefixLength], pref[:]) copy(mapped[:nat64PrefixLen], pref[:])
copy(mapped[proxy.NAT64PrefixLength:], ipData[:]) copy(mapped[nat64PrefixLen:], 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
}

View File

@@ -15,16 +15,6 @@ 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.
@@ -273,22 +263,18 @@ func TestServer_HandleDNSRequest_dns64(t *testing.T) {
return resp, nil return resp, nil
}) })
s := createTestServer(t, &filtering.Config{}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
UseDNS64: true,
}, localUps)
client := &dns.Client{ client := &dns.Client{
Net: "tcp", Net: "tcp",
Timeout: 1 * time.Second, Timeout: 1 * time.Second,
} }
for _, tc := range testCases { for _, tc := range testCases {
// TODO(e.burkov): It seems [proxy.Proxy] isn't intended to be reused
// right after stop, due to a data race in [proxy.Proxy.Init] method
// when setting an OOB size. As a temporary workaround, recreate the
// whole server for each test case.
s := createTestServer(t, &filtering.Config{}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}},
UseDNS64: true,
}, localUps)
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newUps(tc.upsAns)} s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newUps(tc.upsAns)}
startDeferStop(t, s) startDeferStop(t, s)

View File

@@ -80,17 +80,10 @@ type Server struct {
privateNets netutil.SubnetSet privateNets netutil.SubnetSet
localResolvers *proxy.Proxy localResolvers *proxy.Proxy
sysResolvers aghnet.SystemResolvers sysResolvers aghnet.SystemResolvers
recDetector *recursionDetector
// recDetector is a cache for recursive requests. It is used to detect // dns64Prefix is the set of NAT64 prefixes used for DNS64 handling.
// and prevent recursive requests only for private upstreams. dns64Prefs []netip.Prefix
//
// See https://github.com/adguardTeam/adGuardHome/issues/3185#issuecomment-851048135.
recDetector *recursionDetector
// dns64Pref is the NAT64 prefix used for DNS64 response mapping. The major
// part of DNS64 happens inside the [proxy] package, but there still are
// some places where response mapping is needed (e.g. DHCP).
dns64Pref netip.Prefix
// anonymizer masks the client's IP addresses if needed. // anonymizer masks the client's IP addresses if needed.
anonymizer *aghnet.IPMut anonymizer *aghnet.IPMut
@@ -253,8 +246,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, i.e. either as local // Exchange tries to resolve the ip in a suitable way, e.g. either as
// or as external. // local 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
@@ -263,13 +256,13 @@ type RDNSExchanger interface {
} }
const ( const (
// ErrRDNSNoData is returned by [RDNSExchanger.Exchange] when the answer // rDNSEmptyAnswerErr is returned by Exchange method when the answer
// section of response is either NODATA or has no PTR records. // section of respond is empty.
ErrRDNSNoData errors.Error = "no ptr data in response" rDNSEmptyAnswerErr errors.Error = "the answer section is empty"
// ErrRDNSFailed is returned by [RDNSExchanger.Exchange] if the received // rDNSNotPTRErr is returned by Exchange method when the response is not
// response is not a NOERROR or NXDOMAIN. // of PTR type.
ErrRDNSFailed errors.Error = "failed to resolve ptr" rDNSNotPTRErr errors.Error = "the response is not a ptr"
) )
// type check // type check
@@ -324,24 +317,17 @@ 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 resp.Rcode != dns.RcodeSuccess && resp.Rcode != dns.RcodeNameError { if len(resp.Answer) == 0 {
return "", fmt.Errorf( return "", fmt.Errorf("lookup for %q: %w", arpa, rDNSEmptyAnswerErr)
"received %s response: %w",
dns.RcodeToString[resp.Rcode],
ErrRDNSFailed,
)
} }
for _, ans := range resp.Answer { ptr, ok := resp.Answer[0].(*dns.PTR)
ptr, ok := ans.(*dns.PTR) if !ok {
if ok { return "", fmt.Errorf("type checking: %w", rDNSNotPTRErr)
return strings.TrimSuffix(ptr.Ptr, "."), nil
}
} }
return "", ErrRDNSNoData return strings.TrimSuffix(ptr.Ptr, "."), nil
} }
// ResolvesPrivatePTR implements the RDNSExchanger interface for *Server. // ResolvesPrivatePTR implements the RDNSExchanger interface for *Server.
@@ -491,8 +477,6 @@ 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)
@@ -509,18 +493,18 @@ func (s *Server) Prepare(conf *ServerConfig) (err error) {
s.registerHandlers() s.registerHandlers()
// TODO(e.burkov): Remove once the local resolvers logic moved to dnsproxy. err = s.setupDNS64()
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

View File

@@ -89,14 +89,9 @@ 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 {
ups := []upstream.Upstream{localUps} s.localResolvers.UpstreamConfig.Upstreams = []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
@@ -1171,8 +1166,7 @@ func TestNewServer(t *testing.T) {
LocalDomain: "!!!", LocalDomain: "!!!",
}, },
wantErrMsg: `local domain: bad domain name "!!!": ` + wantErrMsg: `local domain: bad domain name "!!!": ` +
`bad top-level domain name label "!!!": ` + `bad domain name label "!!!": bad domain name label rune '!'`,
`bad top-level domain name label rune '!'`,
}} }}
for _, tc := range testCases { for _, tc := range testCases {
@@ -1222,9 +1216,6 @@ 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),
@@ -1269,21 +1260,15 @@ func TestServer_Exchange(t *testing.T) {
}, { }, {
name: "empty_answer_error", name: "empty_answer_error",
want: "", want: "",
wantErr: ErrRDNSNoData, wantErr: rDNSEmptyAnswerErr,
locUpstream: locUpstream, locUpstream: locUpstream,
req: net.IP{192, 168, 1, 2}, req: net.IP{192, 168, 1, 2},
}, { }, {
name: "invalid_answer", name: "not_ptr_error",
want: "", want: "",
wantErr: ErrRDNSNoData, wantErr: rDNSNotPTRErr,
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 {

View File

@@ -337,8 +337,7 @@ func TestValidateUpstreams(t *testing.T) {
}, { }, {
name: "bad_domain", name: "bad_domain",
wantErr: `bad upstream for domain "[/!/]8.8.8.8": domain at index 0: ` + wantErr: `bad upstream for domain "[/!/]8.8.8.8": domain at index 0: ` +
`bad domain name "!": bad top-level domain name label "!": ` + `bad domain name "!": bad domain name label "!": bad domain name label rune '!'`,
`bad top-level domain name label rune '!'`,
set: []string{"[/!/]8.8.8.8"}, set: []string{"[/!/]8.8.8.8"},
}} }}

View File

@@ -22,11 +22,9 @@ 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 q.Qtype == dns.TypeANY && s.conf.RefuseAny { if len(msg.Question) >= 1 && msg.Question[0].Qtype == dns.TypeANY && s.conf.RefuseAny {
shouldLog = false shouldLog = false
} }
@@ -43,20 +41,11 @@ 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 && if shouldLog && s.queryLog != nil {
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 && s.stats.ShouldCount(host, q.Qtype, q.Qclass) { if s.stats != nil {
s.updateStats(dctx, elapsed, *dctx.result, ip) s.updateStats(dctx, elapsed, *dctx.result, ip)
} }

View File

@@ -16,44 +16,34 @@ 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
} }
// ShouldLog implements the [querylog.QueryLog] interface for *testQueryLog. // testStats is a simple stats.Stats implementation for tests.
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.Interface] // Stats is embedded here simply to make testStats a stats.Stats without
// without actually implementing all methods. // actually implementing all methods.
stats.Interface stats.Interface
lastEntry stats.Entry lastEntry stats.Entry
} }
// Update implements the [stats.Interface] interface for *testStats. // Update implements the stats.Stats 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

View File

@@ -0,0 +1,38 @@
//go:build ignore
// +build ignore
package filtering
import (
"fmt"
"sort"
"testing"
)
// This is a simple tool that takes a list of services and prints them to the output.
// It is supposed to be used to update:
// client/src/helpers/constants.js
// client/src/components/ui/Icons.js
//
// Usage:
// 1. go run ./internal/filtering/blocked_test.go
// 2. Use the output to replace `SERVICES` array in "client/src/helpers/constants.js".
// 3. You'll need to enter services names manually.
// 4. Don't forget to add missing icons to "client/src/components/ui/Icons.js".
//
// TODO(ameshkov): Rework generator: have a JSON file with all the metadata we need
// then use this JSON file to generate JS and Go code
func TestGenServicesArray(t *testing.T) {
services := make([]svc, len(serviceRulesArray))
copy(services, serviceRulesArray)
sort.Slice(services, func(i, j int) bool {
return services[i].name < services[j].name
})
fmt.Println("export const SERVICES = [")
for _, s := range services {
fmt.Printf(" {\n id: '%s',\n name: '%s',\n },\n", s.name, s.name)
}
fmt.Println("];")
}

View File

@@ -1,8 +1,11 @@
// DNS Rewrites
package filtering package filtering
import ( import (
"fmt" "fmt"
"net" "net"
"sort"
"strings" "strings"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
@@ -11,8 +14,6 @@ import (
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
// Legacy DNS rewrites
// LegacyRewrite is a single legacy DNS rewrite record. // LegacyRewrite is a single legacy DNS rewrite record.
// //
// Instances of *LegacyRewrite must never be nil. // Instances of *LegacyRewrite must never be nil.
@@ -122,24 +123,38 @@ func matchDomainWildcard(host, wildcard string) (ok bool) {
return isWildcard(wildcard) && strings.HasSuffix(host, wildcard[1:]) return isWildcard(wildcard) && strings.HasSuffix(host, wildcard[1:])
} }
// legacyRewriteSortsBefore sorts rewirtes according to the following priority: // rewritesSorted is a slice of legacy rewrites for sorting.
// //
// 1. A and AAAA > CNAME; // The sorting priority:
// 2. wildcard > exact; //
// 3. lower level wildcard > higher level wildcard; // 1. A and AAAA > CNAME
func legacyRewriteSortsBefore(a, b *LegacyRewrite) (sortsBefore bool) { // 2. wildcard > exact
if a.Type == dns.TypeCNAME && b.Type != dns.TypeCNAME { // 3. lower level wildcard > higher level wildcard
//
// TODO(a.garipov): Replace with slices.Sort.
type rewritesSorted []*LegacyRewrite
// Len implements the sort.Interface interface for rewritesSorted.
func (a rewritesSorted) Len() (l int) { return len(a) }
// Swap implements the sort.Interface interface for rewritesSorted.
func (a rewritesSorted) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
// Less implements the sort.Interface interface for rewritesSorted.
func (a rewritesSorted) Less(i, j int) (less bool) {
ith, jth := a[i], a[j]
if ith.Type == dns.TypeCNAME && jth.Type != dns.TypeCNAME {
return true return true
} else if a.Type != dns.TypeCNAME && b.Type == dns.TypeCNAME { } else if ith.Type != dns.TypeCNAME && jth.Type == dns.TypeCNAME {
return false return false
} }
if aIsWld, bIsWld := isWildcard(a.Domain), isWildcard(b.Domain); aIsWld != bIsWld { if iw, jw := isWildcard(ith.Domain), isWildcard(jth.Domain); iw != jw {
return bIsWld return jw
} }
// Both are either wildcards or both aren't. // Both are either wildcards or not.
return len(a.Domain) > len(b.Domain) return len(ith.Domain) > len(jth.Domain)
} }
// prepareRewrites normalizes and validates all legacy DNS rewrites. // prepareRewrites normalizes and validates all legacy DNS rewrites.
@@ -181,7 +196,7 @@ func findRewrites(
return nil, matched return nil, matched
} }
slices.SortFunc(rewrites, legacyRewriteSortsBefore) sort.Sort(rewritesSorted(rewrites))
for i, r := range rewrites { for i, r := range rewrites {
if isWildcard(r.Domain) { if isWildcard(r.Domain) {

View File

@@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
"sort"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -18,7 +19,6 @@ import (
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/golibs/stringutil"
"github.com/miekg/dns" "github.com/miekg/dns"
"golang.org/x/exp/slices"
"golang.org/x/net/publicsuffix" "golang.org/x/net/publicsuffix"
) )
@@ -241,8 +241,8 @@ func (c *sbCtx) processTXT(resp *dns.Msg) (bool, [][]byte) {
} }
func (c *sbCtx) storeCache(hashes [][]byte) { func (c *sbCtx) storeCache(hashes [][]byte) {
slices.SortFunc(hashes, func(a, b []byte) (sortsBefore bool) { sort.Slice(hashes, func(a, b int) bool {
return bytes.Compare(a, b) == -1 return bytes.Compare(hashes[a], hashes[b]) == -1
}) })
var curData []byte var curData []byte

View File

@@ -1171,16 +1171,6 @@ var blockedServices = []blockedService{{
"||zuckerberg.com^", "||zuckerberg.com^",
"||zuckerberg.net^", "||zuckerberg.net^",
}, },
}, {
ID: "gog",
Name: "GOG",
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 34 34\"><path d=\"M31 31H3a3 3 0 0 1-3-3V3A3 3 0 0 1 3 0H31a3 3 0 0 1 3 3V28A3 3 0 0 1 31 31ZM4 24.5A1.5 1.5 0 0 0 5.5 26H11V24H6.5a.5.5 0 0 1-.5-.5v-3a.5.5 0 0 1 .5-.5H11V18H5.5A1.5 1.5 0 0 0 4 19.5Zm8-18A1.5 1.5 0 0 0 10.5 5h-5A1.5 1.5 0 0 0 4 6.5v5A1.5 1.5 0 0 0 5.5 13H9V11H6.5a.5.5 0 0 1-.5-.5v-3A.5.5 0 0 1 6.5 7h3a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H4v2h6.5A1.5 1.5 0 0 0 12 14.5Zm0 13v5A1.5 1.5 0 0 0 13.5 26h5A1.5 1.5 0 0 0 20 24.5v-5A1.5 1.5 0 0 0 18.5 18h-5A1.5 1.5 0 0 0 12 19.5Zm9-13A1.5 1.5 0 0 0 19.5 5h-5A1.5 1.5 0 0 0 13 6.5v5A1.5 1.5 0 0 0 14.5 13h5A1.5 1.5 0 0 0 21 11.5Zm9 0A1.5 1.5 0 0 0 28.5 5h-5A1.5 1.5 0 0 0 22 6.5v5A1.5 1.5 0 0 0 23.5 13H27V11H24.5a.5.5 0 0 1-.5-.5v-3a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H22v2h6.5A1.5 1.5 0 0 0 30 14.5ZM30 18H22.5A1.5 1.5 0 0 0 21 19.5V26h2V20.5a.5.5 0 0 1 .5-.5h1v6h2V20H28v6h2ZM18.5 11h-3a.5.5 0 0 1-.5-.5v-3a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 .5.5v3A.5.5 0 0 1 18.5 11Zm-4 9h3a.5.5 0 0 1 .5.5v3a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-3A.5.5 0 0 1 14.5 20Z\" /></svg>"),
Rules: []string{
"||gog-cdn-lumen.secure2.footprint.net^",
"||gog-statics.com^",
"||gog.com^",
"||gogalaxy.com^",
},
}, { }, {
ID: "hulu", ID: "hulu",
Name: "Hulu", Name: "Hulu",
@@ -1301,24 +1291,6 @@ var blockedServices = []blockedService{{
"||lolstatic.com^", "||lolstatic.com^",
"||lolusercontent.com^", "||lolusercontent.com^",
}, },
}, {
ID: "line",
Name: "LINE",
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 50 50\"><path d=\"M 9 4 C 6.24 4 4 6.24 4 9 L 4 41 C 4 43.76 6.24 46 9 46 L 41 46 C 43.76 46 46 43.76 46 41 L 46 9 C 46 6.24 43.76 4 41 4 L 9 4 z M 25 11 C 33.27 11 40 16.359219 40 22.949219 C 40 25.579219 38.959297 27.960781 36.779297 30.300781 C 35.209297 32.080781 32.660547 34.040156 30.310547 35.660156 C 27.960547 37.260156 25.8 38.519609 25 38.849609 C 24.68 38.979609 24.44 39.039062 24.25 39.039062 C 23.59 39.039062 23.649219 38.340781 23.699219 38.050781 C 23.739219 37.830781 23.919922 36.789063 23.919922 36.789062 C 23.969922 36.419063 24.019141 35.830937 23.869141 35.460938 C 23.699141 35.050938 23.029062 34.840234 22.539062 34.740234 C 15.339063 33.800234 10 28.849219 10 22.949219 C 10 16.359219 16.73 11 25 11 z M 23.992188 18.998047 C 23.488379 19.007393 23 19.391875 23 20 L 23 26 C 23 26.552 23.448 27 24 27 C 24.552 27 25 26.552 25 26 L 25 23.121094 L 27.185547 26.580078 C 27.751547 27.372078 29 26.973 29 26 L 29 20 C 29 19.448 28.552 19 28 19 C 27.448 19 27 19.448 27 20 L 27 23 L 24.814453 19.419922 C 24.602203 19.122922 24.294473 18.992439 23.992188 18.998047 z M 15 19 C 14.448 19 14 19.448 14 20 L 14 26 C 14 26.552 14.448 27 15 27 L 18 27 C 18.552 27 19 26.552 19 26 C 19 25.448 18.552 25 18 25 L 16 25 L 16 20 C 16 19.448 15.552 19 15 19 z M 21 19 C 20.448 19 20 19.448 20 20 L 20 26 C 20 26.552 20.448 27 21 27 C 21.552 27 22 26.552 22 26 L 22 20 C 22 19.448 21.552 19 21 19 z M 31 19 C 30.448 19 30 19.448 30 20 L 30 26 C 30 26.552 30.448 27 31 27 L 34 27 C 34.552 27 35 26.552 35 26 C 35 25.448 34.552 25 34 25 L 32 25 L 32 24 L 34 24 C 34.553 24 35 23.552 35 23 C 35 22.448 34.553 22 34 22 L 32 22 L 32 21 L 34 21 C 34.552 21 35 20.552 35 20 C 35 19.448 34.552 19 34 19 L 31 19 z\"/></svg>"),
Rules: []string{
"||gcld-line.com^",
"||lin.ee^",
"||line-apps-beta.com^",
"||line-apps-rc.com^",
"||line-apps.com^",
"||line-cdn.net^",
"||line-scdn.net^",
"||line.me^",
"||line.naver.jp^",
"||linecorp.com^",
"||linemyshop.com^",
"||lineshoppingseller.com^",
},
}, { }, {
ID: "mail_ru", ID: "mail_ru",
Name: "Mail.ru", Name: "Mail.ru",
@@ -1335,7 +1307,9 @@ 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^",
@@ -1361,6 +1335,7 @@ 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^",
@@ -1368,15 +1343,13 @@ 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.xyz^", "||mastodon.zaclys.com^",
"||mastodonapp.uk^", "||mastodonapp.uk^",
"||mastodonners.nl^", "||mastodonners.nl^",
"||mastodont.cat^", "||mastodont.cat^",
@@ -1388,9 +1361,9 @@ 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^",
"||newsie.social^", "||newsie.social^",
"||noc.social^", "||noc.social^",
"||norden.social^", "||norden.social^",
@@ -1409,7 +1382,6 @@ var blockedServices = []blockedService{{
"||social.anoxinon.de^", "||social.anoxinon.de^",
"||social.cologne^", "||social.cologne^",
"||social.dev-wiki.de^", "||social.dev-wiki.de^",
"||social.linux.pizza^",
"||social.politicaconciencia.org^", "||social.politicaconciencia.org^",
"||social.vivaldi.net^", "||social.vivaldi.net^",
"||sself.co^", "||sself.co^",

View File

@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"net" "net"
"net/netip" "net/netip"
"sort"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -66,18 +67,15 @@ func (c *Client) closeUpstreams() (err error) {
type clientSource uint type clientSource uint
// Clients information sources. The order determines the priority. // Client sources. The order determines the priority.
const ( const (
ClientSourceNone clientSource = iota ClientSourceWHOIS 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.
@@ -98,7 +96,6 @@ 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.
@@ -270,7 +267,7 @@ func (clients *clientsContainer) addFromConfig(objects []*clientObject) {
} }
} }
slices.Sort(cli.Tags) sort.Strings(cli.Tags)
_, err := clients.Add(cli) _, err := clients.Add(cli)
if err != nil { if err != nil {
@@ -310,9 +307,7 @@ func (clients *clientsContainer) forConfig() (objs []*clientObject) {
// above loop can generate different orderings when writing to the config // above loop can generate different orderings when writing to the config
// file: this produces lots of diffs in config files, so sort objects by // file: this produces lots of diffs in config files, so sort objects by
// name before writing. // name before writing.
slices.SortStableFunc(objs, func(a, b *clientObject) (sortsBefore bool) { sort.Slice(objs, func(i, j int) bool { return objs[i].Name < objs[j].Name })
return a.Name < b.Name
})
return objs return objs
} }
@@ -337,24 +332,23 @@ func (clients *clientsContainer) onDHCPLeaseChanged(flags int) {
} }
} }
// clientSource checks if client with this IP address already exists and returns // exists checks if client with this IP address already exists.
// the source which updated it last. It returns [ClientSourceNone] if the func (clients *clientsContainer) exists(ip netip.Addr, source clientSource) (ok bool) {
// 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 ClientSourcePersistent return true
} }
rc, ok := clients.ipToRC[ip] rc, ok := clients.ipToRC[ip]
if !ok { if !ok {
return ClientSourceNone return false
} }
return rc.Source // Return false if the new source has higher priority.
return source <= rc.Source
} }
func toQueryLogWHOIS(wi *RuntimeClientWHOISInfo) (cw *querylog.ClientWHOIS) { func toQueryLogWHOIS(wi *RuntimeClientWHOISInfo) (cw *querylog.ClientWHOIS) {
@@ -591,7 +585,7 @@ func (clients *clientsContainer) check(c *Client) (err error) {
} }
} }
slices.Sort(c.Tags) sort.Strings(c.Tags)
err = dnsforward.ValidateUpstreams(c.Upstreams) err = dnsforward.ValidateUpstreams(c.Upstreams)
if err != nil { if err != nil {

View File

@@ -67,9 +67,9 @@ func TestClients(t *testing.T) {
assert.Equal(t, "client2", c.Name) assert.Equal(t, "client2", c.Name)
assert.Equal(t, clients.clientSource(cliNoneIP), ClientSourceNone) assert.False(t, clients.exists(cliNoneIP, ClientSourceHostsFile))
assert.Equal(t, clients.clientSource(cli1IP), ClientSourcePersistent) assert.True(t, clients.exists(cli1IP, ClientSourceHostsFile))
assert.Equal(t, clients.clientSource(cli2IP), ClientSourcePersistent) assert.True(t, clients.exists(cli2IP, ClientSourceHostsFile))
}) })
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.Equal(t, clients.clientSource(cliOldIP), ClientSourceNone) assert.False(t, clients.exists(cliOldIP, ClientSourceHostsFile))
assert.Equal(t, clients.clientSource(cliNewIP), ClientSourcePersistent) assert.True(t, clients.exists(cliNewIP, ClientSourceHostsFile))
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.Equal(t, clients.clientSource(netip.MustParseAddr("1.1.1.2")), ClientSourceNone) assert.False(t, clients.exists(netip.MustParseAddr("1.1.1.2"), ClientSourceHostsFile))
}) })
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.Equal(t, clients.clientSource(ip), ClientSourceHostsFile) assert.True(t, clients.exists(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.Equal(t, clients.clientSource(ip), ClientSourceARP) assert.True(t, clients.exists(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.Equal(t, clients.clientSource(ip), ClientSourceDHCP) assert.True(t, clients.exists(ip, ClientSourceDHCP))
}) })
t.Run("addhost_fail", func(t *testing.T) { t.Run("addhost_fail", func(t *testing.T) {

View File

@@ -20,7 +20,6 @@ import (
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/timeutil" "github.com/AdguardTeam/golibs/timeutil"
"github.com/google/renameio/maybe" "github.com/google/renameio/maybe"
"golang.org/x/exp/slices"
yaml "gopkg.in/yaml.v3" yaml "gopkg.in/yaml.v3"
) )
@@ -113,10 +112,8 @@ type configuration struct {
// An active session is automatically refreshed once a day. // An active session is automatically refreshed once a day.
WebSessionTTLHours uint32 `yaml:"web_session_ttl"` WebSessionTTLHours uint32 `yaml:"web_session_ttl"`
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
@@ -150,6 +147,20 @@ 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"`
@@ -177,7 +188,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 []netip.Prefix `yaml:"dns64_prefixes"` DNS64Prefixes []string `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.
// //
@@ -217,37 +228,6 @@ 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.
@@ -258,8 +238,13 @@ var config = &configuration{
AuthBlockMin: 15, AuthBlockMin: 15,
WebSessionTTLHours: 30 * 24, WebSessionTTLHours: 30 * 24,
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,
@@ -297,18 +282,6 @@ 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.
// //
@@ -485,24 +458,19 @@ func (c *configuration) write() (err error) {
} }
if Context.stats != nil { if Context.stats != nil {
statsConf := stats.Config{} sdc := stats.DiskConfig{}
Context.stats.WriteDiskConfig(&statsConf) Context.stats.WriteDiskConfig(&sdc)
config.Stats.Interval = statsConf.LimitDays config.DNS.StatsInterval = sdc.Interval
config.Stats.Enabled = statsConf.Enabled
config.Stats.Ignored = statsConf.Ignored.Values()
slices.Sort(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()
slices.Sort(config.Stats.Ignored)
} }
if Context.filters != nil { if Context.filters != nil {

View File

@@ -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/quic-go/quic-go/http3" "github.com/lucas-clemente/quic-go/http3"
) )
// getAddrsResponse is the response for /install/get_addresses endpoint. // getAddrsResponse is the response for /install/get_addresses endpoint.

View File

@@ -7,7 +7,6 @@ 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"
@@ -21,7 +20,6 @@ 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"
) )
@@ -53,18 +51,10 @@ func initDNS() (err error) {
statsConf := stats.Config{ statsConf := stats.Config{
Filename: filepath.Join(baseDir, "stats.db"), Filename: filepath.Join(baseDir, "stats.db"),
LimitDays: config.Stats.Interval, LimitDays: config.DNS.StatsInterval,
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)
@@ -76,19 +66,12 @@ 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)
@@ -532,27 +515,3 @@ 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
}

View File

@@ -570,14 +570,21 @@ func startMods() (err error) {
func checkPermissions() { func checkPermissions() {
log.Info("Checking if AdGuard Home has necessary permissions") log.Info("Checking if AdGuard Home has necessary permissions")
if ok, err := aghnet.CanBindPrivilegedPorts(); !ok || err != nil { err := aghnet.AcquirePermissions()
log.Fatal("This is the first launch of AdGuard Home. You must run it as Administrator.") if err != nil {
log.Debug("acquiring necessary permissions: %s", err)
var ok bool
if ok, err = aghnet.CanBindPrivilegedPorts(); !ok || err != nil {
log.Fatal("This is the first launch of AdGuard Home. You must run it as Administrator.")
}
} }
// We should check if AdGuard Home is able to bind to port 53 // We should check if AdGuard Home is able to bind to port 53
err := aghnet.CheckPort("tcp", netip.AddrPortFrom(netutil.IPv4Localhost(), defaultPortDNS)) err = aghnet.CheckPort("tcp", netip.AddrPortFrom(netutil.IPv4Localhost(), defaultPortDNS))
if err != nil { if err != nil {
if errors.Is(err, os.ErrPermission) { if errors.Is(err, os.ErrPermission) {
log.Debug("checking permissions via binding: %v", err)
log.Fatal(`Permission check failed. log.Fatal(`Permission check failed.
AdGuard Home is not allowed to bind to privileged ports (for instance, port 53). AdGuard Home is not allowed to bind to privileged ports (for instance, port 53).

View File

@@ -8,7 +8,6 @@ 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"
) )
@@ -17,6 +16,10 @@ 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
@@ -25,21 +28,13 @@ 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 AdGuard Home reverse DNS values. // Default rDNS values.
const ( const (
revDNSCacheSize = 10000 defaultRDNSCacheSize = 10000
defaultRDNSCacheTTL = 1 * 60 * 60
// TODO(e.burkov): Make these values configurable. defaultRDNSIPChSize = 256
revDNSCacheTTL = 24 * 60 * 60
revDNSFailureCacheTTL = 1 * 60 * 60
revDNSQueueSize = 256
) )
// NewRDNS creates and returns initialized RDNS. // NewRDNS creates and returns initialized RDNS.
@@ -53,12 +48,13 @@ func NewRDNS(
clients: clients, clients: clients,
ipCache: cache.New(cache.Config{ ipCache: cache.New(cache.Config{
EnableLRU: true, EnableLRU: true,
MaxCount: revDNSCacheSize, MaxCount: defaultRDNSCacheSize,
}), }),
ipCh: make(chan netip.Addr, revDNSQueueSize), ipCh: make(chan netip.Addr, defaultRDNSIPChSize),
}
if usePrivate {
rDNS.usePrivate = 1
} }
rDNS.usePrivate.Store(usePrivate)
go rDNS.workerLoop() go rDNS.workerLoop()
@@ -72,8 +68,12 @@ 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() {
usePrivate := r.exchanger.ResolvesPrivatePTR() var usePrivate uint32
if r.usePrivate.CompareAndSwap(!usePrivate, usePrivate) { if r.exchanger.ResolvesPrivatePTR() {
usePrivate = 1
}
if atomic.CompareAndSwapUint32(&r.usePrivate, 1-usePrivate, usePrivate) {
r.ipCache.Clear() r.ipCache.Clear()
} }
} }
@@ -84,28 +84,25 @@ 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 {
return binary.BigEndian.Uint64(expire) > now if 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.clientSource(ip) > ClientSourceRDNS { if r.isCached(ip) || r.clients.exists(ip, ClientSourceRDNS) {
return return
} }
@@ -123,21 +120,15 @@ 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) {
// Cache failure for a less time. continue
ttl = revDNSFailureCacheTTL } else if host == "" {
} continue
} }
r.cache(ip, ttl) _ = r.clients.AddHost(ip, host, ClientSourceRDNS)
if host != "" {
_ = r.clients.AddHost(ip, host, ClientSourceRDNS)
}
} }
} }

View File

@@ -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: revDNSCacheSize, MaxCount: defaultRDNSCacheSize,
}) })
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: revDNSCacheSize, MaxCount: defaultRDNSCacheSize,
}) })
ex := &rDNSExchanger{ ex := &rDNSExchanger{
@@ -200,29 +200,25 @@ func TestRDNS_WorkerLoop(t *testing.T) {
errUpstream := aghtest.NewErrorUpstream() errUpstream := aghtest.NewErrorUpstream()
testCases := []struct { testCases := []struct {
ups upstream.Upstream ups upstream.Upstream
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 {
@@ -241,10 +237,6 @@ 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) {
@@ -261,9 +253,11 @@ 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.Equal(t, tc.wantClientSource, cc.clientSource(tc.cliIP)) assert.True(t, cc.exists(tc.cliIP, ClientSourceRDNS))
}) })
} }
} }

View File

@@ -22,7 +22,7 @@ import (
) )
// currentSchemaVersion is the current schema version. // currentSchemaVersion is the current schema version.
const currentSchemaVersion = 16 const currentSchemaVersion = 14
// These aliases are provided for convenience. // These aliases are provided for convenience.
type ( type (
@@ -87,8 +87,6 @@ func upgradeConfigSchema(oldVersion int, diskConf yobj) (err error) {
upgradeSchema11to12, upgradeSchema11to12,
upgradeSchema12to13, upgradeSchema12to13,
upgradeSchema13to14, upgradeSchema13to14,
upgradeSchema14to15,
upgradeSchema15to16,
} }
n := 0 n := 0
@@ -804,107 +802,6 @@ 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 {

View File

@@ -640,110 +640,3 @@ 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)
})
}
}

View File

@@ -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/quic-go/quic-go" "github.com/lucas-clemente/quic-go"
"github.com/quic-go/quic-go/http3" "github.com/lucas-clemente/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"
) )

View File

@@ -48,11 +48,18 @@ type Config struct {
// Service is the AdGuard Home DNS service. A nil *Service is a valid // Service is the AdGuard Home DNS service. A nil *Service is a valid
// [agh.Service] that does nothing. // [agh.Service] that does nothing.
type Service struct { type Service struct {
// running is an atomic boolean value. Keep it the first value in the
// struct to ensure atomic alignment. 0 means that the service is not
// running, 1 means that it is running.
//
// TODO(a.garipov): Use [atomic.Bool] in Go 1.19 or get rid of it
// completely.
running uint64
proxy *proxy.Proxy proxy *proxy.Proxy
bootstraps []string bootstraps []string
upstreams []string upstreams []string
upsTimeout time.Duration upsTimeout time.Duration
running atomic.Bool
} }
// New returns a new properly initialized *Service. If c is nil, svc is a nil // New returns a new properly initialized *Service. If c is nil, svc is a nil
@@ -166,7 +173,11 @@ func (svc *Service) Start() (err error) {
// TODO(a.garipov): [proxy.Proxy.Start] doesn't actually have any way to // TODO(a.garipov): [proxy.Proxy.Start] doesn't actually have any way to
// tell when all servers are actually up, so at best this is merely an // tell when all servers are actually up, so at best this is merely an
// assumption. // assumption.
svc.running.Store(err == nil) if err != nil {
atomic.StoreUint64(&svc.running, 0)
} else {
atomic.StoreUint64(&svc.running, 1)
}
}() }()
return svc.proxy.Start() return svc.proxy.Start()
@@ -190,7 +201,7 @@ func (svc *Service) Config() (c *Config) {
// TODO(a.garipov): Do we need to get the TCP addresses separately? // TODO(a.garipov): Do we need to get the TCP addresses separately?
var addrs []netip.AddrPort var addrs []netip.AddrPort
if svc.running.Load() { if atomic.LoadUint64(&svc.running) == 1 {
udpAddrs := svc.proxy.Addrs(proxy.ProtoUDP) udpAddrs := svc.proxy.Addrs(proxy.ProtoUDP)
addrs = make([]netip.AddrPort, len(udpAddrs)) addrs = make([]netip.AddrPort, len(udpAddrs))
for i, a := range udpAddrs { for i, a := range udpAddrs {

View File

@@ -26,12 +26,13 @@ func TestService_HandlePatchSettingsDNS(t *testing.T) {
UpstreamTimeout: websvc.JSONDuration(2 * time.Second), UpstreamTimeout: websvc.JSONDuration(2 * time.Second),
} }
var started atomic.Bool // TODO(a.garipov): Use [atomic.Bool] in Go 1.19.
var numStarted uint64
confMgr := newConfigManager() confMgr := newConfigManager()
confMgr.onDNS = func() (s agh.ServiceWithConfig[*dnssvc.Config]) { confMgr.onDNS = func() (s agh.ServiceWithConfig[*dnssvc.Config]) {
return &aghtest.ServiceWithConfig[*dnssvc.Config]{ return &aghtest.ServiceWithConfig[*dnssvc.Config]{
OnStart: func() (err error) { OnStart: func() (err error) {
started.Store(true) atomic.AddUint64(&numStarted, 1)
return nil return nil
}, },
@@ -62,7 +63,7 @@ func TestService_HandlePatchSettingsDNS(t *testing.T) {
err := json.Unmarshal(respBody, resp) err := json.Unmarshal(respBody, resp)
require.NoError(t, err) require.NoError(t, err)
assert.True(t, started.Load()) assert.Equal(t, uint64(1), numStarted)
assert.Equal(t, wantDNS, resp) assert.Equal(t, wantDNS, resp)
assert.Equal(t, wantDNS, resp) assert.Equal(t, wantDNS, resp)
} }

View File

@@ -12,10 +12,11 @@ import (
) )
func TestWaitListener_Accept(t *testing.T) { func TestWaitListener_Accept(t *testing.T) {
var accepted atomic.Bool // TODO(a.garipov): use atomic.Bool in Go 1.19.
var numAcceptCalls uint32
var l net.Listener = &aghtest.Listener{ var l net.Listener = &aghtest.Listener{
OnAccept: func() (conn net.Conn, err error) { OnAccept: func() (conn net.Conn, err error) {
accepted.Store(true) atomic.AddUint32(&numAcceptCalls, 1)
return nil, nil return nil, nil
}, },
@@ -41,5 +42,5 @@ func TestWaitListener_Accept(t *testing.T) {
wg.Wait() wg.Wait()
close(done) close(done)
assert.True(t, accepted.Load()) assert.Equal(t, uint32(1), atomic.LoadUint32(&numAcceptCalls))
} }

View File

@@ -44,9 +44,6 @@ 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)

View File

@@ -247,13 +247,3 @@ 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)
}

View File

@@ -2,12 +2,14 @@ package querylog
import ( import (
"fmt" "fmt"
"math/rand"
"net" "net"
"sort"
"testing" "testing"
"time"
"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"
@@ -247,48 +249,6 @@ 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{{
@@ -349,3 +309,72 @@ func assertLogEntry(t *testing.T, entry *logEntry, host string, answer, client n
ip := proxyutil.IPFromRR(msg.Answer[0]).To16() ip := proxyutil.IPFromRR(msg.Answer[0]).To16()
assert.Equal(t, answer, ip) assert.Equal(t, answer, ip)
} }
func testEntries() (entries []*logEntry) {
rsrc := rand.NewSource(time.Now().UnixNano())
rgen := rand.New(rsrc)
entries = make([]*logEntry, 1000)
for i := range entries {
min := rgen.Intn(60)
sec := rgen.Intn(60)
entries[i] = &logEntry{
Time: time.Date(2020, 1, 1, 0, min, sec, 0, time.UTC),
}
}
return entries
}
// logEntriesByTimeDesc is a wrapper over []*logEntry for sorting.
//
// NOTE(a.garipov): Weirdly enough, on my machine this gets consistently
// outperformed by sort.Slice, see the benchmark below. I'm leaving this
// implementation here, in tests, in case we want to make sure it outperforms on
// most machines, but for now this is unused in the actual code.
type logEntriesByTimeDesc []*logEntry
// Len implements the sort.Interface interface for logEntriesByTimeDesc.
func (les logEntriesByTimeDesc) Len() (n int) { return len(les) }
// Less implements the sort.Interface interface for logEntriesByTimeDesc.
func (les logEntriesByTimeDesc) Less(i, j int) (less bool) {
return les[i].Time.After(les[j].Time)
}
// Swap implements the sort.Interface interface for logEntriesByTimeDesc.
func (les logEntriesByTimeDesc) Swap(i, j int) { les[i], les[j] = les[j], les[i] }
func BenchmarkLogEntry_sort(b *testing.B) {
b.Run("methods", func(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
entries := testEntries()
b.StartTimer()
sort.Stable(logEntriesByTimeDesc(entries))
}
})
b.Run("reflect", func(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
entries := testEntries()
b.StartTimer()
sort.SliceStable(entries, func(i, j int) (less bool) {
return entries[i].Time.After(entries[j].Time)
})
}
})
}
func TestLogEntriesByTime_sort(t *testing.T) {
entries := testEntries()
sort.Sort(logEntriesByTimeDesc(entries))
for i := range entries[1:] {
assert.False(t, entries[i+1].Time.After(entries[i].Time),
"%s %s", entries[i+1].Time, entries[i].Time)
}
}

View File

@@ -10,7 +10,6 @@ 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"
) )
@@ -27,9 +26,6 @@ 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.
@@ -75,10 +71,6 @@ 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.

View File

@@ -155,9 +155,6 @@ 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)

View File

@@ -2,10 +2,10 @@ package querylog
import ( import (
"io" "io"
"sort"
"time" "time"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"golang.org/x/exp/slices"
) )
// client finds the client info, if any, by its ClientID and IP address, // client finds the client info, if any, by its ClientID and IP address,
@@ -98,8 +98,8 @@ func (l *queryLog) search(params *searchParams) (entries []*logEntry, oldest tim
// weird on the frontend. // weird on the frontend.
// //
// See https://github.com/AdguardTeam/AdGuardHome/issues/2293. // See https://github.com/AdguardTeam/AdGuardHome/issues/2293.
slices.SortStableFunc(entries, func(a, b *logEntry) (sortsBefore bool) { sort.SliceStable(entries, func(i, j int) (less bool) {
return a.Time.After(b.Time) return entries[i].Time.After(entries[j].Time)
}) })
if params.offset > 0 { if params.offset > 0 {
@@ -263,10 +263,6 @@ 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(

View File

@@ -5,6 +5,7 @@ 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"
@@ -40,11 +41,10 @@ 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) {
s.lock.Lock() limit := atomic.LoadUint32(&s.limitHours)
defer s.lock.Unlock()
start := time.Now() start := time.Now()
resp, ok := s.getData(s.limitHours) resp, ok := s.getData(limit)
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,13 +65,7 @@ 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) {
s.lock.Lock() resp := configResp{IntervalDays: atomic.LoadUint32(&s.limitHours) / 24}
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)
} }

View File

@@ -15,10 +15,16 @@ 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) {
@@ -45,12 +51,6 @@ 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,22 +68,30 @@ 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 *Config) WriteDiskConfig(dc *DiskConfig)
// 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 atomic.Pointer[bbolt.DB] db *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.
@@ -98,21 +106,6 @@ 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
@@ -121,12 +114,11 @@ 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
@@ -145,7 +137,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.Load().Begin(true) tx, err := s.db.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)
} }
@@ -199,7 +191,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.db.Swap(nil) db := s.swapDatabase(nil)
if db == nil { if db == nil {
return nil return nil
} }
@@ -228,10 +220,7 @@ 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) {
s.lock.Lock() if atomic.LoadUint32(&s.limitHours) == 0 {
defer s.lock.Unlock()
if !s.enabled || s.limitHours == 0 {
return return
} }
@@ -259,22 +248,14 @@ 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 *Config) { func (s *StatsCtx) WriteDiskConfig(dc *DiskConfig) {
s.lock.Lock() dc.Interval = atomic.LoadUint32(&s.limitHours) / 24
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) {
s.lock.Lock() limit := atomic.LoadUint32(&s.limitHours)
defer s.lock.Unlock() if limit == 0 {
limit := s.limitHours
if !s.enabled || limit == 0 {
return nil return nil
} }
@@ -303,6 +284,25 @@ 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,7 +358,10 @@ 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.db.Store(db) s.dbMu.Lock()
defer s.dbMu.Unlock()
s.db = db
return nil return nil
} }
@@ -366,9 +369,6 @@ 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 := s.limitHours limit := atomic.LoadUint32(&s.limitHours)
if limit == 0 || ptr.id == id { if limit == 0 || ptr.id == id {
return true, time.Second return true, time.Second
} }
db := s.db.Load() db := s.database()
if db == nil { if db == nil {
return true, 0 return true, 0
} }
@@ -437,30 +437,21 @@ func (s *StatsCtx) periodicFlush() {
} }
func (s *StatsCtx) setLimit(limitDays int) { func (s *StatsCtx) setLimit(limitDays int) {
s.lock.Lock() atomic.StoreUint32(&s.limitHours, uint32(24*limitDays))
defer s.lock.Unlock() if limitDays == 0 {
if err := s.clear(); err != nil {
if limitDays != 0 { log.Error("stats: %s", err)
s.enabled = true }
s.limitHours = uint32(24 * limitDays)
log.Debug("stats: set limit: %d days", limitDays)
return
} }
s.enabled = false log.Debug("stats: set limit: %d days", limitDays)
log.Debug("stats: disabled")
if err := s.clear(); err != nil {
log.Error("stats: %s", err)
}
} }
// 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.db.Swap(nil) db := s.swapDatabase(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)
@@ -504,7 +495,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.db.Load() db := s.database()
if db == nil { if db == nil {
return nil, 0 return nil, 0
} }
@@ -556,13 +547,3 @@ 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)
}

View File

@@ -47,6 +47,8 @@ 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),

View File

@@ -53,7 +53,6 @@ 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
@@ -159,7 +158,6 @@ 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 },
} }

View File

@@ -5,13 +5,12 @@ import (
"encoding/binary" "encoding/binary"
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"sort"
"time" "time"
"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"
"golang.org/x/exp/slices"
) )
// TODO(a.garipov): Rewrite all of this. Add proper error handling and // TODO(a.garipov): Rewrite all of this. Add proper error handling and
@@ -180,8 +179,8 @@ func convertMapToSlice(m map[string]uint64, max int) (s []countPair) {
s = append(s, countPair{Name: k, Count: v}) s = append(s, countPair{Name: k, Count: v})
} }
slices.SortFunc(s, func(a, b countPair) (sortsBefore bool) { sort.Slice(s, func(i, j int) bool {
return a.Count < b.Count return s[j].Count < s[i].Count
}) })
if max > len(s) { if max > len(s) {
max = len(s) max = len(s)
@@ -342,13 +341,11 @@ 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, ignored *stringutil.Set, pg pairsGetter) []map[string]uint64 { func topsCollector(units []*unitDB, max int, 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)
@@ -411,9 +408,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, s.ignored, func(u *unitDB) (pairs []countPair) { return u.Domains }), TopQueried: topsCollector(units, maxDomains, func(u *unitDB) (pairs []countPair) { return u.Domains }),
TopBlocked: topsCollector(units, maxDomains, s.ignored, func(u *unitDB) (pairs []countPair) { return u.BlockedDomains }), TopBlocked: topsCollector(units, maxDomains, func(u *unitDB) (pairs []countPair) { return u.BlockedDomains }),
TopClients: topsCollector(units, maxClients, nil, func(u *unitDB) (pairs []countPair) { return u.Clients }), TopClients: topsCollector(units, maxClients, func(u *unitDB) (pairs []countPair) { return u.Clients }),
} }
// Total counters: // Total counters:

View File

@@ -1,6 +1,6 @@
module github.com/AdguardTeam/AdGuardHome/internal/tools module github.com/AdguardTeam/AdGuardHome/internal/tools
go 1.19 go 1.18
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.15.0 github.com/securego/gosec/v2 v2.14.0
golang.org/x/tools v0.6.1-0.20230217175706-3102dad5faf9 golang.org/x/tools v0.5.1-0.20230117180257-8aba49bb5ea2
golang.org/x/vuln v0.0.0-20230217204342-b91abcc5ae3c golang.org/x/vuln v0.0.0-20230130175424-dd534eeddf33
honnef.co/go/tools v0.4.2 honnef.co/go/tools v0.3.3
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-20230213192124-5e25df0256eb // indirect golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 // indirect
golang.org/x/exp/typeparams v0.0.0-20230213192124-5e25df0256eb // indirect golang.org/x/exp/typeparams v0.0.0-20230131160201-f062dba9d201 // indirect
golang.org/x/mod v0.8.0 // indirect golang.org/x/mod v0.7.0 // indirect
golang.org/x/sync v0.1.0 // indirect golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.5.0 // indirect golang.org/x/sys v0.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
) )

View File

@@ -7,7 +7,6 @@ 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=
@@ -30,14 +29,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.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI= github.com/onsi/ginkgo/v2 v2.3.1 h1:8SbseP7qM32WcvE6VaN6vfXxv698izmsJ1UQX9ve7T8=
github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI=
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.15.0 h1:v4Ym7FF58/jlykYmmhZ7mTm7FQvN/setNm++0fgIAtw= github.com/securego/gosec/v2 v2.14.0 h1:U1hfs0oBackChXA72plCYVA4cOlQ4gO+209dHiSNZbI=
github.com/securego/gosec/v2 v2.15.0/go.mod h1:VOjTrZOkUtSDt2QLSJmQBMWnvwiQPEjg0l+5juIqGk8= github.com/securego/gosec/v2 v2.14.0/go.mod h1:Ff03zEi5NwSOfXj9nFpBfhbWTtROCkg9N+9goggrYn4=
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=
@@ -54,22 +53,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-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w= golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 h1:BEABXpNXLEz0WxtA+6CQIz2xkg80e+1zrhWyMcq8VzE=
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp/typeparams v0.0.0-20230213192124-5e25df0256eb h1:WGs/bGIWYyAY5PVgGGMXqGGCxSJz4fpoUExb/vgqNCU= 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/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230131160201-f062dba9d201/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.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.7.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.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
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=
@@ -84,33 +83,35 @@ 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.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.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.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
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.6.1-0.20230217175706-3102dad5faf9 h1:IuFp2CklNBim6OdHXn/1P4VoeKt5pA2jcDKWlboqtlQ= golang.org/x/tools v0.5.1-0.20230117180257-8aba49bb5ea2 h1:v0FhRDmSCNH/0EurAT6T8KRY4aNuUhz6/WwBMxG+gvQ=
golang.org/x/tools v0.6.1-0.20230217175706-3102dad5faf9/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.5.1-0.20230117180257-8aba49bb5ea2/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
golang.org/x/vuln v0.0.0-20230217204342-b91abcc5ae3c h1:7/jJkMpaKZMxdyOQ7IP7aPbJQaDk4cOUxtXtWHQ1cSk= golang.org/x/vuln v0.0.0-20230130175424-dd534eeddf33 h1:je2aB5nnlseeGvJy5clg6EyC3jjbbCNsRDroC3qQJsA=
golang.org/x/vuln v0.0.0-20230217204342-b91abcc5ae3c/go.mod h1:LTLnfk/dpXDNKsX6aCg/cI4LyCVnTyrQhgV/yLJuly0= golang.org/x/vuln v0.0.0-20230130175424-dd534eeddf33/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.4.2 h1:6qXr+R5w+ktL5UkwEbPp+fEvfyoMPche6GkOpGHZcLc= honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=
honnef.co/go/tools v0.4.2/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA= honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=
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=

View File

@@ -1,4 +1,5 @@
//go:build tools //go:build tools
// +build tools
package tools package tools

View File

@@ -1,4 +1,5 @@
//go:build !next //go:build !next
// +build !next
package main package main

View File

@@ -1,4 +1,5 @@
//go:build next //go:build next
// +build next
package main package main

View File

@@ -205,7 +205,7 @@ code from [the repo][companiesrepo].
### Usage ### Usage
```sh ```sh
sh ./scripts/companiesdb/download.sh ( cd scripts/companiesdb && sh ./download.sh )
``` ```
[companiesrepo]: https://github.com/AdguardTeam/companiesdb [companiesrepo]: https://github.com/AdguardTeam/companiesdb

View File

@@ -4,9 +4,11 @@ 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
curl -o "$output" -v "$trackers_url" whotracksme='https://raw.githubusercontent.com/AdguardTeam/companiesdb/main/dist/whotracksme.json'
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"

View File

@@ -2,18 +2,10 @@
set -e -f -u set -e -f -u
# This comment is used to simplify checking local copies of the script. # Only show interactive prompts if there is a terminal attached. This
# Bump this number every time a significant change is made to this # should work on all of our supported Unix systems.
# script.
#
# AdGuard-Project-Version: 1
# Only show interactive prompts if there a terminal is attached to
# stdout. While this technically doesn't guarantee that reading from
# /dev/tty works, this should work reasonably well on all of our
# supported development systems and in most terminal emulators.
is_tty='0' is_tty='0'
if [ -t '1' ] if [ -e /dev/tty ]
then then
is_tty='1' is_tty='1'
fi fi

View File

@@ -33,19 +33,6 @@ usage() {
exit 2 exit 2
} }
# Function maybe_sudo runs passed command with root privileges if use_sudo isn't
# equal to 0.
#
# TODO(e.burkov): Use everywhere the sudo_cmd isn't quoted.
maybe_sudo() {
if [ "$use_sudo" -eq 0 ]
then
"$@"
else
"$sudo_cmd" "$@"
fi
}
# Function is_command checks if the command exists on the machine. # Function is_command checks if the command exists on the machine.
is_command() { is_command() {
command -v "$1" >/dev/null 2>&1 command -v "$1" >/dev/null 2>&1
@@ -351,18 +338,6 @@ 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() {
@@ -373,9 +348,6 @@ 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
@@ -567,14 +539,7 @@ handle_existing() {
# Function install_service tries to install AGH as service. # Function install_service tries to install AGH as service.
install_service() { install_service() {
# Installing the service as root is required at least on FreeBSD. if ( cd "$agh_dir" && ./AdGuardHome -s install )
use_sudo='0'
if [ "$os" = 'freebsd' ]
then
use_sudo='1'
fi
if ( cd "$agh_dir" && maybe_sudo ./AdGuardHome -s install )
then then
return 0 return 0
fi fi

View File

@@ -1,6 +1,6 @@
# A docker file for scripts/make/build-docker.sh. # A docker file for scripts/make/build-docker.sh.
FROM alpine:3.17 FROM alpine:3.16
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION ARG VERSION

View File

@@ -6,11 +6,6 @@
# only has superficial knowledge of the POSIX shell language and alike. # only has superficial knowledge of the POSIX shell language and alike.
# Experienced readers may find it overly verbose. # Experienced readers may find it overly verbose.
# This comment is used to simplify checking local copies of the script. Bump
# this number every time a significant change is made to this script.
#
# AdGuard-Project-Version: 1
# The default verbosity level is 0. Show every command that is run and every # The default verbosity level is 0. Show every command that is run and every
# package that is processed if the caller requested verbosity level greater than # package that is processed if the caller requested verbosity level greater than
# 0. Also show subcommands if the requested verbosity level is greater than 1. # 0. Also show subcommands if the requested verbosity level is greater than 1.
@@ -116,17 +111,17 @@ readonly o_flags
# must be enabled. # must be enabled.
if [ "${RACE:-0}" -eq '0' ] if [ "${RACE:-0}" -eq '0' ]
then then
CGO_ENABLED='0' cgo_enabled='0'
race_flags='--race=0' race_flags='--race=0'
else else
CGO_ENABLED='1' cgo_enabled='1'
race_flags='--race=1' race_flags='--race=1'
fi fi
readonly CGO_ENABLED race_flags readonly cgo_enabled race_flags
export CGO_ENABLED
CGO_ENABLED="$cgo_enabled"
GO111MODULE='on' GO111MODULE='on'
export GO111MODULE export CGO_ENABLED GO111MODULE
# Build the new binary if requested. # Build the new binary if requested.
if [ "${NEXTAPI:-0}" -eq '0' ] if [ "${NEXTAPI:-0}" -eq '0' ]
@@ -137,16 +132,5 @@ else
fi fi
readonly tags_flags readonly tags_flags
if [ "$verbose" -gt '0' ] "$go" build --ldflags "$ldflags" "$race_flags" "$tags_flags" --trimpath "$o_flags" "$v_flags"\
then
"$go" env
fi
"$go" build\
--ldflags "$ldflags"\
"$race_flags"\
"$tags_flags"\
--trimpath\
"$o_flags"\
"$v_flags"\
"$x_flags" "$x_flags"

View File

@@ -1,10 +1,5 @@
#!/bin/sh #!/bin/sh
# This comment is used to simplify checking local copies of the script. Bump
# this number every time a significant change is made to this script.
#
# AdGuard-Project-Version: 1
verbose="${VERBOSE:-0}" verbose="${VERBOSE:-0}"
readonly verbose readonly verbose
@@ -12,14 +7,14 @@ if [ "$verbose" -gt '1' ]
then then
env env
set -x set -x
x_flags='-x=1' x_flags='-x'
elif [ "$verbose" -gt '0' ] elif [ "$verbose" -gt '0' ]
then then
set -x set -x
x_flags='-x=0' x_flags=''
else else
set +x set +x
x_flags='-x=0' x_flags=''
fi fi
readonly x_flags readonly x_flags
@@ -28,4 +23,6 @@ set -e -f -u
go="${GO:-go}" go="${GO:-go}"
readonly go readonly go
"$go" mod download "$x_flags" # Don't use quotes with flag variables because we want an empty space if those
# aren't set.
"$go" mod download $x_flags

View File

@@ -1,13 +1,8 @@
#!/bin/sh #!/bin/sh
# This comment is used to simplify checking local copies of the script. Bump
# this number every time a significant change is made to this script.
#
# AdGuard-Project-Version: 3
verbose="${VERBOSE:-0}" verbose="${VERBOSE:-0}"
readonly verbose
# Set verbosity.
if [ "$verbose" -gt '0' ] if [ "$verbose" -gt '0' ]
then then
set -x set -x
@@ -21,12 +16,34 @@ else
set -e set -e
fi fi
# We don't need glob expansions and we want to see errors about unset variables.
set -f -u set -f -u
# Source the common helpers, including not_found and run_linter. # Deferred Helpers
. ./scripts/make/helper.sh
not_found_msg='
looks like a binary not found error.
make sure you have installed the linter binaries using:
$ make go-tools
'
readonly not_found_msg
# TODO(a.garipov): Put it into a separate script and source it both here and in
# txt-lint.sh?
not_found() {
if [ "$?" -eq '127' ]
then
# Code 127 is the exit status a shell uses when a command or
# a file is not found, according to the Bash Hackers wiki.
#
# See https://wiki.bash-hackers.org/dict/terms/exit_status.
echo "$not_found_msg" 1>&2
fi
}
trap not_found EXIT
@@ -35,7 +52,7 @@ set -f -u
go_version="$( "${GO:-go}" version )" go_version="$( "${GO:-go}" version )"
readonly go_version readonly go_version
go_min_version='go1.19.6' go_min_version='go1.18'
go_version_msg=" go_version_msg="
warning: your go version (${go_version}) is different from the recommended minimal one (${go_min_version}). warning: your go version (${go_version}) is different from the recommended minimal one (${go_min_version}).
if you have the version installed, please set the GO environment variable. if you have the version installed, please set the GO environment variable.
@@ -57,7 +74,7 @@ esac
# Simple analyzers # Simple Analyzers
# blocklist_imports is a simple check against unwanted packages. The following # blocklist_imports is a simple check against unwanted packages. The following
# packages are banned: # packages are banned:
@@ -74,8 +91,6 @@ esac
# #
# See https://github.com/golang/go/issues/45200. # See https://github.com/golang/go/issues/45200.
# #
# * Package sort is replaced by golang.org/x/exp/slices.
#
# * Package unsafe is… unsafe. # * Package unsafe is… unsafe.
# #
# * Package golang.org/x/net/context has been moved into stdlib. # * Package golang.org/x/net/context has been moved into stdlib.
@@ -86,7 +101,6 @@ blocklist_imports() {
-e '[[:space:]]"io/ioutil"$'\ -e '[[:space:]]"io/ioutil"$'\
-e '[[:space:]]"log"$'\ -e '[[:space:]]"log"$'\
-e '[[:space:]]"reflect"$'\ -e '[[:space:]]"reflect"$'\
-e '[[:space:]]"sort"$'\
-e '[[:space:]]"unsafe"$'\ -e '[[:space:]]"unsafe"$'\
-e '[[:space:]]"golang.org/x/net/context"$'\ -e '[[:space:]]"golang.org/x/net/context"$'\
-n\ -n\
@@ -144,67 +158,96 @@ underscores() {
# Helpers
# exit_on_output exits with a nonzero exit code if there is anything in the
# command's combined output.
exit_on_output() (
set +e
if [ "$VERBOSE" -lt '2' ]
then
set +x
fi
cmd="$1"
shift
output="$( "$cmd" "$@" 2>&1 )"
exitcode="$?"
if [ "$exitcode" -ne '0' ]
then
echo "'$cmd' failed with code $exitcode"
fi
if [ "$output" != '' ]
then
if [ "$*" != '' ]
then
echo "combined output of linter '$cmd $*':"
else
echo "combined output of linter '$cmd':"
fi
echo "$output"
if [ "$exitcode" -eq '0' ]
then
exitcode='1'
fi
fi
return "$exitcode"
)
# Checks # Checks
run_linter -e blocklist_imports exit_on_output blocklist_imports
run_linter -e method_const exit_on_output method_const
run_linter -e underscores exit_on_output underscores
run_linter -e gofumpt --extra -e -l . exit_on_output gofumpt --extra -e -l .
# TODO(a.garipov): golint is deprecated, find a suitable replacement. # TODO(a.garipov): golint is deprecated, and seems to cause more and more
# issues with each release. Find a suitable replacement.
#
# golint --set_exit_status ./...
run_linter "$GO" vet ./... "$GO" vet ./...
run_linter govulncheck ./... govulncheck ./...
# Apply more lax standards to the code we haven't properly refactored yet. # Apply more lax standards to the code we haven't properly refactored yet.
run_linter gocyclo --over 17 ./internal/querylog/ gocyclo --over 17 ./internal/querylog/
run_linter gocyclo --over 13\ gocyclo --over 13 ./internal/dhcpd ./internal/filtering/ ./internal/home/
./internal/dhcpd\
./internal/filtering/\
./internal/home/\
;
# Apply the normal standards to new or somewhat refactored code. # Apply stricter standards to new or somewhat refactored code.
run_linter gocyclo --over 10\ gocyclo --over 10 ./internal/aghio/ ./internal/aghnet/ ./internal/aghos/\
./internal/aghio/\ ./internal/aghtest/ ./internal/dnsforward/ ./internal/filtering/rewrite/\
./internal/aghnet/\ ./internal/stats/ ./internal/tools/ ./internal/updater/ ./internal/next/\
./internal/aghos/\ ./internal/version/ ./scripts/blocked-services/ ./scripts/vetted-filters/\
./internal/aghtest/\ ./main.go
./internal/dnsforward/\
./internal/filtering/rewrite/\
./internal/stats/\
./internal/tools/\
./internal/updater/\
./internal/next/\
./internal/version/\
./scripts/blocked-services/\
./scripts/vetted-filters/\
./main.go\
;
run_linter ineffassign ./... ineffassign ./...
run_linter unparam ./... unparam ./...
git ls-files -- 'Makefile' '*.go' '*.mod' '*.sh' '*.yaml' '*.yml'\ git ls-files -- '*.go' '*.mod' '*.sh' 'Makefile' | xargs misspell --error
| xargs misspell --error
run_linter looppointer ./... looppointer ./...
run_linter nilness ./... nilness ./...
# TODO(a.garipov): Add fieldalignment? exit_on_output shadow --strict ./...
run_linter -e shadow --strict ./...
# TODO(a.garipov): Enable in v0.108.0. # TODO(a.garipov): Enable in v0.108.0.
# run_linter gosec --quiet ./... # gosec --quiet ./...
# TODO(a.garipov): Enable --blank? # TODO(a.garipov): Enable --blank?
run_linter errcheck --asserts ./... errcheck --asserts ./...
run_linter staticcheck ./... staticcheck ./...

View File

@@ -1,10 +1,5 @@
#!/bin/sh #!/bin/sh
# This comment is used to simplify checking local copies of the script. Bump
# this number every time a significant change is made to this script.
#
# AdGuard-Project-Version: 1
verbose="${VERBOSE:-0}" verbose="${VERBOSE:-0}"
readonly verbose readonly verbose
@@ -45,15 +40,8 @@ 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=90s}" timeout_flags="${TIMEOUT_FLAGS:---timeout=30s}"
readonly count_flags cover_flags shuffle_flags timeout_flags readonly count_flags cover_flags shuffle_flags timeout_flags
"$go" test\ "$go" test "$count_flags" "$cover_flags" "$race_flags" "$shuffle_flags" "$timeout_flags"\
"$count_flags"\ "$x_flags" "$v_flags" ./...
"$cover_flags"\
"$shuffle_flags"\
"$race_flags"\
"$timeout_flags"\
"$x_flags"\
"$v_flags"\
./...

View File

@@ -1,27 +1,22 @@
#!/bin/sh #!/bin/sh
# This comment is used to simplify checking local copies of the script. Bump
# this number every time a significant change is made to this script.
#
# AdGuard-Project-Version: 2
verbose="${VERBOSE:-0}" verbose="${VERBOSE:-0}"
readonly verbose readonly verbose
if [ "$verbose" -gt '1' ] if [ "$verbose" -gt '1' ]
then then
set -x set -x
v_flags='-v=1' v_flags='-v'
x_flags='-x=1' x_flags='-x'
elif [ "$verbose" -gt '0' ] elif [ "$verbose" -gt '0' ]
then then
set -x set -x
v_flags='-v=1' v_flags='-v'
x_flags='-x=0' x_flags=''
else else
set +x set +x
v_flags='-v=0' v_flags=''
x_flags='-x=0' x_flags=''
fi fi
readonly v_flags x_flags readonly v_flags x_flags
@@ -32,25 +27,6 @@ readonly go
# TODO(a.garipov): Add goconst? # TODO(a.garipov): Add goconst?
# Remove only the actual binaries in the bin/ directory, as developers may add
# their own scripts there. Most commonly, a script named “go” for tools that
# call the go binary and need a particular version.
rm -f\
bin/errcheck\
bin/fieldalignment\
bin/gocyclo\
bin/gofumpt\
bin/gosec\
bin/govulncheck\
bin/ineffassign\
bin/looppointer\
bin/misspell\
bin/nilness\
bin/shadow\
bin/staticcheck\
bin/unparam\
;
# Reset GOARCH and GOOS to make sure we install the tools for the native # Reset GOARCH and GOOS to make sure we install the tools for the native
# architecture even when we're cross-compiling the main binary, and also to # architecture even when we're cross-compiling the main binary, and also to
# prevent the "cannot install cross-compiled binaries when GOBIN is set" error. # prevent the "cannot install cross-compiled binaries when GOBIN is set" error.
@@ -61,15 +37,14 @@ env\
GOWORK='off'\ GOWORK='off'\
"$go" install\ "$go" install\
--modfile=./internal/tools/go.mod\ --modfile=./internal/tools/go.mod\
"$v_flags"\ $v_flags\
"$x_flags"\ $x_flags\
github.com/fzipp/gocyclo/cmd/gocyclo\ github.com/fzipp/gocyclo/cmd/gocyclo\
github.com/golangci/misspell/cmd/misspell\ github.com/golangci/misspell/cmd/misspell\
github.com/gordonklaus/ineffassign\ github.com/gordonklaus/ineffassign\
github.com/kisielk/errcheck\ github.com/kisielk/errcheck\
github.com/kyoh86/looppointer/cmd/looppointer\ github.com/kyoh86/looppointer/cmd/looppointer\
github.com/securego/gosec/v2/cmd/gosec\ github.com/securego/gosec/v2/cmd/gosec\
golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment\
golang.org/x/tools/go/analysis/passes/nilness/cmd/nilness\ golang.org/x/tools/go/analysis/passes/nilness/cmd/nilness\
golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow\ golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow\
golang.org/x/vuln/cmd/govulncheck\ golang.org/x/vuln/cmd/govulncheck\

View File

@@ -1,84 +0,0 @@
#!/bin/sh
# Common script helpers
#
# This file contains common script helpers. It should be sourced in scripts
# right after the initial environment processing.
# This comment is used to simplify checking local copies of the script. Bump
# this number every time a remarkable change is made to this script.
#
# AdGuard-Project-Version: 2
# Deferred helpers
not_found_msg='
looks like a binary not found error.
make sure you have installed the linter binaries using:
$ make go-tools
'
readonly not_found_msg
not_found() {
if [ "$?" -eq '127' ]
then
# Code 127 is the exit status a shell uses when a command or a file is
# not found, according to the Bash Hackers wiki.
#
# See https://wiki.bash-hackers.org/dict/terms/exit_status.
echo "$not_found_msg" 1>&2
fi
}
trap not_found EXIT
# Helpers
# run_linter runs the given linter with two additions:
#
# 1. If the first argument is "-e", run_linter exits with a nonzero exit code
# if there is anything in the command's combined output.
#
# 2. In any case, run_linter adds the program's name to its combined output.
run_linter() (
set +e
if [ "$VERBOSE" -lt '2' ]
then
set +x
fi
cmd="${1:?run_linter: provide a command}"
shift
exit_on_output='0'
if [ "$cmd" = '-e' ]
then
exit_on_output='1'
cmd="${1:?run_linter: provide a command}"
shift
fi
readonly cmd
output="$( "$cmd" "$@" )"
exitcode="$?"
readonly output
if [ "$output" != '' ]
then
echo "$output" | sed -e "s/^/${cmd}: /"
if [ "$exitcode" -eq '0' ] && [ "$exit_on_output" -eq '1' ]
then
exitcode='1'
fi
fi
return "$exitcode"
)

View File

@@ -1,13 +1,9 @@
#!/bin/sh #!/bin/sh
# This comment is used to simplify checking local copies of the script. Bump
# this number every time a remarkable change is made to this script.
#
# AdGuard-Project-Version: 2
verbose="${VERBOSE:-0}" verbose="${VERBOSE:-0}"
readonly verbose readonly verbose
# Set verbosity.
if [ "$verbose" -gt '0' ] if [ "$verbose" -gt '0' ]
then then
set -x set -x
@@ -24,9 +20,31 @@ fi
# We don't need glob expansions and we want to see errors about unset variables. # We don't need glob expansions and we want to see errors about unset variables.
set -f -u set -f -u
# Source the common helpers, including not_found.
. ./scripts/make/helper.sh
# Deferred Helpers
not_found_msg='
looks like a binary not found error.
make sure you have installed the linter binaries using:
$ make go-tools
'
readonly not_found_msg
# TODO(a.garipov): Put it into a separate script and source it both here and in
# go-lint.sh?
not_found() {
if [ "$?" -eq '127' ]
then
# Code 127 is the exit status a shell uses when a command or
# a file is not found, according to the Bash Hackers wiki.
#
# See https://wiki.bash-hackers.org/dict/terms/exit_status.
echo "$not_found_msg" 1>&2
fi
}
trap not_found EXIT
git ls-files -- '*.md' '*.yaml' '*.yml' 'client/src/__locales/en.json'\ git ls-files -- '*.md' '*.yaml' '*.yml' 'client/src/__locales/en.json'\
| xargs misspell --error\ | xargs misspell --error
| sed -e 's/^/misspell: /'