Compare commits
6 Commits
v0.108.0-b
...
6399-fix-u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24a62d0638 | ||
|
|
f81a94eb94 | ||
|
|
ca898fe74e | ||
|
|
366ec81621 | ||
|
|
f9ee511094 | ||
|
|
deedc490e1 |
7
.github/PULL_REQUEST_TEMPLATE
vendored
7
.github/PULL_REQUEST_TEMPLATE
vendored
@@ -1,8 +1,7 @@
|
||||
Before submitting a PR please make sure that:
|
||||
|
||||
1. You have discussed your solution in an issue and have got an
|
||||
approval from a maintainer. See our
|
||||
[contribution guide](https://github.com/AdguardTeam/AdGuardHome/blob/master/CONTRIBUTING.md).
|
||||
approval from a maintainer.
|
||||
|
||||
2. This isn't a localization fix; please send those to our
|
||||
[CrowdIn](https://crowdin.com/project/adguard-applications/en#/adguard-home)
|
||||
@@ -14,8 +13,8 @@ Before submitting a PR please make sure that:
|
||||
Add a short description here. The description should include:
|
||||
|
||||
1. Which issue this PR closes (`Closes #NNNN.`) or updates (`Updates
|
||||
#NNNN.`). Please do not open PRs without filing an issue first.
|
||||
#NNNN.`).
|
||||
|
||||
2. A short description of how the change achieves that.
|
||||
|
||||
Do not forget to remove these instructions!
|
||||
Do not forget to remove these instructions.
|
||||
|
||||
99
CHANGELOG.md
99
CHANGELOG.md
@@ -14,100 +14,46 @@ and this project adheres to
|
||||
<!--
|
||||
## [v0.108.0] - TBA
|
||||
|
||||
## [v0.107.42] - 2023-12-06 (APPROX.)
|
||||
## [v0.107.41] - 2023-11-01 (APPROX.)
|
||||
|
||||
See also the [v0.107.42 GitHub milestone][ms-v0.107.42].
|
||||
See also the [v0.107.41 GitHub milestone][ms-v0.107.41].
|
||||
|
||||
[ms-v0.107.42]: https://github.com/AdguardTeam/AdGuardHome/milestone/77?closed=1
|
||||
[ms-v0.107.41]: https://github.com/AdguardTeam/AdGuardHome/milestone/76?closed=1
|
||||
|
||||
NOTE: Add new changes BELOW THIS COMMENT.
|
||||
-->
|
||||
|
||||
### Added
|
||||
|
||||
- Ability to disable plain-DNS serving through configuration file if an
|
||||
encrypted protocol is already used ([#1660]).
|
||||
- Ability to specify rate limiting settings in the Web UI ([#6369]).
|
||||
|
||||
#### Configuration changes
|
||||
|
||||
- The new property `dns.serve_plain_dns` has been added to the configuration
|
||||
file ([#1660]).
|
||||
- The property `dns.bogus_nxdomain` is now validated more strictly.
|
||||
- Added new properties `clients.persistent.*.upstreams_cache_enabled` and
|
||||
`clients.persistent.*.upstreams_cache_size` that describe cache configuration
|
||||
for each client's custom upstream configuration.
|
||||
|
||||
### Fixed
|
||||
|
||||
- `ipset` entries family validation ([#6420]).
|
||||
- Pre-filling the New static lease window with data ([#6402]).
|
||||
- Protection pause timer synchronization ([#5759]).
|
||||
|
||||
[#1660]: https://github.com/AdguardTeam/AdGuardHome/issues/1660
|
||||
[#5759]: https://github.com/AdguardTeam/AdGuardHome/issues/5759
|
||||
[#6369]: https://github.com/AdguardTeam/AdGuardHome/issues/6369
|
||||
[#6402]: https://github.com/AdguardTeam/AdGuardHome/issues/6402
|
||||
[#6420]: https://github.com/AdguardTeam/AdGuardHome/issues/6420
|
||||
|
||||
<!--
|
||||
NOTE: Add new changes ABOVE THIS COMMENT.
|
||||
-->
|
||||
|
||||
|
||||
|
||||
## [v0.107.41] - 2023-11-13
|
||||
|
||||
See also the [v0.107.41 GitHub milestone][ms-v0.107.41].
|
||||
|
||||
### Security
|
||||
|
||||
- Go version has been updated to prevent the possibility of exploiting the
|
||||
CVE-2023-45283 and CVE-2023-45284 Go vulnerabilities fixed in
|
||||
[Go 1.20.11][go-1.20.11].
|
||||
|
||||
### Added
|
||||
|
||||
- Ability to specify subnet lengths for IPv4 and IPv6 addresses, used for rate
|
||||
limiting requests, in the configuration file ([#6368]).
|
||||
- Ability to specify multiple domain specific upstreams per line, e.g.
|
||||
`[/domain1/../domain2/]upstream1 upstream2 .. upstreamN` ([#4977]).
|
||||
|
||||
### Changed
|
||||
|
||||
- Increased the height of the ready-to-use filter lists dialog ([#6358]).
|
||||
- Improved logging of authentication failures ([#6357]).
|
||||
|
||||
#### Configuration changes
|
||||
|
||||
- New properties `dns.ratelimit_subnet_len_ipv4` and
|
||||
`dns.ratelimit_subnet_len_ipv6` have been added to the configuration file
|
||||
([#6368]).
|
||||
- The height of ready-to-use filter lists has been increased ([#6358]).
|
||||
- Improved authentication failure logging ([#6357]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Schedule timezone not being sent ([#6401]).
|
||||
- Average request processing time calculation ([#6220]).
|
||||
- Redundant truncation of long client names in the Top Clients table ([#6338]).
|
||||
- Redundant shortening long client names in the Top Clients table ([#6338]).
|
||||
- Scrolling column headers in the tables ([#6337]).
|
||||
- `$important,dnsrewrite` rules not overriding allowlist rules ([#6204]).
|
||||
- `$important,dnsrewrite` rules do not take precedence over allowlist rules
|
||||
([#6204]).
|
||||
- Dark mode DNS rewrite background ([#6329]).
|
||||
- Issues with QUIC and HTTP/3 upstreams on Linux ([#6335]).
|
||||
|
||||
[#4977]: https://github.com/AdguardTeam/AdGuardHome/issues/4977
|
||||
[#6204]: https://github.com/AdguardTeam/AdGuardHome/issues/6204
|
||||
[#6220]: https://github.com/AdguardTeam/AdGuardHome/issues/6220
|
||||
[#6329]: https://github.com/AdguardTeam/AdGuardHome/issues/6329
|
||||
[#6335]: https://github.com/AdguardTeam/AdGuardHome/issues/6335
|
||||
[#6337]: https://github.com/AdguardTeam/AdGuardHome/issues/6337
|
||||
[#6338]: https://github.com/AdguardTeam/AdGuardHome/issues/6338
|
||||
[#6357]: https://github.com/AdguardTeam/AdGuardHome/issues/6357
|
||||
[#6358]: https://github.com/AdguardTeam/AdGuardHome/issues/6358
|
||||
[#6368]: https://github.com/AdguardTeam/AdGuardHome/issues/6368
|
||||
[#6401]: https://github.com/AdguardTeam/AdGuardHome/issues/6401
|
||||
|
||||
[go-1.20.11]: https://groups.google.com/g/golang-announce/c/4tU8LZfBFkY/m/d-jSKR_jBwAJ
|
||||
[ms-v0.107.41]: https://github.com/AdguardTeam/AdGuardHome/milestone/76?closed=1
|
||||
<!--
|
||||
NOTE: Add new changes ABOVE THIS COMMENT.
|
||||
-->
|
||||
|
||||
|
||||
|
||||
@@ -238,7 +184,7 @@ See also the [v0.107.37 GitHub milestone][ms-v0.107.37].
|
||||
is returned if the blocking mode isn't set to `Null IP`. In previous versions
|
||||
it returned NXDOMAIN response in such cases.
|
||||
|
||||
#### Configuration changes
|
||||
#### Configuration Changes
|
||||
|
||||
In this release, the schema version has changed from 24 to 27.
|
||||
|
||||
@@ -448,7 +394,7 @@ See also the [v0.107.34 GitHub milestone][ms-v0.107.34].
|
||||
|
||||
- Improved CPU and RAM consumption during updates of filtering-rule lists.
|
||||
|
||||
#### Configuration changes
|
||||
#### Configuration Changes
|
||||
|
||||
In this release, the schema version has changed from 23 to 24.
|
||||
|
||||
@@ -528,7 +474,7 @@ See also the [v0.107.33 GitHub milestone][ms-v0.107.33].
|
||||
|
||||
### Changed
|
||||
|
||||
#### Configuration changes
|
||||
#### Configuration Changes
|
||||
|
||||
In this release, the schema version has changed from 20 to 23.
|
||||
|
||||
@@ -793,7 +739,7 @@ See also the [v0.107.28 GitHub milestone][ms-v0.107.28].
|
||||
- ARPA domain names containing a subnet within private networks now also
|
||||
considered private, behaving closer to [RFC 6761][rfc6761] ([#5567]).
|
||||
|
||||
#### Configuration changes
|
||||
#### Configuration Changes
|
||||
|
||||
In this release, the schema version has changed from 17 to 20.
|
||||
|
||||
@@ -933,7 +879,7 @@ See also the [v0.107.26 GitHub milestone][ms-v0.107.26].
|
||||
|
||||
### Changed
|
||||
|
||||
#### Configuration changes
|
||||
#### Configuration Changes
|
||||
|
||||
- Property `edns_client_subnet`, which in schema versions 16 and earlier used
|
||||
to be a part of the `dns` object, is now part of the `dns.edns_client_subnet`
|
||||
@@ -1022,7 +968,7 @@ See also the [v0.107.24 GitHub milestone][ms-v0.107.24].
|
||||
|
||||
### Changed
|
||||
|
||||
#### Configuration changes
|
||||
#### Configuration Changes
|
||||
|
||||
In this release, the schema version has changed from 14 to 16.
|
||||
|
||||
@@ -1732,7 +1678,7 @@ See also the [v0.107.7 GitHub milestone][ms-v0.107.7].
|
||||
- The `dns.bogus_nxdomain` property in the configuration file now supports CIDR
|
||||
notation alongside IP addresses ([#1730]).
|
||||
|
||||
#### Configuration changes
|
||||
#### Configuration Changes
|
||||
|
||||
In this release, the schema version has changed from 12 to 14.
|
||||
|
||||
@@ -2073,7 +2019,7 @@ See also the [v0.107.0 GitHub milestone][ms-v0.107.0].
|
||||
file, together with the new `group` and `user` properties ([#2763]).
|
||||
- Permissions on filter files are now `0o644` instead of `0o600` ([#3198]).
|
||||
|
||||
#### Configuration changes
|
||||
#### Configuration Changes
|
||||
|
||||
In this release, the schema version has changed from 10 to 12.
|
||||
|
||||
@@ -2639,12 +2585,11 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
|
||||
|
||||
|
||||
<!--
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.42...HEAD
|
||||
[v0.107.42]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.41...v0.107.42
|
||||
-->
|
||||
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.41...HEAD
|
||||
[v0.107.41]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.40...v0.107.41
|
||||
-->
|
||||
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.40...HEAD
|
||||
[v0.107.40]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.39...v0.107.40
|
||||
[v0.107.39]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.38...v0.107.39
|
||||
[v0.107.38]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.37...v0.107.38
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
# Contributing to AdGuard Home
|
||||
|
||||
If you want to contribute to AdGuard Home by filing or commenting on an issue or
|
||||
opening a pull request, please follow the instructions below.
|
||||
|
||||
|
||||
|
||||
## General recommendations
|
||||
|
||||
Please don't:
|
||||
|
||||
* post comments like “+1” or “this”. Use the :+1: reaction on the issue
|
||||
instead, as this allows us to actually see the level of support for issues.
|
||||
|
||||
* file issues about localization errors or send localization updates as PRs.
|
||||
We're using [CrowdIn] to manage our translations and we generally update
|
||||
them before each Beta and Release build. You can learn more about
|
||||
translating AdGuard products [in our Knowledge Base][kb-trans].
|
||||
|
||||
* file issues about a particular filtering-rule list misbehaving. These are
|
||||
tracked through the [separate form for filtering issues][form].
|
||||
|
||||
* send updates to filtering-rule lists, such as the ones for the Blocked
|
||||
Services feature or the list of approved filtering-rule lists. We update
|
||||
them once before each Beta and Release build.
|
||||
|
||||
Please do:
|
||||
|
||||
* follow the template instructions and provide data for reproducing issues.
|
||||
|
||||
* write the title of your issue or pull request in English. Any language is
|
||||
fine in the body, but it is important to keep the title in English to make
|
||||
it easier for people and bots to look up duplicated issues.
|
||||
|
||||
[CrowdIn]: https://crowdin.com/project/adguard-applications/en#/adguard-home
|
||||
[form]: https://link.adtidy.org/forward.html?action=report&app=home&from=github
|
||||
[kb-trans]: https://kb.adguard.com/en/general/adguard-translations
|
||||
|
||||
|
||||
|
||||
## Issues
|
||||
|
||||
### Search first
|
||||
|
||||
Please make sure that the issue is not a duplicate or a question. If it's a
|
||||
duplicate, please react to the original issue with a thumbs up. If it's a
|
||||
question, please look through our [Wiki] and, if you haven't found the answer,
|
||||
post it to the GitHub [Discussions] page.
|
||||
|
||||
[Discussions]: https://github.com/AdguardTeam/AdGuardHome/discussions/categories/q-a
|
||||
[Wiki]: https://github.com/AdguardTeam/AdGuardHome/wiki
|
||||
|
||||
|
||||
|
||||
### Follow the issue template
|
||||
|
||||
Developers need to be able to reproduce the faulty behavior in order to fix an
|
||||
issue, so please make sure that you follow the instructions in the issue
|
||||
template carefully.
|
||||
|
||||
|
||||
|
||||
## Pull requests
|
||||
|
||||
### Discuss your changes first
|
||||
|
||||
Please discuss your changes by opening an issue. The maintainers should
|
||||
evaluate your proposal, and it's generally better if that's done before any code
|
||||
is written.
|
||||
|
||||
|
||||
|
||||
### Review your changes for style
|
||||
|
||||
We have a set of [code guidelines][hacking] that we expect the code to follow.
|
||||
Please make sure you follow it.
|
||||
|
||||
[hacking]: https://github.com/AdguardTeam/CodeGuidelines/blob/master/Go/Go.md
|
||||
|
||||
|
||||
|
||||
### Test your changes
|
||||
|
||||
Make sure that it passes linters and tests by running the corresponding Make
|
||||
targets. For backend changes, it's `make go-check`. For frontend, run
|
||||
`make js-lint`.
|
||||
|
||||
Additionally, a manual test is often required. While we're constantly working
|
||||
on improving our test suites, they're still not as good as we'd like them to be.
|
||||
@@ -272,7 +272,7 @@
|
||||
# need to build a few of these.
|
||||
'variables':
|
||||
'channel': 'beta'
|
||||
'dockerGo': 'adguard/golang-ubuntu:7.5'
|
||||
'dockerGo': 'adguard/golang-ubuntu:7.4'
|
||||
# release-vX.Y.Z branches are the branches from which the actual final
|
||||
# release is built.
|
||||
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
||||
@@ -287,4 +287,4 @@
|
||||
# are the ones that actually get released.
|
||||
'variables':
|
||||
'channel': 'release'
|
||||
'dockerGo': 'adguard/golang-ubuntu:7.5'
|
||||
'dockerGo': 'adguard/golang-ubuntu:7.4'
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
# need to build a few of these.
|
||||
'variables':
|
||||
'channel': 'beta'
|
||||
'dockerGo': 'adguard/golang-ubuntu:7.5'
|
||||
'dockerGo': 'adguard/golang-ubuntu:7.4'
|
||||
'snapcraftChannel': 'beta'
|
||||
# release-vX.Y.Z branches are the branches from which the actual final
|
||||
# release is built.
|
||||
@@ -207,5 +207,5 @@
|
||||
# are the ones that actually get released.
|
||||
'variables':
|
||||
'channel': 'release'
|
||||
'dockerGo': 'adguard/golang-ubuntu:7.5'
|
||||
'dockerGo': 'adguard/golang-ubuntu:7.4'
|
||||
'snapcraftChannel': 'candidate'
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
"enforced_save_search": "Ужыты бяспечны пошук",
|
||||
"number_of_dns_query_to_safe_search": "Колькасць запытаў DNS для пошукавых сістэм, для якіх быў ужыты Бяспечны пошук",
|
||||
"average_processing_time": "Сярэдні час апрацоўкі запыту",
|
||||
"processing_time": "Час апрацоўкі",
|
||||
"average_processing_time_hint": "Сярэдні час для апрацоўкі запыту DNS у мілісекундах",
|
||||
"block_domain_use_filters_and_hosts": "Блакаваць дамены з выкарыстаннем фільтраў і файлаў хастоў",
|
||||
"filters_block_toggle_hint": "Вы можаце наладзіць правілы блакавання ў «<a>Фільтрах</a>».",
|
||||
@@ -307,7 +308,6 @@
|
||||
"edns_use_custom_ip": "Выкарыстоўваць указаны IP для DNS",
|
||||
"edns_use_custom_ip_desc": "Дазволіць выкарыстоўваць уласны IP для DNS",
|
||||
"rate_limit_desc": "Абмежаванне на колькасць запытаў у секунду для кожнага кліента (0 — неабмежавана)",
|
||||
"rate_limit_whitelist_placeholder": "Увядзіце па адным адрасе на радок",
|
||||
"blocking_ipv4_desc": "IP-адрас, што вяртаецца пры блакаванню A-запыту",
|
||||
"blocking_ipv6_desc": "IP-адрас, што вяртаецца пры блакаванню AAAA-запыту",
|
||||
"blocking_mode_default": "Стандартны: Адказвае з нулёвым IP-адрасам (0.0.0.0 для A; :: для AAAA), калі заблакавана правілам у стылі Adblock; адказвае з IP-адрасам, паказаным у правіле, калі заблакавана правілам у стылі /etc/hosts-style",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Nastavení klienta",
|
||||
"example_upstream_reserved": "odchozí DNS připojení <0>pro konkrétní doménu(y)</0>;",
|
||||
"example_multiple_upstreams_reserved": "více odchozích připojení <0>pro konkrétní domény</0>;",
|
||||
"example_upstream_comment": "komentář.",
|
||||
"upstream_parallel": "Použijte paralelní požadavky na urychlení řešení simultánním dotazováním na všechny navazující servery.",
|
||||
"parallel_requests": "Paralelní požadavky",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Vynucené bezpečné vyhledávání",
|
||||
"number_of_dns_query_to_safe_search": "Počet požadavků DNS na vyhledávače, při kterých bylo vynucené bezpečné vyhledávání",
|
||||
"average_processing_time": "Průměrný čas zpracování",
|
||||
"average_upstream_response_time": "Průměrná doba odezvy odchozích připojení",
|
||||
"response_time": "Čas odezvy",
|
||||
"processing_time": "Doba zpracování",
|
||||
"average_processing_time_hint": "Průměrný čas zpracování požadavků DNS v milisekundách",
|
||||
"block_domain_use_filters_and_hosts": "Blokovat domény pomocí filtrů a seznamů adres",
|
||||
"filters_block_toggle_hint": "Pravidla blokování můžete nastavit v nastavení <a>Filtry</a>.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Použít vlastní IP pro EDNS",
|
||||
"edns_use_custom_ip_desc": "Povolit použití vlastní IP pro EDNS",
|
||||
"rate_limit_desc": "Počet požadavků za sekundu, které smí jeden klient provádět (0: neomezeno)",
|
||||
"rate_limit_subnet_len_ipv4": "Délka předpony podsítě pro adresy IPv4",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Délka předpony podsítě pro adresy IPv4 používané pro omezení rychlosti. Výchozí hodnota je 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "Délka předpony podsítě IPv4 by měla být mezi 0 a 32",
|
||||
"rate_limit_subnet_len_ipv6": "Délka předpony podsítě pro adresy IPv6",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Délka předpony podsítě pro adresy IPv6 používané pro omezení rychlosti. Výchozí hodnota je 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "Délka předpony podsítě IPv6 by měla být mezi 0 a 128",
|
||||
"form_enter_rate_limit_subnet_len": "Zadejte délku předpony podsítě pro omezení rychlosti",
|
||||
"rate_limit_whitelist": "Seznam výjimek pro omezení rychlosti",
|
||||
"rate_limit_whitelist_desc": "IP adresy vyloučené z omezení rychlosti",
|
||||
"rate_limit_whitelist_placeholder": "Zadejte jednu IP adresu na řádek",
|
||||
"blocking_ipv4_desc": "IP adresa, která se má vrátit v případě blokovaného požadavku typu A",
|
||||
"blocking_ipv6_desc": "IP adresa, která se má vrátit v případě blokovaného požadavku typu AAAA",
|
||||
"blocking_mode_default": "Výchozí: Odezva s nulovou IP adresou (0.0.0.0 pro A; :: pro AAAA), pokud je blokováno pravidlem ve stylu Adblock; odezva pomocí IP adresy uvedené v pravidle, pokud je blokováno pravidlem /etc/hosts-style",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Klientindstillinger",
|
||||
"example_upstream_reserved": "en upstream <0>for bestemte domæner</0>;",
|
||||
"example_multiple_upstreams_reserved": "flere upstreams <0>til bestemte domæner</0>;",
|
||||
"example_upstream_comment": "en kommentaren.",
|
||||
"upstream_parallel": "Brug parallelforespørgsler til at accelerere fortolkningen ved at forespørge alle upstream-servere samtidigt.",
|
||||
"parallel_requests": "Parallelle forespørgsler",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Håndhævet sikker søgning",
|
||||
"number_of_dns_query_to_safe_search": "Antallet af DNS-forespørgsler til søgemaskiner, hvor Sikker Søgning blev håndhævet",
|
||||
"average_processing_time": "Gennemsnitlig behandlingstid",
|
||||
"average_upstream_response_time": "Gennemsnitlig upstream-responstid",
|
||||
"response_time": "Responstid",
|
||||
"processing_time": "Behandlingstid",
|
||||
"average_processing_time_hint": "Gennemsnitlig behandlingstid i millisekunder af DNS-forespørgsel",
|
||||
"block_domain_use_filters_and_hosts": "Blokér domæner vha. filtre og værtsfiler",
|
||||
"filters_block_toggle_hint": "Du kan opsætte blokeringsregler i <a>Filterindstillingerne</a>.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Brug tilpasset IP til EDNS",
|
||||
"edns_use_custom_ip_desc": "Tillad brug af tilpasset IP til EDNS",
|
||||
"rate_limit_desc": "Antallet af forespørgsler pr. sekund tilladt pr. klient (værdien 0 = ubegrænset)",
|
||||
"rate_limit_subnet_len_ipv4": "Længde på undernetpræfiks for IPv4-adresser",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Længde på undernetpræfiks for IPv4-adresser til hastighedsbegrænsning. Standard er 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "Længden på IPv4-undernetpræfiks skal være mellem 0 og 32",
|
||||
"rate_limit_subnet_len_ipv6": "Længde på undernetpræfiks for IPv6-adresser",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Længde på undernetpræfiks for IPv6-adresser til hastighedsbegrænsning. Standard er 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "Længden på IPv6-undernetpræfiks skal være mellem 0 og 128",
|
||||
"form_enter_rate_limit_subnet_len": "Angiv længden på undernetpræfiks til hastighedsbegrænsning",
|
||||
"rate_limit_whitelist": "Hvidliste til hastighedsbegrænsning",
|
||||
"rate_limit_whitelist_desc": "IP-adresser undtaget fra hastighedsbegrænsning",
|
||||
"rate_limit_whitelist_placeholder": "Angiv én IP-adresse pr. linje",
|
||||
"blocking_ipv4_desc": "Returneret IP-adresse for en blokeret A-forespørgsel",
|
||||
"blocking_ipv6_desc": "Returneret IP-adresse for en blokeret AAAA-forespørgsel",
|
||||
"blocking_mode_default": "Standard: Svar med nul IP-adresse (0.0.0.0 for A; :: for AAAA), når blokeret af Adblock-lignende regel. Svar med IP-adressen angivet i reglen, når blokeret af /etc/hosts-lignende regel",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Client-Einstellungen",
|
||||
"example_upstream_reserved": "ein Upstream <0>für bestimmte Domains</0>;",
|
||||
"example_multiple_upstreams_reserved": "mehrere Upstreams <0>für bestimmte Domains</0>;",
|
||||
"example_upstream_comment": "ein Kommentar.",
|
||||
"upstream_parallel": "Parallele Abfragen verwenden, um das Auflösen zu beschleunigen, indem alle Upstream-Server gleichzeitig abgefragt werden.",
|
||||
"parallel_requests": "Paralleles Abfragen",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Sichere Suche erzwungen",
|
||||
"number_of_dns_query_to_safe_search": "Anzahl der DNS-Anfragen bei denen Sichere Suche für Suchanfragen erzwungen wurde",
|
||||
"average_processing_time": "Durchschnittliche Bearbeitungsdauer",
|
||||
"average_upstream_response_time": "Durchschnittliche Upstream-Antwortzeit",
|
||||
"response_time": "Antwortzeit",
|
||||
"processing_time": "Verarbeitungszeit",
|
||||
"average_processing_time_hint": "Durchschnittliche Zeit in Millisekunden zur Bearbeitung von DNS-Anfragen",
|
||||
"block_domain_use_filters_and_hosts": "Domains durch Filter und Host-Dateien sperren",
|
||||
"filters_block_toggle_hint": "Sie können Blockierregeln in den <a>Filter</a>einstellungen erstellen.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Benutzerdefinierte IP für EDNS verwenden",
|
||||
"edns_use_custom_ip_desc": "Benutzerdefinierte IP für EDNS zulassen",
|
||||
"rate_limit_desc": "Die Anzahl der Anfragen pro Sekunde, die ein einzelner Client stellen darf. Das Setzen auf 0 bedeutet keine Begrenzung.",
|
||||
"rate_limit_subnet_len_ipv4": "Länge des Subnetzpräfixes für IPv4-Adressen",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Subnetpräfixlänge für IPv4-Adressen, die für die Ratebegrenzung verwendet werden. Der Standardwert ist 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "Die Subnetzpräfixlänge für IPv4-Adressen sollte zwischen 0 und 32 liegen",
|
||||
"rate_limit_subnet_len_ipv6": "Subnetzpräfixlänge für IPv6-Adressen",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Subnetpräfixlänge für IPv6-Adressen, die für die Ratebegrenzung verwendet werden. Der Standardwert ist 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "Die Subnetzpräfixlänge für IPv6-Adressen sollte zwischen 0 und 128 liegen",
|
||||
"form_enter_rate_limit_subnet_len": "Geben Sie die Subnetzpräfixlänge für die Ratebegrenzung ein",
|
||||
"rate_limit_whitelist": "Zulassungsliste für die Ratebegrenzung",
|
||||
"rate_limit_whitelist_desc": "IP-Adressen, die von der Ratebegrenzung ausgeschlossen sind",
|
||||
"rate_limit_whitelist_placeholder": "Geben Sie eine IP-Adresse pro Zeile ein",
|
||||
"blocking_ipv4_desc": "IP-Adresse, die für eine gesperrte A-Anfrage zurückgegeben werden soll",
|
||||
"blocking_ipv6_desc": "IP-Adresse, die für eine gesperrte AAAA-Anfrage zurückgegeben werden soll",
|
||||
"blocking_mode_default": "Standard: Mit Null IP Adress (0.0.0.0 for A; :: for AAAA) antworten, wenn sie durch eine Regel im Adblock-Stil gesperrt sind; mit der in der Regel angegebenen IP-Adresse antworten, wenn sie durch eine Regel im /etc/hosts-Stil gesperrt wurde",
|
||||
|
||||
@@ -144,8 +144,7 @@
|
||||
"enforced_save_search": "Enforced safe search",
|
||||
"number_of_dns_query_to_safe_search": "The number of DNS requests to search engines for which Safe Search was enforced",
|
||||
"average_processing_time": "Average processing time",
|
||||
"average_upstream_response_time": "Average upstream response time",
|
||||
"response_time": "Response time",
|
||||
"processing_time": "Processing time",
|
||||
"average_processing_time_hint": "Average time in milliseconds on processing a DNS request",
|
||||
"block_domain_use_filters_and_hosts": "Block domains using filters and hosts files",
|
||||
"filters_block_toggle_hint": "You can setup blocking rules in the <a>Filters</a> settings.",
|
||||
@@ -310,16 +309,6 @@
|
||||
"edns_use_custom_ip": "Use custom IP for EDNS",
|
||||
"edns_use_custom_ip_desc": "Allow to use custom IP for EDNS",
|
||||
"rate_limit_desc": "The number of requests per second allowed per client. Setting it to 0 means no limit.",
|
||||
"rate_limit_subnet_len_ipv4": "Subnet prefix length for IPv4 addresses",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Subnet prefix length for IPv4 addresses used for rate limiting. The default is 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "The IPv4 subnet prefix length should be between 0 and 32",
|
||||
"rate_limit_subnet_len_ipv6": "Subnet prefix length for IPv6 addresses",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Subnet prefix length for IPv6 addresses used for rate limiting. The default is 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "The IPv6 subnet prefix length should be between 0 and 128",
|
||||
"form_enter_rate_limit_subnet_len": "Enter subnet prefix length for rate limiting",
|
||||
"rate_limit_whitelist": "Rate limiting allowlist",
|
||||
"rate_limit_whitelist_desc": "IP addresses excluded from rate limiting",
|
||||
"rate_limit_whitelist_placeholder": "Enter one IP address per line",
|
||||
"blocking_ipv4_desc": "IP address to be returned for a blocked A request",
|
||||
"blocking_ipv6_desc": "IP address to be returned for a blocked AAAA request",
|
||||
"blocking_mode_default": "Default: Respond with zero IP address (0.0.0.0 for A; :: for AAAA) when blocked by Adblock-style rule; respond with the IP address specified in the rule when blocked by /etc/hosts-style rule",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Configuración de clientes",
|
||||
"example_upstream_reserved": "un DNS de subida <0>para un dominio específico</0>.",
|
||||
"example_multiple_upstreams_reserved": "múltiples upstreams <0>para dominios específicos</0>;",
|
||||
"example_upstream_comment": "un comentario.",
|
||||
"upstream_parallel": "Usar consultas paralelas para acelerar la resolución al consultar simultáneamente a todos los servidores DNS de subida.",
|
||||
"parallel_requests": "Consultas paralelas",
|
||||
@@ -9,9 +8,9 @@
|
||||
"load_balancing_desc": "Consulta un servidor DNS de subida a la vez. AdGuard Home utiliza su algoritmo aleatorio ponderado para elegir el servidor más rápido y sea utilizado con más frecuencia.",
|
||||
"bootstrap_dns": "Servidores DNS de arranque",
|
||||
"bootstrap_dns_desc": "Direcciones IP de servidores DNS utilizadas para resolver direcciones IP de los solucionadores DoH/DoT que especifiques como ascendentes. No se permiten comentarios.",
|
||||
"fallback_dns_title": "Servidores DNS alternativos",
|
||||
"fallback_dns_desc": "Lista de servidores DNS alternativos utilizados cuando los servidores DNS de subida no responden. La sintaxis es la misma que en el campo de los principales DNS de subida anterior.",
|
||||
"fallback_dns_placeholder": "Ingresa un servidor DNS alternativo por línea",
|
||||
"fallback_dns_title": "Servidores DNS de fallback",
|
||||
"fallback_dns_desc": "La lista de DNS de fallback serán usadas cuando los servidores de upstream de DNS no respondan. La sintaxis es la misma que en los principales del campo anterior.",
|
||||
"fallback_dns_placeholder": "Ingresa un servidor de DNS alternativo por línea",
|
||||
"local_ptr_title": "Servidores DNS inversos y privados",
|
||||
"local_ptr_desc": "Los servidores DNS que AdGuard Home utiliza para las consultas PTR locales. Estos servidores se utilizan para resolver las peticiones PTR de direcciones en rangos de IP privadas, por ejemplo \"192.168.12.34\", utilizando DNS inverso. Si no está establecido, AdGuard Home utilizará los resolutores DNS predeterminados de tu sistema operativo, excepto las direcciones del propio AdGuard Home.",
|
||||
"local_ptr_default_resolver": "Por defecto, AdGuard Home utiliza los siguientes resolutores DNS inversos: {{ip}}.",
|
||||
@@ -132,8 +131,8 @@
|
||||
"top_clients": "Clientes más frecuentes",
|
||||
"no_clients_found": "No se han encontrado clientes",
|
||||
"general_statistics": "Estadísticas generales",
|
||||
"top_upstreams": "DNS de subida más frecuentes",
|
||||
"no_upstreams_data_found": "No se han encontrado datos de DNS de subida",
|
||||
"top_upstreams": "Mejores upstreams",
|
||||
"no_upstreams_data_found": "No se han encontrado datos de upstreams",
|
||||
"number_of_dns_query_days": "Número de consultas DNS procesadas durante el último {{count}} día",
|
||||
"number_of_dns_query_days_plural": "Número de consultas DNS procesadas durante los últimos {{count}} días",
|
||||
"number_of_dns_query_hours": "Número de consultas DNS procesadas durante la última {{count}} hora",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Búsquedas seguras forzadas",
|
||||
"number_of_dns_query_to_safe_search": "Número de peticiones DNS a los motores de búsqueda para los que se aplicó la búsqueda segura forzada",
|
||||
"average_processing_time": "Tiempo promedio de procesamiento",
|
||||
"average_upstream_response_time": "Tiempo promedio de respuesta upstream",
|
||||
"response_time": "Tiempo de respuesta",
|
||||
"processing_time": "Tiempo de procesamiento",
|
||||
"average_processing_time_hint": "Tiempo promedio en milisegundos al procesar una petición DNS",
|
||||
"block_domain_use_filters_and_hosts": "Bloquear dominios usando filtros y archivos hosts",
|
||||
"filters_block_toggle_hint": "Puedes configurar las reglas de bloqueo en la configuración de <a>filtros</a>.",
|
||||
@@ -170,7 +168,7 @@
|
||||
"upstream_dns_configured_in_file": "Configurado en {{path}}",
|
||||
"test_upstream_btn": "Probar DNS de subida",
|
||||
"upstreams": "DNS de subida",
|
||||
"upstream": "DNS de subida",
|
||||
"upstream": "Upstream",
|
||||
"apply_btn": "Aplicar",
|
||||
"disabled_filtering_toast": "Filtrado deshabilitado",
|
||||
"enabled_filtering_toast": "Filtrado habilitado",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Usar IP personalizada para EDNS",
|
||||
"edns_use_custom_ip_desc": "Permitir el uso de IP personalizadas para EDNS",
|
||||
"rate_limit_desc": "Número de peticiones por segundo permitidas por cliente. Establecerlo en 0 significa que no hay límite.",
|
||||
"rate_limit_subnet_len_ipv4": "Longitud del prefijo de subred para direcciones IPv4",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Longitud del prefijo de subred para direcciones IPv4 utilizadas para limitar la velocidad. El valor predeterminado es 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "La longitud del prefijo de subred IPv4 debe estar entre 0 y 32",
|
||||
"rate_limit_subnet_len_ipv6": "Longitud del prefijo de subred para direcciones IPv6",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Longitud del prefijo de subred para direcciones IPv6 utilizadas para limitar la velocidad. El valor predeterminado es 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "La longitud del prefijo de subred IPv6 debe estar entre 0 y 128",
|
||||
"form_enter_rate_limit_subnet_len": "Ingresa la longitud del prefijo de subred para limitar la velocidad",
|
||||
"rate_limit_whitelist": "Lista de permitidos de limitación de velocidad",
|
||||
"rate_limit_whitelist_desc": "Direcciones IP excluidas de la limitación de velocidad",
|
||||
"rate_limit_whitelist_placeholder": "Ingresa una dirección IP por línea",
|
||||
"blocking_ipv4_desc": "Dirección IP devolverá una petición A bloqueada",
|
||||
"blocking_ipv6_desc": "Dirección IP devolverá una petición AAAA bloqueada",
|
||||
"blocking_mode_default": "Predeterminado: Responde con dirección IP cero (0.0.0.0 para A; :: para AAAA) cuando está bloqueado por la regla de estilo Adblock; responde con la dirección IP especificada en la regla cuando está bloqueado por una regla de estilo /etc/hosts",
|
||||
@@ -689,21 +677,21 @@
|
||||
"disable_for_hours": "Por {{count}} hora",
|
||||
"disable_for_hours_plural": "Por {{count}} horas",
|
||||
"disable_until_tomorrow": "Hasta mañana",
|
||||
"disable_notify_for_seconds": "Deshabilitar protección por {{count}} segundo",
|
||||
"disable_notify_for_seconds_plural": "Deshabilitar protección por {{count}} segundos",
|
||||
"disable_notify_for_minutes": "Deshabilitar protección por {{count}} minuto",
|
||||
"disable_notify_for_minutes_plural": "Deshabilitar protección por {{count}} minutos",
|
||||
"disable_notify_for_hours": "Deshabilitar protección por {{count}} hora",
|
||||
"disable_notify_for_hours_plural": "Deshabilitar protección por {{count}} horas",
|
||||
"disable_notify_until_tomorrow": "Deshabilitar protección hasta mañana",
|
||||
"enable_protection_timer": "La protección se habilitará a las {{time}}",
|
||||
"disable_notify_for_seconds": "Desactivar la protección por {{count}} segundo",
|
||||
"disable_notify_for_seconds_plural": "Desactivar la protección por {{count}} segundos",
|
||||
"disable_notify_for_minutes": "Desactivar la protección por {{count}} minuto",
|
||||
"disable_notify_for_minutes_plural": "Desactivar la protección por {{count}} minutos",
|
||||
"disable_notify_for_hours": "Desactivar la protección por {{count}} hora",
|
||||
"disable_notify_for_hours_plural": "Desactivar la protección por {{count}} horas",
|
||||
"disable_notify_until_tomorrow": "Desactivar la protección hasta mañana",
|
||||
"enable_protection_timer": "La protección se activará en {{time}}",
|
||||
"custom_retention_input": "Ingresa la retención en horas",
|
||||
"custom_rotation_input": "Ingresa la rotación en horas",
|
||||
"protection_section_label": "Protección",
|
||||
"log_and_stats_section_label": "Registro de consultas y estadísticas",
|
||||
"ignore_query_log": "Ignorar este cliente en el registro de consultas",
|
||||
"ignore_statistics": "Ignorar este cliente en las estadísticas",
|
||||
"schedule_services": "Pausar servicio de bloqueo",
|
||||
"schedule_services": "Pausar el servicio de bloqueo",
|
||||
"schedule_services_desc": "Configura el horario programado de pausa del servicio de bloqueo",
|
||||
"schedule_services_desc_client": "Configurar el horario programado de pausa del bloqueo de servicio filtrado para este cliente",
|
||||
"schedule_desc": "Establecer periodos de inactividad para servicios bloqueados",
|
||||
@@ -713,7 +701,7 @@
|
||||
"schedule_current_timezone": "Zona horaria actual: {{value}}",
|
||||
"schedule_time_all_day": "Todo el dia",
|
||||
"schedule_modal_description": "Este horario sustituirá cualquier horario existente para el mismo día de la semana. Cada día de la semana solo puede tener un periodo de inactividad.",
|
||||
"schedule_modal_time_off": "Detener servicio de bloqueo:",
|
||||
"schedule_modal_time_off": "Detener el servicio de bloqueo:",
|
||||
"schedule_new": "Nuevo horario",
|
||||
"schedule_edit": "Editar horario",
|
||||
"schedule_save": "Guardar horario",
|
||||
|
||||
@@ -139,6 +139,7 @@
|
||||
"enforced_save_search": "جستجوی اَمن اجبار شده",
|
||||
"number_of_dns_query_to_safe_search": "تعداد درخواست های DNS برای موتور جستجو که جستجوی اَمن اجبار شده",
|
||||
"average_processing_time": "میانگین زمان پردازش",
|
||||
"processing_time": "زمان پردازش",
|
||||
"average_processing_time_hint": "زمان میانگین بر هزارم ثانیه در پردازش درخواست DNS",
|
||||
"block_domain_use_filters_and_hosts": "مسدودسازی دامنه ها توسط فیلترها و فایل های میزبان",
|
||||
"filters_block_toggle_hint": "میتوانید دستورات مسدودسازی را در تنظیمات <a>فیلترها</a> راه اندازی کنید.",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Päätelaiteasetukset",
|
||||
"example_upstream_reserved": "ylävirta <0>tietyille verkkotunnuksille</0>;",
|
||||
"example_multiple_upstreams_reserved": "useita ylävirtoja <0>tietyille verkkotunnuksille</0>;",
|
||||
"example_upstream_comment": "kommentti.",
|
||||
"upstream_parallel": "Käytä rinnakkaisia pyyntöjä ja nopeuta selvitystä käyttämällä kaikkia ylävirtapalvelimia samanaikaisesti.",
|
||||
"parallel_requests": "Rinnakkaiset pyynnöt",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Turvallinen haku pakotettiin",
|
||||
"number_of_dns_query_to_safe_search": "DNS-pyyntöjen määrä, joille turvallinen haku pakotettiin käyttöön",
|
||||
"average_processing_time": "Keskimääräinen käsittelyaika",
|
||||
"average_upstream_response_time": "Ylävirran keskimääräinen vasteaika",
|
||||
"response_time": "Vasteaika",
|
||||
"processing_time": "Käsittelyaika",
|
||||
"average_processing_time_hint": "Keskimääräinen DNS-pyynnön käsittelyyn kulutettu aika millisekunteina",
|
||||
"block_domain_use_filters_and_hosts": "Estä verkkotunnuksia suodattimilla ja hosts-tiedostoilla",
|
||||
"filters_block_toggle_hint": "Voit määrittää estosääntöjä <a>suodatinasetuksissa</a>.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Käytä omaa IP-osoitetta EDNS:lle",
|
||||
"edns_use_custom_ip_desc": "Salli oman IP-osoitteen käyttö EDNS-mekanismille.",
|
||||
"rate_limit_desc": "Päätelaitteelle sallittu pyyntöjen enimmäismäärä sekunnissa. Arvo 0 tarkoittaa rajatonta.",
|
||||
"rate_limit_subnet_len_ipv4": "IPv4-osoitteiden aliverkon etuliitteen pituus",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Aliverkon etuliitteen pituus IPv4-osoitteille, joita käytetään nopeuden rajoittamiseen. Oletusarvo on 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "IPv4-aliverkon etuliitteen pituuden tulee olla 0–32",
|
||||
"rate_limit_subnet_len_ipv6": "IPv6-osoitteiden aliverkon etuliitteen pituus",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Aliverkon etuliitteen pituus IPv6-osoitteille, joita käytetään nopeuden rajoittamiseen. Oletusarvo on 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "IPv6-aliverkon etuliitteen pituuden tulee olla 0–128",
|
||||
"form_enter_rate_limit_subnet_len": "Anna aliverkon etuliitteen pituus nopeuden rajoittamista varten",
|
||||
"rate_limit_whitelist": "Nopeutta rajoittava sallittu luettelo",
|
||||
"rate_limit_whitelist_desc": "IP-osoitteet, jotka eivät kuulu nopeusrajoituksen piiriin",
|
||||
"rate_limit_whitelist_placeholder": "Syötä yksi IP-osoite per rivi",
|
||||
"blocking_ipv4_desc": "Estettyyn A-pyyntöön palautettava IP-osoite",
|
||||
"blocking_ipv6_desc": "Estettyyn AAAA-pyyntöön palautettava IP-osoite",
|
||||
"blocking_mode_default": "Oletus: Vastaa IP-nollaosoitteella (0.0.0.0 korvaa A; :: korvaa AAAA) kun estetään mainoseston säännöllä; vastaa säännön määrittämällä IP-osoitteella kun estetään /etc/hosts-tyyppisellä säännöllä",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Paramètres du client",
|
||||
"example_upstream_reserved": "un amont <0>pour des domaines spécifiques</0> ;",
|
||||
"example_multiple_upstreams_reserved": "plusieurs amonts <0>pour des domaines spécifiques</0> ;",
|
||||
"example_upstream_comment": " un commentaire.",
|
||||
"upstream_parallel": "Utilisez des requêtes parallèles pour accélérer la résolution en requêtant simultanément tous les serveurs en amont.",
|
||||
"parallel_requests": "Requêtes en parallèle",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Recherche sécurisée forcée",
|
||||
"number_of_dns_query_to_safe_search": "Le nombre de requêtes DNS faites avec la Recherche securisée",
|
||||
"average_processing_time": "Temps moyen de traitement",
|
||||
"average_upstream_response_time": "Temps de réponse moyen en amont",
|
||||
"response_time": "Temps de réponse",
|
||||
"processing_time": "Délai de traitement",
|
||||
"average_processing_time_hint": "Temps moyen (en millisecondes) de traitement d'une requête DNS",
|
||||
"block_domain_use_filters_and_hosts": "Bloquez les domaines à l'aide des filtres et fichiers hosts",
|
||||
"filters_block_toggle_hint": "Vous pouvez configurer les règles de filtrage dans les paramètres des <a>Filtres</a>.",
|
||||
@@ -310,7 +308,6 @@
|
||||
"edns_use_custom_ip": "Utiliser une IP personnalisée pour EDNS",
|
||||
"edns_use_custom_ip_desc": "Autoriser l'utilisation d'une adresse IP personnalisée pour EDNS",
|
||||
"rate_limit_desc": "Le nombre de requêtes par seconde qu’un seul client est autorisé à faire. Le réglage 0 fait illimité.",
|
||||
"rate_limit_whitelist_placeholder": "Saisissez une adresse IP par ligne",
|
||||
"blocking_ipv4_desc": "Adresse IP à renvoyer pour une demande A bloquée",
|
||||
"blocking_ipv6_desc": "Adresse IP à renvoyer pour une demande AAAA bloquée",
|
||||
"blocking_mode_default": "Par défaut : Répondre avec adresse IP zéro (0.0.0.0 pour A ; :: pour AAAA) lorsque bloqué par la règle de style Adblock ; répondre avec l’adresse IP spécifiée dans la règle lorsque bloquée par la règle du style /etc/hosts",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Postavke klijenta",
|
||||
"example_upstream_reserved": "upstream <0>za određene domene</0>;",
|
||||
"example_multiple_upstreams_reserved": "višestruke upstream poslužitelje <0>za određene domene</0>;",
|
||||
"example_upstream_comment": "komentar.",
|
||||
"upstream_parallel": "Koristi paralelne upite kako bi ubrzali rješavanje istovremenim ispitavanjem svih upstream poslužitelja.",
|
||||
"parallel_requests": "Paralelni zahtjevi",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Omogućeno sigurno pretraživanje",
|
||||
"number_of_dns_query_to_safe_search": "Broj DNS zahtjeva prema pretraživačima za koje je omogućeno Sigurno pretraživanje",
|
||||
"average_processing_time": "Prosječno vrijeme obrade",
|
||||
"average_upstream_response_time": "Prosječno vrijeme odziva upstream poslužitelja",
|
||||
"response_time": "Vrijeme odziva",
|
||||
"processing_time": "Vrijeme obrade",
|
||||
"average_processing_time_hint": "Prosječno vrijeme u milisekundama za obradu DNS zahtjeva",
|
||||
"block_domain_use_filters_and_hosts": "Blokiraj domene koristeći filtre ili hosts datoteke",
|
||||
"filters_block_toggle_hint": "Pravila blokiranja možete postaviti u postavkama <a>filtara</a>.",
|
||||
@@ -310,7 +308,6 @@
|
||||
"edns_use_custom_ip": "Koristi prilagođeni IP za EDNS",
|
||||
"edns_use_custom_ip_desc": "Dopusti korištenje prilagođenog IP-a za EDNS",
|
||||
"rate_limit_desc": "Broj zahtjeva u sekundi koji su dopušteni po jednom klijentu. Postavljanje na 0 znači neograničeno.",
|
||||
"rate_limit_whitelist_placeholder": "Unesite jednu adresu poslužitelja po retku",
|
||||
"blocking_ipv4_desc": "Povratna IP adresa za blokirane A zahtjeve",
|
||||
"blocking_ipv6_desc": "Povratna IP adresa za blokirane AAAA zahtjeve",
|
||||
"blocking_mode_default": "Zadano: Odgovori s nultom IP adresom (0.0.0.0 za A; :: za AAAA) kada ga blokira Adblock slično pravilo; odgovorite s IP adresom definiranom u pravilu kada je blokirano od /etc/hosts sličnog pravila",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Kliens beállítások",
|
||||
"example_upstream_reserved": "Megadhat egy DNS kiszolgálót <0>egy adott domainhez vagy domainekhez</0>",
|
||||
"example_multiple_upstreams_reserved": "több upstream szerver <0>adott domainekhez</0>;",
|
||||
"example_upstream_comment": "egy megjegyzés.",
|
||||
"upstream_parallel": "Használjon párhuzamos lekéréseket a domainek feloldásának felgyorsításához az összes upstream kiszolgálóra való egyidejű lekérdezéssel.",
|
||||
"parallel_requests": "Párhuzamos lekérések",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Kényszerített biztonságos keresés",
|
||||
"number_of_dns_query_to_safe_search": "A biztonságos keresésre kényszerített DNS lekérdezések száma",
|
||||
"average_processing_time": "Átlagos feldolgozási idő",
|
||||
"average_upstream_response_time": "Átlagos upstream válaszidő",
|
||||
"response_time": "Válaszidő",
|
||||
"processing_time": "Feldolgozási idő",
|
||||
"average_processing_time_hint": "A DNS lekérdezések feldolgozásához szükséges átlagos idő milliszekundumban",
|
||||
"block_domain_use_filters_and_hosts": "Domainek blokkolása szűrők és hosztfájlok használatával",
|
||||
"filters_block_toggle_hint": "A <a> szűrőbeállításoknál</a> megadhatja a blokkolási szabályokat.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Használjon egyéni IP-címet az EDNS-hez",
|
||||
"edns_use_custom_ip_desc": "Engedélyezze az egyéni IP-cím használatát az EDNS-hez",
|
||||
"rate_limit_desc": "Maximálisan hány kérést küldhet egy kliens másodpercenkén. Ha 0-ra állítja, akkor nincs korlátozás.",
|
||||
"rate_limit_subnet_len_ipv4": "Az IPv4-címek alhálózati előtagjának hossza",
|
||||
"rate_limit_subnet_len_ipv4_desc": "A sebességkorlátozáshoz használt IPv4-címek alhálózati előtagjának hossza. Az alapértelmezett érték 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "Az IPv4 alhálózati előtag hosszának 0 és 32 között kell lennie",
|
||||
"rate_limit_subnet_len_ipv6": "Az IPv6-címek alhálózati előtagjának hossza",
|
||||
"rate_limit_subnet_len_ipv6_desc": "A sebességkorlátozáshoz használt IPv6-címek alhálózati előtagjának hossza. Az alapértelmezett érték 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "Az IPv6 alhálózati előtag hosszának 0 és 128 között kell lennie",
|
||||
"form_enter_rate_limit_subnet_len": "Adja meg az alhálózati előtag hosszát a sebességkorlátozáshoz",
|
||||
"rate_limit_whitelist": "Sebességkorlátozó engedélyezési lista",
|
||||
"rate_limit_whitelist_desc": "A sebességkorlátozásból kizárt IP-címek",
|
||||
"rate_limit_whitelist_placeholder": "Adjon meg egy IP-címet soronként",
|
||||
"blocking_ipv4_desc": "A blokkolt A kéréshez visszaadandó IP-cím",
|
||||
"blocking_ipv6_desc": "A blokkolt AAAA kéréshez visszaadandó IP-cím",
|
||||
"blocking_mode_default": "Alapértelmezés: Válaszoljon nulla IP-címmel (vagyis 0.0.0.0 az A-hoz, :: pedig az AAAA-hoz), amikor a blokkolás egy adblock-stílusú szabállyal történik; illetve válaszoljon egy, a szabály által meghatározott IP címmel, amikor a blokkolás egy /etc/hosts stílusú szabállyal történik",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Pengaturan klien",
|
||||
"example_upstream_reserved": "upstream <0>untuk domain spesifik</0>;",
|
||||
"example_multiple_upstreams_reserved": "beberapa server upstream <0>untuk domain spesifik</0>;",
|
||||
"example_upstream_comment": "komentar.",
|
||||
"upstream_parallel": "Gunakan kueri paralel untuk mempercepat resoluasi dengan menanyakan semua server upstream secara bersamaan",
|
||||
"parallel_requests": "Permintaan paralel",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Paksa pencarian aman",
|
||||
"number_of_dns_query_to_safe_search": "Jumlah perminataan DNS ke mesin pencari yang dipaksa Pencarian Aman",
|
||||
"average_processing_time": "Rata-rata waktu pemrosesan",
|
||||
"average_upstream_response_time": "Waktu respons server upstream rata-rata",
|
||||
"response_time": "Waktu respons",
|
||||
"processing_time": "Waktu pemrosesan",
|
||||
"average_processing_time_hint": "Rata-rata waktu dalam milidetik untuk pemrosesan sebuah permintaan DNS",
|
||||
"block_domain_use_filters_and_hosts": "Blokir domain menggunakan filter dan file hosts",
|
||||
"filters_block_toggle_hint": "Anda dapat menyiapkan aturan pemblokiran di pengaturan <a>Penyaringan</a>.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Gunakan IP khusus untuk EDNS",
|
||||
"edns_use_custom_ip_desc": "Izinkan untuk menggunakan IP kustom untuk EDNS",
|
||||
"rate_limit_desc": "Jumlah permintaan per detik yang diperbolehkan untuk satu klien. Atur ke 0 untuk tidak terbatas.",
|
||||
"rate_limit_subnet_len_ipv4": "Panjang awalan subnet untuk alamat IPv4",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Panjang awalan subnet untuk alamat IPv4 yang digunakan untuk pembatasan kecepatan. Standarnya adalah 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "Panjang awalan subnet IPv4 harus antara 0 dan 32",
|
||||
"rate_limit_subnet_len_ipv6": "Panjang awalan subnet untuk alamat IPv6",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Panjang awalan subnet untuk alamat IPv6 yang digunakan untuk pembatasan kecepatan. Standarnya adalah 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "Panjang awalan subnet IPv6 harus antara 0 dan 128",
|
||||
"form_enter_rate_limit_subnet_len": "Masukkan panjang awalan subnet untuk pembatasan kecepatan",
|
||||
"rate_limit_whitelist": "Daftar pembatasan tarif yang diizinkan",
|
||||
"rate_limit_whitelist_desc": "Alamat IP dikecualikan dari pembatasan tarif",
|
||||
"rate_limit_whitelist_placeholder": "Masukkan satu alamat IP per baris",
|
||||
"blocking_ipv4_desc": "Alamat IP akan dikembalikan untuk permintaan A yang diblokir",
|
||||
"blocking_ipv6_desc": "Alamat IP akan dipulihkan untuk permintaan AAAA yang diblokir",
|
||||
"blocking_mode_default": "Default: Tanggapi dengan alamat IP nol (0.0.0.0 untuk A; :: untuk AAAA) saat diblokir oleh aturan gaya Adblock; tanggapi dengan alamat IP yang ditentukan dalam aturan ketika diblokir oleh aturan gaya host /etc/",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Impostazioni client",
|
||||
"example_upstream_reserved": "un upstream <0>per specifici domini</0>;",
|
||||
"example_multiple_upstreams_reserved": "upstream multipli <0>per domini specifici</0>;",
|
||||
"example_upstream_comment": "un commento.",
|
||||
"upstream_parallel": "Utilizza richieste parallele per accelerare la risoluzione interrogando simultaneamente tutti i server upstream.",
|
||||
"parallel_requests": "Richieste parallele",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Ricerca sicura forzata",
|
||||
"number_of_dns_query_to_safe_search": "Numero di richieste DNS dai motori di ricerca per i quali la Ricerca Sicura è stata forzata",
|
||||
"average_processing_time": "Tempo di elaborazione medio",
|
||||
"average_upstream_response_time": "Tempo medio di risposta upstream",
|
||||
"response_time": "Tempo di risposta",
|
||||
"processing_time": "Tempo di elaborazione",
|
||||
"average_processing_time_hint": "Tempo medio in millisecondi per elaborare una richiesta DNS",
|
||||
"block_domain_use_filters_and_hosts": "Blocca domini utilizzando filtri e file hosts",
|
||||
"filters_block_toggle_hint": "Puoi impostare le regole di blocco nelle impostazioni dei <a>Filtri</a>.",
|
||||
@@ -310,7 +308,6 @@
|
||||
"edns_use_custom_ip": "Usa IP personalizzato per EDNS",
|
||||
"edns_use_custom_ip_desc": "Consentire l'uso di un IP personalizzato per EDNS",
|
||||
"rate_limit_desc": "Il numero di richieste al secondo consentite da un singolo client. Impostare questo valore a 0 rimuove le limitazioni.",
|
||||
"rate_limit_whitelist_placeholder": "Inserisci un indirizzo IP per riga",
|
||||
"blocking_ipv4_desc": "Indirizzo IP per una richiesta DNS IPv4 bloccata",
|
||||
"blocking_ipv6_desc": "Indirizzo IP restituito per una richiesta DNS IPv6 bloccata",
|
||||
"blocking_mode_default": "Risponde con un indirizzo IP pari a zero (0.0.0.0 per A; :: per AAAA) quando bloccato da una regola in stile Blocca-annunci; risponde con l'indirizzo IP specificato nella regola quando bloccato da una regola in stile /etc/hosts",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "クライアント設定",
|
||||
"example_upstream_reserved": "<0>特定のドメイン</0>に対してDNSアップストリームを指定できます。",
|
||||
"example_multiple_upstreams_reserved": "<0>特定ドメイン</0>のための複数のアップストリームサーバー;",
|
||||
"example_upstream_comment": "コメントを追加できます。",
|
||||
"upstream_parallel": "並列リクエストを使用する(同時にすべてのアップストリームサーバーに処理要求することで解決スピードが向上)",
|
||||
"parallel_requests": "並列リクエスト",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "強制されたセーフサーチ",
|
||||
"number_of_dns_query_to_safe_search": "セーフサーチが強制適用された検索エンジンへのDNSリクエストの数",
|
||||
"average_processing_time": "平均処理時間",
|
||||
"average_upstream_response_time": "アップストリームの平均応答時間",
|
||||
"response_time": "応答時間",
|
||||
"processing_time": "処理時間",
|
||||
"average_processing_time_hint": "DNSリクエストの処理にかかる平均時間(ミリ秒単位)",
|
||||
"block_domain_use_filters_and_hosts": "フィルタとhostsファイルを使用してドメインをブロックする",
|
||||
"filters_block_toggle_hint": "<a>フィルタ</a>の設定でブロックするルールを設定することができます。",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "EDNSにカスタムIPを使用する",
|
||||
"edns_use_custom_ip_desc": "EDNS に対してカスタム IP の使用を許可します。",
|
||||
"rate_limit_desc": "一つのクライアントに対して許可される1秒あたりのリクエスト数(「0」に設定すると、制限なしになります)",
|
||||
"rate_limit_subnet_len_ipv4": "IPv4 アドレスのサブネットプレフィックス長",
|
||||
"rate_limit_subnet_len_ipv4_desc": "rate limiting(レート制限)に使用される IPv4 アドレスのサブネットプレフィックス長です。デフォルト値は 24 です。",
|
||||
"rate_limit_subnet_len_ipv4_error": "IPv4 サブネットプレフィックス長は0〜32の範囲内である必要があります。",
|
||||
"rate_limit_subnet_len_ipv6": "IPv6 アドレスのサブネットプレフィックス長",
|
||||
"rate_limit_subnet_len_ipv6_desc": "rate limiting(レート制限)に使用される IPv6 アドレスのサブネットプレフィックス長です。デフォルト値は 56 です。",
|
||||
"rate_limit_subnet_len_ipv6_error": "IPv6 サブネットのプレフィックス長は0〜128の範囲内である必要があります。",
|
||||
"form_enter_rate_limit_subnet_len": "rate limiting(レート制限)のためのサブネットプレフィックス長を入力してください",
|
||||
"rate_limit_whitelist": "rate limiting(レート制限)の許可リスト",
|
||||
"rate_limit_whitelist_desc": "rate limiting(レート制限)の対象から外すIPアドレスを指定できます。",
|
||||
"rate_limit_whitelist_placeholder": "IPアドレスを1行に1つずづ入力してください。",
|
||||
"blocking_ipv4_desc": "ブロックされたAリクエストに対して応答されるIPアドレス",
|
||||
"blocking_ipv6_desc": "ブロックされたAAAAリクエストに対して応答されるIPアドレス",
|
||||
"blocking_mode_default": "デフォルト:Adblock系ルールによってブロックされると、ゼロIPアドレス(Aに対しては「0.0.0.0」、AAAAに対しては「::」)で応答します。/etc/hosts系ルールによってブロックされると、ルールにて指定されているIPアドレスで応答します。",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "클라이언트 설정",
|
||||
"example_upstream_reserved": "<0>특정 도메인에 대한</0> 업스트림;",
|
||||
"example_multiple_upstreams_reserved": "<0>특정 도메인</0>에 대한 여러 업스트림",
|
||||
"example_upstream_comment": "댓글.",
|
||||
"upstream_parallel": "쿼리 처리 속도를 높이려면 모든 업스트림 서버에서 동시에 병렬 쿼리를 사용해주세요.",
|
||||
"parallel_requests": "병렬 처리 요청",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "세이프서치 강제",
|
||||
"number_of_dns_query_to_safe_search": "세이프서치가 적용된 검색 엔진에 대해 DNS 요청 수",
|
||||
"average_processing_time": "평균처리 시간",
|
||||
"average_upstream_response_time": "평균 업스트림 응답 시간",
|
||||
"response_time": "응답 시간",
|
||||
"processing_time": "처리 시간",
|
||||
"average_processing_time_hint": "DNS 요청 처리시 평균 시간(밀리초)",
|
||||
"block_domain_use_filters_and_hosts": "필터 및 호스트 파일을 사용하여 도메인 차단",
|
||||
"filters_block_toggle_hint": "차단규칙<a>필터</a>을 설정할 수 있습니다.",
|
||||
@@ -310,7 +308,6 @@
|
||||
"edns_use_custom_ip": "EDNS에 사용자 지정 IP 사용",
|
||||
"edns_use_custom_ip_desc": "EDNS에 사용자 지정 IP 사용하도록 허용합니다.",
|
||||
"rate_limit_desc": "단일 클라이언트에서 허용 가능한 초 당 요청 생성 숫자 (0: 무제한)",
|
||||
"rate_limit_whitelist_placeholder": "한 줄에 하나씩 IP 주소를 입력하세요.",
|
||||
"blocking_ipv4_desc": "차단된 A 요청에 대해서 반환할 IP 주소",
|
||||
"blocking_ipv6_desc": "차단된 AAAA 요청에 대해서 반환할 IP 주소",
|
||||
"blocking_mode_default": "기본: Adblock 스타일 규칙에 의해 차단되면 제로 IP 주소(A는 0.0.0.0; AAAA는 ::)로 응답합니다; /etc/hosts 스타일 규칙에 의해 차단되면 규칙에 정의된 IP 주소로 응답합니다",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Cliëntinstellingen",
|
||||
"example_upstream_reserved": "een upstream <0>voor specifieke domeinen</0>;",
|
||||
"example_multiple_upstreams_reserved": "meerdere upstreams <0>voor specifieke domeinen</0>;",
|
||||
"example_upstream_comment": "een commentaar.",
|
||||
"upstream_parallel": "Parallelle verzoeken gebruiken om te versnellen door gelijktijdig verzoeken te sturen naar alle upstream servers.",
|
||||
"parallel_requests": "Parallelle verzoeken",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Geforceerd veilig zoeken",
|
||||
"number_of_dns_query_to_safe_search": "Aantal DNS aanvragen in zoekmachines dmv geforceerd veilig zoeken",
|
||||
"average_processing_time": "Gemiddelde procestijd",
|
||||
"average_upstream_response_time": "Gemiddelde upstream responstijd",
|
||||
"response_time": "Responsetijd",
|
||||
"processing_time": "Verwerkingstijd",
|
||||
"average_processing_time_hint": "Gemiddelde verwerkingstijd in milliseconden van een DNS aanvraag",
|
||||
"block_domain_use_filters_and_hosts": "Domeinen blokkeren d.m.v. filters en host-bestanden",
|
||||
"filters_block_toggle_hint": "Je kan blokkeringsregels toevoegen in de <a>Filters</a> instellingen.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Aangepast IP-adres gebruiken voor EDNS",
|
||||
"edns_use_custom_ip_desc": "Toestaan om aangepast IP-adres voor EDNS te gebruiken",
|
||||
"rate_limit_desc": "Het aantal verzoeken per seconde toegelaten per toestel. 0 betekent onbeperkt.",
|
||||
"rate_limit_subnet_len_ipv4": "Lengte subnetvoorvoegsel voor IPv4-adressen",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Lengte subnetvoorvoegsel voor IPv4-adressen die worden gebruikt voor snelheidsbeperking. De standaardwaarde is 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "De lengte van het IPv4-subnetvoorvoegsel moet tussen 0 en 32 liggen",
|
||||
"rate_limit_subnet_len_ipv6": "Lengte subnetvoorvoegsel voor IPv6-adressen",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Lengte subnetvoorvoegsel voor IPv6-adressen die worden gebruikt voor snelheidsbeperking. De standaardwaarde is 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "De lengte van het IPv6-subnetvoorvoegsel moet tussen 0 en 128 liggen",
|
||||
"form_enter_rate_limit_subnet_len": "Voer de lengte van het subnetvoorvoegsel in voor snelheidsbeperking",
|
||||
"rate_limit_whitelist": "Toelatingslijst voor snelheidsbeperking",
|
||||
"rate_limit_whitelist_desc": "IP-adressen uitgesloten van snelheidsbeperking",
|
||||
"rate_limit_whitelist_placeholder": "Voer één IP-adres per regel in",
|
||||
"blocking_ipv4_desc": "IP-adres dat moet worden teruggegeven voor een geblokkeerd A-verzoek",
|
||||
"blocking_ipv6_desc": "IP-adres dat moet worden teruggegeven voor een geblokkeerd A-verzoek",
|
||||
"blocking_mode_default": "Standaard: Reageer met een nul IP adres (0.0.0.0 for A; :: voor AAAA) wanneer geblokkeerd door een Adblock-type regel; reageer met het IP-adres dat is opgegeven in de regel wanneer geblokkeerd door een /etc/hosts type regel",
|
||||
|
||||
@@ -128,6 +128,7 @@
|
||||
"enforced_save_search": "Påtvungede barnevennlige søk",
|
||||
"number_of_dns_query_to_safe_search": "Antall DNS-forespørsler til søkemotorer der \"Safe Search\" ble fremtvunget",
|
||||
"average_processing_time": "Gjennomsnittlig behandlingstid",
|
||||
"processing_time": "Behandlingstid",
|
||||
"average_processing_time_hint": "Gjennomsnittstid for behandling av DNS-forespørsler i millisekunder",
|
||||
"block_domain_use_filters_and_hosts": "Blokker domener ved hjelp av filtre, «hosts»-filer, og rå domener",
|
||||
"filters_block_toggle_hint": "Du kan sette opp blokkeringsoppføringer i <a>Filtre</a>-innstillingene.",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Ustawienia klienta",
|
||||
"example_upstream_reserved": "upstream <0>dla określonych domen</0>;",
|
||||
"example_multiple_upstreams_reserved": "wiele serwerów nadrzędnych <0>dla konkretnej domeny</0>;",
|
||||
"example_upstream_comment": "komentarz.",
|
||||
"upstream_parallel": "Użyj zapytań równoległych, aby przyspieszyć rozwiązywanie przez jednoczesne wysyłanie zapytań do wszystkich serwerów nadrzędnych.",
|
||||
"parallel_requests": "Równoległe żądania",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Wymuszone bezpieczne wyszukiwanie",
|
||||
"number_of_dns_query_to_safe_search": "Liczba żądań DNS kierowanych do wyszukiwarek, dla których wymuszono Bezpieczne wyszukiwanie",
|
||||
"average_processing_time": "Średni czas przetwarzania",
|
||||
"average_upstream_response_time": "Średni czas odpowiedzi serwera nadrzędnego",
|
||||
"response_time": "Czas odpowiedzi",
|
||||
"processing_time": "Czas przetwarzania",
|
||||
"average_processing_time_hint": "Średni czas przetwarzania żądania DNS liczony w milisekundach",
|
||||
"block_domain_use_filters_and_hosts": "Zablokuj domeny za pomocą filtrów i plików host",
|
||||
"filters_block_toggle_hint": "Możesz skonfigurować reguły blokowania w ustawieniach <a>Filtry</a>.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Użyj niestandardowego adresu IP dla EDNS",
|
||||
"edns_use_custom_ip_desc": "Zezwól na użycie niestandardowego adresu IP dla EDNS",
|
||||
"rate_limit_desc": "Liczba żądań na sekundę dozwolona na klienta. Ustawienie wartości 0 oznacza brak ograniczeń.",
|
||||
"rate_limit_subnet_len_ipv4": "Długość maski podsieci dla adresów IPv4",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Długość maski podsieci dla adresów IPv4 używanych do ograniczania prędkości. Domyślnie jest to 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "Długość maski podsieci IPv4 powinna wynosić od 0 do 32",
|
||||
"rate_limit_subnet_len_ipv6": "Długość prefiksu podsieci dla adresów IPv6",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Długość prefiksu podsieci dla adresów IPv6 używanych do ograniczania szybkości. Domyślnie jest to 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "Długość prefiksu podsieci IPv6 powinna wynosić od 0 do 128",
|
||||
"form_enter_rate_limit_subnet_len": "Wprowadź długość prefiksu podsieci dla ograniczenia prędkości",
|
||||
"rate_limit_whitelist": "Lista zezwoleń ograniczających prędkość",
|
||||
"rate_limit_whitelist_desc": "Adresy IP wykluczone z ograniczania prędkości",
|
||||
"rate_limit_whitelist_placeholder": "Wprowadź po jednym adresie IP w każdym wierszu",
|
||||
"blocking_ipv4_desc": "Adres IP, który ma zostać zwrócony w przypadku zablokowanego żądania A",
|
||||
"blocking_ipv6_desc": "Adres IP, który ma zostać zwrócony w przypadku zablokowanego żądania AAAA",
|
||||
"blocking_mode_default": "Domyślna: Odpowiedz z zerowym adresem IP (0.0.0.0 dla A; :: dla AAAA) po zablokowaniu przez regułę Adblock; odpowiedź adresem IP wpisanym w regule, jeśli jest blokowany przez regułę w stylu /etc/hosts",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Configurações do cliente",
|
||||
"example_upstream_reserved": "um DNS primário <0>para o domínios especificos</0>;",
|
||||
"example_multiple_upstreams_reserved": "múltiplos upstreams <0>para domínios específicos</0>;",
|
||||
"example_upstream_comment": "um comentário.",
|
||||
"upstream_parallel": "Usar consultas paralelas para acelerar a resolução consultando simultaneamente todos os servidores DNS primário",
|
||||
"parallel_requests": "Solicitações paralelas",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Forçar pesquisa segura",
|
||||
"number_of_dns_query_to_safe_search": "O número de solicitações de DNS para mecanismos de pesquisa para os quais a pesquisa segura foi aplicada",
|
||||
"average_processing_time": "Tempo médio de processamento",
|
||||
"average_upstream_response_time": "Tempo médio de resposta upstream",
|
||||
"response_time": "Tempo de resposta",
|
||||
"processing_time": "Tempo de processamento",
|
||||
"average_processing_time_hint": "Tempo médio em milissegundos no processamento de uma solicitação DNS",
|
||||
"block_domain_use_filters_and_hosts": "Bloquear domínios usando arquivos de filtros e hosts",
|
||||
"filters_block_toggle_hint": "Você pode configurar as regras de bloqueio nas configurações de <a>Filtros</a>.",
|
||||
@@ -303,23 +301,13 @@
|
||||
"download_mobileconfig_dot": "BAixar .mobileconfig para DNS-sobre-TLS",
|
||||
"download_mobileconfig": "Baixar arquivo de configuração",
|
||||
"plain_dns": "DNS simples",
|
||||
"form_enter_rate_limit": "Insira a velocidade limite",
|
||||
"rate_limit": "Velocidade limite",
|
||||
"form_enter_rate_limit": "Insira a taxa limite",
|
||||
"rate_limit": "Taxa limite",
|
||||
"edns_enable": "Ativar a sub-rede do cliente EDNS",
|
||||
"edns_cs_desc": "Adicione a opção de sub-rede de cliente EDNS (ECS) às solicitações de servidor DNS primário e registre os valores enviados pelos clientes no registro de consulta.",
|
||||
"edns_use_custom_ip": "Usar IP personalizado para EDNS",
|
||||
"edns_use_custom_ip_desc": "Permitir o uso de IP personalizado para EDNS",
|
||||
"rate_limit_desc": "O número de solicitações por segundo permitidas por cliente. Definir como 0 significa que não há limite.",
|
||||
"rate_limit_subnet_len_ipv4": "Comprimento do prefixo de sub-rede para endereços IPv4",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Comprimento do prefixo de sub-rede para endereços IPv4 usados para limitação de velocidade. O padrão é 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "O comprimento do prefixo da sub-rede IPv4 deve estar entre 0 e 32",
|
||||
"rate_limit_subnet_len_ipv6": "Comprimento do prefixo de sub-rede para endereços IPv6",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Comprimento do prefixo de sub-rede para endereços IPv6 usados para limitação de velocidade. O padrão é 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "O comprimento do prefixo da sub-rede IPv6 deve estar entre 0 e 128",
|
||||
"form_enter_rate_limit_subnet_len": "Insira o comprimento do prefixo da sub-rede para limitação de taxa",
|
||||
"rate_limit_whitelist": "Lista de permissões de limitação de velocidade",
|
||||
"rate_limit_whitelist_desc": "Endereços IP excluídos da limitação de velocidade",
|
||||
"rate_limit_whitelist_placeholder": "Insira um endereço IP por linha",
|
||||
"blocking_ipv4_desc": "Endereço de IP a ser retornado para uma solicitação bloqueada",
|
||||
"blocking_ipv6_desc": "Endereço de IP a ser retornado para uma solicitação AAAA bloqueada",
|
||||
"blocking_mode_default": "Padrão: Responder com zero endereço IP (0.0.0.0 para A; :: para AAAA) quando bloqueado pela regra de estilo Adblock; responde com o endereço IP especificado na regra quando bloqueado pela regra /etc/hosts-style",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Definições do cliente",
|
||||
"example_upstream_reserved": "Podes especificar o DNS primário <0>para domínio(s) especifico(s)</0>",
|
||||
"example_multiple_upstreams_reserved": "múltiplos upstreams <0>para domínios específicos</0>;",
|
||||
"example_upstream_comment": "um comentário.",
|
||||
"upstream_parallel": "Usar consultas paralelas para acelerar a resolução consultando simultaneamente todos os servidores DNS",
|
||||
"parallel_requests": "Solicitações paralelas",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Forçar pesquisa segura",
|
||||
"number_of_dns_query_to_safe_search": "O número de solicitações de DNS para motores de busca para os quais a pesquisa segura foi aplicada",
|
||||
"average_processing_time": "Tempo médio de processamento",
|
||||
"average_upstream_response_time": "Tempo médio de resposta upstream",
|
||||
"response_time": "Tempo de resposta",
|
||||
"processing_time": "Tempo de processamento",
|
||||
"average_processing_time_hint": "Tempo médio em milissegundos no processamento de uma solicitação DNS",
|
||||
"block_domain_use_filters_and_hosts": "Bloquear domínios usando ficheiros de filtros e hosts",
|
||||
"filters_block_toggle_hint": "Pode configurar as regras de bloqueio nas configurações de <a>Filtros</a>.",
|
||||
@@ -303,23 +301,13 @@
|
||||
"download_mobileconfig_dot": "Transferir .mobileconfig para DNS-sobre-TLS",
|
||||
"download_mobileconfig": "Transferir ficheiro de configuração",
|
||||
"plain_dns": "DNS simples",
|
||||
"form_enter_rate_limit": "Insira o limite de velocidade",
|
||||
"rate_limit": "Limite de velocidade",
|
||||
"form_enter_rate_limit": "Insira o limite de taxa",
|
||||
"rate_limit": "Limite de taxa",
|
||||
"edns_enable": "Ativar a sub-rede do cliente EDNS",
|
||||
"edns_cs_desc": "Adicione a opção de sub-rede de cliente EDNS (ECS) às solicitações de servidor DNS primário e registre os valores enviados pelos clientes no registo de consulta.",
|
||||
"edns_use_custom_ip": "Usar IP personalizado para EDNS",
|
||||
"edns_use_custom_ip_desc": "Permitir a utilização de IP personalizado para EDNS",
|
||||
"rate_limit_desc": "O número de solicitações por segundo permitido por cliente. Configurando para 0 significa sem limite.",
|
||||
"rate_limit_subnet_len_ipv4": "Comprimento do prefixo de sub-rede para endereços IPv4",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Comprimento do prefixo de sub-rede para endereços IPv4 usados para limitação de velocidade. O padrão é 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "O comprimento do prefixo da sub-rede IPv4 deve estar entre 0 e 32",
|
||||
"rate_limit_subnet_len_ipv6": "Comprimento do prefixo de sub-rede para endereços IPv6",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Comprimento do prefixo de sub-rede para endereços IPv6 usados para limitação de velocidade. O padrão é 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "O comprimento do prefixo da sub-rede IPv6 deve situar-se entre 0 e 128",
|
||||
"form_enter_rate_limit_subnet_len": "Introduza o comprimento do prefixo da sub-rede para limitação da velocidade",
|
||||
"rate_limit_whitelist": "Lista de permissões de limitação de velocidade",
|
||||
"rate_limit_whitelist_desc": "Endereços IP excluídos da limitação de velocidade",
|
||||
"rate_limit_whitelist_placeholder": "Insira um endereço IP por linha",
|
||||
"blocking_ipv4_desc": "Endereço IP a ser devolvido para uma solicitação A bloqueada",
|
||||
"blocking_ipv6_desc": "Endereço IP a ser devolvido para uma solicitação AAAA bloqueada",
|
||||
"blocking_mode_default": "Predefinido: Responder com zero endereço IP (0.0.0.0 para A; :: para AAAA) quando bloqueado pela regra de estilo Adblock; responde com o endereço IP especificado na regra quando bloqueado pela regra /etc/hosts-style",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Setări client",
|
||||
"example_upstream_reserved": "un flux în amonte <0>pentru domenii specifice</0>;",
|
||||
"example_multiple_upstreams_reserved": "mai mulți servere în amonte <0>pentru domenii specifice</0>;",
|
||||
"example_upstream_comment": "un comentariu.",
|
||||
"upstream_parallel": "Folosiți interogări paralele pentru a accelera rezolvarea, interogând simultan toate serverele în amonte.",
|
||||
"parallel_requests": "Solicitări paralele",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Căutare protejată întărită",
|
||||
"number_of_dns_query_to_safe_search": "Numărul de interogări DNS pe motoarele de căutare pentru care a fost impusă Căutarea Sigură",
|
||||
"average_processing_time": "Timpul mediu de procesare",
|
||||
"average_upstream_response_time": "Timpul mediu de răspuns al serverului în amonte",
|
||||
"response_time": "Timp de răspuns",
|
||||
"processing_time": "Timp de procesare",
|
||||
"average_processing_time_hint": "Timp mediu în milisecunde la procesarea unei cereri DNS",
|
||||
"block_domain_use_filters_and_hosts": "Blocați domenii folosind filtre și fișiere hosts",
|
||||
"filters_block_toggle_hint": "Puteți configura regulile de blocare în setările <a>Filtre</a>.",
|
||||
@@ -310,7 +308,6 @@
|
||||
"edns_use_custom_ip": "Utilizați IP personalizat pentru EDNS",
|
||||
"edns_use_custom_ip_desc": "Permiteți utilizarea IP-ului personalizat pentru EDNS",
|
||||
"rate_limit_desc": "Numărul de interogări pe secundă permise pe client. Setarea la 0 înseamnă că nu există limită.",
|
||||
"rate_limit_whitelist_placeholder": "Introduceți o adresă IP per linie",
|
||||
"blocking_ipv4_desc": "Adresa IP de returnat pentru o cerere A de blocare",
|
||||
"blocking_ipv6_desc": "Adresa IP de returnat pentru o cerere AAAA de blocare",
|
||||
"blocking_mode_default": "Implicit: Răspunde cu adresa IP (0.0.0.0 for A; :: pentru AAAA) când sunt blocate de regulă tip Adblock; răspunde cu adresa IP specificată în regulă când sunt blocate de regula tip /etc/hosts",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Настройки клиентов",
|
||||
"example_upstream_reserved": "DNS-сервер <0>для конкретных доменов</0>;",
|
||||
"example_multiple_upstreams_reserved": "несколько DNS-серверов <0>для конкретных доменов</0>;",
|
||||
"example_upstream_comment": "комментарий.",
|
||||
"upstream_parallel": "Использовать параллельные запросы ко всем серверам одновременно для ускорения обработки запроса.",
|
||||
"parallel_requests": "Параллельные запросы",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Применён безопасный поиск",
|
||||
"number_of_dns_query_to_safe_search": "Количество запросов DNS для поисковых систем, для которых был применён Безопасный поиск",
|
||||
"average_processing_time": "Среднее время обработки запроса",
|
||||
"average_upstream_response_time": "Среднее время ответа upstream-сервера",
|
||||
"response_time": "Время ответа",
|
||||
"processing_time": "Время обработки",
|
||||
"average_processing_time_hint": "Среднее время для обработки запроса DNS в миллисекундах",
|
||||
"block_domain_use_filters_and_hosts": "Блокировать домены с использованием фильтров и файлов hosts",
|
||||
"filters_block_toggle_hint": "Вы можете настроить правила блокировки в <a>«Фильтрах»</a>.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"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": "Введите по одному адресу на строчку",
|
||||
"blocking_ipv4_desc": "IP-адрес, возвращаемый при блокировке A-запроса",
|
||||
"blocking_ipv6_desc": "IP-адрес, возвращаемый при блокировке AAAA-запроса",
|
||||
"blocking_mode_default": "Стандартный: Отвечает с нулевым IP-адресом, (0.0.0.0 для A; :: для AAAA) когда заблокировано правилом в стиле Adblock; отвечает с IP-адресом, указанным в правиле, когда заблокировано правилом в стиле файлов hosts",
|
||||
|
||||
@@ -122,6 +122,7 @@
|
||||
"enforced_save_search": "ආරක්ෂිත සෙවීම බලාත්මක කළ",
|
||||
"number_of_dns_query_to_safe_search": "ආරක්ෂිත සෙවීම බලාත්මක කළ සෙවුම් යන්ත්ර සඳහා ව.නා.ප. ඉල්ලීම් ගණන",
|
||||
"average_processing_time": "සාමාන්ය සැකසුම් කාලය",
|
||||
"processing_time": "සැකසුම් කාලය",
|
||||
"average_processing_time_hint": "ව.නා.ප. ඉල්ලීමක් සැකසීමේ සාමාන්ය කාලය මිලි තත්පර වලින්",
|
||||
"block_domain_use_filters_and_hosts": "පෙරහන් හා සත්කාරක ගොනු භාවිතයෙන් වසම් අවහිර කරන්න",
|
||||
"filters_block_toggle_hint": "ඔබට අවහිර කිරීමේ නීති <a>පෙරහන්</a> තුළ පිහිටුවිය හැකිය.",
|
||||
@@ -646,20 +647,6 @@
|
||||
"log_and_stats_section_label": "විමසුම් සටහන හා සංඛ්යාලේඛන",
|
||||
"ignore_query_log": "විමසුම් සටහනට මෙම අනුග්රාහකය යොදන්න එපා",
|
||||
"ignore_statistics": "සංඛ්යාලේඛනයට මෙම අනුග්රාහකය යොදන්න එපා",
|
||||
"schedule_invalid_select": "ආරම්භක වේලාව අවසන් වේලාවට කලින් විය යුතුය",
|
||||
"schedule_select_days": "දවස් තෝරන්න",
|
||||
"schedule_timezone": "වේලා කලාපයක් තෝරන්න",
|
||||
"schedule_current_timezone": "වත්මන් වේලා කලාපය: {{value}}",
|
||||
"schedule_time_all_day": "දවස පුරාම",
|
||||
"schedule_from": "සිට",
|
||||
"schedule_to": "දක්වා",
|
||||
"sunday": "ඉරිදා",
|
||||
"monday": "සඳුදා",
|
||||
"tuesday": "අඟහරුවාදා",
|
||||
"wednesday": "බදාදා",
|
||||
"thursday": "බ්රහස්පතින්දා",
|
||||
"friday": "සිකුරාදා",
|
||||
"saturday": "සෙනසුරාදා",
|
||||
"sunday_short": "ඉරිදා",
|
||||
"monday_short": "සඳුදා",
|
||||
"tuesday_short": "අඟහ",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Nastavenie klienta",
|
||||
"example_upstream_reserved": "upstream <0>pre konkrétne domény</0>;",
|
||||
"example_multiple_upstreams_reserved": "viaceré upstreamy pre <0>konkrétne domény</0>;",
|
||||
"example_upstream_comment": "komentár.",
|
||||
"upstream_parallel": "Používať paralelné dopyty na zrýchlenie súčasným dopytovaním všetkých upstream serverov súčasne.",
|
||||
"parallel_requests": "Paralelné dopyty",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Vynútené bezpečné vyhľadávanie",
|
||||
"number_of_dns_query_to_safe_search": "Počet DNS dopytov na vyhľadávače, pri ktorých bolo vynútené bezpečné vyhľadávanie",
|
||||
"average_processing_time": "Priemerný čas spracovania",
|
||||
"average_upstream_response_time": "Priemerný čas odozvy upstreamu",
|
||||
"response_time": "Čas odozvy",
|
||||
"processing_time": "Doba spracovania",
|
||||
"average_processing_time_hint": "Priemerný čas spracovania DNS dopytu v milisekundách",
|
||||
"block_domain_use_filters_and_hosts": "Blokovať domény pomocou filtrov a zoznamov adries",
|
||||
"filters_block_toggle_hint": "Pravidlá blokovania môžete nastaviť v nastaveniach <a>Filtre</a>.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Použiť vlastnú IP adresu pre EDNS",
|
||||
"edns_use_custom_ip_desc": "Povoliť používanie vlastnej IP adresy pre EDNS",
|
||||
"rate_limit_desc": "Počet požiadaviek za sekundu, ktoré môže jeden klient vykonať. Nastavenie na hodnotu 0 znamená neobmedzene.",
|
||||
"rate_limit_subnet_len_ipv4": "Dĺžka prefixu podsiete pre adresy IPv4",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Dĺžka prefixu podsiete pre adresy IPv4 používané na obmedzenie rýchlosti. Predvolená hodnota je 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "Dĺžka prefixu podsiete IPv4 musí byť od 0 do 32",
|
||||
"rate_limit_subnet_len_ipv6": "Dĺžka prefixu podsiete pre adresy IPv6",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Dĺžka prefixu podsiete pre adresy IPv6 používané na obmedzenie rýchlosti. Predvolená hodnota je 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "Dĺžka prefixu podsiete IPv6 musí byť od 0 do 128",
|
||||
"form_enter_rate_limit_subnet_len": "Zadajte dĺžku prefixu podsiete pre obmedzenie rýchlosti",
|
||||
"rate_limit_whitelist": "Zoznam povolení obmedzujúcich rýchlosť",
|
||||
"rate_limit_whitelist_desc": "IP adresy vylúčené z obmedzenia rýchlosti",
|
||||
"rate_limit_whitelist_placeholder": "Na každý riadok zadajte IP adresu jedného servera",
|
||||
"blocking_ipv4_desc": "IP adresa, ktorá sa má vrátiť v prípade blokovanej žiadosti A",
|
||||
"blocking_ipv6_desc": "IP adresa, ktorá sa má vrátiť v prípade blokovanej žiadosti AAAA",
|
||||
"blocking_mode_default": "Predvolené: Odpovedať nulovou adresou IP (0,0.0.0 pre A; :: pre AAAA), keď je blokovaná pravidlom v štýle Adblock; odpovedať IP adresou uvedenou v pravidle, keď je blokovaná pravidlom v štýle /etc/hosts",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Nastavitve odjemalca",
|
||||
"example_upstream_reserved": "gorvodni <0>za določene domene</0>;",
|
||||
"example_multiple_upstreams_reserved": "več gorvodnih <0>za določene domene</0>;",
|
||||
"example_upstream_comment": "komentar.",
|
||||
"upstream_parallel": "Uporabite vzporedne zahteve za pospešitev reševanja s hkratnim poizvedovanjem vseh gorvodnih strežnikov.",
|
||||
"parallel_requests": "Vzporedne zahteve",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Prisilno varno iskanje",
|
||||
"number_of_dns_query_to_safe_search": "Število zahtev DNS za iskalnike, za katere je bilo uveljavljeno varno iskanje",
|
||||
"average_processing_time": "Povprečni čas obdelave",
|
||||
"average_upstream_response_time": "Povprečni gorvodni odzivni čas",
|
||||
"response_time": "Odzivni čas",
|
||||
"processing_time": "Čas obdelave",
|
||||
"average_processing_time_hint": "Povprečni čas v milisekundah pri obdelavi zahteve DNS",
|
||||
"block_domain_use_filters_and_hosts": "Onemogoči domene s filtri in gostiteljskimi datotekami",
|
||||
"filters_block_toggle_hint": "Pravila zaviranja lahko nastavite v nastavitvah <a>Filtri</a>.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Uporabi IP po meri za EDNS",
|
||||
"edns_use_custom_ip_desc": "Dovoli uporabo naslova IP po meri za EDNS",
|
||||
"rate_limit_desc": "Dovoljeno število zahtev na sekundo na odjemalca. Nastavitev na 0 pomeni brez omejitve.",
|
||||
"rate_limit_subnet_len_ipv4": "Dolžina predpone podomrežja za naslove IPv4",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Dolžina predpone podomrežja za naslove IPv4, ki se uporabljajo za omejevanje hitrosti. Privzeto je 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "Dolžina predpone podomrežja IPv4 mora biti med 0 in 32",
|
||||
"rate_limit_subnet_len_ipv6": "Dolžina predpone podomrežja za naslove IPv4",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Dolžina predpone podomrežja za naslove IPv6, ki se uporabljajo za omejevanje hitrosti. Privzeta vrednost je 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "Dolžina podomrežne predpone IPv6 mora biti med 0 in 128",
|
||||
"form_enter_rate_limit_subnet_len": "Vnesite dolžino predpone podomrežja za omejitev hitrosti",
|
||||
"rate_limit_whitelist": "Seznam dovoljenih za omejevanje hitrosti",
|
||||
"rate_limit_whitelist_desc": "Naslovi IP so izključeni iz omejitve hitrosti",
|
||||
"rate_limit_whitelist_placeholder": "Vnesite en naslov IP na vrstico",
|
||||
"blocking_ipv4_desc": "IP naslov, ki mora biti vrnjen za onemogočeno zahtevo A",
|
||||
"blocking_ipv6_desc": "IP naslov, ki mora biti vrnjen za onemogočeno zahtevo AAAA",
|
||||
"blocking_mode_default": "Privzeto: odgovori z ničelnim naslovom IP (0.0.0.0 za A; :: za AAAA), ko je onemogočen s pravilom v slogu Adblocka; odgovor z naslovom IP, določenim v pravilu, ko je onemogočen s pravilom /etc/hosts",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Postavke klijenta",
|
||||
"example_upstream_reserved": "upstream <0>za određene domene</0>;",
|
||||
"example_multiple_upstreams_reserved": "nekoliko DNS servera <0>za određene domene</0>;",
|
||||
"example_upstream_comment": "komentar.",
|
||||
"upstream_parallel": "Koristite paralelne upite da biste ubrzali rešavanje tako što ćete istovremeno ispitati sve uzvodne servere.",
|
||||
"parallel_requests": "Paralelni zahtevi",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Nametni sigurno pretraživanje",
|
||||
"number_of_dns_query_to_safe_search": "Broj DNS zahteva ka pretraživačima za koje je nametnuto sigurno pretraživanje",
|
||||
"average_processing_time": "Prosečno vreme obrade",
|
||||
"average_upstream_response_time": "Prosečno vreme odziva upstream-servera",
|
||||
"response_time": "Vreme odziva",
|
||||
"processing_time": "Vreme obrade",
|
||||
"average_processing_time_hint": "Prosečno vreme u milisekundama za obradu DNS zahteva",
|
||||
"block_domain_use_filters_and_hosts": "Blokiraj domene koristeći filtere i hosts datoteke",
|
||||
"filters_block_toggle_hint": "Možete postaviti pravila blokiranja u <a>Filters</a> postavkama.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Koristi prilagođeni IP za EDNS",
|
||||
"edns_use_custom_ip_desc": "Dozvoli korišćenje prilagođenog IP-a za EDNS",
|
||||
"rate_limit_desc": "Broj zahteva u sekundi dozvoljen po klijentu. Postavljanje na 0 znači da nema ograničenja.",
|
||||
"rate_limit_subnet_len_ipv4": "Dužina prefixa podmreže za IPv4 adrese",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Dužina prefixa podmreže za IPv4 adrese koje se koriste za ograničavanje brzine. Podrazumevano je 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "Dužina prefixa IPv4 podmreže treba da bude između 0 i 32",
|
||||
"rate_limit_subnet_len_ipv6": "Dužina prefixa podmreže za IPv6 adrese",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Dužina prefixa podmreže za IPv6 adrese koje se koriste za ograničavanje brzine. Podrazumevano je 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "Dužina prefixa IPv6 podmreže treba da bude između 0 i 128",
|
||||
"form_enter_rate_limit_subnet_len": "Unesite dužinu prefixa podmreže da biste ograničili brzinu",
|
||||
"rate_limit_whitelist": "Lista dozvoljenih lista za ograničavanje brzine",
|
||||
"rate_limit_whitelist_desc": "IP adrese koje nisu obuhvaćene ograničenjem brzine",
|
||||
"rate_limit_whitelist_placeholder": "Unesite jednu IP adresu servera po redu",
|
||||
"blocking_ipv4_desc": "IP adresa koja će biti vraćena za blokirane zahteve",
|
||||
"blocking_ipv6_desc": "IP adresa koja će biti vraćena za blokirane AAAA zahteve",
|
||||
"blocking_mode_default": "Podrazumevano: Odgovara sa REFUSED kada je blokirano od Adblock-style pravila; odgovara sa IP adresom koja je određena u pravilu kada je blokiran od /etc/hosts-style pravila",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
{
|
||||
"client_settings": "Klientinställningar",
|
||||
"example_upstream_reserved": "uppström <0>för en specifik domän</0>;",
|
||||
"example_multiple_upstreams_reserved": "flera uppströmsservrar <0>för specifika domäner</0>;",
|
||||
"example_upstream_comment": "en kommentar.",
|
||||
"example_upstream_comment": "du kan ange en kommentar.",
|
||||
"upstream_parallel": "Använd parallella förfrågningar för att snabba upp dessa genom att fråga alla uppströmsservrar samtidigt.",
|
||||
"parallel_requests": "Parallella förfrågningar",
|
||||
"load_balancing": "Lastbalansering",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Aktivering av Säker surf",
|
||||
"number_of_dns_query_to_safe_search": "Antalet DNS-förfrågningar mot sökmotorer där Säker surf tvingats",
|
||||
"average_processing_time": "Genomsnittlig processtid",
|
||||
"average_upstream_response_time": "Genomsnittlig svarstid uppströmsserver",
|
||||
"response_time": "Svarstid",
|
||||
"processing_time": "Bearbetningstid",
|
||||
"average_processing_time_hint": "Genomsnittlig processtid i millisekunder för DNS-förfrågning",
|
||||
"block_domain_use_filters_and_hosts": "Blockera domäner med filter- och värdfiler",
|
||||
"filters_block_toggle_hint": "Du kan ställa in egna blockerings regler i <a>Filterinställningar</a>.",
|
||||
@@ -310,7 +308,6 @@
|
||||
"edns_use_custom_ip": "Använd anpassad IP för EDNS",
|
||||
"edns_use_custom_ip_desc": "Tillåt att använda anpassad IP för EDNS",
|
||||
"rate_limit_desc": "Antalet förfrågningar per sekund som tillåts per klient. Att sätta den till 0 innebär ingen gräns.",
|
||||
"rate_limit_whitelist_placeholder": "Ange en IP-adress per rad",
|
||||
"blocking_ipv4_desc": "IP adress som ska returneras för en blockerad A förfrågan",
|
||||
"blocking_ipv6_desc": "IP adress som ska returneras för en blockerad AAAA förfrågan",
|
||||
"blocking_mode_default": "Standard: Svara med noll IP-adress (0.0.0.0 för A; :: för AAAA) när det blockeras av regel i Adblock-stil; svara med IP-adressen som anges i regeln när den blockeras av regel i /etc/hosts-stil",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "İstemci ayarları",
|
||||
"example_upstream_reserved": "<0>belirli alan adları</0> için bir üst sunucusu;",
|
||||
"example_multiple_upstreams_reserved": "<0>belirli alanlar için</0> birden fazla üst kaynaklar;",
|
||||
"example_upstream_comment": "bir yorum.",
|
||||
"upstream_parallel": "Tüm üst sunucuları eş zamanlı sorgulayarak çözümlemeyi hızlandırmak için paralel sorgular kullanın.",
|
||||
"parallel_requests": "Paralel istekler",
|
||||
@@ -98,7 +97,7 @@
|
||||
"filters": "Filtreler",
|
||||
"filter": "Filtre",
|
||||
"query_log": "Sorgu Günlüğü",
|
||||
"compact": "Sık",
|
||||
"compact": "Yoğun",
|
||||
"nothing_found": "Hiçbir şey bulunamadı",
|
||||
"faq": "SSS",
|
||||
"version": "Sürüm",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Uygulanan güvenli arama",
|
||||
"number_of_dns_query_to_safe_search": "Güvenli Aramanın uygulandığı arama motorlarına gönderilen DNS isteklerinin sayısı",
|
||||
"average_processing_time": "Ortalama işlem süresi",
|
||||
"average_upstream_response_time": "Ortalama üst kaynak yanıt süresi",
|
||||
"response_time": "Yanıt süresi",
|
||||
"processing_time": "İşlem süresi",
|
||||
"average_processing_time_hint": "Bir DNS isteğinin milisaniye cinsinden ortalama işlem süresi",
|
||||
"block_domain_use_filters_and_hosts": "Filtre ve hosts dosyalarını kullanarak alan adlarını engelle",
|
||||
"filters_block_toggle_hint": "<a>Filtreler</a> ayarlarında engelleme kuralları oluşturabilirsiniz.",
|
||||
@@ -182,7 +180,7 @@
|
||||
"enabled_save_search_toast": "Güvenli Arama etkinleştirildi",
|
||||
"updated_save_search_toast": "Güvenli Arama ayarları güncellendi",
|
||||
"enabled_table_header": "Etkin",
|
||||
"name_table_header": "Adı",
|
||||
"name_table_header": "Ad",
|
||||
"list_url_table_header": "Liste URL'si",
|
||||
"rules_count_table_header": "Kural sayısı",
|
||||
"last_time_updated_table_header": "Son güncelleme zamanı",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "EDNS için özel IP kullan",
|
||||
"edns_use_custom_ip_desc": "EDNS için özel IP kullanımına izin ver",
|
||||
"rate_limit_desc": "İstemci başına izin verilen saniyedeki istek sayısı. 0 olarak ayarlamak, sınır olmadığı anlamına gelir.",
|
||||
"rate_limit_subnet_len_ipv4": "IPv4 adresleri için alt ağ önek uzunluğu",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Hız sınırlaması için kullanılan IPv4 adreslerinin alt ağ önek uzunluğu. Varsayılan 24'tür",
|
||||
"rate_limit_subnet_len_ipv4_error": "IPv4 alt ağ önek uzunluğu 0 ile 32 arasında olmalıdır",
|
||||
"rate_limit_subnet_len_ipv6": "IPv6 adresleri için alt ağ önek uzunluğu",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Hız sınırlaması için kullanılan IPv6 adreslerinin alt ağ önek uzunluğu. Varsayılan 56'tür",
|
||||
"rate_limit_subnet_len_ipv6_error": "IPv6 alt ağ önek uzunluğu 0 ile 128 arasında olmalıdır",
|
||||
"form_enter_rate_limit_subnet_len": "Hız sınırlaması için alt ağ önek uzunluğunu girin",
|
||||
"rate_limit_whitelist": "Hız sınırlama izin listesi",
|
||||
"rate_limit_whitelist_desc": "Hız sınırlamasından hariç tutulan IP adresleri",
|
||||
"rate_limit_whitelist_placeholder": "Her satıra bir IP adresi girin",
|
||||
"blocking_ipv4_desc": "Engellenen bir A isteği için geri döndürülecek IP adresi",
|
||||
"blocking_ipv6_desc": "Engellenen bir AAAA isteği için geri döndürülecek IP adresi",
|
||||
"blocking_mode_default": "Varsayılan: Reklam engelleme tarzı kural tarafından engellendiğinde sıfır IP adresiyle (A için 0.0.0.0; :: AAAA için) yanıt verin; /etc/hosts-tarzı kural tarafından engellendiğinde, kuralda belirtilen IP adresiyle yanıt verin",
|
||||
@@ -447,7 +435,7 @@
|
||||
"settings_global": "Genel",
|
||||
"settings_custom": "Özel",
|
||||
"table_client": "İstemci",
|
||||
"table_name": "AdAdı",
|
||||
"table_name": "Ad",
|
||||
"save_btn": "Kaydet",
|
||||
"client_add": "İstemci Ekle",
|
||||
"client_new": "Yeni İstemci",
|
||||
@@ -461,7 +449,7 @@
|
||||
"form_enter_id": "Tanımlayıcı girin",
|
||||
"form_add_id": "Tanımlayıcı ekle",
|
||||
"form_client_name": "İstemci ismi girin",
|
||||
"name": "Adı",
|
||||
"name": "Ad",
|
||||
"client_global_settings": "Genel ayarları kullan",
|
||||
"client_deleted": "\"{{key}}\" istemcisi başarıyla silindi",
|
||||
"client_added": "\"{{key}}\" istemcisi başarıyla eklendi",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Налаштування клієнта",
|
||||
"example_upstream_reserved": "DNS-сервер <0>для певних доменів</0>;",
|
||||
"example_multiple_upstreams_reserved": "кілька DNS-серверів <0>для конкретних доменів</0>;",
|
||||
"example_upstream_comment": "коментар.",
|
||||
"upstream_parallel": "Використовувати паралельні запити, щоб пришвидшити вирішення одночасною чергою всіх оригінальних серверів.",
|
||||
"parallel_requests": "Паралельні запити",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Примусовий безпечний пошук",
|
||||
"number_of_dns_query_to_safe_search": "Кількість DNS-запитів до пошукових систем, для яких примусово застосований безпечний пошук",
|
||||
"average_processing_time": "Середній час обробки",
|
||||
"average_upstream_response_time": "Середній час відгуку upstream-сервера",
|
||||
"response_time": "Час відгуку",
|
||||
"processing_time": "Час обробки",
|
||||
"average_processing_time_hint": "Середній час обробки DNS запиту в мілісекундах",
|
||||
"block_domain_use_filters_and_hosts": "Блокування доменів за допомогою фільтрів та hosts-файлів",
|
||||
"filters_block_toggle_hint": "Ви можете налаштувати правила блокування в розділі <a>Фільтри</a>.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"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": "Вводьте одну адресу на рядок",
|
||||
"blocking_ipv4_desc": "IP-адреса, яку потрібно видати для заблокованого A запиту",
|
||||
"blocking_ipv6_desc": "IP-адреса, яку потрібно видати для заблокованого АААА запиту",
|
||||
"blocking_mode_default": "Усталено: відповідь із нульовою IP-адресою (0.0.0.0 для A; :: для AAAA), якщо заблоковано правилом у Adblock-стилі; відповідь зазначеною у правилі IP-адресою, якщо заблокувано правилом у hosts-стилі",
|
||||
@@ -695,7 +683,7 @@
|
||||
"disable_notify_for_minutes_plural": "Вимкнення захисту на {{count}} хвилин",
|
||||
"disable_notify_for_hours": "Вимкнення захисту на {{count}} годину",
|
||||
"disable_notify_for_hours_plural": "Вимкнення захисту на {{count}} годин",
|
||||
"disable_notify_until_tomorrow": "Вимкнути захист до завтра",
|
||||
"disable_notify_until_tomorrow": "Відключення захисту до завтра",
|
||||
"enable_protection_timer": "Захист буде ввімкнено о {{time}}",
|
||||
"custom_retention_input": "Введіть час в годинах",
|
||||
"custom_rotation_input": "Введіть час в годинах",
|
||||
@@ -713,7 +701,7 @@
|
||||
"schedule_current_timezone": "Поточний часовий пояс: {{value}}",
|
||||
"schedule_time_all_day": "Увесь день",
|
||||
"schedule_modal_description": "Цей розклад замінить усі наявні розклади на той самий день тижня. Кожен день тижня може мати тільки один період бездіяльності.",
|
||||
"schedule_modal_time_off": "Вимкнення блокування сервісів:",
|
||||
"schedule_modal_time_off": "Блокування сервісів відключена:",
|
||||
"schedule_new": "Новий розклад",
|
||||
"schedule_edit": "Редагувати розклад",
|
||||
"schedule_save": "Зберегти розклад",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "Cài đặt thiết bị",
|
||||
"example_upstream_reserved": "ngược dòng <0>cho các miền cụ thể</0>;",
|
||||
"example_multiple_upstreams_reserved": "nhiều máy chủ thượng nguồn <0>cho các miền cụ thể</0>;",
|
||||
"example_upstream_comment": "một lời bình luận.",
|
||||
"upstream_parallel": "Sử dụng truy vấn song song để tăng tốc độ giải quyết bằng cách truy vấn đồng thời tất cả các máy chủ ngược tuyến",
|
||||
"parallel_requests": "Yêu cầu song song",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "Bắt buộc tìm kiếm an toàn",
|
||||
"number_of_dns_query_to_safe_search": "Số yêu cầu DNS tới công cụ tìm kiếm đã chuyển thành tìm kiếm an toàn",
|
||||
"average_processing_time": "Thời gian xử lý trung bình",
|
||||
"average_upstream_response_time": "Thời gian phản hồi trung bình từ máy chủ thượng nguồn",
|
||||
"response_time": "Thời gian đáp ứng",
|
||||
"processing_time": "Thời gian xử lý",
|
||||
"average_processing_time_hint": "Thời gian trung bình cho một yêu cầu DNS tính bằng mili giây",
|
||||
"block_domain_use_filters_and_hosts": "Chặn tên miền sử dụng các bộ lọc và file hosts",
|
||||
"filters_block_toggle_hint": "Bạn có thể thiết lập quy tắc chặn tại cài đặt <a>Bộ lọc</a>.",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "Sử dụng địa chỉ IP tùy chỉnh cho EDNS",
|
||||
"edns_use_custom_ip_desc": "Cho phép sử dụng địa chỉ IP tùy chỉnh cho EDNS",
|
||||
"rate_limit_desc": "Số lượng yêu cầu mỗi giây mà một khách hàng được phép thực hiện (0: không giới hạn)",
|
||||
"rate_limit_subnet_len_ipv4": "Độ dài tiền tố mạng con cho địa chỉ IPv4",
|
||||
"rate_limit_subnet_len_ipv4_desc": "Độ dài tiền tố mạng con cho các địa chỉ IPv4 được sử dụng để giới hạn tốc độ. Mặc định là 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "Độ dài tiền tố mạng con IPv4 phải nằm trong khoảng từ 0 đến 32",
|
||||
"rate_limit_subnet_len_ipv6": "Độ dài tiền tố mạng con cho địa chỉ IPv6",
|
||||
"rate_limit_subnet_len_ipv6_desc": "Độ dài tiền tố mạng con cho các địa chỉ IPv6 được sử dụng để giới hạn tốc độ. Mặc định là 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "Độ dài tiền tố mạng con IPv6 phải nằm trong khoảng từ 0 đến 128",
|
||||
"form_enter_rate_limit_subnet_len": "Nhập độ dài tiền tố mạng con để giới hạn tốc độ",
|
||||
"rate_limit_whitelist": "Danh sách cho phép giới hạn tỷ lệ",
|
||||
"rate_limit_whitelist_desc": "Địa chỉ IP bị loại trừ khỏi giới hạn tốc độ",
|
||||
"rate_limit_whitelist_placeholder": "Nhập một địa chỉ IP trên mỗi dòng",
|
||||
"blocking_ipv4_desc": "Địa chỉ IP được trả lại cho một yêu cầu A bị chặn",
|
||||
"blocking_ipv6_desc": "Địa chỉ IP được trả lại cho một yêu cầu AAA bị chặn",
|
||||
"blocking_mode_default": "Mặc định: Trả lời với NXDOMAIN khi bị chặn bởi quy tắc kiểu Adblock; phản hồi với địa chỉ IP được chỉ định trong quy tắc khi bị chặn bởi quy tắc / etc / hosts-style",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "客户端设置",
|
||||
"example_upstream_reserved": "指定为<0>特定域名</0>的上游服务器;",
|
||||
"example_multiple_upstreams_reserved": "<0>特定域名</0>的多个上游服务器;",
|
||||
"example_upstream_comment": "注释。",
|
||||
"upstream_parallel": "使用并行请求以同时查询所有上游服务器来加快解析速度。",
|
||||
"parallel_requests": "并行请求",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "强制安全搜索",
|
||||
"number_of_dns_query_to_safe_search": "启用强制安全搜索后对搜索引擎的 DNS 请求总数",
|
||||
"average_processing_time": "平均处理时间",
|
||||
"average_upstream_response_time": "上游服务器的平均响应时间",
|
||||
"response_time": "响应时间",
|
||||
"processing_time": "处理时间",
|
||||
"average_processing_time_hint": "处理 DNS 请求的平均时间(毫秒)",
|
||||
"block_domain_use_filters_and_hosts": "使用过滤器和 Hosts 文件以拦截指定域名",
|
||||
"filters_block_toggle_hint": "你可以在 <a>过滤器</a> 设置中添加过滤规则。",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "为 EDNS 使用自定义 IP",
|
||||
"edns_use_custom_ip_desc": "允许为 EDNS 使用自定义 IP",
|
||||
"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": "拦截 A 记录请求返回的 IP 地址",
|
||||
"blocking_ipv6_desc": "拦截 AAAA 记录请求返回的 IP 地址",
|
||||
"blocking_mode_default": "默认:被 Adblock 规则拦截时反应为零 IP 地址(A记录:0.0.0.0;AAAA记录:::);被 /etc/hosts 规则拦截时反应为规则中指定 IP 地址",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"client_settings": "用戶端設定",
|
||||
"example_upstream_reserved": "<0>供特定的網域</0>之上游;",
|
||||
"example_multiple_upstreams_reserved": "<0>特定網域</0>的多個上游伺服器;",
|
||||
"example_upstream_comment": "註解。",
|
||||
"upstream_parallel": "透過同時地查詢所有上游的伺服器,使用並行的查詢以加速解析。",
|
||||
"parallel_requests": "並行的請求",
|
||||
@@ -9,9 +8,9 @@
|
||||
"load_balancing_desc": "每次查詢一個上游伺服器。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 伺服器",
|
||||
"fallback_dns_title": "備援 DNS 伺服器",
|
||||
"fallback_dns_desc": "當上游 DNS 伺服器未回應時使用的備援 DNS 伺服器清單。語法與上面的主要上游欄位相同。",
|
||||
"fallback_dns_placeholder": "每行輸入一個備援 DNS 伺服器",
|
||||
"local_ptr_title": "私人反向的 DNS 伺服器",
|
||||
"local_ptr_desc": "AdGuard Home 用於區域指標(PTR)查詢之 DNS 伺服器。這些伺服器被用於解析有關在私人 IP 範圍的位址之區域指標查詢,例如,\"192.168.12.34\",使用反向的 DNS。如果未被設定,AdGuard Home 使用您的作業系統之預設 DNS 解析器的位址。",
|
||||
"local_ptr_default_resolver": "預設下,AdGuard Home 使用以下反向的 DNS 解析器:{{ip}}。",
|
||||
@@ -132,7 +131,7 @@
|
||||
"top_clients": "熱門用戶端",
|
||||
"no_clients_found": "無已發現之用戶端",
|
||||
"general_statistics": "一般的統計資料",
|
||||
"top_upstreams": "熱門上游",
|
||||
"top_upstreams": "經常請求的上游伺服器",
|
||||
"no_upstreams_data_found": "找不到上游伺服器資料",
|
||||
"number_of_dns_query_days": "在最近的 {{count}} 日內已處理的 DNS 查詢之數量",
|
||||
"number_of_dns_query_days_plural": "在最近的 {{count}} 日內已處理的 DNS 查詢之數量",
|
||||
@@ -144,8 +143,7 @@
|
||||
"enforced_save_search": "已強制執行的安全搜尋",
|
||||
"number_of_dns_query_to_safe_search": "安全搜尋已被強制執行之屬於搜尋引擎的 DNS 請求之數量",
|
||||
"average_processing_time": "平均的處理時間",
|
||||
"average_upstream_response_time": "平均的上游回應時間",
|
||||
"response_time": "回應時間",
|
||||
"processing_time": "處理時間",
|
||||
"average_processing_time_hint": "在處理一項 DNS 請求時以毫秒(ms)計的平均時間",
|
||||
"block_domain_use_filters_and_hosts": "透過過濾器和主機檔案封鎖網域",
|
||||
"filters_block_toggle_hint": "您可在<a>過濾器</a>設定中設置封鎖規則。",
|
||||
@@ -290,7 +288,7 @@
|
||||
"blocking_ipv4": "封鎖 IPv4",
|
||||
"blocking_ipv6": "封鎖 IPv6",
|
||||
"blocked_response_ttl": "已封鎖的回應之存活時間(TTL)",
|
||||
"blocked_response_ttl_desc": "對用戶端應快取受過濾的回應,指定多少秒數",
|
||||
"blocked_response_ttl_desc": "指定客戶端應將過濾後的回應存入快取的秒數",
|
||||
"form_enter_blocked_response_ttl": "請輸入已封鎖回應的存活時間(秒)",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
@@ -310,16 +308,6 @@
|
||||
"edns_use_custom_ip": "為 EDNS 使用自訂的 IP",
|
||||
"edns_use_custom_ip_desc": "允許為 EDNS 使用自訂的 IP",
|
||||
"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": "要被返回給已封鎖的 A 請求之 IP 位址",
|
||||
"blocking_ipv6_desc": "要被返回給已封鎖的 AAAA 請求之 IP 位址",
|
||||
"blocking_mode_default": "預設:當被 AdBlock 樣式的規則封鎖時,以零值 IP 位址(0.0.0.0 供 A;:: 供 AAAA)回覆;當被 /etc/hosts 樣式的規則封鎖時,以在該規則中之已明確指定的 IP 位址回覆",
|
||||
|
||||
@@ -62,10 +62,6 @@ export const setDnsConfig = (config) => async (dispatch) => {
|
||||
data.upstream_dns = splitByNewLine(config.upstream_dns);
|
||||
hasDnsSettings = true;
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(data, 'ratelimit_whitelist')) {
|
||||
data.ratelimit_whitelist = splitByNewLine(config.ratelimit_whitelist);
|
||||
hasDnsSettings = true;
|
||||
}
|
||||
|
||||
await apiClient.setDnsConfig(data);
|
||||
|
||||
|
||||
@@ -338,40 +338,6 @@ export const getDnsStatus = () => async (dispatch) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const timerStatusRequest = createAction('TIMER_STATUS_REQUEST');
|
||||
export const timerStatusFailure = createAction('TIMER_STATUS_FAILURE');
|
||||
export const timerStatusSuccess = createAction('TIMER_STATUS_SUCCESS');
|
||||
|
||||
export const getTimerStatus = () => async (dispatch) => {
|
||||
dispatch(timerStatusRequest());
|
||||
|
||||
const handleRequestError = () => {
|
||||
dispatch(addErrorToast({ error: 'dns_status_error' }));
|
||||
dispatch(dnsStatusFailure());
|
||||
window.location.reload(true);
|
||||
};
|
||||
|
||||
const handleRequestSuccess = (response) => {
|
||||
const dnsStatus = response.data;
|
||||
if (dnsStatus.protection_disabled_duration === 0) {
|
||||
dnsStatus.protection_disabled_duration = null;
|
||||
}
|
||||
const { running } = dnsStatus;
|
||||
const runningStatus = dnsStatus && running;
|
||||
if (runningStatus === true) {
|
||||
dispatch(timerStatusSuccess(dnsStatus));
|
||||
} else {
|
||||
dispatch(setDnsRunningStatus(running));
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
checkStatus(handleRequestSuccess, handleRequestError);
|
||||
} catch (error) {
|
||||
handleRequestError();
|
||||
}
|
||||
};
|
||||
|
||||
export const testUpstreamRequest = createAction('TEST_UPSTREAM_REQUEST');
|
||||
export const testUpstreamFailure = createAction('TEST_UPSTREAM_FAILURE');
|
||||
export const testUpstreamSuccess = createAction('TEST_UPSTREAM_SUCCESS');
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
} from '../../helpers/constants';
|
||||
import { getLogsUrlParams, setHtmlLangAttr, setUITheme } from '../../helpers/helpers';
|
||||
import Header from '../Header';
|
||||
import { changeLanguage, getDnsStatus, getTimerStatus } from '../../actions';
|
||||
import { changeLanguage, getDnsStatus } from '../../actions';
|
||||
|
||||
import Dashboard from '../../containers/Dashboard';
|
||||
import SetupGuide from '../../containers/SetupGuide';
|
||||
@@ -126,18 +126,6 @@ const App = () => {
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(getDnsStatus());
|
||||
|
||||
const handleVisibilityChange = () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
dispatch(getTimerStatus());
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const setLanguage = () => {
|
||||
|
||||
@@ -38,7 +38,7 @@ const UpstreamAvgTime = ({
|
||||
subtitle,
|
||||
}) => (
|
||||
<Card
|
||||
title={t('average_upstream_response_time')}
|
||||
title={t('average_processing_time')}
|
||||
subtitle={subtitle}
|
||||
bodyType="card-table"
|
||||
refresh={refreshButton}
|
||||
@@ -55,7 +55,7 @@ const UpstreamAvgTime = ({
|
||||
Cell: DomainCell,
|
||||
},
|
||||
{
|
||||
Header: <Trans>response_time</Trans>,
|
||||
Header: <Trans>processing_time</Trans>,
|
||||
accessor: 'count',
|
||||
maxWidth: 190,
|
||||
Cell: TimeCell,
|
||||
|
||||
@@ -81,10 +81,6 @@ export const Modal = ({
|
||||
};
|
||||
});
|
||||
|
||||
if (timezone !== intialTimezone) {
|
||||
newSchedule.time_zone = timezone;
|
||||
}
|
||||
|
||||
onSubmit(newSchedule);
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class Leases extends Component {
|
||||
<div className="logs__row logs__row--center">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-icon--green btn-outline-success btn-sm"
|
||||
className="btn btn-icon btn-icon--green btn-outline-secondary btn-sm"
|
||||
title={t('make_static')}
|
||||
onClick={this.convertToStatic(row)}
|
||||
disabled={disabledLeasesButton}
|
||||
|
||||
@@ -6,7 +6,6 @@ import { Trans, useTranslation } from 'react-i18next';
|
||||
import {
|
||||
renderInputField,
|
||||
renderRadioField,
|
||||
renderTextareaField,
|
||||
CheckboxField,
|
||||
toNumber,
|
||||
} from '../../../../helpers/form';
|
||||
@@ -15,10 +14,7 @@ import {
|
||||
validateIpv6,
|
||||
validateRequiredValue,
|
||||
validateIp,
|
||||
validateIPv4Subnet,
|
||||
validateIPv6Subnet,
|
||||
} from '../../../../helpers/validators';
|
||||
import { removeEmptyLines } from '../../../../helpers/helpers';
|
||||
import { BLOCKING_MODES, FORM_NAME, UINT32_RANGE } from '../../../../helpers/constants';
|
||||
|
||||
const checkboxes = [
|
||||
@@ -94,69 +90,6 @@ const Form = ({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-7">
|
||||
<div className="form__group form__group--settings">
|
||||
<label htmlFor="ratelimit_subnet_len_ipv4"
|
||||
className="form__label form__label--with-desc">
|
||||
<Trans>rate_limit_subnet_len_ipv4</Trans>
|
||||
</label>
|
||||
<div className="form__desc form__desc--top">
|
||||
<Trans>rate_limit_subnet_len_ipv4_desc</Trans>
|
||||
</div>
|
||||
<Field
|
||||
name="ratelimit_subnet_len_ipv4"
|
||||
type="number"
|
||||
component={renderInputField}
|
||||
className="form-control"
|
||||
placeholder={t('form_enter_rate_limit_subnet_len')}
|
||||
normalize={toNumber}
|
||||
validate={[validateRequiredValue, validateIPv4Subnet]}
|
||||
min={0}
|
||||
max={32}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-7">
|
||||
<div className="form__group form__group--settings">
|
||||
<label htmlFor="ratelimit_subnet_len_ipv6"
|
||||
className="form__label form__label--with-desc">
|
||||
<Trans>rate_limit_subnet_len_ipv6</Trans>
|
||||
</label>
|
||||
<div className="form__desc form__desc--top">
|
||||
<Trans>rate_limit_subnet_len_ipv6_desc</Trans>
|
||||
</div>
|
||||
<Field
|
||||
name="ratelimit_subnet_len_ipv6"
|
||||
type="number"
|
||||
component={renderInputField}
|
||||
className="form-control"
|
||||
placeholder={t('form_enter_rate_limit_subnet_len')}
|
||||
normalize={toNumber}
|
||||
validate={[validateRequiredValue, validateIPv6Subnet]}
|
||||
min={0}
|
||||
max={128}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-7">
|
||||
<div className="form__group form__group--settings">
|
||||
<label htmlFor="ratelimit_whitelist"
|
||||
className="form__label form__label--with-desc">
|
||||
<Trans>rate_limit_whitelist</Trans>
|
||||
</label>
|
||||
<div className="form__desc form__desc--top">
|
||||
<Trans>rate_limit_whitelist_desc</Trans>
|
||||
</div>
|
||||
<Field
|
||||
name="ratelimit_whitelist"
|
||||
component={renderTextareaField}
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder={t('rate_limit_whitelist_placeholder')}
|
||||
normalizeOnBlur={removeEmptyLines}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<div className="form__group form__group--settings">
|
||||
<Field
|
||||
|
||||
@@ -11,9 +11,6 @@ const Config = () => {
|
||||
const {
|
||||
blocking_mode,
|
||||
ratelimit,
|
||||
ratelimit_subnet_len_ipv4,
|
||||
ratelimit_subnet_len_ipv6,
|
||||
ratelimit_whitelist,
|
||||
blocking_ipv4,
|
||||
blocking_ipv6,
|
||||
blocked_response_ttl,
|
||||
@@ -39,9 +36,6 @@ const Config = () => {
|
||||
<Form
|
||||
initialValues={{
|
||||
ratelimit,
|
||||
ratelimit_subnet_len_ipv4,
|
||||
ratelimit_subnet_len_ipv6,
|
||||
ratelimit_whitelist,
|
||||
blocking_mode,
|
||||
blocking_ipv4,
|
||||
blocking_ipv6,
|
||||
|
||||
@@ -26,10 +26,6 @@ export const R_WIN_ABSOLUTE_PATH = /^([a-zA-Z]:)?(\\|\/)(?:[^\\/:*?"<>|\x00]+\\)
|
||||
|
||||
export const R_CLIENT_ID = /^[a-z0-9-]{1,63}$/;
|
||||
|
||||
export const R_IPV4_SUBNET = /^([0-9]|[1-2][0-9]|3[0-2])?$/;
|
||||
|
||||
export const R_IPV6_SUBNET = /^([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])?$/;
|
||||
|
||||
export const MIN_PASSWORD_LENGTH = 8;
|
||||
export const MAX_PASSWORD_LENGTH = 72;
|
||||
|
||||
|
||||
@@ -190,12 +190,6 @@ export default {
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists#piracy",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_46.txt"
|
||||
},
|
||||
"hagezi_encrypted_dns_vpn_tor_proxy_bypass": {
|
||||
"name": "HaGeZi's Encrypted DNS/VPN/TOR/Proxy Bypass",
|
||||
"categoryId": "security",
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists#bypass",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_52.txt"
|
||||
},
|
||||
"hagezi_gambling_blocklist": {
|
||||
"name": "HaGeZi's Gambling Blocklist",
|
||||
"categoryId": "other",
|
||||
@@ -208,30 +202,12 @@ export default {
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_34.txt"
|
||||
},
|
||||
"hagezi_pro": {
|
||||
"name": "HaGeZi's Pro Blocklist",
|
||||
"categoryId": "general",
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_48.txt"
|
||||
},
|
||||
"hagezi_pro++": {
|
||||
"name": "HaGeZi's Pro++ Blocklist",
|
||||
"categoryId": "general",
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_51.txt"
|
||||
},
|
||||
"hagezi_threat_intelligence_feeds": {
|
||||
"name": "HaGeZi's Threat Intelligence Feeds",
|
||||
"categoryId": "security",
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_44.txt"
|
||||
},
|
||||
"hagezi_ultimate": {
|
||||
"name": "HaGeZi's Ultimate Blocklist",
|
||||
"categoryId": "general",
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_49.txt"
|
||||
},
|
||||
"no_google": {
|
||||
"name": "No Google",
|
||||
"categoryId": "other",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"timeUpdated": "2023-11-10T12:55:56.663Z",
|
||||
"timeUpdated": "2023-10-15T12:13:01.838Z",
|
||||
"categories": {
|
||||
"0": "audio_video_player",
|
||||
"1": "comments",
|
||||
@@ -681,9 +681,8 @@
|
||||
"adcolony": {
|
||||
"name": "AdColony",
|
||||
"categoryId": 4,
|
||||
"url": "https://www.adcolony.com/history-of-adcolony/",
|
||||
"companyId": "digital_turbine",
|
||||
"source": "AdGuard"
|
||||
"url": "thttp://www.admarvel.com/",
|
||||
"companyId": "adcolony"
|
||||
},
|
||||
"adconion": {
|
||||
"name": "Adconion",
|
||||
@@ -1295,13 +1294,6 @@
|
||||
"url": "http://www.demdex.com/",
|
||||
"companyId": "adobe"
|
||||
},
|
||||
"adobe_developer": {
|
||||
"name": "Adobe Developer",
|
||||
"categoryId": 8,
|
||||
"url": "https://developer.adobe.com/",
|
||||
"companyId": "adobe",
|
||||
"source": "AdGuard"
|
||||
},
|
||||
"adobe_dynamic_media": {
|
||||
"name": "Adobe Dynamic Media",
|
||||
"categoryId": 4,
|
||||
@@ -1317,9 +1309,8 @@
|
||||
"adobe_experience_cloud": {
|
||||
"name": "Adobe Experience Cloud",
|
||||
"categoryId": 6,
|
||||
"url": "https://business.adobe.com/",
|
||||
"companyId": "adobe",
|
||||
"source": "AdGuard"
|
||||
"url": "https://www.adobe.com/experience-cloud.html",
|
||||
"companyId": "adobe"
|
||||
},
|
||||
"adobe_login": {
|
||||
"name": "Adobe Login",
|
||||
@@ -4362,13 +4353,6 @@
|
||||
"url": "http://chartbeat.com/",
|
||||
"companyId": "chartbeat"
|
||||
},
|
||||
"chartboost": {
|
||||
"name": "Chartboost",
|
||||
"categoryId": 4,
|
||||
"url": "http://chartboost.com/",
|
||||
"companyId": "take-two",
|
||||
"source": "AdGuard"
|
||||
},
|
||||
"chaser": {
|
||||
"name": "Chaser",
|
||||
"categoryId": 2,
|
||||
@@ -7346,7 +7330,7 @@
|
||||
"name": "Flurry",
|
||||
"categoryId": 101,
|
||||
"url": "http://www.flurry.com/",
|
||||
"companyId": "apollo_global_management",
|
||||
"companyId": "verizon",
|
||||
"source": "AdGuard"
|
||||
},
|
||||
"flxone": {
|
||||
@@ -12402,13 +12386,6 @@
|
||||
"url": "http://www.nimblecommerce.com/",
|
||||
"companyId": "nimblecommerce"
|
||||
},
|
||||
"nine_direct_digital": {
|
||||
"name": "Nine Digital Direct",
|
||||
"categoryId": 4,
|
||||
"url": "https://ninedigitaldirect.com.au/",
|
||||
"companyId": "nine_entertainment",
|
||||
"source": "AdGuard"
|
||||
},
|
||||
"ninja_access_analysis": {
|
||||
"name": "Ninja Access Analysis",
|
||||
"categoryId": 6,
|
||||
@@ -19569,9 +19546,8 @@
|
||||
"yahoo": {
|
||||
"name": "Yahoo!",
|
||||
"categoryId": 6,
|
||||
"url": "https://yahoo.com/",
|
||||
"companyId": "apollo_global_management",
|
||||
"source": "AdGuard"
|
||||
"url": "https://yahoo.com",
|
||||
"companyId": "verizon"
|
||||
},
|
||||
"yahoo_ad_exchange": {
|
||||
"name": "Yahoo! Ad Exchange",
|
||||
@@ -19585,13 +19561,6 @@
|
||||
"url": "https://developer.yahoo.com/analytics/",
|
||||
"companyId": "verizon"
|
||||
},
|
||||
"yahoo_advertising": {
|
||||
"name": "Yahoo! Advertising",
|
||||
"categoryId": 4,
|
||||
"url": "https://www.advertising.yahooinc.com/",
|
||||
"companyId": "apollo_global_management",
|
||||
"source": "AdGuard"
|
||||
},
|
||||
"yahoo_analytics": {
|
||||
"name": "Yahoo! Analytics",
|
||||
"categoryId": 6,
|
||||
@@ -19622,13 +19591,6 @@
|
||||
"url": "http://searchmarketing.yahoo.com",
|
||||
"companyId": "verizon"
|
||||
},
|
||||
"yahoo_search": {
|
||||
"name": "Yahoo! Search",
|
||||
"categoryId": 4,
|
||||
"url": "https://search.yahooinc.com/",
|
||||
"companyId": "apollo_global_management",
|
||||
"source": "AdGuard"
|
||||
},
|
||||
"yahoo_small_business": {
|
||||
"name": "Yahoo! Small Business",
|
||||
"categoryId": 4,
|
||||
@@ -20266,7 +20228,6 @@
|
||||
"ad-cloud.jp": "adcloud",
|
||||
"admarvel.s3.amazonaws.com": "adcolony",
|
||||
"ads.admarvel.com": "adcolony",
|
||||
"adcolony.com": "adcolony",
|
||||
"adrdgt.com": "adconion",
|
||||
"amgdgt.com": "adconion",
|
||||
"adcrowd.com": "adcrowd",
|
||||
@@ -20421,7 +20382,6 @@
|
||||
"demdex.net": "adobe_audience_manager",
|
||||
"everestjs.net": "adobe_audience_manager",
|
||||
"everesttech.net": "adobe_audience_manager",
|
||||
"adobe.io": "adobe_developer",
|
||||
"scene7.com": "adobe_dynamic_media",
|
||||
"adobedtm.com": "adobe_dynamic_tag_management",
|
||||
"2o7.net": "adobe_experience_cloud",
|
||||
@@ -20694,10 +20654,8 @@
|
||||
"a2z.com": "amazon",
|
||||
"aamazoncognito.com": "amazon",
|
||||
"amazon-corp.com": "amazon",
|
||||
"amazon-dss.com": "amazon",
|
||||
"amazon.com.au": "amazon",
|
||||
"amazon.com.mx": "amazon",
|
||||
"amazon.dev": "amazon",
|
||||
"amazon.in": "amazon",
|
||||
"amazon.nl": "amazon",
|
||||
"amazon.sa": "amazon",
|
||||
@@ -20705,7 +20663,6 @@
|
||||
"amazonbrowserapp.es": "amazon",
|
||||
"amazoncrl.com": "amazon",
|
||||
"firetvcaptiveportal.com": "amazon",
|
||||
"ntp-fireos.com": "amazon",
|
||||
"amazon-adsystem.com": "amazon_adsystem",
|
||||
"serving-sys.com": "amazon_adsystem",
|
||||
"sizmek.com": "amazon_adsystem",
|
||||
@@ -20721,16 +20678,12 @@
|
||||
"amazontrust.com": "amazon_cdn",
|
||||
"associates-amazon.com": "amazon_cdn",
|
||||
"cloudfront.net": "amazon_cloudfront",
|
||||
"ota-cloudfront.net": "amazon_cloudfront",
|
||||
"axx-eu.amazon-adsystem.com": "amazon_mobile_ads",
|
||||
"amazonpay.com": "amazon_payments",
|
||||
"payments-amazon.com": "amazon_payments",
|
||||
"amazonpay.in": "amazon_payments",
|
||||
"aiv-cdn.net": "amazon_video",
|
||||
"aiv-delivery.net": "amazon_video",
|
||||
"amazonvideo.com": "amazon_video",
|
||||
"pv-cdn.net": "amazon_video",
|
||||
"primevideo.com": "amazon_video",
|
||||
"amazonaws.com": "amazon_web_services",
|
||||
"amazonwebservices.com": "amazon_web_services",
|
||||
"awsstatic.com": "amazon_web_services",
|
||||
@@ -20877,8 +20830,6 @@
|
||||
"ad.globe7.com": "axill",
|
||||
"azadify.com": "azadify",
|
||||
"azure.com": "azure",
|
||||
"azure.net": "azure",
|
||||
"azurefd.net": "azure",
|
||||
"trafficmanager.net": "azure",
|
||||
"blob.core.windows.net": "azure_blob_storage",
|
||||
"azureedge.net": "azureedge.net",
|
||||
@@ -21169,7 +21120,6 @@
|
||||
"chaordicsystems.com": "chaordic",
|
||||
"chartbeat.com": "chartbeat",
|
||||
"chartbeat.net": "chartbeat",
|
||||
"chartboost.com": "chartboost",
|
||||
"chaser.ru": "chaser",
|
||||
"cloud.chatbeacon.io": "chat_beacon",
|
||||
"chatango.com": "chatango",
|
||||
@@ -21979,9 +21929,7 @@
|
||||
"githubassets.com": "github",
|
||||
"githubusercontent.com": "github",
|
||||
"ghcr.io": "github",
|
||||
"github.blog": "github",
|
||||
"github.dev": "github",
|
||||
"octocaptcha.com": "github",
|
||||
"githubapp.com": "github_apps",
|
||||
"github.io": "github_pages",
|
||||
"aff3.gittigidiyor.com": "gittigidiyor_affiliate_program",
|
||||
@@ -23140,13 +23088,7 @@
|
||||
"s-microsoft.com": "microsoft",
|
||||
"trouter.io": "microsoft",
|
||||
"windows.net": "microsoft",
|
||||
"bingapis.com": "microsoft",
|
||||
"msauth.net": "microsoft",
|
||||
"msftauth.net": "microsoft",
|
||||
"msftstatic.com": "microsoft",
|
||||
"msidentity.com": "microsoft",
|
||||
"nelreports.net": "microsoft",
|
||||
"windowscentral.com": "microsoft",
|
||||
"analytics.live.com": "microsoft_analytics",
|
||||
"a.clarity.ms": "microsoft_clarity",
|
||||
"b.clarity.ms": "microsoft_clarity",
|
||||
@@ -23231,7 +23173,6 @@
|
||||
"mrpdata.com": "mrpdata",
|
||||
"mrpdata.net": "mrpdata",
|
||||
"mrskincash.com": "mrskincash",
|
||||
"a-msedge.net": "msedge",
|
||||
"e-msedge.net": "msedge",
|
||||
"l-msedge.net": "msedge",
|
||||
"s-msedge.net": "msedge",
|
||||
@@ -23353,7 +23294,6 @@
|
||||
"ads.ngageinc.com": "ngage_inc.",
|
||||
"nice264.com": "nice264.com",
|
||||
"nimblecommerce.com": "nimblecommerce",
|
||||
"nineanalytics.io": "nine_direct_digital",
|
||||
"cho-chin.com": "ninja_access_analysis",
|
||||
"donburako.com": "ninja_access_analysis",
|
||||
"hishaku.com": "ninja_access_analysis",
|
||||
@@ -25007,15 +24947,10 @@
|
||||
"yahoo.com": "yahoo",
|
||||
"yahooapis.com": "yahoo",
|
||||
"yimg.com": "yahoo",
|
||||
"oath.cloud": "yahoo",
|
||||
"yahoo.net": "yahoo",
|
||||
"yahooinc.com": "yahoo",
|
||||
"yahoodns.net": "yahoo",
|
||||
"ads.yahoo.com": "yahoo_ad_exchange",
|
||||
"yads.yahoo.com": "yahoo_ad_exchange",
|
||||
"yieldmanager.com": "yahoo_ad_exchange",
|
||||
"pr-bh.ybp.yahoo.com": "yahoo_ad_manager",
|
||||
"ads.yahoo.com": "yahoo_advertising",
|
||||
"adtech.yahooinc.com": "yahoo_advertising",
|
||||
"analytics.yahoo.com": "yahoo_analytics",
|
||||
"np.lexity.com": "yahoo_commerce_central",
|
||||
"storage-yahoo.jp": "yahoo_japan_retargeting",
|
||||
@@ -25025,7 +24960,6 @@
|
||||
"yjtag.jp": "yahoo_japan_retargeting",
|
||||
"ov.yahoo.co.jp": "yahoo_overture",
|
||||
"overture.com": "yahoo_overture",
|
||||
"search.yahooinc.com": "yahoo_search",
|
||||
"luminate.com": "yahoo_small_business",
|
||||
"pixazza.com": "yahoo_small_business",
|
||||
"awaps.yandex.ru": "yandex",
|
||||
|
||||
@@ -15,8 +15,6 @@ import {
|
||||
R_DOMAIN,
|
||||
MAX_PASSWORD_LENGTH,
|
||||
MIN_PASSWORD_LENGTH,
|
||||
R_IPV4_SUBNET,
|
||||
R_IPV6_SUBNET,
|
||||
} from './constants';
|
||||
import { ip4ToInt, isValidAbsolutePath } from './form';
|
||||
import { isIpInCidr, parseSubnetMask } from './helpers';
|
||||
@@ -367,25 +365,3 @@ export const validateIpGateway = (value, allValues) => {
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param value {string}
|
||||
* @returns {Function}
|
||||
*/
|
||||
export const validateIPv4Subnet = (value) => {
|
||||
if (!R_IPV4_SUBNET.test(value)) {
|
||||
return i18next.t('rate_limit_subnet_len_ipv4_error');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param value {string}
|
||||
* @returns {Function}
|
||||
*/
|
||||
export const validateIPv6Subnet = (value) => {
|
||||
if (!R_IPV6_SUBNET.test(value)) {
|
||||
return i18next.t('rate_limit_subnet_len_ipv6_error');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
@@ -44,19 +44,6 @@ const dashboard = handleActions(
|
||||
|
||||
return newState;
|
||||
},
|
||||
[actions.timerStatusSuccess]: (state, { payload }) => {
|
||||
const {
|
||||
protection_enabled: protectionEnabled,
|
||||
protection_disabled_duration: protectionDisabledDuration,
|
||||
} = payload;
|
||||
const newState = {
|
||||
...state,
|
||||
protectionEnabled,
|
||||
protectionDisabledDuration,
|
||||
};
|
||||
|
||||
return newState;
|
||||
},
|
||||
|
||||
[actions.getVersionRequest]: (state) => ({
|
||||
...state,
|
||||
|
||||
@@ -128,7 +128,8 @@ const dhcp = handleActions(
|
||||
const newState = {
|
||||
...state,
|
||||
isModalOpen: !state.isModalOpen,
|
||||
leaseModalConfig: payload,
|
||||
modalType: payload?.type || '',
|
||||
leaseModalConfig: payload?.config,
|
||||
};
|
||||
return newState;
|
||||
},
|
||||
|
||||
@@ -18,7 +18,6 @@ const dnsConfig = handleActions(
|
||||
fallback_dns,
|
||||
bootstrap_dns,
|
||||
local_ptr_upstreams,
|
||||
ratelimit_whitelist,
|
||||
...values
|
||||
} = payload;
|
||||
|
||||
@@ -31,7 +30,6 @@ const dnsConfig = handleActions(
|
||||
fallback_dns: (fallback_dns && fallback_dns.join('\n')) || '',
|
||||
bootstrap_dns: (bootstrap_dns && bootstrap_dns.join('\n')) || '',
|
||||
local_ptr_upstreams: (local_ptr_upstreams && local_ptr_upstreams.join('\n')) || '',
|
||||
ratelimit_whitelist: (ratelimit_whitelist && ratelimit_whitelist.join('\n')) || '',
|
||||
processingGetConfig: false,
|
||||
};
|
||||
},
|
||||
|
||||
35
go.mod
35
go.mod
@@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/dnsproxy v0.59.0
|
||||
github.com/AdguardTeam/dnsproxy v0.56.3
|
||||
github.com/AdguardTeam/golibs v0.17.2
|
||||
github.com/AdguardTeam/urlfilter v0.17.3
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
@@ -11,12 +11,12 @@ require (
|
||||
github.com/bluele/gcache v0.0.2
|
||||
github.com/digineo/go-ipset/v2 v2.2.1
|
||||
github.com/dimfeld/httptreemux/v5 v5.5.0
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/go-ping/ping v1.1.0
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/google/renameio/v2 v2.0.0
|
||||
github.com/google/uuid v1.4.0
|
||||
github.com/google/uuid v1.3.1
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c
|
||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86
|
||||
github.com/kardianos/service v1.2.2
|
||||
@@ -27,14 +27,14 @@ require (
|
||||
// own code for that. Perhaps, use gopacket.
|
||||
github.com/mdlayher/raw v0.1.0
|
||||
github.com/miekg/dns v1.1.56
|
||||
github.com/quic-go/quic-go v0.40.0
|
||||
github.com/quic-go/quic-go v0.39.2
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/ti-mo/netfilter v0.5.1
|
||||
go.etcd.io/bbolt v1.3.8
|
||||
golang.org/x/crypto v0.15.0
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
||||
golang.org/x/net v0.18.0
|
||||
golang.org/x/sys v0.14.0
|
||||
go.etcd.io/bbolt v1.3.7
|
||||
golang.org/x/crypto v0.14.0
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
|
||||
golang.org/x/net v0.17.0
|
||||
golang.org/x/sys v0.13.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
howett.net/plist v1.0.0
|
||||
@@ -47,20 +47,19 @@ require (
|
||||
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect
|
||||
// TODO(a.garipov): Upgrade to v0.5.0 once we switch to Go 1.21+.
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.13.1 // indirect
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
|
||||
github.com/mdlayher/socket v0.5.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.13.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.18 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4 // indirect
|
||||
github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect
|
||||
go.uber.org/mock v0.3.0 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/sync v0.5.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.15.0 // indirect
|
||||
golang.org/x/mod v0.13.0 // indirect
|
||||
golang.org/x/sync v0.4.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/tools v0.14.0 // indirect
|
||||
)
|
||||
|
||||
73
go.sum
73
go.sum
@@ -1,5 +1,5 @@
|
||||
github.com/AdguardTeam/dnsproxy v0.59.0 h1:J0Iw4+GZ7U44scgkrNCM5W2G+tNS0r9nfQOuSLBqapE=
|
||||
github.com/AdguardTeam/dnsproxy v0.59.0/go.mod h1:ZvkbM71HwpilgkCnTubDiR4Ba6x5Qvnhy2iasMWaTDM=
|
||||
github.com/AdguardTeam/dnsproxy v0.56.3 h1:WP1FooLfZQPHEH2SuwMtJsOurDt32rubGx0OddcsKT0=
|
||||
github.com/AdguardTeam/dnsproxy v0.56.3/go.mod h1:ZvkbM71HwpilgkCnTubDiR4Ba6x5Qvnhy2iasMWaTDM=
|
||||
github.com/AdguardTeam/golibs v0.17.2 h1:vg6wHMjUKscnyPGRvxS5kAt7Uw4YxcJiITZliZ476W8=
|
||||
github.com/AdguardTeam/golibs v0.17.2/go.mod h1:DKhCIXHcUYtBhU8ibTLKh1paUL96n5zhQBlx763sj+U=
|
||||
github.com/AdguardTeam/urlfilter v0.17.3 h1:fg/ObbnO0Cv6aw0tW6N/ETDMhhNvmcUUOZ7HlmKC3rw=
|
||||
@@ -25,9 +25,9 @@ github.com/digineo/go-ipset/v2 v2.2.1 h1:k6skY+0fMqeUjjeWO/m5OuWPSZUAn7AucHMnQ1M
|
||||
github.com/digineo/go-ipset/v2 v2.2.1/go.mod h1:wBsNzJlZlABHUITkesrggFnZQtgW5wkqw1uo8Qxe0VU=
|
||||
github.com/dimfeld/httptreemux/v5 v5.5.0 h1:p8jkiMrCuZ0CmhwYLcbNbl7DDo21fozhKHQ2PccwOFQ=
|
||||
github.com/dimfeld/httptreemux/v5 v5.5.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
|
||||
github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
|
||||
@@ -41,13 +41,13 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk=
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ=
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
|
||||
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c h1:PgxFEySCI41sH0mB7/2XswdXbUykQsRUGod8Rn+NubM=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI=
|
||||
@@ -71,14 +71,14 @@ github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU
|
||||
github.com/mdlayher/raw v0.1.0 h1:K4PFMVy+AFsp0Zdlrts7yNhxc/uXoPVHi9RzRvtZF2Y=
|
||||
github.com/mdlayher/raw v0.1.0/go.mod h1:yXnxvs6c0XoF/aK52/H5PjsVHmWBCFfZUfoh/Y5s9Sg=
|
||||
github.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI=
|
||||
github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
|
||||
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
|
||||
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU=
|
||||
github.com/onsi/ginkgo/v2 v2.13.1/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
|
||||
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
|
||||
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
|
||||
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
@@ -92,10 +92,10 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.40.0 h1:GYd1iznlKm7dpHD7pOVpUvItgMPo/jrMgDWZhMCecqw=
|
||||
github.com/quic-go/quic-go v0.40.0/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.39.2 h1:hmwAf8zAHlvan0Y5PXxeeBFZEW17IW99sXLry8I2kjk=
|
||||
github.com/quic-go/quic-go v0.39.2/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
|
||||
github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -112,32 +112,32 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm
|
||||
github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 h1:YcojQL98T/OO+rybuzn2+5KrD5dBwXIvYBvQ2cD3Avg=
|
||||
github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
|
||||
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
|
||||
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
|
||||
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
|
||||
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
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.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||
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.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
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.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -148,18 +148,19 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
|
||||
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
|
||||
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
package aghnet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/netip"
|
||||
"path"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/hostsfile"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
@@ -144,9 +141,13 @@ func NewHostsContainer(
|
||||
func (hc *HostsContainer) Close() (err error) {
|
||||
log.Debug("%s: closing", hostsContainerPrefix)
|
||||
|
||||
err = errors.Annotate(hc.watcher.Close(), "closing fs watcher: %w")
|
||||
err = hc.watcher.Close()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("closing fs watcher: %w", err)
|
||||
|
||||
// Go on and close the container either way.
|
||||
}
|
||||
|
||||
// Go on and close the container either way.
|
||||
close(hc.done)
|
||||
|
||||
return err
|
||||
@@ -318,39 +319,3 @@ func (hc *HostsContainer) refresh() (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ upstream.Resolver = (*HostsContainer)(nil)
|
||||
|
||||
// LookupNetIP implements the [upstream.Resolver] interface for *HostsContainer.
|
||||
func (hc *HostsContainer) LookupNetIP(
|
||||
ctx context.Context,
|
||||
network string,
|
||||
hostname string,
|
||||
) (addrs []netip.Addr, err error) {
|
||||
// TODO(e.burkov): Think of extracting this logic to a golibs function if
|
||||
// needed anywhere else.
|
||||
var isDesiredProto func(ip netip.Addr) (ok bool)
|
||||
switch network {
|
||||
case "ip4":
|
||||
isDesiredProto = (netip.Addr).Is4
|
||||
case "ip6":
|
||||
isDesiredProto = (netip.Addr).Is6
|
||||
case "ip":
|
||||
isDesiredProto = func(ip netip.Addr) (ok bool) { return true }
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported network: %q", network)
|
||||
}
|
||||
|
||||
idx := hc.current.Load()
|
||||
recs := idx.names[strings.ToLower(hostname)]
|
||||
|
||||
addrs = make([]netip.Addr, 0, len(recs))
|
||||
for _, rec := range recs {
|
||||
if isDesiredProto(rec.Addr) {
|
||||
addrs = append(addrs, rec.Addr)
|
||||
}
|
||||
}
|
||||
|
||||
return slices.Clip(addrs), nil
|
||||
}
|
||||
|
||||
@@ -10,11 +10,9 @@ import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
@@ -309,50 +307,6 @@ func ParseAddrPort(s string, defaultPort uint16) (ipp netip.AddrPort, err error)
|
||||
return ipp, nil
|
||||
}
|
||||
|
||||
// ParseSubnet parses s either as a CIDR prefix itself, or as an IP address,
|
||||
// returning the corresponding single-IP CIDR prefix.
|
||||
//
|
||||
// TODO(e.burkov): Taken from dnsproxy, move to golibs.
|
||||
func ParseSubnet(s string) (p netip.Prefix, err error) {
|
||||
if strings.Contains(s, "/") {
|
||||
p, err = netip.ParsePrefix(s)
|
||||
if err != nil {
|
||||
return netip.Prefix{}, err
|
||||
}
|
||||
} else {
|
||||
var ip netip.Addr
|
||||
ip, err = netip.ParseAddr(s)
|
||||
if err != nil {
|
||||
return netip.Prefix{}, err
|
||||
}
|
||||
|
||||
p = netip.PrefixFrom(ip, ip.BitLen())
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// ParseBootstraps returns the slice of upstream resolvers parsed from addrs.
|
||||
// It additionally returns the closers for each resolver, that should be closed
|
||||
// after use.
|
||||
func ParseBootstraps(
|
||||
addrs []string,
|
||||
opts *upstream.Options,
|
||||
) (boots []*upstream.UpstreamResolver, err error) {
|
||||
boots = make([]*upstream.UpstreamResolver, 0, len(boots))
|
||||
for i, b := range addrs {
|
||||
var r *upstream.UpstreamResolver
|
||||
r, err = upstream.NewUpstreamResolver(b, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("bootstrap at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
boots = append(boots, r)
|
||||
}
|
||||
|
||||
return boots, nil
|
||||
}
|
||||
|
||||
// BroadcastFromPref calculates the broadcast IP address for p.
|
||||
func BroadcastFromPref(p netip.Prefix) (bc netip.Addr) {
|
||||
bc = p.Addr().Unmap()
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/rdns"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/whois"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@@ -117,26 +116,6 @@ func (p *AddressUpdater) UpdateAddress(ip netip.Addr, host string, info *whois.I
|
||||
p.OnUpdateAddress(ip, host, info)
|
||||
}
|
||||
|
||||
// Package dnsforward
|
||||
|
||||
// ClientsContainer is a fake [dnsforward.ClientsContainer] implementation for
|
||||
// tests.
|
||||
type ClientsContainer struct {
|
||||
OnUpstreamConfigByID func(
|
||||
id string,
|
||||
boot upstream.Resolver,
|
||||
) (conf *proxy.CustomUpstreamConfig, err error)
|
||||
}
|
||||
|
||||
// UpstreamConfigByID implements the [dnsforward.ClientsContainer] interface
|
||||
// for *ClientsContainer.
|
||||
func (c *ClientsContainer) UpstreamConfigByID(
|
||||
id string,
|
||||
boot upstream.Resolver,
|
||||
) (conf *proxy.CustomUpstreamConfig, err error) {
|
||||
return c.OnUpstreamConfigByID(id, boot)
|
||||
}
|
||||
|
||||
// Package filtering
|
||||
|
||||
// Resolver is a fake [filtering.Resolver] implementation for tests.
|
||||
|
||||
@@ -2,7 +2,6 @@ package aghtest_test
|
||||
|
||||
import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||
)
|
||||
|
||||
@@ -10,6 +9,3 @@ import (
|
||||
|
||||
// type check
|
||||
var _ filtering.Resolver = (*aghtest.Resolver)(nil)
|
||||
|
||||
// type check
|
||||
var _ dnsforward.ClientsContainer = (*aghtest.ClientsContainer)(nil)
|
||||
|
||||
@@ -7,16 +7,11 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/confmigrate"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testutil.DiscardLogOutput(m)
|
||||
}
|
||||
|
||||
// testdata is a virtual filesystem containing test data.
|
||||
var testdata = os.DirFS("testdata")
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
)
|
||||
|
||||
@@ -50,16 +49,16 @@ type ServerConfig struct {
|
||||
// DHCPServer - DHCP server interface
|
||||
type DHCPServer interface {
|
||||
// ResetLeases resets leases.
|
||||
ResetLeases(leases []*dhcpsvc.Lease) (err error)
|
||||
ResetLeases(leases []*Lease) (err error)
|
||||
// GetLeases returns deep clones of the current leases.
|
||||
GetLeases(flags GetLeasesFlags) (leases []*dhcpsvc.Lease)
|
||||
GetLeases(flags GetLeasesFlags) (leases []*Lease)
|
||||
// AddStaticLease - add a static lease
|
||||
AddStaticLease(l *dhcpsvc.Lease) (err error)
|
||||
AddStaticLease(l *Lease) (err error)
|
||||
// RemoveStaticLease - remove a static lease
|
||||
RemoveStaticLease(l *dhcpsvc.Lease) (err error)
|
||||
RemoveStaticLease(l *Lease) (err error)
|
||||
|
||||
// UpdateStaticLease updates IP, hostname of the lease.
|
||||
UpdateStaticLease(l *dhcpsvc.Lease) (err error)
|
||||
UpdateStaticLease(l *Lease) (err error)
|
||||
|
||||
// FindMACbyIP returns a MAC address by the IP address of its lease, if
|
||||
// there is one.
|
||||
@@ -82,7 +81,7 @@ type DHCPServer interface {
|
||||
Start() (err error)
|
||||
// Stop - stop server
|
||||
Stop() (err error)
|
||||
getLeasesRef() []*dhcpsvc.Lease
|
||||
getLeasesRef() []*Lease
|
||||
}
|
||||
|
||||
// V4ServerConf - server configuration
|
||||
|
||||
@@ -5,13 +5,9 @@ package dhcpd
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/google/renameio/v2/maybe"
|
||||
@@ -32,60 +28,7 @@ type dataLeases struct {
|
||||
Version int `json:"version"`
|
||||
|
||||
// Leases is the list containing stored DHCP leases.
|
||||
Leases []*dbLease `json:"leases"`
|
||||
}
|
||||
|
||||
// dbLease is the structure of stored lease.
|
||||
type dbLease struct {
|
||||
Expiry string `json:"expires"`
|
||||
IP netip.Addr `json:"ip"`
|
||||
Hostname string `json:"hostname"`
|
||||
HWAddr string `json:"mac"`
|
||||
IsStatic bool `json:"static"`
|
||||
}
|
||||
|
||||
// fromLease converts *dhcpsvc.Lease to *dbLease.
|
||||
func fromLease(l *dhcpsvc.Lease) (dl *dbLease) {
|
||||
var expiryStr string
|
||||
if !l.IsStatic {
|
||||
// The front-end is waiting for RFC 3999 format of the time value. It
|
||||
// also shouldn't got an Expiry field for static leases.
|
||||
//
|
||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/2692.
|
||||
expiryStr = l.Expiry.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
return &dbLease{
|
||||
Expiry: expiryStr,
|
||||
Hostname: l.Hostname,
|
||||
HWAddr: l.HWAddr.String(),
|
||||
IP: l.IP,
|
||||
IsStatic: l.IsStatic,
|
||||
}
|
||||
}
|
||||
|
||||
// toLease converts *dbLease to *dhcpsvc.Lease.
|
||||
func (dl *dbLease) toLease() (l *dhcpsvc.Lease, err error) {
|
||||
mac, err := net.ParseMAC(dl.HWAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing hardware address: %w", err)
|
||||
}
|
||||
|
||||
expiry := time.Time{}
|
||||
if !dl.IsStatic {
|
||||
expiry, err = time.Parse(time.RFC3339, dl.Expiry)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing expiry time: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &dhcpsvc.Lease{
|
||||
Expiry: expiry,
|
||||
IP: dl.IP,
|
||||
Hostname: dl.Hostname,
|
||||
HWAddr: mac,
|
||||
IsStatic: dl.IsStatic,
|
||||
}, nil
|
||||
Leases []*Lease `json:"leases"`
|
||||
}
|
||||
|
||||
// dbLoad loads stored leases.
|
||||
@@ -106,22 +49,15 @@ func (s *server) dbLoad() (err error) {
|
||||
}
|
||||
|
||||
leases := dl.Leases
|
||||
leases4 := []*dhcpsvc.Lease{}
|
||||
leases6 := []*dhcpsvc.Lease{}
|
||||
|
||||
leases4 := []*Lease{}
|
||||
leases6 := []*Lease{}
|
||||
|
||||
for _, l := range leases {
|
||||
var lease *dhcpsvc.Lease
|
||||
lease, err = l.toLease()
|
||||
if err != nil {
|
||||
log.Info("dhcp: invalid lease: %s", err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if lease.IP.Is4() {
|
||||
leases4 = append(leases4, lease)
|
||||
if l.IP.Is4() {
|
||||
leases4 = append(leases4, l)
|
||||
} else {
|
||||
leases6 = append(leases6, lease)
|
||||
leases6 = append(leases6, l)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,12 +73,8 @@ func (s *server) dbLoad() (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
log.Info(
|
||||
"dhcp: loaded leases v4:%d v6:%d total-read:%d from DB",
|
||||
len(leases4),
|
||||
len(leases6),
|
||||
len(leases),
|
||||
)
|
||||
log.Info("dhcp: loaded leases v4:%d v6:%d total-read:%d from DB",
|
||||
len(leases4), len(leases6), len(leases))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -151,26 +83,24 @@ func (s *server) dbLoad() (err error) {
|
||||
func (s *server) dbStore() (err error) {
|
||||
// Use an empty slice here as opposed to nil so that it doesn't write
|
||||
// "null" into the database file if leases are empty.
|
||||
leases := []*dbLease{}
|
||||
leases := []*Lease{}
|
||||
|
||||
for _, l := range s.srv4.getLeasesRef() {
|
||||
leases = append(leases, fromLease(l))
|
||||
}
|
||||
leases4 := s.srv4.getLeasesRef()
|
||||
leases = append(leases, leases4...)
|
||||
|
||||
if s.srv6 != nil {
|
||||
for _, l := range s.srv6.getLeasesRef() {
|
||||
leases = append(leases, fromLease(l))
|
||||
}
|
||||
leases6 := s.srv6.getLeasesRef()
|
||||
leases = append(leases, leases6...)
|
||||
}
|
||||
|
||||
return writeDB(s.conf.dbFilePath, leases)
|
||||
}
|
||||
|
||||
// writeDB writes leases to file at path.
|
||||
func writeDB(path string, leases []*dbLease) (err error) {
|
||||
func writeDB(path string, leases []*Lease) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "writing db: %w") }()
|
||||
|
||||
slices.SortFunc(leases, func(a, b *dbLease) (res int) {
|
||||
slices.SortFunc(leases, func(a, b *Lease) (res int) {
|
||||
return strings.Compare(a.Hostname, b.Hostname)
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package dhcpd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/timeutil"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -27,6 +29,105 @@ const (
|
||||
defaultBackoff time.Duration = 500 * time.Millisecond
|
||||
)
|
||||
|
||||
// Lease contains the necessary information about a DHCP lease. It's used as is
|
||||
// in the database, so don't change it until it's absolutely necessary, see
|
||||
// [dataVersion].
|
||||
//
|
||||
// TODO(e.burkov): Unexport it and use [dhcpsvc.Lease].
|
||||
type Lease struct {
|
||||
// Expiry is the expiration time of the lease.
|
||||
Expiry time.Time `json:"expires"`
|
||||
|
||||
// Hostname of the client.
|
||||
Hostname string `json:"hostname"`
|
||||
|
||||
// HWAddr is the physical hardware address (MAC address).
|
||||
HWAddr net.HardwareAddr `json:"mac"`
|
||||
|
||||
// IP is the IP address leased to the client.
|
||||
IP netip.Addr `json:"ip"`
|
||||
|
||||
// IsStatic defines if the lease is static.
|
||||
IsStatic bool `json:"static"`
|
||||
}
|
||||
|
||||
// Clone returns a deep copy of l.
|
||||
func (l *Lease) Clone() (clone *Lease) {
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Lease{
|
||||
Expiry: l.Expiry,
|
||||
Hostname: l.Hostname,
|
||||
HWAddr: slices.Clone(l.HWAddr),
|
||||
IP: l.IP,
|
||||
IsStatic: l.IsStatic,
|
||||
}
|
||||
}
|
||||
|
||||
// IsBlocklisted returns true if the lease is blocklisted.
|
||||
//
|
||||
// TODO(a.garipov): Just make it a boolean field.
|
||||
func (l *Lease) IsBlocklisted() (ok bool) {
|
||||
if len(l.HWAddr) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, b := range l.HWAddr {
|
||||
if b != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface for Lease.
|
||||
func (l Lease) MarshalJSON() ([]byte, error) {
|
||||
var expiryStr string
|
||||
if !l.IsStatic {
|
||||
// The front-end is waiting for RFC 3999 format of the time
|
||||
// value. It also shouldn't got an Expiry field for static
|
||||
// leases.
|
||||
//
|
||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/2692.
|
||||
expiryStr = l.Expiry.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
type lease Lease
|
||||
return json.Marshal(&struct {
|
||||
HWAddr string `json:"mac"`
|
||||
Expiry string `json:"expires,omitempty"`
|
||||
lease
|
||||
}{
|
||||
HWAddr: l.HWAddr.String(),
|
||||
Expiry: expiryStr,
|
||||
lease: lease(l),
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface for *Lease.
|
||||
func (l *Lease) UnmarshalJSON(data []byte) (err error) {
|
||||
type lease Lease
|
||||
aux := struct {
|
||||
*lease
|
||||
HWAddr string `json:"mac"`
|
||||
}{
|
||||
lease: (*lease)(l),
|
||||
}
|
||||
if err = json.Unmarshal(data, &aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.HWAddr, err = net.ParseMAC(aux.HWAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't parse MAC address: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnLeaseChangedT is a callback for lease changes.
|
||||
type OnLeaseChangedT func(flags int)
|
||||
|
||||
@@ -269,7 +370,19 @@ func (s *server) Stop() (err error) {
|
||||
|
||||
// Leases returns the list of active DHCP leases.
|
||||
func (s *server) Leases() (leases []*dhcpsvc.Lease) {
|
||||
return append(s.srv4.GetLeases(LeasesAll), s.srv6.GetLeases(LeasesAll)...)
|
||||
ls := append(s.srv4.GetLeases(LeasesAll), s.srv6.GetLeases(LeasesAll)...)
|
||||
leases = make([]*dhcpsvc.Lease, len(ls))
|
||||
for i, l := range ls {
|
||||
leases[i] = &dhcpsvc.Lease{
|
||||
Expiry: l.Expiry,
|
||||
Hostname: l.Hostname,
|
||||
HWAddr: l.HWAddr,
|
||||
IP: l.IP,
|
||||
IsStatic: l.IsStatic,
|
||||
}
|
||||
}
|
||||
|
||||
return leases
|
||||
}
|
||||
|
||||
// MACByIP returns a MAC address by the IP address of its lease, if there is
|
||||
@@ -301,6 +414,6 @@ func (s *server) IPByHost(host string) (ip netip.Addr) {
|
||||
}
|
||||
|
||||
// AddStaticLease - add static v4 lease
|
||||
func (s *server) AddStaticLease(l *dhcpsvc.Lease) error {
|
||||
func (s *server) AddStaticLease(l *Lease) error {
|
||||
return s.srv4.AddStaticLease(l)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -45,7 +44,7 @@ func TestDB(t *testing.T) {
|
||||
s.srv6, err = v6Create(V6ServerConf{})
|
||||
require.NoError(t, err)
|
||||
|
||||
leases := []*dhcpsvc.Lease{{
|
||||
leases := []*Lease{{
|
||||
Expiry: time.Now().Add(time.Hour),
|
||||
Hostname: "static-1.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
|
||||
@@ -93,13 +93,13 @@ func leasesToStatic(leases []*dhcpsvc.Lease) (static []*leaseStatic) {
|
||||
}
|
||||
|
||||
// toLease converts leaseStatic to Lease or returns error.
|
||||
func (l *leaseStatic) toLease() (lease *dhcpsvc.Lease, err error) {
|
||||
func (l *leaseStatic) toLease() (lease *Lease, err error) {
|
||||
addr, err := net.ParseMAC(l.HWAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't parse MAC address: %w", err)
|
||||
}
|
||||
|
||||
return &dhcpsvc.Lease{
|
||||
return &Lease{
|
||||
HWAddr: addr,
|
||||
IP: l.IP,
|
||||
Hostname: l.Hostname,
|
||||
@@ -593,7 +593,7 @@ func setOtherDHCPResult(ifaceName string, result *dhcpSearchResult) {
|
||||
|
||||
// parseLease parses a lease from r. If there is no error returns DHCPServer
|
||||
// and *Lease. r must be non-nil.
|
||||
func (s *server) parseLease(r io.Reader) (srv DHCPServer, lease *dhcpsvc.Lease, err error) {
|
||||
func (s *server) parseLease(r io.Reader) (srv DHCPServer, lease *Lease, err error) {
|
||||
l := &leaseStatic{}
|
||||
err = json.NewDecoder(r).Decode(l)
|
||||
if err != nil {
|
||||
|
||||
@@ -2,7 +2,6 @@ package dhcpd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
@@ -26,9 +25,9 @@ const (
|
||||
dbFilename = "leases.db"
|
||||
)
|
||||
|
||||
// leaseJSON is the structure of stored lease in a legacy database.
|
||||
// leaseJSON is the structure of stored lease.
|
||||
//
|
||||
// Deprecated: Use [dbLease].
|
||||
// Deprecated: Use [Lease].
|
||||
type leaseJSON struct {
|
||||
HWAddr []byte `json:"mac"`
|
||||
IP []byte `json:"ip"`
|
||||
@@ -36,28 +35,13 @@ type leaseJSON struct {
|
||||
Expiry int64 `json:"exp"`
|
||||
}
|
||||
|
||||
// readOldDB reads the old database from the given path.
|
||||
func readOldDB(path string) (leases []*leaseJSON, err error) {
|
||||
// #nosec G304 -- Trust this path, since it's taken from the old file name
|
||||
// relative to the working directory and should generally be considered
|
||||
// safe.
|
||||
file, err := os.Open(path)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// Nothing to migrate.
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return nil, err
|
||||
}
|
||||
defer func() { err = errors.WithDeferred(err, file.Close()) }()
|
||||
|
||||
leases = []*leaseJSON{}
|
||||
err = json.NewDecoder(file).Decode(&leases)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding old db: %w", err)
|
||||
func normalizeIP(ip net.IP) net.IP {
|
||||
ip4 := ip.To4()
|
||||
if ip4 != nil {
|
||||
return ip4
|
||||
}
|
||||
|
||||
return leases, nil
|
||||
return ip
|
||||
}
|
||||
|
||||
// migrateDB migrates stored leases if necessary.
|
||||
@@ -67,50 +51,59 @@ func migrateDB(conf *ServerConfig) (err error) {
|
||||
oldLeasesPath := filepath.Join(conf.WorkDir, dbFilename)
|
||||
dataDirPath := filepath.Join(conf.DataDir, dataFilename)
|
||||
|
||||
oldLeases, err := readOldDB(oldLeasesPath)
|
||||
// #nosec G304 -- Trust this path, since it's taken from the old file name
|
||||
// relative to the working directory and should generally be considered
|
||||
// safe.
|
||||
file, err := os.Open(oldLeasesPath)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// Nothing to migrate.
|
||||
return nil
|
||||
} else if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
ljs := []leaseJSON{}
|
||||
err = json.NewDecoder(file).Decode(&ljs)
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
} else if oldLeases == nil {
|
||||
// Nothing to migrate.
|
||||
return nil
|
||||
}
|
||||
|
||||
leases := make([]*dbLease, 0, len(oldLeases))
|
||||
for _, l := range oldLeases {
|
||||
l.IP = normalizeIP(l.IP)
|
||||
ip, ok := netip.AddrFromSlice(l.IP)
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
leases := []*Lease{}
|
||||
|
||||
for _, lj := range ljs {
|
||||
lj.IP = normalizeIP(lj.IP)
|
||||
|
||||
ip, ok := netip.AddrFromSlice(lj.IP)
|
||||
if !ok {
|
||||
log.Info("dhcp: invalid IP: %s", l.IP)
|
||||
log.Info("dhcp: invalid IP: %s", lj.IP)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
leases = append(leases, &dbLease{
|
||||
Expiry: time.Unix(l.Expiry, 0).Format(time.RFC3339),
|
||||
Hostname: l.Hostname,
|
||||
HWAddr: net.HardwareAddr(l.HWAddr).String(),
|
||||
lease := &Lease{
|
||||
Expiry: time.Unix(lj.Expiry, 0),
|
||||
Hostname: lj.Hostname,
|
||||
HWAddr: lj.HWAddr,
|
||||
IP: ip,
|
||||
IsStatic: l.Expiry == leaseExpireStatic,
|
||||
})
|
||||
IsStatic: lj.Expiry == leaseExpireStatic,
|
||||
}
|
||||
|
||||
leases = append(leases, lease)
|
||||
}
|
||||
|
||||
err = writeDB(dataDirPath, leases)
|
||||
if err != nil {
|
||||
// Don't wrap the error since an annotation deferred already.
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
return os.Remove(oldLeasesPath)
|
||||
}
|
||||
|
||||
// normalizeIP converts the given IP address to IPv4 if it's IPv4-mapped IPv6,
|
||||
// or leaves it as is otherwise.
|
||||
func normalizeIP(ip net.IP) (normalized net.IP) {
|
||||
normalized = ip.To4()
|
||||
if normalized != nil {
|
||||
return normalized
|
||||
}
|
||||
|
||||
return ip
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package dhcpd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -26,16 +27,16 @@ func TestMigrateDB(t *testing.T) {
|
||||
err := os.WriteFile(oldLeasesPath, []byte(testData), 0o644)
|
||||
require.NoError(t, err)
|
||||
|
||||
wantLeases := []*dbLease{{
|
||||
Expiry: time.Unix(1, 0).Format(time.RFC3339),
|
||||
wantLeases := []*Lease{{
|
||||
Expiry: time.Time{},
|
||||
Hostname: "test1",
|
||||
HWAddr: "11:22:33:44:55:66",
|
||||
HWAddr: net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66},
|
||||
IP: netip.MustParseAddr("1.2.3.4"),
|
||||
IsStatic: true,
|
||||
}, {
|
||||
Expiry: time.Unix(1231231231, 0).Format(time.RFC3339),
|
||||
Expiry: time.Unix(1231231231, 0),
|
||||
Hostname: "test2",
|
||||
HWAddr: "66:55:44:33:22:11",
|
||||
HWAddr: net.HardwareAddr{0x66, 0x55, 0x44, 0x33, 0x22, 0x11},
|
||||
IP: netip.MustParseAddr("4.3.2.1"),
|
||||
IsStatic: false,
|
||||
}}
|
||||
@@ -61,12 +62,12 @@ func TestMigrateDB(t *testing.T) {
|
||||
|
||||
leases := dl.Leases
|
||||
|
||||
for i, wantLease := range wantLeases {
|
||||
assert.Equal(t, wantLease.Hostname, leases[i].Hostname)
|
||||
assert.Equal(t, wantLease.HWAddr, leases[i].HWAddr)
|
||||
assert.Equal(t, wantLease.IP, leases[i].IP)
|
||||
assert.Equal(t, wantLease.IsStatic, leases[i].IsStatic)
|
||||
for i, wl := range wantLeases {
|
||||
assert.Equal(t, wl.Hostname, leases[i].Hostname)
|
||||
assert.Equal(t, wl.HWAddr, leases[i].HWAddr)
|
||||
assert.Equal(t, wl.IP, leases[i].IP)
|
||||
assert.Equal(t, wl.IsStatic, leases[i].IsStatic)
|
||||
|
||||
require.Equal(t, wantLease.Expiry, leases[i].Expiry)
|
||||
require.True(t, wl.Expiry.Equal(leases[i].Expiry))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ package dhcpd
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
)
|
||||
|
||||
type winServer struct{}
|
||||
@@ -16,19 +14,19 @@ type winServer struct{}
|
||||
// type check
|
||||
var _ DHCPServer = winServer{}
|
||||
|
||||
func (winServer) ResetLeases(_ []*dhcpsvc.Lease) (err error) { return nil }
|
||||
func (winServer) GetLeases(_ GetLeasesFlags) (leases []*dhcpsvc.Lease) { return nil }
|
||||
func (winServer) getLeasesRef() []*dhcpsvc.Lease { return nil }
|
||||
func (winServer) AddStaticLease(_ *dhcpsvc.Lease) (err error) { return nil }
|
||||
func (winServer) RemoveStaticLease(_ *dhcpsvc.Lease) (err error) { return nil }
|
||||
func (winServer) UpdateStaticLease(_ *dhcpsvc.Lease) (err error) { return nil }
|
||||
func (winServer) FindMACbyIP(_ netip.Addr) (mac net.HardwareAddr) { return nil }
|
||||
func (winServer) WriteDiskConfig4(_ *V4ServerConf) {}
|
||||
func (winServer) WriteDiskConfig6(_ *V6ServerConf) {}
|
||||
func (winServer) Start() (err error) { return nil }
|
||||
func (winServer) Stop() (err error) { return nil }
|
||||
func (winServer) HostByIP(_ netip.Addr) (host string) { return "" }
|
||||
func (winServer) IPByHost(_ string) (ip netip.Addr) { return netip.Addr{} }
|
||||
func (winServer) ResetLeases(_ []*Lease) (err error) { return nil }
|
||||
func (winServer) GetLeases(_ GetLeasesFlags) (leases []*Lease) { return nil }
|
||||
func (winServer) getLeasesRef() []*Lease { return nil }
|
||||
func (winServer) AddStaticLease(_ *Lease) (err error) { return nil }
|
||||
func (winServer) RemoveStaticLease(_ *Lease) (err error) { return nil }
|
||||
func (winServer) UpdateStaticLease(_ *Lease) (err error) { return nil }
|
||||
func (winServer) FindMACbyIP(_ netip.Addr) (mac net.HardwareAddr) { return nil }
|
||||
func (winServer) WriteDiskConfig4(_ *V4ServerConf) {}
|
||||
func (winServer) WriteDiskConfig6(_ *V6ServerConf) {}
|
||||
func (winServer) Start() (err error) { return nil }
|
||||
func (winServer) Stop() (err error) { return nil }
|
||||
func (winServer) HostByIP(_ netip.Addr) (host string) { return "" }
|
||||
func (winServer) IPByHost(_ string) (ip netip.Addr) { return netip.Addr{} }
|
||||
|
||||
func v4Create(_ *V4ServerConf) (s DHCPServer, err error) { return winServer{}, nil }
|
||||
func v6Create(_ V6ServerConf) (s DHCPServer, err error) { return winServer{}, nil }
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
@@ -39,7 +38,7 @@ type v4Server struct {
|
||||
// have intersections with [implicitOpts].
|
||||
explicitOpts dhcpv4.Options
|
||||
|
||||
// leasesLock protects leases, hostsIndex, ipIndex, and leasedOffsets.
|
||||
// leasesLock protects leases, leaseHosts, and leasedOffsets.
|
||||
leasesLock sync.Mutex
|
||||
|
||||
// leasedOffsets contains offsets from conf.ipRange.start that have been
|
||||
@@ -47,13 +46,13 @@ type v4Server struct {
|
||||
leasedOffsets *bitSet
|
||||
|
||||
// leases contains all dynamic and static leases.
|
||||
leases []*dhcpsvc.Lease
|
||||
leases []*Lease
|
||||
|
||||
// hostsIndex is the set of all hostnames of all known DHCP clients.
|
||||
hostsIndex map[string]*dhcpsvc.Lease
|
||||
hostsIndex map[string]*Lease
|
||||
|
||||
// ipIndex is an index of leases by their IP addresses.
|
||||
ipIndex map[netip.Addr]*dhcpsvc.Lease
|
||||
ipIndex map[netip.Addr]*Lease
|
||||
}
|
||||
|
||||
func (s *v4Server) enabled() (ok bool) {
|
||||
@@ -142,7 +141,7 @@ func (s *v4Server) IPByHost(host string) (ip netip.Addr) {
|
||||
}
|
||||
|
||||
// ResetLeases resets leases.
|
||||
func (s *v4Server) ResetLeases(leases []*dhcpsvc.Lease) (err error) {
|
||||
func (s *v4Server) ResetLeases(leases []*Lease) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "dhcpv4: %w") }()
|
||||
|
||||
if s.conf == nil {
|
||||
@@ -153,8 +152,8 @@ func (s *v4Server) ResetLeases(leases []*dhcpsvc.Lease) (err error) {
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
s.leasedOffsets = newBitSet()
|
||||
s.hostsIndex = make(map[string]*dhcpsvc.Lease, len(leases))
|
||||
s.ipIndex = make(map[netip.Addr]*dhcpsvc.Lease, len(leases))
|
||||
s.hostsIndex = make(map[string]*Lease, len(leases))
|
||||
s.ipIndex = make(map[netip.Addr]*Lease, len(leases))
|
||||
s.leases = nil
|
||||
|
||||
for _, l := range leases {
|
||||
@@ -174,14 +173,14 @@ func (s *v4Server) ResetLeases(leases []*dhcpsvc.Lease) (err error) {
|
||||
}
|
||||
|
||||
// getLeasesRef returns the actual leases slice. For internal use only.
|
||||
func (s *v4Server) getLeasesRef() []*dhcpsvc.Lease {
|
||||
func (s *v4Server) getLeasesRef() []*Lease {
|
||||
return s.leases
|
||||
}
|
||||
|
||||
// isBlocklisted returns true if this lease holds a blocklisted IP.
|
||||
//
|
||||
// TODO(a.garipov): Make a method of *Lease?
|
||||
func (s *v4Server) isBlocklisted(l *dhcpsvc.Lease) (ok bool) {
|
||||
func (s *v4Server) isBlocklisted(l *Lease) (ok bool) {
|
||||
if len(l.HWAddr) == 0 {
|
||||
return false
|
||||
}
|
||||
@@ -197,11 +196,11 @@ func (s *v4Server) isBlocklisted(l *dhcpsvc.Lease) (ok bool) {
|
||||
|
||||
// GetLeases returns the list of current DHCP leases. It is safe for concurrent
|
||||
// use.
|
||||
func (s *v4Server) GetLeases(flags GetLeasesFlags) (leases []*dhcpsvc.Lease) {
|
||||
func (s *v4Server) GetLeases(flags GetLeasesFlags) (leases []*Lease) {
|
||||
// The function shouldn't return nil, because zero-length slice behaves
|
||||
// differently in cases like marshalling. Our front-end also requires
|
||||
// a non-nil value in the response.
|
||||
leases = []*dhcpsvc.Lease{}
|
||||
leases = []*Lease{}
|
||||
|
||||
getDynamic := flags&LeasesDynamic != 0
|
||||
getStatic := flags&LeasesStatic != 0
|
||||
@@ -249,7 +248,7 @@ func (s *v4Server) FindMACbyIP(ip netip.Addr) (mac net.HardwareAddr) {
|
||||
const defaultHwAddrLen = 6
|
||||
|
||||
// Add the specified IP to the black list for a time period
|
||||
func (s *v4Server) blocklistLease(l *dhcpsvc.Lease) {
|
||||
func (s *v4Server) blocklistLease(l *Lease) {
|
||||
l.HWAddr = make(net.HardwareAddr, defaultHwAddrLen)
|
||||
l.Hostname = ""
|
||||
l.Expiry = time.Now().Add(s.conf.leaseTime)
|
||||
@@ -285,7 +284,7 @@ func (s *v4Server) rmLeaseByIndex(i int) {
|
||||
// Return error if a static lease is found
|
||||
//
|
||||
// TODO(s.chzhen): Refactor the code.
|
||||
func (s *v4Server) rmDynamicLease(lease *dhcpsvc.Lease) (err error) {
|
||||
func (s *v4Server) rmDynamicLease(lease *Lease) (err error) {
|
||||
for i, l := range s.leases {
|
||||
isStatic := l.IsStatic
|
||||
|
||||
@@ -321,7 +320,7 @@ const (
|
||||
)
|
||||
|
||||
// addLease adds a dynamic or static lease.
|
||||
func (s *v4Server) addLease(l *dhcpsvc.Lease) (err error) {
|
||||
func (s *v4Server) addLease(l *Lease) (err error) {
|
||||
r := s.conf.ipRange
|
||||
leaseIP := net.IP(l.IP.AsSlice())
|
||||
offset, inOffset := r.offset(leaseIP)
|
||||
@@ -353,7 +352,7 @@ func (s *v4Server) addLease(l *dhcpsvc.Lease) (err error) {
|
||||
}
|
||||
|
||||
// rmLease removes a lease with the same properties.
|
||||
func (s *v4Server) rmLease(lease *dhcpsvc.Lease) (err error) {
|
||||
func (s *v4Server) rmLease(lease *Lease) (err error) {
|
||||
if len(s.leases) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -379,7 +378,7 @@ const ErrUnconfigured errors.Error = "server is unconfigured"
|
||||
|
||||
// AddStaticLease implements the DHCPServer interface for *v4Server. It is
|
||||
// safe for concurrent use.
|
||||
func (s *v4Server) AddStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
func (s *v4Server) AddStaticLease(l *Lease) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "dhcpv4: adding static lease: %w") }()
|
||||
|
||||
if s.conf == nil {
|
||||
@@ -436,7 +435,7 @@ func (s *v4Server) AddStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
}
|
||||
|
||||
// UpdateStaticLease updates IP, hostname of the static lease.
|
||||
func (s *v4Server) UpdateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
func (s *v4Server) UpdateStaticLease(l *Lease) (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = errors.Annotate(err, "dhcpv4: updating static lease: %w")
|
||||
@@ -475,7 +474,7 @@ func (s *v4Server) UpdateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
}
|
||||
|
||||
// validateStaticLease returns an error if the static lease is invalid.
|
||||
func (s *v4Server) validateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
func (s *v4Server) validateStaticLease(l *Lease) (err error) {
|
||||
hostname, err := normalizeHostname(l.Hostname)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
@@ -512,7 +511,7 @@ func (s *v4Server) validateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
|
||||
// updateStaticLease safe removes dynamic lease with the same properties and
|
||||
// then adds a static lease l.
|
||||
func (s *v4Server) updateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
func (s *v4Server) updateStaticLease(l *Lease) (err error) {
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
@@ -530,7 +529,7 @@ func (s *v4Server) updateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
}
|
||||
|
||||
// RemoveStaticLease removes a static lease. It is safe for concurrent use.
|
||||
func (s *v4Server) RemoveStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
func (s *v4Server) RemoveStaticLease(l *Lease) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "dhcpv4: %w") }()
|
||||
|
||||
if s.conf == nil {
|
||||
@@ -607,7 +606,7 @@ func (s *v4Server) addrAvailable(target net.IP) (avail bool) {
|
||||
}
|
||||
|
||||
// findLease finds a lease by its MAC-address.
|
||||
func (s *v4Server) findLease(mac net.HardwareAddr) (l *dhcpsvc.Lease) {
|
||||
func (s *v4Server) findLease(mac net.HardwareAddr) (l *Lease) {
|
||||
for _, l = range s.leases {
|
||||
if bytes.Equal(mac, l.HWAddr) {
|
||||
return l
|
||||
@@ -647,8 +646,8 @@ func (s *v4Server) findExpiredLease() int {
|
||||
|
||||
// reserveLease reserves a lease for a client by its MAC-address. It returns
|
||||
// nil if it couldn't allocate a new lease.
|
||||
func (s *v4Server) reserveLease(mac net.HardwareAddr) (l *dhcpsvc.Lease, err error) {
|
||||
l = &dhcpsvc.Lease{HWAddr: slices.Clone(mac)}
|
||||
func (s *v4Server) reserveLease(mac net.HardwareAddr) (l *Lease, err error) {
|
||||
l = &Lease{HWAddr: slices.Clone(mac)}
|
||||
|
||||
nextIP := s.nextIP()
|
||||
if nextIP == nil {
|
||||
@@ -680,7 +679,7 @@ func (s *v4Server) reserveLease(mac net.HardwareAddr) (l *dhcpsvc.Lease, err err
|
||||
// commitLease refreshes l's values. It takes the desired hostname into account
|
||||
// when setting it into the lease, but generates a unique one if the provided
|
||||
// can't be used.
|
||||
func (s *v4Server) commitLease(l *dhcpsvc.Lease, hostname string) {
|
||||
func (s *v4Server) commitLease(l *Lease, hostname string) {
|
||||
prev := l.Hostname
|
||||
hostname = s.validHostnameForClient(hostname, l.IP)
|
||||
|
||||
@@ -710,7 +709,7 @@ func (s *v4Server) commitLease(l *dhcpsvc.Lease, hostname string) {
|
||||
|
||||
// allocateLease allocates a new lease for the MAC address. If there are no IP
|
||||
// addresses left, both l and err are nil.
|
||||
func (s *v4Server) allocateLease(mac net.HardwareAddr) (l *dhcpsvc.Lease, err error) {
|
||||
func (s *v4Server) allocateLease(mac net.HardwareAddr) (l *Lease, err error) {
|
||||
for {
|
||||
l, err = s.reserveLease(mac)
|
||||
if err != nil {
|
||||
@@ -729,7 +728,7 @@ func (s *v4Server) allocateLease(mac net.HardwareAddr) (l *dhcpsvc.Lease, err er
|
||||
}
|
||||
|
||||
// handleDiscover is the handler for the DHCP Discover request.
|
||||
func (s *v4Server) handleDiscover(req, resp *dhcpv4.DHCPv4) (l *dhcpsvc.Lease, err error) {
|
||||
func (s *v4Server) handleDiscover(req, resp *dhcpv4.DHCPv4) (l *Lease, err error) {
|
||||
mac := req.ClientHWAddr
|
||||
|
||||
defer s.conf.notify(LeaseChangedDBStore)
|
||||
@@ -788,7 +787,7 @@ func OptionFQDN(fqdn string) (opt dhcpv4.Option) {
|
||||
// checkLease checks if the pair of mac and ip is already leased. The mismatch
|
||||
// is true when the existing lease has the same hardware address but differs in
|
||||
// its IP address.
|
||||
func (s *v4Server) checkLease(mac net.HardwareAddr, ip net.IP) (l *dhcpsvc.Lease, mismatch bool) {
|
||||
func (s *v4Server) checkLease(mac net.HardwareAddr, ip net.IP) (lease *Lease, mismatch bool) {
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
@@ -799,7 +798,7 @@ func (s *v4Server) checkLease(mac net.HardwareAddr, ip net.IP) (l *dhcpsvc.Lease
|
||||
return nil, false
|
||||
}
|
||||
|
||||
for _, l = range s.leases {
|
||||
for _, l := range s.leases {
|
||||
if !bytes.Equal(l.HWAddr, mac) {
|
||||
continue
|
||||
}
|
||||
@@ -824,7 +823,7 @@ func (s *v4Server) handleSelecting(
|
||||
req *dhcpv4.DHCPv4,
|
||||
reqIP net.IP,
|
||||
sid net.IP,
|
||||
) (l *dhcpsvc.Lease, needsReply bool) {
|
||||
) (l *Lease, needsReply bool) {
|
||||
// Client inserts the address of the selected server in server identifier,
|
||||
// ciaddr MUST be zero.
|
||||
mac := req.ClientHWAddr
|
||||
@@ -858,10 +857,7 @@ func (s *v4Server) handleSelecting(
|
||||
}
|
||||
|
||||
// handleInitReboot handles the DHCPREQUEST generated during INIT-REBOOT state.
|
||||
func (s *v4Server) handleInitReboot(
|
||||
req *dhcpv4.DHCPv4,
|
||||
reqIP net.IP,
|
||||
) (l *dhcpsvc.Lease, needsReply bool) {
|
||||
func (s *v4Server) handleInitReboot(req *dhcpv4.DHCPv4, reqIP net.IP) (l *Lease, needsReply bool) {
|
||||
mac := req.ClientHWAddr
|
||||
|
||||
ip4 := reqIP.To4()
|
||||
@@ -903,7 +899,7 @@ func (s *v4Server) handleInitReboot(
|
||||
|
||||
// handleRenew handles the DHCPREQUEST generated during RENEWING or REBINDING
|
||||
// state.
|
||||
func (s *v4Server) handleRenew(req *dhcpv4.DHCPv4) (l *dhcpsvc.Lease, needsReply bool) {
|
||||
func (s *v4Server) handleRenew(req *dhcpv4.DHCPv4) (l *Lease, needsReply bool) {
|
||||
mac := req.ClientHWAddr
|
||||
|
||||
// ciaddr MUST be filled in with client's IP address.
|
||||
@@ -930,7 +926,7 @@ func (s *v4Server) handleRenew(req *dhcpv4.DHCPv4) (l *dhcpsvc.Lease, needsReply
|
||||
|
||||
// handleByRequestType handles the DHCPREQUEST according to the state during
|
||||
// which it's generated by client.
|
||||
func (s *v4Server) handleByRequestType(req *dhcpv4.DHCPv4) (lease *dhcpsvc.Lease, needsReply bool) {
|
||||
func (s *v4Server) handleByRequestType(req *dhcpv4.DHCPv4) (lease *Lease, needsReply bool) {
|
||||
reqIP, sid := req.RequestedIPAddress(), req.ServerIdentifier()
|
||||
|
||||
if sid != nil && !sid.IsUnspecified() {
|
||||
@@ -954,7 +950,7 @@ func (s *v4Server) handleByRequestType(req *dhcpv4.DHCPv4) (lease *dhcpsvc.Lease
|
||||
// handleRequest is the handler for a DHCPREQUEST message.
|
||||
//
|
||||
// See https://datatracker.ietf.org/doc/html/rfc2131#section-4.3.2.
|
||||
func (s *v4Server) handleRequest(req, resp *dhcpv4.DHCPv4) (lease *dhcpsvc.Lease, needsReply bool) {
|
||||
func (s *v4Server) handleRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, needsReply bool) {
|
||||
lease, needsReply = s.handleByRequestType(req)
|
||||
if lease == nil {
|
||||
return nil, needsReply
|
||||
@@ -1047,7 +1043,7 @@ func (s *v4Server) handleDecline(req, resp *dhcpv4.DHCPv4) (err error) {
|
||||
}
|
||||
|
||||
// findLeaseForIP returns a lease for provided ip and mac.
|
||||
func (s *v4Server) findLeaseForIP(ip net.IP, mac net.HardwareAddr) (l *dhcpsvc.Lease) {
|
||||
func (s *v4Server) findLeaseForIP(ip net.IP, mac net.HardwareAddr) (l *Lease) {
|
||||
netIP, ok := netip.AddrFromSlice(ip)
|
||||
if !ok {
|
||||
log.Info("dhcpv4: invalid IP: %s", ip)
|
||||
@@ -1110,11 +1106,7 @@ func (s *v4Server) handleRelease(req, resp *dhcpv4.DHCPv4) (err error) {
|
||||
}
|
||||
|
||||
// messageHandler describes a DHCPv4 message handler function.
|
||||
type messageHandler func(
|
||||
s *v4Server,
|
||||
req *dhcpv4.DHCPv4,
|
||||
resp *dhcpv4.DHCPv4,
|
||||
) (rCode int, l *dhcpsvc.Lease, err error)
|
||||
type messageHandler func(s *v4Server, req, resp *dhcpv4.DHCPv4) (rCode int, l *Lease, err error)
|
||||
|
||||
// messageHandlers is a map of handlers for various messages with message types
|
||||
// keys.
|
||||
@@ -1123,7 +1115,7 @@ var messageHandlers = map[dhcpv4.MessageType]messageHandler{
|
||||
s *v4Server,
|
||||
req *dhcpv4.DHCPv4,
|
||||
resp *dhcpv4.DHCPv4,
|
||||
) (rCode int, l *dhcpsvc.Lease, err error) {
|
||||
) (rCode int, l *Lease, err error) {
|
||||
l, err = s.handleDiscover(req, resp)
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("handling discover: %s", err)
|
||||
@@ -1139,7 +1131,7 @@ var messageHandlers = map[dhcpv4.MessageType]messageHandler{
|
||||
s *v4Server,
|
||||
req *dhcpv4.DHCPv4,
|
||||
resp *dhcpv4.DHCPv4,
|
||||
) (rCode int, l *dhcpsvc.Lease, err error) {
|
||||
) (rCode int, l *Lease, err error) {
|
||||
var toReply bool
|
||||
l, toReply = s.handleRequest(req, resp)
|
||||
if l == nil {
|
||||
@@ -1157,7 +1149,7 @@ var messageHandlers = map[dhcpv4.MessageType]messageHandler{
|
||||
s *v4Server,
|
||||
req *dhcpv4.DHCPv4,
|
||||
resp *dhcpv4.DHCPv4,
|
||||
) (rCode int, l *dhcpsvc.Lease, err error) {
|
||||
) (rCode int, l *Lease, err error) {
|
||||
err = s.handleDecline(req, resp)
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("handling decline: %s", err)
|
||||
@@ -1169,7 +1161,7 @@ var messageHandlers = map[dhcpv4.MessageType]messageHandler{
|
||||
s *v4Server,
|
||||
req *dhcpv4.DHCPv4,
|
||||
resp *dhcpv4.DHCPv4,
|
||||
) (rCode int, l *dhcpsvc.Lease, err error) {
|
||||
) (rCode int, l *Lease, err error) {
|
||||
err = s.handleRelease(req, resp)
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("handling release: %s", err)
|
||||
@@ -1410,8 +1402,8 @@ func (s *v4Server) Stop() (err error) {
|
||||
// Create DHCPv4 server
|
||||
func v4Create(conf *V4ServerConf) (srv *v4Server, err error) {
|
||||
s := &v4Server{
|
||||
hostsIndex: map[string]*dhcpsvc.Lease{},
|
||||
ipIndex: map[netip.Addr]*dhcpsvc.Lease{},
|
||||
hostsIndex: map[string]*Lease{},
|
||||
ipIndex: map[netip.Addr]*Lease{},
|
||||
}
|
||||
|
||||
err = conf.Validate()
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/stringutil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
@@ -68,7 +67,7 @@ func TestV4Server_leasing(t *testing.T) {
|
||||
s := defaultSrv(t)
|
||||
|
||||
t.Run("add_static", func(t *testing.T) {
|
||||
err := s.AddStaticLease(&dhcpsvc.Lease{
|
||||
err := s.AddStaticLease(&Lease{
|
||||
Hostname: staticName,
|
||||
HWAddr: staticMAC,
|
||||
IP: staticIP,
|
||||
@@ -77,7 +76,7 @@ func TestV4Server_leasing(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("same_name", func(t *testing.T) {
|
||||
err = s.AddStaticLease(&dhcpsvc.Lease{
|
||||
err = s.AddStaticLease(&Lease{
|
||||
Hostname: staticName,
|
||||
HWAddr: anotherMAC,
|
||||
IP: anotherIP,
|
||||
@@ -91,7 +90,7 @@ func TestV4Server_leasing(t *testing.T) {
|
||||
"dynamic leases for " + anotherIP.String() +
|
||||
" (" + staticMAC.String() + "): static lease already exists"
|
||||
|
||||
err = s.AddStaticLease(&dhcpsvc.Lease{
|
||||
err = s.AddStaticLease(&Lease{
|
||||
Hostname: anotherName,
|
||||
HWAddr: staticMAC,
|
||||
IP: anotherIP,
|
||||
@@ -105,7 +104,7 @@ func TestV4Server_leasing(t *testing.T) {
|
||||
"dynamic leases for " + staticIP.String() +
|
||||
" (" + anotherMAC.String() + "): static lease already exists"
|
||||
|
||||
err = s.AddStaticLease(&dhcpsvc.Lease{
|
||||
err = s.AddStaticLease(&Lease{
|
||||
Hostname: anotherName,
|
||||
HWAddr: anotherMAC,
|
||||
IP: staticIP,
|
||||
@@ -209,11 +208,11 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||
require.Empty(t, ls)
|
||||
|
||||
testCases := []struct {
|
||||
lease *dhcpsvc.Lease
|
||||
lease *Lease
|
||||
name string
|
||||
wantErrMsg string
|
||||
}{{
|
||||
lease: &dhcpsvc.Lease{
|
||||
lease: &Lease{
|
||||
Hostname: "success.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: netip.MustParseAddr("192.168.10.150"),
|
||||
@@ -221,7 +220,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||
name: "success",
|
||||
wantErrMsg: "",
|
||||
}, {
|
||||
lease: &dhcpsvc.Lease{
|
||||
lease: &Lease{
|
||||
Hostname: "probably-router.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: DefaultGatewayIP,
|
||||
@@ -230,7 +229,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||
wantErrMsg: "dhcpv4: adding static lease: " +
|
||||
`can't assign the gateway IP "192.168.10.1" to the lease`,
|
||||
}, {
|
||||
lease: &dhcpsvc.Lease{
|
||||
lease: &Lease{
|
||||
Hostname: "ip6.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: netip.MustParseAddr("ffff::1"),
|
||||
@@ -239,7 +238,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||
wantErrMsg: `dhcpv4: adding static lease: ` +
|
||||
`invalid IP "ffff::1": only IPv4 is supported`,
|
||||
}, {
|
||||
lease: &dhcpsvc.Lease{
|
||||
lease: &Lease{
|
||||
Hostname: "bad-mac.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA},
|
||||
IP: netip.MustParseAddr("192.168.10.150"),
|
||||
@@ -248,7 +247,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||
wantErrMsg: `dhcpv4: adding static lease: bad mac address "aa:aa": ` +
|
||||
`bad mac address length 2, allowed: [6 8 20]`,
|
||||
}, {
|
||||
lease: &dhcpsvc.Lease{
|
||||
lease: &Lease{
|
||||
Hostname: "bad-lbl-.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: netip.MustParseAddr("192.168.10.150"),
|
||||
@@ -267,7 +266,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
err = s.RemoveStaticLease(&dhcpsvc.Lease{
|
||||
err = s.RemoveStaticLease(&Lease{
|
||||
IP: tc.lease.IP,
|
||||
HWAddr: tc.lease.HWAddr,
|
||||
})
|
||||
@@ -290,7 +289,7 @@ func TestV4_AddReplace(t *testing.T) {
|
||||
s, ok := sIface.(*v4Server)
|
||||
require.True(t, ok)
|
||||
|
||||
dynLeases := []dhcpsvc.Lease{{
|
||||
dynLeases := []Lease{{
|
||||
Hostname: "dynamic-1.local",
|
||||
HWAddr: net.HardwareAddr{0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: netip.MustParseAddr("192.168.10.150"),
|
||||
@@ -305,7 +304,7 @@ func TestV4_AddReplace(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
stLeases := []*dhcpsvc.Lease{{
|
||||
stLeases := []*Lease{{
|
||||
Hostname: "static-1.local",
|
||||
HWAddr: net.HardwareAddr{0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: netip.MustParseAddr("192.168.10.150"),
|
||||
@@ -514,7 +513,7 @@ func TestV4StaticLease_Get(t *testing.T) {
|
||||
s.conf.dnsIPAddrs = []netip.Addr{dnsAddr}
|
||||
s.implicitOpts.Update(dhcpv4.OptDNS(dnsAddr.AsSlice()))
|
||||
|
||||
l := &dhcpsvc.Lease{
|
||||
l := &Lease{
|
||||
Hostname: "static-1.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: netip.MustParseAddr("192.168.10.150"),
|
||||
@@ -780,7 +779,7 @@ func TestV4Server_FindMACbyIP(t *testing.T) {
|
||||
anotherMAC := net.HardwareAddr{0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB}
|
||||
|
||||
s := &v4Server{
|
||||
leases: []*dhcpsvc.Lease{{
|
||||
leases: []*Lease{{
|
||||
Hostname: staticName,
|
||||
HWAddr: staticMAC,
|
||||
IP: staticIP,
|
||||
@@ -792,11 +791,11 @@ func TestV4Server_FindMACbyIP(t *testing.T) {
|
||||
IP: anotherIP,
|
||||
}},
|
||||
}
|
||||
s.ipIndex = map[netip.Addr]*dhcpsvc.Lease{
|
||||
s.ipIndex = map[netip.Addr]*Lease{
|
||||
staticIP: s.leases[0],
|
||||
anotherIP: s.leases[1],
|
||||
}
|
||||
s.hostsIndex = map[string]*dhcpsvc.Lease{
|
||||
s.hostsIndex = map[string]*Lease{
|
||||
staticName: s.leases[0],
|
||||
anotherName: s.leases[1],
|
||||
}
|
||||
@@ -846,7 +845,7 @@ func TestV4Server_handleDecline(t *testing.T) {
|
||||
s4, ok := s.(*v4Server)
|
||||
require.True(t, ok)
|
||||
|
||||
s4.leases = []*dhcpsvc.Lease{{
|
||||
s4.leases = []*Lease{{
|
||||
Hostname: dynamicName,
|
||||
HWAddr: dynamicMAC,
|
||||
IP: dynamicIP,
|
||||
@@ -888,7 +887,7 @@ func TestV4Server_handleRelease(t *testing.T) {
|
||||
s4, ok := s.(*v4Server)
|
||||
require.True(t, ok)
|
||||
|
||||
s4.leases = []*dhcpsvc.Lease{{
|
||||
s4.leases = []*Lease{{
|
||||
Hostname: dynamicName,
|
||||
HWAddr: dynamicMAC,
|
||||
IP: dynamicIP,
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
@@ -32,7 +31,7 @@ type v6Server struct {
|
||||
sid dhcpv6.DUID
|
||||
srv *server6.Server
|
||||
|
||||
leases []*dhcpsvc.Lease
|
||||
leases []*Lease
|
||||
leasesLock sync.Mutex
|
||||
ipAddrs [256]byte
|
||||
}
|
||||
@@ -88,7 +87,7 @@ func (s *v6Server) IPByHost(host string) (ip netip.Addr) {
|
||||
}
|
||||
|
||||
// ResetLeases resets leases.
|
||||
func (s *v6Server) ResetLeases(leases []*dhcpsvc.Lease) (err error) {
|
||||
func (s *v6Server) ResetLeases(leases []*Lease) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "dhcpv6: %w") }()
|
||||
|
||||
s.leasesLock.Lock()
|
||||
@@ -112,14 +111,12 @@ func (s *v6Server) ResetLeases(leases []*dhcpsvc.Lease) (err error) {
|
||||
|
||||
// GetLeases returns the list of current DHCP leases. It is safe for concurrent
|
||||
// use.
|
||||
func (s *v6Server) GetLeases(flags GetLeasesFlags) (leases []*dhcpsvc.Lease) {
|
||||
func (s *v6Server) GetLeases(flags GetLeasesFlags) (leases []*Lease) {
|
||||
// The function shouldn't return nil value because zero-length slice
|
||||
// behaves differently in cases like marshalling. Our front-end also
|
||||
// requires non-nil value in the response.
|
||||
leases = []*dhcpsvc.Lease{}
|
||||
leases = []*Lease{}
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
for _, l := range s.leases {
|
||||
if l.IsStatic {
|
||||
if (flags & LeasesStatic) != 0 {
|
||||
@@ -131,12 +128,12 @@ func (s *v6Server) GetLeases(flags GetLeasesFlags) (leases []*dhcpsvc.Lease) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.leasesLock.Unlock()
|
||||
return leases
|
||||
}
|
||||
|
||||
// getLeasesRef returns the actual leases slice. For internal use only.
|
||||
func (s *v6Server) getLeasesRef() []*dhcpsvc.Lease {
|
||||
func (s *v6Server) getLeasesRef() []*Lease {
|
||||
return s.leases
|
||||
}
|
||||
|
||||
@@ -177,7 +174,7 @@ func (s *v6Server) leaseRemoveSwapByIndex(i int) {
|
||||
|
||||
// Remove a dynamic lease with the same properties
|
||||
// Return error if a static lease is found
|
||||
func (s *v6Server) rmDynamicLease(lease *dhcpsvc.Lease) (err error) {
|
||||
func (s *v6Server) rmDynamicLease(lease *Lease) (err error) {
|
||||
for i := 0; i < len(s.leases); i++ {
|
||||
l := s.leases[i]
|
||||
|
||||
@@ -207,7 +204,7 @@ func (s *v6Server) rmDynamicLease(lease *dhcpsvc.Lease) (err error) {
|
||||
}
|
||||
|
||||
// AddStaticLease adds a static lease. It is safe for concurrent use.
|
||||
func (s *v6Server) AddStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
func (s *v6Server) AddStaticLease(l *Lease) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "dhcpv6: %w") }()
|
||||
|
||||
if !l.IP.Is6() {
|
||||
@@ -239,7 +236,7 @@ func (s *v6Server) AddStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
}
|
||||
|
||||
// UpdateStaticLease updates IP, hostname of the static lease.
|
||||
func (s *v6Server) UpdateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
func (s *v6Server) UpdateStaticLease(l *Lease) (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = errors.Annotate(err, "dhcpv6: updating static lease: %w")
|
||||
@@ -270,7 +267,7 @@ func (s *v6Server) UpdateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
}
|
||||
|
||||
// RemoveStaticLease removes a static lease. It is safe for concurrent use.
|
||||
func (s *v6Server) RemoveStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
func (s *v6Server) RemoveStaticLease(l *Lease) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "dhcpv6: %w") }()
|
||||
|
||||
if !l.IP.Is6() {
|
||||
@@ -295,7 +292,7 @@ func (s *v6Server) RemoveStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||
}
|
||||
|
||||
// Add a lease
|
||||
func (s *v6Server) addLease(l *dhcpsvc.Lease) {
|
||||
func (s *v6Server) addLease(l *Lease) {
|
||||
s.leases = append(s.leases, l)
|
||||
ip := l.IP.As16()
|
||||
s.ipAddrs[ip[15]] = 1
|
||||
@@ -303,7 +300,7 @@ func (s *v6Server) addLease(l *dhcpsvc.Lease) {
|
||||
}
|
||||
|
||||
// Remove a lease with the same properties
|
||||
func (s *v6Server) rmLease(lease *dhcpsvc.Lease) (err error) {
|
||||
func (s *v6Server) rmLease(lease *Lease) (err error) {
|
||||
for i, l := range s.leases {
|
||||
if l.IP == lease.IP {
|
||||
if !bytes.Equal(l.HWAddr, lease.HWAddr) ||
|
||||
@@ -321,7 +318,7 @@ func (s *v6Server) rmLease(lease *dhcpsvc.Lease) (err error) {
|
||||
}
|
||||
|
||||
// Find lease by MAC.
|
||||
func (s *v6Server) findLease(mac net.HardwareAddr) (lease *dhcpsvc.Lease) {
|
||||
func (s *v6Server) findLease(mac net.HardwareAddr) (lease *Lease) {
|
||||
for i := range s.leases {
|
||||
if bytes.Equal(mac, s.leases[i].HWAddr) {
|
||||
return s.leases[i]
|
||||
@@ -359,8 +356,8 @@ func (s *v6Server) findFreeIP() net.IP {
|
||||
}
|
||||
|
||||
// Reserve lease for MAC
|
||||
func (s *v6Server) reserveLease(mac net.HardwareAddr) *dhcpsvc.Lease {
|
||||
l := dhcpsvc.Lease{
|
||||
func (s *v6Server) reserveLease(mac net.HardwareAddr) *Lease {
|
||||
l := Lease{
|
||||
HWAddr: make([]byte, len(mac)),
|
||||
}
|
||||
|
||||
@@ -393,7 +390,7 @@ func (s *v6Server) reserveLease(mac net.HardwareAddr) *dhcpsvc.Lease {
|
||||
return &l
|
||||
}
|
||||
|
||||
func (s *v6Server) commitDynamicLease(l *dhcpsvc.Lease) {
|
||||
func (s *v6Server) commitDynamicLease(l *Lease) {
|
||||
l.Expiry = time.Now().Add(s.conf.leaseTime)
|
||||
|
||||
s.leasesLock.Lock()
|
||||
@@ -441,7 +438,7 @@ func (s *v6Server) checkSID(msg *dhcpv6.Message) error {
|
||||
}
|
||||
|
||||
// . IAAddress must be equal to the lease's IP
|
||||
func (s *v6Server) checkIA(msg *dhcpv6.Message, lease *dhcpsvc.Lease) error {
|
||||
func (s *v6Server) checkIA(msg *dhcpv6.Message, lease *Lease) error {
|
||||
switch msg.Type() {
|
||||
case dhcpv6.MessageTypeRequest,
|
||||
dhcpv6.MessageTypeConfirm,
|
||||
@@ -467,7 +464,7 @@ func (s *v6Server) checkIA(msg *dhcpv6.Message, lease *dhcpsvc.Lease) error {
|
||||
}
|
||||
|
||||
// Store lease in DB (if necessary) and return lease life time
|
||||
func (s *v6Server) commitLease(msg *dhcpv6.Message, lease *dhcpsvc.Lease) time.Duration {
|
||||
func (s *v6Server) commitLease(msg *dhcpv6.Message, lease *Lease) time.Duration {
|
||||
lifetime := s.conf.leaseTime
|
||||
|
||||
switch msg.Type() {
|
||||
@@ -509,7 +506,7 @@ func (s *v6Server) process(msg *dhcpv6.Message, req, resp dhcpv6.DHCPv6) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var lease *dhcpsvc.Lease
|
||||
var lease *Lease
|
||||
func() {
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/insomniacslk/dhcp/dhcpv6"
|
||||
"github.com/insomniacslk/dhcp/iana"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -29,7 +28,7 @@ func TestV6_AddRemove_static(t *testing.T) {
|
||||
require.Empty(t, s.GetLeases(LeasesStatic))
|
||||
|
||||
// Add static lease.
|
||||
l := &dhcpsvc.Lease{
|
||||
l := &Lease{
|
||||
IP: netip.MustParseAddr("2001::1"),
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
}
|
||||
@@ -48,7 +47,7 @@ func TestV6_AddRemove_static(t *testing.T) {
|
||||
assert.True(t, ls[0].IsStatic)
|
||||
|
||||
// Try to remove non-existent static lease.
|
||||
err = s.RemoveStaticLease(&dhcpsvc.Lease{
|
||||
err = s.RemoveStaticLease(&Lease{
|
||||
IP: netip.MustParseAddr("2001::2"),
|
||||
HWAddr: l.HWAddr,
|
||||
})
|
||||
@@ -73,7 +72,7 @@ func TestV6_AddReplace(t *testing.T) {
|
||||
require.True(t, ok)
|
||||
|
||||
// Add dynamic leases.
|
||||
dynLeases := []*dhcpsvc.Lease{{
|
||||
dynLeases := []*Lease{{
|
||||
IP: netip.MustParseAddr("2001::1"),
|
||||
HWAddr: net.HardwareAddr{0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
}, {
|
||||
@@ -85,7 +84,7 @@ func TestV6_AddReplace(t *testing.T) {
|
||||
s.addLease(l)
|
||||
}
|
||||
|
||||
stLeases := []*dhcpsvc.Lease{{
|
||||
stLeases := []*Lease{{
|
||||
IP: netip.MustParseAddr("2001::1"),
|
||||
HWAddr: net.HardwareAddr{0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
}, {
|
||||
@@ -127,7 +126,7 @@ func TestV6GetLease(t *testing.T) {
|
||||
LinkLayerAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
}
|
||||
|
||||
l := &dhcpsvc.Lease{
|
||||
l := &Lease{
|
||||
IP: netip.MustParseAddr("2001::1"),
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
}
|
||||
@@ -325,7 +324,7 @@ func TestV6_FindMACbyIP(t *testing.T) {
|
||||
anotherMAC := net.HardwareAddr{0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB}
|
||||
|
||||
s := &v6Server{
|
||||
leases: []*dhcpsvc.Lease{{
|
||||
leases: []*Lease{{
|
||||
Hostname: staticName,
|
||||
HWAddr: staticMAC,
|
||||
IP: staticIP,
|
||||
@@ -338,7 +337,7 @@ func TestV6_FindMACbyIP(t *testing.T) {
|
||||
}},
|
||||
}
|
||||
|
||||
s.leases = []*dhcpsvc.Lease{{
|
||||
s.leases = []*Lease{{
|
||||
Hostname: staticName,
|
||||
HWAddr: staticMAC,
|
||||
IP: staticIP,
|
||||
|
||||
@@ -43,7 +43,7 @@ func (conf *Config) Validate() (err error) {
|
||||
case !conf.Enabled:
|
||||
return nil
|
||||
case conf.ICMPTimeout < 0:
|
||||
return newMustErr("icmp timeout", "be non-negative", conf.ICMPTimeout)
|
||||
return fmt.Errorf("icmp timeout %s must be non-negative", conf.ICMPTimeout)
|
||||
}
|
||||
|
||||
err = netutil.ValidateDomainName(conf.LocalDomainName)
|
||||
@@ -68,9 +68,9 @@ func (conf *Config) Validate() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// newMustErr returns an error that indicates that valName must be as must
|
||||
// mustBeErr returns an error that indicates that valName must be as must
|
||||
// describes.
|
||||
func newMustErr(valName, must string, val fmt.Stringer) (err error) {
|
||||
func mustBeErr(valName, must string, val fmt.Stringer) (err error) {
|
||||
return fmt.Errorf("%s %s must %s", valName, val, must)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// Lease is a DHCP lease.
|
||||
//
|
||||
// TODO(e.burkov): Consider moving it to [agh], since it also may be needed in
|
||||
// [websvc].
|
||||
// TODO(e.burkov): Consider it to [agh], since it also may be needed in
|
||||
// [websvc]. Also think of implementing iterating methods with appropriate
|
||||
// signatures.
|
||||
type Lease struct {
|
||||
// IP is the IP address leased to the client.
|
||||
IP netip.Addr
|
||||
@@ -34,21 +34,6 @@ type Lease struct {
|
||||
IsStatic bool
|
||||
}
|
||||
|
||||
// Clone returns a deep copy of l.
|
||||
func (l *Lease) Clone() (clone *Lease) {
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Lease{
|
||||
Expiry: l.Expiry,
|
||||
Hostname: l.Hostname,
|
||||
HWAddr: slices.Clone(l.HWAddr),
|
||||
IP: l.IP,
|
||||
IsStatic: l.IsStatic,
|
||||
}
|
||||
}
|
||||
|
||||
type Interface interface {
|
||||
agh.ServiceWithConfig[*Config]
|
||||
|
||||
@@ -72,9 +57,6 @@ type Interface interface {
|
||||
IPByHost(host string) (ip netip.Addr)
|
||||
|
||||
// Leases returns all the active DHCP leases.
|
||||
//
|
||||
// TODO(e.burkov): Consider implementing iterating methods with appropriate
|
||||
// signatures instead of cloning the whole list.
|
||||
Leases() (ls []*Lease)
|
||||
|
||||
// AddLease adds a new DHCP lease. It returns an error if the lease is
|
||||
@@ -109,9 +91,6 @@ func (Empty) Shutdown(_ context.Context) (err error) { return nil }
|
||||
// Config implements the [ServiceWithConfig] interface for Empty.
|
||||
func (Empty) Config() (conf *Config) { return nil }
|
||||
|
||||
// type check
|
||||
var _ Interface = Empty{}
|
||||
|
||||
// Enabled implements the [Interface] interface for Empty.
|
||||
func (Empty) Enabled() (ok bool) { return false }
|
||||
|
||||
@@ -124,6 +103,9 @@ func (Empty) MACByIP(_ netip.Addr) (mac net.HardwareAddr) { return nil }
|
||||
// IPByHost implements the [Interface] interface for Empty.
|
||||
func (Empty) IPByHost(_ string) (ip netip.Addr) { return netip.Addr{} }
|
||||
|
||||
// type check
|
||||
var _ Interface = Empty{}
|
||||
|
||||
// Leases implements the [Interface] interface for Empty.
|
||||
func (Empty) Leases() (leases []*Lease) { return nil }
|
||||
|
||||
|
||||
@@ -25,9 +25,6 @@ type DHCPServer struct {
|
||||
// interfaces6 is the set of IPv6 interfaces sorted by interface name.
|
||||
interfaces6 []*iface6
|
||||
|
||||
// leases is the set of active DHCP leases.
|
||||
leases []*Lease
|
||||
|
||||
// icmpTimeout is the timeout for checking another DHCP server's presence.
|
||||
icmpTimeout time.Duration
|
||||
}
|
||||
@@ -78,23 +75,3 @@ func New(conf *Config) (srv *DHCPServer, err error) {
|
||||
icmpTimeout: conf.ICMPTimeout,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// type check
|
||||
//
|
||||
// TODO(e.burkov): Uncomment when the [Interface] interface is implemented.
|
||||
// var _ Interface = (*DHCPServer)(nil)
|
||||
|
||||
// Enabled implements the [Interface] interface for *DHCPServer.
|
||||
func (srv *DHCPServer) Enabled() (ok bool) {
|
||||
return srv.enabled.Load()
|
||||
}
|
||||
|
||||
// Leases implements the [Interface] interface for *DHCPServer.
|
||||
func (srv *DHCPServer) Leases() (leases []*Lease) {
|
||||
leases = make([]*Lease, 0, len(srv.leases))
|
||||
for _, lease := range srv.leases {
|
||||
leases = append(leases, lease.Clone())
|
||||
}
|
||||
|
||||
return leases
|
||||
}
|
||||
|
||||
@@ -45,15 +45,15 @@ func (conf *IPv4Config) validate() (err error) {
|
||||
case !conf.Enabled:
|
||||
return nil
|
||||
case !conf.GatewayIP.Is4():
|
||||
return newMustErr("gateway ip", "be a valid ipv4", conf.GatewayIP)
|
||||
return mustBeErr("gateway ip", "be a valid ipv4", conf.GatewayIP)
|
||||
case !conf.SubnetMask.Is4():
|
||||
return newMustErr("subnet mask", "be a valid ipv4 cidr mask", conf.SubnetMask)
|
||||
return mustBeErr("subnet mask", "be a valid ipv4 cidr mask", conf.SubnetMask)
|
||||
case !conf.RangeStart.Is4():
|
||||
return newMustErr("range start", "be a valid ipv4", conf.RangeStart)
|
||||
return mustBeErr("range start", "be a valid ipv4", conf.RangeStart)
|
||||
case !conf.RangeEnd.Is4():
|
||||
return newMustErr("range end", "be a valid ipv4", conf.RangeEnd)
|
||||
return mustBeErr("range end", "be a valid ipv4", conf.RangeEnd)
|
||||
case conf.LeaseDuration <= 0:
|
||||
return newMustErr("lease duration", "be less than %d", conf.LeaseDuration)
|
||||
return mustBeErr("lease duration", "be less than %d", conf.LeaseDuration)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -27,19 +27,6 @@ import (
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// ClientsContainer provides information about preconfigured DNS clients.
|
||||
type ClientsContainer interface {
|
||||
// UpstreamConfigByID returns the custom upstream configuration for the
|
||||
// client having id, using boot to initialize the one if necessary. It
|
||||
// returns nil if there is no custom upstream configuration for the client.
|
||||
// The id is expected to be either a string representation of an IP address
|
||||
// or the ClientID.
|
||||
UpstreamConfigByID(
|
||||
id string,
|
||||
boot upstream.Resolver,
|
||||
) (conf *proxy.CustomUpstreamConfig, err error)
|
||||
}
|
||||
|
||||
// Config represents the DNS filtering configuration of AdGuard Home. The zero
|
||||
// Config is empty and ready for use.
|
||||
type Config struct {
|
||||
@@ -48,9 +35,10 @@ type Config struct {
|
||||
// FilterHandler is an optional additional filtering callback.
|
||||
FilterHandler func(cliAddr netip.Addr, clientID string, settings *filtering.Settings) `yaml:"-"`
|
||||
|
||||
// ClientsContainer stores the information about special handling of some
|
||||
// DNS clients.
|
||||
ClientsContainer ClientsContainer `yaml:"-"`
|
||||
// GetCustomUpstreamByClient is a callback that returns upstreams
|
||||
// configuration based on the client IP address or ClientID. It returns
|
||||
// nil if there are no custom upstreams for the client.
|
||||
GetCustomUpstreamByClient func(id string) (conf *proxy.UpstreamConfig, err error) `yaml:"-"`
|
||||
|
||||
// Anti-DNS amplification
|
||||
|
||||
@@ -58,14 +46,6 @@ type Config struct {
|
||||
// (0 to disable).
|
||||
Ratelimit uint32 `yaml:"ratelimit"`
|
||||
|
||||
// RatelimitSubnetLenIPv4 is a subnet length for IPv4 addresses used for
|
||||
// rate limiting requests.
|
||||
RatelimitSubnetLenIPv4 int `yaml:"ratelimit_subnet_len_ipv4"`
|
||||
|
||||
// RatelimitSubnetLenIPv6 is a subnet length for IPv6 addresses used for
|
||||
// rate limiting requests.
|
||||
RatelimitSubnetLenIPv6 int `yaml:"ratelimit_subnet_len_ipv6"`
|
||||
|
||||
// RatelimitWhitelist is the list of whitelisted client IP addresses.
|
||||
RatelimitWhitelist []string `yaml:"ratelimit_whitelist"`
|
||||
|
||||
@@ -289,33 +269,30 @@ type ServerConfig struct {
|
||||
// UseHTTP3Upstreams defines if HTTP/3 is be allowed for DNS-over-HTTPS
|
||||
// upstreams.
|
||||
UseHTTP3Upstreams bool
|
||||
|
||||
// ServePlainDNS defines if plain DNS is allowed for incoming requests.
|
||||
ServePlainDNS bool
|
||||
}
|
||||
|
||||
// newProxyConfig creates and validates configuration for the main proxy.
|
||||
func (s *Server) newProxyConfig() (conf *proxy.Config, err error) {
|
||||
// createProxyConfig creates and validates configuration for the main proxy.
|
||||
func (s *Server) createProxyConfig() (conf proxy.Config, err error) {
|
||||
srvConf := s.conf
|
||||
conf = &proxy.Config{
|
||||
HTTP3: srvConf.ServeHTTP3,
|
||||
Ratelimit: int(srvConf.Ratelimit),
|
||||
RatelimitSubnetMaskIPv4: net.CIDRMask(srvConf.RatelimitSubnetLenIPv4, netutil.IPv4BitLen),
|
||||
RatelimitSubnetMaskIPv6: net.CIDRMask(srvConf.RatelimitSubnetLenIPv6, netutil.IPv6BitLen),
|
||||
RatelimitWhitelist: srvConf.RatelimitWhitelist,
|
||||
RefuseAny: srvConf.RefuseAny,
|
||||
TrustedProxies: srvConf.TrustedProxies,
|
||||
CacheMinTTL: srvConf.CacheMinTTL,
|
||||
CacheMaxTTL: srvConf.CacheMaxTTL,
|
||||
CacheOptimistic: srvConf.CacheOptimistic,
|
||||
UpstreamConfig: srvConf.UpstreamConfig,
|
||||
BeforeRequestHandler: s.beforeRequestHandler,
|
||||
RequestHandler: s.handleDNSRequest,
|
||||
HTTPSServerName: aghhttp.UserAgent(),
|
||||
EnableEDNSClientSubnet: srvConf.EDNSClientSubnet.Enabled,
|
||||
MaxGoroutines: int(srvConf.MaxGoroutines),
|
||||
UseDNS64: srvConf.UseDNS64,
|
||||
DNS64Prefs: srvConf.DNS64Prefixes,
|
||||
conf = proxy.Config{
|
||||
UDPListenAddr: srvConf.UDPListenAddrs,
|
||||
TCPListenAddr: srvConf.TCPListenAddrs,
|
||||
HTTP3: srvConf.ServeHTTP3,
|
||||
Ratelimit: int(srvConf.Ratelimit),
|
||||
RatelimitWhitelist: srvConf.RatelimitWhitelist,
|
||||
RefuseAny: srvConf.RefuseAny,
|
||||
TrustedProxies: srvConf.TrustedProxies,
|
||||
CacheMinTTL: srvConf.CacheMinTTL,
|
||||
CacheMaxTTL: srvConf.CacheMaxTTL,
|
||||
CacheOptimistic: srvConf.CacheOptimistic,
|
||||
UpstreamConfig: srvConf.UpstreamConfig,
|
||||
BeforeRequestHandler: s.beforeRequestHandler,
|
||||
RequestHandler: s.handleDNSRequest,
|
||||
HTTPSServerName: aghhttp.UserAgent(),
|
||||
EnableEDNSClientSubnet: srvConf.EDNSClientSubnet.Enabled,
|
||||
MaxGoroutines: int(srvConf.MaxGoroutines),
|
||||
UseDNS64: srvConf.UseDNS64,
|
||||
DNS64Prefs: srvConf.DNS64Prefixes,
|
||||
}
|
||||
|
||||
if srvConf.EDNSClientSubnet.UseCustom {
|
||||
@@ -329,25 +306,27 @@ func (s *Server) newProxyConfig() (conf *proxy.Config, err error) {
|
||||
}
|
||||
|
||||
setProxyUpstreamMode(
|
||||
conf,
|
||||
&conf,
|
||||
srvConf.AllServers,
|
||||
srvConf.FastestAddr,
|
||||
srvConf.FastestTimeout.Duration,
|
||||
)
|
||||
|
||||
conf.BogusNXDomain, err = parseBogusNXDOMAIN(srvConf.BogusNXDomain)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("bogus_nxdomain: %w", err)
|
||||
for i, s := range srvConf.BogusNXDomain {
|
||||
var subnet *net.IPNet
|
||||
subnet, err = netutil.ParseSubnet(s)
|
||||
if err != nil {
|
||||
log.Error("subnet at index %d: %s", i, err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
conf.BogusNXDomain = append(conf.BogusNXDomain, subnet)
|
||||
}
|
||||
|
||||
err = s.prepareTLS(conf)
|
||||
err = s.prepareTLS(&conf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("validating tls: %w", err)
|
||||
}
|
||||
|
||||
err = s.preparePlain(conf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("validating plain: %w", err)
|
||||
return proxy.Config{}, fmt.Errorf("validating tls: %w", err)
|
||||
}
|
||||
|
||||
if c := srvConf.DNSCryptConfig; c.Enabled {
|
||||
@@ -358,27 +337,12 @@ func (s *Server) newProxyConfig() (conf *proxy.Config, err error) {
|
||||
}
|
||||
|
||||
if conf.UpstreamConfig == nil || len(conf.UpstreamConfig.Upstreams) == 0 {
|
||||
return nil, errors.Error("no default upstream servers configured")
|
||||
return proxy.Config{}, errors.Error("no default upstream servers configured")
|
||||
}
|
||||
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
// parseBogusNXDOMAIN parses the bogus NXDOMAIN strings into valid subnets.
|
||||
func parseBogusNXDOMAIN(confBogusNXDOMAIN []string) (subnets []netip.Prefix, err error) {
|
||||
for i, s := range confBogusNXDOMAIN {
|
||||
var subnet netip.Prefix
|
||||
subnet, err = aghnet.ParseSubnet(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("subnet at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
subnets = append(subnets, subnet)
|
||||
}
|
||||
|
||||
return subnets, nil
|
||||
}
|
||||
|
||||
const defaultBlockedResponseTTL = 3600
|
||||
|
||||
// initDefaultSettings initializes default settings if nothing
|
||||
@@ -449,7 +413,10 @@ func collectListenAddr(
|
||||
|
||||
// collectDNSAddrs returns configured set of listening addresses. It also
|
||||
// returns a set of ports of each unspecified listening address.
|
||||
func (conf *ServerConfig) collectDNSAddrs() (addrs mapAddrPortSet, unspecPorts map[uint16]unit) {
|
||||
func (conf *ServerConfig) collectDNSAddrs() (
|
||||
addrs map[netip.AddrPort]unit,
|
||||
unspecPorts map[uint16]unit,
|
||||
) {
|
||||
// TODO(e.burkov): Perhaps, we shouldn't allocate as much memory, since the
|
||||
// TCP and UDP listening addresses are currently the same.
|
||||
addrs = make(map[netip.AddrPort]unit, len(conf.TCPListenAddrs)+len(conf.UDPListenAddrs))
|
||||
@@ -469,64 +436,20 @@ func (conf *ServerConfig) collectDNSAddrs() (addrs mapAddrPortSet, unspecPorts m
|
||||
// defaultPlainDNSPort is the default port for plain DNS.
|
||||
const defaultPlainDNSPort uint16 = 53
|
||||
|
||||
// addrPortSet is a set of [netip.AddrPort] values.
|
||||
type addrPortSet interface {
|
||||
// Has returns true if addrPort is in the set.
|
||||
Has(addrPort netip.AddrPort) (ok bool)
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ addrPortSet = emptyAddrPortSet{}
|
||||
|
||||
// emptyAddrPortSet is the [addrPortSet] containing no values.
|
||||
type emptyAddrPortSet struct{}
|
||||
|
||||
// Has implements the [addrPortSet] interface for [emptyAddrPortSet].
|
||||
func (emptyAddrPortSet) Has(_ netip.AddrPort) (ok bool) { return false }
|
||||
|
||||
// mapAddrPortSet is the [addrPortSet] containing values of [netip.AddrPort] as
|
||||
// keys of a map.
|
||||
type mapAddrPortSet map[netip.AddrPort]unit
|
||||
|
||||
// type check
|
||||
var _ addrPortSet = mapAddrPortSet{}
|
||||
|
||||
// Has implements the [addrPortSet] interface for [mapAddrPortSet].
|
||||
func (m mapAddrPortSet) Has(addrPort netip.AddrPort) (ok bool) {
|
||||
_, ok = m[addrPort]
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
// combinedAddrPortSet is the [addrPortSet] defined by some IP addresses along
|
||||
// with ports, any combination of which is considered being in the set.
|
||||
type combinedAddrPortSet struct {
|
||||
// TODO(e.burkov): Use sorted slices in combination with binary search.
|
||||
ports map[uint16]unit
|
||||
addrs []netip.Addr
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ addrPortSet = (*combinedAddrPortSet)(nil)
|
||||
|
||||
// Has implements the [addrPortSet] interface for [*combinedAddrPortSet].
|
||||
func (m *combinedAddrPortSet) Has(addrPort netip.AddrPort) (ok bool) {
|
||||
_, ok = m.ports[addrPort.Port()]
|
||||
|
||||
return ok && slices.Contains(m.addrs, addrPort.Addr())
|
||||
}
|
||||
// addrPortMatcher is a function that matches an IP address with port.
|
||||
type addrPortMatcher func(addr netip.AddrPort) (ok bool)
|
||||
|
||||
// filterOut filters out all the upstreams that match um. It returns all the
|
||||
// closing errors joined.
|
||||
func filterOutAddrs(upsConf *proxy.UpstreamConfig, set addrPortSet) (err error) {
|
||||
func (m addrPortMatcher) filterOut(upsConf *proxy.UpstreamConfig) (err error) {
|
||||
var errs []error
|
||||
delFunc := func(u upstream.Upstream) (ok bool) {
|
||||
// TODO(e.burkov): We should probably consider the protocol of u to
|
||||
// only filter out the listening addresses of the same protocol.
|
||||
addr, parseErr := aghnet.ParseAddrPort(u.Address(), defaultPlainDNSPort)
|
||||
if parseErr != nil || !set.Has(addr) {
|
||||
if parseErr != nil || !m(addr) {
|
||||
// Don't filter out the upstream if it either cannot be parsed, or
|
||||
// does not match m.
|
||||
// does not match um.
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -546,20 +469,26 @@ func filterOutAddrs(upsConf *proxy.UpstreamConfig, set addrPortSet) (err error)
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
// ourAddrsSet returns an addrPortSet that contains all the configured listening
|
||||
// ourAddrsMatcher returns a matcher that matches all the configured listening
|
||||
// addresses.
|
||||
func (conf *ServerConfig) ourAddrsSet() (m addrPortSet, err error) {
|
||||
func (conf *ServerConfig) ourAddrsMatcher() (m addrPortMatcher, err error) {
|
||||
addrs, unspecPorts := conf.collectDNSAddrs()
|
||||
switch {
|
||||
case len(addrs) == 0:
|
||||
if len(addrs) == 0 {
|
||||
log.Debug("dnsforward: no listen addresses")
|
||||
|
||||
return emptyAddrPortSet{}, nil
|
||||
case len(unspecPorts) == 0:
|
||||
// Match no addresses.
|
||||
return func(_ netip.AddrPort) (ok bool) { return false }, nil
|
||||
}
|
||||
|
||||
if len(unspecPorts) == 0 {
|
||||
log.Debug("dnsforward: filtering out addresses %s", addrs)
|
||||
|
||||
return addrs, nil
|
||||
default:
|
||||
m = func(a netip.AddrPort) (ok bool) {
|
||||
_, ok = addrs[a]
|
||||
|
||||
return ok
|
||||
}
|
||||
} else {
|
||||
var ifaceAddrs []netip.Addr
|
||||
ifaceAddrs, err = aghnet.CollectAllIfacesAddrs()
|
||||
if err != nil {
|
||||
@@ -569,11 +498,16 @@ func (conf *ServerConfig) ourAddrsSet() (m addrPortSet, err error) {
|
||||
|
||||
log.Debug("dnsforward: filtering out addresses %s on ports %d", ifaceAddrs, unspecPorts)
|
||||
|
||||
return &combinedAddrPortSet{
|
||||
ports: unspecPorts,
|
||||
addrs: ifaceAddrs,
|
||||
}, nil
|
||||
m = func(a netip.AddrPort) (ok bool) {
|
||||
if _, ok = unspecPorts[a.Port()]; ok {
|
||||
return slices.Contains(ifaceAddrs, a.Addr())
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// prepareTLS - prepares TLS configuration for the DNS proxy
|
||||
@@ -630,7 +564,7 @@ func (s *Server) prepareTLS(proxyConfig *proxy.Config) (err error) {
|
||||
|
||||
// isWildcard returns true if host is a wildcard hostname.
|
||||
func isWildcard(host string) (ok bool) {
|
||||
return strings.HasPrefix(host, "*.")
|
||||
return len(host) >= 2 && host[0] == '*' && host[1] == '.'
|
||||
}
|
||||
|
||||
// matchesDomainWildcard returns true if host matches the domain wildcard
|
||||
@@ -670,31 +604,6 @@ func (s *Server) onGetCertificate(ch *tls.ClientHelloInfo) (*tls.Certificate, er
|
||||
return &s.conf.cert, nil
|
||||
}
|
||||
|
||||
// preparePlain prepares the plain-DNS configuration for the DNS proxy.
|
||||
// preparePlain assumes that prepareTLS has already been called.
|
||||
func (s *Server) preparePlain(proxyConf *proxy.Config) (err error) {
|
||||
if s.conf.ServePlainDNS {
|
||||
proxyConf.UDPListenAddr = s.conf.UDPListenAddrs
|
||||
proxyConf.TCPListenAddr = s.conf.TCPListenAddrs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
lenEncrypted := len(proxyConf.DNSCryptTCPListenAddr) +
|
||||
len(proxyConf.DNSCryptUDPListenAddr) +
|
||||
len(proxyConf.HTTPSListenAddr) +
|
||||
len(proxyConf.QUICListenAddr) +
|
||||
len(proxyConf.TLSListenAddr)
|
||||
if lenEncrypted == 0 {
|
||||
// TODO(a.garipov): Support full disabling of all DNS.
|
||||
return errors.Error("disabling plain dns requires at least one encrypted protocol")
|
||||
}
|
||||
|
||||
log.Info("dnsforward: warning: plain dns is disabled")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdatedProtectionStatus updates protection state, if the protection was
|
||||
// disabled temporarily. Returns the updated state of protection.
|
||||
func (s *Server) UpdatedProtectionStatus() (enabled bool, disabledUntil *time.Time) {
|
||||
|
||||
@@ -292,7 +292,6 @@ func TestServer_HandleDNSRequest_dns64(t *testing.T) {
|
||||
Config: Config{
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}, localUps)
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
||||
@@ -3,7 +3,6 @@ package dnsforward
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
@@ -109,7 +108,7 @@ type Server struct {
|
||||
// stats is the statistics collector for client's DNS usage data.
|
||||
stats stats.Interface
|
||||
|
||||
// access drops disallowed clients.
|
||||
// access drops unallowed clients.
|
||||
access *accessManager
|
||||
|
||||
// localDomainSuffix is the suffix used to detect internal hosts. It
|
||||
@@ -136,21 +135,8 @@ type Server struct {
|
||||
// PTR resolving.
|
||||
sysResolvers SystemResolvers
|
||||
|
||||
// etcHosts contains the data from the system's hosts files.
|
||||
etcHosts upstream.Resolver
|
||||
|
||||
// bootstrap is the resolver for upstreams' hostnames.
|
||||
bootstrap upstream.Resolver
|
||||
|
||||
// bootResolvers are the resolvers that should be used for
|
||||
// bootstrapping along with [etcHosts].
|
||||
//
|
||||
// TODO(e.burkov): Use [proxy.UpstreamConfig] when it will implement the
|
||||
// [upstream.Resolver] interface.
|
||||
bootResolvers []*upstream.UpstreamResolver
|
||||
|
||||
// recDetector is a cache for recursive requests. It is used to detect and
|
||||
// prevent recursive requests only for private upstreams.
|
||||
// recDetector is a cache for recursive requests. It is used to detect
|
||||
// and prevent recursive requests only for private upstreams.
|
||||
//
|
||||
// See https://github.com/adguardTeam/adGuardHome/issues/3185#issuecomment-851048135.
|
||||
recDetector *recursionDetector
|
||||
@@ -167,8 +153,8 @@ type Server struct {
|
||||
// during the BeforeRequestHandler stage.
|
||||
clientIDCache cache.Cache
|
||||
|
||||
// internalProxy resolves internal requests from the application itself. It
|
||||
// isn't started and so no listen ports are required.
|
||||
// DNS proxy instance for internal usage
|
||||
// We don't Start() it and so no listen port is required.
|
||||
internalProxy *proxy.Proxy
|
||||
|
||||
// isRunning is true if the DNS server is running.
|
||||
@@ -199,7 +185,6 @@ type DNSCreateParams struct {
|
||||
DHCPServer DHCP
|
||||
PrivateNets netutil.SubnetSet
|
||||
Anonymizer *aghnet.IPMut
|
||||
EtcHosts *aghnet.HostsContainer
|
||||
LocalDomain string
|
||||
}
|
||||
|
||||
@@ -232,25 +217,19 @@ func NewServer(p DNSCreateParams) (s *Server, err error) {
|
||||
if p.Anonymizer == nil {
|
||||
p.Anonymizer = aghnet.NewIPMut(nil)
|
||||
}
|
||||
|
||||
s = &Server{
|
||||
dnsFilter: p.DNSFilter,
|
||||
dhcpServer: p.DHCPServer,
|
||||
stats: p.Stats,
|
||||
queryLog: p.QueryLog,
|
||||
privateNets: p.PrivateNets,
|
||||
// TODO(e.burkov): Use some case-insensitive string comparison.
|
||||
localDomainSuffix: strings.ToLower(localDomainSuffix),
|
||||
etcHosts: p.EtcHosts,
|
||||
recDetector: newRecursionDetector(recursionTTL, cachedRecurrentReqNum),
|
||||
clientIDCache: cache.New(cache.Config{
|
||||
EnableLRU: true,
|
||||
MaxCount: defaultClientIDCacheCount,
|
||||
}),
|
||||
anonymizer: p.Anonymizer,
|
||||
conf: ServerConfig{
|
||||
ServePlainDNS: true,
|
||||
},
|
||||
}
|
||||
|
||||
s.sysResolvers, err = sysresolv.NewSystemResolvers(nil, defaultPlainDNSPort)
|
||||
@@ -258,6 +237,8 @@ func NewServer(p DNSCreateParams) (s *Server, err error) {
|
||||
return nil, fmt.Errorf("initializing system resolvers: %w", err)
|
||||
}
|
||||
|
||||
s.dhcpServer = p.DHCPServer
|
||||
|
||||
if runtime.GOARCH == "mips" || runtime.GOARCH == "mipsle" {
|
||||
// Use plain DNS on MIPS, encryption is too slow
|
||||
defaultDNS = defaultBootstrap
|
||||
@@ -373,8 +354,9 @@ func (s *Server) Exchange(ip netip.Addr) (host string, ttl time.Duration, err er
|
||||
}
|
||||
|
||||
dctx := &proxy.DNSContext{
|
||||
Proto: "udp",
|
||||
Req: req,
|
||||
Proto: "udp",
|
||||
Req: req,
|
||||
StartTime: time.Now(),
|
||||
}
|
||||
|
||||
var resolver *proxy.Proxy
|
||||
@@ -440,7 +422,7 @@ func hostFromPTR(resp *dns.Msg) (host string, ttl time.Duration, err error) {
|
||||
return "", 0, ErrRDNSNoData
|
||||
}
|
||||
|
||||
// Start starts the DNS server. It must only be called after [Server.Prepare].
|
||||
// Start starts the DNS server.
|
||||
func (s *Server) Start() error {
|
||||
s.serverLock.Lock()
|
||||
defer s.serverLock.Unlock()
|
||||
@@ -448,14 +430,12 @@ func (s *Server) Start() error {
|
||||
return s.startLocked()
|
||||
}
|
||||
|
||||
// startLocked starts the DNS server without locking. s.serverLock is expected
|
||||
// to be locked.
|
||||
// startLocked starts the DNS server without locking. For internal use only.
|
||||
func (s *Server) startLocked() error {
|
||||
err := s.dnsProxy.Start()
|
||||
if err == nil {
|
||||
s.isRunning = true
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -464,31 +444,34 @@ func (s *Server) startLocked() error {
|
||||
// faster than ordinary upstreams.
|
||||
const defaultLocalTimeout = 1 * time.Second
|
||||
|
||||
// setupLocalResolvers initializes the resolvers for local addresses. It
|
||||
// assumes s.serverLock is locked or the Server not running.
|
||||
func (s *Server) setupLocalResolvers(boot upstream.Resolver) (err error) {
|
||||
set, err := s.conf.ourAddrsSet()
|
||||
// setupLocalResolvers initializes the resolvers for local addresses. For
|
||||
// internal use only.
|
||||
func (s *Server) setupLocalResolvers() (err error) {
|
||||
matcher, err := s.conf.ourAddrsMatcher()
|
||||
if err != nil {
|
||||
// Don't wrap the error because it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
bootstraps := s.conf.BootstrapDNS
|
||||
resolvers := s.conf.LocalPTRResolvers
|
||||
confNeedsFiltering := len(resolvers) > 0
|
||||
if confNeedsFiltering {
|
||||
resolvers = stringutil.FilterOut(resolvers, IsCommentOrEmpty)
|
||||
} else {
|
||||
sysResolvers := slices.DeleteFunc(slices.Clone(s.sysResolvers.Addrs()), set.Has)
|
||||
filterConfig := false
|
||||
|
||||
if len(resolvers) == 0 {
|
||||
sysResolvers := slices.DeleteFunc(s.sysResolvers.Addrs(), matcher)
|
||||
resolvers = make([]string, 0, len(sysResolvers))
|
||||
for _, r := range sysResolvers {
|
||||
resolvers = append(resolvers, r.String())
|
||||
}
|
||||
} else {
|
||||
resolvers = stringutil.FilterOut(resolvers, IsCommentOrEmpty)
|
||||
filterConfig = true
|
||||
}
|
||||
|
||||
log.Debug("dnsforward: upstreams to resolve ptr for local addresses: %v", resolvers)
|
||||
|
||||
uc, err := s.prepareUpstreamConfig(resolvers, nil, &upstream.Options{
|
||||
Bootstrap: boot,
|
||||
Bootstrap: bootstraps,
|
||||
Timeout: defaultLocalTimeout,
|
||||
// TODO(e.burkov): Should we verify server's certificates?
|
||||
PreferIPv6: s.conf.BootstrapPreferIPv6,
|
||||
@@ -497,9 +480,8 @@ func (s *Server) setupLocalResolvers(boot upstream.Resolver) (err error) {
|
||||
return fmt.Errorf("preparing private upstreams: %w", err)
|
||||
}
|
||||
|
||||
if confNeedsFiltering {
|
||||
err = filterOutAddrs(uc, set)
|
||||
if err != nil {
|
||||
if filterConfig {
|
||||
if err = matcher.filterOut(uc); err != nil {
|
||||
return fmt.Errorf("filtering private upstreams: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -510,7 +492,6 @@ func (s *Server) setupLocalResolvers(boot upstream.Resolver) (err error) {
|
||||
},
|
||||
}
|
||||
|
||||
// TODO(e.burkov): Should we also consider the DNS64 usage?
|
||||
if s.conf.UsePrivateRDNS &&
|
||||
// Only set the upstream config if there are any upstreams. It's safe
|
||||
// to put nil into [proxy.Config.PrivateRDNSUpstreamConfig].
|
||||
@@ -537,19 +518,31 @@ func (s *Server) Prepare(conf *ServerConfig) (err error) {
|
||||
|
||||
s.initDefaultSettings()
|
||||
|
||||
boot, err := s.prepareInternalDNS()
|
||||
err = s.prepareIpsetListSettings()
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return fmt.Errorf("preparing ipset settings: %w", err)
|
||||
}
|
||||
|
||||
err = s.prepareUpstreamSettings()
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
proxyConfig, err := s.newProxyConfig()
|
||||
var proxyConfig proxy.Config
|
||||
proxyConfig, err = s.createProxyConfig()
|
||||
if err != nil {
|
||||
return fmt.Errorf("preparing proxy: %w", err)
|
||||
}
|
||||
|
||||
s.setupDNS64()
|
||||
|
||||
err = s.prepareInternalProxy()
|
||||
if err != nil {
|
||||
return fmt.Errorf("preparing internal proxy: %w", err)
|
||||
}
|
||||
|
||||
s.access, err = newAccessCtx(
|
||||
s.conf.AllowedClients,
|
||||
s.conf.DisallowedClients,
|
||||
@@ -562,9 +555,9 @@ func (s *Server) Prepare(conf *ServerConfig) (err error) {
|
||||
// Set the proxy here because [setupLocalResolvers] sets its values.
|
||||
//
|
||||
// TODO(e.burkov): Remove once the local resolvers logic moved to dnsproxy.
|
||||
s.dnsProxy = &proxy.Proxy{Config: *proxyConfig}
|
||||
s.dnsProxy = &proxy.Proxy{Config: proxyConfig}
|
||||
|
||||
err = s.setupLocalResolvers(boot)
|
||||
err = s.setupLocalResolvers()
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting up resolvers: %w", err)
|
||||
}
|
||||
@@ -583,38 +576,6 @@ func (s *Server) Prepare(conf *ServerConfig) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// prepareInternalDNS initializes the internal state of s before initializing
|
||||
// the primary DNS proxy instance. It assumes s.serverLock is locked or the
|
||||
// Server not running.
|
||||
func (s *Server) prepareInternalDNS() (boot upstream.Resolver, err error) {
|
||||
err = s.prepareIpsetListSettings()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("preparing ipset settings: %w", err)
|
||||
}
|
||||
|
||||
s.bootstrap, s.bootResolvers, err = s.createBootstrap(s.conf.BootstrapDNS, &upstream.Options{
|
||||
Timeout: DefaultTimeout,
|
||||
HTTPVersions: UpstreamHTTPVersions(s.conf.UseHTTP3Upstreams),
|
||||
})
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.prepareUpstreamSettings(boot)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return s.bootstrap, err
|
||||
}
|
||||
|
||||
err = s.prepareInternalProxy()
|
||||
if err != nil {
|
||||
return s.bootstrap, fmt.Errorf("preparing internal proxy: %w", err)
|
||||
}
|
||||
|
||||
return s.bootstrap, nil
|
||||
}
|
||||
|
||||
// setupFallbackDNS initializes the fallback DNS servers.
|
||||
func (s *Server) setupFallbackDNS() (err error) {
|
||||
fallbacks := s.conf.FallbackDNS
|
||||
@@ -638,8 +599,7 @@ func (s *Server) setupFallbackDNS() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupAddrProc initializes the address processor. It assumes s.serverLock is
|
||||
// locked or the Server not running.
|
||||
// setupAddrProc initializes the address processor. For internal use only.
|
||||
func (s *Server) setupAddrProc() {
|
||||
// TODO(a.garipov): This is a crutch for tests; remove.
|
||||
if s.conf.AddrProcConf == nil {
|
||||
@@ -728,8 +688,7 @@ func (s *Server) Stop() error {
|
||||
return s.stopLocked()
|
||||
}
|
||||
|
||||
// stopLocked stops the DNS server without locking. s.serverLock is expected to
|
||||
// be locked.
|
||||
// stopLocked stops the DNS server without locking. For internal use only.
|
||||
func (s *Server) stopLocked() (err error) {
|
||||
// TODO(e.burkov, a.garipov): Return critical errors, not just log them.
|
||||
// This will require filtering all the non-critical errors in
|
||||
@@ -742,11 +701,18 @@ func (s *Server) stopLocked() (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
logCloserErr(s.internalProxy.UpstreamConfig, "dnsforward: closing internal resolvers: %s")
|
||||
logCloserErr(s.localResolvers.UpstreamConfig, "dnsforward: closing local resolvers: %s")
|
||||
if upsConf := s.internalProxy.UpstreamConfig; upsConf != nil {
|
||||
err = upsConf.Close()
|
||||
if err != nil {
|
||||
log.Error("dnsforward: closing internal resolvers: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, b := range s.bootResolvers {
|
||||
logCloserErr(b, "dnsforward: closing bootstrap %s: %s", b.Address())
|
||||
if upsConf := s.localResolvers.UpstreamConfig; upsConf != nil {
|
||||
err = upsConf.Close()
|
||||
if err != nil {
|
||||
log.Error("dnsforward: closing local resolvers: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
s.isRunning = false
|
||||
@@ -754,18 +720,6 @@ func (s *Server) stopLocked() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// logCloserErr logs the error returned by c, if any.
|
||||
func logCloserErr(c io.Closer, format string, args ...any) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
err := c.Close()
|
||||
if err != nil {
|
||||
log.Error(format, append(args, err)...)
|
||||
}
|
||||
}
|
||||
|
||||
// IsRunning returns true if the DNS server is running.
|
||||
func (s *Server) IsRunning() bool {
|
||||
s.serverLock.RLock()
|
||||
|
||||
@@ -182,7 +182,6 @@ func createTestTLS(t *testing.T, tlsConf TLSConfig) (s *Server, certPem []byte)
|
||||
Config: Config{
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}, nil)
|
||||
|
||||
tlsConf.CertificateChainData, tlsConf.PrivateKeyData = certPem, keyPem
|
||||
@@ -310,7 +309,6 @@ func TestServer(t *testing.T) {
|
||||
Config: Config{
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}, nil)
|
||||
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()}
|
||||
startDeferStop(t, s)
|
||||
@@ -349,7 +347,6 @@ func TestServer_timeout(t *testing.T) {
|
||||
Config: Config{
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
|
||||
s, err := NewServer(DNSCreateParams{DNSFilter: createTestDNSFilter(t)})
|
||||
@@ -384,7 +381,6 @@ func TestServer_Prepare_fallbacks(t *testing.T) {
|
||||
},
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
|
||||
s, err := NewServer(DNSCreateParams{})
|
||||
@@ -406,7 +402,6 @@ func TestServerWithProtectionDisabled(t *testing.T) {
|
||||
Config: Config{
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}, nil)
|
||||
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()}
|
||||
startDeferStop(t, s)
|
||||
@@ -484,7 +479,6 @@ func TestServerRace(t *testing.T) {
|
||||
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
||||
},
|
||||
ConfigModified: func() {},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
s := createTestServer(t, filterConf, forwardConf, nil)
|
||||
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()}
|
||||
@@ -538,7 +532,6 @@ func TestSafeSearch(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
s := createTestServer(t, filterConf, forwardConf, nil)
|
||||
startDeferStop(t, s)
|
||||
@@ -601,7 +594,6 @@ func TestInvalidRequest(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}, nil)
|
||||
startDeferStop(t, s)
|
||||
|
||||
@@ -630,7 +622,6 @@ func TestBlockedRequest(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
s := createTestServer(t, &filtering.Config{
|
||||
ProtectionEnabled: true,
|
||||
@@ -653,71 +644,45 @@ func TestBlockedRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServerCustomClientUpstream(t *testing.T) {
|
||||
const defaultCacheSize = 1024 * 1024
|
||||
|
||||
var upsCalledCounter uint32
|
||||
|
||||
forwardConf := ServerConfig{
|
||||
UDPListenAddrs: []*net.UDPAddr{{}},
|
||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||
Config: Config{
|
||||
CacheSize: defaultCacheSize,
|
||||
EDNSClientSubnet: &EDNSClientSubnet{
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
s := createTestServer(t, &filtering.Config{
|
||||
BlockingMode: filtering.BlockingModeDefault,
|
||||
}, forwardConf, nil)
|
||||
s.conf.GetCustomUpstreamByClient = func(_ string) (conf *proxy.UpstreamConfig, err error) {
|
||||
ups := aghtest.NewUpstreamMock(func(req *dns.Msg) (resp *dns.Msg, err error) {
|
||||
return aghalg.Coalesce(
|
||||
aghtest.MatchedResponse(req, dns.TypeA, "host", "192.168.0.1"),
|
||||
new(dns.Msg).SetRcode(req, dns.RcodeNameError),
|
||||
), nil
|
||||
})
|
||||
|
||||
ups := aghtest.NewUpstreamMock(func(req *dns.Msg) (resp *dns.Msg, err error) {
|
||||
atomic.AddUint32(&upsCalledCounter, 1)
|
||||
|
||||
return aghalg.Coalesce(
|
||||
aghtest.MatchedResponse(req, dns.TypeA, "host", "192.168.0.1"),
|
||||
new(dns.Msg).SetRcode(req, dns.RcodeNameError),
|
||||
), nil
|
||||
})
|
||||
|
||||
customUpsConf := proxy.NewCustomUpstreamConfig(
|
||||
&proxy.UpstreamConfig{
|
||||
return &proxy.UpstreamConfig{
|
||||
Upstreams: []upstream.Upstream{ups},
|
||||
},
|
||||
true,
|
||||
defaultCacheSize,
|
||||
forwardConf.EDNSClientSubnet.Enabled,
|
||||
)
|
||||
|
||||
s.conf.ClientsContainer = &aghtest.ClientsContainer{
|
||||
OnUpstreamConfigByID: func(
|
||||
_ string,
|
||||
_ upstream.Resolver,
|
||||
) (conf *proxy.CustomUpstreamConfig, err error) {
|
||||
return customUpsConf, nil
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
startDeferStop(t, s)
|
||||
|
||||
addr := s.dnsProxy.Addr(proxy.ProtoUDP).String()
|
||||
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
||||
|
||||
// Send test request.
|
||||
req := createTestMessage("host.")
|
||||
|
||||
reply, err := dns.Exchange(req, addr)
|
||||
reply, err := dns.Exchange(req, addr.String())
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, reply.Answer)
|
||||
require.Len(t, reply.Answer, 1)
|
||||
|
||||
assert.Equal(t, dns.RcodeSuccess, reply.Rcode)
|
||||
assert.Equal(t, net.IP{192, 168, 0, 1}, reply.Answer[0].(*dns.A).A)
|
||||
assert.Equal(t, uint32(1), atomic.LoadUint32(&upsCalledCounter))
|
||||
require.NotEmpty(t, reply.Answer)
|
||||
|
||||
_, err = dns.Exchange(req, addr)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, uint32(1), atomic.LoadUint32(&upsCalledCounter))
|
||||
require.Len(t, reply.Answer, 1)
|
||||
assert.Equal(t, net.IP{192, 168, 0, 1}, reply.Answer[0].(*dns.A).A)
|
||||
}
|
||||
|
||||
// testCNAMEs is a map of names and CNAMEs necessary for the TestUpstream work.
|
||||
@@ -743,7 +708,6 @@ func TestBlockCNAMEProtectionEnabled(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}, nil)
|
||||
testUpstm := &aghtest.Upstream{
|
||||
CName: testCNAMEs,
|
||||
@@ -776,7 +740,6 @@ func TestBlockCNAME(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
s := createTestServer(t, &filtering.Config{
|
||||
ProtectionEnabled: true,
|
||||
@@ -851,7 +814,6 @@ func TestClientRulesForCNAMEMatching(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
s := createTestServer(t, &filtering.Config{
|
||||
BlockingMode: filtering.BlockingModeDefault,
|
||||
@@ -896,7 +858,6 @@ func TestNullBlockedRequest(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
s := createTestServer(t, &filtering.Config{
|
||||
ProtectionEnabled: true,
|
||||
@@ -962,7 +923,6 @@ func TestBlockedCustomIP(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
|
||||
// Invalid BlockingIPv4.
|
||||
@@ -1014,7 +974,6 @@ func TestBlockedByHosts(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
|
||||
s := createTestServer(t, &filtering.Config{
|
||||
@@ -1065,7 +1024,6 @@ func TestBlockedBySafeBrowsing(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
s := createTestServer(t, filterConf, forwardConf, nil)
|
||||
startDeferStop(t, s)
|
||||
@@ -1124,7 +1082,6 @@ func TestRewrite(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}))
|
||||
|
||||
ups := aghtest.NewUpstreamMock(func(req *dns.Msg) (resp *dns.Msg, err error) {
|
||||
|
||||
@@ -40,7 +40,6 @@ func TestServer_FilterDNSRewrite(t *testing.T) {
|
||||
Config: Config{
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}, nil)
|
||||
|
||||
makeQ := func(qtype rules.RRType) (req *dns.Msg) {
|
||||
|
||||
@@ -35,7 +35,6 @@ func TestHandleDNSRequest_handleDNSRequest(t *testing.T) {
|
||||
Enabled: false,
|
||||
},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
filters := []filtering.Filter{{
|
||||
ID: 0, Data: []byte(rules),
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
@@ -46,19 +46,8 @@ type jsonDNSConfig struct {
|
||||
// ProtectionEnabled defines if protection is enabled.
|
||||
ProtectionEnabled *bool `json:"protection_enabled"`
|
||||
|
||||
// Ratelimit is the number of requests per second allowed per client.
|
||||
Ratelimit *uint32 `json:"ratelimit"`
|
||||
|
||||
// RatelimitSubnetLenIPv4 is a subnet length for IPv4 addresses used for
|
||||
// rate limiting requests.
|
||||
RatelimitSubnetLenIPv4 *int `json:"ratelimit_subnet_len_ipv4"`
|
||||
|
||||
// RatelimitSubnetLenIPv6 is a subnet length for IPv6 addresses used for
|
||||
// rate limiting requests.
|
||||
RatelimitSubnetLenIPv6 *int `json:"ratelimit_subnet_len_ipv6"`
|
||||
|
||||
// RatelimitWhitelist is a list of IP addresses excluded from rate limiting.
|
||||
RatelimitWhitelist *[]string `json:"ratelimit_whitelist"`
|
||||
// RateLimit is the number of requests per second allowed per client.
|
||||
RateLimit *uint32 `json:"ratelimit"`
|
||||
|
||||
// BlockingMode defines the way blocked responses are constructed.
|
||||
BlockingMode *filtering.BlockingMode `json:"blocking_mode"`
|
||||
@@ -133,9 +122,6 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
|
||||
blockingMode, blockingIPv4, blockingIPv6 := s.dnsFilter.BlockingMode()
|
||||
blockedResponseTTL := s.dnsFilter.BlockedResponseTTL()
|
||||
ratelimit := s.conf.Ratelimit
|
||||
ratelimitSubnetLenIPv4 := s.conf.RatelimitSubnetLenIPv4
|
||||
ratelimitSubnetLenIPv6 := s.conf.RatelimitSubnetLenIPv6
|
||||
ratelimitWhitelist := stringutil.CloneSliceOrEmpty(s.conf.RatelimitWhitelist)
|
||||
|
||||
customIP := s.conf.EDNSClientSubnet.CustomIP
|
||||
enableEDNSClientSubnet := s.conf.EDNSClientSubnet.Enabled
|
||||
@@ -172,10 +158,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
|
||||
BlockingMode: &blockingMode,
|
||||
BlockingIPv4: blockingIPv4,
|
||||
BlockingIPv6: blockingIPv6,
|
||||
Ratelimit: &ratelimit,
|
||||
RatelimitSubnetLenIPv4: &ratelimitSubnetLenIPv4,
|
||||
RatelimitSubnetLenIPv6: &ratelimitSubnetLenIPv6,
|
||||
RatelimitWhitelist: &ratelimitWhitelist,
|
||||
RateLimit: &ratelimit,
|
||||
EDNSCSCustomIP: customIP,
|
||||
EDNSCSEnabled: &enableEDNSClientSubnet,
|
||||
EDNSCSUseCustom: &useCustom,
|
||||
@@ -198,13 +181,13 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
|
||||
// defaultLocalPTRUpstreams returns the list of default local PTR resolvers
|
||||
// filtered of AdGuard Home's own DNS server addresses. It may appear empty.
|
||||
func (s *Server) defaultLocalPTRUpstreams() (ups []string, err error) {
|
||||
matcher, err := s.conf.ourAddrsSet()
|
||||
matcher, err := s.conf.ourAddrsMatcher()
|
||||
if err != nil {
|
||||
// Don't wrap the error because it's informative enough as is.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sysResolvers := slices.DeleteFunc(s.sysResolvers.Addrs(), matcher.Has)
|
||||
sysResolvers := slices.DeleteFunc(s.sysResolvers.Addrs(), matcher)
|
||||
ups = make([]string, 0, len(sysResolvers))
|
||||
for _, r := range sysResolvers {
|
||||
ups = append(ups, r.String())
|
||||
@@ -219,7 +202,6 @@ func (s *Server) handleGetConfig(w http.ResponseWriter, r *http.Request) {
|
||||
aghhttp.WriteJSONResponseOK(w, r, resp)
|
||||
}
|
||||
|
||||
// checkBlockingMode returns an error if blocking mode is invalid.
|
||||
func (req *jsonDNSConfig) checkBlockingMode() (err error) {
|
||||
if req.BlockingMode == nil {
|
||||
return nil
|
||||
@@ -228,21 +210,12 @@ func (req *jsonDNSConfig) checkBlockingMode() (err error) {
|
||||
return validateBlockingMode(*req.BlockingMode, req.BlockingIPv4, req.BlockingIPv6)
|
||||
}
|
||||
|
||||
// checkUpstreamsMode returns an error if the upstream mode is invalid.
|
||||
func (req *jsonDNSConfig) checkUpstreamsMode() (err error) {
|
||||
if req.UpstreamMode == nil {
|
||||
return nil
|
||||
}
|
||||
func (req *jsonDNSConfig) checkUpstreamsMode() bool {
|
||||
valid := []string{"", "fastest_addr", "parallel"}
|
||||
|
||||
mode := *req.UpstreamMode
|
||||
if ok := slices.Contains([]string{"", "fastest_addr", "parallel"}, mode); !ok {
|
||||
return fmt.Errorf("upstream_mode: incorrect value %q", mode)
|
||||
}
|
||||
|
||||
return nil
|
||||
return req.UpstreamMode == nil || stringutil.InSlice(valid, *req.UpstreamMode)
|
||||
}
|
||||
|
||||
// checkBootstrap returns an error if any bootstrap address is invalid.
|
||||
func (req *jsonDNSConfig) checkBootstrap() (err error) {
|
||||
if req.Bootstraps == nil {
|
||||
return nil
|
||||
@@ -257,7 +230,6 @@ func (req *jsonDNSConfig) checkBootstrap() (err error) {
|
||||
}
|
||||
|
||||
if _, err = upstream.NewUpstreamResolver(b, nil); err != nil {
|
||||
// Don't wrap the error because it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -273,157 +245,67 @@ func (req *jsonDNSConfig) checkFallbacks() (err error) {
|
||||
|
||||
err = ValidateUpstreams(*req.Fallbacks)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fallback servers: %w", err)
|
||||
return fmt.Errorf("validating fallback servers: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validate returns an error if any field of req is invalid.
|
||||
//
|
||||
// TODO(s.chzhen): Parse, don't validate.
|
||||
func (req *jsonDNSConfig) validate(privateNets netutil.SubnetSet) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "validating dns config: %w") }()
|
||||
|
||||
err = req.validateUpstreamDNSServers(privateNets)
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
err = req.checkRatelimitSubnetMaskLen()
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
err = req.checkRatelimitWhitelist()
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
err = req.checkBlockingMode()
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
err = req.checkUpstreamsMode()
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
err = req.checkCacheTTL()
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateUpstreamDNSServers returns an error if any field of req is invalid.
|
||||
func (req *jsonDNSConfig) validateUpstreamDNSServers(privateNets netutil.SubnetSet) (err error) {
|
||||
if req.Upstreams != nil {
|
||||
err = ValidateUpstreams(*req.Upstreams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("upstream servers: %w", err)
|
||||
return fmt.Errorf("validating upstream servers: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if req.LocalPTRUpstreams != nil {
|
||||
err = ValidateUpstreamsPrivate(*req.LocalPTRUpstreams, privateNets)
|
||||
if err != nil {
|
||||
return fmt.Errorf("private upstream servers: %w", err)
|
||||
return fmt.Errorf("validating private upstream servers: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = req.checkBootstrap()
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
err = req.checkFallbacks()
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkCacheTTL returns an error if the configuration of the cache TTL is
|
||||
// invalid.
|
||||
func (req *jsonDNSConfig) checkCacheTTL() (err error) {
|
||||
if req.CacheMinTTL == nil && req.CacheMaxTTL == nil {
|
||||
return nil
|
||||
err = req.checkBlockingMode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var minTTL, maxTTL uint32
|
||||
switch {
|
||||
case !req.checkUpstreamsMode():
|
||||
return errors.Error("upstream_mode: incorrect value")
|
||||
case !req.checkCacheTTL():
|
||||
return errors.Error("cache_ttl_min must be less or equal than cache_ttl_max")
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (req *jsonDNSConfig) checkCacheTTL() bool {
|
||||
if req.CacheMinTTL == nil && req.CacheMaxTTL == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
var min, max uint32
|
||||
if req.CacheMinTTL != nil {
|
||||
minTTL = *req.CacheMinTTL
|
||||
min = *req.CacheMinTTL
|
||||
}
|
||||
if req.CacheMaxTTL != nil {
|
||||
maxTTL = *req.CacheMaxTTL
|
||||
max = *req.CacheMaxTTL
|
||||
}
|
||||
|
||||
if minTTL <= maxTTL {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.Error("cache_ttl_min must be less or equal than cache_ttl_max")
|
||||
}
|
||||
|
||||
// checkRatelimitSubnetMaskLen returns an error if the length of the subnet mask
|
||||
// for IPv4 or IPv6 addresses is invalid.
|
||||
func (req *jsonDNSConfig) checkRatelimitSubnetMaskLen() (err error) {
|
||||
err = checkInclusion(req.RatelimitSubnetLenIPv4, 0, netutil.IPv4BitLen)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ratelimit_subnet_len_ipv4 is invalid: %w", err)
|
||||
}
|
||||
|
||||
err = checkInclusion(req.RatelimitSubnetLenIPv6, 0, netutil.IPv6BitLen)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ratelimit_subnet_len_ipv6 is invalid: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkInclusion returns an error if a ptr is not nil and points to value,
|
||||
// that not in the inclusive range between minN and maxN.
|
||||
func checkInclusion(ptr *int, minN, maxN int) (err error) {
|
||||
if ptr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
n := *ptr
|
||||
switch {
|
||||
case n < minN:
|
||||
return fmt.Errorf("value %d less than min %d", n, minN)
|
||||
case n > maxN:
|
||||
return fmt.Errorf("value %d greater than max %d", n, maxN)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkRatelimitWhitelist returns an error if any of IP addresses is invalid.
|
||||
func (req *jsonDNSConfig) checkRatelimitWhitelist() (err error) {
|
||||
if req.RatelimitWhitelist == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i, ipStr := range *req.RatelimitWhitelist {
|
||||
if _, err = netip.ParseAddr(ipStr); err != nil {
|
||||
return fmt.Errorf("ratelimit whitelist: at index %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return min <= max
|
||||
}
|
||||
|
||||
// handleSetConfig handles requests to the POST /control/dns_config endpoint.
|
||||
@@ -520,9 +402,6 @@ func (s *Server) setConfigRestartable(dc *jsonDNSConfig) (shouldRestart bool) {
|
||||
setIfNotNil(&s.conf.CacheOptimistic, dc.CacheOptimistic),
|
||||
setIfNotNil(&s.conf.AddrProcConf.UseRDNS, dc.ResolveClients),
|
||||
setIfNotNil(&s.conf.UsePrivateRDNS, dc.UsePrivateRDNS),
|
||||
setIfNotNil(&s.conf.RatelimitSubnetLenIPv4, dc.RatelimitSubnetLenIPv4),
|
||||
setIfNotNil(&s.conf.RatelimitSubnetLenIPv6, dc.RatelimitSubnetLenIPv6),
|
||||
setIfNotNil(&s.conf.RatelimitWhitelist, dc.RatelimitWhitelist),
|
||||
} {
|
||||
shouldRestart = shouldRestart || hasSet
|
||||
if shouldRestart {
|
||||
@@ -530,8 +409,8 @@ func (s *Server) setConfigRestartable(dc *jsonDNSConfig) (shouldRestart bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if dc.Ratelimit != nil && s.conf.Ratelimit != *dc.Ratelimit {
|
||||
s.conf.Ratelimit = *dc.Ratelimit
|
||||
if dc.RateLimit != nil && s.conf.Ratelimit != *dc.RateLimit {
|
||||
s.conf.Ratelimit = *dc.RateLimit
|
||||
shouldRestart = true
|
||||
}
|
||||
|
||||
@@ -576,7 +455,7 @@ func newUpstreamConfig(upstreams []string) (conf *proxy.UpstreamConfig, err erro
|
||||
conf, err = proxy.ParseUpstreamsConfig(
|
||||
upstreams,
|
||||
&upstream.Options{
|
||||
Bootstrap: net.DefaultResolver,
|
||||
Bootstrap: []string{},
|
||||
Timeout: DefaultTimeout,
|
||||
},
|
||||
)
|
||||
@@ -605,7 +484,7 @@ func validateUpstreamConfig(conf []string) (err error) {
|
||||
}
|
||||
|
||||
for _, addr := range ups {
|
||||
_, err = validateUpstream(addr, domains)
|
||||
_, err = validateUpstream(addr, len(domains) > 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validating upstream %q: %w", addr, err)
|
||||
}
|
||||
@@ -674,14 +553,14 @@ var protocols = []string{
|
||||
}
|
||||
|
||||
// validateUpstream returns an error if u alongside with domains is not a valid
|
||||
// upstream configuration. useDefault is true if the upstream is
|
||||
// upstream configuration. usesDefault is true if the upstream is
|
||||
// domain-specific and is configured to point at the default upstream server
|
||||
// which is validated separately. The upstream is considered domain-specific
|
||||
// only if domains is at least not nil.
|
||||
func validateUpstream(u string, domains []string) (useDefault bool, err error) {
|
||||
// which is validated separately. specific reflects if the upstream is
|
||||
// domain-specific.
|
||||
func validateUpstream(u string, specific bool) (usesDefault bool, err error) {
|
||||
// The special server address '#' means that default server must be used.
|
||||
if useDefault = u == "#" && domains != nil; useDefault {
|
||||
return useDefault, nil
|
||||
if u == "#" && specific {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Check if the upstream has a valid protocol prefix.
|
||||
@@ -747,8 +626,9 @@ func separateUpstream(upstreamStr string) (upstreams, domains []string, err erro
|
||||
// properly.
|
||||
type healthCheckFunc func(u upstream.Upstream) (err error)
|
||||
|
||||
// checkDNSUpstreamExc checks if the DNS upstream exchanges correctly.
|
||||
func checkDNSUpstreamExc(u upstream.Upstream) (err error) {
|
||||
// checkExchange is a [healthCheckFunc] that checks if the DNS upstream
|
||||
// exchanges correctly.
|
||||
func checkExchange(u upstream.Upstream) (err error) {
|
||||
// testTLD is the special-use fully-qualified domain name for testing the
|
||||
// DNS server reachability.
|
||||
//
|
||||
@@ -778,11 +658,11 @@ func checkDNSUpstreamExc(u upstream.Upstream) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkPrivateUpstreamExc checks if the upstream for resolving private
|
||||
// addresses exchanges correctly.
|
||||
// checkPrivateExchange is a [healthCheckFunc] that checks if the upstream for
|
||||
// resolving private addresses exchanges correctly.
|
||||
//
|
||||
// TODO(e.burkov): Think about testing the ip6.arpa. as well.
|
||||
func checkPrivateUpstreamExc(u upstream.Upstream) (err error) {
|
||||
func checkPrivateExchange(u upstream.Upstream) (err error) {
|
||||
// inAddrArpaTLD is the special-use fully-qualified domain name for PTR IP
|
||||
// address resolution.
|
||||
//
|
||||
@@ -823,93 +703,149 @@ func (err domainSpecificTestError) Error() (msg string) {
|
||||
return fmt.Sprintf("WARNING: %s", err.error)
|
||||
}
|
||||
|
||||
// checkDNS parses line, creates DNS upstreams using opts, and checks if the
|
||||
// upstreams are exchanging correctly. It saves the result into a sync.Map
|
||||
// where key is an upstream address and value is "OK", if the upstream
|
||||
// exchanges correctly, or text of the error. It is intended to be used as a
|
||||
// goroutine.
|
||||
//
|
||||
// TODO(s.chzhen): Separate to a different structure/file.
|
||||
func (s *Server) checkDNS(
|
||||
line string,
|
||||
opts *upstream.Options,
|
||||
check healthCheckFunc,
|
||||
wg *sync.WaitGroup,
|
||||
m *sync.Map,
|
||||
) {
|
||||
defer wg.Done()
|
||||
defer log.OnPanic("dnsforward: checking upstreams")
|
||||
|
||||
upstreams, domains, err := separateUpstream(line)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("wrong upstream format: %w", err)
|
||||
m.Store(line, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
specific := len(domains) > 0
|
||||
|
||||
for _, upstreamAddr := range upstreams {
|
||||
var useDefault bool
|
||||
useDefault, err = validateUpstream(upstreamAddr, domains)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("wrong upstream format: %w", err)
|
||||
m.Store(upstreamAddr, err.Error())
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if useDefault {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debug("dnsforward: checking if upstream %q works", upstreamAddr)
|
||||
|
||||
err = s.checkUpstreamAddr(upstreamAddr, specific, opts, check)
|
||||
if err != nil {
|
||||
m.Store(upstreamAddr, err.Error())
|
||||
} else {
|
||||
m.Store(upstreamAddr, "OK")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkUpstreamAddr creates the DNS upstream using opts and information from
|
||||
// [s.dnsFilter.EtcHosts]. Checks if the DNS upstream exchanges correctly. It
|
||||
// returns an error if addr is not valid DNS upstream address or the upstream
|
||||
// checkUpstreamAddr creates the upstream using opts and, possibly, information
|
||||
// from system hosts files, then checks if the DNS upstream exchanges correctly.
|
||||
// It returns an error if addr is not valid DNS upstream address or the upstream
|
||||
// is not exchanging correctly.
|
||||
//
|
||||
// TODO(e.burkov): Remove the receiver.
|
||||
func (s *Server) checkUpstreamAddr(
|
||||
addr string,
|
||||
specific bool,
|
||||
opts *upstream.Options,
|
||||
basicOpts *upstream.Options,
|
||||
check healthCheckFunc,
|
||||
) (err error) {
|
||||
usesDefault, err := validateUpstream(addr, specific)
|
||||
if err != nil {
|
||||
return fmt.Errorf("wrong upstream format: %w", err)
|
||||
} else if usesDefault {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debug("dnsforward: checking if upstream %q works", addr)
|
||||
|
||||
defer func() {
|
||||
if err != nil && specific {
|
||||
err = domainSpecificTestError{error: err}
|
||||
}
|
||||
}()
|
||||
|
||||
u, err := upstream.AddressToUpstream(addr, &upstream.Options{
|
||||
Bootstrap: opts.Bootstrap,
|
||||
Timeout: opts.Timeout,
|
||||
PreferIPv6: opts.PreferIPv6,
|
||||
})
|
||||
opts := &upstream.Options{
|
||||
Bootstrap: basicOpts.Bootstrap,
|
||||
Timeout: basicOpts.Timeout,
|
||||
PreferIPv6: basicOpts.PreferIPv6,
|
||||
}
|
||||
|
||||
// dnsFilter can be nil during application update.
|
||||
//
|
||||
// TODO(e.burkov): Remove when update dnsproxy.
|
||||
if s.dnsFilter != nil {
|
||||
recs := s.dnsFilter.EtcHostsRecords(extractUpstreamHost(addr))
|
||||
for _, rec := range recs {
|
||||
opts.ServerIPAddrs = append(opts.ServerIPAddrs, rec.Addr.AsSlice())
|
||||
}
|
||||
sortNetIPAddrs(opts.ServerIPAddrs, opts.PreferIPv6)
|
||||
}
|
||||
|
||||
u, err := upstream.AddressToUpstream(addr, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating upstream for %q: %w", addr, err)
|
||||
}
|
||||
|
||||
defer func() { err = errors.WithDeferred(err, u.Close()) }()
|
||||
|
||||
return check(u)
|
||||
}
|
||||
|
||||
// closeBoots closes all the provided bootstrap servers and logs errors if any.
|
||||
func closeBoots(boots []*upstream.UpstreamResolver) {
|
||||
for _, c := range boots {
|
||||
logCloserErr(c, "dnsforward: closing bootstrap %s: %s", c.Address())
|
||||
// checkResult is a result of checking an upstream server.
|
||||
type checkResult = struct {
|
||||
// status is an error message if the upstream server is not working. It's
|
||||
// nil for working upstreams.
|
||||
status error
|
||||
|
||||
// address is the upstream server address as given in the request. It may
|
||||
// appear to be a whole line if it's incorrect itself.
|
||||
address string
|
||||
}
|
||||
|
||||
// checkDNS parses an upstream configuration line using opts and checks if the
|
||||
// specified upstreams are working using check. countWG is decremented when the
|
||||
// expected number of results added to resNum, then results are sent to resCh.
|
||||
//
|
||||
// TODO(e.burkov): Remove the receiver.
|
||||
func (s *Server) checkDNS(
|
||||
line string,
|
||||
opts *upstream.Options,
|
||||
check healthCheckFunc,
|
||||
countWG *sync.WaitGroup,
|
||||
resNum *atomic.Int32,
|
||||
resCh chan<- checkResult,
|
||||
) {
|
||||
defer log.OnPanic("dnsforward: checking upstreams")
|
||||
|
||||
addrs, domains, err := separateUpstream(line)
|
||||
if err != nil {
|
||||
resNum.Add(1)
|
||||
countWG.Done()
|
||||
|
||||
resCh <- checkResult{
|
||||
address: line,
|
||||
status: fmt.Errorf("wrong upstream format: %w", err),
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
resNum.Add(int32(len(addrs)))
|
||||
countWG.Done()
|
||||
|
||||
specific := len(domains) > 0
|
||||
for _, addr := range addrs {
|
||||
resCh <- checkResult{
|
||||
address: addr,
|
||||
status: s.checkUpstreamAddr(addr, specific, opts, check),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check returns the mapping of upstream addresses to their check results.
|
||||
func (s *Server) check(req *upstreamJSON, opts *upstream.Options) (result map[string]string) {
|
||||
req.Upstreams = stringutil.FilterOut(req.Upstreams, IsCommentOrEmpty)
|
||||
req.FallbackDNS = stringutil.FilterOut(req.FallbackDNS, IsCommentOrEmpty)
|
||||
req.PrivateUpstreams = stringutil.FilterOut(req.PrivateUpstreams, IsCommentOrEmpty)
|
||||
|
||||
countWG := &sync.WaitGroup{}
|
||||
countWG.Add(len(req.Upstreams) + len(req.FallbackDNS) + len(req.PrivateUpstreams))
|
||||
|
||||
resNum := &atomic.Int32{}
|
||||
resCh := make(chan checkResult)
|
||||
|
||||
for _, addr := range req.Upstreams {
|
||||
go s.checkDNS(addr, opts, checkExchange, countWG, resNum, resCh)
|
||||
}
|
||||
for _, addr := range req.FallbackDNS {
|
||||
go s.checkDNS(addr, opts, checkExchange, countWG, resNum, resCh)
|
||||
}
|
||||
for _, addr := range req.PrivateUpstreams {
|
||||
go s.checkDNS(addr, opts, checkPrivateExchange, countWG, resNum, resCh)
|
||||
}
|
||||
|
||||
// Wait until all the servers are counted and enqueued.
|
||||
countWG.Wait()
|
||||
n := resNum.Load()
|
||||
|
||||
result = make(map[string]string, n)
|
||||
for i := int32(0); i < n; i++ {
|
||||
// TODO(e.burkov): Upstreams intended for different purposes should
|
||||
// be distinguished in the result, even if specified equally.
|
||||
res := <-resCh
|
||||
if res.status != nil {
|
||||
result[res.address] = res.status.Error()
|
||||
} else {
|
||||
result[res.address] = "OK"
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// handleTestUpstreamDNS handles requests to the POST /control/test_upstream_dns
|
||||
@@ -923,55 +859,18 @@ func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
req.Upstreams = stringutil.FilterOut(req.Upstreams, IsCommentOrEmpty)
|
||||
req.FallbackDNS = stringutil.FilterOut(req.FallbackDNS, IsCommentOrEmpty)
|
||||
req.PrivateUpstreams = stringutil.FilterOut(req.PrivateUpstreams, IsCommentOrEmpty)
|
||||
req.BootstrapDNS = stringutil.FilterOut(req.BootstrapDNS, IsCommentOrEmpty)
|
||||
bootstrapAddrs := stringutil.FilterOut(req.BootstrapDNS, IsCommentOrEmpty)
|
||||
if len(bootstrapAddrs) == 0 {
|
||||
bootstrapAddrs = defaultBootstrap
|
||||
}
|
||||
|
||||
opts := &upstream.Options{
|
||||
Bootstrap: bootstrapAddrs,
|
||||
Timeout: s.conf.UpstreamTimeout,
|
||||
PreferIPv6: s.conf.BootstrapPreferIPv6,
|
||||
}
|
||||
|
||||
var boots []*upstream.UpstreamResolver
|
||||
opts.Bootstrap, boots, err = s.createBootstrap(req.BootstrapDNS, opts)
|
||||
if err != nil {
|
||||
aghhttp.Error(r, w, http.StatusBadRequest, "Failed to parse bootstrap servers: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
defer closeBoots(boots)
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
m := &sync.Map{}
|
||||
|
||||
wg.Add(len(req.Upstreams) + len(req.FallbackDNS) + len(req.PrivateUpstreams))
|
||||
|
||||
for _, ups := range req.Upstreams {
|
||||
go s.checkDNS(ups, opts, checkDNSUpstreamExc, wg, m)
|
||||
}
|
||||
for _, ups := range req.FallbackDNS {
|
||||
go s.checkDNS(ups, opts, checkDNSUpstreamExc, wg, m)
|
||||
}
|
||||
for _, ups := range req.PrivateUpstreams {
|
||||
go s.checkDNS(ups, opts, checkPrivateUpstreamExc, wg, m)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
result := map[string]string{}
|
||||
m.Range(func(k, v any) bool {
|
||||
// TODO(e.burkov): The upstreams used for both common and private
|
||||
// resolving should be reported separately.
|
||||
ups := k.(string)
|
||||
status := v.(string)
|
||||
|
||||
result[ups] = status
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
aghhttp.WriteJSONResponseOK(w, r, result)
|
||||
aghhttp.WriteJSONResponseOK(w, r, s.check(req, opts))
|
||||
}
|
||||
|
||||
// handleCacheClear is the handler for the POST /control/cache_clear HTTP API.
|
||||
|
||||
@@ -72,14 +72,11 @@ func TestDNSForwardHTTP_handleGetConfig(t *testing.T) {
|
||||
UDPListenAddrs: []*net.UDPAddr{},
|
||||
TCPListenAddrs: []*net.TCPAddr{},
|
||||
Config: Config{
|
||||
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
||||
FallbackDNS: []string{"9.9.9.10"},
|
||||
RatelimitSubnetLenIPv4: 24,
|
||||
RatelimitSubnetLenIPv6: 56,
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
||||
FallbackDNS: []string{"9.9.9.10"},
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ConfigModified: func() {},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
s := createTestServer(t, filterConf, forwardConf, nil)
|
||||
s.sysResolvers = &emptySysResolvers{}
|
||||
@@ -153,13 +150,10 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
|
||||
UDPListenAddrs: []*net.UDPAddr{},
|
||||
TCPListenAddrs: []*net.TCPAddr{},
|
||||
Config: Config{
|
||||
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
||||
RatelimitSubnetLenIPv4: 24,
|
||||
RatelimitSubnetLenIPv6: 56,
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ConfigModified: func() {},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
s := createTestServer(t, filterConf, forwardConf, nil)
|
||||
s.sysResolvers = &emptySysResolvers{}
|
||||
@@ -185,19 +179,11 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
|
||||
name: "blocking_mode_good",
|
||||
wantSet: "",
|
||||
}, {
|
||||
name: "blocking_mode_bad",
|
||||
wantSet: "validating dns config: " +
|
||||
"blocking_ipv4 must be valid ipv4 on custom_ip blocking_mode",
|
||||
name: "blocking_mode_bad",
|
||||
wantSet: "blocking_ipv4 must be valid ipv4 on custom_ip blocking_mode",
|
||||
}, {
|
||||
name: "ratelimit",
|
||||
wantSet: "",
|
||||
}, {
|
||||
name: "ratelimit_subnet_len",
|
||||
wantSet: "",
|
||||
}, {
|
||||
name: "ratelimit_whitelist_not_ip",
|
||||
wantSet: `validating dns config: ratelimit whitelist: at index 1: ParseAddr("not.ip"): ` +
|
||||
`unexpected character (at "not.ip")`,
|
||||
}, {
|
||||
name: "edns_cs_enabled",
|
||||
wantSet: "",
|
||||
@@ -220,26 +206,24 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
|
||||
name: "upstream_mode_fastest_addr",
|
||||
wantSet: "",
|
||||
}, {
|
||||
name: "upstream_dns_bad",
|
||||
wantSet: `validating dns config: ` +
|
||||
`upstream servers: validating upstream "!!!": not an ip:port`,
|
||||
name: "upstream_dns_bad",
|
||||
wantSet: `validating upstream servers: validating upstream "!!!": not an ip:port`,
|
||||
}, {
|
||||
name: "bootstraps_bad",
|
||||
wantSet: `validating dns config: checking bootstrap a: invalid address: not a bootstrap: ` +
|
||||
wantSet: `checking bootstrap a: invalid address: bootstrap a:53: ` +
|
||||
`ParseAddr("a"): unable to parse IP`,
|
||||
}, {
|
||||
name: "cache_bad_ttl",
|
||||
wantSet: `validating dns config: cache_ttl_min must be less or equal than cache_ttl_max`,
|
||||
wantSet: `cache_ttl_min must be less or equal than cache_ttl_max`,
|
||||
}, {
|
||||
name: "upstream_mode_bad",
|
||||
wantSet: `validating dns config: upstream_mode: incorrect value "somethingelse"`,
|
||||
wantSet: `upstream_mode: incorrect value`,
|
||||
}, {
|
||||
name: "local_ptr_upstreams_good",
|
||||
wantSet: "",
|
||||
}, {
|
||||
name: "local_ptr_upstreams_bad",
|
||||
wantSet: `validating dns config: ` +
|
||||
`private upstream servers: checking domain-specific upstreams: ` +
|
||||
wantSet: `validating private upstream servers: checking domain-specific upstreams: ` +
|
||||
`bad arpa domain name "non.arpa.": not a reversed ip network`,
|
||||
}, {
|
||||
name: "local_ptr_upstreams_null",
|
||||
@@ -535,9 +519,7 @@ func TestServer_HandleTestUpstreamDNS(t *testing.T) {
|
||||
Config: Config{
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}, nil)
|
||||
srv.etcHosts = hc
|
||||
startDeferStop(t, srv)
|
||||
|
||||
testCases := []struct {
|
||||
|
||||
@@ -2,6 +2,7 @@ package dnsforward
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
@@ -91,7 +92,7 @@ func (s *Server) genForBlockingMode(req *dns.Msg, ips []netip.Addr) (resp *dns.M
|
||||
case filtering.BlockingModeREFUSED:
|
||||
return s.makeResponseREFUSED(req)
|
||||
default:
|
||||
log.Error("dnsforward: invalid blocking mode %q", mode)
|
||||
log.Error("dns: invalid blocking mode %q", mode)
|
||||
|
||||
return s.makeResponse(req)
|
||||
}
|
||||
@@ -112,7 +113,7 @@ func (s *Server) makeResponseCustomIP(
|
||||
default:
|
||||
// Generally shouldn't happen, since the types are checked in
|
||||
// genDNSFilterMessage.
|
||||
log.Error("dnsforward: invalid msg type %s for custom IP blocking mode", dns.Type(qt))
|
||||
log.Error("dns: invalid msg type %s for custom IP blocking mode", dns.Type(qt))
|
||||
|
||||
return s.makeResponse(req)
|
||||
}
|
||||
@@ -207,7 +208,15 @@ func (s *Server) genResponseWithIPs(req *dns.Msg, ips []netip.Addr) (resp *dns.M
|
||||
var ans []dns.RR
|
||||
switch req.Question[0].Qtype {
|
||||
case dns.TypeA:
|
||||
ans = s.genAnswersWithIPv4s(req, ips)
|
||||
for _, ip := range ips {
|
||||
if ip.Is4() {
|
||||
ans = append(ans, s.genAnswerA(req, ip))
|
||||
} else {
|
||||
ans = nil
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
case dns.TypeAAAA:
|
||||
for _, ip := range ips {
|
||||
if ip.Is6() {
|
||||
@@ -224,23 +233,6 @@ func (s *Server) genResponseWithIPs(req *dns.Msg, ips []netip.Addr) (resp *dns.M
|
||||
return resp
|
||||
}
|
||||
|
||||
// genAnswersWithIPv4s generates DNS A answers provided IPv4 addresses. If any
|
||||
// of the IPs isn't an IPv4 address, genAnswersWithIPv4s logs a warning and
|
||||
// returns nil,
|
||||
func (s *Server) genAnswersWithIPv4s(req *dns.Msg, ips []netip.Addr) (ans []dns.RR) {
|
||||
for _, ip := range ips {
|
||||
if !ip.Is4() {
|
||||
log.Info("dnsforward: warning: ip %s is not ipv4 address", ip)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
ans = append(ans, s.genAnswerA(req, ip))
|
||||
}
|
||||
|
||||
return ans
|
||||
}
|
||||
|
||||
// makeResponseNullIP creates a response with 0.0.0.0 for A requests, :: for
|
||||
// AAAA requests, and an empty response for other types.
|
||||
func (s *Server) makeResponseNullIP(req *dns.Msg) (resp *dns.Msg) {
|
||||
@@ -262,7 +254,7 @@ func (s *Server) makeResponseNullIP(req *dns.Msg) (resp *dns.Msg) {
|
||||
|
||||
func (s *Server) genBlockedHost(request *dns.Msg, newAddr string, d *proxy.DNSContext) *dns.Msg {
|
||||
if newAddr == "" {
|
||||
log.Info("dnsforward: block host is not specified")
|
||||
log.Printf("block host is not specified.")
|
||||
|
||||
return s.genServerFailure(request)
|
||||
}
|
||||
@@ -278,21 +270,22 @@ func (s *Server) genBlockedHost(request *dns.Msg, newAddr string, d *proxy.DNSCo
|
||||
replReq.RecursionDesired = true
|
||||
|
||||
newContext := &proxy.DNSContext{
|
||||
Proto: d.Proto,
|
||||
Addr: d.Addr,
|
||||
Req: &replReq,
|
||||
Proto: d.Proto,
|
||||
Addr: d.Addr,
|
||||
StartTime: time.Now(),
|
||||
Req: &replReq,
|
||||
}
|
||||
|
||||
prx := s.proxy()
|
||||
if prx == nil {
|
||||
log.Debug("dnsforward: %s", srvClosedErr)
|
||||
log.Debug("dns: %s", srvClosedErr)
|
||||
|
||||
return s.genServerFailure(request)
|
||||
}
|
||||
|
||||
err = prx.Resolve(newContext)
|
||||
if err != nil {
|
||||
log.Info("dnsforward: looking up replacement host %q: %s", newAddr, err)
|
||||
log.Printf("couldn't look up replacement host %q: %s", newAddr, err)
|
||||
|
||||
return s.genServerFailure(request)
|
||||
}
|
||||
|
||||
@@ -831,13 +831,14 @@ func (s *Server) dhcpHostFromRequest(q *dns.Question) (reqHost string) {
|
||||
|
||||
// setCustomUpstream sets custom upstream settings in pctx, if necessary.
|
||||
func (s *Server) setCustomUpstream(pctx *proxy.DNSContext, clientID string) {
|
||||
if pctx.Addr == nil || s.conf.ClientsContainer == nil {
|
||||
customUpsByClient := s.conf.GetCustomUpstreamByClient
|
||||
if pctx.Addr == nil || customUpsByClient == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Use the ClientID first, since it has a higher priority.
|
||||
id := stringutil.Coalesce(clientID, ipStringFromAddr(pctx.Addr))
|
||||
upsConf, err := s.conf.ClientsContainer.UpstreamConfigByID(id, s.bootstrap)
|
||||
upsConf, err := customUpsByClient(id)
|
||||
if err != nil {
|
||||
log.Error("dnsforward: getting custom upstreams for client %s: %s", id, err)
|
||||
|
||||
@@ -846,9 +847,9 @@ func (s *Server) setCustomUpstream(pctx *proxy.DNSContext, clientID string) {
|
||||
|
||||
if upsConf != nil {
|
||||
log.Debug("dnsforward: using custom upstreams for client %s", id)
|
||||
|
||||
pctx.CustomUpstreamConfig = upsConf
|
||||
}
|
||||
|
||||
pctx.CustomUpstreamConfig = upsConf
|
||||
}
|
||||
|
||||
// Apply filtering logic after we have received response from upstream servers
|
||||
|
||||
@@ -81,7 +81,6 @@ func TestServer_ProcessInitial(t *testing.T) {
|
||||
AAAADisabled: tc.aaaaDisabled,
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
|
||||
s := createTestServer(t, &filtering.Config{
|
||||
@@ -181,7 +180,6 @@ func TestServer_ProcessFilteringAfterResponse(t *testing.T) {
|
||||
AAAADisabled: tc.aaaaDisabled,
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
|
||||
s := createTestServer(t, &filtering.Config{
|
||||
@@ -371,7 +369,6 @@ func prepareTestServer(t *testing.T, portDoH, portDoT, portDoQ int, ddrEnabled b
|
||||
TLSConfig: TLSConfig{
|
||||
ServerName: ddrTestDomainName,
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -702,7 +699,6 @@ func TestServer_ProcessRestrictLocal(t *testing.T) {
|
||||
Config: Config{
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}, ups)
|
||||
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ups}
|
||||
startDeferStop(t, s)
|
||||
@@ -780,7 +776,6 @@ func TestServer_ProcessLocalPTR_usingResolvers(t *testing.T) {
|
||||
Config: Config{
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
},
|
||||
aghtest.NewUpstreamMock(func(req *dns.Msg) (resp *dns.Msg, err error) {
|
||||
return aghalg.Coalesce(
|
||||
|
||||
@@ -20,10 +20,11 @@ func (s *Server) processQueryLogsAndStats(dctx *dnsContext) (rc resultCode) {
|
||||
log.Debug("dnsforward: started processing querylog and stats")
|
||||
defer log.Debug("dnsforward: finished processing querylog and stats")
|
||||
|
||||
elapsed := time.Since(dctx.startTime)
|
||||
pctx := dctx.proxyCtx
|
||||
|
||||
q := pctx.Req.Question[0]
|
||||
host := aghnet.NormalizeDomain(q.Name)
|
||||
processingTime := time.Since(dctx.startTime)
|
||||
|
||||
ip, _ := netutil.IPAndPortFromAddr(pctx.Addr)
|
||||
ip = slices.Clone(ip)
|
||||
@@ -42,7 +43,7 @@ func (s *Server) processQueryLogsAndStats(dctx *dnsContext) (rc resultCode) {
|
||||
defer s.serverLock.RUnlock()
|
||||
|
||||
if s.shouldLog(host, qt, cl, ids) {
|
||||
s.logQuery(dctx, ip, processingTime)
|
||||
s.logQuery(dctx, pctx, elapsed, ip)
|
||||
} else {
|
||||
log.Debug(
|
||||
"dnsforward: request %s %s %q from %s ignored; not adding to querylog",
|
||||
@@ -54,7 +55,7 @@ func (s *Server) processQueryLogsAndStats(dctx *dnsContext) (rc resultCode) {
|
||||
}
|
||||
|
||||
if s.shouldCountStat(host, qt, cl, ids) {
|
||||
s.updateStats(dctx, ipStr, processingTime)
|
||||
s.updateStats(dctx, elapsed, *dctx.result, ipStr)
|
||||
} else {
|
||||
log.Debug(
|
||||
"dnsforward: request %s %s %q from %s ignored; not counting in stats",
|
||||
@@ -89,9 +90,12 @@ func (s *Server) shouldCountStat(host string, qt, cl uint16, ids []string) (ok b
|
||||
}
|
||||
|
||||
// logQuery pushes the request details into the query log.
|
||||
func (s *Server) logQuery(dctx *dnsContext, ip net.IP, processingTime time.Duration) {
|
||||
pctx := dctx.proxyCtx
|
||||
|
||||
func (s *Server) logQuery(
|
||||
dctx *dnsContext,
|
||||
pctx *proxy.DNSContext,
|
||||
elapsed time.Duration,
|
||||
ip net.IP,
|
||||
) {
|
||||
p := &querylog.AddParams{
|
||||
Question: pctx.Req,
|
||||
ReqECS: pctx.ReqECS,
|
||||
@@ -100,7 +104,7 @@ func (s *Server) logQuery(dctx *dnsContext, ip net.IP, processingTime time.Durat
|
||||
Result: dctx.result,
|
||||
ClientID: dctx.clientID,
|
||||
ClientIP: ip,
|
||||
Elapsed: processingTime,
|
||||
Elapsed: elapsed,
|
||||
AuthenticatedData: dctx.responseAD,
|
||||
}
|
||||
|
||||
@@ -128,27 +132,30 @@ func (s *Server) logQuery(dctx *dnsContext, ip net.IP, processingTime time.Durat
|
||||
}
|
||||
|
||||
// updatesStats writes the request into statistics.
|
||||
func (s *Server) updateStats(dctx *dnsContext, clientIP string, processingTime time.Duration) {
|
||||
pctx := dctx.proxyCtx
|
||||
|
||||
func (s *Server) updateStats(
|
||||
ctx *dnsContext,
|
||||
elapsed time.Duration,
|
||||
res filtering.Result,
|
||||
clientIP string,
|
||||
) {
|
||||
pctx := ctx.proxyCtx
|
||||
e := &stats.Entry{
|
||||
Domain: aghnet.NormalizeDomain(pctx.Req.Question[0].Name),
|
||||
Result: stats.RNotFiltered,
|
||||
ProcessingTime: processingTime,
|
||||
UpstreamTime: pctx.QueryDuration,
|
||||
Domain: aghnet.NormalizeDomain(pctx.Req.Question[0].Name),
|
||||
Result: stats.RNotFiltered,
|
||||
Time: elapsed,
|
||||
}
|
||||
|
||||
if pctx.Upstream != nil {
|
||||
e.Upstream = pctx.Upstream.Address()
|
||||
}
|
||||
|
||||
if clientID := dctx.clientID; clientID != "" {
|
||||
if clientID := ctx.clientID; clientID != "" {
|
||||
e.Client = clientID
|
||||
} else {
|
||||
e.Client = clientIP
|
||||
}
|
||||
|
||||
switch dctx.result.Reason {
|
||||
switch res.Reason {
|
||||
case filtering.FilteredSafeBrowsing:
|
||||
e.Result = stats.RSafeBrowsing
|
||||
case filtering.FilteredParental:
|
||||
|
||||
@@ -19,7 +19,6 @@ func TestGenAnswerHTTPS_andSVCB(t *testing.T) {
|
||||
Config: Config{
|
||||
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||
},
|
||||
ServePlainDNS: true,
|
||||
}, nil)
|
||||
|
||||
req := &dns.Msg{
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -56,9 +53,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -95,9 +89,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -63,9 +60,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -105,9 +99,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "refused",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -147,9 +138,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -189,98 +177,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 6,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"cache_optimistic": false,
|
||||
"resolve_clients": false,
|
||||
"use_private_ptr_resolvers": false,
|
||||
"local_ptr_upstreams": [],
|
||||
"edns_cs_use_custom": false,
|
||||
"edns_cs_custom_ip": ""
|
||||
}
|
||||
},
|
||||
"ratelimit_subnet_len": {
|
||||
"req": {
|
||||
"ratelimit": 12,
|
||||
"ratelimit_subnet_len_ipv4": 32,
|
||||
"ratelimit_subnet_len_ipv6": 128
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"fallback_dns": [],
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 12,
|
||||
"ratelimit_subnet_len_ipv4": 32,
|
||||
"ratelimit_subnet_len_ipv6": 128,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"blocked_response_ttl": 10,
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"cache_optimistic": false,
|
||||
"resolve_clients": false,
|
||||
"use_private_ptr_resolvers": false,
|
||||
"local_ptr_upstreams": [],
|
||||
"edns_cs_use_custom": false,
|
||||
"edns_cs_custom_ip": ""
|
||||
}
|
||||
},
|
||||
"ratelimit_whitelist_not_ip": {
|
||||
"req": {
|
||||
"ratelimit_whitelist": [
|
||||
"1.2.3.4",
|
||||
"not.ip"
|
||||
]
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"fallback_dns": [],
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -320,9 +216,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -364,9 +257,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -408,9 +298,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -450,9 +337,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -492,9 +376,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -534,9 +415,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -576,9 +454,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -620,9 +495,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -664,9 +536,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -707,9 +576,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -749,9 +615,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -793,9 +656,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -840,9 +700,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -882,9 +739,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -928,9 +782,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -970,9 +821,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
@@ -1015,9 +863,6 @@
|
||||
"protection_enabled": true,
|
||||
"protection_disabled_until": null,
|
||||
"ratelimit": 0,
|
||||
"ratelimit_subnet_len_ipv4": 24,
|
||||
"ratelimit_subnet_len_ipv6": 56,
|
||||
"ratelimit_whitelist": [],
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
package dnsforward
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/stringutil"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// loadUpstreams parses upstream DNS servers from the configured file or from
|
||||
@@ -33,7 +39,7 @@ func (s *Server) loadUpstreams() (upstreams []string, err error) {
|
||||
}
|
||||
|
||||
// prepareUpstreamSettings sets upstream DNS server settings.
|
||||
func (s *Server) prepareUpstreamSettings(boot upstream.Resolver) (err error) {
|
||||
func (s *Server) prepareUpstreamSettings() (err error) {
|
||||
// Load upstreams either from the file, or from the settings
|
||||
var upstreams []string
|
||||
upstreams, err = s.loadUpstreams()
|
||||
@@ -42,7 +48,7 @@ func (s *Server) prepareUpstreamSettings(boot upstream.Resolver) (err error) {
|
||||
}
|
||||
|
||||
s.conf.UpstreamConfig, err = s.prepareUpstreamConfig(upstreams, defaultDNS, &upstream.Options{
|
||||
Bootstrap: boot,
|
||||
Bootstrap: s.conf.BootstrapDNS,
|
||||
Timeout: s.conf.UpstreamTimeout,
|
||||
HTTPVersions: UpstreamHTTPVersions(s.conf.UseHTTP3Upstreams),
|
||||
PreferIPv6: s.conf.BootstrapPreferIPv6,
|
||||
@@ -86,9 +92,178 @@ func (s *Server) prepareUpstreamConfig(
|
||||
uc.Upstreams = defaultUpstreamConfig.Upstreams
|
||||
}
|
||||
|
||||
// dnsFilter can be nil during application update.
|
||||
if s.dnsFilter != nil {
|
||||
err = s.replaceUpstreamsWithHosts(uc, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("resolving upstreams with hosts: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return uc, nil
|
||||
}
|
||||
|
||||
// replaceUpstreamsWithHosts replaces unique upstreams with their resolved
|
||||
// versions based on the system hosts file.
|
||||
//
|
||||
// TODO(e.burkov): This should be performed inside dnsproxy, which should
|
||||
// actually consider /etc/hosts. See TODO on [aghnet.HostsContainer].
|
||||
func (s *Server) replaceUpstreamsWithHosts(
|
||||
upsConf *proxy.UpstreamConfig,
|
||||
opts *upstream.Options,
|
||||
) (err error) {
|
||||
resolved := map[string]*upstream.Options{}
|
||||
|
||||
err = s.resolveUpstreamsWithHosts(resolved, upsConf.Upstreams, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("resolving upstreams: %w", err)
|
||||
}
|
||||
|
||||
hosts := maps.Keys(upsConf.DomainReservedUpstreams)
|
||||
// TODO(e.burkov): Think of extracting sorted range into an util function.
|
||||
slices.Sort(hosts)
|
||||
for _, host := range hosts {
|
||||
err = s.resolveUpstreamsWithHosts(resolved, upsConf.DomainReservedUpstreams[host], opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("resolving upstreams reserved for %s: %w", host, err)
|
||||
}
|
||||
}
|
||||
|
||||
hosts = maps.Keys(upsConf.SpecifiedDomainUpstreams)
|
||||
slices.Sort(hosts)
|
||||
for _, host := range hosts {
|
||||
err = s.resolveUpstreamsWithHosts(resolved, upsConf.SpecifiedDomainUpstreams[host], opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("resolving upstreams specific for %s: %w", host, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resolveUpstreamsWithHosts resolves the IP addresses of each of the upstreams
|
||||
// and replaces those both in upstreams and resolved. Upstreams that failed to
|
||||
// resolve are placed to resolved as-is. This function only returns error of
|
||||
// upstreams closing.
|
||||
func (s *Server) resolveUpstreamsWithHosts(
|
||||
resolved map[string]*upstream.Options,
|
||||
upstreams []upstream.Upstream,
|
||||
opts *upstream.Options,
|
||||
) (err error) {
|
||||
for i := range upstreams {
|
||||
u := upstreams[i]
|
||||
addr := u.Address()
|
||||
host := extractUpstreamHost(addr)
|
||||
|
||||
withIPs, ok := resolved[host]
|
||||
if !ok {
|
||||
recs := s.dnsFilter.EtcHostsRecords(host)
|
||||
if len(recs) == 0 {
|
||||
resolved[host] = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
withIPs = opts.Clone()
|
||||
withIPs.ServerIPAddrs = make([]net.IP, 0, len(recs))
|
||||
for _, rec := range recs {
|
||||
withIPs.ServerIPAddrs = append(withIPs.ServerIPAddrs, rec.Addr.AsSlice())
|
||||
}
|
||||
|
||||
sortNetIPAddrs(withIPs.ServerIPAddrs, opts.PreferIPv6)
|
||||
resolved[host] = withIPs
|
||||
} else if withIPs == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = u.Close(); err != nil {
|
||||
return fmt.Errorf("closing upstream %s: %w", addr, err)
|
||||
}
|
||||
|
||||
upstreams[i], err = upstream.AddressToUpstream(addr, withIPs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("replacing upstream %s with resolved %s: %w", addr, host, err)
|
||||
}
|
||||
|
||||
log.Debug("dnsforward: using %s for %s", withIPs.ServerIPAddrs, upstreams[i].Address())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// extractUpstreamHost returns the hostname of addr without port with an
|
||||
// assumption that any address passed here has already been successfully parsed
|
||||
// by [upstream.AddressToUpstream]. This function essentially mirrors the logic
|
||||
// of [upstream.AddressToUpstream], see TODO on [replaceUpstreamsWithHosts].
|
||||
func extractUpstreamHost(addr string) (host string) {
|
||||
var err error
|
||||
if strings.Contains(addr, "://") {
|
||||
var u *url.URL
|
||||
u, err = url.Parse(addr)
|
||||
if err != nil {
|
||||
log.Debug("dnsforward: parsing upstream %s: %s", addr, err)
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
return u.Hostname()
|
||||
}
|
||||
|
||||
// Probably, plain UDP upstream defined by address or address:port.
|
||||
host, err = netutil.SplitHost(addr)
|
||||
if err != nil {
|
||||
return addr
|
||||
}
|
||||
|
||||
return host
|
||||
}
|
||||
|
||||
// sortNetIPAddrs sorts addrs in accordance with the protocol preferences.
|
||||
// Invalid addresses are sorted near the end.
|
||||
//
|
||||
// TODO(e.burkov): This function taken from dnsproxy, which also already
|
||||
// contains a few similar functions. Think of moving to golibs.
|
||||
func sortNetIPAddrs(addrs []net.IP, preferIPv6 bool) {
|
||||
l := len(addrs)
|
||||
if l <= 1 {
|
||||
return
|
||||
}
|
||||
|
||||
slices.SortStableFunc(addrs, func(addrA, addrB net.IP) (res int) {
|
||||
switch len(addrA) {
|
||||
case net.IPv4len, net.IPv6len:
|
||||
switch len(addrB) {
|
||||
case net.IPv4len, net.IPv6len:
|
||||
// Go on.
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
|
||||
// Treat IPv6-mapped IPv4 addresses as IPv6 addresses.
|
||||
aIs4, bIs4 := addrA.To4() != nil, addrB.To4() != nil
|
||||
if aIs4 == bIs4 {
|
||||
return bytes.Compare(addrA, addrB)
|
||||
}
|
||||
|
||||
if aIs4 {
|
||||
if preferIPv6 {
|
||||
return 1
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
if preferIPv6 {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 1
|
||||
})
|
||||
}
|
||||
|
||||
// UpstreamHTTPVersions returns the HTTP versions for upstream configuration
|
||||
// depending on configuration.
|
||||
func UpstreamHTTPVersions(http3 bool) (v []upstream.HTTPVersion) {
|
||||
@@ -120,41 +295,3 @@ func setProxyUpstreamMode(
|
||||
conf.UpstreamMode = proxy.UModeLoadBalance
|
||||
}
|
||||
}
|
||||
|
||||
// createBootstrap returns a bootstrap resolver based on the configuration of s.
|
||||
// boots are the upstream resolvers that should be closed after use. r is the
|
||||
// actual bootstrap resolver, which may include the system hosts.
|
||||
//
|
||||
// TODO(e.burkov): This function currently returns a resolver and a slice of
|
||||
// the upstream resolvers, which are essentially the same. boots are returned
|
||||
// for being able to close them afterwards, but it introduces an implicit
|
||||
// contract that r could only be used before that. Anyway, this code should
|
||||
// improve when the [proxy.UpstreamConfig] will become an [upstream.Resolver]
|
||||
// and be used here.
|
||||
func (s *Server) createBootstrap(
|
||||
addrs []string,
|
||||
opts *upstream.Options,
|
||||
) (r upstream.Resolver, boots []*upstream.UpstreamResolver, err error) {
|
||||
if len(addrs) == 0 {
|
||||
addrs = defaultBootstrap
|
||||
}
|
||||
|
||||
boots, err = aghnet.ParseBootstraps(addrs, opts)
|
||||
if err != nil {
|
||||
// Don't wrap the error, since it's informative enough as is.
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var parallel upstream.ParallelResolver
|
||||
for _, b := range boots {
|
||||
parallel = append(parallel, b)
|
||||
}
|
||||
|
||||
if s.etcHosts != nil {
|
||||
r = upstream.ConsequentResolver{s.etcHosts, parallel}
|
||||
} else {
|
||||
r = parallel
|
||||
}
|
||||
|
||||
return r, boots, nil
|
||||
}
|
||||
|
||||
@@ -98,8 +98,6 @@ type Config struct {
|
||||
|
||||
// EtcHosts is a container of IP-hostname pairs taken from the operating
|
||||
// system configuration files (e.g. /etc/hosts).
|
||||
//
|
||||
// TODO(e.burkov): Move it to dnsforward entirely.
|
||||
EtcHosts *aghnet.HostsContainer `yaml:"-"`
|
||||
|
||||
// Called when the configuration is changed by HTTP request
|
||||
|
||||
@@ -428,15 +428,6 @@ var blockedServices = []blockedService{{
|
||||
"||bnet.163.com^",
|
||||
"||bnet.cn^",
|
||||
},
|
||||
}, {
|
||||
ID: "canais_globo",
|
||||
Name: "Canais Globo",
|
||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 980 980\"><path d=\"M455.5 1.1a484.3 484.3 0 0 0-258 95.4 501.4 501.4 0 0 0-101.1 101A483.8 483.8 0 0 0 4 426.5 491.7 491.7 0 0 0 54.7 716a481.2 481.2 0 0 0 89.7 121.5C252.7 945.3 400 995.1 554 975.9c92.4-11.4 178-49.3 253.5-112 15-12.4 47.5-45.5 60.6-61.7A483.7 483.7 0 0 0 976 553.5a488.4 488.4 0 0 0-135.7-406.6A494.8 494.8 0 0 0 640.8 23.2 506.9 506.9 0 0 0 455.5 1.1zm-76.4 245.4c6.4 2.3 359.1 210.1 364.3 214.7 2.8 2.4 5.8 6.5 7.8 10.6 3.2 6.4 3.3 7.2 3.3 18.2s-.1 11.8-3.3 18.2c-2 4.1-5 8.2-7.8 10.6-6.7 5.9-358.7 212.7-365.3 214.6a42 42 0 0 1-29.1-2.6 46 46 0 0 1-18.6-19l-2.9-6.3v-431l2.9-6.2c2.7-6 9.5-13.6 15.7-17.6a44.3 44.3 0 0 1 33-4.2z\"/></svg>"),
|
||||
Rules: []string{
|
||||
"||canaisglobo.globo.com^",
|
||||
"||globosat.globo.com^",
|
||||
"||gsatmulti.globo.com^",
|
||||
},
|
||||
}, {
|
||||
ID: "claro",
|
||||
Name: "Claro",
|
||||
@@ -509,15 +500,6 @@ var blockedServices = []blockedService{{
|
||||
"||clubhouse.com^",
|
||||
"||clubhouseapi.com^",
|
||||
},
|
||||
}, {
|
||||
ID: "coolapk",
|
||||
Name: "CoolApk",
|
||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 384 384\"><path fill-rule=\"evenodd\" d=\"M105.62 104.96c30-1.4 57 6.8 81 24.5a717.7 717.7 0 0 0 34.5 27.5l29-48c12-7.4 21-4.8 27 8l79 142c3 15-3.3 22-18.5 20.5a3007.8 3007.8 0 0 1-103-76 166.46 166.46 0 0 1 25.5-17.5 574.67 574.67 0 0 1 33 24l.5-1a1227.62 1227.62 0 0 0-33-58 2174.49 2174.49 0 0 0-33.5 54c-15 25-35 45.6-59.5 61.5a104.39 104.39 0 0 1-90 6c-41.3-23.1-57.1-58-47.5-104.5a89.1 89.1 0 0 1 75.5-63zm1 31c23-1.6 43.7 4.6 62 18.5a777.4 777.4 0 0 1 26 20.5 668.04 668.04 0 0 0 25.5-17 318.5 318.5 0 0 1-38 57 95.75 95.75 0 0 1-49.5 32.5c-32.5 7-56.4-4.2-71.5-33.5-9.8-30.7-1-54.5 26.5-71.5 6.2-2.9 12.5-5 19-6.5z\"/></svg>"),
|
||||
Rules: []string{
|
||||
"||coolapk.com^",
|
||||
"||coolapkmarket.com^",
|
||||
"||coolapkmarket.net^",
|
||||
},
|
||||
}, {
|
||||
ID: "crunchyroll",
|
||||
Name: "Crunchyroll",
|
||||
@@ -1690,22 +1672,6 @@ var blockedServices = []blockedService{{
|
||||
"||linkedin.qtlcdn.com^",
|
||||
"||lnkd.in^",
|
||||
},
|
||||
}, {
|
||||
ID: "lionsgateplus",
|
||||
Name: "Lionsgate+",
|
||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"-21 2 120 120\"><path d=\"M35 3.7v84.8h43.9v31.8H0V3.7Z\"/></svg>"),
|
||||
Rules: []string{
|
||||
"||lionsgateplus.com^",
|
||||
"||starz.com^",
|
||||
},
|
||||
}, {
|
||||
ID: "looke",
|
||||
Name: "Looke",
|
||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 -28 100 100\"><path d=\"m16.1.1-2-.1C7 0 0 5.2 0 11.2 0 15.4 2.4 17 6.2 17 5 16 4 14.8 4 11.4 4 7 6.7 4 11 2.8v33.5h1c6.1 0 10.5 7.5 15.5 7.5 3.3 0 5.3-2.3 5.3-5 0-.4 0-.8-.2-1.2a9 9 0 0 1-3.6 1c-5.4 0-8.8-3.4-12.9-4.3V.3z\"/><path d=\"M31.6 11.2c-7.1 0-9.3 7.7-9.3 13.2 0 8.2 4.7 11.1 9 11.1 5 0 8-4.7 8-12.5v-2c3-.4 6-1.8 7.3-3.9L46 16a9.2 9.2 0 0 1-6.5 2.8H39c-.6-4.2-2.5-7.5-7.5-7.5zm.5 20.7c-2.1 0-4.6-1.5-4.6-7.7 0-4.6 1.4-10.4 5.4-10.4 1.4 0 2.6.8 3.4 3-1.2 0-2 .5-2 2 0 1.6.9 2.3 2.7 2.4v1.1c0 6-1.6 9.6-4.9 9.6z\"/><path d=\"M51.6 11.2c-7.1 0-9.3 7.7-9.3 13.2 0 8.2 4.7 11.1 9 11.1 5 0 8-4.7 8-12.5v-2c3-.4 6-1.8 7.3-3.9L66 16a9.2 9.2 0 0 1-6.5 2.8H59c-.6-4.2-2.5-7.5-7.5-7.5zm.5 20.7c-2.1 0-4.6-1.5-4.6-7.7 0-4.6 1.4-10.4 5.4-10.4 1.4 0 2.6.8 3.4 3-1.2 0-2 .5-2 2 0 1.6.9 2.3 2.7 2.4v1.1c0 6-1.6 9.6-4.9 9.6z\"/><path d=\"M63 2.6v32.6h4.7v-10c1-2.8 2.2-3.7 3.9-3.7 1.6 0 3 .8 3 4.2V30c0 3 1.5 5.4 5.3 5.4 2 0 5.2-.6 6.6-8.8h-1.7c-.8 3.6-2 5.2-3.6 5.2-1.7 0-1.9-1.6-1.9-2.5l.2-4.1c0-3.1-.8-7.4-6.5-7.4h-.5l8-6.5h-4.6l-8.2 7.8V1.9Z\"/><path d=\"M99.6 17.4c0-5-3.2-6.2-6.4-6.2-6.8 0-9 8-9 13.3 0 8 4.8 11 9 11 3.6 0 6.8-1.9 6.8-4.7l-.1-1.2c-1.2 1.7-3.1 2.3-5.2 2.3-2.7 0-5-1.1-5.5-6.2 6.5-.7 10.4-3.9 10.4-8.3zm-10.4 6.5c0-4.7 1.6-10.4 5-10.4 1.5 0 2.3 1 2.3 3.4 0 3.6-2.8 6.2-7.3 7z\"/></svg>"),
|
||||
Rules: []string{
|
||||
"||looke.com.br^",
|
||||
"||ottvs.com.br^",
|
||||
},
|
||||
}, {
|
||||
ID: "mail_ru",
|
||||
Name: "Mail.ru",
|
||||
@@ -1932,14 +1898,6 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||ok.ru^",
|
||||
},
|
||||
}, {
|
||||
ID: "olvid",
|
||||
Name: "Olvid",
|
||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 250 250\"><path d=\"M51 2.5c-18.4 4-35 17.3-43.3 34.6C.3 52.4.5 50.3.5 126v67.5l2.3 8c3.4 11.7 8.3 19.8 17.6 29 5.9 5.9 10.1 9 15.6 11.7 14.2 7 12.9 6.9 91.3 6.6 69.5-.3 70.3-.3 76-2.5 17.3-6.6 30.3-17.7 37.4-32 7.5-14.9 7.4-13.9 7.1-92.3-.3-68.8-.3-69.6-2.5-76-3.3-9.6-9-18.6-16.3-26-7.6-7.5-14.8-12-25.2-15.8l-7.3-2.7-69.5-.2c-56.7-.1-70.7.1-76 1.2zm95 39.9c39.6 9.5 66 42.4 66 82.1 0 32.6-17.1 60.1-46.5 74.6-14.9 7.4-23 9.2-40.5 9.2-17.3 0-25.5-1.8-39.7-8.8A85.66 85.66 0 0 1 40.4 145c-2.5-9.1-2.5-31.9 0-41 9.3-33.7 34.8-56.6 70.4-63 6.9-1.3 27.7-.5 35.2 1.4z\"/><path d=\"M113.5 78.4a43.05 43.05 0 0 0-29 23.9c-10.1 21.4-4.2 47.7 13.8 61.4 1.7 1.4 2.5 2.7 2.1 3.7-.9 2.3-9.1 8.1-16.2 11.4l-6.2 2.9 3.8.7c10.4 1.7 31.4-.2 44.2-4 17.5-5.2 32.8-17.4 39.5-31.5 5-10.5 6.4-20.9 4.3-31.6-2.9-14.6-10-25.4-20.9-32-9.9-5.9-23.7-7.8-35.4-4.9z\"/></svg>"),
|
||||
Rules: []string{
|
||||
"||olvid-attachment-chunks.s3.eu-west-3.amazonaws.com^",
|
||||
"||olvid.io^",
|
||||
},
|
||||
}, {
|
||||
ID: "onlyfans",
|
||||
Name: "OnlyFans",
|
||||
@@ -2065,13 +2023,6 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||pluto.tv^",
|
||||
},
|
||||
}, {
|
||||
ID: "privacy",
|
||||
Name: "Privacy",
|
||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"-2 0 42 42\"><path fill-rule=\"evenodd\" d=\"m28.516 30.648-.857-1.386-1.935-3.136a9.853 9.853 0 0 0 2.523-3.66 9.76 9.76 0 0 0 .31-6.26 9.853 9.853 0 0 0-3.562-5.185 9.955 9.955 0 0 0-5.985-2 9.94 9.94 0 0 0-5.986 2 9.848 9.848 0 0 0-3.564 5.185 9.76 9.76 0 0 0 .31 6.26 9.853 9.853 0 0 0 2.523 3.66L5.031 37.892a.654.654 0 0 1-.312.267.665.665 0 0 1-.42.013.65.65 0 0 1-.343-.225.65.65 0 0 1-.123-.397V18.875h-.007c0-3.331 1.107-6.468 3.022-9.016a15.152 15.152 0 0 1 7.842-5.436 15.292 15.292 0 0 1 9.572.306c3 1.096 5.65 3.126 7.481 5.92a14.998 14.998 0 0 1 2.427 9.197 15.002 15.002 0 0 1-3.587 8.808 15.267 15.267 0 0 1-2.065 1.992m-9.505 3.26c1.129 0 2.284-.079 3.388-.328.979-.222 1.936-.54 2.856-.951l-.854-1.383-2.838-4.6a1.888 1.888 0 0 1 .636-2.608 6.058 6.058 0 0 0 2.487-2.953 6.02 6.02 0 0 0-1.995-7.03 6.115 6.115 0 0 0-3.68-1.225 6.12 6.12 0 0 0-3.682 1.225 6.03 6.03 0 0 0-2.185 3.178 6.008 6.008 0 0 0 .19 3.852 6.056 6.056 0 0 0 2.487 2.953 1.889 1.889 0 0 1 .637 2.607l-1.845 2.99-1.562 2.532-.278.45a14.152 14.152 0 0 0 6.24 1.292h-.002ZM8.772 39.098l-.476.772a4.468 4.468 0 0 1-2.184 1.829 4.48 4.48 0 0 1-2.846.13 4.468 4.468 0 0 1-2.364-1.592A4.404 4.404 0 0 1 0 37.552V18.875h.007c0-4.183 1.382-8.113 3.771-11.29A18.992 18.992 0 0 1 13.611.78a19.102 19.102 0 0 1 11.967.38 18.97 18.97 0 0 1 9.368 7.422 18.758 18.758 0 0 1 3.04 11.501 18.767 18.767 0 0 1-4.5 11.024 19.006 19.006 0 0 1-10.247 6.17 19.07 19.07 0 0 1-3.613.463c-.089-.003-.534.007-.613.007a19.111 19.111 0 0 1-8.257-1.867l-1.984 3.215v.001Z\" clip-rule=\"evenodd\"/></svg>"),
|
||||
Rules: []string{
|
||||
"||privacy.com.br^",
|
||||
},
|
||||
}, {
|
||||
ID: "qq",
|
||||
Name: "QQ",
|
||||
@@ -2347,15 +2298,11 @@ var blockedServices = []blockedService{{
|
||||
"||huoshanzhibo.com^",
|
||||
"||muscdn.com^",
|
||||
"||musical.ly^",
|
||||
"||p16-tiktok-*.ibyteimg.com^",
|
||||
"||pstatp.com^",
|
||||
"||snssdk.com^",
|
||||
"||tiktok.com^",
|
||||
"||tiktokcdn-us.com^",
|
||||
"||tiktokcdn.com^",
|
||||
"||tiktokv.com^",
|
||||
"||ttlivecdn.com.c.bytefcdn-oversea.com^",
|
||||
"||ttlivecdn.com^",
|
||||
},
|
||||
}, {
|
||||
ID: "tinder",
|
||||
|
||||
@@ -14,11 +14,11 @@ import (
|
||||
|
||||
// Client contains information about persistent clients.
|
||||
type Client struct {
|
||||
// upstreamConfig is the custom upstream configuration for this client. If
|
||||
// it's nil, it has not been initialized yet. If it's non-nil and empty,
|
||||
// there are no valid upstreams. If it's non-nil and non-empty, these
|
||||
// upstream must be used.
|
||||
upstreamConfig *proxy.CustomUpstreamConfig
|
||||
// upstreamConfig is the custom upstream config for this client. If
|
||||
// it's nil, it has not been initialized yet. If it's non-nil and
|
||||
// empty, there are no valid upstreams. If it's non-nil and non-empty,
|
||||
// these upstream must be used.
|
||||
upstreamConfig *proxy.UpstreamConfig
|
||||
|
||||
safeSearchConf filtering.SafeSearchConfig
|
||||
SafeSearch filtering.SafeSearch
|
||||
@@ -32,9 +32,6 @@ type Client struct {
|
||||
Tags []string
|
||||
Upstreams []string
|
||||
|
||||
UpstreamsCacheSize uint32
|
||||
UpstreamsCacheEnabled bool
|
||||
|
||||
UseOwnSettings bool
|
||||
FilteringEnabled bool
|
||||
SafeBrowsingEnabled bool
|
||||
@@ -60,7 +57,8 @@ func (c *Client) ShallowClone() (sh *Client) {
|
||||
// closeUpstreams closes the client-specific upstream config of c if any.
|
||||
func (c *Client) closeUpstreams() (err error) {
|
||||
if c.upstreamConfig != nil {
|
||||
if err = c.upstreamConfig.Close(); err != nil {
|
||||
err = c.upstreamConfig.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("closing upstreams of client %q: %w", c.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,13 +126,7 @@ func (clients *clientsContainer) Init(
|
||||
return nil
|
||||
}
|
||||
|
||||
// The clients.etcHosts may be nil even if config.Clients.Sources.HostsFile
|
||||
// is true, because of the deprecated option --no-etc-hosts.
|
||||
//
|
||||
// TODO(e.burkov): The option should probably be returned, since hosts file
|
||||
// currently used not only for clients' information enrichment, but also in
|
||||
// the filtering module and upstream addresses resolution.
|
||||
if config.Clients.Sources.HostsFile && clients.etcHosts != nil {
|
||||
if clients.etcHosts != nil {
|
||||
go clients.handleHostsUpdates()
|
||||
}
|
||||
|
||||
@@ -185,14 +179,6 @@ type clientObject struct {
|
||||
Tags []string `yaml:"tags"`
|
||||
Upstreams []string `yaml:"upstreams"`
|
||||
|
||||
// UpstreamsCacheSize is the DNS cache size (in bytes).
|
||||
//
|
||||
// TODO(d.kolyshev): Use [datasize.Bytesize].
|
||||
UpstreamsCacheSize uint32 `yaml:"upstreams_cache_size"`
|
||||
|
||||
// UpstreamsCacheEnabled indicates if the DNS cache is enabled.
|
||||
UpstreamsCacheEnabled bool `yaml:"upstreams_cache_enabled"`
|
||||
|
||||
UseGlobalSettings bool `yaml:"use_global_settings"`
|
||||
FilteringEnabled bool `yaml:"filtering_enabled"`
|
||||
ParentalEnabled bool `yaml:"parental_enabled"`
|
||||
@@ -224,8 +210,6 @@ func (clients *clientsContainer) addFromConfig(
|
||||
UseOwnBlockedServices: !o.UseGlobalBlockedServices,
|
||||
IgnoreQueryLog: o.IgnoreQueryLog,
|
||||
IgnoreStatistics: o.IgnoreStatistics,
|
||||
UpstreamsCacheEnabled: o.UpstreamsCacheEnabled,
|
||||
UpstreamsCacheSize: o.UpstreamsCacheSize,
|
||||
}
|
||||
|
||||
if o.SafeSearchConf.Enabled {
|
||||
@@ -294,8 +278,6 @@ func (clients *clientsContainer) forConfig() (objs []*clientObject) {
|
||||
UseGlobalBlockedServices: !cli.UseOwnBlockedServices,
|
||||
IgnoreQueryLog: cli.IgnoreQueryLog,
|
||||
IgnoreStatistics: cli.IgnoreStatistics,
|
||||
UpstreamsCacheEnabled: cli.UpstreamsCacheEnabled,
|
||||
UpstreamsCacheSize: cli.UpstreamsCacheSize,
|
||||
}
|
||||
|
||||
objs = append(objs, o)
|
||||
@@ -437,24 +419,18 @@ func (clients *clientsContainer) shouldCountClient(ids []string) (y bool) {
|
||||
return true
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ dnsforward.ClientsContainer = (*clientsContainer)(nil)
|
||||
|
||||
// UpstreamConfigByID implements the [dnsforward.ClientsContainer] interface for
|
||||
// *clientsContainer. upsConf is nil if the client isn't found or if the client
|
||||
// has no custom upstreams.
|
||||
func (clients *clientsContainer) UpstreamConfigByID(
|
||||
// findUpstreams returns upstreams configured for the client, identified either
|
||||
// by its IP address or its ClientID. upsConf is nil if the client isn't found
|
||||
// or if the client has no custom upstreams.
|
||||
func (clients *clientsContainer) findUpstreams(
|
||||
id string,
|
||||
bootstrap upstream.Resolver,
|
||||
) (conf *proxy.CustomUpstreamConfig, err error) {
|
||||
) (upsConf *proxy.UpstreamConfig, err error) {
|
||||
clients.lock.Lock()
|
||||
defer clients.lock.Unlock()
|
||||
|
||||
c, ok := clients.findLocked(id)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
} else if c.upstreamConfig != nil {
|
||||
return c.upstreamConfig, nil
|
||||
}
|
||||
|
||||
upstreams := stringutil.FilterOut(c.Upstreams, dnsforward.IsCommentOrEmpty)
|
||||
@@ -462,27 +438,24 @@ func (clients *clientsContainer) UpstreamConfigByID(
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var upsConf *proxy.UpstreamConfig
|
||||
upsConf, err = proxy.ParseUpstreamsConfig(
|
||||
if c.upstreamConfig != nil {
|
||||
return c.upstreamConfig, nil
|
||||
}
|
||||
|
||||
var conf *proxy.UpstreamConfig
|
||||
conf, err = proxy.ParseUpstreamsConfig(
|
||||
upstreams,
|
||||
&upstream.Options{
|
||||
Bootstrap: bootstrap,
|
||||
Bootstrap: config.DNS.BootstrapDNS,
|
||||
Timeout: config.DNS.UpstreamTimeout.Duration,
|
||||
HTTPVersions: dnsforward.UpstreamHTTPVersions(config.DNS.UseHTTP3Upstreams),
|
||||
PreferIPv6: config.DNS.BootstrapPreferIPv6,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conf = proxy.NewCustomUpstreamConfig(
|
||||
upsConf,
|
||||
c.UpstreamsCacheEnabled,
|
||||
int(c.UpstreamsCacheSize),
|
||||
config.DNS.EDNSClientSubnet.Enabled,
|
||||
)
|
||||
c.upstreamConfig = conf
|
||||
|
||||
return conf, nil
|
||||
@@ -699,6 +672,10 @@ func (clients *clientsContainer) Del(name string) (ok bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
if err := c.closeUpstreams(); err != nil {
|
||||
log.Error("client container: removing client %s: %s", name, err)
|
||||
}
|
||||
|
||||
clients.del(c)
|
||||
|
||||
return true
|
||||
@@ -706,14 +683,10 @@ func (clients *clientsContainer) Del(name string) (ok bool) {
|
||||
|
||||
// del removes c from the indexes. clients.lock is expected to be locked.
|
||||
func (clients *clientsContainer) del(c *Client) {
|
||||
if err := c.closeUpstreams(); err != nil {
|
||||
log.Error("client container: removing client %s: %s", c.Name, err)
|
||||
}
|
||||
|
||||
// Update the name index.
|
||||
// update Name index
|
||||
delete(clients.list, c.Name)
|
||||
|
||||
// Update the ID index.
|
||||
// update ID index
|
||||
for _, id := range c.IDs {
|
||||
delete(clients.idIndex, id)
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ func TestClientsAddExisting(t *testing.T) {
|
||||
|
||||
clients.dhcp = dhcpServer
|
||||
|
||||
err = dhcpServer.AddStaticLease(&dhcpsvc.Lease{
|
||||
err = dhcpServer.AddStaticLease(&dhcpd.Lease{
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: ip,
|
||||
Hostname: "testhost",
|
||||
@@ -355,11 +355,13 @@ func TestClientsCustomUpstream(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
upsConf, err := clients.UpstreamConfigByID("1.2.3.4", net.DefaultResolver)
|
||||
assert.Nil(t, upsConf)
|
||||
config, err := clients.findUpstreams("1.2.3.4")
|
||||
assert.Nil(t, config)
|
||||
assert.NoError(t, err)
|
||||
|
||||
upsConf, err = clients.UpstreamConfigByID("1.1.1.1", net.DefaultResolver)
|
||||
require.NotNil(t, upsConf)
|
||||
config, err = clients.findUpstreams("1.1.1.1")
|
||||
require.NotNil(t, config)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, config.Upstreams, 1)
|
||||
assert.Len(t, config.DomainReservedUpstreams, 1)
|
||||
}
|
||||
|
||||
@@ -174,12 +174,6 @@ func (clients *clientsContainer) jsonToClient(cj clientJSON, prev *Client) (c *C
|
||||
return nil, fmt.Errorf("validating blocked services: %w", err)
|
||||
}
|
||||
|
||||
var upsCacheEnabled bool
|
||||
var upsCacheSize uint32
|
||||
if prev != nil {
|
||||
upsCacheEnabled, upsCacheSize = prev.UpstreamsCacheEnabled, prev.UpstreamsCacheSize
|
||||
}
|
||||
|
||||
c = &Client{
|
||||
safeSearchConf: safeSearchConf,
|
||||
|
||||
@@ -198,8 +192,6 @@ func (clients *clientsContainer) jsonToClient(cj clientJSON, prev *Client) (c *C
|
||||
UseOwnBlockedServices: !cj.UseGlobalBlockedServices,
|
||||
IgnoreQueryLog: ignoreQueryLog,
|
||||
IgnoreStatistics: ignoreStatistics,
|
||||
UpstreamsCacheEnabled: upsCacheEnabled,
|
||||
UpstreamsCacheSize: upsCacheSize,
|
||||
}
|
||||
|
||||
if safeSearchConf.Enabled {
|
||||
|
||||
@@ -115,8 +115,6 @@ type configuration struct {
|
||||
// Theme is a UI theme for current user.
|
||||
Theme Theme `yaml:"theme"`
|
||||
|
||||
// TODO(a.garipov): Make DNS and the fields below pointers and validate
|
||||
// and/or reset on explicit nulling.
|
||||
DNS dnsConfig `yaml:"dns"`
|
||||
TLS tlsConfigSettings `yaml:"tls"`
|
||||
QueryLog queryLogConfig `yaml:"querylog"`
|
||||
@@ -216,21 +214,18 @@ type dnsConfig struct {
|
||||
// DNS64Prefixes is the list of NAT64 prefixes to be used for DNS64.
|
||||
DNS64Prefixes []netip.Prefix `yaml:"dns64_prefixes"`
|
||||
|
||||
// ServeHTTP3 defines if HTTP/3 is allowed for incoming requests.
|
||||
// ServeHTTP3 defines if HTTP/3 is be allowed for incoming requests.
|
||||
//
|
||||
// TODO(a.garipov): Add to the UI when HTTP/3 support is no longer
|
||||
// experimental.
|
||||
ServeHTTP3 bool `yaml:"serve_http3"`
|
||||
|
||||
// UseHTTP3Upstreams defines if HTTP/3 is allowed for DNS-over-HTTPS
|
||||
// UseHTTP3Upstreams defines if HTTP/3 is be allowed for DNS-over-HTTPS
|
||||
// upstreams.
|
||||
//
|
||||
// TODO(a.garipov): Add to the UI when HTTP/3 support is no longer
|
||||
// experimental.
|
||||
UseHTTP3Upstreams bool `yaml:"use_http3_upstreams"`
|
||||
|
||||
// ServePlainDNS defines if plain DNS is allowed for incoming requests.
|
||||
ServePlainDNS bool `yaml:"serve_plain_dns"`
|
||||
}
|
||||
|
||||
type tlsConfigSettings struct {
|
||||
@@ -311,12 +306,10 @@ var config = &configuration{
|
||||
BindHosts: []netip.Addr{netip.IPv4Unspecified()},
|
||||
Port: defaultPortDNS,
|
||||
Config: dnsforward.Config{
|
||||
Ratelimit: 20,
|
||||
RatelimitSubnetLenIPv4: 24,
|
||||
RatelimitSubnetLenIPv6: 56,
|
||||
RefuseAny: true,
|
||||
AllServers: false,
|
||||
HandleDDR: true,
|
||||
Ratelimit: 20,
|
||||
RefuseAny: true,
|
||||
AllServers: false,
|
||||
HandleDDR: true,
|
||||
FastestTimeout: timeutil.Duration{
|
||||
Duration: fastip.DefaultPingWaitTimeout,
|
||||
},
|
||||
@@ -338,7 +331,6 @@ var config = &configuration{
|
||||
},
|
||||
UpstreamTimeout: timeutil.Duration{Duration: dnsforward.DefaultTimeout},
|
||||
UsePrivateRDNS: true,
|
||||
ServePlainDNS: true,
|
||||
},
|
||||
TLS: tlsConfigSettings{
|
||||
PortHTTPS: defaultPortHTTPS,
|
||||
|
||||
@@ -138,28 +138,28 @@ func initDNSServer(
|
||||
QueryLog: qlog,
|
||||
PrivateNets: privateNets,
|
||||
Anonymizer: anonymizer,
|
||||
DHCPServer: dhcpSrv,
|
||||
EtcHosts: Context.etcHosts,
|
||||
LocalDomain: config.DHCP.LocalDomainName,
|
||||
DHCPServer: dhcpSrv,
|
||||
})
|
||||
defer func() {
|
||||
if err != nil {
|
||||
closeDNSServer()
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
closeDNSServer()
|
||||
|
||||
return fmt.Errorf("dnsforward.NewServer: %w", err)
|
||||
}
|
||||
|
||||
Context.clients.dnsServer = Context.dnsServer
|
||||
|
||||
dnsConf, err := newServerConfig(&config.DNS, config.Clients.Sources, tlsConf, httpReg)
|
||||
dnsConf, err := newServerConfig(tlsConf, httpReg)
|
||||
if err != nil {
|
||||
closeDNSServer()
|
||||
|
||||
return fmt.Errorf("newServerConfig: %w", err)
|
||||
}
|
||||
|
||||
err = Context.dnsServer.Prepare(dnsConf)
|
||||
if err != nil {
|
||||
closeDNSServer()
|
||||
|
||||
return fmt.Errorf("dnsServer.Prepare: %w", err)
|
||||
}
|
||||
|
||||
@@ -222,37 +222,21 @@ func ipsToUDPAddrs(ips []netip.Addr, port uint16) (udpAddrs []*net.UDPAddr) {
|
||||
return udpAddrs
|
||||
}
|
||||
|
||||
// newServerConfig converts values from the configuration file into the internal
|
||||
// DNS server configuration. All arguments must not be nil.
|
||||
func newServerConfig(
|
||||
dnsConf *dnsConfig,
|
||||
clientSrcConf *clientSourcesConfig,
|
||||
tlsConf *tlsConfigSettings,
|
||||
httpReg aghhttp.RegisterFunc,
|
||||
) (newConf *dnsforward.ServerConfig, err error) {
|
||||
dnsConf := config.DNS
|
||||
hosts := aghalg.CoalesceSlice(dnsConf.BindHosts, []netip.Addr{netutil.IPv4Localhost()})
|
||||
|
||||
fwdConf := dnsConf.Config
|
||||
fwdConf.FilterHandler = applyAdditionalFiltering
|
||||
fwdConf.ClientsContainer = &Context.clients
|
||||
|
||||
newConf = &dnsforward.ServerConfig{
|
||||
UDPListenAddrs: ipsToUDPAddrs(hosts, dnsConf.Port),
|
||||
TCPListenAddrs: ipsToTCPAddrs(hosts, dnsConf.Port),
|
||||
Config: fwdConf,
|
||||
TLSConfig: newDNSTLSConfig(tlsConf, hosts),
|
||||
TLSAllowUnencryptedDoH: tlsConf.AllowUnencryptedDoH,
|
||||
UpstreamTimeout: dnsConf.UpstreamTimeout.Duration,
|
||||
TLSv12Roots: Context.tlsRoots,
|
||||
ConfigModified: onConfigModified,
|
||||
HTTPRegister: httpReg,
|
||||
LocalPTRResolvers: dnsConf.LocalPTRResolvers,
|
||||
UseDNS64: dnsConf.UseDNS64,
|
||||
DNS64Prefixes: dnsConf.DNS64Prefixes,
|
||||
UsePrivateRDNS: dnsConf.UsePrivateRDNS,
|
||||
ServeHTTP3: dnsConf.ServeHTTP3,
|
||||
UseHTTP3Upstreams: dnsConf.UseHTTP3Upstreams,
|
||||
ServePlainDNS: dnsConf.ServePlainDNS,
|
||||
UDPListenAddrs: ipsToUDPAddrs(hosts, dnsConf.Port),
|
||||
TCPListenAddrs: ipsToTCPAddrs(hosts, dnsConf.Port),
|
||||
Config: dnsConf.Config,
|
||||
ConfigModified: onConfigModified,
|
||||
HTTPRegister: httpReg,
|
||||
UseDNS64: config.DNS.UseDNS64,
|
||||
DNS64Prefixes: config.DNS.DNS64Prefixes,
|
||||
}
|
||||
|
||||
var initialAddresses []netip.Addr
|
||||
@@ -270,81 +254,79 @@ func newServerConfig(
|
||||
AddressUpdater: &Context.clients,
|
||||
InitialAddresses: initialAddresses,
|
||||
CatchPanics: true,
|
||||
UseRDNS: clientSrcConf.RDNS,
|
||||
UseWHOIS: clientSrcConf.WHOIS,
|
||||
UseRDNS: config.Clients.Sources.RDNS,
|
||||
UseWHOIS: config.Clients.Sources.WHOIS,
|
||||
}
|
||||
|
||||
newConf.DNSCryptConfig, err = newDNSCryptConfig(tlsConf, hosts)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's already wrapped by
|
||||
// newDNSCryptConfig.
|
||||
return nil, err
|
||||
if tlsConf.Enabled {
|
||||
newConf.TLSConfig = tlsConf.TLSConfig
|
||||
newConf.TLSConfig.ServerName = tlsConf.ServerName
|
||||
|
||||
if tlsConf.PortHTTPS != 0 {
|
||||
newConf.HTTPSListenAddrs = ipsToTCPAddrs(hosts, tlsConf.PortHTTPS)
|
||||
}
|
||||
|
||||
if tlsConf.PortDNSOverTLS != 0 {
|
||||
newConf.TLSListenAddrs = ipsToTCPAddrs(hosts, tlsConf.PortDNSOverTLS)
|
||||
}
|
||||
|
||||
if tlsConf.PortDNSOverQUIC != 0 {
|
||||
newConf.QUICListenAddrs = ipsToUDPAddrs(hosts, tlsConf.PortDNSOverQUIC)
|
||||
}
|
||||
|
||||
if tlsConf.PortDNSCrypt != 0 {
|
||||
newConf.DNSCryptConfig, err = newDNSCrypt(hosts, *tlsConf)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's already wrapped by
|
||||
// newDNSCrypt.
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newConf.TLSv12Roots = Context.tlsRoots
|
||||
newConf.TLSAllowUnencryptedDoH = tlsConf.AllowUnencryptedDoH
|
||||
|
||||
newConf.FilterHandler = applyAdditionalFiltering
|
||||
newConf.GetCustomUpstreamByClient = Context.clients.findUpstreams
|
||||
|
||||
newConf.LocalPTRResolvers = dnsConf.LocalPTRResolvers
|
||||
newConf.UpstreamTimeout = dnsConf.UpstreamTimeout.Duration
|
||||
|
||||
newConf.UsePrivateRDNS = dnsConf.UsePrivateRDNS
|
||||
newConf.ServeHTTP3 = dnsConf.ServeHTTP3
|
||||
newConf.UseHTTP3Upstreams = dnsConf.UseHTTP3Upstreams
|
||||
|
||||
return newConf, nil
|
||||
}
|
||||
|
||||
// newDNSTLSConfig converts values from the configuration file into the internal
|
||||
// TLS settings for the DNS server. tlsConf must not be nil.
|
||||
func newDNSTLSConfig(conf *tlsConfigSettings, addrs []netip.Addr) (dnsConf dnsforward.TLSConfig) {
|
||||
if !conf.Enabled {
|
||||
return dnsforward.TLSConfig{}
|
||||
func newDNSCrypt(hosts []netip.Addr, tlsConf tlsConfigSettings) (dnscc dnsforward.DNSCryptConfig, err error) {
|
||||
if tlsConf.DNSCryptConfigFile == "" {
|
||||
return dnscc, errors.Error("no dnscrypt_config_file")
|
||||
}
|
||||
|
||||
dnsConf = conf.TLSConfig
|
||||
dnsConf.ServerName = conf.ServerName
|
||||
|
||||
if conf.PortHTTPS != 0 {
|
||||
dnsConf.HTTPSListenAddrs = ipsToTCPAddrs(addrs, conf.PortHTTPS)
|
||||
}
|
||||
|
||||
if conf.PortDNSOverTLS != 0 {
|
||||
dnsConf.TLSListenAddrs = ipsToTCPAddrs(addrs, conf.PortDNSOverTLS)
|
||||
}
|
||||
|
||||
if conf.PortDNSOverQUIC != 0 {
|
||||
dnsConf.QUICListenAddrs = ipsToUDPAddrs(addrs, conf.PortDNSOverQUIC)
|
||||
}
|
||||
|
||||
return dnsConf
|
||||
}
|
||||
|
||||
// newDNSCryptConfig converts values from the configuration file into the
|
||||
// internal DNSCrypt settings for the DNS server. conf must not be nil.
|
||||
func newDNSCryptConfig(
|
||||
conf *tlsConfigSettings,
|
||||
addrs []netip.Addr,
|
||||
) (dnsCryptConf dnsforward.DNSCryptConfig, err error) {
|
||||
if !conf.Enabled || conf.PortDNSCrypt == 0 {
|
||||
return dnsforward.DNSCryptConfig{}, nil
|
||||
}
|
||||
|
||||
if conf.DNSCryptConfigFile == "" {
|
||||
return dnsforward.DNSCryptConfig{}, errors.Error("no dnscrypt_config_file")
|
||||
}
|
||||
|
||||
f, err := os.Open(conf.DNSCryptConfigFile)
|
||||
f, err := os.Open(tlsConf.DNSCryptConfigFile)
|
||||
if err != nil {
|
||||
return dnsforward.DNSCryptConfig{}, fmt.Errorf("opening dnscrypt config: %w", err)
|
||||
return dnscc, fmt.Errorf("opening dnscrypt config: %w", err)
|
||||
}
|
||||
defer func() { err = errors.WithDeferred(err, f.Close()) }()
|
||||
|
||||
rc := &dnscrypt.ResolverConfig{}
|
||||
err = yaml.NewDecoder(f).Decode(rc)
|
||||
if err != nil {
|
||||
return dnsforward.DNSCryptConfig{}, fmt.Errorf("decoding dnscrypt config: %w", err)
|
||||
return dnscc, fmt.Errorf("decoding dnscrypt config: %w", err)
|
||||
}
|
||||
|
||||
cert, err := rc.CreateCert()
|
||||
if err != nil {
|
||||
return dnsforward.DNSCryptConfig{}, fmt.Errorf("creating dnscrypt cert: %w", err)
|
||||
return dnscc, fmt.Errorf("creating dnscrypt cert: %w", err)
|
||||
}
|
||||
|
||||
return dnsforward.DNSCryptConfig{
|
||||
ResolverCert: cert,
|
||||
ProviderName: rc.ProviderName,
|
||||
UDPListenAddrs: ipsToUDPAddrs(addrs, conf.PortDNSCrypt),
|
||||
TCPListenAddrs: ipsToTCPAddrs(addrs, conf.PortDNSCrypt),
|
||||
UDPListenAddrs: ipsToUDPAddrs(hosts, tlsConf.PortDNSCrypt),
|
||||
TCPListenAddrs: ipsToTCPAddrs(hosts, tlsConf.PortDNSCrypt),
|
||||
Enabled: true,
|
||||
}, nil
|
||||
}
|
||||
@@ -360,36 +342,34 @@ func getDNSEncryption() (de dnsEncryption) {
|
||||
|
||||
Context.tls.WriteDiskConfig(&tlsConf)
|
||||
|
||||
if !tlsConf.Enabled || len(tlsConf.ServerName) == 0 {
|
||||
return dnsEncryption{}
|
||||
}
|
||||
if tlsConf.Enabled && len(tlsConf.ServerName) != 0 {
|
||||
hostname := tlsConf.ServerName
|
||||
if tlsConf.PortHTTPS != 0 {
|
||||
addr := hostname
|
||||
if p := tlsConf.PortHTTPS; p != defaultPortHTTPS {
|
||||
addr = netutil.JoinHostPort(addr, p)
|
||||
}
|
||||
|
||||
hostname := tlsConf.ServerName
|
||||
if tlsConf.PortHTTPS != 0 {
|
||||
addr := hostname
|
||||
if p := tlsConf.PortHTTPS; p != defaultPortHTTPS {
|
||||
addr = netutil.JoinHostPort(addr, p)
|
||||
de.https = (&url.URL{
|
||||
Scheme: "https",
|
||||
Host: addr,
|
||||
Path: "/dns-query",
|
||||
}).String()
|
||||
}
|
||||
|
||||
de.https = (&url.URL{
|
||||
Scheme: "https",
|
||||
Host: addr,
|
||||
Path: "/dns-query",
|
||||
}).String()
|
||||
}
|
||||
if p := tlsConf.PortDNSOverTLS; p != 0 {
|
||||
de.tls = (&url.URL{
|
||||
Scheme: "tls",
|
||||
Host: netutil.JoinHostPort(hostname, p),
|
||||
}).String()
|
||||
}
|
||||
|
||||
if p := tlsConf.PortDNSOverTLS; p != 0 {
|
||||
de.tls = (&url.URL{
|
||||
Scheme: "tls",
|
||||
Host: netutil.JoinHostPort(hostname, p),
|
||||
}).String()
|
||||
}
|
||||
|
||||
if p := tlsConf.PortDNSOverQUIC; p != 0 {
|
||||
de.quic = (&url.URL{
|
||||
Scheme: "quic",
|
||||
Host: netutil.JoinHostPort(hostname, p),
|
||||
}).String()
|
||||
if p := tlsConf.PortDNSOverQUIC; p != 0 {
|
||||
de.quic = (&url.URL{
|
||||
Scheme: "quic",
|
||||
Host: netutil.JoinHostPort(hostname, p),
|
||||
}).String()
|
||||
}
|
||||
}
|
||||
|
||||
return de
|
||||
@@ -474,7 +454,7 @@ func reconfigureDNSServer() (err error) {
|
||||
tlsConf := &tlsConfigSettings{}
|
||||
Context.tls.WriteDiskConfig(tlsConf)
|
||||
|
||||
newConf, err := newServerConfig(&config.DNS, config.Clients.Sources, tlsConf, httpRegister)
|
||||
newConf, err := newServerConfig(tlsConf, httpRegister)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generating forwarding dns server config: %w", err)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
@@ -159,7 +160,7 @@ func setupContext(opts options) (err error) {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if !opts.noEtcHosts {
|
||||
if !opts.noEtcHosts && config.Clients.Sources.HostsFile {
|
||||
err = setupHostsContainer()
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
@@ -238,13 +239,13 @@ func setupHostsContainer() (err error) {
|
||||
)
|
||||
if err != nil {
|
||||
closeErr := hostsWatcher.Close()
|
||||
if errors.Is(err, aghnet.ErrNoHostsPaths) {
|
||||
if errors.Is(err, aghnet.ErrNoHostsPaths) && closeErr == nil {
|
||||
log.Info("warning: initing hosts container: %s", err)
|
||||
|
||||
return closeErr
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.Join(fmt.Errorf("initializing hosts container: %w", err), closeErr)
|
||||
return errors.WithDeferred(fmt.Errorf("initing hosts container: %w", err), closeErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -293,13 +294,19 @@ func initContextClients() (err error) {
|
||||
arpDB = arpdb.New()
|
||||
}
|
||||
|
||||
return Context.clients.Init(
|
||||
err = Context.clients.Init(
|
||||
config.Clients.Persistent,
|
||||
Context.dhcpServer,
|
||||
Context.etcHosts,
|
||||
arpDB,
|
||||
config.Filtering,
|
||||
)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupBindOpts overrides bind host/port from the opts.
|
||||
@@ -369,15 +376,11 @@ func setupDNSFilteringConf(conf *filtering.Config) (err error) {
|
||||
|
||||
upsOpts := &upstream.Options{
|
||||
Timeout: dnsTimeout,
|
||||
Bootstrap: upstream.StaticResolver{
|
||||
// 94.140.14.15.
|
||||
netip.AddrFrom4([4]byte{94, 140, 14, 15}),
|
||||
// 94.140.14.16.
|
||||
netip.AddrFrom4([4]byte{94, 140, 14, 16}),
|
||||
// 2a10:50c0::bad1:ff.
|
||||
netip.AddrFrom16([16]byte{42, 16, 80, 192, 12: 186, 209, 0, 255}),
|
||||
// 2a10:50c0::bad2:ff.
|
||||
netip.AddrFrom16([16]byte{42, 16, 80, 192, 12: 186, 210, 0, 255}),
|
||||
ServerIPAddrs: []net.IP{
|
||||
{94, 140, 14, 15},
|
||||
{94, 140, 15, 16},
|
||||
net.ParseIP("2a10:50c0::bad1:ff"),
|
||||
net.ParseIP("2a10:50c0::bad2:ff"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user