Compare commits
3 Commits
v0.108.0-b
...
4728-cap-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3918789ca7 | ||
|
|
da1b53a3b4 | ||
|
|
b82c67405f |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
'name': 'build'
|
'name': 'build'
|
||||||
|
|
||||||
'env':
|
'env':
|
||||||
'GO_VERSION': '1.19.6'
|
'GO_VERSION': '1.18.9'
|
||||||
'NODE_VERSION': '14'
|
'NODE_VERSION': '14'
|
||||||
|
|
||||||
'on':
|
'on':
|
||||||
|
|||||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
'name': 'lint'
|
'name': 'lint'
|
||||||
|
|
||||||
'env':
|
'env':
|
||||||
'GO_VERSION': '1.19.6'
|
'GO_VERSION': '1.18.9'
|
||||||
|
|
||||||
'on':
|
'on':
|
||||||
'push':
|
'push':
|
||||||
|
|||||||
130
CHANGELOG.md
130
CHANGELOG.md
@@ -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
|
||||||
|
|||||||
32
Makefile
32
Makefile
@@ -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
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -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.
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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':
|
||||||
|
|||||||
@@ -261,7 +261,7 @@
|
|||||||
"query_log_configuration": "Налада часопіса",
|
"query_log_configuration": "Налада часопіса",
|
||||||
"query_log_disabled": "Часопіс запытаў выключаны, яго можна ўключыць у <0>наладах</0>",
|
"query_log_disabled": "Часопіс запытаў выключаны, яго можна ўключыць у <0>наладах</0>",
|
||||||
"query_log_strict_search": "Ужывайце падвойныя двукоссі для строгага пошуку",
|
"query_log_strict_search": "Ужывайце падвойныя двукоссі для строгага пошуку",
|
||||||
"query_log_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання запытаў? Пры памяншэнні інтэрвалу, некаторыя даныя могуць быць страчаны",
|
"query_log_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання запытаў? Пры скарачэнні інтэрвалу дадзеныя могуць быць згублены",
|
||||||
"anonymize_client_ip": "Ананімізацыя IP-адрасы кліента",
|
"anonymize_client_ip": "Ананімізацыя IP-адрасы кліента",
|
||||||
"anonymize_client_ip_desc": "Не захоўвайце поўныя IP-адрасы гэтых удзельнікаў у часопісах або статыстыцы",
|
"anonymize_client_ip_desc": "Не захоўвайце поўныя IP-адрасы гэтых удзельнікаў у часопісах або статыстыцы",
|
||||||
"dns_config": "Налады DNS-сервера",
|
"dns_config": "Налады DNS-сервера",
|
||||||
@@ -356,7 +356,7 @@
|
|||||||
"install_devices_android_list_5": "Зараз можна змяніць палі «DNS 1» і «DNS 2». Увядзіце ў іх адрасы AdGuard Home.",
|
"install_devices_android_list_5": "Зараз можна змяніць палі «DNS 1» і «DNS 2». Увядзіце ў іх адрасы AdGuard Home.",
|
||||||
"install_devices_ios_list_1": "Увайдзіце ў меню налад прылады.",
|
"install_devices_ios_list_1": "Увайдзіце ў меню налад прылады.",
|
||||||
"install_devices_ios_list_2": "Абярыце пункт «Wi-Fi» (для мабільных сетак ручная наладка DNS немагчыма).",
|
"install_devices_ios_list_2": "Абярыце пункт «Wi-Fi» (для мабільных сетак ручная наладка DNS немагчыма).",
|
||||||
"install_devices_ios_list_3": "Націсніце на назву актыўнай у дадзены момант сеткі.",
|
"install_devices_ios_list_3": "Націсніце на назву сетцы, да якой прылада падлучана ў дадзены момант.",
|
||||||
"install_devices_ios_list_4": "У поле «DNS» увядзіце ўвядзіце адрасы AdGuard Home.",
|
"install_devices_ios_list_4": "У поле «DNS» увядзіце ўвядзіце адрасы AdGuard Home.",
|
||||||
"get_started": "Паехалі",
|
"get_started": "Паехалі",
|
||||||
"next": "Далей",
|
"next": "Далей",
|
||||||
@@ -517,10 +517,10 @@
|
|||||||
"filter_updated": "Спіс паспяхова абноўлены",
|
"filter_updated": "Спіс паспяхова абноўлены",
|
||||||
"statistics_configuration": "Канфігурацыя статыстыкі",
|
"statistics_configuration": "Канфігурацыя статыстыкі",
|
||||||
"statistics_retention": "Захаванне статыстыкі",
|
"statistics_retention": "Захаванне статыстыкі",
|
||||||
"statistics_retention_desc": "Калі вы паменшыце значэнне інтэрвалу, некаторыя даныя могуць быць страчаны",
|
"statistics_retention_desc": "Калі вы зменшыце значэнне інтэрвалу, некаторыя дадзеныя могуць быць згублены",
|
||||||
"statistics_clear": "Ачысціць статыстыку",
|
"statistics_clear": "Ачысціць статыстыку",
|
||||||
"statistics_clear_confirm": "Вы ўпэўнены, што хочаце ачысціць статыстыку?",
|
"statistics_clear_confirm": "Вы ўпэўнены, што хочаце ачысціць статыстыку?",
|
||||||
"statistics_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання статыстыкі? Пры памяншэнні інтэрвалу, некаторыя даныя могуць быць страчаны",
|
"statistics_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання статыстыкі? Пры скарачэнні інтэрвалу дадзеныя могуць быць згублены",
|
||||||
"statistics_cleared": "Статыстыка паспяхова вычышчана",
|
"statistics_cleared": "Статыстыка паспяхова вычышчана",
|
||||||
"statistics_enable": "Уключыць статыстыку",
|
"statistics_enable": "Уключыць статыстыку",
|
||||||
"interval_hours": "{{count}} гадзіна",
|
"interval_hours": "{{count}} гадзіна",
|
||||||
@@ -598,7 +598,7 @@
|
|||||||
"show_blocked_responses": "Заблакавана",
|
"show_blocked_responses": "Заблакавана",
|
||||||
"show_whitelisted_responses": "Белы спіс",
|
"show_whitelisted_responses": "Белы спіс",
|
||||||
"show_processed_responses": "Апрацавана",
|
"show_processed_responses": "Апрацавана",
|
||||||
"blocked_safebrowsing": "Заблакіравана згодна з базай даных Safe Browsing",
|
"blocked_safebrowsing": "Заблакавана згодна базе дадзеных Safe Browsing",
|
||||||
"blocked_adult_websites": "Заблакавана Бацькоўскім кантролем",
|
"blocked_adult_websites": "Заблакавана Бацькоўскім кантролем",
|
||||||
"blocked_threats": "Заблакавана пагроз",
|
"blocked_threats": "Заблакавана пагроз",
|
||||||
"allowed": "Дазволены",
|
"allowed": "Дазволены",
|
||||||
@@ -639,7 +639,7 @@
|
|||||||
"safe_browsing": "Бяспечны інтэрнэт",
|
"safe_browsing": "Бяспечны інтэрнэт",
|
||||||
"served_from_cache": "{{value}} <i>(атрымана з кэша)</i>",
|
"served_from_cache": "{{value}} <i>(атрымана з кэша)</i>",
|
||||||
"form_error_password_length": "Пароль павінен быць не менш за {{value}} сімвалаў",
|
"form_error_password_length": "Пароль павінен быць не менш за {{value}} сімвалаў",
|
||||||
"anonymizer_notification": "<0>Заўвага:</0> Ананімізацыя IP уключана. Вы можаце адключыць яе ў <1>Агульных наладах</1>.",
|
"anonymizer_notification": "<0>Заўвага:</0> Ананімізацыя IP уключана. Вы можаце адключыць яго ў <1>Агульных наладах</1> .",
|
||||||
"confirm_dns_cache_clear": "Вы ўпэўнены, што хочаце ачысціць кэш DNS?",
|
"confirm_dns_cache_clear": "Вы ўпэўнены, што хочаце ачысціць кэш DNS?",
|
||||||
"cache_cleared": "Кэш DNS паспяхова ачышчаны",
|
"cache_cleared": "Кэш DNS паспяхова ачышчаны",
|
||||||
"clear_cache": "Ачысціць кэш"
|
"clear_cache": "Ачысціць кэш"
|
||||||
|
|||||||
@@ -454,7 +454,7 @@
|
|||||||
"updates_checked": "La nueva versión de AdGuard Home está disponible",
|
"updates_checked": "La nueva versión de AdGuard Home está disponible",
|
||||||
"updates_version_equal": "AdGuard Home está actualizado",
|
"updates_version_equal": "AdGuard Home está actualizado",
|
||||||
"check_updates_now": "Buscar actualizaciones ahora",
|
"check_updates_now": "Buscar actualizaciones ahora",
|
||||||
"version_request_error": "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é"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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.0;AAAA记录:::);被/etc/hosts 规则拦截时反应为规则中指定 IP 地址",
|
"blocking_mode_default": "默认:被 Adblock 规则拦截时反应为零 IP 地址(A记录:0.0.0.0;AAAA记录:::);被/etc/hosts 规则拦截时反应为规则中指定 IP 地址",
|
||||||
"blocking_mode_refused": "REFUSED:以 REFUSED 码响应请求",
|
"blocking_mode_refused": "REFUSED:以 REFUSED 码响应请求",
|
||||||
"blocking_mode_nxdomain": "NXDOMAIN:以NXDOMAIN码响应",
|
"blocking_mode_nxdomain": "NXDOMAIN:以NXDOMAIN码响应",
|
||||||
"blocking_mode_null_ip": "空 IP:以零 IP 地址响应(A 记录 0.0.0.0;AAAA 记录 ::)",
|
"blocking_mode_null_ip": "空IP:以零IP地址响应(A记录 0.0.0.0;AAAA记录 ::)",
|
||||||
"blocking_mode_custom_ip": "自定IP:以手动设置的IP地址响应",
|
"blocking_mode_custom_ip": "自定IP:以手动设置的IP地址响应",
|
||||||
"theme_auto": "自动",
|
"theme_auto": "自动",
|
||||||
"theme_light": "浅色主题",
|
"theme_light": "浅色主题",
|
||||||
@@ -605,7 +605,7 @@
|
|||||||
"filtered": "已过滤",
|
"filtered": "已过滤",
|
||||||
"rewritten": "重写项",
|
"rewritten": "重写项",
|
||||||
"safe_search": "安全搜索",
|
"safe_search": "安全搜索",
|
||||||
"blocklist": "黑名单",
|
"blocklist": "拦截列表",
|
||||||
"milliseconds_abbreviation": "毫秒",
|
"milliseconds_abbreviation": "毫秒",
|
||||||
"cache_size": "缓存大小",
|
"cache_size": "缓存大小",
|
||||||
"cache_size_desc": "DNS 缓存大小(单位:字节)。要关闭缓存,请留空。",
|
"cache_size_desc": "DNS 缓存大小(单位:字节)。要关闭缓存,请留空。",
|
||||||
@@ -626,7 +626,7 @@
|
|||||||
"filter_category_general_desc": "在大多数设备上阻止跟踪和广告的列表",
|
"filter_category_general_desc": "在大多数设备上阻止跟踪和广告的列表",
|
||||||
"filter_category_security_desc": "专用于拦截恶意软件、钓鱼或欺诈域名的列表",
|
"filter_category_security_desc": "专用于拦截恶意软件、钓鱼或欺诈域名的列表",
|
||||||
"filter_category_regional_desc": "专注于区域广告和跟踪服务器的列表",
|
"filter_category_regional_desc": "专注于区域广告和跟踪服务器的列表",
|
||||||
"filter_category_other_desc": "其他黑名单",
|
"filter_category_other_desc": "其他阻止列表",
|
||||||
"setup_config_to_enable_dhcp_server": "设置配置以启用 DHCP 服务器",
|
"setup_config_to_enable_dhcp_server": "设置配置以启用 DHCP 服务器",
|
||||||
"original_response": "原始响应",
|
"original_response": "原始响应",
|
||||||
"click_to_view_queries": "点击查看查询",
|
"click_to_view_queries": "点击查看查询",
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const STATUS_COLORS = {
|
|||||||
export const REPOSITORY = {
|
export const REPOSITORY = {
|
||||||
URL: 'https://github.com/AdguardTeam/AdGuardHome',
|
URL: 'https://github.com/AdguardTeam/AdGuardHome',
|
||||||
TRACKERS_DB:
|
TRACKERS_DB:
|
||||||
'https://github.com/AdguardTeam/AdGuardHome/tree/master/client/src/helpers/trackers/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',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
175
client/src/helpers/trackers/adguard.json
Normal file
175
client/src/helpers/trackers/adguard.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
|
|||||||
@@ -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
41
go.mod
@@ -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
77
go.sum
@@ -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=
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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"},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
38
internal/filtering/blocked_test.go
Normal file
38
internal/filtering/blocked_test.go
Normal 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("];")
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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^",
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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).
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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 },
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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=
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build tools
|
//go:build tools
|
||||||
|
// +build tools
|
||||||
|
|
||||||
package tools
|
package tools
|
||||||
|
|
||||||
|
|||||||
1
main.go
1
main.go
@@ -1,4 +1,5 @@
|
|||||||
//go:build !next
|
//go:build !next
|
||||||
|
// +build !next
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build next
|
//go:build next
|
||||||
|
// +build next
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 ./...
|
||||||
|
|||||||
@@ -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"\
|
|
||||||
./...
|
|
||||||
|
|||||||
@@ -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\
|
||||||
|
|||||||
@@ -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"
|
|
||||||
)
|
|
||||||
@@ -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: /'
|
|
||||||
|
|||||||
Reference in New Issue
Block a user