Compare commits
63 Commits
infra-fix
...
v0.108.0-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c5a7a5544 | ||
|
|
da8132e127 | ||
|
|
2fe2d254b5 | ||
|
|
b92a3cfb89 | ||
|
|
d3dea0f46c | ||
|
|
cc2006f616 | ||
|
|
91270d0b61 | ||
|
|
a4ea6c2233 | ||
|
|
c7b65fa522 | ||
|
|
1a95161784 | ||
|
|
6633ad6304 | ||
|
|
dfa28af907 | ||
|
|
8f75c6ac9d | ||
|
|
446f21a511 | ||
|
|
0b25119c52 | ||
|
|
20e56b7171 | ||
|
|
261c1599a5 | ||
|
|
21945c6058 | ||
|
|
5c15d1bb16 | ||
|
|
efe2ed1304 | ||
|
|
fe07786d2d | ||
|
|
2b55e56306 | ||
|
|
dedbadafc4 | ||
|
|
d3cc2dc930 | ||
|
|
8f53f6505b | ||
|
|
dab608292a | ||
|
|
11dfc7a3e8 | ||
|
|
c234e5dc31 | ||
|
|
3895cfb4f0 | ||
|
|
37b16bcf79 | ||
|
|
4d470f9484 | ||
|
|
a8431297f7 | ||
|
|
9789e5b0fe | ||
|
|
4a49c4db96 | ||
|
|
d578c713ff | ||
|
|
d4ca14806e | ||
|
|
abb738013a | ||
|
|
098cbab7e6 | ||
|
|
d96e65cb0c | ||
|
|
1d6d85cff4 | ||
|
|
ac5a96fada | ||
|
|
6673bb175a | ||
|
|
b1a0f4fa44 | ||
|
|
d06b18a493 | ||
|
|
80ec01dd49 | ||
|
|
47dfa44cf6 | ||
|
|
1d2026bf7e | ||
|
|
e77de2e67d | ||
|
|
e529d29e8a | ||
|
|
41cce62597 | ||
|
|
5b45f6d508 | ||
|
|
73ff401b0f | ||
|
|
6363f8a2e7 | ||
|
|
2c64ab5a51 | ||
|
|
df097341c3 | ||
|
|
4919630ccc | ||
|
|
b32b8f9c7e | ||
|
|
355cec1d7b | ||
|
|
5b5b397132 | ||
|
|
5578987884 | ||
|
|
54a975f584 | ||
|
|
d40de33316 | ||
|
|
e338214ad5 |
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@@ -1,7 +1,7 @@
|
||||
'name': 'build'
|
||||
|
||||
'env':
|
||||
'GO_VERSION': '1.23.1'
|
||||
'GO_VERSION': '1.23.6'
|
||||
'NODE_VERSION': '16'
|
||||
|
||||
'on':
|
||||
@@ -39,7 +39,7 @@
|
||||
'with':
|
||||
'node-version': '${{ env.NODE_VERSION }}'
|
||||
- 'name': 'Set up Go modules cache'
|
||||
'uses': 'actions/cache@v2'
|
||||
'uses': 'actions/cache@v4'
|
||||
'with':
|
||||
'path': '~/go/pkg/mod'
|
||||
'key': "${{ runner.os }}-go-${{ hashFiles('go.sum') }}"
|
||||
@@ -48,7 +48,7 @@
|
||||
'id': 'npm-cache'
|
||||
'run': 'echo "::set-output name=dir::$( npm config get cache )"'
|
||||
- 'name': 'Set up npm cache'
|
||||
'uses': 'actions/cache@v2'
|
||||
'uses': 'actions/cache@v4'
|
||||
'with':
|
||||
'path': '${{ steps.npm-cache.outputs.dir }}'
|
||||
'key': "${{ runner.os }}-node-${{ hashFiles('client/package-lock.json') }}"
|
||||
@@ -80,7 +80,7 @@
|
||||
'with':
|
||||
'node-version': '${{ env.NODE_VERSION }}'
|
||||
- 'name': 'Set up Go modules cache'
|
||||
'uses': 'actions/cache@v2'
|
||||
'uses': 'actions/cache@v4'
|
||||
'with':
|
||||
'path': '~/go/pkg/mod'
|
||||
'key': "${{ runner.os }}-go-${{ hashFiles('go.sum') }}"
|
||||
@@ -89,13 +89,13 @@
|
||||
'id': 'npm-cache'
|
||||
'run': 'echo "::set-output name=dir::$(npm config get cache)"'
|
||||
- 'name': 'Set up npm cache'
|
||||
'uses': 'actions/cache@v2'
|
||||
'uses': 'actions/cache@v4'
|
||||
'with':
|
||||
'path': '${{ steps.npm-cache.outputs.dir }}'
|
||||
'key': "${{ runner.os }}-node-${{ hashFiles('client/package-lock.json') }}"
|
||||
'restore-keys': '${{ runner.os }}-node-'
|
||||
- 'name': 'Set up Snapcraft'
|
||||
'run': 'sudo apt-get -yq --no-install-suggests --no-install-recommends install snapcraft'
|
||||
'run': 'sudo snap install snapcraft --classic'
|
||||
- 'name': 'Set up QEMU'
|
||||
'uses': 'docker/setup-qemu-action@v1'
|
||||
- 'name': 'Set up Docker Buildx'
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -1,7 +1,7 @@
|
||||
'name': 'lint'
|
||||
|
||||
'env':
|
||||
'GO_VERSION': '1.23.1'
|
||||
'GO_VERSION': '1.23.6'
|
||||
|
||||
'on':
|
||||
'push':
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,3 +1,8 @@
|
||||
# This comment is used to simplify checking local copies of the file. Bump
|
||||
# this number every time a significant change is made to this file.
|
||||
#
|
||||
# AdGuard-Project-Version: 1
|
||||
|
||||
# Please, DO NOT put your text editors' temporary files here. The more are
|
||||
# added, the harder it gets to maintain and manage projects' gitignores. Put
|
||||
# them into your global gitignore file instead.
|
||||
@@ -8,6 +13,7 @@
|
||||
# bottom to make sure they take effect.
|
||||
*.db
|
||||
*.log
|
||||
*.out
|
||||
*.snap
|
||||
*.test
|
||||
/agh-backup/
|
||||
@@ -21,6 +27,7 @@
|
||||
/launchpad_credentials
|
||||
/querylog.json*
|
||||
/snapcraft_login
|
||||
/test-reports/
|
||||
AdGuardHome
|
||||
AdGuardHome.exe
|
||||
AdGuardHome.yaml*
|
||||
|
||||
25
.markdownlint.json
Normal file
25
.markdownlint.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"ul-indent": {
|
||||
"indent": 4
|
||||
},
|
||||
"ul-style": {
|
||||
"style": "dash"
|
||||
},
|
||||
"emphasis-style": {
|
||||
"style": "asterisk"
|
||||
},
|
||||
"no-duplicate-heading": {
|
||||
"siblings_only": true
|
||||
},
|
||||
"no-inline-html": {
|
||||
"allowed_elements": [
|
||||
"a"
|
||||
]
|
||||
},
|
||||
"no-trailing-spaces": {
|
||||
"br_spaces": 0
|
||||
},
|
||||
"line-length": false,
|
||||
"no-bare-urls": false,
|
||||
"link-fragments": false
|
||||
}
|
||||
2395
CHANGELOG.md
2395
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
37
Makefile
37
Makefile
@@ -1,14 +1,14 @@
|
||||
# Keep the Makefile POSIX-compliant. We currently allow hyphens in
|
||||
# target names, but that may change in the future.
|
||||
#
|
||||
# See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html.
|
||||
# See https://pubs.opengroup.org/onlinepubs/9799919799/utilities/make.html.
|
||||
.POSIX:
|
||||
|
||||
# This comment is used to simplify checking local copies of the
|
||||
# Makefile. Bump this number every time a significant change is made to
|
||||
# this Makefile.
|
||||
#
|
||||
# AdGuard-Project-Version: 6
|
||||
# AdGuard-Project-Version: 9
|
||||
|
||||
# Don't name these macros "GO" etc., because GNU Make apparently makes
|
||||
# them exported environment variables with the literal value of
|
||||
@@ -22,14 +22,12 @@ VERBOSE.MACRO = $${VERBOSE:-0}
|
||||
|
||||
CHANNEL = development
|
||||
CLIENT_DIR = client
|
||||
COMMIT = $$( git rev-parse --short HEAD )
|
||||
DEPLOY_SCRIPT_PATH = not/a/real/path
|
||||
DIST_DIR = dist
|
||||
GOAMD64 = v1
|
||||
GOPROXY = https://proxy.golang.org|direct
|
||||
GOSUMDB = sum.golang.google.cn
|
||||
GOTOOLCHAIN = go1.23.1
|
||||
GOTELEMETRY = off
|
||||
GOTOOLCHAIN = go1.23.6
|
||||
GPG_KEY = devteam@adguard.com
|
||||
GPG_KEY_PASSPHRASE = not-a-real-password
|
||||
NPM = npm
|
||||
@@ -37,6 +35,7 @@ NPM_FLAGS = --prefix $(CLIENT_DIR)
|
||||
NPM_INSTALL_FLAGS = $(NPM_FLAGS) --quiet --no-progress --ignore-engines\
|
||||
--ignore-optional --ignore-platform --ignore-scripts
|
||||
RACE = 0
|
||||
REVISION = $${REVISION:-$$(git rev-parse --short HEAD)}
|
||||
SIGN = 1
|
||||
SIGNER_API_KEY = not-a-real-key
|
||||
VERSION = v0.0.0
|
||||
@@ -61,28 +60,28 @@ BUILD_RELEASE_DEPS_1 = go-deps
|
||||
|
||||
ENV = env\
|
||||
CHANNEL='$(CHANNEL)'\
|
||||
COMMIT='$(COMMIT)'\
|
||||
DEPLOY_SCRIPT_PATH='$(DEPLOY_SCRIPT_PATH)' \
|
||||
DIST_DIR='$(DIST_DIR)'\
|
||||
GO="$(GO.MACRO)"\
|
||||
GOAMD64='$(GOAMD64)'\
|
||||
GOPROXY='$(GOPROXY)'\
|
||||
GOSUMDB='$(GOSUMDB)'\
|
||||
GOTELEMETRY='$(GOTELEMETRY)'\
|
||||
GOTOOLCHAIN='$(GOTOOLCHAIN)'\
|
||||
GPG_KEY='$(GPG_KEY)'\
|
||||
GPG_KEY_PASSPHRASE='$(GPG_KEY_PASSPHRASE)'\
|
||||
NEXTAPI='$(NEXTAPI)'\
|
||||
PATH="$${PWD}/bin:$$( "$(GO.MACRO)" env GOPATH )/bin:$${PATH}"\
|
||||
RACE='$(RACE)'\
|
||||
REVISION='$(REVISION)'\
|
||||
SIGN='$(SIGN)'\
|
||||
SIGNER_API_KEY='$(SIGNER_API_KEY)' \
|
||||
NEXTAPI='$(NEXTAPI)'\
|
||||
VERBOSE="$(VERBOSE.MACRO)"\
|
||||
VERSION="$(VERSION)"\
|
||||
|
||||
# Keep the line above blank.
|
||||
|
||||
ENV_MISC = env\
|
||||
PATH="$${PWD}/bin:$$("$(GO.MACRO)" env GOPATH)/bin:$${PATH}"\
|
||||
VERBOSE="$(VERBOSE.MACRO)"\
|
||||
|
||||
# Keep the line above blank.
|
||||
@@ -91,6 +90,8 @@ ENV_MISC = env\
|
||||
# full build.
|
||||
build: deps quick-build
|
||||
|
||||
init: ; git config core.hooksPath ./scripts/hooks
|
||||
|
||||
quick-build: js-build go-build
|
||||
|
||||
deps: js-deps go-deps
|
||||
@@ -104,9 +105,6 @@ build-docker: ; $(ENV) "$(SHELL)" ./scripts/make/build-docker.sh
|
||||
build-release: $(BUILD_RELEASE_DEPS_$(FRONTEND_PREBUILT))
|
||||
$(ENV) "$(SHELL)" ./scripts/make/build-release.sh
|
||||
|
||||
clean: ; $(ENV) "$(SHELL)" ./scripts/make/clean.sh
|
||||
init: ; git config core.hooksPath ./scripts/hooks
|
||||
|
||||
js-build: ; $(NPM) $(NPM_FLAGS) run build-prod
|
||||
js-deps: ; $(NPM) $(NPM_INSTALL_FLAGS) ci
|
||||
js-lint: ; $(NPM) $(NPM_FLAGS) run lint
|
||||
@@ -129,17 +127,16 @@ go-check: go-tools go-lint go-test
|
||||
# A quick check to make sure that all operating systems relevant to the
|
||||
# development of the project can be typechecked and built successfully.
|
||||
go-os-check:
|
||||
env GOOS='darwin' "$(GO.MACRO)" vet ./internal/...
|
||||
env GOOS='freebsd' "$(GO.MACRO)" vet ./internal/...
|
||||
env GOOS='openbsd' "$(GO.MACRO)" vet ./internal/...
|
||||
env GOOS='linux' "$(GO.MACRO)" vet ./internal/...
|
||||
env GOOS='windows' "$(GO.MACRO)" vet ./internal/...
|
||||
|
||||
|
||||
openapi-lint: ; cd ./openapi/ && $(YARN) test
|
||||
openapi-show: ; cd ./openapi/ && $(YARN) start
|
||||
$(ENV) GOOS='darwin' "$(GO.MACRO)" vet ./internal/...
|
||||
$(ENV) GOOS='freebsd' "$(GO.MACRO)" vet ./internal/...
|
||||
$(ENV) GOOS='openbsd' "$(GO.MACRO)" vet ./internal/...
|
||||
$(ENV) GOOS='linux' "$(GO.MACRO)" vet ./internal/...
|
||||
$(ENV) GOOS='windows' "$(GO.MACRO)" vet ./internal/...
|
||||
|
||||
txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh
|
||||
|
||||
md-lint: ; $(ENV_MISC) "$(SHELL)" ./scripts/make/md-lint.sh
|
||||
sh-lint: ; $(ENV_MISC) "$(SHELL)" ./scripts/make/sh-lint.sh
|
||||
|
||||
openapi-lint: ; cd ./openapi/ && $(YARN) test
|
||||
openapi-show: ; cd ./openapi/ && $(YARN) start
|
||||
|
||||
@@ -114,7 +114,7 @@ If you're running **Linux,** there's a secure and easy way to install AdGuard Ho
|
||||
|
||||
[Docker Hub]: https://hub.docker.com/r/adguard/adguardhome
|
||||
[Snap Store]: https://snapcraft.io/adguard-home
|
||||
[wiki-start]: https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started
|
||||
[wiki-start]: https://adguard-dns.io/kb/adguard-home/getting-started/
|
||||
|
||||
### <a href="#guides" id="guides" name="guides">Guides</a>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
'variables':
|
||||
'channel': 'edge'
|
||||
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||
'dockerGo': 'adguard/go-builder:1.23.1--1'
|
||||
'dockerGo': 'adguard/go-builder:1.23.6--1'
|
||||
|
||||
'stages':
|
||||
- 'Build frontend':
|
||||
@@ -142,13 +142,15 @@
|
||||
# Install Qemu, create builder.
|
||||
docker version -f '{{ .Server.Experimental }}'
|
||||
docker buildx rm buildx-builder || :
|
||||
docker buildx create --name buildx-builder --driver docker-container\
|
||||
--use
|
||||
docker buildx create \
|
||||
--name buildx-builder \
|
||||
--driver docker-container \
|
||||
--use
|
||||
docker buildx inspect --bootstrap
|
||||
|
||||
# Login to DockerHub.
|
||||
docker login -u="${bamboo.dockerHubUsername}"\
|
||||
-p="${bamboo.dockerHubPassword}"
|
||||
docker login -u="${bamboo.dockerHubUsername}" \
|
||||
-p="${bamboo.dockerHubPassword}"
|
||||
|
||||
# Boot the builder.
|
||||
docker buildx inspect --bootstrap
|
||||
@@ -157,14 +159,14 @@
|
||||
docker info
|
||||
|
||||
# Prepare and push the build.
|
||||
env\
|
||||
CHANNEL="${bamboo.channel}"\
|
||||
COMMIT="${bamboo.repository.revision.number}"\
|
||||
DIST_DIR='dist'\
|
||||
DOCKER_IMAGE_NAME='adguard/adguardhome'\
|
||||
DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true"\
|
||||
VERBOSE='1'\
|
||||
sh ./scripts/make/build-docker.sh
|
||||
env \
|
||||
CHANNEL="${bamboo.channel}" \
|
||||
REVISION="${bamboo.repository.revision.number}" \
|
||||
DIST_DIR='dist' \
|
||||
DOCKER_IMAGE_NAME='adguard/adguardhome' \
|
||||
DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true" \
|
||||
VERBOSE='1' \
|
||||
sh ./scripts/make/build-docker.sh
|
||||
'environment':
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
'final-tasks':
|
||||
@@ -276,7 +278,7 @@
|
||||
'variables':
|
||||
'channel': 'beta'
|
||||
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||
'dockerGo': 'adguard/go-builder:1.23.1--1'
|
||||
'dockerGo': 'adguard/go-builder:1.23.6--1'
|
||||
# release-vX.Y.Z branches are the branches from which the actual final
|
||||
# release is built.
|
||||
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
||||
@@ -292,4 +294,4 @@
|
||||
'variables':
|
||||
'channel': 'release'
|
||||
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||
'dockerGo': 'adguard/go-builder:1.23.1--1'
|
||||
'dockerGo': 'adguard/go-builder:1.23.6--1'
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
'name': 'AdGuard Home - Build and run tests'
|
||||
'variables':
|
||||
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||
'dockerGo': 'adguard/go-builder:1.23.1--1'
|
||||
'dockerGo': 'adguard/go-builder:1.23.6--1'
|
||||
'channel': 'development'
|
||||
|
||||
'stages':
|
||||
@@ -196,5 +196,5 @@
|
||||
# may need to build a few of these.
|
||||
'variables':
|
||||
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||
'dockerGo': 'adguard/go-builder:1.23.1--1'
|
||||
'dockerGo': 'adguard/go-builder:1.23.6--1'
|
||||
'channel': 'candidate'
|
||||
|
||||
@@ -291,7 +291,7 @@
|
||||
"custom_ip": "عنوان IP مخصص",
|
||||
"blocking_ipv4": "حجب عنوان IPv4",
|
||||
"blocking_ipv6": "حجب عنوان IPv6",
|
||||
"blocked_response_ttl": "زمن حظر الاستجابة",
|
||||
"blocked_response_ttl": "حظر استجابة TTL",
|
||||
"blocked_response_ttl_desc": "تحديد عدد الثواني التي يجب على العملاء تخزين الاستجابة التي تمت تصفيتها مؤقتًا",
|
||||
"form_enter_blocked_response_ttl": "أدخل وقت الاستجابة المحظورة TTL (بالثواني)",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
@@ -734,10 +734,10 @@
|
||||
"thursday": "الخميس",
|
||||
"friday": "الجمعة",
|
||||
"saturday": "السبت",
|
||||
"sunday_short": "الاحد",
|
||||
"sunday_short": "الأحد",
|
||||
"monday_short": "الإثنين",
|
||||
"tuesday_short": "الثلاثاء",
|
||||
"wednesday_short": "الاربعاء",
|
||||
"wednesday_short": "الأربعاء",
|
||||
"thursday_short": "الخميس",
|
||||
"friday_short": "الجمعة",
|
||||
"saturday_short": "السبت",
|
||||
|
||||
@@ -159,6 +159,8 @@
|
||||
"dns_over_https": "DNS-пред-HTTPS",
|
||||
"dns_over_quic": "DNS-over-QUIC",
|
||||
"plain_dns": "Обикновен DNS",
|
||||
"theme_light": "Светла тема",
|
||||
"theme_dark": "Тъмна тема",
|
||||
"source_label": "Източник",
|
||||
"found_in_known_domain_db": "Намерен в списъците с домейни.",
|
||||
"category_label": "Категория",
|
||||
@@ -282,6 +284,14 @@
|
||||
"blocklist": "Черен списък",
|
||||
"filter_category_general": "General",
|
||||
"filter_category_security": "Сигурност",
|
||||
"filter_category_other": "Друго",
|
||||
"port_53_faq_link": "Порт 53 често е зает от \"DNSStubListener\" или \"systemd-resolved\" услуги. Моля, прочетете <0>тази инструкция</0> как да решите това.",
|
||||
"parental_control": "Родителски контрол"
|
||||
"parental_control": "Родителски контрол",
|
||||
"sunday_short": "Нд",
|
||||
"monday_short": "Пон",
|
||||
"tuesday_short": "Вт",
|
||||
"wednesday_short": "Ср",
|
||||
"thursday_short": "Чт",
|
||||
"friday_short": "Пт",
|
||||
"saturday_short": "Съб"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Použijte paralelní požadavky na urychlení řešení simultánním dotazováním na všechny navazující servery.",
|
||||
"parallel_requests": "Paralelní požadavky",
|
||||
"load_balancing": "Optimalizace vytížení",
|
||||
"load_balancing_desc": "Dotazy jednoho odchozího serveru ve stejný čas. AdGuard Home používá náhodný algoritmus pro výběr serverů s nejnižším počtem neúspěšných vyhledávání a nejnižší průměrnou dobou vyhledávání.",
|
||||
"load_balancing_desc": "Dotazy jednoho odchozího serveru ve stejný čas.<br/>AdGuard Home používá náhodný algoritmus pro výběr serverů s nejnižším počtem neúspěšných vyhledávání a nejnižší průměrnou dobou vyhledávání.",
|
||||
"bootstrap_dns": "Bootstrap DNS servery",
|
||||
"bootstrap_dns_desc": "IP adresy DNS serverů používaných k překladu IP adres řešitelů DoH/DoT, které zadáte jako odchozí servery. Komentáře nejsou povoleny.",
|
||||
"fallback_dns_title": "Záložní DNS servery",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Použít službu AdGuard Rodičovská kontrola",
|
||||
"use_adguard_parental_hint": "AdGuard Home zkontroluje, zda doména obsahuje materiály pro dospělé. Používá stejné API přátelské k ochraně osobních údajů jako služba Bezpečnost prohlížení.",
|
||||
"enforce_safe_search": "Použít bezpečné vyhledávání",
|
||||
"enforce_save_search_hint": "AdGuard Home vynutí bezpečné vyhledávání v následujících vyhledávačích: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home vynutí bezpečné vyhledávání v následujících vyhledávačích: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Nebyly specifikovány žádné servery",
|
||||
"general_settings": "Obecná nastavení",
|
||||
"dns_settings": "Nastavení DNS",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "TTL blokované odezvy",
|
||||
"blocked_response_ttl_desc": "Určuje, na kolik sekund by měli klienti ukládat filtrovanou odezvu do mezipaměti",
|
||||
"form_enter_blocked_response_ttl": "Zadejte TTL blokované odezvy (v sekundách)",
|
||||
"upstream_timeout": "Časový limit odchozího serveru",
|
||||
"upstream_timeout_desc": "Určuje počet sekund čekání na odpověď od odchozího serveru",
|
||||
"form_enter_upstream_timeout": "Zadejte dobu časového limitu odchozího serveru v sekundách",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS skrze HTTPS",
|
||||
"dns_over_tls": "DNS skrze TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "Zakázat řešení IPv6 adres",
|
||||
"disable_ipv6_desc": "Odstranění všech dotazů DNS na adresy IPv6 (typ AAAA) a odstranění náznaků IPv6 z odpovědí HTTPS.",
|
||||
"fastest_addr": "Nejrychlejší IP adresa",
|
||||
"fastest_addr_desc": "Dotazovat všechny DNS servery a vrátit nejrychlejší IP adresu ze všech odpovědí. To zpomalí dotazy DNS, protože AdGuard Home musí čekat na odpovědi ze všech serverů DNS, ale celková konektivita se zlepší.",
|
||||
"fastest_addr_desc": "Počká na odpovědi <b>všech</b> serverů DNS, změří rychlost připojení TCP pro každý server a vrátí IP adresu serveru s nejvyšší rychlostí připojení.<br/>Tento režim může výrazně zpomalit dotazy DNS, pokud jeden nebo více odchozích serverů neodpovídá. Ujistěte se, že vaše odchozí servery jsou stabilní a že časový limit odchozích serverů je nízký.",
|
||||
"autofix_warning_text": "Pokud kliknete na „Opravit“, AdGuard Home nakonfiguruje váš systém tak, aby používal DNS server AdGuard Home.",
|
||||
"autofix_warning_list": "Jsou prováděny následující úlohy: <0>Deaktivace systému DNSStubListener</0> <0>Nastavení adresy serveru DNS na 127.0.0.1</0> <0>Nahrazení cíle symbolického odkazu z /etc/resolv.conf do /run/systemd/resolve/resolv.conf</0> <0>Zastavení služby DNSStubListener (znovu načtení služby systemd-resolved)</0>",
|
||||
"autofix_warning_result": "Výsledkem je, že všechny požadavky DNS z vašeho systému jsou ve výchozím nastavení zpracovány službou AdGuard Home.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Brug parallelforespørgsler til at accelerere fortolkningen ved at forespørge alle upstream-servere samtidigt.",
|
||||
"parallel_requests": "Parallelle forespørgsler",
|
||||
"load_balancing": "Belastningsfordeling",
|
||||
"load_balancing_desc": "Forespørg én upstream-server ad gangen. AdGuard Home bruger en vægtet tilfældighedsalgoritme til vælg af servere med det laveste antal fejlslagne opslag og den laveste gennemsnitlige opslagstid.",
|
||||
"load_balancing_desc": "Forespørg én upstream-server ad gangen.<br/>AdGuard Home bruger en vægtet tilfældighedsalgoritme til vælg af servere med det laveste antal fejlslagne opslag og den laveste gennemsnitlige opslagstid.",
|
||||
"bootstrap_dns": "Bootstrap DNS-servere",
|
||||
"bootstrap_dns_desc": "IP-adresser på DNS-servere, som bruges til at opløse IP-adresser på de DoH/DoT-opløsere, som angives som upstreams. Kommentarer er ikke tilladt.",
|
||||
"fallback_dns_title": "Reserve DNS-servere",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Brug AdGuards forældrekontrolwebtjeneste",
|
||||
"use_adguard_parental_hint": "AdGuard Home vil tjekke, om domænet indeholder voksenindhold vha. den samme fortrolighedsvenlige API som browsingsikkerhedswebtjenesten.",
|
||||
"enforce_safe_search": "Brug sikker søgning",
|
||||
"enforce_save_search_hint": "AdGuard Home vil håndhæve sikker søgning i flg. søgemaskiner: Google, YouTube, Bing, DuckDuckGo, Yandex og Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home vil håndhæve sikker søgning i flg. søgemaskiner: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Ingen servere angivet",
|
||||
"general_settings": "Generelle indstillinger",
|
||||
"dns_settings": "DNS-indstillinger",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "Blokeret svar TTL",
|
||||
"blocked_response_ttl_desc": "Angiver, i hvor mange sekunder klienterne skal cache-lagre et filtreret svar",
|
||||
"form_enter_blocked_response_ttl": "Angiv blokeringssvar TTL (sekunder)",
|
||||
"upstream_timeout": "Upstream-timeout",
|
||||
"upstream_timeout_desc": "Angiver antallet af sekunder, der skal ventes på et svar fra upstream-serveren",
|
||||
"form_enter_upstream_timeout": "Angiv varigheden af upstream-server timeout i sekunder",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
"dns_over_tls": "DNS-over-TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "Deaktivér IPv6-adresseopløsning",
|
||||
"disable_ipv6_desc": "Drop alle DNS-forespørgsler for IPv6-adresser (type AAAA), og fjern IPv6-tips fra HTTPS-svar.",
|
||||
"fastest_addr": "Hurtigste IP-adresse",
|
||||
"fastest_addr_desc": "Forespørger alle DNS-servere og returner den hurtigste IP-adresse blandt alle svar. Dette vil gøre DNS-forespørgslerne langsommere grundet afventning af svar fra alle DNS-servere, men forbedrer samlet set forbindelsen.",
|
||||
"fastest_addr_desc": "Vent på svar fra <b>alle</b> DNS-servere, mål TCP-forbindelseshastigheden for hver server, og returner IP-adressen på serveren med den hurtigste forbindelseshastighed.<br/>Denne tilstand kan sinke DNS-forespørgsler, betydeligt hvis en eller flere upstream-servere ikke svarer. Sørg for, at upstream-serverene er stabile, og at upstream-timeouten er lav.",
|
||||
"autofix_warning_text": "Klikker du på \"Reparér\", opsætter AdGuard Home dit system til brug med AdGuard Home DNS-server.",
|
||||
"autofix_warning_list": "Den vil udføre disse opgaver: <0>Deaktivere system DNSStubListener</0> <0>Opsætte DNS-serveradressen til 127.0.0.1</0> <0>Erstatte symbolsk linkmål for /etc/resolv.conf med /run/systemd/resolve/resolv.conf</0> <0>Stoppe DNSStubListener (genindlæs systemd-opløst tjeneste)</0>",
|
||||
"autofix_warning_result": "Det betyder, at alle DNS-forespørgsler fra dit system som standard behandles af AdGuard Home.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Parallele Abfragen verwenden, um das Auflösen zu beschleunigen, indem alle Upstream-Server gleichzeitig abgefragt werden.",
|
||||
"parallel_requests": "Paralleles Abfragen",
|
||||
"load_balancing": "Lastverteilung",
|
||||
"load_balancing_desc": "Es wird jeweils ein Upstream-Server abgefragt. AdGuard Home verwendet einen gewichteten Zufallsalgorithmus, um die Server mit der geringsten Anzahl an fehlgeschlagenen Suchvorgängen und der niedrigsten durchschnittlichen Suchzeit auszuwählen.",
|
||||
"load_balancing_desc": "Es wird jeweils ein Upstream-Server abgefragt.<br/> AdGuard Home verwendet einen gewichteten Zufallsalgorithmus, um die Server mit der geringsten Anzahl an fehlgeschlagenen Suchvorgängen und der niedrigsten durchschnittlichen Suchzeit auszuwählen.",
|
||||
"bootstrap_dns": "Bootstrap-DNS-Server",
|
||||
"bootstrap_dns_desc": "IP-Adressen der DNS-Server, die zum Auflösen der IP-Adressen von DoH/DoT Upstream-Servern verwendet werden, die Sie angegeben haben. Kommentare sind nicht erlaubt.",
|
||||
"fallback_dns_title": "Fallback-DNS-Server",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "AdGuard Webservice für Kindersicherung verwenden",
|
||||
"use_adguard_parental_hint": "AdGuard Home wird prüfen, ob die Domain jugendgefährdende Inhalte enthält. Zum Schutz Ihrer Privatsphäre wird die selbe API wie für den Webservice für Internetsicherheit verwendet.",
|
||||
"enforce_safe_search": "Sichere Suche verwenden",
|
||||
"enforce_save_search_hint": "AdGuard kann Sichere Suche für folgende Suchmaschinen erzwingen: Google, YouTube, Bing, DuckDuckGo, Yandex und Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard kann Sichere Suche für folgende Suchmaschinen erzwingen: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex und Pixabay.",
|
||||
"no_servers_specified": "Keine Server festgelegt",
|
||||
"general_settings": "Allgemeine Einstellungen",
|
||||
"dns_settings": "DNS-Einstellungen",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "Gültigkeitsdauer der blockierten Antwort",
|
||||
"blocked_response_ttl_desc": "Gibt an, wie viele Sekunden lang die Clients eine gefilterte Antwort zwischenspeichern sollen",
|
||||
"form_enter_blocked_response_ttl": "Geben Sie die Gültigkeitsdauer für blockierte Antworten ein (in Sekunden)",
|
||||
"upstream_timeout": "Upstream-Timeout",
|
||||
"upstream_timeout_desc": "Gibt die Anzahl der Sekunden an, die auf eine Antwort des Upstream-Servers gewartet werden soll",
|
||||
"form_enter_upstream_timeout": "Geben Sie die Timeout-Dauer des Upstream-Servers in Sekunden ein",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
"dns_over_tls": "DNS-over-TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "IPv6 deaktivieren",
|
||||
"disable_ipv6_desc": "Alle DNS-Anfragen für IPv6-Adressen (Typ AAAA) verwerfen und IPv6-Hinweise aus HTTPS-Antworten entfernen.",
|
||||
"fastest_addr": "Schnellste IP-Adresse",
|
||||
"fastest_addr_desc": "Fragen Sie alle DNS-Server ab und geben Sie die schnellste IP-Adresse unter allen Antworten zurück. Dies verlangsamt DNS-Abfragen, da AdGuard Home auf Antworten von allen DNS-Servern warten muss, verbessert jedoch die Gesamtkonnektivität.",
|
||||
"fastest_addr_desc": "Auf Antworten von <b>allen</b> DNS-Servern warten, die TCP-Verbindungsgeschwindigkeit für jeden Server messen und die IP-Adresse des Servers mit der schnellsten Verbindungsgeschwindigkeit zurückgeben.<br/>Dieser Modus kann DNS-Anfragen erheblich verlangsamen, wenn ein oder mehrere Server nicht antworten. Stellen Sie sicher, dass Ihre Server stabil laufen und das Upstream-Timeout niedrig ist.",
|
||||
"autofix_warning_text": "Wenn Sie auf „Beheben“ klicken, konfiguriert AdGuardHome Ihr System für die Verwendung des AdGuardHome-DNS-Servers.",
|
||||
"autofix_warning_list": "Es werden folgende Aufgaben ausgeführt: <0>Deaktivieren des DNSStubListener-Systems</0> <0>Festlegen der DNS-Server-Adresse auf 127.0.0.1</0> <0>Ersetzen des symbolischen Linkziels von /etc/resolv.conf auf /run/systemd/resolve/resolv.conf</0> <0>Anhalten des DNSStubListener (systemseitig aufgelöster Dienst wird nachladen)</0>",
|
||||
"autofix_warning_result": "Als Folge daraus werden alle DNS-Anforderungen von Ihrem System standardmäßig von AdGuardHome verarbeitet.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Use parallel queries to speed up resolving by querying all upstream servers simultaneously.",
|
||||
"parallel_requests": "Parallel requests",
|
||||
"load_balancing": "Load-balancing",
|
||||
"load_balancing_desc": "Query one upstream server at a time. AdGuard Home uses a weighted random algorithm to select servers with the lowest number of failed lookups and the lowest average lookup time.",
|
||||
"load_balancing_desc": "Query one upstream server at a time.<br/>AdGuard Home uses a weighted random algorithm to select servers with the lowest number of failed lookups and the lowest average lookup time.",
|
||||
"bootstrap_dns": "Bootstrap DNS servers",
|
||||
"bootstrap_dns_desc": "IP addresses of DNS servers used to resolve IP addresses of the DoH/DoT resolvers you specify as upstreams. Comments are not permitted.",
|
||||
"fallback_dns_title": "Fallback DNS servers",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "Blocked response TTL",
|
||||
"blocked_response_ttl_desc": "Specifies for how many seconds the clients should cache a filtered response",
|
||||
"form_enter_blocked_response_ttl": "Enter blocked response TTL (seconds)",
|
||||
"upstream_timeout": "Upstream timeout",
|
||||
"upstream_timeout_desc": "Specifies the number of seconds to wait for a response from the upstream server",
|
||||
"form_enter_upstream_timeout": "Enter the upstream server timeout duration in seconds",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
"dns_over_tls": "DNS-over-TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "Disable resolving of IPv6 addresses",
|
||||
"disable_ipv6_desc": "Drop all DNS queries for IPv6 addresses (type AAAA) and remove IPv6 hints from HTTPS responses.",
|
||||
"fastest_addr": "Fastest IP address",
|
||||
"fastest_addr_desc": "Query all DNS servers and return the fastest IP address among all responses. This slows down DNS queries as AdGuard Home has to wait for responses from all DNS servers, but improves the overall connectivity.",
|
||||
"fastest_addr_desc": "Wait for responses from <b>all</b> DNS servers, measure the TCP connection speed for each server, and return the IP address of the server with the fastest connection speed.<br/>This mode can significantly slow down DNS queries, if one or more upstream servers are not responding. Make sure that your upstream servers are stable and your upstream timeout is low.",
|
||||
"autofix_warning_text": "If you click \"Fix\", AdGuard Home will configure your system to use AdGuard Home DNS server.",
|
||||
"autofix_warning_list": "It will perform these tasks: <0>Deactivate system DNSStubListener</0> <0>Set DNS server address to 127.0.0.1</0> <0>Replace symbolic link target of /etc/resolv.conf with /run/systemd/resolve/resolv.conf</0> <0>Stop DNSStubListener (reload systemd-resolved service)</0>",
|
||||
"autofix_warning_result": "As a result all DNS requests from your system will be processed by AdGuard Home by default.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Usar consultas paralelas para acelerar la resolución al consultar simultáneamente a todos los servidores DNS de subida.",
|
||||
"parallel_requests": "Consultas paralelas",
|
||||
"load_balancing": "Balanceo de carga",
|
||||
"load_balancing_desc": "Consulta un servidor upstream a la vez. AdGuard Home utiliza un algoritmo aleatorio ponderado para seleccionar los servidores con el menor número de fallos y el menor tiempo medio de búsqueda.",
|
||||
"load_balancing_desc": "Consulta un servidor Dns upstream a la vez.<br/>AdGuard Home utiliza un algoritmo aleatorio ponderado para seleccionar los servidores con el menor número de fallos y el menor tiempo medio de búsqueda.",
|
||||
"bootstrap_dns": "Servidores DNS de arranque",
|
||||
"bootstrap_dns_desc": "Direcciones IP de servidores DNS utilizadas para resolver direcciones IP de los solucionadores DoH/DoT que especifiques como ascendentes. No se permiten comentarios.",
|
||||
"fallback_dns_title": "Servidores DNS alternativos",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Usar el control parental de AdGuard",
|
||||
"use_adguard_parental_hint": "AdGuard Home comprobará si el dominio contiene materiales para adultos. Utiliza la misma API amigable con la privacidad del servicio web de seguridad de navegación.",
|
||||
"enforce_safe_search": "Usar búsqueda segura",
|
||||
"enforce_save_search_hint": "AdGuard Home reforzará la búsqueda segura en los siguientes motores de búsqueda: Google, YouTube, Bing, DuckDuckGo, Yandex y Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home reforzará la búsqueda segura en los siguientes motores de búsqueda: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex y Pixabay.",
|
||||
"no_servers_specified": "No hay servidores especificados",
|
||||
"general_settings": "Configuración general",
|
||||
"dns_settings": "Configuración del DNS",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "Respuesta TTL bloqueada",
|
||||
"blocked_response_ttl_desc": "Especifica durante cuántos segundos los clientes deben almacenar en cache una respuesta filtrada",
|
||||
"form_enter_blocked_response_ttl": "Ingresa el TTL de respuesta bloqueada (segundos)",
|
||||
"upstream_timeout": "Tiempo de espera del upstream",
|
||||
"upstream_timeout_desc": "Especifica el número de segundos que se debe esperar para recibir una respuesta del servidor upstream",
|
||||
"form_enter_upstream_timeout": "Ingresa la duración del tiempo de espera del servidor DNS upstream en segundos",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS mediante HTTPS",
|
||||
"dns_over_tls": "DNS mediante TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "Deshabilitar resolución de direcciones IPv6",
|
||||
"disable_ipv6_desc": "Descarta todas las consultas de DNS para direcciones IPv6 (tipo AAAA) y elimina las sugerencias de IPv6 de las respuestas HTTPS.",
|
||||
"fastest_addr": "Dirección IP más rápida",
|
||||
"fastest_addr_desc": "Consulta todos los servidores DNS y devuelve la dirección IP más rápida de todas las respuestas. Esto ralentiza las consultas DNS ya que AdGuard Home tiene que esperar las respuestas de todos los servidores DNS, pero mejora la conectividad general.",
|
||||
"fastest_addr_desc": "Espera a que respondan <b>todos</b> los servidores DNS, mide la velocidad de conexión TCP de cada servidor y devuelve la Dirección IP del servidor con la velocidad de conexión más rápida.<br/>Este modo puede ralentizar significativamente las consultas DNS, si uno o más servidores DNS de upstream no están respondiendo. Asegúrate de que tus servidores DNS upstream sean estables y tu tiempo de espera de upstream sea bajo.",
|
||||
"autofix_warning_text": "Si haces clic en \"Corregir\", AdGuard Home configurará tu sistema para utilizar el servidor DNS de AdGuard Home.",
|
||||
"autofix_warning_list": "Realizará estas tareas: <0>Deshabilitar el sistema DNSStubListener</0> <0>Establecer la dirección del servidor DNS en 127.0.0.1</0> <0>Reemplazar el destino del enlace simbólico de /etc/resolv.conf por /run/systemd/resolve/resolv.conf</0> <0>Detener DNSStubListener (recargar el servicio systemd-resolved)</0>",
|
||||
"autofix_warning_result": "Como resultado, todas las peticiones DNS de tu sistema serán procesadas por AdGuard Home de manera predeterminada.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Käytä rinnakkaisia pyyntöjä ja nopeuta selvitystä käyttämällä kaikkia ylävirtapalvelimia samanaikaisesti.",
|
||||
"parallel_requests": "Rinnakkaiset pyynnöt",
|
||||
"load_balancing": "Kuormantasaus",
|
||||
"load_balancing_desc": "Lähetä pyyntö yhdelle ylävirtapalvelimelle kerrallaan. AdGuard Home pyrkii valitsemaan nopeimman palvelimen painotetun satunnaisalgoritminsa avulla.",
|
||||
"load_balancing_desc": "Lähetä kysely kerrallaan yhdelle ylävirtapalvelimelle. AdGuard Home valitsee painotetun satunnaisalgoritmin avulla palvelimet, joilla on vähiten epäonnistuneita hakuja ja keskimääräisesti lyhin hakuaika.",
|
||||
"bootstrap_dns": "Bootstrap DNS-palvelimet",
|
||||
"bootstrap_dns_desc": "Ylävirroiksi määrittämiesi DoH/DoT-resolverien IP-osoitteiden selvitykseen käytettävien DNS-palvelimien IP-osoitteet. Kommentteja ei sallita.",
|
||||
"fallback_dns_title": "DNS-varapalvelimet",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Käytä AdGuardin lapsilukko-palvelua",
|
||||
"use_adguard_parental_hint": "AdGuard Home tarkistaa, sisältääkö verkkotunnus aikuisille tarkoitettua sisältöä. Se käyttää samaa tietosuojapainotteista rajapintaa, kuin turvallisen selauksen palvelu.",
|
||||
"enforce_safe_search": "Käytä turvallista hakua",
|
||||
"enforce_save_search_hint": "AdGuard Home voi pakottaa turvallisen haun käyttöön seuraavissa hakukoneissa: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home pakottaa turvallisen haun käyttöön seuraavissa hakukoneissa: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex ja Pixabay.",
|
||||
"no_servers_specified": "Palvelimia ei ole määritetty",
|
||||
"general_settings": "Yleiset asetukset",
|
||||
"dns_settings": "DNS-asetukset",
|
||||
@@ -542,7 +542,7 @@
|
||||
"stats_params": "Tilastoinnin määritys",
|
||||
"config_successfully_saved": "Asetukset tallennettiin",
|
||||
"interval_6_hour": "6 tuntia",
|
||||
"interval_24_hour": "24 tuntia",
|
||||
"interval_24_hour": "24 tunnilta",
|
||||
"interval_days": "{{count}} päivä",
|
||||
"interval_days_plural": "{{count}} päivää",
|
||||
"domain": "Verkkotunnus",
|
||||
@@ -709,9 +709,9 @@
|
||||
"log_and_stats_section_label": "Pyyntöhistoria ja tilastot",
|
||||
"ignore_query_log": "Älä huomioi tätä päätelaitetta pyyntöhistoriassa",
|
||||
"ignore_statistics": "Älä huomioi tätä päätettä tilastoissa",
|
||||
"schedule_services": "Keskeytä palveluesto",
|
||||
"schedule_services_desc": "Määritä palvelunestosuodattimen keskeytysajoitus.",
|
||||
"schedule_services_desc_client": "Määritä palvelunestosuodattimen keskeytysajoitus tälle päätteelle.",
|
||||
"schedule_services": "Pysäytä palveluesto",
|
||||
"schedule_services_desc": "Määritä palvelunestosuodattimen pysäytysajoitus.",
|
||||
"schedule_services_desc_client": "Määritä palvelunestosuodattimen pysäytysajoitus tälle päätteelle.",
|
||||
"schedule_desc": "Aseta estettujen palveluiden käyttämättömyysjaksot",
|
||||
"schedule_invalid_select": "Aloitusaika on oltava ennen lopetusaikaa",
|
||||
"schedule_select_days": "Valitse päivät",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Utilisez des requêtes parallèles pour accélérer la résolution en requêtant simultanément tous les serveurs en amont.",
|
||||
"parallel_requests": "Requêtes en parallèle",
|
||||
"load_balancing": "Équilibrage de charge",
|
||||
"load_balancing_desc": "Une requête par serveur en amont à la fois. AdGuard Home utilise un algorithme aléatoire pondéré pour sélectionner les serveurs avec le plus petit nombre d'échecs de recherche et le temps de recherche moyen le plus bas.",
|
||||
"load_balancing_desc": "Une requête par serveur en amont à la fois.<br/>AdGuard Home utilise un algorithme aléatoire pondéré pour sélectionner les serveurs avec le plus petit nombre d'échecs de recherche et le temps de recherche moyen le plus bas.",
|
||||
"bootstrap_dns": "Serveurs DNS d'amorçage",
|
||||
"bootstrap_dns_desc": "Les adresses IP des serveurs DNS utilisées pour résoudre les adresses IP des résolveurs DoH/DoT que vous spécifiez comme en amont. Les commentaires ne sont pas autorisés.",
|
||||
"fallback_dns_title": "Serveurs DNS de repli",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Utiliser le contrôle parental d'AdGuard",
|
||||
"use_adguard_parental_hint": "AdGuard Home va vérifier s'il y a du contenu pour adultes sur le domaine. Ce sera fait par aide du même API discret que celui utilisé par le service de Sécurité de navigation.",
|
||||
"enforce_safe_search": "Utiliser la Recherche Sécurisée",
|
||||
"enforce_save_search_hint": "AdGuard Home appliquera la recherche sécurisée dans les moteurs de recherche suivants : Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home appliquera la recherche sécurisée dans les moteurs de recherche suivants : Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Pas de serveurs spécifiés",
|
||||
"general_settings": "Paramètres généraux",
|
||||
"dns_settings": "Paramètres DNS",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "Réponse bloquée TTL",
|
||||
"blocked_response_ttl_desc": "Spécifie pendant combien de secondes les clients doivent mettre en cache une réponse filtrée",
|
||||
"form_enter_blocked_response_ttl": "Saisir le TTL de la réponse bloquée (secondes)",
|
||||
"upstream_timeout": "Délai d'attente en amont",
|
||||
"upstream_timeout_desc": "Spécifie le nombre de secondes à attendre pour une réponse du serveur en amont",
|
||||
"form_enter_upstream_timeout": "Saisir le délai d'attente du serveur en amont en secondes",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
"dns_over_tls": "DNS-over-TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "Désactiver la résolution des adresses IPv6",
|
||||
"disable_ipv6_desc": "Supprimer toutes les requêtes DNS pour les adresses IPv6 (type AAAA) et supprimer les indices IPv6 des réponses HTTPS.",
|
||||
"fastest_addr": "Adresse IP la plus rapide",
|
||||
"fastest_addr_desc": "Rechercher tous les serveurs DNS et renvoyer l’adresse IP la plus rapide parmi toutes les réponses. Cela ralentit les requêtes DNS car AdGuard Home doit attendre les réponses de tous les serveurs DNS, mais la connectivité globale s'améliore.",
|
||||
"fastest_addr_desc": "Attente les réponses de <b>tous</b> les serveurs DNS, mesure de la vitesse de connexion TCP pour chaque serveur et renvoi de l'adresse IP du serveur avec la vitesse de connexion la plus rapide.<br/>Ce mode peut considérablement ralentir les requêtes DNS, si un ou plusieurs serveurs en amont ne répondent pas. Assurez-vous que vos serveurs en amont sont stables et que votre délai dépassé en amont est faible.",
|
||||
"autofix_warning_text": "Si vous cliquez sur « Réparer », AdGuard Home configurera votre système pour utiliser le serveur DNS AdGuard Home.",
|
||||
"autofix_warning_list": "Ceci effectuera les tâches suivantes : <0>Désactiver le système DNSStubListener</0> <0>Définir l’adresse du serveur DNS à 127.0.0.1 </0> <0>Remplacer la cible du lien symbolique de /etc/resolv.conf par /run/systemd/resolve/resolv.conf</0> <0>Arrêter DNSStubListener (recharger le service résolu par systemd)</0>",
|
||||
"autofix_warning_result": "Par conséquent, toutes les demandes DNS de votre système seront traitées par AdGuardHome par défaut.",
|
||||
@@ -676,7 +679,7 @@
|
||||
"filter_allowlist": "ATTENTION : Cette action exclura également la règle « {{disallowed_rule}} » de la liste des clients autorisés.",
|
||||
"last_rule_in_allowlist": "Impossible d’interdire ce client, car l’exclusion de la règle « {{disallowed_rule}} » DÉSACTIVERA la liste des « clients autorisés ».",
|
||||
"use_saved_key": "Utiliser la clef précédemment enregistrée",
|
||||
"parental_control": "Contrôle parental",
|
||||
"parental_control": "Contrôle Parental",
|
||||
"safe_browsing": "Navigation sécurisée",
|
||||
"served_from_cache_label": "Servi depuis le cache",
|
||||
"form_error_password_length": "Le mot de passe doit comporter entre {{min}} et {{max}} caractères",
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
{
|
||||
"client_settings": "Pengaturan klien",
|
||||
"example_upstream_reserved": "upstream <0>untuk domain spesifik</0>;",
|
||||
"example_multiple_upstreams_reserved": "beberapa server upstream <0>untuk domain spesifik</0>;",
|
||||
"example_upstream_reserved": "hulu <0>untuk domain tertentu</0>;",
|
||||
"example_multiple_upstreams_reserved": "beberapa hulu <0>untuk domain tertentu</0>;",
|
||||
"example_upstream_comment": "komentar.",
|
||||
"upstream_parallel": "Gunakan kueri paralel untuk mempercepat resoluasi dengan menanyakan semua server upstream secara bersamaan",
|
||||
"upstream_parallel": "Gunakan kueri paralel untuk mempercepat penyelesaian dengan mengkueri seluruh server hulu secara bersamaan.",
|
||||
"parallel_requests": "Permintaan paralel",
|
||||
"load_balancing": "Penyeimbang beban",
|
||||
"load_balancing_desc": "Permintaan satu server pada satu waktu. AdGuard Home akan menggunakan algoritma acak tertimbang untuk memilih server sehingga server tercepat akan lebih sering digunakan.",
|
||||
"bootstrap_dns": "Server DNS bootstrap",
|
||||
"bootstrap_dns_desc": "Alamat IP server DNS yang digunakan untuk menyelesaikan alamat IP resolver DoH/DoT yang Anda tentukan sebagai upstream. Komentar tidak diizinkan.",
|
||||
"bootstrap_dns_desc": "Alamat IP server DNS yang digunakan untuk menyelesaikan alamat IP penyelesai DoH/DoT yang Anda tentukan sebagai hulu. Tidak diizinkan untuk berkomentar.",
|
||||
"fallback_dns_title": "Server DNS cadangan",
|
||||
"fallback_dns_desc": "Daftar server DNS cadangan yang digunakan ketika server hulu DNS tidak merespons. Sintaksnya sama dengan kolom hulu utama di atas.",
|
||||
"fallback_dns_placeholder": "Masukkan satu server DNS cadangan per baris",
|
||||
"local_ptr_title": "Server pembalik DNS pribadi",
|
||||
"local_ptr_desc": "Server DNS yang digunakan AdGuard Home untuk kueri PTR lokal. Server ini digunakan untuk menyelesaikan nama host klien dengan alamat IP pribadi, misalnya \"192.168.12.34\", menggunakan DNS terbalik. Jika tidak disetel, AdGuard Home menggunakan alamat resolver DNS default OS Anda kecuali untuk alamat AdGuard Home itu sendiri.",
|
||||
"local_ptr_desc": "Server DNS yang digunakan oleh AdGuard Home untuk permintaan PTR, SOA, dan NS pribadi. Permintaan dianggap pribadi jika meminta domain ARPA yang berisi subnet dalam rentang IP pribadi (seperti \"192.168.12.34\") dan berasal dari klien dengan alamat IP pribadi. Jika tidak ditetapkan, standar pemecah DNS milik OS Anda akan digunakan, kecuali untuk alamat IP AdGuard Home.",
|
||||
"local_ptr_default_resolver": "Secara bawaan, AdGuard Home menggunakan pemecah DNS terbalik: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home tidak dapat menentukan pemecah DNS terbalik yang sesuai untuk sistem ini.",
|
||||
"local_ptr_placeholder": "Masukkan satu alamat IP per baris",
|
||||
"resolve_clients_title": "Aktifkan resolusi hostname klien",
|
||||
"resolve_clients_desc": "Menyelesaikan alamat IP klien secara terbalik ke nama host mereka dengan mengirimkan kueri PTR ke resolver yang sesuai (server DNS pribadi untuk klien lokal, server upstream untuk klien dengan alamat IP publik).",
|
||||
"resolve_clients_desc": "Selesaikan alamat IP klien secara terbalik ke dalam nama host mereka dengan mengirimkan kueri PTR ke penyelesai yang sesuai (server DNS pribadi untuk klien lokal, server hulu untuk klien dengan alamat IP publik).",
|
||||
"use_private_ptr_resolvers_title": "Gunakan server pembalik DNS pribadi",
|
||||
"use_private_ptr_resolvers_desc": "Lakukan pencarian DNS terbalik untuk alamat yang disajikan secara lokal menggunakan server hulu ini. Jika dinonaktifkan, Adguard Home merespons dengan NXDOMAIN untuk semua permintaan PTR tersebut kecuali untuk klien yang diketahui dari DHCP, /etc/hosts, dan seterusnya.",
|
||||
"use_private_ptr_resolvers_desc": "Menyelesaikan permintaan PTR, SOA, dan NS untuk domain ARPA yang berisi alamat IP pribadi melalui server hulu pribadi, DHCP, /etc/hosts, dll. Jika dinonaktifkan, AdGuard Home akan merespons semua permintaan tersebut dengan NXDOMAIN.",
|
||||
"check_dhcp_servers": "Cek untuk server DHCP",
|
||||
"save_config": "Simpan pengaturan",
|
||||
"enabled_dhcp": "Server DHCP diaktifkan",
|
||||
@@ -49,12 +49,12 @@
|
||||
"form_error_server_name": "Nama server tidak valid",
|
||||
"form_error_subnet": "Subnet \"{{cidr}}\" tidak berisi alamat IP \"{{ip}}\"",
|
||||
"form_error_positive": "Harus lebih dari 0",
|
||||
"form_error_gateway_ip": "Sewa tidak dapat memiliki alamat IP gateway",
|
||||
"form_error_gateway_ip": "Lease tidak dapat memiliki gerbang alamat IP",
|
||||
"out_of_range_error": "Harus di luar rentang \"{{start}}\"-\"{{end}}\"",
|
||||
"lower_range_start_error": "Harus lebih rendah dari rentang awal",
|
||||
"greater_range_start_error": "Harus lebih besar dari rentang awal",
|
||||
"subnet_error": "Alamat harus dalam satu subnet",
|
||||
"gateway_or_subnet_invalid": "Subnet mask tidak valid",
|
||||
"gateway_or_subnet_invalid": "Subnet samaran tidak valid",
|
||||
"dhcp_form_gateway_input": "IP gateway",
|
||||
"dhcp_form_subnet_input": "Subnet mask",
|
||||
"dhcp_form_range_title": "Rentang alamat IP",
|
||||
@@ -132,8 +132,8 @@
|
||||
"top_clients": "Klien teratas",
|
||||
"no_clients_found": "Tidak ditemukan klien",
|
||||
"general_statistics": "Statistik umum",
|
||||
"top_upstreams": "Top servers upstream",
|
||||
"no_upstreams_data_found": "Tidak ada data server upstream yang ditemukan",
|
||||
"top_upstreams": "Hulu teratas",
|
||||
"no_upstreams_data_found": "Tidak ada data hulu yang ditemukan",
|
||||
"number_of_dns_query_days": "Jumlah kueri DNS diproses selama {{value}} hari terakhir",
|
||||
"number_of_dns_query_days_plural": "Jumlah kueri DNS yang diproses selama {{count}} hari terakhir",
|
||||
"number_of_dns_query_hours": "Jumlah kueri DNS diproses selama {{{count}} jam terakhir",
|
||||
@@ -147,14 +147,14 @@
|
||||
"average_upstream_response_time": "Rata-rata waktu respons hulu",
|
||||
"response_time": "Waktu respons",
|
||||
"average_processing_time_hint": "Rata-rata waktu dalam milidetik untuk pemrosesan sebuah permintaan DNS",
|
||||
"block_domain_use_filters_and_hosts": "Blokir domain menggunakan filter dan file hosts",
|
||||
"block_domain_use_filters_and_hosts": "Blokir domain menggunakan filter dan berkas host",
|
||||
"filters_block_toggle_hint": "Anda dapat menyiapkan aturan pemblokiran dalam pengaturan <a>Filter</a>.",
|
||||
"use_adguard_browsing_sec": "Gunakan layanan web Keamanan Penjelajahan AdGuard",
|
||||
"use_adguard_browsing_sec_hint": "AdGuard Home akan memeriksa apakah domain diblokir oleh layanan web keamanan penjelajahan. Ini akan menggunakan API pencarian yang ramah privasi untuk melakukan pemeriksaan: hanya awalan singkat dari hash nama domain SHA256 yang dikirim ke server.",
|
||||
"use_adguard_parental": "Gunakan layanan web kontrol orang tua AdGuard",
|
||||
"use_adguard_parental_hint": "AdGuard Home akan mengecek jika domain mengandung materi dewasa. Akan menggunakan API yang ramah privasi yang sama sebagai layanan web keamanan penjelajahan.",
|
||||
"enforce_safe_search": "Pakai pencarian aman",
|
||||
"enforce_save_search_hint": "AdGuard Home dapat memaksa penelusuran aman pada mesin pencari berikut: Google, Youtube, Bing, DuckDuckGo, Yandex, dan Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home akan memberlakukan pencarian yang aman di mesin pencari berikut ini: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Sever tidak disebutkan",
|
||||
"general_settings": "Pengaturan umum",
|
||||
"dns_settings": "Pengaturan DNS",
|
||||
@@ -169,8 +169,8 @@
|
||||
"upstream_dns_help": "Masukkan satu alamat server per baris. <a>Pelajari lebih lanjut</a> mengenai cara mengonfigurasi server DNS hulu.",
|
||||
"upstream_dns_configured_in_file": "Diatur dalam {{path}}",
|
||||
"test_upstream_btn": "Uji hulu",
|
||||
"upstreams": "Upstream",
|
||||
"upstream": "Server upstream",
|
||||
"upstreams": "Hulu",
|
||||
"upstream": "Hulu",
|
||||
"apply_btn": "Terapkan",
|
||||
"disabled_filtering_toast": "Penyaringan nonaktif",
|
||||
"enabled_filtering_toast": "Penyaringan aktif",
|
||||
@@ -191,7 +191,7 @@
|
||||
"edit_table_action": "Ubah",
|
||||
"delete_table_action": "Hapus",
|
||||
"elapsed": "Berlalu",
|
||||
"filters_and_hosts_hint": "AdGuard Home memahami aturan dasar adblock dan sintak file hosts.",
|
||||
"filters_and_hosts_hint": "AdGuard Home memahami aturan dasar adblock dan sintak berkas host.",
|
||||
"no_blocklist_added": "Tidak ada daftar hitam yang ditambahkan",
|
||||
"no_whitelist_added": "Tidak ada daftar putih yang ditambahkan",
|
||||
"add_blocklist": "Tambahkan daftar hitam",
|
||||
@@ -211,33 +211,33 @@
|
||||
"form_error_url_format": "Format URL tidak valid",
|
||||
"form_error_url_or_path_format": "URL atau jalur absolut dari daftar tidak valid",
|
||||
"custom_filter_rules": "Aturan penyaringan khusus",
|
||||
"custom_filter_rules_hint": "Masukkan satu aturan dalam sebuah baris. Anda dapat menggunakan baik aturan adblock maupun sintaks file hosts.",
|
||||
"system_host_files": "File host sistem",
|
||||
"custom_filter_rules_hint": "Masukkan satu aturan pada satu baris. Anda dapat menggunakan aturan adblock atau sintaks berkas host.",
|
||||
"system_host_files": "Berkas host sistem",
|
||||
"examples_title": "Contoh",
|
||||
"example_meaning_filter_block": "blokir akses ke example.org dan seluruh subdomainnya;",
|
||||
"example_meaning_filter_whitelist": "buka blokir akses ke domain example.orf dan seluruh subdomainnya;",
|
||||
"example_meaning_filter_whitelist": "buka blokir akses ke domain example.org dan seluruh subdomainnya;",
|
||||
"example_meaning_host_block": "merespons dengan 127.0.0.1 untuk example.org (tetapi tidak untuk subdomainnya);",
|
||||
"example_comment": "! Komentar di sini.",
|
||||
"example_comment_meaning": "hanya sebuah komentar;",
|
||||
"example_comment_hash": "# Juga sebuah komentar.",
|
||||
"example_regex_meaning": "blokir akses ke domain yang cocok dengan ekspresi reguler yang ditentukan.",
|
||||
"example_upstream_regular": "DNS reguler (melalui UDP);",
|
||||
"example_upstream_regular_port": "DNS biasa (lebih dari UDP, dengan port);",
|
||||
"example_upstream_udp": "DNS biasa (lebih dari UDP, nama host);",
|
||||
"example_upstream_regular": "DNS biasa (melalui UDP);",
|
||||
"example_upstream_regular_port": "DNS biasa (melalui UDP, dengan port);",
|
||||
"example_upstream_udp": "DNS biasa (melalui UDP, nama host);",
|
||||
"example_upstream_dot": "<0>DNS melalui TLS</0> terenkripsi;",
|
||||
"example_upstream_doh": "<0>DNS melalui HTTPS</0> terenkripsi;",
|
||||
"example_upstream_doh3": "DNS melalui HTTPS terenkripsi dengan <0>HTTP/3</0> secara paksa dan tidak ada cadangan ke HTTP/2 atau lebih rendah;",
|
||||
"example_upstream_doq": "<0>DNS melalui QUIC</0> terenkripsi;",
|
||||
"example_upstream_sdns": "<0>Stempel DNS</0> untuk <1>DNSCrypt</1> atau pengarah <2>DNS-over-HTTPS</2>;",
|
||||
"example_upstream_tcp": "DNS reguler (melalui TCP);",
|
||||
"example_upstream_sdns": "<0>Stempel DNS</0> untuk <1>DNSCrypt</1> atau pengarah <2>DNS melalui HTTPS</2>;",
|
||||
"example_upstream_tcp": "DNS biasa (melalui TCP);",
|
||||
"example_upstream_tcp_port": "DNS biasa (melalui TCP, dengan port);",
|
||||
"example_upstream_tcp_hostname": "DNS biasa (lebih dari TCP, nama host);",
|
||||
"example_upstream_tcp_hostname": "DNS biasa (melalui TCP, nama host);",
|
||||
"all_lists_up_to_date_toast": "Semua daftar sudah diperbarui",
|
||||
"updated_upstream_dns_toast": "Server upstream berhasil disimpan",
|
||||
"updated_upstream_dns_toast": "Server hulu berhasil disimpan",
|
||||
"dns_test_ok_toast": "Server DNS yang ditentukan bekerja dengan benar",
|
||||
"dns_test_not_ok_toast": "Server \"{{key}}\": tidak dapat digunakan, mohon cek bahwa Anda telah menulisnya dengan benar",
|
||||
"dns_test_parsing_error_toast": "Bagian {{section}}: baris {{line}}: tidak dapat digunakan, mohon cek bahwa Anda telah menulisnya dengan benar",
|
||||
"dns_test_warning_toast": "Upstream \"{{key}}\" tidak menanggapi permintaan pengujian dan mungkin tidak berfungsi dengan baik",
|
||||
"dns_test_warning_toast": "Hulu \"{{key}}\" tidak menanggapi permintaan pengujian dan mungkin tidak berfungsi dengan benar",
|
||||
"unblock": "Buka Blokir",
|
||||
"block": "Blok",
|
||||
"disallow_this_client": "Cabut ijin untuk klien ini",
|
||||
@@ -268,18 +268,18 @@
|
||||
"rule_added_to_custom_filtering_toast": "Aturan ditambah ke aturan penyaringan khusus: {{rule}}",
|
||||
"query_log_response_status": "Status: {{value}}",
|
||||
"query_log_filtered": "Difilter oleh {{filter}}",
|
||||
"query_log_confirm_clear": "Apakah Anda yakin ingin menghapus seluruh kueri log?",
|
||||
"query_log_cleared": "Kueri log telah berhasil dihapus",
|
||||
"query_log_updated": "Log permintaan telah berhasil diperbarui",
|
||||
"query_log_clear": "Hapus kueri log",
|
||||
"query_log_confirm_clear": "Apakah Anda yakin ingin menghapus seluruh catatan kueri?",
|
||||
"query_log_cleared": "Catatan kueri berhasil dihapus",
|
||||
"query_log_updated": "Catatan kueri berhasil diperbarui",
|
||||
"query_log_clear": "Hapus catatan kueri",
|
||||
"query_log_retention": "Rotasi kueri log",
|
||||
"query_log_enable": "Aktifkan log",
|
||||
"query_log_configuration": "Konfigurasi log",
|
||||
"query_log_disabled": "Kueri log dinonaktifkan dan dapat dikonfigurasi di <0>pengaturan</0>",
|
||||
"query_log_enable": "Aktifkan catatan",
|
||||
"query_log_configuration": "Konfigurasi catatan",
|
||||
"query_log_disabled": "Catatan kueri dinonaktifkan dan dapat dikonfigurasi di <0>pengaturan</0>",
|
||||
"query_log_strict_search": "Gunakan tanda kutip ganda untuk pencarian ketat",
|
||||
"query_log_retention_confirm": "Apakah Anda yakin ingin mengubah rotasi kueri log? Jika Anda menurunkan nilai interval, beberapa data akan hilang",
|
||||
"anonymize_client_ip": "Anonim IP klien",
|
||||
"anonymize_client_ip_desc": "Jangan simpan alamat lengkap IP klien dalam log dan statistik",
|
||||
"anonymize_client_ip_desc": "Jangan simpan alamat lengkap IP klien dalam catatan atau statistik",
|
||||
"dns_config": "Konfigurasi server DNS",
|
||||
"dns_cache_config": "Konfigurasi cache DNS",
|
||||
"dns_cache_config_desc": "Disini Anda bisa mengonfigurasi cache DNS",
|
||||
@@ -308,8 +308,8 @@
|
||||
"form_enter_rate_limit": "Masukkan batas nilai",
|
||||
"rate_limit": "Batas nilai",
|
||||
"edns_enable": "Aktifkan EDNS Klien Subnet",
|
||||
"edns_cs_desc": "Tambahkan opsi EDNS Client Subnet (ECS) ke permintaan upstream dan catat nilai yang dikirim oleh klien di log kueri.",
|
||||
"edns_use_custom_ip": "Gunakan IP khusus untuk EDNS",
|
||||
"edns_cs_desc": "Tambahkan opsi EDNS Client Subnet (ECS) ke permintaan hulu dan catat nilai yang dikirim oleh klien dalam catatan kueri.",
|
||||
"edns_use_custom_ip": "Gunakan IP kustom untuk EDNS",
|
||||
"edns_use_custom_ip_desc": "Izinkan untuk menggunakan IP kustom untuk EDNS",
|
||||
"rate_limit_desc": "Jumlah permintaan per detik yang diperbolehkan untuk satu klien. Atur ke 0 untuk tidak terbatas.",
|
||||
"rate_limit_subnet_len_ipv4": "Panjang awalan subnet untuk alamat IPv4",
|
||||
@@ -329,13 +329,13 @@
|
||||
"blocking_mode_nxdomain": "NXDOMAIN: Respon pakai kode NXDOMAIN",
|
||||
"blocking_mode_null_ip": "Null IP: Respon pakai alamat IP kosong (0.0.0.0 untuk A; :: untuk AAAA)",
|
||||
"blocking_mode_custom_ip": "IP kustom: respon dengan alamat IP yang diset secara manual",
|
||||
"theme_auto": "Auto",
|
||||
"theme_auto": "Otomatis",
|
||||
"theme_light": "Terang",
|
||||
"theme_dark": "Gelap",
|
||||
"upstream_dns_client_desc": "Jika Anda biarkan kolom ini kosong, AdGuard Home akan menggunakan server yang dikonfigurasi di <0>pengaturan DNS</0>.",
|
||||
"tracker_source": "Sumber pelacak",
|
||||
"source_label": "Sumber",
|
||||
"found_in_known_domain_db": "Ditemukan di database domain dikenal",
|
||||
"found_in_known_domain_db": "Ditemukan di basis data domain yang dikenal.",
|
||||
"category_label": "Kategori",
|
||||
"rule_label": "Atura(n)",
|
||||
"list_label": "Daftar",
|
||||
@@ -366,18 +366,18 @@
|
||||
"install_devices_router": "Router",
|
||||
"install_devices_router_desc": "Penyiapan ini secara otomatis mencakup semua perangkat yang terhubung ke router rumah Anda, tidak perlu mengkonfigurasi masing-masing perangkat secara manual.",
|
||||
"install_devices_address": "Server DNS AdGuard Home akan menggunakan alamat berikut",
|
||||
"install_devices_router_list_1": "Buka preferensi untuk router Anda. Biasanya, Anda dapat mengaksesnya dari browser Anda melalui URL, seperti http://192.168.0.1/ atau http://192.168.1.1/. Anda mungkin diminta untuk memasukkan kata sandi. Jika Anda tidak mengingatnya, Anda sering kali dapat mengatur ulang kata sandi dengan menekan tombol pada perute itu sendiri, tetapi perlu diketahui bahwa jika prosedur ini dipilih, Anda mungkin akan kehilangan seluruh konfigurasi perute. Jika router Anda memerlukan aplikasi untuk menyiapkannya, instal aplikasi tersebut di ponsel atau PC Anda dan gunakan untuk mengakses pengaturan router.",
|
||||
"install_devices_router_list_1": "Buka preferensi untuk router Anda. Biasanya, Anda dapat mengaksesnya dari peramban Anda melalui URL, seperti http://192.168.0.1/ atau http://192.168.1.1/. Anda mungkin diminta untuk memasukkan kata sandi. Jika Anda tidak mengingatnya, Anda sering kali dapat mengatur ulang kata sandi dengan menekan tombol pada router itu sendiri, tetapi perlu diketahui bahwa jika prosedur ini dipilih, Anda mungkin akan kehilangan seluruh konfigurasi router. Jika router Anda memerlukan aplikasi untuk menyiapkannya, pasang aplikasi tersebut di ponsel atau PC Anda dan gunakan untuk mengakses pengaturan router.",
|
||||
"install_devices_router_list_2": "Temukan pengaturan DHCP / DNS. Cari huruf DNS di sebelah kolom yang memungkinkan dua atau tiga set angka, masing-masing dipecah menjadi empat kelompok dengan satu hingga tiga digit.",
|
||||
"install_devices_router_list_3": "Masukkan alamat server AdGuard Home disana",
|
||||
"install_devices_router_list_4": "Anda tidak dapat menyetel server DNS kustom pada beberapa tipe router. Dalam hal ini mungkin membantu jika Anda mengatur AdGuard Home sebagai <0>server DHCP</0>. Jika tidak, Anda harus mencari petunjuk tentang cara mengkustomisasi server DNS untuk model router khusus Anda.",
|
||||
"install_devices_windows_list_1": "Buka Panel Kontrol melalui menu Start atau pencarian Windows.",
|
||||
"install_devices_windows_list_2": "Masuk ke kategori Jaringan dan Internet (Network and Internet) dan kemudian ke Pusat Jaringan dan Berbagi (Network and Sharing Center).",
|
||||
"install_devices_windows_list_3": "Di panel kiri, klik \"Ubah pengaturan adaptor\".",
|
||||
"install_devices_windows_list_4": "Klik kanan koneksi aktif Anda dan pilih Properties.",
|
||||
"install_devices_windows_list_5": "Temukan \"Internet Protocol Version 4 (TCP/IPv4)\" (atau, untuk IPv6, \"Internet Protocol Version 6 (TCP/IPv6)\") dalam daftar, pilih dan kemudian klik Properties lagi.",
|
||||
"install_devices_windows_list_4": "Klik kanan koneksi aktif Anda dan pilih Properti.",
|
||||
"install_devices_windows_list_5": "Temukan \"Protokol Internet Versi 4 (TCP/IPv4)\" (atau, untuk IPv6, \"Protokol Internet Versi 6 (TCP/IPv6)\") dalam daftar, pilih dan kemudian klik Properti lagi.",
|
||||
"install_devices_windows_list_6": "Pilih \"Gunakan alamat server DNS berikut\" dan masukkan alamat server Beranda AdGuard Anda.",
|
||||
"install_devices_macos_list_1": "Klik ikon Apple dan pergi ke System Preferences.",
|
||||
"install_devices_macos_list_2": "Klik Network.",
|
||||
"install_devices_macos_list_1": "Klik ikon Apple dan buka Preferensi Sistem.",
|
||||
"install_devices_macos_list_2": "Klik Jaringan.",
|
||||
"install_devices_macos_list_3": "Pilih koneksi pertama dalam daftar dan klik Advanced.",
|
||||
"install_devices_macos_list_4": "Pilih tab DNS dan masukkan alamat server AdGuard Anda.",
|
||||
"install_devices_android_list_1": "Dari layar beranda Menu Android, ketuk Pengaturan.",
|
||||
@@ -394,7 +394,7 @@
|
||||
"open_dashboard": "Buka Beranda",
|
||||
"install_saved": "Berhasil disimpan",
|
||||
"encryption_title": "Enkripsi",
|
||||
"encryption_desc": "Enkripsi (HTTPS/QUIC/TLS) untuk DNS dan antarmuka admin",
|
||||
"encryption_desc": "Dukungan enkripsi (HTTPS/QUIC/TLS) untuk DNS dan antarmuka web admin",
|
||||
"encryption_config_saved": "Pengaturan enkripsi telah tersimpan",
|
||||
"encryption_server": "Nama server",
|
||||
"encryption_server_enter": "Masukkan nama domain anda",
|
||||
@@ -406,7 +406,7 @@
|
||||
"encryption_dot": "Port DNS-over-TLS",
|
||||
"encryption_dot_desc": "Jika port ini terkonfigurasi, AdGuard Home akan menjalankan server DNS-over-TLS dalam port ini",
|
||||
"encryption_doq": "Port DNS-over-QUIC ",
|
||||
"encryption_doq_desc": "Jika port ini diatur secara sepesifik, AdGuard Home akan menjalankan server DNS-lewat-QUIC pada port ini.",
|
||||
"encryption_doq_desc": "Jika port ini dikonfigurasi, AdGuard Home akan menjalankan server DNS melalui QUIC pada port ini.",
|
||||
"encryption_certificates": "Sertifikat",
|
||||
"encryption_certificates_desc": "Untuk menggunakan enkripsi, Anda perlu memberikan rantai sertifikat SSL yang valid untuk domain Anda. Anda bisa mendapatkan sertifikat gratis di <0>{{link}}</0> atau Anda dapat membelinya dari salah satu Otoritas Sertifikat tepercaya.",
|
||||
"encryption_certificates_input": "Salin / rekatkan sertifikat PEM yang disandikan di sini.",
|
||||
@@ -431,8 +431,8 @@
|
||||
"topline_expiring_certificate": "Sertifikat SSL Anda hampir kedaluwarsa. Perbarui <0>Pengaturan enkripsi</0>.",
|
||||
"topline_expired_certificate": "Sertifikat SSL Anda kedaluwarsa. Perbarui <0>Pengaturan enkripsi</0>.",
|
||||
"form_error_port_range": "Masukkan nomor port di kisaran 80-65535",
|
||||
"form_error_port_unsafe": "Ini adalah port yang tidak aman",
|
||||
"form_error_equal": "Seharusnya tidak sama",
|
||||
"form_error_port_unsafe": "Port tidak aman",
|
||||
"form_error_equal": "Tidak boleh sama",
|
||||
"form_error_password": "Kata sandi tidak cocok",
|
||||
"reset_settings": "Setel ulang pengaturan",
|
||||
"update_announcement": "AdGuard Home {{version}} sekarang tersedia! <0>Klik di sini</0> untuk info lebih lanjut.",
|
||||
@@ -447,7 +447,7 @@
|
||||
"update_failed": "Pembaruan otomatis gagal. Silakan <a>ikuti langkah-langkah berikut</a> untuk memperbarui secara manual.",
|
||||
"manual_update": "Silakan <a>mengikuti langkah berikut</a> untuk memperbarui secara manual.",
|
||||
"processing_update": "Silahkan tunggu, AdGuard Home sedang diperbarui",
|
||||
"clients_title": "Klien yang gigih",
|
||||
"clients_title": "Klien persisten",
|
||||
"clients_desc": "Konfigurasikan catatan klien persisten untuk perangkat yang terhubung ke AdGuard Home",
|
||||
"settings_global": "Global",
|
||||
"settings_custom": "Kustom",
|
||||
@@ -459,7 +459,7 @@
|
||||
"client_edit": "Ubah Klien",
|
||||
"client_identifier": "Identifikasi",
|
||||
"ip_address": "Alamat IP",
|
||||
"client_identifier_desc": "Klien dapat diidentifikasi oleh alamat IP, CIDR, alamat MAC atau ClientID (dapat digunakan untuk DoT/DoH/DoQ). <0>Di sini</0> Anda dapat mempelajari lebih lanjut tentang cara mengidentifikasi klien.",
|
||||
"client_identifier_desc": "Klien dapat diidentifikasi berdasarkan alamat IP, CIDR, alamat MAC, atau ClientID (dapat digunakan untuk DoT/DoH/DoQ). Pelajari lebih lanjut tentang cara mengidentifikasi klien <0>di sini</0>.",
|
||||
"form_enter_ip": "Masukkan IP",
|
||||
"form_enter_subnet_ip": "Masukkan alamat IP di subnet \"{{cidr}}\"",
|
||||
"form_enter_mac": "Masukkan MAC",
|
||||
@@ -475,8 +475,8 @@
|
||||
"clients_not_found": "Tidak ada klien ditemukan",
|
||||
"client_confirm_delete": "Apakah anda yakin ingin menghapus klien \"{{key}}\"?",
|
||||
"list_confirm_delete": "Anda yakin ingin menghapus daftar ini?",
|
||||
"auto_clients_title": "Klien (waktu berjalan)",
|
||||
"auto_clients_desc": "Informasi tentang alamat IP perangkat yang menggunakan atau mungkin menggunakan AdGuard Home. Informasi ini dikumpulkan dari beberapa sumber, termasuk file host, reverse DNS, dll.",
|
||||
"auto_clients_title": "Klien runtime",
|
||||
"auto_clients_desc": "Informasi tentang alamat IP perangkat yang menggunakan atau mungkin menggunakan AdGuard Home. Informasi ini dikumpulkan dari beberapa sumber, termasuk berkas host, DNS terbalik, dll.",
|
||||
"access_title": "Pengaturan akses",
|
||||
"access_desc": "Disini anda dapat mengatur aturan akses untuk server AdGuard Home DNS",
|
||||
"access_allowed_title": "Klien yang diizinkan",
|
||||
@@ -484,9 +484,9 @@
|
||||
"access_disallowed_title": "Klien yang tidak diizinkan",
|
||||
"access_disallowed_desc": "Daftar CIDR, alamat IP, atau <a>ClientID</a>. Jika daftar ini memiliki entri, AdGuard Home akan membatalkan permintaan dari klien ini. Kolom ini diabaikan jika ada entri di daftar putih klien.",
|
||||
"access_blocked_title": "Domain yang diblokir",
|
||||
"access_blocked_desc": "Jangan bingung dengan filter. AdGuard Home menghapus kueri DNS yang cocok dengan domain ini, dan kueri ini bahkan tidak muncul di log kueri. Anda dapat menentukan nama domain, karakter pengganti, atau aturan filter URL yang tepat, mis. \"example.org\", \"*.example.org\", atau \"||example.org^\" yang sesuai.",
|
||||
"access_blocked_desc": "Jangan dikelirukan dengan filter. AdGuard Home membuang kueri DNS yang cocok dengan domain ini, dan kueri ini bahkan tidak muncul di catatan kueri. Anda dapat menentukan nama domain, karakter pengganti, atau aturan filter URL yang tepat, misalnya \"example.org\", \"*.example.org\", atau \"||example.org^\" secara bersamaan.",
|
||||
"access_settings_saved": "Pengaturan akses berhasil disimpan",
|
||||
"updates_checked": "Versi baru AdGuard Home tersedia\n",
|
||||
"updates_checked": "Versi baru AdGuard Home tersedia",
|
||||
"updates_version_equal": "AdGuard Home sudah tebaru",
|
||||
"check_updates_now": "Periksa pembaruan sekarang",
|
||||
"version_request_error": "Pemeriksaan pembaruan gagal. Harap periksa koneksi internet anda.",
|
||||
@@ -494,7 +494,7 @@
|
||||
"setup_dns_privacy_1": "<0>DNS melalui TLS:</0> Gunakan <1>{{address}}</1> string.",
|
||||
"setup_dns_privacy_2": "<0>DNS-over-TLS:</0> Memakai <1>{{address}}</1> string.",
|
||||
"setup_dns_privacy_3": "<0>Berikut daftar perangkat lunak yang dapat Anda gunakan.</0>",
|
||||
"setup_dns_privacy_4": "Di perangkat iOS 14 atau macOS Big Sur, Anda dapat mengunduh file '.mobileconfig' khusus yang menambahkan server <highlight>DNS-over-HTTPS</highlight> atau <highlight>DNS-over-TLS</highlight> ke pengaturan DNS.",
|
||||
"setup_dns_privacy_4": "Pada perangkat iOS 14 atau macOS Big Sur, Anda dapat mengunduh berkas khusus '.mobileconfig' yang menambahkan server <highlight>DNS melalui HTTPS</highlight> atau <highlight>DNS melalui TLS</highlight> ke pengaturan DNS.",
|
||||
"setup_dns_privacy_android_1": "Android 9 mendukung DNS-over-TLS secara asli. Untuk mengkonfigurasinya, buka Pengaturan → Jaringan & internet → Tingkat Lanjut → DNS Pribadi dan masukkan nama domain Anda di sana.",
|
||||
"setup_dns_privacy_android_2": "<0>AdGuard untuk Android</0> mendukung <1>DNS-over-HTTPS</1> dan <1>DNS-over-TLS</1>.",
|
||||
"setup_dns_privacy_android_3": "<0>Intra</0> menambahkan dukungan <1>DNS-over-HTTPS</1> untuk Android.",
|
||||
@@ -517,7 +517,7 @@
|
||||
"rewrite_confirm_delete": "Apakah anda yakin ingin menghapus DNS rewrite untuk \"{{key}}\"?",
|
||||
"rewrite_desc": "Memungkinkan untuk dengan mudah mengkonfigurasi respons DNS kustom untuk nama domain tertentu.",
|
||||
"rewrite_applied": "Aturan Rewrite yang diterapkan",
|
||||
"rewrite_hosts_applied": "Ditulis ulang oleh aturan file hosts",
|
||||
"rewrite_hosts_applied": "Ditulis ulang oleh aturan berkas host",
|
||||
"dns_rewrites": "DNS rewrite",
|
||||
"form_domain": "Masukkan nama domain",
|
||||
"form_answer": "Masaukan alamat IP atau nama domain",
|
||||
@@ -563,7 +563,7 @@
|
||||
"ignore_domains": "Domain yang diabaikan (dipisahkan oleh baris baru)",
|
||||
"ignore_domains_title": "Domain yang diabaikan",
|
||||
"ignore_domains_desc_stats": "Kueri yang cocok dengan aturan ini tidak ditulis ke statistik",
|
||||
"ignore_domains_desc_query": "Kueri yang cocok dengan aturan ini tidak ditulis ke log kueri",
|
||||
"ignore_domains_desc_query": "Kueri yang cocok dengan aturan ini tidak ditulis ke catatan kueri",
|
||||
"interval_hours": "{{count}} jam",
|
||||
"interval_hours_plural": "{{count}} jam",
|
||||
"filters_configuration": "Konfigurasi filter",
|
||||
@@ -593,8 +593,8 @@
|
||||
"example_rewrite_wildcard": "tulis ulang respon untuk semua subdomain <0>contoh.org</0>.",
|
||||
"rewrite_ip_address": "Alamat IP: pakai IP ini dalam respons A atau AAAA",
|
||||
"rewrite_domain_name": "Nama domain: tambah ke rekaman CNAME",
|
||||
"rewrite_A": "<0>A</0>: nilai khusus, biarkan <0>A</0> merekam dari upstream",
|
||||
"rewrite_AAAA": "<0>AAAA</0>: nilai khusus, biarkan <0>AAAA</0> merekam dari upstream",
|
||||
"rewrite_A": "<0>A</0>: nilai khusus, biarkan <0>A</0> merekam dari hulu",
|
||||
"rewrite_AAAA": "<0>AAAA</0>: nilai khusus, biarkan <0>AAAA</0> merekam dari hulu",
|
||||
"disable_ipv6": "Nonaktifkan penyelesaian alamat IPv6",
|
||||
"disable_ipv6_desc": "Hapus semua kueri DNS untuk alamat IPv6 (ketik AAAA) dan hapus petunjuk IPv6 dari respons HTTPS.",
|
||||
"fastest_addr": "Alamat IP tercepat",
|
||||
@@ -655,8 +655,8 @@
|
||||
"enter_cache_size": "Masukkan ukuran cache (bytes)",
|
||||
"enter_cache_ttl_min_override": "Masukkan TTL minimum (detik)",
|
||||
"enter_cache_ttl_max_override": "Masukkan TTL maksimum (detik)",
|
||||
"cache_ttl_min_override_desc": "Perpanjang nilai waktu untuk hidup (detik) yang diterima dari server hulu saat menyimpan respons DNS.",
|
||||
"cache_ttl_max_override_desc": "Tetapkan nilai waktu-online maksimum (detik) untuk entri di cache DNS.",
|
||||
"cache_ttl_min_override_desc": "Perpanjang nilai time-to-live (detik) yang diterima dari server hulu saat menyimpan respons DNS.",
|
||||
"cache_ttl_max_override_desc": "Tetapkan nilai maksimum time-to-live (detik) untuk entri dalam cache DNS.",
|
||||
"ttl_cache_validation": "Nilai TTL cache minimum harus kurang dari atau sama dengan nilai maksimum",
|
||||
"cache_optimistic": "Caching yang optimis",
|
||||
"cache_optimistic_desc": "Buat AdGuard Home merespons dari cache bahkan ketika entri telah kedaluwarsa dan juga mencoba untuk menyegarkannya.",
|
||||
@@ -676,9 +676,9 @@
|
||||
"filter_allowlist": "PERINGATAN: Tindakan ini juga akan mengecualikan aturan \"{{disallowed_rule}}\" dari daftar klien yang diizinkan.",
|
||||
"last_rule_in_allowlist": "Tidak dapat melarang klien ini karena mengecualikan aturan \"{{disallowed_rule}}\" akan MENONAKTIFKAN daftar \"Klien yang diizinkan\".",
|
||||
"use_saved_key": "Gunakan kunci yang disimpan sebelumnya",
|
||||
"parental_control": "Kontrol Orang Tua",
|
||||
"parental_control": "Pengawasan Orang Tua",
|
||||
"safe_browsing": "Penjelajahan Aman",
|
||||
"served_from_cache": "{{value}} <i>(disajikan dari cache)</i>",
|
||||
"served_from_cache_label": "Disajikan dari cache",
|
||||
"form_error_password_length": "Kata sandi harus terdiri dari {{min}} hingga {{max}}",
|
||||
"anonymizer_notification": "<0>Catatan:</0> Anonimisasi IP diaktifkan. Anda dapat menonaktifkannya di <1>Pengaturan umum</1> .",
|
||||
"confirm_dns_cache_clear": "Apakah Anda yakin ingin menghapus cache DNS?",
|
||||
@@ -688,11 +688,11 @@
|
||||
"theme_auto_desc": "Otomatis (berdasarkan skema warna perangkat anda)",
|
||||
"theme_dark_desc": "Tema gelap",
|
||||
"theme_light_desc": "Tema terang",
|
||||
"disable_for_seconds": "Untuk {{count}} detik",
|
||||
"disable_for_seconds_plural": "Untuk {{count}} detik",
|
||||
"disable_for_minutes": "Untuk {{count}} menit",
|
||||
"disable_for_minutes_plural": "Untuk {{count}} menit",
|
||||
"disable_for_hours": "Untuk {{count}} jam",
|
||||
"disable_for_seconds": "Selama {{count}} detik",
|
||||
"disable_for_seconds_plural": "Selama {{count}} detik",
|
||||
"disable_for_minutes": "Selama {{count}} menit",
|
||||
"disable_for_minutes_plural": "Selama {{count}} menit",
|
||||
"disable_for_hours": "Selama {{count}} jam",
|
||||
"disable_for_hours_plural": "Untuk {{count}} jam",
|
||||
"disable_until_tomorrow": "Sampai besok",
|
||||
"disable_notify_for_seconds": "Hentikan perlindungan selama {{count}} detik",
|
||||
@@ -706,10 +706,10 @@
|
||||
"custom_retention_input": "Masukkan retensi dalam hitungan jam",
|
||||
"custom_rotation_input": "Masukkan rotasi dalam hitungan jam",
|
||||
"protection_section_label": "Perlindungan",
|
||||
"log_and_stats_section_label": "Log kueri dan statistik",
|
||||
"ignore_query_log": "Abaikan klien ini di log kueri",
|
||||
"log_and_stats_section_label": "Catatan kueri dan statistik",
|
||||
"ignore_query_log": "Abaikan klien ini di catatan kueri",
|
||||
"ignore_statistics": "Abaikan klien ini di statistik",
|
||||
"schedule_services": "Menjeda pemblokiran layanan",
|
||||
"schedule_services": "Jeda pemblokiran layanan",
|
||||
"schedule_services_desc": "Mengonfigurasi jadwal jeda filter pemblokiran layanan",
|
||||
"schedule_services_desc_client": "Mengonfigurasi jadwal jeda filter pemblokiran layanan untuk klien ini",
|
||||
"schedule_desc": "Tetapkan periode tidak aktif untuk layanan yang diblokir",
|
||||
@@ -741,7 +741,7 @@
|
||||
"thursday_short": "Kam",
|
||||
"friday_short": "Jum",
|
||||
"saturday_short": "Sab",
|
||||
"upstream_dns_cache_configuration": "Konfigurasi cache DNS upstream",
|
||||
"upstream_dns_cache_configuration": "Konfigurasi cache DNS hulu",
|
||||
"enable_upstream_dns_cache": "Aktifkan cache DNS untuk konfigurasi hulu kustom pada klien ini",
|
||||
"dns_cache_size": "Ukuran cache DNS, dalam byte"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Utilizza richieste parallele per accelerare la risoluzione interrogando simultaneamente tutti i server upstream.",
|
||||
"parallel_requests": "Richieste parallele",
|
||||
"load_balancing": "Bilanciamento del carico",
|
||||
"load_balancing_desc": "Esegui una query su un server upstream alla volta. AdGuard Home utilizza un algoritmo casuale ponderato per selezionare i server con il minor numero di ricerche fallite e il tempo medio di ricerca più basso.",
|
||||
"load_balancing_desc": "Esegui una query su un server upstream alla volta.<br/>AdGuard Home utilizza un algoritmo casuale ponderato per selezionare i server con il minor numero di ricerche fallite e il tempo medio di ricerca più basso.",
|
||||
"bootstrap_dns": "Server DNS bootstrap",
|
||||
"bootstrap_dns_desc": "Indirizzi IP dei server DNS utilizzati per risolvere gli indirizzi IP dei resolver DoH/DoT specificati come upstream. I commenti non sono ammessi.",
|
||||
"fallback_dns_title": "Server DNS di fallback",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Utilizza il Controllo Parentale di AdGuard",
|
||||
"use_adguard_parental_hint": "AdGuard Home verificherà se il dominio contiene materiale per adulti. Utilizza le stesse API privacy-friendly del servizio web 'sicurezza di navigazione'.",
|
||||
"enforce_safe_search": "Utilizza Ricerca Sicura",
|
||||
"enforce_save_search_hint": "AdGuard Home forzerà la ricerca sicura sui seguenti motori di ricerca: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home applicherà la ricerca sicura nei seguenti motori di ricerca: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Nessun server specificato",
|
||||
"general_settings": "Impostazioni generali",
|
||||
"dns_settings": "Impostazioni DNS",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "Risposta TTL bloccata",
|
||||
"blocked_response_ttl_desc": "Specifica per quanti secondi i client devono tenere nella cache una risposta filtrata",
|
||||
"form_enter_blocked_response_ttl": "Inserisci tempo di vita (TTL) della risposta bloccata (secondi)",
|
||||
"upstream_timeout": "Timeout upstream",
|
||||
"upstream_timeout_desc": "Specifica il numero di secondi da attendere per una risposta dal server upstream",
|
||||
"form_enter_upstream_timeout": "Inserisci la durata del timeout del server upstream in secondi",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS su HTTPS",
|
||||
"dns_over_tls": "DNS su TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "Disattiva risoluzione indirizzi IPv6",
|
||||
"disable_ipv6_desc": "Eliminare tutte le query DNS per gli indirizzi IPv6 (tipo AAAA) e rimuovere i suggerimenti IPv6 dalle risposte HTTPS.",
|
||||
"fastest_addr": "Indirizzo IP più veloce",
|
||||
"fastest_addr_desc": "Interroga tutti i server DNS e restituisci l'indirizzo IP più veloce tra tutte le risposte. Ciò rallenterà le richieste DNS poiché AdGuard Home dovrà attendere le risposte da tutti i server DNS, ma ciò migliorerà complessivamente la connettività.",
|
||||
"fastest_addr_desc": "Attendi le risposte da <b>tutti i</b> server DNS, misura la velocità di connessione TCP per ogni server e restituisci l'indirizzo IP del server con la velocità di connessione più elevata.<br/>Questa modalità può rallentare notevolmente le query DNS, se uno o più server upstream non rispondono. Assicurati che i tuoi server upstream siano stabili e che il timeout upstream sia basso.",
|
||||
"autofix_warning_text": "Se fai clic su \"Correggi\", AdGuardHome configurerà il tuo sistema per utilizzare il server DNS AdGuardHome.",
|
||||
"autofix_warning_list": "Eseguirà queste attività: <0> Disattiva DNSStubListener di sistema </0> <0> Imposta l'indirizzo del server DNS su 127.0.0.1 </0> <0> Sostituisci la destinazione del collegamento simbolico di /etc/resolv.conf su / run / systemd /resolve/resolv.conf </0> <0> Arresta DNSStubListener (ricarica il servizio systemd-resolved) </0>",
|
||||
"autofix_warning_result": "Di conseguenza, tutte le richieste DNS dal sistema verranno elaborate da AdGuardHome per impostazione predefinita.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "並列リクエストを使用する(同時にすべてのアップストリームサーバーに処理要求することで解決スピードが向上)",
|
||||
"parallel_requests": "並列リクエスト",
|
||||
"load_balancing": "ロードバランシング",
|
||||
"load_balancing_desc": "一度に1つのアップストリームサーバーをクエリします。AdGuard Home は、重み付き乱択アルゴリズムを使用して、ルックアップに失敗した回数が最も少なく、平均ルックアップ時間が最も短いサーバーを選択します。",
|
||||
"load_balancing_desc": "一度に1つのアップストリームサーバーをクエリします。<br/>AdGuard Home は、重み付き乱択アルゴリズムを使用して、ルックアップに失敗した回数が最も少なく、平均ルックアップ時間が最も短いサーバーを選択します。",
|
||||
"bootstrap_dns": "ブートストラップDNSサーバ",
|
||||
"bootstrap_dns_desc": "アップストリームとして指定したDoH/DoTリゾルバのIPアドレスを解決するために使用されるDNSサーバーのIPアドレスです。(コメントは許可されていません)",
|
||||
"fallback_dns_title": "フォールバックDNSサーバー",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "AdGuardペアレンタルコントロール・ウェブサービスを使用する",
|
||||
"use_adguard_parental_hint": "AdGuard Homeは、ドメインにアダルトコンテンツが含まれているかどうかを確認します。 ブラウジングセキュリティ・ウェブサービスと同じプライバシーに優しいAPIを使用します。",
|
||||
"enforce_safe_search": "セーフサーチを使用する",
|
||||
"enforce_save_search_hint": "AdGuard Homeは、次の検索エンジンでセーフサーチを強制適用します: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay",
|
||||
"enforce_save_search_hint": "AdGuard Homeは、次の検索エンジンでセーフサーチを強制適用します: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay",
|
||||
"no_servers_specified": "サーバが指定されていません",
|
||||
"general_settings": "一般設定",
|
||||
"dns_settings": "DNS設定",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "Blocked Response TTL(ブロック済み応答のTTL)",
|
||||
"blocked_response_ttl_desc": "フィルタリングされた応答をクライアントがキャッシュしておく時間(秒)を指定します。",
|
||||
"form_enter_blocked_response_ttl": "ブロック済み応答のTTL(秒単位)を入力してください",
|
||||
"upstream_timeout": "Upstream timeout(アップストリームタイムアウト)",
|
||||
"upstream_timeout_desc": "アップストリームサーバーからの応答を待つ秒数を指定します。",
|
||||
"form_enter_upstream_timeout": "アップストリームサーバーのタイムアウト時間を秒単位で入力します。",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
"dns_over_tls": "DNS-over-TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "IPv6アドレスの解決を無効にする",
|
||||
"disable_ipv6_desc": "IPv6アドレス(タイプAAAA)に対するDNSクエリをすべて破棄し、HTTPS応答から IPv6 hint を削除します。",
|
||||
"fastest_addr": "最速のIPアドレス",
|
||||
"fastest_addr_desc": "すべてのDNSサーバーに処理要求し、全応答の中で最速のIPアドレスを返します。これにより、AdGuard HomeがすべてのDNSサーバーからの応答を待つ必要があるため、DNSクエリが遅くなりますが、全体的な接続性は向上します。",
|
||||
"fastest_addr_desc": "<b>すべての</b>DNSサーバーからの応答を待ち、各サーバーのTCP接続速度を測定し、最も接続速度の速いサーバーのIPアドレスを返します。<br/>※このモードでは、1つまたは複数のアップストリームサーバーが応答しない場合、DNSクエリが大幅に遅くなることがあります。アップストリームサーバーが安定していることを確認し、アップストリームタイムアウトは小さくしておいてください。",
|
||||
"autofix_warning_text": "「修正」をクリックすると、AdGuardHomeはAdGuardHome DNSサーバを使用するようにシステムを構成します。",
|
||||
"autofix_warning_list": "次のタスクを実行します:<0>システムDNSStubListenerを非アクティブ化します</0> <0>DNSサーバのアドレスを127.0.0.1に設定します</0> <0>/etc/resolv.confのシンボリックリンクの対象を/run/systemd/resolve/resolv.confに置換します</0> <0>DNSStubListenerを停止します(systemd-resolvedサービスをリロードします)</0>",
|
||||
"autofix_warning_result": "その結果、システムからのすべてのDNSリクエストは、デフォルトでAdGuard Homeによって処理されます。",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "쿼리 처리 속도를 높이려면 모든 업스트림 서버에서 동시에 병렬 쿼리를 사용해주세요.",
|
||||
"parallel_requests": "병렬 처리 요청",
|
||||
"load_balancing": "로드 밸런싱",
|
||||
"load_balancing_desc": "한 번에 하나의 업스트림 서버를 쿼리합니다. AdGuard Home은 가중 무작위 알고리즘을 사용하여 조회 실패 횟수가 가장 적고 평균 조회 시간이 가장 짧은 서버를 선택합니다.",
|
||||
"load_balancing_desc": "한 번에 하나의 업스트림 서버를 쿼리합니다.<br/>AdGuard Home은 가중 무작위 알고리즘을 사용하여 조회 실패 횟수가 가장 적고 평균 조회 시간이 가장 짧은 서버를 선택합니다.",
|
||||
"bootstrap_dns": "부트스트랩 DNS 서버",
|
||||
"bootstrap_dns_desc": "업스트림으로 지정한 DoH/DoT 리졸버의 IP 주소를 확인하는 데 사용되는 DNS 서버의 IP 주소입니다. 주석은 허용되지 않습니다.",
|
||||
"fallback_dns_title": "폴백 DNS 서버",
|
||||
@@ -108,7 +108,7 @@
|
||||
"off": "OFF",
|
||||
"copyright": "Copyright",
|
||||
"homepage": "홈페이지",
|
||||
"report_an_issue": "문제를 보고합니다",
|
||||
"report_an_issue": "문제 신고",
|
||||
"privacy_policy": "개인정보취급방침",
|
||||
"enable_protection": "보호 활성화",
|
||||
"enabled_protection": "보호 활성화됨",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "AdGuard 자녀 보호 웹 서비스 사용",
|
||||
"use_adguard_parental_hint": "AdGuard Home은 도메인에 성인 자료가 포함되어 있는지 확인합니다. 브라우징 보안 웹 서비스와 동일한 개인정보 보호 API를 사용함.",
|
||||
"enforce_safe_search": "세이프서치 사용",
|
||||
"enforce_save_search_hint": "AdGuard Home은 Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay와 같은 검색 엔진에서 세이프서치를 시행합니다.",
|
||||
"enforce_save_search_hint": "AdGuard Home은 Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay와 같은 검색 엔진에서 세이프서치를 시행합니다.",
|
||||
"no_servers_specified": "지정된 서버 없음",
|
||||
"general_settings": "일반 설정",
|
||||
"dns_settings": "DNS 설정",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "차단된 TTL 응답",
|
||||
"blocked_response_ttl_desc": "클라이언트가 필터링된 응답을 캐시해야 하는 시간(초)을 지정합니다.",
|
||||
"form_enter_blocked_response_ttl": "차단된 응답 TTL(초)을 입력하세요.",
|
||||
"upstream_timeout": "업스트림 제한 시간",
|
||||
"upstream_timeout_desc": "업스트림 서버의 응답을 기다리는 시간(초)을 지정합니다.",
|
||||
"form_enter_upstream_timeout": "업스트림 서버 응답 제한 시간을 초 단위로 입력하세요.",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
"dns_over_tls": "DNS-over-TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "IPv6 주소 확인 비활성화",
|
||||
"disable_ipv6_desc": "IPv6 주소(AAAA 유형)에 대한 모든 DNS 쿼리를 무시하고 HTTPS 유형 응답에서 IPv6 데이터를 제거합니다.",
|
||||
"fastest_addr": "가장 빠른 IP 주소",
|
||||
"fastest_addr_desc": "모든 DNS 서버에 쿼리를 수행한 다음 반응이 가장 빠른 IP주소를 반송합니다. AdGuard Home이 모든 DNS 서버의 응답을 기다려야 하기 때문에 DNS 쿼리 속도가 느려지지만 전반적인 연결이 향상됩니다.",
|
||||
"fastest_addr_desc": "<b>모든</b> DNS 서버의 응답을 기다렸다가 각 서버의 TCP 연결 속도를 측정하여 연결 속도가 가장 빠른 서버의 IP 주소를 반환합니다.<br/>이 모드는 하나 이상의 업스트림 서버가 응답하지 않는 경우, DNS 쿼리 속도가 상당히 느려질 수 있습니다. 업스트림 서버가 안정적이고 업스트림 타임아웃이 짧은지 확인하세요.",
|
||||
"autofix_warning_text": "'수정'을 클릭하면 AdGuard Home이 AdGuard Home DNS 서버를 사용하도록 시스템을 설정합니다.",
|
||||
"autofix_warning_list": "다음 작업을 진행합니다: <0>DNSStubListener 시스템 비활성화</0> <0>DNS 서버 주소를 127.0.0.1로 설정</0> <0>/etc/resolv.conf의 심볼릭 링크 타겟을 /run/systemd/resolve/resolv.conf로 변경</0> <0>DNSStubListener 중지 (systemd-resolved 서비스 새로고침)</0>",
|
||||
"autofix_warning_result": "결과적으로 시스템의 모든 DNS 요청은 기본적으로 AdGuard Home에 의해 처리됩니다.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Parallelle verzoeken gebruiken om te versnellen door gelijktijdig verzoeken te sturen naar alle upstream servers.",
|
||||
"parallel_requests": "Parallelle verzoeken",
|
||||
"load_balancing": "Volume balanceren",
|
||||
"load_balancing_desc": "Voer zoekopdrachten uit op één upstream-server tegelijk. AdGuard Home gebruikt een gewogen willekeurig algoritme om servers te selecteren met het laagste aantal mislukte zoekopdrachten en de laagste gemiddelde opzoektijd.",
|
||||
"load_balancing_desc": "Voer zoekopdrachten uit op één upstream-server tegelijk.<br/>AdGuard Home gebruikt een gewogen willekeurig algoritme om servers te selecteren met het laagste aantal mislukte zoekopdrachten en de laagste gemiddelde opzoektijd.",
|
||||
"bootstrap_dns": "Bootstrap DNS-servers",
|
||||
"bootstrap_dns_desc": "IP-adressen van DNS-servers die worden gebruikt om IP-adressen om te zetten van de DoH/DoT-resolvers die je opgeeft als upstreams. Opmerkingen zijn niet toegestaan.",
|
||||
"fallback_dns_title": "Back-up DNS-servers",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Gebruik AdGuard Ouderlijk toezicht web service",
|
||||
"use_adguard_parental_hint": "AdGuard Home controleert of het domein 18+ content bevat. Dit gebeurt dmv dezelfde privacy vriendelijke API als de Browsing Security web service.",
|
||||
"enforce_safe_search": "Veilig zoeken gebruiken",
|
||||
"enforce_save_search_hint": "AdGuard Home kan veilig zoeken forceren voor de volgende zoekmachines: Google, Youtube, Bing, en DuckDuckGo, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home dwingt veilig zoeken af in de volgende zoekmachines: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Geen servers gespecificeerd",
|
||||
"general_settings": "Algemene instellingen",
|
||||
"dns_settings": "DNS instellingen",
|
||||
@@ -166,7 +166,7 @@
|
||||
"encryption_settings": "Encryptie instellingen",
|
||||
"dhcp_settings": "DHCP instellingen",
|
||||
"upstream_dns": "Upstream DNS-servers",
|
||||
"upstream_dns_help": "Een server-adres per regel invoeren. <a>Meer weten</a> over het configureren van upstream DNS-servers.",
|
||||
"upstream_dns_help": "Een server-adres per regel invoeren. <a>Meer informatie</a> over het configureren van upstream DNS-servers.",
|
||||
"upstream_dns_configured_in_file": "Geconfigureerd in {{path}}",
|
||||
"test_upstream_btn": "Test upstream",
|
||||
"upstreams": "Upstreams",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "Geblokkeerde reactie TTL",
|
||||
"blocked_response_ttl_desc": "Hiermee geef je op hoeveel seconden de clients een gefilterd antwoord in de cache moeten opslaan",
|
||||
"form_enter_blocked_response_ttl": "Voer geblokkeerd antwoord TTL in (seconden)",
|
||||
"upstream_timeout": "Upstream time-out",
|
||||
"upstream_timeout_desc": "Geeft het aantal seconden aan dat moet worden gewacht op een reactie van de upstream-server",
|
||||
"form_enter_upstream_timeout": "Voer de time-outduur van de upstream-server in seconden in",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-via-HTTPS",
|
||||
"dns_over_tls": "DNS-via-TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "Oplossen IPv6-adressen uitschakelen",
|
||||
"disable_ipv6_desc": "Alle DNS-query's voor IPv6-adressen (type AAAA) verwijderen en IPv6-hints uit HTTPS-antwoorden verwijderen.",
|
||||
"fastest_addr": "Snelste IP adres",
|
||||
"fastest_addr_desc": "Alle DNS-servers bevragen en het snelste IP adres terugkoppelen. Dit zal de DNS verzoeken vertragen omdat AdGuard Home moet wachten op de antwoorden van alles DNS-servers, maar verbetert wel de connectiviteit.",
|
||||
"fastest_addr_desc": "Wacht op reacties van <b>alle</b> DNS-servers, meet de TCP-verbindingssnelheid voor elke server en retourneer het IP-adres van de server met de hoogste verbindingssnelheid.<br/>Deze modus kan DNS-query's aanzienlijk vertragen als een of meer upstream-servers niet reageren. Zorg ervoor dat je upstream-servers stabiel zijn en dat je upstream-time-out laag is.",
|
||||
"autofix_warning_text": "Als je op \"Repareren\" klikt, configureert AdGuard Home jouw systeem om de AdGuard Home DNS-server te gebruiken.",
|
||||
"autofix_warning_list": "De volgende taken worden uitgevoerd: <0> Deactiveren van Systeem DNSStubListener</0> <0> DNS-serveradres instellen op 127.0.0.1 </0> <0> Symbolisch koppelingsdoel van /etc/resolv.conf vervangen door /run/systemd/resolve/resolv.conf </0> <0> Stop DNSStubListener (herlaad systemd-resolved service) </0>",
|
||||
"autofix_warning_result": "Als gevolg hiervan worden alle DNS-aanvragen van je systeem standaard door AdGuard Home verwerkt.",
|
||||
|
||||
@@ -128,6 +128,7 @@
|
||||
"enforced_save_search": "Påtvungede barnevennlige søk",
|
||||
"number_of_dns_query_to_safe_search": "Antall DNS-forespørsler til søkemotorer der \"Safe Search\" ble fremtvunget",
|
||||
"average_processing_time": "Gjennomsnittlig behandlingstid",
|
||||
"response_time": "Responstid",
|
||||
"average_processing_time_hint": "Gjennomsnittstid for behandling av DNS-forespørsler i millisekunder",
|
||||
"block_domain_use_filters_and_hosts": "Blokker domener ved hjelp av filtre, «hosts»-filer, og rå domener",
|
||||
"filters_block_toggle_hint": "Du kan sette opp blokkeringsoppføringer i <a>Filtre</a>-innstillingene.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Użyj zapytań równoległych, aby przyspieszyć rozwiązywanie przez jednoczesne wysyłanie zapytań do wszystkich serwerów nadrzędnych.",
|
||||
"parallel_requests": "Równoległe żądania",
|
||||
"load_balancing": "Równoważenie obciążenia",
|
||||
"load_balancing_desc": "Wysyłaj zapytania do jednego serwera nadrzędnego na raz. AdGuard Home używa swojego losowego algorytmu ważonego, aby wybrać serwer, tak aby najszybszy serwer był używany częściej.",
|
||||
"load_balancing_desc": "Zapytaj jeden serwer nadrzędny na raz. AdGuard Home używa ważonego, losowego algorytmu do wybierania serwerów z najmniejszą liczbą nieudanych wyszukiwań i najniższym uśrednionym czasem wyszukiwania.",
|
||||
"bootstrap_dns": "Serwery DNS Bootstrap",
|
||||
"bootstrap_dns_desc": "Adresy IP serwerów DNS używanych do rozpoznawania adresów IP programów rozpoznawania nazw DoH/DoT określonych jako nadrzędne. Komentarze są niedozwolone.",
|
||||
"fallback_dns_title": "Rezerwowe serwery DNS",
|
||||
@@ -122,7 +122,7 @@
|
||||
"stats_query_domain": "Najczęściej wyszukiwane domeny",
|
||||
"for_last_hours": "w ciągu ostatniej {{count}} godziny",
|
||||
"for_last_hours_plural": "w ciągu ostatnich {{count}} godzin",
|
||||
"for_last_days": "za ostatni dzień {{count}}",
|
||||
"for_last_days": "za ostatni {{count}} dzień",
|
||||
"for_last_days_plural": "z ostatnich {{count}} dni",
|
||||
"stats_disabled": "Statystyki zostały wyłączone. Można je włączyć na <0>stronie ustawień</0>.",
|
||||
"stats_disabled_short": "Statystyki zostały wyłączone",
|
||||
@@ -130,7 +130,7 @@
|
||||
"requests_count": "Licznik żądań",
|
||||
"top_blocked_domains": "Najpopularniejsze zablokowane domeny",
|
||||
"top_clients": "Główni klienci",
|
||||
"no_clients_found": "Nie znaleziono klienta",
|
||||
"no_clients_found": "Nie znaleziono klientów",
|
||||
"general_statistics": "Ogólne statystyki",
|
||||
"top_upstreams": "Często żądane serwery nadrzędne",
|
||||
"no_upstreams_data_found": "Brak danych dotyczących serwerów nadrzędnych",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Użyj usługi Kontrola Rodzicielska AdGuard",
|
||||
"use_adguard_parental_hint": "AdGuard Home sprawdzi, czy domena zawiera materiały dla dorosłych. Używa tego samego interfejsu API przyjaznego prywatności, co usługa sieciowa Bezpieczne Przeglądanie. ",
|
||||
"enforce_safe_search": "Użyj bezpiecznego wyszukiwania",
|
||||
"enforce_save_search_hint": "AdGuard Home wymusza bezpieczne wyszukiwanie w następujących wyszukiwarkach: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home wymusza bezpieczne wyszukiwanie w następujących wyszukiwarkach: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Nie określono serwerów",
|
||||
"general_settings": "Ustawienia główne",
|
||||
"dns_settings": "Ustawienia DNS",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Usar consultas paralelas para acelerar a resolução consultando simultaneamente todos os servidores DNS primário",
|
||||
"parallel_requests": "Solicitações paralelas",
|
||||
"load_balancing": "Balanceamento de carga",
|
||||
"load_balancing_desc": "Consulte um servidor upstream por vez. O AdGuard Home usa um algoritmo aleatório ponderado para selecionar servidores com o menor número de falhas e o menor tempo médio de consulta.",
|
||||
"load_balancing_desc": "Consulte um servidor upstream por vez.<br/>O AdGuard Home usa um algoritmo aleatório ponderado para selecionar servidores com o menor número de falhas e o menor tempo médio de consulta.",
|
||||
"bootstrap_dns": "Servidores DNS de inicialização",
|
||||
"bootstrap_dns_desc": "Endereços IP de servidores DNS usados para resolver endereços IP dos resolvedores DoH/DoT que você especifica como upstreams. Comentários não são permitidos.",
|
||||
"fallback_dns_title": "Servidores DNS Fallback",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Usar o serviço de controle parental do AdGuard",
|
||||
"use_adguard_parental_hint": "O AdGuard Home irá verificar se o domínio contém conteúdo adulto. Ele usa a mesma API amigável de privacidade que o serviço de segurança da navegação.",
|
||||
"enforce_safe_search": "Usar pesquisa segura",
|
||||
"enforce_save_search_hint": "O AdGuard Home forcará a pesquisa segura nos seguintes motores de busca: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "O AdGuard Home forcará a pesquisa segura nos seguintes motores de busca: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Nenhum servidor especificado",
|
||||
"general_settings": "Configurações gerais",
|
||||
"dns_settings": "Configurações de DNS",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "Resposta bloqueada TTL",
|
||||
"blocked_response_ttl_desc": "Especifica por quantos segundos os clientes devem armazenar em cache uma resposta filtrada",
|
||||
"form_enter_blocked_response_ttl": "Insira o TTL da resposta bloqueada (segundos)",
|
||||
"upstream_timeout": "Tempo limite de upstream",
|
||||
"upstream_timeout_desc": "Especifica o número de segundos para esperar por uma resposta do servidor upstream",
|
||||
"form_enter_upstream_timeout": "Insira a duração do tempo limite do servidor upstream em segundos",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-sobre-HTTPS",
|
||||
"dns_over_tls": "DNS-sobre-TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "Desativar resolução de endereços IPv6",
|
||||
"disable_ipv6_desc": "Descarta todas as consultas DNS para endereços IPv6 (tipo AAAA) e remove dicas de IPv6 das respostas HTTPS.",
|
||||
"fastest_addr": "Endereço de IP mais rápido",
|
||||
"fastest_addr_desc": "Consulta todos os servidores DNS e retorna o endereço IP mais rápido entre todas as respostas. Isso torna as consultas DNS mais lentas, pois o AdGuard Home tem que esperar pelas respostas de todos os servidores DNS, mas melhora a conectividade geral.",
|
||||
"fastest_addr_desc": "Aguarde as respostas de <b>todos</b> os servidores DNS, meça a velocidade da conexão TCP para cada servidor e retorne o endereço de IP do servidor com a velocidade de conexão mais rápida.<br/>Esse modo pode retardar significativamente as consultas de DNS, se um ou mais servidores DNS primários não estiverem respondendo. Certifique-se de que seus servidores DNS primários sejam estáveis e que seu tempo de espera para DNS seja baixo.",
|
||||
"autofix_warning_text": "Se clicar em \"Corrigir\", o AdGuardHome irá configurar o seu sistema para utilizar o servidor DNS do AdGuardHome.",
|
||||
"autofix_warning_list": "Ele irá realizar estas tarefas: <0>Desativar sistema DNSStubListener</0> <0>Definir endereço do servidor DNS para 127.0.0.1</0> <0>Substituir o alvo simbólico do link /etc/resolv.conf para /run/systemd/resolv.conf</0> <0>Parar DNSStubListener (recarregar serviço resolvido pelo sistema)</0>",
|
||||
"autofix_warning_result": "Como resultado, todos as solicitações DNS do seu sistema serão processadas pelo AdGuard Home por padrão.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Usar consultas paralelas para acelerar a resolução consultando simultaneamente todos os servidores DNS",
|
||||
"parallel_requests": "Solicitações paralelas",
|
||||
"load_balancing": "Balanceamento de carga",
|
||||
"load_balancing_desc": "Consulta um servidor a montante de cada vez. O AdGuard Home usa um algoritmo aleatório ponderado para selecionar servidores com o menor número de pesquisas com falha e o menor tempo médio de pesquisa.",
|
||||
"load_balancing_desc": "Consulta um servidor upstream de cada vez. <br/>O AdGuard Home usa um algoritmo aleatório ponderado para selecionar servidores com o menor número de pesquisas falhadas e o menor tempo médio de pesquisa.",
|
||||
"bootstrap_dns": "Servidores DNS de arranque",
|
||||
"bootstrap_dns_desc": "Endereços IP de servidores DNS usados para resolver endereços IP dos resolvedores DoH/DoT que você especifica como upstreams. Comentários não são permitidos.",
|
||||
"fallback_dns_title": "Servidores DNS de fallback",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Usar o serviço de controlo parental do AdGuard",
|
||||
"use_adguard_parental_hint": "O AdGuard Home irá verificar se o domínio contém conteúdo adulto. Usa a mesma API amigável de privacidade que o serviço de segurança da navegação.",
|
||||
"enforce_safe_search": "Usar pesquisa segura",
|
||||
"enforce_save_search_hint": "O AdGuard Home forçará a pesquisa segura nos seguintes motores de busca: Google, Youtube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "O AdGuard Home aplicará pesquisa segura nos seguintes motores de busca: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Nenhum servidor especificado",
|
||||
"general_settings": "Definições gerais",
|
||||
"dns_settings": "Definições de DNS",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "Resposta bloqueada TTL",
|
||||
"blocked_response_ttl_desc": "Especifica por quantos segundos os clientes devem armazenar em cache uma resposta filtrada",
|
||||
"form_enter_blocked_response_ttl": "Insira o TTL da resposta bloqueada (segundos)",
|
||||
"upstream_timeout": "Tempo esgotado de upstream",
|
||||
"upstream_timeout_desc": "Especifica o número de segundos a aguardar por uma resposta do servidor upstream",
|
||||
"form_enter_upstream_timeout": "Insira a duração do tempo esgotado do servidor upstream em segundos",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-sobre-HTTPS",
|
||||
"dns_over_tls": "DNS-sobre-TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "Desativar resolução de endereços IPv6",
|
||||
"disable_ipv6_desc": "Descarte todas as consultas DNS para endereços IPv6 (tipo AAAA) e remova as dicas IPv6 das respostas HTTPS.",
|
||||
"fastest_addr": "Endereço de IP mais rápido",
|
||||
"fastest_addr_desc": "Consulta todos os servidores DNS e retorna o endereço IP mais rápido entre todas as respostas. Isso torna as consultas DNS mais lentas, pois o AdGuard Home tem que esperar pelas respostas de todos os servidores DNS, mas melhora a conectividade geral.",
|
||||
"fastest_addr_desc": "Aguarda por respostas de <b>todos</b> os servidores DNS, mede a velocidade da ligação TCP para cada servidor e devolva o endereço IP do servidor com a velocidade de ligação mais rápida.<br/>Este modo pode abrandar significativamente as consultas DNS, se um ou mais servidores upstream não estiverem a responder. Certifique-se de que os seus servidores upstream são estáveis e que o tempo esgotado de upstream é baixo.",
|
||||
"autofix_warning_text": "Se clicar em \"Corrigir\", o AdGuardHome irá configurar o seu sistema para utilizar o servidor DNS do AdGuardHome.",
|
||||
"autofix_warning_list": "Irá realizar estas tarefas: <0>Desativar sistema DNSStubListener</0> <0>Definir endereço do servidor DNS para 127.0.0.1</0> <0>Substituir o alvo simbólico do link /etc/resolv.conf para /run/systemd/resolv.conf</0> <0>Parar DNSStubListener (recarregar serviço resolvido pelo sistema)</0>",
|
||||
"autofix_warning_result": "Como resultado, todos as solicitações DNS do seu sistema serão processadas pelo AdGuard Home por predefinição.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Использовать параллельные запросы ко всем серверам одновременно для ускорения обработки запроса.",
|
||||
"parallel_requests": "Параллельные запросы",
|
||||
"load_balancing": "Распределение нагрузки\n",
|
||||
"load_balancing_desc": "Запрашивайте по одному серверу за раз. AdGuard Home использует алгоритм случайной выборки с учётом веса для выбора серверов с наименьшим количеством неудачных запросов и наименьшим средним временем выполнения запроса.",
|
||||
"load_balancing_desc": "Запрашивать по одному upstream-серверу.<br/>AdGuard Home использует алгоритм случайной выборки с учётом веса для выбора серверов с наименьшим количеством неудачных запросов и наименьшим средним временем выполнения запроса.",
|
||||
"bootstrap_dns": "Bootstrap DNS-серверы",
|
||||
"bootstrap_dns_desc": "IP-адреса DNS-серверов, используемых для поиска IP-адресов DoH/DoT upstream-серверов, которые вы указали. Комментарии не допускаются.",
|
||||
"fallback_dns_title": "Резервные DNS-серверы",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Включить модуль Родительского контроля AdGuard ",
|
||||
"use_adguard_parental_hint": "AdGuard Home проверит, содержит ли домен материалы 18+. Он использует тот же API для обеспечения конфиденциальности, что и веб-служба безопасности браузера.",
|
||||
"enforce_safe_search": "Включить безопасный поиск",
|
||||
"enforce_save_search_hint": "AdGuard Home может обеспечить безопасный поиск в следующих поисковых системах: Google, YouTube, Bing, DuckDuckGo, Yandex и Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home будет обеспечивать безопасный поиск в следующих поисковых системах: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Нет указанных серверов",
|
||||
"general_settings": "Основные настройки",
|
||||
"dns_settings": "Настройки DNS",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "TTL заблокированного ответа",
|
||||
"blocked_response_ttl_desc": "Указывает, в течение скольких секунд клиенты должны кешировать отфильтрованный ответ",
|
||||
"form_enter_blocked_response_ttl": "Введите TTL заблокированного ответа (в секундах)",
|
||||
"upstream_timeout": "Время ожидания ответов от upstream-серверов",
|
||||
"upstream_timeout_desc": "Длительность ожидания ответа от upstream-серверов в секундах",
|
||||
"form_enter_upstream_timeout": "Введите время ожидания для upstream-сервера в секундах",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
"dns_over_tls": "DNS-over-TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "Отключить обработку IPv6-адресов",
|
||||
"disable_ipv6_desc": "Игнорировать все DNS-запросы адресов IPv6 (тип AAAA) и удалять IPv6-данные из ответов типа HTTPS.",
|
||||
"fastest_addr": "Самый быстрый IP-адрес",
|
||||
"fastest_addr_desc": "Опросить все DNS-серверы и вернуть самый быстрый IP-адрес из полученных ответов. Это замедлит DNS-запросы, так как нужно будет дождаться ответов со всех DNS-серверов, но улучшит соединение.",
|
||||
"fastest_addr_desc": "Дождаться ответов от <b>всех</b> DNS-серверов, измерить скорость TCP-соединения для каждого сервера и вернуть IP-адрес сервера с самой высокой скоростью соединения.<br/>Этот режим может значительно замедлить выполнение DNS-запросов, если один или несколько серверов не отвечают. Убедитесь, что ваши серверы работают стабильно, а время ожидания серверов мало.",
|
||||
"autofix_warning_text": "При нажатии «Исправить» AdGuard Home настроит вашу систему на использование DNS-сервера AdGuard Home.",
|
||||
"autofix_warning_list": "Будут выполняться следующие задачи: <0>Деактивировать системный DNSStubListener</0> <0>Установить адрес сервера DNS на 127.0.0.1</0> <0>Создать символическую ссылку /etc/resolv.conf на /run/systemd/resolve/resolv.conf</0> <0>Остановить DNSStubListener (перезагрузить системную службу)</0>.",
|
||||
"autofix_warning_result": "В результате все DNS-запросы от вашей системы будут по умолчанию обрабатываться AdGuard Home.\n",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"local_ptr_desc": "ස්ථානීය PTR විමසුම් සඳහා ඇඩ්ගාර්ඩ් හෝම් භාවිතා කරන ව.නා.ප. සේවාදායක. මෙම සේවාදායක පුද්ගලික අ.ජා.කෙ. ලිපින පරාසවල PTR විමසුම් විසඳීමට භාවිතා කරයි, උදාහරණයක් ලෙස ප්රතිවර්ත ව.නා.ප. භාවිතයෙන් \"192.168.12.34\". මෙය සකසා නැති නම්, ඇඩ්ගාර්ඩ් හෝම් හි ලිපින සඳහා හැරුනු විට ඔබගේ මෙහෙයුම් පද්ධතියේ පෙරනිමි ව.නා.ප. විසදුම්වල ලිපින භාවිතා කරයි.",
|
||||
"local_ptr_default_resolver": "පෙරනිමි පරිදි, ඇඩ්ගාර්ඩ් හෝම් පහත ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු භාවිතා කරයි: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "ඇඩ්ගාර්ඩ් හෝම් හට මෙම පද්ධතිය සඳහා සුදුසු පුද්ගලික ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු නිශ්චය කරගත නොහැකි විය.",
|
||||
"local_ptr_placeholder": "පේළියකට එක් සේවාදායක ලිපිනය බැගින් යොදන්න",
|
||||
"local_ptr_placeholder": "පේළියකට අ.ජා.කෙ. ලිපිනය බැගින් ලියන්න",
|
||||
"resolve_clients_title": "අනුග්රාහකවල අ.ජා.කෙ. ලිපින ප්රතිවර්ත විසඳීම සබල කරන්න",
|
||||
"use_private_ptr_resolvers_title": "පෞද්. ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු භාවිතය",
|
||||
"check_dhcp_servers": "ග.ධා.වි.කෙ. සේවාදායක පරීක්ෂා කරන්න",
|
||||
@@ -102,7 +102,6 @@
|
||||
"stats_malware_phishing": "අවහිර කළ ද්වේශාංග/තතුබෑම්",
|
||||
"stats_adult": "අවහිර කළ වැඩිහිටි වියමන අඩවි",
|
||||
"stats_query_domain": "ප්රචලිත විමසන ලද වසම්",
|
||||
"for_last_24_hours": "පසුගිය පැය 24 සඳහා",
|
||||
"for_last_days": "පසුගිය දවස් {{count}} සඳහා",
|
||||
"for_last_days_plural": "පසුගිය දවස් {{count}} සඳහා",
|
||||
"stats_disabled": "සංඛ්යාලේඛන අබල කර ඇත. එය <0>සැකසුම් පිටුවෙන්</0> සබල කළ හැකිය.",
|
||||
@@ -115,13 +114,15 @@
|
||||
"general_statistics": "පොදු සංඛ්යාලේඛන",
|
||||
"number_of_dns_query_days": "පසුගිය දවස් {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||
"number_of_dns_query_days_plural": "පසුගිය දවස් {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||
"number_of_dns_query_24_hours": "පසුගිය පැය 24 සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||
"number_of_dns_query_hours": "පසුගිය පැය {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||
"number_of_dns_query_hours_plural": "පසුගිය පැය {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||
"number_of_dns_query_blocked_24_hours": "දැන්වීම් වාරණ පෙරහන් සහ සත්කාරක වාරණ ලැයිස්තු මගින් අවහිර කළ ව.නා.ප. ඉල්ලීම් ගණන",
|
||||
"number_of_dns_query_blocked_24_hours_by_sec": "ඇඩ්ගාර්ඩ් පිරික්සුම් ආරක්ෂණ ඒකකය මගින් අවහිර කළ ව.නා.ප. ඉල්ලීම් ගණන",
|
||||
"number_of_dns_query_blocked_24_hours_adult": "අවහිර කළ වැඩිහිටි වියමන අඩවි ගණන",
|
||||
"enforced_save_search": "ආරක්ෂිත සෙවීම බලාත්මක කළ",
|
||||
"number_of_dns_query_to_safe_search": "ආරක්ෂිත සෙවීම බලාත්මක කළ සෙවුම් යන්ත්ර සඳහා ව.නා.ප. ඉල්ලීම් ගණන",
|
||||
"average_processing_time": "සාමාන්ය සැකසුම් කාලය",
|
||||
"response_time": "ප්රතිචාර කාලය",
|
||||
"average_processing_time_hint": "ව.නා.ප. ඉල්ලීමක් සැකසීමේ සාමාන්ය කාලය මිලි තත්පර වලින්",
|
||||
"block_domain_use_filters_and_hosts": "පෙරහන් හා සත්කාරක ගොනු භාවිතයෙන් වසම් අවහිර කරන්න",
|
||||
"filters_block_toggle_hint": "ඔබට අවහිර කිරීමේ නීති <a>පෙරහන්</a> තුළ පිහිටුවිය හැකිය.",
|
||||
@@ -130,7 +131,7 @@
|
||||
"use_adguard_parental": "ඇඩ්ගාර්ඩ් දෙමාපිය පාලන වියමන සේවාව භාවිතා කරන්න",
|
||||
"use_adguard_parental_hint": "වසමේ වැඩිහිටියන්ට අදාල කරුණු අඩංගු දැයි ඇඩ්ගාර්ඩ් හෝම් විසින් පරීක්ෂා කරනු ඇත. එය පිරික්සුම් ආරක්ෂණ වියමන සේවාව මෙන් රහස්යතා හිතකාමී යෙ.ක්ර. අ.මු. (API) භාවිතා කරයි.",
|
||||
"enforce_safe_search": "ආරක්ෂිත සෙවුම භාවිතා කරන්න",
|
||||
"enforce_save_search_hint": "ඇඩ්ගාර්ඩ් හෝම් පහත සෙවුම් යන්ත්ර තුළ ආරක්ෂිත සෙවුම බලාත්මක කරනු ඇත: ගූගල්, යූටියුබ්, බින්ග්, ඩක්ඩක්ගෝ, යාන්ඩෙක්ස් සහ පික්සාබේ.",
|
||||
"enforce_save_search_hint": "ඇඩ්ගාර්ඩ් හෝම් පහත සෙවුම් යන්ත්ර තුළ ආරක්ෂිත සෙවුම බලාත්මක කරනු ඇත: ගූගල්, යූටියුබ්, බින්ග්, ඩක්ඩක්ගෝ, එකොසියා, යාන්ඩෙක්ස් සහ පික්සාබේ.",
|
||||
"no_servers_specified": "සේවාදායක කිසිවක් නිශ්චිතව දක්වා නැත",
|
||||
"general_settings": "පොදු සැකසුම්",
|
||||
"dns_settings": "ව.නා.ප. සැකසුම්",
|
||||
@@ -196,12 +197,14 @@
|
||||
"example_comment_hash": "# එසේම අදහස් දැක්වීමක්.",
|
||||
"example_regex_meaning": "නිශ්චිතව දක්වා ඇති නිත්ය වාක්යවිධියට ගැළපෙන වසම් වෙත ප්රවේශය අවහිර කරයි.",
|
||||
"example_upstream_regular": "සාමාන්ය ව.නා.ප. (UDP හරහා);",
|
||||
"example_upstream_regular_port": "සාමාන්ය ව.නා.ප. (UDP හරහා, තොට සමඟ);",
|
||||
"example_upstream_udp": "සාමාන්ය ව.නා.ප. (UDP, සත්කාරක-නම හරහා);",
|
||||
"example_upstream_dot": "සංකේතිත <0>TLS-මගින්-ව.නා.ප.</0>;",
|
||||
"example_upstream_doh": "සංකේතිත <0>HTTPS-මගින්-ව.නා.ප.</0>;",
|
||||
"example_upstream_doq": "සංකේතිත <0>QUIC-මගින්-ව.නා.ප.</0>;",
|
||||
"example_upstream_sdns": "<1>DNSCrypt</1> හෝ <2>HTTPS-මගින්-ව.නා.ප.</2> පිළිවිසඳු සඳහා <0>ව.නා.ප. මුද්දර</0>;",
|
||||
"example_upstream_tcp": "සාමාන්ය ව.නා.ප. (TCP/ස.පා.කෙ. හරහා);",
|
||||
"example_upstream_tcp_port": "සාමාන්ය ව.නා.ප. (TCP හරහා, තොට සමඟ);",
|
||||
"example_upstream_tcp_hostname": "සාමාන්ය ව.නා.ප. (ස.පා.කෙ., සත්කාරක-නම හරහා);",
|
||||
"all_lists_up_to_date_toast": "සියළුම ලැයිස්තු දැනටමත් යාවත්කාලීනයි",
|
||||
"dns_test_ok_toast": "සඳහන් කළ ව.නා.ප. සේවාදායක නිවැරදිව ක්රියා කරයි",
|
||||
@@ -275,6 +278,7 @@
|
||||
"edns_use_custom_ip": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. යොදාගන්න",
|
||||
"edns_use_custom_ip_desc": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. භාවිතයට ඉඩදෙන්න",
|
||||
"rate_limit_desc": "එක් අනුග්රාහකයකට ඉඩ දී ඇති තත්පරයට ඉල්ලීම් ගණන. එය 0 ලෙස සැකසීම යනුවෙන් අදහස් කරන්නේ සීමාවක් නැති බවයි.",
|
||||
"rate_limit_whitelist_placeholder": "පේළියකට අ.ජා.කෙ. ලිපිනය බැගින් ලියන්න",
|
||||
"blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
||||
"blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
||||
"blocking_mode_default": "පොදු: දැන්වීම් අවහිර කරන ආකාරයේ නීතියක් මගින් අවහිර කළ විට REFUSED සමඟ ප්රතිචාර දක්වයි; /etc/host-style ආකාරයේ නීතියක් මගින් අවහිර කළ විට නීතියේ දක්වා ඇති අ.ජා.කෙ. ලිපිනය සමඟ ප්රතිචාර දක්වයි",
|
||||
@@ -505,8 +509,8 @@
|
||||
"statistics_enable": "සංඛ්යාලේඛන සබල කරන්න",
|
||||
"ignore_domains": "නොසලකන වසම් (පේළියකට එක බැගින්)",
|
||||
"ignore_domains_title": "නොසලකන වසම්",
|
||||
"ignore_domains_desc_stats": "සංඛ්යාලේඛනයෙහි මෙම වසම් සඳහා විමසුම් නොලියැවෙයි",
|
||||
"ignore_domains_desc_query": "විමසුම් සටහනෙහි මෙම වසම් සඳහා විමසුම් නොලියැවෙයි",
|
||||
"ignore_domains_desc_stats": "මෙම නීති වලට ගැළපෙන විමසුම් සංඛ්යාලේඛනයට නොලියැවෙයි",
|
||||
"ignore_domains_desc_query": "විමසුම් සටහනට මෙම නීති වලට ගැළපෙන විමසුම් නොලියැවෙයි",
|
||||
"interval_hours": "පැය {{count}}",
|
||||
"interval_hours_plural": "පැය {{count}}",
|
||||
"filters_configuration": "පෙරහන් වින්යාසය",
|
||||
@@ -615,8 +619,8 @@
|
||||
"use_saved_key": "පෙර සුරැකි යතුර භාවිතා කරන්න",
|
||||
"parental_control": "දෙමාපිය පාලනය",
|
||||
"safe_browsing": "ආරක්ෂිත පිරික්සුම",
|
||||
"served_from_cache": "{{value}} <i>(නිහිතයෙන් ගැනිණි)</i>",
|
||||
"form_error_password_length": "මුරපදය අවම වශයෙන් අකුරු {{value}} ක් දිගු විය යුතුමයි",
|
||||
"served_from_cache_label": "නිහිතයෙන් සැපයිණි",
|
||||
"form_error_password_length": "මුරපදය අකුරු {{min}} සහ {{value}} ක් අතර විය යුතුය",
|
||||
"anonymizer_notification": "<0>සටහන:</0> අ.ජා.කෙ. නිර්නාමිකකරණය සබලයි. ඔබට එය <1>පොදු සැකසුම්</1> හරහා අබල කිරීමට හැකිය .",
|
||||
"confirm_dns_cache_clear": "ඔබට ව.නා.ප. නිහිතය හිස් කිරීමට වුවමනාද?",
|
||||
"cache_cleared": "ව.නා.ප. නිහිතය හිස් කෙරිණි",
|
||||
@@ -646,6 +650,7 @@
|
||||
"log_and_stats_section_label": "විමසුම් සටහන හා සංඛ්යාලේඛන",
|
||||
"ignore_query_log": "විමසුම් සටහනට මෙම අනුග්රාහකය යොදන්න එපා",
|
||||
"ignore_statistics": "සංඛ්යාලේඛනයට මෙම අනුග්රාහකය යොදන්න එපා",
|
||||
"schedule_services": "සේවා අවහිර විරාමය",
|
||||
"schedule_invalid_select": "ආරම්භක වේලාව අවසන් වේලාවට කලින් විය යුතුය",
|
||||
"schedule_select_days": "දවස් තෝරන්න",
|
||||
"schedule_timezone": "වේලා කලාපයක් තෝරන්න",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "Používať paralelné dopyty na zrýchlenie súčasným dopytovaním všetkých upstream serverov súčasne.",
|
||||
"parallel_requests": "Paralelné dopyty",
|
||||
"load_balancing": "Vyrovnávanie záťaže",
|
||||
"load_balancing_desc": "Dopytuje sa súčasne len jeden upstream server. AdGuard Home používa vážený náhodný algoritmus na výber serverov s najnižším počtom neúspešných vyhľadávaní a najnižším priemerným časom vyhľadávania.",
|
||||
"load_balancing_desc": "Dopytuje sa súčasne len jeden upstream server.<br/>AdGuard Home používa vážený náhodný algoritmus na výber serverov s najnižším počtom neúspešných vyhľadávaní a najnižším priemerným časom vyhľadávania.",
|
||||
"bootstrap_dns": "Bootstrap DNS servery",
|
||||
"bootstrap_dns_desc": "IP adresy serverov DNS používaných na rozlíšenie IP adries prekladačov DoH/DoT, ktoré zadáte ako upstream. Komentáre nie sú povolené.",
|
||||
"fallback_dns_title": "Záložné servery DNS",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Použiť AdGuard službu Rodičovská kontrola",
|
||||
"use_adguard_parental_hint": "AdGuard Home skontroluje, či doména obsahuje materiály pre dospelých. Používa rovnaké API priateľské k ochrane osobných údajov ako služba Bezpečného prehliadania.",
|
||||
"enforce_safe_search": "Používať bezpečné vyhľadávanie",
|
||||
"enforce_save_search_hint": "AdGuard Home vynucuje bezpečné vyhľadávanie v nasledujúcich vyhľadávačoch: Google, YouTube, Bing, DuckDuckGo, Yandex a Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home vynúti bezpečné vyhľadávanie v nasledujúcich vyhľadávačoch: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Neboli špecifikované žiadne servery",
|
||||
"general_settings": "Všeobecné nastavenia",
|
||||
"dns_settings": "Nastavenia DNS",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "Blokovaná odozva TTL",
|
||||
"blocked_response_ttl_desc": "Určuje, na koľko sekúnd by mali klienti uložiť filtrovanú odozvu do vyrovnávacej pamäte",
|
||||
"form_enter_blocked_response_ttl": "Zadajte TTL blokovanej odozve (sekundy)",
|
||||
"upstream_timeout": "Časový limit pre upstream",
|
||||
"upstream_timeout_desc": "Určuje počet sekúnd čakania na odpoveď z upstream servera",
|
||||
"form_enter_upstream_timeout": "Zadajte trvanie časového limitu upstream servera v sekundách",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
"dns_over_tls": "DNS-over-TLS",
|
||||
@@ -484,7 +487,7 @@
|
||||
"access_disallowed_title": "Nepovolení klienti",
|
||||
"access_disallowed_desc": "Zoznam CIDR, IP adries alebo <a>ClientID</a>. Ak tento zoznam obsahuje položky, AdGuard Home zruší dopyty od týchto klientov. Toto pole sa ignoruje, ak sú v poli Povolení klienti položky.",
|
||||
"access_blocked_title": "Nepovolené domény",
|
||||
"access_blocked_desc": "Nesmie byť zamieňaná s filtrami. AdGuard Home zruší DNS dopyty, ktoré sa zhodujú s týmito doménami, a tieto dopyty sa nezobrazia ani v denníku dopytov. Môžete určiť presné názvy domén, zástupné znaky alebo pravidlá filtrovania URL adries, napr. \"example.org\", \"*.example.org\" alebo ||example.org^\" zodpovedajúcim spôsobom.",
|
||||
"access_blocked_desc": "Nesmie byť zamieňaná s filtrami. AdGuard Home zruší DNS dopyty, ktoré sa zhodujú s týmito doménami, a tieto dopyty sa nezobrazia ani v denníku dopytov. Môžete určiť presné názvy domén, zástupné znaky alebo pravidlá filtrácie URL adries, napr. \"example.org\", \"*.example.org\" alebo ||example.org^\" zodpovedajúcim spôsobom.",
|
||||
"access_settings_saved": "Nastavenia prístupu úspešne uložené",
|
||||
"updates_checked": "K dispozícii je nová verzia aplikácie AdGuard Home\n",
|
||||
"updates_version_equal": "AdGuard Home je aktuálny",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "Vypnúť rozlišovanie IPv6 adries",
|
||||
"disable_ipv6_desc": "Ignorovať všetky dotazy DNS na adresy IPv6 (typ AAAA) a odstrániť IPv6 údaje z HTTPS odpovedí.",
|
||||
"fastest_addr": "Najrýchlejšia IP adresa",
|
||||
"fastest_addr_desc": "Dopytovať všetky servery DNS a vrátiť najrýchlejšiu IP adresu zo všetkých odpovedí. Toto spomalí DNS dopyty, pretože AdGuard Home musí čakať na odpovede zo všetkých serverov DNS, ale zlepší sa celkové pripojenie.",
|
||||
"fastest_addr_desc": "Čaká na odpovede od <b>všetkých</b> DNS serverov, zmeria rýchlosť pripojenia TCP pre každý server a vráti adresu IP servera s najväčšou rýchlosťou pripojenia.<br/>Tento režim môže výrazne spomaliť DNS dopyty, ak jeden alebo viac upstream serverov neodpovedá. Uistite sa, že Vaše upstream servery sú stabilné a upstream upstream je nízky.",
|
||||
"autofix_warning_text": "Ak kliknete na „Opraviť“, AdGuardHome nakonfiguruje Váš systém tak, aby používal DNS server AdGuardHome.",
|
||||
"autofix_warning_list": "Bude vykonávať tieto úlohy: <0>Deaktivovať systém DNSStubListener</0> <0>Nastaviť adresu servera DNS na 127.0.0.1</0> <0>Nahradiť cieľový symbolický odkaz /etc/resolv.conf na /run/systemd/resolve/resolv.conf</0> <0>Zastaviť službu DNSStubListener (znova načítať službu systemd-resolved)</0>",
|
||||
"autofix_warning_result": "Výsledkom bude, že všetky DNS dopyty z Vášho systému budú štandardne spracované službou AdGuard Home.",
|
||||
|
||||
@@ -461,7 +461,7 @@
|
||||
"form_enter_mac": "Skriv in MAC",
|
||||
"form_enter_id": "Ange identifierare",
|
||||
"form_add_id": "Lägg till identifierare",
|
||||
"form_client_name": "Skriv in klientnamn",
|
||||
"form_client_name": "Ange klientnamn",
|
||||
"name": "Namn",
|
||||
"client_name": "Klient {{id}}",
|
||||
"client_global_settings": "Använda globala inställningar",
|
||||
@@ -674,7 +674,6 @@
|
||||
"use_saved_key": "Använd den tidigare sparade nyckeln",
|
||||
"parental_control": "Föräldrakontroll",
|
||||
"safe_browsing": "Säker surfning",
|
||||
"served_from_cache": "{{value}} <i>(levereras från cache)</i>",
|
||||
"form_error_password_length": "Lösenordet måste vara {{min}} till {{max}} tecken långt",
|
||||
"anonymizer_notification": "<0>Observera:</0> IP-anonymisering är aktiverad. Du kan inaktivera den i <1>Allmänna inställningar</1>.",
|
||||
"confirm_dns_cache_clear": "Är du säker på att du vill rensa DNS-cache?",
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"settings": "การตั้งค่า",
|
||||
"filters": "ตัวกรอง",
|
||||
"query_log": "บันทึกการสืบค้น",
|
||||
"nothing_found": "ไม่พบอะไร",
|
||||
"faq": "คำถามที่พบบ่อย",
|
||||
"version": "รุ่น",
|
||||
"address": "ที่อยู่",
|
||||
@@ -349,7 +350,7 @@
|
||||
"statistics_configuration": "การกำหนดค่าสถิติ",
|
||||
"statistics_retention": "การเก็บรักษาสถิติ",
|
||||
"statistics_retention_desc": "หากคุณลดค่าช่วงเวลาข้อมูลบางอย่างจะหายไป",
|
||||
"statistics_clear": " ล้างค่าสถิติ",
|
||||
"statistics_clear": "ล้างสถิติ",
|
||||
"statistics_clear_confirm": "คุณแน่ใจหรือไม่ว่าต้องการล้างสถิติ?",
|
||||
"statistics_retention_confirm": "คุณแน่ใจหรือไม่ว่าต้องการเปลี่ยนการเก็บรักษาสถิติ? หากคุณลดค่าช่วงเวลา ข้อมูลบางอย่างจะหายไป",
|
||||
"statistics_cleared": "สถิติได้ถูกล้างเรียบร้อยแล้ว",
|
||||
@@ -390,10 +391,13 @@
|
||||
"check_title": "ตรวจสอบการกรอง",
|
||||
"check_desc": "ตรวจสอบว่าชื่อโฮสต์ถูกกรอง",
|
||||
"form_enter_host": "ป้อนชื่อโฮสต์",
|
||||
"show_processed_responses": "การประมวลผล",
|
||||
"show_blocked_responses": "ปิดกั้นแล้ว",
|
||||
"show_whitelisted_responses": "รายการที่อนุญาต",
|
||||
"show_processed_responses": "ประมวลผลแล้ว",
|
||||
"blocked_adult_websites": "ถูกปิดกั้นโดยการควบคุมของผู้ปกครอง",
|
||||
"safe_search": "ค้นหาอย่างปลอดภัย",
|
||||
"blocklist": "บัญชีดำ",
|
||||
"allowed": "รายการที่อนุญาต",
|
||||
"filter_category_other": "อื่น ๆ",
|
||||
"parental_control": "ควบคุมโดยผู้ปกครอง",
|
||||
"sunday_short": "อาทิตย์",
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"ip": "IP",
|
||||
"dhcp_table_hostname": "Ana makine Adı",
|
||||
"dhcp_table_expires": "Bitiş tarihi",
|
||||
"dhcp_warning": "DHCP sunucusunu yine de etkinleştirmek istiyorsanız, ağınızda başka aktif DHCP sunucusu olmadığından emin olun, aksi takdirde ağa bağlı cihazların İnternet bağlantısı kesilebilir!",
|
||||
"dhcp_warning": "DHCP sunucusunu yine de etkinleştirmek istiyorsanız, ağınızda başka aktif DHCP sunucusu olmadığından emin olun, aksi takdirde ağa bağlı cihazların internet bağlantısı kesilebilir!",
|
||||
"dhcp_error": "AdGuard Home, ağda başka bir etkin DHCP sunucusu olup olmadığını belirleyemedi",
|
||||
"dhcp_static_ip_error": "DHCP sunucusunu kullanmak için sabit bir IP adresi ayarlanmalıdır. AdGuard Home, bu ağ arayüzünün sabit bir IP adresi kullanılarak yapılandırılıp yapılandırılmadığını belirleyemedi. Lütfen sabit IP adresini elle ayarlayın.",
|
||||
"dhcp_dynamic_ip_found": "Sisteminiz, <0>{{interfaceName}}</0> arayüzü için dinamik IP adresi yapılandırması kullanıyor. DHCP sunucusunu kullanmak için sabit bir IP adresi ayarlanmalıdır. Geçerli olan IP adresiniz <0>{{ipAddress}}</0>. \"DHCP sunucusunu etkinleştir\" düğmesine basarsanız, AdGuard Home bu IP adresini otomatik bir şekilde sabit olarak ayarlayacaktır.",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "AdGuard ebeveyn denetimi web hizmetini kullan",
|
||||
"use_adguard_parental_hint": "AdGuard Home, alan adının yetişkin içerik bulundurup bulundurmadığını kontrol eder. Gezinti koruması web hizmeti ile kullandığımız aynı gizlilik dostu API'yi kullanır.",
|
||||
"enforce_safe_search": "Güvenli Aramayı kullan",
|
||||
"enforce_save_search_hint": "AdGuard Home, şu arama motorlarında güvenli aramayı uygular: Google, YouTube, Bing, DuckDuckGo, Yandex ve Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home, şu arama motorlarında güvenli aramayı uygular: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Sunucu belirtilmedi",
|
||||
"general_settings": "Genel ayarlar",
|
||||
"dns_settings": "DNS ayarları",
|
||||
@@ -476,7 +476,7 @@
|
||||
"client_confirm_delete": "\"{{key}}\" istemcisini silmek istediğinizden emin misiniz?",
|
||||
"list_confirm_delete": "Bu listeyi silmek istediğinizden emin misiniz?",
|
||||
"auto_clients_title": "Çalışma zamanı istemcileri",
|
||||
"auto_clients_desc": "AdGuard Home'u kullanan veya kullanabilecek cihazların IP adresleri hakkında bilgiler. Bu bilgiler, hosts dosyaları, ters DNS, vb. dahil olmak üzere çeşitli kaynaklardan toplanır.",
|
||||
"auto_clients_desc": "AdGuard Home'u kullanan veya kullanabilecek cihazların IP adresleri hakkında bilgiler. Bu bilgiler, hosts dosyaları, ters DNS, vb. dâhil olmak üzere çeşitli kaynaklardan toplanır.",
|
||||
"access_title": "Erişim ayarları",
|
||||
"access_desc": "AdGuard Home DNS sunucusu için erişim kurallarını buradan yapılandırabilirsiniz",
|
||||
"access_allowed_title": "İzin verilen istemciler",
|
||||
@@ -603,7 +603,7 @@
|
||||
"autofix_warning_list": "Bu görevleri gerçekleştirir: <0>Sistem DNSStubListener'ı devre dışı bırakın</0> <0>DNS sunucusu adresini 127.0.0.1 olarak ayarlayın</0> <0>/etc/resolv.conf'un sembolik bağlantı hedefini /run/systemd/resolve/resolv.conf ile değiştirin<0> <0>DNSStubListener'ı durdurun (systemd çözümlenmiş hizmeti yeniden yükleyin)</0>",
|
||||
"autofix_warning_result": "Sonuç olarak, sisteminizden gelen tüm DNS istekleri varsayılan olarak AdGuard Home tarafından işlenecektir.",
|
||||
"tags_title": "Etiketler",
|
||||
"tags_desc": "İstemciye karşılık gelen etiketleri seçebilirsiniz. Etiketleri daha kesin olarak uygulamak için filtreleme kurallarına dahil edin. <0>Daha fazla bilgi edinin</0>.",
|
||||
"tags_desc": "İstemciye karşılık gelen etiketleri seçebilirsiniz. Etiketleri daha kesin olarak uygulamak için filtreleme kurallarına dâhil edin. <0>Daha fazla bilgi edinin</0>.",
|
||||
"form_select_tags": "İstemci etiketlerini seçin",
|
||||
"check_title": "Filtrelemeyi denetleyin",
|
||||
"check_desc": "Ana makine adının filtreleme durumunu kontrol edin.",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"resolve_clients_title": "Увімкнути зворотне вирішення IP-адрес клієнтів",
|
||||
"resolve_clients_desc": "Визначати доменні імена клієнтів за допомогою PTR-запитів до відповідних серверів — приватних DNS-серверів для локальних клієнтів та upstream-серверів для клієнтів з публічними IP-адресами.",
|
||||
"use_private_ptr_resolvers_title": "Використовувати приватні зворотні DNS-резолвери",
|
||||
"use_private_ptr_resolvers_desc": "Надсилати зворотні DNS-запити до вказаних серверів для клієнтів, що обслуговуються локально. Якщо вимкнено, AdGuard Home буде відповідати NXDOMAIN на всі такі PTR-запити, окрім запитів про клієнтів, що уже відомі завдяки DHCP, /etc/hosts тощо.",
|
||||
"use_private_ptr_resolvers_desc": "Розвʼязувати запити PTR, SOA та NS для доменів ARPA, що містять приватні IP-адреси, через приватні вихідні сервери, DHCP, /etc/hosts тощо. Якщо вимкнено, AdGuard Home відповідатиме на всі такі запити з NXDOMAIN.",
|
||||
"check_dhcp_servers": "Перевірити DHCP-сервери",
|
||||
"save_config": "Зберегти конфігурацію",
|
||||
"enabled_dhcp": "DHCP-сервер увімкнено",
|
||||
@@ -343,10 +343,10 @@
|
||||
"known_tracker": "Відомі трекери",
|
||||
"install_welcome_title": "Вітаємо в AdGuard Home!",
|
||||
"install_welcome_desc": "AdGuard Home — це мережевий DNS-сервер, що блокує рекламу та відстеження. Його мета — надати вам контроль над усією мережею та всіма пристроями в ній без потреби використання програми на стороні клієнта.",
|
||||
"install_settings_title": "Веб-інтерфейс адміністратора",
|
||||
"install_settings_title": "Вебінтерфейс адміністратора",
|
||||
"install_settings_listen": "Мережевий інтерфейс",
|
||||
"install_settings_port": "Порт",
|
||||
"install_settings_interface_link": "Веб-інтерфейс адміністратора AdGuard Home буде доступний за такими адресами:",
|
||||
"install_settings_interface_link": "Вебінтерфейс адміністратора AdGuard Home буде доступний за такими адресами:",
|
||||
"form_error_port": "Уведіть правильне значення порту",
|
||||
"install_settings_dns": "DNS-сервер",
|
||||
"install_settings_dns_desc": "Вам потрібно буде налаштувати свої пристрої або маршрутизатор для використання DNS-сервера за такими адресами:",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Sử dụng truy vấn song song để tăng tốc độ giải quyết bằng cách truy vấn đồng thời tất cả các máy chủ ngược tuyến",
|
||||
"parallel_requests": "Yêu cầu song song",
|
||||
"load_balancing": "Cân bằng tải",
|
||||
"load_balancing_desc": "Chỉ truy xuất một máy chủ trong cùng thời điểm. AdGuard Home sẽ sử dụng thuật toán trọng số ngẫu nhiên để chọn một máy chủ nhanh nhất và sử dụng máy chủ đó thường xuyên hơn.",
|
||||
"load_balancing_desc": "Truy vấn một máy chủ thượng nguồn tại một thời điểm. AdGuard Home sử dụng thuật toán ngẫu nhiên có trọng số để chọn máy chủ có số lần tìm kiếm không thành công thấp nhất và thời gian tìm kiếm trung bình thấp nhất.",
|
||||
"bootstrap_dns": "Máy chủ DNS Bootstrap",
|
||||
"bootstrap_dns_desc": "Địa chỉ IP của máy chủ DNS được sử dụng để phân giải địa chỉ IP của trình phân giải DoH/DoT mà bạn chỉ định làm thượng nguồn. Bình luận không được phép.",
|
||||
"fallback_dns_title": "Máy chủ DNS dự phòng",
|
||||
"fallback_dns_desc": "Danh sách máy chủ DNS dự phòng được sử dụng khi máy chủ DNS ngược tuyến không phản hồi. Cú pháp tương tự như trong trường ngược dòng chính ở trên.",
|
||||
"fallback_dns_placeholder": "Nhập một máy chủ DNS dự phòng trên mỗi dòng",
|
||||
"local_ptr_title": "Máy chủ DNS riêng tư",
|
||||
"local_ptr_desc": "Máy chủ DNS hoặc các máy chủ mà AdGuard Home sẽ sử dụng cho các truy vấn về tài nguyên được phân phối cục bộ. Ví dụ: máy chủ này sẽ được sử dụng để phân giải tên máy khách của máy khách cho các máy khách có địa chỉ IP riêng. Nếu không được cài đặt, AdGuard Home sẽ tự động sử dụng trình phân giải DNS mặc định của bạn.",
|
||||
"local_ptr_desc": "Máy chủ DNS được AdGuard Home sử dụng cho các yêu cầu PTR, SOA và NS riêng tư. Một yêu cầu được coi là riêng tư nếu nó yêu cầu một miền ARPA chứa một mạng con trong phạm vi IP riêng tư (chẳng hạn như \"192.168.12.34\") và đến từ một máy khách có địa chỉ IP riêng tư. Nếu không được thiết lập, các trình phân giải DNS mặc định của hệ điều hành của bạn sẽ được sử dụng, ngoại trừ các địa chỉ IP của AdGuard Home.",
|
||||
"local_ptr_default_resolver": "Theo mặc định, AdGuard Home sử dụng các hệ thống phân giải tên miền ngược sau: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home không thể xác định hệ thống phân giải tên miền ngược riêng phù hợp cho hệ thống này.",
|
||||
"local_ptr_placeholder": "Nhập một địa chỉ IP trên mỗi dòng",
|
||||
"resolve_clients_title": "Kích hoạt cho phép phân giải ngược về địa chỉ IP của máy khách",
|
||||
"resolve_clients_desc": "Nếu được bật, AdGuard Home sẽ cố gắng phân giải ngược lại địa chỉ IP của khách hàng thành tên máy chủ của họ bằng cách gửi các truy vấn PTR tới trình phân giải tương ứng (máy chủ DNS riêng cho máy khách cục bộ, máy chủ ngược dòng cho máy khách có địa chỉ IP công cộng).",
|
||||
"use_private_ptr_resolvers_title": "Sử dụng trình rDNS riêng tư",
|
||||
"use_private_ptr_resolvers_desc": "Thực hiện tra cứu ngược DNS cho các địa chỉ được phân phối cục bộ bằng cách sử dụng các máy chủ nguồn. Nếu bị vô hiệu hóa, AdGuard Home sẽ phản hồi với NXDOMAIN cho tất cả các yêu cầu PTR ngoại trừ các ứng dụng khách được biết đến bởi DHCP, / etc / hosts, v. v.",
|
||||
"use_private_ptr_resolvers_desc": "Giải quyết các yêu cầu PTR, SOA và NS cho các miền ARPA chứa địa chỉ IP riêng thông qua máy chủ thượng nguồn riêng, DHCP, /etc/hosts, v. v. Nếu bị vô hiệu hóa, AdGuard Home sẽ phản hồi tất cả các yêu cầu đó bằng NXDOMAIN.",
|
||||
"check_dhcp_servers": "Kiểm tra máy chủ DHCP",
|
||||
"save_config": "Lưu thiết lập",
|
||||
"enabled_dhcp": "Máy chủ DHCP đã kích hoạt",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Sử dụng dịch vụ quản lý của phụ huynh AdGuard",
|
||||
"use_adguard_parental_hint": "AdGuard Home sẽ kiểm tra nếu tên miền chứa từ khoá người lớn. Tính năng sử dụng API thân thiện với quyền riêng tư tương tự với dịch vụ bảo vệ duyệt web",
|
||||
"enforce_safe_search": "Bắt buộc tìm kiếm an toàn",
|
||||
"enforce_save_search_hint": "AdGuard Home có thể bắt buộc tìm kiếm an toàn với các dịch vụ tìm kiếm: Google, Youtube, Bing, Yandex.",
|
||||
"enforce_save_search_hint": "AdGuard Home sẽ thực thi tìm kiếm an toàn trong các công cụ tìm kiếm sau: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Không có máy chủ nào được liệt kê",
|
||||
"general_settings": "Cài đặt chung",
|
||||
"dns_settings": "Cài đặt DNS",
|
||||
@@ -425,6 +425,9 @@
|
||||
"encryption_hostnames": "Tên máy chủ",
|
||||
"encryption_reset": "Bạn có chắc chắn muốn đặt lại cài đặt mã hóa?",
|
||||
"encryption_warning": "Cảnh báo",
|
||||
"encryption_plain_dns_enable": "Kích hoạt DNS đơn giản",
|
||||
"encryption_plain_dns_desc": "DNS đơn giản được bật theo mặc định. Bạn có thể vô hiệu hóa nó để buộc tất cả các thiết bị sử dụng DNS được mã hóa. Để thực hiện việc này, bạn phải kích hoạt ít nhất một giao thức DNS được mã hóa",
|
||||
"encryption_plain_dns_error": "Để tắt DNS đơn giản, hãy bật ít nhất một giao thức DNS được mã hóa",
|
||||
"topline_expiring_certificate": "Chứng chỉ SSL của bạn sắp hết hạn. Cập nhật <0>Cài đặt mã hóa</0>.",
|
||||
"topline_expired_certificate": "Chứng chỉ SSL của bạn đã hết hạn. Cập nhật <0>Cài đặt mã hóa</0>.",
|
||||
"form_error_port_range": "Nhập giá trị cổng trong phạm vi 80-65535",
|
||||
@@ -675,7 +678,7 @@
|
||||
"use_saved_key": "Sử dụng khóa đã lưu trước đó",
|
||||
"parental_control": "Quản lý của phụ huynh",
|
||||
"safe_browsing": "Duyệt web an toàn",
|
||||
"served_from_cache": "{{value}} <i>(được phục vụ từ bộ nhớ cache)</i>",
|
||||
"served_from_cache_label": "Được phục vụ từ bộ nhớ đệm",
|
||||
"form_error_password_length": "Mật khẩu phải dài từ {{min}} đến {{max}} ký tự",
|
||||
"anonymizer_notification": "<0> Lưu ý:</0> Tính năng ẩn danh IP được bật. Bạn có thể tắt nó trong <1> Cài đặt chung</1>.",
|
||||
"confirm_dns_cache_clear": "Bạn có chắc chắn muốn xóa bộ đệm ẩn DNS không?",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "使用并行请求以同时查询所有上游服务器来加快解析速度。",
|
||||
"parallel_requests": "并行请求",
|
||||
"load_balancing": "负载均衡",
|
||||
"load_balancing_desc": "一次查询一台服务器。AdGuard Home 使用加权随机算法来选择具有最少失败查找和最低平均查找时间的服务器。",
|
||||
"load_balancing_desc": "一次查询一台上游服务器。<br/>AdGuard Home 使用加权随机算法来选择具有最少失败查找和最低平均查找时间的服务器。",
|
||||
"bootstrap_dns": "Bootstrap DNS 服务器",
|
||||
"bootstrap_dns_desc": "DNS 服务器的 IP 地址,用于解析指定为上游的 DoH/DoT 解析器的 IP 地址。不允许添加注释。",
|
||||
"fallback_dns_title": "后备 DNS 服务器",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "使用 AdGuard 【家长控制】服务",
|
||||
"use_adguard_parental_hint": "AdGuard Home 将使用与浏览安全服务相同的隐私性强的 API 来检查域名指向的网站是否包含成人内容。",
|
||||
"enforce_safe_search": "使用安全搜索",
|
||||
"enforce_save_search_hint": "AdGuard Home 对以下搜索引擎可强制启用安全搜索:Google、YouTube、Bing、DuckDuckGo、Yandex、Pixabay。",
|
||||
"enforce_save_search_hint": "AdGuard Home 将会在下列搜索引擎中强制启用安全搜索:Google、YouTube、Bing、DuckDuckGo、Ecosia、Yandex、Pixabay。",
|
||||
"no_servers_specified": "未找到指定的服务器",
|
||||
"general_settings": "常规设置",
|
||||
"dns_settings": "DNS 设置",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "屏蔽的 TTL 应答",
|
||||
"blocked_response_ttl_desc": "指定客户端应缓存已过滤响应的秒数",
|
||||
"form_enter_blocked_response_ttl": "输入拦截的 TTL 应答(秒)",
|
||||
"upstream_timeout": "上游超时",
|
||||
"upstream_timeout_desc": "指定等待上游服务器响应的秒数",
|
||||
"form_enter_upstream_timeout": "输入上游服务器超时时间(以秒为单位)",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
"dns_over_tls": "DNS-over-TLS",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "禁用 IPv6 地址的解析",
|
||||
"disable_ipv6_desc": "丢弃对 IPv6 地址(类型 AAAA)的所有 DNS 查询,并从 HTTPS 响应中删除 IPv6 相关的信息。",
|
||||
"fastest_addr": "最快的 IP 地址",
|
||||
"fastest_addr_desc": "查询所有 DNS 服务器并返回所有响应中速度最快的 IP 地址。因 AdGuard Home 必须等待全部 DNS 服务器响应,这会降低 DNS 查询的速度,但此举将会在总体上改善连接速度。",
|
||||
"fastest_addr_desc": "等待<b>所有</b> DNS 服务器的响应,测量每个服务器的 TCP 连接速度,并返回连接速度最快的服务器的 IP 地址。<br/>如果一个或多个上游服务器没有响应,此模式会显著减慢 DNS 查询速度。确保您的上游服务器稳定且上游超时时间短。",
|
||||
"autofix_warning_text": "若您单击「修复」,AdGuard Home 将会配置您的系统以使用 AdGuard Home 的 DNS 服务器。",
|
||||
"autofix_warning_list": "其将会进行如下工作:<0>停用系统DNSStubListener</0><0>设置DNS服务器地址为127.0.0.1</0><0>将/etc/resolv.conf的符号链接目标替换为/run/systemd/resolv/resolv.conf</0><0>停止DNSStubListener(重新加载系统解析服务)</0>",
|
||||
"autofix_warning_result": "因此,默认情况下所有来自系统的 DNS 请求都将由 AdGuard Home 处理。",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"upstream_parallel": "透過同時地查詢所有上游的伺服器,使用並行的查詢以加速解析。",
|
||||
"parallel_requests": "並行的請求",
|
||||
"load_balancing": "負載平衡",
|
||||
"load_balancing_desc": "一次查詢一台伺服器。AdGuard Home 使用加權隨機演算法來選擇具有最少失敗查詢和最低平均查詢時間的伺服器。",
|
||||
"load_balancing_desc": "一次查詢一台上游伺服器。<br/>AdGuard Home 使用加權隨機演算法來選擇具有最少失敗查詢和最低平均查詢時間的伺服器。",
|
||||
"bootstrap_dns": "自我啟動(Bootstrap)DNS 伺服器",
|
||||
"bootstrap_dns_desc": "DNS 伺服器的 IP 位址,用於解析您指定為上游伺服器的 DoH/DoT 解析器的 IP 位址。不允許註釋。",
|
||||
"fallback_dns_title": "應變 DNS 伺服器",
|
||||
@@ -20,17 +20,17 @@
|
||||
"resolve_clients_title": "啟用用戶端的 IP 位址之反向的解析",
|
||||
"resolve_clients_desc": "透過傳送指標(PTR)查詢到對應的解析器(私人 DNS 伺服器供區域的用戶端,上游的伺服器供有公共 IP 位址的用戶端),反向地解析用戶端的 IP 位址變為它們的主機名稱。",
|
||||
"use_private_ptr_resolvers_title": "使用私人反向的 DNS 解析器",
|
||||
"use_private_ptr_resolvers_desc": "使用私人上游伺服器、DHCP、/etc/hosts 等方式解析包含私人 IP 位址的 ARPA 網域的 PTR、SOA 和 NS 請求。如果禁用,AdGuard Home 將對所有此類請求以 NXDOMAIN 回應。",
|
||||
"use_private_ptr_resolvers_desc": "使用私人上游伺服器、DHCP、/etc/hosts 等方式解析包含私人 IP 位址的 ARPA 網域的 PTR、SOA 和 NS 請求。如果停用,AdGuard Home 將對所有此類請求以 NXDOMAIN 回應。",
|
||||
"check_dhcp_servers": "檢查動態主機設定協定(DHCP)伺服器",
|
||||
"save_config": "儲存配置",
|
||||
"enabled_dhcp": "動態主機設定協定(DHCP)伺服器被啟用",
|
||||
"disabled_dhcp": "動態主機設定協定(DHCP)伺服器被禁用",
|
||||
"disabled_dhcp": "DHCP 伺服器已停用",
|
||||
"unavailable_dhcp": "DHCP 為不可用的",
|
||||
"unavailable_dhcp_desc": "AdGuard Home 無法於您的作業系統上執行 DHCP 伺服器",
|
||||
"dhcp_title": "動態主機設定協定(DHCP)伺服器(實驗性的!)",
|
||||
"dhcp_description": "如果您的路由器未提供動態主機設定協定(DHCP)設定,您可使用 AdGuard 自身內建的 DHCP 伺服器。",
|
||||
"dhcp_enable": "啟用動態主機設定協定(DHCP)伺服器",
|
||||
"dhcp_disable": "禁用動態主機設定協定(DHCP)伺服器",
|
||||
"dhcp_disable": "停用 DHCP 伺服器",
|
||||
"dhcp_not_found": "因為 AdGuard Home 於該網路上未發現任何現行的 DHCP 伺服器,啟用內建的動態主機設定協定(DHCP)伺服器為安全的。然而,您應手動地重新檢查那個,因為自動的探查目前不予 100% 保證。",
|
||||
"dhcp_found": "於該網路上,一個現行的動態主機設定協定(DHCP)伺服器被發現。啟用內建的 DHCP 伺服器為不安全的。",
|
||||
"dhcp_leases": "動態主機設定協定(DHCP)租約",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "使用 AdGuard 家長控制之網路服務",
|
||||
"use_adguard_parental_hint": "AdGuard Home 將檢查網域是否包含成人資料。它使用如同瀏覽安全網路服務一樣之對隱私友好的應用程式介面(API)。",
|
||||
"enforce_safe_search": "使用安全搜尋",
|
||||
"enforce_save_search_hint": "AdGuard Home 將在下列的搜尋引擎:Google、YouTube、Bing、DuckDuckGo、Yandex 和 Pixabay 中強制執行安全搜尋。",
|
||||
"enforce_save_search_hint": "AdGuard Home 將在下列的搜尋引擎:Google、YouTube、Bing、DuckDuckGo、Ecosia、Yandex 和 Pixabay 中強制執行安全搜尋。",
|
||||
"no_servers_specified": "無已明確指定的伺服器",
|
||||
"general_settings": "一般設定",
|
||||
"dns_settings": "DNS 設定",
|
||||
@@ -294,6 +294,9 @@
|
||||
"blocked_response_ttl": "已封鎖的回應之存活時間(TTL)",
|
||||
"blocked_response_ttl_desc": "對用戶端應快取受過濾的回應,指定多少秒數",
|
||||
"form_enter_blocked_response_ttl": "請輸入已封鎖回應的存活時間(秒)",
|
||||
"upstream_timeout": "上游超時",
|
||||
"upstream_timeout_desc": "指定等待來自此上游伺服器回應的秒數",
|
||||
"form_enter_upstream_timeout": "輸入上游伺服器超時時間(以秒為單位)",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
"dns_over_tls": "DNS-over-TLS",
|
||||
@@ -479,7 +482,7 @@
|
||||
"auto_clients_desc": "AdGuard Home 使用或可能使用的裝置的 IP 地址資訊。這些資訊來自多個來源,包括主機檔案、反向 DNS 等。",
|
||||
"access_title": "存取設定",
|
||||
"access_desc": "於此您可配置用於 AdGuard Home DNS 伺服器之存取規則",
|
||||
"access_allowed_title": "已允許的用戶端",
|
||||
"access_allowed_title": "被允許的用戶端",
|
||||
"access_allowed_desc": "無類別網域間路由(CIDRs)、IP 位址或<a>用戶端 IDs</a> 之清單。如果此清單有項目,AdGuard Home 將接受僅來自這些用戶端的請求。",
|
||||
"access_disallowed_title": "未被允許的用戶端",
|
||||
"access_disallowed_desc": "無類別網域間路由(CIDRs)、IP 位址或<a>用戶端 IDs</a> 之清單。如果此清單有項目,AdGuard Home 將排除來自這些用戶端的請求。如果在已允許的用戶端中有項目,此欄位被忽略。",
|
||||
@@ -560,7 +563,7 @@
|
||||
"statistics_retention_confirm": "您確定您想要更改統計資料保留嗎?如果您減少該間隔值,某些資料將被丟失",
|
||||
"statistics_cleared": "統計資料被成功地清除",
|
||||
"statistics_enable": "啟用統計資料",
|
||||
"ignore_domains": "忽略的網域(以換行符分隔)",
|
||||
"ignore_domains": "被忽略的網域(被換行分隔)",
|
||||
"ignore_domains_title": "被忽略的網域",
|
||||
"ignore_domains_desc_stats": "符合這些規則的查詢不會被記錄在統計資料中",
|
||||
"ignore_domains_desc_query": "符合這些規則的查詢不會被寫入查詢記錄中",
|
||||
@@ -598,7 +601,7 @@
|
||||
"disable_ipv6": "禁用 IPv6 位址之解析",
|
||||
"disable_ipv6_desc": "停止所有對於 IPv6 位址(類型 AAAA)的 DNS 查詢,並從 HTTPS 回應中移除 IPv6 的提示。",
|
||||
"fastest_addr": "最快的 IP 位址",
|
||||
"fastest_addr_desc": "查詢所有的 DNS 伺服器並返回在所有的回應之中最快的 IP 位址。因為 AdGuard Home 必須等待來自所有的 DNS 伺服器之回應,這使 DNS 查詢變慢,但改善總體的連線。",
|
||||
"fastest_addr_desc": "等待<b>所有</b> DNS 伺服器的回應,測量每個伺服器的 TCP 連線速度,並返回連線速度最快的伺服器的 IP 位址。<br/>如果一個或多個上游伺服器沒有回應,此模式會顯著減慢 DNS 查詢速度。確保您的上游伺服器穩定且上游超時時間短。",
|
||||
"autofix_warning_text": "如果您點擊\"修復\",AdGuard Home 將配置您的系統使用 AdGuard Home DNS 伺服器。",
|
||||
"autofix_warning_list": "它將執行這些任務:<0>撤銷系統 DNSStubListener</0> <0>設定 DNS 伺服器位址為 127.0.0.1</0> <0>用 /run/systemd/resolve/resolv.conf 取代 /etc/resolv.conf 的符號連結目標</0> <0>停止 DNSStubListener(重新載入 systemd-resolved 服務)</0>",
|
||||
"autofix_warning_result": "因此,預設下,來自您的系統之所有的 DNS 請求將被 AdGuard Home 處理。",
|
||||
@@ -637,7 +640,7 @@
|
||||
"validated_with_dnssec": "已用網域名稱系統安全性擴充功能(DNSSEC)驗證",
|
||||
"all_queries": "所有的查詢",
|
||||
"show_blocked_responses": "已封鎖的",
|
||||
"show_whitelisted_responses": "已允許的",
|
||||
"show_whitelisted_responses": "被允許的",
|
||||
"show_processed_responses": "已處理的",
|
||||
"blocked_safebrowsing": "被安全瀏覽封鎖",
|
||||
"blocked_adult_websites": "被家長控制封鎖",
|
||||
@@ -673,8 +676,8 @@
|
||||
"click_to_view_queries": "點擊以檢視查詢",
|
||||
"port_53_faq_link": "連接埠 53 常被 \"DNSStubListener\" 或 \"systemd-resolved\" 服務佔用。請閱讀有關如何解決這個的<0>用法說明</0>。",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home 將持續排除來自此用戶端之所有的 DNS 查詢。",
|
||||
"filter_allowlist": "警告:此動作也將把 \"{{disallowed_rule}}\" 規則排除在已允許的用戶端的清單之外。",
|
||||
"last_rule_in_allowlist": "因為排除 \"{{disallowed_rule}}\" 規則將禁用\"已允許的用戶端\"清單,無法不允許此用戶端。",
|
||||
"filter_allowlist": "警告:此動作也將把 \"{{disallowed_rule}}\" 規則排除在被允許的用戶端的清單之外。",
|
||||
"last_rule_in_allowlist": "因為排除 \"{{disallowed_rule}}\" 規則將禁用\"被允許的用戶端\"清單,無法不允許此用戶端。",
|
||||
"use_saved_key": "使用該先前已儲存的金鑰",
|
||||
"parental_control": "家長控制",
|
||||
"safe_browsing": "安全瀏覽",
|
||||
|
||||
@@ -46,7 +46,7 @@ export const getStats = () => async (dispatch: any) => {
|
||||
const normalizedTopClients = normalizeTopStats(stats.top_clients);
|
||||
|
||||
const clientsParams = getParamsForClientsSearch(normalizedTopClients, 'name');
|
||||
const clients = await apiClient.findClients(clientsParams);
|
||||
const clients = await apiClient.searchClients(clientsParams);
|
||||
const topClientsWithInfo = addClientInfo(normalizedTopClients, clients, 'name');
|
||||
|
||||
const normalizedStats = {
|
||||
|
||||
@@ -415,7 +415,7 @@ class Api {
|
||||
// Per-client settings
|
||||
GET_CLIENTS = { path: 'clients', method: 'GET' };
|
||||
|
||||
FIND_CLIENTS = { path: 'clients/find', method: 'GET' };
|
||||
SEARCH_CLIENTS = { path: 'clients/search', method: 'POST' };
|
||||
|
||||
ADD_CLIENT = { path: 'clients/add', method: 'POST' };
|
||||
|
||||
@@ -453,11 +453,12 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
findClients(params: any) {
|
||||
const { path, method } = this.FIND_CLIENTS;
|
||||
const url = getPathWithQueryString(path, params);
|
||||
|
||||
return this.makeRequest(url, method);
|
||||
searchClients(config: any) {
|
||||
const { path, method } = this.SEARCH_CLIENTS;
|
||||
const parameters = {
|
||||
data: config,
|
||||
};
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
// DNS access settings
|
||||
|
||||
@@ -23,7 +23,7 @@ interface RowProps {
|
||||
|
||||
const Row = ({ label, count, response_status, tooltipTitle, translationComponents }: RowProps) => {
|
||||
const content = response_status ? (
|
||||
<LogsSearchLink response_status={response_status}>{formatNumber(count)}</LogsSearchLink>
|
||||
<LogsSearchLink response_status={response_status}>{count}</LogsSearchLink>
|
||||
) : (
|
||||
count
|
||||
);
|
||||
@@ -77,16 +77,16 @@ const Counters = ({ refreshButton, subtitle }: CountersProps) => {
|
||||
? t('number_of_dns_query_hours', { count: msToHours(interval) })
|
||||
: t('number_of_dns_query_days', { count: msToDays(interval) });
|
||||
|
||||
const rows = [
|
||||
const rows: RowProps[] = [
|
||||
{
|
||||
label: 'dns_query',
|
||||
count: numDnsQueries.toString(),
|
||||
count: formatNumber(numDnsQueries),
|
||||
tooltipTitle: dnsQueryTooltip,
|
||||
response_status: RESPONSE_FILTER.ALL.QUERY,
|
||||
},
|
||||
{
|
||||
label: 'blocked_by',
|
||||
count: numBlockedFiltering.toString(),
|
||||
count: formatNumber(numBlockedFiltering),
|
||||
tooltipTitle: 'number_of_dns_query_blocked_24_hours',
|
||||
response_status: RESPONSE_FILTER.BLOCKED.QUERY,
|
||||
|
||||
@@ -98,19 +98,19 @@ const Counters = ({ refreshButton, subtitle }: CountersProps) => {
|
||||
},
|
||||
{
|
||||
label: 'stats_malware_phishing',
|
||||
count: numReplacedSafebrowsing.toString(),
|
||||
count: formatNumber(numReplacedSafebrowsing),
|
||||
tooltipTitle: 'number_of_dns_query_blocked_24_hours_by_sec',
|
||||
response_status: RESPONSE_FILTER.BLOCKED_THREATS.QUERY,
|
||||
},
|
||||
{
|
||||
label: 'stats_adult',
|
||||
count: numReplacedParental.toString(),
|
||||
count: formatNumber(numReplacedParental),
|
||||
tooltipTitle: 'number_of_dns_query_blocked_24_hours_adult',
|
||||
response_status: RESPONSE_FILTER.BLOCKED_ADULT_WEBSITES.QUERY,
|
||||
},
|
||||
{
|
||||
label: 'enforced_save_search',
|
||||
count: numReplacedSafesearch.toString(),
|
||||
count: formatNumber(numReplacedSafesearch),
|
||||
tooltipTitle: 'number_of_dns_query_to_safe_search',
|
||||
response_status: RESPONSE_FILTER.SAFE_SEARCH.QUERY,
|
||||
},
|
||||
|
||||
@@ -10,6 +10,7 @@ import Card from '../ui/Card';
|
||||
|
||||
import DomainCell from './DomainCell';
|
||||
import { DASHBOARD_TABLES_DEFAULT_PAGE_SIZE, TABLES_MIN_ROWS } from '../../helpers/constants';
|
||||
import { formatNumber } from '../../helpers/helpers';
|
||||
|
||||
interface TimeCellProps {
|
||||
value?: string | number;
|
||||
@@ -20,7 +21,7 @@ const TimeCell = ({ value }: TimeCellProps) => {
|
||||
return '–';
|
||||
}
|
||||
|
||||
const valueInMilliseconds = round(Number(value) * 1000);
|
||||
const valueInMilliseconds = formatNumber(round(Number(value) * 1000));
|
||||
|
||||
return (
|
||||
<div className="logs__row o-hidden">
|
||||
|
||||
@@ -154,7 +154,7 @@ const Dashboard = ({
|
||||
}}
|
||||
disabled={processingProtection}>
|
||||
{protectionDisabledDuration
|
||||
? `${t('enable_protection_timer')} ${getRemaningTimeText(protectionDisabledDuration)}`
|
||||
? `${t('enable_protection_timer', { time: getRemaningTimeText(protectionDisabledDuration) })}`
|
||||
: getProtectionBtnText(protectionEnabled)}
|
||||
</button>
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ const ClientsTable = ({
|
||||
return content;
|
||||
}
|
||||
|
||||
return <LogsSearchLink search={row.original.ids[0]}>{content}</LogsSearchLink>;
|
||||
return <LogsSearchLink search={row.original.name}>{content}</LogsSearchLink>;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7,8 +7,19 @@ import classnames from 'classnames';
|
||||
|
||||
import Examples from './Examples';
|
||||
|
||||
import { renderRadioField, renderTextareaField, CheckboxField } from '../../../../helpers/form';
|
||||
import { DNS_REQUEST_OPTIONS, FORM_NAME, UPSTREAM_CONFIGURATION_WIKI_LINK } from '../../../../helpers/constants';
|
||||
import {
|
||||
renderRadioField,
|
||||
renderTextareaField,
|
||||
CheckboxField,
|
||||
renderInputField,
|
||||
toNumber,
|
||||
} from '../../../../helpers/form';
|
||||
import {
|
||||
DNS_REQUEST_OPTIONS,
|
||||
FORM_NAME,
|
||||
UINT32_RANGE,
|
||||
UPSTREAM_CONFIGURATION_WIKI_LINK,
|
||||
} from '../../../../helpers/constants';
|
||||
|
||||
import { testUpstreamWithFormValues } from '../../../../actions';
|
||||
|
||||
@@ -17,6 +28,7 @@ import { removeEmptyLines, trimLinesAndRemoveEmpty } from '../../../../helpers/h
|
||||
import { getTextareaCommentsHighlight, syncScroll } from '../../../../helpers/highlightTextareaComments';
|
||||
import '../../../ui/texareaCommentsHighlight.css';
|
||||
import { RootState } from '../../../../initialState';
|
||||
import { validateRequiredValue } from '../../../../helpers/validators';
|
||||
|
||||
const UPSTREAM_DNS_NAME = 'upstream_dns';
|
||||
const UPSTREAM_MODE_NAME = 'upstream_mode';
|
||||
@@ -301,7 +313,7 @@ const Form = ({ submitting, invalid, handleSubmit }: FormProps) => {
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div className="col-12 mb-4">
|
||||
<div className="col-12">
|
||||
<Field
|
||||
name="resolve_clients"
|
||||
type="checkbox"
|
||||
@@ -311,6 +323,34 @@ const Form = ({ submitting, invalid, handleSubmit }: FormProps) => {
|
||||
disabled={processingSetConfig}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-12">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div className="col-12 col-md-7">
|
||||
<div className="form__group">
|
||||
<label htmlFor="upstream_timeout" className="form__label form__label--with-desc">
|
||||
<Trans>upstream_timeout</Trans>
|
||||
</label>
|
||||
|
||||
<div className="form__desc form__desc--top">
|
||||
<Trans>upstream_timeout_desc</Trans>
|
||||
</div>
|
||||
|
||||
<Field
|
||||
name="upstream_timeout"
|
||||
type="number"
|
||||
component={renderInputField}
|
||||
className="form-control"
|
||||
placeholder={t('form_enter_upstream_timeout')}
|
||||
normalize={toNumber}
|
||||
validate={validateRequiredValue}
|
||||
min={1}
|
||||
max={UINT32_RANGE.MAX}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="card-actions">
|
||||
|
||||
@@ -19,6 +19,7 @@ const Upstream = () => {
|
||||
resolve_clients,
|
||||
local_ptr_upstreams,
|
||||
use_private_ptr_resolvers,
|
||||
upstream_timeout,
|
||||
} = useSelector((state: RootState) => state.dnsConfig, shallowEqual);
|
||||
|
||||
const upstream_dns_file = useSelector((state: RootState) => state.dnsConfig.upstream_dns_file);
|
||||
@@ -32,6 +33,7 @@ const Upstream = () => {
|
||||
resolve_clients,
|
||||
local_ptr_upstreams,
|
||||
use_private_ptr_resolvers,
|
||||
upstream_timeout,
|
||||
} = values;
|
||||
|
||||
const dnsConfig = {
|
||||
@@ -41,6 +43,7 @@ const Upstream = () => {
|
||||
resolve_clients,
|
||||
local_ptr_upstreams,
|
||||
use_private_ptr_resolvers,
|
||||
upstream_timeout,
|
||||
...(upstream_dns_file ? null : { upstream_dns }),
|
||||
};
|
||||
|
||||
@@ -64,6 +67,7 @@ const Upstream = () => {
|
||||
resolve_clients,
|
||||
local_ptr_upstreams,
|
||||
use_private_ptr_resolvers,
|
||||
upstream_timeout,
|
||||
}}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
|
||||
@@ -14,6 +14,17 @@
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.guide__list {
|
||||
margin-top: 16px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.guide__list {
|
||||
padding-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.guide__address {
|
||||
display: block;
|
||||
margin-bottom: 7px;
|
||||
|
||||
@@ -33,13 +33,13 @@ const SetupGuide = ({
|
||||
<Trans>install_devices_address</Trans>:
|
||||
</div>
|
||||
|
||||
<div className="mt-3">
|
||||
<ul className="guide__list">
|
||||
{dnsAddresses.map((ip: any) => (
|
||||
<li key={ip} className="guide__address">
|
||||
{ip}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<Guide dnsAddresses={dnsAddresses} />
|
||||
|
||||
@@ -238,6 +238,12 @@ export default {
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_51.txt"
|
||||
},
|
||||
"hagezi_samsung_tracker_blocklist": {
|
||||
"name": "HaGeZi's Samsung Tracker Blocklist",
|
||||
"categoryId": "other",
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_61.txt"
|
||||
},
|
||||
"hagezi_the_worlds_most_abused_tlds": {
|
||||
"name": "HaGeZi's The World's Most Abused TLDs",
|
||||
"categoryId": "security",
|
||||
@@ -256,6 +262,18 @@ export default {
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_49.txt"
|
||||
},
|
||||
"hagezi_windows_office_tracker_blocklist": {
|
||||
"name": "HaGeZi's Windows/Office Tracker Blocklist",
|
||||
"categoryId": "other",
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_63.txt"
|
||||
},
|
||||
"hagezi_xiaomi_tracking_blocklist": {
|
||||
"name": "HaGeZi's Xiaomi Tracker Blocklist",
|
||||
"categoryId": "other",
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_60.txt"
|
||||
},
|
||||
"no_google": {
|
||||
"name": "No Google",
|
||||
"categoryId": "other",
|
||||
@@ -340,17 +358,17 @@ export default {
|
||||
"homepage": "https://github.com/uBlockOrigin/uAssets",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_50.txt"
|
||||
},
|
||||
"ukrainian_security_filter": {
|
||||
"name": "Ukrainian Security Filter",
|
||||
"categoryId": "other",
|
||||
"homepage": "https://github.com/braveinnovators/ukrainian-security-filter",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_62.txt"
|
||||
},
|
||||
"urlhaus_filter_online": {
|
||||
"name": "Malicious URL Blocklist (URLHaus)",
|
||||
"categoryId": "security",
|
||||
"homepage": "https://urlhaus.abuse.ch/",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_11.txt"
|
||||
},
|
||||
"windowsspyblocker_hosts_spy_rules": {
|
||||
"name": "WindowsSpyBlocker - Hosts spy rules",
|
||||
"categoryId": "other",
|
||||
"homepage": "https://github.com/crazy-max/WindowsSpyBlocker",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_23.txt"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,13 +451,10 @@ export const getParamsForClientsSearch = (data: any, param: any, additionalParam
|
||||
clients.add(e[additionalParam]);
|
||||
}
|
||||
});
|
||||
const params = {};
|
||||
const ids = Array.from(clients.values());
|
||||
ids.forEach((id, i) => {
|
||||
params[`ip${i}`] = id;
|
||||
});
|
||||
|
||||
return params;
|
||||
return {
|
||||
clients: Array.from(clients).map((id) => ({ id })),
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -524,7 +521,7 @@ export const getObjDiff = (initialValues: any, values: any) =>
|
||||
* @param num {number} to format
|
||||
* @returns {string} Returns a string with a language-sensitive representation of this number
|
||||
*/
|
||||
export const formatNumber = (num: any) => {
|
||||
export const formatNumber = (num: number): string => {
|
||||
const currentLanguage = i18n.languages[0] || DEFAULT_LANGUAGE;
|
||||
return num.toLocaleString(currentLanguage);
|
||||
};
|
||||
@@ -673,9 +670,16 @@ export const countClientsStatistics = (ids: any, autoClients: any) => {
|
||||
* @param {function} t translate
|
||||
* @returns {string}
|
||||
*/
|
||||
export const formatElapsedMs = (elapsedMs: any, t: any) => {
|
||||
const formattedElapsedMs = parseInt(elapsedMs, 10) || parseFloat(elapsedMs).toFixed(2);
|
||||
return `${formattedElapsedMs} ${t('milliseconds_abbreviation')}`;
|
||||
export const formatElapsedMs = (elapsedMs: string, t: (key: string) => string) => {
|
||||
const parsedElapsedMs = parseInt(elapsedMs, 10);
|
||||
|
||||
if (Number.isNaN(parsedElapsedMs)) {
|
||||
return elapsedMs;
|
||||
}
|
||||
|
||||
const formattedMs = formatNumber(parsedElapsedMs);
|
||||
|
||||
return `${formattedMs} ${t('milliseconds_abbreviation')}`;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -757,12 +761,9 @@ type NestedObject = {
|
||||
order: number;
|
||||
};
|
||||
|
||||
export const getObjectKeysSorted = <
|
||||
T extends Record<string, NestedObject>,
|
||||
K extends keyof NestedObject
|
||||
>(
|
||||
export const getObjectKeysSorted = <T extends Record<string, NestedObject>, K extends keyof NestedObject>(
|
||||
object: T,
|
||||
sortKey: K
|
||||
sortKey: K,
|
||||
): string[] => {
|
||||
return Object.entries(object)
|
||||
.sort(([, a], [, b]) => (a[sortKey] as number) - (b[sortKey] as number))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -304,6 +304,7 @@ export type DnsConfigData = {
|
||||
blocking_ipv4: string;
|
||||
blocking_ipv6: string;
|
||||
blocked_response_ttl: number;
|
||||
upstream_timeout: number;
|
||||
edns_cs_enabled: boolean;
|
||||
disable_ipv6: boolean;
|
||||
dnssec_enabled: boolean;
|
||||
@@ -489,6 +490,7 @@ export const initialState: RootState = {
|
||||
blocking_ipv4: DEFAULT_BLOCKING_IPV4,
|
||||
blocking_ipv6: DEFAULT_BLOCKING_IPV6,
|
||||
blocked_response_ttl: 10,
|
||||
upstream_timeout: 10,
|
||||
edns_cs_enabled: false,
|
||||
disable_ipv6: false,
|
||||
dnssec_enabled: false,
|
||||
|
||||
@@ -66,6 +66,7 @@ const dnsConfig = handleActions(
|
||||
blocking_ipv4: DEFAULT_BLOCKING_IPV4,
|
||||
blocking_ipv6: DEFAULT_BLOCKING_IPV6,
|
||||
blocked_response_ttl: 10,
|
||||
upstream_timeout: 10,
|
||||
edns_cs_enabled: false,
|
||||
disable_ipv6: false,
|
||||
dnssec_enabled: false,
|
||||
|
||||
54
go.mod
54
go.mod
@@ -1,24 +1,25 @@
|
||||
module github.com/AdguardTeam/AdGuardHome
|
||||
|
||||
go 1.23.1
|
||||
go 1.23.6
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/dnsproxy v0.73.0
|
||||
github.com/AdguardTeam/golibs v0.26.0
|
||||
github.com/AdguardTeam/urlfilter v0.19.0
|
||||
github.com/AdguardTeam/dnsproxy v0.75.0
|
||||
github.com/AdguardTeam/golibs v0.32.1
|
||||
github.com/AdguardTeam/urlfilter v0.20.0
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/ameshkov/dnscrypt/v2 v2.3.0
|
||||
github.com/bluele/gcache v0.0.2
|
||||
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500
|
||||
github.com/digineo/go-ipset/v2 v2.2.1
|
||||
github.com/dimfeld/httptreemux/v5 v5.5.0
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/go-ping/ping v1.1.0
|
||||
github.com/fsnotify/fsnotify v1.8.0
|
||||
// TODO(e.burkov): This package is deprecated; find a new one or use our
|
||||
// own code for that. Perhaps, use gopacket.
|
||||
github.com/go-ping/ping v1.2.0
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/google/renameio/v2 v2.0.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905
|
||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86
|
||||
github.com/kardianos/service v1.2.2
|
||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
|
||||
@@ -27,15 +28,15 @@ require (
|
||||
// TODO(a.garipov): This package is deprecated; find a new one or use our
|
||||
// own code for that. Perhaps, use gopacket.
|
||||
github.com/mdlayher/raw v0.1.0
|
||||
github.com/miekg/dns v1.1.61
|
||||
github.com/quic-go/quic-go v0.44.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/miekg/dns v1.1.63
|
||||
github.com/quic-go/quic-go v0.49.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/ti-mo/netfilter v0.5.2
|
||||
go.etcd.io/bbolt v1.3.10
|
||||
golang.org/x/crypto v0.26.0
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
|
||||
golang.org/x/net v0.28.0
|
||||
golang.org/x/sys v0.24.0
|
||||
go.etcd.io/bbolt v1.4.0
|
||||
golang.org/x/crypto v0.32.0
|
||||
golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3
|
||||
golang.org/x/net v0.34.0
|
||||
golang.org/x/sys v0.30.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
howett.net/plist v1.0.1
|
||||
@@ -48,19 +49,20 @@ require (
|
||||
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240521024322-9665fa269a30 // indirect
|
||||
github.com/google/pprof v0.0.0-20250202011525-fc3143867406 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.17.3 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.22.2 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
golang.org/x/mod v0.20.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
gonum.org/v1/gonum v0.15.0 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/mod v0.23.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/tools v0.29.0 // indirect
|
||||
gonum.org/v1/gonum v0.15.1 // indirect
|
||||
)
|
||||
|
||||
112
go.sum
112
go.sum
@@ -1,9 +1,9 @@
|
||||
github.com/AdguardTeam/dnsproxy v0.73.0 h1:E1fxzosMqExZH8h7OJnKXLxyktcAFRJapLF4+nKULms=
|
||||
github.com/AdguardTeam/dnsproxy v0.73.0/go.mod h1:ZcvmyQY2EiX5B0yCTkiYTgtm+1lBWA0lajbEI9dOhW4=
|
||||
github.com/AdguardTeam/golibs v0.26.0 h1:uLL0XggEjB+87lL1tPpEAQNoKAlHDq5AyBUVWEgf63E=
|
||||
github.com/AdguardTeam/golibs v0.26.0/go.mod h1:iWdjXPCwmK2g2FKIb/OwEPnovSXeMqRhI8FWLxF5oxE=
|
||||
github.com/AdguardTeam/urlfilter v0.19.0 h1:q7eH13+yNETlpD/VD3u5rLQOripcUdEktqZFy+KiQLk=
|
||||
github.com/AdguardTeam/urlfilter v0.19.0/go.mod h1:+N54ZvxqXYLnXuvpaUhK2exDQW+djZBRSb6F6j0rkBY=
|
||||
github.com/AdguardTeam/dnsproxy v0.75.0 h1:v8/Oq/xPYzNoALR7SEUZEIbKmjnPcXLVhJLFVbrozEc=
|
||||
github.com/AdguardTeam/dnsproxy v0.75.0/go.mod h1:O2qoXwF4BUBFui7OMUiWSYwapEDcYxKWeur4+jfy9nM=
|
||||
github.com/AdguardTeam/golibs v0.32.1 h1:Ajf6Q0k+A9zjFbj8HOzNAbHImrV4JtbT0vwy02D6VeI=
|
||||
github.com/AdguardTeam/golibs v0.32.1/go.mod h1:dXRLSsnJQDxOfQVl0ochy1bfk4NgnJQGQdR1YPJdwcw=
|
||||
github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs=
|
||||
github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk=
|
||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||
@@ -25,16 +25,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/digineo/go-ipset/v2 v2.2.1 h1:k6skY+0fMqeUjjeWO/m5OuWPSZUAn7AucHMnQ1MX77g=
|
||||
github.com/digineo/go-ipset/v2 v2.2.1/go.mod h1:wBsNzJlZlABHUITkesrggFnZQtgW5wkqw1uo8Qxe0VU=
|
||||
github.com/dimfeld/httptreemux/v5 v5.5.0 h1:p8jkiMrCuZ0CmhwYLcbNbl7DDo21fozhKHQ2PccwOFQ=
|
||||
github.com/dimfeld/httptreemux/v5 v5.5.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
|
||||
github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
|
||||
github.com/go-ping/ping v1.2.0 h1:vsJ8slZBZAXNCK4dPcI2PEE9eM9n9RbXbGouVQ/Y4yQ=
|
||||
github.com/go-ping/ping v1.2.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
@@ -44,8 +42,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/pprof v0.0.0-20240521024322-9665fa269a30 h1:r6YdmbD41tGHeCWDyHF691LWtL7D1iSTyJaKejTWwVU=
|
||||
github.com/google/pprof v0.0.0-20240521024322-9665fa269a30/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||
github.com/google/pprof v0.0.0-20250202011525-fc3143867406 h1:wlQI2cYY0BsWmmPPAnxfQ8SDW0S3Jasn+4B8kXFxprg=
|
||||
github.com/google/pprof v0.0.0-20250202011525-fc3143867406/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
|
||||
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -53,8 +51,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8=
|
||||
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49 h1:/OuvSMGT9+xnyZ+7MZQ1zdngaCCAdPoSw8B/uurZ7pg=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk=
|
||||
@@ -78,18 +76,18 @@ github.com/mdlayher/raw v0.1.0/go.mod h1:yXnxvs6c0XoF/aK52/H5PjsVHmWBCFfZUfoh/Y5
|
||||
github.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E=
|
||||
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||
github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
|
||||
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
|
||||
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
|
||||
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU=
|
||||
github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
|
||||
github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE=
|
||||
github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
|
||||
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
|
||||
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
|
||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
|
||||
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
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/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -97,10 +95,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
|
||||
github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94=
|
||||
github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
@@ -109,8 +109,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/ti-mo/netfilter v0.2.0/go.mod h1:8GbBGsY/8fxtyIdfwy29JiluNcPK4K7wIT+x42ipqUU=
|
||||
github.com/ti-mo/netfilter v0.5.2 h1:CTjOwFuNNeZ9QPdRXt1MZFLFUf84cKtiQutNauHWd40=
|
||||
github.com/ti-mo/netfilter v0.5.2/go.mod h1:Btx3AtFiOVdHReTDmP9AE+hlkOcvIy403u7BXXbWZKo=
|
||||
@@ -122,32 +122,32 @@ github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
|
||||
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
|
||||
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3 h1:qNgPs5exUA+G0C96DrPwNrvLSj7GT/9D+3WMWUcUg34=
|
||||
golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
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.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -158,25 +158,25 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ=
|
||||
gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0=
|
||||
gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o=
|
||||
google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
|
||||
google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -14,12 +14,6 @@ import (
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
)
|
||||
|
||||
// HTTP scheme constants.
|
||||
const (
|
||||
SchemeHTTP = "http"
|
||||
SchemeHTTPS = "https"
|
||||
)
|
||||
|
||||
// RegisterFunc is the function that sets the handler to handle the URL for the
|
||||
// method.
|
||||
//
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
@@ -19,6 +20,13 @@ import (
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
|
||||
// Default file, binary, and directory permissions.
|
||||
const (
|
||||
DefaultPermDir fs.FileMode = 0o700
|
||||
DefaultPermExe fs.FileMode = 0o700
|
||||
DefaultPermFile fs.FileMode = 0o600
|
||||
)
|
||||
|
||||
// Unsupported is a helper that returns a wrapped [errors.ErrUnsupported].
|
||||
func Unsupported(op string) (err error) {
|
||||
return fmt.Errorf("%s: not supported on %s: %w", op, runtime.GOOS, errors.ErrUnsupported)
|
||||
@@ -138,16 +146,6 @@ func IsOpenWrt() (ok bool) {
|
||||
return isOpenWrt()
|
||||
}
|
||||
|
||||
// NotifyReconfigureSignal notifies c on receiving reconfigure signals.
|
||||
func NotifyReconfigureSignal(c chan<- os.Signal) {
|
||||
notifyReconfigureSignal(c)
|
||||
}
|
||||
|
||||
// IsReconfigureSignal returns true if sig is a reconfigure signal.
|
||||
func IsReconfigureSignal(sig os.Signal) (ok bool) {
|
||||
return isReconfigureSignal(sig)
|
||||
}
|
||||
|
||||
// SendShutdownSignal sends the shutdown signal to the channel.
|
||||
func SendShutdownSignal(c chan<- os.Signal) {
|
||||
sendShutdownSignal(c)
|
||||
|
||||
@@ -1,22 +1,11 @@
|
||||
//go:build darwin || freebsd || linux || openbsd
|
||||
//go:build unix
|
||||
|
||||
package aghos
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func notifyReconfigureSignal(c chan<- os.Signal) {
|
||||
signal.Notify(c, unix.SIGHUP)
|
||||
}
|
||||
|
||||
func isReconfigureSignal(sig os.Signal) (ok bool) {
|
||||
return sig == unix.SIGHUP
|
||||
}
|
||||
|
||||
func sendShutdownSignal(_ chan<- os.Signal) {
|
||||
// On Unix we are already notified by the system.
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ package aghos
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func setRlimit(val uint64) (err error) {
|
||||
func setRlimit(_ uint64) (err error) {
|
||||
return Unsupported("setrlimit")
|
||||
}
|
||||
|
||||
@@ -38,14 +37,6 @@ func isOpenWrt() (ok bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
func notifyReconfigureSignal(c chan<- os.Signal) {
|
||||
signal.Notify(c, windows.SIGHUP)
|
||||
}
|
||||
|
||||
func isReconfigureSignal(sig os.Signal) (ok bool) {
|
||||
return sig == windows.SIGHUP
|
||||
}
|
||||
|
||||
func sendShutdownSignal(c chan<- os.Signal) {
|
||||
c <- os.Interrupt
|
||||
}
|
||||
|
||||
@@ -62,7 +62,9 @@ func newPendingFile(filePath string, mode fs.FileMode) (f PendingFile, err error
|
||||
return nil, fmt.Errorf("opening pending file: %w", err)
|
||||
}
|
||||
|
||||
err = file.Chmod(mode)
|
||||
// TODO(e.burkov): The [os.Chmod] implementation is useless on Windows,
|
||||
// investigate if it can be removed.
|
||||
err = os.Chmod(file.Name(), mode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("preparing pending file: %w", err)
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func (w *FSWatcher) Add(name string) (err error) {
|
||||
|
||||
// ServiceWithConfig is a fake [agh.ServiceWithConfig] implementation for tests.
|
||||
type ServiceWithConfig[ConfigType any] struct {
|
||||
OnStart func() (err error)
|
||||
OnStart func(ctx context.Context) (err error)
|
||||
OnShutdown func(ctx context.Context) (err error)
|
||||
OnConfig func() (c ConfigType)
|
||||
}
|
||||
@@ -68,8 +68,8 @@ var _ agh.ServiceWithConfig[struct{}] = (*ServiceWithConfig[struct{}])(nil)
|
||||
|
||||
// Start implements the [agh.ServiceWithConfig] interface for
|
||||
// *ServiceWithConfig.
|
||||
func (s *ServiceWithConfig[_]) Start() (err error) {
|
||||
return s.OnStart()
|
||||
func (s *ServiceWithConfig[_]) Start(ctx context.Context) (err error) {
|
||||
return s.OnStart(ctx)
|
||||
}
|
||||
|
||||
// Shutdown implements the [agh.ServiceWithConfig] interface for
|
||||
@@ -89,14 +89,14 @@ func (s *ServiceWithConfig[ConfigType]) Config() (c ConfigType) {
|
||||
// AddressProcessor is a fake [client.AddressProcessor] implementation for
|
||||
// tests.
|
||||
type AddressProcessor struct {
|
||||
OnProcess func(ip netip.Addr)
|
||||
OnProcess func(ctx context.Context, ip netip.Addr)
|
||||
OnClose func() (err error)
|
||||
}
|
||||
|
||||
// Process implements the [client.AddressProcessor] interface for
|
||||
// *AddressProcessor.
|
||||
func (p *AddressProcessor) Process(ip netip.Addr) {
|
||||
p.OnProcess(ip)
|
||||
func (p *AddressProcessor) Process(ctx context.Context, ip netip.Addr) {
|
||||
p.OnProcess(ctx, ip)
|
||||
}
|
||||
|
||||
// Close implements the [client.AddressProcessor] interface for
|
||||
@@ -107,13 +107,18 @@ func (p *AddressProcessor) Close() (err error) {
|
||||
|
||||
// AddressUpdater is a fake [client.AddressUpdater] implementation for tests.
|
||||
type AddressUpdater struct {
|
||||
OnUpdateAddress func(ip netip.Addr, host string, info *whois.Info)
|
||||
OnUpdateAddress func(ctx context.Context, ip netip.Addr, host string, info *whois.Info)
|
||||
}
|
||||
|
||||
// UpdateAddress implements the [client.AddressUpdater] interface for
|
||||
// *AddressUpdater.
|
||||
func (p *AddressUpdater) UpdateAddress(ip netip.Addr, host string, info *whois.Info) {
|
||||
p.OnUpdateAddress(ip, host, info)
|
||||
func (p *AddressUpdater) UpdateAddress(
|
||||
ctx context.Context,
|
||||
ip netip.Addr,
|
||||
host string,
|
||||
info *whois.Info,
|
||||
) {
|
||||
p.OnUpdateAddress(ctx, ip, host, info)
|
||||
}
|
||||
|
||||
// Package dnsforward
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/rdns"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/whois"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
)
|
||||
@@ -22,7 +21,7 @@ const ErrClosed errors.Error = "use of closed address processor"
|
||||
|
||||
// AddressProcessor is the interface for types that can process clients.
|
||||
type AddressProcessor interface {
|
||||
Process(ip netip.Addr)
|
||||
Process(ctx context.Context, ip netip.Addr)
|
||||
Close() (err error)
|
||||
}
|
||||
|
||||
@@ -33,7 +32,7 @@ type EmptyAddrProc struct{}
|
||||
var _ AddressProcessor = EmptyAddrProc{}
|
||||
|
||||
// Process implements the [AddressProcessor] interface for EmptyAddrProc.
|
||||
func (EmptyAddrProc) Process(_ netip.Addr) {}
|
||||
func (EmptyAddrProc) Process(_ context.Context, _ netip.Addr) {}
|
||||
|
||||
// Close implements the [AddressProcessor] interface for EmptyAddrProc.
|
||||
func (EmptyAddrProc) Close() (_ error) { return nil }
|
||||
@@ -90,12 +89,15 @@ type DefaultAddrProcConfig struct {
|
||||
type AddressUpdater interface {
|
||||
// UpdateAddress updates information about an IP address, setting host (if
|
||||
// not empty) and WHOIS information (if not nil).
|
||||
UpdateAddress(ip netip.Addr, host string, info *whois.Info)
|
||||
UpdateAddress(ctx context.Context, ip netip.Addr, host string, info *whois.Info)
|
||||
}
|
||||
|
||||
// DefaultAddrProc processes incoming client addresses with rDNS and WHOIS, if
|
||||
// configured, and updates that information in a client storage.
|
||||
type DefaultAddrProc struct {
|
||||
// logger is used to log the operation of address processor.
|
||||
logger *slog.Logger
|
||||
|
||||
// clientIPsMu serializes closure of clientIPs and access to isClosed.
|
||||
clientIPsMu *sync.Mutex
|
||||
|
||||
@@ -142,6 +144,7 @@ const (
|
||||
// not be nil.
|
||||
func NewDefaultAddrProc(c *DefaultAddrProcConfig) (p *DefaultAddrProc) {
|
||||
p = &DefaultAddrProc{
|
||||
logger: c.BaseLogger.With(slogutil.KeyPrefix, "addrproc"),
|
||||
clientIPsMu: &sync.Mutex{},
|
||||
clientIPs: make(chan netip.Addr, defaultQueueSize),
|
||||
rdns: &rdns.Empty{},
|
||||
@@ -164,10 +167,13 @@ func NewDefaultAddrProc(c *DefaultAddrProcConfig) (p *DefaultAddrProc) {
|
||||
p.whois = newWHOIS(c.BaseLogger.With(slogutil.KeyPrefix, "whois"), c.DialContext)
|
||||
}
|
||||
|
||||
go p.process(c.CatchPanics)
|
||||
// TODO(s.chzhen): Pass context.
|
||||
ctx := context.TODO()
|
||||
|
||||
go p.process(ctx, c.CatchPanics)
|
||||
|
||||
for _, ip := range c.InitialAddresses {
|
||||
p.Process(ip)
|
||||
p.Process(ctx, ip)
|
||||
}
|
||||
|
||||
return p
|
||||
@@ -210,7 +216,7 @@ func newWHOIS(logger *slog.Logger, dialFunc aghnet.DialContextFunc) (w whois.Int
|
||||
var _ AddressProcessor = (*DefaultAddrProc)(nil)
|
||||
|
||||
// Process implements the [AddressProcessor] interface for *DefaultAddrProc.
|
||||
func (p *DefaultAddrProc) Process(ip netip.Addr) {
|
||||
func (p *DefaultAddrProc) Process(ctx context.Context, ip netip.Addr) {
|
||||
p.clientIPsMu.Lock()
|
||||
defer p.clientIPsMu.Unlock()
|
||||
|
||||
@@ -222,38 +228,42 @@ func (p *DefaultAddrProc) Process(ip netip.Addr) {
|
||||
case p.clientIPs <- ip:
|
||||
// Go on.
|
||||
default:
|
||||
log.Debug("clients: ip channel is full; len: %d", len(p.clientIPs))
|
||||
p.logger.DebugContext(ctx, "ip channel is full", "len", len(p.clientIPs))
|
||||
}
|
||||
}
|
||||
|
||||
// process processes the incoming client IP-address information. It is intended
|
||||
// to be used as a goroutine. Once clientIPs is closed, process exits.
|
||||
func (p *DefaultAddrProc) process(catchPanics bool) {
|
||||
func (p *DefaultAddrProc) process(ctx context.Context, catchPanics bool) {
|
||||
if catchPanics {
|
||||
defer log.OnPanic("addrProcessor.process")
|
||||
defer slogutil.RecoverAndLog(ctx, p.logger)
|
||||
}
|
||||
|
||||
log.Info("clients: processing addresses")
|
||||
|
||||
ctx := context.TODO()
|
||||
p.logger.InfoContext(ctx, "processing addresses")
|
||||
|
||||
for ip := range p.clientIPs {
|
||||
host := p.processRDNS(ctx, ip)
|
||||
info := p.processWHOIS(ctx, ip)
|
||||
|
||||
p.addrUpdater.UpdateAddress(ip, host, info)
|
||||
p.addrUpdater.UpdateAddress(ctx, ip, host, info)
|
||||
}
|
||||
|
||||
log.Info("clients: finished processing addresses")
|
||||
p.logger.InfoContext(ctx, "finished processing addresses")
|
||||
}
|
||||
|
||||
// processRDNS resolves the clients' IP addresses using reverse DNS. host is
|
||||
// empty if there were errors or if the information hasn't changed.
|
||||
func (p *DefaultAddrProc) processRDNS(ctx context.Context, ip netip.Addr) (host string) {
|
||||
start := time.Now()
|
||||
log.Debug("clients: processing %s with rdns", ip)
|
||||
p.logger.DebugContext(ctx, "processing rdns", "ip", ip)
|
||||
defer func() {
|
||||
log.Debug("clients: finished processing %s with rdns in %s", ip, time.Since(start))
|
||||
p.logger.DebugContext(
|
||||
ctx,
|
||||
"finished processing rdns",
|
||||
"ip", ip,
|
||||
"host", host,
|
||||
"elapsed", time.Since(start),
|
||||
)
|
||||
}()
|
||||
|
||||
ok := p.shouldResolve(ip)
|
||||
@@ -280,9 +290,15 @@ func (p *DefaultAddrProc) shouldResolve(ip netip.Addr) (ok bool) {
|
||||
// hasn't changed.
|
||||
func (p *DefaultAddrProc) processWHOIS(ctx context.Context, ip netip.Addr) (info *whois.Info) {
|
||||
start := time.Now()
|
||||
log.Debug("clients: processing %s with whois", ip)
|
||||
p.logger.DebugContext(ctx, "processing whois", "ip", ip)
|
||||
defer func() {
|
||||
log.Debug("clients: finished processing %s with whois in %s", ip, time.Since(start))
|
||||
p.logger.DebugContext(
|
||||
ctx,
|
||||
"finished processing whois",
|
||||
"ip", ip,
|
||||
"whois", info,
|
||||
"elapsed", time.Since(start),
|
||||
)
|
||||
}()
|
||||
|
||||
// TODO(s.chzhen): Move the timeout logic from WHOIS configuration to the
|
||||
|
||||
@@ -26,7 +26,8 @@ func TestEmptyAddrProc(t *testing.T) {
|
||||
p := client.EmptyAddrProc{}
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
p.Process(testIP)
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
p.Process(ctx, testIP)
|
||||
})
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
@@ -120,7 +121,8 @@ func TestDefaultAddrProc_Process_rDNS(t *testing.T) {
|
||||
})
|
||||
testutil.CleanupAndRequireSuccess(t, p.Close)
|
||||
|
||||
p.Process(tc.ip)
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
p.Process(ctx, tc.ip)
|
||||
|
||||
if !tc.wantUpd {
|
||||
return
|
||||
@@ -146,8 +148,8 @@ func newOnUpdateAddress(
|
||||
ips chan<- netip.Addr,
|
||||
hosts chan<- string,
|
||||
infos chan<- *whois.Info,
|
||||
) (f func(ip netip.Addr, host string, info *whois.Info)) {
|
||||
return func(ip netip.Addr, host string, info *whois.Info) {
|
||||
) (f func(ctx context.Context, ip netip.Addr, host string, info *whois.Info)) {
|
||||
return func(ctx context.Context, ip netip.Addr, host string, info *whois.Info) {
|
||||
if !want && (host != "" || info != nil) {
|
||||
panic(fmt.Errorf("got unexpected update for %v with %q and %v", ip, host, info))
|
||||
}
|
||||
@@ -230,7 +232,8 @@ func TestDefaultAddrProc_Process_WHOIS(t *testing.T) {
|
||||
})
|
||||
testutil.CleanupAndRequireSuccess(t, p.Close)
|
||||
|
||||
p.Process(testIP)
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
p.Process(ctx, testIP)
|
||||
|
||||
if !tc.wantUpd {
|
||||
return
|
||||
@@ -251,7 +254,9 @@ func TestDefaultAddrProc_Process_WHOIS(t *testing.T) {
|
||||
func TestDefaultAddrProc_Close(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
p := client.NewDefaultAddrProc(&client.DefaultAddrProcConfig{})
|
||||
p := client.NewDefaultAddrProc(&client.DefaultAddrProcConfig{
|
||||
BaseLogger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
|
||||
err := p.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -119,8 +119,8 @@ func (r *Runtime) Info() (cs Source, host string) {
|
||||
return cs, info[0]
|
||||
}
|
||||
|
||||
// SetInfo sets a host as a client information from the cs.
|
||||
func (r *Runtime) SetInfo(cs Source, hosts []string) {
|
||||
// setInfo sets a host as a client information from the cs.
|
||||
func (r *Runtime) setInfo(cs Source, hosts []string) {
|
||||
// TODO(s.chzhen): Use contract where hosts must contain non-empty host.
|
||||
if len(hosts) == 1 && hosts[0] == "" {
|
||||
hosts = []string{}
|
||||
@@ -138,13 +138,13 @@ func (r *Runtime) SetInfo(cs Source, hosts []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// WHOIS returns a WHOIS client information.
|
||||
// WHOIS returns a copy of WHOIS client information.
|
||||
func (r *Runtime) WHOIS() (info *whois.Info) {
|
||||
return r.whois
|
||||
return r.whois.Clone()
|
||||
}
|
||||
|
||||
// SetWHOIS sets a WHOIS client information. info must be non-nil.
|
||||
func (r *Runtime) SetWHOIS(info *whois.Info) {
|
||||
// setWHOIS sets a WHOIS client information. info must be non-nil.
|
||||
func (r *Runtime) setWHOIS(info *whois.Info) {
|
||||
r.whois = info
|
||||
}
|
||||
|
||||
@@ -178,8 +178,12 @@ func (r *Runtime) Addr() (ip netip.Addr) {
|
||||
return r.ip
|
||||
}
|
||||
|
||||
// Clone returns a deep copy of the runtime client.
|
||||
func (r *Runtime) Clone() (c *Runtime) {
|
||||
// clone returns a deep copy of the runtime client. If r is nil, c is nil.
|
||||
func (r *Runtime) clone() (c *Runtime) {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Runtime{
|
||||
ip: r.ip,
|
||||
whois: r.whois.Clone(),
|
||||
|
||||
@@ -2,6 +2,7 @@ package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
@@ -9,7 +10,6 @@ import (
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
// macKey contains MAC as byte array of 6, 8, or 20 bytes.
|
||||
@@ -330,12 +330,14 @@ func (ci *index) size() (n int) {
|
||||
// rangeByName is like [Index.Range] but sorts the persistent clients by name
|
||||
// before iterating ensuring a predictable order.
|
||||
func (ci *index) rangeByName(f func(c *Persistent) (cont bool)) {
|
||||
cs := maps.Values(ci.uidToClient)
|
||||
slices.SortFunc(cs, func(a, b *Persistent) (n int) {
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
})
|
||||
clients := slices.SortedStableFunc(
|
||||
maps.Values(ci.uidToClient),
|
||||
func(a, b *Persistent) (res int) {
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
},
|
||||
)
|
||||
|
||||
for _, c := range cs {
|
||||
for _, c := range clients {
|
||||
if !f(c) {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering/safesearch"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
@@ -136,7 +135,8 @@ type Persistent struct {
|
||||
}
|
||||
|
||||
// validate returns an error if persistent client information contains errors.
|
||||
func (c *Persistent) validate(allTags *container.MapSet[string]) (err error) {
|
||||
// allTags must be sorted.
|
||||
func (c *Persistent) validate(ctx context.Context, l *slog.Logger, allTags []string) (err error) {
|
||||
switch {
|
||||
case c.Name == "":
|
||||
return errors.Error("empty name")
|
||||
@@ -153,11 +153,12 @@ func (c *Persistent) validate(allTags *container.MapSet[string]) (err error) {
|
||||
|
||||
err = conf.Close()
|
||||
if err != nil {
|
||||
log.Error("client: closing upstream config: %s", err)
|
||||
l.ErrorContext(ctx, "client: closing upstream config", slogutil.KeyError, err)
|
||||
}
|
||||
|
||||
for _, t := range c.Tags {
|
||||
if !allTags.Has(t) {
|
||||
_, ok := slices.BinarySearch(allTags, t)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid tag: %q", t)
|
||||
}
|
||||
}
|
||||
@@ -322,20 +323,3 @@ func (c *Persistent) CloseUpstreams() (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetSafeSearch initializes and sets the safe search filter for this client.
|
||||
func (c *Persistent) SetSafeSearch(
|
||||
conf filtering.SafeSearchConfig,
|
||||
cacheSize uint,
|
||||
cacheTTL time.Duration,
|
||||
) (err error) {
|
||||
ss, err := safesearch.NewDefault(conf, fmt.Sprintf("client %q", c.Name), cacheSize, cacheTTL)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
c.SafeSearch = ss
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -125,69 +122,3 @@ func TestPersistent_EqualIDs(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPersistent_Validate(t *testing.T) {
|
||||
const (
|
||||
allowedTag = "allowed_tag"
|
||||
notAllowedTag = "not_allowed_tag"
|
||||
)
|
||||
|
||||
allowedTags := container.NewMapSet(allowedTag)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
cli *Persistent
|
||||
wantErrMsg string
|
||||
}{{
|
||||
name: "success",
|
||||
cli: &Persistent{
|
||||
Name: "basic",
|
||||
IPs: []netip.Addr{
|
||||
netip.MustParseAddr("1.2.3.4"),
|
||||
},
|
||||
UID: MustNewUID(),
|
||||
},
|
||||
wantErrMsg: "",
|
||||
}, {
|
||||
name: "empty_name",
|
||||
cli: &Persistent{
|
||||
Name: "",
|
||||
},
|
||||
wantErrMsg: "empty name",
|
||||
}, {
|
||||
name: "no_id",
|
||||
cli: &Persistent{
|
||||
Name: "no_id",
|
||||
},
|
||||
wantErrMsg: "id required",
|
||||
}, {
|
||||
name: "no_uid",
|
||||
cli: &Persistent{
|
||||
Name: "no_uid",
|
||||
IPs: []netip.Addr{
|
||||
netip.MustParseAddr("1.2.3.4"),
|
||||
},
|
||||
},
|
||||
wantErrMsg: "uid required",
|
||||
}, {
|
||||
name: "not_allowed_tag",
|
||||
cli: &Persistent{
|
||||
Name: "basic",
|
||||
IPs: []netip.Addr{
|
||||
netip.MustParseAddr("1.2.3.4"),
|
||||
},
|
||||
UID: MustNewUID(),
|
||||
Tags: []string{
|
||||
notAllowedTag,
|
||||
},
|
||||
},
|
||||
wantErrMsg: `invalid tag: "` + notAllowedTag + `"`,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := tc.cli.validate(allowedTags)
|
||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,39 +2,34 @@ package client
|
||||
|
||||
import "net/netip"
|
||||
|
||||
// RuntimeIndex stores information about runtime clients.
|
||||
type RuntimeIndex struct {
|
||||
// runtimeIndex stores information about runtime clients.
|
||||
type runtimeIndex struct {
|
||||
// index maps IP address to runtime client.
|
||||
index map[netip.Addr]*Runtime
|
||||
}
|
||||
|
||||
// NewRuntimeIndex returns initialized runtime index.
|
||||
func NewRuntimeIndex() (ri *RuntimeIndex) {
|
||||
return &RuntimeIndex{
|
||||
// newRuntimeIndex returns initialized runtime index.
|
||||
func newRuntimeIndex() (ri *runtimeIndex) {
|
||||
return &runtimeIndex{
|
||||
index: map[netip.Addr]*Runtime{},
|
||||
}
|
||||
}
|
||||
|
||||
// Client returns the saved runtime client by ip. If no such client exists,
|
||||
// client returns the saved runtime client by ip. If no such client exists,
|
||||
// returns nil.
|
||||
func (ri *RuntimeIndex) Client(ip netip.Addr) (rc *Runtime) {
|
||||
func (ri *runtimeIndex) client(ip netip.Addr) (rc *Runtime) {
|
||||
return ri.index[ip]
|
||||
}
|
||||
|
||||
// Add saves the runtime client in the index. IP address of a client must be
|
||||
// add saves the runtime client in the index. IP address of a client must be
|
||||
// unique. See [Runtime.Client]. rc must not be nil.
|
||||
func (ri *RuntimeIndex) Add(rc *Runtime) {
|
||||
func (ri *runtimeIndex) add(rc *Runtime) {
|
||||
ip := rc.Addr()
|
||||
ri.index[ip] = rc
|
||||
}
|
||||
|
||||
// Size returns the number of the runtime clients.
|
||||
func (ri *RuntimeIndex) Size() (n int) {
|
||||
return len(ri.index)
|
||||
}
|
||||
|
||||
// Range calls f for each runtime client in an undefined order.
|
||||
func (ri *RuntimeIndex) Range(f func(rc *Runtime) (cont bool)) {
|
||||
// rangeClients calls f for each runtime client in an undefined order.
|
||||
func (ri *runtimeIndex) rangeClients(f func(rc *Runtime) (cont bool)) {
|
||||
for _, rc := range ri.index {
|
||||
if !f(rc) {
|
||||
return
|
||||
@@ -42,17 +37,31 @@ func (ri *RuntimeIndex) Range(f func(rc *Runtime) (cont bool)) {
|
||||
}
|
||||
}
|
||||
|
||||
// Delete removes the runtime client by ip.
|
||||
func (ri *RuntimeIndex) Delete(ip netip.Addr) {
|
||||
delete(ri.index, ip)
|
||||
// setInfo sets the client information from cs for runtime client stored by ip.
|
||||
// If no such client exists, it creates one.
|
||||
func (ri *runtimeIndex) setInfo(ip netip.Addr, cs Source, hosts []string) (rc *Runtime) {
|
||||
rc = ri.index[ip]
|
||||
if rc == nil {
|
||||
rc = NewRuntime(ip)
|
||||
ri.add(rc)
|
||||
}
|
||||
|
||||
rc.setInfo(cs, hosts)
|
||||
|
||||
return rc
|
||||
}
|
||||
|
||||
// DeleteBySource removes all runtime clients that have information only from
|
||||
// the specified source and returns the number of removed clients.
|
||||
func (ri *RuntimeIndex) DeleteBySource(src Source) (n int) {
|
||||
for ip, rc := range ri.index {
|
||||
// clearSource removes information from the specified source from all clients.
|
||||
func (ri *runtimeIndex) clearSource(src Source) {
|
||||
for _, rc := range ri.index {
|
||||
rc.unset(src)
|
||||
}
|
||||
}
|
||||
|
||||
// removeEmpty removes empty runtime clients and returns the number of removed
|
||||
// clients.
|
||||
func (ri *runtimeIndex) removeEmpty() (n int) {
|
||||
for ip, rc := range ri.index {
|
||||
if rc.isEmpty() {
|
||||
delete(ri.index, ip)
|
||||
n++
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
package client_test
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/client"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRuntimeIndex(t *testing.T) {
|
||||
const cliSrc = client.SourceARP
|
||||
|
||||
var (
|
||||
ip1 = netip.MustParseAddr("1.1.1.1")
|
||||
ip2 = netip.MustParseAddr("2.2.2.2")
|
||||
ip3 = netip.MustParseAddr("3.3.3.3")
|
||||
)
|
||||
|
||||
ri := client.NewRuntimeIndex()
|
||||
currentSize := 0
|
||||
|
||||
testCases := []struct {
|
||||
ip netip.Addr
|
||||
name string
|
||||
hosts []string
|
||||
src client.Source
|
||||
}{{
|
||||
src: cliSrc,
|
||||
ip: ip1,
|
||||
name: "1",
|
||||
hosts: []string{"host1"},
|
||||
}, {
|
||||
src: cliSrc,
|
||||
ip: ip2,
|
||||
name: "2",
|
||||
hosts: []string{"host2"},
|
||||
}, {
|
||||
src: cliSrc,
|
||||
ip: ip3,
|
||||
name: "3",
|
||||
hosts: []string{"host3"},
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
rc := client.NewRuntime(tc.ip)
|
||||
rc.SetInfo(tc.src, tc.hosts)
|
||||
|
||||
ri.Add(rc)
|
||||
currentSize++
|
||||
|
||||
got := ri.Client(tc.ip)
|
||||
assert.Equal(t, rc, got)
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("size", func(t *testing.T) {
|
||||
assert.Equal(t, currentSize, ri.Size())
|
||||
})
|
||||
|
||||
t.Run("range", func(t *testing.T) {
|
||||
s := 0
|
||||
|
||||
ri.Range(func(rc *client.Runtime) (cont bool) {
|
||||
s++
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
assert.Equal(t, currentSize, s)
|
||||
})
|
||||
|
||||
t.Run("delete", func(t *testing.T) {
|
||||
ri.Delete(ip1)
|
||||
currentSize--
|
||||
|
||||
assert.Equal(t, currentSize, ri.Size())
|
||||
})
|
||||
|
||||
t.Run("delete_by_src", func(t *testing.T) {
|
||||
assert.Equal(t, currentSize, ri.DeleteBySource(cliSrc))
|
||||
assert.Equal(t, 0, ri.Size())
|
||||
})
|
||||
}
|
||||
@@ -1,29 +1,121 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/arpdb"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/whois"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/hostsfile"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
)
|
||||
|
||||
// Config is the client storage configuration structure.
|
||||
//
|
||||
// TODO(s.chzhen): Expand.
|
||||
type Config struct {
|
||||
// AllowedTags is a list of all allowed client tags.
|
||||
AllowedTags []string
|
||||
// allowedTags is the list of available client tags.
|
||||
var allowedTags = []string{
|
||||
"device_audio",
|
||||
"device_camera",
|
||||
"device_gameconsole",
|
||||
"device_laptop",
|
||||
"device_nas", // Network-attached Storage
|
||||
"device_other",
|
||||
"device_pc",
|
||||
"device_phone",
|
||||
"device_printer",
|
||||
"device_securityalarm",
|
||||
"device_tablet",
|
||||
"device_tv",
|
||||
|
||||
"os_android",
|
||||
"os_ios",
|
||||
"os_linux",
|
||||
"os_macos",
|
||||
"os_other",
|
||||
"os_windows",
|
||||
|
||||
"user_admin",
|
||||
"user_child",
|
||||
"user_regular",
|
||||
}
|
||||
|
||||
// DHCP is an interface for accessing DHCP lease data the [Storage] needs.
|
||||
type DHCP interface {
|
||||
// Leases returns all the DHCP leases.
|
||||
Leases() (leases []*dhcpsvc.Lease)
|
||||
|
||||
// HostByIP returns the hostname of the DHCP client with the given IP
|
||||
// address. host will be empty if there is no such client, due to an
|
||||
// assumption that a DHCP client must always have a hostname.
|
||||
HostByIP(ip netip.Addr) (host string)
|
||||
|
||||
// MACByIP returns the MAC address for the given IP address leased. It
|
||||
// returns nil if there is no such client, due to an assumption that a DHCP
|
||||
// client must always have a MAC address.
|
||||
MACByIP(ip netip.Addr) (mac net.HardwareAddr)
|
||||
}
|
||||
|
||||
// EmptyDHCP is the empty [DHCP] implementation that does nothing.
|
||||
type EmptyDHCP struct{}
|
||||
|
||||
// type check
|
||||
var _ DHCP = EmptyDHCP{}
|
||||
|
||||
// Leases implements the [DHCP] interface for emptyDHCP.
|
||||
func (EmptyDHCP) Leases() (leases []*dhcpsvc.Lease) { return nil }
|
||||
|
||||
// HostByIP implements the [DHCP] interface for emptyDHCP.
|
||||
func (EmptyDHCP) HostByIP(_ netip.Addr) (host string) { return "" }
|
||||
|
||||
// MACByIP implements the [DHCP] interface for emptyDHCP.
|
||||
func (EmptyDHCP) MACByIP(_ netip.Addr) (mac net.HardwareAddr) { return nil }
|
||||
|
||||
// HostsContainer is an interface for receiving updates to the system hosts
|
||||
// file.
|
||||
type HostsContainer interface {
|
||||
Upd() (updates <-chan *hostsfile.DefaultStorage)
|
||||
}
|
||||
|
||||
// StorageConfig is the client storage configuration structure.
|
||||
type StorageConfig struct {
|
||||
// Logger is used for logging the operation of the client storage. It must
|
||||
// not be nil.
|
||||
Logger *slog.Logger
|
||||
|
||||
// DHCP is used to match IPs against MACs of persistent clients and update
|
||||
// [SourceDHCP] runtime client information. It must not be nil.
|
||||
DHCP DHCP
|
||||
|
||||
// EtcHosts is used to update [SourceHostsFile] runtime client information.
|
||||
EtcHosts HostsContainer
|
||||
|
||||
// ARPDB is used to update [SourceARP] runtime client information.
|
||||
ARPDB arpdb.Interface
|
||||
|
||||
// InitialClients is a list of persistent clients parsed from the
|
||||
// configuration file. Each client must not be nil.
|
||||
InitialClients []*Persistent
|
||||
|
||||
// ARPClientsUpdatePeriod defines how often [SourceARP] runtime client
|
||||
// information is updated.
|
||||
ARPClientsUpdatePeriod time.Duration
|
||||
|
||||
// RuntimeSourceDHCP specifies whether to update [SourceDHCP] information
|
||||
// of runtime clients.
|
||||
RuntimeSourceDHCP bool
|
||||
}
|
||||
|
||||
// Storage contains information about persistent and runtime clients.
|
||||
type Storage struct {
|
||||
// allowedTags is a set of all allowed tags.
|
||||
allowedTags *container.MapSet[string]
|
||||
// logger is used for logging the operation of the client storage. It must
|
||||
// not be nil.
|
||||
logger *slog.Logger
|
||||
|
||||
// mu protects indexes of persistent and runtime clients.
|
||||
mu *sync.Mutex
|
||||
@@ -32,26 +124,277 @@ type Storage struct {
|
||||
index *index
|
||||
|
||||
// runtimeIndex contains information about runtime clients.
|
||||
runtimeIndex *RuntimeIndex
|
||||
runtimeIndex *runtimeIndex
|
||||
|
||||
// dhcp is used to update [SourceDHCP] runtime client information.
|
||||
dhcp DHCP
|
||||
|
||||
// etcHosts is used to update [SourceHostsFile] runtime client information.
|
||||
etcHosts HostsContainer
|
||||
|
||||
// arpDB is used to update [SourceARP] runtime client information.
|
||||
arpDB arpdb.Interface
|
||||
|
||||
// done is the shutdown signaling channel.
|
||||
done chan struct{}
|
||||
|
||||
// allowedTags is a sorted list of all allowed tags. It must not be
|
||||
// modified after initialization.
|
||||
//
|
||||
// TODO(s.chzhen): Use custom type.
|
||||
allowedTags []string
|
||||
|
||||
// arpClientsUpdatePeriod defines how often [SourceARP] runtime client
|
||||
// information is updated. It must be greater than zero.
|
||||
arpClientsUpdatePeriod time.Duration
|
||||
|
||||
// runtimeSourceDHCP specifies whether to update [SourceDHCP] information
|
||||
// of runtime clients.
|
||||
runtimeSourceDHCP bool
|
||||
}
|
||||
|
||||
// NewStorage returns initialized client storage. conf must not be nil.
|
||||
func NewStorage(conf *Config) (s *Storage) {
|
||||
allowedTags := container.NewMapSet(conf.AllowedTags...)
|
||||
func NewStorage(ctx context.Context, conf *StorageConfig) (s *Storage, err error) {
|
||||
tags := slices.Clone(allowedTags)
|
||||
slices.Sort(tags)
|
||||
|
||||
return &Storage{
|
||||
allowedTags: allowedTags,
|
||||
mu: &sync.Mutex{},
|
||||
index: newIndex(),
|
||||
runtimeIndex: NewRuntimeIndex(),
|
||||
s = &Storage{
|
||||
logger: conf.Logger,
|
||||
mu: &sync.Mutex{},
|
||||
index: newIndex(),
|
||||
runtimeIndex: newRuntimeIndex(),
|
||||
dhcp: conf.DHCP,
|
||||
etcHosts: conf.EtcHosts,
|
||||
arpDB: conf.ARPDB,
|
||||
done: make(chan struct{}),
|
||||
allowedTags: tags,
|
||||
arpClientsUpdatePeriod: conf.ARPClientsUpdatePeriod,
|
||||
runtimeSourceDHCP: conf.RuntimeSourceDHCP,
|
||||
}
|
||||
|
||||
for i, p := range conf.InitialClients {
|
||||
err = s.Add(ctx, p)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("adding client %q at index %d: %w", p.Name, i, err)
|
||||
}
|
||||
}
|
||||
|
||||
s.ReloadARP(ctx)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Start starts the goroutines for updating the runtime client information.
|
||||
//
|
||||
// TODO(s.chzhen): Pass context.
|
||||
func (s *Storage) Start(ctx context.Context) (err error) {
|
||||
go s.periodicARPUpdate(ctx)
|
||||
go s.handleHostsUpdates(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shutdown gracefully stops the client storage.
|
||||
//
|
||||
// TODO(s.chzhen): Pass context.
|
||||
func (s *Storage) Shutdown(_ context.Context) (err error) {
|
||||
close(s.done)
|
||||
|
||||
return s.closeUpstreams()
|
||||
}
|
||||
|
||||
// periodicARPUpdate periodically reloads runtime clients from ARP. It is
|
||||
// intended to be used as a goroutine.
|
||||
func (s *Storage) periodicARPUpdate(ctx context.Context) {
|
||||
defer slogutil.RecoverAndLog(ctx, s.logger)
|
||||
|
||||
t := time.NewTicker(s.arpClientsUpdatePeriod)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
s.ReloadARP(ctx)
|
||||
case <-s.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReloadARP reloads runtime clients from ARP, if configured.
|
||||
func (s *Storage) ReloadARP(ctx context.Context) {
|
||||
if s.arpDB != nil {
|
||||
s.addFromSystemARP(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// addFromSystemARP adds the IP-hostname pairings from the output of the arp -a
|
||||
// command.
|
||||
func (s *Storage) addFromSystemARP(ctx context.Context) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if err := s.arpDB.Refresh(); err != nil {
|
||||
s.arpDB = arpdb.Empty{}
|
||||
s.logger.ErrorContext(ctx, "refreshing arp container", slogutil.KeyError, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
ns := s.arpDB.Neighbors()
|
||||
if len(ns) == 0 {
|
||||
s.logger.DebugContext(ctx, "refreshing arp container: the update is empty")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
src := SourceARP
|
||||
s.runtimeIndex.clearSource(src)
|
||||
|
||||
for _, n := range ns {
|
||||
s.runtimeIndex.setInfo(n.IP, src, []string{n.Name})
|
||||
}
|
||||
|
||||
removed := s.runtimeIndex.removeEmpty()
|
||||
|
||||
s.logger.DebugContext(
|
||||
ctx,
|
||||
"updating client aliases from arp neighborhood",
|
||||
"added", len(ns),
|
||||
"removed", removed,
|
||||
)
|
||||
}
|
||||
|
||||
// handleHostsUpdates receives the updates from the hosts container and adds
|
||||
// them to the clients storage. It is intended to be used as a goroutine.
|
||||
func (s *Storage) handleHostsUpdates(ctx context.Context) {
|
||||
if s.etcHosts == nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer slogutil.RecoverAndLog(ctx, s.logger)
|
||||
|
||||
for {
|
||||
select {
|
||||
case upd, ok := <-s.etcHosts.Upd():
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
s.addFromHostsFile(ctx, upd)
|
||||
case <-s.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// addFromHostsFile fills the client-hostname pairing index from the system's
|
||||
// hosts files.
|
||||
func (s *Storage) addFromHostsFile(ctx context.Context, hosts *hostsfile.DefaultStorage) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
src := SourceHostsFile
|
||||
s.runtimeIndex.clearSource(src)
|
||||
|
||||
added := 0
|
||||
hosts.RangeNames(func(addr netip.Addr, names []string) (cont bool) {
|
||||
// Only the first name of the first record is considered a canonical
|
||||
// hostname for the IP address.
|
||||
//
|
||||
// TODO(e.burkov): Consider using all the names from all the records.
|
||||
s.runtimeIndex.setInfo(addr, src, []string{names[0]})
|
||||
added++
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
removed := s.runtimeIndex.removeEmpty()
|
||||
s.logger.DebugContext(
|
||||
ctx,
|
||||
"updating client aliases from system hosts file",
|
||||
"added", added,
|
||||
"removed", removed,
|
||||
)
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ AddressUpdater = (*Storage)(nil)
|
||||
|
||||
// UpdateAddress implements the [AddressUpdater] interface for *Storage
|
||||
func (s *Storage) UpdateAddress(ctx context.Context, ip netip.Addr, host string, info *whois.Info) {
|
||||
// Common fast path optimization.
|
||||
if host == "" && info == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if host != "" {
|
||||
s.runtimeIndex.setInfo(ip, SourceRDNS, []string{host})
|
||||
}
|
||||
|
||||
if info != nil {
|
||||
s.setWHOISInfo(ctx, ip, info)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateDHCP updates [SourceDHCP] runtime client information.
|
||||
func (s *Storage) UpdateDHCP(ctx context.Context) {
|
||||
if s.dhcp == nil || !s.runtimeSourceDHCP {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
src := SourceDHCP
|
||||
s.runtimeIndex.clearSource(src)
|
||||
|
||||
added := 0
|
||||
for _, l := range s.dhcp.Leases() {
|
||||
s.runtimeIndex.setInfo(l.IP, src, []string{l.Hostname})
|
||||
added++
|
||||
}
|
||||
|
||||
removed := s.runtimeIndex.removeEmpty()
|
||||
s.logger.DebugContext(
|
||||
ctx,
|
||||
"updating client aliases from dhcp",
|
||||
"added", added,
|
||||
"removed", removed,
|
||||
)
|
||||
}
|
||||
|
||||
// setWHOISInfo sets the WHOIS information for a runtime client.
|
||||
func (s *Storage) setWHOISInfo(ctx context.Context, ip netip.Addr, wi *whois.Info) {
|
||||
_, ok := s.index.findByIP(ip)
|
||||
if ok {
|
||||
s.logger.DebugContext(
|
||||
ctx,
|
||||
"persistent client is already created, ignore whois info",
|
||||
"ip", ip,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
rc := s.runtimeIndex.client(ip)
|
||||
if rc == nil {
|
||||
rc = NewRuntime(ip)
|
||||
s.runtimeIndex.add(rc)
|
||||
}
|
||||
|
||||
rc.setWHOIS(wi)
|
||||
|
||||
s.logger.DebugContext(ctx, "set whois info for runtime client", "ip", ip, "whois", wi)
|
||||
}
|
||||
|
||||
// Add stores persistent client information or returns an error.
|
||||
func (s *Storage) Add(p *Persistent) (err error) {
|
||||
func (s *Storage) Add(ctx context.Context, p *Persistent) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "adding client: %w") }()
|
||||
|
||||
err = p.validate(s.allowedTags)
|
||||
err = p.validate(ctx, s.logger, s.allowedTags)
|
||||
if err != nil {
|
||||
// Don't wrap the error since there is already an annotation deferred.
|
||||
return err
|
||||
@@ -74,7 +417,13 @@ func (s *Storage) Add(p *Persistent) (err error) {
|
||||
|
||||
s.index.add(p)
|
||||
|
||||
log.Debug("client storage: added %q: IDs: %q [%d]", p.Name, p.IDs(), s.index.size())
|
||||
s.logger.DebugContext(
|
||||
ctx,
|
||||
"client added",
|
||||
"name", p.Name,
|
||||
"ids", p.IDs(),
|
||||
"clients_count", s.index.size(),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -94,6 +443,9 @@ func (s *Storage) FindByName(name string) (p *Persistent, ok bool) {
|
||||
|
||||
// Find finds persistent client by string representation of the client ID, IP
|
||||
// address, or MAC. And returns its shallow copy.
|
||||
//
|
||||
// TODO(s.chzhen): Accept ClientIDData structure instead, which will contain
|
||||
// the parsed IP address, if any.
|
||||
func (s *Storage) Find(id string) (p *Persistent, ok bool) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
@@ -103,6 +455,16 @@ func (s *Storage) Find(id string) (p *Persistent, ok bool) {
|
||||
return p.ShallowClone(), ok
|
||||
}
|
||||
|
||||
ip, err := netip.ParseAddr(id)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
foundMAC := s.dhcp.MACByIP(ip)
|
||||
if foundMAC != nil {
|
||||
return s.FindByMAC(foundMAC)
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -130,11 +492,9 @@ func (s *Storage) FindLoose(ip netip.Addr, id string) (p *Persistent, ok bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// FindByMAC finds persistent client by MAC and returns its shallow copy.
|
||||
// FindByMAC finds persistent client by MAC and returns its shallow copy. s.mu
|
||||
// is expected to be locked.
|
||||
func (s *Storage) FindByMAC(mac net.HardwareAddr) (p *Persistent, ok bool) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
p, ok = s.index.findByMAC(mac)
|
||||
if ok {
|
||||
return p.ShallowClone(), ok
|
||||
@@ -145,7 +505,7 @@ func (s *Storage) FindByMAC(mac net.HardwareAddr) (p *Persistent, ok bool) {
|
||||
|
||||
// RemoveByName removes persistent client information. ok is false if no such
|
||||
// client exists by that name.
|
||||
func (s *Storage) RemoveByName(name string) (ok bool) {
|
||||
func (s *Storage) RemoveByName(ctx context.Context, name string) (ok bool) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
@@ -155,7 +515,7 @@ func (s *Storage) RemoveByName(name string) (ok bool) {
|
||||
}
|
||||
|
||||
if err := p.CloseUpstreams(); err != nil {
|
||||
log.Error("client storage: removing client %q: %s", p.Name, err)
|
||||
s.logger.ErrorContext(ctx, "removing client", "name", p.Name, slogutil.KeyError, err)
|
||||
}
|
||||
|
||||
s.index.remove(p)
|
||||
@@ -165,10 +525,10 @@ func (s *Storage) RemoveByName(name string) (ok bool) {
|
||||
|
||||
// Update finds the stored persistent client by its name and updates its
|
||||
// information from p.
|
||||
func (s *Storage) Update(name string, p *Persistent) (err error) {
|
||||
func (s *Storage) Update(ctx context.Context, name string, p *Persistent) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "updating client: %w") }()
|
||||
|
||||
err = p.validate(s.allowedTags)
|
||||
err = p.validate(ctx, s.logger, s.allowedTags)
|
||||
if err != nil {
|
||||
// Don't wrap the error since there is already an annotation deferred.
|
||||
return err
|
||||
@@ -216,8 +576,8 @@ func (s *Storage) Size() (n int) {
|
||||
return s.index.size()
|
||||
}
|
||||
|
||||
// CloseUpstreams closes upstream configurations of persistent clients.
|
||||
func (s *Storage) CloseUpstreams() (err error) {
|
||||
// closeUpstreams closes upstream configurations of persistent clients.
|
||||
func (s *Storage) closeUpstreams() (err error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
@@ -226,89 +586,31 @@ func (s *Storage) CloseUpstreams() (err error) {
|
||||
|
||||
// ClientRuntime returns a copy of the saved runtime client by ip. If no such
|
||||
// client exists, returns nil.
|
||||
//
|
||||
// TODO(s.chzhen): Use it.
|
||||
func (s *Storage) ClientRuntime(ip netip.Addr) (rc *Runtime) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return s.runtimeIndex.Client(ip)
|
||||
}
|
||||
|
||||
// UpdateRuntime updates the stored runtime client with information from rc. If
|
||||
// no such client exists, saves the copy of rc in storage. rc must not be nil.
|
||||
func (s *Storage) UpdateRuntime(rc *Runtime) (added bool) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return s.updateRuntimeLocked(rc)
|
||||
}
|
||||
|
||||
// updateRuntimeLocked updates the stored runtime client with information from
|
||||
// rc. rc must not be nil. Storage.mu is expected to be locked.
|
||||
func (s *Storage) updateRuntimeLocked(rc *Runtime) (added bool) {
|
||||
stored := s.runtimeIndex.Client(rc.ip)
|
||||
if stored == nil {
|
||||
s.runtimeIndex.Add(rc.Clone())
|
||||
|
||||
return true
|
||||
rc = s.runtimeIndex.client(ip)
|
||||
if !s.runtimeSourceDHCP {
|
||||
return rc.clone()
|
||||
}
|
||||
|
||||
if rc.whois != nil {
|
||||
stored.whois = rc.whois.Clone()
|
||||
// SourceHostsFile > SourceDHCP, so return immediately if the client is from
|
||||
// the hosts file.
|
||||
if rc != nil && rc.hostsFile != nil {
|
||||
return rc.clone()
|
||||
}
|
||||
|
||||
if rc.arp != nil {
|
||||
stored.arp = slices.Clone(rc.arp)
|
||||
// Otherwise, check the DHCP server and add the client information if there
|
||||
// is any.
|
||||
host := s.dhcp.HostByIP(ip)
|
||||
if host == "" {
|
||||
return rc.clone()
|
||||
}
|
||||
|
||||
if rc.rdns != nil {
|
||||
stored.rdns = slices.Clone(rc.rdns)
|
||||
}
|
||||
rc = s.runtimeIndex.setInfo(ip, SourceDHCP, []string{host})
|
||||
|
||||
if rc.dhcp != nil {
|
||||
stored.dhcp = slices.Clone(rc.dhcp)
|
||||
}
|
||||
|
||||
if rc.hostsFile != nil {
|
||||
stored.hostsFile = slices.Clone(rc.hostsFile)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// BatchUpdateBySource updates the stored runtime clients information from the
|
||||
// specified source and returns the number of added and removed clients.
|
||||
func (s *Storage) BatchUpdateBySource(src Source, rcs []*Runtime) (added, removed int) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
for _, rc := range s.runtimeIndex.index {
|
||||
rc.unset(src)
|
||||
}
|
||||
|
||||
for _, rc := range rcs {
|
||||
if s.updateRuntimeLocked(rc) {
|
||||
added++
|
||||
}
|
||||
}
|
||||
|
||||
for ip, rc := range s.runtimeIndex.index {
|
||||
if rc.isEmpty() {
|
||||
delete(s.runtimeIndex.index, ip)
|
||||
removed++
|
||||
}
|
||||
}
|
||||
|
||||
return added, removed
|
||||
}
|
||||
|
||||
// SizeRuntime returns the number of the runtime clients.
|
||||
func (s *Storage) SizeRuntime() (n int) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return s.runtimeIndex.Size()
|
||||
return rc.clone()
|
||||
}
|
||||
|
||||
// RangeRuntime calls f for each runtime client in an undefined order.
|
||||
@@ -316,16 +618,11 @@ func (s *Storage) RangeRuntime(f func(rc *Runtime) (cont bool)) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.runtimeIndex.Range(f)
|
||||
s.runtimeIndex.rangeClients(f)
|
||||
}
|
||||
|
||||
// DeleteBySource removes all runtime clients that have information only from
|
||||
// the specified source and returns the number of removed clients.
|
||||
//
|
||||
// TODO(s.chzhen): Use it.
|
||||
func (s *Storage) DeleteBySource(src Source) (n int) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return s.runtimeIndex.DeleteBySource(src)
|
||||
// AllowedTags returns the list of available client tags. tags must not be
|
||||
// modified.
|
||||
func (s *Storage) AllowedTags() (tags []string) {
|
||||
return s.allowedTags
|
||||
}
|
||||
|
||||
@@ -3,27 +3,652 @@ package client_test
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
"slices"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/arpdb"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/client"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/whois"
|
||||
"github.com/AdguardTeam/golibs/hostsfile"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// newTestStorage is a helper function that returns initialized storage.
|
||||
func newTestStorage(tb testing.TB) (s *client.Storage) {
|
||||
tb.Helper()
|
||||
|
||||
ctx := testutil.ContextWithTimeout(tb, testTimeout)
|
||||
s, err := client.NewStorage(ctx, &client.StorageConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
require.NoError(tb, err)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// testHostsContainer is a mock implementation of the [client.HostsContainer]
|
||||
// interface.
|
||||
type testHostsContainer struct {
|
||||
onUpd func() (updates <-chan *hostsfile.DefaultStorage)
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ client.HostsContainer = (*testHostsContainer)(nil)
|
||||
|
||||
// Upd implements the [client.HostsContainer] interface for *testHostsContainer.
|
||||
func (c *testHostsContainer) Upd() (updates <-chan *hostsfile.DefaultStorage) {
|
||||
return c.onUpd()
|
||||
}
|
||||
|
||||
// Interface stores and refreshes the network neighborhood reported by ARP
|
||||
// (Address Resolution Protocol).
|
||||
type Interface interface {
|
||||
// Refresh updates the stored data. It must be safe for concurrent use.
|
||||
Refresh() (err error)
|
||||
|
||||
// Neighbors returnes the last set of data reported by ARP. Both the method
|
||||
// and it's result must be safe for concurrent use.
|
||||
Neighbors() (ns []arpdb.Neighbor)
|
||||
}
|
||||
|
||||
// testARPDB is a mock implementation of the [arpdb.Interface].
|
||||
type testARPDB struct {
|
||||
onRefresh func() (err error)
|
||||
onNeighbors func() (ns []arpdb.Neighbor)
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ arpdb.Interface = (*testARPDB)(nil)
|
||||
|
||||
// Refresh implements the [arpdb.Interface] interface for *testARP.
|
||||
func (c *testARPDB) Refresh() (err error) {
|
||||
return c.onRefresh()
|
||||
}
|
||||
|
||||
// Neighbors implements the [arpdb.Interface] interface for *testARP.
|
||||
func (c *testARPDB) Neighbors() (ns []arpdb.Neighbor) {
|
||||
return c.onNeighbors()
|
||||
}
|
||||
|
||||
// testDHCP is a mock implementation of the [client.DHCP].
|
||||
type testDHCP struct {
|
||||
OnLeases func() (leases []*dhcpsvc.Lease)
|
||||
OnHostBy func(ip netip.Addr) (host string)
|
||||
OnMACBy func(ip netip.Addr) (mac net.HardwareAddr)
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ client.DHCP = (*testDHCP)(nil)
|
||||
|
||||
// Lease implements the [client.DHCP] interface for *testDHCP.
|
||||
func (t *testDHCP) Leases() (leases []*dhcpsvc.Lease) { return t.OnLeases() }
|
||||
|
||||
// HostByIP implements the [client.DHCP] interface for *testDHCP.
|
||||
func (t *testDHCP) HostByIP(ip netip.Addr) (host string) { return t.OnHostBy(ip) }
|
||||
|
||||
// MACByIP implements the [client.DHCP] interface for *testDHCP.
|
||||
func (t *testDHCP) MACByIP(ip netip.Addr) (mac net.HardwareAddr) { return t.OnMACBy(ip) }
|
||||
|
||||
// compareRuntimeInfo is a helper function that returns true if the runtime
|
||||
// client has provided info.
|
||||
func compareRuntimeInfo(rc *client.Runtime, src client.Source, host string) (ok bool) {
|
||||
s, h := rc.Info()
|
||||
if s != src {
|
||||
return false
|
||||
} else if h != host {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func TestStorage_Add_hostsfile(t *testing.T) {
|
||||
var (
|
||||
cliIP1 = netip.MustParseAddr("1.1.1.1")
|
||||
cliName1 = "client_one"
|
||||
|
||||
cliIP2 = netip.MustParseAddr("2.2.2.2")
|
||||
cliName2 = "client_two"
|
||||
)
|
||||
|
||||
hostCh := make(chan *hostsfile.DefaultStorage)
|
||||
h := &testHostsContainer{
|
||||
onUpd: func() (updates <-chan *hostsfile.DefaultStorage) { return hostCh },
|
||||
}
|
||||
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
storage, err := client.NewStorage(ctx, &client.StorageConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
DHCP: client.EmptyDHCP{},
|
||||
EtcHosts: h,
|
||||
ARPClientsUpdatePeriod: testTimeout / 10,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = storage.Start(testutil.ContextWithTimeout(t, testTimeout))
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.CleanupAndRequireSuccess(t, func() (err error) {
|
||||
return storage.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
|
||||
})
|
||||
|
||||
t.Run("add_hosts", func(t *testing.T) {
|
||||
var s *hostsfile.DefaultStorage
|
||||
s, err = hostsfile.NewDefaultStorage()
|
||||
require.NoError(t, err)
|
||||
|
||||
s.Add(&hostsfile.Record{
|
||||
Addr: cliIP1,
|
||||
Names: []string{cliName1},
|
||||
})
|
||||
|
||||
testutil.RequireSend(t, hostCh, s, testTimeout)
|
||||
|
||||
require.Eventually(t, func() (ok bool) {
|
||||
cli1 := storage.ClientRuntime(cliIP1)
|
||||
if cli1 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
assert.True(t, compareRuntimeInfo(cli1, client.SourceHostsFile, cliName1))
|
||||
|
||||
return true
|
||||
}, testTimeout, testTimeout/10)
|
||||
})
|
||||
|
||||
t.Run("update_hosts", func(t *testing.T) {
|
||||
var s *hostsfile.DefaultStorage
|
||||
s, err = hostsfile.NewDefaultStorage()
|
||||
require.NoError(t, err)
|
||||
|
||||
s.Add(&hostsfile.Record{
|
||||
Addr: cliIP2,
|
||||
Names: []string{cliName2},
|
||||
})
|
||||
|
||||
testutil.RequireSend(t, hostCh, s, testTimeout)
|
||||
|
||||
require.Eventually(t, func() (ok bool) {
|
||||
cli2 := storage.ClientRuntime(cliIP2)
|
||||
if cli2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
assert.True(t, compareRuntimeInfo(cli2, client.SourceHostsFile, cliName2))
|
||||
|
||||
cli1 := storage.ClientRuntime(cliIP1)
|
||||
require.Nil(t, cli1)
|
||||
|
||||
return true
|
||||
}, testTimeout, testTimeout/10)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStorage_Add_arp(t *testing.T) {
|
||||
var (
|
||||
mu sync.Mutex
|
||||
neighbors []arpdb.Neighbor
|
||||
|
||||
cliIP1 = netip.MustParseAddr("1.1.1.1")
|
||||
cliName1 = "client_one"
|
||||
|
||||
cliIP2 = netip.MustParseAddr("2.2.2.2")
|
||||
cliName2 = "client_two"
|
||||
)
|
||||
|
||||
a := &testARPDB{
|
||||
onRefresh: func() (err error) { return nil },
|
||||
onNeighbors: func() (ns []arpdb.Neighbor) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
return neighbors
|
||||
},
|
||||
}
|
||||
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
storage, err := client.NewStorage(ctx, &client.StorageConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
DHCP: client.EmptyDHCP{},
|
||||
ARPDB: a,
|
||||
ARPClientsUpdatePeriod: testTimeout / 10,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = storage.Start(testutil.ContextWithTimeout(t, testTimeout))
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.CleanupAndRequireSuccess(t, func() (err error) {
|
||||
return storage.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
|
||||
})
|
||||
|
||||
t.Run("add_hosts", func(t *testing.T) {
|
||||
func() {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
neighbors = []arpdb.Neighbor{{
|
||||
Name: cliName1,
|
||||
IP: cliIP1,
|
||||
}}
|
||||
}()
|
||||
|
||||
require.Eventually(t, func() (ok bool) {
|
||||
cli1 := storage.ClientRuntime(cliIP1)
|
||||
if cli1 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
assert.True(t, compareRuntimeInfo(cli1, client.SourceARP, cliName1))
|
||||
|
||||
return true
|
||||
}, testTimeout, testTimeout/10)
|
||||
})
|
||||
|
||||
t.Run("update_hosts", func(t *testing.T) {
|
||||
func() {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
neighbors = []arpdb.Neighbor{{
|
||||
Name: cliName2,
|
||||
IP: cliIP2,
|
||||
}}
|
||||
}()
|
||||
|
||||
require.Eventually(t, func() (ok bool) {
|
||||
cli2 := storage.ClientRuntime(cliIP2)
|
||||
if cli2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
assert.True(t, compareRuntimeInfo(cli2, client.SourceARP, cliName2))
|
||||
|
||||
cli1 := storage.ClientRuntime(cliIP1)
|
||||
require.Nil(t, cli1)
|
||||
|
||||
return true
|
||||
}, testTimeout, testTimeout/10)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStorage_Add_whois(t *testing.T) {
|
||||
var (
|
||||
cliIP1 = netip.MustParseAddr("1.1.1.1")
|
||||
|
||||
cliIP2 = netip.MustParseAddr("2.2.2.2")
|
||||
cliName2 = "client_two"
|
||||
|
||||
cliIP3 = netip.MustParseAddr("3.3.3.3")
|
||||
cliName3 = "client_three"
|
||||
)
|
||||
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
storage, err := client.NewStorage(ctx, &client.StorageConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
DHCP: client.EmptyDHCP{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
whois := &whois.Info{
|
||||
Country: "AU",
|
||||
Orgname: "Example Org",
|
||||
}
|
||||
|
||||
t.Run("new_client", func(t *testing.T) {
|
||||
storage.UpdateAddress(ctx, cliIP1, "", whois)
|
||||
cli1 := storage.ClientRuntime(cliIP1)
|
||||
require.NotNil(t, cli1)
|
||||
|
||||
assert.Equal(t, whois, cli1.WHOIS())
|
||||
})
|
||||
|
||||
t.Run("existing_runtime_client", func(t *testing.T) {
|
||||
storage.UpdateAddress(ctx, cliIP2, cliName2, nil)
|
||||
storage.UpdateAddress(ctx, cliIP2, "", whois)
|
||||
|
||||
cli2 := storage.ClientRuntime(cliIP2)
|
||||
require.NotNil(t, cli2)
|
||||
|
||||
assert.True(t, compareRuntimeInfo(cli2, client.SourceRDNS, cliName2))
|
||||
|
||||
assert.Equal(t, whois, cli2.WHOIS())
|
||||
})
|
||||
|
||||
t.Run("can't_set_persistent_client", func(t *testing.T) {
|
||||
err = storage.Add(ctx, &client.Persistent{
|
||||
Name: cliName3,
|
||||
UID: client.MustNewUID(),
|
||||
IPs: []netip.Addr{cliIP3},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
storage.UpdateAddress(ctx, cliIP3, "", whois)
|
||||
rc := storage.ClientRuntime(cliIP3)
|
||||
require.Nil(t, rc)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClientsDHCP(t *testing.T) {
|
||||
var (
|
||||
cliIP1 = netip.MustParseAddr("1.1.1.1")
|
||||
cliName1 = "one.dhcp"
|
||||
|
||||
cliIP2 = netip.MustParseAddr("2.2.2.2")
|
||||
cliMAC2 = mustParseMAC("22:22:22:22:22:22")
|
||||
cliName2 = "two.dhcp"
|
||||
|
||||
cliIP3 = netip.MustParseAddr("3.3.3.3")
|
||||
cliMAC3 = mustParseMAC("33:33:33:33:33:33")
|
||||
cliName3 = "three.dhcp"
|
||||
|
||||
prsCliIP = netip.MustParseAddr("4.3.2.1")
|
||||
prsCliMAC = mustParseMAC("AA:AA:AA:AA:AA:AA")
|
||||
prsCliName = "persistent.dhcp"
|
||||
|
||||
otherARPCliName = "other.arp"
|
||||
otherARPCliIP = netip.MustParseAddr("192.0.2.1")
|
||||
)
|
||||
|
||||
ipToHost := map[netip.Addr]string{
|
||||
cliIP1: cliName1,
|
||||
}
|
||||
ipToMAC := map[netip.Addr]net.HardwareAddr{
|
||||
prsCliIP: prsCliMAC,
|
||||
}
|
||||
|
||||
leases := []*dhcpsvc.Lease{{
|
||||
IP: cliIP2,
|
||||
Hostname: cliName2,
|
||||
HWAddr: cliMAC2,
|
||||
}, {
|
||||
IP: cliIP3,
|
||||
Hostname: cliName3,
|
||||
HWAddr: cliMAC3,
|
||||
}}
|
||||
|
||||
arpCh := make(chan []arpdb.Neighbor, 1)
|
||||
arpDB := &testARPDB{
|
||||
onRefresh: func() (err error) { return nil },
|
||||
onNeighbors: func() (ns []arpdb.Neighbor) {
|
||||
select {
|
||||
case ns = <-arpCh:
|
||||
return ns
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
dhcp := &testDHCP{
|
||||
OnLeases: func() (ls []*dhcpsvc.Lease) {
|
||||
return leases
|
||||
},
|
||||
OnHostBy: func(ip netip.Addr) (host string) {
|
||||
return ipToHost[ip]
|
||||
},
|
||||
OnMACBy: func(ip netip.Addr) (mac net.HardwareAddr) {
|
||||
return ipToMAC[ip]
|
||||
},
|
||||
}
|
||||
|
||||
etcHostsCh := make(chan *hostsfile.DefaultStorage, 1)
|
||||
etcHosts := &testHostsContainer{
|
||||
onUpd: func() (updates <-chan *hostsfile.DefaultStorage) {
|
||||
return etcHostsCh
|
||||
},
|
||||
}
|
||||
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
storage, err := client.NewStorage(ctx, &client.StorageConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
ARPDB: arpDB,
|
||||
DHCP: dhcp,
|
||||
EtcHosts: etcHosts,
|
||||
RuntimeSourceDHCP: true,
|
||||
ARPClientsUpdatePeriod: testTimeout / 10,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = storage.Start(testutil.ContextWithTimeout(t, testTimeout))
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.CleanupAndRequireSuccess(t, func() (err error) {
|
||||
return storage.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
|
||||
})
|
||||
|
||||
require.True(t, t.Run("find_runtime_lower_priority", func(t *testing.T) {
|
||||
// Add a lower-priority client.
|
||||
ns := []arpdb.Neighbor{{
|
||||
Name: cliName1,
|
||||
IP: cliIP1,
|
||||
}}
|
||||
|
||||
testutil.RequireSend(t, arpCh, ns, testTimeout)
|
||||
|
||||
storage.ReloadARP(testutil.ContextWithTimeout(t, testTimeout))
|
||||
|
||||
cli1 := storage.ClientRuntime(cliIP1)
|
||||
require.NotNil(t, cli1)
|
||||
|
||||
assert.True(t, compareRuntimeInfo(cli1, client.SourceDHCP, cliName1))
|
||||
|
||||
// Remove the matching client.
|
||||
//
|
||||
// TODO(a.garipov): Consider adding ways of explicitly clearing runtime
|
||||
// sources by source.
|
||||
ns = []arpdb.Neighbor{{
|
||||
Name: otherARPCliName,
|
||||
IP: otherARPCliIP,
|
||||
}}
|
||||
|
||||
testutil.RequireSend(t, arpCh, ns, testTimeout)
|
||||
|
||||
storage.ReloadARP(testutil.ContextWithTimeout(t, testTimeout))
|
||||
}))
|
||||
|
||||
require.True(t, t.Run("find_runtime", func(t *testing.T) {
|
||||
cli1 := storage.ClientRuntime(cliIP1)
|
||||
require.NotNil(t, cli1)
|
||||
|
||||
assert.True(t, compareRuntimeInfo(cli1, client.SourceDHCP, cliName1))
|
||||
}))
|
||||
|
||||
require.True(t, t.Run("find_runtime_higher_priority", func(t *testing.T) {
|
||||
// Add a higher-priority client.
|
||||
s, strgErr := hostsfile.NewDefaultStorage()
|
||||
require.NoError(t, strgErr)
|
||||
|
||||
s.Add(&hostsfile.Record{
|
||||
Addr: cliIP1,
|
||||
Names: []string{cliName1},
|
||||
})
|
||||
|
||||
testutil.RequireSend(t, etcHostsCh, s, testTimeout)
|
||||
|
||||
cli1 := storage.ClientRuntime(cliIP1)
|
||||
require.NotNil(t, cli1)
|
||||
|
||||
require.Eventually(t, func() (ok bool) {
|
||||
cli := storage.ClientRuntime(cliIP1)
|
||||
if cli == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
assert.True(t, compareRuntimeInfo(cli, client.SourceHostsFile, cliName1))
|
||||
|
||||
return true
|
||||
}, testTimeout, testTimeout/10)
|
||||
|
||||
// Remove the matching client.
|
||||
//
|
||||
// TODO(a.garipov): Consider adding ways of explicitly clearing runtime
|
||||
// sources by source.
|
||||
s, strgErr = hostsfile.NewDefaultStorage()
|
||||
require.NoError(t, strgErr)
|
||||
|
||||
testutil.RequireSend(t, etcHostsCh, s, testTimeout)
|
||||
|
||||
require.Eventually(t, func() (ok bool) {
|
||||
cli := storage.ClientRuntime(cliIP1)
|
||||
|
||||
return compareRuntimeInfo(cli, client.SourceDHCP, cliName1)
|
||||
}, testTimeout, testTimeout/10)
|
||||
}))
|
||||
|
||||
require.True(t, t.Run("find_persistent", func(t *testing.T) {
|
||||
err = storage.Add(ctx, &client.Persistent{
|
||||
Name: prsCliName,
|
||||
UID: client.MustNewUID(),
|
||||
MACs: []net.HardwareAddr{prsCliMAC},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
prsCli, ok := storage.Find(prsCliIP.String())
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, prsCliName, prsCli.Name)
|
||||
}))
|
||||
|
||||
require.True(t, t.Run("leases", func(t *testing.T) {
|
||||
delete(ipToHost, cliIP1)
|
||||
storage.UpdateDHCP(ctx)
|
||||
|
||||
cli1 := storage.ClientRuntime(cliIP1)
|
||||
require.Nil(t, cli1)
|
||||
|
||||
for i, l := range leases {
|
||||
cli := storage.ClientRuntime(l.IP)
|
||||
require.NotNil(t, cli)
|
||||
|
||||
src, host := cli.Info()
|
||||
assert.Equal(t, client.SourceDHCP, src)
|
||||
assert.Equal(t, leases[i].Hostname, host)
|
||||
}
|
||||
}))
|
||||
|
||||
require.True(t, t.Run("range", func(t *testing.T) {
|
||||
s := 0
|
||||
storage.RangeRuntime(func(rc *client.Runtime) (cont bool) {
|
||||
if src, _ := rc.Info(); src == client.SourceDHCP {
|
||||
s++
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
assert.Equal(t, len(leases), s)
|
||||
}))
|
||||
}
|
||||
|
||||
func TestClientsAddExisting(t *testing.T) {
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
|
||||
t.Run("simple", func(t *testing.T) {
|
||||
storage, err := client.NewStorage(ctx, &client.StorageConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
DHCP: client.EmptyDHCP{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
ip := netip.MustParseAddr("1.1.1.1")
|
||||
|
||||
// Add a client.
|
||||
err = storage.Add(ctx, &client.Persistent{
|
||||
Name: "client1",
|
||||
UID: client.MustNewUID(),
|
||||
IPs: []netip.Addr{ip, netip.MustParseAddr("1:2:3::4")},
|
||||
Subnets: []netip.Prefix{netip.MustParsePrefix("2.2.2.0/24")},
|
||||
MACs: []net.HardwareAddr{{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Now add an auto-client with the same IP.
|
||||
storage.UpdateAddress(ctx, ip, "test", nil)
|
||||
rc := storage.ClientRuntime(ip)
|
||||
assert.True(t, compareRuntimeInfo(rc, client.SourceRDNS, "test"))
|
||||
})
|
||||
|
||||
t.Run("complicated", func(t *testing.T) {
|
||||
// TODO(a.garipov): Properly decouple the DHCP server from the client
|
||||
// storage.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("skipping dhcp test on windows")
|
||||
}
|
||||
|
||||
// First, init a DHCP server with a single static lease.
|
||||
config := &dhcpd.ServerConfig{
|
||||
Enabled: true,
|
||||
DataDir: t.TempDir(),
|
||||
Conf4: dhcpd.V4ServerConf{
|
||||
Enabled: true,
|
||||
GatewayIP: netip.MustParseAddr("1.2.3.1"),
|
||||
SubnetMask: netip.MustParseAddr("255.255.255.0"),
|
||||
RangeStart: netip.MustParseAddr("1.2.3.2"),
|
||||
RangeEnd: netip.MustParseAddr("1.2.3.10"),
|
||||
},
|
||||
}
|
||||
|
||||
dhcpServer, err := dhcpd.Create(config)
|
||||
require.NoError(t, err)
|
||||
|
||||
storage, err := client.NewStorage(ctx, &client.StorageConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
DHCP: dhcpServer,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
ip := netip.MustParseAddr("1.2.3.4")
|
||||
|
||||
err = dhcpServer.AddStaticLease(&dhcpsvc.Lease{
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: ip,
|
||||
Hostname: "testhost",
|
||||
Expiry: time.Now().Add(time.Hour),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add a new client with the same IP as for a client with MAC.
|
||||
err = storage.Add(ctx, &client.Persistent{
|
||||
Name: "client2",
|
||||
UID: client.MustNewUID(),
|
||||
IPs: []netip.Addr{ip},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add a new client with the IP from the first client's IP range.
|
||||
err = storage.Add(ctx, &client.Persistent{
|
||||
Name: "client3",
|
||||
UID: client.MustNewUID(),
|
||||
IPs: []netip.Addr{netip.MustParseAddr("2.2.2.2")},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
// newStorage is a helper function that returns a client storage filled with
|
||||
// persistent clients from the m. It also generates a UID for each client.
|
||||
func newStorage(tb testing.TB, m []*client.Persistent) (s *client.Storage) {
|
||||
tb.Helper()
|
||||
|
||||
s = client.NewStorage(&client.Config{
|
||||
AllowedTags: nil,
|
||||
ctx := testutil.ContextWithTimeout(tb, testTimeout)
|
||||
s, err := client.NewStorage(ctx, &client.StorageConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
DHCP: client.EmptyDHCP{},
|
||||
})
|
||||
require.NoError(tb, err)
|
||||
|
||||
for _, c := range m {
|
||||
c.UID = client.MustNewUID()
|
||||
require.NoError(tb, s.Add(c))
|
||||
require.NoError(tb, s.Add(ctx, c))
|
||||
}
|
||||
|
||||
require.Equal(tb, len(m), s.Size())
|
||||
@@ -31,14 +656,6 @@ func newStorage(tb testing.TB, m []*client.Persistent) (s *client.Storage) {
|
||||
return s
|
||||
}
|
||||
|
||||
// newRuntimeClient is a helper function that returns a new runtime client.
|
||||
func newRuntimeClient(ip netip.Addr, source client.Source, host string) (rc *client.Runtime) {
|
||||
rc = client.NewRuntime(ip)
|
||||
rc.SetInfo(source, []string{host})
|
||||
|
||||
return rc
|
||||
}
|
||||
|
||||
// mustParseMAC is wrapper around [net.ParseMAC] that panics if there is an
|
||||
// error.
|
||||
func mustParseMAC(s string) (mac net.HardwareAddr) {
|
||||
@@ -55,7 +672,7 @@ func TestStorage_Add(t *testing.T) {
|
||||
existingName = "existing_name"
|
||||
existingClientID = "existing_client_id"
|
||||
|
||||
allowedTag = "tag"
|
||||
allowedTag = "user_admin"
|
||||
notAllowedTag = "not_allowed_tag"
|
||||
)
|
||||
|
||||
@@ -73,10 +690,19 @@ func TestStorage_Add(t *testing.T) {
|
||||
UID: existingClientUID,
|
||||
}
|
||||
|
||||
s := client.NewStorage(&client.Config{
|
||||
AllowedTags: []string{allowedTag},
|
||||
})
|
||||
err := s.Add(existingClient)
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
s := newTestStorage(t)
|
||||
tags := s.AllowedTags()
|
||||
require.NotZero(t, len(tags))
|
||||
require.True(t, slices.IsSorted(tags))
|
||||
|
||||
_, ok := slices.BinarySearch(tags, allowedTag)
|
||||
require.True(t, ok)
|
||||
|
||||
_, ok = slices.BinarySearch(tags, notAllowedTag)
|
||||
require.False(t, ok)
|
||||
|
||||
err := s.Add(ctx, existingClient)
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
@@ -136,17 +762,48 @@ func TestStorage_Add(t *testing.T) {
|
||||
}, {
|
||||
name: "not_allowed_tag",
|
||||
cli: &client.Persistent{
|
||||
Name: "nont_allowed_tag",
|
||||
Name: "not_allowed_tag",
|
||||
Tags: []string{notAllowedTag},
|
||||
IPs: []netip.Addr{netip.MustParseAddr("4.4.4.4")},
|
||||
UID: client.MustNewUID(),
|
||||
},
|
||||
wantErrMsg: `adding client: invalid tag: "not_allowed_tag"`,
|
||||
}, {
|
||||
name: "allowed_tag",
|
||||
cli: &client.Persistent{
|
||||
Name: "allowed_tag",
|
||||
Tags: []string{allowedTag},
|
||||
IPs: []netip.Addr{netip.MustParseAddr("5.5.5.5")},
|
||||
UID: client.MustNewUID(),
|
||||
},
|
||||
wantErrMsg: "",
|
||||
}, {
|
||||
name: "",
|
||||
cli: &client.Persistent{
|
||||
Name: "",
|
||||
IPs: []netip.Addr{netip.MustParseAddr("6.6.6.6")},
|
||||
UID: client.MustNewUID(),
|
||||
},
|
||||
wantErrMsg: "adding client: empty name",
|
||||
}, {
|
||||
name: "no_id",
|
||||
cli: &client.Persistent{
|
||||
Name: "no_id",
|
||||
UID: client.MustNewUID(),
|
||||
},
|
||||
wantErrMsg: "adding client: id required",
|
||||
}, {
|
||||
name: "no_uid",
|
||||
cli: &client.Persistent{
|
||||
Name: "no_uid",
|
||||
IPs: []netip.Addr{netip.MustParseAddr("7.7.7.7")},
|
||||
},
|
||||
wantErrMsg: "adding client: uid required",
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err = s.Add(tc.cli)
|
||||
err = s.Add(ctx, tc.cli)
|
||||
|
||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
|
||||
})
|
||||
@@ -164,10 +821,9 @@ func TestStorage_RemoveByName(t *testing.T) {
|
||||
UID: client.MustNewUID(),
|
||||
}
|
||||
|
||||
s := client.NewStorage(&client.Config{
|
||||
AllowedTags: nil,
|
||||
})
|
||||
err := s.Add(existingClient)
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
s := newTestStorage(t)
|
||||
err := s.Add(ctx, existingClient)
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
@@ -186,19 +842,17 @@ func TestStorage_RemoveByName(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tc.want(t, s.RemoveByName(tc.cliName))
|
||||
tc.want(t, s.RemoveByName(ctx, tc.cliName))
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("duplicate_remove", func(t *testing.T) {
|
||||
s = client.NewStorage(&client.Config{
|
||||
AllowedTags: nil,
|
||||
})
|
||||
err = s.Add(existingClient)
|
||||
s = newTestStorage(t)
|
||||
err = s.Add(ctx, existingClient)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.True(t, s.RemoveByName(existingName))
|
||||
assert.False(t, s.RemoveByName(existingName))
|
||||
assert.True(t, s.RemoveByName(ctx, existingName))
|
||||
assert.False(t, s.RemoveByName(ctx, existingName))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -557,6 +1211,7 @@ func TestStorage_Update(t *testing.T) {
|
||||
`uses the same ClientID "obstructing_client_id"`,
|
||||
}}
|
||||
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s := newStorage(
|
||||
@@ -567,7 +1222,7 @@ func TestStorage_Update(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
err := s.Update(clientName, tc.cli)
|
||||
err := s.Update(ctx, clientName, tc.cli)
|
||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
|
||||
})
|
||||
}
|
||||
@@ -623,157 +1278,3 @@ func TestStorage_RangeByName(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStorage_UpdateRuntime(t *testing.T) {
|
||||
const (
|
||||
addedARP = "added_arp"
|
||||
addedSecondARP = "added_arp"
|
||||
|
||||
updatedARP = "updated_arp"
|
||||
|
||||
cliCity = "City"
|
||||
cliCountry = "Country"
|
||||
cliOrgname = "Orgname"
|
||||
)
|
||||
|
||||
var (
|
||||
ip = netip.MustParseAddr("1.1.1.1")
|
||||
ip2 = netip.MustParseAddr("2.2.2.2")
|
||||
)
|
||||
|
||||
updated := client.NewRuntime(ip)
|
||||
updated.SetInfo(client.SourceARP, []string{updatedARP})
|
||||
|
||||
info := &whois.Info{
|
||||
City: cliCity,
|
||||
Country: cliCountry,
|
||||
Orgname: cliOrgname,
|
||||
}
|
||||
updated.SetWHOIS(info)
|
||||
|
||||
s := client.NewStorage(&client.Config{
|
||||
AllowedTags: nil,
|
||||
})
|
||||
|
||||
t.Run("add_arp_client", func(t *testing.T) {
|
||||
added := client.NewRuntime(ip)
|
||||
added.SetInfo(client.SourceARP, []string{addedARP})
|
||||
|
||||
require.True(t, s.UpdateRuntime(added))
|
||||
require.Equal(t, 1, s.SizeRuntime())
|
||||
|
||||
got := s.ClientRuntime(ip)
|
||||
source, host := got.Info()
|
||||
assert.Equal(t, client.SourceARP, source)
|
||||
assert.Equal(t, addedARP, host)
|
||||
})
|
||||
|
||||
t.Run("add_second_arp_client", func(t *testing.T) {
|
||||
added := client.NewRuntime(ip2)
|
||||
added.SetInfo(client.SourceARP, []string{addedSecondARP})
|
||||
|
||||
require.True(t, s.UpdateRuntime(added))
|
||||
require.Equal(t, 2, s.SizeRuntime())
|
||||
|
||||
got := s.ClientRuntime(ip2)
|
||||
source, host := got.Info()
|
||||
assert.Equal(t, client.SourceARP, source)
|
||||
assert.Equal(t, addedSecondARP, host)
|
||||
})
|
||||
|
||||
t.Run("update_first_client", func(t *testing.T) {
|
||||
require.False(t, s.UpdateRuntime(updated))
|
||||
got := s.ClientRuntime(ip)
|
||||
require.Equal(t, 2, s.SizeRuntime())
|
||||
|
||||
source, host := got.Info()
|
||||
assert.Equal(t, client.SourceARP, source)
|
||||
assert.Equal(t, updatedARP, host)
|
||||
})
|
||||
|
||||
t.Run("remove_arp_info", func(t *testing.T) {
|
||||
n := s.DeleteBySource(client.SourceARP)
|
||||
require.Equal(t, 1, n)
|
||||
require.Equal(t, 1, s.SizeRuntime())
|
||||
|
||||
got := s.ClientRuntime(ip)
|
||||
source, _ := got.Info()
|
||||
assert.Equal(t, client.SourceWHOIS, source)
|
||||
assert.Equal(t, info, got.WHOIS())
|
||||
})
|
||||
|
||||
t.Run("remove_whois_info", func(t *testing.T) {
|
||||
n := s.DeleteBySource(client.SourceWHOIS)
|
||||
require.Equal(t, 1, n)
|
||||
require.Equal(t, 0, s.SizeRuntime())
|
||||
})
|
||||
}
|
||||
|
||||
func TestStorage_BatchUpdateBySource(t *testing.T) {
|
||||
const (
|
||||
defSrc = client.SourceARP
|
||||
|
||||
cliFirstHost1 = "host1"
|
||||
cliFirstHost2 = "host2"
|
||||
cliUpdatedHost3 = "host3"
|
||||
cliUpdatedHost4 = "host4"
|
||||
cliUpdatedHost5 = "host5"
|
||||
)
|
||||
|
||||
var (
|
||||
cliFirstIP1 = netip.MustParseAddr("1.1.1.1")
|
||||
cliFirstIP2 = netip.MustParseAddr("2.2.2.2")
|
||||
cliUpdatedIP3 = netip.MustParseAddr("3.3.3.3")
|
||||
cliUpdatedIP4 = netip.MustParseAddr("4.4.4.4")
|
||||
cliUpdatedIP5 = netip.MustParseAddr("5.5.5.5")
|
||||
)
|
||||
|
||||
firstClients := []*client.Runtime{
|
||||
newRuntimeClient(cliFirstIP1, defSrc, cliFirstHost1),
|
||||
newRuntimeClient(cliFirstIP2, defSrc, cliFirstHost2),
|
||||
}
|
||||
|
||||
updatedClients := []*client.Runtime{
|
||||
newRuntimeClient(cliUpdatedIP3, defSrc, cliUpdatedHost3),
|
||||
newRuntimeClient(cliUpdatedIP4, defSrc, cliUpdatedHost4),
|
||||
newRuntimeClient(cliUpdatedIP5, defSrc, cliUpdatedHost5),
|
||||
}
|
||||
|
||||
s := client.NewStorage(&client.Config{
|
||||
AllowedTags: nil,
|
||||
})
|
||||
|
||||
t.Run("populate_storage_with_first_clients", func(t *testing.T) {
|
||||
added, removed := s.BatchUpdateBySource(defSrc, firstClients)
|
||||
require.Equal(t, len(firstClients), added)
|
||||
require.Equal(t, 0, removed)
|
||||
require.Equal(t, len(firstClients), s.SizeRuntime())
|
||||
|
||||
rc := s.ClientRuntime(cliFirstIP1)
|
||||
src, host := rc.Info()
|
||||
assert.Equal(t, defSrc, src)
|
||||
assert.Equal(t, cliFirstHost1, host)
|
||||
})
|
||||
|
||||
t.Run("update_storage", func(t *testing.T) {
|
||||
added, removed := s.BatchUpdateBySource(defSrc, updatedClients)
|
||||
require.Equal(t, len(updatedClients), added)
|
||||
require.Equal(t, len(firstClients), removed)
|
||||
require.Equal(t, len(updatedClients), s.SizeRuntime())
|
||||
|
||||
rc := s.ClientRuntime(cliUpdatedIP3)
|
||||
src, host := rc.Info()
|
||||
assert.Equal(t, defSrc, src)
|
||||
assert.Equal(t, cliUpdatedHost3, host)
|
||||
|
||||
rc = s.ClientRuntime(cliFirstIP1)
|
||||
assert.Nil(t, rc)
|
||||
})
|
||||
|
||||
t.Run("remove_all", func(t *testing.T) {
|
||||
added, removed := s.BatchUpdateBySource(defSrc, []*client.Runtime{})
|
||||
require.Equal(t, 0, added)
|
||||
require.Equal(t, len(updatedClients), removed)
|
||||
require.Equal(t, 0, s.SizeRuntime())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
package configmigrate
|
||||
|
||||
// LastSchemaVersion is the most recent schema version.
|
||||
const LastSchemaVersion uint = 28
|
||||
const LastSchemaVersion uint = 29
|
||||
|
||||
@@ -19,6 +19,7 @@ func TestUpgradeSchema1to2(t *testing.T) {
|
||||
|
||||
m := New(&Config{
|
||||
WorkingDir: "",
|
||||
DataDir: "",
|
||||
})
|
||||
|
||||
err := m.migrateTo2(diskConf)
|
||||
@@ -520,7 +521,7 @@ func TestUpgradeSchema11to12(t *testing.T) {
|
||||
name string
|
||||
}{{
|
||||
ivl: 1,
|
||||
want: timeutil.Duration{Duration: timeutil.Day},
|
||||
want: timeutil.Duration(timeutil.Day),
|
||||
wantErr: "",
|
||||
name: "success",
|
||||
}, {
|
||||
@@ -603,7 +604,7 @@ func TestUpgradeSchema11to12(t *testing.T) {
|
||||
ivlVal, ok = ivl.(timeutil.Duration)
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, 90*24*time.Hour, ivlVal.Duration)
|
||||
assert.Equal(t, 90*24*time.Hour, time.Duration(ivlVal))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1054,12 +1055,12 @@ func TestUpgradeSchema19to20(t *testing.T) {
|
||||
name string
|
||||
}{{
|
||||
ivl: 1,
|
||||
want: timeutil.Duration{Duration: timeutil.Day},
|
||||
want: timeutil.Duration(timeutil.Day),
|
||||
wantErr: "",
|
||||
name: "success",
|
||||
}, {
|
||||
ivl: 0,
|
||||
want: timeutil.Duration{Duration: timeutil.Day},
|
||||
want: timeutil.Duration(timeutil.Day),
|
||||
wantErr: "",
|
||||
name: "success",
|
||||
}, {
|
||||
@@ -1142,7 +1143,7 @@ func TestUpgradeSchema19to20(t *testing.T) {
|
||||
ivlVal, ok = ivl.(timeutil.Duration)
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, 24*time.Hour, ivlVal.Duration)
|
||||
assert.Equal(t, 24*time.Hour, time.Duration(ivlVal))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -10,20 +10,24 @@ import (
|
||||
|
||||
// Config is a the configuration for initializing a [Migrator].
|
||||
type Config struct {
|
||||
// WorkingDir is an absolute path to the working directory of AdGuardHome.
|
||||
// WorkingDir is the absolute path to the working directory of AdGuardHome.
|
||||
WorkingDir string
|
||||
|
||||
// DataDir is the absolute path to the data directory of AdGuardHome.
|
||||
DataDir string
|
||||
}
|
||||
|
||||
// Migrator performs the YAML configuration file migrations.
|
||||
type Migrator struct {
|
||||
// workingDir is an absolute path to the working directory of AdGuardHome.
|
||||
workingDir string
|
||||
dataDir string
|
||||
}
|
||||
|
||||
// New creates a new Migrator.
|
||||
func New(cfg *Config) (m *Migrator) {
|
||||
func New(c *Config) (m *Migrator) {
|
||||
return &Migrator{
|
||||
workingDir: cfg.WorkingDir,
|
||||
workingDir: c.WorkingDir,
|
||||
dataDir: c.DataDir,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +124,7 @@ func (m *Migrator) upgradeConfigSchema(current, target uint, diskConf yobj) (err
|
||||
25: migrateTo26,
|
||||
26: migrateTo27,
|
||||
27: migrateTo28,
|
||||
28: m.migrateTo29,
|
||||
}
|
||||
|
||||
for i, migrate := range upgrades[current:target] {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package configmigrate_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/configmigrate"
|
||||
@@ -202,6 +205,7 @@ func TestMigrateConfig_Migrate(t *testing.T) {
|
||||
|
||||
migrator := configmigrate.New(&configmigrate.Config{
|
||||
WorkingDir: t.Name(),
|
||||
DataDir: filepath.Join(t.Name(), "data"),
|
||||
})
|
||||
newBody, upgraded, err := migrator.Migrate(body, tc.targetVersion)
|
||||
require.NoError(t, err)
|
||||
@@ -211,3 +215,43 @@ func TestMigrateConfig_Migrate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Consider ways of merging into the previous one.
|
||||
func TestMigrateConfig_Migrate_v29(t *testing.T) {
|
||||
const (
|
||||
pathUnix = `/path/to/file.txt`
|
||||
userDirPatUnix = `TestMigrateConfig_Migrate/v29/data/userfilters/*`
|
||||
|
||||
pathWindows = `C:\path\to\file.txt`
|
||||
userDirPatWindows = `TestMigrateConfig_Migrate\v29\data\userfilters\*`
|
||||
)
|
||||
|
||||
pathToReplace := pathUnix
|
||||
patternToReplace := userDirPatUnix
|
||||
if runtime.GOOS == "windows" {
|
||||
pathToReplace = pathWindows
|
||||
patternToReplace = userDirPatWindows
|
||||
}
|
||||
|
||||
body, err := fs.ReadFile(testdata, "TestMigrateConfig_Migrate/v29/input.yml")
|
||||
require.NoError(t, err)
|
||||
|
||||
body = bytes.ReplaceAll(body, []byte("FILEPATH"), []byte(pathToReplace))
|
||||
|
||||
wantBody, err := fs.ReadFile(testdata, "TestMigrateConfig_Migrate/v29/output.yml")
|
||||
require.NoError(t, err)
|
||||
|
||||
wantBody = bytes.ReplaceAll(wantBody, []byte("FILEPATH"), []byte(pathToReplace))
|
||||
wantBody = bytes.ReplaceAll(wantBody, []byte("USERFILTERSPATH"), []byte(patternToReplace))
|
||||
|
||||
migrator := configmigrate.New(&configmigrate.Config{
|
||||
WorkingDir: t.Name(),
|
||||
DataDir: "TestMigrateConfig_Migrate/v29/data",
|
||||
})
|
||||
|
||||
newBody, upgraded, err := migrator.Migrate(body, 29)
|
||||
require.NoError(t, err)
|
||||
require.True(t, upgraded)
|
||||
|
||||
require.YAMLEq(t, string(wantBody), string(newBody))
|
||||
}
|
||||
|
||||
117
internal/configmigrate/testdata/TestMigrateConfig_Migrate/v29/input.yml
vendored
Normal file
117
internal/configmigrate/testdata/TestMigrateConfig_Migrate/v29/input.yml
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
http:
|
||||
address: 127.0.0.1:3000
|
||||
session_ttl: 3h
|
||||
pprof:
|
||||
enabled: true
|
||||
port: 6060
|
||||
users:
|
||||
- name: testuser
|
||||
password: testpassword
|
||||
dns:
|
||||
bind_hosts:
|
||||
- 127.0.0.1
|
||||
port: 53
|
||||
parental_sensitivity: 0
|
||||
upstream_dns:
|
||||
- tls://1.1.1.1
|
||||
- tls://1.0.0.1
|
||||
- quic://8.8.8.8:784
|
||||
bootstrap_dns:
|
||||
- 8.8.8.8:53
|
||||
edns_client_subnet:
|
||||
enabled: true
|
||||
use_custom: false
|
||||
custom_ip: ""
|
||||
filtering:
|
||||
filtering_enabled: true
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
safe_search:
|
||||
enabled: false
|
||||
bing: true
|
||||
duckduckgo: true
|
||||
google: true
|
||||
pixabay: true
|
||||
yandex: true
|
||||
youtube: true
|
||||
protection_enabled: true
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids:
|
||||
- 500px
|
||||
blocked_response_ttl: 10
|
||||
filters:
|
||||
- url: https://adaway.org/hosts.txt
|
||||
name: AdAway
|
||||
enabled: false
|
||||
- url: FILEPATH
|
||||
name: Local Filter
|
||||
enabled: false
|
||||
clients:
|
||||
persistent:
|
||||
- name: localhost
|
||||
ids:
|
||||
- 127.0.0.1
|
||||
- aa:aa:aa:aa:aa:aa
|
||||
use_global_settings: true
|
||||
use_global_blocked_services: true
|
||||
filtering_enabled: false
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
safe_search:
|
||||
enabled: true
|
||||
bing: true
|
||||
duckduckgo: true
|
||||
google: true
|
||||
pixabay: true
|
||||
yandex: true
|
||||
youtube: true
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids:
|
||||
- 500px
|
||||
runtime_sources:
|
||||
whois: true
|
||||
arp: true
|
||||
rdns: true
|
||||
dhcp: true
|
||||
hosts: true
|
||||
dhcp:
|
||||
enabled: false
|
||||
interface_name: vboxnet0
|
||||
local_domain_name: local
|
||||
dhcpv4:
|
||||
gateway_ip: 192.168.0.1
|
||||
subnet_mask: 255.255.255.0
|
||||
range_start: 192.168.0.10
|
||||
range_end: 192.168.0.250
|
||||
lease_duration: 1234
|
||||
icmp_timeout_msec: 10
|
||||
schema_version: 28
|
||||
user_rules: []
|
||||
querylog:
|
||||
enabled: true
|
||||
file_enabled: true
|
||||
interval: 720h
|
||||
size_memory: 1000
|
||||
ignored:
|
||||
- '|.^'
|
||||
statistics:
|
||||
enabled: true
|
||||
interval: 240h
|
||||
ignored:
|
||||
- '|.^'
|
||||
os:
|
||||
group: ''
|
||||
rlimit_nofile: 123
|
||||
user: ''
|
||||
log:
|
||||
file: ""
|
||||
max_backups: 0
|
||||
max_size: 100
|
||||
max_age: 3
|
||||
compress: true
|
||||
local_time: false
|
||||
verbose: true
|
||||
120
internal/configmigrate/testdata/TestMigrateConfig_Migrate/v29/output.yml
vendored
Normal file
120
internal/configmigrate/testdata/TestMigrateConfig_Migrate/v29/output.yml
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
http:
|
||||
address: 127.0.0.1:3000
|
||||
session_ttl: 3h
|
||||
pprof:
|
||||
enabled: true
|
||||
port: 6060
|
||||
users:
|
||||
- name: testuser
|
||||
password: testpassword
|
||||
dns:
|
||||
bind_hosts:
|
||||
- 127.0.0.1
|
||||
port: 53
|
||||
parental_sensitivity: 0
|
||||
upstream_dns:
|
||||
- tls://1.1.1.1
|
||||
- tls://1.0.0.1
|
||||
- quic://8.8.8.8:784
|
||||
bootstrap_dns:
|
||||
- 8.8.8.8:53
|
||||
edns_client_subnet:
|
||||
enabled: true
|
||||
use_custom: false
|
||||
custom_ip: ""
|
||||
filtering:
|
||||
filtering_enabled: true
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
safe_fs_patterns:
|
||||
- USERFILTERSPATH
|
||||
- FILEPATH
|
||||
safe_search:
|
||||
enabled: false
|
||||
bing: true
|
||||
duckduckgo: true
|
||||
google: true
|
||||
pixabay: true
|
||||
yandex: true
|
||||
youtube: true
|
||||
protection_enabled: true
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids:
|
||||
- 500px
|
||||
blocked_response_ttl: 10
|
||||
filters:
|
||||
- url: https://adaway.org/hosts.txt
|
||||
name: AdAway
|
||||
enabled: false
|
||||
- url: FILEPATH
|
||||
name: Local Filter
|
||||
enabled: false
|
||||
clients:
|
||||
persistent:
|
||||
- name: localhost
|
||||
ids:
|
||||
- 127.0.0.1
|
||||
- aa:aa:aa:aa:aa:aa
|
||||
use_global_settings: true
|
||||
use_global_blocked_services: true
|
||||
filtering_enabled: false
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
safe_search:
|
||||
enabled: true
|
||||
bing: true
|
||||
duckduckgo: true
|
||||
google: true
|
||||
pixabay: true
|
||||
yandex: true
|
||||
youtube: true
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids:
|
||||
- 500px
|
||||
runtime_sources:
|
||||
whois: true
|
||||
arp: true
|
||||
rdns: true
|
||||
dhcp: true
|
||||
hosts: true
|
||||
dhcp:
|
||||
enabled: false
|
||||
interface_name: vboxnet0
|
||||
local_domain_name: local
|
||||
dhcpv4:
|
||||
gateway_ip: 192.168.0.1
|
||||
subnet_mask: 255.255.255.0
|
||||
range_start: 192.168.0.10
|
||||
range_end: 192.168.0.250
|
||||
lease_duration: 1234
|
||||
icmp_timeout_msec: 10
|
||||
schema_version: 29
|
||||
user_rules: []
|
||||
querylog:
|
||||
enabled: true
|
||||
file_enabled: true
|
||||
interval: 720h
|
||||
size_memory: 1000
|
||||
ignored:
|
||||
- '|.^'
|
||||
statistics:
|
||||
enabled: true
|
||||
interval: 240h
|
||||
ignored:
|
||||
- '|.^'
|
||||
os:
|
||||
group: ''
|
||||
rlimit_nofile: 123
|
||||
user: ''
|
||||
log:
|
||||
file: ""
|
||||
max_backups: 0
|
||||
max_size: 100
|
||||
max_age: 3
|
||||
compress: true
|
||||
local_time: false
|
||||
verbose: true
|
||||
@@ -37,7 +37,7 @@ func migrateTo12(diskConf yobj) (err error) {
|
||||
qlogIvl = 90
|
||||
}
|
||||
|
||||
dns[field] = timeutil.Duration{Duration: time.Duration(qlogIvl) * timeutil.Day}
|
||||
dns[field] = timeutil.Duration(time.Duration(qlogIvl) * timeutil.Day)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func migrateTo20(diskConf yobj) (err error) {
|
||||
ivl = 1
|
||||
}
|
||||
|
||||
stats[field] = timeutil.Duration{Duration: time.Duration(ivl) * timeutil.Day}
|
||||
stats[field] = timeutil.Duration(time.Duration(ivl) * timeutil.Day)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func migrateTo23(diskConf yobj) (err error) {
|
||||
|
||||
diskConf["http"] = yobj{
|
||||
"address": netip.AddrPortFrom(bindHostAddr, uint16(bindPort)).String(),
|
||||
"session_ttl": timeutil.Duration{Duration: time.Duration(sessionTTL) * time.Hour}.String(),
|
||||
"session_ttl": timeutil.Duration(time.Duration(sessionTTL) * time.Hour).String(),
|
||||
}
|
||||
|
||||
delete(diskConf, "bind_host")
|
||||
|
||||
63
internal/configmigrate/v29.go
Normal file
63
internal/configmigrate/v29.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package configmigrate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// migrateTo29 performs the following changes:
|
||||
//
|
||||
// # BEFORE:
|
||||
// 'filters':
|
||||
// - 'enabled': true
|
||||
// 'url': /path/to/file.txt
|
||||
// 'name': My FS Filter
|
||||
// 'id': 1234
|
||||
//
|
||||
// # AFTER:
|
||||
// 'filters':
|
||||
// - 'enabled': true
|
||||
// 'url': /path/to/file.txt
|
||||
// 'name': My FS Filter
|
||||
// 'id': 1234
|
||||
// # …
|
||||
// 'filtering':
|
||||
// 'safe_fs_patterns':
|
||||
// - '/opt/AdGuardHome/data/userfilters/*'
|
||||
// - '/path/to/file.txt'
|
||||
// # …
|
||||
func (m Migrator) migrateTo29(diskConf yobj) (err error) {
|
||||
diskConf["schema_version"] = 29
|
||||
|
||||
filterVals, ok, err := fieldVal[[]any](diskConf, "filters")
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
paths := []string{
|
||||
filepath.Join(m.dataDir, "userfilters", "*"),
|
||||
}
|
||||
|
||||
for i, v := range filterVals {
|
||||
var f yobj
|
||||
f, ok = v.(yobj)
|
||||
if !ok {
|
||||
return fmt.Errorf("filters: at index %d: expected object, got %T", i, v)
|
||||
}
|
||||
|
||||
var u string
|
||||
u, ok, _ = fieldVal[string](f, "url")
|
||||
if ok && filepath.IsAbs(u) {
|
||||
paths = append(paths, u)
|
||||
}
|
||||
}
|
||||
|
||||
fltConf, ok, err := fieldVal[yobj](diskConf, "filtering")
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
fltConf["safe_fs_patterns"] = paths
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,61 +1,50 @@
|
||||
# Testing DHCP Server
|
||||
# Testing DHCP Server
|
||||
|
||||
Contents:
|
||||
* [Test setup with Virtual Box](#vbox)
|
||||
* [Quick test with DHCPTest](#dhcptest)
|
||||
|
||||
## <a href="#vbox" id="vbox" name="vbox">Test setup with Virtual Box</a>
|
||||
- [Test setup with Virtual Box](#vbox)
|
||||
- [Quick test with DHCPTest](#dhcptest)
|
||||
|
||||
### Prerequisites
|
||||
## <a href="#vbox" id="vbox" name="vbox">Test setup with Virtual Box</a>
|
||||
|
||||
### Prerequisites
|
||||
|
||||
To set up a test environment for DHCP server you will need:
|
||||
|
||||
* Linux AG Home host machine (Virtual).
|
||||
* Virtual Box.
|
||||
* Virtual machine (guest OS doesn't matter).
|
||||
- Linux AG Home host machine (Virtual)
|
||||
- Virtual Box
|
||||
- Virtual machine (guest OS doesn't matter)
|
||||
|
||||
### Configure Virtual Box
|
||||
### Configure Virtual Box
|
||||
|
||||
1. Install Virtual Box and run the following command to create a Host-Only
|
||||
network:
|
||||
1. Install Virtual Box and run the following command to create a Host-Only network:
|
||||
|
||||
```sh
|
||||
$ VBoxManage hostonlyif create
|
||||
```
|
||||
```sh
|
||||
VBoxManage hostonlyif create
|
||||
```
|
||||
|
||||
You can check its status by `ip a` command.
|
||||
You can check its status by `ip a` command.
|
||||
|
||||
You can also set up Host-Only network using Virtual Box menu:
|
||||
You can also set up Host-Only network using Virtual Box menu in *File → Host Network Manager.*
|
||||
|
||||
```
|
||||
File -> Host Network Manager...
|
||||
```
|
||||
2. Create your virtual machine and set up its network in *VM Settings → Network → Host-only Adapter.*
|
||||
|
||||
2. Create your virtual machine and set up its network:
|
||||
3. Start your VM, install an OS. Configure your network interface to use DHCP and the OS should ask for a IP address from our DHCP server.
|
||||
|
||||
```
|
||||
VM Settings -> Network -> Host-only Adapter
|
||||
```
|
||||
4. To see the current IP addresses on client OS you can use `ip a` command on Linux or `ipconfig` on Windows.
|
||||
|
||||
3. Start your VM, install an OS. Configure your network interface to use
|
||||
DHCP and the OS should ask for a IP address from our DHCP server.
|
||||
5. To force the client OS to request an IP from DHCP server again, you can use `dhclient` on Linux or `ipconfig /release` on Windows.
|
||||
|
||||
4. To see the current IP addresses on client OS you can use `ip a` command on
|
||||
Linux or `ipconfig` on Windows.
|
||||
### Configure server
|
||||
|
||||
5. To force the client OS to request an IP from DHCP server again, you can
|
||||
use `dhclient` on Linux or `ipconfig /release` on Windows.
|
||||
1. Edit server configuration file `AdGuardHome.yaml`, for example:
|
||||
|
||||
### Configure server
|
||||
|
||||
1. Edit server configuration file `AdGuardHome.yaml`, for example:
|
||||
|
||||
```yaml
|
||||
dhcp:
|
||||
enabled: true
|
||||
interface_name: vboxnet0
|
||||
local_domain_name: lan
|
||||
dhcpv4:
|
||||
```yaml
|
||||
dhcp:
|
||||
enabled: true
|
||||
interface_name: vboxnet0
|
||||
local_domain_name: lan
|
||||
dhcpv4:
|
||||
gateway_ip: 192.168.56.1
|
||||
subnet_mask: 255.255.255.0
|
||||
range_start: 192.168.56.2
|
||||
@@ -63,34 +52,33 @@ To set up a test environment for DHCP server you will need:
|
||||
lease_duration: 86400
|
||||
icmp_timeout_msec: 1000
|
||||
options: []
|
||||
dhcpv6:
|
||||
dhcpv6:
|
||||
range_start: 2001::1
|
||||
lease_duration: 86400
|
||||
ra_slaac_only: false
|
||||
ra_allow_slaac: false
|
||||
```
|
||||
```
|
||||
|
||||
2. Start the server
|
||||
2. Start the server:
|
||||
|
||||
```sh
|
||||
./AdGuardHome -v
|
||||
```
|
||||
```sh
|
||||
./AdGuardHome -v
|
||||
```
|
||||
|
||||
There should be a message in log which shows that DHCP server is ready:
|
||||
There should be a message in log which shows that DHCP server is ready:
|
||||
|
||||
```
|
||||
[info] DHCP: listening on 0.0.0.0:67
|
||||
```
|
||||
```none
|
||||
[info] dhcpv4: listening
|
||||
```
|
||||
|
||||
## <a href="#dhcptest" id="dhcptest" name="dhcptest">Quick test with DHCPTest utility</a>
|
||||
## <a href="#dhcptest" id="dhcptest" name="dhcptest">Quick test with DHCPTest utility</a>
|
||||
|
||||
### Prerequisites
|
||||
### Prerequisites
|
||||
|
||||
* [DHCP test utility][dhcptest-gh].
|
||||
- [DHCP test utility][dhcptest-gh].
|
||||
|
||||
### Quick test
|
||||
### Quick test
|
||||
|
||||
The DHCP server could be tested for DISCOVER-OFFER packets with in
|
||||
interactive mode.
|
||||
The DHCP server could be tested for DISCOVER-OFFER packets with in interactive mode.
|
||||
|
||||
[dhcptest-gh]: https://github.com/CyberShadow/dhcptest
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
@@ -185,7 +186,7 @@ func writeDB(path string, leases []*dbLease) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
err = maybe.WriteFile(path, buf, 0o644)
|
||||
err = maybe.WriteFile(path, buf, aghos.DefaultPermFile)
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
|
||||
@@ -84,7 +84,7 @@ func parseDHCPOptionDur(s string) (val dhcpv4.OptionValue, err error) {
|
||||
return nil, fmt.Errorf("decoding dur: %w", err)
|
||||
}
|
||||
|
||||
return dhcpv4.Duration(v.Duration), nil
|
||||
return dhcpv4.Duration(v), nil
|
||||
}
|
||||
|
||||
// parseDHCPOptionUint parses a DHCP option as an unsigned integer. bitSize is
|
||||
|
||||
@@ -144,8 +144,8 @@ func TestParseOpt(t *testing.T) {
|
||||
in: "24 dur 3y",
|
||||
wantCode: nil,
|
||||
wantVal: nil,
|
||||
wantErrMsg: "invalid option string \"24 dur 3y\": decoding dur: " +
|
||||
"unmarshaling duration: time: unknown unit \"y\" in duration \"3y\"",
|
||||
wantErrMsg: `invalid option string "24 dur 3y": decoding dur: time: ` +
|
||||
`unknown unit "y" in duration "3y"`,
|
||||
}, {
|
||||
name: "u8_error",
|
||||
in: "23 u8 256",
|
||||
|
||||
@@ -18,9 +18,11 @@ import (
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/timeutil"
|
||||
"github.com/go-ping/ping"
|
||||
"github.com/insomniacslk/dhcp/dhcpv4"
|
||||
"github.com/insomniacslk/dhcp/dhcpv4/server4"
|
||||
|
||||
//lint:ignore SA1019 See the TODO in go.mod.
|
||||
"github.com/go-ping/ping"
|
||||
)
|
||||
|
||||
// v4Server is a DHCPv4 server.
|
||||
|
||||
@@ -3,11 +3,12 @@ package dhcpsvc
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"maps"
|
||||
"os"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/mapsutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
)
|
||||
|
||||
@@ -78,14 +79,13 @@ func (conf *Config) Validate() (err error) {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
mapsutil.SortedRange(conf.Interfaces, func(iface string, ic *InterfaceConfig) (ok bool) {
|
||||
for _, iface := range slices.Sorted(maps.Keys(conf.Interfaces)) {
|
||||
ic := conf.Interfaces[iface]
|
||||
err = ic.validate()
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("interface %q: %w", iface, err))
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ type Empty struct{}
|
||||
var _ agh.ServiceWithConfig[*Config] = Empty{}
|
||||
|
||||
// Start implements the [Service] interface for Empty.
|
||||
func (Empty) Start() (err error) { return nil }
|
||||
func (Empty) Start(_ context.Context) (err error) { return nil }
|
||||
|
||||
// Shutdown implements the [Service] interface for Empty.
|
||||
func (Empty) Shutdown(_ context.Context) (err error) { return nil }
|
||||
|
||||
@@ -4,14 +4,15 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"maps"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/mapsutil"
|
||||
)
|
||||
|
||||
// DHCPServer is a DHCP server for both IPv4 and IPv6 address families.
|
||||
@@ -107,7 +108,8 @@ func newInterfaces(
|
||||
v6 = make(dhcpInterfacesV6, 0, len(ifaces))
|
||||
|
||||
var errs []error
|
||||
mapsutil.SortedRange(ifaces, func(name string, iface *InterfaceConfig) (cont bool) {
|
||||
for _, name := range slices.Sorted(maps.Keys(ifaces)) {
|
||||
iface := ifaces[name]
|
||||
var i4 *dhcpInterfaceV4
|
||||
i4, err = newDHCPInterfaceV4(ctx, l, name, iface.IPv4)
|
||||
if err != nil {
|
||||
@@ -120,9 +122,8 @@ func newInterfaces(
|
||||
if i6 != nil {
|
||||
v6 = append(v6, i6)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
if err = errors.Join(errs...); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func (s *Server) clientIDFromDNSContext(pctx *proxy.DNSContext) (clientID string
|
||||
|
||||
cliSrvName, err := clientServerName(pctx, proto)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("getting client server-name: %w", err)
|
||||
}
|
||||
|
||||
clientID, err = clientIDFromClientServerName(
|
||||
|
||||
@@ -3,6 +3,7 @@ package dnsforward
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
@@ -118,17 +119,13 @@ func clientServerName(pctx *proxy.DNSContext, proto proxy.Proto) (srvName string
|
||||
|
||||
switch proto {
|
||||
case proxy.ProtoHTTPS:
|
||||
r := pctx.HTTPRequest
|
||||
if connState := r.TLS; connState != nil {
|
||||
srvName = connState.ServerName
|
||||
} else if r.Host != "" {
|
||||
var host string
|
||||
host, err = netutil.SplitHost(r.Host)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parsing host: %w", err)
|
||||
}
|
||||
var fromHost bool
|
||||
srvName, fromHost, err = clientServerNameFromHTTP(pctx.HTTPRequest)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("from http: %w", err)
|
||||
}
|
||||
|
||||
srvName = host
|
||||
if fromHost {
|
||||
from = "host header"
|
||||
}
|
||||
case proxy.ProtoQUIC:
|
||||
@@ -153,3 +150,23 @@ func clientServerName(pctx *proxy.DNSContext, proto proxy.Proto) (srvName string
|
||||
|
||||
return srvName, nil
|
||||
}
|
||||
|
||||
// clientServerNameFromHTTP returns the TLS server name or the value of the host
|
||||
// header depending on the protocol. fromHost is true if srvName comes from the
|
||||
// "Host" HTTP header.
|
||||
func clientServerNameFromHTTP(r *http.Request) (srvName string, fromHost bool, err error) {
|
||||
if connState := r.TLS; connState != nil {
|
||||
return connState.ServerName, false, nil
|
||||
}
|
||||
|
||||
if r.Host == "" {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
srvName, err = netutil.SplitHost(r.Host)
|
||||
if err != nil {
|
||||
return "", false, fmt.Errorf("parsing host: %w", err)
|
||||
}
|
||||
|
||||
return srvName, true, nil
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ func (s *Server) newProxyConfig() (conf *proxy.Config, err error) {
|
||||
conf.EDNSAddr = net.IP(srvConf.EDNSClientSubnet.CustomIP.AsSlice())
|
||||
}
|
||||
|
||||
err = setProxyUpstreamMode(conf, srvConf.UpstreamMode, srvConf.FastestTimeout.Duration)
|
||||
err = setProxyUpstreamMode(conf, srvConf.UpstreamMode, time.Duration(srvConf.FastestTimeout))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("upstream mode: %w", err)
|
||||
}
|
||||
|
||||
@@ -329,6 +329,14 @@ func (s *Server) AddrProcConfig() (c *client.DefaultAddrProcConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
// UpstreamTimeout returns the current upstream timeout configuration.
|
||||
func (s *Server) UpstreamTimeout() (t time.Duration) {
|
||||
s.serverLock.RLock()
|
||||
defer s.serverLock.RUnlock()
|
||||
|
||||
return s.conf.UpstreamTimeout
|
||||
}
|
||||
|
||||
// Resolve gets IP addresses by host name from an upstream server. No
|
||||
// request/response filtering is performed. Query log and Stats are not
|
||||
// updated. This method may be called before [Server.Start].
|
||||
@@ -740,7 +748,7 @@ func (s *Server) prepareInternalProxy() (err error) {
|
||||
MessageConstructor: s,
|
||||
}
|
||||
|
||||
err = setProxyUpstreamMode(conf, srvConf.UpstreamMode, srvConf.FastestTimeout.Duration)
|
||||
err = setProxyUpstreamMode(conf, srvConf.UpstreamMode, time.Duration(srvConf.FastestTimeout))
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid upstream mode: %w", err)
|
||||
}
|
||||
@@ -818,6 +826,8 @@ func (s *Server) proxy() (p *proxy.Proxy) {
|
||||
}
|
||||
|
||||
// Reconfigure applies the new configuration to the DNS server.
|
||||
//
|
||||
// TODO(a.garipov): This whole piece of API is weird and needs to be remade.
|
||||
func (s *Server) Reconfigure(conf *ServerConfig) error {
|
||||
s.serverLock.Lock()
|
||||
defer s.serverLock.Unlock()
|
||||
@@ -831,14 +841,15 @@ func (s *Server) Reconfigure(conf *ServerConfig) error {
|
||||
// We wait for some time and hope that this fd will be closed.
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// TODO(a.garipov): This whole piece of API is weird and needs to be remade.
|
||||
if s.addrProc != nil {
|
||||
err := s.addrProc.Close()
|
||||
if err != nil {
|
||||
log.Error("dnsforward: closing address processor: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if conf == nil {
|
||||
conf = &s.conf
|
||||
} else {
|
||||
closeErr := s.addrProc.Close()
|
||||
if closeErr != nil {
|
||||
log.Error("dnsforward: closing address processor: %s", closeErr)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(e.burkov): It seems an error here brings the server down, which is
|
||||
|
||||
@@ -500,6 +500,10 @@ func TestServerRace(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSafeSearch(t *testing.T) {
|
||||
const (
|
||||
googleSafeSearch = "forcesafesearch.google.com."
|
||||
)
|
||||
|
||||
safeSearchConf := filtering.SafeSearchConfig{
|
||||
Enabled: true,
|
||||
Google: true,
|
||||
@@ -513,12 +517,14 @@ func TestSafeSearch(t *testing.T) {
|
||||
SafeSearchCacheSize: 1000,
|
||||
CacheTime: 30,
|
||||
}
|
||||
safeSearch, err := safesearch.NewDefault(
|
||||
safeSearchConf,
|
||||
"",
|
||||
filterConf.SafeSearchCacheSize,
|
||||
time.Minute*time.Duration(filterConf.CacheTime),
|
||||
)
|
||||
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
safeSearch, err := safesearch.NewDefault(ctx, &safesearch.DefaultConfig{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
ServicesConfig: safeSearchConf,
|
||||
CacheSize: filterConf.SafeSearchCacheSize,
|
||||
CacheTTL: time.Minute * time.Duration(filterConf.CacheTime),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
filterConf.SafeSearch = safeSearch
|
||||
@@ -534,10 +540,17 @@ func TestSafeSearch(t *testing.T) {
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
s := createTestServer(t, filterConf, forwardConf)
|
||||
startDeferStop(t, s)
|
||||
|
||||
ups := aghtest.NewUpstreamMock(func(req *dns.Msg) (resp *dns.Msg, err error) {
|
||||
pt := testutil.PanicT{}
|
||||
assert.Equal(pt, googleSafeSearch, req.Question[0].Name)
|
||||
|
||||
return aghtest.MatchedResponse(req, dns.TypeA, googleSafeSearch, "1.2.3.4"), nil
|
||||
})
|
||||
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ups}
|
||||
|
||||
startDeferStop(t, s)
|
||||
addr := s.dnsProxy.Addr(proxy.ProtoUDP).String()
|
||||
client := &dns.Client{}
|
||||
|
||||
yandexIP := netip.AddrFrom4([4]byte{213, 180, 193, 56})
|
||||
|
||||
@@ -584,8 +597,8 @@ func TestSafeSearch(t *testing.T) {
|
||||
req := createTestMessage(tc.host)
|
||||
|
||||
var reply *dns.Msg
|
||||
reply, _, err = client.Exchange(req, addr)
|
||||
require.NoErrorf(t, err, "couldn't talk to server %s: %s", addr, err)
|
||||
reply, err = dns.Exchange(req, addr)
|
||||
require.NoError(t, err)
|
||||
|
||||
if tc.wantCNAME != "" {
|
||||
require.Len(t, reply.Answer, 2)
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/stringutil"
|
||||
"github.com/AdguardTeam/golibs/validate"
|
||||
)
|
||||
|
||||
// jsonDNSConfig is the JSON representation of the DNS server configuration.
|
||||
@@ -53,6 +54,9 @@ type jsonDNSConfig struct {
|
||||
// rate limiting requests.
|
||||
RatelimitSubnetLenIPv6 *int `json:"ratelimit_subnet_len_ipv6"`
|
||||
|
||||
// UpstreamTimeout is an upstream timeout in seconds.
|
||||
UpstreamTimeout *int `json:"upstream_timeout"`
|
||||
|
||||
// RatelimitWhitelist is a list of IP addresses excluded from rate limiting.
|
||||
RatelimitWhitelist *[]netip.Addr `json:"ratelimit_whitelist"`
|
||||
|
||||
@@ -147,6 +151,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
|
||||
ratelimitSubnetLenIPv4 := s.conf.RatelimitSubnetLenIPv4
|
||||
ratelimitSubnetLenIPv6 := s.conf.RatelimitSubnetLenIPv6
|
||||
ratelimitWhitelist := append([]netip.Addr{}, s.conf.RatelimitWhitelist...)
|
||||
upstreamTimeout := int(s.conf.UpstreamTimeout.Seconds())
|
||||
|
||||
customIP := s.conf.EDNSClientSubnet.CustomIP
|
||||
enableEDNSClientSubnet := s.conf.EDNSClientSubnet.Enabled
|
||||
@@ -192,6 +197,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
|
||||
RatelimitSubnetLenIPv4: &ratelimitSubnetLenIPv4,
|
||||
RatelimitSubnetLenIPv6: &ratelimitSubnetLenIPv6,
|
||||
RatelimitWhitelist: &ratelimitWhitelist,
|
||||
UpstreamTimeout: &upstreamTimeout,
|
||||
EDNSCSCustomIP: customIP,
|
||||
EDNSCSEnabled: &enableEDNSClientSubnet,
|
||||
EDNSCSUseCustom: &useCustom,
|
||||
@@ -302,6 +308,12 @@ func (req *jsonDNSConfig) validate(
|
||||
return err
|
||||
}
|
||||
|
||||
err = req.checkUpstreamTimeout()
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -437,6 +449,16 @@ func (req *jsonDNSConfig) checkRatelimitSubnetMaskLen() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkUpstreamTimeout returns an error if the configuration of the upstream
|
||||
// timeout is invalid.
|
||||
func (req *jsonDNSConfig) checkUpstreamTimeout() (err error) {
|
||||
if req.UpstreamTimeout == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return validate.NoLessThan("upstream_timeout", *req.UpstreamTimeout, 1)
|
||||
}
|
||||
|
||||
// checkInclusion returns an error if a ptr is not nil and points to value,
|
||||
// that not in the inclusive range between minN and maxN.
|
||||
func checkInclusion(ptr *int, minN, maxN int) (err error) {
|
||||
@@ -588,6 +610,14 @@ func (s *Server) setConfigRestartable(dc *jsonDNSConfig) (shouldRestart bool) {
|
||||
shouldRestart = true
|
||||
}
|
||||
|
||||
if dc.UpstreamTimeout != nil {
|
||||
ut := time.Duration(*dc.UpstreamTimeout) * time.Second
|
||||
if s.conf.UpstreamTimeout != ut {
|
||||
s.conf.UpstreamTimeout = ut
|
||||
shouldRestart = true
|
||||
}
|
||||
}
|
||||
|
||||
return shouldRestart
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package dnsforward
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"net/netip"
|
||||
@@ -203,7 +204,8 @@ func (s *Server) processClientIP(addr netip.Addr) {
|
||||
s.serverLock.RLock()
|
||||
defer s.serverLock.RUnlock()
|
||||
|
||||
s.addrProc.Process(addr)
|
||||
// TODO(s.chzhen): Pass context.
|
||||
s.addrProc.Process(context.TODO(), addr)
|
||||
}
|
||||
|
||||
// processDDRQuery responds to Discovery of Designated Resolvers (DDR) SVCB
|
||||
|
||||
@@ -2,6 +2,7 @@ package dnsforward
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
@@ -90,7 +91,7 @@ func TestServer_ProcessInitial(t *testing.T) {
|
||||
|
||||
var gotAddr netip.Addr
|
||||
s.addrProc = &aghtest.AddressProcessor{
|
||||
OnProcess: func(ip netip.Addr) { gotAddr = ip },
|
||||
OnProcess: func(ctx context.Context, ip netip.Addr) { gotAddr = ip },
|
||||
OnClose: func() (err error) { panic("not implemented") },
|
||||
}
|
||||
|
||||
|
||||
@@ -122,9 +122,14 @@ func (s *Server) logQuery(dctx *dnsContext, ip net.IP, processingTime time.Durat
|
||||
|
||||
if pctx.Upstream != nil {
|
||||
p.Upstream = pctx.Upstream.Address()
|
||||
} else if cachedUps := pctx.CachedUpstreamAddr; cachedUps != "" {
|
||||
p.Upstream = pctx.CachedUpstreamAddr
|
||||
p.Cached = true
|
||||
}
|
||||
|
||||
if qs := pctx.QueryStatistics(); qs != nil {
|
||||
ms := qs.Main()
|
||||
if len(ms) == 1 && ms[0].IsCached {
|
||||
p.Upstream = ms[0].Address
|
||||
p.Cached = true
|
||||
}
|
||||
}
|
||||
|
||||
s.queryLog.Add(p)
|
||||
@@ -134,15 +139,18 @@ func (s *Server) logQuery(dctx *dnsContext, ip net.IP, processingTime time.Durat
|
||||
func (s *Server) updateStats(dctx *dnsContext, clientIP string, processingTime time.Duration) {
|
||||
pctx := dctx.proxyCtx
|
||||
|
||||
var upstreamStats []*proxy.UpstreamStatistics
|
||||
qs := pctx.QueryStatistics()
|
||||
if qs != nil {
|
||||
upstreamStats = append(upstreamStats, qs.Main()...)
|
||||
upstreamStats = append(upstreamStats, qs.Fallback()...)
|
||||
}
|
||||
|
||||
e := &stats.Entry{
|
||||
UpstreamStats: upstreamStats,
|
||||
Domain: aghnet.NormalizeDomain(pctx.Req.Question[0].Name),
|
||||
Result: stats.RNotFiltered,
|
||||
ProcessingTime: processingTime,
|
||||
UpstreamTime: pctx.QueryDuration,
|
||||
}
|
||||
|
||||
if pctx.Upstream != nil {
|
||||
e.Upstream = pctx.Upstream.Address()
|
||||
}
|
||||
|
||||
if clientID := dctx.clientID; clientID != "" {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -63,6 +64,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -102,6 +104,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -70,6 +71,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -112,6 +114,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -154,6 +157,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -196,6 +200,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -240,6 +245,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -285,6 +291,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -327,6 +334,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": true,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -371,6 +379,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": true,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -415,6 +424,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -457,6 +467,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": true,
|
||||
"disable_ipv6": false,
|
||||
@@ -499,6 +510,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -541,6 +553,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -583,6 +596,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -627,6 +641,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -671,6 +686,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -714,6 +730,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -756,6 +773,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -800,6 +818,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -847,6 +866,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -889,6 +909,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -935,6 +956,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -977,6 +999,7 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 11,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
@@ -1022,6 +1045,50 @@
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"cache_optimistic": false,
|
||||
"resolve_clients": false,
|
||||
"use_private_ptr_resolvers": false,
|
||||
"local_ptr_upstreams": [],
|
||||
"edns_cs_use_custom": false,
|
||||
"edns_cs_custom_ip": ""
|
||||
}
|
||||
},
|
||||
"upstream_timeout": {
|
||||
"req": {
|
||||
"upstream_timeout": 11
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"fallback_dns": [],
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"upstream_timeout": 11,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
# AdGuard Home's DNS filtering go library
|
||||
|
||||
Example use:
|
||||
```bash
|
||||
[ -z "$GOPATH" ] && export GOPATH=$HOME/go
|
||||
go get -d github.com/AdguardTeam/AdGuardHome/filtering
|
||||
```
|
||||
|
||||
Create file filter.go
|
||||
```filter.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/AdguardTeam/AdGuardHome/filtering"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
filter := filtering.New()
|
||||
filter.AddRule("||dou*ck.net^")
|
||||
host := "www.doubleclick.net"
|
||||
res, err := filter.CheckHost(host)
|
||||
if err != nil {
|
||||
// temporary failure
|
||||
log.Fatalf("Failed to check host %q: %s", host, err)
|
||||
}
|
||||
if res.IsFiltered {
|
||||
log.Printf("Host %s is filtered, reason - %q, matched rule: %q", host, res.Reason, res.Rule)
|
||||
} else {
|
||||
log.Printf("Host %s is not filtered, reason - %q", host, res.Reason)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And then run it:
|
||||
```bash
|
||||
go run filter.go
|
||||
```
|
||||
|
||||
You will get:
|
||||
```
|
||||
2000/01/01 00:00:00 Host www.doubleclick.net is filtered, reason - 'FilteredBlackList', matched rule: '||dou*ck.net^'
|
||||
```
|
||||
|
||||
You can also enable checking against AdGuard's SafeBrowsing:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/AdguardTeam/AdGuardHome/filtering"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
filter := filtering.New()
|
||||
filter.EnableSafeBrowsing()
|
||||
host := "wmconvirus.narod.ru" // hostname for testing safebrowsing
|
||||
res, err := filter.CheckHost(host)
|
||||
if err != nil {
|
||||
// temporary failure
|
||||
log.Fatalf("Failed to check host %q: %s", host, err)
|
||||
}
|
||||
if res.IsFiltered {
|
||||
log.Printf("Host %s is filtered, reason - %q, matched rule: %q", host, res.Reason, res.Rule)
|
||||
} else {
|
||||
log.Printf("Host %s is not filtered, reason - %q", host, res.Reason)
|
||||
}
|
||||
}
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user