mirror of
https://git.vectorsigma.ru/public/AdGuardHome.git
synced 2026-08-03 19:29:41 +00:00
all: sync with master
This commit is contained in:
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
'name': 'build'
|
'name': 'build'
|
||||||
|
|
||||||
'env':
|
'env':
|
||||||
'GO_VERSION': '1.24.3'
|
'GO_VERSION': '1.24.4'
|
||||||
'NODE_VERSION': '20'
|
'NODE_VERSION': '20'
|
||||||
|
|
||||||
'on':
|
'on':
|
||||||
|
|||||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
'name': 'lint'
|
'name': 'lint'
|
||||||
|
|
||||||
'env':
|
'env':
|
||||||
'GO_VERSION': '1.24.3'
|
'GO_VERSION': '1.24.4'
|
||||||
|
|
||||||
'on':
|
'on':
|
||||||
'push':
|
'push':
|
||||||
|
|||||||
36
CHANGELOG.md
36
CHANGELOG.md
@@ -9,11 +9,11 @@ The format is based on [*Keep a Changelog*](https://keepachangelog.com/en/1.0.0/
|
|||||||
<!--
|
<!--
|
||||||
## [v0.108.0] – TBA
|
## [v0.108.0] – TBA
|
||||||
|
|
||||||
## [v0.107.63] - 2025-06-15 (APPROX.)
|
## [v0.107.64] - 2025-06-15 (APPROX.)
|
||||||
|
|
||||||
See also the [v0.107.63 GitHub milestone][ms-v0.107.63].
|
See also the [v0.107.64 GitHub milestone][ms-v0.107.64].
|
||||||
|
|
||||||
[ms-v0.107.63]: https://github.com/AdguardTeam/AdGuardHome/milestone/98?closed=1
|
[ms-v0.107.64]: https://github.com/AdguardTeam/AdGuardHome/milestone/99?closed=1
|
||||||
|
|
||||||
NOTE: Add new changes BELOW THIS COMMENT.
|
NOTE: Add new changes BELOW THIS COMMENT.
|
||||||
-->
|
-->
|
||||||
@@ -21,6 +21,23 @@ NOTE: Add new changes BELOW THIS COMMENT.
|
|||||||
NOTE: Add new changes ABOVE THIS COMMENT.
|
NOTE: Add new changes ABOVE THIS COMMENT.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## [v0.107.63] - 2025-06-19
|
||||||
|
|
||||||
|
See also the [v0.107.63 GitHub milestone][ms-v0.107.63].
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Go version has been updated to prevent the possibility of exploiting the Go vulnerabilities fixed in [1.24.4][go-1.24.4].
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- The hostnames of DHCP clients with multiple labels not being recognized.
|
||||||
|
|
||||||
|
- Status reported by the systemd service implementation in cases of auto-restart after a failed start.
|
||||||
|
|
||||||
|
[go-1.24.4]: https://groups.google.com/g/golang-announce/c/ufZ8WpEsA3A
|
||||||
|
[ms-v0.107.63]: https://github.com/AdguardTeam/AdGuardHome/milestone/98?closed=1
|
||||||
|
|
||||||
## [v0.107.62] - 2025-05-27
|
## [v0.107.62] - 2025-05-27
|
||||||
|
|
||||||
See also the [v0.107.62 GitHub milestone][ms-v0.107.62].
|
See also the [v0.107.62 GitHub milestone][ms-v0.107.62].
|
||||||
@@ -39,6 +56,8 @@ See also the [v0.107.62 GitHub milestone][ms-v0.107.62].
|
|||||||
|
|
||||||
- Validation process for the DNS-over-TLS, DNS-over-QUIC, and HTTPS ports on the *Encryption Settings* page.
|
- Validation process for the DNS-over-TLS, DNS-over-QUIC, and HTTPS ports on the *Encryption Settings* page.
|
||||||
|
|
||||||
|
- Searching for persistent clients using an exact match for CIDR in the `POST /clients/search` HTTP API.
|
||||||
|
|
||||||
[#2945]: https://github.com/AdguardTeam/AdGuardHome/issues/2945
|
[#2945]: https://github.com/AdguardTeam/AdGuardHome/issues/2945
|
||||||
[#7801]: https://github.com/AdguardTeam/AdGuardHome/issues/7801
|
[#7801]: https://github.com/AdguardTeam/AdGuardHome/issues/7801
|
||||||
|
|
||||||
@@ -55,10 +74,6 @@ See also the [v0.107.61 GitHub milestone][ms-v0.107.61].
|
|||||||
|
|
||||||
**NOTE:** We thank [Xiang Li][mr-xiang-li] for reporting this security issue. It's strongly recommended to leave it enabled, otherwise AdGuard Home will be vulnerable to untrusted clients.
|
**NOTE:** We thank [Xiang Li][mr-xiang-li] for reporting this security issue. It's strongly recommended to leave it enabled, otherwise AdGuard Home will be vulnerable to untrusted clients.
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Searching for persistent clients using an exact match for CIDR in the `POST /clients/search HTTP API`.
|
|
||||||
|
|
||||||
[mr-xiang-li]: https://lixiang521.com/
|
[mr-xiang-li]: https://lixiang521.com/
|
||||||
[ms-v0.107.61]: https://github.com/AdguardTeam/AdGuardHome/milestone/96?closed=1
|
[ms-v0.107.61]: https://github.com/AdguardTeam/AdGuardHome/milestone/96?closed=1
|
||||||
|
|
||||||
@@ -3143,11 +3158,12 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
|
|||||||
[ms-v0.104.2]: https://github.com/AdguardTeam/AdGuardHome/milestone/28?closed=1
|
[ms-v0.104.2]: https://github.com/AdguardTeam/AdGuardHome/milestone/28?closed=1
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.63...HEAD
|
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.64...HEAD
|
||||||
[v0.107.63]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.62...v0.107.63
|
[v0.107.64]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.63...v0.107.64
|
||||||
-->
|
-->
|
||||||
|
|
||||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.62...HEAD
|
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.63...HEAD
|
||||||
|
[v0.107.63]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.62...v0.107.63
|
||||||
[v0.107.62]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.61...v0.107.62
|
[v0.107.62]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.61...v0.107.62
|
||||||
[v0.107.61]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.60...v0.107.61
|
[v0.107.61]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.60...v0.107.61
|
||||||
[v0.107.60]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.59...v0.107.60
|
[v0.107.60]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.59...v0.107.60
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -27,7 +27,7 @@ DIST_DIR = dist
|
|||||||
GOAMD64 = v1
|
GOAMD64 = v1
|
||||||
GOPROXY = https://proxy.golang.org|direct
|
GOPROXY = https://proxy.golang.org|direct
|
||||||
GOTELEMETRY = off
|
GOTELEMETRY = off
|
||||||
GOTOOLCHAIN = go1.24.3
|
GOTOOLCHAIN = go1.24.4
|
||||||
GPG_KEY = devteam@adguard.com
|
GPG_KEY = devteam@adguard.com
|
||||||
GPG_KEY_PASSPHRASE = not-a-real-password
|
GPG_KEY_PASSPHRASE = not-a-real-password
|
||||||
NPM = npm
|
NPM = npm
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
'variables':
|
'variables':
|
||||||
'channel': 'edge'
|
'channel': 'edge'
|
||||||
'dockerFrontend': 'adguard/home-js-builder:3.1'
|
'dockerFrontend': 'adguard/home-js-builder:3.1'
|
||||||
'dockerGo': 'adguard/go-builder:1.24.3--1'
|
'dockerGo': 'adguard/go-builder:1.24.4--1'
|
||||||
|
|
||||||
'stages':
|
'stages':
|
||||||
- 'Build frontend':
|
- 'Build frontend':
|
||||||
@@ -279,7 +279,7 @@
|
|||||||
'variables':
|
'variables':
|
||||||
'channel': 'beta'
|
'channel': 'beta'
|
||||||
'dockerFrontend': 'adguard/home-js-builder:3.1'
|
'dockerFrontend': 'adguard/home-js-builder:3.1'
|
||||||
'dockerGo': 'adguard/go-builder:1.24.3--1'
|
'dockerGo': 'adguard/go-builder:1.24.4--1'
|
||||||
# release-vX.Y.Z branches are the branches from which the actual final
|
# release-vX.Y.Z branches are the branches from which the actual final
|
||||||
# release is built.
|
# release is built.
|
||||||
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
||||||
@@ -295,4 +295,4 @@
|
|||||||
'variables':
|
'variables':
|
||||||
'channel': 'release'
|
'channel': 'release'
|
||||||
'dockerFrontend': 'adguard/home-js-builder:3.1'
|
'dockerFrontend': 'adguard/home-js-builder:3.1'
|
||||||
'dockerGo': 'adguard/go-builder:1.24.3--1'
|
'dockerGo': 'adguard/go-builder:1.24.4--1'
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
'name': 'AdGuard Home - Build and run tests'
|
'name': 'AdGuard Home - Build and run tests'
|
||||||
'variables':
|
'variables':
|
||||||
'dockerFrontend': 'adguard/home-js-builder:3.1'
|
'dockerFrontend': 'adguard/home-js-builder:3.1'
|
||||||
'dockerGo': 'adguard/go-builder:1.24.3--1'
|
'dockerGo': 'adguard/go-builder:1.24.4--1'
|
||||||
'channel': 'development'
|
'channel': 'development'
|
||||||
|
|
||||||
'stages':
|
'stages':
|
||||||
@@ -234,5 +234,5 @@
|
|||||||
# may need to build a few of these.
|
# may need to build a few of these.
|
||||||
'variables':
|
'variables':
|
||||||
'dockerFrontend': 'adguard/home-js-builder:3.1'
|
'dockerFrontend': 'adguard/home-js-builder:3.1'
|
||||||
'dockerGo': 'adguard/go-builder:1.24.3--1'
|
'dockerGo': 'adguard/go-builder:1.24.4--1'
|
||||||
'channel': 'candidate'
|
'channel': 'candidate'
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
"subnet_error": "Адрасы павінны быць усярэдзіне адной падсеткі",
|
"subnet_error": "Адрасы павінны быць усярэдзіне адной падсеткі",
|
||||||
"gateway_or_subnet_invalid": "Некарэктная маска падсеткі",
|
"gateway_or_subnet_invalid": "Некарэктная маска падсеткі",
|
||||||
"dhcp_form_gateway_input": "IP-адрас шлюза",
|
"dhcp_form_gateway_input": "IP-адрас шлюза",
|
||||||
"dhcp_form_subnet_input": "Маска падсеціва",
|
"dhcp_form_subnet_input": "Маска падсеткі",
|
||||||
"dhcp_form_range_title": "Дыяпазон IP-адрасоў",
|
"dhcp_form_range_title": "Дыяпазон IP-адрасоў",
|
||||||
"dhcp_form_range_start": "Пачатак дыяпазону",
|
"dhcp_form_range_start": "Пачатак дыяпазону",
|
||||||
"dhcp_form_range_end": "Конец диапазона",
|
"dhcp_form_range_end": "Конец диапазона",
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
"query_log": "Часопіс",
|
"query_log": "Часопіс",
|
||||||
"compact": "Компактный",
|
"compact": "Компактный",
|
||||||
"nothing_found": "Нічога не знойдзена",
|
"nothing_found": "Нічога не знойдзена",
|
||||||
"faq": "FAQ",
|
"faq": "Частыя пытанні",
|
||||||
"version": "Версія",
|
"version": "Версія",
|
||||||
"address": "Адрас",
|
"address": "Адрас",
|
||||||
"protocol": "Пратакол",
|
"protocol": "Пратакол",
|
||||||
@@ -283,7 +283,7 @@
|
|||||||
"dns_config": "Налады сервер DNSа",
|
"dns_config": "Налады сервер DNSа",
|
||||||
"dns_cache_config": "Налада кэша DNS",
|
"dns_cache_config": "Налада кэша DNS",
|
||||||
"dns_cache_config_desc": "Тут можна наладзіць кэш DNS",
|
"dns_cache_config_desc": "Тут можна наладзіць кэш DNS",
|
||||||
"blocking_mode": "Рэжым блакавання",
|
"blocking_mode": "Рэжым блакіроўкі",
|
||||||
"default": "Стандартны",
|
"default": "Стандартны",
|
||||||
"nxdomain": "NXDOMAIN",
|
"nxdomain": "NXDOMAIN",
|
||||||
"refused": "REFUSED",
|
"refused": "REFUSED",
|
||||||
@@ -294,6 +294,8 @@
|
|||||||
"blocked_response_ttl": "TTL заблакаванага адказу",
|
"blocked_response_ttl": "TTL заблакаванага адказу",
|
||||||
"blocked_response_ttl_desc": "Паказвае, на працягу колькіх секунд кліенты павінны кэшаваць адфільтраваць адказ",
|
"blocked_response_ttl_desc": "Паказвае, на працягу колькіх секунд кліенты павінны кэшаваць адфільтраваць адказ",
|
||||||
"form_enter_blocked_response_ttl": "Увядзіце TTL заблакіраванага адказу (у секундах)",
|
"form_enter_blocked_response_ttl": "Увядзіце TTL заблакіраванага адказу (у секундах)",
|
||||||
|
"upstream_timeout": "Час чакання для upstream.",
|
||||||
|
"form_enter_upstream_timeout": "Увядзіце працягласць часу чакання сервера upstream у секундах.",
|
||||||
"dnscrypt": "DNSCrypt",
|
"dnscrypt": "DNSCrypt",
|
||||||
"dns_over_https": "DNS-over-HTTPS",
|
"dns_over_https": "DNS-over-HTTPS",
|
||||||
"dns_over_tls": "DNS-over-TLS",
|
"dns_over_tls": "DNS-over-TLS",
|
||||||
@@ -344,7 +346,7 @@
|
|||||||
"install_welcome_title": "Сардэчна запрашаем у AdGuard Home!",
|
"install_welcome_title": "Сардэчна запрашаем у AdGuard Home!",
|
||||||
"install_welcome_desc": "AdGuard Home – гэта сервер DNS, што блакуе рэкламу і трэкінг. Яго мэта – даць вам магчымасць кантраляваць усю ваша сеціва і ўсе падлучаныя прылады. Ён не патрабуе ўсталёўкі кліенцкіх праграм.",
|
"install_welcome_desc": "AdGuard Home – гэта сервер DNS, што блакуе рэкламу і трэкінг. Яго мэта – даць вам магчымасць кантраляваць усю ваша сеціва і ўсе падлучаныя прылады. Ён не патрабуе ўсталёўкі кліенцкіх праграм.",
|
||||||
"install_settings_title": "Ўэб-інтэрфейс адміністравання",
|
"install_settings_title": "Ўэб-інтэрфейс адміністравання",
|
||||||
"install_settings_listen": "Інтэрфейс сеціва",
|
"install_settings_listen": "Сеткавы інтэрфейс",
|
||||||
"install_settings_port": "Порт",
|
"install_settings_port": "Порт",
|
||||||
"install_settings_interface_link": "Ваш ўэб-інтэрфейс адміністравання AdGuard Home будзе даступны па наступных адрасах:",
|
"install_settings_interface_link": "Ваш ўэб-інтэрфейс адміністравання AdGuard Home будзе даступны па наступных адрасах:",
|
||||||
"form_error_port": "Увядзіце карэктны нумар порта",
|
"form_error_port": "Увядзіце карэктны нумар порта",
|
||||||
@@ -396,7 +398,7 @@
|
|||||||
"encryption_title": "Шыфраванне",
|
"encryption_title": "Шыфраванне",
|
||||||
"encryption_desc": "Падтрымка шыфравання (HTTPS/QUIC/TLS) для DNS і ўэб-інтэрфейсу адміністравання",
|
"encryption_desc": "Падтрымка шыфравання (HTTPS/QUIC/TLS) для DNS і ўэб-інтэрфейсу адміністравання",
|
||||||
"encryption_config_saved": "Налады шыфравання захаваны",
|
"encryption_config_saved": "Налады шыфравання захаваны",
|
||||||
"encryption_server": "Імя сервера",
|
"encryption_server": "Назва сервера",
|
||||||
"encryption_server_enter": "Увядзіце ваша даменавае імя",
|
"encryption_server_enter": "Увядзіце ваша даменавае імя",
|
||||||
"encryption_server_desc": "Калі ўстаноўлена, AdGuard Home вызначае ClientID, адказвае на запыты DDR і выконвае дадатковыя праверкі злучэння. Калі не ўстаноўлена, гэтыя функцыі адключаны. Павінна адпавядаць аднаму з імёнаў DNS у сертыфікаце.",
|
"encryption_server_desc": "Калі ўстаноўлена, AdGuard Home вызначае ClientID, адказвае на запыты DDR і выконвае дадатковыя праверкі злучэння. Калі не ўстаноўлена, гэтыя функцыі адключаны. Павінна адпавядаць аднаму з імёнаў DNS у сертыфікаце.",
|
||||||
"encryption_redirect": "Аўтаматычна перанакіроўваць на HTTPS",
|
"encryption_redirect": "Аўтаматычна перанакіроўваць на HTTPS",
|
||||||
@@ -425,6 +427,7 @@
|
|||||||
"encryption_hostnames": "Імёны хастоў",
|
"encryption_hostnames": "Імёны хастоў",
|
||||||
"encryption_reset": "Вы ўпэўнены, што хочаце скінуць налады шыфравання?",
|
"encryption_reset": "Вы ўпэўнены, што хочаце скінуць налады шыфравання?",
|
||||||
"encryption_warning": "Папярэджанне",
|
"encryption_warning": "Папярэджанне",
|
||||||
|
"encryption_plain_dns_enable": "Уключыць звычайны DNS",
|
||||||
"topline_expiring_certificate": "Ваш SSL-сертыфікат хутка мінае. Абновіце <0>Налады шыфравання</0>.",
|
"topline_expiring_certificate": "Ваш SSL-сертыфікат хутка мінае. Абновіце <0>Налады шыфравання</0>.",
|
||||||
"topline_expired_certificate": "Ваш SSL-сертыфікат мінуў. Абновіце <0>Налады шыфравання</0>.",
|
"topline_expired_certificate": "Ваш SSL-сертыфікат мінуў. Абновіце <0>Налады шыфравання</0>.",
|
||||||
"form_error_port_range": "Увядзіце нумар порта з інтэрвалу 80-65535",
|
"form_error_port_range": "Увядзіце нумар порта з інтэрвалу 80-65535",
|
||||||
@@ -520,7 +523,7 @@
|
|||||||
"form_answer": "Увядзіце IP адрас ці дамен",
|
"form_answer": "Увядзіце IP адрас ці дамен",
|
||||||
"form_error_domain_format": "Няслушны фармат дамена",
|
"form_error_domain_format": "Няслушны фармат дамена",
|
||||||
"form_error_answer_format": "Няслушны фармат адказу",
|
"form_error_answer_format": "Няслушны фармат адказу",
|
||||||
"configure": "Наладзіць",
|
"configure": "Сканфігурыраваць",
|
||||||
"main_settings": "Асноўныя налады",
|
"main_settings": "Асноўныя налады",
|
||||||
"block_services": "Выбраць заблакаваныя сэрвісы",
|
"block_services": "Выбраць заблакаваныя сэрвісы",
|
||||||
"blocked_services": "Заблакаваныя сэрвісы",
|
"blocked_services": "Заблакаваныя сэрвісы",
|
||||||
@@ -615,6 +618,8 @@
|
|||||||
"check_reason": "Прычына: {{reason}}",
|
"check_reason": "Прычына: {{reason}}",
|
||||||
"check_service": "Назва сэрвісу: {{service}}",
|
"check_service": "Назва сэрвісу: {{service}}",
|
||||||
"service_name": "Назва сэрвіса",
|
"service_name": "Назва сэрвіса",
|
||||||
|
"check_client_id": "Ідэнтыфікатар кліента (ClientID або IP-адрас)",
|
||||||
|
"check_enter_client_id": "Увядзіце ідэнтыфікатар кліента",
|
||||||
"check_not_found": "Не знойдзена ў вашым спісе фільтраў",
|
"check_not_found": "Не знойдзена ў вашым спісе фільтраў",
|
||||||
"client_confirm_block": "Вы ўпэўнены, што хочаце заблакаваць кліента «{{ip}}»?",
|
"client_confirm_block": "Вы ўпэўнены, што хочаце заблакаваць кліента «{{ip}}»?",
|
||||||
"client_confirm_unblock": "Вы ўпэўнены, што хочаце адблакаваць кліента «{{ip}}»?",
|
"client_confirm_unblock": "Вы ўпэўнены, што хочаце адблакаваць кліента «{{ip}}»?",
|
||||||
@@ -702,7 +707,7 @@
|
|||||||
"enable_protection_timer": "Абарона будзе ўключана ў {{time}}",
|
"enable_protection_timer": "Абарона будзе ўключана ў {{time}}",
|
||||||
"custom_retention_input": "Увядзіце тэрмін захоўвання ў гадзінах",
|
"custom_retention_input": "Увядзіце тэрмін захоўвання ў гадзінах",
|
||||||
"custom_rotation_input": "Увядзіце частату ратацыі ў гадзінах",
|
"custom_rotation_input": "Увядзіце частату ратацыі ў гадзінах",
|
||||||
"protection_section_label": "Ахова",
|
"protection_section_label": "Абарона",
|
||||||
"log_and_stats_section_label": "Журнал запытаў і статыстыка",
|
"log_and_stats_section_label": "Журнал запытаў і статыстыка",
|
||||||
"ignore_query_log": "Ігнараваць гэтага кліента ў журнале запытаў",
|
"ignore_query_log": "Ігнараваць гэтага кліента ў журнале запытаў",
|
||||||
"ignore_statistics": "Ігнараваць гэтага кліента ў статыстыцы",
|
"ignore_statistics": "Ігнараваць гэтага кліента ў статыстыцы",
|
||||||
|
|||||||
@@ -1,11 +1,32 @@
|
|||||||
{
|
{
|
||||||
"client_settings": "Kлиентски настройки",
|
"client_settings": "Kлиентски настройки",
|
||||||
|
"example_upstream_reserved": "upstream <0>за специфични домейни</0>;",
|
||||||
|
"example_multiple_upstreams_reserved": "множество upstreams <0>за специфични домейни</0>;",
|
||||||
"example_upstream_comment": "Можете да поставите коментар",
|
"example_upstream_comment": "Можете да поставите коментар",
|
||||||
|
"upstream_parallel": "Използване на паралелни заявки за ускоряване на разрешаването на домейни чрез едновременно запитване към всички сървъри нагоре по веригата.",
|
||||||
|
"parallel_requests": "Паралелни заявки",
|
||||||
"load_balancing": "Балансиране на натоварването",
|
"load_balancing": "Балансиране на натоварването",
|
||||||
|
"load_balancing_desc": "Запитвайте по един сървър нагоре по веригата наведнъж.<br/>AdGuard Home използва тежестен произволен алгоритъм за избор на сървъри с най-малък брой неуспешни заявки и най-ниско средно време за запитване.",
|
||||||
|
"bootstrap_dns": "Bootstrap DNS сървъри",
|
||||||
|
"bootstrap_dns_desc": "IP адреси на DNS сървърите, използвани за разрешаване на IP адресите на DoH/DoT разпознавателите, които определяте като нагоре по веригата. Коментарите не са разрешени.",
|
||||||
|
"fallback_dns_title": "Резервни DNS сървъри",
|
||||||
|
"fallback_dns_desc": "Списък на резервни DNS сървъри, използвани, когато основните DNS сървъри не отговарят. Синтаксисът е същият, както в основното поле за upstream.",
|
||||||
|
"fallback_dns_placeholder": "Въведете по един резервен DNS сервер на ред",
|
||||||
|
"local_ptr_title": "Частни обратни DNS сървъри",
|
||||||
|
"local_ptr_desc": "Сървърите на DNS, използвани от AdGuard Home за частни запроси PTR, SOA и NS. Запитване се счита за частно, ако иска домейн ARPA, съдържащ подмрежа в рамките на частни IP диапазони (като \"192.168.12.34\") и идва от клиент с частен IP адрес. Ако не е зададено, ще се използват стандартните DNS резолвари на вашата ОС, с изключение на IP адресите на AdGuard Home.",
|
||||||
|
"local_ptr_default_resolver": "По подразбиране AdGuard Home използва следните обратни DNS резолвери: {{ip}}.",
|
||||||
|
"local_ptr_no_default_resolver": "AdGuard Home не можа да определи подходящи частни обратни DNS резолвери за тази система.",
|
||||||
|
"local_ptr_placeholder": "Въведете по един IP адрес на ред",
|
||||||
|
"resolve_clients_title": "Активиране на обратното разрешаване на IP адресите на клиентите",
|
||||||
|
"resolve_clients_desc": "Обратно разрешаване на IP адресите на клиентите в техните имена на хостове, като се изпращат PTR заявки до съответните резолвъри (частни DNS сървъри за локални клиенти, upstream сървъри за клиенти с публични IP адреси).",
|
||||||
|
"use_private_ptr_resolvers_title": "Използвайте частни обратни DNS резолвери",
|
||||||
|
"use_private_ptr_resolvers_desc": "Разрешаване на заявки PTR, SOA и NS за домейни ARPA, съдържащи частни IP адреси чрез частни сървъри, DHCP, /etc/hosts и др. Ако е деактивирано, AdGuard Home ще отговори на всички такива заявки с NXDOMAIN.",
|
||||||
"check_dhcp_servers": "Проверка за активен DHCP сървър",
|
"check_dhcp_servers": "Проверка за активен DHCP сървър",
|
||||||
"save_config": "Запиши настройките",
|
"save_config": "Запиши настройките",
|
||||||
"enabled_dhcp": "DHCP е разрешен",
|
"enabled_dhcp": "DHCP е разрешен",
|
||||||
"disabled_dhcp": "DHCP е забранен",
|
"disabled_dhcp": "DHCP е забранен",
|
||||||
|
"unavailable_dhcp": "DHCP не е наличен",
|
||||||
|
"unavailable_dhcp_desc": "AdGuard Home не може да стартира DHCP сървър във вашата операционна система",
|
||||||
"dhcp_title": "DHCP сървър (тестови!)",
|
"dhcp_title": "DHCP сървър (тестови!)",
|
||||||
"dhcp_description": "Ако рутера ви не раздава DHCP адреси, може да използвате вградения в AdGuard DHCP сървър.",
|
"dhcp_description": "Ако рутера ви не раздава DHCP адреси, може да използвате вградения в AdGuard DHCP сървър.",
|
||||||
"dhcp_enable": "Рзреши DHCP сървъра",
|
"dhcp_enable": "Рзреши DHCP сървъра",
|
||||||
@@ -13,11 +34,27 @@
|
|||||||
"dhcp_not_found": "Вашата мрежа няма активен DHCP сървър. Безопасно е ползването на вградения DHCP сървър.",
|
"dhcp_not_found": "Вашата мрежа няма активен DHCP сървър. Безопасно е ползването на вградения DHCP сървър.",
|
||||||
"dhcp_found": "Вашата мрежа вече има активен DHCP сървър. Не е безопасно ползването на втори!",
|
"dhcp_found": "Вашата мрежа вече има активен DHCP сървър. Не е безопасно ползването на втори!",
|
||||||
"dhcp_leases": "DHCP раздадени адреси",
|
"dhcp_leases": "DHCP раздадени адреси",
|
||||||
|
"dhcp_static_leases": "DHCP статични наеми",
|
||||||
"dhcp_leases_not_found": "Няма намерени активни DHCP адреси",
|
"dhcp_leases_not_found": "Няма намерени активни DHCP адреси",
|
||||||
"dhcp_config_saved": "Запиши конфигурацията на DHCP сървъра",
|
"dhcp_config_saved": "Запиши конфигурацията на DHCP сървъра",
|
||||||
|
"dhcp_ipv4_settings": "Change to 'DHCP IPv4 настройки.'",
|
||||||
|
"dhcp_ipv6_settings": "DHCP IPv6 настройки",
|
||||||
"form_error_required": "Задължително поле",
|
"form_error_required": "Задължително поле",
|
||||||
|
"form_error_ip4_format": "Невалиден IPv4 адрес",
|
||||||
|
"form_error_ip4_gateway_format": "Невалиден IPv4 адрес на шлюза",
|
||||||
|
"form_error_ip6_format": "Невалиден IPv6 адрес",
|
||||||
"form_error_ip_format": "Невалиден IPv4 адрес",
|
"form_error_ip_format": "Невалиден IPv4 адрес",
|
||||||
|
"form_error_mac_format": "Невалиден MAC адрес",
|
||||||
|
"form_error_client_id_format": "ClientID трябва да съдържа само цифри, малки букви и тирета",
|
||||||
|
"form_error_server_name": "Невалидно име на сървъра",
|
||||||
|
"form_error_subnet": "Подмрежата \"{{cidr}}\" не съдържа IP адреса \"{{ip}}\"",
|
||||||
"form_error_positive": "Проверете дали е положително число",
|
"form_error_positive": "Проверете дали е положително число",
|
||||||
|
"form_error_gateway_ip": "Наемът не може да има IP адреса на шлюза",
|
||||||
|
"out_of_range_error": "Трябва да е извън обхвата \"{{start}}\"-\"{{end}}\"",
|
||||||
|
"lower_range_start_error": "Трябва да е по-малко от началото на диапазона",
|
||||||
|
"greater_range_start_error": "Трябва да бъде по-голямо от началото на диапазона",
|
||||||
|
"subnet_error": "Адресите трябва да бъдат в една подмрежа",
|
||||||
|
"gateway_or_subnet_invalid": "Невалидна маска на подмрежа",
|
||||||
"dhcp_form_gateway_input": "IP шлюз",
|
"dhcp_form_gateway_input": "IP шлюз",
|
||||||
"dhcp_form_subnet_input": "Мрежова маска",
|
"dhcp_form_subnet_input": "Мрежова маска",
|
||||||
"dhcp_form_range_title": "Група от IP адреси",
|
"dhcp_form_range_title": "Група от IP адреси",
|
||||||
@@ -28,15 +65,32 @@
|
|||||||
"dhcp_interface_select": "Изберете мрежов адаптер за DHCP",
|
"dhcp_interface_select": "Изберете мрежов адаптер за DHCP",
|
||||||
"dhcp_hardware_address": "Хардуерни адреси (MAC)",
|
"dhcp_hardware_address": "Хардуерни адреси (MAC)",
|
||||||
"dhcp_ip_addresses": "IP адреси",
|
"dhcp_ip_addresses": "IP адреси",
|
||||||
|
"ip": "IP",
|
||||||
"dhcp_table_hostname": "Име на устройство",
|
"dhcp_table_hostname": "Име на устройство",
|
||||||
"dhcp_table_expires": "История",
|
"dhcp_table_expires": "История",
|
||||||
"dhcp_warning": "Ако искате да използвате вградения DHCP сървър, трябва да няма друг активен DHCP в мрежата Ви!",
|
"dhcp_warning": "Ако искате да използвате вградения DHCP сървър, трябва да няма друг активен DHCP в мрежата Ви!",
|
||||||
|
"dhcp_error": "AdGuard Home не можа да определи дали има друг активен DHCP сървър в мрежата",
|
||||||
|
"dhcp_static_ip_error": "За да използвате DHCP сървър, трябва да бъде зададен статичен IP адрес. AdGuard Home не успя да определи дали този мрежов интерфейс е конфигуриран с помощта на статичен IP адрес. Моля, задайте статичен IP адрес ръчно.",
|
||||||
|
"dhcp_dynamic_ip_found": "Вашата система използва динамична конфигурация на IP адреса за интерфейс <0>{{interfaceName}}</0>. За да използвате DHCP сървър, трябва да бъде зададен статичен IP адрес. Вашият текущ IP адрес е <0>{{ipAddress}}</0>. AdGuard Home автоматично ще зададе този IP адрес като статичен, ако натиснете бутона \"Активиране на DHCP сървър\".",
|
||||||
|
"dhcp_lease_added": "Статичният наем \"{{key}}\" е успешно добавен",
|
||||||
|
"dhcp_lease_deleted": "Статичният лизинг \"{{key}}\" беше успешно изтрит",
|
||||||
|
"dhcp_lease_updated": "Статичният наем \"{{key}}\" е успешно обновен",
|
||||||
|
"dhcp_new_static_lease": "Нова статична наемна",
|
||||||
|
"dhcp_edit_static_lease": "Редактиране на статичен наем",
|
||||||
|
"dhcp_static_leases_not_found": "Няма намерени статични наеми DHCP",
|
||||||
|
"dhcp_add_static_lease": "Добавяне на статична наемна",
|
||||||
|
"dhcp_reset_leases": "Нулирайте всички наеми",
|
||||||
|
"dhcp_reset_leases_confirm": "Наистина ли искате да нулирате всички наеми?",
|
||||||
|
"dhcp_reset_leases_success": "Наемите на DHCP бяха успешно нулирани",
|
||||||
|
"dhcp_reset": "Сигурни ли сте, че искате да нулирате конфигурацията на DHCP?",
|
||||||
"country": "Държава",
|
"country": "Държава",
|
||||||
"city": "Град",
|
"city": "Град",
|
||||||
"delete_confirm": "Наистина ли искате да изтриете \"{{key}}\"?",
|
"delete_confirm": "Наистина ли искате да изтриете \"{{key}}\"?",
|
||||||
|
"form_enter_hostname": "Въведете име на хост",
|
||||||
"error_details": "Подробности за грешка",
|
"error_details": "Подробности за грешка",
|
||||||
"response_details": "Подробности за отговора",
|
"response_details": "Подробности за отговора",
|
||||||
"request_details": "Поискайте подробности",
|
"request_details": "Поискайте подробности",
|
||||||
|
"client_details": "Детайли на клиента",
|
||||||
"details": "Детайли",
|
"details": "Детайли",
|
||||||
"back": "Назад",
|
"back": "Назад",
|
||||||
"dashboard": "Табло",
|
"dashboard": "Табло",
|
||||||
@@ -66,18 +120,32 @@
|
|||||||
"stats_malware_phishing": "вируси/атаки",
|
"stats_malware_phishing": "вируси/атаки",
|
||||||
"stats_adult": "сайтове за възрастни",
|
"stats_adult": "сайтове за възрастни",
|
||||||
"stats_query_domain": "Най-отваряни страници",
|
"stats_query_domain": "Най-отваряни страници",
|
||||||
|
"for_last_hours": "за последния {{count}} час",
|
||||||
|
"for_last_hours_plural": "за последните {{count}} часа",
|
||||||
|
"for_last_days": "за последния {{count}} ден",
|
||||||
|
"for_last_days_plural": "за последните {{count}} дни",
|
||||||
|
"stats_disabled": "Статистиката е деактивирана. Можете да я активирате от <0>страницата за настройки</0>.",
|
||||||
|
"stats_disabled_short": "Статистиката е деактивирана.",
|
||||||
"no_domains_found": "Няма намерени резултати",
|
"no_domains_found": "Няма намерени резултати",
|
||||||
"requests_count": "Сума на заявките",
|
"requests_count": "Сума на заявките",
|
||||||
"top_blocked_domains": "Най-блокирани страници",
|
"top_blocked_domains": "Най-блокирани страници",
|
||||||
"top_clients": "Най-активни IP адреси",
|
"top_clients": "Най-активни IP адреси",
|
||||||
"no_clients_found": "Нямa намерени адреси",
|
"no_clients_found": "Нямa намерени адреси",
|
||||||
"general_statistics": "Обща статисика",
|
"general_statistics": "Обща статисика",
|
||||||
|
"top_upstreams": "Най-добри upstream сървъри",
|
||||||
|
"no_upstreams_data_found": "Не са намерени данни за upstream-ове",
|
||||||
|
"number_of_dns_query_days": "Броят на обработените DNS запитвания за последния {{count}} ден",
|
||||||
|
"number_of_dns_query_days_plural": "Броят на обработените DNS запитвания за последните {{count}} дни",
|
||||||
|
"number_of_dns_query_hours": "Броят на DNS запитвания, обработени за последния {{count}} час",
|
||||||
|
"number_of_dns_query_hours_plural": "Броят на DNS запитвания, обработени за последните {{count}} часа",
|
||||||
"number_of_dns_query_blocked_24_hours": "Сума на блокирани DNS заявки от филтрите за реклама и местни",
|
"number_of_dns_query_blocked_24_hours": "Сума на блокирани DNS заявки от филтрите за реклама и местни",
|
||||||
"number_of_dns_query_blocked_24_hours_by_sec": "Сума на блокирани DNS заявки от AdGuard свързани със сигурността",
|
"number_of_dns_query_blocked_24_hours_by_sec": "Сума на блокирани DNS заявки от AdGuard свързани със сигурността",
|
||||||
"number_of_dns_query_blocked_24_hours_adult": "Сума на блокирани сайтове за възрастни",
|
"number_of_dns_query_blocked_24_hours_adult": "Сума на блокирани сайтове за възрастни",
|
||||||
"enforced_save_search": "Активирано Безопасно Търсене",
|
"enforced_save_search": "Активирано Безопасно Търсене",
|
||||||
"number_of_dns_query_to_safe_search": "Сума на DNS заявки при който е приложено Безопасно Търсене",
|
"number_of_dns_query_to_safe_search": "Сума на DNS заявки при който е приложено Безопасно Търсене",
|
||||||
"average_processing_time": "Средно време за обработка",
|
"average_processing_time": "Средно време за обработка",
|
||||||
|
"average_upstream_response_time": "Средно време за отговор на upstream",
|
||||||
|
"response_time": "Време за отговор",
|
||||||
"average_processing_time_hint": "Средно време за обработка на DNS заявки в милисекунди",
|
"average_processing_time_hint": "Средно време за обработка на DNS заявки в милисекунди",
|
||||||
"block_domain_use_filters_and_hosts": "Блокирани домейни - общи и местни филтри",
|
"block_domain_use_filters_and_hosts": "Блокирани домейни - общи и местни филтри",
|
||||||
"filters_block_toggle_hint": "Може да зададете собствени настройки в <a>Филтри</a>.",
|
"filters_block_toggle_hint": "Може да зададете собствени настройки в <a>Филтри</a>.",
|
||||||
@@ -86,12 +154,23 @@
|
|||||||
"use_adguard_parental": "Включи AdGuard Родителски Надзор",
|
"use_adguard_parental": "Включи AdGuard Родителски Надзор",
|
||||||
"use_adguard_parental_hint": "Модул XXX в AdGuard Home ще провери дали страницата има материали за възвъстни. Използва се същия API за анонимност като при модула за Сигурност.",
|
"use_adguard_parental_hint": "Модул XXX в AdGuard Home ще провери дали страницата има материали за възвъстни. Използва се същия API за анонимност като при модула за Сигурност.",
|
||||||
"enforce_safe_search": "Включи Безопасно Търсене",
|
"enforce_safe_search": "Включи Безопасно Търсене",
|
||||||
"enforce_save_search_hint": "AdGuard Home прилага Безопасно Търсене в следните търсачки и сайтове: Google, Youtube, Bing, и Yandex.",
|
"enforce_save_search_hint": "AdGuard Home ще прилага безопасно търсене в следните търсачки: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||||
"no_servers_specified": "Няма избрани услуги",
|
"no_servers_specified": "Няма избрани услуги",
|
||||||
"general_settings": "Общи настройки",
|
"general_settings": "Общи настройки",
|
||||||
|
"dns_settings": "DNS настройки",
|
||||||
|
"dns_blocklists": "DNS блоксписъци",
|
||||||
|
"dns_allowlists": "DNS разрешени списъци",
|
||||||
|
"dns_blocklists_desc": "AdGuard Home ще блокира домейни, които съвпадат с блоксписъците.",
|
||||||
|
"dns_allowlists_desc": "Домейните от списъците с разрешения на DNS ще бъдат разрешени, дори ако са в някой от списъците с блокирани.",
|
||||||
"custom_filtering_rules": "Местни правила за филтриране",
|
"custom_filtering_rules": "Местни правила за филтриране",
|
||||||
|
"encryption_settings": "Настройки на криптиране",
|
||||||
|
"dhcp_settings": "Настройки на DHCP",
|
||||||
"upstream_dns": "Главен DNS сървър",
|
"upstream_dns": "Главен DNS сървър",
|
||||||
|
"upstream_dns_help": "Въведете един адрес на сървър на ред. <a>Научете повече</a> за конфигуриране на upstream DNS сървъри.",
|
||||||
|
"upstream_dns_configured_in_file": "Конфигуриран в {{path}}",
|
||||||
"test_upstream_btn": "Тествай главния DNS",
|
"test_upstream_btn": "Тествай главния DNS",
|
||||||
|
"upstreams": "Нагоре по веригата",
|
||||||
|
"upstream": "upstream",
|
||||||
"apply_btn": "Приложи",
|
"apply_btn": "Приложи",
|
||||||
"disabled_filtering_toast": "Забрани филтрирането",
|
"disabled_filtering_toast": "Забрани филтрирането",
|
||||||
"enabled_filtering_toast": "Разреши фитрирането",
|
"enabled_filtering_toast": "Разреши фитрирането",
|
||||||
@@ -101,19 +180,39 @@
|
|||||||
"enabled_parental_toast": "Разреши Родителски Надзор",
|
"enabled_parental_toast": "Разреши Родителски Надзор",
|
||||||
"disabled_safe_search_toast": "Забрани Безопасно Търсене",
|
"disabled_safe_search_toast": "Забрани Безопасно Търсене",
|
||||||
"enabled_save_search_toast": "Разреши Безопасно Търсене",
|
"enabled_save_search_toast": "Разреши Безопасно Търсене",
|
||||||
|
"updated_save_search_toast": "Настройките за безопасно търсене са обновени",
|
||||||
"enabled_table_header": "Разреши",
|
"enabled_table_header": "Разреши",
|
||||||
"name_table_header": "Име",
|
"name_table_header": "Име",
|
||||||
|
"list_url_table_header": "URL на списъка",
|
||||||
"rules_count_table_header": "Правила общо",
|
"rules_count_table_header": "Правила общо",
|
||||||
"last_time_updated_table_header": "Последно обновен",
|
"last_time_updated_table_header": "Последно обновен",
|
||||||
"actions_table_header": "Действия",
|
"actions_table_header": "Действия",
|
||||||
|
"request_table_header": "Заявка",
|
||||||
"edit_table_action": "Редактирай",
|
"edit_table_action": "Редактирай",
|
||||||
"delete_table_action": "Изтрий",
|
"delete_table_action": "Изтрий",
|
||||||
|
"elapsed": "Изтекло",
|
||||||
"filters_and_hosts_hint": "AdGuard Home разбира adblock и host синтаксис.",
|
"filters_and_hosts_hint": "AdGuard Home разбира adblock и host синтаксис.",
|
||||||
|
"no_blocklist_added": "Няма добавени списъци с блокирани",
|
||||||
|
"no_whitelist_added": "Няма добавени списъци с разрешени",
|
||||||
|
"add_blocklist": "Добавяне на списък за блокиране",
|
||||||
|
"add_allowlist": "Добавяне на списък с разрешения",
|
||||||
"cancel_btn": "Откажи",
|
"cancel_btn": "Откажи",
|
||||||
"enter_name_hint": "Въведи име",
|
"enter_name_hint": "Въведи име",
|
||||||
|
"enter_url_or_path_hint": "Въведете URL адрес или абсолютен път на списъка",
|
||||||
"check_updates_btn": "Провери за актуализация",
|
"check_updates_btn": "Провери за актуализация",
|
||||||
|
"new_blocklist": "Нов списък за блокиране",
|
||||||
|
"new_allowlist": "Нов списък с разрешения",
|
||||||
|
"edit_blocklist": "Редактиране на списък за блокиране",
|
||||||
|
"edit_allowlist": "Редактиране на списък с разрешения",
|
||||||
|
"choose_blocklist": "Изберете списъци за блокиране",
|
||||||
|
"choose_allowlist": "Изберете списъци с разрешения",
|
||||||
|
"enter_valid_blocklist": "Въведете валиден URL за списъка за блокиране.",
|
||||||
|
"enter_valid_allowlist": "Въведете валиден URL за списъка с разрешения.",
|
||||||
|
"form_error_url_format": "Невалиден формат на URL",
|
||||||
|
"form_error_url_or_path_format": "Невалиден URL или абсолютен път на списъка",
|
||||||
"custom_filter_rules": "Местни правила за филтриране",
|
"custom_filter_rules": "Местни правила за филтриране",
|
||||||
"custom_filter_rules_hint": "Въвеждайте всяко правило на нов ред. Може да използвате adblock или hosts файлов синтаксис.",
|
"custom_filter_rules_hint": "Въвеждайте всяко правило на нов ред. Може да използвате adblock или hosts файлов синтаксис.",
|
||||||
|
"system_host_files": "Файлове на системен хост",
|
||||||
"examples_title": "Примери",
|
"examples_title": "Примери",
|
||||||
"example_meaning_filter_block": "Блокирай достъп до домейн example.org и всички под домейни.",
|
"example_meaning_filter_block": "Блокирай достъп до домейн example.org и всички под домейни.",
|
||||||
"example_meaning_filter_whitelist": "Разреши достъп до домейн example.org и всичките му под домейни.",
|
"example_meaning_filter_whitelist": "Разреши достъп до домейн example.org и всичките му под домейни.",
|
||||||
@@ -123,22 +222,36 @@
|
|||||||
"example_comment_hash": "# Това е също коментар",
|
"example_comment_hash": "# Това е също коментар",
|
||||||
"example_regex_meaning": "блокирай достъп до домейни който съвпадат със следното",
|
"example_regex_meaning": "блокирай достъп до домейни който съвпадат със следното",
|
||||||
"example_upstream_regular": "класически DNS (UDP протокол)",
|
"example_upstream_regular": "класически DNS (UDP протокол)",
|
||||||
|
"example_upstream_regular_port": "обикновен DNS (върху UDP, с порт);",
|
||||||
"example_upstream_udp": "обикновен DNS (върху UDP, име на хост);",
|
"example_upstream_udp": "обикновен DNS (върху UDP, име на хост);",
|
||||||
"example_upstream_dot": "криптиран <a href='https://en.wikipedia.org/wiki/DNS_over_TLS' target='_blank'>DNS-върху-TLS</a>",
|
"example_upstream_dot": "криптиран <a href='https://en.wikipedia.org/wiki/DNS_over_TLS' target='_blank'>DNS-върху-TLS</a>",
|
||||||
"example_upstream_doh": "криптиран <a href='https://en.wikipedia.org/wiki/DNS_over_HTTPS' target='_blank'>DNS-върху-HTTPS</a>",
|
"example_upstream_doh": "криптиран <a href='https://en.wikipedia.org/wiki/DNS_over_HTTPS' target='_blank'>DNS-върху-HTTPS</a>",
|
||||||
|
"example_upstream_doh3": "криптиран DNS-върху-HTTPS с наложен <0>HTTP/3</0> и без резервиране на HTTP/2 или по-ниско;",
|
||||||
|
"example_upstream_doq": "криптиран <0>DNS-over-QUIC</0>;",
|
||||||
"example_upstream_sdns": "може да ползвате <a href='https://dnscrypt.info/stamps/' target='_blank'>DNS Подписване</a> за <a href='https://dnscrypt.info/' target='_blank'>DNSCrypt</a> или <a href='https://en.wikipedia.org/wiki/DNS_over_HTTPS' target='_blank'>DNS-върху-HTTPS</a> сървъри",
|
"example_upstream_sdns": "може да ползвате <a href='https://dnscrypt.info/stamps/' target='_blank'>DNS Подписване</a> за <a href='https://dnscrypt.info/' target='_blank'>DNSCrypt</a> или <a href='https://en.wikipedia.org/wiki/DNS_over_HTTPS' target='_blank'>DNS-върху-HTTPS</a> сървъри",
|
||||||
"example_upstream_tcp": "класически DNS (TCP протокол)",
|
"example_upstream_tcp": "класически DNS (TCP протокол)",
|
||||||
|
"example_upstream_tcp_port": "обикновен DNS (върху TCP, с порт);",
|
||||||
"example_upstream_tcp_hostname": "обикновен DNS (върху TCP, име на хост);",
|
"example_upstream_tcp_hostname": "обикновен DNS (върху TCP, име на хост);",
|
||||||
|
"all_lists_up_to_date_toast": "Всички списъци вече са актуални",
|
||||||
"updated_upstream_dns_toast": "Глобалните DNS сървъри са обновени",
|
"updated_upstream_dns_toast": "Глобалните DNS сървъри са обновени",
|
||||||
"dns_test_ok_toast": "Въведените DNS сървъри работят коректно",
|
"dns_test_ok_toast": "Въведените DNS сървъри работят коректно",
|
||||||
"dns_test_not_ok_toast": "Сървър \"{{key}}\": не работи, моля проверете дали е въведен коректно",
|
"dns_test_not_ok_toast": "Сървър \"{{key}}\": не работи, моля проверете дали е въведен коректно",
|
||||||
|
"dns_test_parsing_error_toast": "Раздел {{section}}: ред {{line}}: не може да се използва, моля, проверете дали сте го написали правилно",
|
||||||
|
"dns_test_warning_toast": "Ъпстриймът \"{{key}}\" не отговаря на тестовите заявки и може да не работи правилно",
|
||||||
"unblock": "Отблокирай",
|
"unblock": "Отблокирай",
|
||||||
"block": "Блокирай",
|
"block": "Блокирай",
|
||||||
|
"disallow_this_client": "Забранете на този клиент",
|
||||||
|
"allow_this_client": "Позволете на този клиент",
|
||||||
|
"block_for_this_client_only": "Блокирайте само за този клиент",
|
||||||
|
"unblock_for_this_client_only": "Деблокирайте само за този клиент",
|
||||||
|
"add_persistent_client": "Добавяне като постоянен клиент",
|
||||||
"time_table_header": "Време",
|
"time_table_header": "Време",
|
||||||
"date": "Дата",
|
"date": "Дата",
|
||||||
"domain_name_table_header": "Име на домейн",
|
"domain_name_table_header": "Име на домейн",
|
||||||
|
"domain_or_client": "Домейн или клиент",
|
||||||
"type_table_header": "Тип",
|
"type_table_header": "Тип",
|
||||||
"response_table_header": "Отговор",
|
"response_table_header": "Отговор",
|
||||||
|
"response_code": "Код на отговор",
|
||||||
"client_table_header": "Клиент",
|
"client_table_header": "Клиент",
|
||||||
"empty_response_status": "Празен",
|
"empty_response_status": "Празен",
|
||||||
"show_all_filter_type": "Покажи всички",
|
"show_all_filter_type": "Покажи всички",
|
||||||
@@ -153,19 +266,84 @@
|
|||||||
"updated_custom_filtering_toast": "Обновени местни правила за филтриране",
|
"updated_custom_filtering_toast": "Обновени местни правила за филтриране",
|
||||||
"rule_removed_from_custom_filtering_toast": "Премахнато от местни правила за филтриране: {{rule}}",
|
"rule_removed_from_custom_filtering_toast": "Премахнато от местни правила за филтриране: {{rule}}",
|
||||||
"rule_added_to_custom_filtering_toast": "Добавено до местни правила за филтриране: {{rule}}",
|
"rule_added_to_custom_filtering_toast": "Добавено до местни правила за филтриране: {{rule}}",
|
||||||
|
"query_log_response_status": "Статус: {{value}}",
|
||||||
|
"query_log_filtered": "Филтрирано от {{filter}}",
|
||||||
|
"query_log_confirm_clear": "Сигурни ли сте, че искате да изчистите целия дневник на запитванията?",
|
||||||
|
"query_log_cleared": "Дневникът на запитванията е изчистен успешно",
|
||||||
|
"query_log_updated": "Журналът на запитванията беше успешно актуализиран",
|
||||||
|
"query_log_clear": "Изчисти дневниците на запитванията",
|
||||||
|
"query_log_retention": "Ротация на дневниците на запитвания",
|
||||||
|
"query_log_enable": "Активиране на историята",
|
||||||
|
"query_log_configuration": "Конфигурация на дневниците",
|
||||||
|
"query_log_disabled": "Дневникът на запитванията е деактивиран и може да бъде конфигуриран в <0>настройките</0>",
|
||||||
|
"query_log_strict_search": "Използвайте двойни кавички за стриктно търсене",
|
||||||
|
"query_log_retention_confirm": "Наистина ли искате да промените ротацията на дневника със запитвания? Ако намалите стойността на интервала, някои данни ще бъдат изгубени",
|
||||||
|
"anonymize_client_ip": "Анонимен IP адрес на клиента",
|
||||||
|
"anonymize_client_ip_desc": "Не запазвайте пълния IP адрес на клиента в регистрите или статистиката",
|
||||||
|
"dns_config": "Конфигурация на DNS сървъра",
|
||||||
|
"dns_cache_config": "Конфигурация на DNS кеш",
|
||||||
|
"dns_cache_config_desc": "Тук можете да конфигурирате кеша на DNS",
|
||||||
|
"blocking_mode": "Режим на блокиране",
|
||||||
"default": "По подразбиране",
|
"default": "По подразбиране",
|
||||||
|
"nxdomain": "NXDOMAIN",
|
||||||
|
"refused": "ОТКАЗАНО",
|
||||||
|
"null_ip": "Нулев IP",
|
||||||
"custom_ip": "Персонализиран IP",
|
"custom_ip": "Персонализиран IP",
|
||||||
|
"blocking_ipv4": "Блокиране на IPv4",
|
||||||
|
"blocking_ipv6": "Блокиране на IPv6",
|
||||||
|
"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",
|
"dnscrypt": "DNSCrypt",
|
||||||
"dns_over_https": "DNS-пред-HTTPS",
|
"dns_over_https": "DNS-пред-HTTPS",
|
||||||
|
"dns_over_tls": "DNS-над-TLS",
|
||||||
"dns_over_quic": "DNS-over-QUIC",
|
"dns_over_quic": "DNS-over-QUIC",
|
||||||
|
"client_id": "ClientID",
|
||||||
|
"client_id_placeholder": "Въведете ClientID",
|
||||||
|
"client_id_desc": "Клиентите могат да бъдат идентифицирани чрез ClientID. Научете повече за начина на идентифициране на клиенти <a>тук</a>.",
|
||||||
|
"download_mobileconfig_doh": "Изтеглете .mobileconfig за DNS-over-HTTPS",
|
||||||
|
"download_mobileconfig_dot": "Изтеглете .mobileconfig за DNS-over-TLS",
|
||||||
|
"download_mobileconfig": "Изтеглете конфигурационния файл",
|
||||||
"plain_dns": "Обикновен DNS",
|
"plain_dns": "Обикновен DNS",
|
||||||
|
"form_enter_rate_limit": "Въведете ограничение на скоростта",
|
||||||
|
"rate_limit": "Ограничение на скоростта",
|
||||||
|
"edns_enable": "Активиране на подмрежата на клиенти EDNS",
|
||||||
|
"edns_cs_desc": "Добавете опцията за подмрежа на клиента EDNS (ECS) към запитванията нагоре и записвайте стойностите, изпратени от клиентите в журнала на запитванията.",
|
||||||
|
"edns_use_custom_ip": "Използване на персонализиран IP за EDNS",
|
||||||
|
"edns_use_custom_ip_desc": "Разрешаване на използването на персонализиран IP за EDNS",
|
||||||
|
"rate_limit_desc": "Броят на заявките на секунда, разрешени за всеки клиент. Задаването на 0 означава, че няма ограничение.",
|
||||||
|
"rate_limit_subnet_len_ipv4": "Дължина на префикса на подмрежата за IPv4 адреси",
|
||||||
|
"rate_limit_subnet_len_ipv4_desc": "Дължина на префикса на подмрежата за IPv4 адреси, използвани за ограничаване на скоростта. Стандартно е 24",
|
||||||
|
"rate_limit_subnet_len_ipv4_error": "Дължината на префикса на подмрежата IPv4 трябва да бъде между 0 и 32",
|
||||||
|
"rate_limit_subnet_len_ipv6": "Дължина на префикса на подмрежата за IPv6 адреси",
|
||||||
|
"rate_limit_subnet_len_ipv6_desc": "Дължина на префикса на подсетеви адреси за IPv6, използвани за ограничаване на скоростта. Стандартната стойност е 56",
|
||||||
|
"rate_limit_subnet_len_ipv6_error": "Дължината на префикса на подсетевите адреси за IPv6 трябва да бъде между 0 и 128",
|
||||||
|
"form_enter_rate_limit_subnet_len": "Въведете дължина на префикса на подсетевите адреси за ограничаване на скоростта",
|
||||||
|
"rate_limit_whitelist": "Разрешен списък за ограничаване на скоростта",
|
||||||
|
"rate_limit_whitelist_desc": "IP адреси, изключени от ограничаването на скоростта",
|
||||||
|
"rate_limit_whitelist_placeholder": "Въведете по един IP адрес на ред",
|
||||||
|
"blocking_ipv4_desc": "IP адрес, който ще се върне за блокирано A запитване",
|
||||||
|
"blocking_ipv6_desc": "IP адрес, който трябва да се върне за блокирано AAAA запитване",
|
||||||
|
"blocking_mode_default": "По подразбиране: Отговаряйте с код REFUSED, когато е блокиран от правило в стил Adblock; отговаряйте с IP адреса, посочен в правилото, когато е блокиран от правило в стил /etc/hosts.",
|
||||||
|
"blocking_mode_refused": "ОТКАЗАНО: Отговорете с код ОТКАЗАН",
|
||||||
|
"blocking_mode_nxdomain": "NXDOMAIN: Отговаряйте с код NXDOMAIN",
|
||||||
|
"blocking_mode_null_ip": "Нулев IP: Отговорете с нулев IP адрес (0.0.0.0 за A; :: за AAAA)",
|
||||||
|
"blocking_mode_custom_ip": "Персонализиран IP: Отговорете с ръчно зададен IP адрес",
|
||||||
|
"theme_auto": "Автоматично",
|
||||||
"theme_light": "Светла тема",
|
"theme_light": "Светла тема",
|
||||||
"theme_dark": "Тъмна тема",
|
"theme_dark": "Тъмна тема",
|
||||||
|
"upstream_dns_client_desc": "Ако оставите това поле празно, AdGuard Home ще използва сървърите, конфигурирани в <0>настройките на DNS</0>.",
|
||||||
|
"tracker_source": "Източник на проследяването",
|
||||||
"source_label": "Източник",
|
"source_label": "Източник",
|
||||||
"found_in_known_domain_db": "Намерен в списъците с домейни.",
|
"found_in_known_domain_db": "Намерен в списъците с домейни.",
|
||||||
"category_label": "Категория",
|
"category_label": "Категория",
|
||||||
"rule_label": "Правило",
|
"rule_label": "Правило",
|
||||||
|
"list_label": "Списък",
|
||||||
"unknown_filter": "Непознат филтър {{filterId}}",
|
"unknown_filter": "Непознат филтър {{filterId}}",
|
||||||
|
"known_tracker": "Известен проследяващ",
|
||||||
"install_welcome_title": "Добре дошли в AdGuard Home!",
|
"install_welcome_title": "Добре дошли в AdGuard Home!",
|
||||||
"install_welcome_desc": "AdGuard Home e мрежово решение за блокиране на реклами и тракери на DNS ниво. Създадено е за да ви даде пълен контрол над мрежата и всичките ви устройства, без да е необходимо допълнително инсталиране на друг софтуер.",
|
"install_welcome_desc": "AdGuard Home e мрежово решение за блокиране на реклами и тракери на DNS ниво. Създадено е за да ви даде пълен контрол над мрежата и всичките ви устройства, без да е необходимо допълнително инсталиране на друг софтуер.",
|
||||||
"install_settings_title": "Администрация",
|
"install_settings_title": "Администрация",
|
||||||
@@ -194,6 +372,7 @@
|
|||||||
"install_devices_router_list_1": "Отворете страницата за настройки на вашия рутер. Обикновено тя се намира на URL (тук http://192.168.0.1/ или тук http://192.168.1.1/). За достъп може да ви трябва парола. Ако сте забравили паролата може да я ресетнете като натиснета скрития ресет бутон - внимание това ще ресетне всички настройки на рутера до фабрични! Някой рутери могат да бъдате администрирани от софтуер или приложение, който би трябвало да е вече инсталиран на компютъра/телефона ви.",
|
"install_devices_router_list_1": "Отворете страницата за настройки на вашия рутер. Обикновено тя се намира на URL (тук http://192.168.0.1/ или тук http://192.168.1.1/). За достъп може да ви трябва парола. Ако сте забравили паролата може да я ресетнете като натиснета скрития ресет бутон - внимание това ще ресетне всички настройки на рутера до фабрични! Някой рутери могат да бъдате администрирани от софтуер или приложение, който би трябвало да е вече инсталиран на компютъра/телефона ви.",
|
||||||
"install_devices_router_list_2": "Намерета DHCP/DNS настройки. В под раздел DHCP рзгледайте и намерете къде е полето за DNS настройка в което може да въведете персонализирани настройки за DNS сървъри.",
|
"install_devices_router_list_2": "Намерета DHCP/DNS настройки. В под раздел DHCP рзгледайте и намерете къде е полето за DNS настройка в което може да въведете персонализирани настройки за DNS сървъри.",
|
||||||
"install_devices_router_list_3": "Въведете адресът на AdGuard Home сървъра.",
|
"install_devices_router_list_3": "Въведете адресът на AdGuard Home сървъра.",
|
||||||
|
"install_devices_router_list_4": "На някои типове маршрутизатори не може да се зададе персонализиран DNS сървър. В този случай може да помогне настройването на AdGuard Home като <0>DHCP сървър</0>. В противен случай трябва да проверите ръководството на маршрутизатора за информация как да персонализирате DNS сървърите на конкретния модел на вашия маршрутизатор.",
|
||||||
"install_devices_windows_list_1": "Отворете Контролния Панел през Старт меню или чрез функция търсене на Windows.",
|
"install_devices_windows_list_1": "Отворете Контролния Панел през Старт меню или чрез функция търсене на Windows.",
|
||||||
"install_devices_windows_list_2": "Вървете до Настрйки на Мрежи и Интернет и от там изберете Мрежи и Център за Споделяне.",
|
"install_devices_windows_list_2": "Вървете до Настрйки на Мрежи и Интернет и от там изберете Мрежи и Център за Споделяне.",
|
||||||
"install_devices_windows_list_3": "От ляво на екрана намерете Смени настроки на мрежовия адаптер и кликнете на него.",
|
"install_devices_windows_list_3": "От ляво на екрана намерете Смени настроки на мрежовия адаптер и кликнете на него.",
|
||||||
@@ -211,7 +390,7 @@
|
|||||||
"install_devices_android_list_5": "Променете стойностите на DNS 1 и DNS 2 да използват AdGuard Home сървъра.",
|
"install_devices_android_list_5": "Променете стойностите на DNS 1 и DNS 2 да използват AdGuard Home сървъра.",
|
||||||
"install_devices_ios_list_1": "От начален екран, цъкнете на Settings.",
|
"install_devices_ios_list_1": "От начален екран, цъкнете на Settings.",
|
||||||
"install_devices_ios_list_2": "Изберете Wi-Fi от лявото меню (там няма възможност за въвеждане на DNS настройки).",
|
"install_devices_ios_list_2": "Изберете Wi-Fi от лявото меню (там няма възможност за въвеждане на DNS настройки).",
|
||||||
"install_devices_ios_list_3": "Клинете на името на активната мрежа към която сте свързани.",
|
"install_devices_ios_list_3": "Натиснете на името на активната мрежа.",
|
||||||
"install_devices_ios_list_4": "В полето за DNS изберете ръчно и въведете адреса на AdGuard Home сървъра.",
|
"install_devices_ios_list_4": "В полето за DNS изберете ръчно и въведете адреса на AdGuard Home сървъра.",
|
||||||
"get_started": "Да започваме",
|
"get_started": "Да започваме",
|
||||||
"next": "Следващ",
|
"next": "Следващ",
|
||||||
@@ -222,13 +401,15 @@
|
|||||||
"encryption_config_saved": "Конфигурацията е успешно записана",
|
"encryption_config_saved": "Конфигурацията е успешно записана",
|
||||||
"encryption_server": "Име на сървъра",
|
"encryption_server": "Име на сървъра",
|
||||||
"encryption_server_enter": "Въведете име на домейна",
|
"encryption_server_enter": "Въведете име на домейна",
|
||||||
"encryption_server_desc": "За да използвате HTTPS, трябва името на сървъра да съвпада с това на SSL сертификата.",
|
"encryption_server_desc": "Ако е зададено, AdGuard Home открива ClientIDs, отговаря на DDR запитвания и извършва допълнителни проверки на връзките. Ако не е зададено, тези функции са деактивирани. Трябва да съвпада с едно от имената на DNS в сертификата.",
|
||||||
"encryption_redirect": "Автоматично пренасочване към HTTPS",
|
"encryption_redirect": "Автоматично пренасочване към HTTPS",
|
||||||
"encryption_redirect_desc": "Служи за автоматично пренасочване от HTTP към HTTPS на страницата за Администрация в AdGuard Home.",
|
"encryption_redirect_desc": "Служи за автоматично пренасочване от HTTP към HTTPS на страницата за Администрация в AdGuard Home.",
|
||||||
"encryption_https": "HTTPS порт",
|
"encryption_https": "HTTPS порт",
|
||||||
"encryption_https_desc": "Ако зададете HTTPS порт, страницата за Администрация на AdGuard Home ще бъде достъпна на HTTPS, и също ще отговаря на DNS-върху-HTTPS '/dns-запитвания'.",
|
"encryption_https_desc": "Ако зададете HTTPS порт, страницата за Администрация на AdGuard Home ще бъде достъпна на HTTPS, и също ще отговаря на DNS-върху-HTTPS '/dns-запитвания'.",
|
||||||
"encryption_dot": "DNS-върху-TLS порт",
|
"encryption_dot": "DNS-върху-TLS порт",
|
||||||
"encryption_dot_desc": "Ако порта е конфигуриран, AdGuard Home ще стартира и сървър за DNS-върху-TLS.",
|
"encryption_dot_desc": "Ако порта е конфигуриран, AdGuard Home ще стартира и сървър за DNS-върху-TLS.",
|
||||||
|
"encryption_doq": "Порт на DNS-over-QUIC",
|
||||||
|
"encryption_doq_desc": "Ако този порт е конфигуриран, AdGuard Home ще стартира DNS-over-QUIC сървър на този порт. Той е експериментален и може да не е надежден. Освен това в момента не съществуват много клиенти, които да го подкрепят.",
|
||||||
"encryption_certificates": "Сертификати",
|
"encryption_certificates": "Сертификати",
|
||||||
"encryption_certificates_desc": "За да използвате сигурна връзка, ще трябва да осигурите SSL сертификати за вашия домейн. Може да заявите безплатен от <0>{{link}}</0> или да закупите от Certificate Authorities.",
|
"encryption_certificates_desc": "За да използвате сигурна връзка, ще трябва да осигурите SSL сертификати за вашия домейн. Може да заявите безплатен от <0>{{link}}</0> или да закупите от Certificate Authorities.",
|
||||||
"encryption_certificates_input": "Копирай/постави вашия PEM-кодиран сертификат тук.",
|
"encryption_certificates_input": "Копирай/постави вашия PEM-кодиран сертификат тук.",
|
||||||
@@ -247,6 +428,9 @@
|
|||||||
"encryption_hostnames": "Имена на хоста",
|
"encryption_hostnames": "Имена на хоста",
|
||||||
"encryption_reset": "Сигурни ли сте че искате да изтриете настройките за криптиране?",
|
"encryption_reset": "Сигурни ли сте че искате да изтриете настройките за криптиране?",
|
||||||
"encryption_warning": "Внимание",
|
"encryption_warning": "Внимание",
|
||||||
|
"encryption_plain_dns_enable": "Активиране на обикновен DNS",
|
||||||
|
"encryption_plain_dns_desc": "Обикновеният DNS е активиран по подразбиране. Можете да го деактивирате, за да принудите всички устройства да използват криптиран DNS. За да направите това, трябва да активирате поне един криптиран DNS протокол",
|
||||||
|
"encryption_plain_dns_error": "За да деактивирате обикновения DNS, активирайте поне един криптиран DNS протокол",
|
||||||
"topline_expiring_certificate": "Вашият SSL сертификат изтича. Обнови <0>Настройки за криптиране</0>.",
|
"topline_expiring_certificate": "Вашият SSL сертификат изтича. Обнови <0>Настройки за криптиране</0>.",
|
||||||
"topline_expired_certificate": "Вашият SSL сертификат е изтекъл. Обнови <0>Настройки за криптиране</0>.",
|
"topline_expired_certificate": "Вашият SSL сертификат е изтекъл. Обнови <0>Настройки за криптиране</0>.",
|
||||||
"form_error_port_range": "Въведете порт в диапазона 80-65535",
|
"form_error_port_range": "Въведете порт в диапазона 80-65535",
|
||||||
@@ -255,43 +439,316 @@
|
|||||||
"form_error_password": "Паролата не съвпада",
|
"form_error_password": "Паролата не съвпада",
|
||||||
"reset_settings": "Изтрий всички настройки",
|
"reset_settings": "Изтрий всички настройки",
|
||||||
"update_announcement": "Има нова AdGuard Home {{version}}! <0>Цъкни тук</0> за повече информация.",
|
"update_announcement": "Има нова AdGuard Home {{version}}! <0>Цъкни тук</0> за повече информация.",
|
||||||
|
"setup_guide": "Наръчник за настройка",
|
||||||
|
"dns_addresses": "DNS адреси",
|
||||||
|
"dns_start": "DNS сървърът стартира",
|
||||||
|
"dns_status_error": "Грешка при проверка на статуса на DNS сървъра",
|
||||||
|
"down": "Не работи",
|
||||||
|
"fix": "Поправи",
|
||||||
|
"dns_providers": "Ето един <0>списък с известни DNS доставчици</0>, от който да избирате.",
|
||||||
|
"update_now": "Актуализирай сега",
|
||||||
|
"update_failed": "Авто-актуализацията не успя. Моля, <a>следвайте тези стъпки</a>, за да актуализирате ръчно.",
|
||||||
|
"manual_update": "Моля, <a>следвайте тези стъпки</a>, за да актуализирате ръчно.",
|
||||||
|
"processing_update": "Моля, изчакайте, AdGuard Home се актуализира",
|
||||||
|
"clients_title": "Постоянни клиенти",
|
||||||
|
"clients_desc": "Конфигурирайте клиентски записи за устройства, свързани с AdGuard Home",
|
||||||
|
"settings_global": "Глобални",
|
||||||
"settings_custom": "Персонализиране",
|
"settings_custom": "Персонализиране",
|
||||||
"table_client": "Клиент",
|
"table_client": "Клиент",
|
||||||
"table_name": "Име",
|
"table_name": "Име",
|
||||||
"save_btn": "Запази",
|
"save_btn": "Запази",
|
||||||
|
"client_add": "Добавяне на клиент",
|
||||||
|
"client_new": "Нов клиент",
|
||||||
|
"client_edit": "Редактиране на клиент",
|
||||||
|
"client_identifier": "Идентификатор",
|
||||||
|
"ip_address": "Потребителски IP адрес",
|
||||||
|
"client_identifier_desc": "Клиентите могат да бъдат идентифицирани по техния IP адрес, CIDR, MAC адрес или ClientID (може да се използва за DoT/DoH/DoQ). Научете повече как да идентифицирате клиенти <0>тук</0>.",
|
||||||
|
"form_enter_ip": "Въведете IP",
|
||||||
|
"form_enter_subnet_ip": "Въведете IP адрес в подмрежата \"{{cidr}}\"",
|
||||||
|
"form_enter_mac": "Въведете MAC",
|
||||||
|
"form_enter_id": "Въведете идентификатор",
|
||||||
|
"form_add_id": "Добавете идентификатор",
|
||||||
|
"form_client_name": "Въведете името на клиента",
|
||||||
"name": "Име",
|
"name": "Име",
|
||||||
|
"client_name": "Клиент {{id}}",
|
||||||
|
"client_global_settings": "Използвайте глобалните настройки",
|
||||||
|
"client_deleted": "Клиент \"{{key}}\" успешно изтрит",
|
||||||
|
"client_added": "Клиент \"{{key}}\" успешно добавен",
|
||||||
|
"client_updated": "Клиент \"{{key}}\" успешно обновен",
|
||||||
"clients_not_found": "Нямa намерени адреси",
|
"clients_not_found": "Нямa намерени адреси",
|
||||||
|
"client_confirm_delete": "Наистина ли искате да изтриете клиента \"{{key}}\"?",
|
||||||
|
"list_confirm_delete": "Сигурни ли сте, че искате да изтриете този списък?",
|
||||||
|
"auto_clients_title": "Клиенти по време на работа",
|
||||||
|
"auto_clients_desc": "Информация за IP адреси на устройства, които използват или могат да използват AdGuard Home. Тази информация се събира от няколко източника, включително файлове с хост, обратен DNS и др.",
|
||||||
|
"access_title": "Настройки за достъп",
|
||||||
|
"access_desc": "Тук можете да конфигурирате правилата за достъп до DNS сървъра на AdGuard Home",
|
||||||
|
"access_allowed_title": "Разрешени клиенти",
|
||||||
|
"access_allowed_desc": "Списък от CIDR, IP адреси или <a>ClientIDs</a>. Ако този списък съдържа записи, AdGuard Home ще приема заявки само от тези клиенти.",
|
||||||
|
"access_disallowed_title": "Забранени клиенти",
|
||||||
|
"access_disallowed_desc": "Списък с CIDR, IP адреси или <a>ClientIDs</a>. Ако този списък съдържа записи, AdGuard Home ще отхвърли заявките от тези клиенти. Това поле се игнорира, ако има записи в разрешените клиенти.",
|
||||||
|
"access_blocked_title": "Недопустими домейни",
|
||||||
|
"access_blocked_desc": "Не бъркайте с филтри. AdGuard Home отхвърля DNS запитванията, съвпадащи с тези домейни, и тези запитвания дори не се появяват в дневника на запитванията. Можете да зададете точни имена на домейни, символи за подмяна или правила за филтриране на URL адреси, например \"example.org\", \"*.example.org\" или \"||example.org^\".",
|
||||||
|
"access_settings_saved": "Настройките за достъп бяха успешно запазени",
|
||||||
|
"updates_checked": "Достъпна е нова версия на AdGuard Home",
|
||||||
|
"updates_version_equal": "AdGuard Home е актуален.",
|
||||||
"check_updates_now": "Провери за актуализации",
|
"check_updates_now": "Провери за актуализации",
|
||||||
|
"version_request_error": "Неуспешна проверка за актуализации. Моля, проверете връзката си с Интернет.",
|
||||||
|
"dns_privacy": "Доверителност на DNS",
|
||||||
|
"setup_dns_privacy_1": "<0>DNS-върху-TLS:</0> Използвайте <1>{{address}}</1> низ.",
|
||||||
|
"setup_dns_privacy_2": "<0>DNS-върху-HTTPS:</0> Използвайте <1>{{address}}</1> низ.",
|
||||||
|
"setup_dns_privacy_3": "<0>Ето списък с приложения, които можете да използвате.</0>",
|
||||||
|
"setup_dns_privacy_4": "На устройство с iOS 14 или macOS Big Sur можете да изтеглите специален файл '.mobileconfig', който добавя <highlight>DNS-over-HTTPS</highlight> или <highlight>DNS-over-TLS</highlight> сървъри към настройките на DNS.",
|
||||||
|
"setup_dns_privacy_android_1": "Android 9 поддържа DNS-върху-TLS нативно. За да го конфигурирате, отидете на Настройки → Мрежа и интернет → Разширени настройки → Частен DNS и въведете името на домейна си там.",
|
||||||
|
"setup_dns_privacy_android_2": "<0>AdGuard за Android</0> поддържа <1>DNS-върху-HTTPS</1> и <1>DNS-върху-TLS</1>.",
|
||||||
|
"setup_dns_privacy_android_3": "<0>Intra</0> добавя поддръжка за <1>DNS-върху-HTTPS</1> към Android.",
|
||||||
|
"setup_dns_privacy_ios_1": "<0>DNSCloak</0> поддържа <1>DNS-over-HTTPS</1>, но за да го конфигурирате да използва вашия собствен сървър, ще трябва да генерирате <2>DNS Stamp</2> за него.",
|
||||||
|
"setup_dns_privacy_ios_2": "<0>AdGuard за iOS</0> поддържа <1>DNS-over-HTTPS</1> и <1>DNS-over-TLS</1> конфигурация.",
|
||||||
|
"setup_dns_privacy_other_title": "Други реализации",
|
||||||
|
"setup_dns_privacy_other_1": "AdGuard Home сам може да бъде сигурен клиент на DNS на всяка платформа.",
|
||||||
|
"setup_dns_privacy_other_2": "<0>dnsproxy</0> поддържа всички известни сигурни DNS протоколи.",
|
||||||
|
"setup_dns_privacy_other_3": "<0>dnscrypt-proxy</0> поддържа <1>DNS-over-HTTPS</1>.",
|
||||||
|
"setup_dns_privacy_other_4": "<0>Mozilla Firefox</0> поддържа <1>DNS-over-HTTPS</1>.",
|
||||||
|
"setup_dns_privacy_other_5": "Ще намерите повече реализации <0>тук</0> и <1>тук</1>.",
|
||||||
|
"setup_dns_privacy_ioc_mac": "Конфигурация за iOS и macOS",
|
||||||
|
"setup_dns_notice": "За да използвате <1>DNS-over-HTTPS</1> или <1>DNS-over-TLS</1>, трябва да <0>конфигурирате Шифроване</0> в настройките на AdGuard Home.",
|
||||||
|
"rewrite_added": "DNS презапис за \"{{key}}\" успешно добавен",
|
||||||
|
"rewrite_deleted": "DNS презапис за \"{{key}}\" успешно изтрит",
|
||||||
|
"rewrite_updated": "ДНС перезаписването беше успешно актуализирано",
|
||||||
|
"rewrite_add": "Добави DNS презапис",
|
||||||
|
"rewrite_edit": "Редактиране на ДНС перезаписване",
|
||||||
|
"rewrite_not_found": "Не са намерени DNS презаписи",
|
||||||
|
"rewrite_confirm_delete": "Сигурни ли сте, че искате да изтриете DNS презапис за \"{{key}}\"?",
|
||||||
|
"rewrite_desc": "Позволява лесно да конфигурирате персонализиран DNS отговор за конкретно име на домейн.",
|
||||||
|
"rewrite_applied": "Правилото за презапис е приложено",
|
||||||
|
"rewrite_hosts_applied": "Преписано по правило на файла hosts",
|
||||||
|
"dns_rewrites": "DNS презаписи",
|
||||||
|
"form_domain": "Въведете име на домейн или wildcard",
|
||||||
|
"form_answer": "Въведете IP адрес или име на домейн",
|
||||||
|
"form_error_domain_format": "Невалиден формат на домейн",
|
||||||
|
"form_error_answer_format": "Невалиден формат на отговор",
|
||||||
|
"configure": "Конфигурация",
|
||||||
|
"main_settings": "Основни настройки",
|
||||||
|
"block_services": "Блокиране на специфични услуги",
|
||||||
|
"blocked_services": "Блокирани услуги",
|
||||||
|
"blocked_services_desc": "Позволява бързо блокиране на популярни сайтове и услуги.",
|
||||||
|
"blocked_services_saved": "Блокираните услуги успешно запазени",
|
||||||
|
"blocked_services_global": "Използвайте глобални блокирани услуги",
|
||||||
|
"blocked_service": "Блокирана услуга",
|
||||||
|
"block_all": "Блокирайте всичко",
|
||||||
|
"unblock_all": "Отблокирай всичко",
|
||||||
|
"encryption_certificate_path": "Път на удостоверението",
|
||||||
|
"encryption_private_key_path": "Път на частния ключ",
|
||||||
|
"encryption_certificates_source_path": "Задайте път за файл на сертификатите",
|
||||||
|
"encryption_certificates_source_content": "Поставете съдържанието на сертификатите",
|
||||||
|
"encryption_key_source_path": "Задайте файл на ключа",
|
||||||
|
"encryption_key_source_content": "Поставете съдържанието на ключа",
|
||||||
|
"stats_params": "Конфигурация на статистиката",
|
||||||
|
"config_successfully_saved": "Конфигурацията беше успешно запазена",
|
||||||
"interval_6_hour": "6 часа",
|
"interval_6_hour": "6 часа",
|
||||||
"interval_24_hour": "24 часа",
|
"interval_24_hour": "24 часа",
|
||||||
|
"interval_days": "{{count}} ден",
|
||||||
|
"interval_days_plural": "{{count}} дни",
|
||||||
"domain": "Домейн",
|
"domain": "Домейн",
|
||||||
"ecs": "ECS",
|
"ecs": "ECS",
|
||||||
|
"punycode": "Punycode",
|
||||||
|
"answer": "Отговор",
|
||||||
|
"filter_added_successfully": "Списъкът беше успешно добавен",
|
||||||
|
"filter_removed_successfully": "Списъкът е успешно премахнат",
|
||||||
|
"filter_updated": "Списъкът е актуализиран успешно",
|
||||||
|
"statistics_configuration": "Конфигурация на статистиката",
|
||||||
|
"statistics_retention": "Запазване на статистиката",
|
||||||
|
"statistics_retention_desc": "Ако намалите стойността на интервала, някои данни ще бъдат загубени",
|
||||||
"statistics_clear": "Нулирай статистиката",
|
"statistics_clear": "Нулирай статистиката",
|
||||||
|
"statistics_clear_confirm": "Наистина ли искате да изчистите статистиката?",
|
||||||
|
"statistics_retention_confirm": "Наистина ли искате да промените запазването на статистиките? Ако намалите стойността на интервала, някои данни ще бъдат изгубени",
|
||||||
|
"statistics_cleared": "Статистиките бяха успешно изчистени",
|
||||||
|
"statistics_enable": "Активиране на статистиките",
|
||||||
|
"ignore_domains": "Игнорирани домейни (разделени с нов ред)",
|
||||||
|
"ignore_domains_title": "Игнорирани домейни",
|
||||||
|
"ignore_domains_desc_stats": "Запитванията за тези домейни не се записват в статистиката",
|
||||||
|
"ignore_domains_desc_query": "Запитванията за тези домейни не се записват в дневника на запитванията",
|
||||||
|
"interval_hours": "{{count}} час",
|
||||||
|
"interval_hours_plural": "{{count}} часа",
|
||||||
|
"filters_configuration": "Конфигурация на филтри",
|
||||||
|
"filters_enable": "Активиране на филтри",
|
||||||
|
"filters_interval": "Интервал за актуализация на филтрите",
|
||||||
"disabled": "Изключен",
|
"disabled": "Изключен",
|
||||||
"username_label": "Потребител",
|
"username_label": "Потребител",
|
||||||
"username_placeholder": "Въведете потребител",
|
"username_placeholder": "Въведете потребител",
|
||||||
"password_label": "Парола",
|
"password_label": "Парола",
|
||||||
"password_placeholder": "Въведете парола",
|
"password_placeholder": "Въведете парола",
|
||||||
|
"sign_in": "Вход",
|
||||||
|
"sign_out": "Изход",
|
||||||
|
"forgot_password": "Забравили сте паролата?",
|
||||||
|
"forgot_password_desc": "Моля, следвайте <0>тези стъпки</0>, за да създадете нова парола за вашия акаунт.",
|
||||||
|
"location": "Местоположение",
|
||||||
|
"orgname": "Име на организацията",
|
||||||
|
"netname": "Име на мрежата",
|
||||||
"network": "Мрежа",
|
"network": "Мрежа",
|
||||||
"descr": "Описание",
|
"descr": "Описание",
|
||||||
|
"whois": "WHOIS",
|
||||||
|
"filtering_rules_learn_more": "<0>Научете повече</0> за създаването на собствени списъци с хостове.",
|
||||||
|
"blocked_by_response": "Блокирано от CNAME или IP в отговор",
|
||||||
|
"blocked_by_cname_or_ip": "Блокирано от CNAME или IP",
|
||||||
"try_again": "Опитай пак",
|
"try_again": "Опитай пак",
|
||||||
|
"domain_desc": "Въведете име на домейн или wildcard, който искате да бъде пренаписан.",
|
||||||
|
"example_rewrite_domain": "пренапиши отговорите само за това име на домейн.",
|
||||||
|
"example_rewrite_wildcard": "пренапиши отговорите за всички <0>example.org</0> поддомейни.",
|
||||||
|
"rewrite_ip_address": "IP адрес: използвайте този IP в отговор A или AAAA",
|
||||||
|
"rewrite_domain_name": "Име на домейн: добавете запис CNAME",
|
||||||
|
"rewrite_A": "<0>A</0>: специална стойност, запазете <0>A</0> записи от upstream",
|
||||||
|
"rewrite_AAAA": "<0>AAAA</0>: специална стойност, запазете <0>AAAA</0> записи от upstream",
|
||||||
"disable_ipv6": "Изключете IPv6 протокола",
|
"disable_ipv6": "Изключете IPv6 протокола",
|
||||||
|
"disable_ipv6_desc": "Отхвърли всички DNS запитвания за IPv6 адреси (тип AAAA) и премахни IPv6 подсказките от HTTPS отговорите.",
|
||||||
|
"fastest_addr": "Най-бърз IP адрес",
|
||||||
|
"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 (презареждане на услугата systemd-resolved)</0>",
|
||||||
|
"autofix_warning_result": "В резултат на това всички DNS заявки от вашата система ще бъдат обработвани от AdGuard Home по подразбиране.",
|
||||||
|
"tags_title": "Тагове",
|
||||||
|
"tags_desc": "Можете да изберете таговете, които съответстват на клиента. Включете таговете в правилата за филтриране, за да ги приложите по-точно. <0>Научете повече</0>.",
|
||||||
|
"form_select_tags": "Изберете тагове на клиента",
|
||||||
|
"check_title": "Проверете филтрирането",
|
||||||
|
"check_desc": "Проверете дали името на хоста е филтрирано.",
|
||||||
|
"check": "Провери",
|
||||||
|
"form_enter_host": "Въведете име на хост.",
|
||||||
|
"filtered_custom_rules": "Филтрирано по персонализирани правила за филтриране",
|
||||||
|
"choose_from_list": "Изберете от списъка",
|
||||||
|
"add_custom_list": "Добавете персонализиран списък",
|
||||||
|
"host_whitelisted": "Хостът е разрешен",
|
||||||
|
"check_ip": "IP адреси: {{ip}}",
|
||||||
|
"check_cname": "CNAME: {{cname}}",
|
||||||
|
"check_reason": "Причина: {{reason}}",
|
||||||
|
"check_service": "Име на услугата: {{service}}",
|
||||||
|
"check_hostname": "Име на хост или домейн",
|
||||||
|
"check_client_id": "Идентификатор на клиента (ClientID или IP адрес)",
|
||||||
|
"check_enter_client_id": "Въведете идентификатор на клиента",
|
||||||
|
"check_dns_record": "Изберете тип DNS запис",
|
||||||
|
"service_name": "Име на услугата",
|
||||||
|
"check_not_found": "Не е намерено в списъците ви с филтри",
|
||||||
|
"client_confirm_block": "Наистина ли искате да блокирате клиента \"{{ip}}\"?",
|
||||||
|
"client_confirm_unblock": "Наистина ли искате да деблокирате клиента \"{{ip}}\"?",
|
||||||
|
"client_blocked": "Клиентът \"{{ip}}\" е успешно блокиран",
|
||||||
|
"client_unblocked": "Клиентът \"{{ip}}\" е успешно деблокиран",
|
||||||
|
"static_ip": "Статичен IPv4 адрес",
|
||||||
|
"static_ip_desc": "AdGuard Home е сървър, затова му е нужна статична IP адреса, за да функционира правилно. В противен случай, в определен момент, вашия рутер може да присвои различен IP адрес на това устройство.",
|
||||||
|
"set_static_ip": "Задайте статичен IP адрес",
|
||||||
|
"install_static_ok": "Добри новини! Статичният IP адрес вече е конфигуриран",
|
||||||
|
"install_static_error": "AdGuard Home не може автоматично да го конфигурира за този мрежов интерфейс. Моля, потърсете инструкция как да го направите ръчно.",
|
||||||
|
"install_static_configure": "AdGuard Home е открил, че динамичният IP адрес <0>{{ip}}</0> се използва. Искате ли да бъде зададен като ваш статичен адрес?",
|
||||||
|
"confirm_static_ip": "AdGuard Home ще конфигурира {{ip}} да бъде вашият статичен IP адрес. Искате ли да продължите?",
|
||||||
|
"list_updated": "{{count}} списък актуализиран",
|
||||||
|
"list_updated_plural": "{{count}} списъка актуализирани",
|
||||||
|
"dnssec_enable": "Включете DNSSEC",
|
||||||
|
"dnssec_enable_desc": "Задайте флага DNSSEC в изходящите DNS запитвания и проверете резултата (нужен е резолвер с активиран DNSSEC).",
|
||||||
|
"validated_with_dnssec": "Проверено с DNSSEC",
|
||||||
|
"all_queries": "Всички запитвания",
|
||||||
"show_blocked_responses": "Блокирано",
|
"show_blocked_responses": "Блокирано",
|
||||||
"show_whitelisted_responses": "В белия списък",
|
"show_whitelisted_responses": "В белия списък",
|
||||||
"show_processed_responses": "Обработен",
|
"show_processed_responses": "Обработен",
|
||||||
|
"blocked_safebrowsing": "Блокирано от безопасно сърфиране",
|
||||||
|
"blocked_adult_websites": "Блокирано от Родителски Надзор",
|
||||||
|
"blocked_threats": "Блокирани заплахи",
|
||||||
"allowed": "В белия списък",
|
"allowed": "В белия списък",
|
||||||
|
"filtered": "Филтрирано",
|
||||||
|
"rewritten": "Преработено",
|
||||||
"safe_search": "Безопасно търсене",
|
"safe_search": "Безопасно търсене",
|
||||||
"blocklist": "Черен списък",
|
"blocklist": "Черен списък",
|
||||||
|
"milliseconds_abbreviation": "мс",
|
||||||
|
"cache_size": "Размер на кеша",
|
||||||
|
"cache_size_desc": "Размер на кеша на DNS (в байтове). За да деактивирате кеширането, задайте на 0.",
|
||||||
|
"cache_ttl_min_override": "Преобръщане на минималния TTL",
|
||||||
|
"cache_ttl_max_override": "Презаписване на максимален TTL",
|
||||||
|
"enter_cache_size": "Въведете размер на кеша (байтове)",
|
||||||
|
"enter_cache_ttl_min_override": "Въведете минимален TTL (секунди)",
|
||||||
|
"enter_cache_ttl_max_override": "Въведете максимален TTL (секунди)",
|
||||||
|
"cache_ttl_min_override_desc": "Разширете кратките стойности на времето на живот (секунди), получени от upstream сървъра при кеширане на DNS отговори.",
|
||||||
|
"cache_ttl_max_override_desc": "Задайте максимална стойност на времето за живот (секунди) за записи в кеша на DNS.",
|
||||||
|
"ttl_cache_validation": "Минималната стойност на TTL за кеша трябва да бъде по-малка или равна на максималната",
|
||||||
|
"cache_optimistic": "Оптимистично кеширане",
|
||||||
|
"cache_optimistic_desc": "Нека AdGuard Home да отговори от кеша дори когато записите са изтекли и също така опитайте да ги обновите.",
|
||||||
"filter_category_general": "General",
|
"filter_category_general": "General",
|
||||||
"filter_category_security": "Сигурност",
|
"filter_category_security": "Сигурност",
|
||||||
|
"filter_category_regional": "Регионални",
|
||||||
"filter_category_other": "Друго",
|
"filter_category_other": "Друго",
|
||||||
|
"filter_category_general_desc": "Списъци, които блокират проследяването и рекламата на повечето устройства",
|
||||||
|
"filter_category_security_desc": "Списъци, предназначени специално за блокиране на злонамерени, фишинг и измамни домейни",
|
||||||
|
"filter_category_regional_desc": "Списъци, които се фокусират върху регионалните реклами и сървърите за проследяване",
|
||||||
|
"filter_category_other_desc": "Други списъци с блокиране",
|
||||||
|
"setup_config_to_enable_dhcp_server": "Настройка на конфигурация за активиране на DHCP сървър",
|
||||||
|
"original_response": "Оригинален отговор",
|
||||||
|
"click_to_view_queries": "Натиснете, за да видите запитвания",
|
||||||
"port_53_faq_link": "Порт 53 често е зает от \"DNSStubListener\" или \"systemd-resolved\" услуги. Моля, прочетете <0>тази инструкция</0> как да решите това.",
|
"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}}\" ще ДЕАКТИВИРА списъка с \"Разрешени клиенти\".",
|
||||||
|
"use_saved_key": "Използвайте предварително запазения ключ",
|
||||||
"parental_control": "Родителски контрол",
|
"parental_control": "Родителски контрол",
|
||||||
|
"safe_browsing": "Безопасно сърфиране",
|
||||||
|
"served_from_cache_label": "Предоставено от кеша",
|
||||||
|
"form_error_password_length": "Паролата трябва да бъде дълга от {{min}} до {{max}} символа",
|
||||||
|
"anonymizer_notification": "<0>Забележка:</0> Анонимизация на IP е включена. Можете да я деактивирате в <1>Общите настройки</1>.",
|
||||||
|
"confirm_dns_cache_clear": "Сигурни ли сте, че искате да изчистите кеша на DNS?",
|
||||||
|
"cache_cleared": "Кешът на DNS успешно изчистен",
|
||||||
|
"clear_cache": "Изчисти кеша",
|
||||||
|
"make_static": "Направи статичен",
|
||||||
|
"theme_auto_desc": "Авто (въз основа на цветната схема на вашето устройство)",
|
||||||
|
"theme_dark_desc": "Тъмна тема",
|
||||||
|
"theme_light_desc": "Светла тема",
|
||||||
|
"disable_for_seconds": "За {{count}} секунди",
|
||||||
|
"disable_for_seconds_plural": "За {{count}} секунди",
|
||||||
|
"disable_for_minutes": "За {{count}} минута",
|
||||||
|
"disable_for_minutes_plural": "За {{count}} минути",
|
||||||
|
"disable_for_hours": "За {{count}} час",
|
||||||
|
"disable_for_hours_plural": "За {{count}} часа",
|
||||||
|
"disable_until_tomorrow": "До утре",
|
||||||
|
"disable_notify_for_seconds": "Отключи защитата за {{count}} секунда",
|
||||||
|
"disable_notify_for_seconds_plural": "Деактивиране на защитата за {{count}} секунди",
|
||||||
|
"disable_notify_for_minutes": "Деактивиране на защитата за {{count}} минута",
|
||||||
|
"disable_notify_for_minutes_plural": "Деактивиране на защитата за {{count}} минути",
|
||||||
|
"disable_notify_for_hours": "Деактивиране на защитата за {{count}} час",
|
||||||
|
"disable_notify_for_hours_plural": "Деактивиране на защитата за {{count}} часа",
|
||||||
|
"disable_notify_until_tomorrow": "Деактивиране на защитата до утре",
|
||||||
|
"enable_protection_timer": "Защитата ще бъде активирана след {{time}}",
|
||||||
|
"custom_retention_input": "Въведете срок на задържане в часове",
|
||||||
|
"custom_rotation_input": "Въведете ротация в часове",
|
||||||
|
"protection_section_label": "Защита",
|
||||||
|
"log_and_stats_section_label": "Лог на заявките и статистика",
|
||||||
|
"ignore_query_log": "Игнорирайте този клиент в логовете на заявките",
|
||||||
|
"ignore_statistics": "Игнорирайте този клиент в статистиките",
|
||||||
|
"schedule_services": "Пауза на блокирането на услугата",
|
||||||
|
"schedule_services_desc": "Конфигурирайте графика за паузи на филтъра за блокиране на услуги",
|
||||||
|
"schedule_services_desc_client": "Конфигурирайте графика за паузи на филтъра за блокиране на услуги за този клиент",
|
||||||
|
"schedule_desc": "Настройте периодите на неактивност за блокираните услуги",
|
||||||
|
"schedule_invalid_select": "Времето за начало трябва да е преди времето за край",
|
||||||
|
"schedule_select_days": "Изберете дни",
|
||||||
|
"schedule_timezone": "Изберете часова зона",
|
||||||
|
"schedule_current_timezone": "Текуща часова зона: {{value}}",
|
||||||
|
"schedule_time_all_day": "Цял ден",
|
||||||
|
"schedule_modal_description": "Този график ще замени всички съществуващи графици за същия ден от седмицата. Всеки ден от седмицата може да има само един период на неактивност.",
|
||||||
|
"schedule_modal_time_off": "Няма блокиране на услуги:",
|
||||||
|
"schedule_new": "Нов график",
|
||||||
|
"schedule_edit": "Редактиране на график",
|
||||||
|
"schedule_save": "Запиши графика",
|
||||||
|
"schedule_add": "Добавяне на график",
|
||||||
|
"schedule_remove": "Премахване на график",
|
||||||
|
"schedule_from": "От",
|
||||||
|
"schedule_to": "До",
|
||||||
|
"sunday": "Неделя",
|
||||||
|
"monday": "Понеделник",
|
||||||
|
"tuesday": "Вторник",
|
||||||
|
"wednesday": "Сряда",
|
||||||
|
"thursday": "Четвъртък",
|
||||||
|
"friday": "Петък",
|
||||||
|
"saturday": "Събота",
|
||||||
"sunday_short": "Нд",
|
"sunday_short": "Нд",
|
||||||
"monday_short": "Пон",
|
"monday_short": "Пон",
|
||||||
"tuesday_short": "Вт",
|
"tuesday_short": "Вт",
|
||||||
"wednesday_short": "Ср",
|
"wednesday_short": "Ср",
|
||||||
"thursday_short": "Чт",
|
"thursday_short": "Чт",
|
||||||
"friday_short": "Пт",
|
"friday_short": "Пт",
|
||||||
"saturday_short": "Съб"
|
"saturday_short": "Съб",
|
||||||
|
"upstream_dns_cache_configuration": "Конфигурация на кеша на upstream DNS",
|
||||||
|
"enable_upstream_dns_cache": "Активирайте кеширането на DNS за тази персонализирана конфигурация на upstream на клиента",
|
||||||
|
"dns_cache_size": "Размер на кеша на DNS, в байтове"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,26 @@
|
|||||||
{
|
{
|
||||||
"client_settings": "تنظیمات کلاینت",
|
"client_settings": "تنظیمات کلاینت",
|
||||||
"example_upstream_reserved": "میتوانید جریان ارسالی DNS <0> را برای یک دامنه مشخص تعیین کنید </0>",
|
"example_upstream_reserved": "میتوانید جریان ارسالی DNS <0> را برای یک دامنه مشخص تعیین کنید </0>",
|
||||||
|
"example_multiple_upstreams_reserved": "میتوانید چندین سرور بالادست را برای دامنههای خاص تعیین کنید؛",
|
||||||
"example_upstream_comment": "یک نظر.",
|
"example_upstream_comment": "یک نظر.",
|
||||||
"upstream_parallel": "استفاده از جستار موازی برای سرعت دادن به تفکیک با جستار همزمان همه جریان های ارسالی",
|
"upstream_parallel": "استفاده از جستار موازی برای سرعت دادن به تفکیک با جستار همزمان همه جریان های ارسالی",
|
||||||
"parallel_requests": "درخواست های موازی",
|
"parallel_requests": "درخواست های موازی",
|
||||||
"load_balancing": "متعادل کننده بار",
|
"load_balancing": "متعادل کننده بار",
|
||||||
"load_balancing_desc": "یک سرور بالادستی را در یک زمان پرس و جو کنید. AdGuard Home از الگوریتم تصادفی وزنی خود برای انتخاب سرور استفاده می کند تا سریع ترین سرور بیشتر مورد استفاده قرار گیرد.",
|
"load_balancing_desc": "یک سرور بالادستی را در یک زمان پرسوجو کنید.<br/>AdGuard Home از یک الگوریتم تصادفی وزنی برای انتخاب سرورهایی با کمترین تعداد جستجوی ناموفق و کمترین میانگین زمان جستجو استفاده میکند.",
|
||||||
"bootstrap_dns": "خودراه انداز سرورهای DNS",
|
"bootstrap_dns": "خودراه انداز سرورهای DNS",
|
||||||
"bootstrap_dns_desc": "آدرسهای IP سرورهای DNS که برای حل کردن آدرسهای IP حلکنندههای DoH/DoT که بهعنوان upstream مشخص میکنید، استفاده میشوند. اظهار نظر مجاز نیست.",
|
"bootstrap_dns_desc": "آدرسهای IP سرورهای DNS که برای حل کردن آدرسهای IP حلکنندههای DoH/DoT که بهعنوان upstream مشخص میکنید، استفاده میشوند. اظهار نظر مجاز نیست.",
|
||||||
"fallback_dns_title": "سرورهای DNS بازگشتی",
|
"fallback_dns_title": "سرورهای DNS بازگشتی",
|
||||||
"fallback_dns_desc": "لیست سرورهای DNS بازگشتی که در زمانی که سرورهای DNS بالادستی پاسخ نمیدهند استفاده میشوند. نحو مانند فیلد بالادستی اصلی بالا است.",
|
"fallback_dns_desc": "لیست سرورهای DNS بازگشتی که در زمانی که سرورهای DNS بالادستی پاسخ نمیدهند استفاده میشوند. نحو مانند فیلد بالادستی اصلی بالا است.",
|
||||||
"fallback_dns_placeholder": "یک سرور DNS بازگشتی در هر خط وارد کنید",
|
"fallback_dns_placeholder": "یک سرور DNS بازگشتی در هر خط وارد کنید",
|
||||||
"local_ptr_title": "سرورهای خصوصی DNS",
|
"local_ptr_title": "سرورهای خصوصی DNS",
|
||||||
"local_ptr_desc": "سرور یا سرور های DNS ای که AdGuard Home برای درخواست های منابع محلی ارائه شده مورد استفاده قرار خواهد داد. برای مثال، این سرور برای تعیین نام های سرویس دهنده برای سرویس گیرنده با آدرس های آی پی خصوصی مورد استفاده قرار خواهد گرفت. اگر تعیین نشود،AdGuard Home به طور خودکار از تعیین کننده ی DNS پیش فرض شما استفاده خواهد کرد.",
|
"local_ptr_desc": "سرورهای DNS که توسط AdGuard Home برای درخواستهای خصوصی PTR، SOA و NS استفاده میشوند. اگر درخواست یک دامنه ARPA حاوی یک زیرشبکه در محدوده IP خصوصی (مانند \"192.168.12.34\") و از مشتری با آدرس IP خصوصی باشد، خصوصی در نظر گرفته می شود. اگر تنظیم نشود، به جز آدرسهای IP Home AdGuard، از حلکنندههای پیشفرض DNS سیستم عامل شما استفاده میشود.",
|
||||||
"local_ptr_default_resolver": "به طور پیش فرض، AdGuard Home از تعیین کننده های DNS معکوس زیر استفاده می کند: {{ip}}.",
|
"local_ptr_default_resolver": "به طور پیش فرض، AdGuard Home از تعیین کننده های DNS معکوس زیر استفاده می کند: {{ip}}.",
|
||||||
"local_ptr_no_default_resolver": "AdGuard Home نتوانست برای این دستگاه تعیین کننده های DNS معکوس محرمانه مناسب را معین کند.",
|
"local_ptr_no_default_resolver": "AdGuard Home نتوانست برای این دستگاه تعیین کننده های DNS معکوس محرمانه مناسب را معین کند.",
|
||||||
"local_ptr_placeholder": "در هر خط یک آدرس سرور را وارد کنید",
|
"local_ptr_placeholder": "یک آدرس IP در هر خط وارد کنید",
|
||||||
"resolve_clients_title": "فعال سازی تعیین نام های سرویس دهنده ی سرویس گیرندگان",
|
"resolve_clients_title": "فعال سازی تعیین نام های سرویس دهنده ی سرویس گیرندگان",
|
||||||
"resolve_clients_desc": "در صورت فعال بودن،AdGuard Home به طور خودکار اقدام به تعیین نام های سرویس دهنده ی سرویس گیرندگان از آدرس های آی پی با ارسال یک درخواست PTR به یک تعیین کننده ی همتا خواهد کرد (سرور خصوصی DNS برای سرویس گیرندگان محلی،سرور مادر برای سرویس گیرندگان با آی پی عمومی).",
|
"resolve_clients_desc": "در صورت فعال بودن،AdGuard Home به طور خودکار اقدام به تعیین نام های سرویس دهنده ی سرویس گیرندگان از آدرس های آی پی با ارسال یک درخواست PTR به یک تعیین کننده ی همتا خواهد کرد (سرور خصوصی DNS برای سرویس گیرندگان محلی،سرور مادر برای سرویس گیرندگان با آی پی عمومی).",
|
||||||
"use_private_ptr_resolvers_title": "از تعیین کننده های rDNS محرمانه استفاده کنید",
|
"use_private_ptr_resolvers_title": "از تعیین کننده های rDNS محرمانه استفاده کنید",
|
||||||
"use_private_ptr_resolvers_desc": "داده گیری های دی ان اس معکوس را برای آدرس های اینترنتی خدمات منظقه ای با استفاده از سرور های مادر اجرا کنید. چنانچه غیر فعال باشد،AdGuard Home با NXDOMAIN به همه چنین درخواست های PTR پاسخ می دهد به استثناء خدمات گیرنده های شناخته شده از طرف DHCP،/و غیره/هوست ها، و سایر.",
|
"use_private_ptr_resolvers_desc": "درخواستهای PTR، SOA، و NS را برای دامنههای ARPA حاوی آدرسهای IP خصوصی از طریق سرورهای بالادستی خصوصی، DHCP، /etc/hostها و غیره حل کنید. اگر غیرفعال باشد، AdGuard Home به همه این درخواستها با NXDOMAIN پاسخ میدهد.",
|
||||||
"check_dhcp_servers": "بررسی برای سرورهای DHCP",
|
"check_dhcp_servers": "بررسی برای سرورهای DHCP",
|
||||||
"save_config": "ذخیره پیکربندی",
|
"save_config": "ذخیره پیکربندی",
|
||||||
"enabled_dhcp": "سرور DHCP فعال شده است",
|
"enabled_dhcp": "سرور DHCP فعال شده است",
|
||||||
@@ -73,7 +74,9 @@
|
|||||||
"dhcp_dynamic_ip_found": "سیستم شما آدرس آی پی متغییر برای این رابط استفاده می کند <0>{{interfaceName}}</0>. به منظور استفاده از سرور DHCP آدرس ثابت باید تعیین شود. آدرس آی پی فعلی شما هست <0>{{ipAddress}}</0>. اگر شما دکمه DHCP را فشار دهید ما این آدرس آی پی را بعنوان ثابت تنظیم می کنیم.",
|
"dhcp_dynamic_ip_found": "سیستم شما آدرس آی پی متغییر برای این رابط استفاده می کند <0>{{interfaceName}}</0>. به منظور استفاده از سرور DHCP آدرس ثابت باید تعیین شود. آدرس آی پی فعلی شما هست <0>{{ipAddress}}</0>. اگر شما دکمه DHCP را فشار دهید ما این آدرس آی پی را بعنوان ثابت تنظیم می کنیم.",
|
||||||
"dhcp_lease_added": "اجاره ایستا \"{{key}}\" با موفقیت اضافه شد",
|
"dhcp_lease_added": "اجاره ایستا \"{{key}}\" با موفقیت اضافه شد",
|
||||||
"dhcp_lease_deleted": "اجاره ایستا \"{{key}}\" با موفقیت حذف شد",
|
"dhcp_lease_deleted": "اجاره ایستا \"{{key}}\" با موفقیت حذف شد",
|
||||||
|
"dhcp_lease_updated": "اجاره ایستا \"{{key}}\" با موفقیت به روزرسانی شد",
|
||||||
"dhcp_new_static_lease": "اجاره ایستا جدید",
|
"dhcp_new_static_lease": "اجاره ایستا جدید",
|
||||||
|
"dhcp_edit_static_lease": "ویرایش اجاره ایستا",
|
||||||
"dhcp_static_leases_not_found": "هیچ اجاره DHCP ایستا یافت نشد",
|
"dhcp_static_leases_not_found": "هیچ اجاره DHCP ایستا یافت نشد",
|
||||||
"dhcp_add_static_lease": "افزودن اجاره ایستا",
|
"dhcp_add_static_lease": "افزودن اجاره ایستا",
|
||||||
"dhcp_reset_leases": "بازگردانی همه مجوزهای منابع",
|
"dhcp_reset_leases": "بازگردانی همه مجوزهای منابع",
|
||||||
@@ -117,7 +120,8 @@
|
|||||||
"stats_malware_phishing": "بدافزار/فیشینگ مسدود شده است",
|
"stats_malware_phishing": "بدافزار/فیشینگ مسدود شده است",
|
||||||
"stats_adult": "وبسایت غیراخلاقی مسدود شده است",
|
"stats_adult": "وبسایت غیراخلاقی مسدود شده است",
|
||||||
"stats_query_domain": "دامنه جستار بالا",
|
"stats_query_domain": "دامنه جستار بالا",
|
||||||
"for_last_24_hours": "برای 24 ساعت گذشته",
|
"for_last_hours": "برای {{count}} ساعت گذشته",
|
||||||
|
"for_last_hours_plural": "برای {{count}} ساعت گذشته",
|
||||||
"for_last_days": "برای {{count}} روز آخر",
|
"for_last_days": "برای {{count}} روز آخر",
|
||||||
"for_last_days_plural": "برای {{count}} روز گذشته",
|
"for_last_days_plural": "برای {{count}} روز گذشته",
|
||||||
"stats_disabled": "آمار غیرفعال شده است. شما می توانید از قسمت <0>صفحه تنظیمات</0> آن را روشن نمایید.",
|
"stats_disabled": "آمار غیرفعال شده است. شما می توانید از قسمت <0>صفحه تنظیمات</0> آن را روشن نمایید.",
|
||||||
@@ -132,13 +136,16 @@
|
|||||||
"no_upstreams_data_found": "هیچ اطلاعاتی در مورد سرورهای بالادست یافت نشد",
|
"no_upstreams_data_found": "هیچ اطلاعاتی در مورد سرورهای بالادست یافت نشد",
|
||||||
"number_of_dns_query_days": "تعداد جستار DNS پردازش شده در {{count}} روز آخر",
|
"number_of_dns_query_days": "تعداد جستار DNS پردازش شده در {{count}} روز آخر",
|
||||||
"number_of_dns_query_days_plural": "تعداد جستار DNS پردازش شده در {{count}} روز گذشته",
|
"number_of_dns_query_days_plural": "تعداد جستار DNS پردازش شده در {{count}} روز گذشته",
|
||||||
"number_of_dns_query_24_hours": "تعداد جستار DNS پردازش شده در 24 ساعت گذشته",
|
"number_of_dns_query_hours": "تعداد جستارهای DNS پردازش شده برای {{count}} ساعت گذشته",
|
||||||
|
"number_of_dns_query_hours_plural": "تعداد جستارهای DNS پردازش شده برای {{count}} ساعت گذشته",
|
||||||
"number_of_dns_query_blocked_24_hours": "تعداد درخواست DNS مسدود شده با فیلترهای مسدودساز تبلیغ و لیست سیاه میزبان",
|
"number_of_dns_query_blocked_24_hours": "تعداد درخواست DNS مسدود شده با فیلترهای مسدودساز تبلیغ و لیست سیاه میزبان",
|
||||||
"number_of_dns_query_blocked_24_hours_by_sec": "تعداد درخواست DNS مسدود شده با مدل امنیت وب گردی AdGuard",
|
"number_of_dns_query_blocked_24_hours_by_sec": "تعداد درخواست DNS مسدود شده با مدل امنیت وب گردی AdGuard",
|
||||||
"number_of_dns_query_blocked_24_hours_adult": "تعداد وبسایت های غیر اخلاقی مسدود شده",
|
"number_of_dns_query_blocked_24_hours_adult": "تعداد وبسایت های غیر اخلاقی مسدود شده",
|
||||||
"enforced_save_search": "جستجوی اَمن اجبار شده",
|
"enforced_save_search": "جستجوی اَمن اجبار شده",
|
||||||
"number_of_dns_query_to_safe_search": "تعداد درخواست های DNS برای موتور جستجو که جستجوی اَمن اجبار شده",
|
"number_of_dns_query_to_safe_search": "تعداد درخواست های DNS برای موتور جستجو که جستجوی اَمن اجبار شده",
|
||||||
"average_processing_time": "میانگین زمان پردازش",
|
"average_processing_time": "میانگین زمان پردازش",
|
||||||
|
"average_upstream_response_time": "میانگین زمان پاسخ دهی بالادست",
|
||||||
|
"response_time": "زمان پاسخ",
|
||||||
"average_processing_time_hint": "زمان میانگین بر هزارم ثانیه در پردازش درخواست DNS",
|
"average_processing_time_hint": "زمان میانگین بر هزارم ثانیه در پردازش درخواست DNS",
|
||||||
"block_domain_use_filters_and_hosts": "مسدودسازی دامنه ها توسط فیلترها و فایل های میزبان",
|
"block_domain_use_filters_and_hosts": "مسدودسازی دامنه ها توسط فیلترها و فایل های میزبان",
|
||||||
"filters_block_toggle_hint": "میتوانید دستورات مسدودسازی را در تنظیمات <a>فیلترها</a> راه اندازی کنید.",
|
"filters_block_toggle_hint": "میتوانید دستورات مسدودسازی را در تنظیمات <a>فیلترها</a> راه اندازی کنید.",
|
||||||
@@ -147,7 +154,7 @@
|
|||||||
"use_adguard_parental": "از سرویس وب نظارت والدین AdGuard استفاده کن",
|
"use_adguard_parental": "از سرویس وب نظارت والدین AdGuard استفاده کن",
|
||||||
"use_adguard_parental_hint": "AdGuard Home بررسی می کند اگر دامنه حاوی موارد غیر اخلاقی است.آن از همان اِی پی آی دارای حریم خصوصی سرویس وب امنیت وب گردی استفاده می کند.",
|
"use_adguard_parental_hint": "AdGuard Home بررسی می کند اگر دامنه حاوی موارد غیر اخلاقی است.آن از همان اِی پی آی دارای حریم خصوصی سرویس وب امنیت وب گردی استفاده می کند.",
|
||||||
"enforce_safe_search": "اجبار جستجوی اَمن",
|
"enforce_safe_search": "اجبار جستجوی اَمن",
|
||||||
"enforce_save_search_hint": "AdGuard Home میتواند جستجوی اَمن را در موتور جستجوهای زیر اعمال کند:گوگل،یوتوب،بینگ و یاندکس",
|
"enforce_save_search_hint": "AdGuard Home جستجوی ایمن را در موتورهای جستجوی زیر اعمال می کند: Google، YouTube، Bing، DuckDuckGo، Ecosia، Yandex، Pixabay.",
|
||||||
"no_servers_specified": "سروری تعیین نشده است",
|
"no_servers_specified": "سروری تعیین نشده است",
|
||||||
"general_settings": "تنظیمات عمومی",
|
"general_settings": "تنظیمات عمومی",
|
||||||
"dns_settings": "تنظیمات DNS",
|
"dns_settings": "تنظیمات DNS",
|
||||||
@@ -159,6 +166,8 @@
|
|||||||
"encryption_settings": "تنظیمات رمزگُذاری",
|
"encryption_settings": "تنظیمات رمزگُذاری",
|
||||||
"dhcp_settings": "تنظیمات DHCP",
|
"dhcp_settings": "تنظیمات DHCP",
|
||||||
"upstream_dns": "سرورهای DNS جریان ارسالی",
|
"upstream_dns": "سرورهای DNS جریان ارسالی",
|
||||||
|
"upstream_dns_help": "یک آدرس سرور در هر خط وارد کنید. <a>درباره پیکربندی سرورهای DNS بالادستی</a> بیشتر بیاموزید.",
|
||||||
|
"upstream_dns_configured_in_file": "در {{path}} پیکربندی شده است",
|
||||||
"test_upstream_btn": "تست جریان ارسالی",
|
"test_upstream_btn": "تست جریان ارسالی",
|
||||||
"upstreams": "جریان ارسالی",
|
"upstreams": "جریان ارسالی",
|
||||||
"upstream": "سرور مادر",
|
"upstream": "سرور مادر",
|
||||||
@@ -171,6 +180,7 @@
|
|||||||
"enabled_parental_toast": "نظارت والدین فعال شده است",
|
"enabled_parental_toast": "نظارت والدین فعال شده است",
|
||||||
"disabled_safe_search_toast": "جستجوی اَمن غیرفعال شده",
|
"disabled_safe_search_toast": "جستجوی اَمن غیرفعال شده",
|
||||||
"enabled_save_search_toast": "جستجوی اَمن فعال شده",
|
"enabled_save_search_toast": "جستجوی اَمن فعال شده",
|
||||||
|
"updated_save_search_toast": "تنظیمات جستجوی ایمن به روز شد",
|
||||||
"enabled_table_header": "فعال شده",
|
"enabled_table_header": "فعال شده",
|
||||||
"name_table_header": "نام",
|
"name_table_header": "نام",
|
||||||
"list_url_table_header": "لیست آدرس",
|
"list_url_table_header": "لیست آدرس",
|
||||||
@@ -212,20 +222,29 @@
|
|||||||
"example_comment_hash": "# همچنین یک نظر",
|
"example_comment_hash": "# همچنین یک نظر",
|
||||||
"example_regex_meaning": "مسدودسازی دسترسی به دامنه مطابق <0>با عبارت منظم خاص</0>",
|
"example_regex_meaning": "مسدودسازی دسترسی به دامنه مطابق <0>با عبارت منظم خاص</0>",
|
||||||
"example_upstream_regular": "DNS عادی (بر UDP)",
|
"example_upstream_regular": "DNS عادی (بر UDP)",
|
||||||
|
"example_upstream_regular_port": "dNS معمولی (بیش از UDP، با پورت)؛;",
|
||||||
|
"example_upstream_udp": "DNS معمولی (از طریق UDP، نام میزبان)؛;",
|
||||||
"example_upstream_dot": "کُدگذاری شده <a href='https://en.wikipedia.org/wiki/DNS_over_TLS' target='_blank'>DNS-over-TLS</a>",
|
"example_upstream_dot": "کُدگذاری شده <a href='https://en.wikipedia.org/wiki/DNS_over_TLS' target='_blank'>DNS-over-TLS</a>",
|
||||||
"example_upstream_doh": "کُدگذاری شده <a href='https://en.wikipedia.org/wiki/DNS_over_HTTPS' target='_blank'>DNS-over-HTTPS</a>",
|
"example_upstream_doh": "کُدگذاری شده <a href='https://en.wikipedia.org/wiki/DNS_over_HTTPS' target='_blank'>DNS-over-HTTPS</a>",
|
||||||
|
"example_upstream_doh3": "DNS-over-HTTPS رمزگذاری شده با HTTP/3 اجباری و بدون بازگشت به HTTP/2 یا پایینتر؛",
|
||||||
|
"example_upstream_doq": "رمزگذاری شده <0>DNS-over-QUIC</0>;",
|
||||||
"example_upstream_sdns": "شما میتوانید از <a href='https://dnscrypt.info/stamps/' target='_blank'>DNS Stamps</a> برای <a href='https://dnscrypt.info/' target='_blank'>DNSCrypt</a> یا <a href='https://en.wikipedia.org/wiki/DNS_over_HTTPS' target='_blank'>DNS-over-HTTPS</a> resolvers استفاده کنید",
|
"example_upstream_sdns": "شما میتوانید از <a href='https://dnscrypt.info/stamps/' target='_blank'>DNS Stamps</a> برای <a href='https://dnscrypt.info/' target='_blank'>DNSCrypt</a> یا <a href='https://en.wikipedia.org/wiki/DNS_over_HTTPS' target='_blank'>DNS-over-HTTPS</a> resolvers استفاده کنید",
|
||||||
"example_upstream_tcp": "DNS عادی (بر TCP)",
|
"example_upstream_tcp": "DNS عادی (بر TCP)",
|
||||||
|
"example_upstream_tcp_port": "DNS معمولی (از طریق TCP، با پورت)؛;",
|
||||||
|
"example_upstream_tcp_hostname": "DNS معمولی (از طریق TCP، نام میزبان)؛;",
|
||||||
"all_lists_up_to_date_toast": "همه لیست ها از قبل بروز اند",
|
"all_lists_up_to_date_toast": "همه لیست ها از قبل بروز اند",
|
||||||
"updated_upstream_dns_toast": "سرورهای DNS جریان ارسالی بروز رسانی شده است",
|
"updated_upstream_dns_toast": "سرورهای DNS جریان ارسالی بروز رسانی شده است",
|
||||||
"dns_test_ok_toast": "سرورهای DNS تعیین شده بدرستی کار می کنند",
|
"dns_test_ok_toast": "سرورهای DNS تعیین شده بدرستی کار می کنند",
|
||||||
"dns_test_not_ok_toast": "سرور \"{{key}}\": نمیتواند مورد استفاده قرار گیرد،لطفا بررسی کنید آن را بدرستی نوشته اید",
|
"dns_test_not_ok_toast": "سرور \"{{key}}\": نمیتواند مورد استفاده قرار گیرد،لطفا بررسی کنید آن را بدرستی نوشته اید",
|
||||||
"dns_test_parsing_error_toast": "بخش {{section}}: خط {{line}}: نمیتواند مورد استفاده قرار گیرد،لطفا بررسی کنید آن را بهدرستی نوشتهاید",
|
"dns_test_parsing_error_toast": "بخش {{section}}: خط {{line}}: نمیتواند مورد استفاده قرار گیرد،لطفا بررسی کنید آن را بهدرستی نوشتهاید",
|
||||||
|
"dns_test_warning_toast": "بالادست \"{{key}}\" به درخواست های آزمایشی پاسخ نمیدهد و ممکن است به درستی کار نکند",
|
||||||
"unblock": "رفع انسداد",
|
"unblock": "رفع انسداد",
|
||||||
"block": "مسدود کردن",
|
"block": "مسدود کردن",
|
||||||
"disallow_this_client": "این مشتری را رد کنید",
|
"disallow_this_client": "این مشتری را رد کنید",
|
||||||
"allow_this_client": "به این مشتری اجازه دهید",
|
"allow_this_client": "به این مشتری اجازه دهید",
|
||||||
"block_for_this_client_only": "مسدود کردن فقط برای این مشتری",
|
"block_for_this_client_only": "مسدود کردن فقط برای این مشتری",
|
||||||
|
"unblock_for_this_client_only": "رفع مسدودیت فقط برای این کاربر",
|
||||||
|
"add_persistent_client": "به عنوان مشتری دائمی اضافه کنید",
|
||||||
"time_table_header": "زمان",
|
"time_table_header": "زمان",
|
||||||
"date": "تاریخ",
|
"date": "تاریخ",
|
||||||
"domain_name_table_header": "نام دامنه",
|
"domain_name_table_header": "نام دامنه",
|
||||||
@@ -267,6 +286,7 @@
|
|||||||
"blocking_mode": "حالت مسدودسازی",
|
"blocking_mode": "حالت مسدودسازی",
|
||||||
"default": "پيش فرض",
|
"default": "پيش فرض",
|
||||||
"nxdomain": "NXDOMAIN",
|
"nxdomain": "NXDOMAIN",
|
||||||
|
"refused": "مرفوض",
|
||||||
"null_ip": "Null IP",
|
"null_ip": "Null IP",
|
||||||
"custom_ip": "آی پی دستی",
|
"custom_ip": "آی پی دستی",
|
||||||
"blocking_ipv4": "مسدودسازی IPv4",
|
"blocking_ipv4": "مسدودسازی IPv4",
|
||||||
@@ -274,21 +294,45 @@
|
|||||||
"blocked_response_ttl": "TTL پاسخ مسدود شده",
|
"blocked_response_ttl": "TTL پاسخ مسدود شده",
|
||||||
"blocked_response_ttl_desc": "مشخص می کند که کلاینت ها برای چند ثانیه یک پاسخ فیلتر شده را در حافظه پنهان نگه دارند",
|
"blocked_response_ttl_desc": "مشخص می کند که کلاینت ها برای چند ثانیه یک پاسخ فیلتر شده را در حافظه پنهان نگه دارند",
|
||||||
"form_enter_blocked_response_ttl": "پاسخ مسدود شده TTL (ثانیه) را وارد کنید",
|
"form_enter_blocked_response_ttl": "پاسخ مسدود شده TTL (ثانیه) را وارد کنید",
|
||||||
|
"upstream_timeout": "مهلت زمانی بالادست",
|
||||||
|
"upstream_timeout_desc": "تعداد ثانیههایی را که باید منتظر پاسخ سرور بالادستی باشید مشخص میکند",
|
||||||
|
"form_enter_upstream_timeout": "مدت زمان سرورهای بالادستی را بر حسب ثانیه وارد کنید",
|
||||||
"dnscrypt": "DNSCrypt",
|
"dnscrypt": "DNSCrypt",
|
||||||
"dns_over_https": "DNS-over-HTTPS",
|
"dns_over_https": "DNS-over-HTTPS",
|
||||||
"dns_over_tls": "DNS-over-TLS",
|
"dns_over_tls": "DNS-over-TLS",
|
||||||
"dns_over_quic": "DNS-over-QUIC",
|
"dns_over_quic": "DNS-over-QUIC",
|
||||||
|
"client_id": "آیدی کاربر",
|
||||||
|
"client_id_placeholder": "آیدی کاربر را وارد کنید",
|
||||||
|
"client_id_desc": "کاربران را می توانید با آیدی کاربر شناسایی کنید. برای اطلاعات بیشتر درباره نحوه شناسایی کاربران <a>اینجا</a> کلیک کنید.",
|
||||||
|
"download_mobileconfig_doh": "Mobileconfig. را برای DNS-over-HTTPS دانلود کنید",
|
||||||
|
"download_mobileconfig_dot": "Mobileconfig. را برای DNS-over-TLS دانلود کنید",
|
||||||
|
"download_mobileconfig": "دانلود فایل تنظیمات",
|
||||||
|
"plain_dns": "DNS ساده",
|
||||||
"form_enter_rate_limit": "میزان محدودیت را وارد کنید",
|
"form_enter_rate_limit": "میزان محدودیت را وارد کنید",
|
||||||
"rate_limit": "میزان محدودیت",
|
"rate_limit": "میزان محدودیت",
|
||||||
"edns_enable": "فعالسازی زیرشبکه کلاینت EDNS",
|
"edns_enable": "فعالسازی زیرشبکه کلاینت EDNS",
|
||||||
"edns_cs_desc": "اگر فعال باشد،AdGuard Home زیرشبکه های کلاینت ها را به سرورهای DNS می فرستد.",
|
"edns_cs_desc": "اگر فعال باشد،AdGuard Home زیرشبکه های کلاینت ها را به سرورهای DNS می فرستد.",
|
||||||
|
"edns_use_custom_ip": "از IP سفارشی برای EDNS استفاده کنید",
|
||||||
|
"edns_use_custom_ip_desc": "اجازه استفاده از IP سفارشی برای EDNS",
|
||||||
"rate_limit_desc": "تعداد درخواست های بر ثانیه مجازی که یک کلاینت میتواند بسازد (0: نامحدود)",
|
"rate_limit_desc": "تعداد درخواست های بر ثانیه مجازی که یک کلاینت میتواند بسازد (0: نامحدود)",
|
||||||
|
"rate_limit_subnet_len_ipv4": "طول پیشوند زیرشبکه برای نشانیهای IPv4",
|
||||||
|
"rate_limit_subnet_len_ipv4_desc": "طول پیشوند زیرشبکه برای نشانیهای IPv4 استفاده شده برای محدودیت نرخ. پیشفرض ۲۴ است",
|
||||||
|
"rate_limit_subnet_len_ipv4_error": "طول پیشوند زیرشبکه IPv4 باید بین ۰ و ۳۲ باشد",
|
||||||
|
"rate_limit_subnet_len_ipv6": "طول پیشوند زیرشبکه برای نشانیهای IPv6",
|
||||||
|
"rate_limit_subnet_len_ipv6_desc": "طول پیشوند زیرشبکه برای نشانیهای IPv6 استفاده شده برای محدودیت نرخ. پیشفرض ۵۶ است",
|
||||||
|
"rate_limit_subnet_len_ipv6_error": "طول پیشوند زیرشبکه IPv6 باید بین ۰ تا ۱۲۸ باشد",
|
||||||
|
"form_enter_rate_limit_subnet_len": "طول پیشوند زیر شبکه را برای محدود کردن نرخ وارد کنید",
|
||||||
|
"rate_limit_whitelist": "لیست مجاز محدود کننده نرخ",
|
||||||
|
"rate_limit_whitelist_desc": "نشانیهای آی پی استثناء شده از محدودیت نرخ",
|
||||||
|
"rate_limit_whitelist_placeholder": "یک آدرس IP در هر خط وارد کنید",
|
||||||
"blocking_ipv4_desc": "آدرس آی پی برگشت داده شده برای درخواست مسدود شده A",
|
"blocking_ipv4_desc": "آدرس آی پی برگشت داده شده برای درخواست مسدود شده A",
|
||||||
"blocking_ipv6_desc": "آدرس آی پی برگشت داده شده برای درخواست مسدود شده AAAA",
|
"blocking_ipv6_desc": "آدرس آی پی برگشت داده شده برای درخواست مسدود شده AAAA",
|
||||||
"blocking_mode_default": "پیش فرض: وقتی مسدود شود با دستور سبک-مسدودساز تبلیغ REFUSED پاسخ میدهد،پاسخ با آدرس آی پی تعیین شده در دستور وقتی با دستور /etc/hosts-style rule مسدود شود",
|
"blocking_mode_default": "پیش فرض: وقتی مسدود شود با دستور سبک-مسدودساز تبلیغ REFUSED پاسخ میدهد،پاسخ با آدرس آی پی تعیین شده در دستور وقتی با دستور /etc/hosts-style rule مسدود شود",
|
||||||
|
"blocking_mode_refused": "رد: پاسخ با کد رد شده",
|
||||||
"blocking_mode_nxdomain": "NXDOMAIN: پاسخ با کُد NXDOMAIN",
|
"blocking_mode_nxdomain": "NXDOMAIN: پاسخ با کُد NXDOMAIN",
|
||||||
"blocking_mode_null_ip": "Null IP: پاسخ با آدرس آی پی صفر(0.0.0.0 برای A; :: برای AAAA)",
|
"blocking_mode_null_ip": "Null IP: پاسخ با آدرس آی پی صفر(0.0.0.0 برای A; :: برای AAAA)",
|
||||||
"blocking_mode_custom_ip": "آی پی دستی: پاسخ با آدرس آی پی دستی تنظیم شده",
|
"blocking_mode_custom_ip": "آی پی دستی: پاسخ با آدرس آی پی دستی تنظیم شده",
|
||||||
|
"theme_auto": "خودکار",
|
||||||
"theme_light": "پوسته روشن",
|
"theme_light": "پوسته روشن",
|
||||||
"theme_dark": "پوسته تیره",
|
"theme_dark": "پوسته تیره",
|
||||||
"upstream_dns_client_desc": "اگر این فیلد را خالی نگه دارید، AdGuard Home از سرور پیکربندی شده در <0> تنظیماتDNS </0> استفاده می کند.",
|
"upstream_dns_client_desc": "اگر این فیلد را خالی نگه دارید، AdGuard Home از سرور پیکربندی شده در <0> تنظیماتDNS </0> استفاده می کند.",
|
||||||
@@ -364,6 +408,8 @@
|
|||||||
"encryption_https_desc": "اگر پورت HTTPS پیکربندی شده باشد،رابط آدمین AdGuard Home از طریق HTTPS قابل دسترسی خواهد بود و آن همچنین DNS-over-HTTPS را در مکان '/dns-query' ارائه می دهد.",
|
"encryption_https_desc": "اگر پورت HTTPS پیکربندی شده باشد،رابط آدمین AdGuard Home از طریق HTTPS قابل دسترسی خواهد بود و آن همچنین DNS-over-HTTPS را در مکان '/dns-query' ارائه می دهد.",
|
||||||
"encryption_dot": "پورت DNS-over-TLS",
|
"encryption_dot": "پورت DNS-over-TLS",
|
||||||
"encryption_dot_desc": "اگر این پورت پیکربندی شده باشد،AdGuard Home یک DNS-over-TLS سرور روی این پورت اجرا می کند",
|
"encryption_dot_desc": "اگر این پورت پیکربندی شده باشد،AdGuard Home یک DNS-over-TLS سرور روی این پورت اجرا می کند",
|
||||||
|
"encryption_doq": "درگاه DNS-over-QUIC",
|
||||||
|
"encryption_doq_desc": "اگر این درگاه پیکربندی شده باشد، AdGuard Home یک سرور DNS-over-QUIC را بر روی این پورت اجرا خواهد کرد.",
|
||||||
"encryption_certificates": "گواهینامه ها",
|
"encryption_certificates": "گواهینامه ها",
|
||||||
"encryption_certificates_desc": "به منظور استفاده از رمزگُذاری، شما باید زنجیره گواهینامه اِس اِس اِل معتبر برای دامنه خود ارائه دهید. میتوانید گواهینامه رایگان از <0>{{link}}</0> بگیرید یا میتوانید آن را از مراجع گواهینامه معتبر بخرید.",
|
"encryption_certificates_desc": "به منظور استفاده از رمزگُذاری، شما باید زنجیره گواهینامه اِس اِس اِل معتبر برای دامنه خود ارائه دهید. میتوانید گواهینامه رایگان از <0>{{link}}</0> بگیرید یا میتوانید آن را از مراجع گواهینامه معتبر بخرید.",
|
||||||
"encryption_certificates_input": "کپی/چسباندن گواهینامه پی ای اِم کد گذاری شده در اینجا.",
|
"encryption_certificates_input": "کپی/چسباندن گواهینامه پی ای اِم کد گذاری شده در اینجا.",
|
||||||
@@ -382,6 +428,9 @@
|
|||||||
"encryption_hostnames": "نام میزبان",
|
"encryption_hostnames": "نام میزبان",
|
||||||
"encryption_reset": "آیا میخواهید تنظیمات رمزگُذاری به پیش فرض بازگردد؟",
|
"encryption_reset": "آیا میخواهید تنظیمات رمزگُذاری به پیش فرض بازگردد؟",
|
||||||
"encryption_warning": "هشدار",
|
"encryption_warning": "هشدار",
|
||||||
|
"encryption_plain_dns_enable": "فعالسازی DNS ساده",
|
||||||
|
"encryption_plain_dns_desc": "DNS ساده به طور پیش فرض فعال است. می توانید آن را غیرفعال کنید تا همه دستگاه ها مجبور شوند از DNS رمزگذاری شده استفاده کنند. برای انجام این کار، باید حداقل یک پروتکل DNS رمزگذاری شده را فعال کنید",
|
||||||
|
"encryption_plain_dns_error": "برای غیرفعال کردن DNS ساده، حداقل یک پروتکل DNS رمزگذاری شده را فعال کنید",
|
||||||
"topline_expiring_certificate": "گواهینامه اِس اِس اِل شما در صدد انقضاء است. <0>تنظیمات رمزگُذاری</0> را بروز رسانی کنید.",
|
"topline_expiring_certificate": "گواهینامه اِس اِس اِل شما در صدد انقضاء است. <0>تنظیمات رمزگُذاری</0> را بروز رسانی کنید.",
|
||||||
"topline_expired_certificate": "گواهینامه اِس اِس اِل شما منقضی شده است. <0>تنظیمات رمزگُذاری</0> را بروز رسانی کنید.",
|
"topline_expired_certificate": "گواهینامه اِس اِس اِل شما منقضی شده است. <0>تنظیمات رمزگُذاری</0> را بروز رسانی کنید.",
|
||||||
"form_error_port_range": "مقدار پورت را در محدوده 80-65535 وارد کنید",
|
"form_error_port_range": "مقدار پورت را در محدوده 80-65535 وارد کنید",
|
||||||
@@ -430,7 +479,7 @@
|
|||||||
"client_confirm_delete": "آیا واقعا میخواهید \"{{key}}\" کلاینت را حذف کنید؟",
|
"client_confirm_delete": "آیا واقعا میخواهید \"{{key}}\" کلاینت را حذف کنید؟",
|
||||||
"list_confirm_delete": "آیا واقعا میخواهید این لیست را حذف کنید؟",
|
"list_confirm_delete": "آیا واقعا میخواهید این لیست را حذف کنید؟",
|
||||||
"auto_clients_title": "کلاینت ها (زمان اِجرا)",
|
"auto_clients_title": "کلاینت ها (زمان اِجرا)",
|
||||||
"auto_clients_desc": "داده در کلاینت ها که از AdGuard Home استفاده می کند،اما در پیکربندی ذخیره نمی شود",
|
"auto_clients_desc": "دادهها در کلاینتها که از AdGuard Home استفاده میکنند، اما در پیکربندی ذخیره نمیشوند.",
|
||||||
"access_title": "تنظیمات دسترسی",
|
"access_title": "تنظیمات دسترسی",
|
||||||
"access_desc": "در اینجا میتوانید دستورات دسترسی را برای DNS سرور AdGuard Home وارد کنید.",
|
"access_desc": "در اینجا میتوانید دستورات دسترسی را برای DNS سرور AdGuard Home وارد کنید.",
|
||||||
"access_allowed_title": "کلاینت های مجاز",
|
"access_allowed_title": "کلاینت های مجاز",
|
||||||
@@ -448,6 +497,7 @@
|
|||||||
"setup_dns_privacy_1": "<0>DNS-over-TLS:</0> استفاده از<1>{{address}}</1> .",
|
"setup_dns_privacy_1": "<0>DNS-over-TLS:</0> استفاده از<1>{{address}}</1> .",
|
||||||
"setup_dns_privacy_2": "<0>DNS-over-HTTPS:</0> استفاده از <1>{{address}}</1> .",
|
"setup_dns_privacy_2": "<0>DNS-over-HTTPS:</0> استفاده از <1>{{address}}</1> .",
|
||||||
"setup_dns_privacy_3": "<0>لطفا توجه کنید که پروتکل های رمزگذاری شده DNS فقط در آندروئید 9 پشتیبانی می شود. پس برای سیستم عامل های دیگر نیاز است که برنامه دیگری نصب کنید.</0><0>در اینجا میتوانید لیست نرم افزارهای قابل استفاده را ببینید.</0>",
|
"setup_dns_privacy_3": "<0>لطفا توجه کنید که پروتکل های رمزگذاری شده DNS فقط در آندروئید 9 پشتیبانی می شود. پس برای سیستم عامل های دیگر نیاز است که برنامه دیگری نصب کنید.</0><0>در اینجا میتوانید لیست نرم افزارهای قابل استفاده را ببینید.</0>",
|
||||||
|
"setup_dns_privacy_4": "در یک دستگاه iOS 14 یا macOS Big Sur میتوانید فایل ویژه '.mobileconfig' را دانلود کنید که <highlight>DNS-over-HTTPS</highlight> یا <highlight>DNS-over-TLS</highlight> سرورها را به تنظیمات DNS اضافه میکند.",
|
||||||
"setup_dns_privacy_android_1": "آندروئید 9 بطور پیش فرض از DNS-over-TLS پشتیبانی می کند. برای پیکربندی آن، بروید به تنظیمات → شبکه & اینترنت → پیشرفته → DNS خصوصی و نام دامنه را آنجا وارد کنید.",
|
"setup_dns_privacy_android_1": "آندروئید 9 بطور پیش فرض از DNS-over-TLS پشتیبانی می کند. برای پیکربندی آن، بروید به تنظیمات → شبکه & اینترنت → پیشرفته → DNS خصوصی و نام دامنه را آنجا وارد کنید.",
|
||||||
"setup_dns_privacy_android_2": "<0>AdGuard for Android</0> پشتیبانی از <1>DNS-over-HTTPS</1> و <1>DNS-over-TLS</1>.",
|
"setup_dns_privacy_android_2": "<0>AdGuard for Android</0> پشتیبانی از <1>DNS-over-HTTPS</1> و <1>DNS-over-TLS</1>.",
|
||||||
"setup_dns_privacy_android_3": "<0>Intra</0> قابلیت <1>DNS-over-HTTPS</1> را به آندروئید اضافه می کند.",
|
"setup_dns_privacy_android_3": "<0>Intra</0> قابلیت <1>DNS-over-HTTPS</1> را به آندروئید اضافه می کند.",
|
||||||
@@ -459,6 +509,7 @@
|
|||||||
"setup_dns_privacy_other_3": "<0>dnscrypt-proxy</0> supportsپشتیبانی از <1>DNS-over-HTTPS</1>.",
|
"setup_dns_privacy_other_3": "<0>dnscrypt-proxy</0> supportsپشتیبانی از <1>DNS-over-HTTPS</1>.",
|
||||||
"setup_dns_privacy_other_4": "<0>Mozilla Firefox</0> پشتیبانی از <1>DNS-over-HTTPS</1>.",
|
"setup_dns_privacy_other_4": "<0>Mozilla Firefox</0> پشتیبانی از <1>DNS-over-HTTPS</1>.",
|
||||||
"setup_dns_privacy_other_5": "شما میتوانید راه کارهای بیشتر را در <0>اینجا</0> و <1>اینجا</1> پیدا کنید.",
|
"setup_dns_privacy_other_5": "شما میتوانید راه کارهای بیشتر را در <0>اینجا</0> و <1>اینجا</1> پیدا کنید.",
|
||||||
|
"setup_dns_privacy_ioc_mac": "پیکربندی iOS و macOS",
|
||||||
"setup_dns_notice": "به منظور استفاده از <1>DNS-over-HTTPS</1> یا <1>DNS-over-TLS</1>، شما نیاز به <0>پیکربندی رمزگذاری</0> در تنظیمات AdGuard Home دارید.",
|
"setup_dns_notice": "به منظور استفاده از <1>DNS-over-HTTPS</1> یا <1>DNS-over-TLS</1>، شما نیاز به <0>پیکربندی رمزگذاری</0> در تنظیمات AdGuard Home دارید.",
|
||||||
"rewrite_added": "بازنویسی DNS برای \"{{key}}\" با موفقیت اضافه شد",
|
"rewrite_added": "بازنویسی DNS برای \"{{key}}\" با موفقیت اضافه شد",
|
||||||
"rewrite_deleted": "بازنویسی DNS برای \"{{key}}\" با موفقیت حذف شد",
|
"rewrite_deleted": "بازنویسی DNS برای \"{{key}}\" با موفقیت حذف شد",
|
||||||
@@ -498,8 +549,11 @@
|
|||||||
"interval_days": "{{value}} روز",
|
"interval_days": "{{value}} روز",
|
||||||
"interval_days_plural": "{{count}} روز",
|
"interval_days_plural": "{{count}} روز",
|
||||||
"domain": "دامنه",
|
"domain": "دامنه",
|
||||||
|
"ecs": "ECS",
|
||||||
|
"punycode": "پونیکد",
|
||||||
"answer": "پاسخ",
|
"answer": "پاسخ",
|
||||||
"filter_added_successfully": "فیلتر با موفقیت اضافه شد",
|
"filter_added_successfully": "فیلتر با موفقیت اضافه شد",
|
||||||
|
"filter_removed_successfully": "لیست با موفقیت حذف شد",
|
||||||
"filter_updated": "فیلتر با موفقیت بروز رسانی شد",
|
"filter_updated": "فیلتر با موفقیت بروز رسانی شد",
|
||||||
"statistics_configuration": "پیکربندی آمارها",
|
"statistics_configuration": "پیکربندی آمارها",
|
||||||
"statistics_retention": "مدت حفظ آمارها",
|
"statistics_retention": "مدت حفظ آمارها",
|
||||||
@@ -509,6 +563,10 @@
|
|||||||
"statistics_retention_confirm": "آیا واقعا میخواهید مدت حفظ آمار را تغییر دهید؟ اگر فاصله را کاهش دهید، برخی داده ها حذف میشود",
|
"statistics_retention_confirm": "آیا واقعا میخواهید مدت حفظ آمار را تغییر دهید؟ اگر فاصله را کاهش دهید، برخی داده ها حذف میشود",
|
||||||
"statistics_cleared": "آمارها با موفقیت حذف شد",
|
"statistics_cleared": "آمارها با موفقیت حذف شد",
|
||||||
"statistics_enable": "فعالسازی داده های آماری",
|
"statistics_enable": "فعالسازی داده های آماری",
|
||||||
|
"ignore_domains": "دامنه های نادیده گرفته شده (با خط جدید جدا شدهاند)",
|
||||||
|
"ignore_domains_title": "دامنههای نادیده گرفته شده",
|
||||||
|
"ignore_domains_desc_stats": "جستارهای مطابق با این قوانین در آمار نوشته نمیشوند",
|
||||||
|
"ignore_domains_desc_query": "پرس و جوهایی که با این قوانین مطابقت دارند در گزارش پرس و جو نوشته نمیشوند",
|
||||||
"interval_hours": "{{count}} ساعت",
|
"interval_hours": "{{count}} ساعت",
|
||||||
"interval_hours_plural": "{{count}} ساعت",
|
"interval_hours_plural": "{{count}} ساعت",
|
||||||
"filters_configuration": "پیکربندی فیلترها",
|
"filters_configuration": "پیکربندی فیلترها",
|
||||||
@@ -531,14 +589,19 @@
|
|||||||
"whois": "هوئیز",
|
"whois": "هوئیز",
|
||||||
"filtering_rules_learn_more": "درباره ایجاد لیست سیاه میزبان برای خود <0>بیشتر بدانید</0>.",
|
"filtering_rules_learn_more": "درباره ایجاد لیست سیاه میزبان برای خود <0>بیشتر بدانید</0>.",
|
||||||
"blocked_by_response": "مسدودسازی با CNAME یا IP در پاسخ",
|
"blocked_by_response": "مسدودسازی با CNAME یا IP در پاسخ",
|
||||||
|
"blocked_by_cname_or_ip": "توسط CNAME یا IP مسدود شده است",
|
||||||
"try_again": "امتحان دوباره",
|
"try_again": "امتحان دوباره",
|
||||||
"domain_desc": "نامه دامنه یا علامت تطبیقی را برای بازنویسی وارد کنید.",
|
"domain_desc": "نامه دامنه یا علامت تطبیقی را برای بازنویسی وارد کنید.",
|
||||||
"example_rewrite_domain": "فقط بازنویسی پاسخ برای این دامنه.",
|
"example_rewrite_domain": "فقط بازنویسی پاسخ برای این دامنه.",
|
||||||
"example_rewrite_wildcard": "بازنویسی پاسخ ها برای همه زیردامنه های <0>example.org</0>.",
|
"example_rewrite_wildcard": "بازنویسی پاسخ ها برای همه زیردامنه های <0>example.org</0>.",
|
||||||
|
"rewrite_ip_address": "آدرس IP: از این IP در پاسخ A یا AAAA استفاده کنید",
|
||||||
|
"rewrite_domain_name": "نام دامنه: یک رکورد CNAME اضافه کنید",
|
||||||
|
"rewrite_A": "<0>A</0>: مقدار ویژه، <0>A</0> سوابق از بالادست را نگه دارید",
|
||||||
|
"rewrite_AAAA": "<0>AAAA</0>: مقدار ویژه، <0>AAAA</0> سوابق از بالادست را نگه دارید",
|
||||||
"disable_ipv6": "غیرفعالسازی IPv6",
|
"disable_ipv6": "غیرفعالسازی IPv6",
|
||||||
"disable_ipv6_desc": "تمام درخواستهای DNS برای آدرسهای IPv6 را رها کنید (تایپ AAAA) و نکات IPv6 را از پاسخهای HTTPS حذف کنید.",
|
"disable_ipv6_desc": "تمام درخواستهای DNS برای آدرسهای IPv6 را رها کنید (تایپ AAAA) و نکات IPv6 را از پاسخهای HTTPS حذف کنید.",
|
||||||
"fastest_addr": "سریعترین آدرس آی پی",
|
"fastest_addr": "سریعترین آدرس آی پی",
|
||||||
"fastest_addr_desc": "جستار همه سرورهای DNS و بازگرداندن سریعترین آدرس IP از میان همه پاسخ ها",
|
"fastest_addr_desc": "منتظر پاسخهای <b>همه</b> سرورهای DNS باشید، سرعت اتصال TCP را برای هر سرور اندازهگیری کنید و آدرس IP سرور را با سریعترین سرعت اتصال برگردانید.<br/>اگر یک یا چند سرور بالادستی پاسخ نمیدهند، این حالت میتواند بهطور قابلتوجهی درخواستهای DNS را کاهش دهد. اطمینان حاصل کنید که سرورهای بالادست شما پایدار هستند و تایم اوت بالادست شما کم است.",
|
||||||
"autofix_warning_text": "اگر روی \"تعمیر\" کلیک کنید، AdGuardHome سیستم شما را برای استفاده از DNS سرور AdGuardHome پیکربندی می کند.",
|
"autofix_warning_text": "اگر روی \"تعمیر\" کلیک کنید، AdGuardHome سیستم شما را برای استفاده از DNS سرور AdGuardHome پیکربندی می کند.",
|
||||||
"autofix_warning_list": "این وظایف را اجرا میکند: <0>غیرفعالسازی DNSStubListener سیستم</0> <0>تنظیم آدرس DNS 127.0.0.1</0> سرور به <0>جایگزینی لینک نمادی هدف /etc/resolv.conf به/run/systemd/resolve/resolv.conf</0> <0>توقف DNSStubListener (بارگیری مجدد سرویس systemd-resolved)</0>",
|
"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 از سیستم شما بطور پیش فرض با AdGuardHome پردازش خواهد شد.",
|
"autofix_warning_result": "در نتیجه همه درخواست های DNS از سیستم شما بطور پیش فرض با AdGuardHome پردازش خواهد شد.",
|
||||||
@@ -550,11 +613,18 @@
|
|||||||
"check": "بررسی",
|
"check": "بررسی",
|
||||||
"form_enter_host": "نام میزبان را وارد کنید",
|
"form_enter_host": "نام میزبان را وارد کنید",
|
||||||
"filtered_custom_rules": "با دستورات فیلترینگ دستی فیلتر شده است",
|
"filtered_custom_rules": "با دستورات فیلترینگ دستی فیلتر شده است",
|
||||||
|
"choose_from_list": "از لیست انتخاب کنید",
|
||||||
|
"add_custom_list": "یک لیست سفارشی اضافه کنید",
|
||||||
"host_whitelisted": "سایت در لیست سفید است",
|
"host_whitelisted": "سایت در لیست سفید است",
|
||||||
"check_ip": "آدرس آی پی: {{ip}}",
|
"check_ip": "آدرس آی پی: {{ip}}",
|
||||||
"check_cname": "CNAME: {{cname}}",
|
"check_cname": "CNAME: {{cname}}",
|
||||||
"check_reason": "علت: {{reason}}",
|
"check_reason": "علت: {{reason}}",
|
||||||
"check_service": "نام سرویس: {{service}}",
|
"check_service": "نام سرویس: {{service}}",
|
||||||
|
"check_hostname": "نام میزبان یا نام دامنه",
|
||||||
|
"check_client_id": "شناسه مشتری (ClientID یا نشانی IP)",
|
||||||
|
"check_enter_client_id": "شناسه مشتری را وارد کنید",
|
||||||
|
"check_dns_record": "نوع رکورد DNS را انتخاب کنید",
|
||||||
|
"service_name": "نام خدمت",
|
||||||
"check_not_found": "در لیست فیلترهای شما یافت نشد",
|
"check_not_found": "در لیست فیلترهای شما یافت نشد",
|
||||||
"client_confirm_block": "آیا واقعا میخواهید کلاینت \"{{ip}}\" را مسدود کنید؟",
|
"client_confirm_block": "آیا واقعا میخواهید کلاینت \"{{ip}}\" را مسدود کنید؟",
|
||||||
"client_confirm_unblock": "آیا واقعا میخواهید کلاینت \"{{ip}}\" را باز کنید؟",
|
"client_confirm_unblock": "آیا واقعا میخواهید کلاینت \"{{ip}}\" را باز کنید؟",
|
||||||
@@ -572,6 +642,7 @@
|
|||||||
"dnssec_enable": "فعالسازی DNSSEC",
|
"dnssec_enable": "فعالسازی DNSSEC",
|
||||||
"dnssec_enable_desc": "تنظیم نشان DNSSEC در جستارهای حاصل DNS و بررسی نتیجه (تفکیک کننده DNSSEC-فعال شده نیاز است)",
|
"dnssec_enable_desc": "تنظیم نشان DNSSEC در جستارهای حاصل DNS و بررسی نتیجه (تفکیک کننده DNSSEC-فعال شده نیاز است)",
|
||||||
"validated_with_dnssec": "معتبر سازی با DNSSEC",
|
"validated_with_dnssec": "معتبر سازی با DNSSEC",
|
||||||
|
"all_queries": "تمام جستارها",
|
||||||
"show_blocked_responses": "مسدود شده",
|
"show_blocked_responses": "مسدود شده",
|
||||||
"show_whitelisted_responses": "لیست سفید",
|
"show_whitelisted_responses": "لیست سفید",
|
||||||
"show_processed_responses": "پردازش شده",
|
"show_processed_responses": "پردازش شده",
|
||||||
@@ -585,16 +656,62 @@
|
|||||||
"blocklist": "لیست سیاه",
|
"blocklist": "لیست سیاه",
|
||||||
"milliseconds_abbreviation": "هـ ثـ",
|
"milliseconds_abbreviation": "هـ ثـ",
|
||||||
"cache_size": "اندازه کش",
|
"cache_size": "اندازه کش",
|
||||||
|
"cache_size_desc": "اندازه حافظه پنهان DNS (به بایت). برای غیر فعال کردن حافظه پنهان، عدد 0 را تعیین کنید.",
|
||||||
|
"cache_ttl_min_override": "نادیده گرفتن حداقل TTL",
|
||||||
|
"cache_ttl_max_override": "نادیده گرفتن حداکثر TTL",
|
||||||
|
"enter_cache_size": "اندازه حافظه پنهان را وارد کنید (بایت)",
|
||||||
|
"enter_cache_ttl_min_override": "حداقل TTL را وارد کنید (ثانیه)",
|
||||||
|
"enter_cache_ttl_max_override": "حداکثر TTL (ثانیه) را وارد کنید",
|
||||||
|
"cache_ttl_min_override_desc": "در هنگام ذخیره پاسخ های DNS، مقادیر کوتاه مدت زمان (ثانیه) دریافت شده از سرور بالادست را افزایش دهید.",
|
||||||
|
"cache_ttl_max_override_desc": "حداکثر مقدار زمان تا زنده (ثانیه) را برای ورودیهای کش DNS تنظیم کنید.",
|
||||||
|
"ttl_cache_validation": "حداقل لغو TTL حافظه نهان باید کمتر یا مساوی حداکثر باشد",
|
||||||
"cache_optimistic": "حالت ویژه پردازش",
|
"cache_optimistic": "حالت ویژه پردازش",
|
||||||
"cache_optimistic_desc": "AdGuard Home را وادار می کند که از سمت حافظه پنهان پاسخ دهد حتی وقتی که موارد وارد شده منقضی شده باشد و همچنین سعی بر تازه کردن آنها می کند.",
|
"cache_optimistic_desc": "AdGuard Home را وادار می کند که از سمت حافظه پنهان پاسخ دهد حتی وقتی که موارد وارد شده منقضی شده باشد و همچنین سعی بر تازه کردن آنها می کند.",
|
||||||
"filter_category_general": "General",
|
"filter_category_general": "General",
|
||||||
"filter_category_security": "مسدودسازی بدافزار و فیشینگ",
|
"filter_category_security": "مسدودسازی بدافزار و فیشینگ",
|
||||||
"filter_category_regional": "منطقهای",
|
"filter_category_regional": "منطقهای",
|
||||||
"filter_category_other": "ساير",
|
"filter_category_other": "ساير",
|
||||||
|
"filter_category_general_desc": "فهرستهایی که ردیابی و تبلیغات را بر روی اکثر دستگاهها مسدود میکنند",
|
||||||
|
"filter_category_security_desc": "فهرستهایی طراحی شده است که به طور خاص برای مسدودسازی دامنههای مخرب، طعمهگذاری و کلاهبرداری هستند",
|
||||||
|
"filter_category_regional_desc": "فهرستهایی که بر روی تبلیغات منطقهای و سرورهای ردیابی تمرکز دارند",
|
||||||
|
"filter_category_other_desc": "سایر لیست های بلاک شده",
|
||||||
|
"setup_config_to_enable_dhcp_server": "پیکربندی را برای فعال کردن سرور DHCP تنظیم کنید",
|
||||||
|
"original_response": "پاسخ اصلی",
|
||||||
|
"click_to_view_queries": "برای مشاهده جستارها کلیک کنید",
|
||||||
|
"port_53_faq_link": "درگاه ۵۳ اغلب توسط خدمتهای \"DNSStubListener\" یا \"systemd-resolved\" اشغال میشود. لطفاً <0>دستورالعملها</0> را برای حل این موضوع مطالعه کنید.",
|
||||||
|
"adg_will_drop_dns_queries": "AdGuard Home تمام جستارهای DNS از این سرویسگیرنده را حذف خواهد کرد.",
|
||||||
|
"filter_allowlist": "هشدار: این اقدام همچنین باعث استثناء رویه \"{{disallowed_rule}}\" از فهرست سرویسگیرندگان مجاز میشود.",
|
||||||
|
"last_rule_in_allowlist": "نمی توان این مشتری را غیر فعال کرد چرا که استثناء قاعده \"{{disallowed_rule}}\" باعث غیر فعال شدن فهرست \"مشتریان مجاز\" می شود.",
|
||||||
"use_saved_key": "از کلید ذخیره شده قبلی استفاده کنید",
|
"use_saved_key": "از کلید ذخیره شده قبلی استفاده کنید",
|
||||||
"parental_control": "نظارت والدین",
|
"parental_control": "نظارت والدین",
|
||||||
"safe_browsing": "وب گردی اَمن",
|
"safe_browsing": "وب گردی اَمن",
|
||||||
"form_error_password_length": "رمزعبور باید حداقل {{value}} کاراکتر باشد.",
|
"served_from_cache_label": "از حافظه پنهان ارائه میشود",
|
||||||
|
"form_error_password_length": "رمزعبور باید بین {{min}} تا {{max}} کاراکتر باشد.",
|
||||||
|
"anonymizer_notification": "<0>توجه:</0> ناشناس سازی IP فعال است. می توانید آن را در<1>تنظیمات عمومی غیرفعال کنید</1>.",
|
||||||
|
"confirm_dns_cache_clear": "آیا واقعا میخواهید حافظه پنهان DNS را پاک کنید؟",
|
||||||
|
"cache_cleared": "حافظه پنهان DNS با موفقیت حذف شد",
|
||||||
|
"clear_cache": "پاک کردن کش",
|
||||||
|
"make_static": "ایستا کنید",
|
||||||
|
"theme_auto_desc": "اتوماتیک (بر اساس طرح رنگی دستگاه شما)",
|
||||||
|
"theme_dark_desc": "پوسته تیره",
|
||||||
|
"theme_light_desc": "پوسته روشن",
|
||||||
|
"disable_for_seconds": "برای {{count}} ثانیه",
|
||||||
|
"disable_for_seconds_plural": "برای {{count}} ثانیه",
|
||||||
|
"disable_for_minutes": "برای {{count}} دقیقه",
|
||||||
|
"disable_for_minutes_plural": "برای {{count}} دقیقه",
|
||||||
|
"disable_for_hours": "برای {{count}} ساعت",
|
||||||
|
"disable_for_hours_plural": "برای {{count}} ساعت",
|
||||||
|
"disable_until_tomorrow": "تا فردا",
|
||||||
|
"disable_notify_for_seconds": "محافظت را برای {{count}} ثانیه غیرفعال کنید",
|
||||||
|
"disable_notify_for_seconds_plural": "محافظت را برای {{count}} ثانیه غیرفعال کنید",
|
||||||
|
"disable_notify_for_minutes": "محافظت را برای {{count}} دقیقه غیرفعال کنید",
|
||||||
|
"disable_notify_for_minutes_plural": "محافظت را برای {{count}} دقیقه غیرفعال کنید",
|
||||||
|
"disable_notify_for_hours": "محافظت را برای {{count}} ساعت غیرفعال کنید",
|
||||||
|
"disable_notify_for_hours_plural": "محافظت را برای {{count}} ساعت غیرفعال کنید",
|
||||||
|
"disable_notify_until_tomorrow": "محافظت را تا فردا غیرفعال کنید",
|
||||||
|
"enable_protection_timer": "حفاظت در {{time}} فعال خواهد شد",
|
||||||
|
"custom_retention_input": "زمان ذخیره را برحسب ساعت وارد کنید",
|
||||||
|
"custom_rotation_input": "زمان چرخش را بر حسب ساعت وارد کنید",
|
||||||
"protection_section_label": "حفاظت",
|
"protection_section_label": "حفاظت",
|
||||||
"log_and_stats_section_label": "گزارش پرس و جو و آمار",
|
"log_and_stats_section_label": "گزارش پرس و جو و آمار",
|
||||||
"ignore_query_log": "این مشتری را در گزارش پرس و جو نادیده بگیرید",
|
"ignore_query_log": "این مشتری را در گزارش پرس و جو نادیده بگیرید",
|
||||||
@@ -630,5 +747,8 @@
|
|||||||
"wednesday_short": "چهارشنبه",
|
"wednesday_short": "چهارشنبه",
|
||||||
"thursday_short": "پنج شنبه",
|
"thursday_short": "پنج شنبه",
|
||||||
"friday_short": "جمعه",
|
"friday_short": "جمعه",
|
||||||
"saturday_short": "شنبه"
|
"saturday_short": "شنبه",
|
||||||
|
"upstream_dns_cache_configuration": "پیکربندی نهانگاه DNS بالادست",
|
||||||
|
"enable_upstream_dns_cache": "ذخیره DNS را برای پیکربندی بالادستی سفارشی این مشتری فعال کنید",
|
||||||
|
"dns_cache_size": "اندازه کش DNS، بر حسب بایت"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
{
|
{
|
||||||
"client_settings": "Klientinnstillinger",
|
"client_settings": "Klientinnstillinger",
|
||||||
"example_upstream_reserved": "Du kan bestemme en oppstrøms-DNS <0>for et spesifikt domene(r)</0>",
|
"example_upstream_reserved": "Du kan bestemme en oppstrøms-DNS <0>for et spesifikt domene(r)</0>",
|
||||||
|
"example_multiple_upstreams_reserved": "flere upstreams <0>for spesifikke domener</0>;",
|
||||||
"example_upstream_comment": "Du kan spesifisere en kommentar",
|
"example_upstream_comment": "Du kan spesifisere en kommentar",
|
||||||
"upstream_parallel": "Bruk parallele forespørsler for å få oppfarten på behandlinger, ved å forespørre til alle oppstrømstjenerne samtidig",
|
"upstream_parallel": "Bruk parallele forespørsler for å få oppfarten på behandlinger, ved å forespørre til alle oppstrømstjenerne samtidig",
|
||||||
"parallel_requests": "Parallelle forespørsler",
|
"parallel_requests": "Parallelle forespørsler",
|
||||||
"load_balancing": "Pågangstrykk-utjevning",
|
"load_balancing": "Pågangstrykk-utjevning",
|
||||||
"load_balancing_desc": "Forespør én tjener om gangen. AdGuard Home vil bruke en 'vektlagt tilfeldig valg'-algoritme for å velge tjener, slik at den raskeste tjeneren blir brukt oftere.",
|
"load_balancing_desc": "Kjør en forespørsel mot én oppstrømsserver om gangen.<br/>AdGuard Home bruker en vektet tilfeldig algoritme for å velge servere med det laveste antallet mislykkede oppslag og det laveste gjennomsnittlige oppslagstiden.",
|
||||||
"bootstrap_dns": "Bootstrap-DNS-tjenere",
|
"bootstrap_dns": "Bootstrap-DNS-tjenere",
|
||||||
"bootstrap_dns_desc": "IP-adresser til DNS-servere som brukes til å løse IP-adresser til DoH/DoT-løsere du spesifiserer som oppstrøms. Kommentarer er ikke tillatt.",
|
"bootstrap_dns_desc": "IP-adresser til DNS-servere som brukes til å løse IP-adresser til DoH/DoT-løsere du spesifiserer som oppstrøms. Kommentarer er ikke tillatt.",
|
||||||
"fallback_dns_title": "Reserve DNS-servere",
|
"fallback_dns_title": "Reserve DNS-servere",
|
||||||
"fallback_dns_desc": "Liste over reserve-DNS-servere som brukes når oppstrøms DNS-servere ikke svarer. Syntaksen er den samme som i hovedoppstrømsfeltet ovenfor.",
|
"fallback_dns_desc": "Liste over reserve-DNS-servere som brukes når oppstrøms DNS-servere ikke svarer. Syntaksen er den samme som i hovedoppstrømsfeltet ovenfor.",
|
||||||
"fallback_dns_placeholder": "Angi én reserve-DNS-server per linje",
|
"fallback_dns_placeholder": "Angi én reserve-DNS-server per linje",
|
||||||
"local_ptr_title": "Private DNS-tjenere",
|
"local_ptr_title": "Private DNS-tjenere",
|
||||||
"local_ptr_desc": "DNS-tjenerne som AdGuard Home bruker for lokale PTR-spørringer. Disse tjenerne brukes til å løse vertsnavnene til klienter med private IP-adresser, for eksempel \"192.168.12.34\", ved bruk av omvendt DNS. Hvis det ikke er angitt, bruker AdGuard Home adressene til standard-DNS-løserne til operativsystemet ditt, bortsett fra adressene til selve AdGuard Home.",
|
"local_ptr_desc": "DNS-servere brukt av AdGuard Home for private PTR-, SOA- og NS-forespørsel. En forespørsel anses som privat hvis den ber om et ARPA-domene som inneholder et subnett innenfor private IP-områder (som \"192.168.12.34\") og kommer fra en klient med en privat IP-adresse. Hvis det ikke er angitt, vil de standard DNS-oppløserne for ditt operativsystem bli brukt, unntatt for AdGuard Home IP-adressene.",
|
||||||
"local_ptr_default_resolver": "Som standard, bruker AdGuard Home følgende revers-DNS-oppletere: {{ip}}.",
|
"local_ptr_default_resolver": "Som standard, bruker AdGuard Home følgende revers-DNS-oppletere: {{ip}}.",
|
||||||
"local_ptr_no_default_resolver": "AdGuard Home klarte ikke å finne egnede private revers-DNS-oppletere for dette systemet.",
|
"local_ptr_no_default_resolver": "AdGuard Home klarte ikke å finne egnede private revers-DNS-oppletere for dette systemet.",
|
||||||
"local_ptr_placeholder": "Skriv inn én tjeneradresse per linje",
|
"local_ptr_placeholder": "Skriv inn én IP-adresse per linje",
|
||||||
"resolve_clients_title": "Skru på revers-oppleting av klienters IP-adresser",
|
"resolve_clients_title": "Skru på revers-oppleting av klienters IP-adresser",
|
||||||
|
"resolve_clients_desc": "Hvis aktivert, vil AdGuard Home forsøke å automatisk løse klienters vertsnavn fra deres IP-adresser ved å sende en PTR-forespørsel til en tilsvarende resolver (privat DNS-server for lokale klienter, upstream-server for klienter med offentlig IP-adresse).",
|
||||||
"use_private_ptr_resolvers_title": "Bruk private omvendte DNS-løsere",
|
"use_private_ptr_resolvers_title": "Bruk private omvendte DNS-løsere",
|
||||||
|
"use_private_ptr_resolvers_desc": "Løs PTR-, SOA- og NS-forespørslene for ARPA-domener som inneholder private IP-adresser gjennom private oppstrømsservere, DHCP, /etc/hosts osv. Hvis deaktivert, vil AdGuard Home svare på alle slike forespørsel med NXDOMAIN.",
|
||||||
"check_dhcp_servers": "Se etter DHCP-tjenere",
|
"check_dhcp_servers": "Se etter DHCP-tjenere",
|
||||||
"save_config": "Lagre oppsettet",
|
"save_config": "Lagre oppsettet",
|
||||||
"enabled_dhcp": "DHCP-tjeneren ble skrudd på",
|
"enabled_dhcp": "DHCP-tjeneren ble skrudd på",
|
||||||
@@ -38,6 +41,7 @@
|
|||||||
"dhcp_ipv6_settings": "DHCP IPv6-innstillinger",
|
"dhcp_ipv6_settings": "DHCP IPv6-innstillinger",
|
||||||
"form_error_required": "Påkrevd felt",
|
"form_error_required": "Påkrevd felt",
|
||||||
"form_error_ip4_format": "Ugyldig IPv4-format",
|
"form_error_ip4_format": "Ugyldig IPv4-format",
|
||||||
|
"form_error_ip4_gateway_format": "Ugyldig IPv4-adresse for gatewayen",
|
||||||
"form_error_ip6_format": "Ugyldig IPv6-format",
|
"form_error_ip6_format": "Ugyldig IPv6-format",
|
||||||
"form_error_ip_format": "Ugyldig IPv4-format",
|
"form_error_ip_format": "Ugyldig IPv4-format",
|
||||||
"form_error_mac_format": "Ugyldig MAC-format",
|
"form_error_mac_format": "Ugyldig MAC-format",
|
||||||
@@ -45,7 +49,12 @@
|
|||||||
"form_error_server_name": "Ugyldig tjenernavn",
|
"form_error_server_name": "Ugyldig tjenernavn",
|
||||||
"form_error_subnet": "Undernettet «{{cidr}}» inneholder ikke IP-adressen «{{ip}}»",
|
"form_error_subnet": "Undernettet «{{cidr}}» inneholder ikke IP-adressen «{{ip}}»",
|
||||||
"form_error_positive": "Må være høyere enn 0",
|
"form_error_positive": "Må være høyere enn 0",
|
||||||
|
"form_error_gateway_ip": "Leie kan ikke ha IP-adresse til gateway",
|
||||||
|
"out_of_range_error": "Må være utenfor rekkevidden \"{{start}}\"-\"{{end}}\"",
|
||||||
|
"lower_range_start_error": "Må være lavere enn rekkeviddens start",
|
||||||
"greater_range_start_error": "Må være høyere enn rekkeviddens start",
|
"greater_range_start_error": "Må være høyere enn rekkeviddens start",
|
||||||
|
"subnet_error": "Adresser må være i en subnett",
|
||||||
|
"gateway_or_subnet_invalid": "Ugyldig undernettmaske",
|
||||||
"dhcp_form_gateway_input": "Gateway-IP",
|
"dhcp_form_gateway_input": "Gateway-IP",
|
||||||
"dhcp_form_subnet_input": "Nettverksmaske",
|
"dhcp_form_subnet_input": "Nettverksmaske",
|
||||||
"dhcp_form_range_title": "Spennvidden til IP-adressene",
|
"dhcp_form_range_title": "Spennvidden til IP-adressene",
|
||||||
@@ -65,9 +74,14 @@
|
|||||||
"dhcp_dynamic_ip_found": "Systemet ditt bruker et oppsett med dynamisk IP-adresse for grensesnittet <0>{{interfaceName}}</0>. For å kunne bruke DHCP-tjeneren, må en statisk IP-adresse ha blitt satt opp. Din nåværende IP-adresse er <0>{{ipAddress}}</0>. Vi vil automatisk gjøre denne IP-adressen statisk hvis du trykker på «Skru på DHCP»-knappen.",
|
"dhcp_dynamic_ip_found": "Systemet ditt bruker et oppsett med dynamisk IP-adresse for grensesnittet <0>{{interfaceName}}</0>. For å kunne bruke DHCP-tjeneren, må en statisk IP-adresse ha blitt satt opp. Din nåværende IP-adresse er <0>{{ipAddress}}</0>. Vi vil automatisk gjøre denne IP-adressen statisk hvis du trykker på «Skru på DHCP»-knappen.",
|
||||||
"dhcp_lease_added": "Den statiske leieavtalen «{{key}}» ble vellykket lagt til",
|
"dhcp_lease_added": "Den statiske leieavtalen «{{key}}» ble vellykket lagt til",
|
||||||
"dhcp_lease_deleted": "Den statiske leieavtalen «{{key}}» ble vellykket lagt slettet",
|
"dhcp_lease_deleted": "Den statiske leieavtalen «{{key}}» ble vellykket lagt slettet",
|
||||||
|
"dhcp_lease_updated": "Den statiske leieavtalen «{{key}}» ble vellykket oppdatert",
|
||||||
"dhcp_new_static_lease": "Ny statisk leieavtale",
|
"dhcp_new_static_lease": "Ny statisk leieavtale",
|
||||||
|
"dhcp_edit_static_lease": "Rediger statisk leieavtale",
|
||||||
"dhcp_static_leases_not_found": "Ingen statiske DHCP-leieavtaler ble funnet",
|
"dhcp_static_leases_not_found": "Ingen statiske DHCP-leieavtaler ble funnet",
|
||||||
"dhcp_add_static_lease": "Legg til statisk leieavtale",
|
"dhcp_add_static_lease": "Legg til statisk leieavtale",
|
||||||
|
"dhcp_reset_leases": "Tilbakestill alle leieavtaler",
|
||||||
|
"dhcp_reset_leases_confirm": "Er du sikker på at du vil tilbakestille alle leieavtaler?",
|
||||||
|
"dhcp_reset_leases_success": "DHCP-leieavtaler tilbakestilt med suksess",
|
||||||
"dhcp_reset": "Er du sikker på at du vil tilbakestille DHCP-oppsettet?",
|
"dhcp_reset": "Er du sikker på at du vil tilbakestille DHCP-oppsettet?",
|
||||||
"country": "Land",
|
"country": "Land",
|
||||||
"city": "By",
|
"city": "By",
|
||||||
@@ -106,6 +120,8 @@
|
|||||||
"stats_malware_phishing": "Blokkert skadevare/phishing",
|
"stats_malware_phishing": "Blokkert skadevare/phishing",
|
||||||
"stats_adult": "Blokkerte voksennettsteder",
|
"stats_adult": "Blokkerte voksennettsteder",
|
||||||
"stats_query_domain": "Mest forespurte domener",
|
"stats_query_domain": "Mest forespurte domener",
|
||||||
|
"for_last_hours": "for den siste {{count}} timen",
|
||||||
|
"for_last_hours_plural": "for de siste {{count}} timene",
|
||||||
"for_last_days": "for den siste {{count}} dagen",
|
"for_last_days": "for den siste {{count}} dagen",
|
||||||
"for_last_days_plural": "de siste {{count}} dagene",
|
"for_last_days_plural": "de siste {{count}} dagene",
|
||||||
"stats_disabled": "Statistikkene har blitt skrudd av. Du kan skru den på fra <0>innstillingssiden</0>.",
|
"stats_disabled": "Statistikkene har blitt skrudd av. Du kan skru den på fra <0>innstillingssiden</0>.",
|
||||||
@@ -120,12 +136,15 @@
|
|||||||
"no_upstreams_data_found": "Ingen oppstrøms servere data funnet",
|
"no_upstreams_data_found": "Ingen oppstrøms servere data funnet",
|
||||||
"number_of_dns_query_days": "Antall DNS-spørringer behandlet for de siste {{count}} dagene",
|
"number_of_dns_query_days": "Antall DNS-spørringer behandlet for de siste {{count}} dagene",
|
||||||
"number_of_dns_query_days_plural": "Antall DNS-forespørsler som ble behandlet de siste {{count}} dagene",
|
"number_of_dns_query_days_plural": "Antall DNS-forespørsler som ble behandlet de siste {{count}} dagene",
|
||||||
|
"number_of_dns_query_hours": "Antall DNS-forespøringer behandlet for den siste {{count}} timen",
|
||||||
|
"number_of_dns_query_hours_plural": "Antall DNS-forespørsel som ble behandlet de siste {{count}} timene",
|
||||||
"number_of_dns_query_blocked_24_hours": "Antall DNS-forespørsler som ble blokkert av adblock-filtre, hosts-lister, og domene-lister",
|
"number_of_dns_query_blocked_24_hours": "Antall DNS-forespørsler som ble blokkert av adblock-filtre, hosts-lister, og domene-lister",
|
||||||
"number_of_dns_query_blocked_24_hours_by_sec": "Antall DNS-forespørsler som ble blokkert av AdGuard sin nettlesersikkerhetsmodul",
|
"number_of_dns_query_blocked_24_hours_by_sec": "Antall DNS-forespørsler som ble blokkert av AdGuard sin nettlesersikkerhetsmodul",
|
||||||
"number_of_dns_query_blocked_24_hours_adult": "Antall voksennettsteder som ble blokkert",
|
"number_of_dns_query_blocked_24_hours_adult": "Antall voksennettsteder som ble blokkert",
|
||||||
"enforced_save_search": "Påtvungede barnevennlige søk",
|
"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",
|
"number_of_dns_query_to_safe_search": "Antall DNS-forespørsler til søkemotorer der \"Safe Search\" ble fremtvunget",
|
||||||
"average_processing_time": "Gjennomsnittlig behandlingstid",
|
"average_processing_time": "Gjennomsnittlig behandlingstid",
|
||||||
|
"average_upstream_response_time": "Gjennomsnittlig responstid fra oppstrømsserver",
|
||||||
"response_time": "Responstid",
|
"response_time": "Responstid",
|
||||||
"average_processing_time_hint": "Gjennomsnittstid for behandling av DNS-forespørsler i millisekunder",
|
"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",
|
"block_domain_use_filters_and_hosts": "Blokker domener ved hjelp av filtre, «hosts»-filer, og rå domener",
|
||||||
@@ -135,7 +154,7 @@
|
|||||||
"use_adguard_parental": "Benytt AdGuard sin foreldrekontroll-nettjeneste",
|
"use_adguard_parental": "Benytt AdGuard sin foreldrekontroll-nettjeneste",
|
||||||
"use_adguard_parental_hint": "AdGuard Home vil sjekke om domenet inneholder erotisk materiale. Den benytter den samme privatlivsvennlige API-en som nettlesersikkerhetstjenesten.",
|
"use_adguard_parental_hint": "AdGuard Home vil sjekke om domenet inneholder erotisk materiale. Den benytter den samme privatlivsvennlige API-en som nettlesersikkerhetstjenesten.",
|
||||||
"enforce_safe_search": "Påtving barnevennlige søk",
|
"enforce_safe_search": "Påtving barnevennlige søk",
|
||||||
"enforce_save_search_hint": "AdGuard Home kan fremtvinge \"Safe Search\" i de følgende søkemotorene: Google, YouTube, Bing, DuckDuckGo, Yandex, og Pixabay.",
|
"enforce_save_search_hint": "AdGuard Home vil håndheve \"Safe Search\" i følgende søkemotorer: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||||
"no_servers_specified": "Ingen tjenere er spesifisert",
|
"no_servers_specified": "Ingen tjenere er spesifisert",
|
||||||
"general_settings": "Generelle innstillinger",
|
"general_settings": "Generelle innstillinger",
|
||||||
"dns_settings": "DNS-innstillinger",
|
"dns_settings": "DNS-innstillinger",
|
||||||
@@ -161,6 +180,7 @@
|
|||||||
"enabled_parental_toast": "Skrudde på foreldrekontroll",
|
"enabled_parental_toast": "Skrudde på foreldrekontroll",
|
||||||
"disabled_safe_search_toast": "Skrudde av barnevennlige søk",
|
"disabled_safe_search_toast": "Skrudde av barnevennlige søk",
|
||||||
"enabled_save_search_toast": "Skrudde på barnevennlige søk",
|
"enabled_save_search_toast": "Skrudde på barnevennlige søk",
|
||||||
|
"updated_save_search_toast": "Innstillinger for sikker søk oppdatert",
|
||||||
"enabled_table_header": "Skrudd på",
|
"enabled_table_header": "Skrudd på",
|
||||||
"name_table_header": "Navn",
|
"name_table_header": "Navn",
|
||||||
"list_url_table_header": "Listens nettadresse",
|
"list_url_table_header": "Listens nettadresse",
|
||||||
@@ -202,22 +222,29 @@
|
|||||||
"example_comment_hash": "# Også en kommentar",
|
"example_comment_hash": "# Også en kommentar",
|
||||||
"example_regex_meaning": "blokker tilgang til domener som samsvarer med den valgte ordinære oppføringen",
|
"example_regex_meaning": "blokker tilgang til domener som samsvarer med den valgte ordinære oppføringen",
|
||||||
"example_upstream_regular": "vanlig DNS (over UDP)",
|
"example_upstream_regular": "vanlig DNS (over UDP)",
|
||||||
|
"example_upstream_regular_port": "vanlig DNS (over UDP, med port);",
|
||||||
|
"example_upstream_udp": "vanlig DNS (over UDP, vertsnavn);",
|
||||||
"example_upstream_dot": "kryptert <0>DNS-over-TLS</0>",
|
"example_upstream_dot": "kryptert <0>DNS-over-TLS</0>",
|
||||||
"example_upstream_doh": "kryptert <0>DNS-over-HTTPS</0>",
|
"example_upstream_doh": "kryptert <0>DNS-over-HTTPS</0>",
|
||||||
|
"example_upstream_doh3": "kryptert DNS-over-HTTPS med tvungen <0>HTTP/3</0> og uten fallback til HTTP/2 eller lavere;",
|
||||||
"example_upstream_doq": "kryptert <0>DNS-over-QUIC</0>;",
|
"example_upstream_doq": "kryptert <0>DNS-over-QUIC</0>;",
|
||||||
"example_upstream_sdns": "du kan bruke <0>DNS-stempler</0> med <1>DNSCrypt</1> eller <2>DNS-over-HTTPS</2>-behandlere",
|
"example_upstream_sdns": "du kan bruke <0>DNS-stempler</0> med <1>DNSCrypt</1> eller <2>DNS-over-HTTPS</2>-behandlere",
|
||||||
"example_upstream_tcp": "vanlig DNS (over TCP)",
|
"example_upstream_tcp": "vanlig DNS (over TCP)",
|
||||||
|
"example_upstream_tcp_port": "vanlig DNS (over TCP, med port);",
|
||||||
|
"example_upstream_tcp_hostname": "vanlig DNS (over TCP, vertsnavn);",
|
||||||
"all_lists_up_to_date_toast": "Alle listene er allerede oppdatert",
|
"all_lists_up_to_date_toast": "Alle listene er allerede oppdatert",
|
||||||
"updated_upstream_dns_toast": "Oppdaterte oppstrøms-DNS-tjenerne",
|
"updated_upstream_dns_toast": "Oppdaterte oppstrøms-DNS-tjenerne",
|
||||||
"dns_test_ok_toast": "De spesifiserte DNS-tjenerne fungerer riktig",
|
"dns_test_ok_toast": "De spesifiserte DNS-tjenerne fungerer riktig",
|
||||||
"dns_test_not_ok_toast": "Tjeneren «{{key}}» kunne ikke brukes, vennligst dobbeltsjekk at du har skrevet den riktig",
|
"dns_test_not_ok_toast": "Tjeneren «{{key}}» kunne ikke brukes, vennligst dobbeltsjekk at du har skrevet den riktig",
|
||||||
"dns_test_parsing_error_toast": "Seksjon {{section}}: linje {{line}}: kunne ikke brukes, vennligst sjekk at du har skrevet det riktig",
|
"dns_test_parsing_error_toast": "Seksjon {{section}}: linje {{line}}: kunne ikke brukes, vennligst sjekk at du har skrevet det riktig",
|
||||||
|
"dns_test_warning_toast": "Oppstrøms \"{{key}}\" svarer ikke på testforespørselene og fungerer kanskje ikke riktig",
|
||||||
"unblock": "Tillat",
|
"unblock": "Tillat",
|
||||||
"block": "Blokker",
|
"block": "Blokker",
|
||||||
"disallow_this_client": "Ikke tillat denne klienten",
|
"disallow_this_client": "Ikke tillat denne klienten",
|
||||||
"allow_this_client": "Tillat denne klienten",
|
"allow_this_client": "Tillat denne klienten",
|
||||||
"block_for_this_client_only": "Blokker kun for denne klienten",
|
"block_for_this_client_only": "Blokker kun for denne klienten",
|
||||||
"unblock_for_this_client_only": "Opphev blokkering kun for denne enheten",
|
"unblock_for_this_client_only": "Opphev blokkering kun for denne enheten",
|
||||||
|
"add_persistent_client": "Legg til som vedvarende klient",
|
||||||
"time_table_header": "Tidspunkt",
|
"time_table_header": "Tidspunkt",
|
||||||
"date": "Dato",
|
"date": "Dato",
|
||||||
"domain_name_table_header": "Domenenavn",
|
"domain_name_table_header": "Domenenavn",
|
||||||
@@ -265,6 +292,11 @@
|
|||||||
"blocking_ipv4": "IPv4-blokkering",
|
"blocking_ipv4": "IPv4-blokkering",
|
||||||
"blocking_ipv6": "IPv6-blokkering",
|
"blocking_ipv6": "IPv6-blokkering",
|
||||||
"blocked_response_ttl": "Blokkerte svars TTL",
|
"blocked_response_ttl": "Blokkerte svars TTL",
|
||||||
|
"blocked_response_ttl_desc": "Angir hvor mange sekunder klientene skal cache et filtrert svar",
|
||||||
|
"form_enter_blocked_response_ttl": "Skriv inn TTL for blokkerte svar (sekunder)",
|
||||||
|
"upstream_timeout": "Oppstrøms tidsavbrudd",
|
||||||
|
"upstream_timeout_desc": "Spesifiserer antallet sekunder å vente på svar fra oppstrømsserveren",
|
||||||
|
"form_enter_upstream_timeout": "Skriv inn oppstrømsserverens tidsavbrudd varighet i sekunder",
|
||||||
"dnscrypt": "DNSCrypt",
|
"dnscrypt": "DNSCrypt",
|
||||||
"dns_over_https": "DNS-over-HTTPS",
|
"dns_over_https": "DNS-over-HTTPS",
|
||||||
"dns_over_tls": "DNS-over-TLS",
|
"dns_over_tls": "DNS-over-TLS",
|
||||||
@@ -280,7 +312,19 @@
|
|||||||
"rate_limit": "Forespørselsfrekvensgrense",
|
"rate_limit": "Forespørselsfrekvensgrense",
|
||||||
"edns_enable": "Aktiver EDNS-klientundernett",
|
"edns_enable": "Aktiver EDNS-klientundernett",
|
||||||
"edns_cs_desc": "Hvis det er skrudd på, vil AdGuard Home sende klientenes undernett til DNS-tjenerne.",
|
"edns_cs_desc": "Hvis det er skrudd på, vil AdGuard Home sende klientenes undernett til DNS-tjenerne.",
|
||||||
|
"edns_use_custom_ip": "Bruk tilpasset IP for EDNS",
|
||||||
|
"edns_use_custom_ip_desc": "Tillat å bruke tilpasset IP for EDNS",
|
||||||
"rate_limit_desc": "Antallet forespørsler per sekund som én enkelt klient har lov til å be om (0: ubegrenset)",
|
"rate_limit_desc": "Antallet forespørsler per sekund som én enkelt klient har lov til å be om (0: ubegrenset)",
|
||||||
|
"rate_limit_subnet_len_ipv4": "Lengde på subnettprefiks for IPv4-adresser",
|
||||||
|
"rate_limit_subnet_len_ipv4_desc": "Subnet prefixlengde for IPv4-adresser som brukes til ratebegrensning. Standard er 24",
|
||||||
|
"rate_limit_subnet_len_ipv4_error": "IPv4 subnet prefixlengde bør være mellom 0 og 32",
|
||||||
|
"rate_limit_subnet_len_ipv6": "Subnet prefixlengde for IPv6-adresser",
|
||||||
|
"rate_limit_subnet_len_ipv6_desc": "Subnet prefixlengde for IPv6-adresser som brukes til ratebegrensning. Standard er 56",
|
||||||
|
"rate_limit_subnet_len_ipv6_error": "IPv6 subnet prefixlengde bør være mellom 0 og 128",
|
||||||
|
"form_enter_rate_limit_subnet_len": "Oppgi subnet prefixlengde for ratebegrensning",
|
||||||
|
"rate_limit_whitelist": "Ratebegrensnings tillatelsesliste",
|
||||||
|
"rate_limit_whitelist_desc": "IP-adresser unntatt fra ratebegrensning",
|
||||||
|
"rate_limit_whitelist_placeholder": "Skriv inn én IP-adresse per linje",
|
||||||
"blocking_ipv4_desc": "IP-adressen som det skal svares med for blokkerte A-forespørsler",
|
"blocking_ipv4_desc": "IP-adressen som det skal svares med for blokkerte A-forespørsler",
|
||||||
"blocking_ipv6_desc": "IP-adressen som det skal svares med for blokkerte AAAA-forespørsler",
|
"blocking_ipv6_desc": "IP-adressen som det skal svares med for blokkerte AAAA-forespørsler",
|
||||||
"blocking_mode_default": "Standard: Svar med null-IP-adresse (0.0.0.0 for A; :: for AAAA) når den blokkeres av adblock-aktige oppføringer; svar med IP-adressen som er spesifisert i oppføringen når den blokkeres av /etc/hosts-typeoppføringer",
|
"blocking_mode_default": "Standard: Svar med null-IP-adresse (0.0.0.0 for A; :: for AAAA) når den blokkeres av adblock-aktige oppføringer; svar med IP-adressen som er spesifisert i oppføringen når den blokkeres av /etc/hosts-typeoppføringer",
|
||||||
@@ -384,6 +428,9 @@
|
|||||||
"encryption_hostnames": "Vertsnavn",
|
"encryption_hostnames": "Vertsnavn",
|
||||||
"encryption_reset": "Er du sikker på at du vil tilbakestille krypteringsinnstillingene?",
|
"encryption_reset": "Er du sikker på at du vil tilbakestille krypteringsinnstillingene?",
|
||||||
"encryption_warning": "Advarsel",
|
"encryption_warning": "Advarsel",
|
||||||
|
"encryption_plain_dns_enable": "Aktiver vanlig DNS",
|
||||||
|
"encryption_plain_dns_desc": "Vanlig DNS er aktivert som standard. Du kan deaktivere den for å tvinge alle enheter til å bruke kryptert DNS. For å gjøre dette må du aktivere minst ett kryptert DNS-protokoll",
|
||||||
|
"encryption_plain_dns_error": "For å deaktivere vanlig DNS, aktiver minst ett kryptert DNS-protokoll",
|
||||||
"topline_expiring_certificate": "Ditt SSL-sertifikat er i ferd med å utløpe. Oppdater <0>Krypteringsinnstillinger</0>.",
|
"topline_expiring_certificate": "Ditt SSL-sertifikat er i ferd med å utløpe. Oppdater <0>Krypteringsinnstillinger</0>.",
|
||||||
"topline_expired_certificate": "SSL-sertifikatet har utløpt. Oppdater <0>Krypteringsinnstillinger</0>.",
|
"topline_expired_certificate": "SSL-sertifikatet har utløpt. Oppdater <0>Krypteringsinnstillinger</0>.",
|
||||||
"form_error_port_range": "Skriv inn et portnummer i området 80-65535",
|
"form_error_port_range": "Skriv inn et portnummer i området 80-65535",
|
||||||
@@ -401,6 +448,7 @@
|
|||||||
"dns_providers": "Her er en <0>liste over kjente DNS-leverandører</0> som du kan velge blant.",
|
"dns_providers": "Her er en <0>liste over kjente DNS-leverandører</0> som du kan velge blant.",
|
||||||
"update_now": "Oppdater nå",
|
"update_now": "Oppdater nå",
|
||||||
"update_failed": "Auto-oppdatering mislyktes. Vennligst <a>følg trinnene</a> for manuelle oppdateringer.",
|
"update_failed": "Auto-oppdatering mislyktes. Vennligst <a>følg trinnene</a> for manuelle oppdateringer.",
|
||||||
|
"manual_update": "Vennligst <a>følg disse trinnene</a> for manuell oppdatering.",
|
||||||
"processing_update": "Vennligst vent, AdGuard Home blir oppdatert",
|
"processing_update": "Vennligst vent, AdGuard Home blir oppdatert",
|
||||||
"clients_title": "Klienter",
|
"clients_title": "Klienter",
|
||||||
"clients_desc": "Konfigurer enheter som er koblet til AdGuard Home",
|
"clients_desc": "Konfigurer enheter som er koblet til AdGuard Home",
|
||||||
@@ -422,6 +470,7 @@
|
|||||||
"form_add_id": "Legg til identifikator",
|
"form_add_id": "Legg til identifikator",
|
||||||
"form_client_name": "Skriv inn klientnavnet",
|
"form_client_name": "Skriv inn klientnavnet",
|
||||||
"name": "Navn",
|
"name": "Navn",
|
||||||
|
"client_name": "Klient {{id}}",
|
||||||
"client_global_settings": "Bruk de overbestyrte innstillingene",
|
"client_global_settings": "Bruk de overbestyrte innstillingene",
|
||||||
"client_deleted": "Klienten «{{key}}» ble vellykket slettet",
|
"client_deleted": "Klienten «{{key}}» ble vellykket slettet",
|
||||||
"client_added": "Klienten «{{key}}» ble vellykket lagt til",
|
"client_added": "Klienten «{{key}}» ble vellykket lagt til",
|
||||||
@@ -514,6 +563,10 @@
|
|||||||
"statistics_retention_confirm": "Er du sikker på at du vil endre hvor lenge statistikkene skal beholdes? Hvis du reduserer den interne verdien, vil noe av dataene gå tapt",
|
"statistics_retention_confirm": "Er du sikker på at du vil endre hvor lenge statistikkene skal beholdes? Hvis du reduserer den interne verdien, vil noe av dataene gå tapt",
|
||||||
"statistics_cleared": "Statistikkene ble vellykket tømt",
|
"statistics_cleared": "Statistikkene ble vellykket tømt",
|
||||||
"statistics_enable": "Skru på statistikker",
|
"statistics_enable": "Skru på statistikker",
|
||||||
|
"ignore_domains": "Ignorerte domener (separate med linjeskift)",
|
||||||
|
"ignore_domains_title": "Ignorerte domener",
|
||||||
|
"ignore_domains_desc_stats": "Forespørslene som samsvarer med disse reglene, skrives ikke til statistikken",
|
||||||
|
"ignore_domains_desc_query": "Forespørslene som samsvarer med disse reglene, skrives ikke til loggen for forespørslene",
|
||||||
"interval_hours": "{{count}} time",
|
"interval_hours": "{{count}} time",
|
||||||
"interval_hours_plural": "{{count}} timer",
|
"interval_hours_plural": "{{count}} timer",
|
||||||
"filters_configuration": "Oppsett av filtre",
|
"filters_configuration": "Oppsett av filtre",
|
||||||
@@ -548,7 +601,7 @@
|
|||||||
"disable_ipv6": "Skru av IPv6",
|
"disable_ipv6": "Skru av IPv6",
|
||||||
"disable_ipv6_desc": "Slipp alle DNS-spørringer for IPv6-adresser (type AAAA) og fjern IPv6-hint fra HTTPS-svar.",
|
"disable_ipv6_desc": "Slipp alle DNS-spørringer for IPv6-adresser (type AAAA) og fjern IPv6-hint fra HTTPS-svar.",
|
||||||
"fastest_addr": "Raskeste IP-adresse",
|
"fastest_addr": "Raskeste IP-adresse",
|
||||||
"fastest_addr_desc": "Forespør alle DNS-tjenerne og hent den raskeste IP-adressen blant alle svarene. Dette vil gjøre DNS-forespørslene tregere, siden vi må vente på svar fra alle DNS-tjenerne, men det vil forbedre tilkoblingen generelt.",
|
"fastest_addr_desc": "Vent på svar fra <b>alle</b> DNS-serverne, mål TCP-tilkoblingshastigheten for hver server, og returner IP-adressen til serveren med den raskeste tilkoblingshastigheten.<br/>Denne modusen kan betydelig bremse DNS-forespørslene, hvis en eller flere oppstrømsservere ikke svarer. Sørg for at oppstrømsserverne dine er stabile og at oppstrøms tidsavbruddet er lavt.",
|
||||||
"autofix_warning_text": "Hvis du klikker på «Fiks», vil AdGuard Home sette opp systemet ditt til å bruke 'AdGuard Home'-DNS-tjeneren.",
|
"autofix_warning_text": "Hvis du klikker på «Fiks», vil AdGuard Home sette opp systemet ditt til å bruke 'AdGuard Home'-DNS-tjeneren.",
|
||||||
"autofix_warning_list": "Den vil utføre disse handlingene: <0>Skru av systemets DNSStubListener</0> <0>Sette DNS-tjeneradressen til 127.0.0.1</0> <0>Bytte ut det symbolske lenkemålet til /etc/resolv.conf med /run/systemd/resolve/resolv.conf</0> <0>Stoppe DNSStubListener (gjeninnlast 'systemd-resolved'-tjenesten)</0>",
|
"autofix_warning_list": "Den vil utføre disse handlingene: <0>Skru av systemets DNSStubListener</0> <0>Sette DNS-tjeneradressen til 127.0.0.1</0> <0>Bytte ut det symbolske lenkemålet til /etc/resolv.conf med /run/systemd/resolve/resolv.conf</0> <0>Stoppe DNSStubListener (gjeninnlast 'systemd-resolved'-tjenesten)</0>",
|
||||||
"autofix_warning_result": "Som følge av det vil alle DNS-forespørsler fra systemet ditt bli behandlet av AdGuard Home som standard.",
|
"autofix_warning_result": "Som følge av det vil alle DNS-forespørsler fra systemet ditt bli behandlet av AdGuard Home som standard.",
|
||||||
@@ -567,6 +620,10 @@
|
|||||||
"check_cname": "CNAME: {{cname}}",
|
"check_cname": "CNAME: {{cname}}",
|
||||||
"check_reason": "Årsak: {{reason}}",
|
"check_reason": "Årsak: {{reason}}",
|
||||||
"check_service": "Tjenestenavn: {{service}}",
|
"check_service": "Tjenestenavn: {{service}}",
|
||||||
|
"check_hostname": "Vertsnavn eller domenenavn",
|
||||||
|
"check_client_id": "Klientidentifikator (ClientID eller IP-adresse)",
|
||||||
|
"check_enter_client_id": "Skriv inn klientidentifikator",
|
||||||
|
"check_dns_record": "Velg type DNS-post",
|
||||||
"service_name": "Tjenestenavn",
|
"service_name": "Tjenestenavn",
|
||||||
"check_not_found": "Ikke funnet i filterlistene dine",
|
"check_not_found": "Ikke funnet i filterlistene dine",
|
||||||
"client_confirm_block": "Er du sikker på at du vil blokkere klienten «{{ip}}»?",
|
"client_confirm_block": "Er du sikker på at du vil blokkere klienten «{{ip}}»?",
|
||||||
@@ -599,7 +656,7 @@
|
|||||||
"blocklist": "Blokkeringsliste",
|
"blocklist": "Blokkeringsliste",
|
||||||
"milliseconds_abbreviation": "ms",
|
"milliseconds_abbreviation": "ms",
|
||||||
"cache_size": "Mellomlagerstørrelse",
|
"cache_size": "Mellomlagerstørrelse",
|
||||||
"cache_size_desc": "DNS-bufferstørrelse (i byte). For å deaktivere caching, la stå tomt.",
|
"cache_size_desc": "DNS-cache-størrelse (i bytes). For å deaktivere caching, sett til 0.",
|
||||||
"cache_ttl_min_override": "Overstyr minimumslevetiden",
|
"cache_ttl_min_override": "Overstyr minimumslevetiden",
|
||||||
"cache_ttl_max_override": "Overstyr maksimallevetiden",
|
"cache_ttl_max_override": "Overstyr maksimallevetiden",
|
||||||
"enter_cache_size": "Skriv inn mellomlagerstørrelse (i bytes)",
|
"enter_cache_size": "Skriv inn mellomlagerstørrelse (i bytes)",
|
||||||
@@ -623,16 +680,41 @@
|
|||||||
"click_to_view_queries": "Klikk for å vise forespørsler",
|
"click_to_view_queries": "Klikk for å vise forespørsler",
|
||||||
"port_53_faq_link": "Port 53 er ofte opptatt av «DNSStubListener»- eller «systemd-resolved»-tjenestene. Vennligst les <0>denne instruksjonen</0> om hvordan man løser dette.",
|
"port_53_faq_link": "Port 53 er ofte opptatt av «DNSStubListener»- eller «systemd-resolved»-tjenestene. Vennligst les <0>denne instruksjonen</0> om hvordan man løser dette.",
|
||||||
"adg_will_drop_dns_queries": "AdGuard Home vil droppe alle DNS-forespørsler fra denne klienten.",
|
"adg_will_drop_dns_queries": "AdGuard Home vil droppe alle DNS-forespørsler fra denne klienten.",
|
||||||
|
"filter_allowlist": "ADVARSEL: Denne handlingen vil også ekskludere regelen \"{{disallowed_rule}}\" fra listen over tillatte klienter.",
|
||||||
|
"last_rule_in_allowlist": "Kan ikke nekte denne klienten fordi utelukkelse av regelen \"{{disallowed_rule}}\" vil deaktivere listen over \"Tillatte klienter\".",
|
||||||
"use_saved_key": "Bruk den tidligere lagrede nøkkelen",
|
"use_saved_key": "Bruk den tidligere lagrede nøkkelen",
|
||||||
"parental_control": "Foreldrekontroll",
|
"parental_control": "Foreldrekontroll",
|
||||||
"safe_browsing": "Sikker surfing",
|
"safe_browsing": "Sikker surfing",
|
||||||
|
"served_from_cache_label": "Formidlet fra mellomlageret",
|
||||||
|
"form_error_password_length": "Passordet må være {{min}} til {{max}} tegn langt",
|
||||||
|
"anonymizer_notification": "<0>Merk:</0> IP-anonymisering er aktivert. Du kan deaktivere det i <1>Generelle innstillinger</1>.",
|
||||||
|
"confirm_dns_cache_clear": "Er du sikker på at du vil tømme DNS-bufferet?",
|
||||||
|
"cache_cleared": "DNS-bufferet ble vellykket tømt",
|
||||||
|
"clear_cache": "Tøm cache",
|
||||||
|
"make_static": "Gjør statisk",
|
||||||
|
"theme_auto_desc": "Auto (basert på fargeoppsettet til enheten din)",
|
||||||
"theme_dark_desc": "Mørkt tema",
|
"theme_dark_desc": "Mørkt tema",
|
||||||
"theme_light_desc": "Lyst tema",
|
"theme_light_desc": "Lyst tema",
|
||||||
|
"disable_for_seconds": "For {{count}} sekund",
|
||||||
|
"disable_for_seconds_plural": "For {{count}} sekunder",
|
||||||
|
"disable_for_minutes": "For {{count}} minutt",
|
||||||
|
"disable_for_minutes_plural": "For {{count}} minutter",
|
||||||
|
"disable_for_hours": "For {{count}} time",
|
||||||
|
"disable_for_hours_plural": "For {{count}} timer",
|
||||||
|
"disable_until_tomorrow": "Frem til i morgen",
|
||||||
|
"disable_notify_for_seconds": "Deaktiver beskyttelse i {{count}} sekund",
|
||||||
|
"disable_notify_for_seconds_plural": "Deaktiver beskyttelse for {{count}} sekunder",
|
||||||
|
"disable_notify_for_minutes": "Deaktiver beskyttelse i {{count}} minutt",
|
||||||
|
"disable_notify_for_minutes_plural": "Deaktiver beskyttelsen for {{count}} minutter",
|
||||||
|
"disable_notify_for_hours": "Deaktiver beskyttelse i {{count}} time",
|
||||||
|
"disable_notify_for_hours_plural": "Skru av beskyttelse for {{count}} timer",
|
||||||
"disable_notify_until_tomorrow": "Deaktiver beskyttelsen til i morgen",
|
"disable_notify_until_tomorrow": "Deaktiver beskyttelsen til i morgen",
|
||||||
"enable_protection_timer": "Beskyttelse vil være aktivert i {{time}}",
|
"enable_protection_timer": "Beskyttelse vil være aktivert i {{time}}",
|
||||||
"custom_retention_input": "Angi oppbevaring i timer",
|
"custom_retention_input": "Angi oppbevaring i timer",
|
||||||
"custom_rotation_input": "Angi rotasjon i timer",
|
"custom_rotation_input": "Angi rotasjon i timer",
|
||||||
"protection_section_label": "Beskyttelse",
|
"protection_section_label": "Beskyttelse",
|
||||||
|
"log_and_stats_section_label": "Spørringslogg og statistikk",
|
||||||
|
"ignore_query_log": "Ignorer denne klienten i spørringsloggen",
|
||||||
"ignore_statistics": "Ignorer denne klienten i statistikken",
|
"ignore_statistics": "Ignorer denne klienten i statistikken",
|
||||||
"schedule_services": "Sett blokkering av tjenesten på pause",
|
"schedule_services": "Sett blokkering av tjenesten på pause",
|
||||||
"schedule_services_desc": "Konfigurer pauseplanen for tjenesteblokkeringsfilteret",
|
"schedule_services_desc": "Konfigurer pauseplanen for tjenesteblokkeringsfilteret",
|
||||||
@@ -665,5 +747,8 @@
|
|||||||
"wednesday_short": "ons",
|
"wednesday_short": "ons",
|
||||||
"thursday_short": "tor",
|
"thursday_short": "tor",
|
||||||
"friday_short": "fre",
|
"friday_short": "fre",
|
||||||
"saturday_short": "lør"
|
"saturday_short": "lør",
|
||||||
|
"upstream_dns_cache_configuration": "Konfigurasjon av upstream DNS-cache",
|
||||||
|
"enable_upstream_dns_cache": "Aktiver DNS-caching for denne klientens tilpassede upstream-konfigurasjon",
|
||||||
|
"dns_cache_size": "DNS-bufferstørrelse (i byte)"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,26 @@
|
|||||||
{
|
{
|
||||||
"client_settings": "අනුග්රාහකයේ සැකසුම්",
|
"client_settings": "අනුග්රාහකයේ සැකසුම්",
|
||||||
|
"example_upstream_reserved": "ක්රමවේද ගෙන එන <0>නිශ්චිත වසම</0> සඳහා;",
|
||||||
|
"example_multiple_upstreams_reserved": "නිශ්චිත වසම් <0>සඳහා බහු උඩුගං</0>;",
|
||||||
"example_upstream_comment": "අදහසක්.",
|
"example_upstream_comment": "අදහසක්.",
|
||||||
|
"upstream_parallel": "සමාන්තර විමසුම් යොදා ගනිමින් සියලුම උඩුගත කරන සේවාදායක එකවර විමසුම් කිරීම මගින් විමසුම් වේගය වැඩිදියුණු කර ගත හැක.",
|
||||||
"parallel_requests": "සමාන්තර ඉල්ලීම්",
|
"parallel_requests": "සමාන්තර ඉල්ලීම්",
|
||||||
"load_balancing": "ධාරිතාව තුලනය",
|
"load_balancing": "ධාරිතාව තුලනය",
|
||||||
|
"load_balancing_desc": "එක වරකට එක උඩුගත කරන සේවාදායකයක් විමසුම් කරන්න.<br/>AdGuard Home උඩුගත කරන සේවාදායකයන් ගණනාව සහ සාමාන්ය විමසුම් කාලය පහත් කළ වන සේවාදායකය විශේෂිත ලෙස තෝරා ගැනීමට ඇස්තමේන්තු රැඳවුම් ප්රොසිජර් ක්රමයක් භාවිතා කරයි.",
|
||||||
|
"bootstrap_dns": "Bootstrap DNS සේවාදායකය",
|
||||||
|
"bootstrap_dns_desc": "DNS සේවාදායකයේ IP ලිපින, ඔබ උඩුගත සේවා මෙන්ම DoH/DoT විසඳුම් IP ලිපින නිර්දන් කරයි. মন্তব্য සිද්ධ නොවේ.",
|
||||||
|
"fallback_dns_title": "සමාන්ය DNS සේවාදායක",
|
||||||
|
"fallback_dns_desc": "උඩුගත DNS සේවාදායක සක්රිය නොවීමේදී භාවිතා කරන සමාන්ය DNS සේවාදායකවල ලැයිස්තුව. මෙම සංකේතය ඉහත ප්රධාන උඩුගත සේවාදායක ක්ෂේත්රයේ සමඟ ඒකසමාන වේ.",
|
||||||
|
"fallback_dns_placeholder": "ඒක පිරික්සුම් සමාන්ය DNS සේවාදායකයකු සෑදීම",
|
||||||
"local_ptr_title": "පෞද්ගලික ප්රතිවර්ත ව.නා.ප. සේවාදායක",
|
"local_ptr_title": "පෞද්ගලික ප්රතිවර්ත ව.නා.ප. සේවාදායක",
|
||||||
"local_ptr_desc": "ස්ථානීය PTR විමසුම් සඳහා ඇඩ්ගාර්ඩ් හෝම් භාවිතා කරන ව.නා.ප. සේවාදායක. මෙම සේවාදායක පුද්ගලික අ.ජා.කෙ. ලිපින පරාසවල PTR විමසුම් විසඳීමට භාවිතා කරයි, උදාහරණයක් ලෙස ප්රතිවර්ත ව.නා.ප. භාවිතයෙන් \"192.168.12.34\". මෙය සකසා නැති නම්, ඇඩ්ගාර්ඩ් හෝම් හි ලිපින සඳහා හැරුනු විට ඔබගේ මෙහෙයුම් පද්ධතියේ පෙරනිමි ව.නා.ප. විසදුම්වල ලිපින භාවිතා කරයි.",
|
"local_ptr_desc": "AdGuard Home හි පුද්ගලික PTR, SOA සහ NS ඉල්ලීම් සඳහා භාවිතායේ පවතින වා.නා.ප. සේවාදාකයන්. ඉල්ලීමක් පුද්ගලික ලෙස සැලකෙයි එය පුද්ගලික IP පරාසයන් (\"192.168.12.34\" වැනි) ඇතුළුව ඇති ARPA වාසමානේ යාමක් සඳහා ඉල්ලීමක් යැවී එය පුද්ගලික IP ලිපිනයක් ඇති පාරිභෝගිකයකු ලැබේ. එය සකස් නොකිරීමේදී, ඔබේ මෙහෙයුම් පද්ධතියේ දේශපාලනකරණ සේවාදාකයන් භාවිතා කරයි, AdGuard Home IP ලිපිනයන් හැර.",
|
||||||
"local_ptr_default_resolver": "පෙරනිමි පරිදි, ඇඩ්ගාර්ඩ් හෝම් පහත ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු භාවිතා කරයි: {{ip}}.",
|
"local_ptr_default_resolver": "පෙරනිමි පරිදි, ඇඩ්ගාර්ඩ් හෝම් පහත ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු භාවිතා කරයි: {{ip}}.",
|
||||||
"local_ptr_no_default_resolver": "ඇඩ්ගාර්ඩ් හෝම් හට මෙම පද්ධතිය සඳහා සුදුසු පුද්ගලික ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු නිශ්චය කරගත නොහැකි විය.",
|
"local_ptr_no_default_resolver": "ඇඩ්ගාර්ඩ් හෝම් හට මෙම පද්ධතිය සඳහා සුදුසු පුද්ගලික ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු නිශ්චය කරගත නොහැකි විය.",
|
||||||
"local_ptr_placeholder": "පේළියකට අ.ජා.කෙ. ලිපිනය බැගින් ලියන්න",
|
"local_ptr_placeholder": "පේළියකට අ.ජා.කෙ. ලිපිනය බැගින් ලියන්න",
|
||||||
"resolve_clients_title": "අනුග්රාහකවල අ.ජා.කෙ. ලිපින ප්රතිවර්ත විසඳීම සබල කරන්න",
|
"resolve_clients_title": "අනුග්රාහකවල අ.ජා.කෙ. ලිපින ප්රතිවර්ත විසඳීම සබල කරන්න",
|
||||||
|
"resolve_clients_desc": "පාරිභෝගිකයන්ගේ IP නාමාවලිය ආපසු ආශ්රිත කිරීමට PTR විමසුම් යවා මාදිලීන්ට අනුව සම්බන්ධතා අහඹු විකල්ප සඳහා යොදා ගන්න (ගෙන් සේවාදායකය සඳහා ප්රායෝගික DNS සේවාදායකයන්, පොදු IP ලිපිනයක් ඇති ගෙන් සේවාදායකය).",
|
||||||
"use_private_ptr_resolvers_title": "පෞද්. ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු භාවිතය",
|
"use_private_ptr_resolvers_title": "පෞද්. ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු භාවිතය",
|
||||||
|
"use_private_ptr_resolvers_desc": "පුද්ගලික IP ලිපිනයන් අඩංගු ARPA වාසමානේ සඳහා PTR, SOA සහ NS ඉල්ලීම් විසඳා ගැනීම සඳහා පුද්ගලික පෝෂක සේවාදායකය, DHCP, /etc/hosts ආදී व्यापक මාර්ග ආශ්රිත විසඳන්න. අබල කරන්නේ නම්, AdGuard Home සියලුම එවැනි ඉල්ලීම් සඳහා NXDOMAIN වශයෙන් පිළිතුරු දෙනු ඇත.",
|
||||||
"check_dhcp_servers": "ග.ධා.වි.කෙ. සේවාදායක පරීක්ෂා කරන්න",
|
"check_dhcp_servers": "ග.ධා.වි.කෙ. සේවාදායක පරීක්ෂා කරන්න",
|
||||||
"save_config": "වින්යාසය සුරකින්න",
|
"save_config": "වින්යාසය සුරකින්න",
|
||||||
"enabled_dhcp": "ග.ධා.වි.කෙ. සේවාදායකය සබල කෙරිණි",
|
"enabled_dhcp": "ග.ධා.වි.කෙ. සේවාදායකය සබල කෙරිණි",
|
||||||
@@ -30,6 +41,7 @@
|
|||||||
"dhcp_ipv6_settings": "ග.ධා.වි.කෙ. IPv6 සැකසුම්",
|
"dhcp_ipv6_settings": "ග.ධා.වි.කෙ. IPv6 සැකසුම්",
|
||||||
"form_error_required": "ඇවැසි ක්ෂේත්රයකි",
|
"form_error_required": "ඇවැසි ක්ෂේත්රයකි",
|
||||||
"form_error_ip4_format": "IPv4 ලිපිනය වලංගු නොවේ",
|
"form_error_ip4_format": "IPv4 ලිපිනය වලංගු නොවේ",
|
||||||
|
"form_error_ip4_gateway_format": "ගේට්වේ ගැලිමයේ වලංගු නොවන IPv4 ලිපිනය",
|
||||||
"form_error_ip6_format": "වලංගු නොවන IPv6 ලිපිනයකි",
|
"form_error_ip6_format": "වලංගු නොවන IPv6 ලිපිනයකි",
|
||||||
"form_error_ip_format": "අ.ජා.කෙ. (IP) ලිපිනය වලංගු නොවේ",
|
"form_error_ip_format": "අ.ජා.කෙ. (IP) ලිපිනය වලංගු නොවේ",
|
||||||
"form_error_mac_format": "මා.ප්ර.පා. ලිපිනය වලංගු නොවේ",
|
"form_error_mac_format": "මා.ප්ර.පා. ලිපිනය වලංගු නොවේ",
|
||||||
@@ -37,10 +49,14 @@
|
|||||||
"form_error_server_name": "සේවාදායකයේ නම වලංගු නොවේ",
|
"form_error_server_name": "සේවාදායකයේ නම වලංගු නොවේ",
|
||||||
"form_error_subnet": "\"{{cidr}}\" අනුජාලය හි \"{{ip}}\" අ.ජා.කෙ. ලිපිනය අඩංගු නොවේ",
|
"form_error_subnet": "\"{{cidr}}\" අනුජාලය හි \"{{ip}}\" අ.ජා.කෙ. ලිපිනය අඩංගු නොවේ",
|
||||||
"form_error_positive": "0 ට වඩා වැඩි විය යුතුය",
|
"form_error_positive": "0 ට වඩා වැඩි විය යුතුය",
|
||||||
|
"form_error_gateway_ip": "කලාවලට ගේට්වේ IP ලිපිනයක් නොඑන්න",
|
||||||
"out_of_range_error": "\"{{start}}\"-\"{{end}}\" පරාසයෙන් පිට විය යුතුය",
|
"out_of_range_error": "\"{{start}}\"-\"{{end}}\" පරාසයෙන් පිට විය යුතුය",
|
||||||
"lower_range_start_error": "පරාසය ආරම්භයට වඩා අඩු විය යුතුය",
|
"lower_range_start_error": "පරාසය ආරම්භයට වඩා අඩු විය යුතුය",
|
||||||
"greater_range_start_error": "පරාසය ආරම්භයට වඩා වැඩි විය යුතුය",
|
"greater_range_start_error": "පරාසය ආරම්භයට වඩා වැඩි විය යුතුය",
|
||||||
"subnet_error": "ලිපින එක් අනුජාලයක තිබිය යුතුය",
|
"subnet_error": "ලිපින එක් අනුජාලයක තිබිය යුතුය",
|
||||||
|
"gateway_or_subnet_invalid": "උපජාල කාණ්ඩය වලංගු නොවේ",
|
||||||
|
"dhcp_form_gateway_input": "සේවා ප්රවර්ධක දොරටු IP අංකය",
|
||||||
|
"dhcp_form_subnet_input": "උපජාල කාණ්ඩය",
|
||||||
"dhcp_form_range_title": "අ.ජා.කෙ. (IP) ලිපින පරාසය",
|
"dhcp_form_range_title": "අ.ජා.කෙ. (IP) ලිපින පරාසය",
|
||||||
"dhcp_form_range_start": "පරාසය ආරම්භය",
|
"dhcp_form_range_start": "පරාසය ආරම්භය",
|
||||||
"dhcp_form_range_end": "පරාසය අවසානය",
|
"dhcp_form_range_end": "පරාසය අවසානය",
|
||||||
@@ -58,7 +74,9 @@
|
|||||||
"dhcp_dynamic_ip_found": "ඔබගේ පද්ධතිය <0>{{interfaceName}}</0> අතුරු මුහුණත සඳහා ගතික අන්තර්ජාල කෙටුම්පත් (IP) ලිපින වින්යාසය භාවිතා කරයි. ග.ධා.වි.කෙ. සේවාදායකය භාවිතා කිරීම සඳහා ස්ථිතික අ.ජා. කෙ. ලිපිනයක් සැකසිය යුතුය. ඔබගේ වර්තමාන අ.ජා. කෙ. ලිපිනය <0>{{ipAddress}}</0> වේ. ඔබ \"ග.ධා.වි.කෙ. සබල කරන්න\" බොත්තම එබුවහොත් ඇඩ්ගාර්ඩ් හෝම් ස්වයංක්රීයව මෙම අ.ජා. කෙ. ලිපිනය ස්ථිතික ලෙස සකසනු ඇත.",
|
"dhcp_dynamic_ip_found": "ඔබගේ පද්ධතිය <0>{{interfaceName}}</0> අතුරු මුහුණත සඳහා ගතික අන්තර්ජාල කෙටුම්පත් (IP) ලිපින වින්යාසය භාවිතා කරයි. ග.ධා.වි.කෙ. සේවාදායකය භාවිතා කිරීම සඳහා ස්ථිතික අ.ජා. කෙ. ලිපිනයක් සැකසිය යුතුය. ඔබගේ වර්තමාන අ.ජා. කෙ. ලිපිනය <0>{{ipAddress}}</0> වේ. ඔබ \"ග.ධා.වි.කෙ. සබල කරන්න\" බොත්තම එබුවහොත් ඇඩ්ගාර්ඩ් හෝම් ස්වයංක්රීයව මෙම අ.ජා. කෙ. ලිපිනය ස්ථිතික ලෙස සකසනු ඇත.",
|
||||||
"dhcp_lease_added": "\"{{key}}\" ස්ථිර කල්පැවරීම එකතු කෙරිණි",
|
"dhcp_lease_added": "\"{{key}}\" ස්ථිර කල්පැවරීම එකතු කෙරිණි",
|
||||||
"dhcp_lease_deleted": "\"{{key}}\" ස්ථිර කල්පැවරීම මකා දැමිණි",
|
"dhcp_lease_deleted": "\"{{key}}\" ස්ථිර කල්පැවරීම මකා දැමිණි",
|
||||||
|
"dhcp_lease_updated": "ස්ථිර කල්පැවරීම \"{{key}}\" සාර්ථකව යාවත්කාල කර ඇත",
|
||||||
"dhcp_new_static_lease": "නව ස්ථිර කල්පැවරීම",
|
"dhcp_new_static_lease": "නව ස්ථිර කල්පැවරීම",
|
||||||
|
"dhcp_edit_static_lease": "ස්ථිර කල්පැවරීම සංස්කරණය කරන්න",
|
||||||
"dhcp_static_leases_not_found": "ග.ධා.වි.කෙ. ස්ථිර කල්පැවරීම් නැත",
|
"dhcp_static_leases_not_found": "ග.ධා.වි.කෙ. ස්ථිර කල්පැවරීම් නැත",
|
||||||
"dhcp_add_static_lease": "ස්ථිර කල්පැවරීමක් යොදන්න",
|
"dhcp_add_static_lease": "ස්ථිර කල්පැවරීමක් යොදන්න",
|
||||||
"dhcp_reset_leases": "කල්පැවරීම් යළි සකසන්න",
|
"dhcp_reset_leases": "කල්පැවරීම් යළි සකසන්න",
|
||||||
@@ -102,6 +120,8 @@
|
|||||||
"stats_malware_phishing": "අවහිර කළ ද්වේශාංග/තතුබෑම්",
|
"stats_malware_phishing": "අවහිර කළ ද්වේශාංග/තතුබෑම්",
|
||||||
"stats_adult": "අවහිර කළ වැඩිහිටි වියමන අඩවි",
|
"stats_adult": "අවහිර කළ වැඩිහිටි වියමන අඩවි",
|
||||||
"stats_query_domain": "ප්රචලිත විමසන ලද වසම්",
|
"stats_query_domain": "ප්රචලිත විමසන ලද වසම්",
|
||||||
|
"for_last_hours": "අවසන් {{count}} ත්රාසයේ සදහා",
|
||||||
|
"for_last_hours_plural": "අවසන් {{count}} පැයක් සදහා",
|
||||||
"for_last_days": "පසුගිය දවස් {{count}} සඳහා",
|
"for_last_days": "පසුගිය දවස් {{count}} සඳහා",
|
||||||
"for_last_days_plural": "පසුගිය දවස් {{count}} සඳහා",
|
"for_last_days_plural": "පසුගිය දවස් {{count}} සඳහා",
|
||||||
"stats_disabled": "සංඛ්යාලේඛන අබල කර ඇත. එය <0>සැකසුම් පිටුවෙන්</0> සබල කළ හැකිය.",
|
"stats_disabled": "සංඛ්යාලේඛන අබල කර ඇත. එය <0>සැකසුම් පිටුවෙන්</0> සබල කළ හැකිය.",
|
||||||
@@ -112,6 +132,8 @@
|
|||||||
"top_clients": "ප්රචලිත අනුග්රාහක",
|
"top_clients": "ප්රචලිත අනුග්රාහක",
|
||||||
"no_clients_found": "අනුග්රාහක හමු නොවිණි",
|
"no_clients_found": "අනුග්රාහක හමු නොවිණි",
|
||||||
"general_statistics": "පොදු සංඛ්යාලේඛන",
|
"general_statistics": "පොදු සංඛ්යාලේඛන",
|
||||||
|
"top_upstreams": "නිෂ්පාදන සම්පුර්ණ",
|
||||||
|
"no_upstreams_data_found": "උඩුගතදත්ත සොයාගැනීමක් නැත",
|
||||||
"number_of_dns_query_days": "පසුගිය දවස් {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
"number_of_dns_query_days": "පසුගිය දවස් {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||||
"number_of_dns_query_days_plural": "පසුගිය දවස් {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
"number_of_dns_query_days_plural": "පසුගිය දවස් {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||||
"number_of_dns_query_hours": "පසුගිය පැය {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
"number_of_dns_query_hours": "පසුගිය පැය {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||||
@@ -122,6 +144,7 @@
|
|||||||
"enforced_save_search": "ආරක්ෂිත සෙවීම බලාත්මක කළ",
|
"enforced_save_search": "ආරක්ෂිත සෙවීම බලාත්මක කළ",
|
||||||
"number_of_dns_query_to_safe_search": "ආරක්ෂිත සෙවීම බලාත්මක කළ සෙවුම් යන්ත්ර සඳහා ව.නා.ප. ඉල්ලීම් ගණන",
|
"number_of_dns_query_to_safe_search": "ආරක්ෂිත සෙවීම බලාත්මක කළ සෙවුම් යන්ත්ර සඳහා ව.නා.ප. ඉල්ලීම් ගණන",
|
||||||
"average_processing_time": "සාමාන්ය සැකසුම් කාලය",
|
"average_processing_time": "සාමාන්ය සැකසුම් කාලය",
|
||||||
|
"average_upstream_response_time": "උඩුගත කරන සේවාදායකයේ සාමාන්ය පිළිතුරු කාලය",
|
||||||
"response_time": "ප්රතිචාර කාලය",
|
"response_time": "ප්රතිචාර කාලය",
|
||||||
"average_processing_time_hint": "ව.නා.ප. ඉල්ලීමක් සැකසීමේ සාමාන්ය කාලය මිලි තත්පර වලින්",
|
"average_processing_time_hint": "ව.නා.ප. ඉල්ලීමක් සැකසීමේ සාමාන්ය කාලය මිලි තත්පර වලින්",
|
||||||
"block_domain_use_filters_and_hosts": "පෙරහන් හා සත්කාරක ගොනු භාවිතයෙන් වසම් අවහිර කරන්න",
|
"block_domain_use_filters_and_hosts": "පෙරහන් හා සත්කාරක ගොනු භාවිතයෙන් වසම් අවහිර කරන්න",
|
||||||
@@ -146,6 +169,8 @@
|
|||||||
"upstream_dns_help": "පේළියකට එක් සේවාදායක ලිපිනය බැගින් ඇතුල් කරන්න. upstream ව.නා.ප. (DNS) \n සේවාදායක වින්යාසගත කිරීම ගැන <a>තව දැනගන්න</a>.",
|
"upstream_dns_help": "පේළියකට එක් සේවාදායක ලිපිනය බැගින් ඇතුල් කරන්න. upstream ව.නා.ප. (DNS) \n සේවාදායක වින්යාසගත කිරීම ගැන <a>තව දැනගන්න</a>.",
|
||||||
"upstream_dns_configured_in_file": "{{path}} හි වින්යාසගත කර ඇත",
|
"upstream_dns_configured_in_file": "{{path}} හි වින්යාසගත කර ඇත",
|
||||||
"test_upstream_btn": "අත්හදා බලන්න",
|
"test_upstream_btn": "අත්හදා බලන්න",
|
||||||
|
"upstreams": "උඩුගත ධාරාව",
|
||||||
|
"upstream": "උඩුගත",
|
||||||
"apply_btn": "යොදන්න",
|
"apply_btn": "යොදන්න",
|
||||||
"disabled_filtering_toast": "පෙරීම අබල කෙරිණි",
|
"disabled_filtering_toast": "පෙරීම අබල කෙරිණි",
|
||||||
"enabled_filtering_toast": "පෙරීම සබල කෙරිණි",
|
"enabled_filtering_toast": "පෙරීම සබල කෙරිණි",
|
||||||
@@ -201,20 +226,25 @@
|
|||||||
"example_upstream_udp": "සාමාන්ය ව.නා.ප. (UDP, සත්කාරක-නම හරහා);",
|
"example_upstream_udp": "සාමාන්ය ව.නා.ප. (UDP, සත්කාරක-නම හරහා);",
|
||||||
"example_upstream_dot": "සංකේතිත <0>TLS-මගින්-ව.නා.ප.</0>;",
|
"example_upstream_dot": "සංකේතිත <0>TLS-මගින්-ව.නා.ප.</0>;",
|
||||||
"example_upstream_doh": "සංකේතිත <0>HTTPS-මගින්-ව.නා.ප.</0>;",
|
"example_upstream_doh": "සංකේතිත <0>HTTPS-මගින්-ව.නා.ප.</0>;",
|
||||||
|
"example_upstream_doh3": "සිනිළි <0>HTTP/3</0> ප්රධාන විකල්පය හා HTTP/2 හෝ ඔස්සේ භාවිත නොකරන DNS-over-HTTPS;",
|
||||||
"example_upstream_doq": "සංකේතිත <0>QUIC-මගින්-ව.නා.ප.</0>;",
|
"example_upstream_doq": "සංකේතිත <0>QUIC-මගින්-ව.නා.ප.</0>;",
|
||||||
"example_upstream_sdns": "<1>DNSCrypt</1> හෝ <2>HTTPS-මගින්-ව.නා.ප.</2> පිළිවිසඳු සඳහා <0>ව.නා.ප. මුද්දර</0>;",
|
"example_upstream_sdns": "<1>DNSCrypt</1> හෝ <2>HTTPS-මගින්-ව.නා.ප.</2> පිළිවිසඳු සඳහා <0>ව.නා.ප. මුද්දර</0>;",
|
||||||
"example_upstream_tcp": "සාමාන්ය ව.නා.ප. (TCP/ස.පා.කෙ. හරහා);",
|
"example_upstream_tcp": "සාමාන්ය ව.නා.ප. (TCP/ස.පා.කෙ. හරහා);",
|
||||||
"example_upstream_tcp_port": "සාමාන්ය ව.නා.ප. (TCP හරහා, තොට සමඟ);",
|
"example_upstream_tcp_port": "සාමාන්ය ව.නා.ප. (TCP හරහා, තොට සමඟ);",
|
||||||
"example_upstream_tcp_hostname": "සාමාන්ය ව.නා.ප. (ස.පා.කෙ., සත්කාරක-නම හරහා);",
|
"example_upstream_tcp_hostname": "සාමාන්ය ව.නා.ප. (ස.පා.කෙ., සත්කාරක-නම හරහා);",
|
||||||
"all_lists_up_to_date_toast": "සියළුම ලැයිස්තු දැනටමත් යාවත්කාලීනයි",
|
"all_lists_up_to_date_toast": "සියළුම ලැයිස්තු දැනටමත් යාවත්කාලීනයි",
|
||||||
|
"updated_upstream_dns_toast": "උඩුගත කරන සේවාදායක සාර්ථකව සුරකින ලදි",
|
||||||
"dns_test_ok_toast": "සඳහන් කළ ව.නා.ප. සේවාදායක නිවැරදිව ක්රියා කරයි",
|
"dns_test_ok_toast": "සඳහන් කළ ව.නා.ප. සේවාදායක නිවැරදිව ක්රියා කරයි",
|
||||||
"dns_test_not_ok_toast": "\"{{key}}\" සේවාදායක(ය): භාවිතා කිරීමට නොහැකි විය, ඔබ එය නිවැරදිව ලියා ඇතිදැයි පරීක්ෂා කරන්න",
|
"dns_test_not_ok_toast": "\"{{key}}\" සේවාදායක(ය): භාවිතා කිරීමට නොහැකි විය, ඔබ එය නිවැරදිව ලියා ඇතිදැයි පරීක්ෂා කරන්න",
|
||||||
|
"dns_test_parsing_error_toast": "කොටස {{section}}: වාක්ය {{line}}: භාවිතා කළ නොහැක,කරුණාකර ඔබට එය නිවැරදිව සම්මත කර ඇති දැයි පරීක්ෂා කරන්න",
|
||||||
|
"dns_test_warning_toast": "උඩුගත \"{{key}}\" ටෙස්ට් ඉල්ලීම්වලට ප්රතිචාර නොදෙයි හා සරිලන ලෙස ක්රියා නොකරනු ඇත",
|
||||||
"unblock": "අනවහිර",
|
"unblock": "අනවහිර",
|
||||||
"block": "අවහිර",
|
"block": "අවහිර",
|
||||||
"disallow_this_client": "මෙම අනුග්රාහකයට ඉඩ නොදෙන්න",
|
"disallow_this_client": "මෙම අනුග්රාහකයට ඉඩ නොදෙන්න",
|
||||||
"allow_this_client": "මෙම අනුග්රාහකයට ඉඩ දෙන්න",
|
"allow_this_client": "මෙම අනුග්රාහකයට ඉඩ දෙන්න",
|
||||||
"block_for_this_client_only": "මෙම අනුග්රාහකයට අවහිර කරන්න",
|
"block_for_this_client_only": "මෙම අනුග්රාහකයට අවහිර කරන්න",
|
||||||
"unblock_for_this_client_only": "මෙම අනුග්රාහකයට පමණක් අනවහිර කරන්න",
|
"unblock_for_this_client_only": "මෙම අනුග්රාහකයට පමණක් අනවහිර කරන්න",
|
||||||
|
"add_persistent_client": "නිබඳිත පාරිභෝගිකයා ලෙස එකතු කරන්න",
|
||||||
"time_table_header": "වේලාව",
|
"time_table_header": "වේලාව",
|
||||||
"date": "දිනය",
|
"date": "දිනය",
|
||||||
"domain_name_table_header": "වසම් නාමය",
|
"domain_name_table_header": "වසම් නාමය",
|
||||||
@@ -261,6 +291,12 @@
|
|||||||
"custom_ip": "අභිරුචි අ.ජා.කෙ.",
|
"custom_ip": "අභිරුචි අ.ජා.කෙ.",
|
||||||
"blocking_ipv4": "IPv4 අවහිර කිරීම",
|
"blocking_ipv4": "IPv4 අවහිර කිරීම",
|
||||||
"blocking_ipv6": "IPv6 අවහිර කිරීම",
|
"blocking_ipv6": "IPv6 අවහිර කිරීම",
|
||||||
|
"blocked_response_ttl": "ප්රතිචාරය මගින් අවහිර කර ඇති TTL",
|
||||||
|
"blocked_response_ttl_desc": "සු filtr ම කළ ලිපිනයක් මහිහි කළයක් සකස් කරයිාරුවන්",
|
||||||
|
"form_enter_blocked_response_ttl": "අසැක කරන මගුලකෙන් කාලය ඇතුලත් කරන්න (තත්පර)",
|
||||||
|
"upstream_timeout": "උඩුගත කරන සේවාදායකයේ කාල සීමාව",
|
||||||
|
"upstream_timeout_desc": "උඩුගත කරන සේවාදායකයෙන් පිළිතුරු පෑමට ආරක්ෂිතව රැඳී සිටින තත්ත්වය ඉවසන විනාඩි ගණන විශේෂිත කරයි",
|
||||||
|
"form_enter_upstream_timeout": "උඩුගත කරන සේවාදායකයේ කාල සීමාව තෝරන්න.",
|
||||||
"dnscrypt": "DNSCrypt",
|
"dnscrypt": "DNSCrypt",
|
||||||
"dns_over_https": "HTTPS-මගින්-ව.නා.ප.",
|
"dns_over_https": "HTTPS-මගින්-ව.නා.ප.",
|
||||||
"dns_over_tls": "TLS-මගින්-ව.නා.ප.",
|
"dns_over_tls": "TLS-මගින්-ව.නා.ප.",
|
||||||
@@ -275,9 +311,19 @@
|
|||||||
"form_enter_rate_limit": "අනුපාත සීමාව ඇතුල් කරන්න",
|
"form_enter_rate_limit": "අනුපාත සීමාව ඇතුල් කරන්න",
|
||||||
"rate_limit": "අනුපාත සීමාව",
|
"rate_limit": "අනුපාත සීමාව",
|
||||||
"edns_enable": "EDNS අනුග්රාහක අනුජාලය සබල කරන්න",
|
"edns_enable": "EDNS අනුග්රාහක අනුජාලය සබල කරන්න",
|
||||||
|
"edns_cs_desc": "උඩුගත විමසුම් සඳහා EDNS Client Subnet විකල්පය (ECS) එකතු කරන්න සහ විමසුම් ලොගයේ සේවාදායකයින් විසින් යැව්ම කළ වටිනාකම් ලොග් කරන්න.",
|
||||||
"edns_use_custom_ip": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. යොදාගන්න",
|
"edns_use_custom_ip": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. යොදාගන්න",
|
||||||
"edns_use_custom_ip_desc": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. භාවිතයට ඉඩදෙන්න",
|
"edns_use_custom_ip_desc": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. භාවිතයට ඉඩදෙන්න",
|
||||||
"rate_limit_desc": "එක් අනුග්රාහකයකට ඉඩ දී ඇති තත්පරයට ඉල්ලීම් ගණන. එය 0 ලෙස සැකසීම යනුවෙන් අදහස් කරන්නේ සීමාවක් නැති බවයි.",
|
"rate_limit_desc": "එක් අනුග්රාහකයකට ඉඩ දී ඇති තත්පරයට ඉල්ලීම් ගණන. එය 0 ලෙස සැකසීම යනුවෙන් අදහස් කරන්නේ සීමාවක් නැති බවයි.",
|
||||||
|
"rate_limit_subnet_len_ipv4": "IPv4 ලිපින සදහා උපසර්න පෙරහන් දිග",
|
||||||
|
"rate_limit_subnet_len_ipv4_desc": "සමත් කරණය සීමා කරයින් සදහන් කිරීම සඳහා, IPv4 ලිපින සඳහා උපසර්න පෙරහන් දිග. පෙරහනේ පදනම 24 වේ",
|
||||||
|
"rate_limit_subnet_len_ipv4_error": "IPv4 අඩවියේ ප්රතිමා අකුණු දිග 0 සහ 32 අතර විය යුතුය",
|
||||||
|
"rate_limit_subnet_len_ipv6": "IPv6 ලිපින සඳහා අඩවිය අකුණු දිග",
|
||||||
|
"rate_limit_subnet_len_ipv6_desc": "අඩවිය අකුණු දිගක් සමඟ අවම සීමා කිරීමට භාවිතා කරන IPv6 ලිපින සඳහා. ප්රතිමන් 56 වනු ඇත",
|
||||||
|
"rate_limit_subnet_len_ipv6_error": "IPv6 අඩවියේ ප්රතිමා අකුණු දිග 0 සහ 128 අතර විය යුතුය",
|
||||||
|
"form_enter_rate_limit_subnet_len": "අවම සීමා කිරීමට අඩවියේ ආකලන අකුණු දිග ඇතුළත් කරන්න",
|
||||||
|
"rate_limit_whitelist": "අනුපාත සීමා ඉඩදෙන ලැයිස්තුව",
|
||||||
|
"rate_limit_whitelist_desc": "අ.ජා.කෙ. ලිපින (IP) අනුපාත සීමාවෙන් බැහැර කරයි.",
|
||||||
"rate_limit_whitelist_placeholder": "පේළියකට අ.ජා.කෙ. ලිපිනය බැගින් ලියන්න",
|
"rate_limit_whitelist_placeholder": "පේළියකට අ.ජා.කෙ. ලිපිනය බැගින් ලියන්න",
|
||||||
"blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
"blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
||||||
"blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
"blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
||||||
@@ -382,6 +428,9 @@
|
|||||||
"encryption_hostnames": "සත්කාරක නාම",
|
"encryption_hostnames": "සත්කාරක නාම",
|
||||||
"encryption_reset": "සංකේතාංකන සැකසුම් යළි පිහිටුවීමට අවශ්ය බව ඔබට විශ්වාස ද?",
|
"encryption_reset": "සංකේතාංකන සැකසුම් යළි පිහිටුවීමට අවශ්ය බව ඔබට විශ්වාස ද?",
|
||||||
"encryption_warning": "අවවාදයයි",
|
"encryption_warning": "අවවාදයයි",
|
||||||
|
"encryption_plain_dns_enable": "ප්ලේන් DNS සබල කරන්න",
|
||||||
|
"encryption_plain_dns_desc": "ප්ලේන් DNS ඇත්තෙන්ම සක්රීය වේ. ඔබට එය අබල කිරීමෙන් සියලුම උපාංගයන් සිංහලෙන් DNS භාවිතා කිරීමට හෝ කරන්න. එය සඳහා, අත්යාවශ්යය වශයෙන් මින් කිහිපයක් සක්රීය කළ යුතුය.",
|
||||||
|
"encryption_plain_dns_error": "ප්ලේන් DNS අබල කිරීමට, අනිවාර්ය වශයෙන් කුමක් හෝ සංකේතාත්මක DNS කෙටුම්පතක් සක්රීය කරන්න.",
|
||||||
"topline_expiring_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත්වීමට ආසන්න වී ඇත. <0>සංකේතන සැකසුම්</0> යාවත්කාල කරන්න.",
|
"topline_expiring_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත්වීමට ආසන්න වී ඇත. <0>සංකේතන සැකසුම්</0> යාවත්කාල කරන්න.",
|
||||||
"topline_expired_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත් වී ඇත. <0>සංකේතන සැකසුම්</0> යාවත්කාල කරන්න.",
|
"topline_expired_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත් වී ඇත. <0>සංකේතන සැකසුම්</0> යාවත්කාල කරන්න.",
|
||||||
"form_error_port_range": "80-65535 පරාසය හි තොටක අගයක් ඇතුල් කරන්න",
|
"form_error_port_range": "80-65535 පරාසය හි තොටක අගයක් ඇතුල් කරන්න",
|
||||||
@@ -421,6 +470,7 @@
|
|||||||
"form_add_id": "හඳුන්වනයක් එකතු කරන්න",
|
"form_add_id": "හඳුන්වනයක් එකතු කරන්න",
|
||||||
"form_client_name": "අනුග්රාහකයේ නම ඇතුල් කරන්න",
|
"form_client_name": "අනුග්රාහකයේ නම ඇතුල් කරන්න",
|
||||||
"name": "නම",
|
"name": "නම",
|
||||||
|
"client_name": "අනුග්රාහකය {{id}}",
|
||||||
"client_global_settings": "ගෝලීය සැකසුම් භාවිතා කරන්න",
|
"client_global_settings": "ගෝලීය සැකසුම් භාවිතා කරන්න",
|
||||||
"client_deleted": "\"{{key}}\" අනුග්රාහකය සාර්ථකව ඉවත් කෙරිණි",
|
"client_deleted": "\"{{key}}\" අනුග්රාහකය සාර්ථකව ඉවත් කෙරිණි",
|
||||||
"client_added": "\"{{key}}\" අනුග්රාහකය සාර්ථකව එකතු කෙරිණි",
|
"client_added": "\"{{key}}\" අනුග්රාහකය සාර්ථකව එකතු කෙරිණි",
|
||||||
@@ -428,6 +478,7 @@
|
|||||||
"clients_not_found": "අනුග්රාහක හමු නොවිණි",
|
"clients_not_found": "අනුග්රාහක හමු නොවිණි",
|
||||||
"client_confirm_delete": "\"{{key}}\" අනුග්රාහකය ඉවත් කිරීමට අවශ්ය බව ඔබට විශ්වාසද?",
|
"client_confirm_delete": "\"{{key}}\" අනුග්රාහකය ඉවත් කිරීමට අවශ්ය බව ඔබට විශ්වාසද?",
|
||||||
"list_confirm_delete": "මෙම ලැයිස්තුව ඉවත් කිරීමට අවශ්ය බව ඔබට විශ්වාස ද?",
|
"list_confirm_delete": "මෙම ලැයිස්තුව ඉවත් කිරීමට අවශ්ය බව ඔබට විශ්වාස ද?",
|
||||||
|
"auto_clients_title": "ධාවනකාල අනුග්රාහක",
|
||||||
"auto_clients_desc": "ඇඩ්ගාර්ඩ් හෝම් භාවිතා කරන හෝ භාවිතයට ඉඩ තිබෙන උපාංගවල අ.ජා.කෙ. (IP) ලිපින පිළිබඳ තොරතුරු. මෙම තොරතුරු සත්කාරක ගොනු, ප්රතිවර්ත ව.නා.ප. ආදී මූලාශ්ර කිහිපයකින් රැස් කෙරේ.",
|
"auto_clients_desc": "ඇඩ්ගාර්ඩ් හෝම් භාවිතා කරන හෝ භාවිතයට ඉඩ තිබෙන උපාංගවල අ.ජා.කෙ. (IP) ලිපින පිළිබඳ තොරතුරු. මෙම තොරතුරු සත්කාරක ගොනු, ප්රතිවර්ත ව.නා.ප. ආදී මූලාශ්ර කිහිපයකින් රැස් කෙරේ.",
|
||||||
"access_title": "ප්රවේශ සැකසුම්",
|
"access_title": "ප්රවේශ සැකසුම්",
|
||||||
"access_desc": "මෙහි දී ඔබට ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකයට ප්රවේශ වීමේ නීති වින්යාසගත කිරීමට හැකිය",
|
"access_desc": "මෙහි දී ඔබට ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකයට ප්රවේශ වීමේ නීති වින්යාසගත කිරීමට හැකිය",
|
||||||
@@ -436,6 +487,7 @@
|
|||||||
"access_disallowed_title": "ඉඩ නොදෙන අනුග්රාහක",
|
"access_disallowed_title": "ඉඩ නොදෙන අනුග්රාහක",
|
||||||
"access_disallowed_desc": "අන.ජා.(CIDR), අ.ජා.කෙ. ලිපින හෝ <a>අනුග්රාහක හැඳු.</a> ලේඛනයකි. මෙහි නිවේශිත ඇත්නම්, ඇඩ්ගාර්ඩ් හෝම් එම අනුග්රාහක වලින් ඉල්ලීම් අත්හරිනු ඇත. ඉඩ දෙන අනුග්රාහක කොටසේ නිවේශිත තිබේ නම්, මෙම ක්ෂේත්රය නොසලකා හරිනු ඇත.",
|
"access_disallowed_desc": "අන.ජා.(CIDR), අ.ජා.කෙ. ලිපින හෝ <a>අනුග්රාහක හැඳු.</a> ලේඛනයකි. මෙහි නිවේශිත ඇත්නම්, ඇඩ්ගාර්ඩ් හෝම් එම අනුග්රාහක වලින් ඉල්ලීම් අත්හරිනු ඇත. ඉඩ දෙන අනුග්රාහක කොටසේ නිවේශිත තිබේ නම්, මෙම ක්ෂේත්රය නොසලකා හරිනු ඇත.",
|
||||||
"access_blocked_title": "ඉඩ නොදෙන වසම්",
|
"access_blocked_title": "ඉඩ නොදෙන වසම්",
|
||||||
|
"access_blocked_desc": "මෙය පෙරලුවලට වඩා නොවේ. AdGuard Home, මෙම වසමට සමාන DNS විමසුම් වලින් තොරව ඉවත් කරයි, සහ මෙම විමසුම් විමසුම් ලොග් එකේද එක් නොවේ. ඔබ නිශ්චිත ආකාරයට වසමන්, වර්ජ්ජ නීති, හෝ URL විමසුම් නීති සංඛ්යාගත කිරීමට කැමැත්ත දක්වන ලෙසද ඔබට හැක.",
|
||||||
"access_settings_saved": "ප්රවේශ වීමේ සැකසුම් සාර්ථකව සුරකින ලදි",
|
"access_settings_saved": "ප්රවේශ වීමේ සැකසුම් සාර්ථකව සුරකින ලදි",
|
||||||
"updates_checked": "ඇඩ්ගාර්ඩ් හෝම් හි නව අනුවාදයක් තිබේ",
|
"updates_checked": "ඇඩ්ගාර්ඩ් හෝම් හි නව අනුවාදයක් තිබේ",
|
||||||
"updates_version_equal": "ඇඩ්ගාර්ඩ් හෝම් යාවත්කාලීනයි",
|
"updates_version_equal": "ඇඩ්ගාර්ඩ් හෝම් යාවත්කාලීනයි",
|
||||||
@@ -445,9 +497,11 @@
|
|||||||
"setup_dns_privacy_1": "<0>TLS-මගින්-ව.නා.ප.</0> සඳහා <1>{{address}}</1>.",
|
"setup_dns_privacy_1": "<0>TLS-මගින්-ව.නා.ප.</0> සඳහා <1>{{address}}</1>.",
|
||||||
"setup_dns_privacy_2": "<0>HTTPS-මගින්-ව.නා.ප.</0> සඳහා <1>{{address}}</1>.",
|
"setup_dns_privacy_2": "<0>HTTPS-මගින්-ව.නා.ප.</0> සඳහා <1>{{address}}</1>.",
|
||||||
"setup_dns_privacy_3": "<0>මෙහි ඔබට භාවිතා කළ හැකි මෘදුකාංග ලැයිස්තුවක් ඇත.</0>",
|
"setup_dns_privacy_3": "<0>මෙහි ඔබට භාවිතා කළ හැකි මෘදුකාංග ලැයිස්තුවක් ඇත.</0>",
|
||||||
|
"setup_dns_privacy_4": "iOS 14 හෝ macOS Big Sur උපාංගයක ඔබට විශේෂ '.mobileconfig' ගොනුවක් බාගන්නට හැකි අතර එය DNS සැකසුම් සඳහා <highlight>DNS-over-HTTPS</highlight> හෝ <highlight>DNS-over-TLS</highlight> සේවාදායකයන් එක් කරයි.",
|
||||||
"setup_dns_privacy_android_1": "TLS-මගින්-ව.නා.ප සහාය සමගම ඇන්ඩ්රොයිඩ් 9 පැමිණේ. එය වින්යාස කිරීමට, සැකසුම් → ජාලය හා අන්තර්ජාලය → වැඩිදුර → පෞද්. ව.නා.ප. වෙත ගොස් එහි ඔබගේ වසමේ නම යොදන්න.",
|
"setup_dns_privacy_android_1": "TLS-මගින්-ව.නා.ප සහාය සමගම ඇන්ඩ්රොයිඩ් 9 පැමිණේ. එය වින්යාස කිරීමට, සැකසුම් → ජාලය හා අන්තර්ජාලය → වැඩිදුර → පෞද්. ව.නා.ප. වෙත ගොස් එහි ඔබගේ වසමේ නම යොදන්න.",
|
||||||
"setup_dns_privacy_android_2": "<1>HTTPS-මගින්-ව.නා.ප.</1> හා <1>TLS-මගින්-ව.නා.ප.</1> සඳහා <0>ඇන්ඩ්රොයිඩ් සඳහා ඇඩ්ගාර්ඩ්</0> සහාය දක්වයි.",
|
"setup_dns_privacy_android_2": "<1>HTTPS-මගින්-ව.නා.ප.</1> හා <1>TLS-මගින්-ව.නා.ප.</1> සඳහා <0>ඇන්ඩ්රොයිඩ් සඳහා ඇඩ්ගාර්ඩ්</0> සහාය දක්වයි.",
|
||||||
"setup_dns_privacy_android_3": "<0>ඉන්ට්රා</0> විසින් <1>HTTPS-මගින්-ව.නා.ප</1> සහාය ඇන්ඩ්රොයිඩ් සඳහා එකතු කරයි.",
|
"setup_dns_privacy_android_3": "<0>ඉන්ට්රා</0> විසින් <1>HTTPS-මගින්-ව.නා.ප</1> සහාය ඇන්ඩ්රොයිඩ් සඳහා එකතු කරයි.",
|
||||||
|
"setup_dns_privacy_ios_1": "<0>DNSCloak</0> <1>DNS-over-HTTPS</1> අනුකූල වේ, නමුත් ඔබේම සේවාදායකය භාවිතා කිරීමට සකස් කරන්න, ඔබට ඒ සඳහා <2>DNS Stamp</2> හි සෑදීමට අවශ්ය වේ.",
|
||||||
"setup_dns_privacy_ios_2": "<1>HTTPS-මගින්-ව.නා.ප.</1> හා <1>TLS-මගින්-ව.නා.ප.</1> සඳහා <0>අයිඕඑස් සඳහා ඇඩ්ගාර්ඩ්</0> සහාය දක්වයි.",
|
"setup_dns_privacy_ios_2": "<1>HTTPS-මගින්-ව.නා.ප.</1> හා <1>TLS-මගින්-ව.නා.ප.</1> සඳහා <0>අයිඕඑස් සඳහා ඇඩ්ගාර්ඩ්</0> සහාය දක්වයි.",
|
||||||
"setup_dns_privacy_other_title": "වෙනත් ක්රියාවට නැංවූ දෑ",
|
"setup_dns_privacy_other_title": "වෙනත් ක්රියාවට නැංවූ දෑ",
|
||||||
"setup_dns_privacy_other_1": "ඇඩ්ගාර්ඩ් හෝම් මෘදුකාංගයට ඕනෑම වේදිකාවක ආරක්ෂිත ව.නා.ප. අනුග්රාහකයක් ලෙස ක්රියාත්මක වීමට ද හැකිය.",
|
"setup_dns_privacy_other_1": "ඇඩ්ගාර්ඩ් හෝම් මෘදුකාංගයට ඕනෑම වේදිකාවක ආරක්ෂිත ව.නා.ප. අනුග්රාහකයක් ලෙස ක්රියාත්මක වීමට ද හැකිය.",
|
||||||
@@ -468,6 +522,7 @@
|
|||||||
"rewrite_applied": "නැවත ලිවීමේ නීතිය යොදා ඇත",
|
"rewrite_applied": "නැවත ලිවීමේ නීතිය යොදා ඇත",
|
||||||
"rewrite_hosts_applied": "සත්කාරක ගොනුවක නීතියකින් නැවත ලියා ඇත",
|
"rewrite_hosts_applied": "සත්කාරක ගොනුවක නීතියකින් නැවත ලියා ඇත",
|
||||||
"dns_rewrites": "ව.නා.ප. නැවත ලිවීම්",
|
"dns_rewrites": "ව.නා.ප. නැවත ලිවීම්",
|
||||||
|
"form_domain": "වසම නම හෝ තරු සලකුණ යොදන්න",
|
||||||
"form_answer": "අ.ජා.කෙ. (IP) ලිපිනය හෝ වසම ඇතුල් කරන්න ",
|
"form_answer": "අ.ජා.කෙ. (IP) ලිපිනය හෝ වසම ඇතුල් කරන්න ",
|
||||||
"form_error_domain_format": "වලංගු නොවන වසම් ආකෘතියකි",
|
"form_error_domain_format": "වලංගු නොවන වසම් ආකෘතියකි",
|
||||||
"form_error_answer_format": "වලංගු නොවන උත්තර ආකෘතියකි",
|
"form_error_answer_format": "වලංගු නොවන උත්තර ආකෘතියකි",
|
||||||
@@ -495,6 +550,7 @@
|
|||||||
"interval_days_plural": "දවස් {{count}}",
|
"interval_days_plural": "දවස් {{count}}",
|
||||||
"domain": "වසම",
|
"domain": "වසම",
|
||||||
"ecs": "ECS",
|
"ecs": "ECS",
|
||||||
|
"punycode": "Punycode",
|
||||||
"answer": "උත්තරය",
|
"answer": "උත්තරය",
|
||||||
"filter_added_successfully": "පෙරහන සාර්ථකව එකතු කෙරිණි",
|
"filter_added_successfully": "පෙරහන සාර්ථකව එකතු කෙරිණි",
|
||||||
"filter_removed_successfully": "ලැයිස්තුව සාර්ථකව ඉවත් කෙරිණි",
|
"filter_removed_successfully": "ලැයිස්තුව සාර්ථකව ඉවත් කෙරිණි",
|
||||||
@@ -535,15 +591,19 @@
|
|||||||
"blocked_by_response": "ප්රතිචාරය අන්. නාමයක් (CNAME) හෝ අ.ජා.කෙ. මගින් අවහිර කර ඇත",
|
"blocked_by_response": "ප්රතිචාරය අන්. නාමයක් (CNAME) හෝ අ.ජා.කෙ. මගින් අවහිර කර ඇත",
|
||||||
"blocked_by_cname_or_ip": "අන්. නාමයක් (CNAME) හෝ අ.ජා.කෙ. මගින් අවහිර කර ඇත",
|
"blocked_by_cname_or_ip": "අන්. නාමයක් (CNAME) හෝ අ.ජා.කෙ. මගින් අවහිර කර ඇත",
|
||||||
"try_again": "යළි උත්සාහය",
|
"try_again": "යළි උත්සාහය",
|
||||||
|
"domain_desc": "නැවත අලුත් කල යුතු වසම නම හෝ තරු සලකුණ යොදන්න.",
|
||||||
"example_rewrite_domain": "මෙම වසම් නාමය සඳහා පමණක් ප්රතිචාර නැවත ලියයි.",
|
"example_rewrite_domain": "මෙම වසම් නාමය සඳහා පමණක් ප්රතිචාර නැවත ලියයි.",
|
||||||
"example_rewrite_wildcard": "<0>උදාහරණය.ලංකා</0> සහ එහි සියළුම උප වසම් සඳහා ප්රතිචාර නැවත ලියයි.",
|
"example_rewrite_wildcard": "<0>උදාහරණය.ලංකා</0> සහ එහි සියළුම උප වසම් සඳහා ප්රතිචාර නැවත ලියයි.",
|
||||||
"rewrite_ip_address": "අ.ජා.කෙ. ලිපිනය: A හෝ AAAA ප්රතිචාරයකට අ.ජා.කෙ. ලිපිනයක් යොදන්න",
|
"rewrite_ip_address": "අ.ජා.කෙ. ලිපිනය: A හෝ AAAA ප්රතිචාරයකට අ.ජා.කෙ. ලිපිනයක් යොදන්න",
|
||||||
"rewrite_domain_name": "වසම් නාමය: අන්වර්ථ නාමයක් (CNAME) එක් කරන්න",
|
"rewrite_domain_name": "වසම් නාමය: අන්වර්ථ නාමයක් (CNAME) එක් කරන්න",
|
||||||
|
"rewrite_A": "<0>A</0>: විශේෂ අගය, උඩුගත කිරීමෙන් <0>A</0> වාර්තා තබන්න",
|
||||||
|
"rewrite_AAAA": "<0>AAAA</0>: විශේෂ අගය, උඩුගත කිරීමෙන් <0>AAAA</0> වාර්තා තබන්න",
|
||||||
"disable_ipv6": "IPv6 ලිපින විසඳීම අබල කරන්න",
|
"disable_ipv6": "IPv6 ලිපින විසඳීම අබල කරන්න",
|
||||||
"disable_ipv6_desc": "IPv6 ලිපින (AAAA වර්ගය) සඳහා වන සියළුම ව.නා.ප. විමසුම් අතහැර දමයි. HTTPS ප්රතිචාර වලින් IPv6 ඉඟි ඉවත් කරයි.",
|
"disable_ipv6_desc": "IPv6 ලිපින (AAAA වර්ගය) සඳහා වන සියළුම ව.නා.ප. විමසුම් අතහැර දමයි. HTTPS ප්රතිචාර වලින් IPv6 ඉඟි ඉවත් කරයි.",
|
||||||
"fastest_addr": "වේගවත්ම අන්තර්ජාල කෙටුම්පතක (IP) ලිපිනය",
|
"fastest_addr": "වේගවත්ම අන්තර්ජාල කෙටුම්පතක (IP) ලිපිනය",
|
||||||
"fastest_addr_desc": "සියළුම ව.නා.ප. සේවාදායක වලින් විමසා එම ප්රතිචාර අතරින් වේගවත්ම අ.ජා.කෙ. ලිපිනය ලබා දෙයි. සියළුම ව.නා.ප. ප්රතිචාර සඳහා ඇඩ්ගාර්ඩ් හෝම් රැඳී සිටිය යුතු බැවින් මෙය ව.නා.ප. විමසුම් මන්දගාමී කරන නමුත් සමස්ත සම්බන්ධතාවය වැඩි දියුණු කරයි.",
|
"fastest_addr_desc": "උඩුගත කරන සියලු DNS සේවාදායකයන්ගෙන් පිළිතුරු ලබා ගැනීමට කාලය ගණනය කරයි. TCP සම්බන්ධතාවයේ වේගය මනිමින් ඉක්මන්සම සේවාදායකයේ IP ලිපිනය පිළිතුරු ලෙස ලබා දෙයි.<br/>එක් හෝ කීපයකුත් උඩුගත කරන සේවාදායක පොළඹීම නොමැතිනම්, මෙම ක්රමය DNS විමසුම් දැක්මට කාර්යක්ෂම ලෙස මෝඩින්ට පත්වේ. ඔබගේ උඩුගත කරන සේවාදායක සවිකරනු ලබන බව සහ කාල සීමාව පහත් බවට හැකි මොහොතේම නිතිකාලෙන් පරීක්ෂා කරන්න.",
|
||||||
"autofix_warning_text": "ඔබ \"නිරාකරණය\" යන්න එබුවහොත්, ඔබගේ පද්ධතිය ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකය භාවිතයට වින්යාසගත කෙරෙනු ඇත.",
|
"autofix_warning_text": "ඔබ \"නිරාකරණය\" යන්න එබුවහොත්, ඔබගේ පද්ධතිය ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකය භාවිතයට වින්යාසගත කෙරෙනු ඇත.",
|
||||||
|
"autofix_warning_list": "මෙම කාර්යාල කරනු ඇත: <0>සැ ව.නා.ප. ඡේදකය නශ්කරන්න</0> <0>ව.නා.ප. සේවාදායක ලිපිනය 127.0.0.1 සඳහා සකසන්න.</0> <0>/etc/resolv.conf යන ගැඹුරු සම්පූර්ණය මාරු කරන්න /run/systemd/resolve/resolv.conf සඳහා </0> <0>සැ වෙ.නා.ප. ඡේදකය නශ්කරන්න (systemd-resolved සේවාව නැවත පුරෙන්න)</0>",
|
||||||
"autofix_warning_result": "ප්රතිඵලයක් ලෙස ඔබගේ පද්ධතියෙන් ලැබෙන සියළුම ව.නා.ප. ඉල්ලීම් මූලිකවම ඇඩ්ගාර්ඩ් හෝම් විසින් සකසනු ඇත.",
|
"autofix_warning_result": "ප්රතිඵලයක් ලෙස ඔබගේ පද්ධතියෙන් ලැබෙන සියළුම ව.නා.ප. ඉල්ලීම් මූලිකවම ඇඩ්ගාර්ඩ් හෝම් විසින් සකසනු ඇත.",
|
||||||
"tags_title": "අනන්යන",
|
"tags_title": "අනන්යන",
|
||||||
"tags_desc": "අනුග්රාහකයට අනුරූප වන අනන්යන ඔබට තේරීමට හැකිය. ඒවා වඩාත් නිවැරදිව යෙදීමට \nඅනන්යන පෙරහන් නීති වලට ඇතුළත් කරන්න. <0>තව දැන ගන්න</0>.",
|
"tags_desc": "අනුග්රාහකයට අනුරූප වන අනන්යන ඔබට තේරීමට හැකිය. ඒවා වඩාත් නිවැරදිව යෙදීමට \nඅනන්යන පෙරහන් නීති වලට ඇතුළත් කරන්න. <0>තව දැන ගන්න</0>.",
|
||||||
@@ -560,6 +620,10 @@
|
|||||||
"check_cname": "අන්. නාමය (CNAME): {{cname}}",
|
"check_cname": "අන්. නාමය (CNAME): {{cname}}",
|
||||||
"check_reason": "හේතුව: {{reason}}",
|
"check_reason": "හේතුව: {{reason}}",
|
||||||
"check_service": "සේවාවෙහි නම: {{service}}",
|
"check_service": "සේවාවෙහි නම: {{service}}",
|
||||||
|
"check_hostname": "සත්කාරක හෝ වසම් නාමය",
|
||||||
|
"check_client_id": "අනුග්රාහකයේ හඳුන්වනය (හැඳු. හෝ අ.ජා.කෙ. ලිපිනය)",
|
||||||
|
"check_enter_client_id": "අනුග්රාහකයේ හඳුන්වනය ලියන්න",
|
||||||
|
"check_dns_record": "ව.නා.ප. වාර්තා වර්ගය තෝරන්න",
|
||||||
"service_name": "සේවාවේ නම",
|
"service_name": "සේවාවේ නම",
|
||||||
"check_not_found": "ඔබගේ පෙරහන් ලැයිස්තු තුළ නැත",
|
"check_not_found": "ඔබගේ පෙරහන් ලැයිස්තු තුළ නැත",
|
||||||
"client_confirm_block": "{{ip}} අනුග්රාහකය අවහිර කිරීමට ඇවැසි බව ඔබට විශ්වාසද?",
|
"client_confirm_block": "{{ip}} අනුග්රාහකය අවහිර කිරීමට ඇවැසි බව ඔබට විශ්වාසද?",
|
||||||
@@ -576,6 +640,7 @@
|
|||||||
"list_updated": "ලැයිස්තු {{count}} ක් යාවත්කාල කෙරිණි",
|
"list_updated": "ලැයිස්තු {{count}} ක් යාවත්කාල කෙරිණි",
|
||||||
"list_updated_plural": "ලැයිස්තු {{count}} ක් යාවත්කාල කෙරිණි",
|
"list_updated_plural": "ලැයිස්තු {{count}} ක් යාවත්කාල කෙරිණි",
|
||||||
"dnssec_enable": "DNSSEC සබල කරන්න",
|
"dnssec_enable": "DNSSEC සබල කරන්න",
|
||||||
|
"dnssec_enable_desc": "DNSSEC යුග්ම තීරු සෙවනේ සබැඳියෙන් පිළිබඳ අධ්යනය හා ප්රතිඵලය පරික්ෂා කරන්න (DNSSEC- සබල කළ ප්රතිලේඛකය අවශ්යයි).",
|
||||||
"validated_with_dnssec": "DNSSEC සමඟ වලංගු කෙරිණි",
|
"validated_with_dnssec": "DNSSEC සමඟ වලංගු කෙරිණි",
|
||||||
"all_queries": "සියළුම විමසුම්",
|
"all_queries": "සියළුම විමසුම්",
|
||||||
"show_blocked_responses": "අවහිර කර ඇත",
|
"show_blocked_responses": "අවහිර කර ඇත",
|
||||||
@@ -591,12 +656,13 @@
|
|||||||
"blocklist": "අවහිර කිරීමේ ලැයිස්තුව",
|
"blocklist": "අවහිර කිරීමේ ලැයිස්තුව",
|
||||||
"milliseconds_abbreviation": "මිලි තත්.",
|
"milliseconds_abbreviation": "මිලි තත්.",
|
||||||
"cache_size": "නිහිතයෙහි ප්රමාණය",
|
"cache_size": "නිහිතයෙහි ප්රමාණය",
|
||||||
"cache_size_desc": "ව.නා.ප. නිහිතයෙහි ප්රමාණය (බයිට). නිහිතය අබල කිරීමට, හිස්ව තබන්න.",
|
"cache_size_desc": "ව.නා.ප. නිහිතයේ ප්රමාණය (බයිට). නිහිතය අබල කිරීමට, 0 ලෙස තබන්න.",
|
||||||
"cache_ttl_min_override": "අවම පව. කා. අභිබවන්න",
|
"cache_ttl_min_override": "අවම පව. කා. අභිබවන්න",
|
||||||
"cache_ttl_max_override": "උපරිම පව. කා. අභිබවන්න",
|
"cache_ttl_max_override": "උපරිම පව. කා. අභිබවන්න",
|
||||||
"enter_cache_size": "ව.නා.ප. නිහිතයෙහි ප්රමාණය යොදන්න (බයිට)",
|
"enter_cache_size": "ව.නා.ප. නිහිතයෙහි ප්රමාණය යොදන්න (බයිට)",
|
||||||
"enter_cache_ttl_min_override": "අවම පව. කා. (TTL) ඇතුල් කරන්න",
|
"enter_cache_ttl_min_override": "අවම පව. කා. (TTL) ඇතුල් කරන්න",
|
||||||
"enter_cache_ttl_max_override": "උපරිම පව. කා. (TTL) ඇතුල් කරන්න",
|
"enter_cache_ttl_max_override": "උපරිම පව. කා. (TTL) ඇතුල් කරන්න",
|
||||||
|
"cache_ttl_min_override_desc": "DNS ප්රතිචාර කේෂ කිරීමේදී උඩුගත සේවාදායකයෙන් ලබා ගන්නා කෙටි පවත්නා කාලය (තත්පර) වටිනාකම් දිගු කරන්න.",
|
||||||
"cache_ttl_max_override_desc": "ව.නා.ප. නිහිතයෙහි නිවේශිත සඳහා උපරිම පවත්නා කාලයක අගයක් (තත්.) සකසන්න.",
|
"cache_ttl_max_override_desc": "ව.නා.ප. නිහිතයෙහි නිවේශිත සඳහා උපරිම පවත්නා කාලයක අගයක් (තත්.) සකසන්න.",
|
||||||
"ttl_cache_validation": "නිහිතයෙහි පාගාගෙන යන අවම පව. කා. (TTL) උපරිමයට වඩා අඩු හෝ සමාන විය යුතුය",
|
"ttl_cache_validation": "නිහිතයෙහි පාගාගෙන යන අවම පව. කා. (TTL) උපරිමයට වඩා අඩු හෝ සමාන විය යුතුය",
|
||||||
"cache_optimistic": "සර්වශුභවාදී නිහිතගතය",
|
"cache_optimistic": "සර්වශුභවාදී නිහිතගතය",
|
||||||
@@ -614,7 +680,7 @@
|
|||||||
"click_to_view_queries": "විමසුම් බැලීමට ඔබන්න",
|
"click_to_view_queries": "විමසුම් බැලීමට ඔබන්න",
|
||||||
"port_53_faq_link": "53 වන තොට බොහෝ විට \"DNSStubListener\" හෝ \"systemd-resolved\" සේවා භාවිතයට ගනු ලැබේ. කරුණාකර මෙය විසඳන්නේ කෙසේද යන්න පිළිබඳ <0>මෙම උපදෙස්</0> කියවන්න.",
|
"port_53_faq_link": "53 වන තොට බොහෝ විට \"DNSStubListener\" හෝ \"systemd-resolved\" සේවා භාවිතයට ගනු ලැබේ. කරුණාකර මෙය විසඳන්නේ කෙසේද යන්න පිළිබඳ <0>මෙම උපදෙස්</0> කියවන්න.",
|
||||||
"adg_will_drop_dns_queries": "ඇඩ්ගාර්ඩ් හෝම් මෙම අනුග්රාහකයේ සියළුම ව.නා.ප. විමසුම් අතහැර දමනු ඇත.",
|
"adg_will_drop_dns_queries": "ඇඩ්ගාර්ඩ් හෝම් මෙම අනුග්රාහකයේ සියළුම ව.නා.ප. විමසුම් අතහැර දමනු ඇත.",
|
||||||
"filter_allowlist": "අවවාදයයි: මෙම ක්රියාමාර්ගය ඉඩලත් අනුග්රාහක ලේඛන වලින්ද \"{{disallowed_rule}}\" නීතිය බැහැර කරයි.",
|
"filter_allowlist": "අවවාදයයි: මෙම ක්රියාමාර්ගය ඉඩලත් අනුග්රාහක ලැයිස්තු වලින් ද \"{{disallowed_rule}}\" නීතිය බැහැර කරයි.",
|
||||||
"last_rule_in_allowlist": "\"{{disallowed_rule}}\" නීතිය බැහැර කිරීම \"ඉඩලත් අනුග්රාහක\" ලේඛනය අබල කරන බැවින් මෙම අනුග්රාහකය ඉඩ නොදීමට නොහැකිය.",
|
"last_rule_in_allowlist": "\"{{disallowed_rule}}\" නීතිය බැහැර කිරීම \"ඉඩලත් අනුග්රාහක\" ලේඛනය අබල කරන බැවින් මෙම අනුග්රාහකය ඉඩ නොදීමට නොහැකිය.",
|
||||||
"use_saved_key": "පෙර සුරැකි යතුර භාවිතා කරන්න",
|
"use_saved_key": "පෙර සුරැකි යතුර භාවිතා කරන්න",
|
||||||
"parental_control": "දෙමාපිය පාලනය",
|
"parental_control": "දෙමාපිය පාලනය",
|
||||||
@@ -651,11 +717,21 @@
|
|||||||
"ignore_query_log": "විමසුම් සටහනට මෙම අනුග්රාහකය යොදන්න එපා",
|
"ignore_query_log": "විමසුම් සටහනට මෙම අනුග්රාහකය යොදන්න එපා",
|
||||||
"ignore_statistics": "සංඛ්යාලේඛනයට මෙම අනුග්රාහකය යොදන්න එපා",
|
"ignore_statistics": "සංඛ්යාලේඛනයට මෙම අනුග්රාහකය යොදන්න එපා",
|
||||||
"schedule_services": "සේවා අවහිර විරාමය",
|
"schedule_services": "සේවා අවහිර විරාමය",
|
||||||
|
"schedule_services_desc": "සේවා අවහිර විරාමය සඳහා කාලසටහන සකසන්න",
|
||||||
|
"schedule_services_desc_client": "මෙම සේවා අවහිර විරාමය සඳහා කාලසටහන සකසන්න",
|
||||||
|
"schedule_desc": "අවහිර සේවා සඳහා අක්රිය කාල සීමා සකසන්න",
|
||||||
"schedule_invalid_select": "ආරම්භක වේලාව අවසන් වේලාවට කලින් විය යුතුය",
|
"schedule_invalid_select": "ආරම්භක වේලාව අවසන් වේලාවට කලින් විය යුතුය",
|
||||||
"schedule_select_days": "දවස් තෝරන්න",
|
"schedule_select_days": "දවස් තෝරන්න",
|
||||||
"schedule_timezone": "වේලා කලාපයක් තෝරන්න",
|
"schedule_timezone": "වේලා කලාපයක් තෝරන්න",
|
||||||
"schedule_current_timezone": "වත්මන් වේලා කලාපය: {{value}}",
|
"schedule_current_timezone": "වත්මන් වේලා කලාපය: {{value}}",
|
||||||
"schedule_time_all_day": "දවස පුරාම",
|
"schedule_time_all_day": "දවස පුරාම",
|
||||||
|
"schedule_modal_description": "මෙම කාලසටහන සතියේ එකම දිනය සඳහා පවතින කාලසටහන් ප්රතිස්ථාපනය කරයි. සතියේ සෑම දිනකම තිබිය හැක්කේ එක් අක්රිය කාල සීමාවක් පමණි.",
|
||||||
|
"schedule_modal_time_off": "සේවා අවහිර නැත:",
|
||||||
|
"schedule_new": "නව කාලසටහන",
|
||||||
|
"schedule_edit": "කාලසටහන සංස්කරණය කරන්න",
|
||||||
|
"schedule_save": "කාලසටහන සුරකින්න",
|
||||||
|
"schedule_add": "කාලසටහන එක් කරන්න",
|
||||||
|
"schedule_remove": "කාලසටහන ඉවත් කරන්න",
|
||||||
"schedule_from": "සිට",
|
"schedule_from": "සිට",
|
||||||
"schedule_to": "දක්වා",
|
"schedule_to": "දක්වා",
|
||||||
"sunday": "ඉරිදා",
|
"sunday": "ඉරිදා",
|
||||||
@@ -671,5 +747,8 @@
|
|||||||
"wednesday_short": "බදාදා",
|
"wednesday_short": "බදාදා",
|
||||||
"thursday_short": "බ්රහස්",
|
"thursday_short": "බ්රහස්",
|
||||||
"friday_short": "සිකු",
|
"friday_short": "සිකු",
|
||||||
"saturday_short": "සෙන"
|
"saturday_short": "සෙන",
|
||||||
|
"upstream_dns_cache_configuration": "උඩුගත ව.නා.ප. නිහිත වින්යාසය",
|
||||||
|
"enable_upstream_dns_cache": "මෙම ගනුකරුගේ අභිරුචි උඩුගත වින්යාසය සඳහා ව.නා.ප. නිහිතය සක්රිය කරන්න",
|
||||||
|
"dns_cache_size": "ව.නා.ප. නිහිතයේ ප්රමාණය (බයිට වලින්)"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,60 @@
|
|||||||
{
|
{
|
||||||
"client_settings": "การตั้งค่าไคลเอนต์",
|
"client_settings": "การตั้งค่าไคลเอนต์",
|
||||||
|
"example_upstream_reserved": "คุณสามารถระบุ DNS อัปสตรีม <0>สำหรับโดเมนเฉพาะ</0>",
|
||||||
|
"example_multiple_upstreams_reserved": "หลาย upstream <0>สำหรับโดเมนเฉพาะ</0>;",
|
||||||
|
"example_upstream_comment": "คุณสามารถระบุความคิดเห็นได้",
|
||||||
|
"upstream_parallel": "ใช้การสืบค้นแบบขนานเพื่อเพิ่มความเร็วในการแก้ไขโดยการสอบถามเซิร์ฟเวอร์ upstream ทั้งหมดพร้อมกัน",
|
||||||
|
"parallel_requests": "คำขอแบบคู่ขนาน",
|
||||||
|
"load_balancing": "โหลดบาลานซ์",
|
||||||
|
"load_balancing_desc": "สอบถามเซิร์ฟเวอร์ต้นทางทีละตัว<br/>AdGuard Home ใช้อัลกอริธึมการสุ่มแบบถ่วงน้ำหนักเพื่อเลือกเซิร์ฟเวอร์ที่มีจำนวนการค้นหาที่ล้มเหลวต่ำที่สุดและเวลาการค้นหาที่ต่ำที่สุด",
|
||||||
"bootstrap_dns": "Bootstrap เซิร์ฟเวอร์ DNS",
|
"bootstrap_dns": "Bootstrap เซิร์ฟเวอร์ DNS",
|
||||||
"bootstrap_dns_desc": "เซิร์ฟเวอร์ Bootstrap DNS ใช้เพื่อแก้ไขที่อยู่ IP ของตัวแก้ไข DoH / DoT ที่คุณระบุว่าเป็น upstreams",
|
"bootstrap_dns_desc": "เซิร์ฟเวอร์ Bootstrap DNS ใช้เพื่อแก้ไขที่อยู่ IP ของตัวแก้ไข DoH / DoT ที่คุณระบุว่าเป็น upstreams",
|
||||||
|
"fallback_dns_title": "เซิร์ฟเวอร์ DNS สำรอง",
|
||||||
|
"fallback_dns_desc": "รายการเซิร์ฟเวอร์ DNS สำรองที่ใช้เมื่อเซิร์ฟเวอร์ DNS ต้นทางไม่ตอบสนอง ซินแท็กซ์เหมือนกับในฟิลด์เซิร์ฟเวอร์ต้นทางหลักข้างต้น.",
|
||||||
|
"fallback_dns_placeholder": "ป้อนเซิร์ฟเวอร์ DNS สำรองหนึ่งตัวต่อหนึ่งบรรทัด",
|
||||||
|
"local_ptr_title": "เซิร์ฟเวอร์ DNS ส่วนตัว",
|
||||||
|
"local_ptr_desc": "เซิร์ฟเวอร์ DNS ที่ AdGuard Home ใช้สำหรับคำขอ PTR, SOA และ NS ส่วนตัว คำขอจะถูกพิจารณาว่าเป็นส่วนตัวหากขอโดเมน ARPA ที่มีซับเน็ตภายในช่วง IP ส่วนตัว (เช่น \"192.168.12.34\") และมาจากไคลเอนต์ที่มีที่อยู่ IP ส่วนตัว หากไม่ตั้งค่า จะใช้ DNS resolver เริ่มต้นของระบบปฏิบัติการของคุณ ยกเว้นที่อยู่ IP ของ AdGuard Home",
|
||||||
|
"local_ptr_default_resolver": "ตามค่าเริ่มต้น AdGuard Home ใช้ resolver DNS ตรงข้ามต่อไปนี้: {{ip}}",
|
||||||
|
"local_ptr_no_default_resolver": "AdGuard Home ไม่สามารถกำหนด DNS resolver ส่วนตัวที่เหมาะสมสำหรับระบบนี้ได้",
|
||||||
|
"local_ptr_placeholder": "ป้อนที่อยู่เซิร์ฟเวอร์หนึ่งรายการต่อบรรทัด",
|
||||||
|
"resolve_clients_title": "เปิดใช้งานการแก้ไขย้อนกลับของที่อยู่ IP ของไคลเอ็นต์",
|
||||||
|
"resolve_clients_desc": "หากเปิดใช้งาน AdGuard Home จะพยายามแก้ไขที่อยู่ IP ของไคลเอ็นต์กลับเป็นชื่อโฮสต์โดยการส่งแบบสอบถาม PTR ไปยังตัวแก้ไขที่เกี่ยวข้อง (เซิร์ฟเวอร์ DNS ส่วนตัวสำหรับไคลเอนต์ในเครื่องเซิร์ฟเวอร์ต้นน้ำสำหรับไคลเอนต์ที่มีที่อยู่ IP สาธารณะ)",
|
||||||
|
"use_private_ptr_resolvers_title": "ใช้ DNS resolver ส่วนตัวสำหรับ DNS ตรงข้าม",
|
||||||
|
"use_private_ptr_resolvers_desc": "แก้ไขคำขอ PTR, SOA และ NS สำหรับโดเมน ARPA ที่มีที่อยู่ IP ส่วนตัว ผ่านเซิร์ฟเวอร์ต้นทางส่วนตัว, DHCP, /etc/hosts เป็นต้น หากปิดการใช้งาน AdGuard Home จะตอบสนองต่อคำขอทั้งหมดดังกล่าวด้วย NXDOMAIN",
|
||||||
"check_dhcp_servers": "ตรวจสอบ DHCP servers",
|
"check_dhcp_servers": "ตรวจสอบ DHCP servers",
|
||||||
|
"save_config": "บันทึกการตั้งค่า",
|
||||||
"enabled_dhcp": "เปิดการใช้งาน DHCP server แล้ว",
|
"enabled_dhcp": "เปิดการใช้งาน DHCP server แล้ว",
|
||||||
"disabled_dhcp": "ปิดการใช้งาน DHCP server แล้ว",
|
"disabled_dhcp": "ปิดการใช้งาน DHCP server แล้ว",
|
||||||
|
"unavailable_dhcp": "DHCP ไม่พร้อมใช้งาน",
|
||||||
|
"unavailable_dhcp_desc": "AdGuard Home ไม่สามารถทำงาน DHCP server บนระบบปฎิบัติการของ Server คุณ",
|
||||||
"dhcp_title": "DHCP server (ยังไม่สมบูรณ์)",
|
"dhcp_title": "DHCP server (ยังไม่สมบูรณ์)",
|
||||||
"dhcp_description": "ถ้าหากเราเตอร์ของคุณไม่รองรับการตั้งค่า DHCP คุณสามารถใช้ ADGuard's ทำ DHCP server ได้",
|
"dhcp_description": "ถ้าหากเราเตอร์ของคุณไม่รองรับการตั้งค่า DHCP คุณสามารถใช้ ADGuard's ทำ DHCP server ได้",
|
||||||
"dhcp_enable": "เปิด DHCP server",
|
"dhcp_enable": "เปิด DHCP server",
|
||||||
"dhcp_disable": "ปิด DHCP server",
|
"dhcp_disable": "ปิด DHCP server",
|
||||||
|
"dhcp_not_found": "มีความปลอดภัยในการเปิดใช้งานเซิร์ฟเวอร์ DHCP ในตัว - เราไม่พบเซิร์ฟเวอร์ DHCP ที่ใช้งานอยู่ในเครือข่าย อย่างไรก็ตามเราขอแนะนำให้คุณตรวจสอบด้วยตนเองอีกครั้งเนื่องจากการทดสอบอัตโนมัติของเราไม่ได้รับประกัน 100%",
|
||||||
"dhcp_found": "พบเซิร์ฟเวอร์ DHCP ที่ใช้งานอยู่ในเครือข่าย ไม่ปลอดภัยที่จะเปิดใช้งานเซิร์ฟเวอร์ DHCP ในตัว",
|
"dhcp_found": "พบเซิร์ฟเวอร์ DHCP ที่ใช้งานอยู่ในเครือข่าย ไม่ปลอดภัยที่จะเปิดใช้งานเซิร์ฟเวอร์ DHCP ในตัว",
|
||||||
"dhcp_leases": "สัญญาเช่า DHCP",
|
"dhcp_leases": "สัญญาเช่า DHCP",
|
||||||
"dhcp_static_leases": "DHCP แบบกำหนด",
|
"dhcp_static_leases": "DHCP แบบกำหนด",
|
||||||
"dhcp_leases_not_found": "ไม่พบสัญญาเช่า DHCP",
|
"dhcp_leases_not_found": "ไม่พบสัญญาเช่า DHCP",
|
||||||
|
"dhcp_config_saved": "บันทึกการกำหนดค่า DHCP สำเร็จแล้ว",
|
||||||
|
"dhcp_ipv4_settings": "การตั้งค่า DHCP IPv4",
|
||||||
|
"dhcp_ipv6_settings": "การตั้งค่า DHCP IPv6",
|
||||||
"form_error_required": "ช่องที่ต้องกรอก",
|
"form_error_required": "ช่องที่ต้องกรอก",
|
||||||
"form_error_ip4_format": "รูปแบบ IPv4 ไม่ถูกต้อง",
|
"form_error_ip4_format": "รูปแบบ IPv4 ไม่ถูกต้อง",
|
||||||
|
"form_error_ip4_gateway_format": "ที่อยู่ IPv4 ของเกตเวย์ไม่ถูกต้อง",
|
||||||
"form_error_ip6_format": "รูปแบบ IPv6 ไม่ถูกต้อง",
|
"form_error_ip6_format": "รูปแบบ IPv6 ไม่ถูกต้อง",
|
||||||
"form_error_ip_format": "รูปแบบ IP ไม่ถูกต้อง",
|
"form_error_ip_format": "รูปแบบ IP ไม่ถูกต้อง",
|
||||||
"form_error_mac_format": "รูปแบบ MAC ไม่ถูกต้อง",
|
"form_error_mac_format": "รูปแบบ MAC ไม่ถูกต้อง",
|
||||||
"form_error_client_id_format": "รูปแบบ ID ลูกค้าไม่ถูกต้อง",
|
"form_error_client_id_format": "รูปแบบ ID ลูกค้าไม่ถูกต้อง",
|
||||||
|
"form_error_server_name": "ชื่อเซิร์ฟเวอร์ไม่ถูกต้อง",
|
||||||
|
"form_error_subnet": "ซับเน็ต \"{{cidr}}\" ไม่มีที่อยู่ IP \"{{ip}}\"",
|
||||||
"form_error_positive": "ต้องมากกว่า 0",
|
"form_error_positive": "ต้องมากกว่า 0",
|
||||||
|
"form_error_gateway_ip": "สัญญาเช่าไม่สามารถมีที่อยู่ IP ของเกตเวย์ได้",
|
||||||
|
"out_of_range_error": "ต้องออกจากช่วง \"{{start}}\"-\"{{end}}\"",
|
||||||
|
"lower_range_start_error": "ต้องน้อยกว่าช่วงเริ่มต้น",
|
||||||
|
"greater_range_start_error": "ต้องมากกว่าช่วงเริ่มต้น",
|
||||||
|
"subnet_error": "ที่อยู่ต้องอยู่ในซับเน็ตเดียวกัน",
|
||||||
|
"gateway_or_subnet_invalid": "หน้ากากซับเน็ตไม่ถูกต้อง",
|
||||||
"dhcp_form_gateway_input": "IP ของเกตเวย์",
|
"dhcp_form_gateway_input": "IP ของเกตเวย์",
|
||||||
"dhcp_form_subnet_input": "ซับเน็ตมาสก์",
|
"dhcp_form_subnet_input": "ซับเน็ตมาสก์",
|
||||||
"dhcp_form_range_title": "ช่วงของที่อยู่ IP",
|
"dhcp_form_range_title": "ช่วงของที่อยู่ IP",
|
||||||
@@ -30,26 +65,45 @@
|
|||||||
"dhcp_interface_select": "เลือกอินเตอร์เฟส DHCP",
|
"dhcp_interface_select": "เลือกอินเตอร์เฟส DHCP",
|
||||||
"dhcp_hardware_address": "ที่อยู่ฮาร์ดแวร์",
|
"dhcp_hardware_address": "ที่อยู่ฮาร์ดแวร์",
|
||||||
"dhcp_ip_addresses": "ที่อยู่ IP",
|
"dhcp_ip_addresses": "ที่อยู่ IP",
|
||||||
|
"ip": "ไอพี",
|
||||||
"dhcp_table_hostname": "ชื่อโฮสต์",
|
"dhcp_table_hostname": "ชื่อโฮสต์",
|
||||||
"dhcp_table_expires": "วันที่หมดอายุ",
|
"dhcp_table_expires": "วันที่หมดอายุ",
|
||||||
|
"dhcp_warning": "หากคุณต้องการเปิดใช้งานเซิร์ฟเวอร์ DHCP ตรวจสอบให้แน่ใจว่าไม่มีเซิร์ฟเวอร์ DHCP ที่ใช้งานอยู่ในเครือข่ายของคุณ มิฉะนั้นจะทำให้อินเทอร์เน็ตสำหรับอุปกรณ์ที่เชื่อมต่อมีปัญหาได้!",
|
||||||
|
"dhcp_error": "เราไม่สามารถระบุได้ว่ามีเซิร์ฟเวอร์ DHCP อื่นในเครือข่ายหรือไม่",
|
||||||
|
"dhcp_static_ip_error": "ในการใช้เซิร์ฟเวอร์ DHCP จะต้องตั้งค่าที่อยู่ IP แบบคงที่ เราไม่สามารถระบุได้ว่ามีการกำหนดค่าอินเทอร์เฟซเครือข่ายนี้โดยใช้ที่อยู่ IP แบบคงที่หรือไม่ โปรดตั้งค่าที่อยู่ IP แบบคงที่ด้วยตนเอง",
|
||||||
|
"dhcp_dynamic_ip_found": "ระบบของคุณใช้การกำหนดค่าที่อยู่ IP แบบไดนามิกสำหรับอินเทอร์เฟซ <0>{{interfaceName}}</0> ในการใช้เซิร์ฟเวอร์ DHCP จะต้องตั้งค่าที่อยู่ IP แบบคงที่ ที่อยู่ IP ปัจจุบันของคุณคือ <0>{{ipAddress}}</0> เราจะตั้งค่าที่อยู่ IP นี้เป็นแบบคงที่โดยอัตโนมัติหากคุณกดปุ่มเปิดใช้งาน DHCP",
|
||||||
"dhcp_lease_added": "เพิ่มสัญญาเช่าคงที่ \"{{key}}\" สำเร็จแล้ว",
|
"dhcp_lease_added": "เพิ่มสัญญาเช่าคงที่ \"{{key}}\" สำเร็จแล้ว",
|
||||||
"dhcp_lease_deleted": "ลบสัญญาเช่าคงที่ \"{{key}}\" สำเร็จแล้ว",
|
"dhcp_lease_deleted": "ลบสัญญาเช่าคงที่ \"{{key}}\" สำเร็จแล้ว",
|
||||||
|
"dhcp_lease_updated": "อัปเดตสัญญาเช่าคงที่ \"{{key}}\" สำเร็จแล้ว",
|
||||||
"dhcp_new_static_lease": "เช่าใหม่คงที่",
|
"dhcp_new_static_lease": "เช่าใหม่คงที่",
|
||||||
|
"dhcp_edit_static_lease": "แก้ไขสัญญาเช่าคงที่",
|
||||||
"dhcp_static_leases_not_found": "ไม่พบสัญญาเช่า DHCP แบบคงที่",
|
"dhcp_static_leases_not_found": "ไม่พบสัญญาเช่า DHCP แบบคงที่",
|
||||||
"dhcp_add_static_lease": "เพิ่มสัญญาเช่าคงที่",
|
"dhcp_add_static_lease": "เพิ่มสัญญาเช่าคงที่",
|
||||||
|
"dhcp_reset_leases": "รีเซ็ตสัญญาเช่าทั้งหมด",
|
||||||
|
"dhcp_reset_leases_confirm": "คุณแน่ใจหรือว่าต้องการรีเซ็ตสัญญาเช่าทั้งหมด?",
|
||||||
|
"dhcp_reset_leases_success": "รีเซ็ตสัญญาเช่า DHCP สำเร็จแล้ว",
|
||||||
|
"dhcp_reset": "คุณแน่ใจหรือว่าต้องการรีเซ็ตการกำหนดค่า DHCP?",
|
||||||
|
"country": "ประเทศ",
|
||||||
|
"city": "เมือง",
|
||||||
"delete_confirm": "คุณแน่ใจหรือว่าต้องการลบ \"{{key}}\"?",
|
"delete_confirm": "คุณแน่ใจหรือว่าต้องการลบ \"{{key}}\"?",
|
||||||
"form_enter_hostname": "ป้อนชื่อโฮสต์",
|
"form_enter_hostname": "ป้อนชื่อโฮสต์",
|
||||||
"error_details": "รายละเอียดข้อผิดพลาด",
|
"error_details": "รายละเอียดข้อผิดพลาด",
|
||||||
"request_details": "ขอรายละเอียด",
|
"response_details": "รายละเอียดการตอบกลับ",
|
||||||
|
"request_details": "รายละเอียดคำขอ",
|
||||||
|
"client_details": "รายละเอียดลูกข่าย",
|
||||||
|
"details": "รายละเอียด",
|
||||||
"back": "กลับ",
|
"back": "กลับ",
|
||||||
"dashboard": "แผงควบคุม",
|
"dashboard": "แผงควบคุม",
|
||||||
"settings": "การตั้งค่า",
|
"settings": "การตั้งค่า",
|
||||||
"filters": "ตัวกรอง",
|
"filters": "ตัวกรอง",
|
||||||
|
"filter": "ตัวกรอง",
|
||||||
"query_log": "บันทึกการสืบค้น",
|
"query_log": "บันทึกการสืบค้น",
|
||||||
|
"compact": "กะทัดรัด",
|
||||||
"nothing_found": "ไม่พบอะไร",
|
"nothing_found": "ไม่พบอะไร",
|
||||||
"faq": "คำถามที่พบบ่อย",
|
"faq": "คำถามที่พบบ่อย",
|
||||||
"version": "รุ่น",
|
"version": "รุ่น",
|
||||||
"address": "ที่อยู่",
|
"address": "ที่อยู่",
|
||||||
|
"protocol": "โปรโตคอล",
|
||||||
"on": "เปิด",
|
"on": "เปิด",
|
||||||
"off": "ปิด",
|
"off": "ปิด",
|
||||||
"copyright": "ลิขสิทธิ์",
|
"copyright": "ลิขสิทธิ์",
|
||||||
@@ -66,17 +120,32 @@
|
|||||||
"stats_malware_phishing": "ปิดกั้นมัลแวร์/ฟิชชิ่ง แล้ว",
|
"stats_malware_phishing": "ปิดกั้นมัลแวร์/ฟิชชิ่ง แล้ว",
|
||||||
"stats_adult": "ปิดกั้นเว็บไซต์สำหรับผู้ใหญ่แล้ว",
|
"stats_adult": "ปิดกั้นเว็บไซต์สำหรับผู้ใหญ่แล้ว",
|
||||||
"stats_query_domain": "โดเมนที่เข้าบ่อยสุด",
|
"stats_query_domain": "โดเมนที่เข้าบ่อยสุด",
|
||||||
"for_last_24_hours": "ในช่วง 24 ชั่วโมงที่ผ่านมา",
|
"for_last_hours": "สำหรับ {{count}} ชั่วโมงล่าสุด",
|
||||||
|
"for_last_hours_plural": "สำหรับ {{count}} ชั่วโมงล่าสุด",
|
||||||
"for_last_days": "สำหรับ {{count}} วันสุดท้าย",
|
"for_last_days": "สำหรับ {{count}} วันสุดท้าย",
|
||||||
"for_last_days_plural": "สำหรับ {{count}} วันล่าสุด",
|
"for_last_days_plural": "สำหรับ {{count}} วันล่าสุด",
|
||||||
|
"stats_disabled": "สถิติถูกปิดใช้งานแล้ว คุณสามารถเปิดใช้งานได้จาก <0>หน้าการตั้งค่า</0>.",
|
||||||
|
"stats_disabled_short": "สถิติถูกปิดใช้งานแล้ว",
|
||||||
"no_domains_found": "ไม่พบโดเมน",
|
"no_domains_found": "ไม่พบโดเมน",
|
||||||
"requests_count": "จำนวนคำขอ",
|
"requests_count": "จำนวนคำขอ",
|
||||||
"top_blocked_domains": "โดเมนที่ถูกปิดกั้นมากที่สุด",
|
"top_blocked_domains": "โดเมนที่ถูกปิดกั้นมากที่สุด",
|
||||||
"top_clients": "ลูกข่ายที่ใช้งานบ่อยสุด",
|
"top_clients": "ลูกข่ายที่ใช้งานบ่อยสุด",
|
||||||
"no_clients_found": "ไม่มีเครื่องลูกข่าย",
|
"no_clients_found": "ไม่มีเครื่องลูกข่าย",
|
||||||
"general_statistics": "สถิติทั่วไป",
|
"general_statistics": "สถิติทั่วไป",
|
||||||
|
"top_upstreams": "เซิร์ฟเวอร์ต้นทางที่ดีที่สุด",
|
||||||
|
"no_upstreams_data_found": "ไม่พบข้อมูลเซิร์ฟเวอร์ต้นทาง",
|
||||||
|
"number_of_dns_query_days": "จำนวนการสืบค้น DNS ที่ประมวลผลสำหรับ {{count}} วันล่าสุด",
|
||||||
|
"number_of_dns_query_days_plural": "จำนวนการสืบค้น DNS ที่ดำเนินการในช่วง {{count}} วันล่าสุด",
|
||||||
|
"number_of_dns_query_hours": "จำนวนการสืบค้น DNS ที่ดำเนินการในช่วง {{count}} ชั่วโมงล่าสุด",
|
||||||
|
"number_of_dns_query_hours_plural": "จำนวนการสืบค้น DNS ที่ดำเนินการในช่วง {{count}} ชั่วโมงล่าสุด",
|
||||||
|
"number_of_dns_query_blocked_24_hours": "จำนวนคำขอ DNS ที่ถูกปิดกั้นโดยตัวกรองปิดกั้นและโฮสต์รายการปิดกั้น",
|
||||||
|
"number_of_dns_query_blocked_24_hours_by_sec": "คำขอ DNS จำนวนหนึ่งถูกปิดกั้นโดยโมดูลความปลอดภัยการเรียกดู AdGuard",
|
||||||
|
"number_of_dns_query_blocked_24_hours_adult": "มีการปิดกั้นเว็บไซต์สำหรับผู้ใหญ่จำนวนหนึ่ง",
|
||||||
"enforced_save_search": "บังคับใช้การค้นหาที่ปลอดภัย",
|
"enforced_save_search": "บังคับใช้การค้นหาที่ปลอดภัย",
|
||||||
|
"number_of_dns_query_to_safe_search": "จำนวนคำขอ DNS ไปยังเครื่องมือค้นหาที่บังคับใช้การค้นหาปลอดภัย",
|
||||||
"average_processing_time": "เวลาประมวลผลโดยเฉลี่ย",
|
"average_processing_time": "เวลาประมวลผลโดยเฉลี่ย",
|
||||||
|
"average_upstream_response_time": "เวลาเฉลี่ยในการตอบสนองของพอร์ต",
|
||||||
|
"response_time": "เวลาในการตอบสนอง",
|
||||||
"average_processing_time_hint": "เวลาเฉลี่ยเป็นมิลลิวินาทีในการประมวลผลคำขอ DNS",
|
"average_processing_time_hint": "เวลาเฉลี่ยเป็นมิลลิวินาทีในการประมวลผลคำขอ DNS",
|
||||||
"block_domain_use_filters_and_hosts": "ปิดกั้นโดเมนโดยใช้ตัวกรองและไฟล์โฮสต์",
|
"block_domain_use_filters_and_hosts": "ปิดกั้นโดเมนโดยใช้ตัวกรองและไฟล์โฮสต์",
|
||||||
"filters_block_toggle_hint": "คุณสามารถตั้งค่ากฎการปิดกั้นในการตั้งค่า<a>ตัวกรอง</a>",
|
"filters_block_toggle_hint": "คุณสามารถตั้งค่ากฎการปิดกั้นในการตั้งค่า<a>ตัวกรอง</a>",
|
||||||
@@ -85,58 +154,104 @@
|
|||||||
"use_adguard_parental": "ใช้บริการเว็บการควบคุมโดยผู้ปกครองของ AdGuard",
|
"use_adguard_parental": "ใช้บริการเว็บการควบคุมโดยผู้ปกครองของ AdGuard",
|
||||||
"use_adguard_parental_hint": "AdGuard Home จะตรวจสอบว่าโดเมนมีเนื้อหาสำหรับผู้ใหญ่หรือไม่ มันใช้ API ความเป็นส่วนตัวเช่นเดียวกับบริการเว็บการรักษาความปลอดภัยการท่องเว็บ",
|
"use_adguard_parental_hint": "AdGuard Home จะตรวจสอบว่าโดเมนมีเนื้อหาสำหรับผู้ใหญ่หรือไม่ มันใช้ API ความเป็นส่วนตัวเช่นเดียวกับบริการเว็บการรักษาความปลอดภัยการท่องเว็บ",
|
||||||
"enforce_safe_search": "บังคับใช้การค้นหาที่ปลอดภัย",
|
"enforce_safe_search": "บังคับใช้การค้นหาที่ปลอดภัย",
|
||||||
|
"enforce_save_search_hint": "AdGuard Home จะบังคับใช้การค้นหาที่ปลอดภัยในเครื่องมือค้นหาต่อไปนี้: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay",
|
||||||
"no_servers_specified": "ไม่ได้ระบุเซิร์ฟเวอร์",
|
"no_servers_specified": "ไม่ได้ระบุเซิร์ฟเวอร์",
|
||||||
"general_settings": "การตั้งค่าทั่วไป",
|
"general_settings": "การตั้งค่าทั่วไป",
|
||||||
"dns_settings": "การตั้งค่า DNS",
|
"dns_settings": "การตั้งค่า DNS",
|
||||||
"custom_filtering_rules": "กฎการกรองที่กำหนดเอง",
|
"dns_blocklists": "รายการบล็อค DNS",
|
||||||
|
"dns_allowlists": "รายการอนุญาต DNS",
|
||||||
|
"dns_blocklists_desc": "AdGuard Home จะบล็อกโดเมนที่ตรงกับรายการบล็อค",
|
||||||
|
"dns_allowlists_desc": "โดเมนจาก DNS allowlists จะได้รับอนุญาตแม้ว่าจะอยู่ในรายการบล็อคก็ตาม",
|
||||||
|
"custom_filtering_rules": "รายการของกฎการกรอง",
|
||||||
"encryption_settings": "การตั้งค่าการเข้ารหัส",
|
"encryption_settings": "การตั้งค่าการเข้ารหัส",
|
||||||
"dhcp_settings": "การตั้งค่า DHCP",
|
"dhcp_settings": "การตั้งค่า DHCP",
|
||||||
"upstream_dns": "เซิร์ฟเวอร์ DNS ต้นทาง",
|
"upstream_dns": "เซิร์ฟเวอร์ DNS ต้นทาง",
|
||||||
|
"upstream_dns_help": "ป้อนที่อยู่เซิร์ฟเวอร์หนึ่งรายการต่อบรรทัด <a>เรียนรู้เพิ่มเติม</a> เกี่ยวกับการกำหนดค่าเซิร์ฟเวอร์ DNS ต้นทาง",
|
||||||
|
"upstream_dns_configured_in_file": "กำหนดค่าใน {{path}}",
|
||||||
"test_upstream_btn": "ทดสอบต้นทาง",
|
"test_upstream_btn": "ทดสอบต้นทาง",
|
||||||
"upstreams": "ต้นทาง",
|
"upstreams": "ต้นทาง",
|
||||||
|
"upstream": "เซิร์ฟเวอร์ต้นทาง",
|
||||||
"apply_btn": "นำไปใช้",
|
"apply_btn": "นำไปใช้",
|
||||||
"disabled_filtering_toast": "ปิดใช้งานการกรอง",
|
"disabled_filtering_toast": "ปิดใช้งานการกรอง",
|
||||||
"enabled_filtering_toast": "เปิดใช้งานการกรอง",
|
"enabled_filtering_toast": "เปิดใช้งานการกรอง",
|
||||||
"disabled_safe_browsing_toast": "ปิดใช้งานการเรียกดูอย่างปลอดภัย",
|
"disabled_safe_browsing_toast": "ปิดใช้งานการเรียกดูอย่างปลอดภัย",
|
||||||
"enabled_safe_browsing_toast": "เปิดการใช้งาน safebrowsing",
|
"enabled_safe_browsing_toast": "เปิดใช้งานการเรียกดูอย่างปลอดภัย",
|
||||||
"disabled_parental_toast": "ปิดใช้งานการควบคุมโดยผู้ปกครอง",
|
"disabled_parental_toast": "ปิดใช้งานการควบคุมโดยผู้ปกครอง",
|
||||||
"enabled_parental_toast": "เปิดการใช้งานเข้าเว็บไม่พึงประสงค์",
|
"enabled_parental_toast": "เปิดการใช้งานควบคุมโดยผู้ปกครอง",
|
||||||
"disabled_safe_search_toast": "ปิดใช้งานการค้นหาที่ปลอดภัย",
|
"disabled_safe_search_toast": "ปิดใช้งานการค้นหาที่ปลอดภัย",
|
||||||
"enabled_save_search_toast": "เปิดใช้งานการค้นหาที่ปลอดภัย",
|
"enabled_save_search_toast": "เปิดใช้งานการค้นหาที่ปลอดภัย",
|
||||||
|
"updated_save_search_toast": "การตั้งค่าการค้นหาที่ปลอดภัยได้รับการปรับปรุงแล้ว",
|
||||||
"enabled_table_header": "เปิดใช้งาน",
|
"enabled_table_header": "เปิดใช้งาน",
|
||||||
"name_table_header": "ชื่อ",
|
"name_table_header": "ชื่อ",
|
||||||
|
"list_url_table_header": "รายการ URL",
|
||||||
"rules_count_table_header": "กฎการนับ",
|
"rules_count_table_header": "กฎการนับ",
|
||||||
"last_time_updated_table_header": "ปรับปรุงครั้งล่าสุด",
|
"last_time_updated_table_header": "ปรับปรุงครั้งล่าสุด",
|
||||||
"actions_table_header": "การกระทำ",
|
"actions_table_header": "การกระทำ",
|
||||||
|
"request_table_header": "คำขอ",
|
||||||
"edit_table_action": "แก้ไข",
|
"edit_table_action": "แก้ไข",
|
||||||
"delete_table_action": "ลบ",
|
"delete_table_action": "ลบ",
|
||||||
|
"elapsed": "ระยะเวลา",
|
||||||
"filters_and_hosts_hint": "AdGuard Home เข้าใจกฎปิดกั้นโฆษณาพื้นฐานและโฮสต์ไฟล์ไวยากรณ์",
|
"filters_and_hosts_hint": "AdGuard Home เข้าใจกฎปิดกั้นโฆษณาพื้นฐานและโฮสต์ไฟล์ไวยากรณ์",
|
||||||
|
"no_blocklist_added": "ไม่มีรายการบล็อกเพิ่ม",
|
||||||
|
"no_whitelist_added": "ไม่มีการเพิ่มรายการอนุญาต",
|
||||||
|
"add_blocklist": "เพิ่มรายการบล็อก",
|
||||||
|
"add_allowlist": "ไม่มีรายการอนุญาต",
|
||||||
"cancel_btn": "ยกเลิก",
|
"cancel_btn": "ยกเลิก",
|
||||||
"enter_name_hint": "ป้อนชื่อ",
|
"enter_name_hint": "ป้อนชื่อ",
|
||||||
|
"enter_url_or_path_hint": "ป้อน URL หรือเส้นทางสัมบูรณ์ของรายการ",
|
||||||
"check_updates_btn": "ตรวจสอบการปรับปรุง",
|
"check_updates_btn": "ตรวจสอบการปรับปรุง",
|
||||||
|
"new_blocklist": "รายการบล็อคใหม่",
|
||||||
|
"new_allowlist": "รายการอนุญาตใหม่",
|
||||||
|
"edit_blocklist": "แก้ไขรายการบล็อก",
|
||||||
|
"edit_allowlist": "แก้ไขรายการอนุญาต",
|
||||||
|
"choose_blocklist": "Choose blocklists",
|
||||||
|
"choose_allowlist": "เลือกรายการอนุญาต",
|
||||||
|
"enter_valid_blocklist": "ป้อน URL ที่ถูกต้องไปยังรายการปิดกั้น",
|
||||||
|
"enter_valid_allowlist": "ป้อน URL ที่ถูกต้องไปยังรายการที่อนุญาต",
|
||||||
|
"form_error_url_format": "รูปแบบ URL ไม่ถูกต้อง",
|
||||||
|
"form_error_url_or_path_format": "URL ไม่ถูกต้องหรือเส้นทางสัมบูรณ์ของรายการ",
|
||||||
"custom_filter_rules": "กฎการกรองที่กำหนดเอง",
|
"custom_filter_rules": "กฎการกรองที่กำหนดเอง",
|
||||||
"custom_filter_rules_hint": "ป้อนหนึ่งกฎในหนึ่งบรรทัด คุณสามารถใช้กฎปิดกั้นโฆษณาหรือโฮสต์ไฟล์ไวยากรณ์",
|
"custom_filter_rules_hint": "ป้อนหนึ่งกฎในหนึ่งบรรทัด คุณสามารถใช้กฎปิดกั้นโฆษณาหรือโฮสต์ไฟล์ไวยากรณ์",
|
||||||
|
"system_host_files": "ไฟล์โฮสต์ระบบ",
|
||||||
"examples_title": "ตัวอย่าง",
|
"examples_title": "ตัวอย่าง",
|
||||||
"example_meaning_filter_block": "ปิดกั้นการเข้าถึงโดเมน example.org และโดเมนย่อยทั้งหมด",
|
"example_meaning_filter_block": "ปิดกั้นการเข้าถึงโดเมน example.org และโดเมนย่อยทั้งหมด",
|
||||||
"example_meaning_filter_whitelist": "เลิกปิดกั้นการเข้าถึงโดเมน example.org และโดเมนย่อยทั้งหมด",
|
"example_meaning_filter_whitelist": "เลิกปิดกั้นการเข้าถึงโดเมน example.org และโดเมนย่อยทั้งหมด",
|
||||||
"example_meaning_host_block": "ตอนนี้ AdGuard Home จะส่งคืนที่อยู่ 127.0.0.1 สำหรับโดเมน example.org (แต่ไม่ใช่โดเมนย่อย)",
|
"example_meaning_host_block": "ตอนนี้ AdGuard Home จะส่งคืนที่อยู่ 127.0.0.1 สำหรับโดเมน example.org (แต่ไม่ใช่โดเมนย่อย)",
|
||||||
"example_comment": "! นี่ความคิดเห็น",
|
"example_comment": "! นี่คือความคิดเห็น",
|
||||||
"example_comment_meaning": "เพียงความคิดเห็น",
|
"example_comment_meaning": "เพียงความคิดเห็น",
|
||||||
"example_comment_hash": "# นอกจากนี้ยังมีความคิดเห็น",
|
"example_comment_hash": "# นอกจากนี้ยังมีความคิดเห็น",
|
||||||
"example_regex_meaning": "ปิดกั้นการเข้าถึงโดเมนที่ตรงกับนิพจน์ทั่วไปที่ระบุ",
|
"example_regex_meaning": "ปิดกั้นการเข้าถึงโดเมนที่ตรงกับนิพจน์ทั่วไปที่ระบุ",
|
||||||
"example_upstream_regular": "DNS ปกติ (มากกว่า UDP)",
|
"example_upstream_regular": "DNS ปกติ (มากกว่า UDP)",
|
||||||
|
"example_upstream_regular_port": "DNS ปกติ (ผ่าน UDP, พร้อมพอร์ต);",
|
||||||
|
"example_upstream_udp": "DNS ปกติ (ผ่าน UDP, ชื่อโฮสต์);",
|
||||||
"example_upstream_dot": "encrypted <0>DNS-over-TLS</0> แล้ว",
|
"example_upstream_dot": "encrypted <0>DNS-over-TLS</0> แล้ว",
|
||||||
"example_upstream_doh": "เข้ารหัส <0>DNS-over-HTTPS</0> แล้ว",
|
"example_upstream_doh": "เข้ารหัส <0>DNS-over-HTTPS</0> แล้ว",
|
||||||
|
"example_upstream_doh3": "DNS-over-HTTPS ถูกเข้ารหัสพร้อมแรงบีบ <0>HTTP/3</0> และไม่มีการย้อนกลับไปยัง HTTP/2 หรือต่ำกว่า;",
|
||||||
|
"example_upstream_doq": "เข้ารหัส <0> DNS-over-QUIC </0>",
|
||||||
"example_upstream_sdns": "คุณสามรถใช้ <0>DNS Stamps</0> กับ <1>DNSCrypt</1> หรือ <2>DNS-over-HTTPS</2> ตัวแก้ปัญหา",
|
"example_upstream_sdns": "คุณสามรถใช้ <0>DNS Stamps</0> กับ <1>DNSCrypt</1> หรือ <2>DNS-over-HTTPS</2> ตัวแก้ปัญหา",
|
||||||
"example_upstream_tcp": "dNS ปกติ (ผ่าน TCP)",
|
"example_upstream_tcp": "dNS ปกติ (ผ่าน TCP)",
|
||||||
|
"example_upstream_tcp_port": "DNS ปกติ (ผ่าน TCP, พร้อมพอร์ต);",
|
||||||
|
"example_upstream_tcp_hostname": "DNS ปกติ (ผ่าน TCP, ชื่อโฮสต์);",
|
||||||
|
"all_lists_up_to_date_toast": "รายการทั้งหมดเป็นข้อมูลล่าสุดอยู่แล้ว",
|
||||||
|
"updated_upstream_dns_toast": "อัปเดตเซิร์ฟเวอร์ DNS ต้นทาง",
|
||||||
"dns_test_ok_toast": "เซิร์ฟเวอร์ DNS ที่ระบุทำงานอย่างถูกต้อง",
|
"dns_test_ok_toast": "เซิร์ฟเวอร์ DNS ที่ระบุทำงานอย่างถูกต้อง",
|
||||||
"dns_test_not_ok_toast": "เซิร์ฟเวอร์ \"{{key}}\": ไม่สามารถใช้งานได้ โปรดตรวจสอบว่าคุณเขียนถูกต้อง",
|
"dns_test_not_ok_toast": "เซิร์ฟเวอร์ \"{{key}}\": ไม่สามารถใช้งานได้ โปรดตรวจสอบว่าคุณเขียนถูกต้อง",
|
||||||
|
"dns_test_parsing_error_toast": "ส่วน {{section}}: บรรทัด {{line}}: ไม่สามารถใช้งานได้ กรุณาตรวจสอบว่าคุณเขียนถูกต้องแล้ว",
|
||||||
|
"dns_test_warning_toast": "อัปสตรีม \"{{key}}\" ไม่ตอบสนองต่อคำขอทดสอบและอาจไม่ทำงานอย่างถูกต้อง",
|
||||||
"unblock": "เลิกปิดกั้น",
|
"unblock": "เลิกปิดกั้น",
|
||||||
"block": "ปิดกั้น",
|
"block": "ปิดกั้น",
|
||||||
|
"disallow_this_client": "ไม่อนุญาตไคลเอ็นต์นี้",
|
||||||
|
"allow_this_client": "อนุญาตไคลเอ็นต์นี้",
|
||||||
|
"block_for_this_client_only": "ปิดกั้นสำหรับไคลเอ็นต์นี้เท่านั้น",
|
||||||
|
"unblock_for_this_client_only": "เลิกปิดกั้นสำหรับไคลเอนต์นี้เท่านั้น",
|
||||||
|
"add_persistent_client": "เพิ่มเป็นไคลเอนต์ถาวร",
|
||||||
"time_table_header": "เวลา",
|
"time_table_header": "เวลา",
|
||||||
|
"date": "วันที่",
|
||||||
"domain_name_table_header": "ชื่อโดเมน",
|
"domain_name_table_header": "ชื่อโดเมน",
|
||||||
|
"domain_or_client": "โดเมนหรือไคลเอนต์",
|
||||||
"type_table_header": "ประเภท",
|
"type_table_header": "ประเภท",
|
||||||
"response_table_header": "การตอบสนอง",
|
"response_table_header": "การตอบสนอง",
|
||||||
|
"response_code": "รหัสตอบกลับ",
|
||||||
"client_table_header": "เครื่องลูกข่าย",
|
"client_table_header": "เครื่องลูกข่าย",
|
||||||
"empty_response_status": "ว่างเปล่า",
|
"empty_response_status": "ว่างเปล่า",
|
||||||
"show_all_filter_type": "แสดงทั้งหมด",
|
"show_all_filter_type": "แสดงทั้งหมด",
|
||||||
@@ -155,45 +270,87 @@
|
|||||||
"query_log_filtered": "กรองโดย {{filter}}",
|
"query_log_filtered": "กรองโดย {{filter}}",
|
||||||
"query_log_confirm_clear": "คุณแน่ใจหรือไม่ว่าต้องการลบบันทึกการใช้งานทั้งหมด?",
|
"query_log_confirm_clear": "คุณแน่ใจหรือไม่ว่าต้องการลบบันทึกการใช้งานทั้งหมด?",
|
||||||
"query_log_cleared": "บันทึกการใช้งานได้รับการล้างเรียบร้อยแล้ว",
|
"query_log_cleared": "บันทึกการใช้งานได้รับการล้างเรียบร้อยแล้ว",
|
||||||
|
"query_log_updated": "อัปเดตบันทึกการสืบค้นสำเร็จแล้ว",
|
||||||
"query_log_clear": "ล้างบันทึกการสืบค้น",
|
"query_log_clear": "ล้างบันทึกการสืบค้น",
|
||||||
"query_log_retention": "แบบสอบถามบันทึกการเก็บรักษา",
|
"query_log_retention": "การหมุนเวียนบันทึกคำขอ",
|
||||||
"query_log_enable": "เปิดใช้งานบันทึก",
|
"query_log_enable": "เปิดใช้งานบันทึก",
|
||||||
"query_log_configuration": "บันทึกการกำหนดค่า",
|
"query_log_configuration": "บันทึกการกำหนดค่า",
|
||||||
"query_log_disabled": "บันทึกแบบสอบถามถูกปิดใช้งานและสามารถกำหนดค่าใน <0>การตั้งค่า</0>",
|
"query_log_disabled": "บันทึกแบบสอบถามถูกปิดใช้งานและสามารถกำหนดค่าใน <0>การตั้งค่า</0>",
|
||||||
"query_log_strict_search": "ใช้เครื่องหมายคำพูดคู่เพื่อการค้นหาที่จำกัด",
|
"query_log_strict_search": "ใช้เครื่องหมายคำพูดคู่เพื่อการค้นหาที่จำกัด",
|
||||||
"query_log_retention_confirm": "คุณแน่ใจหรือไม่ว่าต้องการเปลี่ยนการเก็บข้อมูลบันทึกแบบสอบถาม? หากคุณลดค่าช่วงเวลา ข้อมูลบางอย่างจะหายไป",
|
"query_log_retention_confirm": "คุณแน่ใจหรือไม่ว่าต้องการเปลี่ยนการเก็บข้อมูลบันทึกแบบสอบถาม? หากคุณลดค่าช่วงเวลา ข้อมูลบางอย่างจะหายไป",
|
||||||
|
"anonymize_client_ip": "ปิดบังเลข ip ของเครื่องลูกข่าย",
|
||||||
|
"anonymize_client_ip_desc": "อย่าบันทึกที่อยู่ IP แบบเต็มของไคลเอนต์ในบันทึกและสถิติ",
|
||||||
"dns_config": "การกำหนดค่าเซิร์ฟเวอร์ DNS",
|
"dns_config": "การกำหนดค่าเซิร์ฟเวอร์ DNS",
|
||||||
|
"dns_cache_config": "การกำหนดค่าแคช DNS",
|
||||||
|
"dns_cache_config_desc": "คุณสามารถกำหนดค่า DNS cache ได้ที่นี่",
|
||||||
"blocking_mode": "โหมดการปิดกั้น",
|
"blocking_mode": "โหมดการปิดกั้น",
|
||||||
"default": "ค่าเริ่มต้น",
|
"default": "ค่าเริ่มต้น",
|
||||||
"nxdomain": "NXDOMAIN",
|
"nxdomain": "NXDOMAIN",
|
||||||
|
"refused": "ปฏิเสธ",
|
||||||
"null_ip": "IP ว่าง",
|
"null_ip": "IP ว่าง",
|
||||||
"custom_ip": "IP กำหนดเอง",
|
"custom_ip": "IP กำหนดเอง",
|
||||||
"blocking_ipv4": "ปิดกั้น IPv4",
|
"blocking_ipv4": "ปิดกั้น IPv4",
|
||||||
"blocking_ipv6": "ปิดกั้น IPv6",
|
"blocking_ipv6": "ปิดกั้น IPv6",
|
||||||
|
"blocked_response_ttl": "การตอบกลับที่ถูกปิดกั้น TTL",
|
||||||
|
"blocked_response_ttl_desc": "ระบุว่าไคลเอนต์ควรแคชการตอบสนองที่ผ่านการกรองเป็นเวลากี่วินาที",
|
||||||
|
"form_enter_blocked_response_ttl": "ป้อนการตอบกลับที่ถูกบล็อค TTL (วินาที)",
|
||||||
|
"upstream_timeout": "ระยะเวลาหมดอายุของต้นทาง",
|
||||||
|
"upstream_timeout_desc": "ระบุจำนวนวินาทีที่ต้องรอการตอบกลับจากเซิร์ฟเวอร์ต้นทาง",
|
||||||
|
"form_enter_upstream_timeout": "ป้อนระยะเวลา timeout ของเซิร์ฟเวอร์ต้นทางเป็นวินาที",
|
||||||
"dnscrypt": "DNSCrypt",
|
"dnscrypt": "DNSCrypt",
|
||||||
"dns_over_https": "DNS-over-HTTPS",
|
"dns_over_https": "DNS-over-HTTPS",
|
||||||
"dns_over_tls": "DNS-over-TLS",
|
"dns_over_tls": "DNS-over-TLS",
|
||||||
"dns_over_quic": "DNS-over-QUIC",
|
"dns_over_quic": "DNS-over-QUIC",
|
||||||
|
"client_id": "รหัสลูกค้า",
|
||||||
|
"client_id_placeholder": "ป้อนรหัสลูกค้า",
|
||||||
|
"client_id_desc": "ลูกค้าที่แตกต่างกันสามารถระบุได้ด้วยรหัสลูกค้าพิเศษ <a>ที่นี่</a> คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับวิธีระบุลูกค้า",
|
||||||
|
"download_mobileconfig_doh": "ดาวน์โหลด .mobileconfig สำหรับ DNS-over-HTTPS",
|
||||||
|
"download_mobileconfig_dot": "ดาวน์โหลด .mobileconfig สำหรับ DNS-over-TLS",
|
||||||
|
"download_mobileconfig": "ดาวน์โหลดไฟล์กำหนดค่า",
|
||||||
|
"plain_dns": "DNS ธรรมดา",
|
||||||
"form_enter_rate_limit": "ป้อนขีดจำกัดอัตรา",
|
"form_enter_rate_limit": "ป้อนขีดจำกัดอัตรา",
|
||||||
"rate_limit": "จำกัดอัตรา",
|
"rate_limit": "จำกัดอัตรา",
|
||||||
"edns_enable": "เปิดใช้งานซับเน็ตไคลเอ็นต์ EDNS",
|
"edns_enable": "เปิดใช้งานซับเน็ตไคลเอ็นต์ EDNS",
|
||||||
"edns_cs_desc": "หากเปิดใช้งาน AdGuard Home จะส่งซับเน็ตของไคลเอนต์ไปยังเซิร์ฟเวอร์ DNS",
|
"edns_cs_desc": "เพิ่มตัวเลือก EDNS Client Subnet (ECS) ลงในคำร้องขอไปยัง upstream และบันทึกค่าที่ส่งโดยไคลเอนต์ในบันทึกคำขอ.",
|
||||||
|
"edns_use_custom_ip": "ใช้ IP ที่กำหนดเองสำหรับ EDNS",
|
||||||
|
"edns_use_custom_ip_desc": "อนุญาตให้ใช้ IP ที่กำหนดเองสำหรับ EDNS",
|
||||||
|
"rate_limit_desc": "จำนวนการร้องขอต่อวินาทีที่อนุญาตให้ไคลเอนต์เดียวทำ (0: ไม่จำกัดจำนวน)",
|
||||||
|
"rate_limit_subnet_len_ipv4": "ความยาวของคำนำหน้าซับเน็ตสำหรับที่อยู่ IPv4",
|
||||||
|
"rate_limit_subnet_len_ipv4_desc": "ความยาวพรีฟิกซ์ซับเน็ตสำหรับที่อยู่ IPv4 ที่ใช้สำหรับการจำกัดอัตรา ค่าเริ่มต้นคือ 24",
|
||||||
|
"rate_limit_subnet_len_ipv4_error": "ความยาวพรีฟิกซ์ซับเน็ต IPv4 ควรอยู่ระหว่าง 0 ถึง 32",
|
||||||
|
"rate_limit_subnet_len_ipv6": "ความยาวของคำนำหน้าซับเน็ตสำหรับที่อยู่ IPv6",
|
||||||
|
"rate_limit_subnet_len_ipv6_desc": "ความยาวพรีฟิกซ์ซับเน็ตสำหรับที่อยู่ IPv6 ที่ใช้สำหรับการจำกัดอัตรา ค่าเริ่มต้นคือ 56",
|
||||||
|
"rate_limit_subnet_len_ipv6_error": "ความยาวพรีฟิกซ์ซับเน็ต IPv6 ควรอยู่ระหว่าง 0 ถึง 128",
|
||||||
|
"form_enter_rate_limit_subnet_len": "ป้อนความยาวคำนำหน้าซับเน็ตเพื่อจำกัดอัตรา",
|
||||||
|
"rate_limit_whitelist": "รายการอนุญาตจำกัดอัตรา",
|
||||||
|
"rate_limit_whitelist_desc": "ที่อยู่ IP ที่ถูกยกเว้นจากการจำกัดอัตรา",
|
||||||
|
"rate_limit_whitelist_placeholder": "ป้อนที่อยู่ IP หนึ่งรายการต่อบรรทัด",
|
||||||
"blocking_ipv4_desc": "ที่อยู่ IP ที่จะส่งคืนสำหรับคำขอที่ถูกปิดกั้น",
|
"blocking_ipv4_desc": "ที่อยู่ IP ที่จะส่งคืนสำหรับคำขอที่ถูกปิดกั้น",
|
||||||
"blocking_ipv6_desc": "ที่อยู่ IP ที่จะส่งคืนสำหรับคำขอ AAAA ที่ถูกปิดกั้น",
|
"blocking_ipv6_desc": "ที่อยู่ IP ที่จะส่งคืนสำหรับคำขอ AAAA ที่ถูกปิดกั้น",
|
||||||
|
"blocking_mode_default": "ปฏิเสธ: ตอบสนองด้วย REFUSED เมื่อถูกปิดกั้นโดยกฎสไตล์ปิดกั้นโฆษณา; ตอบกลับด้วยที่อยู่ IP ที่ระบุในกฎเมื่อถูกปิดกั้นโดยกฎ /etc/hosts-style",
|
||||||
|
"blocking_mode_refused": "REFUSED: ตอบกลับด้วยรหัส REFUSED",
|
||||||
"blocking_mode_nxdomain": "NXDOMAIN: ตอบสนองด้วยรหัส NXDOMAIN",
|
"blocking_mode_nxdomain": "NXDOMAIN: ตอบสนองด้วยรหัส NXDOMAIN",
|
||||||
"blocking_mode_null_ip": "Null IP: ตอบกลับด้วยที่อยู่เลขศูนย์ IP (0.0.0.0 สำหรับ A; :: สำหรับ AAAA)",
|
"blocking_mode_null_ip": "Null IP: ตอบกลับด้วยที่อยู่เลขศูนย์ IP (0.0.0.0 สำหรับ A; :: สำหรับ AAAA)",
|
||||||
"blocking_mode_custom_ip": "IP ที่กำหนดเอง: ตอบกลับด้วยที่อยู่ IP ที่ตั้งค่าด้วยตนเอง",
|
"blocking_mode_custom_ip": "IP ที่กำหนดเอง: ตอบกลับด้วยที่อยู่ IP ที่ตั้งค่าด้วยตนเอง",
|
||||||
|
"theme_auto": "ออโต้",
|
||||||
|
"theme_light": "โหมดสว่าง",
|
||||||
|
"theme_dark": "โหมดมืด",
|
||||||
"upstream_dns_client_desc": "หากคุณเว้นช่องนี้ว่างไว้ AdGuard Home จะใช้เซิร์ฟเวอร์ที่กำหนดค่าใน <0>การตั้งค่า DNS</0>",
|
"upstream_dns_client_desc": "หากคุณเว้นช่องนี้ว่างไว้ AdGuard Home จะใช้เซิร์ฟเวอร์ที่กำหนดค่าใน <0>การตั้งค่า DNS</0>",
|
||||||
|
"tracker_source": "แหล่งที่มาของตัวติดตาม",
|
||||||
"source_label": "ที่มา",
|
"source_label": "ที่มา",
|
||||||
"found_in_known_domain_db": "พบในฐานข้อมูลโดเมนที่รู้จัก",
|
"found_in_known_domain_db": "พบในฐานข้อมูลโดเมนที่รู้จัก",
|
||||||
"category_label": "ประเภท",
|
"category_label": "ประเภท",
|
||||||
|
"rule_label": "กฎ",
|
||||||
|
"list_label": "รายการ",
|
||||||
"unknown_filter": "ตัวกรองที่ไม่รู้จัก {{filterId}}",
|
"unknown_filter": "ตัวกรองที่ไม่รู้จัก {{filterId}}",
|
||||||
|
"known_tracker": "ตัวติดตามที่รู้จัก",
|
||||||
"install_welcome_title": "ยินดีต้อนรับสู่ AdGuard Home",
|
"install_welcome_title": "ยินดีต้อนรับสู่ AdGuard Home",
|
||||||
"install_welcome_desc": "AdGuard Home เป็นเซิร์ฟเวอร์ DNS ปิดกั้นโฆษณาและติดตามทั่วทั้งเครือข่าย วัตถุประสงค์คือเพื่อให้คุณควบคุมเครือข่ายทั้งหมดและอุปกรณ์ทั้งหมดของคุณและไม่จำเป็นต้องใช้โปรแกรมฝั่งไคลเอ็นต์",
|
"install_welcome_desc": "AdGuard Home เป็นเซิร์ฟเวอร์ DNS ปิดกั้นโฆษณาและติดตามทั่วทั้งเครือข่าย วัตถุประสงค์คือเพื่อให้คุณควบคุมเครือข่ายทั้งหมดและอุปกรณ์ทั้งหมดของคุณและไม่จำเป็นต้องใช้โปรแกรมฝั่งไคลเอ็นต์",
|
||||||
"install_settings_title": "รูปแบบเว็บสำหรับผู้ดูแล",
|
"install_settings_title": "รูปแบบเว็บสำหรับผู้ดูแล",
|
||||||
"install_settings_listen": "รูปแบบการดักจับ",
|
"install_settings_listen": "รูปแบบการดักจับ",
|
||||||
"install_settings_port": "พอร์ต",
|
"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": "เซิรฟ์เวอร์ DNS",
|
||||||
"install_settings_dns_desc": "คุณจะต้องกำหนดค่าอุปกรณ์หรือเราเตอร์ของคุณเพื่อใช้เซิร์ฟเวอร์ DNS ตามที่อยู่ต่อไปนี้:",
|
"install_settings_dns_desc": "คุณจะต้องกำหนดค่าอุปกรณ์หรือเราเตอร์ของคุณเพื่อใช้เซิร์ฟเวอร์ DNS ตามที่อยู่ต่อไปนี้:",
|
||||||
"install_settings_all_interfaces": "อินเทอร์เฟซทั้งหมด",
|
"install_settings_all_interfaces": "อินเทอร์เฟซทั้งหมด",
|
||||||
@@ -212,14 +369,16 @@
|
|||||||
"install_devices_router": "เราเตอร์",
|
"install_devices_router": "เราเตอร์",
|
||||||
"install_devices_router_desc": "การตั้งค่านี้จะครอบคลุมอุปกรณ์ทั้งหมดที่เชื่อมต่อกับเราเตอร์ที่บ้านของคุณโดยอัตโนมัติและคุณไม่จำเป็นต้องกำหนดค่าแต่ละอุปกรณ์ด้วยตนเอง",
|
"install_devices_router_desc": "การตั้งค่านี้จะครอบคลุมอุปกรณ์ทั้งหมดที่เชื่อมต่อกับเราเตอร์ที่บ้านของคุณโดยอัตโนมัติและคุณไม่จำเป็นต้องกำหนดค่าแต่ละอุปกรณ์ด้วยตนเอง",
|
||||||
"install_devices_address": "เซิร์ฟเวอร์ DNS ของ AdGuard Home กำลังรับฟังตามที่อยู่ต่อไปนี้",
|
"install_devices_address": "เซิร์ฟเวอร์ DNS ของ AdGuard Home กำลังรับฟังตามที่อยู่ต่อไปนี้",
|
||||||
|
"install_devices_router_list_1": "เปิดการตั้งค่าสำหรับเราเตอร์ของคุณ โดยปกติแล้วคุณสามารถเข้าถึงได้จากเบราว์เซอร์ของคุณผ่าน URL (เช่น http://192.168.0.1/ หรือ http://192.168.1.1/) คุณอาจถูกขอให้ป้อนรหัสผ่าน หากคุณจำไม่ได้คุณสามารถรีเซ็ตรหัสผ่านได้บ่อยครั้งโดยกดปุ่มบนเราเตอร์เอง อย่างไรก็ตามคุณควรทราบว่าหากเลือกขั้นตอนนี้คุณอาจสูญเสียการกำหนดค่าของเราเตอร์ทั้งหมด หากเราเตอร์ของคุณต้องการแอปในการตั้งค่า กรุณาติดตั้งแอปบนโทรศัพท์หรือคอมพิวเตอร์ของคุณแล้วใช้เพื่อเข้าถึงการตั้งค่าของเราเตอร์",
|
||||||
"install_devices_router_list_2": "ค้นหาการตั้งค่า DHCP/DNS ค้นหาตัวอักษร DNS ที่อยู่ถัดจากช่องที่อนุญาตให้มีตัวเลขสองหรือสามชุดโดยแต่ละกลุ่มแบ่งออกเป็นสี่กลุ่มหนึ่งถึงสามหลัก",
|
"install_devices_router_list_2": "ค้นหาการตั้งค่า DHCP/DNS ค้นหาตัวอักษร DNS ที่อยู่ถัดจากช่องที่อนุญาตให้มีตัวเลขสองหรือสามชุดโดยแต่ละกลุ่มแบ่งออกเป็นสี่กลุ่มหนึ่งถึงสามหลัก",
|
||||||
"install_devices_router_list_3": "ป้อนที่อยู่เซิร์ฟเวอร์ AdGuard Home ของคุณที่นั่น",
|
"install_devices_router_list_3": "ป้อนที่อยู่เซิร์ฟเวอร์ AdGuard Home ของคุณที่นั่น",
|
||||||
|
"install_devices_router_list_4": "ในเราเตอร์บางประเภท ไม่สามารถตั้งค่าเซิร์ฟเวอร์ DNS แบบกำหนดเองได้ ในกรณีนั้น ให้ตั้งค่า AdGuard Home เป็นเซิร์ฟเวอร์ DHCP</0> อาจช่วยได้ มิฉะนั้น คุณควรตรวจสอบคู่มือเราเตอร์เพื่อดูวิธีปรับแต่งเซิร์ฟเวอร์ DNS ในรุ่นเราเตอร์ของคุณโดยเฉพาะ",
|
||||||
"install_devices_windows_list_1": "เปิด Control Panel โดยใช้ Start menu หรือ Windows search",
|
"install_devices_windows_list_1": "เปิด Control Panel โดยใช้ Start menu หรือ Windows search",
|
||||||
"install_devices_windows_list_2": "ไปที่หมวด Network and Internet แล้วเลือก Network and Sharing Center",
|
"install_devices_windows_list_2": "ไปที่หมวด Network and Internet แล้วเลือก Network and Sharing Center",
|
||||||
"install_devices_windows_list_3": "ทางด้านซ้ายจะมีคำว่า Change adapter settings ให้กดเข้าไป",
|
"install_devices_windows_list_3": "ทางด้านซ้ายจะมีคำว่า Change adapter settings ให้กดเข้าไป",
|
||||||
"install_devices_windows_list_4": "เลือกการเชื่อมต่อที่ใช้งานอยู่ คลิกขวาแล้วเลือก Properties",
|
"install_devices_windows_list_4": "เลือกการเชื่อมต่อที่ใช้งานอยู่ คลิกขวาแล้วเลือก Properties",
|
||||||
"install_devices_windows_list_5": "ค้นหา Internet Protocol Version 4 (TCP/IP) แล้วคลิก Properties อีกครั้ง",
|
"install_devices_windows_list_5": "ค้นหา Internet Protocol Version 4 (TCP/IP) แล้วคลิก Properties อีกครั้ง",
|
||||||
"install_devices_windows_list_6": "ค้นหา DNS server addresses ให้ทำการกรอกหมายเลข AdGuard Home ลงไปในช่อง",
|
"install_devices_windows_list_6": "เลือก \"ใช้ที่อยู่เซิร์ฟเวอร์ DNS ต่อไปนี้\" และป้อนที่อยู่เซิร์ฟเวอร์ AdGuard Home ของคุณ",
|
||||||
"install_devices_macos_list_1": "คลิกโลโก้แอปเปิ้ลแล้วกด System Preferences",
|
"install_devices_macos_list_1": "คลิกโลโก้แอปเปิ้ลแล้วกด System Preferences",
|
||||||
"install_devices_macos_list_2": "คลิก Network",
|
"install_devices_macos_list_2": "คลิก Network",
|
||||||
"install_devices_macos_list_3": "เลือกการเชื่อมต่อแล้วคลิก Advanced",
|
"install_devices_macos_list_3": "เลือกการเชื่อมต่อแล้วคลิก Advanced",
|
||||||
@@ -238,7 +397,8 @@
|
|||||||
"open_dashboard": "เปิดหน้าควบคุม",
|
"open_dashboard": "เปิดหน้าควบคุม",
|
||||||
"install_saved": "บันทึกเรียบร้อยแล้ว",
|
"install_saved": "บันทึกเรียบร้อยแล้ว",
|
||||||
"encryption_title": "การเข้ารหัส",
|
"encryption_title": "การเข้ารหัส",
|
||||||
"encryption_desc": "การดข้ารหัส (HTTPS/TLS) รองรับทั้ง DNS และหน้าเว็บแอดมิน",
|
"encryption_desc": "การเข้ารหัส (HTTPS/QUIC/TLS) รองรับทั้ง DNS และหน้าเว็บแอดมิน",
|
||||||
|
"encryption_config_saved": "บันทึกการตั้งค่าเข้ารหัสเรียบร้อยแล้ว",
|
||||||
"encryption_server": "ชื่อเซิร์ฟเวอร์",
|
"encryption_server": "ชื่อเซิร์ฟเวอร์",
|
||||||
"encryption_server_enter": "ป้อนชื่อโดเมน",
|
"encryption_server_enter": "ป้อนชื่อโดเมน",
|
||||||
"encryption_redirect": "ไปเส้นทาง HTTPS อัตโนมัติ",
|
"encryption_redirect": "ไปเส้นทาง HTTPS อัตโนมัติ",
|
||||||
@@ -247,6 +407,8 @@
|
|||||||
"encryption_https_desc": "หากมีการกำหนดค่าพอร์ต HTTPS ส่วนติดต่อผู้ดูแลระบบของ AdGuard Home จะสามารถเข้าถึงได้ผ่าน HTTPS และจะให้ DNS-over-HTTPS ในตำแหน่ง '/dns-query'",
|
"encryption_https_desc": "หากมีการกำหนดค่าพอร์ต HTTPS ส่วนติดต่อผู้ดูแลระบบของ AdGuard Home จะสามารถเข้าถึงได้ผ่าน HTTPS และจะให้ DNS-over-HTTPS ในตำแหน่ง '/dns-query'",
|
||||||
"encryption_dot": "พอร์ต DNS-over-TLS",
|
"encryption_dot": "พอร์ต DNS-over-TLS",
|
||||||
"encryption_dot_desc": "หากมีการกำหนดค่าพอร์ตนี้ AdGuard Home จะเรียกใช้เซิร์ฟเวอร์ DNS-over-TLS ในพอร์ตนี้",
|
"encryption_dot_desc": "หากมีการกำหนดค่าพอร์ตนี้ AdGuard Home จะเรียกใช้เซิร์ฟเวอร์ DNS-over-TLS ในพอร์ตนี้",
|
||||||
|
"encryption_doq": "พอร์ต DNS-over-QUIC",
|
||||||
|
"encryption_doq_desc": "หากพอร์ตนี้ถูกกำหนดค่า AdGuard Home จะทำงานเซิร์ฟเวอร์ DNS-over-QUIC ที่พอร์ตนี้ และอาจจะยังไม่เชื่อถือได้ นอกจากนี้ยังมีผู้ใช้ที่ไม่มากนักที่รองรับในขณะนี้",
|
||||||
"encryption_certificates": "ใบรับรอง",
|
"encryption_certificates": "ใบรับรอง",
|
||||||
"encryption_certificates_desc": "ในการใช้การเข้ารหัสคุณต้องระบุเชนใบรับรอง SSL ที่ถูกต้องสำหรับโดเมนของคุณ คุณสามารถรับใบรับรองฟรีได้ที่ <0>{{link}}</0> หรือคุณสามารถซื้อได้จากหนึ่งในผู้ออกใบรับรองที่เชื่อถือได้",
|
"encryption_certificates_desc": "ในการใช้การเข้ารหัสคุณต้องระบุเชนใบรับรอง SSL ที่ถูกต้องสำหรับโดเมนของคุณ คุณสามารถรับใบรับรองฟรีได้ที่ <0>{{link}}</0> หรือคุณสามารถซื้อได้จากหนึ่งในผู้ออกใบรับรองที่เชื่อถือได้",
|
||||||
"encryption_certificates_input": "คัดลอก/วางใบรับรองที่เข้ารหัส PEM ของคุณที่นี่",
|
"encryption_certificates_input": "คัดลอก/วางใบรับรองที่เข้ารหัส PEM ของคุณที่นี่",
|
||||||
@@ -257,7 +419,7 @@
|
|||||||
"encryption_enable": "เปิดการเข้ารหัส (HTTPS, DNS-over-HTTPS, และ DNS-over-TLS)",
|
"encryption_enable": "เปิดการเข้ารหัส (HTTPS, DNS-over-HTTPS, และ DNS-over-TLS)",
|
||||||
"encryption_enable_desc": "หากเปิดใช้งานการเข้ารหัสอินเทอร์เฟซผู้ดูแลระบบของ AdGuard Home จะทำงานผ่าน HTTPS และเซิร์ฟเวอร์ DNS จะรับฟังคำร้องขอผ่านทาง DNS-over-HTTPS และ DNS-over-TLS",
|
"encryption_enable_desc": "หากเปิดใช้งานการเข้ารหัสอินเทอร์เฟซผู้ดูแลระบบของ AdGuard Home จะทำงานผ่าน HTTPS และเซิร์ฟเวอร์ DNS จะรับฟังคำร้องขอผ่านทาง DNS-over-HTTPS และ DNS-over-TLS",
|
||||||
"encryption_chain_valid": "ใบรับรองมีความน่าเชื่อถือ",
|
"encryption_chain_valid": "ใบรับรองมีความน่าเชื่อถือ",
|
||||||
"encryption_chain_invalid": "ใบรับรองไม่มีความน่าเชื่อถือแต่สามรถใช้ได้",
|
"encryption_chain_invalid": "ใบรับรองไม่มีความน่าเชื่อถือ",
|
||||||
"encryption_key_valid": "นี่เป็นคีย์ส่วนตัว {{type}} ที่ถูกต้อง",
|
"encryption_key_valid": "นี่เป็นคีย์ส่วนตัว {{type}} ที่ถูกต้อง",
|
||||||
"encryption_key_invalid": "นี่เป็นคีย์ส่วนตัว {{type}} ที่ไม่ถูกต้อง",
|
"encryption_key_invalid": "นี่เป็นคีย์ส่วนตัว {{type}} ที่ไม่ถูกต้อง",
|
||||||
"encryption_subject": "เรื่อง:",
|
"encryption_subject": "เรื่อง:",
|
||||||
@@ -265,12 +427,18 @@
|
|||||||
"encryption_hostnames": "ชื่อโฮส",
|
"encryption_hostnames": "ชื่อโฮส",
|
||||||
"encryption_reset": "คุณแน่ใจนะว่าจะล้างค่าการเข้ารหัส?",
|
"encryption_reset": "คุณแน่ใจนะว่าจะล้างค่าการเข้ารหัส?",
|
||||||
"encryption_warning": "คำเตือน",
|
"encryption_warning": "คำเตือน",
|
||||||
|
"encryption_plain_dns_enable": "เปิดใช้งาน DNS ธรรมดา",
|
||||||
|
"encryption_plain_dns_desc": "DNS แบบธรรมดาจะเปิดใช้งานตามค่าเริ่มต้น คุณสามารถปิดใช้งานเพื่อบังคับให้อุปกรณ์ทั้งหมดใช้ DNS ที่เข้ารหัสได้ หากต้องการทำเช่นนี้ คุณต้องเปิดใช้งานโปรโตคอล DNS ที่เข้ารหัสอย่างน้อยหนึ่งโปรโตคอล",
|
||||||
|
"encryption_plain_dns_error": "หากต้องการปิดใช้งาน DNS ธรรมดา ให้เปิดใช้งานโปรโตคอล DNS ที่เข้ารหัสอย่างน้อยหนึ่งรายการ",
|
||||||
"topline_expiring_certificate": "ใบรับรอง SSL ของคุณกำลังจะหมดอายุ กรุณาอัปเดท <0>การตั้งค่าเข้ารหัส</0>.",
|
"topline_expiring_certificate": "ใบรับรอง SSL ของคุณกำลังจะหมดอายุ กรุณาอัปเดท <0>การตั้งค่าเข้ารหัส</0>.",
|
||||||
"topline_expired_certificate": "ใบรับรอง SSL ของคุณหมดอายุแล้ว กรุณาอัปเดท <0>การตั้งค่าเข้ารหัส</0>.",
|
"topline_expired_certificate": "ใบรับรอง SSL ของคุณหมดอายุแล้ว กรุณาอัปเดท <0>การตั้งค่าเข้ารหัส</0>.",
|
||||||
|
"form_error_port_range": "ป้อนค่าพอร์ตในช่วง 80-65535",
|
||||||
"form_error_port_unsafe": "เป็นพอร์ทที่ไม่ปลอดภัย",
|
"form_error_port_unsafe": "เป็นพอร์ทที่ไม่ปลอดภัย",
|
||||||
|
"form_error_equal": "ไม่ควรตรงกัน",
|
||||||
"form_error_password": "รหัสผ่านไม่ตรงกัน",
|
"form_error_password": "รหัสผ่านไม่ตรงกัน",
|
||||||
"reset_settings": "รีเซ็ตการตั้งค่า",
|
"reset_settings": "รีเซ็ตการตั้งค่า",
|
||||||
"update_announcement": "AdGuard Home {{version}} พร้อมแล้ว <0>กดตรงนี้</0> สำหรับข้อมูลเพิ่มเติม",
|
"update_announcement": "AdGuard Home {{version}} พร้อมแล้ว <0>กดตรงนี้</0> สำหรับข้อมูลเพิ่มเติม",
|
||||||
|
"setup_guide": "วิธีการตั้งค่า",
|
||||||
"dns_addresses": "ที่อยู่ DNS",
|
"dns_addresses": "ที่อยู่ DNS",
|
||||||
"dns_start": "เซิร์ฟเวอร์ DNS เริ่มทำงาน",
|
"dns_start": "เซิร์ฟเวอร์ DNS เริ่มทำงาน",
|
||||||
"dns_status_error": "เกิดข้อผิดพลาดในการตรวจสอบสถานะเซิร์ฟเวอร์ DNS",
|
"dns_status_error": "เกิดข้อผิดพลาดในการตรวจสอบสถานะเซิร์ฟเวอร์ DNS",
|
||||||
@@ -279,9 +447,10 @@
|
|||||||
"dns_providers": "นี่คือรายการ <0>ของผู้ให้บริการ DNS ที่เป็นที่รู้จัก</0> ให้เลือก",
|
"dns_providers": "นี่คือรายการ <0>ของผู้ให้บริการ DNS ที่เป็นที่รู้จัก</0> ให้เลือก",
|
||||||
"update_now": "อัปเดตตอนนี้",
|
"update_now": "อัปเดตตอนนี้",
|
||||||
"update_failed": "อัปเดทล้มเหลว กรุณา <a> ทำตามขั้นตอน </a> เพื่ออัพเดทด้วยตนเอง",
|
"update_failed": "อัปเดทล้มเหลว กรุณา <a> ทำตามขั้นตอน </a> เพื่ออัพเดทด้วยตนเอง",
|
||||||
|
"manual_update": "อัปเดทล้มเหลว กรุณา <a> ทำตามขั้นตอน </a> เพื่ออัพเดทด้วยตนเอง",
|
||||||
"processing_update": "รอซักครู่ AdGuard Home กำลังอัปเดท",
|
"processing_update": "รอซักครู่ AdGuard Home กำลังอัปเดท",
|
||||||
"clients_title": "เครื่องลูกข่าย",
|
"clients_title": "เครื่องลูกข่าย",
|
||||||
"clients_desc": "ตั้งค่าอุปกรณ์เพื่อเชื่อมต่อ AdGuard Home",
|
"clients_desc": "ตั้งค่าอุปกรณ์ที่เชื่อมต่อกับ AdGuard Home",
|
||||||
"settings_global": "ทั่วโลก",
|
"settings_global": "ทั่วโลก",
|
||||||
"settings_custom": "กำหนดเอง",
|
"settings_custom": "กำหนดเอง",
|
||||||
"table_client": "เครื่องลูกข่าย",
|
"table_client": "เครื่องลูกข่าย",
|
||||||
@@ -292,31 +461,65 @@
|
|||||||
"client_edit": "แก้ไขเครื่องลูกข่าย",
|
"client_edit": "แก้ไขเครื่องลูกข่าย",
|
||||||
"client_identifier": "ตรวจสอบโดย",
|
"client_identifier": "ตรวจสอบโดย",
|
||||||
"ip_address": "IP addresses",
|
"ip_address": "IP addresses",
|
||||||
|
"client_identifier_desc": "ลูกค้าสามารถระบุได้โดยที่อยู่ IP, CIDR, ที่อยู่ MAC โปรดทราบว่าการใช้ MAC เป็นตัวระบุเป็นไปได้ก็ต่อเมื่อ AdGuard Home เป็น <0>เซิร์ฟเวอร์ DHCP</0> ด้วย",
|
||||||
"form_enter_ip": "กรอก IP",
|
"form_enter_ip": "กรอก IP",
|
||||||
|
"form_enter_subnet_ip": "กรอกที่อยู่ IP ในซับเน็ต \"{{cidr}}\"",
|
||||||
"form_enter_mac": "กรอก MAC",
|
"form_enter_mac": "กรอก MAC",
|
||||||
"form_enter_id": "ป้อนตัวระบุ",
|
"form_enter_id": "ป้อนตัวระบุ",
|
||||||
"form_add_id": "เพิ่มตัวระบุ",
|
"form_add_id": "เพิ่มตัวระบุ",
|
||||||
"form_client_name": "กรอกชื่อเครื่องลูกข่าย",
|
"form_client_name": "กรอกชื่อเครื่องลูกข่าย",
|
||||||
|
"name": "ชื่อ",
|
||||||
|
"client_name": "ลูกค้า {{id}}",
|
||||||
"client_global_settings": "ใช้การตั้งค่าทั่วโลก",
|
"client_global_settings": "ใช้การตั้งค่าทั่วโลก",
|
||||||
"client_deleted": "เครื่อง \"{{key}}\" ลบเรียบร้อยแล้ว",
|
"client_deleted": "เครื่อง \"{{key}}\" ลบเรียบร้อยแล้ว",
|
||||||
"client_added": "เครื่อง \"{{key}}\" เพิ่มเรียบร้อยแล้ว",
|
"client_added": "เครื่อง \"{{key}}\" เพิ่มเรียบร้อยแล้ว",
|
||||||
"client_updated": "อัปเดตเครื่อง \"{{key}}\" สำเร็จแล้ว",
|
"client_updated": "อัปเดตเครื่อง \"{{key}}\" สำเร็จแล้ว",
|
||||||
"clients_not_found": "ไม่มีเครื่องลูกข่าย",
|
"clients_not_found": "ไม่มีเครื่องลูกข่าย",
|
||||||
"client_confirm_delete": "คุณแน่ใจนะว่าจะลบเครื่อง \"{{key}}\"?",
|
"client_confirm_delete": "คุณแน่ใจนะว่าจะลบเครื่อง \"{{key}}\"?",
|
||||||
|
"list_confirm_delete": "แน่ใจไหมว่าต้องการลบรายการนี้?",
|
||||||
"auto_clients_title": "เครื่อง (runtime)",
|
"auto_clients_title": "เครื่อง (runtime)",
|
||||||
"auto_clients_desc": "ข้อมูลเกี่ยวกับไคลเอนต์ที่ใช้ AdGuard Home แต่ไม่ได้เก็บไว้ในการกำหนดค่า",
|
"auto_clients_desc": "ข้อมูลเกี่ยวกับที่อยู่ IP ของอุปกรณ์ที่ใช้หรืออาจใช้ AdGuard Home ข้อมูลนี้ถูกรวบรวมจากหลายแหล่งรวมถึงไฟล์โฮสต์, DNS ย้อนกลับ ฯลฯ",
|
||||||
"access_title": "เข้าถึงการตั้งค่า",
|
"access_title": "เข้าถึงการตั้งค่า",
|
||||||
"access_desc": "ที่นี่คุณสามารถกำหนดค่ากฎการเข้าถึงสำหรับเซิร์ฟเวอร์ AdGuard Home DNS",
|
"access_desc": "ที่นี่คุณสามารถกำหนดค่ากฎการเข้าถึงสำหรับเซิร์ฟเวอร์ AdGuard Home DNS",
|
||||||
"access_allowed_title": "ลูกค้าที่ได้รับอนุญาต",
|
"access_allowed_title": "ลูกค้าที่ได้รับอนุญาต",
|
||||||
"access_allowed_desc": "รายการ CIDR หรือที่อยู่ IP หากกำหนดค่า AdGuard Home จะยอมรับคำขอจากที่อยู่ IP เหล่านี้เท่านั้น",
|
"access_allowed_desc": "รายการ CIDR หรือที่อยู่ IP หากมีการตั้งค่าไว้ AdGuard Home จะยอมรับคำขอจากที่อยู่ IP เหล่านี้เท่านั้น",
|
||||||
"access_disallowed_title": "ลูกค้าไม่ได้รับอนุญาต",
|
"access_disallowed_title": "ลูกค้าไม่ได้รับอนุญาต",
|
||||||
"access_disallowed_desc": "รายการ CIDR หรือที่อยู่ IP หากกำหนดค่าไว้ AdGuard Home จะส่งคำขอจากที่อยู่ IP เหล่านี้",
|
"access_disallowed_desc": "รายการ CIDR หรือที่อยู่ IP ถ้าหากมีการตั้งค่าไว้ AdGuard Home จะยกเลิกคำขอจากที่อยู่ IP เหล่านี้ หากมีรายการใน Allowed clients จะไม่มีการพิจารณาฟิลด์นี้.",
|
||||||
"access_blocked_title": "โดเมนที่ถูกปิดกั้น",
|
"access_blocked_title": "โดเมนที่ถูกปิดกั้น",
|
||||||
|
"access_blocked_desc": "อย่าสับสนกับตัวกรอง AdGuard Home จะลบคำขอ DNS ที่ตรงกับโดเมนเหล่านี้ และคำขอเหล่านี้จะไม่ปรากฏในบันทึกคำขอด้วยซ้ำ คุณสามารถระบุชื่อโดเมน ไวล์ดการ์ด หรือกฎตัวกรอง URL ได้ เช่น \"example.org\" \"*.example.org\" หรือ \"||example.org^\" ตามลำดับ",
|
||||||
|
"access_settings_saved": "บันทึกการตั้งค่าการเข้าถึงเรียบร้อยแล้ว",
|
||||||
|
"updates_version_equal": "AdGuard Home เป็นตัวล่าสุดแล้ว",
|
||||||
"check_updates_now": "ตรวจสอบการปรับปรุง",
|
"check_updates_now": "ตรวจสอบการปรับปรุง",
|
||||||
|
"version_request_error": "การตรวจสอบการอัปเดตล้มเหลว โปรดตรวจสอบการเชื่อมต่ออินเทอร์เน็ตของคุณ",
|
||||||
|
"dns_privacy": "ความเป็นส่วนตัวของ DNS",
|
||||||
|
"setup_dns_privacy_1": "<0>DNS-over-TLS</0> ใช้ที่อยู่ <1>{{address}}</1>",
|
||||||
|
"setup_dns_privacy_2": "<0>DNS-over-HTTPS</0> ใช้ที่อยู่ <1>{{address}}</1>",
|
||||||
|
"setup_dns_privacy_3": "<0>นี่คือรายการซอฟต์แวร์ที่คุณสามารถใช้ได้</0>",
|
||||||
|
"setup_dns_privacy_4": "บนอุปกรณ์ iOS 14 หรือ macOS Big Sur คุณสามารถดาวน์โหลดไฟล์พิเศษ '.mobileconfig' ที่จะเพิ่มเซิร์ฟเวอร์ <highlight>DNS-over-HTTPS</highlight> หรือ <highlight>DNS-over-TLS</highlight> ลงในการตั้งค่า DNS",
|
||||||
|
"setup_dns_privacy_android_1": "Android 9 รองรับ DNS-over-TLS โดยตรง หากต้องการกำหนดค่า ให้ไปที่การตั้งค่า → เครือข่ายและอินเทอร์เน็ต → ขั้นสูง → DNS ส่วนตัว และป้อนชื่อโดเมนของคุณที่นั่น",
|
||||||
|
"setup_dns_privacy_android_2": "<0>AdGuard สำหรับ Android</0> รองรับ <1>DNS-over-HTTPS</1> และ <1>DNS-over-TLS</1> -",
|
||||||
|
"setup_dns_privacy_android_3": "<0>ภายใน</0> เพิ่ม <1>DNS-over-HTTPS</1> รองรับระบบ Android",
|
||||||
|
"setup_dns_privacy_ios_1": "<0>DNS โคลก</0> รองรับ <1>DNS-over-HTTPS</1> แต่เพื่อกำหนดค่าให้ใช้เซิร์ฟเวอร์ของคุณเอง คุณจะต้องสร้าง <2>DNS Stamp</2> สำหรับมัน",
|
||||||
|
"setup_dns_privacy_ios_2": "<0>AdGuard สำหรับ iOS</0> รองรับ <1>DNS-over-HTTPS</1> และ <1>DNS-over-TLS</1> การตั้งค่า",
|
||||||
"setup_dns_privacy_other_title": "การใช้งานอื่น ๆ",
|
"setup_dns_privacy_other_title": "การใช้งานอื่น ๆ",
|
||||||
"setup_dns_privacy_other_1": "AdGuard Home จะส่ง DNS ที่ปลอดภัยทุกเครื่อทุกระบบ\n",
|
"setup_dns_privacy_other_1": "AdGuard Home จะส่ง DNS ที่ปลอดภัยทุกเครื่อทุกระบบ\n",
|
||||||
"setup_dns_privacy_other_2": "<0>dnsproxy</0> รองรับโปรโตคอล DNS ที่ปลอดภัยที่รู้จักทั้งหมด",
|
"setup_dns_privacy_other_2": "<0>dnsproxy</0> รองรับโปรโตคอล DNS ที่ปลอดภัยที่รู้จักทั้งหมด",
|
||||||
|
"setup_dns_privacy_other_3": "<0>พร็อกซี DNScrypt</0> รองรับ <1>DNS-over-HTTPS</1> -",
|
||||||
|
"setup_dns_privacy_other_4": "<0>โมซิลล่า ไฟร์ฟอกซ์</0> รองรับ <1>DNS-over-HTTPS</1> -",
|
||||||
|
"setup_dns_privacy_other_5": "คุณจะพบการใช้งานเพิ่มเติมได้<0>ที่นี่</0> และ <1>ที่นี่</1> -",
|
||||||
|
"setup_dns_privacy_ioc_mac": "การกำหนดค่า iOS และ macOS",
|
||||||
|
"setup_dns_notice": "เพื่อใช้ <1>DNS-over-HTTPS</1> หรือ <1>DNS-over-TLS</1> คุณต้อง<0>กำหนดค่าการเข้ารหัส</0> ในการตั้งค่า AdGuard Home",
|
||||||
|
"rewrite_added": "เพิ่มการเขียน DNS ใหม่สำหรับ \"{{key}}\" สำเร็จแล้ว",
|
||||||
|
"rewrite_deleted": "ลบการเขียน DNS ใหม่สำหรับ \"{{key}}\" สำเร็จแล้ว",
|
||||||
|
"rewrite_updated": "อัปเดตการเขียน DNS ใหม่สำเร็จแล้ว",
|
||||||
"rewrite_add": "เพิ่ม DNS rewrite",
|
"rewrite_add": "เพิ่ม DNS rewrite",
|
||||||
|
"rewrite_edit": "แก้ไขการเขียน DNS ใหม่",
|
||||||
|
"rewrite_not_found": "ไม่พบการเขียน DNS ใหม่",
|
||||||
|
"rewrite_confirm_delete": "คุณแน่ใจหรือไม่ว่าต้องการลบการเขียน DNS ใหม่สำหรับ \"{{key}}\"",
|
||||||
|
"rewrite_desc": "ช่วยให้สามารถกำหนดค่าการตอบสนอง DNS แบบกำหนดเองสำหรับชื่อโดเมนเฉพาะได้อย่างง่ายดาย",
|
||||||
|
"rewrite_applied": "กฎการเขียนใหม่ถูกนำมาใช้",
|
||||||
|
"rewrite_hosts_applied": "เขียนใหม่โดยกฎไฟล์โฮสต์",
|
||||||
|
"dns_rewrites": "การเขียน DNS ใหม่",
|
||||||
"form_domain": "ป้อนชื่อโดเมน",
|
"form_domain": "ป้อนชื่อโดเมน",
|
||||||
"form_answer": "ป้อนชื่อโดเมนหรือ IP",
|
"form_answer": "ป้อนชื่อโดเมนหรือ IP",
|
||||||
"form_error_domain_format": "รูปแบบ Domain ไม่ถูกต้อง",
|
"form_error_domain_format": "รูปแบบ Domain ไม่ถูกต้อง",
|
||||||
@@ -344,21 +547,29 @@
|
|||||||
"interval_days": "{{count}} วัน",
|
"interval_days": "{{count}} วัน",
|
||||||
"interval_days_plural": "{{count}} วัน",
|
"interval_days_plural": "{{count}} วัน",
|
||||||
"domain": "โดเมน",
|
"domain": "โดเมน",
|
||||||
|
"ecs": "อีซีเอส",
|
||||||
|
"punycode": "Punycode",
|
||||||
"answer": "คำตอบ",
|
"answer": "คำตอบ",
|
||||||
"filter_added_successfully": "ตัวกรองเพิ่มเรียบร้อยแล้ว",
|
"filter_added_successfully": "ตัวกรองเพิ่มเรียบร้อยแล้ว",
|
||||||
|
"filter_removed_successfully": "รายการถูกลบเรียบร้อยแล้ว",
|
||||||
"filter_updated": "อัปเดตตัวกรองสำเร็จแล้ว",
|
"filter_updated": "อัปเดตตัวกรองสำเร็จแล้ว",
|
||||||
"statistics_configuration": "การกำหนดค่าสถิติ",
|
"statistics_configuration": "การกำหนดค่าสถิติ",
|
||||||
"statistics_retention": "การเก็บรักษาสถิติ",
|
"statistics_retention": "การเก็บรักษาสถิติ",
|
||||||
"statistics_retention_desc": "หากคุณลดค่าช่วงเวลาข้อมูลบางอย่างจะหายไป",
|
"statistics_retention_desc": "หากคุณลดค่าช่วงเวลาข้อมูลบางอย่างจะหายไป",
|
||||||
"statistics_clear": "ล้างสถิติ",
|
"statistics_clear": " ล้างค่าสถิติ",
|
||||||
"statistics_clear_confirm": "คุณแน่ใจหรือไม่ว่าต้องการล้างสถิติ?",
|
"statistics_clear_confirm": "คุณแน่ใจหรือไม่ว่าต้องการล้างสถิติ?",
|
||||||
"statistics_retention_confirm": "คุณแน่ใจหรือไม่ว่าต้องการเปลี่ยนการเก็บรักษาสถิติ? หากคุณลดค่าช่วงเวลา ข้อมูลบางอย่างจะหายไป",
|
"statistics_retention_confirm": "คุณแน่ใจหรือไม่ว่าต้องการเปลี่ยนการเก็บรักษาสถิติ? หากคุณลดค่าช่วงเวลา ข้อมูลบางอย่างจะหายไป",
|
||||||
"statistics_cleared": "สถิติได้ถูกล้างเรียบร้อยแล้ว",
|
"statistics_cleared": "สถิติได้ถูกล้างเรียบร้อยแล้ว",
|
||||||
|
"statistics_enable": "เปิดใช้งานสถิติ",
|
||||||
|
"ignore_domains": "โดเมนที่ถูกละเว้น (แยกด้วยการขึ้นบรรทัดใหม่)",
|
||||||
|
"ignore_domains_title": "โดเมนที่ถูกละเว้น",
|
||||||
|
"ignore_domains_desc_stats": "คำค้นที่ตรงกับกฎเหล่านี้จะไม่ถูกเขียนลงในสถิติ",
|
||||||
|
"ignore_domains_desc_query": "คำค้นที่ตรงกับกฎเหล่านี้จะไม่ถูกเขียนลงในบันทึกคำค้น",
|
||||||
"interval_hours": "{{count}} ชั่วโมง",
|
"interval_hours": "{{count}} ชั่วโมง",
|
||||||
"interval_hours_plural": "{{count}} ชั่วโมง",
|
"interval_hours_plural": "{{count}} ชั่วโมง",
|
||||||
"filters_configuration": "การกำหนดค่าตัวกรอง",
|
"filters_configuration": "การกำหนดค่าตัวกรอง",
|
||||||
"filters_enable": "เปิดใช้งานตัวกรอง",
|
"filters_enable": "เปิดใช้งานตัวกรอง",
|
||||||
"filters_interval": "ตัวกรองช่วงเวลาการอัปเดต",
|
"filters_interval": "ช่วงเวลาการอัปเดตตัวกรอง",
|
||||||
"disabled": "ปิดใช้งาน",
|
"disabled": "ปิดใช้งาน",
|
||||||
"username_label": "ชื่อผู้ใช้",
|
"username_label": "ชื่อผู้ใช้",
|
||||||
"username_placeholder": "ป้อนชื่อผู้ใช้",
|
"username_placeholder": "ป้อนชื่อผู้ใช้",
|
||||||
@@ -376,12 +587,19 @@
|
|||||||
"whois": "Whois",
|
"whois": "Whois",
|
||||||
"filtering_rules_learn_more": "<0>เรียนรู้เพิ่มเติม</0> เกี่ยวกับการสร้างรายการปิดกั้นโฮสต์ของคุณเอง",
|
"filtering_rules_learn_more": "<0>เรียนรู้เพิ่มเติม</0> เกี่ยวกับการสร้างรายการปิดกั้นโฮสต์ของคุณเอง",
|
||||||
"blocked_by_response": "ปิดกั้นโดย CNAME หรือ IP ในการตอบกลับ",
|
"blocked_by_response": "ปิดกั้นโดย CNAME หรือ IP ในการตอบกลับ",
|
||||||
|
"blocked_by_cname_or_ip": "บล็อกโดย CNAME หรือ IP",
|
||||||
"try_again": "ลองอีกครั้ง",
|
"try_again": "ลองอีกครั้ง",
|
||||||
"domain_desc": "ป้อนชื่อโดเมนหรือไวด์การ์ดที่คุณต้องการเขียนใหม่",
|
"domain_desc": "ป้อนชื่อโดเมนหรือไวด์การ์ดที่คุณต้องการเขียนใหม่",
|
||||||
"example_rewrite_domain": "เขียนคำตอบซ้ำสำหรับชื่อโดเมนนี้เท่านั้น",
|
"example_rewrite_domain": "เขียนคำตอบซ้ำสำหรับชื่อโดเมนนี้เท่านั้น",
|
||||||
"example_rewrite_wildcard": "เขียนคำตอบใหม่ทั้งหมดสำหรับ <0>example.org</0> โดเมนย่อย",
|
"example_rewrite_wildcard": "เขียนคำตอบใหม่ทั้งหมดสำหรับ <0>example.org</0> โดเมนย่อย",
|
||||||
|
"rewrite_ip_address": "ที่อยู่ IP: ใช้ IP นี้ในการตอบสนอง A หรือ AAAA",
|
||||||
|
"rewrite_domain_name": "ชื่อโดเมน: เพิ่มระเบียน CNAME",
|
||||||
|
"rewrite_A": "<0>A</0>: ค่าเฉพาะ, เก็บ <0>A</0> บันทึกจาก upstream",
|
||||||
|
"rewrite_AAAA": "<0>AAAA</0>: ค่าเฉพาะ, เก็บ <0>AAAA</0> บันทึกจาก upstream",
|
||||||
"disable_ipv6": "ปิดใช้งาน IPv6",
|
"disable_ipv6": "ปิดใช้งาน IPv6",
|
||||||
"disable_ipv6_desc": "หากเปิดใช้งานคุณสมบัตินี้การสืบค้น DNS ทั้งหมดสำหรับที่อยู่ IPv6 (ประเภท AAAA) จะถูกทิ้ง",
|
"disable_ipv6_desc": "หากเปิดใช้งานคุณสมบัตินี้การสืบค้น DNS ทั้งหมดสำหรับที่อยู่ IPv6 (ประเภท AAAA) จะถูกทิ้ง",
|
||||||
|
"fastest_addr": "ที่อยู่ IP ที่เร็วที่สุด",
|
||||||
|
"fastest_addr_desc": "รอการตอบกลับจาก <b>ทั้งหมด</b> เซิร์ฟเวอร์ DNS, วัดความเร็วการเชื่อมต่อ TCP สำหรับแต่ละเซิร์ฟเวอร์, และคืนค่าที่อยู่ IP ของเซิร์ฟเวอร์ที่มีความเร็วการเชื่อมต่อเร็วที่สุด.<br/>โหมดนี้อาจทำให้การค้นหา DNS ช้าลงอย่างมีนัยสำคัญหากหนึ่งหรือหลายเซิร์ฟเวอร์ต้นทางไม่ได้ตอบกลับ ตรวจสอบให้แน่ใจว่าเซิร์ฟเวอร์ต้นทางของคุณมีเสถียรภาพและเวลาตอบกลับของคุณต่ำ.",
|
||||||
"autofix_warning_text": "หากคุณคลิก \"แก้ไข\" AdGuardHome จะกำหนดค่าระบบของคุณเพื่อใช้เซิร์ฟเวอร์ AdGuardHome",
|
"autofix_warning_text": "หากคุณคลิก \"แก้ไข\" AdGuardHome จะกำหนดค่าระบบของคุณเพื่อใช้เซิร์ฟเวอร์ AdGuardHome",
|
||||||
"autofix_warning_list": "มันจะทำงานเหล่านี้: <0>ปิดการใช้งานระบบ DNSStubListener</0> <0>ตั้งที่อยู่เซิร์ฟเวอร์ DNS เป็น 127.0.0.1</0> <0>แทนที่เป้าหมายลิงก์สัญลักษณ์ของ /etc/resolv.conf เป็น /run/systemd/resolve/resolv.conf</0> <0>หยุด DNSStubListener (โหลดบริการแก้ไขระบบซ้ำ)</0>",
|
"autofix_warning_list": "มันจะทำงานเหล่านี้: <0>ปิดการใช้งานระบบ DNSStubListener</0> <0>ตั้งที่อยู่เซิร์ฟเวอร์ DNS เป็น 127.0.0.1</0> <0>แทนที่เป้าหมายลิงก์สัญลักษณ์ของ /etc/resolv.conf เป็น /run/systemd/resolve/resolv.conf</0> <0>หยุด DNSStubListener (โหลดบริการแก้ไขระบบซ้ำ)</0>",
|
||||||
"autofix_warning_result": "ดังนั้น AdGuardHome จะประมวลผลคำขอ DNS ทั้งหมดจากระบบของคุณตามค่าเริ่มต้น",
|
"autofix_warning_result": "ดังนั้น AdGuardHome จะประมวลผลคำขอ DNS ทั้งหมดจากระบบของคุณตามค่าเริ่มต้น",
|
||||||
@@ -390,21 +608,145 @@
|
|||||||
"form_select_tags": "เลือกแท็กเครื่อง",
|
"form_select_tags": "เลือกแท็กเครื่อง",
|
||||||
"check_title": "ตรวจสอบการกรอง",
|
"check_title": "ตรวจสอบการกรอง",
|
||||||
"check_desc": "ตรวจสอบว่าชื่อโฮสต์ถูกกรอง",
|
"check_desc": "ตรวจสอบว่าชื่อโฮสต์ถูกกรอง",
|
||||||
|
"check": "ตรวจสอบ",
|
||||||
"form_enter_host": "ป้อนชื่อโฮสต์",
|
"form_enter_host": "ป้อนชื่อโฮสต์",
|
||||||
|
"filtered_custom_rules": "ถูกกรองโดยกฎการกรองที่กำหนดเอง",
|
||||||
|
"choose_from_list": "เลือกจากรายการ",
|
||||||
|
"add_custom_list": "เพิ่มรายการที่กำหนดเอง",
|
||||||
|
"host_whitelisted": "โฮสต์ได้รับอนุญาต",
|
||||||
|
"check_ip": "IP addresses: {{ip}}",
|
||||||
|
"check_cname": "CNAME: {{cname}}",
|
||||||
|
"check_reason": "เหตุผล: {{reason}}",
|
||||||
|
"check_service": "ชื่อบริการ: {{service}}",
|
||||||
|
"check_hostname": "ชื่อโฮสต์หรือชื่อโดเมน",
|
||||||
|
"check_client_id": "ตัวระบุไคลเอนต์ (ClientID หรือ ที่อยู่ IP)",
|
||||||
|
"check_enter_client_id": "ป้อนตัวระบุคล้าย",
|
||||||
|
"check_dns_record": "เลือกประเภทระเบียน DNS",
|
||||||
|
"service_name": "ชื่อบริการ",
|
||||||
|
"check_not_found": "ไม่พบในรายการตัวกรองของคุณ",
|
||||||
|
"client_confirm_block": "คุณแน่ใจนะว่าจะบล็อกเครื่อง \"{{ip}}\"?",
|
||||||
|
"client_confirm_unblock": "คุณแน่ใจนะว่าจะยกเลิกบล็อกเครื่อง \"{{ip}}\"?",
|
||||||
|
"client_blocked": "บล็อกเครื่อง \"{{ip}}\" สำเร็จแล้ว",
|
||||||
|
"client_unblocked": "ยกเลิกบล็อกเครื่อง \"{{ip}}\" สำเร็จแล้ว",
|
||||||
|
"static_ip": "ที่อยู่ IP แบบคงที่",
|
||||||
|
"static_ip_desc": "AdGuard Home เป็นเซิร์ฟเวอร์ดังนั้นจึงต้องการที่อยู่ IP แบบคงที่เพื่อให้ทำงานได้อย่างถูกต้อง มิฉะนั้นในบางครั้งเราเตอร์ของคุณอาจกำหนดที่อยู่ IP อื่นให้กับอุปกรณ์นี้",
|
||||||
|
"set_static_ip": "ตั้งค่าที่อยู่ IP แบบคงที่",
|
||||||
|
"install_static_ok": "ข่าวดี! ที่อยู่ IP คงที่ได้ถูกกำหนดค่าแล้ว",
|
||||||
|
"install_static_error": "AdGuard Home ไม่สามารถกำหนดค่าโดยอัตโนมัติสำหรับอินเตอร์เฟซเครือข่ายนี้ได้ กรุณาหาเอกสารในการทำขั้นตอนนี้ด้วยตนเอง.",
|
||||||
|
"install_static_configure": "AdGuard Home ตรวจพบว่าใช้ที่อยู่ IP แบบไดนามิก <0>{{ip}}</0> คุณต้องการให้ตั้งเป็นที่อยู่ IP คงที่ของคุณหรือไม่?",
|
||||||
|
"confirm_static_ip": "AdGuard Home จะกำหนด {{ip}} เป็นที่อยู่ IP คงที่ของคุณ คุณต้องการดำเนินการต่อหรือไม่?",
|
||||||
|
"list_updated": "{{count}} รายการได้รับการอัปเดต",
|
||||||
|
"list_updated_plural": "{{count}} รายการอัปเดต",
|
||||||
|
"dnssec_enable": "เปิดใช้ DNSSEC",
|
||||||
|
"dnssec_enable_desc": "ตั้งค่าสถานะ DNSSEC ในการสืบค้น DNS ขาออกและตรวจสอบผลลัพธ์ (ต้องใช้ตัวแก้ไขที่เปิดใช้ DNSSEC)",
|
||||||
|
"validated_with_dnssec": "ตรวจสอบกับ DNSSEC",
|
||||||
|
"all_queries": "ทุกการสอบถาม",
|
||||||
"show_blocked_responses": "ปิดกั้นแล้ว",
|
"show_blocked_responses": "ปิดกั้นแล้ว",
|
||||||
"show_whitelisted_responses": "รายการที่อนุญาต",
|
"show_whitelisted_responses": "รายการที่อนุญาต",
|
||||||
"show_processed_responses": "ประมวลผลแล้ว",
|
"show_processed_responses": "ประมวลผลแล้ว",
|
||||||
|
"blocked_safebrowsing": "ถูกบล็อกโดยการค้นหาที่ปลอดภัย",
|
||||||
"blocked_adult_websites": "ถูกปิดกั้นโดยการควบคุมของผู้ปกครอง",
|
"blocked_adult_websites": "ถูกปิดกั้นโดยการควบคุมของผู้ปกครอง",
|
||||||
"safe_search": "ค้นหาอย่างปลอดภัย",
|
"blocked_threats": "ภัยคุกคามที่ถูกบล็อก",
|
||||||
"blocklist": "บัญชีดำ",
|
|
||||||
"allowed": "รายการที่อนุญาต",
|
"allowed": "รายการที่อนุญาต",
|
||||||
|
"filtered": "ถูกกรอง",
|
||||||
|
"rewritten": "เขียนใหม่",
|
||||||
|
"safe_search": "ค้นหาอย่างปลอดภัย",
|
||||||
|
"blocklist": "บัญชีดำของระบบ",
|
||||||
|
"milliseconds_abbreviation": "ms",
|
||||||
|
"cache_size": "ขนาดแคช",
|
||||||
|
"cache_size_desc": "ขนาดแคช DNS (ในไบต์). เพื่อปิดการตั้งค่าแคช, ตั้งค่าเป็น 0.",
|
||||||
|
"cache_ttl_min_override": "ไม่มีการกำหนดค่า TTL ขั้นต่ำ",
|
||||||
|
"cache_ttl_max_override": "ไม่มีการกำหนดค่า TTL สูงสุด",
|
||||||
|
"enter_cache_size": "ป้อนขนาดแคช (ไบต์)",
|
||||||
|
"enter_cache_ttl_min_override": "ป้อน TTL ขั้นต่ำ (วินาที)",
|
||||||
|
"enter_cache_ttl_max_override": "ป้อน TTL สูงสุด (วินาที)",
|
||||||
|
"cache_ttl_min_override_desc": "ขยายค่าเวลาที่สั้น (วินาที) ที่ได้รับจากเซิร์ฟเวอร์ upstream เมื่อแคชตอบสนอง DNS",
|
||||||
|
"cache_ttl_max_override_desc": "ตั้งค่าค่าระยะเวลาการมีชีวิตสูงสุด (วินาที) สำหรับคำแนะนำในแคช DNS",
|
||||||
|
"ttl_cache_validation": "ค่าการเขียนทับ TTL ของแคชขั้นต่ำจะต้องน้อยกว่าหรือเท่ากับค่าสูงสุด",
|
||||||
|
"cache_optimistic": "การเก็บข้อมูลแบบมีความหวัง",
|
||||||
|
"cache_optimistic_desc": "ทำให้ AdGuard Home ตอบกลับจากแคช แม้เมื่อข้อมูลหมดอายุแล้ว และยังลองรีเฟรชข้อมูลด้วย.",
|
||||||
|
"filter_category_general": "ทั่วไป",
|
||||||
|
"filter_category_security": "ความปลอดภัย",
|
||||||
|
"filter_category_regional": "ภูมิภาค",
|
||||||
"filter_category_other": "อื่น ๆ",
|
"filter_category_other": "อื่น ๆ",
|
||||||
|
"filter_category_general_desc": "รายการที่ปิดกั้นการติดตามและโฆษณาบนอุปกรณ์ส่วนใหญ่",
|
||||||
|
"filter_category_security_desc": "รายการที่ออกแบบมาเพื่อปิดกั้นโดเมนที่เป็นอันตราย ฟิชชิ่ง และโดเมนหลอกลวง",
|
||||||
|
"filter_category_regional_desc": "รายการที่เน้นโฆษณาระดับภูมิภาคและเซิร์ฟเวอร์ตัวติดตาม",
|
||||||
|
"filter_category_other_desc": "รายการปิดกั้นอื่น ๆ",
|
||||||
|
"setup_config_to_enable_dhcp_server": "ตั้งค่าคอนฟิกเพื่อเปิดใช้งานเซิร์ฟเวอร์ DHCP",
|
||||||
|
"original_response": "ตอบกลับเดิม",
|
||||||
|
"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}}\" จะปิดการใช้งานรายการ \"ไคลเอนต์ที่อนุญาต\"",
|
||||||
|
"use_saved_key": "ใช้คีย์ที่บันทึกไว้ก่อนหน้านี้",
|
||||||
"parental_control": "ควบคุมโดยผู้ปกครอง",
|
"parental_control": "ควบคุมโดยผู้ปกครอง",
|
||||||
|
"safe_browsing": "ท่องเว็บอย่างปลอดภัย",
|
||||||
|
"served_from_cache_label": "เสิร์ฟจากแคช",
|
||||||
|
"form_error_password_length": "รหัสผ่านต้องมีความยาว {{min}} ถึง {{max}} อักขระ",
|
||||||
|
"anonymizer_notification": "<0>หมายเหตุ:</0> เปิดใช้งานการไม่ระบุตัวตนของ IP แล้ว คุณสามารถปิดใช้งานได้ใน <1>การตั้งค่าทั่วไป</1> -",
|
||||||
|
"confirm_dns_cache_clear": "คุณแน่ใจหรือไม่ว่าต้องการล้างแคช DNS?",
|
||||||
|
"cache_cleared": "ล้างแคช DNS สำเร็จแล้ว",
|
||||||
|
"clear_cache": "ล้างแคช",
|
||||||
|
"make_static": "ทำให้คงที่",
|
||||||
|
"theme_auto_desc": "อัตโนมัติ (ขึ้นอยู่กับโทนสีของอุปกรณ์ของคุณ)",
|
||||||
|
"theme_dark_desc": "ธีมสีเข้ม",
|
||||||
|
"theme_light_desc": "ธีมสีอ่อน",
|
||||||
|
"disable_for_seconds": "เป็นเวลา {{count}} วินาที",
|
||||||
|
"disable_for_seconds_plural": "เป็นเวลา {{count}} วินาที",
|
||||||
|
"disable_for_minutes": "เป็นเวลา {{count}} นาที",
|
||||||
|
"disable_for_minutes_plural": "เป็นเวลา {{count}} นาที",
|
||||||
|
"disable_for_hours": "เป็นเวลา {{count}} ชั่วโมง",
|
||||||
|
"disable_for_hours_plural": "เป็นเวลา {{count}} ชั่วโมง",
|
||||||
|
"disable_until_tomorrow": "จนกว่าจะถึงวันพรุ่งนี้",
|
||||||
|
"disable_notify_for_seconds": "ปิดใช้งานการป้องกันเป็นเวลา {{count}} วินาที",
|
||||||
|
"disable_notify_for_seconds_plural": "ปิดใช้งานการป้องกันเป็นเวลา {{count}} วินาที",
|
||||||
|
"disable_notify_for_minutes": "ปิดใช้งานการป้องกันเป็นเวลา {{count}} นาที",
|
||||||
|
"disable_notify_for_minutes_plural": "ปิดใช้งานการป้องกันเป็นเวลา {{count}} นาที",
|
||||||
|
"disable_notify_for_hours": "ปิดใช้งานการป้องกันเป็นเวลา {{count}} ชั่วโมง",
|
||||||
|
"disable_notify_for_hours_plural": "ปิดใช้งานการป้องกันเป็นเวลา {{count}} ชั่วโมง",
|
||||||
|
"disable_notify_until_tomorrow": "ปิดการป้องกันจนถึงพรุ่งนี้",
|
||||||
|
"enable_protection_timer": "การป้องกันจะเปิดใช้งานใน {{time}}",
|
||||||
|
"custom_retention_input": "ป้อนการเก็บรักษาเป็นชั่วโมง",
|
||||||
|
"custom_rotation_input": "ป้อนการหมุนรอบเป็นชั่วโมง",
|
||||||
|
"protection_section_label": "การป้องกัน",
|
||||||
|
"log_and_stats_section_label": "บันทึกการสอบถามและสถิติ",
|
||||||
|
"ignore_query_log": "ละเว้นไคลเอนต์นี้ในบันทึกการค้นหา",
|
||||||
|
"ignore_statistics": "ละเว้นไคลเอนต์นี้ในสถิติ",
|
||||||
|
"schedule_services": "หยุดการบล็อคบริการ",
|
||||||
|
"schedule_services_desc": "กำหนดค่ากำหนดการหยุดชั่วคราวของตัวกรองการบล็อคบริการ",
|
||||||
|
"schedule_services_desc_client": "กำหนดค่ากำหนดการหยุดชั่วคราวของตัวกรองการบล็อคบริการสำหรับไคลเอนต์นี้",
|
||||||
|
"schedule_desc": "ตั้งค่าระยะเวลาที่ไม่มีกิจกรรมสำหรับบริการที่ถูกบล็อค",
|
||||||
|
"schedule_invalid_select": "เวลาเริ่มต้นต้องอยู่ก่อนเวลาสิ้นสุด",
|
||||||
|
"schedule_select_days": "เลือกวัน",
|
||||||
|
"schedule_timezone": "เลือกโซนเวลา",
|
||||||
|
"schedule_current_timezone": "เขตเวลาปัจจุบัน: {{value}}",
|
||||||
|
"schedule_time_all_day": "ตลอดทั้งวัน",
|
||||||
|
"schedule_modal_description": "ตารางนี้จะมาแทนที่ตารางที่มีอยู่สำหรับวันเดียวกันของสัปดาห์ แต่ละวันของสัปดาห์สามารถมีช่วงที่ไม่มีกิจกรรมได้เพียงช่วงเดียวเท่านั้น",
|
||||||
|
"schedule_modal_time_off": "ไม่มีการบล็อคบริการ:",
|
||||||
|
"schedule_new": "ตารางใหม่",
|
||||||
|
"schedule_edit": "แก้ไขตารางเวลา",
|
||||||
|
"schedule_save": "บันทึกตารางเวลา",
|
||||||
|
"schedule_add": "เพิ่มตารางเวลา",
|
||||||
|
"schedule_remove": "ลบตารางเวลา",
|
||||||
|
"schedule_from": "จาก",
|
||||||
|
"schedule_to": "ถึง",
|
||||||
|
"sunday": "วันอาทิตย์",
|
||||||
|
"monday": "วันจันทร์",
|
||||||
|
"tuesday": "อังคาร",
|
||||||
|
"wednesday": "พุธ",
|
||||||
|
"thursday": "พฤหัสบดี",
|
||||||
|
"friday": "ศุกร์",
|
||||||
|
"saturday": "เสาร์",
|
||||||
"sunday_short": "อาทิตย์",
|
"sunday_short": "อาทิตย์",
|
||||||
"monday_short": "จันทร์",
|
"monday_short": "จันทร์",
|
||||||
"tuesday_short": "อังคาร",
|
"tuesday_short": "อังคาร",
|
||||||
"wednesday_short": "พุธ",
|
"wednesday_short": "พุธ",
|
||||||
"thursday_short": "พฤหัส",
|
"thursday_short": "พฤหัส",
|
||||||
"friday_short": "ศุกร์",
|
"friday_short": "ศุกร์",
|
||||||
"saturday_short": "เสาร์"
|
"saturday_short": "เสาร์",
|
||||||
|
"upstream_dns_cache_configuration": "การกำหนดค่าแคช DNS สำหรับเซิร์ฟเวอร์ต้นทาง",
|
||||||
|
"enable_upstream_dns_cache": "เปิดใช้งานการแคช DNS สำหรับการกำหนดค่าสำหรับลูกค้ารายนี้",
|
||||||
|
"dns_cache_size": "ขนาดแคช DNS, เป็นไบต์"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"upstream_parallel": "Tüm üst sunucuları eş zamanlı sorgulayarak çözümlemeyi hızlandırmak için paralel sorgular kullanın.",
|
"upstream_parallel": "Tüm üst sunucuları eş zamanlı sorgulayarak çözümlemeyi hızlandırmak için paralel sorgular kullanın.",
|
||||||
"parallel_requests": "Paralel istekler",
|
"parallel_requests": "Paralel istekler",
|
||||||
"load_balancing": "Yük dengeleme",
|
"load_balancing": "Yük dengeleme",
|
||||||
"load_balancing_desc": "Aynı anda bir üst kaynak sunucusunu sorgulayın. AdGuard Home, en düşük başarısız arama sayısına ve en düşük ortalama arama süresine sahip sunucuları seçmek için ağırlıklı rastgele bir algoritma kullanır.",
|
"load_balancing_desc": "Üst kaynak sunucuları aynı anda sorgulanır.<br/>AdGuard Home, en düşük başarısız sorgu sayısına ve en düşük ortalama sorgu süresine sahip sunucuları seçmek için ağırlıklı rastgele algoritma kullanır.",
|
||||||
"bootstrap_dns": "DNS Önyükleme sunucuları",
|
"bootstrap_dns": "DNS Önyükleme sunucuları",
|
||||||
"bootstrap_dns_desc": "Üst kaynak olarak belirttiğiniz DoH/DoT çözümleyicilerin IP adreslerini çözümlemek için kullanılan DNS sunucularının IP adresleri. Yorumlara izin verilmez.",
|
"bootstrap_dns_desc": "Üst kaynak olarak belirttiğiniz DoH/DoT çözümleyicilerin IP adreslerini çözümlemek için kullanılan DNS sunucularının IP adresleri. Yorumlara izin verilmez.",
|
||||||
"fallback_dns_title": "Yedek DNS sunucuları",
|
"fallback_dns_title": "Yedek DNS sunucuları",
|
||||||
@@ -279,7 +279,7 @@
|
|||||||
"query_log_strict_search": "Tam arama için çift tırnak işareti kullanın",
|
"query_log_strict_search": "Tam arama için çift tırnak işareti kullanın",
|
||||||
"query_log_retention_confirm": "Sorgu günlüğü rotasyonunu değiştirmek istediğinizden emin misiniz? Aralık değerini düşürürseniz, bazı veriler kaybolacaktır.",
|
"query_log_retention_confirm": "Sorgu günlüğü rotasyonunu değiştirmek istediğinizden emin misiniz? Aralık değerini düşürürseniz, bazı veriler kaybolacaktır.",
|
||||||
"anonymize_client_ip": "İstemcinin IP adresini gizle",
|
"anonymize_client_ip": "İstemcinin IP adresini gizle",
|
||||||
"anonymize_client_ip_desc": "İstemcinin tam IP adresini günlüklere veya istatistiklere kaydetmeyin",
|
"anonymize_client_ip_desc": "İstemcinin tam IP adresini günlüklere veya istatistiklere kaydetmez",
|
||||||
"dns_config": "DNS sunucu yapılandırması",
|
"dns_config": "DNS sunucu yapılandırması",
|
||||||
"dns_cache_config": "DNS önbellek yapılandırması",
|
"dns_cache_config": "DNS önbellek yapılandırması",
|
||||||
"dns_cache_config_desc": "Burada DNS önbelleğini yapılandırabilirsiniz",
|
"dns_cache_config_desc": "Burada DNS önbelleğini yapılandırabilirsiniz",
|
||||||
@@ -291,7 +291,7 @@
|
|||||||
"custom_ip": "Özel IP",
|
"custom_ip": "Özel IP",
|
||||||
"blocking_ipv4": "IPv4 engelleme",
|
"blocking_ipv4": "IPv4 engelleme",
|
||||||
"blocking_ipv6": "IPv6 engelleme",
|
"blocking_ipv6": "IPv6 engelleme",
|
||||||
"blocked_response_ttl": "Engellenen yanıt kullanım süresi",
|
"blocked_response_ttl": "Engellenen yanıtın geçerlilik süresi",
|
||||||
"blocked_response_ttl_desc": "İstemcilerin filtrelenmiş bir yanıtı kaç saniye süreyle önbelleğe alması gerektiğini belirtir",
|
"blocked_response_ttl_desc": "İstemcilerin filtrelenmiş bir yanıtı kaç saniye süreyle önbelleğe alması gerektiğini belirtir",
|
||||||
"form_enter_blocked_response_ttl": "Engellenen yanıt kullanım süresini girin (saniye)",
|
"form_enter_blocked_response_ttl": "Engellenen yanıt kullanım süresini girin (saniye)",
|
||||||
"upstream_timeout": "Üst kaynak zaman aşımı",
|
"upstream_timeout": "Üst kaynak zaman aşımı",
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
"dns_over_tls": "DNS-over-TLS",
|
"dns_over_tls": "DNS-over-TLS",
|
||||||
"dns_over_quic": "DNS-over-QUIC",
|
"dns_over_quic": "DNS-over-QUIC",
|
||||||
"client_id": "İstemci Kimliği",
|
"client_id": "İstemci Kimliği",
|
||||||
"client_id_placeholder": "İstemci Kimliği girin",
|
"client_id_placeholder": "İstemci kimliği girin",
|
||||||
"client_id_desc": "İstemciler, İstemci Kimliği ile tanımlanabilir. İstemcileri nasıl tanımlayacağınız hakkında daha fazla bilgiyi <a>buradan</a> öğrenin.",
|
"client_id_desc": "İstemciler, İstemci Kimliği ile tanımlanabilir. İstemcileri nasıl tanımlayacağınız hakkında daha fazla bilgiyi <a>buradan</a> öğrenin.",
|
||||||
"download_mobileconfig_doh": "DNS-over-HTTPS için .mobileconfig dosyasını indir",
|
"download_mobileconfig_doh": "DNS-over-HTTPS için .mobileconfig dosyasını indir",
|
||||||
"download_mobileconfig_dot": "DNS-over-TLS için .mobileconfig dosyasını indir",
|
"download_mobileconfig_dot": "DNS-over-TLS için .mobileconfig dosyasını indir",
|
||||||
@@ -338,7 +338,7 @@
|
|||||||
"upstream_dns_client_desc": "Bu alanı boş bırakırsanız, AdGuard Home, <0>DNS ayarlarında</0> yapılandırılan sunucuları kullanır.",
|
"upstream_dns_client_desc": "Bu alanı boş bırakırsanız, AdGuard Home, <0>DNS ayarlarında</0> yapılandırılan sunucuları kullanır.",
|
||||||
"tracker_source": "İzleyici kaynağı",
|
"tracker_source": "İzleyici kaynağı",
|
||||||
"source_label": "Kaynak",
|
"source_label": "Kaynak",
|
||||||
"found_in_known_domain_db": "Alan adlarının bilindiği veri tabanında bulundu.",
|
"found_in_known_domain_db": "Bilinen alan adları veri tabanında bulundu.",
|
||||||
"category_label": "Kategori",
|
"category_label": "Kategori",
|
||||||
"rule_label": "Kural",
|
"rule_label": "Kural",
|
||||||
"list_label": "Liste",
|
"list_label": "Liste",
|
||||||
@@ -375,7 +375,7 @@
|
|||||||
"install_devices_router_list_4": "Bazı yönlendirici türlerinde özel bir DNS sunucusu yapılandırılamaz. Bu durumda, AdGuard Home'u bir <0>DHCP sunucusu</0> olarak yapılandırmak yardımcı olabilir. Aksi takdirde, yönlendirici modelinizde DNS sunucularını nasıl özelleştireceğinizi öğrenmek için yönlendirici kılavuzunu kontrol etmelisiniz.",
|
"install_devices_router_list_4": "Bazı yönlendirici türlerinde özel bir DNS sunucusu yapılandırılamaz. Bu durumda, AdGuard Home'u bir <0>DHCP sunucusu</0> olarak yapılandırmak yardımcı olabilir. Aksi takdirde, yönlendirici modelinizde DNS sunucularını nasıl özelleştireceğinizi öğrenmek için yönlendirici kılavuzunu kontrol etmelisiniz.",
|
||||||
"install_devices_windows_list_1": "Başlat menüsünden veya Windows araması aracılığıyla Denetim Masası'nı açın.",
|
"install_devices_windows_list_1": "Başlat menüsünden veya Windows araması aracılığıyla Denetim Masası'nı açın.",
|
||||||
"install_devices_windows_list_2": "Ağ ve İnternet kategorisine girin ve ardından Ağ ve Paylaşım Merkezi'ne girin.",
|
"install_devices_windows_list_2": "Ağ ve İnternet kategorisine girin ve ardından Ağ ve Paylaşım Merkezi'ne girin.",
|
||||||
"install_devices_windows_list_3": "Sol panelde \"Bağdaştırıcı ayarlarını değiştirin\" öğesine tıklayın.",
|
"install_devices_windows_list_3": "Panelin solunda \"Bağdaştırıcı ayarlarını değiştirin\" öğesine tıklayın.",
|
||||||
"install_devices_windows_list_4": "Kullandığınız aktif bağlantının üzerine sağ tıklayın ve Özellikler öğesine tıklayın.",
|
"install_devices_windows_list_4": "Kullandığınız aktif bağlantının üzerine sağ tıklayın ve Özellikler öğesine tıklayın.",
|
||||||
"install_devices_windows_list_5": "Listede \"İnternet Protokolü Sürüm 4 (TCP/IPv4)\" (veya IPv6 için \"İnternet Protokolü Sürüm 6 (TCP/IPv6)\") öğesini bulun, seçin ve ardından tekrar Özellikler öğesine tıklayın.",
|
"install_devices_windows_list_5": "Listede \"İnternet Protokolü Sürüm 4 (TCP/IPv4)\" (veya IPv6 için \"İnternet Protokolü Sürüm 6 (TCP/IPv6)\") öğesini bulun, seçin ve ardından tekrar Özellikler öğesine tıklayın.",
|
||||||
"install_devices_windows_list_6": "\"Aşağıdaki DNS sunucu adreslerini kullan\"ı seçin ve AdGuard Home sunucu adreslerinizi girin.",
|
"install_devices_windows_list_6": "\"Aşağıdaki DNS sunucu adreslerini kullan\"ı seçin ve AdGuard Home sunucu adreslerinizi girin.",
|
||||||
@@ -384,12 +384,12 @@
|
|||||||
"install_devices_macos_list_3": "Listedeki ilk bağlantıyı seçin ve Gelişmiş öğesine tıklayın.",
|
"install_devices_macos_list_3": "Listedeki ilk bağlantıyı seçin ve Gelişmiş öğesine tıklayın.",
|
||||||
"install_devices_macos_list_4": "DNS sekmesini seçin ve AdGuard Home sunucunuzun adreslerini girin.",
|
"install_devices_macos_list_4": "DNS sekmesini seçin ve AdGuard Home sunucunuzun adreslerini girin.",
|
||||||
"install_devices_android_list_1": "Android Menüsü ana ekranından Ayarlar'a dokunun.",
|
"install_devices_android_list_1": "Android Menüsü ana ekranından Ayarlar'a dokunun.",
|
||||||
"install_devices_android_list_2": "Menüde bulunan Wi-Fi öğesine dokunun. Mevcut tüm ağlar listelenecektir (telefon ağlar için özel DNS sunucusu ayarlanamaz).",
|
"install_devices_android_list_2": "Menüde bulunan Wi-Fi öğesine dokunun. Mevcut tüm ağlar listelenecektir (mobil ağlar için özel DNS sunucusu ayarlanamaz).",
|
||||||
"install_devices_android_list_3": "Bağlı olduğunuz ağın üzerine basılı tutun ve Ağı Değiştir'e dokunun.",
|
"install_devices_android_list_3": "Bağlı olduğunuz ağın üzerine basılı tutun ve Ağı Değiştir'e dokunun.",
|
||||||
"install_devices_android_list_4": "Bazı cihazlarda, diğer ayarları görmek için \"Gelişmiş\" seçeneğini seçmeniz gerekebilir. Android DNS ayarlarınızı yapmak için IP ayarlarını DHCP modundan Statik moda değiştirmeniz gerekir.",
|
"install_devices_android_list_4": "Bazı cihazlarda, diğer ayarları görmek için \"Gelişmiş\" seçeneğini seçmeniz gerekebilir. Android DNS ayarlarınızı yapmak için IP ayarlarını DHCP modundan Statik moda değiştirmeniz gerekir.",
|
||||||
"install_devices_android_list_5": "DNS 1 ve DNS 2 değerlerini AdGuard Home sunucunuzun adresleriyle değiştirin.",
|
"install_devices_android_list_5": "DNS 1 ve DNS 2 değerlerini AdGuard Home sunucunuzun adresleriyle değiştirin.",
|
||||||
"install_devices_ios_list_1": "Ana ekrandan Ayarlar'a dokunun.",
|
"install_devices_ios_list_1": "Ana ekrandan Ayarlar'a dokunun.",
|
||||||
"install_devices_ios_list_2": "Sol menüde bulunan Wi-Fi bölümüne girin (telefon ağlar için özel DNS sunucusu ayarlanamaz).",
|
"install_devices_ios_list_2": "Sol menüde bulunan Wi-Fi bölümüne girin (mobil ağlar için özel DNS sunucusu ayarlanamaz).",
|
||||||
"install_devices_ios_list_3": "O anda aktif olan ağın adına dokunun.",
|
"install_devices_ios_list_3": "O anda aktif olan ağın adına dokunun.",
|
||||||
"install_devices_ios_list_4": "DNS alanına AdGuard Home sunucunuzun adreslerini girin.",
|
"install_devices_ios_list_4": "DNS alanına AdGuard Home sunucunuzun adreslerini girin.",
|
||||||
"get_started": "Başla",
|
"get_started": "Başla",
|
||||||
@@ -409,7 +409,7 @@
|
|||||||
"encryption_dot": "DNS-over-TLS bağlantı noktası",
|
"encryption_dot": "DNS-over-TLS bağlantı noktası",
|
||||||
"encryption_dot_desc": "Bu bağlantı noktası yapılandırılırsa, AdGuard Home, DNS-over-TLS sunucusunu bu bağlantı noktası üzerinden çalıştırır.",
|
"encryption_dot_desc": "Bu bağlantı noktası yapılandırılırsa, AdGuard Home, DNS-over-TLS sunucusunu bu bağlantı noktası üzerinden çalıştırır.",
|
||||||
"encryption_doq": "DNS-over-QUIC bağlantı noktası",
|
"encryption_doq": "DNS-over-QUIC bağlantı noktası",
|
||||||
"encryption_doq_desc": "Bu bağlantı noktası yapılandırılırsa, AdGuard Home, bu bağlantı noktasında bir DNS-over-QUIC sunucusu çalıştırır.",
|
"encryption_doq_desc": "Bu bağlantı noktası yapılandırılırsa, AdGuard Home, DNS-over-QUIC sunucusunu bu bağlantı noktası üzerinden çalıştırır.",
|
||||||
"encryption_certificates": "Sertifikalar",
|
"encryption_certificates": "Sertifikalar",
|
||||||
"encryption_certificates_desc": "Şifrelemeyi kullanmak için alan adınıza geçerli bir SSL sertifika zinciri sağlamanız gerekir. <0>{{link}}</0> adresinden ücretsiz bir sertifika alabilir veya güvenilir Sertifika Yetkililerinden satın alabilirsiniz.",
|
"encryption_certificates_desc": "Şifrelemeyi kullanmak için alan adınıza geçerli bir SSL sertifika zinciri sağlamanız gerekir. <0>{{link}}</0> adresinden ücretsiz bir sertifika alabilir veya güvenilir Sertifika Yetkililerinden satın alabilirsiniz.",
|
||||||
"encryption_certificates_input": "PEM biçimindeki sertifikalarınızı kopyalayıp buraya yapıştırın.",
|
"encryption_certificates_input": "PEM biçimindeki sertifikalarınızı kopyalayıp buraya yapıştırın.",
|
||||||
@@ -635,7 +635,7 @@
|
|||||||
"set_static_ip": "Sabit IP adresi ayarla",
|
"set_static_ip": "Sabit IP adresi ayarla",
|
||||||
"install_static_ok": "Güzel haber! Sabit IP adresi zaten yapılandırılmış",
|
"install_static_ok": "Güzel haber! Sabit IP adresi zaten yapılandırılmış",
|
||||||
"install_static_error": "AdGuard Home, bu ağ arayüzü için otomatik olarak yapılandıramıyor. Lütfen bunu elle nasıl yapacağınızla ilgili talimatlara bakın.",
|
"install_static_error": "AdGuard Home, bu ağ arayüzü için otomatik olarak yapılandıramıyor. Lütfen bunu elle nasıl yapacağınızla ilgili talimatlara bakın.",
|
||||||
"install_static_configure": "AdGuard Home, <0>{{ip}}</0> sabit IP adresinin kullanıldığını tespit etti. Sabit adresiniz olarak ayarlanmasını ister misiniz?",
|
"install_static_configure": "AdGuard Home, <0>{{ip}}</0> sabit IP adresinin kullanıldığını tespit etti. Sabit adresiniz olarak ayarlanmasını istiyor musunuz?",
|
||||||
"confirm_static_ip": "AdGuard Home, {{ip}} adresini sabit IP adresiniz olacak şekilde yapılandırır. Devam etmek istiyor musunuz?",
|
"confirm_static_ip": "AdGuard Home, {{ip}} adresini sabit IP adresiniz olacak şekilde yapılandırır. Devam etmek istiyor musunuz?",
|
||||||
"list_updated": "{{count}} liste güncellendi",
|
"list_updated": "{{count}} liste güncellendi",
|
||||||
"list_updated_plural": "{{count}} liste güncellendi",
|
"list_updated_plural": "{{count}} liste güncellendi",
|
||||||
|
|||||||
66
go.mod
66
go.mod
@@ -1,10 +1,10 @@
|
|||||||
module github.com/AdguardTeam/AdGuardHome
|
module github.com/AdguardTeam/AdGuardHome
|
||||||
|
|
||||||
go 1.24.3
|
go 1.24.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AdguardTeam/dnsproxy v0.75.5
|
github.com/AdguardTeam/dnsproxy v0.75.6
|
||||||
github.com/AdguardTeam/golibs v0.32.9
|
github.com/AdguardTeam/golibs v0.32.11
|
||||||
github.com/AdguardTeam/urlfilter v0.20.0
|
github.com/AdguardTeam/urlfilter v0.20.0
|
||||||
github.com/NYTimes/gziphandler v1.1.1
|
github.com/NYTimes/gziphandler v1.1.1
|
||||||
github.com/ameshkov/dnscrypt/v2 v2.4.0
|
github.com/ameshkov/dnscrypt/v2 v2.4.0
|
||||||
@@ -19,8 +19,7 @@ require (
|
|||||||
github.com/google/gopacket v1.1.19
|
github.com/google/gopacket v1.1.19
|
||||||
github.com/google/renameio/v2 v2.0.0
|
github.com/google/renameio/v2 v2.0.0
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905
|
github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f
|
||||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86
|
|
||||||
github.com/kardianos/service v1.2.2
|
github.com/kardianos/service v1.2.2
|
||||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
|
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
|
||||||
github.com/mdlayher/netlink v1.7.2
|
github.com/mdlayher/netlink v1.7.2
|
||||||
@@ -28,14 +27,14 @@ require (
|
|||||||
// TODO(a.garipov): This package is deprecated; find a new one or use our
|
// TODO(a.garipov): This package is deprecated; find a new one or use our
|
||||||
// own code for that. Perhaps, use gopacket.
|
// own code for that. Perhaps, use gopacket.
|
||||||
github.com/mdlayher/raw v0.1.0
|
github.com/mdlayher/raw v0.1.0
|
||||||
github.com/miekg/dns v1.1.65
|
github.com/miekg/dns v1.1.66
|
||||||
github.com/quic-go/quic-go v0.50.1
|
github.com/quic-go/quic-go v0.52.0
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/ti-mo/netfilter v0.5.2
|
github.com/ti-mo/netfilter v0.5.3
|
||||||
go.etcd.io/bbolt v1.4.0
|
go.etcd.io/bbolt v1.4.0
|
||||||
golang.org/x/crypto v0.38.0
|
golang.org/x/crypto v0.39.0
|
||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0
|
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b
|
||||||
golang.org/x/net v0.40.0
|
golang.org/x/net v0.41.0
|
||||||
golang.org/x/sys v0.33.0
|
golang.org/x/sys v0.33.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
@@ -43,9 +42,9 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.121.1 // indirect
|
cloud.google.com/go v0.121.2 // indirect
|
||||||
cloud.google.com/go/ai v0.12.0 // indirect
|
cloud.google.com/go/ai v0.12.1 // indirect
|
||||||
cloud.google.com/go/auth v0.16.1 // indirect
|
cloud.google.com/go/auth v0.16.2 // indirect
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||||
cloud.google.com/go/longrunning v0.6.7 // indirect
|
cloud.google.com/go/longrunning v0.6.7 // indirect
|
||||||
@@ -56,17 +55,18 @@ require (
|
|||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/fzipp/gocyclo v0.6.0 // indirect
|
github.com/fzipp/gocyclo v0.6.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||||
github.com/golangci/misspell v0.6.0 // indirect
|
github.com/golangci/misspell v0.7.0 // indirect
|
||||||
github.com/google/generative-ai-go v0.20.1 // indirect
|
github.com/google/generative-ai-go v0.20.1 // indirect
|
||||||
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a // indirect
|
github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e // indirect
|
||||||
github.com/google/s2a-go v0.1.9 // indirect
|
github.com/google/s2a-go v0.1.9 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
|
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
|
||||||
github.com/gookit/color v1.5.4 // indirect
|
github.com/gookit/color v1.5.4 // indirect
|
||||||
github.com/gordonklaus/ineffassign v0.1.0 // indirect
|
github.com/gordonklaus/ineffassign v0.1.0 // indirect
|
||||||
|
github.com/josharian/native v1.1.0 // indirect
|
||||||
github.com/jstemmer/go-junit-report/v2 v2.1.0 // indirect
|
github.com/jstemmer/go-junit-report/v2 v2.1.0 // indirect
|
||||||
github.com/kisielk/errcheck v1.9.0 // indirect
|
github.com/kisielk/errcheck v1.9.0 // indirect
|
||||||
github.com/mdlayher/socket v0.5.1 // indirect
|
github.com/mdlayher/socket v0.5.1 // indirect
|
||||||
@@ -83,28 +83,28 @@ require (
|
|||||||
github.com/uudashr/gocognit v1.2.0 // indirect
|
github.com/uudashr/gocognit v1.2.0 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.35.0 // indirect
|
go.opentelemetry.io/otel v1.36.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
go.opentelemetry.io/otel/trace v1.36.0 // indirect
|
||||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||||
go.uber.org/mock v0.5.2 // indirect
|
go.uber.org/mock v0.5.2 // indirect
|
||||||
golang.org/x/exp/typeparams v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
|
golang.org/x/exp/typeparams v0.0.0-20250606033433-dcc06ee1d476 // indirect
|
||||||
golang.org/x/mod v0.24.0 // indirect
|
golang.org/x/mod v0.25.0 // indirect
|
||||||
golang.org/x/oauth2 v0.30.0 // indirect
|
golang.org/x/oauth2 v0.30.0 // indirect
|
||||||
golang.org/x/sync v0.14.0 // indirect
|
golang.org/x/sync v0.15.0 // indirect
|
||||||
golang.org/x/telemetry v0.0.0-20250507143331-155ddd5254aa // indirect
|
golang.org/x/telemetry v0.0.0-20250609191608-4884ade64e8b // indirect
|
||||||
golang.org/x/term v0.32.0 // indirect
|
golang.org/x/term v0.32.0 // indirect
|
||||||
golang.org/x/text v0.25.0 // indirect
|
golang.org/x/text v0.26.0 // indirect
|
||||||
golang.org/x/time v0.11.0 // indirect
|
golang.org/x/time v0.12.0 // indirect
|
||||||
golang.org/x/tools v0.33.0 // indirect
|
golang.org/x/tools v0.34.0 // indirect
|
||||||
golang.org/x/vuln v1.1.4 // indirect
|
golang.org/x/vuln v1.1.4 // indirect
|
||||||
gonum.org/v1/gonum v0.16.0 // indirect
|
gonum.org/v1/gonum v0.16.0 // indirect
|
||||||
google.golang.org/api v0.233.0 // indirect
|
google.golang.org/api v0.236.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||||
google.golang.org/grpc v1.72.0 // indirect
|
google.golang.org/grpc v1.73.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.6 // indirect
|
google.golang.org/protobuf v1.36.6 // indirect
|
||||||
honnef.co/go/tools v0.6.1 // indirect
|
honnef.co/go/tools v0.6.1 // indirect
|
||||||
mvdan.cc/editorconfig v0.3.0 // indirect
|
mvdan.cc/editorconfig v0.3.0 // indirect
|
||||||
|
|||||||
137
go.sum
137
go.sum
@@ -1,19 +1,19 @@
|
|||||||
cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw=
|
cloud.google.com/go v0.121.2 h1:v2qQpN6Dx9x2NmwrqlesOt3Ys4ol5/lFZ6Mg1B7OJCg=
|
||||||
cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw=
|
cloud.google.com/go v0.121.2/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw=
|
||||||
cloud.google.com/go/ai v0.12.0 h1:i9k0U14BhejPY+yKTm9VTCjRAA3PwYvf4s/zhSkHof0=
|
cloud.google.com/go/ai v0.12.1 h1:m1n/VjUuHS+pEO/2R4/VbuuEIkgk0w67fDQvFaMngM0=
|
||||||
cloud.google.com/go/ai v0.12.0/go.mod h1:SEbNRRerz779yMT0qjDYG245m96WO8Flieiv+/fU9GQ=
|
cloud.google.com/go/ai v0.12.1/go.mod h1:5vIPNe1ZQsVZqCliXIPL4QnhObQQY4d9hAGHdVc4iw4=
|
||||||
cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
|
cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
|
||||||
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
|
cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||||
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
|
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
|
||||||
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
|
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
|
||||||
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
|
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
|
||||||
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
|
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
|
||||||
github.com/AdguardTeam/dnsproxy v0.75.5 h1:/P7+Ku4bjl+sVC/FW3PbT7pabgCjKTcrAOHqsZe2e60=
|
github.com/AdguardTeam/dnsproxy v0.75.6 h1:Xz5dciFQeMCtaqBHAyUYGI5PO1Lu7HwIi5ejhSVGsLY=
|
||||||
github.com/AdguardTeam/dnsproxy v0.75.5/go.mod h1:fdwtHhrDkTueDagDCasYKZbXdppkkBXW7RGPBNH+pis=
|
github.com/AdguardTeam/dnsproxy v0.75.6/go.mod h1:WHwb2fHfyujIZLrBymBQtqDUTbzDlNebWqykd1mCNuM=
|
||||||
github.com/AdguardTeam/golibs v0.32.9 h1:/6luT0aMOn05/s9eh1yA4lbcHgl0d1iEEvEBbIMMUk0=
|
github.com/AdguardTeam/golibs v0.32.11 h1:75EquS8SWvzsM3JFJY0359ZBw66jDjAegteHzh9nSw8=
|
||||||
github.com/AdguardTeam/golibs v0.32.9/go.mod h1:McV1QFFlKLElKa306V4OL/T2kr7564PhsayfvTWYBVs=
|
github.com/AdguardTeam/golibs v0.32.11/go.mod h1:LXr0gqqZuVpt+L+bP3Nnr0/CecLmm3rxkdgyyW5JXXM=
|
||||||
github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs=
|
github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs=
|
||||||
github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk=
|
github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk=
|
||||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
@@ -44,8 +44,8 @@ github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8
|
|||||||
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
|
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
|
||||||
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
|
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
@@ -58,8 +58,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
|
|||||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
|
github.com/golangci/misspell v0.7.0 h1:4GOHr/T1lTW0hhR4tgaaV1WS/lJ+ncvYCoFKmqJsj0c=
|
||||||
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
|
github.com/golangci/misspell v0.7.0/go.mod h1:WZyyI2P3hxPY2UVHs3cS8YcllAeyfquQcKfdeE9AFVg=
|
||||||
github.com/google/generative-ai-go v0.20.1 h1:6dEIujpgN2V0PgLhr6c/M1ynRdc7ARtiIDPFzj45uNQ=
|
github.com/google/generative-ai-go v0.20.1 h1:6dEIujpgN2V0PgLhr6c/M1ynRdc7ARtiIDPFzj45uNQ=
|
||||||
github.com/google/generative-ai-go v0.20.1/go.mod h1:TjOnZJmZKzarWbjUJgy+r3Ee7HGBRVLhOIgupnwR4Bg=
|
github.com/google/generative-ai-go v0.20.1/go.mod h1:TjOnZJmZKzarWbjUJgy+r3Ee7HGBRVLhOIgupnwR4Bg=
|
||||||
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=
|
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=
|
||||||
@@ -72,8 +72,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
|||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||||
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4=
|
github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e h1:FJta/0WsADCe1r9vQjdHbd3KuiLPu7Y9WlyLGwMUNyE=
|
||||||
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
|
github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
|
||||||
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
|
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
|
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
|
||||||
@@ -93,12 +93,12 @@ github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5
|
|||||||
github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
|
github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
|
||||||
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8=
|
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/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4=
|
github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f h1:dd33oobuIv9PcBVqvbEiCXEbNTomOHyj3WFuC5YiPRU=
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k=
|
github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f/go.mod h1:zhFlBeJssZ1YBCMZ5Lzu1pX4vhftDvU10WUVb1uXKtM=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
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.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk=
|
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86/go.mod h1:aFAMtuldEgx/4q7iSGazk22+IcgvtiC+HIimFO9XlS8=
|
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||||
github.com/jstemmer/go-junit-report/v2 v2.1.0 h1:X3+hPYlSczH9IMIpSC9CQSZA0L+BipYafciZUWHEmsc=
|
github.com/jstemmer/go-junit-report/v2 v2.1.0 h1:X3+hPYlSczH9IMIpSC9CQSZA0L+BipYafciZUWHEmsc=
|
||||||
github.com/jstemmer/go-junit-report/v2 v2.1.0/go.mod h1:mgHVr7VUo5Tn8OLVr1cKnLuEy0M92wdRntM99h7RkgQ=
|
github.com/jstemmer/go-junit-report/v2 v2.1.0/go.mod h1:mgHVr7VUo5Tn8OLVr1cKnLuEy0M92wdRntM99h7RkgQ=
|
||||||
github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
|
github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
|
||||||
@@ -124,8 +124,8 @@ 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.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E=
|
||||||
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||||
github.com/miekg/dns v1.1.65 h1:0+tIPHzUW0GCge7IiK3guGP57VAw7hoPDfApjkMD1Fc=
|
github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
|
||||||
github.com/miekg/dns v1.1.65/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
|
github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
|
||||||
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
|
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
|
||||||
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
|
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
|
||||||
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||||
@@ -145,8 +145,8 @@ github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4
|
|||||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
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/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||||
github.com/quic-go/quic-go v0.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q=
|
github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
|
||||||
github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E=
|
github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
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/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
@@ -164,8 +164,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
|||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
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/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.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.3 h1:ikzduvnaUMwre5bhbNwWOd6bjqLMVb33vv0XXbK0xGQ=
|
||||||
github.com/ti-mo/netfilter v0.5.2/go.mod h1:Btx3AtFiOVdHReTDmP9AE+hlkOcvIy403u7BXXbWZKo=
|
github.com/ti-mo/netfilter v0.5.3/go.mod h1:08SyBCg6hu1qyQk4s3DjjJKNrm3RTb32nm6AzyT972E=
|
||||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||||
@@ -183,37 +183,37 @@ 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.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b h1:QoALfVG9rhQ/M7vYDScfPdWjGL9dlsVVM5VGh7aKoAA=
|
||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
||||||
golang.org/x/exp/typeparams v0.0.0-20250506013437-ce4c2cf36ca6 h1:UW7ILaA/QTIxnBKbgCV+72w0gRw97+MY93VyPjnGZJU=
|
golang.org/x/exp/typeparams v0.0.0-20250606033433-dcc06ee1d476 h1:tceuojoK22x7b3gj32PCOPkkFeVtewHm1imqrGyFp1I=
|
||||||
golang.org/x/exp/typeparams v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ=
|
golang.org/x/exp/typeparams v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ=
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
@@ -221,14 +221,14 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
|
|||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -240,26 +240,25 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
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.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.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/telemetry v0.0.0-20250507143331-155ddd5254aa h1:MHtJsiOHK4ZJBZ+1Mj/vw1OfVBmCaVTJ4r1mi30Urlg=
|
golang.org/x/telemetry v0.0.0-20250609191608-4884ade64e8b h1:Y/IUTO67KgVkBoAByyCNRMMLAXUzEiblXXJqxR3OF8Q=
|
||||||
golang.org/x/telemetry v0.0.0-20250507143331-155ddd5254aa/go.mod h1:QNvpSH4vItB4zw8JazOv6Ba3fs1TorwPx9cCU6qTIdE=
|
golang.org/x/telemetry v0.0.0-20250609191608-4884ade64e8b/go.mod h1:mUcjA5g0luJpMYCLjhH91f4t4RAUNp+zq9ZmUoqPD7M=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||||
golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
|
golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
|
||||||
golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s=
|
golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -268,16 +267,16 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/api v0.233.0 h1:iGZfjXAJiUFSSaekVB7LzXl6tRfEKhUN7FkZN++07tI=
|
google.golang.org/api v0.236.0 h1:CAiEiDVtO4D/Qja2IA9VzlFrgPnK3XVMmRoJZlSWbc0=
|
||||||
google.golang.org/api v0.233.0/go.mod h1:TCIVLLlcwunlMpZIhIp7Ltk77W+vUSdUKAAIlbxY44c=
|
google.golang.org/api v0.236.0/go.mod h1:X1WF9CU2oTc+Jml1tiIxGmWFK/UZezdqEu09gcxZAj4=
|
||||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
|
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
|
||||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
|
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9 h1:WvBuA5rjZx9SNIzgcU53OohgZy6lKSus++uY4xLaWKc=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:W3S/3np0/dPWsWLi1h/UymYctGXaGBM2StwzD0y140U=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 h1:IkAfh6J/yllPtpYFU0zZN1hUPYdT0ogkBT/9hMxHjvg=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||||
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
|
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
|
||||||
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -5,8 +5,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SessionTokenLength is the length of the web user session token.
|
||||||
|
const SessionTokenLength = 16
|
||||||
|
|
||||||
// SessionToken is the type for the web user session token.
|
// SessionToken is the type for the web user session token.
|
||||||
type SessionToken [16]byte
|
type SessionToken [SessionTokenLength]byte
|
||||||
|
|
||||||
// NewSessionToken returns a cryptographically secure randomly generated web
|
// NewSessionToken returns a cryptographically secure randomly generated web
|
||||||
// user session token. If an error occurs during random generation, it will
|
// user session token. If an error occurs during random generation, it will
|
||||||
|
|||||||
@@ -10,31 +10,77 @@ import (
|
|||||||
|
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
"github.com/AdguardTeam/golibs/validate"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config is the configuration for the DHCP service.
|
// Config is the configuration for the DHCP service.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// Interfaces stores configurations of DHCP server specific for the network
|
// Interfaces stores configurations of DHCP server specific for the network
|
||||||
// interface identified by its name.
|
// interface identified by its name. It must not be empty and must only
|
||||||
|
// contain valid interface names and configurations.
|
||||||
Interfaces map[string]*InterfaceConfig
|
Interfaces map[string]*InterfaceConfig
|
||||||
|
|
||||||
// Logger will be used to log the DHCP events.
|
// Logger will be used to log the DHCP events. It must not be nil.
|
||||||
Logger *slog.Logger
|
Logger *slog.Logger
|
||||||
|
|
||||||
// LocalDomainName is the top-level domain name to use for resolving DHCP
|
// LocalDomainName is the top-level domain name to use for resolving DHCP
|
||||||
// clients' hostnames.
|
// clients' hostnames. It must be a valid domain name.
|
||||||
LocalDomainName string
|
LocalDomainName string
|
||||||
|
|
||||||
// DBFilePath is the path to the database file containing the DHCP leases.
|
// DBFilePath is the path to the database file containing the DHCP leases.
|
||||||
|
// It must not be empty.
|
||||||
DBFilePath string
|
DBFilePath string
|
||||||
|
|
||||||
// ICMPTimeout is the timeout for checking another DHCP server's presence.
|
// ICMPTimeout is the timeout for checking another DHCP server's presence.
|
||||||
|
// It must be non-negative. If it is zero, the check will be skipped.
|
||||||
ICMPTimeout time.Duration
|
ICMPTimeout time.Duration
|
||||||
|
|
||||||
// Enabled is the state of the service, whether it is enabled or not.
|
// Enabled is the state of the service, whether it is enabled or not.
|
||||||
Enabled bool
|
Enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ validate.Interface = (*Config)(nil)
|
||||||
|
|
||||||
|
// Validate implements the [validate.Interface] for *Config.
|
||||||
|
func (conf *Config) Validate() (err error) {
|
||||||
|
switch {
|
||||||
|
case conf == nil:
|
||||||
|
return errors.ErrNoValue
|
||||||
|
case !conf.Enabled:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := []error{
|
||||||
|
validate.NotNegative("ICMPTimeout", conf.ICMPTimeout),
|
||||||
|
}
|
||||||
|
|
||||||
|
err = netutil.ValidateDomainName(conf.LocalDomainName)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf("LocalDomainName: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a best-effort check for the file accessibility. The file will be
|
||||||
|
// checked again when it is opened later.
|
||||||
|
if _, err = os.Stat(conf.DBFilePath); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
|
errs = append(errs, fmt.Errorf("DBFilePath %q: %w", conf.DBFilePath, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(conf.Interfaces) == 0 {
|
||||||
|
err = fmt.Errorf("interfaces: %w", errors.ErrEmptyValue)
|
||||||
|
errs = append(errs, err)
|
||||||
|
|
||||||
|
return errors.Join(errs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, iface := range slices.Sorted(maps.Keys(conf.Interfaces)) {
|
||||||
|
ifaceConf := conf.Interfaces[iface]
|
||||||
|
errs = validate.Append(errs, iface, ifaceConf)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Join(errs...)
|
||||||
|
}
|
||||||
|
|
||||||
// InterfaceConfig is the configuration of a single DHCP interface.
|
// InterfaceConfig is the configuration of a single DHCP interface.
|
||||||
type InterfaceConfig struct {
|
type InterfaceConfig struct {
|
||||||
// IPv4 is the configuration of DHCP protocol for IPv4.
|
// IPv4 is the configuration of DHCP protocol for IPv4.
|
||||||
@@ -44,65 +90,17 @@ type InterfaceConfig struct {
|
|||||||
IPv6 *IPv6Config
|
IPv6 *IPv6Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate returns an error in conf if any.
|
// type check
|
||||||
//
|
var _ validate.Interface = (*InterfaceConfig)(nil)
|
||||||
// TODO(e.burkov): Unexport and rewrite the test.
|
|
||||||
func (conf *Config) Validate() (err error) {
|
|
||||||
switch {
|
|
||||||
case conf == nil:
|
|
||||||
return errNilConfig
|
|
||||||
case !conf.Enabled:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var errs []error
|
// Validate implements the [validate.Interface] interface for *InterfaceConfig.
|
||||||
if conf.ICMPTimeout < 0 {
|
func (ic *InterfaceConfig) Validate() (err error) {
|
||||||
err = newMustErr("icmp timeout", "be non-negative", conf.ICMPTimeout)
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = netutil.ValidateDomainName(conf.LocalDomainName)
|
|
||||||
if err != nil {
|
|
||||||
// Don't wrap the error since it's informative enough as is.
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a best-effort check for the file accessibility. The file will be
|
|
||||||
// checked again when it is opened later.
|
|
||||||
if _, err = os.Stat(conf.DBFilePath); err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
||||||
errs = append(errs, fmt.Errorf("db file path %q: %w", conf.DBFilePath, err))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(conf.Interfaces) == 0 {
|
|
||||||
errs = append(errs, errNoInterfaces)
|
|
||||||
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate returns an error in ic, if any.
|
|
||||||
func (ic *InterfaceConfig) validate() (err error) {
|
|
||||||
if ic == nil {
|
if ic == nil {
|
||||||
return errNilConfig
|
return errors.ErrNoValue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = ic.IPv4.validate(); err != nil {
|
return errors.Join(
|
||||||
return fmt.Errorf("ipv4: %w", err)
|
errors.Annotate(ic.IPv4.Validate(), "ipv4: %w"),
|
||||||
}
|
errors.Annotate(ic.IPv6.Validate(), "ipv6: %w"),
|
||||||
|
)
|
||||||
if err = ic.IPv6.validate(); err != nil {
|
|
||||||
return fmt.Errorf("ipv6: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,49 @@
|
|||||||
package dhcpsvc_test
|
package dhcpsvc_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/netip"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfig_Validate(t *testing.T) {
|
func TestConfig_Validate(t *testing.T) {
|
||||||
|
validIPv4Conf := &dhcpsvc.IPv4Config{
|
||||||
|
Enabled: true,
|
||||||
|
GatewayIP: netip.MustParseAddr("192.168.0.1"),
|
||||||
|
SubnetMask: netip.MustParseAddr("255.255.255.0"),
|
||||||
|
RangeStart: netip.MustParseAddr("192.168.0.2"),
|
||||||
|
RangeEnd: netip.MustParseAddr("192.168.0.254"),
|
||||||
|
LeaseDuration: 1 * time.Hour,
|
||||||
|
}
|
||||||
|
gwInRangeConf := &dhcpsvc.IPv4Config{
|
||||||
|
Enabled: true,
|
||||||
|
GatewayIP: netip.MustParseAddr("192.168.0.100"),
|
||||||
|
SubnetMask: netip.MustParseAddr("255.255.255.0"),
|
||||||
|
RangeStart: netip.MustParseAddr("192.168.0.1"),
|
||||||
|
RangeEnd: netip.MustParseAddr("192.168.0.254"),
|
||||||
|
LeaseDuration: 1 * time.Hour,
|
||||||
|
}
|
||||||
|
badStartConf := &dhcpsvc.IPv4Config{
|
||||||
|
Enabled: true,
|
||||||
|
GatewayIP: netip.MustParseAddr("192.168.0.1"),
|
||||||
|
SubnetMask: netip.MustParseAddr("255.255.255.0"),
|
||||||
|
RangeStart: netip.MustParseAddr("127.0.0.1"),
|
||||||
|
RangeEnd: netip.MustParseAddr("192.168.0.254"),
|
||||||
|
LeaseDuration: 1 * time.Hour,
|
||||||
|
}
|
||||||
|
|
||||||
|
validIPv6Conf := &dhcpsvc.IPv6Config{
|
||||||
|
Enabled: true,
|
||||||
|
RangeStart: netip.MustParseAddr("2001:db8::1"),
|
||||||
|
LeaseDuration: 1 * time.Hour,
|
||||||
|
RAAllowSLAAC: true,
|
||||||
|
RASLAACOnly: true,
|
||||||
|
}
|
||||||
|
|
||||||
leasesPath := filepath.Join(t.TempDir(), "leases.json")
|
leasesPath := filepath.Join(t.TempDir(), "leases.json")
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
@@ -18,7 +53,7 @@ func TestConfig_Validate(t *testing.T) {
|
|||||||
}{{
|
}{{
|
||||||
name: "nil_config",
|
name: "nil_config",
|
||||||
conf: nil,
|
conf: nil,
|
||||||
wantErrMsg: "config is nil",
|
wantErrMsg: "no value",
|
||||||
}, {
|
}, {
|
||||||
name: "disabled",
|
name: "disabled",
|
||||||
conf: &dhcpsvc.Config{},
|
conf: &dhcpsvc.Config{},
|
||||||
@@ -30,7 +65,7 @@ func TestConfig_Validate(t *testing.T) {
|
|||||||
Interfaces: testInterfaceConf,
|
Interfaces: testInterfaceConf,
|
||||||
DBFilePath: leasesPath,
|
DBFilePath: leasesPath,
|
||||||
},
|
},
|
||||||
wantErrMsg: `bad domain name "": domain name is empty`,
|
wantErrMsg: `LocalDomainName: bad domain name "": domain name is empty`,
|
||||||
}, {
|
}, {
|
||||||
conf: &dhcpsvc.Config{
|
conf: &dhcpsvc.Config{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -39,16 +74,7 @@ func TestConfig_Validate(t *testing.T) {
|
|||||||
DBFilePath: leasesPath,
|
DBFilePath: leasesPath,
|
||||||
},
|
},
|
||||||
name: "no_interfaces",
|
name: "no_interfaces",
|
||||||
wantErrMsg: "no interfaces specified",
|
wantErrMsg: "interfaces: empty value",
|
||||||
}, {
|
|
||||||
conf: &dhcpsvc.Config{
|
|
||||||
Enabled: true,
|
|
||||||
LocalDomainName: testLocalTLD,
|
|
||||||
Interfaces: nil,
|
|
||||||
DBFilePath: leasesPath,
|
|
||||||
},
|
|
||||||
name: "no_interfaces",
|
|
||||||
wantErrMsg: "no interfaces specified",
|
|
||||||
}, {
|
}, {
|
||||||
conf: &dhcpsvc.Config{
|
conf: &dhcpsvc.Config{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -59,7 +85,7 @@ func TestConfig_Validate(t *testing.T) {
|
|||||||
DBFilePath: leasesPath,
|
DBFilePath: leasesPath,
|
||||||
},
|
},
|
||||||
name: "nil_interface",
|
name: "nil_interface",
|
||||||
wantErrMsg: `interface "eth0": config is nil`,
|
wantErrMsg: `eth0: no value`,
|
||||||
}, {
|
}, {
|
||||||
conf: &dhcpsvc.Config{
|
conf: &dhcpsvc.Config{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -73,7 +99,7 @@ func TestConfig_Validate(t *testing.T) {
|
|||||||
DBFilePath: leasesPath,
|
DBFilePath: leasesPath,
|
||||||
},
|
},
|
||||||
name: "nil_ipv4",
|
name: "nil_ipv4",
|
||||||
wantErrMsg: `interface "eth0": ipv4: config is nil`,
|
wantErrMsg: `eth0: ipv4: no value`,
|
||||||
}, {
|
}, {
|
||||||
conf: &dhcpsvc.Config{
|
conf: &dhcpsvc.Config{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -87,7 +113,69 @@ func TestConfig_Validate(t *testing.T) {
|
|||||||
DBFilePath: leasesPath,
|
DBFilePath: leasesPath,
|
||||||
},
|
},
|
||||||
name: "nil_ipv6",
|
name: "nil_ipv6",
|
||||||
wantErrMsg: `interface "eth0": ipv6: config is nil`,
|
wantErrMsg: `eth0: ipv6: no value`,
|
||||||
|
}, {
|
||||||
|
conf: &dhcpsvc.Config{
|
||||||
|
Enabled: true,
|
||||||
|
Logger: discardLog,
|
||||||
|
LocalDomainName: testLocalTLD,
|
||||||
|
Interfaces: map[string]*dhcpsvc.InterfaceConfig{
|
||||||
|
"eth0": {
|
||||||
|
IPv4: validIPv4Conf,
|
||||||
|
IPv6: validIPv6Conf,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DBFilePath: leasesPath,
|
||||||
|
},
|
||||||
|
name: "valid",
|
||||||
|
wantErrMsg: "",
|
||||||
|
}, {
|
||||||
|
conf: &dhcpsvc.Config{
|
||||||
|
Enabled: true,
|
||||||
|
Logger: discardLog,
|
||||||
|
LocalDomainName: testLocalTLD,
|
||||||
|
Interfaces: map[string]*dhcpsvc.InterfaceConfig{
|
||||||
|
"eth0": {
|
||||||
|
IPv4: &dhcpsvc.IPv4Config{Enabled: false},
|
||||||
|
IPv6: &dhcpsvc.IPv6Config{Enabled: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DBFilePath: leasesPath,
|
||||||
|
},
|
||||||
|
name: "disabled_interfaces",
|
||||||
|
wantErrMsg: "",
|
||||||
|
}, {
|
||||||
|
conf: &dhcpsvc.Config{
|
||||||
|
Enabled: true,
|
||||||
|
Logger: discardLog,
|
||||||
|
LocalDomainName: testLocalTLD,
|
||||||
|
Interfaces: map[string]*dhcpsvc.InterfaceConfig{
|
||||||
|
"eth0": {
|
||||||
|
IPv4: gwInRangeConf,
|
||||||
|
IPv6: validIPv6Conf,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DBFilePath: leasesPath,
|
||||||
|
},
|
||||||
|
name: "gateway_within_range",
|
||||||
|
wantErrMsg: "eth0: ipv4: gateway ip 192.168.0.100 in the ip range " +
|
||||||
|
"192.168.0.1-192.168.0.254",
|
||||||
|
}, {
|
||||||
|
conf: &dhcpsvc.Config{
|
||||||
|
Enabled: true,
|
||||||
|
Logger: discardLog,
|
||||||
|
LocalDomainName: testLocalTLD,
|
||||||
|
Interfaces: map[string]*dhcpsvc.InterfaceConfig{
|
||||||
|
"eth0": {
|
||||||
|
IPv4: badStartConf,
|
||||||
|
IPv6: validIPv6Conf,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DBFilePath: leasesPath,
|
||||||
|
},
|
||||||
|
name: "bad_start",
|
||||||
|
wantErrMsg: "eth0: ipv4: range start 127.0.0.1 is not within 192.168.0.1/24" + "\n" +
|
||||||
|
"gateway ip 192.168.0.1 in the ip range 127.0.0.1-192.168.0.254",
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|||||||
@@ -2,20 +2,12 @@ package dhcpsvc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// errNilConfig is returned when a nil config met.
|
|
||||||
errNilConfig errors.Error = "config is nil"
|
|
||||||
|
|
||||||
// errNoInterfaces is returned when no interfaces found in configuration.
|
|
||||||
errNoInterfaces errors.Error = "no interfaces specified"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// newMustErr returns an error that indicates that valName must be as must
|
// newMustErr returns an error that indicates that valName must be as must
|
||||||
// describes.
|
// describes.
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): Use [validate] and remove this function.
|
||||||
func newMustErr(valName, must string, val fmt.Stringer) (err error) {
|
func newMustErr(valName, must string, val fmt.Stringer) (err error) {
|
||||||
return fmt.Errorf("%s %s must %s", valName, val, must)
|
return fmt.Errorf("%s %s must %s", valName, val, must)
|
||||||
}
|
}
|
||||||
|
|||||||
61
internal/dhcpsvc/handle.go
Normal file
61
internal/dhcpsvc/handle.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package dhcpsvc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||||
|
"github.com/google/gopacket/layers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// responseWriter4 writes DHCPv4 response to the client.
|
||||||
|
type responseWriter4 interface {
|
||||||
|
// write writes the DHCPv4 response to the client.
|
||||||
|
write(ctx context.Context, pkt *layers.DHCPv4) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// responseWriter6 writes DHCPv6 response to the client.
|
||||||
|
type responseWriter6 interface {
|
||||||
|
// write writes the DHCPv6 response to the client.
|
||||||
|
write(ctx context.Context, pkt *layers.DHCPv6) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// serve handles the incoming packets and dispatches them to the appropriate
|
||||||
|
// handler based on the Ethernet type. It's used to run in a separate goroutine
|
||||||
|
// as it blocks until packets channel is closed.
|
||||||
|
func (srv *DHCPServer) serve(ctx context.Context) {
|
||||||
|
defer slogutil.RecoverAndLog(ctx, srv.logger)
|
||||||
|
|
||||||
|
for pkt := range srv.packetSource.Packets() {
|
||||||
|
etherLayer, ok := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
|
||||||
|
if !ok {
|
||||||
|
actual := pkt.Layers()
|
||||||
|
srv.logger.DebugContext(ctx, "skipping non-ethernet packet", "layers", actual)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch typ := etherLayer.EthernetType; typ {
|
||||||
|
case layers.EthernetTypeIPv4:
|
||||||
|
// TODO(e.burkov): Set the response writer.
|
||||||
|
var rw responseWriter4
|
||||||
|
err = srv.serveV4(ctx, rw, pkt)
|
||||||
|
case layers.EthernetTypeIPv6:
|
||||||
|
// TODO(e.burkov): Set the response writer.
|
||||||
|
var rw responseWriter6
|
||||||
|
err = srv.serveV6(ctx, rw, pkt)
|
||||||
|
default:
|
||||||
|
// TODO(e.burkov): It seems, there is another standard for Ethernet
|
||||||
|
// header, which uses the Length field instead of the EthernetType,
|
||||||
|
// so handle it properly.
|
||||||
|
srv.logger.DebugContext(ctx, "skipping ethernet packet", "type", typ)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
srv.logger.ErrorContext(ctx, "serving", slogutil.KeyError, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
130
internal/dhcpsvc/handler4.go
Normal file
130
internal/dhcpsvc/handler4.go
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
package dhcpsvc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
"github.com/google/gopacket/layers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// serveV4 handles the ethernet packet of IPv4 type. rw and pkt must not be
|
||||||
|
// nil.
|
||||||
|
func (srv *DHCPServer) serveV4(
|
||||||
|
ctx context.Context,
|
||||||
|
rw responseWriter4,
|
||||||
|
pkt gopacket.Packet,
|
||||||
|
) (err error) {
|
||||||
|
defer func() { err = errors.Annotate(err, "serving dhcpv4: %w") }()
|
||||||
|
|
||||||
|
req, ok := pkt.Layer(layers.LayerTypeDHCPv4).(*layers.DHCPv4)
|
||||||
|
if !ok {
|
||||||
|
// TODO(e.burkov): Consider adding some debug information about the
|
||||||
|
// actual received packet.
|
||||||
|
srv.logger.DebugContext(ctx, "skipping non-dhcpv4 packet")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(e.burkov): Handle duplicate Xid.
|
||||||
|
|
||||||
|
if req.Operation != layers.DHCPOpRequest {
|
||||||
|
srv.logger.DebugContext(ctx, "skipping non-request dhcpv4 packet", "op", req.Operation)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
typ, ok := msg4Type(req)
|
||||||
|
if !ok {
|
||||||
|
// The "DHCP message type" option - must be included in every DHCP
|
||||||
|
// message.
|
||||||
|
//
|
||||||
|
// See https://datatracker.ietf.org/doc/html/rfc2131#section-3.
|
||||||
|
return fmt.Errorf("dhcpv4: message type: %w", errors.ErrNoValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return srv.handleDHCPv4(ctx, rw, typ, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleDHCPv4 handles the DHCPv4 message of the given type.
|
||||||
|
func (srv *DHCPServer) handleDHCPv4(
|
||||||
|
ctx context.Context,
|
||||||
|
rw responseWriter4,
|
||||||
|
typ layers.DHCPMsgType,
|
||||||
|
req *layers.DHCPv4,
|
||||||
|
) (err error) {
|
||||||
|
// Each interface should handle the DISCOVER and REQUEST messages offer and
|
||||||
|
// allocate the available leases. The RELEASE and DECLINE messages should
|
||||||
|
// be handled by the server itself as it should remove the lease.
|
||||||
|
switch typ {
|
||||||
|
case layers.DHCPMsgTypeDiscover:
|
||||||
|
srv.handleDiscover(ctx, rw, req)
|
||||||
|
case layers.DHCPMsgTypeRequest:
|
||||||
|
srv.handleRequest(ctx, rw, req)
|
||||||
|
case layers.DHCPMsgTypeRelease:
|
||||||
|
// TODO(e.burkov): Remove the lease, either allocated or offered.
|
||||||
|
case layers.DHCPMsgTypeDecline:
|
||||||
|
// TODO(e.burkov): Remove the allocated lease. RFC tells it only
|
||||||
|
// possible if the client found the address already in use.
|
||||||
|
default:
|
||||||
|
// TODO(e.burkov): Handle DHCPINFORM.
|
||||||
|
return fmt.Errorf("dhcpv4: request type: %w: %v", errors.ErrBadEnumValue, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleDiscover handles the DHCPv4 message of discover type.
|
||||||
|
func (srv *DHCPServer) handleDiscover(ctx context.Context, rw responseWriter4, req *layers.DHCPv4) {
|
||||||
|
// TODO(e.burkov): Check existing leases, either allocated or offered.
|
||||||
|
|
||||||
|
for _, iface := range srv.interfaces4 {
|
||||||
|
go iface.handleDiscover(ctx, rw, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleRequest handles the DHCPv4 message of request type.
|
||||||
|
func (srv *DHCPServer) handleRequest(ctx context.Context, rw responseWriter4, req *layers.DHCPv4) {
|
||||||
|
srvID, hasSrvID := serverID4(req)
|
||||||
|
reqIP, hasReqIP := requestedIPv4(req)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case hasSrvID && !srvID.IsUnspecified():
|
||||||
|
// If the DHCPREQUEST message contains a server identifier option, the
|
||||||
|
// message is in response to a DHCPOFFER message. Otherwise, the
|
||||||
|
// message is a request to verify or extend an existing lease.
|
||||||
|
iface, hasIface := srv.interfaces4.findInterface(srvID)
|
||||||
|
if !hasIface {
|
||||||
|
srv.logger.DebugContext(ctx, "skipping selecting request", "serverid", srvID)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
iface.handleSelecting(ctx, rw, req, reqIP)
|
||||||
|
case hasReqIP && !reqIP.IsUnspecified():
|
||||||
|
// Requested IP address option MUST be filled in with client's notion of
|
||||||
|
// its previously assigned address.
|
||||||
|
iface, hasIface := srv.interfaces4.findInterface(reqIP)
|
||||||
|
if !hasIface {
|
||||||
|
srv.logger.DebugContext(ctx, "skipping init-reboot request", "requestedip", reqIP)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
iface.handleInitReboot(ctx, rw, req, reqIP)
|
||||||
|
default:
|
||||||
|
// Server identifier MUST NOT be filled in, requested IP address option
|
||||||
|
// MUST NOT be filled in.
|
||||||
|
ip, _ := netip.AddrFromSlice(req.ClientIP.To4())
|
||||||
|
iface, hasIface := srv.interfaces4.findInterface(ip)
|
||||||
|
if !hasIface {
|
||||||
|
srv.logger.DebugContext(ctx, "skipping init-reboot request", "clientip", ip)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
iface.handleRenew(ctx, rw, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
58
internal/dhcpsvc/handler6.go
Normal file
58
internal/dhcpsvc/handler6.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package dhcpsvc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
"github.com/google/gopacket/layers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// serveV6 handles the ethernet packet of IPv6 type. rw and pkt must not be
|
||||||
|
// nil.
|
||||||
|
func (srv *DHCPServer) serveV6(
|
||||||
|
ctx context.Context,
|
||||||
|
rw responseWriter6,
|
||||||
|
pkt gopacket.Packet,
|
||||||
|
) (err error) {
|
||||||
|
defer func() { err = errors.Annotate(err, "serving dhcpv6: %w") }()
|
||||||
|
|
||||||
|
msg, ok := pkt.Layer(layers.LayerTypeDHCPv6).(*layers.DHCPv6)
|
||||||
|
if !ok {
|
||||||
|
// TODO(e.burkov): Consider adding some debug information about the
|
||||||
|
// actual received packet.
|
||||||
|
srv.logger.DebugContext(ctx, "skipping non-dhcpv6 packet")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(e.burkov): Handle duplicate TransactionID.
|
||||||
|
|
||||||
|
return srv.handleDHCPv6(ctx, rw, msg.MsgType, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleDHCPv6 handles the DHCPv6 message of the given type.
|
||||||
|
func (srv *DHCPServer) handleDHCPv6(
|
||||||
|
_ context.Context,
|
||||||
|
_ responseWriter6,
|
||||||
|
typ layers.DHCPv6MsgType,
|
||||||
|
_ *layers.DHCPv6,
|
||||||
|
) (err error) {
|
||||||
|
switch typ {
|
||||||
|
case
|
||||||
|
layers.DHCPv6MsgTypeSolicit,
|
||||||
|
layers.DHCPv6MsgTypeRequest,
|
||||||
|
layers.DHCPv6MsgTypeConfirm,
|
||||||
|
layers.DHCPv6MsgTypeRenew,
|
||||||
|
layers.DHCPv6MsgTypeRebind,
|
||||||
|
layers.DHCPv6MsgTypeInformationRequest,
|
||||||
|
layers.DHCPv6MsgTypeRelease,
|
||||||
|
layers.DHCPv6MsgTypeDecline:
|
||||||
|
// TODO(e.burkov): Handle messages.
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("dhcpv6: request type: %w: %v", errors.ErrBadEnumValue, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -45,17 +45,6 @@ type netInterface struct {
|
|||||||
leaseTTL time.Duration
|
leaseTTL time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// newNetInterface creates a new netInterface with the given name, leaseTTL, and
|
|
||||||
// logger.
|
|
||||||
func newNetInterface(name string, l *slog.Logger, leaseTTL time.Duration) (iface *netInterface) {
|
|
||||||
return &netInterface{
|
|
||||||
logger: l,
|
|
||||||
leases: map[macKey]*Lease{},
|
|
||||||
name: name,
|
|
||||||
leaseTTL: leaseTTL,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset clears all the slices in iface for reuse.
|
// reset clears all the slices in iface for reuse.
|
||||||
func (iface *netInterface) reset() {
|
func (iface *netInterface) reset() {
|
||||||
clear(iface.leases)
|
clear(iface.leases)
|
||||||
|
|||||||
@@ -13,9 +13,13 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
"github.com/google/gopacket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DHCPServer is a DHCP server for both IPv4 and IPv6 address families.
|
// DHCPServer is a DHCP server for both IPv4 and IPv6 address families.
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): Rename to Default.
|
||||||
type DHCPServer struct {
|
type DHCPServer struct {
|
||||||
// enabled indicates whether the DHCP server is enabled and can provide
|
// enabled indicates whether the DHCP server is enabled and can provide
|
||||||
// information about its clients.
|
// information about its clients.
|
||||||
@@ -24,6 +28,11 @@ type DHCPServer struct {
|
|||||||
// logger logs common DHCP events.
|
// logger logs common DHCP events.
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
|
|
||||||
|
// packetSource is the source of DHCP packets to process.
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): Implement and set.
|
||||||
|
packetSource gopacket.PacketSource
|
||||||
|
|
||||||
// localTLD is the top-level domain name to use for resolving DHCP clients'
|
// localTLD is the top-level domain name to use for resolving DHCP clients'
|
||||||
// hostnames.
|
// hostnames.
|
||||||
localTLD string
|
localTLD string
|
||||||
@@ -51,8 +60,8 @@ type DHCPServer struct {
|
|||||||
icmpTimeout time.Duration
|
icmpTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new DHCP server with the given configuration. It returns an
|
// New creates a new DHCP server with the given configuration. conf must be
|
||||||
// error if the given configuration can't be used.
|
// valid.
|
||||||
//
|
//
|
||||||
// TODO(e.burkov): Use.
|
// TODO(e.burkov): Use.
|
||||||
func New(ctx context.Context, conf *Config) (srv *DHCPServer, err error) {
|
func New(ctx context.Context, conf *Config) (srv *DHCPServer, err error) {
|
||||||
@@ -64,11 +73,7 @@ func New(ctx context.Context, conf *Config) (srv *DHCPServer, err error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ifaces4, ifaces6, err := newInterfaces(ctx, l, conf.Interfaces)
|
ifaces4, ifaces6 := newInterfaces(ctx, l, conf.Interfaces)
|
||||||
if err != nil {
|
|
||||||
// Don't wrap the error since it's informative enough as is.
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
enabled := &atomic.Bool{}
|
enabled := &atomic.Bool{}
|
||||||
enabled.Store(conf.Enabled)
|
enabled.Store(conf.Enabled)
|
||||||
@@ -95,40 +100,42 @@ func New(ctx context.Context, conf *Config) (srv *DHCPServer, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newInterfaces creates interfaces for the given map of interface names to
|
// newInterfaces creates interfaces for the given map of interface names to
|
||||||
// their configurations.
|
// their configurations. ifaces must be valid, baseLogger must not be nil.
|
||||||
func newInterfaces(
|
func newInterfaces(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
l *slog.Logger,
|
baseLogger *slog.Logger,
|
||||||
ifaces map[string]*InterfaceConfig,
|
ifaces map[string]*InterfaceConfig,
|
||||||
) (v4 dhcpInterfacesV4, v6 dhcpInterfacesV6, err error) {
|
) (v4 dhcpInterfacesV4, v6 dhcpInterfacesV6) {
|
||||||
defer func() { err = errors.Annotate(err, "creating interfaces: %w") }()
|
|
||||||
|
|
||||||
// TODO(e.burkov): Add validations scoped to the network interfaces set.
|
// TODO(e.burkov): Add validations scoped to the network interfaces set.
|
||||||
v4 = make(dhcpInterfacesV4, 0, len(ifaces))
|
v4 = make(dhcpInterfacesV4, 0, len(ifaces))
|
||||||
v6 = make(dhcpInterfacesV6, 0, len(ifaces))
|
v6 = make(dhcpInterfacesV6, 0, len(ifaces))
|
||||||
|
|
||||||
var errs []error
|
|
||||||
for _, name := range slices.Sorted(maps.Keys(ifaces)) {
|
for _, name := range slices.Sorted(maps.Keys(ifaces)) {
|
||||||
iface := ifaces[name]
|
iface := ifaces[name]
|
||||||
var i4 *dhcpInterfaceV4
|
ifaceLogger := baseLogger.With(keyInterface, name)
|
||||||
i4, err = newDHCPInterfaceV4(ctx, l, name, iface.IPv4)
|
|
||||||
if err != nil {
|
iface4 := newDHCPInterfaceV4(
|
||||||
errs = append(errs, fmt.Errorf("interface %q: ipv4: %w", name, err))
|
ctx,
|
||||||
} else if i4 != nil {
|
ifaceLogger.With(keyFamily, netutil.AddrFamilyIPv4),
|
||||||
v4 = append(v4, i4)
|
name,
|
||||||
|
iface.IPv4,
|
||||||
|
)
|
||||||
|
if iface4 != nil {
|
||||||
|
v4 = append(v4, iface4)
|
||||||
}
|
}
|
||||||
|
|
||||||
i6 := newDHCPInterfaceV6(ctx, l, name, iface.IPv6)
|
iface6 := newDHCPInterfaceV6(
|
||||||
if i6 != nil {
|
ctx,
|
||||||
v6 = append(v6, i6)
|
ifaceLogger.With(keyFamily, netutil.AddrFamilyIPv6),
|
||||||
|
name,
|
||||||
|
iface.IPv6,
|
||||||
|
)
|
||||||
|
if iface6 != nil {
|
||||||
|
v6 = append(v6, iface6)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = errors.Join(errs...); err != nil {
|
return v4, v6
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return v4, v6, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// type check
|
// type check
|
||||||
@@ -136,6 +143,25 @@ func newInterfaces(
|
|||||||
// TODO(e.burkov): Uncomment when the [Interface] interface is implemented.
|
// TODO(e.burkov): Uncomment when the [Interface] interface is implemented.
|
||||||
// var _ Interface = (*DHCPServer)(nil)
|
// var _ Interface = (*DHCPServer)(nil)
|
||||||
|
|
||||||
|
// Start implements the [Interface] interface for *DHCPServer.
|
||||||
|
func (srv *DHCPServer) Start(ctx context.Context) (err error) {
|
||||||
|
srv.logger.DebugContext(ctx, "starting dhcp server")
|
||||||
|
|
||||||
|
// TODO(e.burkov): Listen to configured interfaces.
|
||||||
|
|
||||||
|
go srv.serve(context.WithoutCancel(ctx))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *DHCPServer) Shutdown(ctx context.Context) (err error) {
|
||||||
|
srv.logger.DebugContext(ctx, "shutting down dhcp server")
|
||||||
|
|
||||||
|
// TODO(e.burkov): Close the packet source.
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Enabled implements the [Interface] interface for *DHCPServer.
|
// Enabled implements the [Interface] interface for *DHCPServer.
|
||||||
func (srv *DHCPServer) Enabled() (ok bool) {
|
func (srv *DHCPServer) Enabled() (ok bool) {
|
||||||
return srv.enabled.Load()
|
return srv.enabled.Load()
|
||||||
@@ -146,11 +172,9 @@ func (srv *DHCPServer) Leases() (leases []*Lease) {
|
|||||||
srv.leasesMu.RLock()
|
srv.leasesMu.RLock()
|
||||||
defer srv.leasesMu.RUnlock()
|
defer srv.leasesMu.RUnlock()
|
||||||
|
|
||||||
srv.leases.rangeLeases(func(l *Lease) (cont bool) {
|
for l := range srv.leases.rangeLeases {
|
||||||
leases = append(leases, l.Clone())
|
leases = append(leases, l)
|
||||||
|
}
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
return leases
|
return leases
|
||||||
}
|
}
|
||||||
@@ -253,7 +277,7 @@ func (srv *DHCPServer) AddLease(ctx context.Context, l *Lease) (err error) {
|
|||||||
"hostname", l.Hostname,
|
"hostname", l.Hostname,
|
||||||
"ip", l.IP,
|
"ip", l.IP,
|
||||||
"mac", l.HWAddr,
|
"mac", l.HWAddr,
|
||||||
"static", l.IsStatic,
|
"is_static", l.IsStatic,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -292,7 +316,7 @@ func (srv *DHCPServer) UpdateStaticLease(ctx context.Context, l *Lease) (err err
|
|||||||
"hostname", l.Hostname,
|
"hostname", l.Hostname,
|
||||||
"ip", l.IP,
|
"ip", l.IP,
|
||||||
"mac", l.HWAddr,
|
"mac", l.HWAddr,
|
||||||
"static", l.IsStatic,
|
"is_static", l.IsStatic,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -329,7 +353,51 @@ func (srv *DHCPServer) RemoveLease(ctx context.Context, l *Lease) (err error) {
|
|||||||
"hostname", l.Hostname,
|
"hostname", l.Hostname,
|
||||||
"ip", l.IP,
|
"ip", l.IP,
|
||||||
"mac", l.HWAddr,
|
"mac", l.HWAddr,
|
||||||
"static", l.IsStatic,
|
"is_static", l.IsStatic,
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeLeaseByAddr removes the lease with the given IP address from the
|
||||||
|
// server. It returns an error if the lease can't be removed.
|
||||||
|
//
|
||||||
|
//lint:ignore U1000 TODO(e.burkov): Use
|
||||||
|
func (srv *DHCPServer) removeLeaseByAddr(ctx context.Context, addr netip.Addr) (err error) {
|
||||||
|
defer func() { err = errors.Annotate(err, "removing lease by address: %w") }()
|
||||||
|
|
||||||
|
iface, err := srv.ifaceForAddr(addr)
|
||||||
|
if err != nil {
|
||||||
|
// Don't wrap the error since it's already informative enough as is.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
srv.leasesMu.Lock()
|
||||||
|
defer srv.leasesMu.Unlock()
|
||||||
|
|
||||||
|
l, ok := srv.leases.leaseByAddr(addr)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("no lease for ip %s", addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = srv.leases.remove(l, iface)
|
||||||
|
if err != nil {
|
||||||
|
// Don't wrap the error since there is already an annotation deferred.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = srv.dbStore(ctx)
|
||||||
|
if err != nil {
|
||||||
|
// Don't wrap the error since it's already informative enough as is.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
iface.logger.DebugContext(
|
||||||
|
ctx, "removed lease",
|
||||||
|
"hostname", l.Hostname,
|
||||||
|
"ip", l.IP,
|
||||||
|
"mac", l.HWAddr,
|
||||||
|
"is_static", l.IsStatic,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -40,120 +40,6 @@ func newTempDB(tb testing.TB) (dst string) {
|
|||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
|
||||||
validIPv4Conf := &dhcpsvc.IPv4Config{
|
|
||||||
Enabled: true,
|
|
||||||
GatewayIP: netip.MustParseAddr("192.168.0.1"),
|
|
||||||
SubnetMask: netip.MustParseAddr("255.255.255.0"),
|
|
||||||
RangeStart: netip.MustParseAddr("192.168.0.2"),
|
|
||||||
RangeEnd: netip.MustParseAddr("192.168.0.254"),
|
|
||||||
LeaseDuration: 1 * time.Hour,
|
|
||||||
}
|
|
||||||
gwInRangeConf := &dhcpsvc.IPv4Config{
|
|
||||||
Enabled: true,
|
|
||||||
GatewayIP: netip.MustParseAddr("192.168.0.100"),
|
|
||||||
SubnetMask: netip.MustParseAddr("255.255.255.0"),
|
|
||||||
RangeStart: netip.MustParseAddr("192.168.0.1"),
|
|
||||||
RangeEnd: netip.MustParseAddr("192.168.0.254"),
|
|
||||||
LeaseDuration: 1 * time.Hour,
|
|
||||||
}
|
|
||||||
badStartConf := &dhcpsvc.IPv4Config{
|
|
||||||
Enabled: true,
|
|
||||||
GatewayIP: netip.MustParseAddr("192.168.0.1"),
|
|
||||||
SubnetMask: netip.MustParseAddr("255.255.255.0"),
|
|
||||||
RangeStart: netip.MustParseAddr("127.0.0.1"),
|
|
||||||
RangeEnd: netip.MustParseAddr("192.168.0.254"),
|
|
||||||
LeaseDuration: 1 * time.Hour,
|
|
||||||
}
|
|
||||||
|
|
||||||
validIPv6Conf := &dhcpsvc.IPv6Config{
|
|
||||||
Enabled: true,
|
|
||||||
RangeStart: netip.MustParseAddr("2001:db8::1"),
|
|
||||||
LeaseDuration: 1 * time.Hour,
|
|
||||||
RAAllowSLAAC: true,
|
|
||||||
RASLAACOnly: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
leasesPath := filepath.Join(t.TempDir(), "leases.json")
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
conf *dhcpsvc.Config
|
|
||||||
name string
|
|
||||||
wantErrMsg string
|
|
||||||
}{{
|
|
||||||
conf: &dhcpsvc.Config{
|
|
||||||
Enabled: true,
|
|
||||||
Logger: discardLog,
|
|
||||||
LocalDomainName: testLocalTLD,
|
|
||||||
Interfaces: map[string]*dhcpsvc.InterfaceConfig{
|
|
||||||
"eth0": {
|
|
||||||
IPv4: validIPv4Conf,
|
|
||||||
IPv6: validIPv6Conf,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DBFilePath: leasesPath,
|
|
||||||
},
|
|
||||||
name: "valid",
|
|
||||||
wantErrMsg: "",
|
|
||||||
}, {
|
|
||||||
conf: &dhcpsvc.Config{
|
|
||||||
Enabled: true,
|
|
||||||
Logger: discardLog,
|
|
||||||
LocalDomainName: testLocalTLD,
|
|
||||||
Interfaces: map[string]*dhcpsvc.InterfaceConfig{
|
|
||||||
"eth0": {
|
|
||||||
IPv4: &dhcpsvc.IPv4Config{Enabled: false},
|
|
||||||
IPv6: &dhcpsvc.IPv6Config{Enabled: false},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DBFilePath: leasesPath,
|
|
||||||
},
|
|
||||||
name: "disabled_interfaces",
|
|
||||||
wantErrMsg: "",
|
|
||||||
}, {
|
|
||||||
conf: &dhcpsvc.Config{
|
|
||||||
Enabled: true,
|
|
||||||
Logger: discardLog,
|
|
||||||
LocalDomainName: testLocalTLD,
|
|
||||||
Interfaces: map[string]*dhcpsvc.InterfaceConfig{
|
|
||||||
"eth0": {
|
|
||||||
IPv4: gwInRangeConf,
|
|
||||||
IPv6: validIPv6Conf,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DBFilePath: leasesPath,
|
|
||||||
},
|
|
||||||
name: "gateway_within_range",
|
|
||||||
wantErrMsg: `creating interfaces: interface "eth0": ipv4: ` +
|
|
||||||
`gateway ip 192.168.0.100 in the ip range 192.168.0.1-192.168.0.254`,
|
|
||||||
}, {
|
|
||||||
conf: &dhcpsvc.Config{
|
|
||||||
Enabled: true,
|
|
||||||
Logger: discardLog,
|
|
||||||
LocalDomainName: testLocalTLD,
|
|
||||||
Interfaces: map[string]*dhcpsvc.InterfaceConfig{
|
|
||||||
"eth0": {
|
|
||||||
IPv4: badStartConf,
|
|
||||||
IPv6: validIPv6Conf,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DBFilePath: leasesPath,
|
|
||||||
},
|
|
||||||
name: "bad_start",
|
|
||||||
wantErrMsg: `creating interfaces: interface "eth0": ipv4: ` +
|
|
||||||
`range start 127.0.0.1 is not within 192.168.0.1/24`,
|
|
||||||
}}
|
|
||||||
|
|
||||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
_, err := dhcpsvc.New(ctx, tc.conf)
|
|
||||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDHCPServer_AddLease(t *testing.T) {
|
func TestDHCPServer_AddLease(t *testing.T) {
|
||||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,16 @@ import (
|
|||||||
|
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
"github.com/AdguardTeam/golibs/validate"
|
||||||
"github.com/google/gopacket/layers"
|
"github.com/google/gopacket/layers"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IPv4Config is the interface-specific configuration for DHCPv4.
|
// IPv4Config is the interface-specific configuration for DHCPv4.
|
||||||
type IPv4Config struct {
|
type IPv4Config struct {
|
||||||
// GatewayIP is the IPv4 address of the network's gateway. It is used as
|
// GatewayIP is the IPv4 address of the network's gateway. It is used as
|
||||||
// the default gateway for DHCP clients and also used in calculating the
|
// the default gateway for DHCP clients and also used for calculating the
|
||||||
// network-specific broadcast address.
|
// network-specific broadcast address. It should be a valid IPv4 address,
|
||||||
|
// should be within the subnet, and should be outside the address range.
|
||||||
GatewayIP netip.Addr
|
GatewayIP netip.Addr
|
||||||
|
|
||||||
// SubnetMask is the IPv4 subnet mask of the network. It should be a valid
|
// SubnetMask is the IPv4 subnet mask of the network. It should be a valid
|
||||||
@@ -26,17 +28,22 @@ type IPv4Config struct {
|
|||||||
SubnetMask netip.Addr
|
SubnetMask netip.Addr
|
||||||
|
|
||||||
// RangeStart is the first address in the range to assign to DHCP clients.
|
// RangeStart is the first address in the range to assign to DHCP clients.
|
||||||
|
// It should be a valid IPv4 address, should be within the subnet, and
|
||||||
|
// should be less or equal to RangeEnd.
|
||||||
RangeStart netip.Addr
|
RangeStart netip.Addr
|
||||||
|
|
||||||
// RangeEnd is the last address in the range to assign to DHCP clients.
|
// RangeEnd is the last address in the range to assign to DHCP clients. It
|
||||||
|
// should be a valid IPv4 address, should be within the subnet, and should
|
||||||
|
// be greater or equal to RangeStart.
|
||||||
RangeEnd netip.Addr
|
RangeEnd netip.Addr
|
||||||
|
|
||||||
// Options is the list of DHCP options to send to DHCP clients. The options
|
// Options is the list of explicitly configured DHCP options to send to
|
||||||
// having a zero value within the Length field are treated as deletions of
|
// clients. The options having a zero value within the Length field are
|
||||||
// the corresponding options, either implicit or explicit.
|
// treated as deletions of the corresponding options, either implicit or
|
||||||
|
// explicit.
|
||||||
Options layers.DHCPOptions
|
Options layers.DHCPOptions
|
||||||
|
|
||||||
// LeaseDuration is the TTL of a DHCP lease.
|
// LeaseDuration is the TTL of a DHCP lease. It should be positive.
|
||||||
LeaseDuration time.Duration
|
LeaseDuration time.Duration
|
||||||
|
|
||||||
// Enabled is the state of the DHCPv4 service, whether it is enabled or not
|
// Enabled is the state of the DHCPv4 service, whether it is enabled or not
|
||||||
@@ -44,35 +51,23 @@ type IPv4Config struct {
|
|||||||
Enabled bool
|
Enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate returns an error in conf if any.
|
// type check
|
||||||
func (c *IPv4Config) validate() (err error) {
|
var _ validate.Interface = (*IPv4Config)(nil)
|
||||||
|
|
||||||
|
// Validate implements the [validate.Interface] interface for *IPv4Config.
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): Use [validate].
|
||||||
|
func (c *IPv4Config) Validate() (err error) {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return errNilConfig
|
return errors.ErrNoValue
|
||||||
} else if !c.Enabled {
|
} else if !c.Enabled {
|
||||||
|
// Don't validate the configuration for disabled interface.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs []error
|
var errs []error
|
||||||
|
|
||||||
if !c.GatewayIP.Is4() {
|
errs = c.validateSubnet(errs)
|
||||||
err = newMustErr("gateway ip", "be a valid ipv4", c.GatewayIP)
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.SubnetMask.Is4() {
|
|
||||||
err = newMustErr("subnet mask", "be a valid ipv4 cidr mask", c.SubnetMask)
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.RangeStart.Is4() {
|
|
||||||
err = newMustErr("range start", "be a valid ipv4", c.RangeStart)
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.RangeEnd.Is4() {
|
|
||||||
err = newMustErr("range end", "be a valid ipv4", c.RangeEnd)
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.LeaseDuration <= 0 {
|
if c.LeaseDuration <= 0 {
|
||||||
err = newMustErr("icmp timeout", "be positive", c.LeaseDuration)
|
err = newMustErr("icmp timeout", "be positive", c.LeaseDuration)
|
||||||
@@ -82,6 +77,50 @@ func (c *IPv4Config) validate() (err error) {
|
|||||||
return errors.Join(errs...)
|
return errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateSubnet validates the subnet configuration.
|
||||||
|
func (c *IPv4Config) validateSubnet(errs []error) (res []error) {
|
||||||
|
res = errs
|
||||||
|
|
||||||
|
if !c.GatewayIP.Is4() {
|
||||||
|
err := newMustErr("gateway ip", "be a valid ipv4", c.GatewayIP)
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.SubnetMask.Is4() {
|
||||||
|
err := newMustErr("subnet mask", "be a valid ipv4 cidr mask", c.SubnetMask)
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.RangeStart.Is4() {
|
||||||
|
err := newMustErr("range start", "be a valid ipv4", c.RangeStart)
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.RangeEnd.Is4() {
|
||||||
|
err := newMustErr("range end", "be a valid ipv4", c.RangeEnd)
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
maskLen, _ := net.IPMask(c.SubnetMask.AsSlice()).Size()
|
||||||
|
subnet := netip.PrefixFrom(c.GatewayIP, maskLen)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case !subnet.Contains(c.RangeStart):
|
||||||
|
res = append(res, fmt.Errorf("range start %s is not within %s", c.RangeStart, subnet))
|
||||||
|
case !subnet.Contains(c.RangeEnd):
|
||||||
|
res = append(res, fmt.Errorf("range end %s is not within %s", c.RangeEnd, subnet))
|
||||||
|
}
|
||||||
|
|
||||||
|
addrSpace, err := newIPRange(c.RangeStart, c.RangeEnd)
|
||||||
|
if err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
} else if addrSpace.contains(c.GatewayIP) {
|
||||||
|
res = append(res, fmt.Errorf("gateway ip %s in the ip range %s", c.GatewayIP, addrSpace))
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// dhcpInterfaceV4 is a DHCP interface for IPv4 address family.
|
// dhcpInterfaceV4 is a DHCP interface for IPv4 address family.
|
||||||
type dhcpInterfaceV4 struct {
|
type dhcpInterfaceV4 struct {
|
||||||
// common is the common part of any network interface within the DHCP
|
// common is the common part of any network interface within the DHCP
|
||||||
@@ -91,7 +130,7 @@ type dhcpInterfaceV4 struct {
|
|||||||
// gateway is the IP address of the network gateway.
|
// gateway is the IP address of the network gateway.
|
||||||
gateway netip.Addr
|
gateway netip.Addr
|
||||||
|
|
||||||
// subnet is the network subnet.
|
// subnet is the network subnet of the interface.
|
||||||
subnet netip.Prefix
|
subnet netip.Prefix
|
||||||
|
|
||||||
// addrSpace is the IPv4 address space allocated for leasing.
|
// addrSpace is the IPv4 address space allocated for leasing.
|
||||||
@@ -108,67 +147,39 @@ type dhcpInterfaceV4 struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newDHCPInterfaceV4 creates a new DHCP interface for IPv4 address family with
|
// newDHCPInterfaceV4 creates a new DHCP interface for IPv4 address family with
|
||||||
// the given configuration. It returns an error if the given configuration
|
// the given configuration. If the interface is disabled, it returns nil. conf
|
||||||
// can't be used.
|
// must be valid.
|
||||||
func newDHCPInterfaceV4(
|
func newDHCPInterfaceV4(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
l *slog.Logger,
|
l *slog.Logger,
|
||||||
name string,
|
name string,
|
||||||
conf *IPv4Config,
|
conf *IPv4Config,
|
||||||
) (i *dhcpInterfaceV4, err error) {
|
) (iface *dhcpInterfaceV4) {
|
||||||
l = l.With(
|
|
||||||
keyInterface, name,
|
|
||||||
keyFamily, netutil.AddrFamilyIPv4,
|
|
||||||
)
|
|
||||||
|
|
||||||
if !conf.Enabled {
|
if !conf.Enabled {
|
||||||
l.DebugContext(ctx, "disabled")
|
l.DebugContext(ctx, "disabled")
|
||||||
|
|
||||||
return nil, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(e.burkov): Add a helper for converting [netip.Addr] to subnet mask
|
||||||
|
// to [netutil].
|
||||||
maskLen, _ := net.IPMask(conf.SubnetMask.AsSlice()).Size()
|
maskLen, _ := net.IPMask(conf.SubnetMask.AsSlice()).Size()
|
||||||
subnet := netip.PrefixFrom(conf.GatewayIP, maskLen)
|
addrSpace, _ := newIPRange(conf.RangeStart, conf.RangeEnd)
|
||||||
|
|
||||||
switch {
|
iface = &dhcpInterfaceV4{
|
||||||
case !subnet.Contains(conf.RangeStart):
|
|
||||||
return nil, fmt.Errorf("range start %s is not within %s", conf.RangeStart, subnet)
|
|
||||||
case !subnet.Contains(conf.RangeEnd):
|
|
||||||
return nil, fmt.Errorf("range end %s is not within %s", conf.RangeEnd, subnet)
|
|
||||||
}
|
|
||||||
|
|
||||||
addrSpace, err := newIPRange(conf.RangeStart, conf.RangeEnd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if addrSpace.contains(conf.GatewayIP) {
|
|
||||||
return nil, fmt.Errorf("gateway ip %s in the ip range %s", conf.GatewayIP, addrSpace)
|
|
||||||
}
|
|
||||||
|
|
||||||
i = &dhcpInterfaceV4{
|
|
||||||
gateway: conf.GatewayIP,
|
gateway: conf.GatewayIP,
|
||||||
subnet: subnet,
|
subnet: netip.PrefixFrom(conf.GatewayIP, maskLen),
|
||||||
addrSpace: addrSpace,
|
addrSpace: addrSpace,
|
||||||
common: newNetInterface(name, l, conf.LeaseDuration),
|
common: &netInterface{
|
||||||
|
logger: l,
|
||||||
|
leases: map[macKey]*Lease{},
|
||||||
|
name: name,
|
||||||
|
leaseTTL: conf.LeaseDuration,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
i.implicitOpts, i.explicitOpts = conf.options(ctx, l)
|
iface.implicitOpts, iface.explicitOpts = conf.options(ctx, l)
|
||||||
|
|
||||||
return i, nil
|
return iface
|
||||||
}
|
|
||||||
|
|
||||||
// dhcpInterfacesV4 is a slice of network interfaces of IPv4 address family.
|
|
||||||
type dhcpInterfacesV4 []*dhcpInterfaceV4
|
|
||||||
|
|
||||||
// find returns the first network interface within ifaces containing ip. It
|
|
||||||
// returns false if there is no such interface.
|
|
||||||
func (ifaces dhcpInterfacesV4) find(ip netip.Addr) (iface4 *netInterface, ok bool) {
|
|
||||||
i := slices.IndexFunc(ifaces, func(iface *dhcpInterfaceV4) (contains bool) {
|
|
||||||
return iface.subnet.Contains(ip)
|
|
||||||
})
|
|
||||||
if i < 0 {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return ifaces[i].common, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// options returns the implicit and explicit options for the interface. The two
|
// options returns the implicit and explicit options for the interface. The two
|
||||||
@@ -361,3 +372,106 @@ func (c *IPv4Config) options(ctx context.Context, l *slog.Logger) (imp, exp laye
|
|||||||
func compareV4OptionCodes(a, b layers.DHCPOption) (res int) {
|
func compareV4OptionCodes(a, b layers.DHCPOption) (res int) {
|
||||||
return int(a.Type) - int(b.Type)
|
return int(a.Type) - int(b.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// msg4Type returns the message type of msg, if it's present within the options.
|
||||||
|
func msg4Type(msg *layers.DHCPv4) (typ layers.DHCPMsgType, ok bool) {
|
||||||
|
for _, opt := range msg.Options {
|
||||||
|
if opt.Type == layers.DHCPOptMessageType && len(opt.Data) > 0 {
|
||||||
|
return layers.DHCPMsgType(opt.Data[0]), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// requestedIPv4 returns the IPv4 address, requested by client in the DHCP
|
||||||
|
// message, if any.
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): DRY with other IP-from-option helpers.
|
||||||
|
func requestedIPv4(msg *layers.DHCPv4) (ip netip.Addr, ok bool) {
|
||||||
|
for _, opt := range msg.Options {
|
||||||
|
if opt.Type == layers.DHCPOptRequestIP && len(opt.Data) == net.IPv4len {
|
||||||
|
return netip.AddrFromSlice(opt.Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return netip.Addr{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// serverID4 returns the server ID of the DHCP message, if any.
|
||||||
|
func serverID4(msg *layers.DHCPv4) (ip netip.Addr, ok bool) {
|
||||||
|
for _, opt := range msg.Options {
|
||||||
|
if opt.Type == layers.DHCPOptServerID && len(opt.Data) == net.IPv4len {
|
||||||
|
return netip.AddrFromSlice(opt.Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return netip.Addr{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleDiscover handles messages of type discover.
|
||||||
|
func (iface *dhcpInterfaceV4) handleDiscover(
|
||||||
|
ctx context.Context,
|
||||||
|
rw responseWriter4,
|
||||||
|
msg *layers.DHCPv4,
|
||||||
|
) {
|
||||||
|
// TODO(e.burkov): Implement.
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleSelecting handles messages of type request in SELECTING state.
|
||||||
|
func (iface *dhcpInterfaceV4) handleSelecting(
|
||||||
|
ctx context.Context,
|
||||||
|
rw responseWriter4,
|
||||||
|
msg *layers.DHCPv4,
|
||||||
|
reqIP netip.Addr,
|
||||||
|
) {
|
||||||
|
// TODO(e.burkov): Implement.
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleSelecting handles messages of type request in INIT-REBOOT state.
|
||||||
|
func (iface *dhcpInterfaceV4) handleInitReboot(
|
||||||
|
ctx context.Context,
|
||||||
|
rw responseWriter4,
|
||||||
|
msg *layers.DHCPv4,
|
||||||
|
reqIP netip.Addr,
|
||||||
|
) {
|
||||||
|
// TODO(e.burkov): Implement.
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleRenew handles messages of type request in RENEWING or REBINDING state.
|
||||||
|
func (iface *dhcpInterfaceV4) handleRenew(
|
||||||
|
ctx context.Context,
|
||||||
|
rw responseWriter4,
|
||||||
|
req *layers.DHCPv4,
|
||||||
|
) {
|
||||||
|
// TODO(e.burkov): Implement.
|
||||||
|
}
|
||||||
|
|
||||||
|
// dhcpInterfacesV4 is a slice of network interfaces of IPv4 address family.
|
||||||
|
type dhcpInterfacesV4 []*dhcpInterfaceV4
|
||||||
|
|
||||||
|
// find returns the first network interface within ifaces containing ip. It
|
||||||
|
// returns false if there is no such interface.
|
||||||
|
func (ifaces dhcpInterfacesV4) find(ip netip.Addr) (iface4 *netInterface, ok bool) {
|
||||||
|
i := slices.IndexFunc(ifaces, func(iface *dhcpInterfaceV4) (contains bool) {
|
||||||
|
return iface.subnet.Contains(ip)
|
||||||
|
})
|
||||||
|
if i < 0 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return ifaces[i].common, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// findInterface returns the first DHCPv4 interface within ifaces containing
|
||||||
|
// ip. It returns false if there is no such interface.
|
||||||
|
func (ifaces dhcpInterfacesV4) findInterface(ip netip.Addr) (iface *dhcpInterfaceV4, ok bool) {
|
||||||
|
i := slices.IndexFunc(ifaces, func(iface *dhcpInterfaceV4) (contains bool) {
|
||||||
|
return iface.subnet.Contains(ip)
|
||||||
|
})
|
||||||
|
if i < 0 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return ifaces[i], true
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,20 +10,22 @@ import (
|
|||||||
|
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
"github.com/AdguardTeam/golibs/validate"
|
||||||
"github.com/google/gopacket/layers"
|
"github.com/google/gopacket/layers"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IPv6Config is the interface-specific configuration for DHCPv6.
|
// IPv6Config is the interface-specific configuration for DHCPv6.
|
||||||
type IPv6Config struct {
|
type IPv6Config struct {
|
||||||
// RangeStart is the first address in the range to assign to DHCP clients.
|
// RangeStart is the first address in the range to assign to DHCP clients.
|
||||||
|
// It should be a valid IPv6 address.
|
||||||
RangeStart netip.Addr
|
RangeStart netip.Addr
|
||||||
|
|
||||||
// Options is the list of DHCP options to send to DHCP clients. The options
|
// Options is the list of explicit DHCP options to send to clients. The
|
||||||
// with zero length are treated as deletions of the corresponding options,
|
// options with zero length are treated as deletions of the corresponding
|
||||||
// either implicit or explicit.
|
// options, either implicit or explicit.
|
||||||
Options layers.DHCPv6Options
|
Options layers.DHCPv6Options
|
||||||
|
|
||||||
// LeaseDuration is the TTL of a DHCP lease.
|
// LeaseDuration is the TTL of a DHCP lease. It should be positive.
|
||||||
LeaseDuration time.Duration
|
LeaseDuration time.Duration
|
||||||
|
|
||||||
// RASlaacOnly defines whether the DHCP clients should only use SLAAC for
|
// RASlaacOnly defines whether the DHCP clients should only use SLAAC for
|
||||||
@@ -39,10 +41,13 @@ type IPv6Config struct {
|
|||||||
Enabled bool
|
Enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate returns an error in conf if any.
|
// type check
|
||||||
func (c *IPv6Config) validate() (err error) {
|
var _ validate.Interface = (*IPv6Config)(nil)
|
||||||
|
|
||||||
|
// Validate implements the [validate.Interface] interface for *IPv6Config.
|
||||||
|
func (c *IPv6Config) Validate() (err error) {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return errNilConfig
|
return errors.ErrNoValue
|
||||||
} else if !c.Enabled {
|
} else if !c.Enabled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -89,31 +94,34 @@ type dhcpInterfaceV6 struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newDHCPInterfaceV6 creates a new DHCP interface for IPv6 address family with
|
// newDHCPInterfaceV6 creates a new DHCP interface for IPv6 address family with
|
||||||
// the given configuration.
|
// the given configuration. If the interface is disabled, it returns nil. conf
|
||||||
//
|
// must be valid.
|
||||||
// TODO(e.burkov): Validate properly.
|
|
||||||
func newDHCPInterfaceV6(
|
func newDHCPInterfaceV6(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
l *slog.Logger,
|
l *slog.Logger,
|
||||||
name string,
|
name string,
|
||||||
conf *IPv6Config,
|
conf *IPv6Config,
|
||||||
) (i *dhcpInterfaceV6) {
|
) (iface *dhcpInterfaceV6) {
|
||||||
l = l.With(keyInterface, name, keyFamily, netutil.AddrFamilyIPv6)
|
|
||||||
if !conf.Enabled {
|
if !conf.Enabled {
|
||||||
l.DebugContext(ctx, "disabled")
|
l.DebugContext(ctx, "disabled")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
i = &dhcpInterfaceV6{
|
iface = &dhcpInterfaceV6{
|
||||||
rangeStart: conf.RangeStart,
|
rangeStart: conf.RangeStart,
|
||||||
common: newNetInterface(name, l, conf.LeaseDuration),
|
common: &netInterface{
|
||||||
|
logger: l,
|
||||||
|
leases: map[macKey]*Lease{},
|
||||||
|
name: name,
|
||||||
|
leaseTTL: conf.LeaseDuration,
|
||||||
|
},
|
||||||
raSLAACOnly: conf.RASLAACOnly,
|
raSLAACOnly: conf.RASLAACOnly,
|
||||||
raAllowSLAAC: conf.RAAllowSLAAC,
|
raAllowSLAAC: conf.RAAllowSLAAC,
|
||||||
}
|
}
|
||||||
i.implicitOpts, i.explicitOpts = conf.options(ctx, l)
|
iface.implicitOpts, iface.explicitOpts = conf.options(ctx, l)
|
||||||
|
|
||||||
return i
|
return iface
|
||||||
}
|
}
|
||||||
|
|
||||||
// dhcpInterfacesV6 is a slice of network interfaces of IPv6 address family.
|
// dhcpInterfacesV6 is a slice of network interfaces of IPv6 address family.
|
||||||
|
|||||||
@@ -563,7 +563,7 @@ func (s *Server) dhcpHostFromRequest(q *dns.Question) (reqHost string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reqHost = strings.ToLower(q.Name[:len(q.Name)-1])
|
reqHost = strings.ToLower(q.Name[:len(q.Name)-1])
|
||||||
if !netutil.IsImmediateSubdomain(reqHost, s.localDomainSuffix) {
|
if !netutil.IsSubdomain(reqHost, s.localDomainSuffix) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -498,14 +498,28 @@ func TestServer_ProcessDHCPHosts_localRestriction(t *testing.T) {
|
|||||||
|
|
||||||
func TestServer_ProcessDHCPHosts(t *testing.T) {
|
func TestServer_ProcessDHCPHosts(t *testing.T) {
|
||||||
const (
|
const (
|
||||||
localTLD = "lan"
|
localTLD = "lan"
|
||||||
|
customTLD = "custom"
|
||||||
|
|
||||||
knownClient = "example"
|
oneLabelClient = "example"
|
||||||
externalHost = knownClient + ".com"
|
twoLabelClient = "sub.example"
|
||||||
clientHost = knownClient + "." + localTLD
|
externalHost = oneLabelClient + ".com"
|
||||||
|
oneLabelClientHost = oneLabelClient + "." + localTLD
|
||||||
|
twoLabelClientHost = twoLabelClient + "." + localTLD
|
||||||
)
|
)
|
||||||
|
|
||||||
knownIP := netip.MustParseAddr("1.2.3.4")
|
knownClients := map[string]netip.Addr{
|
||||||
|
oneLabelClient: netip.MustParseAddr("1.2.3.4"),
|
||||||
|
twoLabelClient: netip.MustParseAddr("1.2.3.5"),
|
||||||
|
}
|
||||||
|
|
||||||
|
testDHCP := &testDHCP{
|
||||||
|
OnEnabled: func() (ok bool) { return true },
|
||||||
|
OnIPByHost: func(host string) (ip netip.Addr) {
|
||||||
|
return knownClients[host]
|
||||||
|
},
|
||||||
|
OnHostByIP: func(ip netip.Addr) (host string) { panic("not implemented") },
|
||||||
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
wantIP netip.Addr
|
wantIP netip.Addr
|
||||||
@@ -529,9 +543,16 @@ func TestServer_ProcessDHCPHosts(t *testing.T) {
|
|||||||
wantRes: resultCodeSuccess,
|
wantRes: resultCodeSuccess,
|
||||||
qtyp: dns.TypeCNAME,
|
qtyp: dns.TypeCNAME,
|
||||||
}, {
|
}, {
|
||||||
wantIP: knownIP,
|
wantIP: knownClients[oneLabelClient],
|
||||||
name: "internal",
|
name: "internal",
|
||||||
host: clientHost,
|
host: oneLabelClientHost,
|
||||||
|
suffix: localTLD,
|
||||||
|
wantRes: resultCodeSuccess,
|
||||||
|
qtyp: dns.TypeA,
|
||||||
|
}, {
|
||||||
|
wantIP: knownClients[twoLabelClient],
|
||||||
|
name: "internal_two_label",
|
||||||
|
host: twoLabelClientHost,
|
||||||
suffix: localTLD,
|
suffix: localTLD,
|
||||||
wantRes: resultCodeSuccess,
|
wantRes: resultCodeSuccess,
|
||||||
qtyp: dns.TypeA,
|
qtyp: dns.TypeA,
|
||||||
@@ -545,32 +566,27 @@ func TestServer_ProcessDHCPHosts(t *testing.T) {
|
|||||||
}, {
|
}, {
|
||||||
wantIP: netip.Addr{},
|
wantIP: netip.Addr{},
|
||||||
name: "internal_aaaa",
|
name: "internal_aaaa",
|
||||||
host: clientHost,
|
host: oneLabelClientHost,
|
||||||
suffix: localTLD,
|
suffix: localTLD,
|
||||||
wantRes: resultCodeSuccess,
|
wantRes: resultCodeSuccess,
|
||||||
qtyp: dns.TypeAAAA,
|
qtyp: dns.TypeAAAA,
|
||||||
}, {
|
}, {
|
||||||
wantIP: knownIP,
|
wantIP: knownClients[oneLabelClient],
|
||||||
name: "custom_suffix",
|
name: "custom_suffix",
|
||||||
host: knownClient + ".custom",
|
host: oneLabelClient + "." + customTLD,
|
||||||
suffix: "custom",
|
suffix: customTLD,
|
||||||
|
wantRes: resultCodeSuccess,
|
||||||
|
qtyp: dns.TypeA,
|
||||||
|
}, {
|
||||||
|
wantIP: knownClients[twoLabelClient],
|
||||||
|
name: "custom_suffix_two_label",
|
||||||
|
host: twoLabelClient + "." + customTLD,
|
||||||
|
suffix: customTLD,
|
||||||
wantRes: resultCodeSuccess,
|
wantRes: resultCodeSuccess,
|
||||||
qtyp: dns.TypeA,
|
qtyp: dns.TypeA,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
testDHCP := &testDHCP{
|
|
||||||
OnEnabled: func() (_ bool) { return true },
|
|
||||||
OnIPByHost: func(host string) (ip netip.Addr) {
|
|
||||||
if host == knownClient {
|
|
||||||
ip = knownIP
|
|
||||||
}
|
|
||||||
|
|
||||||
return ip
|
|
||||||
},
|
|
||||||
OnHostByIP: func(ip netip.Addr) (host string) { panic("not implemented") },
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &Server{
|
s := &Server{
|
||||||
dnsFilter: createTestDNSFilter(t),
|
dnsFilter: createTestDNSFilter(t),
|
||||||
dhcpServer: testDHCP,
|
dhcpServer: testDHCP,
|
||||||
@@ -578,16 +594,7 @@ func TestServer_ProcessDHCPHosts(t *testing.T) {
|
|||||||
baseLogger: slogutil.NewDiscardLogger(),
|
baseLogger: slogutil.NewDiscardLogger(),
|
||||||
}
|
}
|
||||||
|
|
||||||
req := &dns.Msg{
|
req := (&dns.Msg{}).SetQuestion(dns.Fqdn(tc.host), tc.qtyp)
|
||||||
MsgHdr: dns.MsgHdr{
|
|
||||||
Id: 1234,
|
|
||||||
},
|
|
||||||
Question: []dns.Question{{
|
|
||||||
Name: dns.Fqdn(tc.host),
|
|
||||||
Qtype: tc.qtyp,
|
|
||||||
Qclass: dns.ClassINET,
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
|
|
||||||
dctx := &dnsContext{
|
dctx := &dnsContext{
|
||||||
proxyCtx: &proxy.DNSContext{
|
proxyCtx: &proxy.DNSContext{
|
||||||
@@ -603,8 +610,8 @@ func TestServer_ProcessDHCPHosts(t *testing.T) {
|
|||||||
require.NoError(t, dctx.err)
|
require.NoError(t, dctx.err)
|
||||||
|
|
||||||
if tc.qtyp == dns.TypeAAAA {
|
if tc.qtyp == dns.TypeAAAA {
|
||||||
// TODO(a.garipov): Remove this special handling
|
// TODO(a.garipov): Remove this special handling when we fully
|
||||||
// when we fully support AAAA.
|
// support AAAA.
|
||||||
require.NotNil(t, pctx.Res)
|
require.NotNil(t, pctx.Res)
|
||||||
|
|
||||||
ans := pctx.Res.Answer
|
ans := pctx.Res.Answer
|
||||||
|
|||||||
@@ -2064,7 +2064,12 @@ var blockedServices = []blockedService{{
|
|||||||
Name: "OK.ru",
|
Name: "OK.ru",
|
||||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 96 96\"><path d=\"M50 28c-3.313 0-6 2.688-6 6 0 3.313 2.688 6 6 6 3.313 0 6-2.688 6-6 0-3.313-2.688-6-6-6zm0 0\" /><path d=\"M50 4C24.637 4 4 24.637 4 50s20.637 46 46 46 46-20.637 46-46S75.363 4 50 4zm0 16c7.73 0 14 6.27 14 14s-6.27 14-14 14-14-6.27-14-14 6.27-14 14-14zm14.828 49.172A3.999 3.999 0 0 1 62 76a3.987 3.987 0 0 1-2.828-1.172L50 65.656l-9.172 9.172a3.999 3.999 0 0 1-5.656 0 3.999 3.999 0 0 1 0-5.656l6.43-6.43c-1.836-.539-3.618-1.207-5.29-2.066A4.302 4.302 0 0 1 34 56.859c0-2.98 3.172-4.761 5.809-3.375A21.767 21.767 0 0 0 50 56c3.684 0 7.148-.91 10.191-2.516C62.828 52.098 66 53.88 66 56.86c0 1.602-.89 3.078-2.313 3.813-1.671.863-3.453 1.531-5.289 2.07zm0 0\" /></svg>"),
|
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 96 96\"><path d=\"M50 28c-3.313 0-6 2.688-6 6 0 3.313 2.688 6 6 6 3.313 0 6-2.688 6-6 0-3.313-2.688-6-6-6zm0 0\" /><path d=\"M50 4C24.637 4 4 24.637 4 50s20.637 46 46 46 46-20.637 46-46S75.363 4 50 4zm0 16c7.73 0 14 6.27 14 14s-6.27 14-14 14-14-6.27-14-14 6.27-14 14-14zm14.828 49.172A3.999 3.999 0 0 1 62 76a3.987 3.987 0 0 1-2.828-1.172L50 65.656l-9.172 9.172a3.999 3.999 0 0 1-5.656 0 3.999 3.999 0 0 1 0-5.656l6.43-6.43c-1.836-.539-3.618-1.207-5.29-2.066A4.302 4.302 0 0 1 34 56.859c0-2.98 3.172-4.761 5.809-3.375A21.767 21.767 0 0 0 50 56c3.684 0 7.148-.91 10.191-2.516C62.828 52.098 66 53.88 66 56.86c0 1.602-.89 3.078-2.313 3.813-1.671.863-3.453 1.531-5.289 2.07zm0 0\" /></svg>"),
|
||||||
Rules: []string{
|
Rules: []string{
|
||||||
|
"||insideok.ru^",
|
||||||
|
"||ok.games^",
|
||||||
"||ok.ru^",
|
"||ok.ru^",
|
||||||
|
"||okcdn.ru^",
|
||||||
|
"||oktech.ru^",
|
||||||
|
"||st.mycdn.me^",
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
ID: "olvid",
|
ID: "olvid",
|
||||||
@@ -2408,6 +2413,18 @@ var blockedServices = []blockedService{{
|
|||||||
"||spotifyforbrands.com^",
|
"||spotifyforbrands.com^",
|
||||||
"||spotifyjobs.com^",
|
"||spotifyjobs.com^",
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
ID: "spotify_video",
|
||||||
|
Name: "Spotify Video",
|
||||||
|
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 50 50\"><path d=\"M25.009,1.982C12.322,1.982,2,12.304,2,24.991S12.322,48,25.009,48s23.009-10.321,23.009-23.009S37.696,1.982,25.009,1.982z M34.748,35.333c-0.289,0.434-0.765,0.668-1.25,0.668c-0.286,0-0.575-0.081-0.831-0.252C30.194,34.1,26,33,22.5,33.001 c-3.714,0.002-6.498,0.914-6.526,0.923c-0.784,0.266-1.635-0.162-1.897-0.948s0.163-1.636,0.949-1.897 c0.132-0.044,3.279-1.075,7.474-1.077C26,30,30.868,30.944,34.332,33.253C35.022,33.713,35.208,34.644,34.748,35.333z M37.74,29.193 c-0.325,0.522-0.886,0.809-1.459,0.809c-0.31,0-0.624-0.083-0.906-0.26c-4.484-2.794-9.092-3.385-13.062-3.35 c-4.482,0.04-8.066,0.895-8.127,0.913c-0.907,0.258-1.861-0.272-2.12-1.183c-0.259-0.913,0.272-1.862,1.184-2.12 c0.277-0.079,3.854-0.959,8.751-1c4.465-0.037,10.029,0.61,15.191,3.826C37.995,27.328,38.242,28.388,37.74,29.193z M40.725,22.013 C40.352,22.647,39.684,23,38.998,23c-0.344,0-0.692-0.089-1.011-0.275c-5.226-3.068-11.58-3.719-15.99-3.725 c-0.021,0-0.042,0-0.063,0c-5.333,0-9.44,0.938-9.481,0.948c-1.078,0.247-2.151-0.419-2.401-1.495 c-0.25-1.075,0.417-2.149,1.492-2.4C11.729,16.01,16.117,15,21.934,15c0.023,0,0.046,0,0.069,0 c4.905,0.007,12.011,0.753,18.01,4.275C40.965,19.835,41.284,21.061,40.725,22.013z\" /></svg>"),
|
||||||
|
Rules: []string{
|
||||||
|
"||eip-ntt.video-ak.cdn.spotify.com.akahost.net^",
|
||||||
|
"||video-ak.cdn.spotify.com^",
|
||||||
|
"||video-akpcw-cdn-spotify-com.akamaized.net^",
|
||||||
|
"||video-akpcw.spotifycdn.com.edgesuite.net^",
|
||||||
|
"||video-akpcw.spotifycdn.com^",
|
||||||
|
"||video-fa.scdn.co^",
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
ID: "steam",
|
ID: "steam",
|
||||||
Name: "Steam",
|
Name: "Steam",
|
||||||
@@ -2748,7 +2765,9 @@ var blockedServices = []blockedService{{
|
|||||||
Rules: []string{
|
Rules: []string{
|
||||||
"||xhscdn.com^",
|
"||xhscdn.com^",
|
||||||
"||xhscdn.net^",
|
"||xhscdn.net^",
|
||||||
|
"||xiaohongshu.com.my^",
|
||||||
"||xiaohongshu.com^",
|
"||xiaohongshu.com^",
|
||||||
|
"||xiaohongshu.net^",
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
ID: "youtube",
|
ID: "youtube",
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package home
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -11,7 +13,9 @@ import (
|
|||||||
|
|
||||||
"github.com/AdguardTeam/golibs/ioutil"
|
"github.com/AdguardTeam/golibs/ioutil"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/josharian/native"
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/httputil"
|
||||||
|
"github.com/AdguardTeam/golibs/timeutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GLMode - enable GL-Inet compatibility mode
|
// GLMode - enable GL-Inet compatibility mode
|
||||||
@@ -97,8 +101,7 @@ func glGetTokenDate(file string) uint32 {
|
|||||||
|
|
||||||
buf := bytes.NewBuffer(bs)
|
buf := bytes.NewBuffer(bs)
|
||||||
|
|
||||||
// TODO(a.garipov): Get rid of github.com/josharian/native dependency.
|
err = binary.Read(buf, binary.NativeEndian, &dateToken)
|
||||||
err = binary.Read(buf, native.Endian, &dateToken)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("decoding token: %s", err)
|
log.Error("decoding token: %s", err)
|
||||||
|
|
||||||
@@ -107,3 +110,125 @@ func glGetTokenDate(file string) uint32 {
|
|||||||
|
|
||||||
return dateToken
|
return dateToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// authMiddlewareGLiNetConfig is the configuration structure for the GLiNet
|
||||||
|
// authentication middleware.
|
||||||
|
type authMiddlewareGLiNetConfig struct {
|
||||||
|
// logger is used for logging the operation of the middleware. It must not
|
||||||
|
// be nil.
|
||||||
|
//
|
||||||
|
// TODO(s.chzhen): Use logger from the context.
|
||||||
|
logger *slog.Logger
|
||||||
|
|
||||||
|
// clock is used to get the current time. It must not be nil.
|
||||||
|
clock timeutil.Clock
|
||||||
|
|
||||||
|
// tokenFilePrefix is the prefix of the filepath where the authentication
|
||||||
|
// token is stored. It must not be empty.
|
||||||
|
tokenFilePrefix string
|
||||||
|
|
||||||
|
// ttl is the TTL (Time To Live) of the authentication token. It must be
|
||||||
|
// greater than zero.
|
||||||
|
ttl time.Duration
|
||||||
|
|
||||||
|
// maxTokenSize is the maximum size of the file containing the
|
||||||
|
// authentication token. It must be greater than zero.
|
||||||
|
maxTokenSize uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// authMiddlewareGLiNet is the GLiNet authentication middleware. It checks if
|
||||||
|
// the request is authenticated using a cookie.
|
||||||
|
type authMiddlewareGLiNet struct {
|
||||||
|
logger *slog.Logger
|
||||||
|
clock timeutil.Clock
|
||||||
|
tokenFilePrefix string
|
||||||
|
ttl time.Duration
|
||||||
|
maxTokenSize uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// newAuthMiddlewareGLiNet returns the new properly initialized
|
||||||
|
// *authMiddlewareGLiNet.
|
||||||
|
func newAuthMiddlewareGLiNet(c *authMiddlewareGLiNetConfig) (mw *authMiddlewareGLiNet) {
|
||||||
|
return &authMiddlewareGLiNet{
|
||||||
|
logger: c.logger,
|
||||||
|
clock: c.clock,
|
||||||
|
tokenFilePrefix: c.tokenFilePrefix,
|
||||||
|
ttl: c.ttl,
|
||||||
|
maxTokenSize: c.maxTokenSize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ httputil.Middleware = (*authMiddlewareGLiNet)(nil)
|
||||||
|
|
||||||
|
// Wrap implements the [httputil.Middleware] interface for
|
||||||
|
// *authMiddlewareGLiNet.
|
||||||
|
func (mw *authMiddlewareGLiNet) Wrap(h http.Handler) (wrapped http.Handler) {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
if mw.isAuthenticated(ctx, r) {
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// isAuthenticated returns true if the request is authenticated using a cookie.
|
||||||
|
//
|
||||||
|
// TODO(s.chzhen): Use the request's path.
|
||||||
|
func (mw *authMiddlewareGLiNet) isAuthenticated(ctx context.Context, r *http.Request) (ok bool) {
|
||||||
|
c, err := r.Cookie(glCookieName)
|
||||||
|
if err == http.ErrNoCookie {
|
||||||
|
mw.logger.ErrorContext(ctx, "no authentication cookie", slogutil.KeyError, err)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return mw.checkToken(ctx, c.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkToken verifies the validity of an authentication token. It retrieves
|
||||||
|
// the time stored in a file named after the token and checks if the token has
|
||||||
|
// expired based on that time.
|
||||||
|
func (mw *authMiddlewareGLiNet) checkToken(ctx context.Context, token string) (ok bool) {
|
||||||
|
tokenFile := mw.tokenFilePrefix + token
|
||||||
|
tokenDate := mw.tokenDate(ctx, tokenFile)
|
||||||
|
now := mw.clock.Now()
|
||||||
|
if now.Before(tokenDate.Add(mw.ttl)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
mw.logger.DebugContext(ctx, "authentication token has expired")
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// tokenDate returns the time stored in the authentication token file. If there
|
||||||
|
// is an error, it logs the error and returns the zero time.
|
||||||
|
func (mw *authMiddlewareGLiNet) tokenDate(ctx context.Context, tokenFile string) (t time.Time) {
|
||||||
|
f, err := os.Open(tokenFile)
|
||||||
|
if err != nil {
|
||||||
|
mw.logger.ErrorContext(ctx, "opening token file", slogutil.KeyError, err)
|
||||||
|
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
defer slogutil.CloseAndLog(ctx, mw.logger, f, slog.LevelError)
|
||||||
|
|
||||||
|
// Create a 4-byte long buffer to store Unix time as a uint32, since GL.iNet
|
||||||
|
// routers use it as part of an authentication mechanism.
|
||||||
|
//
|
||||||
|
// See https://github.com/AdguardTeam/AdGuardHome/issues/1853.
|
||||||
|
data := make([]byte, 4)
|
||||||
|
_, err = io.ReadFull(f, data)
|
||||||
|
if err != nil {
|
||||||
|
mw.logger.ErrorContext(ctx, "reading token file", slogutil.KeyError, err)
|
||||||
|
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Unix(int64(binary.NativeEndian.Uint32(data)), 0)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,84 @@
|
|||||||
package home
|
package home
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/josharian/native"
|
"github.com/AdguardTeam/golibs/timeutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestAuthMiddlewareGLiNet(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
const (
|
||||||
|
testTTL = 60 * time.Second
|
||||||
|
|
||||||
|
glTokenFileSuffix = "test"
|
||||||
|
)
|
||||||
|
|
||||||
|
tempDir := t.TempDir()
|
||||||
|
glFilePrefix = tempDir + "/gl_token_"
|
||||||
|
glTokenFile := glFilePrefix + glTokenFileSuffix
|
||||||
|
|
||||||
|
glFileData := make([]byte, 4)
|
||||||
|
binary.NativeEndian.PutUint32(glFileData, uint32(time.Now().Add(testTTL).Unix()))
|
||||||
|
|
||||||
|
err := os.WriteFile(glTokenFile, glFileData, 0o644)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
mw := newAuthMiddlewareGLiNet(&authMiddlewareGLiNetConfig{
|
||||||
|
logger: testLogger,
|
||||||
|
clock: timeutil.SystemClock{},
|
||||||
|
tokenFilePrefix: glFilePrefix,
|
||||||
|
maxTokenSize: MaxFileSize,
|
||||||
|
ttl: testTTL,
|
||||||
|
})
|
||||||
|
|
||||||
|
h := &testAuthHandler{}
|
||||||
|
wrapped := mw.Wrap(h)
|
||||||
|
|
||||||
|
reqValidCookie := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
reqValidCookie.AddCookie(&http.Cookie{Name: glCookieName, Value: glTokenFileSuffix})
|
||||||
|
|
||||||
|
reqInvalidCookie := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
reqInvalidCookie.AddCookie(&http.Cookie{Name: glCookieName, Value: "invalid_cookie"})
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
req *http.Request
|
||||||
|
name string
|
||||||
|
wantCode int
|
||||||
|
}{{
|
||||||
|
req: httptest.NewRequest(http.MethodGet, "/", nil),
|
||||||
|
name: "no_cookie",
|
||||||
|
wantCode: http.StatusUnauthorized,
|
||||||
|
}, {
|
||||||
|
req: reqValidCookie,
|
||||||
|
name: "valid_cookie",
|
||||||
|
wantCode: http.StatusOK,
|
||||||
|
}, {
|
||||||
|
req: reqInvalidCookie,
|
||||||
|
name: "invalid_cookie",
|
||||||
|
wantCode: http.StatusUnauthorized,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
wrapped.ServeHTTP(w, tc.req)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.wantCode, w.Code)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAuthGL(t *testing.T) {
|
func TestAuthGL(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
|
|
||||||
@@ -19,13 +87,13 @@ func TestAuthGL(t *testing.T) {
|
|||||||
glFilePrefix = dir + "/gl_token_"
|
glFilePrefix = dir + "/gl_token_"
|
||||||
|
|
||||||
data := make([]byte, 4)
|
data := make([]byte, 4)
|
||||||
native.Endian.PutUint32(data, 1)
|
binary.NativeEndian.PutUint32(data, 1)
|
||||||
|
|
||||||
require.NoError(t, os.WriteFile(glFilePrefix+"test", data, 0o644))
|
require.NoError(t, os.WriteFile(glFilePrefix+"test", data, 0o644))
|
||||||
assert.False(t, glCheckToken("test"))
|
assert.False(t, glCheckToken("test"))
|
||||||
|
|
||||||
data = make([]byte, 4)
|
data = make([]byte, 4)
|
||||||
native.Endian.PutUint32(data, uint32(time.Now().UTC().Unix()+60))
|
binary.NativeEndian.PutUint32(data, uint32(time.Now().UTC().Unix()+60))
|
||||||
|
|
||||||
require.NoError(t, os.WriteFile(glFilePrefix+"test", data, 0o644))
|
require.NoError(t, os.WriteFile(glFilePrefix+"test", data, 0o644))
|
||||||
r, _ := http.NewRequest(http.MethodGet, "http://localhost/", nil)
|
r, _ := http.NewRequest(http.MethodGet, "http://localhost/", nil)
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package home
|
package home
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"path"
|
"path"
|
||||||
@@ -12,11 +14,15 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/aghuser"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/httphdr"
|
"github.com/AdguardTeam/golibs/httphdr"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/httputil"
|
||||||
"github.com/AdguardTeam/golibs/timeutil"
|
"github.com/AdguardTeam/golibs/timeutil"
|
||||||
|
"github.com/AdguardTeam/golibs/validate"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cookieTTL is the time-to-live of the session cookie.
|
// cookieTTL is the time-to-live of the session cookie.
|
||||||
@@ -348,3 +354,158 @@ func (a *authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
func optionalAuthHandler(handler http.Handler) http.Handler {
|
func optionalAuthHandler(handler http.Handler) http.Handler {
|
||||||
return &authHandler{handler}
|
return &authHandler{handler}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// errInvalidLogin is returned when there is an invalid login attempt.
|
||||||
|
errInvalidLogin errors.Error = "invalid username or password"
|
||||||
|
)
|
||||||
|
|
||||||
|
// authMiddlewareDefaultConfig is the configuration structure for the default
|
||||||
|
// authentication middleware.
|
||||||
|
type authMiddlewareDefaultConfig struct {
|
||||||
|
// logger is used for logging the operation of the middleware. It must not
|
||||||
|
// be nil.
|
||||||
|
logger *slog.Logger
|
||||||
|
|
||||||
|
// sessions contains web user sessions. It must not be nil.
|
||||||
|
sessions aghuser.SessionStorage
|
||||||
|
|
||||||
|
// users contains web user information. It must not be nil.
|
||||||
|
users aghuser.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// authMiddlewareDefault is the default authentication middleware. It searches
|
||||||
|
// for a web client using an authentication cookie or basic auth credentials and
|
||||||
|
// passes it with the context.
|
||||||
|
type authMiddlewareDefault struct {
|
||||||
|
logger *slog.Logger
|
||||||
|
sessions aghuser.SessionStorage
|
||||||
|
users aghuser.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// newAuthMiddlewareDefault returns the new properly initialized
|
||||||
|
// *authMiddlewareDefault.
|
||||||
|
func newAuthMiddlewareDefault(c *authMiddlewareDefaultConfig) (mw *authMiddlewareDefault) {
|
||||||
|
return &authMiddlewareDefault{
|
||||||
|
logger: c.logger,
|
||||||
|
sessions: c.sessions,
|
||||||
|
users: c.users,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ httputil.Middleware = (*authMiddlewareDefault)(nil)
|
||||||
|
|
||||||
|
// Wrap implements the [httputil.Middleware] interface for
|
||||||
|
// *authMiddlewareDefault.
|
||||||
|
func (mw *authMiddlewareDefault) Wrap(h http.Handler) (wrapped http.Handler) {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
if !mw.needsAuthentication(ctx, r) {
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := mw.userFromRequest(ctx, r)
|
||||||
|
if u != nil {
|
||||||
|
h.ServeHTTP(w, r.WithContext(withWebUser(ctx, u)))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
mw.logger.ErrorContext(ctx, "retrieving user from request", slogutil.KeyError, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// needsAuthentication returns true if the current request requires
|
||||||
|
// authentication.
|
||||||
|
//
|
||||||
|
// TODO(s.chzhen): Use the request's path.
|
||||||
|
func (mw *authMiddlewareDefault) needsAuthentication(
|
||||||
|
ctx context.Context,
|
||||||
|
_ *http.Request,
|
||||||
|
) (ok bool) {
|
||||||
|
users, err := mw.users.All(ctx)
|
||||||
|
if err != nil {
|
||||||
|
// Should not happen.
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(users) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// userFromRequest tries to retrieve a user based on the request.
|
||||||
|
func (mw *authMiddlewareDefault) userFromRequest(
|
||||||
|
ctx context.Context,
|
||||||
|
r *http.Request,
|
||||||
|
) (u *aghuser.User, err error) {
|
||||||
|
defer func() { err = errors.Annotate(err, "getting user from request: %w") }()
|
||||||
|
|
||||||
|
cookie, err := r.Cookie(sessionCookieName)
|
||||||
|
if err == http.ErrNoCookie {
|
||||||
|
return mw.userFromRequestBasicAuth(ctx, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
sess, err := hex.DecodeString(cookie.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("decoding cookie: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l := aghuser.SessionTokenLength
|
||||||
|
|
||||||
|
// TODO(a.garipov): Add validate.Len.
|
||||||
|
err = validate.InRange("token length", len(sess), l, l)
|
||||||
|
if err != nil {
|
||||||
|
// Don't wrap the error because it's informative enough as is.
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := aghuser.SessionToken(sess)
|
||||||
|
s, err := mw.sessions.FindByToken(ctx, t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("searching session by token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err = mw.users.ByLogin(ctx, s.UserLogin)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("searching user by login %q: %w", s.UserLogin, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// userFromRequestBasicAuth searches for a user using Basic Auth credentials.
|
||||||
|
func (mw *authMiddlewareDefault) userFromRequestBasicAuth(
|
||||||
|
ctx context.Context,
|
||||||
|
r *http.Request,
|
||||||
|
) (user *aghuser.User, err error) {
|
||||||
|
login, pass, ok := r.BasicAuth()
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("credentials: %w", errors.ErrNoValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
user, _ = mw.users.ByLogin(ctx, aghuser.Login(login))
|
||||||
|
if user == nil {
|
||||||
|
return nil, errInvalidLogin
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = user.Password.Authenticate(ctx, pass)
|
||||||
|
if !ok {
|
||||||
|
return nil, errInvalidLogin
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,19 +1,612 @@
|
|||||||
package home
|
package home
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"maps"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/aghuser"
|
||||||
"github.com/AdguardTeam/golibs/httphdr"
|
"github.com/AdguardTeam/golibs/httphdr"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// testSessionStorage is the mock implementation of the [aghuser.SessionStorage]
|
||||||
|
// interface.
|
||||||
|
type testSessionStorage struct {
|
||||||
|
onNew func(ctx context.Context, u *aghuser.User) (s *aghuser.Session, err error)
|
||||||
|
onFindByToken func(
|
||||||
|
ctx context.Context,
|
||||||
|
t aghuser.SessionToken,
|
||||||
|
) (s *aghuser.Session, err error)
|
||||||
|
onDeleteByToken func(ctx context.Context, t aghuser.SessionToken) (err error)
|
||||||
|
onClose func() (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ aghuser.SessionStorage = (*testSessionStorage)(nil)
|
||||||
|
|
||||||
|
// newTestSessionStorage returns a new *testSessionStorage all methods of which
|
||||||
|
// panic.
|
||||||
|
func newTestSessionStorage() (ts *testSessionStorage) {
|
||||||
|
return &testSessionStorage{
|
||||||
|
onNew: func(_ context.Context, u *aghuser.User) (_ *aghuser.Session, _ error) {
|
||||||
|
panic(fmt.Errorf("unexpected call to testSessionStorage.New(%v)", u))
|
||||||
|
},
|
||||||
|
onFindByToken: func(
|
||||||
|
_ context.Context,
|
||||||
|
t aghuser.SessionToken,
|
||||||
|
) (_ *aghuser.Session, err error) {
|
||||||
|
panic(fmt.Errorf("unexpected call to testSessionStorage.FindByToken(%v)", t))
|
||||||
|
},
|
||||||
|
onDeleteByToken: func(_ context.Context, t aghuser.SessionToken) (_ error) {
|
||||||
|
panic(fmt.Errorf("unexpected call to testSessionStorage.DeleteByToken(%v)", t))
|
||||||
|
},
|
||||||
|
onClose: func() (_ error) {
|
||||||
|
panic("unexpected call to testSessionStorage.Close")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New implements the [aghuser.SessionStorage] interface for
|
||||||
|
// *testSessionStorage.
|
||||||
|
func (ts *testSessionStorage) New(
|
||||||
|
ctx context.Context,
|
||||||
|
u *aghuser.User,
|
||||||
|
) (s *aghuser.Session, err error) {
|
||||||
|
return ts.onNew(ctx, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindByToken implements the [aghuser.SessionStorage] interface for
|
||||||
|
// *testSessionStorage.
|
||||||
|
func (ts *testSessionStorage) FindByToken(
|
||||||
|
ctx context.Context,
|
||||||
|
t aghuser.SessionToken,
|
||||||
|
) (s *aghuser.Session, err error) {
|
||||||
|
return ts.onFindByToken(ctx, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteByToken implements the [aghuser.SessionStorage] interface for
|
||||||
|
// *testSessionStorage.
|
||||||
|
func (ts *testSessionStorage) DeleteByToken(
|
||||||
|
ctx context.Context,
|
||||||
|
t aghuser.SessionToken,
|
||||||
|
) (err error) {
|
||||||
|
return ts.onDeleteByToken(ctx, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close implements the [aghuser.SessionStorage] interface for
|
||||||
|
// *testSessionStorage.
|
||||||
|
func (ts *testSessionStorage) Close() (err error) {
|
||||||
|
return ts.onClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
// testUsersDB is the mock implementation of the [aghuser.DB] interface.
|
||||||
|
type testUsersDB struct {
|
||||||
|
onAll func(ctx context.Context) (users []*aghuser.User, err error)
|
||||||
|
onByLogin func(ctx context.Context, login aghuser.Login) (u *aghuser.User, err error)
|
||||||
|
onByUUID func(ctx context.Context, id aghuser.UserID) (u *aghuser.User, err error)
|
||||||
|
onCreate func(ctx context.Context, u *aghuser.User) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newTestUsersDB returns a new *testUsersDB all methods of which panic.
|
||||||
|
func newTestUsersDB() (ts *testUsersDB) {
|
||||||
|
return &testUsersDB{
|
||||||
|
onAll: func(_ context.Context) (_ []*aghuser.User, _ error) {
|
||||||
|
panic("unexpected call to testUsersDB.All")
|
||||||
|
},
|
||||||
|
onByLogin: func(_ context.Context, l aghuser.Login) (_ *aghuser.User, _ error) {
|
||||||
|
panic(fmt.Errorf("unexpected call to testUsersDB.ByLogin(%v)", l))
|
||||||
|
},
|
||||||
|
onByUUID: func(_ context.Context, id aghuser.UserID) (_ *aghuser.User, _ error) {
|
||||||
|
panic(fmt.Errorf("unexpected call to testUsersDB.ByUUID(%v)", id))
|
||||||
|
},
|
||||||
|
onCreate: func(_ context.Context, u *aghuser.User) (_ error) {
|
||||||
|
panic(fmt.Errorf("unexpected call to testUsersDB.Create(%v)", u))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ aghuser.DB = (*testUsersDB)(nil)
|
||||||
|
|
||||||
|
// All implements the [aghuser.DB] interface for *testUsersDB.
|
||||||
|
func (db *testUsersDB) All(ctx context.Context) (users []*aghuser.User, err error) {
|
||||||
|
return db.onAll(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByLogin implements the [aghuser.DB] interface for *testUsersDB.
|
||||||
|
func (db *testUsersDB) ByLogin(
|
||||||
|
ctx context.Context,
|
||||||
|
login aghuser.Login,
|
||||||
|
) (u *aghuser.User, err error) {
|
||||||
|
return db.onByLogin(ctx, login)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByUUID implements the [aghuser.DB] interface for *testUsersDB.
|
||||||
|
func (db *testUsersDB) ByUUID(ctx context.Context, id aghuser.UserID) (u *aghuser.User, err error) {
|
||||||
|
return db.onByUUID(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create implements the [aghuser.DB] interface for *testUsersDB.
|
||||||
|
func (db *testUsersDB) Create(ctx context.Context, u *aghuser.User) (err error) {
|
||||||
|
return db.onCreate(ctx, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
// testAuthHandler is a helper handler used for testing HTTP middleware.
|
||||||
|
type testAuthHandler struct {
|
||||||
|
user *aghuser.User
|
||||||
|
called bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ http.Handler = (*testAuthHandler)(nil)
|
||||||
|
|
||||||
|
// ServeHTTP implements the [http.Handler] interface for *testAuthHandler.
|
||||||
|
func (h *testAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
h.called = true
|
||||||
|
h.user, _ = webUserFromContext(r.Context())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAuthMiddlewareDefault_firstRun(t *testing.T) {
|
||||||
|
db := newTestUsersDB()
|
||||||
|
db.onAll = func(_ context.Context) (users []*aghuser.User, err error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mw := newAuthMiddlewareDefault(&authMiddlewareDefaultConfig{
|
||||||
|
logger: testLogger,
|
||||||
|
sessions: &testSessionStorage{},
|
||||||
|
users: db,
|
||||||
|
})
|
||||||
|
|
||||||
|
h := &testAuthHandler{}
|
||||||
|
wrapped := mw.Wrap(h)
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
r := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
wrapped.ServeHTTP(w, r)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
assert.True(t, h.called)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAuthMiddlewareDefault(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
const (
|
||||||
|
login aghuser.Login = "user_login"
|
||||||
|
|
||||||
|
passwordRaw = "user_password"
|
||||||
|
)
|
||||||
|
|
||||||
|
passwordHash, err := bcrypt.GenerateFromPassword(
|
||||||
|
[]byte(passwordRaw),
|
||||||
|
bcrypt.DefaultCost,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
user := &aghuser.User{
|
||||||
|
Login: login,
|
||||||
|
Password: aghuser.NewDefaultPassword(string(passwordHash)),
|
||||||
|
}
|
||||||
|
|
||||||
|
var token aghuser.SessionToken
|
||||||
|
_, _ = rand.Read(token[:])
|
||||||
|
|
||||||
|
tokenHex := hex.EncodeToString(token[:])
|
||||||
|
|
||||||
|
users := map[aghuser.Login]*aghuser.User{login: user}
|
||||||
|
usersDB := newTestUsersDB()
|
||||||
|
usersDB.onAll = func(_ context.Context) (us []*aghuser.User, err error) {
|
||||||
|
return slices.Collect(maps.Values(users)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
usersDB.onByLogin = func(_ context.Context, login aghuser.Login) (u *aghuser.User, err error) {
|
||||||
|
return users[login], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sessions := map[aghuser.SessionToken]*aghuser.Session{
|
||||||
|
token: {
|
||||||
|
UserLogin: login,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ts := newTestSessionStorage()
|
||||||
|
ts.onFindByToken = func(
|
||||||
|
_ context.Context,
|
||||||
|
t aghuser.SessionToken,
|
||||||
|
) (s *aghuser.Session, err error) {
|
||||||
|
return sessions[t], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mw := newAuthMiddlewareDefault(&authMiddlewareDefaultConfig{
|
||||||
|
logger: testLogger,
|
||||||
|
sessions: ts,
|
||||||
|
users: usersDB,
|
||||||
|
})
|
||||||
|
|
||||||
|
reqCookie := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
reqCookie.AddCookie(&http.Cookie{Name: sessionCookieName, Value: tokenHex})
|
||||||
|
|
||||||
|
reqInvalidCookie := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
reqInvalidCookie.AddCookie(&http.Cookie{Name: sessionCookieName, Value: "invalid_cookie"})
|
||||||
|
|
||||||
|
reqBasicAuth := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
reqBasicAuth.SetBasicAuth(string(login), passwordRaw)
|
||||||
|
|
||||||
|
reqInvalidPassBasicAuth := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
reqInvalidPassBasicAuth.SetBasicAuth(string(login), "invalid_password")
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
req *http.Request
|
||||||
|
wantUser *aghuser.User
|
||||||
|
name string
|
||||||
|
wantCode int
|
||||||
|
}{{
|
||||||
|
req: httptest.NewRequest(http.MethodGet, "/", nil),
|
||||||
|
wantUser: nil,
|
||||||
|
name: "no_auth",
|
||||||
|
wantCode: http.StatusUnauthorized,
|
||||||
|
}, {
|
||||||
|
req: reqCookie,
|
||||||
|
wantUser: user,
|
||||||
|
name: "cookie",
|
||||||
|
wantCode: http.StatusOK,
|
||||||
|
}, {
|
||||||
|
req: reqBasicAuth,
|
||||||
|
wantUser: user,
|
||||||
|
name: "basic_auth",
|
||||||
|
wantCode: http.StatusOK,
|
||||||
|
}, {
|
||||||
|
req: reqInvalidCookie,
|
||||||
|
wantUser: nil,
|
||||||
|
name: "invalid_cookie",
|
||||||
|
wantCode: http.StatusUnauthorized,
|
||||||
|
}, {
|
||||||
|
req: reqInvalidPassBasicAuth,
|
||||||
|
wantUser: nil,
|
||||||
|
name: "invalid_basic_auth",
|
||||||
|
wantCode: http.StatusUnauthorized,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
h := &testAuthHandler{}
|
||||||
|
wrapped := mw.Wrap(h)
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
wrapped.ServeHTTP(w, tc.req)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.wantCode, w.Code)
|
||||||
|
assert.Equal(t, tc.wantUser, h.user)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAuth_ServeHTTP_firstRun(t *testing.T) {
|
||||||
|
storeGlobals(t)
|
||||||
|
|
||||||
|
globalContext.firstRun = true
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
globalContext.mux = mux
|
||||||
|
|
||||||
|
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||||
|
web, err := initWeb(ctx, options{}, nil, nil, testLogger, nil, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
globalContext.web = web
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
path string
|
||||||
|
method string
|
||||||
|
wantCode int
|
||||||
|
}{{
|
||||||
|
name: "root",
|
||||||
|
path: "/",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}, {
|
||||||
|
name: "doh_mobileconfig",
|
||||||
|
path: "/apple/doh.mobileconfig",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}, {
|
||||||
|
name: "dot_mobileconfig",
|
||||||
|
path: "/apple/dot.mobileconfig",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}, {
|
||||||
|
name: "change_language",
|
||||||
|
path: "/control/i18n/change_language",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}, {
|
||||||
|
name: "current_language",
|
||||||
|
path: "/control/i18n/current_language",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}, {
|
||||||
|
name: "check_config",
|
||||||
|
path: "/control/install/check_config",
|
||||||
|
method: http.MethodPost,
|
||||||
|
wantCode: http.StatusBadRequest,
|
||||||
|
}, {
|
||||||
|
name: "configure",
|
||||||
|
path: "/control/install/configure",
|
||||||
|
method: http.MethodPost,
|
||||||
|
wantCode: http.StatusBadRequest,
|
||||||
|
}, {
|
||||||
|
name: "get_addresses",
|
||||||
|
path: "/control/install/get_addresses",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusOK,
|
||||||
|
}, {
|
||||||
|
name: "login",
|
||||||
|
path: "/control/login",
|
||||||
|
method: http.MethodPost,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}, {
|
||||||
|
name: "logout",
|
||||||
|
path: "/control/logout",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}, {
|
||||||
|
name: "profile",
|
||||||
|
path: "/control/profile",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}, {
|
||||||
|
name: "profile_update",
|
||||||
|
path: "/control/profile/update",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}, {
|
||||||
|
name: "status",
|
||||||
|
path: "/control/status",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}, {
|
||||||
|
name: "update",
|
||||||
|
path: "/control/update",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}, {
|
||||||
|
name: "version",
|
||||||
|
path: "/control/version.json",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusFound,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
r := httptest.NewRequest(tc.method, tc.path, nil)
|
||||||
|
|
||||||
|
h, pattern := mux.Handler(r)
|
||||||
|
require.NotEmpty(t, pattern)
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.wantCode, w.Code)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAuth_ServeHTTP_auth(t *testing.T) {
|
||||||
|
storeGlobals(t)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testTTL = 60
|
||||||
|
|
||||||
|
glTokenFileSuffix = "test"
|
||||||
|
|
||||||
|
userName = "name"
|
||||||
|
userPassword = "password"
|
||||||
|
)
|
||||||
|
|
||||||
|
passwordHash, err := bcrypt.GenerateFromPassword([]byte(userPassword), bcrypt.DefaultCost)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tempDir := t.TempDir()
|
||||||
|
glFilePrefix = tempDir + "/gl_token_"
|
||||||
|
glTokenFile := glFilePrefix + glTokenFileSuffix
|
||||||
|
|
||||||
|
glFileData := make([]byte, 4)
|
||||||
|
binary.NativeEndian.PutUint32(glFileData, uint32(time.Now().Unix()+testTTL))
|
||||||
|
|
||||||
|
err = os.WriteFile(glTokenFile, glFileData, 0o644)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
sessionsDB := filepath.Join(tempDir, "sessions.db")
|
||||||
|
|
||||||
|
users := []webUser{{
|
||||||
|
Name: userName,
|
||||||
|
PasswordHash: string(passwordHash),
|
||||||
|
}}
|
||||||
|
auth := InitAuth(sessionsDB, users, testTTL, nil, nil)
|
||||||
|
t.Cleanup(auth.Close)
|
||||||
|
globalContext.auth = auth
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
globalContext.mux = mux
|
||||||
|
|
||||||
|
tlsMgr, err := newTLSManager(testutil.ContextWithTimeout(t, testTimeout), &tlsManagerConfig{
|
||||||
|
logger: testLogger,
|
||||||
|
configModified: func() {},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||||
|
web, err := initWeb(ctx, options{}, nil, nil, testLogger, tlsMgr, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
globalContext.web = web
|
||||||
|
|
||||||
|
loginCookie := generateAuthCookie(t, mux, userName, userPassword)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
path string
|
||||||
|
method string
|
||||||
|
wantCode int
|
||||||
|
}{{
|
||||||
|
name: "change_language",
|
||||||
|
path: "/control/i18n/change_language",
|
||||||
|
method: http.MethodPost,
|
||||||
|
wantCode: http.StatusInternalServerError,
|
||||||
|
}, {
|
||||||
|
name: "current_language",
|
||||||
|
path: "/control/i18n/current_language",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusOK,
|
||||||
|
}, {
|
||||||
|
name: "profile",
|
||||||
|
path: "/control/profile",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusOK,
|
||||||
|
}, {
|
||||||
|
name: "profile_update",
|
||||||
|
path: "/control/profile/update",
|
||||||
|
method: http.MethodPut,
|
||||||
|
wantCode: http.StatusBadRequest,
|
||||||
|
}, {
|
||||||
|
name: "status",
|
||||||
|
path: "/control/status",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusOK,
|
||||||
|
}, {
|
||||||
|
name: "version",
|
||||||
|
path: "/control/version.json",
|
||||||
|
method: http.MethodGet,
|
||||||
|
wantCode: http.StatusOK,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.path, func(t *testing.T) {
|
||||||
|
r := httptest.NewRequest(tc.method, tc.path, nil)
|
||||||
|
assertHandlerStatusCode(t, mux, r, http.StatusForbidden)
|
||||||
|
|
||||||
|
r = httptest.NewRequest(tc.method, tc.path, nil)
|
||||||
|
r.SetBasicAuth(userName, userPassword)
|
||||||
|
assertHandlerStatusCode(t, mux, r, tc.wantCode)
|
||||||
|
|
||||||
|
r = httptest.NewRequest(tc.method, tc.path, nil)
|
||||||
|
r.AddCookie(loginCookie)
|
||||||
|
assertHandlerStatusCode(t, mux, r, tc.wantCode)
|
||||||
|
|
||||||
|
GLMode = true
|
||||||
|
t.Cleanup(func() { GLMode = false })
|
||||||
|
|
||||||
|
r.AddCookie(&http.Cookie{Name: glCookieName, Value: "test"})
|
||||||
|
assertHandlerStatusCode(t, mux, r, tc.wantCode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateAuthCookie is a helper function that logs in with the provided
|
||||||
|
// credentials and returns the resulting authentication cookie.
|
||||||
|
func generateAuthCookie(t *testing.T, mux *http.ServeMux, name, password string) (ac *http.Cookie) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
creds, err := json.Marshal(&loginJSON{Name: name, Password: password})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
r := httptest.NewRequest(http.MethodPost, "/control/login", bytes.NewReader(creds))
|
||||||
|
r.Header.Set(httphdr.ContentType, aghhttp.HdrValApplicationJSON)
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
mux.ServeHTTP(w, r)
|
||||||
|
|
||||||
|
for _, c := range w.Result().Cookies() {
|
||||||
|
if c.Name == sessionCookieName {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertHandlerStatusCode is a helper function that asserts the response status
|
||||||
|
// code of a HTTP handler.
|
||||||
|
func assertHandlerStatusCode(t *testing.T, h http.Handler, r *http.Request, wantCode int) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
|
||||||
|
assert.Equal(t, wantCode, w.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAuth_ServeHTTP_logout(t *testing.T) {
|
||||||
|
storeGlobals(t)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testTTL = 60
|
||||||
|
|
||||||
|
userName = "name"
|
||||||
|
userPassword = "password"
|
||||||
|
)
|
||||||
|
|
||||||
|
passwordHash, err := bcrypt.GenerateFromPassword([]byte(userPassword), bcrypt.DefaultCost)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
sessionsDB := filepath.Join(t.TempDir(), "sessions.db")
|
||||||
|
|
||||||
|
users := []webUser{{
|
||||||
|
Name: userName,
|
||||||
|
PasswordHash: string(passwordHash),
|
||||||
|
}}
|
||||||
|
auth := InitAuth(sessionsDB, users, testTTL, nil, nil)
|
||||||
|
t.Cleanup(auth.Close)
|
||||||
|
globalContext.auth = auth
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
globalContext.mux = mux
|
||||||
|
|
||||||
|
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||||
|
web, err := initWeb(ctx, options{}, nil, nil, testLogger, nil, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
globalContext.web = web
|
||||||
|
|
||||||
|
loginCookie := generateAuthCookie(t, mux, userName, userPassword)
|
||||||
|
require.NotNil(t, loginCookie)
|
||||||
|
|
||||||
|
r := httptest.NewRequest(http.MethodGet, "/control/profile", nil)
|
||||||
|
r.AddCookie(loginCookie)
|
||||||
|
assertHandlerStatusCode(t, mux, r, http.StatusOK)
|
||||||
|
|
||||||
|
r = httptest.NewRequest(http.MethodGet, "/control/logout", nil)
|
||||||
|
r.AddCookie(loginCookie)
|
||||||
|
assertHandlerStatusCode(t, mux, r, http.StatusFound)
|
||||||
|
|
||||||
|
r = httptest.NewRequest(http.MethodGet, "/control/profile", nil)
|
||||||
|
r.AddCookie(loginCookie)
|
||||||
|
assertHandlerStatusCode(t, mux, r, http.StatusForbidden)
|
||||||
|
}
|
||||||
|
|
||||||
// implements http.ResponseWriter
|
// implements http.ResponseWriter
|
||||||
type testResponseWriter struct {
|
type testResponseWriter struct {
|
||||||
hdr http.Header
|
hdr http.Header
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/client"
|
"github.com/AdguardTeam/AdGuardHome/internal/client"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -22,7 +21,7 @@ func newClientsContainer(t *testing.T) (c *clientsContainer) {
|
|||||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||||
err := c.Init(
|
err := c.Init(
|
||||||
ctx,
|
ctx,
|
||||||
slogutil.NewDiscardLogger(),
|
testLogger,
|
||||||
nil,
|
nil,
|
||||||
client.EmptyDHCP{},
|
client.EmptyDHCP{},
|
||||||
nil,
|
nil,
|
||||||
|
|||||||
56
internal/home/context.go
Normal file
56
internal/home/context.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package home
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/aghuser"
|
||||||
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ctxKey is the type for context keys within this package.
|
||||||
|
type ctxKey uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
ctxKeyWebUser ctxKey = iota
|
||||||
|
)
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ fmt.Stringer = ctxKey(0)
|
||||||
|
|
||||||
|
// String implements the [fmt.Stringer] interface for ctxKey.
|
||||||
|
func (k ctxKey) String() (s string) {
|
||||||
|
switch k {
|
||||||
|
case ctxKeyWebUser:
|
||||||
|
return "ctxKeyWebUser"
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("ctx key: %w: %d", errors.ErrBadEnumValue, k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// panicBadType is a helper that panics with a message about the context key and
|
||||||
|
// the expected type.
|
||||||
|
func panicBadType(key ctxKey, v any) {
|
||||||
|
panic(fmt.Errorf("bad type for %s: %T(%[2]v)", key, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// withWebUser returns a copy of the parent context with the web user added.
|
||||||
|
func withWebUser(ctx context.Context, u *aghuser.User) (withUser context.Context) {
|
||||||
|
return context.WithValue(ctx, ctxKeyWebUser, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
// webUserFromContext returns the web user from the context, if any.
|
||||||
|
func webUserFromContext(ctx context.Context) (u *aghuser.User, ok bool) {
|
||||||
|
const key = ctxKeyWebUser
|
||||||
|
v := ctx.Value(key)
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
u, ok = v.(*aghuser.User)
|
||||||
|
if !ok {
|
||||||
|
panicBadType(key, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return u, true
|
||||||
|
}
|
||||||
@@ -3,9 +3,12 @@ package home
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var testLogger = slogutil.NewDiscardLogger()
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
initCmdLineOpts()
|
initCmdLineOpts()
|
||||||
testutil.DiscardLogOutput(m)
|
testutil.DiscardLogOutput(m)
|
||||||
|
|||||||
@@ -292,6 +292,10 @@ func handleServiceCommand(s service.Service, action string, opts options) (err e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// statusRestartOnFail is a custom status value used to indicate the service's
|
||||||
|
// state of restarting after failed start.
|
||||||
|
const statusRestartOnFail = service.StatusStopped + 1
|
||||||
|
|
||||||
// handleServiceStatusCommand handles service "status" command.
|
// handleServiceStatusCommand handles service "status" command.
|
||||||
func handleServiceStatusCommand(s service.Service) {
|
func handleServiceStatusCommand(s service.Service) {
|
||||||
status, errSt := svcStatus(s)
|
status, errSt := svcStatus(s)
|
||||||
@@ -306,6 +310,8 @@ func handleServiceStatusCommand(s service.Service) {
|
|||||||
log.Printf("service: stopped")
|
log.Printf("service: stopped")
|
||||||
case service.StatusRunning:
|
case service.StatusRunning:
|
||||||
log.Printf("service: running")
|
log.Printf("service: running")
|
||||||
|
case statusRestartOnFail:
|
||||||
|
log.Printf("service: restarting after failed start")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,12 @@
|
|||||||
package home
|
package home
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||||
"github.com/kardianos/service"
|
"github.com/kardianos/service"
|
||||||
)
|
)
|
||||||
@@ -11,54 +17,71 @@ import (
|
|||||||
// implementation if needed.
|
// implementation if needed.
|
||||||
func chooseSystem() {
|
func chooseSystem() {
|
||||||
sys := service.ChosenSystem()
|
sys := service.ChosenSystem()
|
||||||
// By default, package service uses the SysV system if it cannot detect
|
switch sys.String() {
|
||||||
// anything other, but the update-rc.d fix should not be applied on OpenWrt,
|
case "unix-systemv":
|
||||||
// so exclude it explicitly.
|
// By default, package service uses the SysV system if it cannot detect
|
||||||
//
|
// anything other, but the update-rc.d fix should not be applied on
|
||||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/4480 and
|
// OpenWrt, so exclude it explicitly.
|
||||||
// https://github.com/AdguardTeam/AdGuardHome/issues/4677.
|
//
|
||||||
if sys.String() == "unix-systemv" && !aghos.IsOpenWrt() {
|
// See https://github.com/AdguardTeam/AdGuardHome/issues/4480 and
|
||||||
service.ChooseSystem(sysvSystem{System: sys})
|
// https://github.com/AdguardTeam/AdGuardHome/issues/4677.
|
||||||
|
if !aghos.IsOpenWrt() {
|
||||||
|
service.ChooseSystem(&sysvSystem{System: sys})
|
||||||
|
}
|
||||||
|
case "linux-systemd":
|
||||||
|
service.ChooseSystem(&systemdSystem{System: sys})
|
||||||
|
default:
|
||||||
|
// Do nothing.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sysvSystem is a wrapper for service.System that wraps the service.Service
|
// sysvSystem is a wrapper for a [service.System] that returns the custom
|
||||||
// while creating a new one.
|
// implementation of the [service.Service] interface.
|
||||||
//
|
//
|
||||||
// TODO(e.burkov): File a PR to github.com/kardianos/service.
|
// TODO(e.burkov): File a PR to github.com/kardianos/service.
|
||||||
type sysvSystem struct {
|
type sysvSystem struct {
|
||||||
// System is expected to have an unexported type
|
// System must have an unexported type *service.linuxSystemService.
|
||||||
// *service.linuxSystemService.
|
|
||||||
service.System
|
service.System
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a wrapped service.Service.
|
// type check
|
||||||
func (sys sysvSystem) New(i service.Interface, c *service.Config) (s service.Service, err error) {
|
var _ service.System = (*sysvSystem)(nil)
|
||||||
|
|
||||||
|
// New implements the [service.System] interface for *sysvSystem. i and c must
|
||||||
|
// not be nil.
|
||||||
|
func (sys *sysvSystem) New(i service.Interface, c *service.Config) (s service.Service, err error) {
|
||||||
s, err = sys.System.New(i, c)
|
s, err = sys.System.New(i, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Don't wrap the error to keep it as close to the original one as
|
||||||
|
// possible.
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return sysvService{
|
return &sysvService{
|
||||||
Service: s,
|
Service: s,
|
||||||
name: c.Name,
|
name: c.Name,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// sysvService is a wrapper for a service.Service that also calls update-rc.d in
|
// sysvService is a wrapper for a SysV [service.Service] that supplements the
|
||||||
// a proper way on installing and uninstalling.
|
// installation and uninstallation.
|
||||||
type sysvService struct {
|
type sysvService struct {
|
||||||
// Service is expected to have an unexported type *service.sysv.
|
// Service must have an unexported type *service.sysv.
|
||||||
service.Service
|
service.Service
|
||||||
|
|
||||||
// name stores the name of the service to call updating script with it.
|
// name stores the name of the service to call updating script with it.
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install wraps service.Service.Install call with calling the updating script.
|
// type check
|
||||||
func (svc sysvService) Install() (err error) {
|
var _ service.Service = (*sysvService)(nil)
|
||||||
|
|
||||||
|
// Install implements the [service.Service] interface for *sysvService.
|
||||||
|
func (svc *sysvService) Install() (err error) {
|
||||||
err = svc.Service.Install()
|
err = svc.Service.Install()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Don't wrap an error since it's informative enough as is.
|
// Don't wrap the error to keep it as close to the original one as
|
||||||
|
// possible.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,12 +91,12 @@ func (svc sysvService) Install() (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uninstall wraps service.Service.Uninstall call with calling the updating
|
// Uninstall implements the [service.Service] interface for *sysvService.
|
||||||
// script.
|
func (svc *sysvService) Uninstall() (err error) {
|
||||||
func (svc sysvService) Uninstall() (err error) {
|
|
||||||
err = svc.Service.Uninstall()
|
err = svc.Service.Uninstall()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Don't wrap an error since it's informative enough as is.
|
// Don't wrap the error to keep it as close to the original one as
|
||||||
|
// possible.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,3 +105,139 @@ func (svc sysvService) Uninstall() (err error) {
|
|||||||
// Don't wrap an error since it's informative enough as is.
|
// Don't wrap an error since it's informative enough as is.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// systemdSystem is a wrapper for a [service.System] that returns the custom
|
||||||
|
// implementation of the [service.Service] interface.
|
||||||
|
type systemdSystem struct {
|
||||||
|
// System must have an unexported type *service.linuxSystemService.
|
||||||
|
service.System
|
||||||
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ service.System = (*systemdSystem)(nil)
|
||||||
|
|
||||||
|
// New implements the [service.System] interface for *systemdSystem. i and c
|
||||||
|
// must not be nil.
|
||||||
|
func (sys *systemdSystem) New(i service.Interface, c *service.Config) (s service.Service, err error) {
|
||||||
|
s, err = sys.System.New(i, c)
|
||||||
|
if err != nil {
|
||||||
|
// Don't wrap the error to keep it as close to the original one as
|
||||||
|
// possible.
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &systemdService{
|
||||||
|
Service: s,
|
||||||
|
unitName: fmt.Sprintf("%s.service", c.Name),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ service.Service = (*systemdService)(nil)
|
||||||
|
|
||||||
|
// systemdService is a wrapper for a systemd [service.Service] that enriches the
|
||||||
|
// service status information.
|
||||||
|
type systemdService struct {
|
||||||
|
// Service is expected to have an unexported type *service.systemd.
|
||||||
|
service.Service
|
||||||
|
|
||||||
|
// unitName stores the name of the systemd daemon.
|
||||||
|
unitName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ service.Service = (*systemdService)(nil)
|
||||||
|
|
||||||
|
// Status implements the [service.Service] interface for *systemdService.
|
||||||
|
func (s *systemdService) Status() (status service.Status, err error) {
|
||||||
|
cmd := exec.Command("systemctl", "show", s.unitName)
|
||||||
|
stdout, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return service.StatusUnknown, fmt.Errorf("connecting to command stdout: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = cmd.Start(); err != nil {
|
||||||
|
return service.StatusUnknown, fmt.Errorf("start command executing: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
status, err = parseSystemctlShow(stdout)
|
||||||
|
if err != nil {
|
||||||
|
return service.StatusUnknown, fmt.Errorf("parsing command output: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cmd.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return service.StatusUnknown, fmt.Errorf("executing command: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Searched property names. See man systemctl(1).
|
||||||
|
const (
|
||||||
|
propNameLoadState = "LoadState"
|
||||||
|
propNameActiveState = "ActiveState"
|
||||||
|
propNameSubState = "SubState"
|
||||||
|
)
|
||||||
|
|
||||||
|
// parseSystemctlShow parses the output of the systemctl show command. It
|
||||||
|
// expects the key=value pairs separated by newlines.
|
||||||
|
func parseSystemctlShow(output io.Reader) (status service.Status, err error) {
|
||||||
|
var loadState, activeState, subState string
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(output)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
|
||||||
|
propName, propValue, ok := strings.Cut(line, "=")
|
||||||
|
if !ok {
|
||||||
|
return service.StatusUnknown, fmt.Errorf("unexpected line format: %q", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch propName {
|
||||||
|
case propNameLoadState:
|
||||||
|
loadState = propValue
|
||||||
|
case propNameActiveState:
|
||||||
|
activeState = propValue
|
||||||
|
case propNameSubState:
|
||||||
|
subState = propValue
|
||||||
|
default:
|
||||||
|
// Go on.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = scanner.Err(); err != nil {
|
||||||
|
return service.StatusUnknown, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return statusFromState(loadState, activeState, subState)
|
||||||
|
}
|
||||||
|
|
||||||
|
// statusFromState returns the service status based on the systemctl state
|
||||||
|
// property values.
|
||||||
|
func statusFromState(loadState, activeState, subState string) (status service.Status, err error) {
|
||||||
|
// Desired property values. See man systemctl(1).
|
||||||
|
const (
|
||||||
|
propValueLoadStateNotFound = "not-found"
|
||||||
|
propValueActiveStateActive = "active"
|
||||||
|
propValueActiveStateInactive = "inactive"
|
||||||
|
propValueSubStateAutoRestart = "auto-restart"
|
||||||
|
)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case loadState == propValueLoadStateNotFound:
|
||||||
|
return service.StatusUnknown, service.ErrNotInstalled
|
||||||
|
case activeState == propValueActiveStateActive:
|
||||||
|
return service.StatusRunning, nil
|
||||||
|
case activeState == propValueActiveStateInactive:
|
||||||
|
return service.StatusStopped, nil
|
||||||
|
case subState == propValueSubStateAutoRestart:
|
||||||
|
return statusRestartOnFail, nil
|
||||||
|
default:
|
||||||
|
return service.StatusUnknown, fmt.Errorf(
|
||||||
|
"unexpected state: %s=%q, %s=%q, %s=%q",
|
||||||
|
propNameLoadState, loadState,
|
||||||
|
propNameActiveState, activeState,
|
||||||
|
propNameSubState, subState,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import (
|
|||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/client"
|
"github.com/AdguardTeam/AdGuardHome/internal/client"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
||||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/AdguardTeam/golibs/timeutil"
|
"github.com/AdguardTeam/golibs/timeutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -65,10 +64,9 @@ kXS9jgARhhiWXJrk
|
|||||||
|
|
||||||
func TestValidateCertificates(t *testing.T) {
|
func TestValidateCertificates(t *testing.T) {
|
||||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||||
logger := slogutil.NewDiscardLogger()
|
|
||||||
|
|
||||||
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
||||||
logger: logger,
|
logger: testLogger,
|
||||||
configModified: func() {},
|
configModified: func() {},
|
||||||
servePlainDNS: false,
|
servePlainDNS: false,
|
||||||
})
|
})
|
||||||
@@ -113,26 +111,41 @@ func TestValidateCertificates(t *testing.T) {
|
|||||||
// restores them once the test is complete.
|
// restores them once the test is complete.
|
||||||
//
|
//
|
||||||
// The global variables are:
|
// The global variables are:
|
||||||
// - [configuration.dns]
|
// - [GLMode]
|
||||||
// - [homeContext.clients.storage]
|
// - [config]
|
||||||
// - [homeContext.dnsServer]
|
// - [glFilePrefix]
|
||||||
// - [homeContext.mux]
|
// - [globalContext.auth]
|
||||||
|
// - [globalContext.clients.storage]
|
||||||
|
// - [globalContext.dnsServer]
|
||||||
|
// - [globalContext.firstRun]
|
||||||
|
// - [globalContext.mux]
|
||||||
|
// - [globalContext.web]
|
||||||
//
|
//
|
||||||
// TODO(s.chzhen): Remove this once the TLS manager no longer accesses global
|
// TODO(s.chzhen): Remove this once the TLS manager no longer accesses global
|
||||||
// variables. Make tests that use this helper concurrent.
|
// variables. Make tests that use this helper concurrent.
|
||||||
func storeGlobals(tb testing.TB) {
|
func storeGlobals(tb testing.TB) {
|
||||||
tb.Helper()
|
tb.Helper()
|
||||||
|
|
||||||
|
prevGLMode := GLMode
|
||||||
prevConfig := config
|
prevConfig := config
|
||||||
|
prefGLFilePrefix := glFilePrefix
|
||||||
|
auth := globalContext.auth
|
||||||
storage := globalContext.clients.storage
|
storage := globalContext.clients.storage
|
||||||
dnsServer := globalContext.dnsServer
|
dnsServer := globalContext.dnsServer
|
||||||
|
firstRun := globalContext.firstRun
|
||||||
mux := globalContext.mux
|
mux := globalContext.mux
|
||||||
|
web := globalContext.web
|
||||||
|
|
||||||
tb.Cleanup(func() {
|
tb.Cleanup(func() {
|
||||||
|
GLMode = prevGLMode
|
||||||
config = prevConfig
|
config = prevConfig
|
||||||
|
glFilePrefix = prefGLFilePrefix
|
||||||
|
globalContext.auth = auth
|
||||||
globalContext.clients.storage = storage
|
globalContext.clients.storage = storage
|
||||||
globalContext.dnsServer = dnsServer
|
globalContext.dnsServer = dnsServer
|
||||||
|
globalContext.firstRun = firstRun
|
||||||
globalContext.mux = mux
|
globalContext.mux = mux
|
||||||
|
globalContext.web = web
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,18 +220,17 @@ func TestTLSManager_Reload(t *testing.T) {
|
|||||||
config.DNS.Port = 0
|
config.DNS.Port = 0
|
||||||
|
|
||||||
var (
|
var (
|
||||||
logger = slogutil.NewDiscardLogger()
|
ctx = testutil.ContextWithTimeout(t, testTimeout)
|
||||||
ctx = testutil.ContextWithTimeout(t, testTimeout)
|
err error
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
globalContext.dnsServer, err = dnsforward.NewServer(dnsforward.DNSCreateParams{
|
globalContext.dnsServer, err = dnsforward.NewServer(dnsforward.DNSCreateParams{
|
||||||
Logger: logger,
|
Logger: testLogger,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
globalContext.clients.storage, err = client.NewStorage(ctx, &client.StorageConfig{
|
globalContext.clients.storage, err = client.NewStorage(ctx, &client.StorageConfig{
|
||||||
Logger: logger,
|
Logger: testLogger,
|
||||||
Clock: timeutil.SystemClock{},
|
Clock: timeutil.SystemClock{},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -238,7 +250,7 @@ func TestTLSManager_Reload(t *testing.T) {
|
|||||||
writeCertAndKey(t, certDER, certPath, key, keyPath)
|
writeCertAndKey(t, certDER, certPath, key, keyPath)
|
||||||
|
|
||||||
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
||||||
logger: logger,
|
logger: testLogger,
|
||||||
configModified: func() {},
|
configModified: func() {},
|
||||||
tlsSettings: tlsConfigSettings{
|
tlsSettings: tlsConfigSettings{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -249,7 +261,7 @@ func TestTLSManager_Reload(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
web, err := initWeb(ctx, options{}, nil, nil, logger, nil, false)
|
web, err := initWeb(ctx, options{}, nil, nil, testLogger, nil, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
m.setWebAPI(web)
|
m.setWebAPI(web)
|
||||||
@@ -272,13 +284,12 @@ func TestTLSManager_Reload(t *testing.T) {
|
|||||||
|
|
||||||
func TestTLSManager_HandleTLSStatus(t *testing.T) {
|
func TestTLSManager_HandleTLSStatus(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
logger = slogutil.NewDiscardLogger()
|
ctx = testutil.ContextWithTimeout(t, testTimeout)
|
||||||
ctx = testutil.ContextWithTimeout(t, testTimeout)
|
err error
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
||||||
logger: logger,
|
logger: testLogger,
|
||||||
configModified: func() {},
|
configModified: func() {},
|
||||||
tlsSettings: tlsConfigSettings{
|
tlsSettings: tlsConfigSettings{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -309,19 +320,18 @@ func TestValidateTLSSettings(t *testing.T) {
|
|||||||
globalContext.mux = http.NewServeMux()
|
globalContext.mux = http.NewServeMux()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
logger = slogutil.NewDiscardLogger()
|
ctx = testutil.ContextWithTimeout(t, testTimeout)
|
||||||
ctx = testutil.ContextWithTimeout(t, testTimeout)
|
err error
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
||||||
logger: logger,
|
logger: testLogger,
|
||||||
configModified: func() {},
|
configModified: func() {},
|
||||||
servePlainDNS: false,
|
servePlainDNS: false,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
web, err := initWeb(ctx, options{}, nil, nil, logger, nil, false)
|
web, err := initWeb(ctx, options{}, nil, nil, testLogger, nil, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
m.setWebAPI(web)
|
m.setWebAPI(web)
|
||||||
@@ -409,13 +419,12 @@ func TestTLSManager_HandleTLSValidate(t *testing.T) {
|
|||||||
globalContext.mux = http.NewServeMux()
|
globalContext.mux = http.NewServeMux()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
logger = slogutil.NewDiscardLogger()
|
ctx = testutil.ContextWithTimeout(t, testTimeout)
|
||||||
ctx = testutil.ContextWithTimeout(t, testTimeout)
|
err error
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
||||||
logger: logger,
|
logger: testLogger,
|
||||||
configModified: func() {},
|
configModified: func() {},
|
||||||
tlsSettings: tlsConfigSettings{
|
tlsSettings: tlsConfigSettings{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -426,7 +435,7 @@ func TestTLSManager_HandleTLSValidate(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
web, err := initWeb(ctx, options{}, nil, nil, logger, nil, false)
|
web, err := initWeb(ctx, options{}, nil, nil, testLogger, nil, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
m.setWebAPI(web)
|
m.setWebAPI(web)
|
||||||
@@ -462,13 +471,12 @@ func TestTLSManager_HandleTLSConfigure(t *testing.T) {
|
|||||||
storeGlobals(t)
|
storeGlobals(t)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
logger = slogutil.NewDiscardLogger()
|
ctx = testutil.ContextWithTimeout(t, testTimeout)
|
||||||
ctx = testutil.ContextWithTimeout(t, testTimeout)
|
err error
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
globalContext.dnsServer, err = dnsforward.NewServer(dnsforward.DNSCreateParams{
|
globalContext.dnsServer, err = dnsforward.NewServer(dnsforward.DNSCreateParams{
|
||||||
Logger: logger,
|
Logger: testLogger,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -484,7 +492,7 @@ func TestTLSManager_HandleTLSConfigure(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
globalContext.clients.storage, err = client.NewStorage(ctx, &client.StorageConfig{
|
globalContext.clients.storage, err = client.NewStorage(ctx, &client.StorageConfig{
|
||||||
Logger: logger,
|
Logger: testLogger,
|
||||||
Clock: timeutil.SystemClock{},
|
Clock: timeutil.SystemClock{},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -506,7 +514,7 @@ func TestTLSManager_HandleTLSConfigure(t *testing.T) {
|
|||||||
|
|
||||||
// Initialize the TLS manager and assert its configuration.
|
// Initialize the TLS manager and assert its configuration.
|
||||||
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
m, err := newTLSManager(ctx, &tlsManagerConfig{
|
||||||
logger: logger,
|
logger: testLogger,
|
||||||
configModified: func() {},
|
configModified: func() {},
|
||||||
tlsSettings: tlsConfigSettings{
|
tlsSettings: tlsConfigSettings{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -517,7 +525,7 @@ func TestTLSManager_HandleTLSConfigure(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
web, err := initWeb(ctx, options{}, nil, nil, logger, nil, false)
|
web, err := initWeb(ctx, options{}, nil, nil, testLogger, nil, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
m.setWebAPI(web)
|
m.setWebAPI(web)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ The easiest way would be to use [Swagger Editor](http://editor.swagger.io/) and
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
[Here](CHANGELOG.md) we keep track of all non-compatible changes that are being made.
|
See [`CHANGELOG.md`](CHANGELOG.md) where we keep track of all non-compatible changes that are being made.
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user