Compare commits

..

2 Commits

Author SHA1 Message Date
Stanislav Chzhen
b34a8c169c filtering: imp tests 2023-05-15 10:33:52 +03:00
Stanislav Chzhen
1f2ba07eae filtering: wildcard interference 2023-05-12 12:25:33 +03:00
251 changed files with 6122 additions and 14127 deletions

View File

@@ -10,60 +10,52 @@
- 'label': > - 'label': >
I have checked the I have checked the
[Wiki](https://github.com/AdguardTeam/AdGuardHome/wiki) and [Wiki](https://github.com/AdguardTeam/AdGuardHome/wiki) and
[Discussions](https://github.com/AdguardTeam/AdGuardHome/discussions/categories/q-a) [Discussions](https://github.com/AdguardTeam/AdGuardHome/discussions)
and found no answer and found no answer
'required': true 'required': true
- 'label': > - 'label': >
I have searched other issues and found no duplicates I have searched other issues and found no duplicates
'required': true 'required': true
- 'label': > - 'label': >
I want to report a bug and not [ask a question or ask for I want to report a bug and not ask a question
help](https://github.com/AdguardTeam/AdGuardHome/discussions/categories/q-a)
'required': true
- 'label': >
I have set up AdGuard Home correctly and [configured clients to
use it](https://github.com/AdguardTeam/AdGuardHome/wiki/Clients).
(Use the
[Discussions](https://github.com/AdguardTeam/AdGuardHome/discussions/categories/q-a)
for help with installing and configuring clients.)
'required': true 'required': true
'id': 'prerequisites' 'id': 'prerequisites'
'type': 'checkboxes' 'type': 'checkboxes'
- 'attributes': - 'attributes':
'description': 'On which Platform does the issue occur?' 'description': 'On which operating system type does the issue occur?'
'label': 'Platform (OS and CPU architecture)' 'label': 'Operating system type'
# NOTE: Keep the 386 at the bottom for each OS, because a lot of people
# Seem to confuse them with AMD64, which is what they actually need.
'options': 'options':
- 'Darwin (aka macOS), AMD64 (aka x86_64)' - 'FreeBSD'
- 'Darwin (aka macOS), ARM64' - 'Linux, OpenWrt'
- 'FreeBSD, AMD64 (aka x86_64)' - 'Linux, Other (please mention the version in the description)'
- 'FreeBSD, ARM64' - 'macOS (aka Darwin)'
- 'FreeBSD, ARMv5' - 'OpenBSD'
- 'FreeBSD, ARMv6' - 'Windows'
- 'FreeBSD, ARMv7' - 'Other (please mention in the description)'
- 'FreeBSD, 32-bit Intel (aka 386)'
- 'Linux, AMD64 (aka x86_64)'
- 'Linux, ARM64'
- 'Linux, ARMv5'
- 'Linux, ARMv6'
- 'Linux, ARMv7'
- 'Linux, MIPS LE'
- 'Linux, MIPS'
- 'Linux, MIPS64 LE'
- 'Linux, MIPS64'
- 'Linux, PPC64 LE'
- 'Linux, 32-bit Intel (aka 386)'
- 'OpenBSD, AMD64 (aka x86_64)'
- 'OpenBSD, ARM64'
- 'Windows, AMD64 (aka x86_64)'
- 'Windows, ARM64'
- 'Windows, 32-bit Intel (aka 386)'
- 'Custom (please mention in the description)'
'id': 'os' 'id': 'os'
'type': 'dropdown' 'type': 'dropdown'
'validations': 'validations':
'required': true 'required': true
- 'attributes':
'description': 'On which CPU architecture does the issue occur?'
'label': 'CPU architecture'
'options':
- 'AMD64'
- 'x86'
- '64-bit ARM'
- 'ARMv5'
- 'ARMv6'
- 'ARMv7'
- '64-bit MIPS'
- '64-bit MIPS LE'
- '32-bit MIPS'
- '32-bit MIPS LE'
- '64-bit PowerPC LE'
- 'Other (please mention in the description)'
'id': 'arch'
'type': 'dropdown'
'validations':
'required': true
- 'attributes': - 'attributes':
'description': 'How did you install AdGuard Home?' 'description': 'How did you install AdGuard Home?'
'label': 'Installation' 'label': 'Installation'
@@ -71,7 +63,7 @@
- 'GitHub releases or script from README' - 'GitHub releases or script from README'
- 'Docker' - 'Docker'
- 'Snapcraft' - 'Snapcraft'
- 'Custom package (OpenWrt, HomeAssistant, etc; please mention in the description)' - 'Custom port'
- 'Other (please mention in the description)' - 'Other (please mention in the description)'
'id': 'install' 'id': 'install'
'type': 'dropdown' 'type': 'dropdown'
@@ -97,57 +89,21 @@
'validations': 'validations':
'required': true 'required': true
- 'attributes': - 'attributes':
'description': > 'description': 'Please describe the bug'
Please describe what you did. An `nslookup` or a `dig` command is 'label': 'Description'
the best way. For crashes, please provide a full failure log.
'label': 'Action'
'value': | 'value': |
```sh #### What did you do?
nslookup -debug -type=a 'www.example.com' '$YOUR_AGH_ADDRESS'
``` #### Expected result
'id': 'failing_action'
#### Actual result
#### Screenshots (if applicable)
#### Additional information
'id': 'description'
'type': 'textarea' 'type': 'textarea'
'validations': 'validations':
'required': true 'required': true
- 'attributes': 'description': 'File a bug report'
'description': >
What did you expect to see? Please add a description and/or
screenshots, if applicable.
'label': 'Expected result'
'placeholder': >
What did you expect to see?
'id': 'expected'
'type': 'textarea'
'validations':
'required': true
- 'attributes':
'description': >
What happened instead? Please add a description and/or screenshots,
if applicable.
'label': 'Actual result'
'placeholder': >
What did you see instead?
'id': 'result'
'type': 'textarea'
'validations':
'required': true
- 'attributes':
'description': >
Please add additional information, such as non-standard OS or port,
here. You can also put screenshots here, if applicable. For
example, it is better to copy and paste text from a terminal instead
of posting a screenshot of the terminal.
'label': 'Additional information and/or screenshots'
'placeholder': >
Additional OS information, screenshots of the UI, etc.
'id': 'additional'
'type': 'textarea'
'validations':
'required': false
# NOTE: GitHub limits the description length to 200 characters. Also, Markdown
# doesn't work here.
'description': |
For help, use the Discussions section instead. Write the title in English
to make it easier for other people to search for duplicates. (Any language
is fine in the body.)
'name': 'Bug' 'name': 'Bug'

View File

@@ -23,36 +23,19 @@
'id': 'prerequisites' 'id': 'prerequisites'
'type': 'checkboxes' 'type': 'checkboxes'
- 'attributes': - 'attributes':
'description': 'Please describe the problem you are trying to solve' 'description': 'Please describe the request'
'label': 'The problem' 'label': 'Description'
'placeholder': > 'value': |
Please describe the problem you are trying to solve #### What problem are you trying to solve?
'id': 'problem'
#### Proposed solution
#### Alternatives considered
#### Additional information
'id': 'description'
'type': 'textarea' 'type': 'textarea'
'validations': 'validations':
'required': true 'required': true
- 'attributes': 'description': 'Suggest a feature or an enhancement for AdGuard Home'
'description': 'What feature are you proposing to solve this problem?'
'label': 'Proposed solution'
'placeholder': >
What feature are you proposing to solve this problem?
'id': 'proposed_solution'
'type': 'textarea'
'validations':
'required': true
- 'attributes':
'label': 'Alternatives considered and additional information'
'placeholder': >
Are there any other ways to solve the problem?
'id': 'additional'
'type': 'textarea'
'validations':
'required': false
# NOTE: GitHub limits the description length to 200 characters. Also, Markdown
# doesn't work here.
'description': |
Write the title in English to make it easier for other people to search for
duplicates. (Any language is fine in the body.)
'labels':
- 'feature request'
'name': 'Feature request or enhancement' 'name': 'Feature request or enhancement'

View File

@@ -1,20 +0,0 @@
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.
2. This isn't a localization fix; please send those to our
[CrowdIn](https://crowdin.com/project/adguard-applications/en#/adguard-home)
page.
3. Your code follows our
[code guidelines](https://github.com/AdguardTeam/CodeGuidelines/blob/master/Go/Go.md).
Add a short description here. The description should include:
1. Which issue this PR closes (`Closes #NNNN.`) or updates (`Updates
#NNNN.`).
2. A short description of how the change achieves that.
Do not forget to remove these instructions.

View File

@@ -1,7 +1,7 @@
'name': 'build' 'name': 'build'
'env': 'env':
'GO_VERSION': '1.20.7' 'GO_VERSION': '1.19.8'
'NODE_VERSION': '14' 'NODE_VERSION': '14'
'on': 'on':

View File

@@ -1,7 +1,7 @@
'name': 'lint' 'name': 'lint'
'env': 'env':
'GO_VERSION': '1.20.7' 'GO_VERSION': '1.19.8'
'on': 'on':
'push': 'push':

View File

@@ -1,18 +0,0 @@
'name': 'potential-duplicates'
'on':
'issues':
'types':
- 'opened'
'jobs':
'run':
'runs-on': 'ubuntu-latest'
'steps':
- 'uses': 'wow-actions/potential-duplicates@v1'
'with':
'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}'
'state': 'all'
'threshold': 0.6
'comment': |
Potential duplicates: {{#issues}}
* [#{{ number }}] {{ title }} ({{ accuracy }}%)
{{/issues}}

6
.gitignore vendored
View File

@@ -9,7 +9,6 @@
*.db *.db
*.log *.log
*.snap *.snap
*.test
/agh-backup/ /agh-backup/
/bin/ /bin/
/build/* /build/*
@@ -17,13 +16,10 @@
/dist/ /dist/
/filtering/tests/filtering.TestLotsOfRules*.pprof /filtering/tests/filtering.TestLotsOfRules*.pprof
/filtering/tests/top-1m.csv /filtering/tests/top-1m.csv
/internal/next/AdGuardHome.yaml
/launchpad_credentials /launchpad_credentials
/querylog.json* /querylog.json*
/snapcraft_login /snapcraft_login
AdGuardHome AdGuardHome*
AdGuardHome.exe
AdGuardHome.yaml*
coverage.txt coverage.txt
node_modules/ node_modules/

View File

@@ -14,381 +14,14 @@ and this project adheres to
<!-- <!--
## [v0.108.0] - TBA ## [v0.108.0] - TBA
## [v0.107.37] - 2023-08-16 (APPROX.) ## [v0.107.30] - 2023-04-26 (APPROX.)
See also the [v0.107.37 GitHub milestone][ms-v0.107.37].
[ms-v0.107.37]: https://github.com/AdguardTeam/AdGuardHome/milestone/72?closed=1
NOTE: Add new changes BELOW THIS COMMENT.
-->
### Added
- The ability to set the port for the `pprof` debug API, see configuration
changes below.
### Changed
#### Configuration Changes
In this release, the schema version has changed from 24 to 25.
- Property `debug_pprof` which used to setup profiling HTTP handler, is now
moved to the new `pprof` object under `http` section. The new object contains
properties `enabled` and `port`:
```yaml
# BEFORE:
'debug_pprof': true
# AFTER:
'http':
'pprof':
'enabled': true
'port': 6060
```
Note that the new default `6060` is used as default. To rollback this change,
remove the new object `pprof`, set back `debug_pprof`, and change the
`schema_version` back to `24`.
<!--
NOTE: Add new changes ABOVE THIS COMMENT.
-->
## [v0.107.36] - 2023-08-02
See also the [v0.107.36 GitHub milestone][ms-v0.107.36].
### Security
- Go version has been updated to prevent the possibility of exploiting the
CVE-2023-29409 Go vulnerability fixed in [Go 1.20.7][go-1.20.7].
### Deprecated
- Go 1.20 support. Future versions will require at least Go 1.21 to build.
### Fixed
- Inability to block queries for the root domain, such as `NS .` queries, using
the *Disallowed domains* feature on the *DNS settings* page ([#6049]). Users
who want to block `.` queries should use the `|.^` AdBlock rule or a similar
regular expression.
- Client hostnames not resolving when upstream server responds with zero-TTL
records ([#6046]).
[#6046]: https://github.com/AdguardTeam/AdGuardHome/issues/6046
[#6049]: https://github.com/AdguardTeam/AdGuardHome/issues/6049
[go-1.20.7]: https://groups.google.com/g/golang-announce/c/X0b6CsSAaYI/m/Efv5DbZ9AwAJ
[ms-v0.107.36]: https://github.com/AdguardTeam/AdGuardHome/milestone/71?closed=1
## [v0.107.35] - 2023-07-26
See also the [v0.107.35 GitHub milestone][ms-v0.107.35].
### Changed
- Improved reliability filtering-rule list updates on Unix systems.
### Fixed
- Occasional client information lookup failures that could lead to the DNS
server getting stuck ([#6006]).
- `bufio.Scanner: token too long` and other errors when trying to add
filtering-rule lists with lines over 1024 bytes long or containing cosmetic
rules ([#6003]).
### Removed
- Default exposure of the non-standard ports 784 and 8853 for DNS-over-QUIC in
the `Dockerfile`.
[#6003]: https://github.com/AdguardTeam/AdGuardHome/issues/6003
[#6006]: https://github.com/AdguardTeam/AdGuardHome/issues/6006
[ms-v0.107.35]: https://github.com/AdguardTeam/AdGuardHome/milestone/70?closed=1
## [v0.107.34] - 2023-07-12
See also the [v0.107.34 GitHub milestone][ms-v0.107.34].
### Security
- Go version has been updated to prevent the possibility of exploiting the
CVE-2023-29406 Go vulnerability fixed in [Go 1.19.11][go-1.19.11].
### Added
- Ability to ignore queries for the root domain, such as `NS .` queries
([#5990]).
### Changed
- Improved CPU and RAM consumption during updates of filtering-rule lists.
#### Configuration Changes
In this release, the schema version has changed from 23 to 24.
- Properties starting with `log_`, and `verbose` property, which used to set up
logging are now moved to the new object `log` containing new properties
`file`, `max_backups`, `max_size`, `max_age`, `compress`, `local_time`, and
`verbose`:
```yaml
# BEFORE:
'log_file': ""
'log_max_backups': 0
'log_max_size': 100
'log_max_age': 3
'log_compress': false
'log_localtime': false
'verbose': false
# AFTER:
'log':
'file': ""
'max_backups': 0
'max_size': 100
'max_age': 3
'compress': false
'local_time': false
'verbose': false
```
To rollback this change, remove the new object `log`, set back `log_` and
`verbose` properties and change the `schema_version` back to `23`.
### Deprecated
- Default exposure of the non-standard ports 784 and 8853 for DNS-over-QUIC in
the `Dockerfile`.
### Fixed
- Two unspecified IPs when a host is blocked in two filter lists ([#5972]).
- Incorrect setting of Parental Control cache size.
- Excessive RAM and CPU consumption by Safe Browsing and Parental Control
filters ([#5896]).
### Removed
- The `HEALTHCHECK` section and the use of `tini` in the `ENTRYPOINT` section in
`Dockerfile` ([#5939]). They caused a lot of issues, especially with tools
like `docker-compose` and `podman`.
**NOTE:** Some Docker tools may cache `ENTRYPOINT` sections, so some users may
be required to backup their configuration, stop the container, purge the old
image, and reload it from scratch.
[#5896]: https://github.com/AdguardTeam/AdGuardHome/issues/5896
[#5972]: https://github.com/AdguardTeam/AdGuardHome/issues/5972
[#5990]: https://github.com/AdguardTeam/AdGuardHome/issues/5990
[go-1.19.11]: https://groups.google.com/g/golang-announce/c/2q13H6LEEx0/m/sduSepLLBwAJ
[ms-v0.107.34]: https://github.com/AdguardTeam/AdGuardHome/milestone/69?closed=1
## [v0.107.33] - 2023-07-03
See also the [v0.107.33 GitHub milestone][ms-v0.107.33].
### Added
- The new command-line flag `--web-addr` is the address to serve the web UI on,
in the host:port format.
- The ability to set inactivity periods for filtering blocked services, both
globally and per client, in the configuration file ([#951]). The UI changes
are coming in the upcoming releases.
- The ability to edit rewrite rules via `PUT /control/rewrite/update` HTTP API
and the Web UI ([#1577]).
### Changed
#### Configuration Changes
In this release, the schema version has changed from 20 to 23.
- Properties `bind_host`, `bind_port`, and `web_session_ttl` which used to setup
web UI binding configuration, are now moved to a new object `http` containing
new properties `address` and `session_ttl`:
```yaml
# BEFORE:
'bind_host': '1.2.3.4'
'bind_port': 8080
'web_session_ttl': 720
# AFTER:
'http':
'address': '1.2.3.4:8080'
'session_ttl': '720h'
```
Note that the new `http.session_ttl` property is now a duration string. To
rollback this change, remove the new object `http`, set back `bind_host`,
`bind_port`, `web_session_ttl`, and change the `schema_version` back to `22`.
- Property `clients.persistent.blocked_services`, which in schema versions 21
and earlier used to be a list containing ids of blocked services, is now an
object containing ids and schedule for blocked services:
```yaml
# BEFORE:
'clients':
'persistent':
- 'name': 'client-name'
'blocked_services':
- id_1
- id_2
# AFTER:
'clients':
'persistent':
- 'name': client-name
'blocked_services':
'ids':
- id_1
- id_2
'schedule':
'time_zone': 'Local'
'sun':
'start': '0s'
'end': '24h'
'mon':
'start': '1h'
'end': '23h'
```
To rollback this change, replace `clients.persistent.blocked_services` object
with the list of ids of blocked services and change the `schema_version` back
to `21`.
- Property `dns.blocked_services`, which in schema versions 20 and earlier used
to be a list containing ids of blocked services, is now an object containing
ids and schedule for blocked services:
```yaml
# BEFORE:
'blocked_services':
- id_1
- id_2
# AFTER:
'blocked_services':
'ids':
- id_1
- id_2
'schedule':
'time_zone': 'Local'
'sun':
'start': '0s'
'end': '24h'
'mon':
'start': '10m'
'end': '23h30m'
'tue':
'start': '20m'
'end': '23h'
'wed':
'start': '30m'
'end': '22h30m'
'thu':
'start': '40m'
'end': '22h'
'fri':
'start': '50m'
'end': '21h30m'
'sat':
'start': '1h'
'end': '21h'
```
To rollback this change, replace `dns.blocked_services` object with the list
of ids of blocked services and change the `schema_version` back to `20`.
### Deprecated
- The `HEALTHCHECK` section and the use of `tini` in the `ENTRYPOINT` section in
`Dockerfile` ([#5939]). They cause a lot of issues, especially with tools
like `docker-compose` and `podman`, and will be removed in a future release.
- Flags `-h`, `--host`, `-p`, `--port` have been deprecated. The `-h` flag
will work as an alias for `--help`, instead of the deprecated `--host` in the
future releases.
### Fixed
- Ignoring of `/etc/hosts` file when resolving the hostnames of upstream DNS
servers ([#5902]).
- Excessive error logging when using DNS-over-QUIC ([#5285]).
- Inability to set `bind_host` in `AdGuardHome.yaml` in Docker ([#4231],
[#4235]).
- The blocklists can now be deleted properly ([#5700]).
- Queries with the question-section target `.`, for example `NS .`, are now
counted in the statistics and correctly shown in the query log ([#5910]).
- Safe Search not working with `AAAA` queries for domains that don't have `AAAA`
records ([#5913]).
[#951]: https://github.com/AdguardTeam/AdGuardHome/issues/951
[#1577]: https://github.com/AdguardTeam/AdGuardHome/issues/1577
[#4231]: https://github.com/AdguardTeam/AdGuardHome/issues/4231
[#4235]: https://github.com/AdguardTeam/AdGuardHome/pull/4235
[#5285]: https://github.com/AdguardTeam/AdGuardHome/issues/5285
[#5700]: https://github.com/AdguardTeam/AdGuardHome/issues/5700
[#5902]: https://github.com/AdguardTeam/AdGuardHome/issues/5902
[#5910]: https://github.com/AdguardTeam/AdGuardHome/issues/5910
[#5913]: https://github.com/AdguardTeam/AdGuardHome/issues/5913
[#5939]: https://github.com/AdguardTeam/AdGuardHome/discussions/5939
[ms-v0.107.33]: https://github.com/AdguardTeam/AdGuardHome/milestone/68?closed=1
## [v0.107.32] - 2023-06-13
### Fixed
- DNSCrypt upstream not resetting the client and resolver information on
dialing errors ([#5872]).
## [v0.107.31] - 2023-06-08
See also the [v0.107.31 GitHub milestone][ms-v0.107.31].
### Fixed
- Startup errors on OpenWrt ([#5872]).
- Plain-UDP upstreams always falling back to TCP, causing outages and slowdowns
([#5873], [#5874]).
[#5872]: https://github.com/AdguardTeam/AdGuardHome/issues/5872
[#5873]: https://github.com/AdguardTeam/AdGuardHome/issues/5873
[#5874]: https://github.com/AdguardTeam/AdGuardHome/issues/5874
[ms-v0.107.31]: https://github.com/AdguardTeam/AdGuardHome/milestone/67?closed=1
## [v0.107.30] - 2023-06-07
See also the [v0.107.30 GitHub milestone][ms-v0.107.30]. See also the [v0.107.30 GitHub milestone][ms-v0.107.30].
### Security [ms-v0.107.30]: https://github.com/AdguardTeam/AdGuardHome/milestone/66?closed=1
- Go version has been updated to prevent the possibility of exploiting the NOTE: Add new changes BELOW THIS COMMENT.
CVE-2023-29402, CVE-2023-29403, and CVE-2023-29404 Go vulnerabilities fixed in -->
[Go 1.19.10][go-1.19.10].
### Fixed ### Fixed
@@ -404,8 +37,9 @@ See also the [v0.107.30 GitHub milestone][ms-v0.107.30].
[#5716]: https://github.com/AdguardTeam/AdGuardHome/issues/5716 [#5716]: https://github.com/AdguardTeam/AdGuardHome/issues/5716
[go-1.19.10]: https://groups.google.com/g/golang-announce/c/q5135a9d924/m/j0ZoAJOHAwAJ <!--
[ms-v0.107.30]: https://github.com/AdguardTeam/AdGuardHome/milestone/66?closed=1 NOTE: Add new changes ABOVE THIS COMMENT.
-->
@@ -2330,18 +1964,11 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
<!-- <!--
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.37...HEAD [Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.30...HEAD
[v0.107.37]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.36...v0.107.37 [v0.107.30]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.29...v0.107.30
--> -->
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.36...HEAD [Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.29...HEAD
[v0.107.36]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.35...v0.107.36
[v0.107.35]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.34...v0.107.35
[v0.107.34]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.33...v0.107.34
[v0.107.33]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.32...v0.107.33
[v0.107.32]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.31...v0.107.32
[v0.107.31]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.30...v0.107.31
[v0.107.30]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.29...v0.107.30
[v0.107.29]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.28...v0.107.29 [v0.107.29]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.28...v0.107.29
[v0.107.28]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.27...v0.107.28 [v0.107.28]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.27...v0.107.28
[v0.107.27]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.26...v0.107.27 [v0.107.27]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.26...v0.107.27

View File

@@ -78,7 +78,7 @@ build: deps quick-build
quick-build: js-build go-build quick-build: js-build go-build
ci: deps test go-bench go-fuzz ci: deps test
deps: js-deps go-deps deps: js-deps go-deps
lint: js-lint go-lint lint: js-lint go-lint
@@ -104,10 +104,8 @@ js-deps:
js-lint: ; $(NPM) $(NPM_FLAGS) run lint js-lint: ; $(NPM) $(NPM_FLAGS) run lint
js-test: ; $(NPM) $(NPM_FLAGS) run test js-test: ; $(NPM) $(NPM_FLAGS) run test
go-bench: ; $(ENV) "$(SHELL)" ./scripts/make/go-bench.sh
go-build: ; $(ENV) "$(SHELL)" ./scripts/make/go-build.sh go-build: ; $(ENV) "$(SHELL)" ./scripts/make/go-build.sh
go-deps: ; $(ENV) "$(SHELL)" ./scripts/make/go-deps.sh go-deps: ; $(ENV) "$(SHELL)" ./scripts/make/go-deps.sh
go-fuzz: ; $(ENV) "$(SHELL)" ./scripts/make/go-fuzz.sh
go-lint: ; $(ENV) "$(SHELL)" ./scripts/make/go-lint.sh go-lint: ; $(ENV) "$(SHELL)" ./scripts/make/go-lint.sh
go-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-tools.sh go-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-tools.sh
@@ -130,10 +128,3 @@ openapi-lint: ; cd ./openapi/ && $(YARN) test
openapi-show: ; cd ./openapi/ && $(YARN) start openapi-show: ; cd ./openapi/ && $(YARN) start
txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh
# TODO(a.garipov): Consider adding to scripts/ and the common project
# structure.
go-upd-tools:
cd ./internal/tools/ &&\
"$(GO.MACRO)" get -u &&\
"$(GO.MACRO)" mod tidy

View File

@@ -54,7 +54,7 @@ code.
* [Getting Started](#getting-started) * [Getting Started](#getting-started)
* [Automated install (Linux/Unix/MacOS/FreeBSD/OpenBSD)](#automated-install-linux-and-mac) * [Automated install (Unix)](#automated-install-linux-and-mac)
* [Alternative methods](#alternative-methods) * [Alternative methods](#alternative-methods)
* [Guides](#guides) * [Guides](#guides)
* [API](#api) * [API](#api)
@@ -79,7 +79,7 @@ code.
## <a href="#getting-started" id="getting-started" name="getting-started">Getting Started</a> ## <a href="#getting-started" id="getting-started" name="getting-started">Getting Started</a>
### <a href="#automated-install-linux-and-mac" id="automated-install-linux-and-mac" name="automated-install-linux-and-mac">Automated install (Linux/Unix/MacOS/FreeBSD/OpenBSD)</a> ### <a href="#automated-install-linux-and-mac" id="automated-install-linux-and-mac" name="automated-install-linux-and-mac">Automated install (Unix)</a>
To install with `curl` run the following command: To install with `curl` run the following command:
@@ -261,7 +261,7 @@ Run `make init` to prepare the development environment.
You will need this to build AdGuard Home: You will need this to build AdGuard Home:
* [Go](https://golang.org/dl/) v1.20 or later; * [Go](https://golang.org/dl/) v1.19 or later;
* [Node.js](https://nodejs.org/en/download/) v10.16.2 or later; * [Node.js](https://nodejs.org/en/download/) v10.16.2 or later;
* [npm](https://www.npmjs.com/) v6.14 or later; * [npm](https://www.npmjs.com/) v6.14 or later;
* [yarn](https://yarnpkg.com/) v1.22.5 or later. * [yarn](https://yarnpkg.com/) v1.22.5 or later.
@@ -416,8 +416,7 @@ There are three options how you can install an unstable version:
### <a href="#reporting-issues" id="reporting-issues" name="reporting-issues">Report issues</a> ### <a href="#reporting-issues" id="reporting-issues" name="reporting-issues">Report issues</a>
If you run into any problem or have a suggestion, head to [this page][iss] and If you run into any problem or have a suggestion, head to [this page][iss] and
click on the “New issue” button. Please follow the instructions in the issue click on the “New issue” button.
form carefully and don't forget to start by searching for duplicates.
[iss]: https://github.com/AdguardTeam/AdGuardHome/issues [iss]: https://github.com/AdguardTeam/AdGuardHome/issues
@@ -467,10 +466,6 @@ bug or implementing the feature.
Home](https://github.com/ebrianne/adguard-exporter) by Home](https://github.com/ebrianne/adguard-exporter) by
[@ebrianne](https://github.com/ebrianne). [@ebrianne](https://github.com/ebrianne).
* [Terminal-based, real-time traffic monitoring and statistics for your AdGuard Home
instance](https://github.com/Lissy93/AdGuardian-Term) by
[@Lissy93](https://github.com/Lissy93)
* [AdGuard Home on GLInet * [AdGuard Home on GLInet
routers](https://forum.gl-inet.com/t/adguardhome-on-gl-routers/10664) by routers](https://forum.gl-inet.com/t/adguardhome-on-gl-routers/10664) by
[Gl-Inet](https://gl-inet.com/). [Gl-Inet](https://gl-inet.com/).

View File

@@ -1,8 +1,5 @@
---
!include release.yaml
---
!include snapcraft.yaml
--- ---
!include test.yaml !include test.yaml
---
!include release.yaml

View File

@@ -1,290 +1,349 @@
--- ---
'version': 2 'version': 2
'plan': 'plan':
'project-key': 'AGH' 'project-key': 'AGH'
'key': 'AGHBSNAPSPECS' 'key': 'AGHBSNAPSPECS'
'name': 'AdGuard Home - Build and publish release' 'name': 'AdGuard Home - Build and publish release'
# Make sure to sync any changes with the branch overrides below. # Make sure to sync any changes with the branch overrides below.
'variables': 'variables':
'channel': 'edge' 'channel': 'edge'
'dockerGo': 'adguard/golang-ubuntu:7.0' 'dockerGo': 'adguard/golang-ubuntu:6.3'
'stages': 'stages':
- 'Build frontend': - 'Build frontend':
'manual': false 'manual': false
'final': false 'final': false
'jobs': 'jobs':
- 'Build frontend' - 'Build frontend'
- 'Make release': - 'Make release':
'manual': false 'manual': false
'final': false 'final': false
'jobs': 'jobs':
- 'Make release' - 'Make release'
- 'Make and publish docker': - 'Make and publish docker':
'manual': false 'manual': false
'final': false 'final': false
'jobs': 'jobs':
- 'Make and publish docker' - 'Make and publish docker'
- 'Publish to static storage': - 'Publish to static storage':
'manual': false 'manual': false
'final': false 'final': false
'jobs': 'jobs':
- 'Publish to static storage' - 'Publish to static storage'
- 'Publish to GitHub Releases': - 'Publish to Snapstore':
'manual': false 'manual': false
'final': false 'final': false
'jobs': 'jobs':
- 'Publish to GitHub Releases' - 'Publish to Snapstore'
- 'Publish to GitHub Releases':
'manual': false
'final': false
'jobs':
- 'Publish to GitHub Releases'
'Build frontend': 'Build frontend':
'docker': 'docker':
'image': '${bamboo.dockerGo}' 'image': '${bamboo.dockerGo}'
'volumes': 'volumes':
'${system.YARN_DIR}': '${bamboo.cacheYarn}' '${system.YARN_DIR}': '${bamboo.cacheYarn}'
'key': 'BF' 'key': 'BF'
'other': 'other':
'clean-working-dir': true 'clean-working-dir': true
'tasks': 'tasks':
- 'checkout': - 'checkout':
'force-clean-build': true 'force-clean-build': true
- 'script': - 'script':
'interpreter': 'SHELL' 'interpreter': 'SHELL'
'scripts': 'scripts':
- | - |
#!/bin/sh #!/bin/sh
set -e -f -u -x set -e -f -u -x
# Explicitly checkout the revision that we need. # Explicitly checkout the revision that we need.
git checkout "${bamboo.repository.revision.number}" git checkout "${bamboo.repository.revision.number}"
make js-deps js-build make js-deps js-build
'artifacts': 'artifacts':
- 'name': 'AdGuardHome frontend' - 'name': 'AdGuardHome frontend'
'pattern': 'build/**' 'pattern': 'build*/**'
'shared': true 'shared': true
'required': true 'required': true
'requirements': 'requirements':
- 'adg-docker': 'true' - 'adg-docker': 'true'
'Make release': 'Make release':
'docker': 'docker':
'image': '${bamboo.dockerGo}' 'image': '${bamboo.dockerGo}'
'volumes': 'volumes':
'${system.GO_CACHE_DIR}': '${bamboo.cacheGo}' '${system.GO_CACHE_DIR}': '${bamboo.cacheGo}'
'${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}' '${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}'
'key': 'MR' 'key': 'MR'
'other': 'other':
'clean-working-dir': true 'clean-working-dir': true
'tasks': 'tasks':
- 'checkout': - 'checkout':
'force-clean-build': true 'force-clean-build': true
- 'script': - 'script':
'interpreter': 'SHELL' 'interpreter': 'SHELL'
'scripts': 'scripts':
- | - |
#!/bin/sh #!/bin/sh
set -e -f -u -x set -e -f -u -x
# Explicitly checkout the revision that we need. # Explicitly checkout the revision that we need.
git checkout "${bamboo.repository.revision.number}" git checkout "${bamboo.repository.revision.number}"
# Run the build with the specified channel. # Run the build with the specified channel.
echo "${bamboo.gpgSecretKeyPart1}${bamboo.gpgSecretKeyPart2}"\ echo "${bamboo.gpgSecretKeyPart1}${bamboo.gpgSecretKeyPart2}"\
| awk '{ gsub(/\\n/, "\n"); print; }'\ | awk '{ gsub(/\\n/, "\n"); print; }'\
| gpg --import --batch --yes | gpg --import --batch --yes
make\ make\
CHANNEL=${bamboo.channel}\ CHANNEL=${bamboo.channel}\
GPG_KEY_PASSPHRASE=${bamboo.gpgPassword}\ GPG_KEY_PASSPHRASE=${bamboo.gpgPassword}\
FRONTEND_PREBUILT=1\ FRONTEND_PREBUILT=1\
PARALLELISM=1\ PARALLELISM=1\
VERBOSE=2\ VERBOSE=2\
build-release build-release
# TODO(a.garipov): Use more fine-grained artifact rules. # TODO(a.garipov): Use more fine-grained artifact rules.
'artifacts': 'artifacts':
- 'name': 'AdGuardHome dists' - 'name': 'AdGuardHome dists'
'pattern': 'dist/**' 'pattern': 'dist/**'
'shared': true 'shared': true
'required': true 'required': true
'requirements': 'requirements':
- 'adg-docker': 'true' - 'adg-docker': 'true'
'Make and publish docker': 'Make and publish docker':
'key': 'MPD' 'key': 'MPD'
'other': 'other':
'clean-working-dir': true 'clean-working-dir': true
'tasks': 'tasks':
- 'checkout': - 'checkout':
'force-clean-build': true 'force-clean-build': true
- 'script': - 'script':
'interpreter': 'SHELL' 'interpreter': 'SHELL'
'scripts': 'scripts':
- | - |
#!/bin/sh #!/bin/sh
set -e -f -u -x set -e -f -u -x
COMMIT="${bamboo.repository.revision.number}" COMMIT="${bamboo.repository.revision.number}"
export COMMIT export COMMIT
readonly COMMIT readonly COMMIT
# Explicitly checkout the revision that we need. # Explicitly checkout the revision that we need.
git checkout "$COMMIT" git checkout "$COMMIT"
# Install Qemu, create builder. # Install Qemu, create builder.
docker version -f '{{ .Server.Experimental }}' docker version -f '{{ .Server.Experimental }}'
docker buildx rm buildx-builder || : docker buildx rm buildx-builder || :
docker buildx create --name buildx-builder --driver docker-container\ docker buildx create --name buildx-builder --driver docker-container\
--use --use
docker buildx inspect --bootstrap docker buildx inspect --bootstrap
# Login to DockerHub. # Login to DockerHub.
docker login -u="${bamboo.dockerHubUsername}"\ docker login -u="${bamboo.dockerHubUsername}"\
-p="${bamboo.dockerHubPassword}" -p="${bamboo.dockerHubPassword}"
# Boot the builder. # Boot the builder.
docker buildx inspect --bootstrap docker buildx inspect --bootstrap
# Print Docker info. # Print Docker info.
docker info docker info
# Prepare and push the build. # Prepare and push the build.
env\ env\
CHANNEL="${bamboo.channel}"\ CHANNEL="${bamboo.channel}"\
DIST_DIR='dist'\ DIST_DIR='dist'\
DOCKER_IMAGE_NAME='adguard/adguardhome'\ DOCKER_IMAGE_NAME='adguard/adguardhome'\
DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true"\ DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true"\
VERBOSE='1'\ VERBOSE='1'\
sh ./scripts/make/build-docker.sh sh ./scripts/make/build-docker.sh
'environment': 'environment':
DOCKER_CLI_EXPERIMENTAL=enabled DOCKER_CLI_EXPERIMENTAL=enabled
'final-tasks': 'final-tasks':
- 'clean' - 'clean'
'requirements': 'requirements':
- 'adg-docker': 'true' - 'adg-docker': 'true'
'Publish to static storage': 'Publish to static storage':
'key': 'PUB' 'key': 'PUB'
'other': 'other':
'clean-working-dir': true 'clean-working-dir': true
'tasks': 'tasks':
- 'clean' - 'clean'
- 'checkout': - 'checkout':
'repository': 'bamboo-deploy-publisher' 'repository': 'bamboo-deploy-publisher'
'path': 'bamboo-deploy-publisher' 'path': 'bamboo-deploy-publisher'
'force-clean-build': true 'force-clean-build': true
- 'script': - 'script':
'interpreter': 'SHELL' 'interpreter': 'SHELL'
'scripts': 'scripts':
- | - |
#!/bin/sh #!/bin/sh
set -e -f -u -x set -e -f -u -x
cd ./dist/ cd ./dist/
CHANNEL="${bamboo.channel}" CHANNEL="${bamboo.channel}"
export CHANNEL export CHANNEL
../bamboo-deploy-publisher/deploy.sh adguard-home-"$CHANNEL" ../bamboo-deploy-publisher/deploy.sh adguard-home-"$CHANNEL"
'final-tasks': 'final-tasks':
- 'clean' - 'clean'
'requirements': 'requirements':
- 'adg-docker': 'true' - 'adg-docker': 'true'
'Publish to Snapstore':
'docker':
'image': '${bamboo.dockerGo}'
'key': 'PTS'
'other':
'clean-working-dir': true
'tasks':
- 'clean'
- 'checkout':
'repository': 'bamboo-deploy-publisher'
'path': 'bamboo-deploy-publisher'
'force-clean-build': true
- 'script':
'interpreter': 'SHELL'
'scripts':
- |
#!/bin/sh
set -e -f -u -x
cd ./dist/
channel="${bamboo.channel}"
readonly channel
case "$channel"
in
('release')
snapchannel='candidate'
;;
('beta')
snapchannel='beta'
;;
('edge')
snapchannel='edge'
;;
(*)
echo "invalid channel '$channel'"
exit 1
;;
esac
env\
SNAPCRAFT_CHANNEL="$snapchannel"\
SNAPCRAFT_EMAIL="${bamboo.snapcraftEmail}"\
SNAPCRAFT_MACAROON="${bamboo.snapcraftMacaroonPassword}"\
SNAPCRAFT_UBUNTU_DISCHARGE="${bamboo.snapcraftUbuntuDischargePassword}"\
../bamboo-deploy-publisher/deploy.sh adguard-home-snap
'final-tasks':
- 'clean'
'requirements':
- 'adg-docker': 'true'
'Publish to GitHub Releases': 'Publish to GitHub Releases':
'key': 'PTGR' 'key': 'PTGR'
'other': 'other':
'clean-working-dir': true 'clean-working-dir': true
'tasks': 'tasks':
- 'clean' - 'clean'
- 'checkout': - 'checkout':
'repository': 'bamboo-deploy-publisher' 'repository': 'bamboo-deploy-publisher'
'path': 'bamboo-deploy-publisher' 'path': 'bamboo-deploy-publisher'
'force-clean-build': true 'force-clean-build': true
- 'script': - 'script':
'interpreter': 'SHELL' 'interpreter': 'SHELL'
'scripts': 'scripts':
- | - |
#!/bin/sh #!/bin/sh
set -e -f -u -x set -e -f -u -x
channel="${bamboo.channel}" channel="${bamboo.channel}"
readonly channel readonly channel
if [ "$channel" != 'release' ] && [ "${channel}" != 'beta' ] if [ "$channel" != 'release' ] && [ "${channel}" != 'beta' ]
then then
echo "don't publish to GitHub Releases for this channel" echo "don't publish to GitHub Releases for this channel"
exit 0 exit 0
fi fi
cd ./dist/ cd ./dist/
env\ env\
GITHUB_TOKEN="${bamboo.githubPublicRepoPassword}"\ GITHUB_TOKEN="${bamboo.githubPublicRepoPassword}"\
../bamboo-deploy-publisher/deploy.sh adguard-home-github ../bamboo-deploy-publisher/deploy.sh adguard-home-github
'final-tasks': 'final-tasks':
- 'clean' - 'clean'
'requirements': 'requirements':
- 'adg-docker': 'true' - 'adg-docker': 'true'
'triggers': 'triggers':
# Don't use minute values that end with a zero or a five as these are often # Don't use minute values that end with a zero or a five as these are often used
# used in CI and so resources during these minutes can be quite busy. # in CI and so resources during these minutes can be quite busy.
- 'cron': '0 42 13 ? * MON-FRI *' - 'cron': '0 42 13 ? * MON-FRI *'
'branches': 'branches':
'create': 'manually' 'create': 'manually'
'delete': 'delete':
'after-deleted-days': 1 'after-deleted-days': 1
'after-inactive-days': 30 'after-inactive-days': 30
'integration': 'integration':
'push-on-success': false 'push-on-success': false
'merge-from': 'AdGuard Home - Build and publish release' 'merge-from': 'AdGuard Home - Build and publish release'
'link-to-jira': true 'link-to-jira': true
'notifications': 'notifications':
- 'events': - 'events':
- 'plan-completed' - 'plan-completed'
'recipients': 'recipients':
- 'webhook': - 'webhook':
'name': 'Build webhook' 'name': 'Build webhook'
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo?channel=adguard-qa' 'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo?channel=adguard-qa'
'labels': [] 'labels': []
'other': 'other':
'concurrent-build-plugin': 'system-default' 'concurrent-build-plugin': 'system-default'
'branch-overrides': 'branch-overrides':
# beta-vX.Y branches are the branches into which the commits that are needed # beta-vX.Y branches are the branches into which the commits that are needed to
# to release a new patch version are initially cherry-picked. # release a new patch version are initially cherry-picked.
- '^beta-v[0-9]+\.[0-9]+': - '^beta-v[0-9]+\.[0-9]+':
# Build betas on release branches manually. # Build betas on release branches manually.
'triggers': [] 'triggers': []
# Set the default release channel on the release branch to beta, as we may # Set the default release channel on the release branch to beta, as we may
# need to build a few of these. # need to build a few of these.
'variables': 'variables':
'channel': 'beta' 'channel': 'beta'
'dockerGo': 'adguard/golang-ubuntu:7.0' 'dockerGo': 'adguard/golang-ubuntu:6.3'
# release-vX.Y.Z branches are the branches from which the actual final # release-vX.Y.Z branches are the branches from which the actual final release
# release is built. # is built.
- '^release-v[0-9]+\.[0-9]+\.[0-9]+': - '^release-v[0-9]+\.[0-9]+\.[0-9]+':
# Disable integration branches for release branches. # Disable integration branches for release branches.
'branch-config': 'branch-config':
'integration': 'integration':
'push-on-success': false 'push-on-success': false
'merge-from': 'beta-v0.107' 'merge-from': 'beta-v0.107'
# Build final releases on release branches manually. # Build final releases on release branches manually.
'triggers': [] 'triggers': []
# Set the default release channel on the final branch to release, as these # Set the default release channel on the final branch to release, as these
# are the ones that actually get released. # are the ones that actually get released.
'variables': 'variables':
'channel': 'release' 'channel': 'release'
'dockerGo': 'adguard/golang-ubuntu:7.0' 'dockerGo': 'adguard/golang-ubuntu:6.3'

View File

@@ -1,211 +0,0 @@
---
# This part of the release build is separate from the one described in
# release.yaml, because the Snapcraft infrastructure is brittle, and timeouts
# during logins and uploads often lead to release blocking.
'version': 2
'plan':
'project-key': 'AGH'
'key': 'AGHSNAP'
'name': 'AdGuard Home - Build and publish Snapcraft release'
# Make sure to sync any changes with the branch overrides below.
'variables':
'channel': 'edge'
'dockerGo': 'adguard/golang-ubuntu:7.0'
'snapcraftChannel': 'edge'
'stages':
- 'Download release':
'manual': false
'final': false
'jobs':
- 'Download release'
- 'Build packages':
'manual': false
'final': false
'jobs':
- 'Build packages'
- 'Publish to Snapstore':
'manual': false
'final': false
'jobs':
- 'Publish to Snapstore'
# TODO(a.garipov): Consider using the Artifact Downloader Task if it ever learns
# about plan branches.
'Download release':
'artifacts':
- 'name': 'i386_binary'
'pattern': 'AdGuardHome_i386'
'shared': true
'required': true
- 'name': 'amd64_binary'
'pattern': 'AdGuardHome_amd64'
'shared': true
'required': true
- 'name': 'armhf_binary'
'pattern': 'AdGuardHome_armhf'
'shared': true
'required': true
- 'name': 'arm64_binary'
'pattern': 'AdGuardHome_arm64'
'shared': true
'required': true
'docker':
'image': '${bamboo.dockerGo}'
'key': 'DR'
'other':
'clean-working-dir': true
'tasks':
- 'checkout':
'force-clean-build': true
- 'script':
'interpreter': 'SHELL'
'scripts':
- |
#!/bin/sh
set -e -f -u -x
env\
CHANNEL="${bamboo.channel}"\
VERBOSE='1'\
sh ./scripts/snap/download.sh
'requirements':
- 'adg-docker': 'true'
'Build packages':
'artifact-subscriptions':
- 'artifact': 'i386_binary'
- 'artifact': 'amd64_binary'
- 'artifact': 'armhf_binary'
- 'artifact': 'arm64_binary'
'artifacts':
- 'name': 'i386_snap'
'pattern': 'AdGuardHome_i386.snap'
'shared': true
'required': true
- 'name': 'amd64_snap'
'pattern': 'AdGuardHome_amd64.snap'
'shared': true
'required': true
- 'name': 'armhf_snap'
'pattern': 'AdGuardHome_armhf.snap'
'shared': true
'required': true
- 'name': 'arm64_snap'
'pattern': 'AdGuardHome_arm64.snap'
'shared': true
'required': true
'docker':
'image': '${bamboo.dockerGo}'
'key': 'BP'
'other':
'clean-working-dir': true
'tasks':
- 'checkout':
'force-clean-build': true
- 'script':
'interpreter': 'SHELL'
'scripts':
- |
#!/bin/sh
set -e -f -u -x
env\
VERBOSE='1'\
sh ./scripts/snap/build.sh
'requirements':
- 'adg-docker': 'true'
'Publish to Snapstore':
'artifact-subscriptions':
- 'artifact': 'i386_snap'
- 'artifact': 'amd64_snap'
- 'artifact': 'armhf_snap'
- 'artifact': 'arm64_snap'
'docker':
'image': '${bamboo.dockerGo}'
'key': 'PTS'
'other':
'clean-working-dir': true
'tasks':
- 'checkout':
'force-clean-build': true
- 'script':
'interpreter': 'SHELL'
'scripts':
- |
#!/bin/sh
set -e -f -u -x
env\
SNAPCRAFT_CHANNEL="${bamboo.snapcraftChannel}"\
SNAPCRAFT_STORE_CREDENTIALS="${bamboo.snapcraftMacaroonPassword}"\
VERBOSE='1'\
sh ./scripts/snap/upload.sh
'final-tasks':
- 'clean'
'requirements':
- 'adg-docker': 'true'
'triggers':
# Don't use minute values that end with a zero or a five as these are often
# used in CI and so resources during these minutes can be quite busy.
#
# NOTE: The time is chosen to be exactly one hour after the main release
# build as defined as in release.yaml.
- 'cron': '0 42 14 ? * MON-FRI *'
'branches':
'create': 'manually'
'delete':
'after-deleted-days': 1
'after-inactive-days': 30
'integration':
'push-on-success': false
'merge-from': 'AdGuard Home - Build and publish Snapcraft release'
'link-to-jira': true
'notifications':
- 'events':
- 'plan-completed'
'recipients':
- 'webhook':
'name': 'Build webhook'
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo?channel=adguard-qa'
'labels': []
'other':
'concurrent-build-plugin': 'system-default'
'branch-overrides':
# beta-vX.Y branches are the branches into which the commits that are needed
# to release a new patch version are initially cherry-picked.
- '^beta-v[0-9]+\.[0-9]+':
# Build betas on release branches manually.
'triggers': []
# Set the default release channel on the release branch to beta, as we may
# need to build a few of these.
'variables':
'channel': 'beta'
'dockerGo': 'adguard/golang-ubuntu:7.0'
'snapcraftChannel': 'beta'
# release-vX.Y.Z branches are the branches from which the actual final
# release is built.
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
# Disable integration branches for release branches.
'branch-config':
'integration':
'push-on-success': false
'merge-from': 'beta-v0.107'
# Build final releases on release branches manually.
'triggers': []
# Set the default release channel on the final branch to release, as these
# are the ones that actually get released.
'variables':
'channel': 'release'
'dockerGo': 'adguard/golang-ubuntu:7.0'
'snapcraftChannel': 'candidate'

View File

@@ -1,64 +1,64 @@
--- ---
'version': 2 'version': 2
'plan': 'plan':
'project-key': 'AGH' 'project-key': 'AGH'
'key': 'AHBRTSPECS' 'key': 'AHBRTSPECS'
'name': 'AdGuard Home - Build and run tests' 'name': 'AdGuard Home - Build and run tests'
'variables': 'variables':
'dockerGo': 'adguard/golang-ubuntu:7.0' 'dockerGo': 'adguard/golang-ubuntu:6.3'
'stages': 'stages':
- 'Tests': - 'Tests':
'manual': false 'manual': false
'final': false 'final': false
'jobs': 'jobs':
- 'Test' - 'Test'
'Test': 'Test':
'docker': 'docker':
'image': '${bamboo.dockerGo}' 'image': '${bamboo.dockerGo}'
'volumes': 'volumes':
'${system.YARN_DIR}': '${bamboo.cacheYarn}' '${system.YARN_DIR}': '${bamboo.cacheYarn}'
'${system.GO_CACHE_DIR}': '${bamboo.cacheGo}' '${system.GO_CACHE_DIR}': '${bamboo.cacheGo}'
'${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}' '${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}'
'key': 'TEST' 'key': 'TEST'
'other': 'other':
'clean-working-dir': true 'clean-working-dir': true
'tasks': 'tasks':
- 'checkout': - 'checkout':
'force-clean-build': true 'force-clean-build': true
- 'script': - 'script':
'interpreter': 'SHELL' 'interpreter': 'SHELL'
'scripts': 'scripts':
- | - |
#!/bin/sh #!/bin/sh
set -e -f -u -x set -e -f -u -x
make VERBOSE=1 ci go-tools lint make VERBOSE=1 ci go-tools lint
'final-tasks': 'final-tasks':
- 'clean' - 'clean'
'requirements': 'requirements':
- 'adg-docker': 'true' - 'adg-docker': 'true'
'branches': 'branches':
'create': 'for-pull-request' 'create': 'for-pull-request'
'delete': 'delete':
'after-deleted-days': 1 'after-deleted-days': 1
'after-inactive-days': 5 'after-inactive-days': 5
'integration': 'integration':
'push-on-success': false 'push-on-success': false
'merge-from': 'AdGuard Home - Build and run tests' 'merge-from': 'AdGuard Home - Build and run tests'
'link-to-jira': true 'link-to-jira': true
'notifications': 'notifications':
- 'events': - 'events':
- 'plan-status-changed' - 'plan-status-changed'
'recipients': 'recipients':
- 'webhook': - 'webhook':
'name': 'Build webhook' 'name': 'Build webhook'
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo' 'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo'
'labels': [] 'labels': []
'other': 'other':
'concurrent-build-plugin': 'system-default' 'concurrent-build-plugin': 'system-default'

View File

@@ -150,7 +150,7 @@
"dns_allowlists": "Белыя спісы DNS", "dns_allowlists": "Белыя спісы DNS",
"dns_blocklists_desc": "AdGuard Home будзе блакаваць дамены з чорных спісаў.", "dns_blocklists_desc": "AdGuard Home будзе блакаваць дамены з чорных спісаў.",
"dns_allowlists_desc": "Дамены з белых спісаў DNS будуць дазволены, нават калі яны знаходзяцца ў любым з чорных спісаў.", "dns_allowlists_desc": "Дамены з белых спісаў DNS будуць дазволены, нават калі яны знаходзяцца ў любым з чорных спісаў.",
"custom_filtering_rules": "Карыстальніцкія правілы фільтрацыі", "custom_filtering_rules": "Карыстацкія правілы фільтрацыі",
"encryption_settings": "Налады шыфравання", "encryption_settings": "Налады шыфравання",
"dhcp_settings": "Налады DHCP", "dhcp_settings": "Налады DHCP",
"upstream_dns": "Upstream DNS-серверы", "upstream_dns": "Upstream DNS-серверы",
@@ -247,7 +247,7 @@
"loading_table_status": "Загрузка...", "loading_table_status": "Загрузка...",
"page_table_footer_text": "Старонка", "page_table_footer_text": "Старонка",
"rows_table_footer_text": "радкоў", "rows_table_footer_text": "радкоў",
"updated_custom_filtering_toast": "Карыстальніцкія правілы паспяхова захаваны", "updated_custom_filtering_toast": "Занесены змены ў карыстацкія правілы",
"rule_removed_from_custom_filtering_toast": "Карыстацкае правіла выдалена: {{rule}}", "rule_removed_from_custom_filtering_toast": "Карыстацкае правіла выдалена: {{rule}}",
"rule_added_to_custom_filtering_toast": "Карыстацкае правіла дададзена: {{rule}}", "rule_added_to_custom_filtering_toast": "Карыстацкае правіла дададзена: {{rule}}",
"query_log_response_status": "Статус: {{value}}", "query_log_response_status": "Статус: {{value}}",
@@ -475,9 +475,7 @@
"setup_dns_notice": "Каб выкарыстоўваць <1>DNS-over-HTTPS</1> ці <1>DNS-over-TLS</1>, вам патрэбна <0>наладзіць шыфраванне</0> у наладах AdGuard Home.", "setup_dns_notice": "Каб выкарыстоўваць <1>DNS-over-HTTPS</1> ці <1>DNS-over-TLS</1>, вам патрэбна <0>наладзіць шыфраванне</0> у наладах AdGuard Home.",
"rewrite_added": "Правіла перанакіравання DNS для «{{key}}» паспяхова дададзена", "rewrite_added": "Правіла перанакіравання DNS для «{{key}}» паспяхова дададзена",
"rewrite_deleted": "Правіла перанакіравання DNS для «{{key}}» паспяхова выдалена", "rewrite_deleted": "Правіла перанакіравання DNS для «{{key}}» паспяхова выдалена",
"rewrite_updated": "Перазапіс DNS паспяхова абноўлены",
"rewrite_add": "Дадаць правіла перанакіравання DNS", "rewrite_add": "Дадаць правіла перанакіравання DNS",
"rewrite_edit": "Рэдагаваць перазапіс DNS",
"rewrite_not_found": "Не знойдзена правілаў перанакіравання DNS", "rewrite_not_found": "Не знойдзена правілаў перанакіравання DNS",
"rewrite_confirm_delete": "Вы ўпэўнены, што хочаце выдаліць правіла перанакіравання DNS для «{{key}}»?", "rewrite_confirm_delete": "Вы ўпэўнены, што хочаце выдаліць правіла перанакіравання DNS для «{{key}}»?",
"rewrite_desc": "Дазваляе лёгка наладзіць карыстацкі DNS-адказ для пэўнага дамена.", "rewrite_desc": "Дазваляе лёгка наладзіць карыстацкі DNS-адказ для пэўнага дамена.",
@@ -570,7 +568,7 @@
"check_desc": "Праверыць фільтрацыю імя хаста", "check_desc": "Праверыць фільтрацыю імя хаста",
"check": "Праверыць", "check": "Праверыць",
"form_enter_host": "Увядзіце імя хаста", "form_enter_host": "Увядзіце імя хаста",
"filtered_custom_rules": "Адфільтраваны з дапамогай карыстальніцкіх правіл фільтрацыі", "filtered_custom_rules": "Адфільтраваны з дапамогай карыстацкіх правілаў фільтрацыі",
"choose_from_list": "Абраць са спіса", "choose_from_list": "Абраць са спіса",
"add_custom_list": "Дадаць свой спіс", "add_custom_list": "Дадаць свой спіс",
"host_whitelisted": "Хост занесены ў белы спіс", "host_whitelisted": "Хост занесены ў белы спіс",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "Opravdu chcete odstranit klienta \"{{key}}\"?", "client_confirm_delete": "Opravdu chcete odstranit klienta \"{{key}}\"?",
"list_confirm_delete": "Opravdu chcete smazat tento seznam?", "list_confirm_delete": "Opravdu chcete smazat tento seznam?",
"auto_clients_title": "Spuštění klienti", "auto_clients_title": "Spuštění klienti",
"auto_clients_desc": "Informace o IP adresách zařízení, která používají nebo mohou používat AdGuard Home. Tyto informace se získávají z několika zdrojů, včetně souborů hosts, reverzního DNS atd.", "auto_clients_desc": "Zařízení, která nejsou na seznamu stálých klientů, a mohou nadále používat AdGuard Home",
"access_title": "Nastavení přístupu", "access_title": "Nastavení přístupu",
"access_desc": "Zde můžete konfigurovat pravidla přístupu pro server DNS AdGuard Home", "access_desc": "Zde můžete konfigurovat pravidla přístupu pro server DNS AdGuard Home",
"access_allowed_title": "Povolení klienti", "access_allowed_title": "Povolení klienti",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Pro použití <1>DNS skrze HTTPS</1> nebo <1>DNS skrze TLS</1> potřebujete v nastaveních AdGuard Home <0>nakonfigurovat šifrování</0>.", "setup_dns_notice": "Pro použití <1>DNS skrze HTTPS</1> nebo <1>DNS skrze TLS</1> potřebujete v nastaveních AdGuard Home <0>nakonfigurovat šifrování</0>.",
"rewrite_added": "Přesměrování DNS pro „{{key}}“ úspěšně přidáno", "rewrite_added": "Přesměrování DNS pro „{{key}}“ úspěšně přidáno",
"rewrite_deleted": "Přesměrování DNS pro „{{key}}“ úspěšně smazáno", "rewrite_deleted": "Přesměrování DNS pro „{{key}}“ úspěšně smazáno",
"rewrite_updated": "Přesměrování DNS bylo úspěšně aktualizováno",
"rewrite_add": "Přidat přesměrování DNS", "rewrite_add": "Přidat přesměrování DNS",
"rewrite_edit": "Upravit přesměrování DNS",
"rewrite_not_found": "Přesměrování DNS nenalezeny", "rewrite_not_found": "Přesměrování DNS nenalezeny",
"rewrite_confirm_delete": "Jste si jisti, že chcete smazat přesměrování DNS pro „{{key}}“?", "rewrite_confirm_delete": "Jste si jisti, že chcete smazat přesměrování DNS pro „{{key}}“?",
"rewrite_desc": "Umožňuje snadno nakonfigurovat vlastní DNS odezvy pro konkrétní název domény.", "rewrite_desc": "Umožňuje snadno nakonfigurovat vlastní DNS odezvy pro konkrétní název domény.",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "Sikker på, at du vil slette klient \"{{key}}\"?", "client_confirm_delete": "Sikker på, at du vil slette klient \"{{key}}\"?",
"list_confirm_delete": "Sikker på, at du vil slette denne liste?", "list_confirm_delete": "Sikker på, at du vil slette denne liste?",
"auto_clients_title": "Klienter (runtime)", "auto_clients_title": "Klienter (runtime)",
"auto_clients_desc": "Oplysninger om IP-adresser på enheder, som (måske) bruger AdGuard Home. Disse oplysninger indsamles fra flere kilder, herunder hosts-filer, reverse DNS mv.", "auto_clients_desc": "Enheder, som ikke er på listen over Permanente klienter, kan stadig bruge AdGuard Home",
"access_title": "Adgangsindstillinger", "access_title": "Adgangsindstillinger",
"access_desc": "Her kan adgangsregler for AdGuard Home DNS-serveren opsættes", "access_desc": "Her kan adgangsregler for AdGuard Home DNS-serveren opsættes",
"access_allowed_title": "Tilladte klienter", "access_allowed_title": "Tilladte klienter",
@@ -478,9 +478,7 @@
"setup_dns_notice": "For at kunne bruge <1>DNS-over-HTTPS</1> eller <1>DNS-over-TLS</1>, skal du <0>opsætte Krypteringen</0> i AdGuard Homes indstillinger.", "setup_dns_notice": "For at kunne bruge <1>DNS-over-HTTPS</1> eller <1>DNS-over-TLS</1>, skal du <0>opsætte Krypteringen</0> i AdGuard Homes indstillinger.",
"rewrite_added": "DNS-omskrivning for \"{{key}}\" blev tilføjet", "rewrite_added": "DNS-omskrivning for \"{{key}}\" blev tilføjet",
"rewrite_deleted": "DNS-omskrivning for \"{{key}}\" blev slettet", "rewrite_deleted": "DNS-omskrivning for \"{{key}}\" blev slettet",
"rewrite_updated": "DNS-omskrivning hermed opdateret",
"rewrite_add": "Tilføj DNS-omskrivning", "rewrite_add": "Tilføj DNS-omskrivning",
"rewrite_edit": "Redigér DNS-omskrivning",
"rewrite_not_found": "Ingen DNS-omskrivninger fundet", "rewrite_not_found": "Ingen DNS-omskrivninger fundet",
"rewrite_confirm_delete": "Sikker på, at du vil slette DNS-omskrivning for \"{{key}}\"?", "rewrite_confirm_delete": "Sikker på, at du vil slette DNS-omskrivning for \"{{key}}\"?",
"rewrite_desc": "Gør det nemt at opsætte det tilpassede DNS-svar for et specifikt domænenavn.", "rewrite_desc": "Gør det nemt at opsætte det tilpassede DNS-svar for et specifikt domænenavn.",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "Möchten Sie den Client „{{key}}“ wirklich löschen?", "client_confirm_delete": "Möchten Sie den Client „{{key}}“ wirklich löschen?",
"list_confirm_delete": "Möchten Sie diese Liste wirklich löschen?", "list_confirm_delete": "Möchten Sie diese Liste wirklich löschen?",
"auto_clients_title": "Laufzeit-Clients", "auto_clients_title": "Laufzeit-Clients",
"auto_clients_desc": "Informationen über IP-Adressen der Geräten, die AdGuard Home nutzen oder nutzen könnten. Diese Informationen werden aus verschiedenen Quellen gesammelt, darunter Hosts-Dateien, Reverse-DNS usw.", "auto_clients_desc": "Geräte, die nicht auf der Liste der persistenten Clients stehen und trotzdem AdGuard Home verwenden dürfen",
"access_title": "Zugriffsrechte", "access_title": "Zugriffsrechte",
"access_desc": "Hier können Sie die Zugriffsregeln für den DNS-Server von AdGuard Home konfigurieren", "access_desc": "Hier können Sie die Zugriffsregeln für den DNS-Server von AdGuard Home konfigurieren",
"access_allowed_title": "Zugelassene Clients", "access_allowed_title": "Zugelassene Clients",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Um <1>DNS-over-HTTTPS</1> oder <1>DNS-over-TLS</1> verwenden zu können, müssen Sie in den AdGuard Home Einstellungen die <0>Verschlüsselung konfigurieren</0>.", "setup_dns_notice": "Um <1>DNS-over-HTTTPS</1> oder <1>DNS-over-TLS</1> verwenden zu können, müssen Sie in den AdGuard Home Einstellungen die <0>Verschlüsselung konfigurieren</0>.",
"rewrite_added": "DNS-Umschreibung für „{{key}}“ erfolgreich hinzugefügt", "rewrite_added": "DNS-Umschreibung für „{{key}}“ erfolgreich hinzugefügt",
"rewrite_deleted": "DNS-Umschreibung für „{{key}}“ erfolgreich entfernt", "rewrite_deleted": "DNS-Umschreibung für „{{key}}“ erfolgreich entfernt",
"rewrite_updated": "DNS-Rewrite erfolgreich aktualisiert",
"rewrite_add": "DNS-Umschreibung hinzufügen", "rewrite_add": "DNS-Umschreibung hinzufügen",
"rewrite_edit": "DNS-Rewrite bearbeiten",
"rewrite_not_found": "Keine DNS-Umschreibungen gefunden", "rewrite_not_found": "Keine DNS-Umschreibungen gefunden",
"rewrite_confirm_delete": "Möchten Sie die DNS-Umschreibung für „{{key}}“ wirklich entfernen?", "rewrite_confirm_delete": "Möchten Sie die DNS-Umschreibung für „{{key}}“ wirklich entfernen?",
"rewrite_desc": "Ermöglicht die einfache Konfiguration der benutzerdefinierten DNS-Antwort für einen bestimmten Domainnamen.", "rewrite_desc": "Ermöglicht die einfache Konfiguration der benutzerdefinierten DNS-Antwort für einen bestimmten Domainnamen.",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "Are you sure you want to delete client \"{{key}}\"?", "client_confirm_delete": "Are you sure you want to delete client \"{{key}}\"?",
"list_confirm_delete": "Are you sure you want to delete this list?", "list_confirm_delete": "Are you sure you want to delete this list?",
"auto_clients_title": "Runtime clients", "auto_clients_title": "Runtime clients",
"auto_clients_desc": "Information about IP addresses of devices that are using or may use AdGuard Home. This information is gathered from several sources, including hosts files, reverse DNS, etc.", "auto_clients_desc": "Devices not on the list of Persistent clients that may still use AdGuard Home",
"access_title": "Access settings", "access_title": "Access settings",
"access_desc": "Here you can configure access rules for the AdGuard Home DNS server", "access_desc": "Here you can configure access rules for the AdGuard Home DNS server",
"access_allowed_title": "Allowed clients", "access_allowed_title": "Allowed clients",
@@ -478,9 +478,7 @@
"setup_dns_notice": "In order to use <1>DNS-over-HTTPS</1> or <1>DNS-over-TLS</1>, you need to <0>configure Encryption</0> in AdGuard Home settings.", "setup_dns_notice": "In order to use <1>DNS-over-HTTPS</1> or <1>DNS-over-TLS</1>, you need to <0>configure Encryption</0> in AdGuard Home settings.",
"rewrite_added": "DNS rewrite for \"{{key}}\" successfully added", "rewrite_added": "DNS rewrite for \"{{key}}\" successfully added",
"rewrite_deleted": "DNS rewrite for \"{{key}}\" successfully deleted", "rewrite_deleted": "DNS rewrite for \"{{key}}\" successfully deleted",
"rewrite_updated": "DNS rewrite successfully updated",
"rewrite_add": "Add DNS rewrite", "rewrite_add": "Add DNS rewrite",
"rewrite_edit": "Edit DNS rewrite",
"rewrite_not_found": "No DNS rewrites found", "rewrite_not_found": "No DNS rewrites found",
"rewrite_confirm_delete": "Are you sure you want to delete DNS rewrite for \"{{key}}\"?", "rewrite_confirm_delete": "Are you sure you want to delete DNS rewrite for \"{{key}}\"?",
"rewrite_desc": "Allows to easily configure custom DNS response for a specific domain name.", "rewrite_desc": "Allows to easily configure custom DNS response for a specific domain name.",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "¿Estás seguro de que deseas eliminar el cliente \"{{key}}\"?", "client_confirm_delete": "¿Estás seguro de que deseas eliminar el cliente \"{{key}}\"?",
"list_confirm_delete": "¿Estás seguro de que deseas eliminar esta lista?", "list_confirm_delete": "¿Estás seguro de que deseas eliminar esta lista?",
"auto_clients_title": "Clientes activos", "auto_clients_title": "Clientes activos",
"auto_clients_desc": "Información sobre las direcciones IP de los dispositivos que usan o pueden usar AdGuard Home. Esta información se recopila de varias fuentes, incluidos ficheros de host, DNS inverso, etc.", "auto_clients_desc": "Dispositivos que no están en la lista de clientes persistentes que aún pueden utilizar AdGuard Home",
"access_title": "Configuración de acceso", "access_title": "Configuración de acceso",
"access_desc": "Aquí puedes configurar las reglas de acceso para el servidor DNS de AdGuard Home", "access_desc": "Aquí puedes configurar las reglas de acceso para el servidor DNS de AdGuard Home",
"access_allowed_title": "Clientes permitidos", "access_allowed_title": "Clientes permitidos",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Para utilizar <1>DNS mediante HTTPS</1> o <1>DNS mediante TLS</1>, debes <0>configurar el cifrado</0> en la configuración de AdGuard Home.", "setup_dns_notice": "Para utilizar <1>DNS mediante HTTPS</1> o <1>DNS mediante TLS</1>, debes <0>configurar el cifrado</0> en la configuración de AdGuard Home.",
"rewrite_added": "Reescritura DNS para \"{{key}}\" añadido correctamente", "rewrite_added": "Reescritura DNS para \"{{key}}\" añadido correctamente",
"rewrite_deleted": "Reescritura DNS para \"{{key}}\" eliminado correctamente", "rewrite_deleted": "Reescritura DNS para \"{{key}}\" eliminado correctamente",
"rewrite_updated": "Reconfiguración de DNS actualizada correctamente",
"rewrite_add": "Añadir reescritura DNS", "rewrite_add": "Añadir reescritura DNS",
"rewrite_edit": "Editar reconfiguración de DNS",
"rewrite_not_found": "No se han encontrado reescrituras DNS", "rewrite_not_found": "No se han encontrado reescrituras DNS",
"rewrite_confirm_delete": "¿Estás seguro de que deseas eliminar la reescritura DNS para \"{{key}}\"?", "rewrite_confirm_delete": "¿Estás seguro de que deseas eliminar la reescritura DNS para \"{{key}}\"?",
"rewrite_desc": "Permite configurar fácilmente la respuesta DNS personalizada para un nombre de dominio específico.", "rewrite_desc": "Permite configurar fácilmente la respuesta DNS personalizada para un nombre de dominio específico.",

View File

@@ -268,8 +268,6 @@
"blocking_mode_nxdomain": "NXDOMAIN: پاسخ با کُد NXDOMAIN", "blocking_mode_nxdomain": "NXDOMAIN: پاسخ با کُد NXDOMAIN",
"blocking_mode_null_ip": "Null IP: پاسخ با آدرس آی پی صفر(0.0.0.0 برای A; :: برای AAAA)", "blocking_mode_null_ip": "Null IP: پاسخ با آدرس آی پی صفر(0.0.0.0 برای A; :: برای AAAA)",
"blocking_mode_custom_ip": "آی پی دستی: پاسخ با آدرس آی پی دستی تنظیم شده", "blocking_mode_custom_ip": "آی پی دستی: پاسخ با آدرس آی پی دستی تنظیم شده",
"theme_light": "پوسته روشن",
"theme_dark": "پوسته تیره",
"upstream_dns_client_desc": "اگر این فیلد را خالی نگه دارید، AdGuard Home از سرور پیکربندی شده در <0> تنظیماتDNS </0> استفاده می کند.", "upstream_dns_client_desc": "اگر این فیلد را خالی نگه دارید، AdGuard Home از سرور پیکربندی شده در <0> تنظیماتDNS </0> استفاده می کند.",
"tracker_source": "منبع ردیاب", "tracker_source": "منبع ردیاب",
"source_label": "منبع", "source_label": "منبع",
@@ -440,9 +438,7 @@
"setup_dns_notice": "به منظور استفاده از <1>DNS-over-HTTPS</1> یا <1>DNS-over-TLS</1>، شما نیاز به <0>پیکربندی رمزگذاری</0> در تنظیمات AdGuard Home دارید.", "setup_dns_notice": "به منظور استفاده از <1>DNS-over-HTTPS</1> یا <1>DNS-over-TLS</1>، شما نیاز به <0>پیکربندی رمزگذاری</0> در تنظیمات AdGuard Home دارید.",
"rewrite_added": "بازنویسی DNS برای \"{{key}}\" با موفقیت اضافه شد", "rewrite_added": "بازنویسی DNS برای \"{{key}}\" با موفقیت اضافه شد",
"rewrite_deleted": "بازنویسی DNS برای \"{{key}}\" با موفقیت حذف شد", "rewrite_deleted": "بازنویسی DNS برای \"{{key}}\" با موفقیت حذف شد",
"rewrite_updated": "بازنویسی DNS با موفقیت به روز شد",
"rewrite_add": "افزودن بازنویسی DNS", "rewrite_add": "افزودن بازنویسی DNS",
"rewrite_edit": "بازنویسی DNS را ویرایش کنید",
"rewrite_not_found": "بازنویسی DNS یافت نشد", "rewrite_not_found": "بازنویسی DNS یافت نشد",
"rewrite_confirm_delete": "آیا واقعا میخواهید بازنویسی DNS برای \"{{key}}\" را حذف کنید؟", "rewrite_confirm_delete": "آیا واقعا میخواهید بازنویسی DNS برای \"{{key}}\" را حذف کنید؟",
"rewrite_desc": "به آسانی اجازه پیکربندی پاسخ DNS دستی برای یک نام دامنه خاص را می دهد.", "rewrite_desc": "به آسانی اجازه پیکربندی پاسخ DNS دستی برای یک نام دامنه خاص را می دهد.",
@@ -571,6 +567,5 @@
"use_saved_key": "از کلید ذخیره شده قبلی استفاده کنید", "use_saved_key": "از کلید ذخیره شده قبلی استفاده کنید",
"parental_control": "نظارت والدین", "parental_control": "نظارت والدین",
"safe_browsing": "وب گردی اَمن", "safe_browsing": "وب گردی اَمن",
"form_error_password_length": "رمزعبور باید حداقل {{value}} کاراکتر باشد.", "form_error_password_length": "رمزعبور باید حداقل {{value}} کاراکتر باشد."
"protection_section_label": "حفاظت"
} }

View File

@@ -2,21 +2,21 @@
"client_settings": "Päätelaiteasetukset", "client_settings": "Päätelaiteasetukset",
"example_upstream_reserved": "ylävirta <0>tietyille verkkotunnuksille</0>;", "example_upstream_reserved": "ylävirta <0>tietyille verkkotunnuksille</0>;",
"example_upstream_comment": "kommentti.", "example_upstream_comment": "kommentti.",
"upstream_parallel": "Käytä rinnakkaisia pyyntöjä ja nopeuta selvitystä käyttämällä kaikkia ylävirtapalvelimia samanaikaisesti.", "upstream_parallel": "Käytä rinnakkaisia pyyntöjä ja nopeuta selvitystä käyttämällä kaikkia ylävirran palvelimia samanaikaisesti.",
"parallel_requests": "Rinnakkaiset pyynnöt", "parallel_requests": "Rinnakkaiset pyynnöt",
"load_balancing": "Kuormantasaus", "load_balancing": "Kuormantasaus",
"load_balancing_desc": "Lähetä pyyntö yhdelle ylävirtapalvelimelle kerrallaan. AdGuard Home pyrkii valitsemaan nopeimman palvelimen painotetun satunnaisalgoritminsa avulla.", "load_balancing_desc": "Lähetä pyyntö yhdelle ylävirran palvelimelle kerrallaan. AdGuard Home pyrkii valitsemaan nopeimman palvelimen painotetun satunnaisalgoritminsa avulla.",
"bootstrap_dns": "Bootstrap DNS-palvelimet", "bootstrap_dns": "Bootstrap DNS-palvelimet",
"bootstrap_dns_desc": "Bootstrap DNS-palvelimia käytetään ylävirroiksi määritettyjen DoH/DoT-resolvereiden IP-osoitteiden selvitykseen.", "bootstrap_dns_desc": "Bootstrap DNS-palvelimia käytetään ylävirroiksi määritettyjen DoH/DoT-resolvereiden IP-osoitteiden selvitykseen.",
"local_ptr_title": "Yksityiset käänteis-DNS-palvelimet", "local_ptr_title": "Yksityiset käänteiset DNS-palvelimet",
"local_ptr_desc": "DNS-palvelimet, joita AdGuard Home käyttää paikallisille PTR-pyynnöille. Näitä palvelimia käytetään yksityistä IP-osoitetta käyttävien PTR-pyyntöjen osoitteiden, kuten \"192.168.12.34\", selvitykseen käänteis-DNS:n avulla. Jos ei käytössä, AdGuard Home käyttää käyttöjärjestelmän oletusarvoisia DNS-resolvereita, poislukien AdGuard Homen omat osoitteet.", "local_ptr_desc": "DNS-palvelimet, joita AdGuard Home käyttää paikallisille PTR-pyynnöille. Näitä palvelimia käytetään yksityistä IP-osoitetta käyttävien PTR-pyyntöjen osoitteiden, kuten \"192.168.12.34\", selvitykseen käänteisen DNS:n avulla. Jos ei käytössä, AdGuard Home käyttää käyttöjärjestelmän oletusarvoisia DNS-resolvereita, poislukien AdGuard Homen omat osoitteet.",
"local_ptr_default_resolver": "Oletusarvoisesti AdGuard Home käyttää seuraavia käänteis-DNS-resolvereita: {{ip}}.", "local_ptr_default_resolver": "Oletusarvoisesti AdGuard Home käyttää seuraavia käänteisDNS-resolvereita: {{ip}}.",
"local_ptr_no_default_resolver": "AdGuard Home ei voinut määrittää tälle järjestelmälle sopivaa yksityistä käänteis-DNS-resolveria.", "local_ptr_no_default_resolver": "AdGuard Home ei voinut määrittää tälle järjestelmälle sopivaa yksityistä käänteisDNS-resolveria.",
"local_ptr_placeholder": "Syötä yksi palvelimen osoite per rivi", "local_ptr_placeholder": "Syötä yksi palvelimen osoite per rivi",
"resolve_clients_title": "Käytä päätelaitteiden IP-osoitteille käänteistä selvitystä", "resolve_clients_title": "Käytä päätelaitteiden IP-osoitteille käänteistä selvitystä",
"resolve_clients_desc": "Selvitä päätelaitteiden IP-osoitteiden isäntänimet käänteisesti lähettämällä PTR-pyynnöt sopiville resolvereille (yksityiset DNS-palvelimet paikallisille päätelaitteille, yvirtapalvelimet päätelaitteille, joilla on julkiset IP-osoitteet).", "resolve_clients_desc": "Selvitä päätelaitteiden IP-osoitteiden isäntänimet käänteisesti lähettämällä PTR-pyynnöt sopiville resolvereille (yksityiset DNS-palvelimet paikallisille päätelaitteille, lähtevät palvelimet päätelaitteille, joilla on julkiset IP-osoitteet).",
"use_private_ptr_resolvers_title": "Käytä yksityisiä käänteis-DNS-resolvereita", "use_private_ptr_resolvers_title": "Käytä yksityisiä käänteisDNS-resolvereita",
"use_private_ptr_resolvers_desc": "Suorita käänteis-DNS-selvitykset paikallisesti tarjotuille osoitteille käyttäen näitä ylävirtapalvelimia. Jos ei käytössä, vastaa AdGuard Home kaikkiin sen tyyppisiin PTR-pyyntöihin NXDOMAIN-arvolla, pois lukien DHCP, /etc/hosts, yms. -tiedoista tunnistettut päätelaitteet.", "use_private_ptr_resolvers_desc": "Suorita käänteiset DNS-selvitykset paikallisesti tarjotuille osoitteille käyttäen näitä ylävirran palvelimia. Jos ei käytössä, vastaa AdGuard Home kaikkiin sen tyyppisiin PTR-pyyntöihin NXDOMAIN-arvolla, pois lukien DHCP, /etc/hosts, yms. -tiedoista tunnistettut päätelaitteet.",
"check_dhcp_servers": "Etsi DHCP-palvelimia", "check_dhcp_servers": "Etsi DHCP-palvelimia",
"save_config": "Tallenna asetukset", "save_config": "Tallenna asetukset",
"enabled_dhcp": "DHCP-palvelin otettiin käyttöön", "enabled_dhcp": "DHCP-palvelin otettiin käyttöön",
@@ -86,7 +86,7 @@
"request_details": "Pyynnön tiedot", "request_details": "Pyynnön tiedot",
"client_details": "Päätelaitteen tiedot", "client_details": "Päätelaitteen tiedot",
"details": "Yksityiskohdat", "details": "Yksityiskohdat",
"back": "Palaa takaisin", "back": "Takaisin",
"dashboard": "Tila", "dashboard": "Tila",
"settings": "Asetukset", "settings": "Asetukset",
"filters": "Suodattimet", "filters": "Suodattimet",
@@ -146,8 +146,8 @@
"no_servers_specified": "Palvelimia ei ole määritetty", "no_servers_specified": "Palvelimia ei ole määritetty",
"general_settings": "Yleiset asetukset", "general_settings": "Yleiset asetukset",
"dns_settings": "DNS-asetukset", "dns_settings": "DNS-asetukset",
"dns_blocklists": "DNS-estot", "dns_blocklists": "DNS-estolistat",
"dns_allowlists": "DNS-sallinnat", "dns_allowlists": "DNS-sallittujen listat",
"dns_blocklists_desc": "AdGuard Home estää estolistalla olevat verkkotunnukset.", "dns_blocklists_desc": "AdGuard Home estää estolistalla olevat verkkotunnukset.",
"dns_allowlists_desc": "DNS-sallittujen listalla olevat verkkotunnukset sallitaan myös silloin, jos ne ovat jollain muulla estolistalla.", "dns_allowlists_desc": "DNS-sallittujen listalla olevat verkkotunnukset sallitaan myös silloin, jos ne ovat jollain muulla estolistalla.",
"custom_filtering_rules": "Omat suodatussäännöt", "custom_filtering_rules": "Omat suodatussäännöt",
@@ -220,9 +220,9 @@
"example_upstream_tcp_port": "tavallinen DNS (TCP, portti);", "example_upstream_tcp_port": "tavallinen DNS (TCP, portti);",
"example_upstream_tcp_hostname": "tavallinen DNS (TCP, isäntänimi);", "example_upstream_tcp_hostname": "tavallinen DNS (TCP, isäntänimi);",
"all_lists_up_to_date_toast": "Kaikki listat ovat ajan tasalla", "all_lists_up_to_date_toast": "Kaikki listat ovat ajan tasalla",
"updated_upstream_dns_toast": "Ylävirtapalvelimet tallennettiin", "updated_upstream_dns_toast": "Ylävirtojen palvelimet tallennettiin",
"dns_test_ok_toast": "Määritetyt DNS-palvelimet toimivat oikein", "dns_test_ok_toast": "Määritetyt DNS-palvelimet toimivat oikein",
"dns_test_not_ok_toast": "Palvelin \"{{key}}\": Ei voitu käyttää, tarkista oikeinkirjoitus", "dns_test_not_ok_toast": "Palvelin \"{{key}}\": ei voitu käyttää, tarkista sen oikeinkirjoitus",
"dns_test_warning_toast": "Datavuon \"{{key}}\" ei vastaa testipyyntöihin eikä välttämättä toimi kunnolla", "dns_test_warning_toast": "Datavuon \"{{key}}\" ei vastaa testipyyntöihin eikä välttämättä toimi kunnolla",
"unblock": "Salli", "unblock": "Salli",
"block": "Estä", "block": "Estä",
@@ -444,7 +444,7 @@
"client_confirm_delete": "Haluatko varmasti poistaa päätelaitteen \"{{key}}\"?", "client_confirm_delete": "Haluatko varmasti poistaa päätelaitteen \"{{key}}\"?",
"list_confirm_delete": "Haluatko varmasti poistaa tämän listan?", "list_confirm_delete": "Haluatko varmasti poistaa tämän listan?",
"auto_clients_title": "Määrittämättömät päätelaitteet", "auto_clients_title": "Määrittämättömät päätelaitteet",
"auto_clients_desc": "Päätelaitteet, joita ei ole määritetty pysyviksi ja jotka voivat silti käyttää AdGuard Homea. Näitä tietoja kertään useista lähteistä, mm. hosts-tiedostoista ja kääteis-DNS:llä.", "auto_clients_desc": "Päätelaitteet, joita ei ole määritetty pysyviksi ja jotka voivat silti käyttää AdGuard Homea.",
"access_title": "Käytön asetukset", "access_title": "Käytön asetukset",
"access_desc": "Tässä voidaan määrittää AdGuard Homen DNS-palvelimen käyttöoikeussääntöjä.", "access_desc": "Tässä voidaan määrittää AdGuard Homen DNS-palvelimen käyttöoikeussääntöjä.",
"access_allowed_title": "Sallitut päätelaitteet", "access_allowed_title": "Sallitut päätelaitteet",
@@ -478,9 +478,7 @@
"setup_dns_notice": "<1>DNS-over-HTTPS</1> tai <1>DNS-over-TLS</1> -toteutuksia varten, on AdGuard Homen <0>Salausasetukset</0> määritettävä.", "setup_dns_notice": "<1>DNS-over-HTTPS</1> tai <1>DNS-over-TLS</1> -toteutuksia varten, on AdGuard Homen <0>Salausasetukset</0> määritettävä.",
"rewrite_added": "Kohteen \"{{key}}\" DNS-uudelleenohjaus lisättiin", "rewrite_added": "Kohteen \"{{key}}\" DNS-uudelleenohjaus lisättiin",
"rewrite_deleted": "Kohteen \"{{key}}\" DNS-uudelleenohjaus poistettiin", "rewrite_deleted": "Kohteen \"{{key}}\" DNS-uudelleenohjaus poistettiin",
"rewrite_updated": "DNS-uudelleenohjaukset päivitettiin",
"rewrite_add": "Lisää DNS-uudelleenohjaus", "rewrite_add": "Lisää DNS-uudelleenohjaus",
"rewrite_edit": "Muokkaa DNS-uudelleenohjausta",
"rewrite_not_found": "DNS-uudelleenohjauksia ei löytynyt", "rewrite_not_found": "DNS-uudelleenohjauksia ei löytynyt",
"rewrite_confirm_delete": "Haluatko varmasti poistaa DNS-uudelleenohjauksen kohteelle \"{{key}}\"?", "rewrite_confirm_delete": "Haluatko varmasti poistaa DNS-uudelleenohjauksen kohteelle \"{{key}}\"?",
"rewrite_desc": "Mahdollistaa oman DNS-vastauksen helpon määrityksen tietylle verkkotunnukselle.", "rewrite_desc": "Mahdollistaa oman DNS-vastauksen helpon määrityksen tietylle verkkotunnukselle.",
@@ -623,13 +621,13 @@
"enter_cache_size": "Syötä välimuistin koko (tavuina)", "enter_cache_size": "Syötä välimuistin koko (tavuina)",
"enter_cache_ttl_min_override": "Syötä vähimmäis-TTL (sekunteina)", "enter_cache_ttl_min_override": "Syötä vähimmäis-TTL (sekunteina)",
"enter_cache_ttl_max_override": "Syötä enimmäis-TTL (sekunteina)", "enter_cache_ttl_max_override": "Syötä enimmäis-TTL (sekunteina)",
"cache_ttl_min_override_desc": "Pidennä ylävirtapalvelimelta vastaanotettuja, lyhyitä elinaika-arvoja (sekunteina) tallennettaessa DNS-vastauksia välimuistiin.", "cache_ttl_min_override_desc": "Pidennä ylävirran palvelimelta vastaanotettuja, lyhyitä elinaika-arvoja (sekunteina) tallennettaessa DNS-vastauksia välimuistiin.",
"cache_ttl_max_override_desc": "Määritä DNS-välimuistin kohteiden enimmäiselinaika (sekunteina).", "cache_ttl_max_override_desc": "Määritä DNS-välimuistin kohteiden enimmäiselinaika (sekunteina).",
"ttl_cache_validation": "Välimuistin vähimmäiselinajan on oltava pienempi tai sama kuin enimmäiselinajan", "ttl_cache_validation": "Välimuistin vähimmäiselinajan on oltava pienempi tai sama kuin enimmäiselinajan",
"cache_optimistic": "Optimistinen välimuisti", "cache_optimistic": "Optimistinen välimuisti",
"cache_optimistic_desc": "Pakota AdGuard Home vastaamaan välimuistista vaikka tiedot olisivat vanhentuneet. Pyri samalla myös päivittämään tiedot.", "cache_optimistic_desc": "Pakota AdGuard Home vastaamaan välimuistista vaikka tiedot olisivat vanhentuneet. Pyri samalla myös päivittämään tiedot.",
"filter_category_general": "Yleiset", "filter_category_general": "Yleiset",
"filter_category_security": "Tietoturva", "filter_category_security": "Turvallisuus",
"filter_category_regional": "Alueelliset", "filter_category_regional": "Alueelliset",
"filter_category_other": "Muut", "filter_category_other": "Muut",
"filter_category_general_desc": "Listat, jotka estävät seurannan ja mainokset useimmilla laitteilla", "filter_category_general_desc": "Listat, jotka estävät seurannan ja mainokset useimmilla laitteilla",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "Voulez-vous vraiment supprimer le client « {{key}} » ?", "client_confirm_delete": "Voulez-vous vraiment supprimer le client « {{key}} » ?",
"list_confirm_delete": "Voulez-vous vraiment supprimer cette liste ?", "list_confirm_delete": "Voulez-vous vraiment supprimer cette liste ?",
"auto_clients_title": "Clients d'exécution", "auto_clients_title": "Clients d'exécution",
"auto_clients_desc": "Informations sur les adresses IP des appareils qui utilisent ou pourraient utiliser AdGuard Home. Ces informations sont recueillies à partir de plusieurs sources, notamment les fichiers hosts, le DNS inverse, etc.", "auto_clients_desc": "Appareils ne figurant pas sur la liste des clients persistants qui peuvent encore utiliser AdGuard Home.",
"access_title": "Paramètres d'accès", "access_title": "Paramètres d'accès",
"access_desc": "Ici vous pouvez configurer les règles d'accès au serveur DNS AdGuard Home", "access_desc": "Ici vous pouvez configurer les règles d'accès au serveur DNS AdGuard Home",
"access_allowed_title": "Clients autorisés", "access_allowed_title": "Clients autorisés",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Pour utiliser le <1>DNS-over-HTTPS</1> ou le <1>DNS-over-TLS</1>, vous devez <0>configurer le Chiffrement</0> dans les paramètres de AdGuard Home.", "setup_dns_notice": "Pour utiliser le <1>DNS-over-HTTPS</1> ou le <1>DNS-over-TLS</1>, vous devez <0>configurer le Chiffrement</0> dans les paramètres de AdGuard Home.",
"rewrite_added": "Réécriture DNS pour « {{key}} » ajoutée", "rewrite_added": "Réécriture DNS pour « {{key}} » ajoutée",
"rewrite_deleted": "Réécriture DNS pour « {{key}} » supprimée", "rewrite_deleted": "Réécriture DNS pour « {{key}} » supprimée",
"rewrite_updated": "Réécriture DNS mise à jour",
"rewrite_add": "Ajouter une réécriture DNS", "rewrite_add": "Ajouter une réécriture DNS",
"rewrite_edit": "Modifier la réécriture DNS",
"rewrite_not_found": "Aucune réécriture DNS trouvée", "rewrite_not_found": "Aucune réécriture DNS trouvée",
"rewrite_confirm_delete": "Voulez-vous vraiment supprimer la réécriture DNS pour « {{key}} » ?", "rewrite_confirm_delete": "Voulez-vous vraiment supprimer la réécriture DNS pour « {{key}} » ?",
"rewrite_desc": "Permet de configurer facilement la réponse DNS personnalisée pour un nom de domaine spécifique.", "rewrite_desc": "Permet de configurer facilement la réponse DNS personnalisée pour un nom de domaine spécifique.",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "Jeste li sigurni da želite ukloniti \"{{key}}\" klijenta?", "client_confirm_delete": "Jeste li sigurni da želite ukloniti \"{{key}}\" klijenta?",
"list_confirm_delete": "Jeste li sigurni da želite ukloniti ovaj popis?", "list_confirm_delete": "Jeste li sigurni da želite ukloniti ovaj popis?",
"auto_clients_title": "Runtime klijenti", "auto_clients_title": "Runtime klijenti",
"auto_clients_desc": "Informacije o IP adresama uređaja koji koriste ili bi mogli koristiti AdGuard Home. Ove informacije prikupljaju se iz nekoliko izvora, uključujući datoteke hostova, obrnuti DNS itd.", "auto_clients_desc": "Podaci na klijentu koji koriste AdGuard Home, ali se ne mijenjaju u postavkama",
"access_title": "Postavke pristupa", "access_title": "Postavke pristupa",
"access_desc": "Ovdje možete konfigurirati pravila pristupa za AdGuard Home DNS poslužitelj", "access_desc": "Ovdje možete konfigurirati pravila pristupa za AdGuard Home DNS poslužitelj",
"access_allowed_title": "Dopušteni klijenti", "access_allowed_title": "Dopušteni klijenti",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Da biste koristili <1>DNS-over-HTTPS</1> ili <1>DNS-over-TLS</1>, morate <0>postaviti šifriranje</0> u AdGuard Home postavkama.", "setup_dns_notice": "Da biste koristili <1>DNS-over-HTTPS</1> ili <1>DNS-over-TLS</1>, morate <0>postaviti šifriranje</0> u AdGuard Home postavkama.",
"rewrite_added": "DNS prijepis za \"{{key}}\" je uspješno dodan", "rewrite_added": "DNS prijepis za \"{{key}}\" je uspješno dodan",
"rewrite_deleted": "DNS prijepis za \"{{key}}\" je uspješno uklonjen", "rewrite_deleted": "DNS prijepis za \"{{key}}\" je uspješno uklonjen",
"rewrite_updated": "Prepisivanje DNS-a uspješno ažurirano",
"rewrite_add": "Dodaj DNS prijepis", "rewrite_add": "Dodaj DNS prijepis",
"rewrite_edit": "Uredite prepisivanje DNS-a",
"rewrite_not_found": "Nema DNS prijepisa", "rewrite_not_found": "Nema DNS prijepisa",
"rewrite_confirm_delete": "Jeste li sigurni da želite ukloniti DNS prijepis za \"{{key}}\" klijenta?", "rewrite_confirm_delete": "Jeste li sigurni da želite ukloniti DNS prijepis za \"{{key}}\" klijenta?",
"rewrite_desc": "Omogućuje jednostavno postavljanje prilagođenog DNS odgovora za određenu domenu.", "rewrite_desc": "Omogućuje jednostavno postavljanje prilagođenog DNS odgovora za određenu domenu.",

View File

@@ -167,7 +167,6 @@
"enabled_parental_toast": "Szülői felügyelet engedélyezve", "enabled_parental_toast": "Szülői felügyelet engedélyezve",
"disabled_safe_search_toast": "Biztonságos keresés letiltva", "disabled_safe_search_toast": "Biztonságos keresés letiltva",
"enabled_save_search_toast": "Biztonságos keresés engedélyezve", "enabled_save_search_toast": "Biztonságos keresés engedélyezve",
"updated_save_search_toast": "A Biztonságos keresés beállításai frissítve",
"enabled_table_header": "Engedélyezve", "enabled_table_header": "Engedélyezve",
"name_table_header": "Név", "name_table_header": "Név",
"list_url_table_header": "Lista URL-je", "list_url_table_header": "Lista URL-je",
@@ -291,8 +290,6 @@
"rate_limit": "Kérések korlátozása", "rate_limit": "Kérések korlátozása",
"edns_enable": "EDNS kliens alhálózat engedélyezése", "edns_enable": "EDNS kliens alhálózat engedélyezése",
"edns_cs_desc": "Adja hozzá az EDNS Client Subnet beállítást (ECS) a felfelé irányuló kérésekhez, és naplózza a kliensek által küldött értékeket a lekérdezési naplóban.", "edns_cs_desc": "Adja hozzá az EDNS Client Subnet beállítást (ECS) a felfelé irányuló kérésekhez, és naplózza a kliensek által küldött értékeket a lekérdezési naplóban.",
"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_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.",
"blocking_ipv4_desc": "A blokkolt A kéréshez visszaadandó IP-cím", "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_ipv6_desc": "A blokkolt AAAA kéréshez visszaadandó IP-cím",
@@ -444,7 +441,7 @@
"client_confirm_delete": "Biztosan törölni szeretné a(z) \"{{key}}\" klienst?", "client_confirm_delete": "Biztosan törölni szeretné a(z) \"{{key}}\" klienst?",
"list_confirm_delete": "Biztosan törölni kívánja ezt a listát?", "list_confirm_delete": "Biztosan törölni kívánja ezt a listát?",
"auto_clients_title": "Futási idejű kliensek", "auto_clients_title": "Futási idejű kliensek",
"auto_clients_desc": "Az AdGuard Home-ot használó vagy esetleg használó eszközök IP-címeire vonatkozó információk. Ezeket az információkat több forrásból gyűjtik, beleértve a hosts fájlokat, a fordított DNS-t stb.", "auto_clients_desc": "Ezek az eszközök nem szerepelnek a fenntartott kliensek listáján, de használják az AdGuard Home-ot",
"access_title": "Hozzáférési beállítások", "access_title": "Hozzáférési beállítások",
"access_desc": "Itt konfigurálhatja az AdGuard Home DNS-kiszolgáló hozzáférési szabályait", "access_desc": "Itt konfigurálhatja az AdGuard Home DNS-kiszolgáló hozzáférési szabályait",
"access_allowed_title": "Engedélyezett kliensek", "access_allowed_title": "Engedélyezett kliensek",
@@ -478,9 +475,7 @@
"setup_dns_notice": "Ahhoz, hogy a <1>DNS-over-HTTPS</1> vagy a <1>DNS-over-TLS</1> valamelyikét használja, muszáj <0>beállítania a titkosítást</0> az AdGuard Home beállításaiban.", "setup_dns_notice": "Ahhoz, hogy a <1>DNS-over-HTTPS</1> vagy a <1>DNS-over-TLS</1> valamelyikét használja, muszáj <0>beállítania a titkosítást</0> az AdGuard Home beállításaiban.",
"rewrite_added": "DNS átírás a(z) \"{{key}}\" kulcshoz sikeresen hozzáadva", "rewrite_added": "DNS átírás a(z) \"{{key}}\" kulcshoz sikeresen hozzáadva",
"rewrite_deleted": "DNS átírás a(z) \"{{key}}\" kulcshoz sikeresen törölve", "rewrite_deleted": "DNS átírás a(z) \"{{key}}\" kulcshoz sikeresen törölve",
"rewrite_updated": "A DNS újraírása sikeresen frissítve",
"rewrite_add": "DNS átírás hozzáadása", "rewrite_add": "DNS átírás hozzáadása",
"rewrite_edit": "DNS újraírás szerkesztése",
"rewrite_not_found": "Nem találhatók DNS átírások", "rewrite_not_found": "Nem találhatók DNS átírások",
"rewrite_confirm_delete": "Biztosan törölni szeretné a DNS átírást ehhez: \"{{key}}\"?", "rewrite_confirm_delete": "Biztosan törölni szeretné a DNS átírást ehhez: \"{{key}}\"?",
"rewrite_desc": "Lehetővé teszi, hogy egyszerűen beállítson egyéni DNS választ egy adott domain névhez.", "rewrite_desc": "Lehetővé teszi, hogy egyszerűen beállítson egyéni DNS választ egy adott domain névhez.",
@@ -528,10 +523,6 @@
"statistics_retention_confirm": "Biztos benne, hogy megváltoztatja a statisztika megőrzési idejét? Ha csökkentette az értéket, a megadottnál korábbi adatok elvesznek", "statistics_retention_confirm": "Biztos benne, hogy megváltoztatja a statisztika megőrzési idejét? Ha csökkentette az értéket, a megadottnál korábbi adatok elvesznek",
"statistics_cleared": "A statisztikák sikeresen vissza lettek állítva", "statistics_cleared": "A statisztikák sikeresen vissza lettek állítva",
"statistics_enable": "Statisztikák engedélyezése", "statistics_enable": "Statisztikák engedélyezése",
"ignore_domains": "Figyelmen kívül hagyott domainek (újsorral elválasztva)",
"ignore_domains_title": "Figyelmen kívül hagyott domainek",
"ignore_domains_desc_stats": "Az ezekre a tartományokra vonatkozó lekérdezések nem kerülnek a statisztikákba",
"ignore_domains_desc_query": "Az ezekhez a tartományokhoz tartozó lekérdezések nem kerülnek a lekérdezési naplóba",
"interval_hours": "{{count}} óra", "interval_hours": "{{count}} óra",
"interval_hours_plural": "{{count}} óra", "interval_hours_plural": "{{count}} óra",
"filters_configuration": "Szűrők beállításai", "filters_configuration": "Szűrők beállításai",
@@ -652,29 +643,5 @@
"confirm_dns_cache_clear": "Biztos benne, hogy törölni szeretné a DNS-gyorsítótárat?", "confirm_dns_cache_clear": "Biztos benne, hogy törölni szeretné a DNS-gyorsítótárat?",
"cache_cleared": "A DNS gyorsítótár sikeresen törlődött", "cache_cleared": "A DNS gyorsítótár sikeresen törlődött",
"clear_cache": "Gyorsítótár törlése", "clear_cache": "Gyorsítótár törlése",
"make_static": "Statikussá tétel", "protection_section_label": "Védelem"
"theme_auto_desc": "Automatikus (az eszköz színsémájától függően)",
"theme_dark_desc": "Sötét téma",
"theme_light_desc": "Világos téma",
"disable_for_seconds": "{{count}} másodpercig",
"disable_for_seconds_plural": "{{count}} másodpercig",
"disable_for_minutes": "{{count}} percig",
"disable_for_minutes_plural": "{{count}} percig",
"disable_for_hours": "{{count}} óráig",
"disable_for_hours_plural": "{{count}} óráig",
"disable_until_tomorrow": "Holnapig",
"disable_notify_for_seconds": "Kapcsolja ki a védelmet {{count}} másodpercre",
"disable_notify_for_seconds_plural": "Kapcsolja ki a védelmet {{count}} másodpercre",
"disable_notify_for_minutes": "Kapcsolja ki a védelmet {{count}} percre",
"disable_notify_for_minutes_plural": "Kapcsolja ki a védelmet {{count}} percre",
"disable_notify_for_hours": "Kapcsolja ki a védelmet {{count}} órára",
"disable_notify_for_hours_plural": "Kapcsolja ki a védelmet {{count}} órára",
"disable_notify_until_tomorrow": "Holnapig kapcsolja ki a védelmet",
"enable_protection_timer": "A védelem {{time}}-kor aktiválódik",
"custom_retention_input": "Adja meg a megőrzést órákban",
"custom_rotation_input": "Írja be a forgatást órákban",
"protection_section_label": "Védelem",
"log_and_stats_section_label": "Lekérdezési napló és statisztikák",
"ignore_query_log": "Figyelmen kívül hagyja ezt az ügyfelet a lekérdezési naplóban",
"ignore_statistics": "Hagyja figyelmen kívül ezt az ügyfelet a statisztikákban"
} }

View File

@@ -474,9 +474,7 @@
"setup_dns_notice": "Jikalau ingin menggunakan <1>DNS-over-HTTPS</1> atau <1>DNS-over-TLS</1>, Anda perlu <0>mengatur Enkripsi</0> pada pengaturan AdGuard Home.", "setup_dns_notice": "Jikalau ingin menggunakan <1>DNS-over-HTTPS</1> atau <1>DNS-over-TLS</1>, Anda perlu <0>mengatur Enkripsi</0> pada pengaturan AdGuard Home.",
"rewrite_added": "DNS rewrite untuk \"{{key}}\" berhasil ditambahkan", "rewrite_added": "DNS rewrite untuk \"{{key}}\" berhasil ditambahkan",
"rewrite_deleted": "DNS rewrite untuk \"{{key}}\" berhasil dihapus", "rewrite_deleted": "DNS rewrite untuk \"{{key}}\" berhasil dihapus",
"rewrite_updated": "Penulisan ulang DNS berhasil diperbarui",
"rewrite_add": "Tambah DNS rewrite", "rewrite_add": "Tambah DNS rewrite",
"rewrite_edit": "Edit penulisan ulang DNS",
"rewrite_not_found": "Tidak ada DNS rewrite ditemukan", "rewrite_not_found": "Tidak ada DNS rewrite ditemukan",
"rewrite_confirm_delete": "Apakah anda yakin ingin menghapus DNS rewrite untuk \"{{key}}\"?", "rewrite_confirm_delete": "Apakah anda yakin ingin menghapus DNS rewrite untuk \"{{key}}\"?",
"rewrite_desc": "Memungkinkan untuk dengan mudah mengkonfigurasi respons DNS kustom untuk nama domain tertentu.", "rewrite_desc": "Memungkinkan untuk dengan mudah mengkonfigurasi respons DNS kustom untuk nama domain tertentu.",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "Sei sicuro di voler eliminare il client \"{{key}}\"?", "client_confirm_delete": "Sei sicuro di voler eliminare il client \"{{key}}\"?",
"list_confirm_delete": "Sei sicuro di voler eliminare questo elenco?", "list_confirm_delete": "Sei sicuro di voler eliminare questo elenco?",
"auto_clients_title": "Client in tempo reale", "auto_clients_title": "Client in tempo reale",
"auto_clients_desc": "Informazioni sugli indirizzi IP dei dispositivi che utilizzano o potrebbero utilizzare AdGuard Home. Queste informazioni vengono raccolte da diverse fonti, inclusi file host, DNS inverso, ecc.", "auto_clients_desc": "Dispositivi non presenti nell'elenco dei client Persistenti che possono ancora utilizzare AdGuard Home",
"access_title": "Impostazioni di accesso", "access_title": "Impostazioni di accesso",
"access_desc": "Qui puoi configurare le regole d'accesso per il server DNS di AdGuard Home", "access_desc": "Qui puoi configurare le regole d'accesso per il server DNS di AdGuard Home",
"access_allowed_title": "Client permessi", "access_allowed_title": "Client permessi",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Per utilizzare <1>DNS su HTTPS</1> o <1>DNS su TLS</1>, è necessario <0>configurare la crittografia</0> nelle impostazioni di AdGuard Home.", "setup_dns_notice": "Per utilizzare <1>DNS su HTTPS</1> o <1>DNS su TLS</1>, è necessario <0>configurare la crittografia</0> nelle impostazioni di AdGuard Home.",
"rewrite_added": "Riscrittura DNS per \"{{key}}\" aggiunta correttamente", "rewrite_added": "Riscrittura DNS per \"{{key}}\" aggiunta correttamente",
"rewrite_deleted": "La riscrittura DNS per \"{{key}}\" è stata eliminata correttamente", "rewrite_deleted": "La riscrittura DNS per \"{{key}}\" è stata eliminata correttamente",
"rewrite_updated": "Riscrittura DNS aggiornata correttamente",
"rewrite_add": "Aggiungi la riscrittura DNS", "rewrite_add": "Aggiungi la riscrittura DNS",
"rewrite_edit": "Modifica della riscrittura DNS",
"rewrite_not_found": "Nessuna riscrittura DNS trovata", "rewrite_not_found": "Nessuna riscrittura DNS trovata",
"rewrite_confirm_delete": "Sei sicuro di voler cancellare la riscrittura DNS per \"{{key}}\"?", "rewrite_confirm_delete": "Sei sicuro di voler cancellare la riscrittura DNS per \"{{key}}\"?",
"rewrite_desc": "Consente di configurare facilmente la risposta DNS personalizzata per un nome di dominio specifico.", "rewrite_desc": "Consente di configurare facilmente la risposta DNS personalizzata per un nome di dominio specifico.",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "クライアント \"{{key}}\" を削除してもよろしいですか?", "client_confirm_delete": "クライアント \"{{key}}\" を削除してもよろしいですか?",
"list_confirm_delete": "このリストを削除してもよろしいですか?", "list_confirm_delete": "このリストを削除してもよろしいですか?",
"auto_clients_title": "ランタイムクライアント", "auto_clients_title": "ランタイムクライアント",
"auto_clients_desc": "AdGuard Home を使用している、または使用する可能性のあるデバイスの IP アドレスに関する情報です。この情報は、hosts ファイル、リバース DNS など、複数の情報源から収集されます。", "auto_clients_desc": "永続的クライアントのリストに未登録で、AdGuard Homeを使用する場合があるデバイスのリスト。",
"access_title": "アクセス設定", "access_title": "アクセス設定",
"access_desc": "こちらでは、AdGuard Home DNSサーバーのアクセスルールを設定できます。", "access_desc": "こちらでは、AdGuard Home DNSサーバーのアクセスルールを設定できます。",
"access_allowed_title": "許可されたクライアント", "access_allowed_title": "許可されたクライアント",
@@ -478,9 +478,7 @@
"setup_dns_notice": "<1>DNS-over-HTTPS</1>または<1>DNS-over-TLS</1>を使用するには、AdGuard Home 設定の<0>暗号化設定</0>が必要です。", "setup_dns_notice": "<1>DNS-over-HTTPS</1>または<1>DNS-over-TLS</1>を使用するには、AdGuard Home 設定の<0>暗号化設定</0>が必要です。",
"rewrite_added": "\"{{key}}\" のDNS書き換え情報を追加完了しました", "rewrite_added": "\"{{key}}\" のDNS書き換え情報を追加完了しました",
"rewrite_deleted": "\"{{key}}\" のDNS書き換え情報を削除完了しました", "rewrite_deleted": "\"{{key}}\" のDNS書き換え情報を削除完了しました",
"rewrite_updated": "DNS rewrite を更新完了しました。",
"rewrite_add": "DNS書き換え情報を追加する", "rewrite_add": "DNS書き換え情報を追加する",
"rewrite_edit": "DNS rewrite を編集する",
"rewrite_not_found": "DNS書き換え情報はありません", "rewrite_not_found": "DNS書き換え情報はありません",
"rewrite_confirm_delete": "\"{{key}}\" のDNS書き換え情報を削除してもよろしいですか", "rewrite_confirm_delete": "\"{{key}}\" のDNS書き換え情報を削除してもよろしいですか",
"rewrite_desc": "特定のドメイン名に対するDNS応答を簡単にカスタマイズすることを可能にします。", "rewrite_desc": "特定のドメイン名に対するDNS応答を簡単にカスタマイズすることを可能にします。",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "정말 클라이언트 '{{key}}'을(를) 삭제하시겠습니까?", "client_confirm_delete": "정말 클라이언트 '{{key}}'을(를) 삭제하시겠습니까?",
"list_confirm_delete": "정말로 이 목록을 제거하시겠습니까?", "list_confirm_delete": "정말로 이 목록을 제거하시겠습니까?",
"auto_clients_title": "런타임 클라이언트", "auto_clients_title": "런타임 클라이언트",
"auto_clients_desc": "AdGuard Home을 사용 중이거나 사용할 수 있는 기기의 IP 주소에 대한 정보가 표시됩니다. 이 정보는 호스트 파일, 역방향 DNS 등 여러 소스에서 수집됩니다.", "auto_clients_desc": "AdGuard Home을 계속 사용할 수 있는 영구 클라이언트 목록에 없는 디바이스입니다",
"access_title": "접근 설정", "access_title": "접근 설정",
"access_desc": "여기에서 AdGuard Home DNS 서버에 대한 액세스 규칙을 설정할 수 있습니다", "access_desc": "여기에서 AdGuard Home DNS 서버에 대한 액세스 규칙을 설정할 수 있습니다",
"access_allowed_title": "허용된 클라이언트", "access_allowed_title": "허용된 클라이언트",
@@ -478,9 +478,7 @@
"setup_dns_notice": "<1>DNS-over-HTTPS</1> 또는 <1>DNS-over-TLS를</1> 사용하려면 AdGuard Home 설정에서 <0>암호화를 구성해야 합니다.</0>", "setup_dns_notice": "<1>DNS-over-HTTPS</1> 또는 <1>DNS-over-TLS를</1> 사용하려면 AdGuard Home 설정에서 <0>암호화를 구성해야 합니다.</0>",
"rewrite_added": "'{{key}}'에 대한 DNS 수정 정보를 성공적으로 추가 됩니다", "rewrite_added": "'{{key}}'에 대한 DNS 수정 정보를 성공적으로 추가 됩니다",
"rewrite_deleted": "'{{key}}'에 대한 DNS 수정 정보를 성공적으로 삭제 됩니다", "rewrite_deleted": "'{{key}}'에 대한 DNS 수정 정보를 성공적으로 삭제 됩니다",
"rewrite_updated": "DNS 다시 쓰기 업데이트 완료",
"rewrite_add": "DNS 변환 정보를 추가합니다", "rewrite_add": "DNS 변환 정보를 추가합니다",
"rewrite_edit": "DNS 다시 쓰기 편집",
"rewrite_not_found": "DNS 변경 정보를 찾을 수 없습니다", "rewrite_not_found": "DNS 변경 정보를 찾을 수 없습니다",
"rewrite_confirm_delete": "'{{key}}'에 대한 DNS 변경 정보를 삭제하시겠습니까?", "rewrite_confirm_delete": "'{{key}}'에 대한 DNS 변경 정보를 삭제하시겠습니까?",
"rewrite_desc": "특정 도메인 이름에 대한 사용자 지정 DNS 응답을 쉽게 구성할 수 있습니다.", "rewrite_desc": "특정 도메인 이름에 대한 사용자 지정 DNS 응답을 쉽게 구성할 수 있습니다.",

View File

@@ -186,7 +186,7 @@
"cancel_btn": "Annuleren", "cancel_btn": "Annuleren",
"enter_name_hint": "Voeg naam toe", "enter_name_hint": "Voeg naam toe",
"enter_url_or_path_hint": "Voer een URL in of het pad van de lijst", "enter_url_or_path_hint": "Voer een URL in of het pad van de lijst",
"check_updates_btn": "Controleren op updates", "check_updates_btn": "Controleer op updates",
"new_blocklist": "Nieuwe blokkeerlijst", "new_blocklist": "Nieuwe blokkeerlijst",
"new_allowlist": "Nieuwe toelatingslijst", "new_allowlist": "Nieuwe toelatingslijst",
"edit_blocklist": "Blokkeerlijst beheren", "edit_blocklist": "Blokkeerlijst beheren",
@@ -444,7 +444,7 @@
"client_confirm_delete": "Ben je zeker dat je deze gebruiker \"{{key}}\" wilt verwijderen?", "client_confirm_delete": "Ben je zeker dat je deze gebruiker \"{{key}}\" wilt verwijderen?",
"list_confirm_delete": "Ben je zeker om deze lijst te verwijderen?", "list_confirm_delete": "Ben je zeker om deze lijst te verwijderen?",
"auto_clients_title": "Runtime-clients", "auto_clients_title": "Runtime-clients",
"auto_clients_desc": "Informatie over IP-adressen van apparaten die AdGuard Home gebruiken of kunnen gebruiken. Deze informatie wordt verzameld uit verschillende bronnen, waaronder hosts-bestanden, reverse DNS, enz.", "auto_clients_desc": "Apparaten die niet op de lijst van permanente clients staan die mogelijk nog steeds AdGuard Home gebruiken",
"access_title": "Toegangs instellingen", "access_title": "Toegangs instellingen",
"access_desc": "Hier kan je toegangsregels voor de AdGuard Home DNS-server instellen", "access_desc": "Hier kan je toegangsregels voor de AdGuard Home DNS-server instellen",
"access_allowed_title": "Toegestane gebruikers", "access_allowed_title": "Toegestane gebruikers",
@@ -456,7 +456,7 @@
"access_settings_saved": "Toegangsinstellingen succesvol opgeslagen", "access_settings_saved": "Toegangsinstellingen succesvol opgeslagen",
"updates_checked": "Een nieuwe versie van AdGuard Home is beschikbaar\n", "updates_checked": "Een nieuwe versie van AdGuard Home is beschikbaar\n",
"updates_version_equal": "AdGuard Home is actueel", "updates_version_equal": "AdGuard Home is actueel",
"check_updates_now": "Nu controleren op updates", "check_updates_now": "Controleer op updates",
"version_request_error": "Updatecontrole mislukt. Controleer je internetverbinding.", "version_request_error": "Updatecontrole mislukt. Controleer je internetverbinding.",
"dns_privacy": "DNS Privacy", "dns_privacy": "DNS Privacy",
"setup_dns_privacy_1": "<0>DNS-via-TLS:</0> Gebruik <1>{{address}}</1> string.", "setup_dns_privacy_1": "<0>DNS-via-TLS:</0> Gebruik <1>{{address}}</1> string.",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Om <1>DNS-via-HTTPS</1> of <1>DNS-via-TLS</1> te gebruiken, moet je <0>Versleuteling configureren</0> in de AdGuard Home instellingen.", "setup_dns_notice": "Om <1>DNS-via-HTTPS</1> of <1>DNS-via-TLS</1> te gebruiken, moet je <0>Versleuteling configureren</0> in de AdGuard Home instellingen.",
"rewrite_added": "DNS-herschrijving voor \"{{key}}\" met succes toegevoegd", "rewrite_added": "DNS-herschrijving voor \"{{key}}\" met succes toegevoegd",
"rewrite_deleted": "DNS-herschrijving voor \"{{key}}\" met succes verwijderd", "rewrite_deleted": "DNS-herschrijving voor \"{{key}}\" met succes verwijderd",
"rewrite_updated": "DNS-herschrijven succesvol bijgewerkt",
"rewrite_add": "DNS-herschrijving toevoegen", "rewrite_add": "DNS-herschrijving toevoegen",
"rewrite_edit": "DNS-herschrijven bewerken",
"rewrite_not_found": "Geen DNS-herschrijving gevonden", "rewrite_not_found": "Geen DNS-herschrijving gevonden",
"rewrite_confirm_delete": "Bent u zeker dat u DNS-herschrijving \"{{key}}\" wilt verwijderen?", "rewrite_confirm_delete": "Bent u zeker dat u DNS-herschrijving \"{{key}}\" wilt verwijderen?",
"rewrite_desc": "Hiermee kunt u eenvoudig aangepaste DNS-antwoorden configureren voor een specifieke domeinnaam.", "rewrite_desc": "Hiermee kunt u eenvoudig aangepaste DNS-antwoorden configureren voor een specifieke domeinnaam.",
@@ -573,7 +571,7 @@
"tags_title": "Labels", "tags_title": "Labels",
"tags_desc": "Je kunt labels selecteren die overeenkomen met de client. Labels kunnen worden opgenomen in de filterregels om ze \n nauwkeuriger toe te passen. <0>Meer informatie</0>.", "tags_desc": "Je kunt labels selecteren die overeenkomen met de client. Labels kunnen worden opgenomen in de filterregels om ze \n nauwkeuriger toe te passen. <0>Meer informatie</0>.",
"form_select_tags": "Client tags selecteren", "form_select_tags": "Client tags selecteren",
"check_title": "De filtering controleren", "check_title": "Controleer de filtering",
"check_desc": "Controleren of een hostnaam wordt gefilterd.", "check_desc": "Controleren of een hostnaam wordt gefilterd.",
"check": "Controleren", "check": "Controleren",
"form_enter_host": "Voer een hostnaam in", "form_enter_host": "Voer een hostnaam in",

View File

@@ -282,8 +282,6 @@
"blocking_mode_null_ip": "Null IP: Svar med en 0-IP-adresse (0.0.0.0 for A; :: for AAAA)", "blocking_mode_null_ip": "Null IP: Svar med en 0-IP-adresse (0.0.0.0 for A; :: for AAAA)",
"blocking_mode_custom_ip": "Tilpasset IP: Svar med en manuelt valgt IP-adresse", "blocking_mode_custom_ip": "Tilpasset IP: Svar med en manuelt valgt IP-adresse",
"theme_auto": "Auto", "theme_auto": "Auto",
"theme_light": "Lyst tema",
"theme_dark": "Mørkt tema",
"upstream_dns_client_desc": "Hvis dette feltet holdes tomt, vil AdGuard Home bruke tjenerne som er satt opp i <0>DNS-innstillingene</0>.", "upstream_dns_client_desc": "Hvis dette feltet holdes tomt, vil AdGuard Home bruke tjenerne som er satt opp i <0>DNS-innstillingene</0>.",
"tracker_source": "Sporerkilde", "tracker_source": "Sporerkilde",
"source_label": "Kilde", "source_label": "Kilde",
@@ -457,9 +455,7 @@
"setup_dns_notice": "For å benytte <1>DNS-over-HTTPS</1> eller <1>DNS-over-TLS</1>, må du <0>sette opp Kryptering</0> i AdGuard Home-innstillingene.", "setup_dns_notice": "For å benytte <1>DNS-over-HTTPS</1> eller <1>DNS-over-TLS</1>, må du <0>sette opp Kryptering</0> i AdGuard Home-innstillingene.",
"rewrite_added": "DNS-omdirigeringen for «{{key}}» ble vellykket lagt til", "rewrite_added": "DNS-omdirigeringen for «{{key}}» ble vellykket lagt til",
"rewrite_deleted": "DNS-omdirigeringen for «{{key}}» ble vellykket slettet", "rewrite_deleted": "DNS-omdirigeringen for «{{key}}» ble vellykket slettet",
"rewrite_updated": "DNS-omskriving ble oppdatert",
"rewrite_add": "Legg til DNS-omdirigering", "rewrite_add": "Legg til DNS-omdirigering",
"rewrite_edit": "Rediger DNS-omskriving",
"rewrite_not_found": "Ingen DNS-omdirigeringer ble funnet", "rewrite_not_found": "Ingen DNS-omdirigeringer ble funnet",
"rewrite_confirm_delete": "Er du sikker på at du vil slette DNS-omdirigeringen for «{{key}}»?", "rewrite_confirm_delete": "Er du sikker på at du vil slette DNS-omdirigeringen for «{{key}}»?",
"rewrite_desc": "Lar deg enkelt konfigurere selvvalgte DNS-tilbakemeldinger for et spesifikt domenenavn.", "rewrite_desc": "Lar deg enkelt konfigurere selvvalgte DNS-tilbakemeldinger for et spesifikt domenenavn.",

View File

@@ -222,7 +222,7 @@
"all_lists_up_to_date_toast": "Wszystkie listy są już aktualne", "all_lists_up_to_date_toast": "Wszystkie listy są już aktualne",
"updated_upstream_dns_toast": "Serwery nadrzędne zostały pomyślnie zapisane", "updated_upstream_dns_toast": "Serwery nadrzędne zostały pomyślnie zapisane",
"dns_test_ok_toast": "Określone serwery DNS działają poprawnie", "dns_test_ok_toast": "Określone serwery DNS działają poprawnie",
"dns_test_not_ok_toast": "Serwer \"{{key}}\": nie może być użyte, sprawdź, czy zapisano go poprawnie", "dns_test_not_ok_toast": "Serwer \"{{key}}\": nie można go użyć, sprawdź, czy napisałeś go poprawnie",
"dns_test_warning_toast": "Upstream \"{{key}}\" nie odpowiada na zapytania testowe i może nie działać prawidłowo", "dns_test_warning_toast": "Upstream \"{{key}}\" nie odpowiada na zapytania testowe i może nie działać prawidłowo",
"unblock": "Odblokuj", "unblock": "Odblokuj",
"block": "Zablokuj", "block": "Zablokuj",
@@ -346,7 +346,7 @@
"install_devices_windows_list_2": "Przejdź do kategorii Sieć i Internet, a następnie do Centrum sieci i udostępniania.", "install_devices_windows_list_2": "Przejdź do kategorii Sieć i Internet, a następnie do Centrum sieci i udostępniania.",
"install_devices_windows_list_3": "W lewym panelu kliknij \"Zmień ustawienia adaptera\".", "install_devices_windows_list_3": "W lewym panelu kliknij \"Zmień ustawienia adaptera\".",
"install_devices_windows_list_4": "Kliknij prawym przyciskiem myszy aktywne połączenie i wybierz Właściwości.", "install_devices_windows_list_4": "Kliknij prawym przyciskiem myszy aktywne połączenie i wybierz Właściwości.",
"install_devices_windows_list_5": "Znajdź na liście \"Protokół internetowy w wersji 4 (TCP/IPv4)\" (lub w przypadku IPv6 \"Protokół internetowy w wersji 6 (TCP/IPv6)\"), zaznacz go i ponownie kliknij Właściwości.", "install_devices_windows_list_5": "Znajdź na liście \"Protokół internetowy w wersji 4 (TCP/IPv4)\" (lub w przypadku IPv6 \"Protokół internetowy w wersji 6 (TCP/IPv6)\"), zaznacz go i ponownie kliknij na Właściwości.",
"install_devices_windows_list_6": "Wybierz opcję \"Użyj następujących adresów serwerów DNS\" i wprowadź adresy serwerów AdGuard Home.", "install_devices_windows_list_6": "Wybierz opcję \"Użyj następujących adresów serwerów DNS\" i wprowadź adresy serwerów AdGuard Home.",
"install_devices_macos_list_1": "Kliknij ikonę Apple i przejdź do Preferencje systemowe.", "install_devices_macos_list_1": "Kliknij ikonę Apple i przejdź do Preferencje systemowe.",
"install_devices_macos_list_2": "Kliknij Sieć.", "install_devices_macos_list_2": "Kliknij Sieć.",
@@ -396,7 +396,7 @@
"encryption_issuer": "Zgłaszający", "encryption_issuer": "Zgłaszający",
"encryption_hostnames": "Nazwy hostów", "encryption_hostnames": "Nazwy hostów",
"encryption_reset": "Czy na pewno chcesz zresetować ustawienia szyfrowania?", "encryption_reset": "Czy na pewno chcesz zresetować ustawienia szyfrowania?",
"encryption_warning": "Uwaga", "encryption_warning": "Uwaga!",
"topline_expiring_certificate": "Twój certyfikat SSL wkrótce wygaśnie. Zaktualizuj <0>Ustawienia szyfrowania</0>.", "topline_expiring_certificate": "Twój certyfikat SSL wkrótce wygaśnie. Zaktualizuj <0>Ustawienia szyfrowania</0>.",
"topline_expired_certificate": "Twój certyfikat SSL wygasł. Zaktualizuj <0>Ustawienia szyfrowania</0>.", "topline_expired_certificate": "Twój certyfikat SSL wygasł. Zaktualizuj <0>Ustawienia szyfrowania</0>.",
"form_error_port_range": "Wpisz numer portu z zakresu 80-65535", "form_error_port_range": "Wpisz numer portu z zakresu 80-65535",
@@ -444,7 +444,7 @@
"client_confirm_delete": "Czy na pewno chcesz usunąć klienta \"{{key}}\"?", "client_confirm_delete": "Czy na pewno chcesz usunąć klienta \"{{key}}\"?",
"list_confirm_delete": "Czy na pewno chcesz usunąć tę listę?", "list_confirm_delete": "Czy na pewno chcesz usunąć tę listę?",
"auto_clients_title": "Uruchomieni klienci", "auto_clients_title": "Uruchomieni klienci",
"auto_clients_desc": "Informacje o adresach IP urządzeń korzystających lub mogących korzystać z AdGuard Home. Te informacje są gromadzone z wielu źródeł takich jak pliki hosta, odwrotna translacja DNS, itp.", "auto_clients_desc": "Urządzenia, których nie ma na liście stałych klientów, które mogą nadal korzystać z AdGuard Home",
"access_title": "Ustawienia dostępu", "access_title": "Ustawienia dostępu",
"access_desc": "Tutaj możesz skonfigurować reguły dostępu dla serwera DNS AdGuard Home", "access_desc": "Tutaj możesz skonfigurować reguły dostępu dla serwera DNS AdGuard Home",
"access_allowed_title": "Dozwoleni klienci", "access_allowed_title": "Dozwoleni klienci",
@@ -470,7 +470,7 @@
"setup_dns_privacy_ios_2": "Aplikacja <0>AdGuard dla iOS</0> obsługuje <1>DNS-over-HTTPS</1> i <1>DNS-over-TLS</1>.", "setup_dns_privacy_ios_2": "Aplikacja <0>AdGuard dla iOS</0> obsługuje <1>DNS-over-HTTPS</1> i <1>DNS-over-TLS</1>.",
"setup_dns_privacy_other_title": "Inne implementacje", "setup_dns_privacy_other_title": "Inne implementacje",
"setup_dns_privacy_other_1": "Sam AdGuard Home może być bezpiecznym klientem DNS na dowolnej platformie.", "setup_dns_privacy_other_1": "Sam AdGuard Home może być bezpiecznym klientem DNS na dowolnej platformie.",
"setup_dns_privacy_other_2": "<0>dnsproxy</0> obsługuje wszystkie znane bezpieczne protokoły DNS.", "setup_dns_privacy_other_2": "<0>dnsproxy</0> obsługuje wszystkie znane bezpieczne protokoły DNS.\n\n",
"setup_dns_privacy_other_3": "<0>dnscrypt-proxy</0> obsługuje <1>DNS-over-HTTPS</1>.", "setup_dns_privacy_other_3": "<0>dnscrypt-proxy</0> obsługuje <1>DNS-over-HTTPS</1>.",
"setup_dns_privacy_other_4": "<0>Mozilla Firefox</0> obsługuje <1>DNS-over-HTTPS</1>.", "setup_dns_privacy_other_4": "<0>Mozilla Firefox</0> obsługuje <1>DNS-over-HTTPS</1>.",
"setup_dns_privacy_other_5": "Znajdziesz więcej implementacji <0>tutaj</0> i <1>tutaj</1>.", "setup_dns_privacy_other_5": "Znajdziesz więcej implementacji <0>tutaj</0> i <1>tutaj</1>.",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Aby skorzystać z <1>DNS-over-HTTPS</1> lub <1>DNS-over-TLS</1>, musisz w ustawieniach AdGuard Home <0>skonfigurować szyfrowanie</0>.", "setup_dns_notice": "Aby skorzystać z <1>DNS-over-HTTPS</1> lub <1>DNS-over-TLS</1>, musisz w ustawieniach AdGuard Home <0>skonfigurować szyfrowanie</0>.",
"rewrite_added": "Pomyślnie dodano przepisanie DNS dla „{{key}}”", "rewrite_added": "Pomyślnie dodano przepisanie DNS dla „{{key}}”",
"rewrite_deleted": "Przepisanie DNS dla „{{key}}” zostało pomyślnie usunięte", "rewrite_deleted": "Przepisanie DNS dla „{{key}}” zostało pomyślnie usunięte",
"rewrite_updated": "Pomyślnie zaktualizowano przepisywanie DNS",
"rewrite_add": "Dodaj przepisywanie DNS", "rewrite_add": "Dodaj przepisywanie DNS",
"rewrite_edit": "Edytuj przepisywanie DNS",
"rewrite_not_found": "Nie znaleziono przepisywania DNS", "rewrite_not_found": "Nie znaleziono przepisywania DNS",
"rewrite_confirm_delete": "Czy na pewno chcesz usunąć przepisywanie DNS dla „{{key}}”?", "rewrite_confirm_delete": "Czy na pewno chcesz usunąć przepisywanie DNS dla „{{key}}”?",
"rewrite_desc": "Pozwala łatwo skonfigurować niestandardową odpowiedź DNS dla określonej nazwy domeny.", "rewrite_desc": "Pozwala łatwo skonfigurować niestandardową odpowiedź DNS dla określonej nazwy domeny.",
@@ -544,7 +542,7 @@
"password_placeholder": "Wpisz hasło", "password_placeholder": "Wpisz hasło",
"sign_in": "Zaloguj się", "sign_in": "Zaloguj się",
"sign_out": "Wyloguj się", "sign_out": "Wyloguj się",
"forgot_password": "Zapomniano hasła?", "forgot_password": "Zapomniałeś hasła?",
"forgot_password_desc": "Wykonaj <0>te kroki</0>, aby utworzyć nowe hasło do konta użytkownika.", "forgot_password_desc": "Wykonaj <0>te kroki</0>, aby utworzyć nowe hasło do konta użytkownika.",
"location": "Lokalizacja", "location": "Lokalizacja",
"orgname": "Nazwa firmy", "orgname": "Nazwa firmy",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "Você tem certeza de que deseja excluir o cliente \"{{key}}\"?", "client_confirm_delete": "Você tem certeza de que deseja excluir o cliente \"{{key}}\"?",
"list_confirm_delete": "Você tem certeza de que deseja excluir essa lista?", "list_confirm_delete": "Você tem certeza de que deseja excluir essa lista?",
"auto_clients_title": "Clientes ativos", "auto_clients_title": "Clientes ativos",
"auto_clients_desc": "Informações sobre endereços IP de dispositivos que usam ou podem usar o AdGuard Home. Essas informações são coletadas de várias fontes, incluindo arquivos de hosts, DNS reverso, etc.", "auto_clients_desc": "Dispositivo não está na lista de dispositivos persistentes que podem ser utilizados no AdGuard Home",
"access_title": "Configurações de acessos", "access_title": "Configurações de acessos",
"access_desc": "Aqui você pode configurar as regras de acesso para o servidores de DNS do AdGuard Home", "access_desc": "Aqui você pode configurar as regras de acesso para o servidores de DNS do AdGuard Home",
"access_allowed_title": "Clientes permitidos", "access_allowed_title": "Clientes permitidos",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Para usar o <1>DNS-sobre-HTTPS</1> ou <1>DNS-sobre-TLS</1>, você precisa <0>configurar a criptografia</0> nas configurações do AdGuard Home.", "setup_dns_notice": "Para usar o <1>DNS-sobre-HTTPS</1> ou <1>DNS-sobre-TLS</1>, você precisa <0>configurar a criptografia</0> nas configurações do AdGuard Home.",
"rewrite_added": "Reescrita de DNS para \"{{key}}\" adicionada com sucesso", "rewrite_added": "Reescrita de DNS para \"{{key}}\" adicionada com sucesso",
"rewrite_deleted": "Reescrita de DNS para \"{{key}}\" excluída com sucesso", "rewrite_deleted": "Reescrita de DNS para \"{{key}}\" excluída com sucesso",
"rewrite_updated": "Reconfiguração de DNS atualizada com êxito",
"rewrite_add": "Adicionar reescrita de DNS", "rewrite_add": "Adicionar reescrita de DNS",
"rewrite_edit": "Editar reconfiguração de DNS",
"rewrite_not_found": "Nenhuma reescrita de DNS foi encontrada", "rewrite_not_found": "Nenhuma reescrita de DNS foi encontrada",
"rewrite_confirm_delete": "Você tem certeza de que deseja excluir a reescrita de DNS para \"{{key}}\"?", "rewrite_confirm_delete": "Você tem certeza de que deseja excluir a reescrita de DNS para \"{{key}}\"?",
"rewrite_desc": "Permite configurar uma resposta personalizada do DNS para um nome de domínio específico.", "rewrite_desc": "Permite configurar uma resposta personalizada do DNS para um nome de domínio específico.",
@@ -531,7 +529,7 @@
"ignore_domains": "Domínios ignorados (separados por nova linha)", "ignore_domains": "Domínios ignorados (separados por nova linha)",
"ignore_domains_title": "Domínios ignorados", "ignore_domains_title": "Domínios ignorados",
"ignore_domains_desc_stats": "As consultas para esses domínios não são gravadas nas estatísticas", "ignore_domains_desc_stats": "As consultas para esses domínios não são gravadas nas estatísticas",
"ignore_domains_desc_query": "As consultas para esses domínios não são gravadas no registro de consulta", "ignore_domains_desc_query": "As consultas para esses domínios não são gravadas no log de consulta",
"interval_hours": "{{count}} hora", "interval_hours": "{{count}} hora",
"interval_hours_plural": "{{count}} horas", "interval_hours_plural": "{{count}} horas",
"filters_configuration": "Configuração de filtros", "filters_configuration": "Configuração de filtros",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "Tem a certeza de que deseja excluir o cliente \"{{key}}\"?", "client_confirm_delete": "Tem a certeza de que deseja excluir o cliente \"{{key}}\"?",
"list_confirm_delete": "Você tem certeza de que deseja excluir essa lista?", "list_confirm_delete": "Você tem certeza de que deseja excluir essa lista?",
"auto_clients_title": "Clientes ativos", "auto_clients_title": "Clientes ativos",
"auto_clients_desc": "Informações sobre endereços IP de dispositivos que estão a utilizar ou podem utilizar o AdGuard Home. Estas informações são recolhidas a partir de várias fontes, incluindo ficheiros hosts, DNS reverso etc.", "auto_clients_desc": "Dispositivo não está na lista de dispositivos persistentes que podem ser utilizados no AdGuard Home",
"access_title": "Definições de acesso", "access_title": "Definições de acesso",
"access_desc": "Aqui pode configurar as regras de acesso para o servidores de DNS do AdGuard Home", "access_desc": "Aqui pode configurar as regras de acesso para o servidores de DNS do AdGuard Home",
"access_allowed_title": "Clientes permitidos", "access_allowed_title": "Clientes permitidos",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Para usar o <1>DNS-sobre-HTTPS</1> ou <1>DNS-sobre-TLS</1>, precisa de <0>configurar a criptografia</0> nas configurações do AdGuard Home.", "setup_dns_notice": "Para usar o <1>DNS-sobre-HTTPS</1> ou <1>DNS-sobre-TLS</1>, precisa de <0>configurar a criptografia</0> nas configurações do AdGuard Home.",
"rewrite_added": "Reescrita de DNS para \"{{key}}\" adicionada com sucesso", "rewrite_added": "Reescrita de DNS para \"{{key}}\" adicionada com sucesso",
"rewrite_deleted": "Reescrita de DNS para \"{{key}}\" excluída com sucesso", "rewrite_deleted": "Reescrita de DNS para \"{{key}}\" excluída com sucesso",
"rewrite_updated": "Reedição de DNS atualizada com sucesso",
"rewrite_add": "Adicionar reescrita de DNS", "rewrite_add": "Adicionar reescrita de DNS",
"rewrite_edit": "Editar reedição de DNS",
"rewrite_not_found": "Nenhuma reescrita de DNS foi encontrada", "rewrite_not_found": "Nenhuma reescrita de DNS foi encontrada",
"rewrite_confirm_delete": "Tem a certeza de que deseja excluir a reescrita de DNS para \"{{key}}\"?", "rewrite_confirm_delete": "Tem a certeza de que deseja excluir a reescrita de DNS para \"{{key}}\"?",
"rewrite_desc": "Permite configurar uma resposta personalizada do DNS para um nome de domínio específico.", "rewrite_desc": "Permite configurar uma resposta personalizada do DNS para um nome de domínio específico.",
@@ -531,7 +529,7 @@
"ignore_domains": "Domínios ignorados (separados por nova linha)", "ignore_domains": "Domínios ignorados (separados por nova linha)",
"ignore_domains_title": "Domínios ignorados", "ignore_domains_title": "Domínios ignorados",
"ignore_domains_desc_stats": "As consultas para estes domínios não aparecem nas estatísticas", "ignore_domains_desc_stats": "As consultas para estes domínios não aparecem nas estatísticas",
"ignore_domains_desc_query": "As consultas para estes domínios não aparecem no registo de consultas", "ignore_domains_desc_query": "As consultas para estes domínios nãoaparecem no registo de consultas",
"interval_hours": "{{count}} hora", "interval_hours": "{{count}} hora",
"interval_hours_plural": "{{count}} horas", "interval_hours_plural": "{{count}} horas",
"filters_configuration": "Definição dos filtros", "filters_configuration": "Definição dos filtros",

View File

@@ -167,7 +167,6 @@
"enabled_parental_toast": "Control Parental activat", "enabled_parental_toast": "Control Parental activat",
"disabled_safe_search_toast": "Căutare protejată dezactivată", "disabled_safe_search_toast": "Căutare protejată dezactivată",
"enabled_save_search_toast": "Căutare protejată activată", "enabled_save_search_toast": "Căutare protejată activată",
"updated_save_search_toast": "Setări Căutare sigură actualizate",
"enabled_table_header": "Activat", "enabled_table_header": "Activat",
"name_table_header": "Nume", "name_table_header": "Nume",
"list_url_table_header": "Lista URL", "list_url_table_header": "Lista URL",
@@ -257,12 +256,12 @@
"query_log_cleared": "Jurnalul de interogare a fost șters cu succes", "query_log_cleared": "Jurnalul de interogare a fost șters cu succes",
"query_log_updated": "Jurnalul de solicitări a fost actualizat cu succes", "query_log_updated": "Jurnalul de solicitări a fost actualizat cu succes",
"query_log_clear": "Curăță jurnalele", "query_log_clear": "Curăță jurnalele",
"query_log_retention": "Interogarea jurnalelor de rotație", "query_log_retention": "Retenție jurnale interogare",
"query_log_enable": "Activați jurnal", "query_log_enable": "Activați jurnal",
"query_log_configuration": "Configurația jurnalelor", "query_log_configuration": "Configurația jurnalelor",
"query_log_disabled": "Jurnalul de interogare este dezactivat și poate fi configurat în <0>setări</0>", "query_log_disabled": "Jurnalul de interogare este dezactivat și poate fi configurat în <0>setări</0>",
"query_log_strict_search": "Utilizați ghilimele duble pentru căutare strictă", "query_log_strict_search": "Utilizați ghilimele duble pentru căutare strictă",
"query_log_retention_confirm": "Sigur doriți să modificați rotația jurnalului de interogări? Dacă micșorați valoarea intervalului, unele date se vor pierde", "query_log_retention_confirm": "Sunteți sigur doriți să schimbați retenția jurnalului de interogare? Reducând valoarea intervalului, unele date vor fi pierdute",
"anonymize_client_ip": "Anonimizare client IP", "anonymize_client_ip": "Anonimizare client IP",
"anonymize_client_ip_desc": "Nu salvați adresa IP completă a clientului în jurnale și statistici", "anonymize_client_ip_desc": "Nu salvați adresa IP completă a clientului în jurnale și statistici",
"dns_config": "Configurația serverului DNS", "dns_config": "Configurația serverului DNS",
@@ -291,8 +290,6 @@
"rate_limit": "Limita ratei", "rate_limit": "Limita ratei",
"edns_enable": "Activați subrețeaua de clienți EDNS", "edns_enable": "Activați subrețeaua de clienți EDNS",
"edns_cs_desc": "Adaugă opțiunea EDNS Client Subnet (ECS) la solicitările în amonte și înregistrează valorile trimise de clienți în jurnalul de interogare.", "edns_cs_desc": "Adaugă opțiunea EDNS Client Subnet (ECS) la solicitările în amonte și înregistrează valorile trimise de clienți în jurnalul de interogare.",
"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_desc": "Numărul de interogări pe secundă permise pe client. Setarea la 0 înseamnă că nu există limită.",
"blocking_ipv4_desc": "Adresa IP de returnat pentru o cerere A de blocare", "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_ipv6_desc": "Adresa IP de returnat pentru o cerere AAAA de blocare",
@@ -444,7 +441,7 @@
"client_confirm_delete": "Sunteți sigur că doriți să ștergeți clientul \"{{key}}\"?", "client_confirm_delete": "Sunteți sigur că doriți să ștergeți clientul \"{{key}}\"?",
"list_confirm_delete": "Sigur doriți să ștergeți această listă?", "list_confirm_delete": "Sigur doriți să ștergeți această listă?",
"auto_clients_title": "Clienți runtime", "auto_clients_title": "Clienți runtime",
"auto_clients_desc": "Informații despre adresele IP ale dispozitivelor care utilizează sau pot utiliza AdGuard Home. Aceste informații sunt colectate din mai multe surse, inclusiv din fișiere hosts, DNS inversat etc.", "auto_clients_desc": "Dispozitivele care nu se află pe lista de clienți Persistent care pot utiliza în continuare AdGuard Home",
"access_title": "Setări de acces", "access_title": "Setări de acces",
"access_desc": "Aici puteți configura regulile de acces pentru serverul DNS AdGuard Home", "access_desc": "Aici puteți configura regulile de acces pentru serverul DNS AdGuard Home",
"access_allowed_title": "Clienți autorizați", "access_allowed_title": "Clienți autorizați",
@@ -478,9 +475,7 @@
"setup_dns_notice": "Pentru a utiliza <1>DNS-over-HTTPS</1> sau <1>DNS-over-TLS</1>, trebuie să <0>configurați Criptarea</0> în setările AdGuard Home.", "setup_dns_notice": "Pentru a utiliza <1>DNS-over-HTTPS</1> sau <1>DNS-over-TLS</1>, trebuie să <0>configurați Criptarea</0> în setările AdGuard Home.",
"rewrite_added": "Rescriere DNS pentru \"{{key}}\" adăugată cu succes", "rewrite_added": "Rescriere DNS pentru \"{{key}}\" adăugată cu succes",
"rewrite_deleted": "Rescriere DNS pentru \"{{key}}\" ștearsă cu succes", "rewrite_deleted": "Rescriere DNS pentru \"{{key}}\" ștearsă cu succes",
"rewrite_updated": "DNS rescrie actualizat cu succes",
"rewrite_add": "Adăugați rescriere DNS", "rewrite_add": "Adăugați rescriere DNS",
"rewrite_edit": "Editați rescrierea DNS",
"rewrite_not_found": "Nu s-au găsit rescrieri DNS", "rewrite_not_found": "Nu s-au găsit rescrieri DNS",
"rewrite_confirm_delete": "Sunteți sigur că doriți să ștergeți rescrierea DNS pentru \"{{key}}\"?", "rewrite_confirm_delete": "Sunteți sigur că doriți să ștergeți rescrierea DNS pentru \"{{key}}\"?",
"rewrite_desc": "Permite configurarea cu ușurință a răspunsului personalizat DNS pentru un nume de domeniu specific.", "rewrite_desc": "Permite configurarea cu ușurință a răspunsului personalizat DNS pentru un nume de domeniu specific.",
@@ -528,10 +523,6 @@
"statistics_retention_confirm": "Sunteți sigur că doriți să schimbați păstrarea statisticilor? Dacă reduceți valoarea intervalului, unele date vor fi pierdute", "statistics_retention_confirm": "Sunteți sigur că doriți să schimbați păstrarea statisticilor? Dacă reduceți valoarea intervalului, unele date vor fi pierdute",
"statistics_cleared": "Statisticile au fost șterse cu succes", "statistics_cleared": "Statisticile au fost șterse cu succes",
"statistics_enable": "Activați statisticile", "statistics_enable": "Activați statisticile",
"ignore_domains": "Domenii ignorate (separate prin linie nouă)",
"ignore_domains_title": "Domenii ignorate",
"ignore_domains_desc_stats": "Interogările pentru aceste domenii nu sunt scrise în statistici",
"ignore_domains_desc_query": "Interogările pentru aceste domenii nu sunt scrise în jurnalul de interogări",
"interval_hours": "{{count}} oră", "interval_hours": "{{count}} oră",
"interval_hours_plural": "{{count}} ore", "interval_hours_plural": "{{count}} ore",
"filters_configuration": "Configurația filtrelor", "filters_configuration": "Configurația filtrelor",
@@ -652,29 +643,5 @@
"confirm_dns_cache_clear": "Sunteți sigur că doriți să ștergeți memoria cache DNS?", "confirm_dns_cache_clear": "Sunteți sigur că doriți să ștergeți memoria cache DNS?",
"cache_cleared": "Cache-ul DNS a fost golit cu succes", "cache_cleared": "Cache-ul DNS a fost golit cu succes",
"clear_cache": "Goliți memoria cache", "clear_cache": "Goliți memoria cache",
"make_static": "Faceți static", "protection_section_label": "Protecție"
"theme_auto_desc": "Auto (pe baza schemei de culori a dispozitivului dvs.)",
"theme_dark_desc": "Temă întunecată",
"theme_light_desc": "Temă luminoasă",
"disable_for_seconds": "Timp de {{count}} secundă",
"disable_for_seconds_plural": "Timp de {{count}} secunde",
"disable_for_minutes": "Timp de {{count}} minut",
"disable_for_minutes_plural": "Timp de {{count}} minute",
"disable_for_hours": "Timp de {{count}} oră",
"disable_for_hours_plural": "Timp de {{count}} ore",
"disable_until_tomorrow": "Până mâine",
"disable_notify_for_seconds": "Dezactivați protecția timp de {{count}} secundă",
"disable_notify_for_seconds_plural": "Dezactivați protecția timp de {{count}} secunde",
"disable_notify_for_minutes": "Dezactivați protecția timp de {{count}} minut",
"disable_notify_for_minutes_plural": "Dezactivați protecția timp de {{count}} minute",
"disable_notify_for_hours": "Dezactivează protecția timp de {{count}} oră",
"disable_notify_for_hours_plural": "Dezactivați protecția timp de {{count}} ore",
"disable_notify_until_tomorrow": "Dezactivează protecția până mâine",
"enable_protection_timer": "Protecția va fi activată în {{time}}",
"custom_retention_input": "Introduceți reținerea în ore",
"custom_rotation_input": "Introduceți rotația în ore",
"protection_section_label": "Protecție",
"log_and_stats_section_label": "Jurnal de interogări și statistici",
"ignore_query_log": "Ignorați acest client în jurnalul de interogări",
"ignore_statistics": "Ignorați acest client în statistici"
} }

View File

@@ -135,7 +135,7 @@
"number_of_dns_query_to_safe_search": "Количество запросов DNS для поисковых систем, для которых был применён Безопасный поиск", "number_of_dns_query_to_safe_search": "Количество запросов DNS для поисковых систем, для которых был применён Безопасный поиск",
"average_processing_time": "Среднее время обработки запроса", "average_processing_time": "Среднее время обработки запроса",
"average_processing_time_hint": "Среднее время для обработки запроса DNS в миллисекундах", "average_processing_time_hint": "Среднее время для обработки запроса DNS в миллисекундах",
"block_domain_use_filters_and_hosts": "Блокировать домены с использованием фильтров и файлов hosts", "block_domain_use_filters_and_hosts": "Блокировать домены с использованием фильтров и файлов хостов",
"filters_block_toggle_hint": "Вы можете настроить правила блокировки в <a>«Фильтрах»</a>.", "filters_block_toggle_hint": "Вы можете настроить правила блокировки в <a>«Фильтрах»</a>.",
"use_adguard_browsing_sec": "Включить Безопасную навигацию AdGuard", "use_adguard_browsing_sec": "Включить Безопасную навигацию AdGuard",
"use_adguard_browsing_sec_hint": "AdGuard Home проверит, включён ли домен в веб-службу безопасности браузера. Он будет использовать API, чтобы выполнить проверку: на сервер отправляется только короткий префикс имени домена SHA256.", "use_adguard_browsing_sec_hint": "AdGuard Home проверит, включён ли домен в веб-службу безопасности браузера. Он будет использовать API, чтобы выполнить проверку: на сервер отправляется только короткий префикс имени домена SHA256.",
@@ -296,7 +296,7 @@
"rate_limit_desc": "Ограничение на количество запросов в секунду для каждого клиента (0 — неограниченно).", "rate_limit_desc": "Ограничение на количество запросов в секунду для каждого клиента (0 — неограниченно).",
"blocking_ipv4_desc": "IP-адрес, возвращаемый при блокировке A-запроса", "blocking_ipv4_desc": "IP-адрес, возвращаемый при блокировке A-запроса",
"blocking_ipv6_desc": "IP-адрес, возвращаемый при блокировке AAAA-запроса", "blocking_ipv6_desc": "IP-адрес, возвращаемый при блокировке AAAA-запроса",
"blocking_mode_default": "Стандартный: Отвечает с нулевым IP-адресом, (0.0.0.0 для A; :: для AAAA) когда заблокировано правилом в стиле Adblock; отвечает с IP-адресом, указанным в правиле, когда заблокировано правилом в стиле файлов hosts", "blocking_mode_default": "Стандартный: Отвечает с нулевым IP-адресом, (0.0.0.0 для A; :: для AAAA) когда заблокировано правилом в стиле Adblock; отвечает с IP-адресом, указанным в правиле, когда заблокировано правилом в стиле /etc/hosts-style",
"blocking_mode_refused": "REFUSED: Отвечает с кодом REFUSED", "blocking_mode_refused": "REFUSED: Отвечает с кодом REFUSED",
"blocking_mode_nxdomain": "NXDOMAIN: Отвечает с кодом NXDOMAIN\n", "blocking_mode_nxdomain": "NXDOMAIN: Отвечает с кодом NXDOMAIN\n",
"blocking_mode_null_ip": "Нулевой IP: Отвечает с нулевым IP-адресом (0.0.0.0 для A; :: для AAAA)", "blocking_mode_null_ip": "Нулевой IP: Отвечает с нулевым IP-адресом (0.0.0.0 для A; :: для AAAA)",
@@ -444,7 +444,7 @@
"client_confirm_delete": "Вы уверены, что хотите удалить клиента «{{key}}»?", "client_confirm_delete": "Вы уверены, что хотите удалить клиента «{{key}}»?",
"list_confirm_delete": "Вы уверены, что хотите удалить этот список?", "list_confirm_delete": "Вы уверены, что хотите удалить этот список?",
"auto_clients_title": "Клиенты (runtime)", "auto_clients_title": "Клиенты (runtime)",
"auto_clients_desc": "Информация об IP-адресах устройств, которые используют или могут использовать AdGuard Home. Эта информация собирается из нескольких источников, включая файлы hosts, обратный DNS и так далее.", "auto_clients_desc": "Несохранённые клиенты, которые могут пользоваться AdGuard Home",
"access_title": "Настройки доступа", "access_title": "Настройки доступа",
"access_desc": "Здесь вы можете настроить правила доступа к DNS-серверу AdGuard Home", "access_desc": "Здесь вы можете настроить правила доступа к DNS-серверу AdGuard Home",
"access_allowed_title": "Разрешённые клиенты", "access_allowed_title": "Разрешённые клиенты",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Чтобы использовать <1>DNS-over-HTTPS</1> или <1>DNS-over-TLS</1>, вам нужно <0>настроить шифрование</0> в настройках AdGuard Home.", "setup_dns_notice": "Чтобы использовать <1>DNS-over-HTTPS</1> или <1>DNS-over-TLS</1>, вам нужно <0>настроить шифрование</0> в настройках AdGuard Home.",
"rewrite_added": "Правило перезаписи DNS-запросов для «{{key}}» успешно добавлено", "rewrite_added": "Правило перезаписи DNS-запросов для «{{key}}» успешно добавлено",
"rewrite_deleted": "Правило перезаписи DNS-запросов для «{{key}}» успешно удалено", "rewrite_deleted": "Правило перезаписи DNS-запросов для «{{key}}» успешно удалено",
"rewrite_updated": "Правило перезаписи DNS-запросов успешно обновлено",
"rewrite_add": "Добавить правило перезаписи DNS-запросов", "rewrite_add": "Добавить правило перезаписи DNS-запросов",
"rewrite_edit": "Редактировать правило перезаписи DNS-запросов",
"rewrite_not_found": "Не найдено правил перезаписи DNS-запросов", "rewrite_not_found": "Не найдено правил перезаписи DNS-запросов",
"rewrite_confirm_delete": "Вы уверены, что хотите удалить правило перезаписи DNS-запросов для «{{key}}»?", "rewrite_confirm_delete": "Вы уверены, что хотите удалить правило перезаписи DNS-запросов для «{{key}}»?",
"rewrite_desc": "Позволяет легко настроить пользовательский DNS-ответ для определеннного домена.", "rewrite_desc": "Позволяет легко настроить пользовательский DNS-ответ для определеннного домена.",

View File

@@ -153,7 +153,6 @@
"enabled_parental_toast": "දෙමාපිය පාලනය සබල කෙරිණි", "enabled_parental_toast": "දෙමාපිය පාලනය සබල කෙරිණි",
"disabled_safe_search_toast": "ආරක්‍ෂිත සෙවුම අබල කෙරිණි", "disabled_safe_search_toast": "ආරක්‍ෂිත සෙවුම අබල කෙරිණි",
"enabled_save_search_toast": "ආරක්‍ෂිත සෙවුම සබල කෙරිණි", "enabled_save_search_toast": "ආරක්‍ෂිත සෙවුම සබල කෙරිණි",
"updated_save_search_toast": "ආරක්‍ෂිත සෙවුමේ සැකසුම් යාවත්කාල විය",
"enabled_table_header": "සබලයි", "enabled_table_header": "සබලයි",
"name_table_header": "නම", "name_table_header": "නම",
"list_url_table_header": "ඒ.ස.නි.(URL) ලැයිස්තුව", "list_url_table_header": "ඒ.ස.නි.(URL) ලැයිස්තුව",
@@ -238,12 +237,12 @@
"query_log_cleared": "විමසුම් සටහන සාර්ථකව හිස් කර ඇත", "query_log_cleared": "විමසුම් සටහන සාර්ථකව හිස් කර ඇත",
"query_log_updated": "විමසුම් සටහන සාර්ථකව යාවත්කාල කෙරිණි", "query_log_updated": "විමසුම් සටහන සාර්ථකව යාවත්කාල කෙරිණි",
"query_log_clear": "විමසුම් සටහන් හිස් කරන්න", "query_log_clear": "විමසුම් සටහන් හිස් කරන්න",
"query_log_retention": "විමසුම් සටහන් රඳවීම", "query_log_retention": "විමසුම් සටහන් රඳවා තබා ගැනීම",
"query_log_enable": "සටහන සබල කරන්න", "query_log_enable": "සටහන සබල කරන්න",
"query_log_configuration": "සටහන් වින්‍යාසය", "query_log_configuration": "සටහන් වින්‍යාසය",
"query_log_disabled": "විමසුම් සටහන අබල කර ඇති අතර එය <0>සැකසුම්</0> තුළ වින්‍යාසගත කළ හැකිය", "query_log_disabled": "විමසුම් සටහන අබල කර ඇති අතර එය <0>සැකසුම්</0> තුළ වින්‍යාසගත කළ හැකිය",
"query_log_strict_search": "ඉතා නිවැරදිව සෙවීමට ද්විත්ව උද්ධෘතය භාවිතා කරන්න", "query_log_strict_search": "ඉතා නිවැරදිව සෙවීමට ද්විත්ව උද්ධෘතය භාවිතා කරන්න",
"query_log_retention_confirm": "විමසුම් සටහන රඳවා තබා ගැනීම වෙනස් කිරීමට වුවමනා ද? ඔබ කාල පරතරයෙහි අගය අඩු කළහොත් සමහර දත්ත නැති වී යනු ඇත", "query_log_retention_confirm": "විමසුම් සටහන රඳවා තබා ගැනීම වෙනස් කිරීමට ඇවැසි බව ඔබට විශ්වාසද? ඔබ කාල පරතරයෙහි අගය අඩු කළහොත් සමහර දත්ත නැති වී යනු ඇත",
"anonymize_client_ip": "අනුග්‍රාහකයෙහි අ.ජා.කෙ. (IP) නිර්නාමික කරන්න", "anonymize_client_ip": "අනුග්‍රාහකයෙහි අ.ජා.කෙ. (IP) නිර්නාමික කරන්න",
"anonymize_client_ip_desc": "සටහන් සහ සංඛ්‍යාලේඛන තුළ අනුග්‍රාහකයේ පූර්ණ අ.ජා.කෙ. ලිපිනය සුරකින්න එපා", "anonymize_client_ip_desc": "සටහන් සහ සංඛ්‍යාලේඛන තුළ අනුග්‍රාහකයේ පූර්ණ අ.ජා.කෙ. ලිපිනය සුරකින්න එපා",
"dns_config": "ව.නා.ප. සේවාදායක වින්‍යාසය", "dns_config": "ව.නා.ප. සේවාදායක වින්‍යාසය",
@@ -271,8 +270,6 @@
"form_enter_rate_limit": "අනුපාත සීමාව ඇතුල් කරන්න", "form_enter_rate_limit": "අනුපාත සීමාව ඇතුල් කරන්න",
"rate_limit": "අනුපාත සීමාව", "rate_limit": "අනුපාත සීමාව",
"edns_enable": "EDNS අනුග්‍රාහක අනුජාලය සබල කරන්න", "edns_enable": "EDNS අනුග්‍රාහක අනුජාලය සබල කරන්න",
"edns_use_custom_ip": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. යොදාගන්න",
"edns_use_custom_ip_desc": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. භාවිතයට ඉඩදෙන්න",
"rate_limit_desc": "එක් අනුග්‍රාහකයකට ඉඩ දී ඇති තත්පරයට ඉල්ලීම් ගණන. එය 0 ලෙස සැකසීම යනුවෙන් අදහස් කරන්නේ සීමාවක් නැති බවයි.", "rate_limit_desc": "එක් අනුග්‍රාහකයකට ඉඩ දී ඇති තත්පරයට ඉල්ලීම් ගණන. එය 0 ලෙස සැකසීම යනුවෙන් අදහස් කරන්නේ සීමාවක් නැති බවයි.",
"blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය", "blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
"blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය", "blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
@@ -281,9 +278,6 @@
"blocking_mode_nxdomain": "නොපවතින වසම: NXDOMAIN කේතය සමඟ ප්‍රතිචාර දක්වයි", "blocking_mode_nxdomain": "නොපවතින වසම: NXDOMAIN කේතය සමඟ ප්‍රතිචාර දක්වයි",
"blocking_mode_null_ip": "අභිශූන්‍යය අ.ජා.කෙ.: ශුන්‍ය අ.ජා.කෙ. ලිපිනය සමඟ ප්‍රතිචාර දක්වයි (A සඳහා 0.0.0.0; AAAA සඳහා ::)", "blocking_mode_null_ip": "අභිශූන්‍යය අ.ජා.කෙ.: ශුන්‍ය අ.ජා.කෙ. ලිපිනය සමඟ ප්‍රතිචාර දක්වයි (A සඳහා 0.0.0.0; AAAA සඳහා ::)",
"blocking_mode_custom_ip": "අභිරුචි අන්තර්ජාල කෙටුම්පත: අතින් සැකසූ අ.ජා. කෙ. ලිපිනයක් සමඟ ප්‍රතිචාර දක්වයි", "blocking_mode_custom_ip": "අභිරුචි අන්තර්ජාල කෙටුම්පත: අතින් සැකසූ අ.ජා. කෙ. ලිපිනයක් සමඟ ප්‍රතිචාර දක්වයි",
"theme_auto": "ස්වයං",
"theme_light": "දීප්ත",
"theme_dark": "අඳුරු",
"upstream_dns_client_desc": "ඔබ මෙම ක්ෂේත්‍රය හිස්ව තබා ගන්නේ නම්, ඇඩ්ගාර්ඩ් හෝම් විසින් <0>ව.නා.ප. සැකසුම්</0> හි වින්‍යාසගත කර ඇති සේවාදායක භාවිතා කරනු ඇත.", "upstream_dns_client_desc": "ඔබ මෙම ක්ෂේත්‍රය හිස්ව තබා ගන්නේ නම්, ඇඩ්ගාර්ඩ් හෝම් විසින් <0>ව.නා.ප. සැකසුම්</0> හි වින්‍යාසගත කර ඇති සේවාදායක භාවිතා කරනු ඇත.",
"tracker_source": "ලුහුබැඳීම් මූලාශ්‍රය", "tracker_source": "ලුහුබැඳීම් මූලාශ්‍රය",
"source_label": "මූලාශ්‍රය", "source_label": "මූලාශ්‍රය",
@@ -376,7 +370,6 @@
"encryption_issuer": "නිකුත් කරන්නා", "encryption_issuer": "නිකුත් කරන්නා",
"encryption_hostnames": "ධාරක නාම", "encryption_hostnames": "ධාරක නාම",
"encryption_reset": "සංකේතාංකන සැකසුම් යළි පිහිටුවීමට අවශ්‍ය බව ඔබට විශ්වාස ද?", "encryption_reset": "සංකේතාංකන සැකසුම් යළි පිහිටුවීමට අවශ්‍ය බව ඔබට විශ්වාස ද?",
"encryption_warning": "අවවාදයයි",
"topline_expiring_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත්වීමට ආසන්න වී ඇත. <0>සංකේතන සැකසුම්</0> යාවත්කාල කරන්න.", "topline_expiring_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත්වීමට ආසන්න වී ඇත. <0>සංකේතන සැකසුම්</0> යාවත්කාල කරන්න.",
"topline_expired_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත් වී ඇත. <0>සංකේතන සැකසුම්</0> යාවත්කාල කරන්න.", "topline_expired_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත් වී ඇත. <0>සංකේතන සැකසුම්</0> යාවත්කාල කරන්න.",
"form_error_port_range": "80-65535 පරාසය හි තොටක අගයක් ඇතුල් කරන්න", "form_error_port_range": "80-65535 පරාසය හි තොටක අගයක් ඇතුල් කරන්න",
@@ -435,7 +428,6 @@
"updates_checked": "ඇඩ්ගාර්ඩ් හෝම් හි නව අනුවාදයක් තිබේ", "updates_checked": "ඇඩ්ගාර්ඩ් හෝම් හි නව අනුවාදයක් තිබේ",
"updates_version_equal": "ඇඩ්ගාර්ඩ් හෝම් යාවත්කාලීනයි", "updates_version_equal": "ඇඩ්ගාර්ඩ් හෝම් යාවත්කාලීනයි",
"check_updates_now": "දැන් යාවත්කාල පරීක්‍ෂා කරන්න", "check_updates_now": "දැන් යාවත්කාල පරීක්‍ෂා කරන්න",
"version_request_error": "යාවත්කාලීන පරීක්‍ෂාවට අසමත් විය. ඔබගේ අන්තර්ජාල සම්බන්ධතාවය පරීක්‍ෂා කරන්න.",
"dns_privacy": "ව.නා.ප. රහස්‍යතා", "dns_privacy": "ව.නා.ප. රහස්‍යතා",
"setup_dns_privacy_1": "<0>TLS-මගින්-ව.නා.ප.</0> සඳහා <1>{{address}}</1>.", "setup_dns_privacy_1": "<0>TLS-මගින්-ව.නා.ප.</0> සඳහා <1>{{address}}</1>.",
"setup_dns_privacy_2": "<0>HTTPS-මගින්-ව.නා.ප.</0> සඳහා <1>{{address}}</1>.", "setup_dns_privacy_2": "<0>HTTPS-මගින්-ව.නා.ප.</0> සඳහා <1>{{address}}</1>.",
@@ -454,9 +446,7 @@
"setup_dns_notice": "ඔබට <1>HTTPS-මගින්-ව.නා.ප.</1> හෝ <1>DNS-මගින්-ව.නා.ප.</1> භාවිතයට ඇඩ්ගාර්ඩ් හෝම් සැකසුම් තුළ <0>සංකේතනය වින්‍යාසගත</0> කළ යුතුය.", "setup_dns_notice": "ඔබට <1>HTTPS-මගින්-ව.නා.ප.</1> හෝ <1>DNS-මගින්-ව.නා.ප.</1> භාවිතයට ඇඩ්ගාර්ඩ් හෝම් සැකසුම් තුළ <0>සංකේතනය වින්‍යාසගත</0> කළ යුතුය.",
"rewrite_added": "\"{{key}}\" සඳහා ව.නා.ප. නැවත ලිවීම සාර්ථකව එකතු කෙරිණි", "rewrite_added": "\"{{key}}\" සඳහා ව.නා.ප. නැවත ලිවීම සාර්ථකව එකතු කෙරිණි",
"rewrite_deleted": "\"{{key}}\" සඳහා ව.නා.ප. නැවත ලිවීම ඉවත් කෙරිණි", "rewrite_deleted": "\"{{key}}\" සඳහා ව.නා.ප. නැවත ලිවීම ඉවත් කෙරිණි",
"rewrite_updated": "ව.නා.ප. නැවත ලිවීම සාර්ථකව යාවත්කාලීන කෙරිණි", "rewrite_add": "ව.නා.ප. නැවත ලිවීමක් එකතු කරන්න",
"rewrite_add": "ව.නා.ප. නැවත ලිවීමක් යොදන්න",
"rewrite_edit": "ව.නා.ප. නැවත ලිවීම සංස්කරණය",
"rewrite_not_found": "ව.නා.ප. නැවත ලිවීම් හමු නොවිණි", "rewrite_not_found": "ව.නා.ප. නැවත ලිවීම් හමු නොවිණි",
"rewrite_confirm_delete": "\"{{key}}\" සඳහා ව.නා.ප. නැවත ලිවීම ඉවත් කිරීමට අවශ්‍ය බව ඔබට විශ්වාසද?", "rewrite_confirm_delete": "\"{{key}}\" සඳහා ව.නා.ප. නැවත ලිවීම ඉවත් කිරීමට අවශ්‍ය බව ඔබට විශ්වාසද?",
"rewrite_desc": "නිශ්චිත වසම් නාමයක් සඳහා අභිරුචි ව.නා.ප. ප්‍රතිචාර පහසුවෙන් වින්‍යාසගත කිරීමට ඉඩ දෙයි.", "rewrite_desc": "නිශ්චිත වසම් නාමයක් සඳහා අභිරුචි ව.නා.ප. ප්‍රතිචාර පහසුවෙන් වින්‍යාසගත කිරීමට ඉඩ දෙයි.",
@@ -500,10 +490,8 @@
"statistics_clear": "සංඛ්‍යාලේඛන හිස් කරන්න", "statistics_clear": "සංඛ්‍යාලේඛන හිස් කරන්න",
"statistics_clear_confirm": "සංඛ්‍යාලේඛන ඉවත් කිරීමට වුවමනා ද?", "statistics_clear_confirm": "සංඛ්‍යාලේඛන ඉවත් කිරීමට වුවමනා ද?",
"statistics_retention_confirm": "සංඛ්‍යාලේඛන රඳවා තබා ගැනීම වෙනස් කිරීමට අවශ්‍ය බව ඔබට විශ්වාසද? ඔබ කාල පරතරයෙහි අගය අඩු කළහොත් සමහර දත්ත නැති වී යනු ඇත", "statistics_retention_confirm": "සංඛ්‍යාලේඛන රඳවා තබා ගැනීම වෙනස් කිරීමට අවශ්‍ය බව ඔබට විශ්වාසද? ඔබ කාල පරතරයෙහි අගය අඩු කළහොත් සමහර දත්ත නැති වී යනු ඇත",
"statistics_cleared": "සංඛ්‍යාලේඛන සාර්ථකව හිස් කෙරිණි", "statistics_cleared": "සංඛ්‍යාලේඛන සාර්ථකව ඉවත් කෙරිණි",
"statistics_enable": "සංඛ්‍යාලේඛන සබල කරන්න", "statistics_enable": "සංඛ්‍යාලේඛන සබල කරන්න",
"ignore_domains": "නොසලකන වසම් (පේළියකට එක බැගින්)",
"ignore_domains_title": "නොසලකන වසම්",
"interval_hours": "පැය {{count}}", "interval_hours": "පැය {{count}}",
"interval_hours_plural": "පැය {{count}}", "interval_hours_plural": "පැය {{count}}",
"filters_configuration": "පෙරහන් වින්‍යාසය", "filters_configuration": "පෙරහන් වින්‍යාසය",
@@ -613,34 +601,5 @@
"parental_control": "දෙමාපිය පාලනය", "parental_control": "දෙමාපිය පාලනය",
"safe_browsing": "ආරක්‍ෂිත පිරික්සුම", "safe_browsing": "ආරක්‍ෂිත පිරික්සුම",
"served_from_cache": "{{value}} <i>(නිහිතයෙන් ගැනිණි)</i>", "served_from_cache": "{{value}} <i>(නිහිතයෙන් ගැනිණි)</i>",
"form_error_password_length": "මුරපදය අවම වශයෙන් අකුරු {{value}} ක් දිගු විය යුතුමයි", "form_error_password_length": "මුරපදය අවම වශයෙන් අකුරු {{value}} ක් දිගු විය යුතුමයි"
"anonymizer_notification": "<0>සටහන:</0> අ.ජා.කෙ. නිර්නාමිකකරණය සබලයි. ඔබට එය <1>පොදු සැකසුම්</1> හරහා අබල කිරීමට හැකිය .",
"confirm_dns_cache_clear": "ඔබට ව.නා.ප. නිහිතය හිස් කිරීමට වුවමනාද?",
"cache_cleared": "ව.නා.ප. නිහිතය හිස් කෙරිණි",
"clear_cache": "නිහිතය මකන්න",
"make_static": "ස්ථිතික කරන්න",
"theme_auto_desc": "ස්වයං (උපාංගයේ වර්ණ පරිපාටිය මත පදනම්ව)",
"theme_dark_desc": "අඳුරු තේමාව",
"theme_light_desc": "දීප්ත තේමාව",
"disable_for_seconds": "තත්පර {{count}} ක්",
"disable_for_seconds_plural": "තත්පර {{count}} ක්",
"disable_for_minutes": "විනාඩි {{count}} ක්",
"disable_for_minutes_plural": "විනාඩි {{count}} ක්",
"disable_for_hours": "පැය {{count}} ක්",
"disable_for_hours_plural": "පැය {{count}} ක්",
"disable_until_tomorrow": "හෙට වනතුරු",
"disable_notify_for_seconds": "තත්. {{count}} කට රැකවරණය අබල කරන්න",
"disable_notify_for_seconds_plural": "තත්. {{count}} කට රැකවරණය අබල කරන්න",
"disable_notify_for_minutes": "විනාඩි {{count}} කට රැකවරණය අබල කරන්න",
"disable_notify_for_minutes_plural": "විනාඩි {{count}} කට රැකවරණය අබල කරන්න",
"disable_notify_for_hours": "පැය {{count}} කට රැකවරණය අබල කරන්න",
"disable_notify_for_hours_plural": "පැය {{count}} කට රැකවරණය අබල කරන්න",
"disable_notify_until_tomorrow": "හෙට වනතුරු රැකවරණය අබල කරන්න",
"enable_protection_timer": "{{time}} න් රැකවරණය සබල කෙරේ",
"custom_retention_input": "රඳවා ගැනීම පැය වලින්",
"custom_rotation_input": "රඳවා ගැනීම පැය වලින්",
"protection_section_label": "රැකවරණය",
"log_and_stats_section_label": "විමසුම් සටහන හා සංඛ්‍යාලේඛන",
"ignore_query_log": "සටහනෙහි අනුග්‍රාහකය නොසලකන්න",
"ignore_statistics": "සංඛ්‍යාලේඛනයට අනුග්‍රාහකය නොසලකන්න"
} }

View File

@@ -387,7 +387,7 @@
"encryption_key": "Súkromný kľúč", "encryption_key": "Súkromný kľúč",
"encryption_key_input": "Skopírujte a prilepte sem svoj súkromný kľúč vo formáte PEM pre Váš certifikát.", "encryption_key_input": "Skopírujte a prilepte sem svoj súkromný kľúč vo formáte PEM pre Váš certifikát.",
"encryption_enable": "Zapnite šifrovanie (HTTPS, DNS-cez-HTTPS a DNS-cez-TLS)", "encryption_enable": "Zapnite šifrovanie (HTTPS, DNS-cez-HTTPS a DNS-cez-TLS)",
"encryption_enable_desc": "Ak je šifrovanie zapnuté, AdGuard Home administrátorské rozhranie bude pracovať cez HTTPS a DNS server bude počúvať dopyty cez DNS-cez-HTTPS a DNS-cez-TLS.", "encryption_enable_desc": "Ak je šifrovanie zapnuté, AdGuard Home administrátorské rozhranie bude pracovať cez HTTPS a DNS server bude počúvať požiadavky cez DNS-cez-HTTPS a DNS-cez-TLS.",
"encryption_chain_valid": "Certifikačný reťazec je platný", "encryption_chain_valid": "Certifikačný reťazec je platný",
"encryption_chain_invalid": "Certifikačný reťazec je neplatný", "encryption_chain_invalid": "Certifikačný reťazec je neplatný",
"encryption_key_valid": "Toto je platný {{type}} súkromný kľúč", "encryption_key_valid": "Toto je platný {{type}} súkromný kľúč",
@@ -444,7 +444,7 @@
"client_confirm_delete": "Naozaj chcete vymazať \"{{key}}\" klienta?", "client_confirm_delete": "Naozaj chcete vymazať \"{{key}}\" klienta?",
"list_confirm_delete": "Naozaj chcete vymazať tento zoznam?", "list_confirm_delete": "Naozaj chcete vymazať tento zoznam?",
"auto_clients_title": "Runtime klienti", "auto_clients_title": "Runtime klienti",
"auto_clients_desc": "Informácie o IP adresách zariadení, ktoré používajú alebo môžu používať AdGuard Home. Tieto informácie sa získavajú z viacerých zdrojov vrátane súborov hosts, reverzného DNS atď.", "auto_clients_desc": "Zariadenia, ktoré nie sú na zozname trvalých klientov, ktorí môžu stále používať AdGuard Home",
"access_title": "Nastavenia prístupu", "access_title": "Nastavenia prístupu",
"access_desc": "Tu môžete konfigurovať pravidlá prístupu pre server DNS AdGuard Home.", "access_desc": "Tu môžete konfigurovať pravidlá prístupu pre server DNS AdGuard Home.",
"access_allowed_title": "Povolení klienti", "access_allowed_title": "Povolení klienti",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Pre použitie <1>DNS-over-HTTPS</1> alebo <1>DNS-over-TLS</1>, potrebujete v nastaveniach AdGuard Home <0>nakonfigurovať šifrovanie</0>.", "setup_dns_notice": "Pre použitie <1>DNS-over-HTTPS</1> alebo <1>DNS-over-TLS</1>, potrebujete v nastaveniach AdGuard Home <0>nakonfigurovať šifrovanie</0>.",
"rewrite_added": "DNS prepísanie pre \"{{key}}\" bolo úspešne pridané", "rewrite_added": "DNS prepísanie pre \"{{key}}\" bolo úspešne pridané",
"rewrite_deleted": "DNS prepísanie pre \"{{key}}\" bolo úspešne vymazané", "rewrite_deleted": "DNS prepísanie pre \"{{key}}\" bolo úspešne vymazané",
"rewrite_updated": "Prepísanie DNS bolo úspešne aktualizované",
"rewrite_add": "Pridať DNS prepísanie", "rewrite_add": "Pridať DNS prepísanie",
"rewrite_edit": "Upraviť prepísanie DNS",
"rewrite_not_found": "Neboli nájdené žiadne DNS prepísania", "rewrite_not_found": "Neboli nájdené žiadne DNS prepísania",
"rewrite_confirm_delete": "Naozaj chcete odstrániť prepísanie DNS pre \"{{key}}\"?", "rewrite_confirm_delete": "Naozaj chcete odstrániť prepísanie DNS pre \"{{key}}\"?",
"rewrite_desc": "Umožňuje ľahko nakonfigurovať vlastnú odpoveď DNS pre konkrétne meno domény.", "rewrite_desc": "Umožňuje ľahko nakonfigurovať vlastnú odpoveď DNS pre konkrétne meno domény.",
@@ -497,7 +495,7 @@
"blocked_services": "Blokované služby", "blocked_services": "Blokované služby",
"blocked_services_desc": "Umožňuje rýchlo blokovať populárne stránky a služby.", "blocked_services_desc": "Umožňuje rýchlo blokovať populárne stránky a služby.",
"blocked_services_saved": "Blokované služby boli úspešne uložené", "blocked_services_saved": "Blokované služby boli úspešne uložené",
"blocked_services_global": "Použiť globálne blokované služby", "blocked_services_global": "Použite globálne blokované služby",
"blocked_service": "Blokované služby", "blocked_service": "Blokované služby",
"block_all": "Blokovať všetko", "block_all": "Blokovať všetko",
"unblock_all": "Odblokovať všetko", "unblock_all": "Odblokovať všetko",
@@ -554,7 +552,7 @@
"whois": "WHOIS", "whois": "WHOIS",
"filtering_rules_learn_more": "<0>Dozvedieť sa viac</0> o tvorbe vlastných zoznamov hostiteľov.", "filtering_rules_learn_more": "<0>Dozvedieť sa viac</0> o tvorbe vlastných zoznamov hostiteľov.",
"blocked_by_response": "Blokované pomocou CNAME alebo IP v odpovedi", "blocked_by_response": "Blokované pomocou CNAME alebo IP v odpovedi",
"blocked_by_cname_or_ip": "Blokované pomocou CNAME alebo IP", "blocked_by_cname_or_ip": "Zablokované na základe CNAME alebo IP",
"try_again": "Skúste znova", "try_again": "Skúste znova",
"domain_desc": "Zadajte meno domény alebo zástupný znak, ktorý chcete prepísať.", "domain_desc": "Zadajte meno domény alebo zástupný znak, ktorý chcete prepísať.",
"example_rewrite_domain": "prepísať odpovede iba pre toto meno domény.", "example_rewrite_domain": "prepísať odpovede iba pre toto meno domény.",
@@ -571,7 +569,7 @@
"autofix_warning_list": "Bude vykonávať tieto úlohy: <0>Deaktivovať systém DNSStubListener</0> <0>Nastaviť adresu servera DNS na 127.0.0.1</0> <0>Nahradiť cieľový symbolický odkaz /etc/resolv.conf na /run/systemd/resolve/resolv.conf</0> <0>Zastaviť službu DNSStubListener (znova načítať službu systemd-resolved)</0>", "autofix_warning_list": "Bude vykonávať tieto úlohy: <0>Deaktivovať systém DNSStubListener</0> <0>Nastaviť adresu servera DNS na 127.0.0.1</0> <0>Nahradiť cieľový symbolický odkaz /etc/resolv.conf na /run/systemd/resolve/resolv.conf</0> <0>Zastaviť službu DNSStubListener (znova načítať službu systemd-resolved)</0>",
"autofix_warning_result": "Výsledkom bude, že všetky DNS dopyty z Vášho systému budú štandardne spracované službou AdGuard Home.", "autofix_warning_result": "Výsledkom bude, že všetky DNS dopyty z Vášho systému budú štandardne spracované službou AdGuard Home.",
"tags_title": "Tagy", "tags_title": "Tagy",
"tags_desc": "Môžete vybrať značky, ktoré zodpovedajú klientovi. Zahrňte značky do pravidiel filtrácie, aby ste ich použili presnejšie. <0>Viac informácií</0>.", "tags_desc": "Môžete vybrať značky, ktoré zodpovedajú klientovi. Zahrňte značky do pravidiel filtrovania, aby ste ich použili presnejšie. <0>Viac informácií</0>.",
"form_select_tags": "Zvoľte tagy klienta", "form_select_tags": "Zvoľte tagy klienta",
"check_title": "Skontrolujte filtráciu", "check_title": "Skontrolujte filtráciu",
"check_desc": "Skontrolujte, či je názov hostiteľa filtrovaný.", "check_desc": "Skontrolujte, či je názov hostiteľa filtrovaný.",
@@ -608,7 +606,7 @@
"show_whitelisted_responses": "Obsiahnuté v bielej listine", "show_whitelisted_responses": "Obsiahnuté v bielej listine",
"show_processed_responses": "Spracované", "show_processed_responses": "Spracované",
"blocked_safebrowsing": "Zablokované modulom Bezpečné prehliadanie", "blocked_safebrowsing": "Zablokované modulom Bezpečné prehliadanie",
"blocked_adult_websites": "Zablokované Rodičovskou kontrolou", "blocked_adult_websites": "Zablokovaná stránka pre dospelých",
"blocked_threats": "Zablokované hrozby", "blocked_threats": "Zablokované hrozby",
"allowed": "Povolené", "allowed": "Povolené",
"filtered": "Filtrované", "filtered": "Filtrované",

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "Ali ste prepričani, da želite izbrisati odjemalca \"{{key}}\"?", "client_confirm_delete": "Ali ste prepričani, da želite izbrisati odjemalca \"{{key}}\"?",
"list_confirm_delete": "Ali ste prepričani, da želite izbrisati ta seznam?", "list_confirm_delete": "Ali ste prepričani, da želite izbrisati ta seznam?",
"auto_clients_title": "Odjemalci izvajanja", "auto_clients_title": "Odjemalci izvajanja",
"auto_clients_desc": "Informacije o naslovih IP naprav, ki uporabljajo ali bi lahko uporabljale AdGuard Home. Te informacije so zbrane iz več virov, vključno z datotekami gostiteljev, povratnim DNS-jem itd.", "auto_clients_desc": "Naprave, ki niso na seznamu trajnih odjemalcev, ki morda še vedno uporabljajo AdGuard Home",
"access_title": "Nastavitve dostopa", "access_title": "Nastavitve dostopa",
"access_desc": "Tukaj lahko nastavite pravila dostopa strežnika DNS AdGuard Home", "access_desc": "Tukaj lahko nastavite pravila dostopa strežnika DNS AdGuard Home",
"access_allowed_title": "Dovoljeni odjemalci", "access_allowed_title": "Dovoljeni odjemalci",
@@ -478,9 +478,7 @@
"setup_dns_notice": "Za uporabo <1>DNS-prek-HTTPS</1> ali <1>DNS-prek-TLS</1>, morate <0>konfigurirati šifriranje</0> v nastavitvah AdGuard Home.", "setup_dns_notice": "Za uporabo <1>DNS-prek-HTTPS</1> ali <1>DNS-prek-TLS</1>, morate <0>konfigurirati šifriranje</0> v nastavitvah AdGuard Home.",
"rewrite_added": "Uspešno je dodano DNS prepisovanje za \"{{key}}\"", "rewrite_added": "Uspešno je dodano DNS prepisovanje za \"{{key}}\"",
"rewrite_deleted": "Uspešno je izbrisano DNS prepisovanje za \"{{key}}\"", "rewrite_deleted": "Uspešno je izbrisano DNS prepisovanje za \"{{key}}\"",
"rewrite_updated": "DNS prepisovanje uspešno posodobljen",
"rewrite_add": "Dodaj prepisovanje DNS", "rewrite_add": "Dodaj prepisovanje DNS",
"rewrite_edit": "Urejanje prepisa DNS",
"rewrite_not_found": "Ni bilo najdenih prepisovanj DNS", "rewrite_not_found": "Ni bilo najdenih prepisovanj DNS",
"rewrite_confirm_delete": "Ali ste prepričani, da želite izbrisati prepisovanje DNS za \"{{key}}\"?", "rewrite_confirm_delete": "Ali ste prepričani, da želite izbrisati prepisovanje DNS za \"{{key}}\"?",
"rewrite_desc": "Omogoča enostavno konfiguriranje odgovora DNS po meri za določeno ime domene.", "rewrite_desc": "Omogoča enostavno konfiguriranje odgovora DNS po meri za določeno ime domene.",

View File

@@ -167,7 +167,6 @@
"enabled_parental_toast": "Uključena roditeljska kontrola", "enabled_parental_toast": "Uključena roditeljska kontrola",
"disabled_safe_search_toast": "Isključena sigurna pretraga", "disabled_safe_search_toast": "Isključena sigurna pretraga",
"enabled_save_search_toast": "Uključeno sigurno pretraživanje", "enabled_save_search_toast": "Uključeno sigurno pretraživanje",
"updated_save_search_toast": "Ažurirane postavke bezbedne pretrage",
"enabled_table_header": "Uključeno", "enabled_table_header": "Uključeno",
"name_table_header": "Ime", "name_table_header": "Ime",
"list_url_table_header": "URL do liste", "list_url_table_header": "URL do liste",
@@ -257,12 +256,12 @@
"query_log_cleared": "Dnevnik unosa je uspešno očišćen", "query_log_cleared": "Dnevnik unosa je uspešno očišćen",
"query_log_updated": "Dnevnik zapisa je uspešno ažuriran", "query_log_updated": "Dnevnik zapisa je uspešno ažuriran",
"query_log_clear": "Očisti dnevnike unosa", "query_log_clear": "Očisti dnevnike unosa",
"query_log_retention": "Rotacija evidencija upita", "query_log_retention": "Zadržavanje dnevnika unosa",
"query_log_enable": "Uključi dnevnik", "query_log_enable": "Uključi dnevnik",
"query_log_configuration": "Konfiguracija dnevnika", "query_log_configuration": "Konfiguracija dnevnika",
"query_log_disabled": "Dnevnik unosa je isključen ali se može konfigurisati u <0>postavkama</0>", "query_log_disabled": "Dnevnik unosa je isključen ali se može konfigurisati u <0>postavkama</0>",
"query_log_strict_search": "Koristi duple navodnike za striktnu pretragu", "query_log_strict_search": "Koristi duple navodnike za striktnu pretragu",
"query_log_retention_confirm": "Želite li zaista da promenite rotaciju evidencije upita? Ako smanjite vrednost intervala, neki podaci će biti izgubljeni", "query_log_retention_confirm": "Jeste li sigurni da želite da promenite zadržavanje dnevnika unosa? Ako smanjite vrednost intervala, neki podaci će biti izgubljeni",
"anonymize_client_ip": "Anonimizuj IP klijenta", "anonymize_client_ip": "Anonimizuj IP klijenta",
"anonymize_client_ip_desc": "Ne čuvaj punu IP adresu klijenta u dnevnicima i statistikama", "anonymize_client_ip_desc": "Ne čuvaj punu IP adresu klijenta u dnevnicima i statistikama",
"dns_config": "Konfiguracija DNS servera", "dns_config": "Konfiguracija DNS servera",
@@ -291,8 +290,6 @@
"rate_limit": "Ograničenje brzine", "rate_limit": "Ograničenje brzine",
"edns_enable": "Uključi EDNS Client Subnet", "edns_enable": "Uključi EDNS Client Subnet",
"edns_cs_desc": "Dodajte opciju podmreži EDNS klijenta (ECS) uzvodnim zahtevima i evidentirajte vrednosti koje klijenti šalju u evidenciji upita.", "edns_cs_desc": "Dodajte opciju podmreži EDNS klijenta (ECS) uzvodnim zahtevima i evidentirajte vrednosti koje klijenti šalju u evidenciji upita.",
"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_desc": "Broj zahteva u sekundi dozvoljen po klijentu. Postavljanje na 0 znači da nema ograničenja.",
"blocking_ipv4_desc": "IP adresa koja će biti vraćena za blokirane zahteve", "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_ipv6_desc": "IP adresa koja će biti vraćena za blokirane AAAA zahteve",
@@ -444,7 +441,7 @@
"client_confirm_delete": "Jeste li sigurni da želite da izbrišete klijenta \"{{key}}\"?", "client_confirm_delete": "Jeste li sigurni da želite da izbrišete klijenta \"{{key}}\"?",
"list_confirm_delete": "Jeste li sigurni da želite da izbrišete ovu listu?", "list_confirm_delete": "Jeste li sigurni da želite da izbrišete ovu listu?",
"auto_clients_title": "Klijenti (runtime)", "auto_clients_title": "Klijenti (runtime)",
"auto_clients_desc": "Podaci o klijentima koji koriste AdGuard Home, ali nisu sačuvani u konfiguraciji", "auto_clients_desc": "Uređaji koji nisu na listi upornih klijenata koji i dalje mogu da koriste AdGuard Home",
"access_title": "Postavke pristupa", "access_title": "Postavke pristupa",
"access_desc": "Ovde možete konfigurisati pravila pristupa za AdGuard Home DNS server", "access_desc": "Ovde možete konfigurisati pravila pristupa za AdGuard Home DNS server",
"access_allowed_title": "Dozvoljeni klijenti", "access_allowed_title": "Dozvoljeni klijenti",
@@ -478,9 +475,7 @@
"setup_dns_notice": "Kako biste koristili <1>DNS-over-HTTPS</1> ili <1>DNS-over-TLS</1>, potrebno je da <0>konfigurišete šifrovanje</0> u AdGuard Home postavkama.", "setup_dns_notice": "Kako biste koristili <1>DNS-over-HTTPS</1> ili <1>DNS-over-TLS</1>, potrebno je da <0>konfigurišete šifrovanje</0> u AdGuard Home postavkama.",
"rewrite_added": "DNS prepisivanje za \"{{key}}\" je uspešno dodato", "rewrite_added": "DNS prepisivanje za \"{{key}}\" je uspešno dodato",
"rewrite_deleted": "DNS prepisivanje za \"{{key}}\" uspešno izbrisano", "rewrite_deleted": "DNS prepisivanje za \"{{key}}\" uspešno izbrisano",
"rewrite_updated": "DNS ponovo napisao uspešno ažuriran",
"rewrite_add": "Dodaj DNS prepisivanje", "rewrite_add": "Dodaj DNS prepisivanje",
"rewrite_edit": "Uređivanje DNS prepravke",
"rewrite_not_found": "DNS prepisivanja nisu pronađena", "rewrite_not_found": "DNS prepisivanja nisu pronađena",
"rewrite_confirm_delete": "Jeste li sigurni da želite da izbrišete DNS prepisivanje za \"{{key}}\"?", "rewrite_confirm_delete": "Jeste li sigurni da želite da izbrišete DNS prepisivanje za \"{{key}}\"?",
"rewrite_desc": "Dozvoljava da jednostavno konfigurišete prilagođeni DNS odgovor za određeni domen.", "rewrite_desc": "Dozvoljava da jednostavno konfigurišete prilagođeni DNS odgovor za određeni domen.",
@@ -528,10 +523,6 @@
"statistics_retention_confirm": "Jeste li sigurni da želite da promenite zadržavanje statistike? Ako smanjite vrednost intervala, neki podaci će biti izgubljeni", "statistics_retention_confirm": "Jeste li sigurni da želite da promenite zadržavanje statistike? Ako smanjite vrednost intervala, neki podaci će biti izgubljeni",
"statistics_cleared": "Statistika je uspešno očišćena", "statistics_cleared": "Statistika je uspešno očišćena",
"statistics_enable": "Uključi statistiku", "statistics_enable": "Uključi statistiku",
"ignore_domains": "Zanemari domene (razdvojene novom linijom)",
"ignore_domains_title": "Zanemareni domeni",
"ignore_domains_desc_stats": "Upiti za ove domene nisu upisani u statistiku",
"ignore_domains_desc_query": "Upiti za ove domene nisu upisani u evidenciju upita",
"interval_hours": "{{count}} čas", "interval_hours": "{{count}} čas",
"interval_hours_plural": "{{count}} časova", "interval_hours_plural": "{{count}} časova",
"filters_configuration": "Konfiguracija filtera", "filters_configuration": "Konfiguracija filtera",
@@ -652,29 +643,5 @@
"confirm_dns_cache_clear": "Želite li zaista da obrišite DNS keš?", "confirm_dns_cache_clear": "Želite li zaista da obrišite DNS keš?",
"cache_cleared": "DNS keš je uspešno očišćen", "cache_cleared": "DNS keš je uspešno očišćen",
"clear_cache": "Obriši keš memoriju", "clear_cache": "Obriši keš memoriju",
"make_static": "Učini statičnim", "protection_section_label": "Zaštita"
"theme_auto_desc": "Automatski (na osnovu šeme boja uređaja)",
"theme_dark_desc": "Tamna tema",
"theme_light_desc": "Svetla tema",
"disable_for_seconds": "Za {{count}} sekund",
"disable_for_seconds_plural": "Za {{count}} sekundi",
"disable_for_minutes": "Za {{count}} minut",
"disable_for_minutes_plural": "Za {{count}} minuta",
"disable_for_hours": "Za {{count}} sat",
"disable_for_hours_plural": "Za {{count}} sati",
"disable_until_tomorrow": "Do sutra",
"disable_notify_for_seconds": "Isključi zaštitu na {{count}} sekund",
"disable_notify_for_seconds_plural": "Isključi zaštitu na {{count}} sekundi",
"disable_notify_for_minutes": "Isključi zaštitu na {{count}} minut",
"disable_notify_for_minutes_plural": "Isključi zaštitu na {{count}} minuta",
"disable_notify_for_hours": "Isključi zaštitu na {{count}} sat",
"disable_notify_for_hours_plural": "Isključi zaštitu na {{count}} sati",
"disable_notify_until_tomorrow": "Isključi zaštitu do sutra",
"enable_protection_timer": "Zaštita će biti uključena u {{time}}",
"custom_retention_input": "Unesite zadržavanje u časovima",
"custom_rotation_input": "Unesite rotaciju u časovima",
"protection_section_label": "Zaštita",
"log_and_stats_section_label": "Evidencija upita i statistika",
"ignore_query_log": "Zanemari ovog klijenta u evidenciji upita",
"ignore_statistics": "Zanemari ovog klijenta u statističkim podacima"
} }

View File

@@ -475,9 +475,7 @@
"setup_dns_notice": "För att kunna använda <1>DNS-över-HTTPS</1> eller <1>DNS-över-TLS</1>, behöver du <0>konfigurera Kryptering</0> i AdGuard Home-inställningar.", "setup_dns_notice": "För att kunna använda <1>DNS-över-HTTPS</1> eller <1>DNS-över-TLS</1>, behöver du <0>konfigurera Kryptering</0> i AdGuard Home-inställningar.",
"rewrite_added": "DNS-omskrivning för \"{{key}}\" lyckad", "rewrite_added": "DNS-omskrivning för \"{{key}}\" lyckad",
"rewrite_deleted": "DNS-omskrivning för \"{{key}}\" har tagits bort", "rewrite_deleted": "DNS-omskrivning för \"{{key}}\" har tagits bort",
"rewrite_updated": "DNS-omskrivning har uppdaterats",
"rewrite_add": "Lägg till DNS omskrivning", "rewrite_add": "Lägg till DNS omskrivning",
"rewrite_edit": "Redigera DNS-omskrivning",
"rewrite_not_found": "Inga DNS omskrivningar hittades", "rewrite_not_found": "Inga DNS omskrivningar hittades",
"rewrite_confirm_delete": "Är du säker på att du vill ta bort DNS-omskrivningen för \"{{key}}\"?", "rewrite_confirm_delete": "Är du säker på att du vill ta bort DNS-omskrivningen för \"{{key}}\"?",
"rewrite_desc": "Gör det enkelt att konfigurera anpassat DNS svar för ett specifikt domännamn.", "rewrite_desc": "Gör det enkelt att konfigurera anpassat DNS svar för ett specifikt domännamn.",

View File

@@ -172,7 +172,6 @@
"dnscrypt": "DNSCrypt", "dnscrypt": "DNSCrypt",
"dns_over_https": "DNS-over-HTTPS", "dns_over_https": "DNS-over-HTTPS",
"dns_over_tls": "DNS-over-TLS", "dns_over_tls": "DNS-over-TLS",
"dns_over_quic": "DNS-over-QUIC",
"form_enter_rate_limit": "ป้อนขีดจำกัดอัตรา", "form_enter_rate_limit": "ป้อนขีดจำกัดอัตรา",
"rate_limit": "จำกัดอัตรา", "rate_limit": "จำกัดอัตรา",
"edns_enable": "เปิดใช้งานซับเน็ตไคลเอ็นต์ EDNS", "edns_enable": "เปิดใช้งานซับเน็ตไคลเอ็นต์ EDNS",
@@ -393,7 +392,6 @@
"show_processed_responses": "การประมวลผล", "show_processed_responses": "การประมวลผล",
"blocked_adult_websites": "ถูกปิดกั้นโดยการควบคุมของผู้ปกครอง", "blocked_adult_websites": "ถูกปิดกั้นโดยการควบคุมของผู้ปกครอง",
"safe_search": "ค้นหาอย่างปลอดภัย", "safe_search": "ค้นหาอย่างปลอดภัย",
"blocklist": "บัญชีดำ",
"filter_category_other": "อื่น ๆ", "filter_category_other": "อื่น ๆ",
"parental_control": "ควบคุมโดยผู้ปกครอง" "parental_control": "ควบคุมโดยผู้ปกครอง"
} }

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "\"{{key}}\" istemcisini silmek istediğinizden emin misiniz?", "client_confirm_delete": "\"{{key}}\" istemcisini silmek istediğinizden emin misiniz?",
"list_confirm_delete": "Bu listeyi silmek istediğinizden emin misiniz?", "list_confirm_delete": "Bu listeyi silmek istediğinizden emin misiniz?",
"auto_clients_title": "Çalışma zamanı istemcileri", "auto_clients_title": "Çalışma zamanı istemcileri",
"auto_clients_desc": "AdGuard Home'u kullanan veya kullanabilecek cihazların IP adresleri hakkında bilgiler. Bu bilgiler, hosts dosyaları, ters DNS, vb. dahil olmak üzere çeşitli kaynaklardan toplanır.", "auto_clients_desc": "Henüz AdGuard Home'u kullanabilecek Kalıcı istemciler listesinde olmayan cihazlar",
"access_title": "Erişim ayarları", "access_title": "Erişim ayarları",
"access_desc": "AdGuard Home DNS sunucusu için erişim kurallarını buradan yapılandırabilirsiniz", "access_desc": "AdGuard Home DNS sunucusu için erişim kurallarını buradan yapılandırabilirsiniz",
"access_allowed_title": "İzin verilen istemciler", "access_allowed_title": "İzin verilen istemciler",
@@ -478,9 +478,7 @@
"setup_dns_notice": "<1>DNS-over-HTTPS</1> veya <1>DNS-over-TLS</1> protokolünü kullanmak için AdGuard Home üzerinde <0>Şifreleme ayarları</0> bölümünden ayarları yapmanız gerekir.", "setup_dns_notice": "<1>DNS-over-HTTPS</1> veya <1>DNS-over-TLS</1> protokolünü kullanmak için AdGuard Home üzerinde <0>Şifreleme ayarları</0> bölümünden ayarları yapmanız gerekir.",
"rewrite_added": "\"{{key}}\" için DNS yeniden yazımı başarıyla eklendi", "rewrite_added": "\"{{key}}\" için DNS yeniden yazımı başarıyla eklendi",
"rewrite_deleted": "\"{{key}}\" için DNS yeniden yazımı başarıyla silindi", "rewrite_deleted": "\"{{key}}\" için DNS yeniden yazımı başarıyla silindi",
"rewrite_updated": "DNS yeniden yazma başarıyla güncellendi",
"rewrite_add": "DNS yeniden yazımı ekle", "rewrite_add": "DNS yeniden yazımı ekle",
"rewrite_edit": "DNS yeniden yazmayı düzenle",
"rewrite_not_found": "DNS yeniden yazımı bulunamadı", "rewrite_not_found": "DNS yeniden yazımı bulunamadı",
"rewrite_confirm_delete": "\"{{key}}\" için DNS yeniden yazımını silmek istediğinize emin misiniz?", "rewrite_confirm_delete": "\"{{key}}\" için DNS yeniden yazımını silmek istediğinize emin misiniz?",
"rewrite_desc": "Belirli bir alan adı için özel DNS yanıtını kolayca yapılandırmanızı sağlar.", "rewrite_desc": "Belirli bir alan adı için özel DNS yanıtını kolayca yapılandırmanızı sağlar.",

View File

@@ -167,7 +167,6 @@
"enabled_parental_toast": "«Батьківський контроль» увімкнено", "enabled_parental_toast": "«Батьківський контроль» увімкнено",
"disabled_safe_search_toast": "Безпечний пошук вимкнено", "disabled_safe_search_toast": "Безпечний пошук вимкнено",
"enabled_save_search_toast": "Безпечний пошук увімкнено", "enabled_save_search_toast": "Безпечний пошук увімкнено",
"updated_save_search_toast": "Налаштування Безпечного пошуку оновлено",
"enabled_table_header": "Увімкнено", "enabled_table_header": "Увімкнено",
"name_table_header": "Назва", "name_table_header": "Назва",
"list_url_table_header": "URL списку", "list_url_table_header": "URL списку",
@@ -291,8 +290,6 @@
"rate_limit": "Обмеження швидкості", "rate_limit": "Обмеження швидкості",
"edns_enable": "Увімкнути відправку EDNS Client Subnet", "edns_enable": "Увімкнути відправку EDNS Client Subnet",
"edns_cs_desc": "Додавати параметр EDNS Client Subnet (ECS) до запитів до upstream-серверів, а також записувати в журнал значення, що надсилаються клієнтами.", "edns_cs_desc": "Додавати параметр EDNS Client Subnet (ECS) до запитів до upstream-серверів, а також записувати в журнал значення, що надсилаються клієнтами.",
"edns_use_custom_ip": "Використання користувацької IP-адреси для EDNS",
"edns_use_custom_ip_desc": "Дозволити використовувати користувацьку IP-адресу для EDNS",
"rate_limit_desc": "Кількість запитів в секунду, які може робити один клієнт. Встановлене значення «0» означатиме необмежену кількість.", "rate_limit_desc": "Кількість запитів в секунду, які може робити один клієнт. Встановлене значення «0» означатиме необмежену кількість.",
"blocking_ipv4_desc": "IP-адреса, яку потрібно видати для заблокованого A запиту", "blocking_ipv4_desc": "IP-адреса, яку потрібно видати для заблокованого A запиту",
"blocking_ipv6_desc": "IP-адреса, яку потрібно видати для заблокованого АААА запиту", "blocking_ipv6_desc": "IP-адреса, яку потрібно видати для заблокованого АААА запиту",
@@ -444,7 +441,7 @@
"client_confirm_delete": "Ви впевнені, що хочете видалити клієнта «{{key}}»?", "client_confirm_delete": "Ви впевнені, що хочете видалити клієнта «{{key}}»?",
"list_confirm_delete": "Ви впевнені, що хочете видалити цей список?", "list_confirm_delete": "Ви впевнені, що хочете видалити цей список?",
"auto_clients_title": "Runtime-клієнти", "auto_clients_title": "Runtime-клієнти",
"auto_clients_desc": "Інформація про IP-адреси пристроїв, які використовують або можуть використовувати AdGuard Home. Ця інформація збирається з кількох джерел, зокрема з файлів hosts, зворотного DNS тощо.", "auto_clients_desc": "Клієнти, які використовують AdGuard Home, незалежно від того, чи збережені вони в списку постійних",
"access_title": "Налаштування доступу", "access_title": "Налаштування доступу",
"access_desc": "Тут ви можете налаштувати правила доступу для DNS-сервера AdGuard Home", "access_desc": "Тут ви можете налаштувати правила доступу для DNS-сервера AdGuard Home",
"access_allowed_title": "Дозволені клієнти", "access_allowed_title": "Дозволені клієнти",
@@ -478,9 +475,7 @@
"setup_dns_notice": "Для використання <1>DNS-over-HTTPS</1> або <1>DNS-over-TLS</1>, вам потрібно <0>налаштувати Шифрування</0> в налаштуваннях AdGuard Home.", "setup_dns_notice": "Для використання <1>DNS-over-HTTPS</1> або <1>DNS-over-TLS</1>, вам потрібно <0>налаштувати Шифрування</0> в налаштуваннях AdGuard Home.",
"rewrite_added": "Перезапис DNS для «{{key}}» успішно додано", "rewrite_added": "Перезапис DNS для «{{key}}» успішно додано",
"rewrite_deleted": "Перезапис DNS для «{{key}}» успішно видалено", "rewrite_deleted": "Перезапис DNS для «{{key}}» успішно видалено",
"rewrite_updated": "Перезапис DNS успішно оновлено",
"rewrite_add": "Додати перезапис DNS", "rewrite_add": "Додати перезапис DNS",
"rewrite_edit": "Редагувати перезапис DNS",
"rewrite_not_found": "Перезаписів DNS не знайдено", "rewrite_not_found": "Перезаписів DNS не знайдено",
"rewrite_confirm_delete": "Ви впевнені, що хочете видалити перезапис DNS для «{{key}}»?", "rewrite_confirm_delete": "Ви впевнені, що хочете видалити перезапис DNS для «{{key}}»?",
"rewrite_desc": "Дозволяє легко налаштувати власну відповідь DNS для певного доменного імені.", "rewrite_desc": "Дозволяє легко налаштувати власну відповідь DNS для певного доменного імені.",
@@ -528,10 +523,6 @@
"statistics_retention_confirm": "Ви впевнені, що хочете змінити тривалість статистики? Якщо зменшити значення інтервалу, деякі дані будуть втрачені", "statistics_retention_confirm": "Ви впевнені, що хочете змінити тривалість статистики? Якщо зменшити значення інтервалу, деякі дані будуть втрачені",
"statistics_cleared": "Статистику успішно очищено", "statistics_cleared": "Статистику успішно очищено",
"statistics_enable": "Увімкнути статистику", "statistics_enable": "Увімкнути статистику",
"ignore_domains": "Ігноровані домени (по одному на рядок)",
"ignore_domains_title": "Ігноровані домени",
"ignore_domains_desc_stats": "Запити для цих доменів в статистику не пишуться",
"ignore_domains_desc_query": "Запити для цих доменів не записуються до журналу запитів",
"interval_hours": "{{count}} година", "interval_hours": "{{count}} година",
"interval_hours_plural": "{{count}} годин(и)", "interval_hours_plural": "{{count}} годин(и)",
"filters_configuration": "Конфігурація фільтрів", "filters_configuration": "Конфігурація фільтрів",
@@ -652,29 +643,5 @@
"confirm_dns_cache_clear": "Ви впевнені, що бажаєте очистити кеш DNS?", "confirm_dns_cache_clear": "Ви впевнені, що бажаєте очистити кеш DNS?",
"cache_cleared": "Кеш DNS успішно очищено", "cache_cleared": "Кеш DNS успішно очищено",
"clear_cache": "Очистити кеш", "clear_cache": "Очистити кеш",
"make_static": "Зробити статичним", "protection_section_label": "Захист"
"theme_auto_desc": "Автоматична (на основі теми вашого пристрою)",
"theme_dark_desc": "Темна тема",
"theme_light_desc": "Світла тема",
"disable_for_seconds": "На {{count}} секунду",
"disable_for_seconds_plural": "На {{count}} секунд",
"disable_for_minutes": "На {{count}} хвилину",
"disable_for_minutes_plural": "На {{count}} хвилин",
"disable_for_hours": "На {{count}} годину",
"disable_for_hours_plural": "На {{count}} годин",
"disable_until_tomorrow": "До завтра",
"disable_notify_for_seconds": "Вимкнення захисту на {{count}} секунду",
"disable_notify_for_seconds_plural": "Вимкнення захисту на {{count}} секунд",
"disable_notify_for_minutes": "Вимкнення захисту на {{count}} хвилину",
"disable_notify_for_minutes_plural": "Вимкнення захисту на {{count}} хвилин",
"disable_notify_for_hours": "Вимкнення захисту на {{count}} годину",
"disable_notify_for_hours_plural": "Вимкнення захисту на {{count}} годин",
"disable_notify_until_tomorrow": "Відключення захисту до завтра",
"enable_protection_timer": "Захист буде ввімкнено о {{time}}",
"custom_retention_input": "Введіть час в годинах",
"custom_rotation_input": "Введіть час в годинах",
"protection_section_label": "Захист",
"log_and_stats_section_label": "Журнал запитів і статистика",
"ignore_query_log": "Ігнорувати цей клієнт у журналі запитів",
"ignore_statistics": "Ігноруйте цей клієнт в статистиці"
} }

View File

@@ -1,5 +1,5 @@
{ {
"client_settings": "Cài đặt thiết bị", "client_settings": "Cài đặt máy khách",
"example_upstream_reserved": "ngược dòng <0>cho các miền cụ thể</0>;", "example_upstream_reserved": "ngược dòng <0>cho các miền cụ thể</0>;",
"example_upstream_comment": "một lời bình luận.", "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", "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",
@@ -167,7 +167,6 @@
"enabled_parental_toast": "Đã bật quản lý của phụ huynh", "enabled_parental_toast": "Đã bật quản lý của phụ huynh",
"disabled_safe_search_toast": "Đã tắt tìm kiếm an toàn", "disabled_safe_search_toast": "Đã tắt tìm kiếm an toàn",
"enabled_save_search_toast": "Đã bật tìm kiếm an toàn", "enabled_save_search_toast": "Đã bật tìm kiếm an toàn",
"updated_save_search_toast": "Cài đặt Tìm kiếm an toàn đã được cập nhật",
"enabled_table_header": "Kích hoạt", "enabled_table_header": "Kích hoạt",
"name_table_header": "Tên", "name_table_header": "Tên",
"list_url_table_header": "URL bộ lọc", "list_url_table_header": "URL bộ lọc",
@@ -257,12 +256,12 @@
"query_log_cleared": "Nhật ký truy vấn đã được xóa thành công", "query_log_cleared": "Nhật ký truy vấn đã được xóa thành công",
"query_log_updated": "Cập nhật thành công nhật kí truy xuất", "query_log_updated": "Cập nhật thành công nhật kí truy xuất",
"query_log_clear": "Xóa nhật ký truy vấn", "query_log_clear": "Xóa nhật ký truy vấn",
"query_log_retention": "Xoay vòng nhật ký truy vấn", "query_log_retention": "Lưu giữ nhật ký truy vấn",
"query_log_enable": "Bật nhật ký", "query_log_enable": "Bật nhật ký",
"query_log_configuration": "Cấu hình nhật ký", "query_log_configuration": "Cấu hình nhật ký",
"query_log_disabled": "Nhật ký truy vấn bị vô hiệu hóa và có thể được định cấu hình trong <0>cài đặt</ 0>", "query_log_disabled": "Nhật ký truy vấn bị vô hiệu hóa và có thể được định cấu hình trong <0>cài đặt</ 0>",
"query_log_strict_search": "Sử dụng dấu ngoặc kép để tìm kiếm nghiêm ngặt", "query_log_strict_search": "Sử dụng dấu ngoặc kép để tìm kiếm nghiêm ngặt",
"query_log_retention_confirm": "Bạn có chắc chắn muốn thay đổi xoay vòng nhật ký truy vấn không? Nếu bạn giảm giá trị khoảng thời gian, một số dữ liệu sẽ bị mất", "query_log_retention_confirm": "Bạn có chắc chắn muốn thay đổi lưu giữ nhật ký truy vấn? Nếu bạn giảm giá trị khoảng, một số dữ liệu sẽ bị mất",
"anonymize_client_ip": "Ẩn danh IP khách", "anonymize_client_ip": "Ẩn danh IP khách",
"anonymize_client_ip_desc": "Không lưu địa chỉ IP đầy đủ của khách hàng trong nhật ký và thống kê", "anonymize_client_ip_desc": "Không lưu địa chỉ IP đầy đủ của khách hàng trong nhật ký và thống kê",
"dns_config": "Thiết lập máy chủ DNS", "dns_config": "Thiết lập máy chủ DNS",
@@ -291,8 +290,6 @@
"rate_limit": "Giới hạn yêu cầu", "rate_limit": "Giới hạn yêu cầu",
"edns_enable": "Bật mạng con EDNS Client", "edns_enable": "Bật mạng con EDNS Client",
"edns_cs_desc": "Thêm tùy chọn EDNS Client Subnet (ECS) vào các yêu cầu ngược dòng và ghi lại các giá trị được gửi bởi các máy khách trong nhật ký truy vấn.", "edns_cs_desc": "Thêm tùy chọn EDNS Client Subnet (ECS) vào các yêu cầu ngược dòng và ghi lại các giá trị được gửi bởi các máy khách trong nhật ký truy vấn.",
"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_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)",
"blocking_ipv4_desc": "Địa chỉ IP được trả lại cho một yêu cầu A bị chặn", "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_ipv6_desc": "Địa chỉ IP được trả lại cho một yêu cầu AAA bị chặn",
@@ -444,7 +441,7 @@
"client_confirm_delete": "Bạn có chắc chắn muốn xóa máy khách \"{{key}}\" không?", "client_confirm_delete": "Bạn có chắc chắn muốn xóa máy khách \"{{key}}\" không?",
"list_confirm_delete": "Bạn có muốn xóa bộ lọc này?", "list_confirm_delete": "Bạn có muốn xóa bộ lọc này?",
"auto_clients_title": "Máy khách (thời gian chạy)", "auto_clients_title": "Máy khách (thời gian chạy)",
"auto_clients_desc": "Thông tin về địa chỉ IP của thiết bị đang sử dụng hoặc có thể sử dụng AdGuard Home. Thông tin này được thu thập từ nhiều nguồn, bao gồm tệp máy chủ, DNS ngược, v.v.", "auto_clients_desc": "Các thiết bị không có trong danh sách khách hàng ổn định vẫn có thể sử dụng AdGuard Home",
"access_title": "Cài đặt truy cập", "access_title": "Cài đặt truy cập",
"access_desc": "Tại đây bạn có thể định cấu hình quy tắc truy cập cho máy chủ AdGuard Home DNS", "access_desc": "Tại đây bạn có thể định cấu hình quy tắc truy cập cho máy chủ AdGuard Home DNS",
"access_allowed_title": "Máy chủ được phép", "access_allowed_title": "Máy chủ được phép",
@@ -478,9 +475,7 @@
"setup_dns_notice": "Để sử dụng <1>DNS-over-HTTPS</1> hoặc <1>DNS-over-TLS</1>, bạn cần <0>định cấu hình Mã hóa</0> trong cài đặt AdGuard Home.", "setup_dns_notice": "Để sử dụng <1>DNS-over-HTTPS</1> hoặc <1>DNS-over-TLS</1>, bạn cần <0>định cấu hình Mã hóa</0> trong cài đặt AdGuard Home.",
"rewrite_added": "DNS viết lại cho \"{{key}}\" đã thêm thành công", "rewrite_added": "DNS viết lại cho \"{{key}}\" đã thêm thành công",
"rewrite_deleted": "DNS viết lại cho \"{{key}}\" đã xóa thành công", "rewrite_deleted": "DNS viết lại cho \"{{key}}\" đã xóa thành công",
"rewrite_updated": "Viết lại DNS được cập nhật thành công",
"rewrite_add": "Thêm DNS viết lại", "rewrite_add": "Thêm DNS viết lại",
"rewrite_edit": "Chỉnh sửa viết lại DNS",
"rewrite_not_found": "Không tìm thấy DNS viết lại", "rewrite_not_found": "Không tìm thấy DNS viết lại",
"rewrite_confirm_delete": "Bạn có chắc chắn muốn xóa DNS viết lại cho \"{{key}}\" không?", "rewrite_confirm_delete": "Bạn có chắc chắn muốn xóa DNS viết lại cho \"{{key}}\" không?",
"rewrite_desc": "Cho phép dễ dàng định cấu hình tùy chỉnh DNS phản hồi cho một tên miền cụ thể.", "rewrite_desc": "Cho phép dễ dàng định cấu hình tùy chỉnh DNS phản hồi cho một tên miền cụ thể.",
@@ -528,10 +523,6 @@
"statistics_retention_confirm": "Bạn có chắc chắn muốn thay đổi lưu giữ số liệu thống kê? Nếu bạn giảm giá trị khoảng, một số dữ liệu sẽ bị mất", "statistics_retention_confirm": "Bạn có chắc chắn muốn thay đổi lưu giữ số liệu thống kê? Nếu bạn giảm giá trị khoảng, một số dữ liệu sẽ bị mất",
"statistics_cleared": "Xoá thống kê thành công", "statistics_cleared": "Xoá thống kê thành công",
"statistics_enable": "Bật thống kê", "statistics_enable": "Bật thống kê",
"ignore_domains": "Các miền bị bỏ qua (cách nhau bởi dòng mới)",
"ignore_domains_title": "Các miền bị bỏ qua",
"ignore_domains_desc_stats": "Các truy vấn cho các miền này sẽ không được ghi vào thống kê",
"ignore_domains_desc_query": "Các truy vấn cho các miền này sẽ không được ghi vào nhật ký truy vấn",
"interval_hours": "{{count}} giờ", "interval_hours": "{{count}} giờ",
"interval_hours_plural": "{{count}} giờ", "interval_hours_plural": "{{count}} giờ",
"filters_configuration": "Cấu hình bộ lọc", "filters_configuration": "Cấu hình bộ lọc",
@@ -652,29 +643,5 @@
"confirm_dns_cache_clear": "Bạn có chắc chắn muốn xóa bộ đệm ẩn DNS không?", "confirm_dns_cache_clear": "Bạn có chắc chắn muốn xóa bộ đệm ẩn DNS không?",
"cache_cleared": "Đã xóa thành công bộ đệm DNS", "cache_cleared": "Đã xóa thành công bộ đệm DNS",
"clear_cache": "Xóa bộ nhớ cache", "clear_cache": "Xóa bộ nhớ cache",
"make_static": "Chuyển sang tĩnh", "protection_section_label": "Sự bảo vệ"
"theme_auto_desc": "Tự động (dựa trên chủ đề màu của thiết bị của bạn)",
"theme_dark_desc": "Chủ đề tối",
"theme_light_desc": "Chủ đề sáng",
"disable_for_seconds": "Trong {{count}} giây",
"disable_for_seconds_plural": "Trong {{count}} giây",
"disable_for_minutes": "Trong {{count}} phút",
"disable_for_minutes_plural": "Trong {{count}} phút",
"disable_for_hours": "Trong {{count}} giờ",
"disable_for_hours_plural": "Trong {{count}} giờ",
"disable_until_tomorrow": "Cho đến ngày mai",
"disable_notify_for_seconds": "Tắt bảo vệ trong {{count}} giây",
"disable_notify_for_seconds_plural": "Tắt bảo vệ trong {{count}} giây",
"disable_notify_for_minutes": "Tắt bảo vệ trong {{count}} phút",
"disable_notify_for_minutes_plural": "Tắt bảo vệ trong {{count}} phút",
"disable_notify_for_hours": "Tắt bảo vệ trong {{count}} giờ",
"disable_notify_for_hours_plural": "Tắt bảo vệ trong {{count}} giờ",
"disable_notify_until_tomorrow": "Vô hiệu hóa bảo vệ cho đến ngày mai",
"enable_protection_timer": "Bảo vệ sẽ được bật trong {{time}}",
"custom_retention_input": "Nhập thời gian giữ lại theo giờ",
"custom_rotation_input": "Nhập chu kỳ theo giờ",
"protection_section_label": "Sự bảo vệ",
"log_and_stats_section_label": "Nhật ký truy vấn và thống kê",
"ignore_query_log": "Bỏ qua máy khách này trong nhật ký truy vấn",
"ignore_statistics": "Bỏ qua máy khách này trong thống kê"
} }

View File

@@ -444,7 +444,7 @@
"client_confirm_delete": "您确定要删除客户端 \"{{key}}\"", "client_confirm_delete": "您确定要删除客户端 \"{{key}}\"",
"list_confirm_delete": "您确定要删除此列表吗?", "list_confirm_delete": "您确定要删除此列表吗?",
"auto_clients_title": "客户端(运行时间)", "auto_clients_title": "客户端(运行时间)",
"auto_clients_desc": "有关正在使用或可能使用 AdGuard Home 的设备的 IP 地址的信息。此信息是从多个来源收集的,包括 hosts 文件、反向 DNS 等。", "auto_clients_desc": "不在可继续使用 AdGuard Home 的持久客户端列表中的设备。",
"access_title": "访问设置", "access_title": "访问设置",
"access_desc": "您可以在此处配置 AdGuard Home 的 DNS 服务器的访问规则", "access_desc": "您可以在此处配置 AdGuard Home 的 DNS 服务器的访问规则",
"access_allowed_title": "允许的客户端", "access_allowed_title": "允许的客户端",
@@ -478,9 +478,7 @@
"setup_dns_notice": "为了使用 <1>DNS-over-HTTPS</1> 或者 <1>DNS-over-TLS</1> ,您需要在 AdGuard Home 设置中 <0>配置加密</0> 。", "setup_dns_notice": "为了使用 <1>DNS-over-HTTPS</1> 或者 <1>DNS-over-TLS</1> ,您需要在 AdGuard Home 设置中 <0>配置加密</0> 。",
"rewrite_added": "已成功添加 \"{{key}}\" 的 DNS 重写", "rewrite_added": "已成功添加 \"{{key}}\" 的 DNS 重写",
"rewrite_deleted": "已成功删除 \"{{key}}\" 的 DNS 重写", "rewrite_deleted": "已成功删除 \"{{key}}\" 的 DNS 重写",
"rewrite_updated": "DNS 重写已成功更新",
"rewrite_add": "添加 DNS 重写", "rewrite_add": "添加 DNS 重写",
"rewrite_edit": "编辑 DNS 重写",
"rewrite_not_found": "未找到 DNS 重写", "rewrite_not_found": "未找到 DNS 重写",
"rewrite_confirm_delete": "您确定要删除 \"{{key}}\" 的 DNS 重写?", "rewrite_confirm_delete": "您确定要删除 \"{{key}}\" 的 DNS 重写?",
"rewrite_desc": "可以轻松地为特定域名配置自定义 DNS 响应。", "rewrite_desc": "可以轻松地为特定域名配置自定义 DNS 响应。",

View File

@@ -48,7 +48,6 @@
"out_of_range_error": "必須介於 \"{{start}}\" - \"{{end}}\" 範圍之外", "out_of_range_error": "必須介於 \"{{start}}\" - \"{{end}}\" 範圍之外",
"lower_range_start_error": "必須小於起始值", "lower_range_start_error": "必須小於起始值",
"greater_range_start_error": "必須大於起始值", "greater_range_start_error": "必須大於起始值",
"gateway_or_subnet_invalid": "無效子網路",
"dhcp_form_gateway_input": "閘道 IP 位址", "dhcp_form_gateway_input": "閘道 IP 位址",
"dhcp_form_subnet_input": "子網路遮罩", "dhcp_form_subnet_input": "子網路遮罩",
"dhcp_form_range_title": "IP 位址範圍", "dhcp_form_range_title": "IP 位址範圍",
@@ -164,7 +163,7 @@
"disabled_parental_toast": "已停用家長監護", "disabled_parental_toast": "已停用家長監護",
"enabled_parental_toast": "已啟用家長監護", "enabled_parental_toast": "已啟用家長監護",
"disabled_safe_search_toast": "已停用安全搜尋", "disabled_safe_search_toast": "已停用安全搜尋",
"updated_save_search_toast": "已更新安全搜尋設定", "enabled_save_search_toast": "已啟用安全搜尋",
"enabled_table_header": "啟用", "enabled_table_header": "啟用",
"name_table_header": "名稱", "name_table_header": "名稱",
"list_url_table_header": "清單 URL 網址", "list_url_table_header": "清單 URL 網址",
@@ -196,7 +195,6 @@
"form_error_url_or_path_format": "列表中含有的 URL 網址或絕對路徑", "form_error_url_or_path_format": "列表中含有的 URL 網址或絕對路徑",
"custom_filter_rules": "自訂過濾規則", "custom_filter_rules": "自訂過濾規則",
"custom_filter_rules_hint": "一行一條規則。您可以使用「adblock」語法或「hosts檔案」的語法。", "custom_filter_rules_hint": "一行一條規則。您可以使用「adblock」語法或「hosts檔案」的語法。",
"system_host_files": "系統 hosts 檔案",
"examples_title": "範例", "examples_title": "範例",
"example_meaning_filter_block": "封鎖對 example.org 網域及其所有子網域的存取", "example_meaning_filter_block": "封鎖對 example.org 網域及其所有子網域的存取",
"example_meaning_filter_whitelist": "解除對 example.org 網域及其所有子網域存取封鎖", "example_meaning_filter_whitelist": "解除對 example.org 網域及其所有子網域存取封鎖",
@@ -211,10 +209,6 @@
"example_upstream_doq": "加密 <0>DNS-over-QUIC</0>", "example_upstream_doq": "加密 <0>DNS-over-QUIC</0>",
"example_upstream_sdns": "您可以使透過 <0>DNS Stamps</0> 來解析 <1>DNSCrypt</1> 或 <2>DNS-over-HTTPS</2>", "example_upstream_sdns": "您可以使透過 <0>DNS Stamps</0> 來解析 <1>DNSCrypt</1> 或 <2>DNS-over-HTTPS</2>",
"example_upstream_tcp": "一般 DNS透過 TCP", "example_upstream_tcp": "一般 DNS透過 TCP",
"example_upstream_regular_port": "一般 DNS透過 UDP連接埠",
"example_upstream_udp": "一般 DNS透過 UDP主機名稱",
"example_upstream_tcp_port": "一般 DNS透過 TCP連接埠",
"example_upstream_tcp_hostname": "一般 DNS透過 TCP主機名稱",
"all_lists_up_to_date_toast": "所有清單已更新至最新", "all_lists_up_to_date_toast": "所有清單已更新至最新",
"dns_test_ok_toast": "設定中的 DNS 上游運作正常", "dns_test_ok_toast": "設定中的 DNS 上游運作正常",
"dns_test_not_ok_toast": "DNS 設定中的 \"{{key}}\" 出現錯誤,請確認是否正確輸入", "dns_test_not_ok_toast": "DNS 設定中的 \"{{key}}\" 出現錯誤,請確認是否正確輸入",
@@ -285,8 +279,6 @@
"rate_limit": "速率限制", "rate_limit": "速率限制",
"edns_enable": "啟用 EDNS Client Subnet", "edns_enable": "啟用 EDNS Client Subnet",
"edns_cs_desc": "傳送用戶端的子網路給 DNS 伺服器。", "edns_cs_desc": "傳送用戶端的子網路給 DNS 伺服器。",
"edns_use_custom_ip": "使用自訂 EDNS IP",
"edns_use_custom_ip_desc": "允許使用自訂 EDNS IP",
"rate_limit_desc": "限制單一裝置每秒發出的查詢次數(設定為 0 即表示無限制)", "rate_limit_desc": "限制單一裝置每秒發出的查詢次數(設定為 0 即表示無限制)",
"blocking_ipv4_desc": "回覆指定 IPv4 位址給被封鎖的網域的 A 紀錄查詢", "blocking_ipv4_desc": "回覆指定 IPv4 位址給被封鎖的網域的 A 紀錄查詢",
"blocking_ipv6_desc": "回覆指定 IPv6 位址給被封鎖的網域的 AAAA 紀錄查詢", "blocking_ipv6_desc": "回覆指定 IPv6 位址給被封鎖的網域的 AAAA 紀錄查詢",
@@ -295,9 +287,6 @@
"blocking_mode_nxdomain": "NXDOMAIN回應 NXDOMAIN 狀態碼", "blocking_mode_nxdomain": "NXDOMAIN回應 NXDOMAIN 狀態碼",
"blocking_mode_null_ip": "Null IP回應零值的 IP 位址A 紀錄回應 0.0.0.0 AAAA 紀錄回應 ::", "blocking_mode_null_ip": "Null IP回應零值的 IP 位址A 紀錄回應 0.0.0.0 AAAA 紀錄回應 ::",
"blocking_mode_custom_ip": "自訂 IP 位址:回應一個自訂的 IP 位址", "blocking_mode_custom_ip": "自訂 IP 位址:回應一個自訂的 IP 位址",
"theme_auto": "自動",
"theme_light": "明亮",
"theme_dark": "深色",
"upstream_dns_client_desc": "如果您將此欄位留白AdGuard Home 將使用 <0>DNS 設定</0> 內的設定的 DNS 伺服器。", "upstream_dns_client_desc": "如果您將此欄位留白AdGuard Home 將使用 <0>DNS 設定</0> 內的設定的 DNS 伺服器。",
"tracker_source": "追蹤器來源", "tracker_source": "追蹤器來源",
"source_label": "來源", "source_label": "來源",
@@ -408,7 +397,6 @@
"dns_providers": "下列為常見的<0> DNS 伺服器</0>。", "dns_providers": "下列為常見的<0> DNS 伺服器</0>。",
"update_now": "立即更新", "update_now": "立即更新",
"update_failed": "自動更新發生錯誤。請嘗試依照<a>以下步驟</a> 來手動更新。", "update_failed": "自動更新發生錯誤。請嘗試依照<a>以下步驟</a> 來手動更新。",
"manual_update": "請嘗試依照<a>下列步驟</a>來手動更新。",
"processing_update": "請稍候AdGuard Home 正在更新", "processing_update": "請稍候AdGuard Home 正在更新",
"clients_title": "用戶端", "clients_title": "用戶端",
"clients_desc": "對已連接到 AdGuard Home 的裝置進行設定", "clients_desc": "對已連接到 AdGuard Home 的裝置進行設定",
@@ -472,7 +460,6 @@
"rewrite_added": "「{{key}}」的 DNS 覆寫新增成功", "rewrite_added": "「{{key}}」的 DNS 覆寫新增成功",
"rewrite_deleted": "「{{key}}」的 DNS 覆寫刪除成功", "rewrite_deleted": "「{{key}}」的 DNS 覆寫刪除成功",
"rewrite_add": "新增 DNS 覆寫", "rewrite_add": "新增 DNS 覆寫",
"rewrite_edit": "編輯 DNS 覆寫",
"rewrite_not_found": "找不到 DNS 覆寫", "rewrite_not_found": "找不到 DNS 覆寫",
"rewrite_confirm_delete": "您確定要刪除 \"{{key}}\" 的 DNS 覆寫?", "rewrite_confirm_delete": "您確定要刪除 \"{{key}}\" 的 DNS 覆寫?",
"rewrite_desc": "提供簡單的方式對特定網域自訂 DNS 回應。", "rewrite_desc": "提供簡單的方式對特定網域自訂 DNS 回應。",
@@ -506,7 +493,6 @@
"interval_days": "{{count}} 天", "interval_days": "{{count}} 天",
"interval_days_plural": "{{count}} 天", "interval_days_plural": "{{count}} 天",
"domain": "網域", "domain": "網域",
"ecs": "EDNS 子網",
"punycode": "Punycode", "punycode": "Punycode",
"answer": "回應", "answer": "回應",
"filter_added_successfully": "已成功新增清單", "filter_added_successfully": "已成功新增清單",
@@ -519,9 +505,6 @@
"statistics_clear_confirm": "您確定要清除統計資料嗎?", "statistics_clear_confirm": "您確定要清除統計資料嗎?",
"statistics_retention_confirm": "您確定要更改統計資料保存時間嗎?如果您縮短期限部分資料可能將會遺失", "statistics_retention_confirm": "您確定要更改統計資料保存時間嗎?如果您縮短期限部分資料可能將會遺失",
"statistics_cleared": "已清除統計資料", "statistics_cleared": "已清除統計資料",
"statistics_enable": "啟用統計數據",
"ignore_domains": "已忽略網域(每行一個)",
"ignore_domains_title": "已忽略網域",
"interval_hours": "{{count}} 小時", "interval_hours": "{{count}} 小時",
"interval_hours_plural": "{{count}} 小時", "interval_hours_plural": "{{count}} 小時",
"filters_configuration": "過濾器設定", "filters_configuration": "過濾器設定",
@@ -630,23 +613,5 @@
"original_response": "原始回應", "original_response": "原始回應",
"click_to_view_queries": "按一下以檢視查詢結果", "click_to_view_queries": "按一下以檢視查詢結果",
"port_53_faq_link": "連接埠 53 經常被「DNSStubListener」或「systemd-resolved」服務佔用。請閱讀下列有關解決<0>這個問題</0>的說明", "port_53_faq_link": "連接埠 53 經常被「DNSStubListener」或「systemd-resolved」服務佔用。請閱讀下列有關解決<0>這個問題</0>的說明",
"adg_will_drop_dns_queries": "AdGuard Home 將停止回應此用戶端的所有 DNS 查詢。", "adg_will_drop_dns_queries": "AdGuard Home 將停止回應此用戶端的所有 DNS 查詢。"
"safe_browsing": "安全瀏覽",
"served_from_cache": "{{value}} <i>(由快取回應)</i>",
"form_error_password_length": "密碼必須至少 {{value}} 個字元長度",
"make_static": "新增為靜態",
"theme_dark_desc": "深色主題",
"theme_light_desc": "淺色主題",
"disable_for_seconds": "{{count}} 秒",
"disable_for_seconds_plural": "{{count}} 秒",
"disable_for_minutes": "{{count}} 分鐘",
"disable_for_minutes_plural": "{{count}} 分鐘",
"disable_for_hours": "{{count}} 小時",
"disable_for_hours_plural": "{{count}} 小時",
"disable_until_tomorrow": "直到明天",
"disable_notify_for_seconds": "暫停防護 {{count}} 秒",
"disable_notify_for_seconds_plural": "暫停防護 {{count}} 秒",
"disable_notify_for_minutes": "暫停防護 {{count}} 分鐘",
"disable_notify_for_minutes_plural": "暫停防護 {{count}} 分鐘",
"disable_notify_for_hours": "暫停防護 {{count}} 小時"
} }

View File

@@ -138,9 +138,9 @@
"block_domain_use_filters_and_hosts": "透過過濾器和主機檔案封鎖網域", "block_domain_use_filters_and_hosts": "透過過濾器和主機檔案封鎖網域",
"filters_block_toggle_hint": "您可在<a>過濾器</a>設定中設置封鎖規則。", "filters_block_toggle_hint": "您可在<a>過濾器</a>設定中設置封鎖規則。",
"use_adguard_browsing_sec": "使用 AdGuard 瀏覽安全網路服務", "use_adguard_browsing_sec": "使用 AdGuard 瀏覽安全網路服務",
"use_adguard_browsing_sec_hint": "AdGuard Home 將檢查該網域是否被瀏覽安全網路服務封鎖。它將使用對隱私友好的查找應用程式介面API以執行檢查僅域名 SHA256 雜湊的短前綴被傳送到該伺服器。", "use_adguard_browsing_sec_hint": "AdGuard Home 將檢查該網域是否被瀏覽安全網路服務封鎖。它將使用友好的隱私查找應用程式介面API以執行檢查僅域名 SHA256 雜湊的短前綴被傳送到該伺服器。",
"use_adguard_parental": "使用 AdGuard 家長控制之網路服務", "use_adguard_parental": "使用 AdGuard 家長控制之網路服務",
"use_adguard_parental_hint": "AdGuard Home 將檢查網域是否包含成人資料。它使用如同瀏覽安全網路服務一樣之對隱私友好的應用程式介面API。", "use_adguard_parental_hint": "AdGuard Home 將檢查網域是否包含成人資料。它使用如同瀏覽安全網路服務一樣之友好的隱私應用程式介面API。",
"enforce_safe_search": "使用安全搜尋", "enforce_safe_search": "使用安全搜尋",
"enforce_save_search_hint": "AdGuard Home 將在下列的搜尋引擎Google、YouTube、Bing、DuckDuckGo、Yandex 和 Pixabay 中強制執行安全搜尋。", "enforce_save_search_hint": "AdGuard Home 將在下列的搜尋引擎Google、YouTube、Bing、DuckDuckGo、Yandex 和 Pixabay 中強制執行安全搜尋。",
"no_servers_specified": "無已明確指定的伺服器", "no_servers_specified": "無已明確指定的伺服器",
@@ -444,7 +444,7 @@
"client_confirm_delete": "您確定您想要刪除用戶端 \"{{key}}\" 嗎?", "client_confirm_delete": "您確定您想要刪除用戶端 \"{{key}}\" 嗎?",
"list_confirm_delete": "您確定您想要刪除該清單嗎?", "list_confirm_delete": "您確定您想要刪除該清單嗎?",
"auto_clients_title": "執行時期用戶端", "auto_clients_title": "執行時期用戶端",
"auto_clients_desc": "AdGuard Home 使用或可能使用的裝置的 IP 地址資訊。這些資訊來自多個來源,包括主機檔案、反向 DNS 等。", "auto_clients_desc": "未於可能仍然使用 AdGuard Home 的持續性用戶端之清單上的裝置",
"access_title": "存取設定", "access_title": "存取設定",
"access_desc": "於此您可配置用於 AdGuard Home DNS 伺服器之存取規則", "access_desc": "於此您可配置用於 AdGuard Home DNS 伺服器之存取規則",
"access_allowed_title": "已允許的用戶端", "access_allowed_title": "已允許的用戶端",
@@ -478,9 +478,7 @@
"setup_dns_notice": "為了使用 <1>DNS-over-HTTPS</1> 或 <1>DNS-over-TLS</1>,您需要在 AdGuard Home 設定裡<0>配置加密</0>。", "setup_dns_notice": "為了使用 <1>DNS-over-HTTPS</1> 或 <1>DNS-over-TLS</1>,您需要在 AdGuard Home 設定裡<0>配置加密</0>。",
"rewrite_added": "對於 \"{{key}}\" 之 DNS 改寫被成功地加入", "rewrite_added": "對於 \"{{key}}\" 之 DNS 改寫被成功地加入",
"rewrite_deleted": "對於 \"{{key}}\" 之 DNS 改寫被成功地刪除", "rewrite_deleted": "對於 \"{{key}}\" 之 DNS 改寫被成功地刪除",
"rewrite_updated": "DNS 重寫已成功更新",
"rewrite_add": "新增 DNS 改寫", "rewrite_add": "新增 DNS 改寫",
"rewrite_edit": "編輯 DNS 重寫",
"rewrite_not_found": "無已發現之 DNS 改寫", "rewrite_not_found": "無已發現之 DNS 改寫",
"rewrite_confirm_delete": "您確定您想要刪除對於 \"{{key}}\" 之 DNS 改寫嗎?", "rewrite_confirm_delete": "您確定您想要刪除對於 \"{{key}}\" 之 DNS 改寫嗎?",
"rewrite_desc": "允許輕易地配置自訂的 DNS 回應供特定的域名。", "rewrite_desc": "允許輕易地配置自訂的 DNS 回應供特定的域名。",

View File

@@ -38,29 +38,6 @@ export const addRewrite = (config) => async (dispatch) => {
} }
}; };
export const updateRewriteRequest = createAction('UPDATE_REWRITE_REQUEST');
export const updateRewriteFailure = createAction('UPDATE_REWRITE_FAILURE');
export const updateRewriteSuccess = createAction('UPDATE_REWRITE_SUCCESS');
/**
* @param {Object} config
* @param {string} config.target - current DNS rewrite value
* @param {string} config.update - updated DNS rewrite value
*/
export const updateRewrite = (config) => async (dispatch) => {
dispatch(updateRewriteRequest());
try {
await apiClient.updateRewrite(config);
dispatch(updateRewriteSuccess());
dispatch(toggleRewritesModal());
dispatch(getRewritesList());
dispatch(addSuccessToast(i18next.t('rewrite_updated', { key: config.domain })));
} catch (error) {
dispatch(addErrorToast({ error }));
dispatch(updateRewriteFailure());
}
};
export const deleteRewriteRequest = createAction('DELETE_REWRITE_REQUEST'); export const deleteRewriteRequest = createAction('DELETE_REWRITE_REQUEST');
export const deleteRewriteFailure = createAction('DELETE_REWRITE_FAILURE'); export const deleteRewriteFailure = createAction('DELETE_REWRITE_FAILURE');
export const deleteRewriteSuccess = createAction('DELETE_REWRITE_SUCCESS'); export const deleteRewriteSuccess = createAction('DELETE_REWRITE_SUCCESS');

View File

@@ -455,8 +455,6 @@ class Api {
REWRITE_ADD = { path: 'rewrite/add', method: 'POST' }; REWRITE_ADD = { path: 'rewrite/add', method: 'POST' };
REWRITE_UPDATE = { path: 'rewrite/update', method: 'PUT' };
REWRITE_DELETE = { path: 'rewrite/delete', method: 'POST' }; REWRITE_DELETE = { path: 'rewrite/delete', method: 'POST' };
getRewritesList() { getRewritesList() {
@@ -472,14 +470,6 @@ class Api {
return this.makeRequest(path, method, parameters); return this.makeRequest(path, method, parameters);
} }
updateRewrite(config) {
const { path, method } = this.REWRITE_UPDATE;
const parameters = {
data: config,
};
return this.makeRequest(path, method, parameters);
}
deleteRewrite(config) { deleteRewrite(config) {
const { path, method } = this.REWRITE_DELETE; const { path, method } = this.REWRITE_DELETE;
const parameters = { const parameters = {

View File

@@ -6,7 +6,7 @@ import { shallowEqual, useSelector } from 'react-redux';
import Card from '../ui/Card'; import Card from '../ui/Card';
import { formatNumber } from '../../helpers/helpers'; import { formatNumber } from '../../helpers/helpers';
import LogsSearchLink from '../ui/LogsSearchLink'; import LogsSearchLink from '../ui/LogsSearchLink';
import { RESPONSE_FILTER, DAY } from '../../helpers/constants'; import { RESPONSE_FILTER } from '../../helpers/constants';
import Tooltip from '../ui/Tooltip'; import Tooltip from '../ui/Tooltip';
const Row = ({ const Row = ({
@@ -54,12 +54,12 @@ const Counters = ({ refreshButton, subtitle }) => {
avgProcessingTime, avgProcessingTime,
} = useSelector((state) => state.stats, shallowEqual); } = useSelector((state) => state.stats, shallowEqual);
const { t } = useTranslation(); const { t } = useTranslation();
const days = interval / DAY;
const rows = [ const rows = [
{ {
label: 'dns_query', label: 'dns_query',
count: numDnsQueries, count: numDnsQueries,
tooltipTitle: days === 1 ? 'number_of_dns_query_24_hours' : t('number_of_dns_query_days', { count: days }), tooltipTitle: interval === 1 ? 'number_of_dns_query_24_hours' : t('number_of_dns_query_days', { count: interval }),
response_status: RESPONSE_FILTER.ALL.QUERY, response_status: RESPONSE_FILTER.ALL.QUERY,
}, },
{ {

View File

@@ -105,7 +105,6 @@ Form.propTypes = {
submitting: PropTypes.bool.isRequired, submitting: PropTypes.bool.isRequired,
processingAdd: PropTypes.bool.isRequired, processingAdd: PropTypes.bool.isRequired,
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
initialValues: PropTypes.object,
}; };
export default flow([ export default flow([

View File

@@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
import { Trans, withTranslation } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import ReactModal from 'react-modal'; import ReactModal from 'react-modal';
import { MODAL_TYPE } from '../../../helpers/constants';
import Form from './Form'; import Form from './Form';
const Modal = (props) => { const Modal = (props) => {
@@ -13,8 +12,6 @@ const Modal = (props) => {
toggleRewritesModal, toggleRewritesModal,
processingAdd, processingAdd,
processingDelete, processingDelete,
modalType,
currentRewrite,
} = props; } = props;
return ( return (
@@ -27,18 +24,13 @@ const Modal = (props) => {
<div className="modal-content"> <div className="modal-content">
<div className="modal-header"> <div className="modal-header">
<h4 className="modal-title"> <h4 className="modal-title">
{modalType === MODAL_TYPE.EDIT_REWRITE ? ( <Trans>rewrite_add</Trans>
<Trans>rewrite_edit</Trans>
) : (
<Trans>rewrite_add</Trans>
)}
</h4> </h4>
<button type="button" className="close" onClick={() => toggleRewritesModal()}> <button type="button" className="close" onClick={() => toggleRewritesModal()}>
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
</button> </button>
</div> </div>
<Form <Form
initialValues={{ ...currentRewrite }}
onSubmit={handleSubmit} onSubmit={handleSubmit}
toggleRewritesModal={toggleRewritesModal} toggleRewritesModal={toggleRewritesModal}
processingAdd={processingAdd} processingAdd={processingAdd}
@@ -55,8 +47,6 @@ Modal.propTypes = {
toggleRewritesModal: PropTypes.func.isRequired, toggleRewritesModal: PropTypes.func.isRequired,
processingAdd: PropTypes.bool.isRequired, processingAdd: PropTypes.bool.isRequired,
processingDelete: PropTypes.bool.isRequired, processingDelete: PropTypes.bool.isRequired,
modalType: PropTypes.string.isRequired,
currentRewrite: PropTypes.object,
}; };
export default withTranslation()(Modal); export default withTranslation()(Modal);

View File

@@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import { withTranslation } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import { sortIp } from '../../../helpers/helpers'; import { sortIp } from '../../../helpers/helpers';
import { MODAL_TYPE } from '../../../helpers/constants';
class Table extends Component { class Table extends Component {
cellWrap = ({ value }) => ( cellWrap = ({ value }) => (
@@ -32,44 +31,24 @@ class Table extends Component {
maxWidth: 100, maxWidth: 100,
sortable: false, sortable: false,
resizable: false, resizable: false,
Cell: (value) => { Cell: (value) => (
const currentRewrite = { <div className="logs__row logs__row--center">
answer: value.row.answer, <button
domain: value.row.domain, type="button"
}; className="btn btn-icon btn-icon--green btn-outline-secondary btn-sm"
onClick={() => this.props.handleDelete({
return ( answer: value.row.answer,
<div className="logs__row logs__row--center"> domain: value.row.domain,
<button })
type="button" }
className="btn btn-icon btn-outline-primary btn-sm mr-2" title={this.props.t('delete_table_action')}
onClick={() => { >
this.props.toggleRewritesModal({ <svg className="icons">
type: MODAL_TYPE.EDIT_REWRITE, <use xlinkHref="#delete" />
currentRewrite, </svg>
}); </button>
}} </div>
disabled={this.props.processingUpdate} ),
title={this.props.t('edit_table_action')}
>
<svg className="icons icon12">
<use xlinkHref="#edit" />
</svg>
</button>
<button
type="button"
className="btn btn-icon btn-outline-secondary btn-sm"
onClick={() => this.props.handleDelete(currentRewrite)}
title={this.props.t('delete_table_action')}
>
<svg className="icons">
<use xlinkHref="#delete" />
</svg>
</button>
</div>
);
},
}, },
]; ];
@@ -105,9 +84,7 @@ Table.propTypes = {
processing: PropTypes.bool.isRequired, processing: PropTypes.bool.isRequired,
processingAdd: PropTypes.bool.isRequired, processingAdd: PropTypes.bool.isRequired,
processingDelete: PropTypes.bool.isRequired, processingDelete: PropTypes.bool.isRequired,
processingUpdate: PropTypes.bool.isRequired,
handleDelete: PropTypes.func.isRequired, handleDelete: PropTypes.func.isRequired,
toggleRewritesModal: PropTypes.func.isRequired,
}; };
export default withTranslation()(Table); export default withTranslation()(Table);

View File

@@ -6,13 +6,16 @@ import Table from './Table';
import Modal from './Modal'; import Modal from './Modal';
import Card from '../../ui/Card'; import Card from '../../ui/Card';
import PageTitle from '../../ui/PageTitle'; import PageTitle from '../../ui/PageTitle';
import { MODAL_TYPE } from '../../../helpers/constants';
class Rewrites extends Component { class Rewrites extends Component {
componentDidMount() { componentDidMount() {
this.props.getRewritesList(); this.props.getRewritesList();
} }
handleSubmit = (values) => {
this.props.addRewrite(values);
};
handleDelete = (values) => { handleDelete = (values) => {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
if (window.confirm(this.props.t('rewrite_confirm_delete', { key: values.domain }))) { if (window.confirm(this.props.t('rewrite_confirm_delete', { key: values.domain }))) {
@@ -20,19 +23,6 @@ class Rewrites extends Component {
} }
}; };
handleSubmit = (values) => {
const { modalType, currentRewrite } = this.props.rewrites;
if (modalType === MODAL_TYPE.EDIT_REWRITE && currentRewrite) {
this.props.updateRewrite({
target: currentRewrite,
update: values,
});
} else {
this.props.addRewrite(values);
}
};
render() { render() {
const { const {
t, t,
@@ -46,9 +36,6 @@ class Rewrites extends Component {
processing, processing,
processingAdd, processingAdd,
processingDelete, processingDelete,
processingUpdate,
modalType,
currentRewrite,
} = rewrites; } = rewrites;
return ( return (
@@ -67,15 +54,13 @@ class Rewrites extends Component {
processing={processing} processing={processing}
processingAdd={processingAdd} processingAdd={processingAdd}
processingDelete={processingDelete} processingDelete={processingDelete}
processingUpdate={processingUpdate}
handleDelete={this.handleDelete} handleDelete={this.handleDelete}
toggleRewritesModal={toggleRewritesModal}
/> />
<button <button
type="button" type="button"
className="btn btn-success btn-standard mt-3" className="btn btn-success btn-standard mt-3"
onClick={() => toggleRewritesModal({ type: MODAL_TYPE.ADD_REWRITE })} onClick={() => toggleRewritesModal()}
disabled={processingAdd} disabled={processingAdd}
> >
<Trans>rewrite_add</Trans> <Trans>rewrite_add</Trans>
@@ -83,13 +68,10 @@ class Rewrites extends Component {
<Modal <Modal
isModalOpen={isModalOpen} isModalOpen={isModalOpen}
modalType={modalType}
toggleRewritesModal={toggleRewritesModal} toggleRewritesModal={toggleRewritesModal}
handleSubmit={this.handleSubmit} handleSubmit={this.handleSubmit}
processingAdd={processingAdd} processingAdd={processingAdd}
processingDelete={processingDelete} processingDelete={processingDelete}
processingUpdate={processingUpdate}
currentRewrite={currentRewrite}
/> />
</Fragment> </Fragment>
</Card> </Card>
@@ -104,7 +86,6 @@ Rewrites.propTypes = {
toggleRewritesModal: PropTypes.func.isRequired, toggleRewritesModal: PropTypes.func.isRequired,
addRewrite: PropTypes.func.isRequired, addRewrite: PropTypes.func.isRequired,
deleteRewrite: PropTypes.func.isRequired, deleteRewrite: PropTypes.func.isRequired,
updateRewrite: PropTypes.func.isRequired,
rewrites: PropTypes.object.isRequired, rewrites: PropTypes.object.isRequired,
}; };

View File

@@ -48,7 +48,6 @@ class Table extends Component {
Header: <Trans>list_url_table_header</Trans>, Header: <Trans>list_url_table_header</Trans>,
accessor: 'url', accessor: 'url',
minWidth: 180, minWidth: 180,
// eslint-disable-next-line react/prop-types
Cell: ({ value }) => ( Cell: ({ value }) => (
<div className="logs__row"> <div className="logs__row">
{isValidAbsolutePath(value) ? value {isValidAbsolutePath(value) ? value

View File

@@ -32,8 +32,6 @@ const ProtectionTimer = ({
}; };
ProtectionTimer.propTypes = { ProtectionTimer.propTypes = {
protectionDisabledDuration: PropTypes.number,
toggleProtectionSuccess: PropTypes.func.isRequired,
setProtectionTimerTime: PropTypes.func.isRequired, setProtectionTimerTime: PropTypes.func.isRequired,
}; };

View File

@@ -57,7 +57,7 @@ const ClientsTable = ({
}; };
const handleSubmit = (values) => { const handleSubmit = (values) => {
const config = { ...values }; const config = values;
if (values) { if (values) {
if (values.blocked_services) { if (values.blocked_services) {

View File

@@ -27,6 +27,7 @@ import {
} from '../../../helpers/constants'; } from '../../../helpers/constants';
import '../FormButton.css'; import '../FormButton.css';
const getIntervalTitle = (interval, t) => { const getIntervalTitle = (interval, t) => {
switch (interval) { switch (interval) {
case RETENTION_CUSTOM: case RETENTION_CUSTOM:

View File

@@ -7,6 +7,7 @@ import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
renderRadioField, renderRadioField,
toNumber, toNumber,

View File

@@ -1,4 +1,3 @@
/* eslint-disable react/no-unknown-property */
import React from 'react'; import React from 'react';
import './Icons.css'; import './Icons.css';

View File

@@ -3,7 +3,6 @@ import {
getRewritesList, getRewritesList,
addRewrite, addRewrite,
deleteRewrite, deleteRewrite,
updateRewrite,
toggleRewritesModal, toggleRewritesModal,
} from '../actions/rewrites'; } from '../actions/rewrites';
import Rewrites from '../components/Filters/Rewrites'; import Rewrites from '../components/Filters/Rewrites';
@@ -18,7 +17,6 @@ const mapDispatchToProps = {
getRewritesList, getRewritesList,
addRewrite, addRewrite,
deleteRewrite, deleteRewrite,
updateRewrite,
toggleRewritesModal, toggleRewritesModal,
}; };

View File

@@ -173,8 +173,6 @@ export const MODAL_TYPE = {
ADD_FILTERS: 'ADD_FILTERS', ADD_FILTERS: 'ADD_FILTERS',
EDIT_FILTERS: 'EDIT_FILTERS', EDIT_FILTERS: 'EDIT_FILTERS',
CHOOSE_FILTERING_LIST: 'CHOOSE_FILTERING_LIST', CHOOSE_FILTERING_LIST: 'CHOOSE_FILTERING_LIST',
ADD_REWRITE: 'ADD_REWRITE',
EDIT_REWRITE: 'EDIT_REWRITE',
}; };
export const CLIENT_ID = { export const CLIENT_ID = {

View File

@@ -64,6 +64,12 @@ export default {
"homepage": "https://github.com/MasterKia/PersianBlocker", "homepage": "https://github.com/MasterKia/PersianBlocker",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_19.txt" "source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_19.txt"
}, },
"ITA_filtri_dns": {
"name": "ITA: Filtri-DNS",
"categoryId": "regional",
"homepage": "https://filtri-dns.ga/",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_18.txt"
},
"KOR_list_kr": { "KOR_list_kr": {
"name": "KOR: List-KR DNS", "name": "KOR: List-KR DNS",
"categoryId": "regional", "categoryId": "regional",
@@ -94,12 +100,6 @@ export default {
"homepage": "https://github.com/DandelionSprout/adfilt", "homepage": "https://github.com/DandelionSprout/adfilt",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_13.txt" "source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_13.txt"
}, },
"POL_cert_polska_list_of_malicious_domains": {
"name": "POL: CERT Polska List of malicious domains",
"categoryId": "regional",
"homepage": "https://cert.pl/posts/2020/03/ostrzezenia_phishing/",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_41.txt"
},
"POL_polish_filters_for_pi_hole": { "POL_polish_filters_for_pi_hole": {
"name": "POL: Polish filters for Pi-hole", "name": "POL: Polish filters for Pi-hole",
"categoryId": "regional", "categoryId": "regional",
@@ -118,12 +118,6 @@ export default {
"homepage": "https://github.com/bkrucarci/turk-adlist", "homepage": "https://github.com/bkrucarci/turk-adlist",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_26.txt" "source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_26.txt"
}, },
"TUR_turkish_ad_hosts": {
"name": "TUR: Turkish Ad Hosts",
"categoryId": "regional",
"homepage": "https://github.com/symbuzzer/Turkish-Ad-Hosts",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_40.txt"
},
"VNM_abpvn": { "VNM_abpvn": {
"name": "VNM: ABPVN List", "name": "VNM: ABPVN List",
"categoryId": "regional", "categoryId": "regional",
@@ -160,20 +154,14 @@ export default {
"homepage": "https://github.com/DandelionSprout/adfilt", "homepage": "https://github.com/DandelionSprout/adfilt",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_12.txt" "source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_12.txt"
}, },
"dandelion_sprouts_anti_push_notifications": {
"name": "Dandelion Sprout's Anti Push Notifications",
"categoryId": "other",
"homepage": "https://github.com/DandelionSprout/adfilt",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_39.txt"
},
"dandelion_sprouts_game_console_adblock_list": { "dandelion_sprouts_game_console_adblock_list": {
"name": "Dandelion Sprout's Game Console Adblock List", "name": "Dandelion Sprout's Game Console Adblock List",
"categoryId": "other", "categoryId": "other",
"homepage": "https://github.com/DandelionSprout/adfilt", "homepage": "https://github.com/DandelionSprout/adfilt",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_6.txt" "source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_6.txt"
}, },
"hagezi_multinormal": { "hagezi_personal": {
"name": "HaGeZi Multi NORMAL", "name": "HaGeZi Personal Black \u0026 White",
"categoryId": "general", "categoryId": "general",
"homepage": "https://github.com/hagezi/dns-blocklists", "homepage": "https://github.com/hagezi/dns-blocklists",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_34.txt" "source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_34.txt"
@@ -226,12 +214,6 @@ export default {
"homepage": "https://github.com/durablenapkin/scamblocklist", "homepage": "https://github.com/durablenapkin/scamblocklist",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_10.txt" "source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_10.txt"
}, },
"shadowwhisperers_malware_list": {
"name": "ShadowWhisperer's Malware List",
"categoryId": "security",
"homepage": "https://github.com/ShadowWhisperer/BlockLists",
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_42.txt"
},
"staklerware_indicators_list": { "staklerware_indicators_list": {
"name": "Stalkerware Indicators List", "name": "Stalkerware Indicators List",
"categoryId": "security", "categoryId": "security",

View File

@@ -845,6 +845,7 @@ export const sortIp = (a, b) => {
} }
}; };
/** /**
* @param {number} filterId * @param {number} filterId
* @returns {string} * @returns {string}

File diff suppressed because it is too large Load Diff

View File

@@ -30,27 +30,7 @@ const rewrites = handleActions(
[actions.deleteRewriteFailure]: (state) => ({ ...state, processingDelete: false }), [actions.deleteRewriteFailure]: (state) => ({ ...state, processingDelete: false }),
[actions.deleteRewriteSuccess]: (state) => ({ ...state, processingDelete: false }), [actions.deleteRewriteSuccess]: (state) => ({ ...state, processingDelete: false }),
[actions.updateRewriteRequest]: (state) => ({ ...state, processingUpdate: true }), [actions.toggleRewritesModal]: (state) => {
[actions.updateRewriteFailure]: (state) => ({ ...state, processingUpdate: false }),
[actions.updateRewriteSuccess]: (state) => {
const newState = {
...state,
processingUpdate: false,
};
return newState;
},
[actions.toggleRewritesModal]: (state, { payload }) => {
if (payload) {
const newState = {
...state,
modalType: payload.type || '',
isModalOpen: !state.isModalOpen,
currentRewrite: payload.currentRewrite,
};
return newState;
}
const newState = { const newState = {
...state, ...state,
isModalOpen: !state.isModalOpen, isModalOpen: !state.isModalOpen,
@@ -62,10 +42,7 @@ const rewrites = handleActions(
processing: true, processing: true,
processingAdd: false, processingAdd: false,
processingDelete: false, processingDelete: false,
processingUpdate: false,
isModalOpen: false, isModalOpen: false,
modalType: '',
currentRewrite: {},
list: [], list: [],
}, },
); );

View File

@@ -1,6 +1,6 @@
# A docker file for scripts/make/build-docker.sh. # A docker file for scripts/make/build-docker.sh.
FROM alpine:3.18 FROM alpine:3.17
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION ARG VERSION
@@ -25,6 +25,8 @@ RUN apk --no-cache add ca-certificates libcap tzdata && \
mkdir -p /opt/adguardhome/conf /opt/adguardhome/work && \ mkdir -p /opt/adguardhome/conf /opt/adguardhome/work && \
chown -R nobody: /opt/adguardhome chown -R nobody: /opt/adguardhome
RUN apk --no-cache add tini
ARG DIST_DIR ARG DIST_DIR
ARG TARGETARCH ARG TARGETARCH
ARG TARGETOS ARG TARGETOS
@@ -41,19 +43,45 @@ RUN setcap 'cap_net_bind_service=+eip' /opt/adguardhome/AdGuardHome
# 68 : UDP : DHCP (client) # 68 : UDP : DHCP (client)
# 80 : TCP : HTTP (main) # 80 : TCP : HTTP (main)
# 443 : TCP, UDP : HTTPS, DNS-over-HTTPS (incl. HTTP/3), DNSCrypt (main) # 443 : TCP, UDP : HTTPS, DNS-over-HTTPS (incl. HTTP/3), DNSCrypt (main)
# 784 : UDP : DNS-over-QUIC (experimental)
# 853 : TCP, UDP : DNS-over-TLS, DNS-over-QUIC # 853 : TCP, UDP : DNS-over-TLS, DNS-over-QUIC
# 3000 : TCP, UDP : HTTP(S) (alt, incl. HTTP/3) # 3000 : TCP, UDP : HTTP(S) (alt, incl. HTTP/3)
# 3001 : TCP, UDP : HTTP(S) (beta, incl. HTTP/3)
# 5443 : TCP, UDP : DNSCrypt (alt) # 5443 : TCP, UDP : DNSCrypt (alt)
# 6060 : TCP : HTTP (pprof) # 6060 : TCP : HTTP (pprof)
EXPOSE 53/tcp 53/udp 67/udp 68/udp 80/tcp 443/tcp 443/udp 853/tcp\ # 8853 : UDP : DNS-over-QUIC (experimental)
853/udp 3000/tcp 3000/udp 5443/tcp 5443/udp 6060/tcp #
# TODO(a.garipov): Remove the old, non-standard 784 and 8853 ports for
# DNS-over-QUIC in a future release.
EXPOSE 53/tcp 53/udp 67/udp 68/udp 80/tcp 443/tcp 443/udp 784/udp\
853/tcp 853/udp 3000/tcp 3000/udp 5443/tcp\
5443/udp 6060/tcp 8853/udp
WORKDIR /opt/adguardhome/work WORKDIR /opt/adguardhome/work
ENTRYPOINT ["/opt/adguardhome/AdGuardHome"] # Install helpers for healthcheck.
COPY --chown=nobody:nogroup\
./${DIST_DIR}/docker/scripts\
/opt/adguardhome/scripts
HEALTHCHECK \
--interval=30s \
--timeout=10s \
--retries=3 \
CMD [ "/opt/adguardhome/scripts/healthcheck.sh" ]
# It seems that the healthckech script sometimes spawns zombie processes, so we
# need a way to handle them, since AdGuard Home doesn't know how to keep track
# of the processes delegated to it by the OS. Use tini as entry point because
# it needs the PID=1 to be the default parent for orphaned processes.
#
# See https://github.com/adguardTeam/adGuardHome/issues/3290.
ENTRYPOINT [ "/sbin/tini", "--" ]
CMD [ \ CMD [ \
"/opt/adguardhome/AdGuardHome", \
"--no-check-update", \ "--no-check-update", \
"-c", "/opt/adguardhome/conf/AdGuardHome.yaml", \ "-c", "/opt/adguardhome/conf/AdGuardHome.yaml", \
"-h", "0.0.0.0", \
"-w", "/opt/adguardhome/work" \ "-w", "/opt/adguardhome/work" \
] ]

29
docker/dns-bind.awk Normal file
View File

@@ -0,0 +1,29 @@
/^[^[:space:]]/ { is_dns = /^dns:/ }
/^[[:space:]]+bind_hosts:/ { if (is_dns) prev_line = FNR }
/^[[:space:]]+- .+/ {
if (FNR - prev_line == 1) {
addrs[$2] = true
prev_line = FNR
if ($2 == "0.0.0.0" || $2 == "'::'") {
# Drop all the other addresses.
delete addrs
addrs[""] = true
prev_line = -1
}
}
}
/^[[:space:]]+port:/ { if (is_dns) port = $2 }
END {
for (addr in addrs) {
if (match(addr, ":")) {
print "[" addr "]:" port
} else {
print addr ":" port
}
}
}

107
docker/healthcheck.sh Executable file
View File

@@ -0,0 +1,107 @@
#!/bin/sh
# AdGuard Home Docker healthcheck script
# Exit the script if a pipeline fails (-e), prevent accidental filename
# expansion (-f), and consider undefined variables as errors (-u).
set -e -f -u
# Function error_exit is an echo wrapper that writes to stderr and stops the
# script execution with code 1.
error_exit() {
echo "$1" 1>&2
exit 1
}
agh_dir="/opt/adguardhome"
readonly agh_dir
filename="${agh_dir}/conf/AdGuardHome.yaml"
readonly filename
if ! [ -f "$filename" ]
then
wget "http://127.0.0.1:3000" -O /dev/null -q || exit 1
exit 0
fi
help_dir="${agh_dir}/scripts"
readonly help_dir
# Parse web host
web_url="$( awk -f "${help_dir}/web-bind.awk" "$filename" )"
readonly web_url
if [ "$web_url" = '' ]
then
error_exit "no web bindings could be retrieved from $filename"
fi
# TODO(e.burkov): Deal with 0 port.
case "$web_url"
in
(*':0')
error_exit '0 in web port is not supported by healthcheck'
;;
(*)
# Go on.
;;
esac
# Parse DNS hosts
dns_hosts="$( awk -f "${help_dir}/dns-bind.awk" "$filename" )"
readonly dns_hosts
if [ "$dns_hosts" = '' ]
then
error_exit "no DNS bindings could be retrieved from $filename"
fi
first_dns="$( echo "$dns_hosts" | head -n 1 )"
readonly first_dns
# TODO(e.burkov): Deal with 0 port.
case "$first_dns"
in
(*':0')
error_exit '0 in DNS port is not supported by healthcheck'
;;
(*)
# Go on.
;;
esac
# Check
# Skip SSL certificate validation since there is no guarantee the container
# trusts the one used. It should be safe to drop the SSL validation since the
# current script intended to be used from inside the container and only checks
# the endpoint availability, ignoring the content of the response.
#
# See https://github.com/AdguardTeam/AdGuardHome/issues/5642.
wget --no-check-certificate "$web_url" -O /dev/null -q || exit 1
test_fqdn="healthcheck.adguardhome.test."
readonly test_fqdn
# The awk script currently returns only port prefixed with colon in case of
# unspecified address.
case "$first_dns"
in
(':'*)
nslookup -type=a "$test_fqdn" "127.0.0.1${first_dns}" > /dev/null ||\
nslookup -type=a "$test_fqdn" "[::1]${first_dns}" > /dev/null ||\
error_exit "nslookup failed for $host"
;;
(*)
echo "$dns_hosts" | while read -r host
do
nslookup -type=a "$test_fqdn" "$host" > /dev/null ||\
error_exit "nslookup failed for $host"
done
;;
esac

13
docker/web-bind.awk Normal file
View File

@@ -0,0 +1,13 @@
# Don't consider the HTTPS hostname since the enforced HTTPS redirection should
# work if the SSL check skipped. See file docker/healthcheck.sh.
/^bind_host:/ { host = $2 }
/^bind_port:/ { port = $2 }
END {
if (match(host, ":")) {
print "http://[" host "]:" port
} else {
print "http://" host ":" port
}
}

49
go.mod
View File

@@ -1,43 +1,39 @@
module github.com/AdguardTeam/AdGuardHome module github.com/AdguardTeam/AdGuardHome
go 1.20 go 1.19
require ( require (
github.com/AdguardTeam/dnsproxy v0.52.1-0.20230726165924-30c459b0cdef github.com/AdguardTeam/dnsproxy v0.49.1
github.com/AdguardTeam/golibs v0.13.6 github.com/AdguardTeam/golibs v0.13.2
github.com/AdguardTeam/urlfilter v0.16.1 github.com/AdguardTeam/urlfilter v0.16.1
github.com/NYTimes/gziphandler v1.1.1 github.com/NYTimes/gziphandler v1.1.1
github.com/ameshkov/dnscrypt/v2 v2.2.7 github.com/ameshkov/dnscrypt/v2 v2.2.7
github.com/bluele/gcache v0.0.2
github.com/digineo/go-ipset/v2 v2.2.1 github.com/digineo/go-ipset/v2 v2.2.1
github.com/dimfeld/httptreemux/v5 v5.5.0 github.com/dimfeld/httptreemux/v5 v5.5.0
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.6.0
github.com/go-ping/ping v1.1.0 github.com/go-ping/ping v1.1.0
github.com/google/go-cmp v0.5.9 github.com/google/go-cmp v0.5.9
github.com/google/gopacket v1.1.19 github.com/google/gopacket v1.1.19
github.com/google/renameio/v2 v2.0.0 github.com/google/renameio v1.0.1
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86
github.com/kardianos/service v1.2.2 github.com/kardianos/service v1.2.2
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
github.com/mdlayher/netlink v1.7.2 github.com/mdlayher/netlink v1.7.1
github.com/mdlayher/packet v1.1.2 github.com/mdlayher/packet v1.1.1
// TODO(a.garipov): This package is deprecated; find a new one or use our // TODO(a.garipov): This package is deprecated; find a new one or use our
// own code for that. Perhaps, use gopacket. // own code for that. Perhaps, use gopacket.
github.com/mdlayher/raw v0.1.0 github.com/mdlayher/raw v0.1.0
github.com/miekg/dns v1.1.55 github.com/miekg/dns v1.1.53
// TODO(a.garipov): Update to v0.37.0 once we update to Go 1.20. github.com/quic-go/quic-go v0.33.0
github.com/quic-go/quic-go v0.36.2 github.com/stretchr/testify v1.8.2
github.com/stretchr/testify v1.8.4
github.com/ti-mo/netfilter v0.5.0 github.com/ti-mo/netfilter v0.5.0
go.etcd.io/bbolt v1.3.7 go.etcd.io/bbolt v1.3.7
golang.org/x/crypto v0.11.0 golang.org/x/crypto v0.8.0
// TODO(a.garipov): Update after updating slices.Sort and friends to golang.org/x/exp v0.0.0-20230321023759-10a507213a29
// stdlib versions in dnsproxy and golibs in Go 1.20. golang.org/x/net v0.9.0
golang.org/x/exp v0.0.0-20230724220655-d98519c11495 golang.org/x/sys v0.7.0
golang.org/x/net v0.12.0
golang.org/x/sys v0.10.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
howett.net/plist v1.0.0 howett.net/plist v1.0.0
@@ -48,22 +44,23 @@ require (
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
github.com/ameshkov/dnsstamps v1.0.3 // indirect github.com/ameshkov/dnsstamps v1.0.3 // indirect
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 // indirect github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 // indirect
github.com/bluele/gcache v0.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/mock v1.6.0 // indirect github.com/golang/mock v1.6.0 // indirect
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect github.com/google/pprof v0.0.0-20230406165453-00490a63f317 // indirect
github.com/mdlayher/socket v0.4.1 // indirect github.com/mdlayher/socket v0.4.0 // indirect
github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/onsi/ginkgo/v2 v2.9.2 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect
golang.org/x/mod v0.12.0 // indirect golang.org/x/mod v0.10.0 // indirect
golang.org/x/sync v0.3.0 // indirect golang.org/x/sync v0.1.0 // indirect
golang.org/x/text v0.11.0 // indirect golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.11.0 // indirect golang.org/x/tools v0.8.0 // indirect
) )

131
go.sum
View File

@@ -1,9 +1,9 @@
github.com/AdguardTeam/dnsproxy v0.52.1-0.20230726165924-30c459b0cdef h1:3ZJieG+PV+wJEXLgUndW4yL9/7iubyipbDmA0w3sa7Y= github.com/AdguardTeam/dnsproxy v0.49.1 h1:JpStBK05uCgA3ldleaNLRmIwE9V7vRg7/kVJQSdnQYg=
github.com/AdguardTeam/dnsproxy v0.52.1-0.20230726165924-30c459b0cdef/go.mod h1:Jo2zeRe97Rxt3yikXc+fn0LdLtqCj0Xlyh1PNBj6bpM= github.com/AdguardTeam/dnsproxy v0.49.1/go.mod h1:Y7g7jRTd/u7+KJ/QvnGI2PCE8vnisp6EsW47/Sz0DZw=
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw=
github.com/AdguardTeam/golibs v0.13.6 h1:z/0Q25pRLdaQxtoxvfSaooz5mdv8wj0R8KREj54q8yQ= github.com/AdguardTeam/golibs v0.13.2 h1:BPASsyQKmb+b8VnvsNOHp7bKfcZl9Z+Z2UhPjOiupSc=
github.com/AdguardTeam/golibs v0.13.6/go.mod h1:hOtcb8dPfKcFjWTPA904hTA4dl1aWvzeebdJpE72IPk= github.com/AdguardTeam/golibs v0.13.2/go.mod h1:7ylQLv2Lqsc3UW3jHoITynYk6Y1tYtgEMkR09ppfsN8=
github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU= github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
github.com/AdguardTeam/urlfilter v0.16.1 h1:ZPi0rjqo8cQf2FVdzo6cqumNoHZx2KPXj2yZa1A5BBw= github.com/AdguardTeam/urlfilter v0.16.1 h1:ZPi0rjqo8cQf2FVdzo6cqumNoHZx2KPXj2yZa1A5BBw=
github.com/AdguardTeam/urlfilter v0.16.1/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI= github.com/AdguardTeam/urlfilter v0.16.1/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI=
@@ -31,9 +31,10 @@ 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/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 h1:p8jkiMrCuZ0CmhwYLcbNbl7DDo21fozhKHQ2PccwOFQ=
github.com/dimfeld/httptreemux/v5 v5.5.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw= github.com/dimfeld/httptreemux/v5 v5.5.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw=
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw= github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
@@ -44,59 +45,77 @@ github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= github.com/google/pprof v0.0.0-20230406165453-00490a63f317 h1:hFhpt7CTmR3DX+b4R19ydQFtofxT0Sv3QsKNMVQYTMQ=
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/pprof v0.0.0-20230406165453-00490a63f317/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8=
github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd h1:D772X7igTag7yKErVWAR7boXpOml3fqqBzH1wNaD/jk= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8 h1:Z72DOke2yOK0Ms4Z2LK1E1OrRJXOxSj5DllTz2FYTRg=
github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8/go.mod h1:m5WMe03WCvWcXjRnhvaAbAAXdCnu20J5P+mmH44ZzpE=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk= github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk=
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86/go.mod h1:aFAMtuldEgx/4q7iSGazk22+IcgvtiC+HIimFO9XlS8= github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86/go.mod h1:aFAMtuldEgx/4q7iSGazk22+IcgvtiC+HIimFO9XlS8=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 h1:2oDp6OOhLxQ9JBoUuysVz9UZ9uI6oLUbvAZu0x8o+vE= github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 h1:2oDp6OOhLxQ9JBoUuysVz9UZ9uI6oLUbvAZu0x8o+vE=
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og= github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og=
github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
github.com/mdlayher/netlink v1.7.1 h1:FdUaT/e33HjEXagwELR8R3/KL1Fq5x3G5jgHLp/BTmg=
github.com/mdlayher/netlink v1.7.1/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ=
github.com/mdlayher/packet v1.0.0/go.mod h1:eE7/ctqDhoiRhQ44ko5JZU2zxB88g+JH/6jmnjzPjOU= github.com/mdlayher/packet v1.0.0/go.mod h1:eE7/ctqDhoiRhQ44ko5JZU2zxB88g+JH/6jmnjzPjOU=
github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY= github.com/mdlayher/packet v1.1.1 h1:7Fv4OEMYqPl7//uBm04VgPpnSNi8fbBZznppgh6WMr8=
github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4= github.com/mdlayher/packet v1.1.1/go.mod h1:DRvYY5mH4M4lUqAnMg04E60U4fjUKMZ/4g2cHElZkKo=
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mdlayher/raw v0.1.0 h1:K4PFMVy+AFsp0Zdlrts7yNhxc/uXoPVHi9RzRvtZF2Y= 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/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.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -108,18 +127,24 @@ github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc8
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.36.2 h1:ZX/UNQ4gvpCv2RmwdbA6lrRjF6EBm5yZ7TMoT4NQVrA= github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
github.com/quic-go/quic-go v0.36.2/go.mod h1:zPetvwDlILVxt15n3hr3Gf/I3mDf7LpLKPhR4Ez0AZQ= github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
github.com/shirou/gopsutil/v3 v3.21.8 h1:nKct+uP0TV8DjjNiHanKf8SAuub+GNsbrOtM9Nl9biA= github.com/shirou/gopsutil/v3 v3.21.8 h1:nKct+uP0TV8DjjNiHanKf8SAuub+GNsbrOtM9Nl9biA=
github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ= github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/ti-mo/netfilter v0.2.0/go.mod h1:8GbBGsY/8fxtyIdfwy29JiluNcPK4K7wIT+x42ipqUU= github.com/ti-mo/netfilter v0.2.0/go.mod h1:8GbBGsY/8fxtyIdfwy29JiluNcPK4K7wIT+x42ipqUU=
github.com/ti-mo/netfilter v0.5.0 h1:MZmsUw5bFRecOb0AeyjOPxTHg4UxYzyEs0Ek/6Lxoy8= github.com/ti-mo/netfilter v0.5.0 h1:MZmsUw5bFRecOb0AeyjOPxTHg4UxYzyEs0Ek/6Lxoy8=
github.com/ti-mo/netfilter v0.5.0/go.mod h1:nt+8B9hx/QpqHr7Hazq+2qMCCA8u2OTkyc/7+U9ARz8= github.com/ti-mo/netfilter v0.5.0/go.mod h1:nt+8B9hx/QpqHr7Hazq+2qMCCA8u2OTkyc/7+U9ARz8=
@@ -127,6 +152,7 @@ github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
github.com/u-root/uio v0.0.0-20221213070652-c3537552635f/go.mod h1:IogEAUBXDEwX7oR/BMmCctShYs80ql4hF0ySdzGxf7E=
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 h1:YcojQL98T/OO+rybuzn2+5KrD5dBwXIvYBvQ2cD3Avg=
github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -134,36 +160,52 @@ go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/exp v0.0.0-20230724220655-d98519c11495 h1:zKGKw2WlGb8oPoRGqQ2PT8g2YoCN1w/YbbQjHXCdUWE= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/exp v0.0.0-20230724220655-d98519c11495/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/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-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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -177,22 +219,23 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/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.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -1,11 +1,10 @@
package aghio_test package aghio
import ( import (
"io" "io"
"strings" "strings"
"testing" "testing"
"github.com/AdguardTeam/AdGuardHome/internal/aghio"
"github.com/AdguardTeam/golibs/testutil" "github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -32,7 +31,7 @@ func TestLimitReader(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
_, err := aghio.LimitReader(nil, tc.n) _, err := LimitReader(nil, tc.n)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err) testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
}) })
} }
@@ -58,7 +57,7 @@ func TestLimitedReader_Read(t *testing.T) {
limit: 3, limit: 3,
want: 0, want: 0,
}, { }, {
err: &aghio.LimitReachedError{ err: &LimitReachedError{
Limit: 0, Limit: 0,
}, },
name: "limit_reached", name: "limit_reached",
@@ -75,7 +74,7 @@ func TestLimitedReader_Read(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
readCloser := io.NopCloser(strings.NewReader(tc.rStr)) readCloser := io.NopCloser(strings.NewReader(tc.rStr))
lreader, err := aghio.LimitReader(readCloser, tc.limit) lreader, err := LimitReader(readCloser, tc.limit)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, lreader) require.NotNil(t, lreader)
@@ -90,7 +89,7 @@ func TestLimitedReader_Read(t *testing.T) {
} }
func TestLimitedReader_LimitReachedError(t *testing.T) { func TestLimitedReader_LimitReachedError(t *testing.T) {
testutil.AssertErrorMsg(t, "attempted to read more than 0 bytes", &aghio.LimitReachedError{ testutil.AssertErrorMsg(t, "attempted to read more than 0 bytes", &LimitReachedError{
Limit: 0, Limit: 0,
}) })
} }

View File

@@ -1,43 +0,0 @@
package aghnet
import (
"fmt"
"strings"
"github.com/AdguardTeam/golibs/stringutil"
)
// NormalizeDomain returns a lowercased version of host without the final dot,
// unless host is ".", in which case it returns it unchanged. That is a special
// case that to allow matching queries like:
//
// dig IN NS '.'
func NormalizeDomain(host string) (norm string) {
if host == "." {
return host
}
return strings.ToLower(strings.TrimSuffix(host, "."))
}
// NewDomainNameSet returns nil and error, if list has duplicate or empty domain
// name. Otherwise returns a set, which contains domain names normalized using
// [NormalizeDomain].
func NewDomainNameSet(list []string) (set *stringutil.Set, err error) {
set = stringutil.NewSet()
for i, host := range list {
if host == "" {
return nil, fmt.Errorf("at index %d: hostname is empty", i)
}
host = NormalizeDomain(host)
if set.Has(host) {
return nil, fmt.Errorf("duplicate hostname %q at index %d", host, i)
}
set.Add(host)
}
return set, nil
}

View File

@@ -1,59 +0,0 @@
package aghnet_test
import (
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
)
func TestNewDomainNameSet(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
wantErrMsg string
in []string
}{{
name: "nil",
wantErrMsg: "",
in: nil,
}, {
name: "success",
wantErrMsg: "",
in: []string{
"Domain.Example",
".",
},
}, {
name: "dups",
wantErrMsg: `duplicate hostname "domain.example" at index 1`,
in: []string{
"Domain.Example",
"domain.example",
},
}, {
name: "bad_domain",
wantErrMsg: "at index 0: hostname is empty",
in: []string{
"",
},
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
set, err := aghnet.NewDomainNameSet(tc.in)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
if err != nil {
return
}
for _, host := range tc.in {
assert.Truef(t, set.Has(aghnet.NormalizeDomain(host)), "%q not matched", host)
}
})
}
}

View File

@@ -304,7 +304,7 @@ func tryConn6(req *dhcpv6.Message, c net.PacketConn) (ok, next bool, err error)
if !(response.Type() == dhcpv6.MessageTypeAdvertise && if !(response.Type() == dhcpv6.MessageTypeAdvertise &&
msg.TransactionID == req.TransactionID && msg.TransactionID == req.TransactionID &&
rcid != nil && rcid != nil &&
cid.Equal(rcid)) { cid.Equal(*rcid)) {
log.Debug("dhcpv6: received message from server doesn't match our request") log.Debug("dhcpv6: received message from server doesn't match our request")

View File

@@ -1,8 +1,12 @@
package aghnet package aghnet
import ( import (
"fmt"
"net/netip" "net/netip"
"strings" "strings"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/stringutil"
) )
// GenerateHostname generates the hostname from ip. In case of using IPv4 the // GenerateHostname generates the hostname from ip. In case of using IPv4 the
@@ -25,8 +29,32 @@ func GenerateHostname(ip netip.Addr) (hostname string) {
hostname = ip.StringExpanded() hostname = ip.StringExpanded()
if ip.Is4() { if ip.Is4() {
return strings.ReplaceAll(hostname, ".", "-") return strings.Replace(hostname, ".", "-", -1)
} }
return strings.ReplaceAll(hostname, ":", "-") return strings.Replace(hostname, ":", "-", -1)
}
// NewDomainNameSet returns nil and error, if list has duplicate or empty
// domain name. Otherwise returns a set, which contains non-FQDN domain names,
// and nil error.
func NewDomainNameSet(list []string) (set *stringutil.Set, err error) {
set = stringutil.NewSet()
for i, v := range list {
host := strings.ToLower(strings.TrimSuffix(v, "."))
// TODO(a.garipov): Think about ignoring empty (".") names in the
// future.
if host == "" {
return nil, errors.Error("host name is empty")
}
if set.Has(host) {
return nil, fmt.Errorf("duplicate host name %q at index %d", host, i)
}
set.Add(host)
}
return set, nil
} }

View File

@@ -56,20 +56,15 @@ func (rm *requestMatcher) MatchRequest(
) (res *urlfilter.DNSResult, ok bool) { ) (res *urlfilter.DNSResult, ok bool) {
switch req.DNSType { switch req.DNSType {
case dns.TypeA, dns.TypeAAAA, dns.TypePTR: case dns.TypeA, dns.TypeAAAA, dns.TypePTR:
log.Debug( log.Debug("%s: handling the request for %s", hostsContainerPrefix, req.Hostname)
"%s: handling %s request for %s",
hostsContainerPrefix,
dns.Type(req.DNSType),
req.Hostname,
)
rm.stateLock.RLock()
defer rm.stateLock.RUnlock()
return rm.engine.MatchRequest(req)
default: default:
return nil, false return nil, false
} }
rm.stateLock.RLock()
defer rm.stateLock.RUnlock()
return rm.engine.MatchRequest(req)
} }
// Translate returns the source hosts-syntax rule for the generated dnsrewrite // Translate returns the source hosts-syntax rule for the generated dnsrewrite
@@ -101,8 +96,6 @@ const hostsContainerPrefix = "hosts container"
// HostsContainer stores the relevant hosts database provided by the OS and // HostsContainer stores the relevant hosts database provided by the OS and
// processes both A/AAAA and PTR DNS requests for those. // processes both A/AAAA and PTR DNS requests for those.
//
// TODO(e.burkov): Improve API and move to golibs.
type HostsContainer struct { type HostsContainer struct {
// requestMatcher matches the requests and translates the rules. It's // requestMatcher matches the requests and translates the rules. It's
// embedded to implement MatchRequest and Translate for *HostsContainer. // embedded to implement MatchRequest and Translate for *HostsContainer.
@@ -141,9 +134,9 @@ type HostsRecord struct {
Canonical string Canonical string
} }
// Equal returns true if all fields of rec are equal to field in other or they // equal returns true if all fields of rec are equal to field in other or they
// both are nil. // both are nil.
func (rec *HostsRecord) Equal(other *HostsRecord) (ok bool) { func (rec *HostsRecord) equal(other *HostsRecord) (ok bool) {
if rec == nil { if rec == nil {
return other == nil return other == nil
} else if other == nil { } else if other == nil {
@@ -495,7 +488,7 @@ func (hc *HostsContainer) refresh() (err error) {
} }
// hc.last is nil on the first refresh, so let that one through. // hc.last is nil on the first refresh, so let that one through.
if hc.last != nil && maps.EqualFunc(hp.table, hc.last, (*HostsRecord).Equal) { if hc.last != nil && maps.EqualFunc(hp.table, hc.last, (*HostsRecord).equal) {
log.Debug("%s: no changes detected", hostsContainerPrefix) log.Debug("%s: no changes detected", hostsContainerPrefix)
return nil return nil

View File

@@ -1,144 +0,0 @@
package aghnet
import (
"io/fs"
"net/netip"
"path"
"testing"
"testing/fstest"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil/fakefs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const nl = "\n"
func TestHostsContainer_PathsToPatterns(t *testing.T) {
gsfs := fstest.MapFS{
"dir_0/file_1": &fstest.MapFile{Data: []byte{1}},
"dir_0/file_2": &fstest.MapFile{Data: []byte{2}},
"dir_0/dir_1/file_3": &fstest.MapFile{Data: []byte{3}},
}
testCases := []struct {
name string
paths []string
want []string
}{{
name: "no_paths",
paths: nil,
want: nil,
}, {
name: "single_file",
paths: []string{"dir_0/file_1"},
want: []string{"dir_0/file_1"},
}, {
name: "several_files",
paths: []string{"dir_0/file_1", "dir_0/file_2"},
want: []string{"dir_0/file_1", "dir_0/file_2"},
}, {
name: "whole_dir",
paths: []string{"dir_0"},
want: []string{"dir_0/*"},
}, {
name: "file_and_dir",
paths: []string{"dir_0/file_1", "dir_0/dir_1"},
want: []string{"dir_0/file_1", "dir_0/dir_1/*"},
}, {
name: "non-existing",
paths: []string{path.Join("dir_0", "file_3")},
want: nil,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
patterns, err := pathsToPatterns(gsfs, tc.paths)
require.NoError(t, err)
assert.Equal(t, tc.want, patterns)
})
}
t.Run("bad_file", func(t *testing.T) {
const errStat errors.Error = "bad file"
badFS := &fakefs.StatFS{
OnOpen: func(_ string) (f fs.File, err error) { panic("not implemented") },
OnStat: func(name string) (fi fs.FileInfo, err error) {
return nil, errStat
},
}
_, err := pathsToPatterns(badFS, []string{""})
assert.ErrorIs(t, err, errStat)
})
}
func TestUniqueRules_ParseLine(t *testing.T) {
ip := netutil.IPv4Localhost()
ipStr := ip.String()
testCases := []struct {
name string
line string
wantIP netip.Addr
wantHosts []string
}{{
name: "simple",
line: ipStr + ` hostname`,
wantIP: ip,
wantHosts: []string{"hostname"},
}, {
name: "aliases",
line: ipStr + ` hostname alias`,
wantIP: ip,
wantHosts: []string{"hostname", "alias"},
}, {
name: "invalid_line",
line: ipStr,
wantIP: netip.Addr{},
wantHosts: nil,
}, {
name: "invalid_line_hostname",
line: ipStr + ` # hostname`,
wantIP: ip,
wantHosts: nil,
}, {
name: "commented_aliases",
line: ipStr + ` hostname # alias`,
wantIP: ip,
wantHosts: []string{"hostname"},
}, {
name: "whole_comment",
line: `# ` + ipStr + ` hostname`,
wantIP: netip.Addr{},
wantHosts: nil,
}, {
name: "partial_comment",
line: ipStr + ` host#name`,
wantIP: ip,
wantHosts: []string{"host"},
}, {
name: "empty",
line: ``,
wantIP: netip.Addr{},
wantHosts: nil,
}, {
name: "bad_hosts",
line: ipStr + ` bad..host bad._tld empty.tld. ok.host`,
wantIP: ip,
wantHosts: []string{"ok.host"},
}}
for _, tc := range testCases {
hp := hostsParser{}
t.Run(tc.name, func(t *testing.T) {
got, hosts := hp.parseLine(tc.line)
assert.Equal(t, tc.wantIP, got)
assert.Equal(t, tc.wantHosts, hosts)
})
}
}

View File

@@ -1,7 +1,9 @@
package aghnet_test package aghnet
import ( import (
"io/fs"
"net" "net"
"net/netip"
"path" "path"
"strings" "strings"
"sync/atomic" "sync/atomic"
@@ -10,7 +12,6 @@ import (
"time" "time"
"github.com/AdguardTeam/AdGuardHome/internal/aghchan" "github.com/AdguardTeam/AdGuardHome/internal/aghchan"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/AdGuardHome/internal/aghtest"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/netutil"
@@ -23,7 +24,10 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const nl = "\n" const (
nl = "\n"
sp = " "
)
func TestNewHostsContainer(t *testing.T) { func TestNewHostsContainer(t *testing.T) {
const dirname = "dir" const dirname = "dir"
@@ -44,11 +48,11 @@ func TestNewHostsContainer(t *testing.T) {
name: "one_file", name: "one_file",
paths: []string{p}, paths: []string{p},
}, { }, {
wantErr: aghnet.ErrNoHostsPaths, wantErr: ErrNoHostsPaths,
name: "no_files", name: "no_files",
paths: []string{}, paths: []string{},
}, { }, {
wantErr: aghnet.ErrNoHostsPaths, wantErr: ErrNoHostsPaths,
name: "non-existent_file", name: "non-existent_file",
paths: []string{path.Join(dirname, filename+"2")}, paths: []string{path.Join(dirname, filename+"2")},
}, { }, {
@@ -73,7 +77,7 @@ func TestNewHostsContainer(t *testing.T) {
return eventsCh return eventsCh
} }
hc, err := aghnet.NewHostsContainer(0, testFS, &aghtest.FSWatcher{ hc, err := NewHostsContainer(0, testFS, &aghtest.FSWatcher{
OnEvents: onEvents, OnEvents: onEvents,
OnAdd: onAdd, OnAdd: onAdd,
OnClose: func() (err error) { return nil }, OnClose: func() (err error) { return nil },
@@ -99,7 +103,7 @@ func TestNewHostsContainer(t *testing.T) {
t.Run("nil_fs", func(t *testing.T) { t.Run("nil_fs", func(t *testing.T) {
require.Panics(t, func() { require.Panics(t, func() {
_, _ = aghnet.NewHostsContainer(0, nil, &aghtest.FSWatcher{ _, _ = NewHostsContainer(0, nil, &aghtest.FSWatcher{
// Those shouldn't panic. // Those shouldn't panic.
OnEvents: func() (e <-chan struct{}) { return nil }, OnEvents: func() (e <-chan struct{}) { return nil },
OnAdd: func(name string) (err error) { return nil }, OnAdd: func(name string) (err error) { return nil },
@@ -110,7 +114,7 @@ func TestNewHostsContainer(t *testing.T) {
t.Run("nil_watcher", func(t *testing.T) { t.Run("nil_watcher", func(t *testing.T) {
require.Panics(t, func() { require.Panics(t, func() {
_, _ = aghnet.NewHostsContainer(0, testFS, nil, p) _, _ = NewHostsContainer(0, testFS, nil, p)
}) })
}) })
@@ -123,7 +127,7 @@ func TestNewHostsContainer(t *testing.T) {
OnClose: func() (err error) { return nil }, OnClose: func() (err error) { return nil },
} }
hc, err := aghnet.NewHostsContainer(0, testFS, errWatcher, p) hc, err := NewHostsContainer(0, testFS, errWatcher, p)
require.ErrorIs(t, err, errOnAdd) require.ErrorIs(t, err, errOnAdd)
assert.Nil(t, hc) assert.Nil(t, hc)
@@ -154,11 +158,11 @@ func TestHostsContainer_refresh(t *testing.T) {
OnClose: func() (err error) { return nil }, OnClose: func() (err error) { return nil },
} }
hc, err := aghnet.NewHostsContainer(0, testFS, w, "dir") hc, err := NewHostsContainer(0, testFS, w, "dir")
require.NoError(t, err) require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, hc.Close) testutil.CleanupAndRequireSuccess(t, hc.Close)
checkRefresh := func(t *testing.T, want *aghnet.HostsRecord) { checkRefresh := func(t *testing.T, want *HostsRecord) {
t.Helper() t.Helper()
upd, ok := aghchan.MustReceive(hc.Upd(), 1*time.Second) upd, ok := aghchan.MustReceive(hc.Upd(), 1*time.Second)
@@ -171,11 +175,11 @@ func TestHostsContainer_refresh(t *testing.T) {
require.True(t, ok) require.True(t, ok)
require.NotNil(t, rec) require.NotNil(t, rec)
assert.Truef(t, rec.Equal(want), "%+v != %+v", rec, want) assert.Truef(t, rec.equal(want), "%+v != %+v", rec, want)
} }
t.Run("initial_refresh", func(t *testing.T) { t.Run("initial_refresh", func(t *testing.T) {
checkRefresh(t, &aghnet.HostsRecord{ checkRefresh(t, &HostsRecord{
Aliases: stringutil.NewSet(), Aliases: stringutil.NewSet(),
Canonical: "hostname", Canonical: "hostname",
}) })
@@ -185,7 +189,7 @@ func TestHostsContainer_refresh(t *testing.T) {
testFS["dir/file2"] = &fstest.MapFile{Data: []byte(ipStr + ` alias` + nl)} testFS["dir/file2"] = &fstest.MapFile{Data: []byte(ipStr + ` alias` + nl)}
eventsCh <- event{} eventsCh <- event{}
checkRefresh(t, &aghnet.HostsRecord{ checkRefresh(t, &HostsRecord{
Aliases: stringutil.NewSet("alias"), Aliases: stringutil.NewSet("alias"),
Canonical: "hostname", Canonical: "hostname",
}) })
@@ -224,6 +228,66 @@ func TestHostsContainer_refresh(t *testing.T) {
}) })
} }
func TestHostsContainer_PathsToPatterns(t *testing.T) {
gsfs := fstest.MapFS{
"dir_0/file_1": &fstest.MapFile{Data: []byte{1}},
"dir_0/file_2": &fstest.MapFile{Data: []byte{2}},
"dir_0/dir_1/file_3": &fstest.MapFile{Data: []byte{3}},
}
testCases := []struct {
name string
paths []string
want []string
}{{
name: "no_paths",
paths: nil,
want: nil,
}, {
name: "single_file",
paths: []string{"dir_0/file_1"},
want: []string{"dir_0/file_1"},
}, {
name: "several_files",
paths: []string{"dir_0/file_1", "dir_0/file_2"},
want: []string{"dir_0/file_1", "dir_0/file_2"},
}, {
name: "whole_dir",
paths: []string{"dir_0"},
want: []string{"dir_0/*"},
}, {
name: "file_and_dir",
paths: []string{"dir_0/file_1", "dir_0/dir_1"},
want: []string{"dir_0/file_1", "dir_0/dir_1/*"},
}, {
name: "non-existing",
paths: []string{path.Join("dir_0", "file_3")},
want: nil,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
patterns, err := pathsToPatterns(gsfs, tc.paths)
require.NoError(t, err)
assert.Equal(t, tc.want, patterns)
})
}
t.Run("bad_file", func(t *testing.T) {
const errStat errors.Error = "bad file"
badFS := &aghtest.StatFS{
OnStat: func(name string) (fs.FileInfo, error) {
return nil, errStat
},
}
_, err := pathsToPatterns(badFS, []string{""})
assert.ErrorIs(t, err, errStat)
})
}
func TestHostsContainer_Translate(t *testing.T) { func TestHostsContainer_Translate(t *testing.T) {
stubWatcher := aghtest.FSWatcher{ stubWatcher := aghtest.FSWatcher{
OnEvents: func() (e <-chan struct{}) { return nil }, OnEvents: func() (e <-chan struct{}) { return nil },
@@ -233,7 +297,7 @@ func TestHostsContainer_Translate(t *testing.T) {
require.NoError(t, fstest.TestFS(testdata, "etc_hosts")) require.NoError(t, fstest.TestFS(testdata, "etc_hosts"))
hc, err := aghnet.NewHostsContainer(0, testdata, &stubWatcher, "etc_hosts") hc, err := NewHostsContainer(0, testdata, &stubWatcher, "etc_hosts")
require.NoError(t, err) require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, hc.Close) testutil.CleanupAndRequireSuccess(t, hc.Close)
@@ -463,7 +527,7 @@ func TestHostsContainer(t *testing.T) {
OnClose: func() (err error) { return nil }, OnClose: func() (err error) { return nil },
} }
hc, err := aghnet.NewHostsContainer(listID, testdata, &stubWatcher, "etc_hosts") hc, err := NewHostsContainer(listID, testdata, &stubWatcher, "etc_hosts")
require.NoError(t, err) require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, hc.Close) testutil.CleanupAndRequireSuccess(t, hc.Close)
@@ -494,3 +558,69 @@ func TestHostsContainer(t *testing.T) {
}) })
} }
} }
func TestUniqueRules_ParseLine(t *testing.T) {
ip := netutil.IPv4Localhost()
ipStr := ip.String()
testCases := []struct {
name string
line string
wantIP netip.Addr
wantHosts []string
}{{
name: "simple",
line: ipStr + ` hostname`,
wantIP: ip,
wantHosts: []string{"hostname"},
}, {
name: "aliases",
line: ipStr + ` hostname alias`,
wantIP: ip,
wantHosts: []string{"hostname", "alias"},
}, {
name: "invalid_line",
line: ipStr,
wantIP: netip.Addr{},
wantHosts: nil,
}, {
name: "invalid_line_hostname",
line: ipStr + ` # hostname`,
wantIP: ip,
wantHosts: nil,
}, {
name: "commented_aliases",
line: ipStr + ` hostname # alias`,
wantIP: ip,
wantHosts: []string{"hostname"},
}, {
name: "whole_comment",
line: `# ` + ipStr + ` hostname`,
wantIP: netip.Addr{},
wantHosts: nil,
}, {
name: "partial_comment",
line: ipStr + ` host#name`,
wantIP: ip,
wantHosts: []string{"host"},
}, {
name: "empty",
line: ``,
wantIP: netip.Addr{},
wantHosts: nil,
}, {
name: "bad_hosts",
line: ipStr + ` bad..host bad._tld empty.tld. ok.host`,
wantIP: ip,
wantHosts: []string{"ok.host"},
}}
for _, tc := range testCases {
hp := hostsParser{}
t.Run(tc.name, func(t *testing.T) {
got, hosts := hp.parseLine(tc.line)
assert.Equal(t, tc.wantIP, got)
assert.Equal(t, tc.wantHosts, hosts)
})
}
}

View File

@@ -0,0 +1,17 @@
//go:build windows
package aghnet
import (
"net"
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
)
// listenPacketReusable announces on the local network address additionally
// configuring the socket to have a reusable binding.
func listenPacketReusable(_, _, _ string) (c net.PacketConn, err error) {
// TODO(e.burkov): Check if we are able to control sockets on Windows
// in the same way as on Unix.
return nil, aghos.Unsupported("listening packet reusable")
}

View File

@@ -3,7 +3,6 @@ package aghnet
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@@ -16,10 +15,6 @@ import (
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
) )
// DialContextFunc is the semantic alias for dialing functions, such as
// [http.Transport.DialContext].
type DialContextFunc = func(ctx context.Context, network, addr string) (conn net.Conn, err error)
// Variables and functions to substitute in tests. // Variables and functions to substitute in tests.
var ( var (
// aghosRunCommand is the function to run shell commands. // aghosRunCommand is the function to run shell commands.

View File

@@ -5,9 +5,9 @@ import (
"testing" "testing"
"testing/fstest" "testing/fstest"
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/testutil" "github.com/AdguardTeam/golibs/testutil"
"github.com/AdguardTeam/golibs/testutil/fakefs"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -118,7 +118,7 @@ func TestIfaceSetStaticIP(t *testing.T) {
Data: []byte(`nameserver 1.1.1.1`), Data: []byte(`nameserver 1.1.1.1`),
}, },
} }
panicFsys := &fakefs.FS{ panicFsys := &aghtest.FS{
OnOpen: func(name string) (fs.File, error) { panic("not implemented") }, OnOpen: func(name string) (fs.File, error) { panic("not implemented") },
} }

View File

@@ -1,334 +0,0 @@
package aghnet
import (
"bytes"
"encoding/json"
"fmt"
"io/fs"
"net"
"net/netip"
"os"
"strings"
"testing"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// testdata is the filesystem containing data for testing the package.
var testdata fs.FS = os.DirFS("./testdata")
// substRootDirFS replaces the aghos.RootDirFS function used throughout the
// package with fsys for tests ran under t.
func substRootDirFS(t testing.TB, fsys fs.FS) {
t.Helper()
prev := rootDirFS
t.Cleanup(func() { rootDirFS = prev })
rootDirFS = fsys
}
// RunCmdFunc is the signature of aghos.RunCommand function.
type RunCmdFunc func(cmd string, args ...string) (code int, out []byte, err error)
// substShell replaces the the aghos.RunCommand function used throughout the
// package with rc for tests ran under t.
func substShell(t testing.TB, rc RunCmdFunc) {
t.Helper()
prev := aghosRunCommand
t.Cleanup(func() { aghosRunCommand = prev })
aghosRunCommand = rc
}
// mapShell is a substitution of aghos.RunCommand that maps the command to it's
// execution result. It's only needed to simplify testing.
//
// TODO(e.burkov): Perhaps put all the shell interactions behind an interface.
type mapShell map[string]struct {
err error
out string
code int
}
// theOnlyCmd returns mapShell that only handles a single command and arguments
// combination from cmd.
func theOnlyCmd(cmd string, code int, out string, err error) (s mapShell) {
return mapShell{cmd: {code: code, out: out, err: err}}
}
// RunCmd is a RunCmdFunc handled by s.
func (s mapShell) RunCmd(cmd string, args ...string) (code int, out []byte, err error) {
key := strings.Join(append([]string{cmd}, args...), " ")
ret, ok := s[key]
if !ok {
return 0, nil, fmt.Errorf("unexpected shell command %q", key)
}
return ret.code, []byte(ret.out), ret.err
}
// ifaceAddrsFunc is the signature of net.InterfaceAddrs function.
type ifaceAddrsFunc func() (ifaces []net.Addr, err error)
// substNetInterfaceAddrs replaces the the net.InterfaceAddrs function used
// throughout the package with f for tests ran under t.
func substNetInterfaceAddrs(t *testing.T, f ifaceAddrsFunc) {
t.Helper()
prev := netInterfaceAddrs
t.Cleanup(func() { netInterfaceAddrs = prev })
netInterfaceAddrs = f
}
func TestGatewayIP(t *testing.T) {
const ifaceName = "ifaceName"
const cmd = "ip route show dev " + ifaceName
testCases := []struct {
shell mapShell
want netip.Addr
name string
}{{
shell: theOnlyCmd(cmd, 0, `default via 1.2.3.4 onlink`, nil),
want: netip.MustParseAddr("1.2.3.4"),
name: "success_v4",
}, {
shell: theOnlyCmd(cmd, 0, `default via ::ffff onlink`, nil),
want: netip.MustParseAddr("::ffff"),
name: "success_v6",
}, {
shell: theOnlyCmd(cmd, 0, `non-default via 1.2.3.4 onlink`, nil),
want: netip.Addr{},
name: "bad_output",
}, {
shell: theOnlyCmd(cmd, 0, "", errors.Error("can't run command")),
want: netip.Addr{},
name: "err_runcmd",
}, {
shell: theOnlyCmd(cmd, 1, "", nil),
want: netip.Addr{},
name: "bad_code",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
substShell(t, tc.shell.RunCmd)
assert.Equal(t, tc.want, GatewayIP(ifaceName))
})
}
}
func TestInterfaceByIP(t *testing.T) {
ifaces, err := GetValidNetInterfacesForWeb()
require.NoError(t, err)
require.NotEmpty(t, ifaces)
for _, iface := range ifaces {
t.Run(iface.Name, func(t *testing.T) {
require.NotEmpty(t, iface.Addresses)
for _, ip := range iface.Addresses {
ifaceName := InterfaceByIP(ip)
require.Equal(t, iface.Name, ifaceName)
}
})
}
}
func TestBroadcastFromIPNet(t *testing.T) {
known4 := netip.MustParseAddr("192.168.0.1")
fullBroadcast4 := netip.MustParseAddr("255.255.255.255")
known6 := netip.MustParseAddr("102:304:506:708:90a:b0c:d0e:f10")
testCases := []struct {
pref netip.Prefix
want netip.Addr
name string
}{{
pref: netip.PrefixFrom(known4, 0),
want: fullBroadcast4,
name: "full",
}, {
pref: netip.PrefixFrom(known4, 20),
want: netip.MustParseAddr("192.168.15.255"),
name: "full",
}, {
pref: netip.PrefixFrom(known6, netutil.IPv6BitLen),
want: known6,
name: "ipv6_no_mask",
}, {
pref: netip.PrefixFrom(known4, netutil.IPv4BitLen),
want: known4,
name: "ipv4_no_mask",
}, {
pref: netip.PrefixFrom(netip.IPv4Unspecified(), 0),
want: fullBroadcast4,
name: "unspecified",
}, {
pref: netip.Prefix{},
want: netip.Addr{},
name: "invalid",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
assert.Equal(t, tc.want, BroadcastFromPref(tc.pref))
})
}
}
func TestCheckPort(t *testing.T) {
laddr := netip.AddrPortFrom(netutil.IPv4Localhost(), 0)
t.Run("tcp_bound", func(t *testing.T) {
l, err := net.Listen("tcp", laddr.String())
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, l.Close)
ipp := testutil.RequireTypeAssert[*net.TCPAddr](t, l.Addr()).AddrPort()
require.Equal(t, laddr.Addr(), ipp.Addr())
require.NotZero(t, ipp.Port())
err = CheckPort("tcp", ipp)
target := &net.OpError{}
require.ErrorAs(t, err, &target)
assert.Equal(t, "listen", target.Op)
})
t.Run("udp_bound", func(t *testing.T) {
conn, err := net.ListenPacket("udp", laddr.String())
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, conn.Close)
ipp := testutil.RequireTypeAssert[*net.UDPAddr](t, conn.LocalAddr()).AddrPort()
require.Equal(t, laddr.Addr(), ipp.Addr())
require.NotZero(t, ipp.Port())
err = CheckPort("udp", ipp)
target := &net.OpError{}
require.ErrorAs(t, err, &target)
assert.Equal(t, "listen", target.Op)
})
t.Run("bad_network", func(t *testing.T) {
err := CheckPort("bad_network", netip.AddrPortFrom(netip.Addr{}, 0))
assert.NoError(t, err)
})
t.Run("can_bind", func(t *testing.T) {
err := CheckPort("udp", netip.AddrPortFrom(netip.IPv4Unspecified(), 0))
assert.NoError(t, err)
})
}
func TestCollectAllIfacesAddrs(t *testing.T) {
testCases := []struct {
name string
wantErrMsg string
addrs []net.Addr
wantAddrs []string
}{{
name: "success",
wantErrMsg: ``,
addrs: []net.Addr{&net.IPNet{
IP: net.IP{1, 2, 3, 4},
Mask: net.CIDRMask(24, netutil.IPv4BitLen),
}, &net.IPNet{
IP: net.IP{4, 3, 2, 1},
Mask: net.CIDRMask(16, netutil.IPv4BitLen),
}},
wantAddrs: []string{"1.2.3.4", "4.3.2.1"},
}, {
name: "not_cidr",
wantErrMsg: `parsing cidr: invalid CIDR address: 1.2.3.4`,
addrs: []net.Addr{&net.IPAddr{
IP: net.IP{1, 2, 3, 4},
}},
wantAddrs: nil,
}, {
name: "empty",
wantErrMsg: ``,
addrs: []net.Addr{},
wantAddrs: nil,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
substNetInterfaceAddrs(t, func() ([]net.Addr, error) { return tc.addrs, nil })
addrs, err := CollectAllIfacesAddrs()
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
assert.Equal(t, tc.wantAddrs, addrs)
})
}
t.Run("internal_error", func(t *testing.T) {
const errAddrs errors.Error = "can't get addresses"
const wantErrMsg string = `getting interfaces addresses: ` + string(errAddrs)
substNetInterfaceAddrs(t, func() ([]net.Addr, error) { return nil, errAddrs })
_, err := CollectAllIfacesAddrs()
testutil.AssertErrorMsg(t, wantErrMsg, err)
})
}
func TestIsAddrInUse(t *testing.T) {
t.Run("addr_in_use", func(t *testing.T) {
l, err := net.Listen("tcp", "0.0.0.0:0")
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, l.Close)
_, err = net.Listen(l.Addr().Network(), l.Addr().String())
assert.True(t, IsAddrInUse(err))
})
t.Run("another", func(t *testing.T) {
const anotherErr errors.Error = "not addr in use"
assert.False(t, IsAddrInUse(anotherErr))
})
}
func TestNetInterface_MarshalJSON(t *testing.T) {
const want = `{` +
`"hardware_address":"aa:bb:cc:dd:ee:ff",` +
`"flags":"up|multicast",` +
`"ip_addresses":["1.2.3.4","aaaa::1"],` +
`"name":"iface0",` +
`"mtu":1500` +
`}` + "\n"
ip4, ok := netip.AddrFromSlice([]byte{1, 2, 3, 4})
require.True(t, ok)
ip6, ok := netip.AddrFromSlice([]byte{0xAA, 0xAA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
require.True(t, ok)
net4 := netip.PrefixFrom(ip4, 24)
net6 := netip.PrefixFrom(ip6, 8)
iface := &NetInterface{
Addresses: []netip.Addr{ip4, ip6},
Subnets: []netip.Prefix{net4, net6},
Name: "iface0",
HardwareAddr: net.HardwareAddr{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
Flags: net.FlagUp | net.FlagMulticast,
MTU: 1500,
}
b := &bytes.Buffer{}
err := json.NewEncoder(b).Encode(iface)
require.NoError(t, err)
assert.Equal(t, want, b.String())
}

View File

@@ -14,7 +14,7 @@ import (
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/golibs/stringutil"
"github.com/google/renameio/v2/maybe" "github.com/google/renameio/maybe"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )

View File

@@ -1,11 +1,21 @@
package aghnet_test package aghnet
import ( import (
"bytes"
"encoding/json"
"fmt"
"io/fs" "io/fs"
"net"
"net/netip"
"os" "os"
"strings"
"testing" "testing"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil" "github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@@ -14,3 +24,315 @@ func TestMain(m *testing.M) {
// testdata is the filesystem containing data for testing the package. // testdata is the filesystem containing data for testing the package.
var testdata fs.FS = os.DirFS("./testdata") var testdata fs.FS = os.DirFS("./testdata")
// substRootDirFS replaces the aghos.RootDirFS function used throughout the
// package with fsys for tests ran under t.
func substRootDirFS(t testing.TB, fsys fs.FS) {
t.Helper()
prev := rootDirFS
t.Cleanup(func() { rootDirFS = prev })
rootDirFS = fsys
}
// RunCmdFunc is the signature of aghos.RunCommand function.
type RunCmdFunc func(cmd string, args ...string) (code int, out []byte, err error)
// substShell replaces the the aghos.RunCommand function used throughout the
// package with rc for tests ran under t.
func substShell(t testing.TB, rc RunCmdFunc) {
t.Helper()
prev := aghosRunCommand
t.Cleanup(func() { aghosRunCommand = prev })
aghosRunCommand = rc
}
// mapShell is a substitution of aghos.RunCommand that maps the command to it's
// execution result. It's only needed to simplify testing.
//
// TODO(e.burkov): Perhaps put all the shell interactions behind an interface.
type mapShell map[string]struct {
err error
out string
code int
}
// theOnlyCmd returns mapShell that only handles a single command and arguments
// combination from cmd.
func theOnlyCmd(cmd string, code int, out string, err error) (s mapShell) {
return mapShell{cmd: {code: code, out: out, err: err}}
}
// RunCmd is a RunCmdFunc handled by s.
func (s mapShell) RunCmd(cmd string, args ...string) (code int, out []byte, err error) {
key := strings.Join(append([]string{cmd}, args...), " ")
ret, ok := s[key]
if !ok {
return 0, nil, fmt.Errorf("unexpected shell command %q", key)
}
return ret.code, []byte(ret.out), ret.err
}
// ifaceAddrsFunc is the signature of net.InterfaceAddrs function.
type ifaceAddrsFunc func() (ifaces []net.Addr, err error)
// substNetInterfaceAddrs replaces the the net.InterfaceAddrs function used
// throughout the package with f for tests ran under t.
func substNetInterfaceAddrs(t *testing.T, f ifaceAddrsFunc) {
t.Helper()
prev := netInterfaceAddrs
t.Cleanup(func() { netInterfaceAddrs = prev })
netInterfaceAddrs = f
}
func TestGatewayIP(t *testing.T) {
const ifaceName = "ifaceName"
const cmd = "ip route show dev " + ifaceName
testCases := []struct {
shell mapShell
want netip.Addr
name string
}{{
shell: theOnlyCmd(cmd, 0, `default via 1.2.3.4 onlink`, nil),
want: netip.MustParseAddr("1.2.3.4"),
name: "success_v4",
}, {
shell: theOnlyCmd(cmd, 0, `default via ::ffff onlink`, nil),
want: netip.MustParseAddr("::ffff"),
name: "success_v6",
}, {
shell: theOnlyCmd(cmd, 0, `non-default via 1.2.3.4 onlink`, nil),
want: netip.Addr{},
name: "bad_output",
}, {
shell: theOnlyCmd(cmd, 0, "", errors.Error("can't run command")),
want: netip.Addr{},
name: "err_runcmd",
}, {
shell: theOnlyCmd(cmd, 1, "", nil),
want: netip.Addr{},
name: "bad_code",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
substShell(t, tc.shell.RunCmd)
assert.Equal(t, tc.want, GatewayIP(ifaceName))
})
}
}
func TestInterfaceByIP(t *testing.T) {
ifaces, err := GetValidNetInterfacesForWeb()
require.NoError(t, err)
require.NotEmpty(t, ifaces)
for _, iface := range ifaces {
t.Run(iface.Name, func(t *testing.T) {
require.NotEmpty(t, iface.Addresses)
for _, ip := range iface.Addresses {
ifaceName := InterfaceByIP(ip)
require.Equal(t, iface.Name, ifaceName)
}
})
}
}
func TestBroadcastFromIPNet(t *testing.T) {
known4 := netip.MustParseAddr("192.168.0.1")
fullBroadcast4 := netip.MustParseAddr("255.255.255.255")
known6 := netip.MustParseAddr("102:304:506:708:90a:b0c:d0e:f10")
testCases := []struct {
pref netip.Prefix
want netip.Addr
name string
}{{
pref: netip.PrefixFrom(known4, 0),
want: fullBroadcast4,
name: "full",
}, {
pref: netip.PrefixFrom(known4, 20),
want: netip.MustParseAddr("192.168.15.255"),
name: "full",
}, {
pref: netip.PrefixFrom(known6, netutil.IPv6BitLen),
want: known6,
name: "ipv6_no_mask",
}, {
pref: netip.PrefixFrom(known4, netutil.IPv4BitLen),
want: known4,
name: "ipv4_no_mask",
}, {
pref: netip.PrefixFrom(netip.IPv4Unspecified(), 0),
want: fullBroadcast4,
name: "unspecified",
}, {
pref: netip.Prefix{},
want: netip.Addr{},
name: "invalid",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
assert.Equal(t, tc.want, BroadcastFromPref(tc.pref))
})
}
}
func TestCheckPort(t *testing.T) {
laddr := netip.AddrPortFrom(netutil.IPv4Localhost(), 0)
t.Run("tcp_bound", func(t *testing.T) {
l, err := net.Listen("tcp", laddr.String())
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, l.Close)
ipp := testutil.RequireTypeAssert[*net.TCPAddr](t, l.Addr()).AddrPort()
require.Equal(t, laddr.Addr(), ipp.Addr())
require.NotZero(t, ipp.Port())
err = CheckPort("tcp", ipp)
target := &net.OpError{}
require.ErrorAs(t, err, &target)
assert.Equal(t, "listen", target.Op)
})
t.Run("udp_bound", func(t *testing.T) {
conn, err := net.ListenPacket("udp", laddr.String())
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, conn.Close)
ipp := testutil.RequireTypeAssert[*net.UDPAddr](t, conn.LocalAddr()).AddrPort()
require.Equal(t, laddr.Addr(), ipp.Addr())
require.NotZero(t, ipp.Port())
err = CheckPort("udp", ipp)
target := &net.OpError{}
require.ErrorAs(t, err, &target)
assert.Equal(t, "listen", target.Op)
})
t.Run("bad_network", func(t *testing.T) {
err := CheckPort("bad_network", netip.AddrPortFrom(netip.Addr{}, 0))
assert.NoError(t, err)
})
t.Run("can_bind", func(t *testing.T) {
err := CheckPort("udp", netip.AddrPortFrom(netip.IPv4Unspecified(), 0))
assert.NoError(t, err)
})
}
func TestCollectAllIfacesAddrs(t *testing.T) {
testCases := []struct {
name string
wantErrMsg string
addrs []net.Addr
wantAddrs []string
}{{
name: "success",
wantErrMsg: ``,
addrs: []net.Addr{&net.IPNet{
IP: net.IP{1, 2, 3, 4},
Mask: net.CIDRMask(24, netutil.IPv4BitLen),
}, &net.IPNet{
IP: net.IP{4, 3, 2, 1},
Mask: net.CIDRMask(16, netutil.IPv4BitLen),
}},
wantAddrs: []string{"1.2.3.4", "4.3.2.1"},
}, {
name: "not_cidr",
wantErrMsg: `parsing cidr: invalid CIDR address: 1.2.3.4`,
addrs: []net.Addr{&net.IPAddr{
IP: net.IP{1, 2, 3, 4},
}},
wantAddrs: nil,
}, {
name: "empty",
wantErrMsg: ``,
addrs: []net.Addr{},
wantAddrs: nil,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
substNetInterfaceAddrs(t, func() ([]net.Addr, error) { return tc.addrs, nil })
addrs, err := CollectAllIfacesAddrs()
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
assert.Equal(t, tc.wantAddrs, addrs)
})
}
t.Run("internal_error", func(t *testing.T) {
const errAddrs errors.Error = "can't get addresses"
const wantErrMsg string = `getting interfaces addresses: ` + string(errAddrs)
substNetInterfaceAddrs(t, func() ([]net.Addr, error) { return nil, errAddrs })
_, err := CollectAllIfacesAddrs()
testutil.AssertErrorMsg(t, wantErrMsg, err)
})
}
func TestIsAddrInUse(t *testing.T) {
t.Run("addr_in_use", func(t *testing.T) {
l, err := net.Listen("tcp", "0.0.0.0:0")
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, l.Close)
_, err = net.Listen(l.Addr().Network(), l.Addr().String())
assert.True(t, IsAddrInUse(err))
})
t.Run("another", func(t *testing.T) {
const anotherErr errors.Error = "not addr in use"
assert.False(t, IsAddrInUse(anotherErr))
})
}
func TestNetInterface_MarshalJSON(t *testing.T) {
const want = `{` +
`"hardware_address":"aa:bb:cc:dd:ee:ff",` +
`"flags":"up|multicast",` +
`"ip_addresses":["1.2.3.4","aaaa::1"],` +
`"name":"iface0",` +
`"mtu":1500` +
`}` + "\n"
ip4, ok := netip.AddrFromSlice([]byte{1, 2, 3, 4})
require.True(t, ok)
ip6, ok := netip.AddrFromSlice([]byte{0xAA, 0xAA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
require.True(t, ok)
net4 := netip.PrefixFrom(ip4, 24)
net6 := netip.PrefixFrom(ip6, 8)
iface := &NetInterface{
Addresses: []netip.Addr{ip4, ip6},
Subnets: []netip.Prefix{net4, net6},
Name: "iface0",
HardwareAddr: net.HardwareAddr{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
Flags: net.FlagUp | net.FlagMulticast,
MTU: 1500,
}
b := &bytes.Buffer{}
err := json.NewEncoder(b).Encode(iface)
require.NoError(t, err)
assert.Equal(t, want, b.String())
}

View File

@@ -1,52 +0,0 @@
// Package aghrenameio is a wrapper around package github.com/google/renameio/v2
// that provides a similar stream-based API for both Unix and Windows systems.
// While the Windows API is not technically atomic, it still provides a
// consistent stream-based interface, and atomic renames of files do not seem to
// be possible in all cases anyway.
//
// See https://github.com/google/renameio/issues/1.
//
// TODO(a.garipov): Consider moving to golibs/renameioutil once tried and
// tested.
package aghrenameio
import (
"io/fs"
"github.com/AdguardTeam/golibs/errors"
)
// PendingFile is the interface for pending temporary files.
type PendingFile interface {
// Cleanup closes the file, and removes it without performing the renaming.
// To close and rename the file, use CloseReplace.
Cleanup() (err error)
// CloseReplace closes the temporary file and replaces the destination file
// with it, possibly atomically.
//
// This method is not safe for concurrent use by multiple goroutines.
CloseReplace() (err error)
// Write writes len(b) bytes from b to the File. It returns the number of
// bytes written and an error, if any. Write returns a non-nil error when n
// != len(b).
Write(b []byte) (n int, err error)
}
// NewPendingFile is a wrapper around [renameio.NewPendingFile] on Unix systems
// and [os.CreateTemp] on Windows.
func NewPendingFile(filePath string, mode fs.FileMode) (f PendingFile, err error) {
return newPendingFile(filePath, mode)
}
// WithDeferredCleanup is a helper that performs the necessary cleanups and
// finalizations of the temporary files based on the returned error.
func WithDeferredCleanup(returned error, file PendingFile) (err error) {
// Make sure that any error returned from here is marked as a deferred one.
if returned != nil {
return errors.WithDeferred(returned, file.Cleanup())
}
return errors.WithDeferred(nil, file.CloseReplace())
}

View File

@@ -1,101 +0,0 @@
package aghrenameio_test
import (
"io/fs"
"os"
"path/filepath"
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/aghrenameio"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// testPerm is the common permission mode for tests.
const testPerm fs.FileMode = 0o644
// Common file data for tests.
var (
initialData = []byte("initial data\n")
newData = []byte("new data\n")
)
func TestPendingFile(t *testing.T) {
t.Parallel()
targetPath := newInitialFile(t)
f, err := aghrenameio.NewPendingFile(targetPath, testPerm)
require.NoError(t, err)
_, err = f.Write(newData)
require.NoError(t, err)
err = f.CloseReplace()
require.NoError(t, err)
gotData, err := os.ReadFile(targetPath)
require.NoError(t, err)
assert.Equal(t, newData, gotData)
}
// newInitialFile is a test helper that returns the path to the file containing
// [initialData].
func newInitialFile(t *testing.T) (targetPath string) {
t.Helper()
dir := t.TempDir()
targetPath = filepath.Join(dir, "target")
err := os.WriteFile(targetPath, initialData, 0o644)
require.NoError(t, err)
return targetPath
}
func TestWithDeferredCleanup(t *testing.T) {
t.Parallel()
const testError errors.Error = "test error"
testCases := []struct {
error error
name string
wantErrMsg string
wantData []byte
}{{
name: "success",
error: nil,
wantErrMsg: "",
wantData: newData,
}, {
name: "error",
error: testError,
wantErrMsg: testError.Error(),
wantData: initialData,
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
targetPath := newInitialFile(t)
f, err := aghrenameio.NewPendingFile(targetPath, testPerm)
require.NoError(t, err)
_, err = f.Write(newData)
require.NoError(t, err)
err = aghrenameio.WithDeferredCleanup(tc.error, f)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
gotData, err := os.ReadFile(targetPath)
require.NoError(t, err)
assert.Equal(t, tc.wantData, gotData)
})
}
}

View File

@@ -1,48 +0,0 @@
//go:build unix
package aghrenameio
import (
"io/fs"
"github.com/google/renameio/v2"
)
// pendingFile is a wrapper around [*renameio.PendingFile] making it an
// [io.WriteCloser].
type pendingFile struct {
file *renameio.PendingFile
}
// type check
var _ PendingFile = pendingFile{}
// Cleanup implements the [PendingFile] interface for pendingFile.
func (f pendingFile) Cleanup() (err error) {
return f.file.Cleanup()
}
// CloseReplace implements the [PendingFile] interface for pendingFile.
func (f pendingFile) CloseReplace() (err error) {
return f.file.CloseAtomicallyReplace()
}
// Write implements the [PendingFile] interface for pendingFile.
func (f pendingFile) Write(b []byte) (n int, err error) {
return f.file.Write(b)
}
// NewPendingFile is a wrapper around [renameio.NewPendingFile].
//
// f.Close must be called to finish the renaming.
func newPendingFile(filePath string, mode fs.FileMode) (f PendingFile, err error) {
file, err := renameio.NewPendingFile(filePath, renameio.WithPermissions(mode))
if err != nil {
// Don't wrap the error since it's informative enough as is.
return nil, err
}
return pendingFile{
file: file,
}, nil
}

View File

@@ -1,74 +0,0 @@
//go:build windows
package aghrenameio
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"github.com/AdguardTeam/golibs/errors"
)
// pendingFile is a wrapper around [*os.File] calling [os.Rename] in its Close
// method.
type pendingFile struct {
file *os.File
targetPath string
}
// type check
var _ PendingFile = (*pendingFile)(nil)
// Cleanup implements the [PendingFile] interface for *pendingFile.
func (f *pendingFile) Cleanup() (err error) {
closeErr := f.file.Close()
err = os.Remove(f.file.Name())
// Put closeErr into the deferred error because that's where it is usually
// expected.
return errors.WithDeferred(err, closeErr)
}
// CloseReplace implements the [PendingFile] interface for *pendingFile.
func (f *pendingFile) CloseReplace() (err error) {
err = f.file.Close()
if err != nil {
return fmt.Errorf("closing: %w", err)
}
err = os.Rename(f.file.Name(), f.targetPath)
if err != nil {
return fmt.Errorf("renaming: %w", err)
}
return nil
}
// Write implements the [PendingFile] interface for *pendingFile.
func (f *pendingFile) Write(b []byte) (n int, err error) {
return f.file.Write(b)
}
// NewPendingFile is a wrapper around [os.CreateTemp].
//
// f.Close must be called to finish the renaming.
func newPendingFile(filePath string, mode fs.FileMode) (f PendingFile, err error) {
// Use the same directory as the file itself, because moves across
// filesystems can be especially problematic.
file, err := os.CreateTemp(filepath.Dir(filePath), "")
if err != nil {
return nil, fmt.Errorf("opening pending file: %w", err)
}
err = file.Chmod(mode)
if err != nil {
return nil, fmt.Errorf("preparing pending file: %w", err)
}
return &pendingFile{
file: file,
targetPath: filePath,
}, nil
}

View File

@@ -2,9 +2,7 @@
package aghtest package aghtest
import ( import (
"crypto/sha256"
"io" "io"
"net"
"testing" "testing"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
@@ -36,10 +34,3 @@ func ReplaceLogLevel(t testing.TB, l log.Level) {
t.Cleanup(func() { log.SetLevel(prev) }) t.Cleanup(func() { log.SetLevel(prev) })
log.SetLevel(l) log.SetLevel(l)
} }
// HostToIPs is a helper that generates one IPv4 and one IPv6 address from host.
func HostToIPs(host string) (ipv4, ipv6 net.IP) {
hash := sha256.Sum256([]byte(host))
return net.IP(hash[:4]), net.IP(hash[4:20])
}

View File

@@ -2,15 +2,11 @@ package aghtest
import ( import (
"context" "context"
"io/fs"
"net" "net"
"net/netip"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghos" "github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/AdguardTeam/AdGuardHome/internal/next/agh" "github.com/AdguardTeam/AdGuardHome/internal/next/agh"
"github.com/AdguardTeam/AdGuardHome/internal/rdns"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/dnsproxy/upstream"
"github.com/miekg/dns" "github.com/miekg/dns"
) )
@@ -19,20 +15,94 @@ import (
// //
// Keep entities in this file in alphabetic order. // Keep entities in this file in alphabetic order.
// Standard Library
// Package fs
// type check
var _ fs.FS = &FS{}
// FS is a mock [fs.FS] implementation for tests.
type FS struct {
OnOpen func(name string) (fs.File, error)
}
// Open implements the [fs.FS] interface for *FS.
func (fsys *FS) Open(name string) (fs.File, error) {
return fsys.OnOpen(name)
}
// type check
var _ fs.GlobFS = &GlobFS{}
// GlobFS is a mock [fs.GlobFS] implementation for tests.
type GlobFS struct {
// FS is embedded here to avoid implementing all it's methods.
FS
OnGlob func(pattern string) ([]string, error)
}
// Glob implements the [fs.GlobFS] interface for *GlobFS.
func (fsys *GlobFS) Glob(pattern string) ([]string, error) {
return fsys.OnGlob(pattern)
}
// type check
var _ fs.StatFS = &StatFS{}
// StatFS is a mock [fs.StatFS] implementation for tests.
type StatFS struct {
// FS is embedded here to avoid implementing all it's methods.
FS
OnStat func(name string) (fs.FileInfo, error)
}
// Stat implements the [fs.StatFS] interface for *StatFS.
func (fsys *StatFS) Stat(name string) (fs.FileInfo, error) {
return fsys.OnStat(name)
}
// Package net
// type check
var _ net.Listener = (*Listener)(nil)
// Listener is a mock [net.Listener] implementation for tests.
type Listener struct {
OnAccept func() (conn net.Conn, err error)
OnAddr func() (addr net.Addr)
OnClose func() (err error)
}
// Accept implements the [net.Listener] interface for *Listener.
func (l *Listener) Accept() (conn net.Conn, err error) {
return l.OnAccept()
}
// Addr implements the [net.Listener] interface for *Listener.
func (l *Listener) Addr() (addr net.Addr) {
return l.OnAddr()
}
// Close implements the [net.Listener] interface for *Listener.
func (l *Listener) Close() (err error) {
return l.OnClose()
}
// Module adguard-home // Module adguard-home
// Package aghos // Package aghos
// FSWatcher is a fake [aghos.FSWatcher] implementation for tests. // type check
var _ aghos.FSWatcher = (*FSWatcher)(nil)
// FSWatcher is a mock [aghos.FSWatcher] implementation for tests.
type FSWatcher struct { type FSWatcher struct {
OnEvents func() (e <-chan struct{}) OnEvents func() (e <-chan struct{})
OnAdd func(name string) (err error) OnAdd func(name string) (err error)
OnClose func() (err error) OnClose func() (err error)
} }
// type check
var _ aghos.FSWatcher = (*FSWatcher)(nil)
// Events implements the [aghos.FSWatcher] interface for *FSWatcher. // Events implements the [aghos.FSWatcher] interface for *FSWatcher.
func (w *FSWatcher) Events() (e <-chan struct{}) { func (w *FSWatcher) Events() (e <-chan struct{}) {
return w.OnEvents() return w.OnEvents()
@@ -50,16 +120,16 @@ func (w *FSWatcher) Close() (err error) {
// Package agh // Package agh
// ServiceWithConfig is a fake [agh.ServiceWithConfig] implementation for tests. // type check
var _ agh.ServiceWithConfig[struct{}] = (*ServiceWithConfig[struct{}])(nil)
// ServiceWithConfig is a mock [agh.ServiceWithConfig] implementation for tests.
type ServiceWithConfig[ConfigType any] struct { type ServiceWithConfig[ConfigType any] struct {
OnStart func() (err error) OnStart func() (err error)
OnShutdown func(ctx context.Context) (err error) OnShutdown func(ctx context.Context) (err error)
OnConfig func() (c ConfigType) OnConfig func() (c ConfigType)
} }
// type check
var _ agh.ServiceWithConfig[struct{}] = (*ServiceWithConfig[struct{}])(nil)
// Start implements the [agh.ServiceWithConfig] interface for // Start implements the [agh.ServiceWithConfig] interface for
// *ServiceWithConfig. // *ServiceWithConfig.
func (s *ServiceWithConfig[_]) Start() (err error) { func (s *ServiceWithConfig[_]) Start() (err error) {
@@ -78,76 +148,14 @@ func (s *ServiceWithConfig[ConfigType]) Config() (c ConfigType) {
return s.OnConfig() return s.OnConfig()
} }
// Package client
// AddressProcessor is a fake [client.AddressProcessor] implementation for
// tests.
type AddressProcessor struct {
OnProcess func(ip netip.Addr)
OnClose func() (err error)
}
// type check
var _ client.AddressProcessor = (*AddressProcessor)(nil)
// Process implements the [client.AddressProcessor] interface for
// *AddressProcessor.
func (p *AddressProcessor) Process(ip netip.Addr) {
p.OnProcess(ip)
}
// Close implements the [client.AddressProcessor] interface for
// *AddressProcessor.
func (p *AddressProcessor) Close() (err error) {
return p.OnClose()
}
// AddressUpdater is a fake [client.AddressUpdater] implementation for tests.
type AddressUpdater struct {
OnUpdateAddress func(ip netip.Addr, host string, info *whois.Info)
}
// type check
var _ client.AddressUpdater = (*AddressUpdater)(nil)
// UpdateAddress implements the [client.AddressUpdater] interface for
// *AddressUpdater.
func (p *AddressUpdater) UpdateAddress(ip netip.Addr, host string, info *whois.Info) {
p.OnUpdateAddress(ip, host, info)
}
// Package filtering
// Resolver is a fake [filtering.Resolver] implementation for tests.
type Resolver struct {
OnLookupIP func(ctx context.Context, network, host string) (ips []net.IP, err error)
}
// LookupIP implements the [filtering.Resolver] interface for *Resolver.
func (r *Resolver) LookupIP(ctx context.Context, network, host string) (ips []net.IP, err error) {
return r.OnLookupIP(ctx, network, host)
}
// Package rdns
// Exchanger is a fake [rdns.Exchanger] implementation for tests.
type Exchanger struct {
OnExchange func(ip netip.Addr) (host string, ttl time.Duration, err error)
}
// type check
var _ rdns.Exchanger = (*Exchanger)(nil)
// Exchange implements [rdns.Exchanger] interface for *Exchanger.
func (e *Exchanger) Exchange(ip netip.Addr) (host string, ttl time.Duration, err error) {
return e.OnExchange(ip)
}
// Module dnsproxy // Module dnsproxy
// Package upstream // Package upstream
// UpstreamMock is a fake [upstream.Upstream] implementation for tests. // type check
var _ upstream.Upstream = (*UpstreamMock)(nil)
// UpstreamMock is a mock [upstream.Upstream] implementation for tests.
// //
// TODO(a.garipov): Replace with all uses of Upstream with UpstreamMock and // TODO(a.garipov): Replace with all uses of Upstream with UpstreamMock and
// rename it to just Upstream. // rename it to just Upstream.
@@ -157,9 +165,6 @@ type UpstreamMock struct {
OnClose func() (err error) OnClose func() (err error)
} }
// type check
var _ upstream.Upstream = (*UpstreamMock)(nil)
// Address implements the [upstream.Upstream] interface for *UpstreamMock. // Address implements the [upstream.Upstream] interface for *UpstreamMock.
func (u *UpstreamMock) Address() (addr string) { func (u *UpstreamMock) Address() (addr string) {
return u.OnAddress() return u.OnAddress()

View File

@@ -1,11 +1,3 @@
package aghtest_test package aghtest_test
import (
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
)
// Put interface checks that cause import cycles here. // Put interface checks that cause import cycles here.
// type check
var _ filtering.Resolver = (*aghtest.Resolver)(nil)

View File

@@ -0,0 +1,57 @@
package aghtest
import (
"context"
"crypto/sha256"
"net"
"sync"
)
// TestResolver is a Resolver for tests.
type TestResolver struct {
counter int
counterLock sync.Mutex
}
// HostToIPs generates IPv4 and IPv6 from host.
func (r *TestResolver) HostToIPs(host string) (ipv4, ipv6 net.IP) {
hash := sha256.Sum256([]byte(host))
return net.IP(hash[:4]), net.IP(hash[4:20])
}
// LookupIP implements Resolver interface for *testResolver. It returns the
// slice of net.IP with IPv4 and IPv6 instances.
func (r *TestResolver) LookupIP(_ context.Context, _, host string) (ips []net.IP, err error) {
ipv4, ipv6 := r.HostToIPs(host)
addrs := []net.IP{ipv4, ipv6}
r.counterLock.Lock()
defer r.counterLock.Unlock()
r.counter++
return addrs, nil
}
// LookupHost implements Resolver interface for *testResolver. It returns the
// slice of IPv4 and IPv6 instances converted to strings.
func (r *TestResolver) LookupHost(host string) (addrs []string, err error) {
ipv4, ipv6 := r.HostToIPs(host)
r.counterLock.Lock()
defer r.counterLock.Unlock()
r.counter++
return []string{
ipv4.String(),
ipv6.String(),
}, nil
}
// Counter returns the number of requests handled.
func (r *TestResolver) Counter() int {
r.counterLock.Lock()
defer r.counterLock.Unlock()
return r.counter
}

View File

@@ -1,302 +0,0 @@
package client
import (
"context"
"net/netip"
"sync"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/rdns"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
)
// ErrClosed is returned from [AddressProcessor.Close] if it's closed more than
// once.
const ErrClosed errors.Error = "use of closed address processor"
// AddressProcessor is the interface for types that can process clients.
type AddressProcessor interface {
Process(ip netip.Addr)
Close() (err error)
}
// EmptyAddrProc is an [AddressProcessor] that does nothing.
type EmptyAddrProc struct{}
// type check
var _ AddressProcessor = EmptyAddrProc{}
// Process implements the [AddressProcessor] interface for EmptyAddrProc.
func (EmptyAddrProc) Process(_ netip.Addr) {}
// Close implements the [AddressProcessor] interface for EmptyAddrProc.
func (EmptyAddrProc) Close() (_ error) { return nil }
// DefaultAddrProcConfig is the configuration structure for address processors.
type DefaultAddrProcConfig struct {
// DialContext is used to create TCP connections to WHOIS servers.
// DialContext must not be nil if [DefaultAddrProcConfig.UseWHOIS] is true.
DialContext aghnet.DialContextFunc
// Exchanger is used to perform rDNS queries. Exchanger must not be nil if
// [DefaultAddrProcConfig.UseRDNS] is true.
Exchanger rdns.Exchanger
// PrivateSubnets are used to determine if an incoming IP address is
// private. It must not be nil.
PrivateSubnets netutil.SubnetSet
// AddressUpdater is used to update the information about a client's IP
// address. It must not be nil.
AddressUpdater AddressUpdater
// InitialAddresses are the addresses that are queued for processing
// immediately by [NewDefaultAddrProc].
InitialAddresses []netip.Addr
// CatchPanics, if true, makes the address processor catch and log panics.
//
// TODO(a.garipov): Consider better ways to do this or apply this method to
// other parts of the codebase.
CatchPanics bool
// UseRDNS, if true, enables resolving of client IP addresses using reverse
// DNS.
UseRDNS bool
// UsePrivateRDNS, if true, enables resolving of private client IP addresses
// using reverse DNS. See [DefaultAddrProcConfig.PrivateSubnets].
UsePrivateRDNS bool
// UseWHOIS, if true, enables resolving of client IP addresses using WHOIS.
UseWHOIS bool
}
// AddressUpdater is the interface for storages of DNS clients that can update
// information about them.
//
// TODO(a.garipov): Consider using the actual client storage once it is moved
// into this package.
type AddressUpdater interface {
// UpdateAddress updates information about an IP address, setting host (if
// not empty) and WHOIS information (if not nil).
UpdateAddress(ip netip.Addr, host string, info *whois.Info)
}
// DefaultAddrProc processes incoming client addresses with rDNS and WHOIS, if
// configured, and updates that information in a client storage.
type DefaultAddrProc struct {
// clientIPsMu serializes closure of clientIPs and access to isClosed.
clientIPsMu *sync.Mutex
// clientIPs is the channel queueing client processing tasks.
clientIPs chan netip.Addr
// rdns is used to perform rDNS lookups of clients' IP addresses.
rdns rdns.Interface
// whois is used to perform WHOIS lookups of clients' IP addresses.
whois whois.Interface
// addrUpdater is used to update the information about a client's IP
// address.
addrUpdater AddressUpdater
// privateSubnets are used to determine if an incoming IP address is
// private.
privateSubnets netutil.SubnetSet
// isClosed is set to true once the address processor is closed.
isClosed bool
// usePrivateRDNS, if true, enables resolving of private client IP addresses
// using reverse DNS.
usePrivateRDNS bool
}
const (
// defaultQueueSize is the size of queue of IPs for rDNS and WHOIS
// processing.
defaultQueueSize = 255
// defaultCacheSize is the maximum size of the cache for rDNS and WHOIS
// processing. It must be greater than zero.
defaultCacheSize = 10_000
// defaultIPTTL is the Time to Live duration for IP addresses cached by
// rDNS and WHOIS.
defaultIPTTL = 1 * time.Hour
)
// NewDefaultAddrProc returns a new running client address processor. c must
// not be nil.
func NewDefaultAddrProc(c *DefaultAddrProcConfig) (p *DefaultAddrProc) {
p = &DefaultAddrProc{
clientIPsMu: &sync.Mutex{},
clientIPs: make(chan netip.Addr, defaultQueueSize),
rdns: &rdns.Empty{},
addrUpdater: c.AddressUpdater,
whois: &whois.Empty{},
privateSubnets: c.PrivateSubnets,
usePrivateRDNS: c.UsePrivateRDNS,
}
if c.UseRDNS {
p.rdns = rdns.New(&rdns.Config{
Exchanger: c.Exchanger,
CacheSize: defaultCacheSize,
CacheTTL: defaultIPTTL,
})
}
if c.UseWHOIS {
p.whois = newWHOIS(c.DialContext)
}
go p.process(c.CatchPanics)
for _, ip := range c.InitialAddresses {
p.Process(ip)
}
return p
}
// newWHOIS returns a whois.Interface instance using the given function for
// dialing.
func newWHOIS(dialFunc aghnet.DialContextFunc) (w whois.Interface) {
// TODO(s.chzhen): Consider making configurable.
const (
// defaultTimeout is the timeout for WHOIS requests.
defaultTimeout = 5 * time.Second
// defaultMaxConnReadSize is an upper limit in bytes for reading from a
// net.Conn.
defaultMaxConnReadSize = 64 * 1024
// defaultMaxRedirects is the maximum redirects count.
defaultMaxRedirects = 5
// defaultMaxInfoLen is the maximum length of whois.Info fields.
defaultMaxInfoLen = 250
)
return whois.New(&whois.Config{
DialContext: dialFunc,
ServerAddr: whois.DefaultServer,
Port: whois.DefaultPort,
Timeout: defaultTimeout,
CacheSize: defaultCacheSize,
MaxConnReadSize: defaultMaxConnReadSize,
MaxRedirects: defaultMaxRedirects,
MaxInfoLen: defaultMaxInfoLen,
CacheTTL: defaultIPTTL,
})
}
// type check
var _ AddressProcessor = (*DefaultAddrProc)(nil)
// Process implements the [AddressProcessor] interface for *DefaultAddrProc.
func (p *DefaultAddrProc) Process(ip netip.Addr) {
p.clientIPsMu.Lock()
defer p.clientIPsMu.Unlock()
if p.isClosed {
return
}
select {
case p.clientIPs <- ip:
// Go on.
default:
log.Debug("clients: ip channel is full; len: %d", len(p.clientIPs))
}
}
// process processes the incoming client IP-address information. It is intended
// to be used as a goroutine. Once clientIPs is closed, process exits.
func (p *DefaultAddrProc) process(catchPanics bool) {
if catchPanics {
defer log.OnPanic("addrProcessor.process")
}
log.Info("clients: processing addresses")
for ip := range p.clientIPs {
host := p.processRDNS(ip)
info := p.processWHOIS(ip)
p.addrUpdater.UpdateAddress(ip, host, info)
}
log.Info("clients: finished processing addresses")
}
// processRDNS resolves the clients' IP addresses using reverse DNS. host is
// empty if there were errors or if the information hasn't changed.
func (p *DefaultAddrProc) processRDNS(ip netip.Addr) (host string) {
start := time.Now()
log.Debug("clients: processing %s with rdns", ip)
defer func() {
log.Debug("clients: finished processing %s with rdns in %s", ip, time.Since(start))
}()
ok := p.shouldResolve(ip)
if !ok {
return
}
host, changed := p.rdns.Process(ip)
if !changed {
host = ""
}
return host
}
// shouldResolve returns false if ip is a loopback address, or ip is private and
// resolving of private addresses is disabled.
func (p *DefaultAddrProc) shouldResolve(ip netip.Addr) (ok bool) {
return !ip.IsLoopback() &&
(p.usePrivateRDNS || !p.privateSubnets.Contains(ip.AsSlice()))
}
// processWHOIS looks up the information about clients' IP addresses in the
// WHOIS databases. info is nil if there were errors or if the information
// hasn't changed.
func (p *DefaultAddrProc) processWHOIS(ip netip.Addr) (info *whois.Info) {
start := time.Now()
log.Debug("clients: processing %s with whois", ip)
defer func() {
log.Debug("clients: finished processing %s with whois in %s", ip, time.Since(start))
}()
// TODO(s.chzhen): Move the timeout logic from WHOIS configuration to the
// context.
info, changed := p.whois.Process(context.Background(), ip)
if !changed {
info = nil
}
return info
}
// Close implements the [AddressProcessor] interface for *DefaultAddrProc.
func (p *DefaultAddrProc) Close() (err error) {
p.clientIPsMu.Lock()
defer p.clientIPsMu.Unlock()
if p.isClosed {
return ErrClosed
}
close(p.clientIPs)
p.isClosed = true
return nil
}

View File

@@ -1,262 +0,0 @@
package client_test
import (
"context"
"fmt"
"io"
"net"
"net/netip"
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
"github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil"
"github.com/AdguardTeam/golibs/testutil/fakenet"
"github.com/stretchr/testify/assert"
)
func TestEmptyAddrProc(t *testing.T) {
t.Parallel()
p := client.EmptyAddrProc{}
assert.NotPanics(t, func() {
p.Process(testIP)
})
assert.NotPanics(t, func() {
err := p.Close()
assert.NoError(t, err)
})
}
func TestDefaultAddrProc_Process_rDNS(t *testing.T) {
t.Parallel()
privateIP := netip.MustParseAddr("192.168.0.1")
testCases := []struct {
rdnsErr error
ip netip.Addr
name string
host string
usePrivate bool
wantUpd bool
}{{
rdnsErr: nil,
ip: testIP,
name: "success",
host: testHost,
usePrivate: false,
wantUpd: true,
}, {
rdnsErr: nil,
ip: testIP,
name: "no_host",
host: "",
usePrivate: false,
wantUpd: false,
}, {
rdnsErr: nil,
ip: netip.MustParseAddr("127.0.0.1"),
name: "localhost",
host: "",
usePrivate: false,
wantUpd: false,
}, {
rdnsErr: nil,
ip: privateIP,
name: "private_ignored",
host: "",
usePrivate: false,
wantUpd: false,
}, {
rdnsErr: nil,
ip: privateIP,
name: "private_processed",
host: "private.example",
usePrivate: true,
wantUpd: true,
}, {
rdnsErr: errors.Error("rdns error"),
ip: testIP,
name: "rdns_error",
host: "",
usePrivate: false,
wantUpd: false,
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
updIPCh := make(chan netip.Addr, 1)
updHostCh := make(chan string, 1)
updInfoCh := make(chan *whois.Info, 1)
p := client.NewDefaultAddrProc(&client.DefaultAddrProcConfig{
DialContext: func(_ context.Context, _, _ string) (conn net.Conn, err error) {
panic("not implemented")
},
Exchanger: &aghtest.Exchanger{
OnExchange: func(ip netip.Addr) (host string, ttl time.Duration, err error) {
return tc.host, 0, tc.rdnsErr
},
},
PrivateSubnets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
AddressUpdater: &aghtest.AddressUpdater{
OnUpdateAddress: newOnUpdateAddress(tc.wantUpd, updIPCh, updHostCh, updInfoCh),
},
CatchPanics: false,
UseRDNS: true,
UsePrivateRDNS: tc.usePrivate,
UseWHOIS: false,
})
testutil.CleanupAndRequireSuccess(t, p.Close)
p.Process(tc.ip)
if !tc.wantUpd {
return
}
gotIP, _ := testutil.RequireReceive(t, updIPCh, testTimeout)
assert.Equal(t, tc.ip, gotIP)
gotHost, _ := testutil.RequireReceive(t, updHostCh, testTimeout)
assert.Equal(t, tc.host, gotHost)
gotInfo, _ := testutil.RequireReceive(t, updInfoCh, testTimeout)
assert.Nil(t, gotInfo)
})
}
}
// newOnUpdateAddress is a test helper that returns a new OnUpdateAddress
// callback using the provided channels if an update is expected and panicking
// otherwise.
func newOnUpdateAddress(
want bool,
ips chan<- netip.Addr,
hosts chan<- string,
infos chan<- *whois.Info,
) (f func(ip netip.Addr, host string, info *whois.Info)) {
return func(ip netip.Addr, host string, info *whois.Info) {
if !want && (host != "" || info != nil) {
panic(fmt.Errorf("got unexpected update for %v with %q and %v", ip, host, info))
}
ips <- ip
hosts <- host
infos <- info
}
}
func TestDefaultAddrProc_Process_WHOIS(t *testing.T) {
t.Parallel()
testCases := []struct {
wantInfo *whois.Info
exchErr error
name string
wantUpd bool
}{{
wantInfo: &whois.Info{
City: testWHOISCity,
},
exchErr: nil,
name: "success",
wantUpd: true,
}, {
wantInfo: nil,
exchErr: nil,
name: "no_info",
wantUpd: false,
}, {
wantInfo: nil,
exchErr: errors.Error("whois error"),
name: "whois_error",
wantUpd: false,
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
whoisConn := &fakenet.Conn{
OnClose: func() (err error) { return nil },
OnRead: func(b []byte) (n int, err error) {
if tc.wantInfo == nil {
return 0, tc.exchErr
}
data := "city: " + tc.wantInfo.City + "\n"
copy(b, data)
return len(data), io.EOF
},
OnSetDeadline: func(_ time.Time) (err error) { return nil },
OnWrite: func(b []byte) (n int, err error) { return len(b), nil },
}
updIPCh := make(chan netip.Addr, 1)
updHostCh := make(chan string, 1)
updInfoCh := make(chan *whois.Info, 1)
p := client.NewDefaultAddrProc(&client.DefaultAddrProcConfig{
DialContext: func(_ context.Context, _, _ string) (conn net.Conn, err error) {
return whoisConn, nil
},
Exchanger: &aghtest.Exchanger{
OnExchange: func(_ netip.Addr) (_ string, _ time.Duration, _ error) {
panic("not implemented")
},
},
PrivateSubnets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
AddressUpdater: &aghtest.AddressUpdater{
OnUpdateAddress: newOnUpdateAddress(tc.wantUpd, updIPCh, updHostCh, updInfoCh),
},
CatchPanics: false,
UseRDNS: false,
UsePrivateRDNS: false,
UseWHOIS: true,
})
testutil.CleanupAndRequireSuccess(t, p.Close)
p.Process(testIP)
if !tc.wantUpd {
return
}
gotIP, _ := testutil.RequireReceive(t, updIPCh, testTimeout)
assert.Equal(t, testIP, gotIP)
gotHost, _ := testutil.RequireReceive(t, updHostCh, testTimeout)
assert.Empty(t, gotHost)
gotInfo, _ := testutil.RequireReceive(t, updInfoCh, testTimeout)
assert.Equal(t, tc.wantInfo, gotInfo)
})
}
}
func TestDefaultAddrProc_Close(t *testing.T) {
t.Parallel()
p := client.NewDefaultAddrProc(&client.DefaultAddrProcConfig{})
err := p.Close()
assert.NoError(t, err)
err = p.Close()
assert.ErrorIs(t, err, client.ErrClosed)
}

View File

@@ -1,5 +0,0 @@
// Package client contains types and logic dealing with AdGuard Home's DNS
// clients.
//
// TODO(a.garipov): Expand.
package client

View File

@@ -1,25 +0,0 @@
package client_test
import (
"net/netip"
"testing"
"time"
"github.com/AdguardTeam/golibs/testutil"
)
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
// testHost is the common hostname for tests.
const testHost = "client.example"
// testTimeout is the common timeout for tests.
const testTimeout = 1 * time.Second
// testWHOISCity is the common city for tests.
const testWHOISCity = "Brussels"
// testIP is the common IP address for tests.
var testIP = netip.MustParseAddr("1.2.3.4")

View File

@@ -1,60 +1,46 @@
# Testing DHCP Server # DHCP server
Contents: Contents:
* [Test setup with Virtual Box](#vbox) * [Test setup with Virtual Box](#vbox)
* [Quick test with DHCPTest](#dhcptest)
## <a href="#vbox" id="vbox" name="vbox">Test setup with Virtual Box</a> <a id="vbox"></a>
## Test setup with Virtual Box
### Prerequisites To set up a test environment for DHCP server you need:
To set up a test environment for DHCP server you will need: * Linux host machine
* Virtual Box
* Virtual machine (guest OS doesn't matter)
* Linux AG Home host machine (Virtual). ### Configure client
* Virtual Box.
* Virtual machine (guest OS doesn't matter).
### Configure Virtual Box 1. Install Virtual Box and run the following command to create a Host-Only network:
1. Install Virtual Box and run the following command to create a Host-Only $ VBoxManage hostonlyif create
network:
```sh You can check its status by `ip a` command.
$ VBoxManage hostonlyif create
```
You can check its status by `ip a` command.
You can also set up Host-Only network using Virtual Box menu: You can also set up Host-Only network using Virtual Box menu:
```
File -> Host Network Manager...
```
2. Create your virtual machine and set up its network: File -> Host Network Manager...
``` 2. Create your virtual machine and set up its network:
VM Settings -> Network -> Host-only Adapter
```
3. Start your VM, install an OS. Configure your network interface to use VM Settings -> Network -> Host-only Adapter
DHCP and the OS should ask for a IP address from our DHCP server.
4. To see the current IP addresses on client OS you can use `ip a` command on 3. Start your VM, install an OS. Configure your network interface to use DHCP and the OS should ask for a IP address from our DHCP server.
Linux or `ipconfig` on Windows.
5. To force the client OS to request an IP from DHCP server again, you can 4. To see the current IP address on client OS you can use `ip a` command on Linux or `ipconfig` on Windows.
use `dhclient` on Linux or `ipconfig /release` on Windows.
### Configure server 5. To force the client OS to request an IP from DHCP server again, you can use `dhclient` on Linux or `ipconfig /release` on Windows.
1. Edit server configuration file `AdGuardHome.yaml`, for example: ### Configure server
```yaml 1. Edit server configuration file 'AdGuardHome.yaml', for example:
dhcp:
dhcp:
enabled: true enabled: true
interface_name: vboxnet0 interface_name: vboxnet0
local_domain_name: lan
dhcpv4: dhcpv4:
gateway_ip: 192.168.56.1 gateway_ip: 192.168.56.1
subnet_mask: 255.255.255.0 subnet_mask: 255.255.255.0
@@ -68,29 +54,11 @@ To set up a test environment for DHCP server you will need:
lease_duration: 86400 lease_duration: 86400
ra_slaac_only: false ra_slaac_only: false
ra_allow_slaac: false ra_allow_slaac: false
```
2. Start the server 2. Start the server
```sh ./AdGuardHome
./AdGuardHome -v
```
There should be a message in log which shows that DHCP server is ready: There should be a message in log which shows that DHCP server is ready:
``` [info] DHCP: listening on 0.0.0.0:67
[info] DHCP: listening on 0.0.0.0:67
```
## <a href="#dhcptest" id="dhcptest" name="dhcptest">Quick test with DHCPTest utility</a>
### Prerequisites
* [DHCP test utility][dhcptest-gh].
### Quick test
The DHCP server could be tested for DISCOVER-OFFER packets with in
interactive mode.
[dhcptest-gh]: https://github.com/CyberShadow/dhcptest

Some files were not shown because too many files have changed in this diff Show More